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