diff options
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; } /** |