summaryrefslogtreecommitdiff
path: root/lib/ocsp-api.c
diff options
context:
space:
mode:
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;
}
/**