Save This Page
Home » openjdk-7 » sun.security » provider » certpath » [javadoc | source]
    1   /*
    2    * Copyright 2000-2007 Sun Microsystems, Inc.  All Rights Reserved.
    3    * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
    4    *
    5    * This code is free software; you can redistribute it and/or modify it
    6    * under the terms of the GNU General Public License version 2 only, as
    7    * published by the Free Software Foundation.  Sun designates this
    8    * particular file as subject to the "Classpath" exception as provided
    9    * by Sun in the LICENSE file that accompanied this code.
   10    *
   11    * This code is distributed in the hope that it will be useful, but WITHOUT
   12    * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
   13    * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
   14    * version 2 for more details (a copy is included in the LICENSE file that
   15    * accompanied this code).
   16    *
   17    * You should have received a copy of the GNU General Public License version
   18    * 2 along with this work; if not, write to the Free Software Foundation,
   19    * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
   20    *
   21    * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
   22    * CA 95054 USA or visit www.sun.com if you need additional information or
   23    * have any questions.
   24    */
   25   
   26   package sun.security.provider.certpath;
   27   
   28   import java.io.IOException;
   29   import java.security.GeneralSecurityException;
   30   import java.security.InvalidAlgorithmParameterException;
   31   import java.security.Principal;
   32   import java.security.PublicKey;
   33   import java.util.ArrayList;
   34   import java.util.Collection;
   35   import java.util.Collections;
   36   import java.util.Comparator;
   37   import java.util.HashSet;
   38   import java.util.Iterator;
   39   import java.util.List;
   40   import java.util.LinkedList;
   41   import java.util.Set;
   42   
   43   import java.security.cert;
   44   import java.security.interfaces.DSAPublicKey;
   45   
   46   import javax.security.auth.x500.X500Principal;
   47   
   48   import sun.security.x509.X500Name;
   49   import sun.security.x509.PKIXExtensions;
   50   import sun.security.util.Debug;
   51   
   52   /**
   53    * This class is able to build certification paths in either the forward
   54    * or reverse directions.
   55    *
   56    * <p> If successful, it returns a certification path which has succesfully
   57    * satisfied all the constraints and requirements specified in the
   58    * PKIXBuilderParameters object and has been validated according to the PKIX
   59    * path validation algorithm defined in RFC 3280.
   60    *
   61    * <p> This implementation uses a depth-first search approach to finding
   62    * certification paths. If it comes to a point in which it cannot find
   63    * any more certificates leading to the target OR the path length is too long
   64    * it backtracks to previous paths until the target has been found or
   65    * all possible paths have been exhausted.
   66    *
   67    * <p> This implementation is not thread-safe.
   68    *
   69    * @since       1.4
   70    * @author      Sean Mullan
   71    * @author      Yassir Elley
   72    */
   73   public final class SunCertPathBuilder extends CertPathBuilderSpi {
   74   
   75       private static final Debug debug = Debug.getInstance("certpath");
   76   
   77       /*
   78        * private objects shared by methods
   79        */
   80       private PKIXBuilderParameters buildParams;
   81       private CertificateFactory cf;
   82       private boolean pathCompleted = false;
   83       private X500Principal targetSubjectDN;
   84       private PolicyNode policyTreeResult;
   85       private TrustAnchor trustAnchor;
   86       private PublicKey finalPublicKey;
   87       private X509CertSelector targetSel;
   88       private List<CertStore> orderedCertStores;
   89   
   90       /**
   91        * Create an instance of <code>SunCertPathBuilder</code>.
   92        *
   93        * @throws CertPathBuilderException if an error occurs
   94        */
   95       public SunCertPathBuilder() throws CertPathBuilderException {
   96           try {
   97               cf = CertificateFactory.getInstance("X.509");
   98           } catch (CertificateException e) {
   99               throw new CertPathBuilderException(e);
  100           }
  101       }
  102   
  103       /**
  104        * Attempts to build a certification path using the Sun build
  105        * algorithm from a trusted anchor(s) to a target subject, which must both
  106        * be specified in the input parameter set. By default, this method will
  107        * attempt to build in the forward direction. In order to build in the
  108        * reverse direction, the caller needs to pass in an instance of
  109        * SunCertPathBuilderParameters with the buildForward flag set to false.
  110        *
  111        * <p>The certification path that is constructed is validated
  112        * according to the PKIX specification.
  113        *
  114        * @param params the parameter set for building a path. Must be an instance
  115        *  of <code>PKIXBuilderParameters</code>.
  116        * @return a certification path builder result.
  117        * @exception CertPathBuilderException Exception thrown if builder is
  118        *  unable to build a complete certification path from the trusted anchor(s)
  119        *  to the target subject.
  120        * @throws InvalidAlgorithmParameterException if the given parameters are
  121        *  inappropriate for this certification path builder.
  122        */
  123       public CertPathBuilderResult engineBuild(CertPathParameters params)
  124           throws CertPathBuilderException, InvalidAlgorithmParameterException {
  125   
  126           if (debug != null) {
  127               debug.println("SunCertPathBuilder.engineBuild(" + params + ")");
  128           }
  129   
  130           if (!(params instanceof PKIXBuilderParameters)) {
  131               throw new InvalidAlgorithmParameterException("inappropriate " +
  132                   "parameter type, must be an instance of PKIXBuilderParameters");
  133           }
  134   
  135           boolean buildForward = true;
  136           if (params instanceof SunCertPathBuilderParameters) {
  137               buildForward =
  138                   ((SunCertPathBuilderParameters)params).getBuildForward();
  139           }
  140   
  141           buildParams = (PKIXBuilderParameters)params;
  142   
  143           /* Check mandatory parameters */
  144   
  145           // Make sure that none of the trust anchors include name constraints
  146           // (not supported).
  147           for (TrustAnchor anchor : buildParams.getTrustAnchors()) {
  148               if (anchor.getNameConstraints() != null) {
  149                   throw new InvalidAlgorithmParameterException
  150                       ("name constraints in trust anchor not supported");
  151               }
  152           }
  153   
  154           CertSelector sel = buildParams.getTargetCertConstraints();
  155           if (!(sel instanceof X509CertSelector)) {
  156               throw new InvalidAlgorithmParameterException("the "
  157                   + "targetCertConstraints parameter must be an "
  158                   + "X509CertSelector");
  159           }
  160           targetSel = (X509CertSelector)sel;
  161           targetSubjectDN = targetSel.getSubject();
  162           if (targetSubjectDN == null) {
  163               X509Certificate targetCert = targetSel.getCertificate();
  164               if (targetCert != null) {
  165                   targetSubjectDN = targetCert.getSubjectX500Principal();
  166               }
  167           }
  168           // reorder CertStores so that local CertStores are tried first
  169           orderedCertStores =
  170               new ArrayList<CertStore>(buildParams.getCertStores());
  171           Collections.sort(orderedCertStores, new CertStoreComparator());
  172           if (targetSubjectDN == null) {
  173               targetSubjectDN = getTargetSubjectDN(orderedCertStores, targetSel);
  174           }
  175           if (targetSubjectDN == null) {
  176               throw new InvalidAlgorithmParameterException
  177                   ("Could not determine unique target subject");
  178           }
  179   
  180           List<List<Vertex>> adjList = new ArrayList<List<Vertex>>();
  181           CertPathBuilderResult result =
  182               buildCertPath(buildForward, false, adjList);
  183           if (result == null) {
  184               if (debug != null) {
  185                   debug.println("SunCertPathBuilder.engineBuild: 2nd pass");
  186               }
  187               // try again
  188               adjList.clear();
  189               result = buildCertPath(buildForward, true, adjList);
  190               if (result == null) {
  191                   throw new SunCertPathBuilderException("unable to find valid "
  192                       + "certification path to requested target",
  193                       new AdjacencyList(adjList));
  194               }
  195           }
  196           return result;
  197       }
  198   
  199       private CertPathBuilderResult buildCertPath(boolean buildForward,
  200           boolean searchAllCertStores, List<List<Vertex>> adjList)
  201           throws CertPathBuilderException {
  202   
  203           // Init shared variables and build certification path
  204           pathCompleted = false;
  205           trustAnchor = null;
  206           finalPublicKey = null;
  207           policyTreeResult = null;
  208           LinkedList<X509Certificate> certPathList =
  209               new LinkedList<X509Certificate>();
  210           try {
  211               if (buildForward) {
  212                   buildForward(adjList, certPathList, searchAllCertStores);
  213               } else {
  214                   buildReverse(adjList, certPathList);
  215               }
  216           } catch (Exception e) {
  217               if (debug != null) {
  218                   debug.println("SunCertPathBuilder.engineBuild() exception in "
  219                       + "build");
  220                   e.printStackTrace();
  221               }
  222               throw new SunCertPathBuilderException("unable to find valid "
  223                   + "certification path to requested target", e,
  224                   new AdjacencyList(adjList));
  225           }
  226   
  227           // construct SunCertPathBuilderResult
  228           try {
  229               if (pathCompleted) {
  230                   if (debug != null)
  231                       debug.println("SunCertPathBuilder.engineBuild() "
  232                                     + "pathCompleted");
  233   
  234                   // we must return a certpath which has the target
  235                   // as the first cert in the certpath - i.e. reverse
  236                   // the certPathList
  237                   Collections.reverse(certPathList);
  238   
  239                   return new SunCertPathBuilderResult(
  240                       cf.generateCertPath(certPathList), this.trustAnchor,
  241                       policyTreeResult, finalPublicKey,
  242                       new AdjacencyList(adjList));
  243               }
  244           } catch (Exception e) {
  245               if (debug != null) {
  246                   debug.println("SunCertPathBuilder.engineBuild() exception "
  247                                 + "in wrap-up");
  248                   e.printStackTrace();
  249               }
  250               throw new SunCertPathBuilderException("unable to find valid "
  251                   + "certification path to requested target", e,
  252                   new AdjacencyList(adjList));
  253           }
  254   
  255           return null;
  256       }
  257   
  258       /*
  259        * Private build reverse method.
  260        *
  261        */
  262       private void buildReverse(List<List<Vertex>> adjacencyList,
  263           LinkedList<X509Certificate> certPathList) throws Exception
  264       {
  265           if (debug != null) {
  266               debug.println("SunCertPathBuilder.buildReverse()...");
  267               debug.println("SunCertPathBuilder.buildReverse() InitialPolicies: "
  268                   + buildParams.getInitialPolicies());
  269           }
  270   
  271           ReverseState currentState = new ReverseState();
  272           /* Initialize adjacency list */
  273           adjacencyList.clear();
  274           adjacencyList.add(new LinkedList<Vertex>());
  275   
  276           /*
  277            * Perform a search using each trust anchor, until a valid
  278            * path is found
  279            */
  280           Iterator<TrustAnchor> iter = buildParams.getTrustAnchors().iterator();
  281           while (iter.hasNext()) {
  282               TrustAnchor anchor = iter.next();
  283               /* check if anchor satisfies target constraints */
  284               if (anchorIsTarget(anchor, targetSel)) {
  285                   this.trustAnchor = anchor;
  286                   this.pathCompleted = true;
  287                   this.finalPublicKey = anchor.getTrustedCert().getPublicKey();
  288                   break;
  289               }
  290   
  291               /* Initialize current state */
  292               currentState.initState(buildParams.getMaxPathLength(),
  293                          buildParams.isExplicitPolicyRequired(),
  294                          buildParams.isPolicyMappingInhibited(),
  295                          buildParams.isAnyPolicyInhibited(),
  296                          buildParams.getCertPathCheckers());
  297               currentState.updateState(anchor);
  298               // init the crl checker
  299               currentState.crlChecker =
  300                   new CrlRevocationChecker(null, buildParams);
  301               try {
  302                   depthFirstSearchReverse(null, currentState,
  303                   new ReverseBuilder(buildParams, targetSubjectDN), adjacencyList,
  304                   certPathList);
  305               } catch (Exception e) {
  306                   // continue on error if more anchors to try
  307                   if (iter.hasNext())
  308                       continue;
  309                   else
  310                       throw e;
  311               }
  312   
  313               // break out of loop if search is successful
  314               break;
  315           }
  316   
  317           if (debug != null) {
  318               debug.println("SunCertPathBuilder.buildReverse() returned from "
  319                   + "depthFirstSearchReverse()");
  320               debug.println("SunCertPathBuilder.buildReverse() "
  321                   + "certPathList.size: " + certPathList.size());
  322           }
  323       }
  324   
  325       /*
  326        * Private build forward method.
  327        */
  328       private void buildForward(List<List<Vertex>> adjacencyList,
  329           LinkedList<X509Certificate> certPathList, boolean searchAllCertStores)
  330           throws GeneralSecurityException, IOException
  331       {
  332           if (debug != null) {
  333               debug.println("SunCertPathBuilder.buildForward()...");
  334           }
  335   
  336           /* Initialize current state */
  337           ForwardState currentState = new ForwardState();
  338           currentState.initState(buildParams.getCertPathCheckers());
  339   
  340           /* Initialize adjacency list */
  341           adjacencyList.clear();
  342           adjacencyList.add(new LinkedList<Vertex>());
  343   
  344           // init the crl checker
  345           currentState.crlChecker = new CrlRevocationChecker(null, buildParams);
  346   
  347           depthFirstSearchForward(targetSubjectDN, currentState,
  348             new ForwardBuilder(buildParams, targetSubjectDN, searchAllCertStores),
  349             adjacencyList, certPathList);
  350       }
  351   
  352       /*
  353        * This method performs a depth first search for a certification
  354        * path while building forward which meets the requirements set in
  355        * the parameters object.
  356        * It uses an adjacency list to store all certificates which were
  357        * tried (i.e. at one time added to the path - they may not end up in
  358        * the final path if backtracking occurs). This information can
  359        * be used later to debug or demo the build.
  360        *
  361        * See "Data Structure and Algorithms, by Aho, Hopcroft, and Ullman"
  362        * for an explanation of the DFS algorithm.
  363        *
  364        * @param dN the distinguished name being currently searched for certs
  365        * @param currentState the current PKIX validation state
  366        */
  367       void depthFirstSearchForward(X500Principal dN, ForwardState currentState,
  368           ForwardBuilder builder, List<List<Vertex>> adjList,
  369           LinkedList<X509Certificate> certPathList)
  370           throws GeneralSecurityException, IOException
  371       {
  372           //XXX This method should probably catch & handle exceptions
  373   
  374           if (debug != null) {
  375               debug.println("SunCertPathBuilder.depthFirstSearchForward(" + dN
  376                   + ", " + currentState.toString() + ")");
  377           }
  378   
  379           /*
  380            * Find all the certificates issued to dN which
  381            * satisfy the PKIX certification path constraints.
  382            */
  383           List<Vertex> vertices = addVertices
  384              (builder.getMatchingCerts(currentState, orderedCertStores), adjList);
  385           if (debug != null) {
  386               debug.println("SunCertPathBuilder.depthFirstSearchForward(): "
  387                   + "certs.size=" + vertices.size());
  388           }
  389   
  390           /*
  391            * For each cert in the collection, verify anything
  392            * that hasn't been checked yet (signature, revocation, etc)
  393            * and check for loops. Call depthFirstSearchForward()
  394            * recursively for each good cert.
  395            */
  396   
  397                  vertices:
  398           for (Vertex vertex : vertices) {
  399               /**
  400                * Restore state to currentState each time through the loop.
  401                * This is important because some of the user-defined
  402                * checkers modify the state, which MUST be restored if
  403                * the cert eventually fails to lead to the target and
  404                * the next matching cert is tried.
  405                */
  406               ForwardState nextState = (ForwardState) currentState.clone();
  407               X509Certificate cert = (X509Certificate) vertex.getCertificate();
  408   
  409               try {
  410                   builder.verifyCert(cert, nextState, certPathList);
  411               } catch (GeneralSecurityException gse) {
  412                   if (debug != null) {
  413                       debug.println("SunCertPathBuilder.depthFirstSearchForward()"
  414                           + ": validation failed: " + gse);
  415                       gse.printStackTrace();
  416                   }
  417                   vertex.setThrowable(gse);
  418                   continue;
  419               }
  420   
  421               /*
  422                * Certificate is good.
  423                * If cert completes the path,
  424                *    process userCheckers that don't support forward checking
  425                *    and process policies over whole path
  426                *    and backtrack appropriately if there is a failure
  427                * else if cert does not complete the path,
  428                *    add it to the path
  429                */
  430               if (builder.isPathCompleted(cert)) {
  431   
  432                   BasicChecker basicChecker = null;
  433                   if (debug != null)
  434                       debug.println("SunCertPathBuilder.depthFirstSearchForward()"
  435                           + ": commencing final verification");
  436   
  437                   ArrayList<X509Certificate> appendedCerts =
  438                       new ArrayList<X509Certificate>(certPathList);
  439   
  440                   /*
  441                    * if the trust anchor selected is specified as a trusted
  442                    * public key rather than a trusted cert, then verify this
  443                    * cert (which is signed by the trusted public key), but
  444                    * don't add it yet to the certPathList
  445                    */
  446                   if (builder.trustAnchor.getTrustedCert() == null) {
  447                       appendedCerts.add(0, cert);
  448                   }
  449   
  450                   HashSet<String> initExpPolSet = new HashSet<String>(1);
  451                   initExpPolSet.add(PolicyChecker.ANY_POLICY);
  452   
  453                   PolicyNodeImpl rootNode = new PolicyNodeImpl(null,
  454                       PolicyChecker.ANY_POLICY, null, false, initExpPolSet, false);
  455   
  456                   PolicyChecker policyChecker
  457                       = new PolicyChecker(buildParams.getInitialPolicies(),
  458                                   appendedCerts.size(),
  459                                   buildParams.isExplicitPolicyRequired(),
  460                                   buildParams.isPolicyMappingInhibited(),
  461                                   buildParams.isAnyPolicyInhibited(),
  462                                   buildParams.getPolicyQualifiersRejected(),
  463                                   rootNode);
  464   
  465                   List<PKIXCertPathChecker> userCheckers = new
  466                       ArrayList<PKIXCertPathChecker>
  467                           (buildParams.getCertPathCheckers());
  468                   int mustCheck = 0;
  469                   userCheckers.add(mustCheck, policyChecker);
  470                   mustCheck++;
  471   
  472                   if (nextState.keyParamsNeeded()) {
  473                       PublicKey rootKey = cert.getPublicKey();
  474                       if (builder.trustAnchor.getTrustedCert() == null) {
  475                           rootKey = builder.trustAnchor.getCAPublicKey();
  476                           if (debug != null)
  477                               debug.println("SunCertPathBuilder.depthFirstSearchForward" +
  478                                             " using buildParams public key: " +
  479                                             rootKey.toString());
  480                       }
  481                       TrustAnchor anchor = new TrustAnchor
  482                           (cert.getSubjectX500Principal(), rootKey, null);
  483                       basicChecker = new BasicChecker(anchor,
  484                                              builder.date,
  485                                              buildParams.getSigProvider(),
  486                                              true);
  487                       userCheckers.add(mustCheck, basicChecker);
  488                       mustCheck++;
  489                       if (buildParams.isRevocationEnabled()) {
  490                           userCheckers.add(mustCheck,
  491                               new CrlRevocationChecker(anchor, buildParams));
  492                           mustCheck++;
  493                       }
  494                   }
  495   
  496                   for (int i=0; i<appendedCerts.size(); i++) {
  497                       X509Certificate currCert = appendedCerts.get(i);
  498                       if (debug != null)
  499                           debug.println("current subject = "
  500                                         + currCert.getSubjectX500Principal());
  501                       Set<String> unresCritExts =
  502                           currCert.getCriticalExtensionOIDs();
  503                       if (unresCritExts == null) {
  504                           unresCritExts = Collections.<String>emptySet();
  505                       }
  506   
  507                       for (int j=0; j<userCheckers.size(); j++) {
  508                           PKIXCertPathChecker currChecker = userCheckers.get(j);
  509                           if (j < mustCheck ||
  510                               !currChecker.isForwardCheckingSupported())
  511                           {
  512                               if (i == 0) {
  513                                   currChecker.init(false);
  514                               }
  515   
  516                               try {
  517                                   currChecker.check(currCert, unresCritExts);
  518                               } catch (CertPathValidatorException cpve) {
  519                                   if (debug != null)
  520                                       debug.println
  521                                       ("SunCertPathBuilder.depthFirstSearchForward(): " +
  522                                       "final verification failed: " + cpve);
  523                                   vertex.setThrowable(cpve);
  524                                   continue vertices;
  525                               }
  526                           }
  527                       }
  528   
  529                       /*
  530                        * Remove extensions from user checkers that support
  531                        * forward checking. After this step, we will have
  532                        * removed all extensions that all user checkers
  533                        * are capable of processing.
  534                        */
  535                       for (PKIXCertPathChecker checker :
  536                            buildParams.getCertPathCheckers())
  537                       {
  538                           if (checker.isForwardCheckingSupported()) {
  539                               Set<String> suppExts =
  540                                   checker.getSupportedExtensions();
  541                               if (suppExts != null) {
  542                                   unresCritExts.removeAll(suppExts);
  543                               }
  544                           }
  545                       }
  546   
  547                       if (!unresCritExts.isEmpty()) {
  548                           unresCritExts.remove
  549                               (PKIXExtensions.BasicConstraints_Id.toString());
  550                           unresCritExts.remove
  551                               (PKIXExtensions.NameConstraints_Id.toString());
  552                           unresCritExts.remove
  553                               (PKIXExtensions.CertificatePolicies_Id.toString());
  554                           unresCritExts.remove
  555                               (PKIXExtensions.PolicyMappings_Id.toString());
  556                           unresCritExts.remove
  557                               (PKIXExtensions.PolicyConstraints_Id.toString());
  558                           unresCritExts.remove
  559                               (PKIXExtensions.InhibitAnyPolicy_Id.toString());
  560                           unresCritExts.remove(PKIXExtensions.
  561                               SubjectAlternativeName_Id.toString());
  562                           unresCritExts.remove
  563                               (PKIXExtensions.KeyUsage_Id.toString());
  564                           unresCritExts.remove
  565                               (PKIXExtensions.ExtendedKeyUsage_Id.toString());
  566   
  567                           if (!unresCritExts.isEmpty()) {
  568                               throw new CertPathValidatorException("unrecognized "
  569                                   + "critical extension(s)");
  570                           }
  571                       }
  572                   }
  573                   if (debug != null)
  574                       debug.println("SunCertPathBuilder.depthFirstSearchForward()"
  575                           + ": final verification succeeded - path completed!");
  576                   pathCompleted = true;
  577   
  578                   /*
  579                    * if the user specified a trusted public key rather than
  580                    * trusted certs, then add this cert (which is signed by
  581                    * the trusted public key) to the certPathList
  582                    */
  583                   if (builder.trustAnchor.getTrustedCert() == null)
  584                       builder.addCertToPath(cert, certPathList);
  585                   // Save the trust anchor
  586                   this.trustAnchor = builder.trustAnchor;
  587   
  588                   /*
  589                    * Extract and save the final target public key
  590                    */
  591                   if (basicChecker != null) {
  592                       finalPublicKey = basicChecker.getPublicKey();
  593                   } else {
  594                       Certificate finalCert;
  595                       if (certPathList.size() == 0) {
  596                           finalCert = builder.trustAnchor.getTrustedCert();
  597                       } else {
  598                           finalCert = certPathList.get(certPathList.size()-1);
  599                       }
  600                       finalPublicKey = finalCert.getPublicKey();
  601                   }
  602   
  603                   policyTreeResult = policyChecker.getPolicyTree();
  604                   return;
  605               } else {
  606                   builder.addCertToPath(cert, certPathList);
  607               }
  608   
  609               /* Update the PKIX state */
  610               nextState.updateState(cert);
  611   
  612               /*
  613                * Append an entry for cert in adjacency list and
  614                * set index for current vertex.
  615                */
  616               adjList.add(new LinkedList<Vertex>());
  617               vertex.setIndex(adjList.size() - 1);
  618   
  619               /* recursively search for matching certs at next dN */
  620               depthFirstSearchForward(cert.getIssuerX500Principal(), nextState, builder,
  621                   adjList, certPathList);
  622   
  623               /*
  624                * If path has been completed, return ASAP!
  625                */
  626               if (pathCompleted) {
  627                   return;
  628               } else {
  629                   /*
  630                    * If we get here, it means we have searched all possible
  631                    * certs issued by the dN w/o finding any matching certs.
  632                    * This means we have to backtrack to the previous cert in
  633                    * the path and try some other paths.
  634                    */
  635                   if (debug != null)
  636                       debug.println("SunCertPathBuilder.depthFirstSearchForward()"
  637                           + ": backtracking");
  638                   builder.removeFinalCertFromPath(certPathList);
  639               }
  640           }
  641       }
  642   
  643       /*
  644        * This method performs a depth first search for a certification
  645        * path while building reverse which meets the requirements set in
  646        * the parameters object.
  647        * It uses an adjacency list to store all certificates which were
  648        * tried (i.e. at one time added to the path - they may not end up in
  649        * the final path if backtracking occurs). This information can
  650        * be used later to debug or demo the build.
  651        *
  652        * See "Data Structure and Algorithms, by Aho, Hopcroft, and Ullman"
  653        * for an explanation of the DFS algorithm.
  654        *
  655        * @param dN the distinguished name being currently searched for certs
  656        * @param currentState the current PKIX validation state
  657        */
  658       void depthFirstSearchReverse(X500Principal dN, ReverseState currentState,
  659           ReverseBuilder builder, List<List<Vertex>> adjList,
  660           LinkedList<X509Certificate> certPathList)
  661           throws GeneralSecurityException, IOException
  662       {
  663           if (debug != null)
  664               debug.println("SunCertPathBuilder.depthFirstSearchReverse(" + dN
  665                   + ", " + currentState.toString() + ")");
  666   
  667           /*
  668            * Find all the certificates issued by dN which
  669            * satisfy the PKIX certification path constraints.
  670            */
  671           List<Vertex> vertices = addVertices
  672              (builder.getMatchingCerts(currentState, orderedCertStores), adjList);
  673           if (debug != null)
  674               debug.println("SunCertPathBuilder.depthFirstSearchReverse(): "
  675                   + "certs.size=" + vertices.size());
  676   
  677           /*
  678            * For each cert in the collection, verify anything
  679            * that hasn't been checked yet (signature, revocation, etc)
  680            * and check for loops. Call depthFirstSearchReverse()
  681            * recursively for each good cert.
  682            */
  683           for (Vertex vertex : vertices) {
  684               /**
  685                * Restore state to currentState each time through the loop.
  686                * This is important because some of the user-defined
  687                * checkers modify the state, which MUST be restored if
  688                * the cert eventually fails to lead to the target and
  689                * the next matching cert is tried.
  690                */
  691               ReverseState nextState = (ReverseState) currentState.clone();
  692               X509Certificate cert = (X509Certificate) vertex.getCertificate();
  693               try {
  694                   builder.verifyCert(cert, nextState, certPathList);
  695               } catch (GeneralSecurityException gse) {
  696                   if (debug != null)
  697                       debug.println("SunCertPathBuilder.depthFirstSearchReverse()"
  698                           + ": validation failed: " + gse);
  699                   vertex.setThrowable(gse);
  700                   continue;
  701               }
  702   
  703               /*
  704                * Certificate is good, add it to the path (if it isn't a
  705                * self-signed cert) and update state
  706                */
  707               if (!currentState.isInitial())
  708                   builder.addCertToPath(cert, certPathList);
  709               // save trust anchor
  710               this.trustAnchor = currentState.trustAnchor;
  711   
  712               /*
  713                * Check if path is completed, return ASAP if so.
  714                */
  715               if (builder.isPathCompleted(cert)) {
  716                   if (debug != null)
  717                       debug.println("SunCertPathBuilder.depthFirstSearchReverse()"
  718                           + ": path completed!");
  719                   pathCompleted = true;
  720   
  721                   PolicyNodeImpl rootNode = nextState.rootNode;
  722   
  723                   if (rootNode == null)
  724                       policyTreeResult = null;
  725                   else {
  726                       policyTreeResult = rootNode.copyTree();
  727                       ((PolicyNodeImpl)policyTreeResult).setImmutable();
  728                   }
  729   
  730                   /*
  731                    * Extract and save the final target public key
  732                    */
  733                   finalPublicKey = cert.getPublicKey();
  734                   if (finalPublicKey instanceof DSAPublicKey &&
  735                       ((DSAPublicKey)finalPublicKey).getParams() == null)
  736                   {
  737                       finalPublicKey =
  738                           BasicChecker.makeInheritedParamsKey
  739                               (finalPublicKey, currentState.pubKey);
  740                   }
  741   
  742                   return;
  743               }
  744   
  745               /* Update the PKIX state */
  746               nextState.updateState(cert);
  747   
  748               /*
  749                * Append an entry for cert in adjacency list and
  750                * set index for current vertex.
  751                */
  752               adjList.add(new LinkedList<Vertex>());
  753               vertex.setIndex(adjList.size() - 1);
  754   
  755               /* recursively search for matching certs at next dN */
  756               depthFirstSearchReverse(cert.getSubjectX500Principal(), nextState,
  757                   builder, adjList, certPathList);
  758   
  759               /*
  760                * If path has been completed, return ASAP!
  761                */
  762               if (pathCompleted) {
  763                   return;
  764               } else {
  765                   /*
  766                    * If we get here, it means we have searched all possible
  767                    * certs issued by the dN w/o finding any matching certs. This
  768                    * means we have to backtrack to the previous cert in the path
  769                    * and try some other paths.
  770                    */
  771                   if (debug != null)
  772                       debug.println("SunCertPathBuilder.depthFirstSearchReverse()"
  773                           + ": backtracking");
  774                   if (!currentState.isInitial())
  775                       builder.removeFinalCertFromPath(certPathList);
  776               }
  777           }
  778           if (debug != null)
  779               debug.println("SunCertPathBuilder.depthFirstSearchReverse() all "
  780                   + "certs in this adjacency list checked");
  781       }
  782   
  783       /*
  784        * Adds a collection of matching certificates to the
  785        * adjacency list.
  786        */
  787       private List<Vertex> addVertices(Collection<X509Certificate> certs,
  788           List<List<Vertex>> adjList) {
  789           List<Vertex> l = adjList.get(adjList.size() - 1);
  790   
  791           for (X509Certificate cert : certs) {
  792              Vertex v = new Vertex(cert);
  793              l.add(v);
  794           }
  795   
  796           return l;
  797       }
  798   
  799       /**
  800        * Returns true if trust anchor certificate matches specified
  801        * certificate constraints.
  802        */
  803       private boolean anchorIsTarget(TrustAnchor anchor, X509CertSelector sel) {
  804           X509Certificate anchorCert = anchor.getTrustedCert();
  805           if (anchorCert != null) {
  806               return sel.match(anchorCert);
  807           }
  808           return false;
  809       }
  810   
  811       /**
  812        * Comparator that orders CertStores so that local CertStores come before
  813        * remote CertStores.
  814        */
  815       private static class CertStoreComparator implements Comparator<CertStore> {
  816           public int compare(CertStore store1, CertStore store2) {
  817               if (Builder.isLocalCertStore(store1)) {
  818                   return -1;
  819               } else {
  820                   return 1;
  821               }
  822           }
  823       }
  824   
  825       /**
  826        * Returns the target subject DN from the first X509Certificate that
  827        * is fetched that matches the specified X509CertSelector.
  828        */
  829       private X500Principal getTargetSubjectDN(List<CertStore> stores,
  830           X509CertSelector targetSel) {
  831           for (CertStore store : stores) {
  832               try {
  833                   Collection<? extends Certificate> targetCerts =
  834                       (Collection<? extends Certificate>)
  835                           store.getCertificates(targetSel);
  836                   if (!targetCerts.isEmpty()) {
  837                       X509Certificate targetCert =
  838                           (X509Certificate)targetCerts.iterator().next();
  839                       return targetCert.getSubjectX500Principal();
  840                   }
  841               } catch (CertStoreException e) {
  842                   // ignore but log it
  843                   if (debug != null) {
  844                       debug.println("SunCertPathBuilder.getTargetSubjectDN: " +
  845                           "non-fatal exception retrieving certs: " + e);
  846                       e.printStackTrace();
  847                   }
  848               }
  849           }
  850           return null;
  851       }
  852   }

Save This Page
Home » openjdk-7 » sun.security » provider » certpath » [javadoc | source]