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