]> git.ipfire.org Git - thirdparty/gnutls.git/commitdiff
Added ability to export certificates from PKCS #11 tokens.
authorNikos Mavrogiannopoulos <nmav@gnutls.org>
Mon, 10 May 2010 14:26:24 +0000 (16:26 +0200)
committerNikos Mavrogiannopoulos <nmav@gnutls.org>
Thu, 3 Jun 2010 17:40:27 +0000 (19:40 +0200)
Added ability to list trusted certificates, or only certificates
with a corresponding private key or just all.

lib/gnutls_errors.c
lib/gnutls_str.c
lib/includes/gnutls/gnutls.h.in
lib/includes/gnutls/pkcs11.h
lib/pkcs11.c
src/certtool-common.h
src/certtool-gaa.c
src/certtool-gaa.h
src/certtool.c
src/certtool.gaa
src/pkcs11.c

index 1913420f0f652ed9fa64ebba10cab6d13aa1cf0a..85d4bd6d241133f95c1b7cc4886b6acbef3390fd 100644 (file)
@@ -274,6 +274,17 @@ static const gnutls_error_entry error_algorithms[] = {
   ERROR_ENTRY (N_("Error interfacing with /dev/crypto"),
               GNUTLS_E_CRYPTODEV_IOCTL_ERROR, 1),
 
+  ERROR_ENTRY (N_("PKCS #11 error."),
+              GNUTLS_E_PKCS11_ERROR, 1),
+  ERROR_ENTRY (N_("PKCS #11 initialization error."),
+              GNUTLS_E_PKCS11_LOAD_ERROR, 1),
+  ERROR_ENTRY (N_("Error in parsing."),
+              GNUTLS_E_PARSING_ERROR, 1),
+  ERROR_ENTRY (N_("PKCS #11 error in PIN."),
+              GNUTLS_E_PKCS11_PIN_ERROR, 1),
+  ERROR_ENTRY (N_("PKCS #11 error"),
+              GNUTLS_E_PKCS11_ERROR, 1),
+
   {NULL, NULL, 0, 0}
 };
 
index 2efe4c643f89dea84c64eeebfae114ae9cb34364..4c8aca36f764e2bf9606c94e5b636d6cc753f092 100644 (file)
@@ -442,34 +442,34 @@ _gnutls_hex2bin (const opaque * hex_data, int hex_size, opaque * bin_data,
   opaque hex2_data[3];
   unsigned long val;
 
-  /* FIXME: we don't handle whitespace.
-   */
-  hex_size /= 2;
+  hex2_data[2] = 0;
 
-  if (*bin_size < (size_t) hex_size)
+  for (i = j = 0; i < hex_size;)
     {
-      gnutls_assert ();
-      return GNUTLS_E_SHORT_MEMORY_BUFFER;
-    }
+        if (!isxdigit(hex_data[i])) /* skip non-hex such as the ':' in 00:FF */
+          {
+            i++;
+            continue;
+          }
+
+        if (j > *bin_size) {
+            gnutls_assert();
+            return GNUTLS_E_SHORT_MEMORY_BUFFER;
+        }
 
-  for (i = j = 0; j < hex_size; j++)
-    {
-    
-      if (!isxdigit(hex_data[i])) /* skip non-hex such as the ':' in 00:FF */
-        continue;
-
-      hex2_data[0] = hex_data[i];
-      hex2_data[1] = hex_data[i + 1];
-      hex2_data[2] = 0;
-      i+=2;
-      val = strtoul ((char *) hex2_data, NULL, 16);
-      if (val == ULONG_MAX)
-       {
-         gnutls_assert ();
-         return GNUTLS_E_SRP_PWD_PARSING_ERROR;
-       }
-      bin_data[j] = val;
+        hex2_data[0] = hex_data[i];
+        hex2_data[1] = hex_data[i + 1];
+        i+=2;
+
+        val = strtoul ((char *) hex2_data, NULL, 16);
+        if (val == ULONG_MAX) {
+            gnutls_assert ();
+            return GNUTLS_E_PARSING_ERROR;
+        }
+        bin_data[j] = val;
+        j++;
     }
+  *bin_size = j;
 
   return 0;
 }
index 91aa0a4248d7b48f434e07ac15225b27fbbc5edc..9a129e3ccf0c82895024a044c6c51d8f9dbbcc72 100644 (file)
@@ -1728,8 +1728,16 @@ extern "C"
 #define GNUTLS_E_CRYPTODEV_IOCTL_ERROR -211
 #define GNUTLS_E_CRYPTODEV_DEVICE_ERROR -212
 
+/* PKCS11 related */
+#define GNUTLS_E_PKCS11_ERROR -300
+#define GNUTLS_E_PKCS11_LOAD_ERROR -301
+#define GNUTLS_E_PARSING_ERROR -302
+#define GNUTLS_E_PKCS11_PIN_ERROR -303
+
 #define GNUTLS_E_UNIMPLEMENTED_FEATURE -1250
 
+
+
 #define GNUTLS_E_APPLICATION_ERROR_MAX -65000
 #define GNUTLS_E_APPLICATION_ERROR_MIN -65500
 
index 092333a14c051ed816a3b6fe7d4bb546f1697481..924879f50dcfb5de8aad2c38055b0c6cc0d64b1c 100644 (file)
 #include <gnutls/gnutls.h>
 #include <gnutls/x509.h>
 
-/**
- * @brief PKCS#11 error
- */
-#define GNUTLS_E_PKCS11_ERROR (GNUTLS_E_APPLICATION_ERROR_MIN+529)
-#define GNUTLS_E_PKCS11_LOAD_ERROR 1821
-#define GNUTLS_E_PARSING_ERROR 1822
-#define GNUTLS_E_PKCS11_PIN_ERROR 1823
 
 #define GNUTLS_PKCS11_MAX_PIN_LEN 32
 
@@ -121,7 +114,7 @@ void gnutls_pkcs11_deinit (void);
  * @param data         Data to use when calling callback.
  * @return gnutls status.
  */
-void gnutls_pkcs11_set_pin_function (const gnutls_pkcs11_pin_callback_t callback, void * const data);
+void gnutls_pkcs11_set_pin_function (gnutls_pkcs11_pin_callback_t callback, void * const data);
 
 /**
  * @brief Add PKCS#11 provider.
index c49e628fd911452ba4a469bf2f3a0b7ab271693a..2112b3fd1fc337aa9b38fd2695a20e99f8f43c95 100644 (file)
@@ -29,8 +29,8 @@
 
 #define MAX_PROVIDERS 16
 #define ID_SIZE 128
+#define LABEL_SIZE 128
 
-typedef int (*find_func_t)(pakchois_session_t *pks, struct ck_token_info* tinfo, void* input);
 
 struct gnutls_pkcs11_provider_s {
     pakchois_module_t *module;
@@ -38,15 +38,17 @@ struct gnutls_pkcs11_provider_s {
     ck_slot_id_t *slots;
 };
 
+
 struct pkcs11_url_info
 {
     /* everything here is null terminated strings */
-    opaque id[ID_SIZE];
+    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 {
@@ -57,7 +59,7 @@ struct gnutls_pkcs11_crt_st {
 
 struct url_find_data_st {
     gnutls_pkcs11_crt_t crt;
-    char certid_raw[ID_SIZE/2];
+    char certid_raw[ID_SIZE];
     size_t certid_raw_size;
 };
 
@@ -69,6 +71,15 @@ 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;
+};
+
+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;
 
@@ -109,7 +120,7 @@ int gnutls_pkcs11_add_provider (const char * name, const char * params)
         goto fail;
     }
     
-    _gnutls_debug_log("p11: loaded provider '%s' with %d slots\n", name, providers[active_providers-1].nslots);
+    _gnutls_debug_log("p11: loaded provider '%s' with %d slots\n", name, (int)providers[active_providers-1].nslots);
 
     return 0;
 
@@ -228,8 +239,7 @@ static int unescape_string (char* output, const char* input, size_t* size, char
 static int pkcs11_url_to_info(const char* url, struct pkcs11_url_info* info)
 {
 int ret;
-char* p1;
-char* hexid = NULL;
+char* p1, *p2;
 size_t l;
 
     memset( info, 0, sizeof(*info));
@@ -259,6 +269,16 @@ size_t l;
         }
     }
 
