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
204 valid. (The test is identical to if(sum == GPGME_SIGSUM_GREEN)). */
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)
836 TRACE_BEG3 (DEBUG_CTX, "gpgme_op_verify_start", ctx,
837 "sig=%p, signed_text=%p, plaintext=%p",
838 sig, signed_text, plaintext);
839 err = verify_start (ctx, 0, sig, signed_text, plaintext);
840 return TRACE_ERR (err);
844 /* Decrypt ciphertext CIPHER and make a signature verification within
845 CTX and store the resulting plaintext in PLAIN. */
847 gpgme_op_verify (gpgme_ctx_t ctx, gpgme_data_t sig, gpgme_data_t signed_text,
848 gpgme_data_t plaintext)
852 TRACE_BEG3 (DEBUG_CTX, "gpgme_op_verify", ctx,
853 "sig=%p, signed_text=%p, plaintext=%p",
854 sig, signed_text, plaintext);
856 err = verify_start (ctx, 1, sig, signed_text, plaintext);
858 err = _gpgme_wait_one (ctx);
859 return TRACE_ERR (err);
863 /* Compatibility interfaces. */
865 /* Get the key used to create signature IDX in CTX and return it in
868 gpgme_get_sig_key (gpgme_ctx_t ctx, int idx, gpgme_key_t *r_key)
870 gpgme_verify_result_t result;
871 gpgme_signature_t sig;
873 result = gpgme_op_verify_result (ctx);
874 sig = result->signatures;
882 return gpg_error (GPG_ERR_EOF);
884 return gpgme_get_key (ctx, sig->fpr, r_key, 0);
888 /* Retrieve the signature status of signature IDX in CTX after a
889 successful verify operation in R_STAT (if non-null). The creation
890 time stamp of the signature is returned in R_CREATED (if non-null).
891 The function returns a string containing the fingerprint. */
893 gpgme_get_sig_status (gpgme_ctx_t ctx, int idx,
894 _gpgme_sig_stat_t *r_stat, time_t *r_created)
896 gpgme_verify_result_t result;
897 gpgme_signature_t sig;
899 result = gpgme_op_verify_result (ctx);
900 sig = result->signatures;
912 switch (gpg_err_code (sig->status))
914 case GPG_ERR_NO_ERROR:
915 *r_stat = GPGME_SIG_STAT_GOOD;
918 case GPG_ERR_BAD_SIGNATURE:
919 *r_stat = GPGME_SIG_STAT_BAD;
922 case GPG_ERR_NO_PUBKEY:
923 *r_stat = GPGME_SIG_STAT_NOKEY;
926 case GPG_ERR_NO_DATA:
927 *r_stat = GPGME_SIG_STAT_NOSIG;
930 case GPG_ERR_SIG_EXPIRED:
931 *r_stat = GPGME_SIG_STAT_GOOD_EXP;
934 case GPG_ERR_KEY_EXPIRED:
935 *r_stat = GPGME_SIG_STAT_GOOD_EXPKEY;
939 *r_stat = GPGME_SIG_STAT_ERROR;
944 *r_created = sig->timestamp;
949 /* Retrieve certain attributes of a signature. IDX is the index
950 number of the signature after a successful verify operation. WHAT
951 is an attribute where GPGME_ATTR_EXPIRE is probably the most useful
952 one. WHATIDX is to be passed as 0 for most attributes . */
954 gpgme_get_sig_ulong_attr (gpgme_ctx_t ctx, int idx,
955 _gpgme_attr_t what, int whatidx)
957 gpgme_verify_result_t result;
958 gpgme_signature_t sig;
960 result = gpgme_op_verify_result (ctx);
961 sig = result->signatures;
973 case GPGME_ATTR_CREATED:
974 return sig->timestamp;
976 case GPGME_ATTR_EXPIRE:
977 return sig->exp_timestamp;
979 case GPGME_ATTR_VALIDITY:
980 return (unsigned long) sig->validity;
982 case GPGME_ATTR_SIG_STATUS:
983 switch (gpg_err_code (sig->status))
985 case GPG_ERR_NO_ERROR:
986 return GPGME_SIG_STAT_GOOD;
988 case GPG_ERR_BAD_SIGNATURE:
989 return GPGME_SIG_STAT_BAD;
991 case GPG_ERR_NO_PUBKEY:
992 return GPGME_SIG_STAT_NOKEY;
994 case GPG_ERR_NO_DATA:
995 return GPGME_SIG_STAT_NOSIG;
997 case GPG_ERR_SIG_EXPIRED:
998 return GPGME_SIG_STAT_GOOD_EXP;
1000 case GPG_ERR_KEY_EXPIRED:
1001 return GPGME_SIG_STAT_GOOD_EXPKEY;
1004 return GPGME_SIG_STAT_ERROR;
1007 case GPGME_ATTR_SIG_SUMMARY:
1008 return sig->summary;
1018 gpgme_get_sig_string_attr (gpgme_ctx_t ctx, int idx,
1019 _gpgme_attr_t what, int whatidx)
1021 gpgme_verify_result_t result;
1022 gpgme_signature_t sig;
1024 result = gpgme_op_verify_result (ctx);
1025 sig = result->signatures;
1037 case GPGME_ATTR_FPR:
1040 case GPGME_ATTR_ERRTOK:
1042 return sig->wrong_key_usage ? "Wrong_Key_Usage" : "";