< prev index next >

src/java.security.jgss/share/classes/sun/security/krb5/KrbKdcRep.java

Print this page

        

@@ -29,28 +29,46 @@
  */
 
 package sun.security.krb5;
 
 import sun.security.krb5.internal.*;
+import sun.security.krb5.internal.crypto.KeyUsage;
+import sun.security.util.DerInputStream;
 
 abstract class KrbKdcRep {
 
     static void check(
                       boolean isAsReq,
                       KDCReq req,
-                      KDCRep rep
+                      KDCRep rep,
+                      EncryptionKey replyKey
                       ) throws KrbApErrException {
 
-        if (isAsReq && !req.reqBody.cname.equals(rep.cname)) {
+        // cname change in AS-REP is allowed only if the client
+        // sent CANONICALIZE and the server supports RFC 6806 - Section 11
+        // FAST scheme (ENC-PA-REP flag).
+        if (isAsReq && !req.reqBody.cname.equals(rep.cname) &&
+                (!req.reqBody.kdcOptions.get(KDCOptions.CANONICALIZE) ||
+                 !rep.encKDCRepPart.flags.get(Krb5.TKT_OPTS_ENC_PA_REP))) {
             rep.encKDCRepPart.key.destroy();
             throw new KrbApErrException(Krb5.KRB_AP_ERR_MODIFIED);
         }
 
+        // sname change in TGS-REP is allowed only if client
+        // sent CANONICALIZE and new sname is a referral of
+        // the form krbtgt/TO-REALM.COM@FROM-REALM.COM.
         if (!req.reqBody.sname.equals(rep.encKDCRepPart.sname)) {
+            String[] snameStrings = rep.encKDCRepPart.sname.getNameStrings();
+            if (isAsReq || !req.reqBody.kdcOptions.get(KDCOptions.CANONICALIZE) ||
+                    snameStrings == null || snameStrings.length != 2 ||
+                    !snameStrings[0].equals(PrincipalName.TGS_DEFAULT_SRV_NAME) ||
+                    !rep.encKDCRepPart.sname.getRealmString().equals(
+                            req.reqBody.sname.getRealmString())) {
             rep.encKDCRepPart.key.destroy();
             throw new KrbApErrException(Krb5.KRB_AP_ERR_MODIFIED);
         }
+        }
 
         if (req.reqBody.getNonce() != rep.encKDCRepPart.nonce) {
             rep.encKDCRepPart.key.destroy();
             throw new KrbApErrException(Krb5.KRB_AP_ERR_MODIFIED);
         }

@@ -116,7 +134,42 @@
                     rep.encKDCRepPart.key.destroy();
                     throw new KrbApErrException(Krb5.KRB_AP_ERR_MODIFIED);
                 }
             }
         }
+
+        // RFC 6806 - Section 11 mechanism check
+        if (rep.encKDCRepPart.flags.get(Krb5.TKT_OPTS_ENC_PA_REP) &&
+                req.reqBody.kdcOptions.get(KDCOptions.CANONICALIZE)) {
+            boolean reqPaReqEncPaRep = false;
+            boolean repPaReqEncPaRepValid = false;
+
+            // PA_REQ_ENC_PA_REP only required for AS requests
+            for (PAData pa : req.pAData) {
+                if (pa.getType() == Krb5.PA_REQ_ENC_PA_REP) {
+                    reqPaReqEncPaRep = true;
+                    break;
+                }
+            }
+
+            for (PAData pa : rep.encKDCRepPart.pAData) {
+                if (pa.getType() == Krb5.PA_REQ_ENC_PA_REP) {
+                    try {
+                        Checksum repCksum = new Checksum(
+                                new DerInputStream(pa.getValue()).getDerValue());
+                        repPaReqEncPaRepValid = repCksum.verifyKeyedChecksum(
+                                req.asn1Encode(), replyKey, KeyUsage.KU_AS_REQ);
+                    } catch (Exception e) {
+                        if (Krb5.DEBUG) {
+                            e.printStackTrace();
+                        }
+                    }
+                    break;
+                }
+            }
+
+            if (reqPaReqEncPaRep && !repPaReqEncPaRepValid) {
+                throw new KrbApErrException(Krb5.KRB_AP_ERR_MODIFIED);
+            }
+        }
     }
 }
< prev index next >