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 java.util.*;
2973405ff8729cca39da90b2e2f604062e323f6f7aKenny Rootimport java.security.cert.*;
3073405ff8729cca39da90b2e2f604062e323f6f7aKenny Rootimport java.security.cert.PKIXReason;
3173405ff8729cca39da90b2e2f604062e323f6f7aKenny Root
3273405ff8729cca39da90b2e2f604062e323f6f7aKenny Rootimport sun.security.util.Debug;
3373405ff8729cca39da90b2e2f604062e323f6f7aKenny Rootimport static sun.security.x509.PKIXExtensions.*;
3473405ff8729cca39da90b2e2f604062e323f6f7aKenny Root
3573405ff8729cca39da90b2e2f604062e323f6f7aKenny Root/**
3673405ff8729cca39da90b2e2f604062e323f6f7aKenny Root * KeyChecker is a <code>PKIXCertPathChecker</code> that checks that the
3773405ff8729cca39da90b2e2f604062e323f6f7aKenny Root * keyCertSign bit is set in the keyUsage extension in an intermediate CA
3873405ff8729cca39da90b2e2f604062e323f6f7aKenny Root * certificate. It also checks whether the final certificate in a
3973405ff8729cca39da90b2e2f604062e323f6f7aKenny Root * certification path meets the specified target constraints specified as
4073405ff8729cca39da90b2e2f604062e323f6f7aKenny Root * a CertSelector in the PKIXParameters passed to the CertPathValidator.
4173405ff8729cca39da90b2e2f604062e323f6f7aKenny Root *
4273405ff8729cca39da90b2e2f604062e323f6f7aKenny Root * @since       1.4
4373405ff8729cca39da90b2e2f604062e323f6f7aKenny Root * @author      Yassir Elley
4473405ff8729cca39da90b2e2f604062e323f6f7aKenny Root */
4573405ff8729cca39da90b2e2f604062e323f6f7aKenny Rootclass KeyChecker extends PKIXCertPathChecker {
4673405ff8729cca39da90b2e2f604062e323f6f7aKenny Root
4773405ff8729cca39da90b2e2f604062e323f6f7aKenny Root    private static final Debug debug = Debug.getInstance("certpath");
4873405ff8729cca39da90b2e2f604062e323f6f7aKenny Root    private final int certPathLen;
4973405ff8729cca39da90b2e2f604062e323f6f7aKenny Root    private final CertSelector targetConstraints;
5073405ff8729cca39da90b2e2f604062e323f6f7aKenny Root    private int remainingCerts;
5173405ff8729cca39da90b2e2f604062e323f6f7aKenny Root
5273405ff8729cca39da90b2e2f604062e323f6f7aKenny Root    private Set<String> supportedExts;
5373405ff8729cca39da90b2e2f604062e323f6f7aKenny Root
5473405ff8729cca39da90b2e2f604062e323f6f7aKenny Root    /**
5573405ff8729cca39da90b2e2f604062e323f6f7aKenny Root     * Creates a KeyChecker.
5673405ff8729cca39da90b2e2f604062e323f6f7aKenny Root     *
5773405ff8729cca39da90b2e2f604062e323f6f7aKenny Root     * @param certPathLen allowable cert path length
5873405ff8729cca39da90b2e2f604062e323f6f7aKenny Root     * @param targetCertSel a CertSelector object specifying the constraints
5973405ff8729cca39da90b2e2f604062e323f6f7aKenny Root     * on the target certificate
6073405ff8729cca39da90b2e2f604062e323f6f7aKenny Root     */
6173405ff8729cca39da90b2e2f604062e323f6f7aKenny Root    KeyChecker(int certPathLen, CertSelector targetCertSel) {
6273405ff8729cca39da90b2e2f604062e323f6f7aKenny Root        this.certPathLen = certPathLen;
6373405ff8729cca39da90b2e2f604062e323f6f7aKenny Root        this.targetConstraints = targetCertSel;
6473405ff8729cca39da90b2e2f604062e323f6f7aKenny Root    }
6573405ff8729cca39da90b2e2f604062e323f6f7aKenny Root
6673405ff8729cca39da90b2e2f604062e323f6f7aKenny Root    /**
6773405ff8729cca39da90b2e2f604062e323f6f7aKenny Root     * Initializes the internal state of the checker from parameters
6873405ff8729cca39da90b2e2f604062e323f6f7aKenny Root     * specified in the constructor
6973405ff8729cca39da90b2e2f604062e323f6f7aKenny Root     */
7073405ff8729cca39da90b2e2f604062e323f6f7aKenny Root    @Override
7173405ff8729cca39da90b2e2f604062e323f6f7aKenny Root    public void init(boolean forward) throws CertPathValidatorException {
7273405ff8729cca39da90b2e2f604062e323f6f7aKenny Root        if (!forward) {
7373405ff8729cca39da90b2e2f604062e323f6f7aKenny Root            remainingCerts = certPathLen;
7473405ff8729cca39da90b2e2f604062e323f6f7aKenny Root        } else {
7573405ff8729cca39da90b2e2f604062e323f6f7aKenny Root            throw new CertPathValidatorException
7673405ff8729cca39da90b2e2f604062e323f6f7aKenny Root                ("forward checking not supported");
7773405ff8729cca39da90b2e2f604062e323f6f7aKenny Root        }
7873405ff8729cca39da90b2e2f604062e323f6f7aKenny Root    }
7973405ff8729cca39da90b2e2f604062e323f6f7aKenny Root
8073405ff8729cca39da90b2e2f604062e323f6f7aKenny Root    @Override
8173405ff8729cca39da90b2e2f604062e323f6f7aKenny Root    public boolean isForwardCheckingSupported() {
8273405ff8729cca39da90b2e2f604062e323f6f7aKenny Root        return false;
8373405ff8729cca39da90b2e2f604062e323f6f7aKenny Root    }
8473405ff8729cca39da90b2e2f604062e323f6f7aKenny Root
8573405ff8729cca39da90b2e2f604062e323f6f7aKenny Root    @Override
8673405ff8729cca39da90b2e2f604062e323f6f7aKenny Root    public Set<String> getSupportedExtensions() {
8773405ff8729cca39da90b2e2f604062e323f6f7aKenny Root        if (supportedExts == null) {
8873405ff8729cca39da90b2e2f604062e323f6f7aKenny Root            supportedExts = new HashSet<String>(3);
8973405ff8729cca39da90b2e2f604062e323f6f7aKenny Root            supportedExts.add(KeyUsage_Id.toString());
9073405ff8729cca39da90b2e2f604062e323f6f7aKenny Root            supportedExts.add(ExtendedKeyUsage_Id.toString());
9173405ff8729cca39da90b2e2f604062e323f6f7aKenny Root            supportedExts.add(SubjectAlternativeName_Id.toString());
9273405ff8729cca39da90b2e2f604062e323f6f7aKenny Root            supportedExts = Collections.unmodifiableSet(supportedExts);
9373405ff8729cca39da90b2e2f604062e323f6f7aKenny Root        }
9473405ff8729cca39da90b2e2f604062e323f6f7aKenny Root        return supportedExts;
9573405ff8729cca39da90b2e2f604062e323f6f7aKenny Root    }
9673405ff8729cca39da90b2e2f604062e323f6f7aKenny Root
9773405ff8729cca39da90b2e2f604062e323f6f7aKenny Root    /**
9873405ff8729cca39da90b2e2f604062e323f6f7aKenny Root     * Checks that keyUsage and target constraints are satisfied by
9973405ff8729cca39da90b2e2f604062e323f6f7aKenny Root     * the specified certificate.
10073405ff8729cca39da90b2e2f604062e323f6f7aKenny Root     *
10173405ff8729cca39da90b2e2f604062e323f6f7aKenny Root     * @param cert the Certificate
10273405ff8729cca39da90b2e2f604062e323f6f7aKenny Root     * @param unresolvedCritExts the unresolved critical extensions
10373405ff8729cca39da90b2e2f604062e323f6f7aKenny Root     * @throws CertPathValidatorException if certificate does not verify
10473405ff8729cca39da90b2e2f604062e323f6f7aKenny Root     */
10573405ff8729cca39da90b2e2f604062e323f6f7aKenny Root    @Override
10673405ff8729cca39da90b2e2f604062e323f6f7aKenny Root    public void check(Certificate cert, Collection<String> unresCritExts)
10773405ff8729cca39da90b2e2f604062e323f6f7aKenny Root        throws CertPathValidatorException
10873405ff8729cca39da90b2e2f604062e323f6f7aKenny Root    {
10973405ff8729cca39da90b2e2f604062e323f6f7aKenny Root        X509Certificate currCert = (X509Certificate)cert;
11073405ff8729cca39da90b2e2f604062e323f6f7aKenny Root
11173405ff8729cca39da90b2e2f604062e323f6f7aKenny Root        remainingCerts--;
11273405ff8729cca39da90b2e2f604062e323f6f7aKenny Root
11373405ff8729cca39da90b2e2f604062e323f6f7aKenny Root        // if final certificate, check that target constraints are satisfied
11473405ff8729cca39da90b2e2f604062e323f6f7aKenny Root        if (remainingCerts == 0) {
11573405ff8729cca39da90b2e2f604062e323f6f7aKenny Root            if (targetConstraints != null &&
11673405ff8729cca39da90b2e2f604062e323f6f7aKenny Root                targetConstraints.match(currCert) == false) {
11773405ff8729cca39da90b2e2f604062e323f6f7aKenny Root                throw new CertPathValidatorException("target certificate " +
11873405ff8729cca39da90b2e2f604062e323f6f7aKenny Root                    "constraints check failed");
11973405ff8729cca39da90b2e2f604062e323f6f7aKenny Root            }
12073405ff8729cca39da90b2e2f604062e323f6f7aKenny Root        } else {
12173405ff8729cca39da90b2e2f604062e323f6f7aKenny Root            // otherwise, verify that keyCertSign bit is set in CA certificate
12273405ff8729cca39da90b2e2f604062e323f6f7aKenny Root            verifyCAKeyUsage(currCert);
12373405ff8729cca39da90b2e2f604062e323f6f7aKenny Root        }
12473405ff8729cca39da90b2e2f604062e323f6f7aKenny Root
12573405ff8729cca39da90b2e2f604062e323f6f7aKenny Root        // remove the extensions that we have checked
12673405ff8729cca39da90b2e2f604062e323f6f7aKenny Root        if (unresCritExts != null && !unresCritExts.isEmpty()) {
12773405ff8729cca39da90b2e2f604062e323f6f7aKenny Root            unresCritExts.remove(KeyUsage_Id.toString());
12873405ff8729cca39da90b2e2f604062e323f6f7aKenny Root            unresCritExts.remove(ExtendedKeyUsage_Id.toString());
12973405ff8729cca39da90b2e2f604062e323f6f7aKenny Root            unresCritExts.remove(SubjectAlternativeName_Id.toString());
13073405ff8729cca39da90b2e2f604062e323f6f7aKenny Root        }
13173405ff8729cca39da90b2e2f604062e323f6f7aKenny Root    }
13273405ff8729cca39da90b2e2f604062e323f6f7aKenny Root
13373405ff8729cca39da90b2e2f604062e323f6f7aKenny Root    // the index of keyCertSign in the boolean KeyUsage array
13473405ff8729cca39da90b2e2f604062e323f6f7aKenny Root    private static final int KEY_CERT_SIGN = 5;
13573405ff8729cca39da90b2e2f604062e323f6f7aKenny Root    /**
13673405ff8729cca39da90b2e2f604062e323f6f7aKenny Root     * Verifies the key usage extension in a CA cert.
13773405ff8729cca39da90b2e2f604062e323f6f7aKenny Root     * The key usage extension, if present, must assert the keyCertSign bit.
13873405ff8729cca39da90b2e2f604062e323f6f7aKenny Root     * The extended key usage extension is not checked (see CR 4776794 for
13973405ff8729cca39da90b2e2f604062e323f6f7aKenny Root     * more information).
14073405ff8729cca39da90b2e2f604062e323f6f7aKenny Root     */
14173405ff8729cca39da90b2e2f604062e323f6f7aKenny Root    static void verifyCAKeyUsage(X509Certificate cert)
14273405ff8729cca39da90b2e2f604062e323f6f7aKenny Root            throws CertPathValidatorException {
14373405ff8729cca39da90b2e2f604062e323f6f7aKenny Root        String msg = "CA key usage";
14473405ff8729cca39da90b2e2f604062e323f6f7aKenny Root        if (debug != null) {
14573405ff8729cca39da90b2e2f604062e323f6f7aKenny Root            debug.println("KeyChecker.verifyCAKeyUsage() ---checking " + msg
14673405ff8729cca39da90b2e2f604062e323f6f7aKenny Root                          + "...");
14773405ff8729cca39da90b2e2f604062e323f6f7aKenny Root        }
14873405ff8729cca39da90b2e2f604062e323f6f7aKenny Root
14973405ff8729cca39da90b2e2f604062e323f6f7aKenny Root        boolean[] keyUsageBits = cert.getKeyUsage();
15073405ff8729cca39da90b2e2f604062e323f6f7aKenny Root
15173405ff8729cca39da90b2e2f604062e323f6f7aKenny Root        // getKeyUsage returns null if the KeyUsage extension is not present
15273405ff8729cca39da90b2e2f604062e323f6f7aKenny Root        // in the certificate - in which case there is nothing to check
15373405ff8729cca39da90b2e2f604062e323f6f7aKenny Root        if (keyUsageBits == null) {
15473405ff8729cca39da90b2e2f604062e323f6f7aKenny Root            return;
15573405ff8729cca39da90b2e2f604062e323f6f7aKenny Root        }
15673405ff8729cca39da90b2e2f604062e323f6f7aKenny Root
15773405ff8729cca39da90b2e2f604062e323f6f7aKenny Root        // throw an exception if the keyCertSign bit is not set
15873405ff8729cca39da90b2e2f604062e323f6f7aKenny Root        if (!keyUsageBits[KEY_CERT_SIGN]) {
15973405ff8729cca39da90b2e2f604062e323f6f7aKenny Root            throw new CertPathValidatorException
16073405ff8729cca39da90b2e2f604062e323f6f7aKenny Root                (msg + " check failed: keyCertSign bit is not set", null,
16173405ff8729cca39da90b2e2f604062e323f6f7aKenny Root                 null, -1, PKIXReason.INVALID_KEY_USAGE);
16273405ff8729cca39da90b2e2f604062e323f6f7aKenny Root        }
16373405ff8729cca39da90b2e2f604062e323f6f7aKenny Root
16473405ff8729cca39da90b2e2f604062e323f6f7aKenny Root        if (debug != null) {
16573405ff8729cca39da90b2e2f604062e323f6f7aKenny Root            debug.println("KeyChecker.verifyCAKeyUsage() " + msg
16673405ff8729cca39da90b2e2f604062e323f6f7aKenny Root                          + " verified.");
16773405ff8729cca39da90b2e2f604062e323f6f7aKenny Root        }
16873405ff8729cca39da90b2e2f604062e323f6f7aKenny Root    }
16973405ff8729cca39da90b2e2f604062e323f6f7aKenny Root}
170