gcr-parser.c 87.2 KB
Newer Older
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
/*
 * gnome-keyring
 *
 * Copyright (C) 2008 Stefan Walter
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as
 * published by the Free Software Foundation; either version 2.1 of
 * the License, or (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful, but
 * WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
17
 * License along with this program; if not, see <http://www.gnu.org/licenses/>.
18
19
20
21
 */

#include "config.h"

22
#include "gck/gck.h"
23
24

#include "gcr-internal.h"
25
#include "gcr-openpgp.h"
26
#include "gcr-openssh.h"
27
#include "gcr-parser.h"
Stef Walter's avatar
Stef Walter committed
28
#include "gcr-record.h"
29
30
#include "gcr-types.h"

31
32
33
#include "gcr/gcr-marshal.h"
#include "gcr/gcr-oids.h"

34
#include "egg/egg-armor.h"
35
36
#include "egg/egg-asn1x.h"
#include "egg/egg-asn1-defs.h"
37
#include "egg/egg-dn.h"
38
39
40
41
42
43
44
45
46
#include "egg/egg-openssl.h"
#include "egg/egg-secure-memory.h"
#include "egg/egg-symkey.h"

#include <glib/gi18n-lib.h>

#include <stdlib.h>
#include <gcrypt.h>

Stef Walter's avatar
Stef Walter committed
47
/**
48
 * GcrParser:
Stef Walter's avatar
Stef Walter committed
49
 *
50
 * A parser for parsing various types of files or data.
Stef Walter's avatar
Stef Walter committed
51
 *
52
53
54
 * A `GcrParser` can parse various certificate and key files such as OpenSSL
 * PEM files, DER encoded certifictes, PKCS#8 keys and so on. Each various
 * format is identified by a value in the [enum@DataFormat] enumeration.
Stef Walter's avatar
Stef Walter committed
55
 *
56
57
58
59
 * In order to parse data, a new parser is created with gcr_parser_new() and
 * then the [signal@Parser::authenticate] and [signal@Parser::parsed] signals
 * should be connected to. Data is then fed to the parser via
 * [method@Parser.parse_data] or [method@Parser.parse_stream].
Stef Walter's avatar
Stef Walter committed
60
 *
61
62
63
 * During the [signal@Parser::parsed] signal the attributes that make up the
 * currently parsed item can be retrieved using the
 * [method@Parser.get_parsed_attributes] function.
Stef Walter's avatar
Stef Walter committed
64
65
 */

66
67
68
69
70
71
/**
 * GcrParsed:
 *
 * A parsed item parsed by a #GcrParser.
 */

Stef Walter's avatar
Stef Walter committed
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
/**
 * GcrParserClass:
 * @parent_class: The parent class
 * @authenticate: The default handler for the authenticate signal.
 * @parsed: The default handler for the parsed signal.
 *
 * The class for #GcrParser
 */

/**
 * GCR_DATA_ERROR:
 *
 * A domain for data errors with codes from #GcrDataError
 */

/**
Stef Walter's avatar
Stef Walter committed
88
 * GcrDataError:
Stef Walter's avatar
Stef Walter committed
89
90
91
92
93
94
95
96
 * @GCR_ERROR_FAILURE: Failed to parse or serialize the data
 * @GCR_ERROR_UNRECOGNIZED: The data was unrecognized or unsupported
 * @GCR_ERROR_CANCELLED: The operation was cancelled
 * @GCR_ERROR_LOCKED: The data was encrypted or locked and could not be unlocked.
 *
 * Values responding to error codes for parsing and serializing data.
 */

97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
enum {
	PROP_0,
	PROP_PARSED_LABEL,
	PROP_PARSED_ATTRIBUTES,
	PROP_PARSED_DESCRIPTION
};

enum {
	AUTHENTICATE,
	PARSED,
	LAST_SIGNAL
};

#define SUCCESS 0

static guint signals[LAST_SIGNAL] = { 0 };

114
115
struct _GcrParsed {
	gint refs;
116
	GckBuilder builder;
117
118
119
	GckAttributes *attrs;
	const gchar *description;
	gchar *label;
120
	GBytes *data;
121
	gboolean sensitive;
122
	GcrDataFormat format;
123
	gchar *filename;
124
	struct _GcrParsed *next;
125
};
126

127
128
129
130
struct _GcrParserPrivate {
	GTree *specific_formats;
	gboolean normal_formats;
	GPtrArray *passwords;
131
	GcrParsed *parsed;
132
	gchar *filename;
133
134
};

135
G_DEFINE_TYPE_WITH_PRIVATE (GcrParser, gcr_parser, G_TYPE_OBJECT);
136
137
138
139
140
141
142
143
144
145

typedef struct {
	gint ask_state;
	gint seen;
} PasswordState;

