Commit message: Fix length checks in X509_cmp_time to avoid out-of-bounds reads.

Also tighten X509_cmp_time to reject more than three fractional
seconds in the time; and to reject trailing garbage after the offset.

CVE-2015-1789

Reviewed-by: Viktor Dukhovni <viktor@openssl.org>
Reviewed-by: Richard Levitte <levitte@openssl.org>
CVE: CVE-2015-1789
CWE: CWE-119
Vulnerability description: The X509_cmp_time function in crypto/x509/x509_vfy.c in OpenSSL before 0.9.8zg, 1.0.0 before 1.0.0s, 1.0.1 before 1.0.1n, and 1.0.2 before 1.0.2b allows remote attackers to cause a denial of service (out-of-bounds read and application crash) via a crafted length field in ASN1_TIME data, as demonstrated by an attack against a server that supports client authentication with a custom verification callback.

Project: openssl

static int check_policy(X509_STORE_CTX *ctx)
{
    int ret;
    ret = X509_policy_check(&ctx->tree, &ctx->explicit_policy, ctx->chain,
                            ctx->param->policies, ctx->param->flags);
    if (ret == 0) {
        X509err(X509_F_CHECK_POLICY, ERR_R_MALLOC_FAILURE);
        return 0;
    }
    /* Invalid or inconsistent extensions */
    if (ret == -1) {
        /*
         * Locate certificates with bad extensions and notify callback.
         */
        X509 *x;
        int i;
        for (i = 1; i < sk_X509_num(ctx->chain); i++) {
            x = sk_X509_value(ctx->chain, i);
            if (!(x->ex_flags & EXFLAG_INVALID_POLICY))
                continue;
            ctx->current_cert = x;
            ctx->error = X509_V_ERR_INVALID_POLICY_EXTENSION;
            ret = ctx->verify_cb(0, ctx);
        }
        return 1;
    }
    if (ret == -2) {
        ctx->current_cert = NULL;
        ctx->error = X509_V_ERR_NO_EXPLICIT_POLICY;
        return ctx->verify_cb(0, ctx);
    }

    if (ctx->param->flags & X509_V_FLAG_NOTIFY_POLICY) {
        ctx->current_cert = NULL;
        ctx->error = X509_V_OK;
        if (!ctx->verify_cb(2, ctx))
            return 0;
    }

    return 1;
}

Project: openssl

static int check_revocation(X509_STORE_CTX *ctx)
{
    int i, last, ok;
    if (!(ctx->param->flags & X509_V_FLAG_CRL_CHECK))
        return 1;
    if (ctx->param->flags & X509_V_FLAG_CRL_CHECK_ALL)
        last = sk_X509_num(ctx->chain) - 1;
    else
        last = 0;
    for (i = 0; i <= last; i++) {
        ctx->error_depth = i;
        ok = check_cert(ctx);
        if (!ok)
            return ok;
    }
    return 1;
}

Project: openssl

