x509_trs.c 8.8 KB
Newer Older
1
/*
2
 * Copyright 1999-2020 The OpenSSL Project Authors. All Rights Reserved.
D
Dr. Stephen Henson 已提交
3
 *
R
Rich Salz 已提交
4 5 6 7
 * Licensed under the OpenSSL license (the "License").  You may not use
 * this file except in compliance with the License.  You can obtain a copy
 * in the file LICENSE in the source distribution or at
 * https://www.openssl.org/source/license.html
D
Dr. Stephen Henson 已提交
8 9 10
 */

#include <stdio.h>
11
#include "internal/cryptlib.h"
D
Dr. Stephen Henson 已提交
12
#include <openssl/x509v3.h>
13
#include "crypto/x509.h"
D
Dr. Stephen Henson 已提交
14

15
static int tr_cmp(const X509_TRUST *const *a, const X509_TRUST *const *b);
D
Dr. Stephen Henson 已提交
16 17
static void trtable_free(X509_TRUST *p);

18
static int trust_1oidany(X509_TRUST *trust, X509 *x, int flags);
D
 
Dr. Stephen Henson 已提交
19
static int trust_1oid(X509_TRUST *trust, X509 *x, int flags);
20
static int trust_compat(X509_TRUST *trust, X509 *x, int flags);
D
Dr. Stephen Henson 已提交
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 27 28
/*
 * WARNING: the following table should be kept in order of trust and without
 * any gaps so we can just subtract the minimum trust value to get an index
 * into the table
29 30
 */

D
Dr. Stephen Henson 已提交
31
static X509_TRUST trstandard[] = {
32 33 34 35 36 37 38 39 40 41 42 43 44 45
    {X509_TRUST_COMPAT, 0, trust_compat, "compatible", 0, NULL},
    {X509_TRUST_SSL_CLIENT, 0, trust_1oidany, "SSL Client", NID_client_auth,
     NULL},
    {X509_TRUST_SSL_SERVER, 0, trust_1oidany, "SSL Server", NID_server_auth,
     NULL},
    {X509_TRUST_EMAIL, 0, trust_1oidany, "S/MIME email", NID_email_protect,
     NULL},
    {X509_TRUST_OBJECT_SIGN, 0, trust_1oidany, "Object Signer", NID_code_sign,
     NULL},
    {X509_TRUST_OCSP_SIGN, 0, trust_1oid, "OCSP responder", NID_OCSP_sign,
     NULL},
    {X509_TRUST_OCSP_REQUEST, 0, trust_1oid, "OCSP request", NID_ad_OCSP,
     NULL},
    {X509_TRUST_TSA, 0, trust_1oidany, "TSA server", NID_time_stamp, NULL}
D
Dr. Stephen Henson 已提交
46 47
};

D
Dr. Stephen Henson 已提交
48
#define X509_TRUST_COUNT        OSSL_NELEM(trstandard)
49

D
Dr. Stephen Henson 已提交
50 51
static STACK_OF(X509_TRUST) *trtable = NULL;

52
static int tr_cmp(const X509_TRUST *const *a, const X509_TRUST *const *b)
D
Dr. Stephen Henson 已提交
53
{
54
    return (*a)->trust - (*b)->trust;
D
Dr. Stephen Henson 已提交
55 56
}

57 58 59 60 61 62
int (*X509_TRUST_set_default(int (*trust) (int, X509 *, int))) (int, X509 *,
                                                                int) {
    int (*oldtrust) (int, X509 *, int);
    oldtrust = default_trust;
    default_trust = trust;
    return oldtrust;
63 64
}

D
Dr. Stephen Henson 已提交
65 66
int X509_check_trust(X509 *x, int id, int flags)
{
67 68
    X509_TRUST *pt;
    int idx;
69

70
    /* We get this as a default value */
71 72 73
    if (id == X509_TRUST_DEFAULT)
        return obj_trust(NID_anyExtendedKeyUsage, x,
                         flags | X509_TRUST_DO_SS_COMPAT);
74 75 76 77 78
    idx = X509_TRUST_get_by_id(id);
    if (idx == -1)
        return default_trust(id, x, flags);
    pt = X509_TRUST_get0(idx);
    return pt->check_trust(pt, x, flags);
D
Dr. Stephen Henson 已提交
79 80 81 82
}

int X509_TRUST_get_count(void)
{
83 84 85
    if (!trtable)
        return X509_TRUST_COUNT;
    return sk_X509_TRUST_num(trtable) + X509_TRUST_COUNT;
D
Dr. Stephen Henson 已提交
86 87
}

