jdk/src/share/classes/sun/security/provider/certpath/PKIXMasterCertPathValidator.java
changeset 12860 9ffbd4e43413
parent 5506 202f599c92aa
equal deleted inserted replaced
11673:5fe35861f07e 12860:9ffbd4e43413
     1 /*
     1 /*
     2  * Copyright (c) 2000, 2009, Oracle and/or its affiliates. All rights reserved.
     2  * Copyright (c) 2000, 2012, Oracle and/or its affiliates. All rights reserved.
     3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
     3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
     4  *
     4  *
     5  * This code is free software; you can redistribute it and/or modify it
     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
     6  * under the terms of the GNU General Public License version 2 only, as
     7  * published by the Free Software Foundation.  Oracle designates this
     7  * published by the Free Software Foundation.  Oracle designates this
    28 import sun.security.util.Debug;
    28 import sun.security.util.Debug;
    29 
    29 
    30 import java.util.Collections;
    30 import java.util.Collections;
    31 import java.util.List;
    31 import java.util.List;
    32 import java.util.Set;
    32 import java.util.Set;
    33 import java.security.cert.CertificateRevokedException;
       
    34 import java.security.cert.CertPath;
    33 import java.security.cert.CertPath;
    35 import java.security.cert.CertPathValidatorException;
    34 import java.security.cert.CertPathValidatorException;
    36 import java.security.cert.CertPathValidatorException.BasicReason;
       
    37 import java.security.cert.PKIXCertPathChecker;
    35 import java.security.cert.PKIXCertPathChecker;
    38 import java.security.cert.PKIXReason;
    36 import java.security.cert.PKIXReason;
    39 import java.security.cert.X509Certificate;
    37 import java.security.cert.X509Certificate;
    40 
    38 
    41 /**
    39 /**
    47  * @author      Yassir Elley
    45  * @author      Yassir Elley
    48  */
    46  */
    49 class PKIXMasterCertPathValidator {
    47 class PKIXMasterCertPathValidator {
    50 
    48 
    51     private static final Debug debug = Debug.getInstance("certpath");
    49     private static final Debug debug = Debug.getInstance("certpath");
    52     private List<PKIXCertPathChecker> certPathCheckers;
       
    53 
       
    54     /**
       
    55      * Initializes the list of PKIXCertPathCheckers whose checks
       
    56      * will be performed on each certificate in the certpath.
       
    57      *
       
    58      * @param certPathCheckers a List of checkers to use
       
    59      */
       
    60     PKIXMasterCertPathValidator(List<PKIXCertPathChecker> certPathCheckers) {
       
    61         this.certPathCheckers = certPathCheckers;
       
    62     }
       
    63 
    50 
    64     /**
    51     /**
    65      * Validates a certification path consisting exclusively of
    52      * Validates a certification path consisting exclusively of
    66      * <code>X509Certificate</code>s using the
    53      * <code>X509Certificate</code>s using the specified
    67      * <code>PKIXCertPathChecker</code>s specified
    54      * <code>PKIXCertPathChecker</code>s. It is assumed that the
    68      * in the constructor. It is assumed that the
       
    69      * <code>PKIXCertPathChecker</code>s
    55      * <code>PKIXCertPathChecker</code>s
    70      * have been initialized with any input parameters they may need.
    56      * have been initialized with any input parameters they may need.
    71      *
    57      *
    72      * @param cpOriginal the original X509 CertPath passed in by the user
    58      * @param cpOriginal the original X509 CertPath passed in by the user
    73      * @param reversedCertList the reversed X509 CertPath (as a List)
    59      * @param reversedCertList the reversed X509 CertPath (as a List)
    74      * @exception CertPathValidatorException Exception thrown if cert
    60      * @param certPathCheckers the PKIXCertPathCheckers
    75      * path does not validate.
    61      * @throws CertPathValidatorException if cert path does not validate
    76      */
    62      */
    77     void validate(CertPath cpOriginal, List<X509Certificate> reversedCertList)
    63     static void validate(CertPath cpOriginal,
       
    64                          List<X509Certificate> reversedCertList,
       
    65                          List<PKIXCertPathChecker> certPathCheckers)
    78         throws CertPathValidatorException
    66         throws CertPathValidatorException
    79     {
    67     {
    80         // we actually process reversedCertList, but we keep cpOriginal because
    68         // we actually process reversedCertList, but we keep cpOriginal because
    81         // we need to return the original certPath when we throw an exception.
    69         // we need to return the original certPath when we throw an exception.
    82         // we will also need to modify the index appropriately when we
    70         // we will also need to modify the index appropriately when we
   102              */
    90              */
   103             if (debug != null)
    91             if (debug != null)
   104                 debug.println("Checking cert" + (i+1) + " ...");
    92                 debug.println("Checking cert" + (i+1) + " ...");
   105 
    93 
   106             X509Certificate currCert = reversedCertList.get(i);
    94             X509Certificate currCert = reversedCertList.get(i);
   107             Set<String> unresolvedCritExts =
    95             Set<String> unresCritExts = currCert.getCriticalExtensionOIDs();
   108                                         currCert.getCriticalExtensionOIDs();
    96             if (unresCritExts == null) {
   109             if (unresolvedCritExts == null) {
    97                 unresCritExts = Collections.<String>emptySet();
   110                 unresolvedCritExts = Collections.<String>emptySet();
       
   111             }
    98             }
   112 
    99 
   113             if (debug != null && !unresolvedCritExts.isEmpty()) {
   100             if (debug != null && !unresCritExts.isEmpty()) {
   114                 debug.println("Set of critical extensions:");
   101                 debug.println("Set of critical extensions:");
   115                 for (String oid : unresolvedCritExts) {
   102                 for (String oid : unresCritExts) {
   116                     debug.println(oid);
   103                     debug.println(oid);
   117                 }
   104                 }
   118             }
   105             }
   119 
   106 
   120             CertPathValidatorException ocspCause = null;
       
   121             for (int j = 0; j < certPathCheckers.size(); j++) {
   107             for (int j = 0; j < certPathCheckers.size(); j++) {
   122 
   108 
   123                 PKIXCertPathChecker currChecker = certPathCheckers.get(j);
   109                 PKIXCertPathChecker currChecker = certPathCheckers.get(j);
   124                 if (debug != null) {
   110                 if (debug != null) {
   125                     debug.println("-Using checker" + (j + 1) + " ... [" +
   111                     debug.println("-Using checker" + (j + 1) + " ... [" +
   128 
   114 
   129                 if (i == 0)
   115                 if (i == 0)
   130                     currChecker.init(false);
   116                     currChecker.init(false);
   131 
   117 
   132                 try {
   118                 try {
   133                     currChecker.check(currCert, unresolvedCritExts);
   119                     currChecker.check(currCert, unresCritExts);
   134 
   120 
   135                     // OCSP has validated the cert so skip the CRL check
   121                     if (debug != null) {
   136                     if (isRevocationCheck(currChecker, j, certPathCheckers)) {
   122                         debug.println("-checker" + (j + 1) +
   137                         if (debug != null) {
   123                             " validation succeeded");
   138                             debug.println("-checker" + (j + 1) +
       
   139                                 " validation succeeded");
       
   140                         }
       
   141                         j++;
       
   142                         continue; // skip
       
   143                     }
   124                     }
   144 
   125 
   145                 } catch (CertPathValidatorException cpve) {
   126                 } catch (CertPathValidatorException cpve) {
   146                     // Throw the saved OCSP exception unless the CRL
   127                     throw new CertPathValidatorException(cpve.getMessage(),
   147                     // checker has determined that the cert is revoked
   128                         cpve.getCause(), cpOriginal, cpSize - (i + 1),
   148                     if (ocspCause != null &&
   129                         cpve.getReason());
   149                             currChecker instanceof CrlRevocationChecker) {
       
   150                         if (cpve.getReason() == BasicReason.REVOKED) {
       
   151                             throw cpve;
       
   152                         } else {
       
   153                             throw ocspCause;
       
   154                         }
       
   155                     }
       
   156                     /*
       
   157                      * Handle failover from OCSP to CRLs
       
   158                      */
       
   159                     CertPathValidatorException currentCause =
       
   160                         new CertPathValidatorException(cpve.getMessage(),
       
   161                             cpve.getCause(), cpOriginal, cpSize - (i + 1),
       
   162                             cpve.getReason());
       
   163 
       
   164                     // Check if OCSP has confirmed that the cert was revoked
       
   165                     if (cpve.getReason() == BasicReason.REVOKED) {
       
   166                         throw currentCause;
       
   167                     }
       
   168                     // Check if it is appropriate to failover
       
   169                     if (! isRevocationCheck(currChecker, j, certPathCheckers)) {
       
   170                         // no failover
       
   171                         throw currentCause;
       
   172                     }
       
   173                     // Save the current exception
       
   174                     // (in case the CRL check also fails)
       
   175                     ocspCause = currentCause;
       
   176 
       
   177                     // Otherwise, failover to CRLs
       
   178                     if (debug != null) {
       
   179                         debug.println(cpve.getMessage());
       
   180                         debug.println(
       
   181                             "preparing to failover (from OCSP to CRLs)");
       
   182                     }
       
   183                 }
   130                 }
   184 
       
   185                 if (debug != null)
       
   186                     debug.println("-checker" + (j+1) + " validation succeeded");
       
   187             }
   131             }
   188 
   132 
   189             if (debug != null)
   133             if (!unresCritExts.isEmpty()) {
   190                 debug.println("checking for unresolvedCritExts");
       
   191             if (!unresolvedCritExts.isEmpty()) {
       
   192                 throw new CertPathValidatorException("unrecognized " +
   134                 throw new CertPathValidatorException("unrecognized " +
   193                     "critical extension(s)", null, cpOriginal, cpSize-(i+1),
   135                     "critical extension(s)", null, cpOriginal, cpSize-(i+1),
   194                     PKIXReason.UNRECOGNIZED_CRIT_EXT);
   136                     PKIXReason.UNRECOGNIZED_CRIT_EXT);
   195             }
   137             }
   196 
   138 
   198                 debug.println("\ncert" + (i+1) + " validation succeeded.\n");
   140                 debug.println("\ncert" + (i+1) + " validation succeeded.\n");
   199         }
   141         }
   200 
   142 
   201         if (debug != null) {
   143         if (debug != null) {
   202             debug.println("Cert path validation succeeded. (PKIX validation "
   144             debug.println("Cert path validation succeeded. (PKIX validation "
   203                     + "algorithm)");
   145                           + "algorithm)");
   204             debug.println("-------------------------------------------------"
   146             debug.println("-------------------------------------------------"
   205                     + "-------------");
   147                           + "-------------");
   206         }
   148         }
   207     }
   149     }
   208 
       
   209     /*
       
   210      * Examines the list of PKIX cert path checkers to determine whether
       
   211      * both the current checker and the next checker are revocation checkers.
       
   212      * OCSPChecker and CrlRevocationChecker are both revocation checkers.
       
   213      */
       
   214     private static boolean isRevocationCheck(PKIXCertPathChecker checker,
       
   215         int index, List<PKIXCertPathChecker> checkers) {
       
   216 
       
   217         if (checker instanceof OCSPChecker && index + 1 < checkers.size()) {
       
   218             PKIXCertPathChecker nextChecker = checkers.get(index + 1);
       
   219             if (nextChecker instanceof CrlRevocationChecker) {
       
   220                 return true;
       
   221             }
       
   222         }
       
   223         return false;
       
   224     }
       
   225 }
   150 }