jdk/src/share/classes/sun/security/provider/certpath/PKIXMasterCertPathValidator.java
author mullan
Thu, 11 Sep 2008 14:05:16 -0400
changeset 1238 6d1f4b722acd
parent 2 90ce3da70b43
child 2283 495fbbcc7569
permissions -rw-r--r--
6465942: Add problem identification facility to the CertPathValidator framework Summary: Add support to the java.security.cert APIs for determining the reason that a certification path is invalid. Reviewed-by: vinnie
Ignore whitespace changes - Everywhere: Within whitespace: At end of lines:
2
90ce3da70b43 Initial load
duke
parents:
diff changeset
     1
/*
1238
6d1f4b722acd 6465942: Add problem identification facility to the CertPathValidator framework
mullan
parents: 2
diff changeset
     2
 * Copyright 2000-2008 Sun Microsystems, Inc.  All Rights Reserved.
2
90ce3da70b43 Initial load
duke
parents:
diff changeset
     3
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
90ce3da70b43 Initial load
duke
parents:
diff changeset
     4
 *
90ce3da70b43 Initial load
duke
parents:
diff changeset
     5
 * This code is free software; you can redistribute it and/or modify it
90ce3da70b43 Initial load
duke
parents:
diff changeset
     6
 * under the terms of the GNU General Public License version 2 only, as
90ce3da70b43 Initial load
duke
parents:
diff changeset
     7
 * published by the Free Software Foundation.  Sun designates this
90ce3da70b43 Initial load
duke
parents:
diff changeset
     8
 * particular file as subject to the "Classpath" exception as provided
90ce3da70b43 Initial load
duke
parents:
diff changeset
     9
 * by Sun in the LICENSE file that accompanied this code.
90ce3da70b43 Initial load
duke
parents:
diff changeset
    10
 *
90ce3da70b43 Initial load
duke
parents:
diff changeset
    11
 * This code is distributed in the hope that it will be useful, but WITHOUT
90ce3da70b43 Initial load
duke
parents:
diff changeset
    12
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
90ce3da70b43 Initial load
duke
parents:
diff changeset
    13
 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
90ce3da70b43 Initial load
duke
parents:
diff changeset
    14
 * version 2 for more details (a copy is included in the LICENSE file that
90ce3da70b43 Initial load
duke
parents:
diff changeset
    15
 * accompanied this code).
90ce3da70b43 Initial load
duke
parents:
diff changeset
    16
 *
90ce3da70b43 Initial load
duke
parents:
diff changeset
    17
 * You should have received a copy of the GNU General Public License version
90ce3da70b43 Initial load
duke
parents:
diff changeset
    18
 * 2 along with this work; if not, write to the Free Software Foundation,
90ce3da70b43 Initial load
duke
parents:
diff changeset
    19
 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
90ce3da70b43 Initial load
duke
parents:
diff changeset
    20
 *
90ce3da70b43 Initial load
duke
parents:
diff changeset
    21
 * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
90ce3da70b43 Initial load
duke
parents:
diff changeset
    22
 * CA 95054 USA or visit www.sun.com if you need additional information or
90ce3da70b43 Initial load
duke
parents:
diff changeset
    23
 * have any questions.
90ce3da70b43 Initial load
duke
parents:
diff changeset
    24
 */
90ce3da70b43 Initial load
duke
parents:
diff changeset
    25
90ce3da70b43 Initial load
duke
parents:
diff changeset
    26
package sun.security.provider.certpath;
90ce3da70b43 Initial load
duke
parents:
diff changeset
    27
90ce3da70b43 Initial load
duke
parents:
diff changeset
    28
import sun.security.util.Debug;
90ce3da70b43 Initial load
duke
parents:
diff changeset
    29
90ce3da70b43 Initial load
duke
parents:
diff changeset
    30
import java.util.Collections;
90ce3da70b43 Initial load
duke
parents:
diff changeset
    31
import java.util.List;
90ce3da70b43 Initial load
duke
parents:
diff changeset
    32
import java.util.Set;
1238
6d1f4b722acd 6465942: Add problem identification facility to the CertPathValidator framework
mullan
parents: 2
diff changeset
    33
