_
("The name in the certificate does not match the expected. "));
+ if (status & GNUTLS_CERT_MISSING_OCSP_STATUS)
+ _gnutls_buffer_append_str(&str,
+ _
+ ("The certificate requires the server to include an OCSP status in its response, but the OCSP status is missing. "));
+
return _gnutls_buffer_to_datum(&str, out, 1);
}
* @GNUTLS_CERT_UNEXPECTED_OWNER: The owner is not the expected one.
* @GNUTLS_CERT_MISMATCH: The certificate presented isn't the expected one (TOFU)
* @GNUTLS_CERT_PURPOSE_MISMATCH: The certificate or an intermediate does not match the intended purpose (extended key usage).
+ * @GNUTLS_CERT_MISSING_OCSP_STATUS: The certificate requires the server to send the certifiate status, but no status was received.
*
* Enumeration of certificate status codes. Note that the status
* bits may have different meanings in OpenPGP keys and X.509
GNUTLS_CERT_REVOCATION_DATA_ISSUED_IN_FUTURE = 1 << 15,
GNUTLS_CERT_SIGNER_CONSTRAINTS_FAILURE = 1 << 16,
GNUTLS_CERT_MISMATCH = 1 << 17,
- GNUTLS_CERT_PURPOSE_MISMATCH = 1 << 18
+ GNUTLS_CERT_PURPOSE_MISMATCH = 1 << 18,
+ GNUTLS_CERT_MISSING_OCSP_STATUS = 1 << 19
} gnutls_certificate_status_t;
/**
#include "gnutls_int.h"
#include "auth.h"
#include "errors.h"
+#include "extensions.h"
#include <auth/cert.h>
#include "dh.h"
#include "num.h"
} \
gnutls_free( peer_certificate_list)
+#ifdef ENABLE_OCSP
+static int
+_gnutls_ocsp_verify_mandatory_stapling(gnutls_session_t session,
+ gnutls_x509_crt_t cert,
+ unsigned int * ocsp_status)
+{
+ gnutls_x509_tlsfeatures_t tlsfeatures;
+ int i, ret;
+ unsigned feature;
+
+ /* RFC 7633: If cert has TLS feature GNUTLS_EXTENSION_STATUS_REQUEST, stapling is mandatory.
+ *
+ * At this point, we know that we did not get the certificate status.
+ *
+ * To proceed, first check whether we have requested the certificate status
+ */
+ if (_gnutls_extension_list_check(session, GNUTLS_EXTENSION_STATUS_REQUEST) < 0) {
+ return 0;
+ }
+
+ /* We have requested the status, now check whether the certificate mandates a response */
+ if (gnutls_x509_crt_get_tlsfeatures(cert, &tlsfeatures) == 0) {
+ for (i = 0;; ++i) {
+ ret = gnutls_x509_tlsfeatures_get(tlsfeatures, i, &feature);
+ if (ret == GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE) {
+ break;
+ }
+
+ if (ret < 0) {
+ gnutls_assert();
+ gnutls_x509_tlsfeatures_deinit(tlsfeatures);
+ return ret;
+ }
+ if (feature == GNUTLS_EXTENSION_STATUS_REQUEST) {
+ /* We sent a status request, the certificate mandates a reply, but we did not get any. */
+ *ocsp_status |= GNUTLS_CERT_MISSING_OCSP_STATUS;
+ break;
+ }
+ }
+ gnutls_x509_tlsfeatures_deinit(tlsfeatures);
+ }
+
+ return 0;
+}
+#endif
+
/*-
* _gnutls_x509_cert_verify_peers - return the peer's certificate status
* @session: is a gnutls session
goto skip_ocsp;
ret = gnutls_ocsp_status_request_get(session, &resp);
- if (ret < 0)
+ if (ret < 0) {
+ ret = _gnutls_ocsp_verify_mandatory_stapling(session, peer_certificate_list[0], &ocsp_status);
+ if (ret < 0) {
+ gnutls_assert();
+ CLEAR_CERTS;
+ return ret;
+ }
+
goto skip_ocsp;
+ }
if (peer_certificate_list_size > 1) {
issuer = peer_certificate_list[1];