int X509_verify_cert(X509_STORE_CTX *ctx)
{
    X509 *x, *xtmp, *chain_ss = NULL;
    int bad_chain = 0;
    X509_VERIFY_PARAM *param = ctx->param;
    int depth, i, ok = 0;
    int num;
    int (*cb) (int xok, X509_STORE_CTX *xctx);
    STACK_OF(X509) *sktmp = NULL;
    if (ctx->cert == NULL) {
        X509err(X509_F_X509_VERIFY_CERT, X509_R_NO_CERT_SET_FOR_US_TO_VERIFY);
        return -1;
    }

    cb = ctx->verify_cb;

    /*
     * first we make sure the chain we are going to build is present and that
     * the first entry is in place
     */
    if (ctx->chain == NULL) {
        if (((ctx->chain = sk_X509_new_null()) == NULL) ||
            (!sk_X509_push(ctx->chain, ctx->cert))) {
            X509err(X509_F_X509_VERIFY_CERT, ERR_R_MALLOC_FAILURE);
            goto end;
        }
        CRYPTO_add(&ctx->cert->references, 1, CRYPTO_LOCK_X509);
        ctx->last_untrusted = 1;
    }

    /* We use a temporary STACK so we can chop and hack at it */
    if (ctx->untrusted != NULL
        && (sktmp = sk_X509_dup(ctx->untrusted)) == NULL) {
        X509err(X509_F_X509_VERIFY_CERT, ERR_R_MALLOC_FAILURE);
        goto end;
    }

    num = sk_X509_num(ctx->chain);
    x = sk_X509_value(ctx->chain, num - 1);
    depth = param->depth;

    for (;;) {
        /* If we have enough, we break */
        if (depth < num)
            break;              /* FIXME: If this happens, we should take
                                 * note of it and, if appropriate, use the
                                 * X509_V_ERR_CERT_CHAIN_TOO_LONG error code
                                 * later. */

        /* If we are self signed, we break */
        if (ctx->check_issued(ctx, x, x))
            break;

        /* If we were passed a cert chain, use it first */
        if (ctx->untrusted != NULL) {
            xtmp = find_issuer(ctx, sktmp, x);
            if (xtmp != NULL) {
                if (!sk_X509_push(ctx->chain, xtmp)) {
                    X509err(X509_F_X509_VERIFY_CERT, ERR_R_MALLOC_FAILURE);
                    goto end;
                }
                CRYPTO_add(&xtmp->references, 1, CRYPTO_LOCK_X509);
                (void)sk_X509_delete_ptr(sktmp, xtmp);
                ctx->last_untrusted++;
                x = xtmp;
                num++;
                /*
                 * reparse the full chain for the next one
                 */
                continue;
            }
        }
        break;
    }

    /*
     * at this point, chain should contain a list of untrusted certificates.
     * We now need to add at least one trusted one, if possible, otherwise we
     * complain.
     */

    /*
     * Examine last certificate in chain and see if it is self signed.
     */

    i = sk_X509_num(ctx->chain);
    x = sk_X509_value(ctx->chain, i - 1);
    if (ctx->check_issued(ctx, x, x)) {
        /* we have a self signed certificate */
        if (sk_X509_num(ctx->chain) == 1) {
            /*
             * We have a single self signed certificate: see if we can find
             * it in the store. We must have an exact match to avoid possible
             * impersonation.
             */
            ok = ctx->get_issuer(&xtmp, ctx, x);
            if ((ok <= 0) || X509_cmp(x, xtmp)) {
                ctx->error = X509_V_ERR_DEPTH_ZERO_SELF_SIGNED_CERT;
                ctx->current_cert = x;
                ctx->error_depth = i - 1;
                if (ok == 1)
                    X509_free(xtmp);
                bad_chain = 1;
                ok = cb(0, ctx);
                if (!ok)
                    goto end;
            } else {
                /*
                 * We have a match: replace certificate with store version so
                 * we get any trust settings.
                 */
                X509_free(x);
                x = xtmp;
                (void)sk_X509_set(ctx->chain, i - 1, x);
                ctx->last_untrusted = 0;
            }
        } else {
            /*
             * extract and save self signed certificate for later use
             */
            chain_ss = sk_X509_pop(ctx->chain);
            ctx->last_untrusted--;
            num--;
            x = sk_X509_value(ctx->chain, num - 1);
        }
    }

    /* We now lookup certs from the certificate store */
    for (;;) {
        /* If we have enough, we break */
        if (depth < num)
            break;

        /* If we are self signed, we break */
        if (ctx->check_issued(ctx, x, x))
            break;

        ok = ctx->get_issuer(&xtmp, ctx, x);

        if (ok < 0)
            return ok;
        if (ok == 0)
            break;

        x = xtmp;
        if (!sk_X509_push(ctx->chain, x)) {
            X509_free(xtmp);
            X509err(X509_F_X509_VERIFY_CERT, ERR_R_MALLOC_FAILURE);
            return 0;
        }
        num++;
    }

    /* we now have our chain, lets check it... */

    /* Is last certificate looked up self signed? */
    if (!ctx->check_issued(ctx, x, x)) {
        if ((chain_ss == NULL) || !ctx->check_issued(ctx, x, chain_ss)) {
            if (ctx->last_untrusted >= num)
                ctx->error = X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT_LOCALLY;
            else
                ctx->error = X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT;
            ctx->current_cert = x;
        } else {

            sk_X509_push(ctx->chain, chain_ss);
            num++;
            ctx->last_untrusted = num;
            ctx->current_cert = chain_ss;
            ctx->error = X509_V_ERR_SELF_SIGNED_CERT_IN_CHAIN;
            chain_ss = NULL;
        }

        ctx->error_depth = num - 1;
        bad_chain = 1;
        ok = cb(0, ctx);
        if (!ok)
            goto end;
    }

    /* We have the chain complete: now we need to check its purpose */
    ok = check_chain_extensions(ctx);

    if (!ok)
        goto end;

    /* The chain extensions are OK: check trust */

    if (param->trust > 0)
        ok = check_trust(ctx);

    if (!ok)
        goto end;

    /* We may as well copy down any DSA parameters that are required */
    X509_get_pubkey_parameters(NULL, ctx->chain);

    /*
     * Check revocation status: we do this after copying parameters because
     * they may be needed for CRL signature verification.
     */

    ok = ctx->check_revocation(ctx);
    if (!ok)
        goto end;

    /* At this point, we have a chain and need to verify it */
    if (ctx->verify != NULL)
        ok = ctx->verify(ctx);
    else
        ok = internal_verify(ctx);
    if (!ok)
        goto end;

#ifndef OPENSSL_NO_RFC3779
    /* RFC 3779 path validation, now that CRL check has been done */
    ok = v3_asid_validate_path(ctx);
    if (!ok)
        goto end;
    ok = v3_addr_validate_path(ctx);
    if (!ok)
        goto end;
#endif

    /* If we get this far evaluate policies */
    if (!bad_chain && (ctx->param->flags & X509_V_FLAG_POLICY_CHECK))
        ok = ctx->check_policy(ctx);
    if (!ok)
        goto end;
    if (0) {
 end:
        X509_get_pubkey_parameters(NULL, ctx->chain);
    }
    if (sktmp != NULL)
        sk_X509_free(sktmp);
    if (chain_ss != NULL)
        X509_free(chain_ss);
    return ok;
}

