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