summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorNikos Mavrogiannopoulos <nmav@redhat.com>2017-10-16 14:40:22 +0200
committerNikos Mavrogiannopoulos <nmav@gnutls.org>2017-11-24 11:53:51 +0000
commit3be967c106e275e48f91580e878b1308a1a25c44 (patch)
tree132000eb6bfbcadfb4a9c46dd97b54a1c284ca1e
parentefeb7cafa52867c8900da742776795df7b4c38da (diff)
downloadgnutls-3be967c106e275e48f91580e878b1308a1a25c44.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.c4
-rw-r--r--lib/auth/cert.h16
-rw-r--r--lib/ext/status_request.c140
-rw-r--r--lib/gnutls_int.h2
-rw-r--r--lib/includes/gnutls/gnutls.h.in19
-rw-r--r--lib/libgnutls.map1
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 {