Commit message: Fix OCSP_basic_verify signer certificate validation

The function `OCSP_basic_verify` validates the signer certificate on an OCSP
response. The internal function, ocsp_verify_signer, is responsible for this
and is expected to return a 0 value in the event of a failure to verify.
Unfortunately, due to a bug, it actually returns with a postive success
response in this case. In the normal course of events OCSP_basic_verify
will then continue and will fail anyway in the ocsp_check_issuer function
because the supplied "chain" value will be empty in the case that
ocsp_verify_signer failed to verify the chain. This will cause
OCSP_basic_verify to return with a negative result (fatal error). Normally
in the event of a failure to verify it should return with 0.

However, in the case of the OCSP_NOCHECKS flag being used, OCSP_basic_verify
will return with a positvie result. This could lead to callers trusting an
OCSP Basic response when it should not be.

CVE-2022-1343

Fixes #18053

Reviewed-by: Paul Dale <pauli@openssl.org>
Reviewed-by: Tomas Mraz <tomas@openssl.org>
Reviewed-by: Matt Caswell <matt@openssl.org>
CVE: CVE-2022-1343
CWE: CWE-703
Vulnerability description: The function `OCSP_basic_verify` verifies the signer certificate on an OCSP response. In the case where the (non-default) flag OCSP_NOCHECKS is used then the response will be positive (meaning a successful verification) even in the case where the response signing certificate fails to verify. It is anticipated that most users of `OCSP_basic_verify` will not use the OCSP_NOCHECKS flag. In this case the `OCSP_basic_verify` function will return a negative value (indicating a fatal error) in the case of a certificate verification failure. The normal expected return value in this case would be 0. This issue also impacts the command line OpenSSL "ocsp" application. When verifying an ocsp response with the "-no_cert_checks" option the command line application will report that the verification is successful even though it has in fact failed. In this case the incorrect successful response will also be accompanied by error messages showing the failure and contradicting the apparently successful result. Fixed in OpenSSL 3.0.3 (Affected 3.0.0,3.0.1,3.0.2).

Project: openssl

static int ocsp_verify_signer(X509 *signer, int response,
                              X509_STORE *st, unsigned long flags,
                              STACK_OF(X509) *untrusted, STACK_OF(X509) **chain)
{
    X509_STORE_CTX *ctx = X509_STORE_CTX_new();
    X509_VERIFY_PARAM *vp;
    int ret = -1;

    if (ctx == NULL) {
        ERR_raise(ERR_LIB_OCSP, ERR_R_MALLOC_FAILURE);
        goto end;
    }
    if (!X509_STORE_CTX_init(ctx, st, signer, untrusted)) {
        ERR_raise(ERR_LIB_OCSP, ERR_R_X509_LIB);
        goto end;
    }
    if ((vp = X509_STORE_CTX_get0_param(ctx)) == NULL)
        goto end;
    if ((flags & OCSP_PARTIAL_CHAIN) != 0)
        X509_VERIFY_PARAM_set_flags(vp, X509_V_FLAG_PARTIAL_CHAIN);
    if (response
            && X509_get_ext_by_NID(signer, NID_id_pkix_OCSP_noCheck, -1) >= 0)
        /*
         * Locally disable revocation status checking for OCSP responder cert.
         * Done here for CRLs; should be done also for OCSP-based checks.
         */
        X509_VERIFY_PARAM_clear_flags(vp, X509_V_FLAG_CRL_CHECK);
    X509_STORE_CTX_set_purpose(ctx, X509_PURPOSE_OCSP_HELPER);
    X509_STORE_CTX_set_trust(ctx, X509_TRUST_OCSP_REQUEST);

    ret = X509_verify_cert(ctx);
    if (ret <= 0) {
        ret = X509_STORE_CTX_get_error(ctx);
        ERR_raise_data(ERR_LIB_OCSP, OCSP_R_CERTIFICATE_VERIFY_ERROR,
                       "Verify error: %s", X509_verify_cert_error_string(ret));
        goto end;
    }
    if (chain != NULL)
        *chain = X509_STORE_CTX_get1_chain(ctx);

 end:
    X509_STORE_CTX_free(ctx);
    return ret;
}