提交 3bfa6495 编写于 作者: V vinnie

8015571: OCSP validation fails if ocsp.responderCertSubjectName is set

Reviewed-by: mullan, xuelei
上级 cd0823d7
...@@ -129,7 +129,8 @@ public final class OCSP { ...@@ -129,7 +129,8 @@ 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, issuerCert, null, Collections.<Extension>emptyList()); responderURI, issuerCert, null, null,
Collections.<Extension>emptyList());
return (RevocationStatus)ocspResponse.getSingleResponse(certId); return (RevocationStatus)ocspResponse.getSingleResponse(certId);
} }
...@@ -176,7 +177,7 @@ public final class OCSP { ...@@ -176,7 +177,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, responderCert, date, extensions); responderURI, issuerCert, responderCert, date, extensions);
return (RevocationStatus) ocspResponse.getSingleResponse(certId); return (RevocationStatus) ocspResponse.getSingleResponse(certId);
} }
...@@ -185,6 +186,7 @@ public final class OCSP { ...@@ -185,6 +186,7 @@ public final class OCSP {
* *
* @param certs the CertIds to be checked * @param certs the CertIds to be checked
* @param responderURI the URI of the OCSP responder * @param responderURI the URI of the OCSP responder
* @param issuerCert the issuer's certificate
* @param responderCert the OCSP responder's certificate * @param responderCert the OCSP responder's certificate
* @param date the time the validity of the OCSP responder's certificate * @param date the time the validity of the OCSP responder's certificate
* should be checked against. If null, the current time is used. * should be checked against. If null, the current time is used.
...@@ -195,6 +197,7 @@ public final class OCSP { ...@@ -195,6 +197,7 @@ public final class OCSP {
* encoding the OCSP Request or validating the OCSP Response * encoding the OCSP Request or validating the OCSP Response
*/ */
static OCSPResponse check(List<CertId> certIds, URI responderURI, static OCSPResponse check(List<CertId> certIds, URI responderURI,
X509Certificate issuerCert,
X509Certificate responderCert, Date date, X509Certificate responderCert, Date date,
List<Extension> extensions) List<Extension> extensions)
throws IOException, CertPathValidatorException throws IOException, CertPathValidatorException
...@@ -284,7 +287,8 @@ public final class OCSP { ...@@ -284,7 +287,8 @@ public final class OCSP {
} }
// verify the response // verify the response
ocspResponse.verify(certIds, responderCert, date, request.getNonce()); ocspResponse.verify(certIds, issuerCert, responderCert, date,
request.getNonce());
return ocspResponse; return ocspResponse;
} }
......
/* /*
* Copyright (c) 2003, 2012, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2003, 2013, 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
...@@ -76,7 +76,8 @@ import sun.security.util.*; ...@@ -76,7 +76,8 @@ import sun.security.util.*;
class OCSPRequest { class OCSPRequest {
private static final boolean dump = false; private static final Debug debug = Debug.getInstance("certpath");
private static final boolean dump = debug != null && Debug.isOn("ocsp");
// List of request CertIds // List of request CertIds
private final List<CertId> certIds; private final List<CertId> certIds;
...@@ -138,8 +139,8 @@ class OCSPRequest { ...@@ -138,8 +139,8 @@ class OCSPRequest {
if (dump) { if (dump) {
HexDumpEncoder hexEnc = new HexDumpEncoder(); HexDumpEncoder hexEnc = new HexDumpEncoder();
System.out.println("OCSPRequest bytes are... "); debug.println("OCSPRequest bytes...\n\n" +
System.out.println(hexEnc.encode(bytes)); hexEnc.encode(bytes) + "\n");
} }
return bytes; return bytes;
......
...@@ -132,7 +132,7 @@ public final class OCSPResponse { ...@@ -132,7 +132,7 @@ public final class OCSPResponse {
private static ResponseStatus[] rsvalues = ResponseStatus.values(); private static ResponseStatus[] rsvalues = ResponseStatus.values();
private static final Debug debug = Debug.getInstance("certpath"); private static final Debug debug = Debug.getInstance("certpath");
private static final boolean dump = false; private static final boolean dump = debug != null && Debug.isOn("ocsp");
private static final ObjectIdentifier OCSP_BASIC_RESPONSE_OID = private static final ObjectIdentifier OCSP_BASIC_RESPONSE_OID =
ObjectIdentifier.newInternal(new int[] { 1, 3, 6, 1, 5, 5, 7, 48, 1, 1}); ObjectIdentifier.newInternal(new int[] { 1, 3, 6, 1, 5, 5, 7, 48, 1, 1});
private static final int CERT_STATUS_GOOD = 0; private static final int CERT_STATUS_GOOD = 0;
...@@ -177,11 +177,14 @@ public final class OCSPResponse { ...@@ -177,11 +177,14 @@ public final class OCSPResponse {
private final ResponseStatus responseStatus; private final ResponseStatus responseStatus;
private final Map<CertId, SingleResponse> singleResponseMap; private final Map<CertId, SingleResponse> singleResponseMap;
private final List<X509CertImpl> certs;
private final AlgorithmId sigAlgId; private final AlgorithmId sigAlgId;
private final byte[] signature; private final byte[] signature;
private final byte[] tbsResponseData; private final byte[] tbsResponseData;
private final byte[] responseNonce; private final byte[] responseNonce;
private List<X509CertImpl> certs;
private X509CertImpl signerCert = null;
private X500Principal responderName = null;
private KeyIdentifier responderKeyId = null;
/* /*
* Create an OCSP response from its ASN.1 DER encoding. * Create an OCSP response from its ASN.1 DER encoding.
...@@ -189,8 +192,8 @@ public final class OCSPResponse { ...@@ -189,8 +192,8 @@ public final class OCSPResponse {
OCSPResponse(byte[] bytes) throws IOException { OCSPResponse(byte[] bytes) throws IOException {
if (dump) { if (dump) {
HexDumpEncoder hexEnc = new HexDumpEncoder(); HexDumpEncoder hexEnc = new HexDumpEncoder();
System.out.println("OCSPResponse bytes are..."); debug.println("OCSPResponse bytes...\n\n" +
System.out.println(hexEnc.encode(bytes)); hexEnc.encode(bytes) + "\n");
} }
DerValue der = new DerValue(bytes); DerValue der = new DerValue(bytes);
if (der.tag != DerValue.tag_Sequence) { if (der.tag != DerValue.tag_Sequence) {
...@@ -213,7 +216,7 @@ public final class OCSPResponse { ...@@ -213,7 +216,7 @@ public final class OCSPResponse {
if (responseStatus != ResponseStatus.SUCCESSFUL) { if (responseStatus != ResponseStatus.SUCCESSFUL) {
// no need to continue, responseBytes are not set. // no need to continue, responseBytes are not set.
singleResponseMap = Collections.emptyMap(); singleResponseMap = Collections.emptyMap();
certs = Collections.<X509CertImpl>emptyList(); certs = new ArrayList<X509CertImpl>();
sigAlgId = null; sigAlgId = null;
signature = null; signature = null;
tbsResponseData = null; tbsResponseData = null;
...@@ -288,16 +291,15 @@ public final class OCSPResponse { ...@@ -288,16 +291,15 @@ public final class OCSPResponse {
// responderID // responderID
short tag = (byte)(seq.tag & 0x1f); short tag = (byte)(seq.tag & 0x1f);
if (tag == NAME_TAG) { if (tag == NAME_TAG) {
responderName = new X500Principal(seq.getData().toByteArray());
if (debug != null) { if (debug != null) {
X500Principal responderName = debug.println("Responder's name: " + responderName);
new X500Principal(seq.getData().toByteArray());
debug.println("OCSP Responder name: " + responderName);
} }
} else if (tag == KEY_TAG) { } else if (tag == KEY_TAG) {
responderKeyId = new KeyIdentifier(seq.getData().getOctetString());
if (debug != null) { if (debug != null) {
byte[] responderKey = seq.getData().getOctetString(); debug.println("Responder's key ID: " +
debug.println("OCSP Responder key: " + Debug.toString(responderKeyId.getIdentifier()));
Debug.toString(responderKey));
} }
} else { } else {
throw new IOException("Bad encoding in responderID element of " + throw new IOException("Bad encoding in responderID element of " +
...@@ -368,18 +370,25 @@ public final class OCSPResponse { ...@@ -368,18 +370,25 @@ public final class OCSPResponse {
certs = new ArrayList<X509CertImpl>(derCerts.length); certs = new ArrayList<X509CertImpl>(derCerts.length);
try { try {
for (int i = 0; i < derCerts.length; i++) { for (int i = 0; i < derCerts.length; i++) {
certs.add(new X509CertImpl(derCerts[i].toByteArray())); X509CertImpl cert =
new X509CertImpl(derCerts[i].toByteArray());
certs.add(cert);
if (debug != null) {
debug.println("OCSP response cert #" + (i + 1) + ": " +
cert.getSubjectX500Principal());
}
} }
} catch (CertificateException ce) { } catch (CertificateException ce) {
throw new IOException("Bad encoding in X509 Certificate", ce); throw new IOException("Bad encoding in X509 Certificate", ce);
} }
} else { } else {
certs = Collections.<X509CertImpl>emptyList(); certs = new ArrayList<X509CertImpl>();
} }
} }
void verify(List<CertId> certIds, X509Certificate responderCert, void verify(List<CertId> certIds, X509Certificate issuerCert,
Date date, byte[] nonce) X509Certificate responderCert, Date date, byte[] nonce)
throws CertPathValidatorException throws CertPathValidatorException
{ {
switch (responseStatus) { switch (responseStatus) {
...@@ -414,22 +423,58 @@ public final class OCSPResponse { ...@@ -414,22 +423,58 @@ public final class OCSPResponse {
} }
} }
// Locate the signer cert
if (signerCert == null) {
// Add the Issuing CA cert and/or Trusted Responder cert to the list
// of certs from the OCSP response
certs.add((X509CertImpl) issuerCert);
if (responderCert != null) {
certs.add((X509CertImpl) responderCert);
}
if (responderName != null) {
for (X509CertImpl cert : certs) {
if (cert.getSubjectX500Principal().equals(responderName)) {
signerCert = cert;
break;
}
}
} else if (responderKeyId != null) {
for (X509CertImpl cert : certs) {
KeyIdentifier certKeyId = cert.getSubjectKeyId();
if (certKeyId != null && responderKeyId.equals(certKeyId)) {
signerCert = cert;
break;
}
}
}
}
// Check whether the cert returned by the responder is trusted // Check whether the signer cert returned by the responder is trusted
if (!certs.isEmpty()) { if (signerCert != null) {
X509CertImpl cert = certs.get(0); // Check if the response is signed by the issuing CA
// First check if the cert matches the expected responder cert if (signerCert.equals(issuerCert)) {
if (cert.equals(responderCert)) { if (debug != null) {
debug.println("OCSP response is signed by the target's " +
"Issuing CA");
}
// cert is trusted, now verify the signed response
// Check if the response is signed by a trusted responder
} else if (signerCert.equals(responderCert)) {
if (debug != null) {
debug.println("OCSP response is signed by a Trusted " +
"Responder");
}
// cert is trusted, now verify the signed response // cert is trusted, now verify the signed response
// Next check if the cert was issued by the responder cert // Check if the response is signed by an authorized responder
// which was set locally. } else if (signerCert.getIssuerX500Principal().equals(
} else if (cert.getIssuerX500Principal().equals( issuerCert.getSubjectX500Principal())) {
responderCert.getSubjectX500Principal())) {
// Check for the OCSPSigning key purpose // Check for the OCSPSigning key purpose
try { try {
List<String> keyPurposes = cert.getExtendedKeyUsage(); List<String> keyPurposes = signerCert.getExtendedKeyUsage();
if (keyPurposes == null || if (keyPurposes == null ||
!keyPurposes.contains(KP_OCSP_SIGNING_OID)) { !keyPurposes.contains(KP_OCSP_SIGNING_OID)) {
throw new CertPathValidatorException( throw new CertPathValidatorException(
...@@ -446,16 +491,16 @@ public final class OCSPResponse { ...@@ -446,16 +491,16 @@ 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 AlgorithmChecker(
new TrustAnchor(responderCert, null)); new TrustAnchor(issuerCert, null));
algChecker.init(false); algChecker.init(false);
algChecker.check(cert, Collections.<String>emptySet()); algChecker.check(signerCert, Collections.<String>emptySet());
// check the validity // check the validity
try { try {
if (date == null) { if (date == null) {
cert.checkValidity(); signerCert.checkValidity();
} else { } else {
cert.checkValidity(date); signerCert.checkValidity(date);
} }
} catch (CertificateException e) { } catch (CertificateException e) {
throw new CertPathValidatorException( throw new CertPathValidatorException(
...@@ -471,7 +516,7 @@ public final class OCSPResponse { ...@@ -471,7 +516,7 @@ public final class OCSPResponse {
// extension id-pkix-ocsp-nocheck. // extension id-pkix-ocsp-nocheck.
// //
Extension noCheck = Extension noCheck =
cert.getExtension(PKIXExtensions.OCSPNoCheck_Id); signerCert.getExtension(PKIXExtensions.OCSPNoCheck_Id);
if (noCheck != null) { if (noCheck != null) {
if (debug != null) { if (debug != null) {
debug.println("Responder's certificate includes " + debug.println("Responder's certificate includes " +
...@@ -484,12 +529,15 @@ public final class OCSPResponse { ...@@ -484,12 +529,15 @@ public final class OCSPResponse {
// verify the signature // verify the signature
try { try {
cert.verify(responderCert.getPublicKey()); signerCert.verify(issuerCert.getPublicKey());
responderCert = cert; if (debug != null) {
debug.println("OCSP response is signed by an " +
"Authorized Responder");
}
// cert is trusted, now verify the signed response // cert is trusted, now verify the signed response
} catch (GeneralSecurityException e) { } catch (GeneralSecurityException e) {
responderCert = null; signerCert = null;
} }
} else { } else {
throw new CertPathValidatorException( throw new CertPathValidatorException(
...@@ -500,12 +548,12 @@ public final class OCSPResponse { ...@@ -500,12 +548,12 @@ public final class OCSPResponse {
// Confirm that the signed response was generated using the public // Confirm that the signed response was generated using the public
// key from the trusted responder cert // key from the trusted responder cert
if (responderCert != null) { if (signerCert != null) {
// Check algorithm constraints specified in security property // Check algorithm constraints specified in security property
// "jdk.certpath.disabledAlgorithms". // "jdk.certpath.disabledAlgorithms".
AlgorithmChecker.check(responderCert.getPublicKey(), sigAlgId); AlgorithmChecker.check(signerCert.getPublicKey(), sigAlgId);
if (!verifySignature(responderCert)) { if (!verifySignature(signerCert)) {
throw new CertPathValidatorException( throw new CertPathValidatorException(
"Error verifying OCSP Response's signature"); "Error verifying OCSP Response's signature");
} }
...@@ -555,7 +603,6 @@ public final class OCSPResponse { ...@@ -555,7 +603,6 @@ public final class OCSPResponse {
/* /*
* Verify the signature of the OCSP response. * Verify the signature of the OCSP response.
* The responder's cert is implicitly trusted.
*/ */
private boolean verifySignature(X509Certificate cert) private boolean verifySignature(X509Certificate cert)
throws CertPathValidatorException { throws CertPathValidatorException {
...@@ -593,6 +640,13 @@ public final class OCSPResponse { ...@@ -593,6 +640,13 @@ public final class OCSPResponse {
return singleResponseMap.get(certId); return singleResponseMap.get(certId);
} }
/*
* Returns the certificate for the authority that signed the OCSP response.
*/
X509Certificate getSignerCertificate() {
return signerCert; // set in verify()
}
/* /*
* A class representing a single OCSP response. * A class representing a single OCSP response.
*/ */
......
...@@ -668,9 +668,6 @@ class RevocationChecker extends PKIXRevocationChecker { ...@@ -668,9 +668,6 @@ class RevocationChecker extends PKIXRevocationChecker {
throw new CertPathValidatorException(ce); throw new CertPathValidatorException(ce);
} }
X509Certificate respCert = (responderCert == null) ? issuerCert
: responderCert;
// The algorithm constraints of the OCSP trusted responder certificate // The algorithm constraints of the OCSP trusted responder certificate
// does not need to be checked in this code. The constraints will be // does not need to be checked in this code. The constraints will be
// checked when the responder's certificate is validated. // checked when the responder's certificate is validated.
...@@ -702,8 +699,8 @@ class RevocationChecker extends PKIXRevocationChecker { ...@@ -702,8 +699,8 @@ class RevocationChecker extends PKIXRevocationChecker {
nonce = ext.getValue(); nonce = ext.getValue();
} }
} }
response.verify(Collections.singletonList(certId), respCert, response.verify(Collections.singletonList(certId), issuerCert,
params.date(), nonce); responderCert, params.date(), nonce);
} else { } else {
URI responderURI = (this.responderURI != null) URI responderURI = (this.responderURI != null)
...@@ -716,8 +713,8 @@ class RevocationChecker extends PKIXRevocationChecker { ...@@ -716,8 +713,8 @@ class RevocationChecker extends PKIXRevocationChecker {
} }
response = OCSP.check(Collections.singletonList(certId), response = OCSP.check(Collections.singletonList(certId),
responderURI, respCert, null, responderURI, issuerCert, responderCert,
ocspExtensions); null, ocspExtensions);
} }
} catch (IOException e) { } catch (IOException e) {
throw new CertPathValidatorException( throw new CertPathValidatorException(
...@@ -733,7 +730,7 @@ class RevocationChecker extends PKIXRevocationChecker { ...@@ -733,7 +730,7 @@ class RevocationChecker extends PKIXRevocationChecker {
if (revocationTime.before(params.date())) { if (revocationTime.before(params.date())) {
Throwable t = new CertificateRevokedException( Throwable t = new CertificateRevokedException(
revocationTime, rs.getRevocationReason(), revocationTime, rs.getRevocationReason(),
respCert.getSubjectX500Principal(), response.getSignerCertificate().getSubjectX500Principal(),
rs.getSingleExtensions()); rs.getSingleExtensions());
throw new CertPathValidatorException(t.getMessage(), t, null, throw new CertPathValidatorException(t.getMessage(), t, null,
-1, BasicReason.REVOKED); -1, BasicReason.REVOKED);
......
...@@ -1108,6 +1108,20 @@ public class X509CertImpl extends X509Certificate implements DerEncoder { ...@@ -1108,6 +1108,20 @@ public class X509CertImpl extends X509Certificate implements DerEncoder {
return null; return null;
} }
/**
* Returns the subject's key identifier, or null
*/
public KeyIdentifier getSubjectKeyId() {
SubjectKeyIdentifierExtension ski = getSubjectKeyIdentifierExtension();
if (ski != null) {
try {
return (KeyIdentifier)ski.get(
SubjectKeyIdentifierExtension.KEY_ID);
} catch (IOException ioe) {} // not possible
}
return null;
}
/** /**
* Get AuthorityKeyIdentifier extension * Get AuthorityKeyIdentifier extension
* @return AuthorityKeyIdentifier object or null (if no such object * @return AuthorityKeyIdentifier object or null (if no such object
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册