6959292: regression: cannot login if session key and preauth does not use the same etype
authorweijun
Thu, 17 Jun 2010 13:46:15 +0800
changeset 5802 ea99d72d3c19
parent 5801 8008ed6e4a37
child 5803 c3ddaebe216b
6959292: regression: cannot login if session key and preauth does not use the same etype Reviewed-by: xuelei, valeriep
jdk/src/share/classes/sun/security/krb5/Credentials.java
jdk/src/share/classes/sun/security/krb5/EncryptionKey.java
jdk/src/share/classes/sun/security/krb5/KrbAsReq.java
jdk/src/share/classes/sun/security/krb5/internal/KRBError.java
jdk/src/windows/classes/sun/security/krb5/internal/tools/Kinit.java
jdk/test/sun/security/krb5/auto/KDC.java
jdk/test/sun/security/krb5/auto/W83.java
--- a/jdk/src/share/classes/sun/security/krb5/Credentials.java	Wed Jun 16 14:07:47 2010 -0700
+++ b/jdk/src/share/classes/sun/security/krb5/Credentials.java	Thu Jun 17 13:46:15 2010 +0800
@@ -356,7 +356,6 @@
      * @param princ the client principal. This value cannot be null.
      * @param secretKey the secret key of the client principal.This value
      * cannot be null.
-     * @param password if null, caller is using a keytab
      * @returns the TGT credentials
      */
     public static Credentials acquireTGT(PrincipalName princ,
@@ -373,18 +372,8 @@
                         "Cannot have null secretKey to do AS-Exchange");
 
         KrbAsRep asRep = null;
-
-        // The etype field to be placed in AS-REQ. If caller is using keytab,
-        // it must be limited to etypes in keytab. Otherwise, leave it null,
-        // and KrbAsReq will populate it with all supported etypes.
-
-        int[] eTypes = null;
-        if (password == null) {
-            eTypes = EncryptionKey.getETypes(secretKeys);
-        }
-
         try {
-            asRep = sendASRequest(princ, secretKeys, eTypes, null);
+            asRep = sendASRequest(princ, secretKeys, null);
         } catch (KrbException ke) {
             if ((ke.returnCode() == Krb5.KDC_ERR_PREAUTH_FAILED) ||
                 (ke.returnCode() == Krb5.KDC_ERR_PREAUTH_REQUIRED)) {
@@ -407,7 +396,7 @@
                                 princ.getSalt(), true,
                                 error.getEType(), error.getParams());
                 }
-                asRep = sendASRequest(princ, secretKeys, eTypes, ke.getError());
+                asRep = sendASRequest(princ, secretKeys, ke.getError());
             } else {
                 throw ke;
             }
