From 155b5fe0f93365e6df1c56ee3606b121080c6c12 Mon Sep 17 00:00:00 2001 From: Mounir IDRASSI Date: Mon, 29 Jun 2026 16:00:00 +0900 Subject: [PATCH] x509: fix OCSP BasicResponse leak in in-verify check In check_cert_ocsp_resp(), OCSP_response_get1_basic() returns an owning OCSP_BASICRESP. The combined-condition early return on OCSP_resp_count(bs) < 1 bypassed the end: cleanup label, leaking bs when a stapled OCSP response decoded to a BasicResponse with no single responses. Separate the count check from the acquisition and route the empty case through end: (ret = X509_V_ERR_OCSP_NO_RESPONSE; goto end;) so bs is freed while preserving the previous return value. Reachable only with the non-default X509_V_FLAG_OCSP_RESP_CHECK with peer-supplied (e.g. TLS 1.3 stapled) responses. Reported-by: geeknik (https://github.com/geeknik) Suggested-by: geeknik (https://github.com/geeknik) Fixes #31759 Reviewed-by: Andrew Dinh Reviewed-by: Daniel Kubec MergeDate: Mon Aug 3 07:03:00 2026 (Merged from https://github.com/openssl/openssl/pull/31764) --- crypto/x509/x509_vfy.c | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/crypto/x509/x509_vfy.c b/crypto/x509/x509_vfy.c index 6e1d8f1f291d5..3194519c3677d 100644 --- ./crypto/x509/x509_vfy.c +++ ./crypto/x509/x509_vfy.c @@ -1192,10 +1192,20 @@ static int check_cert_ocsp_resp(X509_STORE_CTX *ctx) return X509_V_ERR_OCSP_NO_RESPONSE; if ((resp = sk_OCSP_RESPONSE_value(ctx->ocsp_resp, ctx->error_depth)) == NULL - || (bs = OCSP_response_get1_basic(resp)) == NULL - || (num = OCSP_resp_count(bs)) < 1) + || (bs = OCSP_response_get1_basic(resp)) == NULL) return X509_V_ERR_OCSP_NO_RESPONSE; + /* + * OCSP_response_get1_basic() returns an owning reference, so once bs is + * non-NULL it must be released via the end: cleanup label. Route an empty + * BasicResponse (no single responses) through end: rather than returning + * directly, otherwise bs leaks. + */ + if ((num = OCSP_resp_count(bs)) < 1) { + ret = X509_V_ERR_OCSP_NO_RESPONSE; + goto end; + } + if (OCSP_response_status(resp) != OCSP_RESPONSE_STATUS_SUCCESSFUL) { OCSP_BASICRESP_free(bs); bs = NULL;