#define PASSWORD_STATE_INIT { 0, 0 }

typedef struct _ParserFormat {
	gint format_id;
146
	gint (*function) (GcrParser *self, GBytes *data);
147
148
149
150
151
152
153
} ParserFormat;

/* Forward declarations */
static const ParserFormat parser_normal[];
static const ParserFormat parser_formats[];
static ParserFormat* parser_format_lookup (gint format_id);

Stef Walter's avatar
Stef Walter committed
154
155
EGG_SECURE_DECLARE (parser);

156
157
158
159
160
161
162
163
164
165
166
167
/* -----------------------------------------------------------------------------
 * QUARK DEFINITIONS
 */

/*
 * PEM STRINGS
 * The xxxxx in: ----- BEGIN xxxxx ------
 */

static GQuark PEM_CERTIFICATE;
static GQuark PEM_RSA_PRIVATE_KEY;
static GQuark PEM_DSA_PRIVATE_KEY;
168
static GQuark PEM_EC_PRIVATE_KEY;
169
170
171
172
173
static GQuark PEM_ANY_PRIVATE_KEY;
static GQuark PEM_ENCRYPTED_PRIVATE_KEY;
static GQuark PEM_PRIVATE_KEY;
static GQuark PEM_PKCS7;
static GQuark PEM_PKCS12;
174
static GQuark PEM_CERTIFICATE_REQUEST;
175
static GQuark PEM_NEW_CERTIFICATE_REQUEST;
176
static GQuark PEM_PUBLIC_KEY;
177

178
179
180
static GQuark ARMOR_PGP_PUBLIC_KEY_BLOCK;
static GQuark ARMOR_PGP_PRIVATE_KEY_BLOCK;

181
182
183
static void
init_quarks (void)
{
184
	static size_t quarks_inited = 0;
185
186
187
188
189
190
191
192
193
194

	if (g_once_init_enter (&quarks_inited)) {

		#define QUARK(name, value) \
			name = g_quark_from_static_string(value)

		QUARK (PEM_CERTIFICATE, "CERTIFICATE");
		QUARK (PEM_PRIVATE_KEY, "PRIVATE KEY");
		QUARK (PEM_RSA_PRIVATE_KEY, "RSA PRIVATE KEY");
		QUARK (PEM_DSA_PRIVATE_KEY, "DSA PRIVATE KEY");
195
		QUARK (PEM_EC_PRIVATE_KEY, "EC PRIVATE KEY");
196
197
198
199
		QUARK (PEM_ANY_PRIVATE_KEY, "ANY PRIVATE KEY");
		QUARK (PEM_ENCRYPTED_PRIVATE_KEY, "ENCRYPTED PRIVATE KEY");
		QUARK (PEM_PKCS7, "PKCS7");
		QUARK (PEM_PKCS12, "PKCS12");
200
		QUARK (PEM_CERTIFICATE_REQUEST, "CERTIFICATE REQUEST");
201
		QUARK (PEM_NEW_CERTIFICATE_REQUEST, "NEW CERTIFICATE REQUEST");
202
		QUARK (PEM_PUBLIC_KEY, "PUBLIC KEY");
203

204
205
		QUARK (ARMOR_PGP_PRIVATE_KEY_BLOCK, "PGP PRIVATE KEY BLOCK");
		QUARK (ARMOR_PGP_PUBLIC_KEY_BLOCK, "PGP PUBLIC KEY BLOCK");
206
207
208
209
210
211
212
213
214
215
216

		#undef QUARK

		g_once_init_leave (&quarks_inited, 1);
	}
}

/* -----------------------------------------------------------------------------
 * INTERNAL
 */

217
218
219
220
221
222
static void
parsed_attribute (GcrParsed *parsed,
                  CK_ATTRIBUTE_TYPE type,
                  gconstpointer data,
                  gsize n_data)
{
223
	g_assert (parsed != NULL);
224
	gck_builder_add_data (&parsed->builder, type, data, n_data);
225
226
}

227
228
229
static void
parsed_attribute_bytes (GcrParsed *parsed,
                        CK_ATTRIBUTE_TYPE type,
230
                        GBytes *data)
231
232
{
	g_assert (parsed != NULL);
233
	gck_builder_add_data (&parsed->builder, type,
234
235
	                      g_bytes_get_data (data, NULL),
	                      g_bytes_get_size (data));
236
237
}

238
static gboolean
239
240
241
242
parsed_asn1_number (GcrParsed *parsed,
                    GNode *asn,
                    const gchar *part,
                    CK_ATTRIBUTE_TYPE type)
