int x509v3_cache_extensions()

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;
}