mirror of
https://github.com/openjdk/jdk.git
synced 2026-02-18 14:25:33 +00:00
6975866: api/org_ietf/jgss/GSSContext/index.html#wrapUnwrapIOTest started to fail since jdk7 b102
Reviewed-by: valeriep
This commit is contained in:
parent
254e7faf34
commit
fdbca6b5f6
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2004, 2006, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2004, 2010, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
@ -710,29 +710,21 @@ class CipherHelper {
|
||||
* where HMAC is on {16-byte confounder | plaintext | 16-byte token_header}
|
||||
* HMAC is not encrypted; it is appended at the end.
|
||||
*/
|
||||
void encryptData(WrapToken_v2 token, byte[] confounder, byte[] tokenHeader,
|
||||
byte[] plaintext, int start, int len, int key_usage, OutputStream os)
|
||||
throws GSSException, IOException {
|
||||
byte[] encryptData(WrapToken_v2 token, byte[] confounder, byte[] tokenHeader,
|
||||
byte[] plaintext, int start, int len, int key_usage)
|
||||
throws GSSException {
|
||||
|
||||
byte[] ctext = null;
|
||||
switch (etype) {
|
||||
case EncryptedData.ETYPE_AES128_CTS_HMAC_SHA1_96:
|
||||
ctext = aes128Encrypt(confounder, tokenHeader,
|
||||
plaintext, start, len, key_usage);
|
||||
break;
|
||||
case EncryptedData.ETYPE_AES256_CTS_HMAC_SHA1_96:
|
||||
ctext = aes256Encrypt(confounder, tokenHeader,
|
||||
plaintext, start, len, key_usage);
|
||||
break;
|
||||
default:
|
||||
throw new GSSException(GSSException.FAILURE, -1,
|
||||
"Unsupported etype: " + etype);
|
||||
case EncryptedData.ETYPE_AES128_CTS_HMAC_SHA1_96:
|
||||
return aes128Encrypt(confounder, tokenHeader,
|
||||
plaintext, start, len, key_usage);
|
||||
case EncryptedData.ETYPE_AES256_CTS_HMAC_SHA1_96:
|
||||
return aes256Encrypt(confounder, tokenHeader,
|
||||
plaintext, start, len, key_usage);
|
||||
default:
|
||||
throw new GSSException(GSSException.FAILURE, -1,
|
||||
"Unsupported etype: " + etype);
|
||||
}
|
||||
|
||||
// Krb5Token.debug("EncryptedData = " +
|
||||
// Krb5Token.getHexBytes(ctext) + "\n");
|
||||
// Write to stream
|
||||
os.write(ctext);
|
||||
}
|
||||
|
||||
void encryptData(WrapToken token, byte[] confounder, byte[] plaintext,
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2004, 2006, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2004, 2010, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
@ -26,42 +26,40 @@
|
||||
package sun.security.jgss.krb5;
|
||||
|
||||
import org.ietf.jgss.*;
|
||||
import sun.security.jgss.*;
|
||||
import sun.security.krb5.*;
|
||||
import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.security.GeneralSecurityException;
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.security.MessageDigest;
|
||||
import java.util.Arrays;
|
||||
|
||||
/**
|
||||
* This class is a base class for new GSS token definitions, as defined
|
||||
* in draft-ietf-krb-wg-gssapi-cfx-07.txt, that pertain to per-message
|
||||
* GSS-API calls. Conceptually GSS-API has two types of per-message tokens:
|
||||
* WrapToken and MicToken. They differ in the respect that a WrapToken
|
||||
* carries additional plaintext or ciphertext application data besides
|
||||
* just the sequence number and checksum. This class encapsulates the
|
||||
* commonality in the structure of the WrapToken and the MicToken.
|
||||
* This structure can be represented as:
|
||||
* in RFC 4121, that pertain to per-message GSS-API calls. Conceptually
|
||||
* GSS-API has two types of per-message tokens: WrapToken and MicToken.
|
||||
* They differ in the respect that a WrapToken carries additional plaintext
|
||||
* or ciphertext application data besides just the sequence number and
|
||||
* checksum. This class encapsulates the commonality in the structure of
|
||||
* the WrapToken and the MicToken. This structure can be represented as:
|
||||
* <p>
|
||||
* <pre>
|
||||
* Wrap Tokens
|
||||
* Wrap Tokens
|
||||
*
|
||||
* Octet no Name Description
|
||||
* ---------------------------------------------------------------
|
||||
* 0..1 TOK_ID Identification field. Tokens emitted by
|
||||
* GSS_Wrap() contain the the hex value 05 04
|
||||
* expressed in big endian order in this field.
|
||||
* GSS_Wrap() contain the hex value 05 04
|
||||
* expressed in big-endian order in this field.
|
||||
* 2 Flags Attributes field, as described in section
|
||||
* 4.2.2.
|
||||
* 3 Filler Contains the hex value FF.
|
||||
* 4..5 EC Contains the "extra count" field, in big
|
||||
* 4..5 EC Contains the "extra count" field, in big-
|
||||
* endian order as described in section 4.2.3.
|
||||
* 6..7 RRC Contains the "right rotation count" in big
|
||||
* endian order, as described in section 4.2.5.
|
||||
* 8..15 SND_SEQ Sequence number field in clear text,
|
||||
* expressed in big endian order.
|
||||
* expressed in big-endian order.
|
||||
* 16..last Data Encrypted data for Wrap tokens with
|
||||
* confidentiality, or plaintext data followed
|
||||
* by the checksum for Wrap tokens without
|
||||
@ -73,67 +71,82 @@ import java.security.MessageDigest;
|
||||
* -----------------------------------------------------------------
|
||||
* 0..1 TOK_ID Identification field. Tokens emitted by
|
||||
* GSS_GetMIC() contain the hex value 04 04
|
||||
* expressed in big endian order in this field.
|
||||
* expressed in big-endian order in this field.
|
||||
* 2 Flags Attributes field, as described in section
|
||||
* 4.2.2.
|
||||
* 3..7 Filler Contains five octets of hex value FF.
|
||||
* 8..15 SND_SEQ Sequence number field in clear text,
|
||||
* expressed in big endian order.
|
||||
* expressed in big-endian order.
|
||||
* 16..last SGN_CKSUM Checksum of the "to-be-signed" data and
|
||||
* octet 0..15, as described in section 4.2.4.
|
||||
*
|
||||
* </pre>
|
||||
* <p>
|
||||
* This class is the super class of WrapToken_v2 and MicToken_v2. The token's
|
||||
* header (bytes[0..15]) and data (byte[16..]) are saved in tokenHeader and
|
||||
* tokenData fields. Since there is no easy way to find out the exact length
|
||||
* of a WrapToken_v2 token from any header info, in the case of reading from
|
||||
* stream, we read all available() bytes into the token.
|
||||
* <p>
|
||||
* All read actions are performed in this super class. On the write part, the
|
||||
* super class only write the tokenHeader, and the content writing is inside
|
||||
* child classes.
|
||||
*
|
||||
* @author Seema Malkani
|
||||
*/
|
||||
|
||||
abstract class MessageToken_v2 extends Krb5Token {
|
||||
|
||||
protected static final int TOKEN_HEADER_SIZE = 16;
|
||||
private static final int TOKEN_ID_POS = 0;
|
||||
private static final int TOKEN_FLAG_POS = 2;
|
||||
private static final int TOKEN_EC_POS = 4;
|
||||
private static final int TOKEN_RRC_POS = 6;
|
||||
|
||||
// token header size
|
||||
static final int TOKEN_HEADER_SIZE = 16;
|
||||
/**
|
||||
* The size of the random confounder used in a WrapToken.
|
||||
*/
|
||||
protected static final int CONFOUNDER_SIZE = 16;
|
||||
|
||||
private int tokenId = 0;
|
||||
private int seqNumber;
|
||||
|
||||
// EC and RRC fields
|
||||
private int ec = 0;
|
||||
private int rrc = 0;
|
||||
|
||||
private boolean confState = true;
|
||||
private boolean initiator = true;
|
||||
|
||||
byte[] confounder = null;
|
||||
byte[] checksum = null;
|
||||
|
||||
private int key_usage = 0;
|
||||
private byte[] seqNumberData = null;
|
||||
|
||||
private MessageTokenHeader tokenHeader = null;
|
||||
|
||||
/* cipher instance used by the corresponding GSSContext */
|
||||
CipherHelper cipherHelper = null;
|
||||
|
||||
// draft-ietf-krb-wg-gssapi-cfx-07
|
||||
// RFC 4121, key usage values
|
||||
static final int KG_USAGE_ACCEPTOR_SEAL = 22;
|
||||
static final int KG_USAGE_ACCEPTOR_SIGN = 23;
|
||||
static final int KG_USAGE_INITIATOR_SEAL = 24;
|
||||
static final int KG_USAGE_INITIATOR_SIGN = 25;
|
||||
|
||||
// draft-ietf-krb-wg-gssapi-cfx-07
|
||||
// RFC 4121, Flags Field
|
||||
private static final int FLAG_SENDER_IS_ACCEPTOR = 1;
|
||||
private static final int FLAG_WRAP_CONFIDENTIAL = 2;
|
||||
private static final int FLAG_ACCEPTOR_SUBKEY = 4;
|
||||
private static final int FILLER = 0xff;
|
||||
|
||||
private MessageTokenHeader tokenHeader = null;
|
||||
|
||||
// Common field
|
||||
private int tokenId = 0;
|
||||
private int seqNumber;
|
||||
protected byte[] tokenData; // content of token, without the header
|
||||
protected int tokenDataLen;
|
||||
|
||||
// Key usage number for crypto action
|
||||
private int key_usage = 0;
|
||||
|
||||
// EC and RRC fields, WrapToken only
|
||||
private int ec = 0;
|
||||
private int rrc = 0;
|
||||
|
||||
// Checksum. Always in MicToken, might be in WrapToken
|
||||
byte[] checksum = null;
|
||||
|
||||
// Context properties
|
||||
private boolean confState = true;
|
||||
private boolean initiator = true;
|
||||
|
||||
/* cipher instance used by the corresponding GSSContext */
|
||||
CipherHelper cipherHelper = null;
|
||||
|
||||
/**
|
||||
* Constructs a MessageToken from a byte array. If there are more bytes
|
||||
* in the array than needed, the extra bytes are simply ignroed.
|
||||
* Constructs a MessageToken from a byte array.
|
||||
*
|
||||
* @param tokenId the token id that should be contained in this token as
|
||||
* it is read.
|
||||
@ -156,7 +169,9 @@ abstract class MessageToken_v2 extends Krb5Token {
|
||||
/**
|
||||
* Constructs a MessageToken from an InputStream. Bytes will be read on
|
||||
* demand and the thread might block if there are not enough bytes to
|
||||
* complete the token.
|
||||
* complete the token. Please note there is no accurate way to find out
|
||||
* the size of a token, but we try our best to make sure there is
|
||||
* enough bytes to construct one.
|
||||
*
|
||||
* @param tokenId the token id that should be contained in this token as
|
||||
* it is read.
|
||||
@ -186,25 +201,58 @@ abstract class MessageToken_v2 extends Krb5Token {
|
||||
: KG_USAGE_ACCEPTOR_SIGN);
|
||||
}
|
||||
|
||||
// Read checksum
|
||||
int tokenLen = is.available();
|
||||
byte[] data = new byte[tokenLen];
|
||||
readFully(is, data);
|
||||
checksum = new byte[cipherHelper.getChecksumLength()];
|
||||
System.arraycopy(data, tokenLen-cipherHelper.getChecksumLength(),
|
||||
checksum, 0, cipherHelper.getChecksumLength());
|
||||
// debug("\nLeaving MessageToken.Cons\n");
|
||||
int minSize = 0; // minimal size for token data
|
||||
if (tokenId == Krb5Token.WRAP_ID_v2 && prop.getPrivacy()) {
|
||||
minSize = CONFOUNDER_SIZE +
|
||||
TOKEN_HEADER_SIZE + cipherHelper.getChecksumLength();
|
||||
} else {
|
||||
minSize = cipherHelper.getChecksumLength();
|
||||
}
|
||||
|
||||
// validate EC for Wrap tokens without confidentiality
|
||||
if (!prop.getPrivacy() &&
|
||||
(tokenId == Krb5Token.WRAP_ID_v2)) {
|
||||
if (checksum.length != ec) {
|
||||
throw new GSSException(GSSException.DEFECTIVE_TOKEN, -1,
|
||||
getTokenName(tokenId) + ":" + "EC incorrect!");
|
||||
// Read token data
|
||||
if (tokenId == Krb5Token.MIC_ID_v2) {
|
||||
// The only case we can precisely predict the token data length
|
||||
tokenDataLen = minSize;
|
||||
tokenData = new byte[minSize];
|
||||
readFully(is, tokenData);
|
||||
} else {
|
||||
tokenDataLen = is.available();
|
||||
if (tokenDataLen >= minSize) { // read in one shot
|
||||
tokenData = new byte[tokenDataLen];
|
||||
readFully(is, tokenData);
|
||||
} else {
|
||||
byte[] tmp = new byte[minSize];
|
||||
readFully(is, tmp);
|
||||
// Hope while blocked in the read above, more data would
|
||||
// come and is.available() below contains the whole token.
|
||||
int more = is.available();
|
||||
tokenDataLen = minSize + more;
|
||||
tokenData = Arrays.copyOf(tmp, tokenDataLen);
|
||||
readFully(is, tokenData, minSize, more);
|
||||
}
|
||||
}
|
||||
|
||||
if (tokenId == Krb5Token.WRAP_ID_v2) {
|
||||
// Does non-confidential data needs a rotate?
|
||||
rotate();
|
||||
}
|
||||
|
||||
if (tokenId == Krb5Token.MIC_ID_v2 ||
|
||||
(tokenId == Krb5Token.WRAP_ID_v2 && !prop.getPrivacy())) {
|
||||
// Read checksum
|
||||
int chkLen = cipherHelper.getChecksumLength();
|
||||
checksum = new byte[chkLen];
|
||||
System.arraycopy(tokenData, tokenDataLen-chkLen,
|
||||
checksum, 0, chkLen);
|
||||
|
||||
// validate EC for Wrap tokens without confidentiality
|
||||
if (tokenId == Krb5Token.WRAP_ID_v2 && !prop.getPrivacy()) {
|
||||
if (chkLen != ec) {
|
||||
throw new GSSException(GSSException.DEFECTIVE_TOKEN, -1,
|
||||
getTokenName(tokenId) + ":" + "EC incorrect!");
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (IOException e) {
|
||||
throw new GSSException(GSSException.DEFECTIVE_TOKEN, -1,
|
||||
getTokenName(tokenId) + ":" + e.getMessage());
|
||||
@ -263,8 +311,7 @@ abstract class MessageToken_v2 extends Krb5Token {
|
||||
prop.setPrivacy(false);
|
||||
}
|
||||
|
||||
// Create a new gss token header as defined in
|
||||
// draft-ietf-krb-wg-gssapi-cfx-07
|
||||
// Create a new gss token header as defined in RFC 4121
|
||||
tokenHeader = new MessageTokenHeader(tokenId,
|
||||
prop.getPrivacy(), true);
|
||||
// debug("\n\t Message Header = " +
|
||||
@ -326,50 +373,21 @@ abstract class MessageToken_v2 extends Krb5Token {
|
||||
* Rotate bytes as per the "RRC" (Right Rotation Count) received.
|
||||
* Our implementation does not do any rotates when sending, only
|
||||
* when receiving, we rotate left as per the RRC count, to revert it.
|
||||
*
|
||||
* @return true if bytes are rotated
|
||||
*/
|
||||
public boolean rotate_left(byte[] in_bytes, int tokenOffset,
|
||||
byte[] out_bytes, int bufsize) {
|
||||
private void rotate() {
|
||||
if (rrc % tokenDataLen != 0) {
|
||||
rrc = rrc % tokenDataLen;
|
||||
byte[] newBytes = new byte[tokenDataLen];
|
||||
|
||||
int offset = 0;
|
||||
// debug("\nRotate left: (before rotation) in_bytes = [ " +
|
||||
// getHexBytes(in_bytes, tokenOffset, bufsize) + "]");
|
||||
if (rrc > 0) {
|
||||
if (bufsize == 0) {
|
||||
return false;
|
||||
}
|
||||
rrc = rrc % (bufsize - TOKEN_HEADER_SIZE);
|
||||
if (rrc == 0) {
|
||||
return false;
|
||||
}
|
||||
System.arraycopy(tokenData, rrc, newBytes, 0, tokenDataLen-rrc);
|
||||
System.arraycopy(tokenData, 0, newBytes, tokenDataLen-rrc, rrc);
|
||||
|
||||
// if offset is not zero
|
||||
if (tokenOffset > 0) {
|
||||
offset += tokenOffset;
|
||||
}
|
||||
|
||||
// copy the header
|
||||
System.arraycopy(in_bytes, offset, out_bytes, 0, TOKEN_HEADER_SIZE);
|
||||
offset += TOKEN_HEADER_SIZE;
|
||||
|
||||
// copy rest of the bytes
|
||||
System.arraycopy(in_bytes, offset+rrc, out_bytes,
|
||||
TOKEN_HEADER_SIZE, bufsize-TOKEN_HEADER_SIZE-rrc);
|
||||
|
||||
// copy the bytes specified by rrc count
|
||||
System.arraycopy(in_bytes, offset, out_bytes,
|
||||
bufsize-TOKEN_HEADER_SIZE-rrc, rrc);
|
||||
|
||||
// debug("\nRotate left: (after rotation) out_bytes = [ " +
|
||||
// getHexBytes(out_bytes, 0, bufsize) + "]");
|
||||
return true;
|
||||
tokenData = newBytes;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public final int getSequenceNumber() {
|
||||
return (readBigEndian(seqNumberData, 0, 4));
|
||||
return seqNumber;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -444,44 +462,25 @@ abstract class MessageToken_v2 extends Krb5Token {
|
||||
|
||||
this.cipherHelper = context.getCipherHelper(null);
|
||||
// debug("In MessageToken.Cons");
|
||||
|
||||
// draft-ietf-krb-wg-gssapi-cfx-07
|
||||
this.tokenId = tokenId;
|
||||
}
|
||||
|
||||
/**
|
||||
* Encodes a GSSHeader and this token onto an OutputStream.
|
||||
* Encodes a MessageTokenHeader onto an OutputStream.
|
||||
*
|
||||
* @param os the OutputStream to which this should be written
|
||||
* @throws GSSException if an error occurs while writing to the OutputStream
|
||||
* @throws IOException is an error occurs while writing to the OutputStream
|
||||
*/
|
||||
public void encode(OutputStream os) throws IOException, GSSException {
|
||||
// debug("Writing tokenHeader " + getHexBytes(tokenHeader.getBytes());
|
||||
// (16 bytes of token header that includes sequence Number)
|
||||
protected void encodeHeader(OutputStream os) throws IOException {
|
||||
tokenHeader.encode(os);
|
||||
// debug("Writing checksum: " + getHexBytes(checksum));
|
||||
if (tokenId == MIC_ID_v2) {
|
||||
os.write(checksum);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Obtains the size of this token. Note that this excludes the size of
|
||||
* the GSSHeader.
|
||||
* @return token size
|
||||
* Encodes a MessageToken_v2 onto an OutputStream.
|
||||
*
|
||||
* @param os the OutputStream to which this should be written
|
||||
* @throws IOException is an error occurs while encoding the token
|
||||
*/
|
||||
protected int getKrb5TokenSize() throws GSSException {
|
||||
return getTokenSize();
|
||||
}
|
||||
|
||||
protected final int getTokenSize() throws GSSException {
|
||||
return (TOKEN_HEADER_SIZE + cipherHelper.getChecksumLength());
|
||||
}
|
||||
|
||||
protected static final int getTokenSize(CipherHelper ch)
|
||||
throws GSSException {
|
||||
return (TOKEN_HEADER_SIZE + ch.getChecksumLength());
|
||||
}
|
||||
public abstract void encode(OutputStream os) throws IOException;
|
||||
|
||||
protected final byte[] getTokenHeader() {
|
||||
return (tokenHeader.getBytes());
|
||||
@ -493,45 +492,14 @@ abstract class MessageToken_v2 extends Krb5Token {
|
||||
|
||||
/**
|
||||
* This inner class represents the initial portion of the message token.
|
||||
* It constitutes the first 16 bytes of the message token:
|
||||
* <pre>
|
||||
* Wrap Tokens
|
||||
*
|
||||
* Octet no Name Description
|
||||
* ---------------------------------------------------------------
|
||||
* 0..1 TOK_ID Identification field. Tokens emitted by
|
||||
* GSS_Wrap() contain the the hex value 05 04
|
||||
* expressed in big endian order in this field.
|
||||
* 2 Flags Attributes field, as described in section
|
||||
* 4.2.2.
|
||||
* 3 Filler Contains the hex value FF.
|
||||
* 4..5 EC Contains the "extra count" field, in big
|
||||
* endian order as described in section 4.2.3.
|
||||
* 6..7 RRC Contains the "right rotation count" in big
|
||||
* endian order, as described in section 4.2.5.
|
||||
* 8..15 SND_SEQ Sequence number field in clear text,
|
||||
* expressed in big endian order.
|
||||
*
|
||||
* MIC Tokens
|
||||
*
|
||||
* Octet no Name Description
|
||||
* -----------------------------------------------------------------
|
||||
* 0..1 TOK_ID Identification field. Tokens emitted by
|
||||
* GSS_GetMIC() contain the hex value 04 04
|
||||
* expressed in big endian order in this field.
|
||||
* 2 Flags Attributes field, as described in section
|
||||
* 4.2.2.
|
||||
* 3..7 Filler Contains five octets of hex value FF.
|
||||
* 8..15 SND_SEQ Sequence number field in clear text,
|
||||
* expressed in big endian order.
|
||||
* </pre>
|
||||
* It constitutes the first 16 bytes of the message token.
|
||||
*/
|
||||
class MessageTokenHeader {
|
||||
|
||||
private int tokenId;
|
||||
private byte[] bytes = new byte[TOKEN_HEADER_SIZE];
|
||||
|
||||
// new token header draft-ietf-krb-wg-gssapi-cfx-07
|
||||
// Writes a new token header
|
||||
public MessageTokenHeader(int tokenId, boolean conf,
|
||||
boolean have_acceptor_subkey) throws GSSException {
|
||||
|
||||
@ -542,16 +510,15 @@ abstract class MessageToken_v2 extends Krb5Token {
|
||||
|
||||
// Flags (Note: MIT impl requires subkey)
|
||||
int flags = 0;
|
||||
flags = ((initiator ? 0 : FLAG_SENDER_IS_ACCEPTOR) |
|
||||
flags = (initiator ? 0 : FLAG_SENDER_IS_ACCEPTOR) |
|
||||
((conf && tokenId != MIC_ID_v2) ?
|
||||
FLAG_WRAP_CONFIDENTIAL : 0) |
|
||||
(have_acceptor_subkey ? FLAG_ACCEPTOR_SUBKEY : 0));
|
||||
(have_acceptor_subkey ? FLAG_ACCEPTOR_SUBKEY : 0);
|
||||
bytes[2] = (byte) flags;
|
||||
|
||||
// filler
|
||||
bytes[3] = (byte) FILLER;
|
||||
|
||||
// EC and RRC fields
|
||||
if (tokenId == WRAP_ID_v2) {
|
||||
// EC field
|
||||
bytes[4] = (byte) 0;
|
||||
@ -560,21 +527,19 @@ abstract class MessageToken_v2 extends Krb5Token {
|
||||
bytes[6] = (byte) 0;
|
||||
bytes[7] = (byte) 0;
|
||||
} else if (tokenId == MIC_ID_v2) {
|
||||
// octets of filler FF
|
||||
// more filler for MicToken
|
||||
for (int i = 4; i < 8; i++) {
|
||||
bytes[i] = (byte) FILLER;
|
||||
}
|
||||
}
|
||||
|
||||
// Calculate SND_SEQ
|
||||
seqNumberData = new byte[8];
|
||||
writeBigEndian(seqNumber, seqNumberData, 4);
|
||||
System.arraycopy(seqNumberData, 0, bytes, 8, 8);
|
||||
// Calculate SND_SEQ, only write 4 bytes from the 12th position
|
||||
writeBigEndian(seqNumber, bytes, 12);
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a MessageTokenHeader by reading it from an InputStream
|
||||
* and sets the appropriate confidentiality and quality of protection
|
||||
* Reads a MessageTokenHeader from an InputStream and sets the
|
||||
* appropriate confidentiality and quality of protection
|
||||
* values in a MessageProp structure.
|
||||
*
|
||||
* @param is the InputStream to read from
|
||||
@ -588,15 +553,23 @@ abstract class MessageToken_v2 extends Krb5Token {
|
||||
readFully(is, bytes, 0, TOKEN_HEADER_SIZE);
|
||||
tokenId = readInt(bytes, TOKEN_ID_POS);
|
||||
|
||||
// validate Token ID
|
||||
if (tokenId != tokId) {
|
||||
throw new GSSException(GSSException.DEFECTIVE_TOKEN, -1,
|
||||
getTokenName(tokenId) + ":" + "Defective Token ID!");
|
||||
}
|
||||
|
||||
/*
|
||||
* Validate new GSS TokenHeader
|
||||
*/
|
||||
// valid acceptor_flag is set
|
||||
|
||||
// valid acceptor_flag
|
||||
// If I am initiator, the received token should have ACCEPTOR on
|
||||
int acceptor_flag = (initiator ? FLAG_SENDER_IS_ACCEPTOR : 0);
|
||||
int flag = bytes[TOKEN_FLAG_POS] & FLAG_SENDER_IS_ACCEPTOR;
|
||||
if (!(flag == acceptor_flag)) {
|
||||
if (flag != acceptor_flag) {
|
||||
throw new GSSException(GSSException.DEFECTIVE_TOKEN, -1,
|
||||
getTokenName(tokenId) + ":" + "Acceptor Flag Missing!");
|
||||
getTokenName(tokenId) + ":" + "Acceptor Flag Error!");
|
||||
}
|
||||
|
||||
// check for confidentiality
|
||||
@ -608,21 +581,20 @@ abstract class MessageToken_v2 extends Krb5Token {
|
||||
prop.setPrivacy(false);
|
||||
}
|
||||
|
||||
// validate Token ID
|
||||
if (tokenId != tokId) {
|
||||
throw new GSSException(GSSException.DEFECTIVE_TOKEN, -1,
|
||||
getTokenName(tokenId) + ":" + "Defective Token ID!");
|
||||
}
|
||||
if (tokenId == WRAP_ID_v2) {
|
||||
// validate filler
|
||||
if ((bytes[3] & 0xff) != FILLER) {
|
||||
throw new GSSException(GSSException.DEFECTIVE_TOKEN, -1,
|
||||
getTokenName(tokenId) + ":" + "Defective Token Filler!");
|
||||
}
|
||||
|
||||
// validate filler
|
||||
if ((bytes[3] & 0xff) != FILLER) {
|
||||
throw new GSSException(GSSException.DEFECTIVE_TOKEN, -1,
|
||||
getTokenName(tokenId) + ":" + "Defective Token Filler!");
|
||||
}
|
||||
// read EC field
|
||||
ec = readBigEndian(bytes, TOKEN_EC_POS, 2);
|
||||
|
||||
// validate next 4 bytes of filler for MIC tokens
|
||||
if (tokenId == MIC_ID_v2) {
|
||||
for (int i = 4; i < 8; i++) {
|
||||
// read RRC field
|
||||
rrc = readBigEndian(bytes, TOKEN_RRC_POS, 2);
|
||||
} else if (tokenId == MIC_ID_v2) {
|
||||
for (int i = 3; i < 8; i++) {
|
||||
if ((bytes[i] & 0xff) != FILLER) {
|
||||
throw new GSSException(GSSException.DEFECTIVE_TOKEN,
|
||||
-1, getTokenName(tokenId) + ":" +
|
||||
@ -631,18 +603,11 @@ abstract class MessageToken_v2 extends Krb5Token {
|
||||
}
|
||||
}
|
||||
|
||||
// read EC field
|
||||
ec = readBigEndian(bytes, TOKEN_EC_POS, 2);
|
||||
|
||||
// read RRC field
|
||||
rrc = readBigEndian(bytes, TOKEN_RRC_POS, 2);
|
||||
|
||||
// set default QOP
|
||||
prop.setQOP(0);
|
||||
|
||||
// sequence number
|
||||
seqNumberData = new byte[8];
|
||||
System.arraycopy(bytes, 8, seqNumberData, 0, 8);
|
||||
seqNumber = readBigEndian(bytes, 0, 8);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2004, 2006, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2004, 2010, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
@ -29,12 +29,11 @@ import org.ietf.jgss.*;
|
||||
import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.ByteArrayOutputStream;
|
||||
|
||||
/**
|
||||
* This class represents the new format of GSS MIC tokens, as specified
|
||||
* in draft-ietf-krb-wg-gssapi-cfx-07.txt
|
||||
* in RFC 4121
|
||||
*
|
||||
* MIC tokens = { 16-byte token-header | HMAC }
|
||||
* where HMAC is on { plaintext | 16-byte token-header }
|
||||
@ -48,12 +47,11 @@ class MicToken_v2 extends MessageToken_v2 {
|
||||
byte[] tokenBytes, int tokenOffset, int tokenLen,
|
||||
MessageProp prop) throws GSSException {
|
||||
super(Krb5Token.MIC_ID_v2, context,
|
||||
tokenBytes, tokenOffset, tokenLen, prop);
|
||||
tokenBytes, tokenOffset, tokenLen, prop);
|
||||
}
|
||||
|
||||
public MicToken_v2(Krb5Context context,
|
||||
InputStream is, MessageProp prop)
|
||||
throws GSSException {
|
||||
public MicToken_v2(Krb5Context context, InputStream is, MessageProp prop)
|
||||
throws GSSException {
|
||||
super(Krb5Token.MIC_ID_v2, context, is, prop);
|
||||
}
|
||||
|
||||
@ -64,7 +62,6 @@ class MicToken_v2 extends MessageToken_v2 {
|
||||
}
|
||||
|
||||
public void verify(InputStream data) throws GSSException {
|
||||
|
||||
byte[] dataBytes = null;
|
||||
try {
|
||||
dataBytes = new byte[data.available()];
|
||||
@ -79,7 +76,7 @@ class MicToken_v2 extends MessageToken_v2 {
|
||||
|
||||
public MicToken_v2(Krb5Context context, MessageProp prop,
|
||||
byte[] data, int pos, int len)
|
||||
throws GSSException {
|
||||
throws GSSException {
|
||||
super(Krb5Token.MIC_ID_v2, context);
|
||||
|
||||
// debug("Application data to MicToken verify is [" +
|
||||
@ -89,7 +86,7 @@ class MicToken_v2 extends MessageToken_v2 {
|
||||
}
|
||||
|
||||
public MicToken_v2(Krb5Context context, MessageProp prop, InputStream data)
|
||||
throws GSSException, IOException {
|
||||
throws GSSException, IOException {
|
||||
|
||||
super(Krb5Token.MIC_ID_v2, context);
|
||||
byte[] dataBytes = new byte[data.available()];
|
||||
@ -101,22 +98,21 @@ class MicToken_v2 extends MessageToken_v2 {
|
||||
genSignAndSeqNumber(prop, dataBytes, 0, dataBytes.length);
|
||||
}
|
||||
|
||||
public int encode(byte[] outToken, int offset)
|
||||
throws IOException, GSSException {
|
||||
|
||||
// Token is small
|
||||
ByteArrayOutputStream bos = new ByteArrayOutputStream();
|
||||
super.encode(bos);
|
||||
byte[] token = bos.toByteArray();
|
||||
System.arraycopy(token, 0, outToken, offset, token.length);
|
||||
return token.length;
|
||||
}
|
||||
|
||||
public byte[] encode() throws IOException, GSSException {
|
||||
|
||||
public byte[] encode() throws IOException {
|
||||
// XXX Fine tune this initial size
|
||||
ByteArrayOutputStream bos = new ByteArrayOutputStream(50);
|
||||
encode(bos);
|
||||
return bos.toByteArray();
|
||||
}
|
||||
|
||||
public int encode(byte[] outToken, int offset) throws IOException {
|
||||
byte[] token = encode();
|
||||
System.arraycopy(token, 0, outToken, offset, token.length);
|
||||
return token.length;
|
||||
}
|
||||
|
||||
public void encode(OutputStream os) throws IOException {
|
||||
encodeHeader(os);
|
||||
os.write(checksum);
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2000, 2007, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2000, 2010, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
@ -27,14 +27,11 @@ package sun.security.jgss.krb5;
|
||||
|
||||
import org.ietf.jgss.*;
|
||||
import sun.security.jgss.*;
|
||||
import java.security.GeneralSecurityException;
|
||||
import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import sun.security.krb5.Confounder;
|
||||
import sun.security.krb5.KrbException;
|
||||
|
||||
/**
|
||||
* This class represents a token emitted by the GSSContext.wrap()
|
||||
@ -336,24 +333,29 @@ class WrapToken extends MessageToken {
|
||||
// debug("\t\tNo encryption was performed by peer.\n");
|
||||
readFully(is, confounder);
|
||||
|
||||
// Data is always a multiple of 8 with this GSS Mech
|
||||
// Copy all but last block as they are
|
||||
int numBlocks = (dataSize - CONFOUNDER_SIZE)/8 - 1;
|
||||
int offset = dataBufOffset;
|
||||
for (int i = 0; i < numBlocks; i++) {
|
||||
readFully(is, dataBuf, offset, 8);
|
||||
offset += 8;
|
||||
if (cipherHelper.isArcFour()) {
|
||||
padding = pads[1];
|
||||
readFully(is, dataBuf, dataBufOffset, dataSize-CONFOUNDER_SIZE-1);
|
||||
} else {
|
||||
// Data is always a multiple of 8 with this GSS Mech
|
||||
// Copy all but last block as they are
|
||||
int numBlocks = (dataSize - CONFOUNDER_SIZE)/8 - 1;
|
||||
int offset = dataBufOffset;
|
||||
for (int i = 0; i < numBlocks; i++) {
|
||||
readFully(is, dataBuf, offset, 8);
|
||||
offset += 8;
|
||||
}
|
||||
|
||||
byte[] finalBlock = new byte[8];
|
||||
readFully(is, finalBlock);
|
||||
|
||||
int padSize = finalBlock[7];
|
||||
padding = pads[padSize];
|
||||
|
||||
// debug("\t\tPadding applied was: " + padSize + "\n");
|
||||
System.arraycopy(finalBlock, 0, dataBuf, offset,
|
||||
finalBlock.length - padSize);
|
||||
}
|
||||
|
||||
byte[] finalBlock = new byte[8];
|
||||
readFully(is, finalBlock);
|
||||
|
||||
int padSize = finalBlock[7];
|
||||
padding = pads[padSize];
|
||||
|
||||
// debug("\t\tPadding applied was: " + padSize + "\n");
|
||||
System.arraycopy(finalBlock, 0, dataBuf, offset,
|
||||
finalBlock.length - padSize);
|
||||
}
|
||||
} catch (IOException e) {
|
||||
throw new GSSException(GSSException.DEFECTIVE_TOKEN, -1,
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2004, 2007, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2004, 2010, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
@ -27,66 +27,30 @@ package sun.security.jgss.krb5;
|
||||
|
||||
import org.ietf.jgss.*;
|
||||
import sun.security.jgss.*;
|
||||
import java.security.GeneralSecurityException;
|
||||
import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.util.Arrays;
|
||||
import sun.security.krb5.Confounder;
|
||||
import sun.security.krb5.KrbException;
|
||||
|
||||
/**
|
||||
* This class represents the new format of GSS tokens, as specified in
|
||||
* draft-ietf-krb-wg-gssapi-cfx-07.txt, emitted by the GSSContext.wrap()
|
||||
* call. It is a MessageToken except that it also contains plaintext or
|
||||
* encrypted data at the end. A WrapToken has certain other rules that are
|
||||
* peculiar to it and different from a MICToken, which is another type of
|
||||
* MessageToken. All data in a WrapToken is prepended by a random counfounder
|
||||
* of 16 bytes. Thus, all application data is replaced by
|
||||
* (confounder || data || tokenHeader || checksum).
|
||||
* This class represents the new format of GSS tokens, as specified in RFC
|
||||
* 4121, emitted by the GSSContext.wrap() call. It is a MessageToken except
|
||||
* that it also contains plaintext or encrypted data at the end. A WrapToken
|
||||
* has certain other rules that are peculiar to it and different from a
|
||||
* MICToken, which is another type of MessageToken. All data in a WrapToken is
|
||||
* prepended by a random confounder of 16 bytes. Thus, all application data
|
||||
* is replaced by (confounder || data || tokenHeader || checksum).
|
||||
*
|
||||
* @author Seema Malkani
|
||||
*/
|
||||
class WrapToken_v2 extends MessageToken_v2 {
|
||||
/**
|
||||
* The size of the random confounder used in a WrapToken.
|
||||
*/
|
||||
static final int CONFOUNDER_SIZE = 16;
|
||||
|
||||
/*
|
||||
* A token may come in either in an InputStream or as a
|
||||
* byte[]. Store a reference to it in either case and process
|
||||
* it's data only later when getData() is called and
|
||||
* decryption/copying is needed to be done. Note that JCE can
|
||||
* decrypt both from a byte[] and from an InputStream.
|
||||
*/
|
||||
private boolean readTokenFromInputStream = true;
|
||||
private InputStream is = null;
|
||||
private byte[] tokenBytes = null;
|
||||
private int tokenOffset = 0;
|
||||
private int tokenLen = 0;
|
||||
|
||||
/*
|
||||
* Application data may come from an InputStream or from a
|
||||
* byte[]. However, it will always be stored and processed as a
|
||||
* byte[] since
|
||||
* (a) the MessageDigest class only accepts a byte[] as input and
|
||||
* (b) It allows writing to an OuputStream via a CipherOutputStream.
|
||||
*/
|
||||
private byte[] dataBytes = null;
|
||||
private int dataOffset = 0;
|
||||
private int dataLen = 0;
|
||||
|
||||
// the len of the token data:
|
||||
// (confounder || data || tokenHeader || checksum)
|
||||
private int dataSize = 0;
|
||||
|
||||
// Accessed by CipherHelper
|
||||
byte[] confounder = null;
|
||||
|
||||
private boolean privacy = false;
|
||||
private boolean initiator = true;
|
||||
private final boolean privacy;
|
||||
|
||||
/**
|
||||
* Constructs a WrapToken from token bytes obtained from the
|
||||
@ -104,30 +68,9 @@ class WrapToken_v2 extends MessageToken_v2 {
|
||||
byte[] tokenBytes, int tokenOffset, int tokenLen,
|
||||
MessageProp prop) throws GSSException {
|
||||
|
||||
// Just parse the MessageToken part first
|
||||
super(Krb5Token.WRAP_ID_v2, context,
|
||||
tokenBytes, tokenOffset, tokenLen, prop);
|
||||
this.readTokenFromInputStream = false;
|
||||
|
||||
// rotate token bytes as per RRC
|
||||
byte[] new_tokenBytes = new byte[tokenLen];
|
||||
if (rotate_left(tokenBytes, tokenOffset, new_tokenBytes, tokenLen)) {
|
||||
this.tokenBytes = new_tokenBytes;
|
||||
this.tokenOffset = 0;
|
||||
} else {
|
||||
this.tokenBytes = tokenBytes;
|
||||
this.tokenOffset = tokenOffset;
|
||||
}
|
||||
|
||||
// Will need the token bytes again when extracting data
|
||||
this.tokenLen = tokenLen;
|
||||
this.privacy = prop.getPrivacy();
|
||||
|
||||
dataSize = tokenLen - TOKEN_HEADER_SIZE;
|
||||
|
||||
// save initiator
|
||||
this.initiator = context.isInitiator();
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
@ -145,27 +88,8 @@ class WrapToken_v2 extends MessageToken_v2 {
|
||||
InputStream is, MessageProp prop)
|
||||
throws GSSException {
|
||||
|
||||
// Just parse the MessageToken part first
|
||||
super(Krb5Token.WRAP_ID_v2, context, is, prop);
|
||||
|
||||
// Will need the token bytes again when extracting data
|
||||
this.is = is;
|
||||
this.privacy = prop.getPrivacy();
|
||||
|
||||
// get the token length
|
||||
try {
|
||||
this.tokenLen = is.available();
|
||||
} catch (IOException e) {
|
||||
throw new GSSException(GSSException.DEFECTIVE_TOKEN, -1,
|
||||
getTokenName(getTokenId())
|
||||
+ ": " + e.getMessage());
|
||||
}
|
||||
|
||||
// data size
|
||||
dataSize = tokenLen - TOKEN_HEADER_SIZE;
|
||||
|
||||
// save initiator
|
||||
this.initiator = context.isInitiator();
|
||||
}
|
||||
|
||||
/**
|
||||
@ -177,13 +101,9 @@ class WrapToken_v2 extends MessageToken_v2 {
|
||||
*/
|
||||
public byte[] getData() throws GSSException {
|
||||
|
||||
byte[] temp = new byte[dataSize];
|
||||
byte[] temp = new byte[tokenDataLen];
|
||||
int len = getData(temp, 0);
|
||||
// len obtained is after removing confounder, tokenHeader and HMAC
|
||||
|
||||
byte[] retVal = new byte[len];
|
||||
System.arraycopy(temp, 0, retVal, 0, retVal.length);
|
||||
return retVal;
|
||||
return Arrays.copyOf(temp, len);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -200,69 +120,26 @@ class WrapToken_v2 extends MessageToken_v2 {
|
||||
public int getData(byte[] dataBuf, int dataBufOffset)
|
||||
throws GSSException {
|
||||
|
||||
if (readTokenFromInputStream)
|
||||
getDataFromStream(dataBuf, dataBufOffset);
|
||||
else
|
||||
getDataFromBuffer(dataBuf, dataBufOffset);
|
||||
|
||||
int retVal = 0;
|
||||
if (privacy) {
|
||||
retVal = dataSize - confounder.length -
|
||||
TOKEN_HEADER_SIZE - cipherHelper.getChecksumLength();
|
||||
} else {
|
||||
retVal = dataSize - cipherHelper.getChecksumLength();
|
||||
}
|
||||
return retVal;
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper routine to obtain the application data transmitted in
|
||||
* this WrapToken. It is called if the WrapToken was constructed
|
||||
* with a byte array as input.
|
||||
* @param dataBuf the output buffer into which the data must be
|
||||
* written
|
||||
* @param dataBufOffset the offset at which to write the data
|
||||
* @throws GSSException if an error occurs while decrypting any
|
||||
* cipher text and checking for validity
|
||||
*/
|
||||
private void getDataFromBuffer(byte[] dataBuf, int dataBufOffset)
|
||||
throws GSSException {
|
||||
|
||||
int dataPos = tokenOffset + TOKEN_HEADER_SIZE;
|
||||
int data_length = 0;
|
||||
|
||||
if (dataPos + dataSize > tokenOffset + tokenLen)
|
||||
throw new GSSException(GSSException.DEFECTIVE_TOKEN, -1,
|
||||
"Insufficient data in "
|
||||
+ getTokenName(getTokenId()));
|
||||
// debug("WrapToken cons: data is token is [" +
|
||||
// getHexBytes(tokenBytes, tokenOffset, tokenLen) + "]\n");
|
||||
confounder = new byte[CONFOUNDER_SIZE];
|
||||
|
||||
// Do decryption if this token was privacy protected.
|
||||
if (privacy) {
|
||||
|
||||
// decrypt data
|
||||
cipherHelper.decryptData(this, tokenBytes, dataPos, dataSize,
|
||||
cipherHelper.decryptData(this, tokenData, 0, tokenDataLen,
|
||||
dataBuf, dataBufOffset, getKeyUsage());
|
||||
/*
|
||||
debug("\t\tDecrypted data is [" +
|
||||
getHexBytes(confounder) + " " +
|
||||
getHexBytes(dataBuf, dataBufOffset,
|
||||
dataSize - CONFOUNDER_SIZE) +
|
||||
"]\n");
|
||||
*/
|
||||
|
||||
data_length = dataSize - CONFOUNDER_SIZE -
|
||||
TOKEN_HEADER_SIZE - cipherHelper.getChecksumLength();
|
||||
return tokenDataLen - CONFOUNDER_SIZE -
|
||||
TOKEN_HEADER_SIZE - cipherHelper.getChecksumLength();
|
||||
} else {
|
||||
|
||||
// Token data is in cleartext
|
||||
debug("\t\tNo encryption was performed by peer.\n");
|
||||
// debug("\t\tNo encryption was performed by peer.\n");
|
||||
|
||||
// data
|
||||
data_length = dataSize - cipherHelper.getChecksumLength();
|
||||
System.arraycopy(tokenBytes, dataPos,
|
||||
int data_length = tokenDataLen - cipherHelper.getChecksumLength();
|
||||
System.arraycopy(tokenData, 0,
|
||||
dataBuf, dataBufOffset,
|
||||
data_length);
|
||||
// debug("\t\tData is: " + getHexBytes(dataBuf, data_length));
|
||||
@ -274,95 +151,26 @@ class WrapToken_v2 extends MessageToken_v2 {
|
||||
throw new GSSException(GSSException.BAD_MIC, -1,
|
||||
"Corrupt checksum in Wrap token");
|
||||
}
|
||||
return data_length;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper routine to obtain the application data transmitted in
|
||||
* this WrapToken. It is called if the WrapToken was constructed
|
||||
* with an Inputstream.
|
||||
* @param dataBuf the output buffer into which the data must be
|
||||
* written
|
||||
* @param dataBufOffset the offset at which to write the data
|
||||
* @throws GSSException if an error occurs while decrypting any
|
||||
* cipher text and checking for validity
|
||||
* Writes a WrapToken_v2 object
|
||||
*/
|
||||
private void getDataFromStream(byte[] dataBuf, int dataBufOffset)
|
||||
throws GSSException {
|
||||
|
||||
int data_length = 0;
|
||||
// Don't check the token length. Data will be read on demand from
|
||||
// the InputStream.
|
||||
// debug("WrapToken cons: data will be read from InputStream.\n");
|
||||
|
||||
confounder = new byte[CONFOUNDER_SIZE];
|
||||
|
||||
try {
|
||||
// Do decryption if this token was privacy protected.
|
||||
if (privacy) {
|
||||
|
||||
cipherHelper.decryptData(this, is, dataSize,
|
||||
dataBuf, dataBufOffset, getKeyUsage());
|
||||
|
||||
/*
|
||||
debug("\t\tDecrypted data is [" +
|
||||
getHexBytes(confounder) + " " +
|
||||
getHexBytes(dataBuf, dataBufOffset,
|
||||
dataSize - CONFOUNDER_SIZE) +
|
||||
"]\n");
|
||||
*/
|
||||
data_length = dataSize - CONFOUNDER_SIZE -
|
||||
TOKEN_HEADER_SIZE - cipherHelper.getChecksumLength();
|
||||
} else {
|
||||
|
||||
// Token data is in cleartext
|
||||
debug("\t\tNo encryption was performed by peer.\n");
|
||||
readFully(is, confounder);
|
||||
|
||||
// read the data
|
||||
data_length = dataSize - cipherHelper.getChecksumLength();
|
||||
readFully(is, dataBuf, dataBufOffset, data_length);
|
||||
|
||||
/*
|
||||
* Make sure checksum is not corrupt
|
||||
*/
|
||||
if (!verifySign(dataBuf, dataBufOffset, data_length)) {
|
||||
throw new GSSException(GSSException.BAD_MIC, -1,
|
||||
"Corrupt checksum in Wrap token");
|
||||
}
|
||||
}
|
||||
} catch (IOException e) {
|
||||
throw new GSSException(GSSException.DEFECTIVE_TOKEN, -1,
|
||||
getTokenName(getTokenId())
|
||||
+ ": " + e.getMessage());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
public WrapToken_v2(Krb5Context context, MessageProp prop,
|
||||
byte[] dataBytes, int dataOffset, int dataLen)
|
||||
throws GSSException {
|
||||
throws GSSException {
|
||||
|
||||
super(Krb5Token.WRAP_ID_v2, context);
|
||||
|
||||
confounder = Confounder.bytes(CONFOUNDER_SIZE);
|
||||
|
||||
dataSize = confounder.length + dataLen + TOKEN_HEADER_SIZE +
|
||||
cipherHelper.getChecksumLength();
|
||||
this.dataBytes = dataBytes;
|
||||
this.dataOffset = dataOffset;
|
||||
this.dataLen = dataLen;
|
||||
|
||||
// save initiator
|
||||
this.initiator = context.isInitiator();
|
||||
|
||||
// debug("\nWrapToken cons: data to wrap is [" +
|
||||
// getHexBytes(confounder) + " " +
|
||||
// getHexBytes(dataBytes, dataOffset, dataLen) + "]\n");
|
||||
|
||||
genSignAndSeqNumber(prop,
|
||||
dataBytes, dataOffset, dataLen);
|
||||
genSignAndSeqNumber(prop, dataBytes, dataOffset, dataLen);
|
||||
|
||||
/*
|
||||
* If the application decides to ask for privacy when the context
|
||||
@ -374,110 +182,42 @@ class WrapToken_v2 extends MessageToken_v2 {
|
||||
prop.setPrivacy(false);
|
||||
|
||||
privacy = prop.getPrivacy();
|
||||
}
|
||||
|
||||
public void encode(OutputStream os) throws IOException, GSSException {
|
||||
|
||||
super.encode(os);
|
||||
|
||||
// debug("\n\nWriting data: [");
|
||||
if (!privacy) {
|
||||
|
||||
// Wrap Tokens (without confidentiality) =
|
||||
// { 16 byte token_header | plaintext | 12-byte HMAC }
|
||||
// where HMAC is on { plaintext | token_header }
|
||||
|
||||
// calculate checksum
|
||||
byte[] checksum = getChecksum(dataBytes, dataOffset, dataLen);
|
||||
|
||||
// data
|
||||
// debug(" " + getHexBytes(dataBytes, dataOffset, dataLen));
|
||||
os.write(dataBytes, dataOffset, dataLen);
|
||||
|
||||
// write HMAC
|
||||
// debug(" " + getHexBytes(checksum,
|
||||
// cipherHelper.getChecksumLength()));
|
||||
os.write(checksum);
|
||||
|
||||
tokenData = new byte[dataLen + checksum.length];
|
||||
System.arraycopy(dataBytes, dataOffset, tokenData, 0, dataLen);
|
||||
System.arraycopy(checksum, 0, tokenData, dataLen, checksum.length);
|
||||
} else {
|
||||
|
||||
// Wrap Tokens (with confidentiality) =
|
||||
// { 16 byte token_header |
|
||||
// Encrypt(16-byte confounder | plaintext | token_header) |
|
||||
// 12-byte HMAC }
|
||||
|
||||
cipherHelper.encryptData(this, confounder, getTokenHeader(),
|
||||
dataBytes, dataOffset, dataLen, getKeyUsage(), os);
|
||||
|
||||
tokenData = cipherHelper.encryptData(this, confounder, getTokenHeader(),
|
||||
dataBytes, dataOffset, dataLen, getKeyUsage());
|
||||
}
|
||||
// debug("]\n");
|
||||
}
|
||||
|
||||
public byte[] encode() throws IOException, GSSException {
|
||||
// XXX Fine tune this initial size
|
||||
ByteArrayOutputStream bos = new ByteArrayOutputStream(dataSize + 50);
|
||||
public void encode(OutputStream os) throws IOException {
|
||||
encodeHeader(os);
|
||||
os.write(tokenData);
|
||||
}
|
||||
|
||||
public byte[] encode() throws IOException {
|
||||
ByteArrayOutputStream bos = new ByteArrayOutputStream(
|
||||
MessageToken_v2.TOKEN_HEADER_SIZE + tokenData.length);
|
||||
encode(bos);
|
||||
return bos.toByteArray();
|
||||
}
|
||||
|
||||
public int encode(byte[] outToken, int offset)
|
||||
throws IOException, GSSException {
|
||||
|
||||
int retVal = 0;
|
||||
|
||||
// Token header is small
|
||||
ByteArrayOutputStream bos = new ByteArrayOutputStream();
|
||||
super.encode(bos);
|
||||
byte[] header = bos.toByteArray();
|
||||
System.arraycopy(header, 0, outToken, offset, header.length);
|
||||
offset += header.length;
|
||||
|
||||
// debug("WrapToken.encode: Writing data: [");
|
||||
if (!privacy) {
|
||||
|
||||
// Wrap Tokens (without confidentiality) =
|
||||
// { 16 byte token_header | plaintext | 12-byte HMAC }
|
||||
// where HMAC is on { plaintext | token_header }
|
||||
|
||||
// calculate checksum
|
||||
byte[] checksum = getChecksum(dataBytes, dataOffset, dataLen);
|
||||
|
||||
// data
|
||||
// debug(" " + getHexBytes(dataBytes, dataOffset, dataLen));
|
||||
System.arraycopy(dataBytes, dataOffset, outToken, offset,
|
||||
dataLen);
|
||||
offset += dataLen;
|
||||
|
||||
// write HMAC
|
||||
// debug(" " + getHexBytes(checksum,
|
||||
// cipherHelper.getChecksumLength()));
|
||||
System.arraycopy(checksum, 0, outToken, offset,
|
||||
cipherHelper.getChecksumLength());
|
||||
|
||||
retVal = header.length + dataLen + cipherHelper.getChecksumLength();
|
||||
} else {
|
||||
|
||||
// Wrap Tokens (with confidentiality) =
|
||||
// { 16 byte token_header |
|
||||
// Encrypt(16-byte confounder | plaintext | token_header) |
|
||||
// 12-byte HMAC }
|
||||
int cLen = cipherHelper.encryptData(this, confounder,
|
||||
getTokenHeader(), dataBytes, dataOffset, dataLen,
|
||||
outToken, offset, getKeyUsage());
|
||||
|
||||
retVal = header.length + cLen;
|
||||
// debug(getHexBytes(outToken, offset, dataSize));
|
||||
}
|
||||
|
||||
// debug("]\n");
|
||||
|
||||
// %%% assume that plaintext length == ciphertext len
|
||||
return retVal;
|
||||
|
||||
}
|
||||
|
||||
protected int getKrb5TokenSize() throws GSSException {
|
||||
return (getTokenSize() + dataSize);
|
||||
public int encode(byte[] outToken, int offset) throws IOException {
|
||||
byte[] token = encode();
|
||||
System.arraycopy(token, 0, outToken, offset, token.length);
|
||||
return token.length;
|
||||
}
|
||||
|
||||
// This implementation is way to conservative. And it certainly
|
||||
@ -485,6 +225,7 @@ class WrapToken_v2 extends MessageToken_v2 {
|
||||
static int getSizeLimit(int qop, boolean confReq, int maxTokenSize,
|
||||
CipherHelper ch) throws GSSException {
|
||||
return (GSSHeader.getMaxMechTokenSize(OID, maxTokenSize) -
|
||||
(getTokenSize(ch) + CONFOUNDER_SIZE) - 8 /* safety */);
|
||||
(TOKEN_HEADER_SIZE + ch.getChecksumLength() + CONFOUNDER_SIZE)
|
||||
- 8 /* safety */);
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2008, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
@ -25,6 +25,34 @@
|
||||
* @test
|
||||
* @bug 6706974
|
||||
* @summary Add krb5 test infrastructure
|
||||
* @run main/othervm BasicKrb5Test
|
||||
* @run main/othervm BasicKrb5Test des-cbc-crc
|
||||
* @run main/othervm BasicKrb5Test des-cbc-md5
|
||||
* @run main/othervm BasicKrb5Test des3-cbc-sha1
|
||||
* @run main/othervm BasicKrb5Test aes128-cts
|
||||
* @run main/othervm BasicKrb5Test aes256-cts
|
||||
* @run main/othervm BasicKrb5Test rc4-hmac
|
||||
* @run main/othervm BasicKrb5Test -s
|
||||
* @run main/othervm BasicKrb5Test des-cbc-crc -s
|
||||
* @run main/othervm BasicKrb5Test des-cbc-md5 -s
|
||||
* @run main/othervm BasicKrb5Test des3-cbc-sha1 -s
|
||||
* @run main/othervm BasicKrb5Test aes128-cts -s
|
||||
* @run main/othervm BasicKrb5Test aes256-cts -s
|
||||
* @run main/othervm BasicKrb5Test rc4-hmac -s
|
||||
* @run main/othervm BasicKrb5Test -C
|
||||
* @run main/othervm BasicKrb5Test des-cbc-crc -C
|
||||
* @run main/othervm BasicKrb5Test des-cbc-md5 -C
|
||||
* @run main/othervm BasicKrb5Test des3-cbc-sha1 -C
|
||||
* @run main/othervm BasicKrb5Test aes128-cts -C
|
||||
* @run main/othervm BasicKrb5Test aes256-cts -C
|
||||
* @run main/othervm BasicKrb5Test rc4-hmac -C
|
||||
* @run main/othervm BasicKrb5Test -s -C
|
||||
* @run main/othervm BasicKrb5Test des-cbc-crc -s -C
|
||||
* @run main/othervm BasicKrb5Test des-cbc-md5 -s -C
|
||||
* @run main/othervm BasicKrb5Test des3-cbc-sha1 -s -C
|
||||
* @run main/othervm BasicKrb5Test aes128-cts -s -C
|
||||
* @run main/othervm BasicKrb5Test aes256-cts -s -C
|
||||
* @run main/othervm BasicKrb5Test rc4-hmac -s -C
|
||||
*/
|
||||
|
||||
import org.ietf.jgss.GSSName;
|
||||
@ -39,6 +67,7 @@ import sun.security.krb5.internal.crypto.EType;
|
||||
*/
|
||||
public class BasicKrb5Test {
|
||||
|
||||
private static boolean conf = true;
|
||||
/**
|
||||
* @param args empty or etype
|
||||
*/
|
||||
@ -46,8 +75,10 @@ public class BasicKrb5Test {
|
||||
throws Exception {
|
||||
|
||||
String etype = null;
|
||||
if (args.length > 0) {
|
||||
etype = args[0];
|
||||
for (String arg: args) {
|
||||
if (arg.equals("-s")) Context.usingStream = true;
|
||||
else if(arg.equals("-C")) conf = false;
|
||||
else etype = arg;
|
||||
}
|
||||
|
||||
// Creates and starts the KDC. This line must be put ahead of etype check
|
||||
@ -56,8 +87,9 @@ public class BasicKrb5Test {
|
||||
|
||||
System.out.println("Testing etype " + etype);
|
||||
if (etype != null && !EType.isSupported(Config.getInstance().getType(etype))) {
|
||||
// aes256 is not enabled on all systems
|
||||
System.out.println("Not supported.");
|
||||
System.exit(0);
|
||||
return;
|
||||
}
|
||||
|
||||
new BasicKrb5Test().go(OneKDC.SERVER, OneKDC.BACKEND);
|
||||
@ -71,6 +103,7 @@ public class BasicKrb5Test {
|
||||
|
||||
c.startAsClient(server, GSSUtil.GSS_KRB5_MECH_OID);
|
||||
c.x().requestCredDeleg(true);
|
||||
c.x().requestConf(conf);
|
||||
s.startAsServer(GSSUtil.GSS_KRB5_MECH_OID);
|
||||
|
||||
c.status();
|
||||
@ -90,6 +123,7 @@ public class BasicKrb5Test {
|
||||
s = null;
|
||||
|
||||
s2.startAsClient(backend, GSSUtil.GSS_KRB5_MECH_OID);
|
||||
s2.x().requestConf(conf);
|
||||
b.startAsServer(GSSUtil.GSS_KRB5_MECH_OID);
|
||||
|
||||
s2.status();
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2008, 2009, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
@ -42,7 +42,8 @@ import org.ietf.jgss.Oid;
|
||||
import com.sun.security.jgss.ExtendedGSSContext;
|
||||
import com.sun.security.jgss.InquireType;
|
||||
import com.sun.security.jgss.AuthorizationDataEntry;
|
||||
import java.io.File;
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.ByteArrayOutputStream;
|
||||
|
||||
/**
|
||||
* Context of a JGSS subject, encapsulating Subject and GSSContext.
|
||||
@ -78,6 +79,8 @@ public class Context {
|
||||
private String name;
|
||||
private GSSCredential cred; // see static method delegated().
|
||||
|
||||
static boolean usingStream = false;
|
||||
|
||||
private Context() {}
|
||||
|
||||
/**
|
||||
@ -365,7 +368,14 @@ public class Context {
|
||||
public byte[] run(Context me, byte[] dummy) throws Exception {
|
||||
System.out.println("wrap");
|
||||
MessageProp p1 = new MessageProp(0, true);
|
||||
byte[] out = me.x.wrap(messageBytes, 0, messageBytes.length, p1);
|
||||
byte[] out;
|
||||
if (usingStream) {
|
||||
ByteArrayOutputStream os = new ByteArrayOutputStream();
|
||||
me.x.wrap(new ByteArrayInputStream(messageBytes), os, p1);
|
||||
out = os.toByteArray();
|
||||
} else {
|
||||
out = me.x.wrap(messageBytes, 0, messageBytes.length, p1);
|
||||
}
|
||||
System.out.println(printProp(p1));
|
||||
return out;
|
||||
}
|
||||
@ -375,27 +385,46 @@ public class Context {
|
||||
@Override
|
||||
public byte[] run(Context me, byte[] input) throws Exception {
|
||||
MessageProp p1 = new MessageProp(0, true);
|
||||
byte[] bytes = me.x.unwrap(input, 0, input.length, p1);
|
||||
byte[] bytes;
|
||||
if (usingStream) {
|
||||
ByteArrayOutputStream os = new ByteArrayOutputStream();
|
||||
me.x.unwrap(new ByteArrayInputStream(input), os, p1);
|
||||
bytes = os.toByteArray();
|
||||
} else {
|
||||
bytes = me.x.unwrap(input, 0, input.length, p1);
|
||||
}
|
||||
if (!Arrays.equals(messageBytes, bytes))
|
||||
throw new Exception("wrap/unwrap mismatch");
|
||||
System.out.println("unwrap");
|
||||
System.out.println(printProp(p1));
|
||||
p1 = new MessageProp(0, true);
|
||||
System.out.println("getMIC");
|
||||
bytes = me.x.getMIC(bytes, 0, bytes.length, p1);
|
||||
if (usingStream) {
|
||||
ByteArrayOutputStream os = new ByteArrayOutputStream();
|
||||
me.x.getMIC(new ByteArrayInputStream(messageBytes), os, p1);
|
||||
bytes = os.toByteArray();
|
||||
} else {
|
||||
bytes = me.x.getMIC(messageBytes, 0, messageBytes.length, p1);
|
||||
}
|
||||
System.out.println(printProp(p1));
|
||||
return bytes;
|
||||
}
|
||||
}, t);
|
||||
|
||||
// Re-unwrap should make p2.isDuplicateToken() returns true
|
||||
s1.doAs(new Action() {
|
||||
@Override
|
||||
public byte[] run(Context me, byte[] input) throws Exception {
|
||||
MessageProp p1 = new MessageProp(0, true);
|
||||
System.out.println("verifyMIC");
|
||||
me.x.verifyMIC(input, 0, input.length,
|
||||
messageBytes, 0, messageBytes.length,
|
||||
p1);
|
||||
if (usingStream) {
|
||||
me.x.verifyMIC(new ByteArrayInputStream(input),
|
||||
new ByteArrayInputStream(messageBytes), p1);
|
||||
} else {
|
||||
me.x.verifyMIC(input, 0, input.length,
|
||||
messageBytes, 0, messageBytes.length,
|
||||
p1);
|
||||
}
|
||||
System.out.println(printProp(p1));
|
||||
return null;
|
||||
}
|
||||
@ -416,7 +445,9 @@ public class Context {
|
||||
sb.append(prop.isGapToken()?"gap, ":"");
|
||||
sb.append(prop.isOldToken()?"old, ":"");
|
||||
sb.append(prop.isUnseqToken()?"unseq, ":"");
|
||||
sb.append(prop.getMinorString()+ "(" + prop.getMinorStatus()+")");
|
||||
if (prop.getMinorStatus() != 0) {
|
||||
sb.append(prop.getMinorString()+ "(" + prop.getMinorStatus()+")");
|
||||
}
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
@ -442,7 +473,13 @@ public class Context {
|
||||
return null;
|
||||
} else {
|
||||
System.out.println(c.name + " call initSecContext");
|
||||
return me.x.initSecContext(input, 0, input.length);
|
||||
if (usingStream) {
|
||||
ByteArrayOutputStream os = new ByteArrayOutputStream();
|
||||
me.x.initSecContext(new ByteArrayInputStream(input), os);
|
||||
return os.size() == 0 ? null : os.toByteArray();
|
||||
} else {
|
||||
return me.x.initSecContext(input, 0, input.length);
|
||||
}
|
||||
}
|
||||
}
|
||||
}, t);
|
||||
@ -460,7 +497,13 @@ public class Context {
|
||||
return null;
|
||||
} else {
|
||||
System.out.println(s.name + " called acceptSecContext");
|
||||
return me.x.acceptSecContext(input, 0, input.length);
|
||||
if (usingStream) {
|
||||
ByteArrayOutputStream os = new ByteArrayOutputStream();
|
||||
me.x.acceptSecContext(new ByteArrayInputStream(input), os);
|
||||
return os.size() == 0 ? null : os.toByteArray();
|
||||
} else {
|
||||
return me.x.acceptSecContext(input, 0, input.length);
|
||||
}
|
||||
}
|
||||
}
|
||||
}, t);
|
||||
|
||||
@ -1,75 +0,0 @@
|
||||
#
|
||||
# Copyright (c) 2008, 2009, Oracle and/or its affiliates. All rights reserved.
|
||||
# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
#
|
||||
# This code is free software; you can redistribute it and/or modify it
|
||||
# under the terms of the GNU General Public License version 2 only, as
|
||||
# published by the Free Software Foundation.
|
||||
#
|
||||
# This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
# version 2 for more details (a copy is included in the LICENSE file that
|
||||
# accompanied this code).
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License version
|
||||
# 2 along with this work; if not, write to the Free Software Foundation,
|
||||
# Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
#
|
||||
# Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
# or visit www.oracle.com if you need additional information or have any
|
||||
# questions.
|
||||
#
|
||||
|
||||
# @test
|
||||
# @bug 6706974
|
||||
# @summary Add krb5 test infrastructure
|
||||
# @run shell/timeout=300 basic.sh
|
||||
#
|
||||
|
||||
if [ "${TESTSRC}" = "" ] ; then
|
||||
TESTSRC="."
|
||||
fi
|
||||
if [ "${TESTJAVA}" = "" ] ; then
|
||||
echo "TESTJAVA not set. Test cannot execute."
|
||||
echo "FAILED!!!"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# set platform-dependent variables
|
||||
OS=`uname -s`
|
||||
case "$OS" in
|
||||
Windows_* )
|
||||
FS="\\"
|
||||
SEP=";"
|
||||
;;
|
||||
CYGWIN* )
|
||||
FS="/"
|
||||
SEP=";"
|
||||
;;
|
||||
* )
|
||||
FS="/"
|
||||
SEP=":"
|
||||
;;
|
||||
esac
|
||||
|
||||
${TESTJAVA}${FS}bin${FS}javac -XDignore.symbol.file -d . \
|
||||
${TESTSRC}${FS}BasicKrb5Test.java \
|
||||
${TESTSRC}${FS}KDC.java \
|
||||
${TESTSRC}${FS}OneKDC.java \
|
||||
${TESTSRC}${FS}Action.java \
|
||||
${TESTSRC}${FS}Context.java \
|
||||
|| exit 10
|
||||
|
||||
# Add $TESTSRC to classpath so that customized nameservice can be used
|
||||
J="${TESTJAVA}${FS}bin${FS}java -cp $TESTSRC${SEP}. BasicKrb5Test"
|
||||
|
||||
$J || exit 100
|
||||
$J des-cbc-crc || exit 1
|
||||
$J des-cbc-md5 || exit 3
|
||||
$J des3-cbc-sha1 || exit 16
|
||||
$J aes128-cts || exit 17
|
||||
$J aes256-cts || exit 18
|
||||
$J rc4-hmac || exit 23
|
||||
|
||||
exit 0
|
||||
Loading…
x
Reference in New Issue
Block a user