diff options
author | Nikos Mavrogiannopoulos <nmav@redhat.com> | 2017-12-07 16:16:55 +0100 |
---|---|---|
committer | Nikos Mavrogiannopoulos <nmav@redhat.com> | 2018-02-19 15:29:37 +0100 |
commit | 1e919486f4f191e372f451f6518f7b93dd19bf22 (patch) | |
tree | b66e38317dfcf41d241f5159c711753881fc5a10 /lib/ocsp-api.c | |
parent | 92536334518011245095c352ec368da96dc421f7 (diff) | |
download | gnutls-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.c | 93 |
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; } /** |