Project: openssl

int X509_STORE_CTX_init(X509_STORE_CTX *ctx, X509_STORE *store, X509 *x509,
                        STACK_OF(X509) *chain)
{
    int ret = 1;
    ctx->ctx = store;
    ctx->current_method = 0;
    ctx->cert = x509;
    ctx->untrusted = chain;
    ctx->crls = NULL;
    ctx->last_untrusted = 0;
    ctx->other_ctx = NULL;
    ctx->valid = 0;
    ctx->chain = NULL;
    ctx->error = 0;
    ctx->explicit_policy = 0;
    ctx->error_depth = 0;
    ctx->current_cert = NULL;
    ctx->current_issuer = NULL;
    ctx->tree = NULL;

    ctx->param = X509_VERIFY_PARAM_new();

    if (!ctx->param) {
        X509err(X509_F_X509_STORE_CTX_INIT, ERR_R_MALLOC_FAILURE);
        return 0;
    }

    /*
     * Inherit callbacks and flags from X509_STORE if not set use defaults.
     */

    if (store)
        ret = X509_VERIFY_PARAM_inherit(ctx->param, store->param);
    else
        ctx->param->inh_flags |= X509_VP_FLAG_DEFAULT | X509_VP_FLAG_ONCE;

    if (store) {
        ctx->verify_cb = store->verify_cb;
        ctx->cleanup = store->cleanup;
    } else
        ctx->cleanup = 0;

    if (ret)
        ret = X509_VERIFY_PARAM_inherit(ctx->param,
                                        X509_VERIFY_PARAM_lookup("default"));

    if (ret == 0) {
        X509err(X509_F_X509_STORE_CTX_INIT, ERR_R_MALLOC_FAILURE);
        return 0;
    }

    if (store && store->check_issued)
        ctx->check_issued = store->check_issued;
    else
        ctx->check_issued = check_issued;

    if (store && store->get_issuer)
        ctx->get_issuer = store->get_issuer;
    else
        ctx->get_issuer = X509_STORE_CTX_get1_issuer;

    if (store && store->verify_cb)
        ctx->verify_cb = store->verify_cb;
    else
        ctx->verify_cb = null_callback;

    if (store && store->verify)
        ctx->verify = store->verify;
    else
        ctx->verify = internal_verify;

    if (store && store->check_revocation)
        ctx->check_revocation = store->check_revocation;
    else
        ctx->check_revocation = check_revocation;

    if (store && store->get_crl)
        ctx->get_crl = store->get_crl;
    else
        ctx->get_crl = get_crl;

    if (store && store->check_crl)
        ctx->check_crl = store->check_crl;
    else
        ctx->check_crl = check_crl;

    if (store && store->cert_crl)
        ctx->cert_crl = store->cert_crl;
    else
        ctx->cert_crl = cert_crl;

    ctx->check_policy = check_policy;

    /*
     * This memset() can't make any sense anyway, so it's removed. As
     * X509_STORE_CTX_cleanup does a proper "free" on the ex_data, we put a
     * corresponding "new" here and remove this bogus initialisation.
     */
    /* memset(&(ctx->ex_data),0,sizeof(CRYPTO_EX_DATA)); */
    if (!CRYPTO_new_ex_data(CRYPTO_EX_INDEX_X509_STORE_CTX, ctx,
                            &(ctx->ex_data))) {
        OPENSSL_free(ctx);
        X509err(X509_F_X509_STORE_CTX_INIT, ERR_R_MALLOC_FAILURE);
        return 0;
    }
    return 1;
}

