~ubuntu-branches/ubuntu/trusty/gcr/trusty-proposed

« back to all changes in this revision

Viewing changes to gcr/gcr-pkcs11-importer.c

  • Committer: Package Import Robot
  • Author(s): Jordi Mallach
  • Date: 2012-05-03 10:18:39 UTC
  • Revision ID: package-import@ubuntu.com-20120503101839-wuvloldm7gmdsnij
Tags: upstream-3.4.1
ImportĀ upstreamĀ versionĀ 3.4.1

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
 * gnome-keyring
 
3
 *
 
4
 * Copyright (C) 2008 Stefan Walter
 
5
 * Copyright (C) 2011 Collabora Ltd.
 
6
 *
 
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.
 
11
 *
 
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.
 
16
 *
 
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
 
20
 * 02111-1307, USA.
 
21
 *
 
22
 * Author: Stef Walter <stefw@collabora.co.uk>
 
23
 */
 
24
 
 
25
#include "config.h"
 
26
 
 
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"
 
37
 
 
38
#include "egg/egg-hex.h"
 
39
 
 
40
#include <gck/gck.h>
 
41
 
 
42
#include <gcrypt.h>
 
43
 
 
44
#include <glib/gi18n-lib.h>
 
45
 
 
46
enum {
 
47
        PROP_0,
 
48
        PROP_LABEL,
 
49
        PROP_ICON,
 
50
        PROP_INTERACTION,
 
51
        PROP_SLOT,
 
52
        PROP_IMPORTED,
 
53
        PROP_QUEUED,
 
54
        PROP_URI
 
55
};
 
56
 
 
57
typedef struct _GcrPkcs11ImporterClass GcrPkcs11ImporterClass;
 
58
 
 
59
struct _GcrPkcs11Importer {
 
60
        GObject parent;
 
61
        GckSlot *slot;
 
62
        GList *objects;
 
63
        GckSession *session;
 
64
        GQueue *queue;
 
65
        GTlsInteraction *interaction;
 
66
        gboolean any_private;
 
67
};
 
68
 
 
69
struct _GcrPkcs11ImporterClass {
 
70
        GObjectClass parent_class;
 
71
};
 
72
 
 
73
typedef struct  {
 
74
        GcrPkcs11Importer *importer;
 
75
        GCancellable *cancellable;
 
76
        gboolean prompted;
 
77
        gboolean async;
 
78
        GckBuilder *supplement;
 
79
} GcrImporterData;
 
80
 
 
81
/* State forward declarations */
 
82
static void   state_cancelled                  (GSimpleAsyncResult *res,
 
83
                                                gboolean async);
 
84
 
 
85
static void   state_complete                   (GSimpleAsyncResult *res,
 
86
                                                gboolean async);
 
87
 
 
88
static void   state_create_object              (GSimpleAsyncResult *res,
 
89
                                                gboolean async);
 
90
 
 
91
static void   state_supplement                 (GSimpleAsyncResult *res,
 
92
                                                gboolean async);
 
93
 
 
94
static void   state_open_session               (GSimpleAsyncResult *res,
 
95
                                                gboolean async);
 
96
 
 
97
static void   _gcr_pkcs11_importer_init_iface  (GcrImporterIface *iface);
 
98
 
 
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);
 
101
);
 
102
 
 
103
#define BLOCK 4096
 
104
 
 
105
static void
 
106
gcr_importer_data_free (gpointer data)
 
107
{
 
108
        GcrImporterData *state = data;
 
109
 
 
110
        g_clear_object (&state->cancellable);
 
111
        g_clear_object (&state->importer);
 
112
        g_free (state);
 
113
}
 
114
 
 
115
static void
 
116
next_state (GSimpleAsyncResult *res,
 
117
            void (*state) (GSimpleAsyncResult *, gboolean))
 
118
{
 
119
        GcrImporterData *data = g_simple_async_result_get_op_res_gpointer (res);
 
120
 
 
121
        g_assert (state);
 
122
 
 
123
        if (g_cancellable_is_cancelled (data->cancellable))
 
124
                state = state_cancelled;
 
125
 
 
126
        (state) (res, data->async);
 
127
}
 
