]> git.ipfire.org Git - thirdparty/gnutls.git/commitdiff
Simplified internal API. The only question that remains now is how to handle
authorNikos Mavrogiannopoulos <nmav@gnutls.org>
Mon, 24 May 2010 17:37:57 +0000 (19:37 +0200)
committerNikos Mavrogiannopoulos <nmav@gnutls.org>
Thu, 3 Jun 2010 17:54:55 +0000 (19:54 +0200)
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.

doc/examples/ex-cert-select-pkcs11.c
lib/gnutls_x509.c
lib/includes/gnutls/pkcs11.h
lib/pkcs11.c
lib/pkcs11_int.h
lib/pkcs11_privkey.c
lib/pkcs11_write.c
src/cli.c

index 2538ed0b23a2182a86662b9667d6fe10ecde0462..e6bac4faae69db1b327ccf98ec1aa73306533f85 100644 (file)
@@ -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",
index 9f772a9d1d11cec3bf2e79e616aed9dca9287765..5d44359b89bfa3895218333707a66d8f66ca5f86 100644 (file)
@@ -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();
index 40bda7077112903268010ba1042b118225fce16c..f29b7bfc2def02972b5303f86c0a06af13751e97 100644 (file)
@@ -209,8 +209,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,
index e35dcc1cecf4a59f506679ba6bac4bd39c2f2ba8..24617a1c984f0e13be9bd042fe1d76971681f621 100644 (file)
@@ -706,6 +706,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;
@@ -765,7 +825,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;
@@ -823,9 +883,7 @@ finish:
     }
 
     if (pks != NULL) {
-        if (leave_session==0 || ret != 0)  {
-            pakchois_close_session(pks);
-        }
+        pakchois_close_session(pks);
     }
    
     return ret;
@@ -1269,7 +1327,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;
@@ -1329,7 +1387,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;
@@ -2071,7 +2129,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;
@@ -2226,7 +2284,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;
index 2eea03cb78512de53230faa27a0a5f6d5590ddd7..63e73e022002a5f89e704d1bbc700368b8a3faab 100644 (file)
@@ -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
index 608b6e97c0fa07e02c2954204e1f694da426f4ab..e039d437bc54e623778979ba01ebfcd6afca6ccb 100644 (file)
 
 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;
        }
index 04f0001eeee1c2491ebf8a0229e42a67e3d4e753..87bcbd0d1258e91267cd13d5ba9bb290e542f9ad 100644 (file)
@@ -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;
index 44008436136d83312a7e40b98117deffb97e5d40..fd9a4e0b829004bd102412debdc51b7ea8b4f0d2 100644 (file)
--- 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
        {