import java.security.cert.CertificateRevokedException;
2
90ce3da70b43 Initial load
duke
parents:
diff changeset
    34
import java.security.cert.CertPath;
90ce3da70b43 Initial load
duke
parents:
diff changeset
    35
import java.security.cert.CertPathValidatorException;
1238
6d1f4b722acd 6465942: Add problem identification facility to the CertPathValidator framework
mullan
parents: 2
diff changeset
    36
import java.security.cert.CertPathValidatorException.BasicReason;
2
90ce3da70b43 Initial load
duke
parents:
diff changeset
    37
import java.security.cert.PKIXCertPathChecker;
1238
6d1f4b722acd 6465942: Add problem identification facility to the CertPathValidator framework
mullan
parents: 2
diff changeset
    38
import java.security.cert.PKIXReason;
2
90ce3da70b43 Initial load
duke
parents:
diff changeset
    39
import java.security.cert.X509Certificate;
90ce3da70b43 Initial load
duke
parents:
diff changeset
    40
90ce3da70b43 Initial load
duke
parents:
diff changeset
    41
/**
90ce3da70b43 Initial load
duke
parents:
diff changeset
    42
 * This class is initialized with a list of <code>PKIXCertPathChecker</code>s
90ce3da70b43 Initial load
duke
parents:
diff changeset
    43
 * and is used to verify the certificates in a <code>CertPath</code> by
90ce3da70b43 Initial load
duke
parents:
diff changeset
    44
 * feeding each certificate to each <code>PKIXCertPathChecker</code>.
90ce3da70b43 Initial load
duke
parents:
diff changeset
    45
 *
90ce3da70b43 Initial load
duke
parents:
diff changeset
    46
 * @since       1.4
90ce3da70b43 Initial load
duke
parents:
diff changeset
    47
 * @author      Yassir Elley
90ce3da70b43 Initial load
duke
parents:
diff changeset
    48
 */
90ce3da70b43 Initial load
duke
parents:
diff changeset
    49
