jdk/src/share/classes/sun/security/krb5/KrbAsRep.java
changeset 7183 d8ccc1c73358
parent 5975 076cd013e5e4
child 8166 13423c0952ad
--- a/jdk/src/share/classes/sun/security/krb5/KrbAsRep.java	Fri Nov 12 07:15:47 2010 -0500
+++ b/jdk/src/share/classes/sun/security/krb5/KrbAsRep.java	Fri Nov 12 21:33:14 2010 +0800
@@ -36,25 +36,24 @@
 import sun.security.krb5.internal.crypto.EType;
 import sun.security.util.*;
 import java.io.IOException;
+import java.util.Objects;
 
 /**
  * This class encapsulates a AS-REP message that the KDC sends to the
  * client.
  */
-public class KrbAsRep extends KrbKdcRep {
+class KrbAsRep extends KrbKdcRep {
 
-    private ASRep rep;
-    private Credentials creds;
+    private ASRep rep;  // The AS-REP message
+    private Credentials creds;  // The Credentials provide by the AS-REP
+                                // message, created by initiator after calling
+                                // the decrypt() method
 
     private boolean DEBUG = Krb5.DEBUG;
 
-    KrbAsRep(byte[] ibuf, EncryptionKey[] keys, KrbAsReq asReq) throws
-    KrbException, Asn1Exception, IOException {
-        if (keys == null)
-            throw new KrbException(Krb5.API_INVALID_ARG);
+    KrbAsRep(byte[] ibuf) throws
+            KrbException, Asn1Exception, IOException {
         DerValue encoding = new DerValue(ibuf);
-        ASReq req = asReq.getMessage();
-        ASRep rep = null;
         try {
             rep = new ASRep(encoding);
         } catch (Asn1Exception e) {
@@ -83,25 +82,77 @@
             ke.initCause(e);
             throw ke;
         }
+    }
 
+    // KrbAsReqBuilder need to read back the PA for key generation
+    PAData[] getPA() {
+        return rep.pAData;
+    }
+
+    /**
+     * Called by KrbAsReqBuilder to resolve a AS-REP message using keys.
+     * @param keys user provided keys, not null
+     * @param asReq the original AS-REQ sent, used to validate AS-REP
+     */
+    void decryptUsingKeys(EncryptionKey[] keys, KrbAsReq asReq)
+            throws KrbException, Asn1Exception, IOException {
+        EncryptionKey dkey = null;
         int encPartKeyType = rep.encPart.getEType();
-        EncryptionKey dkey = EncryptionKey.findKey(encPartKeyType, keys);
-
+        Integer encPartKvno = rep.encPart.kvno;
+        try {
+            dkey = EncryptionKey.findKey(encPartKeyType, encPartKvno, keys);
+        } catch (KrbException ke) {
+            if (ke.returnCode() == Krb5.KRB_AP_ERR_BADKEYVER) {
+                // Fallback to no kvno. In some cases, keytab is generated
+                // not by sysadmin but Java's ktab command
+                dkey = EncryptionKey.findKey(encPartKeyType, keys);
+            }
+        }
         if (dkey == null) {
             throw new KrbException(Krb5.API_INVALID_ARG,
-                "Cannot find key of appropriate type to decrypt AS REP - " +
-                EType.toString(encPartKeyType));
+                "Cannot find key for type/kvno to decrypt AS REP - " +
+                EType.toString(encPartKeyType) + "/" + encPartKvno);
         }
+        decrypt(dkey, asReq);
+    }
 
+    /**
+     * Called by KrbAsReqBuilder to resolve a AS-REP message using a password.
+     * @param password user provided password. not null
+     * @param asReq the original AS-REQ sent, used to validate AS-REP
+     * @param cname the user principal name, used to provide salt
+     */
+    void decryptUsingPassword(char[] password,
+            KrbAsReq asReq, PrincipalName cname)
+            throws KrbException, Asn1Exception, IOException {
+        int encPartKeyType = rep.encPart.getEType();
+        PAData.SaltAndParams snp =
+                PAData.getSaltAndParams(encPartKeyType, rep.pAData);
+        EncryptionKey dkey = null;
+        dkey = EncryptionKey.acquireSecretKey(password,
+                snp.salt == null ? cname.getSalt() : snp.salt,
+                encPartKeyType,
+                snp.params);
+        decrypt(dkey, asReq);
+    }
+
+    /**
+     * Decrypts encrypted content inside AS-REP. Called by initiator.
+     * @param dkey the decryption key to use
+     * @param asReq the original AS-REQ sent, used to validate AS-REP
+     */
+    private void decrypt(EncryptionKey dkey, KrbAsReq asReq)
+            throws KrbException, Asn1Exception, IOException {
         byte[] enc_as_rep_bytes = rep.encPart.decrypt(dkey,
             KeyUsage.KU_ENC_AS_REP_PART);
         byte[] enc_as_rep_part = rep.encPart.reset(enc_as_rep_bytes);
 
-        encoding = new DerValue(enc_as_rep_part);
+        DerValue encoding = new DerValue(enc_as_rep_part);
         EncASRepPart enc_part = new EncASRepPart(encoding);
         rep.ticket.sname.setRealm(rep.ticket.realm);
         rep.encKDCRepPart = enc_part;
 
+        ASReq req = asReq.getMessage();
         check(req, rep);
 
         creds = new Credentials(
@@ -119,17 +170,13 @@
             System.out.println(">>> KrbAsRep cons in KrbAsReq.getReply " +
                                req.reqBody.cname.getNameString());
         }
-
-        this.rep = rep;
-        this.creds = creds;
     }
 
-    public Credentials getCreds() {
-        return creds;
+    Credentials getCreds() {
+        return Objects.nonNull(creds, "Creds not available yet.");
     }
 
-    // made public for Kinit
-    public sun.security.krb5.internal.ccache.Credentials setCredentials() {
+    sun.security.krb5.internal.ccache.Credentials getCCreds() {
         return new sun.security.krb5.internal.ccache.Credentials(rep);
     }
 }