diff --git a/src/share/classes/sun/security/pkcs/SignerInfo.java b/src/share/classes/sun/security/pkcs/SignerInfo.java
index 78d3f631d68d636659e23b43960dcd3d1004dc75..5e69438c8d0bb8ff97cfe107ae6b2c6d98447d30 100644
--- a/src/share/classes/sun/security/pkcs/SignerInfo.java
+++ b/src/share/classes/sun/security/pkcs/SignerInfo.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1996, 2016, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1996, 2017, 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
@@ -37,6 +37,7 @@ import java.security.PublicKey;
import java.security.Signature;
import java.security.SignatureException;
import java.security.Timestamp;
+import java.security.cert.CertPathValidatorException;
import java.security.cert.CertificateException;
import java.security.cert.CertificateFactory;
import java.security.cert.CertPath;
@@ -49,6 +50,7 @@ import java.util.Set;
import sun.misc.HexDumpEncoder;
import sun.security.timestamp.TimestampToken;
+import sun.security.util.ConstraintsParameters;
import sun.security.util.Debug;
import sun.security.util.DerEncoder;
import sun.security.util.DerInputStream;
@@ -209,7 +211,7 @@ public class SignerInfo implements DerEncoder {
/**
* DER encode this object onto an output stream.
- * Implements the DerEncoder interface.
+ * Implements the {@code DerEncoder} interface.
*
* @param out
* the output stream on which to write the DER encoding.
@@ -266,7 +268,7 @@ public class SignerInfo implements DerEncoder {
if (userCert == null)
return null;
- ArrayList certList = new ArrayList();
+ ArrayList certList = new ArrayList<>();
certList.add(userCert);
X509Certificate[] pkcsCerts = block.getCertificates();
@@ -321,6 +323,8 @@ public class SignerInfo implements DerEncoder {
data = content.getContentBytes();
}
+ ConstraintsParameters cparams =
+ new ConstraintsParameters(timestamp);
String digestAlgname = getDigestAlgorithmId().getName();
byte[] dataSigned;
@@ -347,11 +351,11 @@ public class SignerInfo implements DerEncoder {
if (messageDigest == null) // fail if there is no message digest
return null;
- // check that algorithm is not restricted
- if (!JAR_DISABLED_CHECK.permits(DIGEST_PRIMITIVE_SET,
- digestAlgname, null)) {
- throw new SignatureException("Digest check failed. " +
- "Disabled algorithm used: " + digestAlgname);
+ // check that digest algorithm is not restricted
+ try {
+ JAR_DISABLED_CHECK.permits(digestAlgname, cparams);
+ } catch (CertPathValidatorException e) {
+ throw new SignatureException(e.getMessage(), e);
}
MessageDigest md = MessageDigest.getInstance(digestAlgname);
@@ -385,17 +389,18 @@ public class SignerInfo implements DerEncoder {
String algname = AlgorithmId.makeSigAlg(
digestAlgname, encryptionAlgname);
- // check that algorithm is not restricted
- if (!JAR_DISABLED_CHECK.permits(SIG_PRIMITIVE_SET, algname, null)) {
- throw new SignatureException("Signature check failed. " +
- "Disabled algorithm used: " + algname);
+ // check that jar signature algorithm is not restricted
+ try {
+ JAR_DISABLED_CHECK.permits(algname, cparams);
+ } catch (CertPathValidatorException e) {
+ throw new SignatureException(e.getMessage(), e);
}
X509Certificate cert = getCertificate(block);
- PublicKey key = cert.getPublicKey();
if (cert == null) {
return null;
}
+ PublicKey key = cert.getPublicKey();
// check if the public key is restricted
if (!JAR_DISABLED_CHECK.permits(SIG_PRIMITIVE_SET, key)) {
@@ -519,7 +524,7 @@ public class SignerInfo implements DerEncoder {
* Extracts a timestamp from a PKCS7 SignerInfo.
*
* Examines the signer's unsigned attributes for a
- * signatureTimestampToken attribute. If present,
+ * {@code signatureTimestampToken} attribute. If present,
* then it is parsed to extract the date and time at which the
* timestamp was generated.
*
diff --git a/src/share/classes/sun/security/provider/certpath/AlgorithmChecker.java b/src/share/classes/sun/security/provider/certpath/AlgorithmChecker.java
index 73031564557f9a07abfab982734e3ee4cbcd4479..f7bedb99ccbf0702b1fd5f5d030de0977473f808 100644
--- a/src/share/classes/sun/security/provider/certpath/AlgorithmChecker.java
+++ b/src/share/classes/sun/security/provider/certpath/AlgorithmChecker.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2009, 2016, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2009, 2017, 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
@@ -27,8 +27,11 @@ package sun.security.provider.certpath;
import java.security.AlgorithmConstraints;
import java.security.CryptoPrimitive;
+import java.security.Timestamp;
+import java.security.cert.CertPathValidator;
import java.util.Collection;
import java.util.Collections;
+import java.util.Date;
import java.util.Set;
import java.util.EnumSet;
import java.math.BigInteger;
@@ -51,15 +54,16 @@ import java.security.interfaces.DSAPublicKey;
import java.security.spec.DSAPublicKeySpec;
import sun.security.util.AnchorCertificates;
-import sun.security.util.CertConstraintParameters;
+import sun.security.util.ConstraintsParameters;
import sun.security.util.Debug;
import sun.security.util.DisabledAlgorithmConstraints;
+import sun.security.validator.Validator;
import sun.security.x509.X509CertImpl;
import sun.security.x509.X509CRLImpl;
import sun.security.x509.AlgorithmId;
/**
- * A PKIXCertPathChecker implementation to check whether a
+ * A {@code PKIXCertPathChecker} implementation to check whether a
* specified certificate contains the required algorithm constraints.
*
* Certificate fields such as the subject public key, the signature
@@ -69,24 +73,27 @@ import sun.security.x509.AlgorithmId;
* @see PKIXCertPathChecker
* @see PKIXParameters
*/
-final public class AlgorithmChecker extends PKIXCertPathChecker {
+public final class AlgorithmChecker extends PKIXCertPathChecker {
private static final Debug debug = Debug.getInstance("certpath");
private final AlgorithmConstraints constraints;
private final PublicKey trustedPubKey;
+ private final Date pkixdate;
private PublicKey prevPubKey;
+ private final Timestamp jarTimestamp;
+ private final String variant;
- private final static Set SIGNATURE_PRIMITIVE_SET =
+ private static final Set SIGNATURE_PRIMITIVE_SET =
Collections.unmodifiableSet(EnumSet.of(CryptoPrimitive.SIGNATURE));
- private final static Set KU_PRIMITIVE_SET =
+ private static final Set KU_PRIMITIVE_SET =
Collections.unmodifiableSet(EnumSet.of(
CryptoPrimitive.SIGNATURE,
CryptoPrimitive.KEY_ENCAPSULATION,
CryptoPrimitive.PUBLIC_KEY_ENCRYPTION,
CryptoPrimitive.KEY_AGREEMENT));
- private final static DisabledAlgorithmConstraints
+ private static final DisabledAlgorithmConstraints
certPathDefaultConstraints = new DisabledAlgorithmConstraints(
DisabledAlgorithmConstraints.PROPERTY_CERTPATH_DISABLED_ALGS);
@@ -99,64 +106,99 @@ final public class AlgorithmChecker extends PKIXCertPathChecker {
private boolean trustedMatch = false;
/**
- * Create a new AlgorithmChecker with the algorithm
- * constraints specified in security property
- * "jdk.certpath.disabledAlgorithms".
+ * Create a new {@code AlgorithmChecker} with the given algorithm
+ * given {@code TrustAnchor} and {@code String} variant.
*
* @param anchor the trust anchor selected to validate the target
* certificate
+ * @param variant is the Validator variants of the operation. A null value
+ * passed will set it to Validator.GENERIC.
*/
- public AlgorithmChecker(TrustAnchor anchor) {
- this(anchor, certPathDefaultConstraints);
+ public AlgorithmChecker(TrustAnchor anchor, String variant) {
+ this(anchor, certPathDefaultConstraints, null, null, variant);
}
/**
- * Create a new AlgorithmChecker with the
- * given {@code AlgorithmConstraints}.
- *
- * Note that this constructor will be used to check a certification
- * path where the trust anchor is unknown, or a certificate list which may
- * contain the trust anchor. This constructor is used by SunJSSE.
+ * Create a new {@code AlgorithmChecker} with the given
+ * {@code AlgorithmConstraints}, {@code Timestamp}, and {@code String}
+ * variant.
+ *
+ * Note that this constructor can initialize a variation of situations where
+ * the AlgorithmConstraints, Timestamp, or Variant maybe known.
*
* @param constraints the algorithm constraints (or null)
+ * @param jarTimestamp Timestamp passed for JAR timestamp constraint
+ * checking. Set to null if not applicable.
+ * @param variant is the Validator variants of the operation. A null value
+ * passed will set it to Validator.GENERIC.
*/
- public AlgorithmChecker(AlgorithmConstraints constraints) {
- this.prevPubKey = null;
- this.trustedPubKey = null;
- this.constraints = constraints;
+ public AlgorithmChecker(AlgorithmConstraints constraints,
+ Timestamp jarTimestamp, String variant) {
+ this(null, constraints, null, jarTimestamp, variant);
}
/**
- * Create a new AlgorithmChecker with the
- * given TrustAnchor and AlgorithmConstraints.
+ * Create a new {@code AlgorithmChecker} with the
+ * given {@code TrustAnchor}, {@code AlgorithmConstraints},
+ * {@code Timestamp}, and {@code String} variant.
*
* @param anchor the trust anchor selected to validate the target
* certificate
* @param constraints the algorithm constraints (or null)
- *
- * @throws IllegalArgumentException if the anchor is null
+ * @param pkixdate The date specified by the PKIXParameters date. If the
+ * PKIXParameters is null, the current date is used. This
+ * should be null when jar files are being checked.
+ * @param jarTimestamp Timestamp passed for JAR timestamp constraint
+ * checking. Set to null if not applicable.
+ * @param variant is the Validator variants of the operation. A null value
+ * passed will set it to Validator.GENERIC.
*/
public AlgorithmChecker(TrustAnchor anchor,
- AlgorithmConstraints constraints) {
+ AlgorithmConstraints constraints, Date pkixdate,
+ Timestamp jarTimestamp, String variant) {
- if (anchor == null) {
- throw new IllegalArgumentException(
- "The trust anchor cannot be null");
- }
-
- if (anchor.getTrustedCert() != null) {
- this.trustedPubKey = anchor.getTrustedCert().getPublicKey();
- // Check for anchor certificate restrictions
- trustedMatch = checkFingerprint(anchor.getTrustedCert());
- if (trustedMatch && debug != null) {
- debug.println("trustedMatch = true");
+ if (anchor != null) {
+ if (anchor.getTrustedCert() != null) {
+ this.trustedPubKey = anchor.getTrustedCert().getPublicKey();
+ // Check for anchor certificate restrictions
+ trustedMatch = checkFingerprint(anchor.getTrustedCert());
+ if (trustedMatch && debug != null) {
+ debug.println("trustedMatch = true");
+ }
+ } else {
+ this.trustedPubKey = anchor.getCAPublicKey();
}
} else {
- this.trustedPubKey = anchor.getCAPublicKey();
+ this.trustedPubKey = null;
+ if (debug != null) {
+ debug.println("TrustAnchor is null, trustedMatch is false.");
+ }
}
- this.prevPubKey = trustedPubKey;
- this.constraints = constraints;
+ this.prevPubKey = this.trustedPubKey;
+ this.constraints = (constraints == null ? certPathDefaultConstraints :
+ constraints);
+ // If we are checking jar files, set pkixdate the same as the timestamp
+ // for certificate checking
+ this.pkixdate = (jarTimestamp != null ? jarTimestamp.getTimestamp() :
+ pkixdate);
+ this.jarTimestamp = jarTimestamp;
+ this.variant = (variant == null ? Validator.VAR_GENERIC : variant);
+ }
+
+ /**
+ * Create a new {@code AlgorithmChecker} with the given {@code TrustAnchor},
+ * {@code PKIXParameter} date, and {@code varient}
+ *
+ * @param anchor the trust anchor selected to validate the target
+ * certificate
+ * @param pkixdate Date the constraints are checked against. The value is
+ * either the PKIXParameters date or null for the current date.
+ * @param variant is the Validator variants of the operation. A null value
+ * passed will set it to Validator.GENERIC.
+ */
+ public AlgorithmChecker(TrustAnchor anchor, Date pkixdate, String variant) {
+ this(anchor, certPathDefaultConstraints, pkixdate, null, variant);
}
// Check this 'cert' for restrictions in the AnchorCertificates
@@ -217,6 +259,28 @@ final public class AlgorithmChecker extends PKIXCertPathChecker {
null, null, -1, PKIXReason.INVALID_KEY_USAGE);
}
+ X509CertImpl x509Cert;
+ AlgorithmId algorithmId;
+ try {
+ x509Cert = X509CertImpl.toImpl((X509Certificate)cert);
+ algorithmId = (AlgorithmId)x509Cert.get(X509CertImpl.SIG_ALG);
+ } catch (CertificateException ce) {
+ throw new CertPathValidatorException(ce);
+ }
+
+ AlgorithmParameters currSigAlgParams = algorithmId.getParameters();
+ PublicKey currPubKey = cert.getPublicKey();
+ String currSigAlg = ((X509Certificate)cert).getSigAlgName();
+
+ // Check the signature algorithm and parameters against constraints.
+ if (!constraints.permits(SIGNATURE_PRIMITIVE_SET, currSigAlg,
+ currSigAlgParams)) {
+ throw new CertPathValidatorException(
+ "Algorithm constraints check failed on signature " +
+ "algorithm: " + currSigAlg, null, null, -1,
+ BasicReason.ALGORITHM_CONSTRAINED);
+ }
+
// Assume all key usage bits are set if key usage is not present
Set primitives = KU_PRIMITIVE_SET;
@@ -253,101 +317,74 @@ final public class AlgorithmChecker extends PKIXCertPathChecker {
}
}
- PublicKey currPubKey = cert.getPublicKey();
+ ConstraintsParameters cp =
+ new ConstraintsParameters((X509Certificate)cert,
+ trustedMatch, pkixdate, jarTimestamp, variant);
+ // Check against local constraints if it is DisabledAlgorithmConstraints
if (constraints instanceof DisabledAlgorithmConstraints) {
- // Check against DisabledAlgorithmConstraints certpath constraints.
- // permits() will throw exception on failure.
- ((DisabledAlgorithmConstraints)constraints).permits(primitives,
- new CertConstraintParameters((X509Certificate)cert,
- trustedMatch));
- // If there is no previous key, set one and exit
- if (prevPubKey == null) {
- prevPubKey = currPubKey;
- return;
- }
- }
-
- X509CertImpl x509Cert;
- AlgorithmId algorithmId;
- try {
- x509Cert = X509CertImpl.toImpl((X509Certificate)cert);
- algorithmId = (AlgorithmId)x509Cert.get(X509CertImpl.SIG_ALG);
- } catch (CertificateException ce) {
- throw new CertPathValidatorException(ce);
- }
+ ((DisabledAlgorithmConstraints)constraints).permits(currSigAlg, cp);
+ // DisabledAlgorithmsConstraints does not check primitives, so key
+ // additional key check.
- AlgorithmParameters currSigAlgParams = algorithmId.getParameters();
- String currSigAlg = x509Cert.getSigAlgName();
-
- // If 'constraints' is not of DisabledAlgorithmConstraints, check all
- // everything individually
- if (!(constraints instanceof DisabledAlgorithmConstraints)) {
- // Check the current signature algorithm
- if (!constraints.permits(
- SIGNATURE_PRIMITIVE_SET,
- currSigAlg, currSigAlgParams)) {
+ } else {
+ // Perform the default constraints checking anyway.
+ certPathDefaultConstraints.permits(currSigAlg, cp);
+ // Call locally set constraints to check key with primitives.
+ if (!constraints.permits(primitives, currPubKey)) {
throw new CertPathValidatorException(
- "Algorithm constraints check failed on signature " +
- "algorithm: " + currSigAlg, null, null, -1,
- BasicReason.ALGORITHM_CONSTRAINED);
+ "Algorithm constraints check failed on key " +
+ currPubKey.getAlgorithm() + " with size of " +
+ sun.security.util.KeyUtil.getKeySize(currPubKey) +
+ "bits",
+ null, null, -1, BasicReason.ALGORITHM_CONSTRAINED);
}
-
- if (!constraints.permits(primitives, currPubKey)) {
- throw new CertPathValidatorException(
- "Algorithm constraints check failed on keysize: " +
- sun.security.util.KeyUtil.getKeySize(currPubKey),
- null, null, -1, BasicReason.ALGORITHM_CONSTRAINED);
}
+
+ // If there is no previous key, set one and exit
+ if (prevPubKey == null) {
+ prevPubKey = currPubKey;
+ return;
}
// Check with previous cert for signature algorithm and public key
- if (prevPubKey != null) {
- if (!constraints.permits(
- SIGNATURE_PRIMITIVE_SET,
- currSigAlg, prevPubKey, currSigAlgParams)) {
- throw new CertPathValidatorException(
+ if (!constraints.permits(
+ SIGNATURE_PRIMITIVE_SET,
+ currSigAlg, prevPubKey, currSigAlgParams)) {
+ throw new CertPathValidatorException(
"Algorithm constraints check failed on " +
"signature algorithm: " + currSigAlg,
- null, null, -1, BasicReason.ALGORITHM_CONSTRAINED);
- }
+ null, null, -1, BasicReason.ALGORITHM_CONSTRAINED);
+ }
- // Inherit key parameters from previous key
- if (PKIX.isDSAPublicKeyWithoutParams(currPubKey)) {
- // Inherit DSA parameters from previous key
- if (!(prevPubKey instanceof DSAPublicKey)) {
- throw new CertPathValidatorException("Input key is not " +
+ // Inherit key parameters from previous key
+ if (PKIX.isDSAPublicKeyWithoutParams(currPubKey)) {
+ // Inherit DSA parameters from previous key
+ if (!(prevPubKey instanceof DSAPublicKey)) {
+ throw new CertPathValidatorException("Input key is not " +
"of a appropriate type for inheriting parameters");
- }
+ }
- DSAParams params = ((DSAPublicKey)prevPubKey).getParams();
- if (params == null) {
- throw new CertPathValidatorException(
+ DSAParams params = ((DSAPublicKey)prevPubKey).getParams();
+ if (params == null) {
+ throw new CertPathValidatorException(
"Key parameters missing from public key.");
- }
+ }
- try {
- BigInteger y = ((DSAPublicKey)currPubKey).getY();
- KeyFactory kf = KeyFactory.getInstance("DSA");
- DSAPublicKeySpec ks = new DSAPublicKeySpec(y,
- params.getP(),
- params.getQ(),
- params.getG());
- currPubKey = kf.generatePublic(ks);
- } catch (GeneralSecurityException e) {
- throw new CertPathValidatorException("Unable to generate " +
+ try {
+ BigInteger y = ((DSAPublicKey)currPubKey).getY();
+ KeyFactory kf = KeyFactory.getInstance("DSA");
+ DSAPublicKeySpec ks = new DSAPublicKeySpec(y, params.getP(),
+ params.getQ(), params.getG());
+ currPubKey = kf.generatePublic(ks);
+ } catch (GeneralSecurityException e) {
+ throw new CertPathValidatorException("Unable to generate " +
"key with inherited parameters: " + e.getMessage(), e);
- }
}
}
// reset the previous public key
prevPubKey = currPubKey;
-
- // check the extended key usage, ignore the check now
- // List extendedKeyUsages = x509Cert.getExtendedKeyUsage();
-
- // DO NOT remove any unresolved critical extensions
}
/**
@@ -387,8 +424,10 @@ final public class AlgorithmChecker extends PKIXCertPathChecker {
*
* @param key the public key to verify the CRL signature
* @param crl the target CRL
+ * @param variant is the Validator variants of the operation. A null value
+ * passed will set it to Validator.GENERIC.
*/
- static void check(PublicKey key, X509CRL crl)
+ static void check(PublicKey key, X509CRL crl, String variant)
throws CertPathValidatorException {
X509CRLImpl x509CRLImpl = null;
@@ -399,28 +438,24 @@ final public class AlgorithmChecker extends PKIXCertPathChecker {
}
AlgorithmId algorithmId = x509CRLImpl.getSigAlgId();
- check(key, algorithmId);
+ check(key, algorithmId, variant);
}
/**
* Check the signature algorithm with the specified public key.
*
* @param key the public key to verify the CRL signature
- * @param crl the target CRL
+ * @param algorithmId signature algorithm Algorithm ID
+ * @param variant is the Validator variants of the operation. A null value
+ * passed will set it to Validator.GENERIC.
*/
- static void check(PublicKey key, AlgorithmId algorithmId)
+ static void check(PublicKey key, AlgorithmId algorithmId, String variant)
throws CertPathValidatorException {
String sigAlgName = algorithmId.getName();
AlgorithmParameters sigAlgParams = algorithmId.getParameters();
- if (!certPathDefaultConstraints.permits(
- SIGNATURE_PRIMITIVE_SET, sigAlgName, key, sigAlgParams)) {
- throw new CertPathValidatorException(
- "Algorithm constraints check failed on signature algorithm: " +
- sigAlgName + " is disabled",
- null, null, -1, BasicReason.ALGORITHM_CONSTRAINED);
- }
+ certPathDefaultConstraints.permits(new ConstraintsParameters(
+ sigAlgName, sigAlgParams, key, variant));
}
-
}
diff --git a/src/share/classes/sun/security/provider/certpath/DistributionPointFetcher.java b/src/share/classes/sun/security/provider/certpath/DistributionPointFetcher.java
index 086e73f64c938fa1b404c699bd2aa5fa11bc23ba..e4429e0892e5c7eb8faeaa4f74177641d0c42b38 100644
--- a/src/share/classes/sun/security/provider/certpath/DistributionPointFetcher.java
+++ b/src/share/classes/sun/security/provider/certpath/DistributionPointFetcher.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2002, 2015, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2002, 2017, 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
@@ -33,6 +33,7 @@ import javax.security.auth.x500.X500Principal;
import java.util.*;
import sun.security.util.Debug;
+import sun.security.validator.Validator;
import static sun.security.x509.PKIXExtensions.*;
import sun.security.x509.*;
@@ -65,6 +66,20 @@ public class DistributionPointFetcher {
* Return the X509CRLs matching this selector. The selector must be
* an X509CRLSelector with certificateChecking set.
*/
+ public static Collection getCRLs(X509CRLSelector selector,
+ boolean signFlag, PublicKey prevKey, String provider,
+ List certStores, boolean[] reasonsMask,
+ Set trustAnchors, Date validity, String variant)
+ throws CertStoreException
+ {
+ return getCRLs(selector, signFlag, prevKey, null, provider, certStores,
+ reasonsMask, trustAnchors, validity, variant);
+ }
+ /**
+ * Return the X509CRLs matching this selector. The selector must be
+ * an X509CRLSelector with certificateChecking set.
+ */
+ // Called by com.sun.deploy.security.RevocationChecker
public static Collection getCRLs(X509CRLSelector selector,
boolean signFlag,
PublicKey prevKey,
@@ -76,7 +91,7 @@ public class DistributionPointFetcher {
throws CertStoreException
{
return getCRLs(selector, signFlag, prevKey, null, provider, certStores,
- reasonsMask, trustAnchors, validity);
+ reasonsMask, trustAnchors, validity, Validator.VAR_GENERIC);
}
/**
@@ -91,7 +106,8 @@ public class DistributionPointFetcher {
List certStores,
boolean[] reasonsMask,
Set trustAnchors,
- Date validity)
+ Date validity,
+ String variant)
throws CertStoreException
{
X509Certificate cert = selector.getCertificateChecking();
@@ -120,7 +136,7 @@ public class DistributionPointFetcher {
DistributionPoint point = t.next();
Collection crls = getCRLs(selector, certImpl,
point, reasonsMask, signFlag, prevKey, prevCert, provider,
- certStores, trustAnchors, validity);
+ certStores, trustAnchors, validity, variant);
results.addAll(crls);
}
if (debug != null) {
@@ -145,7 +161,7 @@ public class DistributionPointFetcher {
X509CertImpl certImpl, DistributionPoint point, boolean[] reasonsMask,
boolean signFlag, PublicKey prevKey, X509Certificate prevCert,
String provider, List certStores,
- Set trustAnchors, Date validity)
+ Set trustAnchors, Date validity, String variant)
throws CertStoreException {
// check for full name
@@ -208,7 +224,7 @@ public class DistributionPointFetcher {
selector.setIssuerNames(null);
if (selector.match(crl) && verifyCRL(certImpl, point, crl,
reasonsMask, signFlag, prevKey, prevCert, provider,
- trustAnchors, certStores, validity)) {
+ trustAnchors, certStores, validity, variant)) {
crls.add(crl);
}
} catch (IOException | CRLException e) {
@@ -317,7 +333,7 @@ public class DistributionPointFetcher {
X509CRL crl, boolean[] reasonsMask, boolean signFlag,
PublicKey prevKey, X509Certificate prevCert, String provider,
Set trustAnchors, List certStores,
- Date validity) throws CRLException, IOException {
+ Date validity, String variant) throws CRLException, IOException {
if (debug != null) {
debug.println("DistributionPointFetcher.verifyCRL: " +
@@ -443,7 +459,7 @@ public class DistributionPointFetcher {
}
if (indirectCRL) {
if (pointCrlIssuers.size() != 1) {
- // RFC 3280: there must be only 1 CRL issuer
+ // RFC 5280: there must be only 1 CRL issuer
// name when relativeName is present
if (debug != null) {
debug.println("must only be one CRL " +
@@ -664,7 +680,7 @@ public class DistributionPointFetcher {
// check the crl signature algorithm
try {
- AlgorithmChecker.check(prevKey, crl);
+ AlgorithmChecker.check(prevKey, crl, variant);
} catch (CertPathValidatorException cpve) {
if (debug != null) {
debug.println("CRL signature algorithm check failed: " + cpve);
diff --git a/src/share/classes/sun/security/provider/certpath/OCSP.java b/src/share/classes/sun/security/provider/certpath/OCSP.java
index dce8fd6b93403b14effc8288ba44d2dd8ea6701c..dce73028cd0e140fb6283f9b8f205e61e942f7d3 100644
--- a/src/share/classes/sun/security/provider/certpath/OCSP.java
+++ b/src/share/classes/sun/security/provider/certpath/OCSP.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2009, 2013, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2009, 2017, 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
@@ -35,6 +35,7 @@ import java.security.cert.CertPathValidatorException;
import java.security.cert.CertPathValidatorException.BasicReason;
import java.security.cert.CRLReason;
import java.security.cert.Extension;
+import java.security.cert.TrustAnchor;
import java.security.cert.X509Certificate;
import java.util.Arrays;
import java.util.Collections;
@@ -42,14 +43,14 @@ import java.util.Date;
import java.util.List;
import java.util.Map;
-import static sun.security.provider.certpath.OCSPResponse.*;
import sun.security.action.GetIntegerAction;
import sun.security.util.Debug;
-import sun.security.util.ObjectIdentifier;
+import sun.security.validator.Validator;
import sun.security.x509.AccessDescription;
import sun.security.x509.AuthorityInfoAccessExtension;
import sun.security.x509.GeneralName;
import sun.security.x509.GeneralNameInterface;
+import sun.security.x509.PKIXExtensions;
import sun.security.x509.URIName;
import sun.security.x509.X509CertImpl;
@@ -65,9 +66,6 @@ import sun.security.x509.X509CertImpl;
*/
public final class OCSP {
- static final ObjectIdentifier NONCE_EXTENSION_OID =
- ObjectIdentifier.newInternal(new int[]{ 1, 3, 6, 1, 5, 5, 7, 48, 1, 2});
-
private static final Debug debug = Debug.getInstance("certpath");
private static final int DEFAULT_CONNECT_TIMEOUT = 15000;
@@ -97,42 +95,6 @@ public final class OCSP {
private OCSP() {}
- /**
- * Obtains the revocation status of a certificate using OCSP using the most
- * common defaults. The OCSP responder URI is retrieved from the
- * certificate's AIA extension. The OCSP responder certificate is assumed
- * to be the issuer's certificate (or issued by the issuer CA).
- *
- * @param cert the certificate to be checked
- * @param issuerCert the issuer certificate
- * @return the RevocationStatus
- * @throws IOException if there is an exception connecting to or
- * communicating with the OCSP responder
- * @throws CertPathValidatorException if an exception occurs while
- * encoding the OCSP Request or validating the OCSP Response
- */
- public static RevocationStatus check(X509Certificate cert,
- X509Certificate issuerCert)
- throws IOException, CertPathValidatorException {
- CertId certId = null;
- URI responderURI = null;
- try {
- X509CertImpl certImpl = X509CertImpl.toImpl(cert);
- responderURI = getResponderURI(certImpl);
- if (responderURI == null) {
- throw new CertPathValidatorException
- ("No OCSP Responder URI in certificate");
- }
- certId = new CertId(issuerCert, certImpl.getSerialNumberObject());
- } catch (CertificateException | IOException e) {
- throw new CertPathValidatorException
- ("Exception while encoding OCSPRequest", e);
- }
- OCSPResponse ocspResponse = check(Collections.singletonList(certId),
- responderURI, issuerCert, null, null,
- Collections.emptyList());
- return (RevocationStatus)ocspResponse.getSingleResponse(certId);
- }
/**
* Obtains the revocation status of a certificate using OCSP.
@@ -149,6 +111,8 @@ public final class OCSP {
* @throws CertPathValidatorException if an exception occurs while
* encoding the OCSP Request or validating the OCSP Response
*/
+
+ // Called by com.sun.deploy.security.TrustDecider
public static RevocationStatus check(X509Certificate cert,
X509Certificate issuerCert,
URI responderURI,
@@ -157,18 +121,27 @@ public final class OCSP {
throws IOException, CertPathValidatorException
{
return check(cert, issuerCert, responderURI, responderCert, date,
- Collections.emptyList());
+ Collections.emptyList(), Validator.VAR_GENERIC);
}
- // Called by com.sun.deploy.security.TrustDecider
+
public static RevocationStatus check(X509Certificate cert,
- X509Certificate issuerCert,
- URI responderURI,
- X509Certificate responderCert,
- Date date, List extensions)
+ X509Certificate issuerCert, URI responderURI,
+ X509Certificate responderCert, Date date, List extensions,
+ String variant)
throws IOException, CertPathValidatorException
{
- CertId certId = null;
+ return check(cert, responderURI, null, issuerCert, responderCert, date,
+ extensions, variant);
+ }
+
+ public static RevocationStatus check(X509Certificate cert,
+ URI responderURI, TrustAnchor anchor, X509Certificate issuerCert,
+ X509Certificate responderCert, Date date,
+ List extensions, String variant)
+ throws IOException, CertPathValidatorException
+ {
+ CertId certId;
try {
X509CertImpl certImpl = X509CertImpl.toImpl(cert);
certId = new CertId(issuerCert, certImpl.getSerialNumberObject());
@@ -177,19 +150,23 @@ public final class OCSP {
("Exception while encoding OCSPRequest", e);
}
OCSPResponse ocspResponse = check(Collections.singletonList(certId),
- responderURI, issuerCert, responderCert, date, extensions);
+ responderURI, new OCSPResponse.IssuerInfo(anchor, issuerCert),
+ responderCert, date, extensions, variant);
return (RevocationStatus) ocspResponse.getSingleResponse(certId);
}
/**
* Checks the revocation status of a list of certificates using OCSP.
*
- * @param certs the CertIds to be checked
+ * @param certIds the CertIds to be checked
* @param responderURI the URI of the OCSP responder
- * @param issuerCert the issuer's certificate
+ * @param issuerInfo the issuer's certificate and/or subject and public key
* @param responderCert 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.
+ * @param extensions zero or more OCSP extensions to be included in the
+ * request. If no extensions are requested, an empty {@code List} must
+ * be used. A {@code null} value is not allowed.
* @return the OCSPResponse
* @throws IOException if there is an exception connecting to or
* communicating with the OCSP responder
@@ -197,24 +174,59 @@ public final class OCSP {
* encoding the OCSP Request or validating the OCSP Response
*/
static OCSPResponse check(List certIds, URI responderURI,
- X509Certificate issuerCert,
+ OCSPResponse.IssuerInfo issuerInfo,
X509Certificate responderCert, Date date,
- List extensions)
+ List extensions, String variant)
throws IOException, CertPathValidatorException
{
- byte[] bytes = null;
- OCSPRequest request = null;
+ byte[] nonce = null;
+ for (Extension ext : extensions) {
+ if (ext.getId().equals(PKIXExtensions.OCSPNonce_Id.toString())) {
+ nonce = ext.getValue();
+ }
+ }
+
+ OCSPResponse ocspResponse = null;
try {
- request = new OCSPRequest(certIds, extensions);
- bytes = request.encodeBytes();
+ byte[] response = getOCSPBytes(certIds, responderURI, extensions);
+ ocspResponse = new OCSPResponse(response);
+
+ // verify the response
+ ocspResponse.verify(certIds, issuerInfo, responderCert, date,
+ nonce, variant);
} catch (IOException ioe) {
- throw new CertPathValidatorException
- ("Exception while encoding OCSPRequest", ioe);
+ throw new CertPathValidatorException(
+ "Unable to determine revocation status due to network error",
+ ioe, null, -1, BasicReason.UNDETERMINED_REVOCATION_STATUS);
}
+ return ocspResponse;
+ }
+
+
+ /**
+ * Send an OCSP request, then read and return the OCSP response bytes.
+ *
+ * @param certIds the CertIds to be checked
+ * @param responderURI the URI of the OCSP responder
+ * @param extensions zero or more OCSP extensions to be included in the
+ * request. If no extensions are requested, an empty {@code List} must
+ * be used. A {@code null} value is not allowed.
+ *
+ * @return the OCSP response bytes
+ *
+ * @throws IOException if there is an exception connecting to or
+ * communicating with the OCSP responder
+ */
+ public static byte[] getOCSPBytes(List certIds, URI responderURI,
+ List extensions) throws IOException {
+ OCSPRequest request = new OCSPRequest(certIds, extensions);
+ byte[] bytes = request.encodeBytes();
+
InputStream in = null;
OutputStream out = null;
byte[] response = null;
+
try {
URL url = responderURI.toURL();
if (debug != null) {
@@ -257,10 +269,6 @@ public final class OCSP {
}
}
response = Arrays.copyOf(response, total);
- } catch (IOException 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 {
@@ -277,20 +285,7 @@ public final class OCSP {
}
}
}
-
- OCSPResponse ocspResponse = null;
- try {
- ocspResponse = new OCSPResponse(response);
- } catch (IOException ioe) {
- // response decoding exception
- throw new CertPathValidatorException(ioe);
- }
-
- // verify the response
- ocspResponse.verify(certIds, issuerCert, responderCert, date,
- request.getNonce());
-
- return ocspResponse;
+ return response;
}
/**
@@ -322,7 +317,7 @@ public final class OCSP {
List descriptions = aia.getAccessDescriptions();
for (AccessDescription description : descriptions) {
- if (description.getAccessMethod().equals((Object)
+ if (description.getAccessMethod().equals(
AccessDescription.Ad_OCSP_Id)) {
GeneralName generalName = description.getAccessLocation();
diff --git a/src/share/classes/sun/security/provider/certpath/OCSPRequest.java b/src/share/classes/sun/security/provider/certpath/OCSPRequest.java
index 6bded97293b9afc44236e0f6120e7e101b0fe0ca..5eb97d264ba8d5817c24975baeba5c382b942989 100644
--- a/src/share/classes/sun/security/provider/certpath/OCSPRequest.java
+++ b/src/share/classes/sun/security/provider/certpath/OCSPRequest.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2003, 2013, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2003, 2017, 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
@@ -32,10 +32,11 @@ import java.util.List;
import sun.misc.HexDumpEncoder;
import sun.security.util.*;
+import sun.security.x509.PKIXExtensions;
/**
* This class can be used to generate an OCSP request and send it over
- * an outputstream. Currently we do not support signing requests
+ * an output stream. Currently we do not support signing requests.
* The OCSP Request is specified in RFC 2560 and
* the ASN.1 definition is as follows:
*
@@ -118,7 +119,8 @@ class OCSPRequest {
DerOutputStream extOut = new DerOutputStream();
for (Extension ext : extensions) {
ext.encode(extOut);
- if (ext.getId().equals(OCSP.NONCE_EXTENSION_OID.toString())) {
+ if (ext.getId().equals(
+ PKIXExtensions.OCSPNonce_Id.toString())) {
nonce = ext.getValue();
}
}
diff --git a/src/share/classes/sun/security/provider/certpath/OCSPResponse.java b/src/share/classes/sun/security/provider/certpath/OCSPResponse.java
index 47755e7fb67399a17a798b2684c82c16f4f88c6d..f2c23b991b7ecfa1c24758b4f23ef6fd6e62ce8a 100644
--- a/src/share/classes/sun/security/provider/certpath/OCSPResponse.java
+++ b/src/share/classes/sun/security/provider/certpath/OCSPResponse.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2003, 2015, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2003, 2017, 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
@@ -41,6 +41,7 @@ import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
+import java.util.Set;
import javax.security.auth.x500.X500Principal;
import sun.misc.HexDumpEncoder;
@@ -129,7 +130,7 @@ public final class OCSPResponse {
SIG_REQUIRED, // Must sign the request
UNAUTHORIZED // Request unauthorized
};
- private static ResponseStatus[] rsvalues = ResponseStatus.values();
+ private static final ResponseStatus[] rsvalues = ResponseStatus.values();
private static final Debug debug = Debug.getInstance("certpath");
private static final boolean dump = debug != null && Debug.isOn("ocsp");
@@ -173,7 +174,7 @@ public final class OCSPResponse {
}
// an array of all of the CRLReasons (used in SingleResponse)
- private static CRLReason[] values = CRLReason.values();
+ private static final CRLReason[] values = CRLReason.values();
private final ResponseStatus responseStatus;
private final Map singleResponseMap;
@@ -183,13 +184,16 @@ public final class OCSPResponse {
private final byte[] responseNonce;
private List certs;
private X509CertImpl signerCert = null;
- private X500Principal responderName = null;
- private KeyIdentifier responderKeyId = null;
+ private final ResponderId respId;
+ private Date producedAtDate = null;
+ private final Map responseExtensions;
/*
* Create an OCSP response from its ASN.1 DER encoding.
+ *
+ * @param bytes The DER-encoded bytes for an OCSP response
*/
- OCSPResponse(byte[] bytes) throws IOException {
+ public OCSPResponse(byte[] bytes) throws IOException {
if (dump) {
HexDumpEncoder hexEnc = new HexDumpEncoder();
debug.println("OCSPResponse bytes...\n\n" +
@@ -221,6 +225,8 @@ public final class OCSPResponse {
signature = null;
tbsResponseData = null;
responseNonce = null;
+ responseExtensions = Collections.emptyMap();
+ respId = null;
return;
}
@@ -289,27 +295,15 @@ public final class OCSPResponse {
}
// responderID
- short tag = (byte)(seq.tag & 0x1f);
- if (tag == NAME_TAG) {
- responderName = new X500Principal(seq.getData().toByteArray());
- if (debug != null) {
- debug.println("Responder's name: " + responderName);
- }
- } else if (tag == KEY_TAG) {
- responderKeyId = new KeyIdentifier(seq.getData().getOctetString());
- if (debug != null) {
- debug.println("Responder's key ID: " +
- Debug.toString(responderKeyId.getIdentifier()));
- }
- } else {
- throw new IOException("Bad encoding in responderID element of " +
- "OCSP response: expected ASN.1 context specific tag 0 or 1");
+ respId = new ResponderId(seq.toByteArray());
+ if (debug != null) {
+ debug.println("Responder ID: " + respId);
}
// producedAt
seq = seqDerIn.getDerValue();
+ producedAtDate = seq.getGeneralizedTime();
if (debug != null) {
- Date producedAtDate = seq.getGeneralizedTime();
debug.println("OCSP response produced at: " + producedAtDate);
}
@@ -320,37 +314,29 @@ public final class OCSPResponse {
debug.println("OCSP number of SingleResponses: "
+ singleResponseDer.length);
}
- for (int i = 0; i < singleResponseDer.length; i++) {
- SingleResponse singleResponse =
- new SingleResponse(singleResponseDer[i]);
+ for (DerValue srDer : singleResponseDer) {
+ SingleResponse singleResponse = new SingleResponse(srDer);
singleResponseMap.put(singleResponse.getCertId(), singleResponse);
}
// responseExtensions
- byte[] nonce = null;
+ Map tmpExtMap = new HashMap<>();
if (seqDerIn.available() > 0) {
seq = seqDerIn.getDerValue();
if (seq.isContextSpecific((byte)1)) {
- DerValue[] responseExtDer = seq.data.getSequence(3);
- for (int i = 0; i < responseExtDer.length; i++) {
- Extension ext = new Extension(responseExtDer[i]);
- if (debug != null) {
- debug.println("OCSP extension: " + ext);
- }
- // Only the NONCE extension is recognized
- if (ext.getExtensionId().equals((Object)
- OCSP.NONCE_EXTENSION_OID))
- {
- nonce = ext.getExtensionValue();
- } else if (ext.isCritical()) {
- throw new IOException(
- "Unsupported OCSP critical extension: " +
- ext.getExtensionId());
- }
- }
+ tmpExtMap = parseExtensions(seq);
}
}
- responseNonce = nonce;
+ responseExtensions = tmpExtMap;
+
+ // Attach the nonce value if found in the extension map
+ Extension nonceExt = (Extension)tmpExtMap.get(
+ PKIXExtensions.OCSPNonce_Id.toString());
+ responseNonce = (nonceExt != null) ?
+ nonceExt.getExtensionValue() : null;
+ if (debug != null && responseNonce != null) {
+ debug.println("Response nonce: " + Arrays.toString(responseNonce));
+ }
// signatureAlgorithmId
sigAlgId = AlgorithmId.parse(seqTmp[1]);
@@ -387,8 +373,9 @@ public final class OCSPResponse {
}
}
- void verify(List certIds, X509Certificate issuerCert,
- X509Certificate responderCert, Date date, byte[] nonce)
+ void verify(List certIds, IssuerInfo issuerInfo,
+ X509Certificate responderCert, Date date, byte[] nonce,
+ String variant)
throws CertPathValidatorException
{
switch (responseStatus) {
@@ -428,7 +415,9 @@ public final class OCSPResponse {
// Add the Issuing CA cert and/or Trusted Responder cert to the list
// of certs from the OCSP response
try {
- certs.add(X509CertImpl.toImpl(issuerCert));
+ if (issuerInfo.getCertificate() != null) {
+ certs.add(X509CertImpl.toImpl(issuerInfo.getCertificate()));
+ }
if (responderCert != null) {
certs.add(X509CertImpl.toImpl(responderCert));
}
@@ -437,20 +426,22 @@ public final class OCSPResponse {
"Invalid issuer or trusted responder certificate", ce);
}
- if (responderName != null) {
+ if (respId.getType() == ResponderId.Type.BY_NAME) {
+ X500Principal rName = respId.getResponderName();
for (X509CertImpl cert : certs) {
- if (cert.getSubjectX500Principal().equals(responderName)) {
+ if (cert.getSubjectX500Principal().equals(rName)) {
signerCert = cert;
break;
}
}
- } else if (responderKeyId != null) {
+ } else if (respId.getType() == ResponderId.Type.BY_KEY) {
+ KeyIdentifier ridKeyId = respId.getKeyIdentifier();
for (X509CertImpl cert : certs) {
// Match responder's key identifier against the cert's SKID
// This will match if the SKID is encoded using the 160-bit
// SHA-1 hash method as defined in RFC 5280.
KeyIdentifier certKeyId = cert.getSubjectKeyId();
- if (certKeyId != null && responderKeyId.equals(certKeyId)) {
+ if (certKeyId != null && ridKeyId.equals(certKeyId)) {
signerCert = cert;
break;
} else {
@@ -464,7 +455,7 @@ public final class OCSPResponse {
} catch (IOException e) {
// ignore
}
- if (responderKeyId.equals(certKeyId)) {
+ if (ridKeyId.equals(certKeyId)) {
signerCert = cert;
break;
}
@@ -476,7 +467,10 @@ public final class OCSPResponse {
// Check whether the signer cert returned by the responder is trusted
if (signerCert != null) {
// Check if the response is signed by the issuing CA
- if (signerCert.equals(issuerCert)) {
+ if (signerCert.getSubjectX500Principal().equals(
+ issuerInfo.getName()) &&
+ signerCert.getPublicKey().equals(
+ issuerInfo.getPublicKey())) {
if (debug != null) {
debug.println("OCSP response is signed by the target's " +
"Issuing CA");
@@ -493,7 +487,7 @@ public final class OCSPResponse {
// Check if the response is signed by an authorized responder
} else if (signerCert.getIssuerX500Principal().equals(
- issuerCert.getSubjectX500Principal())) {
+ issuerInfo.getName())) {
// Check for the OCSPSigning key purpose
try {
@@ -513,8 +507,9 @@ public final class OCSPResponse {
// Check algorithm constraints specified in security property
// "jdk.certpath.disabledAlgorithms".
- AlgorithmChecker algChecker = new AlgorithmChecker(
- new TrustAnchor(issuerCert, null));
+ AlgorithmChecker algChecker =
+ new AlgorithmChecker(issuerInfo.getAnchor(), date,
+ variant);
algChecker.init(false);
algChecker.check(signerCert, Collections.emptySet());
@@ -552,7 +547,7 @@ public final class OCSPResponse {
// verify the signature
try {
- signerCert.verify(issuerCert.getPublicKey());
+ signerCert.verify(issuerInfo.getPublicKey());
if (debug != null) {
debug.println("OCSP response is signed by an " +
"Authorized Responder");
@@ -574,7 +569,7 @@ public final class OCSPResponse {
if (signerCert != null) {
// Check algorithm constraints specified in security property
// "jdk.certpath.disabledAlgorithms".
- AlgorithmChecker.check(signerCert.getPublicKey(), sigAlgId);
+ AlgorithmChecker.check(signerCert.getPublicKey(), sigAlgId, variant);
if (!verifySignature(signerCert)) {
throw new CertPathValidatorException(
@@ -593,7 +588,6 @@ public final class OCSPResponse {
}
// Check freshness of OCSPResponse
-
long now = (date == null) ? System.currentTimeMillis() : date.getTime();
Date nowPlusSkew = new Date(now + MAX_CLOCK_SKEW);
Date nowMinusSkew = new Date(now - MAX_CLOCK_SKEW);
@@ -604,16 +598,16 @@ public final class OCSPResponse {
until = " until " + sr.nextUpdate;
}
debug.println("OCSP response validity interval is from " +
- sr.thisUpdate + until);
+ sr.thisUpdate + until);
debug.println("Checking validity of OCSP response on: " +
- new Date(now));
+ new Date(now));
}
// Check that the test date is within the validity interval:
// [ thisUpdate - MAX_CLOCK_SKEW,
// MAX(thisUpdate, nextUpdate) + MAX_CLOCK_SKEW ]
if (nowPlusSkew.before(sr.thisUpdate) ||
- nowMinusSkew.after(
+ nowMinusSkew.after(
sr.nextUpdate != null ? sr.nextUpdate : sr.thisUpdate))
{
throw new CertPathValidatorException(
@@ -625,8 +619,10 @@ public final class OCSPResponse {
/**
* Returns the OCSP ResponseStatus.
+ *
+ * @return the {@code ResponseStatus} for this OCSP response
*/
- ResponseStatus getResponseStatus() {
+ public ResponseStatus getResponseStatus() {
return responseStatus;
}
@@ -664,11 +660,27 @@ public final class OCSPResponse {
/**
* Returns the SingleResponse of the specified CertId, or null if
* there is no response for that CertId.
+ *
+ * @param certId the {@code CertId} for a {@code SingleResponse} to be
+ * searched for in the OCSP response.
+ *
+ * @return the {@code SingleResponse} for the provided {@code CertId},
+ * or {@code null} if it is not found.
*/
- SingleResponse getSingleResponse(CertId certId) {
+ public SingleResponse getSingleResponse(CertId certId) {
return singleResponseMap.get(certId);
}
+ /**
+ * Return a set of all CertIds in this {@code OCSPResponse}
+ *
+ * @return an unmodifiable set containing every {@code CertId} in this
+ * response.
+ */
+ public Set getCertIds() {
+ return Collections.unmodifiableSet(singleResponseMap.keySet());
+ }
+
/*
* Returns the certificate for the authority that signed the OCSP response.
*/
@@ -676,10 +688,86 @@ public final class OCSPResponse {
return signerCert; // set in verify()
}
+ /**
+ * Get the {@code ResponderId} from this {@code OCSPResponse}
+ *
+ * @return the {@code ResponderId} from this response or {@code null}
+ * if no responder ID is in the body of the response (e.g. a
+ * response with a status other than SUCCESS.
+ */
+ public ResponderId getResponderId() {
+ return respId;
+ }
+
+ /**
+ * Provide a String representation of an OCSPResponse
+ *
+ * @return a human-readable representation of the OCSPResponse
+ */
+ @Override
+ public String toString() {
+ StringBuilder sb = new StringBuilder();
+ sb.append("OCSP Response:\n");
+ sb.append("Response Status: ").append(responseStatus).append("\n");
+ sb.append("Responder ID: ").append(respId).append("\n");
+ sb.append("Produced at: ").append(producedAtDate).append("\n");
+ int count = singleResponseMap.size();
+ sb.append(count).append(count == 1 ?
+ " response:\n" : " responses:\n");
+ for (SingleResponse sr : singleResponseMap.values()) {
+ sb.append(sr).append("\n");
+ }
+ if (responseExtensions != null && responseExtensions.size() > 0) {
+ count = responseExtensions.size();
+ sb.append(count).append(count == 1 ?
+ " extension:\n" : " extensions:\n");
+ for (String extId : responseExtensions.keySet()) {
+ sb.append(responseExtensions.get(extId)).append("\n");
+ }
+ }
+
+ return sb.toString();
+ }
+
+ /**
+ * Build a String-Extension map from DER encoded data.
+ * @param derVal A {@code DerValue} object built from a SEQUENCE of
+ * extensions
+ *
+ * @return a {@code Map} using the OID in string form as the keys. If no
+ * extensions are found or an empty SEQUENCE is passed in, then
+ * an empty {@code Map} will be returned.
+ *
+ * @throws IOException if any decoding errors occur.
+ */
+ private static Map
+ parseExtensions(DerValue derVal) throws IOException {
+ DerValue[] extDer = derVal.data.getSequence(3);
+ Map extMap =
+ new HashMap<>(extDer.length);
+
+ for (DerValue extDerVal : extDer) {
+ Extension ext = new Extension(extDerVal);
+ if (debug != null) {
+ debug.println("Extension: " + ext);
+ }
+ // We don't support any extensions yet. Therefore, if it
+ // is critical we must throw an exception because we
+ // don't know how to process it.
+ if (ext.isCritical()) {
+ throw new IOException("Unsupported OCSP critical extension: " +
+ ext.getExtensionId());
+ }
+ extMap.put(ext.getId(), ext);
+ }
+
+ return extMap;
+ }
+
/*
* A class representing a single OCSP response.
*/
- final static class SingleResponse implements OCSP.RevocationStatus {
+ public static final class SingleResponse implements OCSP.RevocationStatus {
private final CertId certId;
private final CertStatus certStatus;
private final Date thisUpdate;
@@ -724,7 +812,7 @@ public final class OCSPResponse {
}
} else {
revocationTime = null;
- revocationReason = CRLReason.UNSPECIFIED;
+ revocationReason = null;
if (tag == CERT_STATUS_GOOD) {
certStatus = CertStatus.GOOD;
} else if (tag == CERT_STATUS_UNKNOWN) {
@@ -735,77 +823,131 @@ public final class OCSPResponse {
}
thisUpdate = tmp.getGeneralizedTime();
+ if (debug != null) {
+ debug.println("thisUpdate: " + thisUpdate);
+ }
- if (tmp.available() == 0) {
- // we are done
- nextUpdate = null;
- } else {
+ // Parse optional fields like nextUpdate and singleExtensions
+ Date tmpNextUpdate = null;
+ Map tmpMap = null;
+
+ // Check for the first optional item, it could be nextUpdate
+ // [CONTEXT 0] or singleExtensions [CONTEXT 1]
+ if (tmp.available() > 0) {
derVal = tmp.getDerValue();
- tag = (byte)(derVal.tag & 0x1f);
- if (tag == 0) {
- // next update
- nextUpdate = derVal.data.getGeneralizedTime();
- if (tmp.available() == 0) {
- // we are done
- } else {
- derVal = tmp.getDerValue();
- tag = (byte)(derVal.tag & 0x1f);
+ // nextUpdate processing
+ if (derVal.isContextSpecific((byte)0)) {
+ tmpNextUpdate = derVal.data.getGeneralizedTime();
+ if (debug != null) {
+ debug.println("nextUpdate: " + tmpNextUpdate);
}
- } else {
- nextUpdate = null;
+
+ // If more data exists in the singleResponse, it
+ // can only be singleExtensions. Get this DER value
+ // for processing in the next block
+ derVal = tmp.available() > 0 ? tmp.getDerValue() : null;
}
- }
- // singleExtensions
- if (tmp.available() > 0) {
- derVal = tmp.getDerValue();
- if (derVal.isContextSpecific((byte)1)) {
- DerValue[] singleExtDer = derVal.data.getSequence(3);
- singleExtensions =
- new HashMap
- (singleExtDer.length);
- for (int i = 0; i < singleExtDer.length; i++) {
- Extension ext = new Extension(singleExtDer[i]);
- if (debug != null) {
- debug.println("OCSP single extension: " + ext);
- }
- // We don't support any extensions yet. Therefore, if it
- // is critical we must throw an exception because we
- // don't know how to process it.
- if (ext.isCritical()) {
- throw new IOException(
- "Unsupported OCSP critical extension: " +
- ext.getExtensionId());
+
+ // singleExtensions processing
+ if (derVal != null) {
+ if (derVal.isContextSpecific((byte)1)) {
+ tmpMap = parseExtensions(derVal);
+
+ // There should not be any other items in the
+ // singleResponse at this point.
+ if (tmp.available() > 0) {
+ throw new IOException(tmp.available() +
+ " bytes of additional data in singleResponse");
}
- singleExtensions.put(ext.getId(), ext);
+ } else {
+ // Unknown item in the singleResponse
+ throw new IOException("Unsupported singleResponse " +
+ "item, tag = " + String.format("%02X", derVal.tag));
}
- } else {
- singleExtensions = Collections.emptyMap();
}
- } else {
- singleExtensions = Collections.emptyMap();
+ }
+
+ nextUpdate = tmpNextUpdate;
+ singleExtensions = (tmpMap != null) ? tmpMap :
+ Collections.emptyMap();
+ if (debug != null) {
+ for (java.security.cert.Extension ext :
+ singleExtensions.values()) {
+ debug.println("singleExtension: " + ext);
+ }
}
}
/*
* Return the certificate's revocation status code
*/
- @Override public CertStatus getCertStatus() {
+ @Override
+ public CertStatus getCertStatus() {
return certStatus;
}
- private CertId getCertId() {
+ /**
+ * Get the Cert ID that this SingleResponse is for.
+ *
+ * @return the {@code CertId} for this {@code SingleResponse}
+ */
+ public CertId getCertId() {
return certId;
}
- @Override public Date getRevocationTime() {
- return (Date) revocationTime.clone();
+ /**
+ * Get the {@code thisUpdate} field from this {@code SingleResponse}.
+ *
+ * @return a {@link Date} object containing the thisUpdate date
+ */
+ public Date getThisUpdate() {
+ return (thisUpdate != null ? (Date) thisUpdate.clone() : null);
}
- @Override public CRLReason getRevocationReason() {
+ /**
+ * Get the {@code nextUpdate} field from this {@code SingleResponse}.
+ *
+ * @return a {@link Date} object containing the nexUpdate date or
+ * {@code null} if a nextUpdate field is not present in the response.
+ */
+ public Date getNextUpdate() {
+ return (nextUpdate != null ? (Date) nextUpdate.clone() : null);
+ }
+
+ /**
+ * Get the {@code revocationTime} field from this
+ * {@code SingleResponse}.
+ *
+ * @return a {@link Date} object containing the revocationTime date or
+ * {@code null} if the {@code SingleResponse} does not have a status
+ * of {@code REVOKED}.
+ */
+ @Override
+ public Date getRevocationTime() {
+ return (revocationTime != null ? (Date) revocationTime.clone() :
+ null);
+ }
+
+ /**
+ * Get the {@code revocationReason} field for the
+ * {@code SingleResponse}.
+ *
+ * @return a {@link CRLReason} containing the revocation reason, or
+ * {@code null} if a revocation reason was not provided or the
+ * response status is not {@code REVOKED}.
+ */
+ @Override
+ public CRLReason getRevocationReason() {
return revocationReason;
}
+ /**
+ * Get the {@code singleExtensions} for this {@code SingleResponse}.
+ *
+ * @return a {@link Map} of {@link Extension} objects, keyed by
+ * their OID value in string form.
+ */
@Override
public Map getSingleExtensions() {
return Collections.unmodifiableMap(singleExtensions);
@@ -816,17 +958,116 @@ public final class OCSPResponse {
*/
@Override public String toString() {
StringBuilder sb = new StringBuilder();
- sb.append("SingleResponse: \n");
+ sb.append("SingleResponse:\n");
sb.append(certId);
- sb.append("\nCertStatus: "+ certStatus + "\n");
+ sb.append("\nCertStatus: ").append(certStatus).append("\n");
if (certStatus == CertStatus.REVOKED) {
- sb.append("revocationTime is " + revocationTime + "\n");
- sb.append("revocationReason is " + revocationReason + "\n");
+ sb.append("revocationTime is ");
+ sb.append(revocationTime).append("\n");
+ sb.append("revocationReason is ");
+ sb.append(revocationReason).append("\n");
}
- sb.append("thisUpdate is " + thisUpdate + "\n");
+ sb.append("thisUpdate is ").append(thisUpdate).append("\n");
if (nextUpdate != null) {
- sb.append("nextUpdate is " + nextUpdate + "\n");
+ sb.append("nextUpdate is ").append(nextUpdate).append("\n");
+ }
+ for (java.security.cert.Extension ext : singleExtensions.values()) {
+ sb.append("singleExtension: ");
+ sb.append(ext.toString()).append("\n");
+ }
+ return sb.toString();
+ }
+ }
+
+ /**
+ * 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
+ * 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 {
+ private final TrustAnchor anchor;
+ private final X509Certificate certificate;
+ private final X500Principal name;
+ private final PublicKey pubKey;
+
+ IssuerInfo(TrustAnchor anchor) {
+ this(anchor, (anchor != null) ? anchor.getTrustedCert() : null);
+ }
+
+ 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 {
+ name = anchor.getCA();
+ pubKey = anchor.getCAPublicKey();
+ certificate = anchor.getTrustedCert();
}
+ }
+
+ /**
+ * Get the certificate in this IssuerInfo if present.
+ *
+ * @return the {@code X509Certificate} used to create this IssuerInfo
+ * object, or {@code null} if a certificate was not used in its
+ * creation.
+ */
+ X509Certificate getCertificate() {
+ return certificate;
+ }
+
+ /**
+ * Get the name of this issuer.
+ *
+ * @return an {@code X500Principal} corresponding to this issuer's
+ * name. If derived from an issuer's {@code X509Certificate} this
+ * would be equivalent to the certificate subject name.
+ */
+ X500Principal getName() {
+ return name;
+ }
+
+ /**
+ * Get the public key for this issuer.
+ *
+ * @return a {@code PublicKey} for this issuer.
+ */
+ PublicKey getPublicKey() {
+ return pubKey;
+ }
+
+ /**
+ * Get the TrustAnchor for the certificate chain.
+ *
+ * @return a {@code TrustAnchor}.
+ */
+ TrustAnchor getAnchor() {
+ return anchor;
+ }
+
+ /**
+ * Create a string representation of this IssuerInfo.
+ *
+ * @return a {@code String} form of this IssuerInfo object.
+ */
+ @Override
+ public String toString() {
+ StringBuilder sb = new StringBuilder();
+ sb.append("Issuer Info:\n");
+ sb.append("Name: ").append(name.toString()).append("\n");
+ sb.append("Public Key:\n").append(pubKey.toString()).append("\n");
return sb.toString();
}
}
diff --git a/src/share/classes/sun/security/provider/certpath/PKIX.java b/src/share/classes/sun/security/provider/certpath/PKIX.java
index e33d4a21a5c9ff7945ac9f77bcdfcb5678d8a4f9..8a177c04fc12f89e02b9f48fbc48ed164e4b66ce 100644
--- a/src/share/classes/sun/security/provider/certpath/PKIX.java
+++ b/src/share/classes/sun/security/provider/certpath/PKIX.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2012, 2015, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2012, 2017, 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
@@ -26,6 +26,7 @@ package sun.security.provider.certpath;
import java.security.InvalidAlgorithmParameterException;
import java.security.PublicKey;
+import java.security.Timestamp;
import java.security.cert.*;
import java.security.interfaces.DSAPublicKey;
import java.util.*;
@@ -85,6 +86,8 @@ class PKIX {
private CertSelector constraints;
private Set anchors;
private List certs;
+ private Timestamp timestamp;
+ private String variant;
ValidatorParams(CertPath cp, PKIXParameters params)
throws InvalidAlgorithmParameterException
@@ -100,6 +103,11 @@ class PKIX {
ValidatorParams(PKIXParameters params)
throws InvalidAlgorithmParameterException
{
+ if (params instanceof PKIXExtendedParameters) {
+ timestamp = ((PKIXExtendedParameters) params).getTimestamp();
+ variant = ((PKIXExtendedParameters) params).getVariant();
+ }
+
this.anchors = params.getTrustAnchors();
// Make sure that none of the trust anchors include name constraints
// (not supported).
@@ -189,6 +197,14 @@ class PKIX {
PKIXParameters getPKIXParameters() {
return params;
}
+
+ Timestamp timestamp() {
+ return timestamp;
+ }
+
+ String variant() {
+ return variant;
+ }
}
static class BuilderParams extends ValidatorParams {
diff --git a/src/share/classes/sun/security/provider/certpath/PKIXCertPathValidator.java b/src/share/classes/sun/security/provider/certpath/PKIXCertPathValidator.java
index 98816f779e3173665d979165ca1877da8d93b240..53ae439baf3d262b342e437ca0725159d8c9607c 100644
--- a/src/share/classes/sun/security/provider/certpath/PKIXCertPathValidator.java
+++ b/src/share/classes/sun/security/provider/certpath/PKIXCertPathValidator.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2000, 2015, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2000, 2017, 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
@@ -172,7 +172,8 @@ public final class PKIXCertPathValidator extends CertPathValidatorSpi {
List certPathCheckers = new ArrayList<>();
// add standard checkers that we will be using
certPathCheckers.add(untrustedChecker);
- certPathCheckers.add(new AlgorithmChecker(anchor));
+ certPathCheckers.add(new AlgorithmChecker(anchor, null, params.date(),
+ params.timestamp(), params.variant()));
certPathCheckers.add(new KeyChecker(certPathLen,
params.targetCertConstraints()));
certPathCheckers.add(new ConstraintsChecker(certPathLen));
@@ -189,8 +190,11 @@ public final class PKIXCertPathValidator extends CertPathValidatorSpi {
rootNode);
certPathCheckers.add(pc);
// default value for date is current time
- BasicChecker bc = new BasicChecker(anchor, params.date(),
- params.sigProvider(), false);
+ BasicChecker bc;
+ bc = new BasicChecker(anchor,
+ (params.timestamp() == null ? params.date() :
+ params.timestamp().getTimestamp()),
+ params.sigProvider(), false);
certPathCheckers.add(bc);
boolean revCheckerAdded = false;
diff --git a/src/share/classes/sun/security/provider/certpath/PKIXExtendedParameters.java b/src/share/classes/sun/security/provider/certpath/PKIXExtendedParameters.java
new file mode 100644
index 0000000000000000000000000000000000000000..42c2d1f9c4fb7fe2f282b4e2a930342f4cc6f02e
--- /dev/null
+++ b/src/share/classes/sun/security/provider/certpath/PKIXExtendedParameters.java
@@ -0,0 +1,226 @@
+/*
+ * Copyright (c) 2016, 2017, 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
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation. Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+
+package sun.security.provider.certpath;
+
+import java.security.InvalidAlgorithmParameterException;
+import java.security.Timestamp;
+import java.security.cert.CertSelector;
+import java.security.cert.CertStore;
+import java.security.cert.PKIXBuilderParameters;
+import java.security.cert.PKIXCertPathChecker;
+import java.security.cert.TrustAnchor;
+import java.util.Date;
+import java.util.List;
+import java.util.Set;
+
+/**
+ * This class is a wrapper for PKIXBuilderParameters so that a Timestamp object
+ * and a string for the variant type, can be passed when doing certpath
+ * checking.
+ */
+
+public class PKIXExtendedParameters extends PKIXBuilderParameters {
+
+ private final PKIXBuilderParameters p;
+ private Timestamp jarTimestamp;
+ private final String variant;
+
+ public PKIXExtendedParameters(PKIXBuilderParameters params,
+ Timestamp timestamp, String variant)
+ throws InvalidAlgorithmParameterException {
+ super(params.getTrustAnchors(), null);
+ p = params;
+ jarTimestamp = timestamp;
+ this.variant = variant;
+ }
+
+ public Timestamp getTimestamp() {
+ return jarTimestamp;
+ }
+ public void setTimestamp(Timestamp t) {
+ jarTimestamp = t;
+ }
+
+ public String getVariant() {
+ return variant;
+ }
+
+ @Override
+ public void setDate(Date d) {
+ p.setDate(d);
+ }
+
+ @Override
+ public void addCertPathChecker(PKIXCertPathChecker c) {
+ p.addCertPathChecker(c);
+ }
+
+ @Override
+ public void setMaxPathLength(int maxPathLength) {
+ p.setMaxPathLength(maxPathLength);
+ }
+
+ @Override
+ public int getMaxPathLength() {
+ return p.getMaxPathLength();
+ }
+
+ @Override
+ public String toString() {
+ return p.toString();
+ }
+
+ @Override
+ public Set getTrustAnchors() {
+ return p.getTrustAnchors();
+ }
+
+ @Override
+ public void setTrustAnchors(Set trustAnchors)
+ throws InvalidAlgorithmParameterException {
+ // To avoid problems with PKIXBuilderParameter's constructors
+ if (p == null) {
+ return;
+ }
+ p.setTrustAnchors(trustAnchors);
+ }
+
+ @Override
+ public Set getInitialPolicies() {
+ return p.getInitialPolicies();
+ }
+
+ @Override
+ public void setInitialPolicies(Set initialPolicies) {
+ p.setInitialPolicies(initialPolicies);
+ }
+
+ @Override
+ public void setCertStores(List stores) {
+ p.setCertStores(stores);
+ }
+
+ @Override
+ public void addCertStore(CertStore store) {
+ p.addCertStore(store);
+ }
+
+ @Override
+ public List getCertStores() {
+ return p.getCertStores();
+ }
+
+ @Override
+ public void setRevocationEnabled(boolean val) {
+ p.setRevocationEnabled(val);
+ }
+
+ @Override
+ public boolean isRevocationEnabled() {
+ return p.isRevocationEnabled();
+ }
+
+ @Override
+ public void setExplicitPolicyRequired(boolean val) {
+ p.setExplicitPolicyRequired(val);
+ }
+
+ @Override
+ public boolean isExplicitPolicyRequired() {
+ return p.isExplicitPolicyRequired();
+ }
+
+ @Override
+ public void setPolicyMappingInhibited(boolean val) {
+ p.setPolicyMappingInhibited(val);
+ }
+
+ @Override
+ public boolean isPolicyMappingInhibited() {
+ return p.isPolicyMappingInhibited();
+ }
+
+ @Override
+ public void setAnyPolicyInhibited(boolean val) {
+ p.setAnyPolicyInhibited(val);
+ }
+
+ @Override
+ public boolean isAnyPolicyInhibited() {
+ return p.isAnyPolicyInhibited();
+ }
+
+ @Override
+ public void setPolicyQualifiersRejected(boolean qualifiersRejected) {
+ p.setPolicyQualifiersRejected(qualifiersRejected);
+ }
+
+ @Override
+ public boolean getPolicyQualifiersRejected() {
+ return p.getPolicyQualifiersRejected();
+ }
+
+ @Override
+ public Date getDate() {
+ return p.getDate();
+ }
+
+ @Override
+ public void setCertPathCheckers(List checkers) {
+ p.setCertPathCheckers(checkers);
+ }
+
+ @Override
+ public List getCertPathCheckers() {
+ return p.getCertPathCheckers();
+ }
+
+ @Override
+ public String getSigProvider() {
+ return p.getSigProvider();
+ }
+
+ @Override
+ public void setSigProvider(String sigProvider) {
+ p.setSigProvider(sigProvider);
+ }
+
+ @Override
+ public CertSelector getTargetCertConstraints() {
+ return p.getTargetCertConstraints();
+ }
+
+ @Override
+ public void setTargetCertConstraints(CertSelector selector) {
+ // To avoid problems with PKIXBuilderParameter's constructors
+ if (p == null) {
+ return;
+ }
+ p.setTargetCertConstraints(selector);
+ }
+
+}
diff --git a/src/share/classes/sun/security/provider/certpath/ResponderId.java b/src/share/classes/sun/security/provider/certpath/ResponderId.java
new file mode 100644
index 0000000000000000000000000000000000000000..14d3152925f7c607517227e626c10f74c5488af6
--- /dev/null
+++ b/src/share/classes/sun/security/provider/certpath/ResponderId.java
@@ -0,0 +1,315 @@
+/*
+ * Copyright (c) 2015, 2017 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
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation. Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package sun.security.provider.certpath;
+
+import java.util.Arrays;
+import java.io.IOException;
+import java.security.PublicKey;
+import javax.security.auth.x500.X500Principal;
+import sun.security.x509.KeyIdentifier;
+import sun.security.util.DerValue;
+
+/**
+ * Class for ResponderId entities as described in RFC6960. ResponderId objects
+ * are used to uniquely identify OCSP responders.
+ *
+ * The RFC 6960 defines a ResponderID structure as:
+ *
+ * ResponderID ::= CHOICE {
+ * byName [1] Name,
+ * byKey [2] KeyHash }
+ *
+ * KeyHash ::= OCTET STRING -- SHA-1 hash of responder's public key
+ * (excluding the tag and length fields)
+ *
+ * Name is defined in RFC 5280.
+ *
+ *
+ * @see ResponderId.Type
+ * @since 9
+ */
+public final class ResponderId {
+
+ /**
+ * A {@code ResponderId} enumeration describing the accepted forms for a
+ * {@code ResponderId}.
+ *
+ * @see ResponderId
+ * @since 9
+ */
+ public static enum Type {
+ /**
+ * A BY_NAME {@code ResponderId} will be built from a subject name,
+ * either as an {@code X500Principal} or a DER-encoded byte array.
+ */
+ BY_NAME(1, "byName"),
+
+ /**
+ * A BY_KEY {@code ResponderId} will be built from a public key
+ * identifier, either derived from a {@code PublicKey} or directly
+ * from a DER-encoded byte array containing the key identifier.
+ */
+ BY_KEY(2, "byKey");
+
+ private final int tagNumber;
+ private final String ridTypeName;
+
+ private Type(int value, String name) {
+ this.tagNumber = value;
+ this.ridTypeName = name;
+ }
+
+ public int value() {
+ return tagNumber;
+ }
+
+ @Override
+ public String toString() {
+ return ridTypeName;
+ }
+ }
+
+ private Type type;
+ private X500Principal responderName;
+ private KeyIdentifier responderKeyId;
+ private byte[] encodedRid;
+
+ /**
+ * Constructs a {@code ResponderId} object using an {@code X500Principal}.
+ * When encoded in DER this object will use the BY_NAME option.
+ *
+ * @param subjectName the subject name of the certificate used
+ * to sign OCSP responses.
+ *
+ * @throws IOException if the internal DER-encoding of the
+ * {@code X500Principal} fails.
+ */
+ public ResponderId(X500Principal subjectName) throws IOException {
+ responderName = subjectName;
+ responderKeyId = null;
+ encodedRid = principalToBytes();
+ type = Type.BY_NAME;
+ }
+
+ /**
+ * Constructs a {@code ResponderId} object using a {@code PublicKey}.
+ * When encoded in DER this object will use the byKey option, a
+ * SHA-1 hash of the responder's public key.
+ *
+ * @param pubKey the the OCSP responder's public key
+ *
+ * @throws IOException if the internal DER-encoding of the
+ * {@code KeyIdentifier} fails.
+ */
+ public ResponderId(PublicKey pubKey) throws IOException {
+ responderKeyId = new KeyIdentifier(pubKey);
+ responderName = null;
+ encodedRid = keyIdToBytes();
+ type = Type.BY_KEY;
+ }
+
+ /**
+ * Constructs a {@code ResponderId} object from its DER-encoding.
+ *
+ * @param encodedData the DER-encoded bytes
+ *
+ * @throws IOException if the encodedData is not properly DER encoded
+ */
+ public ResponderId(byte[] encodedData) throws IOException {
+ DerValue outer = new DerValue(encodedData);
+
+ if (outer.isContextSpecific((byte)Type.BY_NAME.value())
+ && outer.isConstructed()) {
+ // Use the X500Principal constructor as a way to sanity
+ // check the incoming data.
+ responderName = new X500Principal(outer.getDataBytes());
+ encodedRid = principalToBytes();
+ type = Type.BY_NAME;
+ } else if (outer.isContextSpecific((byte)Type.BY_KEY.value())
+ && outer.isConstructed()) {
+ // Use the KeyIdentifier constructor as a way to sanity
+ // check the incoming data.
+ responderKeyId =
+ new KeyIdentifier(new DerValue(outer.getDataBytes()));
+ encodedRid = keyIdToBytes();
+ type = Type.BY_KEY;
+ } else {
+ throw new IOException("Invalid ResponderId content");
+ }
+ }
+
+ /**
+ * Encode a {@code ResponderId} in DER form
+ *
+ * @return a byte array containing the DER-encoded representation for this
+ * {@code ResponderId}
+ */
+ public byte[] getEncoded() {
+ return encodedRid.clone();
+ }
+
+ /**
+ * Return the type of {@ResponderId}
+ *
+ * @return a number corresponding to the context-specific tag number
+ * used in the DER-encoding for a {@code ResponderId}
+ */
+ public ResponderId.Type getType() {
+ return type;
+ }
+
+ /**
+ * Get the length of the encoded {@code ResponderId} (including the tag and
+ * length of the explicit tagging from the outer ASN.1 CHOICE).
+ *
+ * @return the length of the encoded {@code ResponderId}
+ */
+ public int length() {
+ return encodedRid.length;
+ }
+
+ /**
+ * Obtain the underlying {@code X500Principal} from a {@code ResponderId}
+ *
+ * @return the {@code X500Principal} for this {@code ResponderId} if it
+ * is a BY_NAME variant. If the {@code ResponderId} is a BY_KEY
+ * variant, this routine will return {@code null}.
+ */
+ public X500Principal getResponderName() {
+ return responderName;
+ }
+
+ /**
+ * Obtain the underlying key identifier from a {@code ResponderId}
+ *
+ * @return the {@code KeyIdentifier} for this {@code ResponderId} if it
+ * is a BY_KEY variant. If the {@code ResponderId} is a BY_NAME
+ * variant, this routine will return {@code null}.
+ */
+ public KeyIdentifier getKeyIdentifier() {
+ return responderKeyId;
+ }
+
+ /**
+ * Compares the specified object with this {@code ResponderId} for equality.
+ * A ResponderId will only be considered equivalent if both the type and
+ * data value are equal. Two ResponderIds initialized by name and
+ * key ID, respectively, will not be equal even if the
+ * ResponderId objects are created from the same source certificate.
+ *
+ * @param obj the object to be compared against
+ *
+ * @return true if the specified object is equal to this {@code Responderid}
+ */
+ @Override
+ public boolean equals(Object obj) {
+ if (obj == null) {
+ return false;
+ }
+
+ if (this == obj) {
+ return true;
+ }
+
+ if (obj instanceof ResponderId) {
+ ResponderId respObj = (ResponderId)obj;
+ return Arrays.equals(encodedRid, respObj.getEncoded());
+ }
+
+ return false;
+ }
+
+ /**
+ * Returns the hash code value for this {@code ResponderId}
+ *
+ * @return the hash code value for this {@code ResponderId}
+ */
+ @Override
+ public int hashCode() {
+ return Arrays.hashCode(encodedRid);
+ }
+
+ /**
+ * Create a String representation of this {@code ResponderId}
+ *
+ * @return a String representation of this {@code ResponderId}
+ */
+ @Override
+ public String toString() {
+ StringBuilder sb = new StringBuilder();
+ switch (type) {
+ case BY_NAME:
+ sb.append(type).append(": ").append(responderName);
+ break;
+ case BY_KEY:
+ sb.append(type).append(": ");
+ for (byte keyIdByte : responderKeyId.getIdentifier()) {
+ sb.append(String.format("%02X", keyIdByte));
+ }
+ break;
+ default:
+ sb.append("Unknown ResponderId Type: ").append(type);
+ }
+ return sb.toString();
+ }
+
+ /**
+ * Convert the responderName data member into its DER-encoded form
+ *
+ * @return the DER encoding for a responder ID byName option, including
+ * explicit context-specific tagging.
+ *
+ * @throws IOException if any encoding error occurs
+ */
+ private byte[] principalToBytes() throws IOException {
+ DerValue dv = new DerValue(DerValue.createTag(DerValue.TAG_CONTEXT,
+ true, (byte)Type.BY_NAME.value()),
+ responderName.getEncoded());
+ return dv.toByteArray();
+ }
+
+ /**
+ * Convert the responderKeyId data member into its DER-encoded form
+ *
+ * @return the DER encoding for a responder ID byKey option, including
+ * explicit context-specific tagging.
+ *
+ * @throws IOException if any encoding error occurs
+ */
+ private byte[] keyIdToBytes() throws IOException {
+ // Place the KeyIdentifier bytes into an OCTET STRING
+ DerValue inner = new DerValue(DerValue.tag_OctetString,
+ responderKeyId.getIdentifier());
+
+ // Mark the OCTET STRING-wrapped KeyIdentifier bytes
+ // as EXPLICIT CONTEXT 2
+ DerValue outer = new DerValue(DerValue.createTag(DerValue.TAG_CONTEXT,
+ true, (byte)Type.BY_KEY.value()), inner.toByteArray());
+
+ return outer.toByteArray();
+ }
+
+}
diff --git a/src/share/classes/sun/security/provider/certpath/RevocationChecker.java b/src/share/classes/sun/security/provider/certpath/RevocationChecker.java
index 7445ade98260d37a2e37d3eddf26125dfc4b3903..a67969047754b070a6dc9adc911bedf3c02a0bc2 100644
--- a/src/share/classes/sun/security/provider/certpath/RevocationChecker.java
+++ b/src/share/classes/sun/security/provider/certpath/RevocationChecker.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2012, 2015, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2012, 2017, 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
@@ -43,7 +43,6 @@ import javax.security.auth.x500.X500Principal;
import static sun.security.provider.certpath.OCSP.*;
import static sun.security.provider.certpath.PKIX.*;
-import sun.security.action.GetPropertyAction;
import sun.security.x509.*;
import static sun.security.x509.PKIXExtensions.*;
import sun.security.util.Debug;
@@ -62,12 +61,12 @@ class RevocationChecker extends PKIXRevocationChecker {
private List certStores;
private Map ocspResponses;
private List ocspExtensions;
- private boolean legacy;
+ private final boolean legacy;
private LinkedList softFailExceptions =
new LinkedList<>();
// state variables
- private X509Certificate issuerCert;
+ private OCSPResponse.IssuerInfo issuerInfo;
private PublicKey prevPubKey;
private boolean crlSignFlag;
private int certIndex;
@@ -302,9 +301,9 @@ class RevocationChecker extends PKIXRevocationChecker {
CertPathValidatorException("forward checking not supported");
}
if (anchor != null) {
- issuerCert = anchor.getTrustedCert();
- prevPubKey = (issuerCert != null) ? issuerCert.getPublicKey()
- : anchor.getCAPublicKey();
+ issuerInfo = new OCSPResponse.IssuerInfo(anchor);
+ prevPubKey = issuerInfo.getPublicKey();
+
}
crlSignFlag = true;
if (params != null && params.certPath() != null) {
@@ -438,7 +437,7 @@ class RevocationChecker extends PKIXRevocationChecker {
private void updateState(X509Certificate cert)
throws CertPathValidatorException
{
- issuerCert = cert;
+ issuerInfo = new OCSPResponse.IssuerInfo(anchor, cert);
// Make new public key if parameters are missing
PublicKey pubKey = cert.getPublicKey();
@@ -466,6 +465,34 @@ class RevocationChecker extends PKIXRevocationChecker {
stackedCerts, params.trustAnchors());
}
+ static boolean isCausedByNetworkIssue(String type, CertStoreException cse) {
+ boolean result;
+ Throwable t = cse.getCause();
+
+ switch (type) {
+ case "LDAP":
+ if (t != null) {
+ // These two exception classes are inside java.naming module
+ String cn = t.getClass().getName();
+ result = (cn.equals("javax.naming.ServiceUnavailableException") ||
+ cn.equals("javax.naming.CommunicationException"));
+ } else {
+ result = false;
+ }
+ break;
+ case "SSLServer":
+ result = (t != null && t instanceof IOException);
+ break;
+ case "URI":
+ result = (t != null && t instanceof IOException);
+ break;
+ default:
+ // we don't know about any other remote CertStore types
+ return false;
+ }
+ return result;
+ }
+
private void checkCRLs(X509Certificate cert, PublicKey prevKey,
X509Certificate prevCert, boolean signFlag,
boolean allowSeparateKey,
@@ -478,9 +505,9 @@ class RevocationChecker extends PKIXRevocationChecker {
" ---checking revocation status ...");
}
- // reject circular dependencies - RFC 3280 is not explicit on how
- // to handle this, so we feel it is safest to reject them until
- // the issue is resolved in the PKIX WG.
+ // Reject circular dependencies - RFC 5280 is not explicit on how
+ // to handle this, but does suggest that they can be a security
+ // risk and can create unresolvable dependencies
if (stackedCerts != null && stackedCerts.contains(cert)) {
if (debug != null) {
debug.println("RevocationChecker.checkCRLs()" +
@@ -510,7 +537,7 @@ class RevocationChecker extends PKIXRevocationChecker {
"CertStoreException: " + e.getMessage());
}
if (networkFailureException == null &&
- CertStoreHelper.isCausedByNetworkIssue(store.getType(),e)) {
+ isCausedByNetworkIssue(store.getType(),e)) {
// save this exception, we may need to throw it later
networkFailureException = new CertPathValidatorException(
"Unable to determine revocation status due to " +
@@ -550,15 +577,14 @@ class RevocationChecker extends PKIXRevocationChecker {
try {
if (crlDP) {
approvedCRLs.addAll(DistributionPointFetcher.getCRLs(
- sel, signFlag, prevKey, prevCert,
- params.sigProvider(), certStores,
- reasonsMask, anchors, null));
+ sel, signFlag, prevKey, prevCert,
+ params.sigProvider(), certStores, reasonsMask,
+ anchors, null, params.variant()));
}
} catch (CertStoreException e) {
if (e instanceof CertStoreTypeException) {
CertStoreTypeException cste = (CertStoreTypeException)e;
- if (CertStoreHelper.isCausedByNetworkIssue(cste.getType(),
- e)) {
+ if (isCausedByNetworkIssue(cste.getType(), e)) {
throw new CertPathValidatorException(
"Unable to determine revocation status due to " +
"network error", e, null, -1,
@@ -634,7 +660,7 @@ class RevocationChecker extends PKIXRevocationChecker {
/*
* Abort CRL validation and throw exception if there are any
* unrecognized critical CRL entry extensions (see section
- * 5.3 of RFC 3280).
+ * 5.3 of RFC 5280).
*/
Set unresCritExts = entry.getCriticalExtensionOIDs();
if (unresCritExts != null && !unresCritExts.isEmpty()) {
@@ -682,14 +708,8 @@ class RevocationChecker extends PKIXRevocationChecker {
OCSPResponse response = null;
CertId certId = null;
try {
- if (issuerCert != null) {
- certId = new CertId(issuerCert,
- currCert.getSerialNumberObject());
- } else {
- // must be an anchor name and key
- certId = new CertId(anchor.getCA(), anchor.getCAPublicKey(),
- currCert.getSerialNumberObject());
- }
+ certId = new CertId(issuerInfo.getName(), issuerInfo.getPublicKey(),
+ currCert.getSerialNumberObject());
// check if there is a cached OCSP response available
byte[] responseBytes = ocspResponses.get(cert);
@@ -706,8 +726,8 @@ class RevocationChecker extends PKIXRevocationChecker {
nonce = ext.getValue();
}
}
- response.verify(Collections.singletonList(certId), issuerCert,
- responderCert, params.date(), nonce);
+ response.verify(Collections.singletonList(certId), issuerInfo,
+ responderCert, params.date(), nonce, params.variant());
} else {
URI responderURI = (this.responderURI != null)
@@ -720,8 +740,8 @@ class RevocationChecker extends PKIXRevocationChecker {
}
response = OCSP.check(Collections.singletonList(certId),
- responderURI, issuerCert, responderCert,
- null, ocspExtensions);
+ responderURI, issuerInfo, responderCert, null,
+ ocspExtensions, params.variant());
}
} catch (IOException e) {
throw new CertPathValidatorException(
@@ -833,7 +853,7 @@ class RevocationChecker extends PKIXRevocationChecker {
if (DistributionPointFetcher.verifyCRL(
certImpl, point, crl, reasonsMask, signFlag,
prevKey, null, params.sigProvider(), anchors,
- certStores, params.date()))
+ certStores, params.date(), params.variant()))
{
results.add(crl);
}
@@ -886,9 +906,9 @@ class RevocationChecker extends PKIXRevocationChecker {
" ---checking " + msg + "...");
}
- // reject circular dependencies - RFC 3280 is not explicit on how
- // to handle this, so we feel it is safest to reject them until
- // the issue is resolved in the PKIX WG.
+ // Reject circular dependencies - RFC 5280 is not explicit on how
+ // to handle this, but does suggest that they can be a security
+ // risk and can create unresolvable dependencies
if ((stackedCerts != null) && stackedCerts.contains(cert)) {
if (debug != null) {
debug.println(
diff --git a/src/share/classes/sun/security/provider/certpath/SunCertPathBuilder.java b/src/share/classes/sun/security/provider/certpath/SunCertPathBuilder.java
index 3e6155cb19bcda7225e0d0b9037ddcd90a249dfc..11d8a0673296a03d8e8f13f03e49d3979a660a89 100644
--- a/src/share/classes/sun/security/provider/certpath/SunCertPathBuilder.java
+++ b/src/share/classes/sun/security/provider/certpath/SunCertPathBuilder.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2000, 2015, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2000, 2017, 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,7 +50,7 @@ import sun.security.util.Debug;
*
If successful, it returns a certification path which has successfully
* satisfied all the constraints and requirements specified in the
* PKIXBuilderParameters object and has been validated according to the PKIX
- * path validation algorithm defined in RFC 3280.
+ * path validation algorithm defined in RFC 5280.
*
*
This implementation uses a depth-first search approach to finding
* certification paths. If it comes to a point in which it cannot find
@@ -343,7 +343,8 @@ public final class SunCertPathBuilder extends CertPathBuilderSpi {
checkers.add(policyChecker);
// add the algorithm checker
- checkers.add(new AlgorithmChecker(builder.trustAnchor));
+ checkers.add(new AlgorithmChecker(builder.trustAnchor,
+ buildParams.date(), null));
BasicChecker basicChecker = null;
if (nextState.keyParamsNeeded()) {
diff --git a/src/share/classes/sun/security/ssl/SSLContextImpl.java b/src/share/classes/sun/security/ssl/SSLContextImpl.java
index c0cab217ce4eaf8fcf1a3c8b240b78cd49dba23b..b471337f5fa3f0c41464afb3f35e7578b84fad81 100644
--- a/src/share/classes/sun/security/ssl/SSLContextImpl.java
+++ b/src/share/classes/sun/security/ssl/SSLContextImpl.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1999, 2015, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1999, 2017, 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
@@ -37,6 +37,7 @@ import javax.net.ssl.*;
import sun.security.provider.certpath.AlgorithmChecker;
import sun.security.action.GetPropertyAction;
+import sun.security.validator.Validator;
public abstract class SSLContextImpl extends SSLContextSpi {
@@ -1040,7 +1041,7 @@ final class AbstractTrustManagerWrapper extends X509ExtendedTrustManager
constraints = new SSLAlgorithmConstraints(sslSocket, true);
}
- checkAlgorithmConstraints(chain, constraints);
+ checkAlgorithmConstraints(chain, constraints, isClient);
}
}
@@ -1082,12 +1083,12 @@ final class AbstractTrustManagerWrapper extends X509ExtendedTrustManager
constraints = new SSLAlgorithmConstraints(engine, true);
}
- checkAlgorithmConstraints(chain, constraints);
+ checkAlgorithmConstraints(chain, constraints, isClient);
}
}
private void checkAlgorithmConstraints(X509Certificate[] chain,
- AlgorithmConstraints constraints) throws CertificateException {
+ AlgorithmConstraints constraints, boolean isClient) throws CertificateException {
try {
// Does the certificate chain end with a trusted certificate?
@@ -1105,7 +1106,9 @@ final class AbstractTrustManagerWrapper extends X509ExtendedTrustManager
// A forward checker, need to check from trust to target
if (checkedLength >= 0) {
- AlgorithmChecker checker = new AlgorithmChecker(constraints);
+ AlgorithmChecker checker =
+ new AlgorithmChecker(constraints, null,
+ (isClient ? Validator.VAR_TLS_CLIENT : Validator.VAR_TLS_SERVER));
checker.init(false);
for (int i = checkedLength; i >= 0; i--) {
Certificate cert = chain[i];
diff --git a/src/share/classes/sun/security/ssl/X509KeyManagerImpl.java b/src/share/classes/sun/security/ssl/X509KeyManagerImpl.java
index b6a5034cad8bb335e2a881e5f7929e78dd68610a..c5c16c46638fe86b249c027d46e2d682cca2e3af 100644
--- a/src/share/classes/sun/security/ssl/X509KeyManagerImpl.java
+++ b/src/share/classes/sun/security/ssl/X509KeyManagerImpl.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2004, 2013, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2004, 2017, 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
@@ -39,6 +39,7 @@ import java.security.cert.Certificate;
import javax.net.ssl.*;
import sun.security.provider.certpath.AlgorithmChecker;
+import sun.security.validator.Validator;
/**
* The new X509 key manager implementation. The main differences to the
@@ -62,7 +63,7 @@ final class X509KeyManagerImpl extends X509ExtendedKeyManager
private static final Debug debug = Debug.getInstance("ssl");
- private final static boolean useDebug =
+ private static final boolean useDebug =
(debug != null) && Debug.isOn("keymanager");
// for unit testing only, set via privileged reflection
@@ -661,6 +662,15 @@ final class X509KeyManagerImpl extends X509ExtendedKeyManager
return CheckResult.OK;
}
+
+ public String getValidator() {
+ if (this == CLIENT) {
+ return Validator.VAR_TLS_CLIENT;
+ } else if (this == SERVER) {
+ return Validator.VAR_TLS_SERVER;
+ }
+ return Validator.VAR_GENERIC;
+ }
}
// enum for the result of the extension check
@@ -774,7 +784,8 @@ final class X509KeyManagerImpl extends X509ExtendedKeyManager
// check the algorithm constraints
if (constraints != null &&
- !conformsToAlgorithmConstraints(constraints, chain)) {
+ !conformsToAlgorithmConstraints(constraints, chain,
+ checkType.getValidator())) {
if (useDebug) {
debug.println("Ignoring alias " + alias +
@@ -811,13 +822,19 @@ final class X509KeyManagerImpl extends X509ExtendedKeyManager
}
private static boolean conformsToAlgorithmConstraints(
- AlgorithmConstraints constraints, Certificate[] chain) {
+ AlgorithmConstraints constraints, Certificate[] chain,
+ String variant) {
- AlgorithmChecker checker = new AlgorithmChecker(constraints);
+ AlgorithmChecker checker = new AlgorithmChecker(constraints, null, variant);
try {
checker.init(false);
} catch (CertPathValidatorException cpve) {
// unlikely to happen
+ if (useDebug) {
+ debug.println(
+ "Cannot initialize algorithm constraints checker: " + cpve);
+ }
+
return false;
}
@@ -828,6 +845,11 @@ final class X509KeyManagerImpl extends X509ExtendedKeyManager
// We don't care about the unresolved critical extensions.
checker.check(cert, Collections.emptySet());
} catch (CertPathValidatorException cpve) {
+ if (useDebug) {
+ debug.println("Certificate (" + cert +
+ ") does not conform to algorithm constraints: " + cpve);
+ }
+
return false;
}
}
diff --git a/src/share/classes/sun/security/util/AnchorCertificates.java b/src/share/classes/sun/security/util/AnchorCertificates.java
index 849834278025d6f76271c8a2333328fef0cbf415..e260dd44ac047ad641f6da509b49100f5cabaac7 100644
--- a/src/share/classes/sun/security/util/AnchorCertificates.java
+++ b/src/share/classes/sun/security/util/AnchorCertificates.java
@@ -31,8 +31,10 @@ import java.security.AccessController;
import java.security.KeyStore;
import java.security.PrivilegedAction;
import java.security.cert.X509Certificate;
+import java.util.Collections;
import java.util.Enumeration;
import java.util.HashSet;
+import java.util.Set;
import sun.security.x509.X509CertImpl;
@@ -44,7 +46,7 @@ public class AnchorCertificates {
private static final Debug debug = Debug.getInstance("certpath");
private static final String HASH = "SHA-256";
- private static HashSet certs;
+ private static Set certs = Collections.emptySet();
static {
AccessController.doPrivileged(new PrivilegedAction() {
diff --git a/src/share/classes/sun/security/util/CertConstraintParameters.java b/src/share/classes/sun/security/util/CertConstraintParameters.java
deleted file mode 100644
index 9f7a938dedecfc49b6ef0149b1d158fe12667abd..0000000000000000000000000000000000000000
--- a/src/share/classes/sun/security/util/CertConstraintParameters.java
+++ /dev/null
@@ -1,59 +0,0 @@
-/*
- * Copyright (c) 2016, 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
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation. Oracle designates this
- * particular file as subject to the "Classpath" exception as provided
- * by Oracle in the LICENSE file that accompanied this code.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-
-package sun.security.util;
-
-import java.security.cert.X509Certificate;
-
-/**
- * This class is a wrapper for keeping state and passing objects between PKIX,
- * AlgorithmChecker, and DisabledAlgorithmConstraints.
- */
-public class CertConstraintParameters {
- // A certificate being passed to check against constraints.
- private final X509Certificate cert;
-
- // This is true if the trust anchor in the certificate chain matches a cert
- // in AnchorCertificates
- private final boolean trustedMatch;
-
- public CertConstraintParameters(X509Certificate c, boolean match) {
- cert = c;
- trustedMatch = match;
- }
-
- public CertConstraintParameters(X509Certificate c) {
- this(c, false);
- }
-
- // Returns if the trust anchor has a match if anchor checking is enabled.
- public boolean isTrustedMatch() {
- return trustedMatch;
- }
-
- public X509Certificate getCertificate() {
- return cert;
- }
-}
diff --git a/src/share/classes/sun/security/util/ConstraintsParameters.java b/src/share/classes/sun/security/util/ConstraintsParameters.java
new file mode 100644
index 0000000000000000000000000000000000000000..8431865455790a3055dd02a20740cc19a2b2aa81
--- /dev/null
+++ b/src/share/classes/sun/security/util/ConstraintsParameters.java
@@ -0,0 +1,135 @@
+/*
+ * Copyright (c) 2016, 2017 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
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation. Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package sun.security.util;
+
+import sun.security.validator.Validator;
+
+import java.security.AlgorithmParameters;
+import java.security.Key;
+import java.security.Timestamp;
+import java.security.cert.X509Certificate;
+import java.util.Date;
+
+/**
+ * This class contains parameters for checking against constraints that extend
+ * past the publicly available parameters in java.security.AlgorithmConstraints.
+
+ * This is currently on passed between between PKIX, AlgorithmChecker,
+ * and DisabledAlgorithmConstraints.
+ */
+public class ConstraintsParameters {
+ /*
+ * The below 3 values are used the same as the permit() methods
+ * published in java.security.AlgorithmConstraints.
+ */
+ // Algorithm string to be checked against constraints
+ private final String algorithm;
+ // AlgorithmParameters to the algorithm being checked
+ private final AlgorithmParameters algParams;
+ // Public Key being checked against constraints
+ private final Key publicKey;
+
+ /*
+ * New values that are checked against constraints that the current public
+ * API does not support.
+ */
+ // A certificate being passed to check against constraints.
+ private final X509Certificate cert;
+ // This is true if the trust anchor in the certificate chain matches a cert
+ // in AnchorCertificates
+ private final boolean trustedMatch;
+ // PKIXParameter date
+ private final Date pkixDate;
+ // Timestamp of the signed JAR file
+ private final Timestamp jarTimestamp;
+ private final String variant;
+
+ public ConstraintsParameters(X509Certificate c, boolean match,
+ Date pkixdate, Timestamp jarTime, String variant) {
+ cert = c;
+ trustedMatch = match;
+ pkixDate = pkixdate;
+ jarTimestamp = jarTime;
+ this.variant = (variant == null ? Validator.VAR_GENERIC : variant);
+ algorithm = null;
+ algParams = null;
+ publicKey = null;
+ }
+
+ public ConstraintsParameters(String algorithm, AlgorithmParameters params,
+ Key key, String variant) {
+ this.algorithm = algorithm;
+ algParams = params;
+ this.publicKey = key;
+ cert = null;
+ trustedMatch = false;
+ pkixDate = null;
+ jarTimestamp = null;
+ this.variant = (variant == null ? Validator.VAR_GENERIC : variant);
+ }
+
+
+ public ConstraintsParameters(X509Certificate c) {
+ this(c, false, null, null,
+ Validator.VAR_GENERIC);
+ }
+
+ public ConstraintsParameters(Timestamp jarTime) {
+ this(null, false, null, jarTime, Validator.VAR_GENERIC);
+ }
+
+ public String getAlgorithm() {
+ return algorithm;
+ }
+
+ public AlgorithmParameters getAlgParams() {
+ return algParams;
+ }
+
+ public Key getPublicKey() {
+ return publicKey;
+ }
+ // Returns if the trust anchor has a match if anchor checking is enabled.
+ public boolean isTrustedMatch() {
+ return trustedMatch;
+ }
+
+ public X509Certificate getCertificate() {
+ return cert;
+ }
+
+ public Date getPKIXParamDate() {
+ return pkixDate;
+ }
+
+ public Timestamp getJARTimestamp() {
+ return jarTimestamp;
+ }
+
+ public String getVariant() {
+ return variant;
+ }
+}
diff --git a/src/share/classes/sun/security/util/DisabledAlgorithmConstraints.java b/src/share/classes/sun/security/util/DisabledAlgorithmConstraints.java
index af1f99b854f3446ea6f170b3e8fa6586567c1423..9051b3929706d739f5c6c3e94ba8af7b0a07edb2 100644
--- a/src/share/classes/sun/security/util/DisabledAlgorithmConstraints.java
+++ b/src/share/classes/sun/security/util/DisabledAlgorithmConstraints.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2010, 2016, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2010, 2017, 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
@@ -25,17 +25,28 @@
package sun.security.util;
+import sun.security.validator.Validator;
+
+import java.io.ByteArrayOutputStream;
+import java.io.PrintStream;
import java.security.CryptoPrimitive;
import java.security.AlgorithmParameters;
import java.security.Key;
import java.security.cert.CertPathValidatorException;
import java.security.cert.CertPathValidatorException.BasicReason;
import java.security.cert.X509Certificate;
+import java.text.SimpleDateFormat;
+import java.util.ArrayList;
+import java.util.Calendar;
+import java.util.Date;
import java.util.HashMap;
import java.util.HashSet;
+import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.Set;
+import java.util.StringTokenizer;
+import java.util.TimeZone;
import java.util.regex.Pattern;
import java.util.regex.Matcher;
@@ -49,11 +60,11 @@ public class DisabledAlgorithmConstraints extends AbstractAlgorithmConstraints {
private static final Debug debug = Debug.getInstance("certpath");
// the known security property, jdk.certpath.disabledAlgorithms
- public final static String PROPERTY_CERTPATH_DISABLED_ALGS =
+ public static final String PROPERTY_CERTPATH_DISABLED_ALGS =
"jdk.certpath.disabledAlgorithms";
// the known security property, jdk.tls.disabledAlgorithms
- public final static String PROPERTY_TLS_DISABLED_ALGS =
+ public static final String PROPERTY_TLS_DISABLED_ALGS =
"jdk.tls.disabledAlgorithms";
// the known security property, jdk.jar.disabledAlgorithms
@@ -93,14 +104,8 @@ public class DisabledAlgorithmConstraints extends AbstractAlgorithmConstraints {
* there are keysize or other limit, this method allow the algorithm.
*/
@Override
- final public boolean permits(Set primitives,
+ public final boolean permits(Set primitives,
String algorithm, AlgorithmParameters parameters) {
-
- if (primitives == null || primitives.isEmpty()) {
- throw new IllegalArgumentException(
- "No cryptographic primitive specified");
- }
-
return checkAlgorithm(disabledAlgorithms, algorithm, decomposer);
}
@@ -109,7 +114,7 @@ public class DisabledAlgorithmConstraints extends AbstractAlgorithmConstraints {
* placed on the key.
*/
@Override
- final public boolean permits(Set primitives, Key key) {
+ public final boolean permits(Set primitives, Key key) {
return checkConstraints(primitives, "", key, null);
}
@@ -118,7 +123,7 @@ public class DisabledAlgorithmConstraints extends AbstractAlgorithmConstraints {
* been placed on the key.
*/
@Override
- final public boolean permits(Set primitives,
+ public final boolean permits(Set primitives,
String algorithm, Key key, AlgorithmParameters parameters) {
if (algorithm == null || algorithm.length() == 0) {
@@ -128,6 +133,18 @@ public class DisabledAlgorithmConstraints extends AbstractAlgorithmConstraints {
return checkConstraints(primitives, algorithm, key, parameters);
}
+ public final void permits(ConstraintsParameters cp)
+ throws CertPathValidatorException {
+ permits(cp.getAlgorithm(), cp);
+ }
+
+ public final void permits(String algorithm, Key key,
+ AlgorithmParameters params, String variant)
+ throws CertPathValidatorException {
+ permits(algorithm, new ConstraintsParameters(algorithm, params, key,
+ (variant == null) ? Validator.VAR_GENERIC : variant));
+ }
+
/*
* Check if a x509Certificate object is permitted. Check if all
* algorithms are allowed, certificate constraints, and the
@@ -135,18 +152,10 @@ public class DisabledAlgorithmConstraints extends AbstractAlgorithmConstraints {
*
* Uses new style permit() which throws exceptions.
*/
- public final void permits(Set primitives,
- CertConstraintParameters cp) throws CertPathValidatorException {
- checkConstraints(primitives, cp);
- }
- /*
- * Check if Certificate object is within the constraints.
- * Uses new style permit() which throws exceptions.
- */
- public final void permits(Set primitives,
- X509Certificate cert) throws CertPathValidatorException {
- checkConstraints(primitives, new CertConstraintParameters(cert));
+ public final void permits(String algorithm, ConstraintsParameters cp)
+ throws CertPathValidatorException {
+ algorithmConstraints.permits(algorithm, cp);
}
// Check if a string is contained inside the property
@@ -169,7 +178,7 @@ public class DisabledAlgorithmConstraints extends AbstractAlgorithmConstraints {
throw new IllegalArgumentException("The key cannot be null");
}
- // check the signature algorithm
+ // check the signature algorithm with parameters
if (algorithm != null && algorithm.length() != 0) {
if (!permits(primitives, algorithm, parameters)) {
return false;
@@ -185,36 +194,6 @@ public class DisabledAlgorithmConstraints extends AbstractAlgorithmConstraints {
return algorithmConstraints.permits(key);
}
- /*
- * Check algorithm constraints with Certificate
- * Uses new style permit() which throws exceptions.
- */
- private void checkConstraints(Set primitives,
- CertConstraintParameters cp) throws CertPathValidatorException {
-
- X509Certificate cert = cp.getCertificate();
- String algorithm = cert.getSigAlgName();
-
- // Check signature algorithm is not disabled
- if (!permits(primitives, algorithm, null)) {
- throw new CertPathValidatorException(
- "Algorithm constraints check failed on disabled "+
- "signature algorithm: " + algorithm,
- null, null, -1, BasicReason.ALGORITHM_CONSTRAINED);
- }
-
- // Check key algorithm is not disabled
- if (!permits(primitives, cert.getPublicKey().getAlgorithm(), null)) {
- throw new CertPathValidatorException(
- "Algorithm constraints check failed on disabled "+
- "public key algorithm: " + algorithm,
- null, null, -1, BasicReason.ALGORITHM_CONSTRAINED);
- }
-
- // Check the certificate and key constraints
- algorithmConstraints.permits(cp);
-
- }
/**
* Key and Certificate Constraints
@@ -229,15 +208,18 @@ public class DisabledAlgorithmConstraints extends AbstractAlgorithmConstraints {
* 'true' means the operation is allowed.
* 'false' means it failed the constraints and is disallowed.
*
- * When passing CertConstraintParameters through permit(), an exception
+ * When passing ConstraintsParameters through permit(), an exception
* will be thrown on a failure to better identify why the operation was
* disallowed.
*/
private static class Constraints {
- private Map> constraintsMap = new HashMap<>();
- private static final Pattern keySizePattern = Pattern.compile(
- "keySize\\s*(<=|<|==|!=|>|>=)\\s*(\\d+)");
+ private Map> constraintsMap = new HashMap<>();
+
+ private static class Holder {
+ private static final Pattern DENY_AFTER_PATTERN = Pattern.compile(
+ "denyAfter\\s+(\\d{4})-(\\d{2})-(\\d{2})");
+ }
public Constraints(String[] constraintArray) {
for (String constraintEntry : constraintArray) {
@@ -252,39 +234,47 @@ public class DisabledAlgorithmConstraints extends AbstractAlgorithmConstraints {
// Check if constraint is a complete disabling of an
// algorithm or has conditions.
- String algorithm;
- String policy;
int space = constraintEntry.indexOf(' ');
- if (space > 0) {
- algorithm = AlgorithmDecomposer.hashName(
- constraintEntry.substring(0, space).
- toUpperCase(Locale.ENGLISH));
- policy = constraintEntry.substring(space + 1);
- } else {
- constraintsMap.putIfAbsent(
- constraintEntry.toUpperCase(Locale.ENGLISH),
- new HashSet<>());
+ String algorithm = AlgorithmDecomposer.hashName(
+ ((space > 0 ? constraintEntry.substring(0, space) :
+ constraintEntry).
+ toUpperCase(Locale.ENGLISH)));
+ List constraintList =
+ constraintsMap.getOrDefault(algorithm,
+ new ArrayList<>(1));
+ constraintsMap.putIfAbsent(algorithm, constraintList);
+ if (space <= 0) {
+ constraintList.add(new DisabledConstraint(algorithm));
continue;
}
+ String policy = constraintEntry.substring(space + 1);
+
// Convert constraint conditions into Constraint classes
- Constraint c = null;
- Constraint lastConstraint = null;
+ Constraint c, lastConstraint = null;
// Allow only one jdkCA entry per constraint entry
boolean jdkCALimit = false;
+ // Allow only one denyAfter entry per constraint entry
+ boolean denyAfterLimit = false;
for (String entry : policy.split("&")) {
entry = entry.trim();
- Matcher matcher = keySizePattern.matcher(entry);
- if (matcher.matches()) {
+ Matcher matcher;
+ if (entry.startsWith("keySize")) {
if (debug != null) {
debug.println("Constraints set to keySize: " +
entry);
}
+ StringTokenizer tokens = new StringTokenizer(entry);
+ if (!"keySize".equals(tokens.nextToken())) {
+ throw new IllegalArgumentException("Error in " +
+ "security property. Constraint unknown: " +
+ entry);
+ }
c = new KeySizeConstraint(algorithm,
- KeySizeConstraint.Operator.of(matcher.group(1)),
- Integer.parseInt(matcher.group(2)));
+ KeySizeConstraint.Operator.of(tokens.nextToken()),
+ Integer.parseInt(tokens.nextToken()));
} else if (entry.equalsIgnoreCase("jdkCA")) {
if (debug != null) {
@@ -297,18 +287,39 @@ public class DisabledAlgorithmConstraints extends AbstractAlgorithmConstraints {
}
c = new jdkCAConstraint(algorithm);
jdkCALimit = true;
+
+ } else if (entry.startsWith("denyAfter") &&
+ (matcher = Holder.DENY_AFTER_PATTERN.matcher(entry))
+ .matches()) {
+ if (debug != null) {
+ debug.println("Constraints set to denyAfter");
+ }
+ if (denyAfterLimit) {
+ throw new IllegalArgumentException("Only one " +
+ "denyAfter entry allowed in property. " +
+ "Constraint: " + constraintEntry);
+ }
+ int year = Integer.parseInt(matcher.group(1));
+ int month = Integer.parseInt(matcher.group(2));
+ int day = Integer.parseInt(matcher.group(3));
+ c = new DenyAfterConstraint(algorithm, year, month,
+ day);
+ denyAfterLimit = true;
+ } else if (entry.startsWith("usage")) {
+ String s[] = (entry.substring(5)).trim().split(" ");
+ c = new UsageConstraint(algorithm, s);
+ if (debug != null) {
+ debug.println("Constraints usage length is " + s.length);
+ }
+ } else {
+ throw new IllegalArgumentException("Error in security" +
+ " property. Constraint unknown: " + entry);
}
// Link multiple conditions for a single constraint
// into a linked list.
if (lastConstraint == null) {
- if (!constraintsMap.containsKey(algorithm)) {
- constraintsMap.putIfAbsent(algorithm,
- new HashSet<>());
- }
- if (c != null) {
- constraintsMap.get(algorithm).add(c);
- }
+ constraintList.add(c);
} else {
lastConstraint.nextConstraint = c;
}
@@ -318,61 +329,73 @@ public class DisabledAlgorithmConstraints extends AbstractAlgorithmConstraints {
}
// Get applicable constraints based off the signature algorithm
- private Set getConstraints(String algorithm) {
+ private List getConstraints(String algorithm) {
return constraintsMap.get(algorithm);
}
// Check if KeySizeConstraints permit the specified key
public boolean permits(Key key) {
- Set set = getConstraints(key.getAlgorithm());
- if (set == null) {
+ List list = getConstraints(key.getAlgorithm());
+ if (list == null) {
return true;
}
- for (Constraint constraint : set) {
+ for (Constraint constraint : list) {
if (!constraint.permits(key)) {
if (debug != null) {
debug.println("keySizeConstraint: failed key " +
"constraint check " + KeyUtil.getKeySize(key));
}
- return false;
- }
+ return false;
+ }
}
- return true;
- }
+ return true;
+ }
// Check if constraints permit this cert.
- public void permits(CertConstraintParameters cp)
+ public void permits(String algorithm, ConstraintsParameters cp)
throws CertPathValidatorException {
X509Certificate cert = cp.getCertificate();
if (debug != null) {
- debug.println("Constraints.permits(): " + cert.getSigAlgName());
+ debug.println("Constraints.permits(): " + algorithm +
+ " Variant: " + cp.getVariant());
}
// Get all signature algorithms to check for constraints
- Set algorithms =
- AlgorithmDecomposer.decomposeOneHash(cert.getSigAlgName());
- if (algorithms == null || algorithms.isEmpty()) {
- return;
- }
-
- // Attempt to add the public key algorithm to the set
- algorithms.add(cert.getPublicKey().getAlgorithm());
+ Set algorithms = new HashSet<>();
+ if (algorithm != null) {
+ algorithms.addAll(AlgorithmDecomposer.decomposeOneHash(algorithm));
+ }
+ // Attempt to add the public key algorithm if cert provided
+ if (cert != null) {
+ algorithms.add(cert.getPublicKey().getAlgorithm());
+ }
+ if (cp.getPublicKey() != null) {
+ algorithms.add(cp.getPublicKey().getAlgorithm());
+ }
// Check all applicable constraints
- for (String algorithm : algorithms) {
- Set set = getConstraints(algorithm);
- if (set == null) {
+ for (String alg : algorithms) {
+ List list = getConstraints(alg);
+ if (list == null) {
continue;
}
- for (Constraint constraint : set) {
+ for (Constraint constraint : list) {
constraint.permits(cp);
}
}
}
- }
+ }
- // Abstract class for algorithm constraint checking
+ /**
+ * This abstract Constraint class for algorithm-based checking
+ * may contain one or more constraints. If the '&' on the {@Security}
+ * property is used, multiple constraints have been grouped together
+ * requiring all the constraints to fail for the check to be disallowed.
+ *
+ * If the class contains multiple constraints, the next constraint
+ * is stored in {@code nextConstraint} in linked-list fashion.
+ */
private abstract static class Constraint {
String algorithm;
Constraint nextConstraint = null;
@@ -408,22 +431,87 @@ public class DisabledAlgorithmConstraints extends AbstractAlgorithmConstraints {
}
/**
- * Check if an algorithm constraint permit this key to be used.
+ * Check if an algorithm constraint is permitted with a given key.
+ *
+ * If the check inside of {@code permit()} fails, it must call
+ * {@code next()} with the same {@code Key} parameter passed if
+ * multiple constraints need to be checked.
+ *
* @param key Public key
- * @return true if constraints do not match
+ * @return 'true' if constraint is allowed, 'false' if disallowed.
*/
public boolean permits(Key key) {
return true;
}
/**
- * Check if an algorithm constraint is permit this certificate to
- * be used.
- * @param cp CertificateParameter containing certificate and state info
- * @return true if constraints do not match
+ * Check if an algorithm constraint is permitted with a given
+ * ConstraintsParameters.
+ *
+ * If the check inside of {@code permits()} fails, it must call
+ * {@code next()} with the same {@code ConstraintsParameters}
+ * parameter passed if multiple constraints need to be checked.
+ *
+ * @param cp CertConstraintParameter containing certificate info
+ * @throws CertPathValidatorException if constraint disallows.
+ *
*/
- public abstract void permits(CertConstraintParameters cp)
+ public abstract void permits(ConstraintsParameters cp)
throws CertPathValidatorException;
+
+ /**
+ * Recursively check if the constraints are allowed.
+ *
+ * If {@code nextConstraint} is non-null, this method will
+ * call {@code nextConstraint}'s {@code permits()} to check if the
+ * constraint is allowed or denied. If the constraint's
+ * {@code permits()} is allowed, this method will exit this and any
+ * recursive next() calls, returning 'true'. If the constraints called
+ * were disallowed, the last constraint will throw
+ * {@code CertPathValidatorException}.
+ *
+ * @param cp ConstraintsParameters
+ * @return 'true' if constraint allows the operation, 'false' if
+ * we are at the end of the constraint list or,
+ * {@code nextConstraint} is null.
+ */
+ boolean next(ConstraintsParameters cp)
+ throws CertPathValidatorException {
+ if (nextConstraint != null) {
+ nextConstraint.permits(cp);
+ return true;
+ }
+ return false;
+ }
+
+ /**
+ * Recursively check if this constraint is allowed,
+ *
+ * If {@code nextConstraint} is non-null, this method will
+ * call {@code nextConstraint}'s {@code permit()} to check if the
+ * constraint is allowed or denied. If the constraint's
+ * {@code permit()} is allowed, this method will exit this and any
+ * recursive next() calls, returning 'true'. If the constraints
+ * called were disallowed the check will exit with 'false'.
+ *
+ * @param key Public key
+ * @return 'true' if constraint allows the operation, 'false' if
+ * the constraint denies the operation.
+ */
+ boolean next(Key key) {
+ if (nextConstraint != null && nextConstraint.permits(key)) {
+ return true;
+ }
+ return false;
+ }
+
+ String extendedMsg(ConstraintsParameters cp) {
+ return (cp.getCertificate() == null ? "." :
+ " used with certificate: " +
+ cp.getCertificate().getSubjectX500Principal() +
+ (cp.getVariant() != Validator.VAR_GENERIC ?
+ ". Usage was " + cp.getVariant() : "."));
+ }
}
/*
@@ -436,30 +524,175 @@ public class DisabledAlgorithmConstraints extends AbstractAlgorithmConstraints {
}
/*
- * Check if each constraint fails and check if there is a linked
- * constraint Any permitted constraint will exit the linked list
- * to allow the operation.
+ * Check if ConstraintsParameters has a trusted match, if it does
+ * call next() for any following constraints. If it does not, exit
+ * as this constraint(s) does not restrict the operation.
*/
- public void permits(CertConstraintParameters cp)
+ public void permits(ConstraintsParameters cp)
throws CertPathValidatorException {
if (debug != null) {
debug.println("jdkCAConstraints.permits(): " + algorithm);
}
- // Return false if the chain has a trust anchor in cacerts
+ // Check chain has a trust anchor in cacerts
if (cp.isTrustedMatch()) {
- if (nextConstraint != null) {
- nextConstraint.permits(cp);
+ if (next(cp)) {
return;
}
throw new CertPathValidatorException(
"Algorithm constraints check failed on certificate " +
- "anchor limits",
+ "anchor limits. " + algorithm + extendedMsg(cp),
null, null, -1, BasicReason.ALGORITHM_CONSTRAINED);
}
}
}
+ /*
+ * This class handles the denyAfter constraint. The date is in the UTC/GMT
+ * timezone.
+ */
+ private static class DenyAfterConstraint extends Constraint {
+ private Date denyAfterDate;
+ private static final SimpleDateFormat dateFormat =
+ new SimpleDateFormat("EEE, MMM d HH:mm:ss z yyyy");
+
+ DenyAfterConstraint(String algo, int year, int month, int day) {
+ Calendar c;
+
+ algorithm = algo;
+
+ if (debug != null) {
+ debug.println("DenyAfterConstraint read in as: year " +
+ year + ", month = " + month + ", day = " + day);
+ }
+
+ c = new Calendar.Builder().setTimeZone(TimeZone.getTimeZone("GMT"))
+ .setDate(year, month - 1, day).build();
+
+ if (year > c.getActualMaximum(Calendar.YEAR) ||
+ year < c.getActualMinimum(Calendar.YEAR)) {
+ throw new IllegalArgumentException(
+ "Invalid year given in constraint: " + year);
+ }
+ if ((month - 1) > c.getActualMaximum(Calendar.MONTH) ||
+ (month - 1) < c.getActualMinimum(Calendar.MONTH)) {
+ throw new IllegalArgumentException(
+ "Invalid month given in constraint: " + month);
+ }
+ if (day > c.getActualMaximum(Calendar.DAY_OF_MONTH) ||
+ day < c.getActualMinimum(Calendar.DAY_OF_MONTH)) {
+ throw new IllegalArgumentException(
+ "Invalid Day of Month given in constraint: " + day);
+ }
+
+ denyAfterDate = c.getTime();
+ if (debug != null) {
+ debug.println("DenyAfterConstraint date set to: " +
+ dateFormat.format(denyAfterDate));
+ }
+ }
+
+ /*
+ * Checking that the provided date is not beyond the constraint date.
+ * The provided date can be the PKIXParameter date if given,
+ * otherwise it is the current date.
+ *
+ * If the constraint disallows, call next() for any following
+ * constraints. Throw an exception if this is the last constraint.
+ */
+ @Override
+ public void permits(ConstraintsParameters cp)
+ throws CertPathValidatorException {
+ Date currentDate;
+ String errmsg;
+
+ if (cp.getJARTimestamp() != null) {
+ currentDate = cp.getJARTimestamp().getTimestamp();
+ errmsg = "JAR Timestamp date: ";
+ } else if (cp.getPKIXParamDate() != null) {
+ currentDate = cp.getPKIXParamDate();
+ errmsg = "PKIXParameter date: ";
+ } else {
+ currentDate = new Date();
+ errmsg = "Current date: ";
+ }
+
+ if (!denyAfterDate.after(currentDate)) {
+ if (next(cp)) {
+ return;
+ }
+ throw new CertPathValidatorException(
+ "denyAfter constraint check failed: " + algorithm +
+ " used with Constraint date: " +
+ dateFormat.format(denyAfterDate) + "; " + errmsg +
+ dateFormat.format(currentDate) + extendedMsg(cp),
+ null, null, -1, BasicReason.ALGORITHM_CONSTRAINED);
+ }
+ }
+
+ /*
+ * Return result if the constraint's date is beyond the current date
+ * in UTC timezone.
+ */
+ public boolean permits(Key key) {
+ if (next(key)) {
+ return true;
+ }
+ if (debug != null) {
+ debug.println("DenyAfterConstraints.permits(): " + algorithm);
+ }
+
+ return denyAfterDate.after(new Date());
+ }
+ }
+
+ /*
+ * The usage constraint is for the "usage" keyword. It checks against the
+ * variant value in ConstraintsParameters.
+ */
+ private static class UsageConstraint extends Constraint {
+ String[] usages;
+
+ UsageConstraint(String algorithm, String[] usages) {
+ this.algorithm = algorithm;
+ this.usages = usages;
+ }
+
+ public void permits(ConstraintsParameters cp)
+ throws CertPathValidatorException {
+ for (String usage : usages) {
+
+ String v = null;
+ if (usage.compareToIgnoreCase("TLSServer") == 0) {
+ v = Validator.VAR_TLS_SERVER;
+ } else if (usage.compareToIgnoreCase("TLSClient") == 0) {
+ v = Validator.VAR_TLS_CLIENT;
+ } else if (usage.compareToIgnoreCase("SignedJAR") == 0) {
+ v = Validator.VAR_PLUGIN_CODE_SIGNING;
+ }
+
+ if (debug != null) {
+ debug.println("Checking if usage constraint \"" + v +
+ "\" matches \"" + cp.getVariant() + "\"");
+ // Because usage checking can come from many places
+ // a stack trace is very helpful.
+ ByteArrayOutputStream ba = new ByteArrayOutputStream();
+ PrintStream ps = new PrintStream(ba);
+ (new Exception()).printStackTrace(ps);
+ debug.println(ba.toString());
+ }
+ if (cp.getVariant().compareTo(v) == 0) {
+ if (next(cp)) {
+ return;
+ }
+ throw new CertPathValidatorException("Usage constraint " +
+ usage + " check failed: " + algorithm +
+ extendedMsg(cp),
+ null, null, -1, BasicReason.ALGORITHM_CONSTRAINED);
+ }
+ }
+ }
+ }
/*
* This class contains constraints dealing with the key size
@@ -470,6 +703,7 @@ public class DisabledAlgorithmConstraints extends AbstractAlgorithmConstraints {
private int minSize; // the minimal available key size
private int maxSize; // the maximal available key size
private int prohibitedSize = -1; // unavailable key sizes
+ private int size;
public KeySizeConstraint(String algo, Operator operator, int length) {
algorithm = algo;
@@ -513,15 +747,22 @@ public class DisabledAlgorithmConstraints extends AbstractAlgorithmConstraints {
* constraint Any permitted constraint will exit the linked list
* to allow the operation.
*/
- public void permits(CertConstraintParameters cp)
+ public void permits(ConstraintsParameters cp)
throws CertPathValidatorException {
- if (!permitsImpl(cp.getCertificate().getPublicKey())) {
+ Key key = null;
+ if (cp.getPublicKey() != null) {
+ key = cp.getPublicKey();
+ } else if (cp.getCertificate() != null) {
+ key = cp.getCertificate().getPublicKey();
+ }
+ if (key != null && !permitsImpl(key)) {
if (nextConstraint != null) {
nextConstraint.permits(cp);
return;
}
throw new CertPathValidatorException(
- "Algorithm constraints check failed on keysize limits",
+ "Algorithm constraints check failed on keysize limits. "
+ + algorithm + " " + size + "bit key" + extendedMsg(cp),
null, null, -1, BasicReason.ALGORITHM_CONSTRAINED);
}
}
@@ -548,7 +789,7 @@ public class DisabledAlgorithmConstraints extends AbstractAlgorithmConstraints {
return true;
}
- int size = KeyUtil.getKeySize(key);
+ size = KeyUtil.getKeySize(key);
if (size == 0) {
return false; // we don't allow any key of size 0.
} else if (size > 0) {
@@ -559,6 +800,27 @@ public class DisabledAlgorithmConstraints extends AbstractAlgorithmConstraints {
return true;
}
+ }
+
+ /*
+ * This constraint is used for the complete disabling of the algorithm.
+ */
+ private static class DisabledConstraint extends Constraint {
+ DisabledConstraint(String algo) {
+ algorithm = algo;
+ }
+
+ public void permits(ConstraintsParameters cp)
+ throws CertPathValidatorException {
+ throw new CertPathValidatorException(
+ "Algorithm constraints check failed on disabled " +
+ "algorithm: " + algorithm + extendedMsg(cp),
+ null, null, -1, BasicReason.ALGORITHM_CONSTRAINED);
+ }
+
+ public boolean permits(Key key) {
+ return false;
}
}
+}
diff --git a/src/share/classes/sun/security/util/SignatureFileVerifier.java b/src/share/classes/sun/security/util/SignatureFileVerifier.java
index ed563dc7b2d6473d9a881ff9beec26610680234c..0663f0573ae35823427a3abbc503151bb292a354 100644
--- a/src/share/classes/sun/security/util/SignatureFileVerifier.java
+++ b/src/share/classes/sun/security/util/SignatureFileVerifier.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1997, 2016, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1997, 2017, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -28,25 +28,23 @@ package sun.security.util;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.security.CodeSigner;
-import java.security.CryptoPrimitive;
+import java.security.GeneralSecurityException;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.security.SignatureException;
+import java.security.Timestamp;
import java.security.cert.CertPath;
import java.security.cert.X509Certificate;
import java.security.cert.CertificateException;
import java.security.cert.CertificateFactory;
import java.util.ArrayList;
import java.util.Base64;
-import java.util.Collections;
-import java.util.EnumSet;
import java.util.HashMap;
import java.util.Hashtable;
import java.util.Iterator;
import java.util.List;
import java.util.Locale;
import java.util.Map;
-import java.util.Set;
import java.util.jar.Attributes;
import java.util.jar.JarException;
import java.util.jar.JarFile;
@@ -61,9 +59,6 @@ public class SignatureFileVerifier {
/* Are we debugging ? */
private static final Debug debug = Debug.getInstance("jar");
- private static final Set DIGEST_PRIMITIVE_SET =
- Collections.unmodifiableSet(EnumSet.of(CryptoPrimitive.MESSAGE_DIGEST));
-
private static final DisabledAlgorithmConstraints JAR_DISABLED_CHECK =
new DisabledAlgorithmConstraints(
DisabledAlgorithmConstraints.PROPERTY_JAR_DISABLED_ALGS);
@@ -78,7 +73,7 @@ public class SignatureFileVerifier {
private PKCS7 block;
/** the raw bytes of the .SF file */
- private byte sfBytes[];
+ private byte[] sfBytes;
/** the name of the signature block file, uppercased and without
* the extension (.DSA/.RSA/.EC)
@@ -97,6 +92,14 @@ public class SignatureFileVerifier {
/* for generating certpath objects */
private CertificateFactory certificateFactory = null;
+ /** Algorithms that have been checked if they are weak. */
+ private Map permittedAlgs= new HashMap<>();
+
+ /** TSA timestamp of signed jar. The newest timestamp is used. If there
+ * was no TSA timestamp used when signed, current time is used ("null").
+ */
+ private Timestamp timestamp = null;
+
/**
* Create the named SignatureFileVerifier.
*
@@ -107,7 +110,7 @@ public class SignatureFileVerifier {
public SignatureFileVerifier(ArrayList signerCache,
ManifestDigester md,
String name,
- byte rawBytes[])
+ byte[] rawBytes)
throws IOException, CertificateException
{
// new PKCS7() calls CertificateFactory.getInstance()
@@ -121,7 +124,7 @@ public class SignatureFileVerifier {
} finally {
Providers.stopJarVerification(obj);
}
- this.name = name.substring(0, name.lastIndexOf("."))
+ this.name = name.substring(0, name.lastIndexOf('.'))
.toUpperCase(Locale.ENGLISH);
this.md = md;
this.signerCache = signerCache;
@@ -152,7 +155,7 @@ public class SignatureFileVerifier {
* used to set the raw bytes of the .SF file when it
* is external to the signature block file.
*/
- public void setSignatureFile(byte sfBytes[])
+ public void setSignatureFile(byte[] sfBytes)
{
this.sfBytes = sfBytes;
}
@@ -168,11 +171,10 @@ public class SignatureFileVerifier {
*/
public static boolean isBlockOrSF(String s) {
// we currently only support DSA and RSA PKCS7 blocks
- if (s.endsWith(".SF") || s.endsWith(".DSA") ||
- s.endsWith(".RSA") || s.endsWith(".EC")) {
- return true;
- }
- return false;
+ return s.endsWith(".SF")
+ || s.endsWith(".DSA")
+ || s.endsWith(".RSA")
+ || s.endsWith(".EC");
}
/**
@@ -182,7 +184,7 @@ public class SignatureFileVerifier {
* unknown signature related files (those starting with SIG- with
* an optional [A-Z0-9]{1,3} extension right inside META-INF).
*
- * @param s file name
+ * @param name file name
* @return true if the input file name is signature related
*/
public static boolean isSigningRelated(String name) {
@@ -198,7 +200,7 @@ public class SignatureFileVerifier {
return true;
} else if (name.startsWith("SIG-")) {
// check filename extension
- // see https://docs.oracle.com/javase/7/docs/technotes/guides/jar/jar.html#Digital_Signatures
+ // see http://docs.oracle.com/javase/7/docs/technotes/guides/jar/jar.html#Digital_Signatures
// for what filename extensions are legal
int extIndex = name.lastIndexOf('.');
if (extIndex != -1) {
@@ -223,17 +225,10 @@ public class SignatureFileVerifier {
/** get digest from cache */
- private MessageDigest getDigest(String algorithm) throws SignatureException {
- // check that algorithm is not restricted
- if (!JAR_DISABLED_CHECK.permits(DIGEST_PRIMITIVE_SET, algorithm, null)) {
- SignatureException e =
- new SignatureException("SignatureFile check failed. " +
- "Disabled algorithm used: " + algorithm);
- throw e;
- }
-
+ private MessageDigest getDigest(String algorithm)
+ throws SignatureException {
if (createdDigests == null)
- createdDigests = new HashMap();
+ createdDigests = new HashMap<>();
MessageDigest digest = createdDigests.get(algorithm);
@@ -303,6 +298,27 @@ public class SignatureFileVerifier {
if (newSigners == null)
return;
+ /*
+ * Look for the latest timestamp in the signature block. If an entry
+ * has no timestamp, use current time (aka null).
+ */
+ for (CodeSigner s: newSigners) {
+ if (debug != null) {
+ debug.println("Gathering timestamp for: " + s.toString());
+ }
+ if (s.getTimestamp() == null) {
+ timestamp = null;
+ break;
+ } else if (timestamp == null) {
+ timestamp = s.getTimestamp();
+ } else {
+ if (timestamp.getTimestamp().before(
+ s.getTimestamp().getTimestamp())) {
+ timestamp = s.getTimestamp();
+ }
+ }
+ }
+
Iterator> entries =
sf.getEntries().entrySet().iterator();
@@ -345,6 +361,68 @@ public class SignatureFileVerifier {
updateSigners(newSigners, signers, JarFile.MANIFEST_NAME);
}
+ /**
+ * Check if algorithm is permitted using the permittedAlgs Map.
+ * If the algorithm is not in the map, check against disabled algorithms and
+ * store the result. If the algorithm is in the map use that result.
+ * False is returned for weak algorithm, true for good algorithms.
+ */
+ boolean permittedCheck(String key, String algorithm) {
+ Boolean permitted = permittedAlgs.get(algorithm);
+ if (permitted == null) {
+ try {
+ JAR_DISABLED_CHECK.permits(algorithm,
+ new ConstraintsParameters(timestamp));
+ } catch(GeneralSecurityException e) {
+ permittedAlgs.put(algorithm, Boolean.FALSE);
+ permittedAlgs.put(key.toUpperCase(), Boolean.FALSE);
+ if (debug != null) {
+ if (e.getMessage() != null) {
+ debug.println(key + ": " + e.getMessage());
+ } else {
+ debug.println(key + ": " + algorithm +
+ " was disabled, no exception msg given.");
+ e.printStackTrace();
+ }
+ }
+ return false;
+ }
+
+ permittedAlgs.put(algorithm, Boolean.TRUE);
+ return true;
+ }
+
+ // Algorithm has already been checked, return the value from map.
+ return permitted.booleanValue();
+ }
+
+ /**
+ * With a given header (*-DIGEST*), return a string that lists all the
+ * algorithms associated with the header.
+ * If there are none, return "Unknown Algorithm".
+ */
+ String getWeakAlgorithms(String header) {
+ String w = "";
+ try {
+ for (String key : permittedAlgs.keySet()) {
+ if (key.endsWith(header)) {
+ w += key.substring(0, key.length() - header.length()) + " ";
+ }
+ }
+ } catch (RuntimeException e) {
+ w = "Unknown Algorithm(s). Error processing " + header + ". " +
+ e.getMessage();
+ }
+
+ // This means we have an error in finding weak algorithms, run in
+ // debug mode to see permittedAlgs map's values.
+ if (w.length() == 0) {
+ return "Unknown Algorithm(s)";
+ }
+
+ return w;
+ }
+
/**
* See if the whole manifest was signed.
*/
@@ -355,6 +433,10 @@ public class SignatureFileVerifier {
{
Attributes mattr = sf.getMainAttributes();
boolean manifestSigned = false;
+ // If only weak algorithms are used.
+ boolean weakAlgs = true;
+ // If a "*-DIGEST-MANIFEST" entry is found.
+ boolean validEntry = false;
// go through all the attributes and process *-Digest-Manifest entries
for (Map.Entry