Branch data Line data Source code
1 : : /*
2 : : * gnome-keyring
3 : : *
4 : : * Copyright (C) 2011 Collabora Ltd.
5 : : *
6 : : * This program is free software; you can redistribute it and/or modify
7 : : * it under the terms of the GNU Lesser General Public License as
8 : : * published by the Free Software Foundation; either version 2.1 of
9 : : * the License, or (at your option) any later version.
10 : : *
11 : : * This program is distributed in the hope that it will be useful, but
12 : : * WITHOUT ANY WARRANTY; without even the implied warranty of
13 : : * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 : : * Lesser General Public License for more details.
15 : : *
16 : : * 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 : : * Author: Stef Walter <stefw@collabora.co.uk>
20 : : */
21 : :
22 : : #include "config.h"
23 : :
24 : : #include "gcr-openpgp.h"
25 : : #include "gcr-internal.h"
26 : : #include "gcr-record.h"
27 : : #include "gcr-types.h"
28 : :
29 : : #include "egg/egg-hex.h"
30 : :
31 : : #include <gcrypt.h>
32 : :
33 : : #include <string.h>
34 : :
35 : : typedef enum {
36 : : OPENPGP_PKT_RESERVED = 0,
37 : : OPENPGP_PKT_PUBKEY_ENC = 1,
38 : : OPENPGP_PKT_SIGNATURE = 2,
39 : : OPENPGP_PKT_ONEPASS_SIG = 4,
40 : : OPENPGP_PKT_SECRET_KEY = 5,
41 : : OPENPGP_PKT_PUBLIC_KEY = 6,
42 : : OPENPGP_PKT_SECRET_SUBKEY = 7,
43 : : OPENPGP_PKT_COMPRESSED = 8,
44 : : OPENPGP_PKT_MARKER = 10,
45 : : OPENPGP_PKT_LITERAL = 11,
46 : : OPENPGP_PKT_RING_TRUST = 12,
47 : : OPENPGP_PKT_USER_ID = 13,
48 : : OPENPGP_PKT_PUBLIC_SUBKEY = 14,
49 : : OPENPGP_PKT_OLD_COMMENT = 16,
50 : : OPENPGP_PKT_ATTRIBUTE = 17,
51 : : OPENPGP_PKT_MDC = 19
52 : : } OpenpgpPktType;
53 : :
54 : : typedef enum {
55 : : OPENPGP_SIG_CREATION = 2,
56 : : OPENPGP_SIG_EXPIRY = 3,
57 : : OPENPGP_SIG_EXPORTABLE = 4,
58 : : OPENPGP_SIG_TRUST = 5,
59 : : OPENPGP_SIG_REGULAR_EXPRESSION = 6,
60 : : OPENPGP_SIG_REVOCABLE = 7,
61 : : OPENPGP_SIG_KEY_EXPIRY = 9,
62 : : OPENPGP_SIG_SYMMETRIC_ALGOS = 11,
63 : : OPENPGP_SIG_REVOCATION_KEY = 12,
64 : : OPENPGP_SIG_ISSUER = 16,
65 : : OPENPGP_SIG_NOTATION_DATA = 20,
66 : : OPENPGP_SIG_HASH_ALGOS = 21,
67 : : OPENPGP_SIG_COMPRESSION_ALGOS = 22,
68 : : OPENPGP_SIG_KEYSERVER_PREFS = 23,
69 : : OPENPGP_SIG_PREFERRED_KEYSERVER = 24,
70 : : OPENPGP_SIG_PRIMARY_USERID = 25,
71 : : OPENPGP_SIG_POLICY_URI = 26,
72 : : OPENPGP_SIG_KEY_FLAGS = 27,
73 : : OPENPGP_SIG_SIGNER_USERID = 28,
74 : : OPENPGP_SIG_REVOCATION_REASON = 29,
75 : : OPENPGP_SIG_FEATURES = 30,
76 : : OPENPGP_SIG_TARGET = 31,
77 : : OPENPGP_SIG_EMBEDDED_SIGNATURE = 32,
78 : : } OpenpgpSigPacket;
79 : :
80 : : static gboolean
81 : 3430 : read_byte (const guchar **at,
82 : : const guchar *end,
83 : : guint8 *result)
84 : : {
85 [ - + ]: 3430 : g_assert (at);
86 [ - + ]: 3430 : if (*at == end)
87 : 0 : *at = NULL;
88 [ - + ]: 3430 : if (*at == NULL)
89 : 0 : return FALSE;
90 [ + - ]: 3430 : if (result)
91 : 3430 : *result = *(*at);
92 : 3430 : (*at)++;
93 : 3430 : return TRUE;
94 : : }
95 : :
96 : : static gboolean
97 : 1832 : read_bytes (const guchar **at,
98 : : const guchar *end,
99 : : gpointer buffer,
100 : : gsize length)
101 : : {
102 [ - + ]: 1832 : g_assert (at);
103 [ - + ]: 1832 : if (*at + length > end)
104 : 0 : *at = NULL;
105 [ - + ]: 1832 : if (*at == NULL)
106 : 0 : return FALSE;
107 [ + + ]: 1832 : if (buffer != NULL)
108 : 1398 : memcpy (buffer, *at, length);
109 : 1832 : (*at) += length;
110 : 1832 : return TRUE;
111 : : }
112 : :
113 : : static gboolean
114 : 303 : read_uint32 (const guchar **at,
115 : : const guchar *end,
116 : : guint32 *value)
117 : : {
118 : : guchar buf[4];
119 [ - + ]: 303 : g_assert (at);
120 [ - + ]: 303 : if (!read_bytes (at, end, buf, 4))
121 : 0 : return FALSE;
122 [ + - ]: 303 : if (value)
123 : 303 : *value = buf[0] << 24 | buf[1] << 16 | buf[2] << 8 | buf[3];
124 : 303 : return TRUE;
125 : : }
126 : :
127 : : static gboolean
128 : 963 : read_uint16 (const guchar **at,
129 : : const guchar *end,
130 : : guint16 *value)
131 : : {
132 : : guchar buf[2];
133 [ - + ]: 963 : g_assert (at);
134 [ - + ]: 963 : if (!read_bytes (at, end, buf, 2))
135 : 0 : return FALSE;
136 [ + - ]: 963 : if (value)
137 : 963 : *value = buf[0] << 8 | buf[1];
138 : 963 : return TRUE;
139 : : }
140 : :
141 : : static gboolean
142 : 434 : read_mpi (const guchar **at,
143 : : const guchar *end,
144 : : guint16 *bits,
145 : : guchar **value)
146 : : {
147 : : gsize bytes;
148 : : guint16 b;
149 [ - + ]: 434 : g_assert (at);
150 [ + + ]: 434 : if (!bits)
151 : 350 : bits = &b;
152 [ - + ]: 434 : if (!read_uint16 (at, end, bits))
153 : 0 : return FALSE;
154 : 434 : bytes = (*bits + 7) / 8;
155 [ - + ]: 434 : if (bytes == 0)
156 : 0 : return FALSE;
157 [ - + ]: 434 : if (value)
158 : 0 : *value = g_malloc (bytes);
159 [ - + - + ]: 434 : if (!read_bytes (at, end, value ? *value : NULL, bytes)) {
160 [ # # ]: 0 : if (value)
161 : 0 : g_free (*value);
162 : 0 : return FALSE;
163 : : }
164 : 434 : return TRUE;
165 : : }
166 : :
167 : : static gboolean
168 : 843 : read_new_length (const guchar **at,
169 : : const guchar *end,
170 : : gsize *pkt_len)
171 : : {
172 : : guint8 c, c1;
173 : : guint32 val;
174 : :
175 [ - + ]: 843 : if (!read_byte (at, end, &c))
176 : 0 : return FALSE;
177 [ + + ]: 843 : if (c < 192) {
178 : 822 : *pkt_len = c;
179 [ + - + + ]: 21 : } else if (c >= 192 && c <= 223) {
180 [ - + ]: 12 : if (!read_byte (at, end, &c1))
181 : 0 : return FALSE;
182 : 12 : *pkt_len = ((c - 192) << 8) + c1 + 192;
183 [ + - ]: 9 : } else if (c == 255) {
184 [ - + ]: 9 : if (!read_uint32 (at, end, &val))
185 : 0 : return FALSE;
186 : 9 : *pkt_len = val;
187 : : } else {
188 : : /* We don't support partial length */
189 : 0 : return FALSE;
190 : : }
191 : :
192 : 843 : return TRUE;
193 : : }
194 : :
195 : : static gboolean
196 : 522 : read_old_length (const guchar **at,
197 : : const guchar *end,
198 : : guchar ctb,
199 : : gsize *pkt_len)
200 : : {
201 : 522 : gsize llen = ctb & 0x03;
202 : : guint16 v16;
203 : : guint32 v32;
204 : : guint8 c;
205 : :
206 [ + + ]: 522 : if (llen == 0) {
207 [ - + ]: 380 : if (!read_byte (at, end, &c))
208 : 0 : return FALSE;
209 : 380 : *pkt_len = c;
210 [ + - ]: 142 : } else if (llen == 1) {
211 [ - + ]: 142 : if (!read_uint16 (at, end, &v16))
212 : 0 : return FALSE;
213 : 142 : *pkt_len = v16;
214 [ # # ]: 0 : } else if (llen == 2) {
215 [ # # ]: 0 : if (!read_uint32 (at, end, &v32))
216 : 0 : return FALSE;
217 : 0 : *pkt_len = v32;
218 : : } else {
219 : 0 : *pkt_len = end - *at;
220 : : }
221 : :
222 : 522 : return TRUE;
223 : : }
224 : :
225 : : static GcrDataError
226 : 574 : read_openpgp_packet (const guchar **at,
227 : : const guchar *end,
228 : : guint8 *pkt_type,
229 : : gsize *length)
230 : : {
231 : : gboolean new_ctb;
232 : : guint8 ctb;
233 : : gboolean ret;
234 : :
235 [ - + ]: 574 : if (!read_byte (at, end, &ctb))
236 : 0 : return GCR_ERROR_UNRECOGNIZED;
237 [ + + ]: 574 : if (!(ctb & 0x80))
238 : 40 : return GCR_ERROR_UNRECOGNIZED;
239 : :
240 : : /* RFC2440 packet format. */
241 [ + + ]: 534 : if (ctb & 0x40) {
242 : 12 : *pkt_type = ctb & 0x3f;
243 : 12 : new_ctb = TRUE;
244 : :
245 : : /* the old RFC1991 packet format. */
246 : : } else {
247 : 522 : *pkt_type = ctb & 0x3f;
248 : 522 : *pkt_type >>= 2;
249 : 522 : new_ctb = FALSE;
250 : : }
251 : :
252 [ - + ]: 534 : if (*pkt_type > 63)
253 : 0 : return GCR_ERROR_UNRECOGNIZED;
254 : :
255 [ + + ]: 534 : if (new_ctb)
256 : 12 : ret = read_new_length (at, end, length);
257 : : else
258 : 522 : ret = read_old_length (at, end, ctb, length);
259 [ - + ]: 534 : if (!ret)
260 : 0 : return GCR_ERROR_UNRECOGNIZED;
261 : :
262 [ - + ]: 534 : if ((*at) + *length > end)
263 : 0 : return GCR_ERROR_FAILURE;
264 : :
265 : 534 : return GCR_SUCCESS;
266 : : }
267 : :
268 : : static gchar *
269 : 90 : hash_user_id_or_attribute (const guchar *beg,
270 : : const guchar *end)
271 : : {
272 : 90 : guint8 digest[20] = { 0, };
273 : :
274 [ - + ]: 90 : g_assert (beg != NULL);
275 [ - + ]: 90 : g_assert (end > beg);
276 : :
277 : 90 : gcry_md_hash_buffer (GCRY_MD_RMD160, digest, beg, end - beg);
278 : 90 : return egg_hex_encode_full (digest, sizeof (digest), TRUE, NULL, 0);
279 : : }
280 : :
281 : : static gboolean
282 : 0 : parse_v3_rsa_bits_and_keyid (const guchar **at,
283 : : const guchar *end,
284 : : guint16 *bits,
285 : : gchar **keyid)
286 : : {
287 : : guchar *n;
288 : : gsize bytes;
289 : :
290 [ # # ]: 0 : g_assert (bits);
291 [ # # ]: 0 : g_assert (keyid);
292 : :
293 : : /* Read in the modulus */
294 [ # # ]: 0 : if (!read_mpi (at, end, bits, &n))
295 : 0 : return FALSE;
296 : :
297 : : /* Last 64-bits of modulus are keyid */
298 : 0 : bytes = (*bits + 7) / 8;
299 [ # # ]: 0 : if (bytes < 8) {
300 : 0 : g_free (n);
301 : 0 : return FALSE;
302 : : }
303 : :
304 : 0 : *keyid = egg_hex_encode_full (n + (bytes - 8), 8, TRUE, NULL, 0);
305 : 0 : return TRUE;
306 : : }
307 : :
308 : : static gchar *
309 : 84 : hash_v4_keyid (const guchar *data,
310 : : const guchar *end,
311 : : gchar **fingerprint)
312 : : {
313 : : gcry_md_hd_t mdh;
314 : : gcry_error_t gcry;
315 : : guchar header[3];
316 : : guint8 *digest;
317 : : gchar *keyid;
318 : : gsize len;
319 : :
320 : : /*
321 : : * Both primary and subkeys use the public key tag byte
322 : : * 0x99 to construct the hash. So we skip over that here.
323 : : */
324 : :
325 [ - + ]: 84 : g_assert (data != NULL);
326 [ - + ]: 84 : g_assert (end > data);
327 : :
328 : 84 : len = end - data;
329 [ - + ]: 84 : g_return_val_if_fail (len < G_MAXUSHORT, NULL);
330 : :
331 : 84 : header[0] = 0x99;
332 : 84 : header[1] = len >> 8 & 0xff;
333 : 84 : header[2] = len & 0xff;
334 : :
335 : 84 : gcry = gcry_md_open (&mdh, GCRY_MD_SHA1, 0);
336 [ - + ]: 84 : g_return_val_if_fail (gcry == 0, NULL);
337 : :
338 : 84 : gcry_md_write (mdh, header, 3);
339 : 84 : gcry_md_write (mdh, data, len);
340 : :
341 : 84 : digest = gcry_md_read (mdh, 0);
342 : 84 : keyid = egg_hex_encode_full (digest + 12, 8, TRUE, NULL, 0);
343 [ + - ]: 84 : if (fingerprint)
344 : 84 : *fingerprint = egg_hex_encode_full (digest, 20, TRUE, NULL, 0);
345 : 84 : gcry_md_close (mdh);
346 : :
347 : 84 : return keyid;
348 : : }
349 : :
350 : : static gboolean
351 : 84 : parse_v4_algo_bits (const guchar **at,
352 : : const guchar *end,
353 : : guint8 algo,
354 : : guint16 *bits)
355 : : {
356 [ + + + - ]: 84 : switch (algo) {
357 : 51 : case GCR_OPENPGP_ALGO_RSA:
358 : : case GCR_OPENPGP_ALGO_RSA_E:
359 : : case GCR_OPENPGP_ALGO_RSA_S:
360 [ + - - + ]: 102 : if (!read_mpi (at, end, bits, NULL) ||
361 : 51 : !read_mpi (at, end, NULL, NULL))
362 : 0 : return FALSE;
363 : 51 : return TRUE;
364 : 27 : case GCR_OPENPGP_ALGO_DSA:
365 [ + - + - ]: 54 : if (!read_mpi (at, end, bits, NULL) ||
366 [ + - ]: 54 : !read_mpi (at, end, NULL, NULL) ||
367 [ - + ]: 54 : !read_mpi (at, end, NULL, NULL) ||
368 : 27 : !read_mpi (at, end, NULL, NULL))
369 : 0 : return FALSE;
370 : 27 : return TRUE;
371 : 6 : case GCR_OPENPGP_ALGO_ELG_E:
372 [ + - + - ]: 12 : if (!read_mpi (at, end, bits, NULL) ||
373 [ - + ]: 12 : !read_mpi (at, end, NULL, NULL) ||
374 : 6 : !read_mpi (at, end, NULL, NULL))
375 : 0 : return FALSE;
376 : 6 : return TRUE;
377 : 0 : default: /* Unsupported key */
378 : 0 : return FALSE;
379 : : }
380 : : }
381 : :
382 : : static const gchar *
383 : 72 : default_caps_for_algo (guint8 algo)
384 : : {
385 [ + - - + : 72 : switch (algo) {
+ - ]
386 : 39 : case GCR_OPENPGP_ALGO_RSA:
387 : 39 : return "cse";
388 : 0 : case GCR_OPENPGP_ALGO_RSA_E:
389 : 0 : return "e";
390 : 0 : case GCR_OPENPGP_ALGO_RSA_S:
391 : 0 : return "s";
392 : 6 : case GCR_OPENPGP_ALGO_ELG_E:
393 : 6 : return "e";
394 : 27 : case GCR_OPENPGP_ALGO_DSA:
395 : 27 : return "sca";
396 : 0 : default:
397 : 0 : return "";
398 : : }
399 : : }
400 : :
401 : : static gboolean
402 : 84 : parse_public_key_or_subkey (GQuark schema,
403 : : guint n_columns,
404 : : const guchar *beg,
405 : : const guchar **at,
406 : : const guchar *end,
407 : : GcrOpenpgpParseFlags flags,
408 : : GPtrArray *records)
409 : : {
410 : 84 : gchar *fingerprint = NULL;
411 : : gchar *keyid;
412 : : GcrRecord *record;
413 : : guint8 version;
414 : : guint32 timestamp;
415 : 84 : guint16 ndays = 0;
416 : : guint8 algo;
417 : : guint16 bits;
418 : : gulong expiry;
419 : : const guchar *data;
420 : :
421 : : /* Start of actual key data in packet */
422 : 84 : data = *at;
423 : :
424 : : /* First byte is version */
425 [ - + ]: 84 : if (!read_byte (at, end, &version))
426 : 0 : return FALSE;
427 [ + - - + ]: 84 : if (version < 2 || version > 4)
428 : 0 : return FALSE;
429 : :
430 : : /* Next a 4 byte create date */
431 [ - + ]: 84 : if (!read_uint32 (at, end, ×tamp))
432 : 0 : return FALSE;
433 : : /* If version 2 or 3, validity days comes next */
434 [ - + ]: 84 : if (version < 4) {
435 [ # # ]: 0 : if (!read_uint16 (at, end, &ndays))
436 : 0 : return FALSE;
437 : : }
438 : :
439 : : /* Algorithm */
440 [ - + ]: 84 : if (!read_byte (at, end, &algo))
441 : 0 : return FALSE;
442 : :
443 : : /* For version 2 and 3, only RSA, keyid is low 64-bits of modulus */
444 [ - + ]: 84 : if (version < 4) {
445 [ # # ]: 0 : if (!parse_v3_rsa_bits_and_keyid (at, end, &bits, &keyid))
446 : 0 : return FALSE;
447 : :
448 : : /* For version 4 */
449 : : } else {
450 [ - + ]: 84 : if (!parse_v4_algo_bits (at, end, algo, &bits))
451 : 0 : return FALSE;
452 : 84 : keyid = hash_v4_keyid (data, *at, &fingerprint);
453 : : }
454 : :
455 : 84 : record = _gcr_record_new (schema, n_columns, ':');
456 : 84 : _gcr_record_set_uint (record, GCR_RECORD_KEY_BITS, bits);
457 : 84 : _gcr_record_set_uint (record, GCR_RECORD_KEY_ALGO, algo);
458 : 84 : _gcr_record_take_raw (record, GCR_RECORD_KEY_KEYID, keyid);
459 : 84 : _gcr_record_set_ulong (record, GCR_RECORD_KEY_TIMESTAMP, timestamp);
460 [ + + + + ]: 84 : if (schema != GCR_RECORD_SCHEMA_SEC && schema != GCR_RECORD_SCHEMA_SSB)
461 : 72 : _gcr_record_set_raw (record, GCR_RECORD_PUB_CAPS, default_caps_for_algo (algo));
462 : :
463 [ - + ]: 84 : if (ndays > 0) {
464 : 0 : expiry = (gulong)timestamp + ((gulong)ndays * 86400);
465 : 0 : _gcr_record_set_ulong (record, GCR_RECORD_KEY_EXPIRY, expiry);
466 : : }
467 : :
468 : 84 : g_ptr_array_add (records, record);
469 : :
470 [ + - + + : 84 : if (fingerprint && (schema == GCR_RECORD_SCHEMA_PUB || schema == GCR_RECORD_SCHEMA_SEC)) {
+ + ]
471 : 42 : record = _gcr_record_new (GCR_RECORD_SCHEMA_FPR, GCR_RECORD_FPR_MAX, ':');
472 : 42 : _gcr_record_take_raw (record, GCR_RECORD_FPR_FINGERPRINT, fingerprint);
473 : 42 : g_ptr_array_add (records, record);
474 : 42 : fingerprint = NULL;
475 : : }
476 : :
477 : 84 : g_free (fingerprint);
478 : 84 : return TRUE;
479 : : }
480 : :
481 : : static gboolean
482 : 12 : parse_secret_key_or_subkey (GQuark schema,
483 : : const guchar *beg,
484 : : const guchar **at,
485 : : const guchar *end,
486 : : GcrOpenpgpParseFlags flags,
487 : : GPtrArray *records)
488 : : {
489 : : /*
490 : : * Identical to a public key, with extra crap after it. The
491 : : * extra crap is hard to parse and doesn't add anything to
492 : : * the records, so just skip over it.
493 : : *
494 : : * Also don't print out trust, that doesn't make sense for
495 : : * secret keys.
496 : : */
497 : :
498 [ - + ]: 12 : if (!parse_public_key_or_subkey (schema, GCR_RECORD_SEC_MAX,
499 : : beg, at, end, flags, records))
500 : 0 : return FALSE;
501 : :
502 : 12 : *at = end;
503 : 12 : return TRUE;
504 : : }
505 : :
506 : : static gboolean
507 : 75 : parse_user_id (const guchar *beg,
508 : : const guchar **at,
509 : : const guchar *end,
510 : : GcrOpenpgpParseFlags flags,
511 : : GPtrArray *records)
512 : : {
513 : : gchar *string;
514 : : GcrRecord *record;
515 : : gchar *fingerprint;
516 : :
517 [ - + ]: 75 : g_assert (at);
518 [ + - + - : 75 : if (!*at || !end || *at > end)
- + ]
519 : 0 : return FALSE;
520 : :
521 : 75 : string = g_strndup ((gchar *)*at, end - *at);
522 : :
523 : 75 : fingerprint = hash_user_id_or_attribute (*at, end);
524 : 75 : record = _gcr_record_new (GCR_RECORD_SCHEMA_UID, GCR_RECORD_UID_MAX, ':');
525 : 75 : _gcr_record_take_raw (record, GCR_RECORD_UID_FINGERPRINT, fingerprint);
526 : 75 : _gcr_record_set_string (record, GCR_RECORD_UID_USERID, string);
527 : 75 : g_free (string);
528 : :
529 : 75 : g_ptr_array_add (records, record);
530 : :
531 : 75 : *at = end;
532 : 75 : return TRUE;
533 : : }
534 : :
535 : : static gboolean
536 : 6 : parse_user_attribute_packet (const guchar *beg,
537 : : const guchar **at,
538 : : const guchar *end,
539 : : guchar subpkt_type,
540 : : GPtrArray *records)
541 : : {
542 : : GcrRecord *record;
543 : : gchar *fingerprint;
544 : :
545 : 6 : record = _gcr_record_new (GCR_RECORD_SCHEMA_XA1, GCR_RECORD_XA1_MAX, ':');
546 : 6 : _gcr_record_set_uint (record, GCR_RECORD_XA1_LENGTH, end - *at);
547 : 6 : _gcr_record_set_uint (record, GCR_RECORD_XA1_TYPE, subpkt_type);
548 : 6 : fingerprint = hash_user_id_or_attribute (*at, end);
549 : 6 : _gcr_record_take_raw (record, GCR_RECORD_XA1_FINGERPRINT, fingerprint);
550 : 6 : _gcr_record_set_base64 (record, GCR_RECORD_XA1_DATA, *at, end - *at);
551 : :
552 : 6 : g_ptr_array_add (records, record);
553 : :
554 : 6 : *at = end;
555 : 6 : return TRUE;
556 : : }
557 : :
558 : : static gboolean
559 : 9 : parse_user_attribute (const guchar *beg,
560 : : const guchar **at,
561 : : const guchar *end,
562 : : GcrOpenpgpParseFlags flags,
563 : : GPtrArray *records)
564 : : {
565 : : gsize subpkt_len;
566 : 9 : guint count = 0;
567 : : const guchar *start;
568 : : const guchar *subpkt_beg;
569 : : guint8 subpkt_type;
570 : : gchar *fingerprint;
571 : : gchar *string;
572 : : GcrRecord *record;
573 : :
574 : 9 : start = *at;
575 [ + + ]: 18 : while (*at != end) {
576 : 9 : subpkt_beg = *at;
577 : :
578 [ + - - + ]: 18 : if (!read_new_length (at, end, &subpkt_len) ||
579 : 9 : !read_byte (at, end, &subpkt_type))
580 : 0 : return FALSE;
581 : :
582 : 9 : count++;
583 : :
584 [ + + ]: 9 : if (flags & GCR_OPENPGP_PARSE_ATTRIBUTES) {
585 [ - + ]: 6 : if (!parse_user_attribute_packet (subpkt_beg, at,
586 : 6 : *at + (subpkt_len - 1),
587 : : subpkt_type, records))
588 : 0 : return FALSE;
589 : :
590 : : /* We already progressed one extra byte for the subpkt_type */
591 : : } else {
592 : 3 : *at += (subpkt_len - 1);
593 : : }
594 : : }
595 : :
596 : 9 : fingerprint = hash_user_id_or_attribute (start, end);
597 : 9 : string = g_strdup_printf ("%d %d", count, (guint)(*at - start));
598 : 9 : record = _gcr_record_new (GCR_RECORD_SCHEMA_UAT, GCR_RECORD_UAT_MAX, ':');
599 : 9 : _gcr_record_take_raw (record, GCR_RECORD_UAT_FINGERPRINT, fingerprint);
600 : 9 : _gcr_record_take_raw (record, GCR_RECORD_UAT_COUNT_SIZE, string);
601 : :
602 : 9 : g_ptr_array_add (records, record);
603 : 9 : return TRUE;
604 : : }
605 : :
606 : : static gboolean
607 : 129 : skip_signature_mpis (const guchar **at,
608 : : const guchar *end,
609 : : guint8 algo)
610 : : {
611 [ + + - ]: 129 : switch (algo) {
612 : :
613 : : /* RSA signature value */
614 : 52 : case GCR_OPENPGP_ALGO_RSA:
615 : 52 : return read_mpi (at, end, NULL, NULL);
616 : :
617 : : /* DSA values r and s */
618 : 77 : case GCR_OPENPGP_ALGO_DSA:
619 [ + - + - ]: 154 : return read_mpi (at, end, NULL, NULL) &&
620 : 77 : read_mpi (at, end, NULL, NULL);
621 : 0 : default:
622 : 0 : return FALSE;
623 : : }
624 : : }
625 : :
626 : : static gboolean
627 : 0 : parse_v3_signature (const guchar **at,
628 : : const guchar *end,
629 : : GcrOpenpgpParseFlags flags,
630 : : GPtrArray *records)
631 : : {
632 : : guchar keyid[8];
633 : : guint8 sig_type;
634 : : guint8 sig_len;
635 : : guint32 sig_time;
636 : : guint8 key_algo;
637 : : guint8 hash_algo;
638 : : guint16 left_bits;
639 : : GcrRecord *record;
640 : : gchar *value;
641 : :
642 [ # # # # ]: 0 : if (!read_byte (at, end, &sig_len) || sig_len != 5)
643 : 0 : return FALSE;
644 : :
645 [ # # # # ]: 0 : if (!read_byte (at, end, &sig_type) ||
646 [ # # ]: 0 : !read_uint32 (at, end, &sig_time) ||
647 [ # # ]: 0 : !read_bytes (at, end, keyid, 8) ||
648 [ # # ]: 0 : !read_byte (at, end, &key_algo) ||
649 [ # # ]: 0 : !read_byte (at, end, &hash_algo) ||
650 [ # # ]: 0 : !read_uint16 (at, end, &left_bits) ||
651 : 0 : !skip_signature_mpis (at, end, key_algo))
652 : 0 : return FALSE;
653 : :
654 [ # # ]: 0 : if (flags & GCR_OPENPGP_PARSE_SIGNATURES) {
655 : 0 : record = _gcr_record_new (GCR_RECORD_SCHEMA_SIG, GCR_RECORD_SIG_MAX, ':');
656 : 0 : _gcr_record_set_uint (record, GCR_RECORD_SIG_ALGO, key_algo);
657 : 0 : value = egg_hex_encode_full (keyid, sizeof (keyid), TRUE, NULL, 0);
658 : 0 : _gcr_record_take_raw (record, GCR_RECORD_SIG_KEYID, value);
659 : 0 : _gcr_record_set_ulong (record, GCR_RECORD_SIG_TIMESTAMP, sig_time);
660 : 0 : value = g_strdup_printf ("%02xx", (guint)sig_type);
661 : 0 : _gcr_record_take_raw (record, GCR_RECORD_SIG_CLASS, value);
662 : 0 : g_ptr_array_add (records, record);
663 : : }
664 : :
665 : 0 : return TRUE;
666 : : }
667 : :
668 : : typedef struct {
669 : : gulong key_expiry;
670 : : gboolean exportable;
671 : : gboolean primary;
672 : : guint8 key_flags;
673 : : GcrRecord *revocation;
674 : : } SigSubpacket;
675 : :
676 : : static gboolean
677 : 3 : parse_v4_signature_revocation (const guchar **at,
678 : : const guchar *end,
679 : : GcrRecord *revocation)
680 : : {
681 : : guchar fingerprint[20];
682 : : gchar *value;
683 : : guint8 klass;
684 : : guint8 algo;
685 : :
686 [ + - + - ]: 6 : if (!read_byte (at, end, &klass) ||
687 [ - + ]: 6 : !read_byte (at, end, &algo) ||
688 : 3 : !read_bytes (at, end, fingerprint, 20))
689 : 0 : return FALSE;
690 : :
691 : 3 : _gcr_record_set_uint (revocation, GCR_RECORD_RVK_ALGO, algo);
692 : 3 : value = egg_hex_encode_full (fingerprint, 20, TRUE, NULL, 0);
693 : 3 : _gcr_record_take_raw (revocation, GCR_RECORD_RVK_FINGERPRINT, value);
694 : 3 : value = g_strdup_printf ("%02X", (guint)klass);
695 : 3 : _gcr_record_take_raw (revocation, GCR_RECORD_RVK_CLASS, value);
696 : :
697 : 3 : return TRUE;
698 : : }
699 : :
700 : : static gboolean
701 : 822 : parse_v4_signature_subpacket (const guchar **at,
702 : : const guchar *end,
703 : : guint8 sub_type,
704 : : GcrRecord *record,
705 : : SigSubpacket *subpkt)
706 : : {
707 : : guchar keyid[8];
708 : : guint32 when;
709 : : guint8 byte;
710 : : gboolean critical;
711 : : gchar *value;
712 : :
713 : 822 : critical = (sub_type & 0x80) ? TRUE : FALSE;
714 : 822 : sub_type &= ~0xC0;
715 : :
716 [ + + + - : 822 : switch (sub_type) {
- + + - +
+ + ]
717 : 129 : case OPENPGP_SIG_CREATION:
718 [ - + ]: 129 : if (!read_uint32 (at, end, &when))
719 : 0 : return FALSE;
720 : 129 : _gcr_record_set_ulong (record, GCR_RECORD_SIG_TIMESTAMP, when);
721 : 129 : return TRUE;
722 : 129 : case OPENPGP_SIG_ISSUER:
723 [ - + ]: 129 : if (!read_bytes (at, end, keyid, 8))
724 : 0 : return FALSE;
725 : 129 : value = egg_hex_encode_full (keyid, 8, TRUE, NULL, 0);
726 : 129 : _gcr_record_take_raw (record, GCR_RECORD_SIG_KEYID, value);
727 : 129 : return TRUE;
728 : 81 : case OPENPGP_SIG_KEY_EXPIRY:
729 [ - + ]: 81 : if (!read_uint32 (at, end, &when))
730 : 0 : return FALSE;
731 : 81 : subpkt->key_expiry = when;
732 : 81 : return TRUE;
733 : 0 : case OPENPGP_SIG_EXPIRY:
734 [ # # ]: 0 : if (!read_uint32 (at, end, &when))
735 : 0 : return FALSE;
736 : 0 : _gcr_record_set_ulong (record, GCR_RECORD_SIG_EXPIRY, when);
737 : 0 : return TRUE;
738 : 0 : case OPENPGP_SIG_EXPORTABLE:
739 [ # # ]: 0 : if (!read_byte (at, end, &byte))
740 : 0 : return FALSE;
741 [ # # # # ]: 0 : if (byte != 0 && byte != 1)
742 : 0 : return FALSE;
743 : 0 : subpkt->exportable = (byte == 0 ? FALSE : TRUE);
744 : 0 : return TRUE;
745 : :
746 : 13 : case OPENPGP_SIG_PRIMARY_USERID:
747 [ - + ]: 13 : if (!read_byte (at, end, &byte))
748 : 0 : return FALSE;
749 [ + - - + ]: 13 : if (byte != 0 && byte != 1)
750 : 0 : return FALSE;
751 : 13 : subpkt->primary = byte;
752 : 13 : return TRUE;
753 : :
754 : 87 : case OPENPGP_SIG_KEY_FLAGS:
755 [ - + ]: 87 : if (!read_byte (at, end, &byte))
756 : 0 : return FALSE;
757 : 87 : *at = end; /* N octets of flags */
758 : 87 : subpkt->key_flags = byte;
759 : 87 : return TRUE;
760 : :
761 : 0 : case OPENPGP_SIG_SIGNER_USERID:
762 : 0 : value = g_strndup ((gchar *)*at, end - *at);
763 : 0 : _gcr_record_set_string (record, GCR_RECORD_SIG_USERID, value);
764 : 0 : g_free (value);
765 : 0 : return TRUE;
766 : :
767 : 3 : case OPENPGP_SIG_REVOCATION_KEY:
768 : 3 : _gcr_record_free (subpkt->revocation);
769 : 3 : subpkt->revocation = _gcr_record_new (GCR_RECORD_SCHEMA_RVK, GCR_RECORD_RVK_MAX, ':');
770 : 3 : return parse_v4_signature_revocation (at, end, subpkt->revocation);
771 : :
772 : : /* Ignored */
773 : 354 : case OPENPGP_SIG_SYMMETRIC_ALGOS:
774 : : case OPENPGP_SIG_HASH_ALGOS:
775 : : case OPENPGP_SIG_COMPRESSION_ALGOS:
776 : : case OPENPGP_SIG_REVOCABLE:
777 : : case OPENPGP_SIG_TRUST:
778 : : case OPENPGP_SIG_REGULAR_EXPRESSION:
779 : : case OPENPGP_SIG_NOTATION_DATA:
780 : : case OPENPGP_SIG_KEYSERVER_PREFS:
781 : : case OPENPGP_SIG_PREFERRED_KEYSERVER:
782 : : case OPENPGP_SIG_POLICY_URI:
783 : : case OPENPGP_SIG_REVOCATION_REASON:
784 : : case OPENPGP_SIG_FEATURES:
785 : : case OPENPGP_SIG_TARGET:
786 : : case OPENPGP_SIG_EMBEDDED_SIGNATURE:
787 : 354 : *at = end;
788 : 354 : return TRUE;
789 : :
790 : : /* Unrecognized */
791 : 26 : default:
792 : : /* Critical, but not recognized */
793 [ - + ]: 26 : if (critical)
794 : 0 : return FALSE;
795 : 26 : *at = end;
796 : 26 : return TRUE;
797 : : }
798 : :
799 : : }
800 : :
801 : : static gboolean
802 : 258 : parse_v4_signature_subpackets (const guchar **at,
803 : : const guchar *end,
804 : : GcrRecord *record,
805 : : SigSubpacket *subpkt)
806 : : {
807 : : gsize length;
808 : : guint8 sub_type;
809 : : const guchar *stop;
810 : :
811 [ + + ]: 1080 : while (*at != end) {
812 [ + - + - ]: 1644 : if (!read_new_length (at, end, &length) ||
813 : 822 : !read_byte (at, end, &sub_type) ||
814 [ - + ]: 822 : length == 0)
815 : 0 : return FALSE;
816 : :
817 : : /* The length includes the sub_type */
818 : 822 : length--;
819 : 822 : stop = *at + length;
820 [ - + ]: 822 : if (stop > end)
821 : 0 : return FALSE;
822 : :
823 : : /* Actually parse the sub packets */
824 [ - + ]: 822 : if (!parse_v4_signature_subpacket (at, stop, sub_type, record, subpkt))
825 : 0 : return FALSE;
826 [ - + ]: 822 : if (*at != stop)
827 : 0 : return FALSE;
828 : : }
829 : :
830 : 258 : return TRUE;
831 : : }
832 : :
833 : : static GcrRecord *
834 : 75 : uid_or_uat_find_for_self_signature (GPtrArray *records,
835 : : guint8 sig_type)
836 : : {
837 : : GcrRecord *record;
838 : : GQuark schema;
839 : :
840 [ - + ]: 75 : if (records->len == 0)
841 : 0 : return NULL;
842 : :
843 [ + - ]: 75 : switch (sig_type) {
844 : : /* Generic certification of a key or userid */
845 : 75 : case 0x10: case 0x11: case 0x12: case 0x13:
846 : 75 : record = records->pdata[records->len - 1];
847 : 75 : schema = _gcr_record_get_schema (record);
848 [ + + + - ]: 84 : if (schema == GCR_RECORD_SCHEMA_UID ||
849 : 9 : schema == GCR_RECORD_SCHEMA_UAT)
850 : 75 : return record;
851 : 0 : return NULL;
852 : :
853 : 0 : default:
854 : 0 : return NULL;
855 : : }
856 : :
857 : : }
858 : :
859 : : static GcrRecord *
860 : 129 : key_or_sub_find_for_self_signature (GPtrArray *records,
861 : : guint8 sig_type,
862 : : const gchar *keyid)
863 : : {
864 : : GcrRecord *record;
865 : : const gchar *check;
866 : : GQuark schema;
867 : : gint i;
868 : :
869 [ - + ]: 129 : if (records->len == 0)
870 : 0 : return NULL;
871 : :
872 [ + + + ]: 129 : switch (sig_type) {
873 : : /* Generic certification of a key or userid */
874 : 84 : case 0x10: case 0x11: case 0x12: case 0x13:
875 [ + - ]: 426 : for (i = records->len - 1; i >= 0; i--) {
876 : 426 : record = records->pdata[i];
877 : 426 : schema = _gcr_record_get_schema (record);
878 [ + + + + ]: 426 : if (schema == GCR_RECORD_SCHEMA_PUB || schema == GCR_RECORD_SCHEMA_SEC) {
879 : 84 : check = _gcr_record_get_raw (record, GCR_RECORD_KEY_KEYID);
880 [ + - + - ]: 84 : return (check != NULL && g_str_equal (check, keyid)) ? record : NULL;
881 : : }
882 : : }
883 : 0 : return NULL;
884 : :
885 : : /* (Primary) Subkey Binding Signature */
886 : 42 : case 0x18: case 0x19:
887 : 42 : record = records->pdata[records->len - 1];
888 : 42 : schema = _gcr_record_get_schema (record);
889 [ + + ]: 42 : if (schema == GCR_RECORD_SCHEMA_SUB)
890 : 36 : return record;
891 : 6 : return NULL;
892 : :
893 : 3 : default:
894 : 3 : return NULL;
895 : : }
896 : : }
897 : :
898 : : static void
899 : 81 : pub_or_sub_set_key_caps (GcrRecord *record,
900 : : guint8 key_flags)
901 : : {
902 : : GString *string;
903 : : GQuark schema;
904 : :
905 : 81 : schema = _gcr_record_get_schema (record);
906 [ + + - + ]: 81 : if (schema == GCR_RECORD_SCHEMA_SEC || schema == GCR_RECORD_SCHEMA_SSB)
907 : 9 : return;
908 : :
909 : 72 : string = g_string_sized_new (8);
910 [ + + ]: 72 : if (key_flags & 0x02)
911 : 49 : g_string_append_c (string, 's');
912 [ + + ]: 72 : if (key_flags & 0x01)
913 : 42 : g_string_append_c (string, 'c');
914 [ + + - + ]: 72 : if (key_flags & 0x04 || key_flags & 0x08)
915 : 23 : g_string_append_c (string, 'e');
916 [ - + ]: 72 : if (key_flags & 0x20)
917 : 0 : g_string_append_c (string, 'a');
918 : :
919 : 72 : _gcr_record_take_raw (record, GCR_RECORD_PUB_CAPS,
920 : : g_string_free (string, FALSE));
921 : : }
922 : :
923 : : static gboolean
924 : 129 : parse_v4_signature (const guchar **at,
925 : : const guchar *end,
926 : : GcrOpenpgpParseFlags flags,
927 : : GPtrArray *records)
928 : : {
929 : : guint8 sig_type;
930 : : guint8 key_algo;
931 : : guint8 hash_algo;
932 : : guint16 hashed_len;
933 : : guint16 unhashed_len;
934 : : guint16 left_bits;
935 : : GcrRecord *record;
936 : : GcrRecord *key, *uid;
937 : : const gchar *keyid;
938 : : gchar *value;
939 : : const guchar *stop;
940 : : gulong timestamp;
941 : :
942 : : /* Information to transfer back onto the key record */
943 : 129 : SigSubpacket subpkt = { 0, };
944 : 129 : subpkt.exportable = 1;
945 : :
946 [ + - + - ]: 258 : if (!read_byte (at, end, &sig_type) ||
947 [ + - ]: 258 : !read_byte (at, end, &key_algo) ||
948 [ - + ]: 258 : !read_byte (at, end, &hash_algo) ||
949 : 129 : !read_uint16 (at, end, &hashed_len))
950 : 0 : return FALSE;
951 : :
952 : : /* Hashed subpackets which we use */
953 : 129 : record = _gcr_record_new (GCR_RECORD_SCHEMA_SIG, GCR_RECORD_SIG_MAX, ':');
954 : 129 : stop = *at + hashed_len;
955 [ + - - + ]: 258 : if (stop > end ||
956 : 129 : !parse_v4_signature_subpackets (at, stop, record, &subpkt)) {
957 : 0 : _gcr_record_free (record);
958 : 0 : _gcr_record_free (subpkt.revocation);
959 : 0 : return FALSE;
960 : : }
961 : :
962 : : /* Includes unhashed subpackets, which we skip over */
963 [ - + ]: 129 : if (!read_uint16 (at, end, &unhashed_len)) {
964 : 0 : _gcr_record_free (record);
965 : 0 : _gcr_record_free (subpkt.revocation);
966 : 0 : return FALSE;
967 : : }
968 : :
969 : 129 : stop = *at + unhashed_len;
970 [ + - + - ]: 258 : if (stop > end ||
971 [ + - ]: 258 : !parse_v4_signature_subpackets (at, stop, record, &subpkt) ||
972 [ - + ]: 258 : !read_uint16 (at, end, &left_bits) ||
973 : 129 : !skip_signature_mpis (at, end, key_algo)) {
974 : 0 : _gcr_record_free (record);
975 : 0 : _gcr_record_free (subpkt.revocation);
976 : 0 : return FALSE;
977 : : }
978 : :
979 [ + + ]: 129 : if (subpkt.revocation) {
980 : 3 : g_ptr_array_add (records, subpkt.revocation);
981 : 3 : subpkt.revocation = NULL;
982 : : }
983 : :
984 : : /* Fill in information on previous key or subkey */
985 : 129 : keyid = _gcr_record_get_raw (record, GCR_RECORD_SIG_KEYID);
986 : 129 : key = key_or_sub_find_for_self_signature (records, sig_type, keyid);
987 [ + + ]: 129 : if (key != NULL) {
988 [ + + ]: 120 : if (subpkt.key_expiry != 0) {
989 [ + - ]: 78 : if (_gcr_record_get_ulong (key, GCR_RECORD_KEY_TIMESTAMP, ×tamp))
990 : 78 : _gcr_record_set_ulong (key, GCR_RECORD_KEY_EXPIRY, timestamp + subpkt.key_expiry);
991 : : }
992 [ + + ]: 120 : if (subpkt.key_flags != 0)
993 : 81 : pub_or_sub_set_key_caps (key, subpkt.key_flags);
994 : : }
995 : :
996 [ + + + + ]: 129 : if (key && _gcr_record_get_schema (key) == GCR_RECORD_SCHEMA_PUB) {
997 : 75 : uid = uid_or_uat_find_for_self_signature (records, sig_type);
998 [ + - ]: 75 : if (uid != NULL) {
999 [ + - ]: 75 : if (_gcr_record_get_ulong (record, GCR_RECORD_SIG_TIMESTAMP, ×tamp))
1000 : 75 : _gcr_record_set_ulong (uid, GCR_RECORD_UID_TIMESTAMP, timestamp);
1001 : : }
1002 : : }
1003 : :
1004 [ + + ]: 129 : if (flags & GCR_OPENPGP_PARSE_SIGNATURES) {
1005 : 89 : _gcr_record_set_uint (record, GCR_RECORD_SIG_ALGO, key_algo);
1006 : 89 : value = g_strdup_printf ("%02x%s", (guint)sig_type,
1007 [ + - ]: 89 : subpkt.exportable ? "x" : "l");
1008 : 89 : _gcr_record_take_raw (record, GCR_RECORD_SIG_CLASS, value);
1009 : 89 : g_ptr_array_add (records, record);
1010 : : } else {
1011 : 40 : _gcr_record_free (record);
1012 : : }
1013 : :
1014 : 129 : return TRUE;
1015 : : }
1016 : :
1017 : : static gboolean
1018 : 129 : parse_signature (const guchar *beg,
1019 : : const guchar **at,
1020 : : const guchar *end,
1021 : : GcrOpenpgpParseFlags flags,
1022 : : GPtrArray *records)
1023 : : {
1024 : : guint8 version;
1025 : :
1026 [ - + ]: 129 : if (!read_byte (at, end, &version))
1027 : 0 : return FALSE;
1028 : :
1029 [ - + ]: 129 : if (version == 3)
1030 : 0 : return parse_v3_signature (at, end, flags, records);
1031 [ + - ]: 129 : else if (version == 4)
1032 : 129 : return parse_v4_signature (at, end, flags, records);
1033 : : else
1034 : 0 : return FALSE;
1035 : : }
1036 : :
1037 : : static GcrDataFormat
1038 : 390 : parse_openpgp_packet (const guchar *beg,
1039 : : const guchar *at,
1040 : : const guchar *end,
1041 : : guint8 pkt_type,
1042 : : GcrOpenpgpParseFlags flags,
1043 : : GPtrArray *records)
1044 : : {
1045 : : gboolean ret;
1046 : :
1047 [ + + + + : 390 : switch (pkt_type) {
+ + + +
- ]
1048 : 36 : case OPENPGP_PKT_PUBLIC_KEY:
1049 : 36 : ret = parse_public_key_or_subkey (GCR_RECORD_SCHEMA_PUB, GCR_RECORD_PUB_MAX,
1050 : : beg, &at, end, flags, records);
1051 : 36 : break;
1052 : 36 : case OPENPGP_PKT_PUBLIC_SUBKEY:
1053 : 36 : ret = parse_public_key_or_subkey (GCR_RECORD_SCHEMA_SUB, GCR_RECORD_PUB_MAX,
1054 : : beg, &at, end, flags, records);
1055 : 36 : break;
1056 : 75 : case OPENPGP_PKT_USER_ID:
1057 : 75 : ret = parse_user_id (beg, &at, end, flags, records);
1058 : 75 : break;
1059 : 9 : case OPENPGP_PKT_ATTRIBUTE:
1060 : 9 : ret = parse_user_attribute (beg, &at, end, flags, records);
1061 : 9 : break;
1062 : 129 : case OPENPGP_PKT_SIGNATURE:
1063 : 129 : ret = parse_signature (beg, &at, end, flags, records);
1064 : 129 : break;
1065 : 6 : case OPENPGP_PKT_SECRET_KEY:
1066 : 6 : ret = parse_secret_key_or_subkey (GCR_RECORD_SCHEMA_SEC,
1067 : : beg, &at, end, flags, records);
1068 : 6 : break;
1069 : 6 : case OPENPGP_PKT_SECRET_SUBKEY:
1070 : 6 : ret = parse_secret_key_or_subkey (GCR_RECORD_SCHEMA_SSB,
1071 : : beg, &at, end, flags, records);
1072 : 6 : break;
1073 : :
1074 : : /* Stuff we don't want to be meddling with right now */
1075 : 93 : case OPENPGP_PKT_RING_TRUST:
1076 : 93 : return GCR_SUCCESS;
1077 : :
1078 : : /* Ignore packets we don't understand */
1079 : 0 : default:
1080 : 0 : return GCR_SUCCESS;
1081 : : }
1082 : :
1083 : : /* Key packet had extra data */
1084 [ + - - + ]: 297 : if (ret == TRUE && at != end)
1085 : 0 : ret = FALSE;
1086 : :
1087 [ + - ]: 297 : return ret ? GCR_SUCCESS : GCR_ERROR_FAILURE;
1088 : : }
1089 : :
1090 : : static void
1091 : 24 : append_key_capabilities (GString *string,
1092 : : const gchar *caps)
1093 : : {
1094 : : guint i;
1095 : : gchar cap;
1096 : :
1097 [ + + ]: 66 : for (i = 0; caps[i] != 0; i++) {
1098 : 42 : cap = g_ascii_toupper (caps[i]);
1099 [ + + ]: 42 : if (!strchr (string->str, cap))
1100 : 36 : g_string_append_c (string, cap);
1101 : : }
1102 : 24 : }
1103 : :
1104 : : static void
1105 : 12 : normalize_capabilities (GPtrArray *records)
1106 : : {
1107 : : GString *string;
1108 : : GQuark schema;
1109 : : const gchar *caps;
1110 : : guint i;
1111 : :
1112 : : /* Gather the capabilities of all subkeys into the primary key */
1113 : 12 : string = g_string_new (_gcr_record_get_raw (records->pdata[0], GCR_RECORD_PUB_CAPS));
1114 [ + + ]: 117 : for (i = 0; i < records->len; i++) {
1115 : 105 : schema = _gcr_record_get_schema (records->pdata[i]);
1116 [ + + + + ]: 105 : if (schema == GCR_RECORD_SCHEMA_PUB || schema == GCR_RECORD_SCHEMA_SUB) {
1117 : 24 : caps = _gcr_record_get_raw (records->pdata[i], GCR_RECORD_PUB_CAPS);
1118 : 24 : append_key_capabilities (string, caps);
1119 : : }
1120 : : }
1121 : 12 : _gcr_record_take_raw (records->pdata[0], GCR_RECORD_PUB_CAPS,
1122 : : g_string_free (string, FALSE));
1123 : 12 : }
1124 : :
1125 : : static gboolean
1126 : 36 : check_key_expiry (GcrRecord *record)
1127 : : {
1128 : : gulong expiry;
1129 : : time_t current;
1130 : :
1131 [ + - ]: 36 : if (_gcr_record_get_ulong (record, GCR_RECORD_KEY_EXPIRY, &expiry)) {
1132 [ + + ]: 36 : if (expiry == 0)
1133 : 12 : return FALSE;
1134 : 24 : current = time (NULL);
1135 [ + - ]: 24 : if (current > expiry)
1136 : 24 : return TRUE;
1137 : : }
1138 : :
1139 : 0 : return FALSE;
1140 : : }
1141 : :
1142 : : static void
1143 : 134 : normalize_key_records (GPtrArray *records)
1144 : : {
1145 : : GQuark schema;
1146 : 134 : guchar trust = 0;
1147 : : const gchar *prev;
1148 : 134 : gboolean force = FALSE;
1149 : : guint i;
1150 : :
1151 [ + + ]: 134 : if (records->len == 0)
1152 : 92 : return;
1153 : :
1154 : 42 : schema = _gcr_record_get_schema (records->pdata[0]);
1155 [ + + ]: 42 : if (schema == GCR_RECORD_SCHEMA_PUB) {
1156 : :
1157 [ + + ]: 36 : if (check_key_expiry (records->pdata[0])) {
1158 : 24 : trust = 'e';
1159 : 24 : force = TRUE;
1160 : :
1161 : : /* Mark public keys as unknown trust */
1162 : : } else {
1163 : 12 : normalize_capabilities (records);
1164 : 12 : trust = 'o';
1165 : 12 : force = FALSE;
1166 : : }
1167 : :
1168 : : /* Ownertrust unknown, new to system */
1169 : 36 : _gcr_record_set_char (records->pdata[0], GCR_RECORD_KEY_OWNERTRUST, 'o');
1170 : :
1171 [ + - ]: 6 : } else if (schema == GCR_RECORD_SCHEMA_SEC) {
1172 : :
1173 : : /* Trust doesn't make sense for secret keys */
1174 : 6 : trust = 0;
1175 : 6 : force = FALSE;
1176 : : }
1177 : :
1178 : :
1179 : : /* Setup default trust if necessary */
1180 [ + + ]: 42 : if (trust != 0) {
1181 [ + + ]: 307 : for (i = 0; i < records->len; i++) {
1182 [ + + ]: 271 : if (!force) {
1183 : 105 : prev = _gcr_record_get_raw (records->pdata[i], GCR_RECORD_TRUST);
1184 [ + - - + ]: 105 : if (prev != NULL && prev[0])
1185 : 0 : continue;
1186 : : }
1187 : 271 : schema = _gcr_record_get_schema (records->pdata[i]);
1188 [ + + + + ]: 271 : if (schema != GCR_RECORD_SCHEMA_SIG && schema != GCR_RECORD_SCHEMA_FPR)
1189 : 156 : _gcr_record_set_char (records->pdata[i], GCR_RECORD_TRUST, trust);
1190 : : }
1191 : : }
1192 : : }
1193 : :
1194 : : typedef struct {
1195 : : GcrOpenpgpCallback callback;
1196 : : gpointer user_data;
1197 : : guint count;
1198 : : GBytes *backing;
1199 : : GPtrArray *records;
1200 : : } openpgp_parse_closure;
1201 : :
1202 : : static void
1203 : 76 : openpgp_parse_free (gpointer data)
1204 : : {
1205 : 76 : openpgp_parse_closure *closure = data;
1206 : 76 : g_ptr_array_unref (closure->records);
1207 : 76 : g_bytes_unref (closure->backing);
1208 : 76 : g_free (closure);
1209 : 76 : }
1210 : :
1211 : : static void
1212 : 134 : maybe_emit_openpgp_block (openpgp_parse_closure *closure,
1213 : : const guchar *block,
1214 : : const guchar *end)
1215 : : {
1216 : : GBytes *outer;
1217 : : gsize length;
1218 : : GPtrArray *records;
1219 : :
1220 [ + + - + ]: 134 : if (block == NULL || block == end)
1221 : 76 : return;
1222 : :
1223 [ - + ]: 58 : g_assert (end != NULL);
1224 [ - + ]: 58 : g_assert (end > block);
1225 : :
1226 : 58 : length = end - block;
1227 : 58 : closure->count++;
1228 : :
1229 : 58 : records = closure->records;
1230 : 58 : closure->records = g_ptr_array_new_with_free_func (_gcr_record_free);
1231 : :
1232 : 58 : outer = g_bytes_new_with_free_func (block, length, (GDestroyNotify)g_bytes_unref,
1233 : 58 : g_bytes_ref (closure->backing));
1234 [ + + ]: 58 : if (closure->callback)
1235 : 42 : (closure->callback) (records, outer, closure->user_data);
1236 : 58 : g_bytes_unref (outer);
1237 : :
1238 : 58 : g_ptr_array_unref (records);
1239 : : }
1240 : :
1241 : : guint
1242 : 76 : _gcr_openpgp_parse (GBytes *data,
1243 : : GcrOpenpgpParseFlags flags,
1244 : : GcrOpenpgpCallback callback,
1245 : : gpointer user_data)
1246 : : {
1247 : : openpgp_parse_closure *closure;
1248 : : const guchar *at;
1249 : : const guchar *beg;
1250 : : const guchar *end;
1251 : : const guchar *block;
1252 : : guint8 pkt_type;
1253 : : GcrDataError res;
1254 : : gsize length;
1255 : : gboolean new_key;
1256 : : guint ret;
1257 : :
1258 [ - + ]: 76 : g_return_val_if_fail (data != NULL, 0);
1259 : :
1260 : : /* For libgcrypt */
1261 : 76 : _gcr_initialize_library ();
1262 : :
1263 : 76 : at = g_bytes_get_data (data, NULL);
1264 : 76 : end = at + g_bytes_get_size (data);
1265 : 76 : block = NULL;
1266 : :
1267 : 76 : closure = g_new0 (openpgp_parse_closure, 1);
1268 : 76 : closure->callback = callback;
1269 : 76 : closure->user_data = user_data;
1270 : 76 : closure->backing = g_bytes_ref (data);
1271 : 76 : closure->records = g_ptr_array_new_with_free_func (_gcr_record_free);
1272 : :
1273 [ + - + + ]: 610 : while (at != NULL && at != end) {
1274 : 574 : beg = at;
1275 : 574 : res = read_openpgp_packet (&at, end, &pkt_type, &length);
1276 : :
1277 [ + + ]: 574 : if (res == GCR_SUCCESS) {
1278 [ + + ]: 1018 : new_key = (pkt_type == OPENPGP_PKT_PUBLIC_KEY ||
1279 [ + + ]: 484 : pkt_type == OPENPGP_PKT_SECRET_KEY);
1280 [ + - + + ]: 534 : if (flags & GCR_OPENPGP_PARSE_KEYS && new_key)
1281 : 58 : normalize_key_records (closure->records);
1282 : : /* Start of a new set of packets, per key */
1283 [ + - + + ]: 534 : if (!(flags & GCR_OPENPGP_PARSE_KEYS) || new_key) {
1284 : 58 : maybe_emit_openpgp_block (closure, block, beg);
1285 : 58 : block = beg;
1286 : : }
1287 [ + + ]: 534 : if (!(flags & GCR_OPENPGP_PARSE_NO_RECORDS))
1288 : 390 : parse_openpgp_packet (beg, at, at + length, pkt_type,
1289 : : flags, closure->records);
1290 : : }
1291 : :
1292 [ + + ]: 574 : if (res != GCR_SUCCESS) {
1293 [ - + - - ]: 40 : if (block != NULL && block != beg)
1294 : 0 : maybe_emit_openpgp_block (closure, block, beg);
1295 : 40 : block = NULL;
1296 : 40 : break;
1297 : : }
1298 : :
1299 : 534 : at += length;
1300 : : }
1301 : :
1302 [ + - ]: 76 : if (flags & GCR_OPENPGP_PARSE_KEYS)
1303 : 76 : normalize_key_records (closure->records);
1304 : 76 : maybe_emit_openpgp_block (closure, block, at);
1305 : 76 : ret = closure->count;
1306 : 76 : openpgp_parse_free (closure);
1307 : 76 : return ret;
1308 : : }
|