243
{
244
	GBytes *value;
245
246

	g_assert (asn);
247
	g_assert (parsed);
248

249
	value = egg_asn1x_get_integer_as_usg (egg_asn1x_node (asn, part, NULL));
250
251
252
	if (value == NULL)
		return FALSE;

253
	parsed_attribute_bytes (parsed, type, value);
254
	g_bytes_unref (value);
255
256
257
	return TRUE;
}

258
259
260
261
262
263
static gboolean
parsed_asn1_element (GcrParsed *parsed,
                     GNode *asn,
                     const gchar *part,
                     CK_ATTRIBUTE_TYPE type)
{
264
	GBytes *value;
265
266
267
268

	g_assert (asn);
	g_assert (parsed);

269
	value = egg_asn1x_get_element_raw (egg_asn1x_node (asn, part, NULL));
270
271
272
	if (value == NULL)
		return FALSE;

273
	parsed_attribute_bytes (parsed, type, value);
274
	g_bytes_unref (value);
275
276
277
	return TRUE;
}

Jakub Jelen's avatar
Jakub Jelen committed
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
static gboolean
parsed_asn1_structure (GcrParsed *parsed,
                      GNode *asn,
                      CK_ATTRIBUTE_TYPE type)
{
	GBytes *value;

	g_assert (asn);
	g_assert (parsed);

	value = egg_asn1x_encode (asn, g_realloc);
	if (value == NULL)
		return FALSE;

	parsed_attribute_bytes (parsed, type, value);
	g_bytes_unref (value);
	return TRUE;
}

297
static void
298
299
300
301
parsed_ulong_attribute (GcrParsed *parsed,
                        CK_ATTRIBUTE_TYPE type,
                        gulong value)
{
302
	g_assert (parsed != NULL);
303
	gck_builder_add_ulong (&parsed->builder, type, value);
304
305
306
307
308
309
310
}

static void
parsed_boolean_attribute (GcrParsed *parsed,
                          CK_ATTRIBUTE_TYPE type,
                          gboolean value)
{
311
	g_assert (parsed != NULL);
312
	gck_builder_add_boolean (&parsed->builder, type, value);
313
314
315
316
317
318
}


static void
parsing_block (GcrParsed *parsed,
               gint format,
319
               GBytes *data)
320
{
321
322
	g_assert (parsed != NULL);
	g_assert (data != NULL);
323
	g_assert (format != 0);
324
	g_assert (parsed->data == NULL);
325

326
	parsed->format = format;
327
	parsed->data = g_bytes_ref (data);
328
329
330
}

static void
331
parsed_description (GcrParsed *parsed,
332
333
                    CK_OBJECT_CLASS klass)
{
334
	g_assert (parsed != NULL);
335
336
	switch (klass) {
	case CKO_PRIVATE_KEY:
337
		parsed->description = _("Private Key");
338
339
		break;
	case CKO_CERTIFICATE:
340
		parsed->description = _("Certificate");
341
342
		break;
	case CKO_PUBLIC_KEY:
343
		parsed->description = _("Public Key");
344
		break;
Stef Walter's avatar
Stef Walter committed
345
346
347
	case CKO_GCR_GNUPG_RECORDS:
		parsed->description = _("PGP Key");
		break;
348
349
350
	case CKO_GCR_CERTIFICATE_REQUEST:
		parsed->description = _("Certificate Request");
		break;
351
	default:
352
		parsed->description = NULL;
353
354
		break;
	}
355
}
356

357
static void
358
parsing_object (GcrParsed *parsed,
359
360
                CK_OBJECT_CLASS klass)
{
361
	g_assert (parsed != NULL);
362

363
	gck_builder_clear (&parsed->builder);
364
	if (parsed->sensitive)
365
		gck_builder_init_full (&parsed->builder, GCK_BUILDER_SECURE_MEMORY);
366
	else
367
368
		gck_builder_init_full (&parsed->builder, GCK_BUILDER_NONE);
	gck_builder_add_ulong (&parsed->builder, CKA_CLASS, klass);
369
	parsed_description (parsed, klass);
370
371
372
}

static void
373
parsed_attributes (GcrParsed *parsed,
374
375
376
377
                   GckAttributes *attrs)
{
	gulong klass;

378
379
	g_assert (parsed != NULL);
	g_assert (attrs != NULL);
380
381

	if (gck_attributes_find_ulong (attrs, CKA_CLASS, &klass))
382
		parsed_description (parsed, klass);
383
	gck_builder_add_all (&parsed->builder, attrs);
384
385
386
}

static void
387
388
parsed_label (GcrParsed *parsed,
              const gchar *label)
389
{
390
391
	g_assert (parsed != NULL);
	g_assert (parsed->label == NULL);
392
	parsed->label = g_strdup (label);
393
394
}

395
static GcrParsed *
396
397
push_parsed (GcrParser *self,
             gboolean sensitive)
