void depthFirstSearchForward(X500Principal dN,
ForwardState currentState,
ForwardBuilder builder,
List adjList,
LinkedList certPathList) throws IOException, GeneralSecurityException {
//XXX This method should probably catch & handle exceptions
if (debug != null) {
debug.println("SunCertPathBuilder.depthFirstSearchForward(" + dN
+ ", " + currentState.toString() + ")");
}
/*
* Find all the certificates issued to dN which
* satisfy the PKIX certification path constraints.
*/
List< Vertex > vertices = addVertices
(builder.getMatchingCerts(currentState, orderedCertStores), 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 = (X509Certificate) vertex.getCertificate();
try {
builder.verifyCert(cert, nextState, certPathList);
} 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)) {
BasicChecker basicChecker = null;
if (debug != null)
debug.println("SunCertPathBuilder.depthFirstSearchForward()"
+ ": commencing final verification");
ArrayList< X509Certificate > appendedCerts =
new ArrayList< X509Certificate >(certPathList);
/*
* 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
*/
if (builder.trustAnchor.getTrustedCert() == null) {
appendedCerts.add(0, cert);
}
HashSet< String > initExpPolSet = new HashSet< String >(1);
initExpPolSet.add(PolicyChecker.ANY_POLICY);
PolicyNodeImpl rootNode = new PolicyNodeImpl(null,
PolicyChecker.ANY_POLICY, null, false, initExpPolSet, false);
PolicyChecker policyChecker
= new PolicyChecker(buildParams.getInitialPolicies(),
appendedCerts.size(),
buildParams.isExplicitPolicyRequired(),
buildParams.isPolicyMappingInhibited(),
buildParams.isAnyPolicyInhibited(),
buildParams.getPolicyQualifiersRejected(),
rootNode);
List< PKIXCertPathChecker > userCheckers = new
ArrayList< PKIXCertPathChecker >
(buildParams.getCertPathCheckers());
int mustCheck = 0;
userCheckers.add(mustCheck, policyChecker);
mustCheck++;
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);
basicChecker = new BasicChecker(anchor,
builder.date,
buildParams.getSigProvider(),
true);
userCheckers.add(mustCheck, basicChecker);
mustCheck++;
if (buildParams.isRevocationEnabled()) {
userCheckers.add(mustCheck,
new CrlRevocationChecker(anchor, buildParams));
mustCheck++;
}
}
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 (int j=0; j< userCheckers.size(); j++) {
PKIXCertPathChecker currChecker = userCheckers.get(j);
if (j < mustCheck ||
!currChecker.isForwardCheckingSupported())
{
if (i == 0) {
currChecker.init(false);
}
try {
currChecker.check(currCert, unresCritExts);
} catch (CertPathValidatorException cpve) {
if (debug != null)
debug.println
("SunCertPathBuilder.depthFirstSearchForward(): " +
"final verification failed: " + 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.getCertPathCheckers())
{
if (checker.isForwardCheckingSupported()) {
Set< String > suppExts =
checker.getSupportedExtensions();
if (suppExts != null) {
unresCritExts.removeAll(suppExts);
}
}
}
if (!unresCritExts.isEmpty()) {
unresCritExts.remove
(PKIXExtensions.BasicConstraints_Id.toString());
unresCritExts.remove
(PKIXExtensions.NameConstraints_Id.toString());
unresCritExts.remove
(PKIXExtensions.CertificatePolicies_Id.toString());
unresCritExts.remove
(PKIXExtensions.PolicyMappings_Id.toString());
unresCritExts.remove
(PKIXExtensions.PolicyConstraints_Id.toString());
unresCritExts.remove
(PKIXExtensions.InhibitAnyPolicy_Id.toString());
unresCritExts.remove(PKIXExtensions.
SubjectAlternativeName_Id.toString());
unresCritExts.remove
(PKIXExtensions.KeyUsage_Id.toString());
unresCritExts.remove
(PKIXExtensions.ExtendedKeyUsage_Id.toString());
if (!unresCritExts.isEmpty()) {
throw new CertPathValidatorException("unrecognized "
+ "critical extension(s)");
}
}
}
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 certPathList
*/
if (builder.trustAnchor.getTrustedCert() == null)
builder.addCertToPath(cert, certPathList);
// 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 (certPathList.size() == 0) {
finalCert = builder.trustAnchor.getTrustedCert();
} else {
finalCert = certPathList.get(certPathList.size()-1);
}
finalPublicKey = finalCert.getPublicKey();
}
policyTreeResult = policyChecker.getPolicyTree();
return;
} else {
builder.addCertToPath(cert, certPathList);
}
/* 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, certPathList);
/*
* 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(certPathList);
}
}
}
|