summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorFiona Klute <fiona.klute@gmx.de>2020-02-08 23:47:17 +0100
committerFiona Klute <fiona.klute@gmx.de>2020-02-08 23:54:52 +0100
commitdd423bcb67c02d6d89090705b1b3dfc1999dd296 (patch)
tree8b9c7325ada69a0ce60ff4b2ab30c8233b14ab0d /src
parentd9bc5bfc8da34da664413f683debc097f170eb99 (diff)
downloadgnutls-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.def11
-rw-r--r--src/cli.c96
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 = {
diff --git a/src/cli.c b/src/cli.c
index f02f842b71..db072b9303 100644
--- a/src/cli.c
+++ b/src/cli.c
@@ -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