提交 84a9b032 编写于 作者: W weijun

6975866: api/org_ietf/jgss/GSSContext/index.html#wrapUnwrapIOTest started to fail since jdk7 b102

Reviewed-by: valeriep
上级 c86e1caa
/* /*
* 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. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
* *
* This code is free software; you can redistribute it and/or modify it * This code is free software; you can redistribute it and/or modify it
...@@ -710,29 +710,21 @@ class CipherHelper { ...@@ -710,29 +710,21 @@ class CipherHelper {
* where HMAC is on {16-byte confounder | plaintext | 16-byte token_header} * where HMAC is on {16-byte confounder | plaintext | 16-byte token_header}
* HMAC is not encrypted; it is appended at the end. * HMAC is not encrypted; it is appended at the end.
*/ */
void encryptData(WrapToken_v2 token, byte[] confounder, byte[] tokenHeader, byte[] encryptData(WrapToken_v2 token, byte[] confounder, byte[] tokenHeader,
byte[] plaintext, int start, int len, int key_usage, OutputStream os) byte[] plaintext, int start, int len, int key_usage)
throws GSSException, IOException { throws GSSException {
byte[] ctext = null;
switch (etype) { switch (etype) {
case EncryptedData.ETYPE_AES128_CTS_HMAC_SHA1_96: case EncryptedData.ETYPE_AES128_CTS_HMAC_SHA1_96:
ctext = aes128Encrypt(confounder, tokenHeader, return aes128Encrypt(confounder, tokenHeader,
plaintext, start, len, key_usage); plaintext, start, len, key_usage);
break;
case EncryptedData.ETYPE_AES256_CTS_HMAC_SHA1_96: case EncryptedData.ETYPE_AES256_CTS_HMAC_SHA1_96:
ctext = aes256Encrypt(confounder, tokenHeader, return aes256Encrypt(confounder, tokenHeader,
plaintext, start, len, key_usage); plaintext, start, len, key_usage);
break;
default: default:
throw new GSSException(GSSException.FAILURE, -1, throw new GSSException(GSSException.FAILURE, -1,
"Unsupported etype: " + etype); "Unsupported etype: " + etype);
} }
// Krb5Token.debug("EncryptedData = " +
// Krb5Token.getHexBytes(ctext) + "\n");
// Write to stream
os.write(ctext);
} }
void encryptData(WrapToken token, byte[] confounder, byte[] plaintext, void encryptData(WrapToken token, byte[] confounder, byte[] plaintext,
......
/* /*
* 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. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
* *
* This code is free software; you can redistribute it and/or modify it * This code is free software; you can redistribute it and/or modify it
...@@ -26,24 +26,22 @@ ...@@ -26,24 +26,22 @@
package sun.security.jgss.krb5; package sun.security.jgss.krb5;
import org.ietf.jgss.*; import org.ietf.jgss.*;
import sun.security.jgss.*;
import sun.security.krb5.*;
import java.io.InputStream; import java.io.InputStream;
import java.io.OutputStream; import java.io.OutputStream;
import java.io.IOException; import java.io.IOException;
import java.io.ByteArrayInputStream; import java.io.ByteArrayInputStream;
import java.security.GeneralSecurityException; import java.io.ByteArrayOutputStream;
import java.security.MessageDigest; import java.security.MessageDigest;
import java.util.Arrays;
/** /**
* This class is a base class for new GSS token definitions, as defined * 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 * in RFC 4121, that pertain to per-message GSS-API calls. Conceptually
* GSS-API calls. Conceptually GSS-API has two types of per-message tokens: * GSS-API has two types of per-message tokens: WrapToken and MicToken.
* WrapToken and MicToken. They differ in the respect that a WrapToken * They differ in the respect that a WrapToken carries additional plaintext
* carries additional plaintext or ciphertext application data besides * or ciphertext application data besides just the sequence number and
* just the sequence number and checksum. This class encapsulates the * checksum. This class encapsulates the commonality in the structure of
* commonality in the structure of the WrapToken and the MicToken. * the WrapToken and the MicToken. This structure can be represented as:
* This structure can be represented as:
* <p> * <p>
* <pre> * <pre>
* Wrap Tokens * Wrap Tokens
...@@ -51,17 +49,17 @@ import java.security.MessageDigest; ...@@ -51,17 +49,17 @@ import java.security.MessageDigest;
* Octet no Name Description * Octet no Name Description
* --------------------------------------------------------------- * ---------------------------------------------------------------
* 0..1 TOK_ID Identification field. Tokens emitted by * 0..1 TOK_ID Identification field. Tokens emitted by
* GSS_Wrap() contain the the hex value 05 04 * GSS_Wrap() contain the hex value 05 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 * 2 Flags Attributes field, as described in section
* 4.2.2. * 4.2.2.
* 3 Filler Contains the hex value FF. * 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. * endian order as described in section 4.2.3.
* 6..7 RRC Contains the "right rotation count" in big * 6..7 RRC Contains the "right rotation count" in big
* endian order, as described in section 4.2.5. * endian order, as described in section 4.2.5.
* 8..15 SND_SEQ Sequence number field in clear text, * 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 * 16..last Data Encrypted data for Wrap tokens with
* confidentiality, or plaintext data followed * confidentiality, or plaintext data followed
* by the checksum for Wrap tokens without * by the checksum for Wrap tokens without
...@@ -73,67 +71,82 @@ import java.security.MessageDigest; ...@@ -73,67 +71,82 @@ import java.security.MessageDigest;
* ----------------------------------------------------------------- * -----------------------------------------------------------------
* 0..1 TOK_ID Identification field. Tokens emitted by * 0..1 TOK_ID Identification field. Tokens emitted by
* GSS_GetMIC() contain the hex value 04 04 * 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 * 2 Flags Attributes field, as described in section
* 4.2.2. * 4.2.2.
* 3..7 Filler Contains five octets of hex value FF. * 3..7 Filler Contains five octets of hex value FF.
* 8..15 SND_SEQ Sequence number field in clear text, * 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 * 16..last SGN_CKSUM Checksum of the "to-be-signed" data and
* octet 0..15, as described in section 4.2.4. * octet 0..15, as described in section 4.2.4.
* *
* </pre> * </pre>
* <p> * <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 * @author Seema Malkani
*/ */
abstract class MessageToken_v2 extends Krb5Token { 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_ID_POS = 0;
private static final int TOKEN_FLAG_POS = 2; private static final int TOKEN_FLAG_POS = 2;
private static final int TOKEN_EC_POS = 4; private static final int TOKEN_EC_POS = 4;
private static final int TOKEN_RRC_POS = 6; 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;
// 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;
// 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 tokenId = 0;
private int seqNumber; private int seqNumber;
protected byte[] tokenData; // content of token, without the header
protected int tokenDataLen;
// EC and RRC fields // Key usage number for crypto action
private int key_usage = 0;
// EC and RRC fields, WrapToken only
private int ec = 0; private int ec = 0;
private int rrc = 0; private int rrc = 0;
private boolean confState = true; // Checksum. Always in MicToken, might be in WrapToken
private boolean initiator = true;
byte[] confounder = null;
byte[] checksum = null; byte[] checksum = null;
private int key_usage = 0; // Context properties
private byte[] seqNumberData = null; private boolean confState = true;
private boolean initiator = true;
private MessageTokenHeader tokenHeader = null;
/* cipher instance used by the corresponding GSSContext */ /* cipher instance used by the corresponding GSSContext */
CipherHelper cipherHelper = null; CipherHelper cipherHelper = null;
// draft-ietf-krb-wg-gssapi-cfx-07
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
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;
/** /**
* Constructs a MessageToken from a byte array. If there are more bytes * Constructs a MessageToken from a byte array.
* in the array than needed, the extra bytes are simply ignroed.
* *
* @param tokenId the token id that should be contained in this token as * @param tokenId the token id that should be contained in this token as
* it is read. * it is read.
...@@ -156,7 +169,9 @@ abstract class MessageToken_v2 extends Krb5Token { ...@@ -156,7 +169,9 @@ abstract class MessageToken_v2 extends Krb5Token {
/** /**
* Constructs a MessageToken from an InputStream. Bytes will be read on * Constructs a MessageToken from an InputStream. Bytes will be read on
* demand and the thread might block if there are not enough bytes to * 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 * @param tokenId the token id that should be contained in this token as
* it is read. * it is read.
...@@ -186,25 +201,58 @@ abstract class MessageToken_v2 extends Krb5Token { ...@@ -186,25 +201,58 @@ abstract class MessageToken_v2 extends Krb5Token {
: KG_USAGE_ACCEPTOR_SIGN); : KG_USAGE_ACCEPTOR_SIGN);
} }
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();
}
// 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 // Read checksum
int tokenLen = is.available(); int chkLen = cipherHelper.getChecksumLength();
byte[] data = new byte[tokenLen]; checksum = new byte[chkLen];
readFully(is, data); System.arraycopy(tokenData, tokenDataLen-chkLen,
checksum = new byte[cipherHelper.getChecksumLength()]; checksum, 0, chkLen);
System.arraycopy(data, tokenLen-cipherHelper.getChecksumLength(),
checksum, 0, cipherHelper.getChecksumLength());
// debug("\nLeaving MessageToken.Cons\n");
// validate EC for Wrap tokens without confidentiality // validate EC for Wrap tokens without confidentiality
if (!prop.getPrivacy() && if (tokenId == Krb5Token.WRAP_ID_v2 && !prop.getPrivacy()) {
(tokenId == Krb5Token.WRAP_ID_v2)) { if (chkLen != ec) {
if (checksum.length != ec) {
throw new GSSException(GSSException.DEFECTIVE_TOKEN, -1, throw new GSSException(GSSException.DEFECTIVE_TOKEN, -1,
getTokenName(tokenId) + ":" + "EC incorrect!"); getTokenName(tokenId) + ":" + "EC incorrect!");
} }
} }
}
} catch (IOException e) { } catch (IOException e) {
throw new GSSException(GSSException.DEFECTIVE_TOKEN, -1, throw new GSSException(GSSException.DEFECTIVE_TOKEN, -1,
getTokenName(tokenId) + ":" + e.getMessage()); getTokenName(tokenId) + ":" + e.getMessage());
...@@ -263,8 +311,7 @@ abstract class MessageToken_v2 extends Krb5Token { ...@@ -263,8 +311,7 @@ abstract class MessageToken_v2 extends Krb5Token {
prop.setPrivacy(false); prop.setPrivacy(false);
} }
// Create a new gss token header as defined in // Create a new gss token header as defined in RFC 4121
// draft-ietf-krb-wg-gssapi-cfx-07
tokenHeader = new MessageTokenHeader(tokenId, tokenHeader = new MessageTokenHeader(tokenId,
prop.getPrivacy(), true); prop.getPrivacy(), true);
// debug("\n\t Message Header = " + // debug("\n\t Message Header = " +
...@@ -326,50 +373,21 @@ abstract class MessageToken_v2 extends Krb5Token { ...@@ -326,50 +373,21 @@ abstract class MessageToken_v2 extends Krb5Token {
* Rotate bytes as per the "RRC" (Right Rotation Count) received. * Rotate bytes as per the "RRC" (Right Rotation Count) received.
* Our implementation does not do any rotates when sending, only * Our implementation does not do any rotates when sending, only
* when receiving, we rotate left as per the RRC count, to revert it. * 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, private void rotate() {
byte[] out_bytes, int bufsize) { if (rrc % tokenDataLen != 0) {
rrc = rrc % tokenDataLen;
int offset = 0; byte[] newBytes = new byte[tokenDataLen];
// 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;
}
// if offset is not zero System.arraycopy(tokenData, rrc, newBytes, 0, tokenDataLen-rrc);
if (tokenOffset > 0) { System.arraycopy(tokenData, 0, newBytes, tokenDataLen-rrc, rrc);
offset += tokenOffset;
}
// copy the header tokenData = newBytes;
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;
} }
return false;
} }
public final int getSequenceNumber() { public final int getSequenceNumber() {
return (readBigEndian(seqNumberData, 0, 4)); return seqNumber;
} }
/** /**
...@@ -444,44 +462,25 @@ abstract class MessageToken_v2 extends Krb5Token { ...@@ -444,44 +462,25 @@ abstract class MessageToken_v2 extends Krb5Token {
this.cipherHelper = context.getCipherHelper(null); this.cipherHelper = context.getCipherHelper(null);
// debug("In MessageToken.Cons"); // 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 * @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 { protected void encodeHeader(OutputStream os) throws IOException {
// debug("Writing tokenHeader " + getHexBytes(tokenHeader.getBytes());
// (16 bytes of token header that includes sequence Number)
tokenHeader.encode(os); 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 * Encodes a MessageToken_v2 onto an OutputStream.
* the GSSHeader. *
* @return token size * @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 { public abstract void encode(OutputStream os) throws IOException;
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());
}
protected final byte[] getTokenHeader() { protected final byte[] getTokenHeader() {
return (tokenHeader.getBytes()); return (tokenHeader.getBytes());
...@@ -493,45 +492,14 @@ abstract class MessageToken_v2 extends Krb5Token { ...@@ -493,45 +492,14 @@ abstract class MessageToken_v2 extends Krb5Token {
/** /**
* This inner class represents the initial portion of the message token. * This inner class represents the initial portion of the message token.
* It constitutes the first 16 bytes 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>
*/ */
class MessageTokenHeader { class MessageTokenHeader {
private int tokenId; private int tokenId;
private byte[] bytes = new byte[TOKEN_HEADER_SIZE]; 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, public MessageTokenHeader(int tokenId, boolean conf,
boolean have_acceptor_subkey) throws GSSException { boolean have_acceptor_subkey) throws GSSException {
...@@ -542,16 +510,15 @@ abstract class MessageToken_v2 extends Krb5Token { ...@@ -542,16 +510,15 @@ abstract class MessageToken_v2 extends Krb5Token {
// Flags (Note: MIT impl requires subkey) // Flags (Note: MIT impl requires subkey)
int flags = 0; int flags = 0;
flags = ((initiator ? 0 : FLAG_SENDER_IS_ACCEPTOR) | flags = (initiator ? 0 : FLAG_SENDER_IS_ACCEPTOR) |
((conf && tokenId != MIC_ID_v2) ? ((conf && tokenId != MIC_ID_v2) ?
FLAG_WRAP_CONFIDENTIAL : 0) | FLAG_WRAP_CONFIDENTIAL : 0) |
(have_acceptor_subkey ? FLAG_ACCEPTOR_SUBKEY : 0)); (have_acceptor_subkey ? FLAG_ACCEPTOR_SUBKEY : 0);
bytes[2] = (byte) flags; bytes[2] = (byte) flags;
// filler // filler
bytes[3] = (byte) FILLER; bytes[3] = (byte) FILLER;
// EC and RRC fields
if (tokenId == WRAP_ID_v2) { if (tokenId == WRAP_ID_v2) {
// EC field // EC field
bytes[4] = (byte) 0; bytes[4] = (byte) 0;
...@@ -560,21 +527,19 @@ abstract class MessageToken_v2 extends Krb5Token { ...@@ -560,21 +527,19 @@ abstract class MessageToken_v2 extends Krb5Token {
bytes[6] = (byte) 0; bytes[6] = (byte) 0;
bytes[7] = (byte) 0; bytes[7] = (byte) 0;
} else if (tokenId == MIC_ID_v2) { } else if (tokenId == MIC_ID_v2) {
// octets of filler FF // more filler for MicToken
for (int i = 4; i < 8; i++) { for (int i = 4; i < 8; i++) {
bytes[i] = (byte) FILLER; bytes[i] = (byte) FILLER;
} }
} }
// Calculate SND_SEQ // Calculate SND_SEQ, only write 4 bytes from the 12th position
seqNumberData = new byte[8]; writeBigEndian(seqNumber, bytes, 12);
writeBigEndian(seqNumber, seqNumberData, 4);
System.arraycopy(seqNumberData, 0, bytes, 8, 8);
} }
/** /**
* Constructs a MessageTokenHeader by reading it from an InputStream * Reads a MessageTokenHeader from an InputStream and sets the
* and sets the appropriate confidentiality and quality of protection * appropriate confidentiality and quality of protection
* values in a MessageProp structure. * values in a MessageProp structure.
* *
* @param is the InputStream to read from * @param is the InputStream to read from
...@@ -588,15 +553,23 @@ abstract class MessageToken_v2 extends Krb5Token { ...@@ -588,15 +553,23 @@ abstract class MessageToken_v2 extends Krb5Token {
readFully(is, bytes, 0, TOKEN_HEADER_SIZE); readFully(is, bytes, 0, TOKEN_HEADER_SIZE);
tokenId = readInt(bytes, TOKEN_ID_POS); 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 * 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 acceptor_flag = (initiator ? FLAG_SENDER_IS_ACCEPTOR : 0);
int flag = bytes[TOKEN_FLAG_POS] & FLAG_SENDER_IS_ACCEPTOR; 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, throw new GSSException(GSSException.DEFECTIVE_TOKEN, -1,
getTokenName(tokenId) + ":" + "Acceptor Flag Missing!"); getTokenName(tokenId) + ":" + "Acceptor Flag Error!");
} }
// check for confidentiality // check for confidentiality
...@@ -608,21 +581,20 @@ abstract class MessageToken_v2 extends Krb5Token { ...@@ -608,21 +581,20 @@ abstract class MessageToken_v2 extends Krb5Token {
prop.setPrivacy(false); prop.setPrivacy(false);
} }
// validate Token ID if (tokenId == WRAP_ID_v2) {
if (tokenId != tokId) {
throw new GSSException(GSSException.DEFECTIVE_TOKEN, -1,
getTokenName(tokenId) + ":" + "Defective Token ID!");
}
// validate filler // validate filler
if ((bytes[3] & 0xff) != FILLER) { if ((bytes[3] & 0xff) != FILLER) {
throw new GSSException(GSSException.DEFECTIVE_TOKEN, -1, throw new GSSException(GSSException.DEFECTIVE_TOKEN, -1,
getTokenName(tokenId) + ":" + "Defective Token Filler!"); getTokenName(tokenId) + ":" + "Defective Token Filler!");
} }
// validate next 4 bytes of filler for MIC tokens // read EC field
if (tokenId == MIC_ID_v2) { ec = readBigEndian(bytes, TOKEN_EC_POS, 2);
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) { if ((bytes[i] & 0xff) != FILLER) {
throw new GSSException(GSSException.DEFECTIVE_TOKEN, throw new GSSException(GSSException.DEFECTIVE_TOKEN,
-1, getTokenName(tokenId) + ":" + -1, getTokenName(tokenId) + ":" +
...@@ -631,18 +603,11 @@ abstract class MessageToken_v2 extends Krb5Token { ...@@ -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 // set default QOP
prop.setQOP(0); prop.setQOP(0);
// sequence number // sequence number
seqNumberData = new byte[8]; seqNumber = readBigEndian(bytes, 0, 8);
System.arraycopy(bytes, 8, seqNumberData, 0, 8);
} }
/** /**
......
/* /*
* 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. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
* *
* This code is free software; you can redistribute it and/or modify it * This code is free software; you can redistribute it and/or modify it
...@@ -29,12 +29,11 @@ import org.ietf.jgss.*; ...@@ -29,12 +29,11 @@ import org.ietf.jgss.*;
import java.io.InputStream; import java.io.InputStream;
import java.io.OutputStream; import java.io.OutputStream;
import java.io.IOException; import java.io.IOException;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream; import java.io.ByteArrayOutputStream;
/** /**
* This class represents the new format of GSS MIC tokens, as specified * 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 } * MIC tokens = { 16-byte token-header | HMAC }
* where HMAC is on { plaintext | 16-byte token-header } * where HMAC is on { plaintext | 16-byte token-header }
...@@ -51,8 +50,7 @@ class MicToken_v2 extends MessageToken_v2 { ...@@ -51,8 +50,7 @@ class MicToken_v2 extends MessageToken_v2 {
tokenBytes, tokenOffset, tokenLen, prop); tokenBytes, tokenOffset, tokenLen, prop);
} }
public MicToken_v2(Krb5Context context, public MicToken_v2(Krb5Context context, InputStream is, MessageProp prop)
InputStream is, MessageProp prop)
throws GSSException { throws GSSException {
super(Krb5Token.MIC_ID_v2, context, is, prop); super(Krb5Token.MIC_ID_v2, context, is, prop);
} }
...@@ -64,7 +62,6 @@ class MicToken_v2 extends MessageToken_v2 { ...@@ -64,7 +62,6 @@ class MicToken_v2 extends MessageToken_v2 {
} }
public void verify(InputStream data) throws GSSException { public void verify(InputStream data) throws GSSException {
byte[] dataBytes = null; byte[] dataBytes = null;
try { try {
dataBytes = new byte[data.available()]; dataBytes = new byte[data.available()];
...@@ -101,22 +98,21 @@ class MicToken_v2 extends MessageToken_v2 { ...@@ -101,22 +98,21 @@ class MicToken_v2 extends MessageToken_v2 {
genSignAndSeqNumber(prop, dataBytes, 0, dataBytes.length); genSignAndSeqNumber(prop, dataBytes, 0, dataBytes.length);
} }
public int encode(byte[] outToken, int offset) public byte[] encode() throws IOException {
throws IOException, GSSException { // XXX Fine tune this initial size
ByteArrayOutputStream bos = new ByteArrayOutputStream(50);
encode(bos);
return bos.toByteArray();
}
// Token is small public int encode(byte[] outToken, int offset) throws IOException {
ByteArrayOutputStream bos = new ByteArrayOutputStream(); byte[] token = encode();
super.encode(bos);
byte[] token = bos.toByteArray();
System.arraycopy(token, 0, outToken, offset, token.length); System.arraycopy(token, 0, outToken, offset, token.length);
return token.length; return token.length;
} }
public byte[] encode() throws IOException, GSSException { public void encode(OutputStream os) throws IOException {
encodeHeader(os);
// XXX Fine tune this initial size os.write(checksum);
ByteArrayOutputStream bos = new ByteArrayOutputStream(50);
encode(bos);
return bos.toByteArray();
} }
} }
/* /*
* 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. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
* *
* This code is free software; you can redistribute it and/or modify it * This code is free software; you can redistribute it and/or modify it
...@@ -27,14 +27,11 @@ package sun.security.jgss.krb5; ...@@ -27,14 +27,11 @@ package sun.security.jgss.krb5;
import org.ietf.jgss.*; import org.ietf.jgss.*;
import sun.security.jgss.*; import sun.security.jgss.*;
import java.security.GeneralSecurityException;
import java.io.InputStream; import java.io.InputStream;
import java.io.OutputStream; import java.io.OutputStream;
import java.io.IOException; import java.io.IOException;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream; import java.io.ByteArrayOutputStream;
import sun.security.krb5.Confounder; import sun.security.krb5.Confounder;
import sun.security.krb5.KrbException;
/** /**
* This class represents a token emitted by the GSSContext.wrap() * This class represents a token emitted by the GSSContext.wrap()
...@@ -336,6 +333,10 @@ class WrapToken extends MessageToken { ...@@ -336,6 +333,10 @@ class WrapToken extends MessageToken {
// debug("\t\tNo encryption was performed by peer.\n"); // debug("\t\tNo encryption was performed by peer.\n");
readFully(is, confounder); readFully(is, confounder);
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 // Data is always a multiple of 8 with this GSS Mech
// Copy all but last block as they are // Copy all but last block as they are
int numBlocks = (dataSize - CONFOUNDER_SIZE)/8 - 1; int numBlocks = (dataSize - CONFOUNDER_SIZE)/8 - 1;
...@@ -355,6 +356,7 @@ class WrapToken extends MessageToken { ...@@ -355,6 +356,7 @@ class WrapToken extends MessageToken {
System.arraycopy(finalBlock, 0, dataBuf, offset, System.arraycopy(finalBlock, 0, dataBuf, offset,
finalBlock.length - padSize); finalBlock.length - padSize);
} }
}
} catch (IOException e) { } catch (IOException e) {
throw new GSSException(GSSException.DEFECTIVE_TOKEN, -1, throw new GSSException(GSSException.DEFECTIVE_TOKEN, -1,
getTokenName(getTokenId()) getTokenName(getTokenId())
......
/* /*
* 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. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
* *
* This code is free software; you can redistribute it and/or modify it * This code is free software; you can redistribute it and/or modify it
...@@ -27,66 +27,30 @@ package sun.security.jgss.krb5; ...@@ -27,66 +27,30 @@ package sun.security.jgss.krb5;
import org.ietf.jgss.*; import org.ietf.jgss.*;
import sun.security.jgss.*; import sun.security.jgss.*;
import java.security.GeneralSecurityException;
import java.io.InputStream; import java.io.InputStream;
import java.io.OutputStream; import java.io.OutputStream;
import java.io.IOException; import java.io.IOException;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream; import java.io.ByteArrayOutputStream;
import java.util.Arrays;
import sun.security.krb5.Confounder; import sun.security.krb5.Confounder;
import sun.security.krb5.KrbException;
/** /**
* This class represents the new format of GSS tokens, as specified in * This class represents the new format of GSS tokens, as specified in RFC
* draft-ietf-krb-wg-gssapi-cfx-07.txt, emitted by the GSSContext.wrap() * 4121, emitted by the GSSContext.wrap() call. It is a MessageToken except
* call. It is a MessageToken except that it also contains plaintext or * that it also contains plaintext or encrypted data at the end. A WrapToken
* encrypted data at the end. A WrapToken has certain other rules that are * has certain other rules that are peculiar to it and different from a
* peculiar to it and different from a MICToken, which is another type of * MICToken, which is another type of MessageToken. All data in a WrapToken is
* MessageToken. All data in a WrapToken is prepended by a random counfounder * prepended by a random confounder of 16 bytes. Thus, all application data
* of 16 bytes. Thus, all application data is replaced by * is replaced by (confounder || data || tokenHeader || checksum).
* (confounder || data || tokenHeader || checksum).
* *
* @author Seema Malkani * @author Seema Malkani
*/ */
class WrapToken_v2 extends MessageToken_v2 { 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 // Accessed by CipherHelper
byte[] confounder = null; byte[] confounder = null;
private boolean privacy = false; private final boolean privacy;
private boolean initiator = true;
/** /**
* Constructs a WrapToken from token bytes obtained from the * Constructs a WrapToken from token bytes obtained from the
...@@ -104,30 +68,9 @@ class WrapToken_v2 extends MessageToken_v2 { ...@@ -104,30 +68,9 @@ class WrapToken_v2 extends MessageToken_v2 {
byte[] tokenBytes, int tokenOffset, int tokenLen, byte[] tokenBytes, int tokenOffset, int tokenLen,
MessageProp prop) throws GSSException { MessageProp prop) throws GSSException {
// Just parse the MessageToken part first
super(Krb5Token.WRAP_ID_v2, context, super(Krb5Token.WRAP_ID_v2, context,
tokenBytes, tokenOffset, tokenLen, prop); 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(); 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 { ...@@ -145,27 +88,8 @@ class WrapToken_v2 extends MessageToken_v2 {
InputStream is, MessageProp prop) InputStream is, MessageProp prop)
throws GSSException { throws GSSException {
// Just parse the MessageToken part first
super(Krb5Token.WRAP_ID_v2, context, is, prop); super(Krb5Token.WRAP_ID_v2, context, is, prop);
// Will need the token bytes again when extracting data
this.is = is;
this.privacy = prop.getPrivacy(); 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 { ...@@ -177,13 +101,9 @@ class WrapToken_v2 extends MessageToken_v2 {
*/ */
public byte[] getData() throws GSSException { public byte[] getData() throws GSSException {
byte[] temp = new byte[dataSize]; byte[] temp = new byte[tokenDataLen];
int len = getData(temp, 0); int len = getData(temp, 0);
// len obtained is after removing confounder, tokenHeader and HMAC return Arrays.copyOf(temp, len);
byte[] retVal = new byte[len];
System.arraycopy(temp, 0, retVal, 0, retVal.length);
return retVal;
} }
/** /**
...@@ -200,69 +120,26 @@ class WrapToken_v2 extends MessageToken_v2 { ...@@ -200,69 +120,26 @@ class WrapToken_v2 extends MessageToken_v2 {
public int getData(byte[] dataBuf, int dataBufOffset) public int getData(byte[] dataBuf, int dataBufOffset)
throws GSSException { 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 [" + // debug("WrapToken cons: data is token is [" +
// getHexBytes(tokenBytes, tokenOffset, tokenLen) + "]\n"); // getHexBytes(tokenBytes, tokenOffset, tokenLen) + "]\n");
confounder = new byte[CONFOUNDER_SIZE];
// Do decryption if this token was privacy protected. // Do decryption if this token was privacy protected.
if (privacy) { if (privacy) {
// decrypt data // decrypt data
cipherHelper.decryptData(this, tokenBytes, dataPos, dataSize, cipherHelper.decryptData(this, tokenData, 0, tokenDataLen,
dataBuf, dataBufOffset, getKeyUsage()); dataBuf, dataBufOffset, getKeyUsage());
/*
debug("\t\tDecrypted data is [" +
getHexBytes(confounder) + " " +
getHexBytes(dataBuf, dataBufOffset,
dataSize - CONFOUNDER_SIZE) +
"]\n");
*/
data_length = dataSize - CONFOUNDER_SIZE - return tokenDataLen - CONFOUNDER_SIZE -
TOKEN_HEADER_SIZE - cipherHelper.getChecksumLength(); TOKEN_HEADER_SIZE - cipherHelper.getChecksumLength();
} else { } else {
// Token data is in cleartext // 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
data_length = dataSize - cipherHelper.getChecksumLength(); int data_length = tokenDataLen - cipherHelper.getChecksumLength();
System.arraycopy(tokenBytes, dataPos, System.arraycopy(tokenData, 0,
dataBuf, dataBufOffset, dataBuf, dataBufOffset,
data_length); data_length);
// debug("\t\tData is: " + getHexBytes(dataBuf, data_length)); // debug("\t\tData is: " + getHexBytes(dataBuf, data_length));
...@@ -274,72 +151,13 @@ class WrapToken_v2 extends MessageToken_v2 { ...@@ -274,72 +151,13 @@ class WrapToken_v2 extends MessageToken_v2 {
throw new GSSException(GSSException.BAD_MIC, -1, throw new GSSException(GSSException.BAD_MIC, -1,
"Corrupt checksum in Wrap token"); "Corrupt checksum in Wrap token");
} }
return data_length;
} }
} }
/** /**
* Helper routine to obtain the application data transmitted in * Writes a WrapToken_v2 object
* 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
*/
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, public WrapToken_v2(Krb5Context context, MessageProp prop,
byte[] dataBytes, int dataOffset, int dataLen) byte[] dataBytes, int dataOffset, int dataLen)
throws GSSException { throws GSSException {
...@@ -348,21 +166,11 @@ class WrapToken_v2 extends MessageToken_v2 { ...@@ -348,21 +166,11 @@ class WrapToken_v2 extends MessageToken_v2 {
confounder = Confounder.bytes(CONFOUNDER_SIZE); 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 [" + // debug("\nWrapToken cons: data to wrap is [" +
// getHexBytes(confounder) + " " + // getHexBytes(confounder) + " " +
// getHexBytes(dataBytes, dataOffset, dataLen) + "]\n"); // getHexBytes(dataBytes, dataOffset, dataLen) + "]\n");
genSignAndSeqNumber(prop, genSignAndSeqNumber(prop, dataBytes, dataOffset, dataLen);
dataBytes, dataOffset, dataLen);
/* /*
* If the application decides to ask for privacy when the context * If the application decides to ask for privacy when the context
...@@ -374,110 +182,42 @@ class WrapToken_v2 extends MessageToken_v2 { ...@@ -374,110 +182,42 @@ class WrapToken_v2 extends MessageToken_v2 {
prop.setPrivacy(false); prop.setPrivacy(false);
privacy = prop.getPrivacy(); privacy = prop.getPrivacy();
}
public void encode(OutputStream os) throws IOException, GSSException {
super.encode(os);
// debug("\n\nWriting data: [");
if (!privacy) { if (!privacy) {
// Wrap Tokens (without confidentiality) = // Wrap Tokens (without confidentiality) =
// { 16 byte token_header | plaintext | 12-byte HMAC } // { 16 byte token_header | plaintext | 12-byte HMAC }
// where HMAC is on { plaintext | token_header } // where HMAC is on { plaintext | token_header }
// calculate checksum tokenData = new byte[dataLen + checksum.length];
byte[] checksum = getChecksum(dataBytes, dataOffset, dataLen); System.arraycopy(dataBytes, dataOffset, tokenData, 0, dataLen);
System.arraycopy(checksum, 0, tokenData, dataLen, checksum.length);
// data
// debug(" " + getHexBytes(dataBytes, dataOffset, dataLen));
os.write(dataBytes, dataOffset, dataLen);
// write HMAC
// debug(" " + getHexBytes(checksum,
// cipherHelper.getChecksumLength()));
os.write(checksum);
} else { } else {
// Wrap Tokens (with confidentiality) = // Wrap Tokens (with confidentiality) =
// { 16 byte token_header | // { 16 byte token_header |
// Encrypt(16-byte confounder | plaintext | token_header) | // Encrypt(16-byte confounder | plaintext | token_header) |
// 12-byte HMAC } // 12-byte HMAC }
cipherHelper.encryptData(this, confounder, getTokenHeader(), tokenData = cipherHelper.encryptData(this, confounder, getTokenHeader(),
dataBytes, dataOffset, dataLen, getKeyUsage(), os); dataBytes, dataOffset, dataLen, getKeyUsage());
} }
// debug("]\n");
} }
public byte[] encode() throws IOException, GSSException { public void encode(OutputStream os) throws IOException {
// XXX Fine tune this initial size encodeHeader(os);
ByteArrayOutputStream bos = new ByteArrayOutputStream(dataSize + 50); os.write(tokenData);
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"); public byte[] encode() throws IOException {
ByteArrayOutputStream bos = new ByteArrayOutputStream(
// %%% assume that plaintext length == ciphertext len MessageToken_v2.TOKEN_HEADER_SIZE + tokenData.length);
return retVal; encode(bos);
return bos.toByteArray();
} }
protected int getKrb5TokenSize() throws GSSException { public int encode(byte[] outToken, int offset) throws IOException {
return (getTokenSize() + dataSize); byte[] token = encode();
System.arraycopy(token, 0, outToken, offset, token.length);
return token.length;
} }
// This implementation is way to conservative. And it certainly // This implementation is way to conservative. And it certainly
...@@ -485,6 +225,7 @@ class WrapToken_v2 extends MessageToken_v2 { ...@@ -485,6 +225,7 @@ class WrapToken_v2 extends MessageToken_v2 {
static int getSizeLimit(int qop, boolean confReq, int maxTokenSize, static int getSizeLimit(int qop, boolean confReq, int maxTokenSize,
CipherHelper ch) throws GSSException { CipherHelper ch) throws GSSException {
return (GSSHeader.getMaxMechTokenSize(OID, maxTokenSize) - return (GSSHeader.getMaxMechTokenSize(OID, maxTokenSize) -
(getTokenSize(ch) + CONFOUNDER_SIZE) - 8 /* safety */); (TOKEN_HEADER_SIZE + ch.getChecksumLength() + CONFOUNDER_SIZE)
- 8 /* safety */);
} }
} }
/* /*
* 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. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
* *
* This code is free software; you can redistribute it and/or modify it * This code is free software; you can redistribute it and/or modify it
...@@ -25,6 +25,34 @@ ...@@ -25,6 +25,34 @@
* @test * @test
* @bug 6706974 * @bug 6706974
* @summary Add krb5 test infrastructure * @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; import org.ietf.jgss.GSSName;
...@@ -39,6 +67,7 @@ import sun.security.krb5.internal.crypto.EType; ...@@ -39,6 +67,7 @@ import sun.security.krb5.internal.crypto.EType;
*/ */
public class BasicKrb5Test { public class BasicKrb5Test {
private static boolean conf = true;
/** /**
* @param args empty or etype * @param args empty or etype
*/ */
...@@ -46,8 +75,10 @@ public class BasicKrb5Test { ...@@ -46,8 +75,10 @@ public class BasicKrb5Test {
throws Exception { throws Exception {
String etype = null; String etype = null;
if (args.length > 0) { for (String arg: args) {
etype = args[0]; 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 // Creates and starts the KDC. This line must be put ahead of etype check
...@@ -56,8 +87,9 @@ public class BasicKrb5Test { ...@@ -56,8 +87,9 @@ public class BasicKrb5Test {
System.out.println("Testing etype " + etype); System.out.println("Testing etype " + etype);
if (etype != null && !EType.isSupported(Config.getInstance().getType(etype))) { if (etype != null && !EType.isSupported(Config.getInstance().getType(etype))) {
// aes256 is not enabled on all systems
System.out.println("Not supported."); System.out.println("Not supported.");
System.exit(0); return;
} }
new BasicKrb5Test().go(OneKDC.SERVER, OneKDC.BACKEND); new BasicKrb5Test().go(OneKDC.SERVER, OneKDC.BACKEND);
...@@ -71,6 +103,7 @@ public class BasicKrb5Test { ...@@ -71,6 +103,7 @@ public class BasicKrb5Test {
c.startAsClient(server, GSSUtil.GSS_KRB5_MECH_OID); c.startAsClient(server, GSSUtil.GSS_KRB5_MECH_OID);
c.x().requestCredDeleg(true); c.x().requestCredDeleg(true);
c.x().requestConf(conf);
s.startAsServer(GSSUtil.GSS_KRB5_MECH_OID); s.startAsServer(GSSUtil.GSS_KRB5_MECH_OID);
c.status(); c.status();
...@@ -90,6 +123,7 @@ public class BasicKrb5Test { ...@@ -90,6 +123,7 @@ public class BasicKrb5Test {
s = null; s = null;
s2.startAsClient(backend, GSSUtil.GSS_KRB5_MECH_OID); s2.startAsClient(backend, GSSUtil.GSS_KRB5_MECH_OID);
s2.x().requestConf(conf);
b.startAsServer(GSSUtil.GSS_KRB5_MECH_OID); b.startAsServer(GSSUtil.GSS_KRB5_MECH_OID);
s2.status(); s2.status();
......
/* /*
* 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. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
* *
* This code is free software; you can redistribute it and/or modify it * This code is free software; you can redistribute it and/or modify it
...@@ -42,7 +42,8 @@ import org.ietf.jgss.Oid; ...@@ -42,7 +42,8 @@ import org.ietf.jgss.Oid;
import com.sun.security.jgss.ExtendedGSSContext; import com.sun.security.jgss.ExtendedGSSContext;
import com.sun.security.jgss.InquireType; import com.sun.security.jgss.InquireType;
import com.sun.security.jgss.AuthorizationDataEntry; 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. * Context of a JGSS subject, encapsulating Subject and GSSContext.
...@@ -78,6 +79,8 @@ public class Context { ...@@ -78,6 +79,8 @@ public class Context {
private String name; private String name;
private GSSCredential cred; // see static method delegated(). private GSSCredential cred; // see static method delegated().
static boolean usingStream = false;
private Context() {} private Context() {}
/** /**
...@@ -365,7 +368,14 @@ public class Context { ...@@ -365,7 +368,14 @@ public class Context {
public byte[] run(Context me, byte[] dummy) throws Exception { public byte[] run(Context me, byte[] dummy) throws Exception {
System.out.println("wrap"); System.out.println("wrap");
MessageProp p1 = new MessageProp(0, true); 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)); System.out.println(printProp(p1));
return out; return out;
} }
...@@ -375,27 +385,46 @@ public class Context { ...@@ -375,27 +385,46 @@ public class Context {
@Override @Override
public byte[] run(Context me, byte[] input) throws Exception { public byte[] run(Context me, byte[] input) throws Exception {
MessageProp p1 = new MessageProp(0, true); 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)) if (!Arrays.equals(messageBytes, bytes))
throw new Exception("wrap/unwrap mismatch"); throw new Exception("wrap/unwrap mismatch");
System.out.println("unwrap"); System.out.println("unwrap");
System.out.println(printProp(p1)); System.out.println(printProp(p1));
p1 = new MessageProp(0, true); p1 = new MessageProp(0, true);
System.out.println("getMIC"); 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)); System.out.println(printProp(p1));
return bytes; return bytes;
} }
}, t); }, t);
// Re-unwrap should make p2.isDuplicateToken() returns true // Re-unwrap should make p2.isDuplicateToken() returns true
s1.doAs(new Action() { s1.doAs(new Action() {
@Override @Override
public byte[] run(Context me, byte[] input) throws Exception { public byte[] run(Context me, byte[] input) throws Exception {
MessageProp p1 = new MessageProp(0, true); MessageProp p1 = new MessageProp(0, true);
System.out.println("verifyMIC"); System.out.println("verifyMIC");
if (usingStream) {
me.x.verifyMIC(new ByteArrayInputStream(input),
new ByteArrayInputStream(messageBytes), p1);
} else {
me.x.verifyMIC(input, 0, input.length, me.x.verifyMIC(input, 0, input.length,
messageBytes, 0, messageBytes.length, messageBytes, 0, messageBytes.length,
p1); p1);
}
System.out.println(printProp(p1)); System.out.println(printProp(p1));
return null; return null;
} }
...@@ -416,7 +445,9 @@ public class Context { ...@@ -416,7 +445,9 @@ public class Context {
sb.append(prop.isGapToken()?"gap, ":""); sb.append(prop.isGapToken()?"gap, ":"");
sb.append(prop.isOldToken()?"old, ":""); sb.append(prop.isOldToken()?"old, ":"");
sb.append(prop.isUnseqToken()?"unseq, ":""); sb.append(prop.isUnseqToken()?"unseq, ":"");
if (prop.getMinorStatus() != 0) {
sb.append(prop.getMinorString()+ "(" + prop.getMinorStatus()+")"); sb.append(prop.getMinorString()+ "(" + prop.getMinorStatus()+")");
}
return sb.toString(); return sb.toString();
} }
...@@ -442,9 +473,15 @@ public class Context { ...@@ -442,9 +473,15 @@ public class Context {
return null; return null;
} else { } else {
System.out.println(c.name + " call initSecContext"); System.out.println(c.name + " call initSecContext");
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); return me.x.initSecContext(input, 0, input.length);
} }
} }
}
}, t); }, t);
t = s.doAs(new Action() { t = s.doAs(new Action() {
...@@ -460,9 +497,15 @@ public class Context { ...@@ -460,9 +497,15 @@ public class Context {
return null; return null;
} else { } else {
System.out.println(s.name + " called acceptSecContext"); System.out.println(s.name + " called acceptSecContext");
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); return me.x.acceptSecContext(input, 0, input.length);
} }
} }
}
}, t); }, t);
} }
} }
......
#
# 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
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册