diff --git a/doc/management.txt b/doc/management.txt index 7586affe3..1fa7d6cb5 100644 --- a/doc/management.txt +++ b/doc/management.txt @@ -3468,6 +3468,37 @@ show ssl ocsp-response [] Next Update: Oct 12 15:43:38 2048 GMT [...] +show ssl ocsp-updates + Display information about the entries concerned by the OCSP update mechanism. + The command will output one line per OCSP response and will contain the + expected update time of the response as well as the time of the last + successful update and counters of successful and failed updates. It will also + give the status of the last update (successful or not) in numerical form as + well as text form. See below for a full list of possible errors. The lines + will be sorted by ascending 'Next Update' time. The lines will also contain a + path to the first frontend certificate that uses the OCSP response. + See "show ssl ocsp-response" command and "ocsp-update" option for more + information on the OCSP auto update. + + The update error codes and error strings can be the following: + + +----+-------------------------------------+ + | ID | message | + +----+-------------------------------------+ + | 0 | "Unknown" | + | 1 | "Update successful" | + | 2 | "HTTP error" | + | 3 | "Missing \"ocsp-response\" header" | + | 4 | "OCSP response check failure" | + | 5 | "Error during insertion" | + +----+-------------------------------------+ + + Example : + $ echo "show ssl ocsp-updates" | socat /tmp/haproxy.sock - + OCSP Certid | Path | Next Update | Last Update | Successes | Failures | Last Update Status | Last Update Status (str) + 303b300906052b0e03021a050004148a83e0060faff709ca7e9b95522a2e81635fda0a0414f652b0e435d5ea923851508f0adbe92d85de007a02021015 | /path_to_cert/cert.pem | 30/Jan/2023:00:08:09 +0000 | - | 0 | 1 | 2 | HTTP error + 304b300906052b0e03021a0500041448dac9a0fb2bd32d4ff0de68d2f567b735f9b3c40414142eb317b75856cbae500940e61faf9d8b14c2c6021203e16a7aa01542f291237b454a627fdea9c1 | /path_to_cert/other_cert.pem | 30/Jan/2023:01:07:09 +0000 | 30/Jan/2023:00:07:09 +0000 | 1 | 0 | 1 | Update successful + show ssl providers Display the names of the providers loaded by OpenSSL during init. Provider loading can indeed be configured via the OpenSSL configuration file and this diff --git a/src/ssl_ocsp.c b/src/ssl_ocsp.c index e234c7ad6..eaac5f734 100644 --- a/src/ssl_ocsp.c +++ b/src/ssl_ocsp.c @@ -1724,10 +1724,166 @@ int ocsp_update_check_cfg_consistency(struct ckch_store *store, struct crtlist_e return err_code; } +struct show_ocsp_updates_ctx { + struct certificate_ocsp *cur_ocsp; +}; + +/* + * Parsing function for 'show ssl ocsp-updates [nb]'. + */ +static int cli_parse_show_ocsp_updates(char **args, char *payload, struct appctx *appctx, void *private) +{ +#if ((defined SSL_CTRL_SET_TLSEXT_STATUS_REQ_CB && !defined OPENSSL_NO_OCSP) && !defined OPENSSL_IS_BORINGSSL) + struct show_ocsp_updates_ctx *ctx = applet_reserve_svcctx(appctx, sizeof(*ctx)); + + HA_SPIN_LOCK(OCSP_LOCK, &ocsp_tree_lock); + + return 0; +#else + return cli_err(appctx, "HAProxy was compiled against a version of OpenSSL that doesn't support OCSP stapling.\n"); +#endif +} + +/* + * Dump information about an ocsp response concerning ocsp auto update. + * It follows the following format : + * OCSP Certid | Path | Next Update | Last Update | Successes | Failures | Last Update Status | Last Update Status (str) + * Return 0 in case of success. + */ +static int dump_ocsp_update_info(struct certificate_ocsp *ocsp, struct buffer *out) +{ + struct tm tm = {}; + char *ret; + int i; + time_t next_update; + + /* Dump OCSP certid */ + for (i = 0; i < ocsp->key_length; ++i) { + chunk_appendf(out, "%02x", ocsp->key_data[i]); + } + + chunk_appendf(out, " | "); + + /* Dump path */ + chunk_appendf(out, "%s", ocsp->path); + + chunk_appendf(out, " | "); + + /* Dump next update time */ + if (ocsp->next_update.key != 0) { + next_update = ocsp->next_update.key; + get_localtime(ocsp->next_update.key, &tm); + } else { + next_update = date.tv_sec; + get_localtime(date.tv_sec, &tm); + } + ret = localdate2str_log(b_orig(out)+b_data(out), next_update, &tm, b_size(out)-b_data(out)); + + if (ret == NULL) + return 1; + + out->data = (ret - out->area); + + chunk_appendf(out, " | "); + + /* Dump last update time or "-" if no update occurred yet */ + if (ocsp->last_update) { + get_localtime(ocsp->last_update, &tm); + ret = localdate2str_log(b_orig(out)+b_data(out), ocsp->last_update, &tm, b_size(out)-b_data(out)); + + if (ret == NULL) + return 1; + + out->data = (ret - out->area); + } else + chunk_appendf(out, "-"); + + chunk_appendf(out, " | "); + + /* Number of successful updates */ + chunk_appendf(out, "%d", ocsp->num_success); + + chunk_appendf(out, " | "); + + /* Number of failed updates */ + chunk_appendf(out, "%d", ocsp->num_failure); + + chunk_appendf(out, " | "); + + /* Last update status */ + chunk_appendf(out, "%d", ocsp->last_update_status); + + chunk_appendf(out, " | "); + + /* Last update status str */ + if (ocsp->last_update_status >= OCSP_UPDT_ERR_LAST) + chunk_appendf(out, "-"); + else + chunk_appendf(out, "%s", istptr(ocsp_update_errors[ocsp->last_update_status])); + + chunk_appendf(out, "\n"); + + return 0; +} + +static int cli_io_handler_show_ocsp_updates(struct appctx *appctx) +{ + struct show_ocsp_updates_ctx *ctx = appctx->svcctx; + struct eb64_node *node; + struct certificate_ocsp *ocsp = NULL; + struct buffer *trash = get_trash_chunk(); + + if (!ctx->cur_ocsp) { + node = eb64_first(&ocsp_update_tree); + chunk_appendf(trash, "OCSP Certid | Path | Next Update | Last Update | Successes | Failures | Last Update Status | Last Update Status (str)\n"); + + /* Look for an entry currently being updated */ + ocsp = ssl_ocsp_task_ctx.cur_ocsp; + if (ocsp) { + if (dump_ocsp_update_info(ocsp, trash)) + goto end; + } + + if (applet_putchk(appctx, trash) == -1) + goto yield; + + } else { + node = &((struct certificate_ocsp*)ctx->cur_ocsp)->next_update; + } + + while (node) { + ocsp = eb64_entry(node, struct certificate_ocsp, next_update); + + chunk_reset(trash); + if (dump_ocsp_update_info(ocsp, trash)) + goto end; + + if (applet_putchk(appctx, trash) == -1) { + ctx->cur_ocsp = ocsp; + goto yield; + } + + node = eb64_next(node); + } + +end: + return 1; + +yield: + return 0; /* should come back */ +} + +static void cli_release_show_ocsp_updates(struct appctx *appctx) +{ + HA_SPIN_UNLOCK(OCSP_LOCK, &ocsp_tree_lock); +} + + static struct cli_kw_list cli_kws = {{ },{ { { "set", "ssl", "ocsp-response", NULL }, "set ssl ocsp-response : update a certificate's OCSP Response from a base64-encode DER", cli_parse_set_ocspresponse, NULL }, { { "show", "ssl", "ocsp-response", NULL },"show ssl ocsp-response [id] : display the IDs of the OCSP responses used in memory, or the details of a single OCSP response", cli_parse_show_ocspresponse, cli_io_handler_show_ocspresponse, NULL }, + { { "show", "ssl", "ocsp-updates", NULL }, "show ssl ocsp-updates : display information about the next 'nb' ocsp responses that will be updated automatically", cli_parse_show_ocsp_updates, cli_io_handler_show_ocsp_updates, cli_release_show_ocsp_updates }, #if ((defined SSL_CTRL_SET_TLSEXT_STATUS_REQ_CB && !defined OPENSSL_NO_OCSP) && !defined OPENSSL_IS_BORINGSSL) { { "update", "ssl", "ocsp-response", NULL }, "update ssl ocsp-response : send ocsp request and update stored ocsp response", cli_parse_update_ocsp_response, cli_io_handler_update_ocsp_response, cli_release_update_ocsp_response }, #endif