Project: openssl

static int cert_crl(X509_STORE_CTX *ctx, X509_CRL *crl, X509 *x)
{
    int idx, ok;
    X509_REVOKED rtmp;
    STACK_OF(X509_EXTENSION) *exts;
    X509_EXTENSION *ext;
    /* Look for serial number of certificate in CRL */
    rtmp.serialNumber = X509_get_serialNumber(x);
    /*
     * Sort revoked into serial number order if not already sorted. Do this
     * under a lock to avoid race condition.
     */
    if (!sk_X509_REVOKED_is_sorted(crl->crl->revoked)) {
        CRYPTO_w_lock(CRYPTO_LOCK_X509_CRL);
        sk_X509_REVOKED_sort(crl->crl->revoked);
        CRYPTO_w_unlock(CRYPTO_LOCK_X509_CRL);
    }
    idx = sk_X509_REVOKED_find(crl->crl->revoked, &rtmp);
    /*
     * If found assume revoked: want something cleverer than this to handle
     * entry extensions in V2 CRLs.
     */
    if (idx >= 0) {
        ctx->error = X509_V_ERR_CERT_REVOKED;
        ok = ctx->verify_cb(0, ctx);
        if (!ok)
            return 0;
    }

    if (ctx->param->flags & X509_V_FLAG_IGNORE_CRITICAL)
        return 1;

    /*
     * See if we have any critical CRL extensions: since we currently don't
     * handle any CRL extensions the CRL must be rejected. This code
     * accesses the X509_CRL structure directly: applications shouldn't do
     * this.
     */

    exts = crl->crl->extensions;

    for (idx = 0; idx < sk_X509_EXTENSION_num(exts); idx++) {
        ext = sk_X509_EXTENSION_value(exts, idx);
        if (ext->critical > 0) {
            ctx->error = X509_V_ERR_UNHANDLED_CRITICAL_CRL_EXTENSION;
            ok = ctx->verify_cb(0, ctx);
            if (!ok)
                return 0;
            break;
        }
    }
    return 1;
}

Project: openssl

