| 1 | /* | 
| 2 |  * Written by Dr Stephen N Henson (steve@openssl.org) for the OpenSSL project | 
| 3 |  * 1999. | 
| 4 |  */ | 
| 5 | /* ==================================================================== | 
| 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 | 
| 13 |  *    notice, this list of conditions and the following disclaimer. | 
| 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 |  | 
| 57 | #include <openssl/buf.h> | 
| 58 | #include <openssl/err.h> | 
| 59 | #include <openssl/mem.h> | 
| 60 | #include <openssl/obj.h> | 
| 61 | #include <openssl/x509v3.h> | 
| 62 |  | 
| 63 | static int tr_cmp(const X509_TRUST **a, const X509_TRUST **b); | 
| 64 | static void trtable_free(X509_TRUST *p); | 
| 65 |  | 
| 66 | static int trust_1oidany(X509_TRUST *trust, X509 *x, int flags); | 
| 67 | static int trust_1oid(X509_TRUST *trust, X509 *x, int flags); | 
| 68 | static int trust_compat(X509_TRUST *trust, X509 *x, int flags); | 
| 69 |  | 
| 70 | static int obj_trust(int id, X509 *x, int flags); | 
| 71 | static int (*default_trust) (int id, X509 *x, int flags) = obj_trust; | 
| 72 |  | 
| 73 | /* | 
| 74 |  * WARNING: the following table should be kept in order of trust and without | 
| 75 |  * any gaps so we can just subtract the minimum trust value to get an index | 
| 76 |  * into the table | 
| 77 |  */ | 
| 78 |  | 
| 79 | static X509_TRUST trstandard[] = { | 
| 80 |     {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, | 
| 94 |      NULL} | 
| 95 | }; | 
| 96 |  | 
| 97 | #define X509_TRUST_COUNT        (sizeof(trstandard)/sizeof(X509_TRUST)) | 
| 98 |  | 
| 99 | static STACK_OF(X509_TRUST) *trtable = NULL; | 
| 100 |  | 
| 101 | static int tr_cmp(const X509_TRUST **a, const X509_TRUST **b) | 
| 102 | { | 
| 103 |     return (*a)->trust - (*b)->trust; | 
| 104 | } | 
| 105 |  | 
| 106 | int (*X509_TRUST_set_default(int (*trust) (int, X509 *, int))) (int, X509 *, | 
| 107 |                                                                 int) { | 
| 108 |     int (*oldtrust) (int, X509 *, int); | 
| 109 |     oldtrust = default_trust; | 
| 110 |     default_trust = trust; | 
| 111 |     return oldtrust; | 
| 112 | } | 
| 113 |  | 
| 114 | int X509_check_trust(X509 *x, int id, int flags) | 
| 115 | { | 
| 116 |     X509_TRUST *pt; | 
| 117 |     int idx; | 
| 118 |     if (id == -1) | 
| 119 |         return 1; | 
| 120 |     /* We get this as a default value */ | 
| 121 |     if (id == 0) { | 
| 122 |         int rv; | 
| 123 |         rv = obj_trust(NID_anyExtendedKeyUsage, x, 0); | 
| 124 |         if (rv != X509_TRUST_UNTRUSTED) | 
| 125 |             return rv; | 
| 126 |         return trust_compat(NULL, x, 0); | 
| 127 |     } | 
| 128 |     idx = X509_TRUST_get_by_id(id); | 
| 129 |     if (idx == -1) | 
| 130 |         return default_trust(id, x, flags); | 
| 131 |     pt = X509_TRUST_get0(idx); | 
| 132 |     return pt->check_trust(pt, x, flags); | 
| 133 | } | 
| 134 |  | 
| 135 | int X509_TRUST_get_count(void) | 
| 136 | { | 
| 137 |     if (!trtable) | 
| 138 |         return X509_TRUST_COUNT; | 
| 139 |     return sk_X509_TRUST_num(trtable) + X509_TRUST_COUNT; | 
| 140 | } | 
| 141 |  | 
| 142 | X509_TRUST *X509_TRUST_get0(int idx) | 
| 143 | { | 
| 144 |     if (idx < 0) | 
| 145 |         return NULL; | 
| 146 |     if (idx < (int)X509_TRUST_COUNT) | 
| 147 |         return trstandard + idx; | 
| 148 |     return sk_X509_TRUST_value(trtable, idx - X509_TRUST_COUNT); | 
| 149 | } | 
| 150 |  | 
| 151 | int X509_TRUST_get_by_id(int id) | 
| 152 | { | 
| 153 |     X509_TRUST tmp; | 
| 154 |     size_t idx; | 
| 155 |  | 
| 156 |     if ((id >= X509_TRUST_MIN) && (id <= X509_TRUST_MAX)) | 
| 157 |         return id - X509_TRUST_MIN; | 
| 158 |     tmp.trust = id; | 
| 159 |     if (!trtable) | 
| 160 |         return -1; | 
| 161 |     sk_X509_TRUST_sort(trtable); | 
| 162 |     if (!sk_X509_TRUST_find(trtable, &idx, &tmp)) { | 
| 163 |         return -1; | 
| 164 |     } | 
| 165 |     return idx + X509_TRUST_COUNT; | 
| 166 | } | 
| 167 |  | 
| 168 | int X509_TRUST_set(int *t, int trust) | 
| 169 | { | 
| 170 |     if (X509_TRUST_get_by_id(trust) == -1) { | 
| 171 |         OPENSSL_PUT_ERROR(X509, X509_R_INVALID_TRUST); | 
| 172 |         return 0; | 
| 173 |     } | 
| 174 |     *t = trust; | 
| 175 |     return 1; | 
| 176 | } | 
| 177 |  | 
| 178 | int X509_TRUST_add(int id, int flags, int (*ck) (X509_TRUST *, X509 *, int), | 
| 179 |                    char *name, int arg1, void *arg2) | 
| 180 | { | 
| 181 |     int idx; | 
| 182 |     X509_TRUST *trtmp; | 
| 183 |     char *name_dup; | 
| 184 |  | 
| 185 |     /* | 
| 186 |      * This is set according to what we change: application can't set it | 
| 187 |      */ | 
| 188 |     flags &= ~X509_TRUST_DYNAMIC; | 
| 189 |     /* This will always be set for application modified trust entries */ | 
| 190 |     flags |= X509_TRUST_DYNAMIC_NAME; | 
| 191 |     /* Get existing entry if any */ | 
| 192 |     idx = X509_TRUST_get_by_id(id); | 
| 193 |     /* Need a new entry */ | 
| 194 |     if (idx == -1) { | 
| 195 |         if (!(trtmp = OPENSSL_malloc(sizeof(X509_TRUST)))) { | 
| 196 |             OPENSSL_PUT_ERROR(X509, ERR_R_MALLOC_FAILURE); | 
| 197 |             return 0; | 
| 198 |         } | 
| 199 |         trtmp->flags = X509_TRUST_DYNAMIC; | 
| 200 |     } else | 
| 201 |         trtmp = X509_TRUST_get0(idx); | 
| 202 |  | 
| 203 |     /* Duplicate the supplied name. */ | 
| 204 |     name_dup = BUF_strdup(name); | 
| 205 |     if (name_dup == NULL) { | 
| 206 |         OPENSSL_PUT_ERROR(X509, ERR_R_MALLOC_FAILURE); | 
| 207 |         if (idx == -1) | 
| 208 |             OPENSSL_free(trtmp); | 
| 209 |         return 0; | 
| 210 |     } | 
| 211 |  | 
| 212 |     /* OPENSSL_free existing name if dynamic */ | 
| 213 |     if (trtmp->flags & X509_TRUST_DYNAMIC_NAME) | 
| 214 |         OPENSSL_free(trtmp->name); | 
| 215 |     trtmp->name = name_dup; | 
| 216 |     /* Keep the dynamic flag of existing entry */ | 
| 217 |     trtmp->flags &= X509_TRUST_DYNAMIC; | 
| 218 |     /* Set all other flags */ | 
| 219 |     trtmp->flags |= flags; | 
| 220 |  | 
| 221 |     trtmp->trust = id; | 
| 222 |     trtmp->check_trust = ck; | 
| 223 |     trtmp->arg1 = arg1; | 
| 224 |     trtmp->arg2 = arg2; | 
| 225 |  | 
| 226 |     /* If its a new entry manage the dynamic table */ | 
| 227 |     if (idx == -1) { | 
| 228 |         if (!trtable && !(trtable = sk_X509_TRUST_new(tr_cmp))) { | 
| 229 |             OPENSSL_PUT_ERROR(X509, ERR_R_MALLOC_FAILURE); | 
| 230 |             trtable_free(trtmp); | 
| 231 |             return 0; | 
| 232 |         } | 
| 233 |         if (!sk_X509_TRUST_push(trtable, trtmp)) { | 
| 234 |             OPENSSL_PUT_ERROR(X509, ERR_R_MALLOC_FAILURE); | 
| 235 |             trtable_free(trtmp); | 
| 236 |             return 0; | 
| 237 |         } | 
| 238 |     } | 
| 239 |     return 1; | 
| 240 | } | 
| 241 |  | 
| 242 | static void trtable_free(X509_TRUST *p) | 
| 243 | { | 
| 244 |     if (!p) | 
| 245 |         return; | 
| 246 |     if (p->flags & X509_TRUST_DYNAMIC) { | 
| 247 |         if (p->flags & X509_TRUST_DYNAMIC_NAME) | 
| 248 |             OPENSSL_free(p->name); | 
| 249 |         OPENSSL_free(p); | 
| 250 |     } | 
| 251 | } | 
| 252 |  | 
| 253 | void X509_TRUST_cleanup(void) | 
| 254 | { | 
| 255 |     unsigned int i; | 
| 256 |     for (i = 0; i < X509_TRUST_COUNT; i++) | 
| 257 |         trtable_free(trstandard + i); | 
| 258 |     sk_X509_TRUST_pop_free(trtable, trtable_free); | 
| 259 |     trtable = NULL; | 
| 260 | } | 
| 261 |  | 
| 262 | int X509_TRUST_get_flags(X509_TRUST *xp) | 
| 263 | { | 
| 264 |     return xp->flags; | 
| 265 | } | 
| 266 |  | 
| 267 | char *X509_TRUST_get0_name(X509_TRUST *xp) | 
| 268 | { | 
| 269 |     return xp->name; | 
| 270 | } | 
| 271 |  | 
| 272 | int X509_TRUST_get_trust(X509_TRUST *xp) | 
| 273 | { | 
| 274 |     return xp->trust; | 
| 275 | } | 
| 276 |  | 
| 277 | static int trust_1oidany(X509_TRUST *trust, X509 *x, int flags) | 
| 278 | { | 
| 279 |     if (x->aux && (x->aux->trust || x->aux->reject)) | 
| 280 |         return obj_trust(trust->arg1, x, flags); | 
| 281 |     /* | 
| 282 |      * we don't have any trust settings: for compatibility we return trusted | 
| 283 |      * if it is self signed | 
| 284 |      */ | 
| 285 |     return trust_compat(trust, x, flags); | 
| 286 | } | 
| 287 |  | 
| 288 | static int trust_1oid(X509_TRUST *trust, X509 *x, int flags) | 
| 289 | { | 
| 290 |     if (x->aux) | 
| 291 |         return obj_trust(trust->arg1, x, flags); | 
| 292 |     return X509_TRUST_UNTRUSTED; | 
| 293 | } | 
| 294 |  | 
| 295 | static int trust_compat(X509_TRUST *trust, X509 *x, int flags) | 
| 296 | { | 
| 297 |     X509_check_purpose(x, -1, 0); | 
| 298 |     if (x->ex_flags & EXFLAG_SS) | 
| 299 |         return X509_TRUST_TRUSTED; | 
| 300 |     else | 
| 301 |         return X509_TRUST_UNTRUSTED; | 
| 302 | } | 
| 303 |  | 
| 304 | static int obj_trust(int id, X509 *x, int flags) | 
| 305 | { | 
| 306 |     ASN1_OBJECT *obj; | 
| 307 |     size_t i; | 
| 308 |     X509_CERT_AUX *ax; | 
| 309 |     ax = x->aux; | 
| 310 |     if (!ax) | 
| 311 |         return X509_TRUST_UNTRUSTED; | 
| 312 |     if (ax->reject) { | 
| 313 |         for (i = 0; i < sk_ASN1_OBJECT_num(ax->reject); i++) { | 
| 314 |             obj = sk_ASN1_OBJECT_value(ax->reject, i); | 
| 315 |             if (OBJ_obj2nid(obj) == id) | 
| 316 |                 return X509_TRUST_REJECTED; | 
| 317 |         } | 
| 318 |     } | 
| 319 |     if (ax->trust) { | 
| 320 |         for (i = 0; i < sk_ASN1_OBJECT_num(ax->trust); i++) { | 
| 321 |             obj = sk_ASN1_OBJECT_value(ax->trust, i); | 
| 322 |             if (OBJ_obj2nid(obj) == id) | 
| 323 |                 return X509_TRUST_TRUSTED; | 
| 324 |         } | 
| 325 |     } | 
| 326 |     return X509_TRUST_UNTRUSTED; | 
| 327 | } | 
| 328 |  |