summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorNikos Mavrogiannopoulos <nmav@gnutls.org>2010-05-24 19:37:57 +0200
committerNikos Mavrogiannopoulos <nmav@gnutls.org>2010-05-24 19:37:57 +0200
commit95c21a502abfad1820b91f7dcd56b9ae423ae631 (patch)
tree3a2497632eb6ff1ce984e7c73d191f213ffb89e6
parent2cb2492fa1d7ac90397a429dabf3aac33b094fe8 (diff)
downloadgnutls-95c21a502abfad1820b91f7dcd56b9ae423ae631.tar.gz
Simplified internal API. The only question that remains now is how to handle
the gnutls_pkcs11_privkey_t. Currently it opens a session and maintains a handle to the object. This will require locks to be added on operations. Alternatively new sessions may be opened for each operation performed. This is guarranteed by PKCS #11 to be thread safe but will of course require to ask for the PIN again.
-rw-r--r--doc/examples/ex-cert-select-pkcs11.c2
-rw-r--r--lib/gnutls_x509.c2
-rw-r--r--lib/includes/gnutls/pkcs11.h3
-rw-r--r--lib/pkcs11.c74
-rw-r--r--lib/pkcs11_int.h6
-rw-r--r--lib/pkcs11_privkey.c150
-rw-r--r--lib/pkcs11_write.c2
-rw-r--r--src/cli.c4
8 files changed, 102 insertions, 141 deletions
diff --git a/doc/examples/ex-cert-select-pkcs11.c b/doc/examples/ex-cert-select-pkcs11.c
index 64875a9760..ab15fdfe48 100644
--- a/doc/examples/ex-cert-select-pkcs11.c
+++ b/doc/examples/ex-cert-select-pkcs11.c
@@ -58,7 +58,7 @@ load_keys (void)
gnutls_pkcs11_privkey_init (&key);
- ret = gnutls_pkcs11_privkey_import_url (key, KEY_URL);
+ ret = gnutls_pkcs11_privkey_import_url (key, KEY_URL, 0);
if (ret < 0)
{
fprintf (stderr, "*** Error loading key file: %s\n",
diff --git a/lib/gnutls_x509.c b/lib/gnutls_x509.c
index 9f772a9d1d..5d44359b89 100644
--- a/lib/gnutls_x509.c
+++ b/lib/gnutls_x509.c
@@ -520,7 +520,7 @@ static int read_key_url (gnutls_certificate_credentials_t res, const char* url)
return ret;
}
- ret = gnutls_pkcs11_privkey_import_url(key1, url);
+ ret = gnutls_pkcs11_privkey_import_url(key1, url, 0);
if (ret < 0)
{
gnutls_assert();
diff --git a/lib/includes/gnutls/pkcs11.h b/lib/includes/gnutls/pkcs11.h
index 4e18e9224f..55836f69ae 100644
--- a/lib/includes/gnutls/pkcs11.h
+++ b/lib/includes/gnutls/pkcs11.h
@@ -211,8 +211,9 @@ 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_obj_info_t itype, void* output, size_t* output_size);
+
int gnutls_pkcs11_privkey_import_url (gnutls_pkcs11_privkey_t key,
- const char* url);
+ const char* url, unsigned int flags);
int gnutls_pkcs11_privkey_sign_data(gnutls_pkcs11_privkey_t signer,
gnutls_digest_algorithm_t hash,
diff --git a/lib/pkcs11.c b/lib/pkcs11.c
index 44434614cd..b032320d08 100644
--- a/lib/pkcs11.c
+++ b/lib/pkcs11.c
@@ -703,6 +703,66 @@ static void terminate_string(unsigned char *str, size_t len)
ptr[1] = '\0';
}
+int pkcs11_find_object (pakchois_session_t** _pks, ck_object_handle_t* _obj,
+ struct pkcs11_url_info *info, unsigned int flags)
+{
+int ret;
+pakchois_session_t *pks;
+ck_object_handle_t obj;
+ck_object_class_t class;
+struct ck_attribute a[4];
+int a_vals = 0;
+unsigned long count;
+ck_rv_t rv;
+
+ class = pkcs11_strtype_to_class(info->type);
+ if (class == -1) {
+ gnutls_assert();
+ return GNUTLS_E_INVALID_REQUEST;
+ }
+
+ ret = pkcs11_open_session (&pks, info, flags);
+ if (ret < 0) {
+ gnutls_assert();
+ return ret;
+ }
+
+ a[a_vals].type = CKA_CLASS;
+ a[a_vals].value = &class;
+ a[a_vals].value_len = sizeof class;
+ a_vals++;
+
+ if (info->certid_raw_size > 0) {
+ a[a_vals].type = CKA_ID;
+ a[a_vals].value = info->certid_raw;
+ a[a_vals].value_len = info->certid_raw_size;
+ a_vals++;
+ }
+
+ rv = pakchois_find_objects_init(pks, a, a_vals);
+ if (rv != CKR_OK) {
+ gnutls_assert();
+ _gnutls_debug_log("pk11: FindObjectsInit failed.\n");
+ ret = GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE;
+ goto fail;
+ }
+
+ if (pakchois_find_objects(pks, &obj, 1, &count) == CKR_OK
+ && count == 1) {
+ *_obj = obj;
+ *_pks = pks;
+ pakchois_find_objects_final(pks);
+ return 0;
+
+ }
+
+ pakchois_find_objects_final(pks);
+fail:
+ pakchois_close_session(pks);
+
+ return ret;
+}
+
int pkcs11_open_session (pakchois_session_t** _pks, struct pkcs11_url_info *info, unsigned int flags)
{
ck_rv_t rv;
@@ -762,7 +822,7 @@ next:
int _pkcs11_traverse_tokens (find_func_t find_func, void* input,
- int leave_session, unsigned int flags)
+ unsigned int flags)
{
ck_rv_t rv;
int found = 0, x, z, ret;
@@ -820,9 +880,7 @@ finish:
}
if (pks != NULL) {
- if (leave_session==0 || ret != 0) {
- pakchois_close_session(pks);
- }
+ pakchois_close_session(pks);
}
return ret;
@@ -1245,7 +1303,7 @@ int gnutls_pkcs11_obj_import_url (gnutls_pkcs11_obj_t cert, const char * url)
return ret;
}
- ret = _pkcs11_traverse_tokens(find_obj_url, &find_data, 0, 0);
+ ret = _pkcs11_traverse_tokens(find_obj_url, &find_data, 0);
if (ret < 0) {
gnutls_assert();
return ret;
@@ -1305,7 +1363,7 @@ int gnutls_pkcs11_token_get_url (unsigned int seq, char** url)
memset(&tn, 0, sizeof(tn));
tn.seq = seq;
- ret = _pkcs11_traverse_tokens(find_token_num, &tn, 0, 0);
+ ret = _pkcs11_traverse_tokens(find_token_num, &tn, 0);
if (ret < 0) {
gnutls_assert();
return ret;
@@ -1877,7 +1935,7 @@ int gnutls_pkcs11_obj_list_import_url (gnutls_pkcs11_obj_t * p_list, unsigned in
return ret;
}
- ret = _pkcs11_traverse_tokens(find_objs, &find_data, 0, 0);
+ ret = _pkcs11_traverse_tokens(find_objs, &find_data, 0);
if (ret < 0) {
gnutls_assert();
return ret;
@@ -2032,7 +2090,7 @@ int gnutls_pkcs11_token_get_flags(const char* url, unsigned int *flags)
return ret;
}
- ret = _pkcs11_traverse_tokens(find_flags, &find_data, 0, 0);
+ ret = _pkcs11_traverse_tokens(find_flags, &find_data, 0);
if (ret < 0) {
gnutls_assert();
return ret;
diff --git a/lib/pkcs11_int.h b/lib/pkcs11_int.h
index 81c2ba7ca1..f1e2c9038c 100644
--- a/lib/pkcs11_int.h
+++ b/lib/pkcs11_int.h
@@ -62,9 +62,13 @@ int pkcs11_info_to_url(const struct pkcs11_url_info* info, char** url);
#define SESSION_WRITE 1
#define SESSION_LOGIN 2
int pkcs11_open_session (pakchois_session_t** _pks, struct pkcs11_url_info *info, unsigned int flags);
-int _pkcs11_traverse_tokens (find_func_t find_func, void* input, int leave_session, unsigned int flags);
+int _pkcs11_traverse_tokens (find_func_t find_func, void* input, unsigned int flags);
ck_object_class_t pkcs11_strtype_to_class(const char* type);
int pkcs11_token_matches_info( struct pkcs11_url_info* info, struct ck_token_info* tinfo);
+/* flags are SESSION_* */
+int pkcs11_find_object (pakchois_session_t** _pks, ck_object_handle_t* _obj,
+ struct pkcs11_url_info *info, unsigned int flags);
+
#endif
diff --git a/lib/pkcs11_privkey.c b/lib/pkcs11_privkey.c
index 3fd54f9a55..1c3e0d0407 100644
--- a/lib/pkcs11_privkey.c
+++ b/lib/pkcs11_privkey.c
@@ -33,15 +33,12 @@
struct gnutls_pkcs11_privkey_st {
pakchois_session_t *pks;
- ck_object_handle_t privkey;
+ ck_object_handle_t obj;
gnutls_pk_algorithm_t pk_algorithm;
+ unsigned int flags;
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);
@@ -61,7 +58,7 @@ int gnutls_pkcs11_privkey_init(gnutls_pkcs11_privkey_t * key)
gnutls_assert();
return GNUTLS_E_MEMORY_ERROR;
}
- (*key)->privkey = CK_INVALID_HANDLE;
+ (*key)->obj = CK_INVALID_HANDLE;
return 0;
}
@@ -76,7 +73,7 @@ void gnutls_pkcs11_privkey_deinit(gnutls_pkcs11_privkey_t key)
{
if (key->pks) {
pakchois_close_session(key->pks);
- }
+ }
gnutls_free(key);
}
@@ -118,23 +115,23 @@ int gnutls_pkcs11_privkey_get_info(gnutls_pkcs11_privkey_t pkey,
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_BLOCK_START int retries = 0; retry:
/* the rescan_slots() here is a dummy but if not
* called my card fails to work when removed and inserted.
* May have to do with the pkcs11 library I use.
*/
-#define RETRY_CHECK(rv, label) { \
+#define RETRY_CHECK(rv, key) { \
if (token_func && (rv == CKR_SESSION_HANDLE_INVALID||rv==CKR_DEVICE_REMOVED)) { \
pkcs11_rescan_slots(); \
pakchois_close_session(key->pks); \
pkcs11_rescan_slots(); \
key->pks = NULL; \
- ret = token_func(token_data, label, retries++); \
+ key->obj = CK_INVALID_HANDLE; \
+ ret = token_func(token_data, key->info.label, retries++); \
if (ret == 0) { \
- _pkcs11_traverse_tokens(find_privkey_url, &find_data, 1, 0); \
+ pkcs11_find_object (&key->pks, &key->obj, &key->info, SESSION_LOGIN); \
goto retry; \
} \
} \
@@ -221,9 +218,9 @@ int gnutls_pkcs11_privkey_sign_hash(gnutls_pkcs11_privkey_t key,
struct ck_mechanism mech;
unsigned long siglen;
- RETRY_BLOCK_START(key);
+ RETRY_BLOCK_START;
- if (key->privkey == CK_INVALID_HANDLE || key->pks == NULL) {
+ if (key->obj == CK_INVALID_HANDLE || key->pks == NULL) {
gnutls_assert();
return GNUTLS_E_PKCS11_ERROR;
}
@@ -235,9 +232,9 @@ int gnutls_pkcs11_privkey_sign_hash(gnutls_pkcs11_privkey_t key,
/* Initialize signing operation; using the private key discovered
* earlier. */
- rv = pakchois_sign_init(key->pks, &mech, key->privkey);
+ rv = pakchois_sign_init(key->pks, &mech, key->obj);
if (rv != CKR_OK) {
- RETRY_CHECK(rv, key->info.label);
+ RETRY_CHECK(rv, key);
gnutls_assert();
return GNUTLS_E_PK_SIGN_FAILED;
}
@@ -246,7 +243,7 @@ int gnutls_pkcs11_privkey_sign_hash(gnutls_pkcs11_privkey_t key,
rv = pakchois_sign(key->pks, hash->data, hash->size, NULL,
&siglen);
if (rv != CKR_OK) {
- RETRY_CHECK(rv, key->info.label);
+ RETRY_CHECK(rv, key);
gnutls_assert();
return GNUTLS_E_PK_SIGN_FAILED;
}
@@ -258,7 +255,7 @@ int gnutls_pkcs11_privkey_sign_hash(gnutls_pkcs11_privkey_t key,
signature->data, &siglen);
if (rv != CKR_OK) {
gnutls_free(signature->data);
- RETRY_CHECK(rv, key->info.label);
+ RETRY_CHECK(rv, key);
gnutls_assert();
return GNUTLS_E_PK_SIGN_FAILED;
}
@@ -268,108 +265,12 @@ int gnutls_pkcs11_privkey_sign_hash(gnutls_pkcs11_privkey_t key,
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 (pkcs11_token_matches_info( &find_data->privkey->info, &info->tinfo) < 0) {
- gnutls_assert();
- return GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE;
- }
-
- if (find_data->privkey->info.type[0] != 0) {
- if (strcmp(find_data->privkey->info.type, "private") != 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;
-}
/**
* gnutls_pkcs11_privkey_import_url:
* @pkey: The structure to store the parsed key
* @url: a PKCS 11 url identifying the key
+ * @flags: sequence of GNUTLS_PKCS_PRIVKEY_*
*
* This function will "import" a PKCS 11 URL identifying a private
* key to the #gnutls_pkcs11_privkey_t structure. In reality since
@@ -380,13 +281,9 @@ static int find_privkey_url(pakchois_session_t * pks,
* negative error value.
**/
int gnutls_pkcs11_privkey_import_url(gnutls_pkcs11_privkey_t pkey,
- const char *url)
+ const char *url, unsigned int flags)
{
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) {
@@ -399,11 +296,12 @@ int gnutls_pkcs11_privkey_import_url(gnutls_pkcs11_privkey_t pkey,
return GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE;
}
- ret = _pkcs11_traverse_tokens(find_privkey_url, &find_data, 1, 0);
+ ret = pkcs11_find_object (&pkey->pks, &pkey->obj, &pkey->info, SESSION_LOGIN);
if (ret < 0) {
gnutls_assert();
return ret;
}
+ pkey->flags = flags;
return 0;
}
@@ -431,9 +329,9 @@ gnutls_pkcs11_privkey_decrypt_data(gnutls_pkcs11_privkey_t key,
struct ck_mechanism mech;
unsigned long siglen;
- RETRY_BLOCK_START(key);
+ RETRY_BLOCK_START;
- if (key->privkey == CK_INVALID_HANDLE) {
+ if (key->obj == CK_INVALID_HANDLE) {
gnutls_assert();
return GNUTLS_E_PKCS11_ERROR;
}
@@ -445,9 +343,9 @@ gnutls_pkcs11_privkey_decrypt_data(gnutls_pkcs11_privkey_t key,
/* Initialize signing operation; using the private key discovered
* earlier. */
- rv = pakchois_decrypt_init(key->pks, &mech, key->privkey);
+ rv = pakchois_decrypt_init(key->pks, &mech, key->obj);
if (rv != CKR_OK) {
- RETRY_CHECK(rv, key->info.label);
+ RETRY_CHECK(rv, key);
gnutls_assert();
return GNUTLS_E_PK_DECRYPTION_FAILED;
}
@@ -456,7 +354,7 @@ gnutls_pkcs11_privkey_decrypt_data(gnutls_pkcs11_privkey_t key,
rv = pakchois_decrypt(key->pks, ciphertext->data, ciphertext->size, NULL,
&siglen);
if (rv != CKR_OK) {
- RETRY_CHECK(rv, key->info.label);
+ RETRY_CHECK(rv, key);
gnutls_assert();
return GNUTLS_E_PK_DECRYPTION_FAILED;
}
diff --git a/lib/pkcs11_write.c b/lib/pkcs11_write.c
index d7a8958d70..ce3a7869f8 100644
--- a/lib/pkcs11_write.c
+++ b/lib/pkcs11_write.c
@@ -499,7 +499,7 @@ int gnutls_pkcs11_delete_url(const char* object_url)
return ret;
}
- ret = _pkcs11_traverse_tokens(delete_obj_url, &find_data, 0, SESSION_WRITE);
+ ret = _pkcs11_traverse_tokens(delete_obj_url, &find_data, SESSION_WRITE);
if (ret < 0) {
gnutls_assert();
return ret;
diff --git a/src/cli.c b/src/cli.c
index 4400843613..fd9a4e0b82 100644
--- a/src/cli.c
+++ b/src/cli.c
@@ -237,7 +237,7 @@ load_keys (void)
{
gnutls_pkcs11_privkey_init (&pkcs11_key);
- ret = gnutls_pkcs11_privkey_import_url (pkcs11_key, x509_keyfile);
+ ret = gnutls_pkcs11_privkey_import_url (pkcs11_key, x509_keyfile, 0);
}
else
{
@@ -293,7 +293,7 @@ load_keys (void)
{
gnutls_pkcs11_privkey_init (&pkcs11_key);
- ret = gnutls_pkcs11_privkey_import_url (pkcs11_key, pgp_keyfile);
+ ret = gnutls_pkcs11_privkey_import_url (pkcs11_key, pgp_keyfile, 0);
}
else
{