static int check_cert(X509_STORE_CTX *ctx)
{
    X509_CRL *crl = NULL;
    X509 *x;
    int ok, cnum;
    cnum = ctx->error_depth;
    x = sk_X509_value(ctx->chain, cnum);
    ctx->current_cert = x;
    /* Try to retrieve relevant CRL */
    ok = ctx->get_crl(ctx, &crl, x);
    /*
     * If error looking up CRL, nothing we can do except notify callback
     */
    if (!ok) {
        ctx->error = X509_V_ERR_UNABLE_TO_GET_CRL;
        ok = ctx->verify_cb(0, ctx);
        goto err;
    }
    ctx->current_crl = crl;
    ok = ctx->check_crl(ctx, crl);
    if (!ok)
        goto err;
    ok = ctx->cert_crl(ctx, crl, x);
 err:
    ctx->current_crl = NULL;
    X509_CRL_free(crl);
    return ok;

}

Project: openssl

ASN1_TIME *X509_time_adj(ASN1_TIME *s, long adj, time_t *in_tm)
{
    time_t t;
    int type = -1;

    if (in_tm)
        t = *in_tm;
    else
        time(&t);

    t += adj;
    if (s)
        type = s->type;
    if (type == V_ASN1_UTCTIME)
        return ASN1_UTCTIME_set(s, t);
    if (type == V_ASN1_GENERALIZEDTIME)
        return ASN1_GENERALIZEDTIME_set(s, t);
    return ASN1_TIME_set(s, t);
}

Project: openssl

static int get_crl_sk(X509_STORE_CTX *ctx, X509_CRL **pcrl,
                      X509_NAME *nm, STACK_OF(X509_CRL) *crls)
{
    int i;
    X509_CRL *crl, *best_crl = NULL;
    for (i = 0; i < sk_X509_CRL_num(crls); i++) {
        crl = sk_X509_CRL_value(crls, i);
        if (X509_NAME_cmp(nm, X509_CRL_get_issuer(crl)))
            continue;
        if (check_crl_time(ctx, crl, 0)) {
            *pcrl = crl;
            CRYPTO_add(&crl->references, 1, CRYPTO_LOCK_X509);
            return 1;
        }
        best_crl = crl;
    }
    if (best_crl) {
        *pcrl = best_crl;
        CRYPTO_add(&best_crl->references, 1, CRYPTO_LOCK_X509);
    }

    return 0;
}

Project: openssl

static int check_crl(X509_STORE_CTX *ctx, X509_CRL *crl)
{
    X509 *issuer = NULL;
    EVP_PKEY *ikey = NULL;
    int ok = 0, chnum, cnum;
    cnum = ctx->error_depth;
    chnum = sk_X509_num(ctx->chain) - 1;
    /*
     * Find CRL issuer: if not last certificate then issuer is next
     * certificate in chain.
     */
    if (cnum < chnum)
        issuer = sk_X509_value(ctx->chain, cnum + 1);
    else {
        issuer = sk_X509_value(ctx->chain, chnum);
        /* If not self signed, can't check signature */
        if (!ctx->check_issued(ctx, issuer, issuer)) {
            ctx->error = X509_V_ERR_UNABLE_TO_GET_CRL_ISSUER;
            ok = ctx->verify_cb(0, ctx);
            if (!ok)
                goto err;
        }
    }

    if (issuer) {
        /* Check for cRLSign bit if keyUsage present */
        if ((issuer->ex_flags & EXFLAG_KUSAGE) &&
            !(issuer->ex_kusage & KU_CRL_SIGN)) {
            ctx->error = X509_V_ERR_KEYUSAGE_NO_CRL_SIGN;
            ok = ctx->verify_cb(0, ctx);
            if (!ok)
                goto err;
        }

        /* Attempt to get issuer certificate public key */
        ikey = X509_get_pubkey(issuer);

        if (!ikey) {
            ctx->error = X509_V_ERR_UNABLE_TO_DECODE_ISSUER_PUBLIC_KEY;
            ok = ctx->verify_cb(0, ctx);
            if (!ok)
                goto err;
        } else {
            /* Verify CRL signature */
            if (X509_CRL_verify(crl, ikey) <= 0) {
                ctx->error = X509_V_ERR_CRL_SIGNATURE_FAILURE;
                ok = ctx->verify_cb(0, ctx);
                if (!ok)
                    goto err;
            }
        }
    }

    ok = check_crl_time(ctx, crl, 1);
    if (!ok)
        goto err;

    ok = 1;

 err:
    EVP_PKEY_free(ikey);
    return ok;
}

