jdk/src/share/classes/sun/security/provider/certpath/PKIXMasterCertPathValidator.java
changeset 2 90ce3da70b43
child 1238 6d1f4b722acd
equal deleted inserted replaced
0:fd16c54261b3 2:90ce3da70b43
       
     1 /*
       
     2  * Copyright 2000-2006 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 sun.security.util.Debug;
       
    29 
       
    30 import java.util.Collections;
       
    31 import java.util.List;
       
    32 import java.util.Set;
       
    33 import java.util.Iterator;
       
    34 import java.security.cert.CertPath;
       
    35 import java.security.cert.CertPathValidatorException;
       
    36 import java.security.cert.CertificateRevokedException;
       
    37 import java.security.cert.PKIXCertPathChecker;
       
    38 import java.security.cert.X509Certificate;
       
    39 
       
    40 /**
       
    41  * This class is initialized with a list of <code>PKIXCertPathChecker</code>s
       
    42  * and is used to verify the certificates in a <code>CertPath</code> by
       
    43  * feeding each certificate to each <code>PKIXCertPathChecker</code>.
       
    44  *
       
    45  * @since       1.4
       
    46  * @author      Yassir Elley
       
    47  */
       
    48 class PKIXMasterCertPathValidator {
       
    49 
       
    50     private static final Debug debug = Debug.getInstance("certpath");
       
    51     private List<PKIXCertPathChecker> certPathCheckers;
       
    52 
       
    53     /**
       
    54      * Initializes the list of PKIXCertPathCheckers whose checks
       
    55      * will be performed on each certificate in the certpath.
       
    56      *
       
    57      * @param certPathCheckers a List of checkers to use
       
    58      */
       
    59     PKIXMasterCertPathValidator(List<PKIXCertPathChecker> certPathCheckers) {
       
    60         this.certPathCheckers = certPathCheckers;
       
    61     }
       
    62 
       
    63     /**
       
    64      * Validates a certification path consisting exclusively of
       
    65      * <code>X509Certificate</code>s using the
       
    66      * <code>PKIXCertPathChecker</code>s specified
       
    67      * in the constructor. It is assumed that the
       
    68      * <code>PKIXCertPathChecker</code>s
       
    69      * have been initialized with any input parameters they may need.
       
    70      *
       
    71      * @param cpOriginal the original X509 CertPath passed in by the user
       
    72      * @param reversedCertList the reversed X509 CertPath (as a List)
       
    73      * @exception CertPathValidatorException Exception thrown if cert
       
    74      * path does not validate.
       
    75      */
       
    76     void validate(CertPath cpOriginal, List<X509Certificate> reversedCertList)
       
    77         throws CertPathValidatorException
       
    78     {
       
    79         // we actually process reversedCertList, but we keep cpOriginal because
       
    80         // we need to return the original certPath when we throw an exception.
       
    81         // we will also need to modify the index appropriately when we
       
    82         // throw an exception.
       
    83 
       
    84         int cpSize = reversedCertList.size();
       
    85 
       
    86         if (debug != null) {
       
    87             debug.println("--------------------------------------------------"
       
    88                   + "------------");
       
    89             debug.println("Executing PKIX certification path validation "
       
    90                   + "algorithm.");
       
    91         }
       
    92 
       
    93         for (int i = 0; i < cpSize; i++) {
       
    94 
       
    95             /* The basic loop algorithm is that we get the
       
    96              * current certificate, we verify the current certificate using
       
    97              * information from the previous certificate and from the state,
       
    98              * and we modify the state for the next loop by setting the
       
    99              * current certificate of this loop to be the previous certificate
       
   100              * of the next loop. The state is initialized during first loop.
       
   101              */
       
   102             if (debug != null)
       
   103                 debug.println("Checking cert" + (i+1) + " ...");
       
   104 
       
   105             X509Certificate currCert = reversedCertList.get(i);
       
   106             Set<String> unresolvedCritExts =
       
   107                                         currCert.getCriticalExtensionOIDs();
       
   108             if (unresolvedCritExts == null) {
       
   109                 unresolvedCritExts = Collections.<String>emptySet();
       
   110             }
       
   111 
       
   112             if (debug != null && !unresolvedCritExts.isEmpty()) {
       
   113                 debug.println("Set of critical extensions:");
       
   114                 for (String oid : unresolvedCritExts) {
       
   115                     debug.println(oid);
       
   116                 }
       
   117             }
       
   118 
       
   119             CertPathValidatorException ocspCause = null;
       
   120             for (int j = 0; j < certPathCheckers.size(); j++) {
       
   121 
       
   122                 PKIXCertPathChecker currChecker = certPathCheckers.get(j);
       
   123                 if (debug != null) {
       
   124                     debug.println("-Using checker" + (j + 1) + " ... [" +
       
   125                         currChecker.getClass().getName() + "]");
       
   126                 }
       
   127 
       
   128                 if (i == 0)
       
   129                     currChecker.init(false);
       
   130 
       
   131                 try {
       
   132                     currChecker.check(currCert, unresolvedCritExts);
       
   133 
       
   134                     // OCSP has validated the cert so skip the CRL check
       
   135                     if (isRevocationCheck(currChecker, j, certPathCheckers)) {
       
   136                         if (debug != null) {
       
   137                             debug.println("-checker" + (j + 1) +
       
   138                                 " validation succeeded");
       
   139                         }
       
   140                         j++;
       
   141                         continue; // skip
       
   142                     }
       
   143 
       
   144                 } catch (CertPathValidatorException cpve) {
       
   145                     // Throw the saved OCSP exception
       
   146                     // (when the CRL check has also failed)
       
   147                     if (ocspCause != null &&
       
   148                         currChecker instanceof CrlRevocationChecker) {
       
   149                         throw ocspCause;
       
   150                     }
       
   151                     /*
       
   152                      * Handle failover from OCSP to CRLs
       
   153                      */
       
   154                     CertPathValidatorException currentCause =
       
   155                         new CertPathValidatorException(cpve.getMessage(),
       
   156                             cpve.getCause(), cpOriginal, cpSize - (i + 1));
       
   157 
       
   158                     // Check if OCSP has confirmed that the cert was revoked
       
   159                     if (cpve.getCause() instanceof CertificateRevokedException) {
       
   160                         throw currentCause;
       
   161                     }
       
   162                     // Check if it is appropriate to failover
       
   163                     if (! isRevocationCheck(currChecker, j, certPathCheckers)) {
       
   164                         // no failover
       
   165                         throw currentCause;
       
   166                     }
       
   167                     // Save the current exception
       
   168                     // (in case the CRL check also fails)
       
   169                     ocspCause = currentCause;
       
   170 
       
   171                     // Otherwise, failover to CRLs
       
   172                     if (debug != null) {
       
   173                         debug.println(cpve.getMessage());
       
   174                         debug.println(
       
   175                             "preparing to failover (from OCSP to CRLs)");
       
   176                     }
       
   177                 }
       
   178 
       
   179                 if (debug != null)
       
   180                     debug.println("-checker" + (j+1) + " validation succeeded");
       
   181             }
       
   182 
       
   183             if (debug != null)
       
   184                 debug.println("checking for unresolvedCritExts");
       
   185             if (!unresolvedCritExts.isEmpty()) {
       
   186                 throw new CertPathValidatorException("unrecognized " +
       
   187                     "critical extension(s)", null, cpOriginal, cpSize-(i+1));
       
   188             }
       
   189 
       
   190             if (debug != null)
       
   191                 debug.println("\ncert" + (i+1) + " validation succeeded.\n");
       
   192         }
       
   193 
       
   194         if (debug != null) {
       
   195             debug.println("Cert path validation succeeded. (PKIX validation "
       
   196                     + "algorithm)");
       
   197             debug.println("-------------------------------------------------"
       
   198                     + "-------------");
       
   199         }
       
   200     }
       
   201 
       
   202     /*
       
   203      * Examines the list of PKIX cert path checkers to determine whether
       
   204      * both the current checker and the next checker are revocation checkers.
       
   205      * OCSPChecker and CrlRevocationChecker are both revocation checkers.
       
   206      */
       
   207     private static boolean isRevocationCheck(PKIXCertPathChecker checker,
       
   208         int index, List<PKIXCertPathChecker> checkers) {
       
   209 
       
   210         if (checker instanceof OCSPChecker && index + 1 < checkers.size()) {
       
   211             PKIXCertPathChecker nextChecker = checkers.get(index + 1);
       
   212             if (nextChecker instanceof CrlRevocationChecker) {
       
   213                 return true;
       
   214             }
       
   215         }
       
   216         return false;
       
   217     }
       
   218 }