summaryrefslogtreecommitdiff
path: root/lib/ocsp-api.c
diff options
context:
space:
mode:
authorNikos Mavrogiannopoulos <nmav@redhat.com>2017-12-07 16:16:55 +0100
committerNikos Mavrogiannopoulos <nmav@redhat.com>2018-02-19 15:29:37 +0100
commit1e919486f4f191e372f451f6518f7b93dd19bf22 (patch)
treeb66e38317dfcf41d241f5159c711753881fc5a10 /lib/ocsp-api.c
parent92536334518011245095c352ec368da96dc421f7 (diff)
downloadgnutls-1e919486f4f191e372f451f6518f7b93dd19bf22.tar.gz
gnutls_certificate_set_ocsp_status_request_file: match input response to certificates
That is, iterate through the certificate chain to figure to which certificate the response corresponds to, and assign it to it. That allows for applications to re-use this function to set multiple responses when available. Signed-off-by: Nikos Mavrogiannopoulos <nmav@redhat.com>
Diffstat (limited to 'lib/ocsp-api.c')
-rw-r--r--lib/ocsp-api.c93
1 files changed, 81 insertions, 12 deletions
diff --git a/lib/ocsp-api.c b/lib/ocsp-api.c
index b7604f789e..1150bd4b84 100644
--- a/lib/ocsp-api.c
+++ b/lib/ocsp-api.c
@@ -30,9 +30,12 @@
#include <auth.h>
#include <auth/cert.h>
#include <handshake.h>
+#include <minmax.h>
#ifdef ENABLE_OCSP
+#include <gnutls/ocsp.h>
+
/**
* gnutls_ocsp_status_request_get:
* @session: is a #gnutls_session_t type.
@@ -184,17 +187,33 @@ gnutls_certificate_set_ocsp_status_request_function2
return 0;
}
-static int file_ocsp_func(gnutls_session_t session, void *ptr,
- gnutls_datum_t * ocsp_response)
+static
+unsigned resp_matches_pcert(gnutls_ocsp_resp_t resp, const gnutls_pcert_st *cert)
{
+ gnutls_x509_crt_t crt;
int ret;
- const char *file = ptr;
+ unsigned retval;
- ret = gnutls_load_file(file, ocsp_response);
+ ret = gnutls_x509_crt_init(&crt);
if (ret < 0)
- return gnutls_assert_val(GNUTLS_E_NO_CERTIFICATE_STATUS);
+ return 0;
- return 0;
+ ret = gnutls_x509_crt_import(crt, &cert->cert, GNUTLS_X509_FMT_DER);
+ if (ret < 0) {
+ gnutls_assert();
+ retval = 0;
+ goto cleanup;
+ }
+
+ ret = gnutls_ocsp_resp_check_crt(resp, 0, crt);
+ if (ret == 0)
+ retval = 1;
+ else
+ retval = 0;
+
+ cleanup:
+ gnutls_x509_crt_deinit(crt);
+ return retval;
}
/**
@@ -218,6 +237,11 @@ static int file_ocsp_func(gnutls_session_t session, void *ptr,
* with the %GNUTLS_CERTIFICATE_API_V2 flag to make the set certificate
* functions return an index usable by this function.
*
+ * This function can be called multiple times since GnuTLS 3.6.xx
+ * when multiple responses which apply to the chain are available.
+ * If the response provided does not match any certificates present
+ * in the chain, the code %GNUTLS_E_OCSP_MISMATCH_WITH_CERTS is returned.
+ *
* Returns: On success, %GNUTLS_E_SUCCESS (0) is returned,
* otherwise a negative error code is returned.
*
@@ -228,17 +252,62 @@ gnutls_certificate_set_ocsp_status_request_file(gnutls_certificate_credentials_t
const char *response_file,
unsigned idx)
{
+ unsigned i, found = 0;
+ gnutls_datum_t der = {NULL, 0};
+ gnutls_ocsp_resp_t resp = NULL;
+ int ret;
+
if (idx >= sc->ncerts)
return gnutls_assert_val(GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE);
- gnutls_free(sc->certs[idx].ocsp_response_file);
- sc->certs[idx].ocsp_response_file = gnutls_strdup(response_file);
- if (sc->certs[idx].ocsp_response_file == NULL)
- return gnutls_assert_val(GNUTLS_E_MEMORY_ERROR);
+ ret = gnutls_load_file(response_file, &der);
+ if (ret < 0)
+ return gnutls_assert_val(GNUTLS_E_FILE_ERROR);
+
+ ret = gnutls_ocsp_resp_init(&resp);
+ if (ret < 0) {
+ gnutls_assert();
+ goto cleanup;
+ }
- gnutls_certificate_set_ocsp_status_request_function2(sc, idx, file_ocsp_func, sc->certs[idx].ocsp_response_file);
+ ret = gnutls_ocsp_resp_import(resp, &der);
+ if (ret < 0) {
+ gnutls_assert();
+ goto cleanup;
+ }
- return 0;
+ /* iterate through all certificates in chain, and add the response
+ * to the certificate that it matches with.
+ */
+ for (i=0;i<MIN(sc->certs[idx].cert_list_length, MAX_OCSP_RESPONSES);i++) {
+ if (sc->certs[idx].ocsp_responses[i].data)
+ continue;
+
+ if (!resp_matches_pcert(resp, &sc->certs[idx].cert_list[i]))
+ continue;
+
+ _gnutls_debug_log("associating OCSP response with chain %d on pos %d\n", idx, i);
+
+ sc->certs[idx].ocsp_responses[i].data = der.data;
+ der.data = NULL;
+ sc->certs[idx].ocsp_responses[i].size = der.size;
+
+ if (sc->certs[idx].ocsp_responses_length <= i)
+ sc->certs[idx].ocsp_responses_length = i+1;
+
+ found = 1;
+ break;
+ }
+
+ if (!found)
+ ret = GNUTLS_E_OCSP_MISMATCH_WITH_CERTS;
+ else
+ ret = 0;
+ cleanup:
+ gnutls_free(der.data);
+ if (resp)
+ gnutls_ocsp_resp_deinit(resp);
+ return ret;
}
/**