changeset 3321:1f0f0737f04e

6975866: api/org_ietf/jgss/GSSContext/index.html#wrapUnwrapIOTest started to fail since jdk7 b102 Reviewed-by: valeriep
author weijun
date Fri, 17 Dec 2010 11:03:33 +0800
parents e67a399dd4ad
children ae84db37130a
files src/share/classes/sun/security/jgss/krb5/CipherHelper.java src/share/classes/sun/security/jgss/krb5/MessageToken_v2.java src/share/classes/sun/security/jgss/krb5/MicToken_v2.java src/share/classes/sun/security/jgss/krb5/WrapToken.java src/share/classes/sun/security/jgss/krb5/WrapToken_v2.java test/sun/security/krb5/auto/BasicKrb5Test.java test/sun/security/krb5/auto/Context.java test/sun/security/krb5/auto/basic.sh
diffstat 8 files changed, 346 insertions(+), 648 deletions(-) [+]
line wrap: on
line diff
--- a/src/share/classes/sun/security/jgss/krb5/CipherHelper.java	Thu Dec 16 20:52:09 2010 +0530
+++ b/src/share/classes/sun/security/jgss/krb5/CipherHelper.java	Fri Dec 17 11:03:33 2010 +0800
@@ -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 @@
      * 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,
--- a/src/share/classes/sun/security/jgss/krb5/MessageToken_v2.java	Thu Dec 16 20:52:09 2010 +0530
+++ b/src/share/classes/sun/security/jgss/krb5/MessageToken_v2.java	Fri Dec 17 11:03:33 2010 +0800
@@ -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 @@
  *     -----------------------------------------------------------------
  *      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 @@
     /**
      * 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 @@
                                 : 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 @@
             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 @@
      * 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 @@
 
         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 @@
 
     /**
      * 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 @@
 
             // 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 @@
                 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 @@
             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 @@
                 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 @@
                 }
             }
 
-            // 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);
         }
 
         /**
--- a/src/share/classes/sun/security/jgss/krb5/MicToken_v2.java	Thu Dec 16 20:52:09 2010 +0530
+++ b/src/share/classes/sun/security/jgss/krb5/MicToken_v2.java	Fri Dec 17 11:03:33 2010 +0800
@@ -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 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 @@
                   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 @@
     }
 
     public void verify(InputStream data) throws GSSException {
-
         byte[] dataBytes = null;
         try {
             dataBytes = new byte[data.available()];
@@ -79,7 +76,7 @@
 
     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 @@
     }
 
     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 @@
         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);
+    }
 }
--- a/src/share/classes/sun/security/jgss/krb5/WrapToken.java	Thu Dec 16 20:52:09 2010 +0530
+++ b/src/share/classes/sun/security/jgss/krb5/WrapToken.java	Fri Dec 17 11:03:33 2010 +0800
@@ -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 @@
 
 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 @@
                 // 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,
--- a/src/share/classes/sun/security/jgss/krb5/WrapToken_v2.java	Thu Dec 16 20:52:09 2010 +0530
+++ b/src/share/classes/sun/security/jgss/krb5/WrapToken_v2.java	Fri Dec 17 11:03:33 2010 +0800
@@ -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 @@
 
 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 @@
                      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 @@
                      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 @@
      */
     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 @@
     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 @@
                 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 @@
             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 @@
     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 */);
     }
 }
--- a/test/sun/security/krb5/auto/BasicKrb5Test.java	Thu Dec 16 20:52:09 2010 +0530
+++ b/test/sun/security/krb5/auto/BasicKrb5Test.java	Fri Dec 17 11:03:33 2010 +0800
@@ -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 @@
  */
 public class BasicKrb5Test {
 
+    private static boolean conf = true;
     /**
      * @param args empty or etype
      */
@@ -46,8 +75,10 @@
             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 @@
 
         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 @@
 
         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 @@
         s = null;
 
         s2.startAsClient(backend, GSSUtil.GSS_KRB5_MECH_OID);
+        s2.x().requestConf(conf);
         b.startAsServer(GSSUtil.GSS_KRB5_MECH_OID);
 
         s2.status();
--- a/test/sun/security/krb5/auto/Context.java	Thu Dec 16 20:52:09 2010 +0530
+++ b/test/sun/security/krb5/auto/Context.java	Fri Dec 17 11:03:33 2010 +0800
@@ -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 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 @@
     private String name;
     private GSSCredential cred;     // see static method delegated().
 
+    static boolean usingStream = false;
+
     private Context() {}
 
     /**
@@ -365,7 +368,14 @@
             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 @@
             @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 @@
         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 @@
                         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 @@
                         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);
--- a/test/sun/security/krb5/auto/basic.sh	Thu Dec 16 20:52:09 2010 +0530
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -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