class PKIXMasterCertPathValidator {
90ce3da70b43 Initial load
duke
parents:
diff changeset
    50
90ce3da70b43 Initial load
duke
parents:
diff changeset
    51
    private static final Debug debug = Debug.getInstance("certpath");
90ce3da70b43 Initial load
duke
parents:
diff changeset
    52
    private List<PKIXCertPathChecker> certPathCheckers;
90ce3da70b43 Initial load
duke
parents:
diff changeset
    53
90ce3da70b43 Initial load
duke
parents:
diff changeset
    54
    /**
90ce3da70b43 Initial load
duke
parents:
diff changeset
    55
     * Initializes the list of PKIXCertPathCheckers whose checks
90ce3da70b43 Initial load
duke
parents:
diff changeset
    56
     * will be performed on each certificate in the certpath.
90ce3da70b43 Initial load
duke
parents:
diff changeset
    57
     *
90ce3da70b43 Initial load
duke
parents:
diff changeset
    58
     * @param certPathCheckers a List of checkers to use
90ce3da70b43 Initial load
duke
parents:
diff changeset
    59
     */
90ce3da70b43 Initial load
duke
parents:
diff changeset
    60
    PKIXMasterCertPathValidator(List<PKIXCertPathChecker> certPathCheckers) {
90ce3da70b43 Initial load
duke
parents:
diff changeset
    61
        this.certPathCheckers = certPathCheckers;
90ce3da70b43 Initial load
duke
parents:
diff changeset
    62
    }
90ce3da70b43 Initial load
duke
parents:
diff changeset
    63
90ce3da70b43 Initial load
duke
parents:
diff changeset
    64
    /**
90ce3da70b43 Initial load
duke
parents:
diff changeset
    65
     * Validates a certification path consisting exclusively of
90ce3da70b43 Initial load
duke
parents:
diff changeset
    66
     * <code>X509Certificate</code>s using the
90ce3da70b43 Initial load
duke
parents:
diff changeset
    67
     * <code>PKIXCertPathChecker</code>s specified
90ce3da70b43 Initial load
duke
parents:
diff changeset
    68
     * in the constructor. It is assumed that the
90ce3da70b43 Initial load
duke
parents:
diff changeset
    69
     * <code>PKIXCertPathChecker</code>s
90ce3da70b43 Initial load
duke
parents:
diff changeset
    70
     * have been initialized with any input parameters they may need.
90ce3da70b43 Initial load
duke
parents:
diff changeset
    71
     *
90ce3da70b43 Initial load
duke
parents:
diff changeset
    72
     * @param cpOriginal the original X509 CertPath passed in by the user
90ce3da70b43 Initial load
duke
parents:
diff changeset
    73
     * @param reversedCertList the reversed X509 CertPath (as a List)
90ce3da70b43 Initial load
duke
parents:
diff changeset
    74
     * @exception CertPathValidatorException Exception thrown if cert
90ce3da70b43 Initial load
duke
parents:
diff changeset
    75
     * path does not validate.
90ce3da70b43 Initial load
duke
parents:
diff changeset
    76
     */
90ce3da70b43 Initial load
duke
parents:
diff changeset
    77
    void validate(CertPath cpOriginal, List<X509Certificate> reversedCertList)
90ce3da70b43 Initial load
duke
parents:
diff changeset
    78
        throws CertPathValidatorException
90ce3da70b43 Initial load
duke
parents:
diff changeset
    79
    {
90ce3da70b43 Initial load
duke
parents:
diff changeset
    80
        // we actually process reversedCertList, but we keep cpOriginal because
90ce3da70b43 Initial load
duke
parents:
diff changeset
    81
        // we need to return the original certPath when we throw an exception.
90ce3da70b43 Initial load
duke
parents:
diff changeset
    82
        // we will also need to modify the index appropriately when we
90ce3da70b43 Initial load
duke
parents:
diff changeset
    83
        // throw an exception.
90ce3da70b43 Initial load
duke
parents:
diff changeset
    84
90ce3da70b43 Initial load
duke
parents:
diff changeset
    85
        int cpSize = reversedCertList.size();
90ce3da70b43 Initial load
duke
parents:
diff changeset
    86
90ce3da70b43 Initial load
duke
parents:
diff changeset
    87
        if (debug != null) {
90ce3da70b43 Initial load
duke
parents:
diff changeset
    88
            debug.println("--------------------------------------------------"
90ce3da70b43 Initial load
duke
parents:
diff changeset
    89
                  + "------------");
90ce3da70b43 Initial load
duke
parents:
diff changeset
    90
            debug.println("Executing PKIX certification path validation "
90ce3da70b43 Initial load
duke
parents:
diff changeset
    91
                  + "algorithm.");
90ce3da70b43 Initial load
duke
parents:
diff changeset
    92
        }
90ce3da70b43 Initial load
duke
parents:
diff changeset
    93
90ce3da70b43 Initial load
duke
parents:
diff changeset
    94
        for (int i = 0; i < cpSize; i++) {
90ce3da70b43 Initial load
duke
parents:
diff changeset
    95
90ce3da70b43 Initial load
duke
parents:
diff changeset
    96
            /* The basic loop algorithm is that we get the
90ce3da70b43 Initial load
duke
parents:
diff changeset
    97
             * current certificate, we verify the current certificate using
90ce3da70b43 Initial load
duke
parents:
diff changeset
    98
             * information from the previous certificate and from the state,
90ce3da70b43 Initial load
duke
parents:
diff changeset
    99
             * and we modify the state for the next loop by setting the
90ce3da70b43 Initial load
duke
parents:
diff changeset
   100
             * current certificate of this loop to be the previous certificate
90ce3da70b43 Initial load
duke
parents:
diff changeset
   101
             * of the next loop. The state is initialized during first loop.
90ce3da70b43 Initial load
duke
parents:
diff changeset
   102
             */
90ce3da70b43 Initial load
duke
parents:
diff changeset
   103
            if (debug != null)
90ce3da70b43 Initial load
duke
parents:
diff changeset
   104
                debug.println("Checking cert" + (i+1) + " ...");
90ce3da70b43 Initial load
duke
parents:
diff changeset
   105
90ce3da70b43 Initial load
duke
parents:
diff changeset
   106
            X509Certificate currCert = reversedCertList.get(i);
90ce3da70b43 Initial load
duke
parents:
diff changeset
   107
            Set<String> unresolvedCritExts =
90ce3da70b43 Initial load
duke
parents:
diff changeset
   108
                                        currCert.getCriticalExtensionOIDs();
90ce3da70b43 Initial load
duke
parents:
diff changeset
   109
            if (unresolvedCritExts == null) {
90ce3da70b43 Initial load
duke
parents:
diff changeset
   110
                unresolvedCritExts = Collections.<String>emptySet();
90ce3da70b43 Initial load
duke
parents:
diff changeset
   111
            }
90ce3da70b43 Initial load
duke
parents:
diff changeset
   112
90ce3da70b43 Initial load
duke
parents:
diff changeset
   113
            if (debug != null && !unresolvedCritExts.isEmpty()) {
90ce3da70b43 Initial load
duke
parents:
diff changeset
   114
                debug.println("Set of critical extensions:");
90ce3da70b43 Initial load
duke
parents:
diff changeset
   115
                for (String oid : unresolvedCritExts) {
90ce3da70b43 Initial load
duke
parents:
diff changeset
   116
                    debug.println(oid);
90ce3da70b43 Initial load
duke
parents:
diff changeset
   117
                }
90ce3da70b43 Initial load
duke
parents:
diff changeset
   118
            }
90ce3da70b43 Initial load
duke
parents:
diff changeset
   119
90ce3da70b43 Initial load
duke
parents:
diff changeset
   120
            CertPathValidatorException ocspCause = null;
90ce3da70b43 Initial load
duke
parents:
diff changeset
   121
            for (int j = 0; j < certPathCheckers.size(); j++) {
90ce3da70b43 Initial load
duke
parents:
diff changeset
   122
90ce3da70b43 Initial load
duke
parents:
diff changeset
   123
                PKIXCertPathChecker currChecker = certPathCheckers.get(j);
90ce3da70b43 Initial load
duke
parents:
diff changeset
   124
                if (debug != null) {
90ce3da70b43 Initial load
duke
parents:
diff changeset
   125
                    debug.println("-Using checker" + (j + 1) + " ... [" +
90ce3da70b43 Initial load
duke
parents:
diff changeset
   126
                        currChecker.getClass().getName() + "]");
90ce3da70b43 Initial load
duke
parents:
diff changeset
   127
                }
90ce3da70b43 Initial load
duke
parents:
diff changeset
   128
90ce3da70b43 Initial load
duke
parents:
diff changeset
   129
                if (i == 0)
90ce3da70b43 Initial load
duke
parents:
diff changeset
   130
                    currChecker.init(false);
90ce3da70b43 Initial load
duke
parents:
diff changeset
   131
90ce3da70b43 Initial load
duke
parents:
diff changeset
   132
                try {
90ce3da70b43 Initial load
duke
parents:
diff changeset
   133
                    currChecker.check(currCert, unresolvedCritExts);
90ce3da70b43 Initial load
duke
parents:
diff changeset
   134
90ce3da70b43 Initial load
duke
parents:
diff changeset
   135
                    // OCSP has validated the cert so skip the CRL check
90ce3da70b43 Initial load
duke
parents:
diff changeset
   136
                    if (isRevocationCheck(currChecker, j, certPathCheckers)) {
90ce3da70b43 Initial load
duke
parents:
diff changeset
   137
                        if (debug != null) {
90ce3da70b43 Initial load
duke
parents:
diff changeset
   138
                            debug.println("-checker" + (j + 1) +
90ce3da70b43 Initial load
duke
parents:
diff changeset
   139
                                " validation succeeded");
90ce3da70b43 Initial load
duke
parents:
diff changeset
   140
                        }
90ce3da70b43 Initial load
duke
parents:
diff changeset
   141
                        j++;
90ce3da70b43 Initial load
duke
parents:
diff changeset
   142
                        continue; // skip
90ce3da70b43 Initial load
duke
parents:
diff changeset
   143
                    }
90ce3da70b43 Initial load
duke
parents:
diff changeset
   144
90ce3da70b43 Initial load
duke
parents:
diff changeset
   145
                } catch (CertPathValidatorException cpve) {
90ce3da70b43 Initial load
duke
parents:
diff changeset
   146
                    // Throw the saved OCSP exception
90ce3da70b43 Initial load
duke
parents:
diff changeset
   147
                    // (when the CRL check has also failed)
90ce3da70b43 Initial load
duke
parents:
diff changeset
   148
                    if (ocspCause != null &&
90ce3da70b43 Initial load
duke
parents:
diff changeset
   149
                        currChecker instanceof CrlRevocationChecker) {
90ce3da70b43 Initial load
duke
parents:
diff changeset
   150
                        throw ocspCause;
90ce3da70b43 Initial load
duke
parents:
diff changeset
   151
                    }
90ce3da70b43 Initial load
duke
parents:
diff changeset
   152
                    /*
90ce3da70b43 Initial load
duke
parents:
diff changeset
   153
                     * Handle failover from OCSP to CRLs
90ce3da70b43 Initial load
duke
parents:
diff changeset
   154
                     */
90ce3da70b43 Initial load
duke
parents:
diff changeset
   155
                    CertPathValidatorException currentCause =
90ce3da70b43 Initial load
duke
parents:
diff changeset
   156
                        new CertPathValidatorException(cpve.getMessage(),
1238
6d1f4b722acd 6465942: Add problem identification facility to the CertPathValidator framework
mullan
parents: 2
diff changeset
   157
                            cpve.getCause(), cpOriginal, cpSize - (i + 1),
6d1f4b722acd 6465942: Add problem identification facility to the CertPathValidator framework
mullan
parents: 2
diff changeset
   158
                            cpve.getReason());
2
90ce3da70b43 Initial load
duke
parents:
diff changeset
   159
90ce3da70b43 Initial load
duke
parents:
diff changeset
   160
                    // Check if OCSP has confirmed that the cert was revoked
1238
6d1f4b722acd 6465942: Add problem identification facility to the CertPathValidator framework
mullan
parents: 2
diff changeset
   161
                    if (cpve.getReason() == BasicReason.REVOKED) {
2
90ce3da70b43 Initial load
duke
parents:
diff changeset
   162
                        throw currentCause;
90ce3da70b43 Initial load
duke
parents:
diff changeset
   163
                    }
90ce3da70b43 Initial load
duke
parents:
diff changeset
   164
                    // Check if it is appropriate to failover
90ce3da70b43 Initial load
duke
parents:
diff changeset
   165
                    if (! isRevocationCheck(currChecker, j, certPathCheckers)) {
90ce3da70b43 Initial load
duke
parents:
diff changeset
   166
                        // no failover
90ce3da70b43 Initial load
duke
parents:
diff changeset
   167
                        throw currentCause;
90ce3da70b43 Initial load
duke
parents:
diff changeset
   168
                    }
90ce3da70b43 Initial load
duke
parents:
diff changeset
   169
                    // Save the current exception
90ce3da70b43 Initial load
duke
parents:
diff changeset
   170
                    // (in case the CRL check also fails)
90ce3da70b43 Initial load
duke
parents:
diff changeset
   171
                    ocspCause = currentCause;
90ce3da70b43 Initial load
duke
parents:
diff changeset
   172
90ce3da70b43 Initial load
duke
parents:
diff changeset
   173
                    // Otherwise, failover to CRLs
90ce3da70b43 Initial load
duke
parents:
diff changeset
   174
                    if (debug != null) {
90ce3da70b43 Initial load
duke
parents:
diff changeset
   175
                        debug.println(cpve.getMessage());
90ce3da70b43 Initial load
duke
parents:
diff changeset
   176
                        debug.println(
90ce3da70b43 Initial load
duke
parents:
diff changeset
   177
                            "preparing to failover (from OCSP to CRLs)");
90ce3da70b43 Initial load
duke
parents:
diff changeset
   178
                    }
90ce3da70b43 Initial load
duke
parents:
diff changeset
   179
                }
90ce3da70b43 Initial load
duke
parents:
diff changeset
   180
90ce3da70b43 Initial load
duke
parents:
diff changeset
   181
                if (debug != null)
90ce3da70b43 Initial load
duke
parents:
diff changeset
   182
                    debug.println("-checker" + (j+1) + " validation succeeded");
90ce3da70b43 Initial load
duke
parents:
diff changeset
   183
            }
90ce3da70b43 Initial load
duke
parents:
diff changeset
   184
90ce3da70b43 Initial load
duke
parents:
diff changeset
   185
            if (debug != null)
90ce3da70b43 Initial load
duke
parents:
diff changeset
   186
                debug.println("checking for unresolvedCritExts");
90ce3da70b43 Initial load
duke
parents:
diff changeset
   187
            if (!unresolvedCritExts.isEmpty()) {
90ce3da70b43 Initial load
duke
parents:
diff changeset
   188
                throw new CertPathValidatorException("unrecognized " +
1238
6d1f4b722acd 6465942: Add problem identification facility to the CertPathValidator framework
mullan
parents: 2
diff changeset
   189
                    "critical extension(s)", null, cpOriginal, cpSize-(i+1),
6d1f4b722acd 6465942: Add problem identification facility to the CertPathValidator framework
mullan
parents: 2
diff changeset
   190
                    PKIXReason.UNRECOGNIZED_CRIT_EXT);
2
90ce3da70b43 Initial load
duke
parents:
diff changeset
   191
            }
90ce3da70b43 Initial load
duke
parents:
diff changeset
   192
90ce3da70b43 Initial load
duke
parents:
diff changeset
   193
            if (debug != null)
90ce3da70b43 Initial load
duke
parents:
diff changeset
   194
                debug.println("\ncert" + (i+1) + " validation succeeded.\n");
90ce3da70b43 Initial load
duke
parents:
diff changeset
   195
        }
90ce3da70b43 Initial load
duke
parents:
diff changeset
   196
90ce3da70b43 Initial load
duke
parents:
diff changeset
   197
        if (debug != null) {
90ce3da70b43 Initial load
duke
parents:
diff changeset
   198
            debug.println("Cert path validation succeeded. (PKIX validation "
90ce3da70b43 Initial load
duke
parents:
diff changeset
   199
                    + "algorithm)");
90ce3da70b43 Initial load
duke
parents:
diff changeset
   200
            debug.println("-------------------------------------------------"
90ce3da70b43 Initial load
duke
parents:
diff changeset
   201
                    + "-------------");
90ce3da70b43 Initial load
duke
parents:
diff changeset
   202
        }
90ce3da70b43 Initial load
duke
parents:
diff changeset
   203
    }
90ce3da70b43 Initial load
duke
parents:
diff changeset
   204
90ce3da70b43 Initial load
duke
parents:
diff changeset
   205
    /*
90ce3da70b43 Initial load
duke
parents:
diff changeset
   206
     * Examines the list of PKIX cert path checkers to determine whether
90ce3da70b43 Initial load
duke
parents:
diff changeset
   207
     * both the current checker and the next checker are revocation checkers.
90ce3da70b43 Initial load
duke
parents:
diff changeset
   208
     * OCSPChecker and CrlRevocationChecker are both revocation checkers.
90ce3da70b43 Initial load
duke
parents:
diff changeset
   209
     */
90ce3da70b43 Initial load
duke
parents:
diff changeset
   210
    private static boolean isRevocationCheck(PKIXCertPathChecker checker,
90ce3da70b43 Initial load
duke
parents:
diff changeset
   211
        int index, List<PKIXCertPathChecker> checkers) {
90ce3da70b43 Initial load
duke
parents:
diff changeset
   212
90ce3da70b43 Initial load
duke
parents:
diff changeset
   213
        if (checker instanceof OCSPChecker && index + 1 < checkers.size()) {
90ce3da70b43 Initial load
duke
parents:
diff changeset
   214
            PKIXCertPathChecker nextChecker = checkers.get(index + 1);
90ce3da70b43 Initial load
duke
parents:
diff changeset
   215
            if (nextChecker instanceof CrlRevocationChecker) {
90ce3da70b43 Initial load
duke
parents:
diff changeset
   216
                return true;
90ce3da70b43 Initial load
duke
parents:
diff changeset
   217
            }
90ce3da70b43 Initial load
duke
parents:
diff changeset
   218
        }
90ce3da70b43 Initial load
duke
parents:
diff changeset
   219
        return false;
90ce3da70b43 Initial load
duke
parents:
diff changeset
   220
    }
90ce3da70b43 Initial load
duke
parents:
diff changeset
   221
}