#include <gnutls_extra.h>
#include "debug.h"
+static gnutls_cert *alloc_and_load_certs(const gnutls_datum * certs,
+ uint ncerts, gnutls_certificate_type type);
+static gnutls_privkey *alloc_and_load_key(const gnutls_datum * raw_key,
+ gnutls_certificate_type type);
+
+
/* Copies data from a internal certificate struct (gnutls_cert) to
* exported certificate struct (CERTIFICATE_AUTH_INFO)
*/
static
-int _gnutls_copy_certificate_auth_info(CERTIFICATE_AUTH_INFO info,
- gnutls_cert * cert, int ncerts)
+int _gnutls_copy_certificate_auth_info(CERTIFICATE_AUTH_INFO info,
+ gnutls_cert * cert, int ncerts)
{
/* Copy peer's information to AUTH_INFO
*/
info->ncerts = 0;
return 0;
}
-
+
info->raw_certificate_list =
gnutls_calloc(1, sizeof(gnutls_datum) * ncerts);
if (info->raw_certificate_list == NULL) {
for (i = 0; i < cred->ncerts; i++) {
for (j = 0; j < cred->cert_list_length[i]; j++) {
if ((result =
- _gnutls_cert_get_dn( &cred->cert_list[i][j], &odn)) < 0) {
+ _gnutls_cert_get_dn(&cred->
+ cert_list[i][j],
+ &odn)) < 0) {
gnutls_assert();
return result;
}
* the *_SIGN algorithm matches
* the cert is our cert!
*/
- cert_pk = cred->cert_list[i][0].subject_pk_algorithm;
+ cert_pk =
+ cred->cert_list[i][0].
+ subject_pk_algorithm;
if ((memcmp(odn.data, data, size) == 0) &&
- (_gnutls_check_pk_algo_in_list(pk_algos, pk_algos_length, cert_pk) == 0)) {
+ (_gnutls_check_pk_algo_in_list
+ (pk_algos, pk_algos_length,
+ cert_pk) == 0)) {
*indx = i;
break;
}
return 0;
}
-/* Some upper limit to protect alloca();
+/* Returns the number of issuers in the server's
+ * certificate request packet.
+ */
+static int get_issuers_num( gnutls_session session, opaque * data, ssize_t data_size)
+{
+int issuers_dn_len, result;
+uint size;
+
+ /* Count the number of the given issuers;
+ * This is used to allocate the issuers_dn without
+ * using realloc().
+ */
+
+ if (gnutls_certificate_type_get(session) != GNUTLS_CRT_X509)
+ return 0;
+
+ do {
+ /* This works like DECR_LEN()
+ */
+ result = GNUTLS_E_UNEXPECTED_PACKET_LENGTH;
+ DECR_LENGTH_COM(data_size, 2, goto error);
+ size = _gnutls_read_uint16(data);
+
+ result = GNUTLS_E_UNEXPECTED_PACKET_LENGTH;
+ DECR_LENGTH_COM(data_size, size, goto error);
+
+ data += 2;
+
+ if (size > 0) {
+ issuers_dn_len++;
+ data += size;
+ }
+
+ if (data_size == 0)
+ break;
+
+ } while (1);
+
+ return issuers_dn_len;
+
+ error:
+ return result;
+}
+
+/* Returns the issuers in the server's certificate request
+ * packet.
+ */
+static int get_issuers( gnutls_session session,
+ gnutls_datum* issuers_dn, int issuers_len,
+ opaque * data, size_t data_size)
+{
+int i;
+uint size;
+
+ if (gnutls_certificate_type_get(session) != GNUTLS_CRT_X509)
+ return 0;
+
+ /* put the requested DNs to req_dn, only in case
+ * of X509 certificates.
+ */
+ if (issuers_len > 0) {
+
+ for (i = 0; i < issuers_len; i++) {
+ /* The checks here for the buffer boundaries
+ * are not needed since the buffer has been
+ * parsed above.
+ */
+ data_size -= 2;
+
+ size = _gnutls_read_uint16(data);
+
+ data += 2;
+
+ issuers_dn[i].data = data;
+ issuers_dn[i].size = size;
+
+ data += size;
+ }
+ }
+
+ return 0;
+}
+
+
+/* Calls the client_cert_callback() to select an index for the
+ * certificate to use.
+ */
+static int call_client_cert_callback(gnutls_session session,
+ const gnutls_certificate_credentials cred, gnutls_pk_algorithm * pk_algos,
+ int pk_algos_length, gnutls_datum * issuers_dn, uint issuers_dn_len)
+{
+ uint i, j;
+ int indx, result;
+ int *ij_map = NULL;
+ gnutls_datum *my_certs = NULL;
+
+ if (cred->ncerts != 0) {
+ my_certs =
+ gnutls_alloca(cred->ncerts *
+ sizeof(gnutls_datum));
+ if (my_certs == NULL) {
+ result = GNUTLS_E_MEMORY_ERROR;
+ gnutls_assert();
+ goto error;
+ }
+
+
+ /* maps j -> i
+ */
+ ij_map = gnutls_alloca(sizeof(int) * cred->ncerts);
+ if (ij_map == NULL) {
+ result = GNUTLS_E_MEMORY_ERROR;
+ gnutls_assert();
+ goto error;
+ }
+ }
+
+ /* put our certificate's issuer and dn into cdn, idn
+ * Note that the certificates we provide to the callback
+ * are not all the certificates we have. Only the certificates
+ * that are requested by the server (certificate type - and sign
+ * algorithm matches), are provided.
+ */
+ for (j = i = 0; i < cred->ncerts; i++) {
+ if ((cred->cert_list[i][0].cert_type ==
+ gnutls_certificate_type_get(session)) &&
+ (_gnutls_check_pk_algo_in_list(pk_algos,
+ pk_algos_length,
+ cred->
+ cert_list[i][0].
+ subject_pk_algorithm)
+ == 0)) {
+ /* Add a certificate ONLY if it is allowed
+ * by the peer.
+ */
+ ij_map[j] = i;
+ my_certs[j++] = cred->cert_list[i][0].raw;
+ }
+ }
+
+ indx =
+ session->internals.client_cert_callback(session,
+ my_certs,
+ j,
+ issuers_dn,
+ issuers_dn_len);
+
+ /* the indx returned by the user is relative
+ * to the certificates we provided him.
+ * This will make it relative to the certificates
+ * we've got.
+ */
+ if (indx != -1 && cred->ncerts != 0)
+ indx = ij_map[indx];
+ else
+ indx = -1;
+
+
+ result = indx;
+
+ error:
+ if (my_certs != NULL) {
+ gnutls_afree(my_certs);
+ }
+ if (ij_map != NULL) {
+ gnutls_afree(ij_map);
+ }
+ return result;
+
+}
+
+/* Calls the client get callback.
*/
-#define MAX_ISSUERS 512
+static int call_client_get_cert_callback( gnutls_session session,
+ gnutls_datum* issuers_dn, int issuers_dn_length)
+{
+gnutls_datum *certs, key;
+uint ncerts, i;
+gnutls_certificate_type type =
+ gnutls_certificate_type_get(session);
+gnutls_cert *local_certs = NULL;
+gnutls_privkey *local_key = NULL;
+int ret;
+
+ ret =
+ session->internals.client_get_cert_callback(session,
+ issuers_dn, issuers_dn_length,
+ &certs, &ncerts, &key);
+ if (ret < 0) {
+ gnutls_assert();
+ return GNUTLS_E_INTERNAL_ERROR;
+ }
+
+ local_certs = alloc_and_load_certs(certs, ncerts, type);
+ if (local_certs != NULL)
+ local_key = alloc_and_load_key(&key, type);
+
+ for (i = 0; i < ncerts; i++) {
+ _gnutls_free_datum(&certs[i]);
+ }
+ _gnutls_free_datum(&key);
+
+ _gnutls_selected_certs_set(session, local_certs, ncerts,
+ local_key, 1);
+
+ return 0;
+}
/* Finds the appropriate certificate depending on the cA Distinguished name
* advertized by the server. If none matches then returns 0 and -1 as index.
* algorithm (only in automatic mode).
*/
static int _select_client_cert(gnutls_session session,
- opaque * _data, size_t _data_size, int *ind,
- gnutls_pk_algorithm *pk_algos, int pk_algos_length)
+ opaque * _data, size_t _data_size,
+ gnutls_pk_algorithm * pk_algos,
+ int pk_algos_length)
{
- int result, size;
+ int result;
int indx = -1;
- uint i, j;
- int *ij_map = NULL;
const gnutls_certificate_credentials cred;
opaque *data = _data;
ssize_t data_size = _data_size;
- gnutls_datum *my_certs = NULL;
- gnutls_datum *issuers_dn = NULL;
+ int issuers_dn_length;
+ gnutls_datum * issuers_dn = NULL;
cred =
_gnutls_get_cred(session->key, GNUTLS_CRD_CERTIFICATE, NULL);
return GNUTLS_E_INSUFFICIENT_CREDENTIALS;
}
- /* If we have no callback.
- */
- if (session->internals.client_cert_callback == NULL) {
+ if (session->internals.client_get_cert_callback != NULL ||
+ session->internals.client_cert_callback != NULL) {
+
+ /* use a callback to get certificate
+ */
+ issuers_dn_length = get_issuers_num( session, data, data_size);
+ if (issuers_dn_length < 0) {
+ gnutls_assert();
+ return issuers_dn_length;
+ }
+
+ if (issuers_dn_length > 0) {
+ issuers_dn = gnutls_malloc( sizeof(gnutls_datum)*issuers_dn_length);
+ if (issuers_dn == NULL) {
+ gnutls_assert();
+ return GNUTLS_E_MEMORY_ERROR;
+ }
+
+ result = get_issuers( session, issuers_dn, issuers_dn_length, data, data_size);
+ if (result < 0) {
+ gnutls_assert();
+ goto cleanup;
+ }
+ }
+
+ if (session->internals.client_get_cert_callback) {
+ result = call_client_get_cert_callback( session, issuers_dn, issuers_dn_length);
+ goto cleanup;
+ }
+
+ /* in case of the callback that returns an index:
+ */
+ indx = call_client_cert_callback(session, cred, pk_algos,
+ pk_algos_length, issuers_dn, issuers_dn_length);
+
+ } else {
+ /* If we have no callbacks, try to guess.
+ */
result = 0;
if (session->security_parameters.cert_type ==
gnutls_assert();
return result;
}
- } else /* If the callback is set, then use it. */
- if (session->internals.client_cert_callback != NULL) {
- /* use a callback to get certificate
- */
- uint issuers_dn_len = 0;
- opaque *dataptr = data;
- ssize_t dataptr_size = data_size;
-
- /* Count the number of the given issuers;
- * This is used to allocate the issuers_dn without
- * using realloc().
- */
-
- if (gnutls_certificate_type_get(session) == GNUTLS_CRT_X509) {
-
- /* Makes the issuers_dn stuff.
- */
- do {
- /* This works like DECR_LEN()
- */
- result = GNUTLS_E_UNEXPECTED_PACKET_LENGTH;
- DECR_LENGTH_COM(dataptr_size, 2, goto error);
- size = _gnutls_read_uint16(dataptr);
-
- result = GNUTLS_E_UNEXPECTED_PACKET_LENGTH;
- DECR_LENGTH_COM(dataptr_size, size, goto error);
-
- dataptr += 2;
-
- if (size > 0) {
- issuers_dn_len++;
- dataptr += size;
- }
-
- if (dataptr_size == 0)
- break;
-
- } while (issuers_dn_len < MAX_ISSUERS);
-
- if (cred->ncerts != 0) {
- my_certs =
- gnutls_alloca(cred->ncerts * sizeof(gnutls_datum));
- if (my_certs == NULL) {
- result = GNUTLS_E_MEMORY_ERROR;
- gnutls_assert();
- goto error;
- }
- }
-
- /* put the requested DNs to req_dn, only in case
- * of X509 certificates.
- */
- if (issuers_dn_len > 0) {
- data = _data;
- data_size = _data_size;
-
- issuers_dn =
- gnutls_alloca(issuers_dn_len *
- sizeof(gnutls_datum));
- if (issuers_dn == NULL) {
- result = GNUTLS_E_MEMORY_ERROR;
- gnutls_assert();
- goto error;
- }
-
- for (i = 0; i < issuers_dn_len; i++) {
- /* The checks here for the buffer boundaries
- * are not needed since the buffer has been
- * parsed above.
- */
- data_size -= 2;
-
- size = _gnutls_read_uint16(data);
-
- data += 2;
-
- issuers_dn[i].data = data;
- issuers_dn[i].size = size;
-
- data += size;
-
- }
- }
-
- } else { /* Other certificate types */
- issuers_dn_len = 0;
- issuers_dn = NULL;
- }
-
- /* If not certificates are present.
- */
- /* maps j -> i
- */
-
- if (cred->ncerts != 0) {
- ij_map = gnutls_alloca(sizeof(int) * cred->ncerts);
- if (ij_map == NULL) {
- result = GNUTLS_E_MEMORY_ERROR;
- gnutls_assert();
- goto error;
- }
- }
-
- /* put our certificate's issuer and dn into cdn, idn
- * Note that the certificates we provide to the callback
- * are not all the certificates we have. Only the certificates
- * that are requested by the server (certificate type - and sign
- * algorithm matches), are provided.
- */
- for (j = i = 0; i < cred->ncerts; i++) {
- if ((cred->cert_list[i][0].cert_type ==
- gnutls_certificate_type_get(session)) &&
- (_gnutls_check_pk_algo_in_list(pk_algos,
- pk_algos_length,
- cred->
- cert_list[i][0].
- subject_pk_algorithm)
- == 0)) {
- /* Add a certificate ONLY if it is allowed
- * by the peer.
- */
- ij_map[j] = i;
- my_certs[j++] = cred->cert_list[i][0].raw;
- }
- }
-
- indx =
- session->internals.client_cert_callback(session,
- my_certs,
- j,
- issuers_dn,
- issuers_dn_len);
-
- /* the indx returned by the user is relative
- * to the certificates we provided him.
- * This will make it relative to the certificates
- * we've got.
- */
- if (indx != -1 && cred->ncerts != 0)
- indx = ij_map[indx];
- else
- indx = -1;
+ }
- if (my_certs) { gnutls_afree(my_certs); }
- if (ij_map) { gnutls_afree(ij_map); }
- if (issuers_dn) { gnutls_afree(issuers_dn); }
+ if (indx >= 0) {
+ _gnutls_selected_certs_set(session,
+ &cred->cert_list[indx][0],
+ cred->cert_list_length[indx],
+ &cred->pkey[indx], 0);
+ } else {
+ _gnutls_selected_certs_set(session, NULL, 0, NULL, 0);
}
- *ind = indx;
- return 0;
+ result = 0;
- error:
- if (my_certs != NULL) { gnutls_afree(my_certs); }
- if (ij_map != NULL) { gnutls_afree(ij_map); }
- if (issuers_dn != NULL) { gnutls_afree(issuers_dn); }
- return result;
+cleanup:
+ gnutls_free( issuers_dn);
+ return result;
}
*/
if ((ret =
_gnutls_get_selected_cert(session, &apr_cert_list,
- &apr_cert_list_length,
- &apr_pkey)) < 0) {
+ &apr_cert_list_length,
+ &apr_pkey)) < 0) {
gnutls_assert();
return ret;
}
int ret;
opaque *pdata;
gnutls_cert *apr_cert_list;
- gnutls_privkey* apr_pkey;
+ gnutls_privkey *apr_pkey;
int apr_cert_list_length;
/* find the appropriate certificate */
if ((ret =
_gnutls_get_selected_cert(session, &apr_cert_list,
- &apr_cert_list_length,
- &apr_pkey)) < 0) {
+ &apr_cert_list_length,
+ &apr_pkey)) < 0) {
gnutls_assert();
return ret;
}
size_t fpr_size;
opaque *pdata;
gnutls_cert *apr_cert_list;
- gnutls_privkey* apr_pkey;
+ gnutls_privkey *apr_pkey;
int apr_cert_list_length;
/* find the appropriate certificate */
if ((ret =
_gnutls_get_selected_cert(session, &apr_cert_list,
- &apr_cert_list_length,
- &apr_pkey)) < 0) {
+ &apr_cert_list_length,
+ &apr_pkey)) < 0) {
gnutls_assert();
return ret;
}
/* Process server certificate
*/
-#define CLEAR_CERTS for(x=0;x<peer_certificate_list_size;x++) _gnutls_free_cert(&peer_certificate_list[x])
+#define CLEAR_CERTS for(x=0;x<peer_certificate_list_size;x++) _gnutls_cert_deinit(&peer_certificate_list[x])
int _gnutls_proc_x509_server_certificate(gnutls_session session,
opaque * data, size_t data_size)
{
if ((ret =
_gnutls_x509_cert2gnutls_cert(&peer_certificate_list
[j], &tmp,
- CERT_ONLY_EXTENSIONS)) < 0) {
+ CERT_ONLY_EXTENSIONS)) <
+ 0) {
gnutls_assert();
goto cleanup;
}
if ((ret =
- _gnutls_copy_certificate_auth_info(info,
+ _gnutls_copy_certificate_auth_info(info,
peer_certificate_list,
- peer_certificate_list_size)) < 0) {
+ peer_certificate_list_size))
+ < 0) {
gnutls_assert();
goto cleanup;
}
if ((ret =
_gnutls_check_key_usage(&peer_certificate_list[0],
- gnutls_kx_get(session))) < 0) {
+ gnutls_kx_get(session))) < 0) {
gnutls_assert();
goto cleanup;
}
ret = 0;
-cleanup:
+ cleanup:
CLEAR_CERTS;
gnutls_free(peer_certificate_list);
return ret;
}
-#define CLEAR_CERTS for(x=0;x<peer_certificate_list_size;x++) _gnutls_free_cert(&peer_certificate_list[x])
+#define CLEAR_CERTS for(x=0;x<peer_certificate_list_size;x++) _gnutls_cert_deinit(&peer_certificate_list[x])
int _gnutls_proc_openpgp_server_certificate(gnutls_session session,
opaque * data,
size_t data_size)
if ((ret =
_gnutls_copy_certificate_auth_info(info,
- peer_certificate_list,
- peer_certificate_list_size)) < 0) {
+ peer_certificate_list,
+ peer_certificate_list_size))
+ < 0) {
gnutls_assert();
goto cleanup;
}
if ((ret =
_gnutls_check_key_usage(&peer_certificate_list[0],
- gnutls_kx_get(session))) < 0) {
+ gnutls_kx_get(session))) < 0) {
gnutls_assert();
goto cleanup;
}
ret = 0;
-
-cleanup:
+
+ cleanup:
_gnutls_free_datum(&akey);
CLEAR_CERTS;
gnutls_afree(peer_certificate_list);
return ret;
-
+
}
int _gnutls_proc_cert_server_certificate(gnutls_session session,
const gnutls_certificate_credentials cred;
CERTIFICATE_AUTH_INFO info;
ssize_t dsize = data_size;
- int i, j, ind;
+ int i, j;
gnutls_pk_algorithm pk_algos[MAX_SIGN_ALGOS];
int pk_algos_length;
*/
if ((ret =
_select_client_cert(session, p, size,
- &ind, pk_algos,
- pk_algos_length)) < 0) {
+ pk_algos, pk_algos_length)) < 0) {
gnutls_assert();
return ret;
}
- /* put the index of the client certificate to use
- */
- if (ind >= 0) {
- session->internals.selected_cert_list_length = cred->cert_list_length[ind];
- session->internals.selected_cert_list = &cred->cert_list[ind][0];
- session->internals.selected_key = &cred->pkey[ind];
- } else {
- session->internals.selected_cert_list_length = 0;
- session->internals.selected_cert_list = NULL;
- session->internals.selected_key = NULL;
- }
/* We should reply with a certificate message,
* even if we have no certificate to send.
{
int ret;
gnutls_cert *apr_cert_list;
- gnutls_privkey* apr_pkey;
+ gnutls_privkey *apr_pkey;
int apr_cert_list_length, size;
gnutls_datum signature;
/* find the appropriate certificate */
if ((ret =
_gnutls_get_selected_cert(session, &apr_cert_list,
- &apr_cert_list_length,
- &apr_pkey)) < 0) {
+ &apr_cert_list_length,
+ &apr_pkey)) < 0) {
gnutls_assert();
return ret;
}
if (apr_pkey != NULL) {
if ((ret =
_gnutls_tls_sign_hdata(session,
- &apr_cert_list[0],
- apr_pkey,
- &signature)) < 0) {
+ &apr_cert_list[0],
+ apr_pkey, &signature)) < 0) {
gnutls_assert();
return ret;
}
if ((ret =
_gnutls_verify_sig_hdata(session, &peer_cert, &sig)) < 0) {
gnutls_assert();
- _gnutls_free_cert(&peer_cert);
+ _gnutls_cert_deinit(&peer_cert);
return ret;
}
- _gnutls_free_cert(&peer_cert);
+ _gnutls_cert_deinit(&peer_cert);
return 0;
}
*/
if (session->security_parameters.cert_type == GNUTLS_CRT_X509 &&
- session->internals.ignore_rdn_sequence == 0)
+ session->internals.ignore_rdn_sequence == 0)
size += cred->x509_rdn_sequence.size;
(*data) = gnutls_malloc(size);
pdata += CERTTYPE_SIZE;
if (session->security_parameters.cert_type == GNUTLS_CRT_X509 &&
- session->internals.ignore_rdn_sequence == 0) {
+ session->internals.ignore_rdn_sequence == 0) {
_gnutls_write_datum16(pdata, cred->x509_rdn_sequence);
/* pdata += cred->x509_rdn_sequence.size + 2; */
}
*
*/
int _gnutls_get_selected_cert(gnutls_session session,
- gnutls_cert ** apr_cert_list,
- int *apr_cert_list_length,
- gnutls_privkey ** apr_pkey)
+ gnutls_cert ** apr_cert_list,
+ int *apr_cert_list_length,
+ gnutls_privkey ** apr_pkey)
{
if (session->security_parameters.entity == GNUTLS_SERVER) {
*apr_cert_list = session->internals.selected_cert_list;
*apr_pkey = session->internals.selected_key;
- *apr_cert_list_length = session->internals.selected_cert_list_length;
+ *apr_cert_list_length =
+ session->internals.selected_cert_list_length;
- if ( apr_cert_list_length == 0 || apr_pkey == NULL ||
- apr_cert_list == NULL)
- {
+ if (apr_cert_list_length == 0 || apr_pkey == NULL ||
+ apr_cert_list == NULL) {
gnutls_assert();
return GNUTLS_E_INSUFFICIENT_CREDENTIALS;
}
- } else { /* CLIENT SIDE
- */
+ } else { /* CLIENT SIDE
+ */
/* we have already decided which certificate
* to send.
*/
*apr_cert_list = session->internals.selected_cert_list;
- *apr_cert_list_length = session->internals.selected_cert_list_length;
+ *apr_cert_list_length =
+ session->internals.selected_cert_list_length;
*apr_pkey = session->internals.selected_key;
}
return 0;
}
+/* converts the given raw certificate to gnutls_cert* and allocates
+ * space for them.
+ */
+static gnutls_cert *alloc_and_load_certs(const gnutls_datum * certs,
+ uint ncerts,
+ gnutls_certificate_type type)
+{
+ gnutls_cert *local_certs;
+ int ret = 0;
+ uint i, j;
+
+ local_certs = gnutls_malloc(sizeof(gnutls_cert) * ncerts);
+ if (local_certs == NULL) {
+ gnutls_assert();
+ return NULL;
+ }
+
+ for (i = 0; i < ncerts; i++) {
+ ret = _gnutls_cert2gnutls_cert(&local_certs[i], type,
+ &certs[i], 0);
+ if (ret < 0)
+ break;
+ }
+
+ if (ret < 0) {
+ gnutls_assert();
+ for (j = 0; j < i; j++) {
+ _gnutls_cert_deinit(&local_certs[j]);
+ }
+ gnutls_free(local_certs);
+ return NULL;
+ }
+
+ return local_certs;
+}
+
+/* converts the given raw key to gnutls_privkey* and allocates
+ * space for it.
+ */
+static gnutls_privkey *alloc_and_load_key(const gnutls_datum * raw_key,
+ gnutls_certificate_type type)
+{
+ gnutls_privkey *local_key;
+ int ret = 0;
+
+ local_key = gnutls_malloc(sizeof(gnutls_privkey));
+ if (local_key == NULL) {
+ gnutls_assert();
+ return NULL;
+ }
+
+ ret =
+ _gnutls_key2gnutls_key(local_key, type, raw_key,
+ GNUTLS_X509_FMT_DER);
+ if (ret < 0) {
+ gnutls_assert();
+ return NULL;
+ }
+
+ return local_key;
+}
+
+void _gnutls_selected_certs_deinit(gnutls_session session)
+{
+ if (session->internals.selected_need_free != 0) {
+ int i;
+
+ for (i = 0;
+ i < session->internals.selected_cert_list_length;
+ i++) {
+ _gnutls_cert_deinit(&session->internals.
+ selected_cert_list[i]);
+ }
+ session->internals.selected_cert_list = NULL;
+ session->internals.selected_cert_list_length = 0;
+
+ _gnutls_privkey_deinit(session->internals.selected_key);
+ }
+
+ return;
+}
+
+void _gnutls_selected_certs_set(gnutls_session session,
+ gnutls_cert * certs, int ncerts,
+ gnutls_privkey * key, int need_free)
+{
+ _gnutls_selected_certs_deinit(session);
+
+ session->internals.selected_cert_list = certs;
+ session->internals.selected_cert_list_length = ncerts;
+ session->internals.selected_key = key;
+ session->internals.selected_need_free = need_free;
+
+}
+
+
/* finds the most appropriate certificate in the cert list.
* The 'appropriate' is defined by the user.
*
*
*/
int _gnutls_server_select_cert(gnutls_session session,
- gnutls_pk_algorithm requested_algo)
+ gnutls_pk_algorithm requested_algo)
{
uint i, j;
int index, ret;
}
- if (session->internals.server_cert_callback != NULL && cred->ncerts > 0) {
+ /* If the callback which retrieves certificate has been
+ * set use it.
+ */
+ if (session->internals.server_get_cert_callback != NULL) {
+ gnutls_datum *certs, key;
+ uint ncerts;
+ gnutls_certificate_type type =
+ gnutls_certificate_type_get(session);
+ gnutls_cert *local_certs = NULL;
+ gnutls_privkey *local_key = NULL;
+
+ ret =
+ session->internals.server_get_cert_callback(session,
+ &certs,
+ &ncerts,
+ &key);
+ if (ret < 0) {
+ gnutls_assert();
+ return GNUTLS_E_INTERNAL_ERROR;
+ }
+
+ local_certs = alloc_and_load_certs(certs, ncerts, type);
+ if (local_certs != NULL)
+ local_key = alloc_and_load_key(&key, type);
+
+ for (i = 0; i < ncerts; i++) {
+ _gnutls_free_datum(&certs[i]);
+ }
+ _gnutls_free_datum(&key);
+
+ _gnutls_selected_certs_set(session, local_certs, ncerts,
+ local_key, 1);
+
+ return 0;
+
+ } else if (session->internals.server_cert_callback != NULL
+ && cred->ncerts > 0) {
/* use the callback to get certificate
*/
gnutls_datum *my_certs;
ret = 0;
gnutls_free(ij_map);
- cleanup_certs:
+ cleanup_certs:
gnutls_free(my_certs);
}
- out:
+ out:
/* store the index for future use, in the handshake.
* (This will allow not calling this callback again.)
*/
if (index >= 0 && ret == 0) {
- session->internals.selected_cert_list = &cred->cert_list[index][0];
- session->internals.selected_cert_list_length = cred->cert_list_length[index];
- session->internals.selected_key = &cred->pkey[index];
+ _gnutls_selected_certs_set(session,
+ &cred->cert_list[index][0],
+ cred->cert_list_length[index],
+ &cred->pkey[index], 0);
}
return ret;
for (i = 0; i < sc->ncerts; i++) {
for (j = 0; j < sc->cert_list_length[i]; j++) {
- _gnutls_free_cert( &sc->cert_list[i][j]);
+ _gnutls_cert_deinit( &sc->cert_list[i][j]);
}
gnutls_free( sc->cert_list[i]);
}
* the raw certificates (DER for X.509 or binary for OpenPGP), of the
* client.
*
- * @req_ca_cert, is only used in X.509 certificates.
+ * @req_ca_dn, is only used in X.509 certificates.
* Contains a list with the CA names that the server considers trusted.
* Normally we should send a certificate that is signed
* by one of these CAs. These names are DER encoded. To get a more
session->internals.server_cert_callback = func;
}
+/**
+ * gnutls_certificate_client_set_retrieve_function - Used to set a callback to retrieve the certificate
+ * @session: is a &gnutls_session structure.
+ * @func: is the callback function
+ *
+ * This function sets a callback to be called in order to retrieve the certificate
+ * to be used in the handshake.
+ * The callback's function prototype is:
+ * int (*callback)(gnutls_session, const gnutls_datum* req_ca_dn, int nreqs,
+ * gnutls_datum **cert, unsigned int *ncerts, gnutls_key* key);
+ *
+ * @cert should contain @ncerts gnutls_datum structures which hold
+ * the raw certificates (DER for X.509 or binary for OpenPGP), of the
+ * client. Those should be allocated with gnutls_malloc(). The certificate
+ * type to be sent should be obtained using gnutls_certificate_type_get();
+ *
+ * @key should contain a private key.
+ *
+ * @req_ca_cert, is only used in X.509 certificates.
+ * Contains a list with the CA names that the server considers trusted.
+ * Normally we should send a certificate that is signed
+ * by one of these CAs. These names are DER encoded. To get a more
+ * meaningful value use the function gnutls_x509_rdn_get().
+ *
+ * If the callback function is provided then gnutls will call it, in the
+ * handshake, after the certificate request message has been received.
+ *
+ * The callback function should set the certificate list to be sent, and
+ * return 0 on success. The value (-1) indicates error and the handshake
+ * will be terminated.
+ **/
+void gnutls_certificate_client_set_retrieve_function(gnutls_session session,
+ gnutls_certificate_client_retrieve_function * func)
+{
+ session->internals.client_get_cert_callback = func;
+}
+
+/**
+ * gnutls_certificate_server_set_retrieve_function - Used to set a callback to retrieve the certificate
+ * @session: is a &gnutls_session structure.
+ * @func: is the callback function
+ *
+ * This function sets a callback to be called in order to retrieve the certificate
+ * to be used in the handshake.
+ * The callback's function prototype is:
+ * int (*callback)(gnutls_session, gnutls_datum **cert, unsigned int *ncerts
+ * gnutls_key* key);
+ *
+ * @cert should contain @ncerts gnutls_datum structures which hold
+ * the raw certificates (DER for X.509 or binary for OpenPGP), of the
+ * server. Those should be allocated with gnutls_malloc(). The certificate
+ * type to be sent should be obtained using gnutls_certificate_type_get();
+ *
+ * @key should contain a private key.
+ *
+ * If the callback function is provided then gnutls will call it, in the
+ * handshake, after the certificate request message has been received.
+ *
+ * The callback function should set the certificate list to be sent, and
+ * return 0 on success. The value (-1) indicates error and the handshake
+ * will be terminated.
+ **/
+void gnutls_certificate_server_set_retrieve_function(gnutls_session session,
+ gnutls_certificate_server_retrieve_function * func)
+{
+ session->internals.server_get_cert_callback = func;
+}
+
+
/* These are set by the gnutls_extra library's initialization function.
*/
}
}
+/* in auth_dhe.c */
+OPENPGP_CERT2GNUTLS_CERT _E_gnutls_openpgp_cert2gnutls_cert;
+OPENPGP_KEY2GNUTLS_KEY _E_gnutls_openpgp_key2gnutls_key;
+
+int _gnutls_cert2gnutls_cert(gnutls_cert * gcert, gnutls_certificate_type type,
+ const gnutls_datum *raw_cert, int flags /* OR of ConvFlags */)
+{
+ switch( type) {
+ case GNUTLS_CRT_X509:
+ return _gnutls_x509_cert2gnutls_cert( gcert,
+ raw_cert, flags);
+ case GNUTLS_CRT_OPENPGP:
+ if (_E_gnutls_openpgp_cert2gnutls_cert==NULL) {
+ gnutls_assert();
+ return GNUTLS_E_INIT_LIBEXTRA;
+ }
+ return
+ _E_gnutls_openpgp_cert2gnutls_cert( gcert,
+ raw_cert);
+ default:
+ gnutls_assert();
+ return GNUTLS_E_INTERNAL_ERROR;
+ }
+}
+
+int _gnutls_key2gnutls_key(gnutls_privkey * key, gnutls_certificate_type type,
+ const gnutls_datum *raw_key, int key_enc /* DER or PEM */)
+{
+ switch( type) {
+ case GNUTLS_CRT_X509:
+ return _gnutls_x509_key2gnutls_key( key,
+ raw_key, key_enc);
+ case GNUTLS_CRT_OPENPGP:
+ if (_E_gnutls_openpgp_key2gnutls_key==NULL) {
+ gnutls_assert();
+ return GNUTLS_E_INIT_LIBEXTRA;
+ }
+ return
+ _E_gnutls_openpgp_key2gnutls_key( key, raw_key);
+ default:
+ gnutls_assert();
+ return GNUTLS_E_INTERNAL_ERROR;
+ }
+}
+
/* This function will convert a der certificate to a format
* (structure) that gnutls can understand and use. Actually the
}
-void _gnutls_free_cert(gnutls_cert *cert)
+void _gnutls_cert_deinit(gnutls_cert *cert)
{
int i;
+ if (cert == NULL) return;
+
for (i = 0; i < cert->params_size; i++) {
_gnutls_mpi_release( &cert->params[i]);
}