alvinalexander.com | career | drupal | java | mac | mysql | perl | scala | uml | unix  

Java example source code file (EndEntityChecker.java)

This example Java source code file (EndEntityChecker.java) is included in the alvinalexander.com "Java Source Code Warehouse" project. The intent of this project is to help you "Learn Java by Example" TM.

Learn more about this Java project at its project page.

Java - Java tags/keywords

certificateexception, collection, endentitychecker, extended, keyusage, ku_signature, netscape, nsct_code_signing, nsct_ssl_server, oid_eku_tls_client, set, string, unknown, util, validatorexception

The EndEntityChecker.java Java example source code

/*
 * Copyright (c) 2002, 2008, Oracle and/or its affiliates. All rights reserved.
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
 *
 * This code is free software; you can redistribute it and/or modify it
 * under the terms of the GNU General Public License version 2 only, as
 * published by the Free Software Foundation.  Oracle designates this
 * particular file as subject to the "Classpath" exception as provided
 * by Oracle in the LICENSE file that accompanied this code.
 *
 * This code is distributed in the hope that it will be useful, but WITHOUT
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
 * version 2 for more details (a copy is included in the LICENSE file that
 * accompanied this code).
 *
 * You should have received a copy of the GNU General Public License version
 * 2 along with this work; if not, write to the Free Software Foundation,
 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
 *
 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
 * or visit www.oracle.com if you need additional information or have any
 * questions.
 */

package sun.security.validator;

import java.util.*;

import java.security.cert.*;

import sun.security.x509.NetscapeCertTypeExtension;

/**
 * Class to check if an end entity cert is suitable for use in some
 * context.<p>
 *
 * This class is used internally by the validator. Currently, seven variants
 * are supported defined as VAR_XXX constants in the Validator class:
 * <ul>
 * <li>Generic. No additional requirements, all certificates are ok.
 *
 * <li>TLS server. Requires that a String parameter is passed to
 * validate that specifies the name of the TLS key exchange algorithm
 * in use. See the JSSE X509TrustManager spec for details.
 *
 * <li>TLS client.
 *
 * <li>Code signing.
 *
 * <li>JCE code signing. Some early JCE code signing certs issued to
 * providers had incorrect extensions. In this mode the checks
 * are relaxed compared to standard code signing checks in order to
 * allow these certificates to pass.
 *
 * <li>Plugin code signing. WebStart and Plugin require their own variant
 * which is equivalent to VAR_CODE_SIGNING with additional checks for
 * compatibility/special cases. See also PKIXValidator.
 *
 * <li>TSA Server (see RFC 3161, section 2.3).
 *
 * </ul>
 *
 * @author Andreas Sterbenz
 */
class EndEntityChecker {

    // extended key usage OIDs for TLS server, TLS client, code signing
    // and any usage

    private final static String OID_EXTENDED_KEY_USAGE =
                                SimpleValidator.OID_EXTENDED_KEY_USAGE;

    private final static String OID_EKU_TLS_SERVER = "1.3.6.1.5.5.7.3.1";

    private final static String OID_EKU_TLS_CLIENT = "1.3.6.1.5.5.7.3.2";

    private final static String OID_EKU_CODE_SIGNING = "1.3.6.1.5.5.7.3.3";

    private final static String OID_EKU_TIME_STAMPING = "1.3.6.1.5.5.7.3.8";

    private final static String OID_EKU_ANY_USAGE = "2.5.29.37.0";

    // the Netscape Server-Gated-Cryptography EKU extension OID
    private final static String OID_EKU_NS_SGC = "2.16.840.1.113730.4.1";

    // the Microsoft Server-Gated-Cryptography EKU extension OID
    private final static String OID_EKU_MS_SGC = "1.3.6.1.4.1.311.10.3.3";

    // the recognized extension OIDs
    private final static String OID_SUBJECT_ALT_NAME = "2.5.29.17";