128
 
 
129
/* ---------------------------------------------------------------------------------
 
130
 * COMPLETE
 
131
 */
 
132
 
 
133
static void
 
134
state_complete (GSimpleAsyncResult *res,
 
135
                gboolean async)
 
136
{
 
137
        g_simple_async_result_complete (res);
 
138
}
 
139
 
 
140
static void
 
141
state_cancelled (GSimpleAsyncResult *res,
 
142
                 gboolean async)
 
143
{
 
144
        GcrImporterData *data = g_simple_async_result_get_op_res_gpointer (res);
 
145
        GError *error = NULL;
 
146
 
 
147
        if (data->cancellable && !g_cancellable_is_cancelled (data->cancellable))
 
148
                g_cancellable_cancel (data->cancellable);
 
149
 
 
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);
 
153
}
 
154
 
 
155
/* ---------------------------------------------------------------------------------
 
156
 * CREATE OBJECTS
 
157
 */
 
158
 
 
159
static void
 
160
complete_create_object (GSimpleAsyncResult *res,
 
161
                        GckObject *object,
 
162
                        GError *error)
 
163
{
 
164
        GcrImporterData *data = g_simple_async_result_get_op_res_gpointer (res);
 
165
        GcrPkcs11Importer *self = data->importer;
 
166
 
 
167
        if (object == NULL) {
 
168
                g_simple_async_result_take_error (res, error);
 
169
                next_state (res, state_complete);
 
170
 
 
171
        } else {
 
172
                self->objects = g_list_append (self->objects, object);
 
173
                next_state (res, state_create_object);
 
174
        }
 
175
}
 
176
 
 
177
static void
 
178
on_create_object (GObject *source,
 
179
                  GAsyncResult *result,
 
180
                  gpointer user_data)
 
181
{
 
182
        GSimpleAsyncResult *res = G_SIMPLE_ASYNC_RESULT (user_data);
 
183
        GError *error = NULL;
 
184
        GckObject *object;
 
185
 
 
186
        object = gck_session_create_object_finish (GCK_SESSION (source), result, &error);
 
187
        complete_create_object (res, object, error);
 
188
        g_object_unref (res);
 
189
}
 
190
 
 
191
static void
 
192
state_create_object (GSimpleAsyncResult *res,
 
193
                     gboolean async)
 
194
{
 
195
        GcrImporterData *data = g_simple_async_result_get_op_res_gpointer (res);
 
196
        GcrPkcs11Importer *self = data->importer;
 
197
        GckAttributes *attrs;
 
198
        GckObject *object;
 
199
        GError *error = NULL;
 
200
 
 
201
        /* No more objects */
 
202
        if (g_queue_is_empty (self->queue)) {
 
203
                next_state (res, state_complete);
 
204
 
 
205
        } else {
 
206
 
 
207
                /* Pop first one off the list */
 
208
                attrs = g_queue_pop_head (self->queue);
 
209
                g_assert (attrs != NULL);
 
210
 
 
211
                if (async) {
 
212
                        gck_session_create_object_async (self->session, attrs,
 
213
                                                         data->cancellable, on_create_object,
 
214
                                                         g_object_ref (res));
 
215
                } else {
 
216
                        object = gck_session_create_object (self->session, attrs,
 
217
                                                            data->cancellable, &error);
 
218
                        complete_create_object (res, object, error);
 
219
                }
 
220
 
 
221
                gck_attributes_unref (attrs);
 
222
        }
 
223
}
 
224
 
 
225
/* ---------------------------------------------------------------------------------
 
226
 * SUPPLEMENTING and FIXING UP
 
227
 */
 
228
 
 
229
typedef struct {
 
230
        GckAttributes *certificate;
 
231
        GckAttributes *private_key;
 
232
} CertificateKeyPair;
 
233
 
 
234
static void
 
235
supplement_with_attributes (GckBuilder *builder,
 
236
                            GckAttributes *supplements)
 
