MINOR: ssl: Add helper function that checks the validity of an OCSP response
This helper function will check that an OCSP response is valid, meaning
that the proper "Content-Type: application/ocsp-response" header is
present and the data itself is a proper OCSP_RESPONSE that can be
checked thanks to the issuer certificate.
diff --git a/include/haproxy/ssl_sock.h b/include/haproxy/ssl_sock.h
index 1c48c14..16428e8 100644
--- a/include/haproxy/ssl_sock.h
+++ b/include/haproxy/ssl_sock.h
@@ -90,6 +90,8 @@
int ssl_ocsp_get_uri_from_cert(X509 *cert, struct buffer *out, char **err);
int ssl_ocsp_create_request_details(const OCSP_CERTID *certid, struct buffer *req_url,
struct buffer *req_body, char **err);
+int ssl_ocsp_check_response(STACK_OF(X509) *chain, X509 *issuer,
+ struct buffer *respbuf, char **err);
#endif
#if (defined SSL_CTRL_SET_TLSEXT_TICKET_KEY_CB && TLS_TICKETS_NO > 0)
int ssl_sock_update_tlskey_ref(struct tls_keys_ref *ref,
diff --git a/src/ssl_sock.c b/src/ssl_sock.c
index c9de250..44f515c 100644
--- a/src/ssl_sock.c
+++ b/src/ssl_sock.c
@@ -1248,6 +1248,72 @@
return errcode;
}
+/*
+ * Parse an OCSP_RESPONSE contained in <respbuf> and check its validity in
+ * regard to the contents of <ckch> or the <issuer> certificate.
+ * Certificate_ocsp structure does not keep a reference to the corresponding
+ * ckch_store so outside of a CLI context (see "send ssl ocsp-response"
+ * command), we only have an easy access to the issuer's certificate whose
+ * reference is held in the structure.
+ * Return 0 in case of success, 1 otherwise.
+ */
+int ssl_ocsp_check_response(STACK_OF(X509) *chain, X509 *issuer,
+ struct buffer *respbuf, char **err)
+{
+ int ret = 1;
+ int n;
+ OCSP_RESPONSE *response = NULL;
+ OCSP_BASICRESP *basic = NULL;
+ X509_STORE *store = NULL;
+ const unsigned char *start = (const unsigned char*)b_orig(respbuf);
+
+ if (!chain && !issuer) {
+ memprintf(err, "check_ocsp_response needs a certificate validation chain or an issuer certificate");
+ goto end;
+ }
+
+ response = d2i_OCSP_RESPONSE(NULL, &start, b_data(respbuf));
+ if (!response) {
+ memprintf(err, "d2i_OCSP_RESPONSE() failed");
+ goto end;
+ }
+
+ n = OCSP_response_status(response);
+
+ if (n != OCSP_RESPONSE_STATUS_SUCCESSFUL) {
+ memprintf(err, "OCSP response not successful (%d: %s)",
+ n, OCSP_response_status_str(n));
+ goto end;
+ }
+
+ basic = OCSP_response_get1_basic(response);
+ if (basic == NULL) {
+ memprintf(err, "OCSP_response_get1_basic() failed");
+ goto end;
+ }
+
+ /* Add ocsp issuer certificate to a store in order verify the ocsp
+ * response. */
+ store = X509_STORE_new();
+ if (!store) {
+ memprintf(err, "X509_STORE_new() failed");
+ goto end;
+ }
+ X509_STORE_add_cert(store, issuer);
+
+ if (OCSP_basic_verify(basic, chain, store, 0) != 1) {
+ memprintf(err, "OCSP_basic_verify() failed");
+ goto end;
+ }
+
+ ret = 0;
+
+end:
+ X509_STORE_free(store);
+ OCSP_RESPONSE_free(response);
+ OCSP_BASICRESP_free(basic);
+ return ret;
+}
#endif /* defined SSL_CTRL_SET_TLSEXT_STATUS_REQ_CB && !defined OPENSSL_NO_OCSP */
/*