+    if ((p1=strstr(url, "object="))!= NULL) {
+        p1+=sizeof("object=")-1;
+        l=sizeof (info->label);
+
+        ret = unescape_string(info->label, p1, &l, ';');
+        if (ret < 0) {
+                goto cleanup;
+        }
+    }
+
     if ((p1=strstr(url, "serial="))!= NULL) {
         p1+=sizeof("serial=")-1;
         l=sizeof (info->serial);
@@ -283,30 +303,25 @@ size_t l;
 
     if (((p1=strstr(url, ";id="))!= NULL) || ((p1=strstr(url, ":id="))!= NULL)) {
         p1+=sizeof(";id=")-1;
-        hexid = gnutls_strdup(p1);
-        if (hexid == NULL) {
-                goto cleanup;
-        }
 
-        if ((p1=strchr(hexid, ';'))!= NULL) {
-                *p1 = 0;
+        if ((p2=strchr(p1, ';'))== NULL) {
+            l = strlen(p1);
         } else {
-                ret = GNUTLS_E_PARSING_ERROR;
-                goto cleanup;
+            l = p2 - p1;
         }
-        
-        l = sizeof(info->id);
-        ret = _gnutls_hex2bin(hexid, strlen(hexid), info->id, &l);
-        if (ret < 0) {
+
+        if (l > sizeof(info->id)-1) {
             gnutls_assert();
-            return ret;
+            ret = GNUTLS_E_PARSING_ERROR;
         }
+
+        memcpy(info->id, p1, l);
+        info->id[l] = 0;
     }
     
     ret = 0;
    
 cleanup:
-    gnutls_free(hexid);
     
     return ret;
 
@@ -371,6 +386,15 @@ static int pkcs11_info_to_url(const struct pkcs11_url_info* info, char** url)
         init = 1;
     }
 
+    if (info->serial[0]) {
+        ret = append(&str, info->serial, "serial", init);
+        if (ret < 0) {
+                gnutls_assert();
+                goto cleanup;
+        }
+        init = 1;
+    }
+
     if (info->model[0]) {
         ret = append(&str, info->model, "model", init);
         if (ret < 0) {
@@ -380,6 +404,7 @@ static int pkcs11_info_to_url(const struct pkcs11_url_info* info, char** url)
         init = 1;
     }
 
+
     if (info->manufacturer[0]) {
         ret = append(&str, info->manufacturer, "manufacturer", init);
         if (ret < 0) {
@@ -389,15 +414,15 @@ static int pkcs11_info_to_url(const struct pkcs11_url_info* info, char** url)
         init = 1;
     }
 
-    if (info->serial[0]) {
-        ret = append(&str, info->serial, "serial", init);
+    if (info->label[0]) {
+        ret = append(&str, info->label, "object", init);
         if (ret < 0) {
                 gnutls_assert();
                 goto cleanup;
         }
         init = 1;
     }
-    
+
     ret = _gnutls_string_append_printf(&str, ";id=%s", info->id);
     if (ret < 0) {
         gnutls_assert();
@@ -443,86 +468,6 @@ static void terminate_string(unsigned char *str, size_t len)
         ptr[1] = '\0';
 }
 
-static int pk11_login(struct gnutls_pkcs11_provider_s *prov, ck_slot_id_t slot_id,
-                      pakchois_session_t *pks, struct ck_slot_info *sinfo, struct ck_token_info* tinfo)
-{
-    int attempt = 0;
-    ck_rv_t rv;
-
-    if (pakchois_get_token_info(prov->module, slot_id, tinfo) != CKR_OK) {
-        gnutls_assert();
-        _gnutls_debug_log("pk11: GetTokenInfo failed\n");
-        return GNUTLS_E_PKCS11_ERROR;
-    }
-
-    if ((tinfo->flags & CKF_LOGIN_REQUIRED) == 0) {
-        _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 (pakchois_login(pks, CKU_USER, NULL, 0) == CKR_OK) {
-            return 0;
-        }
-        else {
-            gnutls_assert();
-            _gnutls_debug_log("pk11: Protected login failed.\n");
-            return GNUTLS_E_PKCS11_ERROR;
-        }
-    }
-
-    /* Otherwise, PIN entry is necessary for login, so fail if there's
-     * no callback. */
-    if (!pin_func) {
-        gnutls_assert();
-        _gnutls_debug_log("pk11: No pin callback but login required.\n");
-        return GNUTLS_E_PKCS11_PIN_ERROR;
-    }
-
-    terminate_string(sinfo->slot_description, sizeof sinfo->slot_description);
-
-    do {
-        char pin[GNUTLS_PKCS11_MAX_PIN_LEN];
-        unsigned int flags = 0;
-
-        /* If login has been attempted once already, check the token
-         * status again, the flags might change. */
-        if (attempt) {
-            if (pakchois_get_token_info(prov->module, slot_id, 
-                                        tinfo) != CKR_OK) {
-                _gnutls_debug_log("pk11: GetTokenInfo failed\n");
-                gnutls_assert();
-                return GNUTLS_E_PKCS11_ERROR;
-            }
-        }
-
-        if (tinfo->flags & CKF_USER_PIN_COUNT_LOW)
-            flags |= GNUTLS_PKCS11_PIN_COUNT_LOW;
-        if (tinfo->flags & CKF_USER_PIN_FINAL_TRY)
-            flags |= GNUTLS_PKCS11_PIN_FINAL_TRY;
-        
-        terminate_string(tinfo->label, sizeof tinfo->label);
-
-        if (pin_func(pin_data, attempt++,
-                         (char *)sinfo->slot_description,
-                         (char *)tinfo->label, flags, pin, sizeof(pin))) {
-            return GNUTLS_E_PKCS11_PIN_ERROR;
-        }
-
-        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);
-    } while (rv == CKR_PIN_INCORRECT);
-
-    _gnutls_debug_log("pk11: Login result = %lu\n", rv);
-
-    return (rv == CKR_OK || rv == CKR_USER_ALREADY_LOGGED_IN) ? 0 : GNUTLS_E_PKCS11_ERROR;
-}
 
 static int traverse_tokens (find_func_t find_func, void* input)
 {
@@ -533,24 +478,31 @@ static int traverse_tokens (find_func_t find_func, void* input)
 
     for (x=0;x<active_providers;x++) {
         for (z=0;z<providers[x].nslots;z++) {
-            struct ck_token_info tinfo;
+            struct token_info info;
+
             rv = pakchois_open_session(providers[x].module, providers[x].slots[z], 
                 CKF_SERIAL_SESSION, NULL, NULL, &pks);
             if (rv != CKR_OK) {
                 continue;
             }
 
-            if (pakchois_get_token_info(providers[x].module, providers[x].slots[z], &tinfo) != CKR_OK) {
+            if (pakchois_get_token_info(providers[x].module, providers[x].slots[z], &info.tinfo) != CKR_OK) {
+                continue;
+            }
+            info.sid = providers[x].slots[z];
+            info.prov = &providers[x];
+
+            if (pakchois_get_slot_info(providers[x].module, providers[x].slots[z], &info.sinfo) != CKR_OK) {
                 continue;
             }
 
             /* XXX make wrapper for token_info? */
-            terminate_string(tinfo.manufacturer_id, sizeof tinfo.manufacturer_id);
-            terminate_string(tinfo.label, sizeof tinfo.label);
-            terminate_string(tinfo.model, sizeof tinfo.model);
-            terminate_string(tinfo.serial_number, sizeof tinfo.serial_number);
+            terminate_string(info.tinfo.manufacturer_id, sizeof info.tinfo.manufacturer_id);
+            terminate_string(info.tinfo.label, sizeof info.tinfo.label);
+            terminate_string(info.tinfo.model, sizeof info.tinfo.model);
+            terminate_string(info.tinfo.serial_number, sizeof info.tinfo.serial_number);
 
-            ret = find_func(pks, &tinfo, input);
+            ret = find_func(pks, &info, input);
             
             pakchois_close_session(pks);
             pks = NULL;
@@ -579,7 +531,7 @@ cleanup:
 /* imports a raw certificate from a token to a pkcs11_crt_t structure.
  */
 static int pkcs11_crt_import(gnutls_pkcs11_crt_t crt, const gnutls_datum_t* data, 
-   const gnutls_datum_t * id, struct ck_token_info* tinfo)
+   const gnutls_datum_t * id, const gnutls_datum_t * label, struct ck_token_info* tinfo)
 {
     char *s;
     int ret;
@@ -601,6 +553,10 @@ static int pkcs11_crt_import(gnutls_pkcs11_crt_t crt, const gnutls_datum_t* data
     snprintf(crt->info.token, sizeof(crt->info.token), "%s", tinfo->label);
     snprintf(crt->info.model, sizeof(crt->info.model), "%s", tinfo->model);
     snprintf(crt->info.serial, sizeof(crt->info.serial), "%s", tinfo->serial_number);
+
+    memcpy(crt->info.label, label->data, label->size);
+    crt->info.label[label->size] = 0;
+
     strcpy(crt->info.type, "cert");
     
     s = _gnutls_bin2hex(id->data, id->size, crt->info.id, sizeof(crt->info.id), ":");
@@ -613,10 +569,10 @@ static int pkcs11_crt_import(gnutls_pkcs11_crt_t crt, const gnutls_datum_t* data
 }
 
 
-static int find_url(pakchois_session_t *pks, struct ck_token_info *tinfo, void* input)
+static int find_cert_url(pakchois_session_t *pks, struct token_info *info, void* input)
 {
     struct url_find_data_st* find_data = input;
-    struct ck_attribute a[3];
+    struct ck_attribute a[4];
     ck_object_class_t class;
     ck_certificate_type_t type;
     ck_rv_t rv;
@@ -624,9 +580,10 @@ static int find_url(pakchois_session_t *pks, struct ck_token_info *tinfo, void*
     unsigned long count;
     int found = 0, ret;
     unsigned char value[8192], subject[8192];
-    char certid_tmp[ID_SIZE/2];
+    char certid_tmp[ID_SIZE];
+    char label_tmp[LABEL_SIZE];
     
-    if (tinfo == NULL) { /* we don't support multiple calls */
+    if (info == NULL) { /* we don't support multiple calls */
         gnutls_assert();
         return GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE;
     }
@@ -634,22 +591,22 @@ static int find_url(pakchois_session_t *pks, struct ck_token_info *tinfo, void*
     /* do not bother reading the token if basic fields do not match
      */
     if (find_data->crt->info.manufacturer[0] != 0) {
-        if (strcmp(find_data->crt->info.manufacturer, tinfo->manufacturer_id) != 0)
+        if (strcmp(find_data->crt->info.manufacturer, info->tinfo.manufacturer_id) != 0)
             return GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE;
     }
 
     if (find_data->crt->info.token[0] != 0) {
-        if (strcmp(find_data->crt->info.token, tinfo->label) != 0)
+        if (strcmp(find_data->crt->info.token, info->tinfo.label) != 0)
             return GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE;
     }
 
     if (find_data->crt->info.model[0] != 0) {
-        if (strcmp(find_data->crt->info.model, tinfo->model) != 0)
+        if (strcmp(find_data->crt->info.model, info->tinfo.model) != 0)
             return GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE;
     }
 
     if (find_data->crt->info.serial[0] != 0) {
-        if (strcmp(find_data->crt->info.serial, tinfo->serial_number) != 0)
+        if (strcmp(find_data->crt->info.serial, info->tinfo.serial_number) != 0)
             return GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE;
     }
 
@@ -691,18 +648,25 @@ static int find_url(pakchois_session_t *pks, struct ck_token_info *tinfo, void*
         a[1].type = CKA_ID;
         a[1].value = certid_tmp;
         a[1].value_len = sizeof(certid_tmp);
-        a[2].type = CKA_SUBJECT;
-        a[2].value = subject;
-        a[2].value_len = sizeof subject;
+        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) {
+char buf[512];
+char buf2[512];
+fprintf(stderr, "val: %d, certid: %d\n", a[1].value_len, find_data->certid_raw_size);
+fprintf(stderr, "fcertid: %s, gcertid: %s\n",    _gnutls_bin2hex (a[1].value, a[1].value_len, buf,
+                                     sizeof (buf), NULL), _gnutls_bin2hex (a[1].value, a[1].value_len, buf2,
+                                     sizeof (buf2), NULL));
 
             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, tinfo);
+                ret = pkcs11_crt_import(find_data->crt, &data, &id, &label, &info->tinfo);
                 if (ret < 0) {
                     gnutls_assert();
                     goto cleanup;
@@ -734,7 +698,6 @@ int gnutls_pkcs11_crt_import_url (gnutls_pkcs11_crt_t cert, const char * url)
 {
     int ret;
     struct url_find_data_st find_data;
-    size_t size;
     
     /* fill in the find data structure */
     find_data.crt = cert;
@@ -747,14 +710,13 @@ int gnutls_pkcs11_crt_import_url (gnutls_pkcs11_crt_t cert, const char * url)
 
     find_data.certid_raw_size = sizeof(find_data.certid_raw);
     
-    size = find_data.certid_raw_size;
-    ret = _gnutls_hex2bin(cert->info.id, sizeof cert->info.id, find_data.certid_raw, &size);
+    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_url, &find_data);
+fprintf(stderr, "hex2bin: %d, %d\n", ret, find_data.certid_raw_size);
+    ret = traverse_tokens(find_cert_url, &find_data);
     if (ret < 0) {
         gnutls_assert();
         return ret;
@@ -781,12 +743,192 @@ gnutls_certificate_type_t gnutls_pkcs11_crt_get_type (gnutls_pkcs11_crt_t certif
     return certificate->type;
 }
 
+struct pkey_list {
+    gnutls_string *key_ids;
+    size_t key_ids_size;
+};
+
+static int pk11_login(pakchois_session_t *pks, struct token_info *info)
+{
+    struct ck_token_info tinfo;
+    int attempt = 0;
+    ck_rv_t rv;
+
+    if (pakchois_get_token_info(info->prov->module, info->sid, &info->tinfo) != CKR_OK) {
+        gnutls_assert();
+        _gnutls_debug_log( "pk11: GetTokenInfo failed\n");
+        return GNUTLS_E_PKCS11_ERROR;
+    }
+
+    /* 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) {
+        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 (pakchois_login(pks, CKU_USER, NULL, 0) == CKR_OK) {
+            return 0;
+        }
+        else {
+            gnutls_assert();
+            _gnutls_debug_log( "pk11: Protected login failed.\n");
+            return GNUTLS_E_PKCS11_ERROR;
+        }
+    }
+
+    /* Otherwise, PIN entry is necessary for login, so fail if there's
+     * no callback. */
+    if (!pin_func) {
+        gnutls_assert();
+        _gnutls_debug_log("pk11: No pin callback but login required.\n");
+        return GNUTLS_E_PKCS11_ERROR;
+    }
+
+    terminate_string(info->sinfo.slot_description, sizeof info->sinfo.slot_description);
+
+    do {
+        char pin[GNUTLS_PKCS11_MAX_PIN_LEN];
+        unsigned int flags = 0;
+
+        /* If login has been attempted once already, check the token
+         * status again, the flags might change. */
+        if (attempt) {
+            if (pakchois_get_token_info(info->prov->module, info->sid,
+                                        &info->tinfo) != CKR_OK) {
+                gnutls_assert();
+                _gnutls_debug_log( "pk11: GetTokenInfo failed\n");
+                return GNUTLS_E_PKCS11_ERROR;
+            }
+        }
+
+        if (info->tinfo.flags & CKF_USER_PIN_COUNT_LOW)
+            flags |= GNUTLS_PKCS11_PIN_COUNT_LOW;
+        if (info->tinfo.flags & CKF_USER_PIN_FINAL_TRY)
+            flags |= GNUTLS_PKCS11_PIN_FINAL_TRY;
+
+        terminate_string(info->tinfo.label, sizeof info->tinfo.label);
+
+        if (pin_func(pin_data, attempt++,
+                         (char *)info->sinfo.slot_description,
+                         (char *)info->tinfo.label, flags, pin, sizeof(pin))) {
+            gnutls_assert();
+            return GNUTLS_E_PKCS11_PIN_ERROR;
+        }
+
+        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);
+    } while (rv == CKR_PIN_INCORRECT);
+
+    _gnutls_debug_log("pk11: Login result = %lu\n", rv);
+
+    return (rv == CKR_OK || rv == CKR_USER_ALREADY_LOGGED_IN) ? 0 : GNUTLS_E_PKCS11_ERROR;
+}
+
+
+static int find_privkeys(pakchois_session_t *pks, struct token_info* info, struct pkey_list *list)
+{
+    struct ck_attribute a[3];
+    ck_object_class_t class;
+    ck_rv_t rv;
+    ck_object_handle_t obj;
+    unsigned long count, current;
+    char certid_tmp[ID_SIZE];
+    int ret;
+
+    class = CKO_PRIVATE_KEY;
+
+    ret = pk11_login(pks, info);
+    if (ret < 0) {
+        gnutls_assert();
+        return ret;
+    }
+
+    /* Find an object with private key class and a certificate ID
+     * which matches the certificate. */
+    /* FIXME: also match the cert subject. */
+    a[0].type = CKA_CLASS;
+    a[0].value = &class;
+    a[0].value_len = sizeof class;
+
+    rv = pakchois_find_objects_init(pks, a, 1);
+    if (rv != CKR_OK) {
+        gnutls_assert();
+        return GNUTLS_E_PKCS11_ERROR;
+    }
+
+    list->key_ids_size = 0;
+    while (pakchois_find_objects(pks, &obj, 1, &count) == CKR_OK
+           && count == 1) {
+        list->key_ids_size++;
+    }
+
+    pakchois_find_objects_final(pks);
+
+    if (list->key_ids_size == 0) {
+        gnutls_assert();
+        return GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE;
+    }
+
+    list->key_ids = gnutls_malloc(sizeof(gnutls_string)*list->key_ids_size);
+    if (list->key_ids == NULL) {
+        gnutls_assert();
+        return GNUTLS_E_MEMORY_ERROR;
+    }
+
+    /* actual search */
+    a[0].type = CKA_CLASS;
+    a[0].value = &class;
+    a[0].value_len = sizeof class;
+
+    rv = pakchois_find_objects_init(pks, a, 1);
+    if (rv != CKR_OK) {
+        gnutls_assert();
+        return GNUTLS_E_PKCS11_ERROR;
+    }
+
+    current = 0;
+    while (pakchois_find_objects(pks, &obj, 1, &count) == CKR_OK
+           && count == 1) {
+
+        a[0].type = CKA_ID;
+        a[0].value = certid_tmp;
+        a[0].value_len = sizeof(certid_tmp);
+
+        _gnutls_string_init(&list->key_ids[current], gnutls_malloc, gnutls_realloc, gnutls_free);
+
+        if (pakchois_get_attribute_value(pks, obj, a, 1) == CKR_OK) {
+            _gnutls_string_append_data(&list->key_ids[current], a[0].value, a[0].value_len);
+            current++;
+        }
+
+        if (current > list->key_ids_size)
+            break;
+    }
+
+    pakchois_find_objects_final(pks);
+
+    list->key_ids_size = current-1;
+
+    return 0;
+}
+
 /* Recover certificate list from tokens */
 
-static int find_crts(pakchois_session_t *pks, struct ck_token_info *tinfo, void* input)
+
+static int find_crts(pakchois_session_t *pks, struct token_info *info, void* input)
 {
     struct crt_find_data_st* find_data = input;
-    struct ck_attribute a[3];
+    struct ck_attribute a[4];
     ck_object_class_t class;
     ck_certificate_type_t type;
     bool trusted;
@@ -794,10 +936,12 @@ static int find_crts(pakchois_session_t *pks, struct ck_token_info *tinfo, void*
     ck_object_handle_t obj;
     unsigned long count;
     unsigned char value[8192], subject[8192];
-    char certid_tmp[ID_SIZE/2];
+    char certid_tmp[ID_SIZE];
+    char label_tmp[LABEL_SIZE];
     int ret, i;
+    struct pkey_list plist; /* private key holder */
 
-    if (tinfo == NULL) { /* final call */
+    if (info == NULL) { /* final call */
         if (find_data->current <= *find_data->n_list)
             ret = 0;
         else
@@ -811,22 +955,22 @@ static int find_crts(pakchois_session_t *pks, struct ck_token_info *tinfo, void*
     /* do not bother reading the token if basic fields do not match
      */
     if (find_data->info.manufacturer[0] != 0) {
-        if (strcmp(find_data->info.manufacturer, tinfo->manufacturer_id) != 0)
+        if (strcmp(find_data->info.manufacturer, info->tinfo.manufacturer_id) != 0)
             return GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE;
     }
 
     if (find_data->info.token[0] != 0) {
-        if (strcmp(find_data->info.token, tinfo->label) != 0)
+        if (strcmp(find_data->info.token, info->tinfo.label) != 0)
             return GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE;
     }
 
     if (find_data->info.model[0] != 0) {
-        if (strcmp(find_data->info.model, tinfo->model) != 0)
+        if (strcmp(find_data->info.model, info->tinfo.model) != 0)
             return GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE;
     }
 
     if (find_data->info.serial[0] != 0) {
-        if (strcmp(find_data->info.serial, tinfo->serial_number) != 0)
+        if (strcmp(find_data->info.serial, info->tinfo.serial_number) != 0)
             return GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE;
     }
 
@@ -837,6 +981,20 @@ static int find_crts(pakchois_session_t *pks, struct ck_token_info *tinfo, void*
         }
     }
 
+    memset(&plist, 0, sizeof(plist));
+    if (find_data->flags==GNUTLS_PKCS11_CRT_ATTR_WITH_PK) {
+        ret = find_privkeys(pks, info, &plist);
+        if (ret < 0) {
+            gnutls_assert();
+            return ret;
+        }
+
+        if (plist.key_ids_size == 0) {
+            gnutls_assert();
+            return GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE;
+        }
+    }
+
     /* Find objects with cert class and X.509 cert type. */
     class = CKO_CERTIFICATE;
     type = CKC_X_509;
@@ -874,20 +1032,24 @@ static int find_crts(pakchois_session_t *pks, struct ck_token_info *tinfo, void*
         a[1].type = CKA_ID;
         a[1].value = certid_tmp;
         a[1].value_len = sizeof(certid_tmp);
-        a[2].type = CKA_SUBJECT;
-        a[2].value = subject;
-        a[2].value_len = sizeof subject;
+        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) {
             gnutls_datum_t data = { a[0].value, a[0].value_len };
             gnutls_datum_t id = { a[1].value, a[1].value_len };
-            
+            gnutls_datum_t label = { a[2].value, a[2].value_len };
+
             /* XXX check also ID with find_data->info.id */
 
             if (find_data->flags == GNUTLS_PKCS11_CRT_ATTR_WITH_PK) {
-                gnutls_assert();
-                /* XXX verify that certificate has a corresponding private key */
-                //not yet
+                for (i=0;i<plist.key_ids_size;i++) {
+                    if (plist.key_ids[i].length != a[1].value_len || memcmp(plist.key_ids[i].data, a[1].value, a[1].value_len)!=0) {
+                        /* not found */
+                        continue;
+                    }
+                }
             }
 
             if (find_data->current < *find_data->n_list) {
@@ -897,8 +1059,8 @@ static int find_crts(pakchois_session_t *pks, struct ck_token_info *tinfo, void*
                     gnutls_assert();
                     goto fail;
                 }
-            
-                ret = pkcs11_crt_import(find_data->p_list[find_data->current], &data, &id, tinfo);
+
+                ret = pkcs11_crt_import(find_data->p_list[find_data->current], &data, &id, &label, &info->tinfo);
                 if (ret < 0) {
                     gnutls_assert();
                     goto fail;
@@ -919,6 +1081,12 @@ static int find_crts(pakchois_session_t *pks, struct ck_token_info *tinfo, void*
 
 fail:
     pakchois_find_objects_final(pks);
+    if (plist.key_ids != NULL) {
+        for (i=0;i<plist.key_ids_size;i++) {
+            _gnutls_string_clear(&plist.key_ids[i]);
+        }
+        gnutls_free( plist.key_ids);
+    }
     for (i=0;i<find_data->current;i++) {
         gnutls_pkcs11_crt_deinit(find_data->p_list[i]);
     }
@@ -1020,58 +1188,6 @@ cleanup:
 #if 0
 #define KEYTYPE_IS_DSA(kt) (kt == CKK_DSA)
 
-static int pk11_find_pkey(ne_ssl_pkcs11_provider *prov, 
-                          pakchois_session_t *pks,
-                          unsigned char *certid, unsigned long cid_len)
-{
-    struct ck_attribute a[3];
-    ck_object_class_t class;
-    ck_rv_t rv;
-    ck_object_handle_t obj;
-    unsigned long count;
-    int found = 0;
-
-    class = CKO_PRIVATE_KEY;
-
-    /* Find an object with private key class and a certificate ID
-     * which matches the certificate. */
-    /* FIXME: also match the cert subject. */
-    a[0].type = CKA_CLASS;
-    a[0].value = &class;
-    a[0].value_len = sizeof class;
-    a[1].type = CKA_ID;
-    a[1].value = certid;
-    a[1].value_len = cid_len;
-
-    rv = pakchois_find_objects_init(pks, a, 2);
-    if (rv != CKR_OK) {
-        NE_DEBUG(NE_DBG_SSL, "pk11: FindObjectsInit failed.\n");
-        /* TODO: error propagation */
-        return 0;
-    }
-
-    rv = pakchois_find_objects(pks, &obj, 1, &count);
-    if (rv == CKR_OK && count == 1) {
-        NE_DEBUG(NE_DBG_SSL, "pk11: Found private key.\n");
-
-        a[0].type = CKA_KEY_TYPE;
-        a[0].value = &prov->keytype;
-        a[0].value_len = sizeof prov->keytype;
-
-        if (pakchois_get_attribute_value(pks, obj, a, 1) == CKR_OK
-            && (prov->keytype == CKK_RSA || KEYTYPE_IS_DSA(prov->keytype))) {
-            found = 1;
-            prov->privkey = obj;
-        }
-        else {
-            NE_DEBUG(NE_DBG_SSL, "pk11: Could not determine key type.\n");
-        }
-    }
-
-    pakchois_find_objects_final(pks);
-
-    return found;
-}
 
 static int find_client_cert(ne_ssl_pkcs11_provider *prov,
                             pakchois_session_t *pks)
index 07be84c5fc4b7b2e4a2697bc66002ea3131eb8f6..f0132d402fce780c3dcd75fe3325d681d7fd0dcf 100644 (file)
@@ -1,3 +1,6 @@
+#include <gnutls/x509.h>
+#include <stdio.h>
+
 enum
 {
   ACTION_SELF_SIGNED,
@@ -24,11 +27,18 @@ enum
   ACTION_RING_INFO,
   ACTION_REQUEST,
   ACTION_PKCS11_LIST,
+  ACTION_PKCS11_EXPORT_URL,
 };
 
 #define TYPE_CRT 1
 #define TYPE_CRQ 2
 
 void certtool_version (void);
-void pkcs11_list( const char* url);
+void pkcs11_list( const char* url, int type);
+void pkcs11_export(FILE* outfile, const char *pkcs11_url);
+void print_certificate_info (gnutls_x509_crt_t crt, FILE * out,
+                                   unsigned int);
 
+#define PKCS11_TYPE_ALL 1
+#define PKCS11_TYPE_TRUSTED 2
+#define PKCS11_TYPE_PK 3
index b0bfd3f73c670f04427508075c3ba988f7f9c3f2..19828a1707970f3a3599c44bac036d95e1837203 100644 (file)
@@ -161,9 +161,6 @@ void gaa_help(void)
        __gaa_helpsingle(0, "v1", "", "Generate an X.509 version 1 certificate (no extensions).");
        __gaa_helpsingle(0, "to-p12", "", "Generate a PKCS #12 structure.");
        __gaa_helpsingle(0, "to-p8", "", "Generate a PKCS #8 key structure.");
-       __gaa_helpsingle(0, "pkcs11-provider", "Library ", "Specify the pkcs11 provider library");
-       __gaa_helpsingle(0, "pkcs11-url", "URL ", "Specify a pkcs11 URL");
-       __gaa_helpsingle(0, "pkcs11-list", "", "List objects specified by a PKCS#11 URL");
        __gaa_helpsingle('8', "pkcs8", "", "Use PKCS #8 format for private keys.");
        __gaa_helpsingle(0, "dsa", "", "Use DSA keys.");
        __gaa_helpsingle(0, "hash", "STR ", "Hash algorithm to use for signing (MD5,SHA1,RMD160,SHA256,SHA384,SHA512).");
@@ -178,6 +175,11 @@ void gaa_help(void)
        __gaa_helpsingle(0, "infile", "FILE ", "Input file.");
        __gaa_helpsingle(0, "template", "FILE ", "Template file to use for non interactive operation.");
        __gaa_helpsingle(0, "pkcs-cipher", "CIPHER ", "Cipher to use for pkcs operations (3des,aes-128,aes-192,aes-256,rc2-40).");
+       __gaa_helpsingle(0, "pkcs11-provider", "Library ", "Specify the pkcs11 provider library");
+       __gaa_helpsingle(0, "pkcs11-export-url", "URL ", "Export data specified a pkcs11 URL");
+       __gaa_helpsingle(0, "pkcs11-list", "", "List objects specified by a PKCS#11 URL");
+       __gaa_helpsingle(0, "pkcs11-list-trusted", "", "List objects marked as trusted, specified by a PKCS#11 URL");
+       __gaa_helpsingle(0, "pkcs11-list-all", "", "List all objects specified by a PKCS#11 URL");
        __gaa_helpsingle('d', "debug", "LEVEL ", "specify the debug level. Default is 1.");
        __gaa_helpsingle('h', "help", "", "shows this help text");
        __gaa_helpsingle('v', "version", "", "shows the program's version");
@@ -195,36 +197,38 @@ typedef struct _gaainfo gaainfo;
 
 struct _gaainfo
 {
-#line 139 "certtool.gaa"
+#line 142 "certtool.gaa"
        int debug;
-#line 135 "certtool.gaa"
+#line 137 "certtool.gaa"
+       int pkcs11_type;
+#line 134 "certtool.gaa"
+       char* pkcs11_url;
+#line 131 "certtool.gaa"
+       char* pkcs11_provider;
+#line 128 "certtool.gaa"
        char *pkcs_cipher;
-#line 132 "certtool.gaa"
+#line 125 "certtool.gaa"
        char *template;
-#line 129 "certtool.gaa"
+#line 122 "certtool.gaa"
        char *infile;
-#line 126 "certtool.gaa"
+#line 119 "certtool.gaa"
        char *outfile;
-#line 123 "certtool.gaa"
+#line 116 "certtool.gaa"
        int quick_random;
-#line 120 "certtool.gaa"
+#line 113 "certtool.gaa"
        int bits;
-#line 116 "certtool.gaa"
+#line 109 "certtool.gaa"
        int outcert_format;
-#line 112 "certtool.gaa"
+#line 105 "certtool.gaa"
        int incert_format;
-#line 109 "certtool.gaa"
+#line 102 "certtool.gaa"
        int export;
-#line 106 "certtool.gaa"
+#line 99 "certtool.gaa"
        char *hash;
-#line 103 "certtool.gaa"
+#line 96 "certtool.gaa"
        int dsa;
-#line 100 "certtool.gaa"
+#line 93 "certtool.gaa"
        int pkcs8;
-#line 95 "certtool.gaa"
-       char* pkcs11_url;
-#line 92 "certtool.gaa"
-       char* pkcs11_provider;
 #line 85 "certtool.gaa"
        int v1_cert;
 #line 82 "certtool.gaa"
@@ -301,59 +305,61 @@ static int gaa_error = 0;
 #define GAA_MULTIPLE_OPTION     3
 
 #define GAA_REST                0
-#define GAA_NB_OPTION           52
+#define GAA_NB_OPTION           54
 #define GAAOPTID_version       1
 #define GAAOPTID_help  2
 #define GAAOPTID_debug 3
-#define GAAOPTID_pkcs_cipher   4
-#define GAAOPTID_template      5
-#define GAAOPTID_infile        6
-#define GAAOPTID_outfile       7
-#define GAAOPTID_disable_quick_random  8
-#define GAAOPTID_bits  9
-#define GAAOPTID_outraw        10
-#define GAAOPTID_outder        11
-#define GAAOPTID_inraw 12
-#define GAAOPTID_inder 13
-#define GAAOPTID_export_ciphers        14
-#define GAAOPTID_hash  15
-#define GAAOPTID_dsa   16
-#define GAAOPTID_pkcs8 17
-#define GAAOPTID_pkcs11_list   18
-#define GAAOPTID_pkcs11_url    19
-#define GAAOPTID_pkcs11_provider       20
-#define GAAOPTID_to_p8 21
-#define GAAOPTID_to_p12        22
-#define GAAOPTID_v1    23
-#define GAAOPTID_fix_key       24
-#define GAAOPTID_pgp_key_info  25
-#define GAAOPTID_key_info      26
-#define GAAOPTID_smime_to_p7   27
-#define GAAOPTID_p7_info       28
-#define GAAOPTID_p12_info      29
-#define GAAOPTID_no_crq_extensions     30
-#define GAAOPTID_crq_info      31
-#define GAAOPTID_crl_info      32
-#define GAAOPTID_pgp_ring_info 33
-#define GAAOPTID_pgp_certificate_info  34
-#define GAAOPTID_certificate_info      35
-#define GAAOPTID_password      36
-#define GAAOPTID_load_ca_certificate   37
-#define GAAOPTID_load_ca_privkey       38
-#define GAAOPTID_load_certificate      39
-#define GAAOPTID_load_request  40
-#define GAAOPTID_load_privkey  41
-#define GAAOPTID_get_dh_params 42
-#define GAAOPTID_generate_dh_params    43
-#define GAAOPTID_verify_crl    44
-#define GAAOPTID_verify_chain  45
-#define GAAOPTID_generate_request      46
-#define GAAOPTID_generate_privkey      47
-#define GAAOPTID_update_certificate    48
-#define GAAOPTID_generate_crl  49
-#define GAAOPTID_generate_proxy        50
-#define GAAOPTID_generate_certificate  51
-#define GAAOPTID_generate_self_signed  52
+#define GAAOPTID_pkcs11_list_all       4
+#define GAAOPTID_pkcs11_list_trusted   5
+#define GAAOPTID_pkcs11_list   6
+#define GAAOPTID_pkcs11_export_url     7
+#define GAAOPTID_pkcs11_provider       8
+#define GAAOPTID_pkcs_cipher   9
+#define GAAOPTID_template      10
+#define GAAOPTID_infile        11
+#define GAAOPTID_outfile       12
+#define GAAOPTID_disable_quick_random  13
+#define GAAOPTID_bits  14
+#define GAAOPTID_outraw        15
+#define GAAOPTID_outder        16
+#define GAAOPTID_inraw 17
+#define GAAOPTID_inder 18
+#define GAAOPTID_export_ciphers        19
+#define GAAOPTID_hash  20
+#define GAAOPTID_dsa   21
+#define GAAOPTID_pkcs8 22
+#define GAAOPTID_to_p8 23
+#define GAAOPTID_to_p12        24
+#define GAAOPTID_v1    25
+#define GAAOPTID_fix_key       26
+#define GAAOPTID_pgp_key_info  27
+#define GAAOPTID_key_info      28
+#define GAAOPTID_smime_to_p7   29
+#define GAAOPTID_p7_info       30
+#define GAAOPTID_p12_info      31
+#define GAAOPTID_no_crq_extensions     32
+#define GAAOPTID_crq_info      33
+#define GAAOPTID_crl_info      34
+#define GAAOPTID_pgp_ring_info 35
+#define GAAOPTID_pgp_certificate_info  36
+#define GAAOPTID_certificate_info      37
+#define GAAOPTID_password      38
+#define GAAOPTID_load_ca_certificate   39
+#define GAAOPTID_load_ca_privkey       40
+#define GAAOPTID_load_certificate      41
+#define GAAOPTID_load_request  42
+#define GAAOPTID_load_privkey  43
+#define GAAOPTID_get_dh_params 44
+#define GAAOPTID_generate_dh_params    45
+#define GAAOPTID_verify_crl    46
+#define GAAOPTID_verify_chain  47
+#define GAAOPTID_generate_request      48
+#define GAAOPTID_generate_privkey      49
+#define GAAOPTID_update_certificate    50
+#define GAAOPTID_generate_crl  51
+#define GAAOPTID_generate_proxy        52
+#define GAAOPTID_generate_certificate  53
+#define GAAOPTID_generate_self_signed  54
 
 #line 168 "gaa.skel"
 
@@ -546,49 +552,49 @@ struct GAAOPTION_debug
        int size1;
 };
 
-struct GAAOPTION_pkcs_cipher 
+struct GAAOPTION_pkcs11_export_url
 {
        char* arg1;
        int size1;
 };
 
-struct GAAOPTION_template 
+struct GAAOPTION_pkcs11_provider
 {
        char* arg1;
        int size1;
 };
 
-struct GAAOPTION_infile 
+struct GAAOPTION_pkcs_cipher
 {
        char* arg1;
        int size1;
 };
 
-struct GAAOPTION_outfile 
+struct GAAOPTION_template
 {
        char* arg1;
        int size1;
 };
 
-struct GAAOPTION_bits 
+struct GAAOPTION_infile
 {
-       int arg1;
+       char* arg1;
        int size1;
 };
 
-struct GAAOPTION_hash 
+struct GAAOPTION_outfile
 {
        char* arg1;
        int size1;
 };
 
-struct GAAOPTION_pkcs11_url 
+struct GAAOPTION_bits
 {
-       char* arg1;
+       int arg1;
        int size1;
 };
 
-struct GAAOPTION_pkcs11_provider 
+struct GAAOPTION_hash
 {
        char* arg1;
        int size1;
@@ -660,14 +666,14 @@ static int gaa_get_option_num(char *str, int status)
         {
         case GAA_LETTER_OPTION:
                        GAA_CHECK1STR("d", GAAOPTID_debug);
+                       GAA_CHECK1STR("", GAAOPTID_pkcs11_export_url);
+                       GAA_CHECK1STR("", GAAOPTID_pkcs11_provider);
                        GAA_CHECK1STR("", GAAOPTID_pkcs_cipher);
                        GAA_CHECK1STR("", GAAOPTID_template);
                        GAA_CHECK1STR("", GAAOPTID_infile);
                        GAA_CHECK1STR("", GAAOPTID_outfile);
                        GAA_CHECK1STR("", GAAOPTID_bits);
                        GAA_CHECK1STR("", GAAOPTID_hash);
-                       GAA_CHECK1STR("", GAAOPTID_pkcs11_url);
-                       GAA_CHECK1STR("", GAAOPTID_pkcs11_provider);
                        GAA_CHECK1STR("", GAAOPTID_password);
                        GAA_CHECK1STR("", GAAOPTID_load_ca_certificate);
                        GAA_CHECK1STR("", GAAOPTID_load_ca_privkey);
@@ -678,6 +684,9 @@ static int gaa_get_option_num(char *str, int status)
 #line 375 "gaa.skel"
                        GAA_CHECK1STR("v", GAAOPTID_version);
                        GAA_CHECK1STR("h", GAAOPTID_help);
+                       GAA_CHECK1STR("", GAAOPTID_pkcs11_list_all);
+                       GAA_CHECK1STR("", GAAOPTID_pkcs11_list_trusted);
+                       GAA_CHECK1STR("", GAAOPTID_pkcs11_list);
                        GAA_CHECK1STR("", GAAOPTID_disable_quick_random);
                        GAA_CHECK1STR("", GAAOPTID_outraw);
                        GAA_CHECK1STR("", GAAOPTID_outder);
@@ -686,7 +695,6 @@ static int gaa_get_option_num(char *str, int status)
                        GAA_CHECK1STR("", GAAOPTID_export_ciphers);
                        GAA_CHECK1STR("", GAAOPTID_dsa);
                        GAA_CHECK1STR("8", GAAOPTID_pkcs8);
-                       GAA_CHECK1STR("", GAAOPTID_pkcs11_list);
                        GAA_CHECK1STR("", GAAOPTID_to_p8);
                        GAA_CHECK1STR("", GAAOPTID_to_p12);
                        GAA_CHECK1STR("", GAAOPTID_v1);
@@ -720,6 +728,11 @@ static int gaa_get_option_num(char *str, int status)
                        GAA_CHECKSTR("version", GAAOPTID_version);
                        GAA_CHECKSTR("help", GAAOPTID_help);
                        GAA_CHECKSTR("debug", GAAOPTID_debug);
+                       GAA_CHECKSTR("pkcs11-list-all", GAAOPTID_pkcs11_list_all);
+                       GAA_CHECKSTR("pkcs11-list-trusted", GAAOPTID_pkcs11_list_trusted);
+                       GAA_CHECKSTR("pkcs11-list", GAAOPTID_pkcs11_list);
+                       GAA_CHECKSTR("pkcs11-export-url", GAAOPTID_pkcs11_export_url);
+                       GAA_CHECKSTR("pkcs11-provider", GAAOPTID_pkcs11_provider);
                        GAA_CHECKSTR("pkcs-cipher", GAAOPTID_pkcs_cipher);
                        GAA_CHECKSTR("template", GAAOPTID_template);
                        GAA_CHECKSTR("infile", GAAOPTID_infile);
@@ -734,9 +747,6 @@ static int gaa_get_option_num(char *str, int status)
                        GAA_CHECKSTR("hash", GAAOPTID_hash);
                        GAA_CHECKSTR("dsa", GAAOPTID_dsa);
                        GAA_CHECKSTR("pkcs8", GAAOPTID_pkcs8);
-                       GAA_CHECKSTR("pkcs11-list", GAAOPTID_pkcs11_list);
-                       GAA_CHECKSTR("pkcs11-url", GAAOPTID_pkcs11_url);
-                       GAA_CHECKSTR("pkcs11-provider", GAAOPTID_pkcs11_provider);
                        GAA_CHECKSTR("to-p8", GAAOPTID_to_p8);
                        GAA_CHECKSTR("to-p12", GAAOPTID_to_p12);
                        GAA_CHECKSTR("v1", GAAOPTID_v1);
@@ -782,14 +792,14 @@ static int gaa_try(int gaa_num, int gaa_index, gaainfo *gaaval, char *opt_list)
     int OK = 0;
     int gaa_last_non_option;
        struct GAAOPTION_debug GAATMP_debug;
+       struct GAAOPTION_pkcs11_export_url GAATMP_pkcs11_export_url;
+       struct GAAOPTION_pkcs11_provider GAATMP_pkcs11_provider;
        struct GAAOPTION_pkcs_cipher GAATMP_pkcs_cipher;
        struct GAAOPTION_template GAATMP_template;
        struct GAAOPTION_infile GAATMP_infile;
        struct GAAOPTION_outfile GAATMP_outfile;
        struct GAAOPTION_bits GAATMP_bits;
        struct GAAOPTION_hash GAATMP_hash;
-       struct GAAOPTION_pkcs11_url GAATMP_pkcs11_url;
-       struct GAAOPTION_pkcs11_provider GAATMP_pkcs11_provider;
        struct GAAOPTION_password GAATMP_password;
        struct GAAOPTION_load_ca_certificate GAATMP_load_ca_certificate;
        struct GAAOPTION_load_ca_privkey GAATMP_load_ca_privkey;
@@ -818,14 +828,14 @@ static int gaa_try(int gaa_num, int gaa_index, gaainfo *gaaval, char *opt_list)
     {
        case GAAOPTID_version:
        OK = 0;
-#line 144 "certtool.gaa"
+#line 147 "certtool.gaa"
 { certtool_version(); exit(0); ;};
 
                return GAA_OK;
                break;
        case GAAOPTID_help:
        OK = 0;
-#line 142 "certtool.gaa"
+#line 145 "certtool.gaa"
 { gaa_help(); exit(0); ;};
 
                return GAA_OK;
@@ -835,9 +845,50 @@ static int gaa_try(int gaa_num, int gaa_index, gaainfo *gaaval, char *opt_list)
                GAA_TESTMOREARGS;
                GAA_FILL(GAATMP_debug.arg1, gaa_getint, GAATMP_debug.size1);
                gaa_index++;
-#line 140 "certtool.gaa"
+#line 143 "certtool.gaa"
 { gaaval->debug = GAATMP_debug.arg1 ;};
 
+               return GAA_OK;
+               break;
+       case GAAOPTID_pkcs11_list_all:
+       OK = 0;
+#line 140 "certtool.gaa"
+{ gaaval->action = ACTION_PKCS11_LIST; gaaval->pkcs11_type=PKCS11_TYPE_ALL; ;};
+
+               return GAA_OK;
+               break;
+       case GAAOPTID_pkcs11_list_trusted:
+       OK = 0;
+#line 139 "certtool.gaa"
+{ gaaval->action = ACTION_PKCS11_LIST; gaaval->pkcs11_type=PKCS11_TYPE_TRUSTED; ;};
+
+               return GAA_OK;
+               break;
+       case GAAOPTID_pkcs11_list:
+       OK = 0;
+#line 138 "certtool.gaa"
+{ gaaval->action = ACTION_PKCS11_LIST; gaaval->pkcs11_type=PKCS11_TYPE_PK; ;};
+
+               return GAA_OK;
+               break;
+       case GAAOPTID_pkcs11_export_url:
+       OK = 0;
+               GAA_TESTMOREARGS;
+               GAA_FILL(GAATMP_pkcs11_export_url.arg1, gaa_getstr, GAATMP_pkcs11_export_url.size1);
+               gaa_index++;
+#line 135 "certtool.gaa"
+{ gaaval->action = ACTION_PKCS11_EXPORT_URL; gaaval->pkcs11_url = GAATMP_pkcs11_export_url.arg1; ;};
+
+               return GAA_OK;
+               break;
+       case GAAOPTID_pkcs11_provider:
+       OK = 0;
+               GAA_TESTMOREARGS;
+               GAA_FILL(GAATMP_pkcs11_provider.arg1, gaa_getstr, GAATMP_pkcs11_provider.size1);
+               gaa_index++;
+#line 132 "certtool.gaa"
+{ gaaval->pkcs11_provider = GAATMP_pkcs11_provider.arg1 ;};
+
                return GAA_OK;
                break;
        case GAAOPTID_pkcs_cipher:
@@ -845,7 +896,7 @@ static int gaa_try(int gaa_num, int gaa_index, gaainfo *gaaval, char *opt_list)
                GAA_TESTMOREARGS;
                GAA_FILL(GAATMP_pkcs_cipher.arg1, gaa_getstr, GAATMP_pkcs_cipher.size1);
                gaa_index++;
-#line 136 "certtool.gaa"
+#line 129 "certtool.gaa"
 { gaaval->pkcs_cipher = GAATMP_pkcs_cipher.arg1 ;};
 
                return GAA_OK;
@@ -855,7 +906,7 @@ static int gaa_try(int gaa_num, int gaa_index, gaainfo *gaaval, char *opt_list)
                GAA_TESTMOREARGS;
                GAA_FILL(GAATMP_template.arg1, gaa_getstr, GAATMP_template.size1);
                gaa_index++;
-#line 133 "certtool.gaa"
+#line 126 "certtool.gaa"
 { gaaval->template = GAATMP_template.arg1 ;};
 
                return GAA_OK;
@@ -865,7 +916,7 @@ static int gaa_try(int gaa_num, int gaa_index, gaainfo *gaaval, char *opt_list)
                GAA_TESTMOREARGS;
                GAA_FILL(GAATMP_infile.arg1, gaa_getstr, GAATMP_infile.size1);
                gaa_index++;
-#line 130 "certtool.gaa"
+#line 123 "certtool.gaa"
 { gaaval->infile = GAATMP_infile.arg1 ;};
 
                return GAA_OK;
@@ -875,14 +926,14 @@ static int gaa_try(int gaa_num, int gaa_index, gaainfo *gaaval, char *opt_list)
                GAA_TESTMOREARGS;
                GAA_FILL(GAATMP_outfile.arg1, gaa_getstr, GAATMP_outfile.size1);
                gaa_index++;
-#line 127 "certtool.gaa"
+#line 120 "certtool.gaa"
 { gaaval->outfile = GAATMP_outfile.arg1 ;};
 
                return GAA_OK;
                break;
        case GAAOPTID_disable_quick_random:
        OK = 0;
-#line 124 "certtool.gaa"
+#line 117 "certtool.gaa"
 { gaaval->quick_random = 0; ;};
 
                return GAA_OK;
@@ -892,42 +943,42 @@ static int gaa_try(int gaa_num, int gaa_index, gaainfo *gaaval, char *opt_list)
                GAA_TESTMOREARGS;
                GAA_FILL(GAATMP_bits.arg1, gaa_getint, GAATMP_bits.size1);
                gaa_index++;
-#line 121 "certtool.gaa"
+#line 114 "certtool.gaa"
 { gaaval->bits = GAATMP_bits.arg1 ;};
 
                return GAA_OK;
                break;
        case GAAOPTID_outraw:
        OK = 0;
-#line 118 "certtool.gaa"
+#line 111 "certtool.gaa"
 { gaaval->outcert_format=1 ;};
 
                return GAA_OK;
                break;
        case GAAOPTID_outder:
        OK = 0;
-#line 117 "certtool.gaa"
+#line 110 "certtool.gaa"
 { gaaval->outcert_format=1 ;};
 
                return GAA_OK;
                break;
        case GAAOPTID_inraw:
        OK = 0;
-#line 114 "certtool.gaa"
+#line 107 "certtool.gaa"
 { gaaval->incert_format=1 ;};
 
                return GAA_OK;
                break;
        case GAAOPTID_inder:
        OK = 0;
-#line 113 "certtool.gaa"
+#line 106 "certtool.gaa"
 { gaaval->incert_format=1 ;};
 
                return GAA_OK;
                break;
        case GAAOPTID_export_ciphers:
        OK = 0;
-#line 110 "certtool.gaa"
+#line 103 "certtool.gaa"
 { gaaval->export=1 ;};
 
                return GAA_OK;
@@ -937,50 +988,23 @@ static int gaa_try(int gaa_num, int gaa_index, gaainfo *gaaval, char *opt_list)
                GAA_TESTMOREARGS;
                GAA_FILL(GAATMP_hash.arg1, gaa_getstr, GAATMP_hash.size1);
                gaa_index++;
-#line 107 "certtool.gaa"
+#line 100 "certtool.gaa"
 { gaaval->hash = GAATMP_hash.arg1 ;};
 
                return GAA_OK;
                break;
        case GAAOPTID_dsa:
        OK = 0;
-#line 104 "certtool.gaa"
+#line 97 "certtool.gaa"
 { gaaval->dsa=1 ;};
 
                return GAA_OK;
                break;
        case GAAOPTID_pkcs8:
        OK = 0;
-#line 101 "certtool.gaa"
+#line 94 "certtool.gaa"
 { gaaval->pkcs8=1 ;};
 
-               return GAA_OK;
-               break;
-       case GAAOPTID_pkcs11_list:
-       OK = 0;
-#line 98 "certtool.gaa"
-{ gaaval->action = ACTION_PKCS11_LIST ;};
-
-               return GAA_OK;
-               break;
-       case GAAOPTID_pkcs11_url:
-       OK = 0;
-               GAA_TESTMOREARGS;
-               GAA_FILL(GAATMP_pkcs11_url.arg1, gaa_getstr, GAATMP_pkcs11_url.size1);
-               gaa_index++;
-#line 96 "certtool.gaa"
-{ gaaval->pkcs11_url = GAATMP_pkcs11_url.arg1 ;};
-
-               return GAA_OK;
-               break;
-       case GAAOPTID_pkcs11_provider:
-       OK = 0;
-               GAA_TESTMOREARGS;
-               GAA_FILL(GAATMP_pkcs11_provider.arg1, gaa_getstr, GAATMP_pkcs11_provider.size1);
-               gaa_index++;
-#line 93 "certtool.gaa"
-{ gaaval->pkcs11_provider = GAATMP_pkcs11_provider.arg1 ;};
-
                return GAA_OK;
                break;
        case GAAOPTID_to_p8:
@@ -1249,13 +1273,13 @@ int gaa(int argc, char **argv, gaainfo *gaaval)
     if(inited == 0)
     {
 
-#line 146 "certtool.gaa"
+#line 149 "certtool.gaa"
 { gaaval->bits = 2048; gaaval->pkcs8 = 0; gaaval->privkey = NULL; gaaval->ca=NULL; gaaval->ca_privkey = NULL; 
        gaaval->debug=1; gaaval->request = NULL; gaaval->infile = NULL; gaaval->outfile = NULL; gaaval->cert = NULL; 
        gaaval->incert_format = 0; gaaval->outcert_format = 0; gaaval->action=-1; gaaval->pass = NULL; gaaval->v1_cert = 0;
        gaaval->export = 0; gaaval->template = NULL; gaaval->hash=NULL; gaaval->fix_key = 0; gaaval->quick_random=1; 
        gaaval->privkey_op = 0; gaaval->pkcs_cipher = "3des"; gaaval->crq_extensions=1; gaaval->pkcs11_provider= NULL;
-       gaaval->pkcs11_url = NULL; ;};
+       gaaval->pkcs11_url = NULL; gaaval->pkcs11_type = PKCS11_TYPE_PK; ;};
 
     }
     inited = 1;
index 28e3cce57c5fdf50816d7dc401b4944cdb7a11dc..8e00cb9a7df2b75b9736da553f1171d1d3467a8b 100644 (file)
@@ -8,36 +8,38 @@ typedef struct _gaainfo gaainfo;
 
 struct _gaainfo
 {
-#line 139 "certtool.gaa"
+#line 142 "certtool.gaa"
        int debug;
-#line 135 "certtool.gaa"
+#line 137 "certtool.gaa"
+       int pkcs11_type;
+#line 134 "certtool.gaa"
+       char* pkcs11_url;
+#line 131 "certtool.gaa"
+       char* pkcs11_provider;
+#line 128 "certtool.gaa"
        char *pkcs_cipher;
-#line 132 "certtool.gaa"
+#line 125 "certtool.gaa"
        char *template;
-#line 129 "certtool.gaa"
+#line 122 "certtool.gaa"
        char *infile;
-#line 126 "certtool.gaa"
+#line 119 "certtool.gaa"
        char *outfile;
-#line 123 "certtool.gaa"
+#line 116 "certtool.gaa"
        int quick_random;
-#line 120 "certtool.gaa"
+#line 113 "certtool.gaa"
        int bits;
-#line 116 "certtool.gaa"
+#line 109 "certtool.gaa"
        int outcert_format;
-#line 112 "certtool.gaa"
+#line 105 "certtool.gaa"
        int incert_format;
-#line 109 "certtool.gaa"
+#line 102 "certtool.gaa"
        int export;
-#line 106 "certtool.gaa"
+#line 99 "certtool.gaa"
        char *hash;
-#line 103 "certtool.gaa"
+#line 96 "certtool.gaa"
        int dsa;
-#line 100 "certtool.gaa"
+#line 93 "certtool.gaa"
        int pkcs8;
-#line 95 "certtool.gaa"
-       char* pkcs11_url;
-#line 92 "certtool.gaa"
-       char* pkcs11_provider;
 #line 85 "certtool.gaa"
        int v1_cert;
 #line 82 "certtool.gaa"
index b65386e027d4927db2a30078e399538128a18501..bf12195aca38b01894ee6a36a4345b29377a599f 100644 (file)
@@ -71,8 +71,6 @@ void certificate_info (void);
 void pgp_certificate_info (void);
 void crl_info (void);
 void privkey_info (void);
-static void print_certificate_info (gnutls_x509_crt_t crt, FILE * out,
-                                   unsigned int);
 static void gaa_parser (int argc, char **argv);
 void generate_self_signed (void);
 void generate_request (void);
@@ -1028,7 +1026,10 @@ gaa_parser (int argc, char **argv)
       generate_pkcs8 ();
       break;
     case ACTION_PKCS11_LIST:
-      pkcs11_list(info.pkcs11_url);
+      pkcs11_list(info.pkcs11_url, info.pkcs11_type);
+      break;
+    case ACTION_PKCS11_EXPORT_URL:
+      pkcs11_export(outfile, info.pkcs11_url);
       break;
 #ifdef ENABLE_OPENPGP
     case ACTION_PGP_INFO:
@@ -1370,7 +1371,7 @@ print_hex_datum (gnutls_datum_t * dat)
 }
 
 
-static void
+void
 print_certificate_info (gnutls_x509_crt_t crt, FILE * out, unsigned int all)
 {
   gnutls_datum_t cinfo;
index 53d3ac169af0efb6a718aaa02729fe2bee02cf6d..fec590e7f1d80e45afc1216637b671ec6d3b68ef 100644 (file)
@@ -89,13 +89,6 @@ option (to-p12) { $action = ACTION_TO_PKCS12; } "Generate a PKCS #12 structure."
 
 option (to-p8) { $action = ACTION_GENERATE_PKCS8; } "Generate a PKCS #8 key structure."
 
-#char* pkcs11_provider;
-option (pkcs11-provider) STR "Library" { $pkcs11_provider = $1 } "Specify the pkcs11 provider library"
-
-#char* pkcs11_url;
-option (pkcs11-url) STR "URL" { $pkcs11_url = $1 } "Specify a pkcs11 URL"
-
-option (pkcs11-list) { $action = ACTION_PKCS11_LIST } "List objects specified by a PKCS#11 URL"
 
 #int pkcs8;
 option (8, pkcs8) { $pkcs8=1 } "Use PKCS #8 format for private keys."
@@ -135,6 +128,16 @@ option (template) STR "FILE" { $template = $1 } "Template file to use for non in
 #char *pkcs_cipher;
 option (pkcs-cipher) STR "CIPHER" { $pkcs_cipher = $1 } "Cipher to use for pkcs operations (3des,aes-128,aes-192,aes-256,rc2-40)."
 
+#char* pkcs11_provider;
+option (pkcs11-provider) STR "Library" { $pkcs11_provider = $1 } "Specify the pkcs11 provider library"
+
+#char* pkcs11_url;
+option (pkcs11-export-url) STR "URL" { $action = ACTION_PKCS11_EXPORT_URL; $pkcs11_url = $1; } "Export data specified a pkcs11 URL"
+
+#int pkcs11_type;
+option (pkcs11-list) { $action = ACTION_PKCS11_LIST; $pkcs11_type=PKCS11_TYPE_PK; } "List objects specified by a PKCS#11 URL"
+option (pkcs11-list-trusted) { $action = ACTION_PKCS11_LIST; $pkcs11_type=PKCS11_TYPE_TRUSTED; } "List objects marked as trusted, specified by a PKCS#11 URL"
+option (pkcs11-list-all) { $action = ACTION_PKCS11_LIST; $pkcs11_type=PKCS11_TYPE_ALL; } "List all objects specified by a PKCS#11 URL"
 
 #int debug;
 option (d, debug) INT "LEVEL" { $debug = $1 } "specify the debug level. Default is 1."
@@ -148,4 +151,4 @@ init { $bits = 2048; $pkcs8 = 0; $privkey = NULL; $ca=NULL; $ca_privkey = NULL;
        $incert_format = 0; $outcert_format = 0; $action=-1; $pass = NULL; $v1_cert = 0;
        $export = 0; $template = NULL; $hash=NULL; $fix_key = 0; $quick_random=1; 
        $privkey_op = 0; $pkcs_cipher = "3des"; $crq_extensions=1; $pkcs11_provider= NULL;
-       $pkcs11_url = NULL; }
+       $pkcs11_url = NULL; $pkcs11_type = PKCS11_TYPE_PK; }
index fc3953d5dcc7682d39c7047906e9ca3e7c6135c4..b27cf0e01db12a042156c6976c6a9d90e52d923d 100644 (file)
@@ -6,20 +6,56 @@
 #include <stdio.h>
 #include <stdlib.h>
 #include "certtool-common.h"
+#include "certtool-cfg.h"
+#include <string.h>
 
-void pkcs11_list( const char* url)
+#define MIN(x,y) ((x)<(y))?(x):(y)
+
+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;
+
+       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 = get_pass();
+       if (password==NULL) {
+               fprintf(stderr, "No password given\n");
+               exit(1);
+       }
+       memcpy(pin, password, MIN(pin_max,strlen(password)));
+
+       return 0;
+}
+
+static void pkcs11_common(void)
+{
+
+       gnutls_pkcs11_set_pin_function (pin_callback, NULL);
+
+}
+
+/* lists certificates from a token
+ */
+void pkcs11_list( const char* url, int type)
 {
 gnutls_pkcs11_crt_t *crt_list;
 unsigned int crt_list_size = 0;
 int ret;
 char* output;
-int i;
+int i, flags;
+
+       pkcs11_common();
 
        if (url == NULL)
                url = "pkcs11:";
 
        ret = gnutls_pkcs11_crt_list_import( NULL, &crt_list_size, url, GNUTLS_PKCS11_CRT_ATTR_ALL);
-       if (ret != 0 && ret != GNUTLS_E_SHORT_MEMORY_BUFFER) {
+       if (ret < 0 && ret != GNUTLS_E_SHORT_MEMORY_BUFFER) {
                fprintf(stderr, "Error in crt_list_import (1): %s\n", gnutls_strerror(ret));
                exit(1);
        }
@@ -35,7 +71,15 @@ int i;
                exit(1);
        }
 
-       ret = gnutls_pkcs11_crt_list_import( crt_list, &crt_list_size, url, GNUTLS_PKCS11_CRT_ATTR_ALL);
+       if (type == PKCS11_TYPE_TRUSTED) {
+               flags = GNUTLS_PKCS11_CRT_ATTR_TRUSTED;
+       } else if (type == PKCS11_TYPE_PK) {
+               flags = GNUTLS_PKCS11_CRT_ATTR_WITH_PK;
+       } else {
+               flags = GNUTLS_PKCS11_CRT_ATTR_ALL;
+       }
+
+       ret = gnutls_pkcs11_crt_list_import( crt_list, &crt_list_size, url, flags);
        if (ret < 0) {
                fprintf(stderr, "Error in crt_list_import: %s\n", gnutls_strerror(ret));
                exit(1);
@@ -48,3 +92,49 @@ int i;
        
        return;
 }
+
+void pkcs11_export(FILE* outfile, const char* url)
+{
+gnutls_pkcs11_crt_t crt;
+gnutls_x509_crt_t xcrt;
+int ret;
+
+       pkcs11_common();
+
+       if (url == NULL)
+               url = "pkcs11:";
+
+       ret = gnutls_pkcs11_crt_init(&crt);
+       if (ret < 0) {
+               fprintf(stderr, "Error in %s:%d: %s\n", __func__, __LINE__, gnutls_strerror(ret));
+               exit(1);
+       }
+
+       ret = gnutls_pkcs11_crt_import_url( crt, url);
+       if (ret < 0) {
+               fprintf(stderr, "Error in %s:%d: %s\n", __func__, __LINE__, gnutls_strerror(ret));
+               exit(1);
+       }
+
+       ret = gnutls_x509_crt_init(&xcrt);
+       if (ret < 0) {
+               fprintf(stderr, "Error in %s:%d: %s\n", __func__, __LINE__, gnutls_strerror(ret));
+               exit(1);
+       }
+
+       ret = gnutls_x509_crt_import_pkcs11(xcrt, crt);
+       if (ret < 0) {
+               fprintf(stderr, "Error in %s:%d: %s\n", __func__, __LINE__, gnutls_strerror(ret));
+               exit(1);
+       }
+
+       print_certificate_info(xcrt, outfile, 1);
+
+       gnutls_x509_crt_deinit(xcrt);
+       gnutls_pkcs11_crt_deinit(crt);
+
+       return;
+
+
+
+}