398
{
399
	GcrParsed *parsed = g_new0 (GcrParsed, 1);
400
401
	parsed->refs = 0;
	parsed->sensitive = sensitive;
402
	parsed->next = self->pv->parsed;
403
	parsed->filename = g_strdup (gcr_parser_get_filename (self));
404
405
	self->pv->parsed = parsed;
	return parsed;
406
407
}

408
static void
409
_gcr_parsed_free (GcrParsed *parsed)
410
{
411
	gck_builder_clear (&parsed->builder);
412
413
	if (parsed->attrs)
		gck_attributes_unref (parsed->attrs);
414
	if (parsed->data)
415
		g_bytes_unref (parsed->data);
416
	g_free (parsed->label);
417
	g_free (parsed->filename);
418
	g_free (parsed);
419
420
}

421
422
423
424
425
426
427
428
429
static void
pop_parsed (GcrParser *self,
            GcrParsed *parsed)
{
	g_assert (parsed == self->pv->parsed);
	self->pv->parsed = parsed->next;
	_gcr_parsed_free (parsed);
}

430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
static gint
enum_next_password (GcrParser *self, PasswordState *state, const gchar **password)
{
	gboolean result;

	/*
	 * Next passes we look through all the passwords that the parser
	 * has seen so far. This is because different parts of a encrypted
	 * container (such as PKCS#12) often use the same password even
	 * if with different algorithms.
	 *
	 * If we didn't do this and the user chooses enters a password,
	 * but doesn't save it, they would get prompted for the same thing
	 * over and over, dumb.
	 */

	/* Look in our list of passwords */
	if (state->seen < self->pv->passwords->len) {
		g_assert (state->seen >= 0);
		*password = g_ptr_array_index (self->pv->passwords, state->seen);
		++state->seen;
		return SUCCESS;
	}

	/* Fire off all the parsed property signals so anyone watching can update their state */
	g_object_notify (G_OBJECT (self), "parsed-description");
	g_object_notify (G_OBJECT (self), "parsed-attributes");
	g_object_notify (G_OBJECT (self), "parsed-label");

	g_signal_emit (self, signals[AUTHENTICATE], 0, state->ask_state, &result);
	++state->ask_state;

	if (!result)
463
		return GCR_ERROR_CANCELLED;
464
465
466
467
468
469
470
471
472

	/* Return any passwords added */
	if (state->seen < self->pv->passwords->len) {
		g_assert (state->seen >= 0);
		*password = g_ptr_array_index (self->pv->passwords, state->seen);
		++state->seen;
		return SUCCESS;
	}

473
	return GCR_ERROR_LOCKED;
474
475
476
}

static void
477
478
parsed_fire (GcrParser *self,
             GcrParsed *parsed)
479
{
480
	g_assert (GCR_IS_PARSER (self));
Stef Walter's avatar
Stef Walter committed
481
	g_assert (parsed != NULL);
482
	g_assert (parsed == self->pv->parsed);
483
484
	g_assert (parsed->attrs == NULL);

485
	parsed->attrs = gck_builder_end (&parsed->builder);
486

487
488
489
490
491
492
493
494
495
496
497
498
	g_object_notify (G_OBJECT (self), "parsed-description");
	g_object_notify (G_OBJECT (self), "parsed-attributes");
	g_object_notify (G_OBJECT (self), "parsed-label");

	g_signal_emit (self, signals[PARSED], 0);
}

/* -----------------------------------------------------------------------------
 * RSA PRIVATE KEY
 */

static gint
499
parse_der_private_key_rsa (GcrParser *self,
500
                           GBytes *data)
