/*
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* 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.
*/
/**
* 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 succesfully
* 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
*/
/*
* private objects shared by methods
*/
private boolean pathCompleted = false;
private boolean onlyEECert = false;
/**
* Create an instance of <code>SunCertPathBuilder</code>.
*
* @throws CertPathBuilderException if an error occurs
*/
try {
} catch (CertificateException e) {
throw new CertPathBuilderException(e);
}
("com.sun.security.onlyCheckRevocationOfEECert"));
}
/**
* 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.
*/
}
if (!(params instanceof PKIXBuilderParameters)) {
throw new InvalidAlgorithmParameterException("inappropriate " +
"parameter type, must be an instance of PKIXBuilderParameters");
}
boolean buildForward = true;
if (params instanceof SunCertPathBuilderParameters) {
}
/* Check mandatory parameters */
// Make sure that none of the trust anchors include name constraints
// (not supported).
throw new InvalidAlgorithmParameterException
("name constraints in trust anchor not supported");
}
}
if (!(sel instanceof X509CertSelector)) {
throw new InvalidAlgorithmParameterException("the "
+ "targetCertConstraints parameter must be an "
+ "X509CertSelector");
}
if (targetSubjectDN == null) {
if (targetCert != null) {
}
}
// reorder CertStores so that local CertStores are tried first
if (targetSubjectDN == null) {
}
if (targetSubjectDN == null) {
throw new InvalidAlgorithmParameterException
("Could not determine unique target subject");
}
}
// try again
throw new SunCertPathBuilderException("unable to find valid "
+ "certification path to requested target",
new AdjacencyList(adjList));
}
}
return result;
}
throws CertPathBuilderException {
// Init shared variables and build certification path
pathCompleted = false;
trustAnchor = null;
new LinkedList<X509Certificate>();
try {
if (buildForward) {
} else {
}
} catch (Exception e) {
+ "build");
e.printStackTrace();
}
throw new SunCertPathBuilderException("unable to find valid "
+ "certification path to requested target", e,
new AdjacencyList(adjList));
}
// construct SunCertPathBuilderResult
try {
if (pathCompleted) {
+ "pathCompleted");
// we must return a certpath which has the target
// as the first cert in the certpath - i.e. reverse
// the certPathList
return new SunCertPathBuilderResult(
new AdjacencyList(adjList));
}
} catch (Exception e) {
+ "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.
*/
{
}
/* Initialize adjacency list */
/*
* Perform a search using each trust anchor, until a valid
* path is found
*/
/* check if anchor satisfies target constraints */
this.trustAnchor = anchor;
this.pathCompleted = true;
break;
}
/* Initialize current state */
// init the crl checker
try {
} catch (Exception e) {
// continue on error if more anchors to try
continue;
else
throw e;
}
// break out of loop if search is successful
break;
}
+ "depthFirstSearchReverse()");
}
}
/*
* Private build forward method.
*/
throws GeneralSecurityException, IOException
{
}
/* Initialize current state */
/* Initialize adjacency list */
// init the crl checker
new ForwardBuilder
}
/*
* 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
*/
throws GeneralSecurityException, IOException
{
//XXX This method should probably catch & handle exceptions
}
/*
* Find all the certificates issued to dN which
* satisfy the PKIX certification path constraints.
*/
}
/*
* 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.
*/
/**
* 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.
*/
try {
} catch (GeneralSecurityException gse) {
+ ": validation failed: " + 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
*/
+ ": commencing final verification");
/*
* 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 certPathList
*/
}
rootNode);
int mustCheck = 0;
mustCheck++;
// add the algorithm checker
mustCheck++;
if (nextState.keyParamsNeeded()) {
"SunCertPathBuilder.depthFirstSearchForward " +
"using buildParams public key: " +
}
// add the basic checker
true);
mustCheck++;
// add the crl revocation checker
if (buildParams.isRevocationEnabled()) {
mustCheck++;
}
}
// Why we don't need BasicChecker and CrlRevocationChecker
// if nextState.keyParamsNeeded() is false?
if (unresCritExts == null) {
}
if (j < mustCheck ||
if (i == 0) {
currChecker.init(false);
// The user specified
// AlgorithmChecker may not be
// able to set the trust anchor until now.
if (j >= mustCheck &&
currChecker instanceof AlgorithmChecker) {
}
}
try {
} catch (CertPathValidatorException cpve) {
("SunCertPathBuilder.depthFirstSearchForward(): " +
"final verification failed: " + 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 :
{
if (checker.isForwardCheckingSupported()) {
}
}
}
if (!unresCritExts.isEmpty()) {
if (!unresCritExts.isEmpty()) {
throw new CertPathValidatorException
("unrecognized critical extension(s)", null,
}
}
}
+ ": 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 certPathList
*/
// Save the trust anchor
/*
* Extract and save the final target public key
*/
if (basicChecker != null) {
} else {
} else {
}
}
return;
} else {
}
/* Update the PKIX state */
/*
* Append an entry for cert in adjacency list and
* set index for current vertex.
*/
/* recursively search for matching certs at next dN */
/*
* 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.
*/
+ ": backtracking");
}
}
}
/*
* 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
*/
throws GeneralSecurityException, IOException
{
/*
* Find all the certificates issued by dN which
* satisfy the PKIX certification path constraints.
*/
/*
* 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.
*/
/**
* 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.
*/
try {
} catch (GeneralSecurityException gse) {
+ ": validation failed: " + gse);
continue;
}
/*
* Certificate is good, add it to the path (if it isn't a
* self-signed cert) and update state
*/
if (!currentState.isInitial())
// save trust anchor
/*
* Check if path is completed, return ASAP if so.
*/
+ ": path completed!");
pathCompleted = true;
else {
}
/*
* Extract and save the final target public key
*/
if (finalPublicKey instanceof DSAPublicKey &&
{
}
return;
}
/* Update the PKIX state */
/*
* Append an entry for cert in adjacency list and
* set index for current vertex.
*/
/* recursively search for matching certs at next dN */
/*
* 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.
*/
+ ": backtracking");
if (!currentState.isInitial())
}
}
+ "certs in this adjacency list checked");
}
/*
* Adds a collection of matching certificates to the
* adjacency list.
*/
l.add(v);
}
return l;
}
/**
* Returns true if trust anchor certificate matches specified
* certificate constraints.
*/
if (anchorCert != null) {
}
return false;
}
/**
* Comparator that orders CertStores so that local CertStores come before
* remote CertStores.
*/
return -1;
} else {
return 1;
}
}
}
/**
* Returns the target subject DN from the first X509Certificate that
* is fetched that matches the specified X509CertSelector.
*/
try {
(Collection<? extends Certificate>)
if (!targetCerts.isEmpty()) {
return targetCert.getSubjectX500Principal();
}
} catch (CertStoreException e) {
// ignore but log it
"non-fatal exception retrieving certs: " + e);
e.printStackTrace();
}
}
}
return null;
}
}