237
{
 
238
        const GckAttribute *supplement;
 
239
        gint i;
 
240
 
 
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);
 
245
        }
 
246
}
 
247
 
 
248
static void
 
249
supplement_id_for_data (GckBuilder *builder,
 
250
                        guchar *nonce,
 
251
                        gsize n_once,
 
252
                        gpointer data,
 
253
                        gsize n_data)
 
254
{
 
255
        gcry_md_hd_t mdh;
 
256
        gcry_error_t gcry;
 
257
 
 
258
        if (gck_builder_find (builder, CKA_ID) != NULL)
 
259
                return;
 
260
 
 
261
        gcry = gcry_md_open (&mdh, GCRY_MD_SHA1, 0);
 
262
        g_return_if_fail (gcry == 0);
 
263
 
 
264
        gcry_md_write (mdh, nonce, n_once);
 
265
        gcry_md_write (mdh, data, n_data);
 
266
 
 
267
        gck_builder_add_data (builder, CKA_ID,
 
268
                              gcry_md_read (mdh, 0),
 
269
                              gcry_md_get_algo_dlen (GCRY_MD_SHA1));
 
270
 
 
271
        gcry_md_close (mdh);
 
272
}
 
273
 
 
274
static void
 
275
supplement_attributes (GcrPkcs11Importer *self,
 
276
                       GckAttributes *supplements)
 
277
{
 
278
        GckBuilder builder = GCK_BUILDER_INIT;
 
279
        GHashTable *pairs;
 
280
        GHashTable *paired;
 
281
        CertificateKeyPair *pair;
 
282
        gboolean supplemented = FALSE;
 
283
        GckAttributes *attrs;
 
284
        gulong klass;
 
285
        guchar *finger;
 
286
        gchar *fingerprint;
 
287
        guchar nonce[20];
 
288
        GHashTableIter iter;
 
289
        gsize n_finger;
 
290
        GQueue *queue;
 
291
        GList *l;
 
292
 
 
293
        /* A table of certificate/key pairs by fingerprint */
 
294
        pairs = g_hash_table_new_full (g_str_hash, g_str_equal,
 
295
                                       g_free, g_free);
 
296
 
 
297
        for (l = self->queue->head; l != NULL; l = g_list_next (l)) {
 
298
                attrs = l->data;
 
299
                if (!gck_attributes_find_ulong (attrs, CKA_CLASS, &klass))
 
300
                        g_return_if_reached ();
 
301
 
 
302
                /* Make a string fingerprint for this guy */
 
303
                finger = gcr_fingerprint_from_attributes (attrs, G_CHECKSUM_SHA1,
 
304
                                                          &n_finger);
 
305
                if (finger) {
 
306
                        fingerprint = egg_hex_encode (finger, n_finger);
 
307
                        g_free (finger);
 
308
 
 
309
                        pair = g_hash_table_lookup (pairs, fingerprint);
 
310
                        if (pair == NULL) {
 
311
                                pair = g_new0 (CertificateKeyPair, 1);
 
312
                                g_hash_table_insert (pairs, fingerprint, pair);
 
313
                        } else {
 
314
                                g_free (fingerprint);
 
315
                        }
 
316
                } else {
 
317
                        pair = NULL;
 
318
                }
 
319
 
 
320
                fingerprint = NULL;
 
321
                gck_builder_add_all (&builder, attrs);
 
322
                gck_builder_set_boolean (&builder, CKA_TOKEN, CK_TRUE);
 
323
 
 
324
                switch (klass) {
 
325
                case CKO_CERTIFICATE:
 
326
                        gck_builder_set_boolean (&builder, CKA_PRIVATE, FALSE);
 
327
                        break;
 
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);
 
335
                        break;
 
336
                }
 
337
 
 
338
                gck_attributes_unref (attrs);
 
339
                l->data = attrs = gck_attributes_ref_sink (gck_builder_end (&builder));
 
340
 
 
341
                switch (klass) {
 
342
                case CKO_CERTIFICATE:
 
343
                        if (pair != NULL && pair->certificate == NULL)
 
344
                                pair->certificate = attrs;
 
345
                        break;
 
346
                case CKO_PRIVATE_KEY:
 
347
                        if (pair != NULL && pair->private_key == NULL)
 
348
                                pair->private_key = attrs;
 
349
                        break;
 
350
                }
 
351
        }
 
