mirror of
https://github.com/openjdk/jdk.git
synced 2025-08-28 15:24:43 +02:00
8187443: Forest Consolidation: Move files to unified layout
Reviewed-by: darcy, ihse
This commit is contained in:
parent
270fe13182
commit
3789983e89
56923 changed files with 3 additions and 15727 deletions
|
@ -0,0 +1,581 @@
|
|||
/*
|
||||
* Copyright (c) 2000, 2017, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* 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.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 builds certification paths in the forward direction.
|
||||
*
|
||||
* <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 5280.
|
||||
*
|
||||
* <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. This method will
|
||||
* attempt to build in the forward direction: from the target to the CA.
|
||||
*
|
||||
* <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 building again searching all certstores");
|
||||
}
|
||||
// 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 {
|
||||
buildForward(adjList, certPathList, searchAllCertStores);
|
||||
} 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 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,
|
||||
buildParams.date(), buildParams.variant()));
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* 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;
|
||||
}
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue