2 * Copyright notice from original mutt:
3 * crypt-gpgme.c - GPGME based crypto operations
4 * Copyright (C) 1996,1997 Michael R. Elkins <me@cs.hmc.edu>
5 * Copyright (C) 1998,1999,2000 Thomas Roessler <roessler@guug.de>
6 * Copyright (C) 2001 Thomas Roessler <roessler@guug.de>
7 * Oliver Ehli <elmy@acm.org>
8 * Copyright (C) 2002, 2003, 2004 g10 Code GmbH
10 * This file is part of mutt-ng, see http://www.muttng.org/.
11 * It's licensed under the GNU General Public License,
12 * please see the file GPL in the top level source directory.
19 #ifdef CRYPT_BACKEND_GPGME
22 #include "mutt_crypt.h"
23 #include "mutt_menu.h"
24 #include "mutt_curses.h"
33 #include "lib/debug.h"
48 #ifdef HAVE_LANGINFO_D_T_FMT
52 #ifdef HAVE_SYS_TIME_H
53 # include <sys/time.h>
56 #ifdef HAVE_SYS_RESOURCE_H
57 # include <sys/resource.h>
63 #define digitp(p) (*(p) >= '0' && *(p) <= '9')
64 #define hexdigitp(a) (digitp (a) \
65 || (*(a) >= 'A' && *(a) <= 'F') \
66 || (*(a) >= 'a' && *(a) <= 'f'))
67 #define xtoi_1(p) (*(p) <= '9'? (*(p)- '0'): \
68 *(p) <= 'F'? (*(p)-'A'+10):(*(p)-'a'+10))
69 #define xtoi_2(p) ((xtoi_1(p) * 16) + xtoi_1((p)+1))
71 /* Values used for comparing addresses. */
72 #define CRYPT_KV_VALID 1
73 #define CRYPT_KV_ADDR 2
74 #define CRYPT_KV_STRING 4
75 #define CRYPT_KV_STRONGID 8
76 #define CRYPT_KV_MATCH (CRYPT_KV_ADDR|CRYPT_KV_STRING)
85 struct crypt_cache *next;
93 /* We work based on user IDs, getting from a user ID to the key is
94 check and does not need any memory (gpgme uses reference counting). */
95 typedef struct crypt_keyinfo {
96 struct crypt_keyinfo *next;
98 int idx; /* and the user ID at this index */
99 const char *uid; /* and for convenience point to this user ID */
100 unsigned int flags; /* global and per uid flags (for convenience) */
103 typedef struct crypt_entry {
109 static struct crypt_cache *id_defaults = NULL;
110 static gpgme_key_t signature_key = NULL;
113 * General helper functions.
116 /* return true when S points to a didgit or letter. */
117 static int digit_or_letter (const unsigned char *s)
119 return ((*s >= '0' && *s <= '9')
120 || (*s >= 'A' && *s <= 'Z')
121 || (*s >= 'a' && *s <= 'z'));
125 /* Print the utf-8 encoded string BUF of length LEN bytes to stream
126 FP. Convert the character set. */
127 static void print_utf8 (FILE * fp, const char *buf, size_t len)
131 tstr = safe_malloc (len + 1);
132 memcpy (tstr, buf, len);
134 mutt_convert_string (&tstr, "utf-8", Charset, M_ICONV_HOOK_FROM);
144 /* Return the keyID for the key K. Note that this string is valid as
145 long as K is valid */
146 static const char *crypt_keyid (crypt_key_t * k)
148 const char *s = "????????";
150 if (k->kobj && k->kobj->subkeys) {
151 s = k->kobj->subkeys->keyid;
152 if ((!option (OPTPGPLONGIDS)) && (safe_strlen (s) == 16))
153 /* Return only the short keyID. */
160 /* Return the hexstring fingerprint from the key K. */
161 static const char *crypt_fpr (crypt_key_t * k)
165 if (k->kobj && k->kobj->subkeys)
166 s = k->kobj->subkeys->fpr;
171 /* Parse FLAGS and return a statically allocated(!) string with them. */
172 static char *crypt_key_abilities (int flags)
176 if (!(flags & KEYFLAG_CANENCRYPT))
178 else if (flags & KEYFLAG_PREFER_SIGNING)
183 if (!(flags & KEYFLAG_CANSIGN))
185 else if (flags & KEYFLAG_PREFER_ENCRYPTION)
195 /* Parse FLAGS and return a character describing the most important flag. */
196 static char crypt_flags (int flags)
198 if (flags & KEYFLAG_REVOKED)
200 else if (flags & KEYFLAG_EXPIRED)
202 else if (flags & KEYFLAG_DISABLED)
204 else if (flags & KEYFLAG_CRITICAL)
210 /* Return a copy of KEY. */
211 static crypt_key_t *crypt_copy_key (crypt_key_t * key)
215 k = safe_calloc (1, sizeof *k);
217 gpgme_key_ref (key->kobj);
220 k->flags = key->flags;
225 /* Release all the keys at the address of KEYLIST and set the address
227 static void crypt_free_key (crypt_key_t ** keylist)
230 crypt_key_t *k = (*keylist)->next;
237 /* Return trute when key K is valid. */
238 static int crypt_key_is_valid (crypt_key_t * k)
240 if (k->flags & KEYFLAG_CANTUSE)
245 /* Return true whe validity of KEY is sufficient. */
246 static int crypt_id_is_strong (crypt_key_t * key)
248 gpgme_validity_t val = GPGME_VALIDITY_UNKNOWN;
249 gpgme_user_id_t uid = NULL;
250 unsigned int is_strong = 0;
253 if ((key->flags & KEYFLAG_ISX509))
256 for (i = 0, uid = key->kobj->uids; (i < key->idx) && uid;
257 i++, uid = uid->next);
262 case GPGME_VALIDITY_UNKNOWN:
263 case GPGME_VALIDITY_UNDEFINED:
264 case GPGME_VALIDITY_NEVER:
265 case GPGME_VALIDITY_MARGINAL:
269 case GPGME_VALIDITY_FULL:
270 case GPGME_VALIDITY_ULTIMATE:
278 /* Return true when the KEY is valid, i.e. not marked as unusable. */
279 static int crypt_id_is_valid (crypt_key_t * key)
281 return !(key->flags & KEYFLAG_CANTUSE);
284 /* Return a bit vector describing how well the addresses ADDR and
285 U_ADDR match and whether KEY is valid. */
286 static int crypt_id_matches_addr (ADDRESS * addr, ADDRESS * u_addr,
291 if (crypt_id_is_valid (key))
292 rv |= CRYPT_KV_VALID;
294 if (crypt_id_is_strong (key))
295 rv |= CRYPT_KV_STRONGID;
297 if (addr->mailbox && u_addr->mailbox
298 && safe_strcasecmp (addr->mailbox, u_addr->mailbox) == 0)
301 if (addr->personal && u_addr->personal
302 && safe_strcasecmp (addr->personal, u_addr->personal) == 0)
303 rv |= CRYPT_KV_STRING;
310 * GPGME convenient functions.
313 /* Create a new gpgme context and return it. With FOR_SMIME set to
314 true, the protocol of the context is set to CMS. */
315 static gpgme_ctx_t create_gpgme_context (int for_smime)
320 err = gpgme_new (&ctx);
322 mutt_error ("error creating gpgme context: %s\n", gpgme_strerror (err));
328 err = gpgme_set_protocol (ctx, GPGME_PROTOCOL_CMS);
330 mutt_error ("error enabling CMS protocol: %s\n", gpgme_strerror (err));
339 /* Create a new gpgme data object. This is a wrapper to die on
341 static gpgme_data_t create_gpgme_data (void)
346 err = gpgme_data_new (&data);
348 mutt_error ("error creating gpgme data object: %s\n",
349 gpgme_strerror (err));
356 /* Create a new GPGME Data object from the mail body A. With CONVERT
357 passed as true, the lines are converted to CR,LF if required.
358 Return NULL on error or the gpgme_data_t object on success. */
359 static gpgme_data_t body_to_data_object (BODY * a, int convert)
361 char tempfile[_POSIX_PATH_MAX];
366 mutt_mktemp (tempfile);
367 fptmp = safe_fopen (tempfile, "w+");
369 mutt_perror (tempfile);
373 mutt_write_mime_header (a, fptmp);
375 mutt_write_mime_body (a, fptmp);
379 unsigned char buf[1];
381 data = create_gpgme_data ();
383 while ((c = fgetc (fptmp)) != EOF) {
387 if (c == '\n' && !hadcr) {
389 gpgme_data_write (data, buf, 1);
394 /* FIXME: This is quite suboptimal */
396 gpgme_data_write (data, buf, 1);
399 gpgme_data_seek (data, 0, SEEK_SET);
403 err = gpgme_data_new_from_file (&data, tempfile, 1);
407 mutt_error ("error allocating data object: %s\n", gpgme_strerror (err));
414 /* Create a GPGME data object from the stream FP but limit the object
415 to LENGTH bytes starting at OFFSET bytes from the beginning of the
417 static gpgme_data_t file_to_data_object (FILE * fp, long offset, long length)
422 err = gpgme_data_new_from_filepart (&data, NULL, fp, offset, length);
424 mutt_error ("error allocating data object: %s\n", gpgme_strerror (err));
431 /* Write a GPGME data object to the stream FP. */
432 static int data_object_to_stream (gpgme_data_t data, FILE * fp)
438 err = ((gpgme_data_seek (data, 0, SEEK_SET) == -1)
439 ? gpgme_error_from_errno (errno) : 0);
441 mutt_error ("error rewinding data object: %s\n", gpgme_strerror (err));
445 while ((nread = gpgme_data_read (data, buf, sizeof (buf)))) {
446 /* fixme: we are not really converting CRLF to LF but just
447 skipping CR. Doing it correctly needs a more complex logic */
448 for (p = buf; nread; p++, nread--) {
454 mutt_perror ("[tempfile]");
459 mutt_error ("error reading data object: %s\n", strerror (errno));
465 /* Copy a data object to a newly created temporay file and return that
466 filename. Caller must free. With RET_FP not NULL, don't close the
467 stream but return it there. */
468 static char *data_object_to_tempfile (gpgme_data_t data, FILE ** ret_fp)
471 char tempfile[_POSIX_PATH_MAX];
475 mutt_mktemp (tempfile);
476 fp = safe_fopen (tempfile, "w+");
478 mutt_perror (tempfile);
482 err = ((gpgme_data_seek (data, 0, SEEK_SET) == -1)
483 ? gpgme_error_from_errno (errno) : 0);
487 while ((nread = gpgme_data_read (data, buf, sizeof (buf)))) {
488 if (fwrite (buf, nread, 1, fp) != 1) {
489 mutt_perror (tempfile);
501 mutt_error ("error reading data object: %s\n", gpgme_strerror (err));
508 return safe_strdup (tempfile);
512 /* Create a GpgmeRecipientSet from the keys in the string KEYLIST.
513 The keys must be space delimited. */
514 static gpgme_key_t *create_recipient_set (const char *keylist,
515 gpgme_protocol_t protocol)
521 gpgme_key_t *rset = NULL;
522 unsigned int rset_n = 0;
523 gpgme_key_t key = NULL;
524 gpgme_ctx_t context = NULL;
526 err = gpgme_new (&context);
528 err = gpgme_set_protocol (context, protocol);
535 for (i = 0; *s && *s != ' ' && i < sizeof (buf) - 1;)
539 if (i > 1 && buf[i - 1] == '!') {
540 /* The user selected to override the valididy of that
544 err = gpgme_get_key (context, buf, &key, 0);
546 key->uids->validity = GPGME_VALIDITY_FULL;
550 err = gpgme_get_key (context, buf, &key, 0);
553 safe_realloc (&rset, sizeof (*rset) * (rset_n + 1));
554 rset[rset_n++] = key;
557 mutt_error ("error adding recipient `%s': %s\n",
558 buf, gpgme_strerror (err));
566 /* NULL terminate. */
567 safe_realloc (&rset, sizeof (*rset) * (rset_n + 1));
568 rset[rset_n++] = NULL;
571 gpgme_release (context);
577 /* Make sure that the correct signer is set. Returns 0 on success. */
578 static int set_signer (gpgme_ctx_t ctx, int for_smime)
580 char *signid = for_smime ? SmimeDefaultKey : PgpSignAs;
583 gpgme_key_t key, key2;
585 if (!signid || !*signid)
588 listctx = create_gpgme_context (for_smime);
589 err = gpgme_op_keylist_start (listctx, signid, 1);
591 err = gpgme_op_keylist_next (listctx, &key);
593 gpgme_release (listctx);
594 mutt_error (_("secret key `%s' not found: %s\n"),
595 signid, gpgme_strerror (err));
598 err = gpgme_op_keylist_next (listctx, &key2);
600 gpgme_key_release (key);
601 gpgme_key_release (key2);
602 gpgme_release (listctx);
603 mutt_error (_("ambiguous specfication of secret key `%s'\n"), signid);
606 gpgme_op_keylist_end (listctx);
607 gpgme_release (listctx);
609 gpgme_signers_clear (ctx);
610 err = gpgme_signers_add (ctx, key);
611 gpgme_key_release (key);
613 mutt_error (_("error setting secret key `%s': %s\n"),
614 signid, gpgme_strerror (err));
621 /* Encrypt the gpgme data object PLAINTEXT to the recipients in RSET
622 and return an allocated filename to a temporary file containing the
623 enciphered text. With USE_SMIME set to true, the smime backend is
624 used. With COMBINED_SIGNED a PGP message is signed and
625 encrypted. Returns NULL in case of error */
626 static char *encrypt_gpgme_object (gpgme_data_t plaintext, gpgme_key_t * rset,
627 int use_smime, int combined_signed)
631 gpgme_data_t ciphertext;
634 ctx = create_gpgme_context (use_smime);
636 gpgme_set_armor (ctx, 1);
638 ciphertext = create_gpgme_data ();
640 if (combined_signed) {
641 if (set_signer (ctx, use_smime)) {
642 gpgme_data_release (ciphertext);
646 err = gpgme_op_encrypt_sign (ctx, rset, GPGME_ENCRYPT_ALWAYS_TRUST,
647 plaintext, ciphertext);
650 err = gpgme_op_encrypt (ctx, rset, GPGME_ENCRYPT_ALWAYS_TRUST,
651 plaintext, ciphertext);
652 mutt_need_hard_redraw ();
654 mutt_error ("error encrypting data: %s\n", gpgme_strerror (err));
655 gpgme_data_release (ciphertext);
662 outfile = data_object_to_tempfile (ciphertext, NULL);
663 gpgme_data_release (ciphertext);
667 /* Find the "micalg" parameter from the last Gpgme operation on
668 context CTX. It is expected that this operation was a sign
669 operation. Return the algorithm name as a C string in buffer BUF
670 which must have been allocated by the caller with size BUFLEN.
671 Returns 0 on success or -1 in case of an error. The return string
672 is truncted to BUFLEN - 1. */
673 static int get_micalg (gpgme_ctx_t ctx, char *buf, size_t buflen)
675 gpgme_sign_result_t result = NULL;
676 const char *algorithm_name = NULL;
682 result = gpgme_op_sign_result (ctx);
684 algorithm_name = gpgme_hash_algo_name (result->signatures->hash_algo);
685 if (algorithm_name) {
686 strncpy (buf, algorithm_name, buflen - 1);
691 return *buf ? 0 : -1;
694 static void print_time (time_t t, STATE * s)
698 setlocale (LC_TIME, "");
699 #ifdef HAVE_LANGINFO_D_T_FMT
700 strftime (p, sizeof (p), nl_langinfo (D_T_FMT), localtime (&t));
702 strftime (p, sizeof (p), "%c", localtime (&t));
704 setlocale (LC_TIME, "C");
705 state_attach_puts (p, s);
709 * Implementation of `sign_message'.
712 /* Sign the MESSAGE in body A either using OpenPGP or S/MIME when
713 USE_SMIME is passed as true. Returns the new body or NULL on
715 static BODY *sign_message (BODY * a, int use_smime)
722 gpgme_data_t message, signature;
724 convert_to_7bit (a); /* Signed data _must_ be in 7-bit format. */
726 message = body_to_data_object (a, 1);
729 signature = create_gpgme_data ();
731 ctx = create_gpgme_context (use_smime);
733 gpgme_set_armor (ctx, 1);
735 if (set_signer (ctx, use_smime)) {
736 gpgme_data_release (signature);
741 err = gpgme_op_sign (ctx, message, signature, GPGME_SIG_MODE_DETACH);
742 mutt_need_hard_redraw ();
743 gpgme_data_release (message);
745 gpgme_data_release (signature);
747 mutt_error ("error signing data: %s\n", gpgme_strerror (err));
751 sigfile = data_object_to_tempfile (signature, NULL);
752 gpgme_data_release (signature);
758 t = mutt_new_body ();
759 t->type = TYPEMULTIPART;
760 t->subtype = safe_strdup ("signed");
761 t->encoding = ENC7BIT;
763 t->disposition = DISPINLINE;
765 mutt_generate_boundary (&t->parameter);
766 mutt_set_parameter ("protocol",
767 use_smime ? "application/pkcs7-signature"
768 : "application/pgp-signature", &t->parameter);
769 /* Get the micalg from gpgme. Old gpgme versions don't support this
770 for S/MIME so we assume sha-1 in this case. */
771 if (!get_micalg (ctx, buf, sizeof buf))
772 mutt_set_parameter ("micalg", buf, &t->parameter);
774 mutt_set_parameter ("micalg", "sha1", &t->parameter);
780 t->parts->next = mutt_new_body ();
782 t->type = TYPEAPPLICATION;
784 t->subtype = safe_strdup ("pkcs7-signature");
785 mutt_set_parameter ("name", "smime.p7s", &t->parameter);
786 t->encoding = ENCBASE64;
788 t->disposition = DISPATTACH;
789 t->d_filename = safe_strdup ("smime.p7s");
792 t->subtype = safe_strdup ("pgp-signature");
794 t->disposition = DISPINLINE;
795 t->encoding = ENC7BIT;
797 t->filename = sigfile;
798 t->unlink = 1; /* ok to remove this file after sending. */
804 BODY *pgp_gpgme_sign_message (BODY * a)
806 return sign_message (a, 0);
809 BODY *smime_gpgme_sign_message (BODY * a)
811 return sign_message (a, 1);
815 * Implementation of `encrypt_message'.
818 /* Encrypt the mail body A to all keys given as space separated keyids
819 or fingerprints in KEYLIST and return the encrypted body. */
820 BODY *pgp_gpgme_encrypt_message (BODY * a, char *keylist, int sign)
822 char *outfile = NULL;
824 gpgme_key_t *rset = NULL;
825 gpgme_data_t plaintext;
827 rset = create_recipient_set (keylist, GPGME_PROTOCOL_OpenPGP);
833 plaintext = body_to_data_object (a, 0);
839 outfile = encrypt_gpgme_object (plaintext, rset, 0, sign);
840 gpgme_data_release (plaintext);
845 t = mutt_new_body ();
846 t->type = TYPEMULTIPART;
847 t->subtype = safe_strdup ("encrypted");
848 t->encoding = ENC7BIT;
850 t->disposition = DISPINLINE;
852 mutt_generate_boundary (&t->parameter);
853 mutt_set_parameter ("protocol", "application/pgp-encrypted", &t->parameter);
855 t->parts = mutt_new_body ();
856 t->parts->type = TYPEAPPLICATION;
857 t->parts->subtype = safe_strdup ("pgp-encrypted");
858 t->parts->encoding = ENC7BIT;
860 t->parts->next = mutt_new_body ();
861 t->parts->next->type = TYPEAPPLICATION;
862 t->parts->next->subtype = safe_strdup ("octet-stream");
863 t->parts->next->encoding = ENC7BIT;
864 t->parts->next->filename = outfile;
865 t->parts->next->use_disp = 1;
866 t->parts->next->disposition = DISPINLINE;
867 t->parts->next->unlink = 1; /* delete after sending the message */
868 t->parts->next->d_filename = safe_strdup ("msg.asc"); /* non pgp/mime
875 * Implementation of `smime_build_smime_entity'.
878 /* Encrypt the mail body A to all keys given as space separated
879 fingerprints in KEYLIST and return the S/MIME encrypted body. */
880 BODY *smime_gpgme_build_smime_entity (BODY * a, char *keylist)
882 char *outfile = NULL;
884 gpgme_key_t *rset = NULL;
885 gpgme_data_t plaintext;
887 rset = create_recipient_set (keylist, GPGME_PROTOCOL_CMS);
891 plaintext = body_to_data_object (a, 0);
897 outfile = encrypt_gpgme_object (plaintext, rset, 1, 0);
898 gpgme_data_release (plaintext);
903 t = mutt_new_body ();
904 t->type = TYPEAPPLICATION;
905 t->subtype = safe_strdup ("pkcs7-mime");
906 mutt_set_parameter ("name", "smime.p7m", &t->parameter);
907 mutt_set_parameter ("smime-type", "enveloped-data", &t->parameter);
908 t->encoding = ENCBASE64; /* The output of OpenSSL SHOULD be binary */
910 t->disposition = DISPATTACH;
911 t->d_filename = safe_strdup ("smime.p7m");
912 t->filename = outfile;
913 t->unlink = 1; /*delete after sending the message */
922 * Implementation of `verify_one'.
925 /* Display the common attributes of the signature summary SUM.
926 Return 1 if there is is a severe warning.
928 static int show_sig_summary (unsigned long sum,
929 gpgme_ctx_t ctx, gpgme_key_t key, int idx,
934 if ((sum & GPGME_SIGSUM_KEY_REVOKED)) {
935 state_attach_puts (_("Warning: One of the keys has been revoked\n"), s);
939 if ((sum & GPGME_SIGSUM_KEY_EXPIRED)) {
940 time_t at = key->subkeys->expires ? key->subkeys->expires : 0;
943 state_attach_puts (_("Warning: The key used to create the "
944 "signature expired at: "), s);
946 state_attach_puts ("\n", s);
949 state_attach_puts (_("Warning: At least one certification key "
950 "has expired\n"), s);
953 if ((sum & GPGME_SIGSUM_SIG_EXPIRED)) {
954 gpgme_verify_result_t result;
955 gpgme_signature_t sig;
958 result = gpgme_op_verify_result (ctx);
960 for (sig = result->signatures, i = 0; sig && (i < idx);
961 sig = sig->next, i++);
963 state_attach_puts (_("Warning: The signature expired at: "), s);
964 print_time (sig ? sig->exp_timestamp : 0, s);
965 state_attach_puts ("\n", s);
968 if ((sum & GPGME_SIGSUM_KEY_MISSING))
969 state_attach_puts (_("Can't verify due to a missing "
970 "key or certificate\n"), s);
972 if ((sum & GPGME_SIGSUM_CRL_MISSING)) {
973 state_attach_puts (_("The CRL is not available\n"), s);
977 if ((sum & GPGME_SIGSUM_CRL_TOO_OLD)) {
978 state_attach_puts (_("Available CRL is too old\n"), s);
982 if ((sum & GPGME_SIGSUM_BAD_POLICY))
983 state_attach_puts (_("A policy requirement was not met\n"), s);
985 if ((sum & GPGME_SIGSUM_SYS_ERROR)) {
986 const char *t0 = NULL, *t1 = NULL;
987 gpgme_verify_result_t result;
988 gpgme_signature_t sig;
991 state_attach_puts (_("A system error occured"), s);
993 /* Try to figure out some more detailed system error information. */
994 result = gpgme_op_verify_result (ctx);
995 for (sig = result->signatures, i = 0; sig && (i < idx);
996 sig = sig->next, i++);
999 t1 = sig->wrong_key_usage ? "Wrong_Key_Usage" : "";
1003 state_attach_puts (": ", s);
1005 state_attach_puts (t0, s);
1006 if (t1 && !(t0 && !safe_strcmp (t0, t1))) {
1008 state_attach_puts (",", s);
1009 state_attach_puts (t1, s);
1012 state_attach_puts ("\n", s);
1019 static void show_fingerprint (gpgme_key_t key, STATE * state)
1024 const char *prefix = _("Fingerprint: ");
1028 s = key->subkeys ? key->subkeys->fpr : NULL;
1031 is_pgp = (key->protocol == GPGME_PROTOCOL_OpenPGP);
1033 buf = safe_malloc (safe_strlen (prefix) + safe_strlen (s) * 4 + 2);
1034 strcpy (buf, prefix); /* __STRCPY_CHECKED__ */
1035 p = buf + safe_strlen (buf);
1036 if (is_pgp && safe_strlen (s) == 40) { /* PGP v4 style formatted. */
1037 for (i = 0; *s && s[1] && s[2] && s[3] && s[4]; s += 4, i++) {
1048 for (i = 0; *s && s[1] && s[2]; s += 2, i++) {
1051 *p++ = is_pgp ? ' ' : ':';
1052 if (is_pgp && i == 7)
1057 /* just in case print remaining odd digits */
1062 state_attach_puts (buf, state);
1066 /* Show the valididy of a key used for one signature. */
1067 static void show_one_sig_validity (gpgme_ctx_t ctx, int idx, STATE * s)
1069 gpgme_verify_result_t result = NULL;
1070 gpgme_signature_t sig = NULL;
1071 const char *txt = NULL;
1073 result = gpgme_op_verify_result (ctx);
1075 for (sig = result->signatures; sig && (idx > 0); sig = sig->next, idx--);
1077 switch (sig ? sig->validity : 0) {
1078 case GPGME_VALIDITY_UNKNOWN:
1079 txt = _("WARNING: We have NO indication whether "
1080 "the key belongs to the person named " "as shown above\n");
1082 case GPGME_VALIDITY_UNDEFINED:
1084 case GPGME_VALIDITY_NEVER:
1085 txt = _("WARNING: The key does NOT BELONG to "
1086 "the person named as shown above\n");
1088 case GPGME_VALIDITY_MARGINAL:
1089 txt = _("WARNING: It is NOT certain that the key "
1090 "belongs to the person named as shown above\n");
1092 case GPGME_VALIDITY_FULL:
1093 case GPGME_VALIDITY_ULTIMATE:
1098 state_attach_puts (txt, s);
1101 /* Show information about one signature. This fucntion is called with
1102 the context CTX of a sucessful verification operation and the
1103 enumerator IDX which should start at 0 and incremete for each
1106 Return values are: 0 for normal procession, 1 for a bad signature,
1107 2 for a signature with a warning or -1 for no more signature. */
1108 static int show_one_sig_status (gpgme_ctx_t ctx, int idx, STATE * s)
1111 const char *fpr, *uid;
1112 gpgme_key_t key = NULL;
1113 int i, anybad = 0, anywarn = 0;
1115 gpgme_user_id_t uids = NULL;
1116 gpgme_verify_result_t result;
1117 gpgme_signature_t sig;
1118 gpgme_error_t err = GPG_ERR_NO_ERROR;
1120 result = gpgme_op_verify_result (ctx);
1122 /* FIXME: this code should use a static variable and remember
1123 the current position in the list of signatures, IMHO.
1126 for (i = 0, sig = result->signatures; sig && (i < idx);
1127 i++, sig = sig->next);
1129 return -1; /* Signature not found. */
1131 if (signature_key) {
1132 gpgme_key_release (signature_key);
1133 signature_key = NULL;
1136 created = sig->timestamp;
1140 if (gpg_err_code (sig->status) != GPG_ERR_NO_ERROR)
1143 err = gpgme_get_key (ctx, fpr, &key, 0); /* secret key? */
1145 uid = (key->uids && key->uids->uid) ? key->uids->uid : "[?]";
1147 signature_key = key;
1150 key = NULL; /* Old gpgme versions did not set KEY to NULL on
1151 error. Do it here to avoid a double free. */
1155 if (!s || !s->fpout || !(s->flags & M_DISPLAY)); /* No state information so no way to print anything. */
1157 state_attach_puts (_("Error getting key information: "), s);
1158 state_attach_puts (gpg_strerror (err), s);
1159 state_attach_puts ("\n", s);
1162 else if ((sum & GPGME_SIGSUM_GREEN)) {
1163 state_attach_puts (_("Good signature from: "), s);
1164 state_attach_puts (uid, s);
1165 state_attach_puts ("\n", s);
1166 for (i = 1, uids = key->uids; uids; i++, uids = uids->next) {
1168 /* Skip primary UID. */
1172 state_attach_puts (_(" aka: "), s);
1173 state_attach_puts (uids->uid, s);
1174 state_attach_puts ("\n", s);
1176 state_attach_puts (_(" created: "), s);
1177 print_time (created, s);
1178 state_attach_puts ("\n", s);
1179 if (show_sig_summary (sum, ctx, key, idx, s))
1181 show_one_sig_validity (ctx, idx, s);
1183 else if ((sum & GPGME_SIGSUM_RED)) {
1184 state_attach_puts (_("*BAD* signature claimed to be from: "), s);
1185 state_attach_puts (uid, s);
1186 state_attach_puts ("\n", s);
1187 show_sig_summary (sum, ctx, key, idx, s);
1189 else if (!anybad && key && (key->protocol == GPGME_PROTOCOL_OpenPGP)) { /* We can't decide (yellow) but this is a PGP key with a good
1190 signature, so we display what a PGP user expects: The name,
1191 fingerprint and the key validity (which is neither fully or
1193 state_attach_puts (_("Good signature from: "), s);
1194 state_attach_puts (uid, s);
1195 state_attach_puts ("\n", s);
1196 state_attach_puts (_(" created: "), s);
1197 print_time (created, s);
1198 state_attach_puts ("\n", s);
1199 show_one_sig_validity (ctx, idx, s);
1200 show_fingerprint (key, s);
1201 if (show_sig_summary (sum, ctx, key, idx, s))
1204 else { /* can't decide (yellow) */
1206 state_attach_puts (_("Error checking signature"), s);
1207 state_attach_puts ("\n", s);
1208 show_sig_summary (sum, ctx, key, idx, s);
1211 if (key != signature_key)
1212 gpgme_key_release (key);
1215 return anybad ? 1 : anywarn ? 2 : 0;
1218 /* Do the actual verification step. With IS_SMIME set to true we
1219 assume S/MIME (surprise!) */
1220 static int verify_one (BODY * sigbdy, STATE * s,
1221 const char *tempfile, int is_smime)
1227 gpgme_data_t signature, message;
1229 signature = file_to_data_object (s->fpin, sigbdy->offset, sigbdy->length);
1233 /* We need to tell gpgme about the encoding because the backend can't
1234 auto-detect plain base-64 encoding which is used by S/MIME. */
1236 gpgme_data_set_encoding (signature, GPGME_DATA_ENCODING_BASE64);
1238 err = gpgme_data_new_from_file (&message, tempfile, 1);
1240 gpgme_data_release (signature);
1241 mutt_error ("error allocating data object: %s\n", gpgme_strerror (err));
1244 ctx = create_gpgme_context (is_smime);
1246 /* Note: We don't need a current time output because GPGME avoids
1247 such an attack by separating the meta information from the
1249 state_attach_puts (_("[-- Begin signature information --]\n"), s);
1251 err = gpgme_op_verify (ctx, signature, message, NULL);
1252 mutt_need_hard_redraw ();
1256 snprintf (buf, sizeof (buf) - 1,
1257 _("Error: verification failed: %s\n"), gpgme_strerror (err));
1258 state_attach_puts (buf, s);
1260 else { /* Verification succeeded, see what the result is. */
1264 if (signature_key) {
1265 gpgme_key_release (signature_key);
1266 signature_key = NULL;
1269 for (idx = 0; (res = show_one_sig_status (ctx, idx, s)) != -1; idx++) {
1280 gpgme_verify_result_t result;
1281 gpgme_sig_notation_t notation;
1282 gpgme_signature_t signature;
1284 result = gpgme_op_verify_result (ctx);
1286 for (signature = result->signatures; signature;
1287 signature = signature->next) {
1288 if (signature->notations) {
1289 state_attach_puts ("*** Begin Notation (signature by: ", s);
1290 state_attach_puts (signature->fpr, s);
1291 state_attach_puts (") ***\n", s);
1292 for (notation = signature->notations; notation;
1293 notation = notation->next) {
1294 if (notation->name) {
1295 state_attach_puts (notation->name, s);
1296 state_attach_puts ("=", s);
1298 if (notation->value) {
1299 state_attach_puts (notation->value, s);
1300 if (!(*notation->value
1301 && (notation->value[safe_strlen (notation->value) - 1] ==
1303 state_attach_puts ("\n", s);
1306 state_attach_puts ("*** End Notation ***\n", s);
1312 gpgme_release (ctx);
1314 state_attach_puts (_("[-- End signature information --]\n\n"), s);
1315 debug_print (1, ("returning %d.\n", badsig));
1317 return badsig ? 1 : anywarn ? 2 : 0;
1320 int pgp_gpgme_verify_one (BODY * sigbdy, STATE * s, const char *tempfile)
1322 return verify_one (sigbdy, s, tempfile, 0);
1325 int smime_gpgme_verify_one (BODY * sigbdy, STATE * s, const char *tempfile)
1327 return verify_one (sigbdy, s, tempfile, 1);
1331 * Implementation of `decrypt_part'.
1334 /* Decrypt a PGP or SMIME message (depending on the boolean flag
1335 IS_SMIME) with body A described further by state S. Write
1336 plaintext out to file FPOUT and return a new body. For PGP returns
1337 a flag in R_IS_SIGNED to indicate whether this is a combined
1338 encrypted and signed message, for S/MIME it returns true when it is
1339 not a encrypted but a signed message. */
1340 static BODY *decrypt_part (BODY * a, STATE * s, FILE * fpout, int is_smime,
1347 gpgme_data_t ciphertext, plaintext;
1348 int maybe_signed = 0;
1355 ctx = create_gpgme_context (is_smime);
1358 /* Make a data object from the body, create context etc. */
1359 ciphertext = file_to_data_object (s->fpin, a->offset, a->length);
1362 plaintext = create_gpgme_data ();
1364 /* Do the decryption or the verification in case of the S/MIME hack. */
1365 if ((!is_smime) || maybe_signed) {
1367 err = gpgme_op_decrypt_verify (ctx, ciphertext, plaintext);
1368 else if (maybe_signed)
1369 err = gpgme_op_verify (ctx, ciphertext, NULL, plaintext);
1372 /* Check wether signatures have been verified. */
1373 gpgme_verify_result_t verify_result = gpgme_op_verify_result (ctx);
1375 if (verify_result->signatures)
1380 err = gpgme_op_decrypt (ctx, ciphertext, plaintext);
1381 gpgme_data_release (ciphertext);
1383 if (is_smime && !maybe_signed && gpg_err_code (err) == GPG_ERR_NO_DATA) {
1384 /* Check whether this might be a signed message despite what
1385 the mime header told us. Retry then. gpgsm returns the
1386 error information "unsupported Algorithm '?'" but gpgme
1387 will not store this unknown algorithm, thus we test that
1388 it has not been set. */
1389 gpgme_decrypt_result_t result;
1391 result = gpgme_op_decrypt_result (ctx);
1392 if (!result->unsupported_algorithm) {
1394 gpgme_data_release (plaintext);
1398 mutt_need_hard_redraw ();
1399 if ((s->flags & M_DISPLAY)) {
1402 snprintf (buf, sizeof (buf) - 1,
1403 _("[-- Error: decryption failed: %s --]\n\n"),
1404 gpgme_strerror (err));
1405 state_attach_puts (buf, s);
1407 gpgme_data_release (plaintext);
1408 gpgme_release (ctx);
1411 mutt_need_hard_redraw ();
1413 /* Read the output from GPGME, and make sure to change CRLF to LF,
1414 otherwise read_mime_header has a hard time parsing the message. */
1415 if (data_object_to_stream (plaintext, fpout)) {
1416 gpgme_data_release (plaintext);
1417 gpgme_release (ctx);
1420 gpgme_data_release (plaintext);
1422 a->is_signed_data = 0;
1428 a->is_signed_data = 1;
1430 *r_is_signed = -1; /* A signature exists. */
1432 if ((s->flags & M_DISPLAY))
1433 state_attach_puts (_("[-- Begin signature " "information --]\n"), s);
1434 for (idx = 0; (res = show_one_sig_status (ctx, idx, s)) != -1; idx++) {
1440 if (!anybad && idx && r_is_signed && *r_is_signed)
1441 *r_is_signed = anywarn ? 2 : 1; /* Good signature. */
1443 if ((s->flags & M_DISPLAY))
1444 state_attach_puts (_("[-- End signature " "information --]\n\n"), s);
1446 gpgme_release (ctx);
1451 tattach = mutt_read_mime_header (fpout, 0);
1454 * Need to set the length of this body part.
1456 fstat (fileno (fpout), &info);
1457 tattach->length = info.st_size - tattach->offset;
1459 tattach->warnsig = anywarn;
1461 /* See if we need to recurse on this MIME part. */
1462 mutt_parse_part (fpout, tattach);
1468 /* Decrypt a PGP/MIME message in FPIN and B and return a new body and
1469 the stream in CUR and FPOUT. Returns 0 on success. */
1470 int pgp_gpgme_decrypt_mime (FILE * fpin, FILE ** fpout, BODY * b, BODY ** cur)
1472 char tempfile[_POSIX_PATH_MAX];
1474 BODY *first_part = b;
1477 first_part->goodsig = 0;
1478 first_part->warnsig = 0;
1480 if (!mutt_is_multipart_encrypted (b))
1483 if (!b->parts || !b->parts->next)
1488 memset (&s, 0, sizeof (s));
1490 mutt_mktemp (tempfile);
1491 if (!(*fpout = safe_fopen (tempfile, "w+"))) {
1492 mutt_perror (tempfile);
1497 *cur = decrypt_part (b, &s, *fpout, 0, &is_signed);
1500 first_part->goodsig = 1;
1502 return *cur ? 0 : -1;
1506 /* Decrypt a S/MIME message in FPIN and B and return a new body and
1507 the stream in CUR and FPOUT. Returns 0 on success. */
1508 int smime_gpgme_decrypt_mime (FILE * fpin, FILE ** fpout, BODY * b,
1511 char tempfile[_POSIX_PATH_MAX];
1515 long saved_b_offset;
1516 size_t saved_b_length;
1519 if (!mutt_is_application_smime (b))
1525 /* Decode the body - we need to pass binary CMS to the
1526 backend. The backend allows for Base64 encoded data but it does
1527 not allow for QP which I have seen in some messages. So better
1529 saved_b_type = b->type;
1530 saved_b_offset = b->offset;
1531 saved_b_length = b->length;
1532 memset (&s, 0, sizeof (s));
1534 fseek (s.fpin, b->offset, 0);
1535 mutt_mktemp (tempfile);
1536 if (!(tmpfp = safe_fopen (tempfile, "w+"))) {
1537 mutt_perror (tempfile);
1540 mutt_unlink (tempfile);
1543 mutt_decode_attachment (b, &s);
1545 b->length = ftell (s.fpout);
1549 memset (&s, 0, sizeof (s));
1552 mutt_mktemp (tempfile);
1553 if (!(*fpout = safe_fopen (tempfile, "w+"))) {
1554 mutt_perror (tempfile);
1557 mutt_unlink (tempfile);
1559 *cur = decrypt_part (b, &s, *fpout, 1, &is_signed);
1561 (*cur)->goodsig = is_signed > 0;
1562 b->type = saved_b_type;
1563 b->length = saved_b_length;
1564 b->offset = saved_b_offset;
1567 if (*cur && !is_signed && !(*cur)->parts
1568 && mutt_is_application_smime (*cur)) {
1569 /* Assume that this is a opaque signed s/mime message. This is
1570 an ugly way of doing it but we have anyway a problem with
1571 arbitrary encoded S/MIME messages: Only the outer part may be
1572 encrypted. The entire mime parsing should be revamped,
1573 probably by keeping the temportary files so that we don't
1574 need to decrypt them all the time. Inner parts of an
1575 encrypted part can then pint into this file and tehre won't
1576 never be a need to decrypt again. This needs a partial
1577 rewrite of the MIME engine. */
1581 saved_b_type = bb->type;
1582 saved_b_offset = bb->offset;
1583 saved_b_length = bb->length;
1584 memset (&s, 0, sizeof (s));
1586 fseek (s.fpin, bb->offset, 0);
1587 mutt_mktemp (tempfile);
1588 if (!(tmpfp = safe_fopen (tempfile, "w+"))) {
1589 mutt_perror (tempfile);
1592 mutt_unlink (tempfile);
1595 mutt_decode_attachment (bb, &s);
1597 bb->length = ftell (s.fpout);
1602 memset (&s, 0, sizeof (s));
1605 mutt_mktemp (tempfile);
1606 if (!(*fpout = safe_fopen (tempfile, "w+"))) {
1607 mutt_perror (tempfile);
1610 mutt_unlink (tempfile);
1612 tmp_b = decrypt_part (bb, &s, *fpout, 1, &is_signed);
1614 tmp_b->goodsig = is_signed > 0;
1615 bb->type = saved_b_type;
1616 bb->length = saved_b_length;
1617 bb->offset = saved_b_offset;
1620 mutt_free_body (cur);
1623 return *cur ? 0 : -1;
1628 * Implementation of `pgp_check_traditional'.
1631 static int pgp_check_traditional_one_body (FILE * fp, BODY * b,
1634 char tempfile[_POSIX_PATH_MAX];
1635 char buf[HUGE_STRING];
1641 if (b->type != TYPETEXT)
1644 if (tagged_only && !b->tagged)
1647 mutt_mktemp (tempfile);
1648 if (mutt_decode_save_attachment (fp, b, tempfile, 0, 0) != 0) {
1653 if ((tfp = fopen (tempfile, "r")) == NULL) {
1658 while (fgets (buf, sizeof (buf), tfp)) {
1659 if (!safe_strncmp ("-----BEGIN PGP ", buf, 15)) {
1660 if (!safe_strcmp ("MESSAGE-----\n", buf + 15))
1662 else if (!safe_strcmp ("SIGNED MESSAGE-----\n", buf + 15))
1672 /* fix the content type */
1674 mutt_set_parameter ("format", "fixed", &b->parameter);
1675 mutt_set_parameter ("x-action", enc ? "pgp-encrypted" : "pgp-signed",
1681 int pgp_gpgme_check_traditional (FILE * fp, BODY * b, int tagged_only)
1686 for (; b; b = b->next) {
1687 if (is_multipart (b))
1688 rv = (pgp_gpgme_check_traditional (fp, b->parts, tagged_only) || rv);
1689 else if (b->type == TYPETEXT) {
1690 if ((r = mutt_is_application_pgp (b)))
1693 rv = (pgp_check_traditional_one_body (fp, b, tagged_only) || rv);
1701 * Implementation of `application_handler'.
1705 Copy a clearsigned message, and strip the signature and PGP's
1708 XXX - charset handling: We assume that it is safe to do
1709 character set decoding first, dash decoding second here, while
1710 we do it the other way around in the main handler.
1712 (Note that we aren't worse than Outlook & Cie in this, and also
1713 note that we can successfully handle anything produced by any
1714 existing versions of mutt.) */
1716 static void copy_clearsigned (gpgme_data_t data, STATE * s, char *charset)
1718 char buf[HUGE_STRING];
1719 short complete, armor_header;
1724 fname = data_object_to_tempfile (data, &fp);
1730 fc = fgetconv_open (fp, charset, Charset, M_ICONV_HOOK_FROM);
1732 for (complete = 1, armor_header = 1;
1733 fgetconvs (buf, sizeof (buf), fc) != NULL;
1734 complete = strchr (buf, '\n') != NULL) {
1737 state_puts (buf, s);
1741 if (!safe_strcmp (buf, "-----BEGIN PGP SIGNATURE-----\n"))
1751 state_puts (s->prefix, s);
1753 if (buf[0] == '-' && buf[1] == ' ')
1754 state_puts (buf + 2, s);
1756 state_puts (buf, s);
1759 fgetconv_close (&fc);
1764 /* Support for classic_application/pgp */
1765 void pgp_gpgme_application_handler (BODY * m, STATE * s)
1767 int needpass = -1, pgp_keyblock = 0;
1770 long bytes, last_pos, offset;
1771 char buf[HUGE_STRING];
1772 FILE *pgpout = NULL;
1775 gpgme_data_t armored_data = NULL;
1777 short maybe_goodsig = 1;
1778 short have_any_sigs = 0;
1780 char body_charset[STRING]; /* Only used for clearsigned messages. */
1782 debug_print (2, ("Entering pgp_application_pgp handler\n"));
1784 /* For clearsigned messages we won't be able to get a character set
1785 but we know that this may only be text thus we assume Latin-1
1787 if (!mutt_get_body_charset (body_charset, sizeof (body_charset), m))
1788 strfcpy (body_charset, "iso-8859-1", sizeof body_charset);
1790 fseek (s->fpin, m->offset, 0);
1791 last_pos = m->offset;
1793 for (bytes = m->length; bytes > 0;) {
1794 if (fgets (buf, sizeof (buf), s->fpin) == NULL)
1797 offset = ftell (s->fpin);
1798 bytes -= (offset - last_pos); /* don't rely on safe_strlen(buf) */
1801 if (!safe_strncmp ("-----BEGIN PGP ", buf, 15)) {
1803 start_pos = last_pos;
1805 if (!safe_strcmp ("MESSAGE-----\n", buf + 15))
1807 else if (!safe_strcmp ("SIGNED MESSAGE-----\n", buf + 15)) {
1811 else if (!option (OPTDONTHANDLEPGPKEYS) &&
1812 !safe_strcmp ("PUBLIC KEY BLOCK-----\n", buf + 15)) {
1817 /* XXX - we may wish to recode here */
1819 state_puts (s->prefix, s);
1820 state_puts (buf, s);
1824 have_any_sigs = (have_any_sigs || (clearsign && (s->flags & M_VERIFY)));
1826 /* Copy PGP material to an data container */
1827 armored_data = create_gpgme_data ();
1828 gpgme_data_write (armored_data, buf, safe_strlen (buf));
1829 while (bytes > 0 && fgets (buf, sizeof (buf) - 1, s->fpin) != NULL) {
1830 offset = ftell (s->fpin);
1831 bytes -= (offset - last_pos); /* don't rely on safe_strlen(buf) */
1834 gpgme_data_write (armored_data, buf, safe_strlen (buf));
1836 if ((needpass && !safe_strcmp ("-----END PGP MESSAGE-----\n", buf))
1838 && (!safe_strcmp ("-----END PGP SIGNATURE-----\n", buf)
1839 || !safe_strcmp ("-----END PGP PUBLIC KEY BLOCK-----\n",
1844 /* Invoke PGP if needed */
1845 if (!clearsign || (s->flags & M_VERIFY)) {
1846 unsigned int sig_stat = 0;
1847 gpgme_data_t plaintext;
1850 plaintext = create_gpgme_data ();
1851 ctx = create_gpgme_context (0);
1854 err = gpgme_op_verify (ctx, armored_data, NULL, plaintext);
1856 err = gpgme_op_decrypt_verify (ctx, armored_data, plaintext);
1857 if (gpg_err_code (err) == GPG_ERR_NO_DATA) {
1858 /* Decrypt verify can't handle signed only messages. */
1859 err = (gpgme_data_seek (armored_data, 0, SEEK_SET) == -1)
1860 ? gpgme_error_from_errno (errno) : 0;
1861 /* Must release plaintext so that we supply an
1862 uninitialized object. */
1863 gpgme_data_release (plaintext);
1864 plaintext = create_gpgme_data ();
1865 err = gpgme_op_verify (ctx, armored_data, NULL, plaintext);
1872 snprintf (errbuf, sizeof (errbuf) - 1,
1873 _("Error: decryption/verification failed: %s\n"),
1874 gpgme_strerror (err));
1875 state_attach_puts (errbuf, s);
1877 else { /* Decryption/Verification succeeded */
1881 /* Check wether signatures have been verified. */
1882 gpgme_verify_result_t verify_result;
1884 verify_result = gpgme_op_verify_result (ctx);
1885 if (verify_result->signatures)
1891 if ((s->flags & M_DISPLAY) && sig_stat) {
1896 state_attach_puts (_("[-- Begin signature "
1897 "information --]\n"), s);
1900 (res = show_one_sig_status (ctx, idx, s)) != -1; idx++) {
1909 state_attach_puts (_("[-- End signature "
1910 "information --]\n\n"), s);
1913 tmpfname = data_object_to_tempfile (plaintext, &pgpout);
1916 state_attach_puts (_("Error: copy data failed\n"), s);
1923 gpgme_release (ctx);
1927 * Now, copy cleartext to the screen. NOTE - we expect that PGP
1928 * outputs utf-8 cleartext. This may not always be true, but it
1929 * seems to be a reasonable guess.
1932 if (s->flags & M_DISPLAY) {
1934 state_attach_puts (_("[-- BEGIN PGP MESSAGE --]\n\n"), s);
1935 else if (pgp_keyblock)
1936 state_attach_puts (_("[-- BEGIN PGP PUBLIC KEY BLOCK --]\n"), s);
1938 state_attach_puts (_("[-- BEGIN PGP SIGNED MESSAGE --]\n\n"), s);
1942 copy_clearsigned (armored_data, s, body_charset);
1949 fc = fgetconv_open (pgpout, "utf-8", Charset, 0);
1950 while ((c = fgetconv (fc)) != EOF) {
1952 if (c == '\n' && s->prefix)
1953 state_puts (s->prefix, s);
1955 fgetconv_close (&fc);
1958 if (s->flags & M_DISPLAY) {
1959 state_putc ('\n', s);
1961 state_attach_puts (_("[-- END PGP MESSAGE --]\n"), s);
1962 else if (pgp_keyblock)
1963 state_attach_puts (_("[-- END PGP PUBLIC KEY BLOCK --]\n"), s);
1965 state_attach_puts (_("[-- END PGP SIGNED MESSAGE --]\n"), s);
1969 safe_fclose (&pgpout);
1973 /* XXX - we may wish to recode here */
1975 state_puts (s->prefix, s);
1976 state_puts (buf, s);
1980 m->goodsig = (maybe_goodsig && have_any_sigs);
1982 if (needpass == -1) {
1983 state_attach_puts (_("[-- Error: could not find beginning"
1984 " of PGP message! --]\n\n"), s);
1987 debug_print (2, ("Leaving pgp_application_pgp handler\n"));
1991 * Implementation of `encrypted_handler'.
1994 /* MIME handler for pgp/mime encrypted messages. */
1995 void pgp_gpgme_encrypted_handler (BODY * a, STATE * s)
1997 char tempfile[_POSIX_PATH_MAX];
2000 BODY *orig_body = a;
2003 debug_print (2, ("Entering pgp_encrypted handler\n"));
2005 if (!a || a->type != TYPEAPPLICATION || !a->subtype
2006 || ascii_strcasecmp ("pgp-encrypted", a->subtype)
2007 || !a->next || a->next->type != TYPEAPPLICATION || !a->next->subtype
2008 || ascii_strcasecmp ("octet-stream", a->next->subtype)) {
2009 if (s->flags & M_DISPLAY)
2010 state_attach_puts (_("[-- Error: malformed PGP/MIME message! --]\n\n"),
2015 /* Move forward to the application/pgp-encrypted body. */
2018 mutt_mktemp (tempfile);
2019 if (!(fpout = safe_fopen (tempfile, "w+"))) {
2020 if (s->flags & M_DISPLAY)
2021 state_attach_puts (_("[-- Error: could not create temporary file! "
2026 tattach = decrypt_part (a, s, fpout, 0, &is_signed);
2028 tattach->goodsig = is_signed > 0;
2030 if (s->flags & M_DISPLAY)
2031 state_attach_puts (is_signed ?
2033 ("[-- The following data is PGP/MIME signed and encrypted --]\n\n")
2036 ("[-- The following data is PGP/MIME encrypted --]\n\n"),
2040 FILE *savefp = s->fpin;
2043 mutt_body_handler (tattach, s);
2048 * if a multipart/signed is the _only_ sub-part of a
2049 * multipart/encrypted, cache signature verification
2052 if (mutt_is_multipart_signed (tattach) && !tattach->next)
2053 orig_body->goodsig |= tattach->goodsig;
2055 if (s->flags & M_DISPLAY) {
2056 state_puts ("\n", s);
2057 state_attach_puts (is_signed ?
2059 ("[-- End of PGP/MIME signed and encrypted data --]\n")
2060 : _("[-- End of PGP/MIME encrypted data --]\n"), s);
2063 mutt_free_body (&tattach);
2067 mutt_unlink (tempfile);
2068 debug_print (2, ("Leaving pgp_encrypted handler\n"));
2071 /* Support for application/smime */
2072 void smime_gpgme_application_handler (BODY * a, STATE * s)
2074 char tempfile[_POSIX_PATH_MAX];
2080 debug_print (2, ("Entering smime_encrypted handler\n"));
2083 mutt_mktemp (tempfile);
2084 if (!(fpout = safe_fopen (tempfile, "w+"))) {
2085 if (s->flags & M_DISPLAY)
2086 state_attach_puts (_("[-- Error: could not create temporary file! "
2091 tattach = decrypt_part (a, s, fpout, 1, &is_signed);
2093 tattach->goodsig = is_signed > 0;
2095 if (s->flags & M_DISPLAY)
2096 state_attach_puts (is_signed ?
2097 _("[-- The following data is S/MIME signed --]\n\n")
2100 ("[-- The following data is S/MIME encrypted --]\n\n"),
2104 FILE *savefp = s->fpin;
2107 mutt_body_handler (tattach, s);
2112 * if a multipart/signed is the _only_ sub-part of a
2113 * multipart/encrypted, cache signature verification
2116 if (mutt_is_multipart_signed (tattach) && !tattach->next) {
2117 if (!(a->goodsig = tattach->goodsig))
2118 a->warnsig = tattach->warnsig;
2120 else if (tattach->goodsig) {
2122 a->warnsig = tattach->warnsig;
2125 if (s->flags & M_DISPLAY) {
2126 state_puts ("\n", s);
2127 state_attach_puts (is_signed ?
2128 _("[-- End of S/MIME signed data --]\n") :
2129 _("[-- End of S/MIME encrypted data --]\n"), s);
2132 mutt_free_body (&tattach);
2136 mutt_unlink (tempfile);
2137 debug_print (2, ("Leaving smime_encrypted handler\n"));
2142 * Format an entry on the CRYPT key selection menu.
2145 * %k key id %K key id of the principal key
2147 * %a algorithm %A algorithm of the princ. key
2148 * %l length %L length of the princ. key
2149 * %f flags %F flags of the princ. key
2150 * %c capabilities %C capabilities of the princ. key
2151 * %t trust/validity of the key-uid association
2153 * %[...] date of key using strftime(3)
2156 static const char *crypt_entry_fmt (char *dest,
2161 const char *ifstring,
2162 const char *elsestring,
2163 unsigned long data, format_flag flags)
2166 crypt_entry_t *entry;
2169 int optional = (flags & M_FORMAT_OPTIONAL);
2170 const char *s = NULL;
2173 entry = (crypt_entry_t *) data;
2176 /* if (isupper ((unsigned char) op)) */
2179 kflags = (key->flags /*| (pkey->flags & KEYFLAG_RESTRICTIONS)
2182 switch (ascii_tolower (op)) {
2186 char buf2[SHORT_STRING], *p;
2202 while (len > 0 && *cp != ']') {
2211 break; /* not enough space */
2221 if (do_locales && Locale)
2222 setlocale (LC_TIME, Locale);
2227 if (key->kobj->subkeys && (key->kobj->subkeys->timestamp > 0))
2228 tt = key->kobj->subkeys->timestamp;
2230 tm = localtime (&tt);
2232 strftime (buf2, sizeof (buf2), dest, tm);
2235 setlocale (LC_TIME, "C");
2237 snprintf (fmt, sizeof (fmt), "%%%ss", prefix);
2238 snprintf (dest, destlen, fmt, buf2);
2245 snprintf (fmt, sizeof (fmt), "%%%sd", prefix);
2246 snprintf (dest, destlen, fmt, entry->num);
2251 /* fixme: we need a way to distinguish between main and subkeys.
2252 Store the idx in entry? */
2253 snprintf (fmt, sizeof (fmt), "%%%ss", prefix);
2254 snprintf (dest, destlen, fmt, crypt_keyid (key));
2259 snprintf (fmt, sizeof (fmt), "%%%ss", prefix);
2260 snprintf (dest, destlen, fmt, key->uid);
2265 snprintf (fmt, sizeof (fmt), "%%%s.3s", prefix);
2266 if (key->kobj->subkeys)
2267 s = gpgme_pubkey_algo_name (key->kobj->subkeys->pubkey_algo);
2270 snprintf (dest, destlen, fmt, s);
2275 snprintf (fmt, sizeof (fmt), "%%%slu", prefix);
2276 if (key->kobj->subkeys)
2277 val = key->kobj->subkeys->length;
2280 snprintf (dest, destlen, fmt, val);
2285 snprintf (fmt, sizeof (fmt), "%%%sc", prefix);
2286 snprintf (dest, destlen, fmt, crypt_flags (kflags));
2288 else if (!(kflags & (KEYFLAG_RESTRICTIONS)))
2293 snprintf (fmt, sizeof (fmt), "%%%ss", prefix);
2294 snprintf (dest, destlen, fmt, crypt_key_abilities (kflags));
2296 else if (!(kflags & (KEYFLAG_ABILITIES)))
2300 if ((kflags & KEYFLAG_ISX509))
2303 gpgme_user_id_t uid = NULL;
2306 for (i = 0, uid = key->kobj->uids; uid && (i < key->idx);
2307 i++, uid = uid->next);
2309 switch (uid->validity) {
2310 case GPGME_VALIDITY_UNDEFINED:
2313 case GPGME_VALIDITY_NEVER:
2316 case GPGME_VALIDITY_MARGINAL:
2319 case GPGME_VALIDITY_FULL:
2322 case GPGME_VALIDITY_ULTIMATE:
2325 case GPGME_VALIDITY_UNKNOWN:
2331 snprintf (fmt, sizeof (fmt), "%%%sc", prefix);
2332 snprintf (dest, destlen, fmt, s ? *s : 'B');
2335 snprintf (fmt, sizeof (fmt), "%%%ss", prefix);
2336 snprintf (dest, destlen, fmt,
2337 gpgme_get_protocol_name (key->kobj->protocol));
2345 mutt_FormatString (dest, destlen, ifstring, mutt_attach_fmt, data, 0);
2346 else if (flags & M_FORMAT_OPTIONAL)
2347 mutt_FormatString (dest, destlen, elsestring, mutt_attach_fmt, data, 0);
2351 /* Used by the display fucntion to format a line. */
2352 static void crypt_entry (char *s, size_t l, MUTTMENU * menu, int num)
2354 crypt_key_t **key_table = (crypt_key_t **) menu->data;
2355 crypt_entry_t entry;
2357 entry.key = key_table[num];
2358 entry.num = num + 1;
2360 mutt_FormatString (s, l, NONULL (PgpEntryFormat), crypt_entry_fmt,
2361 (unsigned long) &entry, M_FORMAT_ARROWCURSOR);
2364 /* Compare two addresses and the keyid to be used for sorting. */
2365 static int _crypt_compare_address (const void *a, const void *b)
2367 crypt_key_t **s = (crypt_key_t **) a;
2368 crypt_key_t **t = (crypt_key_t **) b;
2371 if ((r = safe_strcasecmp ((*s)->uid, (*t)->uid)))
2374 return safe_strcasecmp (crypt_keyid (*s), crypt_keyid (*t)) > 0;
2377 static int crypt_compare_address (const void *a, const void *b)
2379 return ((PgpSortKeys & SORT_REVERSE) ? !_crypt_compare_address (a, b)
2380 : _crypt_compare_address (a, b));
2384 /* Compare two key IDs and the addresses to be used for sorting. */
2385 static int _crypt_compare_keyid (const void *a, const void *b)
2387 crypt_key_t **s = (crypt_key_t **) a;
2388 crypt_key_t **t = (crypt_key_t **) b;
2391 if ((r = safe_strcasecmp (crypt_keyid (*s), crypt_keyid (*t))))
2394 return safe_strcasecmp ((*s)->uid, (*t)->uid) > 0;
2397 static int crypt_compare_keyid (const void *a, const void *b)
2399 return ((PgpSortKeys & SORT_REVERSE) ? !_crypt_compare_keyid (a, b)
2400 : _crypt_compare_keyid (a, b));
2403 /* Compare 2 creation dates and the addresses. For sorting. */
2404 static int _crypt_compare_date (const void *a, const void *b)
2406 crypt_key_t **s = (crypt_key_t **) a;
2407 crypt_key_t **t = (crypt_key_t **) b;
2408 unsigned long ts = 0, tt = 0;
2410 if ((*s)->kobj->subkeys && ((*s)->kobj->subkeys->timestamp > 0))
2411 ts = (*s)->kobj->subkeys->timestamp;
2412 if ((*t)->kobj->subkeys && ((*t)->kobj->subkeys->timestamp > 0))
2413 tt = (*t)->kobj->subkeys->timestamp;
2420 return safe_strcasecmp ((*s)->uid, (*t)->uid) > 0;
2423 static int crypt_compare_date (const void *a, const void *b)
2425 return ((PgpSortKeys & SORT_REVERSE) ? !_crypt_compare_date (a, b)
2426 : _crypt_compare_date (a, b));
2429 /* Compare two trust values, the key length, the creation dates. the
2430 addresses and the key IDs. For sorting. */
2431 static int _crypt_compare_trust (const void *a, const void *b)
2433 crypt_key_t **s = (crypt_key_t **) a;
2434 crypt_key_t **t = (crypt_key_t **) b;
2435 unsigned long ts = 0, tt = 0;
2438 if ((r = (((*s)->flags & (KEYFLAG_RESTRICTIONS))
2439 - ((*t)->flags & (KEYFLAG_RESTRICTIONS)))))
2442 if ((*s)->kobj->uids)
2443 ts = (*s)->kobj->uids->validity;
2444 if ((*t)->kobj->uids)
2445 tt = (*t)->kobj->uids->validity;
2446 if ((r = (tt - ts)))
2449 if ((*s)->kobj->subkeys)
2450 ts = (*s)->kobj->subkeys->length;
2451 if ((*t)->kobj->subkeys)
2452 tt = (*t)->kobj->subkeys->length;
2456 if ((*s)->kobj->subkeys && ((*s)->kobj->subkeys->timestamp > 0))
2457 ts = (*s)->kobj->subkeys->timestamp;
2458 if ((*t)->kobj->subkeys && ((*t)->kobj->subkeys->timestamp > 0))
2459 tt = (*t)->kobj->subkeys->timestamp;
2465 if ((r = safe_strcasecmp ((*s)->uid, (*t)->uid)))
2467 return (safe_strcasecmp (crypt_keyid ((*s)), crypt_keyid ((*t)))) > 0;
2470 static int crypt_compare_trust (const void *a, const void *b)
2472 return ((PgpSortKeys & SORT_REVERSE) ? !_crypt_compare_trust (a, b)
2473 : _crypt_compare_trust (a, b));
2476 /* Print the X.500 Distinguished Name part KEY from the array of parts
2478 static int print_dn_part (FILE * fp, struct dn_array_s *dn, const char *key)
2482 for (; dn->key; dn++) {
2483 if (!safe_strcmp (dn->key, key)) {
2486 print_utf8 (fp, dn->value, safe_strlen (dn->value));
2493 /* Print all parts of a DN in a standard sequence. */
2494 static void print_dn_parts (FILE * fp, struct dn_array_s *dn)
2496 const char *stdpart[] = {
2497 "CN", "OU", "O", "STREET", "L", "ST", "C", NULL
2499 int any = 0, any2 = 0, i;
2501 for (i = 0; stdpart[i]; i++) {
2504 any = print_dn_part (fp, dn, stdpart[i]);
2506 /* now print the rest without any specific ordering */
2507 for (; dn->key; dn++) {
2508 for (i = 0; stdpart[i]; i++) {
2509 if (!safe_strcmp (dn->key, stdpart[i]))
2517 any = print_dn_part (fp, dn, dn->key);
2526 /* Parse an RDN; this is a helper to parse_dn(). */
2527 static const unsigned char *parse_dn_part (struct dn_array_s *array,
2528 const unsigned char *string)
2530 const unsigned char *s, *s1;
2534 /* parse attributeType */
2535 for (s = string + 1; *s && *s != '='; s++);
2537 return NULL; /* error */
2540 return NULL; /* empty key */
2541 array->key = safe_malloc (n + 1);
2542 p = (unsigned char *) array->key;
2543 memcpy (p, string, n); /* fixme: trim trailing spaces */
2547 if (*string == '#') { /* hexstring */
2549 for (s = string; hexdigitp (s); s++)
2553 return NULL; /* empty or odd number of digits */
2555 p = safe_malloc (n + 1);
2556 array->value = (char *) p;
2557 for (s1 = string; n; s1 += 2, n--)
2561 else { /* regular v3 quoted string */
2562 for (n = 0, s = string; *s; s++) {
2563 if (*s == '\\') { /* pair */
2565 if (*s == ',' || *s == '=' || *s == '+'
2566 || *s == '<' || *s == '>' || *s == '#' || *s == ';'
2567 || *s == '\\' || *s == '\"' || *s == ' ')
2569 else if (hexdigitp (s) && hexdigitp (s + 1)) {
2574 return NULL; /* invalid escape sequence */
2576 else if (*s == '\"')
2577 return NULL; /* invalid encoding */
2578 else if (*s == ',' || *s == '=' || *s == '+'
2579 || *s == '<' || *s == '>' || *s == '#' || *s == ';')
2585 p = safe_malloc (n + 1);
2586 array->value = (char *) p;
2587 for (s = string; n; s++, n--) {
2590 if (hexdigitp (s)) {
2606 /* Parse a DN and return an array-ized one. This is not a validating
2607 parser and it does not support any old-stylish syntax; gpgme is
2608 expected to return only rfc2253 compatible strings. */
2609 static struct dn_array_s *parse_dn (const unsigned char *string)
2611 struct dn_array_s *array;
2612 size_t arrayidx, arraysize;
2615 arraysize = 7; /* C,ST,L,O,OU,CN,email */
2616 array = safe_malloc ((arraysize + 1) * sizeof *array);
2619 while (*string == ' ')
2623 if (arrayidx >= arraysize) { /* mutt lacks a real safe_realoc - so we need to copy */
2624 struct dn_array_s *a2;
2627 a2 = safe_malloc ((arraysize + 1) * sizeof *array);
2628 for (i = 0; i < arrayidx; i++) {
2629 a2[i].key = array[i].key;
2630 a2[i].value = array[i].value;
2635 array[arrayidx].key = NULL;
2636 array[arrayidx].value = NULL;
2637 string = parse_dn_part (array + arrayidx, string);
2641 while (*string == ' ')
2643 if (*string && *string != ',' && *string != ';' && *string != '+')
2644 goto failure; /* invalid delimiter */
2648 array[arrayidx].key = NULL;
2649 array[arrayidx].value = NULL;
2653 for (i = 0; i < arrayidx; i++) {
2654 FREE (&array[i].key);
2655 FREE (&array[i].value);
2662 /* Print a nice representation of the USERID and make sure it is
2663 displayed in a proper way, which does mean to reorder some parts
2664 for S/MIME's DNs. USERID is a string as returned by the gpgme key
2665 functions. It is utf-8 encoded. */
2666 static void parse_and_print_user_id (FILE * fp, const char *userid)
2671 if (*userid == '<') {
2672 s = strchr (userid + 1, '>');
2674 print_utf8 (fp, userid + 1, s - userid - 1);
2676 else if (*userid == '(')
2677 fputs (_("[Can't display this user ID (unknown encoding)]"), fp);
2678 else if (!digit_or_letter ((const unsigned char *) userid))
2679 fputs (_("[Can't display this user ID (invalid encoding)]"), fp);
2681 struct dn_array_s *dn = parse_dn ((const unsigned char *) userid);
2684 fputs (_("[Can't display this user ID (invalid DN)]"), fp);
2686 print_dn_parts (fp, dn);
2687 for (i = 0; dn[i].key; i++) {
2689 FREE (&dn[i].value);
2697 KEY_CAP_CAN_ENCRYPT,
2702 static unsigned int key_check_cap (gpgme_key_t key, key_cap_t cap)
2704 gpgme_subkey_t subkey = NULL;
2705 unsigned int ret = 0;
2708 case KEY_CAP_CAN_ENCRYPT:
2709 if (!(ret = key->can_encrypt))
2710 for (subkey = key->subkeys; subkey; subkey = subkey->next)
2711 if ((ret = subkey->can_encrypt))
2714 case KEY_CAP_CAN_SIGN:
2715 if (!(ret = key->can_sign))
2716 for (subkey = key->subkeys; subkey; subkey = subkey->next)
2717 if ((ret = subkey->can_sign))
2720 case KEY_CAP_CAN_CERTIFY:
2721 if (!(ret = key->can_certify))
2722 for (subkey = key->subkeys; subkey; subkey = subkey->next)
2723 if ((ret = subkey->can_certify))
2732 /* Print verbose information about a key or certificate to FP. */
2733 static void print_key_info (gpgme_key_t key, FILE * fp)
2736 const char *s = NULL, *s2 = NULL;
2739 char shortbuf[SHORT_STRING];
2740 unsigned long aval = 0;
2744 gpgme_user_id_t uid = NULL;
2747 setlocale (LC_TIME, Locale);
2749 is_pgp = key->protocol == GPGME_PROTOCOL_OpenPGP;
2751 for (idx = 0, uid = key->uids; uid; idx++, uid = uid->next) {
2756 fprintf (fp, "%s ......: ", idx ? _(" aka") : _("Name"));
2758 fputs (_("[Invalid]"), fp);
2762 print_utf8 (fp, s, safe_strlen (s));
2764 parse_and_print_user_id (fp, s);
2768 if (key->subkeys && (key->subkeys->timestamp > 0)) {
2769 tt = key->subkeys->timestamp;
2771 tm = localtime (&tt);
2772 #ifdef HAVE_LANGINFO_D_T_FMT
2773 strftime (shortbuf, sizeof shortbuf, nl_langinfo (D_T_FMT), tm);
2775 strftime (shortbuf, sizeof shortbuf, "%c", tm);
2777 fprintf (fp, "Valid From : %s\n", shortbuf);
2780 if (key->subkeys && (key->subkeys->expires > 0)) {
2781 tt = key->subkeys->expires;
2783 tm = localtime (&tt);
2784 #ifdef HAVE_LANGINFO_D_T_FMT
2785 strftime (shortbuf, sizeof shortbuf, nl_langinfo (D_T_FMT), tm);
2787 strftime (shortbuf, sizeof shortbuf, "%c", tm);
2789 fprintf (fp, "Valid To ..: %s\n", shortbuf);
2793 s = gpgme_pubkey_algo_name (key->subkeys->pubkey_algo);
2797 s2 = is_pgp ? "PGP" : "X.509";
2800 aval = key->subkeys->length;
2802 fprintf (fp, "Key Type ..: %s, %lu bit %s\n", s2, aval, s);
2804 fprintf (fp, "Key Usage .: ");
2807 if (key_check_cap (key, KEY_CAP_CAN_ENCRYPT)) {
2808 fprintf (fp, "%s%s", delim, _("encryption"));
2811 if (key_check_cap (key, KEY_CAP_CAN_SIGN)) {
2812 fprintf (fp, "%s%s", delim, _("signing"));
2815 if (key_check_cap (key, KEY_CAP_CAN_CERTIFY)) {
2816 fprintf (fp, "%s%s", delim, _("certification"));
2822 s = key->subkeys->fpr;
2823 fputs (_("Fingerprint: "), fp);
2824 if (is_pgp && safe_strlen (s) == 40) {
2825 for (i = 0; *s && s[1] && s[2] && s[3] && s[4]; s += 4, i++) {
2830 putc (is_pgp ? ' ' : ':', fp);
2831 if (is_pgp && i == 4)
2836 for (i = 0; *s && s[1] && s[2]; s += 2, i++) {
2839 putc (is_pgp ? ' ' : ':', fp);
2840 if (is_pgp && i == 7)
2844 fprintf (fp, "%s\n", s);
2847 if (key->issuer_serial) {
2848 s = key->issuer_serial;
2850 fprintf (fp, "Serial-No .: 0x%s\n", s);
2853 if (key->issuer_name) {
2854 s = key->issuer_name;
2856 fprintf (fp, "Issued By .: ");
2857 parse_and_print_user_id (fp, s);
2862 /* For PGP we list all subkeys. */
2864 gpgme_subkey_t subkey = NULL;
2866 for (idx = 1, subkey = key->subkeys; subkey; idx++, subkey = subkey->next) {
2870 if (safe_strlen (s) == 16)
2871 s += 8; /* display only the short keyID */
2872 fprintf (fp, "Subkey ....: 0x%s", s);
2873 if (subkey->revoked) {
2875 fputs (_("[Revoked]"), fp);
2877 if (subkey->invalid) {
2879 fputs (_("[Invalid]"), fp);
2881 if (subkey->expired) {
2883 fputs (_("[Expired]"), fp);
2885 if (subkey->disabled) {
2887 fputs (_("[Disabled]"), fp);
2891 if (subkey->timestamp > 0) {
2892 tt = subkey->timestamp;
2894 tm = localtime (&tt);
2895 #ifdef HAVE_LANGINFO_D_T_FMT
2896 strftime (shortbuf, sizeof shortbuf, nl_langinfo (D_T_FMT), tm);
2898 strftime (shortbuf, sizeof shortbuf, "%c", tm);
2900 fprintf (fp, "Valid From : %s\n", shortbuf);
2903 if (subkey->expires > 0) {
2904 tt = subkey->expires;
2906 tm = localtime (&tt);
2907 #ifdef HAVE_LANGINFO_D_T_FMT
2908 strftime (shortbuf, sizeof shortbuf, nl_langinfo (D_T_FMT), tm);
2910 strftime (shortbuf, sizeof shortbuf, "%c", tm);
2912 fprintf (fp, "Valid To ..: %s\n", shortbuf);
2916 s = gpgme_pubkey_algo_name (subkey->pubkey_algo);
2921 aval = subkey->length;
2925 fprintf (fp, "Key Type ..: %s, %lu bit %s\n", "PGP", aval, s);
2927 fprintf (fp, "Key Usage .: ");
2930 if (subkey->can_encrypt) {
2931 fprintf (fp, "%s%s", delim, _("encryption"));
2934 if (subkey->can_sign) {
2935 fprintf (fp, "%s%s", delim, _("signing"));
2938 if (subkey->can_certify) {
2939 fprintf (fp, "%s%s", delim, _("certification"));
2947 setlocale (LC_TIME, "C");
2951 /* Show detailed information about the selected key */
2952 static void verify_key (crypt_key_t * key)
2955 char cmd[LONG_STRING], tempfile[_POSIX_PATH_MAX];
2957 gpgme_ctx_t listctx = NULL;
2959 gpgme_key_t k = NULL;
2962 mutt_mktemp (tempfile);
2963 if (!(fp = safe_fopen (tempfile, "w"))) {
2964 mutt_perror (_("Can't create temporary file"));
2968 mutt_message _("Collecting data...");
2970 print_key_info (key->kobj, fp);
2972 err = gpgme_new (&listctx);
2974 fprintf (fp, "Internal error: can't create gpgme context: %s\n",
2975 gpgme_strerror (err));
2978 if ((key->flags & KEYFLAG_ISX509))
2979 gpgme_set_protocol (listctx, GPGME_PROTOCOL_CMS);
2983 while ((s = k->chain_id) && k->subkeys && safe_strcmp (s, k->subkeys->fpr)) {
2985 err = gpgme_op_keylist_start (listctx, s, 0);
2986 gpgme_key_release (k);
2989 err = gpgme_op_keylist_next (listctx, &k);
2991 fprintf (fp, _("Error finding issuer key: %s\n"), gpgme_strerror (err));
2994 gpgme_op_keylist_end (listctx);
2996 print_key_info (k, fp);
2999 fputs (_("Error: certification chain to long - stopping here\n"), fp);
3005 gpgme_key_release (k);
3006 gpgme_release (listctx);
3008 mutt_clear_error ();
3009 snprintf (cmd, sizeof (cmd), _("Key ID: 0x%s"), crypt_keyid (key));
3010 mutt_do_pager (cmd, tempfile, 0, NULL);
3014 * Implementation of `findkeys'.
3018 /* Convert LIST into a pattern string suitable to be passed to GPGME.
3019 We need to convert spaces in an item into a '+' and '%' into
3021 static char *list_to_pattern (LIST * list)
3029 for (l = list; l; l = l->next) {
3030 for (s = l->data; *s; s++) {
3035 n++; /* delimiter or end of string */
3037 n++; /* make sure to allocate at least one byte */
3038 pattern = p = safe_calloc (1, n);
3039 for (l = list; l; l = l->next) {
3044 for (s = l->data; *s; s++) {
3050 else if (*s == '+') {
3066 /* Return a list of keys which are candidates for the selection.
3067 Select by looking at the HINTS list. */
3068 static crypt_key_t *get_candidates (LIST * hints, unsigned int app,
3071 crypt_key_t *db, *k, **kend;
3077 gpgme_user_id_t uid = NULL;
3079 pattern = list_to_pattern (hints);
3083 err = gpgme_new (&ctx);
3085 mutt_error ("gpgme_new failed: %s", gpgme_strerror (err));
3093 if ((app & APPLICATION_PGP)) {
3094 /* Its all a mess. That old GPGME expects different things
3095 depending on the protocol. For gpg we don' t need percent
3096 escaped pappert but simple strings passed in an array to the
3097 keylist_ext_start function. */
3102 for (l = hints, n = 0; l; l = l->next) {
3103 if (l->data && *l->data)
3109 patarr = safe_calloc (n + 1, sizeof *patarr);
3110 for (l = hints, n = 0; l; l = l->next) {
3111 if (l->data && *l->data)
3112 patarr[n++] = safe_strdup (l->data);
3115 err = gpgme_op_keylist_ext_start (ctx, (const char **) patarr, secret, 0);
3116 for (n = 0; patarr[n]; n++)
3120 mutt_error ("gpgme_op_keylist_start failed: %s", gpgme_strerror (err));
3121 gpgme_release (ctx);
3126 while (!(err = gpgme_op_keylist_next (ctx, &key))) {
3127 unsigned int flags = 0;
3129 if (key_check_cap (key, KEY_CAP_CAN_ENCRYPT))
3130 flags |= KEYFLAG_CANENCRYPT;
3131 if (key_check_cap (key, KEY_CAP_CAN_SIGN))
3132 flags |= KEYFLAG_CANSIGN;
3134 #if 0 /* DISABLED code */
3136 /* Bug in gpg. Capabilities are not listed for secret
3137 keys. Try to deduce them from the algorithm. */
3139 switch (key->subkeys[0].pubkey_algo) {
3141 flags |= KEYFLAG_CANENCRYPT;
3142 flags |= KEYFLAG_CANSIGN;
3144 case GPGME_PK_ELG_E:
3145 flags |= KEYFLAG_CANENCRYPT;
3148 flags |= KEYFLAG_CANSIGN;
3152 #endif /* DISABLED code */
3154 for (idx = 0, uid = key->uids; uid; idx++, uid = uid->next) {
3155 k = safe_calloc (1, sizeof *k);
3164 if (gpg_err_code (err) != GPG_ERR_EOF)
3165 mutt_error ("gpgme_op_keylist_next failed: %s", gpgme_strerror (err));
3166 gpgme_op_keylist_end (ctx);
3171 if ((app & APPLICATION_SMIME)) {
3172 /* and now look for x509 certificates */
3173 gpgme_set_protocol (ctx, GPGME_PROTOCOL_CMS);
3174 err = gpgme_op_keylist_start (ctx, pattern, 0);
3176 mutt_error ("gpgme_op_keylist_start failed: %s", gpgme_strerror (err));
3177 gpgme_release (ctx);
3182 while (!(err = gpgme_op_keylist_next (ctx, &key))) {
3183 unsigned int flags = KEYFLAG_ISX509;
3185 if (key_check_cap (key, KEY_CAP_CAN_ENCRYPT))
3186 flags |= KEYFLAG_CANENCRYPT;
3187 if (key_check_cap (key, KEY_CAP_CAN_SIGN))
3188 flags |= KEYFLAG_CANSIGN;
3190 for (idx = 0, uid = key->uids; uid; idx++, uid = uid->next) {
3191 k = safe_calloc (1, sizeof *k);
3200 if (gpg_err_code (err) != GPG_ERR_EOF)
3201 mutt_error ("gpgme_op_keylist_next failed: %s", gpgme_strerror (err));
3202 gpgme_op_keylist_end (ctx);
3205 gpgme_release (ctx);
3210 /* Add the string STR to the list HINTS. This list is later used to
3212 static LIST *crypt_add_string_to_hints (LIST * hints, const char *str)
3217 if ((scratch = safe_strdup (str)) == NULL)
3220 for (t = strtok (scratch, " ,.:\"()<>\n"); t;
3221 t = strtok (NULL, " ,.:\"()<>\n")) {
3222 if (safe_strlen (t) > 3)
3223 hints = mutt_add_list (hints, t);
3230 /* Display a menu to select a key from the array KEYS. FORCED_VALID
3231 will be set to true on return if the user did override the the
3233 static crypt_key_t *crypt_select_key (crypt_key_t * keys,
3234 ADDRESS * p, const char *s,
3235 unsigned int app, int *forced_valid)
3238 crypt_key_t **key_table;
3241 char helpstr[SHORT_STRING], buf[LONG_STRING];
3243 int (*f) (const void *, const void *);
3244 int menu_to_use = 0;
3249 /* build the key table */
3252 for (k = keys; k; k = k->next) {
3253 if (!option (OPTPGPSHOWUNUSABLE) && (k->flags & KEYFLAG_CANTUSE)) {
3260 safe_realloc (&key_table, sizeof (crypt_key_t *) * keymax);
3266 if (!i && unusable) {
3267 mutt_error _("All matching keys are marked expired/revoked.");
3273 switch (PgpSortKeys & SORT_MASK) {
3275 f = crypt_compare_date;
3278 f = crypt_compare_keyid;
3281 f = crypt_compare_address;
3285 f = crypt_compare_trust;
3288 qsort (key_table, i, sizeof (crypt_key_t *), f);
3290 if (app & APPLICATION_PGP)
3291 menu_to_use = MENU_KEY_SELECT_PGP;
3292 else if (app & APPLICATION_SMIME)
3293 menu_to_use = MENU_KEY_SELECT_SMIME;
3296 mutt_make_help (buf, sizeof (buf), _("Exit "), menu_to_use, OP_EXIT);
3297 strcat (helpstr, buf); /* __STRCAT_CHECKED__ */
3298 mutt_make_help (buf, sizeof (buf), _("Select "), menu_to_use,
3299 OP_GENERIC_SELECT_ENTRY);
3300 strcat (helpstr, buf); /* __STRCAT_CHECKED__ */
3301 mutt_make_help (buf, sizeof (buf), _("Check key "),
3302 menu_to_use, OP_VERIFY_KEY);
3303 strcat (helpstr, buf); /* __STRCAT_CHECKED__ */
3304 mutt_make_help (buf, sizeof (buf), _("Help"), menu_to_use, OP_HELP);
3305 strcat (helpstr, buf); /* __STRCAT_CHECKED__ */
3307 menu = mutt_new_menu ();
3309 menu->make_entry = crypt_entry;
3310 menu->menu = menu_to_use;
3311 menu->help = helpstr;
3312 menu->data = key_table;
3317 if ((app & APPLICATION_PGP) && (app & APPLICATION_SMIME))
3318 ts = _("PGP and S/MIME keys matching");
3319 else if ((app & APPLICATION_PGP))
3320 ts = _("PGP keys matching");
3321 else if ((app & APPLICATION_SMIME))
3322 ts = _("S/MIME keys matching");
3324 ts = _("keys matching");
3327 snprintf (buf, sizeof (buf), _("%s <%s>."), ts, p->mailbox);
3329 snprintf (buf, sizeof (buf), _("%s \"%s\"."), ts, s);
3333 mutt_clear_error ();
3337 switch (mutt_menuLoop (menu)) {
3339 verify_key (key_table[menu->current]);
3340 menu->redraw = REDRAW_FULL;
3344 mutt_message ("%s", key_table[menu->current]->uid);
3347 case OP_GENERIC_SELECT_ENTRY:
3348 /* FIXME make error reporting more verbose - this should be
3349 easy because gpgme provides more information */
3350 if (option (OPTPGPCHECKTRUST)) {
3351 if (!crypt_key_is_valid (key_table[menu->current])) {
3352 mutt_error _("This key can't be used: "
3353 "expired/disabled/revoked.");
3358 if (option (OPTPGPCHECKTRUST) &&
3359 (!crypt_id_is_valid (key_table[menu->current])
3360 || !crypt_id_is_strong (key_table[menu->current]))) {
3362 char buff[LONG_STRING];
3364 if (key_table[menu->current]->flags & KEYFLAG_CANTUSE)
3365 s = N_("ID is expired/disabled/revoked.");
3367 gpgme_validity_t val = GPGME_VALIDITY_UNKNOWN;
3368 gpgme_user_id_t uid = NULL;
3373 uid = key_table[menu->current]->kobj->uids;
3374 for (j = 0; (j < key_table[menu->current]->idx) && uid;
3375 j++, uid = uid->next);
3377 val = uid->validity;
3380 case GPGME_VALIDITY_UNKNOWN:
3381 case GPGME_VALIDITY_UNDEFINED:
3382 warn_s = N_("ID has undefined validity.");
3384 case GPGME_VALIDITY_NEVER:
3385 warn_s = N_("ID is not valid.");
3387 case GPGME_VALIDITY_MARGINAL:
3388 warn_s = N_("ID is only marginally valid.");
3390 case GPGME_VALIDITY_FULL:
3391 case GPGME_VALIDITY_ULTIMATE:
3395 snprintf (buff, sizeof (buff),
3396 _("%s Do you really want to use the key?"), _(warn_s));
3398 if (mutt_yesorno (buff, 0) != 1) {
3399 mutt_clear_error ();
3406 k = crypt_copy_key (key_table[menu->current]);
3417 mutt_menuDestroy (&menu);
3420 set_option (OPTNEEDREDRAW);
3425 static crypt_key_t *crypt_getkeybyaddr (ADDRESS * a, short abilities,
3426 unsigned int app, int *forced_valid)
3434 int this_key_has_strong;
3435 int this_key_has_weak;
3436 int this_key_has_invalid;
3439 crypt_key_t *keys, *k;
3440 crypt_key_t *the_valid_key = NULL;
3441 crypt_key_t *matches = NULL;
3442 crypt_key_t **matches_endp = &matches;
3446 if (a && a->mailbox)
3447 hints = crypt_add_string_to_hints (hints, a->mailbox);
3448 if (a && a->personal)
3449 hints = crypt_add_string_to_hints (hints, a->personal);
3451 mutt_message (_("Looking for keys matching \"%s\"..."), a->mailbox);
3452 keys = get_candidates (hints, app, (abilities & KEYFLAG_CANSIGN));
3454 mutt_free_list (&hints);
3459 debug_print (5, ("looking for %s <%s>.\n", a->personal, a->mailbox));
3461 for (k = keys; k; k = k->next) {
3462 debug_print (5, (" looking at key: %s `%.15s'\n", crypt_keyid (k), k->uid));
3464 if (abilities && !(k->flags & abilities)) {
3465 debug_print (5, (" insufficient abilities: Has %x, want %x\n", k->flags, abilities));
3469 this_key_has_weak = 0; /* weak but valid match */
3470 this_key_has_invalid = 0; /* invalid match */
3471 this_key_has_strong = 0; /* strong and valid match */
3472 match = 0; /* any match */
3474 r = rfc822_parse_adrlist (NULL, k->uid);
3475 for (p = r; p; p = p->next) {
3476 int validity = crypt_id_matches_addr (a, p, k);
3478 if (validity & CRYPT_KV_MATCH) /* something matches */
3481 /* is this key a strong candidate? */
3482 if ((validity & CRYPT_KV_VALID)
3483 && (validity & CRYPT_KV_STRONGID)
3484 && (validity & CRYPT_KV_ADDR)) {
3485 if (the_valid_key && the_valid_key != k)
3488 this_key_has_strong = 1;
3490 else if ((validity & CRYPT_KV_MATCH)
3491 && !(validity & CRYPT_KV_VALID))
3492 this_key_has_invalid = 1;
3493 else if ((validity & CRYPT_KV_MATCH)
3494 && (!(validity & CRYPT_KV_STRONGID)
3495 || !(validity & CRYPT_KV_ADDR)))
3496 this_key_has_weak = 1;
3498 rfc822_free_address (&r);
3503 if (!this_key_has_strong && this_key_has_invalid)
3505 if (!this_key_has_strong && this_key_has_weak)
3508 *matches_endp = tmp = crypt_copy_key (k);
3509 matches_endp = &tmp->next;
3510 the_valid_key = tmp;
3514 crypt_free_key (&keys);
3517 if (the_valid_key && !multi && !weak
3518 && !(invalid && option (OPTPGPSHOWUNUSABLE))) {
3520 * There was precisely one strong match on a valid ID, there
3521 * were no valid keys with weak matches, and we aren't
3522 * interested in seeing invalid keys.
3524 * Proceed without asking the user.
3526 k = crypt_copy_key (the_valid_key);
3530 * Else: Ask the user.
3532 k = crypt_select_key (matches, a, NULL, app, forced_valid);
3534 crypt_free_key (&matches);
3543 static crypt_key_t *crypt_getkeybystr (char *p, short abilities,
3544 unsigned int app, int *forced_valid)
3548 crypt_key_t *matches = NULL;
3549 crypt_key_t **matches_endp = &matches;
3553 mutt_message (_("Looking for keys matching \"%s\"..."), p);
3557 hints = crypt_add_string_to_hints (hints, p);
3558 keys = get_candidates (hints, app, (abilities & KEYFLAG_CANSIGN));
3559 mutt_free_list (&hints);
3564 for (k = keys; k; k = k->next) {
3565 if (abilities && !(k->flags & abilities))
3569 debug_print (5, ("matching \"%s\" against " "key %s, \"%s\":\n", p, crypt_keyid (k), k->uid));
3571 if (!*p || !safe_strcasecmp (p, crypt_keyid (k))
3572 || (!safe_strncasecmp (p, "0x", 2)
3573 && !safe_strcasecmp (p + 2, crypt_keyid (k)))
3574 || (option (OPTPGPLONGIDS)
3575 && !safe_strncasecmp (p, "0x", 2)
3576 && !safe_strcasecmp (p + 2, crypt_keyid (k) + 8))
3577 || str_isstr (k->uid, p)) {
3580 debug_print (5, ("match.\n"));
3582 *matches_endp = tmp = crypt_copy_key (k);
3583 matches_endp = &tmp->next;
3587 crypt_free_key (&keys);
3590 k = crypt_select_key (matches, NULL, p, app, forced_valid);
3591 crypt_free_key (&matches);
3598 /* Display TAG as a prompt to ask for a key. If WHATFOR is not null
3599 use it as default and store it under that label as the next
3600 default. ABILITIES describe the required key abilities (sign,
3601 encrypt) and APP the type of the requested key; ether S/MIME or
3602 PGP. Return a copy of the key or NULL if not found. */
3603 static crypt_key_t *crypt_ask_for_key (char *tag,
3606 unsigned int app, int *forced_valid)
3609 char resp[SHORT_STRING];
3610 struct crypt_cache *l = NULL;
3614 forced_valid = &dummy;
3616 mutt_clear_error ();
3622 for (l = id_defaults; l; l = l->next)
3623 if (!safe_strcasecmp (whatfor, l->what)) {
3624 strfcpy (resp, NONULL (l->dflt), sizeof (resp));
3632 if (mutt_get_field (tag, resp, sizeof (resp), M_CLEAR) != 0)
3637 str_replace (&l->dflt, resp);
3639 l = safe_malloc (sizeof (struct crypt_cache));
3640 l->next = id_defaults;
3642 l->what = safe_strdup (whatfor);
3643 l->dflt = safe_strdup (resp);
3647 if ((key = crypt_getkeybystr (resp, abilities, app, forced_valid)))
3655 /* This routine attempts to find the keyids of the recipients of a
3656 message. It returns NULL if any of the keys can not be found. */
3657 static char *find_keys (ADDRESS * to, ADDRESS * cc, ADDRESS * bcc,
3660 char *keyID, *keylist = NULL, *t;
3661 size_t keylist_size = 0;
3662 size_t keylist_used = 0;
3663 ADDRESS *tmp = NULL, *addr = NULL;
3664 ADDRESS **last = &tmp;
3667 crypt_key_t *k_info, *key;
3668 const char *fqdn = mutt_fqdn (1);
3671 *r_application = APPLICATION_PGP | APPLICATION_SMIME;
3674 for (i = 0; i < 3; i++) {
3689 *last = rfc822_cpy_adr (p);
3691 last = &((*last)->next);
3695 rfc822_qualify (tmp, fqdn);
3697 tmp = mutt_remove_duplicates (tmp);
3699 for (p = tmp; p; p = p->next) {
3700 char buf[LONG_STRING];
3701 int forced_valid = 0;
3706 if ((keyID = mutt_crypt_hook (p)) != NULL) {
3709 snprintf (buf, sizeof (buf), _("Use keyID = \"%s\" for %s?"),
3711 if ((r = mutt_yesorno (buf, M_YES)) == M_YES) {
3712 /* check for e-mail address */
3713 if ((t = strchr (keyID, '@')) &&
3714 (addr = rfc822_parse_adrlist (NULL, keyID))) {
3716 rfc822_qualify (addr, fqdn);
3721 k_info = crypt_getkeybystr (keyID, KEYFLAG_CANENCRYPT,
3722 *r_application, &forced_valid);
3724 k_info = crypt_getkeybystr (keyID, KEYFLAG_CANENCRYPT,
3725 app, &forced_valid);
3731 rfc822_free_address (&tmp);
3732 rfc822_free_address (&addr);
3738 && (k_info = crypt_getkeybyaddr (q, KEYFLAG_CANENCRYPT,
3739 app, &forced_valid)) == NULL) {
3740 snprintf (buf, sizeof (buf), _("Enter keyID for %s: "), q->mailbox);
3742 if ((key = crypt_ask_for_key (buf, q->mailbox, KEYFLAG_CANENCRYPT,
3748 &forced_valid)) == NULL) {
3750 rfc822_free_address (&tmp);
3751 rfc822_free_address (&addr);
3759 const char *s = crypt_fpr (key);
3762 if (key->flags & KEYFLAG_ISX509)
3763 *r_application &= ~APPLICATION_PGP;
3764 if (!(key->flags & KEYFLAG_ISX509))
3765 *r_application &= ~APPLICATION_SMIME;
3768 keylist_size += safe_strlen (s) + 4 + 1;
3769 safe_realloc (&keylist, keylist_size);
3770 sprintf (keylist + keylist_used, "%s0x%s%s", /* __SPRINTF_CHECKED__ */
3771 keylist_used ? " " : "", s, forced_valid ? "!" : "");
3773 keylist_used = safe_strlen (keylist);
3775 crypt_free_key (&key);
3776 rfc822_free_address (&addr);
3778 rfc822_free_address (&tmp);
3782 char *pgp_gpgme_findkeys (ADDRESS * to, ADDRESS * cc, ADDRESS * bcc)
3784 return find_keys (to, cc, bcc, APPLICATION_PGP);
3787 char *smime_gpgme_findkeys (ADDRESS * to, ADDRESS * cc, ADDRESS * bcc)
3789 return find_keys (to, cc, bcc, APPLICATION_SMIME);
3793 * Implementation of `init'.
3796 /* Initialization. */
3797 static void init_gpgme (void)
3799 /* Make sure that gpg-agent is running. */
3800 if (!getenv ("GPG_AGENT_INFO")) {
3801 mutt_error ("\nUsing GPGME backend, although no gpg-agent is running");
3802 if (mutt_any_key_to_continue (NULL) == -1)
3807 void pgp_gpgme_init (void)
3812 void smime_gpgme_init (void)
3816 static int gpgme_send_menu (HEADER * msg, int *redraw, int is_smime)
3819 char input_signas[SHORT_STRING];
3822 if (msg->security & APPLICATION_PGP)
3824 else if (msg->security & APPLICATION_SMIME)
3829 mutt_multi_choice (_
3830 ("S/MIME (e)ncrypt, (s)ign, sign (a)s, (b)oth, (t)oggle or (f)orget it?"),
3834 mutt_multi_choice (_
3835 ("PGP (e)ncrypt, (s)ign, sign (a)s, (b)oth, (t)oggle or (f)orget it?"),
3839 case 1: /* (e)ncrypt */
3840 msg->security |= (is_smime ? SMIMEENCRYPT : PGPENCRYPT);
3843 case 2: /* (s)ign */
3844 msg->security |= (is_smime ? SMIMESIGN : PGPSIGN);
3847 case 3: /* sign (a)s */
3848 /* unset_option(OPTCRYPTCHECKTRUST); */
3849 if ((p = crypt_ask_for_key (_("Sign as: "), NULL, KEYFLAG_CANSIGN,
3850 is_smime ? APPLICATION_SMIME :
3851 APPLICATION_PGP, NULL))) {
3852 snprintf (input_signas, sizeof (input_signas), "0x%s", crypt_keyid (p));
3853 str_replace (is_smime ? &SmimeDefaultKey : &PgpSignAs,
3855 crypt_free_key (&p);
3857 msg->security |= (is_smime ? SMIMESIGN : PGPSIGN);
3860 msg->security &= (is_smime ? ~SMIMESIGN : ~PGPSIGN);
3862 *redraw = REDRAW_FULL;
3865 case 4: /* (b)oth */
3867 (is_smime ? (SMIMEENCRYPT | SMIMESIGN) : (PGPENCRYPT | PGPSIGN));
3870 case 5: /* (t)oggle */
3871 is_smime = !is_smime;
3874 case 6: /* (f)orget it */
3880 else if (is_smime) {
3881 msg->security &= ~APPLICATION_PGP;
3882 msg->security |= APPLICATION_SMIME;
3885 msg->security &= ~APPLICATION_SMIME;
3886 msg->security |= APPLICATION_PGP;
3889 return (msg->security);
3892 int pgp_gpgme_send_menu (HEADER * msg, int *redraw)
3894 return gpgme_send_menu (msg, redraw, 0);
3897 int smime_gpgme_send_menu (HEADER * msg, int *redraw)
3899 return gpgme_send_menu (msg, redraw, 1);
3902 static int verify_sender (HEADER * h, gpgme_protocol_t protocol)
3904 ADDRESS *sender = NULL;
3905 unsigned int ret = 1;
3908 h->env->from = mutt_expand_aliases (h->env->from);
3909 sender = h->env->from;
3911 else if (h->env->sender) {
3912 h->env->sender = mutt_expand_aliases (h->env->sender);
3913 sender = h->env->sender;
3917 if (signature_key) {
3918 gpgme_key_t key = signature_key;
3919 gpgme_user_id_t uid = NULL;
3920 int sender_length = 0;
3923 sender_length = safe_strlen (sender->mailbox);
3924 for (uid = key->uids; uid && ret; uid = uid->next) {
3925 uid_length = safe_strlen (uid->email);
3926 if (1 && (uid->email[0] == '<')
3927 && (uid->email[uid_length - 1] == '>')
3928 && (uid_length == sender_length + 2)
3929 && (!strncmp (uid->email + 1, sender->mailbox, sender_length)))
3934 mutt_any_key_to_continue ("Failed to verify sender");
3937 mutt_any_key_to_continue ("Failed to figure out sender");
3939 if (signature_key) {
3940 gpgme_key_release (signature_key);
3941 signature_key = NULL;
3947 int smime_gpgme_verify_sender (HEADER * h)
3949 return verify_sender (h, GPGME_PROTOCOL_CMS);