static int internal_verify(X509_STORE_CTX *ctx)
{
    int n = sk_X509_num(ctx->chain) - 1;
    X509 *xi = sk_X509_value(ctx->chain, n);
    X509 *xs;

    /*
     * With DANE-verified bare public key TA signatures, it remains only to
     * check the timestamps of the top certificate.  We report the issuer as
     * NULL, since all we have is a bare key.
     */
    if (ctx->bare_ta_signed) {
        xs = xi;
        xi = NULL;
        goto check_cert_time;
    }

    if (ctx->check_issued(ctx, xi, xi))
        xs = xi; /* the typical case: last cert in the chain is self-issued */
    else {
        if (ctx->param->flags & X509_V_FLAG_PARTIAL_CHAIN) {
            xs = xi;
            goto check_cert_time;
        }
        if (n <= 0) {
            if (!verify_cb_cert(ctx, xi, 0,
                                X509_V_ERR_UNABLE_TO_VERIFY_LEAF_SIGNATURE))
                return 0;

            xs = xi;
            goto check_cert_time;
        }

        n--;
        ctx->error_depth = n;
        xs = sk_X509_value(ctx->chain, n);
    }

    /*
     * Do not clear ctx->error=0, it must be "sticky", only the user's callback
     * is allowed to reset errors (at its own peril).
     */
    while (n >= 0) {
        /*
         * For each iteration of this loop:
         * n is the subject depth
         * xs is the subject cert, for which the signature is to be checked
         * xi is the supposed issuer cert containing the public key to use
         * Initially xs == xi if the last cert in the chain is self-issued.
         *
         * Skip signature check for self-signed certificates unless explicitly
         * asked for because it does not add any security and just wastes time.
         */
        if (xs != xi || ((ctx->param->flags & X509_V_FLAG_CHECK_SS_SIGNATURE)
                         && (xi->ex_flags & EXFLAG_SS) != 0)) {
            EVP_PKEY *pkey;
            /*
             * If the issuer's public key is not available or its key usage
             * does not support issuing the subject cert, report the issuer
             * cert and its depth (rather than n, the depth of the subject).
             */
            int issuer_depth = n + (xs == xi ? 0 : 1);
            /*
             * According to https://tools.ietf.org/html/rfc5280#section-6.1.4
             * step (n) we must check any given key usage extension in a CA cert
             * when preparing the verification of a certificate issued by it.
             * According to https://tools.ietf.org/html/rfc5280#section-4.2.1.3
             * we must not verify a certifiate signature if the key usage of the
             * CA certificate that issued the certificate prohibits signing.
             * In case the 'issuing' certificate is the last in the chain and is
             * not a CA certificate but a 'self-issued' end-entity cert (i.e.,
             * xs == xi && !(xi->ex_flags & EXFLAG_CA)) RFC 5280 does not apply
             * (see https://tools.ietf.org/html/rfc6818#section-2) and thus
             * we are free to ignore any key usage restrictions on such certs.
             */
            int ret = xs == xi && (xi->ex_flags & EXFLAG_CA) == 0
                ? X509_V_OK : x509_signing_allowed(xi, xs);

            if (ret != X509_V_OK && !verify_cb_cert(ctx, xi, issuer_depth, ret))
                return 0;
            if ((pkey = X509_get0_pubkey(xi)) == NULL) {
                ret = X509_V_ERR_UNABLE_TO_DECODE_ISSUER_PUBLIC_KEY;
                if (!verify_cb_cert(ctx, xi, issuer_depth, ret))
                    return 0;
            } else if (X509_verify(xs, pkey) <= 0) {
                ret = X509_V_ERR_CERT_SIGNATURE_FAILURE;
                if (!verify_cb_cert(ctx, xs, n, ret))
                    return 0;
            }
        }

    check_cert_time: /* in addition to RFC 5280, do also for trusted (root) cert */
        /* Calls verify callback as needed */
        if (!x509_check_cert_time(ctx, xs, n))
            return 0;

        /*
         * Signal success at this depth.  However, the previous error (if any)
         * is retained.
         */
        ctx->current_issuer = xi;
        ctx->current_cert = xs;
        ctx->error_depth = n;
        if (!ctx->verify_cb(1, ctx))
            return 0;

        if (--n >= 0) {
            xi = xs;
            xs = sk_X509_value(ctx->chain, n);
        }
    }
    return 1;
}