MINOR: ssl: Accept certpath as param in "show ssl ocsp-response" CLI command

In order to increase usability, the "show ssl ocsp-response" also takes
a frontend certificate path as parameter. In such a case, it behaves the
same way as "show ssl cert foo.pem.ocsp".
diff --git a/doc/management.txt b/doc/management.txt
index 008f2b0..022348e 100644
--- a/doc/management.txt
+++ b/doc/management.txt
@@ -3432,16 +3432,17 @@
     ecdsa.pem:3 [verify none allow-0rtt ssl-min-ver TLSv1.0 ssl-max-ver TLSv1.3] localhost !www.test1.com
     ecdsa.pem:4 [verify none allow-0rtt ssl-min-ver TLSv1.0 ssl-max-ver TLSv1.3]
 
-show ssl ocsp-response [[text|base64] <id>]
+show ssl ocsp-response [[text|base64] <id|path>]
   Display the IDs of the OCSP tree entries corresponding to all the OCSP
   responses used in HAProxy, as well as the issuer's name and key hash and the
-  serial number of the certificate for which the OCSP response was built.  If a
-  valid <id> is provided, display the contents of the corresponding OCSP
-  response. When an <id> is provided, it it possible to format in which the
-  data is dumped. The 'text' option is the default one and it allows to display
-  detailed information about the OCSP response the same way as in an "openssl
-  ocsp -respin <ocsp-response> -text" call. The 'base64' format allows to dump
-  the contents of an OCSP response in base64.
+  serial number of the certificate for which the OCSP response was built.
+  If a valid <id> or the <path> of a valid frontend certificate is provided,
+  display the contents of the corresponding OCSP response. When an <id> is
+  provided, it it possible to define the format in which the data is dumped.
+  The 'text' option is the default one and it allows to display detailed
+  information about the OCSP response the same way as in an "openssl ocsp
+  -respin <ocsp-response> -text" call. The 'base64' format allows to dump the
+  contents of an OCSP response in base64.
 
   Example :
 
@@ -3471,7 +3472,7 @@
       Next Update: Oct 12 15:43:38 2048 GMT
       [...]
 
-    $ echo "show ssl ocsp-response base64 304b300906052b0e03021a0500041448dac[...]" | socat /var/run/haproxy.sock -
+    $ echo "show ssl ocsp-response base64 /path_to_cert/foo.pem" | socat /var/run/haproxy.sock -
       MIIB8woBAKCCAewwggHoBgkrBgEFBQcwAQEEggHZMIIB1TCBvqE[...]
 
 show ssl ocsp-updates
diff --git a/reg-tests/ssl/show_ssl_ocspresponse.vtc b/reg-tests/ssl/show_ssl_ocspresponse.vtc
index 3d67fe5..6c1a6b2 100644
--- a/reg-tests/ssl/show_ssl_ocspresponse.vtc
+++ b/reg-tests/ssl/show_ssl_ocspresponse.vtc
@@ -64,6 +64,14 @@
     expect ~ "Cert Status: good"
 }
 
+# Test the "show ssl ocsp-response" command with a certificate path as parameter
+shell {
+    ocsp_response=$(echo "show ssl ocsp-response ${testdir}/show_ocsp_server.pem" | socat "${tmpdir}/h1/stats" -)
+
+    echo "$ocsp_response" | grep "Responder Id: C = FR, O = HAProxy Technologies, CN = ocsp.haproxy.com" &&
+    echo "$ocsp_response" | grep "Cert Status: good"
+}
+
 # Test the "show ssl cert foo.pem.ocsp" command
 haproxy h1 -cli {
     send "show ssl cert"
diff --git a/src/ssl_ocsp.c b/src/ssl_ocsp.c
index 14fb7e9..17d217e 100644
--- a/src/ssl_ocsp.c
+++ b/src/ssl_ocsp.c
@@ -1464,31 +1464,52 @@
 #if ((defined SSL_CTRL_SET_TLSEXT_STATUS_REQ_CB && !defined OPENSSL_NO_OCSP) && !defined OPENSSL_IS_BORINGSSL)
 
 	struct show_ocspresp_cli_ctx *ctx = applet_reserve_svcctx(appctx, sizeof(*ctx));
-	int certid_arg_idx = 3;
+	int arg_idx = 3;
 
 	if (*args[3]) {
 		struct certificate_ocsp *ocsp = NULL;
 		char key[OCSP_MAX_CERTID_ASN1_LENGTH] = {};
 		int key_length = OCSP_MAX_CERTID_ASN1_LENGTH;
 		char *key_ptr = key;
+		unsigned char *p;
+		struct ckch_store *ckch_store = NULL;
 
 		if (strcmp(args[3], "text") == 0) {
 			ctx->format = SHOW_OCSPRESP_FMT_TEXT;
-			++certid_arg_idx;
+			++arg_idx;
 		} else if (strcmp(args[3], "base64") == 0) {
 			ctx->format = SHOW_OCSPRESP_FMT_B64;
-			++certid_arg_idx;
+			++arg_idx;
 		}
 
-		if (ctx->format != SHOW_OCSPRESP_FMT_DFLT && !*args[certid_arg_idx])
+		if (ctx->format != SHOW_OCSPRESP_FMT_DFLT && !*args[arg_idx])
 			return cli_err(appctx, "'show ssl ocsp-response [text|base64]' expects a valid certid.\n");
 
-		if (strlen(args[certid_arg_idx]) > OCSP_MAX_CERTID_ASN1_LENGTH*2) {
-			return cli_err(appctx, "'show ssl ocsp-response' received a too big key.\n");
+		/* Try to convert parameter into an OCSP certid first, and consider it
+		 * as a filename if it fails. */
+		if (strlen(args[arg_idx]) > OCSP_MAX_CERTID_ASN1_LENGTH*2 ||
+		    !parse_binary(args[arg_idx], &key_ptr, &key_length, NULL)) {
+
+			key_ptr = key;
+			key_length = 0;
+
+			/* The operations on the CKCH architecture are locked so we can
+			 * manipulate ckch_store and ckch_inst */
+			if (HA_SPIN_TRYLOCK(CKCH_LOCK, &ckch_lock)) {
+				return cli_err(appctx, "Operations on certificates are currently locked!\n");
+			}
+
+			ckch_store = ckchs_lookup(args[arg_idx]);
+
+			if (ckch_store) {
+				p = (unsigned char*)key;
+				key_length = i2d_OCSP_CERTID(ckch_store->data->ocsp_cid, &p);
+			}
+			HA_SPIN_UNLOCK(CKCH_LOCK, &ckch_lock);
 		}
 
-		if (!parse_binary(args[certid_arg_idx], &key_ptr, &key_length, NULL)) {
-			return cli_err(appctx, "'show ssl ocsp-response' received an invalid key.\n");
+		if (key_length == 0) {
+			return cli_err(appctx, "'show ssl ocsp-response' expects a valid certid or certificate path.\n");
 		}
 
 		HA_SPIN_LOCK(OCSP_LOCK, &ocsp_tree_lock);
@@ -1496,7 +1517,7 @@
 
 		if (!ocsp) {
 			HA_SPIN_UNLOCK(OCSP_LOCK, &ocsp_tree_lock);
-			return cli_err(appctx, "Certificate ID does not match any certificate.\n");
+			return cli_err(appctx, "Certificate ID or path does not match any certificate.\n");
 		}
 		++ocsp->refcount;
 		HA_SPIN_UNLOCK(OCSP_LOCK, &ocsp_tree_lock);