APIMANS += gnutls_priority_set_direct.3
APIMANS += gnutls_set_default_priority.3
APIMANS += gnutls_set_default_export_priority.3
+APIMANS += gnutls_privkey_sign_data.3
APIMANS += gnutls_psk_free_client_credentials.3
APIMANS += gnutls_psk_allocate_client_credentials.3
APIMANS += gnutls_psk_set_client_credentials.3
APIMANS += gnutls_certificate_set_x509_simple_pkcs12_file.3
APIMANS += gnutls_certificate_set_x509_simple_pkcs12_mem.3
APIMANS += gnutls_certificate_free_crls.3
+APIMANS += gnutls_pkcs11_privkey_sign_data.3
+APIMANS += gnutls_pkcs11_privkey_decrypt_data.3
APIMANS += gnutls_pem_base64_encode.3
APIMANS += gnutls_pem_base64_encode_alloc.3
APIMANS += gnutls_pem_base64_decode.3
APIMANS += gnutls_x509_privkey_export_dsa_raw.3
APIMANS += gnutls_x509_privkey_generate.3
APIMANS += gnutls_x509_privkey_get_key_id.3
-APIMANS += gnutls_x509_privkey_sign_data.3
+APIMANS += gnutls_x509_privkey_sign_data2.3
APIMANS += gnutls_x509_privkey_sign_hash.3
+APIMANS += gnutls_x509_privkey_sign_data.3
APIMANS += gnutls_x509_privkey_verify_data.3
APIMANS += gnutls_x509_privkey_fix.3
APIMANS += gnutls_x509_privkey_export_pkcs8.3
APIMANS += gnutls_certificate_set_openpgp_keyring_mem.3
APIMANS += gnutls_openpgp_set_recv_key_function.3
APIMANS += gnutls_openpgp_privkey_sign_hash.3
+APIMANS += gnutls_openpgp_privkey_decrypt_data.3
APIMANS += gnutls_openpgp_crt_print.3
APIMANS += gnutls_openpgp_crt_init.3
APIMANS += gnutls_openpgp_crt_deinit.3
auth_dh_common.c gnutls_helper.c gnutls_supplemental.c \
crypto.c random.c pk-libgcrypt.c mpi-libgcrypt.c cryptodev.c \
rnd-libgcrypt.c cipher-libgcrypt.c mac-libgcrypt.c ext_signature.c \
- crypto-api.c ext_safe_renegotiation.c gnutls_mbuffers.c
+ crypto-api.c ext_safe_renegotiation.c gnutls_mbuffers.c gnutls_privkey.c
if ENABLE_PKCS11
-COBJECTS += pkcs11.c
+COBJECTS += pkcs11.c pkcs11_privkey.c
endif
if ENABLE_OPRFI
#include <gnutls_state.h>
#include <gnutls_pk.h>
#include <gnutls_x509.h>
+#include <gnutls/privkey.h>
#include "debug.h"
#ifdef ENABLE_OPENPGP
# include "openpgp/gnutls_openpgp.h"
-static gnutls_privkey *alloc_and_load_pgp_key (const gnutls_openpgp_privkey_t
- key);
+static gnutls_privkey_t alloc_and_load_pgp_key (const gnutls_openpgp_privkey_t
+ key, int deinit);
static gnutls_cert *alloc_and_load_pgp_certs (gnutls_openpgp_crt_t cert);
#endif
static gnutls_cert *alloc_and_load_x509_certs (gnutls_x509_crt_t * certs,
unsigned);
-static gnutls_privkey *alloc_and_load_x509_key (gnutls_x509_privkey_t key);
+static gnutls_privkey_t alloc_and_load_x509_key (gnutls_x509_privkey_t key, int deinit);
+static gnutls_privkey_t alloc_and_load_pkcs11_key ( gnutls_pkcs11_privkey_t key, int deinit);
/* Copies data from a internal certificate struct (gnutls_cert) to
return 0;
}
+static void st_to_st2(gnutls_retr2_st *st2, gnutls_retr_st* st)
+{
+ st2->cert_type = st->type;
+ if (st->type == GNUTLS_CRT_OPENPGP) {
+ st2->key_type = GNUTLS_PRIVKEY_OPENPGP;
+ } else {
+ st2->key_type = GNUTLS_PRIVKEY_X509;
+ }
+ st2->ncerts = st->ncerts;
+ st2->deinit_all = st->deinit_all;
+
+ switch(st2->cert_type) {
+ case GNUTLS_CRT_OPENPGP:
+ st2->cert.pgp = st->cert.pgp;
+ st2->key.pgp = st->key.pgp;
+ break;
+ case GNUTLS_CRT_X509:
+ st2->cert.x509 = st->cert.x509;
+ st2->key.x509 = st->key.x509;
+ break;
+ default:
+ return;
+ }
+
+}
+
/* Calls the client get callback.
*/
static int
call_get_cert_callback (gnutls_session_t session,
- gnutls_datum_t * issuers_dn,
+ const gnutls_datum_t * issuers_dn,
int issuers_dn_length,
gnutls_pk_algorithm_t * pk_algos, int pk_algos_length)
{
unsigned i;
gnutls_cert *local_certs = NULL;
- gnutls_privkey *local_key = NULL;
- gnutls_retr_st st;
+ 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;
cred = (gnutls_certificate_credentials_t)
_gnutls_get_cred (session->key, GNUTLS_CRD_CERTIFICATE, NULL);
return GNUTLS_E_INSUFFICIENT_CREDENTIALS;
}
- memset (&st, 0, sizeof (st));
+ memset (&st2, 0, sizeof (st2));
- if (session->security_parameters.entity == GNUTLS_SERVER)
- {
- if (cred->server_get_cert_callback == NULL)
+ if (cred->get_cert_callback)
{
- gnutls_assert ();
- return GNUTLS_E_INTERNAL_ERROR;
+ ret = cred->get_cert_callback( session, issuers_dn, issuers_dn_length,
+ pk_algos, pk_algos_length, &st2);
+
}
- ret = cred->server_get_cert_callback (session, &st);
- }
else
- { /* CLIENT */
- if (cred->client_get_cert_callback == NULL)
- {
- gnutls_assert ();
- return GNUTLS_E_INTERNAL_ERROR;
+ { /* compatibility mode */
+ gnutls_retr_st st;
+ memset (&st, 0, sizeof (st));
+ if (session->security_parameters.entity == GNUTLS_SERVER)
+ {
+ if (cred->server_get_cert_callback == NULL)
+ {
+ gnutls_assert ();
+ return GNUTLS_E_INTERNAL_ERROR;
+ }
+ ret = cred->server_get_cert_callback (session, &st);
+ if (ret >= 0) st_to_st2(&st2, &st);
+ }
+ else
+ { /* CLIENT */
+
+ if (cred->client_get_cert_callback == NULL)
+ {
+ gnutls_assert ();
+ return GNUTLS_E_INTERNAL_ERROR;
+ }
+ ret = cred->client_get_cert_callback (session,
+ issuers_dn, issuers_dn_length,
+ pk_algos, pk_algos_length, &st);
+ if (ret >= 0) st_to_st2(&st2, &st);
+ }
}
- ret =
- cred->client_get_cert_callback (session,
- issuers_dn, issuers_dn_length,
- pk_algos, pk_algos_length, &st);
- }
if (ret < 0)
{
return GNUTLS_E_INTERNAL_ERROR;
}
- if (st.ncerts == 0)
+ if (st2.ncerts == 0)
return 0; /* no certificate was selected */
- if (type != st.type)
+ 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 (st.cert.x509, st.ncerts);
- if (local_certs != NULL && st.key.x509 != NULL)
- {
- local_key = alloc_and_load_x509_key (st.key.x509);
- if (local_key == NULL)
- {
- gnutls_assert ();
- ret = GNUTLS_E_INTERNAL_ERROR;
- goto cleanup;
- }
- }
-
+ local_certs = alloc_and_load_x509_certs (st2.cert.x509, st2.ncerts);
}
else
{ /* PGP */
- if (st.ncerts > 1)
- {
- gnutls_assert ();
- ret = GNUTLS_E_INVALID_REQUEST;
- goto cleanup;
- }
-
+ if (st2.ncerts > 1)
+ {
+ gnutls_assert ();
+ ret = GNUTLS_E_INVALID_REQUEST;
+ goto cleanup;
+ }
#ifdef ENABLE_OPENPGP
- {
- local_certs = alloc_and_load_pgp_certs (st.cert.pgp);
- if (local_certs != NULL && st.key.pgp != NULL)
{
- local_key = alloc_and_load_pgp_key (st.key.pgp);
- if (local_key == NULL)
- {
- gnutls_assert ();
- ret = GNUTLS_E_INTERNAL_ERROR;
- goto cleanup;
- }
- }
+ local_certs = alloc_and_load_pgp_certs (st2.cert.pgp);
}
+#else
+ ret = GNUTLS_E_UNIMPLEMENTED_FEATURE;
+ goto cleanup;
#endif
}
+ if (local_certs == NULL) {
+ gnutls_assert();
+ ret = GNUTLS_E_MEMORY_ERROR;
+ goto cleanup;
+ }
+
+ switch(st2.key_type) {
+ case GNUTLS_PRIVKEY_OPENPGP:
+#ifdef ENABLE_OPENPGP
+ if (st2.key.pgp != NULL)
+ {
+ local_key = alloc_and_load_pgp_key (st2.key.pgp, st2.deinit_all);
+ if (local_key == NULL)
+ {
+ gnutls_assert ();
+ ret = GNUTLS_E_INTERNAL_ERROR;
+ goto cleanup;
+ }
+ }
+ break;
+#endif
+ 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;
+ 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;
+ }
+
_gnutls_selected_certs_set (session, local_certs,
- (local_certs != NULL) ? st.ncerts : 0,
+ (local_certs != NULL) ? st2.ncerts : 0,
local_key, 1);
ret = 0;
cleanup:
- if (st.type == GNUTLS_CRT_X509)
+ if (st2.cert_type == GNUTLS_CRT_X509)
{
- if (st.deinit_all)
- {
- for (i = 0; i < st.ncerts; i++)
- {
- gnutls_x509_crt_deinit (st.cert.x509[i]);
- }
- gnutls_free (st.cert.x509);
- gnutls_x509_privkey_deinit (st.key.x509);
- }
+ if (st2.deinit_all)
+ {
+ for (i = 0; i < st2.ncerts; i++)
+ {
+ gnutls_x509_crt_deinit (st2.cert.x509[i]);
+ }
+ }
}
else
{
#ifdef ENABLE_OPENPGP
- if (st.deinit_all)
- {
- gnutls_openpgp_crt_deinit (st.cert.pgp);
- gnutls_openpgp_privkey_deinit (st.key.pgp);
- }
+ if (st2.deinit_all)
+ {
+ gnutls_openpgp_crt_deinit (st2.cert.pgp);
+ }
#endif
}
+
+ if (ret < 0)
+ {
+ if (local_key != NULL)
+ gnutls_privkey_deinit(local_key);
+ }
return ret;
}
return GNUTLS_E_INSUFFICIENT_CREDENTIALS;
}
- if (cred->client_get_cert_callback != NULL)
+ if (cred->client_get_cert_callback != NULL || cred->get_cert_callback != NULL)
{
/* use a callback to get certificate
_gnutls_selected_certs_set (session,
&cred->cert_list[indx][0],
cred->cert_list_length[indx],
- &cred->pkey[indx], 0);
+ cred->pkey[indx], 0);
}
else
{
int ret, i;
opaque *pdata;
gnutls_cert *apr_cert_list;
- gnutls_privkey *apr_pkey;
+ gnutls_privkey_t apr_pkey;
int apr_cert_list_length;
/* find the appropriate certificate
int ret;
opaque *pdata;
gnutls_cert *apr_cert_list;
- gnutls_privkey *apr_pkey;
+ gnutls_privkey_t apr_pkey;
int apr_cert_list_length;
/* find the appropriate certificate */
size_t fpr_size;
opaque *pdata;
gnutls_cert *apr_cert_list;
- gnutls_privkey *apr_pkey;
+ gnutls_privkey_t apr_pkey;
int apr_cert_list_length;
/* find the appropriate certificate */
{
int ret;
gnutls_cert *apr_cert_list;
- gnutls_privkey *apr_pkey;
+ gnutls_privkey_t apr_pkey;
int apr_cert_list_length, size;
gnutls_datum_t signature;
int total_data;
_gnutls_get_selected_cert (gnutls_session_t session,
gnutls_cert ** apr_cert_list,
int *apr_cert_list_length,
- gnutls_privkey ** apr_pkey)
+ gnutls_privkey_t * apr_pkey)
{
if (session->security_parameters.entity == GNUTLS_SERVER)
{
/* converts the given x509 key to gnutls_privkey* and allocates
* space for it.
*/
-static gnutls_privkey *
-alloc_and_load_x509_key (gnutls_x509_privkey_t key)
+static gnutls_privkey_t
+alloc_and_load_x509_key (gnutls_x509_privkey_t key, int deinit)
{
- gnutls_privkey *local_key;
+ gnutls_privkey_t local_key;
int ret = 0;
if (key == NULL)
return NULL;
- local_key = gnutls_malloc (sizeof (gnutls_privkey));
- if (local_key == NULL)
+ ret = gnutls_privkey_init(&local_key);
+ if (ret < 0)
{
gnutls_assert ();
return NULL;
}
- ret = _gnutls_x509_privkey_to_gkey (local_key, key);
+ 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;
}
/* converts the given raw key to gnutls_privkey* and allocates
* space for it.
*/
-static gnutls_privkey *
-alloc_and_load_pgp_key (const gnutls_openpgp_privkey_t key)
+static gnutls_privkey_t
+alloc_and_load_pgp_key ( gnutls_openpgp_privkey_t key, int deinit)
{
- gnutls_privkey *local_key;
+ gnutls_privkey_t local_key;
int ret = 0;
if (key == NULL)
return NULL;
- local_key = gnutls_malloc (sizeof (gnutls_privkey));
- if (local_key == NULL)
+ ret = gnutls_privkey_init(&local_key);
+ if (ret < 0)
{
gnutls_assert ();
return NULL;
}
- ret = _gnutls_openpgp_privkey_to_gkey (local_key, key);
+ ret = gnutls_privkey_import_openpgp (local_key, key, deinit?GNUTLS_PRIVKEY_IMPORT_AUTO_RELEASE:0);
if (ret < 0)
{
gnutls_assert ();
+ gnutls_privkey_deinit(local_key);
return NULL;
}
}
#endif
+/* 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;
+}
+
void
_gnutls_selected_certs_deinit (gnutls_session_t session)
{
session->internals.selected_cert_list = NULL;
session->internals.selected_cert_list_length = 0;
- _gnutls_gkey_deinit (session->internals.selected_key);
- if (session->internals.selected_key)
- {
- gnutls_free (session->internals.selected_key);
- session->internals.selected_key = NULL;
- }
+ session->internals.selected_key = NULL;
}
return;
void
_gnutls_selected_certs_set (gnutls_session_t session,
gnutls_cert * certs, int ncerts,
- gnutls_privkey * key, int need_free)
+ gnutls_privkey_t key, int need_free)
{
_gnutls_selected_certs_deinit (session);
_gnutls_selected_certs_set (session,
&cred->cert_list[idx][0],
cred->cert_list_length[idx],
- &cred->pkey[idx], 0);
+ cred->pkey[idx], 0);
}
else
/* Certificate does not support REQUESTED_ALGO. */
# include "auth_dh_common.h"
# include "x509/x509_int.h"
# include "openpgp/openpgp_int.h"
+# include <gnutls/privkey.h>
+# include <gnutls/compat.h>
/* This structure may be complex, but it's the only way to
* support a server that has multiple certificates
* This is the same with the number of pkeys.
*/
- gnutls_privkey *pkey;
+ gnutls_privkey_t *pkey;
/* private keys. It contains ncerts private
* keys. pkey[i] corresponds to certificate in
* cert_list[i][0].
*/
gnutls_datum_t x509_rdn_sequence;
- gnutls_certificate_client_retrieve_function *client_get_cert_callback;
- gnutls_certificate_server_retrieve_function *server_get_cert_callback;
+ gnutls_certificate_client_retrieve_function *client_get_cert_callback; /* deprecated */
+ gnutls_certificate_server_retrieve_function *server_get_cert_callback; /* deprecated */
gnutls_certificate_verify_function *verify_callback;
+
+ gnutls_certificate_retrieve_function *get_cert_callback;
} certificate_credentials_st;
typedef struct rsa_info_st
int _gnutls_get_selected_cert (gnutls_session_t session,
gnutls_cert ** apr_cert_list,
int *apr_cert_list_length,
- gnutls_privkey ** apr_pkey);
+ gnutls_privkey_t * apr_pkey);
int _gnutls_server_select_cert (struct gnutls_session_int *,
gnutls_pk_algorithm_t);
void _gnutls_selected_certs_deinit (gnutls_session_t session);
void _gnutls_selected_certs_set (gnutls_session_t session,
gnutls_cert * certs, int ncerts,
- gnutls_privkey * key, int need_free);
+ gnutls_privkey_t key, int need_free);
#define _gnutls_proc_cert_client_certificate _gnutls_proc_cert_server_certificate
const bigint_t *mpis;
int ret = 0, data_size;
gnutls_cert *apr_cert_list;
- gnutls_privkey *apr_pkey;
+ gnutls_privkey_t apr_pkey;
int apr_cert_list_length;
gnutls_datum_t signature, ddata;
gnutls_certificate_credentials_t cred;
#include <gnutls_mpi.h>
int _gnutls_gen_rsa_client_kx (gnutls_session_t, opaque **);
-int _gnutls_proc_rsa_client_kx (gnutls_session_t, opaque *, size_t);
+static int proc_rsa_client_kx (gnutls_session_t, opaque *, size_t);
const mod_auth_st rsa_auth_struct = {
"RSA",
_gnutls_proc_cert_server_certificate,
_gnutls_proc_cert_client_certificate,
NULL, /* proc server kx */
- _gnutls_proc_rsa_client_kx, /* proc client kx */
+ proc_rsa_client_kx, /* proc client kx */
_gnutls_proc_cert_client_cert_vrfy, /* proc client cert vrfy */
_gnutls_proc_cert_cert_req /* proc server cert request */
};
return 0;
}
-/* This function reads the RSA parameters from the private key
- */
static int
-_gnutls_get_private_rsa_params (gnutls_session_t session,
- bigint_t ** params, int *params_size)
-{
- int bits;
- gnutls_certificate_credentials_t cred;
- gnutls_rsa_params_t rsa_params;
-
- cred = (gnutls_certificate_credentials_t)
- _gnutls_get_cred (session->key, GNUTLS_CRD_CERTIFICATE, NULL);
- if (cred == NULL)
- {
- gnutls_assert ();
- return GNUTLS_E_INSUFFICIENT_CREDENTIALS;
- }
-
- if (session->internals.selected_cert_list == NULL)
- {
- gnutls_assert ();
- return GNUTLS_E_INSUFFICIENT_CREDENTIALS;
- }
-
- bits =
- _gnutls_mpi_get_nbits (session->internals.
- selected_cert_list[0].params[0]);
-
- if (_gnutls_cipher_suite_get_kx_algo
- (&session->security_parameters.current_cipher_suite)
- == GNUTLS_KX_RSA_EXPORT && bits > 512)
- {
-
- rsa_params =
- _gnutls_certificate_get_rsa_params (cred->rsa_params,
- cred->params_func, session);
- /* EXPORT case: */
- if (rsa_params == NULL)
- {
- gnutls_assert ();
- return GNUTLS_E_NO_TEMPORARY_RSA_PARAMS;
- }
-
- /* In the export case, we do use temporary RSA params
- * of 512 bits size. The params in the certificate are
- * used to sign this temporary stuff.
- */
- *params_size = RSA_PRIVATE_PARAMS;
- *params = rsa_params->params;
-
- return 0;
- }
-
- /* non export cipher suites. */
-
- *params_size = session->internals.selected_key->params_size;
- *params = session->internals.selected_key->params;
-
- return 0;
-}
-
-int
-_gnutls_proc_rsa_client_kx (gnutls_session_t session, opaque * data,
+proc_rsa_client_kx (gnutls_session_t session, opaque * data,
size_t _data_size)
{
gnutls_datum_t plaintext;
gnutls_datum_t ciphertext;
int ret, dsize;
- bigint_t *params;
- int params_len;
int randomize_key = 0;
ssize_t data_size = _data_size;
ciphertext.size = dsize;
}
- ret = _gnutls_get_private_rsa_params (session, ¶ms, ¶ms_len);
- if (ret < 0)
- {
- gnutls_assert ();
- return ret;
- }
-
- ret = _gnutls_pkcs1_rsa_decrypt (&plaintext, &ciphertext, params, params_len, 2); /* btype==2 */
+ ret = gnutls_privkey_decrypt_data (session->internals.selected_key, 0, &ciphertext, &plaintext);
if (ret < 0 || plaintext.size != GNUTLS_MASTER_SIZE)
{
#include <gnutls_x509.h>
#include <gnutls_rsa_export.h>
#include <gnutls_state.h>
+#include <random.h>
int _gnutls_gen_rsa_client_kx (gnutls_session_t, opaque **);
-int _gnutls_proc_rsa_client_kx (gnutls_session_t, opaque *, size_t);
static int gen_rsa_export_server_kx (gnutls_session_t, opaque **);
static int proc_rsa_export_server_kx (gnutls_session_t, opaque *, size_t);
+static int proc_rsa_export_client_kx (gnutls_session_t session, opaque * data,
+ size_t _data_size);
const mod_auth_st rsa_export_auth_struct = {
"RSA EXPORT",
_gnutls_proc_cert_server_certificate,
_gnutls_proc_cert_client_certificate,
proc_rsa_export_server_kx,
- _gnutls_proc_rsa_client_kx, /* proc client kx */
+ proc_rsa_export_client_kx, /* proc client kx */
_gnutls_proc_cert_client_cert_vrfy, /* proc client cert vrfy */
_gnutls_proc_cert_cert_req /* proc server cert request */
};
+/* This function reads the RSA parameters from the private key
+ */
+static int
+_gnutls_get_private_rsa_params (gnutls_session_t session,
+ bigint_t ** params, int *params_size)
+{
+ int bits;
+ gnutls_certificate_credentials_t cred;
+ gnutls_rsa_params_t rsa_params;
+
+ cred = (gnutls_certificate_credentials_t)
+ _gnutls_get_cred (session->key, GNUTLS_CRD_CERTIFICATE, NULL);
+ if (cred == NULL)
+ {
+ gnutls_assert ();
+ return GNUTLS_E_INSUFFICIENT_CREDENTIALS;
+ }
+
+ if (session->internals.selected_cert_list == NULL)
+ {
+ gnutls_assert ();
+ return GNUTLS_E_INSUFFICIENT_CREDENTIALS;
+ }
+
+ bits =
+ _gnutls_mpi_get_nbits (session->internals.
+ selected_cert_list[0].params[0]);
+
+ if (_gnutls_cipher_suite_get_kx_algo
+ (&session->security_parameters.current_cipher_suite)
+ != GNUTLS_KX_RSA_EXPORT || bits < 512)
+ {
+ gnutls_assert();
+ return GNUTLS_E_INVALID_REQUEST;
+ }
+
+ rsa_params =
+ _gnutls_certificate_get_rsa_params (cred->rsa_params,
+ cred->params_func, session);
+ /* EXPORT case: */
+ if (rsa_params == NULL)
+ {
+ gnutls_assert ();
+ return GNUTLS_E_NO_TEMPORARY_RSA_PARAMS;
+ }
+
+ /* In the export case, we do use temporary RSA params
+ * of 512 bits size. The params in the certificate are
+ * used to sign this temporary stuff.
+ */
+ *params_size = RSA_PRIVATE_PARAMS;
+ *params = rsa_params->params;
+
+ return 0;
+}
+
+int proc_rsa_export_client_kx (gnutls_session_t session, opaque * data,
+ size_t _data_size)
+{
+ gnutls_datum_t plaintext;
+ gnutls_datum_t ciphertext;
+ int ret, dsize;
+ bigint_t *params;
+ int params_len;
+ int randomize_key = 0;
+ ssize_t data_size = _data_size;
+
+ if (gnutls_protocol_get_version (session) == GNUTLS_SSL3)
+ {
+ /* SSL 3.0
+ */
+ ciphertext.data = data;
+ ciphertext.size = data_size;
+ }
+ else
+ {
+ /* TLS 1.0
+ */
+ DECR_LEN (data_size, 2);
+ ciphertext.data = &data[2];
+ dsize = _gnutls_read_uint16 (data);
+
+ if (dsize != data_size)
+ {
+ gnutls_assert ();
+ return GNUTLS_E_UNEXPECTED_PACKET_LENGTH;
+ }
+ ciphertext.size = dsize;
+ }
+
+ ret = _gnutls_get_private_rsa_params (session, ¶ms, ¶ms_len);
+ if (ret < 0)
+ {
+ gnutls_assert ();
+ return ret;
+ }
+
+ ret = _gnutls_pkcs1_rsa_decrypt (&plaintext, &ciphertext, params, params_len, 2); /* btype==2 */
+
+ if (ret < 0 || plaintext.size != GNUTLS_MASTER_SIZE)
+ {
+ /* In case decryption fails then don't inform
+ * the peer. Just use a random key. (in order to avoid
+ * attack against pkcs-1 formating).
+ */
+ gnutls_assert ();
+ _gnutls_x509_log ("auth_rsa: Possible PKCS #1 format attack\n");
+ randomize_key = 1;
+ }
+ else
+ {
+ /* If the secret was properly formatted, then
+ * check the version number.
+ */
+ if (_gnutls_get_adv_version_major (session) != plaintext.data[0]
+ || _gnutls_get_adv_version_minor (session) != plaintext.data[1])
+ {
+ /* No error is returned here, if the version number check
+ * fails. We proceed normally.
+ * That is to defend against the attack described in the paper
+ * "Attacking RSA-based sessions in SSL/TLS" by Vlastimil Klima,
+ * Ondej Pokorny and Tomas Rosa.
+ */
+ gnutls_assert ();
+ _gnutls_x509_log
+ ("auth_rsa: Possible PKCS #1 version check format attack\n");
+ }
+ }
+
+ if (randomize_key != 0)
+ {
+ session->key->key.size = GNUTLS_MASTER_SIZE;
+ session->key->key.data = gnutls_malloc (session->key->key.size);
+ if (session->key->key.data == NULL)
+ {
+ gnutls_assert ();
+ return GNUTLS_E_MEMORY_ERROR;
+ }
+
+ /* we do not need strong random numbers here.
+ */
+ ret = _gnutls_rnd (GNUTLS_RND_NONCE, session->key->key.data,
+ session->key->key.size);
+ if (ret < 0)
+ {
+ gnutls_assert ();
+ return ret;
+ }
+
+ }
+ else
+ {
+ session->key->key.data = plaintext.data;
+ session->key->key.size = plaintext.size;
+ }
+
+ /* This is here to avoid the version check attack
+ * discussed above.
+ */
+ session->key->key.data[0] = _gnutls_get_adv_version_major (session);
+ session->key->key.data[1] = _gnutls_get_adv_version_minor (session);
+
+ return 0;
+}
+
static int
gen_rsa_export_server_kx (gnutls_session_t session, opaque ** data)
{
uint8_t *data_e, *data_m;
int ret = 0, data_size;
gnutls_cert *apr_cert_list;
- gnutls_privkey *apr_pkey;
+ gnutls_privkey_t apr_pkey;
int apr_cert_list_length;
gnutls_datum_t signature, ddata;
gnutls_certificate_credentials_t cred;
gnutls_sign_algorithm_t sign_algo;
+ unsigned int bits = 0;
cred = (gnutls_certificate_credentials_t)
_gnutls_get_cred (session->key, GNUTLS_CRD_CERTIFICATE, NULL);
/* abort sending this message if we have a certificate
* of 512 bits or less.
*/
- if (apr_pkey && _gnutls_mpi_get_nbits (apr_pkey->params[0]) <= 512)
+ gnutls_privkey_get_pk_algorithm(apr_pkey, &bits);
+ if (apr_pkey && bits <= 512)
{
gnutls_assert ();
return GNUTLS_E_INT_RET_0;
gnutls_datum_t signature, ddata;
gnutls_certificate_credentials_t cred;
gnutls_cert *apr_cert_list;
- gnutls_privkey *apr_pkey;
+ gnutls_privkey_t apr_pkey;
int apr_cert_list_length;
gnutls_sign_algorithm_t sign_algo;
for (i = 0; i < sc->ncerts; i++)
{
- _gnutls_gkey_deinit (&sc->pkey[i]);
+ gnutls_privkey_deinit (sc->pkey[i]);
}
gnutls_free (sc->pkey);
cred->server_get_cert_callback = func;
}
+/**
+ * gnutls_certificate_set_retrieve_function:
+ * @cred: is a #gnutls_certificate_credentials_t 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_t, const gnutls_datum_t* req_ca_dn, int nreqs,
+ * const gnutls_pk_algorithm_t* pk_algos, int pk_algos_length, gnutls_retr2_st* st);
+ *
+ * @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().
+ *
+ * @pk_algos contains a list with server's acceptable signature algorithms.
+ * The certificate returned should support the server's given algorithms.
+ *
+ * @st should contain the certificates and private keys.
+ *
+ * If the callback function is provided then gnutls will call it, in the
+ * handshake, after the certificate request message has been received.
+ *
+ * In server side pk_algos and req_ca_dn are NULL.
+ *
+ * The callback function should set the certificate list to be sent,
+ * and return 0 on success. If no certificate was selected then the
+ * number of certificates should be set to zero. The value (-1)
+ * indicates error and the handshake will be terminated.
+ **/
+void gnutls_certificate_set_retrieve_function
+ (gnutls_certificate_credentials_t cred,
+ gnutls_certificate_retrieve_function * func)
+{
+ cred->get_cert_callback = func;
+}
+
/**
* gnutls_certificate_set_verify_function:
* @cred: is a #gnutls_certificate_credentials_t structure.
#endif
} gnutls_cert;
-typedef struct gnutls_privkey_int
-{
- /* the size of params depends on the public
- * key algorithm
- * RSA: [0] is modulus
- * [1] is public exponent
- * [2] is private exponent
- * [3] is prime1 (p)
- * [4] is prime2 (q)
- * [5] is coefficient (u == inverse of p mod q)
- * DSA: [0] is p
- * [1] is q
- * [2] is g
- * [3] is y (public key)
- * [4] is x (private key)
- */
- bigint_t params[MAX_PRIV_PARAMS_SIZE];
- int params_size; /* holds the number of params */
-
- gnutls_pk_algorithm_t pk_algorithm;
-} gnutls_privkey;
-
/* because gnutls_session_t is not defined when this file is included */
struct gnutls_session_int;
int _gnutls_x509_crt_to_gcert (gnutls_cert * gcert, gnutls_x509_crt_t cert,
unsigned int flags);
-void _gnutls_gkey_deinit (gnutls_privkey * key);
void _gnutls_gcert_deinit (gnutls_cert * cert);
int _gnutls_selected_cert_supported_kx (struct gnutls_session_int *session,
#include <gnutls_dh.h>
#include <random.h>
#include <gcrypt.h>
+#include <gnutls/pkcs11.h>
#include <gnutls_extensions.h> /* for _gnutls_ext_init */
#include <gnutls_cryptodev.h>
goto out;
}
+ gnutls_pkcs11_init(GNUTLS_PKCS11_FLAG_AUTO, NULL);
+
_gnutls_cryptodev_init ();
out:
asn1_delete_structure (&_gnutls_pkix1_asn);
_gnutls_crypto_deregister ();
_gnutls_cryptodev_deinit ();
+ gnutls_pkcs11_deinit();
}
_gnutls_init--;
}
*/
gnutls_cert *selected_cert_list;
int selected_cert_list_length;
- gnutls_privkey *selected_key;
+ struct gnutls_privkey_st *selected_key;
int selected_need_free;
/* holds the extensions we sent to the peer
--- /dev/null
+/*
+ * GnuTLS PKCS#11 support
+ * Copyright (C) 2010 Free Software Foundation
+ *
+ * Author: Nikos Mavrogiannopoulos
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the Free
+ * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
+ * MA 02111-1307, USA
+*/
+
+#include <gnutls_int.h>
+#include <pakchois/pakchois.h>
+#include <gnutls/pkcs11.h>
+#include <stdio.h>
+#include <stdbool.h>
+#include <string.h>
+#include <gnutls_errors.h>
+#include <gnutls_datum.h>
+#include <pkcs11_int.h>
+#include <gnutls/privkey.h>
+#include <sign.h>
+#include <gnutls_pk.h>
+#include <x509_int.h>
+#include <openpgp/openpgp_int.h>
+
+struct gnutls_privkey_st {
+ gnutls_privkey_type_t type;
+ gnutls_pk_algorithm_t pk_algorithm;
+
+ union {
+ gnutls_x509_privkey_t x509;
+ gnutls_pkcs11_privkey_t pkcs11;
+ gnutls_openpgp_privkey_t openpgp;
+ } key;
+
+ unsigned int flags;
+};
+
+int gnutls_privkey_get_type (gnutls_privkey_t key)
+{
+ return key->type;
+}
+
+int gnutls_privkey_get_pk_algorithm (gnutls_privkey_t key, unsigned int* bits)
+{
+ switch(key->type) {
+ case GNUTLS_PRIVKEY_OPENPGP:
+ return gnutls_openpgp_privkey_get_pk_algorithm(key->key.openpgp, bits);
+ case GNUTLS_PRIVKEY_PKCS11:
+ return gnutls_pkcs11_privkey_get_pk_algorithm(key->key.pkcs11, bits);
+ case GNUTLS_PRIVKEY_X509:
+ if (bits)
+ *bits = _gnutls_mpi_get_nbits (key->key.x509->params[0]);
+ return gnutls_x509_privkey_get_pk_algorithm(key->key.x509);
+ default:
+ gnutls_assert();
+ return GNUTLS_E_INVALID_REQUEST;
+ }
+
+}
+
+int gnutls_privkey_init(gnutls_privkey_t * key)
+{
+ *key = gnutls_calloc(1, sizeof(struct gnutls_privkey_st));
+ if (*key == NULL) {
+ gnutls_assert();
+ return GNUTLS_E_MEMORY_ERROR;
+ }
+
+ return 0;
+}
+
+void gnutls_privkey_deinit(gnutls_privkey_t key)
+{
+ if (key->flags & GNUTLS_PRIVKEY_IMPORT_AUTO_RELEASE)
+ switch(key->type) {
+ case GNUTLS_PRIVKEY_OPENPGP:
+ return gnutls_openpgp_privkey_deinit(key->key.openpgp);
+ case GNUTLS_PRIVKEY_PKCS11:
+ return gnutls_pkcs11_privkey_deinit(key->key.pkcs11);
+ case GNUTLS_PRIVKEY_X509:
+ return gnutls_x509_privkey_deinit(key->key.x509);
+ }
+ gnutls_free(key);
+}
+
+int gnutls_privkey_import_pkcs11 (gnutls_privkey_t pkey, gnutls_pkcs11_privkey_t key, unsigned int flags)
+{
+ pkey->key.pkcs11 = key;
+ pkey->type = GNUTLS_PRIVKEY_PKCS11;
+ pkey->pk_algorithm = gnutls_pkcs11_privkey_get_pk_algorithm(key, NULL);
+ pkey->flags = flags;
+
+ return 0;
+}
+
+int gnutls_privkey_import_x509 (gnutls_privkey_t pkey, gnutls_x509_privkey_t key, unsigned int flags)
+{
+ pkey->key.x509 = key;
+ pkey->type = GNUTLS_PRIVKEY_X509;
+ pkey->pk_algorithm = gnutls_x509_privkey_get_pk_algorithm(key);
+ pkey->flags = flags;
+
+ return 0;
+}
+
+int gnutls_privkey_import_openpgp (gnutls_privkey_t pkey, gnutls_openpgp_privkey_t key, unsigned int flags)
+{
+ pkey->key.openpgp = key;
+ pkey->type = GNUTLS_PRIVKEY_OPENPGP;
+ pkey->pk_algorithm = gnutls_openpgp_privkey_get_pk_algorithm(key, NULL);
+ pkey->flags = flags;
+
+ return 0;
+}
+
+/**
+ * gnutls_privkey_sign_data:
+ * @signer: Holds the key
+ * @digest: should be MD5 or SHA1
+ * @flags: should be 0 for now
+ * @data: holds the data to be signed
+ * @signature: will contain the signature allocate with gnutls_malloc()
+ *
+ * This function will sign the given data using a signature algorithm
+ * supported by the private key. Signature algorithms are always used
+ * together with a hash functions. Different hash functions may be
+ * used for the RSA algorithm, but only SHA-1 for the DSA keys.
+ *
+ * If the buffer provided is not long enough to hold the output, then
+ * *@signature_size is updated and %GNUTLS_E_SHORT_MEMORY_BUFFER will
+ * be returned.
+ *
+ * Returns: On success, %GNUTLS_E_SUCCESS is returned, otherwise a
+ * negative error value.
+ **/
+int
+gnutls_privkey_sign_data(gnutls_privkey_t signer,
+ gnutls_digest_algorithm_t hash,
+ unsigned int flags,
+ const gnutls_datum_t * data,
+ gnutls_datum_t * signature)
+{
+ int ret;
+ gnutls_datum_t digest;
+
+ switch (signer->pk_algorithm) {
+ case GNUTLS_PK_RSA:
+ ret = pk_pkcs1_rsa_hash(hash, data, &digest);
+ if (ret < 0) {
+ gnutls_assert();
+ return ret;
+ }
+ break;
+ case GNUTLS_PK_DSA:
+ ret = pk_dsa_hash(data, &digest);
+ if (ret < 0) {
+ gnutls_assert();
+ return ret;
+ }
+
+ break;
+ default:
+ gnutls_assert();
+ return GNUTLS_E_INTERNAL_ERROR;
+ }
+
+ ret = gnutls_privkey_sign_hash(signer, &digest, signature);
+ _gnutls_free_datum(&digest);
+
+ if (ret < 0) {
+ gnutls_assert();
+ return ret;
+ }
+
+ return 0;
+}
+
+int gnutls_privkey_sign_hash (gnutls_privkey_t key,
+ const gnutls_datum_t * hash,
+ gnutls_datum_t * signature)
+{
+ switch(key->type) {
+ case GNUTLS_PRIVKEY_OPENPGP:
+ return gnutls_openpgp_privkey_sign_hash(key->key.openpgp, hash, signature);
+ case GNUTLS_PRIVKEY_PKCS11:
+ return gnutls_pkcs11_privkey_sign_hash(key->key.pkcs11, hash, signature);
+ case GNUTLS_PRIVKEY_X509:
+ return gnutls_x509_privkey_sign_hash(key->key.x509, hash, signature);
+ default:
+ gnutls_assert();
+ return GNUTLS_E_INVALID_REQUEST;
+ }
+}
+
+int gnutls_privkey_decrypt_data(gnutls_privkey_t key,
+ unsigned int flags,
+ const gnutls_datum_t * ciphertext,
+ gnutls_datum_t * plaintext)
+{
+ if (key->pk_algorithm != GNUTLS_PK_RSA) {
+ gnutls_assert();
+ return GNUTLS_E_INVALID_REQUEST;
+ }
+
+ switch(key->type) {
+ case GNUTLS_PRIVKEY_OPENPGP:
+ return gnutls_openpgp_privkey_decrypt_data(key->key.openpgp, flags, ciphertext, plaintext);
+ case GNUTLS_PRIVKEY_X509:
+ return _gnutls_pkcs1_rsa_decrypt (plaintext, ciphertext, key->key.x509->params, key->key.x509->params_size, 2);
+ case GNUTLS_PRIVKEY_PKCS11:
+ return gnutls_pkcs11_privkey_decrypt_data(key->key.pkcs11, flags, ciphertext, plaintext);
+ default:
+ gnutls_assert();
+ return GNUTLS_E_INVALID_REQUEST;
+ }
+}
+
+
+
static int
_gnutls_tls_sign (gnutls_session_t session,
- gnutls_cert * cert, gnutls_privkey * pkey,
+ gnutls_cert * cert, gnutls_privkey_t pkey,
const gnutls_datum_t * hash_concat,
gnutls_datum_t * signature);
*/
int
_gnutls_handshake_sign_data (gnutls_session_t session, gnutls_cert * cert,
- gnutls_privkey * pkey, gnutls_datum_t * params,
+ gnutls_privkey_t pkey, gnutls_datum_t * params,
gnutls_datum_t * signature,
gnutls_sign_algorithm_t * sign_algo)
{
* given data. The output will be allocated and be put in signature.
*/
int
-_gnutls_sign (gnutls_pk_algorithm_t algo, bigint_t * params,
+_gnutls_soft_sign (gnutls_pk_algorithm_t algo, bigint_t * params,
int params_size, const gnutls_datum_t * data,
gnutls_datum_t * signature)
{
*/
static int
_gnutls_tls_sign (gnutls_session_t session,
- gnutls_cert * cert, gnutls_privkey * pkey,
+ gnutls_cert * cert, gnutls_privkey_t pkey,
const gnutls_datum_t * hash_concat,
gnutls_datum_t * signature)
{
}
/* External signing. */
- if (!pkey || pkey->params_size == 0)
+ if (!pkey)
{
if (!session->internals.sign_func)
return GNUTLS_E_INSUFFICIENT_CREDENTIALS;
}
}
- return _gnutls_sign (pkey->pk_algorithm, pkey->params,
- pkey->params_size, hash_concat, signature);
+ return gnutls_privkey_sign_hash(pkey, hash_concat, signature);
}
static int
*/
static int
_gnutls_handshake_sign_cert_vrfy12 (gnutls_session_t session,
- gnutls_cert * cert, gnutls_privkey * pkey,
+ gnutls_cert * cert, gnutls_privkey_t pkey,
gnutls_datum_t * signature)
{
gnutls_datum_t dconcat;
*/
int
_gnutls_handshake_sign_cert_vrfy (gnutls_session_t session,
- gnutls_cert * cert, gnutls_privkey * pkey,
+ gnutls_cert * cert, gnutls_privkey_t pkey,
gnutls_datum_t * signature)
{
gnutls_datum_t dconcat;
#ifndef GNUTLS_SIG_H
# define GNUTLS_SIG_H
+#include <gnutls/privkey.h>
+
int _gnutls_handshake_sign_cert_vrfy (gnutls_session_t session,
gnutls_cert * cert,
- gnutls_privkey * pkey,
+ gnutls_privkey_t pkey,
gnutls_datum_t * signature);
int _gnutls_handshake_sign_data (gnutls_session_t session,
gnutls_cert * cert,
- gnutls_privkey * pkey,
+ gnutls_privkey_t pkey,
gnutls_datum_t * params,
gnutls_datum_t * signature,
gnutls_sign_algorithm_t * algo);
gnutls_datum_t * signature,
gnutls_sign_algorithm_t algo);
-int _gnutls_sign (gnutls_pk_algorithm_t algo,
+int _gnutls_soft_sign (gnutls_pk_algorithm_t algo,
bigint_t * params, int params_size,
const gnutls_datum_t * data, gnutls_datum_t * signature);
if (cred == NULL)
return GNUTLS_E_UNSUPPORTED_CERTIFICATE_TYPE;
- if (cred->server_get_cert_callback == NULL)
+ if (cred->server_get_cert_callback == NULL && cred->get_cert_callback == NULL)
{
for (i = 0; i < cred->ncerts; i++)
{
rv = 0;
- cleanup:
-
return rv;
}
{
unsigned int i, j;
const opaque *old = _old;
- int init = 0;
int step = 2;
const char empty[] = "";
#include "x509/x509_int.h"
#include "read-file.h"
+static int append_crt_list( gnutls_certificate_credentials_t res, gnutls_cert *crt, int nr);
+static int append_pkey( gnutls_certificate_credentials_t res, gnutls_privkey_t pkey);
+
/*
* some x509 certificate parsing functions.
*/
static int
_gnutls_check_key_cert_match (gnutls_certificate_credentials_t res)
{
- gnutls_datum_t cid;
- gnutls_datum_t kid;
- unsigned pk = res->cert_list[res->ncerts - 1][0].subject_pk_algorithm;
-
- if (res->pkey[res->ncerts - 1].pk_algorithm != pk)
- {
- gnutls_assert ();
- return GNUTLS_E_CERTIFICATE_KEY_MISMATCH;
- }
-
- if (pk == GNUTLS_PK_RSA)
- {
- _gnutls_x509_write_rsa_params (res->pkey[res->ncerts - 1].params,
- res->pkey[res->ncerts -
- 1].params_size, &kid);
-
+ unsigned int pk = res->cert_list[res->ncerts - 1][0].subject_pk_algorithm;
- _gnutls_x509_write_rsa_params (res->
- cert_list[res->ncerts - 1][0].params,
- res->cert_list[res->ncerts -
- 1][0].params_size, &cid);
- }
- else if (pk == GNUTLS_PK_DSA)
- {
-
- _gnutls_x509_write_dsa_params (res->pkey[res->ncerts - 1].params,
- res->pkey[res->ncerts -
- 1].params_size, &kid);
-
- _gnutls_x509_write_dsa_params (res->
- cert_list[res->ncerts - 1][0].params,
- res->cert_list[res->ncerts -
- 1][0].params_size, &cid);
- }
-
- if (cid.size != kid.size)
+ if (gnutls_privkey_get_pk_algorithm(res->pkey[res->ncerts - 1], NULL) != pk)
{
gnutls_assert ();
- _gnutls_free_datum (&kid);
- _gnutls_free_datum (&cid);
return GNUTLS_E_CERTIFICATE_KEY_MISMATCH;
}
- if (memcmp (kid.data, cid.data, kid.size) != 0)
- {
- gnutls_assert ();
- _gnutls_free_datum (&kid);
- _gnutls_free_datum (&cid);
- return GNUTLS_E_CERTIFICATE_KEY_MISMATCH;
- }
-
- _gnutls_free_datum (&kid);
- _gnutls_free_datum (&cid);
return 0;
}
/* Reads a DER encoded certificate list from memory and stores it to a
- * gnutls_cert structure. Returns the number of certificates parsed.
+ * gnutls_cert structure. Returns the number of certificates parsed.
*/
static int
-parse_crt_mem (gnutls_cert ** cert_list, unsigned *ncerts,
- gnutls_x509_crt_t cert)
+parse_der_cert_mem (gnutls_certificate_credentials_t res,
+ const void *input_cert, int input_cert_size)
{
- int i;
+ gnutls_datum_t tmp;
+ gnutls_x509_crt_t crt;
+ gnutls_cert *ccert;
int ret;
- i = *ncerts + 1;
-
- *cert_list =
- (gnutls_cert *) gnutls_realloc_fast (*cert_list,
- i * sizeof (gnutls_cert));
-
- if (*cert_list == NULL)
+ ccert = gnutls_malloc(sizeof(*ccert));
+ if (ccert == NULL)
{
- gnutls_assert ();
+ gnutls_assert();
return GNUTLS_E_MEMORY_ERROR;
}
- ret = _gnutls_x509_crt_to_gcert (&cert_list[0][i - 1], cert, 0);
+ ret = gnutls_x509_crt_init (&crt);
if (ret < 0)
{
gnutls_assert ();
+ gnutls_free(ccert);
return ret;
}
- *ncerts = i;
-
- return 1; /* one certificate parsed */
-}
-
-/* Reads a DER encoded certificate list from memory and stores it to a
- * gnutls_cert structure. Returns the number of certificates parsed.
- */
-static int
-parse_der_cert_mem (gnutls_cert ** cert_list, unsigned *ncerts,
- const void *input_cert, int input_cert_size)
-{
- gnutls_datum_t tmp;
- gnutls_x509_crt_t cert;
- int ret;
+ tmp.data = (opaque *) input_cert;
+ tmp.size = input_cert_size;
- ret = gnutls_x509_crt_init (&cert);
+ ret = gnutls_x509_crt_import (crt, &tmp, GNUTLS_X509_FMT_DER);
if (ret < 0)
{
gnutls_assert ();
+ gnutls_x509_crt_deinit (crt);
+ gnutls_free(ccert);
return ret;
}
- tmp.data = (opaque *) input_cert;
- tmp.size = input_cert_size;
-
- ret = gnutls_x509_crt_import (cert, &tmp, GNUTLS_X509_FMT_DER);
+ ret = _gnutls_x509_crt_to_gcert (ccert, crt, 0);
+ gnutls_x509_crt_deinit (crt);
+
if (ret < 0)
{
- gnutls_assert ();
- gnutls_x509_crt_deinit (cert);
+ gnutls_assert();
+ gnutls_free(ccert);
+ return ret;
+ }
+
+ ret = append_crt_list(res, ccert, 1);
+ if (ret < 0)
+ {
+ gnutls_assert();
+ gnutls_free(ccert);
return ret;
}
-
- ret = parse_crt_mem (cert_list, ncerts, cert);
- gnutls_x509_crt_deinit (cert);
return ret;
}
* a gnutls_cert structure. Returns the number of certificate parsed.
*/
static int
-parse_pem_cert_mem (gnutls_cert ** cert_list, unsigned *ncerts,
+parse_pem_cert_mem (gnutls_certificate_credentials_t res,
const char *input_cert, int input_cert_size)
{
- int size, siz2, i;
+ int size, siz2;
const char *ptr;
opaque *ptr2;
gnutls_datum_t tmp;
int ret, count;
+ gnutls_cert* certs = NULL;
/* move to the certificate
*/
}
size = input_cert_size - (ptr - input_cert);
- i = *ncerts + 1;
count = 0;
do
return GNUTLS_E_BASE64_DECODING_ERROR;
}
- *cert_list =
- (gnutls_cert *) gnutls_realloc_fast (*cert_list,
- i * sizeof (gnutls_cert));
+ certs = gnutls_realloc_fast (certs, (count+1) * sizeof (gnutls_cert));
- if (*cert_list == NULL)
+ if (certs == NULL)
{
gnutls_assert ();
return GNUTLS_E_MEMORY_ERROR;
tmp.data = ptr2;
tmp.size = siz2;
- ret = _gnutls_x509_raw_cert_to_gcert (&cert_list[0][i - 1], &tmp, 0);
+ ret = _gnutls_x509_raw_cert_to_gcert (&certs[count], &tmp, 0);
if (ret < 0)
{
gnutls_assert ();
+ gnutls_free(certs);
return ret;
}
+
_gnutls_free_datum (&tmp); /* free ptr2 */
/* now we move ptr after the pem header
else
ptr = NULL;
- i++;
count++;
}
while (ptr != NULL);
- *ncerts = i - 1;
+ ret = append_crt_list(res, certs, count);
+ if (ret < 0)
+ {
+ gnutls_assert();
+ gnutls_free(certs);
+ return ret;
+ }
return count;
}
{
int ret;
- /* allocate space for the certificate to add
- */
- res->cert_list = gnutls_realloc_fast (res->cert_list,
- (1 +
- res->ncerts) *
- sizeof (gnutls_cert *));
- if (res->cert_list == NULL)
- {
- gnutls_assert ();
- return GNUTLS_E_MEMORY_ERROR;
- }
-
- res->cert_list_length = gnutls_realloc_fast (res->cert_list_length,
- (1 +
- res->ncerts) * sizeof (int));
- if (res->cert_list_length == NULL)
- {
- gnutls_assert ();
- return GNUTLS_E_MEMORY_ERROR;
- }
-
- res->cert_list[res->ncerts] = NULL; /* for realloc */
- res->cert_list_length[res->ncerts] = 0;
-
if (type == GNUTLS_X509_FMT_DER)
- ret = parse_der_cert_mem (&res->cert_list[res->ncerts],
- &res->cert_list_length[res->ncerts],
+ ret = parse_der_cert_mem (res,
cert, cert_size);
else
- ret = parse_pem_cert_mem (&res->cert_list[res->ncerts],
- &res->cert_list_length[res->ncerts], cert,
- cert_size);
+ ret = parse_pem_cert_mem (res,
+ cert, cert_size);
if (ret < 0)
{
return ret;
}
-
-int
-_gnutls_x509_privkey_to_gkey (gnutls_privkey * dest,
- gnutls_x509_privkey_t src)
-{
- int i, ret;
-
- memset (dest, 0, sizeof (gnutls_privkey));
-
- for (i = 0; i < src->params_size; i++)
- {
- dest->params[i] = _gnutls_mpi_copy (src->params[i]);
- if (dest->params[i] == NULL)
- {
- gnutls_assert ();
- ret = GNUTLS_E_MEMORY_ERROR;
- goto cleanup;
- }
- }
-
- dest->pk_algorithm = src->pk_algorithm;
- dest->params_size = src->params_size;
-
- return 0;
-
-cleanup:
-
- for (i = 0; i < src->params_size; i++)
- {
- _gnutls_mpi_release (&dest->params[i]);
- }
- return ret;
-}
-
-void
-_gnutls_gkey_deinit (gnutls_privkey * key)
-{
- int i;
- if (key == NULL)
- return;
-
- for (i = 0; i < key->params_size; i++)
- {
- _gnutls_mpi_release (&key->params[i]);
- }
-}
-
-int
-_gnutls_x509_raw_privkey_to_gkey (gnutls_privkey * privkey,
+static int
+_gnutls_x509_raw_privkey_to_privkey (gnutls_privkey_t *privkey,
const gnutls_datum_t * raw_key,
gnutls_x509_crt_fmt_t type)
{
gnutls_assert ();
return ret;
}
-
+
ret = gnutls_x509_privkey_import (tmpkey, raw_key, type);
#ifdef ENABLE_PKI
return ret;
}
- ret = _gnutls_x509_privkey_to_gkey (privkey, tmpkey);
+ ret = gnutls_privkey_init(privkey);
+ if (ret < 0)
+ {
+ gnutls_assert();
+ gnutls_x509_privkey_deinit (tmpkey);
+ return ret;
+ }
+
+ ret = gnutls_privkey_import_x509 (*privkey, tmpkey, GNUTLS_PRIVKEY_IMPORT_AUTO_RELEASE);
if (ret < 0)
{
gnutls_assert ();
gnutls_x509_privkey_deinit (tmpkey);
+ gnutls_privkey_deinit (*privkey);
return ret;
}
- gnutls_x509_privkey_deinit (tmpkey);
-
return 0;
}
{
int ret;
gnutls_datum_t tmp;
-
- /* allocate space for the pkey list
- */
- res->pkey =
- gnutls_realloc_fast (res->pkey,
- (res->ncerts + 1) * sizeof (gnutls_privkey));
- if (res->pkey == NULL)
- {
- gnutls_assert ();
- return GNUTLS_E_MEMORY_ERROR;
- }
+ gnutls_privkey_t privkey;
if (key)
{
tmp.size = key_size;
ret =
- _gnutls_x509_raw_privkey_to_gkey (&res->pkey[res->ncerts], &tmp,
- type);
+ _gnutls_x509_raw_privkey_to_privkey (&privkey, &tmp, type);
if (ret < 0)
{
gnutls_assert ();
return ret;
}
+
+ ret = append_pkey(res, privkey);
+ if (ret < 0)
+ {
+ gnutls_assert ();
+ gnutls_privkey_deinit(privkey);
+ return ret;
+ }
+
}
else
- memset (&res->pkey[res->ncerts], 0, sizeof (gnutls_privkey));
+ {
+ gnutls_assert();
+ return GNUTLS_E_INVALID_REQUEST;
+ }
+
+
+ return 0;
+}
+
+/* Reads a private key from a token.
+ */
+static int read_key_url (gnutls_certificate_credentials_t res, const char* url)
+{
+ int ret;
+ gnutls_pkcs11_privkey_t key1 = NULL;
+ gnutls_privkey_t pkey = NULL;
+
+ /* allocate space for the pkey list
+ */
+
+fprintf(stderr, "%s:%d\n", __func__, __LINE__);
+ ret = gnutls_pkcs11_privkey_init(&key1);
+ if (ret < 0)
+ {
+ gnutls_assert();
+ return ret;
+ }
+
+ ret = gnutls_pkcs11_privkey_import_url(key1, url);
+ if (ret < 0)
+ {
+ gnutls_assert();
+ goto cleanup;
+ }
+
+ ret = gnutls_privkey_init(&pkey);
+ if (ret < 0)
+ {
+ gnutls_assert();
+ goto cleanup;
+ }
+
+ ret = gnutls_privkey_import_pkcs11(pkey, key1, GNUTLS_PRIVKEY_IMPORT_AUTO_RELEASE);
+ if (ret < 0)
+ {
+ gnutls_assert();
+ goto cleanup;
+ }
+
+ ret = append_pkey(res, pkey);
+ if (ret < 0)
+ {
+ gnutls_assert();
+ goto cleanup;
+ }
+
+ return 0;
+
+cleanup:
+ if (pkey)
+ gnutls_privkey_deinit(pkey);
+
+ if (key1)
+ gnutls_pkcs11_privkey_deinit(key1);
+
+ return ret;
+}
+
+/* Reads a private key from a token.
+ */
+static int read_cert_url (gnutls_certificate_credentials_t res, const char* url)
+{
+int ret;
+gnutls_x509_crt_t crt;
+gnutls_cert * ccert;
+
+fprintf(stderr, "%s:%d\n", __func__, __LINE__);
+ ccert = gnutls_malloc(sizeof(*ccert));
+ if (ccert == NULL)
+ {
+ gnutls_assert();
+ return GNUTLS_E_MEMORY_ERROR;
+ }
+
+ ret = gnutls_x509_crt_init(&crt);
+ if (ret < 0)
+ {
+ gnutls_assert();
+ gnutls_free(ccert);
+ return ret;
+ }
+
+ ret = gnutls_x509_crt_import_pkcs11_url(crt, url);
+ if (ret < 0)
+ {
+ gnutls_assert();
+ gnutls_free(ccert);
+ gnutls_x509_crt_deinit(crt);
+ return ret;
+ }
+
+ ret = _gnutls_x509_crt_to_gcert (ccert, crt, 0);
+ gnutls_x509_crt_deinit(crt);
+
+ if (ret < 0)
+ {
+ gnutls_assert();
+ gnutls_free(ccert);
+ return ret;
+ }
+
+ ret = append_crt_list(res, ccert, 1);
+ if (ret < 0)
+ {
+ gnutls_assert();
+ gnutls_free(ccert);
+ return ret;
+ }
return 0;
+
}
/* Reads a certificate file
{
int ret;
size_t size;
- char *data = read_binary_file (certfile, &size);
+ char *data;
+
+ if (strncmp(certfile, "pkcs11:", 7)==0) {
+ return read_cert_url(res, certfile);
+ }
+
+ data = read_binary_file (certfile, &size);
if (data == NULL)
{
{
int ret;
size_t size;
- char *data = read_binary_file (keyfile, &size);
+ char* data;
+
+ if (strncmp(keyfile, "pkcs11:", 7)==0) {
+ return read_key_url(res, keyfile);
+ }
+
+ data = read_binary_file (keyfile, &size);
if (data == NULL)
{
return 0;
}
+static int append_crt_list( gnutls_certificate_credentials_t res, gnutls_cert *crt, int nr)
+{
+ res->cert_list = gnutls_realloc_fast (res->cert_list,
+ (1 +
+ res->ncerts) *
+ sizeof (gnutls_cert *));
+ if (res->cert_list == NULL)
+ {
+ gnutls_assert ();
+ return GNUTLS_E_MEMORY_ERROR;
+ }
+
+ res->cert_list_length = gnutls_realloc_fast (res->cert_list_length,
+ (1 +
+ res->ncerts) * sizeof (int));
+ if (res->cert_list_length == NULL)
+ {
+ gnutls_assert ();
+ return GNUTLS_E_MEMORY_ERROR;
+ }
+
+ res->cert_list[res->ncerts] = crt;
+ res->cert_list_length[res->ncerts] = nr;
+
+ return 0;
+
+}
+
+static int append_pkey( gnutls_certificate_credentials_t res, gnutls_privkey_t pkey)
+{
+ res->pkey = gnutls_realloc_fast (res->pkey,
+ (1 + res->ncerts) *
+ sizeof (gnutls_privkey_t));
+ if (res->pkey == NULL)
+ {
+ gnutls_assert ();
+ return GNUTLS_E_MEMORY_ERROR;
+ }
+
+ res->pkey[res->ncerts] = pkey;
+ return 0;
+
+}
+
/**
* gnutls_certificate_set_x509_key:
* @res: is a #gnutls_certificate_credentials_t structure.
* entity certificate (e.g., also an intermediate CA cert) then put
* the certificate chain in @cert_list.
*
+ *
+ *
* Returns: %GNUTLS_E_SUCCESS on success, or an error code.
*
* Since: 2.4.0
gnutls_x509_privkey_t key)
{
int ret, i;
+ gnutls_privkey_t pkey;
+ gnutls_cert* pcerts = NULL;
/* this should be first
*/
-
- res->pkey =
- gnutls_realloc_fast (res->pkey,
- (res->ncerts + 1) * sizeof (gnutls_privkey));
- if (res->pkey == NULL)
+ ret = gnutls_privkey_init(&pkey);
+ if (ret < 0)
{
gnutls_assert ();
- return GNUTLS_E_MEMORY_ERROR;
+ return ret;
}
-
- ret = _gnutls_x509_privkey_to_gkey (&res->pkey[res->ncerts], key);
+
+ ret = gnutls_privkey_import_x509 (pkey, key, 0);
if (ret < 0)
{
gnutls_assert ();
return ret;
}
-
- res->cert_list = gnutls_realloc_fast (res->cert_list,
- (1 +
- res->ncerts) *
- sizeof (gnutls_cert *));
- if (res->cert_list == NULL)
+
+ ret = append_pkey(res, pkey);
+ if (ret < 0)
{
gnutls_assert ();
- return GNUTLS_E_MEMORY_ERROR;
+ return ret;
}
- res->cert_list_length = gnutls_realloc_fast (res->cert_list_length,
- (1 +
- res->ncerts) * sizeof (int));
- if (res->cert_list_length == NULL)
+ /* load certificates */
+ pcerts = gnutls_malloc(sizeof(gnutls_cert)*cert_list_size);
+ if (pcerts == NULL)
{
- gnutls_assert ();
+ gnutls_assert();
return GNUTLS_E_MEMORY_ERROR;
}
- res->cert_list[res->ncerts] = NULL; /* for realloc */
- res->cert_list_length[res->ncerts] = 0;
-
-
for (i = 0; i < cert_list_size; i++)
{
- ret = parse_crt_mem (&res->cert_list[res->ncerts],
- &res->cert_list_length[res->ncerts], cert_list[i]);
+ ret = _gnutls_x509_crt_to_gcert (&pcerts[i], cert_list[i], 0);
if (ret < 0)
{
gnutls_assert ();
return ret;
}
}
+
+ ret = append_crt_list(res, pcerts, cert_list_size);
+ if (ret < 0)
+ {
+ gnutls_assert();
+ return ret;
+ }
+
res->ncerts++;
if ((ret = _gnutls_check_key_cert_match (res)) < 0)
}
}
- /* check if the key and certificate found match */
- if (key && (ret = _gnutls_check_key_cert_match (res)) < 0)
- {
- gnutls_assert ();
- goto done;
- }
-
ret = 0;
done:
*/
#include <libtasn1.h>
+#include <gnutls/privkey.h>
int _gnutls_x509_cert_verify_peers (gnutls_session_t session,
unsigned int *status);
int _gnutls_check_key_usage (const gnutls_cert * cert,
gnutls_kx_algorithm_t alg);
-int _gnutls_x509_raw_privkey_to_gkey (gnutls_privkey * privkey,
+int _gnutls_x509_raw_privkey_to_gkey (gnutls_privkey_t * privkey,
const gnutls_datum_t * raw_key,
gnutls_x509_crt_fmt_t type);
-int _gnutls_x509_privkey_to_gkey (gnutls_privkey * privkey,
- gnutls_x509_privkey_t);
/* Typedefs for more compatibility with older GnuTLS. */
-#ifndef GNUTLS_COMPAT_H
-# define GNUTLS_COMPAT_H
+#ifndef _GNUTLS_COMPAT_H
+# define _GNUTLS_COMPAT_H
#define gnutls_cipher_algorithm gnutls_cipher_algorithm_t
#define gnutls_kx_algorithm gnutls_kx_algorithm_t
#define LIBGNUTLS_VERSION_NUMBER GNUTLS_VERSION_NUMBER
#define LIBGNUTLS_EXTRA_VERSION GNUTLS_VERSION
-#endif /* GNUTLS_COMPAT_H */
+ typedef struct gnutls_retr_st
+ {
+ gnutls_certificate_type_t type;
+ union
+ {
+ gnutls_x509_crt_t *x509;
+ gnutls_openpgp_crt_t pgp;
+ } cert;
+ unsigned int ncerts; /* one for pgp keys */
+
+ union
+ {
+ gnutls_x509_privkey_t x509;
+ gnutls_openpgp_privkey_t pgp;
+ } key;
+
+ unsigned int deinit_all; /* if non zero all keys will be deinited */
+ } gnutls_retr_st;
+
+typedef int gnutls_certificate_client_retrieve_function (gnutls_session_t,
+ const
+ gnutls_datum_t *
+ req_ca_rdn,
+ int nreqs,
+ const
+ gnutls_pk_algorithm_t
+ * pk_algos,
+ int
+ pk_algos_length,
+ gnutls_retr_st *);
+typedef int gnutls_certificate_server_retrieve_function (gnutls_session_t,
+ gnutls_retr_st *);
+
+void gnutls_certificate_client_set_retrieve_function
+ (gnutls_certificate_credentials_t cred,
+ gnutls_certificate_client_retrieve_function * func);
+void gnutls_certificate_server_set_retrieve_function
+ (gnutls_certificate_credentials_t cred,
+ gnutls_certificate_server_retrieve_function * func);
+
+#endif /* _GNUTLS_COMPAT_H */
#endif
/* Get time_t. */
#include <time.h>
-#include <gnutls/compat.h>
#ifdef __cplusplus
extern "C"
{
struct gnutls_openpgp_privkey_int;
typedef struct gnutls_openpgp_privkey_int *gnutls_openpgp_privkey_t;
- typedef struct gnutls_retr_st
+ struct gnutls_pkcs11_privkey_st;
+ typedef struct gnutls_pkcs11_privkey_st* gnutls_pkcs11_privkey_t;
+
+ typedef enum {
+ GNUTLS_PRIVKEY_X509, /* gnutls_x509_privkey_t */
+ GNUTLS_PRIVKEY_OPENPGP, /* gnutls_openpgp_privkey_t */
+ GNUTLS_PRIVKEY_PKCS11, /* gnutls_pkcs11_privkey_t */
+ } gnutls_privkey_type_t;
+
+ typedef struct gnutls_retr2_st
{
- gnutls_certificate_type_t type;
- union cert
+ gnutls_certificate_type_t cert_type;
+ gnutls_privkey_type_t key_type;
+
+ union
{
gnutls_x509_crt_t *x509;
gnutls_openpgp_crt_t pgp;
} cert;
unsigned int ncerts; /* one for pgp keys */
- union key
+ union
{
gnutls_x509_privkey_t x509;
gnutls_openpgp_privkey_t pgp;
+ gnutls_pkcs11_privkey_t pkcs11;
} key;
unsigned int deinit_all; /* if non zero all keys will be deinited */
- } gnutls_retr_st;
-
- typedef int gnutls_certificate_client_retrieve_function (gnutls_session_t,
- const
- gnutls_datum_t *
- req_ca_rdn,
- int nreqs,
- const
- gnutls_pk_algorithm_t
- * pk_algos,
- int
- pk_algos_length,
- gnutls_retr_st *);
- typedef int gnutls_certificate_server_retrieve_function (gnutls_session_t,
- gnutls_retr_st *);
-
- typedef int gnutls_certificate_verify_function (gnutls_session_t);
+ } gnutls_retr2_st;
/* Functions that allow auth_info_t structures handling
/* These are set on the credentials structure.
*/
- void gnutls_certificate_client_set_retrieve_function
- (gnutls_certificate_credentials_t cred,
- gnutls_certificate_client_retrieve_function * func);
- void gnutls_certificate_server_set_retrieve_function
+
+ typedef int gnutls_certificate_retrieve_function (gnutls_session_t,
+ const
+ gnutls_datum_t *
+ req_ca_rdn,
+ int nreqs,
+ const
+ gnutls_pk_algorithm_t
+ * pk_algos,
+ int
+ pk_algos_length,
+ gnutls_retr2_st *);
+
+
+ void gnutls_certificate_set_retrieve_function
(gnutls_certificate_credentials_t cred,
- gnutls_certificate_server_retrieve_function * func);
+ gnutls_certificate_retrieve_function * func);
+ typedef int gnutls_certificate_verify_function (gnutls_session_t);
void
gnutls_certificate_set_verify_function (gnutls_certificate_credentials_t
cred,
}
#endif
+#include <gnutls/compat.h>
+
#endif /* GNUTLS_H */
gnutls_openpgp_crt_fmt_t format,
const char *password,
unsigned int flags);
+
+ int gnutls_openpgp_privkey_decrypt_data (gnutls_openpgp_privkey_t key,
+ unsigned int flags, const gnutls_datum_t * ciphertext,
+ gnutls_datum_t * plaintext);
int gnutls_openpgp_privkey_sign_hash (gnutls_openpgp_privkey_t key,
const gnutls_datum_t * hash,
gnutls_datum_t * signature);
* @brief PKCS#11 certificate reference.
*/
struct gnutls_pkcs11_crt_st;
-
-
typedef struct gnutls_pkcs11_crt_st* gnutls_pkcs11_crt_t;
+
#define GNUTLS_PKCS11_FLAG_MANUAL 0 /* Manual loading of libraries */
#define GNUTLS_PKCS11_FLAG_AUTO 1 /* Automatically load libraries by reading /etc/gnutls/pkcs11.conf */
* @param data Data to use when calling callback.
* @return gnutls status.
*/
-//int gnutls_pkcs11_set_token_function (const gnutls_pkcs11_token_callback_t callback, void * const data);
+void gnutls_pkcs11_set_token_function(gnutls_pkcs11_token_callback_t fn, void *userdata);
/**
* @brief Set PIN prompt callback.
GNUTLS_PKCS11_CRT_TOKEN_SERIAL,
GNUTLS_PKCS11_CRT_TOKEN_MANUFACTURER,
GNUTLS_PKCS11_CRT_TOKEN_MODEL,
+ GNUTLS_PKCS11_CRT_ID,
} gnutls_pkcs11_cert_info_t;
int gnutls_pkcs11_crt_get_info(gnutls_pkcs11_crt_t crt, gnutls_pkcs11_cert_info_t itype, void* output, size_t* output_size);
unsigned int flags);
-/* XXX: private key functions...*/
-
-/**
- * @brief Setup session to be used with gnutls-pkcs11.
- * @param session Session to setup.
- * @param certificate Certificate to use in this session.
- * @return gnutls status.
- * @see gnutls_pkcs11_cleanup_session()
- * @note Resources must be released using @ref gnutls_pkcs11_cleanup_session().
- */
-//int gnutls_pkcs11_setup_session (gnutls_session session, gnutls_pkcs11_crt_t certificate);
-
-/**
- * @brief Cleanup session.
- * @param session Session to cleanup.
- * @return gnutls status.
- */
-//int gnutls_pkcs11_cleanup_session (gnutls_session session);
+/* private key functions...*/
+int gnutls_pkcs11_privkey_init (gnutls_pkcs11_privkey_t * key);
+void gnutls_pkcs11_privkey_deinit (gnutls_pkcs11_privkey_t key);
+int gnutls_pkcs11_privkey_get_pk_algorithm (gnutls_pkcs11_privkey_t key, unsigned int* bits);
+int gnutls_pkcs11_privkey_get_info(gnutls_pkcs11_privkey_t crt, gnutls_pkcs11_cert_info_t itype, void* output, size_t* output_size);
+int gnutls_pkcs11_privkey_import_url (gnutls_pkcs11_privkey_t key,
+ const char* url);
+
+int
+gnutls_pkcs11_privkey_sign_data(gnutls_pkcs11_privkey_t signer,
+ gnutls_digest_algorithm_t hash,
+ unsigned int flags,
+ const gnutls_datum_t * data,
+ gnutls_datum_t * signature);
+int gnutls_pkcs11_privkey_sign_hash (gnutls_pkcs11_privkey_t key,
+ const gnutls_datum_t * hash,
+ gnutls_datum_t * signature);
+int
+gnutls_pkcs11_privkey_decrypt_data(gnutls_pkcs11_privkey_t key,
+ unsigned int flags, const gnutls_datum_t * ciphertext,
+ gnutls_datum_t * plaintext);
/** @} */
--- /dev/null
+#ifndef __GNUTLS_PRIVKEY_H
+#define __GNUTLS_PRIVKEY_H
+
+#include <stdarg.h>
+#include <gnutls/gnutls.h>
+#include <gnutls/x509.h>
+#include <gnutls/pkcs11.h>
+#include <gnutls/openpgp.h>
+
+struct gnutls_privkey_st;
+typedef struct gnutls_privkey_st* gnutls_privkey_t;
+
+int gnutls_privkey_init (gnutls_privkey_t * key);
+void gnutls_privkey_deinit (gnutls_privkey_t key);
+int gnutls_privkey_get_pk_algorithm (gnutls_privkey_t key, unsigned int* bits);
+int gnutls_privkey_get_type (gnutls_privkey_t key);
+
+#define GNUTLS_PRIVKEY_IMPORT_AUTO_RELEASE 1
+int gnutls_privkey_import_pkcs11 (gnutls_privkey_t pkey, gnutls_pkcs11_privkey_t key, unsigned int flags);
+int gnutls_privkey_import_x509 (gnutls_privkey_t pkey, gnutls_x509_privkey_t key, unsigned int flags);
+int gnutls_privkey_import_openpgp (gnutls_privkey_t pkey, gnutls_openpgp_privkey_t key, unsigned int flags);
+
+int gnutls_privkey_sign_data(gnutls_privkey_t signer,
+ gnutls_digest_algorithm_t hash,
+ unsigned int flags,
+ const gnutls_datum_t * data,
+ gnutls_datum_t * signature);
+int gnutls_privkey_sign_hash (gnutls_privkey_t key,
+ const gnutls_datum_t * hash,
+ gnutls_datum_t * signature);
+
+int gnutls_privkey_decrypt_data(gnutls_privkey_t signer,
+ unsigned int flags,
+ const gnutls_datum_t * ciphertext,
+ gnutls_datum_t * plaintext);
+
+#endif
const gnutls_datum_t * data,
void *signature,
size_t * signature_size);
+ int gnutls_x509_privkey_sign_data2 (gnutls_x509_privkey_t key,
+ gnutls_digest_algorithm_t digest,
+ unsigned int flags,
+ const gnutls_datum_t * data,
+ gnutls_datum_t *signature);
int gnutls_x509_privkey_verify_data (gnutls_x509_privkey_t key,
unsigned int flags,
const gnutls_datum_t * data,
GNUTLS_2_11
{
global:
+ gnutls_certificate_set_retrieve_function;
gnutls_pkcs11_init;
gnutls_pkcs11_deinit;
gnutls_pkcs11_set_pin_function;
gnutls_pkcs11_crt_get_info;
gnutls_pkcs11_token_get_info;
gnutls_pkcs11_token_get_url;
+ gnutls_pkcs11_privkey_init;
+ gnutls_pkcs11_privkey_deinit;
+ gnutls_pkcs11_privkey_get_pk_algorithm;
+ gnutls_pkcs11_privkey_get_info;
+ gnutls_pkcs11_privkey_import_url;
+ gnutls_pkcs11_privkey_sign_data;
+ gnutls_pkcs11_privkey_sign_hash;
+ gnutls_pkcs11_privkey_decrypt_data;
+
+ gnutls_privkey_init;
+ gnutls_privkey_deinit;
+ gnutls_privkey_get_pk_algorithm;
+ gnutls_privkey_get_type;
+ gnutls_privkey_import_pkcs11;
+ gnutls_privkey_import_x509;
+ gnutls_privkey_import_openpgp;
+ gnutls_privkey_sign_data;
+ gnutls_privkey_sign_hash;
+ gnutls_privkey_decrypt_data;
+
} GNUTLS_2_10;
GNUTLS_PRIVATE {
res->pkey = gnutls_realloc_fast (res->pkey,
(res->ncerts + 1) *
- sizeof (gnutls_privkey));
+ sizeof (gnutls_privkey_t));
if (res->pkey == NULL)
{
gnutls_assert ();
return GNUTLS_E_MEMORY_ERROR;
}
- ret = _gnutls_openpgp_privkey_to_gkey (&res->pkey[res->ncerts], pkey);
+ ret = gnutls_privkey_init(&res->pkey[res->ncerts]);
+ if (ret < 0)
+ {
+ gnutls_assert();
+ return ret;
+ }
+
+ ret = gnutls_privkey_import_openpgp (res->pkey[res->ncerts], pkey, 0);
if (ret < 0)
{
+ gnutls_privkey_deinit(res->pkey[res->ncerts]);
gnutls_assert ();
return ret;
}
if (res->cert_list == NULL)
{
gnutls_assert ();
+ /* memory leak here? */
return GNUTLS_E_MEMORY_ERROR;
}
}
-/* Copies a gnutls_openpgp_privkey_t to a gnutls_privkey structure. */
-int
-_gnutls_openpgp_privkey_to_gkey (gnutls_privkey * dest,
- gnutls_openpgp_privkey_t src)
-{
- int ret = 0;
- gnutls_openpgp_keyid_t keyid;
- char err_buf[33];
-
- if (dest == NULL || src == NULL)
- {
- gnutls_assert ();
- return GNUTLS_E_CERTIFICATE_ERROR;
- }
-
- dest->params_size = MAX_PRIV_PARAMS_SIZE;
-
- ret = gnutls_openpgp_privkey_get_preferred_key_id (src, keyid);
-
- if (ret == 0)
- {
- int idx;
- uint32_t kid32[2];
-
- _gnutls_debug_log
- ("Importing Openpgp key and using openpgp sub key: %s\n",
- _gnutls_bin2hex (keyid, sizeof (keyid), err_buf, sizeof (err_buf), NULL));
-
- KEYID_IMPORT (kid32, keyid);
-
- idx = gnutls_openpgp_privkey_get_subkey_idx (src, keyid);
- if (idx < 0)
- {
- gnutls_assert ();
- return idx;
- }
-
- dest->pk_algorithm =
- gnutls_openpgp_privkey_get_subkey_pk_algorithm (src, idx, NULL);
-
- ret =
- _gnutls_openpgp_privkey_get_mpis (src, kid32, dest->params,
- &dest->params_size);
- }
- else
- {
- _gnutls_debug_log
- ("Importing Openpgp key and using main openpgp key.\n");
-
- dest->pk_algorithm =
- gnutls_openpgp_privkey_get_pk_algorithm (src, NULL);
- ret =
- _gnutls_openpgp_privkey_get_mpis (src, NULL, dest->params,
- &dest->params_size);
- }
-
-
- if (ret < 0)
- {
- gnutls_assert ();
- return ret;
- }
-
- return 0;
-
-}
-
/* Converts a parsed gnutls_openpgp_crt_t to a gnutls_cert structure.
*/
int
pk_algorithm = gnutls_openpgp_privkey_get_pk_algorithm (key, NULL);
- result = _gnutls_sign (pk_algorithm, params, params_size, hash, signature);
+ result = _gnutls_soft_sign (pk_algorithm, params, params_size, hash, signature);
+
+ for (i = 0; i < params_size; i++)
+ _gnutls_mpi_release (¶ms[i]);
+
+ if (result < 0)
+ {
+ gnutls_assert ();
+ return result;
+ }
+
+ return 0;
+}
+
+/**
+ * gnutls_openpgp_privkey_decrypt_data:
+ * @key: Holds the key
+ * @flags: zero for now
+ * @ciphertext: holds the data to be decrypted
+ * @plaintext: will contain newly allocated plaintext
+ *
+ * This function will sign the given hash using the private key. You
+ * should use gnutls_openpgp_privkey_set_preferred_key_id() before
+ * calling this function to set the subkey to use.
+ *
+ * Returns: On success, %GNUTLS_E_SUCCESS is returned, otherwise a
+ * negative error value.
+ **/
+int
+gnutls_openpgp_privkey_decrypt_data (gnutls_openpgp_privkey_t key,
+ unsigned int flags, const gnutls_datum_t * ciphertext,
+ gnutls_datum_t * plaintext)
+{
+ int result, i;
+ bigint_t params[MAX_PUBLIC_PARAMS_SIZE];
+ int params_size = MAX_PUBLIC_PARAMS_SIZE;
+ int pk_algorithm;
+ gnutls_openpgp_keyid_t keyid;
+
+ if (key == NULL)
+ {
+ gnutls_assert ();
+ return GNUTLS_E_INVALID_REQUEST;
+ }
+
+ result = gnutls_openpgp_privkey_get_preferred_key_id (key, keyid);
+ if (result == 0)
+ {
+ uint32_t kid[2];
+
+ KEYID_IMPORT (kid, keyid);
+ result = _gnutls_openpgp_privkey_get_mpis (key, kid,
+ params, ¶ms_size);
+ }
+ else
+ {
+ result = _gnutls_openpgp_privkey_get_mpis (key, NULL,
+ params, ¶ms_size);
+ }
+
+ if (result < 0)
+ {
+ gnutls_assert ();
+ return result;
+ }
+
+ pk_algorithm = gnutls_openpgp_privkey_get_pk_algorithm (key, NULL);
+
+ if (pk_algorithm != GNUTLS_PK_RSA)
+ {
+ gnutls_assert();
+ return GNUTLS_E_INVALID_REQUEST;
+ }
+
+ result = _gnutls_pkcs1_rsa_decrypt (plaintext, ciphertext, params, params_size, 2);
for (i = 0; i < params_size; i++)
_gnutls_mpi_release (¶ms[i]);
#include <auth_cert.h>
#include <opencdk.h>
+#include <gnutls/privkey.h>
/* OpenCDK compatible */
typedef enum
const gnutls_openpgp_keyid_t);
int
-_gnutls_openpgp_raw_privkey_to_gkey (gnutls_privkey * pkey,
+_gnutls_openpgp_raw_privkey_to_gkey (gnutls_privkey_t * pkey,
const gnutls_datum_t * raw_key);
int
int _gnutls_openpgp_crt_to_gcert (gnutls_cert * gcert,
gnutls_openpgp_crt_t cert);
-int _gnutls_openpgp_privkey_to_gkey (gnutls_privkey * dest,
- gnutls_openpgp_privkey_t src);
cdk_packet_t _gnutls_get_valid_subkey (cdk_kbnode_t knode, int key_type);
/*
- neon PKCS#11 support
- Copyright (C) 2008, Joe Orton <joe@manyfish.co.uk>
-
- This library is free software; you can redistribute it and/or
- modify it under the terms of the GNU Library General Public
- License as published by the Free Software Foundation; either
- version 2 of the License, or (at your option) any later version.
-
- This library is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- Library General Public License for more details.
-
- You should have received a copy of the GNU Library General Public
- License along with this library; if not, write to the Free
- Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
- MA 02111-1307, USA
+ * GnuTLS PKCS#11 support
+ * Copyright (C) 2010 Free Software Foundation
+ *
+ * Author: Nikos Mavrogiannopoulos
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the Free
+ * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
+ * MA 02111-1307, USA
*/
#include <gnutls_int.h>
-#include <pakchois/pakchois.h>
#include <gnutls/pkcs11.h>
#include <stdio.h>
#include <stdbool.h>
#include <string.h>
#include <gnutls_errors.h>
#include <gnutls_datum.h>
+#include <pkcs11_int.h>
#define MAX_PROVIDERS 16
-#define ID_SIZE 128
-#define LABEL_SIZE 128
/* XXX: try to eliminate this */
#define MAX_CERT_SIZE 8*1024
ck_slot_id_t *slots;
};
-
-struct pkcs11_url_info
-{
- /* everything here is null terminated strings */
- opaque id[ID_SIZE*3+1]; /* hex with delimiters */
- opaque type[16]; /* cert/key etc. */
- opaque manufacturer[sizeof (((struct ck_token_info *)NULL)->manufacturer_id)+1];
- opaque token[sizeof (((struct ck_token_info *)NULL)->label)+1];
- opaque serial[sizeof (((struct ck_token_info *)NULL)->serial_number)+1];
- opaque model[sizeof (((struct ck_token_info *)NULL)->model)+1];
- opaque label[LABEL_SIZE+1];
-};
-
struct gnutls_pkcs11_crt_st {
gnutls_datum_t raw;
gnutls_certificate_type_t type;
struct url_find_data_st {
gnutls_pkcs11_crt_t crt;
- char certid_raw[ID_SIZE];
- size_t certid_raw_size;
};
struct crt_find_data_st {
struct pkcs11_url_info info;
};
-struct token_info {
- struct ck_token_info tinfo;
- struct ck_slot_info sinfo;
- ck_slot_id_t sid;
- struct gnutls_pkcs11_provider_s* prov;
-};
-
-/* thus function is called for every token in the traverse_tokens
- * function. Once everything is traversed it is called with NULL tinfo.
- * It should return 0 if found what it was looking for.
- */
-typedef int (*find_func_t)(pakchois_session_t *pks, struct token_info* tinfo, void* input);
static struct gnutls_pkcs11_provider_s providers[MAX_PROVIDERS];
static int active_providers = 0;
static gnutls_pkcs11_pin_callback_t pin_func;
static void* pin_data;
+gnutls_pkcs11_token_callback_t token_func;
+void* token_data;
+
int gnutls_pkcs11_add_provider (const char * name, const char * params)
{
int gnutls_pkcs11_crt_get_info(gnutls_pkcs11_crt_t crt, gnutls_pkcs11_cert_info_t itype,
void* output, size_t* output_size)
{
- const char* str;
+ return pkcs11_get_info(&crt->info, itype, output, output_size);
+}
+
+int pkcs11_get_info(struct pkcs11_url_info *info, gnutls_pkcs11_cert_info_t itype,
+ void* output, size_t* output_size)
+{
+ const char* str = NULL;
size_t len;
switch(itype) {
+ case GNUTLS_PKCS11_CRT_ID:
+ if (*output_size < info->certid_raw_size) {
+ *output_size = info->certid_raw_size;
+ return GNUTLS_E_SHORT_MEMORY_BUFFER;
+ }
+ if (output) memcpy(output, info->certid_raw, info->certid_raw_size);
+ *output_size = info->certid_raw_size;
+
+ return 0;
case GNUTLS_PKCS11_CRT_ID_HEX:
- str = crt->info.id;
+ str = info->id;
break;
case GNUTLS_PKCS11_CRT_LABEL:
- str = crt->info.label;
+ str = info->label;
break;
case GNUTLS_PKCS11_CRT_TOKEN_LABEL:
- str = crt->info.token;
+ str = info->token;
break;
case GNUTLS_PKCS11_CRT_TOKEN_SERIAL:
- str = crt->info.serial;
+ str = info->serial;
break;
case GNUTLS_PKCS11_CRT_TOKEN_MANUFACTURER:
- str = crt->info.manufacturer;
+ str = info->manufacturer;
break;
case GNUTLS_PKCS11_CRT_TOKEN_MODEL:
- str = crt->info.model;
+ str = info->model;
break;
+ default:
+ gnutls_assert();
+ return GNUTLS_E_INVALID_REQUEST;
}
len = strlen(str);
return 0;
}
+static int init = 0;
int gnutls_pkcs11_init(unsigned int flags, const char* configfile)
{
int ret;
+ if (init != 0) {
+ init++;
+ return 0;
+ }
+ init++;
+
if (flags == GNUTLS_PKCS11_FLAG_MANUAL)
return 0;
else {
void gnutls_pkcs11_deinit (void)
{
int i;
+
+ init--;
+ if (init > 0)
+ return;
+ if (init < 0)
+ {
+ init = 0;
+ return;
+ }
for (i=0;i<active_providers;i++) {
pakchois_module_destroy(providers[i].module);
pin_data = userdata;
}
+void gnutls_pkcs11_set_token_function(gnutls_pkcs11_token_callback_t fn,
+ void *userdata)
+{
+ token_func = fn;
+ token_data = userdata;
+}
+
static int unescape_string (char* output, const char* input, size_t* size, char terminator)
{
gnutls_string str;
return ret;
}
-static int pkcs11_url_to_info(const char* url, struct pkcs11_url_info* info)
+int pkcs11_url_to_info(const char* url, struct pkcs11_url_info* info)
{
int ret;
char* p1, *p2;
memcpy(info->id, p1, l);
info->id[l] = 0;
+
+ /* convert to raw */
+ info->certid_raw_size = sizeof(info->certid_raw);
+ ret = _gnutls_hex2bin(info->id, strlen(info->id), info->certid_raw, &info->certid_raw_size);
+ if (ret < 0) {
+ gnutls_assert();
+ goto cleanup;
+ }
}
ret = 0;
gnutls_string str;
int init = 0;
int ret;
- char *s;
_gnutls_string_init (&str, gnutls_malloc, gnutls_realloc, gnutls_free);
int gnutls_pkcs11_crt_init(gnutls_pkcs11_crt_t * crt)
{
- *crt = gnutls_malloc(sizeof(struct gnutls_pkcs11_crt_st));
+ *crt = gnutls_calloc(1, sizeof(struct gnutls_pkcs11_crt_st));
if (*crt == NULL) {
gnutls_assert();
return GNUTLS_E_MEMORY_ERROR;
}
+ return 0;
}
void gnutls_pkcs11_crt_deinit(gnutls_pkcs11_crt_t crt)
}
-static int traverse_tokens (find_func_t find_func, void* input)
+int _pkcs11_traverse_tokens (find_func_t find_func, void* input, int leave_session)
{
- struct ck_attribute a[3];
ck_rv_t rv;
int found = 0, x, z, ret;
pakchois_session_t *pks = NULL;
ret = find_func(pks, &info, input);
- pakchois_close_session(pks);
- pks = NULL;
-
if (ret == 0) {
found = 1;
goto finish;
+ } else {
+ pakchois_close_session(pks);
+ pks = NULL;
}
}
}
ret = 0;
}
-cleanup:
- if (pks != NULL) pakchois_close_session(pks);
+ if (pks != NULL) {
+ if (leave_session==0 || ret != 0) {
+ pakchois_close_session(pks);
+ }
+ }
return ret;
}
gnutls_assert();
return GNUTLS_E_PKCS11_ERROR;
}
+
+ memmove(crt->info.certid_raw, id->data, id->size);
+ crt->info.certid_raw_size = id->size;
return 0;
}
ck_object_handle_t obj;
unsigned long count;
int found = 0, ret;
- unsigned char value[MAX_CERT_SIZE];
- char certid_tmp[ID_SIZE];
- char label_tmp[LABEL_SIZE];
+ opaque* cert_data = NULL;
+ char label_tmp[PKCS11_LABEL_SIZE];
if (info == NULL) { /* we don't support multiple calls */
gnutls_assert();
/* search the token for the id */
+ cert_data = gnutls_malloc(MAX_CERT_SIZE);
+ if (cert_data == NULL) {
+ gnutls_assert();
+ return GNUTLS_E_MEMORY_ERROR;
+ }
+
/* Find objects with cert class and X.509 cert type. */
class = CKO_CERTIFICATE;
type = CKC_X_509;
a[1].type = CKA_CERTIFICATE_TYPE;
a[1].value = &type;
a[1].value_len = sizeof type;
+ a[2].type = CKA_ID;
+ a[2].value = find_data->crt->info.certid_raw;
+ a[2].value_len = find_data->crt->info.certid_raw_size;
- rv = pakchois_find_objects_init(pks, a, 2);
+ rv = pakchois_find_objects_init(pks, a, 3);
if (rv != CKR_OK) {
gnutls_assert();
_gnutls_debug_log("pk11: FindObjectsInit failed.\n");
&& count == 1) {
a[0].type = CKA_VALUE;
- a[0].value = value;
- a[0].value_len = sizeof value;
- a[1].type = CKA_ID;
- a[1].value = certid_tmp;
- a[1].value_len = sizeof(certid_tmp);
- a[2].type = CKA_LABEL;
- a[2].value = label_tmp;
- a[2].value_len = sizeof(label_tmp);
-
- if (pakchois_get_attribute_value(pks, obj, a, 3) == CKR_OK) {
- if (a[1].value_len == find_data->certid_raw_size &&
- memcmp(certid_tmp, find_data->certid_raw, find_data->certid_raw_size)==0) {
- gnutls_datum_t id = { a[1].value, a[1].value_len };
- gnutls_datum_t data = { a[0].value, a[0].value_len };
- gnutls_datum_t label = { a[2].value, a[2].value_len };
-
- ret = pkcs11_crt_import(find_data->crt, &data, &id, &label, &info->tinfo);
- if (ret < 0) {
- gnutls_assert();
- goto cleanup;
- }
-
- found = 1;
- break;
+ a[0].value = cert_data;
+ a[0].value_len = MAX_CERT_SIZE;
+ a[1].type = CKA_LABEL;
+ a[1].value = label_tmp;
+ a[1].value_len = sizeof(label_tmp);
+
+ if (pakchois_get_attribute_value(pks, obj, a, 2) == CKR_OK) {
+ gnutls_datum_t id = { find_data->crt->info.certid_raw, find_data->crt->info.certid_raw_size };
+ gnutls_datum_t data = { a[0].value, a[0].value_len };
+ gnutls_datum_t label = { a[1].value, a[1].value_len };
+
+ ret = pkcs11_crt_import(find_data->crt, &data, &id, &label, &info->tinfo);
+ if (ret < 0) {
+ gnutls_assert();
+ goto cleanup;
}
+
+ found = 1;
+ break;
}
else {
_gnutls_debug_log("pk11: Skipped cert, missing attrs.\n");
}
cleanup:
+ gnutls_free(cert_data);
pakchois_find_objects_final(pks);
return ret;
return ret;
}
- find_data.certid_raw_size = sizeof(find_data.certid_raw);
-
- ret = _gnutls_hex2bin(cert->info.id, strlen(cert->info.id), find_data.certid_raw, &find_data.certid_raw_size);
- if (ret < 0) {
- gnutls_assert();
- return ret;
- }
-
- ret = traverse_tokens(find_cert_url, &find_data);
+ ret = _pkcs11_traverse_tokens(find_cert_url, &find_data, 0);
if (ret < 0) {
gnutls_assert();
return ret;
memset(&tn, 0, sizeof(tn));
tn.seq = seq;
-
- ret = traverse_tokens(find_token_num, &tn);
+
+ ret = _pkcs11_traverse_tokens(find_token_num, &tn, 0);
if (ret < 0) {
gnutls_assert();
return ret;
case GNUTLS_PKCS11_TOKEN_MODEL:
str = info.model;
break;
+ default:
+ gnutls_assert();
+ return GNUTLS_E_INVALID_REQUEST;
}
len = strlen(str);
size_t key_ids_size;
};
-static int pk11_login(pakchois_session_t *pks, struct token_info *info)
+int pkcs11_login(pakchois_session_t *pks, struct token_info *info)
{
- struct ck_token_info tinfo;
int attempt = 0;
ck_rv_t rv;
/* force login on HW tokens. Some tokens will not list private keys
* if login has not been performed.
*/
- if (!(info->sinfo.flags & CKF_HW_SLOT) && (tinfo.flags & CKF_LOGIN_REQUIRED) == 0) {
+// if (!(info->sinfo.flags & CKF_HW_SLOT) && (info->tinfo.flags & CKF_LOGIN_REQUIRED) == 0) {
+ if ((info->tinfo.flags & CKF_LOGIN_REQUIRED) == 0) {
gnutls_assert();
_gnutls_debug_log( "pk11: No login required.\n");
return 0;
/* For a token with a "protected" (out-of-band) authentication
* path, calling login with a NULL username is all that is
* required. */
- if (tinfo.flags & CKF_PROTECTED_AUTHENTICATION_PATH) {
+ if (info->tinfo.flags & CKF_PROTECTED_AUTHENTICATION_PATH) {
if (pakchois_login(pks, CKU_USER, NULL, 0) == CKR_OK) {
return 0;
}
}
rv = pakchois_login(pks, CKU_USER, (unsigned char *)pin, strlen(pin));
-
/* Try to scrub the pin off the stack. Clever compilers will
* probably optimize this away, oh well. */
memset(pin, 0, sizeof pin);
ck_rv_t rv;
ck_object_handle_t obj;
unsigned long count, current;
- char certid_tmp[ID_SIZE];
+ char certid_tmp[PKCS11_ID_SIZE];
int ret;
class = CKO_PRIVATE_KEY;
- ret = pk11_login(pks, info);
+ ret = pkcs11_login(pks, info);
if (ret < 0) {
gnutls_assert();
return ret;
ck_rv_t rv;
ck_object_handle_t obj;
unsigned long count;
- unsigned char value[MAX_CERT_SIZE];
- char certid_tmp[ID_SIZE];
- char label_tmp[LABEL_SIZE];
+ opaque *cert_data;
+ char certid_tmp[PKCS11_ID_SIZE];
+ char label_tmp[PKCS11_LABEL_SIZE];
int ret, i;
struct pkey_list plist; /* private key holder */
}
}
+ cert_data = gnutls_malloc(MAX_CERT_SIZE);
+ if (cert_data == NULL) {
+ gnutls_assert();
+ return GNUTLS_E_MEMORY_ERROR;
+ }
+
/* Find objects with cert class and X.509 cert type. */
class = CKO_CERTIFICATE;
type = CKC_X_509;
&& count == 1) {
a[0].type = CKA_VALUE;
- a[0].value = value;
- a[0].value_len = sizeof value;
+ a[0].value = cert_data;
+ a[0].value_len = MAX_CERT_SIZE;
a[1].type = CKA_ID;
a[1].value = certid_tmp;
a[1].value_len = sizeof(certid_tmp);
}
}
+ gnutls_free(cert_data);
pakchois_find_objects_final(pks);
return GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE; /* continue until all tokens have been checked */
fail:
+ gnutls_free(cert_data);
pakchois_find_objects_final(pks);
if (plist.key_ids != NULL) {
for (i=0;i<plist.key_ids_size;i++) {
return ret;
}
- ret = traverse_tokens(find_crts, &find_data);
+ ret = _pkcs11_traverse_tokens(find_crts, &find_data, 0);
if (ret < 0) {
gnutls_assert();
return ret;
*/
-#if 0
-#define KEYTYPE_IS_DSA(kt) (kt == CKK_DSA)
-
-
-static int find_client_cert(ne_ssl_pkcs11_provider *prov,
- pakchois_session_t *pks)
-{
- unsigned char certid[8192];
- unsigned long cid_len = sizeof certid;
-
- /* TODO: match cert subject too. */
- return pk11_find_x509(prov, pks, certid, &cid_len)
- && pk11_find_pkey(prov, pks, certid, cid_len);
-}
-
-/* Callback invoked by GnuTLS to provide the signature. The signature
- * operation is handled here by the PKCS#11 provider. */
-static int pk11_sign_callback(gnutls_session_t session,
- void *userdata,
- gnutls_certificate_type_t cert_type,
- const gnutls_datum_t *cert,
- const gnutls_datum_t *hash,
- gnutls_datum_t *signature)
-{
- ne_ssl_pkcs11_provider *prov = userdata;
- ck_rv_t rv;
- struct ck_mechanism mech;
- unsigned long siglen;
-
- if (!prov->session || prov->privkey == CK_INVALID_HANDLE) {
- NE_DEBUG(NE_DBG_SSL, "pk11: Cannot sign, no session/key.\n");
- return GNUTLS_E_NO_CERTIFICATE_FOUND;
- }
-
- mech.mechanism = prov->keytype == CKK_DSA ? CKM_DSA : CKM_RSA_PKCS;
- mech.parameter = NULL;
- mech.parameter_len = 0;
-
- /* Initialize signing operation; using the private key discovered
- * earlier. */
- rv = pakchois_sign_init(prov->session, &mech, prov->privkey);
- if (rv != CKR_OK) {
- NE_DEBUG(NE_DBG_SSL, "pk11: SignInit failed: %lx.\n", rv);
- return GNUTLS_E_PK_SIGN_FAILED;
- }
-
- /* Work out how long the signature must be: */
- rv = pakchois_sign(prov->session, hash->data, hash->size, NULL, &siglen);
- if (rv != CKR_OK) {
- NE_DEBUG(NE_DBG_SSL, "pk11: Sign1 failed.\n");
- return GNUTLS_E_PK_SIGN_FAILED;
- }
-
- signature->data = gnutls_malloc(siglen);
- signature->size = siglen;
-
- rv = pakchois_sign(prov->session, hash->data, hash->size,
- signature->data, &siglen);
- if (rv != CKR_OK) {
- NE_DEBUG(NE_DBG_SSL, "pk11: Sign2 failed.\n");
- return GNUTLS_E_PK_SIGN_FAILED;
- }
-
- NE_DEBUG(NE_DBG_SSL, "pk11: Signed successfully.\n");
-
- return 0;
-}
-
-static void terminate_string(unsigned char *str, size_t len)
-{
- unsigned char *ptr = str + len - 1;
-
- while ((*ptr == ' ' || *ptr == '\t' || *ptr == '\0') && ptr >= str)
- ptr--;
-
- if (ptr == str - 1)
- str[0] = '\0';
- else if (ptr == str + len - 1)
- str[len-1] = '\0';
- else
- ptr[1] = '\0';
-}
-
-
-static void pk11_provide(void *userdata, ne_session *sess,
- const ne_ssl_dname *const *dnames,
- int dncount)
-{
- ne_ssl_pkcs11_provider *prov = userdata;
- ck_slot_id_t *slots;
- unsigned long scount, n;
-
- if (prov->clicert) {
- NE_DEBUG(NE_DBG_SSL, "pk11: Using existing clicert.\n");
- ne_ssl_set_clicert(sess, prov->clicert);
- return;
- }
-
- if (pakchois_get_slot_list(prov->module, 1, NULL, &scount) != CKR_OK
- || scount == 0) {
- NE_DEBUG(NE_DBG_SSL, "pk11: No slots.\n");
- /* TODO: propagate error. */
- return;
- }
-
- slots = ne_malloc(scount * sizeof *slots);
- if (pakchois_get_slot_list(prov->module, 1, slots, &scount) != CKR_OK) {
- ne_free(slots);
- NE_DEBUG(NE_DBG_SSL, "pk11: Really, no slots?\n");
- /* TODO: propagate error. */
- return;
- }
-
- NE_DEBUG(NE_DBG_SSL, "pk11: Found %ld slots.\n", scount);
-
- for (n = 0; n < scount; n++) {
- pakchois_session_t *pks;
- ck_rv_t rv;
- struct ck_slot_info sinfo;
-
- if (pakchois_get_slot_info(prov->module, slots[n], &sinfo) != CKR_OK) {
- NE_DEBUG(NE_DBG_SSL, "pk11: GetSlotInfo failed\n");
- continue;
- }
-
- if ((sinfo.flags & CKF_TOKEN_PRESENT) == 0) {
- NE_DEBUG(NE_DBG_SSL, "pk11: slot empty, ignoring\n");
- continue;
- }
-
- rv = pakchois_open_session(prov->module, slots[n],
- CKF_SERIAL_SESSION,
- NULL, NULL, &pks);
- if (rv != CKR_OK) {
- NE_DEBUG(NE_DBG_SSL, "pk11: could not open slot, %ld (%ld: %ld)\n",
- rv, n, slots[n]);
- continue;
- }
-
- if (pk11_login(prov, slots[n], pks, &sinfo) == 0) {
- if (find_client_cert(prov, pks)) {
- NE_DEBUG(NE_DBG_SSL, "pk11: Setup complete.\n");
- prov->session = pks;
- ne_ssl_set_clicert(sess, prov->clicert);
- ne_free(slots);
- return;
- }
- }
-
- pakchois_close_session(pks);
- }
-
- ne_free(slots);
-}
-
-
-
-void ne_ssl_set_pkcs11_provider(ne_session *sess,
- ne_ssl_pkcs11_provider *provider)
-{
- sess->ssl_context->sign_func = pk11_sign_callback;
- sess->ssl_context->sign_data = provider;
-
- ne_ssl_provide_clicert(sess, pk11_provide, provider);
-}
-
-void ne_ssl_pkcs11_provider_destroy(ne_ssl_pkcs11_provider *prov)
-{
- if (prov->session) {
- pakchois_close_session(prov->session);
- }
- if (prov->clicert) {
- ne_ssl_clicert_free(prov->clicert);
- }
- pakchois_module_destroy(prov->module);
- ne_free(prov);
-}
-
-#endif
-
-
--- /dev/null
+#ifndef PKCS11_INT_H
+# define PKCS11_INT_H
+
+#include <pakchois/pakchois.h>
+#include <gnutls/pkcs11.h>
+
+#define PKCS11_ID_SIZE 128
+#define PKCS11_LABEL_SIZE 128
+
+struct token_info {
+ struct ck_token_info tinfo;
+ struct ck_slot_info sinfo;
+ ck_slot_id_t sid;
+ struct gnutls_pkcs11_provider_s* prov;
+};
+
+struct pkcs11_url_info
+{
+ /* everything here is null terminated strings */
+ opaque id[PKCS11_ID_SIZE*3+1]; /* hex with delimiters */
+ opaque type[16]; /* cert/key etc. */
+ opaque manufacturer[sizeof (((struct ck_token_info *)NULL)->manufacturer_id)+1];
+ opaque token[sizeof (((struct ck_token_info *)NULL)->label)+1];
+ opaque serial[sizeof (((struct ck_token_info *)NULL)->serial_number)+1];
+ opaque model[sizeof (((struct ck_token_info *)NULL)->model)+1];
+ opaque label[PKCS11_LABEL_SIZE+1];
+
+ opaque certid_raw[PKCS11_ID_SIZE]; /* same as ID but raw */
+ size_t certid_raw_size;
+};
+
+/* thus function is called for every token in the traverse_tokens
+ * function. Once everything is traversed it is called with NULL tinfo.
+ * It should return 0 if found what it was looking for.
+ */
+typedef int (*find_func_t)(pakchois_session_t *pks, struct token_info* tinfo, void* input);
+
+int _pkcs11_traverse_tokens (find_func_t find_func, void* input, int leave_session);
+int pkcs11_url_to_info(const char* url, struct pkcs11_url_info* info);
+
+int pkcs11_get_info(struct pkcs11_url_info *info, gnutls_pkcs11_cert_info_t itype,
+ void* output, size_t* output_size);
+int pkcs11_login(pakchois_session_t *pks, struct token_info *info);
+
+extern gnutls_pkcs11_token_callback_t token_func;
+extern void* token_data;
+
+
+#endif
--- /dev/null
+/*
+ * GnuTLS PKCS#11 support
+ * Copyright (C) 2010 Free Software Foundation
+ *
+ * Author: Nikos Mavrogiannopoulos
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the Free
+ * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
+ * MA 02111-1307, USA
+*/
+
+#include <gnutls_int.h>
+#include <pakchois/pakchois.h>
+#include <gnutls/pkcs11.h>
+#include <stdio.h>
+#include <stdbool.h>
+#include <string.h>
+#include <gnutls_errors.h>
+#include <gnutls_datum.h>
+#include <pkcs11_int.h>
+#include <sign.h>
+
+struct gnutls_pkcs11_privkey_st {
+ pakchois_session_t *pks;
+ ck_object_handle_t privkey;
+ gnutls_pk_algorithm_t pk_algorithm;
+ struct pkcs11_url_info info;
+};
+
+struct privkey_find_data_st {
+ gnutls_pkcs11_privkey_t privkey;
+};
+
+static int find_privkey_url(pakchois_session_t * pks,
+ struct token_info *info, void *input);
+
+int gnutls_pkcs11_privkey_init(gnutls_pkcs11_privkey_t * key)
+{
+ *key = gnutls_calloc(1, sizeof(struct gnutls_pkcs11_privkey_st));
+ if (*key == NULL) {
+ gnutls_assert();
+ return GNUTLS_E_MEMORY_ERROR;
+ }
+ (*key)->privkey = CK_INVALID_HANDLE;
+
+ return 0;
+}
+
+void gnutls_pkcs11_privkey_deinit(gnutls_pkcs11_privkey_t key)
+{
+ if (key->pks) {
+fprintf(stderr, "xxx: close session %p at %d\n", key->pks, __LINE__);
+ pakchois_close_session(key->pks);
+ }
+ gnutls_free(key);
+}
+
+int gnutls_pkcs11_privkey_get_pk_algorithm(gnutls_pkcs11_privkey_t key, unsigned int *bits)
+{
+ if (bits)
+ *bits = 0; /* FIXME */
+ return key->pk_algorithm;
+}
+
+int gnutls_pkcs11_privkey_get_info(gnutls_pkcs11_privkey_t pkey,
+ gnutls_pkcs11_cert_info_t itype,
+ void *output, size_t * output_size)
+{
+ return pkcs11_get_info(&pkey->info, itype, output, output_size);
+}
+
+#define RETRY_BLOCK_START(key) struct privkey_find_data_st find_data; \
+ int retries = 0; find_data.privkey = key; retry:
+
+
+
+#define RETRY_CHECK(rv, label) { \
+ if (token_func && rv == CKR_SESSION_HANDLE_INVALID) { \
+ ret = token_func(token_data, label, retries++); \
+ if (ret == 0) { \
+ _pkcs11_traverse_tokens(find_privkey_url, &find_data, 1); \
+ goto retry; \
+ } \
+ } \
+ }
+
+/**
+ * gnutls_pkcs11_privkey_sign_data:
+ * @signer: Holds the key
+ * @digest: should be MD5 or SHA1
+ * @flags: should be 0 for now
+ * @data: holds the data to be signed
+ * @signature: will contain the signature allocated with gnutls_malloc()
+ *
+ * This function will sign the given data using a signature algorithm
+ * supported by the private key. Signature algorithms are always used
+ * together with a hash functions. Different hash functions may be
+ * used for the RSA algorithm, but only SHA-1 for the DSA keys.
+ *
+ * Returns: On success, %GNUTLS_E_SUCCESS is returned, otherwise a
+ * negative error value.
+ **/
+int
+gnutls_pkcs11_privkey_sign_data(gnutls_pkcs11_privkey_t signer,
+ gnutls_digest_algorithm_t hash,
+ unsigned int flags,
+ const gnutls_datum_t * data,
+ gnutls_datum_t * signature)
+{
+ int ret;
+ gnutls_datum_t digest;
+
+ switch (signer->pk_algorithm) {
+ case GNUTLS_PK_RSA:
+ ret = pk_pkcs1_rsa_hash(hash, data, &digest);
+ if (ret < 0) {
+ gnutls_assert();
+ return ret;
+ }
+ break;
+ case GNUTLS_PK_DSA:
+ ret = pk_dsa_hash(data, &digest);
+ if (ret < 0) {
+ gnutls_assert();
+ return ret;
+ }
+
+ break;
+ default:
+ gnutls_assert();
+ return GNUTLS_E_INTERNAL_ERROR;
+ }
+
+ ret = gnutls_pkcs11_privkey_sign_hash(signer, &digest, signature);
+ _gnutls_free_datum(&digest);
+
+ if (ret < 0) {
+ gnutls_assert();
+ return ret;
+ }
+
+ return 0;
+
+}
+
+
+int gnutls_pkcs11_privkey_sign_hash(gnutls_pkcs11_privkey_t key,
+ const gnutls_datum_t * hash,
+ gnutls_datum_t * signature)
+{
+ ck_rv_t rv;
+ int ret;
+ struct ck_mechanism mech;
+ unsigned long siglen;
+
+ RETRY_BLOCK_START(key);
+
+ if (key->privkey == CK_INVALID_HANDLE) {
+ gnutls_assert();
+ return GNUTLS_E_PKCS11_ERROR;
+ }
+
+ mech.mechanism =
+ key->pk_algorithm == GNUTLS_PK_DSA ? CKM_DSA : CKM_RSA_PKCS;
+ mech.parameter = NULL;
+ mech.parameter_len = 0;
+
+ /* Initialize signing operation; using the private key discovered
+ * earlier. */
+ rv = pakchois_sign_init(key->pks, &mech, key->privkey);
+ if (rv != CKR_OK) {
+ RETRY_CHECK(rv, key->info.label);
+ gnutls_assert();
+ return GNUTLS_E_PK_SIGN_FAILED;
+ }
+
+ /* Work out how long the signature must be: */
+ rv = pakchois_sign(key->pks, hash->data, hash->size, NULL,
+ &siglen);
+ if (rv != CKR_OK) {
+ RETRY_CHECK(rv, key->info.label);
+ gnutls_assert();
+ return GNUTLS_E_PK_SIGN_FAILED;
+ }
+
+ signature->data = gnutls_malloc(siglen);
+ signature->size = siglen;
+
+ rv = pakchois_sign(key->pks, hash->data, hash->size,
+ signature->data, &siglen);
+ if (rv != CKR_OK) {
+ gnutls_free(signature->data);
+ gnutls_assert();
+ return GNUTLS_E_PK_SIGN_FAILED;
+ }
+
+ signature->size = siglen;
+
+ return 0;
+}
+
+static int find_privkey_url(pakchois_session_t * pks,
+ struct token_info *info, void *input)
+{
+ struct privkey_find_data_st *find_data = input;
+ struct ck_attribute a[4];
+ ck_object_class_t class;
+ ck_rv_t rv;
+ ck_object_handle_t obj;
+ unsigned long count;
+ int found = 0, ret;
+ ck_key_type_t keytype;
+
+ if (info == NULL) { /* we don't support multiple calls */
+ gnutls_assert();
+ return GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE;
+ }
+
+ /* do not bother reading the token if basic fields do not match
+ */
+ if (find_data->privkey->info.manufacturer[0] != 0) {
+ if (strcmp
+ (find_data->privkey->info.manufacturer,
+ info->tinfo.manufacturer_id) != 0)
+ return GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE;
+ }
+
+ if (find_data->privkey->info.token[0] != 0) {
+ if (strcmp
+ (find_data->privkey->info.token,
+ info->tinfo.label) != 0)
+ return GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE;
+ }
+
+ if (find_data->privkey->info.model[0] != 0) {
+ if (strcmp
+ (find_data->privkey->info.model,
+ info->tinfo.model) != 0)
+ return GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE;
+ }
+
+ if (find_data->privkey->info.serial[0] != 0) {
+ if (strcmp
+ (find_data->privkey->info.serial,
+ info->tinfo.serial_number) != 0)
+ return GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE;
+ }
+
+ if (find_data->privkey->info.type[0] != 0) {
+ if (strcmp(find_data->privkey->info.type, "cert") != 0) {
+ gnutls_assert();
+ return GNUTLS_E_UNIMPLEMENTED_FEATURE;
+ }
+ }
+
+ /* search the token for the id */
+ ret = pkcs11_login(pks, info);
+ if (ret < 0) {
+ gnutls_assert();
+ return ret;
+ }
+
+ /* Find objects with cert class and X.509 cert type. */
+ class = CKO_PRIVATE_KEY;
+
+ a[0].type = CKA_CLASS;
+ a[0].value = &class;
+ a[0].value_len = sizeof class;
+
+ a[1].type = CKA_ID;
+ a[1].value = find_data->privkey->info.certid_raw;
+ a[1].value_len = find_data->privkey->info.certid_raw_size;
+
+
+ rv = pakchois_find_objects_init(pks, a, 2);
+ if (rv != CKR_OK) {
+ gnutls_assert();
+ _gnutls_debug_log("pk11: FindObjectsInit failed.\n");
+ ret = GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE;
+ goto cleanup;
+ }
+
+ while (pakchois_find_objects(pks, &obj, 1, &count) == CKR_OK
+ && count == 1) {
+
+ a[0].type = CKA_KEY_TYPE;
+ a[0].value = &keytype;
+ a[0].value_len = sizeof keytype;
+
+ if (pakchois_get_attribute_value(pks, obj, a, 1) == CKR_OK) {
+ if (keytype == CKK_RSA)
+ find_data->privkey->pk_algorithm = GNUTLS_PK_RSA;
+ else if (keytype == CKK_DSA)
+ find_data->privkey->pk_algorithm = GNUTLS_PK_DSA;
+ else {
+ gnutls_assert();
+ ret =
+ GNUTLS_E_UNSUPPORTED_CERTIFICATE_TYPE;
+ goto cleanup;
+ }
+ find_data->privkey->pks = pks;
+ find_data->privkey->privkey = obj;
+ found = 1;
+ } else {
+ _gnutls_debug_log
+ ("pk11: Skipped cert, missing attrs.\n");
+ }
+ }
+
+ if (found == 0) {
+ gnutls_assert();
+ ret = GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE;
+ } else {
+ ret = 0;
+ }
+
+ cleanup:
+ pakchois_find_objects_final(pks);
+
+ return ret;
+}
+
+int gnutls_pkcs11_privkey_import_url(gnutls_pkcs11_privkey_t pkey,
+ const char *url)
+{
+ int ret;
+ struct privkey_find_data_st find_data;
+
+ /* fill in the find data structure */
+ find_data.privkey = pkey;
+
+ ret = pkcs11_url_to_info(url, &pkey->info);
+ if (ret < 0) {
+ gnutls_assert();
+ return ret;
+ }
+
+ if (pkey->info.id[0] == 0) {
+ gnutls_assert();
+ return GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE;
+ }
+
+ ret = _pkcs11_traverse_tokens(find_privkey_url, &find_data, 1);
+ if (ret < 0) {
+ gnutls_assert();
+ return ret;
+ }
+
+ return 0;
+}
+
+/**
+ * gnutls_pkcs11_privkey_decrypt_data:
+ * @key: Holds the key
+ * @flags: should be 0 for now
+ * @ciphertext: holds the data to be signed
+ * @plaintext: will contain the plaintext, allocated with gnutls_malloc()
+ *
+ * This function will decrypt the given data using the public key algorithm
+ * supported by the private key.
+ *
+ * Returns: On success, %GNUTLS_E_SUCCESS is returned, otherwise a
+ * negative error value.
+ **/
+int
+gnutls_pkcs11_privkey_decrypt_data(gnutls_pkcs11_privkey_t key,
+ unsigned int flags, const gnutls_datum_t * ciphertext,
+ gnutls_datum_t * plaintext)
+{
+ ck_rv_t rv;
+ int ret;
+ struct ck_mechanism mech;
+ unsigned long siglen;
+
+ RETRY_BLOCK_START(key);
+
+ if (key->privkey == CK_INVALID_HANDLE) {
+ gnutls_assert();
+ return GNUTLS_E_PKCS11_ERROR;
+ }
+
+ mech.mechanism =
+ key->pk_algorithm == GNUTLS_PK_DSA ? CKM_DSA : CKM_RSA_PKCS;
+ mech.parameter = NULL;
+ mech.parameter_len = 0;
+
+ /* Initialize signing operation; using the private key discovered
+ * earlier. */
+ rv = pakchois_decrypt_init(key->pks, &mech, key->privkey);
+ if (rv != CKR_OK) {
+ RETRY_CHECK(rv, key->info.label);
+ gnutls_assert();
+ return GNUTLS_E_PK_DECRYPTION_FAILED;
+ }
+
+ /* Work out how long the plaintext must be: */
+ rv = pakchois_decrypt(key->pks, ciphertext->data, ciphertext->size, NULL,
+ &siglen);
+ if (rv != CKR_OK) {
+ RETRY_CHECK(rv, key->info.label);
+ gnutls_assert();
+ return GNUTLS_E_PK_DECRYPTION_FAILED;
+ }
+
+ plaintext->data = gnutls_malloc(siglen);
+ plaintext->size = siglen;
+
+ rv = pakchois_decrypt(key->pks, ciphertext->data, ciphertext->size,
+ plaintext->data, &siglen);
+ if (rv != CKR_OK) {
+ gnutls_free(plaintext->data);
+ gnutls_assert();
+ return GNUTLS_E_PK_DECRYPTION_FAILED;
+ }
+
+ plaintext->size = siglen;
+
+ return 0;
+}
#include <x509_b64.h>
#include <x509_int.h>
#include <gnutls_pk.h>
+#include <sign.h>
static int _gnutls_asn1_encode_rsa (ASN1_TYPE * c2, bigint_t * params);
* @src: The source key
*
* This function will copy a private key from source to destination
- * key.
+ * key. Destination has to be initialized.
*
* Returns: On success, %GNUTLS_E_SUCCESS is returned, otherwise a
* negative error value.
return result;
}
-#ifdef ENABLE_PKI
/**
- * gnutls_x509_privkey_sign_data:
- * @key: Holds the key
- * @digest: should be MD5 or SHAx. May be ignored.
+ * gnutls_x509_privkey_sign_data2:
+ * @signer: Holds the key
+ * @digest: should be MD5 or SHA1
* @flags: should be 0 for now
* @data: holds the data to be signed
- * @signature: will contain the signature
- * @signature_size: holds the size of signature (and will be replaced
- * by the new size)
+ * @signature: will contain the signature allocate with gnutls_malloc()
*
* This function will sign the given data using a signature algorithm
* supported by the private key. Signature algorithms are always used
* negative error value.
**/
int
-gnutls_x509_privkey_sign_data (gnutls_x509_privkey_t key,
- gnutls_digest_algorithm_t digest,
+gnutls_x509_privkey_sign_data2 (gnutls_x509_privkey_t signer,
+ gnutls_digest_algorithm_t hash,
unsigned int flags,
const gnutls_datum_t * data,
- void *signature, size_t * signature_size)
+ gnutls_datum_t * signature)
{
- int result;
- gnutls_datum_t sig = { NULL, 0 };
-
- if (key == NULL)
+ int ret;
+ gnutls_datum_t digest;
+
+ switch (signer->pk_algorithm)
{
- gnutls_assert ();
- return GNUTLS_E_INVALID_REQUEST;
- }
+ case GNUTLS_PK_RSA:
+ ret =
+ pk_pkcs1_rsa_hash (hash, data, &digest);
+ if (ret < 0)
+ {
+ gnutls_assert ();
+ return ret;
+ }
+ break;
+ case GNUTLS_PK_DSA:
+ ret = pk_dsa_hash (data, &digest);
+ if (ret < 0)
+ {
+ gnutls_assert ();
+ return ret;
+ }
- result = _gnutls_x509_sign (data, digest, key, &sig);
- if (result < 0)
- {
+ break;
+ default:
gnutls_assert ();
- return result;
+ return GNUTLS_E_INTERNAL_ERROR;
}
-
- if (*signature_size < sig.size)
+
+ ret = gnutls_x509_privkey_sign_hash(signer, &digest, signature);
+ _gnutls_free_datum (&digest);
+
+ if (ret < 0)
{
- *signature_size = sig.size;
- _gnutls_free_datum (&sig);
- return GNUTLS_E_SHORT_MEMORY_BUFFER;
+ gnutls_assert ();
+ return ret;
}
- *signature_size = sig.size;
- memcpy (signature, sig.data, sig.size);
-
- _gnutls_free_datum (&sig);
-
return 0;
+
}
/**
return GNUTLS_E_INVALID_REQUEST;
}
- result = _gnutls_sign (key->pk_algorithm, key->params,
+ result = _gnutls_soft_sign (key->pk_algorithm, key->params,
key->params_size, hash, signature);
if (result < 0)
{
return 0;
}
+#ifdef ENABLE_PKI
+/**
+ * gnutls_x509_privkey_sign_data:
+ * @key: Holds the key
+ * @digest: should be MD5 or SHA1
+ * @flags: should be 0 for now
+ * @data: holds the data to be signed
+ * @signature: will contain the signature
+ * @signature_size: holds the size of signature (and will be replaced
+ * by the new size)
+ *
+ * This function will sign the given data using a signature algorithm
+ * supported by the private key. Signature algorithms are always used
+ * together with a hash functions. Different hash functions may be
+ * used for the RSA algorithm, but only SHA-1 for the DSA keys.
+ *
+ * If the buffer provided is not long enough to hold the output, then
+ * *@signature_size is updated and %GNUTLS_E_SHORT_MEMORY_BUFFER will
+ * be returned.
+ *
+ * Returns: On success, %GNUTLS_E_SUCCESS is returned, otherwise a
+ * negative error value.
+ **/
+int
+gnutls_x509_privkey_sign_data (gnutls_x509_privkey_t key,
+ gnutls_digest_algorithm_t digest,
+ unsigned int flags,
+ const gnutls_datum_t * data,
+ void *signature, size_t * signature_size)
+{
+ int result;
+ gnutls_datum_t sig = { NULL, 0 };
+
+ if (key == NULL)
+ {
+ gnutls_assert ();
+ return GNUTLS_E_INVALID_REQUEST;
+ }
+
+ result = gnutls_x509_privkey_sign_data2(key, digest, flags, data, &sig);
+ if (result < 0)
+ {
+ gnutls_assert ();
+ return result;
+ }
+
+ if (*signature_size < sig.size)
+ {
+ *signature_size = sig.size;
+ _gnutls_free_datum (&sig);
+ return GNUTLS_E_SHORT_MEMORY_BUFFER;
+ }
+
+ *signature_size = sig.size;
+ memcpy (signature, sig.data, sig.size);
+
+ _gnutls_free_datum (&sig);
+
+ return 0;
+}
+
+
/**
* gnutls_x509_privkey_verify_data:
* @key: Holds the key
#include <gnutls_datum.h>
#include <x509_int.h>
#include <common.h>
+#include <sign.h>
/* Writes the digest information and the digest in a DER encoded
* structure. The digest info is allocated and stored into the info structure.
* params[0] is modulus
* params[1] is public key
*/
-static int
-pkcs1_rsa_sign (gnutls_digest_algorithm_t hash, const gnutls_datum_t * text,
- bigint_t * params, int params_len, gnutls_datum_t * signature)
+int
+pk_pkcs1_rsa_hash (gnutls_digest_algorithm_t hash, const gnutls_datum_t * text, gnutls_datum_t * output)
{
int ret;
opaque _digest[MAX_HASH_SIZE];
digest_hd_st hd;
- gnutls_datum_t digest, info;
+ gnutls_datum_t digest;
ret = _gnutls_hash_init (&hd, HASH2MAC (hash));
if (ret < 0)
/* Encode the digest as a DigestInfo
*/
- if ((ret = encode_ber_digest_info (hash, &digest, &info)) != 0)
+ if ((ret = encode_ber_digest_info (hash, &digest, output)) != 0)
{
gnutls_assert ();
return ret;
}
- if ((ret =
- _gnutls_sign (GNUTLS_PK_RSA, params, params_len, &info,
- signature)) < 0)
- {
- gnutls_assert ();
- _gnutls_free_datum (&info);
- return ret;
- }
-
- _gnutls_free_datum (&info);
-
return 0;
}
-static int
-dsa_sign (const gnutls_datum_t * text,
- bigint_t * params, int params_len, gnutls_datum_t * signature)
+int
+pk_dsa_hash (const gnutls_datum_t * text, gnutls_datum_t * hash)
{
int ret;
opaque _digest[MAX_HASH_SIZE];
return 0;
}
-/* Signs the given data using the parameters from the signer's
- * private key.
- *
- * returns 0 on success.
- *
- * 'tbs' is the data to be signed
- * 'signature' will hold the signature!
- * 'hash' is only used in PKCS1 RSA signing.
- */
-int
-_gnutls_x509_sign (const gnutls_datum_t * tbs,
- gnutls_digest_algorithm_t hash,
- gnutls_x509_privkey_t signer, gnutls_datum_t * signature)
-{
- int ret;
-
- switch (signer->pk_algorithm)
- {
- case GNUTLS_PK_RSA:
- ret =
- pkcs1_rsa_sign (hash, tbs, signer->params, signer->params_size,
- signature);
- if (ret < 0)
- {
- gnutls_assert ();
- return ret;
- }
- return 0;
- break;
- case GNUTLS_PK_DSA:
- ret = dsa_sign (tbs, signer->params, signer->params_size, signature);
- if (ret < 0)
- {
- gnutls_assert ();
- return ret;
- }
-
- return 0;
- break;
- default:
- gnutls_assert ();
- return GNUTLS_E_INTERNAL_ERROR;
- }
-
-}
-
/* This is the same as the _gnutls_x509_sign, but this one will decode
* the ASN1_TYPE given, and sign the DER data. Actually used to get the DER
* of the TBS and sign it on the fly.
tbs.data = buf;
tbs.size = buf_size;
- result = _gnutls_x509_sign (&tbs, hash, signer, signature);
+ result = gnutls_x509_privkey_sign_data2 (signer, hash, 0, &tbs, signature);
gnutls_free (buf);
return result;
--- /dev/null
+#ifndef GNUTLS_SIGN_H
+# define GNUTLS_SIGN_H
+
+int pk_pkcs1_rsa_hash (gnutls_digest_algorithm_t hash, const gnutls_datum_t * text, gnutls_datum_t * output);
+int pk_dsa_hash (const gnutls_datum_t * text, gnutls_datum_t * hash);
+
+#endif
gnutls_datum_t * dn);
/* sign.c */
-int _gnutls_x509_sign (const gnutls_datum_t * tbs,
- gnutls_digest_algorithm_t hash,
- gnutls_x509_privkey_t signer,
- gnutls_datum_t * signature);
int _gnutls_x509_sign_tbs (ASN1_TYPE cert, const char *tbs_name,
gnutls_digest_algorithm_t hash,
gnutls_x509_privkey_t signer,
#include <gnutls/extra.h>
#include <gnutls/x509.h>
#include <gnutls/openpgp.h>
+#include <gnutls/pkcs11.h>
#include <gcrypt.h>
/* Gnulib portability files. */
static gnutls_x509_crt_t x509_crt[MAX_CRT];
static gnutls_x509_privkey_t x509_key = NULL;
+static gnutls_pkcs11_privkey_t pkcs11_key = NULL;
+
static gnutls_openpgp_crt_t pgp_crt = NULL;
static gnutls_openpgp_privkey_t pgp_key = NULL;
if (x509_certfile != NULL && x509_keyfile != NULL)
{
- data = load_file (x509_certfile);
- if (data.data == NULL)
+ if (strncmp (x509_certfile, "pkcs11:", 7) == 0)
{
- fprintf (stderr, "*** Error loading cert file.\n");
- exit (1);
- }
+ crt_num = 1;
+ gnutls_x509_crt_init (&x509_crt[0]);
- crt_num = MAX_CRT;
- ret =
- gnutls_x509_crt_list_import (x509_crt, &crt_num, &data,
- GNUTLS_X509_FMT_PEM,
- GNUTLS_X509_CRT_LIST_IMPORT_FAIL_IF_EXCEED);
- if (ret < 0)
- {
- if (ret == GNUTLS_E_SHORT_MEMORY_BUFFER)
+ ret =
+ gnutls_x509_crt_import_pkcs11_url (x509_crt[0], x509_certfile);
+ if (ret < 0)
{
- fprintf (stderr,
- "*** Error loading cert file: Too many certs %d\n",
- crt_num);
+ fprintf (stderr, "*** Error loading cert file.\n");
+ exit (1);
+ }
+ x509_crt_size = 1;
+ }
+ else
+ {
+ data = load_file (x509_certfile);
+ if (data.data == NULL)
+ {
+ fprintf (stderr, "*** Error loading cert file.\n");
+ exit (1);
}
- else
+
+ crt_num = MAX_CRT;
+ ret =
+ gnutls_x509_crt_list_import (x509_crt, &crt_num, &data,
+ GNUTLS_X509_FMT_PEM,
+ GNUTLS_X509_CRT_LIST_IMPORT_FAIL_IF_EXCEED);
+ if (ret < 0)
{
- fprintf (stderr,
- "*** Error loading cert file: %s\n",
- gnutls_strerror (ret));
+ if (ret == GNUTLS_E_SHORT_MEMORY_BUFFER)
+ {
+ fprintf (stderr,
+ "*** Error loading cert file: Too many certs %d\n",
+ crt_num);
+
+ }
+ else
+ {
+ fprintf (stderr,
+ "*** Error loading cert file: %s\n",
+ gnutls_strerror (ret));
+ }
+ exit (1);
}
- exit (1);
+ x509_crt_size = ret;
}
- x509_crt_size = ret;
fprintf (stderr, "Processed %d client certificates...\n", ret);
unload_file (data);
- data = load_file (x509_keyfile);
- if (data.data == NULL)
+ if (strncmp (x509_keyfile, "pkcs11:", 7) == 0)
{
- fprintf (stderr, "*** Error loading key file.\n");
- exit (1);
+ gnutls_pkcs11_privkey_init (&pkcs11_key);
+
+ ret = gnutls_pkcs11_privkey_import_url (pkcs11_key, x509_keyfile);
}
+ else
+ {
+ data = load_file (x509_keyfile);
+ if (data.data == NULL)
+ {
+ fprintf (stderr, "*** Error loading key file.\n");
+ exit (1);
+ }
- gnutls_x509_privkey_init (&x509_key);
+ gnutls_x509_privkey_init (&x509_key);
- ret = gnutls_x509_privkey_import (x509_key, &data, GNUTLS_X509_FMT_PEM);
- if (ret < 0)
- {
- fprintf (stderr, "*** Error loading key file: %s\n",
- gnutls_strerror (ret));
- exit (1);
- }
+ ret =
+ gnutls_x509_privkey_import (x509_key, &data, GNUTLS_X509_FMT_PEM);
+ if (ret < 0)
+ {
+ fprintf (stderr, "*** Error loading key file: %s\n",
+ gnutls_strerror (ret));
+ exit (1);
+ }
- unload_file (data);
+ unload_file (data);
+ }
fprintf (stderr, "Processed %d client X.509 certificates...\n",
x509_crt_size);
unload_file (data);
- data = load_file (pgp_keyfile);
- if (data.data == NULL)
+ if (strncmp (pgp_keyfile, "pkcs11:", 7) == 0)
{
- fprintf (stderr, "*** Error loading PGP key file.\n");
- exit (1);
+ gnutls_pkcs11_privkey_init (&pkcs11_key);
+
+ ret = gnutls_pkcs11_privkey_import_url (pkcs11_key, pgp_keyfile);
}
+ else
+ {
- gnutls_openpgp_privkey_init (&pgp_key);
+ data = load_file (pgp_keyfile);
+ if (data.data == NULL)
+ {
+ fprintf (stderr, "*** Error loading PGP key file.\n");
+ exit (1);
+ }
- ret =
- gnutls_openpgp_privkey_import (pgp_key, &data,
- GNUTLS_OPENPGP_FMT_BASE64, NULL, 0);
- if (ret < 0)
- {
- fprintf (stderr,
- "*** Error loading PGP key file: %s\n",
- gnutls_strerror (ret));
- exit (1);
- }
+ gnutls_openpgp_privkey_init (&pgp_key);
- unload_file (data);
+ ret =
+ gnutls_openpgp_privkey_import (pgp_key, &data,
+ GNUTLS_OPENPGP_FMT_BASE64, NULL,
+ 0);
+ if (ret < 0)
+ {
+ fprintf (stderr,
+ "*** Error loading PGP key file: %s\n",
+ gnutls_strerror (ret));
+ exit (1);
+ }
+
+ unload_file (data);
+ }
if (info.pgp_subkey != NULL)
{
cert_callback (gnutls_session_t session,
const gnutls_datum_t * req_ca_rdn, int nreqs,
const gnutls_pk_algorithm_t * sign_algos,
- int sign_algos_length, gnutls_retr_st * st)
+ int sign_algos_length, gnutls_retr2_st * st)
{
char issuer_dn[256];
int i, ret;
if (verbose)
{
-
/* Print the server's trusted CAs
*/
if (nreqs > 0)
* supported by the server.
*/
- st->type = gnutls_certificate_type_get (session);
-
+ st->cert_type = gnutls_certificate_type_get (session);
st->ncerts = 0;
- if (st->type == GNUTLS_CRT_X509)
+ if (st->cert_type == GNUTLS_CRT_X509)
{
gnutls_sign_algorithm_t cert_algo, req_algo;
int i, match = 0;
}
}
- if (x509_crt != NULL && x509_key != NULL)
+ if (x509_key != NULL)
+ {
+ st->key.x509 = x509_key;
+ st->key_type = GNUTLS_PRIVKEY_X509;
+ }
+ else if (pkcs11_key != NULL)
+ {
+ st->key.pkcs11 = pkcs11_key;
+ st->key_type = GNUTLS_PRIVKEY_PKCS11;
+ }
+ else
+ {
+ printf ("- Could not find a suitable key to send to server\n");
+ return -1;
+ }
+
+ if (x509_crt != NULL)
{
st->ncerts = x509_crt_size;
st->cert.x509 = x509_crt;
- st->key.x509 = x509_key;
st->deinit_all = 0;
return 0;
}
}
- else if (st->type == GNUTLS_CRT_OPENPGP)
+ else if (st->cert_type == GNUTLS_CRT_OPENPGP)
{
- if (pgp_key != NULL && pgp_crt != NULL)
+ if (pgp_key != NULL)
+ {
+ st->key.pgp = pgp_key;
+ st->key_type = GNUTLS_PRIVKEY_OPENPGP;
+ }
+ else if (pkcs11_key != NULL)
+ {
+ st->key.pkcs11 = pkcs11_key;
+ st->key_type = GNUTLS_PRIVKEY_PKCS11;
+ }
+ else
+ {
+ printf ("- Could not find a suitable key to send to server\n");
+ return -1;
+ }
+
+ if (pgp_crt != NULL)
{
st->ncerts = 1;
st->cert.pgp = pgp_crt;
- st->key.pgp = pgp_key;
st->deinit_all = 0;
gnutls_credentials_set (session, GNUTLS_CRD_PSK, psk_cred);
gnutls_credentials_set (session, GNUTLS_CRD_CERTIFICATE, xcred);
- gnutls_certificate_client_set_retrieve_function (xcred, cert_callback);
+ gnutls_certificate_set_retrieve_function (xcred, cert_callback);
gnutls_certificate_set_verify_function (xcred, cert_verify_callback);
/* send the fingerprint */
exit (1);
}
+ pkcs11_common ();
gaa_parser (argc, argv);
if (hostname == NULL)
{
#include <gnutls/openpgp.h>
#include <time.h>
#include <common.h>
+#include <gnutls/pkcs11.h>
#define SU(x) (x!=NULL?x:"Unknown")
+#define MIN(x,y) ((x)<(y))?(x):(y)
int print_cert;
extern int verbose;
return ntohs (server_port->s_port);
}
+
+static int pin_callback(void* user, int attempt, const char *slot_descr,
+ const char *token_label, unsigned int flags, char* pin, size_t pin_max)
+{
+const char* password;
+int len;
+
+ printf("PIN required for token '%s' in slot '%s'\n", token_label, slot_descr);
+ if (flags & GNUTLS_PKCS11_PIN_FINAL_TRY)
+ printf("*** This is the final try before locking!\n");
+ if (flags & GNUTLS_PKCS11_PIN_COUNT_LOW)
+ printf("*** Only few tries left before locking!\n");
+
+ password = getpass("Enter pin: ");
+ if (password==NULL || password[0] == 0) {
+ fprintf(stderr, "No password given\n");
+ exit(1);
+ }
+
+ len = MIN(pin_max,strlen(password));
+ memcpy(pin, password, len);
+ pin[len] = 0;
+
+ return 0;
+}
+
+void pkcs11_common(void)
+{
+
+ gnutls_pkcs11_set_pin_function (pin_callback, NULL);
+
+}
int *protocol_priority);
const char *raw_to_string (const unsigned char *raw, size_t raw_size);
int service_to_port (const char *service);
-
+void pkcs11_common(void);
void sockets_init (void);
const char *token_label, unsigned int flags, char* pin, size_t pin_max)
{
const char* password;
+int len;
printf("PIN required for token '%s' in slot '%s'\n", token_label, slot_descr);
if (flags & GNUTLS_PKCS11_PIN_FINAL_TRY)
fprintf(stderr, "No password given\n");
exit(1);
}
- memcpy(pin, password, MIN(pin_max,strlen(password)));
+ len = MIN(pin_max,strlen(password));
+ memcpy(pin, password, len);
+ pin[len] = 0;
+
return 0;
}
exit (1);
}
+ pkcs11_common();
gnutls_global_set_log_function (tls_log_func);
gnutls_global_set_log_level (debug);