Backport of:

From aeb1a281cab13c7ba791cb104e556b20e713941f Mon Sep 17 00:00:00 2001
From: Daniel Stenberg <daniel@haxx.se>
Date: Tue, 20 Aug 2024 16:14:39 +0200
Subject: [PATCH] gtls: fix OCSP stapling management

Reported-by: Hiroki Kurosawa
Closes #14642

Upstream-Status: Backport [import from ubuntu https://git.launchpad.net/ubuntu/+source/curl/tree/debian/patches/CVE-2024-8096.patch?h=ubuntu/jammy-security
Upstream commit https://github.com/curl/curl/commit/aeb1a281cab13c7ba791cb104e556b20e713941f]
CVE: CVE-2024-8096
Signed-off-by: Vijay Anusuri <vanusuri@mvista.com>
---
 lib/vtls/gtls.c | 146 ++++++++++++++++++++++++------------------------
 1 file changed, 73 insertions(+), 73 deletions(-)

--- a/lib/vtls/gtls.c
+++ b/lib/vtls/gtls.c
@@ -530,6 +530,13 @@ gtls_connect_step1(struct Curl_easy *dat
   init_flags |= GNUTLS_NO_TICKETS;
 #endif
 
+#if defined(GNUTLS_NO_STATUS_REQUEST)
+  if(!config->verifystatus)
+    /* Disable the "status_request" TLS extension, enabled by default since
+       GnuTLS 3.8.0. */
+    init_flags |= GNUTLS_NO_STATUS_REQUEST;
+#endif
+
   rc = gnutls_init(&backend->session, init_flags);
   if(rc != GNUTLS_E_SUCCESS) {
     failf(data, "gnutls_init() failed: %d", rc);
@@ -929,104 +936,97 @@ Curl_gtls_verifyserver(struct Curl_easy
     infof(data, "  server certificate verification SKIPPED");
 
   if(SSL_CONN_CONFIG(verifystatus)) {
-    if(gnutls_ocsp_status_request_is_checked(session, 0) == 0) {
-      gnutls_datum_t status_request;
-      gnutls_ocsp_resp_t ocsp_resp;
+    gnutls_datum_t status_request;
+    gnutls_ocsp_resp_t ocsp_resp;
+    gnutls_ocsp_cert_status_t status;
+    gnutls_x509_crl_reason_t reason;
 
-      gnutls_ocsp_cert_status_t status;
-      gnutls_x509_crl_reason_t reason;
+    rc = gnutls_ocsp_status_request_get(session, &status_request);
 
-      rc = gnutls_ocsp_status_request_get(session, &status_request);
+    if(rc == GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE) {
+      failf(data, "No OCSP response received");
+      return CURLE_SSL_INVALIDCERTSTATUS;
+    }
 
-      infof(data, " server certificate status verification FAILED");
+    if(rc < 0) {
+      failf(data, "Invalid OCSP response received");
+      return CURLE_SSL_INVALIDCERTSTATUS;
+    }
 
-      if(rc == GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE) {
-        failf(data, "No OCSP response received");
-        return CURLE_SSL_INVALIDCERTSTATUS;
-      }
+    gnutls_ocsp_resp_init(&ocsp_resp);
 
-      if(rc < 0) {
-        failf(data, "Invalid OCSP response received");
-        return CURLE_SSL_INVALIDCERTSTATUS;
-      }
+    rc = gnutls_ocsp_resp_import(ocsp_resp, &status_request);
+    if(rc < 0) {
+      failf(data, "Invalid OCSP response received");
+      return CURLE_SSL_INVALIDCERTSTATUS;
+    }
 
-      gnutls_ocsp_resp_init(&ocsp_resp);
+    (void)gnutls_ocsp_resp_get_single(ocsp_resp, 0, NULL, NULL, NULL, NULL,
+                                      &status, NULL, NULL, NULL, &reason);
 
-      rc = gnutls_ocsp_resp_import(ocsp_resp, &status_request);
-      if(rc < 0) {
-        failf(data, "Invalid OCSP response received");
-        return CURLE_SSL_INVALIDCERTSTATUS;
-      }
+    switch(status) {
+    case GNUTLS_OCSP_CERT_GOOD:
+      break;
 
-      (void)gnutls_ocsp_resp_get_single(ocsp_resp, 0, NULL, NULL, NULL, NULL,
-                                        &status, NULL, NULL, NULL, &reason);
+    case GNUTLS_OCSP_CERT_REVOKED: {
+      const char *crl_reason;
 
-      switch(status) {
-      case GNUTLS_OCSP_CERT_GOOD:
+      switch(reason) {
+      default:
+      case GNUTLS_X509_CRLREASON_UNSPECIFIED:
+        crl_reason = "unspecified reason";
         break;
 
-      case GNUTLS_OCSP_CERT_REVOKED: {
-        const char *crl_reason;
+      case GNUTLS_X509_CRLREASON_KEYCOMPROMISE:
+        crl_reason = "private key compromised";
+        break;
 
-        switch(reason) {
-          default:
-          case GNUTLS_X509_CRLREASON_UNSPECIFIED:
-            crl_reason = "unspecified reason";
-            break;
-
-          case GNUTLS_X509_CRLREASON_KEYCOMPROMISE:
-            crl_reason = "private key compromised";
-            break;
-
-          case GNUTLS_X509_CRLREASON_CACOMPROMISE:
-            crl_reason = "CA compromised";
-            break;
-
-          case GNUTLS_X509_CRLREASON_AFFILIATIONCHANGED:
-            crl_reason = "affiliation has changed";
-            break;
-
-          case GNUTLS_X509_CRLREASON_SUPERSEDED:
-            crl_reason = "certificate superseded";
-            break;
-
-          case GNUTLS_X509_CRLREASON_CESSATIONOFOPERATION:
-            crl_reason = "operation has ceased";
-            break;
-
-          case GNUTLS_X509_CRLREASON_CERTIFICATEHOLD:
-            crl_reason = "certificate is on hold";
-            break;
-
-          case GNUTLS_X509_CRLREASON_REMOVEFROMCRL:
-            crl_reason = "will be removed from delta CRL";
-            break;
-
-          case GNUTLS_X509_CRLREASON_PRIVILEGEWITHDRAWN:
-            crl_reason = "privilege withdrawn";
-            break;
-
-          case GNUTLS_X509_CRLREASON_AACOMPROMISE:
-            crl_reason = "AA compromised";
-            break;
-        }
+      case GNUTLS_X509_CRLREASON_CACOMPROMISE:
+        crl_reason = "CA compromised";
+        break;
 
-        failf(data, "Server certificate was revoked: %s", crl_reason);
+      case GNUTLS_X509_CRLREASON_AFFILIATIONCHANGED:
+        crl_reason = "affiliation has changed";
         break;
-      }
 
-      default:
-      case GNUTLS_OCSP_CERT_UNKNOWN:
-        failf(data, "Server certificate status is unknown");
+      case GNUTLS_X509_CRLREASON_SUPERSEDED:
+        crl_reason = "certificate superseded";
+        break;
+
+      case GNUTLS_X509_CRLREASON_CESSATIONOFOPERATION:
+        crl_reason = "operation has ceased";
+        break;
+
+      case GNUTLS_X509_CRLREASON_CERTIFICATEHOLD:
+        crl_reason = "certificate is on hold";
+        break;
+
+      case GNUTLS_X509_CRLREASON_REMOVEFROMCRL:
+        crl_reason = "will be removed from delta CRL";
+        break;
+
+      case GNUTLS_X509_CRLREASON_PRIVILEGEWITHDRAWN:
+        crl_reason = "privilege withdrawn";
+        break;
+
+      case GNUTLS_X509_CRLREASON_AACOMPROMISE:
+        crl_reason = "AA compromised";
         break;
       }
 
-      gnutls_ocsp_resp_deinit(ocsp_resp);
+      failf(data, "Server certificate was revoked: %s", crl_reason);
+      break;
+    }
+
+    default:
+    case GNUTLS_OCSP_CERT_UNKNOWN:
+      failf(data, "Server certificate status is unknown");
+      break;
+    }
 
+    gnutls_ocsp_resp_deinit(ocsp_resp);
+    if(status != GNUTLS_OCSP_CERT_GOOD)
       return CURLE_SSL_INVALIDCERTSTATUS;
-    }
-    else
-      infof(data, "  server certificate status verification OK");
   }
   else
     infof(data, "  server certificate status verification SKIPPED");