501
{
502
	gint res = GCR_ERROR_UNRECOGNIZED;
503
504
	GNode *asn = NULL;
	gulong version;
505
506
	GcrParsed *parsed;

507
	parsed = push_parsed (self, TRUE);
508

509
	asn = egg_asn1x_create_and_decode (pk_asn1_tab, "RSAPrivateKey", data);
510
511
512
	if (!asn)
		goto done;

513
	parsing_block (parsed, GCR_FORMAT_DER_PRIVATE_KEY_RSA, data);
514
515
516
	parsing_object (parsed, CKO_PRIVATE_KEY);
	parsed_ulong_attribute (parsed, CKA_KEY_TYPE, CKK_RSA);
	parsed_boolean_attribute (parsed, CKA_PRIVATE, CK_TRUE);
517
	res = GCR_ERROR_FAILURE;
518

519
	if (!egg_asn1x_get_integer_as_ulong (egg_asn1x_node (asn, "version", NULL), &version))
520
521
522
523
		goto done;

	/* We only support simple version */
	if (version != 0) {
524
		res = GCR_ERROR_UNRECOGNIZED;
525
		g_message ("unsupported version of RSA key: %lu", version);
526
527
528
		goto done;
	}

529
530
531
532
533
534
	if (!parsed_asn1_number (parsed, asn, "modulus", CKA_MODULUS) ||
	    !parsed_asn1_number (parsed, asn, "publicExponent", CKA_PUBLIC_EXPONENT) ||
	    !parsed_asn1_number (parsed, asn, "privateExponent", CKA_PRIVATE_EXPONENT) ||
	    !parsed_asn1_number (parsed, asn, "prime1", CKA_PRIME_1) ||
	    !parsed_asn1_number (parsed, asn, "prime2", CKA_PRIME_2) ||
	    !parsed_asn1_number (parsed, asn, "coefficient", CKA_COEFFICIENT))
535
536
		goto done;

537
	parsed_fire (self, parsed);
538
539
540
	res = SUCCESS;

done:
541
	egg_asn1x_destroy (asn);
542
	if (res == GCR_ERROR_FAILURE)
543
544
		g_message ("invalid RSA key");

545
	pop_parsed (self, parsed);
546
547
548
549
550
551
552
553
	return res;
}

/* -----------------------------------------------------------------------------
 * DSA PRIVATE KEY
 */

static gint
554
parse_der_private_key_dsa (GcrParser *self,
555
                           GBytes *data)
556
{
557
	gint ret = GCR_ERROR_UNRECOGNIZED;
558
	GNode *asn = NULL;
559
560
	GcrParsed *parsed;

561
	parsed = push_parsed (self, TRUE);
562

563
	asn = egg_asn1x_create_and_decode (pk_asn1_tab, "DSAPrivateKey", data);
564
565
566
	if (!asn)
		goto done;

567
	parsing_block (parsed, GCR_FORMAT_DER_PRIVATE_KEY_DSA, data);
568
569
570
	parsing_object (parsed, CKO_PRIVATE_KEY);
	parsed_ulong_attribute (parsed, CKA_KEY_TYPE, CKK_DSA);
	parsed_boolean_attribute (parsed, CKA_PRIVATE, CK_TRUE);
571
	ret = GCR_ERROR_FAILURE;
572

573
574
575
576
	if (!parsed_asn1_number (parsed, asn, "p", CKA_PRIME) ||
	    !parsed_asn1_number (parsed, asn, "q", CKA_SUBPRIME) ||
	    !parsed_asn1_number (parsed, asn, "g", CKA_BASE) ||
	    !parsed_asn1_number (parsed, asn, "priv", CKA_VALUE))
577
578
		goto done;

579
	parsed_fire (self, parsed);
580
581
582
	ret = SUCCESS;

done:
583
	egg_asn1x_destroy (asn);
584
	if (ret == GCR_ERROR_FAILURE)
585
586
		g_message ("invalid DSA key");

587
	pop_parsed (self, parsed);
588
589
590
591
	return ret;
}

static gint
592
parse_der_private_key_dsa_parts (GcrParser *self,
593
                                 GBytes *keydata,
594
                                 GNode *params)
595
{
596
	gint ret = GCR_ERROR_UNRECOGNIZED;
597
598
	GNode *asn_params = NULL;
	GNode *asn_key = NULL;
599
600
	GcrParsed *parsed;

601
	parsed = push_parsed (self, TRUE);
602

603
	asn_params = egg_asn1x_get_any_as (params, pk_asn1_tab, "DSAParameters");
604
	asn_key = egg_asn1x_create_and_decode (pk_asn1_tab, "DSAPrivatePart", keydata);
605
606
607
	if (!asn_params || !asn_key)
		goto done;

608
609
610
	parsing_object (parsed, CKO_PRIVATE_KEY);
	parsed_ulong_attribute (parsed, CKA_KEY_TYPE, CKK_DSA);
	parsed_boolean_attribute (parsed, CKA_PRIVATE, CK_TRUE);
611
	ret = GCR_ERROR_FAILURE;
612

613
614
615
616
	if (!parsed_asn1_number (parsed, asn_params, "p", CKA_PRIME) ||
	    !parsed_asn1_number (parsed, asn_params, "q", CKA_SUBPRIME) ||
	    !parsed_asn1_number (parsed, asn_params, "g", CKA_BASE) ||
	    !parsed_asn1_number (parsed, asn_key, NULL, CKA_VALUE))
617
618
		goto done;

619
	parsed_fire (self, parsed);
620
621
622
	ret = SUCCESS;

done:
623
624
	egg_asn1x_destroy (asn_key);
	egg_asn1x_destroy (asn_params);
625
	if (ret == GCR_ERROR_FAILURE)
626
627
		g_message ("invalid DSA key");

628
	pop_parsed (self, parsed);
629
630
	return ret;
}
631
632
633
634
635
636
637
638
639
640
641
642
/* -----------------------------------------------------------------------------
 * EC PRIVATE KEY
 */

