cert_list[0],
cred->certs[indx].
cert_list_length,
- NULL, 0,
+ cred->certs[indx].ocsp_responses,
+ cred->certs[indx].ocsp_responses_length,
cred->certs[indx].pkey, 0,
NULL, 0);
} else {
*/
finished:
if (idx >= 0) {
- selected_certs_set(session,
- &cred->certs[idx].cert_list[0],
- cred->certs[idx].cert_list_length,
- NULL, 0,
- cred->certs[idx].pkey, 0,
- cred->certs[idx].ocsp_func,
- cred->certs[idx].ocsp_func_ptr);
+ if (cred->certs[idx].ocsp_func) {
+ selected_certs_set(session,
+ &cred->certs[idx].cert_list[0],
+ cred->certs[idx].cert_list_length,
+ NULL, 0,
+ cred->certs[idx].pkey, 0,
+ cred->certs[idx].ocsp_func,
+ cred->certs[idx].ocsp_func_ptr);
+ } else {
+ selected_certs_set(session,
+ &cred->certs[idx].cert_list[0],
+ cred->certs[idx].cert_list_length,
+ &cred->certs[idx].ocsp_responses[0],
+ cred->certs[idx].ocsp_responses_length,
+ cred->certs[idx].pkey, 0,
+ NULL, NULL);
+ }
} else {
gnutls_assert();
/* Certificate does not support REQUESTED_ALGO. */
#include <gnutls/compat.h>
#include <str_array.h>
+#define MAX_OCSP_RESPONSES 8
+
typedef struct {
gnutls_pcert_st *cert_list; /* a certificate chain */
unsigned int cert_list_length; /* its length */
gnutls_status_request_ocsp_func ocsp_func;
void *ocsp_func_ptr; /* corresponding OCSP response function + ptr */
- char *ocsp_response_file; /* corresponding OCSP response file */
+ gnutls_datum_t ocsp_responses[MAX_OCSP_RESPONSES]; /* corresponding OCSP response file */
+ unsigned int ocsp_responses_length;
/* the private key corresponding to certificate */
gnutls_privkey_t pkey;
gnutls_pcert_deinit(&sc->certs[i].cert_list[j]);
}
gnutls_free(sc->certs[i].cert_list);
- gnutls_free(sc->certs[i].ocsp_response_file);
+
+ for (j = 0; j < sc->certs[i].ocsp_responses_length; j++) {
+ gnutls_free(sc->certs[i].ocsp_responses[j].data);
+ sc->certs[i].ocsp_responses[j].data = NULL;
+ }
_gnutls_str_array_clear(&sc->certs[i].names);
gnutls_privkey_deinit(sc->certs[i].pkey);
}
GNUTLS_E_CERTIFICATE_LIST_UNSORTED),
ERROR_ENTRY(N_("The OCSP response is invalid"),
GNUTLS_E_OCSP_RESPONSE_ERROR),
+ ERROR_ENTRY(N_("The OCSP response provided doesn't match the available certificates"),
+ GNUTLS_E_OCSP_MISMATCH_WITH_CERTS),
ERROR_ENTRY(N_("There is no certificate status (OCSP)."),
GNUTLS_E_NO_CERTIFICATE_STATUS),
ERROR_ENTRY(N_("Error in the system's randomness device."),
#define GNUTLS_E_INCOMPATIBLE_SIG_WITH_KEY -419
#define GNUTLS_E_PK_INVALID_PUBKEY_PARAMS -420
#define GNUTLS_E_PK_NO_VALIDATION_PARAMS -421
+#define GNUTLS_E_OCSP_MISMATCH_WITH_CERTS -422
#define GNUTLS_E_NO_COMMON_KEY_SHARE -423
#define GNUTLS_E_REAUTH_REQUEST -424
#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.
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;
}
/**
* 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.
*
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;
}
/**