1 /* 2 * Copyright (c) 2002, 2020, Oracle and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. Oracle designates this 8 * particular file as subject to the "Classpath" exception as provided 9 * by Oracle in the LICENSE file that accompanied this code. 10 * 11 * This code is distributed in the hope that it will be useful, but WITHOUT 12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 14 * version 2 for more details (a copy is included in the LICENSE file that 15 * accompanied this code). 16 * 17 * You should have received a copy of the GNU General Public License version 18 * 2 along with this work; if not, write to the Free Software Foundation, 19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 20 * 21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 22 * or visit www.oracle.com if you need additional information or have any 23 * questions. 24 */ 25 26 package sun.security.validator; 27 28 import java.util.*; 29 30 import java.security.cert.*; 31 import sun.security.util.KnownOIDs; 32 import sun.security.x509.NetscapeCertTypeExtension; 33 34 /** 35 * Class to check if an end entity cert is suitable for use in some 36 * context.<p> 37 * 38 * This class is used internally by the validator. Currently, seven variants 39 * are supported defined as VAR_XXX constants in the Validator class: 40 * <ul> 41 * <li>Generic. No additional requirements, all certificates are ok. 42 * 43 * <li>TLS server. Requires that a String parameter is passed to 44 * validate that specifies the name of the TLS key exchange algorithm 45 * in use. See the JSSE X509TrustManager spec for details. 46 * 47 * <li>TLS client. 48 * 49 * <li>Code signing. 50 * 51 * <li>JCE code signing. Some early JCE code signing certs issued to 52 * providers had incorrect extensions. In this mode the checks 53 * are relaxed compared to standard code signing checks in order to 54 * allow these certificates to pass. 55 * 56 * <li>Plugin code signing. WebStart and Plugin require their own variant 57 * which is equivalent to VAR_CODE_SIGNING with additional checks for 58 * compatibility/special cases. See also PKIXValidator. 59 * 60 * <li>TSA Server (see RFC 3161, section 2.3). 61 * 62 * </ul> 63 * 64 * @author Andreas Sterbenz 65 */ 66 class EndEntityChecker { 67 68 // extended key usage OIDs for TLS server, TLS client, code signing 69 // and any usage 70 71 private static final String OID_EXTENDED_KEY_USAGE = 72 SimpleValidator.OID_EXTENDED_KEY_USAGE; 73 74 private static final String OID_EKU_TLS_SERVER = 75 KnownOIDs.serverAuth.value(); 76 77 private static final String OID_EKU_TLS_CLIENT = 78 KnownOIDs.clientAuth.value(); 79 80 private static final String OID_EKU_CODE_SIGNING = 81 KnownOIDs.codeSigning.value(); 82 83 private static final String OID_EKU_TIME_STAMPING = 84 KnownOIDs.KP_TimeStamping.value(); 85 86 private static final String OID_EKU_ANY_USAGE = 87 KnownOIDs.anyExtendedKeyUsage.value(); 88 89 // the Netscape Server-Gated-Cryptography EKU extension OID 90 private static final String OID_EKU_NS_SGC = 91 KnownOIDs.NETSCAPE_ExportApproved.value(); 92 93 // the Microsoft Server-Gated-Cryptography EKU extension OID 94 private static final String OID_EKU_MS_SGC = 95 KnownOIDs.MICROSOFT_ExportApproved.value(); 96 97 // the recognized extension OIDs 98 private static final String OID_SUBJECT_ALT_NAME = 99 KnownOIDs.SubjectAlternativeName.value(); 100 101 private static final String NSCT_SSL_CLIENT = 102 NetscapeCertTypeExtension.SSL_CLIENT; 103 104 private static final String NSCT_SSL_SERVER = 105 NetscapeCertTypeExtension.SSL_SERVER; 106 107 private static final String NSCT_CODE_SIGNING = 108 NetscapeCertTypeExtension.OBJECT_SIGNING; 109 110 // bit numbers in the key usage extension 111 private static final int KU_SIGNATURE = 0; 112 private static final int KU_KEY_ENCIPHERMENT = 2; 113 private static final int KU_KEY_AGREEMENT = 4; 114 115 // TLS key exchange algorithms requiring digitalSignature key usage 116 private static final Collection<String> KU_SERVER_SIGNATURE = 117 Arrays.asList("DHE_DSS", "DHE_RSA", "ECDHE_ECDSA", "ECDHE_RSA", 118 "RSA_EXPORT", "UNKNOWN"); 119 120 // TLS key exchange algorithms requiring keyEncipherment key usage 121 private static final Collection<String> KU_SERVER_ENCRYPTION = 122 Arrays.asList("RSA"); 123 124 // TLS key exchange algorithms requiring keyAgreement key usage 125 private static final Collection<String> KU_SERVER_KEY_AGREEMENT = 126 Arrays.asList("DH_DSS", "DH_RSA", "ECDH_ECDSA", "ECDH_RSA"); 127 128 // variant of this end entity cert checker 129 private final String variant; 130 131 // type of the validator this checker belongs to 132 private final String type; 133 EndEntityChecker(String type, String variant)134 private EndEntityChecker(String type, String variant) { 135 this.type = type; 136 this.variant = variant; 137 } 138 getInstance(String type, String variant)139 static EndEntityChecker getInstance(String type, String variant) { 140 return new EndEntityChecker(type, variant); 141 } 142 check(X509Certificate[] chain, Object parameter, boolean checkUnresolvedCritExts)143 void check(X509Certificate[] chain, Object parameter, 144 boolean checkUnresolvedCritExts) throws CertificateException { 145 146 if (variant.equals(Validator.VAR_GENERIC)) { 147 return; // no checks 148 } 149 150 Set<String> exts = getCriticalExtensions(chain[0]); 151 if (variant.equals(Validator.VAR_TLS_SERVER)) { 152 checkTLSServer(chain[0], (String)parameter, exts); 153 } else if (variant.equals(Validator.VAR_TLS_CLIENT)) { 154 checkTLSClient(chain[0], exts); 155 } else if (variant.equals(Validator.VAR_CODE_SIGNING)) { 156 checkCodeSigning(chain[0], exts); 157 } else if (variant.equals(Validator.VAR_JCE_SIGNING)) { 158 checkCodeSigning(chain[0], exts); 159 } else if (variant.equals(Validator.VAR_PLUGIN_CODE_SIGNING)) { 160 checkCodeSigning(chain[0], exts); 161 } else if (variant.equals(Validator.VAR_TSA_SERVER)) { 162 checkTSAServer(chain[0], exts); 163 } else { 164 throw new CertificateException("Unknown variant: " + variant); 165 } 166 167 // if neither VAR_GENERIC variant nor unknown variant 168 if (checkUnresolvedCritExts) { 169 checkRemainingExtensions(exts); 170 } 171 172 // check if certificate should be distrusted according to policies 173 // set in the jdk.security.caDistrustPolicies security property 174 for (CADistrustPolicy policy : CADistrustPolicy.POLICIES) { 175 policy.checkDistrust(variant, chain); 176 } 177 } 178 179 /** 180 * Utility method returning the Set of critical extensions for 181 * certificate cert (never null). 182 */ getCriticalExtensions(X509Certificate cert)183 private Set<String> getCriticalExtensions(X509Certificate cert) { 184 Set<String> exts = cert.getCriticalExtensionOIDs(); 185 if (exts == null) { 186 exts = Collections.emptySet(); 187 } 188 return exts; 189 } 190 191 /** 192 * Utility method checking if there are any unresolved critical extensions. 193 * @throws CertificateException if so. 194 */ checkRemainingExtensions(Set<String> exts)195 private void checkRemainingExtensions(Set<String> exts) 196 throws CertificateException { 197 // basic constraints irrelevant in EE certs 198 exts.remove(SimpleValidator.OID_BASIC_CONSTRAINTS); 199 200 // If the subject field contains an empty sequence, the subjectAltName 201 // extension MUST be marked critical. 202 // We do not check the validity of the critical extension, just mark 203 // it recognizable here. 204 exts.remove(OID_SUBJECT_ALT_NAME); 205 206 if (!exts.isEmpty()) { 207 throw new CertificateException("Certificate contains unsupported " 208 + "critical extensions: " + exts); 209 } 210 } 211 212 /** 213 * Utility method checking if the extended key usage extension in 214 * certificate cert allows use for expectedEKU. 215 */ checkEKU(X509Certificate cert, Set<String> exts, String expectedEKU)216 private boolean checkEKU(X509Certificate cert, Set<String> exts, 217 String expectedEKU) throws CertificateException { 218 List<String> eku = cert.getExtendedKeyUsage(); 219 if (eku == null) { 220 return true; 221 } 222 return eku.contains(expectedEKU) || eku.contains(OID_EKU_ANY_USAGE); 223 } 224 225 /** 226 * Utility method checking if bit 'bit' is set in this certificates 227 * key usage extension. 228 * @throws CertificateException if not 229 */ checkKeyUsage(X509Certificate cert, int bit)230 private boolean checkKeyUsage(X509Certificate cert, int bit) 231 throws CertificateException { 232 boolean[] keyUsage = cert.getKeyUsage(); 233 if (keyUsage == null) { 234 return true; 235 } 236 return (keyUsage.length > bit) && keyUsage[bit]; 237 } 238 239 /** 240 * Check whether this certificate can be used for TLS client 241 * authentication. 242 * @throws CertificateException if not. 243 */ checkTLSClient(X509Certificate cert, Set<String> exts)244 private void checkTLSClient(X509Certificate cert, Set<String> exts) 245 throws CertificateException { 246 if (checkKeyUsage(cert, KU_SIGNATURE) == false) { 247 throw new ValidatorException 248 ("KeyUsage does not allow digital signatures", 249 ValidatorException.T_EE_EXTENSIONS, cert); 250 } 251 252 if (checkEKU(cert, exts, OID_EKU_TLS_CLIENT) == false) { 253 throw new ValidatorException("Extended key usage does not " 254 + "permit use for TLS client authentication", 255 ValidatorException.T_EE_EXTENSIONS, cert); 256 } 257 258 if (!SimpleValidator.getNetscapeCertTypeBit(cert, NSCT_SSL_CLIENT)) { 259 throw new ValidatorException 260 ("Netscape cert type does not permit use for SSL client", 261 ValidatorException.T_EE_EXTENSIONS, cert); 262 } 263 264 // remove extensions we checked 265 exts.remove(SimpleValidator.OID_KEY_USAGE); 266 exts.remove(SimpleValidator.OID_EXTENDED_KEY_USAGE); 267 exts.remove(SimpleValidator.OID_NETSCAPE_CERT_TYPE); 268 } 269 270 /** 271 * Check whether this certificate can be used for TLS server authentication 272 * using the specified authentication type parameter. See X509TrustManager 273 * specification for details. 274 * @throws CertificateException if not. 275 */ checkTLSServer(X509Certificate cert, String parameter, Set<String> exts)276 private void checkTLSServer(X509Certificate cert, String parameter, 277 Set<String> exts) throws CertificateException { 278 if (KU_SERVER_ENCRYPTION.contains(parameter)) { 279 if (checkKeyUsage(cert, KU_KEY_ENCIPHERMENT) == false) { 280 throw new ValidatorException 281 ("KeyUsage does not allow key encipherment", 282 ValidatorException.T_EE_EXTENSIONS, cert); 283 } 284 } else if (KU_SERVER_SIGNATURE.contains(parameter)) { 285 if (checkKeyUsage(cert, KU_SIGNATURE) == false) { 286 throw new ValidatorException 287 ("KeyUsage does not allow digital signatures", 288 ValidatorException.T_EE_EXTENSIONS, cert); 289 } 290 } else if (KU_SERVER_KEY_AGREEMENT.contains(parameter)) { 291 if (checkKeyUsage(cert, KU_KEY_AGREEMENT) == false) { 292 throw new ValidatorException 293 ("KeyUsage does not allow key agreement", 294 ValidatorException.T_EE_EXTENSIONS, cert); 295 } 296 } else { 297 throw new CertificateException("Unknown authType: " + parameter); 298 } 299 300 if (checkEKU(cert, exts, OID_EKU_TLS_SERVER) == false) { 301 // check for equivalent but now obsolete Server-Gated-Cryptography 302 // (aka Step-Up, 128 bit) EKU OIDs 303 if ((checkEKU(cert, exts, OID_EKU_MS_SGC) == false) && 304 (checkEKU(cert, exts, OID_EKU_NS_SGC) == false)) { 305 throw new ValidatorException 306 ("Extended key usage does not permit use for TLS " 307 + "server authentication", 308 ValidatorException.T_EE_EXTENSIONS, cert); 309 } 310 } 311 312 if (!SimpleValidator.getNetscapeCertTypeBit(cert, NSCT_SSL_SERVER)) { 313 throw new ValidatorException 314 ("Netscape cert type does not permit use for SSL server", 315 ValidatorException.T_EE_EXTENSIONS, cert); 316 } 317 318 // remove extensions we checked 319 exts.remove(SimpleValidator.OID_KEY_USAGE); 320 exts.remove(SimpleValidator.OID_EXTENDED_KEY_USAGE); 321 exts.remove(SimpleValidator.OID_NETSCAPE_CERT_TYPE); 322 } 323 324 /** 325 * Check whether this certificate can be used for code signing. 326 * @throws CertificateException if not. 327 */ checkCodeSigning(X509Certificate cert, Set<String> exts)328 private void checkCodeSigning(X509Certificate cert, Set<String> exts) 329 throws CertificateException { 330 if (checkKeyUsage(cert, KU_SIGNATURE) == false) { 331 throw new ValidatorException 332 ("KeyUsage does not allow digital signatures", 333 ValidatorException.T_EE_EXTENSIONS, cert); 334 } 335 336 if (checkEKU(cert, exts, OID_EKU_CODE_SIGNING) == false) { 337 throw new ValidatorException 338 ("Extended key usage does not permit use for code signing", 339 ValidatorException.T_EE_EXTENSIONS, cert); 340 } 341 342 // do not check Netscape cert type for JCE code signing checks 343 // (some certs were issued with incorrect extensions) 344 if (variant.equals(Validator.VAR_JCE_SIGNING) == false) { 345 if (!SimpleValidator.getNetscapeCertTypeBit(cert, NSCT_CODE_SIGNING)) { 346 throw new ValidatorException 347 ("Netscape cert type does not permit use for code signing", 348 ValidatorException.T_EE_EXTENSIONS, cert); 349 } 350 exts.remove(SimpleValidator.OID_NETSCAPE_CERT_TYPE); 351 } 352 353 // remove extensions we checked 354 exts.remove(SimpleValidator.OID_KEY_USAGE); 355 exts.remove(SimpleValidator.OID_EXTENDED_KEY_USAGE); 356 } 357 358 /** 359 * Check whether this certificate can be used by a time stamping authority 360 * server (see RFC 3161, section 2.3). 361 * @throws CertificateException if not. 362 */ checkTSAServer(X509Certificate cert, Set<String> exts)363 private void checkTSAServer(X509Certificate cert, Set<String> exts) 364 throws CertificateException { 365 if (checkKeyUsage(cert, KU_SIGNATURE) == false) { 366 throw new ValidatorException 367 ("KeyUsage does not allow digital signatures", 368 ValidatorException.T_EE_EXTENSIONS, cert); 369 } 370 371 if (cert.getExtendedKeyUsage() == null) { 372 throw new ValidatorException 373 ("Certificate does not contain an extended key usage " + 374 "extension required for a TSA server", 375 ValidatorException.T_EE_EXTENSIONS, cert); 376 } 377 378 if (checkEKU(cert, exts, OID_EKU_TIME_STAMPING) == false) { 379 throw new ValidatorException 380 ("Extended key usage does not permit use for TSA server", 381 ValidatorException.T_EE_EXTENSIONS, cert); 382 } 383 384 // remove extensions we checked 385 exts.remove(SimpleValidator.OID_KEY_USAGE); 386 exts.remove(SimpleValidator.OID_EXTENDED_KEY_USAGE); 387 } 388 } 389