diff options
Diffstat (limited to 'lib/ext/status_request.c')
-rw-r--r-- | lib/ext/status_request.c | 140 |
1 files changed, 119 insertions, 21 deletions
diff --git a/lib/ext/status_request.c b/lib/ext/status_request.c index 1d7d28f70b..85f0f679d9 100644 --- a/lib/ext/status_request.c +++ b/lib/ext/status_request.c @@ -164,28 +164,30 @@ server_send(gnutls_session_t session, { int ret; gnutls_certificate_credentials_t cred; - gnutls_status_request_ocsp_func func; - void *func_ptr; + gnutls_cert_info_st cinfo; cred = (gnutls_certificate_credentials_t) _gnutls_get_cred(session, GNUTLS_CRD_CERTIFICATE); if (cred == NULL) /* no certificate authentication */ return gnutls_assert_val(0); + memset(&cinfo, 0, sizeof(cinfo)); + cinfo.pcert = session->internals.selected_cert_list; + if (session->internals.selected_ocsp_func) { - func = session->internals.selected_ocsp_func; - func_ptr = session->internals.selected_ocsp_func_ptr; + ret = session->internals.selected_ocsp_func(session, + &cinfo, + session->internals.selected_ocsp_func_ptr, + &priv->sresp); } else if (cred->glob_ocsp_func) { - func = cred->glob_ocsp_func; - func_ptr = cred->glob_ocsp_func_ptr; + ret = cred->glob_ocsp_func(session, + &cinfo, + cred->glob_ocsp_func_ptr, + &priv->sresp); } else { return 0; } - if (func == NULL) - return 0; - - ret = func(session, func_ptr, &priv->sresp); if (ret == GNUTLS_E_NO_CERTIFICATE_STATUS) return 0; else if (ret < 0) @@ -362,6 +364,18 @@ gnutls_ocsp_status_request_get2(gnutls_session_t session, return 0; } +static int +legacy_ocsp_func_emu(gnutls_session_t session, const gnutls_cert_info_st *cinfo, + void *ptr, gnutls_datum_t * ocsp_response) +{ + legacy_ocsp_func_st *s = ptr; + + if (cinfo->cert_index == 0) + return s->func(session, s->ptr, ocsp_response); + + return GNUTLS_E_NO_CERTIFICATE_STATUS; +} + /** * gnutls_certificate_set_ocsp_status_request_function: * @sc: is a #gnutls_certificate_credentials_t type. @@ -389,13 +403,15 @@ gnutls_ocsp_status_request_get2(gnutls_session_t session, * Since: 3.1.3 **/ void -gnutls_certificate_set_ocsp_status_request_function -(gnutls_certificate_credentials_t sc, -gnutls_status_request_ocsp_func ocsp_func, void *ptr) +gnutls_certificate_set_ocsp_status_request_function(gnutls_certificate_credentials_t sc, + gnutls_status_request_ocsp_func ocsp_func, + void *ptr) { + sc->glob_ocsp_func = legacy_ocsp_func_emu; + sc->glob_ocsp_func_ptr = &sc->glob_legacy_ocsp; - sc->glob_ocsp_func = ocsp_func; - sc->glob_ocsp_func_ptr = ptr; + sc->glob_legacy_ocsp.func = ocsp_func; + sc->glob_legacy_ocsp.ptr = ptr; } /** @@ -428,30 +444,114 @@ gnutls_status_request_ocsp_func ocsp_func, void *ptr) * with the %GNUTLS_CERTIFICATE_API_V2 flag to make the set certificate * functions return an index usable by this function. * + * This function works with the pre-loaded certificate chains, and + * must be called after they are set. When the certificate chains are + * obtained via a callback, i.e., when gnutls_certificate_set_retrieve_function() + * and friends are used, use gnutls_certificate_set_ocsp_status_request_function3() + * with %GNUTLS_OCSP_CB_GLOBAL_SET flag instead. + * * Returns: On success, %GNUTLS_E_SUCCESS (0) is returned, * otherwise a negative error code is returned. * * Since: 3.5.5 **/ int -gnutls_certificate_set_ocsp_status_request_function2 -(gnutls_certificate_credentials_t sc, unsigned idx, gnutls_status_request_ocsp_func ocsp_func, void *ptr) +gnutls_certificate_set_ocsp_status_request_function2(gnutls_certificate_credentials_t sc, + unsigned idx, + gnutls_status_request_ocsp_func ocsp_func, + void *ptr) { if (idx >= sc->ncerts) return gnutls_assert_val(GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE); + sc->certs[idx].legacy_ocsp.func = ocsp_func; + sc->certs[idx].legacy_ocsp.ptr = ptr; + + return gnutls_certificate_set_ocsp_status_request_function3(sc, idx, + legacy_ocsp_func_emu, + &sc->certs[idx].legacy_ocsp, + 0); +} + +/** + * gnutls_certificate_set_ocsp_status_request_function3: + * @sc: is a #gnutls_certificate_credentials_t type. + * @idx: is a certificate index as returned by gnutls_certificate_set_key() and friends + * @ocsp_func: function pointer to OCSP status request callback. + * @ptr: opaque pointer passed to callback function + * @flags: must be zero + * + * This function is to be used by server to register a callback to + * provide OCSP status requests that correspond to the indexed certificate chain + * from the client. The callback will be invoked if the client supplied a + * status-request OCSP extension. + * + * The callback function prototype is: + * + * typedef int (*gnutls_status_request_ocsp_func2) + * (gnutls_session_t session, const gnutls_cert_info_st *cinfo, void *ptr, gnutls_datum_t *ocsp_resp); + * + * The callback will be invoked if the client requests an OCSP certificate + * status. The callback may return %GNUTLS_E_NO_CERTIFICATE_STATUS, if + * there is no recent OCSP response. If the callback returns %GNUTLS_E_SUCCESS, + * it is expected to have the @ocsp_response field set with a valid (DER-encoded) + * OCSP response. The response must be a value allocated using gnutls_malloc(), + * and will be deinitialized by the caller. + * + * This function allows a server to provide more than a single OCSP responses + * corresponding to each certificate in the certificate chain. + * + * When the flag %GNUTLS_OCSP_CB_GLOBAL_SET is specified in @flags, this + * function can be used to set a callback that is used even when the + * certificates are provided by the application via a callback. That is, + * when gnutls_certificate_set_retrieve_function() and friends are used. + * In that case the callback will be called with the selected certificate. + * + * Note: the ability to set multiple OCSP responses per credential + * structure via the index @idx was added in version 3.5.6. To keep + * backwards compatibility, it requires using gnutls_certificate_set_flags() + * with the %GNUTLS_CERTIFICATE_API_V2 flag to make the set certificate + * functions return an index usable by this function. + * + * Returns: On success, %GNUTLS_E_SUCCESS (0) is returned, + * otherwise a negative error code is returned. + * + * Since: 3.6.xx + **/ +int +gnutls_certificate_set_ocsp_status_request_function3(gnutls_certificate_credentials_t sc, + unsigned idx, + gnutls_status_request_ocsp_func2 ocsp_func, + void *ptr, + unsigned flags) +{ + if (flags & GNUTLS_OCSP_CB_GLOBAL_SET) { + sc->glob_ocsp_func = ocsp_func; + sc->glob_ocsp_func_ptr = ptr; + + return 0; + } + + if (idx >= sc->ncerts) + return gnutls_assert_val(GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE); + sc->certs[idx].ocsp_func = ocsp_func; sc->certs[idx].ocsp_func_ptr = ptr; return 0; } -static int file_ocsp_func(gnutls_session_t session, void *ptr, +static int file_ocsp_func(gnutls_session_t session, + const gnutls_cert_info_st *cinfo, + void *ptr, gnutls_datum_t * ocsp_response) { int ret; const char *file = ptr; + if (cinfo->cert_index > 0) + return GNUTLS_E_NO_CERTIFICATE_STATUS; + ret = gnutls_load_file(file, ocsp_response); if (ret < 0) return gnutls_assert_val(GNUTLS_E_NO_CERTIFICATE_STATUS); @@ -498,9 +598,7 @@ gnutls_certificate_set_ocsp_status_request_file(gnutls_certificate_credentials_t if (sc->certs[idx].ocsp_response_file == NULL) return gnutls_assert_val(GNUTLS_E_MEMORY_ERROR); - gnutls_certificate_set_ocsp_status_request_function2(sc, idx, file_ocsp_func, sc->certs[idx].ocsp_response_file); - - return 0; + return gnutls_certificate_set_ocsp_status_request_function3(sc, idx, file_ocsp_func, sc->certs[idx].ocsp_response_file, 0); } static void _gnutls_status_request_deinit_data(gnutls_ext_priv_data_t epriv) |