static gint
parse_der_private_key_ec (GcrParser *self,
                          GBytes *data)
{
	gint ret = GCR_ERROR_UNRECOGNIZED;
	GNode *asn = NULL;
	GBytes *value = NULL;
	GBytes *pub = NULL;
Jakub Jelen's avatar
Jakub Jelen committed
643
	GNode *asn_q = NULL;
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
	GcrParsed *parsed;
	guint bits;
	gulong version;

	parsed = push_parsed (self, TRUE);

	asn = egg_asn1x_create_and_decode (pk_asn1_tab, "ECPrivateKey", data);
	if (!asn)
		goto done;

	if (!egg_asn1x_get_integer_as_ulong (egg_asn1x_node (asn, "version", NULL), &version))
		goto done;

	/* We only support simple version */
	if (version != 1) {
		g_message ("unsupported version of EC key: %lu", version);
		goto done;
	}

	parsing_block (parsed, GCR_FORMAT_DER_PRIVATE_KEY_EC, data);
	parsing_object (parsed, CKO_PRIVATE_KEY);
	parsed_ulong_attribute (parsed, CKA_KEY_TYPE, CKK_EC);
	parsed_boolean_attribute (parsed, CKA_PRIVATE, CK_TRUE);
	ret = GCR_ERROR_FAILURE;

	if (!parsed_asn1_element (parsed, asn, "parameters", CKA_EC_PARAMS))
		goto done;

	value = egg_asn1x_get_string_as_usg (egg_asn1x_node (asn, "privateKey", NULL), egg_secure_realloc);
	if (!value)
		goto done;

	parsed_attribute_bytes (parsed, CKA_VALUE, value);

	pub = egg_asn1x_get_bits_as_raw (egg_asn1x_node (asn, "publicKey", NULL), &bits);
Jakub Jelen's avatar
Jakub Jelen committed
679
680
681
682
683
684
685
686
687
688
	if (!pub || bits != 8 * g_bytes_get_size (pub))
		goto done;
	asn_q = egg_asn1x_create (pk_asn1_tab, "ECPoint");
	if (!asn_q)
		goto done;
	egg_asn1x_set_string_as_bytes (asn_q, pub);

	if (!parsed_asn1_structure (parsed, asn_q, CKA_EC_POINT))
		goto done;

689
690
691
692
693
694
695
696
697
	parsed_fire (self, parsed);
	ret = SUCCESS;

done:
	if (pub)
		g_bytes_unref (pub);
	if (value)
		g_bytes_unref (value);
	egg_asn1x_destroy (asn);
Jakub Jelen's avatar
Jakub Jelen committed
698
	egg_asn1x_destroy (asn_q);
699
700
701
702
703
704
	if (ret == GCR_ERROR_FAILURE)
		g_message ("invalid EC key");

	pop_parsed (self, parsed);
	return ret;
}
705
706
707
708
709
710

/* -----------------------------------------------------------------------------
 * PRIVATE KEY
 */

static gint
711
parse_der_private_key (GcrParser *self,
712
                       GBytes *data)
713
714
715
{
	gint res;

716
	res = parse_der_private_key_rsa (self, data);
717
	if (res == GCR_ERROR_UNRECOGNIZED)
718
		res = parse_der_private_key_dsa (self, data);
719
720
	if (res == GCR_ERROR_UNRECOGNIZED)
		res = parse_der_private_key_ec (self, data);
721
722
723
724

	return res;
}

725
726
727
728
729
730
731
/* -----------------------------------------------------------------------------
 * SUBJECT PUBLIC KEY
 */

static gint
handle_subject_public_key_rsa (GcrParser *self,
                               GcrParsed *parsed,
732
                               GBytes *key,
733
                               GNode *params)
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
{
	gint res = GCR_ERROR_FAILURE;
	GNode *asn = NULL;

	asn = egg_asn1x_create_and_decode (pk_asn1_tab, "RSAPublicKey", key);
	if (!asn)
		goto done;

	parsing_object (parsed, CKO_PUBLIC_KEY);
	parsed_ulong_attribute (parsed, CKA_KEY_TYPE, CKK_RSA);

	if (!parsed_asn1_number (parsed, asn, "modulus", CKA_MODULUS) ||
	    !parsed_asn1_number (parsed, asn, "publicExponent", CKA_PUBLIC_EXPONENT))
		goto done;

	res = SUCCESS;

done:
	egg_asn1x_destroy (asn);
	return res;
}

static gint
handle_subject_public_key_dsa (GcrParser *self,
                               GcrParsed *parsed,
759
                               GBytes *key,
760
                               GNode *params)
