8010748: Add PKIXRevocationChecker NO_FALLBACK option and improve SOFT_FAIL option
Reviewed-by: vinnie
This commit is contained in:
parent
6788137f6f
commit
74a0cc9f37
@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved.
|
* Copyright (c) 2012, 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
|
||||||
@ -50,21 +50,26 @@ import java.util.Set;
|
|||||||
* status of certificates with OCSP and CRLs. By default, OCSP is the
|
* status of certificates with OCSP and CRLs. By default, OCSP is the
|
||||||
* preferred mechanism for checking revocation status, with CRLs as the
|
* preferred mechanism for checking revocation status, with CRLs as the
|
||||||
* fallback mechanism. However, this preference can be switched to CRLs with
|
* fallback mechanism. However, this preference can be switched to CRLs with
|
||||||
* the {@link Option#PREFER_CRLS PREFER_CRLS} option.
|
* the {@link Option#PREFER_CRLS PREFER_CRLS} option. In addition, the fallback
|
||||||
|
* mechanism can be disabled with the {@link Option#NO_FALLBACK NO_FALLBACK}
|
||||||
|
* option.
|
||||||
*
|
*
|
||||||
* <p>A {@code PKIXRevocationChecker} is obtained by calling the
|
* <p>A {@code PKIXRevocationChecker} is obtained by calling the
|
||||||
* {@link CertPathValidator#getRevocationChecker getRevocationChecker} method
|
* {@link CertPathValidator#getRevocationChecker getRevocationChecker} method
|
||||||
* of a PKIX {@code CertPathValidator}. Additional parameters and options
|
* of a PKIX {@code CertPathValidator}. Additional parameters and options
|
||||||
* specific to revocation can be set (by calling {@link #setOCSPResponder}
|
* specific to revocation can be set (by calling the
|
||||||
* method for instance). The {@code PKIXRevocationChecker} is added to
|
* {@link #setOcspResponder setOcspResponder} method for instance). The
|
||||||
* a {@code PKIXParameters} object using the
|
* {@code PKIXRevocationChecker} is added to a {@code PKIXParameters} object
|
||||||
* {@link PKIXParameters#addCertPathChecker addCertPathChecker}
|
* using the {@link PKIXParameters#addCertPathChecker addCertPathChecker}
|
||||||
* or {@link PKIXParameters#setCertPathCheckers setCertPathCheckers} method,
|
* or {@link PKIXParameters#setCertPathCheckers setCertPathCheckers} method,
|
||||||
* and then the {@code PKIXParameters} is passed along with the {@code CertPath}
|
* and then the {@code PKIXParameters} is passed along with the {@code CertPath}
|
||||||
* to be validated to the {@link CertPathValidator#validate validate} method
|
* to be validated to the {@link CertPathValidator#validate validate} method
|
||||||
* of a PKIX {@code CertPathValidator}. When supplying a revocation checker in
|
* of a PKIX {@code CertPathValidator}. When supplying a revocation checker in
|
||||||
* this manner, it will be used to check revocation irrespective of the setting
|
* this manner, it will be used to check revocation irrespective of the setting
|
||||||
* of the {@link PKIXParameters#isRevocationEnabled RevocationEnabled} flag.
|
* of the {@link PKIXParameters#isRevocationEnabled RevocationEnabled} flag.
|
||||||
|
* Similarly, a {@code PKIXRevocationChecker} may be added to a
|
||||||
|
* {@code PKIXBuilderParameters} object for use with a PKIX
|
||||||
|
* {@code CertPathBuilder}.
|
||||||
*
|
*
|
||||||
* <p>Note that when a {@code PKIXRevocationChecker} is added to
|
* <p>Note that when a {@code PKIXRevocationChecker} is added to
|
||||||
* {@code PKIXParameters}, it clones the {@code PKIXRevocationChecker};
|
* {@code PKIXParameters}, it clones the {@code PKIXRevocationChecker};
|
||||||
@ -83,6 +88,13 @@ import java.util.Set;
|
|||||||
* need not synchronize.
|
* need not synchronize.
|
||||||
*
|
*
|
||||||
* @since 1.8
|
* @since 1.8
|
||||||
|
*
|
||||||
|
* @see <a href="http://www.ietf.org/rfc/rfc2560.txt"><i>RFC 2560: X.509
|
||||||
|
* Internet Public Key Infrastructure Online Certificate Status Protocol -
|
||||||
|
* OCSP</i></a>, <br><a
|
||||||
|
* href="http://www.ietf.org/rfc/rfc5280.txt"><i>RFC 5280: Internet X.509
|
||||||
|
* Public Key Infrastructure Certificate and Certificate Revocation List (CRL)
|
||||||
|
* Profile</i></a>
|
||||||
*/
|
*/
|
||||||
public abstract class PKIXRevocationChecker extends PKIXCertPathChecker {
|
public abstract class PKIXRevocationChecker extends PKIXCertPathChecker {
|
||||||
private URI ocspResponder;
|
private URI ocspResponder;
|
||||||
@ -101,7 +113,7 @@ public abstract class PKIXRevocationChecker extends PKIXCertPathChecker {
|
|||||||
*
|
*
|
||||||
* @param uri the responder URI
|
* @param uri the responder URI
|
||||||
*/
|
*/
|
||||||
public void setOCSPResponder(URI uri) {
|
public void setOcspResponder(URI uri) {
|
||||||
this.ocspResponder = uri;
|
this.ocspResponder = uri;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -114,7 +126,7 @@ public abstract class PKIXRevocationChecker extends PKIXCertPathChecker {
|
|||||||
*
|
*
|
||||||
* @return the responder URI, or {@code null} if not set
|
* @return the responder URI, or {@code null} if not set
|
||||||
*/
|
*/
|
||||||
public URI getOCSPResponder() {
|
public URI getOcspResponder() {
|
||||||
return ocspResponder;
|
return ocspResponder;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -126,7 +138,7 @@ public abstract class PKIXRevocationChecker extends PKIXCertPathChecker {
|
|||||||
*
|
*
|
||||||
* @param cert the responder's certificate
|
* @param cert the responder's certificate
|
||||||
*/
|
*/
|
||||||
public void setOCSPResponderCert(X509Certificate cert) {
|
public void setOcspResponderCert(X509Certificate cert) {
|
||||||
this.ocspResponderCert = cert;
|
this.ocspResponderCert = cert;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -140,7 +152,7 @@ public abstract class PKIXRevocationChecker extends PKIXCertPathChecker {
|
|||||||
*
|
*
|
||||||
* @return the responder's certificate, or {@code null} if not set
|
* @return the responder's certificate, or {@code null} if not set
|
||||||
*/
|
*/
|
||||||
public X509Certificate getOCSPResponderCert() {
|
public X509Certificate getOcspResponderCert() {
|
||||||
return ocspResponderCert;
|
return ocspResponderCert;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -151,7 +163,7 @@ public abstract class PKIXRevocationChecker extends PKIXCertPathChecker {
|
|||||||
* @param extensions a list of extensions. The list is copied to protect
|
* @param extensions a list of extensions. The list is copied to protect
|
||||||
* against subsequent modification.
|
* against subsequent modification.
|
||||||
*/
|
*/
|
||||||
public void setOCSPExtensions(List<Extension> extensions)
|
public void setOcspExtensions(List<Extension> extensions)
|
||||||
{
|
{
|
||||||
this.ocspExtensions = (extensions == null)
|
this.ocspExtensions = (extensions == null)
|
||||||
? Collections.<Extension>emptyList()
|
? Collections.<Extension>emptyList()
|
||||||
@ -161,10 +173,10 @@ public abstract class PKIXRevocationChecker extends PKIXCertPathChecker {
|
|||||||
/**
|
/**
|
||||||
* Gets the optional OCSP request extensions.
|
* Gets the optional OCSP request extensions.
|
||||||
*
|
*
|
||||||
* @return an unmodifiable list of extensions. Returns an empty list if no
|
* @return an unmodifiable list of extensions. The list is empty if no
|
||||||
* extensions have been specified.
|
* extensions have been specified.
|
||||||
*/
|
*/
|
||||||
public List<Extension> getOCSPExtensions() {
|
public List<Extension> getOcspExtensions() {
|
||||||
return Collections.unmodifiableList(ocspExtensions);
|
return Collections.unmodifiableList(ocspExtensions);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -177,7 +189,7 @@ public abstract class PKIXRevocationChecker extends PKIXCertPathChecker {
|
|||||||
* DER-encoded OCSP response for that certificate. A deep copy of
|
* DER-encoded OCSP response for that certificate. A deep copy of
|
||||||
* the map is performed to protect against subsequent modification.
|
* the map is performed to protect against subsequent modification.
|
||||||
*/
|
*/
|
||||||
public void setOCSPResponses(Map<X509Certificate, byte[]> responses)
|
public void setOcspResponses(Map<X509Certificate, byte[]> responses)
|
||||||
{
|
{
|
||||||
if (responses == null) {
|
if (responses == null) {
|
||||||
this.ocspResponses = Collections.<X509Certificate, byte[]>emptyMap();
|
this.ocspResponses = Collections.<X509Certificate, byte[]>emptyMap();
|
||||||
@ -200,7 +212,7 @@ public abstract class PKIXRevocationChecker extends PKIXCertPathChecker {
|
|||||||
* the map is returned to protect against subsequent modification.
|
* the map is returned to protect against subsequent modification.
|
||||||
* Returns an empty map if no responses have been specified.
|
* Returns an empty map if no responses have been specified.
|
||||||
*/
|
*/
|
||||||
public Map<X509Certificate, byte[]> getOCSPResponses() {
|
public Map<X509Certificate, byte[]> getOcspResponses() {
|
||||||
Map<X509Certificate, byte[]> copy = new HashMap<>(ocspResponses.size());
|
Map<X509Certificate, byte[]> copy = new HashMap<>(ocspResponses.size());
|
||||||
for (Map.Entry<X509Certificate, byte[]> e : ocspResponses.entrySet()) {
|
for (Map.Entry<X509Certificate, byte[]> e : ocspResponses.entrySet()) {
|
||||||
copy.put(e.getKey(), e.getValue().clone());
|
copy.put(e.getKey(), e.getValue().clone());
|
||||||
@ -223,15 +235,31 @@ public abstract class PKIXRevocationChecker extends PKIXCertPathChecker {
|
|||||||
/**
|
/**
|
||||||
* Gets the revocation options.
|
* Gets the revocation options.
|
||||||
*
|
*
|
||||||
* @return an unmodifiable set of revocation options, or an empty set if
|
* @return an unmodifiable set of revocation options. The set is empty if
|
||||||
* none are specified
|
* no options have been specified.
|
||||||
*/
|
*/
|
||||||
public Set<Option> getOptions() {
|
public Set<Option> getOptions() {
|
||||||
return Collections.unmodifiableSet(options);
|
return Collections.unmodifiableSet(options);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns a list containing the exceptions that are ignored by the
|
||||||
|
* revocation checker when the {@link Option#SOFT_FAIL SOFT_FAIL} option
|
||||||
|
* is set. The list is cleared each time {@link #init init} is called.
|
||||||
|
* The list is ordered in ascending order according to the certificate
|
||||||
|
* index returned by {@link CertPathValidatorException#getIndex getIndex}
|
||||||
|
* method of each entry.
|
||||||
|
* <p>
|
||||||
|
* An implementation of {@code PKIXRevocationChecker} is responsible for
|
||||||
|
* adding the ignored exceptions to the list.
|
||||||
|
*
|
||||||
|
* @return an unmodifiable list containing the ignored exceptions. The list
|
||||||
|
* is empty if no exceptions have been ignored.
|
||||||
|
*/
|
||||||
|
public abstract List<CertPathValidatorException> getSoftFailExceptions();
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Object clone() {
|
public PKIXRevocationChecker clone() {
|
||||||
PKIXRevocationChecker copy = (PKIXRevocationChecker)super.clone();
|
PKIXRevocationChecker copy = (PKIXRevocationChecker)super.clone();
|
||||||
copy.ocspExtensions = new ArrayList<>(ocspExtensions);
|
copy.ocspExtensions = new ArrayList<>(ocspExtensions);
|
||||||
copy.ocspResponses = new HashMap<>(ocspResponses);
|
copy.ocspResponses = new HashMap<>(ocspResponses);
|
||||||
@ -262,9 +290,26 @@ public abstract class PKIXRevocationChecker extends PKIXCertPathChecker {
|
|||||||
*/
|
*/
|
||||||
PREFER_CRLS,
|
PREFER_CRLS,
|
||||||
/**
|
/**
|
||||||
* Ignore network failures. The default behavior is to consider it a
|
* Disable the fallback mechanism.
|
||||||
* failure if the revocation status of a certificate cannot be obtained
|
*/
|
||||||
* due to a network error. This option applies to both OCSP and CRLs.
|
NO_FALLBACK,
|
||||||
|
/**
|
||||||
|
* Allow revocation check to succeed if the revocation status cannot be
|
||||||
|
* determined for one of the following reasons:
|
||||||
|
* <p><ul>
|
||||||
|
* <li>The CRL or OCSP response cannot be obtained because of a
|
||||||
|
* network error.
|
||||||
|
* <li>The OCSP responder returns one of the following errors
|
||||||
|
* specified in section 2.3 of RFC 2560: internalError, tryLater,
|
||||||
|
* or unauthorized.
|
||||||
|
* </ul><br>
|
||||||
|
* Note that these conditions apply to both OCSP and CRLs, and unless
|
||||||
|
* the {@code NO_FALLBACK} option is set, the revocation check is
|
||||||
|
* allowed to succeed only if both mechanisms fail under one of the
|
||||||
|
* conditions as stated above.
|
||||||
|
* Exceptions that cause the network errors are ignored but can be
|
||||||
|
* later retrieved by calling the
|
||||||
|
* {@link #getSoftFailExceptions getSoftFailExceptions} method.
|
||||||
*/
|
*/
|
||||||
SOFT_FAIL
|
SOFT_FAIL
|
||||||
}
|
}
|
||||||
|
@ -255,7 +255,9 @@ public final class OCSP {
|
|||||||
}
|
}
|
||||||
response = Arrays.copyOf(response, total);
|
response = Arrays.copyOf(response, total);
|
||||||
} catch (IOException ioe) {
|
} catch (IOException ioe) {
|
||||||
throw new NetworkFailureException(ioe);
|
throw new CertPathValidatorException(
|
||||||
|
"Unable to determine revocation status due to network error",
|
||||||
|
ioe, null, -1, BasicReason.UNDETERMINED_REVOCATION_STATUS);
|
||||||
} finally {
|
} finally {
|
||||||
if (in != null) {
|
if (in != null) {
|
||||||
try {
|
try {
|
||||||
@ -355,17 +357,4 @@ public final class OCSP {
|
|||||||
*/
|
*/
|
||||||
Map<String, Extension> getSingleExtensions();
|
Map<String, Extension> getSingleExtensions();
|
||||||
}
|
}
|
||||||
|
|
||||||
static class NetworkFailureException extends CertPathValidatorException {
|
|
||||||
private static final long serialVersionUID = 0l;
|
|
||||||
|
|
||||||
NetworkFailureException(Throwable t) {
|
|
||||||
super(t);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public CertPathValidatorException.Reason getReason() {
|
|
||||||
return BasicReason.UNDETERMINED_REVOCATION_STATUS;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -30,6 +30,7 @@ import java.security.*;
|
|||||||
import java.security.cert.CertificateException;
|
import java.security.cert.CertificateException;
|
||||||
import java.security.cert.CertificateParsingException;
|
import java.security.cert.CertificateParsingException;
|
||||||
import java.security.cert.CertPathValidatorException;
|
import java.security.cert.CertPathValidatorException;
|
||||||
|
import java.security.cert.CertPathValidatorException.BasicReason;
|
||||||
import java.security.cert.CRLReason;
|
import java.security.cert.CRLReason;
|
||||||
import java.security.cert.TrustAnchor;
|
import java.security.cert.TrustAnchor;
|
||||||
import java.security.cert.X509Certificate;
|
import java.security.cert.X509Certificate;
|
||||||
@ -121,8 +122,8 @@ public final class OCSPResponse {
|
|||||||
|
|
||||||
public enum ResponseStatus {
|
public enum ResponseStatus {
|
||||||
SUCCESSFUL, // Response has valid confirmations
|
SUCCESSFUL, // Response has valid confirmations
|
||||||
MALFORMED_REQUEST, // Illegal confirmation request
|
MALFORMED_REQUEST, // Illegal request
|
||||||
INTERNAL_ERROR, // Internal error in issuer
|
INTERNAL_ERROR, // Internal error in responder
|
||||||
TRY_LATER, // Try again later
|
TRY_LATER, // Try again later
|
||||||
UNUSED, // is not used
|
UNUSED, // is not used
|
||||||
SIG_REQUIRED, // Must sign the request
|
SIG_REQUIRED, // Must sign the request
|
||||||
@ -381,9 +382,18 @@ public final class OCSPResponse {
|
|||||||
Date date, byte[] nonce)
|
Date date, byte[] nonce)
|
||||||
throws CertPathValidatorException
|
throws CertPathValidatorException
|
||||||
{
|
{
|
||||||
if (responseStatus != ResponseStatus.SUCCESSFUL) {
|
switch (responseStatus) {
|
||||||
throw new CertPathValidatorException
|
case SUCCESSFUL:
|
||||||
("OCSP response error: " + responseStatus);
|
break;
|
||||||
|
case UNAUTHORIZED:
|
||||||
|
case TRY_LATER:
|
||||||
|
case INTERNAL_ERROR:
|
||||||
|
throw new CertPathValidatorException(
|
||||||
|
"OCSP response error: " + responseStatus, null, null, -1,
|
||||||
|
BasicReason.UNDETERMINED_REVOCATION_STATUS);
|
||||||
|
default:
|
||||||
|
throw new CertPathValidatorException("OCSP response error: " +
|
||||||
|
responseStatus);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check that the response includes a response for all of the
|
// Check that the response includes a response for all of the
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright (c) 2000, 2012, Oracle and/or its affiliates. All rights reserved.
|
* Copyright (c) 2000, 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
|
||||||
@ -193,12 +193,17 @@ public final class PKIXCertPathValidator extends CertPathValidatorSpi {
|
|||||||
List<PKIXCertPathChecker> checkers = params.certPathCheckers();
|
List<PKIXCertPathChecker> checkers = params.certPathCheckers();
|
||||||
for (PKIXCertPathChecker checker : checkers) {
|
for (PKIXCertPathChecker checker : checkers) {
|
||||||
if (checker instanceof PKIXRevocationChecker) {
|
if (checker instanceof PKIXRevocationChecker) {
|
||||||
|
if (revCheckerAdded) {
|
||||||
|
throw new CertPathValidatorException(
|
||||||
|
"Only one PKIXRevocationChecker can be specified");
|
||||||
|
}
|
||||||
revCheckerAdded = true;
|
revCheckerAdded = true;
|
||||||
// if it's our own, initialize it
|
// if it's our own, initialize it
|
||||||
if (checker instanceof RevocationChecker)
|
if (checker instanceof RevocationChecker) {
|
||||||
((RevocationChecker)checker).init(anchor, params);
|
((RevocationChecker)checker).init(anchor, params);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
// only add a RevocationChecker if revocation is enabled and
|
// only add a RevocationChecker if revocation is enabled and
|
||||||
// a PKIXRevocationChecker has not already been added
|
// a PKIXRevocationChecker has not already been added
|
||||||
if (params.revocationEnabled() && !revCheckerAdded) {
|
if (params.revocationEnabled() && !revCheckerAdded) {
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright (c) 2000, 2012, Oracle and/or its affiliates. All rights reserved.
|
* Copyright (c) 2000, 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
|
||||||
@ -30,6 +30,7 @@ import java.security.PublicKey;
|
|||||||
import java.security.cert.CertificateException;
|
import java.security.cert.CertificateException;
|
||||||
import java.security.cert.CertPathValidatorException;
|
import java.security.cert.CertPathValidatorException;
|
||||||
import java.security.cert.PKIXCertPathChecker;
|
import java.security.cert.PKIXCertPathChecker;
|
||||||
|
import java.security.cert.PKIXRevocationChecker;
|
||||||
import java.security.cert.TrustAnchor;
|
import java.security.cert.TrustAnchor;
|
||||||
import java.security.cert.X509Certificate;
|
import java.security.cert.X509Certificate;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
@ -235,9 +236,16 @@ class ReverseState implements State {
|
|||||||
for (PKIXCertPathChecker checker : userCheckers) {
|
for (PKIXCertPathChecker checker : userCheckers) {
|
||||||
if (checker instanceof AlgorithmChecker) {
|
if (checker instanceof AlgorithmChecker) {
|
||||||
((AlgorithmChecker)checker).trySetTrustAnchor(anchor);
|
((AlgorithmChecker)checker).trySetTrustAnchor(anchor);
|
||||||
} else if (checker instanceof RevocationChecker) {
|
} else if (checker instanceof PKIXRevocationChecker) {
|
||||||
|
if (revCheckerAdded) {
|
||||||
|
throw new CertPathValidatorException(
|
||||||
|
"Only one PKIXRevocationChecker can be specified");
|
||||||
|
}
|
||||||
|
// if it's our own, initialize it
|
||||||
|
if (checker instanceof RevocationChecker) {
|
||||||
((RevocationChecker)checker).init(anchor, buildParams);
|
((RevocationChecker)checker).init(anchor, buildParams);
|
||||||
((RevocationChecker)checker).init(false);
|
}
|
||||||
|
((PKIXRevocationChecker)checker).init(false);
|
||||||
revCheckerAdded = true;
|
revCheckerAdded = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -38,14 +38,7 @@ import java.security.Security;
|
|||||||
import java.security.cert.CertPathValidatorException.BasicReason;
|
import java.security.cert.CertPathValidatorException.BasicReason;
|
||||||
import java.security.cert.Extension;
|
import java.security.cert.Extension;
|
||||||
import java.security.cert.*;
|
import java.security.cert.*;
|
||||||
import java.util.Arrays;
|
import java.util.*;
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.Collection;
|
|
||||||
import java.util.Collections;
|
|
||||||
import java.util.HashSet;
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.Map;
|
|
||||||
import java.util.Set;
|
|
||||||
import javax.security.auth.x500.X500Principal;
|
import javax.security.auth.x500.X500Principal;
|
||||||
|
|
||||||
import static sun.security.provider.certpath.OCSP.*;
|
import static sun.security.provider.certpath.OCSP.*;
|
||||||
@ -70,13 +63,16 @@ class RevocationChecker extends PKIXRevocationChecker {
|
|||||||
private Map<X509Certificate, byte[]> ocspResponses;
|
private Map<X509Certificate, byte[]> ocspResponses;
|
||||||
private List<Extension> ocspExtensions;
|
private List<Extension> ocspExtensions;
|
||||||
private boolean legacy;
|
private boolean legacy;
|
||||||
|
private LinkedList<CertPathValidatorException> softFailExceptions =
|
||||||
|
new LinkedList<>();
|
||||||
|
|
||||||
// state variables
|
// state variables
|
||||||
private X509Certificate issuerCert;
|
private X509Certificate issuerCert;
|
||||||
private PublicKey prevPubKey;
|
private PublicKey prevPubKey;
|
||||||
private boolean crlSignFlag;
|
private boolean crlSignFlag;
|
||||||
|
private int certIndex;
|
||||||
|
|
||||||
private enum Mode { PREFER_OCSP, PREFER_CRLS, ONLY_CRLS };
|
private enum Mode { PREFER_OCSP, PREFER_CRLS, ONLY_CRLS, ONLY_OCSP };
|
||||||
private Mode mode = Mode.PREFER_OCSP;
|
private Mode mode = Mode.PREFER_OCSP;
|
||||||
|
|
||||||
private static class RevocationProperties {
|
private static class RevocationProperties {
|
||||||
@ -104,9 +100,9 @@ class RevocationChecker extends PKIXRevocationChecker {
|
|||||||
throws CertPathValidatorException
|
throws CertPathValidatorException
|
||||||
{
|
{
|
||||||
RevocationProperties rp = getRevocationProperties();
|
RevocationProperties rp = getRevocationProperties();
|
||||||
URI uri = getOCSPResponder();
|
URI uri = getOcspResponder();
|
||||||
responderURI = (uri == null) ? toURI(rp.ocspUrl) : uri;
|
responderURI = (uri == null) ? toURI(rp.ocspUrl) : uri;
|
||||||
X509Certificate cert = getOCSPResponderCert();
|
X509Certificate cert = getOcspResponderCert();
|
||||||
responderCert = (cert == null)
|
responderCert = (cert == null)
|
||||||
? getResponderCert(rp, params.trustAnchors(),
|
? getResponderCert(rp, params.trustAnchors(),
|
||||||
params.certStores())
|
params.certStores())
|
||||||
@ -117,31 +113,38 @@ class RevocationChecker extends PKIXRevocationChecker {
|
|||||||
case ONLY_END_ENTITY:
|
case ONLY_END_ENTITY:
|
||||||
case PREFER_CRLS:
|
case PREFER_CRLS:
|
||||||
case SOFT_FAIL:
|
case SOFT_FAIL:
|
||||||
|
case NO_FALLBACK:
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
throw new CertPathValidatorException(
|
throw new CertPathValidatorException(
|
||||||
"Unrecognized revocation parameter option: " + option);
|
"Unrecognized revocation parameter option: " + option);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
softFail = options.contains(Option.SOFT_FAIL);
|
||||||
|
|
||||||
// set mode, only end entity flag
|
// set mode, only end entity flag
|
||||||
if (legacy) {
|
if (legacy) {
|
||||||
mode = (rp.ocspEnabled) ? Mode.PREFER_OCSP : Mode.ONLY_CRLS;
|
mode = (rp.ocspEnabled) ? Mode.PREFER_OCSP : Mode.ONLY_CRLS;
|
||||||
onlyEE = rp.onlyEE;
|
onlyEE = rp.onlyEE;
|
||||||
} else {
|
} else {
|
||||||
|
if (options.contains(Option.NO_FALLBACK)) {
|
||||||
if (options.contains(Option.PREFER_CRLS)) {
|
if (options.contains(Option.PREFER_CRLS)) {
|
||||||
|
mode = Mode.ONLY_CRLS;
|
||||||
|
} else {
|
||||||
|
mode = Mode.ONLY_OCSP;
|
||||||
|
}
|
||||||
|
} else if (options.contains(Option.PREFER_CRLS)) {
|
||||||
mode = Mode.PREFER_CRLS;
|
mode = Mode.PREFER_CRLS;
|
||||||
}
|
}
|
||||||
onlyEE = options.contains(Option.ONLY_END_ENTITY);
|
onlyEE = options.contains(Option.ONLY_END_ENTITY);
|
||||||
}
|
}
|
||||||
softFail = options.contains(Option.SOFT_FAIL);
|
|
||||||
if (legacy) {
|
if (legacy) {
|
||||||
crlDP = rp.crlDPEnabled;
|
crlDP = rp.crlDPEnabled;
|
||||||
} else {
|
} else {
|
||||||
crlDP = true;
|
crlDP = true;
|
||||||
}
|
}
|
||||||
ocspResponses = getOCSPResponses();
|
ocspResponses = getOcspResponses();
|
||||||
ocspExtensions = getOCSPExtensions();
|
ocspExtensions = getOcspExtensions();
|
||||||
|
|
||||||
this.anchor = anchor;
|
this.anchor = anchor;
|
||||||
this.params = params;
|
this.params = params;
|
||||||
@ -297,14 +300,19 @@ class RevocationChecker extends PKIXRevocationChecker {
|
|||||||
if (forward) {
|
if (forward) {
|
||||||
throw new
|
throw new
|
||||||
CertPathValidatorException("forward checking not supported");
|
CertPathValidatorException("forward checking not supported");
|
||||||
} else {
|
}
|
||||||
if (anchor != null) {
|
if (anchor != null) {
|
||||||
issuerCert = anchor.getTrustedCert();
|
issuerCert = anchor.getTrustedCert();
|
||||||
prevPubKey = (issuerCert != null) ? issuerCert.getPublicKey()
|
prevPubKey = (issuerCert != null) ? issuerCert.getPublicKey()
|
||||||
: anchor.getCAPublicKey();
|
: anchor.getCAPublicKey();
|
||||||
}
|
}
|
||||||
crlSignFlag = true;
|
crlSignFlag = true;
|
||||||
|
if (params.certPath() != null) {
|
||||||
|
certIndex = params.certPath().getCertificates().size() - 1;
|
||||||
|
} else {
|
||||||
|
certIndex = -1;
|
||||||
}
|
}
|
||||||
|
softFailExceptions.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -317,28 +325,35 @@ class RevocationChecker extends PKIXRevocationChecker {
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<CertPathValidatorException> getSoftFailExceptions() {
|
||||||
|
return Collections.unmodifiableList(softFailExceptions);
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void check(Certificate cert, Collection<String> unresolvedCritExts)
|
public void check(Certificate cert, Collection<String> unresolvedCritExts)
|
||||||
throws CertPathValidatorException
|
throws CertPathValidatorException
|
||||||
{
|
{
|
||||||
X509Certificate xcert = (X509Certificate)cert;
|
check((X509Certificate)cert, unresolvedCritExts,
|
||||||
if (onlyEE && xcert.getBasicConstraints() != -1) {
|
prevPubKey, crlSignFlag);
|
||||||
if (debug != null) {
|
|
||||||
debug.println("Skipping revocation check, not end entity cert");
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
check(xcert, unresolvedCritExts, prevPubKey, crlSignFlag);
|
|
||||||
}
|
|
||||||
updateState(xcert);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void check(X509Certificate xcert, Collection<String> unresolvedCritExts,
|
private void check(X509Certificate xcert,
|
||||||
|
Collection<String> unresolvedCritExts,
|
||||||
PublicKey pubKey, boolean crlSignFlag)
|
PublicKey pubKey, boolean crlSignFlag)
|
||||||
throws CertPathValidatorException
|
throws CertPathValidatorException
|
||||||
{
|
{
|
||||||
try {
|
try {
|
||||||
|
if (onlyEE && xcert.getBasicConstraints() != -1) {
|
||||||
|
if (debug != null) {
|
||||||
|
debug.println("Skipping revocation check, not end " +
|
||||||
|
"entity cert");
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
switch (mode) {
|
switch (mode) {
|
||||||
case PREFER_OCSP:
|
case PREFER_OCSP:
|
||||||
|
case ONLY_OCSP:
|
||||||
checkOCSP(xcert, unresolvedCritExts);
|
checkOCSP(xcert, unresolvedCritExts);
|
||||||
break;
|
break;
|
||||||
case PREFER_CRLS:
|
case PREFER_CRLS:
|
||||||
@ -351,14 +366,17 @@ class RevocationChecker extends PKIXRevocationChecker {
|
|||||||
if (e.getReason() == BasicReason.REVOKED) {
|
if (e.getReason() == BasicReason.REVOKED) {
|
||||||
throw e;
|
throw e;
|
||||||
}
|
}
|
||||||
CertPathValidatorException cause = e;
|
boolean eSoftFail = isSoftFailException(e);
|
||||||
if (softFail && e instanceof NetworkFailureException) {
|
if (eSoftFail) {
|
||||||
if (mode == Mode.ONLY_CRLS) return;
|
if (mode == Mode.ONLY_OCSP || mode == Mode.ONLY_CRLS) {
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
// Rethrow the exception if ONLY_CRLS
|
} else {
|
||||||
if (mode == Mode.ONLY_CRLS) {
|
if (mode == Mode.ONLY_OCSP || mode == Mode.ONLY_CRLS) {
|
||||||
throw e;
|
throw e;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
CertPathValidatorException cause = e;
|
||||||
// Otherwise, failover
|
// Otherwise, failover
|
||||||
if (debug != null) {
|
if (debug != null) {
|
||||||
debug.println("RevocationChecker.check() " + e.getMessage());
|
debug.println("RevocationChecker.check() " + e.getMessage());
|
||||||
@ -382,20 +400,33 @@ class RevocationChecker extends PKIXRevocationChecker {
|
|||||||
if (x.getReason() == BasicReason.REVOKED) {
|
if (x.getReason() == BasicReason.REVOKED) {
|
||||||
throw x;
|
throw x;
|
||||||
}
|
}
|
||||||
if (cause != null) {
|
if (!isSoftFailException(x)) {
|
||||||
if (softFail && cause instanceof NetworkFailureException) {
|
|
||||||
return;
|
|
||||||
} else {
|
|
||||||
cause.addSuppressed(x);
|
cause.addSuppressed(x);
|
||||||
throw cause;
|
throw cause;
|
||||||
|
} else {
|
||||||
|
// only pass if both exceptions were soft failures
|
||||||
|
if (!eSoftFail) {
|
||||||
|
throw cause;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (softFail && x instanceof NetworkFailureException) {
|
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
throw x;
|
} finally {
|
||||||
|
updateState(xcert);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private boolean isSoftFailException(CertPathValidatorException e) {
|
||||||
|
if (softFail &&
|
||||||
|
e.getReason() == BasicReason.UNDETERMINED_REVOCATION_STATUS)
|
||||||
|
{
|
||||||
|
// recreate exception with correct index
|
||||||
|
CertPathValidatorException e2 = new CertPathValidatorException(
|
||||||
|
e.getMessage(), e.getCause(), params.certPath(), certIndex,
|
||||||
|
e.getReason());
|
||||||
|
softFailExceptions.addFirst(e2);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void updateState(X509Certificate cert)
|
private void updateState(X509Certificate cert)
|
||||||
@ -411,6 +442,9 @@ class RevocationChecker extends PKIXRevocationChecker {
|
|||||||
}
|
}
|
||||||
prevPubKey = pubKey;
|
prevPubKey = pubKey;
|
||||||
crlSignFlag = certCanSignCrl(cert);
|
crlSignFlag = certCanSignCrl(cert);
|
||||||
|
if (certIndex > 0) {
|
||||||
|
certIndex--;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Maximum clock skew in milliseconds (15 minutes) allowed when checking
|
// Maximum clock skew in milliseconds (15 minutes) allowed when checking
|
||||||
@ -457,7 +491,7 @@ class RevocationChecker extends PKIXRevocationChecker {
|
|||||||
CertPathHelper.setDateAndTime(sel, params.date(), MAX_CLOCK_SKEW);
|
CertPathHelper.setDateAndTime(sel, params.date(), MAX_CLOCK_SKEW);
|
||||||
|
|
||||||
// First, check user-specified CertStores
|
// First, check user-specified CertStores
|
||||||
NetworkFailureException nfe = null;
|
CertPathValidatorException networkFailureException = null;
|
||||||
for (CertStore store : certStores) {
|
for (CertStore store : certStores) {
|
||||||
try {
|
try {
|
||||||
for (CRL crl : store.getCRLs(sel)) {
|
for (CRL crl : store.getCRLs(sel)) {
|
||||||
@ -468,10 +502,13 @@ class RevocationChecker extends PKIXRevocationChecker {
|
|||||||
debug.println("RevocationChecker.checkCRLs() " +
|
debug.println("RevocationChecker.checkCRLs() " +
|
||||||
"CertStoreException: " + e.getMessage());
|
"CertStoreException: " + e.getMessage());
|
||||||
}
|
}
|
||||||
if (softFail && nfe == null &&
|
if (networkFailureException == null &&
|
||||||
CertStoreHelper.isCausedByNetworkIssue(store.getType(),e)) {
|
CertStoreHelper.isCausedByNetworkIssue(store.getType(),e)) {
|
||||||
// save this exception, we may need to throw it later
|
// save this exception, we may need to throw it later
|
||||||
nfe = new NetworkFailureException(e);
|
networkFailureException = new CertPathValidatorException(
|
||||||
|
"Unable to determine revocation status due to " +
|
||||||
|
"network error", e, null, -1,
|
||||||
|
BasicReason.UNDETERMINED_REVOCATION_STATUS);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -508,14 +545,17 @@ class RevocationChecker extends PKIXRevocationChecker {
|
|||||||
approvedCRLs.addAll(DistributionPointFetcher.getCRLs(
|
approvedCRLs.addAll(DistributionPointFetcher.getCRLs(
|
||||||
sel, signFlag, prevKey,
|
sel, signFlag, prevKey,
|
||||||
params.sigProvider(), certStores,
|
params.sigProvider(), certStores,
|
||||||
reasonsMask, anchors, params.date()));
|
reasonsMask, anchors, null));
|
||||||
}
|
}
|
||||||
} catch (CertStoreException e) {
|
} catch (CertStoreException e) {
|
||||||
if (softFail && e instanceof CertStoreTypeException) {
|
if (e instanceof CertStoreTypeException) {
|
||||||
CertStoreTypeException cste = (CertStoreTypeException)e;
|
CertStoreTypeException cste = (CertStoreTypeException)e;
|
||||||
if (CertStoreHelper.isCausedByNetworkIssue(cste.getType(),
|
if (CertStoreHelper.isCausedByNetworkIssue(cste.getType(),
|
||||||
e)) {
|
e)) {
|
||||||
throw new NetworkFailureException(e);
|
throw new CertPathValidatorException(
|
||||||
|
"Unable to determine revocation status due to " +
|
||||||
|
"network error", e, null, -1,
|
||||||
|
BasicReason.UNDETERMINED_REVOCATION_STATUS);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
throw new CertPathValidatorException(e);
|
throw new CertPathValidatorException(e);
|
||||||
@ -531,25 +571,25 @@ class RevocationChecker extends PKIXRevocationChecker {
|
|||||||
stackedCerts);
|
stackedCerts);
|
||||||
return;
|
return;
|
||||||
} catch (CertPathValidatorException cpve) {
|
} catch (CertPathValidatorException cpve) {
|
||||||
if (nfe != null) {
|
if (networkFailureException != null) {
|
||||||
// if a network issue previously prevented us from
|
// if a network issue previously prevented us from
|
||||||
// retrieving a CRL from one of the user-specified
|
// retrieving a CRL from one of the user-specified
|
||||||
// CertStores and SOFT_FAIL is enabled, throw it now
|
// CertStores, throw it now so it can be handled
|
||||||
// so it can be handled appropriately
|
// appropriately
|
||||||
throw nfe;
|
throw networkFailureException;
|
||||||
}
|
}
|
||||||
throw cpve;
|
throw cpve;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if (nfe != null) {
|
if (networkFailureException != null) {
|
||||||
// if a network issue previously prevented us from
|
// if a network issue previously prevented us from
|
||||||
// retrieving a CRL from one of the user-specified
|
// retrieving a CRL from one of the user-specified
|
||||||
// CertStores and SOFT_FAIL is enabled, throw it now
|
// CertStores, throw it now so it can be handled
|
||||||
// so it can be handled appropriately
|
// appropriately
|
||||||
throw nfe;
|
throw networkFailureException;
|
||||||
}
|
}
|
||||||
throw new CertPathValidatorException
|
throw new CertPathValidatorException(
|
||||||
("Could not determine revocation status", null, null, -1,
|
"Could not determine revocation status", null, null, -1,
|
||||||
BasicReason.UNDETERMINED_REVOCATION_STATUS);
|
BasicReason.UNDETERMINED_REVOCATION_STATUS);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -595,14 +635,9 @@ class RevocationChecker extends PKIXRevocationChecker {
|
|||||||
unresCritExts.remove(ReasonCode_Id.toString());
|
unresCritExts.remove(ReasonCode_Id.toString());
|
||||||
unresCritExts.remove(CertificateIssuer_Id.toString());
|
unresCritExts.remove(CertificateIssuer_Id.toString());
|
||||||
if (!unresCritExts.isEmpty()) {
|
if (!unresCritExts.isEmpty()) {
|
||||||
if (debug != null) {
|
throw new CertPathValidatorException(
|
||||||
debug.println("Unrecognized "
|
"Unrecognized critical extension(s) in revoked " +
|
||||||
+ "critical extension(s) in revoked CRL entry: "
|
"CRL entry");
|
||||||
+ unresCritExts);
|
|
||||||
}
|
|
||||||
throw new CertPathValidatorException
|
|
||||||
("Could not determine revocation status", null, null,
|
|
||||||
-1, BasicReason.UNDETERMINED_REVOCATION_STATUS);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -610,11 +645,14 @@ class RevocationChecker extends PKIXRevocationChecker {
|
|||||||
if (reasonCode == null) {
|
if (reasonCode == null) {
|
||||||
reasonCode = CRLReason.UNSPECIFIED;
|
reasonCode = CRLReason.UNSPECIFIED;
|
||||||
}
|
}
|
||||||
Throwable t = new CertificateRevokedException
|
Date revocationDate = entry.getRevocationDate();
|
||||||
(entry.getRevocationDate(), reasonCode,
|
if (revocationDate.before(params.date())) {
|
||||||
|
Throwable t = new CertificateRevokedException(
|
||||||
|
revocationDate, reasonCode,
|
||||||
crl.getIssuerX500Principal(), entry.getExtensions());
|
crl.getIssuerX500Principal(), entry.getExtensions());
|
||||||
throw new CertPathValidatorException(t.getMessage(), t,
|
throw new CertPathValidatorException(
|
||||||
null, -1, BasicReason.REVOKED);
|
t.getMessage(), t, null, -1, BasicReason.REVOKED);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -630,9 +668,6 @@ class RevocationChecker extends PKIXRevocationChecker {
|
|||||||
throw new CertPathValidatorException(ce);
|
throw new CertPathValidatorException(ce);
|
||||||
}
|
}
|
||||||
|
|
||||||
URI responderURI = (this.responderURI != null)
|
|
||||||
? this.responderURI : getOCSPServerURI(currCert);
|
|
||||||
|
|
||||||
X509Certificate respCert = (responderCert == null) ? issuerCert
|
X509Certificate respCert = (responderCert == null) ? issuerCert
|
||||||
: responderCert;
|
: responderCert;
|
||||||
|
|
||||||
@ -671,23 +706,38 @@ class RevocationChecker extends PKIXRevocationChecker {
|
|||||||
params.date(), nonce);
|
params.date(), nonce);
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
|
URI responderURI = (this.responderURI != null)
|
||||||
|
? this.responderURI
|
||||||
|
: OCSP.getResponderURI(currCert);
|
||||||
|
if (responderURI == null) {
|
||||||
|
throw new CertPathValidatorException(
|
||||||
|
"Certificate does not specify OCSP responder", null,
|
||||||
|
null, -1);
|
||||||
|
}
|
||||||
|
|
||||||
response = OCSP.check(Collections.singletonList(certId),
|
response = OCSP.check(Collections.singletonList(certId),
|
||||||
responderURI, respCert, params.date(),
|
responderURI, respCert, null,
|
||||||
ocspExtensions);
|
ocspExtensions);
|
||||||
}
|
}
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
throw new CertPathValidatorException(e);
|
throw new CertPathValidatorException(
|
||||||
|
"Unable to determine revocation status due to network error",
|
||||||
|
e, null, -1, BasicReason.UNDETERMINED_REVOCATION_STATUS);
|
||||||
}
|
}
|
||||||
|
|
||||||
RevocationStatus rs =
|
RevocationStatus rs =
|
||||||
(RevocationStatus)response.getSingleResponse(certId);
|
(RevocationStatus)response.getSingleResponse(certId);
|
||||||
RevocationStatus.CertStatus certStatus = rs.getCertStatus();
|
RevocationStatus.CertStatus certStatus = rs.getCertStatus();
|
||||||
if (certStatus == RevocationStatus.CertStatus.REVOKED) {
|
if (certStatus == RevocationStatus.CertStatus.REVOKED) {
|
||||||
|
Date revocationTime = rs.getRevocationTime();
|
||||||
|
if (revocationTime.before(params.date())) {
|
||||||
Throwable t = new CertificateRevokedException(
|
Throwable t = new CertificateRevokedException(
|
||||||
rs.getRevocationTime(), rs.getRevocationReason(),
|
revocationTime, rs.getRevocationReason(),
|
||||||
respCert.getSubjectX500Principal(), rs.getSingleExtensions());
|
respCert.getSubjectX500Principal(),
|
||||||
|
rs.getSingleExtensions());
|
||||||
throw new CertPathValidatorException(t.getMessage(), t, null,
|
throw new CertPathValidatorException(t.getMessage(), t, null,
|
||||||
-1, BasicReason.REVOKED);
|
-1, BasicReason.REVOKED);
|
||||||
|
}
|
||||||
} else if (certStatus == RevocationStatus.CertStatus.UNKNOWN) {
|
} else if (certStatus == RevocationStatus.CertStatus.UNKNOWN) {
|
||||||
throw new CertPathValidatorException(
|
throw new CertPathValidatorException(
|
||||||
"Certificate's revocation status is unknown", null,
|
"Certificate's revocation status is unknown", null,
|
||||||
@ -711,34 +761,6 @@ class RevocationChecker extends PKIXRevocationChecker {
|
|||||||
return hexNumber.toString();
|
return hexNumber.toString();
|
||||||
}
|
}
|
||||||
|
|
||||||
private static URI getOCSPServerURI(X509CertImpl cert)
|
|
||||||
throws CertPathValidatorException
|
|
||||||
{
|
|
||||||
// Examine the certificate's AuthorityInfoAccess extension
|
|
||||||
AuthorityInfoAccessExtension aia =
|
|
||||||
cert.getAuthorityInfoAccessExtension();
|
|
||||||
if (aia == null) {
|
|
||||||
throw new CertPathValidatorException(
|
|
||||||
"Must specify the location of an OCSP Responder");
|
|
||||||
}
|
|
||||||
|
|
||||||
List<AccessDescription> descriptions = aia.getAccessDescriptions();
|
|
||||||
for (AccessDescription description : descriptions) {
|
|
||||||
if (description.getAccessMethod().equals((Object)
|
|
||||||
AccessDescription.Ad_OCSP_Id)) {
|
|
||||||
|
|
||||||
GeneralName generalName = description.getAccessLocation();
|
|
||||||
if (generalName.getType() == GeneralNameInterface.NAME_URI) {
|
|
||||||
URIName uri = (URIName)generalName.getName();
|
|
||||||
return uri.getURI();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
throw new CertPathValidatorException(
|
|
||||||
"Cannot find the location of the OCSP Responder");
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Checks that a cert can be used to verify a CRL.
|
* Checks that a cert can be used to verify a CRL.
|
||||||
*
|
*
|
||||||
@ -870,8 +892,8 @@ class RevocationChecker extends PKIXRevocationChecker {
|
|||||||
" circular dependency");
|
" circular dependency");
|
||||||
}
|
}
|
||||||
throw new CertPathValidatorException
|
throw new CertPathValidatorException
|
||||||
("Could not determine revocation status", null, null,
|
("Could not determine revocation status", null, null, -1,
|
||||||
-1, BasicReason.UNDETERMINED_REVOCATION_STATUS);
|
BasicReason.UNDETERMINED_REVOCATION_STATUS);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Try to find another key that might be able to sign
|
// Try to find another key that might be able to sign
|
||||||
@ -1067,6 +1089,15 @@ class RevocationChecker extends PKIXRevocationChecker {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public RevocationChecker clone() {
|
||||||
|
RevocationChecker copy = (RevocationChecker)super.clone();
|
||||||
|
// we don't deep-copy the exceptions, but that is ok because they
|
||||||
|
// are never modified after they are instantiated
|
||||||
|
copy.softFailExceptions = new LinkedList<>(softFailExceptions);
|
||||||
|
return copy;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* This inner class extends the X509CertSelector to add an additional
|
* This inner class extends the X509CertSelector to add an additional
|
||||||
* check to make sure the subject public key isn't on a particular list.
|
* check to make sure the subject public key isn't on a particular list.
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright (c) 2000, 2012, Oracle and/or its affiliates. All rights reserved.
|
* Copyright (c) 2000, 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
|
||||||
@ -422,7 +422,6 @@ public final class SunCertPathBuilder extends CertPathBuilderSpi {
|
|||||||
buildParams.anyPolicyInhibited(),
|
buildParams.anyPolicyInhibited(),
|
||||||
buildParams.policyQualifiersRejected(),
|
buildParams.policyQualifiersRejected(),
|
||||||
rootNode);
|
rootNode);
|
||||||
|
|
||||||
checkers.add(policyChecker);
|
checkers.add(policyChecker);
|
||||||
|
|
||||||
// add the algorithm checker
|
// add the algorithm checker
|
||||||
@ -455,13 +454,18 @@ public final class SunCertPathBuilder extends CertPathBuilderSpi {
|
|||||||
List<PKIXCertPathChecker> ckrs = buildParams.certPathCheckers();
|
List<PKIXCertPathChecker> ckrs = buildParams.certPathCheckers();
|
||||||
for (PKIXCertPathChecker ckr : ckrs) {
|
for (PKIXCertPathChecker ckr : ckrs) {
|
||||||
if (ckr instanceof PKIXRevocationChecker) {
|
if (ckr instanceof PKIXRevocationChecker) {
|
||||||
|
if (revCheckerAdded) {
|
||||||
|
throw new CertPathValidatorException(
|
||||||
|
"Only one PKIXRevocationChecker can be specified");
|
||||||
|
}
|
||||||
revCheckerAdded = true;
|
revCheckerAdded = true;
|
||||||
// if it's our own, initialize it
|
// if it's our own, initialize it
|
||||||
if (ckr instanceof RevocationChecker)
|
if (ckr instanceof RevocationChecker) {
|
||||||
((RevocationChecker)ckr).init(builder.trustAnchor,
|
((RevocationChecker)ckr).init(builder.trustAnchor,
|
||||||
buildParams);
|
buildParams);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
// only add a RevocationChecker if revocation is enabled and
|
// only add a RevocationChecker if revocation is enabled and
|
||||||
// a PKIXRevocationChecker has not already been added
|
// a PKIXRevocationChecker has not already been added
|
||||||
if (buildParams.revocationEnabled() && !revCheckerAdded) {
|
if (buildParams.revocationEnabled() && !revCheckerAdded) {
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved.
|
* Copyright (c) 2012, 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
|
||||||
@ -23,7 +23,7 @@
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* @test
|
* @test
|
||||||
* @bug 6854712 7171570
|
* @bug 6854712 7171570 8010748
|
||||||
* @summary Basic unit test for PKIXRevocationChecker
|
* @summary Basic unit test for PKIXRevocationChecker
|
||||||
*/
|
*/
|
||||||
|
|
||||||
@ -32,19 +32,9 @@ import java.io.InputStream;
|
|||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.OutputStream;
|
import java.io.OutputStream;
|
||||||
import java.net.URI;
|
import java.net.URI;
|
||||||
import java.security.cert.CertificateFactory;
|
import java.security.cert.*;
|
||||||
import java.security.cert.CertPathBuilder;
|
|
||||||
import java.security.cert.CertPathChecker;
|
|
||||||
import java.security.cert.CertPathValidator;
|
|
||||||
import java.security.cert.Extension;
|
|
||||||
import java.security.cert.PKIXRevocationChecker;
|
|
||||||
import java.security.cert.PKIXRevocationChecker.Option;
|
import java.security.cert.PKIXRevocationChecker.Option;
|
||||||
import java.security.cert.X509Certificate;
|
import java.util.*;
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.EnumSet;
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.Map;
|
|
||||||
import java.util.Set;
|
|
||||||
|
|
||||||
public class UnitTest {
|
public class UnitTest {
|
||||||
|
|
||||||
@ -56,22 +46,23 @@ public class UnitTest {
|
|||||||
|
|
||||||
System.out.println("Testing that get methods return null or " +
|
System.out.println("Testing that get methods return null or " +
|
||||||
"empty lists/sets/maps");
|
"empty lists/sets/maps");
|
||||||
requireNull(prc.getOCSPResponder(), "getOCSPResponder()");
|
requireNull(prc.getOcspResponder(), "getOcspResponder()");
|
||||||
requireNull(prc.getOCSPResponderCert(), "getOCSPResponderCert()");
|
requireNull(prc.getOcspResponderCert(), "getOcspResponderCert()");
|
||||||
requireEmpty(prc.getOCSPExtensions(), "getOCSPExtensions()");
|
requireEmpty(prc.getOcspExtensions(), "getOcspExtensions()");
|
||||||
requireEmpty(prc.getOCSPResponses(), "getOCSPResponses()");
|
requireEmpty(prc.getOcspResponses(), "getOcspResponses()");
|
||||||
requireEmpty(prc.getOptions(), "getOptions()");
|
requireEmpty(prc.getOptions(), "getOptions()");
|
||||||
|
requireEmpty(prc.getSoftFailExceptions(), "getSoftFailExceptions()");
|
||||||
|
|
||||||
System.out.println("Testing that get methods return same parameters " +
|
System.out.println("Testing that get methods return same parameters " +
|
||||||
"that are passed to set methods");
|
"that are passed to set methods");
|
||||||
URI uri = new URI("http://localhost");
|
URI uri = new URI("http://localhost");
|
||||||
prc.setOCSPResponder(uri);
|
prc.setOcspResponder(uri);
|
||||||
requireEquals(uri, prc.getOCSPResponder(), "getOCSPResponder()");
|
requireEquals(uri, prc.getOcspResponder(), "getOcspResponder()");
|
||||||
|
|
||||||
X509Certificate cert = getCert();
|
X509Certificate cert = getCert();
|
||||||
prc.setOCSPResponderCert(cert);
|
prc.setOcspResponderCert(cert);
|
||||||
requireEquals(cert, prc.getOCSPResponderCert(),
|
requireEquals(cert, prc.getOcspResponderCert(),
|
||||||
"getOCSPResponderCert()");
|
"getOcspResponderCert()");
|
||||||
|
|
||||||
List<Extension> exts = new ArrayList<>();
|
List<Extension> exts = new ArrayList<>();
|
||||||
for (String oid : cert.getNonCriticalExtensionOIDs()) {
|
for (String oid : cert.getNonCriticalExtensionOIDs()) {
|
||||||
@ -79,8 +70,8 @@ public class UnitTest {
|
|||||||
exts.add(new ExtensionImpl(oid,
|
exts.add(new ExtensionImpl(oid,
|
||||||
cert.getExtensionValue(oid), false));
|
cert.getExtensionValue(oid), false));
|
||||||
}
|
}
|
||||||
prc.setOCSPExtensions(exts);
|
prc.setOcspExtensions(exts);
|
||||||
requireEquals(exts, prc.getOCSPExtensions(), "getOCSPExtensions()");
|
requireEquals(exts, prc.getOcspExtensions(), "getOcspExtensions()");
|
||||||
|
|
||||||
Set<Option> options = EnumSet.of(Option.ONLY_END_ENTITY);
|
Set<Option> options = EnumSet.of(Option.ONLY_END_ENTITY);
|
||||||
prc.setOptions(options);
|
prc.setOptions(options);
|
||||||
@ -88,14 +79,14 @@ public class UnitTest {
|
|||||||
|
|
||||||
System.out.println("Testing that parameters are re-initialized to " +
|
System.out.println("Testing that parameters are re-initialized to " +
|
||||||
"default values if null is passed to set methods");
|
"default values if null is passed to set methods");
|
||||||
prc.setOCSPResponder(null);
|
prc.setOcspResponder(null);
|
||||||
requireNull(prc.getOCSPResponder(), "getOCSPResponder()");
|
requireNull(prc.getOcspResponder(), "getOcspResponder()");
|
||||||
prc.setOCSPResponderCert(null);
|
prc.setOcspResponderCert(null);
|
||||||
requireNull(prc.getOCSPResponderCert(), "getOCSPResponderCert()");
|
requireNull(prc.getOcspResponderCert(), "getOcspResponderCert()");
|
||||||
prc.setOCSPExtensions(null);
|
prc.setOcspExtensions(null);
|
||||||
requireEmpty(prc.getOCSPExtensions(), "getOCSPExtensions()");
|
requireEmpty(prc.getOcspExtensions(), "getOcspExtensions()");
|
||||||
prc.setOCSPResponses(null);
|
prc.setOcspResponses(null);
|
||||||
requireEmpty(prc.getOCSPResponses(), "getOCSPResponses()");
|
requireEmpty(prc.getOcspResponses(), "getOcspResponses()");
|
||||||
prc.setOptions(null);
|
prc.setOptions(null);
|
||||||
requireEmpty(prc.getOptions(), "getOptions()");
|
requireEmpty(prc.getOptions(), "getOptions()");
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user