Merge changes Ic63473d6,Ie6d84509,I056d6da9,I393b79f6,I92c363ec, ...
* changes:
Use sun.security.provider.Sun
Update certpath code
Update sun.security supporting classes for certpath update
Add CertPathChecker and subclasses
Update supporting classes for OCSP update
Track fixes in nist-pkits tests
diff --git a/expectations/knownfailures.txt b/expectations/knownfailures.txt
index 0a6d8ac..db08a10 100644
--- a/expectations/knownfailures.txt
+++ b/expectations/knownfailures.txt
@@ -1299,21 +1299,8 @@
description: "Android's PKIX validation fails on many NIST PKIX tests",
bug: 8030138,
names: [
- "libcore.java.security.cert.X509CertificateNistPkitsTest#testBasicCertificateRevocationTests_InvalidSeparateCertificateandCRLKeysTest20",
- "libcore.java.security.cert.X509CertificateNistPkitsTest#testBasicCertificateRevocationTests_InvalidSeparateCertificateandCRLKeysTest21",
- "libcore.java.security.cert.X509CertificateNistPkitsTest#testBasicCertificateRevocationTests_ValidSeparateCertificateandCRLKeysTest19",
"libcore.java.security.cert.X509CertificateNistPkitsTest#testDeltaCRLs_InvaliddeltaCRLTest4",
- "libcore.java.security.cert.X509CertificateNistPkitsTest#testDeltaCRLs_ValiddeltaCRLTest5",
- "libcore.java.security.cert.X509CertificateNistPkitsTest#testDistributionPoints_ValidIDPwithindirectCRLTest24",
- "libcore.java.security.cert.X509CertificateNistPkitsTest#testDistributionPoints_ValidIDPwithindirectCRLTest25",
- "libcore.java.security.cert.X509CertificateNistPkitsTest#testDistributionPoints_ValidcRLIssuerTest28",
- "libcore.java.security.cert.X509CertificateNistPkitsTest#testDistributionPoints_ValidcRLIssuerTest29",
- "libcore.java.security.cert.X509CertificateNistPkitsTest#testDistributionPoints_ValidcRLIssuerTest30",
- "libcore.java.security.cert.X509CertificateNistPkitsTest#testDistributionPoints_ValidcRLIssuerTest33",
- "libcore.java.security.cert.X509CertificateNistPkitsTest#testKeyUsage_ValidSelfIssuedDNnameConstraintsTest19",
- "libcore.java.security.cert.X509CertificateNistPkitsTest#testVerifyingNameChaining_ValidRFC3280OptionalAttributeTypesTest8",
- "libcore.java.security.cert.X509CertificateNistPkitsTest#testVerifyingPathswithSelfIssuedCertificates_ValidBasicSelfIssuedCRLSigningKeyTest6",
- "libcore.java.security.cert.X509CertificateNistPkitsTest#testVerifyingPathswithSelfIssuedCertificates_ValidBasicSelfIssuedNewWithOldTest4"
+ "libcore.java.security.cert.X509CertificateNistPkitsTest#testDeltaCRLs_ValiddeltaCRLTest5"
]
},
{
diff --git a/luni/src/main/java/java/security/security.properties b/luni/src/main/java/java/security/security.properties
index 289efa9..783a672 100644
--- a/luni/src/main/java/java/security/security.properties
+++ b/luni/src/main/java/java/security/security.properties
@@ -20,10 +20,11 @@
#
# Android's provider of OpenSSL backed implementations
security.provider.1=com.android.org.conscrypt.OpenSSLProvider
+security.provider.2=sun.security.provider.Sun
# Android's stripped down BouncyCastle provider
-security.provider.2=com.android.org.bouncycastle.jce.provider.BouncyCastleProvider
+security.provider.3=com.android.org.bouncycastle.jce.provider.BouncyCastleProvider
# Android's provider of OpenSSL backed implementations
-security.provider.3=com.android.org.conscrypt.JSSEProvider
+security.provider.4=com.android.org.conscrypt.JSSEProvider
diff --git a/ojluni/src/main/java/java/lang/InternalError.java b/ojluni/src/main/java/java/lang/InternalError.java
index f49e9c2..8d33821 100755
--- a/ojluni/src/main/java/java/lang/InternalError.java
+++ b/ojluni/src/main/java/java/lang/InternalError.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1994, 2008, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1994, 2011, 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,8 +32,7 @@
* @author unascribed
* @since JDK1.0
*/
-public
-class InternalError extends VirtualMachineError {
+public class InternalError extends VirtualMachineError {
private static final long serialVersionUID = -9062593416125562365L;
/**
@@ -47,9 +46,45 @@
* Constructs an <code>InternalError</code> with the specified
* detail message.
*
- * @param s the detail message.
+ * @param message the detail message.
*/
- public InternalError(String s) {
- super(s);
+ public InternalError(String message) {
+ super(message);
}
+
+
+ /**
+ * Constructs an {@code InternalError} with the specified detail
+ * message and cause. <p>Note that the detail message associated
+ * with {@code cause} is <i>not</i> automatically incorporated in
+ * this error's detail message.
+ *
+ * @param message the detail message (which is saved for later retrieval
+ * by the {@link #getMessage()} method).
+ * @param cause the cause (which is saved for later retrieval by the
+ * {@link #getCause()} method). (A {@code null} value is
+ * permitted, and indicates that the cause is nonexistent or
+ * unknown.)
+ * @since 1.8
+ */
+ public InternalError(String message, Throwable cause) {
+ super(message, cause);
+ }
+
+ /**
+ * Constructs an {@code InternalError} with the specified cause
+ * and a detail message of {@code (cause==null ? null :
+ * cause.toString())} (which typically contains the class and
+ * detail message of {@code cause}).
+ *
+ * @param cause the cause (which is saved for later retrieval by the
+ * {@link #getCause()} method). (A {@code null} value is
+ * permitted, and indicates that the cause is nonexistent or
+ * unknown.)
+ * @since 1.8
+ */
+ public InternalError(Throwable cause) {
+ super(cause);
+ }
+
}
diff --git a/ojluni/src/main/java/java/lang/VirtualMachineError.java b/ojluni/src/main/java/java/lang/VirtualMachineError.java
index 2843147..c0a2a92 100755
--- a/ojluni/src/main/java/java/lang/VirtualMachineError.java
+++ b/ojluni/src/main/java/java/lang/VirtualMachineError.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1995, 1997, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1995, 2011, 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,8 +33,9 @@
* @author Frank Yellin
* @since JDK1.0
*/
-abstract public
-class VirtualMachineError extends Error {
+abstract public class VirtualMachineError extends Error {
+ private static final long serialVersionUID = 4161983926571568670L;
+
/**
* Constructs a <code>VirtualMachineError</code> with no detail message.
*/
@@ -46,9 +47,43 @@
* Constructs a <code>VirtualMachineError</code> with the specified
* detail message.
*
- * @param s the detail message.
+ * @param message the detail message.
*/
- public VirtualMachineError(String s) {
- super(s);
+ public VirtualMachineError(String message) {
+ super(message);
+ }
+
+ /**
+ * Constructs a {@code VirtualMachineError} with the specified
+ * detail message and cause. <p>Note that the detail message
+ * associated with {@code cause} is <i>not</i> automatically
+ * incorporated in this error's detail message.
+ *
+ * @param message the detail message (which is saved for later retrieval
+ * by the {@link #getMessage()} method).
+ * @param cause the cause (which is saved for later retrieval by the
+ * {@link #getCause()} method). (A {@code null} value is
+ * permitted, and indicates that the cause is nonexistent or
+ * unknown.)
+ * @since 1.8
+ */
+ public VirtualMachineError(String message, Throwable cause) {
+ super(message, cause);
+ }
+
+ /**
+ * Constructs an a {@code VirtualMachineError} with the specified
+ * cause and a detail message of {@code (cause==null ? null :
+ * cause.toString())} (which typically contains the class and
+ * detail message of {@code cause}).
+ *
+ * @param cause the cause (which is saved for later retrieval by the
+ * {@link #getCause()} method). (A {@code null} value is
+ * permitted, and indicates that the cause is nonexistent or
+ * unknown.)
+ * @since 1.8
+ */
+ public VirtualMachineError(Throwable cause) {
+ super(cause);
}
}
diff --git a/ojluni/src/main/java/java/security/Security.java b/ojluni/src/main/java/java/security/Security.java
index 126ed49..c0ce73d 100755
--- a/ojluni/src/main/java/java/security/Security.java
+++ b/ojluni/src/main/java/java/security/Security.java
@@ -98,8 +98,9 @@
props.put("security.provider.5", "sun.security.jgss.SunProvider");
props.put("security.provider.6", "com.sun.security.sasl.Provider"); */
props.put("security.provider.1", "com.android.org.conscrypt.OpenSSLProvider");
- props.put("security.provider.2", "com.android.org.bouncycastle.jce.provider.BouncyCastleProvider");
- props.put("security.provider.3", "com.android.org.conscrypt.JSSEProvider");
+ props.put("security.provider.2", "sun.security.provider.Sun");
+ props.put("security.provider.3", "com.android.org.bouncycastle.jce.provider.BouncyCastleProvider");
+ props.put("security.provider.4", "com.android.org.conscrypt.JSSEProvider");
// ----- END android -----
}
diff --git a/ojluni/src/main/java/java/security/cert/CertPathBuilder.java b/ojluni/src/main/java/java/security/cert/CertPathBuilder.java
index 95988d4..6008e9e 100755
--- a/ojluni/src/main/java/java/security/cert/CertPathBuilder.java
+++ b/ojluni/src/main/java/java/security/cert/CertPathBuilder.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2000, 2011, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2000, 2013, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -41,22 +41,35 @@
* A class for building certification paths (also known as certificate chains).
* <p>
* This class uses a provider-based architecture.
- * To create a <code>CertPathBuilder</code>, call
- * one of the static <code>getInstance</code> methods, passing in the
- * algorithm name of the <code>CertPathBuilder</code> desired and optionally
+ * To create a {@code CertPathBuilder}, call
+ * one of the static {@code getInstance} methods, passing in the
+ * algorithm name of the {@code CertPathBuilder} desired and optionally
* the name of the provider desired.
- * <p>
- * Once a <code>CertPathBuilder</code> object has been created, certification
+ *
+ * <p>Once a {@code CertPathBuilder} object has been created, certification
* paths can be constructed by calling the {@link #build build} method and
* passing it an algorithm-specific set of parameters. If successful, the
- * result (including the <code>CertPath</code> that was built) is returned
- * in an object that implements the <code>CertPathBuilderResult</code>
+ * result (including the {@code CertPath} that was built) is returned
+ * in an object that implements the {@code CertPathBuilderResult}
* interface.
*
- * <p> Every implementation of the Java platform is required to support the
- * following standard <code>CertPathBuilder</code> algorithm:
+ * <p>The {@link #getRevocationChecker} method allows an application to specify
+ * additional algorithm-specific parameters and options used by the
+ * {@code CertPathBuilder} when checking the revocation status of certificates.
+ * Here is an example demonstrating how it is used with the PKIX algorithm:
+ *
+ * <pre>
+ * CertPathBuilder cpb = CertPathBuilder.getInstance("PKIX");
+ * PKIXRevocationChecker rc = (PKIXRevocationChecker)cpb.getRevocationChecker();
+ * rc.setOptions(EnumSet.of(Option.PREFER_CRLS));
+ * params.addCertPathChecker(rc);
+ * CertPathBuilderResult cpbr = cpb.build(params);
+ * </pre>
+ *
+ * <p>Every implementation of the Java platform is required to support the
+ * following standard {@code CertPathBuilder} algorithm:
* <ul>
- * <li><tt>PKIX</tt></li>
+ * <li>{@code PKIX}</li>
* </ul>
* This algorithm is described in the <a href=
* "{@docRoot}/../technotes/guides/security/StandardNames.html#CertPathBuilder">
@@ -74,9 +87,9 @@
* <p>
* However, this is not true for the non-static methods defined by this class.
* Unless otherwise documented by a specific provider, threads that need to
- * access a single <code>CertPathBuilder</code> instance concurrently should
+ * access a single {@code CertPathBuilder} instance concurrently should
* synchronize amongst themselves and provide the necessary locking. Multiple
- * threads each manipulating a different <code>CertPathBuilder</code> instance
+ * threads each manipulating a different {@code CertPathBuilder} instance
* need not synchronize.
*
* @see CertPath
@@ -96,13 +109,12 @@
* </pre>
*/
private static final String CPB_TYPE = "certpathbuilder.type";
- private static final Debug debug = Debug.getInstance("certpath");
- private CertPathBuilderSpi builderSpi;
- private Provider provider;
- private String algorithm;
+ private final CertPathBuilderSpi builderSpi;
+ private final Provider provider;
+ private final String algorithm;
/**
- * Creates a <code>CertPathBuilder</code> object of the given algorithm,
+ * Creates a {@code CertPathBuilder} object of the given algorithm,
* and encapsulates the given provider implementation (SPI object) in it.
*
* @param builderSpi the provider implementation
@@ -118,7 +130,7 @@
}
/**
- * Returns a <code>CertPathBuilder</code> object that implements the
+ * Returns a {@code CertPathBuilder} object that implements the
* specified algorithm.
*
* <p> This method traverses the list of registered security Providers,
@@ -130,13 +142,13 @@
* <p> Note that the list of registered providers may be retrieved via
* the {@link Security#getProviders() Security.getProviders()} method.
*
- * @param algorithm the name of the requested <code>CertPathBuilder</code>
+ * @param algorithm the name of the requested {@code CertPathBuilder}
* algorithm. See the CertPathBuilder section in the <a href=
* "{@docRoot}/../technotes/guides/security/StandardNames.html#CertPathBuilder">
* Java Cryptography Architecture Standard Algorithm Name Documentation</a>
* for information about standard algorithm names.
*
- * @return a <code>CertPathBuilder</code> object that implements the
+ * @return a {@code CertPathBuilder} object that implements the
* specified algorithm.
*
* @throws NoSuchAlgorithmException if no Provider supports a
@@ -154,7 +166,7 @@
}
/**
- * Returns a <code>CertPathBuilder</code> object that implements the
+ * Returns a {@code CertPathBuilder} object that implements the
* specified algorithm.
*
* <p> A new CertPathBuilder object encapsulating the
@@ -165,7 +177,7 @@
* <p> Note that the list of registered providers may be retrieved via
* the {@link Security#getProviders() Security.getProviders()} method.
*
- * @param algorithm the name of the requested <code>CertPathBuilder</code>
+ * @param algorithm the name of the requested {@code CertPathBuilder}
* algorithm. See the CertPathBuilder section in the <a href=
* "{@docRoot}/../technotes/guides/security/StandardNames.html#CertPathBuilder">
* Java Cryptography Architecture Standard Algorithm Name Documentation</a>
@@ -173,7 +185,7 @@
*
* @param provider the name of the provider.
*
- * @return a <code>CertPathBuilder</code> object that implements the
+ * @return a {@code CertPathBuilder} object that implements the
* specified algorithm.
*
* @throws NoSuchAlgorithmException if a CertPathBuilderSpi
@@ -183,7 +195,7 @@
* @throws NoSuchProviderException if the specified provider is not
* registered in the security provider list.
*
- * @exception IllegalArgumentException if the <code>provider</code> is
+ * @exception IllegalArgumentException if the {@code provider} is
* null or empty.
*
* @see java.security.Provider
@@ -197,7 +209,7 @@
}
/**
- * Returns a <code>CertPathBuilder</code> object that implements the
+ * Returns a {@code CertPathBuilder} object that implements the
* specified algorithm.
*
* <p> A new CertPathBuilder object encapsulating the
@@ -205,7 +217,7 @@
* object is returned. Note that the specified Provider object
* does not have to be registered in the provider list.
*
- * @param algorithm the name of the requested <code>CertPathBuilder</code>
+ * @param algorithm the name of the requested {@code CertPathBuilder}
* algorithm. See the CertPathBuilder section in the <a href=
* "{@docRoot}/../technotes/guides/security/StandardNames.html#CertPathBuilder">
* Java Cryptography Architecture Standard Algorithm Name Documentation</a>
@@ -213,14 +225,14 @@
*
* @param provider the provider.
*
- * @return a <code>CertPathBuilder</code> object that implements the
+ * @return a {@code CertPathBuilder} object that implements the
* specified algorithm.
*
* @exception NoSuchAlgorithmException if a CertPathBuilderSpi
* implementation for the specified algorithm is not available
* from the specified Provider object.
*
- * @exception IllegalArgumentException if the <code>provider</code> is
+ * @exception IllegalArgumentException if the {@code provider} is
* null.
*
* @see java.security.Provider
@@ -234,18 +246,18 @@
}
/**
- * Returns the provider of this <code>CertPathBuilder</code>.
+ * Returns the provider of this {@code CertPathBuilder}.
*
- * @return the provider of this <code>CertPathBuilder</code>
+ * @return the provider of this {@code CertPathBuilder}
*/
public final Provider getProvider() {
return this.provider;
}
/**
- * Returns the name of the algorithm of this <code>CertPathBuilder</code>.
+ * Returns the name of the algorithm of this {@code CertPathBuilder}.
*
- * @return the name of the algorithm of this <code>CertPathBuilder</code>
+ * @return the name of the algorithm of this {@code CertPathBuilder}
*/
public final String getAlgorithm() {
return this.algorithm;
@@ -260,7 +272,7 @@
* @throws CertPathBuilderException if the builder is unable to construct
* a certification path that satisfies the specified parameters
* @throws InvalidAlgorithmParameterException if the specified parameters
- * are inappropriate for this <code>CertPathBuilder</code>
+ * are inappropriate for this {@code CertPathBuilder}
*/
public final CertPathBuilderResult build(CertPathParameters params)
throws CertPathBuilderException, InvalidAlgorithmParameterException
@@ -269,36 +281,51 @@
}
/**
- * Returns the default <code>CertPathBuilder</code> type as specified in
- * the Java security properties file, or the string "PKIX"
- * if no such property exists. The Java security properties file is
- * located in the file named <JAVA_HOME>/lib/security/java.security.
- * <JAVA_HOME> refers to the value of the java.home system property,
- * and specifies the directory where the JRE is installed.
+ * Returns the default {@code CertPathBuilder} type as specified by
+ * the {@code certpathbuilder.type} security property, or the string
+ * {@literal "PKIX"} if no such property exists.
*
- * <p>The default <code>CertPathBuilder</code> type can be used by
+ * <p>The default {@code CertPathBuilder} type can be used by
* applications that do not want to use a hard-coded type when calling one
- * of the <code>getInstance</code> methods, and want to provide a default
+ * of the {@code getInstance} methods, and want to provide a default
* type in case a user does not specify its own.
*
- * <p>The default <code>CertPathBuilder</code> type can be changed by
- * setting the value of the "certpathbuilder.type" security property
- * (in the Java security properties file) to the desired type.
+ * <p>The default {@code CertPathBuilder} type can be changed by
+ * setting the value of the {@code certpathbuilder.type} security property
+ * to the desired type.
*
- * @return the default <code>CertPathBuilder</code> type as specified
- * in the Java security properties file, or the string "PKIX"
- * if no such property exists.
+ * @see java.security.Security security properties
+ * @return the default {@code CertPathBuilder} type as specified
+ * by the {@code certpathbuilder.type} security property, or the string
+ * {@literal "PKIX"} if no such property exists.
*/
public final static String getDefaultType() {
- String cpbtype;
- cpbtype = AccessController.doPrivileged(new PrivilegedAction<String>() {
- public String run() {
- return Security.getProperty(CPB_TYPE);
- }
- });
- if (cpbtype == null) {
- cpbtype = "PKIX";
- }
- return cpbtype;
+ String cpbtype =
+ AccessController.doPrivileged(new PrivilegedAction<String>() {
+ public String run() {
+ return Security.getProperty(CPB_TYPE);
+ }
+ });
+ return (cpbtype == null) ? "PKIX" : cpbtype;
+ }
+
+ /**
+ * Returns a {@code CertPathChecker} that the encapsulated
+ * {@code CertPathBuilderSpi} implementation uses to check the revocation
+ * status of certificates. A PKIX implementation returns objects of
+ * type {@code PKIXRevocationChecker}. Each invocation of this method
+ * returns a new instance of {@code CertPathChecker}.
+ *
+ * <p>The primary purpose of this method is to allow callers to specify
+ * additional input parameters and options specific to revocation checking.
+ * See the class description for an example.
+ *
+ * @return a {@code CertPathChecker}
+ * @throws UnsupportedOperationException if the service provider does not
+ * support this method
+ * @since 1.8
+ */
+ public final CertPathChecker getRevocationChecker() {
+ return builderSpi.engineGetRevocationChecker();
}
}
diff --git a/ojluni/src/main/java/java/security/cert/CertPathBuilderException.java b/ojluni/src/main/java/java/security/cert/CertPathBuilderException.java
index 4d460c6..cf95847 100755
--- a/ojluni/src/main/java/java/security/cert/CertPathBuilderException.java
+++ b/ojluni/src/main/java/java/security/cert/CertPathBuilderException.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2000, 2003, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2000, 2013, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -29,9 +29,9 @@
/**
* An exception indicating one of a variety of problems encountered when
- * building a certification path with a <code>CertPathBuilder</code>.
+ * building a certification path with a {@code CertPathBuilder}.
* <p>
- * A <code>CertPathBuilderException</code> provides support for wrapping
+ * A {@code CertPathBuilderException} provides support for wrapping
* exceptions. The {@link #getCause getCause} method returns the throwable,
* if any, that caused this exception to be thrown.
* <p>
@@ -53,7 +53,7 @@
private static final long serialVersionUID = 5316471420178794402L;
/**
- * Creates a <code>CertPathBuilderException</code> with <code>null</code>
+ * Creates a {@code CertPathBuilderException} with {@code null}
* as its detail message.
*/
public CertPathBuilderException() {
@@ -61,8 +61,8 @@
}
/**
- * Creates a <code>CertPathBuilderException</code> with the given
- * detail message. The detail message is a <code>String</code> that
+ * Creates a {@code CertPathBuilderException} with the given
+ * detail message. The detail message is a {@code String} that
* describes this particular exception in more detail.
*
* @param msg the detail message
@@ -72,16 +72,16 @@
}
/**
- * Creates a <code>CertPathBuilderException</code> that wraps the specified
+ * Creates a {@code CertPathBuilderException} that wraps the specified
* throwable. This allows any exception to be converted into a
- * <code>CertPathBuilderException</code>, while retaining information
+ * {@code CertPathBuilderException}, while retaining information
* about the wrapped exception, which may be useful for debugging. The
- * detail message is set to (<code>cause==null ? null : cause.toString()
- * </code>) (which typically contains the class and detail message of
+ * detail message is set to ({@code cause==null ? null : cause.toString()})
+ * (which typically contains the class and detail message of
* cause).
*
* @param cause the cause (which is saved for later retrieval by the
- * {@link #getCause getCause()} method). (A <code>null</code> value is
+ * {@link #getCause getCause()} method). (A {@code null} value is
* permitted, and indicates that the cause is nonexistent or unknown.)
*/
public CertPathBuilderException(Throwable cause) {
@@ -89,12 +89,12 @@
}
/**
- * Creates a <code>CertPathBuilderException</code> with the specified
+ * Creates a {@code CertPathBuilderException} with the specified
* detail message and cause.
*
* @param msg the detail message
* @param cause the cause (which is saved for later retrieval by the
- * {@link #getCause getCause()} method). (A <code>null</code> value is
+ * {@link #getCause getCause()} method). (A {@code null} value is
* permitted, and indicates that the cause is nonexistent or unknown.)
*/
public CertPathBuilderException(String msg, Throwable cause) {
diff --git a/ojluni/src/main/java/java/security/cert/CertPathBuilderResult.java b/ojluni/src/main/java/java/security/cert/CertPathBuilderResult.java
index 71eed20..ecf53bb 100755
--- a/ojluni/src/main/java/java/security/cert/CertPathBuilderResult.java
+++ b/ojluni/src/main/java/java/security/cert/CertPathBuilderResult.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2000, 2001, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2000, 2013, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -30,8 +30,8 @@
* All results returned by the {@link CertPathBuilder#build
* CertPathBuilder.build} method must implement this interface.
* <p>
- * At a minimum, a <code>CertPathBuilderResult</code> contains the
- * <code>CertPath</code> built by the <code>CertPathBuilder</code> instance.
+ * At a minimum, a {@code CertPathBuilderResult} contains the
+ * {@code CertPath} built by the {@code CertPathBuilder} instance.
* Implementations of this interface may add methods to return implementation
* or algorithm specific information, such as debugging information or
* certification path validation results.
@@ -54,15 +54,15 @@
/**
* Returns the built certification path.
*
- * @return the certification path (never <code>null</code>)
+ * @return the certification path (never {@code null})
*/
CertPath getCertPath();
/**
- * Makes a copy of this <code>CertPathBuilderResult</code>. Changes to the
+ * Makes a copy of this {@code CertPathBuilderResult}. Changes to the
* copy will not affect the original and vice versa.
*
- * @return a copy of this <code>CertPathBuilderResult</code>
+ * @return a copy of this {@code CertPathBuilderResult}
*/
Object clone();
}
diff --git a/ojluni/src/main/java/java/security/cert/CertPathBuilderSpi.java b/ojluni/src/main/java/java/security/cert/CertPathBuilderSpi.java
index 0c10a4d..e775541 100755
--- a/ojluni/src/main/java/java/security/cert/CertPathBuilderSpi.java
+++ b/ojluni/src/main/java/java/security/cert/CertPathBuilderSpi.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2000, 2001, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2000, 2013, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -30,23 +30,23 @@
/**
* The <i>Service Provider Interface</i> (<b>SPI</b>)
* for the {@link CertPathBuilder CertPathBuilder} class. All
- * <code>CertPathBuilder</code> implementations must include a class (the
- * SPI class) that extends this class (<code>CertPathBuilderSpi</code>) and
+ * {@code CertPathBuilder} implementations must include a class (the
+ * SPI class) that extends this class ({@code CertPathBuilderSpi}) and
* implements all of its methods. In general, instances of this class should
- * only be accessed through the <code>CertPathBuilder</code> class. For
+ * only be accessed through the {@code CertPathBuilder} class. For
* details, see the Java Cryptography Architecture.
* <p>
* <b>Concurrent Access</b>
* <p>
* Instances of this class need not be protected against concurrent
* access from multiple threads. Threads that need to access a single
- * <code>CertPathBuilderSpi</code> instance concurrently should synchronize
+ * {@code CertPathBuilderSpi} instance concurrently should synchronize
* amongst themselves and provide the necessary locking before calling the
- * wrapping <code>CertPathBuilder</code> object.
+ * wrapping {@code CertPathBuilder} object.
* <p>
- * However, implementations of <code>CertPathBuilderSpi</code> may still
+ * However, implementations of {@code CertPathBuilderSpi} may still
* encounter concurrency issues, since multiple threads each
- * manipulating a different <code>CertPathBuilderSpi</code> instance need not
+ * manipulating a different {@code CertPathBuilderSpi} instance need not
* synchronize.
*
* @since 1.4
@@ -68,8 +68,31 @@
* @throws CertPathBuilderException if the builder is unable to construct
* a certification path that satisfies the specified parameters
* @throws InvalidAlgorithmParameterException if the specified parameters
- * are inappropriate for this <code>CertPathBuilder</code>
+ * are inappropriate for this {@code CertPathBuilder}
*/
public abstract CertPathBuilderResult engineBuild(CertPathParameters params)
throws CertPathBuilderException, InvalidAlgorithmParameterException;
+
+ /**
+ * Returns a {@code CertPathChecker} that this implementation uses to
+ * check the revocation status of certificates. A PKIX implementation
+ * returns objects of type {@code PKIXRevocationChecker}.
+ *
+ * <p>The primary purpose of this method is to allow callers to specify
+ * additional input parameters and options specific to revocation checking.
+ * See the class description of {@code CertPathBuilder} for an example.
+ *
+ * <p>This method was added to version 1.8 of the Java Platform Standard
+ * Edition. In order to maintain backwards compatibility with existing
+ * service providers, this method cannot be abstract and by default throws
+ * an {@code UnsupportedOperationException}.
+ *
+ * @return a {@code CertPathChecker} that this implementation uses to
+ * check the revocation status of certificates
+ * @throws UnsupportedOperationException if this method is not supported
+ * @since 1.8
+ */
+ public CertPathChecker engineGetRevocationChecker() {
+ throw new UnsupportedOperationException();
+ }
}
diff --git a/ojluni/src/main/java/java/security/cert/CertPathChecker.java b/ojluni/src/main/java/java/security/cert/CertPathChecker.java
new file mode 100644
index 0000000..c40a65b
--- /dev/null
+++ b/ojluni/src/main/java/java/security/cert/CertPathChecker.java
@@ -0,0 +1,77 @@
+/*
+ * Copyright (c) 2012, 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 java.security.cert;
+
+/**
+ * <p>Performs one or more checks on each {@code Certificate} of a
+ * {@code CertPath}.
+ *
+ * <p>A {@code CertPathChecker} implementation is typically created to extend
+ * a certification path validation algorithm. For example, an implementation
+ * may check for and process a critical private extension of each certificate
+ * in a certification path.
+ *
+ * @since 1.8
+ */
+public interface CertPathChecker {
+
+ /**
+ * Initializes the internal state of this {@code CertPathChecker}.
+ *
+ * <p>The {@code forward} flag specifies the order that certificates will
+ * be passed to the {@link #check check} method (forward or reverse).
+ *
+ * @param forward the order that certificates are presented to the
+ * {@code check} method. If {@code true}, certificates are
+ * presented from target to trust anchor (forward); if
+ * {@code false}, from trust anchor to target (reverse).
+ * @throws CertPathValidatorException if this {@code CertPathChecker} is
+ * unable to check certificates in the specified order
+ */
+ void init(boolean forward) throws CertPathValidatorException;
+
+ /**
+ * Indicates if forward checking is supported. Forward checking refers
+ * to the ability of the {@code CertPathChecker} to perform its checks
+ * when certificates are presented to the {@code check} method in the
+ * forward direction (from target to trust anchor).
+ *
+ * @return {@code true} if forward checking is supported, {@code false}
+ * otherwise
+ */
+ boolean isForwardCheckingSupported();
+
+ /**
+ * Performs the check(s) on the specified certificate using its internal
+ * state. The certificates are presented in the order specified by the
+ * {@code init} method.
+ *
+ * @param cert the {@code Certificate} to be checked
+ * @throws CertPathValidatorException if the specified certificate does
+ * not pass the check
+ */
+ void check(Certificate cert) throws CertPathValidatorException;
+}
diff --git a/ojluni/src/main/java/java/security/cert/CertPathValidator.java b/ojluni/src/main/java/java/security/cert/CertPathValidator.java
index ddeea99..bd2ff56 100755
--- a/ojluni/src/main/java/java/security/cert/CertPathValidator.java
+++ b/ojluni/src/main/java/java/security/cert/CertPathValidator.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2000, 2011, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2000, 2013, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -42,22 +42,36 @@
* chains).
* <p>
* This class uses a provider-based architecture.
- * To create a <code>CertPathValidator</code>,
- * call one of the static <code>getInstance</code> methods, passing in the
- * algorithm name of the <code>CertPathValidator</code> desired and
+ * To create a {@code CertPathValidator},
+ * call one of the static {@code getInstance} methods, passing in the
+ * algorithm name of the {@code CertPathValidator} desired and
* optionally the name of the provider desired.
- * <p>
- * Once a <code>CertPathValidator</code> object has been created, it can
+ *
+ * <p>Once a {@code CertPathValidator} object has been created, it can
* be used to validate certification paths by calling the {@link #validate
- * validate} method and passing it the <code>CertPath</code> to be validated
+ * validate} method and passing it the {@code CertPath} to be validated
* and an algorithm-specific set of parameters. If successful, the result is
* returned in an object that implements the
- * <code>CertPathValidatorResult</code> interface.
+ * {@code CertPathValidatorResult} interface.
*
- * <p> Every implementation of the Java platform is required to support the
- * following standard <code>CertPathValidator</code> algorithm:
+ * <p>The {@link #getRevocationChecker} method allows an application to specify
+ * additional algorithm-specific parameters and options used by the
+ * {@code CertPathValidator} when checking the revocation status of
+ * certificates. Here is an example demonstrating how it is used with the PKIX
+ * algorithm:
+ *
+ * <pre>
+ * CertPathValidator cpv = CertPathValidator.getInstance("PKIX");
+ * PKIXRevocationChecker rc = (PKIXRevocationChecker)cpv.getRevocationChecker();
+ * rc.setOptions(EnumSet.of(Option.SOFT_FAIL));
+ * params.addCertPathChecker(rc);
+ * CertPathValidatorResult cpvr = cpv.validate(path, params);
+ * </pre>
+ *
+ * <p>Every implementation of the Java platform is required to support the
+ * following standard {@code CertPathValidator} algorithm:
* <ul>
- * <li><tt>PKIX</tt></li>
+ * <li>{@code PKIX}</li>
* </ul>
* This algorithm is described in the <a href=
* "{@docRoot}/../technotes/guides/security/StandardNames.html#CertPathValidator">
@@ -75,9 +89,9 @@
* <p>
* However, this is not true for the non-static methods defined by this class.
* Unless otherwise documented by a specific provider, threads that need to
- * access a single <code>CertPathValidator</code> instance concurrently should
+ * access a single {@code CertPathValidator} instance concurrently should
* synchronize amongst themselves and provide the necessary locking. Multiple
- * threads each manipulating a different <code>CertPathValidator</code>
+ * threads each manipulating a different {@code CertPathValidator}
* instance need not synchronize.
*
* @see CertPath
@@ -96,13 +110,12 @@
* </pre>
*/
private static final String CPV_TYPE = "certpathvalidator.type";
- private static final Debug debug = Debug.getInstance("certpath");
- private CertPathValidatorSpi validatorSpi;
- private Provider provider;
- private String algorithm;
+ private final CertPathValidatorSpi validatorSpi;
+ private final Provider provider;
+ private final String algorithm;
/**
- * Creates a <code>CertPathValidator</code> object of the given algorithm,
+ * Creates a {@code CertPathValidator} object of the given algorithm,
* and encapsulates the given provider implementation (SPI object) in it.
*
* @param validatorSpi the provider implementation
@@ -118,7 +131,7 @@
}
/**
- * Returns a <code>CertPathValidator</code> object that implements the
+ * Returns a {@code CertPathValidator} object that implements the
* specified algorithm.
*
* <p> This method traverses the list of registered security Providers,
@@ -130,13 +143,13 @@
* <p> Note that the list of registered providers may be retrieved via
* the {@link Security#getProviders() Security.getProviders()} method.
*
- * @param algorithm the name of the requested <code>CertPathValidator</code>
+ * @param algorithm the name of the requested {@code CertPathValidator}
* algorithm. See the CertPathValidator section in the <a href=
* "{@docRoot}/../technotes/guides/security/StandardNames.html#CertPathValidator">
* Java Cryptography Architecture Standard Algorithm Name Documentation</a>
* for information about standard algorithm names.
*
- * @return a <code>CertPathValidator</code> object that implements the
+ * @return a {@code CertPathValidator} object that implements the
* specified algorithm.
*
* @exception NoSuchAlgorithmException if no Provider supports a
@@ -154,7 +167,7 @@
}
/**
- * Returns a <code>CertPathValidator</code> object that implements the
+ * Returns a {@code CertPathValidator} object that implements the
* specified algorithm.
*
* <p> A new CertPathValidator object encapsulating the
@@ -165,7 +178,7 @@
* <p> Note that the list of registered providers may be retrieved via
* the {@link Security#getProviders() Security.getProviders()} method.
*
- * @param algorithm the name of the requested <code>CertPathValidator</code>
+ * @param algorithm the name of the requested {@code CertPathValidator}
* algorithm. See the CertPathValidator section in the <a href=
* "{@docRoot}/../technotes/guides/security/StandardNames.html#CertPathValidator">
* Java Cryptography Architecture Standard Algorithm Name Documentation</a>
@@ -173,7 +186,7 @@
*
* @param provider the name of the provider.
*
- * @return a <code>CertPathValidator</code> object that implements the
+ * @return a {@code CertPathValidator} object that implements the
* specified algorithm.
*
* @exception NoSuchAlgorithmException if a CertPathValidatorSpi
@@ -183,7 +196,7 @@
* @exception NoSuchProviderException if the specified provider is not
* registered in the security provider list.
*
- * @exception IllegalArgumentException if the <code>provider</code> is
+ * @exception IllegalArgumentException if the {@code provider} is
* null or empty.
*
* @see java.security.Provider
@@ -198,7 +211,7 @@
}
/**
- * Returns a <code>CertPathValidator</code> object that implements the
+ * Returns a {@code CertPathValidator} object that implements the
* specified algorithm.
*
* <p> A new CertPathValidator object encapsulating the
@@ -206,7 +219,7 @@
* object is returned. Note that the specified Provider object
* does not have to be registered in the provider list.
*
- * @param algorithm the name of the requested <code>CertPathValidator</code>
+ * @param algorithm the name of the requested {@code CertPathValidator}
* algorithm. See the CertPathValidator section in the <a href=
* "{@docRoot}/../technotes/guides/security/StandardNames.html#CertPathValidator">
* Java Cryptography Architecture Standard Algorithm Name Documentation</a>
@@ -214,14 +227,14 @@
*
* @param provider the provider.
*
- * @return a <code>CertPathValidator</code> object that implements the
+ * @return a {@code CertPathValidator} object that implements the
* specified algorithm.
*
* @exception NoSuchAlgorithmException if a CertPathValidatorSpi
* implementation for the specified algorithm is not available
* from the specified Provider object.
*
- * @exception IllegalArgumentException if the <code>provider</code> is
+ * @exception IllegalArgumentException if the {@code provider} is
* null.
*
* @see java.security.Provider
@@ -235,19 +248,19 @@
}
/**
- * Returns the <code>Provider</code> of this
- * <code>CertPathValidator</code>.
+ * Returns the {@code Provider} of this
+ * {@code CertPathValidator}.
*
- * @return the <code>Provider</code> of this <code>CertPathValidator</code>
+ * @return the {@code Provider} of this {@code CertPathValidator}
*/
public final Provider getProvider() {
return this.provider;
}
/**
- * Returns the algorithm name of this <code>CertPathValidator</code>.
+ * Returns the algorithm name of this {@code CertPathValidator}.
*
- * @return the algorithm name of this <code>CertPathValidator</code>
+ * @return the algorithm name of this {@code CertPathValidator}
*/
public final String getAlgorithm() {
return this.algorithm;
@@ -257,20 +270,20 @@
* Validates the specified certification path using the specified
* algorithm parameter set.
* <p>
- * The <code>CertPath</code> specified must be of a type that is
+ * The {@code CertPath} specified must be of a type that is
* supported by the validation algorithm, otherwise an
- * <code>InvalidAlgorithmParameterException</code> will be thrown. For
- * example, a <code>CertPathValidator</code> that implements the PKIX
- * algorithm validates <code>CertPath</code> objects of type X.509.
+ * {@code InvalidAlgorithmParameterException} will be thrown. For
+ * example, a {@code CertPathValidator} that implements the PKIX
+ * algorithm validates {@code CertPath} objects of type X.509.
*
- * @param certPath the <code>CertPath</code> to be validated
+ * @param certPath the {@code CertPath} to be validated
* @param params the algorithm parameters
* @return the result of the validation algorithm
- * @exception CertPathValidatorException if the <code>CertPath</code>
+ * @exception CertPathValidatorException if the {@code CertPath}
* does not validate
* @exception InvalidAlgorithmParameterException if the specified
- * parameters or the type of the specified <code>CertPath</code> are
- * inappropriate for this <code>CertPathValidator</code>
+ * parameters or the type of the specified {@code CertPath} are
+ * inappropriate for this {@code CertPathValidator}
*/
public final CertPathValidatorResult validate(CertPath certPath,
CertPathParameters params)
@@ -280,36 +293,51 @@
}
/**
- * Returns the default <code>CertPathValidator</code> type as specified in
- * the Java security properties file, or the string "PKIX"
- * if no such property exists. The Java security properties file is
- * located in the file named <JAVA_HOME>/lib/security/java.security.
- * <JAVA_HOME> refers to the value of the java.home system property,
- * and specifies the directory where the JRE is installed.
+ * Returns the default {@code CertPathValidator} type as specified by
+ * the {@code certpathvalidator.type} security property, or the string
+ * {@literal "PKIX"} if no such property exists.
*
- * <p>The default <code>CertPathValidator</code> type can be used by
+ * <p>The default {@code CertPathValidator} type can be used by
* applications that do not want to use a hard-coded type when calling one
- * of the <code>getInstance</code> methods, and want to provide a default
+ * of the {@code getInstance} methods, and want to provide a default
* type in case a user does not specify its own.
*
- * <p>The default <code>CertPathValidator</code> type can be changed by
- * setting the value of the "certpathvalidator.type" security property
- * (in the Java security properties file) to the desired type.
+ * <p>The default {@code CertPathValidator} type can be changed by
+ * setting the value of the {@code certpathvalidator.type} security
+ * property to the desired type.
*
- * @return the default <code>CertPathValidator</code> type as specified
- * in the Java security properties file, or the string "PKIX"
- * if no such property exists.
+ * @see java.security.Security security properties
+ * @return the default {@code CertPathValidator} type as specified
+ * by the {@code certpathvalidator.type} security property, or the string
+ * {@literal "PKIX"} if no such property exists.
*/
public final static String getDefaultType() {
- String cpvtype;
- cpvtype = AccessController.doPrivileged(new PrivilegedAction<String>() {
- public String run() {
- return Security.getProperty(CPV_TYPE);
- }
- });
- if (cpvtype == null) {
- cpvtype = "PKIX";
- }
- return cpvtype;
+ String cpvtype =
+ AccessController.doPrivileged(new PrivilegedAction<String>() {
+ public String run() {
+ return Security.getProperty(CPV_TYPE);
+ }
+ });
+ return (cpvtype == null) ? "PKIX" : cpvtype;
+ }
+
+ /**
+ * Returns a {@code CertPathChecker} that the encapsulated
+ * {@code CertPathValidatorSpi} implementation uses to check the revocation
+ * status of certificates. A PKIX implementation returns objects of
+ * type {@code PKIXRevocationChecker}. Each invocation of this method
+ * returns a new instance of {@code CertPathChecker}.
+ *
+ * <p>The primary purpose of this method is to allow callers to specify
+ * additional input parameters and options specific to revocation checking.
+ * See the class description for an example.
+ *
+ * @return a {@code CertPathChecker}
+ * @throws UnsupportedOperationException if the service provider does not
+ * support this method
+ * @since 1.8
+ */
+ public final CertPathChecker getRevocationChecker() {
+ return validatorSpi.engineGetRevocationChecker();
}
}
diff --git a/ojluni/src/main/java/java/security/cert/CertPathValidatorException.java b/ojluni/src/main/java/java/security/cert/CertPathValidatorException.java
index 9eedb62..7e6b916 100755
--- a/ojluni/src/main/java/java/security/cert/CertPathValidatorException.java
+++ b/ojluni/src/main/java/java/security/cert/CertPathValidatorException.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2000, 2011, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2000, 2013, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -34,11 +34,11 @@
* An exception indicating one of a variety of problems encountered when
* validating a certification path.
* <p>
- * A <code>CertPathValidatorException</code> provides support for wrapping
+ * A {@code CertPathValidatorException} provides support for wrapping
* exceptions. The {@link #getCause getCause} method returns the throwable,
* if any, that caused this exception to be thrown.
* <p>
- * A <code>CertPathValidatorException</code> may also include the
+ * A {@code CertPathValidatorException} may also include the
* certification path that was being validated when the exception was thrown,
* the index of the certificate in the certification path that caused the
* exception to be thrown, and the reason that caused the failure. Use the
@@ -70,7 +70,7 @@
private int index = -1;
/**
- * @serial the <code>CertPath</code> that was being validated when
+ * @serial the {@code CertPath} that was being validated when
* the exception was thrown
*/
private CertPath certPath;
@@ -81,7 +81,7 @@
private Reason reason = BasicReason.UNSPECIFIED;
/**
- * Creates a <code>CertPathValidatorException</code> with
+ * Creates a {@code CertPathValidatorException} with
* no detail message.
*/
public CertPathValidatorException() {
@@ -89,8 +89,8 @@
}
/**
- * Creates a <code>CertPathValidatorException</code> with the given
- * detail message. A detail message is a <code>String</code> that
+ * Creates a {@code CertPathValidatorException} with the given
+ * detail message. A detail message is a {@code String} that
* describes this particular exception.
*
* @param msg the detail message
@@ -100,16 +100,16 @@
}
/**
- * Creates a <code>CertPathValidatorException</code> that wraps the
+ * Creates a {@code CertPathValidatorException} that wraps the
* specified throwable. This allows any exception to be converted into a
- * <code>CertPathValidatorException</code>, while retaining information
+ * {@code CertPathValidatorException}, while retaining information
* about the wrapped exception, which may be useful for debugging. The
- * detail message is set to (<code>cause==null ? null : cause.toString()
- * </code>) (which typically contains the class and detail message of
+ * detail message is set to ({@code cause==null ? null : cause.toString()})
+ * (which typically contains the class and detail message of
* cause).
*
* @param cause the cause (which is saved for later retrieval by the
- * {@link #getCause getCause()} method). (A <code>null</code> value is
+ * {@link #getCause getCause()} method). (A {@code null} value is
* permitted, and indicates that the cause is nonexistent or unknown.)
*/
public CertPathValidatorException(Throwable cause) {
@@ -117,12 +117,12 @@
}
/**
- * Creates a <code>CertPathValidatorException</code> with the specified
+ * Creates a {@code CertPathValidatorException} with the specified
* detail message and cause.
*
* @param msg the detail message
* @param cause the cause (which is saved for later retrieval by the
- * {@link #getCause getCause()} method). (A <code>null</code> value is
+ * {@link #getCause getCause()} method). (A {@code null} value is
* permitted, and indicates that the cause is nonexistent or unknown.)
*/
public CertPathValidatorException(String msg, Throwable cause) {
@@ -130,21 +130,21 @@
}
/**
- * Creates a <code>CertPathValidatorException</code> with the specified
+ * Creates a {@code CertPathValidatorException} with the specified
* detail message, cause, certification path, and index.
*
- * @param msg the detail message (or <code>null</code> if none)
- * @param cause the cause (or <code>null</code> if none)
+ * @param msg the detail message (or {@code null} if none)
+ * @param cause the cause (or {@code null} if none)
* @param certPath the certification path that was in the process of
* being validated when the error was encountered
* @param index the index of the certificate in the certification path
* that caused the error (or -1 if not applicable). Note that
- * the list of certificates in a <code>CertPath</code> is zero based.
+ * the list of certificates in a {@code CertPath} is zero based.
* @throws IndexOutOfBoundsException if the index is out of range
- * <code>(index < -1 || (certPath != null && index >=
- * certPath.getCertificates().size())</code>
- * @throws IllegalArgumentException if <code>certPath</code> is
- * <code>null</code> and <code>index</code> is not -1
+ * {@code (index < -1 || (certPath != null && index >=
+ * certPath.getCertificates().size()) }
+ * @throws IllegalArgumentException if {@code certPath} is
+ * {@code null} and {@code index} is not -1
*/
public CertPathValidatorException(String msg, Throwable cause,
CertPath certPath, int index) {
@@ -152,23 +152,23 @@
}
/**
- * Creates a <code>CertPathValidatorException</code> with the specified
+ * Creates a {@code CertPathValidatorException} with the specified
* detail message, cause, certification path, index, and reason.
*
- * @param msg the detail message (or <code>null</code> if none)
- * @param cause the cause (or <code>null</code> if none)
+ * @param msg the detail message (or {@code null} if none)
+ * @param cause the cause (or {@code null} if none)
* @param certPath the certification path that was in the process of
* being validated when the error was encountered
* @param index the index of the certificate in the certification path
* that caused the error (or -1 if not applicable). Note that
- * the list of certificates in a <code>CertPath</code> is zero based.
+ * the list of certificates in a {@code CertPath} is zero based.
* @param reason the reason the validation failed
* @throws IndexOutOfBoundsException if the index is out of range
- * <code>(index < -1 || (certPath != null && index >=
- * certPath.getCertificates().size())</code>
- * @throws IllegalArgumentException if <code>certPath</code> is
- * <code>null</code> and <code>index</code> is not -1
- * @throws NullPointerException if <code>reason</code> is <code>null</code>
+ * {@code (index < -1 || (certPath != null && index >=
+ * certPath.getCertificates().size()) }
+ * @throws IllegalArgumentException if {@code certPath} is
+ * {@code null} and {@code index} is not -1
+ * @throws NullPointerException if {@code reason} is {@code null}
*
* @since 1.7
*/
@@ -194,8 +194,8 @@
* Returns the certification path that was being validated when
* the exception was thrown.
*
- * @return the <code>CertPath</code> that was being validated when
- * the exception was thrown (or <code>null</code> if not specified)
+ * @return the {@code CertPath} that was being validated when
+ * the exception was thrown (or {@code null} if not specified)
*/
public CertPath getCertPath() {
return this.certPath;
@@ -204,7 +204,7 @@
/**
* Returns the index of the certificate in the certification path
* that caused the exception to be thrown. Note that the list of
- * certificates in a <code>CertPath</code> is zero based. If no
+ * certificates in a {@code CertPath} is zero based. If no
* index has been set, -1 is returned.
*
* @return the index that has been set, or -1 if none has been set
@@ -219,7 +219,7 @@
* {@link #getIndex}.
*
* @return the reason that the validation failed, or
- * <code>BasicReason.UNSPECIFIED</code> if a reason has not been
+ * {@code BasicReason.UNSPECIFIED} if a reason has not been
* specified
*
* @since 1.7
diff --git a/ojluni/src/main/java/java/security/cert/CertPathValidatorResult.java b/ojluni/src/main/java/java/security/cert/CertPathValidatorResult.java
index 1756db6..ae07dc4 100755
--- a/ojluni/src/main/java/java/security/cert/CertPathValidatorResult.java
+++ b/ojluni/src/main/java/java/security/cert/CertPathValidatorResult.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2000, 2001, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2000, 2013, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -41,10 +41,10 @@
public interface CertPathValidatorResult extends Cloneable {
/**
- * Makes a copy of this <code>CertPathValidatorResult</code>. Changes to the
+ * Makes a copy of this {@code CertPathValidatorResult}. Changes to the
* copy will not affect the original and vice versa.
*
- * @return a copy of this <code>CertPathValidatorResult</code>
+ * @return a copy of this {@code CertPathValidatorResult}
*/
Object clone();
}
diff --git a/ojluni/src/main/java/java/security/cert/CertPathValidatorSpi.java b/ojluni/src/main/java/java/security/cert/CertPathValidatorSpi.java
index 6dd4143..02d503c 100755
--- a/ojluni/src/main/java/java/security/cert/CertPathValidatorSpi.java
+++ b/ojluni/src/main/java/java/security/cert/CertPathValidatorSpi.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2000, 2001, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2000, 2013, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -31,23 +31,23 @@
*
* The <i>Service Provider Interface</i> (<b>SPI</b>)
* for the {@link CertPathValidator CertPathValidator} class. All
- * <code>CertPathValidator</code> implementations must include a class (the
- * SPI class) that extends this class (<code>CertPathValidatorSpi</code>)
+ * {@code CertPathValidator} implementations must include a class (the
+ * SPI class) that extends this class ({@code CertPathValidatorSpi})
* and implements all of its methods. In general, instances of this class
- * should only be accessed through the <code>CertPathValidator</code> class.
+ * should only be accessed through the {@code CertPathValidator} class.
* For details, see the Java Cryptography Architecture.
* <p>
* <b>Concurrent Access</b>
* <p>
* Instances of this class need not be protected against concurrent
* access from multiple threads. Threads that need to access a single
- * <code>CertPathValidatorSpi</code> instance concurrently should synchronize
+ * {@code CertPathValidatorSpi} instance concurrently should synchronize
* amongst themselves and provide the necessary locking before calling the
- * wrapping <code>CertPathValidator</code> object.
+ * wrapping {@code CertPathValidator} object.
* <p>
- * However, implementations of <code>CertPathValidatorSpi</code> may still
+ * However, implementations of {@code CertPathValidatorSpi} may still
* encounter concurrency issues, since multiple threads each
- * manipulating a different <code>CertPathValidatorSpi</code> instance need not
+ * manipulating a different {@code CertPathValidatorSpi} instance need not
* synchronize.
*
* @since 1.4
@@ -64,22 +64,45 @@
* Validates the specified certification path using the specified
* algorithm parameter set.
* <p>
- * The <code>CertPath</code> specified must be of a type that is
+ * The {@code CertPath} specified must be of a type that is
* supported by the validation algorithm, otherwise an
- * <code>InvalidAlgorithmParameterException</code> will be thrown. For
- * example, a <code>CertPathValidator</code> that implements the PKIX
- * algorithm validates <code>CertPath</code> objects of type X.509.
+ * {@code InvalidAlgorithmParameterException} will be thrown. For
+ * example, a {@code CertPathValidator} that implements the PKIX
+ * algorithm validates {@code CertPath} objects of type X.509.
*
- * @param certPath the <code>CertPath</code> to be validated
+ * @param certPath the {@code CertPath} to be validated
* @param params the algorithm parameters
* @return the result of the validation algorithm
- * @exception CertPathValidatorException if the <code>CertPath</code>
+ * @exception CertPathValidatorException if the {@code CertPath}
* does not validate
* @exception InvalidAlgorithmParameterException if the specified
- * parameters or the type of the specified <code>CertPath</code> are
- * inappropriate for this <code>CertPathValidator</code>
+ * parameters or the type of the specified {@code CertPath} are
+ * inappropriate for this {@code CertPathValidator}
*/
public abstract CertPathValidatorResult
engineValidate(CertPath certPath, CertPathParameters params)
throws CertPathValidatorException, InvalidAlgorithmParameterException;
+
+ /**
+ * Returns a {@code CertPathChecker} that this implementation uses to
+ * check the revocation status of certificates. A PKIX implementation
+ * returns objects of type {@code PKIXRevocationChecker}.
+ *
+ * <p>The primary purpose of this method is to allow callers to specify
+ * additional input parameters and options specific to revocation checking.
+ * See the class description of {@code CertPathValidator} for an example.
+ *
+ * <p>This method was added to version 1.8 of the Java Platform Standard
+ * Edition. In order to maintain backwards compatibility with existing
+ * service providers, this method cannot be abstract and by default throws
+ * an {@code UnsupportedOperationException}.
+ *
+ * @return a {@code CertPathChecker} that this implementation uses to
+ * check the revocation status of certificates
+ * @throws UnsupportedOperationException if this method is not supported
+ * @since 1.8
+ */
+ public CertPathChecker engineGetRevocationChecker() {
+ throw new UnsupportedOperationException();
+ }
}
diff --git a/ojluni/src/main/java/java/security/cert/PKIXCertPathChecker.java b/ojluni/src/main/java/java/security/cert/PKIXCertPathChecker.java
index 0cca284..21e01bf 100755
--- a/ojluni/src/main/java/java/security/cert/PKIXCertPathChecker.java
+++ b/ojluni/src/main/java/java/security/cert/PKIXCertPathChecker.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2000, 2003, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2000, 2013, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -30,38 +30,38 @@
/**
* An abstract class that performs one or more checks on an
- * <code>X509Certificate</code>.
+ * {@code X509Certificate}.
*
- * <p>A concrete implementation of the <code>PKIXCertPathChecker</code> class
+ * <p>A concrete implementation of the {@code PKIXCertPathChecker} class
* can be created to extend the PKIX certification path validation algorithm.
* For example, an implementation may check for and process a critical private
* extension of each certificate in a certification path.
*
- * <p>Instances of <code>PKIXCertPathChecker</code> are passed as parameters
+ * <p>Instances of {@code PKIXCertPathChecker} are passed as parameters
* using the {@link PKIXParameters#setCertPathCheckers setCertPathCheckers}
* or {@link PKIXParameters#addCertPathChecker addCertPathChecker} methods
- * of the <code>PKIXParameters</code> and <code>PKIXBuilderParameters</code>
- * class. Each of the <code>PKIXCertPathChecker</code>s {@link #check check}
+ * of the {@code PKIXParameters} and {@code PKIXBuilderParameters}
+ * class. Each of the {@code PKIXCertPathChecker}s {@link #check check}
* methods will be called, in turn, for each certificate processed by a PKIX
- * <code>CertPathValidator</code> or <code>CertPathBuilder</code>
+ * {@code CertPathValidator} or {@code CertPathBuilder}
* implementation.
*
- * <p>A <code>PKIXCertPathChecker</code> may be called multiple times on
+ * <p>A {@code PKIXCertPathChecker} may be called multiple times on
* successive certificates in a certification path. Concrete subclasses
* are expected to maintain any internal state that may be necessary to
* check successive certificates. The {@link #init init} method is used
* to initialize the internal state of the checker so that the certificates
* of a new certification path may be checked. A stateful implementation
* <b>must</b> override the {@link #clone clone} method if necessary in
- * order to allow a PKIX <code>CertPathBuilder</code> to efficiently
+ * order to allow a PKIX {@code CertPathBuilder} to efficiently
* backtrack and try other paths. In these situations, the
- * <code>CertPathBuilder</code> is able to restore prior path validation
- * states by restoring the cloned <code>PKIXCertPathChecker</code>s.
+ * {@code CertPathBuilder} is able to restore prior path validation
+ * states by restoring the cloned {@code PKIXCertPathChecker}s.
*
* <p>The order in which the certificates are presented to the
- * <code>PKIXCertPathChecker</code> may be either in the forward direction
+ * {@code PKIXCertPathChecker} may be either in the forward direction
* (from target to most-trusted CA) or in the reverse direction (from
- * most-trusted CA to target). A <code>PKIXCertPathChecker</code> implementation
+ * most-trusted CA to target). A {@code PKIXCertPathChecker} implementation
* <b>must</b> support reverse checking (the ability to perform its checks when
* it is presented with certificates in the reverse direction) and <b>may</b>
* support forward checking (the ability to perform its checks when it is
@@ -87,7 +87,8 @@
* @author Yassir Elley
* @author Sean Mullan
*/
-public abstract class PKIXCertPathChecker implements Cloneable {
+public abstract class PKIXCertPathChecker
+ implements CertPathChecker, Cloneable {
/**
* Default constructor.
@@ -95,52 +96,54 @@
protected PKIXCertPathChecker() {}
/**
- * Initializes the internal state of this <code>PKIXCertPathChecker</code>.
+ * Initializes the internal state of this {@code PKIXCertPathChecker}.
* <p>
- * The <code>forward</code> flag specifies the order that
+ * The {@code forward} flag specifies the order that
* certificates will be passed to the {@link #check check} method
- * (forward or reverse). A <code>PKIXCertPathChecker</code> <b>must</b>
+ * (forward or reverse). A {@code PKIXCertPathChecker} <b>must</b>
* support reverse checking and <b>may</b> support forward checking.
*
* @param forward the order that certificates are presented to
- * the <code>check</code> method. If <code>true</code>, certificates
+ * the {@code check} method. If {@code true}, certificates
* are presented from target to most-trusted CA (forward); if
- * <code>false</code>, from most-trusted CA to target (reverse).
+ * {@code false}, from most-trusted CA to target (reverse).
* @throws CertPathValidatorException if this
- * <code>PKIXCertPathChecker</code> is unable to check certificates in
+ * {@code PKIXCertPathChecker} is unable to check certificates in
* the specified order; it should never be thrown if the forward flag
* is false since reverse checking must be supported
*/
+ @Override
public abstract void init(boolean forward)
throws CertPathValidatorException;
/**
* Indicates if forward checking is supported. Forward checking refers
- * to the ability of the <code>PKIXCertPathChecker</code> to perform
- * its checks when certificates are presented to the <code>check</code>
+ * to the ability of the {@code PKIXCertPathChecker} to perform
+ * its checks when certificates are presented to the {@code check}
* method in the forward direction (from target to most-trusted CA).
*
- * @return <code>true</code> if forward checking is supported,
- * <code>false</code> otherwise
+ * @return {@code true} if forward checking is supported,
+ * {@code false} otherwise
*/
+ @Override
public abstract boolean isForwardCheckingSupported();
/**
- * Returns an immutable <code>Set</code> of X.509 certificate extensions
- * that this <code>PKIXCertPathChecker</code> supports (i.e. recognizes, is
- * able to process), or <code>null</code> if no extensions are supported.
+ * Returns an immutable {@code Set} of X.509 certificate extensions
+ * that this {@code PKIXCertPathChecker} supports (i.e. recognizes, is
+ * able to process), or {@code null} if no extensions are supported.
* <p>
- * Each element of the set is a <code>String</code> representing the
+ * Each element of the set is a {@code String} representing the
* Object Identifier (OID) of the X.509 extension that is supported.
* The OID is represented by a set of nonnegative integers separated by
* periods.
* <p>
- * All X.509 certificate extensions that a <code>PKIXCertPathChecker</code>
+ * All X.509 certificate extensions that a {@code PKIXCertPathChecker}
* might possibly be able to process should be included in the set.
*
- * @return an immutable <code>Set</code> of X.509 extension OIDs (in
- * <code>String</code> format) supported by this
- * <code>PKIXCertPathChecker</code>, or <code>null</code> if no
+ * @return an immutable {@code Set} of X.509 extension OIDs (in
+ * {@code String} format) supported by this
+ * {@code PKIXCertPathChecker}, or {@code null} if no
* extensions are supported
*/
public abstract Set<String> getSupportedExtensions();
@@ -150,10 +153,10 @@
* state and removes any critical extensions that it processes from the
* specified collection of OID strings that represent the unresolved
* critical extensions. The certificates are presented in the order
- * specified by the <code>init</code> method.
+ * specified by the {@code init} method.
*
- * @param cert the <code>Certificate</code> to be checked
- * @param unresolvedCritExts a <code>Collection</code> of OID strings
+ * @param cert the {@code Certificate} to be checked
+ * @param unresolvedCritExts a {@code Collection} of OID strings
* representing the current set of unresolved critical extensions
* @exception CertPathValidatorException if the specified certificate does
* not pass the check
@@ -163,19 +166,31 @@
throws CertPathValidatorException;
/**
- * Returns a clone of this object. Calls the <code>Object.clone()</code>
+ * {@inheritDoc}
+ *
+ * <p>This implementation calls
+ * {@code check(cert, java.util.Collections.<String>emptySet())}.
+ */
+ @Override
+ public void check(Certificate cert) throws CertPathValidatorException {
+ check(cert, java.util.Collections.<String>emptySet());
+ }
+
+ /**
+ * Returns a clone of this object. Calls the {@code Object.clone()}
* method.
* All subclasses which maintain state must support and
* override this method, if necessary.
*
- * @return a copy of this <code>PKIXCertPathChecker</code>
+ * @return a copy of this {@code PKIXCertPathChecker}
*/
+ @Override
public Object clone() {
try {
return super.clone();
} catch (CloneNotSupportedException e) {
/* Cannot happen */
- throw new InternalError(e.toString());
+ throw new InternalError(e.toString(), e);
}
}
}
diff --git a/ojluni/src/main/java/java/security/cert/PKIXRevocationChecker.java b/ojluni/src/main/java/java/security/cert/PKIXRevocationChecker.java
new file mode 100644
index 0000000..054d964
--- /dev/null
+++ b/ojluni/src/main/java/java/security/cert/PKIXRevocationChecker.java
@@ -0,0 +1,311 @@
+/*
+ * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * 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 java.security.cert;
+
+import java.net.URI;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Map.Entry;
+import java.util.Set;
+
+/**
+ * A {@code PKIXCertPathChecker} for checking the revocation status of
+ * certificates with the PKIX algorithm.
+ *
+ * <p>A {@code PKIXRevocationChecker} checks the revocation status of
+ * certificates with the Online Certificate Status Protocol (OCSP) or
+ * Certificate Revocation Lists (CRLs). OCSP is described in RFC 2560 and
+ * is a network protocol for determining the status of a certificate. A CRL
+ * is a time-stamped list identifying revoked certificates, and RFC 5280
+ * describes an algorithm for determining the revocation status of certificates
+ * using CRLs.
+ *
+ * <p>Each {@code PKIXRevocationChecker} must be able to check the revocation
+ * status of certificates with OCSP and CRLs. By default, OCSP is the
+ * preferred mechanism for checking revocation status, with CRLs as the
+ * fallback mechanism. However, this preference can be switched to CRLs with
+ * the {@link Option#PREFER_CRLS PREFER_CRLS} option. In addition, the fallback
+ * mechanism can be disabled with the {@link Option#NO_FALLBACK NO_FALLBACK}
+ * option.
+ *
+ * <p>A {@code PKIXRevocationChecker} is obtained by calling the
+ * {@link CertPathValidator#getRevocationChecker getRevocationChecker} method
+ * of a PKIX {@code CertPathValidator}. Additional parameters and options
+ * specific to revocation can be set (by calling the
+ * {@link #setOcspResponder setOcspResponder} method for instance). The
+ * {@code PKIXRevocationChecker} is added to a {@code PKIXParameters} object
+ * using the {@link PKIXParameters#addCertPathChecker addCertPathChecker}
+ * or {@link PKIXParameters#setCertPathCheckers setCertPathCheckers} method,
+ * and then the {@code PKIXParameters} is passed along with the {@code CertPath}
+ * to be validated to the {@link CertPathValidator#validate validate} method
+ * of a PKIX {@code CertPathValidator}. When supplying a revocation checker in
+ * this manner, it will be used to check revocation irrespective of the setting
+ * of the {@link PKIXParameters#isRevocationEnabled RevocationEnabled} flag.
+ * Similarly, a {@code PKIXRevocationChecker} may be added to a
+ * {@code PKIXBuilderParameters} object for use with a PKIX
+ * {@code CertPathBuilder}.
+ *
+ * <p>Note that when a {@code PKIXRevocationChecker} is added to
+ * {@code PKIXParameters}, it clones the {@code PKIXRevocationChecker};
+ * thus any subsequent modifications to the {@code PKIXRevocationChecker}
+ * have no effect.
+ *
+ * <p>Any parameter that is not set (or is set to {@code null}) will be set to
+ * the default value for that parameter.
+ *
+ * <p><b>Concurrent Access</b>
+ *
+ * <p>Unless otherwise specified, the methods defined in this class are not
+ * thread-safe. Multiple threads that need to access a single object
+ * concurrently should synchronize amongst themselves and provide the
+ * necessary locking. Multiple threads each manipulating separate objects
+ * need not synchronize.
+ *
+ * @since 1.8
+ */
+public abstract class PKIXRevocationChecker extends PKIXCertPathChecker {
+ private URI ocspResponder;
+ private X509Certificate ocspResponderCert;
+ private List<Extension> ocspExtensions = Collections.<Extension>emptyList();
+ private Map<X509Certificate, byte[]> ocspResponses = Collections.emptyMap();
+ private Set<Option> options = Collections.emptySet();
+
+ /**
+ * Default constructor.
+ */
+ protected PKIXRevocationChecker() {}
+
+ /**
+ * Sets the URI that identifies the location of the OCSP responder. This
+ * overrides the {@code ocsp.responderURL} security property and any
+ * responder specified in a certificate's Authority Information Access
+ * Extension, as defined in RFC 5280.
+ *
+ * @param uri the responder URI
+ */
+ public void setOcspResponder(URI uri) {
+ this.ocspResponder = uri;
+ }
+
+ /**
+ * Gets the URI that identifies the location of the OCSP responder. This
+ * overrides the {@code ocsp.responderURL} security property. If this
+ * parameter or the {@code ocsp.responderURL} property is not set, the
+ * location is determined from the certificate's Authority Information
+ * Access Extension, as defined in RFC 5280.
+ *
+ * @return the responder URI, or {@code null} if not set
+ */
+ public URI getOcspResponder() {
+ return ocspResponder;
+ }
+
+ /**
+ * Sets the OCSP responder's certificate. This overrides the
+ * {@code ocsp.responderCertSubjectName},
+ * {@code ocsp.responderCertIssuerName},
+ * and {@code ocsp.responderCertSerialNumber} security properties.
+ *
+ * @param cert the responder's certificate
+ */
+ public void setOcspResponderCert(X509Certificate cert) {
+ this.ocspResponderCert = cert;
+ }
+
+ /**
+ * Gets the OCSP responder's certificate. This overrides the
+ * {@code ocsp.responderCertSubjectName},
+ * {@code ocsp.responderCertIssuerName},
+ * and {@code ocsp.responderCertSerialNumber} security properties. If this
+ * parameter or the aforementioned properties are not set, then the
+ * responder's certificate is determined as specified in RFC 2560.
+ *
+ * @return the responder's certificate, or {@code null} if not set
+ */
+ public X509Certificate getOcspResponderCert() {
+ return ocspResponderCert;
+ }
+
+ // request extensions; single extensions not supported
+ /**
+ * Sets the optional OCSP request extensions.
+ *
+ * @param extensions a list of extensions. The list is copied to protect
+ * against subsequent modification.
+ */
+ public void setOcspExtensions(List<Extension> extensions)
+ {
+ this.ocspExtensions = (extensions == null)
+ ? Collections.<Extension>emptyList()
+ : new ArrayList<Extension>(extensions);
+ }
+
+ /**
+ * Gets the optional OCSP request extensions.
+ *
+ * @return an unmodifiable list of extensions. The list is empty if no
+ * extensions have been specified.
+ */
+ public List<Extension> getOcspExtensions() {
+ return Collections.unmodifiableList(ocspExtensions);
+ }
+
+ /**
+ * Sets the OCSP responses. These responses are used to determine
+ * the revocation status of the specified certificates when OCSP is used.
+ *
+ * @param responses a map of OCSP responses. Each key is an
+ * {@code X509Certificate} that maps to the corresponding
+ * DER-encoded OCSP response for that certificate. A deep copy of
+ * the map is performed to protect against subsequent modification.
+ */
+ public void setOcspResponses(Map<X509Certificate, byte[]> responses)
+ {
+ if (responses == null) {
+ this.ocspResponses = Collections.<X509Certificate, byte[]>emptyMap();
+ } else {
+ Map<X509Certificate, byte[]> copy = new HashMap<>(responses.size());
+ for (Map.Entry<X509Certificate, byte[]> e : responses.entrySet()) {
+ copy.put(e.getKey(), e.getValue().clone());
+ }
+ this.ocspResponses = copy;
+ }
+ }
+
+ /**
+ * Gets the OCSP responses. These responses are used to determine
+ * the revocation status of the specified certificates when OCSP is used.
+ *
+ * @return a map of OCSP responses. Each key is an
+ * {@code X509Certificate} that maps to the corresponding
+ * DER-encoded OCSP response for that certificate. A deep copy of
+ * the map is returned to protect against subsequent modification.
+ * Returns an empty map if no responses have been specified.
+ */
+ public Map<X509Certificate, byte[]> getOcspResponses() {
+ Map<X509Certificate, byte[]> copy = new HashMap<>(ocspResponses.size());
+ for (Map.Entry<X509Certificate, byte[]> e : ocspResponses.entrySet()) {
+ copy.put(e.getKey(), e.getValue().clone());
+ }
+ return copy;
+ }
+
+ /**
+ * Sets the revocation options.
+ *
+ * @param options a set of revocation options. The set is copied to protect
+ * against subsequent modification.
+ */
+ public void setOptions(Set<Option> options) {
+ this.options = (options == null)
+ ? Collections.<Option>emptySet()
+ : new HashSet<Option>(options);
+ }
+
+ /**
+ * Gets the revocation options.
+ *
+ * @return an unmodifiable set of revocation options. The set is empty if
+ * no options have been specified.
+ */
+ public Set<Option> getOptions() {
+ return Collections.unmodifiableSet(options);
+ }
+
+ /**
+ * Returns a list containing the exceptions that are ignored by the
+ * revocation checker when the {@link Option#SOFT_FAIL SOFT_FAIL} option
+ * is set. The list is cleared each time {@link #init init} is called.
+ * The list is ordered in ascending order according to the certificate
+ * index returned by {@link CertPathValidatorException#getIndex getIndex}
+ * method of each entry.
+ * <p>
+ * An implementation of {@code PKIXRevocationChecker} is responsible for
+ * adding the ignored exceptions to the list.
+ *
+ * @return an unmodifiable list containing the ignored exceptions. The list
+ * is empty if no exceptions have been ignored.
+ */
+ public abstract List<CertPathValidatorException> getSoftFailExceptions();
+
+ @Override
+ public PKIXRevocationChecker clone() {
+ PKIXRevocationChecker copy = (PKIXRevocationChecker)super.clone();
+ copy.ocspExtensions = new ArrayList<>(ocspExtensions);
+ copy.ocspResponses = new HashMap<>(ocspResponses);
+ // deep-copy the encoded responses, since they are mutable
+ for (Map.Entry<X509Certificate, byte[]> entry :
+ copy.ocspResponses.entrySet())
+ {
+ byte[] encoded = entry.getValue();
+ entry.setValue(encoded.clone());
+ }
+ copy.options = new HashSet<>(options);
+ return copy;
+ }
+
+ /**
+ * Various revocation options that can be specified for the revocation
+ * checking mechanism.
+ */
+ public enum Option {
+ /**
+ * Only check the revocation status of end-entity certificates.
+ */
+ ONLY_END_ENTITY,
+ /**
+ * Prefer CRLs to OSCP. The default behavior is to prefer OCSP. Each
+ * PKIX implementation should document further details of their
+ * specific preference rules and fallback policies.
+ */
+ PREFER_CRLS,
+ /**
+ * Disable the fallback mechanism.
+ */
+ NO_FALLBACK,
+ /**
+ * Allow revocation check to succeed if the revocation status cannot be
+ * determined for one of the following reasons:
+ * <ul>
+ * <li>The CRL or OCSP response cannot be obtained because of a
+ * network error.
+ * <li>The OCSP responder returns one of the following errors
+ * specified in section 2.3 of RFC 2560: internalError or tryLater.
+ * </ul><br>
+ * Note that these conditions apply to both OCSP and CRLs, and unless
+ * the {@code NO_FALLBACK} option is set, the revocation check is
+ * allowed to succeed only if both mechanisms fail under one of the
+ * conditions as stated above.
+ * Exceptions that cause the network errors are ignored but can be
+ * later retrieved by calling the
+ * {@link #getSoftFailExceptions getSoftFailExceptions} method.
+ */
+ SOFT_FAIL
+ }
+}
diff --git a/ojluni/src/main/java/java/security/cert/X509Certificate.java b/ojluni/src/main/java/java/security/cert/X509Certificate.java
index cb0e548..0aba5da 100755
--- a/ojluni/src/main/java/java/security/cert/X509Certificate.java
+++ b/ojluni/src/main/java/java/security/cert/X509Certificate.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1997, 2010, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -26,8 +26,7 @@
package java.security.cert;
import java.math.BigInteger;
-import java.security.Principal;
-import java.security.PublicKey;
+import java.security.*;
import java.util.Collection;
import java.util.Date;
import java.util.List;
@@ -67,7 +66,7 @@
* <a href="http://www.ietf.org/rfc/rfc3280.txt">RFC 3280: Internet X.509
* Public Key Infrastructure Certificate and CRL Profile</a>.
* <p>
- * The ASN.1 definition of <code>tbsCertificate</code> is:
+ * The ASN.1 definition of {@code tbsCertificate} is:
* <pre>
* TBSCertificate ::= SEQUENCE {
* version [0] EXPLICIT Version DEFAULT v1,
@@ -89,15 +88,9 @@
* Certificates are instantiated using a certificate factory. The following is
* an example of how to instantiate an X.509 certificate:
* <pre>
- * InputStream inStream = null;
- * try {
- * inStream = new FileInputStream("fileName-of-cert");
+ * try (InputStream inStream = new FileInputStream("fileName-of-cert")) {
* CertificateFactory cf = CertificateFactory.getInstance("X.509");
* X509Certificate cert = (X509Certificate)cf.generateCertificate(inStream);
- * } finally {
- * if (inStream != null) {
- * inStream.close();
- * }
* }
* </pre>
*
@@ -133,10 +126,12 @@
* is valid. It is defined in
* ASN.1 as:
* <pre>
- * validity Validity<p>
+ * validity Validity
+ *
* Validity ::= SEQUENCE {
* notBefore CertificateValidityDate,
- * notAfter CertificateValidityDate }<p>
+ * notAfter CertificateValidityDate }
+ *
* CertificateValidityDate ::= CHOICE {
* utcTime UTCTime,
* generalTime GeneralizedTime }
@@ -158,9 +153,9 @@
* is valid at that date/time.
*
* @exception CertificateExpiredException if the certificate has expired
- * with respect to the <code>date</code> supplied.
+ * with respect to the {@code date} supplied.
* @exception CertificateNotYetValidException if the certificate is not
- * yet valid with respect to the <code>date</code> supplied.
+ * yet valid with respect to the {@code date} supplied.
*
* @see #checkValidity()
*/
@@ -168,11 +163,12 @@
throws CertificateExpiredException, CertificateNotYetValidException;
/**
- * Gets the <code>version</code> (version number) value from the
+ * Gets the {@code version} (version number) value from the
* certificate.
* The ASN.1 definition for this is:
* <pre>
- * version [0] EXPLICIT Version DEFAULT v1<p>
+ * version [0] EXPLICIT Version DEFAULT v1
+ *
* Version ::= INTEGER { v1(0), v2(1), v3(2) }
* </pre>
* @return the version number, i.e. 1, 2 or 3.
@@ -180,14 +176,14 @@
public abstract int getVersion();
/**
- * Gets the <code>serialNumber</code> value from the certificate.
+ * Gets the {@code serialNumber} value from the certificate.
* The serial number is an integer assigned by the certification
* authority to each certificate. It must be unique for each
* certificate issued by a given CA (i.e., the issuer name and
* serial number identify a unique certificate).
* The ASN.1 definition for this is:
* <pre>
- * serialNumber CertificateSerialNumber<p>
+ * serialNumber CertificateSerialNumber
*
* CertificateSerialNumber ::= INTEGER
* </pre>
@@ -198,12 +194,12 @@
/**
* <strong>Denigrated</strong>, replaced by {@linkplain
- * #getIssuerX500Principal()}. This method returns the <code>issuer</code>
+ * #getIssuerX500Principal()}. This method returns the {@code issuer}
* as an implementation specific Principal object, which should not be
* relied upon by portable code.
*
* <p>
- * Gets the <code>issuer</code> (issuer distinguished name) value from
+ * Gets the {@code issuer} (issuer distinguished name) value from
* the certificate. The issuer name identifies the entity that signed (and
* issued) the certificate.
*
@@ -211,7 +207,7 @@
* X.500 distinguished name (DN).
* The ASN.1 definition for this is:
* <pre>
- * issuer Name<p>
+ * issuer Name
*
* Name ::= CHOICE { RDNSequence }
* RDNSequence ::= SEQUENCE OF RelativeDistinguishedName
@@ -224,14 +220,14 @@
* AttributeType ::= OBJECT IDENTIFIER
* AttributeValue ::= ANY
* </pre>
- * The <code>Name</code> describes a hierarchical name composed of
+ * The {@code Name} describes a hierarchical name composed of
* attributes,
* such as country name, and corresponding values, such as US.
- * The type of the <code>AttributeValue</code> component is determined by
- * the <code>AttributeType</code>; in general it will be a
- * <code>directoryString</code>. A <code>directoryString</code> is usually
- * one of <code>PrintableString</code>,
- * <code>TeletexString</code> or <code>UniversalString</code>.
+ * The type of the {@code AttributeValue} component is determined by
+ * the {@code AttributeType}; in general it will be a
+ * {@code directoryString}. A {@code directoryString} is usually
+ * one of {@code PrintableString},
+ * {@code TeletexString} or {@code UniversalString}.
*
* @return a Principal whose name is the issuer distinguished name.
*/
@@ -239,11 +235,11 @@
/**
* Returns the issuer (issuer distinguished name) value from the
- * certificate as an <code>X500Principal</code>.
+ * certificate as an {@code X500Principal}.
* <p>
* It is recommended that subclasses override this method.
*
- * @return an <code>X500Principal</code> representing the issuer
+ * @return an {@code X500Principal} representing the issuer
* distinguished name
* @since 1.4
*/
@@ -256,22 +252,22 @@
/**
* <strong>Denigrated</strong>, replaced by {@linkplain
- * #getSubjectX500Principal()}. This method returns the <code>subject</code>
+ * #getSubjectX500Principal()}. This method returns the {@code subject}
* as an implementation specific Principal object, which should not be
* relied upon by portable code.
*
* <p>
- * Gets the <code>subject</code> (subject distinguished name) value
- * from the certificate. If the <code>subject</code> value is empty,
- * then the <code>getName()</code> method of the returned
- * <code>Principal</code> object returns an empty string ("").
+ * Gets the {@code subject} (subject distinguished name) value
+ * from the certificate. If the {@code subject} value is empty,
+ * then the {@code getName()} method of the returned
+ * {@code Principal} object returns an empty string ("").
*
* <p> The ASN.1 definition for this is:
* <pre>
* subject Name
* </pre>
*
- * <p>See {@link #getIssuerDN() getIssuerDN} for <code>Name</code>
+ * <p>See {@link #getIssuerDN() getIssuerDN} for {@code Name}
* and other relevant definitions.
*
* @return a Principal whose name is the subject name.
@@ -280,13 +276,13 @@
/**
* Returns the subject (subject distinguished name) value from the
- * certificate as an <code>X500Principal</code>. If the subject value
- * is empty, then the <code>getName()</code> method of the returned
- * <code>X500Principal</code> object returns an empty string ("").
+ * certificate as an {@code X500Principal}. If the subject value
+ * is empty, then the {@code getName()} method of the returned
+ * {@code X500Principal} object returns an empty string ("").
* <p>
* It is recommended that subclasses override this method.
*
- * @return an <code>X500Principal</code> representing the subject
+ * @return an {@code X500Principal} representing the subject
* distinguished name
* @since 1.4
*/
@@ -298,15 +294,16 @@
}
/**
- * Gets the <code>notBefore</code> date from the validity period of
+ * Gets the {@code notBefore} date from the validity period of
* the certificate.
* The relevant ASN.1 definitions are:
* <pre>
- * validity Validity<p>
+ * validity Validity
*
* Validity ::= SEQUENCE {
* notBefore CertificateValidityDate,
- * notAfter CertificateValidityDate }<p>
+ * notAfter CertificateValidityDate }
+ *
* CertificateValidityDate ::= CHOICE {
* utcTime UTCTime,
* generalTime GeneralizedTime }
@@ -318,7 +315,7 @@
public abstract Date getNotBefore();
/**
- * Gets the <code>notAfter</code> date from the validity period of
+ * Gets the {@code notAfter} date from the validity period of
* the certificate. See {@link #getNotBefore() getNotBefore}
* for relevant ASN.1 definitions.
*
@@ -329,7 +326,7 @@
/**
* Gets the DER-encoded certificate information, the
- * <code>tbsCertificate</code> from this certificate.
+ * {@code tbsCertificate} from this certificate.
* This can be used to verify the signature independently.
*
* @return the DER-encoded certificate information.
@@ -339,7 +336,7 @@
throws CertificateEncodingException;
/**
- * Gets the <code>signature</code> value (the raw signature bits) from
+ * Gets the {@code signature} value (the raw signature bits) from
* the certificate.
* The ASN.1 definition for this is:
* <pre>
@@ -355,7 +352,8 @@
* signature algorithm. An example is the string "SHA256withRSA".
* The ASN.1 definition for this is:
* <pre>
- * signatureAlgorithm AlgorithmIdentifier<p>
+ * signatureAlgorithm AlgorithmIdentifier
+ *
* AlgorithmIdentifier ::= SEQUENCE {
* algorithm OBJECT IDENTIFIER,
* parameters ANY DEFINED BY algorithm OPTIONAL }
@@ -364,7 +362,7 @@
* -- algorithm object identifier value
* </pre>
*
- * <p>The algorithm name is determined from the <code>algorithm</code>
+ * <p>The algorithm name is determined from the {@code algorithm}
* OID string.
*
* @return the signature algorithm name.
@@ -407,7 +405,7 @@
public abstract byte[] getSigAlgParams();
/**
- * Gets the <code>issuerUniqueID</code> value from the certificate.
+ * Gets the {@code issuerUniqueID} value from the certificate.
* The issuer unique identifier is present in the certificate
* to handle the possibility of reuse of issuer names over time.
* RFC 3280 recommends that names not be reused and that
@@ -417,7 +415,8 @@
*
* <p>The ASN.1 definition for this is:
* <pre>
- * issuerUniqueID [1] IMPLICIT UniqueIdentifier OPTIONAL<p>
+ * issuerUniqueID [1] IMPLICIT UniqueIdentifier OPTIONAL
+ *
* UniqueIdentifier ::= BIT STRING
* </pre>
*
@@ -427,11 +426,12 @@
public abstract boolean[] getIssuerUniqueID();
/**
- * Gets the <code>subjectUniqueID</code> value from the certificate.
+ * Gets the {@code subjectUniqueID} value from the certificate.
*
* <p>The ASN.1 definition for this is:
* <pre>
- * subjectUniqueID [2] IMPLICIT UniqueIdentifier OPTIONAL<p>
+ * subjectUniqueID [2] IMPLICIT UniqueIdentifier OPTIONAL
+ *
* UniqueIdentifier ::= BIT STRING
* </pre>
*
@@ -442,7 +442,7 @@
/**
* Gets a boolean array representing bits of
- * the <code>KeyUsage</code> extension, (OID = 2.5.29.15).
+ * the {@code KeyUsage} extension, (OID = 2.5.29.15).
* The key usage extension defines the purpose (e.g., encipherment,
* signature, certificate signing) of the key contained in the
* certificate.
@@ -474,16 +474,16 @@
/**
* Gets an unmodifiable list of Strings representing the OBJECT
- * IDENTIFIERs of the <code>ExtKeyUsageSyntax</code> field of the
+ * IDENTIFIERs of the {@code ExtKeyUsageSyntax} field of the
* extended key usage extension, (OID = 2.5.29.37). It indicates
* one or more purposes for which the certified public key may be
* used, in addition to or in place of the basic purposes
* indicated in the key usage extension field. The ASN.1
* definition for this is:
* <pre>
- * ExtKeyUsageSyntax ::= SEQUENCE SIZE (1..MAX) OF KeyPurposeId<p>
+ * ExtKeyUsageSyntax ::= SEQUENCE SIZE (1..MAX) OF KeyPurposeId
*
- * KeyPurposeId ::= OBJECT IDENTIFIER<p>
+ * KeyPurposeId ::= OBJECT IDENTIFIER
* </pre>
*
* Key purposes may be defined by any organization with a
@@ -493,7 +493,7 @@
* <p>
* This method was added to version 1.4 of the Java 2 Platform Standard
* Edition. In order to maintain backwards compatibility with existing
- * service providers, this method is not <code>abstract</code>
+ * service providers, this method is not {@code abstract}
* and it provides a default implementation. Subclasses
* should override this method with a correct implementation.
*
@@ -510,13 +510,13 @@
/**
* Gets the certificate constraints path length from the
- * critical <code>BasicConstraints</code> extension, (OID = 2.5.29.19).
+ * critical {@code BasicConstraints} extension, (OID = 2.5.29.19).
* <p>
* The basic constraints extension identifies whether the subject
* of the certificate is a Certificate Authority (CA) and
* how deep a certification path may exist through that CA. The
- * <code>pathLenConstraint</code> field (see below) is meaningful
- * only if <code>cA</code> is set to TRUE. In this case, it gives the
+ * {@code pathLenConstraint} field (see below) is meaningful
+ * only if {@code cA} is set to TRUE. In this case, it gives the
* maximum number of CA certificates that may follow this certificate in a
* certification path. A value of zero indicates that only an end-entity
* certificate may follow in the path.
@@ -528,21 +528,21 @@
* pathLenConstraint INTEGER (0..MAX) OPTIONAL }
* </pre>
*
- * @return the value of <code>pathLenConstraint</code> if the
+ * @return the value of {@code pathLenConstraint} if the
* BasicConstraints extension is present in the certificate and the
* subject of the certificate is a CA, otherwise -1.
* If the subject of the certificate is a CA and
- * <code>pathLenConstraint</code> does not appear,
- * <code>Integer.MAX_VALUE</code> is returned to indicate that there is no
+ * {@code pathLenConstraint} does not appear,
+ * {@code Integer.MAX_VALUE} is returned to indicate that there is no
* limit to the allowed length of the certification path.
*/
public abstract int getBasicConstraints();
/**
* Gets an immutable collection of subject alternative names from the
- * <code>SubjectAltName</code> extension, (OID = 2.5.29.17).
+ * {@code SubjectAltName} extension, (OID = 2.5.29.17).
* <p>
- * The ASN.1 definition of the <code>SubjectAltName</code> extension is:
+ * The ASN.1 definition of the {@code SubjectAltName} extension is:
* <pre>
* SubjectAltName ::= GeneralNames
*
@@ -560,23 +560,23 @@
* registeredID [8] OBJECT IDENTIFIER}
* </pre>
* <p>
- * If this certificate does not contain a <code>SubjectAltName</code>
- * extension, <code>null</code> is returned. Otherwise, a
- * <code>Collection</code> is returned with an entry representing each
- * <code>GeneralName</code> included in the extension. Each entry is a
- * <code>List</code> whose first entry is an <code>Integer</code>
- * (the name type, 0-8) and whose second entry is a <code>String</code>
+ * If this certificate does not contain a {@code SubjectAltName}
+ * extension, {@code null} is returned. Otherwise, a
+ * {@code Collection} is returned with an entry representing each
+ * {@code GeneralName} included in the extension. Each entry is a
+ * {@code List} whose first entry is an {@code Integer}
+ * (the name type, 0-8) and whose second entry is a {@code String}
* or a byte array (the name, in string or ASN.1 DER encoded form,
* respectively).
* <p>
* <a href="http://www.ietf.org/rfc/rfc822.txt">RFC 822</a>, DNS, and URI
- * names are returned as <code>String</code>s,
+ * names are returned as {@code String}s,
* using the well-established string formats for those types (subject to
* the restrictions included in RFC 3280). IPv4 address names are
* returned using dotted quad notation. IPv6 address names are returned
* in the form "a1:a2:...:a8", where a1-a8 are hexadecimal values
* representing the eight 16-bit pieces of the address. OID names are
- * returned as <code>String</code>s represented as a series of nonnegative
+ * returned as {@code String}s represented as a series of nonnegative
* integers separated by periods. And directory names (distinguished names)
* are returned in <a href="http://www.ietf.org/rfc/rfc2253.txt">
* RFC 2253</a> string format. No standard string format is
@@ -584,19 +584,19 @@
* other type of names. They are returned as byte arrays
* containing the ASN.1 DER encoded form of the name.
* <p>
- * Note that the <code>Collection</code> returned may contain more
+ * Note that the {@code Collection} returned may contain more
* than one name of the same type. Also, note that the returned
- * <code>Collection</code> is immutable and any entries containing byte
+ * {@code Collection} is immutable and any entries containing byte
* arrays are cloned to protect against subsequent modifications.
* <p>
* This method was added to version 1.4 of the Java 2 Platform Standard
* Edition. In order to maintain backwards compatibility with existing
- * service providers, this method is not <code>abstract</code>
+ * service providers, this method is not {@code abstract}
* and it provides a default implementation. Subclasses
* should override this method with a correct implementation.
*
- * @return an immutable <code>Collection</code> of subject alternative
- * names (or <code>null</code>)
+ * @return an immutable {@code Collection} of subject alternative
+ * names (or {@code null})
* @throws CertificateParsingException if the extension cannot be decoded
* @since 1.4
*/
@@ -607,38 +607,38 @@
/**
* Gets an immutable collection of issuer alternative names from the
- * <code>IssuerAltName</code> extension, (OID = 2.5.29.18).
+ * {@code IssuerAltName} extension, (OID = 2.5.29.18).
* <p>
- * The ASN.1 definition of the <code>IssuerAltName</code> extension is:
+ * The ASN.1 definition of the {@code IssuerAltName} extension is:
* <pre>
* IssuerAltName ::= GeneralNames
* </pre>
- * The ASN.1 definition of <code>GeneralNames</code> is defined
+ * The ASN.1 definition of {@code GeneralNames} is defined
* in {@link #getSubjectAlternativeNames getSubjectAlternativeNames}.
* <p>
- * If this certificate does not contain an <code>IssuerAltName</code>
- * extension, <code>null</code> is returned. Otherwise, a
- * <code>Collection</code> is returned with an entry representing each
- * <code>GeneralName</code> included in the extension. Each entry is a
- * <code>List</code> whose first entry is an <code>Integer</code>
- * (the name type, 0-8) and whose second entry is a <code>String</code>
+ * If this certificate does not contain an {@code IssuerAltName}
+ * extension, {@code null} is returned. Otherwise, a
+ * {@code Collection} is returned with an entry representing each
+ * {@code GeneralName} included in the extension. Each entry is a
+ * {@code List} whose first entry is an {@code Integer}
+ * (the name type, 0-8) and whose second entry is a {@code String}
* or a byte array (the name, in string or ASN.1 DER encoded form,
* respectively). For more details about the formats used for each
- * name type, see the <code>getSubjectAlternativeNames</code> method.
+ * name type, see the {@code getSubjectAlternativeNames} method.
* <p>
- * Note that the <code>Collection</code> returned may contain more
+ * Note that the {@code Collection} returned may contain more
* than one name of the same type. Also, note that the returned
- * <code>Collection</code> is immutable and any entries containing byte
+ * {@code Collection} is immutable and any entries containing byte
* arrays are cloned to protect against subsequent modifications.
* <p>
* This method was added to version 1.4 of the Java 2 Platform Standard
* Edition. In order to maintain backwards compatibility with existing
- * service providers, this method is not <code>abstract</code>
+ * service providers, this method is not {@code abstract}
* and it provides a default implementation. Subclasses
* should override this method with a correct implementation.
*
- * @return an immutable <code>Collection</code> of issuer alternative
- * names (or <code>null</code>)
+ * @return an immutable {@code Collection} of issuer alternative
+ * names (or {@code null})
* @throws CertificateParsingException if the extension cannot be decoded
* @since 1.4
*/
@@ -646,4 +646,33 @@
throws CertificateParsingException {
return X509CertImpl.getIssuerAlternativeNames(this);
}
+
+ /**
+ * Verifies that this certificate was signed using the
+ * private key that corresponds to the specified public key.
+ * This method uses the signature verification engine
+ * supplied by the specified provider. Note that the specified
+ * Provider object does not have to be registered in the provider list.
+ *
+ * This method was added to version 1.8 of the Java Platform Standard
+ * Edition. In order to maintain backwards compatibility with existing
+ * service providers, this method is not {@code abstract}
+ * and it provides a default implementation.
+ *
+ * @param key the PublicKey used to carry out the verification.
+ * @param sigProvider the signature provider.
+ *
+ * @exception NoSuchAlgorithmException on unsupported signature
+ * algorithms.
+ * @exception InvalidKeyException on incorrect key.
+ * @exception SignatureException on signature errors.
+ * @exception CertificateException on encoding errors.
+ * @exception UnsupportedOperationException if the method is not supported
+ * @since 1.8
+ */
+ public void verify(PublicKey key, Provider sigProvider)
+ throws CertificateException, NoSuchAlgorithmException,
+ InvalidKeyException, SignatureException {
+ X509CertImpl.verify(this, key, sigProvider);
+ }
}
diff --git a/ojluni/src/main/java/sun/security/provider/Sun.java b/ojluni/src/main/java/sun/security/provider/Sun.java
new file mode 100755
index 0000000..20edc86
--- /dev/null
+++ b/ojluni/src/main/java/sun/security/provider/Sun.java
@@ -0,0 +1,64 @@
+/*
+ * Copyright (c) 1996, 2011, 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;
+
+import java.util.*;
+import java.security.*;
+
+import sun.security.action.PutAllAction;
+
+/**
+ * The SUN Security Provider.
+ *
+ */
+public final class Sun extends Provider {
+
+ private static final long serialVersionUID = 6440182097568097204L;
+
+ private static final String INFO = "SUN " +
+ "(DSA key/parameter generation; DSA signing; SHA-1, MD5 digests; " +
+ "SecureRandom; X.509 certificates; JKS keystore; PKIX CertPathValidator; " +
+ "PKIX CertPathBuilder; LDAP, Collection CertStores, JavaPolicy Policy; " +
+ "JavaLoginConfig Configuration)";
+
+ public Sun() {
+ /* We are the SUN provider */
+ super("SUN", 1.7, INFO);
+
+ // if there is no security manager installed, put directly into
+ // the provider. Otherwise, create a temporary map and use a
+ // doPrivileged() call at the end to transfer the contents
+ if (System.getSecurityManager() == null) {
+ SunEntries.putEntries(this);
+ } else {
+ // use LinkedHashMap to preserve the order of the PRNGs
+ Map<Object, Object> map = new LinkedHashMap<>();
+ SunEntries.putEntries(map);
+ AccessController.doPrivileged(new PutAllAction(this, map));
+ }
+ }
+
+}
diff --git a/ojluni/src/main/java/sun/security/provider/certpath/AdaptableX509CertSelector.java b/ojluni/src/main/java/sun/security/provider/certpath/AdaptableX509CertSelector.java
new file mode 100644
index 0000000..680795c
--- /dev/null
+++ b/ojluni/src/main/java/sun/security/provider/certpath/AdaptableX509CertSelector.java
@@ -0,0 +1,203 @@
+/*
+ * Copyright (c) 2011, 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.io.IOException;
+import java.util.Date;
+
+import java.security.cert.Certificate;
+import java.security.cert.X509Certificate;
+import java.security.cert.X509CertSelector;
+import java.security.cert.CertificateException;
+
+import sun.security.util.DerOutputStream;
+import sun.security.x509.SerialNumber;
+import sun.security.x509.KeyIdentifier;
+import sun.security.x509.AuthorityKeyIdentifierExtension;
+
+/**
+ * An adaptable X509 certificate selector for forward certification path
+ * building.
+ *
+ * @since 1.7
+ */
+class AdaptableX509CertSelector extends X509CertSelector {
+ // The start date of a validity period.
+ private Date startDate;
+
+ // The end date of a validity period.
+ private Date endDate;
+
+ // Is subject key identifier sensitive?
+ private boolean isSKIDSensitive = false;
+
+ // Is serial number sensitive?
+ private boolean isSNSensitive = false;
+
+ AdaptableX509CertSelector() {
+ super();
+ }
+
+ /**
+ * Sets the criterion of the X509Certificate validity period.
+ *
+ * Normally, we may not have to check that a certificate validity period
+ * must fall within its issuer's certificate validity period. However,
+ * when we face root CA key updates for version 1 certificates, according
+ * to scheme of RFC 4210 or 2510, the validity periods should be checked
+ * to determine the right issuer's certificate.
+ *
+ * Conservatively, we will only check the validity periods for version
+ * 1 and version 2 certificates. For version 3 certificates, we can
+ * determine the right issuer by authority and subject key identifier
+ * extensions.
+ *
+ * @param startDate the start date of a validity period that must fall
+ * within the certificate validity period for the X509Certificate
+ * @param endDate the end date of a validity period that must fall
+ * within the certificate validity period for the X509Certificate
+ */
+ void setValidityPeriod(Date startDate, Date endDate) {
+ this.startDate = startDate;
+ this.endDate = endDate;
+ }
+
+ /**
+ * Parse the authority key identifier extension.
+ *
+ * If the keyIdentifier field of the extension is non-null, set the
+ * subjectKeyIdentifier criterion. If the authorityCertSerialNumber
+ * field is non-null, set the serialNumber criterion.
+ *
+ * Note that we will not set the subject criterion according to the
+ * authorityCertIssuer field of the extension. The caller MUST set
+ * the subject criterion before call match().
+ *
+ * @param akidext the authorityKeyIdentifier extension
+ */
+ void parseAuthorityKeyIdentifierExtension(
+ AuthorityKeyIdentifierExtension akidext) throws IOException {
+ if (akidext != null) {
+ KeyIdentifier akid = (KeyIdentifier)akidext.get(
+ AuthorityKeyIdentifierExtension.KEY_ID);
+ if (akid != null) {
+ // Do not override the previous setting for initial selection.
+ if (isSKIDSensitive || getSubjectKeyIdentifier() == null) {
+ DerOutputStream derout = new DerOutputStream();
+ derout.putOctetString(akid.getIdentifier());
+ super.setSubjectKeyIdentifier(derout.toByteArray());
+
+ isSKIDSensitive = true;
+ }
+ }
+
+ SerialNumber asn = (SerialNumber)akidext.get(
+ AuthorityKeyIdentifierExtension.SERIAL_NUMBER);
+ if (asn != null) {
+ // Do not override the previous setting for initial selection.
+ if (isSNSensitive || getSerialNumber() == null) {
+ super.setSerialNumber(asn.getNumber());
+ isSNSensitive = true;
+ }
+ }
+
+ // the subject criterion should be set by the caller.
+ }
+ }
+
+ /**
+ * Decides whether a <code>Certificate</code> should be selected.
+ *
+ * For the purpose of compatibility, when a certificate is of
+ * version 1 and version 2, or the certificate does not include
+ * a subject key identifier extension, the selection criterion
+ * of subjectKeyIdentifier will be disabled.
+ */
+ @Override
+ public boolean match(Certificate cert) {
+ if (!(cert instanceof X509Certificate)) {
+ return false;
+ }
+
+ X509Certificate xcert = (X509Certificate)cert;
+ int version = xcert.getVersion();
+
+ // Check the validity period for version 1 and 2 certificate.
+ if (version < 3) {
+ if (startDate != null) {
+ try {
+ xcert.checkValidity(startDate);
+ } catch (CertificateException ce) {
+ return false;
+ }
+ }
+
+ if (endDate != null) {
+ try {
+ xcert.checkValidity(endDate);
+ } catch (CertificateException ce) {
+ return false;
+ }
+ }
+ }
+
+ // If no SubjectKeyIdentifier extension, don't bother to check it.
+ if (isSKIDSensitive &&
+ (version < 3 || xcert.getExtensionValue("2.5.29.14") == null)) {
+ setSubjectKeyIdentifier(null);
+ }
+
+ // In practice, a CA may replace its root certificate and require that
+ // the existing certificate is still valid, even if the AKID extension
+ // does not match the replacement root certificate fields.
+ //
+ // Conservatively, we only support the replacement for version 1 and
+ // version 2 certificate. As for version 2, the certificate extension
+ // may contain sensitive information (for example, policies), the
+ // AKID need to be respected to seek the exact certificate in case
+ // of key or certificate abuse.
+ if (isSNSensitive && version < 3) {
+ setSerialNumber(null);
+ }
+
+ return super.match(cert);
+ }
+
+ @Override
+ public Object clone() {
+ AdaptableX509CertSelector copy =
+ (AdaptableX509CertSelector)super.clone();
+ if (startDate != null) {
+ copy.startDate = (Date)startDate.clone();
+ }
+
+ if (endDate != null) {
+ copy.endDate = (Date)endDate.clone();
+ }
+
+ return copy;
+ }
+}
diff --git a/ojluni/src/main/java/sun/security/provider/certpath/AdjacencyList.java b/ojluni/src/main/java/sun/security/provider/certpath/AdjacencyList.java
new file mode 100644
index 0000000..f26919b
--- /dev/null
+++ b/ojluni/src/main/java/sun/security/provider/certpath/AdjacencyList.java
@@ -0,0 +1,258 @@
+/*
+ * Copyright (c) 2000, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * 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.ArrayList;
+import java.util.Collections;
+import java.util.Iterator;
+import java.util.List;
+
+/**
+ * An AdjacencyList is used to store the history of certification paths
+ * attempted in constructing a path from an initiator to a target. The
+ * AdjacencyList is initialized with a <code>List</code> of
+ * <code>List</code>s, where each sub-<code>List</code> contains objects of
+ * type <code>Vertex</code>. A <code>Vertex</code> describes one possible or
+ * actual step in the chain building process, and the associated
+ * <code>Certificate</code>. Specifically, a <code>Vertex</code> object
+ * contains a <code>Certificate</code> and an index value referencing the
+ * next sub-list in the process. If the index value is -1 then this
+ * <code>Vertex</code> doesn't continue the attempted build path.
+ * <p>
+ * Example:
+ * <p>
+ * Attempted Paths:<ul>
+ * <li>C1->C2->C3
+ * <li>C1->C4->C5
+ * <li>C1->C4->C6
+ * <li>C1->C4->C7
+ * <li>C1->C8->C9
+ * <li>C1->C10->C11
+ * </ul>
+ * <p>
+ * AdjacencyList structure:<ul>
+ * <li>AL[0] = C1,1
+ * <li>AL[1] = C2,2 =>C4,3 =>C8,4 =>C10,5
+ * <li>AL[2] = C3,-1
+ * <li>AL[3] = C5,-1 =>C6,-1 =>C7,-1
+ * <li>AL[4] = C9,-1
+ * <li>AL[5] = C11,-1
+ * </ul>
+ * <p>
+ * The iterator method returns objects of type <code>BuildStep</code>, not
+ * objects of type <code>Vertex</code>.
+ * A <code>BuildStep</code> contains a <code>Vertex</code> and a result code,
+ * accessible via getResult method. There are five result values.
+ * <code>POSSIBLE</code> denotes that the current step represents a
+ * <code>Certificate</code> that the builder is considering at this point in
+ * the build. <code>FOLLOW</code> denotes a <code>Certificate</code> (one of
+ * those noted as <code>POSSIBLE</code>) that the builder is using to try
+ * extending the chain. <code>BACK</code> represents that a
+ * <code>FOLLOW</code> was incorrect, and is being removed from the chain.
+ * There is exactly one <code>FOLLOW</code> for each <code>BACK</code>. The
+ * values <code>SUCCEED</code> and <code>FAIL</code> mean that we've come to
+ * the end of the build process, and there will not be any more entries in
+ * the list.
+ * <p>
+ * @see sun.security.provider.certpath.BuildStep
+ * @see sun.security.provider.certpath.Vertex
+ * <p>
+ * @author seth proctor
+ * @since 1.4
+ */
+public class AdjacencyList {
+
+ // the actual set of steps the AdjacencyList represents
+ private ArrayList<BuildStep> mStepList;
+
+ // the original list, just for the toString method
+ private List<List<Vertex>> mOrigList;
+
+ /**
+ * Constructs a new <code>AdjacencyList</code> based on the specified
+ * <code>List</code>. See the example above.
+ *
+ * @param list a <code>List</code> of <code>List</code>s of
+ * <code>Vertex</code> objects
+ */
+ public AdjacencyList(List<List<Vertex>> list) {
+ mStepList = new ArrayList<BuildStep>();
+ mOrigList = list;
+ buildList(list, 0, null);
+ }
+
+ /**
+ * Gets an <code>Iterator</code> to iterate over the set of
+ * <code>BuildStep</code>s in build-order. Any attempts to change
+ * the list through the remove method will fail.
+ *
+ * @return an <code>Iterator</code> over the <code>BuildStep</code>s
+ */
+ public Iterator<BuildStep> iterator() {
+ return Collections.unmodifiableList(mStepList).iterator();
+ }
+
+ /**
+ * Recursive, private method which actually builds the step list from
+ * the given adjacency list. <code>Follow</code> is the parent BuildStep
+ * that we followed to get here, and if it's null, it means that we're
+ * at the start.
+ */
+ private boolean buildList(List<List<Vertex>> theList, int index,
+ BuildStep follow) {
+
+ // Each time this method is called, we're examining a new list
+ // from the global list. So, we have to start by getting the list
+ // that contains the set of Vertexes we're considering.
+ List<Vertex> l = theList.get(index);
+
+ // we're interested in the case where all indexes are -1...
+ boolean allNegOne = true;
+ // ...and in the case where every entry has a Throwable
+ boolean allXcps = true;
+
+ for (Vertex v : l) {
+ if (v.getIndex() != -1) {
+ // count an empty list the same as an index of -1...this
+ // is to patch a bug somewhere in the builder
+ if (theList.get(v.getIndex()).size() != 0)
+ allNegOne = false;
+ } else {
+ if (v.getThrowable() == null)
+ allXcps = false;
+ }
+ // every entry, regardless of the final use for it, is always
+ // entered as a possible step before we take any actions
+ mStepList.add(new BuildStep(v, BuildStep.POSSIBLE));
+ }
+
+ if (allNegOne) {
+ // There are two cases that we could be looking at here. We
+ // may need to back up, or the build may have succeeded at
+ // this point. This is based on whether or not any
+ // exceptions were found in the list.
+ if (allXcps) {
+ // we need to go back...see if this is the last one
+ if (follow == null)
+ mStepList.add(new BuildStep(null, BuildStep.FAIL));
+ else
+ mStepList.add(new BuildStep(follow.getVertex(),
+ BuildStep.BACK));
+
+ return false;
+ } else {
+ // we succeeded...now the only question is which is the
+ // successful step? If there's only one entry without
+ // a throwable, then that's the successful step. Otherwise,
+ // we'll have to make some guesses...
+ List<Vertex> possibles = new ArrayList<>();
+ for (Vertex v : l) {
+ if (v.getThrowable() == null)
+ possibles.add(v);
+ }
+
+ if (possibles.size() == 1) {
+ // real easy...we've found the final Vertex
+ mStepList.add(new BuildStep(possibles.get(0),
+ BuildStep.SUCCEED));
+ } else {
+ // ok...at this point, there is more than one Cert
+ // which might be the succeed step...how do we know
+ // which it is? I'm going to assume that our builder
+ // algorithm is good enough to know which is the
+ // correct one, and put it first...but a FIXME goes
+ // here anyway, and we should be comparing to the
+ // target/initiator Cert...
+ mStepList.add(new BuildStep(possibles.get(0),
+ BuildStep.SUCCEED));
+ }
+
+ return true;
+ }
+ } else {
+ // There's at least one thing that we can try before we give
+ // up and go back. Run through the list now, and enter a new
+ // BuildStep for each path that we try to follow. If none of
+ // the paths we try produce a successful end, we're going to
+ // have to back out ourselves.
+ boolean success = false;
+
+ for (Vertex v : l) {
+
+ // Note that we'll only find a SUCCEED case when we're
+ // looking at the last possible path, so we don't need to
+ // consider success in the while loop
+
+ if (v.getIndex() != -1) {
+ if (theList.get(v.getIndex()).size() != 0) {
+ // If the entry we're looking at doesn't have an
+ // index of -1, and doesn't lead to an empty list,
+ // then it's something we follow!
+ BuildStep bs = new BuildStep(v, BuildStep.FOLLOW);
+ mStepList.add(bs);
+ success = buildList(theList, v.getIndex(), bs);
+ }
+ }
+ }
+
+ if (success) {
+ // We're already finished!
+ return true;
+ } else {
+ // We failed, and we've exhausted all the paths that we
+ // could take. The only choice is to back ourselves out.
+ if (follow == null)
+ mStepList.add(new BuildStep(null, BuildStep.FAIL));
+ else
+ mStepList.add(new BuildStep(follow.getVertex(),
+ BuildStep.BACK));
+
+ return false;
+ }
+ }
+ }
+
+ /**
+ * Prints out a string representation of this AdjacencyList.
+ *
+ * @return String representation
+ */
+ @Override
+ public String toString() {
+ StringBuilder sb = new StringBuilder("[\n");
+
+ int i = 0;
+ for (List<Vertex> l : mOrigList) {
+ sb.append("LinkedList[").append(i++).append("]:\n");
+
+ for (Vertex step : l) {
+ sb.append(step.toString()).append("\n");
+ }
+ }
+ sb.append("]\n");
+
+ return sb.toString();
+ }
+}
diff --git a/ojluni/src/main/java/sun/security/provider/certpath/AlgorithmChecker.java b/ojluni/src/main/java/sun/security/provider/certpath/AlgorithmChecker.java
old mode 100755
new mode 100644
index 27a9caa..ab75ff0
--- a/ojluni/src/main/java/sun/security/provider/certpath/AlgorithmChecker.java
+++ b/ojluni/src/main/java/sun/security/provider/certpath/AlgorithmChecker.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2009, 2011, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2009, 2012, 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
@@ -259,8 +259,7 @@
}
// Inherit key parameters from previous key
- if (currPubKey instanceof DSAPublicKey &&
- ((DSAPublicKey)currPubKey).getParams() == null) {
+ if (PKIX.isDSAPublicKeyWithoutParams(currPubKey)) {
// Inherit DSA parameters from previous key
if (!(prevPubKey instanceof DSAPublicKey)) {
throw new CertPathValidatorException("Input key is not " +
diff --git a/ojluni/src/main/java/sun/security/provider/certpath/BasicChecker.java b/ojluni/src/main/java/sun/security/provider/certpath/BasicChecker.java
new file mode 100644
index 0000000..49a0368
--- /dev/null
+++ b/ojluni/src/main/java/sun/security/provider/certpath/BasicChecker.java
@@ -0,0 +1,302 @@
+/*
+ * Copyright (c) 2000, 2012, 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.math.BigInteger;
+import java.util.Collection;
+import java.util.Date;
+import java.util.Set;
+import java.security.GeneralSecurityException;
+import java.security.KeyFactory;
+import java.security.PublicKey;
+import java.security.SignatureException;
+import java.security.cert.Certificate;
+import java.security.cert.CertificateExpiredException;
+import java.security.cert.CertificateNotYetValidException;
+import java.security.cert.CertPathValidatorException;
+import java.security.cert.CertPathValidatorException.BasicReason;
+import java.security.cert.X509Certificate;
+import java.security.cert.PKIXCertPathChecker;
+import java.security.cert.PKIXReason;
+import java.security.cert.TrustAnchor;
+import java.security.interfaces.DSAParams;
+import java.security.interfaces.DSAPublicKey;
+import java.security.spec.DSAPublicKeySpec;
+import javax.security.auth.x500.X500Principal;
+import sun.security.x509.X500Name;
+import sun.security.util.Debug;
+
+/**
+ * BasicChecker is a PKIXCertPathChecker that checks the basic information
+ * on a PKIX certificate, namely the signature, timestamp, and subject/issuer
+ * name chaining.
+ *
+ * @since 1.4
+ * @author Yassir Elley
+ */
+class BasicChecker extends PKIXCertPathChecker {
+
+ private static final Debug debug = Debug.getInstance("certpath");
+ private final PublicKey trustedPubKey;
+ private final X500Principal caName;
+ private final Date date;
+ private final String sigProvider;
+ private final boolean sigOnly;
+ private X500Principal prevSubject;
+ private PublicKey prevPubKey;
+
+ /**
+ * Constructor that initializes the input parameters.
+ *
+ * @param anchor the anchor selected to validate the target certificate
+ * @param testDate the time for which the validity of the certificate
+ * should be determined
+ * @param sigProvider the name of the signature provider
+ * @param sigOnly true if only signature checking is to be done;
+ * if false, all checks are done
+ */
+ BasicChecker(TrustAnchor anchor, Date date, String sigProvider,
+ boolean sigOnly) {
+ if (anchor.getTrustedCert() != null) {
+ this.trustedPubKey = anchor.getTrustedCert().getPublicKey();
+ this.caName = anchor.getTrustedCert().getSubjectX500Principal();
+ } else {
+ this.trustedPubKey = anchor.getCAPublicKey();
+ this.caName = anchor.getCA();
+ }
+ this.date = date;
+ this.sigProvider = sigProvider;
+ this.sigOnly = sigOnly;
+ this.prevPubKey = trustedPubKey;
+ }
+
+ /**
+ * Initializes the internal state of the checker from parameters
+ * specified in the constructor.
+ */
+ @Override
+ public void init(boolean forward) throws CertPathValidatorException {
+ if (!forward) {
+ prevPubKey = trustedPubKey;
+ if (PKIX.isDSAPublicKeyWithoutParams(prevPubKey)) {
+ // If TrustAnchor is a DSA public key and it has no params, it
+ // cannot be used to verify the signature of the first cert,
+ // so throw exception
+ throw new CertPathValidatorException("Key parameters missing");
+ }
+ prevSubject = caName;
+ } else {
+ throw new
+ CertPathValidatorException("forward checking not supported");
+ }
+ }
+
+ @Override
+ public boolean isForwardCheckingSupported() {
+ return false;
+ }
+
+ @Override
+ public Set<String> getSupportedExtensions() {
+ return null;
+ }
+
+ /**
+ * Performs the signature, timestamp, and subject/issuer name chaining
+ * checks on the certificate using its internal state. This method does
+ * not remove any critical extensions from the Collection.
+ *
+ * @param cert the Certificate
+ * @param unresolvedCritExts a Collection of the unresolved critical
+ * extensions
+ * @throws CertPathValidatorException if certificate does not verify
+ */
+ @Override
+ public void check(Certificate cert, Collection<String> unresolvedCritExts)
+ throws CertPathValidatorException
+ {
+ X509Certificate currCert = (X509Certificate)cert;
+
+ if (!sigOnly) {
+ verifyTimestamp(currCert);
+ verifyNameChaining(currCert);
+ }
+ verifySignature(currCert);
+
+ updateState(currCert);
+ }
+
+ /**
+ * Verifies the signature on the certificate using the previous public key.
+ *
+ * @param cert the X509Certificate
+ * @throws CertPathValidatorException if certificate does not verify
+ */
+ private void verifySignature(X509Certificate cert)
+ throws CertPathValidatorException
+ {
+ String msg = "signature";
+ if (debug != null)
+ debug.println("---checking " + msg + "...");
+
+ try {
+ cert.verify(prevPubKey, sigProvider);
+ } catch (SignatureException e) {
+ throw new CertPathValidatorException
+ (msg + " check failed", e, null, -1,
+ BasicReason.INVALID_SIGNATURE);
+ } catch (GeneralSecurityException e) {
+ throw new CertPathValidatorException(msg + " check failed", e);
+ }
+
+ if (debug != null)
+ debug.println(msg + " verified.");
+ }
+
+ /**
+ * Internal method to verify the timestamp on a certificate
+ */
+ private void verifyTimestamp(X509Certificate cert)
+ throws CertPathValidatorException
+ {
+ String msg = "timestamp";
+ if (debug != null)
+ debug.println("---checking " + msg + ":" + date.toString() + "...");
+
+ try {
+ cert.checkValidity(date);
+ } catch (CertificateExpiredException e) {
+ throw new CertPathValidatorException
+ (msg + " check failed", e, null, -1, BasicReason.EXPIRED);
+ } catch (CertificateNotYetValidException e) {
+ throw new CertPathValidatorException
+ (msg + " check failed", e, null, -1, BasicReason.NOT_YET_VALID);
+ }
+
+ if (debug != null)
+ debug.println(msg + " verified.");
+ }
+
+ /**
+ * Internal method to check that cert has a valid DN to be next in a chain
+ */
+ private void verifyNameChaining(X509Certificate cert)
+ throws CertPathValidatorException
+ {
+ if (prevSubject != null) {
+
+ String msg = "subject/issuer name chaining";
+ if (debug != null)
+ debug.println("---checking " + msg + "...");
+
+ X500Principal currIssuer = cert.getIssuerX500Principal();
+
+ // reject null or empty issuer DNs
+ if (X500Name.asX500Name(currIssuer).isEmpty()) {
+ throw new CertPathValidatorException
+ (msg + " check failed: " +
+ "empty/null issuer DN in certificate is invalid", null,
+ null, -1, PKIXReason.NAME_CHAINING);
+ }
+
+ if (!(currIssuer.equals(prevSubject))) {
+ throw new CertPathValidatorException
+ (msg + " check failed", null, null, -1,
+ PKIXReason.NAME_CHAINING);
+ }
+
+ if (debug != null)
+ debug.println(msg + " verified.");
+ }
+ }
+
+ /**
+ * Internal method to manage state information at each iteration
+ */
+ private void updateState(X509Certificate currCert)
+ throws CertPathValidatorException
+ {
+ PublicKey cKey = currCert.getPublicKey();
+ if (debug != null) {
+ debug.println("BasicChecker.updateState issuer: " +
+ currCert.getIssuerX500Principal().toString() + "; subject: " +
+ currCert.getSubjectX500Principal() + "; serial#: " +
+ currCert.getSerialNumber().toString());
+ }
+ if (PKIX.isDSAPublicKeyWithoutParams(cKey)) {
+ // cKey needs to inherit DSA parameters from prev key
+ cKey = makeInheritedParamsKey(cKey, prevPubKey);
+ if (debug != null) debug.println("BasicChecker.updateState Made " +
+ "key with inherited params");
+ }
+ prevPubKey = cKey;
+ prevSubject = currCert.getSubjectX500Principal();
+ }
+
+ /**
+ * Internal method to create a new key with inherited key parameters.
+ *
+ * @param keyValueKey key from which to obtain key value
+ * @param keyParamsKey key from which to obtain key parameters
+ * @return new public key having value and parameters
+ * @throws CertPathValidatorException if keys are not appropriate types
+ * for this operation
+ */
+ static PublicKey makeInheritedParamsKey(PublicKey keyValueKey,
+ PublicKey keyParamsKey) throws CertPathValidatorException
+ {
+ if (!(keyValueKey instanceof DSAPublicKey) ||
+ !(keyParamsKey instanceof DSAPublicKey))
+ throw new CertPathValidatorException("Input key is not " +
+ "appropriate type for " +
+ "inheriting parameters");
+ DSAParams params = ((DSAPublicKey)keyParamsKey).getParams();
+ if (params == null)
+ throw new CertPathValidatorException("Key parameters missing");
+ try {
+ BigInteger y = ((DSAPublicKey)keyValueKey).getY();
+ KeyFactory kf = KeyFactory.getInstance("DSA");
+ DSAPublicKeySpec ks = new DSAPublicKeySpec(y,
+ params.getP(),
+ params.getQ(),
+ params.getG());
+ return kf.generatePublic(ks);
+ } catch (GeneralSecurityException e) {
+ throw new CertPathValidatorException("Unable to generate key with" +
+ " inherited parameters: " +
+ e.getMessage(), e);
+ }
+ }
+
+ /**
+ * return the public key associated with the last certificate processed
+ *
+ * @return PublicKey the last public key processed
+ */
+ PublicKey getPublicKey() {
+ return prevPubKey;
+ }
+}
diff --git a/ojluni/src/main/java/sun/security/provider/certpath/BuildStep.java b/ojluni/src/main/java/sun/security/provider/certpath/BuildStep.java
new file mode 100644
index 0000000..bf06411
--- /dev/null
+++ b/ojluni/src/main/java/sun/security/provider/certpath/BuildStep.java
@@ -0,0 +1,277 @@
+/*
+ * Copyright (c) 2000, 2012, 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.cert.X509Certificate;
+
+/**
+ * Describes one step of a certification path build, consisting of a
+ * <code>Vertex</code> state description, a certificate, a possible throwable,
+ * and a result code.
+ *
+ * @author Anne Anderson
+ * @since 1.4
+ * @see sun.security.provider.certpath.Vertex
+ */
+public class BuildStep {
+
+ private Vertex vertex;
+ private X509Certificate cert;
+ private Throwable throwable;
+ private int result;
+
+ /**
+ * result code associated with a certificate that may continue a path from
+ * the current certificate.
+ */
+ public static final int POSSIBLE = 1;
+
+ /**
+ * result code associated with a certificate that was tried, but that
+ * represents an unsuccessful path, so the certificate has been backed out
+ * to allow backtracking to the next possible path.
+ */
+ public static final int BACK = 2;
+
+ /**
+ * result code associated with a certificate that successfully continues the
+ * current path, but does not yet reach the target.
+ */
+ public static final int FOLLOW = 3;
+
+ /**
+ * result code associated with a certificate that represents the end of the
+ * last possible path, where no path successfully reached the target.
+ */
+ public static final int FAIL = 4;
+
+ /**
+ * result code associated with a certificate that represents the end of a
+ * path that successfully reaches the target.
+ */
+ public static final int SUCCEED = 5;
+
+ /**
+ * construct a BuildStep
+ *
+ * @param vtx description of the vertex at this step
+ * @param res result, where result is one of POSSIBLE, BACK,
+ * FOLLOW, FAIL, SUCCEED
+ */
+ public BuildStep(Vertex vtx, int res) {
+ vertex = vtx;
+ if (vertex != null) {
+ cert = vertex.getCertificate();
+ throwable = vertex.getThrowable();
+ }
+ result = res;
+ }
+
+ /**
+ * return vertex description for this build step
+ *
+ * @returns Vertex
+ */
+ public Vertex getVertex() {
+ return vertex;
+ }
+
+ /**
+ * return the certificate associated with this build step
+ *
+ * @returns X509Certificate
+ */
+ public X509Certificate getCertificate() {
+ return cert;
+ }
+
+ /**
+ * return string form of issuer name from certificate associated with this
+ * build step
+ *
+ * @returns String form of issuer name or null, if no certificate.
+ */
+ public String getIssuerName() {
+ return getIssuerName(null);
+ }
+
+ /**
+ * return string form of issuer name from certificate associated with this
+ * build step, or a default name if no certificate associated with this
+ * build step, or if issuer name could not be obtained from the certificate.
+ *
+ * @param defaultName name to use as default if unable to return an issuer
+ * name from the certificate, or if no certificate.
+ * @returns String form of issuer name or defaultName, if no certificate or
+ * exception received while trying to extract issuer name from certificate.
+ */
+ public String getIssuerName(String defaultName) {
+ return (cert == null ? defaultName
+ : cert.getIssuerX500Principal().toString());
+ }
+
+ /**
+ * return string form of subject name from certificate associated with this
+ * build step.
+ *
+ * @returns String form of subject name or null, if no certificate.
+ */
+ public String getSubjectName() {
+ return getSubjectName(null);
+ }
+
+ /**
+ * return string form of subject name from certificate associated with this
+ * build step, or a default name if no certificate associated with this
+ * build step, or if subject name could not be obtained from the
+ * certificate.
+ *
+ * @param defaultName name to use as default if unable to return a subject
+ * name from the certificate, or if no certificate.
+ * @returns String form of subject name or defaultName, if no certificate or
+ * if an exception was received while attempting to extract the subject name
+ * from the certificate.
+ */
+ public String getSubjectName(String defaultName) {
+ return (cert == null ? defaultName
+ : cert.getSubjectX500Principal().toString());
+ }
+
+ /**
+ * return the exception associated with this build step.
+ *
+ * @returns Throwable
+ */
+ public Throwable getThrowable() {
+ return throwable;
+ }
+
+ /**
+ * return the result code associated with this build step. The result codes
+ * are POSSIBLE, FOLLOW, BACK, FAIL, SUCCEED.
+ *
+ * @returns int result code
+ */
+ public int getResult() {
+ return result;
+ }
+
+ /**
+ * return a string representing the meaning of the result code associated
+ * with this build step.
+ *
+ * @param res result code
+ * @returns String string representing meaning of the result code
+ */
+ public String resultToString(int res) {
+ String resultString = "";
+ switch (res) {
+ case POSSIBLE:
+ resultString = "Certificate to be tried.\n";
+ break;
+ case BACK:
+ resultString = "Certificate backed out since path does not "
+ + "satisfy build requirements.\n";
+ break;
+ case FOLLOW:
+ resultString = "Certificate satisfies conditions.\n";
+ break;
+ case FAIL:
+ resultString = "Certificate backed out since path does not "
+ + "satisfy conditions.\n";
+ break;
+ case SUCCEED:
+ resultString = "Certificate satisfies conditions.\n";
+ break;
+ default:
+ resultString = "Internal error: Invalid step result value.\n";
+ }
+ return resultString;
+ }
+
+ /**
+ * return a string representation of this build step, showing minimal
+ * detail.
+ *
+ * @returns String
+ */
+ @Override
+ public String toString() {
+ String out = "Internal Error\n";
+ switch (result) {
+ case BACK:
+ case FAIL:
+ out = resultToString(result);
+ out = out + vertex.throwableToString();
+ break;
+ case FOLLOW:
+ case SUCCEED:
+ case POSSIBLE:
+ out = resultToString(result);
+ break;
+ default:
+ out = "Internal Error: Invalid step result\n";
+ }
+ return out;
+ }
+
+ /**
+ * return a string representation of this build step, showing all detail of
+ * the vertex state appropriate to the result of this build step, and the
+ * certificate contents.
+ *
+ * @returns String
+ */
+ public String verboseToString() {
+ String out = resultToString(getResult());
+ switch (result) {
+ case BACK:
+ case FAIL:
+ out = out + vertex.throwableToString();
+ break;
+ case FOLLOW:
+ case SUCCEED:
+ out = out + vertex.moreToString();
+ break;
+ case POSSIBLE:
+ break;
+ default:
+ break;
+ }
+ out = out + "Certificate contains:\n" + vertex.certToString();
+ return out;
+ }
+
+ /**
+ * return a string representation of this build step, including all possible
+ * detail of the vertex state, but not including the certificate contents.
+ *
+ * @returns String
+ */
+ public String fullToString() {
+ return resultToString(getResult()) + vertex.toString();
+ }
+}
diff --git a/ojluni/src/main/java/sun/security/provider/certpath/Builder.java b/ojluni/src/main/java/sun/security/provider/certpath/Builder.java
new file mode 100644
index 0000000..e053b20
--- /dev/null
+++ b/ojluni/src/main/java/sun/security/provider/certpath/Builder.java
@@ -0,0 +1,472 @@
+/*
+ * Copyright (c) 2000, 2012, 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.io.IOException;
+import java.security.AccessController;
+import java.security.GeneralSecurityException;
+import java.security.cert.*;
+import java.util.*;
+
+import sun.security.action.GetBooleanAction;
+import sun.security.provider.certpath.PKIX.BuilderParams;
+import sun.security.util.Debug;
+import sun.security.x509.GeneralNames;
+import sun.security.x509.GeneralNameInterface;
+import sun.security.x509.GeneralSubtrees;
+import sun.security.x509.NameConstraintsExtension;
+import sun.security.x509.SubjectAlternativeNameExtension;
+import sun.security.x509.X500Name;
+import sun.security.x509.X509CertImpl;
+
+/**
+ * Abstract class representing a builder, which is able to retrieve
+ * matching certificates and is able to verify a particular certificate.
+ *
+ * @since 1.4
+ * @author Sean Mullan
+ * @author Yassir Elley
+ */
+
+public abstract class Builder {
+
+ private static final Debug debug = Debug.getInstance("certpath");
+ private Set<String> matchingPolicies;
+ final BuilderParams buildParams;
+ final X509CertSelector targetCertConstraints;
+
+ /**
+ * Flag indicating whether support for the caIssuers field of the
+ * Authority Information Access extension shall be enabled. Currently
+ * disabled by default for compatibility reasons.
+ */
+ final static boolean USE_AIA = AccessController.doPrivileged
+ (new GetBooleanAction("com.sun.security.enableAIAcaIssuers"));
+
+ /**
+ * Initialize the builder with the input parameters.
+ *
+ * @param params the parameter set used to build a certification path
+ */
+ Builder(BuilderParams buildParams) {
+ this.buildParams = buildParams;
+ this.targetCertConstraints =
+ (X509CertSelector)buildParams.targetCertConstraints();
+ }
+
+ /**
+ * Retrieves certificates from the list of certStores using the buildParams
+ * and the currentState as a filter
+ *
+ * @param currentState the current State
+ * @param certStores list of CertStores
+ */
+ abstract Collection<X509Certificate> getMatchingCerts
+ (State currentState, List<CertStore> certStores)
+ throws CertStoreException, CertificateException, IOException;
+
+ /**
+ * Verifies the cert against the currentState, using the certPathList
+ * generated thus far to help with loop detection
+ *
+ * @param cert the certificate to be verified
+ * @param currentState the current state against which the cert is verified
+ * @param certPathList the certPathList generated thus far
+ */
+ abstract void verifyCert(X509Certificate cert, State currentState,
+ List<X509Certificate> certPathList)
+ throws GeneralSecurityException;
+
+ /**
+ * Verifies whether the input certificate completes the path.
+ * When building forward, a trust anchor will complete the path.
+ * When building reverse, the target certificate will complete the path.
+ *
+ * @param cert the certificate to test
+ * @return a boolean value indicating whether the cert completes the path.
+ */
+ abstract boolean isPathCompleted(X509Certificate cert);
+
+ /**
+ * Adds the certificate to the certPathList
+ *
+ * @param cert the certificate to be added
+ * @param certPathList the certification path list
+ */
+ abstract void addCertToPath(X509Certificate cert,
+ LinkedList<X509Certificate> certPathList);
+
+ /**
+ * Removes final certificate from the certPathList
+ *
+ * @param certPathList the certification path list
+ */
+ abstract void removeFinalCertFromPath
+ (LinkedList<X509Certificate> certPathList);
+
+ /**
+ * get distance of one GeneralName from another
+ *
+ * @param base GeneralName at base of subtree
+ * @param test GeneralName to be tested against base
+ * @param incomparable the value to return if the names are
+ * incomparable
+ * @return distance of test name from base, where 0
+ * means exact match, 1 means test is an immediate
+ * child of base, 2 means test is a grandchild, etc.
+ * -1 means test is a parent of base, -2 means test
+ * is a grandparent, etc.
+ */
+ static int distance(GeneralNameInterface base,
+ GeneralNameInterface test, int incomparable)
+ {
+ switch (base.constrains(test)) {
+ case GeneralNameInterface.NAME_DIFF_TYPE:
+ if (debug != null) {
+ debug.println("Builder.distance(): Names are different types");
+ }
+ return incomparable;
+ case GeneralNameInterface.NAME_SAME_TYPE:
+ if (debug != null) {
+ debug.println("Builder.distance(): Names are same type but " +
+ "in different subtrees");
+ }
+ return incomparable;
+ case GeneralNameInterface.NAME_MATCH:
+ return 0;
+ case GeneralNameInterface.NAME_WIDENS:
+ break;
+ case GeneralNameInterface.NAME_NARROWS:
+ break;
+ default: // should never occur
+ return incomparable;
+ }
+
+ /* names are in same subtree */
+ return test.subtreeDepth() - base.subtreeDepth();
+ }
+
+ /**
+ * get hop distance of one GeneralName from another in links where
+ * the names need not have an ancestor/descendant relationship.
+ * For example, the hop distance from ou=D,ou=C,o=B,c=US to
+ * ou=F,ou=E,ou=C,o=B,c=US is 3: D->C, C->E, E->F. The hop distance
+ * from ou=C,o=B,c=US to ou=D,ou=C,o=B,c=US is -1: C->D
+ *
+ * @param base GeneralName
+ * @param test GeneralName to be tested against base
+ * @param incomparable the value to return if the names are
+ * incomparable
+ * @return distance of test name from base measured in hops in the
+ * namespace hierarchy, where 0 means exact match. Result
+ * is positive if path is some number of up hops followed by
+ * some number of down hops; result is negative if path is
+ * some number of down hops.
+ */
+ static int hops(GeneralNameInterface base, GeneralNameInterface test,
+ int incomparable)
+ {
+ int baseRtest = base.constrains(test);
+ switch (baseRtest) {
+ case GeneralNameInterface.NAME_DIFF_TYPE:
+ if (debug != null) {
+ debug.println("Builder.hops(): Names are different types");
+ }
+ return incomparable;
+ case GeneralNameInterface.NAME_SAME_TYPE:
+ /* base and test are in different subtrees */
+ break;
+ case GeneralNameInterface.NAME_MATCH:
+ /* base matches test */
+ return 0;
+ case GeneralNameInterface.NAME_WIDENS:
+ /* base is ancestor of test */
+ return (test.subtreeDepth()-base.subtreeDepth());
+ case GeneralNameInterface.NAME_NARROWS:
+ /* base is descendant of test */
+ return (test.subtreeDepth()-base.subtreeDepth());
+ default: // should never occur
+ return incomparable;
+ }
+
+ /* names are in different subtrees */
+ if (base.getType() != GeneralNameInterface.NAME_DIRECTORY) {
+ if (debug != null) {
+ debug.println("Builder.hops(): hopDistance not implemented " +
+ "for this name type");
+ }
+ return incomparable;
+ }
+ X500Name baseName = (X500Name)base;
+ X500Name testName = (X500Name)test;
+ X500Name commonName = baseName.commonAncestor(testName);
+ if (commonName == null) {
+ if (debug != null) {
+ debug.println("Builder.hops(): Names are in different " +
+ "namespaces");
+ }
+ return incomparable;
+ } else {
+ int commonDistance = commonName.subtreeDepth();
+ int baseDistance = baseName.subtreeDepth();
+ int testDistance = testName.subtreeDepth();
+ return (baseDistance + testDistance - (2 * commonDistance));
+ }
+ }
+
+ /**
+ * Determine how close a given certificate gets you toward
+ * a given target.
+ *
+ * @param constraints Current NameConstraints; if null,
+ * then caller must verify NameConstraints
+ * independently, realizing that this certificate
+ * may not actually lead to the target at all.
+ * @param cert Candidate certificate for chain
+ * @param target GeneralNameInterface name of target
+ * @return distance from this certificate to target:
+ * <ul>
+ * <li>-1 means certificate could be CA for target, but
+ * there are no NameConstraints limiting how close
+ * <li> 0 means certificate subject or subjectAltName
+ * matches target
+ * <li> 1 means certificate is permitted to be CA for
+ * target.
+ * <li> 2 means certificate is permitted to be CA for
+ * parent of target.
+ * <li>>0 in general, means certificate is permitted
+ * to be a CA for this distance higher in the naming
+ * hierarchy than the target, plus 1.
+ * </ul>
+ * <p>Note that the subject and/or subjectAltName of the
+ * candidate cert does not have to be an ancestor of the
+ * target in order to be a CA that can issue a certificate to
+ * the target. In these cases, the target distance is calculated
+ * by inspecting the NameConstraints extension in the candidate
+ * certificate. For example, suppose the target is an X.500 DN with
+ * a value of "CN=mullan,OU=ireland,O=sun,C=us" and the
+ * NameConstraints extension in the candidate certificate
+ * includes a permitted component of "O=sun,C=us", which implies
+ * that the candidate certificate is allowed to issue certs in
+ * the "O=sun,C=us" namespace. The target distance is 3
+ * ((distance of permitted NC from target) + 1).
+ * The (+1) is added to distinguish the result from the case
+ * which returns (0).
+ * @throws IOException if certificate does not get closer
+ */
+ static int targetDistance(NameConstraintsExtension constraints,
+ X509Certificate cert, GeneralNameInterface target)
+ throws IOException
+ {
+ /* ensure that certificate satisfies existing name constraints */
+ if (constraints != null && !constraints.verify(cert)) {
+ throw new IOException("certificate does not satisfy existing name "
+ + "constraints");
+ }
+
+ X509CertImpl certImpl;
+ try {
+ certImpl = X509CertImpl.toImpl(cert);
+ } catch (CertificateException e) {
+ throw new IOException("Invalid certificate", e);
+ }
+ /* see if certificate subject matches target */
+ X500Name subject = X500Name.asX500Name(certImpl.getSubjectX500Principal());
+ if (subject.equals(target)) {
+ /* match! */
+ return 0;
+ }
+
+ SubjectAlternativeNameExtension altNameExt =
+ certImpl.getSubjectAlternativeNameExtension();
+ if (altNameExt != null) {
+ GeneralNames altNames = altNameExt.get(
+ SubjectAlternativeNameExtension.SUBJECT_NAME);
+ /* see if any alternative name matches target */
+ if (altNames != null) {
+ for (int j = 0, n = altNames.size(); j < n; j++) {
+ GeneralNameInterface altName = altNames.get(j).getName();
+ if (altName.equals(target)) {
+ return 0;
+ }
+ }
+ }
+ }
+
+
+ /* no exact match; see if certificate can get us to target */
+
+ /* first, get NameConstraints out of certificate */
+ NameConstraintsExtension ncExt = certImpl.getNameConstraintsExtension();
+ if (ncExt == null) {
+ return -1;
+ }
+
+ /* merge certificate's NameConstraints with current NameConstraints */
+ if (constraints != null) {
+ constraints.merge(ncExt);
+ } else {
+ // Make sure we do a clone here, because we're probably
+ // going to modify this object later and we don't want to
+ // be sharing it with a Certificate object!
+ constraints = (NameConstraintsExtension) ncExt.clone();
+ }
+
+ if (debug != null) {
+ debug.println("Builder.targetDistance() merged constraints: "
+ + String.valueOf(constraints));
+ }
+ /* reduce permitted by excluded */
+ GeneralSubtrees permitted =
+ constraints.get(NameConstraintsExtension.PERMITTED_SUBTREES);
+ GeneralSubtrees excluded =
+ constraints.get(NameConstraintsExtension.EXCLUDED_SUBTREES);
+ if (permitted != null) {
+ permitted.reduce(excluded);
+ }
+ if (debug != null) {
+ debug.println("Builder.targetDistance() reduced constraints: "
+ + permitted);
+ }
+ /* see if new merged constraints allow target */
+ if (!constraints.verify(target)) {
+ throw new IOException("New certificate not allowed to sign "
+ + "certificate for target");
+ }
+ /* find distance to target, if any, in permitted */
+ if (permitted == null) {
+ /* certificate is unconstrained; could sign for anything */
+ return -1;
+ }
+ for (int i = 0, n = permitted.size(); i < n; i++) {
+ GeneralNameInterface perName = permitted.get(i).getName().getName();
+ int distance = distance(perName, target, -1);
+ if (distance >= 0) {
+ return (distance + 1);
+ }
+ }
+ /* no matching type in permitted; cert holder could certify target */
+ return -1;
+ }
+
+ /**
+ * This method can be used as an optimization to filter out
+ * certificates that do not have policies which are valid.
+ * It returns the set of policies (String OIDs) that should exist in
+ * the certificate policies extension of the certificate that is
+ * needed by the builder. The logic applied is as follows:
+ * <p>
+ * 1) If some initial policies have been set *and* policy mappings are
+ * inhibited, then acceptable certificates are those that include
+ * the ANY_POLICY OID or with policies that intersect with the
+ * initial policies.
+ * 2) If no initial policies have been set *or* policy mappings are
+ * not inhibited then we don't have much to work with. All we know is
+ * that a certificate must have *some* policy because if it didn't
+ * have any policy then the policy tree would become null (and validation
+ * would fail).
+ *
+ * @return the Set of policies any of which must exist in a
+ * cert's certificate policies extension in order for a cert to be selected.
+ */
+ Set<String> getMatchingPolicies() {
+ if (matchingPolicies != null) {
+ Set<String> initialPolicies = buildParams.initialPolicies();
+ if ((!initialPolicies.isEmpty()) &&
+ (!initialPolicies.contains(PolicyChecker.ANY_POLICY)) &&
+ (buildParams.policyMappingInhibited()))
+ {
+ matchingPolicies = new HashSet<>(initialPolicies);
+ matchingPolicies.add(PolicyChecker.ANY_POLICY);
+ } else {
+ // we just return an empty set to make sure that there is
+ // at least a certificate policies extension in the cert
+ matchingPolicies = Collections.<String>emptySet();
+ }
+ }
+ return matchingPolicies;
+ }
+
+ /**
+ * Search the specified CertStores and add all certificates matching
+ * selector to resultCerts. Self-signed certs are not useful here
+ * and therefore ignored.
+ *
+ * If the targetCert criterion of the selector is set, only that cert
+ * is examined and the CertStores are not searched.
+ *
+ * If checkAll is true, all CertStores are searched for matching certs.
+ * If false, the method returns as soon as the first CertStore returns
+ * a matching cert(s).
+ *
+ * Returns true iff resultCerts changed (a cert was added to the collection)
+ */
+ boolean addMatchingCerts(X509CertSelector selector,
+ Collection<CertStore> certStores,
+ Collection<X509Certificate> resultCerts,
+ boolean checkAll)
+ {
+ X509Certificate targetCert = selector.getCertificate();
+ if (targetCert != null) {
+ // no need to search CertStores
+ if (selector.match(targetCert) && !X509CertImpl.isSelfSigned
+ (targetCert, buildParams.sigProvider())) {
+ if (debug != null) {
+ debug.println("Builder.addMatchingCerts: adding target cert");
+ }
+ return resultCerts.add(targetCert);
+ }
+ return false;
+ }
+ boolean add = false;
+ for (CertStore store : certStores) {
+ try {
+ Collection<? extends Certificate> certs =
+ store.getCertificates(selector);
+ for (Certificate cert : certs) {
+ if (!X509CertImpl.isSelfSigned
+ ((X509Certificate)cert, buildParams.sigProvider())) {
+ if (resultCerts.add((X509Certificate)cert)) {
+ add = true;
+ }
+ }
+ }
+ if (!checkAll && add) {
+ return true;
+ }
+ } catch (CertStoreException cse) {
+ // if getCertificates throws a CertStoreException, we ignore
+ // it and move on to the next CertStore
+ if (debug != null) {
+ debug.println("Builder.addMatchingCerts, non-fatal " +
+ "exception retrieving certs: " + cse);
+ cse.printStackTrace();
+ }
+ }
+ }
+ return add;
+ }
+}
diff --git a/ojluni/src/main/java/sun/security/provider/certpath/CertId.java b/ojluni/src/main/java/sun/security/provider/certpath/CertId.java
new file mode 100644
index 0000000..ff7be69
--- /dev/null
+++ b/ojluni/src/main/java/sun/security/provider/certpath/CertId.java
@@ -0,0 +1,235 @@
+/*
+ * Copyright (c) 2003, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * 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.io.IOException;
+import java.math.BigInteger;
+import java.security.MessageDigest;
+import java.security.NoSuchAlgorithmException;
+import java.security.PublicKey;
+import java.security.cert.X509Certificate;
+import java.util.Arrays;
+import javax.security.auth.x500.X500Principal;
+import sun.misc.HexDumpEncoder;
+import sun.security.x509.*;
+import sun.security.util.*;
+
+/**
+ * This class corresponds to the CertId field in OCSP Request
+ * and the OCSP Response. The ASN.1 definition for CertID is defined
+ * in RFC 2560 as:
+ * <pre>
+ *
+ * CertID ::= SEQUENCE {
+ * hashAlgorithm AlgorithmIdentifier,
+ * issuerNameHash OCTET STRING, -- Hash of Issuer's DN
+ * issuerKeyHash OCTET STRING, -- Hash of Issuers public key
+ * serialNumber CertificateSerialNumber
+ * }
+ *
+ * </pre>
+ *
+ * @author Ram Marti
+ */
+
+public class CertId {
+
+ private static final boolean debug = false;
+ private static final AlgorithmId SHA1_ALGID
+ = new AlgorithmId(AlgorithmId.SHA_oid);
+ private final AlgorithmId hashAlgId;
+ private final byte[] issuerNameHash;
+ private final byte[] issuerKeyHash;
+ private final SerialNumber certSerialNumber;
+ private int myhash = -1; // hashcode for this CertId
+
+ /**
+ * Creates a CertId. The hash algorithm used is SHA-1.
+ */
+ public CertId(X509Certificate issuerCert, SerialNumber serialNumber)
+ throws IOException {
+
+ this(issuerCert.getSubjectX500Principal(),
+ issuerCert.getPublicKey(), serialNumber);
+ }
+
+ public CertId(X500Principal issuerName, PublicKey issuerKey,
+ SerialNumber serialNumber) throws IOException {
+
+ // compute issuerNameHash
+ MessageDigest md = null;
+ try {
+ md = MessageDigest.getInstance("SHA1");
+ } catch (NoSuchAlgorithmException nsae) {
+ throw new IOException("Unable to create CertId", nsae);
+ }
+ hashAlgId = SHA1_ALGID;
+ md.update(issuerName.getEncoded());
+ issuerNameHash = md.digest();
+
+ // compute issuerKeyHash (remove the tag and length)
+ byte[] pubKey = issuerKey.getEncoded();
+ DerValue val = new DerValue(pubKey);
+ DerValue[] seq = new DerValue[2];
+ seq[0] = val.data.getDerValue(); // AlgorithmID
+ seq[1] = val.data.getDerValue(); // Key
+ byte[] keyBytes = seq[1].getBitString();
+ md.update(keyBytes);
+ issuerKeyHash = md.digest();
+ certSerialNumber = serialNumber;
+
+ if (debug) {
+ HexDumpEncoder encoder = new HexDumpEncoder();
+ System.out.println("Issuer Name is " + issuerName);
+ System.out.println("issuerNameHash is " +
+ encoder.encodeBuffer(issuerNameHash));
+ System.out.println("issuerKeyHash is " +
+ encoder.encodeBuffer(issuerKeyHash));
+ System.out.println("SerialNumber is " + serialNumber.getNumber());
+ }
+ }
+
+ /**
+ * Creates a CertId from its ASN.1 DER encoding.
+ */
+ public CertId(DerInputStream derIn) throws IOException {
+ hashAlgId = AlgorithmId.parse(derIn.getDerValue());
+ issuerNameHash = derIn.getOctetString();
+ issuerKeyHash = derIn.getOctetString();
+ certSerialNumber = new SerialNumber(derIn);
+ }
+
+ /**
+ * Return the hash algorithm identifier.
+ */
+ public AlgorithmId getHashAlgorithm() {
+ return hashAlgId;
+ }
+
+ /**
+ * Return the hash value for the issuer name.
+ */
+ public byte[] getIssuerNameHash() {
+ return issuerNameHash;
+ }
+
+ /**
+ * Return the hash value for the issuer key.
+ */
+ public byte[] getIssuerKeyHash() {
+ return issuerKeyHash;
+ }
+
+ /**
+ * Return the serial number.
+ */
+ public BigInteger getSerialNumber() {
+ return certSerialNumber.getNumber();
+ }
+
+ /**
+ * Encode the CertId using ASN.1 DER.
+ * The hash algorithm used is SHA-1.
+ */
+ public void encode(DerOutputStream out) throws IOException {
+
+ DerOutputStream tmp = new DerOutputStream();
+ hashAlgId.encode(tmp);
+ tmp.putOctetString(issuerNameHash);
+ tmp.putOctetString(issuerKeyHash);
+ certSerialNumber.encode(tmp);
+ out.write(DerValue.tag_Sequence, tmp);
+
+ if (debug) {
+ HexDumpEncoder encoder = new HexDumpEncoder();
+ System.out.println("Encoded certId is " +
+ encoder.encode(out.toByteArray()));
+ }
+ }
+
+ /**
+ * Returns a hashcode value for this CertId.
+ *
+ * @return the hashcode value.
+ */
+ @Override public int hashCode() {
+ if (myhash == -1) {
+ myhash = hashAlgId.hashCode();
+ for (int i = 0; i < issuerNameHash.length; i++) {
+ myhash += issuerNameHash[i] * i;
+ }
+ for (int i = 0; i < issuerKeyHash.length; i++) {
+ myhash += issuerKeyHash[i] * i;
+ }
+ myhash += certSerialNumber.getNumber().hashCode();
+ }
+ return myhash;
+ }
+
+ /**
+ * Compares this CertId for equality with the specified
+ * object. Two CertId objects are considered equal if their hash algorithms,
+ * their issuer name and issuer key hash values and their serial numbers
+ * are equal.
+ *
+ * @param other the object to test for equality with this object.
+ * @return true if the objects are considered equal, false otherwise.
+ */
+ @Override public boolean equals(Object other) {
+ if (this == other) {
+ return true;
+ }
+ if (other == null || (!(other instanceof CertId))) {
+ return false;
+ }
+
+ CertId that = (CertId) other;
+ if (hashAlgId.equals(that.getHashAlgorithm()) &&
+ Arrays.equals(issuerNameHash, that.getIssuerNameHash()) &&
+ Arrays.equals(issuerKeyHash, that.getIssuerKeyHash()) &&
+ certSerialNumber.getNumber().equals(that.getSerialNumber())) {
+ return true;
+ } else {
+ return false;
+ }
+ }
+
+ /**
+ * Create a string representation of the CertId.
+ */
+ @Override public String toString() {
+ StringBuilder sb = new StringBuilder();
+ sb.append("CertId \n");
+ sb.append("Algorithm: " + hashAlgId.toString() +"\n");
+ sb.append("issuerNameHash \n");
+ HexDumpEncoder encoder = new HexDumpEncoder();
+ sb.append(encoder.encode(issuerNameHash));
+ sb.append("\nissuerKeyHash: \n");
+ sb.append(encoder.encode(issuerKeyHash));
+ sb.append("\n" + certSerialNumber.toString());
+ return sb.toString();
+ }
+}
diff --git a/ojluni/src/main/java/sun/security/provider/certpath/CertPathHelper.java b/ojluni/src/main/java/sun/security/provider/certpath/CertPathHelper.java
old mode 100755
new mode 100644
index bd3a342..af6da8a
--- a/ojluni/src/main/java/sun/security/provider/certpath/CertPathHelper.java
+++ b/ojluni/src/main/java/sun/security/provider/certpath/CertPathHelper.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2002, 2009, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2002, 2013, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
diff --git a/ojluni/src/main/java/sun/security/provider/certpath/CertStoreHelper.java b/ojluni/src/main/java/sun/security/provider/certpath/CertStoreHelper.java
new file mode 100644
index 0000000..b8b562e
--- /dev/null
+++ b/ojluni/src/main/java/sun/security/provider/certpath/CertStoreHelper.java
@@ -0,0 +1,148 @@
+/*
+ * Copyright (c) 2009, 2012, 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.net.URI;
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.Map;
+import java.security.AccessController;
+import java.security.NoSuchAlgorithmException;
+import java.security.InvalidAlgorithmParameterException;
+import java.security.PrivilegedActionException;
+import java.security.PrivilegedExceptionAction;
+import java.security.cert.CertStore;
+import java.security.cert.CertStoreException;
+import java.security.cert.X509CertSelector;
+import java.security.cert.X509CRLSelector;
+import javax.security.auth.x500.X500Principal;
+import java.io.IOException;
+
+import sun.security.util.Cache;
+
+/**
+ * Helper used by URICertStore and others when delegating to another CertStore
+ * to fetch certs and CRLs.
+ */
+
+public abstract class CertStoreHelper {
+
+ private static final int NUM_TYPES = 2;
+ private final static Map<String,String> classMap = new HashMap<>(NUM_TYPES);
+ static {
+ classMap.put(
+ "LDAP",
+ "sun.security.provider.certpath.ldap.LDAPCertStoreHelper");
+ classMap.put(
+ "SSLServer",
+ "sun.security.provider.certpath.ssl.SSLServerCertStoreHelper");
+ };
+ private static Cache<String, CertStoreHelper> cache
+ = Cache.newSoftMemoryCache(NUM_TYPES);
+
+ public static CertStoreHelper getInstance(final String type)
+ throws NoSuchAlgorithmException
+ {
+ CertStoreHelper helper = cache.get(type);
+ if (helper != null) {
+ return helper;
+ }
+ final String cl = classMap.get(type);
+ if (cl == null) {
+ throw new NoSuchAlgorithmException(type + " not available");
+ }
+ try {
+ helper = AccessController.doPrivileged(
+ new PrivilegedExceptionAction<CertStoreHelper>() {
+ public CertStoreHelper run() throws ClassNotFoundException {
+ try {
+ Class<?> c = Class.forName(cl, true, null);
+ CertStoreHelper csh
+ = (CertStoreHelper)c.newInstance();
+ cache.put(type, csh);
+ return csh;
+ } catch (InstantiationException |
+ IllegalAccessException e) {
+ throw new AssertionError(e);
+ }
+ }
+ });
+ return helper;
+ } catch (PrivilegedActionException e) {
+ throw new NoSuchAlgorithmException(type + " not available",
+ e.getException());
+ }
+ }
+
+ static boolean isCausedByNetworkIssue(String type, CertStoreException cse) {
+ switch (type) {
+ case "LDAP":
+ case "SSLServer":
+ try {
+ CertStoreHelper csh = CertStoreHelper.getInstance(type);
+ return csh.isCausedByNetworkIssue(cse);
+ } catch (NoSuchAlgorithmException nsae) {
+ return false;
+ }
+ case "URI":
+ Throwable t = cse.getCause();
+ return (t != null && t instanceof IOException);
+ default:
+ // we don't know about any other remote CertStore types
+ return false;
+ }
+ }
+
+ /**
+ * Returns a CertStore using the given URI as parameters.
+ */
+ public abstract CertStore getCertStore(URI uri)
+ throws NoSuchAlgorithmException, InvalidAlgorithmParameterException;
+
+ /**
+ * Wraps an existing X509CertSelector when needing to avoid DN matching
+ * issues.
+ */
+ public abstract X509CertSelector wrap(X509CertSelector selector,
+ X500Principal certSubject,
+ String dn)
+ throws IOException;
+
+ /**
+ * Wraps an existing X509CRLSelector when needing to avoid DN matching
+ * issues.
+ */
+ public abstract X509CRLSelector wrap(X509CRLSelector selector,
+ Collection<X500Principal> certIssuers,
+ String dn)
+ throws IOException;
+
+ /**
+ * Returns true if the cause of the CertStoreException is a network
+ * related issue.
+ */
+ public abstract boolean isCausedByNetworkIssue(CertStoreException e);
+}
diff --git a/ojluni/src/main/java/sun/security/provider/certpath/CollectionCertStore.java b/ojluni/src/main/java/sun/security/provider/certpath/CollectionCertStore.java
new file mode 100644
index 0000000..f991434
--- /dev/null
+++ b/ojluni/src/main/java/sun/security/provider/certpath/CollectionCertStore.java
@@ -0,0 +1,185 @@
+/*
+ * Copyright (c) 2000, 2012, 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.cert.Certificate;
+import java.security.cert.CRL;
+import java.util.Collection;
+import java.util.ConcurrentModificationException;
+import java.util.HashSet;
+import java.security.cert.CertSelector;
+import java.security.cert.CertStore;
+import java.security.cert.CertStoreException;
+import java.security.cert.CertStoreParameters;
+import java.security.cert.CollectionCertStoreParameters;
+import java.security.cert.CRLSelector;
+import java.security.cert.CertStoreSpi;
+
+/**
+ * A <code>CertStore</code> that retrieves <code>Certificates</code> and
+ * <code>CRL</code>s from a <code>Collection</code>.
+ * <p>
+ * Before calling the {@link #engineGetCertificates engineGetCertificates} or
+ * {@link #engineGetCRLs engineGetCRLs} methods, the
+ * {@link #CollectionCertStore(CertStoreParameters)
+ * CollectionCertStore(CertStoreParameters)} constructor is called to
+ * create the <code>CertStore</code> and establish the
+ * <code>Collection</code> from which <code>Certificate</code>s and
+ * <code>CRL</code>s will be retrieved. If the specified
+ * <code>Collection</code> contains an object that is not a
+ * <code>Certificate</code> or <code>CRL</code>, that object will be
+ * ignored.
+ * <p>
+ * <b>Concurrent Access</b>
+ * <p>
+ * As described in the javadoc for <code>CertStoreSpi</code>, the
+ * <code>engineGetCertificates</code> and <code>engineGetCRLs</code> methods
+ * must be thread-safe. That is, multiple threads may concurrently
+ * invoke these methods on a single <code>CollectionCertStore</code>
+ * object (or more than one) with no ill effects.
+ * <p>
+ * This is achieved by requiring that the <code>Collection</code> passed to
+ * the {@link #CollectionCertStore(CertStoreParameters)
+ * CollectionCertStore(CertStoreParameters)} constructor (via the
+ * <code>CollectionCertStoreParameters</code> object) must have fail-fast
+ * iterators. Simultaneous modifications to the <code>Collection</code> can thus be
+ * detected and certificate or CRL retrieval can be retried. The fact that
+ * <code>Certificate</code>s and <code>CRL</code>s must be thread-safe is also
+ * essential.
+ *
+ * @see java.security.cert.CertStore
+ *
+ * @since 1.4
+ * @author Steve Hanna
+ */
+public class CollectionCertStore extends CertStoreSpi {
+
+ private Collection<?> coll;
+
+ /**
+ * Creates a <code>CertStore</code> with the specified parameters.
+ * For this class, the parameters object must be an instance of
+ * <code>CollectionCertStoreParameters</code>. The <code>Collection</code>
+ * included in the <code>CollectionCertStoreParameters</code> object
+ * must be thread-safe.
+ *
+ * @param params the algorithm parameters
+ * @exception InvalidAlgorithmParameterException if params is not an
+ * instance of <code>CollectionCertStoreParameters</code>
+ */
+ public CollectionCertStore(CertStoreParameters params)
+ throws InvalidAlgorithmParameterException
+ {
+ super(params);
+ if (!(params instanceof CollectionCertStoreParameters))
+ throw new InvalidAlgorithmParameterException(
+ "parameters must be CollectionCertStoreParameters");
+ coll = ((CollectionCertStoreParameters) params).getCollection();
+ }
+
+ /**
+ * Returns a <code>Collection</code> of <code>Certificate</code>s that
+ * match the specified selector. If no <code>Certificate</code>s
+ * match the selector, an empty <code>Collection</code> will be returned.
+ *
+ * @param selector a <code>CertSelector</code> used to select which
+ * <code>Certificate</code>s should be returned. Specify <code>null</code>
+ * to return all <code>Certificate</code>s.
+ * @return a <code>Collection</code> of <code>Certificate</code>s that
+ * match the specified selector
+ * @throws CertStoreException if an exception occurs
+ */
+ @Override
+ public Collection<Certificate> engineGetCertificates
+ (CertSelector selector) throws CertStoreException {
+ if (coll == null) {
+ throw new CertStoreException("Collection is null");
+ }
+ // Tolerate a few ConcurrentModificationExceptions
+ for (int c = 0; c < 10; c++) {
+ try {
+ HashSet<Certificate> result = new HashSet<>();
+ if (selector != null) {
+ for (Object o : coll) {
+ if ((o instanceof Certificate) &&
+ selector.match((Certificate) o))
+ result.add((Certificate)o);
+ }
+ } else {
+ for (Object o : coll) {
+ if (o instanceof Certificate)
+ result.add((Certificate)o);
+ }
+ }
+ return(result);
+ } catch (ConcurrentModificationException e) { }
+ }
+ throw new ConcurrentModificationException("Too many "
+ + "ConcurrentModificationExceptions");
+ }
+
+ /**
+ * Returns a <code>Collection</code> of <code>CRL</code>s that
+ * match the specified selector. If no <code>CRL</code>s
+ * match the selector, an empty <code>Collection</code> will be returned.
+ *
+ * @param selector a <code>CRLSelector</code> used to select which
+ * <code>CRL</code>s should be returned. Specify <code>null</code>
+ * to return all <code>CRL</code>s.
+ * @return a <code>Collection</code> of <code>CRL</code>s that
+ * match the specified selector
+ * @throws CertStoreException if an exception occurs
+ */
+ @Override
+ public Collection<CRL> engineGetCRLs(CRLSelector selector)
+ throws CertStoreException
+ {
+ if (coll == null)
+ throw new CertStoreException("Collection is null");
+
+ // Tolerate a few ConcurrentModificationExceptions
+ for (int c = 0; c < 10; c++) {
+ try {
+ HashSet<CRL> result = new HashSet<>();
+ if (selector != null) {
+ for (Object o : coll) {
+ if ((o instanceof CRL) && selector.match((CRL) o))
+ result.add((CRL)o);
+ }
+ } else {
+ for (Object o : coll) {
+ if (o instanceof CRL)
+ result.add((CRL)o);
+ }
+ }
+ return result;
+ } catch (ConcurrentModificationException e) { }
+ }
+ throw new ConcurrentModificationException("Too many "
+ + "ConcurrentModificationExceptions");
+ }
+}
diff --git a/ojluni/src/main/java/sun/security/provider/certpath/ConstraintsChecker.java b/ojluni/src/main/java/sun/security/provider/certpath/ConstraintsChecker.java
new file mode 100644
index 0000000..a08c990
--- /dev/null
+++ b/ojluni/src/main/java/sun/security/provider/certpath/ConstraintsChecker.java
@@ -0,0 +1,308 @@
+/*
+ * Copyright (c) 2000, 2012, 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.io.IOException;
+import java.security.cert.Certificate;
+import java.security.cert.CertificateException;
+import java.security.cert.CertPathValidatorException;
+import java.security.cert.PKIXCertPathChecker;
+import java.security.cert.PKIXReason;
+import java.security.cert.X509Certificate;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.Set;
+
+import sun.security.util.Debug;
+import static sun.security.x509.PKIXExtensions.*;
+import sun.security.x509.NameConstraintsExtension;
+import sun.security.x509.X509CertImpl;
+
+/**
+ * ConstraintsChecker is a <code>PKIXCertPathChecker</code> that checks
+ * constraints information on a PKIX certificate, namely basic constraints
+ * and name constraints.
+ *
+ * @since 1.4
+ * @author Yassir Elley
+ */
+class ConstraintsChecker extends PKIXCertPathChecker {
+
+ private static final Debug debug = Debug.getInstance("certpath");
+ /* length of cert path */
+ private final int certPathLength;
+ /* current maximum path length (as defined in PKIX) */
+ private int maxPathLength;
+ /* current index of cert */
+ private int i;
+ private NameConstraintsExtension prevNC;
+
+ private Set<String> supportedExts;
+
+ /**
+ * Creates a ConstraintsChecker.
+ *
+ * @param certPathLength the length of the certification path
+ */
+ ConstraintsChecker(int certPathLength) {
+ this.certPathLength = certPathLength;
+ }
+
+ @Override
+ public void init(boolean forward) throws CertPathValidatorException {
+ if (!forward) {
+ i = 0;
+ maxPathLength = certPathLength;
+ prevNC = null;
+ } else {
+ throw new CertPathValidatorException
+ ("forward checking not supported");
+ }
+ }
+
+ @Override
+ public boolean isForwardCheckingSupported() {
+ return false;
+ }
+
+ @Override
+ public Set<String> getSupportedExtensions() {
+ if (supportedExts == null) {
+ supportedExts = new HashSet<String>(2);
+ supportedExts.add(BasicConstraints_Id.toString());
+ supportedExts.add(NameConstraints_Id.toString());
+ supportedExts = Collections.unmodifiableSet(supportedExts);
+ }
+ return supportedExts;
+ }
+
+ /**
+ * Performs the basic constraints and name constraints
+ * checks on the certificate using its internal state.
+ *
+ * @param cert the <code>Certificate</code> to be checked
+ * @param unresCritExts a <code>Collection</code> of OID strings
+ * representing the current set of unresolved critical extensions
+ * @throws CertPathValidatorException if the specified certificate
+ * does not pass the check
+ */
+ @Override
+ public void check(Certificate cert, Collection<String> unresCritExts)
+ throws CertPathValidatorException
+ {
+ X509Certificate currCert = (X509Certificate)cert;
+
+ i++;
+ // MUST run NC check second, since it depends on BC check to
+ // update remainingCerts
+ checkBasicConstraints(currCert);
+ verifyNameConstraints(currCert);
+
+ if (unresCritExts != null && !unresCritExts.isEmpty()) {
+ unresCritExts.remove(BasicConstraints_Id.toString());
+ unresCritExts.remove(NameConstraints_Id.toString());
+ }
+ }
+
+ /**
+ * Internal method to check the name constraints against a cert
+ */
+ private void verifyNameConstraints(X509Certificate currCert)
+ throws CertPathValidatorException
+ {
+ String msg = "name constraints";
+ if (debug != null) {
+ debug.println("---checking " + msg + "...");
+ }
+
+ // check name constraints only if there is a previous name constraint
+ // and either the currCert is the final cert or the currCert is not
+ // self-issued
+ if (prevNC != null && ((i == certPathLength) ||
+ !X509CertImpl.isSelfIssued(currCert))) {
+ if (debug != null) {
+ debug.println("prevNC = " + prevNC);
+ debug.println("currDN = " + currCert.getSubjectX500Principal());
+ }
+
+ try {
+ if (!prevNC.verify(currCert)) {
+ throw new CertPathValidatorException(msg + " check failed",
+ null, null, -1, PKIXReason.INVALID_NAME);
+ }
+ } catch (IOException ioe) {
+ throw new CertPathValidatorException(ioe);
+ }
+ }
+
+ // merge name constraints regardless of whether cert is self-issued
+ prevNC = mergeNameConstraints(currCert, prevNC);
+
+ if (debug != null)
+ debug.println(msg + " verified.");
+ }
+
+ /**
+ * Helper to fold sets of name constraints together
+ */
+ static NameConstraintsExtension mergeNameConstraints(
+ X509Certificate currCert, NameConstraintsExtension prevNC)
+ throws CertPathValidatorException
+ {
+ X509CertImpl currCertImpl;
+ try {
+ currCertImpl = X509CertImpl.toImpl(currCert);
+ } catch (CertificateException ce) {
+ throw new CertPathValidatorException(ce);
+ }
+
+ NameConstraintsExtension newConstraints =
+ currCertImpl.getNameConstraintsExtension();
+
+ if (debug != null) {
+ debug.println("prevNC = " + prevNC);
+ debug.println("newNC = " + String.valueOf(newConstraints));
+ }
+
+ // if there are no previous name constraints, we just return the
+ // new name constraints.
+ if (prevNC == null) {
+ if (debug != null) {
+ debug.println("mergedNC = " + String.valueOf(newConstraints));
+ }
+ if (newConstraints == null) {
+ return newConstraints;
+ } else {
+ // Make sure we do a clone here, because we're probably
+ // going to modify this object later and we don't want to
+ // be sharing it with a Certificate object!
+ return (NameConstraintsExtension)newConstraints.clone();
+ }
+ } else {
+ try {
+ // after merge, prevNC should contain the merged constraints
+ prevNC.merge(newConstraints);
+ } catch (IOException ioe) {
+ throw new CertPathValidatorException(ioe);
+ }
+ if (debug != null) {
+ debug.println("mergedNC = " + prevNC);
+ }
+ return prevNC;
+ }
+ }
+
+ /**
+ * Internal method to check that a given cert meets basic constraints.
+ */
+ private void checkBasicConstraints(X509Certificate currCert)
+ throws CertPathValidatorException
+ {
+ String msg = "basic constraints";
+ if (debug != null) {
+ debug.println("---checking " + msg + "...");
+ debug.println("i = " + i);
+ debug.println("maxPathLength = " + maxPathLength);
+ }
+
+ /* check if intermediate cert */
+ if (i < certPathLength) {
+ // RFC5280: If certificate i is a version 3 certificate, verify
+ // that the basicConstraints extension is present and that cA is
+ // set to TRUE. (If certificate i is a version 1 or version 2
+ // certificate, then the application MUST either verify that
+ // certificate i is a CA certificate through out-of-band means
+ // or reject the certificate. Conforming implementations may
+ // choose to reject all version 1 and version 2 intermediate
+ // certificates.)
+ //
+ // We choose to reject all version 1 and version 2 intermediate
+ // certificates except that it is self issued by the trust
+ // anchor in order to support key rollover or changes in
+ // certificate policies.
+ int pathLenConstraint = -1;
+ if (currCert.getVersion() < 3) { // version 1 or version 2
+ if (i == 1) { // issued by a trust anchor
+ if (X509CertImpl.isSelfIssued(currCert)) {
+ pathLenConstraint = Integer.MAX_VALUE;
+ }
+ }
+ } else {
+ pathLenConstraint = currCert.getBasicConstraints();
+ }
+
+ if (pathLenConstraint == -1) {
+ throw new CertPathValidatorException
+ (msg + " check failed: this is not a CA certificate",
+ null, null, -1, PKIXReason.NOT_CA_CERT);
+ }
+
+ if (!X509CertImpl.isSelfIssued(currCert)) {
+ if (maxPathLength <= 0) {
+ throw new CertPathValidatorException
+ (msg + " check failed: pathLenConstraint violated - "
+ + "this cert must be the last cert in the "
+ + "certification path", null, null, -1,
+ PKIXReason.PATH_TOO_LONG);
+ }
+ maxPathLength--;
+ }
+ if (pathLenConstraint < maxPathLength)
+ maxPathLength = pathLenConstraint;
+ }
+
+ if (debug != null) {
+ debug.println("after processing, maxPathLength = " + maxPathLength);
+ debug.println(msg + " verified.");
+ }
+ }
+
+ /**
+ * Merges the specified maxPathLength with the pathLenConstraint
+ * obtained from the certificate.
+ *
+ * @param cert the <code>X509Certificate</code>
+ * @param maxPathLength the previous maximum path length
+ * @return the new maximum path length constraint (-1 means no more
+ * certificates can follow, Integer.MAX_VALUE means path length is
+ * unconstrained)
+ */
+ static int mergeBasicConstraints(X509Certificate cert, int maxPathLength) {
+
+ int pathLenConstraint = cert.getBasicConstraints();
+
+ if (!X509CertImpl.isSelfIssued(cert)) {
+ maxPathLength--;
+ }
+
+ if (pathLenConstraint < maxPathLength) {
+ maxPathLength = pathLenConstraint;
+ }
+
+ return maxPathLength;
+ }
+}
diff --git a/ojluni/src/main/java/sun/security/provider/certpath/DistributionPointFetcher.java b/ojluni/src/main/java/sun/security/provider/certpath/DistributionPointFetcher.java
new file mode 100644
index 0000000..ecf609b
--- /dev/null
+++ b/ojluni/src/main/java/sun/security/provider/certpath/DistributionPointFetcher.java
@@ -0,0 +1,773 @@
+/*
+ * Copyright (c) 2002, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * 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.io.*;
+import java.net.URI;
+import java.security.*;
+import java.security.cert.*;
+import javax.security.auth.x500.X500Principal;
+import java.util.*;
+
+import sun.security.util.Debug;
+import sun.security.util.DerOutputStream;
+import static sun.security.x509.PKIXExtensions.*;
+import sun.security.x509.*;
+
+/**
+ * Class to obtain CRLs via the CRLDistributionPoints extension.
+ * Note that the functionality of this class must be explicitly enabled
+ * via a system property, see the USE_CRLDP variable below.
+ *
+ * This class uses the URICertStore class to fetch CRLs. The URICertStore
+ * class also implements CRL caching: see the class description for more
+ * information.
+ *
+ * @author Andreas Sterbenz
+ * @author Sean Mullan
+ * @since 1.4.2
+ */
+public class DistributionPointFetcher {
+
+ private static final Debug debug = Debug.getInstance("certpath");
+
+ private static final boolean[] ALL_REASONS =
+ {true, true, true, true, true, true, true, true, true};
+
+ /**
+ * Private instantiation only.
+ */
+ private DistributionPointFetcher() {}
+
+ /**
+ * Return the X509CRLs matching this selector. The selector must be
+ * an X509CRLSelector with certificateChecking set.
+ */
+ public static Collection<X509CRL> getCRLs(X509CRLSelector selector,
+ boolean signFlag,
+ PublicKey prevKey,
+ String provider,
+ List<CertStore> certStores,
+ boolean[] reasonsMask,
+ Set<TrustAnchor> trustAnchors,
+ Date validity)
+ throws CertStoreException
+ {
+ return getCRLs(selector, signFlag, prevKey, null, provider, certStores,
+ reasonsMask, trustAnchors, validity);
+ }
+
+ /**
+ * Return the X509CRLs matching this selector. The selector must be
+ * an X509CRLSelector with certificateChecking set.
+ */
+ public static Collection<X509CRL> getCRLs(X509CRLSelector selector,
+ boolean signFlag,
+ PublicKey prevKey,
+ X509Certificate prevCert,
+ String provider,
+ List<CertStore> certStores,
+ boolean[] reasonsMask,
+ Set<TrustAnchor> trustAnchors,
+ Date validity)
+ throws CertStoreException
+ {
+ X509Certificate cert = selector.getCertificateChecking();
+ if (cert == null) {
+ return Collections.emptySet();
+ }
+ try {
+ X509CertImpl certImpl = X509CertImpl.toImpl(cert);
+ if (debug != null) {
+ debug.println("DistributionPointFetcher.getCRLs: Checking "
+ + "CRLDPs for " + certImpl.getSubjectX500Principal());
+ }
+ CRLDistributionPointsExtension ext =
+ certImpl.getCRLDistributionPointsExtension();
+ if (ext == null) {
+ if (debug != null) {
+ debug.println("No CRLDP ext");
+ }
+ return Collections.emptySet();
+ }
+ List<DistributionPoint> points =
+ ext.get(CRLDistributionPointsExtension.POINTS);
+ Set<X509CRL> results = new HashSet<>();
+ for (Iterator<DistributionPoint> t = points.iterator();
+ t.hasNext() && !Arrays.equals(reasonsMask, ALL_REASONS); ) {
+ DistributionPoint point = t.next();
+ Collection<X509CRL> crls = getCRLs(selector, certImpl,
+ point, reasonsMask, signFlag, prevKey, prevCert, provider,
+ certStores, trustAnchors, validity);
+ results.addAll(crls);
+ }
+ if (debug != null) {
+ debug.println("Returning " + results.size() + " CRLs");
+ }
+ return results;
+ } catch (CertificateException | IOException e) {
+ return Collections.emptySet();
+ }
+ }
+
+ /**
+ * Download CRLs from the given distribution point, verify and return them.
+ * See the top of the class for current limitations.
+ *
+ * @throws CertStoreException if there is an error retrieving the CRLs
+ * from one of the GeneralNames and no other CRLs are retrieved from
+ * the other GeneralNames. If more than one GeneralName throws an
+ * exception then the one from the last GeneralName is thrown.
+ */
+ private static Collection<X509CRL> getCRLs(X509CRLSelector selector,
+ X509CertImpl certImpl, DistributionPoint point, boolean[] reasonsMask,
+ boolean signFlag, PublicKey prevKey, X509Certificate prevCert,
+ String provider, List<CertStore> certStores,
+ Set<TrustAnchor> trustAnchors, Date validity)
+ throws CertStoreException {
+
+ // check for full name
+ GeneralNames fullName = point.getFullName();
+ if (fullName == null) {
+ // check for relative name
+ RDN relativeName = point.getRelativeName();
+ if (relativeName == null) {
+ return Collections.emptySet();
+ }
+ try {
+ GeneralNames crlIssuers = point.getCRLIssuer();
+ if (crlIssuers == null) {
+ fullName = getFullNames
+ ((X500Name) certImpl.getIssuerDN(), relativeName);
+ } else {
+ // should only be one CRL Issuer
+ if (crlIssuers.size() != 1) {
+ return Collections.emptySet();
+ } else {
+ fullName = getFullNames
+ ((X500Name) crlIssuers.get(0).getName(), relativeName);
+ }
+ }
+ } catch (IOException ioe) {
+ return Collections.emptySet();
+ }
+ }
+ Collection<X509CRL> possibleCRLs = new ArrayList<>();
+ CertStoreException savedCSE = null;
+ for (Iterator<GeneralName> t = fullName.iterator(); t.hasNext(); ) {
+ try {
+ GeneralName name = t.next();
+ if (name.getType() == GeneralNameInterface.NAME_DIRECTORY) {
+ X500Name x500Name = (X500Name) name.getName();
+ possibleCRLs.addAll(
+ getCRLs(x500Name, certImpl.getIssuerX500Principal(),
+ certStores));
+ } else if (name.getType() == GeneralNameInterface.NAME_URI) {
+ URIName uriName = (URIName)name.getName();
+ X509CRL crl = getCRL(uriName);
+ if (crl != null) {
+ possibleCRLs.add(crl);
+ }
+ }
+ } catch (CertStoreException cse) {
+ savedCSE = cse;
+ }
+ }
+ // only throw CertStoreException if no CRLs are retrieved
+ if (possibleCRLs.isEmpty() && savedCSE != null) {
+ throw savedCSE;
+ }
+
+ Collection<X509CRL> crls = new ArrayList<>(2);
+ for (X509CRL crl : possibleCRLs) {
+ try {
+ // make sure issuer is not set
+ // we check the issuer in verifyCRLs method
+ selector.setIssuerNames(null);
+ if (selector.match(crl) && verifyCRL(certImpl, point, crl,
+ reasonsMask, signFlag, prevKey, prevCert, provider,
+ trustAnchors, certStores, validity)) {
+ crls.add(crl);
+ }
+ } catch (IOException | CRLException e) {
+ // don't add the CRL
+ if (debug != null) {
+ debug.println("Exception verifying CRL: " + e.getMessage());
+ e.printStackTrace();
+ }
+ }
+ }
+ return crls;
+ }
+
+ /**
+ * Download CRL from given URI.
+ */
+ private static X509CRL getCRL(URIName name) throws CertStoreException {
+ URI uri = name.getURI();
+ if (debug != null) {
+ debug.println("Trying to fetch CRL from DP " + uri);
+ }
+ CertStore ucs = null;
+ try {
+ ucs = URICertStore.getInstance
+ (new URICertStore.URICertStoreParameters(uri));
+ } catch (InvalidAlgorithmParameterException |
+ NoSuchAlgorithmException e) {
+ if (debug != null) {
+ debug.println("Can't create URICertStore: " + e.getMessage());
+ }
+ return null;
+ }
+
+ Collection<? extends CRL> crls = ucs.getCRLs(null);
+ if (crls.isEmpty()) {
+ return null;
+ } else {
+ return (X509CRL) crls.iterator().next();
+ }
+ }
+
+ /**
+ * Fetch CRLs from certStores.
+ *
+ * @throws CertStoreException if there is an error retrieving the CRLs from
+ * one of the CertStores and no other CRLs are retrieved from
+ * the other CertStores. If more than one CertStore throws an
+ * exception then the one from the last CertStore is thrown.
+ */
+ private static Collection<X509CRL> getCRLs(X500Name name,
+ X500Principal certIssuer,
+ List<CertStore> certStores)
+ throws CertStoreException
+ {
+ if (debug != null) {
+ debug.println("Trying to fetch CRL from DP " + name);
+ }
+ X509CRLSelector xcs = new X509CRLSelector();
+ xcs.addIssuer(name.asX500Principal());
+ xcs.addIssuer(certIssuer);
+ Collection<X509CRL> crls = new ArrayList<>();
+ CertStoreException savedCSE = null;
+ for (CertStore store : certStores) {
+ try {
+ for (CRL crl : store.getCRLs(xcs)) {
+ crls.add((X509CRL)crl);
+ }
+ } catch (CertStoreException cse) {
+ if (debug != null) {
+ debug.println("Exception while retrieving " +
+ "CRLs: " + cse);
+ cse.printStackTrace();
+ }
+ savedCSE = new PKIX.CertStoreTypeException(store.getType(),cse);
+ }
+ }
+ // only throw CertStoreException if no CRLs are retrieved
+ if (crls.isEmpty() && savedCSE != null) {
+ throw savedCSE;
+ } else {
+ return crls;
+ }
+ }
+
+ /**
+ * Verifies a CRL for the given certificate's Distribution Point to
+ * ensure it is appropriate for checking the revocation status.
+ *
+ * @param certImpl the certificate whose revocation status is being checked
+ * @param point one of the distribution points of the certificate
+ * @param crl the CRL
+ * @param reasonsMask the interim reasons mask
+ * @param signFlag true if prevKey can be used to verify the CRL
+ * @param prevKey the public key that verifies the certificate's signature
+ * @param prevCert the certificate whose public key verifies
+ * {@code certImpl}'s signature
+ * @param provider the Signature provider to use
+ * @param trustAnchors a {@code Set} of {@code TrustAnchor}s
+ * @param certStores a {@code List} of {@code CertStore}s to be used in
+ * finding certificates and CRLs
+ * @param validity the time for which the validity of the CRL issuer's
+ * certification path should be determined
+ * @return true if ok, false if not
+ */
+ static boolean verifyCRL(X509CertImpl certImpl, DistributionPoint point,
+ X509CRL crl, boolean[] reasonsMask, boolean signFlag,
+ PublicKey prevKey, X509Certificate prevCert, String provider,
+ Set<TrustAnchor> trustAnchors, List<CertStore> certStores,
+ Date validity) throws CRLException, IOException {
+
+ boolean indirectCRL = false;
+ X509CRLImpl crlImpl = X509CRLImpl.toImpl(crl);
+ IssuingDistributionPointExtension idpExt =
+ crlImpl.getIssuingDistributionPointExtension();
+ X500Name certIssuer = (X500Name) certImpl.getIssuerDN();
+ X500Name crlIssuer = (X500Name) crlImpl.getIssuerDN();
+
+ // if crlIssuer is set, verify that it matches the issuer of the
+ // CRL and the CRL contains an IDP extension with the indirectCRL
+ // boolean asserted. Otherwise, verify that the CRL issuer matches the
+ // certificate issuer.
+ GeneralNames pointCrlIssuers = point.getCRLIssuer();
+ X500Name pointCrlIssuer = null;
+ if (pointCrlIssuers != null) {
+ if (idpExt == null ||
+ ((Boolean) idpExt.get
+ (IssuingDistributionPointExtension.INDIRECT_CRL)).equals
+ (Boolean.FALSE)) {
+ return false;
+ }
+ boolean match = false;
+ for (Iterator<GeneralName> t = pointCrlIssuers.iterator();
+ !match && t.hasNext(); ) {
+ GeneralNameInterface name = t.next().getName();
+ if (crlIssuer.equals(name) == true) {
+ pointCrlIssuer = (X500Name) name;
+ match = true;
+ }
+ }
+ if (match == false) {
+ return false;
+ }
+
+ // we accept the case that a CRL issuer provide status
+ // information for itself.
+ if (issues(certImpl, crlImpl, provider)) {
+ // reset the public key used to verify the CRL's signature
+ prevKey = certImpl.getPublicKey();
+ } else {
+ indirectCRL = true;
+ }
+ } else if (crlIssuer.equals(certIssuer) == false) {
+ if (debug != null) {
+ debug.println("crl issuer does not equal cert issuer");
+ }
+ return false;
+ } else {
+ // in case of self-issued indirect CRL issuer.
+ KeyIdentifier certAKID = certImpl.getAuthKeyId();
+ KeyIdentifier crlAKID = crlImpl.getAuthKeyId();
+
+ if (certAKID == null || crlAKID == null) {
+ // cannot recognize indirect CRL without AKID
+
+ // we accept the case that a CRL issuer provide status
+ // information for itself.
+ if (issues(certImpl, crlImpl, provider)) {
+ // reset the public key used to verify the CRL's signature
+ prevKey = certImpl.getPublicKey();
+ }
+ } else if (!certAKID.equals(crlAKID)) {
+ // we accept the case that a CRL issuer provide status
+ // information for itself.
+ if (issues(certImpl, crlImpl, provider)) {
+ // reset the public key used to verify the CRL's signature
+ prevKey = certImpl.getPublicKey();
+ } else {
+ indirectCRL = true;
+ }
+ }
+ }
+
+ if (!indirectCRL && !signFlag) {
+ // cert's key cannot be used to verify the CRL
+ return false;
+ }
+
+ if (idpExt != null) {
+ DistributionPointName idpPoint = (DistributionPointName)
+ idpExt.get(IssuingDistributionPointExtension.POINT);
+ if (idpPoint != null) {
+ GeneralNames idpNames = idpPoint.getFullName();
+ if (idpNames == null) {
+ RDN relativeName = idpPoint.getRelativeName();
+ if (relativeName == null) {
+ if (debug != null) {
+ debug.println("IDP must be relative or full DN");
+ }
+ return false;
+ }
+ if (debug != null) {
+ debug.println("IDP relativeName:" + relativeName);
+ }
+ idpNames = getFullNames(crlIssuer, relativeName);
+ }
+ // if the DP name is present in the IDP CRL extension and the
+ // DP field is present in the DP, then verify that one of the
+ // names in the IDP matches one of the names in the DP
+ if (point.getFullName() != null ||
+ point.getRelativeName() != null) {
+ GeneralNames pointNames = point.getFullName();
+ if (pointNames == null) {
+ RDN relativeName = point.getRelativeName();
+ if (relativeName == null) {
+ if (debug != null) {
+ debug.println("DP must be relative or full DN");
+ }
+ return false;
+ }
+ if (debug != null) {
+ debug.println("DP relativeName:" + relativeName);
+ }
+ if (indirectCRL) {
+ if (pointCrlIssuers.size() != 1) {
+ // RFC 3280: there must be only 1 CRL issuer
+ // name when relativeName is present
+ if (debug != null) {
+ debug.println("must only be one CRL " +
+ "issuer when relative name present");
+ }
+ return false;
+ }
+ pointNames = getFullNames
+ (pointCrlIssuer, relativeName);
+ } else {
+ pointNames = getFullNames(certIssuer, relativeName);
+ }
+ }
+ boolean match = false;
+ for (Iterator<GeneralName> i = idpNames.iterator();
+ !match && i.hasNext(); ) {
+ GeneralNameInterface idpName = i.next().getName();
+ if (debug != null) {
+ debug.println("idpName: " + idpName);
+ }
+ for (Iterator<GeneralName> p = pointNames.iterator();
+ !match && p.hasNext(); ) {
+ GeneralNameInterface pointName = p.next().getName();
+ if (debug != null) {
+ debug.println("pointName: " + pointName);
+ }
+ match = idpName.equals(pointName);
+ }
+ }
+ if (!match) {
+ if (debug != null) {
+ debug.println("IDP name does not match DP name");
+ }
+ return false;
+ }
+ // if the DP name is present in the IDP CRL extension and the
+ // DP field is absent from the DP, then verify that one of the
+ // names in the IDP matches one of the names in the crlIssuer
+ // field of the DP
+ } else {
+ // verify that one of the names in the IDP matches one of
+ // the names in the cRLIssuer of the cert's DP
+ boolean match = false;
+ for (Iterator<GeneralName> t = pointCrlIssuers.iterator();
+ !match && t.hasNext(); ) {
+ GeneralNameInterface crlIssuerName = t.next().getName();
+ for (Iterator<GeneralName> i = idpNames.iterator();
+ !match && i.hasNext(); ) {
+ GeneralNameInterface idpName = i.next().getName();
+ match = crlIssuerName.equals(idpName);
+ }
+ }
+ if (!match) {
+ return false;
+ }
+ }
+ }
+
+ // if the onlyContainsUserCerts boolean is asserted, verify that the
+ // cert is not a CA cert
+ Boolean b = (Boolean)
+ idpExt.get(IssuingDistributionPointExtension.ONLY_USER_CERTS);
+ if (b.equals(Boolean.TRUE) && certImpl.getBasicConstraints() != -1) {
+ if (debug != null) {
+ debug.println("cert must be a EE cert");
+ }
+ return false;
+ }
+
+ // if the onlyContainsCACerts boolean is asserted, verify that the
+ // cert is a CA cert
+ b = (Boolean)
+ idpExt.get(IssuingDistributionPointExtension.ONLY_CA_CERTS);
+ if (b.equals(Boolean.TRUE) && certImpl.getBasicConstraints() == -1) {
+ if (debug != null) {
+ debug.println("cert must be a CA cert");
+ }
+ return false;
+ }
+
+ // verify that the onlyContainsAttributeCerts boolean is not
+ // asserted
+ b = (Boolean) idpExt.get
+ (IssuingDistributionPointExtension.ONLY_ATTRIBUTE_CERTS);
+ if (b.equals(Boolean.TRUE)) {
+ if (debug != null) {
+ debug.println("cert must not be an AA cert");
+ }
+ return false;
+ }
+ }
+
+ // compute interim reasons mask
+ boolean[] interimReasonsMask = new boolean[9];
+ ReasonFlags reasons = null;
+ if (idpExt != null) {
+ reasons = (ReasonFlags)
+ idpExt.get(IssuingDistributionPointExtension.REASONS);
+ }
+
+ boolean[] pointReasonFlags = point.getReasonFlags();
+ if (reasons != null) {
+ if (pointReasonFlags != null) {
+ // set interim reasons mask to the intersection of
+ // reasons in the DP and onlySomeReasons in the IDP
+ boolean[] idpReasonFlags = reasons.getFlags();
+ for (int i = 0; i < idpReasonFlags.length; i++) {
+ if (idpReasonFlags[i] && pointReasonFlags[i]) {
+ interimReasonsMask[i] = true;
+ }
+ }
+ } else {
+ // set interim reasons mask to the value of
+ // onlySomeReasons in the IDP (and clone it since we may
+ // modify it)
+ interimReasonsMask = reasons.getFlags().clone();
+ }
+ } else if (idpExt == null || reasons == null) {
+ if (pointReasonFlags != null) {
+ // set interim reasons mask to the value of DP reasons
+ interimReasonsMask = pointReasonFlags.clone();
+ } else {
+ // set interim reasons mask to the special value all-reasons
+ interimReasonsMask = new boolean[9];
+ Arrays.fill(interimReasonsMask, true);
+ }
+ }
+
+ // verify that interim reasons mask includes one or more reasons
+ // not included in the reasons mask
+ boolean oneOrMore = false;
+ for (int i = 0; i < interimReasonsMask.length && !oneOrMore; i++) {
+ if (!reasonsMask[i] && interimReasonsMask[i]) {
+ oneOrMore = true;
+ }
+ }
+ if (!oneOrMore) {
+ return false;
+ }
+
+ // Obtain and validate the certification path for the complete
+ // CRL issuer (if indirect CRL). If a key usage extension is present
+ // in the CRL issuer's certificate, verify that the cRLSign bit is set.
+ if (indirectCRL) {
+ X509CertSelector certSel = new X509CertSelector();
+ certSel.setSubject(crlIssuer.asX500Principal());
+ boolean[] crlSign = {false,false,false,false,false,false,true};
+ certSel.setKeyUsage(crlSign);
+
+ // Currently by default, forward builder does not enable
+ // subject/authority key identifier identifying for target
+ // certificate, instead, it only compares the CRL issuer and
+ // the target certificate subject. If the certificate of the
+ // delegated CRL issuer is a self-issued certificate, the
+ // builder is unable to find the proper CRL issuer by issuer
+ // name only, there is a potential dead loop on finding the
+ // proper issuer. It is of great help to narrow the target
+ // scope down to aware of authority key identifiers in the
+ // selector, for the purposes of breaking the dead loop.
+ AuthorityKeyIdentifierExtension akidext =
+ crlImpl.getAuthKeyIdExtension();
+ if (akidext != null) {
+ KeyIdentifier akid = (KeyIdentifier)akidext.get(
+ AuthorityKeyIdentifierExtension.KEY_ID);
+ if (akid != null) {
+ DerOutputStream derout = new DerOutputStream();
+ derout.putOctetString(akid.getIdentifier());
+ certSel.setSubjectKeyIdentifier(derout.toByteArray());
+ }
+
+ SerialNumber asn = (SerialNumber)akidext.get(
+ AuthorityKeyIdentifierExtension.SERIAL_NUMBER);
+ if (asn != null) {
+ certSel.setSerialNumber(asn.getNumber());
+ }
+ // the subject criterion will be set by builder automatically.
+ }
+
+ // By now, we have validated the previous certificate, so we can
+ // trust it during the validation of the CRL issuer.
+ // In addition to the performance improvement, another benefit is to
+ // break the dead loop while looking for the issuer back and forth
+ // between the delegated self-issued certificate and its issuer.
+ Set<TrustAnchor> newTrustAnchors = new HashSet<>(trustAnchors);
+
+ if (prevKey != null) {
+ // Add the previous certificate as a trust anchor.
+ // If prevCert is not null, we want to construct a TrustAnchor
+ // using the cert object because when the certpath for the CRL
+ // is built later, the CertSelector will make comparisons with
+ // the TrustAnchor's trustedCert member rather than its pubKey.
+ TrustAnchor temporary;
+ if (prevCert != null) {
+ temporary = new TrustAnchor(prevCert, null);
+ } else {
+ X500Principal principal = certImpl.getIssuerX500Principal();
+ temporary = new TrustAnchor(principal, prevKey, null);
+ }
+ newTrustAnchors.add(temporary);
+ }
+
+ PKIXBuilderParameters params = null;
+ try {
+ params = new PKIXBuilderParameters(newTrustAnchors, certSel);
+ } catch (InvalidAlgorithmParameterException iape) {
+ throw new CRLException(iape);
+ }
+ params.setCertStores(certStores);
+ params.setSigProvider(provider);
+ params.setDate(validity);
+ try {
+ CertPathBuilder builder = CertPathBuilder.getInstance("PKIX");
+ PKIXCertPathBuilderResult result =
+ (PKIXCertPathBuilderResult) builder.build(params);
+ prevKey = result.getPublicKey();
+ } catch (GeneralSecurityException e) {
+ throw new CRLException(e);
+ }
+ }
+
+ // check the crl signature algorithm
+ try {
+ AlgorithmChecker.check(prevKey, crl);
+ } catch (CertPathValidatorException cpve) {
+ if (debug != null) {
+ debug.println("CRL signature algorithm check failed: " + cpve);
+ }
+ return false;
+ }
+
+ // validate the signature on the CRL
+ try {
+ crl.verify(prevKey, provider);
+ } catch (GeneralSecurityException e) {
+ if (debug != null) {
+ debug.println("CRL signature failed to verify");
+ }
+ return false;
+ }
+
+ // reject CRL if any unresolved critical extensions remain in the CRL.
+ Set<String> unresCritExts = crl.getCriticalExtensionOIDs();
+ // remove any that we have processed
+ if (unresCritExts != null) {
+ unresCritExts.remove(IssuingDistributionPoint_Id.toString());
+ if (!unresCritExts.isEmpty()) {
+ if (debug != null) {
+ debug.println("Unrecognized critical extension(s) in CRL: "
+ + unresCritExts);
+ for (String ext : unresCritExts) {
+ debug.println(ext);
+ }
+ }
+ return false;
+ }
+ }
+
+ // update reasonsMask
+ for (int i = 0; i < interimReasonsMask.length; i++) {
+ if (!reasonsMask[i] && interimReasonsMask[i]) {
+ reasonsMask[i] = true;
+ }
+ }
+ return true;
+ }
+
+ /**
+ * Append relative name to the issuer name and return a new
+ * GeneralNames object.
+ */
+ private static GeneralNames getFullNames(X500Name issuer, RDN rdn)
+ throws IOException
+ {
+ List<RDN> rdns = new ArrayList<>(issuer.rdns());
+ rdns.add(rdn);
+ X500Name fullName = new X500Name(rdns.toArray(new RDN[0]));
+ GeneralNames fullNames = new GeneralNames();
+ fullNames.add(new GeneralName(fullName));
+ return fullNames;
+ }
+
+ /**
+ * Verifies whether a CRL is issued by a certain certificate
+ *
+ * @param cert the certificate
+ * @param crl the CRL to be verified
+ * @param provider the name of the signature provider
+ */
+ private static boolean issues(X509CertImpl cert, X509CRLImpl crl,
+ String provider) throws IOException
+ {
+ boolean matched = false;
+
+ AdaptableX509CertSelector issuerSelector =
+ new AdaptableX509CertSelector();
+
+ // check certificate's key usage
+ boolean[] usages = cert.getKeyUsage();
+ if (usages != null) {
+ usages[6] = true; // cRLSign
+ issuerSelector.setKeyUsage(usages);
+ }
+
+ // check certificate's subject
+ X500Principal crlIssuer = crl.getIssuerX500Principal();
+ issuerSelector.setSubject(crlIssuer);
+
+ /*
+ * Facilitate certification path construction with authority
+ * key identifier and subject key identifier.
+ *
+ * In practice, conforming CAs MUST use the key identifier method,
+ * and MUST include authority key identifier extension in all CRLs
+ * issued. [section 5.2.1, RFC 2459]
+ */
+ AuthorityKeyIdentifierExtension crlAKID = crl.getAuthKeyIdExtension();
+ if (crlAKID != null) {
+ issuerSelector.parseAuthorityKeyIdentifierExtension(crlAKID);
+ }
+
+ matched = issuerSelector.match(cert);
+
+ // if AKID is unreliable, verify the CRL signature with the cert
+ if (matched && (crlAKID == null ||
+ cert.getAuthorityKeyIdentifierExtension() == null)) {
+ try {
+ crl.verify(cert.getPublicKey(), provider);
+ matched = true;
+ } catch (GeneralSecurityException e) {
+ matched = false;
+ }
+ }
+
+ return matched;
+ }
+}
diff --git a/ojluni/src/main/java/sun/security/provider/certpath/ForwardBuilder.java b/ojluni/src/main/java/sun/security/provider/certpath/ForwardBuilder.java
new file mode 100644
index 0000000..9523e9c
--- /dev/null
+++ b/ojluni/src/main/java/sun/security/provider/certpath/ForwardBuilder.java
@@ -0,0 +1,874 @@
+/*
+ * Copyright (c) 2000, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * 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.io.IOException;
+import java.security.GeneralSecurityException;
+import java.security.InvalidKeyException;
+import java.security.PublicKey;
+import java.security.cert.CertificateException;
+import java.security.cert.CertPathValidatorException;
+import java.security.cert.PKIXReason;
+import java.security.cert.CertStore;
+import java.security.cert.CertStoreException;
+import java.security.cert.PKIXBuilderParameters;
+import java.security.cert.PKIXCertPathChecker;
+import java.security.cert.TrustAnchor;
+import java.security.cert.X509Certificate;
+import java.security.cert.X509CertSelector;
+import java.util.*;
+import javax.security.auth.x500.X500Principal;
+
+import sun.security.provider.certpath.PKIX.BuilderParams;
+import sun.security.util.Debug;
+import sun.security.x509.AccessDescription;
+import sun.security.x509.AuthorityInfoAccessExtension;
+import static sun.security.x509.PKIXExtensions.*;
+import sun.security.x509.X500Name;
+import sun.security.x509.AuthorityKeyIdentifierExtension;
+
+/**
+ * This class represents a forward builder, which is able to retrieve
+ * matching certificates from CertStores and verify a particular certificate
+ * against a ForwardState.
+ *
+ * @since 1.4
+ * @author Yassir Elley
+ * @author Sean Mullan
+ */
+class ForwardBuilder extends Builder {
+
+ private static final Debug debug = Debug.getInstance("certpath");
+ private final Set<X509Certificate> trustedCerts;
+ private final Set<X500Principal> trustedSubjectDNs;
+ private final Set<TrustAnchor> trustAnchors;
+ private X509CertSelector eeSelector;
+ private AdaptableX509CertSelector caSelector;
+ private X509CertSelector caTargetSelector;
+ TrustAnchor trustAnchor;
+ private Comparator<X509Certificate> comparator;
+ private boolean searchAllCertStores = true;
+
+ /**
+ * Initialize the builder with the input parameters.
+ *
+ * @param params the parameter set used to build a certification path
+ */
+ ForwardBuilder(BuilderParams buildParams, boolean searchAllCertStores) {
+ super(buildParams);
+
+ // populate sets of trusted certificates and subject DNs
+ trustAnchors = buildParams.trustAnchors();
+ trustedCerts = new HashSet<X509Certificate>(trustAnchors.size());
+ trustedSubjectDNs = new HashSet<X500Principal>(trustAnchors.size());
+ for (TrustAnchor anchor : trustAnchors) {
+ X509Certificate trustedCert = anchor.getTrustedCert();
+ if (trustedCert != null) {
+ trustedCerts.add(trustedCert);
+ trustedSubjectDNs.add(trustedCert.getSubjectX500Principal());
+ } else {
+ trustedSubjectDNs.add(anchor.getCA());
+ }
+ }
+ comparator = new PKIXCertComparator(trustedSubjectDNs);
+ this.searchAllCertStores = searchAllCertStores;
+ }
+
+ /**
+ * Retrieves all certs from the specified CertStores that satisfy the
+ * requirements specified in the parameters and the current
+ * PKIX state (name constraints, policy constraints, etc).
+ *
+ * @param currentState the current state.
+ * Must be an instance of <code>ForwardState</code>
+ * @param certStores list of CertStores
+ */
+ @Override
+ Collection<X509Certificate> getMatchingCerts(State currentState,
+ List<CertStore> certStores)
+ throws CertStoreException, CertificateException, IOException
+ {
+ if (debug != null) {
+ debug.println("ForwardBuilder.getMatchingCerts()...");
+ }
+
+ ForwardState currState = (ForwardState) currentState;
+
+ /*
+ * We store certs in a Set because we don't want duplicates.
+ * As each cert is added, it is sorted based on the PKIXCertComparator
+ * algorithm.
+ */
+ Set<X509Certificate> certs = new TreeSet<>(comparator);
+
+ /*
+ * Only look for EE certs if search has just started.
+ */
+ if (currState.isInitial()) {
+ getMatchingEECerts(currState, certStores, certs);
+ }
+ getMatchingCACerts(currState, certStores, certs);
+
+ return certs;
+ }
+
+ /*
+ * Retrieves all end-entity certificates which satisfy constraints
+ * and requirements specified in the parameters and PKIX state.
+ */
+ private void getMatchingEECerts(ForwardState currentState,
+ List<CertStore> certStores,
+ Collection<X509Certificate> eeCerts)
+ throws IOException
+ {
+ if (debug != null) {
+ debug.println("ForwardBuilder.getMatchingEECerts()...");
+ }
+ /*
+ * Compose a certificate matching rule to filter out
+ * certs which don't satisfy constraints
+ *
+ * First, retrieve clone of current target cert constraints,
+ * and then add more selection criteria based on current validation
+ * state. Since selector never changes, cache local copy & reuse.
+ */
+ if (eeSelector == null) {
+ eeSelector = (X509CertSelector) targetCertConstraints.clone();
+
+ /*
+ * Match on certificate validity date
+ */
+ eeSelector.setCertificateValid(buildParams.date());
+
+ /*
+ * Policy processing optimizations
+ */
+ if (buildParams.explicitPolicyRequired()) {
+ eeSelector.setPolicy(getMatchingPolicies());
+ }
+ /*
+ * Require EE certs
+ */
+ eeSelector.setBasicConstraints(-2);
+ }
+
+ /* Retrieve matching EE certs from CertStores */
+ addMatchingCerts(eeSelector, certStores, eeCerts, searchAllCertStores);
+ }
+
+ /**
+ * Retrieves all CA certificates which satisfy constraints
+ * and requirements specified in the parameters and PKIX state.
+ */
+ private void getMatchingCACerts(ForwardState currentState,
+ List<CertStore> certStores,
+ Collection<X509Certificate> caCerts)
+ throws IOException
+ {
+ if (debug != null) {
+ debug.println("ForwardBuilder.getMatchingCACerts()...");
+ }
+ int initialSize = caCerts.size();
+
+ /*
+ * Compose a CertSelector to filter out
+ * certs which do not satisfy requirements.
+ */
+ X509CertSelector sel = null;
+
+ if (currentState.isInitial()) {
+ if (targetCertConstraints.getBasicConstraints() == -2) {
+ // no need to continue: this means we never can match a CA cert
+ return;
+ }
+
+ /* This means a CA is the target, so match on same stuff as
+ * getMatchingEECerts
+ */
+ if (debug != null) {
+ debug.println("ForwardBuilder.getMatchingCACerts(): ca is target");
+ }
+
+ if (caTargetSelector == null) {
+ caTargetSelector =
+ (X509CertSelector) targetCertConstraints.clone();
+
+ /*
+ * Since we don't check the validity period of trusted
+ * certificates, please don't set the certificate valid
+ * criterion unless the trusted certificate matching is
+ * completed.
+ */
+
+ /*
+ * Policy processing optimizations
+ */
+ if (buildParams.explicitPolicyRequired())
+ caTargetSelector.setPolicy(getMatchingPolicies());
+ }
+
+ sel = caTargetSelector;
+ } else {
+
+ if (caSelector == null) {
+ caSelector = new AdaptableX509CertSelector();
+
+ /*
+ * Since we don't check the validity period of trusted
+ * certificates, please don't set the certificate valid
+ * criterion unless the trusted certificate matching is
+ * completed.
+ */
+
+ /*
+ * Policy processing optimizations
+ */
+ if (buildParams.explicitPolicyRequired())
+ caSelector.setPolicy(getMatchingPolicies());
+ }
+
+ /*
+ * Match on subject (issuer of previous cert)
+ */
+ caSelector.setSubject(currentState.issuerDN);
+
+ /*
+ * Match on subjectNamesTraversed (both DNs and AltNames)
+ * (checks that current cert's name constraints permit it
+ * to certify all the DNs and AltNames that have been traversed)
+ */
+ CertPathHelper.setPathToNames
+ (caSelector, currentState.subjectNamesTraversed);
+
+ /*
+ * Facilitate certification path construction with authority
+ * key identifier and subject key identifier.
+ */
+ AuthorityKeyIdentifierExtension akidext =
+ currentState.cert.getAuthorityKeyIdentifierExtension();
+ caSelector.parseAuthorityKeyIdentifierExtension(akidext);
+
+ /*
+ * check the validity period
+ */
+ caSelector.setValidityPeriod(currentState.cert.getNotBefore(),
+ currentState.cert.getNotAfter());
+
+ sel = caSelector;
+ }
+
+ /*
+ * For compatibility, conservatively, we don't check the path
+ * length constraint of trusted anchors. Please don't set the
+ * basic constraints criterion unless the trusted certificate
+ * matching is completed.
+ */
+ sel.setBasicConstraints(-1);
+
+ for (X509Certificate trustedCert : trustedCerts) {
+ if (sel.match(trustedCert)) {
+ if (debug != null) {
+ debug.println("ForwardBuilder.getMatchingCACerts: "
+ + "found matching trust anchor");
+ }
+ if (caCerts.add(trustedCert) && !searchAllCertStores) {
+ return;
+ }
+ }
+ }
+
+ /*
+ * The trusted certificate matching is completed. We need to match
+ * on certificate validity date.
+ */
+ sel.setCertificateValid(buildParams.date());
+
+ /*
+ * Require CA certs with a pathLenConstraint that allows
+ * at least as many CA certs that have already been traversed
+ */
+ sel.setBasicConstraints(currentState.traversedCACerts);
+
+ /*
+ * If we have already traversed as many CA certs as the maxPathLength
+ * will allow us to, then we don't bother looking through these
+ * certificate pairs. If maxPathLength has a value of -1, this
+ * means it is unconstrained, so we always look through the
+ * certificate pairs.
+ */
+ if (currentState.isInitial() ||
+ (buildParams.maxPathLength() == -1) ||
+ (buildParams.maxPathLength() > currentState.traversedCACerts))
+ {
+ if (addMatchingCerts(sel, certStores,
+ caCerts, searchAllCertStores)
+ && !searchAllCertStores) {
+ return;
+ }
+ }
+
+ if (!currentState.isInitial() && Builder.USE_AIA) {
+ // check for AuthorityInformationAccess extension
+ AuthorityInfoAccessExtension aiaExt =
+ currentState.cert.getAuthorityInfoAccessExtension();
+ if (aiaExt != null) {
+ getCerts(aiaExt, caCerts);
+ }
+ }
+
+ if (debug != null) {
+ int numCerts = caCerts.size() - initialSize;
+ debug.println("ForwardBuilder.getMatchingCACerts: found " +
+ numCerts + " CA certs");
+ }
+ }
+
+ /**
+ * Download Certificates from the given AIA and add them to the
+ * specified Collection.
+ */
+ // cs.getCertificates(caSelector) returns a collection of X509Certificate's
+ // because of the selector, so the cast is safe
+ @SuppressWarnings("unchecked")
+ private boolean getCerts(AuthorityInfoAccessExtension aiaExt,
+ Collection<X509Certificate> certs)
+ {
+ if (Builder.USE_AIA == false) {
+ return false;
+ }
+ List<AccessDescription> adList = aiaExt.getAccessDescriptions();
+ if (adList == null || adList.isEmpty()) {
+ return false;
+ }
+
+ boolean add = false;
+ for (AccessDescription ad : adList) {
+ CertStore cs = URICertStore.getInstance(ad);
+ if (cs != null) {
+ try {
+ if (certs.addAll((Collection<X509Certificate>)
+ cs.getCertificates(caSelector))) {
+ add = true;
+ if (!searchAllCertStores) {
+ return true;
+ }
+ }
+ } catch (CertStoreException cse) {
+ if (debug != null) {
+ debug.println("exception getting certs from CertStore:");
+ cse.printStackTrace();
+ }
+ }
+ }
+ }
+ return add;
+ }
+
+ /**
+ * This inner class compares 2 PKIX certificates according to which
+ * should be tried first when building a path from the target.
+ * The preference order is as follows:
+ *
+ * Given trusted certificate(s):
+ * Subject:ou=D,ou=C,o=B,c=A
+ *
+ * Preference order for current cert:
+ *
+ * 1) Issuer matches a trusted subject
+ * Issuer: ou=D,ou=C,o=B,c=A
+ *
+ * 2) Issuer is a descendant of a trusted subject (in order of
+ * number of links to the trusted subject)
+ * a) Issuer: ou=E,ou=D,ou=C,o=B,c=A [links=1]
+ * b) Issuer: ou=F,ou=E,ou=D,ou=C,ou=B,c=A [links=2]
+ *
+ * 3) Issuer is an ancestor of a trusted subject (in order of number of
+ * links to the trusted subject)
+ * a) Issuer: ou=C,o=B,c=A [links=1]
+ * b) Issuer: o=B,c=A [links=2]
+ *
+ * 4) Issuer is in the same namespace as a trusted subject (in order of
+ * number of links to the trusted subject)
+ * a) Issuer: ou=G,ou=C,o=B,c=A [links=2]
+ * b) Issuer: ou=H,o=B,c=A [links=3]
+ *
+ * 5) Issuer is an ancestor of certificate subject (in order of number
+ * of links to the certificate subject)
+ * a) Issuer: ou=K,o=J,c=A
+ * Subject: ou=L,ou=K,o=J,c=A
+ * b) Issuer: o=J,c=A
+ * Subject: ou=L,ou=K,0=J,c=A
+ *
+ * 6) Any other certificates
+ */
+ static class PKIXCertComparator implements Comparator<X509Certificate> {
+
+ final static String METHOD_NME = "PKIXCertComparator.compare()";
+
+ private final Set<X500Principal> trustedSubjectDNs;
+
+ PKIXCertComparator(Set<X500Principal> trustedSubjectDNs) {
+ this.trustedSubjectDNs = trustedSubjectDNs;
+ }
+
+ /**
+ * @param oCert1 First X509Certificate to be compared
+ * @param oCert2 Second X509Certificate to be compared
+ * @return -1 if oCert1 is preferable to oCert2, or
+ * if oCert1 and oCert2 are equally preferable (in this
+ * case it doesn't matter which is preferable, but we don't
+ * return 0 because the comparator would behave strangely
+ * when used in a SortedSet).
+ * 1 if oCert2 is preferable to oCert1
+ * 0 if oCert1.equals(oCert2). We only return 0 if the
+ * certs are equal so that this comparator behaves
+ * correctly when used in a SortedSet.
+ * @throws ClassCastException if either argument is not of type
+ * X509Certificate
+ */
+ @Override
+ public int compare(X509Certificate oCert1, X509Certificate oCert2) {
+
+ // if certs are the same, return 0
+ if (oCert1.equals(oCert2)) return 0;
+
+ X500Principal cIssuer1 = oCert1.getIssuerX500Principal();
+ X500Principal cIssuer2 = oCert2.getIssuerX500Principal();
+ X500Name cIssuer1Name = X500Name.asX500Name(cIssuer1);
+ X500Name cIssuer2Name = X500Name.asX500Name(cIssuer2);
+
+ if (debug != null) {
+ debug.println(METHOD_NME + " o1 Issuer: " + cIssuer1);
+ debug.println(METHOD_NME + " o2 Issuer: " + cIssuer2);
+ }
+
+ /* If one cert's issuer matches a trusted subject, then it is
+ * preferable.
+ */
+ if (debug != null) {
+ debug.println(METHOD_NME + " MATCH TRUSTED SUBJECT TEST...");
+ }
+
+ boolean m1 = trustedSubjectDNs.contains(cIssuer1);
+ boolean m2 = trustedSubjectDNs.contains(cIssuer2);
+ if (debug != null) {
+ debug.println(METHOD_NME + " m1: " + m1);
+ debug.println(METHOD_NME + " m2: " + m2);
+ }
+ if (m1 && m2) {
+ return -1;
+ } else if (m1) {
+ return -1;
+ } else if (m2) {
+ return 1;
+ }
+
+ /* If one cert's issuer is a naming descendant of a trusted subject,
+ * then it is preferable, in order of increasing naming distance.
+ */
+ if (debug != null) {
+ debug.println(METHOD_NME + " NAMING DESCENDANT TEST...");
+ }
+ for (X500Principal tSubject : trustedSubjectDNs) {
+ X500Name tSubjectName = X500Name.asX500Name(tSubject);
+ int distanceTto1 =
+ Builder.distance(tSubjectName, cIssuer1Name, -1);
+ int distanceTto2 =
+ Builder.distance(tSubjectName, cIssuer2Name, -1);
+ if (debug != null) {
+ debug.println(METHOD_NME +" distanceTto1: " + distanceTto1);
+ debug.println(METHOD_NME +" distanceTto2: " + distanceTto2);
+ }
+ if (distanceTto1 > 0 || distanceTto2 > 0) {
+ if (distanceTto1 == distanceTto2) {
+ return -1;
+ } else if (distanceTto1 > 0 && distanceTto2 <= 0) {
+ return -1;
+ } else if (distanceTto1 <= 0 && distanceTto2 > 0) {
+ return 1;
+ } else if (distanceTto1 < distanceTto2) {
+ return -1;
+ } else { // distanceTto1 > distanceTto2
+ return 1;
+ }
+ }
+ }
+
+ /* If one cert's issuer is a naming ancestor of a trusted subject,
+ * then it is preferable, in order of increasing naming distance.
+ */
+ if (debug != null) {
+ debug.println(METHOD_NME + " NAMING ANCESTOR TEST...");
+ }
+ for (X500Principal tSubject : trustedSubjectDNs) {
+ X500Name tSubjectName = X500Name.asX500Name(tSubject);
+
+ int distanceTto1 = Builder.distance
+ (tSubjectName, cIssuer1Name, Integer.MAX_VALUE);
+ int distanceTto2 = Builder.distance
+ (tSubjectName, cIssuer2Name, Integer.MAX_VALUE);
+ if (debug != null) {
+ debug.println(METHOD_NME +" distanceTto1: " + distanceTto1);
+ debug.println(METHOD_NME +" distanceTto2: " + distanceTto2);
+ }
+ if (distanceTto1 < 0 || distanceTto2 < 0) {
+ if (distanceTto1 == distanceTto2) {
+ return -1;
+ } else if (distanceTto1 < 0 && distanceTto2 >= 0) {
+ return -1;
+ } else if (distanceTto1 >= 0 && distanceTto2 < 0) {
+ return 1;
+ } else if (distanceTto1 > distanceTto2) {
+ return -1;
+ } else {
+ return 1;
+ }
+ }
+ }
+
+ /* If one cert's issuer is in the same namespace as a trusted
+ * subject, then it is preferable, in order of increasing naming
+ * distance.
+ */
+ if (debug != null) {
+ debug.println(METHOD_NME +" SAME NAMESPACE AS TRUSTED TEST...");
+ }
+ for (X500Principal tSubject : trustedSubjectDNs) {
+ X500Name tSubjectName = X500Name.asX500Name(tSubject);
+ X500Name tAo1 = tSubjectName.commonAncestor(cIssuer1Name);
+ X500Name tAo2 = tSubjectName.commonAncestor(cIssuer2Name);
+ if (debug != null) {
+ debug.println(METHOD_NME +" tAo1: " + String.valueOf(tAo1));
+ debug.println(METHOD_NME +" tAo2: " + String.valueOf(tAo2));
+ }
+ if (tAo1 != null || tAo2 != null) {
+ if (tAo1 != null && tAo2 != null) {
+ int hopsTto1 = Builder.hops
+ (tSubjectName, cIssuer1Name, Integer.MAX_VALUE);
+ int hopsTto2 = Builder.hops
+ (tSubjectName, cIssuer2Name, Integer.MAX_VALUE);
+ if (debug != null) {
+ debug.println(METHOD_NME +" hopsTto1: " + hopsTto1);
+ debug.println(METHOD_NME +" hopsTto2: " + hopsTto2);
+ }
+ if (hopsTto1 == hopsTto2) {
+ } else if (hopsTto1 > hopsTto2) {
+ return 1;
+ } else { // hopsTto1 < hopsTto2
+ return -1;
+ }
+ } else if (tAo1 == null) {
+ return 1;
+ } else {
+ return -1;
+ }
+ }
+ }
+
+
+ /* If one cert's issuer is an ancestor of that cert's subject,
+ * then it is preferable, in order of increasing naming distance.
+ */
+ if (debug != null) {
+ debug.println(METHOD_NME+" CERT ISSUER/SUBJECT COMPARISON TEST...");
+ }
+ X500Principal cSubject1 = oCert1.getSubjectX500Principal();
+ X500Principal cSubject2 = oCert2.getSubjectX500Principal();
+ X500Name cSubject1Name = X500Name.asX500Name(cSubject1);
+ X500Name cSubject2Name = X500Name.asX500Name(cSubject2);
+
+ if (debug != null) {
+ debug.println(METHOD_NME + " o1 Subject: " + cSubject1);
+ debug.println(METHOD_NME + " o2 Subject: " + cSubject2);
+ }
+ int distanceStoI1 = Builder.distance
+ (cSubject1Name, cIssuer1Name, Integer.MAX_VALUE);
+ int distanceStoI2 = Builder.distance
+ (cSubject2Name, cIssuer2Name, Integer.MAX_VALUE);
+ if (debug != null) {
+ debug.println(METHOD_NME + " distanceStoI1: " + distanceStoI1);
+ debug.println(METHOD_NME + " distanceStoI2: " + distanceStoI2);
+ }
+ if (distanceStoI2 > distanceStoI1) {
+ return -1;
+ } else if (distanceStoI2 < distanceStoI1) {
+ return 1;
+ }
+
+ /* Otherwise, certs are equally preferable.
+ */
+ if (debug != null) {
+ debug.println(METHOD_NME + " no tests matched; RETURN 0");
+ }
+ return -1;
+ }
+ }
+
+ /**
+ * Verifies a matching certificate.
+ *
+ * This method executes the validation steps in the PKIX path
+ * validation algorithm <draft-ietf-pkix-new-part1-08.txt> which were
+ * not satisfied by the selection criteria used by getCertificates()
+ * to find the certs and only the steps that can be executed in a
+ * forward direction (target to trust anchor). Those steps that can
+ * only be executed in a reverse direction are deferred until the
+ * complete path has been built.
+ *
+ * Trust anchor certs are not validated, but are used to verify the
+ * signature and revocation status of the previous cert.
+ *
+ * If the last certificate is being verified (the one whose subject
+ * matches the target subject, then steps in 6.1.4 of the PKIX
+ * Certification Path Validation algorithm are NOT executed,
+ * regardless of whether or not the last cert is an end-entity
+ * cert or not. This allows callers to certify CA certs as
+ * well as EE certs.
+ *
+ * @param cert the certificate to be verified
+ * @param currentState the current state against which the cert is verified
+ * @param certPathList the certPathList generated thus far
+ */
+ @Override
+ void verifyCert(X509Certificate cert, State currentState,
+ List<X509Certificate> certPathList)
+ throws GeneralSecurityException
+ {
+ if (debug != null) {
+ debug.println("ForwardBuilder.verifyCert(SN: "
+ + Debug.toHexString(cert.getSerialNumber())
+ + "\n Issuer: " + cert.getIssuerX500Principal() + ")"
+ + "\n Subject: " + cert.getSubjectX500Principal() + ")");
+ }
+
+ ForwardState currState = (ForwardState)currentState;
+
+ // Don't bother to verify untrusted certificate more.
+ currState.untrustedChecker.check(cert, Collections.<String>emptySet());
+
+ /*
+ * check for looping - abort a loop if we encounter the same
+ * certificate twice
+ */
+ if (certPathList != null) {
+ for (X509Certificate cpListCert : certPathList) {
+ if (cert.equals(cpListCert)) {
+ if (debug != null) {
+ debug.println("loop detected!!");
+ }
+ throw new CertPathValidatorException("loop detected");
+ }
+ }
+ }
+
+ /* check if trusted cert */
+ boolean isTrustedCert = trustedCerts.contains(cert);
+
+ /* we don't perform any validation of the trusted cert */
+ if (!isTrustedCert) {
+ /*
+ * Check CRITICAL private extensions for user checkers that
+ * support forward checking (forwardCheckers) and remove
+ * ones we know how to check.
+ */
+ Set<String> unresCritExts = cert.getCriticalExtensionOIDs();
+ if (unresCritExts == null) {
+ unresCritExts = Collections.<String>emptySet();
+ }
+ for (PKIXCertPathChecker checker : currState.forwardCheckers) {
+ checker.check(cert, unresCritExts);
+ }
+
+ /*
+ * Remove extensions from user checkers that don't support
+ * forward checking. After this step, we will have removed
+ * all extensions that all user checkers are capable of
+ * processing.
+ */
+ for (PKIXCertPathChecker checker : buildParams.certPathCheckers()) {
+ if (!checker.isForwardCheckingSupported()) {
+ Set<String> supportedExts = checker.getSupportedExtensions();
+ if (supportedExts != null) {
+ unresCritExts.removeAll(supportedExts);
+ }
+ }
+ }
+
+ /*
+ * Look at the remaining extensions and remove any ones we know how
+ * to check. If there are any left, throw an exception!
+ */
+ if (!unresCritExts.isEmpty()) {
+ unresCritExts.remove(BasicConstraints_Id.toString());
+ unresCritExts.remove(NameConstraints_Id.toString());
+ unresCritExts.remove(CertificatePolicies_Id.toString());
+ unresCritExts.remove(PolicyMappings_Id.toString());
+ unresCritExts.remove(PolicyConstraints_Id.toString());
+ unresCritExts.remove(InhibitAnyPolicy_Id.toString());
+ unresCritExts.remove(SubjectAlternativeName_Id.toString());
+ unresCritExts.remove(KeyUsage_Id.toString());
+ unresCritExts.remove(ExtendedKeyUsage_Id.toString());
+
+ if (!unresCritExts.isEmpty())
+ throw new CertPathValidatorException
+ ("Unrecognized critical extension(s)", null, null, -1,
+ PKIXReason.UNRECOGNIZED_CRIT_EXT);
+ }
+ }
+
+ /*
+ * if this is the target certificate (init=true), then we are
+ * not able to do any more verification, so just return
+ */
+ if (currState.isInitial()) {
+ return;
+ }
+
+ /* we don't perform any validation of the trusted cert */
+ if (!isTrustedCert) {
+ /* Make sure this is a CA cert */
+ if (cert.getBasicConstraints() == -1) {
+ throw new CertificateException("cert is NOT a CA cert");
+ }
+
+ /*
+ * Check keyUsage extension
+ */
+ KeyChecker.verifyCAKeyUsage(cert);
+ }
+
+ /*
+ * the following checks are performed even when the cert
+ * is a trusted cert, since we are only extracting the
+ * subjectDN, and publicKey from the cert
+ * in order to verify a previous cert
+ */
+
+ /*
+ * Check signature only if no key requiring key parameters has been
+ * encountered.
+ */
+ if (!currState.keyParamsNeeded()) {
+ (currState.cert).verify(cert.getPublicKey(),
+ buildParams.sigProvider());
+ }
+ }
+
+ /**
+ * Verifies whether the input certificate completes the path.
+ * Checks the cert against each trust anchor that was specified, in order,
+ * and returns true as soon as it finds a valid anchor.
+ * Returns true if the cert matches a trust anchor specified as a
+ * certificate or if the cert verifies with a trust anchor that
+ * was specified as a trusted {pubkey, caname} pair. Returns false if none
+ * of the trust anchors are valid for this cert.
+ *
+ * @param cert the certificate to test
+ * @return a boolean value indicating whether the cert completes the path.
+ */
+ @Override
+ boolean isPathCompleted(X509Certificate cert) {
+ for (TrustAnchor anchor : trustAnchors) {
+ if (anchor.getTrustedCert() != null) {
+ if (cert.equals(anchor.getTrustedCert())) {
+ this.trustAnchor = anchor;
+ return true;
+ } else {
+ continue;
+ }
+ }
+ X500Principal principal = anchor.getCA();
+ PublicKey publicKey = anchor.getCAPublicKey();
+
+ if (principal != null && publicKey != null &&
+ principal.equals(cert.getSubjectX500Principal())) {
+ if (publicKey.equals(cert.getPublicKey())) {
+ // the cert itself is a trust anchor
+ this.trustAnchor = anchor;
+ return true;
+ }
+ // else, it is a self-issued certificate of the anchor
+ }
+
+ // Check subject/issuer name chaining
+ if (principal == null ||
+ !principal.equals(cert.getIssuerX500Principal())) {
+ continue;
+ }
+
+ // skip anchor if it contains a DSA key with no DSA params
+ if (PKIX.isDSAPublicKeyWithoutParams(publicKey)) {
+ continue;
+ }
+
+ /*
+ * Check signature
+ */
+ try {
+ cert.verify(publicKey, buildParams.sigProvider());
+ } catch (InvalidKeyException ike) {
+ if (debug != null) {
+ debug.println("ForwardBuilder.isPathCompleted() invalid "
+ + "DSA key found");
+ }
+ continue;
+ } catch (GeneralSecurityException e){
+ if (debug != null) {
+ debug.println("ForwardBuilder.isPathCompleted() " +
+ "unexpected exception");
+ e.printStackTrace();
+ }
+ continue;
+ }
+
+ this.trustAnchor = anchor;
+ return true;
+ }
+
+ return false;
+ }
+
+ /** Adds the certificate to the certPathList
+ *
+ * @param cert the certificate to be added
+ * @param certPathList the certification path list
+ */
+ @Override
+ void addCertToPath(X509Certificate cert,
+ LinkedList<X509Certificate> certPathList)
+ {
+ certPathList.addFirst(cert);
+ }
+
+ /** Removes final certificate from the certPathList
+ *
+ * @param certPathList the certification path list
+ */
+ @Override
+ void removeFinalCertFromPath(LinkedList<X509Certificate> certPathList) {
+ certPathList.removeFirst();
+ }
+}
diff --git a/ojluni/src/main/java/sun/security/provider/certpath/ForwardState.java b/ojluni/src/main/java/sun/security/provider/certpath/ForwardState.java
new file mode 100644
index 0000000..2dc9e20
--- /dev/null
+++ b/ojluni/src/main/java/sun/security/provider/certpath/ForwardState.java
@@ -0,0 +1,259 @@
+/*
+ * Copyright (c) 2000, 2012, 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.io.IOException;
+import java.security.cert.CertificateException;
+import java.security.cert.CertPathValidatorException;
+import java.security.cert.PKIXCertPathChecker;
+import java.security.cert.X509Certificate;
+import java.util.ArrayList;
+import java.util.HashSet;
+import java.util.List;
+import java.util.ListIterator;
+import javax.security.auth.x500.X500Principal;
+
+import sun.security.util.Debug;
+import sun.security.x509.SubjectAlternativeNameExtension;
+import sun.security.x509.GeneralNames;
+import sun.security.x509.GeneralName;
+import sun.security.x509.GeneralNameInterface;
+import sun.security.x509.X500Name;
+import sun.security.x509.X509CertImpl;
+
+/**
+ * A specification of a forward PKIX validation state
+ * which is initialized by each build and updated each time a
+ * certificate is added to the current path.
+ * @since 1.4
+ * @author Yassir Elley
+ */
+class ForwardState implements State {
+
+ private static final Debug debug = Debug.getInstance("certpath");
+
+ /* The issuer DN of the last cert in the path */
+ X500Principal issuerDN;
+
+ /* The last cert in the path */
+ X509CertImpl cert;
+
+ /* The set of subjectDNs and subjectAltNames of all certs in the path */
+ HashSet<GeneralNameInterface> subjectNamesTraversed;
+
+ /*
+ * The number of intermediate CA certs which have been traversed so
+ * far in the path
+ */
+ int traversedCACerts;
+
+ /* Flag indicating if state is initial (path is just starting) */
+ private boolean init = true;
+
+
+ /* the untrusted certificates checker */
+ UntrustedChecker untrustedChecker;
+
+ /* The list of user-defined checkers that support forward checking */
+ ArrayList<PKIXCertPathChecker> forwardCheckers;
+
+ /* Flag indicating if key needing to inherit key parameters has been
+ * encountered.
+ */
+ boolean keyParamsNeededFlag = false;
+
+ /**
+ * Returns a boolean flag indicating if the state is initial
+ * (just starting)
+ *
+ * @return boolean flag indicating if the state is initial (just starting)
+ */
+ @Override
+ public boolean isInitial() {
+ return init;
+ }
+
+ /**
+ * Return boolean flag indicating whether a public key that needs to inherit
+ * key parameters has been encountered.
+ *
+ * @return boolean true if key needing to inherit parameters has been
+ * encountered; false otherwise.
+ */
+ @Override
+ public boolean keyParamsNeeded() {
+ return keyParamsNeededFlag;
+ }
+
+ /**
+ * Display state for debugging purposes
+ */
+ @Override
+ public String toString() {
+ StringBuilder sb = new StringBuilder();
+ sb.append("State [");
+ sb.append("\n issuerDN of last cert: ").append(issuerDN);
+ sb.append("\n traversedCACerts: ").append(traversedCACerts);
+ sb.append("\n init: ").append(String.valueOf(init));
+ sb.append("\n keyParamsNeeded: ").append
+ (String.valueOf(keyParamsNeededFlag));
+ sb.append("\n subjectNamesTraversed: \n").append
+ (subjectNamesTraversed);
+ sb.append("]\n");
+ return sb.toString();
+ }
+
+ /**
+ * Initialize the state.
+ *
+ * @param certPathCheckers the list of user-defined PKIXCertPathCheckers
+ */
+ public void initState(List<PKIXCertPathChecker> certPathCheckers)
+ throws CertPathValidatorException
+ {
+ subjectNamesTraversed = new HashSet<GeneralNameInterface>();
+ traversedCACerts = 0;
+
+ /*
+ * Populate forwardCheckers with every user-defined checker
+ * that supports forward checking and initialize the forwardCheckers
+ */
+ forwardCheckers = new ArrayList<PKIXCertPathChecker>();
+ for (PKIXCertPathChecker checker : certPathCheckers) {
+ if (checker.isForwardCheckingSupported()) {
+ checker.init(true);
+ forwardCheckers.add(checker);
+ }
+ }
+
+ init = true;
+ }
+
+ /**
+ * Update the state with the next certificate added to the path.
+ *
+ * @param cert the certificate which is used to update the state
+ */
+ @Override
+ public void updateState(X509Certificate cert)
+ throws CertificateException, IOException, CertPathValidatorException {
+
+ if (cert == null)
+ return;
+
+ X509CertImpl icert = X509CertImpl.toImpl(cert);
+
+ /* see if certificate key has null parameters */
+ if (PKIX.isDSAPublicKeyWithoutParams(icert.getPublicKey())) {
+ keyParamsNeededFlag = true;
+ }
+
+ /* update certificate */
+ this.cert = icert;
+
+ /* update issuer DN */
+ issuerDN = cert.getIssuerX500Principal();
+
+ if (!X509CertImpl.isSelfIssued(cert)) {
+
+ /*
+ * update traversedCACerts only if this is a non-self-issued
+ * intermediate CA cert
+ */
+ if (!init && cert.getBasicConstraints() != -1) {
+ traversedCACerts++;
+ }
+ }
+
+ /* update subjectNamesTraversed only if this is the EE cert or if
+ this cert is not self-issued */
+ if (init || !X509CertImpl.isSelfIssued(cert)){
+ X500Principal subjName = cert.getSubjectX500Principal();
+ subjectNamesTraversed.add(X500Name.asX500Name(subjName));
+
+ try {
+ SubjectAlternativeNameExtension subjAltNameExt
+ = icert.getSubjectAlternativeNameExtension();
+ if (subjAltNameExt != null) {
+ GeneralNames gNames = subjAltNameExt.get(
+ SubjectAlternativeNameExtension.SUBJECT_NAME);
+ for (GeneralName gName : gNames.names()) {
+ subjectNamesTraversed.add(gName.getName());
+ }
+ }
+ } catch (IOException e) {
+ if (debug != null) {
+ debug.println("ForwardState.updateState() unexpected "
+ + "exception");
+ e.printStackTrace();
+ }
+ throw new CertPathValidatorException(e);
+ }
+ }
+
+ init = false;
+ }
+
+ /*
+ * Clone current state. The state is cloned as each cert is
+ * added to the path. This is necessary if backtracking occurs,
+ * and a prior state needs to be restored.
+ *
+ * Note that this is a SMART clone. Not all fields are fully copied,
+ * because some of them will
+ * not have their contents modified by subsequent calls to updateState.
+ */
+ @Override
+ @SuppressWarnings("unchecked") // Safe casts assuming clone() works correctly
+ public Object clone() {
+ try {
+ ForwardState clonedState = (ForwardState) super.clone();
+
+ /* clone checkers, if cloneable */
+ clonedState.forwardCheckers = (ArrayList<PKIXCertPathChecker>)
+ forwardCheckers.clone();
+ ListIterator<PKIXCertPathChecker> li =
+ clonedState.forwardCheckers.listIterator();
+ while (li.hasNext()) {
+ PKIXCertPathChecker checker = li.next();
+ if (checker instanceof Cloneable) {
+ li.set((PKIXCertPathChecker)checker.clone());
+ }
+ }
+
+ /*
+ * Shallow copy traversed names. There is no need to
+ * deep copy contents, since the elements of the Set
+ * are never modified by subsequent calls to updateState().
+ */
+ clonedState.subjectNamesTraversed
+ = (HashSet<GeneralNameInterface>)subjectNamesTraversed.clone();
+ return clonedState;
+ } catch (CloneNotSupportedException e) {
+ throw new InternalError(e.toString(), e);
+ }
+ }
+}
diff --git a/ojluni/src/main/java/sun/security/provider/certpath/IndexedCollectionCertStore.java b/ojluni/src/main/java/sun/security/provider/certpath/IndexedCollectionCertStore.java
new file mode 100644
index 0000000..64fcc56
--- /dev/null
+++ b/ojluni/src/main/java/sun/security/provider/certpath/IndexedCollectionCertStore.java
@@ -0,0 +1,424 @@
+/*
+ * Copyright (c) 2002, 2012, 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.*;
+
+import java.security.InvalidAlgorithmParameterException;
+import java.security.cert.*;
+
+import javax.security.auth.x500.X500Principal;
+
+/**
+ * A <code>CertStore</code> that retrieves <code>Certificates</code> and
+ * <code>CRL</code>s from a <code>Collection</code>.
+ * <p>
+ * This implementation is functionally equivalent to CollectionCertStore
+ * with two differences:
+ * <ol>
+ * <li>Upon construction, the elements in the specified Collection are
+ * partially indexed. X509Certificates are indexed by subject, X509CRLs
+ * by issuer, non-X509 Certificates and CRLs are copied without indexing,
+ * other objects are ignored. This increases CertStore construction time
+ * but allows significant speedups for searches which specify the indexed
+ * attributes, in particular for large Collections (reduction from linear
+ * time to effectively constant time). Searches for non-indexed queries
+ * are as fast (or marginally faster) than for the standard
+ * CollectionCertStore. Certificate subjects and CRL issuers
+ * were found to be specified in most searches used internally by the
+ * CertPath provider. Additional attributes could indexed if there are
+ * queries that justify the effort.
+ *
+ * <li>Changes to the specified Collection after construction time are
+ * not detected and ignored. This is because there is no way to efficiently
+ * detect if a Collection has been modified, a full traversal would be
+ * required. That would degrade lookup performance to linear time and
+ * eliminated the benefit of indexing. We may fix this via the introduction
+ * of new public APIs in the future.
+ * </ol>
+ * <p>
+ * Before calling the {@link #engineGetCertificates engineGetCertificates} or
+ * {@link #engineGetCRLs engineGetCRLs} methods, the
+ * {@link #CollectionCertStore(CertStoreParameters)
+ * CollectionCertStore(CertStoreParameters)} constructor is called to
+ * create the <code>CertStore</code> and establish the
+ * <code>Collection</code> from which <code>Certificate</code>s and
+ * <code>CRL</code>s will be retrieved. If the specified
+ * <code>Collection</code> contains an object that is not a
+ * <code>Certificate</code> or <code>CRL</code>, that object will be
+ * ignored.
+ * <p>
+ * <b>Concurrent Access</b>
+ * <p>
+ * As described in the javadoc for <code>CertStoreSpi</code>, the
+ * <code>engineGetCertificates</code> and <code>engineGetCRLs</code> methods
+ * must be thread-safe. That is, multiple threads may concurrently
+ * invoke these methods on a single <code>CollectionCertStore</code>
+ * object (or more than one) with no ill effects.
+ * <p>
+ * This is achieved by requiring that the <code>Collection</code> passed to
+ * the {@link #CollectionCertStore(CertStoreParameters)
+ * CollectionCertStore(CertStoreParameters)} constructor (via the
+ * <code>CollectionCertStoreParameters</code> object) must have fail-fast
+ * iterators. Simultaneous modifications to the <code>Collection</code> can thus be
+ * detected and certificate or CRL retrieval can be retried. The fact that
+ * <code>Certificate</code>s and <code>CRL</code>s must be thread-safe is also
+ * essential.
+ *
+ * @see java.security.cert.CertStore
+ * @see CollectionCertStore
+ *
+ * @author Andreas Sterbenz
+ */
+public class IndexedCollectionCertStore extends CertStoreSpi {
+
+ /**
+ * Map X500Principal(subject) -> X509Certificate | List of X509Certificate
+ */
+ private Map<X500Principal, Object> certSubjects;
+ /**
+ * Map X500Principal(issuer) -> X509CRL | List of X509CRL
+ */
+ private Map<X500Principal, Object> crlIssuers;
+ /**
+ * Sets of non-X509 certificates and CRLs
+ */
+ private Set<Certificate> otherCertificates;
+ private Set<CRL> otherCRLs;
+
+ /**
+ * Creates a <code>CertStore</code> with the specified parameters.
+ * For this class, the parameters object must be an instance of
+ * <code>CollectionCertStoreParameters</code>.
+ *
+ * @param params the algorithm parameters
+ * @exception InvalidAlgorithmParameterException if params is not an
+ * instance of <code>CollectionCertStoreParameters</code>
+ */
+ public IndexedCollectionCertStore(CertStoreParameters params)
+ throws InvalidAlgorithmParameterException {
+ super(params);
+ if (!(params instanceof CollectionCertStoreParameters)) {
+ throw new InvalidAlgorithmParameterException(
+ "parameters must be CollectionCertStoreParameters");
+ }
+ Collection<?> coll = ((CollectionCertStoreParameters)params).getCollection();
+ if (coll == null) {
+ throw new InvalidAlgorithmParameterException
+ ("Collection must not be null");
+ }
+ buildIndex(coll);
+ }
+
+ /**
+ * Index the specified Collection copying all references to Certificates
+ * and CRLs.
+ */
+ private void buildIndex(Collection<?> coll) {
+ certSubjects = new HashMap<X500Principal, Object>();
+ crlIssuers = new HashMap<X500Principal, Object>();
+ otherCertificates = null;
+ otherCRLs = null;
+ for (Object obj : coll) {
+ if (obj instanceof X509Certificate) {
+ indexCertificate((X509Certificate)obj);
+ } else if (obj instanceof X509CRL) {
+ indexCRL((X509CRL)obj);
+ } else if (obj instanceof Certificate) {
+ if (otherCertificates == null) {
+ otherCertificates = new HashSet<Certificate>();
+ }
+ otherCertificates.add((Certificate)obj);
+ } else if (obj instanceof CRL) {
+ if (otherCRLs == null) {
+ otherCRLs = new HashSet<CRL>();
+ }
+ otherCRLs.add((CRL)obj);
+ } else {
+ // ignore
+ }
+ }
+ if (otherCertificates == null) {
+ otherCertificates = Collections.<Certificate>emptySet();
+ }
+ if (otherCRLs == null) {
+ otherCRLs = Collections.<CRL>emptySet();
+ }
+ }
+
+ /**
+ * Add an X509Certificate to the index.
+ */
+ private void indexCertificate(X509Certificate cert) {
+ X500Principal subject = cert.getSubjectX500Principal();
+ Object oldEntry = certSubjects.put(subject, cert);
+ if (oldEntry != null) { // assume this is unlikely
+ if (oldEntry instanceof X509Certificate) {
+ if (cert.equals(oldEntry)) {
+ return;
+ }
+ List<X509Certificate> list = new ArrayList<>(2);
+ list.add(cert);
+ list.add((X509Certificate)oldEntry);
+ certSubjects.put(subject, list);
+ } else {
+ @SuppressWarnings("unchecked") // See certSubjects javadoc.
+ List<X509Certificate> list = (List<X509Certificate>)oldEntry;
+ if (list.contains(cert) == false) {
+ list.add(cert);
+ }
+ certSubjects.put(subject, list);
+ }
+ }
+ }
+
+ /**
+ * Add an X509CRL to the index.
+ */
+ private void indexCRL(X509CRL crl) {
+ X500Principal issuer = crl.getIssuerX500Principal();
+ Object oldEntry = crlIssuers.put(issuer, crl);
+ if (oldEntry != null) { // assume this is unlikely
+ if (oldEntry instanceof X509CRL) {
+ if (crl.equals(oldEntry)) {
+ return;
+ }
+ List<X509CRL> list = new ArrayList<>(2);
+ list.add(crl);
+ list.add((X509CRL)oldEntry);
+ crlIssuers.put(issuer, list);
+ } else {
+ // See crlIssuers javadoc.
+ @SuppressWarnings("unchecked")
+ List<X509CRL> list = (List<X509CRL>)oldEntry;
+ if (list.contains(crl) == false) {
+ list.add(crl);
+ }
+ crlIssuers.put(issuer, list);
+ }
+ }
+ }
+
+ /**
+ * Returns a <code>Collection</code> of <code>Certificate</code>s that
+ * match the specified selector. If no <code>Certificate</code>s
+ * match the selector, an empty <code>Collection</code> will be returned.
+ *
+ * @param selector a <code>CertSelector</code> used to select which
+ * <code>Certificate</code>s should be returned. Specify <code>null</code>
+ * to return all <code>Certificate</code>s.
+ * @return a <code>Collection</code> of <code>Certificate</code>s that
+ * match the specified selector
+ * @throws CertStoreException if an exception occurs
+ */
+ @Override
+ public Collection<? extends Certificate> engineGetCertificates(CertSelector selector)
+ throws CertStoreException {
+
+ // no selector means match all
+ if (selector == null) {
+ Set<Certificate> matches = new HashSet<>();
+ matchX509Certs(new X509CertSelector(), matches);
+ matches.addAll(otherCertificates);
+ return matches;
+ }
+
+ if (selector instanceof X509CertSelector == false) {
+ Set<Certificate> matches = new HashSet<>();
+ matchX509Certs(selector, matches);
+ for (Certificate cert : otherCertificates) {
+ if (selector.match(cert)) {
+ matches.add(cert);
+ }
+ }
+ return matches;
+ }
+
+ if (certSubjects.isEmpty()) {
+ return Collections.<X509Certificate>emptySet();
+ }
+ X509CertSelector x509Selector = (X509CertSelector)selector;
+ // see if the subject is specified
+ X500Principal subject;
+ X509Certificate matchCert = x509Selector.getCertificate();
+ if (matchCert != null) {
+ subject = matchCert.getSubjectX500Principal();
+ } else {
+ subject = x509Selector.getSubject();
+ }
+ if (subject != null) {
+ // yes, narrow down candidates to indexed possibilities
+ Object entry = certSubjects.get(subject);
+ if (entry == null) {
+ return Collections.<X509Certificate>emptySet();
+ }
+ if (entry instanceof X509Certificate) {
+ X509Certificate x509Entry = (X509Certificate)entry;
+ if (x509Selector.match(x509Entry)) {
+ return Collections.singleton(x509Entry);
+ } else {
+ return Collections.<X509Certificate>emptySet();
+ }
+ } else {
+ // See certSubjects javadoc.
+ @SuppressWarnings("unchecked")
+ List<X509Certificate> list = (List<X509Certificate>)entry;
+ Set<X509Certificate> matches = new HashSet<>(16);
+ for (X509Certificate cert : list) {
+ if (x509Selector.match(cert)) {
+ matches.add(cert);
+ }
+ }
+ return matches;
+ }
+ }
+ // cannot use index, iterate all
+ Set<Certificate> matches = new HashSet<>(16);
+ matchX509Certs(x509Selector, matches);
+ return matches;
+ }
+
+ /**
+ * Iterate through all the X509Certificates and add matches to the
+ * collection.
+ */
+ private void matchX509Certs(CertSelector selector,
+ Collection<Certificate> matches) {
+
+ for (Object obj : certSubjects.values()) {
+ if (obj instanceof X509Certificate) {
+ X509Certificate cert = (X509Certificate)obj;
+ if (selector.match(cert)) {
+ matches.add(cert);
+ }
+ } else {
+ // See certSubjects javadoc.
+ @SuppressWarnings("unchecked")
+ List<X509Certificate> list = (List<X509Certificate>)obj;
+ for (X509Certificate cert : list) {
+ if (selector.match(cert)) {
+ matches.add(cert);
+ }
+ }
+ }
+ }
+ }
+
+ /**
+ * Returns a <code>Collection</code> of <code>CRL</code>s that
+ * match the specified selector. If no <code>CRL</code>s
+ * match the selector, an empty <code>Collection</code> will be returned.
+ *
+ * @param selector a <code>CRLSelector</code> used to select which
+ * <code>CRL</code>s should be returned. Specify <code>null</code>
+ * to return all <code>CRL</code>s.
+ * @return a <code>Collection</code> of <code>CRL</code>s that
+ * match the specified selector
+ * @throws CertStoreException if an exception occurs
+ */
+ @Override
+ public Collection<CRL> engineGetCRLs(CRLSelector selector)
+ throws CertStoreException {
+
+ if (selector == null) {
+ Set<CRL> matches = new HashSet<>();
+ matchX509CRLs(new X509CRLSelector(), matches);
+ matches.addAll(otherCRLs);
+ return matches;
+ }
+
+ if (selector instanceof X509CRLSelector == false) {
+ Set<CRL> matches = new HashSet<>();
+ matchX509CRLs(selector, matches);
+ for (CRL crl : otherCRLs) {
+ if (selector.match(crl)) {
+ matches.add(crl);
+ }
+ }
+ return matches;
+ }
+
+ if (crlIssuers.isEmpty()) {
+ return Collections.<CRL>emptySet();
+ }
+ X509CRLSelector x509Selector = (X509CRLSelector)selector;
+ // see if the issuer is specified
+ Collection<X500Principal> issuers = x509Selector.getIssuers();
+ if (issuers != null) {
+ HashSet<CRL> matches = new HashSet<>(16);
+ for (X500Principal issuer : issuers) {
+ Object entry = crlIssuers.get(issuer);
+ if (entry == null) {
+ // empty
+ } else if (entry instanceof X509CRL) {
+ X509CRL crl = (X509CRL)entry;
+ if (x509Selector.match(crl)) {
+ matches.add(crl);
+ }
+ } else { // List
+ // See crlIssuers javadoc.
+ @SuppressWarnings("unchecked")
+ List<X509CRL> list = (List<X509CRL>)entry;
+ for (X509CRL crl : list) {
+ if (x509Selector.match(crl)) {
+ matches.add(crl);
+ }
+ }
+ }
+ }
+ return matches;
+ }
+ // cannot use index, iterate all
+ Set<CRL> matches = new HashSet<>(16);
+ matchX509CRLs(x509Selector, matches);
+ return matches;
+ }
+
+ /**
+ * Iterate through all the X509CRLs and add matches to the
+ * collection.
+ */
+ private void matchX509CRLs(CRLSelector selector, Collection<CRL> matches) {
+ for (Object obj : crlIssuers.values()) {
+ if (obj instanceof X509CRL) {
+ X509CRL crl = (X509CRL)obj;
+ if (selector.match(crl)) {
+ matches.add(crl);
+ }
+ } else {
+ // See crlIssuers javadoc.
+ @SuppressWarnings("unchecked")
+ List<X509CRL> list = (List<X509CRL>)obj;
+ for (X509CRL crl : list) {
+ if (selector.match(crl)) {
+ matches.add(crl);
+ }
+ }
+ }
+ }
+ }
+
+}
diff --git a/ojluni/src/main/java/sun/security/provider/certpath/KeyChecker.java b/ojluni/src/main/java/sun/security/provider/certpath/KeyChecker.java
new file mode 100644
index 0000000..2d45d95
--- /dev/null
+++ b/ojluni/src/main/java/sun/security/provider/certpath/KeyChecker.java
@@ -0,0 +1,169 @@
+/*
+ * Copyright (c) 2000, 2012, 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.*;
+import java.security.cert.*;
+import java.security.cert.PKIXReason;
+
+import sun.security.util.Debug;
+import static sun.security.x509.PKIXExtensions.*;
+
+/**
+ * KeyChecker is a <code>PKIXCertPathChecker</code> that checks that the
+ * keyCertSign bit is set in the keyUsage extension in an intermediate CA
+ * certificate. It also checks whether the final certificate in a
+ * certification path meets the specified target constraints specified as
+ * a CertSelector in the PKIXParameters passed to the CertPathValidator.
+ *
+ * @since 1.4
+ * @author Yassir Elley
+ */
+class KeyChecker extends PKIXCertPathChecker {
+
+ private static final Debug debug = Debug.getInstance("certpath");
+ private final int certPathLen;
+ private final CertSelector targetConstraints;
+ private int remainingCerts;
+
+ private Set<String> supportedExts;
+
+ /**
+ * Creates a KeyChecker.
+ *
+ * @param certPathLen allowable cert path length
+ * @param targetCertSel a CertSelector object specifying the constraints
+ * on the target certificate
+ */
+ KeyChecker(int certPathLen, CertSelector targetCertSel) {
+ this.certPathLen = certPathLen;
+ this.targetConstraints = targetCertSel;
+ }
+
+ /**
+ * Initializes the internal state of the checker from parameters
+ * specified in the constructor
+ */
+ @Override
+ public void init(boolean forward) throws CertPathValidatorException {
+ if (!forward) {
+ remainingCerts = certPathLen;
+ } else {
+ throw new CertPathValidatorException
+ ("forward checking not supported");
+ }
+ }
+
+ @Override
+ public boolean isForwardCheckingSupported() {
+ return false;
+ }
+
+ @Override
+ public Set<String> getSupportedExtensions() {
+ if (supportedExts == null) {
+ supportedExts = new HashSet<String>(3);
+ supportedExts.add(KeyUsage_Id.toString());
+ supportedExts.add(ExtendedKeyUsage_Id.toString());
+ supportedExts.add(SubjectAlternativeName_Id.toString());
+ supportedExts = Collections.unmodifiableSet(supportedExts);
+ }
+ return supportedExts;
+ }
+
+ /**
+ * Checks that keyUsage and target constraints are satisfied by
+ * the specified certificate.
+ *
+ * @param cert the Certificate
+ * @param unresolvedCritExts the unresolved critical extensions
+ * @throws CertPathValidatorException if certificate does not verify
+ */
+ @Override
+ public void check(Certificate cert, Collection<String> unresCritExts)
+ throws CertPathValidatorException
+ {
+ X509Certificate currCert = (X509Certificate)cert;
+
+ remainingCerts--;
+
+ // if final certificate, check that target constraints are satisfied
+ if (remainingCerts == 0) {
+ if (targetConstraints != null &&
+ targetConstraints.match(currCert) == false) {
+ throw new CertPathValidatorException("target certificate " +
+ "constraints check failed");
+ }
+ } else {
+ // otherwise, verify that keyCertSign bit is set in CA certificate
+ verifyCAKeyUsage(currCert);
+ }
+
+ // remove the extensions that we have checked
+ if (unresCritExts != null && !unresCritExts.isEmpty()) {
+ unresCritExts.remove(KeyUsage_Id.toString());
+ unresCritExts.remove(ExtendedKeyUsage_Id.toString());
+ unresCritExts.remove(SubjectAlternativeName_Id.toString());
+ }
+ }
+
+ // the index of keyCertSign in the boolean KeyUsage array
+ private static final int KEY_CERT_SIGN = 5;
+ /**
+ * Verifies the key usage extension in a CA cert.
+ * The key usage extension, if present, must assert the keyCertSign bit.
+ * The extended key usage extension is not checked (see CR 4776794 for
+ * more information).
+ */
+ static void verifyCAKeyUsage(X509Certificate cert)
+ throws CertPathValidatorException {
+ String msg = "CA key usage";
+ if (debug != null) {
+ debug.println("KeyChecker.verifyCAKeyUsage() ---checking " + msg
+ + "...");
+ }
+
+ boolean[] keyUsageBits = cert.getKeyUsage();
+
+ // getKeyUsage returns null if the KeyUsage extension is not present
+ // in the certificate - in which case there is nothing to check
+ if (keyUsageBits == null) {
+ return;
+ }
+
+ // throw an exception if the keyCertSign bit is not set
+ if (!keyUsageBits[KEY_CERT_SIGN]) {
+ throw new CertPathValidatorException
+ (msg + " check failed: keyCertSign bit is not set", null,
+ null, -1, PKIXReason.INVALID_KEY_USAGE);
+ }
+
+ if (debug != null) {
+ debug.println("KeyChecker.verifyCAKeyUsage() " + msg
+ + " verified.");
+ }
+ }
+}
diff --git a/ojluni/src/main/java/sun/security/provider/certpath/OCSP.java b/ojluni/src/main/java/sun/security/provider/certpath/OCSP.java
new file mode 100644
index 0000000..dce8fd6
--- /dev/null
+++ b/ojluni/src/main/java/sun/security/provider/certpath/OCSP.java
@@ -0,0 +1,364 @@
+/*
+ * Copyright (c) 2009, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * 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.io.InputStream;
+import java.io.IOException;
+import java.io.OutputStream;
+import java.net.URI;
+import java.net.URL;
+import java.net.HttpURLConnection;
+import java.security.cert.CertificateException;
+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.X509Certificate;
+import java.util.Arrays;
+import java.util.Collections;
+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.x509.AccessDescription;
+import sun.security.x509.AuthorityInfoAccessExtension;
+import sun.security.x509.GeneralName;
+import sun.security.x509.GeneralNameInterface;
+import sun.security.x509.URIName;
+import sun.security.x509.X509CertImpl;
+
+/**
+ * This is a class that checks the revocation status of a certificate(s) using
+ * OCSP. It is not a PKIXCertPathChecker and therefore can be used outside of
+ * the CertPathValidator framework. It is useful when you want to
+ * just check the revocation status of a certificate, and you don't want to
+ * incur the overhead of validating all of the certificates in the
+ * associated certificate chain.
+ *
+ * @author Sean Mullan
+ */
+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;
+
+ /**
+ * Integer value indicating the timeout length, in seconds, to be
+ * used for the OCSP check. A timeout of zero is interpreted as
+ * an infinite timeout.
+ */
+ private static final int CONNECT_TIMEOUT = initializeTimeout();
+
+ /**
+ * Initialize the timeout length by getting the OCSP timeout
+ * system property. If the property has not been set, or if its
+ * value is negative, set the timeout length to the default.
+ */
+ private static int initializeTimeout() {
+ Integer tmp = java.security.AccessController.doPrivileged(
+ new GetIntegerAction("com.sun.security.ocsp.timeout"));
+ if (tmp == null || tmp < 0) {
+ return DEFAULT_CONNECT_TIMEOUT;
+ }
+ // Convert to milliseconds, as the system property will be
+ // specified in seconds
+ return tmp * 1000;
+ }
+
+ 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.<Extension>emptyList());
+ return (RevocationStatus)ocspResponse.getSingleResponse(certId);
+ }
+
+ /**
+ * Obtains the revocation status of a certificate using OCSP.
+ *
+ * @param cert the certificate to be checked
+ * @param issuerCert the issuer certificate
+ * @param responderURI the URI of the OCSP responder
+ * @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.
+ * @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,
+ URI responderURI,
+ X509Certificate responderCert,
+ Date date)
+ throws IOException, CertPathValidatorException
+ {
+ return check(cert, issuerCert, responderURI, responderCert, date,
+ Collections.<Extension>emptyList());
+ }
+
+ // Called by com.sun.deploy.security.TrustDecider
+ public static RevocationStatus check(X509Certificate cert,
+ X509Certificate issuerCert,
+ URI responderURI,
+ X509Certificate responderCert,
+ Date date, List<Extension> extensions)
+ throws IOException, CertPathValidatorException
+ {
+ CertId certId = null;
+ try {
+ X509CertImpl certImpl = X509CertImpl.toImpl(cert);
+ 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, responderCert, date, extensions);
+ return (RevocationStatus) ocspResponse.getSingleResponse(certId);
+ }
+
+ /**
+ * Checks the revocation status of a list of certificates using OCSP.
+ *
+ * @param certs the CertIds to be checked
+ * @param responderURI the URI of the OCSP responder
+ * @param issuerCert the issuer's certificate
+ * @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.
+ * @return the OCSPResponse
+ * @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
+ */
+ static OCSPResponse check(List<CertId> certIds, URI responderURI,
+ X509Certificate issuerCert,
+ X509Certificate responderCert, Date date,
+ List<Extension> extensions)
+ throws IOException, CertPathValidatorException
+ {
+ byte[] bytes = null;
+ OCSPRequest request = null;
+ try {
+ request = new OCSPRequest(certIds, extensions);
+ bytes = request.encodeBytes();
+ } catch (IOException ioe) {
+ throw new CertPathValidatorException
+ ("Exception while encoding OCSPRequest", ioe);
+ }
+
+ InputStream in = null;
+ OutputStream out = null;
+ byte[] response = null;
+ try {
+ URL url = responderURI.toURL();
+ if (debug != null) {
+ debug.println("connecting to OCSP service at: " + url);
+ }
+ HttpURLConnection con = (HttpURLConnection)url.openConnection();
+ con.setConnectTimeout(CONNECT_TIMEOUT);
+ con.setReadTimeout(CONNECT_TIMEOUT);
+ con.setDoOutput(true);
+ con.setDoInput(true);
+ con.setRequestMethod("POST");
+ con.setRequestProperty
+ ("Content-type", "application/ocsp-request");
+ con.setRequestProperty
+ ("Content-length", String.valueOf(bytes.length));
+ out = con.getOutputStream();
+ out.write(bytes);
+ out.flush();
+ // Check the response
+ if (debug != null &&
+ con.getResponseCode() != HttpURLConnection.HTTP_OK) {
+ debug.println("Received HTTP error: " + con.getResponseCode()
+ + " - " + con.getResponseMessage());
+ }
+ in = con.getInputStream();
+ int contentLength = con.getContentLength();
+ if (contentLength == -1) {
+ contentLength = Integer.MAX_VALUE;
+ }
+ response = new byte[contentLength > 2048 ? 2048 : contentLength];
+ int total = 0;
+ while (total < contentLength) {
+ int count = in.read(response, total, response.length - total);
+ if (count < 0)
+ break;
+
+ total += count;
+ if (total >= response.length && total < contentLength) {
+ response = Arrays.copyOf(response, total * 2);
+ }
+ }
+ 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 {
+ in.close();
+ } catch (IOException ioe) {
+ throw ioe;
+ }
+ }
+ if (out != null) {
+ try {
+ out.close();
+ } catch (IOException ioe) {
+ throw ioe;
+ }
+ }
+ }
+
+ 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;
+ }
+
+ /**
+ * Returns the URI of the OCSP Responder as specified in the
+ * certificate's Authority Information Access extension, or null if
+ * not specified.
+ *
+ * @param cert the certificate
+ * @return the URI of the OCSP Responder, or null if not specified
+ */
+ // Called by com.sun.deploy.security.TrustDecider
+ public static URI getResponderURI(X509Certificate cert) {
+ try {
+ return getResponderURI(X509CertImpl.toImpl(cert));
+ } catch (CertificateException ce) {
+ // treat this case as if the cert had no extension
+ return null;
+ }
+ }
+
+ static URI getResponderURI(X509CertImpl certImpl) {
+
+ // Examine the certificate's AuthorityInfoAccess extension
+ AuthorityInfoAccessExtension aia =
+ certImpl.getAuthorityInfoAccessExtension();
+ if (aia == null) {
+ return null;
+ }
+
+ List<AccessDescription> descriptions = aia.getAccessDescriptions();
+ for (AccessDescription description : descriptions) {
+ if (description.getAccessMethod().equals((Object)
+ AccessDescription.Ad_OCSP_Id)) {
+
+ GeneralName generalName = description.getAccessLocation();
+ if (generalName.getType() == GeneralNameInterface.NAME_URI) {
+ URIName uri = (URIName) generalName.getName();
+ return uri.getURI();
+ }
+ }
+ }
+ return null;
+ }
+
+ /**
+ * The Revocation Status of a certificate.
+ */
+ public static interface RevocationStatus {
+ public enum CertStatus { GOOD, REVOKED, UNKNOWN };
+
+ /**
+ * Returns the revocation status.
+ */
+ CertStatus getCertStatus();
+ /**
+ * Returns the time when the certificate was revoked, or null
+ * if it has not been revoked.
+ */
+ Date getRevocationTime();
+ /**
+ * Returns the reason the certificate was revoked, or null if it
+ * has not been revoked.
+ */
+ CRLReason getRevocationReason();
+
+ /**
+ * Returns a Map of additional extensions.
+ */
+ Map<String, Extension> getSingleExtensions();
+ }
+}
diff --git a/ojluni/src/main/java/sun/security/provider/certpath/OCSPRequest.java b/ojluni/src/main/java/sun/security/provider/certpath/OCSPRequest.java
new file mode 100644
index 0000000..6bded97
--- /dev/null
+++ b/ojluni/src/main/java/sun/security/provider/certpath/OCSPRequest.java
@@ -0,0 +1,156 @@
+/*
+ * Copyright (c) 2003, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * 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.io.IOException;
+import java.security.cert.Extension;
+import java.util.Collections;
+import java.util.List;
+
+import sun.misc.HexDumpEncoder;
+import sun.security.util.*;
+
+/**
+ * This class can be used to generate an OCSP request and send it over
+ * an outputstream. Currently we do not support signing requests
+ * The OCSP Request is specified in RFC 2560 and
+ * the ASN.1 definition is as follows:
+ * <pre>
+ *
+ * OCSPRequest ::= SEQUENCE {
+ * tbsRequest TBSRequest,
+ * optionalSignature [0] EXPLICIT Signature OPTIONAL }
+ *
+ * TBSRequest ::= SEQUENCE {
+ * version [0] EXPLICIT Version DEFAULT v1,
+ * requestorName [1] EXPLICIT GeneralName OPTIONAL,
+ * requestList SEQUENCE OF Request,
+ * requestExtensions [2] EXPLICIT Extensions OPTIONAL }
+ *
+ * Signature ::= SEQUENCE {
+ * signatureAlgorithm AlgorithmIdentifier,
+ * signature BIT STRING,
+ * certs [0] EXPLICIT SEQUENCE OF Certificate OPTIONAL
+ * }
+ *
+ * Version ::= INTEGER { v1(0) }
+ *
+ * Request ::= SEQUENCE {
+ * reqCert CertID,
+ * singleRequestExtensions [0] EXPLICIT Extensions OPTIONAL }
+ *
+ * CertID ::= SEQUENCE {
+ * hashAlgorithm AlgorithmIdentifier,
+ * issuerNameHash OCTET STRING, -- Hash of Issuer's DN
+ * issuerKeyHash OCTET STRING, -- Hash of Issuers public key
+ * serialNumber CertificateSerialNumber
+ * }
+ *
+ * </pre>
+ *
+ * @author Ram Marti
+ */
+
+class OCSPRequest {
+
+ private static final Debug debug = Debug.getInstance("certpath");
+ private static final boolean dump = debug != null && Debug.isOn("ocsp");
+
+ // List of request CertIds
+ private final List<CertId> certIds;
+ private final List<Extension> extensions;
+ private byte[] nonce;
+
+ /*
+ * Constructs an OCSPRequest. This constructor is used
+ * to construct an unsigned OCSP Request for a single user cert.
+ */
+ OCSPRequest(CertId certId) {
+ this(Collections.singletonList(certId));
+ }
+
+ OCSPRequest(List<CertId> certIds) {
+ this.certIds = certIds;
+ this.extensions = Collections.<Extension>emptyList();
+ }
+
+ OCSPRequest(List<CertId> certIds, List<Extension> extensions) {
+ this.certIds = certIds;
+ this.extensions = extensions;
+ }
+
+ byte[] encodeBytes() throws IOException {
+
+ // encode tbsRequest
+ DerOutputStream tmp = new DerOutputStream();
+ DerOutputStream requestsOut = new DerOutputStream();
+ for (CertId certId : certIds) {
+ DerOutputStream certIdOut = new DerOutputStream();
+ certId.encode(certIdOut);
+ requestsOut.write(DerValue.tag_Sequence, certIdOut);
+ }
+
+ tmp.write(DerValue.tag_Sequence, requestsOut);
+ if (!extensions.isEmpty()) {
+ DerOutputStream extOut = new DerOutputStream();
+ for (Extension ext : extensions) {
+ ext.encode(extOut);
+ if (ext.getId().equals(OCSP.NONCE_EXTENSION_OID.toString())) {
+ nonce = ext.getValue();
+ }
+ }
+ DerOutputStream extsOut = new DerOutputStream();
+ extsOut.write(DerValue.tag_Sequence, extOut);
+ tmp.write(DerValue.createTag(DerValue.TAG_CONTEXT,
+ true, (byte)2), extsOut);
+ }
+
+ DerOutputStream tbsRequest = new DerOutputStream();
+ tbsRequest.write(DerValue.tag_Sequence, tmp);
+
+ // OCSPRequest without the signature
+ DerOutputStream ocspRequest = new DerOutputStream();
+ ocspRequest.write(DerValue.tag_Sequence, tbsRequest);
+
+ byte[] bytes = ocspRequest.toByteArray();
+
+ if (dump) {
+ HexDumpEncoder hexEnc = new HexDumpEncoder();
+ debug.println("OCSPRequest bytes...\n\n" +
+ hexEnc.encode(bytes) + "\n");
+ }
+
+ return bytes;
+ }
+
+ List<CertId> getCertIds() {
+ return certIds;
+ }
+
+ byte[] getNonce() {
+ return nonce;
+ }
+}
diff --git a/ojluni/src/main/java/sun/security/provider/certpath/OCSPResponse.java b/ojluni/src/main/java/sun/security/provider/certpath/OCSPResponse.java
new file mode 100644
index 0000000..8075d73
--- /dev/null
+++ b/ojluni/src/main/java/sun/security/provider/certpath/OCSPResponse.java
@@ -0,0 +1,827 @@
+/*
+ * Copyright (c) 2003, 2014, 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.io.*;
+import java.security.*;
+import java.security.cert.CertificateException;
+import java.security.cert.CertificateParsingException;
+import java.security.cert.CertPathValidatorException;
+import java.security.cert.CertPathValidatorException.BasicReason;
+import java.security.cert.CRLReason;
+import java.security.cert.TrustAnchor;
+import java.security.cert.X509Certificate;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.Date;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import javax.security.auth.x500.X500Principal;
+
+import sun.misc.HexDumpEncoder;
+import sun.security.action.GetIntegerAction;
+import sun.security.x509.*;
+import sun.security.util.*;
+
+/**
+ * This class is used to process an OCSP response.
+ * The OCSP Response is defined
+ * in RFC 2560 and the ASN.1 encoding is as follows:
+ * <pre>
+ *
+ * OCSPResponse ::= SEQUENCE {
+ * responseStatus OCSPResponseStatus,
+ * responseBytes [0] EXPLICIT ResponseBytes OPTIONAL }
+ *
+ * OCSPResponseStatus ::= ENUMERATED {
+ * successful (0), --Response has valid confirmations
+ * malformedRequest (1), --Illegal confirmation request
+ * internalError (2), --Internal error in issuer
+ * tryLater (3), --Try again later
+ * --(4) is not used
+ * sigRequired (5), --Must sign the request
+ * unauthorized (6) --Request unauthorized
+ * }
+ *
+ * ResponseBytes ::= SEQUENCE {
+ * responseType OBJECT IDENTIFIER,
+ * response OCTET STRING }
+ *
+ * BasicOCSPResponse ::= SEQUENCE {
+ * tbsResponseData ResponseData,
+ * signatureAlgorithm AlgorithmIdentifier,
+ * signature BIT STRING,
+ * certs [0] EXPLICIT SEQUENCE OF Certificate OPTIONAL }
+ *
+ * The value for signature SHALL be computed on the hash of the DER
+ * encoding ResponseData.
+ *
+ * ResponseData ::= SEQUENCE {
+ * version [0] EXPLICIT Version DEFAULT v1,
+ * responderID ResponderID,
+ * producedAt GeneralizedTime,
+ * responses SEQUENCE OF SingleResponse,
+ * responseExtensions [1] EXPLICIT Extensions OPTIONAL }
+ *
+ * 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)
+ *
+ * SingleResponse ::= SEQUENCE {
+ * certID CertID,
+ * certStatus CertStatus,
+ * thisUpdate GeneralizedTime,
+ * nextUpdate [0] EXPLICIT GeneralizedTime OPTIONAL,
+ * singleExtensions [1] EXPLICIT Extensions OPTIONAL }
+ *
+ * CertStatus ::= CHOICE {
+ * good [0] IMPLICIT NULL,
+ * revoked [1] IMPLICIT RevokedInfo,
+ * unknown [2] IMPLICIT UnknownInfo }
+ *
+ * RevokedInfo ::= SEQUENCE {
+ * revocationTime GeneralizedTime,
+ * revocationReason [0] EXPLICIT CRLReason OPTIONAL }
+ *
+ * UnknownInfo ::= NULL -- this can be replaced with an enumeration
+ *
+ * </pre>
+ *
+ * @author Ram Marti
+ */
+
+public final class OCSPResponse {
+
+ public enum ResponseStatus {
+ SUCCESSFUL, // Response has valid confirmations
+ MALFORMED_REQUEST, // Illegal request
+ INTERNAL_ERROR, // Internal error in responder
+ TRY_LATER, // Try again later
+ UNUSED, // is not used
+ SIG_REQUIRED, // Must sign the request
+ UNAUTHORIZED // Request unauthorized
+ };
+ private static ResponseStatus[] rsvalues = ResponseStatus.values();
+
+ private static final Debug debug = Debug.getInstance("certpath");
+ private static final boolean dump = debug != null && Debug.isOn("ocsp");
+ private static final ObjectIdentifier OCSP_BASIC_RESPONSE_OID =
+ ObjectIdentifier.newInternal(new int[] { 1, 3, 6, 1, 5, 5, 7, 48, 1, 1});
+ private static final int CERT_STATUS_GOOD = 0;
+ private static final int CERT_STATUS_REVOKED = 1;
+ private static final int CERT_STATUS_UNKNOWN = 2;
+
+ // ResponderID CHOICE tags
+ private static final int NAME_TAG = 1;
+ private static final int KEY_TAG = 2;
+
+ // Object identifier for the OCSPSigning key purpose
+ private static final String KP_OCSP_SIGNING_OID = "1.3.6.1.5.5.7.3.9";
+
+ // Default maximum clock skew in milliseconds (15 minutes)
+ // allowed when checking validity of OCSP responses
+ private static final int DEFAULT_MAX_CLOCK_SKEW = 900000;
+
+ /**
+ * Integer value indicating the maximum allowable clock skew, in seconds,
+ * to be used for the OCSP check.
+ */
+ private static final int MAX_CLOCK_SKEW = initializeClockSkew();
+
+ /**
+ * Initialize the maximum allowable clock skew by getting the OCSP
+ * clock skew system property. If the property has not been set, or if its
+ * value is negative, set the skew to the default.
+ */
+ private static int initializeClockSkew() {
+ Integer tmp = java.security.AccessController.doPrivileged(
+ new GetIntegerAction("com.sun.security.ocsp.clockSkew"));
+ if (tmp == null || tmp < 0) {
+ return DEFAULT_MAX_CLOCK_SKEW;
+ }
+ // Convert to milliseconds, as the system property will be
+ // specified in seconds
+ return tmp * 1000;
+ }
+
+ // an array of all of the CRLReasons (used in SingleResponse)
+ private static CRLReason[] values = CRLReason.values();
+
+ private final ResponseStatus responseStatus;
+ private final Map<CertId, SingleResponse> singleResponseMap;
+ private final AlgorithmId sigAlgId;
+ private final byte[] signature;
+ private final byte[] tbsResponseData;
+ private final byte[] responseNonce;
+ private List<X509CertImpl> certs;
+ private X509CertImpl signerCert = null;
+ private X500Principal responderName = null;
+ private KeyIdentifier responderKeyId = null;
+
+ /*
+ * Create an OCSP response from its ASN.1 DER encoding.
+ */
+ OCSPResponse(byte[] bytes) throws IOException {
+ if (dump) {
+ HexDumpEncoder hexEnc = new HexDumpEncoder();
+ debug.println("OCSPResponse bytes...\n\n" +
+ hexEnc.encode(bytes) + "\n");
+ }
+ DerValue der = new DerValue(bytes);
+ if (der.tag != DerValue.tag_Sequence) {
+ throw new IOException("Bad encoding in OCSP response: " +
+ "expected ASN.1 SEQUENCE tag.");
+ }
+ DerInputStream derIn = der.getData();
+
+ // responseStatus
+ int status = derIn.getEnumerated();
+ if (status >= 0 && status < rsvalues.length) {
+ responseStatus = rsvalues[status];
+ } else {
+ // unspecified responseStatus
+ throw new IOException("Unknown OCSPResponse status: " + status);
+ }
+ if (debug != null) {
+ debug.println("OCSP response status: " + responseStatus);
+ }
+ if (responseStatus != ResponseStatus.SUCCESSFUL) {
+ // no need to continue, responseBytes are not set.
+ singleResponseMap = Collections.emptyMap();
+ certs = new ArrayList<X509CertImpl>();
+ sigAlgId = null;
+ signature = null;
+ tbsResponseData = null;
+ responseNonce = null;
+ return;
+ }
+
+ // responseBytes
+ der = derIn.getDerValue();
+ if (!der.isContextSpecific((byte)0)) {
+ throw new IOException("Bad encoding in responseBytes element " +
+ "of OCSP response: expected ASN.1 context specific tag 0.");
+ }
+ DerValue tmp = der.data.getDerValue();
+ if (tmp.tag != DerValue.tag_Sequence) {
+ throw new IOException("Bad encoding in responseBytes element " +
+ "of OCSP response: expected ASN.1 SEQUENCE tag.");
+ }
+
+ // responseType
+ derIn = tmp.data;
+ ObjectIdentifier responseType = derIn.getOID();
+ if (responseType.equals((Object)OCSP_BASIC_RESPONSE_OID)) {
+ if (debug != null) {
+ debug.println("OCSP response type: basic");
+ }
+ } else {
+ if (debug != null) {
+ debug.println("OCSP response type: " + responseType);
+ }
+ throw new IOException("Unsupported OCSP response type: " +
+ responseType);
+ }
+
+ // BasicOCSPResponse
+ DerInputStream basicOCSPResponse =
+ new DerInputStream(derIn.getOctetString());
+
+ DerValue[] seqTmp = basicOCSPResponse.getSequence(2);
+ if (seqTmp.length < 3) {
+ throw new IOException("Unexpected BasicOCSPResponse value");
+ }
+
+ DerValue responseData = seqTmp[0];
+
+ // Need the DER encoded ResponseData to verify the signature later
+ tbsResponseData = seqTmp[0].toByteArray();
+
+ // tbsResponseData
+ if (responseData.tag != DerValue.tag_Sequence) {
+ throw new IOException("Bad encoding in tbsResponseData " +
+ "element of OCSP response: expected ASN.1 SEQUENCE tag.");
+ }
+ DerInputStream seqDerIn = responseData.data;
+ DerValue seq = seqDerIn.getDerValue();
+
+ // version
+ if (seq.isContextSpecific((byte)0)) {
+ // seq[0] is version
+ if (seq.isConstructed() && seq.isContextSpecific()) {
+ //System.out.println ("version is available");
+ seq = seq.data.getDerValue();
+ int version = seq.getInteger();
+ if (seq.data.available() != 0) {
+ throw new IOException("Bad encoding in version " +
+ " element of OCSP response: bad format");
+ }
+ seq = seqDerIn.getDerValue();
+ }
+ }
+
+ // 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");
+ }
+
+ // producedAt
+ seq = seqDerIn.getDerValue();
+ if (debug != null) {
+ Date producedAtDate = seq.getGeneralizedTime();
+ debug.println("OCSP response produced at: " + producedAtDate);
+ }
+
+ // responses
+ DerValue[] singleResponseDer = seqDerIn.getSequence(1);
+ singleResponseMap = new HashMap<>(singleResponseDer.length);
+ if (debug != null) {
+ debug.println("OCSP number of SingleResponses: "
+ + singleResponseDer.length);
+ }
+ for (int i = 0; i < singleResponseDer.length; i++) {
+ SingleResponse singleResponse =
+ new SingleResponse(singleResponseDer[i]);
+ singleResponseMap.put(singleResponse.getCertId(), singleResponse);
+ }
+
+ // responseExtensions
+ byte[] nonce = null;
+ 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());
+ }
+ }
+ }
+ }
+ responseNonce = nonce;
+
+ // signatureAlgorithmId
+ sigAlgId = AlgorithmId.parse(seqTmp[1]);
+
+ // signature
+ signature = seqTmp[2].getBitString();
+
+ // if seq[3] is available , then it is a sequence of certificates
+ if (seqTmp.length > 3) {
+ // certs are available
+ DerValue seqCert = seqTmp[3];
+ if (!seqCert.isContextSpecific((byte)0)) {
+ throw new IOException("Bad encoding in certs element of " +
+ "OCSP response: expected ASN.1 context specific tag 0.");
+ }
+ DerValue[] derCerts = seqCert.getData().getSequence(3);
+ certs = new ArrayList<X509CertImpl>(derCerts.length);
+ try {
+ for (int i = 0; i < derCerts.length; i++) {
+ X509CertImpl cert =
+ new X509CertImpl(derCerts[i].toByteArray());
+ certs.add(cert);
+
+ if (debug != null) {
+ debug.println("OCSP response cert #" + (i + 1) + ": " +
+ cert.getSubjectX500Principal());
+ }
+ }
+ } catch (CertificateException ce) {
+ throw new IOException("Bad encoding in X509 Certificate", ce);
+ }
+ } else {
+ certs = new ArrayList<X509CertImpl>();
+ }
+ }
+
+ void verify(List<CertId> certIds, X509Certificate issuerCert,
+ X509Certificate responderCert, Date date, byte[] nonce)
+ throws CertPathValidatorException
+ {
+ switch (responseStatus) {
+ case SUCCESSFUL:
+ break;
+ case TRY_LATER:
+ case INTERNAL_ERROR:
+ throw new CertPathValidatorException(
+ "OCSP response error: " + responseStatus, null, null, -1,
+ BasicReason.UNDETERMINED_REVOCATION_STATUS);
+ case UNAUTHORIZED:
+ default:
+ throw new CertPathValidatorException("OCSP response error: " +
+ responseStatus);
+ }
+
+ // Check that the response includes a response for all of the
+ // certs that were supplied in the request
+ for (CertId certId : certIds) {
+ SingleResponse sr = getSingleResponse(certId);
+ if (sr == null) {
+ if (debug != null) {
+ debug.println("No response found for CertId: " + certId);
+ }
+ throw new CertPathValidatorException(
+ "OCSP response does not include a response for a " +
+ "certificate supplied in the OCSP request");
+ }
+ if (debug != null) {
+ debug.println("Status of certificate (with serial number " +
+ certId.getSerialNumber() + ") is: " + sr.getCertStatus());
+ }
+ }
+
+ // Locate the signer cert
+ if (signerCert == null) {
+ // Add the Issuing CA cert and/or Trusted Responder cert to the list
+ // of certs from the OCSP response
+ try {
+ certs.add(X509CertImpl.toImpl(issuerCert));
+ if (responderCert != null) {
+ certs.add(X509CertImpl.toImpl(responderCert));
+ }
+ } catch (CertificateException ce) {
+ throw new CertPathValidatorException(
+ "Invalid issuer or trusted responder certificate", ce);
+ }
+
+ if (responderName != null) {
+ for (X509CertImpl cert : certs) {
+ if (cert.getSubjectX500Principal().equals(responderName)) {
+ signerCert = cert;
+ break;
+ }
+ }
+ } else if (responderKeyId != null) {
+ 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)) {
+ signerCert = cert;
+ break;
+ } else {
+ // The certificate does not have a SKID or may have
+ // been using a different algorithm (ex: see RFC 7093).
+ // Check if the responder's key identifier matches
+ // against a newly generated key identifier of the
+ // cert's public key using the 160-bit SHA-1 method.
+ try {
+ certKeyId = new KeyIdentifier(cert.getPublicKey());
+ } catch (IOException e) {
+ // ignore
+ }
+ if (responderKeyId.equals(certKeyId)) {
+ signerCert = cert;
+ break;
+ }
+ }
+ }
+ }
+ }
+
+ // 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 (debug != null) {
+ debug.println("OCSP response is signed by the target's " +
+ "Issuing CA");
+ }
+ // cert is trusted, now verify the signed response
+
+ // Check if the response is signed by a trusted responder
+ } else if (signerCert.equals(responderCert)) {
+ if (debug != null) {
+ debug.println("OCSP response is signed by a Trusted " +
+ "Responder");
+ }
+ // cert is trusted, now verify the signed response
+
+ // Check if the response is signed by an authorized responder
+ } else if (signerCert.getIssuerX500Principal().equals(
+ issuerCert.getSubjectX500Principal())) {
+
+ // Check for the OCSPSigning key purpose
+ try {
+ List<String> keyPurposes = signerCert.getExtendedKeyUsage();
+ if (keyPurposes == null ||
+ !keyPurposes.contains(KP_OCSP_SIGNING_OID)) {
+ throw new CertPathValidatorException(
+ "Responder's certificate not valid for signing " +
+ "OCSP responses");
+ }
+ } catch (CertificateParsingException cpe) {
+ // assume cert is not valid for signing
+ throw new CertPathValidatorException(
+ "Responder's certificate not valid for signing " +
+ "OCSP responses", cpe);
+ }
+
+ // Check algorithm constraints specified in security property
+ // "jdk.certpath.disabledAlgorithms".
+ AlgorithmChecker algChecker = new AlgorithmChecker(
+ new TrustAnchor(issuerCert, null));
+ algChecker.init(false);
+ algChecker.check(signerCert, Collections.<String>emptySet());
+
+ // check the validity
+ try {
+ if (date == null) {
+ signerCert.checkValidity();
+ } else {
+ signerCert.checkValidity(date);
+ }
+ } catch (CertificateException e) {
+ throw new CertPathValidatorException(
+ "Responder's certificate not within the " +
+ "validity period", e);
+ }
+
+ // check for revocation
+ //
+ // A CA may specify that an OCSP client can trust a
+ // responder for the lifetime of the responder's
+ // certificate. The CA does so by including the
+ // extension id-pkix-ocsp-nocheck.
+ //
+ Extension noCheck =
+ signerCert.getExtension(PKIXExtensions.OCSPNoCheck_Id);
+ if (noCheck != null) {
+ if (debug != null) {
+ debug.println("Responder's certificate includes " +
+ "the extension id-pkix-ocsp-nocheck.");
+ }
+ } else {
+ // we should do the revocation checking of the
+ // authorized responder in a future update.
+ }
+
+ // verify the signature
+ try {
+ signerCert.verify(issuerCert.getPublicKey());
+ if (debug != null) {
+ debug.println("OCSP response is signed by an " +
+ "Authorized Responder");
+ }
+ // cert is trusted, now verify the signed response
+
+ } catch (GeneralSecurityException e) {
+ signerCert = null;
+ }
+ } else {
+ throw new CertPathValidatorException(
+ "Responder's certificate is not authorized to sign " +
+ "OCSP responses");
+ }
+ }
+
+ // Confirm that the signed response was generated using the public
+ // key from the trusted responder cert
+ if (signerCert != null) {
+ // Check algorithm constraints specified in security property
+ // "jdk.certpath.disabledAlgorithms".
+ AlgorithmChecker.check(signerCert.getPublicKey(), sigAlgId);
+
+ if (!verifySignature(signerCert)) {
+ throw new CertPathValidatorException(
+ "Error verifying OCSP Response's signature");
+ }
+ } else {
+ // Need responder's cert in order to verify the signature
+ throw new CertPathValidatorException(
+ "Unable to verify OCSP Response's signature");
+ }
+
+ // Check freshness of OCSPResponse
+ if (nonce != null) {
+ if (responseNonce != null && !Arrays.equals(nonce, responseNonce)) {
+ throw new CertPathValidatorException("Nonces don't match");
+ }
+ }
+
+ long now = (date == null) ? System.currentTimeMillis() : date.getTime();
+ Date nowPlusSkew = new Date(now + MAX_CLOCK_SKEW);
+ Date nowMinusSkew = new Date(now - MAX_CLOCK_SKEW);
+ for (SingleResponse sr : singleResponseMap.values()) {
+ if (debug != null) {
+ String until = "";
+ if (sr.nextUpdate != null) {
+ until = " until " + sr.nextUpdate;
+ }
+ debug.println("Response's validity interval is from " +
+ sr.thisUpdate + until);
+ }
+
+ // Check that the test date is within the validity interval
+ if ((sr.thisUpdate != null && nowPlusSkew.before(sr.thisUpdate)) ||
+ (sr.nextUpdate != null && nowMinusSkew.after(sr.nextUpdate)))
+ {
+ throw new CertPathValidatorException(
+ "Response is unreliable: its validity " +
+ "interval is out-of-date");
+ }
+ }
+ }
+
+ /**
+ * Returns the OCSP ResponseStatus.
+ */
+ ResponseStatus getResponseStatus() {
+ return responseStatus;
+ }
+
+ /*
+ * Verify the signature of the OCSP response.
+ */
+ private boolean verifySignature(X509Certificate cert)
+ throws CertPathValidatorException {
+
+ try {
+ Signature respSignature = Signature.getInstance(sigAlgId.getName());
+ respSignature.initVerify(cert.getPublicKey());
+ respSignature.update(tbsResponseData);
+
+ if (respSignature.verify(signature)) {
+ if (debug != null) {
+ debug.println("Verified signature of OCSP Response");
+ }
+ return true;
+
+ } else {
+ if (debug != null) {
+ debug.println(
+ "Error verifying signature of OCSP Response");
+ }
+ return false;
+ }
+ } catch (InvalidKeyException | NoSuchAlgorithmException |
+ SignatureException e)
+ {
+ throw new CertPathValidatorException(e);
+ }
+ }
+
+ /**
+ * Returns the SingleResponse of the specified CertId, or null if
+ * there is no response for that CertId.
+ */
+ SingleResponse getSingleResponse(CertId certId) {
+ return singleResponseMap.get(certId);
+ }
+
+ /*
+ * Returns the certificate for the authority that signed the OCSP response.
+ */
+ X509Certificate getSignerCertificate() {
+ return signerCert; // set in verify()
+ }
+
+ /*
+ * A class representing a single OCSP response.
+ */
+ final static class SingleResponse implements OCSP.RevocationStatus {
+ private final CertId certId;
+ private final CertStatus certStatus;
+ private final Date thisUpdate;
+ private final Date nextUpdate;
+ private final Date revocationTime;
+ private final CRLReason revocationReason;
+ private final Map<String, java.security.cert.Extension> singleExtensions;
+
+ private SingleResponse(DerValue der) throws IOException {
+ if (der.tag != DerValue.tag_Sequence) {
+ throw new IOException("Bad ASN.1 encoding in SingleResponse");
+ }
+ DerInputStream tmp = der.data;
+
+ certId = new CertId(tmp.getDerValue().data);
+ DerValue derVal = tmp.getDerValue();
+ short tag = (byte)(derVal.tag & 0x1f);
+ if (tag == CERT_STATUS_REVOKED) {
+ certStatus = CertStatus.REVOKED;
+ revocationTime = derVal.data.getGeneralizedTime();
+ if (derVal.data.available() != 0) {
+ DerValue dv = derVal.data.getDerValue();
+ tag = (byte)(dv.tag & 0x1f);
+ if (tag == 0) {
+ int reason = dv.data.getEnumerated();
+ // if reason out-of-range just leave as UNSPECIFIED
+ if (reason >= 0 && reason < values.length) {
+ revocationReason = values[reason];
+ } else {
+ revocationReason = CRLReason.UNSPECIFIED;
+ }
+ } else {
+ revocationReason = CRLReason.UNSPECIFIED;
+ }
+ } else {
+ revocationReason = CRLReason.UNSPECIFIED;
+ }
+ // RevokedInfo
+ if (debug != null) {
+ debug.println("Revocation time: " + revocationTime);
+ debug.println("Revocation reason: " + revocationReason);
+ }
+ } else {
+ revocationTime = null;
+ revocationReason = CRLReason.UNSPECIFIED;
+ if (tag == CERT_STATUS_GOOD) {
+ certStatus = CertStatus.GOOD;
+ } else if (tag == CERT_STATUS_UNKNOWN) {
+ certStatus = CertStatus.UNKNOWN;
+ } else {
+ throw new IOException("Invalid certificate status");
+ }
+ }
+
+ thisUpdate = tmp.getGeneralizedTime();
+
+ if (tmp.available() == 0) {
+ // we are done
+ nextUpdate = null;
+ } else {
+ 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);
+ }
+ } else {
+ nextUpdate = null;
+ }
+ }
+ // singleExtensions
+ if (tmp.available() > 0) {
+ derVal = tmp.getDerValue();
+ if (derVal.isContextSpecific((byte)1)) {
+ DerValue[] singleExtDer = derVal.data.getSequence(3);
+ singleExtensions =
+ new HashMap<String, java.security.cert.Extension>
+ (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.put(ext.getId(), ext);
+ }
+ } else {
+ singleExtensions = Collections.emptyMap();
+ }
+ } else {
+ singleExtensions = Collections.emptyMap();
+ }
+ }
+
+ /*
+ * Return the certificate's revocation status code
+ */
+ @Override public CertStatus getCertStatus() {
+ return certStatus;
+ }
+
+ private CertId getCertId() {
+ return certId;
+ }
+
+ @Override public Date getRevocationTime() {
+ return (Date) revocationTime.clone();
+ }
+
+ @Override public CRLReason getRevocationReason() {
+ return revocationReason;
+ }
+
+ @Override
+ public Map<String, java.security.cert.Extension> getSingleExtensions() {
+ return Collections.unmodifiableMap(singleExtensions);
+ }
+
+ /**
+ * Construct a string representation of a single OCSP response.
+ */
+ @Override public String toString() {
+ StringBuilder sb = new StringBuilder();
+ sb.append("SingleResponse: \n");
+ sb.append(certId);
+ sb.append("\nCertStatus: "+ certStatus + "\n");
+ if (certStatus == CertStatus.REVOKED) {
+ sb.append("revocationTime is " + revocationTime + "\n");
+ sb.append("revocationReason is " + revocationReason + "\n");
+ }
+ sb.append("thisUpdate is " + thisUpdate + "\n");
+ if (nextUpdate != null) {
+ sb.append("nextUpdate is " + nextUpdate + "\n");
+ }
+ return sb.toString();
+ }
+ }
+}
diff --git a/ojluni/src/main/java/sun/security/provider/certpath/PKIX.java b/ojluni/src/main/java/sun/security/provider/certpath/PKIX.java
new file mode 100644
index 0000000..98c8834
--- /dev/null
+++ b/ojluni/src/main/java/sun/security/provider/certpath/PKIX.java
@@ -0,0 +1,314 @@
+/*
+ * Copyright (c) 2012, 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.KeyStore;
+import java.security.PublicKey;
+import java.security.cert.*;
+import java.security.interfaces.DSAPublicKey;
+import java.util.*;
+import javax.security.auth.x500.X500Principal;
+
+import sun.security.util.Debug;
+
+/**
+ * Common utility methods and classes used by the PKIX CertPathValidator and
+ * CertPathBuilder implementation.
+ */
+class PKIX {
+
+ private static final Debug debug = Debug.getInstance("certpath");
+
+ private PKIX() { }
+
+ static boolean isDSAPublicKeyWithoutParams(PublicKey publicKey) {
+ return (publicKey instanceof DSAPublicKey &&
+ ((DSAPublicKey)publicKey).getParams() == null);
+ }
+
+ static ValidatorParams checkParams(CertPath cp, CertPathParameters params)
+ throws InvalidAlgorithmParameterException
+ {
+ if (!(params instanceof PKIXParameters)) {
+ throw new InvalidAlgorithmParameterException("inappropriate "
+ + "params, must be an instance of PKIXParameters");
+ }
+ return new ValidatorParams(cp, (PKIXParameters)params);
+ }
+
+ static BuilderParams checkBuilderParams(CertPathParameters params)
+ throws InvalidAlgorithmParameterException
+ {
+ if (!(params instanceof PKIXBuilderParameters)) {
+ throw new InvalidAlgorithmParameterException("inappropriate "
+ + "params, must be an instance of PKIXBuilderParameters");
+ }
+ return new BuilderParams((PKIXBuilderParameters)params);
+ }
+
+ /**
+ * PKIXParameters that are shared by the PKIX CertPathValidator
+ * implementation. Provides additional functionality and avoids
+ * unnecessary cloning.
+ */
+ static class ValidatorParams {
+ private final PKIXParameters params;
+ private CertPath certPath;
+ private List<PKIXCertPathChecker> checkers;
+ private List<CertStore> stores;
+ private boolean gotDate;
+ private Date date;
+ private Set<String> policies;
+ private boolean gotConstraints;
+ private CertSelector constraints;
+ private Set<TrustAnchor> anchors;
+ private List<X509Certificate> certs;
+
+ ValidatorParams(CertPath cp, PKIXParameters params)
+ throws InvalidAlgorithmParameterException
+ {
+ this(params);
+ if (!cp.getType().equals("X.509") && !cp.getType().equals("X509")) {
+ throw new InvalidAlgorithmParameterException("inappropriate "
+ + "CertPath type specified, must be X.509 or X509");
+ }
+ this.certPath = cp;
+ }
+
+ ValidatorParams(PKIXParameters params)
+ throws InvalidAlgorithmParameterException
+ {
+ this.anchors = params.getTrustAnchors();
+ // Make sure that none of the trust anchors include name constraints
+ // (not supported).
+ for (TrustAnchor anchor : this.anchors) {
+ if (anchor.getNameConstraints() != null) {
+ throw new InvalidAlgorithmParameterException
+ ("name constraints in trust anchor not supported");
+ }
+ }
+ this.params = params;
+ }
+
+ CertPath certPath() {
+ return certPath;
+ }
+ // called by CertPathBuilder after path has been built
+ void setCertPath(CertPath cp) {
+ this.certPath = cp;
+ }
+ List<X509Certificate> certificates() {
+ if (certs == null) {
+ if (certPath == null) {
+ certs = Collections.emptyList();
+ } else {
+ // Reverse the ordering for validation so that the target
+ // cert is the last certificate
+ @SuppressWarnings("unchecked")
+ List<X509Certificate> xc = new ArrayList<>
+ ((List<X509Certificate>)certPath.getCertificates());
+ Collections.reverse(xc);
+ certs = xc;
+ }
+ }
+ return certs;
+ }
+ List<PKIXCertPathChecker> certPathCheckers() {
+ if (checkers == null)
+ checkers = params.getCertPathCheckers();
+ return checkers;
+ }
+ List<CertStore> certStores() {
+ if (stores == null)
+ stores = params.getCertStores();
+ return stores;
+ }
+ Date date() {
+ if (!gotDate) {
+ date = params.getDate();
+ if (date == null)
+ date = new Date();
+ gotDate = true;
+ }
+ return date;
+ }
+ Set<String> initialPolicies() {
+ if (policies == null)
+ policies = params.getInitialPolicies();
+ return policies;
+ }
+ CertSelector targetCertConstraints() {
+ if (!gotConstraints) {
+ constraints = params.getTargetCertConstraints();
+ gotConstraints = true;
+ }
+ return constraints;
+ }
+ Set<TrustAnchor> trustAnchors() {
+ return anchors;
+ }
+ boolean revocationEnabled() {
+ return params.isRevocationEnabled();
+ }
+ boolean policyMappingInhibited() {
+ return params.isPolicyMappingInhibited();
+ }
+ boolean explicitPolicyRequired() {
+ return params.isExplicitPolicyRequired();
+ }
+ boolean policyQualifiersRejected() {
+ return params.getPolicyQualifiersRejected();
+ }
+ String sigProvider() { return params.getSigProvider(); }
+ boolean anyPolicyInhibited() { return params.isAnyPolicyInhibited(); }
+
+ // in rare cases we need access to the original params, for example
+ // in order to clone CertPathCheckers before building a new chain
+ PKIXParameters getPKIXParameters() {
+ return params;
+ }
+ }
+
+ static class BuilderParams extends ValidatorParams {
+ private PKIXBuilderParameters params;
+ private boolean buildForward = true;
+ private List<CertStore> stores;
+ private X500Principal targetSubject;
+
+ BuilderParams(PKIXBuilderParameters params)
+ throws InvalidAlgorithmParameterException
+ {
+ super(params);
+ checkParams(params);
+ }
+ private void checkParams(PKIXBuilderParameters params)
+ throws InvalidAlgorithmParameterException
+ {
+ CertSelector sel = targetCertConstraints();
+ if (!(sel instanceof X509CertSelector)) {
+ throw new InvalidAlgorithmParameterException("the "
+ + "targetCertConstraints parameter must be an "
+ + "X509CertSelector");
+ }
+ if (params instanceof SunCertPathBuilderParameters) {
+ buildForward =
+ ((SunCertPathBuilderParameters)params).getBuildForward();
+ }
+ this.params = params;
+ this.targetSubject = getTargetSubject(
+ certStores(), (X509CertSelector)targetCertConstraints());
+ }
+ @Override List<CertStore> certStores() {
+ if (stores == null) {
+ // reorder CertStores so that local CertStores are tried first
+ stores = new ArrayList<>(params.getCertStores());
+ Collections.sort(stores, new CertStoreComparator());
+ }
+ return stores;
+ }
+ int maxPathLength() { return params.getMaxPathLength(); }
+ boolean buildForward() { return buildForward; }
+ PKIXBuilderParameters params() { return params; }
+ X500Principal targetSubject() { return targetSubject; }
+
+ /**
+ * Returns the target subject DN from the first X509Certificate that
+ * is fetched that matches the specified X509CertSelector.
+ */
+ private static X500Principal getTargetSubject(List<CertStore> stores,
+ X509CertSelector sel)
+ throws InvalidAlgorithmParameterException
+ {
+ X500Principal subject = sel.getSubject();
+ if (subject != null) {
+ return subject;
+ }
+ X509Certificate cert = sel.getCertificate();
+ if (cert != null) {
+ subject = cert.getSubjectX500Principal();
+ }
+ if (subject != null) {
+ return subject;
+ }
+ for (CertStore store : stores) {
+ try {
+ Collection<? extends Certificate> certs =
+ (Collection<? extends Certificate>)
+ store.getCertificates(sel);
+ if (!certs.isEmpty()) {
+ X509Certificate xc =
+ (X509Certificate)certs.iterator().next();
+ return xc.getSubjectX500Principal();
+ }
+ } catch (CertStoreException e) {
+ // ignore but log it
+ if (debug != null) {
+ debug.println("BuilderParams.getTargetSubjectDN: " +
+ "non-fatal exception retrieving certs: " + e);
+ e.printStackTrace();
+ }
+ }
+ }
+ throw new InvalidAlgorithmParameterException
+ ("Could not determine unique target subject");
+ }
+ }
+
+ /**
+ * A CertStoreException with additional information about the type of
+ * CertStore that generated the exception.
+ */
+ static class CertStoreTypeException extends CertStoreException {
+ private static final long serialVersionUID = 7463352639238322556L;
+
+ private final String type;
+
+ CertStoreTypeException(String type, CertStoreException cse) {
+ super(cse.getMessage(), cse.getCause());
+ this.type = type;
+ }
+ String getType() {
+ return type;
+ }
+ }
+
+ /**
+ * Comparator that orders CertStores so that local CertStores come before
+ * remote CertStores.
+ */
+ private static class CertStoreComparator implements Comparator<CertStore> {
+ @Override
+ public int compare(CertStore store1, CertStore store2) {
+ if (store1.getType().equals("Collection") ||
+ store1.getCertStoreParameters() instanceof
+ CollectionCertStoreParameters) {
+ return -1;
+ } else {
+ return 1;
+ }
+ }
+ }
+}
diff --git a/ojluni/src/main/java/sun/security/provider/certpath/PKIXCertPathValidator.java b/ojluni/src/main/java/sun/security/provider/certpath/PKIXCertPathValidator.java
new file mode 100644
index 0000000..728bc19
--- /dev/null
+++ b/ojluni/src/main/java/sun/security/provider/certpath/PKIXCertPathValidator.java
@@ -0,0 +1,222 @@
+/*
+ * Copyright (c) 2000, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * 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.io.IOException;
+import java.security.InvalidAlgorithmParameterException;
+import java.security.cert.*;
+import java.util.*;
+
+import sun.security.provider.certpath.PKIX.ValidatorParams;
+import sun.security.x509.X509CertImpl;
+import sun.security.util.Debug;
+
+/**
+ * This class implements the PKIX validation algorithm for certification
+ * paths consisting exclusively of <code>X509Certificates</code>. It uses
+ * the specified input parameter set (which must be a
+ * <code>PKIXParameters</code> object).
+ *
+ * @since 1.4
+ * @author Yassir Elley
+ */
+public final class PKIXCertPathValidator extends CertPathValidatorSpi {
+
+ private static final Debug debug = Debug.getInstance("certpath");
+
+ /**
+ * Default constructor.
+ */
+ public PKIXCertPathValidator() {}
+
+ @Override
+ public CertPathChecker engineGetRevocationChecker() {
+ return new RevocationChecker();
+ }
+
+ /**
+ * Validates a certification path consisting exclusively of
+ * <code>X509Certificate</code>s using the PKIX validation algorithm,
+ * which uses the specified input parameter set.
+ * The input parameter set must be a <code>PKIXParameters</code> object.
+ *
+ * @param cp the X509 certification path
+ * @param params the input PKIX parameter set
+ * @return the result
+ * @throws CertPathValidatorException if cert path does not validate.
+ * @throws InvalidAlgorithmParameterException if the specified
+ * parameters are inappropriate for this CertPathValidator
+ */
+ @Override
+ public CertPathValidatorResult engineValidate(CertPath cp,
+ CertPathParameters params)
+ throws CertPathValidatorException, InvalidAlgorithmParameterException
+ {
+ ValidatorParams valParams = PKIX.checkParams(cp, params);
+ return validate(valParams);
+ }
+
+ private static PKIXCertPathValidatorResult validate(ValidatorParams params)
+ throws CertPathValidatorException
+ {
+ if (debug != null)
+ debug.println("PKIXCertPathValidator.engineValidate()...");
+
+ // Retrieve the first certificate in the certpath
+ // (to be used later in pre-screening)
+ AdaptableX509CertSelector selector = null;
+ List<X509Certificate> certList = params.certificates();
+ if (!certList.isEmpty()) {
+ selector = new AdaptableX509CertSelector();
+ X509Certificate firstCert = certList.get(0);
+ // check trusted certificate's subject
+ selector.setSubject(firstCert.getIssuerX500Principal());
+ // check the validity period
+ selector.setValidityPeriod(firstCert.getNotBefore(),
+ firstCert.getNotAfter());
+ /*
+ * Facilitate certification path construction with authority
+ * key identifier and subject key identifier.
+ */
+ try {
+ X509CertImpl firstCertImpl = X509CertImpl.toImpl(firstCert);
+ selector.parseAuthorityKeyIdentifierExtension(
+ firstCertImpl.getAuthorityKeyIdentifierExtension());
+ } catch (CertificateException | IOException e) {
+ // ignore
+ }
+ }
+
+ CertPathValidatorException lastException = null;
+
+ // We iterate through the set of trust anchors until we find
+ // one that works at which time we stop iterating
+ for (TrustAnchor anchor : params.trustAnchors()) {
+ X509Certificate trustedCert = anchor.getTrustedCert();
+ if (trustedCert != null) {
+ // if this trust anchor is not worth trying,
+ // we move on to the next one
+ if (selector != null && !selector.match(trustedCert)) {
+ if (debug != null) {
+ debug.println("NO - don't try this trustedCert");
+ }
+ continue;
+ }
+
+ if (debug != null) {
+ debug.println("YES - try this trustedCert");
+ debug.println("anchor.getTrustedCert()."
+ + "getSubjectX500Principal() = "
+ + trustedCert.getSubjectX500Principal());
+ }
+ } else {
+ if (debug != null) {
+ debug.println("PKIXCertPathValidator.engineValidate(): "
+ + "anchor.getTrustedCert() == null");
+ }
+ }
+
+ try {
+ return validate(anchor, params);
+ } catch (CertPathValidatorException cpe) {
+ // remember this exception
+ lastException = cpe;
+ }
+ }
+
+ // could not find a trust anchor that verified
+ // (a) if we did a validation and it failed, use that exception
+ if (lastException != null) {
+ throw lastException;
+ }
+ // (b) otherwise, generate new exception
+ throw new CertPathValidatorException
+ ("Path does not chain with any of the trust anchors",
+ null, null, -1, PKIXReason.NO_TRUST_ANCHOR);
+ }
+
+ private static PKIXCertPathValidatorResult validate(TrustAnchor anchor,
+ ValidatorParams params)
+ throws CertPathValidatorException
+ {
+ int certPathLen = params.certificates().size();
+
+ // create PKIXCertPathCheckers
+ List<PKIXCertPathChecker> certPathCheckers = new ArrayList<>();
+ // add standard checkers that we will be using
+ certPathCheckers.add(new UntrustedChecker());
+ certPathCheckers.add(new AlgorithmChecker(anchor));
+ certPathCheckers.add(new KeyChecker(certPathLen,
+ params.targetCertConstraints()));
+ certPathCheckers.add(new ConstraintsChecker(certPathLen));
+ PolicyNodeImpl rootNode =
+ new PolicyNodeImpl(null, PolicyChecker.ANY_POLICY, null, false,
+ Collections.singleton(PolicyChecker.ANY_POLICY),
+ false);
+ PolicyChecker pc = new PolicyChecker(params.initialPolicies(),
+ certPathLen,
+ params.explicitPolicyRequired(),
+ params.policyMappingInhibited(),
+ params.anyPolicyInhibited(),
+ params.policyQualifiersRejected(),
+ rootNode);
+ certPathCheckers.add(pc);
+ // default value for date is current time
+ BasicChecker bc = new BasicChecker(anchor, params.date(),
+ params.sigProvider(), false);
+ certPathCheckers.add(bc);
+
+ boolean revCheckerAdded = false;
+ List<PKIXCertPathChecker> checkers = params.certPathCheckers();
+ for (PKIXCertPathChecker checker : checkers) {
+ if (checker instanceof PKIXRevocationChecker) {
+ if (revCheckerAdded) {
+ throw new CertPathValidatorException(
+ "Only one PKIXRevocationChecker can be specified");
+ }
+ revCheckerAdded = true;
+ // if it's our own, initialize it
+ if (checker instanceof RevocationChecker) {
+ ((RevocationChecker)checker).init(anchor, params);
+ }
+ }
+ }
+ // only add a RevocationChecker if revocation is enabled and
+ // a PKIXRevocationChecker has not already been added
+ if (params.revocationEnabled() && !revCheckerAdded) {
+ certPathCheckers.add(new RevocationChecker(anchor, params));
+ }
+ // add user-specified checkers
+ certPathCheckers.addAll(checkers);
+
+ PKIXMasterCertPathValidator.validate(params.certPath(),
+ params.certificates(),
+ certPathCheckers);
+
+ return new PKIXCertPathValidatorResult(anchor, pc.getPolicyTree(),
+ bc.getPublicKey());
+ }
+}
diff --git a/ojluni/src/main/java/sun/security/provider/certpath/PKIXMasterCertPathValidator.java b/ojluni/src/main/java/sun/security/provider/certpath/PKIXMasterCertPathValidator.java
new file mode 100644
index 0000000..db5edda
--- /dev/null
+++ b/ojluni/src/main/java/sun/security/provider/certpath/PKIXMasterCertPathValidator.java
@@ -0,0 +1,150 @@
+/*
+ * Copyright (c) 2000, 2012, 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 sun.security.util.Debug;
+
+import java.util.Collections;
+import java.util.List;
+import java.util.Set;
+import java.security.cert.CertPath;
+import java.security.cert.CertPathValidatorException;
+import java.security.cert.PKIXCertPathChecker;
+import java.security.cert.PKIXReason;
+import java.security.cert.X509Certificate;
+
+/**
+ * This class is initialized with a list of <code>PKIXCertPathChecker</code>s
+ * and is used to verify the certificates in a <code>CertPath</code> by
+ * feeding each certificate to each <code>PKIXCertPathChecker</code>.
+ *
+ * @since 1.4
+ * @author Yassir Elley
+ */
+class PKIXMasterCertPathValidator {
+
+ private static final Debug debug = Debug.getInstance("certpath");
+
+ /**
+ * Validates a certification path consisting exclusively of
+ * <code>X509Certificate</code>s using the specified
+ * <code>PKIXCertPathChecker</code>s. It is assumed that the
+ * <code>PKIXCertPathChecker</code>s
+ * have been initialized with any input parameters they may need.
+ *
+ * @param cpOriginal the original X509 CertPath passed in by the user
+ * @param reversedCertList the reversed X509 CertPath (as a List)
+ * @param certPathCheckers the PKIXCertPathCheckers
+ * @throws CertPathValidatorException if cert path does not validate
+ */
+ static void validate(CertPath cpOriginal,
+ List<X509Certificate> reversedCertList,
+ List<PKIXCertPathChecker> certPathCheckers)
+ throws CertPathValidatorException
+ {
+ // we actually process reversedCertList, but we keep cpOriginal because
+ // we need to return the original certPath when we throw an exception.
+ // we will also need to modify the index appropriately when we
+ // throw an exception.
+
+ int cpSize = reversedCertList.size();
+
+ if (debug != null) {
+ debug.println("--------------------------------------------------"
+ + "------------");
+ debug.println("Executing PKIX certification path validation "
+ + "algorithm.");
+ }
+
+ for (int i = 0; i < cpSize; i++) {
+
+ /* The basic loop algorithm is that we get the
+ * current certificate, we verify the current certificate using
+ * information from the previous certificate and from the state,
+ * and we modify the state for the next loop by setting the
+ * current certificate of this loop to be the previous certificate
+ * of the next loop. The state is initialized during first loop.
+ */
+ if (debug != null)
+ debug.println("Checking cert" + (i+1) + " ...");
+
+ X509Certificate currCert = reversedCertList.get(i);
+ Set<String> unresCritExts = currCert.getCriticalExtensionOIDs();
+ if (unresCritExts == null) {
+ unresCritExts = Collections.<String>emptySet();
+ }
+
+ if (debug != null && !unresCritExts.isEmpty()) {
+ debug.println("Set of critical extensions:");
+ for (String oid : unresCritExts) {
+ debug.println(oid);
+ }
+ }
+
+ for (int j = 0; j < certPathCheckers.size(); j++) {
+
+ PKIXCertPathChecker currChecker = certPathCheckers.get(j);
+ if (debug != null) {
+ debug.println("-Using checker" + (j + 1) + " ... [" +
+ currChecker.getClass().getName() + "]");
+ }
+
+ if (i == 0)
+ currChecker.init(false);
+
+ try {
+ currChecker.check(currCert, unresCritExts);
+
+ if (debug != null) {
+ debug.println("-checker" + (j + 1) +
+ " validation succeeded");
+ }
+
+ } catch (CertPathValidatorException cpve) {
+ throw new CertPathValidatorException(cpve.getMessage(),
+ cpve.getCause(), cpOriginal, cpSize - (i + 1),
+ cpve.getReason());
+ }
+ }
+
+ if (!unresCritExts.isEmpty()) {
+ throw new CertPathValidatorException("unrecognized " +
+ "critical extension(s)", null, cpOriginal, cpSize-(i+1),
+ PKIXReason.UNRECOGNIZED_CRIT_EXT);
+ }
+
+ if (debug != null)
+ debug.println("\ncert" + (i+1) + " validation succeeded.\n");
+ }
+
+ if (debug != null) {
+ debug.println("Cert path validation succeeded. (PKIX validation "
+ + "algorithm)");
+ debug.println("-------------------------------------------------"
+ + "-------------");
+ }
+ }
+}
diff --git a/ojluni/src/main/java/sun/security/provider/certpath/PolicyChecker.java b/ojluni/src/main/java/sun/security/provider/certpath/PolicyChecker.java
new file mode 100644
index 0000000..ab82820
--- /dev/null
+++ b/ojluni/src/main/java/sun/security/provider/certpath/PolicyChecker.java
@@ -0,0 +1,924 @@
+/*
+ * Copyright (c) 2000, 2012, 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.io.IOException;
+import java.security.GeneralSecurityException;
+import java.security.cert.Certificate;
+import java.security.cert.CertificateException;
+import java.security.cert.CertPathValidatorException;
+import java.security.cert.PKIXCertPathChecker;
+import java.security.cert.PKIXReason;
+import java.security.cert.PolicyNode;
+import java.security.cert.PolicyQualifierInfo;
+import java.security.cert.X509Certificate;
+import java.util.*;
+
+import sun.security.util.Debug;
+import sun.security.x509.CertificatePoliciesExtension;
+import sun.security.x509.PolicyConstraintsExtension;
+import sun.security.x509.PolicyMappingsExtension;
+import sun.security.x509.CertificatePolicyMap;
+import static sun.security.x509.PKIXExtensions.*;
+import sun.security.x509.PolicyInformation;
+import sun.security.x509.X509CertImpl;
+import sun.security.x509.InhibitAnyPolicyExtension;
+
+/**
+ * PolicyChecker is a <code>PKIXCertPathChecker</code> that checks policy
+ * information on a PKIX certificate, namely certificate policies, policy
+ * mappings, policy constraints and policy qualifiers.
+ *
+ * @since 1.4
+ * @author Yassir Elley
+ */
+class PolicyChecker extends PKIXCertPathChecker {
+
+ private final Set<String> initPolicies;
+ private final int certPathLen;
+ private final boolean expPolicyRequired;
+ private final boolean polMappingInhibited;
+ private final boolean anyPolicyInhibited;
+ private final boolean rejectPolicyQualifiers;
+ private PolicyNodeImpl rootNode;
+ private int explicitPolicy;
+ private int policyMapping;
+ private int inhibitAnyPolicy;
+ private int certIndex;
+
+ private Set<String> supportedExts;
+
+ private static final Debug debug = Debug.getInstance("certpath");
+ static final String ANY_POLICY = "2.5.29.32.0";
+
+ /**
+ * Constructs a Policy Checker.
+ *
+ * @param initialPolicies Set of initial policies
+ * @param certPathLen length of the certification path to be checked
+ * @param expPolicyRequired true if explicit policy is required
+ * @param polMappingInhibited true if policy mapping is inhibited
+ * @param anyPolicyInhibited true if the ANY_POLICY OID should be inhibited
+ * @param rejectPolicyQualifiers true if pol qualifiers are to be rejected
+ * @param rootNode the initial root node of the valid policy tree
+ */
+ PolicyChecker(Set<String> initialPolicies, int certPathLen,
+ boolean expPolicyRequired, boolean polMappingInhibited,
+ boolean anyPolicyInhibited, boolean rejectPolicyQualifiers,
+ PolicyNodeImpl rootNode)
+ {
+ if (initialPolicies.isEmpty()) {
+ // if no initialPolicies are specified by user, set
+ // initPolicies to be anyPolicy by default
+ this.initPolicies = new HashSet<String>(1);
+ this.initPolicies.add(ANY_POLICY);
+ } else {
+ this.initPolicies = new HashSet<String>(initialPolicies);
+ }
+ this.certPathLen = certPathLen;
+ this.expPolicyRequired = expPolicyRequired;
+ this.polMappingInhibited = polMappingInhibited;
+ this.anyPolicyInhibited = anyPolicyInhibited;
+ this.rejectPolicyQualifiers = rejectPolicyQualifiers;
+ this.rootNode = rootNode;
+ }
+
+ /**
+ * Initializes the internal state of the checker from parameters
+ * specified in the constructor
+ *
+ * @param forward a boolean indicating whether this checker should be
+ * initialized capable of building in the forward direction
+ * @throws CertPathValidatorException if user wants to enable forward
+ * checking and forward checking is not supported.
+ */
+ @Override
+ public void init(boolean forward) throws CertPathValidatorException {
+ if (forward) {
+ throw new CertPathValidatorException
+ ("forward checking not supported");
+ }
+
+ certIndex = 1;
+ explicitPolicy = (expPolicyRequired ? 0 : certPathLen + 1);
+ policyMapping = (polMappingInhibited ? 0 : certPathLen + 1);
+ inhibitAnyPolicy = (anyPolicyInhibited ? 0 : certPathLen + 1);
+ }
+
+ /**
+ * Checks if forward checking is supported. Forward checking refers
+ * to the ability of the PKIXCertPathChecker to perform its checks
+ * when presented with certificates in the forward direction (from
+ * target to anchor).
+ *
+ * @return true if forward checking is supported, false otherwise
+ */
+ @Override
+ public boolean isForwardCheckingSupported() {
+ return false;
+ }
+
+ /**
+ * Gets an immutable Set of the OID strings for the extensions that
+ * the PKIXCertPathChecker supports (i.e. recognizes, is able to
+ * process), or null if no extensions are
+ * supported. All OID strings that a PKIXCertPathChecker might
+ * possibly be able to process should be included.
+ *
+ * @return the Set of extensions supported by this PKIXCertPathChecker,
+ * or null if no extensions are supported
+ */
+ @Override
+ public Set<String> getSupportedExtensions() {
+ if (supportedExts == null) {
+ supportedExts = new HashSet<String>(4);
+ supportedExts.add(CertificatePolicies_Id.toString());
+ supportedExts.add(PolicyMappings_Id.toString());
+ supportedExts.add(PolicyConstraints_Id.toString());
+ supportedExts.add(InhibitAnyPolicy_Id.toString());
+ supportedExts = Collections.unmodifiableSet(supportedExts);
+ }
+ return supportedExts;
+ }
+
+ /**
+ * Performs the policy processing checks on the certificate using its
+ * internal state.
+ *
+ * @param cert the Certificate to be processed
+ * @param unresCritExts the unresolved critical extensions
+ * @throws CertPathValidatorException if the certificate does not verify
+ */
+ @Override
+ public void check(Certificate cert, Collection<String> unresCritExts)
+ throws CertPathValidatorException
+ {
+ // now do the policy checks
+ checkPolicy((X509Certificate) cert);
+
+ if (unresCritExts != null && !unresCritExts.isEmpty()) {
+ unresCritExts.remove(CertificatePolicies_Id.toString());
+ unresCritExts.remove(PolicyMappings_Id.toString());
+ unresCritExts.remove(PolicyConstraints_Id.toString());
+ unresCritExts.remove(InhibitAnyPolicy_Id.toString());
+ }
+ }
+
+ /**
+ * Internal method to run through all the checks.
+ *
+ * @param currCert the certificate to be processed
+ * @exception CertPathValidatorException Exception thrown if
+ * the certificate does not verify
+ */
+ private void checkPolicy(X509Certificate currCert)
+ throws CertPathValidatorException
+ {
+ String msg = "certificate policies";
+ if (debug != null) {
+ debug.println("PolicyChecker.checkPolicy() ---checking " + msg
+ + "...");
+ debug.println("PolicyChecker.checkPolicy() certIndex = "
+ + certIndex);
+ debug.println("PolicyChecker.checkPolicy() BEFORE PROCESSING: "
+ + "explicitPolicy = " + explicitPolicy);
+ debug.println("PolicyChecker.checkPolicy() BEFORE PROCESSING: "
+ + "policyMapping = " + policyMapping);
+ debug.println("PolicyChecker.checkPolicy() BEFORE PROCESSING: "
+ + "inhibitAnyPolicy = " + inhibitAnyPolicy);
+ debug.println("PolicyChecker.checkPolicy() BEFORE PROCESSING: "
+ + "policyTree = " + rootNode);
+ }
+
+ X509CertImpl currCertImpl = null;
+ try {
+ currCertImpl = X509CertImpl.toImpl(currCert);
+ } catch (CertificateException ce) {
+ throw new CertPathValidatorException(ce);
+ }
+
+ boolean finalCert = (certIndex == certPathLen);
+
+ rootNode = processPolicies(certIndex, initPolicies, explicitPolicy,
+ policyMapping, inhibitAnyPolicy, rejectPolicyQualifiers, rootNode,
+ currCertImpl, finalCert);
+
+ if (!finalCert) {
+ explicitPolicy = mergeExplicitPolicy(explicitPolicy, currCertImpl,
+ finalCert);
+ policyMapping = mergePolicyMapping(policyMapping, currCertImpl);
+ inhibitAnyPolicy = mergeInhibitAnyPolicy(inhibitAnyPolicy,
+ currCertImpl);
+ }
+
+ certIndex++;
+
+ if (debug != null) {
+ debug.println("PolicyChecker.checkPolicy() AFTER PROCESSING: "
+ + "explicitPolicy = " + explicitPolicy);
+ debug.println("PolicyChecker.checkPolicy() AFTER PROCESSING: "
+ + "policyMapping = " + policyMapping);
+ debug.println("PolicyChecker.checkPolicy() AFTER PROCESSING: "
+ + "inhibitAnyPolicy = " + inhibitAnyPolicy);
+ debug.println("PolicyChecker.checkPolicy() AFTER PROCESSING: "
+ + "policyTree = " + rootNode);
+ debug.println("PolicyChecker.checkPolicy() " + msg + " verified");
+ }
+ }
+
+ /**
+ * Merges the specified explicitPolicy value with the
+ * requireExplicitPolicy field of the <code>PolicyConstraints</code>
+ * extension obtained from the certificate. An explicitPolicy
+ * value of -1 implies no constraint.
+ *
+ * @param explicitPolicy an integer which indicates if a non-null
+ * valid policy tree is required
+ * @param currCert the Certificate to be processed
+ * @param finalCert a boolean indicating whether currCert is
+ * the final cert in the cert path
+ * @return returns the new explicitPolicy value
+ * @exception CertPathValidatorException Exception thrown if an error
+ * occurs
+ */
+ static int mergeExplicitPolicy(int explicitPolicy, X509CertImpl currCert,
+ boolean finalCert) throws CertPathValidatorException
+ {
+ if ((explicitPolicy > 0) && !X509CertImpl.isSelfIssued(currCert)) {
+ explicitPolicy--;
+ }
+
+ try {
+ PolicyConstraintsExtension polConstExt
+ = currCert.getPolicyConstraintsExtension();
+ if (polConstExt == null)
+ return explicitPolicy;
+ int require =
+ polConstExt.get(PolicyConstraintsExtension.REQUIRE).intValue();
+ if (debug != null) {
+ debug.println("PolicyChecker.mergeExplicitPolicy() "
+ + "require Index from cert = " + require);
+ }
+ if (!finalCert) {
+ if (require != -1) {
+ if ((explicitPolicy == -1) || (require < explicitPolicy)) {
+ explicitPolicy = require;
+ }
+ }
+ } else {
+ if (require == 0)
+ explicitPolicy = require;
+ }
+ } catch (IOException e) {
+ if (debug != null) {
+ debug.println("PolicyChecker.mergeExplicitPolicy "
+ + "unexpected exception");
+ e.printStackTrace();
+ }
+ throw new CertPathValidatorException(e);
+ }
+
+ return explicitPolicy;
+ }
+
+ /**
+ * Merges the specified policyMapping value with the
+ * inhibitPolicyMapping field of the <code>PolicyConstraints</code>
+ * extension obtained from the certificate. A policyMapping
+ * value of -1 implies no constraint.
+ *
+ * @param policyMapping an integer which indicates if policy mapping
+ * is inhibited
+ * @param currCert the Certificate to be processed
+ * @return returns the new policyMapping value
+ * @exception CertPathValidatorException Exception thrown if an error
+ * occurs
+ */
+ static int mergePolicyMapping(int policyMapping, X509CertImpl currCert)
+ throws CertPathValidatorException
+ {
+ if ((policyMapping > 0) && !X509CertImpl.isSelfIssued(currCert)) {
+ policyMapping--;
+ }
+
+ try {
+ PolicyConstraintsExtension polConstExt
+ = currCert.getPolicyConstraintsExtension();
+ if (polConstExt == null)
+ return policyMapping;
+
+ int inhibit =
+ polConstExt.get(PolicyConstraintsExtension.INHIBIT).intValue();
+ if (debug != null)
+ debug.println("PolicyChecker.mergePolicyMapping() "
+ + "inhibit Index from cert = " + inhibit);
+
+ if (inhibit != -1) {
+ if ((policyMapping == -1) || (inhibit < policyMapping)) {
+ policyMapping = inhibit;
+ }
+ }
+ } catch (IOException e) {
+ if (debug != null) {
+ debug.println("PolicyChecker.mergePolicyMapping "
+ + "unexpected exception");
+ e.printStackTrace();
+ }
+ throw new CertPathValidatorException(e);
+ }
+
+ return policyMapping;
+ }
+
+ /**
+ * Merges the specified inhibitAnyPolicy value with the
+ * SkipCerts value of the InhibitAnyPolicy
+ * extension obtained from the certificate.
+ *
+ * @param inhibitAnyPolicy an integer which indicates whether
+ * "any-policy" is considered a match
+ * @param currCert the Certificate to be processed
+ * @return returns the new inhibitAnyPolicy value
+ * @exception CertPathValidatorException Exception thrown if an error
+ * occurs
+ */
+ static int mergeInhibitAnyPolicy(int inhibitAnyPolicy,
+ X509CertImpl currCert) throws CertPathValidatorException
+ {
+ if ((inhibitAnyPolicy > 0) && !X509CertImpl.isSelfIssued(currCert)) {
+ inhibitAnyPolicy--;
+ }
+
+ try {
+ InhibitAnyPolicyExtension inhAnyPolExt = (InhibitAnyPolicyExtension)
+ currCert.getExtension(InhibitAnyPolicy_Id);
+ if (inhAnyPolExt == null)
+ return inhibitAnyPolicy;
+
+ int skipCerts =
+ inhAnyPolExt.get(InhibitAnyPolicyExtension.SKIP_CERTS).intValue();
+ if (debug != null)
+ debug.println("PolicyChecker.mergeInhibitAnyPolicy() "
+ + "skipCerts Index from cert = " + skipCerts);
+
+ if (skipCerts != -1) {
+ if (skipCerts < inhibitAnyPolicy) {
+ inhibitAnyPolicy = skipCerts;
+ }
+ }
+ } catch (IOException e) {
+ if (debug != null) {
+ debug.println("PolicyChecker.mergeInhibitAnyPolicy "
+ + "unexpected exception");
+ e.printStackTrace();
+ }
+ throw new CertPathValidatorException(e);
+ }
+
+ return inhibitAnyPolicy;
+ }
+
+ /**
+ * Processes certificate policies in the certificate.
+ *
+ * @param certIndex the index of the certificate
+ * @param initPolicies the initial policies required by the user
+ * @param explicitPolicy an integer which indicates if a non-null
+ * valid policy tree is required
+ * @param policyMapping an integer which indicates if policy
+ * mapping is inhibited
+ * @param inhibitAnyPolicy an integer which indicates whether
+ * "any-policy" is considered a match
+ * @param rejectPolicyQualifiers a boolean indicating whether the
+ * user wants to reject policies that have qualifiers
+ * @param origRootNode the root node of the valid policy tree
+ * @param currCert the Certificate to be processed
+ * @param finalCert a boolean indicating whether currCert is the final
+ * cert in the cert path
+ * @return the root node of the valid policy tree after modification
+ * @exception CertPathValidatorException Exception thrown if an
+ * error occurs while processing policies.
+ */
+ static PolicyNodeImpl processPolicies(int certIndex, Set<String> initPolicies,
+ int explicitPolicy, int policyMapping, int inhibitAnyPolicy,
+ boolean rejectPolicyQualifiers, PolicyNodeImpl origRootNode,
+ X509CertImpl currCert, boolean finalCert)
+ throws CertPathValidatorException
+ {
+ boolean policiesCritical = false;
+ List<PolicyInformation> policyInfo;
+ PolicyNodeImpl rootNode = null;
+ Set<PolicyQualifierInfo> anyQuals = new HashSet<>();
+
+ if (origRootNode == null)
+ rootNode = null;
+ else
+ rootNode = origRootNode.copyTree();
+
+ // retrieve policyOIDs from currCert
+ CertificatePoliciesExtension currCertPolicies
+ = currCert.getCertificatePoliciesExtension();
+
+ // PKIX: Section 6.1.3: Step (d)
+ if ((currCertPolicies != null) && (rootNode != null)) {
+ policiesCritical = currCertPolicies.isCritical();
+ if (debug != null)
+ debug.println("PolicyChecker.processPolicies() "
+ + "policiesCritical = " + policiesCritical);
+
+ try {
+ policyInfo = currCertPolicies.get(CertificatePoliciesExtension.POLICIES);
+ } catch (IOException ioe) {
+ throw new CertPathValidatorException("Exception while "
+ + "retrieving policyOIDs", ioe);
+ }
+
+ if (debug != null)
+ debug.println("PolicyChecker.processPolicies() "
+ + "rejectPolicyQualifiers = " + rejectPolicyQualifiers);
+
+ boolean foundAnyPolicy = false;
+
+ // process each policy in cert
+ for (PolicyInformation curPolInfo : policyInfo) {
+ String curPolicy =
+ curPolInfo.getPolicyIdentifier().getIdentifier().toString();
+
+ if (curPolicy.equals(ANY_POLICY)) {
+ foundAnyPolicy = true;
+ anyQuals = curPolInfo.getPolicyQualifiers();
+ } else {
+ // PKIX: Section 6.1.3: Step (d)(1)
+ if (debug != null)
+ debug.println("PolicyChecker.processPolicies() "
+ + "processing policy: " + curPolicy);
+
+ // retrieve policy qualifiers from cert
+ Set<PolicyQualifierInfo> pQuals =
+ curPolInfo.getPolicyQualifiers();
+
+ // reject cert if we find critical policy qualifiers and
+ // the policyQualifiersRejected flag is set in the params
+ if (!pQuals.isEmpty() && rejectPolicyQualifiers &&
+ policiesCritical) {
+ throw new CertPathValidatorException(
+ "critical policy qualifiers present in certificate",
+ null, null, -1, PKIXReason.INVALID_POLICY);
+ }
+
+ // PKIX: Section 6.1.3: Step (d)(1)(i)
+ boolean foundMatch = processParents(certIndex,
+ policiesCritical, rejectPolicyQualifiers, rootNode,
+ curPolicy, pQuals, false);
+
+ if (!foundMatch) {
+ // PKIX: Section 6.1.3: Step (d)(1)(ii)
+ processParents(certIndex, policiesCritical,
+ rejectPolicyQualifiers, rootNode, curPolicy,
+ pQuals, true);
+ }
+ }
+ }
+
+ // PKIX: Section 6.1.3: Step (d)(2)
+ if (foundAnyPolicy) {
+ if ((inhibitAnyPolicy > 0) ||
+ (!finalCert && X509CertImpl.isSelfIssued(currCert))) {
+ if (debug != null) {
+ debug.println("PolicyChecker.processPolicies() "
+ + "processing policy: " + ANY_POLICY);
+ }
+ processParents(certIndex, policiesCritical,
+ rejectPolicyQualifiers, rootNode, ANY_POLICY, anyQuals,
+ true);
+ }
+ }
+
+ // PKIX: Section 6.1.3: Step (d)(3)
+ rootNode.prune(certIndex);
+ if (!rootNode.getChildren().hasNext()) {
+ rootNode = null;
+ }
+ } else if (currCertPolicies == null) {
+ if (debug != null)
+ debug.println("PolicyChecker.processPolicies() "
+ + "no policies present in cert");
+ // PKIX: Section 6.1.3: Step (e)
+ rootNode = null;
+ }
+
+ // We delay PKIX: Section 6.1.3: Step (f) to the end
+ // because the code that follows may delete some nodes
+ // resulting in a null tree
+ if (rootNode != null) {
+ if (!finalCert) {
+ // PKIX: Section 6.1.4: Steps (a)-(b)
+ rootNode = processPolicyMappings(currCert, certIndex,
+ policyMapping, rootNode, policiesCritical, anyQuals);
+ }
+ }
+
+ // At this point, we optimize the PKIX algorithm by
+ // removing those nodes which would later have
+ // been removed by PKIX: Section 6.1.5: Step (g)(iii)
+
+ if ((rootNode != null) && (!initPolicies.contains(ANY_POLICY))
+ && (currCertPolicies != null)) {
+ rootNode = removeInvalidNodes(rootNode, certIndex,
+ initPolicies, currCertPolicies);
+
+ // PKIX: Section 6.1.5: Step (g)(iii)
+ if ((rootNode != null) && finalCert) {
+ // rewrite anyPolicy leaf nodes (see method comments)
+ rootNode = rewriteLeafNodes(certIndex, initPolicies, rootNode);
+ }
+ }
+
+
+ if (finalCert) {
+ // PKIX: Section 6.1.5: Steps (a) and (b)
+ explicitPolicy = mergeExplicitPolicy(explicitPolicy, currCert,
+ finalCert);
+ }
+
+ // PKIX: Section 6.1.3: Step (f)
+ // verify that either explicit policy is greater than 0 or
+ // the valid_policy_tree is not equal to NULL
+
+ if ((explicitPolicy == 0) && (rootNode == null)) {
+ throw new CertPathValidatorException
+ ("non-null policy tree required and policy tree is null",
+ null, null, -1, PKIXReason.INVALID_POLICY);
+ }
+
+ return rootNode;
+ }
+
+ /**
+ * Rewrite leaf nodes at the end of validation as described in RFC 3280
+ * section 6.1.5: Step (g)(iii). Leaf nodes with anyPolicy are replaced
+ * by nodes explicitly representing initial policies not already
+ * represented by leaf nodes.
+ *
+ * This method should only be called when processing the final cert
+ * and if the policy tree is not null and initial policies is not
+ * anyPolicy.
+ *
+ * @param certIndex the depth of the tree
+ * @param initPolicies Set of user specified initial policies
+ * @param rootNode the root of the policy tree
+ */
+ private static PolicyNodeImpl rewriteLeafNodes(int certIndex,
+ Set<String> initPolicies, PolicyNodeImpl rootNode) {
+ Set<PolicyNodeImpl> anyNodes =
+ rootNode.getPolicyNodesValid(certIndex, ANY_POLICY);
+ if (anyNodes.isEmpty()) {
+ return rootNode;
+ }
+ PolicyNodeImpl anyNode = anyNodes.iterator().next();
+ PolicyNodeImpl parentNode = (PolicyNodeImpl)anyNode.getParent();
+ parentNode.deleteChild(anyNode);
+ // see if there are any initialPolicies not represented by leaf nodes
+ Set<String> initial = new HashSet<>(initPolicies);
+ for (PolicyNodeImpl node : rootNode.getPolicyNodes(certIndex)) {
+ initial.remove(node.getValidPolicy());
+ }
+ if (initial.isEmpty()) {
+ // we deleted the anyPolicy node and have nothing to re-add,
+ // so we need to prune the tree
+ rootNode.prune(certIndex);
+ if (rootNode.getChildren().hasNext() == false) {
+ rootNode = null;
+ }
+ } else {
+ boolean anyCritical = anyNode.isCritical();
+ Set<PolicyQualifierInfo> anyQualifiers =
+ anyNode.getPolicyQualifiers();
+ for (String policy : initial) {
+ Set<String> expectedPolicies = Collections.singleton(policy);
+ PolicyNodeImpl node = new PolicyNodeImpl(parentNode, policy,
+ anyQualifiers, anyCritical, expectedPolicies, false);
+ }
+ }
+ return rootNode;
+ }
+
+ /**
+ * Finds the policy nodes of depth (certIndex-1) where curPolicy
+ * is in the expected policy set and creates a new child node
+ * appropriately. If matchAny is true, then a value of ANY_POLICY
+ * in the expected policy set will match any curPolicy. If matchAny
+ * is false, then the expected policy set must exactly contain the
+ * curPolicy to be considered a match. This method returns a boolean
+ * value indicating whether a match was found.
+ *
+ * @param certIndex the index of the certificate whose policy is
+ * being processed
+ * @param policiesCritical a boolean indicating whether the certificate
+ * policies extension is critical
+ * @param rejectPolicyQualifiers a boolean indicating whether the
+ * user wants to reject policies that have qualifiers
+ * @param rootNode the root node of the valid policy tree
+ * @param curPolicy a String representing the policy being processed
+ * @param pQuals the policy qualifiers of the policy being processed or an
+ * empty Set if there are no qualifiers
+ * @param matchAny a boolean indicating whether a value of ANY_POLICY
+ * in the expected policy set will be considered a match
+ * @return a boolean indicating whether a match was found
+ * @exception CertPathValidatorException Exception thrown if error occurs.
+ */
+ private static boolean processParents(int certIndex,
+ boolean policiesCritical, boolean rejectPolicyQualifiers,
+ PolicyNodeImpl rootNode, String curPolicy,
+ Set<PolicyQualifierInfo> pQuals,
+ boolean matchAny) throws CertPathValidatorException
+ {
+ boolean foundMatch = false;
+
+ if (debug != null)
+ debug.println("PolicyChecker.processParents(): matchAny = "
+ + matchAny);
+
+ // find matching parents
+ Set<PolicyNodeImpl> parentNodes =
+ rootNode.getPolicyNodesExpected(certIndex - 1,
+ curPolicy, matchAny);
+
+ // for each matching parent, extend policy tree
+ for (PolicyNodeImpl curParent : parentNodes) {
+ if (debug != null)
+ debug.println("PolicyChecker.processParents() "
+ + "found parent:\n" + curParent.asString());
+
+ foundMatch = true;
+ String curParPolicy = curParent.getValidPolicy();
+
+ PolicyNodeImpl curNode = null;
+ Set<String> curExpPols = null;
+
+ if (curPolicy.equals(ANY_POLICY)) {
+ // do step 2
+ Set<String> parExpPols = curParent.getExpectedPolicies();
+ parentExplicitPolicies:
+ for (String curParExpPol : parExpPols) {
+
+ Iterator<PolicyNodeImpl> childIter =
+ curParent.getChildren();
+ while (childIter.hasNext()) {
+ PolicyNodeImpl childNode = childIter.next();
+ String childPolicy = childNode.getValidPolicy();
+ if (curParExpPol.equals(childPolicy)) {
+ if (debug != null)
+ debug.println(childPolicy + " in parent's "
+ + "expected policy set already appears in "
+ + "child node");
+ continue parentExplicitPolicies;
+ }
+ }
+
+ Set<String> expPols = new HashSet<>();
+ expPols.add(curParExpPol);
+
+ curNode = new PolicyNodeImpl
+ (curParent, curParExpPol, pQuals,
+ policiesCritical, expPols, false);
+ }
+ } else {
+ curExpPols = new HashSet<String>();
+ curExpPols.add(curPolicy);
+
+ curNode = new PolicyNodeImpl
+ (curParent, curPolicy, pQuals,
+ policiesCritical, curExpPols, false);
+ }
+ }
+
+ return foundMatch;
+ }
+
+ /**
+ * Processes policy mappings in the certificate.
+ *
+ * @param currCert the Certificate to be processed
+ * @param certIndex the index of the current certificate
+ * @param policyMapping an integer which indicates if policy
+ * mapping is inhibited
+ * @param rootNode the root node of the valid policy tree
+ * @param policiesCritical a boolean indicating if the certificate policies
+ * extension is critical
+ * @param anyQuals the qualifiers associated with ANY-POLICY, or an empty
+ * Set if there are no qualifiers associated with ANY-POLICY
+ * @return the root node of the valid policy tree after modification
+ * @exception CertPathValidatorException exception thrown if an error
+ * occurs while processing policy mappings
+ */
+ private static PolicyNodeImpl processPolicyMappings(X509CertImpl currCert,
+ int certIndex, int policyMapping, PolicyNodeImpl rootNode,
+ boolean policiesCritical, Set<PolicyQualifierInfo> anyQuals)
+ throws CertPathValidatorException
+ {
+ PolicyMappingsExtension polMappingsExt
+ = currCert.getPolicyMappingsExtension();
+
+ if (polMappingsExt == null)
+ return rootNode;
+
+ if (debug != null)
+ debug.println("PolicyChecker.processPolicyMappings() "
+ + "inside policyMapping check");
+
+ List<CertificatePolicyMap> maps = null;
+ try {
+ maps = polMappingsExt.get(PolicyMappingsExtension.MAP);
+ } catch (IOException e) {
+ if (debug != null) {
+ debug.println("PolicyChecker.processPolicyMappings() "
+ + "mapping exception");
+ e.printStackTrace();
+ }
+ throw new CertPathValidatorException("Exception while checking "
+ + "mapping", e);
+ }
+
+ boolean childDeleted = false;
+ for (CertificatePolicyMap polMap : maps) {
+ String issuerDomain
+ = polMap.getIssuerIdentifier().getIdentifier().toString();
+ String subjectDomain
+ = polMap.getSubjectIdentifier().getIdentifier().toString();
+ if (debug != null) {
+ debug.println("PolicyChecker.processPolicyMappings() "
+ + "issuerDomain = " + issuerDomain);
+ debug.println("PolicyChecker.processPolicyMappings() "
+ + "subjectDomain = " + subjectDomain);
+ }
+
+ if (issuerDomain.equals(ANY_POLICY)) {
+ throw new CertPathValidatorException
+ ("encountered an issuerDomainPolicy of ANY_POLICY",
+ null, null, -1, PKIXReason.INVALID_POLICY);
+ }
+
+ if (subjectDomain.equals(ANY_POLICY)) {
+ throw new CertPathValidatorException
+ ("encountered a subjectDomainPolicy of ANY_POLICY",
+ null, null, -1, PKIXReason.INVALID_POLICY);
+ }
+
+ Set<PolicyNodeImpl> validNodes =
+ rootNode.getPolicyNodesValid(certIndex, issuerDomain);
+ if (!validNodes.isEmpty()) {
+ for (PolicyNodeImpl curNode : validNodes) {
+ if ((policyMapping > 0) || (policyMapping == -1)) {
+ curNode.addExpectedPolicy(subjectDomain);
+ } else if (policyMapping == 0) {
+ PolicyNodeImpl parentNode =
+ (PolicyNodeImpl) curNode.getParent();
+ if (debug != null)
+ debug.println("PolicyChecker.processPolicyMappings"
+ + "() before deleting: policy tree = "
+ + rootNode);
+ parentNode.deleteChild(curNode);
+ childDeleted = true;
+ if (debug != null)
+ debug.println("PolicyChecker.processPolicyMappings"
+ + "() after deleting: policy tree = "
+ + rootNode);
+ }
+ }
+ } else { // no node of depth i has a valid policy
+ if ((policyMapping > 0) || (policyMapping == -1)) {
+ Set<PolicyNodeImpl> validAnyNodes =
+ rootNode.getPolicyNodesValid(certIndex, ANY_POLICY);
+ for (PolicyNodeImpl curAnyNode : validAnyNodes) {
+ PolicyNodeImpl curAnyNodeParent =
+ (PolicyNodeImpl) curAnyNode.getParent();
+
+ Set<String> expPols = new HashSet<>();
+ expPols.add(subjectDomain);
+
+ PolicyNodeImpl curNode = new PolicyNodeImpl
+ (curAnyNodeParent, issuerDomain, anyQuals,
+ policiesCritical, expPols, true);
+ }
+ }
+ }
+ }
+
+ if (childDeleted) {
+ rootNode.prune(certIndex);
+ if (!rootNode.getChildren().hasNext()) {
+ if (debug != null)
+ debug.println("setting rootNode to null");
+ rootNode = null;
+ }
+ }
+
+ return rootNode;
+ }
+
+ /**
+ * Removes those nodes which do not intersect with the initial policies
+ * specified by the user.
+ *
+ * @param rootNode the root node of the valid policy tree
+ * @param certIndex the index of the certificate being processed
+ * @param initPolicies the Set of policies required by the user
+ * @param currCertPolicies the CertificatePoliciesExtension of the
+ * certificate being processed
+ * @returns the root node of the valid policy tree after modification
+ * @exception CertPathValidatorException Exception thrown if error occurs.
+ */
+ private static PolicyNodeImpl removeInvalidNodes(PolicyNodeImpl rootNode,
+ int certIndex, Set<String> initPolicies,
+ CertificatePoliciesExtension currCertPolicies)
+ throws CertPathValidatorException
+ {
+ List<PolicyInformation> policyInfo = null;
+ try {
+ policyInfo = currCertPolicies.get(CertificatePoliciesExtension.POLICIES);
+ } catch (IOException ioe) {
+ throw new CertPathValidatorException("Exception while "
+ + "retrieving policyOIDs", ioe);
+ }
+
+ boolean childDeleted = false;
+ for (PolicyInformation curPolInfo : policyInfo) {
+ String curPolicy =
+ curPolInfo.getPolicyIdentifier().getIdentifier().toString();
+
+ if (debug != null)
+ debug.println("PolicyChecker.processPolicies() "
+ + "processing policy second time: " + curPolicy);
+
+ Set<PolicyNodeImpl> validNodes =
+ rootNode.getPolicyNodesValid(certIndex, curPolicy);
+ for (PolicyNodeImpl curNode : validNodes) {
+ PolicyNodeImpl parentNode = (PolicyNodeImpl)curNode.getParent();
+ if (parentNode.getValidPolicy().equals(ANY_POLICY)) {
+ if ((!initPolicies.contains(curPolicy)) &&
+ (!curPolicy.equals(ANY_POLICY))) {
+ if (debug != null)
+ debug.println("PolicyChecker.processPolicies() "
+ + "before deleting: policy tree = " + rootNode);
+ parentNode.deleteChild(curNode);
+ childDeleted = true;
+ if (debug != null)
+ debug.println("PolicyChecker.processPolicies() "
+ + "after deleting: policy tree = " + rootNode);
+ }
+ }
+ }
+ }
+
+ if (childDeleted) {
+ rootNode.prune(certIndex);
+ if (!rootNode.getChildren().hasNext()) {
+ rootNode = null;
+ }
+ }
+
+ return rootNode;
+ }
+
+ /**
+ * Gets the root node of the valid policy tree, or null if the
+ * valid policy tree is null. Marks each node of the returned tree
+ * immutable and thread-safe.
+ *
+ * @returns the root node of the valid policy tree, or null if
+ * the valid policy tree is null
+ */
+ PolicyNode getPolicyTree() {
+ if (rootNode == null)
+ return null;
+ else {
+ PolicyNodeImpl policyTree = rootNode.copyTree();
+ policyTree.setImmutable();
+ return policyTree;
+ }
+ }
+}
diff --git a/ojluni/src/main/java/sun/security/provider/certpath/PolicyNodeImpl.java b/ojluni/src/main/java/sun/security/provider/certpath/PolicyNodeImpl.java
new file mode 100644
index 0000000..02109d4
--- /dev/null
+++ b/ojluni/src/main/java/sun/security/provider/certpath/PolicyNodeImpl.java
@@ -0,0 +1,424 @@
+/*
+ * Copyright (c) 2000, 2012, 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.Collections;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.Set;
+
+import java.security.cert.*;
+
+/**
+ * Implements the <code>PolicyNode</code> interface.
+ * <p>
+ * This class provides an implementation of the <code>PolicyNode</code>
+ * interface, and is used internally to build and search Policy Trees.
+ * While the implementation is mutable during construction, it is immutable
+ * before returning to a client and no mutable public or protected methods
+ * are exposed by this implementation, as per the contract of PolicyNode.
+ *
+ * @since 1.4
+ * @author Seth Proctor
+ * @author Sean Mullan
+ */
+final class PolicyNodeImpl implements PolicyNode {
+
+ /**
+ * Use to specify the special policy "Any Policy"
+ */
+ private static final String ANY_POLICY = "2.5.29.32.0";
+
+ // every node has one parent, and zero or more children
+ private PolicyNodeImpl mParent;
+ private HashSet<PolicyNodeImpl> mChildren;
+
+ // the 4 fields specified by RFC 3280
+ private String mValidPolicy;
+ private HashSet<PolicyQualifierInfo> mQualifierSet;
+ private boolean mCriticalityIndicator;
+ private HashSet<String> mExpectedPolicySet;
+ private boolean mOriginalExpectedPolicySet;
+
+ // the tree depth
+ private int mDepth;
+ // immutability flag
+ private boolean isImmutable = false;
+
+ /**
+ * Constructor which takes a <code>PolicyNodeImpl</code> representing the
+ * parent in the Policy Tree to this node. If null, this is the
+ * root of the tree. The constructor also takes the associated data
+ * for this node, as found in the certificate. It also takes a boolean
+ * argument specifying whether this node is being created as a result
+ * of policy mapping.
+ *
+ * @param parent the PolicyNode above this in the tree, or null if this
+ * node is the tree's root node
+ * @param validPolicy a String representing this node's valid policy OID
+ * @param qualifierSet the Set of qualifiers for this policy
+ * @param criticalityIndicator a boolean representing whether or not the
+ * extension is critical
+ * @param expectedPolicySet a Set of expected policies
+ * @param generatedByPolicyMapping a boolean indicating whether this
+ * node was generated by a policy mapping
+ */
+ PolicyNodeImpl(PolicyNodeImpl parent, String validPolicy,
+ Set<PolicyQualifierInfo> qualifierSet,
+ boolean criticalityIndicator, Set<String> expectedPolicySet,
+ boolean generatedByPolicyMapping) {
+ mParent = parent;
+ mChildren = new HashSet<PolicyNodeImpl>();
+
+ if (validPolicy != null)
+ mValidPolicy = validPolicy;
+ else
+ mValidPolicy = "";
+
+ if (qualifierSet != null)
+ mQualifierSet = new HashSet<PolicyQualifierInfo>(qualifierSet);
+ else
+ mQualifierSet = new HashSet<PolicyQualifierInfo>();
+
+ mCriticalityIndicator = criticalityIndicator;
+
+ if (expectedPolicySet != null)
+ mExpectedPolicySet = new HashSet<String>(expectedPolicySet);
+ else
+ mExpectedPolicySet = new HashSet<String>();
+
+ mOriginalExpectedPolicySet = !generatedByPolicyMapping;
+
+ // see if we're the root, and act appropriately
+ if (mParent != null) {
+ mDepth = mParent.getDepth() + 1;
+ mParent.addChild(this);
+ } else {
+ mDepth = 0;
+ }
+ }
+
+ /**
+ * Alternate constructor which makes a new node with the policy data
+ * in an existing <code>PolicyNodeImpl</code>.
+ *
+ * @param parent a PolicyNode that's the new parent of the node, or
+ * null if this is the root node
+ * @param node a PolicyNode containing the policy data to copy
+ */
+ PolicyNodeImpl(PolicyNodeImpl parent, PolicyNodeImpl node) {
+ this(parent, node.mValidPolicy, node.mQualifierSet,
+ node.mCriticalityIndicator, node.mExpectedPolicySet, false);
+ }
+
+ @Override
+ public PolicyNode getParent() {
+ return mParent;
+ }
+
+ @Override
+ public Iterator<PolicyNodeImpl> getChildren() {
+ return Collections.unmodifiableSet(mChildren).iterator();
+ }
+
+ @Override
+ public int getDepth() {
+ return mDepth;
+ }
+
+ @Override
+ public String getValidPolicy() {
+ return mValidPolicy;
+ }
+
+ @Override
+ public Set<PolicyQualifierInfo> getPolicyQualifiers() {
+ return Collections.unmodifiableSet(mQualifierSet);
+ }
+
+ @Override
+ public Set<String> getExpectedPolicies() {
+ return Collections.unmodifiableSet(mExpectedPolicySet);
+ }
+
+ @Override
+ public boolean isCritical() {
+ return mCriticalityIndicator;
+ }
+
+ /**
+ * Return a printable representation of the PolicyNode.
+ * Starting at the node on which this method is called,
+ * it recurses through the tree and prints out each node.
+ *
+ * @return a String describing the contents of the Policy Node
+ */
+ @Override
+ public String toString() {
+ StringBuilder buffer = new StringBuilder(this.asString());
+
+ for (PolicyNodeImpl node : mChildren) {
+ buffer.append(node);
+ }
+ return buffer.toString();
+ }
+
+ // private methods and package private operations
+
+ boolean isImmutable() {
+ return isImmutable;
+ }
+
+ /**
+ * Sets the immutability flag of this node and all of its children
+ * to true.
+ */
+ void setImmutable() {
+ if (isImmutable)
+ return;
+ for (PolicyNodeImpl node : mChildren) {
+ node.setImmutable();
+ }
+ isImmutable = true;
+ }
+
+ /**
+ * Private method sets a child node. This is called from the child's
+ * constructor.
+ *
+ * @param child new <code>PolicyNodeImpl</code> child node
+ */
+ private void addChild(PolicyNodeImpl child) {
+ if (isImmutable) {
+ throw new IllegalStateException("PolicyNode is immutable");
+ }
+ mChildren.add(child);
+ }
+
+ /**
+ * Adds an expectedPolicy to the expected policy set.
+ * If this is the original expected policy set initialized
+ * by the constructor, then the expected policy set is cleared
+ * before the expected policy is added.
+ *
+ * @param expectedPolicy a String representing an expected policy.
+ */
+ void addExpectedPolicy(String expectedPolicy) {
+ if (isImmutable) {
+ throw new IllegalStateException("PolicyNode is immutable");
+ }
+ if (mOriginalExpectedPolicySet) {
+ mExpectedPolicySet.clear();
+ mOriginalExpectedPolicySet = false;
+ }
+ mExpectedPolicySet.add(expectedPolicy);
+ }
+
+ /**
+ * Removes all paths which don't reach the specified depth.
+ *
+ * @param depth an int representing the desired minimum depth of all paths
+ */
+ void prune(int depth) {
+ if (isImmutable)
+ throw new IllegalStateException("PolicyNode is immutable");
+
+ // if we have no children, we can't prune below us...
+ if (mChildren.size() == 0)
+ return;
+
+ Iterator<PolicyNodeImpl> it = mChildren.iterator();
+ while (it.hasNext()) {
+ PolicyNodeImpl node = it.next();
+ node.prune(depth);
+ // now that we've called prune on the child, see if we should
+ // remove it from the tree
+ if ((node.mChildren.size() == 0) && (depth > mDepth + 1))
+ it.remove();
+ }
+ }
+
+ /**
+ * Deletes the specified child node of this node, if it exists.
+ *
+ * @param childNode the child node to be deleted
+ */
+ void deleteChild(PolicyNode childNode) {
+ if (isImmutable) {
+ throw new IllegalStateException("PolicyNode is immutable");
+ }
+ mChildren.remove(childNode);
+ }
+
+ /**
+ * Returns a copy of the tree, without copying the policy-related data,
+ * rooted at the node on which this was called.
+ *
+ * @return a copy of the tree
+ */
+ PolicyNodeImpl copyTree() {
+ return copyTree(null);
+ }
+
+ private PolicyNodeImpl copyTree(PolicyNodeImpl parent) {
+ PolicyNodeImpl newNode = new PolicyNodeImpl(parent, this);
+
+ for (PolicyNodeImpl node : mChildren) {
+ node.copyTree(newNode);
+ }
+
+ return newNode;
+ }
+
+ /**
+ * Returns all nodes at the specified depth in the tree.
+ *
+ * @param depth an int representing the depth of the desired nodes
+ * @return a <code>Set</code> of all nodes at the specified depth
+ */
+ Set<PolicyNodeImpl> getPolicyNodes(int depth) {
+ Set<PolicyNodeImpl> set = new HashSet<>();
+ getPolicyNodes(depth, set);
+ return set;
+ }
+
+ /**
+ * Add all nodes at depth depth to set and return the Set.
+ * Internal recursion helper.
+ */
+ private void getPolicyNodes(int depth, Set<PolicyNodeImpl> set) {
+ // if we've reached the desired depth, then return ourself
+ if (mDepth == depth) {
+ set.add(this);
+ } else {
+ for (PolicyNodeImpl node : mChildren) {
+ node.getPolicyNodes(depth, set);
+ }
+ }
+ }
+
+ /**
+ * Finds all nodes at the specified depth whose expected_policy_set
+ * contains the specified expected OID (if matchAny is false)
+ * or the special OID "any value" (if matchAny is true).
+ *
+ * @param depth an int representing the desired depth
+ * @param expectedOID a String encoding the valid OID to match
+ * @param matchAny a boolean indicating whether an expected_policy_set
+ * containing ANY_POLICY should be considered a match
+ * @return a Set of matched <code>PolicyNode</code>s
+ */
+ Set<PolicyNodeImpl> getPolicyNodesExpected(int depth,
+ String expectedOID, boolean matchAny) {
+
+ if (expectedOID.equals(ANY_POLICY)) {
+ return getPolicyNodes(depth);
+ } else {
+ return getPolicyNodesExpectedHelper(depth, expectedOID, matchAny);
+ }
+ }
+
+ private Set<PolicyNodeImpl> getPolicyNodesExpectedHelper(int depth,
+ String expectedOID, boolean matchAny) {
+
+ HashSet<PolicyNodeImpl> set = new HashSet<>();
+
+ if (mDepth < depth) {
+ for (PolicyNodeImpl node : mChildren) {
+ set.addAll(node.getPolicyNodesExpectedHelper(depth,
+ expectedOID,
+ matchAny));
+ }
+ } else {
+ if (matchAny) {
+ if (mExpectedPolicySet.contains(ANY_POLICY))
+ set.add(this);
+ } else {
+ if (mExpectedPolicySet.contains(expectedOID))
+ set.add(this);
+ }
+ }
+
+ return set;
+ }
+
+ /**
+ * Finds all nodes at the specified depth that contains the
+ * specified valid OID
+ *
+ * @param depth an int representing the desired depth
+ * @param validOID a String encoding the valid OID to match
+ * @return a Set of matched <code>PolicyNode</code>s
+ */
+ Set<PolicyNodeImpl> getPolicyNodesValid(int depth, String validOID) {
+ HashSet<PolicyNodeImpl> set = new HashSet<>();
+
+ if (mDepth < depth) {
+ for (PolicyNodeImpl node : mChildren) {
+ set.addAll(node.getPolicyNodesValid(depth, validOID));
+ }
+ } else {
+ if (mValidPolicy.equals(validOID))
+ set.add(this);
+ }
+
+ return set;
+ }
+
+ private static String policyToString(String oid) {
+ if (oid.equals(ANY_POLICY)) {
+ return "anyPolicy";
+ } else {
+ return oid;
+ }
+ }
+
+ /**
+ * Prints out some data on this node.
+ */
+ String asString() {
+ if (mParent == null) {
+ return "anyPolicy ROOT\n";
+ } else {
+ StringBuilder sb = new StringBuilder();
+ for (int i = 0, n = getDepth(); i < n; i++) {
+ sb.append(" ");
+ }
+ sb.append(policyToString(getValidPolicy()));
+ sb.append(" CRIT: ");
+ sb.append(isCritical());
+ sb.append(" EP: ");
+ for (String policy : getExpectedPolicies()) {
+ sb.append(policyToString(policy));
+ sb.append(" ");
+ }
+ sb.append(" (");
+ sb.append(getDepth());
+ sb.append(")\n");
+ return sb.toString();
+ }
+ }
+}
diff --git a/ojluni/src/main/java/sun/security/provider/certpath/ReverseBuilder.java b/ojluni/src/main/java/sun/security/provider/certpath/ReverseBuilder.java
new file mode 100644
index 0000000..a70945d
--- /dev/null
+++ b/ojluni/src/main/java/sun/security/provider/certpath/ReverseBuilder.java
@@ -0,0 +1,551 @@
+/*
+ * Copyright (c) 2000, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * 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.io.IOException;
+import java.security.GeneralSecurityException;
+import java.security.Principal;
+import java.security.cert.CertificateException;
+import java.security.cert.CertPathValidatorException;
+import java.security.cert.CertStore;
+import java.security.cert.CertStoreException;
+import java.security.cert.PKIXBuilderParameters;
+import java.security.cert.PKIXCertPathChecker;
+import java.security.cert.PKIXParameters;
+import java.security.cert.PKIXReason;
+import java.security.cert.TrustAnchor;
+import java.security.cert.X509Certificate;
+import java.security.cert.X509CertSelector;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.Comparator;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.List;
+import java.util.LinkedList;
+import java.util.Set;
+
+import javax.security.auth.x500.X500Principal;
+
+import sun.security.provider.certpath.PKIX.BuilderParams;
+import sun.security.util.Debug;
+import sun.security.x509.Extension;
+import static sun.security.x509.PKIXExtensions.*;
+import sun.security.x509.X500Name;
+import sun.security.x509.X509CertImpl;
+import sun.security.x509.PolicyMappingsExtension;
+
+/**
+ * This class represents a reverse builder, which is able to retrieve
+ * matching certificates from CertStores and verify a particular certificate
+ * against a ReverseState.
+ *
+ * @since 1.4
+ * @author Sean Mullan
+ * @author Yassir Elley
+ */
+
+class ReverseBuilder extends Builder {
+
+ private Debug debug = Debug.getInstance("certpath");
+
+ private final Set<String> initPolicies;
+
+ /**
+ * Initialize the builder with the input parameters.
+ *
+ * @param params the parameter set used to build a certification path
+ */
+ ReverseBuilder(BuilderParams buildParams) {
+ super(buildParams);
+
+ Set<String> initialPolicies = buildParams.initialPolicies();
+ initPolicies = new HashSet<String>();
+ if (initialPolicies.isEmpty()) {
+ // if no initialPolicies are specified by user, set
+ // initPolicies to be anyPolicy by default
+ initPolicies.add(PolicyChecker.ANY_POLICY);
+ } else {
+ initPolicies.addAll(initialPolicies);
+ }
+ }
+
+ /**
+ * Retrieves all certs from the specified CertStores that satisfy the
+ * requirements specified in the parameters and the current
+ * PKIX state (name constraints, policy constraints, etc).
+ *
+ * @param currentState the current state.
+ * Must be an instance of <code>ReverseState</code>
+ * @param certStores list of CertStores
+ */
+ @Override
+ Collection<X509Certificate> getMatchingCerts
+ (State currState, List<CertStore> certStores)
+ throws CertStoreException, CertificateException, IOException
+ {
+ ReverseState currentState = (ReverseState) currState;
+
+ if (debug != null)
+ debug.println("In ReverseBuilder.getMatchingCerts.");
+
+ /*
+ * The last certificate could be an EE or a CA certificate
+ * (we may be building a partial certification path or
+ * establishing trust in a CA).
+ *
+ * Try the EE certs before the CA certs. It will be more
+ * common to build a path to an end entity.
+ */
+ Collection<X509Certificate> certs =
+ getMatchingEECerts(currentState, certStores);
+ certs.addAll(getMatchingCACerts(currentState, certStores));
+
+ return certs;
+ }
+
+ /*
+ * Retrieves all end-entity certificates which satisfy constraints
+ * and requirements specified in the parameters and PKIX state.
+ */
+ private Collection<X509Certificate> getMatchingEECerts
+ (ReverseState currentState, List<CertStore> certStores)
+ throws CertStoreException, CertificateException, IOException {
+
+ /*
+ * Compose a CertSelector to filter out
+ * certs which do not satisfy requirements.
+ *
+ * First, retrieve clone of current target cert constraints, and
+ * then add more selection criteria based on current validation state.
+ */
+ X509CertSelector sel = (X509CertSelector) targetCertConstraints.clone();
+
+ /*
+ * Match on issuer (subject of previous cert)
+ */
+ sel.setIssuer(currentState.subjectDN);
+
+ /*
+ * Match on certificate validity date.
+ */
+ sel.setCertificateValid(buildParams.date());
+
+ /*
+ * Policy processing optimizations
+ */
+ if (currentState.explicitPolicy == 0)
+ sel.setPolicy(getMatchingPolicies());
+
+ /*
+ * If previous cert has a subject key identifier extension,
+ * use it to match on authority key identifier extension.
+ */
+ /*if (currentState.subjKeyId != null) {
+ AuthorityKeyIdentifierExtension authKeyId = new AuthorityKeyIdentifierExtension(
+ (KeyIdentifier) currentState.subjKeyId.get(SubjectKeyIdentifierExtension.KEY_ID),
+ null, null);
+ sel.setAuthorityKeyIdentifier(authKeyId.getExtensionValue());
+ }*/
+
+ /*
+ * Require EE certs
+ */
+ sel.setBasicConstraints(-2);
+
+ /* Retrieve matching certs from CertStores */
+ HashSet<X509Certificate> eeCerts = new HashSet<>();
+ addMatchingCerts(sel, certStores, eeCerts, true);
+
+ if (debug != null) {
+ debug.println("ReverseBuilder.getMatchingEECerts got "
+ + eeCerts.size() + " certs.");
+ }
+ return eeCerts;
+ }
+
+ /*
+ * Retrieves all CA certificates which satisfy constraints
+ * and requirements specified in the parameters and PKIX state.
+ */
+ private Collection<X509Certificate> getMatchingCACerts
+ (ReverseState currentState, List<CertStore> certStores)
+ throws CertificateException, CertStoreException, IOException {
+
+ /*
+ * Compose a CertSelector to filter out
+ * certs which do not satisfy requirements.
+ */
+ X509CertSelector sel = new X509CertSelector();
+
+ /*
+ * Match on issuer (subject of previous cert)
+ */
+ sel.setIssuer(currentState.subjectDN);
+
+ /*
+ * Match on certificate validity date.
+ */
+ sel.setCertificateValid(buildParams.date());
+
+ /*
+ * Match on target subject name (checks that current cert's
+ * name constraints permit it to certify target).
+ * (4 is the integer type for DIRECTORY name).
+ */
+ byte[] subject = targetCertConstraints.getSubjectAsBytes();
+ if (subject != null) {
+ sel.addPathToName(4, subject);
+ } else {
+ X509Certificate cert = targetCertConstraints.getCertificate();
+ if (cert != null) {
+ sel.addPathToName(4,
+ cert.getSubjectX500Principal().getEncoded());
+ }
+ }
+
+ /*
+ * Policy processing optimizations
+ */
+ if (currentState.explicitPolicy == 0)
+ sel.setPolicy(getMatchingPolicies());
+
+ /*
+ * If previous cert has a subject key identifier extension,
+ * use it to match on authority key identifier extension.
+ */
+ /*if (currentState.subjKeyId != null) {
+ AuthorityKeyIdentifierExtension authKeyId = new AuthorityKeyIdentifierExtension(
+ (KeyIdentifier) currentState.subjKeyId.get(SubjectKeyIdentifierExtension.KEY_ID),
+ null, null);
+ sel.setAuthorityKeyIdentifier(authKeyId.getExtensionValue());
+ }*/
+
+ /*
+ * Require CA certs
+ */
+ sel.setBasicConstraints(0);
+
+ /* Retrieve matching certs from CertStores */
+ ArrayList<X509Certificate> reverseCerts = new ArrayList<>();
+ addMatchingCerts(sel, certStores, reverseCerts, true);
+
+ /* Sort remaining certs using name constraints */
+ Collections.sort(reverseCerts, new PKIXCertComparator());
+
+ if (debug != null)
+ debug.println("ReverseBuilder.getMatchingCACerts got " +
+ reverseCerts.size() + " certs.");
+ return reverseCerts;
+ }
+
+ /*
+ * This inner class compares 2 PKIX certificates according to which
+ * should be tried first when building a path to the target. For
+ * now, the algorithm is to look at name constraints in each cert and those
+ * which constrain the path closer to the target should be
+ * ranked higher. Later, we may want to consider other components,
+ * such as key identifiers.
+ */
+ class PKIXCertComparator implements Comparator<X509Certificate> {
+
+ private Debug debug = Debug.getInstance("certpath");
+
+ @Override
+ public int compare(X509Certificate cert1, X509Certificate cert2) {
+
+ /*
+ * if either cert certifies the target, always
+ * put at head of list.
+ */
+ X500Principal targetSubject = buildParams.targetSubject();
+ if (cert1.getSubjectX500Principal().equals(targetSubject)) {
+ return -1;
+ }
+ if (cert2.getSubjectX500Principal().equals(targetSubject)) {
+ return 1;
+ }
+
+ int targetDist1;
+ int targetDist2;
+ try {
+ X500Name targetSubjectName = X500Name.asX500Name(targetSubject);
+ targetDist1 = Builder.targetDistance(
+ null, cert1, targetSubjectName);
+ targetDist2 = Builder.targetDistance(
+ null, cert2, targetSubjectName);
+ } catch (IOException e) {
+ if (debug != null) {
+ debug.println("IOException in call to Builder.targetDistance");
+ e.printStackTrace();
+ }
+ throw new ClassCastException
+ ("Invalid target subject distinguished name");
+ }
+
+ if (targetDist1 == targetDist2)
+ return 0;
+
+ if (targetDist1 == -1)
+ return 1;
+
+ if (targetDist1 < targetDist2)
+ return -1;
+
+ return 1;
+ }
+ }
+
+ /**
+ * Verifies a matching certificate.
+ *
+ * This method executes any of the validation steps in the PKIX path validation
+ * algorithm which were not satisfied via filtering out non-compliant
+ * certificates with certificate matching rules.
+ *
+ * If the last certificate is being verified (the one whose subject
+ * matches the target subject, then the steps in Section 6.1.4 of the
+ * Certification Path Validation algorithm are NOT executed,
+ * regardless of whether or not the last cert is an end-entity
+ * cert or not. This allows callers to certify CA certs as
+ * well as EE certs.
+ *
+ * @param cert the certificate to be verified
+ * @param currentState the current state against which the cert is verified
+ * @param certPathList the certPathList generated thus far
+ */
+ @Override
+ void verifyCert(X509Certificate cert, State currState,
+ List<X509Certificate> certPathList)
+ throws GeneralSecurityException
+ {
+ if (debug != null) {
+ debug.println("ReverseBuilder.verifyCert(SN: "
+ + Debug.toHexString(cert.getSerialNumber())
+ + "\n Subject: " + cert.getSubjectX500Principal() + ")");
+ }
+
+ ReverseState currentState = (ReverseState) currState;
+
+ /* we don't perform any validation of the trusted cert */
+ if (currentState.isInitial()) {
+ return;
+ }
+
+ // Don't bother to verify untrusted certificate more.
+ currentState.untrustedChecker.check(cert,
+ Collections.<String>emptySet());
+
+ /*
+ * check for looping - abort a loop if
+ * ((we encounter the same certificate twice) AND
+ * ((policyMappingInhibited = true) OR (no policy mapping
+ * extensions can be found between the occurrences of the same
+ * certificate)))
+ * in order to facilitate the check to see if there are
+ * any policy mapping extensions found between the occurrences
+ * of the same certificate, we reverse the certpathlist first
+ */
+ if ((certPathList != null) && (!certPathList.isEmpty())) {
+ List<X509Certificate> reverseCertList = new ArrayList<>();
+ for (X509Certificate c : certPathList) {
+ reverseCertList.add(0, c);
+ }
+
+ boolean policyMappingFound = false;
+ for (X509Certificate cpListCert : reverseCertList) {
+ X509CertImpl cpListCertImpl = X509CertImpl.toImpl(cpListCert);
+ PolicyMappingsExtension policyMappingsExt =
+ cpListCertImpl.getPolicyMappingsExtension();
+ if (policyMappingsExt != null) {
+ policyMappingFound = true;
+ }
+ if (debug != null)
+ debug.println("policyMappingFound = " + policyMappingFound);
+ if (cert.equals(cpListCert)) {
+ if ((buildParams.policyMappingInhibited()) ||
+ (!policyMappingFound)){
+ if (debug != null)
+ debug.println("loop detected!!");
+ throw new CertPathValidatorException("loop detected");
+ }
+ }
+ }
+ }
+
+ /* check if target cert */
+ boolean finalCert = cert.getSubjectX500Principal().equals(buildParams.targetSubject());
+
+ /* check if CA cert */
+ boolean caCert = (cert.getBasicConstraints() != -1 ? true : false);
+
+ /* if there are more certs to follow, verify certain constraints */
+ if (!finalCert) {
+
+ /* check if CA cert */
+ if (!caCert)
+ throw new CertPathValidatorException("cert is NOT a CA cert");
+
+ /* If the certificate was not self-issued, verify that
+ * remainingCerts is greater than zero
+ */
+ if ((currentState.remainingCACerts <= 0) && !X509CertImpl.isSelfIssued(cert)) {
+ throw new CertPathValidatorException
+ ("pathLenConstraint violated, path too long", null,
+ null, -1, PKIXReason.PATH_TOO_LONG);
+ }
+
+ /*
+ * Check keyUsage extension (only if CA cert and not final cert)
+ */
+ KeyChecker.verifyCAKeyUsage(cert);
+
+ } else {
+
+ /*
+ * If final cert, check that it satisfies specified target
+ * constraints
+ */
+ if (targetCertConstraints.match(cert) == false) {
+ throw new CertPathValidatorException("target certificate " +
+ "constraints check failed");
+ }
+ }
+
+ /*
+ * Check revocation.
+ */
+ if (buildParams.revocationEnabled() && currentState.revChecker != null) {
+ currentState.revChecker.check(cert, Collections.<String>emptySet());
+ }
+
+ /* Check name constraints if this is not a self-issued cert */
+ if (finalCert || !X509CertImpl.isSelfIssued(cert)){
+ if (currentState.nc != null) {
+ try {
+ if (!currentState.nc.verify(cert)){
+ throw new CertPathValidatorException
+ ("name constraints check failed", null, null, -1,
+ PKIXReason.INVALID_NAME);
+ }
+ } catch (IOException ioe) {
+ throw new CertPathValidatorException(ioe);
+ }
+ }
+ }
+
+ /*
+ * Check policy
+ */
+ X509CertImpl certImpl = X509CertImpl.toImpl(cert);
+ currentState.rootNode = PolicyChecker.processPolicies
+ (currentState.certIndex, initPolicies,
+ currentState.explicitPolicy, currentState.policyMapping,
+ currentState.inhibitAnyPolicy,
+ buildParams.policyQualifiersRejected(), currentState.rootNode,
+ certImpl, finalCert);
+
+ /*
+ * Check CRITICAL private extensions
+ */
+ Set<String> unresolvedCritExts = cert.getCriticalExtensionOIDs();
+ if (unresolvedCritExts == null) {
+ unresolvedCritExts = Collections.<String>emptySet();
+ }
+
+ /*
+ * Check that the signature algorithm is not disabled.
+ */
+ currentState.algorithmChecker.check(cert, unresolvedCritExts);
+
+ for (PKIXCertPathChecker checker : currentState.userCheckers) {
+ checker.check(cert, unresolvedCritExts);
+ }
+
+ /*
+ * Look at the remaining extensions and remove any ones we have
+ * already checked. If there are any left, throw an exception!
+ */
+ if (!unresolvedCritExts.isEmpty()) {
+ unresolvedCritExts.remove(BasicConstraints_Id.toString());
+ unresolvedCritExts.remove(NameConstraints_Id.toString());
+ unresolvedCritExts.remove(CertificatePolicies_Id.toString());
+ unresolvedCritExts.remove(PolicyMappings_Id.toString());
+ unresolvedCritExts.remove(PolicyConstraints_Id.toString());
+ unresolvedCritExts.remove(InhibitAnyPolicy_Id.toString());
+ unresolvedCritExts.remove(SubjectAlternativeName_Id.toString());
+ unresolvedCritExts.remove(KeyUsage_Id.toString());
+ unresolvedCritExts.remove(ExtendedKeyUsage_Id.toString());
+
+ if (!unresolvedCritExts.isEmpty())
+ throw new CertPathValidatorException
+ ("Unrecognized critical extension(s)", null, null, -1,
+ PKIXReason.UNRECOGNIZED_CRIT_EXT);
+ }
+
+ /*
+ * Check signature.
+ */
+ if (buildParams.sigProvider() != null) {
+ cert.verify(currentState.pubKey, buildParams.sigProvider());
+ } else {
+ cert.verify(currentState.pubKey);
+ }
+ }
+
+ /**
+ * Verifies whether the input certificate completes the path.
+ * This checks whether the cert is the target certificate.
+ *
+ * @param cert the certificate to test
+ * @return a boolean value indicating whether the cert completes the path.
+ */
+ @Override
+ boolean isPathCompleted(X509Certificate cert) {
+ return cert.getSubjectX500Principal().equals(buildParams.targetSubject());
+ }
+
+ /** Adds the certificate to the certPathList
+ *
+ * @param cert the certificate to be added
+ * @param certPathList the certification path list
+ */
+ @Override
+ void addCertToPath(X509Certificate cert,
+ LinkedList<X509Certificate> certPathList) {
+ certPathList.addLast(cert);
+ }
+
+ /** Removes final certificate from the certPathList
+ *
+ * @param certPathList the certification path list
+ */
+ @Override
+ void removeFinalCertFromPath(LinkedList<X509Certificate> certPathList) {
+ certPathList.removeLast();
+ }
+}
diff --git a/ojluni/src/main/java/sun/security/provider/certpath/ReverseState.java b/ojluni/src/main/java/sun/security/provider/certpath/ReverseState.java
new file mode 100644
index 0000000..c515003
--- /dev/null
+++ b/ojluni/src/main/java/sun/security/provider/certpath/ReverseState.java
@@ -0,0 +1,406 @@
+/*
+ * Copyright (c) 2000, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * 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.io.IOException;
+import java.security.PublicKey;
+import java.security.cert.CertificateException;
+import java.security.cert.CertPathValidatorException;
+import java.security.cert.PKIXCertPathChecker;
+import java.security.cert.PKIXRevocationChecker;
+import java.security.cert.TrustAnchor;
+import java.security.cert.X509Certificate;
+import java.util.ArrayList;
+import java.util.HashSet;
+import java.util.List;
+import java.util.ListIterator;
+import java.util.Set;
+import javax.security.auth.x500.X500Principal;
+
+import sun.security.provider.certpath.PKIX.BuilderParams;
+import sun.security.util.Debug;
+import sun.security.x509.NameConstraintsExtension;
+import sun.security.x509.SubjectKeyIdentifierExtension;
+import sun.security.x509.X509CertImpl;
+
+/**
+ * A specification of a reverse PKIX validation state
+ * which is initialized by each build and updated each time a
+ * certificate is added to the current path.
+ * @since 1.4
+ * @author Sean Mullan
+ * @author Yassir Elley
+ */
+
+class ReverseState implements State {
+
+ private static final Debug debug = Debug.getInstance("certpath");
+
+ /* The subject DN of the last cert in the path */
+ X500Principal subjectDN;
+
+ /* The subject public key of the last cert */
+ PublicKey pubKey;
+
+ /* The subject key identifier extension (if any) of the last cert */
+ SubjectKeyIdentifierExtension subjKeyId;
+
+ /* The PKIX constrained/excluded subtrees state variable */
+ NameConstraintsExtension nc;
+
+ /* The PKIX explicit policy, policy mapping, and inhibit_any-policy
+ state variables */
+ int explicitPolicy;
+ int policyMapping;
+ int inhibitAnyPolicy;
+ int certIndex;
+ PolicyNodeImpl rootNode;
+
+ /* The number of remaining CA certs which may follow in the path.
+ * -1: previous cert was an EE cert
+ * 0: only EE certs may follow.
+ * >0 and <Integer.MAX_VALUE:no more than this number of CA certs may follow
+ * Integer.MAX_VALUE: unlimited
+ */
+ int remainingCACerts;
+
+ /* The list of user-defined checkers retrieved from the PKIXParameters
+ * instance */
+ ArrayList<PKIXCertPathChecker> userCheckers;
+
+ /* Flag indicating if state is initial (path is just starting) */
+ private boolean init = true;
+
+ /* the checker used for revocation status */
+ RevocationChecker revChecker;
+
+ /* the algorithm checker */
+ AlgorithmChecker algorithmChecker;
+
+ /* the untrusted certificates checker */
+ UntrustedChecker untrustedChecker;
+
+ /* the trust anchor used to validate the path */
+ TrustAnchor trustAnchor;
+
+ /* Flag indicating if current cert can vouch for the CRL for
+ * the next cert
+ */
+ boolean crlSign = true;
+
+ /**
+ * Returns a boolean flag indicating if the state is initial
+ * (just starting)
+ *
+ * @return boolean flag indicating if the state is initial (just starting)
+ */
+ @Override
+ public boolean isInitial() {
+ return init;
+ }
+
+ /**
+ * Display state for debugging purposes
+ */
+ @Override
+ public String toString() {
+ StringBuilder sb = new StringBuilder();
+ sb.append("State [");
+ sb.append("\n subjectDN of last cert: ").append(subjectDN);
+ sb.append("\n subjectKeyIdentifier: ").append
+ (String.valueOf(subjKeyId));
+ sb.append("\n nameConstraints: ").append(String.valueOf(nc));
+ sb.append("\n certIndex: ").append(certIndex);
+ sb.append("\n explicitPolicy: ").append(explicitPolicy);
+ sb.append("\n policyMapping: ").append(policyMapping);
+ sb.append("\n inhibitAnyPolicy: ").append(inhibitAnyPolicy);
+ sb.append("\n rootNode: ").append(rootNode);
+ sb.append("\n remainingCACerts: ").append(remainingCACerts);
+ sb.append("\n crlSign: ").append(crlSign);
+ sb.append("\n init: ").append(init);
+ sb.append("\n]\n");
+ return sb.toString();
+ }
+
+ /**
+ * Initialize the state.
+ *
+ * @param buildParams builder parameters
+ */
+ public void initState(BuilderParams buildParams)
+ throws CertPathValidatorException
+ {
+ /*
+ * Initialize number of remainingCACerts.
+ * Note that -1 maxPathLen implies unlimited.
+ * 0 implies only an EE cert is acceptable.
+ */
+ int maxPathLen = buildParams.maxPathLength();
+ remainingCACerts = (maxPathLen == -1) ? Integer.MAX_VALUE
+ : maxPathLen;
+
+ /* Initialize explicit policy state variable */
+ if (buildParams.explicitPolicyRequired()) {
+ explicitPolicy = 0;
+ } else {
+ // unconstrained if maxPathLen is -1,
+ // otherwise, we want to initialize this to the value of the
+ // longest possible path + 1 (i.e. maxpathlen + finalcert + 1)
+ explicitPolicy = (maxPathLen == -1) ? maxPathLen : maxPathLen + 2;
+ }
+
+ /* Initialize policy mapping state variable */
+ if (buildParams.policyMappingInhibited()) {
+ policyMapping = 0;
+ } else {
+ policyMapping = (maxPathLen == -1) ? maxPathLen : maxPathLen + 2;
+ }
+
+ /* Initialize inhibit any policy state variable */
+ if (buildParams.anyPolicyInhibited()) {
+ inhibitAnyPolicy = 0;
+ } else {
+ inhibitAnyPolicy = (maxPathLen == -1) ? maxPathLen : maxPathLen + 2;
+ }
+
+ /* Initialize certIndex */
+ certIndex = 1;
+
+ /* Initialize policy tree */
+ Set<String> initExpPolSet = new HashSet<>(1);
+ initExpPolSet.add(PolicyChecker.ANY_POLICY);
+
+ rootNode = new PolicyNodeImpl(null, PolicyChecker.ANY_POLICY, null,
+ false, initExpPolSet, false);
+
+ /*
+ * Initialize each user-defined checker
+ * Shallow copy the checkers
+ */
+ userCheckers = new ArrayList<>(buildParams.certPathCheckers());
+ /* initialize each checker (just in case) */
+ for (PKIXCertPathChecker checker : userCheckers) {
+ checker.init(false);
+ }
+
+ /* Start by trusting the cert to sign CRLs */
+ crlSign = true;
+
+ init = true;
+ }
+
+ /**
+ * Update the state with the specified trust anchor.
+ *
+ * @param anchor the most-trusted CA
+ * @param buildParams builder parameters
+ */
+ public void updateState(TrustAnchor anchor, BuilderParams buildParams)
+ throws CertificateException, IOException, CertPathValidatorException
+ {
+ trustAnchor = anchor;
+ X509Certificate trustedCert = anchor.getTrustedCert();
+ if (trustedCert != null) {
+ updateState(trustedCert);
+ } else {
+ X500Principal caName = anchor.getCA();
+ updateState(anchor.getCAPublicKey(), caName);
+ }
+
+ // The user specified AlgorithmChecker and RevocationChecker may not be
+ // able to set the trust anchor until now.
+ boolean revCheckerAdded = false;
+ for (PKIXCertPathChecker checker : userCheckers) {
+ if (checker instanceof AlgorithmChecker) {
+ ((AlgorithmChecker)checker).trySetTrustAnchor(anchor);
+ } else if (checker instanceof PKIXRevocationChecker) {
+ if (revCheckerAdded) {
+ throw new CertPathValidatorException(
+ "Only one PKIXRevocationChecker can be specified");
+ }
+ // if it's our own, initialize it
+ if (checker instanceof RevocationChecker) {
+ ((RevocationChecker)checker).init(anchor, buildParams);
+ }
+ ((PKIXRevocationChecker)checker).init(false);
+ revCheckerAdded = true;
+ }
+ }
+
+ // only create a RevocationChecker if revocation is enabled and
+ // a PKIXRevocationChecker has not already been added
+ if (buildParams.revocationEnabled() && !revCheckerAdded) {
+ revChecker = new RevocationChecker(anchor, buildParams);
+ revChecker.init(false);
+ }
+
+ init = false;
+ }
+
+ /**
+ * Update the state. This method is used when the most-trusted CA is
+ * a trusted public-key and caName, instead of a trusted cert.
+ *
+ * @param pubKey the public key of the trusted CA
+ * @param subjectDN the subject distinguished name of the trusted CA
+ */
+ private void updateState(PublicKey pubKey, X500Principal subjectDN) {
+
+ /* update subject DN */
+ this.subjectDN = subjectDN;
+
+ /* update subject public key */
+ this.pubKey = pubKey;
+ }
+
+ /**
+ * Update the state with the next certificate added to the path.
+ *
+ * @param cert the certificate which is used to update the state
+ */
+ public void updateState(X509Certificate cert)
+ throws CertificateException, IOException, CertPathValidatorException {
+
+ if (cert == null) {
+ return;
+ }
+
+ /* update subject DN */
+ subjectDN = cert.getSubjectX500Principal();
+
+ /* check for key needing to inherit alg parameters */
+ X509CertImpl icert = X509CertImpl.toImpl(cert);
+ PublicKey newKey = cert.getPublicKey();
+ if (PKIX.isDSAPublicKeyWithoutParams(newKey)) {
+ newKey = BasicChecker.makeInheritedParamsKey(newKey, pubKey);
+ }
+
+ /* update subject public key */
+ pubKey = newKey;
+
+ /*
+ * if this is a trusted cert (init == true), then we
+ * don't update any of the remaining fields
+ */
+ if (init) {
+ init = false;
+ return;
+ }
+
+ /* update subject key identifier */
+ subjKeyId = icert.getSubjectKeyIdentifierExtension();
+
+ /* update crlSign */
+ crlSign = RevocationChecker.certCanSignCrl(cert);
+
+ /* update current name constraints */
+ if (nc != null) {
+ nc.merge(icert.getNameConstraintsExtension());
+ } else {
+ nc = icert.getNameConstraintsExtension();
+ if (nc != null) {
+ // Make sure we do a clone here, because we're probably
+ // going to modify this object later and we don't want to
+ // be sharing it with a Certificate object!
+ nc = (NameConstraintsExtension) nc.clone();
+ }
+ }
+
+ /* update policy state variables */
+ explicitPolicy =
+ PolicyChecker.mergeExplicitPolicy(explicitPolicy, icert, false);
+ policyMapping =
+ PolicyChecker.mergePolicyMapping(policyMapping, icert);
+ inhibitAnyPolicy =
+ PolicyChecker.mergeInhibitAnyPolicy(inhibitAnyPolicy, icert);
+ certIndex++;
+
+ /*
+ * Update remaining CA certs
+ */
+ remainingCACerts =
+ ConstraintsChecker.mergeBasicConstraints(cert, remainingCACerts);
+
+ init = false;
+ }
+
+ /**
+ * Returns a boolean flag indicating if a key lacking necessary key
+ * algorithm parameters has been encountered.
+ *
+ * @return boolean flag indicating if key lacking parameters encountered.
+ */
+ @Override
+ public boolean keyParamsNeeded() {
+ /* when building in reverse, we immediately get parameters needed
+ * or else throw an exception
+ */
+ return false;
+ }
+
+ /*
+ * Clone current state. The state is cloned as each cert is
+ * added to the path. This is necessary if backtracking occurs,
+ * and a prior state needs to be restored.
+ *
+ * Note that this is a SMART clone. Not all fields are fully copied,
+ * because some of them (e.g., subjKeyId) will
+ * not have their contents modified by subsequent calls to updateState.
+ */
+ @Override
+ @SuppressWarnings("unchecked") // Safe casts assuming clone() works correctly
+ public Object clone() {
+ try {
+ ReverseState clonedState = (ReverseState) super.clone();
+
+ /* clone checkers, if cloneable */
+ clonedState.userCheckers =
+ (ArrayList<PKIXCertPathChecker>)userCheckers.clone();
+ ListIterator<PKIXCertPathChecker> li =
+ clonedState.userCheckers.listIterator();
+ while (li.hasNext()) {
+ PKIXCertPathChecker checker = li.next();
+ if (checker instanceof Cloneable) {
+ li.set((PKIXCertPathChecker)checker.clone());
+ }
+ }
+
+ /* make copy of name constraints */
+ if (nc != null) {
+ clonedState.nc = (NameConstraintsExtension) nc.clone();
+ }
+
+ /* make copy of policy tree */
+ if (rootNode != null) {
+ clonedState.rootNode = rootNode.copyTree();
+ }
+
+ return clonedState;
+ } catch (CloneNotSupportedException e) {
+ throw new InternalError(e.toString(), e);
+ }
+ }
+}
diff --git a/ojluni/src/main/java/sun/security/provider/certpath/RevocationChecker.java b/ojluni/src/main/java/sun/security/provider/certpath/RevocationChecker.java
new file mode 100644
index 0000000..19b41f6
--- /dev/null
+++ b/ojluni/src/main/java/sun/security/provider/certpath/RevocationChecker.java
@@ -0,0 +1,1160 @@
+/*
+ * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * 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.io.IOException;
+import java.math.BigInteger;
+import java.net.URI;
+import java.net.URISyntaxException;
+import java.security.AccessController;
+import java.security.InvalidAlgorithmParameterException;
+import java.security.NoSuchAlgorithmException;
+import java.security.PrivilegedAction;
+import java.security.PublicKey;
+import java.security.Security;
+import java.security.cert.CertPathValidatorException.BasicReason;
+import java.security.cert.Extension;
+import java.security.cert.*;
+import java.util.*;
+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;
+
+class RevocationChecker extends PKIXRevocationChecker {
+
+ private static final Debug debug = Debug.getInstance("certpath");
+
+ private TrustAnchor anchor;
+ private ValidatorParams params;
+ private boolean onlyEE;
+ private boolean softFail;
+ private boolean crlDP;
+ private URI responderURI;
+ private X509Certificate responderCert;
+ private List<CertStore> certStores;
+ private Map<X509Certificate, byte[]> ocspResponses;
+ private List<Extension> ocspExtensions;
+ private boolean legacy;
+ private LinkedList<CertPathValidatorException> softFailExceptions =
+ new LinkedList<>();
+
+ // state variables
+ private X509Certificate issuerCert;
+ private PublicKey prevPubKey;
+ private boolean crlSignFlag;
+ private int certIndex;
+
+ private enum Mode { PREFER_OCSP, PREFER_CRLS, ONLY_CRLS, ONLY_OCSP };
+ private Mode mode = Mode.PREFER_OCSP;
+
+ private static class RevocationProperties {
+ boolean onlyEE;
+ boolean ocspEnabled;
+ boolean crlDPEnabled;
+ String ocspUrl;
+ String ocspSubject;
+ String ocspIssuer;
+ String ocspSerial;
+ }
+
+ RevocationChecker() {
+ legacy = false;
+ }
+
+ RevocationChecker(TrustAnchor anchor, ValidatorParams params)
+ throws CertPathValidatorException
+ {
+ legacy = true;
+ init(anchor, params);
+ }
+
+ void init(TrustAnchor anchor, ValidatorParams params)
+ throws CertPathValidatorException
+ {
+ RevocationProperties rp = getRevocationProperties();
+ URI uri = getOcspResponder();
+ responderURI = (uri == null) ? toURI(rp.ocspUrl) : uri;
+ X509Certificate cert = getOcspResponderCert();
+ responderCert = (cert == null)
+ ? getResponderCert(rp, params.trustAnchors(),
+ params.certStores())
+ : cert;
+ Set<Option> options = getOptions();
+ for (Option option : options) {
+ switch (option) {
+ case ONLY_END_ENTITY:
+ case PREFER_CRLS:
+ case SOFT_FAIL:
+ case NO_FALLBACK:
+ break;
+ default:
+ throw new CertPathValidatorException(
+ "Unrecognized revocation parameter option: " + option);
+ }
+ }
+ softFail = options.contains(Option.SOFT_FAIL);
+
+ // set mode, only end entity flag
+ if (legacy) {
+ mode = (rp.ocspEnabled) ? Mode.PREFER_OCSP : Mode.ONLY_CRLS;
+ onlyEE = rp.onlyEE;
+ } else {
+ if (options.contains(Option.NO_FALLBACK)) {
+ if (options.contains(Option.PREFER_CRLS)) {
+ mode = Mode.ONLY_CRLS;
+ } else {
+ mode = Mode.ONLY_OCSP;
+ }
+ } else if (options.contains(Option.PREFER_CRLS)) {
+ mode = Mode.PREFER_CRLS;
+ }
+ onlyEE = options.contains(Option.ONLY_END_ENTITY);
+ }
+ if (legacy) {
+ crlDP = rp.crlDPEnabled;
+ } else {
+ crlDP = true;
+ }
+ ocspResponses = getOcspResponses();
+ ocspExtensions = getOcspExtensions();
+
+ this.anchor = anchor;
+ this.params = params;
+ this.certStores = new ArrayList<>(params.certStores());
+ try {
+ this.certStores.add(CertStore.getInstance("Collection",
+ new CollectionCertStoreParameters(params.certificates())));
+ } catch (InvalidAlgorithmParameterException |
+ NoSuchAlgorithmException e) {
+ // should never occur but not necessarily fatal, so log it,
+ // ignore and continue
+ if (debug != null) {
+ debug.println("RevocationChecker: " +
+ "error creating Collection CertStore: " + e);
+ }
+ }
+ }
+
+ private static URI toURI(String uriString)
+ throws CertPathValidatorException
+ {
+ try {
+ if (uriString != null) {
+ return new URI(uriString);
+ }
+ return null;
+ } catch (URISyntaxException e) {
+ throw new CertPathValidatorException(
+ "cannot parse ocsp.responderURL property", e);
+ }
+ }
+
+ private static RevocationProperties getRevocationProperties() {
+ return AccessController.doPrivileged(
+ new PrivilegedAction<RevocationProperties>() {
+ public RevocationProperties run() {
+ RevocationProperties rp = new RevocationProperties();
+ String onlyEE = Security.getProperty(
+ "com.sun.security.onlyCheckRevocationOfEECert");
+ rp.onlyEE = onlyEE != null
+ && onlyEE.equalsIgnoreCase("true");
+ String ocspEnabled = Security.getProperty("ocsp.enable");
+ rp.ocspEnabled = ocspEnabled != null
+ && ocspEnabled.equalsIgnoreCase("true");
+ rp.ocspUrl = Security.getProperty("ocsp.responderURL");
+ rp.ocspSubject
+ = Security.getProperty("ocsp.responderCertSubjectName");
+ rp.ocspIssuer
+ = Security.getProperty("ocsp.responderCertIssuerName");
+ rp.ocspSerial
+ = Security.getProperty("ocsp.responderCertSerialNumber");
+ rp.crlDPEnabled
+ = Boolean.getBoolean("com.sun.security.enableCRLDP");
+ return rp;
+ }
+ }
+ );
+ }
+
+ private static X509Certificate getResponderCert(RevocationProperties rp,
+ Set<TrustAnchor> anchors,
+ List<CertStore> stores)
+ throws CertPathValidatorException
+ {
+ if (rp.ocspSubject != null) {
+ return getResponderCert(rp.ocspSubject, anchors, stores);
+ } else if (rp.ocspIssuer != null && rp.ocspSerial != null) {
+ return getResponderCert(rp.ocspIssuer, rp.ocspSerial,
+ anchors, stores);
+ } else if (rp.ocspIssuer != null || rp.ocspSerial != null) {
+ throw new CertPathValidatorException(
+ "Must specify both ocsp.responderCertIssuerName and " +
+ "ocsp.responderCertSerialNumber properties");
+ }
+ return null;
+ }
+
+ private static X509Certificate getResponderCert(String subject,
+ Set<TrustAnchor> anchors,
+ List<CertStore> stores)
+ throws CertPathValidatorException
+ {
+ X509CertSelector sel = new X509CertSelector();
+ try {
+ sel.setSubject(new X500Principal(subject));
+ } catch (IllegalArgumentException e) {
+ throw new CertPathValidatorException(
+ "cannot parse ocsp.responderCertSubjectName property", e);
+ }
+ return getResponderCert(sel, anchors, stores);
+ }
+
+ private static X509Certificate getResponderCert(String issuer,
+ String serial,
+ Set<TrustAnchor> anchors,
+ List<CertStore> stores)
+ throws CertPathValidatorException
+ {
+ X509CertSelector sel = new X509CertSelector();
+ try {
+ sel.setIssuer(new X500Principal(issuer));
+ } catch (IllegalArgumentException e) {
+ throw new CertPathValidatorException(
+ "cannot parse ocsp.responderCertIssuerName property", e);
+ }
+ try {
+ sel.setSerialNumber(new BigInteger(stripOutSeparators(serial), 16));
+ } catch (NumberFormatException e) {
+ throw new CertPathValidatorException(
+ "cannot parse ocsp.responderCertSerialNumber property", e);
+ }
+ return getResponderCert(sel, anchors, stores);
+ }
+
+ private static X509Certificate getResponderCert(X509CertSelector sel,
+ Set<TrustAnchor> anchors,
+ List<CertStore> stores)
+ throws CertPathValidatorException
+ {
+ // first check TrustAnchors
+ for (TrustAnchor anchor : anchors) {
+ X509Certificate cert = anchor.getTrustedCert();
+ if (cert == null) {
+ continue;
+ }
+ if (sel.match(cert)) {
+ return cert;
+ }
+ }
+ // now check CertStores
+ for (CertStore store : stores) {
+ try {
+ Collection<? extends Certificate> certs =
+ store.getCertificates(sel);
+ if (!certs.isEmpty()) {
+ return (X509Certificate)certs.iterator().next();
+ }
+ } catch (CertStoreException e) {
+ // ignore and try next CertStore
+ if (debug != null) {
+ debug.println("CertStore exception:" + e);
+ }
+ continue;
+ }
+ }
+ throw new CertPathValidatorException(
+ "Cannot find the responder's certificate " +
+ "(set using the OCSP security properties).");
+ }
+
+ @Override
+ public void init(boolean forward) throws CertPathValidatorException {
+ if (forward) {
+ throw new
+ CertPathValidatorException("forward checking not supported");
+ }
+ if (anchor != null) {
+ issuerCert = anchor.getTrustedCert();
+ prevPubKey = (issuerCert != null) ? issuerCert.getPublicKey()
+ : anchor.getCAPublicKey();
+ }
+ crlSignFlag = true;
+ if (params != null && params.certPath() != null) {
+ certIndex = params.certPath().getCertificates().size() - 1;
+ } else {
+ certIndex = -1;
+ }
+ softFailExceptions.clear();
+ }
+
+ @Override
+ public boolean isForwardCheckingSupported() {
+ return false;
+ }
+
+ @Override
+ public Set<String> getSupportedExtensions() {
+ return null;
+ }
+
+ @Override
+ public List<CertPathValidatorException> getSoftFailExceptions() {
+ return Collections.unmodifiableList(softFailExceptions);
+ }
+
+ @Override
+ public void check(Certificate cert, Collection<String> unresolvedCritExts)
+ throws CertPathValidatorException
+ {
+ check((X509Certificate)cert, unresolvedCritExts,
+ prevPubKey, crlSignFlag);
+ }
+
+ private void check(X509Certificate xcert,
+ Collection<String> unresolvedCritExts,
+ PublicKey pubKey, boolean crlSignFlag)
+ throws CertPathValidatorException
+ {
+ try {
+ if (onlyEE && xcert.getBasicConstraints() != -1) {
+ if (debug != null) {
+ debug.println("Skipping revocation check, not end " +
+ "entity cert");
+ }
+ return;
+ }
+ switch (mode) {
+ case PREFER_OCSP:
+ case ONLY_OCSP:
+ checkOCSP(xcert, unresolvedCritExts);
+ break;
+ case PREFER_CRLS:
+ case ONLY_CRLS:
+ checkCRLs(xcert, unresolvedCritExts, null,
+ pubKey, crlSignFlag);
+ break;
+ }
+ } catch (CertPathValidatorException e) {
+ if (e.getReason() == BasicReason.REVOKED) {
+ throw e;
+ }
+ boolean eSoftFail = isSoftFailException(e);
+ if (eSoftFail) {
+ if (mode == Mode.ONLY_OCSP || mode == Mode.ONLY_CRLS) {
+ return;
+ }
+ } else {
+ if (mode == Mode.ONLY_OCSP || mode == Mode.ONLY_CRLS) {
+ throw e;
+ }
+ }
+ CertPathValidatorException cause = e;
+ // Otherwise, failover
+ if (debug != null) {
+ debug.println("RevocationChecker.check() " + e.getMessage());
+ debug.println("RevocationChecker.check() preparing to failover");
+ }
+ try {
+ switch (mode) {
+ case PREFER_OCSP:
+ checkCRLs(xcert, unresolvedCritExts, null,
+ pubKey, crlSignFlag);
+ break;
+ case PREFER_CRLS:
+ checkOCSP(xcert, unresolvedCritExts);
+ break;
+ }
+ } catch (CertPathValidatorException x) {
+ if (debug != null) {
+ debug.println("RevocationChecker.check() failover failed");
+ debug.println("RevocationChecker.check() " + x.getMessage());
+ }
+ if (x.getReason() == BasicReason.REVOKED) {
+ throw x;
+ }
+ if (!isSoftFailException(x)) {
+ cause.addSuppressed(x);
+ throw cause;
+ } else {
+ // only pass if both exceptions were soft failures
+ if (!eSoftFail) {
+ throw cause;
+ }
+ }
+ }
+ } finally {
+ updateState(xcert);
+ }
+ }
+
+ private boolean isSoftFailException(CertPathValidatorException e) {
+ if (softFail &&
+ e.getReason() == BasicReason.UNDETERMINED_REVOCATION_STATUS)
+ {
+ // recreate exception with correct index
+ CertPathValidatorException e2 = new CertPathValidatorException(
+ e.getMessage(), e.getCause(), params.certPath(), certIndex,
+ e.getReason());
+ softFailExceptions.addFirst(e2);
+ return true;
+ }
+ return false;
+ }
+
+ private void updateState(X509Certificate cert)
+ throws CertPathValidatorException
+ {
+ issuerCert = cert;
+
+ // Make new public key if parameters are missing
+ PublicKey pubKey = cert.getPublicKey();
+ if (PKIX.isDSAPublicKeyWithoutParams(pubKey)) {
+ // pubKey needs to inherit DSA parameters from prev key
+ pubKey = BasicChecker.makeInheritedParamsKey(pubKey, prevPubKey);
+ }
+ prevPubKey = pubKey;
+ crlSignFlag = certCanSignCrl(cert);
+ if (certIndex > 0) {
+ certIndex--;
+ }
+ }
+
+ // Maximum clock skew in milliseconds (15 minutes) allowed when checking
+ // validity of CRLs
+ private static final long MAX_CLOCK_SKEW = 900000;
+ private void checkCRLs(X509Certificate cert,
+ Collection<String> unresolvedCritExts,
+ Set<X509Certificate> stackedCerts,
+ PublicKey pubKey, boolean signFlag)
+ throws CertPathValidatorException
+ {
+ checkCRLs(cert, pubKey, null, signFlag, true,
+ stackedCerts, params.trustAnchors());
+ }
+
+ private void checkCRLs(X509Certificate cert, PublicKey prevKey,
+ X509Certificate prevCert, boolean signFlag,
+ boolean allowSeparateKey,
+ Set<X509Certificate> stackedCerts,
+ Set<TrustAnchor> anchors)
+ throws CertPathValidatorException
+ {
+ if (debug != null) {
+ debug.println("RevocationChecker.checkCRLs()" +
+ " ---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.
+ if (stackedCerts != null && stackedCerts.contains(cert)) {
+ if (debug != null) {
+ debug.println("RevocationChecker.checkCRLs()" +
+ " circular dependency");
+ }
+ throw new CertPathValidatorException
+ ("Could not determine revocation status", null, null, -1,
+ BasicReason.UNDETERMINED_REVOCATION_STATUS);
+ }
+
+ Set<X509CRL> possibleCRLs = new HashSet<>();
+ Set<X509CRL> approvedCRLs = new HashSet<>();
+ X509CRLSelector sel = new X509CRLSelector();
+ sel.setCertificateChecking(cert);
+ CertPathHelper.setDateAndTime(sel, params.date(), MAX_CLOCK_SKEW);
+
+ // First, check user-specified CertStores
+ CertPathValidatorException networkFailureException = null;
+ for (CertStore store : certStores) {
+ try {
+ for (CRL crl : store.getCRLs(sel)) {
+ possibleCRLs.add((X509CRL)crl);
+ }
+ } catch (CertStoreException e) {
+ if (debug != null) {
+ debug.println("RevocationChecker.checkCRLs() " +
+ "CertStoreException: " + e.getMessage());
+ }
+ if (networkFailureException == null &&
+ CertStoreHelper.isCausedByNetworkIssue(store.getType(),e)) {
+ // save this exception, we may need to throw it later
+ networkFailureException = new CertPathValidatorException(
+ "Unable to determine revocation status due to " +
+ "network error", e, null, -1,
+ BasicReason.UNDETERMINED_REVOCATION_STATUS);
+ }
+ }
+ }
+
+ if (debug != null) {
+ debug.println("RevocationChecker.checkCRLs() " +
+ "possible crls.size() = " + possibleCRLs.size());
+ }
+ boolean[] reasonsMask = new boolean[9];
+ if (!possibleCRLs.isEmpty()) {
+ // Now that we have a list of possible CRLs, see which ones can
+ // be approved
+ approvedCRLs.addAll(verifyPossibleCRLs(possibleCRLs, cert, prevKey,
+ signFlag, reasonsMask,
+ anchors));
+ }
+
+ if (debug != null) {
+ debug.println("RevocationChecker.checkCRLs() " +
+ "approved crls.size() = " + approvedCRLs.size());
+ }
+
+ // make sure that we have at least one CRL that _could_ cover
+ // the certificate in question and all reasons are covered
+ if (!approvedCRLs.isEmpty() &&
+ Arrays.equals(reasonsMask, ALL_REASONS))
+ {
+ checkApprovedCRLs(cert, approvedCRLs);
+ } else {
+ // Check Distribution Points
+ // all CRLs returned by the DP Fetcher have also been verified
+ try {
+ if (crlDP) {
+ approvedCRLs.addAll(DistributionPointFetcher.getCRLs(
+ sel, signFlag, prevKey, prevCert,
+ params.sigProvider(), certStores,
+ reasonsMask, anchors, null));
+ }
+ } catch (CertStoreException e) {
+ if (e instanceof CertStoreTypeException) {
+ CertStoreTypeException cste = (CertStoreTypeException)e;
+ if (CertStoreHelper.isCausedByNetworkIssue(cste.getType(),
+ e)) {
+ throw new CertPathValidatorException(
+ "Unable to determine revocation status due to " +
+ "network error", e, null, -1,
+ BasicReason.UNDETERMINED_REVOCATION_STATUS);
+ }
+ }
+ throw new CertPathValidatorException(e);
+ }
+ if (!approvedCRLs.isEmpty() &&
+ Arrays.equals(reasonsMask, ALL_REASONS))
+ {
+ checkApprovedCRLs(cert, approvedCRLs);
+ } else {
+ if (allowSeparateKey) {
+ try {
+ verifyWithSeparateSigningKey(cert, prevKey, signFlag,
+ stackedCerts);
+ return;
+ } catch (CertPathValidatorException cpve) {
+ if (networkFailureException != null) {
+ // if a network issue previously prevented us from
+ // retrieving a CRL from one of the user-specified
+ // CertStores, throw it now so it can be handled
+ // appropriately
+ throw networkFailureException;
+ }
+ throw cpve;
+ }
+ } else {
+ if (networkFailureException != null) {
+ // if a network issue previously prevented us from
+ // retrieving a CRL from one of the user-specified
+ // CertStores, throw it now so it can be handled
+ // appropriately
+ throw networkFailureException;
+ }
+ throw new CertPathValidatorException(
+ "Could not determine revocation status", null, null, -1,
+ BasicReason.UNDETERMINED_REVOCATION_STATUS);
+ }
+ }
+ }
+ }
+
+ private void checkApprovedCRLs(X509Certificate cert,
+ Set<X509CRL> approvedCRLs)
+ throws CertPathValidatorException
+ {
+ // See if the cert is in the set of approved crls.
+ if (debug != null) {
+ BigInteger sn = cert.getSerialNumber();
+ debug.println("RevocationChecker.checkApprovedCRLs() " +
+ "starting the final sweep...");
+ debug.println("RevocationChecker.checkApprovedCRLs()" +
+ " cert SN: " + sn.toString());
+ }
+
+ CRLReason reasonCode = CRLReason.UNSPECIFIED;
+ X509CRLEntryImpl entry = null;
+ for (X509CRL crl : approvedCRLs) {
+ X509CRLEntry e = crl.getRevokedCertificate(cert);
+ if (e != null) {
+ try {
+ entry = X509CRLEntryImpl.toImpl(e);
+ } catch (CRLException ce) {
+ throw new CertPathValidatorException(ce);
+ }
+ if (debug != null) {
+ debug.println("RevocationChecker.checkApprovedCRLs()"
+ + " CRL entry: " + entry.toString());
+ }
+
+ /*
+ * Abort CRL validation and throw exception if there are any
+ * unrecognized critical CRL entry extensions (see section
+ * 5.3 of RFC 3280).
+ */
+ Set<String> unresCritExts = entry.getCriticalExtensionOIDs();
+ if (unresCritExts != null && !unresCritExts.isEmpty()) {
+ /* remove any that we will process */
+ unresCritExts.remove(ReasonCode_Id.toString());
+ unresCritExts.remove(CertificateIssuer_Id.toString());
+ if (!unresCritExts.isEmpty()) {
+ throw new CertPathValidatorException(
+ "Unrecognized critical extension(s) in revoked " +
+ "CRL entry");
+ }
+ }
+
+ reasonCode = entry.getRevocationReason();
+ if (reasonCode == null) {
+ reasonCode = CRLReason.UNSPECIFIED;
+ }
+ Date revocationDate = entry.getRevocationDate();
+ if (revocationDate.before(params.date())) {
+ Throwable t = new CertificateRevokedException(
+ revocationDate, reasonCode,
+ crl.getIssuerX500Principal(), entry.getExtensions());
+ throw new CertPathValidatorException(
+ t.getMessage(), t, null, -1, BasicReason.REVOKED);
+ }
+ }
+ }
+ }
+
+ private void checkOCSP(X509Certificate cert,
+ Collection<String> unresolvedCritExts)
+ throws CertPathValidatorException
+ {
+ X509CertImpl currCert = null;
+ try {
+ currCert = X509CertImpl.toImpl(cert);
+ } catch (CertificateException ce) {
+ throw new CertPathValidatorException(ce);
+ }
+
+ // The algorithm constraints of the OCSP trusted responder certificate
+ // does not need to be checked in this code. The constraints will be
+ // checked when the responder's certificate is validated.
+
+ 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());
+ }
+
+ // check if there is a cached OCSP response available
+ byte[] responseBytes = ocspResponses.get(cert);
+ if (responseBytes != null) {
+ if (debug != null) {
+ debug.println("Found cached OCSP response");
+ }
+ response = new OCSPResponse(responseBytes);
+
+ // verify the response
+ byte[] nonce = null;
+ for (Extension ext : ocspExtensions) {
+ if (ext.getId().equals("1.3.6.1.5.5.7.48.1.2")) {
+ nonce = ext.getValue();
+ }
+ }
+ response.verify(Collections.singletonList(certId), issuerCert,
+ responderCert, params.date(), nonce);
+
+ } else {
+ URI responderURI = (this.responderURI != null)
+ ? this.responderURI
+ : OCSP.getResponderURI(currCert);
+ if (responderURI == null) {
+ throw new CertPathValidatorException(
+ "Certificate does not specify OCSP responder", null,
+ null, -1);
+ }
+
+ response = OCSP.check(Collections.singletonList(certId),
+ responderURI, issuerCert, responderCert,
+ null, ocspExtensions);
+ }
+ } catch (IOException e) {
+ throw new CertPathValidatorException(
+ "Unable to determine revocation status due to network error",
+ e, null, -1, BasicReason.UNDETERMINED_REVOCATION_STATUS);
+ }
+
+ RevocationStatus rs =
+ (RevocationStatus)response.getSingleResponse(certId);
+ RevocationStatus.CertStatus certStatus = rs.getCertStatus();
+ if (certStatus == RevocationStatus.CertStatus.REVOKED) {
+ Date revocationTime = rs.getRevocationTime();
+ if (revocationTime.before(params.date())) {
+ Throwable t = new CertificateRevokedException(
+ revocationTime, rs.getRevocationReason(),
+ response.getSignerCertificate().getSubjectX500Principal(),
+ rs.getSingleExtensions());
+ throw new CertPathValidatorException(t.getMessage(), t, null,
+ -1, BasicReason.REVOKED);
+ }
+ } else if (certStatus == RevocationStatus.CertStatus.UNKNOWN) {
+ throw new CertPathValidatorException(
+ "Certificate's revocation status is unknown", null,
+ params.certPath(), -1,
+ BasicReason.UNDETERMINED_REVOCATION_STATUS);
+ }
+ }
+
+ /*
+ * Removes any non-hexadecimal characters from a string.
+ */
+ private static final String HEX_DIGITS = "0123456789ABCDEFabcdef";
+ private static String stripOutSeparators(String value) {
+ char[] chars = value.toCharArray();
+ StringBuilder hexNumber = new StringBuilder();
+ for (int i = 0; i < chars.length; i++) {
+ if (HEX_DIGITS.indexOf(chars[i]) != -1) {
+ hexNumber.append(chars[i]);
+ }
+ }
+ return hexNumber.toString();
+ }
+
+ /**
+ * Checks that a cert can be used to verify a CRL.
+ *
+ * @param cert an X509Certificate to check
+ * @return a boolean specifying if the cert is allowed to vouch for the
+ * validity of a CRL
+ */
+ static boolean certCanSignCrl(X509Certificate cert) {
+ // if the cert doesn't include the key usage ext, or
+ // the key usage ext asserts cRLSigning, return true,
+ // otherwise return false.
+ boolean[] keyUsage = cert.getKeyUsage();
+ if (keyUsage != null) {
+ return keyUsage[6];
+ }
+ return false;
+ }
+
+ /**
+ * Internal method that verifies a set of possible_crls,
+ * and sees if each is approved, based on the cert.
+ *
+ * @param crls a set of possible CRLs to test for acceptability
+ * @param cert the certificate whose revocation status is being checked
+ * @param signFlag <code>true</code> if prevKey was trusted to sign CRLs
+ * @param prevKey the public key of the issuer of cert
+ * @param reasonsMask the reason code mask
+ * @param trustAnchors a <code>Set</code> of <code>TrustAnchor</code>s>
+ * @return a collection of approved crls (or an empty collection)
+ */
+ private static final boolean[] ALL_REASONS =
+ {true, true, true, true, true, true, true, true, true};
+ private Collection<X509CRL> verifyPossibleCRLs(Set<X509CRL> crls,
+ X509Certificate cert,
+ PublicKey prevKey,
+ boolean signFlag,
+ boolean[] reasonsMask,
+ Set<TrustAnchor> anchors)
+ throws CertPathValidatorException
+ {
+ try {
+ X509CertImpl certImpl = X509CertImpl.toImpl(cert);
+ if (debug != null) {
+ debug.println("RevocationChecker.verifyPossibleCRLs: " +
+ "Checking CRLDPs for "
+ + certImpl.getSubjectX500Principal());
+ }
+ CRLDistributionPointsExtension ext =
+ certImpl.getCRLDistributionPointsExtension();
+ List<DistributionPoint> points = null;
+ if (ext == null) {
+ // assume a DP with reasons and CRLIssuer fields omitted
+ // and a DP name of the cert issuer.
+ // TODO add issuerAltName too
+ X500Name certIssuer = (X500Name)certImpl.getIssuerDN();
+ DistributionPoint point = new DistributionPoint(
+ new GeneralNames().add(new GeneralName(certIssuer)),
+ null, null);
+ points = Collections.singletonList(point);
+ } else {
+ points = ext.get(CRLDistributionPointsExtension.POINTS);
+ }
+ Set<X509CRL> results = new HashSet<>();
+ for (DistributionPoint point : points) {
+ for (X509CRL crl : crls) {
+ if (DistributionPointFetcher.verifyCRL(
+ certImpl, point, crl, reasonsMask, signFlag,
+ prevKey, null, params.sigProvider(), anchors,
+ certStores, params.date()))
+ {
+ results.add(crl);
+ }
+ }
+ if (Arrays.equals(reasonsMask, ALL_REASONS))
+ break;
+ }
+ return results;
+ } catch (CertificateException | CRLException | IOException e) {
+ if (debug != null) {
+ debug.println("Exception while verifying CRL: "+e.getMessage());
+ e.printStackTrace();
+ }
+ return Collections.emptySet();
+ }
+ }
+
+ /**
+ * We have a cert whose revocation status couldn't be verified by
+ * a CRL issued by the cert that issued the CRL. See if we can
+ * find a valid CRL issued by a separate key that can verify the
+ * revocation status of this certificate.
+ * <p>
+ * Note that this does not provide support for indirect CRLs,
+ * only CRLs signed with a different key (but the same issuer
+ * name) as the certificate being checked.
+ *
+ * @param currCert the <code>X509Certificate</code> to be checked
+ * @param prevKey the <code>PublicKey</code> that failed
+ * @param signFlag <code>true</code> if that key was trusted to sign CRLs
+ * @param stackedCerts a <code>Set</code> of <code>X509Certificate</code>s>
+ * whose revocation status depends on the
+ * non-revoked status of this cert. To avoid
+ * circular dependencies, we assume they're
+ * revoked while checking the revocation
+ * status of this cert.
+ * @throws CertPathValidatorException if the cert's revocation status
+ * cannot be verified successfully with another key
+ */
+ private void verifyWithSeparateSigningKey(X509Certificate cert,
+ PublicKey prevKey,
+ boolean signFlag,
+ Set<X509Certificate> stackedCerts)
+ throws CertPathValidatorException
+ {
+ String msg = "revocation status";
+ if (debug != null) {
+ debug.println(
+ "RevocationChecker.verifyWithSeparateSigningKey()" +
+ " ---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.
+ if ((stackedCerts != null) && stackedCerts.contains(cert)) {
+ if (debug != null) {
+ debug.println(
+ "RevocationChecker.verifyWithSeparateSigningKey()" +
+ " circular dependency");
+ }
+ throw new CertPathValidatorException
+ ("Could not determine revocation status", null, null, -1,
+ BasicReason.UNDETERMINED_REVOCATION_STATUS);
+ }
+
+ // Try to find another key that might be able to sign
+ // CRLs vouching for this cert.
+ // If prevKey wasn't trusted, maybe we just didn't have the right
+ // path to it. Don't rule that key out.
+ if (!signFlag) {
+ buildToNewKey(cert, null, stackedCerts);
+ } else {
+ buildToNewKey(cert, prevKey, stackedCerts);
+ }
+ }
+
+ /**
+ * Tries to find a CertPath that establishes a key that can be
+ * used to verify the revocation status of a given certificate.
+ * Ignores keys that have previously been tried. Throws a
+ * CertPathValidatorException if no such key could be found.
+ *
+ * @param currCert the <code>X509Certificate</code> to be checked
+ * @param prevKey the <code>PublicKey</code> of the certificate whose key
+ * cannot be used to vouch for the CRL and should be ignored
+ * @param stackedCerts a <code>Set</code> of <code>X509Certificate</code>s>
+ * whose revocation status depends on the
+ * establishment of this path.
+ * @throws CertPathValidatorException on failure
+ */
+ private static final boolean [] CRL_SIGN_USAGE =
+ { false, false, false, false, false, false, true };
+ private void buildToNewKey(X509Certificate currCert,
+ PublicKey prevKey,
+ Set<X509Certificate> stackedCerts)
+ throws CertPathValidatorException
+ {
+
+ if (debug != null) {
+ debug.println("RevocationChecker.buildToNewKey()" +
+ " starting work");
+ }
+ Set<PublicKey> badKeys = new HashSet<>();
+ if (prevKey != null) {
+ badKeys.add(prevKey);
+ }
+ X509CertSelector certSel = new RejectKeySelector(badKeys);
+ certSel.setSubject(currCert.getIssuerX500Principal());
+ certSel.setKeyUsage(CRL_SIGN_USAGE);
+
+ Set<TrustAnchor> newAnchors = anchor == null ?
+ params.trustAnchors() :
+ Collections.singleton(anchor);
+
+ PKIXBuilderParameters builderParams;
+ try {
+ builderParams = new PKIXBuilderParameters(newAnchors, certSel);
+ } catch (InvalidAlgorithmParameterException iape) {
+ throw new RuntimeException(iape); // should never occur
+ }
+ builderParams.setInitialPolicies(params.initialPolicies());
+ builderParams.setCertStores(certStores);
+ builderParams.setExplicitPolicyRequired
+ (params.explicitPolicyRequired());
+ builderParams.setPolicyMappingInhibited
+ (params.policyMappingInhibited());
+ builderParams.setAnyPolicyInhibited(params.anyPolicyInhibited());
+ // Policy qualifiers must be rejected, since we don't have
+ // any way to convey them back to the application.
+ // That's the default, so no need to write code.
+ builderParams.setDate(params.date());
+ // CertPathCheckers need to be cloned to start from fresh state
+ builderParams.setCertPathCheckers(
+ params.getPKIXParameters().getCertPathCheckers());
+ builderParams.setSigProvider(params.sigProvider());
+
+ // Skip revocation during this build to detect circular
+ // references. But check revocation afterwards, using the
+ // key (or any other that works).
+ builderParams.setRevocationEnabled(false);
+
+ // check for AuthorityInformationAccess extension
+ if (Builder.USE_AIA == true) {
+ X509CertImpl currCertImpl = null;
+ try {
+ currCertImpl = X509CertImpl.toImpl(currCert);
+ } catch (CertificateException ce) {
+ // ignore but log it
+ if (debug != null) {
+ debug.println("RevocationChecker.buildToNewKey: " +
+ "error decoding cert: " + ce);
+ }
+ }
+ AuthorityInfoAccessExtension aiaExt = null;
+ if (currCertImpl != null) {
+ aiaExt = currCertImpl.getAuthorityInfoAccessExtension();
+ }
+ if (aiaExt != null) {
+ List<AccessDescription> adList = aiaExt.getAccessDescriptions();
+ if (adList != null) {
+ for (AccessDescription ad : adList) {
+ CertStore cs = URICertStore.getInstance(ad);
+ if (cs != null) {
+ if (debug != null) {
+ debug.println("adding AIAext CertStore");
+ }
+ builderParams.addCertStore(cs);
+ }
+ }
+ }
+ }
+ }
+
+ CertPathBuilder builder = null;
+ try {
+ builder = CertPathBuilder.getInstance("PKIX");
+ } catch (NoSuchAlgorithmException nsae) {
+ throw new CertPathValidatorException(nsae);
+ }
+ while (true) {
+ try {
+ if (debug != null) {
+ debug.println("RevocationChecker.buildToNewKey()" +
+ " about to try build ...");
+ }
+ PKIXCertPathBuilderResult cpbr =
+ (PKIXCertPathBuilderResult)builder.build(builderParams);
+
+ if (debug != null) {
+ debug.println("RevocationChecker.buildToNewKey()" +
+ " about to check revocation ...");
+ }
+ // Now check revocation of all certs in path, assuming that
+ // the stackedCerts are revoked.
+ if (stackedCerts == null) {
+ stackedCerts = new HashSet<X509Certificate>();
+ }
+ stackedCerts.add(currCert);
+ TrustAnchor ta = cpbr.getTrustAnchor();
+ PublicKey prevKey2 = ta.getCAPublicKey();
+ if (prevKey2 == null) {
+ prevKey2 = ta.getTrustedCert().getPublicKey();
+ }
+ boolean signFlag = true;
+ List<? extends Certificate> cpList =
+ cpbr.getCertPath().getCertificates();
+ try {
+ for (int i = cpList.size()-1; i >= 0; i-- ) {
+ X509Certificate cert = (X509Certificate)cpList.get(i);
+
+ if (debug != null) {
+ debug.println("RevocationChecker.buildToNewKey()"
+ + " index " + i + " checking "
+ + cert);
+ }
+ checkCRLs(cert, prevKey2, null, signFlag, true,
+ stackedCerts, newAnchors);
+ signFlag = certCanSignCrl(cert);
+ prevKey2 = cert.getPublicKey();
+ }
+ } catch (CertPathValidatorException cpve) {
+ // ignore it and try to get another key
+ badKeys.add(cpbr.getPublicKey());
+ continue;
+ }
+
+ if (debug != null) {
+ debug.println("RevocationChecker.buildToNewKey()" +
+ " got key " + cpbr.getPublicKey());
+ }
+ // Now check revocation on the current cert using that key and
+ // the corresponding certificate.
+ // If it doesn't check out, try to find a different key.
+ // And if we can't find a key, then return false.
+ PublicKey newKey = cpbr.getPublicKey();
+ try {
+ checkCRLs(currCert, newKey, (X509Certificate) cpList.get(0),
+ true, false, null, params.trustAnchors());
+ // If that passed, the cert is OK!
+ return;
+ } catch (CertPathValidatorException cpve) {
+ // If it is revoked, rethrow exception
+ if (cpve.getReason() == BasicReason.REVOKED) {
+ throw cpve;
+ }
+ // Otherwise, ignore the exception and
+ // try to get another key.
+ }
+ badKeys.add(newKey);
+ } catch (InvalidAlgorithmParameterException iape) {
+ throw new CertPathValidatorException(iape);
+ } catch (CertPathBuilderException cpbe) {
+ throw new CertPathValidatorException
+ ("Could not determine revocation status", null, null,
+ -1, BasicReason.UNDETERMINED_REVOCATION_STATUS);
+ }
+ }
+ }
+
+ @Override
+ public RevocationChecker clone() {
+ RevocationChecker copy = (RevocationChecker)super.clone();
+ // we don't deep-copy the exceptions, but that is ok because they
+ // are never modified after they are instantiated
+ copy.softFailExceptions = new LinkedList<>(softFailExceptions);
+ return copy;
+ }
+
+ /*
+ * This inner class extends the X509CertSelector to add an additional
+ * check to make sure the subject public key isn't on a particular list.
+ * This class is used by buildToNewKey() to make sure the builder doesn't
+ * end up with a CertPath to a public key that has already been rejected.
+ */
+ private static class RejectKeySelector extends X509CertSelector {
+ private final Set<PublicKey> badKeySet;
+
+ /**
+ * Creates a new <code>RejectKeySelector</code>.
+ *
+ * @param badPublicKeys a <code>Set</code> of
+ * <code>PublicKey</code>s that
+ * should be rejected (or <code>null</code>
+ * if no such check should be done)
+ */
+ RejectKeySelector(Set<PublicKey> badPublicKeys) {
+ this.badKeySet = badPublicKeys;
+ }
+
+ /**
+ * Decides whether a <code>Certificate</code> should be selected.
+ *
+ * @param cert the <code>Certificate</code> to be checked
+ * @return <code>true</code> if the <code>Certificate</code> should be
+ * selected, <code>false</code> otherwise
+ */
+ @Override
+ public boolean match(Certificate cert) {
+ if (!super.match(cert))
+ return(false);
+
+ if (badKeySet.contains(cert.getPublicKey())) {
+ if (debug != null)
+ debug.println("RejectKeySelector.match: bad key");
+ return false;
+ }
+
+ if (debug != null)
+ debug.println("RejectKeySelector.match: returning true");
+ return true;
+ }
+
+ /**
+ * Return a printable representation of the <code>CertSelector</code>.
+ *
+ * @return a <code>String</code> describing the contents of the
+ * <code>CertSelector</code>
+ */
+ @Override
+ public String toString() {
+ StringBuilder sb = new StringBuilder();
+ sb.append("RejectKeySelector: [\n");
+ sb.append(super.toString());
+ sb.append(badKeySet);
+ sb.append("]");
+ return sb.toString();
+ }
+ }
+}
diff --git a/ojluni/src/main/java/sun/security/provider/certpath/State.java b/ojluni/src/main/java/sun/security/provider/certpath/State.java
new file mode 100644
index 0000000..93a153f
--- /dev/null
+++ b/ojluni/src/main/java/sun/security/provider/certpath/State.java
@@ -0,0 +1,73 @@
+/*
+ * Copyright (c) 2000, 2001, 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.io.IOException;
+import java.security.cert.CertificateException;
+import java.security.cert.X509Certificate;
+import java.security.cert.CertPathValidatorException;
+
+/**
+ * A specification of a PKIX validation state
+ * which is initialized by each build and updated each time a
+ * certificate is added to the current path.
+ *
+ * @since 1.4
+ * @author Sean Mullan
+ * @author Yassir Elley
+ */
+
+interface State extends Cloneable {
+
+ /**
+ * Update the state with the next certificate added to the path.
+ *
+ * @param cert the certificate which is used to update the state
+ */
+ public void updateState(X509Certificate cert)
+ throws CertificateException, IOException, CertPathValidatorException;
+
+ /**
+ * Creates and returns a copy of this object
+ */
+ public Object clone();
+
+ /**
+ * Returns a boolean flag indicating if the state is initial
+ * (just starting)
+ *
+ * @return boolean flag indicating if the state is initial (just starting)
+ */
+ public boolean isInitial();
+
+ /**
+ * Returns a boolean flag indicating if a key lacking necessary key
+ * algorithm parameters has been encountered.
+ *
+ * @return boolean flag indicating if key lacking parameters encountered.
+ */
+ public boolean keyParamsNeeded();
+}
diff --git a/ojluni/src/main/java/sun/security/provider/certpath/SunCertPathBuilder.java b/ojluni/src/main/java/sun/security/provider/certpath/SunCertPathBuilder.java
new file mode 100644
index 0000000..3950760
--- /dev/null
+++ b/ojluni/src/main/java/sun/security/provider/certpath/SunCertPathBuilder.java
@@ -0,0 +1,804 @@
+/*
+ * Copyright (c) 2000, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * 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.io.IOException;
+import java.security.GeneralSecurityException;
+import java.security.InvalidAlgorithmParameterException;
+import java.security.PublicKey;
+import java.security.cert.*;
+import java.security.cert.CertPathValidatorException.BasicReason;
+import java.security.cert.PKIXReason;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.List;
+import java.util.LinkedList;
+import java.util.Set;
+import javax.security.auth.x500.X500Principal;
+
+import sun.security.provider.certpath.PKIX.BuilderParams;
+import static sun.security.x509.PKIXExtensions.*;
+import sun.security.util.Debug;
+
+/**
+ * This class is able to build certification paths in either the forward
+ * or reverse directions.
+ *
+ * <p> 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.
+ *
+ * <p> This implementation uses a depth-first search approach to finding
+ * certification paths. If it comes to a point in which it cannot find
+ * any more certificates leading to the target OR the path length is too long
+ * it backtracks to previous paths until the target has been found or
+ * all possible paths have been exhausted.
+ *
+ * <p> This implementation is not thread-safe.
+ *
+ * @since 1.4
+ * @author Sean Mullan
+ * @author Yassir Elley
+ */
+public final class SunCertPathBuilder extends CertPathBuilderSpi {
+
+ private static final Debug debug = Debug.getInstance("certpath");
+
+ /*
+ * private objects shared by methods
+ */
+ private BuilderParams buildParams;
+ private CertificateFactory cf;
+ private boolean pathCompleted = false;
+ private PolicyNode policyTreeResult;
+ private TrustAnchor trustAnchor;
+ private PublicKey finalPublicKey;
+
+ /**
+ * Create an instance of <code>SunCertPathBuilder</code>.
+ *
+ * @throws CertPathBuilderException if an error occurs
+ */
+ public SunCertPathBuilder() throws CertPathBuilderException {
+ try {
+ cf = CertificateFactory.getInstance("X.509");
+ } catch (CertificateException e) {
+ throw new CertPathBuilderException(e);
+ }
+ }
+
+ @Override
+ public CertPathChecker engineGetRevocationChecker() {
+ return new RevocationChecker();
+ }
+
+ /**
+ * Attempts to build a certification path using the Sun build
+ * algorithm from a trusted anchor(s) to a target subject, which must both
+ * be specified in the input parameter set. By default, this method will
+ * attempt to build in the forward direction. In order to build in the
+ * reverse direction, the caller needs to pass in an instance of
+ * SunCertPathBuilderParameters with the buildForward flag set to false.
+ *
+ * <p>The certification path that is constructed is validated
+ * according to the PKIX specification.
+ *
+ * @param params the parameter set for building a path. Must be an instance
+ * of <code>PKIXBuilderParameters</code>.
+ * @return a certification path builder result.
+ * @exception CertPathBuilderException Exception thrown if builder is
+ * unable to build a complete certification path from the trusted anchor(s)
+ * to the target subject.
+ * @throws InvalidAlgorithmParameterException if the given parameters are
+ * inappropriate for this certification path builder.
+ */
+ @Override
+ public CertPathBuilderResult engineBuild(CertPathParameters params)
+ throws CertPathBuilderException, InvalidAlgorithmParameterException {
+
+ if (debug != null) {
+ debug.println("SunCertPathBuilder.engineBuild(" + params + ")");
+ }
+
+ buildParams = PKIX.checkBuilderParams(params);
+ return build();
+ }
+
+ private PKIXCertPathBuilderResult build() throws CertPathBuilderException {
+ List<List<Vertex>> adjList = new ArrayList<>();
+ PKIXCertPathBuilderResult result = buildCertPath(false, adjList);
+ if (result == null) {
+ if (debug != null) {
+ debug.println("SunCertPathBuilder.engineBuild: 2nd pass");
+ }
+ // try again
+ adjList.clear();
+ result = buildCertPath(true, adjList);
+ if (result == null) {
+ throw new SunCertPathBuilderException("unable to find valid "
+ + "certification path to requested target",
+ new AdjacencyList(adjList));
+ }
+ }
+ return result;
+ }
+
+ private PKIXCertPathBuilderResult buildCertPath(boolean searchAllCertStores,
+ List<List<Vertex>> adjList)
+ throws CertPathBuilderException
+ {
+ // Init shared variables and build certification path
+ pathCompleted = false;
+ trustAnchor = null;
+ finalPublicKey = null;
+ policyTreeResult = null;
+ LinkedList<X509Certificate> certPathList = new LinkedList<>();
+ try {
+ if (buildParams.buildForward()) {
+ buildForward(adjList, certPathList, searchAllCertStores);
+ } else {
+ buildReverse(adjList, certPathList);
+ }
+ } catch (GeneralSecurityException | IOException e) {
+ if (debug != null) {
+ debug.println("SunCertPathBuilder.engineBuild() exception in "
+ + "build");
+ e.printStackTrace();
+ }
+ throw new SunCertPathBuilderException("unable to find valid "
+ + "certification path to requested target", e,
+ new AdjacencyList(adjList));
+ }
+
+ // construct SunCertPathBuilderResult
+ try {
+ if (pathCompleted) {
+ if (debug != null)
+ debug.println("SunCertPathBuilder.engineBuild() "
+ + "pathCompleted");
+
+ // we must return a certpath which has the target
+ // as the first cert in the certpath - i.e. reverse
+ // the certPathList
+ Collections.reverse(certPathList);
+
+ return new SunCertPathBuilderResult(
+ cf.generateCertPath(certPathList), trustAnchor,
+ policyTreeResult, finalPublicKey,
+ new AdjacencyList(adjList));
+ }
+ } catch (CertificateException e) {
+ if (debug != null) {
+ debug.println("SunCertPathBuilder.engineBuild() exception "
+ + "in wrap-up");
+ e.printStackTrace();
+ }
+ throw new SunCertPathBuilderException("unable to find valid "
+ + "certification path to requested target", e,
+ new AdjacencyList(adjList));
+ }
+
+ return null;
+ }
+
+ /*
+ * Private build reverse method.
+ */
+ private void buildReverse(List<List<Vertex>> adjacencyList,
+ LinkedList<X509Certificate> certPathList)
+ throws GeneralSecurityException, IOException
+ {
+ if (debug != null) {
+ debug.println("SunCertPathBuilder.buildReverse()...");
+ debug.println("SunCertPathBuilder.buildReverse() InitialPolicies: "
+ + buildParams.initialPolicies());
+ }
+
+ ReverseState currentState = new ReverseState();
+ /* Initialize adjacency list */
+ adjacencyList.clear();
+ adjacencyList.add(new LinkedList<Vertex>());
+
+ /*
+ * Perform a search using each trust anchor, until a valid
+ * path is found
+ */
+ Iterator<TrustAnchor> iter = buildParams.trustAnchors().iterator();
+ while (iter.hasNext()) {
+ TrustAnchor anchor = iter.next();
+
+ /* check if anchor satisfies target constraints */
+ if (anchorIsTarget(anchor, buildParams.targetCertConstraints())) {
+ this.trustAnchor = anchor;
+ this.pathCompleted = true;
+ this.finalPublicKey = anchor.getTrustedCert().getPublicKey();
+ break;
+ }
+
+ // skip anchor if it contains a DSA key with no DSA params
+ X509Certificate trustedCert = anchor.getTrustedCert();
+ PublicKey pubKey = trustedCert != null ? trustedCert.getPublicKey()
+ : anchor.getCAPublicKey();
+
+ if (PKIX.isDSAPublicKeyWithoutParams(pubKey)) {
+ continue;
+ }
+
+ /* Initialize current state */
+ currentState.initState(buildParams);
+ currentState.updateState(anchor, buildParams);
+
+ currentState.algorithmChecker = new AlgorithmChecker(anchor);
+ currentState.untrustedChecker = new UntrustedChecker();
+ try {
+ depthFirstSearchReverse(null, currentState,
+ new ReverseBuilder(buildParams),
+ adjacencyList, certPathList);
+ } catch (GeneralSecurityException | IOException e) {
+ // continue on error if more anchors to try
+ if (iter.hasNext())
+ continue;
+ else
+ throw e;
+ }
+
+ // break out of loop if search is successful
+ if (pathCompleted) {
+ break;
+ }
+ }
+
+ if (debug != null) {
+ debug.println("SunCertPathBuilder.buildReverse() returned from "
+ + "depthFirstSearchReverse()");
+ debug.println("SunCertPathBuilder.buildReverse() "
+ + "certPathList.size: " + certPathList.size());
+ }
+ }
+
+ /*
+ * Private build forward method.
+ */
+ private void buildForward(List<List<Vertex>> adjacencyList,
+ LinkedList<X509Certificate> certPathList,
+ boolean searchAllCertStores)
+ throws GeneralSecurityException, IOException
+ {
+ if (debug != null) {
+ debug.println("SunCertPathBuilder.buildForward()...");
+ }
+
+ /* Initialize current state */
+ ForwardState currentState = new ForwardState();
+ currentState.initState(buildParams.certPathCheckers());
+
+ /* Initialize adjacency list */
+ adjacencyList.clear();
+ adjacencyList.add(new LinkedList<Vertex>());
+
+ currentState.untrustedChecker = new UntrustedChecker();
+
+ depthFirstSearchForward(buildParams.targetSubject(), currentState,
+ new ForwardBuilder(buildParams,
+ searchAllCertStores),
+ adjacencyList, certPathList);
+ }
+
+ /*
+ * This method performs a depth first search for a certification
+ * path while building forward which meets the requirements set in
+ * the parameters object.
+ * It uses an adjacency list to store all certificates which were
+ * tried (i.e. at one time added to the path - they may not end up in
+ * the final path if backtracking occurs). This information can
+ * be used later to debug or demo the build.
+ *
+ * See "Data Structure and Algorithms, by Aho, Hopcroft, and Ullman"
+ * for an explanation of the DFS algorithm.
+ *
+ * @param dN the distinguished name being currently searched for certs
+ * @param currentState the current PKIX validation state
+ */
+ private void depthFirstSearchForward(X500Principal dN,
+ ForwardState currentState,
+ ForwardBuilder builder,
+ List<List<Vertex>> adjList,
+ LinkedList<X509Certificate> cpList)
+ throws GeneralSecurityException, IOException
+ {
+ if (debug != null) {
+ debug.println("SunCertPathBuilder.depthFirstSearchForward(" + dN
+ + ", " + currentState.toString() + ")");
+ }
+
+ /*
+ * Find all the certificates issued to dN which
+ * satisfy the PKIX certification path constraints.
+ */
+ Collection<X509Certificate> certs =
+ builder.getMatchingCerts(currentState, buildParams.certStores());
+ List<Vertex> vertices = addVertices(certs, adjList);
+ if (debug != null) {
+ debug.println("SunCertPathBuilder.depthFirstSearchForward(): "
+ + "certs.size=" + vertices.size());
+ }
+
+ /*
+ * For each cert in the collection, verify anything
+ * that hasn't been checked yet (signature, revocation, etc)
+ * and check for loops. Call depthFirstSearchForward()
+ * recursively for each good cert.
+ */
+
+ vertices:
+ for (Vertex vertex : vertices) {
+ /**
+ * Restore state to currentState each time through the loop.
+ * This is important because some of the user-defined
+ * checkers modify the state, which MUST be restored if
+ * the cert eventually fails to lead to the target and
+ * the next matching cert is tried.
+ */
+ ForwardState nextState = (ForwardState) currentState.clone();
+ X509Certificate cert = vertex.getCertificate();
+
+ try {
+ builder.verifyCert(cert, nextState, cpList);
+ } catch (GeneralSecurityException gse) {
+ if (debug != null) {
+ debug.println("SunCertPathBuilder.depthFirstSearchForward()"
+ + ": validation failed: " + gse);
+ gse.printStackTrace();
+ }
+ vertex.setThrowable(gse);
+ continue;
+ }
+
+ /*
+ * Certificate is good.
+ * If cert completes the path,
+ * process userCheckers that don't support forward checking
+ * and process policies over whole path
+ * and backtrack appropriately if there is a failure
+ * else if cert does not complete the path,
+ * add it to the path
+ */
+ if (builder.isPathCompleted(cert)) {
+
+ if (debug != null)
+ debug.println("SunCertPathBuilder.depthFirstSearchForward()"
+ + ": commencing final verification");
+
+ List<X509Certificate> appendedCerts = new ArrayList<>(cpList);
+
+ /*
+ * if the trust anchor selected is specified as a trusted
+ * public key rather than a trusted cert, then verify this
+ * cert (which is signed by the trusted public key), but
+ * don't add it yet to the cpList
+ */
+ if (builder.trustAnchor.getTrustedCert() == null) {
+ appendedCerts.add(0, cert);
+ }
+
+ Set<String> initExpPolSet =
+ Collections.singleton(PolicyChecker.ANY_POLICY);
+
+ PolicyNodeImpl rootNode = new PolicyNodeImpl(null,
+ PolicyChecker.ANY_POLICY, null, false, initExpPolSet, false);
+
+ List<PKIXCertPathChecker> checkers = new ArrayList<>();
+ PolicyChecker policyChecker
+ = new PolicyChecker(buildParams.initialPolicies(),
+ appendedCerts.size(),
+ buildParams.explicitPolicyRequired(),
+ buildParams.policyMappingInhibited(),
+ buildParams.anyPolicyInhibited(),
+ buildParams.policyQualifiersRejected(),
+ rootNode);
+ checkers.add(policyChecker);
+
+ // add the algorithm checker
+ checkers.add(new AlgorithmChecker(builder.trustAnchor));
+
+ BasicChecker basicChecker = null;
+ if (nextState.keyParamsNeeded()) {
+ PublicKey rootKey = cert.getPublicKey();
+ if (builder.trustAnchor.getTrustedCert() == null) {
+ rootKey = builder.trustAnchor.getCAPublicKey();
+ if (debug != null)
+ debug.println(
+ "SunCertPathBuilder.depthFirstSearchForward " +
+ "using buildParams public key: " +
+ rootKey.toString());
+ }
+ TrustAnchor anchor = new TrustAnchor
+ (cert.getSubjectX500Principal(), rootKey, null);
+
+ // add the basic checker
+ basicChecker = new BasicChecker(anchor, buildParams.date(),
+ buildParams.sigProvider(),
+ true);
+ checkers.add(basicChecker);
+ }
+
+ buildParams.setCertPath(cf.generateCertPath(appendedCerts));
+
+ boolean revCheckerAdded = false;
+ List<PKIXCertPathChecker> ckrs = buildParams.certPathCheckers();
+ for (PKIXCertPathChecker ckr : ckrs) {
+ if (ckr instanceof PKIXRevocationChecker) {
+ if (revCheckerAdded) {
+ throw new CertPathValidatorException(
+ "Only one PKIXRevocationChecker can be specified");
+ }
+ revCheckerAdded = true;
+ // if it's our own, initialize it
+ if (ckr instanceof RevocationChecker) {
+ ((RevocationChecker)ckr).init(builder.trustAnchor,
+ buildParams);
+ }
+ }
+ }
+ // only add a RevocationChecker if revocation is enabled and
+ // a PKIXRevocationChecker has not already been added
+ if (buildParams.revocationEnabled() && !revCheckerAdded) {
+ checkers.add(new RevocationChecker(builder.trustAnchor,
+ buildParams));
+ }
+
+ checkers.addAll(ckrs);
+
+ // Why we don't need BasicChecker and RevocationChecker
+ // if nextState.keyParamsNeeded() is false?
+
+ for (int i = 0; i < appendedCerts.size(); i++) {
+ X509Certificate currCert = appendedCerts.get(i);
+ if (debug != null)
+ debug.println("current subject = "
+ + currCert.getSubjectX500Principal());
+ Set<String> unresCritExts =
+ currCert.getCriticalExtensionOIDs();
+ if (unresCritExts == null) {
+ unresCritExts = Collections.<String>emptySet();
+ }
+
+ for (PKIXCertPathChecker currChecker : checkers) {
+ if (!currChecker.isForwardCheckingSupported()) {
+ if (i == 0) {
+ currChecker.init(false);
+
+ // The user specified
+ // AlgorithmChecker may not be
+ // able to set the trust anchor until now.
+ if (currChecker instanceof AlgorithmChecker) {
+ ((AlgorithmChecker)currChecker).
+ trySetTrustAnchor(builder.trustAnchor);
+ }
+ }
+
+ try {
+ currChecker.check(currCert, unresCritExts);
+ } catch (CertPathValidatorException cpve) {
+ if (debug != null)
+ debug.println
+ ("SunCertPathBuilder.depthFirstSearchForward(): " +
+ "final verification failed: " + cpve);
+ // If the target cert itself is revoked, we
+ // cannot trust it. We can bail out here.
+ if (buildParams.targetCertConstraints().match(currCert)
+ && cpve.getReason() == BasicReason.REVOKED) {
+ throw cpve;
+ }
+ vertex.setThrowable(cpve);
+ continue vertices;
+ }
+ }
+ }
+
+ /*
+ * Remove extensions from user checkers that support
+ * forward checking. After this step, we will have
+ * removed all extensions that all user checkers
+ * are capable of processing.
+ */
+ for (PKIXCertPathChecker checker :
+ buildParams.certPathCheckers())
+ {
+ if (checker.isForwardCheckingSupported()) {
+ Set<String> suppExts =
+ checker.getSupportedExtensions();
+ if (suppExts != null) {
+ unresCritExts.removeAll(suppExts);
+ }
+ }
+ }
+
+ if (!unresCritExts.isEmpty()) {
+ unresCritExts.remove(BasicConstraints_Id.toString());
+ unresCritExts.remove(NameConstraints_Id.toString());
+ unresCritExts.remove(CertificatePolicies_Id.toString());
+ unresCritExts.remove(PolicyMappings_Id.toString());
+ unresCritExts.remove(PolicyConstraints_Id.toString());
+ unresCritExts.remove(InhibitAnyPolicy_Id.toString());
+ unresCritExts.remove(
+ SubjectAlternativeName_Id.toString());
+ unresCritExts.remove(KeyUsage_Id.toString());
+ unresCritExts.remove(ExtendedKeyUsage_Id.toString());
+
+ if (!unresCritExts.isEmpty()) {
+ throw new CertPathValidatorException
+ ("unrecognized critical extension(s)", null,
+ null, -1, PKIXReason.UNRECOGNIZED_CRIT_EXT);
+ }
+ }
+ }
+ if (debug != null)
+ debug.println("SunCertPathBuilder.depthFirstSearchForward()"
+ + ": final verification succeeded - path completed!");
+ pathCompleted = true;
+
+ /*
+ * if the user specified a trusted public key rather than
+ * trusted certs, then add this cert (which is signed by
+ * the trusted public key) to the cpList
+ */
+ if (builder.trustAnchor.getTrustedCert() == null)
+ builder.addCertToPath(cert, cpList);
+ // Save the trust anchor
+ this.trustAnchor = builder.trustAnchor;
+
+ /*
+ * Extract and save the final target public key
+ */
+ if (basicChecker != null) {
+ finalPublicKey = basicChecker.getPublicKey();
+ } else {
+ Certificate finalCert;
+ if (cpList.isEmpty()) {
+ finalCert = builder.trustAnchor.getTrustedCert();
+ } else {
+ finalCert = cpList.getLast();
+ }
+ finalPublicKey = finalCert.getPublicKey();
+ }
+
+ policyTreeResult = policyChecker.getPolicyTree();
+ return;
+ } else {
+ builder.addCertToPath(cert, cpList);
+ }
+
+ /* Update the PKIX state */
+ nextState.updateState(cert);
+
+ /*
+ * Append an entry for cert in adjacency list and
+ * set index for current vertex.
+ */
+ adjList.add(new LinkedList<Vertex>());
+ vertex.setIndex(adjList.size() - 1);
+
+ /* recursively search for matching certs at next dN */
+ depthFirstSearchForward(cert.getIssuerX500Principal(), nextState,
+ builder, adjList, cpList);
+
+ /*
+ * If path has been completed, return ASAP!
+ */
+ if (pathCompleted) {
+ return;
+ } else {
+ /*
+ * If we get here, it means we have searched all possible
+ * certs issued by the dN w/o finding any matching certs.
+ * This means we have to backtrack to the previous cert in
+ * the path and try some other paths.
+ */
+ if (debug != null)
+ debug.println("SunCertPathBuilder.depthFirstSearchForward()"
+ + ": backtracking");
+ builder.removeFinalCertFromPath(cpList);
+ }
+ }
+ }
+
+ /*
+ * This method performs a depth first search for a certification
+ * path while building reverse which meets the requirements set in
+ * the parameters object.
+ * It uses an adjacency list to store all certificates which were
+ * tried (i.e. at one time added to the path - they may not end up in
+ * the final path if backtracking occurs). This information can
+ * be used later to debug or demo the build.
+ *
+ * See "Data Structure and Algorithms, by Aho, Hopcroft, and Ullman"
+ * for an explanation of the DFS algorithm.
+ *
+ * @param dN the distinguished name being currently searched for certs
+ * @param currentState the current PKIX validation state
+ */
+ private void depthFirstSearchReverse(X500Principal dN,
+ ReverseState currentState,
+ ReverseBuilder builder,
+ List<List<Vertex>> adjList,
+ LinkedList<X509Certificate> cpList)
+ throws GeneralSecurityException, IOException
+ {
+ if (debug != null)
+ debug.println("SunCertPathBuilder.depthFirstSearchReverse(" + dN
+ + ", " + currentState.toString() + ")");
+
+ /*
+ * Find all the certificates issued by dN which
+ * satisfy the PKIX certification path constraints.
+ */
+ Collection<X509Certificate> certs =
+ builder.getMatchingCerts(currentState, buildParams.certStores());
+ List<Vertex> vertices = addVertices(certs, adjList);
+ if (debug != null)
+ debug.println("SunCertPathBuilder.depthFirstSearchReverse(): "
+ + "certs.size=" + vertices.size());
+
+ /*
+ * For each cert in the collection, verify anything
+ * that hasn't been checked yet (signature, revocation, etc)
+ * and check for loops. Call depthFirstSearchReverse()
+ * recursively for each good cert.
+ */
+ for (Vertex vertex : vertices) {
+ /**
+ * Restore state to currentState each time through the loop.
+ * This is important because some of the user-defined
+ * checkers modify the state, which MUST be restored if
+ * the cert eventually fails to lead to the target and
+ * the next matching cert is tried.
+ */
+ ReverseState nextState = (ReverseState) currentState.clone();
+ X509Certificate cert = vertex.getCertificate();
+ try {
+ builder.verifyCert(cert, nextState, cpList);
+ } catch (GeneralSecurityException gse) {
+ if (debug != null)
+ debug.println("SunCertPathBuilder.depthFirstSearchReverse()"
+ + ": validation failed: " + gse);
+ vertex.setThrowable(gse);
+ continue;
+ }
+
+ /*
+ * Certificate is good, add it to the path (if it isn't a
+ * self-signed cert) and update state
+ */
+ if (!currentState.isInitial())
+ builder.addCertToPath(cert, cpList);
+ // save trust anchor
+ this.trustAnchor = currentState.trustAnchor;
+
+ /*
+ * Check if path is completed, return ASAP if so.
+ */
+ if (builder.isPathCompleted(cert)) {
+ if (debug != null)
+ debug.println("SunCertPathBuilder.depthFirstSearchReverse()"
+ + ": path completed!");
+ pathCompleted = true;
+
+ PolicyNodeImpl rootNode = nextState.rootNode;
+
+ if (rootNode == null)
+ policyTreeResult = null;
+ else {
+ policyTreeResult = rootNode.copyTree();
+ ((PolicyNodeImpl)policyTreeResult).setImmutable();
+ }
+
+ /*
+ * Extract and save the final target public key
+ */
+ finalPublicKey = cert.getPublicKey();
+ if (PKIX.isDSAPublicKeyWithoutParams(finalPublicKey)) {
+ finalPublicKey =
+ BasicChecker.makeInheritedParamsKey
+ (finalPublicKey, currentState.pubKey);
+ }
+
+ return;
+ }
+
+ /* Update the PKIX state */
+ nextState.updateState(cert);
+
+ /*
+ * Append an entry for cert in adjacency list and
+ * set index for current vertex.
+ */
+ adjList.add(new LinkedList<Vertex>());
+ vertex.setIndex(adjList.size() - 1);
+
+ /* recursively search for matching certs at next dN */
+ depthFirstSearchReverse(cert.getSubjectX500Principal(), nextState,
+ builder, adjList, cpList);
+
+ /*
+ * If path has been completed, return ASAP!
+ */
+ if (pathCompleted) {
+ return;
+ } else {
+ /*
+ * If we get here, it means we have searched all possible
+ * certs issued by the dN w/o finding any matching certs. This
+ * means we have to backtrack to the previous cert in the path
+ * and try some other paths.
+ */
+ if (debug != null)
+ debug.println("SunCertPathBuilder.depthFirstSearchReverse()"
+ + ": backtracking");
+ if (!currentState.isInitial())
+ builder.removeFinalCertFromPath(cpList);
+ }
+ }
+ if (debug != null)
+ debug.println("SunCertPathBuilder.depthFirstSearchReverse() all "
+ + "certs in this adjacency list checked");
+ }
+
+ /*
+ * Adds a collection of matching certificates to the
+ * adjacency list.
+ */
+ private static List<Vertex> addVertices(Collection<X509Certificate> certs,
+ List<List<Vertex>> adjList)
+ {
+ List<Vertex> l = adjList.get(adjList.size() - 1);
+
+ for (X509Certificate cert : certs) {
+ Vertex v = new Vertex(cert);
+ l.add(v);
+ }
+
+ return l;
+ }
+
+ /**
+ * Returns true if trust anchor certificate matches specified
+ * certificate constraints.
+ */
+ private static boolean anchorIsTarget(TrustAnchor anchor,
+ CertSelector sel)
+ {
+ X509Certificate anchorCert = anchor.getTrustedCert();
+ if (anchorCert != null) {
+ return sel.match(anchorCert);
+ }
+ return false;
+ }
+}
diff --git a/ojluni/src/main/java/sun/security/provider/certpath/SunCertPathBuilderException.java b/ojluni/src/main/java/sun/security/provider/certpath/SunCertPathBuilderException.java
new file mode 100644
index 0000000..8ba440d
--- /dev/null
+++ b/ojluni/src/main/java/sun/security/provider/certpath/SunCertPathBuilderException.java
@@ -0,0 +1,131 @@
+/*
+ * Copyright (c) 2000, 2004, 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.List;
+import java.security.cert.CertPathBuilderException;
+
+/**
+ * This is a subclass of the generic <code>CertPathBuilderException</code>.
+ * It contains an adjacency list with information regarding the unsuccessful
+ * paths that the SunCertPathBuilder tried.
+ *
+ * @since 1.4
+ * @author Sean Mullan
+ * @see CertPathBuilderException
+ */
+public class SunCertPathBuilderException extends CertPathBuilderException {
+
+ private static final long serialVersionUID = -7814288414129264709L;
+
+ /**
+ * @serial
+ */
+ private transient AdjacencyList adjList;
+
+ /**
+ * Constructs a <code>SunCertPathBuilderException</code> with
+ * <code>null</code> as its detail message.
+ */
+ public SunCertPathBuilderException() {
+ super();
+ }
+
+ /**
+ * Constructs a <code>SunCertPathBuilderException</code> with the specified
+ * detail message. A detail message is a <code>String</code> that
+ * describes this particular exception.
+ *
+ * @param msg the detail message
+ */
+ public SunCertPathBuilderException(String msg) {
+ super(msg);
+ }
+
+ /**
+ * Constructs a <code>SunCertPathBuilderException</code> that wraps the
+ * specified throwable. This allows any exception to be converted into a
+ * <code>SunCertPathBuilderException</code>, while retaining information
+ * about the cause, which may be useful for debugging. The detail message is
+ * set to (<code>cause==null ? null : cause.toString()</code>) (which
+ * typically contains the class and detail message of cause).
+ *
+ * @param cause the cause (which is saved for later retrieval by the
+ * {@link #getCause getCause()} method). (A <code>null</code> value is
+ * permitted, and indicates that the cause is nonexistent or unknown.)
+ * root cause.
+ */
+ public SunCertPathBuilderException(Throwable cause) {
+ super(cause);
+ }
+
+ /**
+ * Creates a <code>SunCertPathBuilderException</code> with the specified
+ * detail message and cause.
+ *
+ * @param msg the detail message
+ * @param cause the cause
+ */
+ public SunCertPathBuilderException(String msg, Throwable cause) {
+ super(msg, cause);
+ }
+
+ /**
+ * Creates a <code>SunCertPathBuilderException</code> withe the specified
+ * detail message and adjacency list.
+ *
+ * @param msg the detail message
+ * @param adjList the adjacency list
+ */
+ SunCertPathBuilderException(String msg, AdjacencyList adjList) {
+ this(msg);
+ this.adjList = adjList;
+ }
+
+ /**
+ * Creates a <code>SunCertPathBuilderException</code> with the specified
+ * detail message, cause, and adjacency list.
+ *
+ * @param msg the detail message
+ * @param cause the throwable that occurred
+ * @param adjList Adjacency list
+ */
+ SunCertPathBuilderException(String msg, Throwable cause,
+ AdjacencyList adjList)
+ {
+ this(msg, cause);
+ this.adjList = adjList;
+ }
+
+ /**
+ * Returns the adjacency list containing information about the build.
+ *
+ * @return the adjacency list containing information about the build
+ */
+ public AdjacencyList getAdjacencyList() {
+ return adjList;
+ }
+}
diff --git a/ojluni/src/main/java/sun/security/provider/certpath/SunCertPathBuilderParameters.java b/ojluni/src/main/java/sun/security/provider/certpath/SunCertPathBuilderParameters.java
new file mode 100644
index 0000000..186e252
--- /dev/null
+++ b/ojluni/src/main/java/sun/security/provider/certpath/SunCertPathBuilderParameters.java
@@ -0,0 +1,131 @@
+/*
+ * Copyright (c) 2000, 2012, 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.KeyStore;
+import java.security.KeyStoreException;
+import java.security.cert.*;
+import java.util.Set;
+
+/**
+ * This class specifies the set of parameters used as input for the Sun
+ * certification path build algorithm. It is identical to PKIXBuilderParameters
+ * with the addition of a <code>buildForward</code> parameter which allows
+ * the caller to specify whether or not the path should be constructed in
+ * the forward direction.
+ *
+ * The default for the <code>buildForward</code> parameter is
+ * true, which means that the build algorithm should construct paths
+ * from the target subject back to the trusted anchor.
+ *
+ * @since 1.4
+ * @author Sean Mullan
+ * @author Yassir Elley
+ */
+public class SunCertPathBuilderParameters extends PKIXBuilderParameters {
+
+ private boolean buildForward = true;
+
+ /**
+ * Creates an instance of <code>SunCertPathBuilderParameters</code> with the
+ * specified parameter values.
+ *
+ * @param trustAnchors a <code>Set</code> of <code>TrustAnchor</code>s
+ * @param targetConstraints a <code>CertSelector</code> specifying the
+ * constraints on the target certificate
+ * @throws InvalidAlgorithmParameterException if the specified
+ * <code>Set</code> is empty <code>(trustAnchors.isEmpty() == true)</code>
+ * @throws NullPointerException if the specified <code>Set</code> is
+ * <code>null</code>
+ * @throws ClassCastException if any of the elements in the <code>Set</code>
+ * are not of type <code>java.security.cert.TrustAnchor</code>
+ */
+ public SunCertPathBuilderParameters(Set<TrustAnchor> trustAnchors,
+ CertSelector targetConstraints) throws InvalidAlgorithmParameterException
+ {
+ super(trustAnchors, targetConstraints);
+ setBuildForward(true);
+ }
+
+ /**
+ * Creates an instance of <code>SunCertPathBuilderParameters</code> that
+ * uses the specified <code>KeyStore</code> to populate the set
+ * of most-trusted CA certificates.
+ *
+ * @param keystore A keystore from which the set of most-trusted
+ * CA certificates will be populated.
+ * @param targetConstraints a <code>CertSelector</code> specifying the
+ * constraints on the target certificate
+ * @throws KeyStoreException if the keystore has not been initialized.
+ * @throws InvalidAlgorithmParameterException if the keystore does
+ * not contain at least one trusted certificate entry
+ * @throws NullPointerException if the keystore is <code>null</code>
+ */
+ public SunCertPathBuilderParameters(KeyStore keystore,
+ CertSelector targetConstraints)
+ throws KeyStoreException, InvalidAlgorithmParameterException
+ {
+ super(keystore, targetConstraints);
+ setBuildForward(true);
+ }
+
+ /**
+ * Returns the value of the buildForward flag.
+ *
+ * @return the value of the buildForward flag
+ */
+ public boolean getBuildForward() {
+ return this.buildForward;
+ }
+
+ /**
+ * Sets the value of the buildForward flag. If true, paths
+ * are built from the target subject to the trusted anchor.
+ * If false, paths are built from the trusted anchor to the
+ * target subject. The default value if not specified is true.
+ *
+ * @param buildForward the value of the buildForward flag
+ */
+ public void setBuildForward(boolean buildForward) {
+ this.buildForward = buildForward;
+ }
+
+ /**
+ * Returns a formatted string describing the parameters.
+ *
+ * @return a formatted string describing the parameters.
+ */
+ @Override
+ public String toString() {
+ StringBuilder sb = new StringBuilder();
+ sb.append("[\n");
+ sb.append(super.toString());
+ sb.append(" Build Forward Flag: " + String.valueOf(buildForward) + "\n");
+ sb.append("]\n");
+ return sb.toString();
+ }
+}
diff --git a/ojluni/src/main/java/sun/security/provider/certpath/SunCertPathBuilderResult.java b/ojluni/src/main/java/sun/security/provider/certpath/SunCertPathBuilderResult.java
new file mode 100644
index 0000000..5924190
--- /dev/null
+++ b/ojluni/src/main/java/sun/security/provider/certpath/SunCertPathBuilderResult.java
@@ -0,0 +1,83 @@
+/*
+ * Copyright (c) 2000, 2001, 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 sun.security.util.Debug;
+import java.security.PublicKey;
+import java.security.cert.CertPath;
+import java.security.cert.PKIXCertPathBuilderResult;
+import java.security.cert.PolicyNode;
+import java.security.cert.TrustAnchor;
+
+/**
+ * This class represents the result of a SunCertPathBuilder build.
+ * Since all paths returned by the SunCertPathProvider are PKIX validated
+ * the result contains the valid policy tree and subject public key returned
+ * by the algorithm. It also contains the trust anchor and debug information
+ * represented in the form of an adjacency list.
+ *
+ * @see PKIXCertPathBuilderResult
+ *
+ * @since 1.4
+ * @author Sean Mullan
+ */
+//@@@ Note: this class is not in public API and access to adjacency list is
+//@@@ intended for debugging/replay of Sun PKIX CertPathBuilder implementation.
+
+public class SunCertPathBuilderResult extends PKIXCertPathBuilderResult {
+
+ private static final Debug debug = Debug.getInstance("certpath");
+
+ private AdjacencyList adjList;
+
+ /**
+ * Creates a SunCertPathBuilderResult instance.
+ *
+ * @param certPath the validated <code>CertPath</code>
+ * @param trustAnchor a <code>TrustAnchor</code> describing the CA that
+ * served as a trust anchor for the certification path
+ * @param policyTree the valid policy tree, or <code>null</code>
+ * if there are no valid policies
+ * @param subjectPublicKey the public key of the subject
+ * @param adjList an Adjacency list containing debug information
+ */
+ SunCertPathBuilderResult(CertPath certPath,
+ TrustAnchor trustAnchor, PolicyNode policyTree,
+ PublicKey subjectPublicKey, AdjacencyList adjList)
+ {
+ super(certPath, trustAnchor, policyTree, subjectPublicKey);
+ this.adjList = adjList;
+ }
+
+ /**
+ * Returns the adjacency list containing information about the build.
+ *
+ * @return The adjacency list containing information about the build.
+ */
+ public AdjacencyList getAdjacencyList() {
+ return adjList;
+ }
+}
diff --git a/ojluni/src/main/java/sun/security/provider/certpath/URICertStore.java b/ojluni/src/main/java/sun/security/provider/certpath/URICertStore.java
new file mode 100644
index 0000000..a5ec5d3
--- /dev/null
+++ b/ojluni/src/main/java/sun/security/provider/certpath/URICertStore.java
@@ -0,0 +1,491 @@
+/*
+ * Copyright (c) 2006, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * 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.io.InputStream;
+import java.io.IOException;
+import java.net.HttpURLConnection;
+import java.net.URI;
+import java.net.URLConnection;
+import java.security.InvalidAlgorithmParameterException;
+import java.security.NoSuchAlgorithmException;
+import java.security.Provider;
+import java.security.cert.CertificateException;
+import java.security.cert.CertificateFactory;
+import java.security.cert.CertSelector;
+import java.security.cert.CertStore;
+import java.security.cert.CertStoreException;
+import java.security.cert.CertStoreParameters;
+import java.security.cert.CertStoreSpi;
+import java.security.cert.CRLException;
+import java.security.cert.CRLSelector;
+import java.security.cert.X509Certificate;
+import java.security.cert.X509CertSelector;
+import java.security.cert.X509CRL;
+import java.security.cert.X509CRLSelector;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.List;
+import java.util.Locale;
+import sun.security.action.GetIntegerAction;
+import sun.security.x509.AccessDescription;
+import sun.security.x509.GeneralNameInterface;
+import sun.security.x509.URIName;
+import sun.security.util.Cache;
+import sun.security.util.Debug;
+
+/**
+ * A <code>CertStore</code> that retrieves <code>Certificates</code> or
+ * <code>CRL</code>s from a URI, for example, as specified in an X.509
+ * AuthorityInformationAccess or CRLDistributionPoint extension.
+ * <p>
+ * For CRLs, this implementation retrieves a single DER encoded CRL per URI.
+ * For Certificates, this implementation retrieves a single DER encoded CRL or
+ * a collection of Certificates encoded as a PKCS#7 "certs-only" CMS message.
+ * <p>
+ * This <code>CertStore</code> also implements Certificate/CRL caching.
+ * Currently, the cache is shared between all applications in the VM and uses a
+ * hardcoded policy. The cache has a maximum size of 185 entries, which are held
+ * by SoftReferences. A request will be satisfied from the cache if we last
+ * checked for an update within CHECK_INTERVAL (last 30 seconds). Otherwise,
+ * we open an URLConnection to download the Certificate(s)/CRL using an
+ * If-Modified-Since request (HTTP) if possible. Note that both positive and
+ * negative responses are cached, i.e. if we are unable to open the connection
+ * or the Certificate(s)/CRL cannot be parsed, we remember this result and
+ * additional calls during the CHECK_INTERVAL period do not try to open another
+ * connection.
+ * <p>
+ * The URICertStore is not currently a standard CertStore type. We should
+ * consider adding a standard "URI" CertStore type.
+ *
+ * @author Andreas Sterbenz
+ * @author Sean Mullan
+ * @since 7.0
+ */
+class URICertStore extends CertStoreSpi {
+
+ private static final Debug debug = Debug.getInstance("certpath");
+
+ // interval between checks for update of cached Certificates/CRLs
+ // (30 seconds)
+ private final static int CHECK_INTERVAL = 30 * 1000;
+
+ // size of the cache (see Cache class for sizing recommendations)
+ private final static int CACHE_SIZE = 185;
+
+ // X.509 certificate factory instance
+ private final CertificateFactory factory;
+
+ // cached Collection of X509Certificates (may be empty, never null)
+ private Collection<X509Certificate> certs = Collections.emptySet();
+
+ // cached X509CRL (may be null)
+ private X509CRL crl;
+
+ // time we last checked for an update
+ private long lastChecked;
+
+ // time server returned as last modified time stamp
+ // or 0 if not available
+ private long lastModified;
+
+ // the URI of this CertStore
+ private URI uri;
+
+ // true if URI is ldap
+ private boolean ldap = false;
+ private CertStoreHelper ldapHelper;
+ private CertStore ldapCertStore;
+ private String ldapPath;
+
+ // Default maximum connect timeout in milliseconds (15 seconds)
+ // allowed when downloading CRLs
+ private static final int DEFAULT_CRL_CONNECT_TIMEOUT = 15000;
+
+ /**
+ * Integer value indicating the connect timeout, in seconds, to be
+ * used for the CRL download. A timeout of zero is interpreted as
+ * an infinite timeout.
+ */
+ private static final int CRL_CONNECT_TIMEOUT = initializeTimeout();
+
+ /**
+ * Initialize the timeout length by getting the CRL timeout
+ * system property. If the property has not been set, or if its
+ * value is negative, set the timeout length to the default.
+ */
+ private static int initializeTimeout() {
+ Integer tmp = java.security.AccessController.doPrivileged(
+ new GetIntegerAction("com.sun.security.crl.timeout"));
+ if (tmp == null || tmp < 0) {
+ return DEFAULT_CRL_CONNECT_TIMEOUT;
+ }
+ // Convert to milliseconds, as the system property will be
+ // specified in seconds
+ return tmp * 1000;
+ }
+
+ /**
+ * Creates a URICertStore.
+ *
+ * @param parameters specifying the URI
+ */
+ URICertStore(CertStoreParameters params)
+ throws InvalidAlgorithmParameterException, NoSuchAlgorithmException {
+ super(params);
+ if (!(params instanceof URICertStoreParameters)) {
+ throw new InvalidAlgorithmParameterException
+ ("params must be instanceof URICertStoreParameters");
+ }
+ this.uri = ((URICertStoreParameters) params).uri;
+ // if ldap URI, use an LDAPCertStore to fetch certs and CRLs
+ if (uri.getScheme().toLowerCase(Locale.ENGLISH).equals("ldap")) {
+ ldap = true;
+ ldapHelper = CertStoreHelper.getInstance("LDAP");
+ ldapCertStore = ldapHelper.getCertStore(uri);
+ ldapPath = uri.getPath();
+ // strip off leading '/'
+ if (ldapPath.charAt(0) == '/') {
+ ldapPath = ldapPath.substring(1);
+ }
+ }
+ try {
+ factory = CertificateFactory.getInstance("X.509");
+ } catch (CertificateException e) {
+ throw new RuntimeException();
+ }
+ }
+
+ /**
+ * Returns a URI CertStore. This method consults a cache of
+ * CertStores (shared per JVM) using the URI as a key.
+ */
+ private static final Cache<URICertStoreParameters, CertStore>
+ certStoreCache = Cache.newSoftMemoryCache(CACHE_SIZE);
+ static synchronized CertStore getInstance(URICertStoreParameters params)
+ throws NoSuchAlgorithmException, InvalidAlgorithmParameterException {
+ if (debug != null) {
+ debug.println("CertStore URI:" + params.uri);
+ }
+ CertStore ucs = certStoreCache.get(params);
+ if (ucs == null) {
+ ucs = new UCS(new URICertStore(params), null, "URI", params);
+ certStoreCache.put(params, ucs);
+ } else {
+ if (debug != null) {
+ debug.println("URICertStore.getInstance: cache hit");
+ }
+ }
+ return ucs;
+ }
+
+ /**
+ * Creates a CertStore from information included in the AccessDescription
+ * object of a certificate's Authority Information Access Extension.
+ */
+ static CertStore getInstance(AccessDescription ad) {
+ if (!ad.getAccessMethod().equals((Object)
+ AccessDescription.Ad_CAISSUERS_Id)) {
+ return null;
+ }
+ GeneralNameInterface gn = ad.getAccessLocation().getName();
+ if (!(gn instanceof URIName)) {
+ return null;
+ }
+ URI uri = ((URIName) gn).getURI();
+ try {
+ return URICertStore.getInstance
+ (new URICertStore.URICertStoreParameters(uri));
+ } catch (Exception ex) {
+ if (debug != null) {
+ debug.println("exception creating CertStore: " + ex);
+ ex.printStackTrace();
+ }
+ return null;
+ }
+ }
+
+ /**
+ * Returns a <code>Collection</code> of <code>X509Certificate</code>s that
+ * match the specified selector. If no <code>X509Certificate</code>s
+ * match the selector, an empty <code>Collection</code> will be returned.
+ *
+ * @param selector a <code>CertSelector</code> used to select which
+ * <code>X509Certificate</code>s should be returned. Specify
+ * <code>null</code> to return all <code>X509Certificate</code>s.
+ * @return a <code>Collection</code> of <code>X509Certificate</code>s that
+ * match the specified selector
+ * @throws CertStoreException if an exception occurs
+ */
+ @Override
+ @SuppressWarnings("unchecked")
+ public synchronized Collection<X509Certificate> engineGetCertificates
+ (CertSelector selector) throws CertStoreException {
+
+ // if ldap URI we wrap the CertSelector in an LDAPCertSelector to
+ // avoid LDAP DN matching issues (see LDAPCertSelector for more info)
+ if (ldap) {
+ X509CertSelector xsel = (X509CertSelector) selector;
+ try {
+ xsel = ldapHelper.wrap(xsel, xsel.getSubject(), ldapPath);
+ } catch (IOException ioe) {
+ throw new CertStoreException(ioe);
+ }
+ // Fetch the certificates via LDAP. LDAPCertStore has its own
+ // caching mechanism, see the class description for more info.
+ // Safe cast since xsel is an X509 certificate selector.
+ return (Collection<X509Certificate>)
+ ldapCertStore.getCertificates(xsel);
+ }
+
+ // Return the Certificates for this entry. It returns the cached value
+ // if it is still current and fetches the Certificates otherwise.
+ // For the caching details, see the top of this class.
+ long time = System.currentTimeMillis();
+ if (time - lastChecked < CHECK_INTERVAL) {
+ if (debug != null) {
+ debug.println("Returning certificates from cache");
+ }
+ return getMatchingCerts(certs, selector);
+ }
+ lastChecked = time;
+ try {
+ URLConnection connection = uri.toURL().openConnection();
+ if (lastModified != 0) {
+ connection.setIfModifiedSince(lastModified);
+ }
+ long oldLastModified = lastModified;
+ try (InputStream in = connection.getInputStream()) {
+ lastModified = connection.getLastModified();
+ if (oldLastModified != 0) {
+ if (oldLastModified == lastModified) {
+ if (debug != null) {
+ debug.println("Not modified, using cached copy");
+ }
+ return getMatchingCerts(certs, selector);
+ } else if (connection instanceof HttpURLConnection) {
+ // some proxy servers omit last modified
+ HttpURLConnection hconn = (HttpURLConnection)connection;
+ if (hconn.getResponseCode()
+ == HttpURLConnection.HTTP_NOT_MODIFIED) {
+ if (debug != null) {
+ debug.println("Not modified, using cached copy");
+ }
+ return getMatchingCerts(certs, selector);
+ }
+ }
+ }
+ if (debug != null) {
+ debug.println("Downloading new certificates...");
+ }
+ // Safe cast since factory is an X.509 certificate factory
+ certs = (Collection<X509Certificate>)
+ factory.generateCertificates(in);
+ }
+ return getMatchingCerts(certs, selector);
+ } catch (IOException | CertificateException e) {
+ if (debug != null) {
+ debug.println("Exception fetching certificates:");
+ e.printStackTrace();
+ }
+ }
+ // exception, forget previous values
+ lastModified = 0;
+ certs = Collections.emptySet();
+ return certs;
+ }
+
+ /**
+ * Iterates over the specified Collection of X509Certificates and
+ * returns only those that match the criteria specified in the
+ * CertSelector.
+ */
+ private static Collection<X509Certificate> getMatchingCerts
+ (Collection<X509Certificate> certs, CertSelector selector) {
+ // if selector not specified, all certs match
+ if (selector == null) {
+ return certs;
+ }
+ List<X509Certificate> matchedCerts = new ArrayList<>(certs.size());
+ for (X509Certificate cert : certs) {
+ if (selector.match(cert)) {
+ matchedCerts.add(cert);
+ }
+ }
+ return matchedCerts;
+ }
+
+ /**
+ * Returns a <code>Collection</code> of <code>X509CRL</code>s that
+ * match the specified selector. If no <code>X509CRL</code>s
+ * match the selector, an empty <code>Collection</code> will be returned.
+ *
+ * @param selector A <code>CRLSelector</code> used to select which
+ * <code>X509CRL</code>s should be returned. Specify <code>null</code>
+ * to return all <code>X509CRL</code>s.
+ * @return A <code>Collection</code> of <code>X509CRL</code>s that
+ * match the specified selector
+ * @throws CertStoreException if an exception occurs
+ */
+ @Override
+ @SuppressWarnings("unchecked")
+ public synchronized Collection<X509CRL> engineGetCRLs(CRLSelector selector)
+ throws CertStoreException {
+
+ // if ldap URI we wrap the CRLSelector in an LDAPCRLSelector to
+ // avoid LDAP DN matching issues (see LDAPCRLSelector for more info)
+ if (ldap) {
+ X509CRLSelector xsel = (X509CRLSelector) selector;
+ try {
+ xsel = ldapHelper.wrap(xsel, null, ldapPath);
+ } catch (IOException ioe) {
+ throw new CertStoreException(ioe);
+ }
+ // Fetch the CRLs via LDAP. LDAPCertStore has its own
+ // caching mechanism, see the class description for more info.
+ // Safe cast since xsel is an X509 certificate selector.
+ try {
+ return (Collection<X509CRL>) ldapCertStore.getCRLs(xsel);
+ } catch (CertStoreException cse) {
+ throw new PKIX.CertStoreTypeException("LDAP", cse);
+ }
+ }
+
+ // Return the CRLs for this entry. It returns the cached value
+ // if it is still current and fetches the CRLs otherwise.
+ // For the caching details, see the top of this class.
+ long time = System.currentTimeMillis();
+ if (time - lastChecked < CHECK_INTERVAL) {
+ if (debug != null) {
+ debug.println("Returning CRL from cache");
+ }
+ return getMatchingCRLs(crl, selector);
+ }
+ lastChecked = time;
+ try {
+ URLConnection connection = uri.toURL().openConnection();
+ if (lastModified != 0) {
+ connection.setIfModifiedSince(lastModified);
+ }
+ long oldLastModified = lastModified;
+ connection.setConnectTimeout(CRL_CONNECT_TIMEOUT);
+ try (InputStream in = connection.getInputStream()) {
+ lastModified = connection.getLastModified();
+ if (oldLastModified != 0) {
+ if (oldLastModified == lastModified) {
+ if (debug != null) {
+ debug.println("Not modified, using cached copy");
+ }
+ return getMatchingCRLs(crl, selector);
+ } else if (connection instanceof HttpURLConnection) {
+ // some proxy servers omit last modified
+ HttpURLConnection hconn = (HttpURLConnection)connection;
+ if (hconn.getResponseCode()
+ == HttpURLConnection.HTTP_NOT_MODIFIED) {
+ if (debug != null) {
+ debug.println("Not modified, using cached copy");
+ }
+ return getMatchingCRLs(crl, selector);
+ }
+ }
+ }
+ if (debug != null) {
+ debug.println("Downloading new CRL...");
+ }
+ crl = (X509CRL) factory.generateCRL(in);
+ }
+ return getMatchingCRLs(crl, selector);
+ } catch (IOException | CRLException e) {
+ if (debug != null) {
+ debug.println("Exception fetching CRL:");
+ e.printStackTrace();
+ }
+ // exception, forget previous values
+ lastModified = 0;
+ crl = null;
+ throw new PKIX.CertStoreTypeException("URI",
+ new CertStoreException(e));
+ }
+ }
+
+ /**
+ * Checks if the specified X509CRL matches the criteria specified in the
+ * CRLSelector.
+ */
+ private static Collection<X509CRL> getMatchingCRLs
+ (X509CRL crl, CRLSelector selector) {
+ if (selector == null || (crl != null && selector.match(crl))) {
+ return Collections.singletonList(crl);
+ } else {
+ return Collections.emptyList();
+ }
+ }
+
+ /**
+ * CertStoreParameters for the URICertStore.
+ */
+ static class URICertStoreParameters implements CertStoreParameters {
+ private final URI uri;
+ private volatile int hashCode = 0;
+ URICertStoreParameters(URI uri) {
+ this.uri = uri;
+ }
+ @Override public boolean equals(Object obj) {
+ if (!(obj instanceof URICertStoreParameters)) {
+ return false;
+ }
+ URICertStoreParameters params = (URICertStoreParameters) obj;
+ return uri.equals(params.uri);
+ }
+ @Override public int hashCode() {
+ if (hashCode == 0) {
+ int result = 17;
+ result = 37*result + uri.hashCode();
+ hashCode = result;
+ }
+ return hashCode;
+ }
+ @Override public Object clone() {
+ try {
+ return super.clone();
+ } catch (CloneNotSupportedException e) {
+ /* Cannot happen */
+ throw new InternalError(e.toString(), e);
+ }
+ }
+ }
+
+ /**
+ * This class allows the URICertStore to be accessed as a CertStore.
+ */
+ private static class UCS extends CertStore {
+ protected UCS(CertStoreSpi spi, Provider p, String type,
+ CertStoreParameters params) {
+ super(spi, p, type, params);
+ }
+ }
+}
diff --git a/ojluni/src/main/java/sun/security/provider/certpath/UntrustedChecker.java b/ojluni/src/main/java/sun/security/provider/certpath/UntrustedChecker.java
old mode 100755
new mode 100644
diff --git a/ojluni/src/main/java/sun/security/provider/certpath/Vertex.java b/ojluni/src/main/java/sun/security/provider/certpath/Vertex.java
new file mode 100644
index 0000000..e2503f0
--- /dev/null
+++ b/ojluni/src/main/java/sun/security/provider/certpath/Vertex.java
@@ -0,0 +1,235 @@
+/*
+ * Copyright (c) 2000, 2012, 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.io.IOException;
+import java.security.cert.CertificateException;
+import java.security.cert.X509Certificate;
+
+import sun.security.util.Debug;
+import sun.security.x509.AuthorityKeyIdentifierExtension;
+import sun.security.x509.KeyIdentifier;
+import sun.security.x509.SubjectKeyIdentifierExtension;
+import sun.security.x509.X509CertImpl;
+
+/*
+ * This class represents a vertex in the adjacency list. A
+ * vertex in the builder's view is just a distinguished name
+ * in the directory. The Vertex contains a certificate
+ * along an attempted certification path, along with a pointer
+ * to a list of certificates that followed this one in various
+ * attempted certification paths.
+ *
+ * @author Sean Mullan
+ * @since 1.4
+ */
+public class Vertex {
+
+ private static final Debug debug = Debug.getInstance("certpath");
+ private X509Certificate cert;
+ private int index;
+ private Throwable throwable;
+
+ /**
+ * Constructor; creates vertex with index of -1
+ * Use setIndex method to set another index.
+ *
+ * @param cert X509Certificate associated with vertex
+ */
+ Vertex(X509Certificate cert) {
+ this.cert = cert;
+ this.index = -1;
+ }
+
+ /**
+ * return the certificate for this vertex
+ *
+ * @returns X509Certificate
+ */
+ public X509Certificate getCertificate() {
+ return cert;
+ }
+
+ /**
+ * get the index for this vertex, where the index is the row of the
+ * adjacency list that contains certificates that could follow this
+ * certificate.
+ *
+ * @returns int index for this vertex, or -1 if no following certificates.
+ */
+ public int getIndex() {
+ return index;
+ }
+
+ /**
+ * set the index for this vertex, where the index is the row of the
+ * adjacency list that contains certificates that could follow this
+ * certificate.
+ *
+ * @param ndx int index for vertex, or -1 if no following certificates.
+ */
+ void setIndex(int ndx) {
+ index = ndx;
+ }
+
+ /**
+ * return the throwable associated with this vertex;
+ * returns null if none.
+ *
+ * @returns Throwable
+ */
+ public Throwable getThrowable() {
+ return throwable;
+ }
+
+ /**
+ * set throwable associated with this vertex; default value is null.
+ *
+ * @param throwable Throwable associated with this vertex
+ * (or null)
+ */
+ void setThrowable(Throwable throwable) {
+ this.throwable = throwable;
+ }
+
+ /**
+ * Return full string representation of vertex
+ *
+ * @returns String representation of vertex
+ */
+ @Override
+ public String toString() {
+ return certToString() + throwableToString() + indexToString();
+ }
+
+ /**
+ * Return string representation of this vertex's
+ * certificate information.
+ *
+ * @returns String representation of certificate info
+ */
+ public String certToString() {
+ StringBuilder sb = new StringBuilder();
+
+ X509CertImpl x509Cert = null;
+ try {
+ x509Cert = X509CertImpl.toImpl(cert);
+ } catch (CertificateException ce) {
+ if (debug != null) {
+ debug.println("Vertex.certToString() unexpected exception");
+ ce.printStackTrace();
+ }
+ return sb.toString();
+ }
+
+ sb.append("Issuer: ").append
+ (x509Cert.getIssuerX500Principal()).append("\n");
+ sb.append("Subject: ").append
+ (x509Cert.getSubjectX500Principal()).append("\n");
+ sb.append("SerialNum: ").append
+ (x509Cert.getSerialNumber().toString(16)).append("\n");
+ sb.append("Expires: ").append
+ (x509Cert.getNotAfter().toString()).append("\n");
+ boolean[] iUID = x509Cert.getIssuerUniqueID();
+ if (iUID != null) {
+ sb.append("IssuerUID: ");
+ for (boolean b : iUID) {
+ sb.append(b ? 1 : 0);
+ }
+ sb.append("\n");
+ }
+ boolean[] sUID = x509Cert.getSubjectUniqueID();
+ if (sUID != null) {
+ sb.append("SubjectUID: ");
+ for (boolean b : sUID) {
+ sb.append(b ? 1 : 0);
+ }
+ sb.append("\n");
+ }
+ try {
+ SubjectKeyIdentifierExtension sKeyID =
+ x509Cert.getSubjectKeyIdentifierExtension();
+ if (sKeyID != null) {
+ KeyIdentifier keyID = sKeyID.get(
+ SubjectKeyIdentifierExtension.KEY_ID);
+ sb.append("SubjKeyID: ").append(keyID.toString());
+ }
+ AuthorityKeyIdentifierExtension aKeyID =
+ x509Cert.getAuthorityKeyIdentifierExtension();
+ if (aKeyID != null) {
+ KeyIdentifier keyID = (KeyIdentifier)aKeyID.get(
+ AuthorityKeyIdentifierExtension.KEY_ID);
+ sb.append("AuthKeyID: ").append(keyID.toString());
+ }
+ } catch (IOException e) {
+ if (debug != null) {
+ debug.println("Vertex.certToString() unexpected exception");
+ e.printStackTrace();
+ }
+ }
+ return sb.toString();
+ }
+
+ /**
+ * return Vertex throwable as String compatible with
+ * the way toString returns other information
+ *
+ * @returns String form of exception (or "none")
+ */
+ public String throwableToString() {
+ StringBuilder sb = new StringBuilder("Exception: ");
+ if (throwable != null)
+ sb.append(throwable.toString());
+ else
+ sb.append("null");
+ sb.append("\n");
+ return sb.toString();
+ }
+
+ /**
+ * return Vertex index as String compatible with
+ * the way other Vertex.xToString() methods display
+ * information.
+ *
+ * @returns String form of index as "Last cert? [Yes/No]
+ */
+ public String moreToString() {
+ StringBuilder sb = new StringBuilder("Last cert? ");
+ sb.append((index == -1) ? "Yes" : "No");
+ sb.append("\n");
+ return sb.toString();
+ }
+
+ /**
+ * return Vertex index as String compatible with
+ * the way other Vertex.xToString() methods displays other information.
+ *
+ * @returns String form of index as "Index: [numeric index]"
+ */
+ public String indexToString() {
+ return "Index: " + index + "\n";
+ }
+}
diff --git a/ojluni/src/main/java/sun/security/provider/certpath/X509CertPath.java b/ojluni/src/main/java/sun/security/provider/certpath/X509CertPath.java
old mode 100755
new mode 100644
index 27465b5..f738b5f
--- a/ojluni/src/main/java/sun/security/provider/certpath/X509CertPath.java
+++ b/ojluni/src/main/java/sun/security/provider/certpath/X509CertPath.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2000, 2006, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2000, 2012, 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,7 +25,6 @@
package sun.security.provider.certpath;
-import java.io.BufferedInputStream;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
@@ -34,9 +33,10 @@
import java.security.cert.Certificate;
import java.security.cert.CertificateException;
import java.security.cert.CertificateFactory;
+import java.security.cert.CertPath;
import java.security.cert.X509Certificate;
import java.util.*;
-import java.security.cert.CertPath;
+
import sun.security.pkcs.ContentInfo;
import sun.security.pkcs.PKCS7;
import sun.security.pkcs.SignerInfo;
@@ -45,7 +45,6 @@
import sun.security.util.DerOutputStream;
import sun.security.util.DerInputStream;
-
/**
* A {@link java.security.cert.CertPath CertPath} (certification path)
* consisting exclusively of
@@ -84,7 +83,7 @@
private static final Collection<String> encodingList;
static {
- List<String> list = new ArrayList<String>(2);
+ List<String> list = new ArrayList<>(2);
list.add(PKIPATH_ENCODING);
list.add(PKCS7_ENCODING);
encodingList = Collections.unmodifiableCollection(list);
@@ -101,11 +100,18 @@
* @exception CertificateException if <code>certs</code> contains an element
* that is not an <code>X509Certificate</code>
*/
+ @SuppressWarnings("unchecked")
public X509CertPath(List<? extends Certificate> certs) throws CertificateException {
super("X.509");
// Ensure that the List contains only X509Certificates
- for (Object obj : (List<?>)certs) {
+ //
+ // Note; The certs parameter is not necessarily to be of Certificate
+ // for some old code. For compatibility, to make sure the exception
+ // is CertificateException, rather than ClassCastException, please
+ // don't use
+ // for (Certificate obj : certs)
+ for (Object obj : certs) {
if (obj instanceof X509Certificate == false) {
throw new CertificateException
("List is not all X509Certificates: "
@@ -147,12 +153,15 @@
throws CertificateException {
super("X.509");
- if (PKIPATH_ENCODING.equals(encoding)) {
- certs = parsePKIPATH(is);
- } else if (PKCS7_ENCODING.equals(encoding)) {
- certs = parsePKCS7(is);
- } else {
- throw new CertificateException("unsupported encoding");
+ switch (encoding) {
+ case PKIPATH_ENCODING:
+ certs = parsePKIPATH(is);
+ break;
+ case PKCS7_ENCODING:
+ certs = parsePKCS7(is);
+ break;
+ default:
+ throw new CertificateException("unsupported encoding");
}
}
@@ -192,10 +201,8 @@
return Collections.unmodifiableList(certList);
} catch (IOException ioe) {
- CertificateException ce = new CertificateException("IOException" +
- " parsing PkiPath data: " + ioe);
- ce.initCause(ioe);
- throw ce;
+ throw new CertificateException("IOException parsing PkiPath data: "
+ + ioe, ioe);
}
}
@@ -220,7 +227,7 @@
// Copy the entire input stream into an InputStream that does
// support mark
is = new ByteArrayInputStream(readAllBytes(is));
- };
+ }
PKCS7 pkcs7 = new PKCS7(is);
X509Certificate[] certArray = pkcs7.getCertificates();
@@ -265,6 +272,7 @@
* @return the encoded bytes
* @exception CertificateEncodingException if an encoding error occurs
*/
+ @Override
public byte[] getEncoded() throws CertificateEncodingException {
// @@@ Should cache the encoded form
return encodePKIPATH();
@@ -301,10 +309,8 @@
return derout.toByteArray();
} catch (IOException ioe) {
- CertificateEncodingException ce = new CertificateEncodingException
- ("IOException encoding PkiPath data: " + ioe);
- ce.initCause(ioe);
- throw ce;
+ throw new CertificateEncodingException("IOException encoding " +
+ "PkiPath data: " + ioe, ioe);
}
}
@@ -337,14 +343,16 @@
* @exception CertificateEncodingException if an encoding error occurs or
* the encoding requested is not supported
*/
+ @Override
public byte[] getEncoded(String encoding)
throws CertificateEncodingException {
- if (PKIPATH_ENCODING.equals(encoding)) {
- return encodePKIPATH();
- } else if (PKCS7_ENCODING.equals(encoding)) {
- return encodePKCS7();
- } else {
- throw new CertificateEncodingException("unsupported encoding");
+ switch (encoding) {
+ case PKIPATH_ENCODING:
+ return encodePKIPATH();
+ case PKCS7_ENCODING:
+ return encodePKCS7();
+ default:
+ throw new CertificateEncodingException("unsupported encoding");
}
}
@@ -370,6 +378,7 @@
* @return an <code>Iterator</code> over the names of the supported
* encodings (as Strings)
*/
+ @Override
public Iterator<String> getEncodings() {
return getEncodingsStatic();
}
@@ -381,6 +390,7 @@
* @return an immutable <code>List</code> of <code>X509Certificate</code>s
* (may be empty, but not null)
*/
+ @Override
public List<X509Certificate> getCertificates() {
return certs;
}
diff --git a/ojluni/src/main/java/sun/security/provider/certpath/X509CertificatePair.java b/ojluni/src/main/java/sun/security/provider/certpath/X509CertificatePair.java
old mode 100755
new mode 100644
index 20d05f7..ea139dd
--- a/ojluni/src/main/java/sun/security/provider/certpath/X509CertificatePair.java
+++ b/ojluni/src/main/java/sun/security/provider/certpath/X509CertificatePair.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2000, 2002, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2000, 2012, 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
@@ -79,7 +79,8 @@
private X509Certificate reverse;
private byte[] encoded;
- private static final Cache cache = Cache.newSoftMemoryCache(750);
+ private static final Cache<Object, X509CertificatePair> cache
+ = Cache.newSoftMemoryCache(750);
/**
* Creates an empty instance of X509CertificatePair.
@@ -114,7 +115,7 @@
*
* For internal use only, external code should use generateCertificatePair.
*/
- private X509CertificatePair(byte[] encoded)throws CertificateException {
+ private X509CertificatePair(byte[] encoded) throws CertificateException {
try {
parse(new DerValue(encoded));
this.encoded = encoded;
@@ -138,7 +139,7 @@
public static synchronized X509CertificatePair generateCertificatePair
(byte[] encoded) throws CertificateException {
Object key = new Cache.EqualByteArray(encoded);
- X509CertificatePair pair = (X509CertificatePair)cache.get(key);
+ X509CertificatePair pair = cache.get(key);
if (pair != null) {
return pair;
}
@@ -206,13 +207,14 @@
*
* @return A String describing the contents of the pair.
*/
+ @Override
public String toString() {
- StringBuffer sb = new StringBuffer();
+ StringBuilder sb = new StringBuilder();
sb.append("X.509 Certificate Pair: [\n");
if (forward != null)
- sb.append(" Forward: " + forward + "\n");
+ sb.append(" Forward: ").append(forward).append("\n");
if (reverse != null)
- sb.append(" Reverse: " + reverse + "\n");
+ sb.append(" Reverse: ").append(reverse).append("\n");
sb.append("]");
return sb.toString();
}
diff --git a/ojluni/src/main/java/sun/security/provider/certpath/ldap/LDAPCertStore.java b/ojluni/src/main/java/sun/security/provider/certpath/ldap/LDAPCertStore.java
new file mode 100644
index 0000000..5a24a69
--- /dev/null
+++ b/ojluni/src/main/java/sun/security/provider/certpath/ldap/LDAPCertStore.java
@@ -0,0 +1,1086 @@
+/*
+ * Copyright (c) 2000, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * 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.ldap;
+
+import java.io.ByteArrayInputStream;
+import java.io.IOException;
+import java.math.BigInteger;
+import java.net.URI;
+import java.util.*;
+import javax.naming.Context;
+import javax.naming.NamingEnumeration;
+import javax.naming.NamingException;
+import javax.naming.NameNotFoundException;
+import javax.naming.directory.Attribute;
+import javax.naming.directory.Attributes;
+import javax.naming.directory.BasicAttributes;
+import javax.naming.directory.DirContext;
+import javax.naming.directory.InitialDirContext;
+
+import java.security.*;
+import java.security.cert.Certificate;
+import java.security.cert.*;
+import javax.security.auth.x500.X500Principal;
+
+import sun.misc.HexDumpEncoder;
+import sun.security.provider.certpath.X509CertificatePair;
+import sun.security.util.Cache;
+import sun.security.util.Debug;
+import sun.security.x509.X500Name;
+import sun.security.action.GetBooleanAction;
+import sun.security.action.GetPropertyAction;
+
+/**
+ * A <code>CertStore</code> that retrieves <code>Certificates</code> and
+ * <code>CRL</code>s from an LDAP directory, using the PKIX LDAP V2 Schema
+ * (RFC 2587):
+ * <a href="http://www.ietf.org/rfc/rfc2587.txt">
+ * http://www.ietf.org/rfc/rfc2587.txt</a>.
+ * <p>
+ * Before calling the {@link #engineGetCertificates engineGetCertificates} or
+ * {@link #engineGetCRLs engineGetCRLs} methods, the
+ * {@link #LDAPCertStore(CertStoreParameters)
+ * LDAPCertStore(CertStoreParameters)} constructor is called to create the
+ * <code>CertStore</code> and establish the DNS name and port of the LDAP
+ * server from which <code>Certificate</code>s and <code>CRL</code>s will be
+ * retrieved.
+ * <p>
+ * <b>Concurrent Access</b>
+ * <p>
+ * As described in the javadoc for <code>CertStoreSpi</code>, the
+ * <code>engineGetCertificates</code> and <code>engineGetCRLs</code> methods
+ * must be thread-safe. That is, multiple threads may concurrently
+ * invoke these methods on a single <code>LDAPCertStore</code> object
+ * (or more than one) with no ill effects. This allows a
+ * <code>CertPathBuilder</code> to search for a CRL while simultaneously
+ * searching for further certificates, for instance.
+ * <p>
+ * This is achieved by adding the <code>synchronized</code> keyword to the
+ * <code>engineGetCertificates</code> and <code>engineGetCRLs</code> methods.
+ * <p>
+ * This classes uses caching and requests multiple attributes at once to
+ * minimize LDAP round trips. The cache is associated with the CertStore
+ * instance. It uses soft references to hold the values to minimize impact
+ * on footprint and currently has a maximum size of 750 attributes and a
+ * 30 second default lifetime.
+ * <p>
+ * We always request CA certificates, cross certificate pairs, and ARLs in
+ * a single LDAP request when any one of them is needed. The reason is that
+ * we typically need all of them anyway and requesting them in one go can
+ * reduce the number of requests to a third. Even if we don't need them,
+ * these attributes are typically small enough not to cause a noticeable
+ * overhead. In addition, when the prefetchCRLs flag is true, we also request
+ * the full CRLs. It is currently false initially but set to true once any
+ * request for an ARL to the server returns an null value. The reason is
+ * that CRLs could be rather large but are rarely used. This implementation
+ * should improve performance in most cases.
+ *
+ * @see java.security.cert.CertStore
+ *
+ * @since 1.4
+ * @author Steve Hanna
+ * @author Andreas Sterbenz
+ */
+public final class LDAPCertStore extends CertStoreSpi {
+
+ private static final Debug debug = Debug.getInstance("certpath");
+
+ private final static boolean DEBUG = false;
+
+ /**
+ * LDAP attribute identifiers.
+ */
+ private static final String USER_CERT = "userCertificate;binary";
+ private static final String CA_CERT = "cACertificate;binary";
+ private static final String CROSS_CERT = "crossCertificatePair;binary";
+ private static final String CRL = "certificateRevocationList;binary";
+ private static final String ARL = "authorityRevocationList;binary";
+ private static final String DELTA_CRL = "deltaRevocationList;binary";
+
+ // Constants for various empty values
+ private final static String[] STRING0 = new String[0];
+
+ private final static byte[][] BB0 = new byte[0][];
+
+ private final static Attributes EMPTY_ATTRIBUTES = new BasicAttributes();
+
+ // cache related constants
+ private final static int DEFAULT_CACHE_SIZE = 750;
+ private final static int DEFAULT_CACHE_LIFETIME = 30;
+
+ private final static int LIFETIME;
+
+ private final static String PROP_LIFETIME =
+ "sun.security.certpath.ldap.cache.lifetime";
+
+ /*
+ * Internal system property, that when set to "true", disables the
+ * JNDI application resource files lookup to prevent recursion issues
+ * when validating signed JARs with LDAP URLs in certificates.
+ */
+ private final static String PROP_DISABLE_APP_RESOURCE_FILES =
+ "sun.security.certpath.ldap.disable.app.resource.files";
+
+ static {
+ String s = AccessController.doPrivileged(
+ new GetPropertyAction(PROP_LIFETIME));
+ if (s != null) {
+ LIFETIME = Integer.parseInt(s); // throws NumberFormatException
+ } else {
+ LIFETIME = DEFAULT_CACHE_LIFETIME;
+ }
+ }
+
+ /**
+ * The CertificateFactory used to decode certificates from
+ * their binary stored form.
+ */
+ private CertificateFactory cf;
+ /**
+ * The JNDI directory context.
+ */
+ private DirContext ctx;
+
+ /**
+ * Flag indicating whether we should prefetch CRLs.
+ */
+ private boolean prefetchCRLs = false;
+
+ private final Cache<String, byte[][]> valueCache;
+
+ private int cacheHits = 0;
+ private int cacheMisses = 0;
+ private int requests = 0;
+
+ /**
+ * Creates a <code>CertStore</code> with the specified parameters.
+ * For this class, the parameters object must be an instance of
+ * <code>LDAPCertStoreParameters</code>.
+ *
+ * @param params the algorithm parameters
+ * @exception InvalidAlgorithmParameterException if params is not an
+ * instance of <code>LDAPCertStoreParameters</code>
+ */
+ public LDAPCertStore(CertStoreParameters params)
+ throws InvalidAlgorithmParameterException {
+ super(params);
+ if (!(params instanceof LDAPCertStoreParameters))
+ throw new InvalidAlgorithmParameterException(
+ "parameters must be LDAPCertStoreParameters");
+
+ LDAPCertStoreParameters lparams = (LDAPCertStoreParameters) params;
+
+ // Create InitialDirContext needed to communicate with the server
+ createInitialDirContext(lparams.getServerName(), lparams.getPort());
+
+ // Create CertificateFactory for use later on
+ try {
+ cf = CertificateFactory.getInstance("X.509");
+ } catch (CertificateException e) {
+ throw new InvalidAlgorithmParameterException(
+ "unable to create CertificateFactory for X.509");
+ }
+ if (LIFETIME == 0) {
+ valueCache = Cache.newNullCache();
+ } else if (LIFETIME < 0) {
+ valueCache = Cache.newSoftMemoryCache(DEFAULT_CACHE_SIZE);
+ } else {
+ valueCache = Cache.newSoftMemoryCache(DEFAULT_CACHE_SIZE, LIFETIME);
+ }
+ }
+
+ /**
+ * Returns an LDAP CertStore. This method consults a cache of
+ * CertStores (shared per JVM) using the LDAP server/port as a key.
+ */
+ private static final Cache<LDAPCertStoreParameters, CertStore>
+ certStoreCache = Cache.newSoftMemoryCache(185);
+ static synchronized CertStore getInstance(LDAPCertStoreParameters params)
+ throws NoSuchAlgorithmException, InvalidAlgorithmParameterException {
+ CertStore lcs = certStoreCache.get(params);
+ if (lcs == null) {
+ lcs = CertStore.getInstance("LDAP", params);
+ certStoreCache.put(params, lcs);
+ } else {
+ if (debug != null) {
+ debug.println("LDAPCertStore.getInstance: cache hit");
+ }
+ }
+ return lcs;
+ }
+
+ /**
+ * Create InitialDirContext.
+ *
+ * @param server Server DNS name hosting LDAP service
+ * @param port Port at which server listens for requests
+ * @throws InvalidAlgorithmParameterException if creation fails
+ */
+ private void createInitialDirContext(String server, int port)
+ throws InvalidAlgorithmParameterException {
+ String url = "ldap://" + server + ":" + port;
+ Hashtable<String,Object> env = new Hashtable<>();
+ env.put(Context.INITIAL_CONTEXT_FACTORY,
+ "com.sun.jndi.ldap.LdapCtxFactory");
+ env.put(Context.PROVIDER_URL, url);
+
+ // If property is set to true, disable application resource file lookup.
+ boolean disableAppResourceFiles = AccessController.doPrivileged(
+ new GetBooleanAction(PROP_DISABLE_APP_RESOURCE_FILES));
+ if (disableAppResourceFiles) {
+ if (debug != null) {
+ debug.println("LDAPCertStore disabling app resource files");
+ }
+ env.put("com.sun.naming.disable.app.resource.files", "true");
+ }
+
+ try {
+ ctx = new InitialDirContext(env);
+ /*
+ * By default, follow referrals unless application has
+ * overridden property in an application resource file.
+ */
+ Hashtable<?,?> currentEnv = ctx.getEnvironment();
+ if (currentEnv.get(Context.REFERRAL) == null) {
+ ctx.addToEnvironment(Context.REFERRAL, "follow");
+ }
+ } catch (NamingException e) {
+ if (debug != null) {
+ debug.println("LDAPCertStore.engineInit about to throw "
+ + "InvalidAlgorithmParameterException");
+ e.printStackTrace();
+ }
+ Exception ee = new InvalidAlgorithmParameterException
+ ("unable to create InitialDirContext using supplied parameters");
+ ee.initCause(e);
+ throw (InvalidAlgorithmParameterException)ee;
+ }
+ }
+
+ /**
+ * Private class encapsulating the actual LDAP operations and cache
+ * handling. Use:
+ *
+ * LDAPRequest request = new LDAPRequest(dn);
+ * request.addRequestedAttribute(CROSS_CERT);
+ * request.addRequestedAttribute(CA_CERT);
+ * byte[][] crossValues = request.getValues(CROSS_CERT);
+ * byte[][] caValues = request.getValues(CA_CERT);
+ *
+ * At most one LDAP request is sent for each instance created. If all
+ * getValues() calls can be satisfied from the cache, no request
+ * is sent at all. If a request is sent, all requested attributes
+ * are always added to the cache irrespective of whether the getValues()
+ * method is called.
+ */
+ private class LDAPRequest {
+
+ private final String name;
+ private Map<String, byte[][]> valueMap;
+ private final List<String> requestedAttributes;
+
+ LDAPRequest(String name) {
+ this.name = name;
+ requestedAttributes = new ArrayList<>(5);
+ }
+
+ String getName() {
+ return name;
+ }
+
+ void addRequestedAttribute(String attrId) {
+ if (valueMap != null) {
+ throw new IllegalStateException("Request already sent");
+ }
+ requestedAttributes.add(attrId);
+ }
+
+ /**
+ * Gets one or more binary values from an attribute.
+ *
+ * @param name the location holding the attribute
+ * @param attrId the attribute identifier
+ * @return an array of binary values (byte arrays)
+ * @throws NamingException if a naming exception occurs
+ */
+ byte[][] getValues(String attrId) throws NamingException {
+ if (DEBUG && ((cacheHits + cacheMisses) % 50 == 0)) {
+ System.out.println("Cache hits: " + cacheHits + "; misses: "
+ + cacheMisses);
+ }
+ String cacheKey = name + "|" + attrId;
+ byte[][] values = valueCache.get(cacheKey);
+ if (values != null) {
+ cacheHits++;
+ return values;
+ }
+ cacheMisses++;
+ Map<String, byte[][]> attrs = getValueMap();
+ values = attrs.get(attrId);
+ return values;
+ }
+
+ /**
+ * Get a map containing the values for this request. The first time
+ * this method is called on an object, the LDAP request is sent,
+ * the results parsed and added to a private map and also to the
+ * cache of this LDAPCertStore. Subsequent calls return the private
+ * map immediately.
+ *
+ * The map contains an entry for each requested attribute. The
+ * attribute name is the key, values are byte[][]. If there are no
+ * values for that attribute, values are byte[0][].
+ *
+ * @return the value Map
+ * @throws NamingException if a naming exception occurs
+ */
+ private Map<String, byte[][]> getValueMap() throws NamingException {
+ if (valueMap != null) {
+ return valueMap;
+ }
+ if (DEBUG) {
+ System.out.println("Request: " + name + ":" + requestedAttributes);
+ requests++;
+ if (requests % 5 == 0) {
+ System.out.println("LDAP requests: " + requests);
+ }
+ }
+ valueMap = new HashMap<>(8);
+ String[] attrIds = requestedAttributes.toArray(STRING0);
+ Attributes attrs;
+ try {
+ attrs = ctx.getAttributes(name, attrIds);
+ } catch (NameNotFoundException e) {
+ // name does not exist on this LDAP server
+ // treat same as not attributes found
+ attrs = EMPTY_ATTRIBUTES;
+ }
+ for (String attrId : requestedAttributes) {
+ Attribute attr = attrs.get(attrId);
+ byte[][] values = getAttributeValues(attr);
+ cacheAttribute(attrId, values);
+ valueMap.put(attrId, values);
+ }
+ return valueMap;
+ }
+
+ /**
+ * Add the values to the cache.
+ */
+ private void cacheAttribute(String attrId, byte[][] values) {
+ String cacheKey = name + "|" + attrId;
+ valueCache.put(cacheKey, values);
+ }
+
+ /**
+ * Get the values for the given attribute. If the attribute is null
+ * or does not contain any values, a zero length byte array is
+ * returned. NOTE that it is assumed that all values are byte arrays.
+ */
+ private byte[][] getAttributeValues(Attribute attr)
+ throws NamingException {
+ byte[][] values;
+ if (attr == null) {
+ values = BB0;
+ } else {
+ values = new byte[attr.size()][];
+ int i = 0;
+ NamingEnumeration<?> enum_ = attr.getAll();
+ while (enum_.hasMore()) {
+ Object obj = enum_.next();
+ if (debug != null) {
+ if (obj instanceof String) {
+ debug.println("LDAPCertStore.getAttrValues() "
+ + "enum.next is a string!: " + obj);
+ }
+ }
+ byte[] value = (byte[])obj;
+ values[i++] = value;
+ }
+ }
+ return values;
+ }
+
+ }
+
+ /*
+ * Gets certificates from an attribute id and location in the LDAP
+ * directory. Returns a Collection containing only the Certificates that
+ * match the specified CertSelector.
+ *
+ * @param name the location holding the attribute
+ * @param id the attribute identifier
+ * @param sel a CertSelector that the Certificates must match
+ * @return a Collection of Certificates found
+ * @throws CertStoreException if an exception occurs
+ */
+ private Collection<X509Certificate> getCertificates(LDAPRequest request,
+ String id, X509CertSelector sel) throws CertStoreException {
+
+ /* fetch encoded certs from storage */
+ byte[][] encodedCert;
+ try {
+ encodedCert = request.getValues(id);
+ } catch (NamingException namingEx) {
+ throw new CertStoreException(namingEx);
+ }
+
+ int n = encodedCert.length;
+ if (n == 0) {
+ return Collections.emptySet();
+ }
+
+ List<X509Certificate> certs = new ArrayList<>(n);
+ /* decode certs and check if they satisfy selector */
+ for (int i = 0; i < n; i++) {
+ ByteArrayInputStream bais = new ByteArrayInputStream(encodedCert[i]);
+ try {
+ Certificate cert = cf.generateCertificate(bais);
+ if (sel.match(cert)) {
+ certs.add((X509Certificate)cert);
+ }
+ } catch (CertificateException e) {
+ if (debug != null) {
+ debug.println("LDAPCertStore.getCertificates() encountered "
+ + "exception while parsing cert, skipping the bad data: ");
+ HexDumpEncoder encoder = new HexDumpEncoder();
+ debug.println(
+ "[ " + encoder.encodeBuffer(encodedCert[i]) + " ]");
+ }
+ }
+ }
+
+ return certs;
+ }
+
+ /*
+ * Gets certificate pairs from an attribute id and location in the LDAP
+ * directory.
+ *
+ * @param name the location holding the attribute
+ * @param id the attribute identifier
+ * @return a Collection of X509CertificatePairs found
+ * @throws CertStoreException if an exception occurs
+ */
+ private Collection<X509CertificatePair> getCertPairs(
+ LDAPRequest request, String id) throws CertStoreException {
+
+ /* fetch the encoded cert pairs from storage */
+ byte[][] encodedCertPair;
+ try {
+ encodedCertPair = request.getValues(id);
+ } catch (NamingException namingEx) {
+ throw new CertStoreException(namingEx);
+ }
+
+ int n = encodedCertPair.length;
+ if (n == 0) {
+ return Collections.emptySet();
+ }
+
+ List<X509CertificatePair> certPairs = new ArrayList<>(n);
+ /* decode each cert pair and add it to the Collection */
+ for (int i = 0; i < n; i++) {
+ try {
+ X509CertificatePair certPair =
+ X509CertificatePair.generateCertificatePair(encodedCertPair[i]);
+ certPairs.add(certPair);
+ } catch (CertificateException e) {
+ if (debug != null) {
+ debug.println(
+ "LDAPCertStore.getCertPairs() encountered exception "
+ + "while parsing cert, skipping the bad data: ");
+ HexDumpEncoder encoder = new HexDumpEncoder();
+ debug.println(
+ "[ " + encoder.encodeBuffer(encodedCertPair[i]) + " ]");
+ }
+ }
+ }
+
+ return certPairs;
+ }
+
+ /*
+ * Looks at certificate pairs stored in the crossCertificatePair attribute
+ * at the specified location in the LDAP directory. Returns a Collection
+ * containing all Certificates stored in the forward component that match
+ * the forward CertSelector and all Certificates stored in the reverse
+ * component that match the reverse CertSelector.
+ * <p>
+ * If either forward or reverse is null, all certificates from the
+ * corresponding component will be rejected.
+ *
+ * @param name the location to look in
+ * @param forward the forward CertSelector (or null)
+ * @param reverse the reverse CertSelector (or null)
+ * @return a Collection of Certificates found
+ * @throws CertStoreException if an exception occurs
+ */
+ private Collection<X509Certificate> getMatchingCrossCerts(
+ LDAPRequest request, X509CertSelector forward,
+ X509CertSelector reverse)
+ throws CertStoreException {
+ // Get the cert pairs
+ Collection<X509CertificatePair> certPairs =
+ getCertPairs(request, CROSS_CERT);
+
+ // Find Certificates that match and put them in a list
+ ArrayList<X509Certificate> matchingCerts = new ArrayList<>();
+ for (X509CertificatePair certPair : certPairs) {
+ X509Certificate cert;
+ if (forward != null) {
+ cert = certPair.getForward();
+ if ((cert != null) && forward.match(cert)) {
+ matchingCerts.add(cert);
+ }
+ }
+ if (reverse != null) {
+ cert = certPair.getReverse();
+ if ((cert != null) && reverse.match(cert)) {
+ matchingCerts.add(cert);
+ }
+ }
+ }
+ return matchingCerts;
+ }
+
+ /**
+ * Returns a <code>Collection</code> of <code>Certificate</code>s that
+ * match the specified selector. If no <code>Certificate</code>s
+ * match the selector, an empty <code>Collection</code> will be returned.
+ * <p>
+ * It is not practical to search every entry in the LDAP database for
+ * matching <code>Certificate</code>s. Instead, the <code>CertSelector</code>
+ * is examined in order to determine where matching <code>Certificate</code>s
+ * are likely to be found (according to the PKIX LDAPv2 schema, RFC 2587).
+ * If the subject is specified, its directory entry is searched. If the
+ * issuer is specified, its directory entry is searched. If neither the
+ * subject nor the issuer are specified (or the selector is not an
+ * <code>X509CertSelector</code>), a <code>CertStoreException</code> is
+ * thrown.
+ *
+ * @param selector a <code>CertSelector</code> used to select which
+ * <code>Certificate</code>s should be returned.
+ * @return a <code>Collection</code> of <code>Certificate</code>s that
+ * match the specified selector
+ * @throws CertStoreException if an exception occurs
+ */
+ public synchronized Collection<X509Certificate> engineGetCertificates
+ (CertSelector selector) throws CertStoreException {
+ if (debug != null) {
+ debug.println("LDAPCertStore.engineGetCertificates() selector: "
+ + String.valueOf(selector));
+ }
+
+ if (selector == null) {
+ selector = new X509CertSelector();
+ }
+ if (!(selector instanceof X509CertSelector)) {
+ throw new CertStoreException("LDAPCertStore needs an X509CertSelector " +
+ "to find certs");
+ }
+ X509CertSelector xsel = (X509CertSelector) selector;
+ int basicConstraints = xsel.getBasicConstraints();
+ String subject = xsel.getSubjectAsString();
+ String issuer = xsel.getIssuerAsString();
+ HashSet<X509Certificate> certs = new HashSet<>();
+ if (debug != null) {
+ debug.println("LDAPCertStore.engineGetCertificates() basicConstraints: "
+ + basicConstraints);
+ }
+
+ // basicConstraints:
+ // -2: only EE certs accepted
+ // -1: no check is done
+ // 0: any CA certificate accepted
+ // >1: certificate's basicConstraints extension pathlen must match
+ if (subject != null) {
+ if (debug != null) {
+ debug.println("LDAPCertStore.engineGetCertificates() "
+ + "subject is not null");
+ }
+ LDAPRequest request = new LDAPRequest(subject);
+ if (basicConstraints > -2) {
+ request.addRequestedAttribute(CROSS_CERT);
+ request.addRequestedAttribute(CA_CERT);
+ request.addRequestedAttribute(ARL);
+ if (prefetchCRLs) {
+ request.addRequestedAttribute(CRL);
+ }
+ }
+ if (basicConstraints < 0) {
+ request.addRequestedAttribute(USER_CERT);
+ }
+
+ if (basicConstraints > -2) {
+ certs.addAll(getMatchingCrossCerts(request, xsel, null));
+ if (debug != null) {
+ debug.println("LDAPCertStore.engineGetCertificates() after "
+ + "getMatchingCrossCerts(subject,xsel,null),certs.size(): "
+ + certs.size());
+ }
+ certs.addAll(getCertificates(request, CA_CERT, xsel));
+ if (debug != null) {
+ debug.println("LDAPCertStore.engineGetCertificates() after "
+ + "getCertificates(subject,CA_CERT,xsel),certs.size(): "
+ + certs.size());
+ }
+ }
+ if (basicConstraints < 0) {
+ certs.addAll(getCertificates(request, USER_CERT, xsel));
+ if (debug != null) {
+ debug.println("LDAPCertStore.engineGetCertificates() after "
+ + "getCertificates(subject,USER_CERT, xsel),certs.size(): "
+ + certs.size());
+ }
+ }
+ } else {
+ if (debug != null) {
+ debug.println
+ ("LDAPCertStore.engineGetCertificates() subject is null");
+ }
+ if (basicConstraints == -2) {
+ throw new CertStoreException("need subject to find EE certs");
+ }
+ if (issuer == null) {
+ throw new CertStoreException("need subject or issuer to find certs");
+ }
+ }
+ if (debug != null) {
+ debug.println("LDAPCertStore.engineGetCertificates() about to "
+ + "getMatchingCrossCerts...");
+ }
+ if ((issuer != null) && (basicConstraints > -2)) {
+ LDAPRequest request = new LDAPRequest(issuer);
+ request.addRequestedAttribute(CROSS_CERT);
+ request.addRequestedAttribute(CA_CERT);
+ request.addRequestedAttribute(ARL);
+ if (prefetchCRLs) {
+ request.addRequestedAttribute(CRL);
+ }
+
+ certs.addAll(getMatchingCrossCerts(request, null, xsel));
+ if (debug != null) {
+ debug.println("LDAPCertStore.engineGetCertificates() after "
+ + "getMatchingCrossCerts(issuer,null,xsel),certs.size(): "
+ + certs.size());
+ }
+ certs.addAll(getCertificates(request, CA_CERT, xsel));
+ if (debug != null) {
+ debug.println("LDAPCertStore.engineGetCertificates() after "
+ + "getCertificates(issuer,CA_CERT,xsel),certs.size(): "
+ + certs.size());
+ }
+ }
+ if (debug != null) {
+ debug.println("LDAPCertStore.engineGetCertificates() returning certs");
+ }
+ return certs;
+ }
+
+ /*
+ * Gets CRLs from an attribute id and location in the LDAP directory.
+ * Returns a Collection containing only the CRLs that match the
+ * specified CRLSelector.
+ *
+ * @param name the location holding the attribute
+ * @param id the attribute identifier
+ * @param sel a CRLSelector that the CRLs must match
+ * @return a Collection of CRLs found
+ * @throws CertStoreException if an exception occurs
+ */
+ private Collection<X509CRL> getCRLs(LDAPRequest request, String id,
+ X509CRLSelector sel) throws CertStoreException {
+
+ /* fetch the encoded crls from storage */
+ byte[][] encodedCRL;
+ try {
+ encodedCRL = request.getValues(id);
+ } catch (NamingException namingEx) {
+ throw new CertStoreException(namingEx);
+ }
+
+ int n = encodedCRL.length;
+ if (n == 0) {
+ return Collections.emptySet();
+ }
+
+ List<X509CRL> crls = new ArrayList<>(n);
+ /* decode each crl and check if it matches selector */
+ for (int i = 0; i < n; i++) {
+ try {
+ CRL crl = cf.generateCRL(new ByteArrayInputStream(encodedCRL[i]));
+ if (sel.match(crl)) {
+ crls.add((X509CRL)crl);
+ }
+ } catch (CRLException e) {
+ if (debug != null) {
+ debug.println("LDAPCertStore.getCRLs() encountered exception"
+ + " while parsing CRL, skipping the bad data: ");
+ HexDumpEncoder encoder = new HexDumpEncoder();
+ debug.println("[ " + encoder.encodeBuffer(encodedCRL[i]) + " ]");
+ }
+ }
+ }
+
+ return crls;
+ }
+
+ /**
+ * Returns a <code>Collection</code> of <code>CRL</code>s that
+ * match the specified selector. If no <code>CRL</code>s
+ * match the selector, an empty <code>Collection</code> will be returned.
+ * <p>
+ * It is not practical to search every entry in the LDAP database for
+ * matching <code>CRL</code>s. Instead, the <code>CRLSelector</code>
+ * is examined in order to determine where matching <code>CRL</code>s
+ * are likely to be found (according to the PKIX LDAPv2 schema, RFC 2587).
+ * If issuerNames or certChecking are specified, the issuer's directory
+ * entry is searched. If neither issuerNames or certChecking are specified
+ * (or the selector is not an <code>X509CRLSelector</code>), a
+ * <code>CertStoreException</code> is thrown.
+ *
+ * @param selector A <code>CRLSelector</code> used to select which
+ * <code>CRL</code>s should be returned. Specify <code>null</code>
+ * to return all <code>CRL</code>s.
+ * @return A <code>Collection</code> of <code>CRL</code>s that
+ * match the specified selector
+ * @throws CertStoreException if an exception occurs
+ */
+ public synchronized Collection<X509CRL> engineGetCRLs(CRLSelector selector)
+ throws CertStoreException {
+ if (debug != null) {
+ debug.println("LDAPCertStore.engineGetCRLs() selector: "
+ + selector);
+ }
+ // Set up selector and collection to hold CRLs
+ if (selector == null) {
+ selector = new X509CRLSelector();
+ }
+ if (!(selector instanceof X509CRLSelector)) {
+ throw new CertStoreException("need X509CRLSelector to find CRLs");
+ }
+ X509CRLSelector xsel = (X509CRLSelector) selector;
+ HashSet<X509CRL> crls = new HashSet<>();
+
+ // Look in directory entry for issuer of cert we're checking.
+ Collection<Object> issuerNames;
+ X509Certificate certChecking = xsel.getCertificateChecking();
+ if (certChecking != null) {
+ issuerNames = new HashSet<>();
+ X500Principal issuer = certChecking.getIssuerX500Principal();
+ issuerNames.add(issuer.getName(X500Principal.RFC2253));
+ } else {
+ // But if we don't know which cert we're checking, try the directory
+ // entries of all acceptable CRL issuers
+ issuerNames = xsel.getIssuerNames();
+ if (issuerNames == null) {
+ throw new CertStoreException("need issuerNames or certChecking to "
+ + "find CRLs");
+ }
+ }
+ for (Object nameObject : issuerNames) {
+ String issuerName;
+ if (nameObject instanceof byte[]) {
+ try {
+ X500Principal issuer = new X500Principal((byte[])nameObject);
+ issuerName = issuer.getName(X500Principal.RFC2253);
+ } catch (IllegalArgumentException e) {
+ continue;
+ }
+ } else {
+ issuerName = (String)nameObject;
+ }
+ // If all we want is CA certs, try to get the (probably shorter) ARL
+ Collection<X509CRL> entryCRLs = Collections.emptySet();
+ if (certChecking == null || certChecking.getBasicConstraints() != -1) {
+ LDAPRequest request = new LDAPRequest(issuerName);
+ request.addRequestedAttribute(CROSS_CERT);
+ request.addRequestedAttribute(CA_CERT);
+ request.addRequestedAttribute(ARL);
+ if (prefetchCRLs) {
+ request.addRequestedAttribute(CRL);
+ }
+ try {
+ entryCRLs = getCRLs(request, ARL, xsel);
+ if (entryCRLs.isEmpty()) {
+ // no ARLs found. We assume that means that there are
+ // no ARLs on this server at all and prefetch the CRLs.
+ prefetchCRLs = true;
+ } else {
+ crls.addAll(entryCRLs);
+ }
+ } catch (CertStoreException e) {
+ if (debug != null) {
+ debug.println("LDAPCertStore.engineGetCRLs non-fatal error "
+ + "retrieving ARLs:" + e);
+ e.printStackTrace();
+ }
+ }
+ }
+ // Otherwise, get the CRL
+ // if certChecking is null, we don't know if we should look in ARL or CRL
+ // attribute, so check both for matching CRLs.
+ if (entryCRLs.isEmpty() || certChecking == null) {
+ LDAPRequest request = new LDAPRequest(issuerName);
+ request.addRequestedAttribute(CRL);
+ entryCRLs = getCRLs(request, CRL, xsel);
+ crls.addAll(entryCRLs);
+ }
+ }
+ return crls;
+ }
+
+ // converts an LDAP URI into LDAPCertStoreParameters
+ static LDAPCertStoreParameters getParameters(URI uri) {
+ String host = uri.getHost();
+ if (host == null) {
+ return new SunLDAPCertStoreParameters();
+ } else {
+ int port = uri.getPort();
+ return (port == -1
+ ? new SunLDAPCertStoreParameters(host)
+ : new SunLDAPCertStoreParameters(host, port));
+ }
+ }
+
+ /*
+ * Subclass of LDAPCertStoreParameters with overridden equals/hashCode
+ * methods. This is necessary because the parameters are used as
+ * keys in the LDAPCertStore cache.
+ */
+ private static class SunLDAPCertStoreParameters
+ extends LDAPCertStoreParameters {
+
+ private volatile int hashCode = 0;
+
+ SunLDAPCertStoreParameters(String serverName, int port) {
+ super(serverName, port);
+ }
+ SunLDAPCertStoreParameters(String serverName) {
+ super(serverName);
+ }
+ SunLDAPCertStoreParameters() {
+ super();
+ }
+ public boolean equals(Object obj) {
+ if (!(obj instanceof LDAPCertStoreParameters)) {
+ return false;
+ }
+ LDAPCertStoreParameters params = (LDAPCertStoreParameters) obj;
+ return (getPort() == params.getPort() &&
+ getServerName().equalsIgnoreCase(params.getServerName()));
+ }
+ public int hashCode() {
+ if (hashCode == 0) {
+ int result = 17;
+ result = 37*result + getPort();
+ result = 37*result +
+ getServerName().toLowerCase(Locale.ENGLISH).hashCode();
+ hashCode = result;
+ }
+ return hashCode;
+ }
+ }
+
+ /*
+ * This inner class wraps an existing X509CertSelector and adds
+ * additional criteria to match on when the certificate's subject is
+ * different than the LDAP Distinguished Name entry. The LDAPCertStore
+ * implementation uses the subject DN as the directory entry for
+ * looking up certificates. This can be problematic if the certificates
+ * that you want to fetch have a different subject DN than the entry
+ * where they are stored. You could set the selector's subject to the
+ * LDAP DN entry, but then the resulting match would fail to find the
+ * desired certificates because the subject DNs would not match. This
+ * class avoids that problem by introducing a certSubject which should
+ * be set to the certificate's subject DN when it is different than
+ * the LDAP DN.
+ */
+ static class LDAPCertSelector extends X509CertSelector {
+
+ private X500Principal certSubject;
+ private X509CertSelector selector;
+ private X500Principal subject;
+
+ /**
+ * Creates an LDAPCertSelector.
+ *
+ * @param selector the X509CertSelector to wrap
+ * @param certSubject the subject DN of the certificate that you want
+ * to retrieve via LDAP
+ * @param ldapDN the LDAP DN where the certificate is stored
+ */
+ LDAPCertSelector(X509CertSelector selector, X500Principal certSubject,
+ String ldapDN) throws IOException {
+ this.selector = selector == null ? new X509CertSelector() : selector;
+ this.certSubject = certSubject;
+ this.subject = new X500Name(ldapDN).asX500Principal();
+ }
+
+ // we only override the get (accessor methods) since the set methods
+ // will not be invoked by the code that uses this LDAPCertSelector.
+ public X509Certificate getCertificate() {
+ return selector.getCertificate();
+ }
+ public BigInteger getSerialNumber() {
+ return selector.getSerialNumber();
+ }
+ public X500Principal getIssuer() {
+ return selector.getIssuer();
+ }
+ public String getIssuerAsString() {
+ return selector.getIssuerAsString();
+ }
+ public byte[] getIssuerAsBytes() throws IOException {
+ return selector.getIssuerAsBytes();
+ }
+ public X500Principal getSubject() {
+ // return the ldap DN
+ return subject;
+ }
+ public String getSubjectAsString() {
+ // return the ldap DN
+ return subject.getName();
+ }
+ public byte[] getSubjectAsBytes() throws IOException {
+ // return the encoded ldap DN
+ return subject.getEncoded();
+ }
+ public byte[] getSubjectKeyIdentifier() {
+ return selector.getSubjectKeyIdentifier();
+ }
+ public byte[] getAuthorityKeyIdentifier() {
+ return selector.getAuthorityKeyIdentifier();
+ }
+ public Date getCertificateValid() {
+ return selector.getCertificateValid();
+ }
+ public Date getPrivateKeyValid() {
+ return selector.getPrivateKeyValid();
+ }
+ public String getSubjectPublicKeyAlgID() {
+ return selector.getSubjectPublicKeyAlgID();
+ }
+ public PublicKey getSubjectPublicKey() {
+ return selector.getSubjectPublicKey();
+ }
+ public boolean[] getKeyUsage() {
+ return selector.getKeyUsage();
+ }
+ public Set<String> getExtendedKeyUsage() {
+ return selector.getExtendedKeyUsage();
+ }
+ public boolean getMatchAllSubjectAltNames() {
+ return selector.getMatchAllSubjectAltNames();
+ }
+ public Collection<List<?>> getSubjectAlternativeNames() {
+ return selector.getSubjectAlternativeNames();
+ }
+ public byte[] getNameConstraints() {
+ return selector.getNameConstraints();
+ }
+ public int getBasicConstraints() {
+ return selector.getBasicConstraints();
+ }
+ public Set<String> getPolicy() {
+ return selector.getPolicy();
+ }
+ public Collection<List<?>> getPathToNames() {
+ return selector.getPathToNames();
+ }
+
+ public boolean match(Certificate cert) {
+ // temporarily set the subject criterion to the certSubject
+ // so that match will not reject the desired certificates
+ selector.setSubject(certSubject);
+ boolean match = selector.match(cert);
+ selector.setSubject(subject);
+ return match;
+ }
+ }
+
+ /**
+ * This class has the same purpose as LDAPCertSelector except it is for
+ * X.509 CRLs.
+ */
+ static class LDAPCRLSelector extends X509CRLSelector {
+
+ private X509CRLSelector selector;
+ private Collection<X500Principal> certIssuers;
+ private Collection<X500Principal> issuers;
+ private HashSet<Object> issuerNames;
+
+ /**
+ * Creates an LDAPCRLSelector.
+ *
+ * @param selector the X509CRLSelector to wrap
+ * @param certIssuers the issuer DNs of the CRLs that you want
+ * to retrieve via LDAP
+ * @param ldapDN the LDAP DN where the CRL is stored
+ */
+ LDAPCRLSelector(X509CRLSelector selector,
+ Collection<X500Principal> certIssuers, String ldapDN)
+ throws IOException {
+ this.selector = selector == null ? new X509CRLSelector() : selector;
+ this.certIssuers = certIssuers;
+ issuerNames = new HashSet<>();
+ issuerNames.add(ldapDN);
+ issuers = new HashSet<>();
+ issuers.add(new X500Name(ldapDN).asX500Principal());
+ }
+ // we only override the get (accessor methods) since the set methods
+ // will not be invoked by the code that uses this LDAPCRLSelector.
+ public Collection<X500Principal> getIssuers() {
+ // return the ldap DN
+ return Collections.unmodifiableCollection(issuers);
+ }
+ public Collection<Object> getIssuerNames() {
+ // return the ldap DN
+ return Collections.unmodifiableCollection(issuerNames);
+ }
+ public BigInteger getMinCRL() {
+ return selector.getMinCRL();
+ }
+ public BigInteger getMaxCRL() {
+ return selector.getMaxCRL();
+ }
+ public Date getDateAndTime() {
+ return selector.getDateAndTime();
+ }
+ public X509Certificate getCertificateChecking() {
+ return selector.getCertificateChecking();
+ }
+ public boolean match(CRL crl) {
+ // temporarily set the issuer criterion to the certIssuers
+ // so that match will not reject the desired CRL
+ selector.setIssuers(certIssuers);
+ boolean match = selector.match(crl);
+ selector.setIssuers(issuers);
+ return match;
+ }
+ }
+}
diff --git a/ojluni/src/main/java/sun/security/provider/certpath/ldap/LDAPCertStoreHelper.java b/ojluni/src/main/java/sun/security/provider/certpath/ldap/LDAPCertStoreHelper.java
new file mode 100644
index 0000000..8e6899b
--- /dev/null
+++ b/ojluni/src/main/java/sun/security/provider/certpath/ldap/LDAPCertStoreHelper.java
@@ -0,0 +1,81 @@
+/*
+ * Copyright (c) 2009, 2012, 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.ldap;
+
+import java.io.IOException;
+import java.net.URI;
+import java.util.Collection;
+import java.security.NoSuchAlgorithmException;
+import java.security.InvalidAlgorithmParameterException;
+import java.security.cert.CertStore;
+import java.security.cert.CertStoreException;
+import java.security.cert.X509CertSelector;
+import java.security.cert.X509CRLSelector;
+import javax.naming.CommunicationException;
+import javax.naming.ServiceUnavailableException;
+import javax.security.auth.x500.X500Principal;
+
+import sun.security.provider.certpath.CertStoreHelper;
+
+/**
+ * LDAP implementation of CertStoreHelper.
+ */
+
+public final class LDAPCertStoreHelper
+ extends CertStoreHelper
+{
+ @Override
+ public CertStore getCertStore(URI uri)
+ throws NoSuchAlgorithmException, InvalidAlgorithmParameterException
+ {
+ return LDAPCertStore.getInstance(LDAPCertStore.getParameters(uri));
+ }
+
+ @Override
+ public X509CertSelector wrap(X509CertSelector selector,
+ X500Principal certSubject,
+ String ldapDN)
+ throws IOException
+ {
+ return new LDAPCertStore.LDAPCertSelector(selector, certSubject, ldapDN);
+ }
+
+ @Override
+ public X509CRLSelector wrap(X509CRLSelector selector,
+ Collection<X500Principal> certIssuers,
+ String ldapDN)
+ throws IOException
+ {
+ return new LDAPCertStore.LDAPCRLSelector(selector, certIssuers, ldapDN);
+ }
+
+ @Override
+ public boolean isCausedByNetworkIssue(CertStoreException e) {
+ Throwable t = e.getCause();
+ return (t != null && (t instanceof ServiceUnavailableException ||
+ t instanceof CommunicationException));
+ }
+}
diff --git a/ojluni/src/main/java/sun/security/ssl/SSLSessionContextImpl.java b/ojluni/src/main/java/sun/security/ssl/SSLSessionContextImpl.java
index 15ac884..51fac9b 100755
--- a/ojluni/src/main/java/sun/security/ssl/SSLSessionContextImpl.java
+++ b/ojluni/src/main/java/sun/security/ssl/SSLSessionContextImpl.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1999, 2009, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1999, 2012, 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,32 +26,24 @@
package sun.security.ssl;
-import java.io.*;
-import java.net.*;
-import java.util.Date;
import java.util.Enumeration;
-import java.util.Hashtable;
-import java.util.NoSuchElementException;
import java.util.Vector;
+import java.util.Locale;
import javax.net.ssl.SSLSession;
import javax.net.ssl.SSLSessionContext;
-import javax.net.ssl.SSLSessionBindingListener;
-import javax.net.ssl.SSLSessionBindingEvent;
-import javax.net.ssl.SSLPeerUnverifiedException;
-import javax.net.ssl.SSLSession;
import sun.security.util.Cache;
final class SSLSessionContextImpl implements SSLSessionContext {
- private Cache sessionCache; // session cache, session id as key
- private Cache sessionHostPortCache; // session cache, "host:port" as key
+ private Cache<SessionId, SSLSessionImpl> sessionCache;
+ // session cache, session id as key
+ private Cache<String, SSLSessionImpl> sessionHostPortCache;
+ // session cache, "host:port" as key
private int cacheLimit; // the max cache size
private int timeout; // timeout in seconds
- private static final Debug debug = Debug.getInstance("ssl");
-
// package private
SSLSessionContextImpl() {
cacheLimit = getDefaultCacheLimit(); // default cache size
@@ -65,13 +57,13 @@
/**
* Returns the <code>SSLSession</code> bound to the specified session id.
*/
+ @Override
public SSLSession getSession(byte[] sessionId) {
if (sessionId == null) {
throw new NullPointerException("session id cannot be null");
}
- SSLSessionImpl sess =
- (SSLSessionImpl)sessionCache.get(new SessionId(sessionId));
+ SSLSessionImpl sess = sessionCache.get(new SessionId(sessionId));
if (!isTimedout(sess)) {
return sess;
}
@@ -82,6 +74,7 @@
/**
* Returns an enumeration of the active SSL sessions.
*/
+ @Override
public Enumeration<byte[]> getIds() {
SessionCacheVisitor scVisitor = new SessionCacheVisitor();
sessionCache.accept(scVisitor);
@@ -96,6 +89,7 @@
* should be timed within the shorter one of the old timeout and the
* new timeout.
*/
+ @Override
public void setSessionTimeout(int seconds)
throws IllegalArgumentException {
if (seconds < 0) {
@@ -112,6 +106,7 @@
/**
* Gets the timeout limit for cached <code>SSLSession</code> objects
*/
+ @Override
public int getSessionTimeout() {
return timeout;
}
@@ -120,6 +115,7 @@
* Sets the size of the cache used for storing
* <code>SSLSession</code> objects.
*/
+ @Override
public void setSessionCacheSize(int size)
throws IllegalArgumentException {
if (size < 0)
@@ -136,6 +132,7 @@
* Gets the size of the cache used for storing
* <code>SSLSession</code> objects.
*/
+ @Override
public int getSessionCacheSize() {
return cacheLimit;
}
@@ -156,8 +153,7 @@
return null;
}
- SSLSessionImpl sess =
- (SSLSessionImpl)sessionHostPortCache.get(getKey(hostname, port));
+ SSLSessionImpl sess = sessionHostPortCache.get(getKey(hostname, port));
if (!isTimedout(sess)) {
return sess;
}
@@ -166,7 +162,8 @@
}
private String getKey(String hostname, int port) {
- return (hostname + ":" + String.valueOf(port)).toLowerCase();
+ return (hostname + ":" +
+ String.valueOf(port)).toLowerCase(Locale.ENGLISH);
}
// cache a SSLSession
@@ -191,7 +188,7 @@
// package-private method, remove a cached SSLSession
void remove(SessionId key) {
- SSLSessionImpl s = (SSLSessionImpl)sessionCache.get(key);
+ SSLSessionImpl s = sessionCache.get(key);
if (s != null) {
sessionCache.remove(key);
sessionHostPortCache.remove(
@@ -204,6 +201,7 @@
try {
String s = java.security.AccessController.doPrivileged(
new java.security.PrivilegedAction<String>() {
+ @Override
public String run() {
return System.getProperty(
"javax.net.ssl.sessionCacheSize");
@@ -231,17 +229,18 @@
}
final class SessionCacheVisitor
- implements sun.security.util.Cache.CacheVisitor {
+ implements Cache.CacheVisitor<SessionId, SSLSessionImpl> {
Vector<byte[]> ids = null;
- // public void visit(java.util.Map<Object, Object> map) {}
- public void visit(java.util.Map<Object, Object> map) {
- ids = new Vector<byte[]>(map.size());
+ // public void visit(java.util.Map<K,V> map) {}
+ @Override
+ public void visit(java.util.Map<SessionId, SSLSessionImpl> map) {
+ ids = new Vector<>(map.size());
- for (Object key : map.keySet()) {
- SSLSessionImpl value = (SSLSessionImpl)map.get(key);
+ for (SessionId key : map.keySet()) {
+ SSLSessionImpl value = map.get(key);
if (!isTimedout(value)) {
- ids.addElement(((SessionId)key).getId());
+ ids.addElement(key.getId());
}
}
}
diff --git a/ojluni/src/main/java/sun/security/util/Cache.java b/ojluni/src/main/java/sun/security/util/Cache.java
index 031b56c..8037324 100755
--- a/ojluni/src/main/java/sun/security/util/Cache.java
+++ b/ojluni/src/main/java/sun/security/util/Cache.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2002, 2009, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2002, 2011, 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,7 @@
*
* . optional lifetime, specified in seconds.
*
- * . save for concurrent use by multiple threads
+ * . safe for concurrent use by multiple threads
*
* . values are held by either standard references or via SoftReferences.
* SoftReferences have the advantage that they are automatically cleared
@@ -69,7 +69,7 @@
*
* @author Andreas Sterbenz
*/
-public abstract class Cache {
+public abstract class Cache<K,V> {
protected Cache() {
// empty
@@ -88,12 +88,12 @@
/**
* Add an entry to the cache.
*/
- public abstract void put(Object key, Object value);
+ public abstract void put(K key, V value);
/**
* Get a value from the cache.
*/
- public abstract Object get(Object key);
+ public abstract V get(Object key);
/**
* Remove an entry from the cache.
@@ -113,14 +113,14 @@
/**
* accept a visitor
*/
- public abstract void accept(CacheVisitor visitor);
+ public abstract void accept(CacheVisitor<K,V> visitor);
/**
* Return a new memory cache with the specified maximum size, unlimited
* lifetime for entries, with the values held by SoftReferences.
*/
- public static Cache newSoftMemoryCache(int size) {
- return new MemoryCache(true, size);
+ public static <K,V> Cache<K,V> newSoftMemoryCache(int size) {
+ return new MemoryCache<>(true, size);
}
/**
@@ -128,23 +128,24 @@
* specified maximum lifetime (in seconds), with the values held
* by SoftReferences.
*/
- public static Cache newSoftMemoryCache(int size, int timeout) {
- return new MemoryCache(true, size, timeout);
+ public static <K,V> Cache<K,V> newSoftMemoryCache(int size, int timeout) {
+ return new MemoryCache<>(true, size, timeout);
}
/**
* Return a new memory cache with the specified maximum size, unlimited
* lifetime for entries, with the values held by standard references.
*/
- public static Cache newHardMemoryCache(int size) {
- return new MemoryCache(false, size);
+ public static <K,V> Cache<K,V> newHardMemoryCache(int size) {
+ return new MemoryCache<>(false, size);
}
/**
* Return a dummy cache that does nothing.
*/
- public static Cache newNullCache() {
- return NullCache.INSTANCE;
+ @SuppressWarnings("unchecked")
+ public static <K,V> Cache<K,V> newNullCache() {
+ return (Cache<K,V>) NullCache.INSTANCE;
}
/**
@@ -152,8 +153,8 @@
* specified maximum lifetime (in seconds), with the values held
* by standard references.
*/
- public static Cache newHardMemoryCache(int size, int timeout) {
- return new MemoryCache(false, size, timeout);
+ public static <K,V> Cache<K,V> newHardMemoryCache(int size, int timeout) {
+ return new MemoryCache<>(false, size, timeout);
}
/**
@@ -193,15 +194,15 @@
}
}
- public interface CacheVisitor {
- public void visit(Map<Object, Object> map);
+ public interface CacheVisitor<K,V> {
+ public void visit(Map<K,V> map);
}
}
-class NullCache extends Cache {
+class NullCache<K,V> extends Cache<K,V> {
- final static Cache INSTANCE = new NullCache();
+ final static Cache<Object,Object> INSTANCE = new NullCache<>();
private NullCache() {
// empty
@@ -215,11 +216,11 @@
// empty
}
- public void put(Object key, Object value) {
+ public void put(K key, V value) {
// empty
}
- public Object get(Object key) {
+ public V get(Object key) {
return null;
}
@@ -235,23 +236,26 @@
// empty
}
- public void accept(CacheVisitor visitor) {
+ public void accept(CacheVisitor<K,V> visitor) {
// empty
}
}
-class MemoryCache extends Cache {
+class MemoryCache<K,V> extends Cache<K,V> {
private final static float LOAD_FACTOR = 0.75f;
// XXXX
private final static boolean DEBUG = false;
- private final Map<Object, CacheEntry> cacheMap;
+ private final Map<K, CacheEntry<K,V>> cacheMap;
private int maxSize;
private long lifetime;
- private final ReferenceQueue queue;
+
+ // ReferenceQueue is of type V instead of Cache<K,V>
+ // to allow SoftCacheEntry to extend SoftReference<V>
+ private final ReferenceQueue<V> queue;
public MemoryCache(boolean soft, int maxSize) {
this(soft, maxSize, 0);
@@ -260,10 +264,13 @@
public MemoryCache(boolean soft, int maxSize, int lifetime) {
this.maxSize = maxSize;
this.lifetime = lifetime * 1000;
- this.queue = soft ? new ReferenceQueue() : null;
+ if (soft)
+ this.queue = new ReferenceQueue<>();
+ else
+ this.queue = null;
+
int buckets = (int)(maxSize / LOAD_FACTOR) + 1;
- cacheMap = new LinkedHashMap<Object, CacheEntry>(buckets,
- LOAD_FACTOR, true);
+ cacheMap = new LinkedHashMap<>(buckets, LOAD_FACTOR, true);
}
/**
@@ -279,16 +286,17 @@
}
int startSize = cacheMap.size();
while (true) {
- CacheEntry entry = (CacheEntry)queue.poll();
+ @SuppressWarnings("unchecked")
+ CacheEntry<K,V> entry = (CacheEntry<K,V>)queue.poll();
if (entry == null) {
break;
}
- Object key = entry.getKey();
+ K key = entry.getKey();
if (key == null) {
// key is null, entry has already been removed
continue;
}
- CacheEntry currentEntry = cacheMap.remove(key);
+ CacheEntry<K,V> currentEntry = cacheMap.remove(key);
// check if the entry in the map corresponds to the expired
// entry. If not, readd the entry
if ((currentEntry != null) && (entry != currentEntry)) {
@@ -314,9 +322,9 @@
}
int cnt = 0;
long time = System.currentTimeMillis();
- for (Iterator<CacheEntry> t = cacheMap.values().iterator();
+ for (Iterator<CacheEntry<K,V>> t = cacheMap.values().iterator();
t.hasNext(); ) {
- CacheEntry entry = t.next();
+ CacheEntry<K,V> entry = t.next();
if (entry.isValid(time) == false) {
t.remove();
cnt++;
@@ -339,7 +347,7 @@
if (queue != null) {
// if this is a SoftReference cache, first invalidate() all
// entries so that GC does not have to enqueue them
- for (CacheEntry entry : cacheMap.values()) {
+ for (CacheEntry<K,V> entry : cacheMap.values()) {
entry.invalidate();
}
while (queue.poll() != null) {
@@ -349,12 +357,12 @@
cacheMap.clear();
}
- public synchronized void put(Object key, Object value) {
+ public synchronized void put(K key, V value) {
emptyQueue();
long expirationTime = (lifetime == 0) ? 0 :
System.currentTimeMillis() + lifetime;
- CacheEntry newEntry = newEntry(key, value, expirationTime, queue);
- CacheEntry oldEntry = cacheMap.put(key, newEntry);
+ CacheEntry<K,V> newEntry = newEntry(key, value, expirationTime, queue);
+ CacheEntry<K,V> oldEntry = cacheMap.put(key, newEntry);
if (oldEntry != null) {
oldEntry.invalidate();
return;
@@ -362,8 +370,8 @@
if (maxSize > 0 && cacheMap.size() > maxSize) {
expungeExpiredEntries();
if (cacheMap.size() > maxSize) { // still too large?
- Iterator<CacheEntry> t = cacheMap.values().iterator();
- CacheEntry lruEntry = t.next();
+ Iterator<CacheEntry<K,V>> t = cacheMap.values().iterator();
+ CacheEntry<K,V> lruEntry = t.next();
if (DEBUG) {
System.out.println("** Overflow removal "
+ lruEntry.getKey() + " | " + lruEntry.getValue());
@@ -374,9 +382,9 @@
}
}
- public synchronized Object get(Object key) {
+ public synchronized V get(Object key) {
emptyQueue();
- CacheEntry entry = cacheMap.get(key);
+ CacheEntry<K,V> entry = cacheMap.get(key);
if (entry == null) {
return null;
}
@@ -393,7 +401,7 @@
public synchronized void remove(Object key) {
emptyQueue();
- CacheEntry entry = cacheMap.remove(key);
+ CacheEntry<K,V> entry = cacheMap.remove(key);
if (entry != null) {
entry.invalidate();
}
@@ -402,9 +410,9 @@
public synchronized void setCapacity(int size) {
expungeExpiredEntries();
if (size > 0 && cacheMap.size() > size) {
- Iterator<CacheEntry> t = cacheMap.values().iterator();
+ Iterator<CacheEntry<K,V>> t = cacheMap.values().iterator();
for (int i = cacheMap.size() - size; i > 0; i--) {
- CacheEntry lruEntry = t.next();
+ CacheEntry<K,V> lruEntry = t.next();
if (DEBUG) {
System.out.println("** capacity reset removal "
+ lruEntry.getKey() + " | " + lruEntry.getValue());
@@ -431,60 +439,61 @@
}
// it is a heavyweight method.
- public synchronized void accept(CacheVisitor visitor) {
+ public synchronized void accept(CacheVisitor<K,V> visitor) {
expungeExpiredEntries();
- Map<Object, Object> cached = getCachedEntries();
+ Map<K,V> cached = getCachedEntries();
visitor.visit(cached);
}
- private Map<Object, Object> getCachedEntries() {
- Map<Object,Object> kvmap = new HashMap<Object,Object>(cacheMap.size());
+ private Map<K,V> getCachedEntries() {
+ Map<K,V> kvmap = new HashMap<>(cacheMap.size());
- for (CacheEntry entry : cacheMap.values()) {
+ for (CacheEntry<K,V> entry : cacheMap.values()) {
kvmap.put(entry.getKey(), entry.getValue());
}
return kvmap;
}
- protected CacheEntry newEntry(Object key, Object value,
- long expirationTime, ReferenceQueue queue) {
+ protected CacheEntry<K,V> newEntry(K key, V value,
+ long expirationTime, ReferenceQueue<V> queue) {
if (queue != null) {
- return new SoftCacheEntry(key, value, expirationTime, queue);
+ return new SoftCacheEntry<>(key, value, expirationTime, queue);
} else {
- return new HardCacheEntry(key, value, expirationTime);
+ return new HardCacheEntry<>(key, value, expirationTime);
}
}
- private static interface CacheEntry {
+ private static interface CacheEntry<K,V> {
boolean isValid(long currentTime);
void invalidate();
- Object getKey();
+ K getKey();
- Object getValue();
+ V getValue();
}
- private static class HardCacheEntry implements CacheEntry {
+ private static class HardCacheEntry<K,V> implements CacheEntry<K,V> {
- private Object key, value;
+ private K key;
+ private V value;
private long expirationTime;
- HardCacheEntry(Object key, Object value, long expirationTime) {
+ HardCacheEntry(K key, V value, long expirationTime) {
this.key = key;
this.value = value;
this.expirationTime = expirationTime;
}
- public Object getKey() {
+ public K getKey() {
return key;
}
- public Object getValue() {
+ public V getValue() {
return value;
}
@@ -503,24 +512,25 @@
}
}
- private static class SoftCacheEntry
- extends SoftReference implements CacheEntry {
+ private static class SoftCacheEntry<K,V>
+ extends SoftReference<V>
+ implements CacheEntry<K,V> {
- private Object key;
+ private K key;
private long expirationTime;
- SoftCacheEntry(Object key, Object value, long expirationTime,
- ReferenceQueue queue) {
+ SoftCacheEntry(K key, V value, long expirationTime,
+ ReferenceQueue<V> queue) {
super(value, queue);
this.key = key;
this.expirationTime = expirationTime;
}
- public Object getKey() {
+ public K getKey() {
return key;
}
- public Object getValue() {
+ public V getValue() {
return get();
}
diff --git a/ojluni/src/main/java/sun/security/x509/CRLDistributionPointsExtension.java b/ojluni/src/main/java/sun/security/x509/CRLDistributionPointsExtension.java
index e2df22d..c381430 100755
--- a/ojluni/src/main/java/sun/security/x509/CRLDistributionPointsExtension.java
+++ b/ojluni/src/main/java/sun/security/x509/CRLDistributionPointsExtension.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2002, 2006, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2002, 2011, 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
@@ -222,6 +222,7 @@
/**
* Set the attribute value.
*/
+ @SuppressWarnings("unchecked") // Checked with instanceof
public void set(String name, Object obj) throws IOException {
if (name.equalsIgnoreCase(POINTS)) {
if (!(obj instanceof List)) {
@@ -239,7 +240,7 @@
/**
* Get the attribute value.
*/
- public Object get(String name) throws IOException {
+ public List<DistributionPoint> get(String name) throws IOException {
if (name.equalsIgnoreCase(POINTS)) {
return distributionPoints;
} else {
diff --git a/ojluni/src/main/java/sun/security/x509/CertificatePoliciesExtension.java b/ojluni/src/main/java/sun/security/x509/CertificatePoliciesExtension.java
index 2d53b42..4f04bed 100755
--- a/ojluni/src/main/java/sun/security/x509/CertificatePoliciesExtension.java
+++ b/ojluni/src/main/java/sun/security/x509/CertificatePoliciesExtension.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2000, 2006, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2000, 2011, 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
@@ -189,6 +189,7 @@
/**
* Set the attribute value.
*/
+ @SuppressWarnings("unchecked") // Checked with an instanceof check
public void set(String name, Object obj) throws IOException {
if (name.equalsIgnoreCase(POLICIES)) {
if (!(obj instanceof List)) {
@@ -206,7 +207,7 @@
/**
* Get the attribute value.
*/
- public Object get(String name) throws IOException {
+ public List<PolicyInformation> get(String name) throws IOException {
if (name.equalsIgnoreCase(POLICIES)) {
//XXXX May want to consider cloning this
return certPolicies;
diff --git a/ojluni/src/main/java/sun/security/x509/Extension.java b/ojluni/src/main/java/sun/security/x509/Extension.java
index 77a2da2..a5bcc86 100755
--- a/ojluni/src/main/java/sun/security/x509/Extension.java
+++ b/ojluni/src/main/java/sun/security/x509/Extension.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1997, 2006, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1997, 2011, 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
@@ -269,7 +269,7 @@
Extension otherExt = (Extension) other;
if (critical != otherExt.critical)
return false;
- if (!extensionId.equals(otherExt.extensionId))
+ if (!extensionId.equals((Object)otherExt.extensionId))
return false;
return Arrays.equals(extensionValue, otherExt.extensionValue);
}
diff --git a/ojluni/src/main/java/sun/security/x509/InhibitAnyPolicyExtension.java b/ojluni/src/main/java/sun/security/x509/InhibitAnyPolicyExtension.java
index ffc7572..26de497 100755
--- a/ojluni/src/main/java/sun/security/x509/InhibitAnyPolicyExtension.java
+++ b/ojluni/src/main/java/sun/security/x509/InhibitAnyPolicyExtension.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2000, 2006, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2000, 2011, 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
@@ -215,7 +215,7 @@
* Integer.
* @throws IOException on error
*/
- public Object get(String name) throws IOException {
+ public Integer get(String name) throws IOException {
if (name.equalsIgnoreCase(SKIP_CERTS))
return (new Integer(skipCerts));
else
diff --git a/ojluni/src/main/java/sun/security/x509/IssuerAlternativeNameExtension.java b/ojluni/src/main/java/sun/security/x509/IssuerAlternativeNameExtension.java
index 654932c..ba1f584 100755
--- a/ojluni/src/main/java/sun/security/x509/IssuerAlternativeNameExtension.java
+++ b/ojluni/src/main/java/sun/security/x509/IssuerAlternativeNameExtension.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1997, 2009, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1997, 2011, 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
@@ -190,7 +190,7 @@
/**
* Get the attribute value.
*/
- public Object get(String name) throws IOException {
+ public GeneralNames get(String name) throws IOException {
if (name.equalsIgnoreCase(ISSUER_NAME)) {
return (names);
} else {
diff --git a/ojluni/src/main/java/sun/security/x509/NameConstraintsExtension.java b/ojluni/src/main/java/sun/security/x509/NameConstraintsExtension.java
index 3ca995e..f043183 100755
--- a/ojluni/src/main/java/sun/security/x509/NameConstraintsExtension.java
+++ b/ojluni/src/main/java/sun/security/x509/NameConstraintsExtension.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1997, 2006, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1997, 2011, 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,10 +27,7 @@
import java.io.IOException;
import java.io.OutputStream;
-import java.security.Principal;
-import java.security.cert.CertificateEncodingException;
import java.security.cert.CertificateException;
-import java.security.cert.CertificateParsingException;
import java.security.cert.X509Certificate;
import java.util.*;
@@ -268,7 +265,7 @@
/**
* Get the attribute value.
*/
- public Object get(String name) throws IOException {
+ public GeneralSubtrees get(String name) throws IOException {
if (name.equalsIgnoreCase(PERMITTED_SUBTREES)) {
return (permitted);
} else if (name.equalsIgnoreCase(EXCLUDED_SUBTREES)) {
@@ -349,8 +346,7 @@
* value and the value indicated in the extension field.
*/
- GeneralSubtrees newExcluded =
- (GeneralSubtrees)newConstraints.get(EXCLUDED_SUBTREES);
+ GeneralSubtrees newExcluded = newConstraints.get(EXCLUDED_SUBTREES);
if (excluded == null) {
excluded = (newExcluded != null) ?
(GeneralSubtrees)newExcluded.clone() : null;
@@ -367,8 +363,7 @@
* previous value and the value indicated in the extension field.
*/
- GeneralSubtrees newPermitted =
- (GeneralSubtrees)newConstraints.get(PERMITTED_SUBTREES);
+ GeneralSubtrees newPermitted = newConstraints.get(PERMITTED_SUBTREES);
if (permitted == null) {
permitted = (newPermitted != null) ?
(GeneralSubtrees)newPermitted.clone() : null;
@@ -455,8 +450,8 @@
if (altNameExt != null) {
// extract altNames from extension; this call does not
// return an IOException on null altnames
- altNames = (GeneralNames)
- (altNameExt.get(altNameExt.SUBJECT_NAME));
+ altNames = altNameExt.get(
+ SubjectAlternativeNameExtension.SUBJECT_NAME);
}
} catch (CertificateException ce) {
throw new IOException("Unable to extract extensions from " +
@@ -575,10 +570,9 @@
* @throws IOException on error
*/
public boolean verifyRFC822SpecialCase(X500Name subject) throws IOException {
- for (Iterator t = subject.allAvas().iterator(); t.hasNext(); ) {
- AVA ava = (AVA)t.next();
+ for (AVA ava : subject.allAvas()) {
ObjectIdentifier attrOID = ava.getObjectIdentifier();
- if (attrOID.equals(PKCS9Attribute.EMAIL_ADDRESS_OID)) {
+ if (attrOID.equals((Object)PKCS9Attribute.EMAIL_ADDRESS_OID)) {
String attrValue = ava.getValueString();
if (attrValue != null) {
RFC822Name emailName;
diff --git a/ojluni/src/main/java/sun/security/x509/PolicyConstraintsExtension.java b/ojluni/src/main/java/sun/security/x509/PolicyConstraintsExtension.java
index c9b1ea7..fe7ede3 100755
--- a/ojluni/src/main/java/sun/security/x509/PolicyConstraintsExtension.java
+++ b/ojluni/src/main/java/sun/security/x509/PolicyConstraintsExtension.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1997, 2006, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1997, 2011, 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
@@ -231,7 +231,7 @@
/**
* Get the attribute value.
*/
- public Object get(String name) throws IOException {
+ public Integer get(String name) throws IOException {
if (name.equalsIgnoreCase(REQUIRE)) {
return new Integer(require);
} else if (name.equalsIgnoreCase(INHIBIT)) {
diff --git a/ojluni/src/main/java/sun/security/x509/PolicyMappingsExtension.java b/ojluni/src/main/java/sun/security/x509/PolicyMappingsExtension.java
index acdbdb9..fba5104 100755
--- a/ojluni/src/main/java/sun/security/x509/PolicyMappingsExtension.java
+++ b/ojluni/src/main/java/sun/security/x509/PolicyMappingsExtension.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1997, 2006, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1997, 2011, 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
@@ -29,8 +29,6 @@
import java.io.OutputStream;
import java.util.*;
-import java.security.cert.CertificateException;
-
import sun.security.util.*;
/**
@@ -165,6 +163,7 @@
/**
* Set the attribute value.
*/
+ @SuppressWarnings("unchecked") // Checked with instanceof
public void set(String name, Object obj) throws IOException {
if (name.equalsIgnoreCase(MAP)) {
if (!(obj instanceof List)) {
@@ -182,7 +181,7 @@
/**
* Get the attribute value.
*/
- public Object get(String name) throws IOException {
+ public List<CertificatePolicyMap> get(String name) throws IOException {
if (name.equalsIgnoreCase(MAP)) {
return (maps);
} else {
diff --git a/ojluni/src/main/java/sun/security/x509/SubjectAlternativeNameExtension.java b/ojluni/src/main/java/sun/security/x509/SubjectAlternativeNameExtension.java
index 5d74cc4..95eb67e 100755
--- a/ojluni/src/main/java/sun/security/x509/SubjectAlternativeNameExtension.java
+++ b/ojluni/src/main/java/sun/security/x509/SubjectAlternativeNameExtension.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1997, 2006, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1997, 2011, 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
@@ -195,7 +195,7 @@
/**
* Get the attribute value.
*/
- public Object get(String name) throws IOException {
+ public GeneralNames get(String name) throws IOException {
if (name.equalsIgnoreCase(SUBJECT_NAME)) {
return (names);
} else {
diff --git a/ojluni/src/main/java/sun/security/x509/SubjectKeyIdentifierExtension.java b/ojluni/src/main/java/sun/security/x509/SubjectKeyIdentifierExtension.java
index a22129f..79482c9 100755
--- a/ojluni/src/main/java/sun/security/x509/SubjectKeyIdentifierExtension.java
+++ b/ojluni/src/main/java/sun/security/x509/SubjectKeyIdentifierExtension.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1997, 2006, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1997, 2011, 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
@@ -156,7 +156,7 @@
/**
* Get the attribute value.
*/
- public Object get(String name) throws IOException {
+ public KeyIdentifier get(String name) throws IOException {
if (name.equalsIgnoreCase(KEY_ID)) {
return (id);
} else {
diff --git a/ojluni/src/main/java/sun/security/x509/X509CertImpl.java b/ojluni/src/main/java/sun/security/x509/X509CertImpl.java
index 92ee71a..5ff1c9b 100755
--- a/ojluni/src/main/java/sun/security/x509/X509CertImpl.java
+++ b/ojluni/src/main/java/sun/security/x509/X509CertImpl.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1996, 2012, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1996, 2013, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -37,6 +37,7 @@
import java.security.cert.*;
import java.security.cert.Certificate;
import java.util.*;
+import java.util.concurrent.ConcurrentHashMap;
import javax.security.auth.x500.X500Principal;
@@ -96,12 +97,10 @@
*/
// x509.info.subject.dname
public static final String SUBJECT_DN = NAME + DOT + INFO + DOT +
- X509CertInfo.SUBJECT + DOT +
- CertificateSubjectName.DN_NAME;
+ X509CertInfo.SUBJECT + DOT + X509CertInfo.DN_NAME;
// x509.info.issuer.dname
public static final String ISSUER_DN = NAME + DOT + INFO + DOT +
- X509CertInfo.ISSUER + DOT +
- CertificateIssuerName.DN_NAME;
+ X509CertInfo.ISSUER + DOT + X509CertInfo.DN_NAME;
// x509.info.serialNumber.number
public static final String SERIAL_ID = NAME + DOT + INFO + DOT +
X509CertInfo.SERIAL_NUMBER + DOT +
@@ -453,6 +452,62 @@
}
/**
+ * Throws an exception if the certificate was not signed using the
+ * verification key provided. This method uses the signature verification
+ * engine supplied by the specified provider. Note that the specified
+ * Provider object does not have to be registered in the provider list.
+ * Successfully verifying a certificate does <em>not</em> indicate that one
+ * should trust the entity which it represents.
+ *
+ * @param key the public key used for verification.
+ * @param sigProvider the provider.
+ *
+ * @exception NoSuchAlgorithmException on unsupported signature
+ * algorithms.
+ * @exception InvalidKeyException on incorrect key.
+ * @exception SignatureException on signature errors.
+ * @exception CertificateException on encoding errors.
+ */
+ public synchronized void verify(PublicKey key, Provider sigProvider)
+ throws CertificateException, NoSuchAlgorithmException,
+ InvalidKeyException, SignatureException {
+ if (signedCert == null) {
+ throw new CertificateEncodingException("Uninitialized certificate");
+ }
+ // Verify the signature ...
+ Signature sigVerf = null;
+ if (sigProvider == null) {
+ sigVerf = Signature.getInstance(algId.getName());
+ } else {
+ sigVerf = Signature.getInstance(algId.getName(), sigProvider);
+ }
+ sigVerf.initVerify(key);
+
+ byte[] rawCert = info.getEncodedInfo();
+ sigVerf.update(rawCert, 0, rawCert.length);
+
+ // verify may throw SignatureException for invalid encodings, etc.
+ verificationResult = sigVerf.verify(signature);
+ verifiedPublicKey = key;
+
+ if (verificationResult == false) {
+ throw new SignatureException("Signature does not match.");
+ }
+ }
+
+ /**
+ * This static method is the default implementation of the
+ * verify(PublicKey key, Provider sigProvider) method in X509Certificate.
+ * Called from java.security.cert.X509Certificate.verify(PublicKey key,
+ * Provider sigProvider)
+ */
+ public static void verify(X509Certificate cert, PublicKey key,
+ Provider sigProvider) throws CertificateException,
+ NoSuchAlgorithmException, InvalidKeyException, SignatureException {
+ cert.verify(key, sigProvider);
+ }
+
+ /**
* Creates an X.509 certificate, and signs it using the given key
* (associating a signature algorithm and an X.500 name).
* This operation is used to implement the certificate generation
@@ -834,9 +889,8 @@
if (info == null)
return null;
try {
- Principal subject = (Principal)info.get(
- CertificateSubjectName.NAME + DOT +
- CertificateSubjectName.DN_NAME);
+ Principal subject = (Principal)info.get(X509CertInfo.SUBJECT + DOT +
+ X509CertInfo.DN_NAME);
return subject;
} catch (Exception e) {
return null;
@@ -854,8 +908,8 @@
}
try {
X500Principal subject = (X500Principal)info.get(
- CertificateSubjectName.NAME + DOT +
- CertificateSubjectName.DN_PRINCIPAL);
+ X509CertInfo.SUBJECT + DOT +
+ "x500principal");
return subject;
} catch (Exception e) {
return null;
@@ -871,9 +925,8 @@
if (info == null)
return null;
try {
- Principal issuer = (Principal)info.get(
- CertificateIssuerName.NAME + DOT +
- CertificateIssuerName.DN_NAME);
+ Principal issuer = (Principal)info.get(X509CertInfo.ISSUER + DOT +
+ X509CertInfo.DN_NAME);
return issuer;
} catch (Exception e) {
return null;
@@ -891,8 +944,8 @@
}
try {
X500Principal issuer = (X500Principal)info.get(
- CertificateIssuerName.NAME + DOT +
- CertificateIssuerName.DN_PRINCIPAL);
+ X509CertInfo.ISSUER + DOT +
+ "x500principal");
return issuer;
} catch (Exception e) {
return null;
@@ -1014,8 +1067,7 @@
return null;
try {
UniqueIdentity id = (UniqueIdentity)info.get(
- CertificateIssuerUniqueIdentity.NAME
- + DOT + CertificateIssuerUniqueIdentity.ID);
+ X509CertInfo.ISSUER_ID);
if (id == null)
return null;
else
@@ -1035,8 +1087,7 @@
return null;
try {
UniqueIdentity id = (UniqueIdentity)info.get(
- CertificateSubjectUniqueIdentity.NAME
- + DOT + CertificateSubjectUniqueIdentity.ID);
+ X509CertInfo.SUBJECT_ID);
if (id == null)
return null;
else
@@ -1046,6 +1097,32 @@
}
}
+ public KeyIdentifier getAuthKeyId() {
+ AuthorityKeyIdentifierExtension aki
+ = getAuthorityKeyIdentifierExtension();
+ if (aki != null) {
+ try {
+ return (KeyIdentifier)aki.get(
+ AuthorityKeyIdentifierExtension.KEY_ID);
+ } catch (IOException ioe) {} // not possible
+ }
+ return null;
+ }
+
+ /**
+ * Returns the subject's key identifier, or null
+ */
+ public KeyIdentifier getSubjectKeyId() {
+ SubjectKeyIdentifierExtension ski = getSubjectKeyIdentifierExtension();
+ if (ski != null) {
+ try {
+ return (KeyIdentifier)ski.get(
+ SubjectKeyIdentifierExtension.KEY_ID);
+ } catch (IOException ioe) {} // not possible
+ }
+ return null;
+ }
+
/**
* Get AuthorityKeyIdentifier extension
* @return AuthorityKeyIdentifier object or null (if no such object
@@ -1058,32 +1135,6 @@
}
/**
- * Return the issuing authority's key identifier bytes, or null
- */
- public byte[] getIssuerKeyIdentifier()
- {
- byte[] issuerKeyId = null;
- AuthorityKeyIdentifierExtension aki =
- getAuthorityKeyIdentifierExtension();
-
- if (aki != null) {
-
- try {
- KeyIdentifier ki =
- ((KeyIdentifier) aki.get(
- AuthorityKeyIdentifierExtension.KEY_ID));
- if (ki != null) {
- issuerKeyId = ki.getIdentifier();
- }
- } catch (IOException e) {
- // should never happen (because KEY_ID attr is supported)
- }
- }
-
- return issuerKeyId;
- }
-
- /**
* Get BasicConstraints extension
* @return BasicConstraints object or null (if no such object in
* certificate)
@@ -1183,31 +1234,6 @@
}
/**
- * Returns the subject's key identifier bytes, or null
- */
- public byte[] getSubjectKeyIdentifier()
- {
- byte[] subjectKeyId = null;
- SubjectKeyIdentifierExtension ski = getSubjectKeyIdentifierExtension();
-
- if (ski != null) {
-
- try {
- KeyIdentifier ki =
- ((KeyIdentifier) ski.get(
- SubjectKeyIdentifierExtension.KEY_ID));
- if (ki != null) {
- subjectKeyId = ki.getIdentifier();
- }
- } catch (IOException e) {
- // should never happen (because KEY_ID attr is supported)
- }
- }
-
- return subjectKeyId;
- }
-
- /**
* Get CRLDistributionPoints extension
* @return CRLDistributionPoints object or null (if no such object in
* certificate)
@@ -1618,7 +1644,7 @@
}
GeneralNames names;
try {
- names = (GeneralNames) subjectAltNameExt.get(
+ names = subjectAltNameExt.get(
SubjectAlternativeNameExtension.SUBJECT_NAME);
} catch (IOException ioe) {
// should not occur
@@ -1650,7 +1676,7 @@
GeneralNames names;
try {
- names = (GeneralNames) subjectAltNameExt.get(
+ names = subjectAltNameExt.get(
SubjectAlternativeNameExtension.SUBJECT_NAME);
} catch (IOException ioe) {
// should not occur
@@ -1681,7 +1707,7 @@
}
GeneralNames names;
try {
- names = (GeneralNames) issuerAltNameExt.get(
+ names = issuerAltNameExt.get(
IssuerAlternativeNameExtension.ISSUER_NAME);
} catch (IOException ioe) {
// should not occur
@@ -1713,7 +1739,7 @@
data);
GeneralNames names;
try {
- names = (GeneralNames) issuerAltNameExt.get(
+ names = issuerAltNameExt.get(
IssuerAlternativeNameExtension.ISSUER_NAME);
} catch (IOException ioe) {
// should not occur
@@ -1903,4 +1929,47 @@
}
return false;
}
+
+ private ConcurrentHashMap<String,String> fingerprints =
+ new ConcurrentHashMap<>(2);
+
+ public String getFingerprint(String algorithm) {
+ if (!fingerprints.containsKey(algorithm)) {
+ fingerprints.put(algorithm, getCertificateFingerPrint(algorithm));
+ }
+ return fingerprints.get(algorithm);
+ }
+
+ /**
+ * Gets the requested finger print of the certificate. The result
+ * only contains 0-9 and A-F. No small case, no colon.
+ */
+ private String getCertificateFingerPrint(String mdAlg) {
+ String fingerPrint = "";
+ try {
+ byte[] encCertInfo = getEncoded();
+ MessageDigest md = MessageDigest.getInstance(mdAlg);
+ byte[] digest = md.digest(encCertInfo);
+ StringBuffer buf = new StringBuffer();
+ for (int i = 0; i < digest.length; i++) {
+ byte2hex(digest[i], buf);
+ }
+ fingerPrint = buf.toString();
+ } catch (NoSuchAlgorithmException | CertificateEncodingException e) {
+ // ignored
+ }
+ return fingerPrint;
+ }
+
+ /**
+ * Converts a byte to hex digit and writes to the supplied buffer
+ */
+ private static void byte2hex(byte b, StringBuffer buf) {
+ char[] hexChars = { '0', '1', '2', '3', '4', '5', '6', '7', '8',
+ '9', 'A', 'B', 'C', 'D', 'E', 'F' };
+ int high = ((b & 0xf0) >> 4);
+ int low = (b & 0x0f);
+ buf.append(hexChars[high]);
+ buf.append(hexChars[low]);
+ }
}
diff --git a/ojluni/src/main/java/sun/security/x509/X509CertInfo.java b/ojluni/src/main/java/sun/security/x509/X509CertInfo.java
index 419f1e7..b7f2dd8 100755
--- a/ojluni/src/main/java/sun/security/x509/X509CertInfo.java
+++ b/ojluni/src/main/java/sun/security/x509/X509CertInfo.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1997, 2006, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1997, 2012, 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
@@ -68,29 +68,30 @@
public static final String IDENT = "x509.info";
// Certificate attribute names
public static final String NAME = "info";
+ public static final String DN_NAME = "dname";
public static final String VERSION = CertificateVersion.NAME;
public static final String SERIAL_NUMBER = CertificateSerialNumber.NAME;
public static final String ALGORITHM_ID = CertificateAlgorithmId.NAME;
- public static final String ISSUER = CertificateIssuerName.NAME;
+ public static final String ISSUER = "issuer";
+ public static final String SUBJECT = "subject";
public static final String VALIDITY = CertificateValidity.NAME;
- public static final String SUBJECT = CertificateSubjectName.NAME;
public static final String KEY = CertificateX509Key.NAME;
- public static final String ISSUER_ID = CertificateIssuerUniqueIdentity.NAME;
- public static final String SUBJECT_ID = CertificateSubjectUniqueIdentity.NAME;
+ public static final String ISSUER_ID = "issuerID";
+ public static final String SUBJECT_ID = "subjectID";
public static final String EXTENSIONS = CertificateExtensions.NAME;
// X509.v1 data
protected CertificateVersion version = new CertificateVersion();
protected CertificateSerialNumber serialNum = null;
protected CertificateAlgorithmId algId = null;
- protected CertificateIssuerName issuer = null;
+ protected X500Name issuer = null;
+ protected X500Name subject = null;
protected CertificateValidity interval = null;
- protected CertificateSubjectName subject = null;
protected CertificateX509Key pubKey = null;
// X509.v2 & v3 extensions
- protected CertificateIssuerUniqueIdentity issuerUniqueId = null;
- protected CertificateSubjectUniqueIdentity subjectUniqueId = null;
+ protected UniqueIdentity issuerUniqueId = null;
+ protected UniqueIdentity subjectUniqueId = null;
// X509.v3 extensions
protected CertificateExtensions extensions = null;
@@ -149,10 +150,7 @@
parse(in);
} catch (IOException e) {
- CertificateParsingException parseException =
- new CertificateParsingException(e.toString());
- parseException.initCause(e);
- throw parseException;
+ throw new CertificateParsingException(e);
}
}
@@ -168,10 +166,7 @@
try {
parse(derVal);
} catch (IOException e) {
- CertificateParsingException parseException =
- new CertificateParsingException(e.toString());
- parseException.initCause(e);
- throw parseException;
+ throw new CertificateParsingException(e);
}
}
@@ -319,12 +314,12 @@
sb.append(" Subject Id:\n" + subjectUniqueId.toString() + "\n");
}
if (extensions != null) {
- Collection allExts = extensions.getAllExtensions();
- Object[] objs = allExts.toArray();
- sb.append("\nCertificate Extensions: " + objs.length);
- for (int i = 0; i < objs.length; i++) {
+ Collection<Extension> allExts = extensions.getAllExtensions();
+ Extension[] exts = allExts.toArray(new Extension[0]);
+ sb.append("\nCertificate Extensions: " + exts.length);
+ for (int i = 0; i < exts.length; i++) {
sb.append("\n[" + (i+1) + "]: ");
- Extension ext = (Extension)objs[i];
+ Extension ext = exts[i];
try {
if (OIDMap.getClass(ext.getExtensionId()) == null) {
sb.append(ext.toString());
@@ -405,11 +400,7 @@
break;
case ATTR_ISSUER:
- if (suffix == null) {
- setIssuer(val);
- } else {
- issuer.set(suffix, val);
- }
+ setIssuer(val);
break;
case ATTR_VALIDITY:
@@ -421,11 +412,7 @@
break;
case ATTR_SUBJECT:
- if (suffix == null) {
- setSubject(val);
- } else {
- subject.set(suffix, val);
- }
+ setSubject(val);
break;
case ATTR_KEY:
@@ -437,19 +424,11 @@
break;
case ATTR_ISSUER_ID:
- if (suffix == null) {
- setIssuerUniqueId(val);
- } else {
- issuerUniqueId.set(suffix, val);
- }
+ setIssuerUniqueId(val);
break;
case ATTR_SUBJECT_ID:
- if (suffix == null) {
- setSubjectUniqueId(val);
- } else {
- subjectUniqueId.set(suffix, val);
- }
+ setSubjectUniqueId(val);
break;
case ATTR_EXTENSIONS:
@@ -507,11 +486,7 @@
}
break;
case (ATTR_ISSUER):
- if (suffix == null) {
- issuer = null;
- } else {
- issuer.delete(suffix);
- }
+ issuer = null;
break;
case (ATTR_VALIDITY):
if (suffix == null) {
@@ -521,11 +496,7 @@
}
break;
case (ATTR_SUBJECT):
- if (suffix == null) {
- subject = null;
- } else {
- subject.delete(suffix);
- }
+ subject = null;
break;
case (ATTR_KEY):
if (suffix == null) {
@@ -535,18 +506,10 @@
}
break;
case (ATTR_ISSUER_ID):
- if (suffix == null) {
- issuerUniqueId = null;
- } else {
- issuerUniqueId.delete(suffix);
- }
+ issuerUniqueId = null;
break;
case (ATTR_SUBJECT_ID):
- if (suffix == null) {
- subjectUniqueId = null;
- } else {
- subjectUniqueId.delete(suffix);
- }
+ subjectUniqueId = null;
break;
case (ATTR_EXTENSIONS):
if (suffix == null) {
@@ -593,13 +556,13 @@
if (suffix == null) {
return(subject);
} else {
- return(subject.get(suffix));
+ return(getX500Name(suffix, false));
}
case (ATTR_ISSUER):
if (suffix == null) {
return(issuer);
} else {
- return(issuer.get(suffix));
+ return(getX500Name(suffix, true));
}
case (ATTR_KEY):
if (suffix == null) {
@@ -632,28 +595,29 @@
return(serialNum.get(suffix));
}
case (ATTR_ISSUER_ID):
- if (suffix == null) {
- return(issuerUniqueId);
- } else {
- if (issuerUniqueId == null)
- return null;
- else
- return(issuerUniqueId.get(suffix));
- }
+ return(issuerUniqueId);
case (ATTR_SUBJECT_ID):
- if (suffix == null) {
- return(subjectUniqueId);
- } else {
- if (subjectUniqueId == null)
- return null;
- else
- return(subjectUniqueId.get(suffix));
- }
+ return(subjectUniqueId);
}
return null;
}
/*
+ * Get the Issuer or Subject name
+ */
+ private Object getX500Name(String name, boolean getIssuer)
+ throws IOException {
+ if (name.equalsIgnoreCase(X509CertInfo.DN_NAME)) {
+ return getIssuer ? issuer : subject;
+ } else if (name.equalsIgnoreCase("x500principal")) {
+ return getIssuer ? issuer.asX500Principal()
+ : subject.asX500Principal();
+ } else {
+ throw new IOException("Attribute name not recognized.");
+ }
+ }
+
+ /*
* This routine unmarshals the certificate information.
*/
private void parse(DerValue val)
@@ -682,9 +646,8 @@
algId = new CertificateAlgorithmId(in);
// Issuer name
- issuer = new CertificateIssuerName(in);
- X500Name issuerDN = (X500Name)issuer.get(CertificateIssuerName.DN_NAME);
- if (issuerDN.isEmpty()) {
+ issuer = new X500Name(in);
+ if (issuer.isEmpty()) {
throw new CertificateParsingException(
"Empty issuer DN not allowed in X509Certificates");
}
@@ -693,10 +656,9 @@
interval = new CertificateValidity(in);
// subject name
- subject = new CertificateSubjectName(in);
- X500Name subjectDN = (X500Name)subject.get(CertificateSubjectName.DN_NAME);
+ subject = new X500Name(in);
if ((version.compare(CertificateVersion.V1) == 0) &&
- subjectDN.isEmpty()) {
+ subject.isEmpty()) {
throw new CertificateParsingException(
"Empty subject DN not allowed in v1 certificate");
}
@@ -717,7 +679,7 @@
// Get the issuerUniqueId if present
tmp = in.getDerValue();
if (tmp.isContextSpecific((byte)1)) {
- issuerUniqueId = new CertificateIssuerUniqueIdentity(tmp);
+ issuerUniqueId = new UniqueIdentity(tmp);
if (in.available() == 0)
return;
tmp = in.getDerValue();
@@ -725,7 +687,7 @@
// Get the subjectUniqueId if present.
if (tmp.isContextSpecific((byte)2)) {
- subjectUniqueId = new CertificateSubjectUniqueIdentity(tmp);
+ subjectUniqueId = new UniqueIdentity(tmp);
if (in.available() == 0)
return;
tmp = in.getDerValue();
@@ -748,13 +710,12 @@
/*
* Verify if X.509 V3 Certificate is compliant with RFC 3280.
*/
- private void verifyCert(CertificateSubjectName subject,
+ private void verifyCert(X500Name subject,
CertificateExtensions extensions)
throws CertificateParsingException, IOException {
// if SubjectName is empty, check for SubjectAlternativeNameExtension
- X500Name subjectDN = (X500Name)subject.get(CertificateSubjectName.DN_NAME);
- if (subjectDN.isEmpty()) {
+ if (subject.isEmpty()) {
if (extensions == null) {
throw new CertificateParsingException("X.509 Certificate is " +
"incomplete: subject field is empty, and certificate " +
@@ -766,8 +727,8 @@
try {
subjectAltNameExt = (SubjectAlternativeNameExtension)
extensions.get(SubjectAlternativeNameExtension.NAME);
- names = (GeneralNames) subjectAltNameExt.get
- (SubjectAlternativeNameExtension.SUBJECT_NAME);
+ names = subjectAltNameExt.get(
+ SubjectAlternativeNameExtension.SUBJECT_NAME);
} catch (IOException e) {
throw new CertificateParsingException("X.509 Certificate is " +
"incomplete: subject field is empty, and " +
@@ -820,10 +781,12 @@
// Encode issuerUniqueId & subjectUniqueId.
if (issuerUniqueId != null) {
- issuerUniqueId.encode(tmp);
+ issuerUniqueId.encode(tmp, DerValue.createTag(DerValue.TAG_CONTEXT,
+ false,(byte)1));
}
if (subjectUniqueId != null) {
- subjectUniqueId.encode(tmp);
+ subjectUniqueId.encode(tmp, DerValue.createTag(DerValue.TAG_CONTEXT,
+ false,(byte)2));
}
// Write all the extensions.
@@ -893,11 +856,11 @@
* @exception CertificateException on invalid data.
*/
private void setIssuer(Object val) throws CertificateException {
- if (!(val instanceof CertificateIssuerName)) {
+ if (!(val instanceof X500Name)) {
throw new CertificateException(
"Issuer class type invalid.");
}
- issuer = (CertificateIssuerName)val;
+ issuer = (X500Name)val;
}
/**
@@ -921,11 +884,11 @@
* @exception CertificateException on invalid data.
*/
private void setSubject(Object val) throws CertificateException {
- if (!(val instanceof CertificateSubjectName)) {
+ if (!(val instanceof X500Name)) {
throw new CertificateException(
"Subject class type invalid.");
}
- subject = (CertificateSubjectName)val;
+ subject = (X500Name)val;
}
/**
@@ -952,11 +915,11 @@
if (version.compare(CertificateVersion.V2) < 0) {
throw new CertificateException("Invalid version");
}
- if (!(val instanceof CertificateIssuerUniqueIdentity)) {
+ if (!(val instanceof UniqueIdentity)) {
throw new CertificateException(
"IssuerUniqueId class type invalid.");
}
- issuerUniqueId = (CertificateIssuerUniqueIdentity)val;
+ issuerUniqueId = (UniqueIdentity)val;
}
/**
@@ -969,11 +932,11 @@
if (version.compare(CertificateVersion.V2) < 0) {
throw new CertificateException("Invalid version");
}
- if (!(val instanceof CertificateSubjectUniqueIdentity)) {
+ if (!(val instanceof UniqueIdentity)) {
throw new CertificateException(
"SubjectUniqueId class type invalid.");
}
- subjectUniqueId = (CertificateSubjectUniqueIdentity)val;
+ subjectUniqueId = (UniqueIdentity)val;
}
/**
diff --git a/openjdk_java_files.mk b/openjdk_java_files.mk
index 65ad839..f066f03 100644
--- a/openjdk_java_files.mk
+++ b/openjdk_java_files.mk
@@ -512,6 +512,7 @@
ojluni/src/main/java/java/security/cert/CertPathBuilderSpi.java \
ojluni/src/main/java/java/security/cert/CertPathHelperImpl.java \
ojluni/src/main/java/java/security/cert/CertPath.java \
+ ojluni/src/main/java/java/security/cert/CertPathChecker.java \
ojluni/src/main/java/java/security/cert/CertPathParameters.java \
ojluni/src/main/java/java/security/cert/CertPathValidatorException.java \
ojluni/src/main/java/java/security/cert/CertPathValidator.java \
@@ -536,6 +537,7 @@
ojluni/src/main/java/java/security/cert/PKIXCertPathValidatorResult.java \
ojluni/src/main/java/java/security/cert/PKIXParameters.java \
ojluni/src/main/java/java/security/cert/PKIXReason.java \
+ ojluni/src/main/java/java/security/cert/PKIXRevocationChecker.java \
ojluni/src/main/java/java/security/cert/PolicyNode.java \
ojluni/src/main/java/java/security/cert/PolicyQualifierInfo.java \
ojluni/src/main/java/java/security/cert/TrustAnchor.java \
@@ -1312,15 +1314,46 @@
ojluni/src/main/java/sun/security/pkcs/PKCS9Attributes.java \
ojluni/src/main/java/sun/security/pkcs/SignerInfo.java \
ojluni/src/main/java/sun/security/pkcs/SigningCertificateInfo.java \
+ ojluni/src/main/java/sun/security/provider/certpath/AdaptableX509CertSelector.java \
+ ojluni/src/main/java/sun/security/provider/certpath/AdjacencyList.java \
ojluni/src/main/java/sun/security/provider/certpath/AlgorithmChecker.java \
+ ojluni/src/main/java/sun/security/provider/certpath/BasicChecker.java \
+ ojluni/src/main/java/sun/security/provider/certpath/BuildStep.java \
+ ojluni/src/main/java/sun/security/provider/certpath/Builder.java \
+ ojluni/src/main/java/sun/security/provider/certpath/CertId.java \
ojluni/src/main/java/sun/security/provider/certpath/CertPathHelper.java \
+ ojluni/src/main/java/sun/security/provider/certpath/CertStoreHelper.java \
+ ojluni/src/main/java/sun/security/provider/certpath/ConstraintsChecker.java \
+ ojluni/src/main/java/sun/security/provider/certpath/DistributionPointFetcher.java \
+ ojluni/src/main/java/sun/security/provider/certpath/ForwardBuilder.java \
+ ojluni/src/main/java/sun/security/provider/certpath/ForwardState.java \
+ ojluni/src/main/java/sun/security/provider/certpath/KeyChecker.java \
+ ojluni/src/main/java/sun/security/provider/certpath/OCSP.java \
+ ojluni/src/main/java/sun/security/provider/certpath/OCSPRequest.java \
+ ojluni/src/main/java/sun/security/provider/certpath/OCSPResponse.java \
+ ojluni/src/main/java/sun/security/provider/certpath/PKIX.java \
+ ojluni/src/main/java/sun/security/provider/certpath/PKIXCertPathValidator.java \
+ ojluni/src/main/java/sun/security/provider/certpath/PKIXMasterCertPathValidator.java \
+ ojluni/src/main/java/sun/security/provider/certpath/PolicyChecker.java \
+ ojluni/src/main/java/sun/security/provider/certpath/PolicyNodeImpl.java \
+ ojluni/src/main/java/sun/security/provider/certpath/ReverseBuilder.java \
+ ojluni/src/main/java/sun/security/provider/certpath/ReverseState.java \
+ ojluni/src/main/java/sun/security/provider/certpath/RevocationChecker.java \
+ ojluni/src/main/java/sun/security/provider/certpath/State.java \
+ ojluni/src/main/java/sun/security/provider/certpath/SunCertPathBuilder.java \
+ ojluni/src/main/java/sun/security/provider/certpath/SunCertPathBuilderException.java \
+ ojluni/src/main/java/sun/security/provider/certpath/SunCertPathBuilderParameters.java \
+ ojluni/src/main/java/sun/security/provider/certpath/SunCertPathBuilderResult.java \
+ ojluni/src/main/java/sun/security/provider/certpath/URICertStore.java \
ojluni/src/main/java/sun/security/provider/certpath/UntrustedChecker.java \
- ojluni/src/main/java/sun/security/provider/certpath/X509CertificatePair.java \
+ ojluni/src/main/java/sun/security/provider/certpath/Vertex.java \
ojluni/src/main/java/sun/security/provider/certpath/X509CertPath.java \
+ ojluni/src/main/java/sun/security/provider/certpath/X509CertificatePair.java \
ojluni/src/main/java/sun/security/provider/NativePRNG.java \
ojluni/src/main/java/sun/security/provider/NativeSeedGenerator.java \
ojluni/src/main/java/sun/security/provider/SecureRandom.java \
ojluni/src/main/java/sun/security/provider/SeedGenerator.java \
+ ojluni/src/main/java/sun/security/provider/Sun.java \
ojluni/src/main/java/sun/security/provider/SunEntries.java \
ojluni/src/main/java/sun/security/provider/VerificationProvider.java \
ojluni/src/main/java/sun/security/provider/X509Factory.java \