88
X509_TRUST *X509_TRUST_get0(int idx)
D
Dr. Stephen Henson 已提交
89
{
90 91 92 93 94
    if (idx < 0)
        return NULL;
    if (idx < (int)X509_TRUST_COUNT)
        return trstandard + idx;
    return sk_X509_TRUST_value(trtable, idx - X509_TRUST_COUNT);
D
Dr. Stephen Henson 已提交
95 96 97 98
}

int X509_TRUST_get_by_id(int id)
{
99 100
    X509_TRUST tmp;
    int idx;
101

102 103
    if ((id >= X509_TRUST_MIN) && (id <= X509_TRUST_MAX))
        return id - X509_TRUST_MIN;
104
    if (trtable == NULL)
105
        return -1;
106
    tmp.trust = id;
107
    idx = sk_X509_TRUST_find(trtable, &tmp);
108
    if (idx < 0)
109 110
        return -1;
    return idx + X509_TRUST_COUNT;
D
Dr. Stephen Henson 已提交
111 112
}

D
 
Dr. Stephen Henson 已提交
113 114
int X509_TRUST_set(int *t, int trust)
{
115 116 117 118 119 120
    if (X509_TRUST_get_by_id(trust) == -1) {
        X509err(X509_F_X509_TRUST_SET, X509_R_INVALID_TRUST);
        return 0;
    }
    *t = trust;
    return 1;
D
 
Dr. Stephen Henson 已提交
121 122
}

123
int X509_TRUST_add(int id, int flags, int (*ck) (X509_TRUST *, X509 *, int),
F
FdaSilvaYY 已提交
124
                   const char *name, int arg1, void *arg2)
D
Dr. Stephen Henson 已提交
125
{
126 127 128 129 130 131 132 133 134 135 136 137
    int idx;
    X509_TRUST *trtmp;
    /*
     * This is set according to what we change: application can't set it
     */
    flags &= ~X509_TRUST_DYNAMIC;
    /* This will always be set for application modified trust entries */
    flags |= X509_TRUST_DYNAMIC_NAME;
    /* Get existing entry if any */
    idx = X509_TRUST_get_by_id(id);
    /* Need a new entry */
    if (idx == -1) {
138
        if ((trtmp = OPENSSL_malloc(sizeof(*trtmp))) == NULL) {
139 140 141 142 143 144 145 146 147 148 149
            X509err(X509_F_X509_TRUST_ADD, ERR_R_MALLOC_FAILURE);
            return 0;
        }
        trtmp->flags = X509_TRUST_DYNAMIC;
    } else
        trtmp = X509_TRUST_get0(idx);

    /* OPENSSL_free existing name if dynamic */
    if (trtmp->flags & X509_TRUST_DYNAMIC_NAME)
        OPENSSL_free(trtmp->name);
    /* dup supplied name */
R
Rich Salz 已提交
150
    if ((trtmp->name = OPENSSL_strdup(name)) == NULL) {
151
        X509err(X509_F_X509_TRUST_ADD, ERR_R_MALLOC_FAILURE);
152
        goto err;
153 154 155 156 157 158 159 160 161 162 163 164 165
    }
    /* Keep the dynamic flag of existing entry */
    trtmp->flags &= X509_TRUST_DYNAMIC;
    /* Set all other flags */
    trtmp->flags |= flags;

    trtmp->trust = id;
    trtmp->check_trust = ck;
    trtmp->arg1 = arg1;
    trtmp->arg2 = arg2;

    /* If its a new entry manage the dynamic table */
    if (idx == -1) {
166 167
        if (trtable == NULL
            && (trtable = sk_X509_TRUST_new(tr_cmp)) == NULL) {
168
            X509err(X509_F_X509_TRUST_ADD, ERR_R_MALLOC_FAILURE);
169
            goto err;;
170 171 172
        }
        if (!sk_X509_TRUST_push(trtable, trtmp)) {
            X509err(X509_F_X509_TRUST_ADD, ERR_R_MALLOC_FAILURE);
173
            goto err;
174 175 176
        }
    }
    return 1;
177 178 179 180 181 182
 err:
    if (idx == -1) {
        OPENSSL_free(trtmp->name);
        OPENSSL_free(trtmp);
    }
    return 0;
D
Dr. Stephen Henson 已提交
183 184 185
}

static void trtable_free(X509_TRUST *p)
186 187 188 189 190 191 192 193 194
{
    if (!p)
        return;
    if (p->flags & X509_TRUST_DYNAMIC) {
        if (p->flags & X509_TRUST_DYNAMIC_NAME)
            OPENSSL_free(p->name);
        OPENSSL_free(p);
    }
}
D
Dr. Stephen Henson 已提交
195 196 197

void X509_TRUST_cleanup(void)
{
198 199
    sk_X509_TRUST_pop_free(trtable, trtable_free);
    trtable = NULL;
D
Dr. Stephen Henson 已提交
200 201
}

