8165274: SHA1 certpath constraint check fails with OCSP certificate

Reviewed-by: mullan, jnimeh
This commit is contained in:
Anthony Scarpino 2016-10-18 15:13:11 -07:00
parent 32d92f8f0d
commit a96f94cb3e
5 changed files with 71 additions and 45 deletions

View File

@ -185,11 +185,7 @@ public final class AlgorithmChecker extends PKIXCertPathChecker {
AlgorithmConstraints constraints, AlgorithmConstraints constraints,
Date pkixdate) { Date pkixdate) {
if (anchor == null) { if (anchor != null) {
throw new IllegalArgumentException(
"The trust anchor cannot be null");
}
if (anchor.getTrustedCert() != null) { if (anchor.getTrustedCert() != null) {
this.trustedPubKey = anchor.getTrustedCert().getPublicKey(); this.trustedPubKey = anchor.getTrustedCert().getPublicKey();
// Check for anchor certificate restrictions // Check for anchor certificate restrictions
@ -200,6 +196,12 @@ public final class AlgorithmChecker extends PKIXCertPathChecker {
} else { } else {
this.trustedPubKey = anchor.getCAPublicKey(); this.trustedPubKey = anchor.getCAPublicKey();
} }
} else {
this.trustedPubKey = null;
if (debug != null) {
debug.println("TrustAnchor is null, trustedMatch is false.");
}
}
this.prevPubKey = trustedPubKey; this.prevPubKey = trustedPubKey;
this.constraints = constraints; this.constraints = constraints;

View File

@ -35,6 +35,7 @@ import java.security.cert.CertPathValidatorException;
import java.security.cert.CertPathValidatorException.BasicReason; import java.security.cert.CertPathValidatorException.BasicReason;
import java.security.cert.CRLReason; import java.security.cert.CRLReason;
import java.security.cert.Extension; import java.security.cert.Extension;
import java.security.cert.TrustAnchor;
import java.security.cert.X509Certificate; import java.security.cert.X509Certificate;
import java.util.Arrays; import java.util.Arrays;
import java.util.Collections; import java.util.Collections;
@ -163,6 +164,15 @@ public final class OCSP {
X509Certificate responderCert, X509Certificate responderCert,
Date date, List<Extension> extensions) Date date, List<Extension> extensions)
throws IOException, CertPathValidatorException throws IOException, CertPathValidatorException
{
return check(cert, responderURI, null, issuerCert, responderCert, date, extensions);
}
public static RevocationStatus check(X509Certificate cert,
URI responderURI, TrustAnchor anchor, X509Certificate issuerCert,
X509Certificate responderCert, Date date,
List<Extension> extensions)
throws IOException, CertPathValidatorException
{ {
CertId certId = null; CertId certId = null;
try { try {
@ -173,7 +183,7 @@ public final class OCSP {
("Exception while encoding OCSPRequest", e); ("Exception while encoding OCSPRequest", e);
} }
OCSPResponse ocspResponse = check(Collections.singletonList(certId), OCSPResponse ocspResponse = check(Collections.singletonList(certId),
responderURI, new OCSPResponse.IssuerInfo(issuerCert), responderURI, new OCSPResponse.IssuerInfo(anchor, issuerCert),
responderCert, date, extensions); responderCert, date, extensions);
return (RevocationStatus) ocspResponse.getSingleResponse(certId); return (RevocationStatus) ocspResponse.getSingleResponse(certId);
} }

View File

@ -507,9 +507,8 @@ public final class OCSPResponse {
// Check algorithm constraints specified in security property // Check algorithm constraints specified in security property
// "jdk.certpath.disabledAlgorithms". // "jdk.certpath.disabledAlgorithms".
AlgorithmChecker algChecker = new AlgorithmChecker( AlgorithmChecker algChecker =
new TrustAnchor(issuerInfo.getName(), new AlgorithmChecker(issuerInfo.getAnchor(), date);
issuerInfo.getPublicKey(), null));
algChecker.init(false); algChecker.init(false);
algChecker.check(signerCert, Collections.<String>emptySet()); algChecker.check(signerCert, Collections.<String>emptySet());
@ -982,36 +981,38 @@ public final class OCSPResponse {
/** /**
* Helper class that allows consumers to pass in issuer information. This * Helper class that allows consumers to pass in issuer information. This
* will always consist of the issuer's name and public key, but may also * will always consist of the issuer's name and public key, but may also
* contain a certificate if the originating data is in that form. * contain a certificate if the originating data is in that form. The
* trust anchor for the certificate chain will be included for certpath
* disabled algorithm checking.
*/ */
static final class IssuerInfo { static final class IssuerInfo {
private final TrustAnchor anchor;
private final X509Certificate certificate; private final X509Certificate certificate;
private final X500Principal name; private final X500Principal name;
private final PublicKey pubKey; private final PublicKey pubKey;
IssuerInfo(X509Certificate issuerCert) {
certificate = Objects.requireNonNull(issuerCert,
"Constructor requires non-null certificate");
name = certificate.getSubjectX500Principal();
pubKey = certificate.getPublicKey();
}
IssuerInfo(X500Principal subjectName, PublicKey key) {
certificate = null;
name = Objects.requireNonNull(subjectName,
"Constructor requires non-null subject");
pubKey = Objects.requireNonNull(key,
"Constructor requires non-null public key");
}
IssuerInfo(TrustAnchor anchor) { IssuerInfo(TrustAnchor anchor) {
certificate = anchor.getTrustedCert(); this(anchor, (anchor != null) ? anchor.getTrustedCert() : null);
if (certificate != null) { }
name = certificate.getSubjectX500Principal();
pubKey = certificate.getPublicKey(); IssuerInfo(X509Certificate issuerCert) {
this(null, issuerCert);
}
IssuerInfo(TrustAnchor anchor, X509Certificate issuerCert) {
if (anchor == null && issuerCert == null) {
throw new NullPointerException("TrustAnchor and issuerCert " +
"cannot be null");
}
this.anchor = anchor;
if (issuerCert != null) {
name = issuerCert.getSubjectX500Principal();
pubKey = issuerCert.getPublicKey();
certificate = issuerCert;
} else { } else {
name = anchor.getCA(); name = anchor.getCA();
pubKey = anchor.getCAPublicKey(); pubKey = anchor.getCAPublicKey();
certificate = anchor.getTrustedCert();
} }
} }
@ -1046,6 +1047,15 @@ public final class OCSPResponse {
return pubKey; return pubKey;
} }
/**
* Get the TrustAnchor for the certificate chain.
*
* @return a {@code TrustAnchor}.
*/
TrustAnchor getAnchor() {
return anchor;
}
/** /**
* Create a string representation of this IssuerInfo. * Create a string representation of this IssuerInfo.
* *

View File

@ -437,7 +437,7 @@ class RevocationChecker extends PKIXRevocationChecker {
private void updateState(X509Certificate cert) private void updateState(X509Certificate cert)
throws CertPathValidatorException throws CertPathValidatorException
{ {
issuerInfo = new OCSPResponse.IssuerInfo(cert); issuerInfo = new OCSPResponse.IssuerInfo(anchor, cert);
// Make new public key if parameters are missing // Make new public key if parameters are missing
PublicKey pubKey = cert.getPublicKey(); PublicKey pubKey = cert.getPublicKey();
@ -740,8 +740,8 @@ class RevocationChecker extends PKIXRevocationChecker {
} }
response = OCSP.check(Collections.singletonList(certId), response = OCSP.check(Collections.singletonList(certId),
responderURI, issuerInfo, responderURI, issuerInfo, responderCert, params.date(),
responderCert, null, ocspExtensions); ocspExtensions);
} }
} catch (IOException e) { } catch (IOException e) {
throw new CertPathValidatorException( throw new CertPathValidatorException(

View File

@ -530,7 +530,8 @@ public class DisabledAlgorithmConstraints extends AbstractAlgorithmConstraints {
} }
throw new CertPathValidatorException( throw new CertPathValidatorException(
"Algorithm constraints check failed on certificate " + "Algorithm constraints check failed on certificate " +
"anchor limits", "anchor limits. " + algorithm + " used with " +
cp.getCertificate().getSubjectX500Principal(),
null, null, -1, BasicReason.ALGORITHM_CONSTRAINED); null, null, -1, BasicReason.ALGORITHM_CONSTRAINED);
} }
} }
@ -611,8 +612,8 @@ public class DisabledAlgorithmConstraints extends AbstractAlgorithmConstraints {
return; return;
} }
throw new CertPathValidatorException( throw new CertPathValidatorException(
"denyAfter constraint check failed. " + "denyAfter constraint check failed: " + algorithm +
"Constraint date: " + " used with Constraint date: " +
dateFormat.format(denyAfterDate) + "; " dateFormat.format(denyAfterDate) + "; "
+ errmsg + dateFormat.format(currentDate), + errmsg + dateFormat.format(currentDate),
null, null, -1, BasicReason.ALGORITHM_CONSTRAINED); null, null, -1, BasicReason.ALGORITHM_CONSTRAINED);
@ -644,6 +645,7 @@ public class DisabledAlgorithmConstraints extends AbstractAlgorithmConstraints {
private int minSize; // the minimal available key size private int minSize; // the minimal available key size
private int maxSize; // the maximal available key size private int maxSize; // the maximal available key size
private int prohibitedSize = -1; // unavailable key sizes private int prohibitedSize = -1; // unavailable key sizes
private int size;
public KeySizeConstraint(String algo, Operator operator, int length) { public KeySizeConstraint(String algo, Operator operator, int length) {
algorithm = algo; algorithm = algo;
@ -695,7 +697,9 @@ public class DisabledAlgorithmConstraints extends AbstractAlgorithmConstraints {
return; return;
} }
throw new CertPathValidatorException( throw new CertPathValidatorException(
"Algorithm constraints check failed on keysize limits", "Algorithm constraints check failed on keysize limits. "
+ algorithm + " " + size + "bit key used with "
+ cp.getCertificate().getSubjectX500Principal(),
null, null, -1, BasicReason.ALGORITHM_CONSTRAINED); null, null, -1, BasicReason.ALGORITHM_CONSTRAINED);
} }
} }
@ -722,7 +726,7 @@ public class DisabledAlgorithmConstraints extends AbstractAlgorithmConstraints {
return true; return true;
} }
int size = KeyUtil.getKeySize(key); size = KeyUtil.getKeySize(key);
if (size == 0) { if (size == 0) {
return false; // we don't allow any key of size 0. return false; // we don't allow any key of size 0.
} else if (size > 0) { } else if (size > 0) {