352
 
 
353
        /* For generation of CKA_ID's */
 
354
        gcry_create_nonce (nonce, sizeof (nonce));
 
355
 
 
356
        /* A table for marking which attributes are in the pairs table */
 
357
        paired = g_hash_table_new (g_direct_hash, g_direct_equal);
 
358
 
 
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) {
 
364
                        /*
 
365
                         * Generate a CKA_ID based on the fingerprint and nonce,
 
366
                         * and do the same CKA_ID for both private key and certificate.
 
367
                         */
 
368
 
 
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");
 
375
 
 
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");
 
382
 
 
383
                        /* Used the suplements for the pairs, don't use for unpaired stuff */
 
384
                        supplemented = TRUE;
 
385
                }
 
386
        }
 
387
 
 
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)) {
 
390
                attrs = l->data;
 
391
                if (!g_hash_table_lookup (paired, attrs)) {
 
392
                        gck_builder_add_all (&builder, attrs);
 
393
                        if (!supplemented)
 
394
                                supplement_with_attributes (&builder, supplements);
 
395
 
 
396
                        /*
 
397
                         * Generate a CKA_ID based on the location of attrs in,
 
398
                         * memory, since this together with the nonce should
 
399
                         * be unique.
 
400
                         */
 
401
                        supplement_id_for_data (&builder, nonce, sizeof (nonce),
 
402
                                                &attrs, sizeof (gpointer));
 
403
 
 
404
                        g_queue_push_tail (queue, gck_attributes_ref_sink (gck_builder_end (&builder)));
 
405
                }
 
406
        }
 
407
 
 
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);
 
411
        self->queue = queue;
 
412
 
 
413
        g_hash_table_destroy (paired);
 
414
        g_hash_table_destroy (pairs);
 
415
}
 
416
 
 
417
static void
 
418
complete_supplement (GSimpleAsyncResult *res,
 
419
                     GError *error)
 
420
{
 
421
        GcrImporterData *data = g_simple_async_result_get_op_res_gpointer (res);
 
422
        GckAttributes *attributes;
 
423
 
 
424
        if (error == NULL) {
 
425
                attributes = gck_attributes_ref_sink (gck_builder_end (data->supplement));
 
426
                supplement_attributes (data->importer, attributes);
 
427
                gck_attributes_unref (attributes);
 
428
 
 
429
                next_state (res, state_create_object);
 
430
        } else {
 
431
                g_simple_async_result_take_error (res, error);
 
432
                next_state (res, state_complete);
 
433
        }
 
434
}
 
435
 
 
436
static void
 
437
on_supplement_done (GObject *source,
 
438
                    GAsyncResult *result,
 
439
                    gpointer user_data)
 
440
{
 
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;
 
445
 
 
446
        gcr_import_interaction_supplement_finish (GCR_IMPORT_INTERACTION (self->interaction),
 
447
                                                  result, &error);
 
448
        complete_supplement (res, error);
 
449
        g_object_unref (res);
 
450
}
 
451
 
 
452
static void
 
453
state_supplement (GSimpleAsyncResult *res,
 
454
                  gboolean async)
 
455
{
 
456
        GcrImporterData *data = g_simple_async_result_get_op_res_gpointer (res);
 
457
        GcrPkcs11Importer *self = data->importer;
 
458
        GError *error = NULL;
 
459
 
 
460
        if (self->interaction == NULL || !GCR_IS_IMPORT_INTERACTION (self->interaction)) {
 
461
                complete_supplement (res, NULL);
 
462
 
 
463
        } else if (async) {
 
464
                gcr_import_interaction_supplement_async (GCR_IMPORT_INTERACTION (self->interaction),
 
465
                                                         data->supplement, data->cancellable,
 
466
                                                         on_supplement_done, g_object_ref (res));
 
467
 
 
468
        } else {
 
469
                gcr_import_interaction_supplement (GCR_IMPORT_INTERACTION (self->interaction),
 
470
                                                   data->supplement, data->cancellable, &error);
 
471
                complete_supplement (res, error);
 
472
        }
 
473
}
 
