8178714: PKIX validator nameConstraints check failing after change 8175940

Reviewed-by: mullan, ahgross
This commit is contained in:
Weijun Wang 2017-05-18 08:52:50 +08:00
parent 8c6afbd3da
commit e7fdfdb7e7
2 changed files with 81 additions and 76 deletions

View File

@ -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. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
* *
* This code is free software; you can redistribute it and/or modify it * This code is free software; you can redistribute it and/or modify it
@ -194,45 +194,31 @@ public class DNSName implements GeneralNameInterface {
*/ */
public int constrains(GeneralNameInterface inputName) throws UnsupportedOperationException { public int constrains(GeneralNameInterface inputName) throws UnsupportedOperationException {
int constraintType; int constraintType;
if (inputName == null) { if (inputName == null)
return NAME_DIFF_TYPE; constraintType = NAME_DIFF_TYPE;
} else if (inputName.getType() != NAME_DNS)
String inName; constraintType = NAME_DIFF_TYPE;
switch (inputName.getType()) { else {
case NAME_DNS: String inName =
inName = ((DNSName)inputName).getName(); (((DNSName)inputName).getName()).toLowerCase(Locale.ENGLISH);
break; String thisName = name.toLowerCase(Locale.ENGLISH);
case NAME_DIRECTORY: if (inName.equals(thisName))
try { constraintType = NAME_MATCH;
inName = ((X500Name) inputName).getCommonName(); else if (thisName.endsWith(inName)) {
if (inName == null) { int inNdx = thisName.lastIndexOf(inName);
return NAME_DIFF_TYPE; if (thisName.charAt(inNdx-1) == '.' )
} constraintType = NAME_WIDENS;
} catch (IOException ioe) { else
return NAME_DIFF_TYPE; constraintType = NAME_SAME_TYPE;
} } else if (inName.endsWith(thisName)) {
break; int ndx = inName.lastIndexOf(thisName);
default: if (inName.charAt(ndx-1) == '.' )
return NAME_DIFF_TYPE; constraintType = NAME_NARROWS;
} else
inName = inName.toLowerCase(Locale.ENGLISH); constraintType = NAME_SAME_TYPE;
String thisName = name.toLowerCase(Locale.ENGLISH); } else {
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; 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; return constraintType;
} }

View File

@ -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. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
* *
* This code is free software; you can redistribute it and/or modify it * This code is free software; you can redistribute it and/or modify it
@ -33,6 +33,7 @@ import java.util.*;
import javax.security.auth.x500.X500Principal; import javax.security.auth.x500.X500Principal;
import sun.net.util.IPAddressUtil;
import sun.security.util.*; import sun.security.util.*;
import sun.security.pkcs.PKCS9Attribute; import sun.security.pkcs.PKCS9Attribute;
@ -440,6 +441,7 @@ implements CertAttrSet<String>, Cloneable {
X500Principal subjectPrincipal = cert.getSubjectX500Principal(); X500Principal subjectPrincipal = cert.getSubjectX500Principal();
X500Name subject = X500Name.asX500Name(subjectPrincipal); X500Name subject = X500Name.asX500Name(subjectPrincipal);
// Check subject as an X500Name
if (subject.isEmpty() == false) { if (subject.isEmpty() == false) {
if (verify(subject) == false) { if (verify(subject) == false) {
return false; return false;
@ -465,12 +467,51 @@ implements CertAttrSet<String>, Cloneable {
"certificate: " + ce.getMessage()); "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) { 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 // verify each subjectAltName
@ -485,6 +526,15 @@ implements CertAttrSet<String>, Cloneable {
return true; 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. * check whether a name conforms to these NameConstraints.
* This involves verifying that the name is consistent with the * This involves verifying that the name is consistent with the
@ -566,37 +616,6 @@ implements CertAttrSet<String>, Cloneable {
return true; return true;
} }
/**
* 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. * Clone all objects that may be modified during certificate validation.
*/ */