    private final static String NSCT_SSL_CLIENT =
                                NetscapeCertTypeExtension.SSL_CLIENT;

    private final static String NSCT_SSL_SERVER =
                                NetscapeCertTypeExtension.SSL_SERVER;

    private final static String NSCT_CODE_SIGNING =
                                NetscapeCertTypeExtension.OBJECT_SIGNING;

    // bit numbers in the key usage extension
    private final static int KU_SIGNATURE = 0;
    private final static int KU_KEY_ENCIPHERMENT = 2;
    private final static int KU_KEY_AGREEMENT = 4;

    // TLS key exchange algorithms requiring digitalSignature key usage
    private final static Collection<String> KU_SERVER_SIGNATURE =
        Arrays.asList("DHE_DSS", "DHE_RSA", "ECDHE_ECDSA", "ECDHE_RSA",
            "RSA_EXPORT", "UNKNOWN");

    // TLS key exchange algorithms requiring keyEncipherment key usage
    private final static Collection<String> KU_SERVER_ENCRYPTION =
        Arrays.asList("RSA");

    // TLS key exchange algorithms requiring keyAgreement key usage
    private final static Collection<String> KU_SERVER_KEY_AGREEMENT =
        Arrays.asList("DH_DSS", "DH_RSA", "ECDH_ECDSA", "ECDH_RSA");

    // variant of this end entity cert checker
    private final String variant;

    // type of the validator this checker belongs to
    private final String type;

    private EndEntityChecker(String type, String variant) {
        this.type = type;
        this.variant = variant;
    }

    static EndEntityChecker getInstance(String type, String variant) {
        return new EndEntityChecker(type, variant);
    }

    void check(X509Certificate cert, Object parameter)
            throws CertificateException {
        if (variant.equals(Validator.VAR_GENERIC)) {
            // no checks
            return;
        } else if (variant.equals(Validator.VAR_TLS_SERVER)) {
            checkTLSServer(cert, (String)parameter);
        } else if (variant.equals(Validator.VAR_TLS_CLIENT)) {
            checkTLSClient(cert);
        } else if (variant.equals(Validator.VAR_CODE_SIGNING)) {
            checkCodeSigning(cert);
        } else if (variant.equals(Validator.VAR_JCE_SIGNING)) {
            checkCodeSigning(cert);
        } else if (variant.equals(Validator.VAR_PLUGIN_CODE_SIGNING)) {
            checkCodeSigning(cert);
        } else if (variant.equals(Validator.VAR_TSA_SERVER)) {
            checkTSAServer(cert);
        } else {
            throw new CertificateException("Unknown variant: " + variant);
        }
    }

    /**
     * Utility method returning the Set of critical extensions for
     * certificate cert (never null).
     */
    private Set<String> getCriticalExtensions(X509Certificate cert) {
        Set<String> exts = cert.getCriticalExtensionOIDs();
        if (exts == null) {
            exts = Collections.emptySet();
        }
        return exts;
    }

    /**
     * Utility method checking if there are any unresolved critical extensions.
     * @throws CertificateException if so.
     */
    private void checkRemainingExtensions(Set<String> exts)
            throws CertificateException {
        // basic constraints irrelevant in EE certs
        exts.remove(SimpleValidator.OID_BASIC_CONSTRAINTS);

        // If the subject field contains an empty sequence, the subjectAltName
        // extension MUST be marked critical.
        // We do not check the validity of the critical extension, just mark
        // it recognizable here.
        exts.remove(OID_SUBJECT_ALT_NAME);

        if (!exts.isEmpty()) {
            throw new CertificateException("Certificate contains unsupported "
                + "critical extensions: " + exts);
        }
    }

