in crypto/x509v3/v3_purp.c [415:600]
int x509v3_cache_extensions(X509 *x)
{
BASIC_CONSTRAINTS *bs;
PROXY_CERT_INFO_EXTENSION *pci;
ASN1_BIT_STRING *usage;
ASN1_BIT_STRING *ns;
EXTENDED_KEY_USAGE *extusage;
X509_EXTENSION *ex;
size_t i;
int j;
CRYPTO_MUTEX_lock_read(&x->lock);
const int is_set = x->ex_flags & EXFLAG_SET;
CRYPTO_MUTEX_unlock_read(&x->lock);
if (is_set) {
return (x->ex_flags & EXFLAG_INVALID) == 0;
}
CRYPTO_MUTEX_lock_write(&x->lock);
if (x->ex_flags & EXFLAG_SET) {
CRYPTO_MUTEX_unlock_write(&x->lock);
return (x->ex_flags & EXFLAG_INVALID) == 0;
}
if (!X509_digest(x, EVP_sha1(), x->sha1_hash, NULL))
x->ex_flags |= EXFLAG_INVALID;
/* V1 should mean no extensions ... */
if (X509_get_version(x) == X509_VERSION_1)
x->ex_flags |= EXFLAG_V1;
/* Handle basic constraints */
if ((bs = X509_get_ext_d2i(x, NID_basic_constraints, &j, NULL))) {
if (bs->ca)
x->ex_flags |= EXFLAG_CA;
if (bs->pathlen) {
if ((bs->pathlen->type == V_ASN1_NEG_INTEGER)
|| !bs->ca) {
x->ex_flags |= EXFLAG_INVALID;
x->ex_pathlen = 0;
} else {
/* TODO(davidben): |ASN1_INTEGER_get| returns -1 on overflow,
* which currently acts as if the constraint isn't present. This
* works (an overflowing path length constraint may as well be
* infinity), but Chromium's verifier simply treats values above
* 255 as an error. */
x->ex_pathlen = ASN1_INTEGER_get(bs->pathlen);
}
} else
x->ex_pathlen = -1;
BASIC_CONSTRAINTS_free(bs);
x->ex_flags |= EXFLAG_BCONS;
} else if (j != -1) {
x->ex_flags |= EXFLAG_INVALID;
}
/* Handle proxy certificates */
if ((pci = X509_get_ext_d2i(x, NID_proxyCertInfo, &j, NULL))) {
if (x->ex_flags & EXFLAG_CA
|| X509_get_ext_by_NID(x, NID_subject_alt_name, -1) >= 0
|| X509_get_ext_by_NID(x, NID_issuer_alt_name, -1) >= 0) {
x->ex_flags |= EXFLAG_INVALID;
}
if (pci->pcPathLengthConstraint) {
x->ex_pcpathlen = ASN1_INTEGER_get(pci->pcPathLengthConstraint);
} else
x->ex_pcpathlen = -1;
PROXY_CERT_INFO_EXTENSION_free(pci);
x->ex_flags |= EXFLAG_PROXY;
} else if (j != -1) {
x->ex_flags |= EXFLAG_INVALID;
}
/* Handle key usage */
if ((usage = X509_get_ext_d2i(x, NID_key_usage, &j, NULL))) {
if (usage->length > 0) {
x->ex_kusage = usage->data[0];
if (usage->length > 1)
x->ex_kusage |= usage->data[1] << 8;
} else
x->ex_kusage = 0;
x->ex_flags |= EXFLAG_KUSAGE;
ASN1_BIT_STRING_free(usage);
} else if (j != -1) {
x->ex_flags |= EXFLAG_INVALID;
}
x->ex_xkusage = 0;
if ((extusage = X509_get_ext_d2i(x, NID_ext_key_usage, &j, NULL))) {
x->ex_flags |= EXFLAG_XKUSAGE;
for (i = 0; i < sk_ASN1_OBJECT_num(extusage); i++) {
switch (OBJ_obj2nid(sk_ASN1_OBJECT_value(extusage, i))) {
case NID_server_auth:
x->ex_xkusage |= XKU_SSL_SERVER;
break;
case NID_client_auth:
x->ex_xkusage |= XKU_SSL_CLIENT;
break;
case NID_email_protect:
x->ex_xkusage |= XKU_SMIME;
break;
case NID_code_sign:
x->ex_xkusage |= XKU_CODE_SIGN;
break;
case NID_ms_sgc:
case NID_ns_sgc:
x->ex_xkusage |= XKU_SGC;
break;
case NID_OCSP_sign:
x->ex_xkusage |= XKU_OCSP_SIGN;
break;
case NID_time_stamp:
x->ex_xkusage |= XKU_TIMESTAMP;
break;
case NID_dvcs:
x->ex_xkusage |= XKU_DVCS;
break;
case NID_anyExtendedKeyUsage:
x->ex_xkusage |= XKU_ANYEKU;
break;
}
}
sk_ASN1_OBJECT_pop_free(extusage, ASN1_OBJECT_free);
} else if (j != -1) {
x->ex_flags |= EXFLAG_INVALID;
}
if ((ns = X509_get_ext_d2i(x, NID_netscape_cert_type, &j, NULL))) {
if (ns->length > 0)
x->ex_nscert = ns->data[0];
else
x->ex_nscert = 0;
x->ex_flags |= EXFLAG_NSCERT;
ASN1_BIT_STRING_free(ns);
} else if (j != -1) {
x->ex_flags |= EXFLAG_INVALID;
}
x->skid = X509_get_ext_d2i(x, NID_subject_key_identifier, &j, NULL);
if (x->skid == NULL && j != -1) {
x->ex_flags |= EXFLAG_INVALID;
}
x->akid = X509_get_ext_d2i(x, NID_authority_key_identifier, &j, NULL);
if (x->akid == NULL && j != -1) {
x->ex_flags |= EXFLAG_INVALID;
}
/* Does subject name match issuer ? */
if (!X509_NAME_cmp(X509_get_subject_name(x), X509_get_issuer_name(x))) {
x->ex_flags |= EXFLAG_SI;
/* If SKID matches AKID also indicate self signed */
if (X509_check_akid(x, x->akid) == X509_V_OK &&
!ku_reject(x, KU_KEY_CERT_SIGN))
x->ex_flags |= EXFLAG_SS;
}
x->altname = X509_get_ext_d2i(x, NID_subject_alt_name, &j, NULL);
if (x->altname == NULL && j != -1) {
x->ex_flags |= EXFLAG_INVALID;
}
x->nc = X509_get_ext_d2i(x, NID_name_constraints, &j, NULL);
if (x->nc == NULL && j != -1) {
x->ex_flags |= EXFLAG_INVALID;
}
if (!setup_crldp(x)) {
x->ex_flags |= EXFLAG_INVALID;
}
for (j = 0; j < X509_get_ext_count(x); j++) {
ex = X509_get_ext(x, j);
if (OBJ_obj2nid(X509_EXTENSION_get_object(ex))
== NID_freshest_crl)
x->ex_flags |= EXFLAG_FRESHEST;
if (!X509_EXTENSION_get_critical(ex))
continue;
if (!X509_supported_extension(ex)) {
x->ex_flags |= EXFLAG_CRITICAL;
break;
}
}
x->ex_flags |= EXFLAG_SET;
CRYPTO_MUTEX_unlock_write(&x->lock);
return (x->ex_flags & EXFLAG_INVALID) == 0;
}