blob: 71cf71dccb19aea9f9b7383695ac426374a6a2ae [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 * 1999.
4 */
Adam Langley95c29f32014-06-20 12:00:00 -07005/* ====================================================================
6 * Copyright (c) 1999 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 Langley95c29f32014-06-20 12:00:00 -070057#include <openssl/err.h>
58#include <openssl/mem.h>
59#include <openssl/obj.h>
60#include <openssl/x509v3.h>
61
David Benjaminfd86eaa2020-06-17 15:13:16 -040062#include "../x509v3/internal.h"
David Benjamin9f55d972021-05-05 16:37:05 -040063#include "internal.h"
64
David Benjaminfd86eaa2020-06-17 15:13:16 -040065
David Benjaminaf0739f2023-01-09 10:03:02 -080066static int tr_cmp(const X509_TRUST *const *a, const X509_TRUST *const *b);
Adam Langley95c29f32014-06-20 12:00:00 -070067static void trtable_free(X509_TRUST *p);
68
69static int trust_1oidany(X509_TRUST *trust, X509 *x, int flags);
70static int trust_1oid(X509_TRUST *trust, X509 *x, int flags);
71static int trust_compat(X509_TRUST *trust, X509 *x, int flags);
72
73static int obj_trust(int id, X509 *x, int flags);
Adam Langley95c29f32014-06-20 12:00:00 -070074
David Benjamin46350482022-06-16 14:03:12 -040075// WARNING: the following table should be kept in order of trust and without
76// any gaps so we can just subtract the minimum trust value to get an index
77// into the table
Adam Langley95c29f32014-06-20 12:00:00 -070078
79static X509_TRUST trstandard[] = {
Adam Langley57707c72016-01-14 11:25:12 -080080 {X509_TRUST_COMPAT, 0, trust_compat, (char *)"compatible", 0, NULL},
81 {X509_TRUST_SSL_CLIENT, 0, trust_1oidany, (char *)"SSL Client",
82 NID_client_auth, NULL},
83 {X509_TRUST_SSL_SERVER, 0, trust_1oidany, (char *)"SSL Server",
84 NID_server_auth, NULL},
85 {X509_TRUST_EMAIL, 0, trust_1oidany, (char *)"S/MIME email",
86 NID_email_protect, NULL},
87 {X509_TRUST_OBJECT_SIGN, 0, trust_1oidany, (char *)"Object Signer",
88 NID_code_sign, NULL},
89 {X509_TRUST_OCSP_SIGN, 0, trust_1oid, (char *)"OCSP responder",
90 NID_OCSP_sign, NULL},
91 {X509_TRUST_OCSP_REQUEST, 0, trust_1oid, (char *)"OCSP request",
92 NID_ad_OCSP, NULL},
93 {X509_TRUST_TSA, 0, trust_1oidany, (char *)"TSA server", NID_time_stamp,
David Benjamin260a10c2022-06-16 13:58:28 -040094 NULL}};
Adam Langley95c29f32014-06-20 12:00:00 -070095
David Benjamin260a10c2022-06-16 13:58:28 -040096#define X509_TRUST_COUNT (sizeof(trstandard) / sizeof(X509_TRUST))
Adam Langley95c29f32014-06-20 12:00:00 -070097
98static STACK_OF(X509_TRUST) *trtable = NULL;
99
David Benjaminaf0739f2023-01-09 10:03:02 -0800100static int tr_cmp(const X509_TRUST *const *a, const X509_TRUST *const *b) {
David Benjamin260a10c2022-06-16 13:58:28 -0400101 return (*a)->trust - (*b)->trust;
Adam Langley95c29f32014-06-20 12:00:00 -0700102}
103
David Benjamin260a10c2022-06-16 13:58:28 -0400104int X509_check_trust(X509 *x, int id, int flags) {
105 X509_TRUST *pt;
106 int idx;
David Benjaminc0b87a02022-06-16 14:02:15 -0400107 if (id == -1) {
David Benjamin260a10c2022-06-16 13:58:28 -0400108 return 1;
David Benjaminc0b87a02022-06-16 14:02:15 -0400109 }
David Benjamin46350482022-06-16 14:03:12 -0400110 // We get this as a default value
David Benjamin260a10c2022-06-16 13:58:28 -0400111 if (id == 0) {
112 int rv;
113 rv = obj_trust(NID_anyExtendedKeyUsage, x, 0);
David Benjaminc0b87a02022-06-16 14:02:15 -0400114 if (rv != X509_TRUST_UNTRUSTED) {
David Benjamin260a10c2022-06-16 13:58:28 -0400115 return rv;
David Benjaminc0b87a02022-06-16 14:02:15 -0400116 }
David Benjamin260a10c2022-06-16 13:58:28 -0400117 return trust_compat(NULL, x, 0);
118 }
119 idx = X509_TRUST_get_by_id(id);
David Benjaminc0b87a02022-06-16 14:02:15 -0400120 if (idx == -1) {
David Benjamin260a10c2022-06-16 13:58:28 -0400121 return obj_trust(id, x, flags);
David Benjaminc0b87a02022-06-16 14:02:15 -0400122 }
David Benjamin260a10c2022-06-16 13:58:28 -0400123 pt = X509_TRUST_get0(idx);
124 return pt->check_trust(pt, x, flags);
125}
126
127int X509_TRUST_get_count(void) {
David Benjaminc0b87a02022-06-16 14:02:15 -0400128 if (!trtable) {
David Benjamin260a10c2022-06-16 13:58:28 -0400129 return X509_TRUST_COUNT;
David Benjaminc0b87a02022-06-16 14:02:15 -0400130 }
David Benjamin260a10c2022-06-16 13:58:28 -0400131 return sk_X509_TRUST_num(trtable) + X509_TRUST_COUNT;
132}
133
134X509_TRUST *X509_TRUST_get0(int idx) {
David Benjaminc0b87a02022-06-16 14:02:15 -0400135 if (idx < 0) {
David Benjamin260a10c2022-06-16 13:58:28 -0400136 return NULL;
David Benjaminc0b87a02022-06-16 14:02:15 -0400137 }
138 if (idx < (int)X509_TRUST_COUNT) {
David Benjamin260a10c2022-06-16 13:58:28 -0400139 return trstandard + idx;
David Benjaminc0b87a02022-06-16 14:02:15 -0400140 }
David Benjamin260a10c2022-06-16 13:58:28 -0400141 return sk_X509_TRUST_value(trtable, idx - X509_TRUST_COUNT);
142}
143
144int X509_TRUST_get_by_id(int id) {
145 X509_TRUST tmp;
146 size_t idx;
147
David Benjaminc0b87a02022-06-16 14:02:15 -0400148 if ((id >= X509_TRUST_MIN) && (id <= X509_TRUST_MAX)) {
David Benjamin260a10c2022-06-16 13:58:28 -0400149 return id - X509_TRUST_MIN;
David Benjaminc0b87a02022-06-16 14:02:15 -0400150 }
David Benjamin260a10c2022-06-16 13:58:28 -0400151 tmp.trust = id;
David Benjaminc0b87a02022-06-16 14:02:15 -0400152 if (!trtable) {
David Benjamin260a10c2022-06-16 13:58:28 -0400153 return -1;
David Benjaminc0b87a02022-06-16 14:02:15 -0400154 }
David Benjamin260a10c2022-06-16 13:58:28 -0400155 if (!sk_X509_TRUST_find(trtable, &idx, &tmp)) {
156 return -1;
157 }
158 return idx + X509_TRUST_COUNT;
159}
160
161int X509_TRUST_set(int *t, int trust) {
162 if (X509_TRUST_get_by_id(trust) == -1) {
163 OPENSSL_PUT_ERROR(X509, X509_R_INVALID_TRUST);
164 return 0;
165 }
166 *t = trust;
167 return 1;
168}
169
170int X509_TRUST_add(int id, int flags, int (*ck)(X509_TRUST *, X509 *, int),
David Benjamincbb96b42023-06-04 12:50:39 -0400171 const char *name, int arg1, void *arg2) {
David Benjamin260a10c2022-06-16 13:58:28 -0400172 int idx;
173 X509_TRUST *trtmp;
174 char *name_dup;
175
David Benjamin46350482022-06-16 14:03:12 -0400176 // This is set according to what we change: application can't set it
David Benjamin260a10c2022-06-16 13:58:28 -0400177 flags &= ~X509_TRUST_DYNAMIC;
David Benjamin46350482022-06-16 14:03:12 -0400178 // This will always be set for application modified trust entries
David Benjamin260a10c2022-06-16 13:58:28 -0400179 flags |= X509_TRUST_DYNAMIC_NAME;
David Benjamin46350482022-06-16 14:03:12 -0400180 // Get existing entry if any
David Benjamin260a10c2022-06-16 13:58:28 -0400181 idx = X509_TRUST_get_by_id(id);
David Benjamin46350482022-06-16 14:03:12 -0400182 // Need a new entry
David Benjamin260a10c2022-06-16 13:58:28 -0400183 if (idx == -1) {
184 if (!(trtmp = OPENSSL_malloc(sizeof(X509_TRUST)))) {
David Benjamin260a10c2022-06-16 13:58:28 -0400185 return 0;
Adam Langley57707c72016-01-14 11:25:12 -0800186 }
David Benjamin260a10c2022-06-16 13:58:28 -0400187 trtmp->flags = X509_TRUST_DYNAMIC;
David Benjaminc0b87a02022-06-16 14:02:15 -0400188 } else {
David Benjamin260a10c2022-06-16 13:58:28 -0400189 trtmp = X509_TRUST_get0(idx);
David Benjaminc0b87a02022-06-16 14:02:15 -0400190 }
David Benjamin260a10c2022-06-16 13:58:28 -0400191
David Benjamin46350482022-06-16 14:03:12 -0400192 // Duplicate the supplied name.
David Benjamin260a10c2022-06-16 13:58:28 -0400193 name_dup = OPENSSL_strdup(name);
194 if (name_dup == NULL) {
David Benjaminc0b87a02022-06-16 14:02:15 -0400195 if (idx == -1) {
David Benjamin260a10c2022-06-16 13:58:28 -0400196 OPENSSL_free(trtmp);
David Benjaminc0b87a02022-06-16 14:02:15 -0400197 }
David Benjamin260a10c2022-06-16 13:58:28 -0400198 return 0;
199 }
Adam Langley95c29f32014-06-20 12:00:00 -0700200
David Benjamin46350482022-06-16 14:03:12 -0400201 // OPENSSL_free existing name if dynamic
David Benjaminc0b87a02022-06-16 14:02:15 -0400202 if (trtmp->flags & X509_TRUST_DYNAMIC_NAME) {
David Benjamin260a10c2022-06-16 13:58:28 -0400203 OPENSSL_free(trtmp->name);
David Benjaminc0b87a02022-06-16 14:02:15 -0400204 }
David Benjamin260a10c2022-06-16 13:58:28 -0400205 trtmp->name = name_dup;
David Benjamin46350482022-06-16 14:03:12 -0400206 // Keep the dynamic flag of existing entry
David Benjamin260a10c2022-06-16 13:58:28 -0400207 trtmp->flags &= X509_TRUST_DYNAMIC;
David Benjamin46350482022-06-16 14:03:12 -0400208 // Set all other flags
David Benjamin260a10c2022-06-16 13:58:28 -0400209 trtmp->flags |= flags;
Adam Langley95c29f32014-06-20 12:00:00 -0700210
David Benjamin260a10c2022-06-16 13:58:28 -0400211 trtmp->trust = id;
212 trtmp->check_trust = ck;
213 trtmp->arg1 = arg1;
214 trtmp->arg2 = arg2;
Adam Langley95c29f32014-06-20 12:00:00 -0700215
David Benjamin46350482022-06-16 14:03:12 -0400216 // If its a new entry manage the dynamic table
David Benjamin260a10c2022-06-16 13:58:28 -0400217 if (idx == -1) {
David Benjamin97d48db2023-03-29 03:09:15 +0900218 // TODO(davidben): This should be locked. Alternatively, remove the dynamic
219 // registration mechanism entirely. The trouble is there no way to pass in
220 // the various parameters into an |X509_VERIFY_PARAM| directly. You can only
221 // register it in the global table and get an ID.
David Benjamin260a10c2022-06-16 13:58:28 -0400222 if (!trtable && !(trtable = sk_X509_TRUST_new(tr_cmp))) {
David Benjamin260a10c2022-06-16 13:58:28 -0400223 trtable_free(trtmp);
224 return 0;
Adam Langley57707c72016-01-14 11:25:12 -0800225 }
David Benjamin260a10c2022-06-16 13:58:28 -0400226 if (!sk_X509_TRUST_push(trtable, trtmp)) {
David Benjamin260a10c2022-06-16 13:58:28 -0400227 trtable_free(trtmp);
228 return 0;
Adam Langley57707c72016-01-14 11:25:12 -0800229 }
David Benjamin97d48db2023-03-29 03:09:15 +0900230 sk_X509_TRUST_sort(trtable);
David Benjamin260a10c2022-06-16 13:58:28 -0400231 }
232 return 1;
Adam Langley95c29f32014-06-20 12:00:00 -0700233}
234
David Benjamin260a10c2022-06-16 13:58:28 -0400235static void trtable_free(X509_TRUST *p) {
David Benjaminc0b87a02022-06-16 14:02:15 -0400236 if (!p) {
David Benjamin260a10c2022-06-16 13:58:28 -0400237 return;
David Benjaminc0b87a02022-06-16 14:02:15 -0400238 }
David Benjamin260a10c2022-06-16 13:58:28 -0400239 if (p->flags & X509_TRUST_DYNAMIC) {
David Benjaminc0b87a02022-06-16 14:02:15 -0400240 if (p->flags & X509_TRUST_DYNAMIC_NAME) {
David Benjamin260a10c2022-06-16 13:58:28 -0400241 OPENSSL_free(p->name);
David Benjaminc0b87a02022-06-16 14:02:15 -0400242 }
David Benjamin260a10c2022-06-16 13:58:28 -0400243 OPENSSL_free(p);
244 }
Adam Langley95c29f32014-06-20 12:00:00 -0700245}
246
David Benjamin260a10c2022-06-16 13:58:28 -0400247void X509_TRUST_cleanup(void) {
248 unsigned int i;
David Benjaminc0b87a02022-06-16 14:02:15 -0400249 for (i = 0; i < X509_TRUST_COUNT; i++) {
David Benjamin260a10c2022-06-16 13:58:28 -0400250 trtable_free(trstandard + i);
David Benjaminc0b87a02022-06-16 14:02:15 -0400251 }
David Benjamin260a10c2022-06-16 13:58:28 -0400252 sk_X509_TRUST_pop_free(trtable, trtable_free);
253 trtable = NULL;
Adam Langley57707c72016-01-14 11:25:12 -0800254}
Adam Langley95c29f32014-06-20 12:00:00 -0700255
David Benjamin260a10c2022-06-16 13:58:28 -0400256int X509_TRUST_get_flags(const X509_TRUST *xp) { return xp->flags; }
257
258char *X509_TRUST_get0_name(const X509_TRUST *xp) { return xp->name; }
259
260int X509_TRUST_get_trust(const X509_TRUST *xp) { return xp->trust; }
261
262static int trust_1oidany(X509_TRUST *trust, X509 *x, int flags) {
David Benjaminc0b87a02022-06-16 14:02:15 -0400263 if (x->aux && (x->aux->trust || x->aux->reject)) {
David Benjamin260a10c2022-06-16 13:58:28 -0400264 return obj_trust(trust->arg1, x, flags);
David Benjaminc0b87a02022-06-16 14:02:15 -0400265 }
David Benjamin46350482022-06-16 14:03:12 -0400266 // we don't have any trust settings: for compatibility we return trusted
267 // if it is self signed
David Benjamin260a10c2022-06-16 13:58:28 -0400268 return trust_compat(trust, x, flags);
Adam Langley95c29f32014-06-20 12:00:00 -0700269}
270
David Benjamin260a10c2022-06-16 13:58:28 -0400271static int trust_1oid(X509_TRUST *trust, X509 *x, int flags) {
David Benjaminc0b87a02022-06-16 14:02:15 -0400272 if (x->aux) {
David Benjamin260a10c2022-06-16 13:58:28 -0400273 return obj_trust(trust->arg1, x, flags);
David Benjaminc0b87a02022-06-16 14:02:15 -0400274 }
David Benjamin260a10c2022-06-16 13:58:28 -0400275 return X509_TRUST_UNTRUSTED;
Adam Langley95c29f32014-06-20 12:00:00 -0700276}
277
David Benjamin260a10c2022-06-16 13:58:28 -0400278static int trust_compat(X509_TRUST *trust, X509 *x, int flags) {
David Benjaminc0b87a02022-06-16 14:02:15 -0400279 if (!x509v3_cache_extensions(x)) {
David Benjamin260a10c2022-06-16 13:58:28 -0400280 return X509_TRUST_UNTRUSTED;
David Benjaminc0b87a02022-06-16 14:02:15 -0400281 }
282 if (x->ex_flags & EXFLAG_SS) {
David Benjamin260a10c2022-06-16 13:58:28 -0400283 return X509_TRUST_TRUSTED;
David Benjaminc0b87a02022-06-16 14:02:15 -0400284 } else {
Adam Langley57707c72016-01-14 11:25:12 -0800285 return X509_TRUST_UNTRUSTED;
David Benjaminc0b87a02022-06-16 14:02:15 -0400286 }
Adam Langley95c29f32014-06-20 12:00:00 -0700287}
288
David Benjamin260a10c2022-06-16 13:58:28 -0400289static int obj_trust(int id, X509 *x, int flags) {
290 ASN1_OBJECT *obj;
291 size_t i;
292 X509_CERT_AUX *ax;
293 ax = x->aux;
David Benjaminc0b87a02022-06-16 14:02:15 -0400294 if (!ax) {
David Benjamin260a10c2022-06-16 13:58:28 -0400295 return X509_TRUST_UNTRUSTED;
David Benjaminc0b87a02022-06-16 14:02:15 -0400296 }
David Benjamin260a10c2022-06-16 13:58:28 -0400297 if (ax->reject) {
298 for (i = 0; i < sk_ASN1_OBJECT_num(ax->reject); i++) {
299 obj = sk_ASN1_OBJECT_value(ax->reject, i);
David Benjaminc0b87a02022-06-16 14:02:15 -0400300 if (OBJ_obj2nid(obj) == id) {
David Benjamin260a10c2022-06-16 13:58:28 -0400301 return X509_TRUST_REJECTED;
David Benjaminc0b87a02022-06-16 14:02:15 -0400302 }
David Benjamin260a10c2022-06-16 13:58:28 -0400303 }
304 }
305 if (ax->trust) {
306 for (i = 0; i < sk_ASN1_OBJECT_num(ax->trust); i++) {
307 obj = sk_ASN1_OBJECT_value(ax->trust, i);
David Benjaminc0b87a02022-06-16 14:02:15 -0400308 if (OBJ_obj2nid(obj) == id) {
Adam Langley57707c72016-01-14 11:25:12 -0800309 return X509_TRUST_TRUSTED;
David Benjaminc0b87a02022-06-16 14:02:15 -0400310 }
Adam Langley57707c72016-01-14 11:25:12 -0800311 }
David Benjamin260a10c2022-06-16 13:58:28 -0400312 }
313 return X509_TRUST_UNTRUSTED;
Adam Langley95c29f32014-06-20 12:00:00 -0700314}