Line data Source code
1 : /* verify.c - Signature verification.
2 : Copyright (C) 2000 Werner Koch (dd9jn)
3 : Copyright (C) 2001, 2002, 2003, 2004, 2005 g10 Code GmbH
4 :
5 : This file is part of GPGME.
6 :
7 : GPGME is free software; you can redistribute it and/or modify it
8 : under the terms of the GNU Lesser General Public License as
9 : published by the Free Software Foundation; either version 2.1 of
10 : the License, or (at your option) any later version.
11 :
12 : GPGME is distributed in the hope that it will be useful, but
13 : WITHOUT ANY WARRANTY; without even the implied warranty of
14 : MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 : Lesser General Public License for more details.
16 :
17 : You should have received a copy of the GNU Lesser General Public
18 : License along with this program; if not, write to the Free Software
19 : Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
20 : 02111-1307, USA. */
21 :
22 : #if HAVE_CONFIG_H
23 : #include <config.h>
24 : #endif
25 : #include <stdlib.h>
26 : #include <string.h>
27 : #include <errno.h>
28 : #include <assert.h>
29 : #include <limits.h>
30 :
31 : #include "gpgme.h"
32 : #include "debug.h"
33 : #include "util.h"
34 : #include "context.h"
35 : #include "ops.h"
36 :
37 :
38 : typedef struct
39 : {
40 : struct _gpgme_op_verify_result result;
41 :
42 : /* The error code from a FAILURE status line or 0. */
43 : gpg_error_t failure_code;
44 :
45 : gpgme_signature_t current_sig;
46 : int did_prepare_new_sig;
47 : int only_newsig_seen;
48 : int plaintext_seen;
49 : int conflict_user_seen;
50 : } *op_data_t;
51 :
52 :
53 : static void
54 73 : release_op_data (void *hook)
55 : {
56 73 : op_data_t opd = (op_data_t) hook;
57 73 : gpgme_signature_t sig = opd->result.signatures;
58 :
59 205 : while (sig)
60 : {
61 59 : gpgme_signature_t next = sig->next;
62 59 : gpgme_sig_notation_t notation = sig->notations;
63 :
64 187 : while (notation)
65 : {
66 69 : gpgme_sig_notation_t next_nota = notation->next;
67 :
68 69 : _gpgme_sig_notation_free (notation);
69 69 : notation = next_nota;
70 : }
71 :
72 59 : if (sig->fpr)
73 59 : free (sig->fpr);
74 59 : if (sig->pka_address)
75 0 : free (sig->pka_address);
76 59 : if (sig->key)
77 9 : gpgme_key_unref (sig->key);
78 59 : free (sig);
79 59 : sig = next;
80 : }
81 :
82 73 : if (opd->result.file_name)
83 21 : free (opd->result.file_name);
84 73 : }
85 :
86 :
87 : gpgme_verify_result_t
88 63 : gpgme_op_verify_result (gpgme_ctx_t ctx)
89 : {
90 : void *hook;
91 : op_data_t opd;
92 : gpgme_error_t err;
93 : gpgme_signature_t sig;
94 :
95 63 : TRACE_BEG (DEBUG_CTX, "gpgme_op_verify_result", ctx);
96 63 : err = _gpgme_op_data_lookup (ctx, OPDATA_VERIFY, &hook, -1, NULL);
97 63 : opd = hook;
98 63 : if (err || !opd)
99 : {
100 0 : TRACE_SUC0 ("result=(null)");
101 0 : return NULL;
102 : }
103 :
104 : /* It is possible that we saw a new signature only followed by an
105 : ERROR line for that. In particular a missing X.509 key triggers
106 : this. In this case it is surprising that the summary field has
107 : not been updated. We fix it here by explicitly looking for this
108 : case. The real fix would be to have GPGME emit ERRSIG. */
109 120 : for (sig = opd->result.signatures; sig; sig = sig->next)
110 : {
111 57 : if (!sig->summary)
112 : {
113 23 : switch (gpg_err_code (sig->status))
114 : {
115 : case GPG_ERR_KEY_EXPIRED:
116 0 : sig->summary |= GPGME_SIGSUM_KEY_EXPIRED;
117 0 : break;
118 :
119 : case GPG_ERR_NO_PUBKEY:
120 0 : sig->summary |= GPGME_SIGSUM_KEY_MISSING;
121 0 : break;
122 :
123 : default:
124 23 : break;
125 : }
126 : }
127 : }
128 :
129 : /* Now for some tracing stuff. */
130 : if (_gpgme_debug_trace ())
131 : {
132 : int i;
133 :
134 120 : for (sig = opd->result.signatures, i = 0; sig; sig = sig->next, i++)
135 : {
136 57 : TRACE_LOG4 ("sig[%i] = fpr %s, summary 0x%x, status %s",
137 : i, sig->fpr, sig->summary, gpg_strerror (sig->status));
138 57 : TRACE_LOG6 ("sig[%i] = timestamps 0x%x/0x%x flags:%s%s%s",
139 : i, sig->timestamp, sig->exp_timestamp,
140 : sig->wrong_key_usage ? "wrong key usage" : "",
141 : sig->pka_trust == 1 ? "pka bad"
142 : : (sig->pka_trust == 2 ? "pka_okay" : "pka RFU"),
143 : sig->chain_model ? "chain model" : "");
144 57 : TRACE_LOG5 ("sig[%i] = validity 0x%x (%s), algos %s/%s",
145 : i, sig->validity, gpg_strerror (sig->validity_reason),
146 : gpgme_pubkey_algo_name (sig->pubkey_algo),
147 : gpgme_hash_algo_name (sig->hash_algo));
148 57 : if (sig->pka_address)
149 : {
150 0 : TRACE_LOG2 ("sig[%i] = PKA address %s", i, sig->pka_address);
151 : }
152 57 : if (sig->notations)
153 : {
154 21 : TRACE_LOG1 ("sig[%i] = has notations (not shown)", i);
155 : }
156 : }
157 : }
158 :
159 63 : TRACE_SUC1 ("result=%p", &opd->result);
160 63 : return &opd->result;
161 : }
162 :
163 :
164 : /* Build a summary vector from RESULT. */
165 : static void
166 57 : calc_sig_summary (gpgme_signature_t sig)
167 : {
168 57 : unsigned long sum = 0;
169 :
170 : /* Calculate the red/green flag. */
171 57 : if (sig->validity == GPGME_VALIDITY_FULL
172 29 : || sig->validity == GPGME_VALIDITY_ULTIMATE)
173 : {
174 56 : if (gpg_err_code (sig->status) == GPG_ERR_NO_ERROR
175 0 : || gpg_err_code (sig->status) == GPG_ERR_SIG_EXPIRED
176 0 : || gpg_err_code (sig->status) == GPG_ERR_KEY_EXPIRED)
177 28 : sum |= GPGME_SIGSUM_GREEN;
178 : }
179 29 : else if (sig->validity == GPGME_VALIDITY_NEVER)
180 : {
181 0 : if (gpg_err_code (sig->status) == GPG_ERR_NO_ERROR
182 0 : || gpg_err_code (sig->status) == GPG_ERR_SIG_EXPIRED
183 0 : || gpg_err_code (sig->status) == GPG_ERR_KEY_EXPIRED)
184 0 : sum |= GPGME_SIGSUM_RED;
185 : }
186 29 : else if (gpg_err_code (sig->status) == GPG_ERR_BAD_SIGNATURE)
187 6 : sum |= GPGME_SIGSUM_RED;
188 :
189 :
190 : /* FIXME: handle the case when key and message are expired. */
191 57 : switch (gpg_err_code (sig->status))
192 : {
193 : case GPG_ERR_SIG_EXPIRED:
194 0 : sum |= GPGME_SIGSUM_SIG_EXPIRED;
195 0 : break;
196 :
197 : case GPG_ERR_KEY_EXPIRED:
198 0 : sum |= GPGME_SIGSUM_KEY_EXPIRED;
199 0 : break;
200 :
201 : case GPG_ERR_NO_PUBKEY:
202 0 : sum |= GPGME_SIGSUM_KEY_MISSING;
203 0 : break;
204 :
205 : case GPG_ERR_CERT_REVOKED:
206 0 : sum |= GPGME_SIGSUM_KEY_REVOKED;
207 0 : break;
208 :
209 : case GPG_ERR_BAD_SIGNATURE:
210 : case GPG_ERR_NO_ERROR:
211 57 : break;
212 :
213 : default:
214 0 : sum |= GPGME_SIGSUM_SYS_ERROR;
215 0 : break;
216 : }
217 :
218 : /* Now look at the certain reason codes. */
219 57 : switch (gpg_err_code (sig->validity_reason))
220 : {
221 : case GPG_ERR_CRL_TOO_OLD:
222 0 : if (sig->validity == GPGME_VALIDITY_UNKNOWN)
223 0 : sum |= GPGME_SIGSUM_CRL_TOO_OLD;
224 0 : break;
225 :
226 : case GPG_ERR_CERT_REVOKED:
227 : /* Note that this is a second way to set this flag. It may also
228 : have been set due to a sig->status of STATUS_REVKEYSIG from
229 : parse_new_sig. */
230 0 : sum |= GPGME_SIGSUM_KEY_REVOKED;
231 0 : break;
232 :
233 : default:
234 57 : break;
235 : }
236 :
237 : /* Check other flags. */
238 57 : if (sig->wrong_key_usage)
239 0 : sum |= GPGME_SIGSUM_BAD_POLICY;
240 :
241 : /* Set the valid flag when the signature is unquestionable
242 : valid. (The test is identical to if(sum == GPGME_SIGSUM_GREEN)). */
243 57 : if ((sum & GPGME_SIGSUM_GREEN) && !(sum & ~GPGME_SIGSUM_GREEN))
244 28 : sum |= GPGME_SIGSUM_VALID;
245 :
246 57 : sig->summary = sum;
247 57 : }
248 :
249 :
250 : static gpgme_error_t
251 58 : prepare_new_sig (op_data_t opd)
252 : {
253 : gpgme_signature_t sig;
254 :
255 58 : if (opd->only_newsig_seen && opd->current_sig)
256 : {
257 : /* We have only seen the NEWSIG status and nothing else - we
258 : better skip this signature therefore and reuse it for the
259 : next possible signature. */
260 0 : sig = opd->current_sig;
261 0 : memset (sig, 0, sizeof *sig);
262 0 : assert (opd->result.signatures == sig);
263 : }
264 : else
265 : {
266 58 : sig = calloc (1, sizeof (*sig));
267 58 : if (!sig)
268 0 : return gpg_error_from_syserror ();
269 58 : if (!opd->result.signatures)
270 58 : opd->result.signatures = sig;
271 58 : if (opd->current_sig)
272 0 : opd->current_sig->next = sig;
273 58 : opd->current_sig = sig;
274 : }
275 58 : opd->did_prepare_new_sig = 1;
276 58 : opd->only_newsig_seen = 0;
277 58 : return 0;
278 : }
279 :
280 : static gpgme_error_t
281 57 : parse_new_sig (op_data_t opd, gpgme_status_code_t code, char *args,
282 : gpgme_protocol_t protocol)
283 : {
284 : gpgme_signature_t sig;
285 57 : char *end = strchr (args, ' ');
286 : char *tail;
287 :
288 57 : if (end)
289 : {
290 57 : *end = '\0';
291 57 : end++;
292 : }
293 :
294 57 : if (!opd->did_prepare_new_sig)
295 : {
296 : gpg_error_t err;
297 :
298 0 : err = prepare_new_sig (opd);
299 0 : if (err)
300 0 : return err;
301 : }
302 57 : assert (opd->did_prepare_new_sig);
303 57 : opd->did_prepare_new_sig = 0;
304 :
305 57 : assert (opd->current_sig);
306 57 : sig = opd->current_sig;
307 :
308 : /* FIXME: We should set the source of the state. */
309 57 : switch (code)
310 : {
311 : case GPGME_STATUS_GOODSIG:
312 51 : sig->status = gpg_error (GPG_ERR_NO_ERROR);
313 51 : break;
314 :
315 : case GPGME_STATUS_EXPSIG:
316 0 : sig->status = gpg_error (GPG_ERR_SIG_EXPIRED);
317 0 : break;
318 :
319 : case GPGME_STATUS_EXPKEYSIG:
320 0 : sig->status = gpg_error (GPG_ERR_KEY_EXPIRED);
321 0 : break;
322 :
323 : case GPGME_STATUS_BADSIG:
324 6 : sig->status = gpg_error (GPG_ERR_BAD_SIGNATURE);
325 6 : break;
326 :
327 : case GPGME_STATUS_REVKEYSIG:
328 0 : sig->status = gpg_error (GPG_ERR_CERT_REVOKED);
329 0 : break;
330 :
331 : case GPGME_STATUS_ERRSIG:
332 : /* Parse the pubkey algo. */
333 0 : if (!end)
334 0 : goto parse_err_sig_fail;
335 0 : gpg_err_set_errno (0);
336 0 : sig->pubkey_algo = _gpgme_map_pk_algo (strtol (end, &tail, 0), protocol);
337 0 : if (errno || end == tail || *tail != ' ')
338 : goto parse_err_sig_fail;
339 0 : end = tail;
340 0 : while (*end == ' ')
341 0 : end++;
342 :
343 : /* Parse the hash algo. */
344 0 : if (!*end)
345 0 : goto parse_err_sig_fail;
346 0 : gpg_err_set_errno (0);
347 0 : sig->hash_algo = strtol (end, &tail, 0);
348 0 : if (errno || end == tail || *tail != ' ')
349 : goto parse_err_sig_fail;
350 0 : end = tail;
351 0 : while (*end == ' ')
352 0 : end++;
353 :
354 : /* Skip the sig class. */
355 0 : end = strchr (end, ' ');
356 0 : if (!end)
357 0 : goto parse_err_sig_fail;
358 0 : while (*end == ' ')
359 0 : end++;
360 :
361 : /* Parse the timestamp. */
362 0 : sig->timestamp = _gpgme_parse_timestamp (end, &tail);
363 0 : if (sig->timestamp == -1 || end == tail || (*tail && *tail != ' '))
364 0 : return trace_gpg_error (GPG_ERR_INV_ENGINE);
365 0 : end = tail;
366 0 : while (*end == ' ')
367 0 : end++;
368 :
369 : /* Parse the return code. */
370 0 : if (!*end)
371 0 : goto parse_err_sig_fail;
372 :
373 0 : sig->status = strtoul (end, NULL, 10);
374 0 : goto parse_err_sig_ok;
375 :
376 : parse_err_sig_fail:
377 0 : sig->status = gpg_error (GPG_ERR_GENERAL);
378 : parse_err_sig_ok:
379 0 : break;
380 :
381 : default:
382 0 : return gpg_error (GPG_ERR_GENERAL);
383 : }
384 :
385 57 : if (*args)
386 : {
387 57 : sig->fpr = strdup (args);
388 57 : if (!sig->fpr)
389 0 : return gpg_error_from_syserror ();
390 : }
391 57 : return 0;
392 : }
393 :
394 :
395 : static gpgme_error_t
396 51 : parse_valid_sig (gpgme_signature_t sig, char *args, gpgme_protocol_t protocol)
397 : {
398 51 : char *end = strchr (args, ' ');
399 51 : if (end)
400 : {
401 51 : *end = '\0';
402 51 : end++;
403 : }
404 :
405 51 : if (!*args)
406 : /* We require at least the fingerprint. */
407 0 : return gpg_error (GPG_ERR_GENERAL);
408 :
409 51 : if (sig->fpr)
410 51 : free (sig->fpr);
411 51 : sig->fpr = strdup (args);
412 51 : if (!sig->fpr)
413 0 : return gpg_error_from_syserror ();
414 :
415 : /* Skip the creation date. */
416 51 : end = strchr (end, ' ');
417 51 : if (end)
418 : {
419 : char *tail;
420 :
421 51 : sig->timestamp = _gpgme_parse_timestamp (end, &tail);
422 51 : if (sig->timestamp == -1 || end == tail || (*tail && *tail != ' '))
423 0 : return trace_gpg_error (GPG_ERR_INV_ENGINE);
424 51 : end = tail;
425 :
426 51 : sig->exp_timestamp = _gpgme_parse_timestamp (end, &tail);
427 51 : if (sig->exp_timestamp == -1 || end == tail || (*tail && *tail != ' '))
428 0 : return trace_gpg_error (GPG_ERR_INV_ENGINE);
429 51 : end = tail;
430 :
431 153 : while (*end == ' ')
432 51 : end++;
433 : /* Skip the signature version. */
434 51 : end = strchr (end, ' ');
435 51 : if (end)
436 : {
437 153 : while (*end == ' ')
438 51 : end++;
439 :
440 : /* Skip the reserved field. */
441 51 : end = strchr (end, ' ');
442 51 : if (end)
443 : {
444 : /* Parse the pubkey algo. */
445 51 : gpg_err_set_errno (0);
446 51 : sig->pubkey_algo = _gpgme_map_pk_algo (strtol (end, &tail, 0),
447 : protocol);
448 51 : if (errno || end == tail || *tail != ' ')
449 0 : return trace_gpg_error (GPG_ERR_INV_ENGINE);
450 51 : end = tail;
451 :
452 153 : while (*end == ' ')
453 51 : end++;
454 :
455 51 : if (*end)
456 : {
457 : /* Parse the hash algo. */
458 :
459 51 : gpg_err_set_errno (0);
460 51 : sig->hash_algo = strtol (end, &tail, 0);
461 51 : if (errno || end == tail || *tail != ' ')
462 0 : return trace_gpg_error (GPG_ERR_INV_ENGINE);
463 51 : end = tail;
464 : }
465 : }
466 : }
467 : }
468 51 : return 0;
469 : }
470 :
471 :
472 : static gpgme_error_t
473 165 : parse_notation (gpgme_signature_t sig, gpgme_status_code_t code, char *args)
474 : {
475 : gpgme_error_t err;
476 165 : gpgme_sig_notation_t *lastp = &sig->notations;
477 165 : gpgme_sig_notation_t notation = sig->notations;
478 : char *p;
479 :
480 165 : if (code == GPGME_STATUS_NOTATION_NAME || code == GPGME_STATUS_POLICY_URL)
481 : {
482 63 : p = strchr (args, ' ');
483 63 : if (p)
484 0 : *p = '\0';
485 :
486 : /* FIXME: We could keep a pointer to the last notation in the list. */
487 189 : while (notation && notation->value)
488 : {
489 63 : lastp = ¬ation->next;
490 63 : notation = notation->next;
491 : }
492 :
493 63 : if (notation)
494 : /* There is another notation name without data for the
495 : previous one. The crypto backend misbehaves. */
496 0 : return trace_gpg_error (GPG_ERR_INV_ENGINE);
497 :
498 63 : err = _gpgme_sig_notation_create (¬ation, NULL, 0, NULL, 0, 0);
499 63 : if (err)
500 0 : return err;
501 :
502 63 : if (code == GPGME_STATUS_NOTATION_NAME)
503 : {
504 42 : err = _gpgme_decode_percent_string (args, ¬ation->name, 0, 0);
505 42 : if (err)
506 : {
507 0 : _gpgme_sig_notation_free (notation);
508 0 : return err;
509 : }
510 :
511 42 : notation->name_len = strlen (notation->name);
512 :
513 : /* Set default flags for use with older gpg versions which
514 : * do not emit a NOTATIONS_FLAG line. */
515 42 : notation->flags = GPGME_SIG_NOTATION_HUMAN_READABLE;
516 42 : notation->human_readable = 1;
517 : }
518 : else
519 : {
520 : /* This is a policy URL. */
521 :
522 21 : err = _gpgme_decode_percent_string (args, ¬ation->value, 0, 0);
523 21 : if (err)
524 : {
525 0 : _gpgme_sig_notation_free (notation);
526 0 : return err;
527 : }
528 :
529 21 : notation->value_len = strlen (notation->value);
530 : }
531 63 : *lastp = notation;
532 : }
533 102 : else if (code == GPGME_STATUS_NOTATION_FLAGS)
534 : {
535 : char *field[2];
536 :
537 147 : while (notation && notation->next)
538 : {
539 63 : lastp = ¬ation->next;
540 63 : notation = notation->next;
541 : }
542 :
543 42 : if (!notation || !notation->name)
544 : { /* There are notation flags without a previous notation name.
545 : * The crypto backend misbehaves. */
546 0 : return trace_gpg_error (GPG_ERR_INV_ENGINE);
547 : }
548 42 : if (_gpgme_split_fields (args, field, DIM (field)) < 2)
549 : { /* Required args missing. */
550 0 : return trace_gpg_error (GPG_ERR_INV_ENGINE);
551 : }
552 42 : notation->flags = 0;
553 42 : if (atoi (field[0]))
554 : {
555 3 : notation->flags |= GPGME_SIG_NOTATION_CRITICAL;
556 3 : notation->critical = 1;
557 : }
558 42 : if (atoi (field[1]))
559 : {
560 42 : notation->flags |= GPGME_SIG_NOTATION_HUMAN_READABLE;
561 42 : notation->human_readable = 1;
562 : }
563 : }
564 60 : else if (code == GPGME_STATUS_NOTATION_DATA)
565 : {
566 60 : int len = strlen (args) + 1;
567 : char *dest;
568 :
569 : /* FIXME: We could keep a pointer to the last notation in the list. */
570 219 : while (notation && notation->next)
571 : {
572 99 : lastp = ¬ation->next;
573 99 : notation = notation->next;
574 : }
575 :
576 60 : if (!notation || !notation->name)
577 : /* There is notation data without a previous notation
578 : name. The crypto backend misbehaves. */
579 0 : return trace_gpg_error (GPG_ERR_INV_ENGINE);
580 :
581 60 : if (!notation->value)
582 : {
583 42 : dest = notation->value = malloc (len);
584 42 : if (!dest)
585 0 : return gpg_error_from_syserror ();
586 : }
587 : else
588 : {
589 18 : int cur_len = strlen (notation->value);
590 18 : dest = realloc (notation->value, len + strlen (notation->value));
591 18 : if (!dest)
592 0 : return gpg_error_from_syserror ();
593 18 : notation->value = dest;
594 18 : dest += cur_len;
595 : }
596 :
597 60 : err = _gpgme_decode_percent_string (args, &dest, len, 0);
598 60 : if (err)
599 0 : return err;
600 :
601 60 : notation->value_len += strlen (dest);
602 : }
603 : else
604 0 : return trace_gpg_error (GPG_ERR_INV_ENGINE);
605 165 : return 0;
606 : }
607 :
608 :
609 : static gpgme_error_t
610 51 : parse_trust (gpgme_signature_t sig, gpgme_status_code_t code, char *args)
611 : {
612 51 : char *end = strchr (args, ' ');
613 :
614 51 : if (end)
615 51 : *end = '\0';
616 :
617 51 : switch (code)
618 : {
619 : case GPGME_STATUS_TRUST_UNDEFINED:
620 : default:
621 14 : sig->validity = GPGME_VALIDITY_UNKNOWN;
622 14 : break;
623 :
624 : case GPGME_STATUS_TRUST_NEVER:
625 0 : sig->validity = GPGME_VALIDITY_NEVER;
626 0 : break;
627 :
628 : case GPGME_STATUS_TRUST_MARGINAL:
629 9 : sig->validity = GPGME_VALIDITY_MARGINAL;
630 9 : break;
631 :
632 : case GPGME_STATUS_TRUST_FULLY:
633 : case GPGME_STATUS_TRUST_ULTIMATE:
634 28 : sig->validity = GPGME_VALIDITY_FULL;
635 28 : break;
636 : }
637 :
638 51 : sig->validity_reason = 0;
639 51 : sig->chain_model = 0;
640 51 : if (*args)
641 : {
642 51 : sig->validity_reason = atoi (args);
643 153 : while (*args && *args != ' ')
644 51 : args++;
645 51 : if (*args)
646 : {
647 0 : while (*args == ' ')
648 0 : args++;
649 0 : if (!strncmp (args, "chain", 2) && (args[2] == ' ' || !args[2]))
650 0 : sig->chain_model = 1;
651 : }
652 : }
653 :
654 51 : return 0;
655 : }
656 :
657 :
658 : /* Parse a TOFU_USER line and put the info into SIG. */
659 : static gpgme_error_t
660 15 : parse_tofu_user (gpgme_signature_t sig, char *args, gpgme_protocol_t protocol)
661 : {
662 : gpg_error_t err;
663 : char *tail;
664 : gpgme_user_id_t uid;
665 : gpgme_tofu_info_t ti;
666 15 : char *fpr = NULL;
667 15 : char *address = NULL;
668 :
669 15 : tail = strchr (args, ' ');
670 15 : if (!tail || tail == args)
671 : {
672 0 : err = trace_gpg_error (GPG_ERR_INV_ENGINE); /* No fingerprint. */
673 0 : goto leave;
674 : }
675 15 : *tail++ = 0;
676 :
677 15 : fpr = strdup (args);
678 15 : if (!fpr)
679 : {
680 0 : err = gpg_error_from_syserror ();
681 0 : goto leave;
682 : }
683 :
684 15 : if (sig->key && sig->key->fpr && strcmp (sig->key->fpr, fpr))
685 : {
686 : /* GnuPG since 2.1.17 emits multiple TOFU_USER lines with
687 : different fingerprints in case of conflicts for a signature. */
688 0 : err = gpg_error (GPG_ERR_DUP_VALUE);
689 0 : goto leave;
690 : }
691 :
692 15 : args = tail;
693 15 : tail = strchr (args, ' ');
694 15 : if (tail == args)
695 : {
696 0 : err = trace_gpg_error (GPG_ERR_INV_ENGINE); /* No addr-spec. */
697 0 : goto leave;
698 : }
699 15 : if (tail)
700 0 : *tail = 0;
701 :
702 15 : err = _gpgme_decode_percent_string (args, &address, 0, 0);
703 15 : if (err)
704 0 : goto leave;
705 :
706 15 : if (!sig->key)
707 : {
708 9 : err = _gpgme_key_new (&sig->key);
709 9 : if (err)
710 0 : goto leave;
711 9 : sig->key->fpr = fpr;
712 9 : sig->key->protocol = protocol;
713 9 : fpr = NULL;
714 : }
715 6 : else if (!sig->key->fpr)
716 : {
717 0 : err = trace_gpg_error (GPG_ERR_INTERNAL);
718 0 : goto leave;
719 : }
720 :
721 15 : err = _gpgme_key_append_name (sig->key, address, 0);
722 15 : if (err)
723 0 : goto leave;
724 :
725 15 : uid = sig->key->_last_uid;
726 15 : assert (uid);
727 :
728 15 : ti = calloc (1, sizeof *ti);
729 15 : if (!ti)
730 : {
731 0 : err = gpg_error_from_syserror ();
732 0 : goto leave;
733 : }
734 15 : uid->tofu = ti;
735 :
736 :
737 : leave:
738 15 : free (fpr);
739 15 : free (address);
740 15 : return err;
741 : }
742 :
743 :
744 : /* Parse a TOFU_STATS line and store it in the last tofu info of SIG.
745 : *
746 : * TOFU_STATS <validity> <sign-count> <encr-count> \
747 : * [<policy> [<tm1> <tm2> <tm3> <tm4>]]
748 : */
749 : static gpgme_error_t
750 15 : parse_tofu_stats (gpgme_signature_t sig, char *args)
751 : {
752 : gpgme_error_t err;
753 : gpgme_tofu_info_t ti;
754 : char *field[8];
755 : int nfields;
756 : unsigned long uval;
757 :
758 15 : if (!sig->key || !sig->key->_last_uid || !(ti = sig->key->_last_uid->tofu))
759 0 : return trace_gpg_error (GPG_ERR_INV_ENGINE); /* No TOFU_USER seen. */
760 15 : if (ti->signfirst || ti->signcount || ti->validity || ti->policy)
761 0 : return trace_gpg_error (GPG_ERR_INV_ENGINE); /* Already set. */
762 :
763 15 : nfields = _gpgme_split_fields (args, field, DIM (field));
764 15 : if (nfields < 3)
765 0 : return trace_gpg_error (GPG_ERR_INV_ENGINE); /* Required args missing. */
766 :
767 : /* Note that we allow a value of up to 7 which is what we can store
768 : * in the ti->validity. */
769 15 : err = _gpgme_strtoul_field (field[0], &uval);
770 15 : if (err || uval > 7)
771 0 : return trace_gpg_error (GPG_ERR_INV_ENGINE);
772 15 : ti->validity = uval;
773 :
774 : /* Parse the sign-count. */
775 15 : err = _gpgme_strtoul_field (field[1], &uval);
776 15 : if (err)
777 0 : return trace_gpg_error (GPG_ERR_INV_ENGINE);
778 15 : if (uval > USHRT_MAX)
779 0 : uval = USHRT_MAX;
780 15 : ti->signcount = uval;
781 :
782 : /* Parse the encr-count. */
783 15 : err = _gpgme_strtoul_field (field[2], &uval);
784 15 : if (err)
785 0 : return trace_gpg_error (GPG_ERR_INV_ENGINE);
786 15 : if (uval > USHRT_MAX)
787 0 : uval = USHRT_MAX;
788 15 : ti->encrcount = uval;
789 :
790 15 : if (nfields == 3)
791 0 : return 0; /* All mandatory fields parsed. */
792 :
793 : /* Parse the policy. */
794 15 : if (!strcmp (field[3], "none"))
795 0 : ti->policy = GPGME_TOFU_POLICY_NONE;
796 15 : else if (!strcmp (field[3], "auto"))
797 15 : ti->policy = GPGME_TOFU_POLICY_AUTO;
798 0 : else if (!strcmp (field[3], "good"))
799 0 : ti->policy = GPGME_TOFU_POLICY_GOOD;
800 0 : else if (!strcmp (field[3], "bad"))
801 0 : ti->policy = GPGME_TOFU_POLICY_BAD;
802 0 : else if (!strcmp (field[3], "ask"))
803 0 : ti->policy = GPGME_TOFU_POLICY_ASK;
804 : else /* "unknown" and invalid policy strings. */
805 0 : ti->policy = GPGME_TOFU_POLICY_UNKNOWN;
806 :
807 15 : if (nfields == 4)
808 0 : return 0; /* No more optional fields. */
809 :
810 : /* Parse first and last seen timestamps (none or both are required). */
811 15 : if (nfields < 6)
812 0 : return trace_gpg_error (GPG_ERR_INV_ENGINE); /* "tm2" missing. */
813 15 : err = _gpgme_strtoul_field (field[4], &uval);
814 15 : if (err)
815 0 : return trace_gpg_error (GPG_ERR_INV_ENGINE);
816 15 : ti->signfirst = uval;
817 15 : err = _gpgme_strtoul_field (field[5], &uval);
818 15 : if (err)
819 0 : return trace_gpg_error (GPG_ERR_INV_ENGINE);
820 15 : ti->signlast = uval;
821 15 : if (nfields > 7)
822 : {
823 : /* This condition is only to allow for gpg 2.1.15 - can
824 : * eventually be removed. */
825 15 : err = _gpgme_strtoul_field (field[6], &uval);
826 15 : if (err)
827 0 : return trace_gpg_error (GPG_ERR_INV_ENGINE);
828 15 : ti->encrfirst = uval;
829 15 : err = _gpgme_strtoul_field (field[7], &uval);
830 15 : if (err)
831 0 : return trace_gpg_error (GPG_ERR_INV_ENGINE);
832 15 : ti->encrlast = uval;
833 : }
834 :
835 15 : return 0;
836 : }
837 :
838 :
839 : /* Parse a TOFU_STATS_LONG line and store it in the last tofu info of SIG. */
840 : static gpgme_error_t
841 15 : parse_tofu_stats_long (gpgme_signature_t sig, char *args, int raw)
842 : {
843 : gpgme_error_t err;
844 : gpgme_tofu_info_t ti;
845 : char *p;
846 :
847 15 : if (!sig->key || !sig->key->_last_uid || !(ti = sig->key->_last_uid->tofu))
848 0 : return trace_gpg_error (GPG_ERR_INV_ENGINE); /* No TOFU_USER seen. */
849 15 : if (ti->description)
850 0 : return trace_gpg_error (GPG_ERR_INV_ENGINE); /* Already set. */
851 :
852 15 : err = _gpgme_decode_percent_string (args, &ti->description, 0, 0);
853 15 : if (err)
854 0 : return err;
855 :
856 : /* Remove the non-breaking spaces. */
857 15 : if (!raw)
858 : {
859 1281 : for (p = ti->description; *p; p++)
860 1266 : if (*p == '~')
861 30 : *p = ' ';
862 : }
863 15 : return 0;
864 : }
865 :
866 :
867 : /* Parse an error status line and if SET_STATUS is true update the
868 : result status as appropriate. With SET_STATUS being false, only
869 : check for an error. */
870 : static gpgme_error_t
871 5 : parse_error (gpgme_signature_t sig, char *args, int set_status)
872 : {
873 : gpgme_error_t err;
874 5 : char *where = strchr (args, ' ');
875 : char *which;
876 :
877 5 : if (where)
878 : {
879 5 : *where = '\0';
880 5 : which = where + 1;
881 :
882 5 : where = strchr (which, ' ');
883 5 : if (where)
884 0 : *where = '\0';
885 :
886 5 : where = args;
887 : }
888 : else
889 0 : return trace_gpg_error (GPG_ERR_INV_ENGINE);
890 :
891 5 : err = atoi (which);
892 :
893 5 : if (!strcmp (where, "proc_pkt.plaintext")
894 5 : && gpg_err_code (err) == GPG_ERR_BAD_DATA)
895 : {
896 : /* This indicates a double plaintext. The only solid way to
897 : handle this is by failing the oepration. */
898 5 : return gpg_error (GPG_ERR_BAD_DATA);
899 : }
900 0 : else if (!set_status)
901 : ;
902 0 : else if (!strcmp (where, "verify.findkey"))
903 0 : sig->status = err;
904 0 : else if (!strcmp (where, "verify.keyusage")
905 0 : && gpg_err_code (err) == GPG_ERR_WRONG_KEY_USAGE)
906 0 : sig->wrong_key_usage = 1;
907 :
908 0 : return 0;
909 : }
910 :
911 :
912 : gpgme_error_t
913 1049 : _gpgme_verify_status_handler (void *priv, gpgme_status_code_t code, char *args)
914 : {
915 1049 : gpgme_ctx_t ctx = (gpgme_ctx_t) priv;
916 : gpgme_error_t err;
917 : void *hook;
918 : op_data_t opd;
919 : gpgme_signature_t sig;
920 : char *end;
921 :
922 1049 : err = _gpgme_op_data_lookup (ctx, OPDATA_VERIFY, &hook, -1, NULL);
923 1050 : opd = hook;
924 1050 : if (err)
925 0 : return err;
926 :
927 1050 : sig = opd->current_sig;
928 :
929 1050 : switch (code)
930 : {
931 : case GPGME_STATUS_NEWSIG:
932 58 : if (sig)
933 0 : calc_sig_summary (sig);
934 58 : err = prepare_new_sig (opd);
935 58 : opd->only_newsig_seen = 1;
936 58 : opd->conflict_user_seen = 0;
937 58 : return err;
938 :
939 : case GPGME_STATUS_GOODSIG:
940 : case GPGME_STATUS_EXPSIG:
941 : case GPGME_STATUS_EXPKEYSIG:
942 : case GPGME_STATUS_BADSIG:
943 : case GPGME_STATUS_ERRSIG:
944 : case GPGME_STATUS_REVKEYSIG:
945 57 : if (sig && !opd->did_prepare_new_sig)
946 0 : calc_sig_summary (sig);
947 57 : opd->only_newsig_seen = 0;
948 57 : return parse_new_sig (opd, code, args, ctx->protocol);
949 :
950 : case GPGME_STATUS_VALIDSIG:
951 51 : opd->only_newsig_seen = 0;
952 51 : return sig ? parse_valid_sig (sig, args, ctx->protocol)
953 102 : : trace_gpg_error (GPG_ERR_INV_ENGINE);
954 :
955 : case GPGME_STATUS_NODATA:
956 3 : opd->only_newsig_seen = 0;
957 3 : if (!sig)
958 3 : return gpg_error (GPG_ERR_NO_DATA);
959 0 : sig->status = gpg_error (GPG_ERR_NO_DATA);
960 0 : break;
961 :
962 : case GPGME_STATUS_UNEXPECTED:
963 0 : opd->only_newsig_seen = 0;
964 0 : if (!sig)
965 0 : return gpg_error (GPG_ERR_GENERAL);
966 0 : sig->status = gpg_error (GPG_ERR_NO_DATA);
967 0 : break;
968 :
969 : case GPGME_STATUS_NOTATION_NAME:
970 : case GPGME_STATUS_NOTATION_FLAGS:
971 : case GPGME_STATUS_NOTATION_DATA:
972 : case GPGME_STATUS_POLICY_URL:
973 165 : opd->only_newsig_seen = 0;
974 : return sig ? parse_notation (sig, code, args)
975 165 : : trace_gpg_error (GPG_ERR_INV_ENGINE);
976 :
977 : case GPGME_STATUS_TRUST_UNDEFINED:
978 : case GPGME_STATUS_TRUST_NEVER:
979 : case GPGME_STATUS_TRUST_MARGINAL:
980 : case GPGME_STATUS_TRUST_FULLY:
981 : case GPGME_STATUS_TRUST_ULTIMATE:
982 51 : opd->only_newsig_seen = 0;
983 : return sig ? parse_trust (sig, code, args)
984 51 : : trace_gpg_error (GPG_ERR_INV_ENGINE);
985 :
986 : case GPGME_STATUS_PKA_TRUST_BAD:
987 : case GPGME_STATUS_PKA_TRUST_GOOD:
988 0 : opd->only_newsig_seen = 0;
989 : /* Check that we only get one of these status codes per
990 : signature; if not the crypto backend misbehaves. */
991 0 : if (!sig || sig->pka_trust || sig->pka_address)
992 0 : return trace_gpg_error (GPG_ERR_INV_ENGINE);
993 0 : sig->pka_trust = code == GPGME_STATUS_PKA_TRUST_GOOD? 2 : 1;
994 0 : end = strchr (args, ' ');
995 0 : if (end)
996 0 : *end = 0;
997 0 : sig->pka_address = strdup (args);
998 0 : break;
999 :
1000 : case GPGME_STATUS_TOFU_USER:
1001 15 : opd->only_newsig_seen = 0;
1002 15 : if (!sig)
1003 0 : return trace_gpg_error (GPG_ERR_INV_ENGINE);
1004 15 : err = parse_tofu_user (sig, args, ctx->protocol);
1005 : /* gpg emits TOFU User lines for each conflicting key.
1006 : * GPGME does not expose this to have a clean API and
1007 : * a GPGME user can do a keylisting with the address
1008 : * normalisation.
1009 : * So when a duplicated TOFU_USER line is encountered
1010 : * we ignore the conflicting tofu stats emited afterwards.
1011 : */
1012 15 : if (gpg_err_code (err) == GPG_ERR_DUP_VALUE)
1013 : {
1014 0 : opd->conflict_user_seen = 1;
1015 0 : break;
1016 : }
1017 15 : opd->conflict_user_seen = 0;
1018 15 : return trace_gpg_error (err);
1019 :
1020 : case GPGME_STATUS_TOFU_STATS:
1021 15 : opd->only_newsig_seen = 0;
1022 15 : if (opd->conflict_user_seen)
1023 0 : break;
1024 : return sig ? parse_tofu_stats (sig, args)
1025 15 : /* */ : trace_gpg_error (GPG_ERR_INV_ENGINE);
1026 :
1027 : case GPGME_STATUS_TOFU_STATS_LONG:
1028 15 : opd->only_newsig_seen = 0;
1029 15 : if (opd->conflict_user_seen)
1030 0 : break;
1031 15 : return sig ? parse_tofu_stats_long (sig, args, ctx->raw_description)
1032 30 : /* */ : trace_gpg_error (GPG_ERR_INV_ENGINE);
1033 :
1034 : case GPGME_STATUS_ERROR:
1035 5 : opd->only_newsig_seen = 0;
1036 : /* Some error stati are informational, so we don't return an
1037 : error code if we are not ready to process this status. */
1038 5 : return parse_error (sig, args, !!sig );
1039 :
1040 : case GPGME_STATUS_FAILURE:
1041 0 : opd->failure_code = _gpgme_parse_failure (args);
1042 0 : break;
1043 :
1044 : case GPGME_STATUS_EOF:
1045 63 : if (sig && !opd->did_prepare_new_sig)
1046 57 : calc_sig_summary (sig);
1047 63 : if (opd->only_newsig_seen && sig)
1048 : {
1049 : gpgme_signature_t sig2;
1050 : /* The last signature has no valid information - remove it
1051 : from the list. */
1052 0 : assert (!sig->next);
1053 0 : if (sig == opd->result.signatures)
1054 0 : opd->result.signatures = NULL;
1055 : else
1056 : {
1057 0 : for (sig2 = opd->result.signatures; sig2; sig2 = sig2->next)
1058 0 : if (sig2->next == sig)
1059 : {
1060 0 : sig2->next = NULL;
1061 0 : break;
1062 : }
1063 : }
1064 : /* Note that there is no need to release the members of SIG
1065 : because we won't be here if they have been set. */
1066 0 : free (sig);
1067 0 : opd->current_sig = NULL;
1068 : }
1069 63 : opd->only_newsig_seen = 0;
1070 63 : if (opd->failure_code)
1071 0 : return opd->failure_code;
1072 63 : break;
1073 :
1074 : case GPGME_STATUS_PLAINTEXT:
1075 43 : if (++opd->plaintext_seen > 1)
1076 0 : return gpg_error (GPG_ERR_BAD_DATA);
1077 43 : err = _gpgme_parse_plaintext (args, &opd->result.file_name);
1078 43 : if (err)
1079 0 : return err;
1080 :
1081 : default:
1082 552 : break;
1083 : }
1084 615 : return 0;
1085 : }
1086 :
1087 :
1088 : static gpgme_error_t
1089 725 : verify_status_handler (void *priv, gpgme_status_code_t code, char *args)
1090 : {
1091 : gpgme_error_t err;
1092 :
1093 725 : err = _gpgme_progress_status_handler (priv, code, args);
1094 724 : if (!err)
1095 724 : err = _gpgme_verify_status_handler (priv, code, args);
1096 725 : return err;
1097 : }
1098 :
1099 :
1100 : gpgme_error_t
1101 72 : _gpgme_op_verify_init_result (gpgme_ctx_t ctx)
1102 : {
1103 : void *hook;
1104 : op_data_t opd;
1105 :
1106 72 : return _gpgme_op_data_lookup (ctx, OPDATA_VERIFY, &hook,
1107 : sizeof (*opd), release_op_data);
1108 : }
1109 :
1110 :
1111 : static gpgme_error_t
1112 55 : verify_start (gpgme_ctx_t ctx, int synchronous, gpgme_data_t sig,
1113 : gpgme_data_t signed_text, gpgme_data_t plaintext)
1114 : {
1115 : gpgme_error_t err;
1116 :
1117 55 : err = _gpgme_op_reset (ctx, synchronous);
1118 55 : if (err)
1119 0 : return err;
1120 :
1121 55 : err = _gpgme_op_verify_init_result (ctx);
1122 55 : if (err)
1123 0 : return err;
1124 :
1125 55 : _gpgme_engine_set_status_handler (ctx->engine, verify_status_handler, ctx);
1126 :
1127 55 : if (!sig)
1128 0 : return gpg_error (GPG_ERR_NO_DATA);
1129 :
1130 55 : return _gpgme_engine_op_verify (ctx->engine, sig, signed_text, plaintext,
1131 : ctx);
1132 : }
1133 :
1134 :
1135 : /* Decrypt ciphertext CIPHER and make a signature verification within
1136 : CTX and store the resulting plaintext in PLAIN. */
1137 : gpgme_error_t
1138 3 : gpgme_op_verify_start (gpgme_ctx_t ctx, gpgme_data_t sig,
1139 : gpgme_data_t signed_text, gpgme_data_t plaintext)
1140 : {
1141 : gpg_error_t err;
1142 3 : TRACE_BEG3 (DEBUG_CTX, "gpgme_op_verify_start", ctx,
1143 : "sig=%p, signed_text=%p, plaintext=%p",
1144 : sig, signed_text, plaintext);
1145 :
1146 3 : if (!ctx)
1147 0 : return TRACE_ERR (gpg_error (GPG_ERR_INV_VALUE));
1148 :
1149 3 : err = verify_start (ctx, 0, sig, signed_text, plaintext);
1150 3 : return TRACE_ERR (err);
1151 : }
1152 :
1153 :
1154 : /* Decrypt ciphertext CIPHER and make a signature verification within
1155 : CTX and store the resulting plaintext in PLAIN. */
1156 : gpgme_error_t
1157 52 : gpgme_op_verify (gpgme_ctx_t ctx, gpgme_data_t sig, gpgme_data_t signed_text,
1158 : gpgme_data_t plaintext)
1159 : {
1160 : gpgme_error_t err;
1161 :
1162 52 : TRACE_BEG3 (DEBUG_CTX, "gpgme_op_verify", ctx,
1163 : "sig=%p, signed_text=%p, plaintext=%p",
1164 : sig, signed_text, plaintext);
1165 :
1166 52 : if (!ctx)
1167 0 : return TRACE_ERR (gpg_error (GPG_ERR_INV_VALUE));
1168 :
1169 52 : err = verify_start (ctx, 1, sig, signed_text, plaintext);
1170 51 : if (!err)
1171 51 : err = _gpgme_wait_one (ctx);
1172 51 : return TRACE_ERR (err);
1173 : }
1174 :
1175 :
1176 : /* Compatibility interfaces. */
1177 :
1178 : /* Get the key used to create signature IDX in CTX and return it in
1179 : R_KEY. */
1180 : gpgme_error_t
1181 0 : gpgme_get_sig_key (gpgme_ctx_t ctx, int idx, gpgme_key_t *r_key)
1182 : {
1183 : gpgme_verify_result_t result;
1184 : gpgme_signature_t sig;
1185 :
1186 0 : if (!ctx)
1187 0 : return gpg_error (GPG_ERR_INV_VALUE);
1188 :
1189 0 : result = gpgme_op_verify_result (ctx);
1190 0 : sig = result->signatures;
1191 :
1192 0 : while (sig && idx)
1193 : {
1194 0 : sig = sig->next;
1195 0 : idx--;
1196 : }
1197 0 : if (!sig || idx)
1198 0 : return gpg_error (GPG_ERR_EOF);
1199 :
1200 0 : return gpgme_get_key (ctx, sig->fpr, r_key, 0);
1201 : }
1202 :
1203 :
1204 : /* Retrieve the signature status of signature IDX in CTX after a
1205 : successful verify operation in R_STAT (if non-null). The creation
1206 : time stamp of the signature is returned in R_CREATED (if non-null).
1207 : The function returns a string containing the fingerprint. */
1208 : const char *
1209 0 : gpgme_get_sig_status (gpgme_ctx_t ctx, int idx,
1210 : _gpgme_sig_stat_t *r_stat, time_t *r_created)
1211 : {
1212 : gpgme_verify_result_t result;
1213 : gpgme_signature_t sig;
1214 :
1215 0 : result = gpgme_op_verify_result (ctx);
1216 0 : sig = result->signatures;
1217 :
1218 0 : while (sig && idx)
1219 : {
1220 0 : sig = sig->next;
1221 0 : idx--;
1222 : }
1223 0 : if (!sig || idx)
1224 0 : return NULL;
1225 :
1226 0 : if (r_stat)
1227 : {
1228 0 : switch (gpg_err_code (sig->status))
1229 : {
1230 : case GPG_ERR_NO_ERROR:
1231 0 : *r_stat = GPGME_SIG_STAT_GOOD;
1232 0 : break;
1233 :
1234 : case GPG_ERR_BAD_SIGNATURE:
1235 0 : *r_stat = GPGME_SIG_STAT_BAD;
1236 0 : break;
1237 :
1238 : case GPG_ERR_NO_PUBKEY:
1239 0 : *r_stat = GPGME_SIG_STAT_NOKEY;
1240 0 : break;
1241 :
1242 : case GPG_ERR_NO_DATA:
1243 0 : *r_stat = GPGME_SIG_STAT_NOSIG;
1244 0 : break;
1245 :
1246 : case GPG_ERR_SIG_EXPIRED:
1247 0 : *r_stat = GPGME_SIG_STAT_GOOD_EXP;
1248 0 : break;
1249 :
1250 : case GPG_ERR_KEY_EXPIRED:
1251 0 : *r_stat = GPGME_SIG_STAT_GOOD_EXPKEY;
1252 0 : break;
1253 :
1254 : default:
1255 0 : *r_stat = GPGME_SIG_STAT_ERROR;
1256 0 : break;
1257 : }
1258 : }
1259 0 : if (r_created)
1260 0 : *r_created = sig->timestamp;
1261 0 : return sig->fpr;
1262 : }
1263 :
1264 :
1265 : /* Retrieve certain attributes of a signature. IDX is the index
1266 : number of the signature after a successful verify operation. WHAT
1267 : is an attribute where GPGME_ATTR_EXPIRE is probably the most useful
1268 : one. WHATIDX is to be passed as 0 for most attributes . */
1269 : unsigned long
1270 0 : gpgme_get_sig_ulong_attr (gpgme_ctx_t ctx, int idx,
1271 : _gpgme_attr_t what, int whatidx)
1272 : {
1273 : gpgme_verify_result_t result;
1274 : gpgme_signature_t sig;
1275 :
1276 : (void)whatidx;
1277 :
1278 0 : result = gpgme_op_verify_result (ctx);
1279 0 : sig = result->signatures;
1280 :
1281 0 : while (sig && idx)
1282 : {
1283 0 : sig = sig->next;
1284 0 : idx--;
1285 : }
1286 0 : if (!sig || idx)
1287 0 : return 0;
1288 :
1289 0 : switch (what)
1290 : {
1291 : case GPGME_ATTR_CREATED:
1292 0 : return sig->timestamp;
1293 :
1294 : case GPGME_ATTR_EXPIRE:
1295 0 : return sig->exp_timestamp;
1296 :
1297 : case GPGME_ATTR_VALIDITY:
1298 0 : return (unsigned long) sig->validity;
1299 :
1300 : case GPGME_ATTR_SIG_STATUS:
1301 0 : switch (gpg_err_code (sig->status))
1302 : {
1303 : case GPG_ERR_NO_ERROR:
1304 0 : return GPGME_SIG_STAT_GOOD;
1305 :
1306 : case GPG_ERR_BAD_SIGNATURE:
1307 0 : return GPGME_SIG_STAT_BAD;
1308 :
1309 : case GPG_ERR_NO_PUBKEY:
1310 0 : return GPGME_SIG_STAT_NOKEY;
1311 :
1312 : case GPG_ERR_NO_DATA:
1313 0 : return GPGME_SIG_STAT_NOSIG;
1314 :
1315 : case GPG_ERR_SIG_EXPIRED:
1316 0 : return GPGME_SIG_STAT_GOOD_EXP;
1317 :
1318 : case GPG_ERR_KEY_EXPIRED:
1319 0 : return GPGME_SIG_STAT_GOOD_EXPKEY;
1320 :
1321 : default:
1322 0 : return GPGME_SIG_STAT_ERROR;
1323 : }
1324 :
1325 : case GPGME_ATTR_SIG_SUMMARY:
1326 0 : return sig->summary;
1327 :
1328 : default:
1329 0 : break;
1330 : }
1331 0 : return 0;
1332 : }
1333 :
1334 :
1335 : const char *
1336 0 : gpgme_get_sig_string_attr (gpgme_ctx_t ctx, int idx,
1337 : _gpgme_attr_t what, int whatidx)
1338 : {
1339 : gpgme_verify_result_t result;
1340 : gpgme_signature_t sig;
1341 :
1342 0 : result = gpgme_op_verify_result (ctx);
1343 0 : sig = result->signatures;
1344 :
1345 0 : while (sig && idx)
1346 : {
1347 0 : sig = sig->next;
1348 0 : idx--;
1349 : }
1350 0 : if (!sig || idx)
1351 0 : return NULL;
1352 :
1353 0 : switch (what)
1354 : {
1355 : case GPGME_ATTR_FPR:
1356 0 : return sig->fpr;
1357 :
1358 : case GPGME_ATTR_ERRTOK:
1359 0 : if (whatidx == 1)
1360 0 : return sig->wrong_key_usage ? "Wrong_Key_Usage" : "";
1361 : else
1362 0 : return "";
1363 : default:
1364 0 : break;
1365 : }
1366 :
1367 0 : return NULL;
1368 : }
|