761
762
763
764
765
766
{
	gint res = GCR_ERROR_FAILURE;
	GNode *key_asn = NULL;
	GNode *param_asn = NULL;

	key_asn = egg_asn1x_create_and_decode (pk_asn1_tab, "DSAPublicPart", key);
767
	param_asn = egg_asn1x_get_any_as (params, pk_asn1_tab, "DSAParameters");
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788

	if (!key_asn || !param_asn)
		goto done;

	parsing_object (parsed, CKO_PUBLIC_KEY);
	parsed_ulong_attribute (parsed, CKA_KEY_TYPE, CKK_DSA);

	if (!parsed_asn1_number (parsed, param_asn, "p", CKA_PRIME) ||
	    !parsed_asn1_number (parsed, param_asn, "q", CKA_SUBPRIME) ||
	    !parsed_asn1_number (parsed, param_asn, "g", CKA_BASE) ||
	    !parsed_asn1_number (parsed, key_asn, NULL, CKA_VALUE))
		goto done;

	res = SUCCESS;

done:
	egg_asn1x_destroy (key_asn);
	egg_asn1x_destroy (param_asn);
	return res;
}

789
790
791
792
793
794
static gint
handle_subject_public_key_ec (GcrParser *self,
                              GcrParsed *parsed,
                              GBytes *key,
                              GNode *params)
{
Jakub Jelen's avatar
Jakub Jelen committed
795
796
797
	gint ret = GCR_ERROR_FAILURE;
	GBytes *bytes = NULL;
	GNode *asn = NULL;
798
799
800
801
802
803
804
805

	parsing_object (parsed, CKO_PUBLIC_KEY);
	parsed_ulong_attribute (parsed, CKA_KEY_TYPE, CKK_EC);

	bytes = egg_asn1x_encode (params, g_realloc);
	parsed_attribute_bytes (parsed, CKA_EC_PARAMS, bytes);
	g_bytes_unref (bytes);

Jakub Jelen's avatar
Jakub Jelen committed
806
807
808
809
810
811
812
813
814
	asn = egg_asn1x_create (pk_asn1_tab, "ECPoint");
	if (!asn)
		goto done;
	egg_asn1x_set_string_as_bytes (asn, key);
	parsed_asn1_structure (parsed, asn, CKA_EC_POINT);
	ret = SUCCESS;
done:
	egg_asn1x_destroy (asn);
	return ret;
815
816
}

817
818
static gint
parse_der_subject_public_key (GcrParser *self,
819
                              GBytes *data)
820
821
{
	GcrParsed *parsed;
822
	GNode *params;
823
	GBytes *key;
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
	GNode *asn = NULL;
	GNode *node;
	GQuark oid;
	guint bits;
	gint ret;

	asn = egg_asn1x_create_and_decode (pkix_asn1_tab, "SubjectPublicKeyInfo", data);
	if (asn == NULL)
		return GCR_ERROR_UNRECOGNIZED;

	parsed = push_parsed (self, TRUE);
	parsing_block (parsed, GCR_FORMAT_DER_SUBJECT_PUBLIC_KEY, data);

	node = egg_asn1x_node (asn, "algorithm", "algorithm", NULL);
	oid = egg_asn1x_get_oid_as_quark (node);

840
	params = egg_asn1x_node (asn, "algorithm", "parameters", NULL);
841
842
843
844
845
846
847
848
849
850

	node = egg_asn1x_node (asn, "subjectPublicKey", NULL);
	key = egg_asn1x_get_bits_as_raw (node, &bits);

	if (oid == GCR_OID_PKIX1_RSA)
		ret = handle_subject_public_key_rsa (self, parsed, key, params);

	else if (oid == GCR_OID_PKIX1_DSA)
		ret = handle_subject_public_key_dsa (self, parsed, key, params);

851
852
853
	else if (oid == GCR_OID_PKIX1_EC)
		ret = handle_subject_public_key_ec (self, parsed, key, params);

854
855
856
	else
		ret = GCR_ERROR_UNRECOGNIZED;

857
	g_bytes_unref (key);
858
859
860
861
862
863
864
865
866
867

	if (ret == SUCCESS)
		parsed_fire (self, parsed);

	pop_parsed (self, parsed);

	egg_asn1x_destroy (asn);
	return ret;
}

868
869
870
871
872
/* -----------------------------------------------------------------------------
 * PKCS8
 */

static gint
873
parse_der_pkcs8_plain (GcrParser *self,
874
                       GBytes *data)
