提交 9dd8cab5 编写于 作者: M mullan

8010748: Add PKIXRevocationChecker NO_FALLBACK option and improve SOFT_FAIL option

Reviewed-by: vinnie
上级 d7ce324e
/*
* 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.
*
* 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
* preferred mechanism for checking revocation status, with CRLs as the
* 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
* {@link CertPathValidator#getRevocationChecker getRevocationChecker} method
* of a PKIX {@code CertPathValidator}. Additional parameters and options
* specific to revocation can be set (by calling {@link #setOCSPResponder}
* method for instance). The {@code PKIXRevocationChecker} is added to
* a {@code PKIXParameters} object using the
* {@link PKIXParameters#addCertPathChecker addCertPathChecker}
* specific to revocation can be set (by calling the
* {@link #setOcspResponder setOcspResponder} method for instance). The
* {@code PKIXRevocationChecker} is added to a {@code PKIXParameters} object
* using the {@link PKIXParameters#addCertPathChecker addCertPathChecker}
* or {@link PKIXParameters#setCertPathCheckers setCertPathCheckers} method,
* and then the {@code PKIXParameters} is passed along with the {@code CertPath}
* to be validated to the {@link CertPathValidator#validate validate} method
* of a PKIX {@code CertPathValidator}. When supplying a revocation checker in
* this manner, it will be used to check revocation irrespective of the setting
* 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
* {@code PKIXParameters}, it clones the {@code PKIXRevocationChecker};
......@@ -83,6 +88,13 @@ import java.util.Set;
* need not synchronize.
*
* @since 1.8
*
* @see <a href="http://www.ietf.org/rfc/rfc2560.txt"><i>RFC&nbsp;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&nbsp;5280: Internet X.509
* Public Key Infrastructure Certificate and Certificate Revocation List (CRL)
* Profile</i></a>
*/
public abstract class PKIXRevocationChecker extends PKIXCertPathChecker {
private URI ocspResponder;
......@@ -101,7 +113,7 @@ public abstract class PKIXRevocationChecker extends PKIXCertPathChecker {
*
* @param uri the responder URI
*/
public void setOCSPResponder(URI uri) {
public void setOcspResponder(URI uri) {
this.ocspResponder = uri;
}
......@@ -114,7 +126,7 @@ public abstract class PKIXRevocationChecker extends PKIXCertPathChecker {
*
* @return the responder URI, or {@code null} if not set
*/
public URI getOCSPResponder() {
public URI getOcspResponder() {
return ocspResponder;
}
......@@ -126,7 +138,7 @@ public abstract class PKIXRevocationChecker extends PKIXCertPathChecker {
*
* @param cert the responder's certificate
*/
public void setOCSPResponderCert(X509Certificate cert) {
public void setOcspResponderCert(X509Certificate 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
*/
public X509Certificate getOCSPResponderCert() {
public X509Certificate getOcspResponderCert() {
return ocspResponderCert;
}
......@@ -151,7 +163,7 @@ public abstract class PKIXRevocationChecker extends PKIXCertPathChecker {
* @param extensions a list of extensions. The list is copied to protect
* against subsequent modification.
*/
public void setOCSPExtensions(List<Extension> extensions)
public void setOcspExtensions(List<Extension> extensions)
{
this.ocspExtensions = (extensions == null)
? Collections.<Extension>emptyList()
......@@ -161,10 +173,10 @@ public abstract class PKIXRevocationChecker extends PKIXCertPathChecker {
/**
* 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.
*/
public List<Extension> getOCSPExtensions() {
public List<Extension> getOcspExtensions() {
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
* 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) {
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.
* 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());
for (Map.Entry<X509Certificate, byte[]> e : ocspResponses.entrySet()) {
copy.put(e.getKey(), e.getValue().clone());
......@@ -223,15 +235,31 @@ public abstract class PKIXRevocationChecker extends PKIXCertPathChecker {
/**
* Gets the revocation options.
*
* @return an unmodifiable set of revocation options, or an empty set if
* none are specified
* @return an unmodifiable set of revocation options. The set is empty if
* no options have been specified.
*/
public Set<Option> getOptions() {
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
public Object clone() {
public PKIXRevocationChecker clone() {
PKIXRevocationChecker copy = (PKIXRevocationChecker)super.clone();
copy.ocspExtensions = new ArrayList<>(ocspExtensions);
copy.ocspResponses = new HashMap<>(ocspResponses);
......@@ -262,9 +290,26 @@ public abstract class PKIXRevocationChecker extends PKIXCertPathChecker {
*/
PREFER_CRLS,
/**
* Ignore network failures. The default behavior is to consider it a
* failure if the revocation status of a certificate cannot be obtained
* due to a network error. This option applies to both OCSP and CRLs.
* Disable the fallback mechanism.
*/
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
}
......
......@@ -255,7 +255,9 @@ public final class OCSP {
}
response = Arrays.copyOf(response, total);
} 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 {
if (in != null) {
try {
......@@ -355,17 +357,4 @@ public final class OCSP {
*/
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.CertificateParsingException;
import java.security.cert.CertPathValidatorException;
import java.security.cert.CertPathValidatorException.BasicReason;
import java.security.cert.CRLReason;
import java.security.cert.TrustAnchor;
import java.security.cert.X509Certificate;
......@@ -121,8 +122,8 @@ public final class OCSPResponse {
public enum ResponseStatus {
SUCCESSFUL, // Response has valid confirmations
MALFORMED_REQUEST, // Illegal confirmation request
INTERNAL_ERROR, // Internal error in issuer
MALFORMED_REQUEST, // Illegal request
INTERNAL_ERROR, // Internal error in responder
TRY_LATER, // Try again later
UNUSED, // is not used
SIG_REQUIRED, // Must sign the request
......@@ -381,9 +382,18 @@ public final class OCSPResponse {
Date date, byte[] nonce)
throws CertPathValidatorException
{
if (responseStatus != ResponseStatus.SUCCESSFUL) {
throw new CertPathValidatorException
("OCSP response error: " + responseStatus);
switch (responseStatus) {
case SUCCESSFUL:
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
......
/*
* 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.
*
* This code is free software; you can redistribute it and/or modify it
......@@ -193,10 +193,15 @@ public final class PKIXCertPathValidator extends CertPathValidatorSpi {
List<PKIXCertPathChecker> checkers = params.certPathCheckers();
for (PKIXCertPathChecker checker : checkers) {
if (checker instanceof PKIXRevocationChecker) {
if (revCheckerAdded) {
throw new CertPathValidatorException(
"Only one PKIXRevocationChecker can be specified");
}
revCheckerAdded = true;
// if it's our own, initialize it
if (checker instanceof RevocationChecker)
if (checker instanceof RevocationChecker) {
((RevocationChecker)checker).init(anchor, params);
}
}
}
// only add a RevocationChecker if revocation is enabled and
......
/*
* 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.
*
* 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.CertPathValidatorException;
import java.security.cert.PKIXCertPathChecker;
import java.security.cert.PKIXRevocationChecker;
import java.security.cert.TrustAnchor;
import java.security.cert.X509Certificate;
import java.util.ArrayList;
......@@ -235,9 +236,16 @@ class ReverseState implements State {
for (PKIXCertPathChecker checker : userCheckers) {
if (checker instanceof AlgorithmChecker) {
((AlgorithmChecker)checker).trySetTrustAnchor(anchor);
} else if (checker instanceof RevocationChecker) {
((RevocationChecker)checker).init(anchor, buildParams);
((RevocationChecker)checker).init(false);
} 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);
}
((PKIXRevocationChecker)checker).init(false);
revCheckerAdded = true;
}
}
......
/*
* 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.
*
* 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.policyQualifiersRejected(),
rootNode);
checkers.add(policyChecker);
// add the algorithm checker
......@@ -455,11 +454,16 @@ public final class SunCertPathBuilder extends CertPathBuilderSpi {
List<PKIXCertPathChecker> ckrs = buildParams.certPathCheckers();
for (PKIXCertPathChecker ckr : ckrs) {
if (ckr instanceof PKIXRevocationChecker) {
if (revCheckerAdded) {
throw new CertPathValidatorException(
"Only one PKIXRevocationChecker can be specified");
}
revCheckerAdded = true;
// if it's our own, initialize it
if (ckr instanceof RevocationChecker)
if (ckr instanceof RevocationChecker) {
((RevocationChecker)ckr).init(builder.trustAnchor,
buildParams);
}
}
}
// only add a RevocationChecker if revocation is enabled and
......
/*
* 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.
*
* This code is free software; you can redistribute it and/or modify it
......@@ -23,7 +23,7 @@
/**
* @test
* @bug 6854712 7171570
* @bug 6854712 7171570 8010748
* @summary Basic unit test for PKIXRevocationChecker
*/
......@@ -32,19 +32,9 @@ import java.io.InputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.net.URI;
import java.security.cert.CertificateFactory;
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.*;
import java.security.cert.PKIXRevocationChecker.Option;
import java.security.cert.X509Certificate;
import java.util.ArrayList;
import java.util.EnumSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.*;
public class UnitTest {
......@@ -56,22 +46,23 @@ public class UnitTest {
System.out.println("Testing that get methods return null or " +
"empty lists/sets/maps");
requireNull(prc.getOCSPResponder(), "getOCSPResponder()");
requireNull(prc.getOCSPResponderCert(), "getOCSPResponderCert()");
requireEmpty(prc.getOCSPExtensions(), "getOCSPExtensions()");
requireEmpty(prc.getOCSPResponses(), "getOCSPResponses()");
requireNull(prc.getOcspResponder(), "getOcspResponder()");
requireNull(prc.getOcspResponderCert(), "getOcspResponderCert()");
requireEmpty(prc.getOcspExtensions(), "getOcspExtensions()");
requireEmpty(prc.getOcspResponses(), "getOcspResponses()");
requireEmpty(prc.getOptions(), "getOptions()");
requireEmpty(prc.getSoftFailExceptions(), "getSoftFailExceptions()");
System.out.println("Testing that get methods return same parameters " +
"that are passed to set methods");
URI uri = new URI("http://localhost");
prc.setOCSPResponder(uri);
requireEquals(uri, prc.getOCSPResponder(), "getOCSPResponder()");
prc.setOcspResponder(uri);
requireEquals(uri, prc.getOcspResponder(), "getOcspResponder()");
X509Certificate cert = getCert();
prc.setOCSPResponderCert(cert);
requireEquals(cert, prc.getOCSPResponderCert(),
"getOCSPResponderCert()");
prc.setOcspResponderCert(cert);
requireEquals(cert, prc.getOcspResponderCert(),
"getOcspResponderCert()");
List<Extension> exts = new ArrayList<>();
for (String oid : cert.getNonCriticalExtensionOIDs()) {
......@@ -79,8 +70,8 @@ public class UnitTest {
exts.add(new ExtensionImpl(oid,
cert.getExtensionValue(oid), false));
}
prc.setOCSPExtensions(exts);
requireEquals(exts, prc.getOCSPExtensions(), "getOCSPExtensions()");
prc.setOcspExtensions(exts);
requireEquals(exts, prc.getOcspExtensions(), "getOcspExtensions()");
Set<Option> options = EnumSet.of(Option.ONLY_END_ENTITY);
prc.setOptions(options);
......@@ -88,14 +79,14 @@ public class UnitTest {
System.out.println("Testing that parameters are re-initialized to " +
"default values if null is passed to set methods");
prc.setOCSPResponder(null);
requireNull(prc.getOCSPResponder(), "getOCSPResponder()");
prc.setOCSPResponderCert(null);
requireNull(prc.getOCSPResponderCert(), "getOCSPResponderCert()");
prc.setOCSPExtensions(null);
requireEmpty(prc.getOCSPExtensions(), "getOCSPExtensions()");
prc.setOCSPResponses(null);
requireEmpty(prc.getOCSPResponses(), "getOCSPResponses()");
prc.setOcspResponder(null);
requireNull(prc.getOcspResponder(), "getOcspResponder()");
prc.setOcspResponderCert(null);
requireNull(prc.getOcspResponderCert(), "getOcspResponderCert()");
prc.setOcspExtensions(null);
requireEmpty(prc.getOcspExtensions(), "getOcspExtensions()");
prc.setOcspResponses(null);
requireEmpty(prc.getOcspResponses(), "getOcspResponses()");
prc.setOptions(null);
requireEmpty(prc.getOptions(), "getOptions()");
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册