    /**
     * Utility method checking if the extended key usage extension in
     * certificate cert allows use for expectedEKU.
     */
    private boolean checkEKU(X509Certificate cert, Set<String> exts,
            String expectedEKU) throws CertificateException {
        List<String> eku = cert.getExtendedKeyUsage();
        if (eku == null) {
            return true;
        }
        return eku.contains(expectedEKU) || eku.contains(OID_EKU_ANY_USAGE);
    }

    /**
     * Utility method checking if bit 'bit' is set in this certificates
     * key usage extension.
     * @throws CertificateException if not
     */
    private boolean checkKeyUsage(X509Certificate cert, int bit)
            throws CertificateException {
        boolean[] keyUsage = cert.getKeyUsage();
        if (keyUsage == null) {
            return true;
        }
        return (keyUsage.length > bit) && keyUsage[bit];
    }

    /**
     * Check whether this certificate can be used for TLS client
     * authentication.
     * @throws CertificateException if not.
     */
    private void checkTLSClient(X509Certificate cert)
            throws CertificateException {
        Set<String> exts = getCriticalExtensions(cert);

        if (checkKeyUsage(cert, KU_SIGNATURE) == false) {
            throw new ValidatorException
                ("KeyUsage does not allow digital signatures",
                ValidatorException.T_EE_EXTENSIONS, cert);
        }

        if (checkEKU(cert, exts, OID_EKU_TLS_CLIENT) == false) {
            throw new ValidatorException("Extended key usage does not "
                + "permit use for TLS client authentication",
                ValidatorException.T_EE_EXTENSIONS, cert);
        }

        if (!SimpleValidator.getNetscapeCertTypeBit(cert, NSCT_SSL_CLIENT)) {
            throw new ValidatorException
                ("Netscape cert type does not permit use for SSL client",
                ValidatorException.T_EE_EXTENSIONS, cert);
        }

        // remove extensions we checked
        exts.remove(SimpleValidator.OID_KEY_USAGE);
        exts.remove(SimpleValidator.OID_EXTENDED_KEY_USAGE);
        exts.remove(SimpleValidator.OID_NETSCAPE_CERT_TYPE);

        checkRemainingExtensions(exts);
    }

    /**
     * Check whether this certificate can be used for TLS server authentication
     * using the specified authentication type parameter. See X509TrustManager
     * specification for details.
     * @throws CertificateException if not.
     */
    private void checkTLSServer(X509Certificate cert, String parameter)
            throws CertificateException {
        Set<String> exts = getCriticalExtensions(cert);

        if (KU_SERVER_ENCRYPTION.contains(parameter)) {
            if (checkKeyUsage(cert, KU_KEY_ENCIPHERMENT) == false) {
                throw new ValidatorException
                        ("KeyUsage does not allow key encipherment",
                        ValidatorException.T_EE_EXTENSIONS, cert);
            }
        } else if (KU_SERVER_SIGNATURE.contains(parameter)) {
            if (checkKeyUsage(cert, KU_SIGNATURE) == false) {
                throw new ValidatorException
                        ("KeyUsage does not allow digital signatures",
                        ValidatorException.T_EE_EXTENSIONS, cert);
            }
        } else if (KU_SERVER_KEY_AGREEMENT.contains(parameter)) {
            if (checkKeyUsage(cert, KU_KEY_AGREEMENT) == false) {
                throw new ValidatorException
                        ("KeyUsage does not allow key agreement",
                        ValidatorException.T_EE_EXTENSIONS, cert);
            }
        } else {
            throw new CertificateException("Unknown authType: " + parameter);
        }

        if (checkEKU(cert, exts, OID_EKU_TLS_SERVER) == false) {
            // check for equivalent but now obsolete Server-Gated-Cryptography
            // (aka Step-Up, 128 bit) EKU OIDs
            if ((checkEKU(cert, exts, OID_EKU_MS_SGC) == false) &&
                (checkEKU(cert, exts, OID_EKU_NS_SGC) == false)) {
                throw new ValidatorException
                    ("Extended key usage does not permit use for TLS "
                    + "server authentication",
                    ValidatorException.T_EE_EXTENSIONS, cert);
            }
        }

        if (!SimpleValidator.getNetscapeCertTypeBit(cert, NSCT_SSL_SERVER)) {
            throw new ValidatorException
                ("Netscape cert type does not permit use for SSL server",
                ValidatorException.T_EE_EXTENSIONS, cert);
        }

        // remove extensions we checked
        exts.remove(SimpleValidator.OID_KEY_USAGE);
        exts.remove(SimpleValidator.OID_EXTENDED_KEY_USAGE);
        exts.remove(SimpleValidator.OID_NETSCAPE_CERT_TYPE);

        checkRemainingExtensions(exts);
    }

