1 /* 2 * Copyright (c) 2002, 2019, 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 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 final static String OID_EXTENDED_KEY_USAGE = 72 SimpleValidator.OID_EXTENDED_KEY_USAGE; 73 74 private final static String OID_EKU_TLS_SERVER = "1.3.6.1.5.5.7.3.1"; 75 76 private final static String OID_EKU_TLS_CLIENT = "1.3.6.1.5.5.7.3.2"; 77 78 private final static String OID_EKU_CODE_SIGNING = "1.3.6.1.5.5.7.3.3"; 79 80 private final static String OID_EKU_TIME_STAMPING = "1.3.6.1.5.5.7.3.8"; 81 82 private final static String OID_EKU_ANY_USAGE = "2.5.29.37.0"; 83 84 // the Netscape Server-Gated-Cryptography EKU extension OID 85 private final static String OID_EKU_NS_SGC = "2.16.840.1.113730.4.1"; 86 87 // the Microsoft Server-Gated-Cryptography EKU extension OID 88 private final static String OID_EKU_MS_SGC = "1.3.6.1.4.1.311.10.3.3"; 89 90 // the recognized extension OIDs 91 private final static String OID_SUBJECT_ALT_NAME = "2.5.29.17"; 92 93 private final static String NSCT_SSL_CLIENT = 94 NetscapeCertTypeExtension.SSL_CLIENT; 95 96 private final static String NSCT_SSL_SERVER = 97 NetscapeCertTypeExtension.SSL_SERVER; 98 99 private final static String NSCT_CODE_SIGNING = 100 NetscapeCertTypeExtension.OBJECT_SIGNING; 101 102 // bit numbers in the key usage extension 103 private final static int KU_SIGNATURE = 0; 104 private final static int KU_KEY_ENCIPHERMENT = 2; 105 private final static int KU_KEY_AGREEMENT = 4; 106 107 // TLS key exchange algorithms requiring digitalSignature key usage 108 private final static Collection<String> KU_SERVER_SIGNATURE = 109 Arrays.asList("DHE_DSS", "DHE_RSA", "ECDHE_ECDSA", "ECDHE_RSA", 110 "RSA_EXPORT", "UNKNOWN"); 111 112 // TLS key exchange algorithms requiring keyEncipherment key usage 113 private final static Collection<String> KU_SERVER_ENCRYPTION = 114 Arrays.asList("RSA"); 115 116 // TLS key exchange algorithms requiring keyAgreement key usage 117 private final static Collection<String> KU_SERVER_KEY_AGREEMENT = 118 Arrays.asList("DH_DSS", "DH_RSA", "ECDH_ECDSA", "ECDH_RSA"); 119 120 // variant of this end entity cert checker 121 private final String variant; 122 123 // type of the validator this checker belongs to 124 private final String type; 125 126 private EndEntityChecker(String type, String variant) { 127 this.type = type; 128 this.variant = variant; 129 } 130 131 static EndEntityChecker getInstance(String type, String variant) { 132 return new EndEntityChecker(type, variant); 133 } 134 135 void check(X509Certificate[] chain, Object parameter, 136 boolean checkUnresolvedCritExts) 137 throws CertificateException { 138 if (variant.equals(Validator.VAR_GENERIC)) { 139 return; // no checks 140 } 141 142 Set<String> exts = getCriticalExtensions(chain[0]); 143 if (variant.equals(Validator.VAR_TLS_SERVER)) { 144 checkTLSServer(chain[0], (String)parameter, exts); 145 } else if (variant.equals(Validator.VAR_TLS_CLIENT)) { 146 checkTLSClient(chain[0], exts); 147 } else if (variant.equals(Validator.VAR_CODE_SIGNING)) { 148 checkCodeSigning(chain[0], exts); 149 } else if (variant.equals(Validator.VAR_JCE_SIGNING)) { 150 checkCodeSigning(chain[0], exts); 151 } else if (variant.equals(Validator.VAR_PLUGIN_CODE_SIGNING)) { 152 checkCodeSigning(chain[0], exts); 153 } else if (variant.equals(Validator.VAR_TSA_SERVER)) { 154 checkTSAServer(chain[0], exts); 155 } else { 156 throw new CertificateException("Unknown variant: " + variant); 157 } 158 159 // if neither VAR_GENERIC variant nor unknown variant 160 if (checkUnresolvedCritExts) { 161 checkRemainingExtensions(exts); 162 } 163 164 // check if certificate should be distrusted according to policies 165 // set in the jdk.security.caDistrustPolicies security property 166 for (CADistrustPolicy policy : CADistrustPolicy.POLICIES) { 167 policy.checkDistrust(variant, chain); 168 } 169 } 170 171 /** 172 * Utility method returning the Set of critical extensions for 173 * certificate cert (never null). 174 */ 175 private Set<String> getCriticalExtensions(X509Certificate cert) { 176 Set<String> exts = cert.getCriticalExtensionOIDs(); 177 if (exts == null) { 178 exts = Collections.emptySet(); 179 } 180 return exts; 181 } 182 183 /** 184 * Utility method checking if there are any unresolved critical extensions. 185 * @throws CertificateException if so. 186 */ 187 private void checkRemainingExtensions(Set<String> exts) 188 throws CertificateException { 189 // basic constraints irrelevant in EE certs 190 exts.remove(SimpleValidator.OID_BASIC_CONSTRAINTS); 191 192 // If the subject field contains an empty sequence, the subjectAltName 193 // extension MUST be marked critical. 194 // We do not check the validity of the critical extension, just mark 195 // it recognizable here. 196 exts.remove(OID_SUBJECT_ALT_NAME); 197 198 if (!exts.isEmpty()) { 199 throw new CertificateException("Certificate contains unsupported " 200 + "critical extensions: " + exts); 201 } 202 } 203 204 /** 205 * Utility method checking if the extended key usage extension in 206 * certificate cert allows use for expectedEKU. 207 */ 208 private boolean checkEKU(X509Certificate cert, Set<String> exts, 209 String expectedEKU) throws CertificateException { 210 List<String> eku = cert.getExtendedKeyUsage(); 211 if (eku == null) { 212 return true; 213 } 214 return eku.contains(expectedEKU) || eku.contains(OID_EKU_ANY_USAGE); 215 } 216 217 /** 218 * Utility method checking if bit 'bit' is set in this certificates 219 * key usage extension. 220 * @throws CertificateException if not 221 */ 222 private boolean checkKeyUsage(X509Certificate cert, int bit) 223 throws CertificateException { 224 boolean[] keyUsage = cert.getKeyUsage(); 225 if (keyUsage == null) { 226 return true; 227 } 228 return (keyUsage.length > bit) && keyUsage[bit]; 229 } 230 231 /** 232 * Check whether this certificate can be used for TLS client 233 * authentication. 234 * @throws CertificateException if not. 235 */ 236 private void checkTLSClient(X509Certificate cert, Set<String> exts) 237 throws CertificateException { 238 if (checkKeyUsage(cert, KU_SIGNATURE) == false) { 239 throw new ValidatorException 240 ("KeyUsage does not allow digital signatures", 241 ValidatorException.T_EE_EXTENSIONS, cert); 242 } 243 244 if (checkEKU(cert, exts, OID_EKU_TLS_CLIENT) == false) { 245 throw new ValidatorException("Extended key usage does not " 246 + "permit use for TLS client authentication", 247 ValidatorException.T_EE_EXTENSIONS, cert); 248 } 249 250 if (!SimpleValidator.getNetscapeCertTypeBit(cert, NSCT_SSL_CLIENT)) { 251 throw new ValidatorException 252 ("Netscape cert type does not permit use for SSL client", 253 ValidatorException.T_EE_EXTENSIONS, cert); 254 } 255 256 // remove extensions we checked 257 exts.remove(SimpleValidator.OID_KEY_USAGE); 258 exts.remove(SimpleValidator.OID_EXTENDED_KEY_USAGE); 259 exts.remove(SimpleValidator.OID_NETSCAPE_CERT_TYPE); 260 } 261 262 /** 263 * Check whether this certificate can be used for TLS server authentication 264 * using the specified authentication type parameter. See X509TrustManager 265 * specification for details. 266 * @throws CertificateException if not. 267 */ 268 private void checkTLSServer(X509Certificate cert, String parameter, 269 Set<String> exts) throws CertificateException { 270 if (KU_SERVER_ENCRYPTION.contains(parameter)) { 271 if (checkKeyUsage(cert, KU_KEY_ENCIPHERMENT) == false) { 272 throw new ValidatorException 273 ("KeyUsage does not allow key encipherment", 274 ValidatorException.T_EE_EXTENSIONS, cert); 275 } 276 } else if (KU_SERVER_SIGNATURE.contains(parameter)) { 277 if (checkKeyUsage(cert, KU_SIGNATURE) == false) { 278 throw new ValidatorException 279 ("KeyUsage does not allow digital signatures", 280 ValidatorException.T_EE_EXTENSIONS, cert); 281 } 282 } else if (KU_SERVER_KEY_AGREEMENT.contains(parameter)) { 283 if (checkKeyUsage(cert, KU_KEY_AGREEMENT) == false) { 284 throw new ValidatorException 285 ("KeyUsage does not allow key agreement", 286 ValidatorException.T_EE_EXTENSIONS, cert); 287 } 288 } else { 289 throw new CertificateException("Unknown authType: " + parameter); 290 } 291 292 if (checkEKU(cert, exts, OID_EKU_TLS_SERVER) == false) { 293 // check for equivalent but now obsolete Server-Gated-Cryptography 294 // (aka Step-Up, 128 bit) EKU OIDs 295 if ((checkEKU(cert, exts, OID_EKU_MS_SGC) == false) && 296 (checkEKU(cert, exts, OID_EKU_NS_SGC) == false)) { 297 throw new ValidatorException 298 ("Extended key usage does not permit use for TLS " 299 + "server authentication", 300 ValidatorException.T_EE_EXTENSIONS, cert); 301 } 302 } 303 304 if (!SimpleValidator.getNetscapeCertTypeBit(cert, NSCT_SSL_SERVER)) { 305 throw new ValidatorException 306 ("Netscape cert type does not permit use for SSL server", 307 ValidatorException.T_EE_EXTENSIONS, cert); 308 } 309 310 // remove extensions we checked 311 exts.remove(SimpleValidator.OID_KEY_USAGE); 312 exts.remove(SimpleValidator.OID_EXTENDED_KEY_USAGE); 313 exts.remove(SimpleValidator.OID_NETSCAPE_CERT_TYPE); 314 } 315 316 /** 317 * Check whether this certificate can be used for code signing. 318 * @throws CertificateException if not. 319 */ 320 private void checkCodeSigning(X509Certificate cert, Set<String> exts) 321 throws CertificateException { 322 if (checkKeyUsage(cert, KU_SIGNATURE) == false) { 323 throw new ValidatorException 324 ("KeyUsage does not allow digital signatures", 325 ValidatorException.T_EE_EXTENSIONS, cert); 326 } 327 328 if (checkEKU(cert, exts, OID_EKU_CODE_SIGNING) == false) { 329 throw new ValidatorException 330 ("Extended key usage does not permit use for code signing", 331 ValidatorException.T_EE_EXTENSIONS, cert); 332 } 333 334 // do not check Netscape cert type for JCE code signing checks 335 // (some certs were issued with incorrect extensions) 336 if (variant.equals(Validator.VAR_JCE_SIGNING) == false) { 337 if (!SimpleValidator.getNetscapeCertTypeBit(cert, NSCT_CODE_SIGNING)) { 338 throw new ValidatorException 339 ("Netscape cert type does not permit use for code signing", 340 ValidatorException.T_EE_EXTENSIONS, cert); 341 } 342 exts.remove(SimpleValidator.OID_NETSCAPE_CERT_TYPE); 343 } 344 345 // remove extensions we checked 346 exts.remove(SimpleValidator.OID_KEY_USAGE); 347 exts.remove(SimpleValidator.OID_EXTENDED_KEY_USAGE); 348 } 349 350 /** 351 * Check whether this certificate can be used by a time stamping authority 352 * server (see RFC 3161, section 2.3). 353 * @throws CertificateException if not. 354 */ 355 private void checkTSAServer(X509Certificate cert, Set<String> exts) 356 throws CertificateException { 357 if (checkKeyUsage(cert, KU_SIGNATURE) == false) { 358 throw new ValidatorException 359 ("KeyUsage does not allow digital signatures", 360 ValidatorException.T_EE_EXTENSIONS, cert); 361 } 362 363 if (cert.getExtendedKeyUsage() == null) { 364 throw new ValidatorException 365 ("Certificate does not contain an extended key usage " + 366 "extension required for a TSA server", 367 ValidatorException.T_EE_EXTENSIONS, cert); 368 } 369 370 if (checkEKU(cert, exts, OID_EKU_TIME_STAMPING) == false) { 371 throw new ValidatorException 372 ("Extended key usage does not permit use for TSA server", 373 ValidatorException.T_EE_EXTENSIONS, cert); 374 } 375 376 // remove extensions we checked 377 exts.remove(SimpleValidator.OID_KEY_USAGE); 378 exts.remove(SimpleValidator.OID_EXTENDED_KEY_USAGE); 379 } 380 }