diff options
author | Nikos Mavrogiannopoulos <nmav@gnutls.org> | 2010-05-24 19:37:57 +0200 |
---|---|---|
committer | Nikos Mavrogiannopoulos <nmav@gnutls.org> | 2010-05-24 19:37:57 +0200 |
commit | 95c21a502abfad1820b91f7dcd56b9ae423ae631 (patch) | |
tree | 3a2497632eb6ff1ce984e7c73d191f213ffb89e6 | |
parent | 2cb2492fa1d7ac90397a429dabf3aac33b094fe8 (diff) | |
download | gnutls-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.c | 2 | ||||
-rw-r--r-- | lib/gnutls_x509.c | 2 | ||||
-rw-r--r-- | lib/includes/gnutls/pkcs11.h | 3 | ||||
-rw-r--r-- | lib/pkcs11.c | 74 | ||||
-rw-r--r-- | lib/pkcs11_int.h | 6 | ||||
-rw-r--r-- | lib/pkcs11_privkey.c | 150 | ||||
-rw-r--r-- | lib/pkcs11_write.c | 2 | ||||
-rw-r--r-- | src/cli.c | 4 |
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; @@ -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 { |