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