875
876
877
878
{
	gint ret;
	CK_KEY_TYPE key_type;
	GQuark key_algo;
879
	GBytes *keydata = NULL;
880
	GNode *params = NULL;
881
	GNode *asn = NULL;
882
	GcrParsed *parsed;
883

884
	parsed = push_parsed (self, TRUE);
885
	ret = GCR_ERROR_UNRECOGNIZED;
886

887
	asn = egg_asn1x_create_and_decode (pkix_asn1_tab, "pkcs-8-PrivateKeyInfo", data);
888
889
890
	if (!asn)
		goto done;

891
	parsing_block (parsed, GCR_FORMAT_DER_PKCS8_PLAIN, data);
892
	ret = GCR_ERROR_FAILURE;
893
	key_type = GCK_INVALID;
894

895
	key_algo = egg_asn1x_get_oid_as_quark (egg_asn1x_node (asn, "privateKeyAlgorithm", "algorithm", NULL));
896
897
898
899
900
901
	if (!key_algo)
		goto done;
	else if (key_algo == GCR_OID_PKIX1_RSA)
		key_type = CKK_RSA;
	else if (key_algo == GCR_OID_PKIX1_DSA)
		key_type = CKK_DSA;
902
903
	else if (key_algo == GCR_OID_PKIX1_EC)
		key_type = CKK_EC;
904

905
	if (key_type == GCK_INVALID) {
906
  		ret = GCR_ERROR_UNRECOGNIZED;
907
908
909
  		goto done;
  	}

910
	keydata = egg_asn1x_get_string_as_bytes (egg_asn1x_node (asn, "privateKey", NULL));
911
912
913
	if (!keydata)
		goto done;

914
	params = egg_asn1x_node (asn, "privateKeyAlgorithm", "parameters", NULL);
915
916
917
918
919
920
921

	ret = SUCCESS;

done:
	if (ret == SUCCESS) {
		switch (key_type) {
		case CKK_RSA:
922
			ret = parse_der_private_key_rsa (self, keydata);
923
924
925
			break;
		case CKK_DSA:
			/* Try the normal sane format */
926
			ret = parse_der_private_key_dsa (self, keydata);
927
928

			/* Otherwise try the two part format that everyone seems to like */
929
930
			if (ret == GCR_ERROR_UNRECOGNIZED && params)
				ret = parse_der_private_key_dsa_parts (self, keydata, params);
931
			break;
932
933
934
935
		case CKK_EC:
			ret = parse_der_private_key_ec (self, keydata);
			break;

936
937
		default:
			g_message ("invalid or unsupported key type in PKCS#8 key");
938
			ret = GCR_ERROR_UNRECOGNIZED;
939
940
941
			break;
		};

942
	} else if (ret == GCR_ERROR_FAILURE) {
943
944
945
		g_message ("invalid PKCS#8 key");
	}

946
	if (keydata)
947
		g_bytes_unref (keydata);
948
	egg_asn1x_destroy (asn);
949
	pop_parsed (self, parsed);
950
951
952
953
	return ret;
}

static gint
954
parse_der_pkcs8_encrypted (GcrParser *self,
955
                           GBytes *data)
956
957
{
	PasswordState pstate = PASSWORD_STATE_INIT;
958
	GNode *asn = NULL;
959
960
961
962
963
	gcry_cipher_hd_t cih = NULL;
	gcry_error_t gcry;
	gint ret, r;
	GQuark scheme;
	guchar *crypted = NULL;
964
	GNode *params = NULL;
965
	GBytes *cbytes;
966
	gsize n_crypted;
967
	const gchar *password;
968
	GcrParsed *parsed;
969
	gint l;
970

971
	parsed = push_parsed (self, FALSE);
972
	ret = GCR_ERROR_UNRECOGNIZED;
973

974
	asn = egg_asn1x_create_and_decode (pkix_asn1_tab, "pkcs-8-EncryptedPrivateKeyInfo", data);
975
976
977
	if (!asn)
		goto done;

978
	parsing_block (parsed, GCR_FORMAT_DER_PKCS8_ENCRYPTED, data);
979
	ret = GCR_ERROR_FAILURE;
980
981

	/* Figure out the type of encryption */
982
	scheme = egg_asn1x_get_oid_as_quark (egg_asn1x_node (asn, "encryptionAlgorithm", "algorithm", NULL));
983
984
985
	if (!scheme)
		goto done;

986
	params = egg_asn1x_node (asn, "encryptionAlgorithm", "parameters", NULL);
987
988
989
990
991
992
993
994
995
996
997
998
999

	/* Loop to try different passwords */
	for (;;) {

		g_assert (cih == NULL);

		r = enum_next_password (self, &pstate, &password);
		if (r != SUCCESS) {
			ret = r;
			break;
		}

		/* Parse the encryption stuff into a cipher. */
1000
		if (!egg_symkey_read_cipher (scheme, password, -1, params, &cih))