13070Spst/* v3_purp.c */ 23070Spst/* Written by Dr Stephen N Henson (steve@openssl.org) for the OpenSSL 33070Spst * project 2001. 43070Spst */ 53070Spst/* ==================================================================== 63070Spst * Copyright (c) 1999-2004 The OpenSSL Project. All rights reserved. 73070Spst * 83070Spst * Redistribution and use in source and binary forms, with or without 93070Spst * modification, are permitted provided that the following conditions 103070Spst * are met: 113070Spst * 123070Spst * 1. Redistributions of source code must retain the above copyright 133070Spst * notice, this list of conditions and the following disclaimer. 143070Spst * 153070Spst * 2. Redistributions in binary form must reproduce the above copyright 163070Spst * notice, this list of conditions and the following disclaimer in 173070Spst * the documentation and/or other materials provided with the 183070Spst * distribution. 193070Spst * 203070Spst * 3. All advertising materials mentioning features or use of this 213070Spst * software must display the following acknowledgment: 223070Spst * "This product includes software developed by the OpenSSL Project 233070Spst * for use in the OpenSSL Toolkit. (http://www.OpenSSL.org/)" 243070Spst * 253070Spst * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to 263070Spst * endorse or promote products derived from this software without 273070Spst * prior written permission. For written permission, please contact 283070Spst * licensing@OpenSSL.org. 293070Spst * 303070Spst * 5. Products derived from this software may not be called "OpenSSL" 313070Spst * nor may "OpenSSL" appear in their names without prior written 323070Spst * permission of the OpenSSL Project. 333070Spst * 348870Srgrimes * 6. Redistributions of any form whatsoever must retain the following 353070Spst * acknowledgment: 363070Spst * "This product includes software developed by the OpenSSL Project 373070Spst * for use in the OpenSSL Toolkit (http://www.OpenSSL.org/)" 383070Spst * 393070Spst * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY 403070Spst * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 418870Srgrimes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 423070Spst * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE OpenSSL PROJECT OR 433070Spst * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 443070Spst * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 453070Spst * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 463070Spst * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 473070Spst * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 483070Spst * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 493070Spst * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED 503070Spst * OF THE POSSIBILITY OF SUCH DAMAGE. 513070Spst * ==================================================================== 523070Spst * 533070Spst * This product includes cryptographic software written by Eric Young 543070Spst * (eay@cryptsoft.com). This product includes software written by Tim 553070Spst * Hudson (tjh@cryptsoft.com). 5618608Spst * 573070Spst */ 583070Spst 5917903Speter#include <stdio.h> 603070Spst#include "cryptlib.h" 613070Spst#include <openssl/x509v3.h> 623070Spst#include <openssl/x509_vfy.h> 633070Spst 643070Spststatic void x509v3_cache_extensions(X509 *x); 6510133Speter 6610133Speterstatic int check_ssl_ca(const X509 *x); 6711661Sphkstatic int check_purpose_ssl_client(const X509_PURPOSE *xp, const X509 *x, int ca); 6810133Speterstatic int check_purpose_ssl_server(const X509_PURPOSE *xp, const X509 *x, int ca); 693070Spststatic int check_purpose_ns_ssl_server(const X509_PURPOSE *xp, const X509 *x, int ca); 703070Spststatic int purpose_smime(const X509 *x, int ca); 713070Spststatic int check_purpose_smime_sign(const X509_PURPOSE *xp, const X509 *x, int ca); 723070Spststatic int check_purpose_smime_encrypt(const X509_PURPOSE *xp, const X509 *x, int ca); 733070Spststatic int check_purpose_crl_sign(const X509_PURPOSE *xp, const X509 *x, int ca); 743070Spststatic int check_purpose_timestamp_sign(const X509_PURPOSE *xp, const X509 *x, int ca); 7510150Sbdestatic int no_check(const X509_PURPOSE *xp, const X509 *x, int ca); 763070Spststatic int ocsp_helper(const X509_PURPOSE *xp, const X509 *x, int ca); 7717141Sjkh 7817141Sjkhstatic int xp_cmp(const X509_PURPOSE * const *a, 7917903Speter const X509_PURPOSE * const *b); 8017903Speterstatic void xptable_free(X509_PURPOSE *p); 813070Spst 823070Spststatic X509_PURPOSE xstandard[] = { 833070Spst {X509_PURPOSE_SSL_CLIENT, X509_TRUST_SSL_CLIENT, 0, check_purpose_ssl_client, "SSL client", "sslclient", NULL}, 843070Spst {X509_PURPOSE_SSL_SERVER, X509_TRUST_SSL_SERVER, 0, check_purpose_ssl_server, "SSL server", "sslserver", NULL}, 8513408Speter {X509_PURPOSE_NS_SSL_SERVER, X509_TRUST_SSL_SERVER, 0, check_purpose_ns_ssl_server, "Netscape SSL server", "nssslserver", NULL}, 863070Spst {X509_PURPOSE_SMIME_SIGN, X509_TRUST_EMAIL, 0, check_purpose_smime_sign, "S/MIME signing", "smimesign", NULL}, 873070Spst {X509_PURPOSE_SMIME_ENCRYPT, X509_TRUST_EMAIL, 0, check_purpose_smime_encrypt, "S/MIME encryption", "smimeencrypt", NULL}, 8817903Speter {X509_PURPOSE_CRL_SIGN, X509_TRUST_COMPAT, 0, check_purpose_crl_sign, "CRL signing", "crlsign", NULL}, 893070Spst {X509_PURPOSE_ANY, X509_TRUST_DEFAULT, 0, no_check, "Any Purpose", "any", NULL}, 903070Spst {X509_PURPOSE_OCSP_HELPER, X509_TRUST_COMPAT, 0, ocsp_helper, "OCSP helper", "ocsphelper", NULL}, 913070Spst {X509_PURPOSE_TIMESTAMP_SIGN, X509_TRUST_TSA, 0, check_purpose_timestamp_sign, "Time Stamp signing", "timestampsign", NULL}, 923070Spst}; 9317903Speter 943070Spst#define X509_PURPOSE_COUNT (sizeof(xstandard)/sizeof(X509_PURPOSE)) 9513408Speter 9613408SpeterIMPLEMENT_STACK_OF(X509_PURPOSE) 9713408Speter 9813408Speterstatic STACK_OF(X509_PURPOSE) *xptable = NULL; 993070Spst 1003070Spststatic int xp_cmp(const X509_PURPOSE * const *a, 1013070Spst const X509_PURPOSE * const *b) 1023070Spst{ 1033070Spst return (*a)->purpose - (*b)->purpose; 1043070Spst} 1053070Spst 1063070Spst/* As much as I'd like to make X509_check_purpose use a "const" X509* 1073070Spst * I really can't because it does recalculate hashes and do other non-const 1083070Spst * things. */ 1093070Spstint X509_check_purpose(X509 *x, int id, int ca) 1103070Spst{ 1113070Spst int idx; 1123070Spst const X509_PURPOSE *pt; 1133070Spst if(!(x->ex_flags & EXFLAG_SET)) { 1143070Spst CRYPTO_w_lock(CRYPTO_LOCK_X509); 1153070Spst x509v3_cache_extensions(x); 1163070Spst CRYPTO_w_unlock(CRYPTO_LOCK_X509); 11710133Speter } 11810133Speter if(id == -1) return 1; 11910133Speter idx = X509_PURPOSE_get_by_id(id); 12010133Speter if(idx == -1) return -1; 12110133Speter pt = X509_PURPOSE_get0(idx); 12210133Speter return pt->check_purpose(pt, x, ca); 12310133Speter} 12410133Speter 12510133Speterint X509_PURPOSE_set(int *p, int purpose) 12610133Speter{ 12710133Speter if(X509_PURPOSE_get_by_id(purpose) == -1) { 12810133Speter X509V3err(X509V3_F_X509_PURPOSE_SET, X509V3_R_INVALID_PURPOSE); 12910133Speter return 0; 13010133Speter } 13110133Speter *p = purpose; 13210133Speter return 1; 13310133Speter} 1343070Spst 13517903Speterint X509_PURPOSE_get_count(void) 1363070Spst{ 1373070Spst if(!xptable) return X509_PURPOSE_COUNT; 1383070Spst return sk_X509_PURPOSE_num(xptable) + X509_PURPOSE_COUNT; 13917903Speter} 1403070Spst 1413070SpstX509_PURPOSE * X509_PURPOSE_get0(int idx) 1423070Spst{ 1433070Spst if(idx < 0) return NULL; 1443070Spst if(idx < (int)X509_PURPOSE_COUNT) return xstandard + idx; 1453070Spst return sk_X509_PURPOSE_value(xptable, idx - X509_PURPOSE_COUNT); 1463070Spst} 1473070Spst 1483070Spstint X509_PURPOSE_get_by_sname(char *sname) 1493070Spst{ 15013408Speter int i; 15117903Speter X509_PURPOSE *xptmp; 1523070Spst for(i = 0; i < X509_PURPOSE_get_count(); i++) { 15313408Speter xptmp = X509_PURPOSE_get0(i); 1543070Spst if(!strcmp(xptmp->sname, sname)) return i; 1553070Spst } 15617903Speter return -1; 15717903Speter} 15817903Speter 15917903Speterint X509_PURPOSE_get_by_id(int purpose) 16017903Speter{ 16117903Speter X509_PURPOSE tmp; 16217903Speter int idx; 16317903Speter if((purpose >= X509_PURPOSE_MIN) && (purpose <= X509_PURPOSE_MAX)) 16417903Speter return purpose - X509_PURPOSE_MIN; 16517903Speter tmp.purpose = purpose; 16617903Speter if(!xptable) return -1; 16717903Speter idx = sk_X509_PURPOSE_find(xptable, &tmp); 1683070Spst if(idx == -1) return -1; 1693070Spst return idx + X509_PURPOSE_COUNT; 1703070Spst} 1713070Spst 1723070Spstint X509_PURPOSE_add(int id, int trust, int flags, 1733070Spst int (*ck)(const X509_PURPOSE *, const X509 *, int), 1743070Spst char *name, char *sname, void *arg) 1753070Spst{ 1763070Spst int idx; 1773070Spst X509_PURPOSE *ptmp; 1783070Spst /* This is set according to what we change: application can't set it */ 1793070Spst flags &= ~X509_PURPOSE_DYNAMIC; 1803070Spst /* This will always be set for application modified trust entries */ 18117903Speter flags |= X509_PURPOSE_DYNAMIC_NAME; 18217903Speter /* Get existing entry if any */ 1833070Spst idx = X509_PURPOSE_get_by_id(id); 1843070Spst /* Need a new entry */ 1853070Spst if(idx == -1) { 1863070Spst if(!(ptmp = OPENSSL_malloc(sizeof(X509_PURPOSE)))) { 18717903Speter X509V3err(X509V3_F_X509_PURPOSE_ADD,ERR_R_MALLOC_FAILURE); 1883070Spst return 0; 1893070Spst } 1903070Spst ptmp->flags = X509_PURPOSE_DYNAMIC; 1913070Spst } else ptmp = X509_PURPOSE_get0(idx); 1923070Spst 1933070Spst /* OPENSSL_free existing name if dynamic */ 1943070Spst if(ptmp->flags & X509_PURPOSE_DYNAMIC_NAME) { 1953070Spst OPENSSL_free(ptmp->name); 1963070Spst OPENSSL_free(ptmp->sname); 1973070Spst } 1983070Spst /* dup supplied name */ 1993070Spst ptmp->name = BUF_strdup(name); 2003070Spst ptmp->sname = BUF_strdup(sname); 2013070Spst if(!ptmp->name || !ptmp->sname) { 2023070Spst X509V3err(X509V3_F_X509_PURPOSE_ADD,ERR_R_MALLOC_FAILURE); 2033070Spst return 0; 2043070Spst } 2053070Spst /* Keep the dynamic flag of existing entry */ 2063070Spst ptmp->flags &= X509_PURPOSE_DYNAMIC; 2073070Spst /* Set all other flags */ 2083070Spst ptmp->flags |= flags; 20917903Speter 2103070Spst ptmp->purpose = id; 2113070Spst ptmp->trust = trust; 2123070Spst ptmp->check_purpose = ck; 2133070Spst ptmp->usr_data = arg; 2143070Spst 2153070Spst /* If its a new entry manage the dynamic table */ 2163070Spst if(idx == -1) { 2173070Spst if(!xptable && !(xptable = sk_X509_PURPOSE_new(xp_cmp))) { 2183070Spst X509V3err(X509V3_F_X509_PURPOSE_ADD,ERR_R_MALLOC_FAILURE); 2193070Spst return 0; 22017903Speter } 2213070Spst if (!sk_X509_PURPOSE_push(xptable, ptmp)) { 2223070Spst X509V3err(X509V3_F_X509_PURPOSE_ADD,ERR_R_MALLOC_FAILURE); 2233070Spst return 0; 2243070Spst } 22517903Speter } 2263070Spst return 1; 2273070Spst} 2283070Spst 22917903Speterstatic void xptable_free(X509_PURPOSE *p) 2303070Spst { 2313070Spst if(!p) return; 2323070Spst if (p->flags & X509_PURPOSE_DYNAMIC) 2333070Spst { 2343070Spst if (p->flags & X509_PURPOSE_DYNAMIC_NAME) { 2353070Spst OPENSSL_free(p->name); 2363070Spst OPENSSL_free(p->sname); 2373070Spst } 2383070Spst OPENSSL_free(p); 2393070Spst } 2403070Spst } 2413070Spst 2423070Spstvoid X509_PURPOSE_cleanup(void) 2433070Spst{ 2443070Spst unsigned int i; 2453070Spst sk_X509_PURPOSE_pop_free(xptable, xptable_free); 2463070Spst for(i = 0; i < X509_PURPOSE_COUNT; i++) xptable_free(xstandard + i); 2473070Spst xptable = NULL; 2483070Spst} 2493070Spst 2503070Spstint X509_PURPOSE_get_id(X509_PURPOSE *xp) 25113408Speter{ 25213408Speter return xp->purpose; 25317903Speter} 25413408Speter 25513408Speterchar *X509_PURPOSE_get0_name(X509_PURPOSE *xp) 25613408Speter{ 25713408Speter return xp->name; 25813408Speter} 25913408Speter 26013408Speterchar *X509_PURPOSE_get0_sname(X509_PURPOSE *xp) 26113408Speter{ 26213408Speter return xp->sname; 26313408Speter} 26413408Speter 26513408Speterint X509_PURPOSE_get_trust(X509_PURPOSE *xp) 26613408Speter{ 26713408Speter return xp->trust; 26813408Speter} 26913408Speter 2703070Spststatic int nid_cmp(const int *a, const int *b) 2713070Spst { 27213408Speter return *a - *b; 27317903Speter } 27413408Speter 2753070SpstDECLARE_OBJ_BSEARCH_CMP_FN(int, int, nid); 2763070SpstIMPLEMENT_OBJ_BSEARCH_CMP_FN(int, int, nid); 2773070Spst 2783070Spstint X509_supported_extension(X509_EXTENSION *ex) 2793070Spst { 28013408Speter /* This table is a list of the NIDs of supported extensions: 2813070Spst * that is those which are used by the verify process. If 2823070Spst * an extension is critical and doesn't appear in this list 2833070Spst * then the verify process will normally reject the certificate. 2843070Spst * The list must be kept in numerical order because it will be 2853070Spst * searched using bsearch. 2863070Spst */ 28717903Speter 2883070Spst static const int supported_nids[] = { 2893070Spst NID_netscape_cert_type, /* 71 */ 2903070Spst NID_key_usage, /* 83 */ 29117903Speter NID_subject_alt_name, /* 85 */ 2923070Spst NID_basic_constraints, /* 87 */ 2933070Spst NID_certificate_policies, /* 89 */ 2943070Spst NID_ext_key_usage, /* 126 */ 2953070Spst#ifndef OPENSSL_NO_RFC3779 2963070Spst NID_sbgp_ipAddrBlock, /* 290 */ 2973070Spst NID_sbgp_autonomousSysNum, /* 291 */ 2983070Spst#endif 2993070Spst NID_policy_constraints, /* 401 */ 3003070Spst NID_proxyCertInfo, /* 663 */ 3013070Spst NID_name_constraints, /* 666 */ 3023070Spst NID_policy_mappings, /* 747 */ 3033070Spst NID_inhibit_any_policy /* 748 */ 3043070Spst }; 3053070Spst 3063070Spst int ex_nid = OBJ_obj2nid(X509_EXTENSION_get_object(ex)); 30717903Speter 30817903Speter if (ex_nid == NID_undef) 30917903Speter return 0; 31017903Speter 31117903Speter if (OBJ_bsearch_nid(&ex_nid, supported_nids, 31217903Speter sizeof(supported_nids)/sizeof(int))) 31310133Speter return 1; 3143070Spst return 0; 3153070Spst } 3163070Spst 31717903Speterstatic void setup_dp(X509 *x, DIST_POINT *dp) 3183070Spst { 3193070Spst X509_NAME *iname = NULL; 3203070Spst int i; 3213070Spst if (dp->reasons) 3223070Spst { 3233070Spst if (dp->reasons->length > 0) 32418608Spst dp->dp_reasons = dp->reasons->data[0]; 32518608Spst if (dp->reasons->length > 1) 32618608Spst dp->dp_reasons |= (dp->reasons->data[1] << 8); 32718608Spst dp->dp_reasons &= CRLDP_ALL_REASONS; 32818608Spst } 3293070Spst else 3303070Spst dp->dp_reasons = CRLDP_ALL_REASONS; 3313070Spst if (!dp->distpoint || (dp->distpoint->type != 1)) 3323070Spst return; 3333070Spst for (i = 0; i < sk_GENERAL_NAME_num(dp->CRLissuer); i++) 3343070Spst { 3353070Spst GENERAL_NAME *gen = sk_GENERAL_NAME_value(dp->CRLissuer, i); 3363070Spst if (gen->type == GEN_DIRNAME) 3373070Spst { 3383070Spst iname = gen->d.directoryName; 3393070Spst break; 34010133Speter } 3413070Spst } 3423070Spst if (!iname) 3433070Spst iname = X509_get_issuer_name(x); 3443070Spst 34510133Speter DIST_POINT_set_dpname(dp->distpoint, iname); 34610133Speter 34713408Speter } 3483070Spst 3493070Spststatic void setup_crldp(X509 *x) 3503070Spst { 3513070Spst int i; 3523070Spst x->crldp = X509_get_ext_d2i(x, NID_crl_distribution_points, NULL, NULL); 35317903Speter for (i = 0; i < sk_DIST_POINT_num(x->crldp); i++) 3543070Spst setup_dp(x, sk_DIST_POINT_value(x->crldp, i)); 3553070Spst } 3563070Spst 35710133Speterstatic void x509v3_cache_extensions(X509 *x) 35810133Speter{ 35910133Speter BASIC_CONSTRAINTS *bs; 3603070Spst PROXY_CERT_INFO_EXTENSION *pci; 3613070Spst ASN1_BIT_STRING *usage; 3623070Spst ASN1_BIT_STRING *ns; 3633070Spst EXTENDED_KEY_USAGE *extusage; 3643070Spst X509_EXTENSION *ex; 3653070Spst 3663070Spst int i; 3673070Spst if(x->ex_flags & EXFLAG_SET) return; 3683070Spst#ifndef OPENSSL_NO_SHA 3693070Spst X509_digest(x, EVP_sha1(), x->sha1_hash, NULL); 3703070Spst#endif 3713070Spst /* Does subject name match issuer ? */ 3723070Spst if(!X509_NAME_cmp(X509_get_subject_name(x), X509_get_issuer_name(x))) 37317903Speter x->ex_flags |= EXFLAG_SI; 3743070Spst /* V1 should mean no extensions ... */ 3753070Spst if(!X509_get_version(x)) x->ex_flags |= EXFLAG_V1; 3763070Spst /* Handle basic constraints */ 3773070Spst if((bs=X509_get_ext_d2i(x, NID_basic_constraints, NULL, NULL))) { 37817903Speter if(bs->ca) x->ex_flags |= EXFLAG_CA; 37917903Speter if(bs->pathlen) { 3803070Spst if((bs->pathlen->type == V_ASN1_NEG_INTEGER) 3813070Spst || !bs->ca) { 38217903Speter x->ex_flags |= EXFLAG_INVALID; 38317903Speter x->ex_pathlen = 0; 3843070Spst } else x->ex_pathlen = ASN1_INTEGER_get(bs->pathlen); 38517903Speter } else x->ex_pathlen = -1; 38617903Speter BASIC_CONSTRAINTS_free(bs); 38710133Speter x->ex_flags |= EXFLAG_BCONS; 3883070Spst } 3893070Spst /* Handle proxy certificates */ 39017903Speter if((pci=X509_get_ext_d2i(x, NID_proxyCertInfo, NULL, NULL))) { 39117903Speter if (x->ex_flags & EXFLAG_CA 39217903Speter || X509_get_ext_by_NID(x, NID_subject_alt_name, -1) >= 0 3933070Spst || X509_get_ext_by_NID(x, NID_issuer_alt_name, -1) >= 0) { 3943070Spst x->ex_flags |= EXFLAG_INVALID; 3953070Spst } 39617903Speter if (pci->pcPathLengthConstraint) { 3973070Spst x->ex_pcpathlen = 39817903Speter ASN1_INTEGER_get(pci->pcPathLengthConstraint); 3993070Spst } else x->ex_pcpathlen = -1; 4003070Spst PROXY_CERT_INFO_EXTENSION_free(pci); 4013070Spst x->ex_flags |= EXFLAG_PROXY; 40217903Speter } 40317903Speter /* Handle key usage */ 4043070Spst if((usage=X509_get_ext_d2i(x, NID_key_usage, NULL, NULL))) { 40510133Speter if(usage->length > 0) { 40610133Speter x->ex_kusage = usage->data[0]; 40710133Speter if(usage->length > 1) 40810133Speter x->ex_kusage |= usage->data[1] << 8; 40910133Speter } else x->ex_kusage = 0; 41017903Speter x->ex_flags |= EXFLAG_KUSAGE; 41117903Speter ASN1_BIT_STRING_free(usage); 41217903Speter } 41317903Speter x->ex_xkusage = 0; 41417903Speter if((extusage=X509_get_ext_d2i(x, NID_ext_key_usage, NULL, NULL))) { 41517903Speter x->ex_flags |= EXFLAG_XKUSAGE; 41617903Speter for(i = 0; i < sk_ASN1_OBJECT_num(extusage); i++) { 41717903Speter switch(OBJ_obj2nid(sk_ASN1_OBJECT_value(extusage,i))) { 41817903Speter case NID_server_auth: 41917903Speter x->ex_xkusage |= XKU_SSL_SERVER; 42017903Speter break; 42117903Speter 42217903Speter case NID_client_auth: 42317903Speter x->ex_xkusage |= XKU_SSL_CLIENT; 42417903Speter break; 42517903Speter 42617903Speter case NID_email_protect: 42717903Speter x->ex_xkusage |= XKU_SMIME; 4283070Spst break; 42910133Speter 43010133Speter case NID_code_sign: 43110133Speter x->ex_xkusage |= XKU_CODE_SIGN; 43210133Speter break; 43310133Speter 43410133Speter case NID_ms_sgc: 43510133Speter case NID_ns_sgc: 43610133Speter x->ex_xkusage |= XKU_SGC; 4373070Spst break; 4383070Spst 4393070Spst case NID_OCSP_sign: 4403070Spst x->ex_xkusage |= XKU_OCSP_SIGN; 4413070Spst break; 4423070Spst 4433070Spst case NID_time_stamp: 4443070Spst x->ex_xkusage |= XKU_TIMESTAMP; 4453070Spst break; 4463070Spst 4473070Spst case NID_dvcs: 4483070Spst x->ex_xkusage |= XKU_DVCS; 4493070Spst break; 45017903Speter } 4513070Spst } 4523070Spst sk_ASN1_OBJECT_pop_free(extusage, ASN1_OBJECT_free); 4533070Spst } 45410133Speter 45510133Speter if((ns=X509_get_ext_d2i(x, NID_netscape_cert_type, NULL, NULL))) { 45617903Speter if(ns->length > 0) x->ex_nscert = ns->data[0]; 45717903Speter else x->ex_nscert = 0; 45810133Speter x->ex_flags |= EXFLAG_NSCERT; 4593070Spst ASN1_BIT_STRING_free(ns); 4603070Spst } 46117903Speter x->skid =X509_get_ext_d2i(x, NID_subject_key_identifier, NULL, NULL); 4623070Spst x->akid =X509_get_ext_d2i(x, NID_authority_key_identifier, NULL, NULL); 4633070Spst x->altname = X509_get_ext_d2i(x, NID_subject_alt_name, NULL, NULL); 46417903Speter x->nc = X509_get_ext_d2i(x, NID_name_constraints, &i, NULL); 46517903Speter if (!x->nc && (i != -1)) 46613408Speter x->ex_flags |= EXFLAG_INVALID; 4673070Spst setup_crldp(x); 4683070Spst 46913408Speter#ifndef OPENSSL_NO_RFC3779 4703070Spst x->rfc3779_addr =X509_get_ext_d2i(x, NID_sbgp_ipAddrBlock, NULL, NULL); 4713070Spst x->rfc3779_asid =X509_get_ext_d2i(x, NID_sbgp_autonomousSysNum, 4723070Spst NULL, NULL); 47317903Speter#endif 47410133Speter for (i = 0; i < X509_get_ext_count(x); i++) 4753070Spst { 4763070Spst ex = X509_get_ext(x, i); 47717903Speter if (OBJ_obj2nid(X509_EXTENSION_get_object(ex)) 4783070Spst == NID_freshest_crl) 4793070Spst x->ex_flags |= EXFLAG_FRESHEST; 4803070Spst if (!X509_EXTENSION_get_critical(ex)) 48117903Speter continue; 48217903Speter if (!X509_supported_extension(ex)) 48317903Speter { 4843070Spst x->ex_flags |= EXFLAG_CRITICAL; 48517903Speter break; 48617903Speter } 48717903Speter } 48817903Speter x->ex_flags |= EXFLAG_SET; 4893070Spst} 4903070Spst 49117903Speter/* CA checks common to all purposes 49210133Speter * return codes: 49310133Speter * 0 not a CA 49410133Speter * 1 is a CA 49510133Speter * 2 basicConstraints absent so "maybe" a CA 49610133Speter * 3 basicConstraints absent but self signed V1. 49710133Speter * 4 basicConstraints absent but keyUsage present and keyCertSign asserted. 49813408Speter */ 49910133Speter 50010133Speter#define V1_ROOT (EXFLAG_V1|EXFLAG_SS) 5013070Spst#define ku_reject(x, usage) \ 50210133Speter (((x)->ex_flags & EXFLAG_KUSAGE) && !((x)->ex_kusage & (usage))) 50317903Speter#define xku_reject(x, usage) \ 50417903Speter (((x)->ex_flags & EXFLAG_XKUSAGE) && !((x)->ex_xkusage & (usage))) 50517903Speter#define ns_reject(x, usage) \ 50617903Speter (((x)->ex_flags & EXFLAG_NSCERT) && !((x)->ex_nscert & (usage))) 50717903Speter 50817903Speterstatic int check_ca(const X509 *x) 50917903Speter{ 51017903Speter /* keyUsage if present should allow cert signing */ 51117903Speter if(ku_reject(x, KU_KEY_CERT_SIGN)) return 0; 51217903Speter if(x->ex_flags & EXFLAG_BCONS) { 51317903Speter if(x->ex_flags & EXFLAG_CA) return 1; 51417903Speter /* If basicConstraints says not a CA then say so */ 51517903Speter else return 0; 51617903Speter } else { 51717903Speter /* we support V1 roots for... uh, I don't really know why. */ 51817903Speter if((x->ex_flags & V1_ROOT) == V1_ROOT) return 3; 51917903Speter /* If key usage present it must have certSign so tolerate it */ 52010133Speter else if (x->ex_flags & EXFLAG_KUSAGE) return 4; 52110133Speter /* Older certificates could have Netscape-specific CA types */ 52210133Speter else if (x->ex_flags & EXFLAG_NSCERT 52310133Speter && x->ex_nscert & NS_ANY_CA) return 5; 52417903Speter /* can this still be regarded a CA certificate? I doubt it */ 52517903Speter return 0; 52617903Speter } 52717903Speter} 52817903Speter 52917903Speterint X509_check_ca(X509 *x) 53017903Speter{ 53117903Speter if(!(x->ex_flags & EXFLAG_SET)) { 53217903Speter CRYPTO_w_lock(CRYPTO_LOCK_X509); 53317903Speter x509v3_cache_extensions(x); 53417903Speter CRYPTO_w_unlock(CRYPTO_LOCK_X509); 53517903Speter } 53617903Speter 53717903Speter return check_ca(x); 53817903Speter} 53917903Speter 54017903Speter/* Check SSL CA: common checks for SSL client and server */ 54117903Speterstatic int check_ssl_ca(const X509 *x) 54217903Speter{ 54317903Speter int ca_ret; 54417903Speter ca_ret = check_ca(x); 54517903Speter if(!ca_ret) return 0; 54617903Speter /* check nsCertType if present */ 54717903Speter if(ca_ret != 5 || x->ex_nscert & NS_SSL_CA) return ca_ret; 54817903Speter else return 0; 5493070Spst} 5503070Spst 55110133Speter 5523070Spststatic int check_purpose_ssl_client(const X509_PURPOSE *xp, const X509 *x, int ca) 5533070Spst{ 55417903Speter if(xku_reject(x,XKU_SSL_CLIENT)) return 0; 55510133Speter if(ca) return check_ssl_ca(x); 55610133Speter /* We need to do digital signatures with it */ 55717903Speter if(ku_reject(x,KU_DIGITAL_SIGNATURE)) return 0; 55817903Speter /* nsCertType if present should allow SSL client use */ 55917903Speter if(ns_reject(x, NS_SSL_CLIENT)) return 0; 56017903Speter return 1; 56117903Speter} 56217903Speter 56317903Speterstatic int check_purpose_ssl_server(const X509_PURPOSE *xp, const X509 *x, int ca) 56417903Speter{ 56517903Speter if(xku_reject(x,XKU_SSL_SERVER|XKU_SGC)) return 0; 56617903Speter if(ca) return check_ssl_ca(x); 56717903Speter 56810133Speter if(ns_reject(x, NS_SSL_SERVER)) return 0; 56910133Speter /* Now as for keyUsage: we'll at least need to sign OR encipher */ 57010133Speter if(ku_reject(x, KU_DIGITAL_SIGNATURE|KU_KEY_ENCIPHERMENT)) return 0; 57110133Speter 57210133Speter return 1; 5733070Spst 57417903Speter} 57517903Speter 57617903Speterstatic int check_purpose_ns_ssl_server(const X509_PURPOSE *xp, const X509 *x, int ca) 57710133Speter{ 57810133Speter int ret; 57917903Speter ret = check_purpose_ssl_server(xp, x, ca); 58010133Speter if(!ret || ca) return ret; 58110133Speter /* We need to encipher or Netscape complains */ 58210133Speter if(ku_reject(x, KU_KEY_ENCIPHERMENT)) return 0; 58310133Speter return ret; 58410133Speter} 58517903Speter 58610133Speter/* common S/MIME checks */ 58710133Speterstatic int purpose_smime(const X509 *x, int ca) 58817903Speter{ 5893070Spst if(xku_reject(x,XKU_SMIME)) return 0; 59017903Speter if(ca) { 59117903Speter int ca_ret; 5923070Spst ca_ret = check_ca(x); 59317903Speter if(!ca_ret) return 0; 59417903Speter /* check nsCertType if present */ 59517903Speter if(ca_ret != 5 || x->ex_nscert & NS_SMIME_CA) return ca_ret; 59617903Speter else return 0; 59717903Speter } 59810133Speter if(x->ex_flags & EXFLAG_NSCERT) { 5993070Spst if(x->ex_nscert & NS_SMIME) return 1; 6003070Spst /* Workaround for some buggy certificates */ 6013070Spst if(x->ex_nscert & NS_SSL_CLIENT) return 2; 60213408Speter return 0; 60313408Speter } 60413408Speter return 1; 60513408Speter} 60613408Speter 60713408Speterstatic int check_purpose_smime_sign(const X509_PURPOSE *xp, const X509 *x, int ca) 60813408Speter{ 60913408Speter int ret; 61013408Speter ret = purpose_smime(x, ca); 61113408Speter if(!ret || ca) return ret; 61213408Speter if(ku_reject(x, KU_DIGITAL_SIGNATURE|KU_NON_REPUDIATION)) return 0; 61313408Speter return ret; 61413408Speter} 61513408Speter 61613408Speterstatic int check_purpose_smime_encrypt(const X509_PURPOSE *xp, const X509 *x, int ca) 61713408Speter{ 61813408Speter int ret; 61913408Speter ret = purpose_smime(x, ca); 62013408Speter if(!ret || ca) return ret; 62113408Speter if(ku_reject(x, KU_KEY_ENCIPHERMENT)) return 0; 62213408Speter return ret; 62313408Speter} 62413408Speter 62513408Speterstatic int check_purpose_crl_sign(const X509_PURPOSE *xp, const X509 *x, int ca) 62613408Speter{ 62713408Speter if(ca) { 62813408Speter int ca_ret; 62913408Speter if((ca_ret = check_ca(x)) != 2) return ca_ret; 63013408Speter else return 0; 63113408Speter } 63213408Speter if(ku_reject(x, KU_CRL_SIGN)) return 0; 63313408Speter return 1; 63413408Speter} 63513408Speter 63613408Speter/* OCSP helper: this is *not* a full OCSP check. It just checks that 63713408Speter * each CA is valid. Additional checks must be made on the chain. 63813408Speter */ 63913408Speter 64013408Speterstatic int ocsp_helper(const X509_PURPOSE *xp, const X509 *x, int ca) 64113408Speter{ 64213408Speter /* Must be a valid CA. Should we really support the "I don't know" 64313408Speter value (2)? */ 64413408Speter if(ca) return check_ca(x); 64513408Speter /* leaf certificate is checked in OCSP_verify() */ 6463070Spst return 1; 6473070Spst} 6483070Spst 6493070Spststatic int check_purpose_timestamp_sign(const X509_PURPOSE *xp, const X509 *x, 65013408Speter int ca) 65113408Speter{ 6523070Spst int i_ext; 6533070Spst 6543070Spst /* If ca is true we must return if this is a valid CA certificate. */ 6553070Spst if (ca) return check_ca(x); 6563070Spst 6573070Spst /* 6583070Spst * Check the optional key usage field: 6593070Spst * if Key Usage is present, it must be one of digitalSignature 6603070Spst * and/or nonRepudiation (other values are not consistent and shall 6613070Spst * be rejected). 662 */ 663 if ((x->ex_flags & EXFLAG_KUSAGE) 664 && ((x->ex_kusage & ~(KU_NON_REPUDIATION | KU_DIGITAL_SIGNATURE)) || 665 !(x->ex_kusage & (KU_NON_REPUDIATION | KU_DIGITAL_SIGNATURE)))) 666 return 0; 667 668 /* Only time stamp key usage is permitted and it's required. */ 669 if (!(x->ex_flags & EXFLAG_XKUSAGE) || x->ex_xkusage != XKU_TIMESTAMP) 670 return 0; 671 672 /* Extended Key Usage MUST be critical */ 673 i_ext = X509_get_ext_by_NID((X509 *) x, NID_ext_key_usage, -1); 674 if (i_ext >= 0) 675 { 676 X509_EXTENSION *ext = X509_get_ext((X509 *) x, i_ext); 677 if (!X509_EXTENSION_get_critical(ext)) 678 return 0; 679 } 680 681 return 1; 682} 683 684static int no_check(const X509_PURPOSE *xp, const X509 *x, int ca) 685{ 686 return 1; 687} 688 689/* Various checks to see if one certificate issued the second. 690 * This can be used to prune a set of possible issuer certificates 691 * which have been looked up using some simple method such as by 692 * subject name. 693 * These are: 694 * 1. Check issuer_name(subject) == subject_name(issuer) 695 * 2. If akid(subject) exists check it matches issuer 696 * 3. If key_usage(issuer) exists check it supports certificate signing 697 * returns 0 for OK, positive for reason for mismatch, reasons match 698 * codes for X509_verify_cert() 699 */ 700 701int X509_check_issued(X509 *issuer, X509 *subject) 702{ 703 if(X509_NAME_cmp(X509_get_subject_name(issuer), 704 X509_get_issuer_name(subject))) 705 return X509_V_ERR_SUBJECT_ISSUER_MISMATCH; 706 x509v3_cache_extensions(issuer); 707 x509v3_cache_extensions(subject); 708 709 if(subject->akid) 710 { 711 int ret = X509_check_akid(issuer, subject->akid); 712 if (ret != X509_V_OK) 713 return ret; 714 } 715 716 if(subject->ex_flags & EXFLAG_PROXY) 717 { 718 if(ku_reject(issuer, KU_DIGITAL_SIGNATURE)) 719 return X509_V_ERR_KEYUSAGE_NO_DIGITAL_SIGNATURE; 720 } 721 else if(ku_reject(issuer, KU_KEY_CERT_SIGN)) 722 return X509_V_ERR_KEYUSAGE_NO_CERTSIGN; 723 return X509_V_OK; 724} 725 726int X509_check_akid(X509 *issuer, AUTHORITY_KEYID *akid) 727 { 728 729 if(!akid) 730 return X509_V_OK; 731 732 /* Check key ids (if present) */ 733 if(akid->keyid && issuer->skid && 734 ASN1_OCTET_STRING_cmp(akid->keyid, issuer->skid) ) 735 return X509_V_ERR_AKID_SKID_MISMATCH; 736 /* Check serial number */ 737 if(akid->serial && 738 ASN1_INTEGER_cmp(X509_get_serialNumber(issuer), akid->serial)) 739 return X509_V_ERR_AKID_ISSUER_SERIAL_MISMATCH; 740 /* Check issuer name */ 741 if(akid->issuer) 742 { 743 /* Ugh, for some peculiar reason AKID includes 744 * SEQUENCE OF GeneralName. So look for a DirName. 745 * There may be more than one but we only take any 746 * notice of the first. 747 */ 748 GENERAL_NAMES *gens; 749 GENERAL_NAME *gen; 750 X509_NAME *nm = NULL; 751 int i; 752 gens = akid->issuer; 753 for(i = 0; i < sk_GENERAL_NAME_num(gens); i++) 754 { 755 gen = sk_GENERAL_NAME_value(gens, i); 756 if(gen->type == GEN_DIRNAME) 757 { 758 nm = gen->d.dirn; 759 break; 760 } 761 } 762 if(nm && X509_NAME_cmp(nm, X509_get_issuer_name(issuer))) 763 return X509_V_ERR_AKID_ISSUER_SERIAL_MISMATCH; 764 } 765 return X509_V_OK; 766 } 767 768