summaryrefslogtreecommitdiff
path: root/lib/pkcs11_privkey.c
diff options
context:
space:
mode:
authorNikos Mavrogiannopoulos <nmav@redhat.com>2014-08-07 14:19:25 +0200
committerNikos Mavrogiannopoulos <nmav@redhat.com>2014-08-07 14:29:53 +0200
commit388f2bd531c3f787f98a4fcd6fd6a4325c1690dd (patch)
tree504a7e10a1f4a0bb53fc43a3106fd5de513be407 /lib/pkcs11_privkey.c
parent93f726973cea68225a513c0cf57d2de556c56616 (diff)
downloadgnutls-388f2bd531c3f787f98a4fcd6fd6a4325c1690dd.tar.gz
pkcs11: simplified pkcs11_privkey handling
A PKCS #11 always holds an open session to the key.
Diffstat (limited to 'lib/pkcs11_privkey.c')
-rw-r--r--lib/pkcs11_privkey.c163
1 files changed, 47 insertions, 116 deletions
diff --git a/lib/pkcs11_privkey.c b/lib/pkcs11_privkey.c
index 76179a4824..68e6ee6c4a 100644
--- a/lib/pkcs11_privkey.c
+++ b/lib/pkcs11_privkey.c
@@ -31,30 +31,41 @@
#include <p11-kit/uri.h>
/* In case of a fork, it will invalidate the open session
- * in privkey */
+ * in the privkey and start another */
#define PKCS11_CHECK_INIT_PRIVKEY(k) \
ret = _gnutls_pkcs11_check_init(); \
if (ret < 0) \
return gnutls_assert_val(ret); \
- if (ret == 1) \
- memset(&k->sinfo, 0, sizeof(k->sinfo))
-
-#define CHECK_SHANDLE(rv, key, sinfo) \
- if (rv == CKR_SESSION_HANDLE_INVALID && sinfo == &key->sinfo) { \
- if (key->sinfo.init != 0) { \
- pkcs11_close_session(&key->sinfo); \
- key->sinfo.init = 0; \
- goto restart; \
- } \
- }
+ if (ret == 1) { \
+ memset(&k->sinfo, 0, sizeof(k->sinfo)); \
+ FIND_OBJECT(k); \
+ }
+
+#define FIND_OBJECT(key) \
+ do { \
+ int retries = 0; \
+ int rret; \
+ ret = find_object (&key->sinfo, &key->pin, &key->ref, key->uinfo, \
+ SESSION_LOGIN); \
+ if (ret == GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE) { \
+ if (_gnutls_token_func) \
+ { \
+ rret = pkcs11_call_token_func (key->uinfo, retries++); \
+ if (rret == 0) continue; \
+ } \
+ return gnutls_assert_val(ret); \
+ } else if (ret < 0) { \
+ return gnutls_assert_val(ret); \
+ } \
+ } while (0);
struct gnutls_pkcs11_privkey_st {
gnutls_pk_algorithm_t pk_algorithm;
unsigned int flags;
- struct p11_kit_uri *info;
+ struct p11_kit_uri *uinfo;
struct pkcs11_session_info sinfo;
- ck_object_handle_t obj; /* the key in the session */
+ ck_object_handle_t ref; /* the key in the session */
struct pin_info_st pin;
};
@@ -78,8 +89,8 @@ int gnutls_pkcs11_privkey_init(gnutls_pkcs11_privkey_t * key)
return GNUTLS_E_MEMORY_ERROR;
}
- (*key)->info = p11_kit_uri_new();
- if ((*key)->info == NULL) {
+ (*key)->uinfo = p11_kit_uri_new();
+ if ((*key)->uinfo == NULL) {
free(*key);
gnutls_assert();
return GNUTLS_E_MEMORY_ERROR;
@@ -96,7 +107,7 @@ int gnutls_pkcs11_privkey_init(gnutls_pkcs11_privkey_t * key)
**/
void gnutls_pkcs11_privkey_deinit(gnutls_pkcs11_privkey_t key)
{
- p11_kit_uri_free(key->info);
+ p11_kit_uri_free(key->uinfo);
if (key->sinfo.init != 0)
pkcs11_close_session(&key->sinfo);
gnutls_free(key);
@@ -141,7 +152,7 @@ gnutls_pkcs11_privkey_get_info(gnutls_pkcs11_privkey_t pkey,
gnutls_pkcs11_obj_info_t itype,
void *output, size_t * output_size)
{
- return pkcs11_get_info(pkey->info, itype, output, output_size);
+ return pkcs11_get_info(pkey->uinfo, itype, output, output_size);
}
static int
@@ -190,23 +201,6 @@ find_object(struct pkcs11_session_info *sinfo,
return ret;
}
-#define FIND_OBJECT(sinfo, pin_info, obj, key) \
- do { \
- int retries = 0; \
- int rret; \
- ret = find_object (sinfo, pin_info, &obj, key->info, \
- SESSION_LOGIN); \
- if (ret == GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE) { \
- if (_gnutls_token_func) \
- { \
- rret = pkcs11_call_token_func (key->info, retries++); \
- if (rret == 0) continue; \
- } \
- return gnutls_assert_val(ret); \
- } else if (ret < 0) { \
- return gnutls_assert_val(ret); \
- } \
- } while (0);
/*-
@@ -232,21 +226,11 @@ _gnutls_pkcs11_privkey_sign_hash(gnutls_pkcs11_privkey_t key,
struct ck_mechanism mech;
gnutls_datum_t tmp = { NULL, 0 };
unsigned long siglen;
- struct pkcs11_session_info _sinfo;
struct pkcs11_session_info *sinfo;
- ck_object_handle_t obj;
PKCS11_CHECK_INIT_PRIVKEY(key);
- restart:
- if (key->sinfo.init != 0) {
- sinfo = &key->sinfo;
- obj = key->obj;
- } else {
- sinfo = &_sinfo;
- memset(sinfo, 0, sizeof(*sinfo));
- FIND_OBJECT(sinfo, &key->pin, obj, key);
- }
+ sinfo = &key->sinfo;
mech.mechanism = pk_to_mech(key->pk_algorithm);
mech.parameter = NULL;
@@ -254,10 +238,9 @@ _gnutls_pkcs11_privkey_sign_hash(gnutls_pkcs11_privkey_t key,
/* Initialize signing operation; using the private key discovered
* earlier. */
- rv = pkcs11_sign_init(sinfo->module, sinfo->pks, &mech, obj);
+ rv = pkcs11_sign_init(sinfo->module, sinfo->pks, &mech, key->ref);
if (rv != CKR_OK) {
gnutls_assert();
- CHECK_SHANDLE(rv, key, sinfo);
ret = pkcs11_rv_to_err(rv);
goto cleanup;
}
@@ -267,7 +250,6 @@ _gnutls_pkcs11_privkey_sign_hash(gnutls_pkcs11_privkey_t key,
NULL, &siglen);
if (rv != CKR_OK) {
gnutls_assert();
- CHECK_SHANDLE(rv, key, sinfo);
ret = pkcs11_rv_to_err(rv);
goto cleanup;
}
@@ -279,7 +261,6 @@ _gnutls_pkcs11_privkey_sign_hash(gnutls_pkcs11_privkey_t key,
tmp.data, &siglen);
if (rv != CKR_OK) {
gnutls_assert();
- CHECK_SHANDLE(rv, key, sinfo);
ret = pkcs11_rv_to_err(rv);
goto cleanup;
}
@@ -342,34 +323,18 @@ int gnutls_pkcs11_privkey_status(gnutls_pkcs11_privkey_t key)
{
ck_rv_t rv;
int ret;
- struct pkcs11_session_info _sinfo;
- struct pkcs11_session_info *sinfo;
- ck_object_handle_t obj;
struct ck_session_info session_info;
PKCS11_CHECK_INIT_PRIVKEY(key);
- restart:
- if (key->sinfo.init != 0) {
- sinfo = &key->sinfo;
- obj = key->obj;
- } else {
- sinfo = &_sinfo;
- memset(sinfo, 0, sizeof(*sinfo));
- FIND_OBJECT(sinfo, &key->pin, obj, key);
- }
-
- rv = (sinfo->module)->C_GetSessionInfo(sinfo->pks, &session_info);
+ rv = (key->sinfo.module)->C_GetSessionInfo(key->sinfo.pks, &session_info);
if (rv != CKR_OK) {
- CHECK_SHANDLE(rv, key, sinfo);
ret = 0;
goto cleanup;
}
ret = 1;
cleanup:
- if (sinfo != &key->sinfo)
- pkcs11_close_session(sinfo);
return ret;
}
@@ -394,16 +359,14 @@ gnutls_pkcs11_privkey_import_url(gnutls_pkcs11_privkey_t pkey,
{
int ret;
struct ck_attribute *attr;
- ck_object_handle_t obj;
struct ck_attribute a[4];
ck_key_type_t key_type;
- struct pkcs11_session_info sinfo;
PKCS11_CHECK_INIT;
- memset(&sinfo, 0, sizeof(sinfo));
+ memset(&pkey->sinfo, 0, sizeof(pkey->sinfo));
- ret = pkcs11_url_to_info(url, &pkey->info);
+ ret = pkcs11_url_to_info(url, &pkey->uinfo);
if (ret < 0) {
gnutls_assert();
return ret;
@@ -411,29 +374,29 @@ gnutls_pkcs11_privkey_import_url(gnutls_pkcs11_privkey_t pkey,
pkey->flags = flags;
- attr = p11_kit_uri_get_attribute(pkey->info, CKA_CLASS);
+ attr = p11_kit_uri_get_attribute(pkey->uinfo, CKA_CLASS);
if (!attr || attr->value_len != sizeof(ck_object_class_t) ||
*(ck_object_class_t *) attr->value != CKO_PRIVATE_KEY) {
gnutls_assert();
return GNUTLS_E_INVALID_REQUEST;
}
- attr = p11_kit_uri_get_attribute(pkey->info, CKA_ID);
+ attr = p11_kit_uri_get_attribute(pkey->uinfo, CKA_ID);
if (!attr) {
- attr = p11_kit_uri_get_attribute(pkey->info, CKA_LABEL);
+ attr = p11_kit_uri_get_attribute(pkey->uinfo, CKA_LABEL);
if (!attr) {
gnutls_assert();
return GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE;
}
}
- FIND_OBJECT(&sinfo, &pkey->pin, obj, pkey);
+ FIND_OBJECT(pkey);
a[0].type = CKA_KEY_TYPE;
a[0].value = &key_type;
a[0].value_len = sizeof(key_type);
- if (pkcs11_get_attribute_value(sinfo.module, sinfo.pks, obj, a, 1)
+ if (pkcs11_get_attribute_value(pkey->sinfo.module, pkey->sinfo.pks, pkey->ref, a, 1)
== CKR_OK) {
pkey->pk_algorithm = mech_to_pk(key_type);
if (pkey->pk_algorithm == GNUTLS_PK_UNKNOWN) {
@@ -446,20 +409,10 @@ gnutls_pkcs11_privkey_import_url(gnutls_pkcs11_privkey_t pkey,
ret = 0;
- if (pkey->sinfo.init)
- pkcs11_close_session(&pkey->sinfo);
-
- if (sinfo.tinfo.max_session_count != 1) {
- /* We do not keep the session open in tokens that can
- * only support a single session.
- */
- memcpy(&pkey->sinfo, &sinfo, sizeof(pkey->sinfo));
- pkey->obj = obj;
- return ret;
- }
+ return ret;
cleanup:
- pkcs11_close_session(&sinfo);
+ pkcs11_close_session(&pkey->sinfo);
return ret;
}
@@ -487,22 +440,9 @@ _gnutls_pkcs11_privkey_decrypt_data(gnutls_pkcs11_privkey_t key,
int ret;
struct ck_mechanism mech;
unsigned long siglen;
- ck_object_handle_t obj;
- struct pkcs11_session_info _sinfo;
- struct pkcs11_session_info *sinfo;
PKCS11_CHECK_INIT_PRIVKEY(key);
- restart:
- if (key->sinfo.init != 0) {
- sinfo = &key->sinfo;
- obj = key->obj;
- } else {
- sinfo = &_sinfo;
- memset(sinfo, 0, sizeof(*sinfo));
- FIND_OBJECT(sinfo, &key->pin, obj, key);
- }
-
if (key->pk_algorithm != GNUTLS_PK_RSA)
return gnutls_assert_val(GNUTLS_E_INVALID_REQUEST);
@@ -512,20 +452,18 @@ _gnutls_pkcs11_privkey_decrypt_data(gnutls_pkcs11_privkey_t key,
/* Initialize signing operation; using the private key discovered
* earlier. */
- rv = pkcs11_decrypt_init(sinfo->module, sinfo->pks, &mech, obj);
+ rv = pkcs11_decrypt_init(key->sinfo.module, key->sinfo.pks, &mech, key->ref);
if (rv != CKR_OK) {
gnutls_assert();
- CHECK_SHANDLE(rv, key, sinfo);
ret = pkcs11_rv_to_err(rv);
goto cleanup;
}
/* Work out how long the plaintext must be: */
- rv = pkcs11_decrypt(sinfo->module, sinfo->pks, ciphertext->data,
+ rv = pkcs11_decrypt(key->sinfo.module, key->sinfo.pks, ciphertext->data,
ciphertext->size, NULL, &siglen);
if (rv != CKR_OK) {
gnutls_assert();
- CHECK_SHANDLE(rv, key, sinfo);
ret = pkcs11_rv_to_err(rv);
goto cleanup;
}
@@ -533,12 +471,11 @@ _gnutls_pkcs11_privkey_decrypt_data(gnutls_pkcs11_privkey_t key,
plaintext->data = gnutls_malloc(siglen);
plaintext->size = siglen;
- rv = pkcs11_decrypt(sinfo->module, sinfo->pks, ciphertext->data,
+ rv = pkcs11_decrypt(key->sinfo.module, key->sinfo.pks, ciphertext->data,
ciphertext->size, plaintext->data, &siglen);
if (rv != CKR_OK) {
gnutls_free(plaintext->data);
gnutls_assert();
- CHECK_SHANDLE(rv, key, sinfo);
ret = pkcs11_rv_to_err(rv);
goto cleanup;
}
@@ -548,9 +485,6 @@ _gnutls_pkcs11_privkey_decrypt_data(gnutls_pkcs11_privkey_t key,
ret = 0;
cleanup:
- if (sinfo != &key->sinfo)
- pkcs11_close_session(sinfo);
-
return ret;
}
@@ -572,7 +506,7 @@ gnutls_pkcs11_privkey_export_url(gnutls_pkcs11_privkey_t key,
{
int ret;
- ret = pkcs11_info_to_url(key->info, detailed, url);
+ ret = pkcs11_info_to_url(key->uinfo, detailed, url);
if (ret < 0) {
gnutls_assert();
return ret;
@@ -888,22 +822,19 @@ gnutls_pkcs11_privkey_generate2(const char *url, gnutls_pk_algorithm_t pk,
int
_pkcs11_privkey_get_pubkey (gnutls_pkcs11_privkey_t pkey, gnutls_pubkey_t *pub, unsigned flags)
{
- ck_object_handle_t priv_obj;
struct ck_mechanism mech;
gnutls_pubkey_t pubkey = NULL;
gnutls_pkcs11_obj_t obj = NULL;
ck_key_type_t key_type;
int ret;
- PKCS11_CHECK_INIT;
+ PKCS11_CHECK_INIT_PRIVKEY(pkey);
if (!pkey) {
gnutls_assert();
return GNUTLS_E_INVALID_REQUEST;
}
- priv_obj = pkey->obj;
-
ret = gnutls_pubkey_init(&pubkey);
if (ret < 0) {
gnutls_assert();
@@ -919,7 +850,7 @@ _pkcs11_privkey_get_pubkey (gnutls_pkcs11_privkey_t pkey, gnutls_pubkey_t *pub,
obj->pk_algorithm = gnutls_pkcs11_privkey_get_pk_algorithm(pkey, 0);
obj->type = GNUTLS_PKCS11_OBJ_PUBKEY;
mech.mechanism = pk_to_genmech(obj->pk_algorithm, &key_type);
- ret = pkcs11_read_pubkey(pkey->sinfo.module, pkey->sinfo.pks, priv_obj, mech.mechanism, obj->pubkey);
+ ret = pkcs11_read_pubkey(pkey->sinfo.module, pkey->sinfo.pks, pkey->ref, mech.mechanism, obj->pubkey);
if (ret < 0) {
gnutls_assert();
goto cleanup;