8178714: PKIX validator nameConstraints check failing after change 8175940
authorweijun
Thu, 18 May 2017 08:52:50 +0800
changeset 47413 17b77ca4d419
parent 47412 194f4c32678b
child 47414 3448b80444f3
8178714: PKIX validator nameConstraints check failing after change 8175940 Reviewed-by: mullan, ahgross
src/java.base/share/classes/sun/security/x509/DNSName.java
src/java.base/share/classes/sun/security/x509/NameConstraintsExtension.java
--- a/src/java.base/share/classes/sun/security/x509/DNSName.java	Tue Mar 28 12:10:20 2017 -0700
+++ b/src/java.base/share/classes/sun/security/x509/DNSName.java	Thu May 18 08:52:50 2017 +0800
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 1997, 2017, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1997, 2011, 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
@@ -194,45 +194,31 @@
      */
     public int constrains(GeneralNameInterface inputName) throws UnsupportedOperationException {
         int constraintType;
-        if (inputName == null) {
-            return NAME_DIFF_TYPE;
-        }
-        String inName;
-        switch (inputName.getType()) {
-            case NAME_DNS:
-                inName = ((DNSName)inputName).getName();
-                break;
-            case NAME_DIRECTORY:
-                try {
-                    inName = ((X500Name) inputName).getCommonName();
-                    if (inName == null) {
-                        return NAME_DIFF_TYPE;
-                    }
-                } catch (IOException ioe) {
-                    return NAME_DIFF_TYPE;
-                }
-                break;
-            default:
-                return NAME_DIFF_TYPE;
-        }
-        inName = inName.toLowerCase(Locale.ENGLISH);
-        String thisName = name.toLowerCase(Locale.ENGLISH);
-        if (inName.equals(thisName))
-            constraintType = NAME_MATCH;
-        else if (thisName.endsWith(inName)) {
-            int inNdx = thisName.lastIndexOf(inName);
-            if (thisName.charAt(inNdx-1) == '.' )
-                constraintType = NAME_WIDENS;
-            else
+        if (inputName == null)
+            constraintType = NAME_DIFF_TYPE;
+        else if (inputName.getType() != NAME_DNS)
+            constraintType = NAME_DIFF_TYPE;
+        else {
+            String inName =
+                (((DNSName)inputName).getName()).toLowerCase(Locale.ENGLISH);
+            String thisName = name.toLowerCase(Locale.ENGLISH);
+            if (inName.equals(thisName))
+                constraintType = NAME_MATCH;
+            else if (thisName.endsWith(inName)) {
+                int inNdx = thisName.lastIndexOf(inName);
+                if (thisName.charAt(inNdx-1) == '.' )
+                    constraintType = NAME_WIDENS;
+                else
+                    constraintType = NAME_SAME_TYPE;
+            } else if (inName.endsWith(thisName)) {
+                int ndx = inName.lastIndexOf(thisName);
+                if (inName.charAt(ndx-1) == '.' )
+                    constraintType = NAME_NARROWS;
+                else
+                    constraintType = NAME_SAME_TYPE;
+            } else {
                 constraintType = NAME_SAME_TYPE;
-        } else if (inName.endsWith(thisName)) {
-            int ndx = inName.lastIndexOf(thisName);
-            if (inName.charAt(ndx-1) == '.' )
-                constraintType = NAME_NARROWS;
-            else
-                constraintType = NAME_SAME_TYPE;
-        } else {
-            constraintType = NAME_SAME_TYPE;
+            }
         }
         return constraintType;
     }
--- a/src/java.base/share/classes/sun/security/x509/NameConstraintsExtension.java	Tue Mar 28 12:10:20 2017 -0700
+++ b/src/java.base/share/classes/sun/security/x509/NameConstraintsExtension.java	Thu May 18 08:52:50 2017 +0800
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 1997, 2015, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1997, 2017, 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
@@ -33,6 +33,7 @@
 
 import javax.security.auth.x500.X500Principal;
 
+import sun.net.util.IPAddressUtil;
 import sun.security.util.*;
 import sun.security.pkcs.PKCS9Attribute;
 
@@ -440,6 +441,7 @@
         X500Principal subjectPrincipal = cert.getSubjectX500Principal();
         X500Name subject = X500Name.asX500Name(subjectPrincipal);
 
+        // Check subject as an X500Name
         if (subject.isEmpty() == false) {
             if (verify(subject) == false) {
                 return false;
@@ -465,12 +467,51 @@
                         "certificate: " + ce.getMessage());
         }
 
-        // If there are no subjectAlternativeNames, perform the special-case
-        // check where if the subjectName contains any EMAILADDRESS
-        // attributes, they must be checked against RFC822 constraints.
-        // If that passes, we're fine.
         if (altNames == null) {
-            return verifyRFC822SpecialCase(subject);
+            altNames = new GeneralNames();
+
+            // RFC 5280 4.2.1.10:
+            // When constraints are imposed on the rfc822Name name form,
+            // but the certificate does not include a subject alternative name,
+            // the rfc822Name constraint MUST be applied to the attribute of
+            // type emailAddress in the subject distinguished name.
+            for (AVA ava : subject.allAvas()) {
+                ObjectIdentifier attrOID = ava.getObjectIdentifier();
+                if (attrOID.equals(PKCS9Attribute.EMAIL_ADDRESS_OID)) {
+                    String attrValue = ava.getValueString();
+                    if (attrValue != null) {
+                        try {
+                            altNames.add(new GeneralName(
+                                    new RFC822Name(attrValue)));
+                        } catch (IOException ioe) {
+                            continue;
+                        }
+                    }
+                }
+            }
+        }
+
+        // If there is no IPAddressName or DNSName in subjectAlternativeNames,
+        // see if the last CN inside subjectName can be used instead.
+        DerValue derValue = subject.findMostSpecificAttribute
+                (X500Name.commonName_oid);
+        String cn = derValue == null ? null : derValue.getAsString();
+
+        if (cn != null) {
+            try {
+                if (IPAddressUtil.isIPv4LiteralAddress(cn) ||
+                        IPAddressUtil.isIPv6LiteralAddress(cn)) {
+                    if (!hasNameType(altNames, GeneralNameInterface.NAME_IP)) {
+                        altNames.add(new GeneralName(new IPAddressName(cn)));
+                    }
+                } else {
+                    if (!hasNameType(altNames, GeneralNameInterface.NAME_DNS)) {
+                        altNames.add(new GeneralName(new DNSName(cn)));
+                    }
+                }
+            } catch (IOException ioe) {
+                // OK, cn is neither IP nor DNS
+            }
         }
 
         // verify each subjectAltName
@@ -485,6 +526,15 @@
         return true;
     }
 