Project: openssl

int X509_cmp_time(ASN1_TIME *ctm, time_t *cmp_time)
{
    char *str;
    ASN1_TIME atm;
    long offset;
    char buff1[24], buff2[24], *p;
    int i, j, remaining;

    p = buff1;
    remaining = ctm->length;
    str = (char *)ctm->data;
    /*
     * Note that the following (historical) code allows much more slack in the
     * time format than RFC5280. In RFC5280, the representation is fixed:
     * UTCTime: YYMMDDHHMMSSZ
     * GeneralizedTime: YYYYMMDDHHMMSSZ
     */
    if (ctm->type == V_ASN1_UTCTIME) {
        /* YYMMDDHHMM[SS]Z or YYMMDDHHMM[SS](+-)hhmm */
        int min_length = sizeof("YYMMDDHHMMZ") - 1;
        int max_length = sizeof("YYMMDDHHMMSS+hhmm") - 1;
        if (remaining < min_length || remaining > max_length)
            return 0;
        memcpy(p, str, 10);
        p += 10;
        str += 10;
        remaining -= 10;
    } else {
        /* YYYYMMDDHHMM[SS[.fff]]Z or YYYYMMDDHHMM[SS[.f[f[f]]]](+-)hhmm */
        int min_length = sizeof("YYYYMMDDHHMMZ") - 1;
        int max_length = sizeof("YYYYMMDDHHMMSS.fff+hhmm") - 1;
        if (remaining < min_length || remaining > max_length)
            return 0;
        memcpy(p, str, 12);
        p += 12;
        str += 12;
        remaining -= 12;
    }

    if ((*str == 'Z') || (*str == '-') || (*str == '+')) {
        *(p++) = '0';
        *(p++) = '0';
    } else {
        /* SS (seconds) */
        if (remaining < 2)
            return 0;
        *(p++) = *(str++);
        *(p++) = *(str++);
        remaining -= 2;
        /*
         * Skip any (up to three) fractional seconds...
         * TODO(emilia): in RFC5280, fractional seconds are forbidden.
         * Can we just kill them altogether?
         */
        if (remaining && *str == '.') {
            str++;
            remaining--;
            for (i = 0; i < 3 && remaining; i++, str++, remaining--) {
                if (*str < '0' || *str > '9')
                    break;
            }
        }

    }
    *(p++) = 'Z';
    *(p++) = '\0';

    /* We now need either a terminating 'Z' or an offset. */
    if (!remaining)
        return 0;
    if (*str == 'Z') {
        if (remaining != 1)
            return 0;
        offset = 0;
    } else {
        /* (+-)HHMM */
        if ((*str != '+') && (*str != '-'))
            return 0;
        /* Historical behaviour: the (+-)hhmm offset is forbidden in RFC5280. */
        if (remaining != 5)
            return 0;
        if (str[1] < '0' || str[1] > '9' || str[2] < '0' || str[2] > '9' ||
            str[3] < '0' || str[3] > '9' || str[4] < '0' || str[4] > '9')
            return 0;
        offset = ((str[1] - '0') * 10 + (str[2] - '0')) * 60;
        offset += (str[3] - '0') * 10 + (str[4] - '0');
        if (*str == '-')
            offset = -offset;
    }
    atm.type = ctm->type;
    atm.length = sizeof(buff2);
    atm.data = (unsigned char *)buff2;

    if (X509_time_adj(&atm, offset * 60, cmp_time) == NULL)
        return 0;

    if (ctm->type == V_ASN1_UTCTIME) {
        i = (buff1[0] - '0') * 10 + (buff1[1] - '0');
        if (i < 50)
            i += 100;           /* cf. RFC 2459 */
        j = (buff2[0] - '0') * 10 + (buff2[1] - '0');
        if (j < 50)
            j += 100;

        if (i < j)
            return -1;
        if (i > j)
            return 1;
    }
    i = strcmp(buff1, buff2);
    if (i == 0)                 /* wait a second then return younger :-) */
        return -1;
    else
        return i;
}

Project: openssl

