173405ff8729cca39da90b2e2f604062e323f6f7aKenny Root/*
273405ff8729cca39da90b2e2f604062e323f6f7aKenny Root * Copyright (c) 2000, 2012, Oracle and/or its affiliates. All rights reserved.
373405ff8729cca39da90b2e2f604062e323f6f7aKenny Root * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
473405ff8729cca39da90b2e2f604062e323f6f7aKenny Root *
573405ff8729cca39da90b2e2f604062e323f6f7aKenny Root * This code is free software; you can redistribute it and/or modify it
673405ff8729cca39da90b2e2f604062e323f6f7aKenny Root * under the terms of the GNU General Public License version 2 only, as
773405ff8729cca39da90b2e2f604062e323f6f7aKenny Root * published by the Free Software Foundation.  Oracle designates this
873405ff8729cca39da90b2e2f604062e323f6f7aKenny Root * particular file as subject to the "Classpath" exception as provided
973405ff8729cca39da90b2e2f604062e323f6f7aKenny Root * by Oracle in the LICENSE file that accompanied this code.
1073405ff8729cca39da90b2e2f604062e323f6f7aKenny Root *
1173405ff8729cca39da90b2e2f604062e323f6f7aKenny Root * This code is distributed in the hope that it will be useful, but WITHOUT
1273405ff8729cca39da90b2e2f604062e323f6f7aKenny Root * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
1373405ff8729cca39da90b2e2f604062e323f6f7aKenny Root * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
1473405ff8729cca39da90b2e2f604062e323f6f7aKenny Root * version 2 for more details (a copy is included in the LICENSE file that
1573405ff8729cca39da90b2e2f604062e323f6f7aKenny Root * accompanied this code).
1673405ff8729cca39da90b2e2f604062e323f6f7aKenny Root *
1773405ff8729cca39da90b2e2f604062e323f6f7aKenny Root * You should have received a copy of the GNU General Public License version
1873405ff8729cca39da90b2e2f604062e323f6f7aKenny Root * 2 along with this work; if not, write to the Free Software Foundation,
1973405ff8729cca39da90b2e2f604062e323f6f7aKenny Root * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
2073405ff8729cca39da90b2e2f604062e323f6f7aKenny Root *
2173405ff8729cca39da90b2e2f604062e323f6f7aKenny Root * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
2273405ff8729cca39da90b2e2f604062e323f6f7aKenny Root * or visit www.oracle.com if you need additional information or have any
2373405ff8729cca39da90b2e2f604062e323f6f7aKenny Root * questions.
2473405ff8729cca39da90b2e2f604062e323f6f7aKenny Root */
2573405ff8729cca39da90b2e2f604062e323f6f7aKenny Root
2673405ff8729cca39da90b2e2f604062e323f6f7aKenny Rootpackage sun.security.provider.certpath;
2773405ff8729cca39da90b2e2f604062e323f6f7aKenny Root
2873405ff8729cca39da90b2e2f604062e323f6f7aKenny Rootimport sun.security.util.Debug;
2973405ff8729cca39da90b2e2f604062e323f6f7aKenny Root
3073405ff8729cca39da90b2e2f604062e323f6f7aKenny Rootimport java.util.Collections;
3173405ff8729cca39da90b2e2f604062e323f6f7aKenny Rootimport java.util.List;
3273405ff8729cca39da90b2e2f604062e323f6f7aKenny Rootimport java.util.Set;
3373405ff8729cca39da90b2e2f604062e323f6f7aKenny Rootimport java.security.cert.CertPath;
3473405ff8729cca39da90b2e2f604062e323f6f7aKenny Rootimport java.security.cert.CertPathValidatorException;
3573405ff8729cca39da90b2e2f604062e323f6f7aKenny Rootimport java.security.cert.PKIXCertPathChecker;
3673405ff8729cca39da90b2e2f604062e323f6f7aKenny Rootimport java.security.cert.PKIXReason;
3773405ff8729cca39da90b2e2f604062e323f6f7aKenny Rootimport java.security.cert.X509Certificate;
3873405ff8729cca39da90b2e2f604062e323f6f7aKenny Root
3973405ff8729cca39da90b2e2f604062e323f6f7aKenny Root/**
4073405ff8729cca39da90b2e2f604062e323f6f7aKenny Root * This class is initialized with a list of <code>PKIXCertPathChecker</code>s
4173405ff8729cca39da90b2e2f604062e323f6f7aKenny Root * and is used to verify the certificates in a <code>CertPath</code> by
4273405ff8729cca39da90b2e2f604062e323f6f7aKenny Root * feeding each certificate to each <code>PKIXCertPathChecker</code>.
4373405ff8729cca39da90b2e2f604062e323f6f7aKenny Root *
4473405ff8729cca39da90b2e2f604062e323f6f7aKenny Root * @since       1.4
4573405ff8729cca39da90b2e2f604062e323f6f7aKenny Root * @author      Yassir Elley
4673405ff8729cca39da90b2e2f604062e323f6f7aKenny Root */
4773405ff8729cca39da90b2e2f604062e323f6f7aKenny Rootclass PKIXMasterCertPathValidator {
4873405ff8729cca39da90b2e2f604062e323f6f7aKenny Root
4973405ff8729cca39da90b2e2f604062e323f6f7aKenny Root    private static final Debug debug = Debug.getInstance("certpath");
5073405ff8729cca39da90b2e2f604062e323f6f7aKenny Root
5173405ff8729cca39da90b2e2f604062e323f6f7aKenny Root    /**
5273405ff8729cca39da90b2e2f604062e323f6f7aKenny Root     * Validates a certification path consisting exclusively of
5373405ff8729cca39da90b2e2f604062e323f6f7aKenny Root     * <code>X509Certificate</code>s using the specified
5473405ff8729cca39da90b2e2f604062e323f6f7aKenny Root     * <code>PKIXCertPathChecker</code>s. It is assumed that the
5573405ff8729cca39da90b2e2f604062e323f6f7aKenny Root     * <code>PKIXCertPathChecker</code>s
5673405ff8729cca39da90b2e2f604062e323f6f7aKenny Root     * have been initialized with any input parameters they may need.
5773405ff8729cca39da90b2e2f604062e323f6f7aKenny Root     *
5873405ff8729cca39da90b2e2f604062e323f6f7aKenny Root     * @param cpOriginal the original X509 CertPath passed in by the user
5973405ff8729cca39da90b2e2f604062e323f6f7aKenny Root     * @param reversedCertList the reversed X509 CertPath (as a List)
6073405ff8729cca39da90b2e2f604062e323f6f7aKenny Root     * @param certPathCheckers the PKIXCertPathCheckers
6173405ff8729cca39da90b2e2f604062e323f6f7aKenny Root     * @throws CertPathValidatorException if cert path does not validate
6273405ff8729cca39da90b2e2f604062e323f6f7aKenny Root     */
6373405ff8729cca39da90b2e2f604062e323f6f7aKenny Root    static void validate(CertPath cpOriginal,
6473405ff8729cca39da90b2e2f604062e323f6f7aKenny Root                         List<X509Certificate> reversedCertList,
6573405ff8729cca39da90b2e2f604062e323f6f7aKenny Root                         List<PKIXCertPathChecker> certPathCheckers)
6673405ff8729cca39da90b2e2f604062e323f6f7aKenny Root        throws CertPathValidatorException
6773405ff8729cca39da90b2e2f604062e323f6f7aKenny Root    {
6873405ff8729cca39da90b2e2f604062e323f6f7aKenny Root        // we actually process reversedCertList, but we keep cpOriginal because
6973405ff8729cca39da90b2e2f604062e323f6f7aKenny Root        // we need to return the original certPath when we throw an exception.
7073405ff8729cca39da90b2e2f604062e323f6f7aKenny Root        // we will also need to modify the index appropriately when we
7173405ff8729cca39da90b2e2f604062e323f6f7aKenny Root        // throw an exception.
7273405ff8729cca39da90b2e2f604062e323f6f7aKenny Root
7373405ff8729cca39da90b2e2f604062e323f6f7aKenny Root        int cpSize = reversedCertList.size();
7473405ff8729cca39da90b2e2f604062e323f6f7aKenny Root
7573405ff8729cca39da90b2e2f604062e323f6f7aKenny Root        if (debug != null) {
7673405ff8729cca39da90b2e2f604062e323f6f7aKenny Root            debug.println("--------------------------------------------------"
7773405ff8729cca39da90b2e2f604062e323f6f7aKenny Root                  + "------------");
7873405ff8729cca39da90b2e2f604062e323f6f7aKenny Root            debug.println("Executing PKIX certification path validation "
7973405ff8729cca39da90b2e2f604062e323f6f7aKenny Root                  + "algorithm.");
8073405ff8729cca39da90b2e2f604062e323f6f7aKenny Root        }
8173405ff8729cca39da90b2e2f604062e323f6f7aKenny Root
8273405ff8729cca39da90b2e2f604062e323f6f7aKenny Root        for (int i = 0; i < cpSize; i++) {
8373405ff8729cca39da90b2e2f604062e323f6f7aKenny Root
8473405ff8729cca39da90b2e2f604062e323f6f7aKenny Root            /* The basic loop algorithm is that we get the
8573405ff8729cca39da90b2e2f604062e323f6f7aKenny Root             * current certificate, we verify the current certificate using
8673405ff8729cca39da90b2e2f604062e323f6f7aKenny Root             * information from the previous certificate and from the state,
8773405ff8729cca39da90b2e2f604062e323f6f7aKenny Root             * and we modify the state for the next loop by setting the
8873405ff8729cca39da90b2e2f604062e323f6f7aKenny Root             * current certificate of this loop to be the previous certificate
8973405ff8729cca39da90b2e2f604062e323f6f7aKenny Root             * of the next loop. The state is initialized during first loop.
9073405ff8729cca39da90b2e2f604062e323f6f7aKenny Root             */
9173405ff8729cca39da90b2e2f604062e323f6f7aKenny Root            if (debug != null)
9273405ff8729cca39da90b2e2f604062e323f6f7aKenny Root                debug.println("Checking cert" + (i+1) + " ...");
9373405ff8729cca39da90b2e2f604062e323f6f7aKenny Root
9473405ff8729cca39da90b2e2f604062e323f6f7aKenny Root            X509Certificate currCert = reversedCertList.get(i);
9573405ff8729cca39da90b2e2f604062e323f6f7aKenny Root            Set<String> unresCritExts = currCert.getCriticalExtensionOIDs();
9673405ff8729cca39da90b2e2f604062e323f6f7aKenny Root            if (unresCritExts == null) {
9773405ff8729cca39da90b2e2f604062e323f6f7aKenny Root                unresCritExts = Collections.<String>emptySet();
9873405ff8729cca39da90b2e2f604062e323f6f7aKenny Root            }
9973405ff8729cca39da90b2e2f604062e323f6f7aKenny Root
10073405ff8729cca39da90b2e2f604062e323f6f7aKenny Root            if (debug != null && !unresCritExts.isEmpty()) {
10173405ff8729cca39da90b2e2f604062e323f6f7aKenny Root                debug.println("Set of critical extensions:");
10273405ff8729cca39da90b2e2f604062e323f6f7aKenny Root                for (String oid : unresCritExts) {
10373405ff8729cca39da90b2e2f604062e323f6f7aKenny Root                    debug.println(oid);
10473405ff8729cca39da90b2e2f604062e323f6f7aKenny Root                }
10573405ff8729cca39da90b2e2f604062e323f6f7aKenny Root            }
10673405ff8729cca39da90b2e2f604062e323f6f7aKenny Root
10773405ff8729cca39da90b2e2f604062e323f6f7aKenny Root            for (int j = 0; j < certPathCheckers.size(); j++) {
10873405ff8729cca39da90b2e2f604062e323f6f7aKenny Root
10973405ff8729cca39da90b2e2f604062e323f6f7aKenny Root                PKIXCertPathChecker currChecker = certPathCheckers.get(j);
11073405ff8729cca39da90b2e2f604062e323f6f7aKenny Root                if (debug != null) {
11173405ff8729cca39da90b2e2f604062e323f6f7aKenny Root                    debug.println("-Using checker" + (j + 1) + " ... [" +
11273405ff8729cca39da90b2e2f604062e323f6f7aKenny Root                        currChecker.getClass().getName() + "]");
11373405ff8729cca39da90b2e2f604062e323f6f7aKenny Root                }
11473405ff8729cca39da90b2e2f604062e323f6f7aKenny Root
11573405ff8729cca39da90b2e2f604062e323f6f7aKenny Root                if (i == 0)
11673405ff8729cca39da90b2e2f604062e323f6f7aKenny Root                    currChecker.init(false);
11773405ff8729cca39da90b2e2f604062e323f6f7aKenny Root
11873405ff8729cca39da90b2e2f604062e323f6f7aKenny Root                try {
11973405ff8729cca39da90b2e2f604062e323f6f7aKenny Root                    currChecker.check(currCert, unresCritExts);
12073405ff8729cca39da90b2e2f604062e323f6f7aKenny Root
12173405ff8729cca39da90b2e2f604062e323f6f7aKenny Root                    if (debug != null) {
12273405ff8729cca39da90b2e2f604062e323f6f7aKenny Root                        debug.println("-checker" + (j + 1) +
12373405ff8729cca39da90b2e2f604062e323f6f7aKenny Root                            " validation succeeded");
12473405ff8729cca39da90b2e2f604062e323f6f7aKenny Root                    }
12573405ff8729cca39da90b2e2f604062e323f6f7aKenny Root
12673405ff8729cca39da90b2e2f604062e323f6f7aKenny Root                } catch (CertPathValidatorException cpve) {
12773405ff8729cca39da90b2e2f604062e323f6f7aKenny Root                    throw new CertPathValidatorException(cpve.getMessage(),
12873405ff8729cca39da90b2e2f604062e323f6f7aKenny Root                        cpve.getCause(), cpOriginal, cpSize - (i + 1),
12973405ff8729cca39da90b2e2f604062e323f6f7aKenny Root                        cpve.getReason());
13073405ff8729cca39da90b2e2f604062e323f6f7aKenny Root                }
13173405ff8729cca39da90b2e2f604062e323f6f7aKenny Root            }
13273405ff8729cca39da90b2e2f604062e323f6f7aKenny Root
13373405ff8729cca39da90b2e2f604062e323f6f7aKenny Root            if (!unresCritExts.isEmpty()) {
13473405ff8729cca39da90b2e2f604062e323f6f7aKenny Root                throw new CertPathValidatorException("unrecognized " +
13573405ff8729cca39da90b2e2f604062e323f6f7aKenny Root                    "critical extension(s)", null, cpOriginal, cpSize-(i+1),
13673405ff8729cca39da90b2e2f604062e323f6f7aKenny Root                    PKIXReason.UNRECOGNIZED_CRIT_EXT);
13773405ff8729cca39da90b2e2f604062e323f6f7aKenny Root            }
13873405ff8729cca39da90b2e2f604062e323f6f7aKenny Root
13973405ff8729cca39da90b2e2f604062e323f6f7aKenny Root            if (debug != null)
14073405ff8729cca39da90b2e2f604062e323f6f7aKenny Root                debug.println("\ncert" + (i+1) + " validation succeeded.\n");
14173405ff8729cca39da90b2e2f604062e323f6f7aKenny Root        }
14273405ff8729cca39da90b2e2f604062e323f6f7aKenny Root
14373405ff8729cca39da90b2e2f604062e323f6f7aKenny Root        if (debug != null) {
14473405ff8729cca39da90b2e2f604062e323f6f7aKenny Root            debug.println("Cert path validation succeeded. (PKIX validation "
14573405ff8729cca39da90b2e2f604062e323f6f7aKenny Root                          + "algorithm)");
14673405ff8729cca39da90b2e2f604062e323f6f7aKenny Root            debug.println("-------------------------------------------------"
14773405ff8729cca39da90b2e2f604062e323f6f7aKenny Root                          + "-------------");
14873405ff8729cca39da90b2e2f604062e323f6f7aKenny Root        }
14973405ff8729cca39da90b2e2f604062e323f6f7aKenny Root    }
15073405ff8729cca39da90b2e2f604062e323f6f7aKenny Root}
151