diff options
author | Fiona Klute <fiona.klute@gmx.de> | 2020-02-08 23:47:17 +0100 |
---|---|---|
committer | Fiona Klute <fiona.klute@gmx.de> | 2020-02-08 23:54:52 +0100 |
commit | dd423bcb67c02d6d89090705b1b3dfc1999dd296 (patch) | |
tree | 8b9c7325ada69a0ce60ff4b2ab30c8233b14ab0d /src | |
parent | d9bc5bfc8da34da664413f683debc097f170eb99 (diff) | |
download | gnutls-dd423bcb67c02d6d89090705b1b3dfc1999dd296.tar.gz |
gnutls-cli: Add option to store all stapled OCSP responses
Note that there's a small modification to the behavior of the existing
--ocsp-save option: If there is no stapled OCSP response the output
file is still created and will be empty.
Signed-off-by: Fiona Klute <fiona.klute@gmx.de>
Diffstat (limited to 'src')
-rw-r--r-- | src/cli-args.def | 11 | ||||
-rw-r--r-- | src/cli.c | 96 |
2 files changed, 91 insertions, 16 deletions
diff --git a/src/cli-args.def b/src/cli-args.def index 12b8bb05db..a8760fab90 100644 --- a/src/cli-args.def +++ b/src/cli-args.def @@ -172,7 +172,16 @@ flag = { name = save-ocsp; arg-type = string; descrip = "Save the peer's OCSP status response in the provided file"; - doc = ""; + doc = ""; + flags-cant = save-ocsp-multi; +}; + +flag = { + name = save-ocsp-multi; + arg-type = string; + descrip = "Save all OCSP responses provided by the peer in this file"; + doc = "The file will contain a list of PEM encoded OCSP status responses if any were provided by the peer, starting with the one for the peer's server certificate."; + flags-cant = save-ocsp; }; flag = { @@ -358,6 +358,84 @@ static void try_save_cert(gnutls_session_t session) return; } +static void try_save_ocsp_status(gnutls_session_t session) +{ + unsigned int cert_num = 0; + gnutls_certificate_get_peers(session, &cert_num); + if (cert_num == 0) { + fprintf(stderr, "no certificates sent by server, so can't get OCSP status!\n"); + return; + } + + const char *path; + gnutls_x509_crt_fmt_t type; + unsigned int max_out; + + /* This function is called if exactly one of SAVE_OCSP and + * SAVE_OCSP_MULTI is set. */ + if (HAVE_OPT(SAVE_OCSP)) + { + path = OPT_ARG(SAVE_OCSP); + type = GNUTLS_X509_FMT_DER; + max_out = 1; + } else { + path = OPT_ARG(SAVE_OCSP_MULTI); + type = GNUTLS_X509_FMT_PEM; + max_out = cert_num; + } + + FILE *fp = fopen(path, "w"); + if (fp == NULL) { + fprintf(stderr, "could not open %s for writing\n", path); + exit(1); + } + + for (unsigned int i = 0; i < max_out; i++) { + gnutls_datum_t oresp; + int ret = gnutls_ocsp_status_request_get2(session, i, &oresp); + if (ret == GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE) { + fprintf(stderr, "no OCSP response for certificate %u\n", i); + continue; + } else if (ret < 0) { + fprintf(stderr, "error getting OCSP response %u: %s\n", + i, gnutls_strerror(ret)); + exit(1); + } + + if (type == GNUTLS_X509_FMT_DER) { + /* on success the return value is equal to the + * number of items (third parameter) */ + if (fwrite(oresp.data, oresp.size, 1, fp) != 1) { + fprintf(stderr, "writing to %s failed\n", path); + exit(1); + } + continue; + } + + gnutls_datum_t t; + ret = gnutls_pem_base64_encode_alloc("OCSP RESPONSE", + &oresp, &t); + if (ret < 0) { + fprintf(stderr, "error allocating PEM OCSP response: %s\n", + gnutls_strerror(ret)); + exit(1); + } + + /* on success the return value is equal to the number + * of items (third parameter) */ + if (fwrite(t.data, t.size, 1, fp) != 1) { + fprintf(stderr, "writing to %s failed\n", path); + exit(1); + } + gnutls_free(t.data); + } + if (fclose(fp) != 0) { + perror("failed to close OCSP save file"); + } + + return; +} + static int cert_verify_callback(gnutls_session_t session) { int rc; @@ -367,7 +445,6 @@ static int cert_verify_callback(gnutls_session_t session) int dane = ENABLED_OPT(DANE); int ca_verify = ENABLED_OPT(CA_VERIFICATION); const char *txt_service; - gnutls_datum_t oresp; const char *host; /* On an session with TOFU the PKI/DANE verification @@ -390,23 +467,12 @@ static int cert_verify_callback(gnutls_session_t session) } #ifndef ENABLE_OCSP - if (HAVE_OPT(SAVE_OCSP) || HAVE_OPT(OCSP)) { + if (HAVE_OPT(SAVE_OCSP_MULTI) || HAVE_OPT(SAVE_OCSP) || HAVE_OPT(OCSP)) { fprintf(stderr, "OCSP is not supported!\n"); } #else - rc = gnutls_ocsp_status_request_get(session, &oresp); - if (rc < 0) { - oresp.data = NULL; - oresp.size = 0; - } - - if (HAVE_OPT(SAVE_OCSP) && oresp.data) { - FILE *fp = fopen(OPT_ARG(SAVE_OCSP), "w"); - - if (fp != NULL) { - fwrite(oresp.data, 1, oresp.size, fp); - fclose(fp); - } + if (HAVE_OPT(SAVE_OCSP_MULTI) || HAVE_OPT(SAVE_OCSP)) { + try_save_ocsp_status(session); } #endif |