int ssl_build_cert_chain(SSL *s, SSL_CTX *ctx, int flags)
{
    CERT *c = s ? s->cert : ctx->cert;
    CERT_PKEY *cpk = c->key;
    X509_STORE *chain_store = NULL;
    X509_STORE_CTX *xs_ctx = NULL;
    STACK_OF(X509) *chain = NULL, *untrusted = NULL;
    X509 *x;
    SSL_CTX *real_ctx = (s == NULL) ? ctx : s->ctx;
    int i, rv = 0;

    if (!cpk->x509) {
        ERR_raise(ERR_LIB_SSL, SSL_R_NO_CERTIFICATE_SET);
        goto err;
    }
    /* Rearranging and check the chain: add everything to a store */
    if (flags & SSL_BUILD_CHAIN_FLAG_CHECK) {
        chain_store = X509_STORE_new();
        if (chain_store == NULL)
            goto err;
        for (i = 0; i < sk_X509_num(cpk->chain); i++) {
            x = sk_X509_value(cpk->chain, i);
            if (!X509_STORE_add_cert(chain_store, x))
                goto err;
        }
        /* Add EE cert too: it might be self signed */
        if (!X509_STORE_add_cert(chain_store, cpk->x509))
            goto err;
    } else {
        if (c->chain_store)
            chain_store = c->chain_store;
        else if (s)
            chain_store = s->ctx->cert_store;
        else
            chain_store = ctx->cert_store;

        if (flags & SSL_BUILD_CHAIN_FLAG_UNTRUSTED)
            untrusted = cpk->chain;
    }

    xs_ctx = X509_STORE_CTX_new_ex(real_ctx->libctx, real_ctx->propq);
    if (xs_ctx == NULL) {
        ERR_raise(ERR_LIB_SSL, ERR_R_MALLOC_FAILURE);
        goto err;
    }
    if (!X509_STORE_CTX_init(xs_ctx, chain_store, cpk->x509, untrusted)) {
        ERR_raise(ERR_LIB_SSL, ERR_R_X509_LIB);
        goto err;
    }
    /* Set suite B flags if needed */
    X509_STORE_CTX_set_flags(xs_ctx,
                             c->cert_flags & SSL_CERT_FLAG_SUITEB_128_LOS);

    i = X509_verify_cert(xs_ctx);
    if (i <= 0 && flags & SSL_BUILD_CHAIN_FLAG_IGNORE_ERROR) {
        if (flags & SSL_BUILD_CHAIN_FLAG_CLEAR_ERROR)
            ERR_clear_error();
        i = 1;
        rv = 2;
    }
    if (i > 0)
        chain = X509_STORE_CTX_get1_chain(xs_ctx);
    if (i <= 0) {
        i = X509_STORE_CTX_get_error(xs_ctx);
        ERR_raise_data(ERR_LIB_SSL, SSL_R_CERTIFICATE_VERIFY_FAILED,
                       "Verify error:%s", X509_verify_cert_error_string(i));

        goto err;
    }
    /* Remove EE certificate from chain */
    x = sk_X509_shift(chain);
    X509_free(x);
    if (flags & SSL_BUILD_CHAIN_FLAG_NO_ROOT) {
        if (sk_X509_num(chain) > 0) {
            /* See if last cert is self signed */
            x = sk_X509_value(chain, sk_X509_num(chain) - 1);
            if (X509_get_extension_flags(x) & EXFLAG_SS) {
                x = sk_X509_pop(chain);
                X509_free(x);
            }
        }
    }
    /*
     * Check security level of all CA certificates: EE will have been checked
     * already.
     */
    for (i = 0; i < sk_X509_num(chain); i++) {
        x = sk_X509_value(chain, i);
        rv = ssl_security_cert(s, ctx, x, 0, 0);
        if (rv != 1) {
            ERR_raise(ERR_LIB_SSL, rv);
            sk_X509_pop_free(chain, X509_free);
            rv = 0;
            goto err;
        }
    }
    sk_X509_pop_free(cpk->chain, X509_free);
    cpk->chain = chain;
    if (rv == 0)
        rv = 1;
 err:
    if (flags & SSL_BUILD_CHAIN_FLAG_CHECK)
        X509_STORE_free(chain_store);
    X509_STORE_CTX_free(xs_ctx);

    return rv;
}