474
 
 
475
static void
 
476
supplement_prep (GSimpleAsyncResult *res)
 
477
{
 
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;
 
483
        GList *l;
 
484
 
 
485
        if (data->supplement)
 
486
                gck_builder_unref (data->supplement);
 
487
        data->supplement = gck_builder_new (GCK_BUILDER_NONE);
 
488
 
 
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);
 
492
                if (first)
 
493
                        the_label = attr;
 
494
                else if (!gck_attribute_equal (the_label, attr))
 
495
                        the_label = NULL;
 
496
                first = FALSE;
 
497
        }
 
498
 
 
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);
 
502
        else
 
503
                gck_builder_add_empty (data->supplement, CKA_LABEL);
 
504
 
 
505
        if (GCR_IS_IMPORT_INTERACTION (self->interaction))
 
506
                gcr_import_interaction_supplement_prep (GCR_IMPORT_INTERACTION (self->interaction),
 
507
                                                        data->supplement);
 
508
}
 
509
 
 
510
/* ---------------------------------------------------------------------------------
 
511
 * OPEN SESSION
 
512
 */
 
513
 
 
514
static void
 
515
complete_open_session (GSimpleAsyncResult *res,
 
516
                       GckSession *session,
 
517
                       GError *error)
 
518
{
 
519
        GcrImporterData *data = g_simple_async_result_get_op_res_gpointer (res);
 
520
        GcrPkcs11Importer *self = data->importer;
 
521
 
 
522
        if (!session) {
 
523
                g_simple_async_result_take_error (res, error);
 
524
                next_state (res, state_complete);
 
525
 
 
526
        } else {
 
527
                g_clear_object (&self->session);
 
528
                self->session = session;
 
529
                next_state (res, state_supplement);
 
530
        }
 
531
}
 
532
 
 
533
static void
 
534
on_open_session (GObject *source,
 
535
                 GAsyncResult *result,
 
536
                 gpointer user_data)
 
537
{
 
538
        GSimpleAsyncResult *res = G_SIMPLE_ASYNC_RESULT (user_data);
 
539
        GError *error = NULL;
 
540
        GckSession *session;
 
541
 
 
542
        session = gck_session_open_finish (result, &error);
 
543
        complete_open_session (res, session, error);
 
544
        g_object_unref (res);
 
545
}
 
546
 
 
547
static void
 
548
state_open_session (GSimpleAsyncResult *res,
 
549
                    gboolean async)
 
550
{
 
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;
 
554
        GckSession *session;
 
555
        GError *error = NULL;
 
556
 
 
557
        if (async) {
 
558
                gck_session_open_async (self->slot, options, self->interaction,
 
559
                                        data->cancellable, on_open_session, g_object_ref (res));
 
560
        } else {
 
561
                session = gck_session_open (self->slot, options, self->interaction,
 
562
                                            data->cancellable, &error);
 
563
                complete_open_session (res, session, error);
 
564
        }
 
565
}
 
566
 
 
567
static void
 
568
_gcr_pkcs11_importer_init (GcrPkcs11Importer *self)
 
569
{
 
570
        self->queue = g_queue_new ();
 
571
}
 
572
 
 
573
static void
 
574
_gcr_pkcs11_importer_dispose (GObject *obj)
 
575
{
 
576
        GcrPkcs11Importer *self = GCR_PKCS11_IMPORTER (obj);
 
577
 
 
578
        gck_list_unref_free (self->objects);
 
579
        self->objects = NULL;
 
580
        g_clear_object (&self->session);
 
581
        g_clear_object (&self->interaction);
 
582
 
 
583
        while (!g_queue_is_empty (self->queue))
 
584
                gck_attributes_unref (g_queue_pop_head (self->queue));
 
585
 
 
586
        G_OBJECT_CLASS (_gcr_pkcs11_importer_parent_class)->dispose (obj);
 
587
}
 
