MEDIUM: ssl: basic OCSP stapling support.
The support is all based on static responses. This doesn't add any
request / response logic to HAProxy, but allows a way to update
information through the socket interface.
Currently certificates specified using "crt" or "crt-list" on "bind" lines
are loaded as PEM files.
For each PEM file, haproxy checks for the presence of file at the same path
suffixed by ".ocsp". If such file is found, support for the TLS Certificate
Status Request extension (also known as "OCSP stapling") is automatically
enabled. The content of this file is optional. If not empty, it must contain
a valid OCSP Response in DER format. In order to be valid an OCSP Response
must comply with the following rules: it has to indicate a good status,
it has to be a single response for the certificate of the PEM file, and it
has to be valid at the moment of addition. If these rules are not respected
the OCSP Response is ignored and a warning is emitted. In order to identify
which certificate an OCSP Response applies to, the issuer's certificate is
necessary. If the issuer's certificate is not found in the PEM file, it will
be loaded from a file at the same path as the PEM file suffixed by ".issuer"
if it exists otherwise it will fail with an error.
It is possible to update an OCSP Response from the unix socket using:
set ssl ocsp-response <response>
This command is used to update an OCSP Response for a certificate (see "crt"
on "bind" lines). Same controls are performed as during the initial loading of
the response. The <response> must be passed as a base64 encoded string of the
DER encoded response from the OCSP server.
Example:
openssl ocsp -issuer issuer.pem -cert server.pem \
-host ocsp.issuer.com:80 -respout resp.der
echo "set ssl ocsp-response $(base64 -w 10000 resp.der)" | \
socat stdio /var/run/haproxy.stat
This feature is automatically enabled on openssl 0.9.8h and above.
This work was performed jointly by Dirkjan Bussink of GitHub and
Emeric Brun of HAProxy Technologies.
diff --git a/src/dumpstats.c b/src/dumpstats.c
index bc0bea7..36b4684 100644
--- a/src/dumpstats.c
+++ b/src/dumpstats.c
@@ -35,6 +35,7 @@
#include <common/time.h>
#include <common/uri_auth.h>
#include <common/version.h>
+#include <common/base64.h>
#include <types/global.h>
@@ -195,6 +196,7 @@
" add map : add map entry\n"
" del map : delete map entry\n"
" clear map <id> : clear the content of this map\n"
+ " set ssl <stmt> : set statement for ssl\n"
"";
static const char stats_permission_denied_msg[] =
@@ -1789,6 +1791,50 @@
appctx->st0 = STAT_CLI_PRINT;
return 1;
}
+#ifdef USE_OPENSSL
+ else if (strcmp(args[1], "ssl") == 0) {
+ if (strcmp(args[2], "ocsp-response") == 0) {
+#ifdef SSL_CTRL_SET_TLSEXT_STATUS_REQ_CB
+ char *err = NULL;
+
+ /* Expect two parameters: certificate file name and the new response in base64 encoding */
+ if (!*args[3]) {
+ appctx->ctx.cli.msg = "'set ssl ocsp-response' expects response in base64 encoding.\n";
+ appctx->st0 = STAT_CLI_PRINT;
+ return 1;
+ }
+
+ trash.len = base64dec(args[3], strlen(args[3]), trash.str, trash.size);
+ if (trash.len < 0) {
+ appctx->ctx.cli.msg = "'set ssl ocsp-response' received invalid base64 encoded response.\n";
+ appctx->st0 = STAT_CLI_PRINT;
+ return 1;
+ }
+
+ if (ssl_sock_update_ocsp_response(&trash, &err)) {
+ if (err) {
+ memprintf(&err, "%s.\n", err);
+ appctx->ctx.cli.err = err;
+ appctx->st0 = STAT_CLI_PRINT_FREE;
+ }
+ return 1;
+ }
+ appctx->ctx.cli.msg = "OCSP Response updated!";
+ appctx->st0 = STAT_CLI_PRINT;
+ return 1;
+#else
+ appctx->ctx.cli.msg = "HAProxy was compiled against a version of OpenSSL that doesn't support OCSP stapling.\n";
+ appctx->st0 = STAT_CLI_PRINT;
+ return 1;
+#endif
+ }
+ else {
+ appctx->ctx.cli.msg = "'set ssl' only supports 'ocsp-response'.\n";
+ appctx->st0 = STAT_CLI_PRINT;
+ return 1;
+ }
+ }
+#endif
else { /* unknown "set" parameter */
return 0;
}