Path: blob/master/src/java.base/share/classes/sun/security/validator/EndEntityChecker.java
41159 views
/*1* Copyright (c) 2002, 2020, Oracle and/or its affiliates. All rights reserved.2* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.3*4* This code is free software; you can redistribute it and/or modify it5* under the terms of the GNU General Public License version 2 only, as6* published by the Free Software Foundation. Oracle designates this7* particular file as subject to the "Classpath" exception as provided8* by Oracle in the LICENSE file that accompanied this code.9*10* This code is distributed in the hope that it will be useful, but WITHOUT11* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or12* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License13* version 2 for more details (a copy is included in the LICENSE file that14* accompanied this code).15*16* You should have received a copy of the GNU General Public License version17* 2 along with this work; if not, write to the Free Software Foundation,18* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.19*20* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA21* or visit www.oracle.com if you need additional information or have any22* questions.23*/2425package sun.security.validator;2627import java.util.*;2829import java.security.cert.*;30import sun.security.util.KnownOIDs;31import sun.security.x509.NetscapeCertTypeExtension;3233/**34* Class to check if an end entity cert is suitable for use in some35* context.<p>36*37* This class is used internally by the validator. Currently, seven variants38* are supported defined as VAR_XXX constants in the Validator class:39* <ul>40* <li>Generic. No additional requirements, all certificates are ok.41*42* <li>TLS server. Requires that a String parameter is passed to43* validate that specifies the name of the TLS key exchange algorithm44* in use. See the JSSE X509TrustManager spec for details.45*46* <li>TLS client.47*48* <li>Code signing.49*50* <li>JCE code signing. Some early JCE code signing certs issued to51* providers had incorrect extensions. In this mode the checks52* are relaxed compared to standard code signing checks in order to53* allow these certificates to pass.54*55* <li>Plugin code signing. WebStart and Plugin require their own variant56* which is equivalent to VAR_CODE_SIGNING with additional checks for57* compatibility/special cases. See also PKIXValidator.58*59* <li>TSA Server (see RFC 3161, section 2.3).60*61* </ul>62*63* @author Andreas Sterbenz64*/65class EndEntityChecker {6667// extended key usage OIDs for TLS server, TLS client, code signing68// and any usage6970private static final String OID_EXTENDED_KEY_USAGE =71SimpleValidator.OID_EXTENDED_KEY_USAGE;7273private static final String OID_EKU_TLS_SERVER =74KnownOIDs.serverAuth.value();7576private static final String OID_EKU_TLS_CLIENT =77KnownOIDs.clientAuth.value();7879private static final String OID_EKU_CODE_SIGNING =80KnownOIDs.codeSigning.value();8182private static final String OID_EKU_TIME_STAMPING =83KnownOIDs.KP_TimeStamping.value();8485private static final String OID_EKU_ANY_USAGE =86KnownOIDs.anyExtendedKeyUsage.value();8788// the Netscape Server-Gated-Cryptography EKU extension OID89private static final String OID_EKU_NS_SGC =90KnownOIDs.NETSCAPE_ExportApproved.value();9192// the Microsoft Server-Gated-Cryptography EKU extension OID93private static final String OID_EKU_MS_SGC =94KnownOIDs.MICROSOFT_ExportApproved.value();9596// the recognized extension OIDs97private static final String OID_SUBJECT_ALT_NAME =98KnownOIDs.SubjectAlternativeName.value();99100private static final String NSCT_SSL_CLIENT =101NetscapeCertTypeExtension.SSL_CLIENT;102103private static final String NSCT_SSL_SERVER =104NetscapeCertTypeExtension.SSL_SERVER;105106private static final String NSCT_CODE_SIGNING =107NetscapeCertTypeExtension.OBJECT_SIGNING;108109// bit numbers in the key usage extension110private static final int KU_SIGNATURE = 0;111private static final int KU_KEY_ENCIPHERMENT = 2;112private static final int KU_KEY_AGREEMENT = 4;113114// TLS key exchange algorithms requiring digitalSignature key usage115private static final Collection<String> KU_SERVER_SIGNATURE =116Arrays.asList("DHE_DSS", "DHE_RSA", "ECDHE_ECDSA", "ECDHE_RSA",117"RSA_EXPORT", "UNKNOWN");118119// TLS key exchange algorithms requiring keyEncipherment key usage120private static final Collection<String> KU_SERVER_ENCRYPTION =121Arrays.asList("RSA");122123// TLS key exchange algorithms requiring keyAgreement key usage124private static final Collection<String> KU_SERVER_KEY_AGREEMENT =125Arrays.asList("DH_DSS", "DH_RSA", "ECDH_ECDSA", "ECDH_RSA");126127// variant of this end entity cert checker128private final String variant;129130// type of the validator this checker belongs to131private final String type;132133private EndEntityChecker(String type, String variant) {134this.type = type;135this.variant = variant;136}137138static EndEntityChecker getInstance(String type, String variant) {139return new EndEntityChecker(type, variant);140}141142void check(X509Certificate[] chain, Object parameter,143boolean checkUnresolvedCritExts) throws CertificateException {144145if (variant.equals(Validator.VAR_GENERIC)) {146return; // no checks147}148149Set<String> exts = getCriticalExtensions(chain[0]);150if (variant.equals(Validator.VAR_TLS_SERVER)) {151checkTLSServer(chain[0], (String)parameter, exts);152} else if (variant.equals(Validator.VAR_TLS_CLIENT)) {153checkTLSClient(chain[0], exts);154} else if (variant.equals(Validator.VAR_CODE_SIGNING)) {155checkCodeSigning(chain[0], exts);156} else if (variant.equals(Validator.VAR_JCE_SIGNING)) {157checkCodeSigning(chain[0], exts);158} else if (variant.equals(Validator.VAR_PLUGIN_CODE_SIGNING)) {159checkCodeSigning(chain[0], exts);160} else if (variant.equals(Validator.VAR_TSA_SERVER)) {161checkTSAServer(chain[0], exts);162} else {163throw new CertificateException("Unknown variant: " + variant);164}165166// if neither VAR_GENERIC variant nor unknown variant167if (checkUnresolvedCritExts) {168checkRemainingExtensions(exts);169}170171// check if certificate should be distrusted according to policies172// set in the jdk.security.caDistrustPolicies security property173for (CADistrustPolicy policy : CADistrustPolicy.POLICIES) {174policy.checkDistrust(variant, chain);175}176}177178/**179* Utility method returning the Set of critical extensions for180* certificate cert (never null).181*/182private Set<String> getCriticalExtensions(X509Certificate cert) {183Set<String> exts = cert.getCriticalExtensionOIDs();184if (exts == null) {185exts = Collections.emptySet();186}187return exts;188}189190/**191* Utility method checking if there are any unresolved critical extensions.192* @throws CertificateException if so.193*/194private void checkRemainingExtensions(Set<String> exts)195throws CertificateException {196// basic constraints irrelevant in EE certs197exts.remove(SimpleValidator.OID_BASIC_CONSTRAINTS);198199// If the subject field contains an empty sequence, the subjectAltName200// extension MUST be marked critical.201// We do not check the validity of the critical extension, just mark202// it recognizable here.203exts.remove(OID_SUBJECT_ALT_NAME);204205if (!exts.isEmpty()) {206throw new CertificateException("Certificate contains unsupported "207+ "critical extensions: " + exts);208}209}210211/**212* Utility method checking if the extended key usage extension in213* certificate cert allows use for expectedEKU.214*/215private boolean checkEKU(X509Certificate cert, Set<String> exts,216String expectedEKU) throws CertificateException {217List<String> eku = cert.getExtendedKeyUsage();218if (eku == null) {219return true;220}221return eku.contains(expectedEKU) || eku.contains(OID_EKU_ANY_USAGE);222}223224/**225* Utility method checking if bit 'bit' is set in this certificates226* key usage extension.227* @throws CertificateException if not228*/229private boolean checkKeyUsage(X509Certificate cert, int bit)230throws CertificateException {231boolean[] keyUsage = cert.getKeyUsage();232if (keyUsage == null) {233return true;234}235return (keyUsage.length > bit) && keyUsage[bit];236}237238/**239* Check whether this certificate can be used for TLS client240* authentication.241* @throws CertificateException if not.242*/243private void checkTLSClient(X509Certificate cert, Set<String> exts)244throws CertificateException {245if (checkKeyUsage(cert, KU_SIGNATURE) == false) {246throw new ValidatorException247("KeyUsage does not allow digital signatures",248ValidatorException.T_EE_EXTENSIONS, cert);249}250251if (checkEKU(cert, exts, OID_EKU_TLS_CLIENT) == false) {252throw new ValidatorException("Extended key usage does not "253+ "permit use for TLS client authentication",254ValidatorException.T_EE_EXTENSIONS, cert);255}256257if (!SimpleValidator.getNetscapeCertTypeBit(cert, NSCT_SSL_CLIENT)) {258throw new ValidatorException259("Netscape cert type does not permit use for SSL client",260ValidatorException.T_EE_EXTENSIONS, cert);261}262263// remove extensions we checked264exts.remove(SimpleValidator.OID_KEY_USAGE);265exts.remove(SimpleValidator.OID_EXTENDED_KEY_USAGE);266exts.remove(SimpleValidator.OID_NETSCAPE_CERT_TYPE);267}268269/**270* Check whether this certificate can be used for TLS server authentication271* using the specified authentication type parameter. See X509TrustManager272* specification for details.273* @throws CertificateException if not.274*/275private void checkTLSServer(X509Certificate cert, String parameter,276Set<String> exts) throws CertificateException {277if (KU_SERVER_ENCRYPTION.contains(parameter)) {278if (checkKeyUsage(cert, KU_KEY_ENCIPHERMENT) == false) {279throw new ValidatorException280("KeyUsage does not allow key encipherment",281ValidatorException.T_EE_EXTENSIONS, cert);282}283} else if (KU_SERVER_SIGNATURE.contains(parameter)) {284if (checkKeyUsage(cert, KU_SIGNATURE) == false) {285throw new ValidatorException286("KeyUsage does not allow digital signatures",287ValidatorException.T_EE_EXTENSIONS, cert);288}289} else if (KU_SERVER_KEY_AGREEMENT.contains(parameter)) {290if (checkKeyUsage(cert, KU_KEY_AGREEMENT) == false) {291throw new ValidatorException292("KeyUsage does not allow key agreement",293ValidatorException.T_EE_EXTENSIONS, cert);294}295} else {296throw new CertificateException("Unknown authType: " + parameter);297}298299if (checkEKU(cert, exts, OID_EKU_TLS_SERVER) == false) {300// check for equivalent but now obsolete Server-Gated-Cryptography301// (aka Step-Up, 128 bit) EKU OIDs302if ((checkEKU(cert, exts, OID_EKU_MS_SGC) == false) &&303(checkEKU(cert, exts, OID_EKU_NS_SGC) == false)) {304throw new ValidatorException305("Extended key usage does not permit use for TLS "306+ "server authentication",307ValidatorException.T_EE_EXTENSIONS, cert);308}309}310311if (!SimpleValidator.getNetscapeCertTypeBit(cert, NSCT_SSL_SERVER)) {312throw new ValidatorException313("Netscape cert type does not permit use for SSL server",314ValidatorException.T_EE_EXTENSIONS, cert);315}316317// remove extensions we checked318exts.remove(SimpleValidator.OID_KEY_USAGE);319exts.remove(SimpleValidator.OID_EXTENDED_KEY_USAGE);320exts.remove(SimpleValidator.OID_NETSCAPE_CERT_TYPE);321}322323/**324* Check whether this certificate can be used for code signing.325* @throws CertificateException if not.326*/327private void checkCodeSigning(X509Certificate cert, Set<String> exts)328throws CertificateException {329if (checkKeyUsage(cert, KU_SIGNATURE) == false) {330throw new ValidatorException331("KeyUsage does not allow digital signatures",332ValidatorException.T_EE_EXTENSIONS, cert);333}334335if (checkEKU(cert, exts, OID_EKU_CODE_SIGNING) == false) {336throw new ValidatorException337("Extended key usage does not permit use for code signing",338ValidatorException.T_EE_EXTENSIONS, cert);339}340341// do not check Netscape cert type for JCE code signing checks342// (some certs were issued with incorrect extensions)343if (variant.equals(Validator.VAR_JCE_SIGNING) == false) {344if (!SimpleValidator.getNetscapeCertTypeBit(cert, NSCT_CODE_SIGNING)) {345throw new ValidatorException346("Netscape cert type does not permit use for code signing",347ValidatorException.T_EE_EXTENSIONS, cert);348}349exts.remove(SimpleValidator.OID_NETSCAPE_CERT_TYPE);350}351352// remove extensions we checked353exts.remove(SimpleValidator.OID_KEY_USAGE);354exts.remove(SimpleValidator.OID_EXTENDED_KEY_USAGE);355}356357/**358* Check whether this certificate can be used by a time stamping authority359* server (see RFC 3161, section 2.3).360* @throws CertificateException if not.361*/362private void checkTSAServer(X509Certificate cert, Set<String> exts)363throws CertificateException {364if (checkKeyUsage(cert, KU_SIGNATURE) == false) {365throw new ValidatorException366("KeyUsage does not allow digital signatures",367ValidatorException.T_EE_EXTENSIONS, cert);368}369370if (cert.getExtendedKeyUsage() == null) {371throw new ValidatorException372("Certificate does not contain an extended key usage " +373"extension required for a TSA server",374ValidatorException.T_EE_EXTENSIONS, cert);375}376377if (checkEKU(cert, exts, OID_EKU_TIME_STAMPING) == false) {378throw new ValidatorException379("Extended key usage does not permit use for TSA server",380ValidatorException.T_EE_EXTENSIONS, cert);381}382383// remove extensions we checked384exts.remove(SimpleValidator.OID_KEY_USAGE);385exts.remove(SimpleValidator.OID_EXTENDED_KEY_USAGE);386}387}388389390