summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--lib/auth/cert.c254
-rw-r--r--lib/auth/cert.h5
-rw-r--r--lib/cert.c284
-rw-r--r--lib/ext/post_handshake.c2
-rw-r--r--lib/gnutls_int.h10
-rw-r--r--lib/includes/gnutls/abstract.h33
-rw-r--r--lib/libgnutls.map1
7 files changed, 366 insertions, 223 deletions
diff --git a/lib/auth/cert.c b/lib/auth/cert.c
index 2d02465089..085857bcd2 100644
--- a/lib/auth/cert.c
+++ b/lib/auth/cert.c
@@ -47,19 +47,10 @@
#include "abstract_int.h"
#include "debug.h"
-static gnutls_pcert_st *alloc_and_load_x509_certs(gnutls_x509_crt_t *
- certs, unsigned);
-static gnutls_privkey_t alloc_and_load_x509_key(gnutls_x509_privkey_t key,
- int deinit);
-
-#ifdef ENABLE_PKCS11
-static gnutls_privkey_t alloc_and_load_pkcs11_key(gnutls_pkcs11_privkey_t
- key, int deinit);
-#endif
-
static void
_gnutls_selected_certs_set(gnutls_session_t session,
gnutls_pcert_st * certs, int ncerts,
+ gnutls_datum_t *ocsp, int nocsp,
gnutls_privkey_t key, int need_free,
gnutls_status_request_ocsp_func ocsp_func,
void *ocsp_func_ptr);
@@ -356,14 +347,13 @@ call_get_cert_callback(gnutls_session_t session,
int issuers_dn_length,
gnutls_pk_algorithm_t * pk_algos, int pk_algos_length)
{
- unsigned i;
- gnutls_pcert_st *local_certs = NULL;
gnutls_privkey_t local_key = NULL;
int ret = GNUTLS_E_INTERNAL_ERROR;
gnutls_certificate_type_t type = gnutls_certificate_type_get(session);
gnutls_certificate_credentials_t cred;
- gnutls_retr2_st st2;
gnutls_pcert_st *pcert = NULL;
+ gnutls_datum_t *ocsp = NULL;
+ unsigned int ocsp_length = 0;
unsigned int pcert_length = 0;
cred = (gnutls_certificate_credentials_t)
@@ -373,15 +363,23 @@ call_get_cert_callback(gnutls_session_t session,
return GNUTLS_E_INSUFFICIENT_CREDENTIALS;
}
- memset(&st2, 0, sizeof(st2));
+ if (cred->get_cert_callback3) {
+ struct gnutls_cert_retr_st info;
+ unsigned int flags = 0;
+
+ memset(&info, 0, sizeof(info));
+ info.req_ca_rdn = issuers_dn;
+ info.nreqs = issuers_dn_length;
+ info.pk_algos = pk_algos;
+ info.pk_algos_length = pk_algos_length;
+ info.cred = cred;
- if (cred->get_cert_callback2) {
/* we avoid all allocations and transformations */
ret =
- cred->get_cert_callback2(session, issuers_dn,
- issuers_dn_length, pk_algos,
- pk_algos_length, &pcert,
- &pcert_length, &local_key);
+ cred->get_cert_callback3(session, &info,
+ &pcert, &pcert_length,
+ &ocsp, &ocsp_length,
+ &local_key, &flags);
if (ret < 0)
return gnutls_assert_val(GNUTLS_E_USER_ERROR);
@@ -394,100 +392,15 @@ call_get_cert_callback(gnutls_session_t session,
}
_gnutls_selected_certs_set(session, pcert, pcert_length,
- local_key, 0, NULL, NULL);
+ ocsp, ocsp_length,
+ local_key, flags&GNUTLS_CERT_RETR_DEINIT_ALL?1:0,
+ NULL, NULL);
return 0;
-
- } else if (cred->get_cert_callback) {
- ret =
- cred->get_cert_callback(session, issuers_dn,
- issuers_dn_length, pk_algos,
- pk_algos_length, &st2);
-
- } else { /* compatibility mode */
+ } else {
gnutls_assert();
return GNUTLS_E_INTERNAL_ERROR;
}
-
- if (ret < 0) {
- gnutls_assert();
- return GNUTLS_E_USER_ERROR;
- }
-
- if (st2.ncerts == 0)
- return 0; /* no certificate was selected */
-
- if (type != st2.cert_type) {
- gnutls_assert();
- ret = GNUTLS_E_INVALID_REQUEST;
- goto cleanup;
- }
-
- if (type == GNUTLS_CRT_X509) {
- local_certs =
- alloc_and_load_x509_certs(st2.cert.x509, st2.ncerts);
- } else { /* PGP */
- ret = GNUTLS_E_UNIMPLEMENTED_FEATURE;
- goto cleanup;
- }
-
- if (local_certs == NULL) {
- gnutls_assert();
- ret = GNUTLS_E_MEMORY_ERROR;
- goto cleanup;
- }
-
- switch (st2.key_type) {
- case GNUTLS_PRIVKEY_PKCS11:
-#ifdef ENABLE_PKCS11
- if (st2.key.pkcs11 != NULL) {
- local_key =
- alloc_and_load_pkcs11_key(st2.key.pkcs11,
- st2.deinit_all);
- if (local_key == NULL) {
- gnutls_assert();
- ret = GNUTLS_E_INTERNAL_ERROR;
- goto cleanup;
- }
- }
-#endif
- break;
- case GNUTLS_PRIVKEY_X509:
- if (st2.key.x509 != NULL) {
- local_key =
- alloc_and_load_x509_key(st2.key.x509,
- st2.deinit_all);
- if (local_key == NULL) {
- gnutls_assert();
- ret = GNUTLS_E_INTERNAL_ERROR;
- goto cleanup;
- }
- }
- break;
- default:
- gnutls_assert();
- ret = GNUTLS_E_INVALID_REQUEST;
- goto cleanup;
- }
-
- _gnutls_selected_certs_set(session, local_certs,
- st2.ncerts, local_key, 1,
- NULL, NULL);
-
- ret = 0;
-
- cleanup:
-
- if (st2.cert_type == GNUTLS_CRT_X509) {
- if (st2.deinit_all) {
- for (i = 0; i < st2.ncerts; i++) {
- gnutls_x509_crt_deinit(st2.cert.x509[i]);
- }
- gnutls_free(st2.cert.x509);
- }
- }
-
- return ret;
}
/* Finds the appropriate certificate depending on the cA Distinguished name
@@ -517,8 +430,7 @@ _gnutls_select_client_cert(gnutls_session_t session,
return GNUTLS_E_INSUFFICIENT_CREDENTIALS;
}
- if (cred->get_cert_callback != NULL
- || cred->get_cert_callback2 != NULL) {
+ if (cred->get_cert_callback3 != NULL) {
/* use a callback to get certificate
*/
@@ -579,11 +491,12 @@ _gnutls_select_client_cert(gnutls_session_t session,
cert_list[0],
cred->certs[indx].
cert_list_length,
+ NULL, 0,
cred->certs[indx].pkey, 0,
NULL, NULL);
} else {
_gnutls_selected_certs_set(session, NULL, 0, NULL, 0,
- NULL, NULL);
+ NULL, 0, NULL, NULL);
}
result = 0;
@@ -1225,109 +1138,6 @@ _gnutls_get_selected_cert(gnutls_session_t session,
return 0;
}
-/* converts the given x509 certificate list to gnutls_pcert_st* and allocates
- * space for them.
- */
-static gnutls_pcert_st *alloc_and_load_x509_certs(gnutls_x509_crt_t *
- certs, unsigned ncerts)
-{
- gnutls_pcert_st *local_certs;
- int ret = 0;
- unsigned i, j;
-
- if (certs == NULL)
- return NULL;
-
- local_certs = gnutls_malloc(sizeof(gnutls_pcert_st) * ncerts);
- if (local_certs == NULL) {
- gnutls_assert();
- return NULL;
- }
-
- for (i = 0; i < ncerts; i++) {
- ret = gnutls_pcert_import_x509(&local_certs[i], certs[i], 0);
- if (ret < 0)
- break;
- }
-
- if (ret < 0) {
- gnutls_assert();
- for (j = 0; j < i; j++) {
- gnutls_pcert_deinit(&local_certs[j]);
- }
- gnutls_free(local_certs);
- return NULL;
- }
-
- return local_certs;
-}
-
-/* converts the given x509 key to gnutls_privkey* and allocates
- * space for it.
- */
-static gnutls_privkey_t
-alloc_and_load_x509_key(gnutls_x509_privkey_t key, int deinit)
-{
- gnutls_privkey_t local_key;
- int ret = 0;
-
- if (key == NULL)
- return NULL;
-
- ret = gnutls_privkey_init(&local_key);
- if (ret < 0) {
- gnutls_assert();
- return NULL;
- }
-
- ret =
- gnutls_privkey_import_x509(local_key, key,
- deinit ?
- GNUTLS_PRIVKEY_IMPORT_AUTO_RELEASE : 0);
- if (ret < 0) {
- gnutls_assert();
- gnutls_privkey_deinit(local_key);
- return NULL;
- }
-
- return local_key;
-}
-
-#ifdef ENABLE_PKCS11
-
-/* converts the given raw key to gnutls_privkey* and allocates
- * space for it.
- */
-static gnutls_privkey_t
-alloc_and_load_pkcs11_key(gnutls_pkcs11_privkey_t key, int deinit)
-{
- gnutls_privkey_t local_key;
- int ret = 0;
-
- if (key == NULL)
- return NULL;
-
- ret = gnutls_privkey_init(&local_key);
- if (ret < 0) {
- gnutls_assert();
- return NULL;
- }
-
- ret =
- gnutls_privkey_import_pkcs11(local_key, key,
- deinit ?
- GNUTLS_PRIVKEY_IMPORT_AUTO_RELEASE
- : 0);
- if (ret < 0) {
- gnutls_assert();
- gnutls_privkey_deinit(local_key);
- return NULL;
- }
-
- return local_key;
-}
-
-#endif
void _gnutls_selected_certs_deinit(gnutls_session_t session)
{
@@ -1341,6 +1151,13 @@ void _gnutls_selected_certs_deinit(gnutls_session_t session)
}
gnutls_free(session->internals.selected_cert_list);
+ for (i = 0;
+ i < session->internals.selected_ocsp_length; i++) {
+ _gnutls_free_datum(&session->internals.
+ selected_ocsp[i]);
+ }
+ gnutls_free(session->internals.selected_ocsp);
+
gnutls_privkey_deinit(session->internals.selected_key);
}
session->internals.selected_ocsp_func = NULL;
@@ -1356,6 +1173,7 @@ void _gnutls_selected_certs_deinit(gnutls_session_t session)
static void
_gnutls_selected_certs_set(gnutls_session_t session,
gnutls_pcert_st * certs, int ncerts,
+ gnutls_datum_t *ocsp, int nocsp,
gnutls_privkey_t key, int need_free,
gnutls_status_request_ocsp_func ocsp_func,
void *ocsp_func_ptr)
@@ -1364,6 +1182,10 @@ _gnutls_selected_certs_set(gnutls_session_t session,
session->internals.selected_cert_list = certs;
session->internals.selected_cert_list_length = ncerts;
+
+ session->internals.selected_ocsp = ocsp;
+ session->internals.selected_ocsp_length = nocsp;
+
session->internals.selected_key = key;
session->internals.selected_need_free = need_free;
@@ -1486,8 +1308,7 @@ _gnutls_server_select_cert(gnutls_session_t session, const gnutls_cipher_suite_e
/* If the callback which retrieves certificate has been set,
* use it and leave. We make sure that this is called once.
*/
- if (cred->get_cert_callback
- || cred->get_cert_callback2) {
+ if (cred->get_cert_callback3) {
if (session->internals.selected_cert_list_length == 0) {
ret = call_get_cert_callback(session, NULL, 0, NULL, 0);
@@ -1608,6 +1429,7 @@ _gnutls_server_select_cert(gnutls_session_t session, const gnutls_cipher_suite_e
_gnutls_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);
diff --git a/lib/auth/cert.h b/lib/auth/cert.h
index fee7c03ccd..f890f48624 100644
--- a/lib/auth/cert.h
+++ b/lib/auth/cert.h
@@ -77,8 +77,9 @@ typedef struct gnutls_certificate_credentials_st {
/* It's a mess here. However we need to keep the old 3 functions
* for compatibility */
- gnutls_certificate_retrieve_function *get_cert_callback; /* deprecated */
- gnutls_certificate_retrieve_function2 *get_cert_callback2;
+ gnutls_certificate_retrieve_function *legacy_cert_cb1; /* deprecated */
+ gnutls_certificate_retrieve_function2 *legacy_cert_cb2;
+ gnutls_certificate_retrieve_function3 *get_cert_callback3;
gnutls_certificate_verify_function *verify_callback;
diff --git a/lib/cert.c b/lib/cert.c
index 9e3a00f484..617ad8e644 100644
--- a/lib/cert.c
+++ b/lib/cert.c
@@ -236,6 +236,110 @@ gnutls_certificate_allocate_credentials(gnutls_certificate_credentials_t *
return 0;
}
+/* converts the given x509 certificate list to gnutls_pcert_st* and allocates
+ * space for them.
+ */
+static gnutls_pcert_st *alloc_and_load_x509_certs(gnutls_x509_crt_t *
+ certs, unsigned ncerts)
+{
+ gnutls_pcert_st *local_certs;
+ int ret = 0;
+ unsigned i, j;
+
+ if (certs == NULL)
+ return NULL;
+
+ local_certs = gnutls_malloc(sizeof(gnutls_pcert_st) * ncerts);
+ if (local_certs == NULL) {
+ gnutls_assert();
+ return NULL;
+ }
+
+ for (i = 0; i < ncerts; i++) {
+ ret = gnutls_pcert_import_x509(&local_certs[i], certs[i], 0);
+ if (ret < 0)
+ break;
+ }
+
+ if (ret < 0) {
+ gnutls_assert();
+ for (j = 0; j < i; j++) {
+ gnutls_pcert_deinit(&local_certs[j]);
+ }
+ gnutls_free(local_certs);
+ return NULL;
+ }
+
+ return local_certs;
+}
+
+/* converts the given x509 key to gnutls_privkey* and allocates
+ * space for it.
+ */
+static gnutls_privkey_t
+alloc_and_load_x509_key(gnutls_x509_privkey_t key, int deinit)
+{
+ gnutls_privkey_t local_key;
+ int ret = 0;
+
+ if (key == NULL)
+ return NULL;
+
+ ret = gnutls_privkey_init(&local_key);
+ if (ret < 0) {
+ gnutls_assert();
+ return NULL;
+ }
+
+ ret =
+ gnutls_privkey_import_x509(local_key, key,
+ deinit ?
+ GNUTLS_PRIVKEY_IMPORT_AUTO_RELEASE : 0);
+ if (ret < 0) {
+ gnutls_assert();
+ gnutls_privkey_deinit(local_key);
+ return NULL;
+ }
+
+ return local_key;
+}
+
+#ifdef ENABLE_PKCS11
+
+/* converts the given raw key to gnutls_privkey* and allocates
+ * space for it.
+ */
+static gnutls_privkey_t
+alloc_and_load_pkcs11_key(gnutls_pkcs11_privkey_t key, int deinit)
+{
+ gnutls_privkey_t local_key;
+ int ret = 0;
+
+ if (key == NULL)
+ return NULL;
+
+ ret = gnutls_privkey_init(&local_key);
+ if (ret < 0) {
+ gnutls_assert();
+ return NULL;
+ }
+
+ ret =
+ gnutls_privkey_import_pkcs11(local_key, key,
+ deinit ?
+ GNUTLS_PRIVKEY_IMPORT_AUTO_RELEASE
+ : 0);
+ if (ret < 0) {
+ gnutls_assert();
+ gnutls_privkey_deinit(local_key);
+ return NULL;
+ }
+
+ return local_key;
+}
+
+#endif
+
/**
* gnutls_certificate_server_set_request:
* @session: is a #gnutls_session_t type.
@@ -254,6 +358,102 @@ gnutls_certificate_server_set_request(gnutls_session_t session,
session->internals.send_cert_req = req;
}
+static int call_legacy_cert_cb1(gnutls_session_t session,
+ const struct gnutls_cert_retr_st *info,
+ gnutls_pcert_st **certs,
+ unsigned int *pcert_length,
+ gnutls_datum_t **ocsp,
+ unsigned int *ocsp_length,
+ gnutls_privkey_t *privkey,
+ unsigned int *flags)
+{
+ gnutls_retr2_st st2;
+ gnutls_pcert_st *local_certs = NULL;
+ gnutls_privkey_t local_key = NULL;
+ unsigned i;
+ int ret;
+
+ *ocsp_length = 0;
+
+ memset(&st2, 0, sizeof(st2));
+
+ ret = info->cred->legacy_cert_cb1(session, info->req_ca_rdn, info->nreqs,
+ info->pk_algos, info->pk_algos_length,
+ &st2);
+ if (ret < 0)
+ return gnutls_assert_val(ret);
+
+ if (st2.cert_type != GNUTLS_CRT_X509) {
+ gnutls_assert();
+ ret = GNUTLS_E_INVALID_REQUEST;
+ goto cleanup;
+ }
+
+ local_certs =
+ alloc_and_load_x509_certs(st2.cert.x509, st2.ncerts);
+ if (local_certs == NULL) {
+ gnutls_assert();
+ ret = GNUTLS_E_MEMORY_ERROR;
+ goto cleanup;
+ }
+
+ switch (st2.key_type) {
+#ifdef ENABLE_PKCS11
+ case GNUTLS_PRIVKEY_PKCS11:
+ if (st2.key.pkcs11 != NULL) {
+ local_key =
+ alloc_and_load_pkcs11_key(st2.key.pkcs11,
+ st2.deinit_all);
+ if (local_key == NULL) {
+ gnutls_assert();
+ ret = GNUTLS_E_INTERNAL_ERROR;
+ goto cleanup;
+ }
+ }
+ break;
+#endif
+ case GNUTLS_PRIVKEY_X509:
+ if (st2.key.x509 != NULL) {
+ local_key =
+ alloc_and_load_x509_key(st2.key.x509,
+ st2.deinit_all);
+ if (local_key == NULL) {
+ gnutls_assert();
+ ret = GNUTLS_E_INTERNAL_ERROR;
+ goto cleanup;
+ }
+ }
+ break;
+ default:
+ gnutls_assert();
+ ret = GNUTLS_E_INVALID_REQUEST;
+ goto cleanup;
+ }
+
+ *privkey = local_key;
+ *certs = local_certs;
+ *pcert_length = st2.ncerts;
+
+ /* flag the caller to deinitialize our values */
+ *flags |= GNUTLS_CERT_RETR_DEINIT_ALL;
+
+ ret = 0;
+
+ cleanup:
+
+ if (st2.cert_type == GNUTLS_CRT_X509) {
+ if (st2.deinit_all) {
+ for (i = 0; i < st2.ncerts; i++) {
+ gnutls_x509_crt_deinit(st2.cert.x509[i]);
+ }
+ gnutls_free(st2.cert.x509);
+ }
+ }
+
+ return ret;
+
+}
+
/**
* gnutls_certificate_set_retrieve_function:
* @cred: is a #gnutls_certificate_credentials_t type.
@@ -298,7 +498,30 @@ void gnutls_certificate_set_retrieve_function
(gnutls_certificate_credentials_t cred,
gnutls_certificate_retrieve_function * func)
{
- cred->get_cert_callback = func;
+ cred->legacy_cert_cb1 = func;
+ cred->get_cert_callback3 = call_legacy_cert_cb1;
+}
+
+static int call_legacy_cert_cb2(gnutls_session_t session,
+ const struct gnutls_cert_retr_st *info,
+ gnutls_pcert_st **certs,
+ unsigned int *pcert_length,
+ gnutls_datum_t **ocsp,
+ unsigned int *ocsp_length,
+ gnutls_privkey_t *privkey,
+ unsigned int *flags)
+{
+ int ret;
+ *ocsp_length = 0;
+ /* flags will be assumed to be zero */
+
+ ret = info->cred->legacy_cert_cb2(session, info->req_ca_rdn, info->nreqs,
+ info->pk_algos, info->pk_algos_length,
+ certs, pcert_length, privkey);
+ if (ret < 0) {
+ gnutls_assert();
+ }
+ return ret;
}
/**
@@ -350,7 +573,64 @@ void gnutls_certificate_set_retrieve_function2
(gnutls_certificate_credentials_t cred,
gnutls_certificate_retrieve_function2 * func)
{
- cred->get_cert_callback2 = func;
+ cred->legacy_cert_cb2 = func;
+ cred->get_cert_callback3 = call_legacy_cert_cb2;
+}
+
+/**
+ * gnutls_certificate_set_retrieve_function3:
+ * @cred: is a #gnutls_certificate_credentials_t type.
+ * @func: is the callback function
+ *
+ * This function sets a callback to be called in order to retrieve the
+ * certificate and OCSP responses to be used in the handshake. The callback will
+ * take control only if a certificate is requested by the peer.
+ *
+ * The callback's function prototype is defined in `abstract.h':
+ * int (*callback)(gnutls_session_t, const struct gnutls_cert_retr_st *info,
+ * gnutls_pcert_st **certs, unsigned int *pcert_length,
+ * gnutls_datum_t **ocsp, unsigned int *ocsp_length,
+ * gnutls_privkey_t * pkey, unsigned int *flags);
+ *
+ * The info field of the callback contains:
+ * @req_ca_dn which is a list with the CA names that the server considers trusted.
+ * This is a hint and typically the client should send a certificate that is signed
+ * by one of these CAs. These names, when available, are DER encoded. To get a more
+ * meaningful value use the function gnutls_x509_rdn_get().
+ * @pk_algos contains a list with server's acceptable public key algorithms.
+ * The certificate returned should support the server's given algorithms.
+ *
+ * The callback should fill-in the following values.
+ *
+ * @pcert should contain a single certificate and public key or a list of them.
+ * @pcert_length is the size of the previous list.
+ * @ocsp should contain a single OCSP response or a list of them.
+ * @ocsp_length is the size of the previous list.
+ * @pkey is the private key.
+ *
+ * If the callback function is provided then gnutls will call it, during
+ * handshake, after the certificate request message has been received,
+ * or during post-handshake.
+ *
+ * All the provided by the callback values will not be released or
+ * modified by gnutls.
+ *
+ * When this callback is set in server side, @pk_algos and @req_ca_dn are NULL.
+ *
+ * The callback function should set the certificate and OCSP response
+ * list to be sent, and return 0 on success. If no certificate was selected then
+ * the @pcert_length and @Ocsp_length should be set to zero. The return
+ * value (-1) indicates error and the handshake will be terminated. If both
+ * certificates are set in the credentials and a callback is available, the
+ * callback takes predence.
+ *
+ * Since: 3.6.xx
+ **/
+void gnutls_certificate_set_retrieve_function3
+ (gnutls_certificate_credentials_t cred,
+ gnutls_certificate_retrieve_function3 *func)
+{
+ cred->get_cert_callback3 = func;
}
/**
diff --git a/lib/ext/post_handshake.c b/lib/ext/post_handshake.c
index 9aa67e2aed..0af7e53f21 100644
--- a/lib/ext/post_handshake.c
+++ b/lib/ext/post_handshake.c
@@ -94,7 +94,7 @@ _gnutls_post_handshake_send_params(gnutls_session_t session,
if (unlikely(max == NULL))
return gnutls_assert_val(0);
- if (max->post_handshake_auth && (cred->ncerts || cred->get_cert_callback2 || cred->get_cert_callback))
+ if (max->post_handshake_auth && (cred->ncerts || cred->get_cert_callback3))
return GNUTLS_E_INT_RET_0;
else
return 0;
diff --git a/lib/gnutls_int.h b/lib/gnutls_int.h
index bb422ddbe9..63111a3a89 100644
--- a/lib/gnutls_int.h
+++ b/lib/gnutls_int.h
@@ -1085,9 +1085,17 @@ typedef struct {
gnutls_pcert_st *selected_cert_list;
int16_t selected_cert_list_length;
struct gnutls_privkey_st *selected_key;
- bool selected_need_free;
+
+ /* new callbacks such as gnutls_certificate_retrieve_function3
+ * set the selected_ocsp datum values. The older OCSP callback-based
+ * functions, set the ocsp_func. The former takes precedence when
+ * set.
+ */
+ gnutls_datum_t *selected_ocsp;
+ int16_t selected_ocsp_length;
gnutls_status_request_ocsp_func selected_ocsp_func;
void *selected_ocsp_func_ptr;
+ bool selected_need_free;
/* This holds the default version that our first
diff --git a/lib/includes/gnutls/abstract.h b/lib/includes/gnutls/abstract.h
index bf29f877cd..bc97086262 100644
--- a/lib/includes/gnutls/abstract.h
+++ b/lib/includes/gnutls/abstract.h
@@ -655,7 +655,38 @@ typedef int gnutls_certificate_retrieve_function2(gnutls_session_t,
void gnutls_certificate_set_retrieve_function2
(gnutls_certificate_credentials_t cred,
- gnutls_certificate_retrieve_function2 * func);
+ gnutls_certificate_retrieve_function2 *func);
+
+struct gnutls_cert_retr_st {
+ unsigned version; /* set to 1 */
+ gnutls_certificate_credentials_t cred;
+ const gnutls_datum_t *req_ca_rdn;
+ unsigned nreqs;
+ const gnutls_pk_algorithm_t *pk_algos;
+ unsigned pk_algos_length;
+
+ /* other fields may be added if version is > 1 */
+ unsigned char padding[64];
+};
+
+/* When the callback sets this value, gnutls will deinitialize the given
+ * values after use */
+#define GNUTLS_CERT_RETR_DEINIT_ALL 1
+
+typedef int gnutls_certificate_retrieve_function3(
+ gnutls_session_t,
+ const struct gnutls_cert_retr_st *info,
+ gnutls_pcert_st **certs,
+ unsigned int *pcert_length,
+ gnutls_datum_t **ocsp,
+ unsigned int *ocsp_length,
+ gnutls_privkey_t *privkey,
+ unsigned int *flags);
+
+
+void gnutls_certificate_set_retrieve_function3
+ (gnutls_certificate_credentials_t cred,
+ gnutls_certificate_retrieve_function3 *func);
int
gnutls_certificate_set_key(gnutls_certificate_credentials_t res,
diff --git a/lib/libgnutls.map b/lib/libgnutls.map
index d29d650a81..e861aeaf7d 100644
--- a/lib/libgnutls.map
+++ b/lib/libgnutls.map
@@ -1214,6 +1214,7 @@ GNUTLS_3_6_xx
gnutls_ocsp_resp_import2;
gnutls_ocsp_resp_export2;
gnutls_ocsp_resp_list_import2;
+ gnutls_certificate_retrieve_function3;
} GNUTLS_3_6_2;
GNUTLS_FIPS140_3_4 {