Line data Source code
1 : /* keylist.c - Listing keys.
2 : Copyright (C) 2000 Werner Koch (dd9jn)
3 : Copyright (C) 2001, 2002, 2003, 2004, 2006, 2007,
4 : 2008, 2009 g10 Code GmbH
5 :
6 : This file is part of GPGME.
7 :
8 : GPGME is free software; you can redistribute it and/or modify it
9 : under the terms of the GNU Lesser General Public License as
10 : published by the Free Software Foundation; either version 2.1 of
11 : the License, or (at your option) any later version.
12 :
13 : GPGME is distributed in the hope that it will be useful, but
14 : WITHOUT ANY WARRANTY; without even the implied warranty of
15 : MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 : Lesser General Public License for more details.
17 :
18 : You should have received a copy of the GNU Lesser General Public
19 : License along with this program; if not, see <http://www.gnu.org/licenses/>.
20 : */
21 :
22 : #if HAVE_CONFIG_H
23 : #include <config.h>
24 : #endif
25 : #include <stdio.h>
26 : #include <stdlib.h>
27 : #include <string.h>
28 : #ifdef HAVE_SYS_TYPES_H
29 : /* Solaris 8 needs sys/types.h before time.h. */
30 : # include <sys/types.h>
31 : #endif
32 : #include <time.h>
33 : #include <assert.h>
34 : #include <ctype.h>
35 : #include <errno.h>
36 : #include <limits.h>
37 :
38 : /* Suppress warning for accessing deprecated member "class". */
39 : #define _GPGME_IN_GPGME
40 : #include "gpgme.h"
41 : #include "util.h"
42 : #include "context.h"
43 : #include "ops.h"
44 : #include "debug.h"
45 :
46 :
47 : struct key_queue_item_s
48 : {
49 : struct key_queue_item_s *next;
50 : gpgme_key_t key;
51 : };
52 :
53 : typedef struct
54 : {
55 : struct _gpgme_op_keylist_result result;
56 :
57 : gpgme_key_t tmp_key;
58 :
59 : /* This points to the last uid in tmp_key. */
60 : gpgme_user_id_t tmp_uid;
61 :
62 : /* This points to the last sig in tmp_uid. */
63 : gpgme_key_sig_t tmp_keysig;
64 :
65 : /* Something new is available. */
66 : int key_cond;
67 : struct key_queue_item_s *key_queue;
68 : } *op_data_t;
69 :
70 :
71 : static void
72 100 : release_op_data (void *hook)
73 : {
74 100 : op_data_t opd = (op_data_t) hook;
75 100 : struct key_queue_item_s *key = opd->key_queue;
76 :
77 100 : if (opd->tmp_key)
78 3 : gpgme_key_unref (opd->tmp_key);
79 :
80 : /* opd->tmp_uid and opd->tmp_keysig are actually part of opd->tmp_key,
81 : so we do not need to release them here. */
82 :
83 202 : while (key)
84 : {
85 2 : struct key_queue_item_s *next = key->next;
86 :
87 2 : gpgme_key_unref (key->key);
88 2 : key = next;
89 : }
90 100 : }
91 :
92 :
93 : gpgme_keylist_result_t
94 15 : gpgme_op_keylist_result (gpgme_ctx_t ctx)
95 : {
96 : void *hook;
97 : op_data_t opd;
98 : gpgme_error_t err;
99 :
100 15 : TRACE_BEG (DEBUG_CTX, "gpgme_op_keylist_result", ctx);
101 :
102 15 : err = _gpgme_op_data_lookup (ctx, OPDATA_KEYLIST, &hook, -1, NULL);
103 15 : opd = hook;
104 15 : if (err || !opd)
105 : {
106 0 : TRACE_SUC0 ("result=(null)");
107 0 : return NULL;
108 : }
109 :
110 15 : TRACE_LOG1 ("truncated = %i", opd->result.truncated);
111 :
112 15 : TRACE_SUC1 ("result=%p", &opd->result);
113 15 : return &opd->result;
114 : }
115 :
116 :
117 : static gpgme_error_t
118 220 : keylist_status_handler (void *priv, gpgme_status_code_t code, char *args)
119 : {
120 220 : gpgme_ctx_t ctx = (gpgme_ctx_t) priv;
121 : gpgme_error_t err;
122 : void *hook;
123 : op_data_t opd;
124 :
125 220 : err = _gpgme_op_data_lookup (ctx, OPDATA_KEYLIST, &hook, -1, NULL);
126 220 : opd = hook;
127 220 : if (err)
128 0 : return err;
129 :
130 220 : switch (code)
131 : {
132 : case GPGME_STATUS_TRUNCATED:
133 0 : opd->result.truncated = 1;
134 0 : break;
135 :
136 : default:
137 220 : break;
138 : }
139 220 : return 0;
140 : }
141 :
142 :
143 : static void
144 365 : set_subkey_trust_info (gpgme_subkey_t subkey, const char *src)
145 : {
146 1094 : while (*src && !isdigit (*src))
147 : {
148 364 : switch (*src)
149 : {
150 : case 'e':
151 6 : subkey->expired = 1;
152 6 : break;
153 :
154 : case 'r':
155 0 : subkey->revoked = 1;
156 0 : break;
157 :
158 : case 'd':
159 : /* Note that gpg 1.3 won't print that anymore but only uses
160 : the capabilities field. */
161 0 : subkey->disabled = 1;
162 0 : break;
163 :
164 : case 'i':
165 0 : subkey->invalid = 1;
166 0 : break;
167 : }
168 364 : src++;
169 : }
170 365 : }
171 :
172 :
173 : static void
174 189 : set_mainkey_trust_info (gpgme_key_t key, const char *src)
175 : {
176 : /* First set the trust info of the main key (the first subkey). */
177 189 : set_subkey_trust_info (key->subkeys, src);
178 :
179 : /* Now set the summarized trust info. */
180 566 : while (*src && !isdigit (*src))
181 : {
182 188 : switch (*src)
183 : {
184 : case 'e':
185 0 : key->expired = 1;
186 0 : break;
187 :
188 : case 'r':
189 0 : key->revoked = 1;
190 0 : break;
191 :
192 : case 'd':
193 : /* Note that gpg 1.3 won't print that anymore but only uses
194 : the capabilities field. However, it is still used for
195 : external key listings. */
196 0 : key->disabled = 1;
197 0 : break;
198 :
199 : case 'i':
200 0 : key->invalid = 1;
201 0 : break;
202 : }
203 188 : src++;
204 : }
205 189 : }
206 :
207 :
208 : static void
209 337 : set_userid_flags (gpgme_key_t key, const char *src)
210 : {
211 337 : gpgme_user_id_t uid = key->_last_uid;
212 :
213 337 : assert (uid);
214 : /* Look at letters and stop at the first digit. */
215 1009 : while (*src && !isdigit (*src))
216 : {
217 335 : switch (*src)
218 : {
219 : case 'r':
220 0 : uid->revoked = 1;
221 0 : break;
222 :
223 : case 'i':
224 0 : uid->invalid = 1;
225 0 : break;
226 :
227 : case 'n':
228 4 : uid->validity = GPGME_VALIDITY_NEVER;
229 4 : break;
230 :
231 : case 'm':
232 8 : uid->validity = GPGME_VALIDITY_MARGINAL;
233 8 : break;
234 :
235 : case 'f':
236 0 : uid->validity = GPGME_VALIDITY_FULL;
237 0 : break;
238 :
239 : case 'u':
240 41 : uid->validity = GPGME_VALIDITY_ULTIMATE;
241 41 : break;
242 : }
243 335 : src++;
244 : }
245 337 : }
246 :
247 :
248 : static void
249 365 : set_subkey_capability (gpgme_subkey_t subkey, const char *src)
250 : {
251 2180 : while (*src)
252 : {
253 1450 : switch (*src)
254 : {
255 : case 'e':
256 184 : subkey->can_encrypt = 1;
257 184 : break;
258 :
259 : case 's':
260 183 : subkey->can_sign = 1;
261 183 : break;
262 :
263 : case 'c':
264 189 : subkey->can_certify = 1;
265 189 : break;
266 :
267 : case 'a':
268 172 : subkey->can_authenticate = 1;
269 172 : break;
270 :
271 : case 'q':
272 0 : subkey->is_qualified = 1;
273 0 : break;
274 :
275 : case 'd':
276 0 : subkey->disabled = 1;
277 0 : break;
278 : }
279 1450 : src++;
280 : }
281 365 : }
282 :
283 :
284 : static void
285 189 : set_mainkey_capability (gpgme_key_t key, const char *src)
286 : {
287 : /* First set the capabilities of the main key (the first subkey). */
288 189 : set_subkey_capability (key->subkeys, src);
289 :
290 1652 : while (*src)
291 : {
292 1274 : switch (*src)
293 : {
294 : case 'd':
295 : case 'D':
296 : /* Note, that this flag is also set using the key validity
297 : field for backward compatibility with gpg 1.2. We use d
298 : and D, so that a future gpg version will be able to
299 : disable certain subkeys. Currently it is expected that
300 : gpg sets this for the primary key. */
301 0 : key->disabled = 1;
302 0 : break;
303 :
304 : case 'e':
305 : case 'E':
306 192 : key->can_encrypt = 1;
307 192 : break;
308 :
309 : case 's':
310 : case 'S':
311 360 : key->can_sign = 1;
312 360 : break;
313 :
314 : case 'c':
315 : case 'C':
316 378 : key->can_certify = 1;
317 378 : break;
318 :
319 : case 'a':
320 : case 'A':
321 344 : key->can_authenticate = 1;
322 344 : break;
323 :
324 : case 'q':
325 : case 'Q':
326 0 : key->is_qualified = 1;
327 0 : break;
328 : }
329 1274 : src++;
330 : }
331 189 : }
332 :
333 :
334 : static void
335 189 : set_ownertrust (gpgme_key_t key, const char *src)
336 : {
337 : /* Look at letters and stop at the first digit. */
338 561 : while (*src && !isdigit (*src))
339 : {
340 183 : switch (*src)
341 : {
342 : case 'n':
343 0 : key->owner_trust = GPGME_VALIDITY_NEVER;
344 0 : break;
345 :
346 : case 'm':
347 0 : key->owner_trust = GPGME_VALIDITY_MARGINAL;
348 0 : break;
349 :
350 : case 'f':
351 0 : key->owner_trust = GPGME_VALIDITY_FULL;
352 0 : break;
353 :
354 : case 'u':
355 15 : key->owner_trust = GPGME_VALIDITY_ULTIMATE;
356 15 : break;
357 :
358 : default:
359 168 : key->owner_trust = GPGME_VALIDITY_UNKNOWN;
360 168 : break;
361 : }
362 183 : src++;
363 : }
364 189 : }
365 :
366 :
367 : /* Parse field 15 of a secret key or subkey. This fields holds a
368 : reference to smartcards. FIELD is the content of the field and we
369 : are allowed to modify it. */
370 : static gpg_error_t
371 29 : parse_sec_field15 (gpgme_key_t key, gpgme_subkey_t subkey, char *field)
372 : {
373 29 : if (!*field)
374 : ; /* Empty. */
375 9 : else if (*field == '#')
376 : {
377 : /* This is a stub for an offline key. We reset the SECRET flag
378 : of the subkey here. Note that the secret flag of the entire
379 : key will be true even then. We even explicitly set
380 : key->secret to make it works for GPGME_KEYLIST_MODE_WITH_SECRET. */
381 0 : subkey->secret = 0;
382 0 : key->secret = 1;
383 : }
384 9 : else if (strchr ("01234567890ABCDEFabcdef", *field))
385 : {
386 : /* Fields starts with a hex digit; thus it is a serial number. */
387 0 : key->secret = 1;
388 0 : subkey->is_cardkey = 1;
389 0 : subkey->card_number = strdup (field);
390 0 : if (!subkey->card_number)
391 0 : return gpg_error_from_syserror ();
392 : }
393 9 : else if (*field == '+')
394 : {
395 9 : key->secret = 1;
396 9 : subkey->secret = 1;
397 : }
398 : else
399 : {
400 : /* RFU. */
401 : }
402 :
403 29 : return 0;
404 : }
405 :
406 :
407 : /* Parse a tfs record. */
408 : static gpg_error_t
409 7 : parse_tfs_record (gpgme_user_id_t uid, char **field, int nfield)
410 : {
411 : gpg_error_t err;
412 : gpgme_tofu_info_t ti;
413 : unsigned long uval;
414 :
415 : /* We add only the first TOFU record in case future versions emit
416 : * several. */
417 7 : if (uid->tofu)
418 0 : return 0;
419 :
420 : /* Check that we have enough fields and that the version is supported. */
421 7 : if (nfield < 8 || atoi(field[1]) != 1)
422 0 : return trace_gpg_error (GPG_ERR_INV_ENGINE);
423 :
424 7 : ti = calloc (1, sizeof *ti);
425 7 : if (!ti)
426 0 : return gpg_error_from_syserror ();
427 :
428 : /* Note that we allow a value of up to 7 which is what we can store
429 : * in the ti->validity. */
430 7 : err = _gpgme_strtoul_field (field[2], &uval);
431 7 : if (err || uval > 7)
432 : goto inv_engine;
433 7 : ti->validity = uval;
434 :
435 : /* Parse the sign-count. */
436 7 : err = _gpgme_strtoul_field (field[3], &uval);
437 7 : if (err)
438 0 : goto inv_engine;
439 7 : if (uval > USHRT_MAX)
440 0 : uval = USHRT_MAX;
441 7 : ti->signcount = uval;
442 :
443 : /* Parse the encr-count. */
444 7 : err = _gpgme_strtoul_field (field[4], &uval);
445 7 : if (err)
446 0 : goto inv_engine;
447 7 : if (uval > USHRT_MAX)
448 0 : uval = USHRT_MAX;
449 7 : ti->encrcount = uval;
450 :
451 : /* Parse the policy. */
452 7 : if (!strcmp (field[5], "none"))
453 0 : ti->policy = GPGME_TOFU_POLICY_NONE;
454 7 : else if (!strcmp (field[5], "auto"))
455 7 : ti->policy = GPGME_TOFU_POLICY_AUTO;
456 0 : else if (!strcmp (field[5], "good"))
457 0 : ti->policy = GPGME_TOFU_POLICY_GOOD;
458 0 : else if (!strcmp (field[5], "bad"))
459 0 : ti->policy = GPGME_TOFU_POLICY_BAD;
460 0 : else if (!strcmp (field[5], "ask"))
461 0 : ti->policy = GPGME_TOFU_POLICY_ASK;
462 : else /* "unknown" and invalid policy strings. */
463 0 : ti->policy = GPGME_TOFU_POLICY_UNKNOWN;
464 :
465 : /* Parse first and last seen timestamps. */
466 7 : err = _gpgme_strtoul_field (field[6], &uval);
467 7 : if (err)
468 0 : goto inv_engine;
469 7 : ti->signfirst = uval;
470 7 : err = _gpgme_strtoul_field (field[7], &uval);
471 7 : if (err)
472 0 : goto inv_engine;
473 7 : ti->signlast = uval;
474 :
475 7 : if (nfield > 9)
476 : {
477 : /* This condition is only to allow for gpg 2.1.15 - can
478 : * eventually be removed. */
479 0 : err = _gpgme_strtoul_field (field[8], &uval);
480 0 : if (err)
481 0 : goto inv_engine;
482 0 : ti->encrfirst = uval;
483 0 : err = _gpgme_strtoul_field (field[9], &uval);
484 0 : if (err)
485 0 : goto inv_engine;
486 0 : ti->encrlast = uval;
487 : }
488 :
489 : /* Ready. */
490 7 : uid->tofu = ti;
491 7 : return 0;
492 :
493 : inv_engine:
494 0 : free (ti);
495 0 : return trace_gpg_error (GPG_ERR_INV_ENGINE);
496 : }
497 :
498 :
499 : /* We have read an entire key into tmp_key and should now finish it.
500 : It is assumed that this releases tmp_key. */
501 : static void
502 286 : finish_key (gpgme_ctx_t ctx, op_data_t opd)
503 : {
504 286 : gpgme_key_t key = opd->tmp_key;
505 :
506 286 : opd->tmp_key = NULL;
507 286 : opd->tmp_uid = NULL;
508 286 : opd->tmp_keysig = NULL;
509 :
510 286 : if (key)
511 186 : _gpgme_engine_io_event (ctx->engine, GPGME_EVENT_NEXT_KEY, key);
512 286 : }
513 :
514 :
515 : /* Note: We are allowed to modify LINE. */
516 : static gpgme_error_t
517 1309 : keylist_colon_handler (void *priv, char *line)
518 : {
519 1309 : gpgme_ctx_t ctx = (gpgme_ctx_t) priv;
520 : enum
521 : {
522 : RT_NONE, RT_SIG, RT_UID, RT_TFS, RT_SUB, RT_PUB, RT_FPR, RT_GRP,
523 : RT_SSB, RT_SEC, RT_CRT, RT_CRS, RT_REV, RT_SPK
524 : }
525 1309 : rectype = RT_NONE;
526 : #define NR_FIELDS 17
527 : char *field[NR_FIELDS];
528 1309 : int fields = 0;
529 : void *hook;
530 : op_data_t opd;
531 : gpgme_error_t err;
532 : gpgme_key_t key;
533 1309 : gpgme_subkey_t subkey = NULL;
534 1309 : gpgme_key_sig_t keysig = NULL;
535 :
536 1309 : err = _gpgme_op_data_lookup (ctx, OPDATA_KEYLIST, &hook, -1, NULL);
537 1309 : opd = hook;
538 1309 : if (err)
539 0 : return err;
540 :
541 1309 : key = opd->tmp_key;
542 :
543 1309 : TRACE2 (DEBUG_CTX, "gpgme:keylist_colon_handler", ctx,
544 : "key = %p, line = %s", key, line ? line : "(null)");
545 :
546 1309 : if (!line)
547 : {
548 : /* End Of File. */
549 97 : finish_key (ctx, opd);
550 97 : return 0;
551 : }
552 :
553 17836 : while (line && fields < NR_FIELDS)
554 : {
555 15412 : field[fields++] = line;
556 15412 : line = strchr (line, ':');
557 15412 : if (line)
558 14559 : *(line++) = '\0';
559 : }
560 :
561 1212 : if (!strcmp (field[0], "sig"))
562 25 : rectype = RT_SIG;
563 1187 : else if (!strcmp (field[0], "rev"))
564 0 : rectype = RT_REV;
565 1187 : else if (!strcmp (field[0], "pub"))
566 166 : rectype = RT_PUB;
567 1021 : else if (!strcmp (field[0], "sec"))
568 17 : rectype = RT_SEC;
569 1004 : else if (!strcmp (field[0], "crt"))
570 4 : rectype = RT_CRT;
571 1000 : else if (!strcmp (field[0], "crs"))
572 2 : rectype = RT_CRS;
573 998 : else if (!strcmp (field[0], "fpr") && key)
574 365 : rectype = RT_FPR;
575 633 : else if (!strcmp (field[0], "grp") && key)
576 29 : rectype = RT_GRP;
577 604 : else if (!strcmp (field[0], "uid") && key)
578 337 : rectype = RT_UID;
579 267 : else if (!strcmp (field[0], "tfs") && key)
580 7 : rectype = RT_TFS;
581 260 : else if (!strcmp (field[0], "sub") && key)
582 164 : rectype = RT_SUB;
583 96 : else if (!strcmp (field[0], "ssb") && key)
584 12 : rectype = RT_SSB;
585 84 : else if (!strcmp (field[0], "spk") && key)
586 0 : rectype = RT_SPK;
587 : else
588 84 : rectype = RT_NONE;
589 :
590 : /* Only look at signature and trust info records immediately
591 : following a user ID. For this, clear the user ID pointer when
592 : encountering anything but a signature or trust record. */
593 1212 : if (rectype != RT_SIG && rectype != RT_REV && rectype != RT_TFS)
594 1180 : opd->tmp_uid = NULL;
595 :
596 : /* Only look at subpackets immediately following a signature. For
597 : this, clear the signature pointer when encountering anything but
598 : a subpacket. */
599 1212 : if (rectype != RT_SPK)
600 1212 : opd->tmp_keysig = NULL;
601 :
602 1212 : switch (rectype)
603 : {
604 : case RT_PUB:
605 : case RT_SEC:
606 : case RT_CRT:
607 : case RT_CRS:
608 : /* Start a new keyblock. */
609 189 : err = _gpgme_key_new (&key);
610 189 : if (err)
611 0 : return err;
612 189 : key->keylist_mode = ctx->keylist_mode;
613 189 : err = _gpgme_key_add_subkey (key, &subkey);
614 189 : if (err)
615 : {
616 0 : gpgme_key_unref (key);
617 0 : return err;
618 : }
619 :
620 189 : if (rectype == RT_SEC || rectype == RT_CRS)
621 19 : key->secret = subkey->secret = 1;
622 189 : if (rectype == RT_CRT || rectype == RT_CRS)
623 6 : key->protocol = GPGME_PROTOCOL_CMS;
624 189 : finish_key (ctx, opd);
625 189 : opd->tmp_key = key;
626 :
627 : /* Field 2 has the trust info. */
628 189 : if (fields >= 2)
629 189 : set_mainkey_trust_info (key, field[1]);
630 :
631 : /* Field 3 has the key length. */
632 189 : if (fields >= 3)
633 : {
634 189 : int i = atoi (field[2]);
635 : /* Ignore invalid values. */
636 189 : if (i > 1)
637 189 : subkey->length = i;
638 : }
639 :
640 : /* Field 4 has the public key algorithm. */
641 189 : if (fields >= 4)
642 : {
643 189 : int i = atoi (field[3]);
644 189 : if (i >= 1 && i < 128)
645 189 : subkey->pubkey_algo = _gpgme_map_pk_algo (i, ctx->protocol);
646 : }
647 :
648 : /* Field 5 has the long keyid. Allow short key IDs for the
649 : output of an external keyserver listing. */
650 189 : if (fields >= 5 && strlen (field[4]) <= DIM(subkey->_keyid) - 1)
651 189 : strcpy (subkey->_keyid, field[4]);
652 :
653 : /* Field 6 has the timestamp (seconds). */
654 189 : if (fields >= 6)
655 189 : subkey->timestamp = _gpgme_parse_timestamp (field[5], NULL);
656 :
657 : /* Field 7 has the expiration time (seconds). */
658 189 : if (fields >= 7)
659 189 : subkey->expires = _gpgme_parse_timestamp (field[6], NULL);
660 :
661 : /* Field 8 has the X.509 serial number. */
662 189 : if (fields >= 8 && (rectype == RT_CRT || rectype == RT_CRS))
663 : {
664 6 : key->issuer_serial = strdup (field[7]);
665 6 : if (!key->issuer_serial)
666 0 : return gpg_error_from_syserror ();
667 : }
668 :
669 : /* Field 9 has the ownertrust. */
670 189 : if (fields >= 9)
671 189 : set_ownertrust (key, field[8]);
672 :
673 : /* Field 10 is not used for gpg due to --fixed-list-mode option
674 : but GPGSM stores the issuer name. */
675 189 : if (fields >= 10 && (rectype == RT_CRT || rectype == RT_CRS))
676 6 : if (_gpgme_decode_c_string (field[9], &key->issuer_name, 0))
677 0 : return gpg_error (GPG_ERR_ENOMEM); /* FIXME */
678 :
679 : /* Field 11 has the signature class. */
680 :
681 : /* Field 12 has the capabilities. */
682 189 : if (fields >= 12)
683 189 : set_mainkey_capability (key, field[11]);
684 :
685 : /* Field 15 carries special flags of a secret key. */
686 189 : if (fields >= 15
687 183 : && (key->secret
688 166 : || (ctx->keylist_mode & GPGME_KEYLIST_MODE_WITH_SECRET)))
689 : {
690 17 : err = parse_sec_field15 (key, subkey, field[14]);
691 17 : if (err)
692 0 : return err;
693 : }
694 :
695 : /* Field 17 has the curve name for ECC. */
696 189 : if (fields >= 17 && *field[16])
697 : {
698 0 : subkey->curve = strdup (field[16]);
699 0 : if (!subkey->curve)
700 0 : return gpg_error_from_syserror ();
701 : }
702 :
703 189 : break;
704 :
705 : case RT_SUB:
706 : case RT_SSB:
707 : /* Start a new subkey. */
708 176 : err = _gpgme_key_add_subkey (key, &subkey);
709 176 : if (err)
710 0 : return err;
711 :
712 176 : if (rectype == RT_SSB)
713 12 : subkey->secret = 1;
714 :
715 : /* Field 2 has the trust info. */
716 176 : if (fields >= 2)
717 176 : set_subkey_trust_info (subkey, field[1]);
718 :
719 : /* Field 3 has the key length. */
720 176 : if (fields >= 3)
721 : {
722 176 : int i = atoi (field[2]);
723 : /* Ignore invalid values. */
724 176 : if (i > 1)
725 176 : subkey->length = i;
726 : }
727 :
728 : /* Field 4 has the public key algorithm. */
729 176 : if (fields >= 4)
730 : {
731 176 : int i = atoi (field[3]);
732 176 : if (i >= 1 && i < 128)
733 176 : subkey->pubkey_algo = _gpgme_map_pk_algo (i, ctx->protocol);
734 : }
735 :
736 : /* Field 5 has the long keyid. */
737 176 : if (fields >= 5 && strlen (field[4]) == DIM(subkey->_keyid) - 1)
738 176 : strcpy (subkey->_keyid, field[4]);
739 :
740 : /* Field 6 has the timestamp (seconds). */
741 176 : if (fields >= 6)
742 176 : subkey->timestamp = _gpgme_parse_timestamp (field[5], NULL);
743 :
744 : /* Field 7 has the expiration time (seconds). */
745 176 : if (fields >= 7)
746 176 : subkey->expires = _gpgme_parse_timestamp (field[6], NULL);
747 :
748 : /* Field 8 is reserved (LID). */
749 : /* Field 9 has the ownertrust. */
750 : /* Field 10, the user ID, is n/a for a subkey. */
751 :
752 : /* Field 11 has the signature class. */
753 :
754 : /* Field 12 has the capabilities. */
755 176 : if (fields >= 12)
756 176 : set_subkey_capability (subkey, field[11]);
757 :
758 : /* Field 15 carries special flags of a secret key. */
759 176 : if (fields >= 15
760 176 : && (key->secret
761 164 : || (ctx->keylist_mode & GPGME_KEYLIST_MODE_WITH_SECRET)))
762 : {
763 12 : err = parse_sec_field15 (key, subkey, field[14]);
764 12 : if (err)
765 0 : return err;
766 : }
767 :
768 : /* Field 17 has the curve name for ECC. */
769 176 : if (fields >= 17 && *field[16])
770 : {
771 0 : subkey->curve = strdup (field[16]);
772 0 : if (!subkey->curve)
773 0 : return gpg_error_from_syserror ();
774 : }
775 :
776 176 : break;
777 :
778 : case RT_UID:
779 : /* Field 2 has the trust info, and field 10 has the user ID. */
780 337 : if (fields >= 10)
781 : {
782 337 : if (_gpgme_key_append_name (key, field[9], 1))
783 0 : return gpg_error (GPG_ERR_ENOMEM); /* FIXME */
784 : else
785 : {
786 337 : if (field[1])
787 337 : set_userid_flags (key, field[1]);
788 337 : opd->tmp_uid = key->_last_uid;
789 : }
790 : }
791 337 : break;
792 :
793 : case RT_TFS:
794 7 : if (opd->tmp_uid)
795 : {
796 7 : err = parse_tfs_record (opd->tmp_uid, field, fields);
797 7 : if (err)
798 0 : return err;
799 : }
800 7 : break;
801 :
802 : case RT_FPR:
803 : /* Field 10 has the fingerprint (take only the first one). */
804 365 : if (fields >= 10 && field[9] && *field[9])
805 : {
806 : /* Need to apply it to the last subkey because all subkeys
807 : do have fingerprints. */
808 365 : subkey = key->_last_subkey;
809 365 : if (!subkey->fpr)
810 : {
811 365 : subkey->fpr = strdup (field[9]);
812 365 : if (!subkey->fpr)
813 0 : return gpg_error_from_syserror ();
814 : }
815 : /* If this is the first subkey, store the fingerprint also
816 : in the KEY object. */
817 365 : if (subkey == key->subkeys)
818 : {
819 189 : if (key->fpr && strcmp (key->fpr, subkey->fpr))
820 : {
821 : /* FPR already set but mismatch: Should never happen. */
822 0 : return trace_gpg_error (GPG_ERR_INTERNAL);
823 : }
824 189 : if (!key->fpr)
825 : {
826 189 : key->fpr = strdup (subkey->fpr);
827 189 : if (!key->fpr)
828 0 : return gpg_error_from_syserror ();
829 : }
830 : }
831 : }
832 :
833 : /* Field 13 has the gpgsm chain ID (take only the first one). */
834 365 : if (fields >= 13 && !key->chain_id && *field[12])
835 : {
836 6 : key->chain_id = strdup (field[12]);
837 6 : if (!key->chain_id)
838 0 : return gpg_error_from_syserror ();
839 : }
840 365 : break;
841 :
842 : case RT_GRP:
843 : /* Field 10 has the keygrip. */
844 29 : if (fields >= 10 && field[9] && *field[9])
845 : {
846 : /* Need to apply it to the last subkey because all subkeys
847 : have a keygrip. */
848 29 : subkey = key->_last_subkey;
849 29 : if (!subkey->keygrip)
850 : {
851 29 : subkey->keygrip = strdup (field[9]);
852 29 : if (!subkey->keygrip)
853 0 : return gpg_error_from_syserror ();
854 : }
855 : }
856 29 : break;
857 :
858 : case RT_SIG:
859 : case RT_REV:
860 25 : if (!opd->tmp_uid)
861 5 : return 0;
862 :
863 : /* Start a new (revoked) signature. */
864 20 : assert (opd->tmp_uid == key->_last_uid);
865 20 : keysig = _gpgme_key_add_sig (key, (fields >= 10) ? field[9] : NULL);
866 20 : if (!keysig)
867 0 : return gpg_error (GPG_ERR_ENOMEM); /* FIXME */
868 :
869 : /* Field 2 has the calculated trust ('!', '-', '?', '%'). */
870 20 : if (fields >= 2)
871 20 : switch (field[1][0])
872 : {
873 : case '!':
874 20 : keysig->status = gpg_error (GPG_ERR_NO_ERROR);
875 20 : break;
876 :
877 : case '-':
878 0 : keysig->status = gpg_error (GPG_ERR_BAD_SIGNATURE);
879 0 : break;
880 :
881 : case '?':
882 0 : keysig->status = gpg_error (GPG_ERR_NO_PUBKEY);
883 0 : break;
884 :
885 : case '%':
886 0 : keysig->status = gpg_error (GPG_ERR_GENERAL);
887 0 : break;
888 :
889 : default:
890 0 : keysig->status = gpg_error (GPG_ERR_NO_ERROR);
891 0 : break;
892 : }
893 :
894 : /* Field 4 has the public key algorithm. */
895 20 : if (fields >= 4)
896 : {
897 20 : int i = atoi (field[3]);
898 20 : if (i >= 1 && i < 128)
899 20 : keysig->pubkey_algo = _gpgme_map_pk_algo (i, ctx->protocol);
900 : }
901 :
902 : /* Field 5 has the long keyid. */
903 20 : if (fields >= 5 && strlen (field[4]) == DIM(keysig->_keyid) - 1)
904 20 : strcpy (keysig->_keyid, field[4]);
905 :
906 : /* Field 6 has the timestamp (seconds). */
907 20 : if (fields >= 6)
908 20 : keysig->timestamp = _gpgme_parse_timestamp (field[5], NULL);
909 :
910 : /* Field 7 has the expiration time (seconds). */
911 20 : if (fields >= 7)
912 20 : keysig->expires = _gpgme_parse_timestamp (field[6], NULL);
913 :
914 : /* Field 11 has the signature class (eg, 0x30 means revoked). */
915 20 : if (fields >= 11)
916 20 : if (field[10][0] && field[10][1])
917 : {
918 20 : int sig_class = _gpgme_hextobyte (field[10]);
919 20 : if (sig_class >= 0)
920 : {
921 20 : keysig->sig_class = sig_class;
922 20 : keysig->class = keysig->sig_class;
923 20 : if (sig_class == 0x30)
924 0 : keysig->revoked = 1;
925 : }
926 20 : if (field[10][2] == 'x')
927 20 : keysig->exportable = 1;
928 : }
929 :
930 20 : opd->tmp_keysig = keysig;
931 20 : break;
932 :
933 : case RT_SPK:
934 0 : if (!opd->tmp_keysig)
935 0 : return 0;
936 0 : assert (opd->tmp_keysig == key->_last_uid->_last_keysig);
937 :
938 0 : if (fields >= 4)
939 : {
940 : /* Field 2 has the subpacket type. */
941 0 : int type = atoi (field[1]);
942 :
943 : /* Field 3 has the flags. */
944 0 : int flags = atoi (field[2]);
945 :
946 : /* Field 4 has the length. */
947 0 : int len = atoi (field[3]);
948 :
949 : /* Field 5 has the data. */
950 0 : char *data = field[4];
951 :
952 : /* Type 20: Notation data. */
953 : /* Type 26: Policy URL. */
954 0 : if (type == 20 || type == 26)
955 : {
956 : gpgme_sig_notation_t notation;
957 :
958 0 : keysig = opd->tmp_keysig;
959 :
960 : /* At this time, any error is serious. */
961 0 : err = _gpgme_parse_notation (¬ation, type, flags, len, data);
962 0 : if (err)
963 0 : return err;
964 :
965 : /* Add a new notation. FIXME: Could be factored out. */
966 0 : if (!keysig->notations)
967 0 : keysig->notations = notation;
968 0 : if (keysig->_last_notation)
969 0 : keysig->_last_notation->next = notation;
970 0 : keysig->_last_notation = notation;
971 : }
972 : }
973 :
974 : case RT_NONE:
975 : /* Unknown record. */
976 84 : break;
977 : }
978 1207 : return 0;
979 : }
980 :
981 :
982 : void
983 186 : _gpgme_op_keylist_event_cb (void *data, gpgme_event_io_t type, void *type_data)
984 : {
985 : gpgme_error_t err;
986 186 : gpgme_ctx_t ctx = (gpgme_ctx_t) data;
987 186 : gpgme_key_t key = (gpgme_key_t) type_data;
988 : void *hook;
989 : op_data_t opd;
990 : struct key_queue_item_s *q, *q2;
991 :
992 186 : assert (type == GPGME_EVENT_NEXT_KEY);
993 :
994 186 : err = _gpgme_op_data_lookup (ctx, OPDATA_KEYLIST, &hook, -1, NULL);
995 186 : opd = hook;
996 186 : if (err)
997 0 : return;
998 :
999 186 : q = malloc (sizeof *q);
1000 186 : if (!q)
1001 : {
1002 0 : gpgme_key_unref (key);
1003 : /* FIXME return GPGME_Out_Of_Core; */
1004 0 : return;
1005 : }
1006 186 : q->key = key;
1007 186 : q->next = NULL;
1008 : /* FIXME: Use a tail pointer? */
1009 186 : if (!(q2 = opd->key_queue))
1010 132 : opd->key_queue = q;
1011 : else
1012 : {
1013 54 : for (; q2->next; q2 = q2->next)
1014 : ;
1015 54 : q2->next = q;
1016 : }
1017 186 : opd->key_cond = 1;
1018 : }
1019 :
1020 :
1021 : /* Start a keylist operation within CTX, searching for keys which
1022 : match PATTERN. If SECRET_ONLY is true, only secret keys are
1023 : returned. */
1024 : gpgme_error_t
1025 100 : gpgme_op_keylist_start (gpgme_ctx_t ctx, const char *pattern, int secret_only)
1026 : {
1027 : gpgme_error_t err;
1028 : void *hook;
1029 : op_data_t opd;
1030 100 : int flags = 0;
1031 :
1032 100 : TRACE_BEG2 (DEBUG_CTX, "gpgme_op_keylist_start", ctx,
1033 : "pattern=%s, secret_only=%i", pattern, secret_only);
1034 :
1035 100 : if (!ctx)
1036 0 : return TRACE_ERR (gpg_error (GPG_ERR_INV_VALUE));
1037 :
1038 100 : err = _gpgme_op_reset (ctx, 2);
1039 100 : if (err)
1040 0 : return TRACE_ERR (err);
1041 :
1042 100 : err = _gpgme_op_data_lookup (ctx, OPDATA_KEYLIST, &hook,
1043 : sizeof (*opd), release_op_data);
1044 100 : opd = hook;
1045 100 : if (err)
1046 0 : return TRACE_ERR (err);
1047 :
1048 100 : _gpgme_engine_set_status_handler (ctx->engine, keylist_status_handler, ctx);
1049 :
1050 100 : err = _gpgme_engine_set_colon_line_handler (ctx->engine,
1051 : keylist_colon_handler, ctx);
1052 100 : if (err)
1053 0 : return TRACE_ERR (err);
1054 :
1055 100 : if (ctx->offline)
1056 0 : flags |= GPGME_ENGINE_FLAG_OFFLINE;
1057 :
1058 100 : err = _gpgme_engine_op_keylist (ctx->engine, pattern, secret_only,
1059 : ctx->keylist_mode, flags);
1060 100 : return TRACE_ERR (err);
1061 : }
1062 :
1063 :
1064 : /* Start a keylist operation within CTX, searching for keys which
1065 : match PATTERN. If SECRET_ONLY is true, only secret keys are
1066 : returned. */
1067 : gpgme_error_t
1068 0 : gpgme_op_keylist_ext_start (gpgme_ctx_t ctx, const char *pattern[],
1069 : int secret_only, int reserved)
1070 : {
1071 : gpgme_error_t err;
1072 : void *hook;
1073 : op_data_t opd;
1074 0 : int flags = 0;
1075 :
1076 0 : TRACE_BEG2 (DEBUG_CTX, "gpgme_op_keylist_ext_start", ctx,
1077 : "secret_only=%i, reserved=0x%x", secret_only, reserved);
1078 :
1079 0 : if (!ctx)
1080 0 : return TRACE_ERR (gpg_error (GPG_ERR_INV_VALUE));
1081 :
1082 0 : err = _gpgme_op_reset (ctx, 2);
1083 0 : if (err)
1084 0 : return TRACE_ERR (err);
1085 :
1086 0 : err = _gpgme_op_data_lookup (ctx, OPDATA_KEYLIST, &hook,
1087 : sizeof (*opd), release_op_data);
1088 0 : opd = hook;
1089 0 : if (err)
1090 0 : return TRACE_ERR (err);
1091 :
1092 0 : _gpgme_engine_set_status_handler (ctx->engine, keylist_status_handler, ctx);
1093 0 : err = _gpgme_engine_set_colon_line_handler (ctx->engine,
1094 : keylist_colon_handler, ctx);
1095 0 : if (err)
1096 0 : return TRACE_ERR (err);
1097 :
1098 0 : if (ctx->offline)
1099 0 : flags |= GPGME_ENGINE_FLAG_OFFLINE;
1100 :
1101 0 : err = _gpgme_engine_op_keylist_ext (ctx->engine, pattern, secret_only,
1102 : reserved, ctx->keylist_mode,
1103 : flags);
1104 0 : return TRACE_ERR (err);
1105 : }
1106 :
1107 :
1108 : /* Return the next key from the keylist in R_KEY. */
1109 : gpgme_error_t
1110 279 : gpgme_op_keylist_next (gpgme_ctx_t ctx, gpgme_key_t *r_key)
1111 : {
1112 : gpgme_error_t err;
1113 : struct key_queue_item_s *queue_item;
1114 : void *hook;
1115 : op_data_t opd;
1116 :
1117 279 : TRACE_BEG (DEBUG_CTX, "gpgme_op_keylist_next", ctx);
1118 :
1119 279 : if (!ctx || !r_key)
1120 0 : return TRACE_ERR (gpg_error (GPG_ERR_INV_VALUE));
1121 279 : *r_key = NULL;
1122 279 : if (!ctx)
1123 0 : return TRACE_ERR (gpg_error (GPG_ERR_INV_VALUE));
1124 :
1125 279 : err = _gpgme_op_data_lookup (ctx, OPDATA_KEYLIST, &hook, -1, NULL);
1126 279 : opd = hook;
1127 279 : if (err)
1128 0 : return TRACE_ERR (err);
1129 279 : if (opd == NULL)
1130 0 : return TRACE_ERR (gpg_error (GPG_ERR_INV_VALUE));
1131 :
1132 279 : if (!opd->key_queue)
1133 : {
1134 227 : err = _gpgme_wait_on_condition (ctx, &opd->key_cond, NULL);
1135 227 : if (err)
1136 0 : return TRACE_ERR (err);
1137 :
1138 227 : if (!opd->key_cond)
1139 95 : return TRACE_ERR (gpg_error (GPG_ERR_EOF));
1140 :
1141 132 : opd->key_cond = 0;
1142 132 : assert (opd->key_queue);
1143 : }
1144 184 : queue_item = opd->key_queue;
1145 184 : opd->key_queue = queue_item->next;
1146 184 : if (!opd->key_queue)
1147 130 : opd->key_cond = 0;
1148 :
1149 184 : *r_key = queue_item->key;
1150 184 : free (queue_item);
1151 :
1152 184 : return TRACE_SUC2 ("key=%p (%s)", *r_key,
1153 : ((*r_key)->subkeys && (*r_key)->subkeys->fpr) ?
1154 : (*r_key)->subkeys->fpr : "invalid");
1155 : }
1156 :
1157 :
1158 : /* Terminate a pending keylist operation within CTX. */
1159 : gpgme_error_t
1160 18 : gpgme_op_keylist_end (gpgme_ctx_t ctx)
1161 : {
1162 18 : TRACE (DEBUG_CTX, "gpgme_op_keylist_end", ctx);
1163 :
1164 18 : if (!ctx)
1165 0 : return gpg_error (GPG_ERR_INV_VALUE);
1166 :
1167 18 : return 0;
1168 : }
1169 :
1170 :
1171 : /* Get the key with the fingerprint FPR from the crypto backend. If
1172 : SECRET is true, get the secret key. */
1173 : gpgme_error_t
1174 80 : gpgme_get_key (gpgme_ctx_t ctx, const char *fpr, gpgme_key_t *r_key,
1175 : int secret)
1176 : {
1177 : gpgme_ctx_t listctx;
1178 : gpgme_error_t err;
1179 : gpgme_key_t key;
1180 :
1181 80 : TRACE_BEG2 (DEBUG_CTX, "gpgme_get_key", ctx,
1182 : "fpr=%s, secret=%i", fpr, secret);
1183 :
1184 80 : if (!ctx || !r_key || !fpr)
1185 0 : return TRACE_ERR (gpg_error (GPG_ERR_INV_VALUE));
1186 :
1187 80 : if (strlen (fpr) < 8) /* We have at least a key ID. */
1188 0 : return TRACE_ERR (gpg_error (GPG_ERR_INV_VALUE));
1189 :
1190 : /* FIXME: We use our own context because we have to avoid the user's
1191 : I/O callback handlers. */
1192 80 : err = gpgme_new (&listctx);
1193 80 : if (err)
1194 0 : return TRACE_ERR (err);
1195 : {
1196 : gpgme_protocol_t proto;
1197 : gpgme_engine_info_t info;
1198 :
1199 : /* Clone the relevant state. */
1200 80 : proto = gpgme_get_protocol (ctx);
1201 80 : gpgme_set_protocol (listctx, proto);
1202 80 : gpgme_set_keylist_mode (listctx, gpgme_get_keylist_mode (ctx));
1203 80 : info = gpgme_ctx_get_engine_info (ctx);
1204 161 : while (info && info->protocol != proto)
1205 1 : info = info->next;
1206 80 : if (info)
1207 80 : gpgme_ctx_set_engine_info (listctx, proto,
1208 80 : info->file_name, info->home_dir);
1209 : }
1210 :
1211 81 : err = gpgme_op_keylist_start (listctx, fpr, secret);
1212 81 : if (!err)
1213 81 : err = gpgme_op_keylist_next (listctx, r_key);
1214 81 : if (!err)
1215 : {
1216 : try_next_key:
1217 81 : err = gpgme_op_keylist_next (listctx, &key);
1218 81 : if (gpgme_err_code (err) == GPG_ERR_EOF)
1219 81 : err = 0;
1220 : else
1221 : {
1222 0 : if (!err
1223 0 : && *r_key && (*r_key)->subkeys && (*r_key)->subkeys->fpr
1224 0 : && key && key->subkeys && key->subkeys->fpr
1225 0 : && !strcmp ((*r_key)->subkeys->fpr, key->subkeys->fpr))
1226 : {
1227 : /* The fingerprint is identical. We assume that this is
1228 : the same key and don't mark it as an ambiguous. This
1229 : problem may occur with corrupted keyrings and has
1230 : been noticed often with gpgsm. In fact gpgsm uses a
1231 : similar hack to sort out such duplicates but it can't
1232 : do that while listing keys. */
1233 0 : gpgme_key_unref (key);
1234 0 : goto try_next_key;
1235 : }
1236 0 : if (!err)
1237 : {
1238 0 : gpgme_key_unref (key);
1239 0 : err = gpg_error (GPG_ERR_AMBIGUOUS_NAME);
1240 : }
1241 0 : gpgme_key_unref (*r_key);
1242 : }
1243 : }
1244 81 : gpgme_release (listctx);
1245 81 : if (! err)
1246 : {
1247 81 : TRACE_LOG2 ("key=%p (%s)", *r_key,
1248 : ((*r_key)->subkeys && (*r_key)->subkeys->fpr) ?
1249 : (*r_key)->subkeys->fpr : "invalid");
1250 : }
1251 81 : return TRACE_ERR (err);
1252 : }
|