int X509_cmp_current_time(ASN1_TIME *ctm)
{
    return X509_cmp_time(ctm, NULL);
}

Project: openssl

static int check_chain_extensions(X509_STORE_CTX *ctx)
{
#ifdef OPENSSL_NO_CHAIN_VERIFY
    return 1;
#else
    int i, ok = 0, must_be_ca, plen = 0;
    X509 *x;
    int (*cb) (int xok, X509_STORE_CTX *xctx);
    int proxy_path_length = 0;
    int allow_proxy_certs =
        ! !(ctx->param->flags & X509_V_FLAG_ALLOW_PROXY_CERTS);
    cb = ctx->verify_cb;

    /*-
     *  must_be_ca can have 1 of 3 values:
     * -1: we accept both CA and non-CA certificates, to allow direct
     *     use of self-signed certificates (which are marked as CA).
     * 0:  we only accept non-CA certificates.  This is currently not
     *     used, but the possibility is present for future extensions.
     * 1:  we only accept CA certificates.  This is currently used for
     *     all certificates in the chain except the leaf certificate.
     */
    must_be_ca = -1;

    /*
     * A hack to keep people who don't want to modify their software happy
     */
    if (getenv("OPENSSL_ALLOW_PROXY_CERTS"))
        allow_proxy_certs = 1;

    /* Check all untrusted certificates */
    for (i = 0; i < ctx->last_untrusted; i++) {
        int ret;
        x = sk_X509_value(ctx->chain, i);
        if (!(ctx->param->flags & X509_V_FLAG_IGNORE_CRITICAL)
            && (x->ex_flags & EXFLAG_CRITICAL)) {
            ctx->error = X509_V_ERR_UNHANDLED_CRITICAL_EXTENSION;
            ctx->error_depth = i;
            ctx->current_cert = x;
            ok = cb(0, ctx);
            if (!ok)
                goto end;
        }
        if (!allow_proxy_certs && (x->ex_flags & EXFLAG_PROXY)) {
            ctx->error = X509_V_ERR_PROXY_CERTIFICATES_NOT_ALLOWED;
            ctx->error_depth = i;
            ctx->current_cert = x;
            ok = cb(0, ctx);
            if (!ok)
                goto end;
        }
        ret = X509_check_ca(x);
        switch (must_be_ca) {
        case -1:
            if ((ctx->param->flags & X509_V_FLAG_X509_STRICT)
                && (ret != 1) && (ret != 0)) {
                ret = 0;
                ctx->error = X509_V_ERR_INVALID_CA;
            } else
                ret = 1;
            break;
        case 0:
            if (ret != 0) {
                ret = 0;
                ctx->error = X509_V_ERR_INVALID_NON_CA;
            } else
                ret = 1;
            break;
        default:
            if ((ret == 0)
                || ((ctx->param->flags & X509_V_FLAG_X509_STRICT)
                    && (ret != 1))) {
                ret = 0;
                ctx->error = X509_V_ERR_INVALID_CA;
            } else
                ret = 1;
            break;
        }
        if (ret == 0) {
            ctx->error_depth = i;
            ctx->current_cert = x;
            ok = cb(0, ctx);
            if (!ok)
                goto end;
        }
        if (ctx->param->purpose > 0) {
            ret = X509_check_purpose(x, ctx->param->purpose, must_be_ca > 0);
            if ((ret == 0)
                || ((ctx->param->flags & X509_V_FLAG_X509_STRICT)
                    && (ret != 1))) {
                ctx->error = X509_V_ERR_INVALID_PURPOSE;
                ctx->error_depth = i;
                ctx->current_cert = x;
                ok = cb(0, ctx);
                if (!ok)
                    goto end;
            }
        }
        /* Check pathlen if not self issued */
        if ((i > 1) && !(x->ex_flags & EXFLAG_SI)
            && (x->ex_pathlen != -1)
            && (plen > (x->ex_pathlen + proxy_path_length + 1))) {
            ctx->error = X509_V_ERR_PATH_LENGTH_EXCEEDED;
            ctx->error_depth = i;
            ctx->current_cert = x;
            ok = cb(0, ctx);
            if (!ok)
                goto end;
        }
        /* Increment path length if not self issued */
        if (!(x->ex_flags & EXFLAG_SI))
            plen++;
        /*
         * If this certificate is a proxy certificate, the next certificate
         * must be another proxy certificate or a EE certificate.  If not,
         * the next certificate must be a CA certificate.
         */
        if (x->ex_flags & EXFLAG_PROXY) {
            if (x->ex_pcpathlen != -1 && i > x->ex_pcpathlen) {
                ctx->error = X509_V_ERR_PROXY_PATH_LENGTH_EXCEEDED;
                ctx->error_depth = i;
                ctx->current_cert = x;
                ok = cb(0, ctx);
                if (!ok)
                    goto end;
            }
            proxy_path_length++;
            must_be_ca = 0;
        } else
            must_be_ca = 1;
    }
    ok = 1;
 end:
    return ok;
#endif
}

