src/java.security.jgss/share/classes/sun/security/krb5/KrbKdcRep.java
changeset 55258 d65d3c37232c
parent 47216 71c04702a3d5
child 55570 1e95931e7d8f
--- a/src/java.security.jgss/share/classes/sun/security/krb5/KrbKdcRep.java	Thu Jun 06 10:03:22 2019 -0400
+++ b/src/java.security.jgss/share/classes/sun/security/krb5/KrbKdcRep.java	Wed Jun 05 01:42:11 2019 -0300
@@ -31,23 +31,41 @@
 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)) {
-            rep.encKDCRepPart.key.destroy();
-            throw new KrbApErrException(Krb5.KRB_AP_ERR_MODIFIED);
+            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) {
@@ -118,5 +136,45 @@
                 }
             }
         }
+
+        // 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;
+                }
+            }
+
+            if (rep.encKDCRepPart.pAData != null) {
+                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);
+            }
+        }
     }
 }