Line data Source code
1 : /* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */
2 : /* gkm-data-der.c - parsing and serializing of common crypto DER structures
3 :
4 : Copyright (C) 2007 Stefan Walter
5 :
6 : The Gnome Keyring Library is free software; you can redistribute it and/or
7 : modify it under the terms of the GNU Library General Public License as
8 : published by the Free Software Foundation; either version 2 of the
9 : License, or (at your option) any later version.
10 :
11 : The Gnome Keyring Library is distributed in the hope that it will be useful,
12 : but WITHOUT ANY WARRANTY; without even the implied warranty of
13 : MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 : Library General Public License for more details.
15 :
16 : You should have received a copy of the GNU Library General Public
17 : License along with the Gnome Library; see the file COPYING.LIB. If not,
18 : <http://www.gnu.org/licenses/>.
19 :
20 : Author: Stef Walter <stef@memberwebs.com>
21 : */
22 :
23 : #include "config.h"
24 :
25 : #include "gkm-data-asn1.h"
26 : #include "gkm-data-der.h"
27 : #include "gkm-data-types.h"
28 : #include "gkm-sexp.h"
29 :
30 : #include "egg/egg-asn1x.h"
31 : #include "egg/egg-asn1-defs.h"
32 : #include "egg/egg-secure-memory.h"
33 : #include "egg/egg-symkey.h"
34 :
35 : #include <glib.h>
36 : #include <gcrypt.h>
37 :
38 77 : EGG_SECURE_DECLARE (data_der);
39 :
40 : /* -----------------------------------------------------------------------------
41 : * QUARKS
42 : */
43 :
44 : static GQuark OID_PKIX1_RSA;
45 : static GQuark OID_PKIX1_DSA;
46 : static GQuark OID_PKIX1_ECDSA;
47 : static GQuark OID_PKCS12_PBE_3DES_SHA1;
48 : static GQuark OID_ANSI_SECP256R1;
49 : static GQuark OID_ANSI_SECP384R1;
50 : static GQuark OID_ANSI_SECP521R1;
51 :
52 : static void
53 263 : init_quarks (void)
54 : {
55 : static gsize quarks_inited = 0;
56 :
57 263 : if (g_once_init_enter (&quarks_inited)) {
58 :
59 : #define QUARK(name, value) \
60 : name = g_quark_from_static_string(value)
61 :
62 11 : QUARK (OID_PKIX1_RSA, "1.2.840.113549.1.1.1");
63 11 : QUARK (OID_PKIX1_DSA, "1.2.840.10040.4.1");
64 11 : QUARK (OID_PKIX1_ECDSA, "1.2.840.10045.2.1");
65 11 : QUARK (OID_PKCS12_PBE_3DES_SHA1, "1.2.840.113549.1.12.1.3");
66 11 : QUARK (OID_ANSI_SECP256R1, "1.2.840.10045.3.1.7");
67 11 : QUARK (OID_ANSI_SECP384R1, "1.3.132.0.34");
68 11 : QUARK (OID_ANSI_SECP521R1, "1.3.132.0.35");
69 :
70 : #undef QUARK
71 :
72 11 : g_once_init_leave (&quarks_inited, 1);
73 : }
74 263 : }
75 :
76 : const gchar *
77 11 : gkm_data_der_oid_to_curve (GQuark oid)
78 : {
79 11 : if (oid == OID_ANSI_SECP256R1)
80 7 : return "NIST P-256";
81 4 : else if (oid == OID_ANSI_SECP384R1)
82 2 : return "NIST P-384";
83 2 : else if (oid == OID_ANSI_SECP521R1)
84 2 : return "NIST P-521";
85 0 : return NULL;
86 : }
87 :
88 : /*
89 : * Convert ecc->curve values from libgcrypt representation to internal one.
90 : * Ignore duplicates and alternative names, since S-expressions are created
91 : * only by us throught this code.
92 : */
93 : static GQuark
94 5 : gkm_data_der_curve_to_oid (const gchar *curve)
95 : {
96 5 : if (g_str_equal (curve, "NIST P-256"))
97 3 : return OID_ANSI_SECP256R1;
98 2 : else if (g_str_equal (curve, "NIST P-384"))
99 1 : return OID_ANSI_SECP384R1;
100 1 : else if (g_str_equal (curve, "NIST P-521"))
101 1 : return OID_ANSI_SECP521R1;
102 0 : return 0;
103 : }
104 :
105 :
106 : GQuark
107 1 : gkm_data_der_oid_from_ec_params (GBytes *params)
108 : {
109 : GNode *asn;
110 : GQuark oid;
111 :
112 1 : init_quarks ();
113 :
114 1 : asn = egg_asn1x_create_and_decode (pk_asn1_tab, "Parameters", params);
115 1 : if (!asn)
116 0 : return 0;
117 :
118 1 : oid = egg_asn1x_get_oid_as_quark (egg_asn1x_node (asn, "namedCurve", NULL));
119 :
120 1 : egg_asn1x_destroy (asn);
121 1 : return oid;
122 : }
123 :
124 : GBytes *
125 1 : gkm_data_der_get_ec_params (GQuark oid)
126 : {
127 : GNode *asn;
128 1 : GBytes *params = NULL;
129 : GNode *named_curve;
130 :
131 1 : asn = egg_asn1x_create (pk_asn1_tab, "Parameters");
132 1 : if (!asn)
133 0 : goto done;
134 :
135 1 : named_curve = egg_asn1x_node (asn, "namedCurve", NULL);
136 :
137 1 : if (!egg_asn1x_set_oid_as_quark (named_curve, oid))
138 0 : goto done;
139 :
140 1 : if (!egg_asn1x_set_choice (asn, named_curve))
141 0 : goto done;
142 :
143 1 : params = egg_asn1x_encode (asn, NULL);
144 :
145 1 : done:
146 1 : egg_asn1x_destroy (asn);
147 1 : return params;
148 : }
149 :
150 : /* wrapper so we do not have to export the GQuark magic */
151 : GBytes *
152 1 : gkm_data_der_curve_to_ec_params (const gchar *curve_name)
153 : {
154 : GQuark oid;
155 :
156 1 : init_quarks ();
157 :
158 1 : oid = gkm_data_der_curve_to_oid (curve_name);
159 1 : if (oid == 0)
160 0 : return NULL;
161 :
162 1 : return gkm_data_der_get_ec_params (oid);
163 : }
164 :
165 : GBytes *
166 1 : gkm_data_der_encode_ecdsa_q_str (const guchar *data, gsize data_len)
167 : {
168 1 : GNode *asn = NULL;
169 1 : GBytes *bytes, *result = NULL;
170 :
171 1 : asn = egg_asn1x_create (pk_asn1_tab, "ECKeyQ");
172 1 : g_return_val_if_fail (asn, FALSE);
173 :
174 1 : bytes = g_bytes_new_static (data, data_len);
175 :
176 : /* "consumes" bytes */
177 1 : if (!gkm_data_asn1_write_string (asn, bytes))
178 0 : goto done;
179 :
180 1 : result = egg_asn1x_encode (asn, g_realloc);
181 1 : if (result == NULL)
182 0 : g_warning ("couldn't encode Q into the PKCS#11 structure: %s", egg_asn1x_message (asn));
183 1 : done:
184 1 : egg_asn1x_destroy (asn);
185 1 : return result;
186 : }
187 :
188 : gboolean
189 1 : gkm_data_der_encode_ecdsa_q (gcry_mpi_t q, GBytes **result)
190 : {
191 : gcry_error_t gcry;
192 : guchar data[1024];
193 1 : gsize data_len = 1024;
194 1 : gboolean rv = TRUE;
195 :
196 1 : g_assert (q);
197 1 : g_assert (result);
198 :
199 1 : gcry = gcry_mpi_print (GCRYMPI_FMT_USG, data, data_len, &data_len, q);
200 1 : g_return_val_if_fail (gcry == 0, FALSE);
201 :
202 1 : *result = gkm_data_der_encode_ecdsa_q_str (data, data_len);
203 1 : if (*result == NULL)
204 0 : rv = FALSE;
205 :
206 1 : return rv;
207 : }
208 :
209 : gboolean
210 1 : gkm_data_der_decode_ecdsa_q (GBytes *data, GBytes **result)
211 : {
212 1 : GNode *asn = NULL;
213 1 : gboolean rv = TRUE;
214 :
215 1 : g_assert (data);
216 1 : g_assert (result);
217 :
218 1 : asn = egg_asn1x_create_and_decode (pk_asn1_tab, "ECKeyQ", data);
219 : /* workaround a bug in gcr (not DER encoding the MPI) */
220 1 : if (!asn) {
221 0 : *result = data;
222 0 : return rv;
223 : }
224 :
225 1 : rv = gkm_data_asn1_read_string (asn, result);
226 :
227 1 : egg_asn1x_destroy (asn);
228 1 : return rv;
229 : }
230 :
231 : /* -----------------------------------------------------------------------------
232 : * KEY PARSING
233 : */
234 :
235 : #define SEXP_PUBLIC_RSA \
236 : "(public-key" \
237 : " (rsa" \
238 : " (n %m)" \
239 : " (e %m)))"
240 :
241 : GkmDataResult
242 180 : gkm_data_der_read_public_key_rsa (GBytes *data,
243 : gcry_sexp_t *s_key)
244 : {
245 180 : GkmDataResult ret = GKM_DATA_UNRECOGNIZED;
246 180 : GNode *asn = NULL;
247 : gcry_mpi_t n, e;
248 : int res;
249 :
250 180 : n = e = NULL;
251 :
252 180 : asn = egg_asn1x_create_and_decode (pk_asn1_tab, "RSAPublicKey", data);
253 180 : if (!asn)
254 2 : goto done;
255 :
256 178 : ret = GKM_DATA_FAILURE;
257 :
258 356 : if (!gkm_data_asn1_read_mpi (egg_asn1x_node (asn, "modulus", NULL), &n) ||
259 178 : !gkm_data_asn1_read_mpi (egg_asn1x_node (asn, "publicExponent", NULL), &e))
260 0 : goto done;
261 :
262 178 : res = gcry_sexp_build (s_key, NULL, SEXP_PUBLIC_RSA, n, e);
263 178 : if (res)
264 0 : goto done;
265 :
266 178 : g_assert (*s_key);
267 178 : ret = GKM_DATA_SUCCESS;
268 :
269 180 : done:
270 180 : egg_asn1x_destroy (asn);
271 180 : gcry_mpi_release (n);
272 180 : gcry_mpi_release (e);
273 :
274 180 : if (ret == GKM_DATA_FAILURE)
275 0 : g_message ("invalid RSA public key");
276 :
277 180 : return ret;
278 : }
279 :
280 : #define SEXP_PRIVATE_RSA \
281 : "(private-key" \
282 : " (rsa" \
283 : " (n %m)" \
284 : " (e %m)" \
285 : " (d %m)" \
286 : " (p %m)" \
287 : " (q %m)" \
288 : " (u %m)))"
289 :
290 : GkmDataResult
291 39 : gkm_data_der_read_private_key_rsa (GBytes *data,
292 : gcry_sexp_t *s_key)
293 : {
294 39 : GkmDataResult ret = GKM_DATA_UNRECOGNIZED;
295 : gcry_mpi_t n, e, d, p, q, u;
296 : gcry_mpi_t tmp;
297 : gulong version;
298 39 : GNode *asn = NULL;
299 : int res;
300 :
301 39 : n = e = d = p = q = u = NULL;
302 :
303 39 : asn = egg_asn1x_create_and_decode (pk_asn1_tab, "RSAPrivateKey", data);
304 39 : if (!asn)
305 18 : goto done;
306 :
307 21 : ret = GKM_DATA_FAILURE;
308 :
309 21 : if (!egg_asn1x_get_integer_as_ulong (egg_asn1x_node (asn, "version", NULL), &version))
310 0 : goto done;
311 :
312 : /* We only support simple version */
313 21 : if (version != 0) {
314 0 : ret = GKM_DATA_UNRECOGNIZED;
315 0 : g_message ("unsupported version of RSA key: %lu", version);
316 0 : goto done;
317 : }
318 :
319 42 : if (!gkm_data_asn1_read_mpi (egg_asn1x_node (asn, "modulus", NULL), &n) ||
320 42 : !gkm_data_asn1_read_mpi (egg_asn1x_node (asn, "publicExponent", NULL), &e) ||
321 42 : !gkm_data_asn1_read_mpi (egg_asn1x_node (asn, "privateExponent", NULL), &d) ||
322 42 : !gkm_data_asn1_read_mpi (egg_asn1x_node (asn, "prime1", NULL), &p) ||
323 42 : !gkm_data_asn1_read_mpi (egg_asn1x_node (asn, "prime2", NULL), &q) ||
324 21 : !gkm_data_asn1_read_mpi (egg_asn1x_node (asn, "coefficient", NULL), &u))
325 0 : goto done;
326 :
327 : /* Fix up the incoming key so gcrypt likes it */
328 21 : if (gcry_mpi_cmp (p, q) > 0) {
329 : /* P shall be smaller then Q! Swap primes. iqmp becomes u. */
330 16 : tmp = p;
331 16 : p = q;
332 16 : q = tmp;
333 : } else {
334 : /* U needs to be recomputed. */
335 5 : gcry_mpi_invm (u, p, q);
336 : }
337 :
338 21 : res = gcry_sexp_build (s_key, NULL, SEXP_PRIVATE_RSA, n, e, d, p, q, u);
339 21 : if (res)
340 0 : goto done;
341 :
342 21 : g_assert (*s_key);
343 21 : ret = GKM_DATA_SUCCESS;
344 :
345 39 : done:
346 39 : egg_asn1x_destroy (asn);
347 39 : gcry_mpi_release (n);
348 39 : gcry_mpi_release (e);
349 39 : gcry_mpi_release (d);
350 39 : gcry_mpi_release (p);
351 39 : gcry_mpi_release (q);
352 39 : gcry_mpi_release (u);
353 :
354 39 : if (ret == GKM_DATA_FAILURE)
355 0 : g_message ("invalid RSA key");
356 :
357 39 : return ret;
358 : }
359 :
360 : #define SEXP_PUBLIC_DSA \
361 : "(public-key" \
362 : " (dsa" \
363 : " (p %m)" \
364 : " (q %m)" \
365 : " (g %m)" \
366 : " (y %m)))"
367 :
368 : GkmDataResult
369 1 : gkm_data_der_read_public_key_dsa (GBytes *data,
370 : gcry_sexp_t *s_key)
371 : {
372 1 : GkmDataResult ret = GKM_DATA_UNRECOGNIZED;
373 1 : GNode *asn = NULL;
374 : gcry_mpi_t p, q, g, y;
375 : int res;
376 :
377 1 : p = q = g = y = NULL;
378 :
379 1 : asn = egg_asn1x_create_and_decode (pk_asn1_tab, "DSAPublicKey", data);
380 1 : if (!asn)
381 0 : goto done;
382 :
383 1 : ret = GKM_DATA_FAILURE;
384 :
385 2 : if (!gkm_data_asn1_read_mpi (egg_asn1x_node (asn, "p", NULL), &p) ||
386 2 : !gkm_data_asn1_read_mpi (egg_asn1x_node (asn, "q", NULL), &q) ||
387 2 : !gkm_data_asn1_read_mpi (egg_asn1x_node (asn, "g", NULL), &g) ||
388 1 : !gkm_data_asn1_read_mpi (egg_asn1x_node (asn, "Y", NULL), &y))
389 0 : goto done;
390 :
391 1 : res = gcry_sexp_build (s_key, NULL, SEXP_PUBLIC_DSA, p, q, g, y);
392 1 : if (res)
393 0 : goto done;
394 :
395 1 : g_assert (*s_key);
396 1 : ret = GKM_DATA_SUCCESS;
397 :
398 1 : done:
399 1 : egg_asn1x_destroy (asn);
400 1 : gcry_mpi_release (p);
401 1 : gcry_mpi_release (q);
402 1 : gcry_mpi_release (g);
403 1 : gcry_mpi_release (y);
404 :
405 1 : if (ret == GKM_DATA_FAILURE)
406 0 : g_message ("invalid public DSA key");
407 :
408 1 : return ret;
409 : }
410 :
411 : GkmDataResult
412 1 : gkm_data_der_read_public_key_dsa_parts (GBytes *keydata,
413 : GBytes *params,
414 : gcry_sexp_t *s_key)
415 : {
416 : gcry_mpi_t p, q, g, y;
417 1 : GkmDataResult ret = GKM_DATA_UNRECOGNIZED;
418 1 : GNode *asn_params = NULL;
419 1 : GNode *asn_key = NULL;
420 : int res;
421 :
422 1 : p = q = g = y = NULL;
423 :
424 1 : asn_params = egg_asn1x_create_and_decode (pk_asn1_tab, "DSAParameters", params);
425 1 : asn_key = egg_asn1x_create_and_decode (pk_asn1_tab, "DSAPublicPart", keydata);
426 1 : if (!asn_params || !asn_key)
427 0 : goto done;
428 :
429 1 : ret = GKM_DATA_FAILURE;
430 :
431 2 : if (!gkm_data_asn1_read_mpi (egg_asn1x_node (asn_params, "p", NULL), &p) ||
432 2 : !gkm_data_asn1_read_mpi (egg_asn1x_node (asn_params, "q", NULL), &q) ||
433 1 : !gkm_data_asn1_read_mpi (egg_asn1x_node (asn_params, "g", NULL), &g))
434 0 : goto done;
435 :
436 1 : if (!gkm_data_asn1_read_mpi (asn_key, &y))
437 0 : goto done;
438 :
439 1 : res = gcry_sexp_build (s_key, NULL, SEXP_PUBLIC_DSA, p, q, g, y);
440 1 : if (res)
441 0 : goto done;
442 :
443 1 : g_assert (*s_key);
444 1 : ret = GKM_DATA_SUCCESS;
445 :
446 1 : done:
447 1 : egg_asn1x_destroy (asn_key);
448 1 : egg_asn1x_destroy (asn_params);
449 1 : gcry_mpi_release (p);
450 1 : gcry_mpi_release (q);
451 1 : gcry_mpi_release (g);
452 1 : gcry_mpi_release (y);
453 :
454 1 : if (ret == GKM_DATA_FAILURE)
455 0 : g_message ("invalid DSA key");
456 :
457 1 : return ret;
458 : }
459 :
460 : #define SEXP_PRIVATE_DSA \
461 : "(private-key" \
462 : " (dsa" \
463 : " (p %m)" \
464 : " (q %m)" \
465 : " (g %m)" \
466 : " (y %m)" \
467 : " (x %m)))"
468 :
469 : GkmDataResult
470 21 : gkm_data_der_read_private_key_dsa (GBytes *data,
471 : gcry_sexp_t *s_key)
472 : {
473 : gcry_mpi_t p, q, g, y, x;
474 21 : GkmDataResult ret = GKM_DATA_UNRECOGNIZED;
475 : int res;
476 21 : GNode *asn = NULL;
477 :
478 21 : p = q = g = y = x = NULL;
479 :
480 21 : asn = egg_asn1x_create_and_decode (pk_asn1_tab, "DSAPrivateKey", data);
481 21 : if (!asn)
482 16 : goto done;
483 :
484 5 : ret = GKM_DATA_FAILURE;
485 :
486 10 : if (!gkm_data_asn1_read_mpi (egg_asn1x_node (asn, "p", NULL), &p) ||
487 10 : !gkm_data_asn1_read_mpi (egg_asn1x_node (asn, "q", NULL), &q) ||
488 10 : !gkm_data_asn1_read_mpi (egg_asn1x_node (asn, "g", NULL), &g) ||
489 10 : !gkm_data_asn1_read_mpi (egg_asn1x_node (asn, "Y", NULL), &y) ||
490 5 : !gkm_data_asn1_read_mpi (egg_asn1x_node (asn, "priv", NULL), &x))
491 0 : goto done;
492 :
493 5 : res = gcry_sexp_build (s_key, NULL, SEXP_PRIVATE_DSA, p, q, g, y, x);
494 5 : if (res)
495 0 : goto done;
496 :
497 5 : g_assert (*s_key);
498 5 : ret = GKM_DATA_SUCCESS;
499 :
500 21 : done:
501 21 : egg_asn1x_destroy (asn);
502 21 : gcry_mpi_release (p);
503 21 : gcry_mpi_release (q);
504 21 : gcry_mpi_release (g);
505 21 : gcry_mpi_release (y);
506 21 : gcry_mpi_release (x);
507 :
508 21 : if (ret == GKM_DATA_FAILURE)
509 0 : g_message ("invalid DSA key");
510 :
511 21 : return ret;
512 : }
513 :
514 : GkmDataResult
515 4 : gkm_data_der_read_private_key_dsa_parts (GBytes *keydata,
516 : GBytes *params,
517 : gcry_sexp_t *s_key)
518 : {
519 : gcry_mpi_t p, q, g, y, x;
520 4 : GkmDataResult ret = GKM_DATA_UNRECOGNIZED;
521 : int res;
522 4 : GNode *asn_params = NULL;
523 4 : GNode *asn_key = NULL;
524 :
525 4 : p = q = g = y = x = NULL;
526 :
527 4 : asn_params = egg_asn1x_create_and_decode (pk_asn1_tab, "DSAParameters", params);
528 4 : asn_key = egg_asn1x_create_and_decode (pk_asn1_tab, "DSAPrivatePart", keydata);
529 4 : if (!asn_params || !asn_key)
530 0 : goto done;
531 :
532 4 : ret = GKM_DATA_FAILURE;
533 :
534 8 : if (!gkm_data_asn1_read_mpi (egg_asn1x_node (asn_params, "p", NULL), &p) ||
535 8 : !gkm_data_asn1_read_mpi (egg_asn1x_node (asn_params, "q", NULL), &q) ||
536 4 : !gkm_data_asn1_read_mpi (egg_asn1x_node (asn_params, "g", NULL), &g))
537 0 : goto done;
538 :
539 4 : if (!gkm_data_asn1_read_mpi (asn_key, &x))
540 0 : goto done;
541 :
542 : /* Now we calculate y */
543 4 : y = gcry_mpi_snew (1024);
544 4 : gcry_mpi_powm (y, g, x, p);
545 :
546 4 : res = gcry_sexp_build (s_key, NULL, SEXP_PRIVATE_DSA, p, q, g, y, x);
547 4 : if (res)
548 0 : goto done;
549 :
550 4 : g_assert (*s_key);
551 4 : ret = GKM_DATA_SUCCESS;
552 :
553 4 : done:
554 4 : egg_asn1x_destroy (asn_key);
555 4 : egg_asn1x_destroy (asn_params);
556 4 : gcry_mpi_release (p);
557 4 : gcry_mpi_release (q);
558 4 : gcry_mpi_release (g);
559 4 : gcry_mpi_release (y);
560 4 : gcry_mpi_release (x);
561 :
562 4 : if (ret == GKM_DATA_FAILURE)
563 0 : g_message ("invalid DSA key");
564 :
565 4 : return ret;
566 : }
567 :
568 : #define SEXP_PUBLIC_ECDSA \
569 : "(public-key" \
570 : " (ecdsa" \
571 : " (curve %s)" \
572 : " (q %b)))"
573 :
574 : GkmDataResult
575 3 : gkm_data_der_read_public_key_ecdsa (GBytes *data,
576 : gcry_sexp_t *s_key)
577 : {
578 3 : GkmDataResult ret = GKM_DATA_UNRECOGNIZED;
579 : int res;
580 3 : GNode *asn = NULL;
581 3 : GBytes *q = NULL;
582 : gsize q_bits;
583 : GQuark oid;
584 3 : const gchar *curve = NULL;
585 :
586 3 : init_quarks ();
587 :
588 3 : asn = egg_asn1x_create_and_decode (pk_asn1_tab, "ECPublicKey", data);
589 3 : if (!asn)
590 2 : goto done;
591 :
592 1 : ret = GKM_DATA_FAILURE;
593 :
594 2 : if (!gkm_data_asn1_read_oid (egg_asn1x_node (asn, "parameters", "namedCurve", NULL), &oid) ||
595 1 : !gkm_data_asn1_read_bit_string (egg_asn1x_node (asn, "q", NULL), &q, &q_bits))
596 0 : goto done;
597 :
598 1 : curve = gkm_data_der_oid_to_curve (oid);
599 1 : if (curve == NULL)
600 0 : goto done;
601 :
602 1 : res = gcry_sexp_build (s_key, NULL, SEXP_PUBLIC_ECDSA,
603 : curve,
604 : g_bytes_get_size(q), g_bytes_get_data(q, NULL));
605 1 : if (res)
606 0 : goto done;
607 :
608 1 : g_assert (*s_key);
609 1 : ret = GKM_DATA_SUCCESS;
610 :
611 3 : done:
612 3 : egg_asn1x_destroy (asn);
613 3 : g_bytes_unref (q);
614 :
615 3 : if (ret == GKM_DATA_FAILURE)
616 0 : g_message ("invalid ECDSA key");
617 :
618 3 : return ret;
619 : }
620 :
621 : #define SEXP_PRIVATE_ECDSA \
622 : "(private-key" \
623 : " (ecdsa" \
624 : " (curve %s)" \
625 : " (q %b)" \
626 : " (d %m)))"
627 :
628 : GkmDataResult
629 15 : gkm_data_der_read_private_key_ecdsa (GBytes *data,
630 : gcry_sexp_t *s_key)
631 : {
632 15 : gcry_mpi_t d = NULL;
633 15 : GkmDataResult ret = GKM_DATA_UNRECOGNIZED;
634 : int res;
635 15 : GNode *asn = NULL;
636 15 : GBytes *q = NULL;
637 : gsize q_bits;
638 : GQuark oid;
639 15 : const gchar *curve = NULL;
640 :
641 15 : init_quarks ();
642 :
643 15 : asn = egg_asn1x_create_and_decode (pk_asn1_tab, "ECPrivateKey", data);
644 15 : if (!asn)
645 6 : goto done;
646 :
647 9 : ret = GKM_DATA_FAILURE;
648 :
649 18 : if (!gkm_data_asn1_read_string_mpi (egg_asn1x_node (asn, "d", NULL), &d) ||
650 18 : !gkm_data_asn1_read_oid (egg_asn1x_node (asn, "parameters", "namedCurve", NULL), &oid) ||
651 9 : !gkm_data_asn1_read_bit_string (egg_asn1x_node (asn, "q", NULL), &q, &q_bits))
652 0 : goto done;
653 :
654 9 : curve = gkm_data_der_oid_to_curve (oid);
655 9 : if (curve == NULL)
656 0 : goto done;
657 :
658 9 : res = gcry_sexp_build (s_key, NULL, SEXP_PRIVATE_ECDSA,
659 : curve,
660 : g_bytes_get_size(q), g_bytes_get_data(q, NULL), d);
661 9 : if (res)
662 0 : goto done;
663 :
664 9 : g_assert (*s_key);
665 9 : ret = GKM_DATA_SUCCESS;
666 :
667 15 : done:
668 15 : egg_asn1x_destroy (asn);
669 15 : gcry_mpi_release (d);
670 15 : g_bytes_unref (q);
671 :
672 15 : if (ret == GKM_DATA_FAILURE)
673 0 : g_message ("invalid ECDSA key");
674 :
675 15 : return ret;
676 : }
677 :
678 : GkmDataResult
679 3 : gkm_data_der_read_public_key (GBytes *data, gcry_sexp_t *s_key)
680 : {
681 : GkmDataResult res;
682 :
683 3 : res = gkm_data_der_read_public_key_rsa (data, s_key);
684 3 : if (res == GKM_DATA_UNRECOGNIZED)
685 2 : res = gkm_data_der_read_public_key_ecdsa (data, s_key);
686 3 : if (res == GKM_DATA_UNRECOGNIZED)
687 1 : res = gkm_data_der_read_public_key_dsa (data, s_key);
688 :
689 3 : return res;
690 : }
691 :
692 : GkmDataResult
693 179 : gkm_data_der_read_public_key_info (GBytes *data,
694 : gcry_sexp_t* s_key)
695 : {
696 179 : GkmDataResult ret = GKM_DATA_UNRECOGNIZED;
697 : GQuark oid;
698 179 : GNode *asn = NULL;
699 : GBytes *params;
700 179 : GBytes *key = NULL;
701 : guint n_bits;
702 :
703 179 : init_quarks ();
704 :
705 179 : asn = egg_asn1x_create_and_decode (pkix_asn1_tab, "SubjectPublicKeyInfo", data);
706 179 : if (!asn)
707 0 : goto done;
708 :
709 179 : ret = GKM_DATA_FAILURE;
710 :
711 : /* Figure out the algorithm */
712 179 : oid = egg_asn1x_get_oid_as_quark (egg_asn1x_node (asn, "algorithm", "algorithm", NULL));
713 179 : if (!oid)
714 0 : goto done;
715 :
716 : /* A bit string so we cannot process in place */
717 179 : key = egg_asn1x_get_bits_as_raw (egg_asn1x_node (asn, "subjectPublicKey", NULL), &n_bits);
718 179 : if (!key)
719 0 : goto done;
720 179 : if (n_bits % 8 != 0) {
721 0 : g_message ("invalid bit length for public key: %u", n_bits);
722 0 : goto done;
723 : }
724 :
725 : /* An RSA key is simple */
726 179 : if (oid == OID_PKIX1_RSA) {
727 177 : ret = gkm_data_der_read_public_key_rsa (key, s_key);
728 :
729 : /* A DSA key paramaters are stored separately */
730 2 : } else if (oid == OID_PKIX1_DSA) {
731 1 : params = egg_asn1x_get_element_raw (egg_asn1x_node (asn, "algorithm", "parameters", NULL));
732 1 : if (!params)
733 0 : goto done;
734 1 : ret = gkm_data_der_read_public_key_dsa_parts (key, params, s_key);
735 1 : g_bytes_unref (params);
736 :
737 : /* A ECDSA key */
738 1 : } else if (oid == OID_PKIX1_ECDSA) {
739 1 : ret = gkm_data_der_read_public_key_ecdsa (key, s_key);
740 :
741 : } else {
742 0 : g_message ("unsupported key algorithm in certificate: %s", g_quark_to_string (oid));
743 0 : ret = GKM_DATA_UNRECOGNIZED;
744 0 : goto done;
745 : }
746 :
747 179 : done:
748 179 : egg_asn1x_destroy (asn);
749 179 : if (key)
750 179 : g_bytes_unref (key);
751 :
752 179 : if (ret == GKM_DATA_FAILURE)
753 0 : g_message ("invalid subject public-key info");
754 :
755 179 : return ret;
756 : }
757 :
758 : GkmDataResult
759 23 : gkm_data_der_read_private_key (GBytes *data,
760 : gcry_sexp_t *s_key)
761 : {
762 : GkmDataResult res;
763 :
764 23 : res = gkm_data_der_read_private_key_rsa (data, s_key);
765 23 : if (res == GKM_DATA_UNRECOGNIZED)
766 18 : res = gkm_data_der_read_private_key_dsa (data, s_key);
767 23 : if (res == GKM_DATA_UNRECOGNIZED)
768 13 : res = gkm_data_der_read_private_key_ecdsa (data, s_key);
769 :
770 23 : return res;
771 : }
772 :
773 : GkmDataResult
774 25 : gkm_data_der_read_private_pkcs8_plain (GBytes *data,
775 : gcry_sexp_t *s_key)
776 : {
777 25 : GNode *asn = NULL;
778 : GkmDataResult ret;
779 : int algorithm;
780 : GQuark key_algo;
781 25 : GBytes *keydata = NULL;
782 25 : GBytes *params = NULL;
783 :
784 25 : ret = GKM_DATA_UNRECOGNIZED;
785 :
786 25 : init_quarks ();
787 :
788 25 : asn = egg_asn1x_create_and_decode (pkix_asn1_tab, "pkcs-8-PrivateKeyInfo", data);
789 25 : if (!asn)
790 4 : goto done;
791 :
792 21 : ret = GKM_DATA_FAILURE;
793 21 : algorithm = 0;
794 :
795 21 : key_algo = egg_asn1x_get_oid_as_quark (egg_asn1x_node (asn, "privateKeyAlgorithm", "algorithm", NULL));
796 21 : if (!key_algo)
797 0 : goto done;
798 21 : else if (key_algo == OID_PKIX1_RSA)
799 16 : algorithm = GCRY_PK_RSA;
800 5 : else if (key_algo == OID_PKIX1_DSA)
801 3 : algorithm = GCRY_PK_DSA;
802 2 : else if (key_algo == OID_PKIX1_ECDSA)
803 2 : algorithm = GCRY_PK_ECC;
804 :
805 21 : if (!algorithm) {
806 0 : ret = GKM_DATA_UNRECOGNIZED;
807 0 : goto done;
808 : }
809 :
810 21 : keydata = egg_asn1x_get_string_as_bytes (egg_asn1x_node (asn, "privateKey", NULL));
811 21 : if (!keydata)
812 0 : goto done;
813 :
814 21 : params = egg_asn1x_get_element_raw (egg_asn1x_node (asn, "privateKeyAlgorithm", "parameters", NULL));
815 :
816 21 : ret = GKM_DATA_SUCCESS;
817 :
818 25 : done:
819 25 : if (ret == GKM_DATA_SUCCESS) {
820 21 : switch (algorithm) {
821 16 : case GCRY_PK_RSA:
822 16 : ret = gkm_data_der_read_private_key_rsa (keydata, s_key);
823 16 : break;
824 3 : case GCRY_PK_DSA:
825 : /* Try the normal one block format */
826 3 : ret = gkm_data_der_read_private_key_dsa (keydata, s_key);
827 :
828 : /* Otherwise try the two part format that everyone seems to like */
829 3 : if (ret == GKM_DATA_UNRECOGNIZED && params)
830 3 : ret = gkm_data_der_read_private_key_dsa_parts (keydata, params, s_key);
831 3 : break;
832 2 : case GCRY_PK_ECC:
833 2 : ret = gkm_data_der_read_private_key_ecdsa (keydata, s_key);
834 2 : break;
835 0 : default:
836 0 : g_message ("invalid or unsupported key type in PKCS#8 key");
837 0 : ret = GKM_DATA_UNRECOGNIZED;
838 0 : break;
839 : };
840 :
841 4 : } else if (ret == GKM_DATA_FAILURE) {
842 0 : g_message ("invalid PKCS#8 key");
843 : }
844 :
845 25 : if (params)
846 15 : g_bytes_unref (params);
847 25 : if (keydata)
848 21 : g_bytes_unref (keydata);
849 25 : egg_asn1x_destroy (asn);
850 25 : return ret;
851 : }
852 :
853 : GkmDataResult
854 21 : gkm_data_der_read_private_pkcs8_crypted (GBytes *data,
855 : const gchar *password,
856 : gsize n_password,
857 : gcry_sexp_t *s_key)
858 : {
859 21 : GNode *asn = NULL;
860 21 : gcry_cipher_hd_t cih = NULL;
861 : gcry_error_t gcry;
862 : GkmDataResult ret, r;
863 : GQuark scheme;
864 21 : guchar *crypted = NULL;
865 : GNode *params;
866 : GBytes *bytes;
867 : gsize n_crypted;
868 : gint l;
869 :
870 21 : init_quarks ();
871 :
872 21 : ret = GKM_DATA_UNRECOGNIZED;
873 :
874 21 : asn = egg_asn1x_create_and_decode (pkix_asn1_tab, "pkcs-8-EncryptedPrivateKeyInfo", data);
875 21 : if (!asn)
876 1 : goto done;
877 :
878 20 : ret = GKM_DATA_FAILURE;
879 :
880 : /* Figure out the type of encryption */
881 20 : scheme = egg_asn1x_get_oid_as_quark (egg_asn1x_node (asn, "encryptionAlgorithm", "algorithm", NULL));
882 20 : if (!scheme)
883 0 : goto done;
884 :
885 20 : params = egg_asn1x_node (asn, "encryptionAlgorithm", "parameters", NULL);
886 20 : if (!params)
887 0 : goto done;
888 :
889 : /*
890 : * Parse the encryption stuff into a cipher.
891 : */
892 20 : r = egg_symkey_read_cipher (scheme, password, n_password, params, &cih);
893 :
894 20 : if (r == GKM_DATA_UNRECOGNIZED) {
895 0 : ret = GKM_DATA_FAILURE;
896 0 : goto done;
897 20 : } else if (r != GKM_DATA_SUCCESS) {
898 0 : ret = r;
899 0 : goto done;
900 : }
901 :
902 20 : crypted = egg_asn1x_get_string_as_raw (egg_asn1x_node (asn, "encryptedData", NULL),
903 : egg_secure_realloc, &n_crypted);
904 20 : if (!crypted)
905 0 : goto done;
906 :
907 20 : gcry = gcry_cipher_decrypt (cih, crypted, n_crypted, NULL, 0);
908 20 : gcry_cipher_close (cih);
909 20 : cih = NULL;
910 :
911 20 : if (gcry != 0) {
912 0 : g_warning ("couldn't decrypt pkcs8 data: %s", gcry_strerror (gcry));
913 0 : goto done;
914 : }
915 :
916 : /* Unpad the DER data */
917 20 : l = egg_asn1x_element_length (crypted, n_crypted);
918 20 : if (l <= 0 || l > n_crypted) {
919 0 : ret = GKM_DATA_LOCKED;
920 0 : goto done;
921 : }
922 20 : n_crypted = l;
923 :
924 20 : bytes = g_bytes_new_with_free_func (crypted, n_crypted, egg_secure_free, crypted);
925 20 : crypted = NULL;
926 :
927 : /* Try to parse the resulting key */
928 20 : ret = gkm_data_der_read_private_pkcs8_plain (bytes, s_key);
929 20 : g_bytes_unref (bytes);
930 :
931 : /* If unrecognized we assume bad password */
932 20 : if (ret == GKM_DATA_UNRECOGNIZED)
933 4 : ret = GKM_DATA_LOCKED;
934 :
935 16 : done:
936 21 : if (cih)
937 0 : gcry_cipher_close (cih);
938 21 : egg_asn1x_destroy (asn);
939 21 : egg_secure_free (crypted);
940 :
941 21 : return ret;
942 : }
943 :
944 : GkmDataResult
945 17 : gkm_data_der_read_private_pkcs8 (GBytes *data,
946 : const gchar *password,
947 : gsize n_password,
948 : gcry_sexp_t *s_key)
949 : {
950 : GkmDataResult res;
951 :
952 17 : res = gkm_data_der_read_private_pkcs8_crypted (data, password, n_password, s_key);
953 17 : if (res == GKM_DATA_UNRECOGNIZED)
954 1 : res = gkm_data_der_read_private_pkcs8_plain (data, s_key);
955 :
956 17 : return res;
957 : }
958 :
959 : GBytes *
960 1 : gkm_data_der_write_public_key_rsa (gcry_sexp_t s_key)
961 : {
962 1 : GNode *asn = NULL;
963 : gcry_mpi_t n, e;
964 1 : GBytes *result = NULL;
965 :
966 1 : n = e = NULL;
967 :
968 1 : asn = egg_asn1x_create (pk_asn1_tab, "RSAPublicKey");
969 1 : g_return_val_if_fail (asn, NULL);
970 :
971 2 : if (!gkm_sexp_extract_mpi (s_key, &n, "rsa", "n", NULL) ||
972 1 : !gkm_sexp_extract_mpi (s_key, &e, "rsa", "e", NULL))
973 0 : goto done;
974 :
975 2 : if (!gkm_data_asn1_write_mpi (egg_asn1x_node (asn, "modulus", NULL), n) ||
976 1 : !gkm_data_asn1_write_mpi (egg_asn1x_node (asn, "publicExponent", NULL), e))
977 0 : goto done;
978 :
979 1 : result = egg_asn1x_encode (asn, NULL);
980 1 : if (result == NULL)
981 0 : g_warning ("couldn't encode public rsa key: %s", egg_asn1x_message (asn));
982 :
983 1 : done:
984 1 : egg_asn1x_destroy (asn);
985 1 : gcry_mpi_release (n);
986 1 : gcry_mpi_release (e);
987 :
988 1 : return result;
989 : }
990 :
991 : GBytes *
992 6 : gkm_data_der_write_private_key_rsa (gcry_sexp_t s_key)
993 : {
994 6 : GNode *asn = NULL;
995 : gcry_mpi_t n, e, d, p, q, u, e1, e2, tmp;
996 6 : GBytes *result = NULL;
997 :
998 6 : n = e = d = p = q = u = e1 = e2 = tmp = NULL;
999 :
1000 6 : asn = egg_asn1x_create (pk_asn1_tab, "RSAPrivateKey");
1001 6 : g_return_val_if_fail (asn, NULL);
1002 :
1003 12 : if (!gkm_sexp_extract_mpi (s_key, &n, "rsa", "n", NULL) ||
1004 12 : !gkm_sexp_extract_mpi (s_key, &e, "rsa", "e", NULL) ||
1005 12 : !gkm_sexp_extract_mpi (s_key, &d, "rsa", "d", NULL) ||
1006 12 : !gkm_sexp_extract_mpi (s_key, &p, "rsa", "p", NULL) ||
1007 12 : !gkm_sexp_extract_mpi (s_key, &q, "rsa", "q", NULL) ||
1008 6 : !gkm_sexp_extract_mpi (s_key, &u, "rsa", "u", NULL))
1009 0 : goto done;
1010 :
1011 12 : if (!gkm_data_asn1_write_mpi (egg_asn1x_node (asn, "modulus", NULL), n) ||
1012 12 : !gkm_data_asn1_write_mpi (egg_asn1x_node (asn, "publicExponent", NULL), e) ||
1013 12 : !gkm_data_asn1_write_mpi (egg_asn1x_node (asn, "privateExponent", NULL), d) ||
1014 12 : !gkm_data_asn1_write_mpi (egg_asn1x_node (asn, "prime1", NULL), p) ||
1015 12 : !gkm_data_asn1_write_mpi (egg_asn1x_node (asn, "prime2", NULL), q) ||
1016 6 : !gkm_data_asn1_write_mpi (egg_asn1x_node (asn, "coefficient", NULL), u))
1017 0 : goto done;
1018 :
1019 : /* Calculate e1 and e2 */
1020 6 : tmp = gcry_mpi_snew (1024);
1021 6 : gcry_mpi_sub_ui (tmp, p, 1);
1022 6 : e1 = gcry_mpi_snew (1024);
1023 6 : gcry_mpi_mod (e1, d, tmp);
1024 6 : gcry_mpi_sub_ui (tmp, q, 1);
1025 6 : e2 = gcry_mpi_snew (1024);
1026 6 : gcry_mpi_mod (e2, d, tmp);
1027 :
1028 : /* Write out calculated */
1029 12 : if (!gkm_data_asn1_write_mpi (egg_asn1x_node (asn, "exponent1", NULL), e1) ||
1030 6 : !gkm_data_asn1_write_mpi (egg_asn1x_node (asn, "exponent2", NULL), e2))
1031 0 : goto done;
1032 :
1033 : /* Write out the version */
1034 6 : egg_asn1x_set_integer_as_ulong (egg_asn1x_node (asn, "version", NULL), 0);
1035 :
1036 6 : result = egg_asn1x_encode (asn, egg_secure_realloc);
1037 6 : if (result == NULL)
1038 0 : g_warning ("couldn't encode private rsa key: %s", egg_asn1x_message (asn));
1039 :
1040 6 : done:
1041 6 : egg_asn1x_destroy (asn);
1042 6 : gcry_mpi_release (n);
1043 6 : gcry_mpi_release (e);
1044 6 : gcry_mpi_release (d);
1045 6 : gcry_mpi_release (p);
1046 6 : gcry_mpi_release (q);
1047 6 : gcry_mpi_release (u);
1048 :
1049 6 : gcry_mpi_release (tmp);
1050 6 : gcry_mpi_release (e1);
1051 6 : gcry_mpi_release (e2);
1052 :
1053 6 : return result;
1054 : }
1055 :
1056 : GBytes *
1057 1 : gkm_data_der_write_public_key_dsa (gcry_sexp_t s_key)
1058 : {
1059 1 : GNode *asn = NULL;
1060 : gcry_mpi_t p, q, g, y;
1061 1 : GBytes *result = NULL;
1062 :
1063 1 : p = q = g = y = NULL;
1064 :
1065 1 : asn = egg_asn1x_create (pk_asn1_tab, "DSAPublicKey");
1066 1 : g_return_val_if_fail (asn, NULL);
1067 :
1068 2 : if (!gkm_sexp_extract_mpi (s_key, &p, "dsa", "p", NULL) ||
1069 2 : !gkm_sexp_extract_mpi (s_key, &q, "dsa", "q", NULL) ||
1070 2 : !gkm_sexp_extract_mpi (s_key, &g, "dsa", "g", NULL) ||
1071 1 : !gkm_sexp_extract_mpi (s_key, &y, "dsa", "y", NULL))
1072 0 : goto done;
1073 :
1074 2 : if (!gkm_data_asn1_write_mpi (egg_asn1x_node (asn, "p", NULL), p) ||
1075 2 : !gkm_data_asn1_write_mpi (egg_asn1x_node (asn, "q", NULL), q) ||
1076 2 : !gkm_data_asn1_write_mpi (egg_asn1x_node (asn, "g", NULL), g) ||
1077 1 : !gkm_data_asn1_write_mpi (egg_asn1x_node (asn, "Y", NULL), y))
1078 0 : goto done;
1079 :
1080 1 : egg_asn1x_set_integer_as_ulong (egg_asn1x_node (asn, "version", NULL), 0);
1081 :
1082 1 : result = egg_asn1x_encode (asn, NULL);
1083 1 : if (result == NULL)
1084 0 : g_warning ("couldn't encode public dsa key: %s", egg_asn1x_message (asn));
1085 :
1086 1 : done:
1087 1 : egg_asn1x_destroy (asn);
1088 1 : gcry_mpi_release (p);
1089 1 : gcry_mpi_release (q);
1090 1 : gcry_mpi_release (g);
1091 1 : gcry_mpi_release (y);
1092 :
1093 1 : return result;
1094 : }
1095 :
1096 : GBytes *
1097 3 : gkm_data_der_write_private_key_dsa_part (gcry_sexp_t skey)
1098 : {
1099 3 : GNode *asn = NULL;
1100 : gcry_mpi_t x;
1101 3 : GBytes *result = NULL;
1102 :
1103 3 : x = NULL;
1104 :
1105 3 : asn = egg_asn1x_create (pk_asn1_tab, "DSAPrivatePart");
1106 3 : g_return_val_if_fail (asn, NULL);
1107 :
1108 3 : if (!gkm_sexp_extract_mpi (skey, &x, "dsa", "x", NULL))
1109 0 : goto done;
1110 :
1111 3 : if (!gkm_data_asn1_write_mpi (asn, x))
1112 0 : goto done;
1113 :
1114 3 : result = egg_asn1x_encode (asn, egg_secure_realloc);
1115 3 : if (result == NULL)
1116 0 : g_warning ("couldn't encode private dsa key: %s", egg_asn1x_message (asn));
1117 :
1118 3 : done:
1119 3 : egg_asn1x_destroy (asn);
1120 3 : gcry_mpi_release (x);
1121 :
1122 3 : return result;
1123 : }
1124 :
1125 : GBytes *
1126 3 : gkm_data_der_write_private_key_dsa_params (gcry_sexp_t skey)
1127 : {
1128 3 : GNode *asn = NULL;
1129 : gcry_mpi_t p, q, g;
1130 3 : GBytes *result = NULL;
1131 :
1132 3 : p = q = g = NULL;
1133 :
1134 3 : asn = egg_asn1x_create (pk_asn1_tab, "DSAParameters");
1135 3 : g_return_val_if_fail (asn, NULL);
1136 :
1137 6 : if (!gkm_sexp_extract_mpi (skey, &p, "dsa", "p", NULL) ||
1138 6 : !gkm_sexp_extract_mpi (skey, &q, "dsa", "q", NULL) ||
1139 3 : !gkm_sexp_extract_mpi (skey, &g, "dsa", "g", NULL))
1140 0 : goto done;
1141 :
1142 6 : if (!gkm_data_asn1_write_mpi (egg_asn1x_node (asn, "p", NULL), p) ||
1143 6 : !gkm_data_asn1_write_mpi (egg_asn1x_node (asn, "q", NULL), q) ||
1144 3 : !gkm_data_asn1_write_mpi (egg_asn1x_node (asn, "g", NULL), g))
1145 0 : goto done;
1146 :
1147 3 : result = egg_asn1x_encode (asn, egg_secure_realloc);
1148 3 : if (result == NULL)
1149 0 : g_warning ("couldn't encode private dsa params: %s", egg_asn1x_message (asn));
1150 :
1151 3 : done:
1152 3 : egg_asn1x_destroy (asn);
1153 3 : gcry_mpi_release (p);
1154 3 : gcry_mpi_release (q);
1155 3 : gcry_mpi_release (g);
1156 :
1157 3 : return result;
1158 : }
1159 :
1160 : GBytes *
1161 1 : gkm_data_der_write_private_key_dsa (gcry_sexp_t s_key)
1162 : {
1163 1 : GNode *asn = NULL;
1164 : gcry_mpi_t p, q, g, y, x;
1165 1 : GBytes *result = NULL;
1166 :
1167 1 : p = q = g = y = x = NULL;
1168 :
1169 1 : asn = egg_asn1x_create (pk_asn1_tab, "DSAPrivateKey");
1170 1 : g_return_val_if_fail (asn, NULL);
1171 :
1172 2 : if (!gkm_sexp_extract_mpi (s_key, &p, "dsa", "p", NULL) ||
1173 2 : !gkm_sexp_extract_mpi (s_key, &q, "dsa", "q", NULL) ||
1174 2 : !gkm_sexp_extract_mpi (s_key, &g, "dsa", "g", NULL) ||
1175 2 : !gkm_sexp_extract_mpi (s_key, &y, "dsa", "y", NULL) ||
1176 1 : !gkm_sexp_extract_mpi (s_key, &x, "dsa", "x", NULL))
1177 0 : goto done;
1178 :
1179 2 : if (!gkm_data_asn1_write_mpi (egg_asn1x_node (asn, "p", NULL), p) ||
1180 2 : !gkm_data_asn1_write_mpi (egg_asn1x_node (asn, "q", NULL), q) ||
1181 2 : !gkm_data_asn1_write_mpi (egg_asn1x_node (asn, "g", NULL), g) ||
1182 2 : !gkm_data_asn1_write_mpi (egg_asn1x_node (asn, "Y", NULL), y) ||
1183 1 : !gkm_data_asn1_write_mpi (egg_asn1x_node (asn, "priv", NULL), x))
1184 0 : goto done;
1185 :
1186 1 : egg_asn1x_set_integer_as_ulong (egg_asn1x_node (asn, "version", NULL), 0);
1187 :
1188 1 : result = egg_asn1x_encode (asn, egg_secure_realloc);
1189 1 : if (result == NULL)
1190 0 : g_warning ("couldn't encode private dsa key: %s", egg_asn1x_message (asn));
1191 :
1192 1 : done:
1193 1 : egg_asn1x_destroy (asn);
1194 1 : gcry_mpi_release (p);
1195 1 : gcry_mpi_release (q);
1196 1 : gcry_mpi_release (g);
1197 1 : gcry_mpi_release (y);
1198 1 : gcry_mpi_release (x);
1199 :
1200 1 : return result;
1201 : }
1202 :
1203 : GBytes *
1204 1 : gkm_data_der_write_public_key_ecdsa (gcry_sexp_t s_key)
1205 : {
1206 1 : GNode *asn = NULL, *named_curve;
1207 1 : gcry_mpi_t d = NULL;
1208 1 : GBytes *result = NULL, *q = NULL;
1209 1 : gchar *q_data = NULL;
1210 : GQuark oid;
1211 1 : gchar *curve = NULL;
1212 : gsize q_size;
1213 :
1214 1 : init_quarks ();
1215 :
1216 1 : asn = egg_asn1x_create (pk_asn1_tab, "ECPublicKey");
1217 1 : g_return_val_if_fail (asn, NULL);
1218 :
1219 2 : if (!gkm_sexp_extract_buffer (s_key, &q_data, &q_size, "ecdsa", "q", NULL) ||
1220 1 : !gkm_sexp_extract_string (s_key, &curve, "ecdsa", "curve", NULL))
1221 0 : goto done;
1222 :
1223 1 : oid = gkm_data_der_curve_to_oid (curve);
1224 1 : g_free (curve);
1225 1 : if (oid == 0)
1226 0 : goto done;
1227 :
1228 1 : q = g_bytes_new_take (q_data, q_size);
1229 1 : if (q == NULL)
1230 0 : goto done;
1231 :
1232 1 : named_curve = egg_asn1x_node (asn, "parameters", "namedCurve", NULL);
1233 :
1234 : /* XXX the bit size does not have to match byte size * 8 exactly
1235 : * it would be good to cover this with more tests
1236 : */
1237 2 : if (!gkm_data_asn1_write_bit_string (egg_asn1x_node (asn, "q", NULL), q, q_size*8) ||
1238 1 : !gkm_data_asn1_write_oid (named_curve, oid))
1239 0 : goto done;
1240 :
1241 1 : if (!egg_asn1x_set_choice (egg_asn1x_node (asn, "parameters", NULL), named_curve))
1242 0 : goto done;
1243 :
1244 1 : result = egg_asn1x_encode (asn, egg_secure_realloc);
1245 1 : if (result == NULL)
1246 0 : g_warning ("couldn't encode public ecdsa key: %s", egg_asn1x_message (asn));
1247 :
1248 1 : done:
1249 1 : egg_asn1x_destroy (asn);
1250 1 : gcry_mpi_release (d);
1251 1 : g_bytes_unref (q);
1252 :
1253 1 : return result;
1254 : }
1255 :
1256 : GBytes *
1257 3 : gkm_data_der_write_private_key_ecdsa (gcry_sexp_t s_key)
1258 : {
1259 3 : GNode *asn = NULL, *named_curve;
1260 3 : gcry_mpi_t d = NULL;
1261 3 : GBytes *result = NULL, *q = NULL;
1262 3 : gchar *q_data = NULL;
1263 : GQuark oid;
1264 3 : gchar *curve = NULL;
1265 : gsize q_size;
1266 :
1267 3 : init_quarks ();
1268 :
1269 3 : asn = egg_asn1x_create (pk_asn1_tab, "ECPrivateKey");
1270 3 : g_return_val_if_fail (asn, NULL);
1271 :
1272 6 : if (!gkm_sexp_extract_mpi (s_key, &d, "ecdsa", "d", NULL) ||
1273 6 : !gkm_sexp_extract_buffer (s_key, &q_data, &q_size, "ecdsa", "q", NULL) ||
1274 3 : !gkm_sexp_extract_string (s_key, &curve, "ecdsa", "curve", NULL))
1275 0 : goto done;
1276 :
1277 3 : oid = gkm_data_der_curve_to_oid (curve);
1278 3 : g_free (curve);
1279 3 : if (oid == 0)
1280 0 : goto done;
1281 :
1282 3 : q = g_bytes_new_take (q_data, q_size);
1283 3 : if (q == NULL)
1284 0 : goto done;
1285 :
1286 3 : named_curve = egg_asn1x_node (asn, "parameters", "namedCurve", NULL);
1287 :
1288 6 : if (!gkm_data_asn1_write_string_mpi (egg_asn1x_node (asn, "d", NULL), d) ||
1289 6 : !gkm_data_asn1_write_bit_string (egg_asn1x_node (asn, "q", NULL), q, q_size*8) ||
1290 3 : !gkm_data_asn1_write_oid (named_curve, oid))
1291 0 : goto done;
1292 :
1293 3 : if (!egg_asn1x_set_choice (egg_asn1x_node (asn, "parameters", NULL), named_curve))
1294 0 : goto done;
1295 :
1296 3 : egg_asn1x_set_integer_as_ulong (egg_asn1x_node (asn, "version", NULL), 1);
1297 :
1298 3 : result = egg_asn1x_encode (asn, egg_secure_realloc);
1299 3 : if (result == NULL)
1300 0 : g_warning ("couldn't encode private ecdsa key: %s", egg_asn1x_message (asn));
1301 :
1302 3 : done:
1303 3 : egg_asn1x_destroy (asn);
1304 3 : gcry_mpi_release (d);
1305 3 : g_bytes_unref (q);
1306 :
1307 3 : return result;
1308 : }
1309 :
1310 : GBytes *
1311 3 : gkm_data_der_write_public_key (gcry_sexp_t s_key)
1312 : {
1313 : gboolean is_priv;
1314 : int algorithm;
1315 :
1316 3 : g_return_val_if_fail (s_key != NULL, NULL);
1317 :
1318 3 : if (!gkm_sexp_parse_key (s_key, &algorithm, &is_priv, NULL))
1319 0 : g_return_val_if_reached (NULL);
1320 :
1321 3 : g_return_val_if_fail (!is_priv, NULL);
1322 :
1323 3 : switch (algorithm) {
1324 1 : case GCRY_PK_RSA:
1325 1 : return gkm_data_der_write_public_key_rsa (s_key);
1326 1 : case GCRY_PK_DSA:
1327 1 : return gkm_data_der_write_public_key_dsa (s_key);
1328 1 : case GCRY_PK_ECC:
1329 1 : return gkm_data_der_write_public_key_ecdsa (s_key);
1330 0 : default:
1331 0 : g_return_val_if_reached (NULL);
1332 : }
1333 : }
1334 :
1335 : GBytes *
1336 3 : gkm_data_der_write_private_key (gcry_sexp_t s_key)
1337 : {
1338 : gboolean is_priv;
1339 : int algorithm;
1340 :
1341 3 : g_return_val_if_fail (s_key != NULL, NULL);
1342 :
1343 3 : if (!gkm_sexp_parse_key (s_key, &algorithm, &is_priv, NULL))
1344 0 : g_return_val_if_reached (NULL);
1345 :
1346 3 : g_return_val_if_fail (is_priv, NULL);
1347 :
1348 3 : switch (algorithm) {
1349 1 : case GCRY_PK_RSA:
1350 1 : return gkm_data_der_write_private_key_rsa (s_key);
1351 1 : case GCRY_PK_DSA:
1352 1 : return gkm_data_der_write_private_key_dsa (s_key);
1353 1 : case GCRY_PK_ECC:
1354 1 : return gkm_data_der_write_private_key_ecdsa (s_key);
1355 0 : default:
1356 0 : g_return_val_if_reached (NULL);
1357 : }
1358 : }
1359 :
1360 : static gcry_cipher_hd_t
1361 5 : prepare_and_encode_pkcs8_cipher (GNode *asn, const gchar *password,
1362 : gsize n_password, gsize *n_block)
1363 : {
1364 5 : GNode *asn1_params = NULL;
1365 : gcry_cipher_hd_t cih;
1366 : guchar *salt;
1367 : gsize n_salt;
1368 : gcry_error_t gcry;
1369 : guchar *key, *iv;
1370 : gsize n_key;
1371 : int iterations;
1372 :
1373 5 : init_quarks ();
1374 :
1375 : /* Make sure the encryption algorithm works */
1376 5 : g_return_val_if_fail (gcry_cipher_algo_info (gcry_cipher_map_name (g_quark_to_string (OID_PKCS12_PBE_3DES_SHA1)),
1377 : GCRYCTL_TEST_ALGO, NULL, 0) == 0, NULL);
1378 :
1379 : /* The encryption algorithm */
1380 5 : if(!egg_asn1x_set_oid_as_quark (egg_asn1x_node (asn, "encryptionAlgorithm", "algorithm", NULL),
1381 : OID_PKCS12_PBE_3DES_SHA1))
1382 0 : g_return_val_if_reached (NULL);
1383 :
1384 : /* Randomize some input for the password based secret */
1385 5 : iterations = g_random_int_range (1000, 4096);
1386 5 : n_salt = 8;
1387 5 : salt = g_malloc (n_salt);
1388 5 : gcry_create_nonce (salt, n_salt);
1389 :
1390 : /* Allocate space for the key and iv */
1391 5 : n_key = gcry_cipher_get_algo_keylen (GCRY_CIPHER_3DES);
1392 5 : *n_block = gcry_cipher_get_algo_blklen (GCRY_MD_SHA1);
1393 5 : g_return_val_if_fail (n_key && *n_block, NULL);
1394 :
1395 5 : if (!egg_symkey_generate_pkcs12 (GCRY_CIPHER_3DES, GCRY_MD_SHA1,
1396 : password, n_password, salt,
1397 : sizeof (salt), iterations, &key, &iv))
1398 0 : g_return_val_if_reached (NULL);
1399 :
1400 : /* Now write out the parameters */
1401 5 : asn1_params = egg_asn1x_create (pkix_asn1_tab, "pkcs-12-PbeParams");
1402 5 : g_return_val_if_fail (asn1_params, NULL);
1403 5 : egg_asn1x_set_string_as_raw (egg_asn1x_node (asn1_params, "salt", NULL), salt, n_salt, g_free);
1404 5 : egg_asn1x_set_integer_as_ulong (egg_asn1x_node (asn1_params, "iterations", NULL), iterations);
1405 5 : egg_asn1x_set_any_from (egg_asn1x_node (asn, "encryptionAlgorithm", "parameters", NULL), asn1_params);
1406 :
1407 : /* Now make a cipher that matches what we wrote out */
1408 5 : gcry = gcry_cipher_open (&cih, GCRY_CIPHER_3DES, GCRY_CIPHER_MODE_CBC, 0);
1409 5 : g_return_val_if_fail (gcry == 0, NULL);
1410 5 : g_return_val_if_fail (cih, NULL);
1411 :
1412 5 : gcry_cipher_setiv (cih, iv, *n_block);
1413 5 : gcry_cipher_setkey (cih, key, n_key);
1414 :
1415 5 : g_free (iv);
1416 5 : egg_secure_free (key);
1417 5 : egg_asn1x_destroy (asn1_params);
1418 :
1419 5 : return cih;
1420 : }
1421 :
1422 : GBytes *
1423 9 : gkm_data_der_write_private_pkcs8_plain (gcry_sexp_t skey)
1424 : {
1425 9 : GNode *asn = NULL;
1426 : int algorithm;
1427 : gboolean is_priv;
1428 : GQuark oid;
1429 : GBytes *params;
1430 : GBytes *key;
1431 : GBytes *data;
1432 :
1433 9 : init_quarks ();
1434 :
1435 : /* Parse and check that the key is for real */
1436 9 : if (!gkm_sexp_parse_key (skey, &algorithm, &is_priv, NULL))
1437 0 : g_return_val_if_reached (NULL);
1438 9 : g_return_val_if_fail (is_priv == TRUE, NULL);
1439 :
1440 9 : asn = egg_asn1x_create (pkix_asn1_tab, "pkcs-8-PrivateKeyInfo");
1441 9 : g_return_val_if_fail (asn, NULL);
1442 :
1443 : /* Write out the version */
1444 9 : egg_asn1x_set_integer_as_ulong (egg_asn1x_node (asn, "version", NULL), 0);
1445 :
1446 : /* Per algorithm differences */
1447 9 : switch (algorithm)
1448 : {
1449 : /* RSA gets encoded in a standard simple way */
1450 5 : case GCRY_PK_RSA:
1451 5 : oid = OID_PKIX1_RSA;
1452 5 : params = NULL;
1453 5 : key = gkm_data_der_write_private_key_rsa (skey);
1454 5 : break;
1455 :
1456 : /* DSA gets incoded with the params seperate */
1457 2 : case GCRY_PK_DSA:
1458 2 : oid = OID_PKIX1_DSA;
1459 2 : key = gkm_data_der_write_private_key_dsa_part (skey);
1460 2 : params = gkm_data_der_write_private_key_dsa_params (skey);
1461 2 : break;
1462 :
1463 2 : case GCRY_PK_ECC:
1464 2 : oid = OID_PKIX1_ECDSA;
1465 2 : params = NULL;
1466 2 : key = gkm_data_der_write_private_key_ecdsa (skey);
1467 2 : break;
1468 :
1469 0 : default:
1470 0 : g_warning ("trying to serialize unsupported private key algorithm: %d", algorithm);
1471 0 : return NULL;
1472 : };
1473 :
1474 : /* Write out the algorithm */
1475 9 : if (!egg_asn1x_set_oid_as_quark (egg_asn1x_node (asn, "privateKeyAlgorithm", "algorithm", NULL), oid))
1476 0 : g_return_val_if_reached (NULL);
1477 :
1478 : /* Write out the parameters */
1479 9 : if (params) {
1480 2 : egg_asn1x_set_any_raw (egg_asn1x_node (asn, "privateKeyAlgorithm", "parameters", NULL), params);
1481 2 : g_bytes_unref (params);
1482 : }
1483 :
1484 : /* Write out the key portion */
1485 9 : egg_asn1x_set_string_as_bytes (egg_asn1x_node (asn, "privateKey", NULL), key);
1486 9 : g_bytes_unref (key);
1487 :
1488 9 : data = egg_asn1x_encode (asn, egg_secure_realloc);
1489 9 : if (data == NULL)
1490 0 : g_warning ("couldn't encode private pkcs8 key: %s", egg_asn1x_message (asn));
1491 :
1492 9 : egg_asn1x_destroy (asn);
1493 9 : return data;
1494 : }
1495 :
1496 : GBytes *
1497 5 : gkm_data_der_write_private_pkcs8_crypted (gcry_sexp_t skey,
1498 : const gchar *password,
1499 : gsize n_password)
1500 : {
1501 : gcry_error_t gcry;
1502 : gcry_cipher_hd_t cih;
1503 5 : GNode *asn = NULL;
1504 : GBytes *key, *data;
1505 : guchar *raw;
1506 : gsize n_raw, n_key;
1507 5 : gsize block = 0;
1508 :
1509 : /* Encode the key in normal pkcs8 fashion */
1510 5 : key = gkm_data_der_write_private_pkcs8_plain (skey);
1511 5 : if (key == NULL)
1512 0 : return NULL;
1513 :
1514 5 : asn = egg_asn1x_create (pkix_asn1_tab, "pkcs-8-EncryptedPrivateKeyInfo");
1515 5 : g_return_val_if_fail (asn, NULL);
1516 :
1517 : /* Create a and write out a cipher used for encryption */
1518 5 : cih = prepare_and_encode_pkcs8_cipher (asn, password, n_password, &block);
1519 5 : g_return_val_if_fail (cih, NULL);
1520 :
1521 5 : n_key = g_bytes_get_size (key);
1522 :
1523 : /* Pad the block of data */
1524 5 : if(block > 1) {
1525 5 : gsize n_pad = block - (n_key % block);
1526 5 : if (n_pad == 0)
1527 0 : n_pad = block;
1528 5 : raw = egg_secure_alloc (n_key + n_pad);
1529 5 : memcpy (raw, g_bytes_get_data (key, NULL), n_key);
1530 5 : memset (raw + n_key, (int)n_pad, n_pad);
1531 5 : n_raw = n_key + n_pad;
1532 :
1533 : /* No padding, probably stream cipher */
1534 : } else {
1535 0 : raw = egg_secure_alloc (n_key);
1536 0 : memcpy (raw, g_bytes_get_data (key, NULL), n_key);
1537 0 : n_raw = n_key;
1538 : }
1539 :
1540 5 : g_bytes_unref (key);
1541 :
1542 5 : gcry = gcry_cipher_encrypt (cih, raw, n_raw, NULL, 0);
1543 5 : g_return_val_if_fail (gcry == 0, NULL);
1544 :
1545 5 : gcry_cipher_close (cih);
1546 5 : key = g_bytes_new_with_free_func (raw, n_raw, egg_secure_free, raw);
1547 :
1548 5 : egg_asn1x_set_string_as_bytes (egg_asn1x_node (asn, "encryptedData", NULL), key);
1549 :
1550 5 : g_bytes_unref (key);
1551 :
1552 5 : data = egg_asn1x_encode (asn, NULL);
1553 5 : if (data == NULL)
1554 0 : g_warning ("couldn't encode encrypted pkcs8 key: %s", egg_asn1x_message (asn));
1555 :
1556 5 : egg_asn1x_destroy (asn);
1557 5 : return data;
1558 : }
1559 :
1560 : /* -----------------------------------------------------------------------------
1561 : * CERTIFICATES
1562 : */
1563 :
1564 : GkmDataResult
1565 179 : gkm_data_der_read_certificate (GBytes *data,
1566 : GNode **asn1)
1567 : {
1568 179 : *asn1 = egg_asn1x_create_and_decode (pkix_asn1_tab, "Certificate", data);
1569 179 : if (!*asn1)
1570 0 : return GKM_DATA_UNRECOGNIZED;
1571 :
1572 179 : return GKM_DATA_SUCCESS;
1573 : }
1574 :
1575 : GkmDataResult
1576 1 : gkm_data_der_read_basic_constraints (GBytes *data,
1577 : gboolean *is_ca,
1578 : gint *path_len)
1579 : {
1580 1 : GkmDataResult ret = GKM_DATA_UNRECOGNIZED;
1581 1 : GNode *asn = NULL;
1582 : GNode *node;
1583 : gulong value;
1584 :
1585 1 : asn = egg_asn1x_create_and_decode (pkix_asn1_tab, "BasicConstraints", data);
1586 1 : if (!asn)
1587 0 : goto done;
1588 :
1589 1 : ret = GKM_DATA_FAILURE;
1590 :
1591 1 : if (path_len) {
1592 1 : node = egg_asn1x_node (asn, "pathLenConstraint", NULL);
1593 1 : if (!egg_asn1x_have (node))
1594 1 : *path_len = -1;
1595 0 : else if (!egg_asn1x_get_integer_as_ulong (node, &value))
1596 0 : goto done;
1597 : else
1598 0 : *path_len = value;
1599 : }
1600 :
1601 1 : if (is_ca) {
1602 1 : node = egg_asn1x_node (asn, "cA", NULL);
1603 1 : if (!egg_asn1x_have (node))
1604 0 : *is_ca = FALSE;
1605 1 : else if (!egg_asn1x_get_boolean (node, is_ca))
1606 0 : goto done;
1607 : }
1608 :
1609 1 : ret = GKM_DATA_SUCCESS;
1610 :
1611 1 : done:
1612 1 : egg_asn1x_destroy (asn);
1613 1 : if (ret == GKM_DATA_FAILURE)
1614 0 : g_message ("invalid basic constraints");
1615 :
1616 1 : return ret;
1617 : }
1618 :
1619 : GkmDataResult
1620 1 : gkm_data_der_read_key_usage (GBytes *data,
1621 : gulong *key_usage)
1622 : {
1623 1 : GkmDataResult ret = GKM_DATA_UNRECOGNIZED;
1624 1 : GNode *asn = NULL;
1625 : guint n_bits;
1626 :
1627 1 : asn = egg_asn1x_create_and_decode (pkix_asn1_tab, "KeyUsage", data);
1628 1 : if (!asn)
1629 0 : goto done;
1630 :
1631 1 : ret = GKM_DATA_FAILURE;
1632 :
1633 1 : if (!egg_asn1x_get_bits_as_ulong (asn, key_usage, &n_bits))
1634 0 : goto done;
1635 :
1636 1 : ret = GKM_DATA_SUCCESS;
1637 :
1638 1 : done:
1639 1 : egg_asn1x_destroy (asn);
1640 1 : return ret;
1641 : }
1642 :
1643 : GkmDataResult
1644 1 : gkm_data_der_read_enhanced_usage (GBytes *data,
1645 : GQuark **usage_oids)
1646 : {
1647 1 : GkmDataResult ret = GKM_DATA_UNRECOGNIZED;
1648 1 : GNode *asn = NULL;
1649 : GNode *node;
1650 : GArray *array;
1651 : GQuark oid;
1652 : int i;
1653 :
1654 1 : asn = egg_asn1x_create_and_decode (pkix_asn1_tab, "ExtKeyUsageSyntax", data);
1655 1 : if (!asn)
1656 0 : goto done;
1657 :
1658 1 : ret = GKM_DATA_FAILURE;
1659 :
1660 1 : array = g_array_new (TRUE, TRUE, sizeof (GQuark));
1661 1 : for (i = 0; TRUE; ++i) {
1662 2 : node = egg_asn1x_node (asn, i + 1, NULL);
1663 2 : if (node == NULL)
1664 1 : break;
1665 :
1666 1 : oid = egg_asn1x_get_oid_as_quark (node);
1667 1 : g_array_append_val (array, oid);
1668 : }
1669 :
1670 1 : *usage_oids = (GQuark*)g_array_free (array, FALSE);
1671 1 : ret = GKM_DATA_SUCCESS;
1672 :
1673 1 : done:
1674 1 : egg_asn1x_destroy (asn);
1675 1 : return ret;
1676 : }
1677 :
1678 :
1679 : GBytes *
1680 1 : gkm_data_der_write_certificate (GNode *asn1)
1681 : {
1682 : GBytes *result;
1683 :
1684 1 : g_return_val_if_fail (asn1, NULL);
1685 :
1686 1 : result = egg_asn1x_encode (asn1, NULL);
1687 1 : if (result == NULL)
1688 0 : g_warning ("couldn't encode certificate: %s", egg_asn1x_message (asn1));
1689 :
1690 1 : return result;
1691 : }
|