CVSS3
Attack Vector
NETWORK
Attack Complexity
LOW
Privileges Required
NONE
User Interaction
NONE
Scope
UNCHANGED
Confidentiality Impact
LOW
Integrity Impact
LOW
Availability Impact
NONE
CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:L/I:L/A:N
AI Score
Confidence
High
EPSS
Percentile
16.4%
When the TLS backend is GnuTLS, there is an issue with the OCSP stapling validation process. As a result, even if the certificate is revoked, the connection can be established without resulting in an error.
When the OCSP stapling status response is “revoked,” gnutls_certificate_verify_peers2() returns an error. However, gnutls_certificate_verify_peers2() only returns an error when the OCSP status is “revoked.” For other statuses, gnutls_certificate_verify_peers2() returns a successful result.
In curl, the verification of the OCSP stapling status response is performed not only with the above function but also with gnutls_ocsp_status_request_is_checked(). However, this function returns a non-zero value if the OCSP stapling status response exists. As a result, if any response exists, it is treated as a successful case, and the verification process concludes.
if(config->verifystatus) {
if(gnutls_ocsp_status_request_is_checked(session, 0) == 0) {
gnutls_datum_t status_request;
gnutls_ocsp_resp_t ocsp_resp;
gnutls_ocsp_cert_status_t status;
gnutls_x509_crl_reason_t reason;
rc = gnutls_ocsp_status_request_get(session, &status_request);
infof(data, " server certificate status verification FAILED");
if(rc == GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE) {
failf(data, "No OCSP response received");
return CURLE_SSL_INVALIDCERTSTATUS;
}
if(rc < 0) {
failf(data, "Invalid OCSP response received");
return CURLE_SSL_INVALIDCERTSTATUS;
}
gnutls_ocsp_resp_init(&ocsp_resp);
rc = gnutls_ocsp_resp_import(ocsp_resp, &status_request);
if(rc < 0) {
failf(data, "Invalid OCSP response received");
return CURLE_SSL_INVALIDCERTSTATUS;
}
(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:
break;
case GNUTLS_OCSP_CERT_REVOKED: {
const char *crl_reason;
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;
}
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);
return CURLE_SSL_INVALIDCERTSTATUS;
}
else
infof(data, " server certificate status verification OK");
}
else
infof(data, " server certificate status verification SKIPPED");
I have set up a test site, so please try it out.
OCSP stapling status response is configured to return “unauthorized (6).”
An error will occur if the TLS backend is OpenSSL.
I noticed while researching that starting from GnuTLS 3.1.2, OCSP stapling is enabled by default with gnutls_init. As a result, whether you specify --cert-status or not, the behavior remains the same (currently, in the curl source code, it is not possible to disable OCSP stapling).
https://www.gnutls.org/manual/html_node/Session-initialization.html
Bypassing OCSP verification.