From be6c4ee7faaa55c62567a8c3fb0f4e98a482292e Mon Sep 17 00:00:00 2001 From: Joshua Rogers Date: Tue, 19 May 2026 15:54:30 +0200 Subject: [PATCH] gtls: verify OCSP response signature in gtls_verify_ocsp_status Since aeb1a281ca ("gtls: fix OCSP stapling management"), the function parses the stapled OCSP response and reads the certificate status via gnutls_ocsp_resp_get_single(), but never calls gnutls_ocsp_resp_verify() or gnutls_ocsp_resp_verify_direct(). A response with a forged or corrupted signature is accepted without question. Fix by calling gnutls_ocsp_resp_verify() against the trust list obtained from the session credentials immediately after gnutls_ocsp_resp_import(). This handles both directly-signed responses and delegated OCSP responders without requiring the issuer certificate to be present in the peer chain. The missing check only affects the CURLOPT_SSL_VERIFYSTATUS code path when CURLOPT_SSL_VERIFYPEER is disabled. With peer verification enabled, gnutls_certificate_verify_peers2() independently catches the invalid response via GNUTLS_CERT_INVALID_OCSP_STATUS before gtls_verify_ocsp_status() is reached. As a result, no attack is possible that is not already trivially achievable without OCSP stapling when peer verification is off. This is a correctness and consistency fix, not a security vulnerability. Reported-by: Joshua Rogers Closes #21677 --- lib/vtls/gtls.c | 21 +++++++++++++++++---- 1 file changed, 17 insertions(+), 4 deletions(-) diff --git a/lib/vtls/gtls.c b/lib/vtls/gtls.c index 0b0744517d..3019143ad6 100644 --- a/lib/vtls/gtls.c +++ b/lib/vtls/gtls.c @@ -1429,6 +1429,9 @@ static CURLcode gtls_verify_ocsp_status(struct Curl_easy *data, { gnutls_ocsp_resp_t ocsp_resp = NULL; gnutls_datum_t status_request; + gnutls_certificate_credentials_t creds = NULL; + gnutls_x509_trust_list_t tlist = NULL; + unsigned int verify_status = 0; gnutls_ocsp_cert_status_t status = GNUTLS_OCSP_CERT_UNKNOWN; gnutls_x509_crl_reason_t reason; CURLcode result = CURLE_OK; @@ -1461,13 +1464,23 @@ static CURLcode gtls_verify_ocsp_status(struct Curl_easy *data, goto out; } - rc = gnutls_ocsp_resp_get_single(ocsp_resp, 0, NULL, NULL, NULL, NULL, - &status, NULL, NULL, NULL, &reason); - if(rc < 0) { - failf(data, "Invalid OCSP response received"); + if(!gnutls_credentials_get(session, GNUTLS_CRD_CERTIFICATE, + (void **)&creds)) + gnutls_certificate_get_trust_list(creds, &tlist); + if(!tlist) { + failf(data, "OCSP response signature verification failed"); result = CURLE_SSL_INVALIDCERTSTATUS; goto out; } + rc = gnutls_ocsp_resp_verify(ocsp_resp, tlist, &verify_status, 0); + if(rc < 0 || verify_status) { + failf(data, "OCSP response signature verification failed"); + result = CURLE_SSL_INVALIDCERTSTATUS; + goto out; + } + + (void)gnutls_ocsp_resp_get_single(ocsp_resp, 0, NULL, NULL, NULL, NULL, + &status, NULL, NULL, NULL, &reason); switch(status) { case GNUTLS_OCSP_CERT_GOOD: