diff options
author | Nikos Mavrogiannopoulos <nmav@redhat.com> | 2017-10-16 14:40:22 +0200 |
---|---|---|
committer | Nikos Mavrogiannopoulos <nmav@redhat.com> | 2017-11-20 16:58:00 +0100 |
commit | 4514bb353a9327b6bed626280a699a2f103019b1 (patch) | |
tree | cab3b6fc336e15862d53fe885692460f1fe0e398 | |
parent | 0205e29fa302391fa0d54d806b74dc2990271405 (diff) | |
download | gnutls-4514bb353a9327b6bed626280a699a2f103019b1.tar.gz |
ocsp: introduced a new OCSP response callback
That allows more information to be provided to the application callback,
including the certificate that the response is needed for.
Signed-off-by: Nikos Mavrogiannopoulos <nmav@redhat.com>
-rw-r--r-- | lib/auth/cert.c | 4 | ||||
-rw-r--r-- | lib/auth/cert.h | 16 | ||||
-rw-r--r-- | lib/ext/status_request.c | 140 | ||||
-rw-r--r-- | lib/gnutls_int.h | 2 | ||||
-rw-r--r-- | lib/includes/gnutls/gnutls.h.in | 19 | ||||
-rw-r--r-- | lib/libgnutls.map | 1 |
6 files changed, 155 insertions, 27 deletions
diff --git a/lib/auth/cert.c b/lib/auth/cert.c index 6987dde40e..e840345247 100644 --- a/lib/auth/cert.c +++ b/lib/auth/cert.c @@ -61,7 +61,7 @@ static void _gnutls_selected_certs_set(gnutls_session_t session, gnutls_pcert_st * certs, int ncerts, gnutls_privkey_t key, int need_free, - gnutls_status_request_ocsp_func ocsp_func, + gnutls_status_request_ocsp_func2 ocsp_func, void *ocsp_func_ptr); #define MAX_CLIENT_SIGN_ALGOS 3 @@ -1357,7 +1357,7 @@ static void _gnutls_selected_certs_set(gnutls_session_t session, gnutls_pcert_st * certs, int ncerts, gnutls_privkey_t key, int need_free, - gnutls_status_request_ocsp_func ocsp_func, + gnutls_status_request_ocsp_func2 ocsp_func, void *ocsp_func_ptr) { _gnutls_selected_certs_deinit(session); diff --git a/lib/auth/cert.h b/lib/auth/cert.h index fee7c03ccd..0f8aba162b 100644 --- a/lib/auth/cert.h +++ b/lib/auth/cert.h @@ -30,13 +30,21 @@ #include <gnutls/compat.h> #include <str_array.h> +typedef struct legacy_ocsp_func_st { + gnutls_status_request_ocsp_func func; + void *ptr; /* private data of legacy_ocsp_func */ +} legacy_ocsp_func_st; + typedef struct { gnutls_pcert_st *cert_list; /* a certificate chain */ unsigned int cert_list_length; /* its length */ gnutls_str_array_t names; /* the names in the first certificate */ - gnutls_status_request_ocsp_func ocsp_func; - void *ocsp_func_ptr; /* corresponding OCSP response function + ptr */ + legacy_ocsp_func_st legacy_ocsp; + + gnutls_status_request_ocsp_func2 ocsp_func; + void *ocsp_func_ptr; /* private data of ocsp_func */ + char *ocsp_response_file; /* corresponding OCSP response file */ /* the private key corresponding to certificate */ @@ -86,8 +94,10 @@ typedef struct gnutls_certificate_credentials_st { /* temporarily hold the PIN if set_key_file2() is used with a PIN */ char pin_tmp[GNUTLS_PKCS11_MAX_PIN_LEN]; + legacy_ocsp_func_st glob_legacy_ocsp; + /* OCSP */ - gnutls_status_request_ocsp_func glob_ocsp_func; + gnutls_status_request_ocsp_func2 glob_ocsp_func; void *glob_ocsp_func_ptr; /* corresponding OCSP response function */ } certificate_credentials_st; 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) diff --git a/lib/gnutls_int.h b/lib/gnutls_int.h index 9e50af67ce..5cfd137f69 100644 --- a/lib/gnutls_int.h +++ b/lib/gnutls_int.h @@ -1043,7 +1043,7 @@ typedef struct { int16_t selected_cert_list_length; struct gnutls_privkey_st *selected_key; bool selected_need_free; - gnutls_status_request_ocsp_func selected_ocsp_func; + gnutls_status_request_ocsp_func2 selected_ocsp_func; void *selected_ocsp_func_ptr; diff --git a/lib/includes/gnutls/gnutls.h.in b/lib/includes/gnutls/gnutls.h.in index 4f02010a4d..e815437228 100644 --- a/lib/includes/gnutls/gnutls.h.in +++ b/lib/includes/gnutls/gnutls.h.in @@ -1868,6 +1868,17 @@ int gnutls_certificate_get_x509_crt(gnutls_certificate_credentials_t res, typedef int (*gnutls_status_request_ocsp_func) (gnutls_session_t session, void *ptr, gnutls_datum_t * ocsp_response); +typedef struct gnutls_cert_info_st { + const struct gnutls_pcert_st *pcert; + unsigned cert_index; /* position in chain - zero being the end-certificate */ + unsigned flags; +} gnutls_cert_info_st; + +typedef int (*gnutls_status_request_ocsp_func2)(gnutls_session_t session, + const gnutls_cert_info_st *cinfo, + void *ptr, + gnutls_datum_t *ocsp_response); + void gnutls_certificate_set_ocsp_status_request_function (gnutls_certificate_credentials_t res, @@ -1878,6 +1889,14 @@ gnutls_certificate_set_ocsp_status_request_function2 (gnutls_certificate_credentials_t res, unsigned idx, gnutls_status_request_ocsp_func ocsp_func, void *ptr); +#define GNUTLS_OCSP_CB_GLOBAL_SET 1 +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); + int gnutls_certificate_set_ocsp_status_request_file (gnutls_certificate_credentials_t res, const char *response_file, diff --git a/lib/libgnutls.map b/lib/libgnutls.map index 1fd149aeb5..e93fce9e26 100644 --- a/lib/libgnutls.map +++ b/lib/libgnutls.map @@ -1197,6 +1197,7 @@ GNUTLS_3_6_xx global: gnutls_ext_get_current_msg; gnutls_ocsp_status_request_get2; + gnutls_certificate_set_ocsp_status_request_function3; } GNUTLS_3_6_0; GNUTLS_FIPS140_3_4 { |