F
FdaSilvaYY 已提交
202
int X509_TRUST_get_flags(const X509_TRUST *xp)
D
Dr. Stephen Henson 已提交
203
{
204
    return xp->flags;
D
Dr. Stephen Henson 已提交
205 206
}

F
FdaSilvaYY 已提交
207
char *X509_TRUST_get0_name(const X509_TRUST *xp)
D
Dr. Stephen Henson 已提交
208
{
209
    return xp->name;
D
Dr. Stephen Henson 已提交
210 211
}

F
FdaSilvaYY 已提交
212
int X509_TRUST_get_trust(const X509_TRUST *xp)
D
Dr. Stephen Henson 已提交
213
{
214
    return xp->trust;
D
Dr. Stephen Henson 已提交
215 216
}

217
static int trust_1oidany(X509_TRUST *trust, X509 *x, int flags)
D
Dr. Stephen Henson 已提交
218
{
219
    /*
220 221 222 223
     * Declare the chain verified if the desired trust OID is not rejected in
     * any auxiliary trust info for this certificate, and the OID is either
     * expressly trusted, or else either "anyEKU" is trusted, or the
     * certificate is self-signed.
224
     */
225 226
    flags |= X509_TRUST_DO_SS_COMPAT | X509_TRUST_OK_ANY_EKU;
    return obj_trust(trust->arg1, x, flags);
227 228
}

D
 
Dr. Stephen Henson 已提交
229 230
static int trust_1oid(X509_TRUST *trust, X509 *x, int flags)
{
231 232 233 234 235 236 237
    /*
     * Declare the chain verified only if the desired trust OID is not
     * rejected and is expressly trusted.  Neither "anyEKU" nor "compat"
     * trust in self-signed certificates apply.
     */
    flags &= ~(X509_TRUST_DO_SS_COMPAT | X509_TRUST_OK_ANY_EKU);
    return obj_trust(trust->arg1, x, flags);
D
 
Dr. Stephen Henson 已提交
238 239
}

240 241
static int trust_compat(X509_TRUST *trust, X509 *x, int flags)
{
242
    /* Call for side-effect of computing hash and caching extensions */
243 244 245
    if (X509_check_purpose(x, -1, 0) != 1)
        return X509_TRUST_UNTRUSTED;
    if ((flags & X509_TRUST_NO_SS_COMPAT) == 0 && (x->ex_flags & EXFLAG_SS))
246 247 248
        return X509_TRUST_TRUSTED;
    else
        return X509_TRUST_UNTRUSTED;
D
Dr. Stephen Henson 已提交
249 250
}

251 252
static int obj_trust(int id, X509 *x, int flags)
{
253
    X509_CERT_AUX *ax = x->aux;
254
    int i;
255

256
    if (ax && ax->reject) {
257
        for (i = 0; i < sk_ASN1_OBJECT_num(ax->reject); i++) {
258 259 260
            ASN1_OBJECT *obj = sk_ASN1_OBJECT_value(ax->reject, i);
            int nid = OBJ_obj2nid(obj);

261 262
            if (nid == id || (nid == NID_anyExtendedKeyUsage &&
                (flags & X509_TRUST_OK_ANY_EKU)))
263 264 265
                return X509_TRUST_REJECTED;
        }
    }
266 267

    if (ax && ax->trust) {
268
        for (i = 0; i < sk_ASN1_OBJECT_num(ax->trust); i++) {
269 270 271
            ASN1_OBJECT *obj = sk_ASN1_OBJECT_value(ax->trust, i);
            int nid = OBJ_obj2nid(obj);

272 273
            if (nid == id || (nid == NID_anyExtendedKeyUsage &&
                (flags & X509_TRUST_OK_ANY_EKU)))
274 275
                return X509_TRUST_TRUSTED;
        }
276 277 278 279 280 281 282 283 284 285 286 287 288 289 290
        /*
         * Reject when explicit trust EKU are set and none match.
         *
         * Returning untrusted is enough for for full chains that end in
         * self-signed roots, because when explicit trust is specified it
         * suppresses the default blanket trust of self-signed objects.
         *
         * But for partial chains, this is not enough, because absent a similar
         * trust-self-signed policy, non matching EKUs are indistinguishable
         * from lack of EKU constraints.
         *
         * Therefore, failure to match any trusted purpose must trigger an
         * explicit reject.
         */
        return X509_TRUST_REJECTED;
291
    }
292 293 294 295 296 297 298 299

    if ((flags & X509_TRUST_DO_SS_COMPAT) == 0)
        return X509_TRUST_UNTRUSTED;

    /*
     * Not rejected, and there is no list of accepted uses, try compat.
     */
    return trust_compat(NULL, x, flags);
300
}