Project: openssl

void X509_STORE_CTX_cleanup(X509_STORE_CTX *ctx)
{
    if (ctx->cleanup)
        ctx->cleanup(ctx);
    if (ctx->param != NULL) {
        X509_VERIFY_PARAM_free(ctx->param);
        ctx->param = NULL;
    }
    if (ctx->tree != NULL) {
        X509_policy_tree_free(ctx->tree);
        ctx->tree = NULL;
    }
    if (ctx->chain != NULL) {
        sk_X509_pop_free(ctx->chain, X509_free);
        ctx->chain = NULL;
    }
    CRYPTO_free_ex_data(CRYPTO_EX_INDEX_X509_STORE_CTX, ctx, &(ctx->ex_data));
    memset(&ctx->ex_data, 0, sizeof(CRYPTO_EX_DATA));
}

Project: openssl

static int check_crl_time(X509_STORE_CTX *ctx, X509_CRL *crl, int notify)
{
    time_t *ptime;
    int i;
    ctx->current_crl = crl;
    if (ctx->param->flags & X509_V_FLAG_USE_CHECK_TIME)
        ptime = &ctx->param->check_time;
    else
        ptime = NULL;

    i = X509_cmp_time(X509_CRL_get_lastUpdate(crl), ptime);
    if (i == 0) {
        ctx->error = X509_V_ERR_ERROR_IN_CRL_LAST_UPDATE_FIELD;
        if (!notify || !ctx->verify_cb(0, ctx))
            return 0;
    }

    if (i > 0) {
        ctx->error = X509_V_ERR_CRL_NOT_YET_VALID;
        if (!notify || !ctx->verify_cb(0, ctx))
            return 0;
    }

    if (X509_CRL_get_nextUpdate(crl)) {
        i = X509_cmp_time(X509_CRL_get_nextUpdate(crl), ptime);

        if (i == 0) {
            ctx->error = X509_V_ERR_ERROR_IN_CRL_NEXT_UPDATE_FIELD;
            if (!notify || !ctx->verify_cb(0, ctx))
                return 0;
        }

        if (i < 0) {
            ctx->error = X509_V_ERR_CRL_HAS_EXPIRED;
            if (!notify || !ctx->verify_cb(0, ctx))
                return 0;
        }
    }

    ctx->current_crl = NULL;

    return 1;
}

Project: openssl

static int get_crl(X509_STORE_CTX *ctx, X509_CRL **pcrl, X509 *x)
{
    int ok;
    X509_CRL *crl = NULL;
    X509_OBJECT xobj;
    X509_NAME *nm;
    nm = X509_get_issuer_name(x);
    ok = get_crl_sk(ctx, &crl, nm, ctx->crls);
    if (ok) {
        *pcrl = crl;
        return 1;
    }

    ok = X509_STORE_get_by_subject(ctx, X509_LU_CRL, nm, &xobj);

    if (!ok) {
        /* If we got a near match from get_crl_sk use that */
        if (crl) {
            *pcrl = crl;
            return 1;
        }
        return 0;
    }

    *pcrl = xobj.data.crl;
    if (crl)
        X509_CRL_free(crl);
    return 1;
}