    /**
     * Check whether this certificate can be used for code signing.
     * @throws CertificateException if not.
     */
    private void checkCodeSigning(X509Certificate cert)
            throws CertificateException {
        Set<String> exts = getCriticalExtensions(cert);

        if (checkKeyUsage(cert, KU_SIGNATURE) == false) {
            throw new ValidatorException
                ("KeyUsage does not allow digital signatures",
                ValidatorException.T_EE_EXTENSIONS, cert);
        }

        if (checkEKU(cert, exts, OID_EKU_CODE_SIGNING) == false) {
            throw new ValidatorException
                ("Extended key usage does not permit use for code signing",
                ValidatorException.T_EE_EXTENSIONS, cert);
        }

        // do not check Netscape cert type for JCE code signing checks
        // (some certs were issued with incorrect extensions)
        if (variant.equals(Validator.VAR_JCE_SIGNING) == false) {
            if (!SimpleValidator.getNetscapeCertTypeBit(cert, NSCT_CODE_SIGNING)) {
                throw new ValidatorException
                    ("Netscape cert type does not permit use for code signing",
                    ValidatorException.T_EE_EXTENSIONS, cert);
            }
            exts.remove(SimpleValidator.OID_NETSCAPE_CERT_TYPE);
        }

        // remove extensions we checked
        exts.remove(SimpleValidator.OID_KEY_USAGE);
        exts.remove(SimpleValidator.OID_EXTENDED_KEY_USAGE);

        checkRemainingExtensions(exts);
    }

    /**
     * Check whether this certificate can be used by a time stamping authority
     * server (see RFC 3161, section 2.3).
     * @throws CertificateException if not.
     */
    private void checkTSAServer(X509Certificate cert)
            throws CertificateException {
        Set<String> exts = getCriticalExtensions(cert);

        if (checkKeyUsage(cert, KU_SIGNATURE) == false) {
            throw new ValidatorException
                ("KeyUsage does not allow digital signatures",
                ValidatorException.T_EE_EXTENSIONS, cert);
        }

        if (cert.getExtendedKeyUsage() == null) {
            throw new ValidatorException
                ("Certificate does not contain an extended key usage " +
                "extension required for a TSA server",
                ValidatorException.T_EE_EXTENSIONS, cert);
        }

        if (checkEKU(cert, exts, OID_EKU_TIME_STAMPING) == false) {
            throw new ValidatorException
                ("Extended key usage does not permit use for TSA server",
                ValidatorException.T_EE_EXTENSIONS, cert);
        }

        // remove extensions we checked
        exts.remove(SimpleValidator.OID_KEY_USAGE);
        exts.remove(SimpleValidator.OID_EXTENDED_KEY_USAGE);

        checkRemainingExtensions(exts);
    }
}

Other Java examples (source code examples)

Here is a short list of links related to this Java EndEntityChecker.java source code file:

... this post is sponsored by my books ...

#1 New Release!

FP Best Seller

 

new blog posts

 

Copyright 1998-2021 Alvin Alexander, alvinalexander.com
All Rights Reserved.

A percentage of advertising revenue from
pages under the /java/jwarehouse URI on this website is
paid back to open source projects.