]>
Commit | Line | Data |
---|---|---|
0f113f3e | 1 | /* |
da1c088f | 2 | * Copyright 1999-2023 The OpenSSL Project Authors. All Rights Reserved. |
673b102c | 3 | * |
4286ca47 | 4 | * Licensed under the Apache License 2.0 (the "License"). You may not use |
d2e9e320 RS |
5 | * this file except in compliance with the License. You can obtain a copy |
6 | * in the file LICENSE in the source distribution or at | |
7 | * https://www.openssl.org/source/license.html | |
673b102c DSH |
8 | */ |
9 | ||
10 | #include <stdio.h> | |
b39fc560 | 11 | #include "internal/cryptlib.h" |
1912c5d8 | 12 | #include "internal/numbers.h" |
673b102c | 13 | #include <openssl/x509v3.h> |
2f043896 | 14 | #include <openssl/x509_vfy.h> |
25f2138b | 15 | #include "crypto/x509.h" |
f21b5b64 | 16 | #include "internal/tsan_assist.h" |
02369787 | 17 | #include "x509_local.h" |
673b102c | 18 | |
ccd86b68 | 19 | static int check_ssl_ca(const X509 *x); |
0f113f3e | 20 | static int check_purpose_ssl_client(const X509_PURPOSE *xp, const X509 *x, |
8a2f9a7c | 21 | int non_leaf); |
0f113f3e | 22 | static int check_purpose_ssl_server(const X509_PURPOSE *xp, const X509 *x, |
8a2f9a7c | 23 | int non_leaf); |
0f113f3e | 24 | static int check_purpose_ns_ssl_server(const X509_PURPOSE *xp, const X509 *x, |
8a2f9a7c DDO |
25 | int non_leaf); |
26 | static int purpose_smime(const X509 *x, int non_leaf); | |
0f113f3e | 27 | static int check_purpose_smime_sign(const X509_PURPOSE *xp, const X509 *x, |
8a2f9a7c | 28 | int non_leaf); |
0f113f3e | 29 | static int check_purpose_smime_encrypt(const X509_PURPOSE *xp, const X509 *x, |
8a2f9a7c | 30 | int non_leaf); |
0f113f3e | 31 | static int check_purpose_crl_sign(const X509_PURPOSE *xp, const X509 *x, |
8a2f9a7c | 32 | int non_leaf); |
0f113f3e | 33 | static int check_purpose_timestamp_sign(const X509_PURPOSE *xp, const X509 *x, |
8a2f9a7c | 34 | int non_leaf); |
178696d6 | 35 | static int check_purpose_code_sign(const X509_PURPOSE *xp, const X509 *x, |
8a2f9a7c | 36 | int non_leaf); |
4ef70dbc | 37 | static int no_check_purpose(const X509_PURPOSE *xp, const X509 *x, |
8a2f9a7c | 38 | int non_leaf); |
4ef70dbc | 39 | static int check_purpose_ocsp_helper(const X509_PURPOSE *xp, const X509 *x, |
8a2f9a7c | 40 | int non_leaf); |
ccd86b68 | 41 | |
0f113f3e | 42 | static int xp_cmp(const X509_PURPOSE *const *a, const X509_PURPOSE *const *b); |
d4cec6a1 | 43 | static void xptable_free(X509_PURPOSE *p); |
673b102c DSH |
44 | |
45 | static X509_PURPOSE xstandard[] = { | |
0f113f3e MC |
46 | {X509_PURPOSE_SSL_CLIENT, X509_TRUST_SSL_CLIENT, 0, |
47 | check_purpose_ssl_client, "SSL client", "sslclient", NULL}, | |
48 | {X509_PURPOSE_SSL_SERVER, X509_TRUST_SSL_SERVER, 0, | |
49 | check_purpose_ssl_server, "SSL server", "sslserver", NULL}, | |
50 | {X509_PURPOSE_NS_SSL_SERVER, X509_TRUST_SSL_SERVER, 0, | |
51 | check_purpose_ns_ssl_server, "Netscape SSL server", "nssslserver", NULL}, | |
52 | {X509_PURPOSE_SMIME_SIGN, X509_TRUST_EMAIL, 0, check_purpose_smime_sign, | |
53 | "S/MIME signing", "smimesign", NULL}, | |
54 | {X509_PURPOSE_SMIME_ENCRYPT, X509_TRUST_EMAIL, 0, | |
55 | check_purpose_smime_encrypt, "S/MIME encryption", "smimeencrypt", NULL}, | |
56 | {X509_PURPOSE_CRL_SIGN, X509_TRUST_COMPAT, 0, check_purpose_crl_sign, | |
57 | "CRL signing", "crlsign", NULL}, | |
4ef70dbc DDO |
58 | {X509_PURPOSE_ANY, X509_TRUST_DEFAULT, 0, no_check_purpose, |
59 | "Any Purpose", "any", | |
0f113f3e | 60 | NULL}, |
4ef70dbc | 61 | {X509_PURPOSE_OCSP_HELPER, X509_TRUST_COMPAT, 0, check_purpose_ocsp_helper, |
0f113f3e MC |
62 | "OCSP helper", "ocsphelper", NULL}, |
63 | {X509_PURPOSE_TIMESTAMP_SIGN, X509_TRUST_TSA, 0, | |
64 | check_purpose_timestamp_sign, "Time Stamp signing", "timestampsign", | |
65 | NULL}, | |
178696d6 LJ |
66 | {X509_PURPOSE_CODE_SIGN, X509_TRUST_OBJECT_SIGN, 0, |
67 | check_purpose_code_sign, "Code signing", "codesign", | |
68 | NULL}, | |
673b102c DSH |
69 | }; |
70 | ||
b6eb9827 | 71 | #define X509_PURPOSE_COUNT OSSL_NELEM(xstandard) |
dd413410 | 72 | |
79875776 | 73 | static STACK_OF(X509_PURPOSE) *xptable = NULL; |
673b102c | 74 | |
0f113f3e | 75 | static int xp_cmp(const X509_PURPOSE *const *a, const X509_PURPOSE *const *b) |
673b102c | 76 | { |
0f113f3e | 77 | return (*a)->purpose - (*b)->purpose; |
673b102c DSH |
78 | } |
79 | ||
0f113f3e | 80 | /* |
4ef70dbc DDO |
81 | * As much as I'd like to make X509_check_purpose use a "const" X509* I really |
82 | * can't because it does recalculate hashes and do other non-const things. | |
83 | * If id == -1 it just calls x509v3_cache_extensions() for its side-effect. | |
84 | * Returns 1 on success, 0 if x does not allow purpose, -1 on (internal) error. | |
0f113f3e | 85 | */ |
8a2f9a7c | 86 | int X509_check_purpose(X509 *x, int id, int non_leaf) |
673b102c | 87 | { |
0f113f3e MC |
88 | int idx; |
89 | const X509_PURPOSE *pt; | |
bc624bd9 | 90 | |
4669015d | 91 | if (!ossl_x509v3_cache_extensions(x)) |
7e06a675 | 92 | return -1; |
0f113f3e MC |
93 | if (id == -1) |
94 | return 1; | |
4ef70dbc | 95 | |
0f113f3e MC |
96 | idx = X509_PURPOSE_get_by_id(id); |
97 | if (idx == -1) | |
98 | return -1; | |
99 | pt = X509_PURPOSE_get0(idx); | |
8a2f9a7c | 100 | return pt->check_purpose(pt, x, non_leaf); |
673b102c | 101 | } |
e947f396 | 102 | |
926a56bf DSH |
103 | int X509_PURPOSE_set(int *p, int purpose) |
104 | { | |
0f113f3e | 105 | if (X509_PURPOSE_get_by_id(purpose) == -1) { |
9311d0c4 | 106 | ERR_raise(ERR_LIB_X509V3, X509V3_R_INVALID_PURPOSE); |
0f113f3e MC |
107 | return 0; |
108 | } | |
109 | *p = purpose; | |
110 | return 1; | |
926a56bf DSH |
111 | } |
112 | ||
d4cec6a1 DSH |
113 | int X509_PURPOSE_get_count(void) |
114 | { | |
0f113f3e MC |
115 | if (!xptable) |
116 | return X509_PURPOSE_COUNT; | |
117 | return sk_X509_PURPOSE_num(xptable) + X509_PURPOSE_COUNT; | |
d4cec6a1 | 118 | } |
ce1b4fe1 | 119 | |
0f113f3e | 120 | X509_PURPOSE *X509_PURPOSE_get0(int idx) |
d4cec6a1 | 121 | { |
0f113f3e MC |
122 | if (idx < 0) |
123 | return NULL; | |
124 | if (idx < (int)X509_PURPOSE_COUNT) | |
125 | return xstandard + idx; | |
126 | return sk_X509_PURPOSE_value(xptable, idx - X509_PURPOSE_COUNT); | |
d4cec6a1 DSH |
127 | } |
128 | ||
c8f717fe | 129 | int X509_PURPOSE_get_by_sname(const char *sname) |
d4cec6a1 | 130 | { |
0f113f3e MC |
131 | int i; |
132 | X509_PURPOSE *xptmp; | |
a2db4e6c | 133 | |
0f113f3e MC |
134 | for (i = 0; i < X509_PURPOSE_get_count(); i++) { |
135 | xptmp = X509_PURPOSE_get0(i); | |
86885c28 | 136 | if (strcmp(xptmp->sname, sname) == 0) |
0f113f3e MC |
137 | return i; |
138 | } | |
139 | return -1; | |
d4cec6a1 | 140 | } |
673b102c | 141 | |
4ef70dbc | 142 | /* Returns -1 on error, else an index => 0 in standard/extended purpose table */ |
13938ace | 143 | int X509_PURPOSE_get_by_id(int purpose) |
673b102c | 144 | { |
0f113f3e MC |
145 | X509_PURPOSE tmp; |
146 | int idx; | |
5b37fef0 | 147 | |
4ef70dbc | 148 | if (purpose >= X509_PURPOSE_MIN && purpose <= X509_PURPOSE_MAX) |
0f113f3e | 149 | return purpose - X509_PURPOSE_MIN; |
5b37fef0 | 150 | if (xptable == NULL) |
0f113f3e | 151 | return -1; |
5b37fef0 | 152 | tmp.purpose = purpose; |
0f113f3e | 153 | idx = sk_X509_PURPOSE_find(xptable, &tmp); |
5b37fef0 | 154 | if (idx < 0) |
0f113f3e MC |
155 | return -1; |
156 | return idx + X509_PURPOSE_COUNT; | |
673b102c DSH |
157 | } |
158 | ||
dd413410 | 159 | int X509_PURPOSE_add(int id, int trust, int flags, |
0f113f3e | 160 | int (*ck) (const X509_PURPOSE *, const X509 *, int), |
c8f717fe | 161 | const char *name, const char *sname, void *arg) |
0f113f3e MC |
162 | { |
163 | int idx; | |
164 | X509_PURPOSE *ptmp; | |
4ef70dbc DDO |
165 | |
166 | /* This is set according to what we change: application can't set it */ | |
0f113f3e MC |
167 | flags &= ~X509_PURPOSE_DYNAMIC; |
168 | /* This will always be set for application modified trust entries */ | |
169 | flags |= X509_PURPOSE_DYNAMIC_NAME; | |
170 | /* Get existing entry if any */ | |
171 | idx = X509_PURPOSE_get_by_id(id); | |
172 | /* Need a new entry */ | |
173 | if (idx == -1) { | |
e077455e | 174 | if ((ptmp = OPENSSL_malloc(sizeof(*ptmp))) == NULL) |
0f113f3e | 175 | return 0; |
0f113f3e | 176 | ptmp->flags = X509_PURPOSE_DYNAMIC; |
a2db4e6c | 177 | } else { |
0f113f3e | 178 | ptmp = X509_PURPOSE_get0(idx); |
a2db4e6c | 179 | } |
0f113f3e MC |
180 | |
181 | /* OPENSSL_free existing name if dynamic */ | |
a2db4e6c | 182 | if ((ptmp->flags & X509_PURPOSE_DYNAMIC_NAME) != 0) { |
0f113f3e MC |
183 | OPENSSL_free(ptmp->name); |
184 | OPENSSL_free(ptmp->sname); | |
185 | } | |
4ef70dbc | 186 | /* Dup supplied name */ |
7644a9ae RS |
187 | ptmp->name = OPENSSL_strdup(name); |
188 | ptmp->sname = OPENSSL_strdup(sname); | |
e077455e | 189 | if (ptmp->name == NULL || ptmp->sname == NULL) |
137e5555 | 190 | goto err; |
0f113f3e MC |
191 | /* Keep the dynamic flag of existing entry */ |
192 | ptmp->flags &= X509_PURPOSE_DYNAMIC; | |
193 | /* Set all other flags */ | |
194 | ptmp->flags |= flags; | |
195 | ||
196 | ptmp->purpose = id; | |
197 | ptmp->trust = trust; | |
198 | ptmp->check_purpose = ck; | |
199 | ptmp->usr_data = arg; | |
200 | ||
201 | /* If its a new entry manage the dynamic table */ | |
202 | if (idx == -1) { | |
75ebbd9a RS |
203 | if (xptable == NULL |
204 | && (xptable = sk_X509_PURPOSE_new(xp_cmp)) == NULL) { | |
e077455e | 205 | ERR_raise(ERR_LIB_X509V3, ERR_R_CRYPTO_LIB); |
137e5555 | 206 | goto err; |
0f113f3e MC |
207 | } |
208 | if (!sk_X509_PURPOSE_push(xptable, ptmp)) { | |
e077455e | 209 | ERR_raise(ERR_LIB_X509V3, ERR_R_CRYPTO_LIB); |
137e5555 | 210 | goto err; |
0f113f3e MC |
211 | } |
212 | } | |
213 | return 1; | |
137e5555 MC |
214 | err: |
215 | if (idx == -1) { | |
216 | OPENSSL_free(ptmp->name); | |
217 | OPENSSL_free(ptmp->sname); | |
218 | OPENSSL_free(ptmp); | |
219 | } | |
220 | return 0; | |
673b102c DSH |
221 | } |
222 | ||
79875776 | 223 | static void xptable_free(X509_PURPOSE *p) |
0f113f3e | 224 | { |
12a765a5 | 225 | if (p == NULL) |
0f113f3e | 226 | return; |
a2db4e6c DDO |
227 | if ((p->flags & X509_PURPOSE_DYNAMIC) != 0) { |
228 | if ((p->flags & X509_PURPOSE_DYNAMIC_NAME) != 0) { | |
0f113f3e MC |
229 | OPENSSL_free(p->name); |
230 | OPENSSL_free(p->sname); | |
231 | } | |
232 | OPENSSL_free(p); | |
233 | } | |
234 | } | |
79875776 BM |
235 | |
236 | void X509_PURPOSE_cleanup(void) | |
237 | { | |
0f113f3e | 238 | sk_X509_PURPOSE_pop_free(xptable, xptable_free); |
0f113f3e | 239 | xptable = NULL; |
79875776 BM |
240 | } |
241 | ||
c8f717fe | 242 | int X509_PURPOSE_get_id(const X509_PURPOSE *xp) |
673b102c | 243 | { |
0f113f3e | 244 | return xp->purpose; |
673b102c DSH |
245 | } |
246 | ||
c8f717fe | 247 | char *X509_PURPOSE_get0_name(const X509_PURPOSE *xp) |
d4cec6a1 | 248 | { |
0f113f3e | 249 | return xp->name; |
d4cec6a1 | 250 | } |
673b102c | 251 | |
c8f717fe | 252 | char *X509_PURPOSE_get0_sname(const X509_PURPOSE *xp) |
673b102c | 253 | { |
0f113f3e | 254 | return xp->sname; |
673b102c DSH |
255 | } |
256 | ||
c8f717fe | 257 | int X509_PURPOSE_get_trust(const X509_PURPOSE *xp) |
673b102c | 258 | { |
0f113f3e | 259 | return xp->trust; |
673b102c DSH |
260 | } |
261 | ||
babb3798 | 262 | static int nid_cmp(const int *a, const int *b) |
0f113f3e MC |
263 | { |
264 | return *a - *b; | |
265 | } | |
f1558bb4 | 266 | |
e19106f5 DSH |
267 | DECLARE_OBJ_BSEARCH_CMP_FN(int, int, nid); |
268 | IMPLEMENT_OBJ_BSEARCH_CMP_FN(int, int, nid); | |
babb3798 | 269 | |
f1558bb4 | 270 | int X509_supported_extension(X509_EXTENSION *ex) |
0f113f3e MC |
271 | { |
272 | /* | |
273 | * This table is a list of the NIDs of supported extensions: that is | |
274 | * those which are used by the verify process. If an extension is | |
275 | * critical and doesn't appear in this list then the verify process will | |
276 | * normally reject the certificate. The list must be kept in numerical | |
277 | * order because it will be searched using bsearch. | |
278 | */ | |
0f113f3e MC |
279 | static const int supported_nids[] = { |
280 | NID_netscape_cert_type, /* 71 */ | |
281 | NID_key_usage, /* 83 */ | |
282 | NID_subject_alt_name, /* 85 */ | |
283 | NID_basic_constraints, /* 87 */ | |
284 | NID_certificate_policies, /* 89 */ | |
e6f648fd | 285 | NID_crl_distribution_points, /* 103 */ |
0f113f3e | 286 | NID_ext_key_usage, /* 126 */ |
47bbaa5b | 287 | #ifndef OPENSSL_NO_RFC3779 |
0f113f3e MC |
288 | NID_sbgp_ipAddrBlock, /* 290 */ |
289 | NID_sbgp_autonomousSysNum, /* 291 */ | |
47bbaa5b | 290 | #endif |
4ff993d7 | 291 | NID_id_pkix_OCSP_noCheck, /* 369 */ |
0f113f3e MC |
292 | NID_policy_constraints, /* 401 */ |
293 | NID_proxyCertInfo, /* 663 */ | |
294 | NID_name_constraints, /* 666 */ | |
295 | NID_policy_mappings, /* 747 */ | |
296 | NID_inhibit_any_policy /* 748 */ | |
297 | }; | |
298 | ||
299 | int ex_nid = OBJ_obj2nid(X509_EXTENSION_get_object(ex)); | |
300 | ||
301 | if (ex_nid == NID_undef) | |
302 | return 0; | |
303 | ||
b6eb9827 | 304 | if (OBJ_bsearch_nid(&ex_nid, supported_nids, OSSL_NELEM(supported_nids))) |
0f113f3e MC |
305 | return 1; |
306 | return 0; | |
307 | } | |
3e727a3b | 308 | |
4ef70dbc | 309 | /* Returns 1 on success, 0 if x is invalid, -1 on (internal) error. */ |
1e41dadf | 310 | static int setup_dp(const X509 *x, DIST_POINT *dp) |
0f113f3e | 311 | { |
8cc86b81 | 312 | const X509_NAME *iname = NULL; |
0f113f3e | 313 | int i; |
7e06a675 | 314 | |
1e41dadf | 315 | if (dp->distpoint == NULL && sk_GENERAL_NAME_num(dp->CRLissuer) <= 0) { |
9311d0c4 | 316 | ERR_raise(ERR_LIB_X509, X509_R_INVALID_DISTPOINT); |
1e41dadf DDO |
317 | return 0; |
318 | } | |
319 | if (dp->reasons != NULL) { | |
0f113f3e MC |
320 | if (dp->reasons->length > 0) |
321 | dp->dp_reasons = dp->reasons->data[0]; | |
322 | if (dp->reasons->length > 1) | |
323 | dp->dp_reasons |= (dp->reasons->data[1] << 8); | |
324 | dp->dp_reasons &= CRLDP_ALL_REASONS; | |
1e41dadf | 325 | } else { |
0f113f3e | 326 | dp->dp_reasons = CRLDP_ALL_REASONS; |
1e41dadf DDO |
327 | } |
328 | if (dp->distpoint == NULL || dp->distpoint->type != 1) | |
7e06a675 | 329 | return 1; |
1e41dadf | 330 | |
4ef70dbc | 331 | /* Handle name fragment given by nameRelativeToCRLIssuer */ |
1e41dadf DDO |
332 | /* |
333 | * Note that the below way of determining iname is not really compliant | |
334 | * with https://tools.ietf.org/html/rfc5280#section-4.2.1.13 | |
335 | * According to it, sk_GENERAL_NAME_num(dp->CRLissuer) MUST be <= 1 | |
336 | * and any CRLissuer could be of type different to GEN_DIRNAME. | |
337 | */ | |
0f113f3e MC |
338 | for (i = 0; i < sk_GENERAL_NAME_num(dp->CRLissuer); i++) { |
339 | GENERAL_NAME *gen = sk_GENERAL_NAME_value(dp->CRLissuer, i); | |
1e41dadf | 340 | |
0f113f3e MC |
341 | if (gen->type == GEN_DIRNAME) { |
342 | iname = gen->d.directoryName; | |
343 | break; | |
344 | } | |
345 | } | |
1e41dadf | 346 | if (iname == NULL) |
0f113f3e | 347 | iname = X509_get_issuer_name(x); |
1e41dadf | 348 | return DIST_POINT_set_dpname(dp->distpoint, iname) ? 1 : -1; |
0f113f3e | 349 | } |
3e727a3b | 350 | |
4ef70dbc | 351 | /* Return 1 on success, 0 if x is invalid, -1 on (internal) error. */ |
7e06a675 | 352 | static int setup_crldp(X509 *x) |
0f113f3e MC |
353 | { |
354 | int i; | |
7e06a675 BE |
355 | |
356 | x->crldp = X509_get_ext_d2i(x, NID_crl_distribution_points, &i, NULL); | |
357 | if (x->crldp == NULL && i != -1) | |
358 | return 0; | |
1e41dadf | 359 | |
7e06a675 | 360 | for (i = 0; i < sk_DIST_POINT_num(x->crldp); i++) { |
1e41dadf DDO |
361 | int res = setup_dp(x, sk_DIST_POINT_value(x->crldp, i)); |
362 | ||
363 | if (res < 1) | |
364 | return res; | |
7e06a675 BE |
365 | } |
366 | return 1; | |
0f113f3e | 367 | } |
f1558bb4 | 368 | |
02369787 | 369 | /* Check that issuer public key algorithm matches subject signature algorithm */ |
199df4a9 | 370 | static int check_sig_alg_match(const EVP_PKEY *issuer_key, const X509 *subject) |
02369787 | 371 | { |
0a4e660a | 372 | int subj_sig_nid; |
02369787 | 373 | |
199df4a9 | 374 | if (issuer_key == NULL) |
02369787 DDO |
375 | return X509_V_ERR_NO_ISSUER_PUBLIC_KEY; |
376 | if (OBJ_find_sigid_algs(OBJ_obj2nid(subject->cert_info.signature.algorithm), | |
199df4a9 | 377 | NULL, &subj_sig_nid) == 0) |
a2db4e6c | 378 | return X509_V_ERR_UNSUPPORTED_SIGNATURE_ALGORITHM; |
0a4e660a MC |
379 | if (EVP_PKEY_is_a(issuer_key, OBJ_nid2sn(subj_sig_nid)) |
380 | || (EVP_PKEY_is_a(issuer_key, "RSA") && subj_sig_nid == NID_rsassaPss)) | |
199df4a9 DDO |
381 | return X509_V_OK; |
382 | return X509_V_ERR_SIGNATURE_ALGORITHM_MISMATCH; | |
02369787 DDO |
383 | } |
384 | ||
a2db4e6c | 385 | #define V1_ROOT (EXFLAG_V1 | EXFLAG_SS) |
f51e5ed6 | 386 | #define ku_reject(x, usage) \ |
4ef70dbc | 387 | (((x)->ex_flags & EXFLAG_KUSAGE) != 0 && ((x)->ex_kusage & (usage)) == 0) |
f51e5ed6 | 388 | #define xku_reject(x, usage) \ |
4ef70dbc | 389 | (((x)->ex_flags & EXFLAG_XKUSAGE) != 0 && ((x)->ex_xkusage & (usage)) == 0) |
f51e5ed6 | 390 | #define ns_reject(x, usage) \ |
4ef70dbc | 391 | (((x)->ex_flags & EXFLAG_NSCERT) != 0 && ((x)->ex_nscert & (usage)) == 0) |
f51e5ed6 | 392 | |
b4cb9498 DDO |
393 | /* |
394 | * Cache info on various X.509v3 extensions and further derived information, | |
395 | * e.g., if cert 'x' is self-issued, in x->ex_flags and other internal fields. | |
f2a04587 | 396 | * x->sha1_hash is filled in, or else EXFLAG_NO_FINGERPRINT is set in x->flags. |
1e41dadf | 397 | * X509_SIG_INFO_VALID is set in x->flags if x->siginf was filled successfully. |
b4cb9498 DDO |
398 | * Set EXFLAG_INVALID and return 0 in case the certificate is invalid. |
399 | */ | |
4669015d | 400 | int ossl_x509v3_cache_extensions(X509 *x) |
673b102c | 401 | { |
0f113f3e MC |
402 | BASIC_CONSTRAINTS *bs; |
403 | PROXY_CERT_INFO_EXTENSION *pci; | |
404 | ASN1_BIT_STRING *usage; | |
405 | ASN1_BIT_STRING *ns; | |
406 | EXTENDED_KEY_USAGE *extusage; | |
0f113f3e | 407 | int i; |
1e41dadf | 408 | int res; |
bc624bd9 | 409 | |
7d38ca3f | 410 | #ifdef tsan_ld_acq |
4ef70dbc | 411 | /* Fast lock-free check, see end of the function for details. */ |
7d38ca3f | 412 | if (tsan_ld_acq((TSAN_QUALIFIER int *)&x->ex_cached)) |
33328581 | 413 | return (x->ex_flags & EXFLAG_INVALID) == 0; |
7d38ca3f | 414 | #endif |
f21b5b64 | 415 | |
cd3f8c1b RS |
416 | if (!CRYPTO_THREAD_write_lock(x->lock)) |
417 | return 0; | |
a2db4e6c | 418 | if ((x->ex_flags & EXFLAG_SET) != 0) { /* Cert has already been processed */ |
bc624bd9 | 419 | CRYPTO_THREAD_unlock(x->lock); |
33328581 | 420 | return (x->ex_flags & EXFLAG_INVALID) == 0; |
bc624bd9 DMSP |
421 | } |
422 | ||
2c05607c DDO |
423 | ERR_set_mark(); |
424 | ||
1e41dadf | 425 | /* Cache the SHA1 digest of the cert */ |
6725682d | 426 | if (!X509_digest(x, EVP_sha1(), x->sha1_hash, NULL)) |
f2a04587 DDO |
427 | x->ex_flags |= EXFLAG_NO_FINGERPRINT; |
428 | ||
0f113f3e | 429 | /* V1 should mean no extensions ... */ |
cdf63a37 | 430 | if (X509_get_version(x) == X509_VERSION_1) |
0f113f3e | 431 | x->ex_flags |= EXFLAG_V1; |
b4cb9498 | 432 | |
0f113f3e | 433 | /* Handle basic constraints */ |
1e41dadf | 434 | x->ex_pathlen = -1; |
b4cb9498 | 435 | if ((bs = X509_get_ext_d2i(x, NID_basic_constraints, &i, NULL)) != NULL) { |
0f113f3e MC |
436 | if (bs->ca) |
437 | x->ex_flags |= EXFLAG_CA; | |
b4cb9498 | 438 | if (bs->pathlen != NULL) { |
1e41dadf | 439 | /* |
4ef70dbc | 440 | * The error case !bs->ca is checked by check_chain() |
1e41dadf DDO |
441 | * in case ctx->param->flags & X509_V_FLAG_X509_STRICT |
442 | */ | |
428cf5ff | 443 | if (bs->pathlen->type == V_ASN1_NEG_INTEGER) { |
959c150a | 444 | ERR_raise(ERR_LIB_X509V3, X509V3_R_NEGATIVE_PATHLEN); |
0f113f3e | 445 | x->ex_flags |= EXFLAG_INVALID; |
428cf5ff | 446 | } else { |
0f113f3e | 447 | x->ex_pathlen = ASN1_INTEGER_get(bs->pathlen); |
428cf5ff | 448 | } |
b4cb9498 | 449 | } |
0f113f3e MC |
450 | BASIC_CONSTRAINTS_free(bs); |
451 | x->ex_flags |= EXFLAG_BCONS; | |
7e06a675 BE |
452 | } else if (i != -1) { |
453 | x->ex_flags |= EXFLAG_INVALID; | |
0f113f3e | 454 | } |
b4cb9498 | 455 | |
0f113f3e | 456 | /* Handle proxy certificates */ |
b4cb9498 | 457 | if ((pci = X509_get_ext_d2i(x, NID_proxyCertInfo, &i, NULL)) != NULL) { |
a2db4e6c | 458 | if ((x->ex_flags & EXFLAG_CA) != 0 |
0f113f3e MC |
459 | || X509_get_ext_by_NID(x, NID_subject_alt_name, -1) >= 0 |
460 | || X509_get_ext_by_NID(x, NID_issuer_alt_name, -1) >= 0) { | |
461 | x->ex_flags |= EXFLAG_INVALID; | |
462 | } | |
1e41dadf | 463 | if (pci->pcPathLengthConstraint != NULL) |
0f113f3e | 464 | x->ex_pcpathlen = ASN1_INTEGER_get(pci->pcPathLengthConstraint); |
1e41dadf | 465 | else |
0f113f3e MC |
466 | x->ex_pcpathlen = -1; |
467 | PROXY_CERT_INFO_EXTENSION_free(pci); | |
468 | x->ex_flags |= EXFLAG_PROXY; | |
7e06a675 BE |
469 | } else if (i != -1) { |
470 | x->ex_flags |= EXFLAG_INVALID; | |
0f113f3e | 471 | } |
b4cb9498 | 472 | |
8a639b9d | 473 | /* Handle (basic) key usage */ |
b4cb9498 DDO |
474 | if ((usage = X509_get_ext_d2i(x, NID_key_usage, &i, NULL)) != NULL) { |
475 | x->ex_kusage = 0; | |
0f113f3e MC |
476 | if (usage->length > 0) { |
477 | x->ex_kusage = usage->data[0]; | |
478 | if (usage->length > 1) | |
479 | x->ex_kusage |= usage->data[1] << 8; | |
b4cb9498 | 480 | } |
0f113f3e MC |
481 | x->ex_flags |= EXFLAG_KUSAGE; |
482 | ASN1_BIT_STRING_free(usage); | |
1e41dadf DDO |
483 | /* Check for empty key usage according to RFC 5280 section 4.2.1.3 */ |
484 | if (x->ex_kusage == 0) { | |
959c150a | 485 | ERR_raise(ERR_LIB_X509V3, X509V3_R_EMPTY_KEY_USAGE); |
1e41dadf DDO |
486 | x->ex_flags |= EXFLAG_INVALID; |
487 | } | |
7e06a675 BE |
488 | } else if (i != -1) { |
489 | x->ex_flags |= EXFLAG_INVALID; | |
0f113f3e | 490 | } |
1e41dadf DDO |
491 | |
492 | /* Handle extended key usage */ | |
0f113f3e | 493 | x->ex_xkusage = 0; |
b4cb9498 | 494 | if ((extusage = X509_get_ext_d2i(x, NID_ext_key_usage, &i, NULL)) != NULL) { |
0f113f3e MC |
495 | x->ex_flags |= EXFLAG_XKUSAGE; |
496 | for (i = 0; i < sk_ASN1_OBJECT_num(extusage); i++) { | |
497 | switch (OBJ_obj2nid(sk_ASN1_OBJECT_value(extusage, i))) { | |
498 | case NID_server_auth: | |
499 | x->ex_xkusage |= XKU_SSL_SERVER; | |
500 | break; | |
0f113f3e MC |
501 | case NID_client_auth: |
502 | x->ex_xkusage |= XKU_SSL_CLIENT; | |
503 | break; | |
0f113f3e MC |
504 | case NID_email_protect: |
505 | x->ex_xkusage |= XKU_SMIME; | |
506 | break; | |
0f113f3e MC |
507 | case NID_code_sign: |
508 | x->ex_xkusage |= XKU_CODE_SIGN; | |
509 | break; | |
0f113f3e MC |
510 | case NID_ms_sgc: |
511 | case NID_ns_sgc: | |
512 | x->ex_xkusage |= XKU_SGC; | |
513 | break; | |
0f113f3e MC |
514 | case NID_OCSP_sign: |
515 | x->ex_xkusage |= XKU_OCSP_SIGN; | |
516 | break; | |
0f113f3e MC |
517 | case NID_time_stamp: |
518 | x->ex_xkusage |= XKU_TIMESTAMP; | |
519 | break; | |
0f113f3e MC |
520 | case NID_dvcs: |
521 | x->ex_xkusage |= XKU_DVCS; | |
522 | break; | |
0f113f3e MC |
523 | case NID_anyExtendedKeyUsage: |
524 | x->ex_xkusage |= XKU_ANYEKU; | |
525 | break; | |
b4cb9498 | 526 | default: |
4ef70dbc | 527 | /* Ignore unknown extended key usage */ |
b4cb9498 | 528 | break; |
0f113f3e MC |
529 | } |
530 | } | |
531 | sk_ASN1_OBJECT_pop_free(extusage, ASN1_OBJECT_free); | |
7e06a675 BE |
532 | } else if (i != -1) { |
533 | x->ex_flags |= EXFLAG_INVALID; | |
0f113f3e MC |
534 | } |
535 | ||
b4cb9498 DDO |
536 | /* Handle legacy Netscape extension */ |
537 | if ((ns = X509_get_ext_d2i(x, NID_netscape_cert_type, &i, NULL)) != NULL) { | |
0f113f3e MC |
538 | if (ns->length > 0) |
539 | x->ex_nscert = ns->data[0]; | |
540 | else | |
541 | x->ex_nscert = 0; | |
542 | x->ex_flags |= EXFLAG_NSCERT; | |
543 | ASN1_BIT_STRING_free(ns); | |
7e06a675 BE |
544 | } else if (i != -1) { |
545 | x->ex_flags |= EXFLAG_INVALID; | |
0f113f3e | 546 | } |
b4cb9498 DDO |
547 | |
548 | /* Handle subject key identifier and issuer/authority key identifier */ | |
7e06a675 BE |
549 | x->skid = X509_get_ext_d2i(x, NID_subject_key_identifier, &i, NULL); |
550 | if (x->skid == NULL && i != -1) | |
551 | x->ex_flags |= EXFLAG_INVALID; | |
1e41dadf | 552 | |
7e06a675 BE |
553 | x->akid = X509_get_ext_d2i(x, NID_authority_key_identifier, &i, NULL); |
554 | if (x->akid == NULL && i != -1) | |
555 | x->ex_flags |= EXFLAG_INVALID; | |
b4cb9498 DDO |
556 | |
557 | /* Check if subject name matches issuer */ | |
558 | if (X509_NAME_cmp(X509_get_subject_name(x), X509_get_issuer_name(x)) == 0) { | |
4ef70dbc | 559 | x->ex_flags |= EXFLAG_SI; /* Cert is self-issued */ |
ade08735 | 560 | if (X509_check_akid(x, x->akid) == X509_V_OK /* SKID matches AKID */ |
0e7b1383 DDO |
561 | /* .. and the signature alg matches the PUBKEY alg: */ |
562 | && check_sig_alg_match(X509_get0_pubkey(x), x) == X509_V_OK) | |
ade08735 | 563 | x->ex_flags |= EXFLAG_SS; /* indicate self-signed */ |
4669015d | 564 | /* This is very related to ossl_x509_likely_issued(x, x) == X509_V_OK */ |
0f113f3e | 565 | } |
b4cb9498 DDO |
566 | |
567 | /* Handle subject alternative names and various other extensions */ | |
7e06a675 BE |
568 | x->altname = X509_get_ext_d2i(x, NID_subject_alt_name, &i, NULL); |
569 | if (x->altname == NULL && i != -1) | |
570 | x->ex_flags |= EXFLAG_INVALID; | |
0f113f3e | 571 | x->nc = X509_get_ext_d2i(x, NID_name_constraints, &i, NULL); |
7e06a675 BE |
572 | if (x->nc == NULL && i != -1) |
573 | x->ex_flags |= EXFLAG_INVALID; | |
1e41dadf DDO |
574 | |
575 | /* Handle CRL distribution point entries */ | |
576 | res = setup_crldp(x); | |
577 | if (res == 0) | |
0f113f3e | 578 | x->ex_flags |= EXFLAG_INVALID; |
d43c4497 | 579 | |
47bbaa5b | 580 | #ifndef OPENSSL_NO_RFC3779 |
7e06a675 BE |
581 | x->rfc3779_addr = X509_get_ext_d2i(x, NID_sbgp_ipAddrBlock, &i, NULL); |
582 | if (x->rfc3779_addr == NULL && i != -1) | |
583 | x->ex_flags |= EXFLAG_INVALID; | |
584 | x->rfc3779_asid = X509_get_ext_d2i(x, NID_sbgp_autonomousSysNum, &i, NULL); | |
585 | if (x->rfc3779_asid == NULL && i != -1) | |
586 | x->ex_flags |= EXFLAG_INVALID; | |
47bbaa5b | 587 | #endif |
0f113f3e | 588 | for (i = 0; i < X509_get_ext_count(x); i++) { |
89f13ca4 DDO |
589 | X509_EXTENSION *ex = X509_get_ext(x, i); |
590 | int nid = OBJ_obj2nid(X509_EXTENSION_get_object(ex)); | |
591 | ||
592 | if (nid == NID_freshest_crl) | |
0f113f3e MC |
593 | x->ex_flags |= EXFLAG_FRESHEST; |
594 | if (!X509_EXTENSION_get_critical(ex)) | |
595 | continue; | |
596 | if (!X509_supported_extension(ex)) { | |
597 | x->ex_flags |= EXFLAG_CRITICAL; | |
598 | break; | |
599 | } | |
89f13ca4 DDO |
600 | switch (nid) { |
601 | case NID_basic_constraints: | |
602 | x->ex_flags |= EXFLAG_BCONS_CRITICAL; | |
603 | break; | |
604 | case NID_authority_key_identifier: | |
605 | x->ex_flags |= EXFLAG_AKID_CRITICAL; | |
606 | break; | |
607 | case NID_subject_key_identifier: | |
608 | x->ex_flags |= EXFLAG_SKID_CRITICAL; | |
da6c691d DDO |
609 | break; |
610 | case NID_subject_alt_name: | |
611 | x->ex_flags |= EXFLAG_SAN_CRITICAL; | |
89f13ca4 DDO |
612 | break; |
613 | default: | |
614 | break; | |
615 | } | |
0f113f3e | 616 | } |
b4cb9498 | 617 | |
1e41dadf | 618 | /* Set x->siginf, ignoring errors due to unsupported algos */ |
4669015d | 619 | (void)ossl_x509_init_sig_info(x); |
b4cb9498 | 620 | |
4ef70dbc | 621 | x->ex_flags |= EXFLAG_SET; /* Indicate that cert has been processed */ |
7d38ca3f AP |
622 | #ifdef tsan_st_rel |
623 | tsan_st_rel((TSAN_QUALIFIER int *)&x->ex_cached, 1); | |
f21b5b64 | 624 | /* |
7d38ca3f AP |
625 | * Above store triggers fast lock-free check in the beginning of the |
626 | * function. But one has to ensure that the structure is "stable", i.e. | |
627 | * all stores are visible on all processors. Hence the release fence. | |
f21b5b64 | 628 | */ |
7d38ca3f | 629 | #endif |
de3713d4 | 630 | ERR_pop_to_mark(); |
2c05607c DDO |
631 | |
632 | if ((x->ex_flags & EXFLAG_INVALID) == 0) { | |
1e41dadf DDO |
633 | CRYPTO_THREAD_unlock(x->lock); |
634 | return 1; | |
635 | } | |
1e41dadf | 636 | CRYPTO_THREAD_unlock(x->lock); |
959c150a | 637 | ERR_raise(ERR_LIB_X509V3, X509V3_R_INVALID_CERTIFICATE); |
1e41dadf | 638 | return 0; |
673b102c DSH |
639 | } |
640 | ||
1d97c843 TH |
641 | /*- |
642 | * CA checks common to all purposes | |
673b102c DSH |
643 | * return codes: |
644 | * 0 not a CA | |
645 | * 1 is a CA | |
eacd30a7 JM |
646 | * 2 Only possible in older versions of openSSL when basicConstraints are absent |
647 | * new versions will not return this value. May be a CA | |
ade08735 | 648 | * 3 basicConstraints absent but self-signed V1. |
bc501570 | 649 | * 4 basicConstraints absent but keyUsage present and keyCertSign asserted. |
eacd30a7 | 650 | * 5 Netscape specific CA Flags present |
673b102c DSH |
651 | */ |
652 | ||
5073ff03 | 653 | static int check_ca(const X509 *x) |
673b102c | 654 | { |
0f113f3e MC |
655 | /* keyUsage if present should allow cert signing */ |
656 | if (ku_reject(x, KU_KEY_CERT_SIGN)) | |
657 | return 0; | |
4ef70dbc | 658 | if ((x->ex_flags & EXFLAG_BCONS) != 0) { |
0f113f3e | 659 | /* If basicConstraints says not a CA then say so */ |
4ef70dbc | 660 | return (x->ex_flags & EXFLAG_CA) != 0; |
0f113f3e | 661 | } else { |
4ef70dbc | 662 | /* We support V1 roots for... uh, I don't really know why. */ |
0f113f3e MC |
663 | if ((x->ex_flags & V1_ROOT) == V1_ROOT) |
664 | return 3; | |
665 | /* | |
666 | * If key usage present it must have certSign so tolerate it | |
667 | */ | |
a2db4e6c | 668 | else if ((x->ex_flags & EXFLAG_KUSAGE) != 0) |
0f113f3e MC |
669 | return 4; |
670 | /* Older certificates could have Netscape-specific CA types */ | |
a2db4e6c DDO |
671 | else if ((x->ex_flags & EXFLAG_NSCERT) != 0 |
672 | && (x->ex_nscert & NS_ANY_CA) != 0) | |
0f113f3e | 673 | return 5; |
4ef70dbc | 674 | /* Can this still be regarded a CA certificate? I doubt it. */ |
0f113f3e MC |
675 | return 0; |
676 | } | |
673b102c DSH |
677 | } |
678 | ||
9961cb77 RL |
679 | void X509_set_proxy_flag(X509 *x) |
680 | { | |
96a68f21 P |
681 | if (CRYPTO_THREAD_write_lock(x->lock)) { |
682 | x->ex_flags |= EXFLAG_PROXY; | |
683 | CRYPTO_THREAD_unlock(x->lock); | |
684 | } | |
9961cb77 RL |
685 | } |
686 | ||
fe0169b0 RL |
687 | void X509_set_proxy_pathlen(X509 *x, long l) |
688 | { | |
689 | x->ex_pcpathlen = l; | |
690 | } | |
691 | ||
5073ff03 RL |
692 | int X509_check_ca(X509 *x) |
693 | { | |
33328581 | 694 | /* Note 0 normally means "not a CA" - but in this case means error. */ |
4669015d | 695 | if (!ossl_x509v3_cache_extensions(x)) |
33328581 | 696 | return 0; |
5073ff03 | 697 | |
0f113f3e | 698 | return check_ca(x); |
5073ff03 RL |
699 | } |
700 | ||
4ef70dbc | 701 | /* Check SSL CA: common checks for SSL client and server. */ |
ccd86b68 | 702 | static int check_ssl_ca(const X509 *x) |
0cb957a6 | 703 | { |
4ef70dbc DDO |
704 | int ca_ret = check_ca(x); |
705 | ||
706 | if (ca_ret == 0) | |
0f113f3e | 707 | return 0; |
4ef70dbc DDO |
708 | /* Check nsCertType if present */ |
709 | return ca_ret != 5 || (x->ex_nscert & NS_SSL_CA) != 0; | |
0cb957a6 | 710 | } |
8cff6331 | 711 | |
0f113f3e | 712 | static int check_purpose_ssl_client(const X509_PURPOSE *xp, const X509 *x, |
8a2f9a7c | 713 | int non_leaf) |
673b102c | 714 | { |
0f113f3e MC |
715 | if (xku_reject(x, XKU_SSL_CLIENT)) |
716 | return 0; | |
8a2f9a7c | 717 | if (non_leaf) |
0f113f3e MC |
718 | return check_ssl_ca(x); |
719 | /* We need to do digital signatures or key agreement */ | |
720 | if (ku_reject(x, KU_DIGITAL_SIGNATURE | KU_KEY_AGREEMENT)) | |
721 | return 0; | |
722 | /* nsCertType if present should allow SSL client use */ | |
723 | if (ns_reject(x, NS_SSL_CLIENT)) | |
724 | return 0; | |
725 | return 1; | |
673b102c | 726 | } |
0f113f3e MC |
727 | |
728 | /* | |
729 | * Key usage needed for TLS/SSL server: digital signature, encipherment or | |
7568d15a DSH |
730 | * key agreement. The ssl code can check this more thoroughly for individual |
731 | * key types. | |
732 | */ | |
733 | #define KU_TLS \ | |
a2db4e6c | 734 | KU_DIGITAL_SIGNATURE | KU_KEY_ENCIPHERMENT | KU_KEY_AGREEMENT |
673b102c | 735 | |
0f113f3e | 736 | static int check_purpose_ssl_server(const X509_PURPOSE *xp, const X509 *x, |
8a2f9a7c | 737 | int non_leaf) |
673b102c | 738 | { |
0f113f3e MC |
739 | if (xku_reject(x, XKU_SSL_SERVER | XKU_SGC)) |
740 | return 0; | |
8a2f9a7c | 741 | if (non_leaf) |
0f113f3e MC |
742 | return check_ssl_ca(x); |
743 | ||
744 | if (ns_reject(x, NS_SSL_SERVER)) | |
745 | return 0; | |
746 | if (ku_reject(x, KU_TLS)) | |
747 | return 0; | |
673b102c | 748 | |
0f113f3e | 749 | return 1; |
673b102c DSH |
750 | |
751 | } | |
752 | ||
0f113f3e | 753 | static int check_purpose_ns_ssl_server(const X509_PURPOSE *xp, const X509 *x, |
8a2f9a7c | 754 | int non_leaf) |
673b102c | 755 | { |
8a2f9a7c | 756 | int ret = check_purpose_ssl_server(xp, x, non_leaf); |
a2db4e6c | 757 | |
8a2f9a7c | 758 | if (!ret || non_leaf) |
0f113f3e MC |
759 | return ret; |
760 | /* We need to encipher or Netscape complains */ | |
a2db4e6c | 761 | return ku_reject(x, KU_KEY_ENCIPHERMENT) ? 0 : ret; |
673b102c DSH |
762 | } |
763 | ||
764 | /* common S/MIME checks */ | |
8a2f9a7c | 765 | static int purpose_smime(const X509 *x, int non_leaf) |
673b102c | 766 | { |
0f113f3e MC |
767 | if (xku_reject(x, XKU_SMIME)) |
768 | return 0; | |
8a2f9a7c | 769 | if (non_leaf) { |
a2db4e6c DDO |
770 | int ca_ret = check_ca(x); |
771 | ||
4ef70dbc | 772 | if (ca_ret == 0) |
0f113f3e | 773 | return 0; |
4ef70dbc | 774 | /* Check nsCertType if present */ |
a2db4e6c | 775 | if (ca_ret != 5 || (x->ex_nscert & NS_SMIME_CA) != 0) |
0f113f3e MC |
776 | return ca_ret; |
777 | else | |
778 | return 0; | |
779 | } | |
a2db4e6c DDO |
780 | if ((x->ex_flags & EXFLAG_NSCERT) != 0) { |
781 | if ((x->ex_nscert & NS_SMIME) != 0) | |
0f113f3e MC |
782 | return 1; |
783 | /* Workaround for some buggy certificates */ | |
a2db4e6c | 784 | return (x->ex_nscert & NS_SSL_CLIENT) != 0 ? 2 : 0; |
0f113f3e MC |
785 | } |
786 | return 1; | |
673b102c DSH |
787 | } |
788 | ||
0f113f3e | 789 | static int check_purpose_smime_sign(const X509_PURPOSE *xp, const X509 *x, |
8a2f9a7c | 790 | int non_leaf) |
673b102c | 791 | { |
8a2f9a7c | 792 | int ret = purpose_smime(x, non_leaf); |
a2db4e6c | 793 | |
8a2f9a7c | 794 | if (!ret || non_leaf) |
0f113f3e | 795 | return ret; |
a2db4e6c | 796 | return ku_reject(x, KU_DIGITAL_SIGNATURE | KU_NON_REPUDIATION) ? 0 : ret; |
673b102c DSH |
797 | } |
798 | ||
0f113f3e | 799 | static int check_purpose_smime_encrypt(const X509_PURPOSE *xp, const X509 *x, |
8a2f9a7c | 800 | int non_leaf) |
673b102c | 801 | { |
8a2f9a7c | 802 | int ret = purpose_smime(x, non_leaf); |
a2db4e6c | 803 | |
8a2f9a7c | 804 | if (!ret || non_leaf) |
0f113f3e | 805 | return ret; |
a2db4e6c | 806 | return ku_reject(x, KU_KEY_ENCIPHERMENT) ? 0 : ret; |
673b102c DSH |
807 | } |
808 | ||
0f113f3e | 809 | static int check_purpose_crl_sign(const X509_PURPOSE *xp, const X509 *x, |
8a2f9a7c | 810 | int non_leaf) |
673b102c | 811 | { |
8a2f9a7c | 812 | if (non_leaf) { |
a2db4e6c DDO |
813 | int ca_ret = check_ca(x); |
814 | ||
815 | return ca_ret == 2 ? 0 : ca_ret; | |
0f113f3e | 816 | } |
a2db4e6c | 817 | return !ku_reject(x, KU_CRL_SIGN); |
673b102c | 818 | } |
068fdce8 | 819 | |
0f113f3e MC |
820 | /* |
821 | * OCSP helper: this is *not* a full OCSP check. It just checks that each CA | |
822 | * is valid. Additional checks must be made on the chain. | |
81f169e9 | 823 | */ |
4ef70dbc | 824 | static int check_purpose_ocsp_helper(const X509_PURPOSE *xp, const X509 *x, |
8a2f9a7c | 825 | int non_leaf) |
81f169e9 | 826 | { |
0f113f3e MC |
827 | /* |
828 | * Must be a valid CA. Should we really support the "I don't know" value | |
829 | * (2)? | |
830 | */ | |
8a2f9a7c | 831 | if (non_leaf) |
0f113f3e | 832 | return check_ca(x); |
4ef70dbc | 833 | /* Leaf certificate is checked in OCSP_verify() */ |
0f113f3e | 834 | return 1; |
81f169e9 DSH |
835 | } |
836 | ||
c7235be6 | 837 | static int check_purpose_timestamp_sign(const X509_PURPOSE *xp, const X509 *x, |
8a2f9a7c | 838 | int non_leaf) |
c7235be6 | 839 | { |
0f113f3e MC |
840 | int i_ext; |
841 | ||
3fa6dbd1 | 842 | /* |
8a2f9a7c | 843 | * If non_leaf is true we must check if this is a valid CA certificate. |
3fa6dbd1 DDO |
844 | * The extra requirements by the CA/Browser Forum are not checked. |
845 | */ | |
8a2f9a7c | 846 | if (non_leaf) |
0f113f3e MC |
847 | return check_ca(x); |
848 | ||
3fa6dbd1 DDO |
849 | /* |
850 | * Key Usage is checked according to RFC 5280 and | |
851 | * Extended Key Usage attributes is checked according to RFC 3161. | |
852 | * The extra (and somewhat conflicting) CA/Browser Forum | |
853 | * Baseline Requirements for the Issuance and Management of | |
854 | * Publicly‐Trusted Code Signing Certificates, Version 3.0.0, | |
855 | * Section 7.1.2.3: Code signing and Timestamp Certificate are not checked. | |
856 | */ | |
0f113f3e MC |
857 | /* |
858 | * Check the optional key usage field: | |
859 | * if Key Usage is present, it must be one of digitalSignature | |
860 | * and/or nonRepudiation (other values are not consistent and shall | |
861 | * be rejected). | |
862 | */ | |
a2db4e6c | 863 | if ((x->ex_flags & EXFLAG_KUSAGE) != 0 |
0f113f3e MC |
864 | && ((x->ex_kusage & ~(KU_NON_REPUDIATION | KU_DIGITAL_SIGNATURE)) || |
865 | !(x->ex_kusage & (KU_NON_REPUDIATION | KU_DIGITAL_SIGNATURE)))) | |
866 | return 0; | |
867 | ||
c7340583 | 868 | /* Only timestamp key usage is permitted and it's required. */ |
a2db4e6c | 869 | if ((x->ex_flags & EXFLAG_XKUSAGE) == 0 || x->ex_xkusage != XKU_TIMESTAMP) |
0f113f3e MC |
870 | return 0; |
871 | ||
872 | /* Extended Key Usage MUST be critical */ | |
7569362e | 873 | i_ext = X509_get_ext_by_NID(x, NID_ext_key_usage, -1); |
a2db4e6c DDO |
874 | if (i_ext >= 0 |
875 | && !X509_EXTENSION_get_critical(X509_get_ext((X509 *)x, i_ext))) | |
876 | return 0; | |
0f113f3e | 877 | return 1; |
c7235be6 UM |
878 | } |
879 | ||
178696d6 | 880 | static int check_purpose_code_sign(const X509_PURPOSE *xp, const X509 *x, |
8a2f9a7c | 881 | int non_leaf) |
178696d6 LJ |
882 | { |
883 | int i_ext; | |
884 | ||
3fa6dbd1 | 885 | /* |
8a2f9a7c | 886 | * If non_leaf is true we must check if this is a valid CA certificate. |
3fa6dbd1 DDO |
887 | * The extra requirements by the CA/Browser Forum are not checked. |
888 | */ | |
8a2f9a7c | 889 | if (non_leaf) |
178696d6 LJ |
890 | return check_ca(x); |
891 | ||
892 | /* | |
893 | * Check the key usage and extended key usage fields: | |
894 | * | |
3fa6dbd1 DDO |
895 | * Reference: CA/Browser Forum, |
896 | * Baseline Requirements for the Issuance and Management of | |
178696d6 LJ |
897 | * Publicly‐Trusted Code Signing Certificates, Version 3.0.0, |
898 | * Section 7.1.2.3: Code signing and Timestamp Certificate | |
899 | * | |
900 | * Checking covers Key Usage and Extended Key Usage attributes. | |
3fa6dbd1 DDO |
901 | * The certificatePolicies, cRLDistributionPoints (CDP), and |
902 | * authorityInformationAccess (AIA) extensions are so far not checked. | |
178696d6 LJ |
903 | */ |
904 | /* Key Usage */ | |
905 | if ((x->ex_flags & EXFLAG_KUSAGE) == 0) | |
906 | return 0; | |
907 | if ((x->ex_kusage & KU_DIGITAL_SIGNATURE) == 0) | |
908 | return 0; | |
909 | if ((x->ex_kusage & (KU_KEY_CERT_SIGN | KU_CRL_SIGN)) != 0) | |
910 | return 0; | |
911 | ||
912 | /* Key Usage MUST be critical */ | |
913 | i_ext = X509_get_ext_by_NID(x, NID_key_usage, -1); | |
914 | if (i_ext < 0) | |
915 | return 0; | |
916 | if (i_ext >= 0) { | |
917 | X509_EXTENSION *ext = X509_get_ext((X509 *)x, i_ext); | |
918 | if (!X509_EXTENSION_get_critical(ext)) | |
919 | return 0; | |
920 | } | |
921 | ||
922 | /* Extended Key Usage */ | |
923 | if ((x->ex_flags & EXFLAG_XKUSAGE) == 0) | |
924 | return 0; | |
925 | if ((x->ex_xkusage & XKU_CODE_SIGN) == 0) | |
926 | return 0; | |
927 | if ((x->ex_xkusage & (XKU_ANYEKU | XKU_SSL_SERVER)) != 0) | |
928 | return 0; | |
929 | ||
930 | return 1; | |
931 | ||
932 | } | |
933 | ||
4ef70dbc | 934 | static int no_check_purpose(const X509_PURPOSE *xp, const X509 *x, |
8a2f9a7c | 935 | int non_leaf) |
068fdce8 | 936 | { |
0f113f3e | 937 | return 1; |
068fdce8 | 938 | } |
2f043896 | 939 | |
1d97c843 | 940 | /*- |
ade08735 DDO |
941 | * Various checks to see if one certificate potentially issued the second. |
942 | * This can be used to prune a set of possible issuer certificates which | |
943 | * have been looked up using some simple method such as by subject name. | |
2f043896 | 944 | * These are: |
f9ac6f69 DDO |
945 | * 1. issuer_name(subject) == subject_name(issuer) |
946 | * 2. If akid(subject) exists, it matches the respective issuer fields. | |
947 | * 3. subject signature algorithm == issuer public key algorithm | |
948 | * 4. If key_usage(issuer) exists, it allows for signing subject. | |
ade08735 DDO |
949 | * Note that this does not include actually checking the signature. |
950 | * Returns 0 for OK, or positive for reason for mismatch | |
951 | * where reason codes match those for X509_verify_cert(). | |
2f043896 | 952 | */ |
6725682d | 953 | int X509_check_issued(X509 *issuer, X509 *subject) |
02369787 DDO |
954 | { |
955 | int ret; | |
2f043896 | 956 | |
4669015d | 957 | if ((ret = ossl_x509_likely_issued(issuer, subject)) != X509_V_OK) |
02369787 | 958 | return ret; |
4669015d | 959 | return ossl_x509_signing_allowed(issuer, subject); |
02369787 DDO |
960 | } |
961 | ||
4669015d SL |
962 | /* do the checks 1., 2., and 3. as described above for X509_check_issued() */ |
963 | int ossl_x509_likely_issued(X509 *issuer, X509 *subject) | |
2f043896 | 964 | { |
02369787 DDO |
965 | int ret; |
966 | ||
0f113f3e | 967 | if (X509_NAME_cmp(X509_get_subject_name(issuer), |
02369787 | 968 | X509_get_issuer_name(subject)) != 0) |
0f113f3e | 969 | return X509_V_ERR_SUBJECT_ISSUER_MISMATCH; |
bc624bd9 | 970 | |
4669015d SL |
971 | /* set issuer->skid and subject->akid */ |
972 | if (!ossl_x509v3_cache_extensions(issuer) | |
973 | || !ossl_x509v3_cache_extensions(subject)) | |
7e06a675 | 974 | return X509_V_ERR_UNSPECIFIED; |
0f113f3e | 975 | |
02369787 DDO |
976 | ret = X509_check_akid(issuer, subject->akid); |
977 | if (ret != X509_V_OK) | |
978 | return ret; | |
0f113f3e | 979 | |
4ef70dbc | 980 | /* Check if the subject signature alg matches the issuer's PUBKEY alg */ |
02369787 DDO |
981 | return check_sig_alg_match(X509_get0_pubkey(issuer), subject); |
982 | } | |
ffd2df13 | 983 | |
02369787 DDO |
984 | /*- |
985 | * Check if certificate I<issuer> is allowed to issue certificate I<subject> | |
986 | * according to the B<keyUsage> field of I<issuer> if present | |
987 | * depending on any proxyCertInfo extension of I<subject>. | |
988 | * Returns 0 for OK, or positive for reason for rejection | |
989 | * where reason codes match those for X509_verify_cert(). | |
990 | */ | |
4669015d | 991 | int ossl_x509_signing_allowed(const X509 *issuer, const X509 *subject) |
02369787 | 992 | { |
a2db4e6c | 993 | if ((subject->ex_flags & EXFLAG_PROXY) != 0) { |
0f113f3e MC |
994 | if (ku_reject(issuer, KU_DIGITAL_SIGNATURE)) |
995 | return X509_V_ERR_KEYUSAGE_NO_DIGITAL_SIGNATURE; | |
a2db4e6c | 996 | } else if (ku_reject(issuer, KU_KEY_CERT_SIGN)) { |
0f113f3e | 997 | return X509_V_ERR_KEYUSAGE_NO_CERTSIGN; |
a2db4e6c | 998 | } |
0f113f3e | 999 | return X509_V_OK; |
2f043896 DSH |
1000 | } |
1001 | ||
1337a3a9 | 1002 | int X509_check_akid(const X509 *issuer, const AUTHORITY_KEYID *akid) |
0f113f3e | 1003 | { |
02369787 | 1004 | if (akid == NULL) |
0f113f3e MC |
1005 | return X509_V_OK; |
1006 | ||
1007 | /* Check key ids (if present) */ | |
1008 | if (akid->keyid && issuer->skid && | |
1009 | ASN1_OCTET_STRING_cmp(akid->keyid, issuer->skid)) | |
1010 | return X509_V_ERR_AKID_SKID_MISMATCH; | |
1011 | /* Check serial number */ | |
1012 | if (akid->serial && | |
1337a3a9 | 1013 | ASN1_INTEGER_cmp(X509_get0_serialNumber(issuer), akid->serial)) |
0f113f3e MC |
1014 | return X509_V_ERR_AKID_ISSUER_SERIAL_MISMATCH; |
1015 | /* Check issuer name */ | |
1016 | if (akid->issuer) { | |
1017 | /* | |
1018 | * Ugh, for some peculiar reason AKID includes SEQUENCE OF | |
1019 | * GeneralName. So look for a DirName. There may be more than one but | |
1020 | * we only take any notice of the first. | |
1021 | */ | |
a2db4e6c | 1022 | GENERAL_NAMES *gens = akid->issuer; |
0f113f3e MC |
1023 | GENERAL_NAME *gen; |
1024 | X509_NAME *nm = NULL; | |
1025 | int i; | |
a2db4e6c | 1026 | |
0f113f3e MC |
1027 | for (i = 0; i < sk_GENERAL_NAME_num(gens); i++) { |
1028 | gen = sk_GENERAL_NAME_value(gens, i); | |
1029 | if (gen->type == GEN_DIRNAME) { | |
1030 | nm = gen->d.dirn; | |
1031 | break; | |
1032 | } | |
1033 | } | |
02369787 | 1034 | if (nm != NULL && X509_NAME_cmp(nm, X509_get_issuer_name(issuer)) != 0) |
0f113f3e MC |
1035 | return X509_V_ERR_AKID_ISSUER_SERIAL_MISMATCH; |
1036 | } | |
1037 | return X509_V_OK; | |
1038 | } | |
063f1f0c DSH |
1039 | |
1040 | uint32_t X509_get_extension_flags(X509 *x) | |
1041 | { | |
109f8b5d | 1042 | /* Call for side-effect of computing hash and caching extensions */ |
4ef70dbc | 1043 | X509_check_purpose(x, -1, 0); |
063f1f0c DSH |
1044 | return x->ex_flags; |
1045 | } | |
1046 | ||
1047 | uint32_t X509_get_key_usage(X509 *x) | |
1048 | { | |
109f8b5d | 1049 | /* Call for side-effect of computing hash and caching extensions */ |
4ef70dbc | 1050 | if (X509_check_purpose(x, -1, 0) != 1) |
7e06a675 | 1051 | return 0; |
a2db4e6c | 1052 | return (x->ex_flags & EXFLAG_KUSAGE) != 0 ? x->ex_kusage : UINT32_MAX; |
063f1f0c DSH |
1053 | } |
1054 | ||
1055 | uint32_t X509_get_extended_key_usage(X509 *x) | |
1056 | { | |
109f8b5d | 1057 | /* Call for side-effect of computing hash and caching extensions */ |
4ef70dbc | 1058 | if (X509_check_purpose(x, -1, 0) != 1) |
7e06a675 | 1059 | return 0; |
a2db4e6c | 1060 | return (x->ex_flags & EXFLAG_XKUSAGE) != 0 ? x->ex_xkusage : UINT32_MAX; |
063f1f0c | 1061 | } |
d19a50c9 DSH |
1062 | |
1063 | const ASN1_OCTET_STRING *X509_get0_subject_key_id(X509 *x) | |
1064 | { | |
109f8b5d | 1065 | /* Call for side-effect of computing hash and caching extensions */ |
4ef70dbc | 1066 | if (X509_check_purpose(x, -1, 0) != 1) |
7e06a675 | 1067 | return NULL; |
d19a50c9 DSH |
1068 | return x->skid; |
1069 | } | |
e417070c | 1070 | |
b383aa20 MP |
1071 | const ASN1_OCTET_STRING *X509_get0_authority_key_id(X509 *x) |
1072 | { | |
1073 | /* Call for side-effect of computing hash and caching extensions */ | |
4ef70dbc | 1074 | if (X509_check_purpose(x, -1, 0) != 1) |
7e06a675 | 1075 | return NULL; |
b383aa20 MP |
1076 | return (x->akid != NULL ? x->akid->keyid : NULL); |
1077 | } | |
1078 | ||
afdec13d DMSP |
1079 | const GENERAL_NAMES *X509_get0_authority_issuer(X509 *x) |
1080 | { | |
1081 | /* Call for side-effect of computing hash and caching extensions */ | |
4ef70dbc | 1082 | if (X509_check_purpose(x, -1, 0) != 1) |
7e06a675 | 1083 | return NULL; |
afdec13d DMSP |
1084 | return (x->akid != NULL ? x->akid->issuer : NULL); |
1085 | } | |
1086 | ||
1087 | const ASN1_INTEGER *X509_get0_authority_serial(X509 *x) | |
1088 | { | |
1089 | /* Call for side-effect of computing hash and caching extensions */ | |
4ef70dbc | 1090 | if (X509_check_purpose(x, -1, 0) != 1) |
7e06a675 | 1091 | return NULL; |
afdec13d DMSP |
1092 | return (x->akid != NULL ? x->akid->serial : NULL); |
1093 | } | |
1094 | ||
e417070c RS |
1095 | long X509_get_pathlen(X509 *x) |
1096 | { | |
1097 | /* Called for side effect of caching extensions */ | |
4ef70dbc | 1098 | if (X509_check_purpose(x, -1, 0) != 1 |
e417070c RS |
1099 | || (x->ex_flags & EXFLAG_BCONS) == 0) |
1100 | return -1; | |
1101 | return x->ex_pathlen; | |
1102 | } | |
fe0169b0 RL |
1103 | |
1104 | long X509_get_proxy_pathlen(X509 *x) | |
1105 | { | |
1106 | /* Called for side effect of caching extensions */ | |
4ef70dbc | 1107 | if (X509_check_purpose(x, -1, 0) != 1 |
fe0169b0 RL |
1108 | || (x->ex_flags & EXFLAG_PROXY) == 0) |
1109 | return -1; | |
1110 | return x->ex_pcpathlen; | |
1111 | } |