588
 
 
589
static void
 
590
_gcr_pkcs11_importer_finalize (GObject *obj)
 
591
{
 
592
        GcrPkcs11Importer *self = GCR_PKCS11_IMPORTER (obj);
 
593
 
 
594
        g_clear_object (&self->slot);
 
595
 
 
596
        G_OBJECT_CLASS (_gcr_pkcs11_importer_parent_class)->finalize (obj);
 
597
}
 
598
 
 
599
static void
 
600
_gcr_pkcs11_importer_set_property (GObject *obj,
 
601
                                   guint prop_id,
 
602
                                   const GValue *value,
 
603
                                   GParamSpec *pspec)
 
604
{
 
605
        GcrPkcs11Importer *self = GCR_PKCS11_IMPORTER (obj);
 
606
 
 
607
        switch (prop_id) {
 
608
        case PROP_SLOT:
 
609
                self->slot = g_value_dup_object (value);
 
610
                g_return_if_fail (self->slot);
 
611
                break;
 
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");
 
616
                break;
 
617
        default:
 
618
                G_OBJECT_WARN_INVALID_PROPERTY_ID (obj, prop_id, pspec);
 
619
                break;
 
620
        }
 
621
}
 
622
 
 
623
static gchar *
 
624
calculate_label (GcrPkcs11Importer *self)
 
625
{
 
626
        GckTokenInfo *info;
 
627
        gchar *result;
 
628
 
 
629
        info = gck_slot_get_token_info (self->slot);
 
630
        result = g_strdup (info->label);
 
631
        gck_token_info_free (info);
 
632
 
 
633
        return result;
 
634
}
 
635
 
 
636
static GIcon *
 
637
calculate_icon (GcrPkcs11Importer *self,
 
638
                GckTokenInfo *token_info)
 
639
{
 
640
        GckTokenInfo *info = NULL;
 
641
        GIcon *result;
 
642
 
 
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);
 
647
 
 
648
        return result;
 
649
}
 
650
 
 
651
static gchar *
 
652
calculate_uri (GcrPkcs11Importer *self)
 
653
{
 
654
        GckUriData *data;
 
655
        gchar *uri;
 
656
 
 
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);
 
662
 
 
663
        return uri;
 
664
}
 
665
 
 
666
static void
 
667
_gcr_pkcs11_importer_get_property (GObject *obj,
 
668
                                   guint prop_id,
 
669
                                   GValue *value,
 
670
                                   GParamSpec *pspec)
 
671
{
 
672
        GcrPkcs11Importer *self = GCR_PKCS11_IMPORTER (obj);
 
673
 
 
674
        switch (prop_id) {
 
675
        case PROP_LABEL:
 
676
                g_value_take_string (value, calculate_label (self));
 
677
                break;
 
678
        case PROP_ICON:
 
679
                g_value_take_object (value, calculate_icon (self, NULL));
 
680
                break;
 
681
        case PROP_SLOT:
 
682
                g_value_set_object (value, _gcr_pkcs11_importer_get_slot (self));
 
683
                break;
 
684
        case PROP_IMPORTED:
 
685
                g_value_take_boxed (value, _gcr_pkcs11_importer_get_imported (self));
 
686
                break;
 
687
        case PROP_QUEUED:
 
688
                g_value_set_pointer (value, _gcr_pkcs11_importer_get_queued (self));
 
689
                break;
 
690
        case PROP_INTERACTION:
 
691
                g_value_set_object (value, self->interaction);
 
692
                break;
 
693
        case PROP_URI:
 
694
                g_value_take_string (value, calculate_uri (self));
 
695
                break;
 
696
        default:
 
697
                G_OBJECT_WARN_INVALID_PROPERTY_ID (obj, prop_id, pspec);
 
698
                break;
 
699
        }
 
700
}
 