@@ -417,18 +406,17 @@
 
     /**
      * Sends the AS-REQ
-     * @param eTypes not null if caller using keytab
      */
     private static KrbAsRep sendASRequest(PrincipalName princ,
-        EncryptionKey[] secretKeys, int[] eTypes, KRBError error)
+        EncryptionKey[] secretKeys, KRBError error)
         throws KrbException, IOException {
 
         // %%%
         KrbAsReq asReq = null;
         if (error == null) {
-            asReq = new KrbAsReq(princ, secretKeys, eTypes);
+            asReq = new KrbAsReq(princ, secretKeys);
         } else {
-            asReq = new KrbAsReq(princ, secretKeys, eTypes, true,
+            asReq = new KrbAsReq(princ, secretKeys, true,
                         error.getEType(), error.getSalt(), error.getParams());
         }
 
--- a/jdk/src/share/classes/sun/security/krb5/EncryptionKey.java	Wed Jun 16 14:07:47 2010 -0700
+++ b/jdk/src/share/classes/sun/security/krb5/EncryptionKey.java	Thu Jun 17 13:46:15 2010 +0800
@@ -76,26 +76,6 @@
 
     private static final boolean DEBUG = Krb5.DEBUG;
 
-    public static int[] getETypes(EncryptionKey[] keys) {
-        int len = keys.length;
-        int[] result = new int[len];
-        int count = 0;  // Number of elements in result. Might be less than
-                        // len if there are keys having the same etype
-        loopi: for (int i=0; i<len; i++) {
-            int eType = keys[i].getEType();
-            for (int j=0; j<count; j++) {
-                if (result[j] == eType) {
-                    continue loopi;
-                }
-            }
-            result[count++] = eType;
-        }
-        if (count != len) {
-            result = Arrays.copyOf(result, count);
-        }
-        return result;
-    }
-
     public synchronized int getEType() {
         return keyType;
     }
@@ -208,24 +188,13 @@
             etypes = EType.getBuiltInDefaults();
         }
 
-        // set the preferred etype for preauth
-        if ((pa_exists) && (pa_etype != EncryptedData.ETYPE_NULL)) {
-            if (DEBUG) {
-                System.out.println("Pre-Authentication: " +
-                        "Set preferred etype = " + pa_etype);
-            }
-            if (EType.isSupported(pa_etype)) {
-                // reset etypes to preferred value
-                etypes = new int[1];
-                etypes[0] = pa_etype;
-            }
-        }
-
         EncryptionKey[] encKeys = new EncryptionKey[etypes.length];
         for (int i = 0; i < etypes.length; i++) {
             if (EType.isSupported(etypes[i])) {
+                byte[] s2kparams = (pa_exists && etypes[i] == pa_etype)
+                        ? pa_s2kparams : null;
                 encKeys[i] = new EncryptionKey(
-                        stringToKey(password, salt, pa_s2kparams, etypes[i]),
+                        stringToKey(password, salt, s2kparams, etypes[i]),
                         etypes[i], null);
             } else {
                 if (DEBUG) {
--- a/jdk/src/share/classes/sun/security/krb5/KrbAsReq.java	Wed Jun 16 14:07:47 2010 -0700
+++ b/jdk/src/share/classes/sun/security/krb5/KrbAsReq.java	Thu Jun 17 13:46:15 2010 +0800
@@ -35,9 +35,11 @@
 import sun.security.krb5.internal.crypto.EType;
 import sun.security.krb5.internal.crypto.Nonce;
 import sun.security.krb5.internal.crypto.KeyUsage;
+import sun.security.util.*;
 import java.io.IOException;
+import java.io.ByteArrayInputStream;
 import java.net.UnknownHostException;
-import java.util.Arrays;
+import java.util.StringTokenizer;
 
 /**
  * This class encapsulates the KRB-AS-REQ message that the client
@@ -62,13 +64,11 @@
 
     /**
      * Creates a KRB-AS-REQ to send to the default KDC
-     * @param eTypes not null when using a keytab, this can make sure the etypes
-     * in AS-REQ contains only those available on client
      * @throws KrbException
      * @throws IOException
      */
      // Called by Credentials
-    KrbAsReq(PrincipalName principal, EncryptionKey[] keys, int[] eTypes)
+    KrbAsReq(PrincipalName principal, EncryptionKey[] keys)
         throws KrbException, IOException {
         this(keys, // for pre-authentication
              false, 0, null, null, // pre-auth values
@@ -78,7 +78,7 @@
              null, // KerberosTime from
              null, // KerberosTime till
              null, // KerberosTime rtime
-             eTypes, // int[] eTypes
+             null, // int[] eTypes
              null, // HostAddresses addresses
              null); // Ticket[] additionalTickets
     }
@@ -86,10 +86,8 @@
     /**
      * Creates a KRB-AS-REQ to send to the default KDC
      * with pre-authentication values
-     * @param eTypes not null when using a keytab, this can make sure the etypes
-     * in AS-REQ contains only those available on client
      */
-    KrbAsReq(PrincipalName principal, EncryptionKey[] keys, int[] eTypes,
+    KrbAsReq(PrincipalName principal, EncryptionKey[] keys,
         boolean pa_exists, int etype, String salt, byte[] s2kparams)
         throws KrbException, IOException {
         this(keys, // for pre-authentication
@@ -100,7 +98,7 @@
              null, // KerberosTime from
              null, // KerberosTime till
              null, // KerberosTime rtime
-             eTypes, // int[] eTypes
+             null, // int[] eTypes
              null, // HostAddresses addresses
              null); // Ticket[] additionalTickets
     }
@@ -344,24 +342,18 @@
         }
 
         princName = cname;
-
-        // keys might contain many etypes, or only one if in preauth mode,
-        // coz EncryptionKey.acquireSecretKeys() with pa returns only one key.
-
+        int[] tktETypes = EType.getDefaults("default_tkt_enctypes", keys);
         PAData[] paData = null;
         if (PA_ENC_TIMESTAMP_REQUIRED) {
             EncryptionKey key = null;
             if (pa_etype != EncryptedData.ETYPE_NULL) {
                 if (DEBUG) {
-                    System.out.println("Pre-Authenticaton: " +
-                            "find key for etype = " + pa_etype);
+                    System.out.println("Pre-Authenticaton: find key for etype = " + pa_etype);
                 }
                 key = EncryptionKey.findKey(pa_etype, keys);
             } else {
-                int[] availableETypes =
-                        EType.getDefaults("default_tkt_enctypes", keys);
-                if (availableETypes.length > 0) {
-                    key = EncryptionKey.findKey(availableETypes[0], keys);
+                if (tktETypes.length > 0) {
+                    key = EncryptionKey.findKey(tktETypes[0], keys);
                 }
             }
             if (DEBUG) {
@@ -384,7 +376,7 @@
         }
 
         if (eTypes == null) {
-            eTypes = EType.getDefaults("default_tkt_enctypes");
+            eTypes = tktETypes;
         }
 
         // check to use addresses in tickets
--- a/jdk/src/share/classes/sun/security/krb5/internal/KRBError.java	Wed Jun 16 14:07:47 2010 -0700
+++ b/jdk/src/share/classes/sun/security/krb5/internal/KRBError.java	Thu Jun 17 13:46:15 2010 +0800
@@ -286,6 +286,19 @@
                         salt = info.getSalt();
                         if (DEBUG) {
                             System.out.println("\t PA-ETYPE-INFO etype = " + etype);
+                            System.out.println("\t PA-ETYPE-INFO salt = " + salt);
+                        }
+                        while (der.data.available() > 0) {
+                            value = der.data.getDerValue();
+                            info = new ETypeInfo(value);
+                            if (DEBUG) {
+                                etype = info.getEType();
+                                System.out.println("\t salt for " + etype
+                                        + " is " + info.getSalt());
+                            }
+                            if (salt == null || salt.isEmpty()) {
+                                salt = info.getSalt();
+                            }
                         }
                     }
                     break;
@@ -299,6 +312,19 @@
                         s2kparams = info2.getParams();
                         if (DEBUG) {
                             System.out.println("\t PA-ETYPE-INFO2 etype = " + etype);
+                            System.out.println("\t PA-ETYPE-INFO salt = " + salt);
+                        }
+                        while (der.data.available() > 0) {
+                            value = der.data.getDerValue();
+                            info2 = new ETypeInfo2(value);
+                            if (DEBUG) {
+                                etype = info2.getEType();
+                                System.out.println("\t salt for " + etype
+                                        + " is " + info2.getSalt());
+                            }
+                            if (salt == null || salt.isEmpty()) {
+                                salt = info2.getSalt();
+                            }
                         }
                     }
                     break;
--- a/jdk/src/windows/classes/sun/security/krb5/internal/tools/Kinit.java	Wed Jun 16 14:07:47 2010 -0700
+++ b/jdk/src/windows/classes/sun/security/krb5/internal/tools/Kinit.java	Thu Jun 17 13:46:15 2010 +0800
@@ -229,9 +229,7 @@
             if (useKeytab) {
                 as_req = new KrbAsReq(skeys, opt,
                                       principal, sname,
-                                      null, null, null,
-                                      EncryptionKey.getETypes(skeys),
-                                      addresses, null);
+                                      null, null, null, null, addresses, null);
             } else {
                 as_req = new KrbAsReq(psswd, opt,
                                       principal, sname,
@@ -259,9 +257,7 @@
                 if (useKeytab) {
                     as_req = new KrbAsReq(skeys, true, etype, salt,
                                         s2kparams, opt, principal, sname,
-                                        null, null, null,
-                                        EncryptionKey.getETypes(skeys),
-                                        addresses, null);
+                                        null, null, null, null, addresses, null);
                 } else {
                     as_req = new KrbAsReq(psswd, true, etype, salt,
                                         s2kparams, opt, principal, sname,
--- a/jdk/test/sun/security/krb5/auto/KDC.java	Wed Jun 16 14:07:47 2010 -0700
+++ b/jdk/test/sun/security/krb5/auto/KDC.java	Thu Jun 17 13:46:15 2010 +0800
@@ -155,9 +155,13 @@
          */
         PREAUTH_REQUIRED,
         /**
-         * Onlyy issue TGT in RC4
+         * Only issue TGT in RC4
          */
         ONLY_RC4_TGT,
+        /**
+         * Only use RC4 in preauth, enc-type still using eTypes[0]
+         */
+        ONLY_RC4_PREAUTH,
     };
 
     static {
@@ -905,7 +909,11 @@
                         ke.returnCode() == Krb5.KDC_ERR_PREAUTH_FAILED) {
                     PAData pa;
 
-                    ETypeInfo2 ei2 = new ETypeInfo2(eTypes[0], null, null);
+                    int epa = eTypes[0];
+                    if (options.containsKey(KDC.Option.ONLY_RC4_PREAUTH)) {
+                        epa = EncryptedData.ETYPE_ARCFOUR_HMAC;
+                    }
+                    ETypeInfo2 ei2 = new ETypeInfo2(epa, null, null);
                     DerOutputStream eid = new DerOutputStream();
                     eid.write(DerValue.tag_Sequence, ei2.asn1Encode());
 
@@ -924,7 +932,7 @@
                         }
                     }
                     if (allOld) {
-                        ETypeInfo ei = new ETypeInfo(eTypes[0], null);
+                        ETypeInfo ei = new ETypeInfo(epa, null);
                         eid = new DerOutputStream();
                         eid.write(DerValue.tag_Sequence, ei.asn1Encode());
                         pa = new PAData(Krb5.PA_ETYPE_INFO, eid.toByteArray());
--- a/jdk/test/sun/security/krb5/auto/W83.java	Wed Jun 16 14:07:47 2010 -0700
+++ b/jdk/test/sun/security/krb5/auto/W83.java	Thu Jun 17 13:46:15 2010 +0800
@@ -23,8 +23,9 @@
 
 /*
  * @test
- * @bug 6951366
+ * @bug 6932525 6951366 6959292
  * @summary kerberos login failure on win2008 with AD set to win2000 compat mode
+ * and cannot login if session key and preauth does not use the same etype
  */
 import com.sun.security.auth.module.Krb5LoginModule;
 import java.io.File;
@@ -52,8 +53,6 @@
         new File(OneKDC.KRB5_CONF).deleteOnExit();
         new File(OneKDC.KTAB).deleteOnExit();
 
-        kdc.setOption(KDC.Option.ONLY_RC4_TGT, true);
-
         KeyTab ktab = KeyTab.getInstance(OneKDC.KTAB);
         for (int etype: EType.getBuiltInDefaults()) {
             if (etype != EncryptedData.ETYPE_ARCFOUR_HMAC) {
@@ -61,6 +60,15 @@
             }
         }
         ktab.save();
+
+        // For 6932525 and 6951366, make sure the etypes sent in 2nd AS-REQ
+        // is not restricted to that of preauth
+        kdc.setOption(KDC.Option.ONLY_RC4_TGT, true);
+        x.go();
+
+        // For 6959292, make sure that when etype for enc-part in 2nd AS-REQ
+        // is different from that of preauth, client can still decrypt it
+        kdc.setOption(KDC.Option.ONLY_RC4_PREAUTH, true);
         x.go();
     }