Adam Langley | 57707c7 | 2016-01-14 11:25:12 -0800 | [diff] [blame] | 1 | /* |
| 2 | * Written by Dr Stephen N Henson (steve@openssl.org) for the OpenSSL project |
| 3 | * 2001. |
Adam Langley | 95c29f3 | 2014-06-20 12:00:00 -0700 | [diff] [blame] | 4 | */ |
| 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 Langley | 57707c7 | 2016-01-14 11:25:12 -0800 | [diff] [blame] | 13 | * notice, this list of conditions and the following disclaimer. |
Adam Langley | 95c29f3 | 2014-06-20 12:00:00 -0700 | [diff] [blame] | 14 | * |
| 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 Langley | 2b2d66d | 2015-01-30 17:08:37 -0800 | [diff] [blame] | 57 | #include <string.h> |
| 58 | |
Adam Langley | 95c29f3 | 2014-06-20 12:00:00 -0700 | [diff] [blame] | 59 | #include <openssl/digest.h> |
David Benjamin | 260a10c | 2022-06-16 13:58:28 -0400 | [diff] [blame] | 60 | #include <openssl/err.h> |
Adam Langley | 95c29f3 | 2014-06-20 12:00:00 -0700 | [diff] [blame] | 61 | #include <openssl/mem.h> |
| 62 | #include <openssl/obj.h> |
Brian Smith | 054e682 | 2015-03-27 21:12:01 -1000 | [diff] [blame] | 63 | #include <openssl/thread.h> |
David Benjamin | 58906ea | 2023-11-20 23:59:49 -0500 | [diff] [blame] | 64 | #include <openssl/x509.h> |
Adam Langley | 95c29f3 | 2014-06-20 12:00:00 -0700 | [diff] [blame] | 65 | |
Adam Langley | 4bdb6e4 | 2015-05-15 15:29:21 -0700 | [diff] [blame] | 66 | #include "../internal.h" |
David Benjamin | fd86eaa | 2020-06-17 15:13:16 -0400 | [diff] [blame] | 67 | #include "internal.h" |
Adam Langley | 4bdb6e4 | 2015-05-15 15:29:21 -0700 | [diff] [blame] | 68 | |
David Benjamin | 1b08502 | 2023-12-26 07:58:45 -0500 | [diff] [blame] | 69 | |
| 70 | struct 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 Benjamin | 260a10c | 2022-06-16 13:58:28 -0400 | [diff] [blame] | 77 | #define V1_ROOT (EXFLAG_V1 | EXFLAG_SS) |
David Benjamin | 0ea470f | 2015-10-23 18:08:51 -0400 | [diff] [blame] | 78 | #define ku_reject(x, usage) \ |
David Benjamin | 260a10c | 2022-06-16 13:58:28 -0400 | [diff] [blame] | 79 | (((x)->ex_flags & EXFLAG_KUSAGE) && !((x)->ex_kusage & (usage))) |
David Benjamin | 0ea470f | 2015-10-23 18:08:51 -0400 | [diff] [blame] | 80 | #define xku_reject(x, usage) \ |
David Benjamin | 260a10c | 2022-06-16 13:58:28 -0400 | [diff] [blame] | 81 | (((x)->ex_flags & EXFLAG_XKUSAGE) && !((x)->ex_xkusage & (usage))) |
David Benjamin | 0ea470f | 2015-10-23 18:08:51 -0400 | [diff] [blame] | 82 | |
David Benjamin | 5507ccd | 2023-12-26 00:41:06 -0500 | [diff] [blame] | 83 | static int check_ca(const X509 *x); |
Adam Langley | 57707c7 | 2016-01-14 11:25:12 -0800 | [diff] [blame] | 84 | static int check_purpose_ssl_client(const X509_PURPOSE *xp, const X509 *x, |
| 85 | int ca); |
| 86 | static int check_purpose_ssl_server(const X509_PURPOSE *xp, const X509 *x, |
| 87 | int ca); |
| 88 | static int check_purpose_ns_ssl_server(const X509_PURPOSE *xp, const X509 *x, |
| 89 | int ca); |
Adam Langley | 57707c7 | 2016-01-14 11:25:12 -0800 | [diff] [blame] | 90 | static int check_purpose_smime_sign(const X509_PURPOSE *xp, const X509 *x, |
| 91 | int ca); |
| 92 | static int check_purpose_smime_encrypt(const X509_PURPOSE *xp, const X509 *x, |
| 93 | int ca); |
| 94 | static int check_purpose_crl_sign(const X509_PURPOSE *xp, const X509 *x, |
| 95 | int ca); |
| 96 | static int check_purpose_timestamp_sign(const X509_PURPOSE *xp, const X509 *x, |
| 97 | int ca); |
Adam Langley | 95c29f3 | 2014-06-20 12:00:00 -0700 | [diff] [blame] | 98 | static int no_check(const X509_PURPOSE *xp, const X509 *x, int ca); |
Adam Langley | 95c29f3 | 2014-06-20 12:00:00 -0700 | [diff] [blame] | 99 | |
David Benjamin | 5a1a5fb | 2023-12-26 01:35:36 -0500 | [diff] [blame] | 100 | // 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 Benjamin | 6099ab9 | 2023-12-02 17:20:35 -0500 | [diff] [blame] | 105 | static const X509_PURPOSE xstandard[] = { |
David Benjamin | 1b08502 | 2023-12-26 07:58:45 -0500 | [diff] [blame] | 106 | {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 Benjamin | 5507ccd | 2023-12-26 00:41:06 -0500 | [diff] [blame] | 119 | // |X509_PURPOSE_OCSP_HELPER| performs no actual checks. OpenSSL's OCSP |
| 120 | // implementation relied on the caller performing EKU and KU checks. |
David Benjamin | 1b08502 | 2023-12-26 07:58:45 -0500 | [diff] [blame] | 121 | {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 Langley | 95c29f3 | 2014-06-20 12:00:00 -0700 | [diff] [blame] | 124 | }; |
| 125 | |
David Benjamin | 260a10c | 2022-06-16 13:58:28 -0400 | [diff] [blame] | 126 | int X509_check_purpose(X509 *x, int id, int ca) { |
David Benjamin | 0c8bc46 | 2023-12-25 22:52:22 -0500 | [diff] [blame] | 127 | // 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 Benjamin | 260a10c | 2022-06-16 13:58:28 -0400 | [diff] [blame] | 129 | if (!x509v3_cache_extensions(x)) { |
David Benjamin | 0c8bc46 | 2023-12-25 22:52:22 -0500 | [diff] [blame] | 130 | return 0; |
David Benjamin | 260a10c | 2022-06-16 13:58:28 -0400 | [diff] [blame] | 131 | } |
| 132 | |
David Benjamin | c0b87a0 | 2022-06-16 14:02:15 -0400 | [diff] [blame] | 133 | if (id == -1) { |
David Benjamin | 260a10c | 2022-06-16 13:58:28 -0400 | [diff] [blame] | 134 | return 1; |
David Benjamin | c0b87a0 | 2022-06-16 14:02:15 -0400 | [diff] [blame] | 135 | } |
David Benjamin | 8e6a26d | 2023-12-26 08:28:47 -0500 | [diff] [blame^] | 136 | const X509_PURPOSE *pt = X509_PURPOSE_get0(id); |
| 137 | if (pt == NULL) { |
David Benjamin | 0c8bc46 | 2023-12-25 22:52:22 -0500 | [diff] [blame] | 138 | return 0; |
David Benjamin | c0b87a0 | 2022-06-16 14:02:15 -0400 | [diff] [blame] | 139 | } |
David Benjamin | 5507ccd | 2023-12-26 00:41:06 -0500 | [diff] [blame] | 140 | // 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 Benjamin | 260a10c | 2022-06-16 13:58:28 -0400 | [diff] [blame] | 147 | return pt->check_purpose(pt, x, ca); |
Adam Langley | 95c29f3 | 2014-06-20 12:00:00 -0700 | [diff] [blame] | 148 | } |
| 149 | |
David Benjamin | 8e6a26d | 2023-12-26 08:28:47 -0500 | [diff] [blame^] | 150 | const 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 Benjamin | 260a10c | 2022-06-16 13:58:28 -0400 | [diff] [blame] | 155 | } |
David Benjamin | 8e6a26d | 2023-12-26 08:28:47 -0500 | [diff] [blame^] | 156 | return NULL; |
David Benjamin | 260a10c | 2022-06-16 13:58:28 -0400 | [diff] [blame] | 157 | } |
| 158 | |
David Benjamin | cbb96b4 | 2023-06-04 12:50:39 -0400 | [diff] [blame] | 159 | int X509_PURPOSE_get_by_sname(const char *sname) { |
David Benjamin | 8e6a26d | 2023-12-26 08:28:47 -0500 | [diff] [blame^] | 160 | 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 Benjamin | 0beff26 | 2023-12-25 16:41:55 -0500 | [diff] [blame] | 163 | } |
David Benjamin | c0b87a0 | 2022-06-16 14:02:15 -0400 | [diff] [blame] | 164 | } |
David Benjamin | 396f2ef | 2023-12-02 09:21:37 -0500 | [diff] [blame] | 165 | return -1; |
David Benjamin | 260a10c | 2022-06-16 13:58:28 -0400 | [diff] [blame] | 166 | } |
| 167 | |
| 168 | int X509_PURPOSE_get_id(const X509_PURPOSE *xp) { return xp->purpose; } |
| 169 | |
David Benjamin | 260a10c | 2022-06-16 13:58:28 -0400 | [diff] [blame] | 170 | int X509_PURPOSE_get_trust(const X509_PURPOSE *xp) { return xp->trust; } |
| 171 | |
David Benjamin | 09b8fd4 | 2022-07-10 19:14:48 -0400 | [diff] [blame] | 172 | int X509_supported_extension(const X509_EXTENSION *ex) { |
David Benjamin | 7ff31d3 | 2023-11-25 00:38:01 -0500 | [diff] [blame] | 173 | int nid = OBJ_obj2nid(X509_EXTENSION_get_object(ex)); |
David Benjamin | 100e212 | 2023-12-25 23:38:05 -0500 | [diff] [blame] | 174 | return nid == NID_key_usage || // |
David Benjamin | 7ff31d3 | 2023-11-25 00:38:01 -0500 | [diff] [blame] | 175 | 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 Langley | 57707c7 | 2016-01-14 11:25:12 -0800 | [diff] [blame] | 183 | } |
Adam Langley | 95c29f3 | 2014-06-20 12:00:00 -0700 | [diff] [blame] | 184 | |
David Benjamin | 260a10c | 2022-06-16 13:58:28 -0400 | [diff] [blame] | 185 | static int setup_dp(X509 *x, DIST_POINT *dp) { |
David Benjamin | c0b87a0 | 2022-06-16 14:02:15 -0400 | [diff] [blame] | 186 | if (!dp->distpoint || (dp->distpoint->type != 1)) { |
David Benjamin | 260a10c | 2022-06-16 13:58:28 -0400 | [diff] [blame] | 187 | return 1; |
David Benjamin | c0b87a0 | 2022-06-16 14:02:15 -0400 | [diff] [blame] | 188 | } |
David Benjamin | 580c041 | 2023-11-12 14:28:51 -0500 | [diff] [blame] | 189 | X509_NAME *iname = NULL; |
| 190 | for (size_t i = 0; i < sk_GENERAL_NAME_num(dp->CRLissuer); i++) { |
David Benjamin | 260a10c | 2022-06-16 13:58:28 -0400 | [diff] [blame] | 191 | GENERAL_NAME *gen = sk_GENERAL_NAME_value(dp->CRLissuer, i); |
| 192 | if (gen->type == GEN_DIRNAME) { |
| 193 | iname = gen->d.directoryName; |
| 194 | break; |
David Benjamin | 7d75978 | 2016-09-23 19:19:57 -0400 | [diff] [blame] | 195 | } |
David Benjamin | 260a10c | 2022-06-16 13:58:28 -0400 | [diff] [blame] | 196 | } |
David Benjamin | c0b87a0 | 2022-06-16 14:02:15 -0400 | [diff] [blame] | 197 | if (!iname) { |
David Benjamin | 260a10c | 2022-06-16 13:58:28 -0400 | [diff] [blame] | 198 | iname = X509_get_issuer_name(x); |
David Benjamin | c0b87a0 | 2022-06-16 14:02:15 -0400 | [diff] [blame] | 199 | } |
David Benjamin | 7d75978 | 2016-09-23 19:19:57 -0400 | [diff] [blame] | 200 | |
David Benjamin | 260a10c | 2022-06-16 13:58:28 -0400 | [diff] [blame] | 201 | return DIST_POINT_set_dpname(dp->distpoint, iname); |
| 202 | } |
Adam Langley | 4bdb6e4 | 2015-05-15 15:29:21 -0700 | [diff] [blame] | 203 | |
David Benjamin | 260a10c | 2022-06-16 13:58:28 -0400 | [diff] [blame] | 204 | static 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 Langley | 57707c7 | 2016-01-14 11:25:12 -0800 | [diff] [blame] | 213 | } |
David Benjamin | 260a10c | 2022-06-16 13:58:28 -0400 | [diff] [blame] | 214 | } |
| 215 | return 1; |
| 216 | } |
Adam Langley | 95c29f3 | 2014-06-20 12:00:00 -0700 | [diff] [blame] | 217 | |
David Benjamin | 260a10c | 2022-06-16 13:58:28 -0400 | [diff] [blame] | 218 | int x509v3_cache_extensions(X509 *x) { |
| 219 | BASIC_CONSTRAINTS *bs; |
David Benjamin | 260a10c | 2022-06-16 13:58:28 -0400 | [diff] [blame] | 220 | ASN1_BIT_STRING *usage; |
David Benjamin | 260a10c | 2022-06-16 13:58:28 -0400 | [diff] [blame] | 221 | EXTENDED_KEY_USAGE *extusage; |
David Benjamin | 260a10c | 2022-06-16 13:58:28 -0400 | [diff] [blame] | 222 | size_t i; |
| 223 | int j; |
Adam Langley | 95c29f3 | 2014-06-20 12:00:00 -0700 | [diff] [blame] | 224 | |
David Benjamin | 260a10c | 2022-06-16 13:58:28 -0400 | [diff] [blame] | 225 | CRYPTO_MUTEX_lock_read(&x->lock); |
| 226 | const int is_set = x->ex_flags & EXFLAG_SET; |
| 227 | CRYPTO_MUTEX_unlock_read(&x->lock); |
Adam Langley | 95c29f3 | 2014-06-20 12:00:00 -0700 | [diff] [blame] | 228 | |
David Benjamin | 260a10c | 2022-06-16 13:58:28 -0400 | [diff] [blame] | 229 | if (is_set) { |
| 230 | return (x->ex_flags & EXFLAG_INVALID) == 0; |
| 231 | } |
Adam Langley | 95c29f3 | 2014-06-20 12:00:00 -0700 | [diff] [blame] | 232 | |
David Benjamin | 260a10c | 2022-06-16 13:58:28 -0400 | [diff] [blame] | 233 | CRYPTO_MUTEX_lock_write(&x->lock); |
| 234 | if (x->ex_flags & EXFLAG_SET) { |
David Benjamin | 7d75978 | 2016-09-23 19:19:57 -0400 | [diff] [blame] | 235 | CRYPTO_MUTEX_unlock_write(&x->lock); |
David Benjamin | fd86eaa | 2020-06-17 15:13:16 -0400 | [diff] [blame] | 236 | return (x->ex_flags & EXFLAG_INVALID) == 0; |
David Benjamin | 260a10c | 2022-06-16 13:58:28 -0400 | [diff] [blame] | 237 | } |
| 238 | |
David Benjamin | c0b87a0 | 2022-06-16 14:02:15 -0400 | [diff] [blame] | 239 | if (!X509_digest(x, EVP_sha256(), x->cert_hash, NULL)) { |
David Benjamin | 260a10c | 2022-06-16 13:58:28 -0400 | [diff] [blame] | 240 | x->ex_flags |= EXFLAG_INVALID; |
David Benjamin | c0b87a0 | 2022-06-16 14:02:15 -0400 | [diff] [blame] | 241 | } |
David Benjamin | 4635048 | 2022-06-16 14:03:12 -0400 | [diff] [blame] | 242 | // V1 should mean no extensions ... |
David Benjamin | c0b87a0 | 2022-06-16 14:02:15 -0400 | [diff] [blame] | 243 | if (X509_get_version(x) == X509_VERSION_1) { |
David Benjamin | 260a10c | 2022-06-16 13:58:28 -0400 | [diff] [blame] | 244 | x->ex_flags |= EXFLAG_V1; |
David Benjamin | c0b87a0 | 2022-06-16 14:02:15 -0400 | [diff] [blame] | 245 | } |
David Benjamin | 4635048 | 2022-06-16 14:03:12 -0400 | [diff] [blame] | 246 | // Handle basic constraints |
David Benjamin | 260a10c | 2022-06-16 13:58:28 -0400 | [diff] [blame] | 247 | if ((bs = X509_get_ext_d2i(x, NID_basic_constraints, &j, NULL))) { |
David Benjamin | c0b87a0 | 2022-06-16 14:02:15 -0400 | [diff] [blame] | 248 | if (bs->ca) { |
David Benjamin | 260a10c | 2022-06-16 13:58:28 -0400 | [diff] [blame] | 249 | x->ex_flags |= EXFLAG_CA; |
David Benjamin | c0b87a0 | 2022-06-16 14:02:15 -0400 | [diff] [blame] | 250 | } |
David Benjamin | 260a10c | 2022-06-16 13:58:28 -0400 | [diff] [blame] | 251 | 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 Benjamin | 4635048 | 2022-06-16 14:03:12 -0400 | [diff] [blame] | 256 | // 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 Benjamin | 260a10c | 2022-06-16 13:58:28 -0400 | [diff] [blame] | 261 | x->ex_pathlen = ASN1_INTEGER_get(bs->pathlen); |
| 262 | } |
David Benjamin | c0b87a0 | 2022-06-16 14:02:15 -0400 | [diff] [blame] | 263 | } else { |
David Benjamin | 260a10c | 2022-06-16 13:58:28 -0400 | [diff] [blame] | 264 | x->ex_pathlen = -1; |
David Benjamin | c0b87a0 | 2022-06-16 14:02:15 -0400 | [diff] [blame] | 265 | } |
David Benjamin | 260a10c | 2022-06-16 13:58:28 -0400 | [diff] [blame] | 266 | BASIC_CONSTRAINTS_free(bs); |
| 267 | x->ex_flags |= EXFLAG_BCONS; |
| 268 | } else if (j != -1) { |
| 269 | x->ex_flags |= EXFLAG_INVALID; |
| 270 | } |
David Benjamin | 4635048 | 2022-06-16 14:03:12 -0400 | [diff] [blame] | 271 | // Handle key usage |
David Benjamin | 260a10c | 2022-06-16 13:58:28 -0400 | [diff] [blame] | 272 | 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 Benjamin | c0b87a0 | 2022-06-16 14:02:15 -0400 | [diff] [blame] | 275 | if (usage->length > 1) { |
David Benjamin | 260a10c | 2022-06-16 13:58:28 -0400 | [diff] [blame] | 276 | x->ex_kusage |= usage->data[1] << 8; |
David Benjamin | c0b87a0 | 2022-06-16 14:02:15 -0400 | [diff] [blame] | 277 | } |
| 278 | } else { |
David Benjamin | 260a10c | 2022-06-16 13:58:28 -0400 | [diff] [blame] | 279 | x->ex_kusage = 0; |
David Benjamin | c0b87a0 | 2022-06-16 14:02:15 -0400 | [diff] [blame] | 280 | } |
David Benjamin | 260a10c | 2022-06-16 13:58:28 -0400 | [diff] [blame] | 281 | 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 Benjamin | 260a10c | 2022-06-16 13:58:28 -0400 | [diff] [blame] | 334 | 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 Benjamin | 4635048 | 2022-06-16 14:03:12 -0400 | [diff] [blame] | 342 | // Does subject name match issuer ? |
David Benjamin | 260a10c | 2022-06-16 13:58:28 -0400 | [diff] [blame] | 343 | if (!X509_NAME_cmp(X509_get_subject_name(x), X509_get_issuer_name(x))) { |
| 344 | x->ex_flags |= EXFLAG_SI; |
David Benjamin | 4635048 | 2022-06-16 14:03:12 -0400 | [diff] [blame] | 345 | // If SKID matches AKID also indicate self signed |
David Benjamin | 260a10c | 2022-06-16 13:58:28 -0400 | [diff] [blame] | 346 | if (X509_check_akid(x, x->akid) == X509_V_OK && |
David Benjamin | 314c252 | 2023-11-27 23:26:09 -0500 | [diff] [blame] | 347 | !ku_reject(x, X509v3_KU_KEY_CERT_SIGN)) { |
David Benjamin | 260a10c | 2022-06-16 13:58:28 -0400 | [diff] [blame] | 348 | x->ex_flags |= EXFLAG_SS; |
David Benjamin | c0b87a0 | 2022-06-16 14:02:15 -0400 | [diff] [blame] | 349 | } |
David Benjamin | 260a10c | 2022-06-16 13:58:28 -0400 | [diff] [blame] | 350 | } |
| 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 Benjamin | 09b8fd4 | 2022-07-10 19:14:48 -0400 | [diff] [blame] | 364 | const X509_EXTENSION *ex = X509_get_ext(x, j); |
David Benjamin | c0b87a0 | 2022-06-16 14:02:15 -0400 | [diff] [blame] | 365 | if (!X509_EXTENSION_get_critical(ex)) { |
David Benjamin | 260a10c | 2022-06-16 13:58:28 -0400 | [diff] [blame] | 366 | continue; |
David Benjamin | c0b87a0 | 2022-06-16 14:02:15 -0400 | [diff] [blame] | 367 | } |
David Benjamin | 260a10c | 2022-06-16 13:58:28 -0400 | [diff] [blame] | 368 | 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 Langley | 95c29f3 | 2014-06-20 12:00:00 -0700 | [diff] [blame] | 377 | } |
| 378 | |
David Benjamin | 4635048 | 2022-06-16 14:03:12 -0400 | [diff] [blame] | 379 | // check_ca returns one if |x| should be considered a CA certificate and zero |
| 380 | // otherwise. |
David Benjamin | 260a10c | 2022-06-16 13:58:28 -0400 | [diff] [blame] | 381 | static int check_ca(const X509 *x) { |
David Benjamin | 4635048 | 2022-06-16 14:03:12 -0400 | [diff] [blame] | 382 | // keyUsage if present should allow cert signing |
David Benjamin | 314c252 | 2023-11-27 23:26:09 -0500 | [diff] [blame] | 383 | if (ku_reject(x, X509v3_KU_KEY_CERT_SIGN)) { |
David Benjamin | 260a10c | 2022-06-16 13:58:28 -0400 | [diff] [blame] | 384 | return 0; |
David Benjamin | c0b87a0 | 2022-06-16 14:02:15 -0400 | [diff] [blame] | 385 | } |
David Benjamin | 4635048 | 2022-06-16 14:03:12 -0400 | [diff] [blame] | 386 | // Version 1 certificates are considered CAs and don't have extensions. |
David Benjamin | 260a10c | 2022-06-16 13:58:28 -0400 | [diff] [blame] | 387 | if ((x->ex_flags & V1_ROOT) == V1_ROOT) { |
| 388 | return 1; |
| 389 | } |
David Benjamin | 4635048 | 2022-06-16 14:03:12 -0400 | [diff] [blame] | 390 | // Otherwise, it's only a CA if basicConstraints says so. |
David Benjamin | 260a10c | 2022-06-16 13:58:28 -0400 | [diff] [blame] | 391 | return ((x->ex_flags & EXFLAG_BCONS) && (x->ex_flags & EXFLAG_CA)); |
Adam Langley | 95c29f3 | 2014-06-20 12:00:00 -0700 | [diff] [blame] | 392 | } |
| 393 | |
David Benjamin | 260a10c | 2022-06-16 13:58:28 -0400 | [diff] [blame] | 394 | int X509_check_ca(X509 *x) { |
| 395 | if (!x509v3_cache_extensions(x)) { |
| 396 | return 0; |
| 397 | } |
| 398 | return check_ca(x); |
Adam Langley | 95c29f3 | 2014-06-20 12:00:00 -0700 | [diff] [blame] | 399 | } |
| 400 | |
David Benjamin | 5507ccd | 2023-12-26 00:41:06 -0500 | [diff] [blame] | 401 | // 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. |
| 404 | static 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 Langley | 57707c7 | 2016-01-14 11:25:12 -0800 | [diff] [blame] | 415 | static int check_purpose_ssl_client(const X509_PURPOSE *xp, const X509 *x, |
David Benjamin | 260a10c | 2022-06-16 13:58:28 -0400 | [diff] [blame] | 416 | int ca) { |
David Benjamin | 5507ccd | 2023-12-26 00:41:06 -0500 | [diff] [blame] | 417 | // 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 Langley | 95c29f3 | 2014-06-20 12:00:00 -0700 | [diff] [blame] | 423 | } |
Adam Langley | 57707c7 | 2016-01-14 11:25:12 -0800 | [diff] [blame] | 424 | |
David Benjamin | 4635048 | 2022-06-16 14:03:12 -0400 | [diff] [blame] | 425 | // 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 Benjamin | 314c252 | 2023-11-27 23:26:09 -0500 | [diff] [blame] | 428 | #define X509v3_KU_TLS \ |
| 429 | (X509v3_KU_DIGITAL_SIGNATURE | X509v3_KU_KEY_ENCIPHERMENT | \ |
| 430 | X509v3_KU_KEY_AGREEMENT) |
Adam Langley | 95c29f3 | 2014-06-20 12:00:00 -0700 | [diff] [blame] | 431 | |
Adam Langley | 57707c7 | 2016-01-14 11:25:12 -0800 | [diff] [blame] | 432 | static int check_purpose_ssl_server(const X509_PURPOSE *xp, const X509 *x, |
David Benjamin | 260a10c | 2022-06-16 13:58:28 -0400 | [diff] [blame] | 433 | int ca) { |
David Benjamin | 5507ccd | 2023-12-26 00:41:06 -0500 | [diff] [blame] | 434 | return check_purpose(x, ca, XKU_SSL_SERVER, X509v3_KU_TLS); |
Adam Langley | 95c29f3 | 2014-06-20 12:00:00 -0700 | [diff] [blame] | 435 | } |
| 436 | |
Adam Langley | 57707c7 | 2016-01-14 11:25:12 -0800 | [diff] [blame] | 437 | static int check_purpose_ns_ssl_server(const X509_PURPOSE *xp, const X509 *x, |
David Benjamin | 260a10c | 2022-06-16 13:58:28 -0400 | [diff] [blame] | 438 | int ca) { |
David Benjamin | 5507ccd | 2023-12-26 00:41:06 -0500 | [diff] [blame] | 439 | // We need to encipher or Netscape complains. |
| 440 | return check_purpose(x, ca, XKU_SSL_SERVER, X509v3_KU_KEY_ENCIPHERMENT); |
Adam Langley | 95c29f3 | 2014-06-20 12:00:00 -0700 | [diff] [blame] | 441 | } |
| 442 | |
Adam Langley | 57707c7 | 2016-01-14 11:25:12 -0800 | [diff] [blame] | 443 | static int check_purpose_smime_sign(const X509_PURPOSE *xp, const X509 *x, |
David Benjamin | 260a10c | 2022-06-16 13:58:28 -0400 | [diff] [blame] | 444 | int ca) { |
David Benjamin | 5507ccd | 2023-12-26 00:41:06 -0500 | [diff] [blame] | 445 | return check_purpose(x, ca, XKU_SMIME, |
| 446 | X509v3_KU_DIGITAL_SIGNATURE | X509v3_KU_NON_REPUDIATION); |
Adam Langley | 95c29f3 | 2014-06-20 12:00:00 -0700 | [diff] [blame] | 447 | } |
| 448 | |
Adam Langley | 57707c7 | 2016-01-14 11:25:12 -0800 | [diff] [blame] | 449 | static int check_purpose_smime_encrypt(const X509_PURPOSE *xp, const X509 *x, |
David Benjamin | 260a10c | 2022-06-16 13:58:28 -0400 | [diff] [blame] | 450 | int ca) { |
David Benjamin | 5507ccd | 2023-12-26 00:41:06 -0500 | [diff] [blame] | 451 | return check_purpose(x, ca, XKU_SMIME, X509v3_KU_KEY_ENCIPHERMENT); |
Adam Langley | 95c29f3 | 2014-06-20 12:00:00 -0700 | [diff] [blame] | 452 | } |
| 453 | |
Adam Langley | 57707c7 | 2016-01-14 11:25:12 -0800 | [diff] [blame] | 454 | static int check_purpose_crl_sign(const X509_PURPOSE *xp, const X509 *x, |
David Benjamin | 260a10c | 2022-06-16 13:58:28 -0400 | [diff] [blame] | 455 | int ca) { |
David Benjamin | 5507ccd | 2023-12-26 00:41:06 -0500 | [diff] [blame] | 456 | return check_purpose(x, ca, /*required_xku=*/0, X509v3_KU_CRL_SIGN); |
Adam Langley | 95c29f3 | 2014-06-20 12:00:00 -0700 | [diff] [blame] | 457 | } |
| 458 | |
| 459 | static int check_purpose_timestamp_sign(const X509_PURPOSE *xp, const X509 *x, |
David Benjamin | 260a10c | 2022-06-16 13:58:28 -0400 | [diff] [blame] | 460 | int ca) { |
David Benjamin | c0b87a0 | 2022-06-16 14:02:15 -0400 | [diff] [blame] | 461 | if (ca) { |
David Benjamin | 5507ccd | 2023-12-26 00:41:06 -0500 | [diff] [blame] | 462 | return 1; |
David Benjamin | c0b87a0 | 2022-06-16 14:02:15 -0400 | [diff] [blame] | 463 | } |
Adam Langley | 95c29f3 | 2014-06-20 12:00:00 -0700 | [diff] [blame] | 464 | |
David Benjamin | 4635048 | 2022-06-16 14:03:12 -0400 | [diff] [blame] | 465 | // 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 Benjamin | 260a10c | 2022-06-16 13:58:28 -0400 | [diff] [blame] | 469 | if ((x->ex_flags & EXFLAG_KUSAGE) && |
David Benjamin | 314c252 | 2023-11-27 23:26:09 -0500 | [diff] [blame] | 470 | ((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 Benjamin | 260a10c | 2022-06-16 13:58:28 -0400 | [diff] [blame] | 474 | return 0; |
David Benjamin | c0b87a0 | 2022-06-16 14:02:15 -0400 | [diff] [blame] | 475 | } |
Adam Langley | 95c29f3 | 2014-06-20 12:00:00 -0700 | [diff] [blame] | 476 | |
David Benjamin | 4635048 | 2022-06-16 14:03:12 -0400 | [diff] [blame] | 477 | // Only time stamp key usage is permitted and it's required. |
David Benjamin | 5507ccd | 2023-12-26 00:41:06 -0500 | [diff] [blame] | 478 | // |
| 479 | // TODO(davidben): Should we check EKUs up the chain like the other cases? |
David Benjamin | c0b87a0 | 2022-06-16 14:02:15 -0400 | [diff] [blame] | 480 | if (!(x->ex_flags & EXFLAG_XKUSAGE) || x->ex_xkusage != XKU_TIMESTAMP) { |
David Benjamin | 260a10c | 2022-06-16 13:58:28 -0400 | [diff] [blame] | 481 | return 0; |
David Benjamin | c0b87a0 | 2022-06-16 14:02:15 -0400 | [diff] [blame] | 482 | } |
Adam Langley | 95c29f3 | 2014-06-20 12:00:00 -0700 | [diff] [blame] | 483 | |
David Benjamin | 4635048 | 2022-06-16 14:03:12 -0400 | [diff] [blame] | 484 | // Extended Key Usage MUST be critical |
David Benjamin | 352740c | 2023-12-25 18:24:41 -0500 | [diff] [blame] | 485 | int i_ext = X509_get_ext_by_NID(x, NID_ext_key_usage, -1); |
David Benjamin | 260a10c | 2022-06-16 13:58:28 -0400 | [diff] [blame] | 486 | if (i_ext >= 0) { |
David Benjamin | 352740c | 2023-12-25 18:24:41 -0500 | [diff] [blame] | 487 | const X509_EXTENSION *ext = X509_get_ext(x, i_ext); |
David Benjamin | c0b87a0 | 2022-06-16 14:02:15 -0400 | [diff] [blame] | 488 | if (!X509_EXTENSION_get_critical(ext)) { |
David Benjamin | 260a10c | 2022-06-16 13:58:28 -0400 | [diff] [blame] | 489 | return 0; |
David Benjamin | c0b87a0 | 2022-06-16 14:02:15 -0400 | [diff] [blame] | 490 | } |
David Benjamin | 260a10c | 2022-06-16 13:58:28 -0400 | [diff] [blame] | 491 | } |
Adam Langley | 95c29f3 | 2014-06-20 12:00:00 -0700 | [diff] [blame] | 492 | |
David Benjamin | 260a10c | 2022-06-16 13:58:28 -0400 | [diff] [blame] | 493 | return 1; |
Adam Langley | 95c29f3 | 2014-06-20 12:00:00 -0700 | [diff] [blame] | 494 | } |
| 495 | |
David Benjamin | 260a10c | 2022-06-16 13:58:28 -0400 | [diff] [blame] | 496 | static int no_check(const X509_PURPOSE *xp, const X509 *x, int ca) { return 1; } |
Adam Langley | 95c29f3 | 2014-06-20 12:00:00 -0700 | [diff] [blame] | 497 | |
David Benjamin | 260a10c | 2022-06-16 13:58:28 -0400 | [diff] [blame] | 498 | int X509_check_issued(X509 *issuer, X509 *subject) { |
| 499 | if (X509_NAME_cmp(X509_get_subject_name(issuer), |
David Benjamin | c0b87a0 | 2022-06-16 14:02:15 -0400 | [diff] [blame] | 500 | X509_get_issuer_name(subject))) { |
David Benjamin | 260a10c | 2022-06-16 13:58:28 -0400 | [diff] [blame] | 501 | return X509_V_ERR_SUBJECT_ISSUER_MISMATCH; |
David Benjamin | c0b87a0 | 2022-06-16 14:02:15 -0400 | [diff] [blame] | 502 | } |
David Benjamin | 260a10c | 2022-06-16 13:58:28 -0400 | [diff] [blame] | 503 | if (!x509v3_cache_extensions(issuer) || !x509v3_cache_extensions(subject)) { |
| 504 | return X509_V_ERR_UNSPECIFIED; |
| 505 | } |
Adam Langley | 95c29f3 | 2014-06-20 12:00:00 -0700 | [diff] [blame] | 506 | |
David Benjamin | 260a10c | 2022-06-16 13:58:28 -0400 | [diff] [blame] | 507 | if (subject->akid) { |
| 508 | int ret = X509_check_akid(issuer, subject->akid); |
David Benjamin | c0b87a0 | 2022-06-16 14:02:15 -0400 | [diff] [blame] | 509 | if (ret != X509_V_OK) { |
David Benjamin | 260a10c | 2022-06-16 13:58:28 -0400 | [diff] [blame] | 510 | return ret; |
David Benjamin | c0b87a0 | 2022-06-16 14:02:15 -0400 | [diff] [blame] | 511 | } |
David Benjamin | 260a10c | 2022-06-16 13:58:28 -0400 | [diff] [blame] | 512 | } |
Adam Langley | 95c29f3 | 2014-06-20 12:00:00 -0700 | [diff] [blame] | 513 | |
David Benjamin | 314c252 | 2023-11-27 23:26:09 -0500 | [diff] [blame] | 514 | if (ku_reject(issuer, X509v3_KU_KEY_CERT_SIGN)) { |
David Benjamin | 260a10c | 2022-06-16 13:58:28 -0400 | [diff] [blame] | 515 | return X509_V_ERR_KEYUSAGE_NO_CERTSIGN; |
David Benjamin | c0b87a0 | 2022-06-16 14:02:15 -0400 | [diff] [blame] | 516 | } |
David Benjamin | 260a10c | 2022-06-16 13:58:28 -0400 | [diff] [blame] | 517 | return X509_V_OK; |
| 518 | } |
| 519 | |
David Benjamin | 9e40481 | 2023-12-06 22:33:21 -0500 | [diff] [blame] | 520 | int X509_check_akid(X509 *issuer, const AUTHORITY_KEYID *akid) { |
David Benjamin | c0b87a0 | 2022-06-16 14:02:15 -0400 | [diff] [blame] | 521 | if (!akid) { |
Adam Langley | 57707c7 | 2016-01-14 11:25:12 -0800 | [diff] [blame] | 522 | return X509_V_OK; |
David Benjamin | c0b87a0 | 2022-06-16 14:02:15 -0400 | [diff] [blame] | 523 | } |
Adam Langley | 95c29f3 | 2014-06-20 12:00:00 -0700 | [diff] [blame] | 524 | |
David Benjamin | 4635048 | 2022-06-16 14:03:12 -0400 | [diff] [blame] | 525 | // Check key ids (if present) |
David Benjamin | 260a10c | 2022-06-16 13:58:28 -0400 | [diff] [blame] | 526 | if (akid->keyid && issuer->skid && |
David Benjamin | c0b87a0 | 2022-06-16 14:02:15 -0400 | [diff] [blame] | 527 | ASN1_OCTET_STRING_cmp(akid->keyid, issuer->skid)) { |
David Benjamin | 260a10c | 2022-06-16 13:58:28 -0400 | [diff] [blame] | 528 | return X509_V_ERR_AKID_SKID_MISMATCH; |
David Benjamin | c0b87a0 | 2022-06-16 14:02:15 -0400 | [diff] [blame] | 529 | } |
David Benjamin | 4635048 | 2022-06-16 14:03:12 -0400 | [diff] [blame] | 530 | // Check serial number |
David Benjamin | 260a10c | 2022-06-16 13:58:28 -0400 | [diff] [blame] | 531 | if (akid->serial && |
David Benjamin | c0b87a0 | 2022-06-16 14:02:15 -0400 | [diff] [blame] | 532 | ASN1_INTEGER_cmp(X509_get_serialNumber(issuer), akid->serial)) { |
David Benjamin | 260a10c | 2022-06-16 13:58:28 -0400 | [diff] [blame] | 533 | return X509_V_ERR_AKID_ISSUER_SERIAL_MISMATCH; |
David Benjamin | c0b87a0 | 2022-06-16 14:02:15 -0400 | [diff] [blame] | 534 | } |
David Benjamin | 4635048 | 2022-06-16 14:03:12 -0400 | [diff] [blame] | 535 | // Check issuer name |
David Benjamin | 260a10c | 2022-06-16 13:58:28 -0400 | [diff] [blame] | 536 | if (akid->issuer) { |
David Benjamin | 4635048 | 2022-06-16 14:03:12 -0400 | [diff] [blame] | 537 | // 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 Benjamin | 260a10c | 2022-06-16 13:58:28 -0400 | [diff] [blame] | 540 | 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 Langley | 57707c7 | 2016-01-14 11:25:12 -0800 | [diff] [blame] | 551 | } |
David Benjamin | c0b87a0 | 2022-06-16 14:02:15 -0400 | [diff] [blame] | 552 | if (nm && X509_NAME_cmp(nm, X509_get_issuer_name(issuer))) { |
David Benjamin | 260a10c | 2022-06-16 13:58:28 -0400 | [diff] [blame] | 553 | return X509_V_ERR_AKID_ISSUER_SERIAL_MISMATCH; |
David Benjamin | c0b87a0 | 2022-06-16 14:02:15 -0400 | [diff] [blame] | 554 | } |
David Benjamin | 260a10c | 2022-06-16 13:58:28 -0400 | [diff] [blame] | 555 | } |
| 556 | return X509_V_OK; |
Adam Langley | 57707c7 | 2016-01-14 11:25:12 -0800 | [diff] [blame] | 557 | } |
David Benjamin | bc3286b | 2018-08-13 17:52:48 -0500 | [diff] [blame] | 558 | |
David Benjamin | 260a10c | 2022-06-16 13:58:28 -0400 | [diff] [blame] | 559 | uint32_t X509_get_extension_flags(X509 *x) { |
David Benjamin | 4635048 | 2022-06-16 14:03:12 -0400 | [diff] [blame] | 560 | // Ignore the return value. On failure, |x->ex_flags| will include |
| 561 | // |EXFLAG_INVALID|. |
David Benjamin | 260a10c | 2022-06-16 13:58:28 -0400 | [diff] [blame] | 562 | x509v3_cache_extensions(x); |
| 563 | return x->ex_flags; |
David Benjamin | bc3286b | 2018-08-13 17:52:48 -0500 | [diff] [blame] | 564 | } |
| 565 | |
David Benjamin | 260a10c | 2022-06-16 13:58:28 -0400 | [diff] [blame] | 566 | uint32_t X509_get_key_usage(X509 *x) { |
| 567 | if (!x509v3_cache_extensions(x)) { |
| 568 | return 0; |
| 569 | } |
David Benjamin | c0b87a0 | 2022-06-16 14:02:15 -0400 | [diff] [blame] | 570 | if (x->ex_flags & EXFLAG_KUSAGE) { |
David Benjamin | 260a10c | 2022-06-16 13:58:28 -0400 | [diff] [blame] | 571 | return x->ex_kusage; |
David Benjamin | c0b87a0 | 2022-06-16 14:02:15 -0400 | [diff] [blame] | 572 | } |
David Benjamin | 314c252 | 2023-11-27 23:26:09 -0500 | [diff] [blame] | 573 | // 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 Benjamin | 260a10c | 2022-06-16 13:58:28 -0400 | [diff] [blame] | 576 | return UINT32_MAX; |
David Benjamin | bc3286b | 2018-08-13 17:52:48 -0500 | [diff] [blame] | 577 | } |
| 578 | |
David Benjamin | 260a10c | 2022-06-16 13:58:28 -0400 | [diff] [blame] | 579 | uint32_t X509_get_extended_key_usage(X509 *x) { |
| 580 | if (!x509v3_cache_extensions(x)) { |
| 581 | return 0; |
| 582 | } |
David Benjamin | c0b87a0 | 2022-06-16 14:02:15 -0400 | [diff] [blame] | 583 | if (x->ex_flags & EXFLAG_XKUSAGE) { |
David Benjamin | 260a10c | 2022-06-16 13:58:28 -0400 | [diff] [blame] | 584 | return x->ex_xkusage; |
David Benjamin | c0b87a0 | 2022-06-16 14:02:15 -0400 | [diff] [blame] | 585 | } |
David Benjamin | 314c252 | 2023-11-27 23:26:09 -0500 | [diff] [blame] | 586 | // If there is no extension, extended key usage is unconstrained, so set all |
| 587 | // bits to one. |
David Benjamin | 260a10c | 2022-06-16 13:58:28 -0400 | [diff] [blame] | 588 | return UINT32_MAX; |
David Benjamin | bc3286b | 2018-08-13 17:52:48 -0500 | [diff] [blame] | 589 | } |
David Benjamin | 298d8be | 2020-08-24 16:54:35 -0400 | [diff] [blame] | 590 | |
David Benjamin | 260a10c | 2022-06-16 13:58:28 -0400 | [diff] [blame] | 591 | const 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 Benjamin | 298d8be | 2020-08-24 16:54:35 -0400 | [diff] [blame] | 596 | } |
| 597 | |
David Benjamin | 260a10c | 2022-06-16 13:58:28 -0400 | [diff] [blame] | 598 | const 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 Benjamin | 298d8be | 2020-08-24 16:54:35 -0400 | [diff] [blame] | 603 | } |
| 604 | |
David Benjamin | 260a10c | 2022-06-16 13:58:28 -0400 | [diff] [blame] | 605 | const 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 Benjamin | 298d8be | 2020-08-24 16:54:35 -0400 | [diff] [blame] | 610 | } |
| 611 | |
David Benjamin | 260a10c | 2022-06-16 13:58:28 -0400 | [diff] [blame] | 612 | const 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 Benjamin | 298d8be | 2020-08-24 16:54:35 -0400 | [diff] [blame] | 617 | } |
David Benjamin | ee4af9e | 2020-08-31 16:54:47 -0400 | [diff] [blame] | 618 | |
David Benjamin | 260a10c | 2022-06-16 13:58:28 -0400 | [diff] [blame] | 619 | long 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 Benjamin | ee4af9e | 2020-08-31 16:54:47 -0400 | [diff] [blame] | 624 | } |