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