701
 
 
702
static void
 
703
_gcr_pkcs11_importer_class_init (GcrPkcs11ImporterClass *klass)
 
704
{
 
705
        GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
 
706
        GckBuilder builder = GCK_BUILDER_INIT;
 
707
 
 
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;
 
712
 
 
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");
 
717
 
 
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));
 
721
 
 
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));
 
725
 
 
726
        g_object_class_install_property (gobject_class, PROP_QUEUED,
 
727
                   g_param_spec_pointer ("queued", "Queued", "Queued attributes",
 
728
                                         G_PARAM_READABLE));
 
729
 
 
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));
 
733
 
 
734
        gck_builder_add_ulong (&builder, CKA_CLASS, CKO_PRIVATE_KEY);
 
735
        gcr_importer_register (GCR_TYPE_PKCS11_IMPORTER, gck_builder_end (&builder));
 
736
 
 
737
        _gcr_initialize_library ();
 
738
}
 
739
 
 
740
static GList *
 
741
list_all_slots (void)
 
742
{
 
743
        GList *modules;
 
744
        GList *results;
 
745
 
 
746
        modules = gcr_pkcs11_get_modules ();
 
747
        results = gck_modules_get_slots (modules, TRUE);
 
748
        gck_list_unref_free (modules);
 
749
 
 
750
        return results;
 
751
}
 
752
 
 
753
static const char *token_blacklist[] = {
 
754
        "pkcs11:manufacturer=Gnome%20Keyring;serial=1:SECRET:MAIN",
 
755
        "pkcs11:manufacturer=Gnome%20Keyring;serial=1:USER:DEFAULT",
 
756
        NULL
 
757
};
 
758
 
 
759
static gboolean
 
760
is_slot_importable (GckSlot *slot,
 
761
                    GckTokenInfo *token)
 
762
{
 
763
        GError *error = NULL;
 
764
        GckUriData *uri;
 
765
        gboolean match;
 
766
        guint i;
 
767
 
 
768
        if (token->flags & CKF_WRITE_PROTECTED) {
 
769
                _gcr_debug ("token is not importable: %s: write protected", token->label);
 
770
                return FALSE;
 
771
        }
 
772
        if (!(token->flags & CKF_TOKEN_INITIALIZED)) {
 
773
                _gcr_debug ("token is not importable: %s: not initialized", token->label);
 
774
                return FALSE;
 
775
        }
 
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);
 
779
                return FALSE;
 
780
        }
 
781
 
 
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);
 
784
                if (uri == NULL) {
 
785
                        g_warning ("couldn't parse pkcs11 blacklist uri: %s", error->message);
 
786
                        g_clear_error (&error);
 
787
                        continue;
 
788
                }
 
789
 
 
790
                match = gck_slot_match (slot, uri);
 
791
                gck_uri_data_free (uri);
 
792
 
 
793
                if (match) {
 
794
                        _gcr_debug ("token is not importable: %s: on the black list", token->label);
 
795
                        return FALSE;
 
796
                }
 
797
        }
 
798
 
 
799
        return TRUE;
 
800
}
 
801
 
 
802
static GList *
 
803
_gcr_pkcs11_importer_create_for_parsed (GcrParsed *parsed)
 
804
{
 
805
        GcrImporter *self;
 
806
        GList *slots, *l;
 
807
        GList *results = NULL;
 
808
        GckTokenInfo *token_info;
 
809
        gboolean importable;
 
810
 
 
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);
 
815
 
 
816
                if (importable) {
 
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);
 
822
                }
 
823
 
 
824
                gck_token_info_free (token_info);
 
825
        }
 
826
        gck_list_unref_free (slots);
 
827
 
 
828
        return g_list_reverse (results);
 
829
}
 
830
 
 
831
static gboolean
 
832
_gcr_pkcs11_importer_queue_for_parsed (GcrImporter *importer,
 
833
                                       GcrParsed *parsed)
 
