159191Skris/* v3_purp.c */
2296465Sdelphij/*
3296465Sdelphij * Written by Dr Stephen N Henson (steve@openssl.org) for the OpenSSL project
4296465Sdelphij * 2001.
559191Skris */
659191Skris/* ====================================================================
7127128Snectar * Copyright (c) 1999-2004 The OpenSSL Project.  All rights reserved.
859191Skris *
959191Skris * Redistribution and use in source and binary forms, with or without
1059191Skris * modification, are permitted provided that the following conditions
1159191Skris * are met:
1259191Skris *
1359191Skris * 1. Redistributions of source code must retain the above copyright
14296465Sdelphij *    notice, this list of conditions and the following disclaimer.
1559191Skris *
1659191Skris * 2. Redistributions in binary form must reproduce the above copyright
1759191Skris *    notice, this list of conditions and the following disclaimer in
1859191Skris *    the documentation and/or other materials provided with the
1959191Skris *    distribution.
2059191Skris *
2159191Skris * 3. All advertising materials mentioning features or use of this
2259191Skris *    software must display the following acknowledgment:
2359191Skris *    "This product includes software developed by the OpenSSL Project
2459191Skris *    for use in the OpenSSL Toolkit. (http://www.OpenSSL.org/)"
2559191Skris *
2659191Skris * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to
2759191Skris *    endorse or promote products derived from this software without
2859191Skris *    prior written permission. For written permission, please contact
2959191Skris *    licensing@OpenSSL.org.
3059191Skris *
3159191Skris * 5. Products derived from this software may not be called "OpenSSL"
3259191Skris *    nor may "OpenSSL" appear in their names without prior written
3359191Skris *    permission of the OpenSSL Project.
3459191Skris *
3559191Skris * 6. Redistributions of any form whatsoever must retain the following
3659191Skris *    acknowledgment:
3759191Skris *    "This product includes software developed by the OpenSSL Project
3859191Skris *    for use in the OpenSSL Toolkit (http://www.OpenSSL.org/)"
3959191Skris *
4059191Skris * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY
4159191Skris * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
4259191Skris * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
4359191Skris * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE OpenSSL PROJECT OR
4459191Skris * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
4559191Skris * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
4659191Skris * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
4759191Skris * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
4859191Skris * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
4959191Skris * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
5059191Skris * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
5159191Skris * OF THE POSSIBILITY OF SUCH DAMAGE.
5259191Skris * ====================================================================
5359191Skris *
5459191Skris * This product includes cryptographic software written by Eric Young
5559191Skris * (eay@cryptsoft.com).  This product includes software written by Tim
5659191Skris * Hudson (tjh@cryptsoft.com).
5759191Skris *
5859191Skris */
5959191Skris
6059191Skris#include <stdio.h>
6159191Skris#include "cryptlib.h"
6259191Skris#include <openssl/x509v3.h>
6368651Skris#include <openssl/x509_vfy.h>
6459191Skris
6559191Skrisstatic void x509v3_cache_extensions(X509 *x);
6659191Skris
6768651Skrisstatic int check_ssl_ca(const X509 *x);
68296465Sdelphijstatic int check_purpose_ssl_client(const X509_PURPOSE *xp, const X509 *x,
69296465Sdelphij                                    int ca);
70296465Sdelphijstatic int check_purpose_ssl_server(const X509_PURPOSE *xp, const X509 *x,
71296465Sdelphij                                    int ca);
72296465Sdelphijstatic int check_purpose_ns_ssl_server(const X509_PURPOSE *xp, const X509 *x,
73296465Sdelphij                                       int ca);
7468651Skrisstatic int purpose_smime(const X509 *x, int ca);
75296465Sdelphijstatic int check_purpose_smime_sign(const X509_PURPOSE *xp, const X509 *x,
76296465Sdelphij                                    int ca);
77296465Sdelphijstatic int check_purpose_smime_encrypt(const X509_PURPOSE *xp, const X509 *x,
78296465Sdelphij                                       int ca);
79296465Sdelphijstatic int check_purpose_crl_sign(const X509_PURPOSE *xp, const X509 *x,
80296465Sdelphij                                  int ca);
8168651Skrisstatic int no_check(const X509_PURPOSE *xp, const X509 *x, int ca);
82109998Smarkmstatic int ocsp_helper(const X509_PURPOSE *xp, const X509 *x, int ca);
8359191Skris
84296465Sdelphijstatic int xp_cmp(const X509_PURPOSE *const *a, const X509_PURPOSE *const *b);
8559191Skrisstatic void xptable_free(X509_PURPOSE *p);
8659191Skris
8759191Skrisstatic X509_PURPOSE xstandard[] = {
88296465Sdelphij    {X509_PURPOSE_SSL_CLIENT, X509_TRUST_SSL_CLIENT, 0,
89296465Sdelphij     check_purpose_ssl_client, "SSL client", "sslclient", NULL},
90296465Sdelphij    {X509_PURPOSE_SSL_SERVER, X509_TRUST_SSL_SERVER, 0,
91296465Sdelphij     check_purpose_ssl_server, "SSL server", "sslserver", NULL},
92296465Sdelphij    {X509_PURPOSE_NS_SSL_SERVER, X509_TRUST_SSL_SERVER, 0,
93296465Sdelphij     check_purpose_ns_ssl_server, "Netscape SSL server", "nssslserver", NULL},
94296465Sdelphij    {X509_PURPOSE_SMIME_SIGN, X509_TRUST_EMAIL, 0, check_purpose_smime_sign,
95296465Sdelphij     "S/MIME signing", "smimesign", NULL},
96296465Sdelphij    {X509_PURPOSE_SMIME_ENCRYPT, X509_TRUST_EMAIL, 0,
97296465Sdelphij     check_purpose_smime_encrypt, "S/MIME encryption", "smimeencrypt", NULL},
98296465Sdelphij    {X509_PURPOSE_CRL_SIGN, X509_TRUST_COMPAT, 0, check_purpose_crl_sign,
99296465Sdelphij     "CRL signing", "crlsign", NULL},
100296465Sdelphij    {X509_PURPOSE_ANY, X509_TRUST_DEFAULT, 0, no_check, "Any Purpose", "any",
101296465Sdelphij     NULL},
102296465Sdelphij    {X509_PURPOSE_OCSP_HELPER, X509_TRUST_COMPAT, 0, ocsp_helper,
103296465Sdelphij     "OCSP helper", "ocsphelper", NULL},
10459191Skris};
10559191Skris
10659191Skris#define X509_PURPOSE_COUNT (sizeof(xstandard)/sizeof(X509_PURPOSE))
10759191Skris
10859191SkrisIMPLEMENT_STACK_OF(X509_PURPOSE)
10959191Skris
11059191Skrisstatic STACK_OF(X509_PURPOSE) *xptable = NULL;
11159191Skris
112296465Sdelphijstatic int xp_cmp(const X509_PURPOSE *const *a, const X509_PURPOSE *const *b)
11359191Skris{
114296465Sdelphij    return (*a)->purpose - (*b)->purpose;
11559191Skris}
11659191Skris
117296465Sdelphij/*
118296465Sdelphij * As much as I'd like to make X509_check_purpose use a "const" X509* I
119296465Sdelphij * really can't because it does recalculate hashes and do other non-const
120296465Sdelphij * things.
121296465Sdelphij */
12259191Skrisint X509_check_purpose(X509 *x, int id, int ca)
12359191Skris{
124296465Sdelphij    int idx;
125296465Sdelphij    const X509_PURPOSE *pt;
126296465Sdelphij    if (!(x->ex_flags & EXFLAG_SET)) {
127296465Sdelphij        CRYPTO_w_lock(CRYPTO_LOCK_X509);
128296465Sdelphij        x509v3_cache_extensions(x);
129296465Sdelphij        CRYPTO_w_unlock(CRYPTO_LOCK_X509);
130296465Sdelphij    }
131296465Sdelphij    if (id == -1)
132296465Sdelphij        return 1;
133296465Sdelphij    idx = X509_PURPOSE_get_by_id(id);
134296465Sdelphij    if (idx == -1)
135296465Sdelphij        return -1;
136296465Sdelphij    pt = X509_PURPOSE_get0(idx);
137296465Sdelphij    return pt->check_purpose(pt, x, ca);
13859191Skris}
13959191Skris
140109998Smarkmint X509_PURPOSE_set(int *p, int purpose)
141109998Smarkm{
142296465Sdelphij    if (X509_PURPOSE_get_by_id(purpose) == -1) {
143296465Sdelphij        X509V3err(X509V3_F_X509_PURPOSE_SET, X509V3_R_INVALID_PURPOSE);
144296465Sdelphij        return 0;
145296465Sdelphij    }
146296465Sdelphij    *p = purpose;
147296465Sdelphij    return 1;
148109998Smarkm}
149109998Smarkm
15059191Skrisint X509_PURPOSE_get_count(void)
15159191Skris{
152296465Sdelphij    if (!xptable)
153296465Sdelphij        return X509_PURPOSE_COUNT;
154296465Sdelphij    return sk_X509_PURPOSE_num(xptable) + X509_PURPOSE_COUNT;
15559191Skris}
15659191Skris
157296465SdelphijX509_PURPOSE *X509_PURPOSE_get0(int idx)
15859191Skris{
159296465Sdelphij    if (idx < 0)
160296465Sdelphij        return NULL;
161296465Sdelphij    if (idx < (int)X509_PURPOSE_COUNT)
162296465Sdelphij        return xstandard + idx;
163296465Sdelphij    return sk_X509_PURPOSE_value(xptable, idx - X509_PURPOSE_COUNT);
16459191Skris}
16559191Skris
16659191Skrisint X509_PURPOSE_get_by_sname(char *sname)
16759191Skris{
168296465Sdelphij    int i;
169296465Sdelphij    X509_PURPOSE *xptmp;
170296465Sdelphij    for (i = 0; i < X509_PURPOSE_get_count(); i++) {
171296465Sdelphij        xptmp = X509_PURPOSE_get0(i);
172296465Sdelphij        if (!strcmp(xptmp->sname, sname))
173296465Sdelphij            return i;
174296465Sdelphij    }
175296465Sdelphij    return -1;
17659191Skris}
17759191Skris
17859191Skrisint X509_PURPOSE_get_by_id(int purpose)
17959191Skris{
180296465Sdelphij    X509_PURPOSE tmp;
181296465Sdelphij    int idx;
182296465Sdelphij    if ((purpose >= X509_PURPOSE_MIN) && (purpose <= X509_PURPOSE_MAX))
183296465Sdelphij        return purpose - X509_PURPOSE_MIN;
184296465Sdelphij    tmp.purpose = purpose;
185296465Sdelphij    if (!xptable)
186296465Sdelphij        return -1;
187296465Sdelphij    idx = sk_X509_PURPOSE_find(xptable, &tmp);
188296465Sdelphij    if (idx == -1)
189296465Sdelphij        return -1;
190296465Sdelphij    return idx + X509_PURPOSE_COUNT;
19159191Skris}
19259191Skris
19359191Skrisint X509_PURPOSE_add(int id, int trust, int flags,
194296465Sdelphij                     int (*ck) (const X509_PURPOSE *, const X509 *, int),
195296465Sdelphij                     char *name, char *sname, void *arg)
19659191Skris{
197296465Sdelphij    int idx;
198296465Sdelphij    X509_PURPOSE *ptmp;
199296465Sdelphij    /*
200296465Sdelphij     * This is set according to what we change: application can't set it
201296465Sdelphij     */
202296465Sdelphij    flags &= ~X509_PURPOSE_DYNAMIC;
203296465Sdelphij    /* This will always be set for application modified trust entries */
204296465Sdelphij    flags |= X509_PURPOSE_DYNAMIC_NAME;
205296465Sdelphij    /* Get existing entry if any */
206296465Sdelphij    idx = X509_PURPOSE_get_by_id(id);
207296465Sdelphij    /* Need a new entry */
208296465Sdelphij    if (idx == -1) {
209296465Sdelphij        if (!(ptmp = OPENSSL_malloc(sizeof(X509_PURPOSE)))) {
210296465Sdelphij            X509V3err(X509V3_F_X509_PURPOSE_ADD, ERR_R_MALLOC_FAILURE);
211296465Sdelphij            return 0;
212296465Sdelphij        }
213296465Sdelphij        ptmp->flags = X509_PURPOSE_DYNAMIC;
214296465Sdelphij    } else
215296465Sdelphij        ptmp = X509_PURPOSE_get0(idx);
21659191Skris
217296465Sdelphij    /* OPENSSL_free existing name if dynamic */
218296465Sdelphij    if (ptmp->flags & X509_PURPOSE_DYNAMIC_NAME) {
219296465Sdelphij        OPENSSL_free(ptmp->name);
220296465Sdelphij        OPENSSL_free(ptmp->sname);
221296465Sdelphij    }
222296465Sdelphij    /* dup supplied name */
223296465Sdelphij    ptmp->name = BUF_strdup(name);
224296465Sdelphij    ptmp->sname = BUF_strdup(sname);
225296465Sdelphij    if (!ptmp->name || !ptmp->sname) {
226296465Sdelphij        X509V3err(X509V3_F_X509_PURPOSE_ADD, ERR_R_MALLOC_FAILURE);
227296465Sdelphij        return 0;
228296465Sdelphij    }
229296465Sdelphij    /* Keep the dynamic flag of existing entry */
230296465Sdelphij    ptmp->flags &= X509_PURPOSE_DYNAMIC;
231296465Sdelphij    /* Set all other flags */
232296465Sdelphij    ptmp->flags |= flags;
23359191Skris
234296465Sdelphij    ptmp->purpose = id;
235296465Sdelphij    ptmp->trust = trust;
236296465Sdelphij    ptmp->check_purpose = ck;
237296465Sdelphij    ptmp->usr_data = arg;
23859191Skris
239296465Sdelphij    /* If its a new entry manage the dynamic table */
240296465Sdelphij    if (idx == -1) {
241296465Sdelphij        if (!xptable && !(xptable = sk_X509_PURPOSE_new(xp_cmp))) {
242296465Sdelphij            X509V3err(X509V3_F_X509_PURPOSE_ADD, ERR_R_MALLOC_FAILURE);
243296465Sdelphij            return 0;
244296465Sdelphij        }
245296465Sdelphij        if (!sk_X509_PURPOSE_push(xptable, ptmp)) {
246296465Sdelphij            X509V3err(X509V3_F_X509_PURPOSE_ADD, ERR_R_MALLOC_FAILURE);
247296465Sdelphij            return 0;
248296465Sdelphij        }
249296465Sdelphij    }
250296465Sdelphij    return 1;
25159191Skris}
25259191Skris
25359191Skrisstatic void xptable_free(X509_PURPOSE *p)
254296465Sdelphij{
255296465Sdelphij    if (!p)
256296465Sdelphij        return;
257296465Sdelphij    if (p->flags & X509_PURPOSE_DYNAMIC) {
258296465Sdelphij        if (p->flags & X509_PURPOSE_DYNAMIC_NAME) {
259296465Sdelphij            OPENSSL_free(p->name);
260296465Sdelphij            OPENSSL_free(p->sname);
261296465Sdelphij        }
262296465Sdelphij        OPENSSL_free(p);
263296465Sdelphij    }
264296465Sdelphij}
26559191Skris
26659191Skrisvoid X509_PURPOSE_cleanup(void)
26759191Skris{
268296465Sdelphij    unsigned int i;
269296465Sdelphij    sk_X509_PURPOSE_pop_free(xptable, xptable_free);
270296465Sdelphij    for (i = 0; i < X509_PURPOSE_COUNT; i++)
271296465Sdelphij        xptable_free(xstandard + i);
272296465Sdelphij    xptable = NULL;
27359191Skris}
27459191Skris
27559191Skrisint X509_PURPOSE_get_id(X509_PURPOSE *xp)
27659191Skris{
277296465Sdelphij    return xp->purpose;
27859191Skris}
27959191Skris
28059191Skrischar *X509_PURPOSE_get0_name(X509_PURPOSE *xp)
28159191Skris{
282296465Sdelphij    return xp->name;
28359191Skris}
28459191Skris
28559191Skrischar *X509_PURPOSE_get0_sname(X509_PURPOSE *xp)
28659191Skris{
287296465Sdelphij    return xp->sname;
28859191Skris}
28959191Skris
29059191Skrisint X509_PURPOSE_get_trust(X509_PURPOSE *xp)
29159191Skris{
292296465Sdelphij    return xp->trust;
29359191Skris}
29459191Skris
295109998Smarkmstatic int nid_cmp(int *a, int *b)
296296465Sdelphij{
297296465Sdelphij    return *a - *b;
298296465Sdelphij}
299109998Smarkm
300109998Smarkmint X509_supported_extension(X509_EXTENSION *ex)
301296465Sdelphij{
302296465Sdelphij    /*
303296465Sdelphij     * This table is a list of the NIDs of supported extensions: that is
304296465Sdelphij     * those which are used by the verify process. If an extension is
305296465Sdelphij     * critical and doesn't appear in this list then the verify process will
306296465Sdelphij     * normally reject the certificate. The list must be kept in numerical
307296465Sdelphij     * order because it will be searched using bsearch.
308296465Sdelphij     */
309109998Smarkm
310296465Sdelphij    static int supported_nids[] = {
311296465Sdelphij        NID_netscape_cert_type, /* 71 */
312296465Sdelphij        NID_key_usage,          /* 83 */
313296465Sdelphij        NID_subject_alt_name,   /* 85 */
314296465Sdelphij        NID_basic_constraints,  /* 87 */
315296465Sdelphij        NID_certificate_policies, /* 89 */
316296465Sdelphij        NID_ext_key_usage,      /* 126 */
317167612Ssimon#ifndef OPENSSL_NO_RFC3779
318296465Sdelphij        NID_sbgp_ipAddrBlock,   /* 290 */
319296465Sdelphij        NID_sbgp_autonomousSysNum, /* 291 */
320167612Ssimon#endif
321296465Sdelphij        NID_policy_constraints, /* 401 */
322296465Sdelphij        NID_proxyCertInfo,      /* 661 */
323296465Sdelphij        NID_inhibit_any_policy  /* 748 */
324296465Sdelphij    };
325109998Smarkm
326296465Sdelphij    int ex_nid;
327109998Smarkm
328296465Sdelphij    ex_nid = OBJ_obj2nid(X509_EXTENSION_get_object(ex));
329109998Smarkm
330296465Sdelphij    if (ex_nid == NID_undef)
331296465Sdelphij        return 0;
332109998Smarkm
333296465Sdelphij    if (OBJ_bsearch((char *)&ex_nid, (char *)supported_nids,
334296465Sdelphij                    sizeof(supported_nids) / sizeof(int), sizeof(int),
335296465Sdelphij                    (int (*)(const void *, const void *))nid_cmp))
336296465Sdelphij        return 1;
337296465Sdelphij    return 0;
338296465Sdelphij}
339109998Smarkm
34059191Skrisstatic void x509v3_cache_extensions(X509 *x)
34159191Skris{
342296465Sdelphij    BASIC_CONSTRAINTS *bs;
343296465Sdelphij    PROXY_CERT_INFO_EXTENSION *pci;
344296465Sdelphij    ASN1_BIT_STRING *usage;
345296465Sdelphij    ASN1_BIT_STRING *ns;
346296465Sdelphij    EXTENDED_KEY_USAGE *extusage;
347296465Sdelphij    X509_EXTENSION *ex;
348296465Sdelphij
349296465Sdelphij    int i;
350296465Sdelphij    if (x->ex_flags & EXFLAG_SET)
351296465Sdelphij        return;
352109998Smarkm#ifndef OPENSSL_NO_SHA
353296465Sdelphij    X509_digest(x, EVP_sha1(), x->sha1_hash, NULL);
35468651Skris#endif
355296465Sdelphij    /* Does subject name match issuer ? */
356296465Sdelphij    if (!X509_NAME_cmp(X509_get_subject_name(x), X509_get_issuer_name(x)))
357296465Sdelphij        x->ex_flags |= EXFLAG_SI;
358296465Sdelphij    /* V1 should mean no extensions ... */
359296465Sdelphij    if (!X509_get_version(x))
360296465Sdelphij        x->ex_flags |= EXFLAG_V1;
361296465Sdelphij    /* Handle basic constraints */
362296465Sdelphij    if ((bs = X509_get_ext_d2i(x, NID_basic_constraints, NULL, NULL))) {
363296465Sdelphij        if (bs->ca)
364296465Sdelphij            x->ex_flags |= EXFLAG_CA;
365296465Sdelphij        if (bs->pathlen) {
366296465Sdelphij            if ((bs->pathlen->type == V_ASN1_NEG_INTEGER)
367296465Sdelphij                || !bs->ca) {
368296465Sdelphij                x->ex_flags |= EXFLAG_INVALID;
369296465Sdelphij                x->ex_pathlen = 0;
370296465Sdelphij            } else
371296465Sdelphij                x->ex_pathlen = ASN1_INTEGER_get(bs->pathlen);
372296465Sdelphij        } else
373296465Sdelphij            x->ex_pathlen = -1;
374296465Sdelphij        BASIC_CONSTRAINTS_free(bs);
375296465Sdelphij        x->ex_flags |= EXFLAG_BCONS;
376296465Sdelphij    }
377296465Sdelphij    /* Handle proxy certificates */
378296465Sdelphij    if ((pci = X509_get_ext_d2i(x, NID_proxyCertInfo, NULL, NULL))) {
379296465Sdelphij        if (x->ex_flags & EXFLAG_CA
380296465Sdelphij            || X509_get_ext_by_NID(x, NID_subject_alt_name, 0) >= 0
381296465Sdelphij            || X509_get_ext_by_NID(x, NID_issuer_alt_name, 0) >= 0) {
382296465Sdelphij            x->ex_flags |= EXFLAG_INVALID;
383296465Sdelphij        }
384296465Sdelphij        if (pci->pcPathLengthConstraint) {
385296465Sdelphij            x->ex_pcpathlen = ASN1_INTEGER_get(pci->pcPathLengthConstraint);
386296465Sdelphij        } else
387296465Sdelphij            x->ex_pcpathlen = -1;
388296465Sdelphij        PROXY_CERT_INFO_EXTENSION_free(pci);
389296465Sdelphij        x->ex_flags |= EXFLAG_PROXY;
390296465Sdelphij    }
391296465Sdelphij    /* Handle key usage */
392296465Sdelphij    if ((usage = X509_get_ext_d2i(x, NID_key_usage, NULL, NULL))) {
393296465Sdelphij        if (usage->length > 0) {
394296465Sdelphij            x->ex_kusage = usage->data[0];
395296465Sdelphij            if (usage->length > 1)
396296465Sdelphij                x->ex_kusage |= usage->data[1] << 8;
397296465Sdelphij        } else
398296465Sdelphij            x->ex_kusage = 0;
399296465Sdelphij        x->ex_flags |= EXFLAG_KUSAGE;
400296465Sdelphij        ASN1_BIT_STRING_free(usage);
401296465Sdelphij    }
402296465Sdelphij    x->ex_xkusage = 0;
403296465Sdelphij    if ((extusage = X509_get_ext_d2i(x, NID_ext_key_usage, NULL, NULL))) {
404296465Sdelphij        x->ex_flags |= EXFLAG_XKUSAGE;
405296465Sdelphij        for (i = 0; i < sk_ASN1_OBJECT_num(extusage); i++) {
406296465Sdelphij            switch (OBJ_obj2nid(sk_ASN1_OBJECT_value(extusage, i))) {
407296465Sdelphij            case NID_server_auth:
408296465Sdelphij                x->ex_xkusage |= XKU_SSL_SERVER;
409296465Sdelphij                break;
41059191Skris
411296465Sdelphij            case NID_client_auth:
412296465Sdelphij                x->ex_xkusage |= XKU_SSL_CLIENT;
413296465Sdelphij                break;
41459191Skris
415296465Sdelphij            case NID_email_protect:
416296465Sdelphij                x->ex_xkusage |= XKU_SMIME;
417296465Sdelphij                break;
41859191Skris
419296465Sdelphij            case NID_code_sign:
420296465Sdelphij                x->ex_xkusage |= XKU_CODE_SIGN;
421296465Sdelphij                break;
42259191Skris
423296465Sdelphij            case NID_ms_sgc:
424296465Sdelphij            case NID_ns_sgc:
425296465Sdelphij                x->ex_xkusage |= XKU_SGC;
426296465Sdelphij                break;
427109998Smarkm
428296465Sdelphij            case NID_OCSP_sign:
429296465Sdelphij                x->ex_xkusage |= XKU_OCSP_SIGN;
430296465Sdelphij                break;
431109998Smarkm
432296465Sdelphij            case NID_time_stamp:
433296465Sdelphij                x->ex_xkusage |= XKU_TIMESTAMP;
434296465Sdelphij                break;
435111147Snectar
436296465Sdelphij            case NID_dvcs:
437296465Sdelphij                x->ex_xkusage |= XKU_DVCS;
438296465Sdelphij                break;
439296465Sdelphij            }
440296465Sdelphij        }
441296465Sdelphij        sk_ASN1_OBJECT_pop_free(extusage, ASN1_OBJECT_free);
442296465Sdelphij    }
44359191Skris
444296465Sdelphij    if ((ns = X509_get_ext_d2i(x, NID_netscape_cert_type, NULL, NULL))) {
445296465Sdelphij        if (ns->length > 0)
446296465Sdelphij            x->ex_nscert = ns->data[0];
447296465Sdelphij        else
448296465Sdelphij            x->ex_nscert = 0;
449296465Sdelphij        x->ex_flags |= EXFLAG_NSCERT;
450296465Sdelphij        ASN1_BIT_STRING_free(ns);
451296465Sdelphij    }
452296465Sdelphij    x->skid = X509_get_ext_d2i(x, NID_subject_key_identifier, NULL, NULL);
453296465Sdelphij    x->akid = X509_get_ext_d2i(x, NID_authority_key_identifier, NULL, NULL);
454167612Ssimon#ifndef OPENSSL_NO_RFC3779
455296465Sdelphij    x->rfc3779_addr = X509_get_ext_d2i(x, NID_sbgp_ipAddrBlock, NULL, NULL);
456296465Sdelphij    x->rfc3779_asid = X509_get_ext_d2i(x, NID_sbgp_autonomousSysNum,
457296465Sdelphij                                       NULL, NULL);
458167612Ssimon#endif
459296465Sdelphij    for (i = 0; i < X509_get_ext_count(x); i++) {
460296465Sdelphij        ex = X509_get_ext(x, i);
461296465Sdelphij        if (!X509_EXTENSION_get_critical(ex))
462296465Sdelphij            continue;
463296465Sdelphij        if (!X509_supported_extension(ex)) {
464296465Sdelphij            x->ex_flags |= EXFLAG_CRITICAL;
465296465Sdelphij            break;
466296465Sdelphij        }
467296465Sdelphij    }
468296465Sdelphij    x->ex_flags |= EXFLAG_SET;
46959191Skris}
47059191Skris
471296465Sdelphij/*-
472296465Sdelphij * CA checks common to all purposes
47359191Skris * return codes:
47459191Skris * 0 not a CA
47559191Skris * 1 is a CA
47659191Skris * 2 basicConstraints absent so "maybe" a CA
47759191Skris * 3 basicConstraints absent but self signed V1.
478127128Snectar * 4 basicConstraints absent but keyUsage present and keyCertSign asserted.
47959191Skris */
48059191Skris
48159191Skris#define V1_ROOT (EXFLAG_V1|EXFLAG_SS)
48259191Skris#define ku_reject(x, usage) \
483296465Sdelphij        (((x)->ex_flags & EXFLAG_KUSAGE) && !((x)->ex_kusage & (usage)))
48459191Skris#define xku_reject(x, usage) \
485296465Sdelphij        (((x)->ex_flags & EXFLAG_XKUSAGE) && !((x)->ex_xkusage & (usage)))
48659191Skris#define ns_reject(x, usage) \
487296465Sdelphij        (((x)->ex_flags & EXFLAG_NSCERT) && !((x)->ex_nscert & (usage)))
48859191Skris
489160814Ssimonstatic int check_ca(const X509 *x)
49059191Skris{
491296465Sdelphij    /* keyUsage if present should allow cert signing */
492296465Sdelphij    if (ku_reject(x, KU_KEY_CERT_SIGN))
493296465Sdelphij        return 0;
494296465Sdelphij    if (x->ex_flags & EXFLAG_BCONS) {
495296465Sdelphij        if (x->ex_flags & EXFLAG_CA)
496296465Sdelphij            return 1;
497296465Sdelphij        /* If basicConstraints says not a CA then say so */
498296465Sdelphij        else
499296465Sdelphij            return 0;
500296465Sdelphij    } else {
501296465Sdelphij        /* we support V1 roots for...  uh, I don't really know why. */
502296465Sdelphij        if ((x->ex_flags & V1_ROOT) == V1_ROOT)
503296465Sdelphij            return 3;
504296465Sdelphij        /*
505296465Sdelphij         * If key usage present it must have certSign so tolerate it
506296465Sdelphij         */
507296465Sdelphij        else if (x->ex_flags & EXFLAG_KUSAGE)
508296465Sdelphij            return 4;
509296465Sdelphij        /* Older certificates could have Netscape-specific CA types */
510296465Sdelphij        else if (x->ex_flags & EXFLAG_NSCERT && x->ex_nscert & NS_ANY_CA)
511296465Sdelphij            return 5;
512296465Sdelphij        /* can this still be regarded a CA certificate?  I doubt it */
513296465Sdelphij        return 0;
514296465Sdelphij    }
51559191Skris}
51659191Skris
517160814Ssimonint X509_check_ca(X509 *x)
518160814Ssimon{
519296465Sdelphij    if (!(x->ex_flags & EXFLAG_SET)) {
520296465Sdelphij        CRYPTO_w_lock(CRYPTO_LOCK_X509);
521296465Sdelphij        x509v3_cache_extensions(x);
522296465Sdelphij        CRYPTO_w_unlock(CRYPTO_LOCK_X509);
523296465Sdelphij    }
524160814Ssimon
525296465Sdelphij    return check_ca(x);
526160814Ssimon}
527160814Ssimon
52868651Skris/* Check SSL CA: common checks for SSL client and server */
52968651Skrisstatic int check_ssl_ca(const X509 *x)
53068651Skris{
531296465Sdelphij    int ca_ret;
532296465Sdelphij    ca_ret = check_ca(x);
533296465Sdelphij    if (!ca_ret)
534296465Sdelphij        return 0;
535296465Sdelphij    /* check nsCertType if present */
536296465Sdelphij    if (ca_ret != 5 || x->ex_nscert & NS_SSL_CA)
537296465Sdelphij        return ca_ret;
538296465Sdelphij    else
539296465Sdelphij        return 0;
54068651Skris}
54159191Skris
542296465Sdelphijstatic int check_purpose_ssl_client(const X509_PURPOSE *xp, const X509 *x,
543296465Sdelphij                                    int ca)
54459191Skris{
545296465Sdelphij    if (xku_reject(x, XKU_SSL_CLIENT))
546296465Sdelphij        return 0;
547296465Sdelphij    if (ca)
548296465Sdelphij        return check_ssl_ca(x);
549296465Sdelphij    /* We need to do digital signatures with it */
550296465Sdelphij    if (ku_reject(x, KU_DIGITAL_SIGNATURE))
551296465Sdelphij        return 0;
552296465Sdelphij    /* nsCertType if present should allow SSL client use */
553296465Sdelphij    if (ns_reject(x, NS_SSL_CLIENT))
554296465Sdelphij        return 0;
555296465Sdelphij    return 1;
55659191Skris}
55759191Skris
558296465Sdelphijstatic int check_purpose_ssl_server(const X509_PURPOSE *xp, const X509 *x,
559296465Sdelphij                                    int ca)
56059191Skris{
561296465Sdelphij    if (xku_reject(x, XKU_SSL_SERVER | XKU_SGC))
562296465Sdelphij        return 0;
563296465Sdelphij    if (ca)
564296465Sdelphij        return check_ssl_ca(x);
56559191Skris
566296465Sdelphij    if (ns_reject(x, NS_SSL_SERVER))
567296465Sdelphij        return 0;
568296465Sdelphij    /* Now as for keyUsage: we'll at least need to sign OR encipher */
569296465Sdelphij    if (ku_reject(x, KU_DIGITAL_SIGNATURE | KU_KEY_ENCIPHERMENT))
570296465Sdelphij        return 0;
57159191Skris
572296465Sdelphij    return 1;
573296465Sdelphij
57459191Skris}
57559191Skris
576296465Sdelphijstatic int check_purpose_ns_ssl_server(const X509_PURPOSE *xp, const X509 *x,
577296465Sdelphij                                       int ca)
57859191Skris{
579296465Sdelphij    int ret;
580296465Sdelphij    ret = check_purpose_ssl_server(xp, x, ca);
581296465Sdelphij    if (!ret || ca)
582296465Sdelphij        return ret;
583296465Sdelphij    /* We need to encipher or Netscape complains */
584296465Sdelphij    if (ku_reject(x, KU_KEY_ENCIPHERMENT))
585296465Sdelphij        return 0;
586296465Sdelphij    return ret;
58759191Skris}
58859191Skris
58959191Skris/* common S/MIME checks */
59068651Skrisstatic int purpose_smime(const X509 *x, int ca)
59159191Skris{
592296465Sdelphij    if (xku_reject(x, XKU_SMIME))
593296465Sdelphij        return 0;
594296465Sdelphij    if (ca) {
595296465Sdelphij        int ca_ret;
596296465Sdelphij        ca_ret = check_ca(x);
597296465Sdelphij        if (!ca_ret)
598296465Sdelphij            return 0;
599296465Sdelphij        /* check nsCertType if present */
600296465Sdelphij        if (ca_ret != 5 || x->ex_nscert & NS_SMIME_CA)
601296465Sdelphij            return ca_ret;
602296465Sdelphij        else
603296465Sdelphij            return 0;
604296465Sdelphij    }
605296465Sdelphij    if (x->ex_flags & EXFLAG_NSCERT) {
606296465Sdelphij        if (x->ex_nscert & NS_SMIME)
607296465Sdelphij            return 1;
608296465Sdelphij        /* Workaround for some buggy certificates */
609296465Sdelphij        if (x->ex_nscert & NS_SSL_CLIENT)
610296465Sdelphij            return 2;
611296465Sdelphij        return 0;
612296465Sdelphij    }
613296465Sdelphij    return 1;
61459191Skris}
61559191Skris
616296465Sdelphijstatic int check_purpose_smime_sign(const X509_PURPOSE *xp, const X509 *x,
617296465Sdelphij                                    int ca)
61859191Skris{
619296465Sdelphij    int ret;
620296465Sdelphij    ret = purpose_smime(x, ca);
621296465Sdelphij    if (!ret || ca)
622296465Sdelphij        return ret;
623296465Sdelphij    if (ku_reject(x, KU_DIGITAL_SIGNATURE | KU_NON_REPUDIATION))
624296465Sdelphij        return 0;
625296465Sdelphij    return ret;
62659191Skris}
62759191Skris
628296465Sdelphijstatic int check_purpose_smime_encrypt(const X509_PURPOSE *xp, const X509 *x,
629296465Sdelphij                                       int ca)
63059191Skris{
631296465Sdelphij    int ret;
632296465Sdelphij    ret = purpose_smime(x, ca);
633296465Sdelphij    if (!ret || ca)
634296465Sdelphij        return ret;
635296465Sdelphij    if (ku_reject(x, KU_KEY_ENCIPHERMENT))
636296465Sdelphij        return 0;
637296465Sdelphij    return ret;
63859191Skris}
63959191Skris
640296465Sdelphijstatic int check_purpose_crl_sign(const X509_PURPOSE *xp, const X509 *x,
641296465Sdelphij                                  int ca)
64259191Skris{
643296465Sdelphij    if (ca) {
644296465Sdelphij        int ca_ret;
645296465Sdelphij        if ((ca_ret = check_ca(x)) != 2)
646296465Sdelphij            return ca_ret;
647296465Sdelphij        else
648296465Sdelphij            return 0;
649296465Sdelphij    }
650296465Sdelphij    if (ku_reject(x, KU_CRL_SIGN))
651296465Sdelphij        return 0;
652296465Sdelphij    return 1;
65359191Skris}
65459191Skris
655296465Sdelphij/*
656296465Sdelphij * OCSP helper: this is *not* a full OCSP check. It just checks that each CA
657296465Sdelphij * is valid. Additional checks must be made on the chain.
658109998Smarkm */
659109998Smarkm
660109998Smarkmstatic int ocsp_helper(const X509_PURPOSE *xp, const X509 *x, int ca)
661109998Smarkm{
662296465Sdelphij    /*
663296465Sdelphij     * Must be a valid CA.  Should we really support the "I don't know" value
664296465Sdelphij     * (2)?
665296465Sdelphij     */
666296465Sdelphij    if (ca)
667296465Sdelphij        return check_ca(x);
668296465Sdelphij    /* leaf certificate is checked in OCSP_verify() */
669296465Sdelphij    return 1;
670109998Smarkm}
671109998Smarkm
67268651Skrisstatic int no_check(const X509_PURPOSE *xp, const X509 *x, int ca)
67359191Skris{
674296465Sdelphij    return 1;
67559191Skris}
67668651Skris
677296465Sdelphij/*-
678296465Sdelphij * Various checks to see if one certificate issued the second.
67968651Skris * This can be used to prune a set of possible issuer certificates
68068651Skris * which have been looked up using some simple method such as by
68168651Skris * subject name.
68268651Skris * These are:
68368651Skris * 1. Check issuer_name(subject) == subject_name(issuer)
68468651Skris * 2. If akid(subject) exists check it matches issuer
68568651Skris * 3. If key_usage(issuer) exists check it supports certificate signing
68668651Skris * returns 0 for OK, positive for reason for mismatch, reasons match
68768651Skris * codes for X509_verify_cert()
68868651Skris */
68968651Skris
69068651Skrisint X509_check_issued(X509 *issuer, X509 *subject)
69168651Skris{
692296465Sdelphij    if (X509_NAME_cmp(X509_get_subject_name(issuer),
693296465Sdelphij                      X509_get_issuer_name(subject)))
694296465Sdelphij        return X509_V_ERR_SUBJECT_ISSUER_MISMATCH;
695296465Sdelphij    x509v3_cache_extensions(issuer);
696296465Sdelphij    x509v3_cache_extensions(subject);
697296465Sdelphij    if (subject->akid) {
698296465Sdelphij        /* Check key ids (if present) */
699296465Sdelphij        if (subject->akid->keyid && issuer->skid &&
700296465Sdelphij            ASN1_OCTET_STRING_cmp(subject->akid->keyid, issuer->skid))
701296465Sdelphij            return X509_V_ERR_AKID_SKID_MISMATCH;
702296465Sdelphij        /* Check serial number */
703296465Sdelphij        if (subject->akid->serial &&
704296465Sdelphij            ASN1_INTEGER_cmp(X509_get_serialNumber(issuer),
705296465Sdelphij                             subject->akid->serial))
706296465Sdelphij            return X509_V_ERR_AKID_ISSUER_SERIAL_MISMATCH;
707296465Sdelphij        /* Check issuer name */
708296465Sdelphij        if (subject->akid->issuer) {
709296465Sdelphij            /*
710296465Sdelphij             * Ugh, for some peculiar reason AKID includes SEQUENCE OF
711296465Sdelphij             * GeneralName. So look for a DirName. There may be more than one
712296465Sdelphij             * but we only take any notice of the first.
713296465Sdelphij             */
714296465Sdelphij            GENERAL_NAMES *gens;
715296465Sdelphij            GENERAL_NAME *gen;
716296465Sdelphij            X509_NAME *nm = NULL;
717296465Sdelphij            int i;
718296465Sdelphij            gens = subject->akid->issuer;
719296465Sdelphij            for (i = 0; i < sk_GENERAL_NAME_num(gens); i++) {
720296465Sdelphij                gen = sk_GENERAL_NAME_value(gens, i);
721296465Sdelphij                if (gen->type == GEN_DIRNAME) {
722296465Sdelphij                    nm = gen->d.dirn;
723296465Sdelphij                    break;
724296465Sdelphij                }
725296465Sdelphij            }
726296465Sdelphij            if (nm && X509_NAME_cmp(nm, X509_get_issuer_name(issuer)))
727296465Sdelphij                return X509_V_ERR_AKID_ISSUER_SERIAL_MISMATCH;
728296465Sdelphij        }
729296465Sdelphij    }
730296465Sdelphij    if (subject->ex_flags & EXFLAG_PROXY) {
731296465Sdelphij        if (ku_reject(issuer, KU_DIGITAL_SIGNATURE))
732296465Sdelphij            return X509_V_ERR_KEYUSAGE_NO_DIGITAL_SIGNATURE;
733296465Sdelphij    } else if (ku_reject(issuer, KU_KEY_CERT_SIGN))
734296465Sdelphij        return X509_V_ERR_KEYUSAGE_NO_CERTSIGN;
735296465Sdelphij    return X509_V_OK;
73668651Skris}
737