4
* Copyright (C) 2008 Stefan Walter
5
* Copyright (C) 2011 Collabora Ltd.
7
* This program is free software; you can redistribute it and/or modify
8
* it under the terms of the GNU Lesser General Public License as
9
* published by the Free Software Foundation; either version 2.1 of
10
* the License, or (at your option) any later version.
12
* This program is distributed in the hope that it will be useful, but
13
* WITHOUT ANY WARRANTY; without even the implied warranty of
14
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15
* Lesser General Public License for more details.
17
* You should have received a copy of the GNU Lesser General Public
18
* License along with this program; if not, write to the Free Software
19
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
22
* Author: Stef Walter <stefw@collabora.co.uk>
27
#define DEBUG_FLAG GCR_DEBUG_IMPORT
28
#include "gcr-debug.h"
29
#include "gcr-fingerprint.h"
30
#include "gcr-icons.h"
31
#include "gcr-internal.h"
32
#include "gcr-library.h"
33
#include "gcr-import-interaction.h"
34
#include "gcr-internal.h"
35
#include "gcr-parser.h"
36
#include "gcr-pkcs11-importer.h"
38
#include "egg/egg-hex.h"
44
#include <glib/gi18n-lib.h>
57
typedef struct _GcrPkcs11ImporterClass GcrPkcs11ImporterClass;
59
struct _GcrPkcs11Importer {
65
GTlsInteraction *interaction;
69
struct _GcrPkcs11ImporterClass {
70
GObjectClass parent_class;
74
GcrPkcs11Importer *importer;
75
GCancellable *cancellable;
78
GckBuilder *supplement;
81
/* State forward declarations */
82
static void state_cancelled (GSimpleAsyncResult *res,
85
static void state_complete (GSimpleAsyncResult *res,
88
static void state_create_object (GSimpleAsyncResult *res,
91
static void state_supplement (GSimpleAsyncResult *res,
94
static void state_open_session (GSimpleAsyncResult *res,
97
static void _gcr_pkcs11_importer_init_iface (GcrImporterIface *iface);
99
G_DEFINE_TYPE_WITH_CODE (GcrPkcs11Importer, _gcr_pkcs11_importer, G_TYPE_OBJECT,
100
G_IMPLEMENT_INTERFACE (GCR_TYPE_IMPORTER, _gcr_pkcs11_importer_init_iface);
106
gcr_importer_data_free (gpointer data)
108
GcrImporterData *state = data;
110
g_clear_object (&state->cancellable);
111
g_clear_object (&state->importer);
116
next_state (GSimpleAsyncResult *res,
117
void (*state) (GSimpleAsyncResult *, gboolean))
119
GcrImporterData *data = g_simple_async_result_get_op_res_gpointer (res);
123
if (g_cancellable_is_cancelled (data->cancellable))
124
state = state_cancelled;
126
(state) (res, data->async);
129
/* ---------------------------------------------------------------------------------
134
state_complete (GSimpleAsyncResult *res,
137
g_simple_async_result_complete (res);
141
state_cancelled (GSimpleAsyncResult *res,
144
GcrImporterData *data = g_simple_async_result_get_op_res_gpointer (res);
145
GError *error = NULL;
147
if (data->cancellable && !g_cancellable_is_cancelled (data->cancellable))
148
g_cancellable_cancel (data->cancellable);
150
g_cancellable_set_error_if_cancelled (data->cancellable, &error);
151
g_simple_async_result_take_error (res, error);
152
next_state (res, state_complete);
155
/* ---------------------------------------------------------------------------------
160
complete_create_object (GSimpleAsyncResult *res,
164
GcrImporterData *data = g_simple_async_result_get_op_res_gpointer (res);
165
GcrPkcs11Importer *self = data->importer;
167
if (object == NULL) {
168
g_simple_async_result_take_error (res, error);
169
next_state (res, state_complete);
172
self->objects = g_list_append (self->objects, object);
173
next_state (res, state_create_object);
178
on_create_object (GObject *source,
179
GAsyncResult *result,
182
GSimpleAsyncResult *res = G_SIMPLE_ASYNC_RESULT (user_data);
183
GError *error = NULL;
186
object = gck_session_create_object_finish (GCK_SESSION (source), result, &error);
187
complete_create_object (res, object, error);
188
g_object_unref (res);
192
state_create_object (GSimpleAsyncResult *res,
195
GcrImporterData *data = g_simple_async_result_get_op_res_gpointer (res);
196
GcrPkcs11Importer *self = data->importer;
197
GckAttributes *attrs;
199
GError *error = NULL;
201
/* No more objects */
202
if (g_queue_is_empty (self->queue)) {
203
next_state (res, state_complete);
207
/* Pop first one off the list */
208
attrs = g_queue_pop_head (self->queue);
209
g_assert (attrs != NULL);
212
gck_session_create_object_async (self->session, attrs,
213
data->cancellable, on_create_object,
216
object = gck_session_create_object (self->session, attrs,
217
data->cancellable, &error);
218
complete_create_object (res, object, error);
221
gck_attributes_unref (attrs);
225
/* ---------------------------------------------------------------------------------
226
* SUPPLEMENTING and FIXING UP
230
GckAttributes *certificate;
231
GckAttributes *private_key;
232
} CertificateKeyPair;
235
supplement_with_attributes (GckBuilder *builder,
236
GckAttributes *supplements)
238
const GckAttribute *supplement;
241
for (i = 0; i < gck_attributes_count (supplements); i++) {
242
supplement = gck_attributes_at (supplements, i);
243
if (!gck_attribute_is_invalid (supplement) && supplement->length != 0)
244
gck_builder_add_attribute (builder, supplement);
249
supplement_id_for_data (GckBuilder *builder,
258
if (gck_builder_find (builder, CKA_ID) != NULL)
261
gcry = gcry_md_open (&mdh, GCRY_MD_SHA1, 0);
262
g_return_if_fail (gcry == 0);
264
gcry_md_write (mdh, nonce, n_once);
265
gcry_md_write (mdh, data, n_data);
267
gck_builder_add_data (builder, CKA_ID,
268
gcry_md_read (mdh, 0),
269
gcry_md_get_algo_dlen (GCRY_MD_SHA1));
275
supplement_attributes (GcrPkcs11Importer *self,
276
GckAttributes *supplements)
278
GckBuilder builder = GCK_BUILDER_INIT;
281
CertificateKeyPair *pair;
282
gboolean supplemented = FALSE;
283
GckAttributes *attrs;
293
/* A table of certificate/key pairs by fingerprint */
294
pairs = g_hash_table_new_full (g_str_hash, g_str_equal,
297
for (l = self->queue->head; l != NULL; l = g_list_next (l)) {
299
if (!gck_attributes_find_ulong (attrs, CKA_CLASS, &klass))
300
g_return_if_reached ();
302
/* Make a string fingerprint for this guy */
303
finger = gcr_fingerprint_from_attributes (attrs, G_CHECKSUM_SHA1,
306
fingerprint = egg_hex_encode (finger, n_finger);
309
pair = g_hash_table_lookup (pairs, fingerprint);
311
pair = g_new0 (CertificateKeyPair, 1);
312
g_hash_table_insert (pairs, fingerprint, pair);
314
g_free (fingerprint);
321
gck_builder_add_all (&builder, attrs);
322
gck_builder_set_boolean (&builder, CKA_TOKEN, CK_TRUE);
325
case CKO_CERTIFICATE:
326
gck_builder_set_boolean (&builder, CKA_PRIVATE, FALSE);
328
case CKO_PRIVATE_KEY:
329
gck_builder_set_boolean (&builder, CKA_PRIVATE, TRUE);
330
gck_builder_add_boolean (&builder, CKA_DECRYPT, TRUE);
331
gck_builder_add_boolean (&builder, CKA_SIGN, TRUE);
332
gck_builder_add_boolean (&builder, CKA_SIGN_RECOVER, TRUE);
333
gck_builder_add_boolean (&builder, CKA_UNWRAP, TRUE);
334
gck_builder_add_boolean (&builder, CKA_SENSITIVE, TRUE);
338
gck_attributes_unref (attrs);
339
l->data = attrs = gck_attributes_ref_sink (gck_builder_end (&builder));
342
case CKO_CERTIFICATE:
343
if (pair != NULL && pair->certificate == NULL)
344
pair->certificate = attrs;
346
case CKO_PRIVATE_KEY:
347
if (pair != NULL && pair->private_key == NULL)
348
pair->private_key = attrs;
353
/* For generation of CKA_ID's */
354
gcry_create_nonce (nonce, sizeof (nonce));
356
/* A table for marking which attributes are in the pairs table */
357
paired = g_hash_table_new (g_direct_hash, g_direct_equal);
359
/* Now move everything in pairs to the front */
360
queue = g_queue_new ();
361
g_hash_table_iter_init (&iter, pairs);
362
while (g_hash_table_iter_next (&iter, (gpointer *)&fingerprint, (gpointer *)&pair)) {
363
if (pair->certificate != NULL && pair->private_key != NULL) {
365
* Generate a CKA_ID based on the fingerprint and nonce,
366
* and do the same CKA_ID for both private key and certificate.
369
gck_builder_add_all (&builder, pair->private_key);
370
supplement_with_attributes (&builder, supplements);
371
supplement_id_for_data (&builder, nonce, sizeof (nonce),
372
fingerprint, strlen (fingerprint));
373
g_queue_push_tail (queue, gck_attributes_ref_sink (gck_builder_end (&builder)));
374
g_hash_table_insert (paired, pair->private_key, "present");
376
gck_builder_add_all (&builder, pair->certificate);
377
supplement_with_attributes (&builder, supplements);
378
supplement_id_for_data (&builder, nonce, sizeof (nonce),
379
fingerprint, strlen (fingerprint));
380
g_queue_push_tail (queue, gck_attributes_ref_sink (gck_builder_end (&builder)));
381
g_hash_table_insert (paired, pair->certificate, "present");
383
/* Used the suplements for the pairs, don't use for unpaired stuff */
388
/* Go through the old queue, and look for anything not paired */
389
for (l = self->queue->head; l != NULL; l = g_list_next (l)) {
391
if (!g_hash_table_lookup (paired, attrs)) {
392
gck_builder_add_all (&builder, attrs);
394
supplement_with_attributes (&builder, supplements);
397
* Generate a CKA_ID based on the location of attrs in,
398
* memory, since this together with the nonce should
401
supplement_id_for_data (&builder, nonce, sizeof (nonce),
402
&attrs, sizeof (gpointer));
404
g_queue_push_tail (queue, gck_attributes_ref_sink (gck_builder_end (&builder)));
408
/* And swap the new queue into place */
409
g_queue_foreach (self->queue, (GFunc)gck_attributes_unref, NULL);
410
g_queue_free (self->queue);
413
g_hash_table_destroy (paired);
414
g_hash_table_destroy (pairs);
418
complete_supplement (GSimpleAsyncResult *res,
421
GcrImporterData *data = g_simple_async_result_get_op_res_gpointer (res);
422
GckAttributes *attributes;
425
attributes = gck_attributes_ref_sink (gck_builder_end (data->supplement));
426
supplement_attributes (data->importer, attributes);
427
gck_attributes_unref (attributes);
429
next_state (res, state_create_object);
431
g_simple_async_result_take_error (res, error);
432
next_state (res, state_complete);
437
on_supplement_done (GObject *source,
438
GAsyncResult *result,
441
GSimpleAsyncResult *res = G_SIMPLE_ASYNC_RESULT (user_data);
442
GcrImporterData *data = g_simple_async_result_get_op_res_gpointer (res);
443
GcrPkcs11Importer *self = data->importer;
444
GError *error = NULL;
446
gcr_import_interaction_supplement_finish (GCR_IMPORT_INTERACTION (self->interaction),
448
complete_supplement (res, error);
449
g_object_unref (res);
453
state_supplement (GSimpleAsyncResult *res,
456
GcrImporterData *data = g_simple_async_result_get_op_res_gpointer (res);
457
GcrPkcs11Importer *self = data->importer;
458
GError *error = NULL;
460
if (self->interaction == NULL || !GCR_IS_IMPORT_INTERACTION (self->interaction)) {
461
complete_supplement (res, NULL);
464
gcr_import_interaction_supplement_async (GCR_IMPORT_INTERACTION (self->interaction),
465
data->supplement, data->cancellable,
466
on_supplement_done, g_object_ref (res));
469
gcr_import_interaction_supplement (GCR_IMPORT_INTERACTION (self->interaction),
470
data->supplement, data->cancellable, &error);
471
complete_supplement (res, error);
476
supplement_prep (GSimpleAsyncResult *res)
478
GcrImporterData *data = g_simple_async_result_get_op_res_gpointer (res);
479
GcrPkcs11Importer *self = data->importer;
480
const GckAttribute *the_label = NULL;
481
const GckAttribute *attr;
482
gboolean first = TRUE;
485
if (data->supplement)
486
gck_builder_unref (data->supplement);
487
data->supplement = gck_builder_new (GCK_BUILDER_NONE);
489
/* Do we have a consistent label across all objects? */
490
for (l = self->queue->head; l != NULL; l = g_list_next (l)) {
491
attr = gck_attributes_find (l->data, CKA_LABEL);
494
else if (!gck_attribute_equal (the_label, attr))
499
/* If consistent label, set that in supplement data */
500
if (the_label != NULL)
501
gck_builder_add_data (data->supplement, CKA_LABEL, the_label->value, the_label->length);
503
gck_builder_add_empty (data->supplement, CKA_LABEL);
505
if (GCR_IS_IMPORT_INTERACTION (self->interaction))
506
gcr_import_interaction_supplement_prep (GCR_IMPORT_INTERACTION (self->interaction),
510
/* ---------------------------------------------------------------------------------
515
complete_open_session (GSimpleAsyncResult *res,
519
GcrImporterData *data = g_simple_async_result_get_op_res_gpointer (res);
520
GcrPkcs11Importer *self = data->importer;
523
g_simple_async_result_take_error (res, error);
524
next_state (res, state_complete);
527
g_clear_object (&self->session);
528
self->session = session;
529
next_state (res, state_supplement);
534
on_open_session (GObject *source,
535
GAsyncResult *result,
538
GSimpleAsyncResult *res = G_SIMPLE_ASYNC_RESULT (user_data);
539
GError *error = NULL;
542
session = gck_session_open_finish (result, &error);
543
complete_open_session (res, session, error);
544
g_object_unref (res);
548
state_open_session (GSimpleAsyncResult *res,
551
GcrImporterData *data = g_simple_async_result_get_op_res_gpointer (res);
552
GcrPkcs11Importer *self = data->importer;
553
guint options = GCK_SESSION_READ_WRITE | GCK_SESSION_LOGIN_USER;
555
GError *error = NULL;
558
gck_session_open_async (self->slot, options, self->interaction,
559
data->cancellable, on_open_session, g_object_ref (res));
561
session = gck_session_open (self->slot, options, self->interaction,
562
data->cancellable, &error);
563
complete_open_session (res, session, error);
568
_gcr_pkcs11_importer_init (GcrPkcs11Importer *self)
570
self->queue = g_queue_new ();
574
_gcr_pkcs11_importer_dispose (GObject *obj)
576
GcrPkcs11Importer *self = GCR_PKCS11_IMPORTER (obj);
578
gck_list_unref_free (self->objects);
579
self->objects = NULL;
580
g_clear_object (&self->session);
581
g_clear_object (&self->interaction);
583
while (!g_queue_is_empty (self->queue))
584
gck_attributes_unref (g_queue_pop_head (self->queue));
586
G_OBJECT_CLASS (_gcr_pkcs11_importer_parent_class)->dispose (obj);
590
_gcr_pkcs11_importer_finalize (GObject *obj)
592
GcrPkcs11Importer *self = GCR_PKCS11_IMPORTER (obj);
594
g_clear_object (&self->slot);
596
G_OBJECT_CLASS (_gcr_pkcs11_importer_parent_class)->finalize (obj);
600
_gcr_pkcs11_importer_set_property (GObject *obj,
605
GcrPkcs11Importer *self = GCR_PKCS11_IMPORTER (obj);
609
self->slot = g_value_dup_object (value);
610
g_return_if_fail (self->slot);
612
case PROP_INTERACTION:
613
g_clear_object (&self->interaction);
614
self->interaction = g_value_dup_object (value);
615
g_object_notify (G_OBJECT (self), "interaction");
618
G_OBJECT_WARN_INVALID_PROPERTY_ID (obj, prop_id, pspec);
624
calculate_label (GcrPkcs11Importer *self)
629
info = gck_slot_get_token_info (self->slot);
630
result = g_strdup (info->label);
631
gck_token_info_free (info);
637
calculate_icon (GcrPkcs11Importer *self,
638
GckTokenInfo *token_info)
640
GckTokenInfo *info = NULL;
643
if (token_info == NULL)
644
info = token_info = gck_slot_get_token_info (self->slot);
645
result = gcr_icon_for_token (token_info);
646
gck_token_info_free (info);
652
calculate_uri (GcrPkcs11Importer *self)
657
data = gck_uri_data_new ();
658
data->token_info = gck_slot_get_token_info (self->slot);
659
uri = gck_uri_build (data, GCK_URI_FOR_TOKEN);
660
data->token_info = NULL;
661
gck_uri_data_free (data);
667
_gcr_pkcs11_importer_get_property (GObject *obj,
672
GcrPkcs11Importer *self = GCR_PKCS11_IMPORTER (obj);
676
g_value_take_string (value, calculate_label (self));
679
g_value_take_object (value, calculate_icon (self, NULL));
682
g_value_set_object (value, _gcr_pkcs11_importer_get_slot (self));
685
g_value_take_boxed (value, _gcr_pkcs11_importer_get_imported (self));
688
g_value_set_pointer (value, _gcr_pkcs11_importer_get_queued (self));
690
case PROP_INTERACTION:
691
g_value_set_object (value, self->interaction);
694
g_value_take_string (value, calculate_uri (self));
697
G_OBJECT_WARN_INVALID_PROPERTY_ID (obj, prop_id, pspec);
703
_gcr_pkcs11_importer_class_init (GcrPkcs11ImporterClass *klass)
705
GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
706
GckBuilder builder = GCK_BUILDER_INIT;
708
gobject_class->dispose = _gcr_pkcs11_importer_dispose;
709
gobject_class->finalize = _gcr_pkcs11_importer_finalize;
710
gobject_class->set_property = _gcr_pkcs11_importer_set_property;
711
gobject_class->get_property = _gcr_pkcs11_importer_get_property;
713
g_object_class_override_property (gobject_class, PROP_LABEL, "label");
714
g_object_class_override_property (gobject_class, PROP_ICON, "icon");
715
g_object_class_override_property (gobject_class, PROP_INTERACTION, "interaction");
716
g_object_class_override_property (gobject_class, PROP_URI, "uri");
718
g_object_class_install_property (gobject_class, PROP_SLOT,
719
g_param_spec_object ("slot", "Slot", "PKCS#11 slot to import data into",
720
GCK_TYPE_SLOT, G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
722
g_object_class_install_property (gobject_class, PROP_IMPORTED,
723
g_param_spec_boxed ("imported", "Imported", "Imported objects",
724
GCK_TYPE_LIST, G_PARAM_READABLE));
726
g_object_class_install_property (gobject_class, PROP_QUEUED,
727
g_param_spec_pointer ("queued", "Queued", "Queued attributes",
730
gck_builder_add_ulong (&builder, CKA_CLASS, CKO_CERTIFICATE);
731
gck_builder_add_ulong (&builder, CKA_CERTIFICATE_TYPE, CKC_X_509);
732
gcr_importer_register (GCR_TYPE_PKCS11_IMPORTER, gck_builder_end (&builder));
734
gck_builder_add_ulong (&builder, CKA_CLASS, CKO_PRIVATE_KEY);
735
gcr_importer_register (GCR_TYPE_PKCS11_IMPORTER, gck_builder_end (&builder));
737
_gcr_initialize_library ();
741
list_all_slots (void)
746
modules = gcr_pkcs11_get_modules ();
747
results = gck_modules_get_slots (modules, TRUE);
748
gck_list_unref_free (modules);
753
static const char *token_blacklist[] = {
754
"pkcs11:manufacturer=Gnome%20Keyring;serial=1:SECRET:MAIN",
755
"pkcs11:manufacturer=Gnome%20Keyring;serial=1:USER:DEFAULT",
760
is_slot_importable (GckSlot *slot,
763
GError *error = NULL;
768
if (token->flags & CKF_WRITE_PROTECTED) {
769
_gcr_debug ("token is not importable: %s: write protected", token->label);
772
if (!(token->flags & CKF_TOKEN_INITIALIZED)) {
773
_gcr_debug ("token is not importable: %s: not initialized", token->label);
776
if ((token->flags & CKF_LOGIN_REQUIRED) &&
777
!(token->flags & CKF_USER_PIN_INITIALIZED)) {
778
_gcr_debug ("token is not importable: %s: user pin not initialized", token->label);
782
for (i = 0; token_blacklist[i] != NULL; i++) {
783
uri = gck_uri_parse (token_blacklist[i], GCK_URI_FOR_TOKEN | GCK_URI_FOR_MODULE, &error);
785
g_warning ("couldn't parse pkcs11 blacklist uri: %s", error->message);
786
g_clear_error (&error);
790
match = gck_slot_match (slot, uri);
791
gck_uri_data_free (uri);
794
_gcr_debug ("token is not importable: %s: on the black list", token->label);
803
_gcr_pkcs11_importer_create_for_parsed (GcrParsed *parsed)
807
GList *results = NULL;
808
GckTokenInfo *token_info;
811
slots = list_all_slots ();
812
for (l = slots; l != NULL; l = g_list_next (l)) {
813
token_info = gck_slot_get_token_info (l->data);
814
importable = is_slot_importable (l->data, token_info);
817
_gcr_debug ("creating importer for token: %s", token_info->label);
818
self = _gcr_pkcs11_importer_new (l->data);
819
if (!gcr_importer_queue_for_parsed (self, parsed))
820
g_assert_not_reached ();
821
results = g_list_prepend (results, self);
824
gck_token_info_free (token_info);
826
gck_list_unref_free (slots);
828
return g_list_reverse (results);
832
_gcr_pkcs11_importer_queue_for_parsed (GcrImporter *importer,
835
GcrPkcs11Importer *self = GCR_PKCS11_IMPORTER (importer);
836
GckAttributes *attrs;
839
attrs = gcr_parsed_get_attributes (parsed);
840
label = gcr_parsed_get_label (parsed);
841
_gcr_pkcs11_importer_queue (self, label, attrs);
847
_gcr_pkcs11_importer_import_async (GcrImporter *importer,
848
GCancellable *cancellable,
849
GAsyncReadyCallback callback,
852
GSimpleAsyncResult *res;
853
GcrImporterData *data;
855
res = g_simple_async_result_new (G_OBJECT (importer), callback, user_data,
856
_gcr_pkcs11_importer_import_async);
857
data = g_new0 (GcrImporterData, 1);
859
data->importer = g_object_ref (importer);
860
data->cancellable = cancellable ? g_object_ref (cancellable) : NULL;
861
g_simple_async_result_set_op_res_gpointer (res, data, gcr_importer_data_free);
863
supplement_prep (res);
865
next_state (res, state_open_session);
866
g_object_unref (res);
870
_gcr_pkcs11_importer_import_finish (GcrImporter *importer,
871
GAsyncResult *result,
874
g_return_val_if_fail (g_simple_async_result_is_valid (result, G_OBJECT (importer),
875
_gcr_pkcs11_importer_import_async), FALSE);
877
if (g_simple_async_result_propagate_error (G_SIMPLE_ASYNC_RESULT (result), error))
884
_gcr_pkcs11_importer_init_iface (GcrImporterIface *iface)
886
iface->create_for_parsed = _gcr_pkcs11_importer_create_for_parsed;
887
iface->queue_for_parsed = _gcr_pkcs11_importer_queue_for_parsed;
888
iface->import_async = _gcr_pkcs11_importer_import_async;
889
iface->import_finish = _gcr_pkcs11_importer_import_finish;
893
* _gcr_pkcs11_importer_new:
895
* Create a new #GcrPkcs11Importer.
897
* Returns: (transfer full) (type Gcr.Pkcs11Importer): the new importer
900
_gcr_pkcs11_importer_new (GckSlot *slot)
902
g_return_val_if_fail (GCK_IS_SLOT (slot), NULL);
904
return g_object_new (GCR_TYPE_PKCS11_IMPORTER,
910
_gcr_pkcs11_importer_get_slot (GcrPkcs11Importer *self)
912
g_return_val_if_fail (GCR_IS_PKCS11_IMPORTER (self), NULL);
917
_gcr_pkcs11_importer_get_imported (GcrPkcs11Importer *self)
919
g_return_val_if_fail (GCR_IS_PKCS11_IMPORTER (self), NULL);
920
return g_list_copy (self->objects);
924
_gcr_pkcs11_importer_get_queued (GcrPkcs11Importer *self)
926
g_return_val_if_fail (GCR_IS_PKCS11_IMPORTER (self), NULL);
927
return g_list_copy (self->queue->head);
931
_gcr_pkcs11_importer_queue (GcrPkcs11Importer *self,
933
GckAttributes *attrs)
935
GckBuilder builder = GCK_BUILDER_INIT;
937
g_return_if_fail (GCR_IS_PKCS11_IMPORTER (self));
938
g_return_if_fail (attrs != NULL);
940
if (label != NULL && !gck_attributes_find (attrs, CKA_LABEL)) {
941
gck_builder_add_all (&builder, attrs);
942
gck_builder_add_string (&builder, CKA_LABEL, label);
943
attrs = gck_builder_end (&builder);
946
g_queue_push_tail (self->queue, gck_attributes_ref_sink (attrs));