blob: 78681c54a51b3a26cf104f9040a24ff2fff105dd [file] [log] [blame]
Adam Langley57707c72016-01-14 11:25:12 -08001/*
2 * Written by Dr Stephen N Henson (steve@openssl.org) for the OpenSSL project
3 * 2001.
Adam Langley95c29f32014-06-20 12:00:00 -07004 */
5/* ====================================================================
6 * Copyright (c) 1999-2004 The OpenSSL Project. All rights reserved.
7 *
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
10 * are met:
11 *
12 * 1. Redistributions of source code must retain the above copyright
Adam Langley57707c72016-01-14 11:25:12 -080013 * notice, this list of conditions and the following disclaimer.
Adam Langley95c29f32014-06-20 12:00:00 -070014 *
15 * 2. Redistributions in binary form must reproduce the above copyright
16 * notice, this list of conditions and the following disclaimer in
17 * the documentation and/or other materials provided with the
18 * distribution.
19 *
20 * 3. All advertising materials mentioning features or use of this
21 * software must display the following acknowledgment:
22 * "This product includes software developed by the OpenSSL Project
23 * for use in the OpenSSL Toolkit. (http://www.OpenSSL.org/)"
24 *
25 * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to
26 * endorse or promote products derived from this software without
27 * prior written permission. For written permission, please contact
28 * licensing@OpenSSL.org.
29 *
30 * 5. Products derived from this software may not be called "OpenSSL"
31 * nor may "OpenSSL" appear in their names without prior written
32 * permission of the OpenSSL Project.
33 *
34 * 6. Redistributions of any form whatsoever must retain the following
35 * acknowledgment:
36 * "This product includes software developed by the OpenSSL Project
37 * for use in the OpenSSL Toolkit (http://www.OpenSSL.org/)"
38 *
39 * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY
40 * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
41 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
42 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE OpenSSL PROJECT OR
43 * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
44 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
45 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
46 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
47 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
48 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
49 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
50 * OF THE POSSIBILITY OF SUCH DAMAGE.
51 * ====================================================================
52 *
53 * This product includes cryptographic software written by Eric Young
54 * (eay@cryptsoft.com). This product includes software written by Tim
55 * Hudson (tjh@cryptsoft.com). */
56
Adam Langley2b2d66d2015-01-30 17:08:37 -080057#include <string.h>
58
Adam Langley95c29f32014-06-20 12:00:00 -070059#include <openssl/digest.h>
David Benjamin260a10c2022-06-16 13:58:28 -040060#include <openssl/err.h>
Adam Langley95c29f32014-06-20 12:00:00 -070061#include <openssl/mem.h>
62#include <openssl/obj.h>
Brian Smith054e6822015-03-27 21:12:01 -100063#include <openssl/thread.h>
David Benjamin58906ea2023-11-20 23:59:49 -050064#include <openssl/x509.h>
Adam Langley95c29f32014-06-20 12:00:00 -070065
Adam Langley4bdb6e42015-05-15 15:29:21 -070066#include "../internal.h"
David Benjaminfd86eaa2020-06-17 15:13:16 -040067#include "internal.h"
Adam Langley4bdb6e42015-05-15 15:29:21 -070068
David Benjamin1b085022023-12-26 07:58:45 -050069
70struct x509_purpose_st {
71 int purpose;
72 int trust; // Default trust ID
73 int (*check_purpose)(const struct x509_purpose_st *, const X509 *, int);
74 const char *sname;
75} /* X509_PURPOSE */;
76
David Benjamin260a10c2022-06-16 13:58:28 -040077#define V1_ROOT (EXFLAG_V1 | EXFLAG_SS)
David Benjamin0ea470f2015-10-23 18:08:51 -040078#define ku_reject(x, usage) \
David Benjamin260a10c2022-06-16 13:58:28 -040079 (((x)->ex_flags & EXFLAG_KUSAGE) && !((x)->ex_kusage & (usage)))
David Benjamin0ea470f2015-10-23 18:08:51 -040080#define xku_reject(x, usage) \
David Benjamin260a10c2022-06-16 13:58:28 -040081 (((x)->ex_flags & EXFLAG_XKUSAGE) && !((x)->ex_xkusage & (usage)))
David Benjamin0ea470f2015-10-23 18:08:51 -040082
David Benjamin5507ccd2023-12-26 00:41:06 -050083static int check_ca(const X509 *x);
Adam Langley57707c72016-01-14 11:25:12 -080084static int check_purpose_ssl_client(const X509_PURPOSE *xp, const X509 *x,
85 int ca);
86static int check_purpose_ssl_server(const X509_PURPOSE *xp, const X509 *x,
87 int ca);
88static int check_purpose_ns_ssl_server(const X509_PURPOSE *xp, const X509 *x,
89 int ca);
Adam Langley57707c72016-01-14 11:25:12 -080090static int check_purpose_smime_sign(const X509_PURPOSE *xp, const X509 *x,
91 int ca);
92static int check_purpose_smime_encrypt(const X509_PURPOSE *xp, const X509 *x,
93 int ca);
94static int check_purpose_crl_sign(const X509_PURPOSE *xp, const X509 *x,
95 int ca);
96static int check_purpose_timestamp_sign(const X509_PURPOSE *xp, const X509 *x,
97 int ca);
Adam Langley95c29f32014-06-20 12:00:00 -070098static int no_check(const X509_PURPOSE *xp, const X509 *x, int ca);
Adam Langley95c29f32014-06-20 12:00:00 -070099
David Benjamin5a1a5fb2023-12-26 01:35:36 -0500100// X509_TRUST_NONE is not a valid |X509_TRUST_*| constant. It is used by
101// |X509_PURPOSE_ANY| to indicate that it has no corresponding trust type and
102// cannot be used with |X509_STORE_CTX_set_purpose|.
103#define X509_TRUST_NONE (-1)
104
David Benjamin6099ab92023-12-02 17:20:35 -0500105static const X509_PURPOSE xstandard[] = {
David Benjamin1b085022023-12-26 07:58:45 -0500106 {X509_PURPOSE_SSL_CLIENT, X509_TRUST_SSL_CLIENT, check_purpose_ssl_client,
107 "sslclient"},
108 {X509_PURPOSE_SSL_SERVER, X509_TRUST_SSL_SERVER, check_purpose_ssl_server,
109 "sslserver"},
110 {X509_PURPOSE_NS_SSL_SERVER, X509_TRUST_SSL_SERVER,
111 check_purpose_ns_ssl_server, "nssslserver"},
112 {X509_PURPOSE_SMIME_SIGN, X509_TRUST_EMAIL, check_purpose_smime_sign,
113 "smimesign"},
114 {X509_PURPOSE_SMIME_ENCRYPT, X509_TRUST_EMAIL, check_purpose_smime_encrypt,
115 "smimeencrypt"},
116 {X509_PURPOSE_CRL_SIGN, X509_TRUST_COMPAT, check_purpose_crl_sign,
117 "crlsign"},
118 {X509_PURPOSE_ANY, X509_TRUST_NONE, no_check, "any"},
David Benjamin5507ccd2023-12-26 00:41:06 -0500119 // |X509_PURPOSE_OCSP_HELPER| performs no actual checks. OpenSSL's OCSP
120 // implementation relied on the caller performing EKU and KU checks.
David Benjamin1b085022023-12-26 07:58:45 -0500121 {X509_PURPOSE_OCSP_HELPER, X509_TRUST_COMPAT, no_check, "ocsphelper"},
122 {X509_PURPOSE_TIMESTAMP_SIGN, X509_TRUST_TSA, check_purpose_timestamp_sign,
123 "timestampsign"},
Adam Langley95c29f32014-06-20 12:00:00 -0700124};
125
David Benjamin260a10c2022-06-16 13:58:28 -0400126int X509_check_purpose(X509 *x, int id, int ca) {
David Benjamin0c8bc462023-12-25 22:52:22 -0500127 // This differs from OpenSSL, which uses -1 to indicate a fatal error and 0 to
128 // indicate an invalid certificate. BoringSSL uses 0 for both.
David Benjamin260a10c2022-06-16 13:58:28 -0400129 if (!x509v3_cache_extensions(x)) {
David Benjamin0c8bc462023-12-25 22:52:22 -0500130 return 0;
David Benjamin260a10c2022-06-16 13:58:28 -0400131 }
132
David Benjaminc0b87a02022-06-16 14:02:15 -0400133 if (id == -1) {
David Benjamin260a10c2022-06-16 13:58:28 -0400134 return 1;
David Benjaminc0b87a02022-06-16 14:02:15 -0400135 }
David Benjamin8e6a26d2023-12-26 08:28:47 -0500136 const X509_PURPOSE *pt = X509_PURPOSE_get0(id);
137 if (pt == NULL) {
David Benjamin0c8bc462023-12-25 22:52:22 -0500138 return 0;
David Benjaminc0b87a02022-06-16 14:02:15 -0400139 }
David Benjamin5507ccd2023-12-26 00:41:06 -0500140 // Historically, |check_purpose| implementations other than |X509_PURPOSE_ANY|
141 // called |check_ca|. This is redundant with the |X509_V_ERR_INVALID_CA|
142 // logic, but |X509_check_purpose| is public API, so we preserve this
143 // behavior.
144 if (ca && id != X509_PURPOSE_ANY && !check_ca(x)) {
145 return 0;
146 }
David Benjamin260a10c2022-06-16 13:58:28 -0400147 return pt->check_purpose(pt, x, ca);
Adam Langley95c29f32014-06-20 12:00:00 -0700148}
149
David Benjamin8e6a26d2023-12-26 08:28:47 -0500150const X509_PURPOSE *X509_PURPOSE_get0(int id) {
151 for (size_t i = 0; i < OPENSSL_ARRAY_SIZE(xstandard); i++) {
152 if (xstandard[i].purpose == id) {
153 return &xstandard[i];
154 }
David Benjamin260a10c2022-06-16 13:58:28 -0400155 }
David Benjamin8e6a26d2023-12-26 08:28:47 -0500156 return NULL;
David Benjamin260a10c2022-06-16 13:58:28 -0400157}
158
David Benjamincbb96b42023-06-04 12:50:39 -0400159int X509_PURPOSE_get_by_sname(const char *sname) {
David Benjamin8e6a26d2023-12-26 08:28:47 -0500160 for (size_t i = 0; i < OPENSSL_ARRAY_SIZE(xstandard); i++) {
161 if (strcmp(xstandard[i].sname, sname) == 0) {
162 return xstandard[i].purpose;
David Benjamin0beff262023-12-25 16:41:55 -0500163 }
David Benjaminc0b87a02022-06-16 14:02:15 -0400164 }
David Benjamin396f2ef2023-12-02 09:21:37 -0500165 return -1;
David Benjamin260a10c2022-06-16 13:58:28 -0400166}
167
168int X509_PURPOSE_get_id(const X509_PURPOSE *xp) { return xp->purpose; }
169
David Benjamin260a10c2022-06-16 13:58:28 -0400170int X509_PURPOSE_get_trust(const X509_PURPOSE *xp) { return xp->trust; }
171
David Benjamin09b8fd42022-07-10 19:14:48 -0400172int X509_supported_extension(const X509_EXTENSION *ex) {
David Benjamin7ff31d32023-11-25 00:38:01 -0500173 int nid = OBJ_obj2nid(X509_EXTENSION_get_object(ex));
David Benjamin100e2122023-12-25 23:38:05 -0500174 return nid == NID_key_usage || //
David Benjamin7ff31d32023-11-25 00:38:01 -0500175 nid == NID_subject_alt_name || //
176 nid == NID_basic_constraints || //
177 nid == NID_certificate_policies || //
178 nid == NID_ext_key_usage || //
179 nid == NID_policy_constraints || //
180 nid == NID_name_constraints || //
181 nid == NID_policy_mappings || //
182 nid == NID_inhibit_any_policy;
Adam Langley57707c72016-01-14 11:25:12 -0800183}
Adam Langley95c29f32014-06-20 12:00:00 -0700184
David Benjamin260a10c2022-06-16 13:58:28 -0400185static int setup_dp(X509 *x, DIST_POINT *dp) {
David Benjaminc0b87a02022-06-16 14:02:15 -0400186 if (!dp->distpoint || (dp->distpoint->type != 1)) {
David Benjamin260a10c2022-06-16 13:58:28 -0400187 return 1;
David Benjaminc0b87a02022-06-16 14:02:15 -0400188 }
David Benjamin580c0412023-11-12 14:28:51 -0500189 X509_NAME *iname = NULL;
190 for (size_t i = 0; i < sk_GENERAL_NAME_num(dp->CRLissuer); i++) {
David Benjamin260a10c2022-06-16 13:58:28 -0400191 GENERAL_NAME *gen = sk_GENERAL_NAME_value(dp->CRLissuer, i);
192 if (gen->type == GEN_DIRNAME) {
193 iname = gen->d.directoryName;
194 break;
David Benjamin7d759782016-09-23 19:19:57 -0400195 }
David Benjamin260a10c2022-06-16 13:58:28 -0400196 }
David Benjaminc0b87a02022-06-16 14:02:15 -0400197 if (!iname) {
David Benjamin260a10c2022-06-16 13:58:28 -0400198 iname = X509_get_issuer_name(x);
David Benjaminc0b87a02022-06-16 14:02:15 -0400199 }
David Benjamin7d759782016-09-23 19:19:57 -0400200
David Benjamin260a10c2022-06-16 13:58:28 -0400201 return DIST_POINT_set_dpname(dp->distpoint, iname);
202}
Adam Langley4bdb6e42015-05-15 15:29:21 -0700203
David Benjamin260a10c2022-06-16 13:58:28 -0400204static int setup_crldp(X509 *x) {
205 int j;
206 x->crldp = X509_get_ext_d2i(x, NID_crl_distribution_points, &j, NULL);
207 if (x->crldp == NULL && j != -1) {
208 return 0;
209 }
210 for (size_t i = 0; i < sk_DIST_POINT_num(x->crldp); i++) {
211 if (!setup_dp(x, sk_DIST_POINT_value(x->crldp, i))) {
212 return 0;
Adam Langley57707c72016-01-14 11:25:12 -0800213 }
David Benjamin260a10c2022-06-16 13:58:28 -0400214 }
215 return 1;
216}
Adam Langley95c29f32014-06-20 12:00:00 -0700217
David Benjamin260a10c2022-06-16 13:58:28 -0400218int x509v3_cache_extensions(X509 *x) {
219 BASIC_CONSTRAINTS *bs;
David Benjamin260a10c2022-06-16 13:58:28 -0400220 ASN1_BIT_STRING *usage;
David Benjamin260a10c2022-06-16 13:58:28 -0400221 EXTENDED_KEY_USAGE *extusage;
David Benjamin260a10c2022-06-16 13:58:28 -0400222 size_t i;
223 int j;
Adam Langley95c29f32014-06-20 12:00:00 -0700224
David Benjamin260a10c2022-06-16 13:58:28 -0400225 CRYPTO_MUTEX_lock_read(&x->lock);
226 const int is_set = x->ex_flags & EXFLAG_SET;
227 CRYPTO_MUTEX_unlock_read(&x->lock);
Adam Langley95c29f32014-06-20 12:00:00 -0700228
David Benjamin260a10c2022-06-16 13:58:28 -0400229 if (is_set) {
230 return (x->ex_flags & EXFLAG_INVALID) == 0;
231 }
Adam Langley95c29f32014-06-20 12:00:00 -0700232
David Benjamin260a10c2022-06-16 13:58:28 -0400233 CRYPTO_MUTEX_lock_write(&x->lock);
234 if (x->ex_flags & EXFLAG_SET) {
David Benjamin7d759782016-09-23 19:19:57 -0400235 CRYPTO_MUTEX_unlock_write(&x->lock);
David Benjaminfd86eaa2020-06-17 15:13:16 -0400236 return (x->ex_flags & EXFLAG_INVALID) == 0;
David Benjamin260a10c2022-06-16 13:58:28 -0400237 }
238
David Benjaminc0b87a02022-06-16 14:02:15 -0400239 if (!X509_digest(x, EVP_sha256(), x->cert_hash, NULL)) {
David Benjamin260a10c2022-06-16 13:58:28 -0400240 x->ex_flags |= EXFLAG_INVALID;
David Benjaminc0b87a02022-06-16 14:02:15 -0400241 }
David Benjamin46350482022-06-16 14:03:12 -0400242 // V1 should mean no extensions ...
David Benjaminc0b87a02022-06-16 14:02:15 -0400243 if (X509_get_version(x) == X509_VERSION_1) {
David Benjamin260a10c2022-06-16 13:58:28 -0400244 x->ex_flags |= EXFLAG_V1;
David Benjaminc0b87a02022-06-16 14:02:15 -0400245 }
David Benjamin46350482022-06-16 14:03:12 -0400246 // Handle basic constraints
David Benjamin260a10c2022-06-16 13:58:28 -0400247 if ((bs = X509_get_ext_d2i(x, NID_basic_constraints, &j, NULL))) {
David Benjaminc0b87a02022-06-16 14:02:15 -0400248 if (bs->ca) {
David Benjamin260a10c2022-06-16 13:58:28 -0400249 x->ex_flags |= EXFLAG_CA;
David Benjaminc0b87a02022-06-16 14:02:15 -0400250 }
David Benjamin260a10c2022-06-16 13:58:28 -0400251 if (bs->pathlen) {
252 if ((bs->pathlen->type == V_ASN1_NEG_INTEGER) || !bs->ca) {
253 x->ex_flags |= EXFLAG_INVALID;
254 x->ex_pathlen = 0;
255 } else {
David Benjamin46350482022-06-16 14:03:12 -0400256 // TODO(davidben): |ASN1_INTEGER_get| returns -1 on overflow,
257 // which currently acts as if the constraint isn't present. This
258 // works (an overflowing path length constraint may as well be
259 // infinity), but Chromium's verifier simply treats values above
260 // 255 as an error.
David Benjamin260a10c2022-06-16 13:58:28 -0400261 x->ex_pathlen = ASN1_INTEGER_get(bs->pathlen);
262 }
David Benjaminc0b87a02022-06-16 14:02:15 -0400263 } else {
David Benjamin260a10c2022-06-16 13:58:28 -0400264 x->ex_pathlen = -1;
David Benjaminc0b87a02022-06-16 14:02:15 -0400265 }
David Benjamin260a10c2022-06-16 13:58:28 -0400266 BASIC_CONSTRAINTS_free(bs);
267 x->ex_flags |= EXFLAG_BCONS;
268 } else if (j != -1) {
269 x->ex_flags |= EXFLAG_INVALID;
270 }
David Benjamin46350482022-06-16 14:03:12 -0400271 // Handle key usage
David Benjamin260a10c2022-06-16 13:58:28 -0400272 if ((usage = X509_get_ext_d2i(x, NID_key_usage, &j, NULL))) {
273 if (usage->length > 0) {
274 x->ex_kusage = usage->data[0];
David Benjaminc0b87a02022-06-16 14:02:15 -0400275 if (usage->length > 1) {
David Benjamin260a10c2022-06-16 13:58:28 -0400276 x->ex_kusage |= usage->data[1] << 8;
David Benjaminc0b87a02022-06-16 14:02:15 -0400277 }
278 } else {
David Benjamin260a10c2022-06-16 13:58:28 -0400279 x->ex_kusage = 0;
David Benjaminc0b87a02022-06-16 14:02:15 -0400280 }
David Benjamin260a10c2022-06-16 13:58:28 -0400281 x->ex_flags |= EXFLAG_KUSAGE;
282 ASN1_BIT_STRING_free(usage);
283 } else if (j != -1) {
284 x->ex_flags |= EXFLAG_INVALID;
285 }
286 x->ex_xkusage = 0;
287 if ((extusage = X509_get_ext_d2i(x, NID_ext_key_usage, &j, NULL))) {
288 x->ex_flags |= EXFLAG_XKUSAGE;
289 for (i = 0; i < sk_ASN1_OBJECT_num(extusage); i++) {
290 switch (OBJ_obj2nid(sk_ASN1_OBJECT_value(extusage, i))) {
291 case NID_server_auth:
292 x->ex_xkusage |= XKU_SSL_SERVER;
293 break;
294
295 case NID_client_auth:
296 x->ex_xkusage |= XKU_SSL_CLIENT;
297 break;
298
299 case NID_email_protect:
300 x->ex_xkusage |= XKU_SMIME;
301 break;
302
303 case NID_code_sign:
304 x->ex_xkusage |= XKU_CODE_SIGN;
305 break;
306
307 case NID_ms_sgc:
308 case NID_ns_sgc:
309 x->ex_xkusage |= XKU_SGC;
310 break;
311
312 case NID_OCSP_sign:
313 x->ex_xkusage |= XKU_OCSP_SIGN;
314 break;
315
316 case NID_time_stamp:
317 x->ex_xkusage |= XKU_TIMESTAMP;
318 break;
319
320 case NID_dvcs:
321 x->ex_xkusage |= XKU_DVCS;
322 break;
323
324 case NID_anyExtendedKeyUsage:
325 x->ex_xkusage |= XKU_ANYEKU;
326 break;
327 }
328 }
329 sk_ASN1_OBJECT_pop_free(extusage, ASN1_OBJECT_free);
330 } else if (j != -1) {
331 x->ex_flags |= EXFLAG_INVALID;
332 }
333
David Benjamin260a10c2022-06-16 13:58:28 -0400334 x->skid = X509_get_ext_d2i(x, NID_subject_key_identifier, &j, NULL);
335 if (x->skid == NULL && j != -1) {
336 x->ex_flags |= EXFLAG_INVALID;
337 }
338 x->akid = X509_get_ext_d2i(x, NID_authority_key_identifier, &j, NULL);
339 if (x->akid == NULL && j != -1) {
340 x->ex_flags |= EXFLAG_INVALID;
341 }
David Benjamin46350482022-06-16 14:03:12 -0400342 // Does subject name match issuer ?
David Benjamin260a10c2022-06-16 13:58:28 -0400343 if (!X509_NAME_cmp(X509_get_subject_name(x), X509_get_issuer_name(x))) {
344 x->ex_flags |= EXFLAG_SI;
David Benjamin46350482022-06-16 14:03:12 -0400345 // If SKID matches AKID also indicate self signed
David Benjamin260a10c2022-06-16 13:58:28 -0400346 if (X509_check_akid(x, x->akid) == X509_V_OK &&
David Benjamin314c2522023-11-27 23:26:09 -0500347 !ku_reject(x, X509v3_KU_KEY_CERT_SIGN)) {
David Benjamin260a10c2022-06-16 13:58:28 -0400348 x->ex_flags |= EXFLAG_SS;
David Benjaminc0b87a02022-06-16 14:02:15 -0400349 }
David Benjamin260a10c2022-06-16 13:58:28 -0400350 }
351 x->altname = X509_get_ext_d2i(x, NID_subject_alt_name, &j, NULL);
352 if (x->altname == NULL && j != -1) {
353 x->ex_flags |= EXFLAG_INVALID;
354 }
355 x->nc = X509_get_ext_d2i(x, NID_name_constraints, &j, NULL);
356 if (x->nc == NULL && j != -1) {
357 x->ex_flags |= EXFLAG_INVALID;
358 }
359 if (!setup_crldp(x)) {
360 x->ex_flags |= EXFLAG_INVALID;
361 }
362
363 for (j = 0; j < X509_get_ext_count(x); j++) {
David Benjamin09b8fd42022-07-10 19:14:48 -0400364 const X509_EXTENSION *ex = X509_get_ext(x, j);
David Benjaminc0b87a02022-06-16 14:02:15 -0400365 if (!X509_EXTENSION_get_critical(ex)) {
David Benjamin260a10c2022-06-16 13:58:28 -0400366 continue;
David Benjaminc0b87a02022-06-16 14:02:15 -0400367 }
David Benjamin260a10c2022-06-16 13:58:28 -0400368 if (!X509_supported_extension(ex)) {
369 x->ex_flags |= EXFLAG_CRITICAL;
370 break;
371 }
372 }
373 x->ex_flags |= EXFLAG_SET;
374
375 CRYPTO_MUTEX_unlock_write(&x->lock);
376 return (x->ex_flags & EXFLAG_INVALID) == 0;
Adam Langley95c29f32014-06-20 12:00:00 -0700377}
378
David Benjamin46350482022-06-16 14:03:12 -0400379// check_ca returns one if |x| should be considered a CA certificate and zero
380// otherwise.
David Benjamin260a10c2022-06-16 13:58:28 -0400381static int check_ca(const X509 *x) {
David Benjamin46350482022-06-16 14:03:12 -0400382 // keyUsage if present should allow cert signing
David Benjamin314c2522023-11-27 23:26:09 -0500383 if (ku_reject(x, X509v3_KU_KEY_CERT_SIGN)) {
David Benjamin260a10c2022-06-16 13:58:28 -0400384 return 0;
David Benjaminc0b87a02022-06-16 14:02:15 -0400385 }
David Benjamin46350482022-06-16 14:03:12 -0400386 // Version 1 certificates are considered CAs and don't have extensions.
David Benjamin260a10c2022-06-16 13:58:28 -0400387 if ((x->ex_flags & V1_ROOT) == V1_ROOT) {
388 return 1;
389 }
David Benjamin46350482022-06-16 14:03:12 -0400390 // Otherwise, it's only a CA if basicConstraints says so.
David Benjamin260a10c2022-06-16 13:58:28 -0400391 return ((x->ex_flags & EXFLAG_BCONS) && (x->ex_flags & EXFLAG_CA));
Adam Langley95c29f32014-06-20 12:00:00 -0700392}
393
David Benjamin260a10c2022-06-16 13:58:28 -0400394int X509_check_ca(X509 *x) {
395 if (!x509v3_cache_extensions(x)) {
396 return 0;
397 }
398 return check_ca(x);
Adam Langley95c29f32014-06-20 12:00:00 -0700399}
400
David Benjamin5507ccd2023-12-26 00:41:06 -0500401// check_purpose returns one if |x| is a valid part of a certificate path for
402// extended key usage |required_xku| and at least one of key usages in
403// |required_kus|. |ca| indicates whether |x| is a CA or end-entity certificate.
404static int check_purpose(const X509 *x, int ca, int required_xku,
405 int required_kus) {
406 // Check extended key usage on the entire chain.
407 if (required_xku != 0 && xku_reject(x, required_xku)) {
408 return 0;
409 }
410
411 // Check key usages only on the end-entity certificate.
412 return ca || !ku_reject(x, required_kus);
413}
414
Adam Langley57707c72016-01-14 11:25:12 -0800415static int check_purpose_ssl_client(const X509_PURPOSE *xp, const X509 *x,
David Benjamin260a10c2022-06-16 13:58:28 -0400416 int ca) {
David Benjamin5507ccd2023-12-26 00:41:06 -0500417 // We need to do digital signatures or key agreement.
418 //
419 // TODO(davidben): We do not implement any TLS client certificate modes based
420 // on key agreement.
421 return check_purpose(x, ca, XKU_SSL_CLIENT,
422 X509v3_KU_DIGITAL_SIGNATURE | X509v3_KU_KEY_AGREEMENT);
Adam Langley95c29f32014-06-20 12:00:00 -0700423}
Adam Langley57707c72016-01-14 11:25:12 -0800424
David Benjamin46350482022-06-16 14:03:12 -0400425// Key usage needed for TLS/SSL server: digital signature, encipherment or
426// key agreement. The ssl code can check this more thoroughly for individual
427// key types.
David Benjamin314c2522023-11-27 23:26:09 -0500428#define X509v3_KU_TLS \
429 (X509v3_KU_DIGITAL_SIGNATURE | X509v3_KU_KEY_ENCIPHERMENT | \
430 X509v3_KU_KEY_AGREEMENT)
Adam Langley95c29f32014-06-20 12:00:00 -0700431
Adam Langley57707c72016-01-14 11:25:12 -0800432static int check_purpose_ssl_server(const X509_PURPOSE *xp, const X509 *x,
David Benjamin260a10c2022-06-16 13:58:28 -0400433 int ca) {
David Benjamin5507ccd2023-12-26 00:41:06 -0500434 return check_purpose(x, ca, XKU_SSL_SERVER, X509v3_KU_TLS);
Adam Langley95c29f32014-06-20 12:00:00 -0700435}
436
Adam Langley57707c72016-01-14 11:25:12 -0800437static int check_purpose_ns_ssl_server(const X509_PURPOSE *xp, const X509 *x,
David Benjamin260a10c2022-06-16 13:58:28 -0400438 int ca) {
David Benjamin5507ccd2023-12-26 00:41:06 -0500439 // We need to encipher or Netscape complains.
440 return check_purpose(x, ca, XKU_SSL_SERVER, X509v3_KU_KEY_ENCIPHERMENT);
Adam Langley95c29f32014-06-20 12:00:00 -0700441}
442
Adam Langley57707c72016-01-14 11:25:12 -0800443static int check_purpose_smime_sign(const X509_PURPOSE *xp, const X509 *x,
David Benjamin260a10c2022-06-16 13:58:28 -0400444 int ca) {
David Benjamin5507ccd2023-12-26 00:41:06 -0500445 return check_purpose(x, ca, XKU_SMIME,
446 X509v3_KU_DIGITAL_SIGNATURE | X509v3_KU_NON_REPUDIATION);
Adam Langley95c29f32014-06-20 12:00:00 -0700447}
448
Adam Langley57707c72016-01-14 11:25:12 -0800449static int check_purpose_smime_encrypt(const X509_PURPOSE *xp, const X509 *x,
David Benjamin260a10c2022-06-16 13:58:28 -0400450 int ca) {
David Benjamin5507ccd2023-12-26 00:41:06 -0500451 return check_purpose(x, ca, XKU_SMIME, X509v3_KU_KEY_ENCIPHERMENT);
Adam Langley95c29f32014-06-20 12:00:00 -0700452}
453
Adam Langley57707c72016-01-14 11:25:12 -0800454static int check_purpose_crl_sign(const X509_PURPOSE *xp, const X509 *x,
David Benjamin260a10c2022-06-16 13:58:28 -0400455 int ca) {
David Benjamin5507ccd2023-12-26 00:41:06 -0500456 return check_purpose(x, ca, /*required_xku=*/0, X509v3_KU_CRL_SIGN);
Adam Langley95c29f32014-06-20 12:00:00 -0700457}
458
459static int check_purpose_timestamp_sign(const X509_PURPOSE *xp, const X509 *x,
David Benjamin260a10c2022-06-16 13:58:28 -0400460 int ca) {
David Benjaminc0b87a02022-06-16 14:02:15 -0400461 if (ca) {
David Benjamin5507ccd2023-12-26 00:41:06 -0500462 return 1;
David Benjaminc0b87a02022-06-16 14:02:15 -0400463 }
Adam Langley95c29f32014-06-20 12:00:00 -0700464
David Benjamin46350482022-06-16 14:03:12 -0400465 // Check the optional key usage field:
466 // if Key Usage is present, it must be one of digitalSignature
467 // and/or nonRepudiation (other values are not consistent and shall
468 // be rejected).
David Benjamin260a10c2022-06-16 13:58:28 -0400469 if ((x->ex_flags & EXFLAG_KUSAGE) &&
David Benjamin314c2522023-11-27 23:26:09 -0500470 ((x->ex_kusage &
471 ~(X509v3_KU_NON_REPUDIATION | X509v3_KU_DIGITAL_SIGNATURE)) ||
472 !(x->ex_kusage &
473 (X509v3_KU_NON_REPUDIATION | X509v3_KU_DIGITAL_SIGNATURE)))) {
David Benjamin260a10c2022-06-16 13:58:28 -0400474 return 0;
David Benjaminc0b87a02022-06-16 14:02:15 -0400475 }
Adam Langley95c29f32014-06-20 12:00:00 -0700476
David Benjamin46350482022-06-16 14:03:12 -0400477 // Only time stamp key usage is permitted and it's required.
David Benjamin5507ccd2023-12-26 00:41:06 -0500478 //
479 // TODO(davidben): Should we check EKUs up the chain like the other cases?
David Benjaminc0b87a02022-06-16 14:02:15 -0400480 if (!(x->ex_flags & EXFLAG_XKUSAGE) || x->ex_xkusage != XKU_TIMESTAMP) {
David Benjamin260a10c2022-06-16 13:58:28 -0400481 return 0;
David Benjaminc0b87a02022-06-16 14:02:15 -0400482 }
Adam Langley95c29f32014-06-20 12:00:00 -0700483
David Benjamin46350482022-06-16 14:03:12 -0400484 // Extended Key Usage MUST be critical
David Benjamin352740c2023-12-25 18:24:41 -0500485 int i_ext = X509_get_ext_by_NID(x, NID_ext_key_usage, -1);
David Benjamin260a10c2022-06-16 13:58:28 -0400486 if (i_ext >= 0) {
David Benjamin352740c2023-12-25 18:24:41 -0500487 const X509_EXTENSION *ext = X509_get_ext(x, i_ext);
David Benjaminc0b87a02022-06-16 14:02:15 -0400488 if (!X509_EXTENSION_get_critical(ext)) {
David Benjamin260a10c2022-06-16 13:58:28 -0400489 return 0;
David Benjaminc0b87a02022-06-16 14:02:15 -0400490 }
David Benjamin260a10c2022-06-16 13:58:28 -0400491 }
Adam Langley95c29f32014-06-20 12:00:00 -0700492
David Benjamin260a10c2022-06-16 13:58:28 -0400493 return 1;
Adam Langley95c29f32014-06-20 12:00:00 -0700494}
495
David Benjamin260a10c2022-06-16 13:58:28 -0400496static int no_check(const X509_PURPOSE *xp, const X509 *x, int ca) { return 1; }
Adam Langley95c29f32014-06-20 12:00:00 -0700497
David Benjamin260a10c2022-06-16 13:58:28 -0400498int X509_check_issued(X509 *issuer, X509 *subject) {
499 if (X509_NAME_cmp(X509_get_subject_name(issuer),
David Benjaminc0b87a02022-06-16 14:02:15 -0400500 X509_get_issuer_name(subject))) {
David Benjamin260a10c2022-06-16 13:58:28 -0400501 return X509_V_ERR_SUBJECT_ISSUER_MISMATCH;
David Benjaminc0b87a02022-06-16 14:02:15 -0400502 }
David Benjamin260a10c2022-06-16 13:58:28 -0400503 if (!x509v3_cache_extensions(issuer) || !x509v3_cache_extensions(subject)) {
504 return X509_V_ERR_UNSPECIFIED;
505 }
Adam Langley95c29f32014-06-20 12:00:00 -0700506
David Benjamin260a10c2022-06-16 13:58:28 -0400507 if (subject->akid) {
508 int ret = X509_check_akid(issuer, subject->akid);
David Benjaminc0b87a02022-06-16 14:02:15 -0400509 if (ret != X509_V_OK) {
David Benjamin260a10c2022-06-16 13:58:28 -0400510 return ret;
David Benjaminc0b87a02022-06-16 14:02:15 -0400511 }
David Benjamin260a10c2022-06-16 13:58:28 -0400512 }
Adam Langley95c29f32014-06-20 12:00:00 -0700513
David Benjamin314c2522023-11-27 23:26:09 -0500514 if (ku_reject(issuer, X509v3_KU_KEY_CERT_SIGN)) {
David Benjamin260a10c2022-06-16 13:58:28 -0400515 return X509_V_ERR_KEYUSAGE_NO_CERTSIGN;
David Benjaminc0b87a02022-06-16 14:02:15 -0400516 }
David Benjamin260a10c2022-06-16 13:58:28 -0400517 return X509_V_OK;
518}
519
David Benjamin9e404812023-12-06 22:33:21 -0500520int X509_check_akid(X509 *issuer, const AUTHORITY_KEYID *akid) {
David Benjaminc0b87a02022-06-16 14:02:15 -0400521 if (!akid) {
Adam Langley57707c72016-01-14 11:25:12 -0800522 return X509_V_OK;
David Benjaminc0b87a02022-06-16 14:02:15 -0400523 }
Adam Langley95c29f32014-06-20 12:00:00 -0700524
David Benjamin46350482022-06-16 14:03:12 -0400525 // Check key ids (if present)
David Benjamin260a10c2022-06-16 13:58:28 -0400526 if (akid->keyid && issuer->skid &&
David Benjaminc0b87a02022-06-16 14:02:15 -0400527 ASN1_OCTET_STRING_cmp(akid->keyid, issuer->skid)) {
David Benjamin260a10c2022-06-16 13:58:28 -0400528 return X509_V_ERR_AKID_SKID_MISMATCH;
David Benjaminc0b87a02022-06-16 14:02:15 -0400529 }
David Benjamin46350482022-06-16 14:03:12 -0400530 // Check serial number
David Benjamin260a10c2022-06-16 13:58:28 -0400531 if (akid->serial &&
David Benjaminc0b87a02022-06-16 14:02:15 -0400532 ASN1_INTEGER_cmp(X509_get_serialNumber(issuer), akid->serial)) {
David Benjamin260a10c2022-06-16 13:58:28 -0400533 return X509_V_ERR_AKID_ISSUER_SERIAL_MISMATCH;
David Benjaminc0b87a02022-06-16 14:02:15 -0400534 }
David Benjamin46350482022-06-16 14:03:12 -0400535 // Check issuer name
David Benjamin260a10c2022-06-16 13:58:28 -0400536 if (akid->issuer) {
David Benjamin46350482022-06-16 14:03:12 -0400537 // Ugh, for some peculiar reason AKID includes SEQUENCE OF
538 // GeneralName. So look for a DirName. There may be more than one but
539 // we only take any notice of the first.
David Benjamin260a10c2022-06-16 13:58:28 -0400540 GENERAL_NAMES *gens;
541 GENERAL_NAME *gen;
542 X509_NAME *nm = NULL;
543 size_t i;
544 gens = akid->issuer;
545 for (i = 0; i < sk_GENERAL_NAME_num(gens); i++) {
546 gen = sk_GENERAL_NAME_value(gens, i);
547 if (gen->type == GEN_DIRNAME) {
548 nm = gen->d.dirn;
549 break;
550 }
Adam Langley57707c72016-01-14 11:25:12 -0800551 }
David Benjaminc0b87a02022-06-16 14:02:15 -0400552 if (nm && X509_NAME_cmp(nm, X509_get_issuer_name(issuer))) {
David Benjamin260a10c2022-06-16 13:58:28 -0400553 return X509_V_ERR_AKID_ISSUER_SERIAL_MISMATCH;
David Benjaminc0b87a02022-06-16 14:02:15 -0400554 }
David Benjamin260a10c2022-06-16 13:58:28 -0400555 }
556 return X509_V_OK;
Adam Langley57707c72016-01-14 11:25:12 -0800557}
David Benjaminbc3286b2018-08-13 17:52:48 -0500558
David Benjamin260a10c2022-06-16 13:58:28 -0400559uint32_t X509_get_extension_flags(X509 *x) {
David Benjamin46350482022-06-16 14:03:12 -0400560 // Ignore the return value. On failure, |x->ex_flags| will include
561 // |EXFLAG_INVALID|.
David Benjamin260a10c2022-06-16 13:58:28 -0400562 x509v3_cache_extensions(x);
563 return x->ex_flags;
David Benjaminbc3286b2018-08-13 17:52:48 -0500564}
565
David Benjamin260a10c2022-06-16 13:58:28 -0400566uint32_t X509_get_key_usage(X509 *x) {
567 if (!x509v3_cache_extensions(x)) {
568 return 0;
569 }
David Benjaminc0b87a02022-06-16 14:02:15 -0400570 if (x->ex_flags & EXFLAG_KUSAGE) {
David Benjamin260a10c2022-06-16 13:58:28 -0400571 return x->ex_kusage;
David Benjaminc0b87a02022-06-16 14:02:15 -0400572 }
David Benjamin314c2522023-11-27 23:26:09 -0500573 // If there is no extension, key usage is unconstrained, so set all bits to
574 // one. Note that, although we use |UINT32_MAX|, |ex_kusage| only contains the
575 // first 16 bits when the extension is present.
David Benjamin260a10c2022-06-16 13:58:28 -0400576 return UINT32_MAX;
David Benjaminbc3286b2018-08-13 17:52:48 -0500577}
578
David Benjamin260a10c2022-06-16 13:58:28 -0400579uint32_t X509_get_extended_key_usage(X509 *x) {
580 if (!x509v3_cache_extensions(x)) {
581 return 0;
582 }
David Benjaminc0b87a02022-06-16 14:02:15 -0400583 if (x->ex_flags & EXFLAG_XKUSAGE) {
David Benjamin260a10c2022-06-16 13:58:28 -0400584 return x->ex_xkusage;
David Benjaminc0b87a02022-06-16 14:02:15 -0400585 }
David Benjamin314c2522023-11-27 23:26:09 -0500586 // If there is no extension, extended key usage is unconstrained, so set all
587 // bits to one.
David Benjamin260a10c2022-06-16 13:58:28 -0400588 return UINT32_MAX;
David Benjaminbc3286b2018-08-13 17:52:48 -0500589}
David Benjamin298d8be2020-08-24 16:54:35 -0400590
David Benjamin260a10c2022-06-16 13:58:28 -0400591const ASN1_OCTET_STRING *X509_get0_subject_key_id(X509 *x509) {
592 if (!x509v3_cache_extensions(x509)) {
593 return NULL;
594 }
595 return x509->skid;
David Benjamin298d8be2020-08-24 16:54:35 -0400596}
597
David Benjamin260a10c2022-06-16 13:58:28 -0400598const ASN1_OCTET_STRING *X509_get0_authority_key_id(X509 *x509) {
599 if (!x509v3_cache_extensions(x509)) {
600 return NULL;
601 }
602 return x509->akid != NULL ? x509->akid->keyid : NULL;
David Benjamin298d8be2020-08-24 16:54:35 -0400603}
604
David Benjamin260a10c2022-06-16 13:58:28 -0400605const GENERAL_NAMES *X509_get0_authority_issuer(X509 *x509) {
606 if (!x509v3_cache_extensions(x509)) {
607 return NULL;
608 }
609 return x509->akid != NULL ? x509->akid->issuer : NULL;
David Benjamin298d8be2020-08-24 16:54:35 -0400610}
611
David Benjamin260a10c2022-06-16 13:58:28 -0400612const ASN1_INTEGER *X509_get0_authority_serial(X509 *x509) {
613 if (!x509v3_cache_extensions(x509)) {
614 return NULL;
615 }
616 return x509->akid != NULL ? x509->akid->serial : NULL;
David Benjamin298d8be2020-08-24 16:54:35 -0400617}
David Benjaminee4af9e2020-08-31 16:54:47 -0400618
David Benjamin260a10c2022-06-16 13:58:28 -0400619long X509_get_pathlen(X509 *x509) {
620 if (!x509v3_cache_extensions(x509) || (x509->ex_flags & EXFLAG_BCONS) == 0) {
621 return -1;
622 }
623 return x509->ex_pathlen;
David Benjaminee4af9e2020-08-31 16:54:47 -0400624}