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