1 /* verify.c - Signature verification.
2 Copyright (C) 2000 Werner Koch (dd9jn)
3 Copyright (C) 2001, 2002, 2003, 2004, 2005 g10 Code GmbH
5 This file is part of GPGME.
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.
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.
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
39 struct _gpgme_op_verify_result result;
41 gpgme_signature_t current_sig;
42 int did_prepare_new_sig;
49 release_op_data (void *hook)
51 op_data_t opd = (op_data_t) hook;
52 gpgme_signature_t sig = opd->result.signatures;
56 gpgme_signature_t next = sig->next;
57 gpgme_sig_notation_t notation = sig->notations;
61 gpgme_sig_notation_t next_nota = notation->next;
63 _gpgme_sig_notation_free (notation);
70 free (sig->pka_address);
75 if (opd->result.file_name)
76 free (opd->result.file_name);
81 gpgme_op_verify_result (gpgme_ctx_t ctx)
87 TRACE_BEG (DEBUG_CTX, "gpgme_op_verify_result", ctx);
88 err = _gpgme_op_data_lookup (ctx, OPDATA_VERIFY, &hook, -1, NULL);
92 TRACE_SUC0 ("result=(null)");
96 if (_gpgme_debug_trace ())
98 gpgme_signature_t sig = opd->result.signatures;
103 TRACE_LOG4 ("sig[%i] = fpr %s, summary 0x%x, status %s",
104 i, sig->fpr, sig->summary, gpg_strerror (sig->status));
105 TRACE_LOG6 ("sig[%i] = timestamps 0x%x/0x%x flags:%s%s%s",
106 i, sig->timestamp, sig->exp_timestamp,
107 sig->wrong_key_usage ? "wrong key usage" : "",
108 sig->pka_trust == 1 ? "pka bad"
109 : (sig->pka_trust == 2 ? "pka_okay" : "pka RFU"),
110 sig->chain_model ? "chain model" : "");
111 TRACE_LOG5 ("sig[%i] = validity 0x%x (%s), algos %s/%s",
112 i, sig->validity, gpg_strerror (sig->validity_reason),
113 gpgme_pubkey_algo_name (sig->pubkey_algo),
114 gpgme_hash_algo_name (sig->hash_algo));
115 if (sig->pka_address)
117 TRACE_LOG2 ("sig[%i] = PKA address %s", i, sig->pka_address);
121 TRACE_LOG1 ("sig[%i] = has notations (not shown)", i);
128 TRACE_SUC1 ("result=%p", &opd->result);
133 /* Build a summary vector from RESULT. */
135 calc_sig_summary (gpgme_signature_t sig)
137 unsigned long sum = 0;
139 /* Calculate the red/green flag. */
140 if (sig->validity == GPGME_VALIDITY_FULL
141 || sig->validity == GPGME_VALIDITY_ULTIMATE)
143 if (gpg_err_code (sig->status) == GPG_ERR_NO_ERROR
144 || gpg_err_code (sig->status) == GPG_ERR_SIG_EXPIRED
145 || gpg_err_code (sig->status) == GPG_ERR_KEY_EXPIRED)
146 sum |= GPGME_SIGSUM_GREEN;
148 else if (sig->validity == GPGME_VALIDITY_NEVER)
150 if (gpg_err_code (sig->status) == GPG_ERR_NO_ERROR
151 || gpg_err_code (sig->status) == GPG_ERR_SIG_EXPIRED
152 || gpg_err_code (sig->status) == GPG_ERR_KEY_EXPIRED)
153 sum |= GPGME_SIGSUM_RED;
155 else if (gpg_err_code (sig->status) == GPG_ERR_BAD_SIGNATURE)
156 sum |= GPGME_SIGSUM_RED;
159 /* FIXME: handle the case when key and message are expired. */
160 switch (gpg_err_code (sig->status))
162 case GPG_ERR_SIG_EXPIRED:
163 sum |= GPGME_SIGSUM_SIG_EXPIRED;
166 case GPG_ERR_KEY_EXPIRED:
167 sum |= GPGME_SIGSUM_KEY_EXPIRED;
170 case GPG_ERR_NO_PUBKEY:
171 sum |= GPGME_SIGSUM_KEY_MISSING;
174 case GPG_ERR_BAD_SIGNATURE:
175 case GPG_ERR_NO_ERROR:
179 sum |= GPGME_SIGSUM_SYS_ERROR;
183 /* Now look at the certain reason codes. */
184 switch (gpg_err_code (sig->validity_reason))
186 case GPG_ERR_CRL_TOO_OLD:
187 if (sig->validity == GPGME_VALIDITY_UNKNOWN)
188 sum |= GPGME_SIGSUM_CRL_TOO_OLD;
191 case GPG_ERR_CERT_REVOKED:
192 sum |= GPGME_SIGSUM_KEY_REVOKED;
199 /* Check other flags. */
200 if (sig->wrong_key_usage)
201 sum |= GPGME_SIGSUM_BAD_POLICY;
203 /* Set the valid flag when the signature is unquestionable
205 if ((sum & GPGME_SIGSUM_GREEN) && !(sum & ~GPGME_SIGSUM_GREEN))
206 sum |= GPGME_SIGSUM_VALID;
213 prepare_new_sig (op_data_t opd)
215 gpgme_signature_t sig;
217 if (opd->only_newsig_seen && opd->current_sig)
219 /* We have only seen the NEWSIG status and nothing else - we
220 better skip this signature therefore and reuse it for the
221 next possible signature. */
222 sig = opd->current_sig;
223 memset (sig, 0, sizeof *sig);
224 assert (opd->result.signatures == sig);
228 sig = calloc (1, sizeof (*sig));
230 return gpg_error_from_errno (errno);
231 if (!opd->result.signatures)
232 opd->result.signatures = sig;
233 if (opd->current_sig)
234 opd->current_sig->next = sig;
235 opd->current_sig = sig;
237 opd->did_prepare_new_sig = 1;
238 opd->only_newsig_seen = 0;
243 parse_new_sig (op_data_t opd, gpgme_status_code_t code, char *args)
245 gpgme_signature_t sig;
246 char *end = strchr (args, ' ');
255 if (!opd->did_prepare_new_sig)
259 err = prepare_new_sig (opd);
263 assert (opd->did_prepare_new_sig);
264 opd->did_prepare_new_sig = 0;
266 assert (opd->current_sig);
267 sig = opd->current_sig;
269 /* FIXME: We should set the source of the state. */
272 case GPGME_STATUS_GOODSIG:
273 sig->status = gpg_error (GPG_ERR_NO_ERROR);
276 case GPGME_STATUS_EXPSIG:
277 sig->status = gpg_error (GPG_ERR_SIG_EXPIRED);
280 case GPGME_STATUS_EXPKEYSIG:
281 sig->status = gpg_error (GPG_ERR_KEY_EXPIRED);
284 case GPGME_STATUS_BADSIG:
285 sig->status = gpg_error (GPG_ERR_BAD_SIGNATURE);
288 case GPGME_STATUS_REVKEYSIG:
289 sig->status = gpg_error (GPG_ERR_CERT_REVOKED);
292 case GPGME_STATUS_ERRSIG:
293 /* Parse the pubkey algo. */
295 goto parse_err_sig_fail;
297 sig->pubkey_algo = strtol (end, &tail, 0);
298 if (errno || end == tail || *tail != ' ')
299 goto parse_err_sig_fail;
304 /* Parse the hash algo. */
306 goto parse_err_sig_fail;
308 sig->hash_algo = strtol (end, &tail, 0);
309 if (errno || end == tail || *tail != ' ')
310 goto parse_err_sig_fail;
315 /* Skip the sig class. */
316 end = strchr (end, ' ');
318 goto parse_err_sig_fail;
322 /* Parse the timestamp. */
323 sig->timestamp = _gpgme_parse_timestamp (end, &tail);
324 if (sig->timestamp == -1 || end == tail || (*tail && *tail != ' '))
325 return gpg_error (GPG_ERR_INV_ENGINE);
330 /* Parse the return code. */
331 if (end[0] && (!end[1] || end[1] == ' '))
336 sig->status = gpg_error (GPG_ERR_UNSUPPORTED_ALGORITHM);
340 sig->status = gpg_error (GPG_ERR_NO_PUBKEY);
344 sig->status = gpg_error (GPG_ERR_GENERAL);
348 goto parse_err_sig_fail;
350 goto parse_err_sig_ok;
353 sig->status = gpg_error (GPG_ERR_GENERAL);
358 return gpg_error (GPG_ERR_GENERAL);
363 sig->fpr = strdup (args);
365 return gpg_error_from_errno (errno);
372 parse_valid_sig (gpgme_signature_t sig, char *args)
374 char *end = strchr (args, ' ');
382 /* We require at least the fingerprint. */
383 return gpg_error (GPG_ERR_GENERAL);
387 sig->fpr = strdup (args);
389 return gpg_error_from_errno (errno);
391 /* Skip the creation date. */
392 end = strchr (end, ' ');
397 sig->timestamp = _gpgme_parse_timestamp (end, &tail);
398 if (sig->timestamp == -1 || end == tail || (*tail && *tail != ' '))
399 return gpg_error (GPG_ERR_INV_ENGINE);
402 sig->exp_timestamp = _gpgme_parse_timestamp (end, &tail);
403 if (sig->exp_timestamp == -1 || end == tail || (*tail && *tail != ' '))
404 return gpg_error (GPG_ERR_INV_ENGINE);
409 /* Skip the signature version. */
410 end = strchr (end, ' ');
416 /* Skip the reserved field. */
417 end = strchr (end, ' ');
420 /* Parse the pubkey algo. */
422 sig->pubkey_algo = strtol (end, &tail, 0);
423 if (errno || end == tail || *tail != ' ')
424 return gpg_error (GPG_ERR_INV_ENGINE);
432 /* Parse the hash algo. */
435 sig->hash_algo = strtol (end, &tail, 0);
436 if (errno || end == tail || *tail != ' ')
437 return gpg_error (GPG_ERR_INV_ENGINE);
448 parse_notation (gpgme_signature_t sig, gpgme_status_code_t code, char *args)
451 gpgme_sig_notation_t *lastp = &sig->notations;
452 gpgme_sig_notation_t notation = sig->notations;
453 char *end = strchr (args, ' ');
458 if (code == GPGME_STATUS_NOTATION_NAME || code == GPGME_STATUS_POLICY_URL)
460 /* FIXME: We could keep a pointer to the last notation in the list. */
461 while (notation && notation->value)
463 lastp = ¬ation->next;
464 notation = notation->next;
468 /* There is another notation name without data for the
469 previous one. The crypto backend misbehaves. */
470 return gpg_error (GPG_ERR_INV_ENGINE);
472 err = _gpgme_sig_notation_create (¬ation, NULL, 0, NULL, 0, 0);
476 if (code == GPGME_STATUS_NOTATION_NAME)
478 err = _gpgme_decode_percent_string (args, ¬ation->name, 0, 0);
481 _gpgme_sig_notation_free (notation);
485 notation->name_len = strlen (notation->name);
487 /* FIXME: For now we fake the human-readable flag. The
488 critical flag can not be reported as it is not
490 notation->flags = GPGME_SIG_NOTATION_HUMAN_READABLE;
491 notation->human_readable = 1;
495 /* This is a policy URL. */
497 err = _gpgme_decode_percent_string (args, ¬ation->value, 0, 0);
500 _gpgme_sig_notation_free (notation);
504 notation->value_len = strlen (notation->value);
508 else if (code == GPGME_STATUS_NOTATION_DATA)
510 int len = strlen (args) + 1;
513 /* FIXME: We could keep a pointer to the last notation in the list. */
514 while (notation && notation->next)
516 lastp = ¬ation->next;
517 notation = notation->next;
520 if (!notation || !notation->name)
521 /* There is notation data without a previous notation
522 name. The crypto backend misbehaves. */
523 return gpg_error (GPG_ERR_INV_ENGINE);
525 if (!notation->value)
527 dest = notation->value = malloc (len);
529 return gpg_error_from_errno (errno);
533 int cur_len = strlen (notation->value);
534 dest = realloc (notation->value, len + strlen (notation->value));
536 return gpg_error_from_errno (errno);
537 notation->value = dest;
541 err = _gpgme_decode_percent_string (args, &dest, len, 0);
545 notation->value_len += strlen (dest);
548 return gpg_error (GPG_ERR_INV_ENGINE);
554 parse_trust (gpgme_signature_t sig, gpgme_status_code_t code, char *args)
556 char *end = strchr (args, ' ');
563 case GPGME_STATUS_TRUST_UNDEFINED:
565 sig->validity = GPGME_VALIDITY_UNKNOWN;
568 case GPGME_STATUS_TRUST_NEVER:
569 sig->validity = GPGME_VALIDITY_NEVER;
572 case GPGME_STATUS_TRUST_MARGINAL:
573 sig->validity = GPGME_VALIDITY_MARGINAL;
576 case GPGME_STATUS_TRUST_FULLY:
577 case GPGME_STATUS_TRUST_ULTIMATE:
578 sig->validity = GPGME_VALIDITY_FULL;
582 sig->validity_reason = 0;
583 sig->chain_model = 0;
586 sig->validity_reason = atoi (args);
587 while (*args && *args != ' ')
593 if (!strncmp (args, "chain", 2) && (args[2] == ' ' || !args[2]))
594 sig->chain_model = 1;
602 /* Parse an error status line and if SET_STATUS is true update the
603 result status as appropriate. With SET_STATUS being false, only
604 check for an error. */
606 parse_error (gpgme_signature_t sig, char *args, int set_status)
609 char *where = strchr (args, ' ');
617 where = strchr (which, ' ');
624 return gpg_error (GPG_ERR_INV_ENGINE);
628 if (!strcmp (where, "proc_pkt.plaintext")
629 && gpg_err_code (err) == GPG_ERR_BAD_DATA)
631 /* This indicates a double plaintext. The only solid way to
632 handle this is by failing the oepration. */
633 return gpg_error (GPG_ERR_BAD_DATA);
635 else if (!set_status)
637 else if (!strcmp (where, "verify.findkey"))
639 else if (!strcmp (where, "verify.keyusage")
640 && gpg_err_code (err) == GPG_ERR_WRONG_KEY_USAGE)
641 sig->wrong_key_usage = 1;
648 _gpgme_verify_status_handler (void *priv, gpgme_status_code_t code, char *args)
650 gpgme_ctx_t ctx = (gpgme_ctx_t) priv;
654 gpgme_signature_t sig;
657 err = _gpgme_op_data_lookup (ctx, OPDATA_VERIFY, &hook, -1, NULL);
662 sig = opd->current_sig;
666 case GPGME_STATUS_NEWSIG:
668 calc_sig_summary (sig);
669 err = prepare_new_sig (opd);
670 opd->only_newsig_seen = 1;
673 case GPGME_STATUS_GOODSIG:
674 case GPGME_STATUS_EXPSIG:
675 case GPGME_STATUS_EXPKEYSIG:
676 case GPGME_STATUS_BADSIG:
677 case GPGME_STATUS_ERRSIG:
678 case GPGME_STATUS_REVKEYSIG:
679 if (sig && !opd->did_prepare_new_sig)
680 calc_sig_summary (sig);
681 opd->only_newsig_seen = 0;
682 return parse_new_sig (opd, code, args);
684 case GPGME_STATUS_VALIDSIG:
685 opd->only_newsig_seen = 0;
686 return sig ? parse_valid_sig (sig, args)
687 : gpg_error (GPG_ERR_INV_ENGINE);
689 case GPGME_STATUS_NODATA:
690 opd->only_newsig_seen = 0;
692 return gpg_error (GPG_ERR_NO_DATA);
693 sig->status = gpg_error (GPG_ERR_NO_DATA);
696 case GPGME_STATUS_UNEXPECTED:
697 opd->only_newsig_seen = 0;
699 return gpg_error (GPG_ERR_GENERAL);
700 sig->status = gpg_error (GPG_ERR_NO_DATA);
703 case GPGME_STATUS_NOTATION_NAME:
704 case GPGME_STATUS_NOTATION_DATA:
705 case GPGME_STATUS_POLICY_URL:
706 opd->only_newsig_seen = 0;
707 return sig ? parse_notation (sig, code, args)
708 : gpg_error (GPG_ERR_INV_ENGINE);
710 case GPGME_STATUS_TRUST_UNDEFINED:
711 case GPGME_STATUS_TRUST_NEVER:
712 case GPGME_STATUS_TRUST_MARGINAL:
713 case GPGME_STATUS_TRUST_FULLY:
714 case GPGME_STATUS_TRUST_ULTIMATE:
715 opd->only_newsig_seen = 0;
716 return sig ? parse_trust (sig, code, args)
717 : gpg_error (GPG_ERR_INV_ENGINE);
719 case GPGME_STATUS_PKA_TRUST_BAD:
720 case GPGME_STATUS_PKA_TRUST_GOOD:
721 opd->only_newsig_seen = 0;
722 /* Check that we only get one of these status codes per
723 signature; if not the crypto backend misbehaves. */
724 if (!sig || sig->pka_trust || sig->pka_address)
725 return gpg_error (GPG_ERR_INV_ENGINE);
726 sig->pka_trust = code == GPGME_STATUS_PKA_TRUST_GOOD? 2 : 1;
727 end = strchr (args, ' ');
730 sig->pka_address = strdup (args);
733 case GPGME_STATUS_ERROR:
734 opd->only_newsig_seen = 0;
735 /* Some error stati are informational, so we don't return an
736 error code if we are not ready to process this status. */
737 return parse_error (sig, args, !!sig );
739 case GPGME_STATUS_EOF:
740 if (sig && !opd->did_prepare_new_sig)
741 calc_sig_summary (sig);
742 if (opd->only_newsig_seen && sig)
744 gpgme_signature_t sig2;
745 /* The last signature has no valid information - remove it
748 if (sig == opd->result.signatures)
749 opd->result.signatures = NULL;
752 for (sig2 = opd->result.signatures; sig2; sig2 = sig2->next)
753 if (sig2->next == sig)
759 /* Note that there is no need to release the members of SIG
760 because we won't be here if they have been set. */
762 opd->current_sig = NULL;
764 opd->only_newsig_seen = 0;
767 case GPGME_STATUS_PLAINTEXT:
768 if (++opd->plaintext_seen > 1)
769 return gpg_error (GPG_ERR_BAD_DATA);
770 err = _gpgme_parse_plaintext (args, &opd->result.file_name);
782 verify_status_handler (void *priv, gpgme_status_code_t code, char *args)
786 err = _gpgme_progress_status_handler (priv, code, args);
788 err = _gpgme_verify_status_handler (priv, code, args);
794 _gpgme_op_verify_init_result (gpgme_ctx_t ctx)
799 return _gpgme_op_data_lookup (ctx, OPDATA_VERIFY, &hook,
800 sizeof (*opd), release_op_data);
805 verify_start (gpgme_ctx_t ctx, int synchronous, gpgme_data_t sig,
806 gpgme_data_t signed_text, gpgme_data_t plaintext)
810 err = _gpgme_op_reset (ctx, synchronous);
814 err = _gpgme_op_verify_init_result (ctx);
818 _gpgme_engine_set_status_handler (ctx->engine, verify_status_handler, ctx);
821 return gpg_error (GPG_ERR_NO_DATA);
822 if (!signed_text && !plaintext)
823 return gpg_error (GPG_ERR_INV_VALUE);
825 return _gpgme_engine_op_verify (ctx->engine, sig, signed_text, plaintext);
829 /* Decrypt ciphertext CIPHER and make a signature verification within
830 CTX and store the resulting plaintext in PLAIN. */
832 gpgme_op_verify_start (gpgme_ctx_t ctx, gpgme_data_t sig,
833 gpgme_data_t signed_text, gpgme_data_t plaintext)
835 TRACE_BEG3 (DEBUG_CTX, "gpgme_op_verify_start", ctx,
836 "sig=%p, signed_text=%p, plaintext=%p",
837 sig, signed_text, plaintext);
838 return TRACE_ERR (verify_start (ctx, 0, sig, signed_text, plaintext));
842 /* Decrypt ciphertext CIPHER and make a signature verification within
843 CTX and store the resulting plaintext in PLAIN. */
845 gpgme_op_verify (gpgme_ctx_t ctx, gpgme_data_t sig, gpgme_data_t signed_text,
846 gpgme_data_t plaintext)
850 TRACE_BEG3 (DEBUG_CTX, "gpgme_op_verify", ctx,
851 "sig=%p, signed_text=%p, plaintext=%p",
852 sig, signed_text, plaintext);
854 err = verify_start (ctx, 1, sig, signed_text, plaintext);
856 err = _gpgme_wait_one (ctx);
857 return TRACE_ERR (err);
861 /* Compatibility interfaces. */
863 /* Get the key used to create signature IDX in CTX and return it in
866 gpgme_get_sig_key (gpgme_ctx_t ctx, int idx, gpgme_key_t *r_key)
868 gpgme_verify_result_t result;
869 gpgme_signature_t sig;
871 result = gpgme_op_verify_result (ctx);
872 sig = result->signatures;
880 return gpg_error (GPG_ERR_EOF);
882 return gpgme_get_key (ctx, sig->fpr, r_key, 0);
886 /* Retrieve the signature status of signature IDX in CTX after a
887 successful verify operation in R_STAT (if non-null). The creation
888 time stamp of the signature is returned in R_CREATED (if non-null).
889 The function returns a string containing the fingerprint. */
891 gpgme_get_sig_status (gpgme_ctx_t ctx, int idx,
892 _gpgme_sig_stat_t *r_stat, time_t *r_created)
894 gpgme_verify_result_t result;
895 gpgme_signature_t sig;
897 result = gpgme_op_verify_result (ctx);
898 sig = result->signatures;
910 switch (gpg_err_code (sig->status))
912 case GPG_ERR_NO_ERROR:
913 *r_stat = GPGME_SIG_STAT_GOOD;
916 case GPG_ERR_BAD_SIGNATURE:
917 *r_stat = GPGME_SIG_STAT_BAD;
920 case GPG_ERR_NO_PUBKEY:
921 *r_stat = GPGME_SIG_STAT_NOKEY;
924 case GPG_ERR_NO_DATA:
925 *r_stat = GPGME_SIG_STAT_NOSIG;
928 case GPG_ERR_SIG_EXPIRED:
929 *r_stat = GPGME_SIG_STAT_GOOD_EXP;
932 case GPG_ERR_KEY_EXPIRED:
933 *r_stat = GPGME_SIG_STAT_GOOD_EXPKEY;
937 *r_stat = GPGME_SIG_STAT_ERROR;
942 *r_created = sig->timestamp;
947 /* Retrieve certain attributes of a signature. IDX is the index
948 number of the signature after a successful verify operation. WHAT
949 is an attribute where GPGME_ATTR_EXPIRE is probably the most useful
950 one. WHATIDX is to be passed as 0 for most attributes . */
952 gpgme_get_sig_ulong_attr (gpgme_ctx_t ctx, int idx,
953 _gpgme_attr_t what, int whatidx)
955 gpgme_verify_result_t result;
956 gpgme_signature_t sig;
958 result = gpgme_op_verify_result (ctx);
959 sig = result->signatures;
971 case GPGME_ATTR_CREATED:
972 return sig->timestamp;
974 case GPGME_ATTR_EXPIRE:
975 return sig->exp_timestamp;
977 case GPGME_ATTR_VALIDITY:
978 return (unsigned long) sig->validity;
980 case GPGME_ATTR_SIG_STATUS:
981 switch (gpg_err_code (sig->status))
983 case GPG_ERR_NO_ERROR:
984 return GPGME_SIG_STAT_GOOD;
986 case GPG_ERR_BAD_SIGNATURE:
987 return GPGME_SIG_STAT_BAD;
989 case GPG_ERR_NO_PUBKEY:
990 return GPGME_SIG_STAT_NOKEY;
992 case GPG_ERR_NO_DATA:
993 return GPGME_SIG_STAT_NOSIG;
995 case GPG_ERR_SIG_EXPIRED:
996 return GPGME_SIG_STAT_GOOD_EXP;
998 case GPG_ERR_KEY_EXPIRED:
999 return GPGME_SIG_STAT_GOOD_EXPKEY;
1002 return GPGME_SIG_STAT_ERROR;
1005 case GPGME_ATTR_SIG_SUMMARY:
1006 return sig->summary;
1016 gpgme_get_sig_string_attr (gpgme_ctx_t ctx, int idx,
1017 _gpgme_attr_t what, int whatidx)
1019 gpgme_verify_result_t result;
1020 gpgme_signature_t sig;
1022 result = gpgme_op_verify_result (ctx);
1023 sig = result->signatures;
1035 case GPGME_ATTR_FPR:
1038 case GPGME_ATTR_ERRTOK:
1040 return sig->wrong_key_usage ? "Wrong_Key_Usage" : "";