834
{
 
835
        GcrPkcs11Importer *self = GCR_PKCS11_IMPORTER (importer);
 
836
        GckAttributes *attrs;
 
837
        const gchar *label;
 
838
 
 
839
        attrs = gcr_parsed_get_attributes (parsed);
 
840
        label = gcr_parsed_get_label (parsed);
 
841
        _gcr_pkcs11_importer_queue (self, label, attrs);
 
842
 
 
843
        return TRUE;
 
844
}
 
845
 
 
846
static void
 
847
_gcr_pkcs11_importer_import_async (GcrImporter *importer,
 
848
                                   GCancellable *cancellable,
 
849
                                   GAsyncReadyCallback callback,
 
850
                                   gpointer user_data)
 
851
{
 
852
        GSimpleAsyncResult *res;
 
853
        GcrImporterData *data;
 
854
 
 
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);
 
858
        data->async = TRUE;
 
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);
 
862
 
 
863
        supplement_prep (res);
 
864
 
 
865
        next_state (res, state_open_session);
 
866
        g_object_unref (res);
 
867
}
 
868
 
 
869
static gboolean
 
870
_gcr_pkcs11_importer_import_finish (GcrImporter *importer,
 
871
                                    GAsyncResult *result,
 
872
                                    GError **error)
 
873
{
 
874
        g_return_val_if_fail (g_simple_async_result_is_valid (result, G_OBJECT (importer),
 
875
                              _gcr_pkcs11_importer_import_async), FALSE);
 
876
 
 
877
        if (g_simple_async_result_propagate_error (G_SIMPLE_ASYNC_RESULT (result), error))
 
878
                return FALSE;
 
879
 
 
880
        return TRUE;
 
881
}
 
882
 
 
883
static void
 
884
_gcr_pkcs11_importer_init_iface (GcrImporterIface *iface)
 
885
{
 
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;
 
890
}
 
891
 
 
892
/**
 
893
 * _gcr_pkcs11_importer_new:
 
894
 *
 
895
 * Create a new #GcrPkcs11Importer.
 
896
 *
 
897
 * Returns: (transfer full) (type Gcr.Pkcs11Importer): the new importer
 
898
 */
 
899
GcrImporter *
 
900
_gcr_pkcs11_importer_new (GckSlot *slot)
 
901
{
 
902
        g_return_val_if_fail (GCK_IS_SLOT (slot), NULL);
 
903
 
 
904
        return g_object_new (GCR_TYPE_PKCS11_IMPORTER,
 
905
                             "slot", slot,
 
906
                             NULL);
 
907
}
 
908
 
 
909
GckSlot *
 
910
_gcr_pkcs11_importer_get_slot (GcrPkcs11Importer *self)
 
911
{
 
912
        g_return_val_if_fail (GCR_IS_PKCS11_IMPORTER (self), NULL);
 
913
        return self->slot;
 
914
}
 
915
 
 
916
GList *
 
917
_gcr_pkcs11_importer_get_imported (GcrPkcs11Importer *self)
 
918
{
 
919
        g_return_val_if_fail (GCR_IS_PKCS11_IMPORTER (self), NULL);
 
920
        return g_list_copy (self->objects);
 
921
}
 
922
 
 
923
GList *
 
924
_gcr_pkcs11_importer_get_queued (GcrPkcs11Importer *self)
 
925
{
 
926
        g_return_val_if_fail (GCR_IS_PKCS11_IMPORTER (self), NULL);
 
927
        return g_list_copy (self->queue->head);
 
928
}
 
929
 
 
930
void
 
931
_gcr_pkcs11_importer_queue (GcrPkcs11Importer *self,
 
932
                            const gchar *label,
 
933
                            GckAttributes *attrs)
 
934
{
 
935
        GckBuilder builder = GCK_BUILDER_INIT;
 
936
 
 
937
        g_return_if_fail (GCR_IS_PKCS11_IMPORTER (self));
 
938
        g_return_if_fail (attrs != NULL);
 
939
 
 
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);
 
944
        }
 
945
 
 
946
        g_queue_push_tail (self->queue, gck_attributes_ref_sink (attrs));
 
947
}