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 :
30 : #include "gpgme.h"
31 : #include "debug.h"
32 : #include "util.h"
33 : #include "context.h"
34 : #include "ops.h"
35 :
36 :
37 : typedef struct
38 : {
39 : struct _gpgme_op_verify_result result;
40 :
41 : /* The error code from a FAILURE status line or 0. */
42 : gpg_error_t failure_code;
43 :
44 : gpgme_signature_t current_sig;
45 : int did_prepare_new_sig;
46 : int only_newsig_seen;
47 : int plaintext_seen;
48 : } *op_data_t;
49 :
50 :
51 : static void
52 9 : release_op_data (void *hook)
53 : {
54 9 : op_data_t opd = (op_data_t) hook;
55 9 : gpgme_signature_t sig = opd->result.signatures;
56 :
57 25 : while (sig)
58 : {
59 7 : gpgme_signature_t next = sig->next;
60 7 : gpgme_sig_notation_t notation = sig->notations;
61 :
62 20 : while (notation)
63 : {
64 6 : gpgme_sig_notation_t next_nota = notation->next;
65 :
66 6 : _gpgme_sig_notation_free (notation);
67 6 : notation = next_nota;
68 : }
69 :
70 7 : if (sig->fpr)
71 7 : free (sig->fpr);
72 7 : if (sig->pka_address)
73 0 : free (sig->pka_address);
74 7 : free (sig);
75 7 : sig = next;
76 : }
77 :
78 9 : if (opd->result.file_name)
79 3 : free (opd->result.file_name);
80 9 : }
81 :
82 :
83 : gpgme_verify_result_t
84 7 : gpgme_op_verify_result (gpgme_ctx_t ctx)
85 : {
86 : void *hook;
87 : op_data_t opd;
88 : gpgme_error_t err;
89 : gpgme_signature_t sig;
90 :
91 7 : TRACE_BEG (DEBUG_CTX, "gpgme_op_verify_result", ctx);
92 7 : err = _gpgme_op_data_lookup (ctx, OPDATA_VERIFY, &hook, -1, NULL);
93 7 : opd = hook;
94 7 : if (err || !opd)
95 : {
96 0 : TRACE_SUC0 ("result=(null)");
97 0 : return NULL;
98 : }
99 :
100 : /* It is possible that we saw a new signature only followed by an
101 : ERROR line for that. In particular a missing X.509 key triggers
102 : this. In this case it is surprising that the summary field has
103 : not been updated. We fix it here by explicitly looking for this
104 : case. The real fix would be to have GPGME emit ERRSIG. */
105 14 : for (sig = opd->result.signatures; sig; sig = sig->next)
106 : {
107 7 : if (!sig->summary)
108 : {
109 4 : switch (gpg_err_code (sig->status))
110 : {
111 : case GPG_ERR_KEY_EXPIRED:
112 0 : sig->summary |= GPGME_SIGSUM_KEY_EXPIRED;
113 0 : break;
114 :
115 : case GPG_ERR_NO_PUBKEY:
116 0 : sig->summary |= GPGME_SIGSUM_KEY_MISSING;
117 0 : break;
118 :
119 : default:
120 4 : break;
121 : }
122 : }
123 : }
124 :
125 : /* Now for some tracing stuff. */
126 : if (_gpgme_debug_trace ())
127 : {
128 : int i;
129 :
130 14 : for (sig = opd->result.signatures, i = 0; sig; sig = sig->next, i++)
131 : {
132 7 : TRACE_LOG4 ("sig[%i] = fpr %s, summary 0x%x, status %s",
133 : i, sig->fpr, sig->summary, gpg_strerror (sig->status));
134 7 : TRACE_LOG6 ("sig[%i] = timestamps 0x%x/0x%x flags:%s%s%s",
135 : i, sig->timestamp, sig->exp_timestamp,
136 : sig->wrong_key_usage ? "wrong key usage" : "",
137 : sig->pka_trust == 1 ? "pka bad"
138 : : (sig->pka_trust == 2 ? "pka_okay" : "pka RFU"),
139 : sig->chain_model ? "chain model" : "");
140 7 : TRACE_LOG5 ("sig[%i] = validity 0x%x (%s), algos %s/%s",
141 : i, sig->validity, gpg_strerror (sig->validity_reason),
142 : gpgme_pubkey_algo_name (sig->pubkey_algo),
143 : gpgme_hash_algo_name (sig->hash_algo));
144 7 : if (sig->pka_address)
145 : {
146 0 : TRACE_LOG2 ("sig[%i] = PKA address %s", i, sig->pka_address);
147 : }
148 7 : if (sig->notations)
149 : {
150 2 : TRACE_LOG1 ("sig[%i] = has notations (not shown)", i);
151 : }
152 : }
153 : }
154 :
155 7 : TRACE_SUC1 ("result=%p", &opd->result);
156 7 : return &opd->result;
157 : }
158 :
159 :
160 : /* Build a summary vector from RESULT. */
161 : static void
162 7 : calc_sig_summary (gpgme_signature_t sig)
163 : {
164 7 : unsigned long sum = 0;
165 :
166 : /* Calculate the red/green flag. */
167 7 : if (sig->validity == GPGME_VALIDITY_FULL
168 6 : || sig->validity == GPGME_VALIDITY_ULTIMATE)
169 : {
170 2 : if (gpg_err_code (sig->status) == GPG_ERR_NO_ERROR
171 0 : || gpg_err_code (sig->status) == GPG_ERR_SIG_EXPIRED
172 0 : || gpg_err_code (sig->status) == GPG_ERR_KEY_EXPIRED)
173 1 : sum |= GPGME_SIGSUM_GREEN;
174 : }
175 6 : else if (sig->validity == GPGME_VALIDITY_NEVER)
176 : {
177 0 : if (gpg_err_code (sig->status) == GPG_ERR_NO_ERROR
178 0 : || gpg_err_code (sig->status) == GPG_ERR_SIG_EXPIRED
179 0 : || gpg_err_code (sig->status) == GPG_ERR_KEY_EXPIRED)
180 0 : sum |= GPGME_SIGSUM_RED;
181 : }
182 6 : else if (gpg_err_code (sig->status) == GPG_ERR_BAD_SIGNATURE)
183 2 : sum |= GPGME_SIGSUM_RED;
184 :
185 :
186 : /* FIXME: handle the case when key and message are expired. */
187 7 : switch (gpg_err_code (sig->status))
188 : {
189 : case GPG_ERR_SIG_EXPIRED:
190 0 : sum |= GPGME_SIGSUM_SIG_EXPIRED;
191 0 : break;
192 :
193 : case GPG_ERR_KEY_EXPIRED:
194 0 : sum |= GPGME_SIGSUM_KEY_EXPIRED;
195 0 : break;
196 :
197 : case GPG_ERR_NO_PUBKEY:
198 0 : sum |= GPGME_SIGSUM_KEY_MISSING;
199 0 : break;
200 :
201 : case GPG_ERR_CERT_REVOKED:
202 0 : sum |= GPGME_SIGSUM_KEY_REVOKED;
203 0 : break;
204 :
205 : case GPG_ERR_BAD_SIGNATURE:
206 : case GPG_ERR_NO_ERROR:
207 7 : break;
208 :
209 : default:
210 0 : sum |= GPGME_SIGSUM_SYS_ERROR;
211 0 : break;
212 : }
213 :
214 : /* Now look at the certain reason codes. */
215 7 : switch (gpg_err_code (sig->validity_reason))
216 : {
217 : case GPG_ERR_CRL_TOO_OLD:
218 0 : if (sig->validity == GPGME_VALIDITY_UNKNOWN)
219 0 : sum |= GPGME_SIGSUM_CRL_TOO_OLD;
220 0 : break;
221 :
222 : case GPG_ERR_CERT_REVOKED:
223 : /* Note that this is a second way to set this flag. It may also
224 : have been set due to a sig->status of STATUS_REVKEYSIG from
225 : parse_new_sig. */
226 0 : sum |= GPGME_SIGSUM_KEY_REVOKED;
227 0 : break;
228 :
229 : default:
230 7 : break;
231 : }
232 :
233 : /* Check other flags. */
234 7 : if (sig->wrong_key_usage)
235 0 : sum |= GPGME_SIGSUM_BAD_POLICY;
236 :
237 : /* Set the valid flag when the signature is unquestionable
238 : valid. (The test is identical to if(sum == GPGME_SIGSUM_GREEN)). */
239 7 : if ((sum & GPGME_SIGSUM_GREEN) && !(sum & ~GPGME_SIGSUM_GREEN))
240 1 : sum |= GPGME_SIGSUM_VALID;
241 :
242 7 : sig->summary = sum;
243 7 : }
244 :
245 :
246 : static gpgme_error_t
247 7 : prepare_new_sig (op_data_t opd)
248 : {
249 : gpgme_signature_t sig;
250 :
251 7 : if (opd->only_newsig_seen && opd->current_sig)
252 : {
253 : /* We have only seen the NEWSIG status and nothing else - we
254 : better skip this signature therefore and reuse it for the
255 : next possible signature. */
256 0 : sig = opd->current_sig;
257 0 : memset (sig, 0, sizeof *sig);
258 0 : assert (opd->result.signatures == sig);
259 : }
260 : else
261 : {
262 7 : sig = calloc (1, sizeof (*sig));
263 7 : if (!sig)
264 0 : return gpg_error_from_syserror ();
265 7 : if (!opd->result.signatures)
266 7 : opd->result.signatures = sig;
267 7 : if (opd->current_sig)
268 0 : opd->current_sig->next = sig;
269 7 : opd->current_sig = sig;
270 : }
271 7 : opd->did_prepare_new_sig = 1;
272 7 : opd->only_newsig_seen = 0;
273 7 : return 0;
274 : }
275 :
276 : static gpgme_error_t
277 7 : parse_new_sig (op_data_t opd, gpgme_status_code_t code, char *args,
278 : gpgme_protocol_t protocol)
279 : {
280 : gpgme_signature_t sig;
281 7 : char *end = strchr (args, ' ');
282 : char *tail;
283 :
284 7 : if (end)
285 : {
286 7 : *end = '\0';
287 7 : end++;
288 : }
289 :
290 7 : if (!opd->did_prepare_new_sig)
291 : {
292 : gpg_error_t err;
293 :
294 0 : err = prepare_new_sig (opd);
295 0 : if (err)
296 0 : return err;
297 : }
298 7 : assert (opd->did_prepare_new_sig);
299 7 : opd->did_prepare_new_sig = 0;
300 :
301 7 : assert (opd->current_sig);
302 7 : sig = opd->current_sig;
303 :
304 : /* FIXME: We should set the source of the state. */
305 7 : switch (code)
306 : {
307 : case GPGME_STATUS_GOODSIG:
308 5 : sig->status = gpg_error (GPG_ERR_NO_ERROR);
309 5 : break;
310 :
311 : case GPGME_STATUS_EXPSIG:
312 0 : sig->status = gpg_error (GPG_ERR_SIG_EXPIRED);
313 0 : break;
314 :
315 : case GPGME_STATUS_EXPKEYSIG:
316 0 : sig->status = gpg_error (GPG_ERR_KEY_EXPIRED);
317 0 : break;
318 :
319 : case GPGME_STATUS_BADSIG:
320 2 : sig->status = gpg_error (GPG_ERR_BAD_SIGNATURE);
321 2 : break;
322 :
323 : case GPGME_STATUS_REVKEYSIG:
324 0 : sig->status = gpg_error (GPG_ERR_CERT_REVOKED);
325 0 : break;
326 :
327 : case GPGME_STATUS_ERRSIG:
328 : /* Parse the pubkey algo. */
329 0 : if (!end)
330 0 : goto parse_err_sig_fail;
331 0 : gpg_err_set_errno (0);
332 0 : sig->pubkey_algo = _gpgme_map_pk_algo (strtol (end, &tail, 0), protocol);
333 0 : if (errno || end == tail || *tail != ' ')
334 : goto parse_err_sig_fail;
335 0 : end = tail;
336 0 : while (*end == ' ')
337 0 : end++;
338 :
339 : /* Parse the hash algo. */
340 0 : if (!*end)
341 0 : goto parse_err_sig_fail;
342 0 : gpg_err_set_errno (0);
343 0 : sig->hash_algo = strtol (end, &tail, 0);
344 0 : if (errno || end == tail || *tail != ' ')
345 : goto parse_err_sig_fail;
346 0 : end = tail;
347 0 : while (*end == ' ')
348 0 : end++;
349 :
350 : /* Skip the sig class. */
351 0 : end = strchr (end, ' ');
352 0 : if (!end)
353 0 : goto parse_err_sig_fail;
354 0 : while (*end == ' ')
355 0 : end++;
356 :
357 : /* Parse the timestamp. */
358 0 : sig->timestamp = _gpgme_parse_timestamp (end, &tail);
359 0 : if (sig->timestamp == -1 || end == tail || (*tail && *tail != ' '))
360 0 : return trace_gpg_error (GPG_ERR_INV_ENGINE);
361 0 : end = tail;
362 0 : while (*end == ' ')
363 0 : end++;
364 :
365 : /* Parse the return code. */
366 0 : if (end[0] && (!end[1] || end[1] == ' '))
367 : {
368 0 : switch (end[0])
369 : {
370 : case '4':
371 0 : sig->status = gpg_error (GPG_ERR_UNSUPPORTED_ALGORITHM);
372 0 : break;
373 :
374 : case '9':
375 0 : sig->status = gpg_error (GPG_ERR_NO_PUBKEY);
376 0 : break;
377 :
378 : default:
379 0 : sig->status = gpg_error (GPG_ERR_GENERAL);
380 : }
381 : }
382 : else
383 : goto parse_err_sig_fail;
384 :
385 0 : goto parse_err_sig_ok;
386 :
387 : parse_err_sig_fail:
388 0 : sig->status = gpg_error (GPG_ERR_GENERAL);
389 : parse_err_sig_ok:
390 0 : break;
391 :
392 : default:
393 0 : return gpg_error (GPG_ERR_GENERAL);
394 : }
395 :
396 7 : if (*args)
397 : {
398 7 : sig->fpr = strdup (args);
399 7 : if (!sig->fpr)
400 0 : return gpg_error_from_syserror ();
401 : }
402 7 : return 0;
403 : }
404 :
405 :
406 : static gpgme_error_t
407 5 : parse_valid_sig (gpgme_signature_t sig, char *args, gpgme_protocol_t protocol)
408 : {
409 5 : char *end = strchr (args, ' ');
410 5 : if (end)
411 : {
412 5 : *end = '\0';
413 5 : end++;
414 : }
415 :
416 5 : if (!*args)
417 : /* We require at least the fingerprint. */
418 0 : return gpg_error (GPG_ERR_GENERAL);
419 :
420 5 : if (sig->fpr)
421 5 : free (sig->fpr);
422 5 : sig->fpr = strdup (args);
423 5 : if (!sig->fpr)
424 0 : return gpg_error_from_syserror ();
425 :
426 : /* Skip the creation date. */
427 5 : end = strchr (end, ' ');
428 5 : if (end)
429 : {
430 : char *tail;
431 :
432 5 : sig->timestamp = _gpgme_parse_timestamp (end, &tail);
433 5 : if (sig->timestamp == -1 || end == tail || (*tail && *tail != ' '))
434 0 : return trace_gpg_error (GPG_ERR_INV_ENGINE);
435 5 : end = tail;
436 :
437 5 : sig->exp_timestamp = _gpgme_parse_timestamp (end, &tail);
438 5 : if (sig->exp_timestamp == -1 || end == tail || (*tail && *tail != ' '))
439 0 : return trace_gpg_error (GPG_ERR_INV_ENGINE);
440 5 : end = tail;
441 :
442 15 : while (*end == ' ')
443 5 : end++;
444 : /* Skip the signature version. */
445 5 : end = strchr (end, ' ');
446 5 : if (end)
447 : {
448 15 : while (*end == ' ')
449 5 : end++;
450 :
451 : /* Skip the reserved field. */
452 5 : end = strchr (end, ' ');
453 5 : if (end)
454 : {
455 : /* Parse the pubkey algo. */
456 5 : gpg_err_set_errno (0);
457 5 : sig->pubkey_algo = _gpgme_map_pk_algo (strtol (end, &tail, 0),
458 : protocol);
459 5 : if (errno || end == tail || *tail != ' ')
460 0 : return trace_gpg_error (GPG_ERR_INV_ENGINE);
461 5 : end = tail;
462 :
463 15 : while (*end == ' ')
464 5 : end++;
465 :
466 5 : if (*end)
467 : {
468 : /* Parse the hash algo. */
469 :
470 5 : gpg_err_set_errno (0);
471 5 : sig->hash_algo = strtol (end, &tail, 0);
472 5 : if (errno || end == tail || *tail != ' ')
473 0 : return trace_gpg_error (GPG_ERR_INV_ENGINE);
474 5 : end = tail;
475 : }
476 : }
477 : }
478 : }
479 5 : return 0;
480 : }
481 :
482 :
483 : static gpgme_error_t
484 11 : parse_notation (gpgme_signature_t sig, gpgme_status_code_t code, char *args)
485 : {
486 : gpgme_error_t err;
487 11 : gpgme_sig_notation_t *lastp = &sig->notations;
488 11 : gpgme_sig_notation_t notation = sig->notations;
489 11 : char *end = strchr (args, ' ');
490 :
491 11 : if (end)
492 0 : *end = '\0';
493 :
494 11 : if (code == GPGME_STATUS_NOTATION_NAME || code == GPGME_STATUS_POLICY_URL)
495 : {
496 : /* FIXME: We could keep a pointer to the last notation in the list. */
497 18 : while (notation && notation->value)
498 : {
499 6 : lastp = ¬ation->next;
500 6 : notation = notation->next;
501 : }
502 :
503 6 : if (notation)
504 : /* There is another notation name without data for the
505 : previous one. The crypto backend misbehaves. */
506 0 : return trace_gpg_error (GPG_ERR_INV_ENGINE);
507 :
508 6 : err = _gpgme_sig_notation_create (¬ation, NULL, 0, NULL, 0, 0);
509 6 : if (err)
510 0 : return err;
511 :
512 6 : if (code == GPGME_STATUS_NOTATION_NAME)
513 : {
514 4 : err = _gpgme_decode_percent_string (args, ¬ation->name, 0, 0);
515 4 : if (err)
516 : {
517 0 : _gpgme_sig_notation_free (notation);
518 0 : return err;
519 : }
520 :
521 4 : notation->name_len = strlen (notation->name);
522 :
523 : /* FIXME: For now we fake the human-readable flag. The
524 : critical flag can not be reported as it is not
525 : provided. */
526 4 : notation->flags = GPGME_SIG_NOTATION_HUMAN_READABLE;
527 4 : notation->human_readable = 1;
528 : }
529 : else
530 : {
531 : /* This is a policy URL. */
532 :
533 2 : err = _gpgme_decode_percent_string (args, ¬ation->value, 0, 0);
534 2 : if (err)
535 : {
536 0 : _gpgme_sig_notation_free (notation);
537 0 : return err;
538 : }
539 :
540 2 : notation->value_len = strlen (notation->value);
541 : }
542 6 : *lastp = notation;
543 : }
544 5 : else if (code == GPGME_STATUS_NOTATION_DATA)
545 : {
546 5 : int len = strlen (args) + 1;
547 : char *dest;
548 :
549 : /* FIXME: We could keep a pointer to the last notation in the list. */
550 18 : while (notation && notation->next)
551 : {
552 8 : lastp = ¬ation->next;
553 8 : notation = notation->next;
554 : }
555 :
556 5 : if (!notation || !notation->name)
557 : /* There is notation data without a previous notation
558 : name. The crypto backend misbehaves. */
559 0 : return trace_gpg_error (GPG_ERR_INV_ENGINE);
560 :
561 5 : if (!notation->value)
562 : {
563 4 : dest = notation->value = malloc (len);
564 4 : if (!dest)
565 0 : return gpg_error_from_syserror ();
566 : }
567 : else
568 : {
569 1 : int cur_len = strlen (notation->value);
570 1 : dest = realloc (notation->value, len + strlen (notation->value));
571 1 : if (!dest)
572 0 : return gpg_error_from_syserror ();
573 1 : notation->value = dest;
574 1 : dest += cur_len;
575 : }
576 :
577 5 : err = _gpgme_decode_percent_string (args, &dest, len, 0);
578 5 : if (err)
579 0 : return err;
580 :
581 5 : notation->value_len += strlen (dest);
582 : }
583 : else
584 0 : return trace_gpg_error (GPG_ERR_INV_ENGINE);
585 11 : return 0;
586 : }
587 :
588 :
589 : static gpgme_error_t
590 5 : parse_trust (gpgme_signature_t sig, gpgme_status_code_t code, char *args)
591 : {
592 5 : char *end = strchr (args, ' ');
593 :
594 5 : if (end)
595 1 : *end = '\0';
596 :
597 5 : switch (code)
598 : {
599 : case GPGME_STATUS_TRUST_UNDEFINED:
600 : default:
601 4 : sig->validity = GPGME_VALIDITY_UNKNOWN;
602 4 : break;
603 :
604 : case GPGME_STATUS_TRUST_NEVER:
605 0 : sig->validity = GPGME_VALIDITY_NEVER;
606 0 : break;
607 :
608 : case GPGME_STATUS_TRUST_MARGINAL:
609 0 : sig->validity = GPGME_VALIDITY_MARGINAL;
610 0 : break;
611 :
612 : case GPGME_STATUS_TRUST_FULLY:
613 : case GPGME_STATUS_TRUST_ULTIMATE:
614 1 : sig->validity = GPGME_VALIDITY_FULL;
615 1 : break;
616 : }
617 :
618 5 : sig->validity_reason = 0;
619 5 : sig->chain_model = 0;
620 5 : if (*args)
621 : {
622 1 : sig->validity_reason = atoi (args);
623 3 : while (*args && *args != ' ')
624 1 : args++;
625 1 : if (*args)
626 : {
627 0 : while (*args == ' ')
628 0 : args++;
629 0 : if (!strncmp (args, "chain", 2) && (args[2] == ' ' || !args[2]))
630 0 : sig->chain_model = 1;
631 : }
632 : }
633 :
634 5 : return 0;
635 : }
636 :
637 :
638 : /* Parse an error status line and if SET_STATUS is true update the
639 : result status as appropriate. With SET_STATUS being false, only
640 : check for an error. */
641 : static gpgme_error_t
642 1 : parse_error (gpgme_signature_t sig, char *args, int set_status)
643 : {
644 : gpgme_error_t err;
645 1 : char *where = strchr (args, ' ');
646 : char *which;
647 :
648 1 : if (where)
649 : {
650 1 : *where = '\0';
651 1 : which = where + 1;
652 :
653 1 : where = strchr (which, ' ');
654 1 : if (where)
655 0 : *where = '\0';
656 :
657 1 : where = args;
658 : }
659 : else
660 0 : return trace_gpg_error (GPG_ERR_INV_ENGINE);
661 :
662 1 : err = atoi (which);
663 :
664 1 : if (!strcmp (where, "proc_pkt.plaintext")
665 1 : && gpg_err_code (err) == GPG_ERR_BAD_DATA)
666 : {
667 : /* This indicates a double plaintext. The only solid way to
668 : handle this is by failing the oepration. */
669 1 : return gpg_error (GPG_ERR_BAD_DATA);
670 : }
671 0 : else if (!set_status)
672 : ;
673 0 : else if (!strcmp (where, "verify.findkey"))
674 0 : sig->status = err;
675 0 : else if (!strcmp (where, "verify.keyusage")
676 0 : && gpg_err_code (err) == GPG_ERR_WRONG_KEY_USAGE)
677 0 : sig->wrong_key_usage = 1;
678 :
679 0 : return 0;
680 : }
681 :
682 :
683 : gpgme_error_t
684 72 : _gpgme_verify_status_handler (void *priv, gpgme_status_code_t code, char *args)
685 : {
686 72 : gpgme_ctx_t ctx = (gpgme_ctx_t) priv;
687 : gpgme_error_t err;
688 : void *hook;
689 : op_data_t opd;
690 : gpgme_signature_t sig;
691 : char *end;
692 :
693 72 : err = _gpgme_op_data_lookup (ctx, OPDATA_VERIFY, &hook, -1, NULL);
694 72 : opd = hook;
695 72 : if (err)
696 0 : return err;
697 :
698 72 : sig = opd->current_sig;
699 :
700 72 : switch (code)
701 : {
702 : case GPGME_STATUS_NEWSIG:
703 7 : if (sig)
704 0 : calc_sig_summary (sig);
705 7 : err = prepare_new_sig (opd);
706 7 : opd->only_newsig_seen = 1;
707 7 : return err;
708 :
709 : case GPGME_STATUS_GOODSIG:
710 : case GPGME_STATUS_EXPSIG:
711 : case GPGME_STATUS_EXPKEYSIG:
712 : case GPGME_STATUS_BADSIG:
713 : case GPGME_STATUS_ERRSIG:
714 : case GPGME_STATUS_REVKEYSIG:
715 7 : if (sig && !opd->did_prepare_new_sig)
716 0 : calc_sig_summary (sig);
717 7 : opd->only_newsig_seen = 0;
718 7 : return parse_new_sig (opd, code, args, ctx->protocol);
719 :
720 : case GPGME_STATUS_VALIDSIG:
721 5 : opd->only_newsig_seen = 0;
722 10 : return sig ? parse_valid_sig (sig, args, ctx->protocol)
723 10 : : trace_gpg_error (GPG_ERR_INV_ENGINE);
724 :
725 : case GPGME_STATUS_NODATA:
726 1 : opd->only_newsig_seen = 0;
727 1 : if (!sig)
728 1 : return gpg_error (GPG_ERR_NO_DATA);
729 0 : sig->status = gpg_error (GPG_ERR_NO_DATA);
730 0 : break;
731 :
732 : case GPGME_STATUS_UNEXPECTED:
733 0 : opd->only_newsig_seen = 0;
734 0 : if (!sig)
735 0 : return gpg_error (GPG_ERR_GENERAL);
736 0 : sig->status = gpg_error (GPG_ERR_NO_DATA);
737 0 : break;
738 :
739 : case GPGME_STATUS_NOTATION_NAME:
740 : case GPGME_STATUS_NOTATION_DATA:
741 : case GPGME_STATUS_POLICY_URL:
742 11 : opd->only_newsig_seen = 0;
743 11 : return sig ? parse_notation (sig, code, args)
744 11 : : trace_gpg_error (GPG_ERR_INV_ENGINE);
745 :
746 : case GPGME_STATUS_TRUST_UNDEFINED:
747 : case GPGME_STATUS_TRUST_NEVER:
748 : case GPGME_STATUS_TRUST_MARGINAL:
749 : case GPGME_STATUS_TRUST_FULLY:
750 : case GPGME_STATUS_TRUST_ULTIMATE:
751 5 : opd->only_newsig_seen = 0;
752 5 : return sig ? parse_trust (sig, code, args)
753 5 : : trace_gpg_error (GPG_ERR_INV_ENGINE);
754 :
755 : case GPGME_STATUS_PKA_TRUST_BAD:
756 : case GPGME_STATUS_PKA_TRUST_GOOD:
757 0 : opd->only_newsig_seen = 0;
758 : /* Check that we only get one of these status codes per
759 : signature; if not the crypto backend misbehaves. */
760 0 : if (!sig || sig->pka_trust || sig->pka_address)
761 0 : return trace_gpg_error (GPG_ERR_INV_ENGINE);
762 0 : sig->pka_trust = code == GPGME_STATUS_PKA_TRUST_GOOD? 2 : 1;
763 0 : end = strchr (args, ' ');
764 0 : if (end)
765 0 : *end = 0;
766 0 : sig->pka_address = strdup (args);
767 0 : break;
768 :
769 : case GPGME_STATUS_ERROR:
770 1 : opd->only_newsig_seen = 0;
771 : /* Some error stati are informational, so we don't return an
772 : error code if we are not ready to process this status. */
773 1 : return parse_error (sig, args, !!sig );
774 :
775 : case GPGME_STATUS_FAILURE:
776 0 : opd->failure_code = _gpgme_parse_failure (args);
777 0 : break;
778 :
779 : case GPGME_STATUS_EOF:
780 7 : if (sig && !opd->did_prepare_new_sig)
781 7 : calc_sig_summary (sig);
782 7 : if (opd->only_newsig_seen && sig)
783 : {
784 : gpgme_signature_t sig2;
785 : /* The last signature has no valid information - remove it
786 : from the list. */
787 0 : assert (!sig->next);
788 0 : if (sig == opd->result.signatures)
789 0 : opd->result.signatures = NULL;
790 : else
791 : {
792 0 : for (sig2 = opd->result.signatures; sig2; sig2 = sig2->next)
793 0 : if (sig2->next == sig)
794 : {
795 0 : sig2->next = NULL;
796 0 : break;
797 : }
798 : }
799 : /* Note that there is no need to release the members of SIG
800 : because we won't be here if they have been set. */
801 0 : free (sig);
802 0 : opd->current_sig = NULL;
803 : }
804 7 : opd->only_newsig_seen = 0;
805 7 : if (opd->failure_code)
806 0 : return opd->failure_code;
807 7 : break;
808 :
809 : case GPGME_STATUS_PLAINTEXT:
810 4 : if (++opd->plaintext_seen > 1)
811 0 : return gpg_error (GPG_ERR_BAD_DATA);
812 4 : err = _gpgme_parse_plaintext (args, &opd->result.file_name);
813 4 : if (err)
814 0 : return err;
815 :
816 : default:
817 28 : break;
818 : }
819 35 : return 0;
820 : }
821 :
822 :
823 : static gpgme_error_t
824 56 : verify_status_handler (void *priv, gpgme_status_code_t code, char *args)
825 : {
826 : gpgme_error_t err;
827 :
828 56 : err = _gpgme_progress_status_handler (priv, code, args);
829 56 : if (!err)
830 56 : err = _gpgme_verify_status_handler (priv, code, args);
831 56 : return err;
832 : }
833 :
834 :
835 : gpgme_error_t
836 9 : _gpgme_op_verify_init_result (gpgme_ctx_t ctx)
837 : {
838 : void *hook;
839 : op_data_t opd;
840 :
841 9 : return _gpgme_op_data_lookup (ctx, OPDATA_VERIFY, &hook,
842 : sizeof (*opd), release_op_data);
843 : }
844 :
845 :
846 : static gpgme_error_t
847 8 : verify_start (gpgme_ctx_t ctx, int synchronous, gpgme_data_t sig,
848 : gpgme_data_t signed_text, gpgme_data_t plaintext)
849 : {
850 : gpgme_error_t err;
851 :
852 8 : err = _gpgme_op_reset (ctx, synchronous);
853 8 : if (err)
854 0 : return err;
855 :
856 8 : err = _gpgme_op_verify_init_result (ctx);
857 8 : if (err)
858 0 : return err;
859 :
860 8 : _gpgme_engine_set_status_handler (ctx->engine, verify_status_handler, ctx);
861 :
862 8 : if (!sig)
863 0 : return gpg_error (GPG_ERR_NO_DATA);
864 8 : if (!signed_text && !plaintext)
865 0 : return gpg_error (GPG_ERR_INV_VALUE);
866 :
867 8 : return _gpgme_engine_op_verify (ctx->engine, sig, signed_text, plaintext);
868 : }
869 :
870 :
871 : /* Decrypt ciphertext CIPHER and make a signature verification within
872 : CTX and store the resulting plaintext in PLAIN. */
873 : gpgme_error_t
874 1 : gpgme_op_verify_start (gpgme_ctx_t ctx, gpgme_data_t sig,
875 : gpgme_data_t signed_text, gpgme_data_t plaintext)
876 : {
877 : gpg_error_t err;
878 1 : TRACE_BEG3 (DEBUG_CTX, "gpgme_op_verify_start", ctx,
879 : "sig=%p, signed_text=%p, plaintext=%p",
880 : sig, signed_text, plaintext);
881 :
882 1 : if (!ctx)
883 0 : return TRACE_ERR (gpg_error (GPG_ERR_INV_VALUE));
884 :
885 1 : err = verify_start (ctx, 0, sig, signed_text, plaintext);
886 1 : return TRACE_ERR (err);
887 : }
888 :
889 :
890 : /* Decrypt ciphertext CIPHER and make a signature verification within
891 : CTX and store the resulting plaintext in PLAIN. */
892 : gpgme_error_t
893 7 : gpgme_op_verify (gpgme_ctx_t ctx, gpgme_data_t sig, gpgme_data_t signed_text,
894 : gpgme_data_t plaintext)
895 : {
896 : gpgme_error_t err;
897 :
898 7 : TRACE_BEG3 (DEBUG_CTX, "gpgme_op_verify", ctx,
899 : "sig=%p, signed_text=%p, plaintext=%p",
900 : sig, signed_text, plaintext);
901 :
902 7 : if (!ctx)
903 0 : return TRACE_ERR (gpg_error (GPG_ERR_INV_VALUE));
904 :
905 7 : err = verify_start (ctx, 1, sig, signed_text, plaintext);
906 7 : if (!err)
907 7 : err = _gpgme_wait_one (ctx);
908 7 : return TRACE_ERR (err);
909 : }
910 :
911 :
912 : /* Compatibility interfaces. */
913 :
914 : /* Get the key used to create signature IDX in CTX and return it in
915 : R_KEY. */
916 : gpgme_error_t
917 0 : gpgme_get_sig_key (gpgme_ctx_t ctx, int idx, gpgme_key_t *r_key)
918 : {
919 : gpgme_verify_result_t result;
920 : gpgme_signature_t sig;
921 :
922 0 : if (!ctx)
923 0 : return gpg_error (GPG_ERR_INV_VALUE);
924 :
925 0 : result = gpgme_op_verify_result (ctx);
926 0 : sig = result->signatures;
927 :
928 0 : while (sig && idx)
929 : {
930 0 : sig = sig->next;
931 0 : idx--;
932 : }
933 0 : if (!sig || idx)
934 0 : return gpg_error (GPG_ERR_EOF);
935 :
936 0 : return gpgme_get_key (ctx, sig->fpr, r_key, 0);
937 : }
938 :
939 :
940 : /* Retrieve the signature status of signature IDX in CTX after a
941 : successful verify operation in R_STAT (if non-null). The creation
942 : time stamp of the signature is returned in R_CREATED (if non-null).
943 : The function returns a string containing the fingerprint. */
944 : const char *
945 0 : gpgme_get_sig_status (gpgme_ctx_t ctx, int idx,
946 : _gpgme_sig_stat_t *r_stat, time_t *r_created)
947 : {
948 : gpgme_verify_result_t result;
949 : gpgme_signature_t sig;
950 :
951 0 : result = gpgme_op_verify_result (ctx);
952 0 : sig = result->signatures;
953 :
954 0 : while (sig && idx)
955 : {
956 0 : sig = sig->next;
957 0 : idx--;
958 : }
959 0 : if (!sig || idx)
960 0 : return NULL;
961 :
962 0 : if (r_stat)
963 : {
964 0 : switch (gpg_err_code (sig->status))
965 : {
966 : case GPG_ERR_NO_ERROR:
967 0 : *r_stat = GPGME_SIG_STAT_GOOD;
968 0 : break;
969 :
970 : case GPG_ERR_BAD_SIGNATURE:
971 0 : *r_stat = GPGME_SIG_STAT_BAD;
972 0 : break;
973 :
974 : case GPG_ERR_NO_PUBKEY:
975 0 : *r_stat = GPGME_SIG_STAT_NOKEY;
976 0 : break;
977 :
978 : case GPG_ERR_NO_DATA:
979 0 : *r_stat = GPGME_SIG_STAT_NOSIG;
980 0 : break;
981 :
982 : case GPG_ERR_SIG_EXPIRED:
983 0 : *r_stat = GPGME_SIG_STAT_GOOD_EXP;
984 0 : break;
985 :
986 : case GPG_ERR_KEY_EXPIRED:
987 0 : *r_stat = GPGME_SIG_STAT_GOOD_EXPKEY;
988 0 : break;
989 :
990 : default:
991 0 : *r_stat = GPGME_SIG_STAT_ERROR;
992 0 : break;
993 : }
994 : }
995 0 : if (r_created)
996 0 : *r_created = sig->timestamp;
997 0 : return sig->fpr;
998 : }
999 :
1000 :
1001 : /* Retrieve certain attributes of a signature. IDX is the index
1002 : number of the signature after a successful verify operation. WHAT
1003 : is an attribute where GPGME_ATTR_EXPIRE is probably the most useful
1004 : one. WHATIDX is to be passed as 0 for most attributes . */
1005 : unsigned long
1006 0 : gpgme_get_sig_ulong_attr (gpgme_ctx_t ctx, int idx,
1007 : _gpgme_attr_t what, int whatidx)
1008 : {
1009 : gpgme_verify_result_t result;
1010 : gpgme_signature_t sig;
1011 :
1012 0 : result = gpgme_op_verify_result (ctx);
1013 0 : sig = result->signatures;
1014 :
1015 0 : while (sig && idx)
1016 : {
1017 0 : sig = sig->next;
1018 0 : idx--;
1019 : }
1020 0 : if (!sig || idx)
1021 0 : return 0;
1022 :
1023 0 : switch (what)
1024 : {
1025 : case GPGME_ATTR_CREATED:
1026 0 : return sig->timestamp;
1027 :
1028 : case GPGME_ATTR_EXPIRE:
1029 0 : return sig->exp_timestamp;
1030 :
1031 : case GPGME_ATTR_VALIDITY:
1032 0 : return (unsigned long) sig->validity;
1033 :
1034 : case GPGME_ATTR_SIG_STATUS:
1035 0 : switch (gpg_err_code (sig->status))
1036 : {
1037 : case GPG_ERR_NO_ERROR:
1038 0 : return GPGME_SIG_STAT_GOOD;
1039 :
1040 : case GPG_ERR_BAD_SIGNATURE:
1041 0 : return GPGME_SIG_STAT_BAD;
1042 :
1043 : case GPG_ERR_NO_PUBKEY:
1044 0 : return GPGME_SIG_STAT_NOKEY;
1045 :
1046 : case GPG_ERR_NO_DATA:
1047 0 : return GPGME_SIG_STAT_NOSIG;
1048 :
1049 : case GPG_ERR_SIG_EXPIRED:
1050 0 : return GPGME_SIG_STAT_GOOD_EXP;
1051 :
1052 : case GPG_ERR_KEY_EXPIRED:
1053 0 : return GPGME_SIG_STAT_GOOD_EXPKEY;
1054 :
1055 : default:
1056 0 : return GPGME_SIG_STAT_ERROR;
1057 : }
1058 :
1059 : case GPGME_ATTR_SIG_SUMMARY:
1060 0 : return sig->summary;
1061 :
1062 : default:
1063 0 : break;
1064 : }
1065 0 : return 0;
1066 : }
1067 :
1068 :
1069 : const char *
1070 0 : gpgme_get_sig_string_attr (gpgme_ctx_t ctx, int idx,
1071 : _gpgme_attr_t what, int whatidx)
1072 : {
1073 : gpgme_verify_result_t result;
1074 : gpgme_signature_t sig;
1075 :
1076 0 : result = gpgme_op_verify_result (ctx);
1077 0 : sig = result->signatures;
1078 :
1079 0 : while (sig && idx)
1080 : {
1081 0 : sig = sig->next;
1082 0 : idx--;
1083 : }
1084 0 : if (!sig || idx)
1085 0 : return NULL;
1086 :
1087 0 : switch (what)
1088 : {
1089 : case GPGME_ATTR_FPR:
1090 0 : return sig->fpr;
1091 :
1092 : case GPGME_ATTR_ERRTOK:
1093 0 : if (whatidx == 1)
1094 0 : return sig->wrong_key_usage ? "Wrong_Key_Usage" : "";
1095 : else
1096 0 : return "";
1097 : default:
1098 0 : break;
1099 : }
1100 :
1101 0 : return NULL;
1102 : }
|