+    private static boolean hasNameType(GeneralNames names, int type) {
+        for (GeneralName name : names.names()) {
+            if (name.getType() == type) {
+                return true;
+            }
+        }
+        return false;
+    }
+
     /**
      * check whether a name conforms to these NameConstraints.
      * This involves verifying that the name is consistent with the
@@ -567,37 +617,6 @@
     }
 
     /**
-     * Perform the RFC 822 special case check. We have a certificate
-     * that does not contain any subject alternative names. Check that
-     * any EMAILADDRESS attributes in its subject name conform to these
-     * NameConstraints.
-     *
-     * @param subject the certificate's subject name
-     * @return true if certificate verifies successfully
-     * @throws IOException on error
-     */
-    public boolean verifyRFC822SpecialCase(X500Name subject) throws IOException {
-        for (AVA ava : subject.allAvas()) {
-            ObjectIdentifier attrOID = ava.getObjectIdentifier();
-            if (attrOID.equals(PKCS9Attribute.EMAIL_ADDRESS_OID)) {
-                String attrValue = ava.getValueString();
-                if (attrValue != null) {
-                    RFC822Name emailName;
-                    try {
-                        emailName = new RFC822Name(attrValue);
-                    } catch (IOException ioe) {
-                        continue;
-                    }
-                    if (!verify(emailName)) {
-                        return(false);
-                    }
-                }
-             }
-        }
-        return true;
-    }
-
-    /**
      * Clone all objects that may be modified during certificate validation.
      */
     public Object clone() {