1*b077aed3SPierre Pronchery /*
2*b077aed3SPierre Pronchery * Copyright 1999-2022 The OpenSSL Project Authors. All Rights Reserved.
3*b077aed3SPierre Pronchery *
4*b077aed3SPierre Pronchery * Licensed under the Apache License 2.0 (the "License"). You may not use
5*b077aed3SPierre Pronchery * this file except in compliance with the License. You can obtain a copy
6*b077aed3SPierre Pronchery * in the file LICENSE in the source distribution or at
7*b077aed3SPierre Pronchery * https://www.openssl.org/source/license.html
8*b077aed3SPierre Pronchery */
9*b077aed3SPierre Pronchery
10*b077aed3SPierre Pronchery #include <stdio.h>
11*b077aed3SPierre Pronchery #include "internal/cryptlib.h"
12*b077aed3SPierre Pronchery #include <openssl/x509v3.h>
13*b077aed3SPierre Pronchery #include "crypto/x509.h"
14*b077aed3SPierre Pronchery
15*b077aed3SPierre Pronchery static int tr_cmp(const X509_TRUST *const *a, const X509_TRUST *const *b);
16*b077aed3SPierre Pronchery static void trtable_free(X509_TRUST *p);
17*b077aed3SPierre Pronchery
18*b077aed3SPierre Pronchery static int trust_1oidany(X509_TRUST *trust, X509 *x, int flags);
19*b077aed3SPierre Pronchery static int trust_1oid(X509_TRUST *trust, X509 *x, int flags);
20*b077aed3SPierre Pronchery static int trust_compat(X509_TRUST *trust, X509 *x, int flags);
21*b077aed3SPierre Pronchery
22*b077aed3SPierre Pronchery static int obj_trust(int id, X509 *x, int flags);
23*b077aed3SPierre Pronchery static int (*default_trust) (int id, X509 *x, int flags) = obj_trust;
24*b077aed3SPierre Pronchery
25*b077aed3SPierre Pronchery /*
26*b077aed3SPierre Pronchery * WARNING: the following table should be kept in order of trust and without
27*b077aed3SPierre Pronchery * any gaps so we can just subtract the minimum trust value to get an index
28*b077aed3SPierre Pronchery * into the table
29*b077aed3SPierre Pronchery */
30*b077aed3SPierre Pronchery
31*b077aed3SPierre Pronchery static X509_TRUST trstandard[] = {
32*b077aed3SPierre Pronchery {X509_TRUST_COMPAT, 0, trust_compat, "compatible", 0, NULL},
33*b077aed3SPierre Pronchery {X509_TRUST_SSL_CLIENT, 0, trust_1oidany, "SSL Client", NID_client_auth,
34*b077aed3SPierre Pronchery NULL},
35*b077aed3SPierre Pronchery {X509_TRUST_SSL_SERVER, 0, trust_1oidany, "SSL Server", NID_server_auth,
36*b077aed3SPierre Pronchery NULL},
37*b077aed3SPierre Pronchery {X509_TRUST_EMAIL, 0, trust_1oidany, "S/MIME email", NID_email_protect,
38*b077aed3SPierre Pronchery NULL},
39*b077aed3SPierre Pronchery {X509_TRUST_OBJECT_SIGN, 0, trust_1oidany, "Object Signer", NID_code_sign,
40*b077aed3SPierre Pronchery NULL},
41*b077aed3SPierre Pronchery {X509_TRUST_OCSP_SIGN, 0, trust_1oid, "OCSP responder", NID_OCSP_sign,
42*b077aed3SPierre Pronchery NULL},
43*b077aed3SPierre Pronchery {X509_TRUST_OCSP_REQUEST, 0, trust_1oid, "OCSP request", NID_ad_OCSP,
44*b077aed3SPierre Pronchery NULL},
45*b077aed3SPierre Pronchery {X509_TRUST_TSA, 0, trust_1oidany, "TSA server", NID_time_stamp, NULL}
46*b077aed3SPierre Pronchery };
47*b077aed3SPierre Pronchery
48*b077aed3SPierre Pronchery #define X509_TRUST_COUNT OSSL_NELEM(trstandard)
49*b077aed3SPierre Pronchery
50*b077aed3SPierre Pronchery static STACK_OF(X509_TRUST) *trtable = NULL;
51*b077aed3SPierre Pronchery
tr_cmp(const X509_TRUST * const * a,const X509_TRUST * const * b)52*b077aed3SPierre Pronchery static int tr_cmp(const X509_TRUST *const *a, const X509_TRUST *const *b)
53*b077aed3SPierre Pronchery {
54*b077aed3SPierre Pronchery return (*a)->trust - (*b)->trust;
55*b077aed3SPierre Pronchery }
56*b077aed3SPierre Pronchery
X509_TRUST_set_default(int (* trust)(int,X509 *,int))57*b077aed3SPierre Pronchery int (*X509_TRUST_set_default(int (*trust) (int, X509 *, int))) (int, X509 *,
58*b077aed3SPierre Pronchery int) {
59*b077aed3SPierre Pronchery int (*oldtrust) (int, X509 *, int);
60*b077aed3SPierre Pronchery oldtrust = default_trust;
61*b077aed3SPierre Pronchery default_trust = trust;
62*b077aed3SPierre Pronchery return oldtrust;
63*b077aed3SPierre Pronchery }
64*b077aed3SPierre Pronchery
X509_check_trust(X509 * x,int id,int flags)65*b077aed3SPierre Pronchery int X509_check_trust(X509 *x, int id, int flags)
66*b077aed3SPierre Pronchery {
67*b077aed3SPierre Pronchery X509_TRUST *pt;
68*b077aed3SPierre Pronchery int idx;
69*b077aed3SPierre Pronchery
70*b077aed3SPierre Pronchery /* We get this as a default value */
71*b077aed3SPierre Pronchery if (id == X509_TRUST_DEFAULT)
72*b077aed3SPierre Pronchery return obj_trust(NID_anyExtendedKeyUsage, x,
73*b077aed3SPierre Pronchery flags | X509_TRUST_DO_SS_COMPAT);
74*b077aed3SPierre Pronchery idx = X509_TRUST_get_by_id(id);
75*b077aed3SPierre Pronchery if (idx < 0)
76*b077aed3SPierre Pronchery return default_trust(id, x, flags);
77*b077aed3SPierre Pronchery pt = X509_TRUST_get0(idx);
78*b077aed3SPierre Pronchery return pt->check_trust(pt, x, flags);
79*b077aed3SPierre Pronchery }
80*b077aed3SPierre Pronchery
X509_TRUST_get_count(void)81*b077aed3SPierre Pronchery int X509_TRUST_get_count(void)
82*b077aed3SPierre Pronchery {
83*b077aed3SPierre Pronchery if (!trtable)
84*b077aed3SPierre Pronchery return X509_TRUST_COUNT;
85*b077aed3SPierre Pronchery return sk_X509_TRUST_num(trtable) + X509_TRUST_COUNT;
86*b077aed3SPierre Pronchery }
87*b077aed3SPierre Pronchery
X509_TRUST_get0(int idx)88*b077aed3SPierre Pronchery X509_TRUST *X509_TRUST_get0(int idx)
89*b077aed3SPierre Pronchery {
90*b077aed3SPierre Pronchery if (idx < 0)
91*b077aed3SPierre Pronchery return NULL;
92*b077aed3SPierre Pronchery if (idx < (int)X509_TRUST_COUNT)
93*b077aed3SPierre Pronchery return trstandard + idx;
94*b077aed3SPierre Pronchery return sk_X509_TRUST_value(trtable, idx - X509_TRUST_COUNT);
95*b077aed3SPierre Pronchery }
96*b077aed3SPierre Pronchery
X509_TRUST_get_by_id(int id)97*b077aed3SPierre Pronchery int X509_TRUST_get_by_id(int id)
98*b077aed3SPierre Pronchery {
99*b077aed3SPierre Pronchery X509_TRUST tmp;
100*b077aed3SPierre Pronchery int idx;
101*b077aed3SPierre Pronchery
102*b077aed3SPierre Pronchery if ((id >= X509_TRUST_MIN) && (id <= X509_TRUST_MAX))
103*b077aed3SPierre Pronchery return id - X509_TRUST_MIN;
104*b077aed3SPierre Pronchery if (trtable == NULL)
105*b077aed3SPierre Pronchery return -1;
106*b077aed3SPierre Pronchery tmp.trust = id;
107*b077aed3SPierre Pronchery idx = sk_X509_TRUST_find(trtable, &tmp);
108*b077aed3SPierre Pronchery if (idx < 0)
109*b077aed3SPierre Pronchery return -1;
110*b077aed3SPierre Pronchery return idx + X509_TRUST_COUNT;
111*b077aed3SPierre Pronchery }
112*b077aed3SPierre Pronchery
X509_TRUST_set(int * t,int trust)113*b077aed3SPierre Pronchery int X509_TRUST_set(int *t, int trust)
114*b077aed3SPierre Pronchery {
115*b077aed3SPierre Pronchery if (X509_TRUST_get_by_id(trust) < 0) {
116*b077aed3SPierre Pronchery ERR_raise(ERR_LIB_X509, X509_R_INVALID_TRUST);
117*b077aed3SPierre Pronchery return 0;
118*b077aed3SPierre Pronchery }
119*b077aed3SPierre Pronchery *t = trust;
120*b077aed3SPierre Pronchery return 1;
121*b077aed3SPierre Pronchery }
122*b077aed3SPierre Pronchery
X509_TRUST_add(int id,int flags,int (* ck)(X509_TRUST *,X509 *,int),const char * name,int arg1,void * arg2)123*b077aed3SPierre Pronchery int X509_TRUST_add(int id, int flags, int (*ck) (X509_TRUST *, X509 *, int),
124*b077aed3SPierre Pronchery const char *name, int arg1, void *arg2)
125*b077aed3SPierre Pronchery {
126*b077aed3SPierre Pronchery int idx;
127*b077aed3SPierre Pronchery X509_TRUST *trtmp;
128*b077aed3SPierre Pronchery /*
129*b077aed3SPierre Pronchery * This is set according to what we change: application can't set it
130*b077aed3SPierre Pronchery */
131*b077aed3SPierre Pronchery flags &= ~X509_TRUST_DYNAMIC;
132*b077aed3SPierre Pronchery /* This will always be set for application modified trust entries */
133*b077aed3SPierre Pronchery flags |= X509_TRUST_DYNAMIC_NAME;
134*b077aed3SPierre Pronchery /* Get existing entry if any */
135*b077aed3SPierre Pronchery idx = X509_TRUST_get_by_id(id);
136*b077aed3SPierre Pronchery /* Need a new entry */
137*b077aed3SPierre Pronchery if (idx < 0) {
138*b077aed3SPierre Pronchery if ((trtmp = OPENSSL_malloc(sizeof(*trtmp))) == NULL) {
139*b077aed3SPierre Pronchery ERR_raise(ERR_LIB_X509, ERR_R_MALLOC_FAILURE);
140*b077aed3SPierre Pronchery return 0;
141*b077aed3SPierre Pronchery }
142*b077aed3SPierre Pronchery trtmp->flags = X509_TRUST_DYNAMIC;
143*b077aed3SPierre Pronchery } else
144*b077aed3SPierre Pronchery trtmp = X509_TRUST_get0(idx);
145*b077aed3SPierre Pronchery
146*b077aed3SPierre Pronchery /* OPENSSL_free existing name if dynamic */
147*b077aed3SPierre Pronchery if (trtmp->flags & X509_TRUST_DYNAMIC_NAME)
148*b077aed3SPierre Pronchery OPENSSL_free(trtmp->name);
149*b077aed3SPierre Pronchery /* dup supplied name */
150*b077aed3SPierre Pronchery if ((trtmp->name = OPENSSL_strdup(name)) == NULL) {
151*b077aed3SPierre Pronchery ERR_raise(ERR_LIB_X509, ERR_R_MALLOC_FAILURE);
152*b077aed3SPierre Pronchery goto err;
153*b077aed3SPierre Pronchery }
154*b077aed3SPierre Pronchery /* Keep the dynamic flag of existing entry */
155*b077aed3SPierre Pronchery trtmp->flags &= X509_TRUST_DYNAMIC;
156*b077aed3SPierre Pronchery /* Set all other flags */
157*b077aed3SPierre Pronchery trtmp->flags |= flags;
158*b077aed3SPierre Pronchery
159*b077aed3SPierre Pronchery trtmp->trust = id;
160*b077aed3SPierre Pronchery trtmp->check_trust = ck;
161*b077aed3SPierre Pronchery trtmp->arg1 = arg1;
162*b077aed3SPierre Pronchery trtmp->arg2 = arg2;
163*b077aed3SPierre Pronchery
164*b077aed3SPierre Pronchery /* If its a new entry manage the dynamic table */
165*b077aed3SPierre Pronchery if (idx < 0) {
166*b077aed3SPierre Pronchery if (trtable == NULL
167*b077aed3SPierre Pronchery && (trtable = sk_X509_TRUST_new(tr_cmp)) == NULL) {
168*b077aed3SPierre Pronchery ERR_raise(ERR_LIB_X509, ERR_R_MALLOC_FAILURE);
169*b077aed3SPierre Pronchery goto err;;
170*b077aed3SPierre Pronchery }
171*b077aed3SPierre Pronchery if (!sk_X509_TRUST_push(trtable, trtmp)) {
172*b077aed3SPierre Pronchery ERR_raise(ERR_LIB_X509, ERR_R_MALLOC_FAILURE);
173*b077aed3SPierre Pronchery goto err;
174*b077aed3SPierre Pronchery }
175*b077aed3SPierre Pronchery }
176*b077aed3SPierre Pronchery return 1;
177*b077aed3SPierre Pronchery err:
178*b077aed3SPierre Pronchery if (idx < 0) {
179*b077aed3SPierre Pronchery OPENSSL_free(trtmp->name);
180*b077aed3SPierre Pronchery OPENSSL_free(trtmp);
181*b077aed3SPierre Pronchery }
182*b077aed3SPierre Pronchery return 0;
183*b077aed3SPierre Pronchery }
184*b077aed3SPierre Pronchery
trtable_free(X509_TRUST * p)185*b077aed3SPierre Pronchery static void trtable_free(X509_TRUST *p)
186*b077aed3SPierre Pronchery {
187*b077aed3SPierre Pronchery if (p == NULL)
188*b077aed3SPierre Pronchery return;
189*b077aed3SPierre Pronchery if (p->flags & X509_TRUST_DYNAMIC) {
190*b077aed3SPierre Pronchery if (p->flags & X509_TRUST_DYNAMIC_NAME)
191*b077aed3SPierre Pronchery OPENSSL_free(p->name);
192*b077aed3SPierre Pronchery OPENSSL_free(p);
193*b077aed3SPierre Pronchery }
194*b077aed3SPierre Pronchery }
195*b077aed3SPierre Pronchery
X509_TRUST_cleanup(void)196*b077aed3SPierre Pronchery void X509_TRUST_cleanup(void)
197*b077aed3SPierre Pronchery {
198*b077aed3SPierre Pronchery sk_X509_TRUST_pop_free(trtable, trtable_free);
199*b077aed3SPierre Pronchery trtable = NULL;
200*b077aed3SPierre Pronchery }
201*b077aed3SPierre Pronchery
X509_TRUST_get_flags(const X509_TRUST * xp)202*b077aed3SPierre Pronchery int X509_TRUST_get_flags(const X509_TRUST *xp)
203*b077aed3SPierre Pronchery {
204*b077aed3SPierre Pronchery return xp->flags;
205*b077aed3SPierre Pronchery }
206*b077aed3SPierre Pronchery
X509_TRUST_get0_name(const X509_TRUST * xp)207*b077aed3SPierre Pronchery char *X509_TRUST_get0_name(const X509_TRUST *xp)
208*b077aed3SPierre Pronchery {
209*b077aed3SPierre Pronchery return xp->name;
210*b077aed3SPierre Pronchery }
211*b077aed3SPierre Pronchery
X509_TRUST_get_trust(const X509_TRUST * xp)212*b077aed3SPierre Pronchery int X509_TRUST_get_trust(const X509_TRUST *xp)
213*b077aed3SPierre Pronchery {
214*b077aed3SPierre Pronchery return xp->trust;
215*b077aed3SPierre Pronchery }
216*b077aed3SPierre Pronchery
trust_1oidany(X509_TRUST * trust,X509 * x,int flags)217*b077aed3SPierre Pronchery static int trust_1oidany(X509_TRUST *trust, X509 *x, int flags)
218*b077aed3SPierre Pronchery {
219*b077aed3SPierre Pronchery /*
220*b077aed3SPierre Pronchery * Declare the chain verified if the desired trust OID is not rejected in
221*b077aed3SPierre Pronchery * any auxiliary trust info for this certificate, and the OID is either
222*b077aed3SPierre Pronchery * expressly trusted, or else either "anyEKU" is trusted, or the
223*b077aed3SPierre Pronchery * certificate is self-signed and X509_TRUST_NO_SS_COMPAT is not set.
224*b077aed3SPierre Pronchery */
225*b077aed3SPierre Pronchery flags |= X509_TRUST_DO_SS_COMPAT | X509_TRUST_OK_ANY_EKU;
226*b077aed3SPierre Pronchery return obj_trust(trust->arg1, x, flags);
227*b077aed3SPierre Pronchery }
228*b077aed3SPierre Pronchery
trust_1oid(X509_TRUST * trust,X509 * x,int flags)229*b077aed3SPierre Pronchery static int trust_1oid(X509_TRUST *trust, X509 *x, int flags)
230*b077aed3SPierre Pronchery {
231*b077aed3SPierre Pronchery /*
232*b077aed3SPierre Pronchery * Declare the chain verified only if the desired trust OID is not
233*b077aed3SPierre Pronchery * rejected and is expressly trusted. Neither "anyEKU" nor "compat"
234*b077aed3SPierre Pronchery * trust in self-signed certificates apply.
235*b077aed3SPierre Pronchery */
236*b077aed3SPierre Pronchery flags &= ~(X509_TRUST_DO_SS_COMPAT | X509_TRUST_OK_ANY_EKU);
237*b077aed3SPierre Pronchery return obj_trust(trust->arg1, x, flags);
238*b077aed3SPierre Pronchery }
239*b077aed3SPierre Pronchery
trust_compat(X509_TRUST * trust,X509 * x,int flags)240*b077aed3SPierre Pronchery static int trust_compat(X509_TRUST *trust, X509 *x, int flags)
241*b077aed3SPierre Pronchery {
242*b077aed3SPierre Pronchery /* Call for side-effect of setting EXFLAG_SS for self-signed-certs */
243*b077aed3SPierre Pronchery if (X509_check_purpose(x, -1, 0) != 1)
244*b077aed3SPierre Pronchery return X509_TRUST_UNTRUSTED;
245*b077aed3SPierre Pronchery if ((flags & X509_TRUST_NO_SS_COMPAT) == 0 && (x->ex_flags & EXFLAG_SS))
246*b077aed3SPierre Pronchery return X509_TRUST_TRUSTED;
247*b077aed3SPierre Pronchery else
248*b077aed3SPierre Pronchery return X509_TRUST_UNTRUSTED;
249*b077aed3SPierre Pronchery }
250*b077aed3SPierre Pronchery
obj_trust(int id,X509 * x,int flags)251*b077aed3SPierre Pronchery static int obj_trust(int id, X509 *x, int flags)
252*b077aed3SPierre Pronchery {
253*b077aed3SPierre Pronchery X509_CERT_AUX *ax = x->aux;
254*b077aed3SPierre Pronchery int i;
255*b077aed3SPierre Pronchery
256*b077aed3SPierre Pronchery if (ax && ax->reject) {
257*b077aed3SPierre Pronchery for (i = 0; i < sk_ASN1_OBJECT_num(ax->reject); i++) {
258*b077aed3SPierre Pronchery ASN1_OBJECT *obj = sk_ASN1_OBJECT_value(ax->reject, i);
259*b077aed3SPierre Pronchery int nid = OBJ_obj2nid(obj);
260*b077aed3SPierre Pronchery
261*b077aed3SPierre Pronchery if (nid == id || (nid == NID_anyExtendedKeyUsage &&
262*b077aed3SPierre Pronchery (flags & X509_TRUST_OK_ANY_EKU)))
263*b077aed3SPierre Pronchery return X509_TRUST_REJECTED;
264*b077aed3SPierre Pronchery }
265*b077aed3SPierre Pronchery }
266*b077aed3SPierre Pronchery
267*b077aed3SPierre Pronchery if (ax && ax->trust) {
268*b077aed3SPierre Pronchery for (i = 0; i < sk_ASN1_OBJECT_num(ax->trust); i++) {
269*b077aed3SPierre Pronchery ASN1_OBJECT *obj = sk_ASN1_OBJECT_value(ax->trust, i);
270*b077aed3SPierre Pronchery int nid = OBJ_obj2nid(obj);
271*b077aed3SPierre Pronchery
272*b077aed3SPierre Pronchery if (nid == id || (nid == NID_anyExtendedKeyUsage &&
273*b077aed3SPierre Pronchery (flags & X509_TRUST_OK_ANY_EKU)))
274*b077aed3SPierre Pronchery return X509_TRUST_TRUSTED;
275*b077aed3SPierre Pronchery }
276*b077aed3SPierre Pronchery /*
277*b077aed3SPierre Pronchery * Reject when explicit trust EKU are set and none match.
278*b077aed3SPierre Pronchery *
279*b077aed3SPierre Pronchery * Returning untrusted is enough for for full chains that end in
280*b077aed3SPierre Pronchery * self-signed roots, because when explicit trust is specified it
281*b077aed3SPierre Pronchery * suppresses the default blanket trust of self-signed objects.
282*b077aed3SPierre Pronchery *
283*b077aed3SPierre Pronchery * But for partial chains, this is not enough, because absent a similar
284*b077aed3SPierre Pronchery * trust-self-signed policy, non matching EKUs are indistinguishable
285*b077aed3SPierre Pronchery * from lack of EKU constraints.
286*b077aed3SPierre Pronchery *
287*b077aed3SPierre Pronchery * Therefore, failure to match any trusted purpose must trigger an
288*b077aed3SPierre Pronchery * explicit reject.
289*b077aed3SPierre Pronchery */
290*b077aed3SPierre Pronchery return X509_TRUST_REJECTED;
291*b077aed3SPierre Pronchery }
292*b077aed3SPierre Pronchery
293*b077aed3SPierre Pronchery if ((flags & X509_TRUST_DO_SS_COMPAT) == 0)
294*b077aed3SPierre Pronchery return X509_TRUST_UNTRUSTED;
295*b077aed3SPierre Pronchery
296*b077aed3SPierre Pronchery /*
297*b077aed3SPierre Pronchery * Not rejected, and there is no list of accepted uses, try compat.
298*b077aed3SPierre Pronchery */
299*b077aed3SPierre Pronchery return trust_compat(NULL, x, flags);
300*b077aed3SPierre Pronchery }
301