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 = mem_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)) && (str_len (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 = mem_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 && str_casecmp (addr->mailbox, u_addr->mailbox) == 0)
301 if (addr->personal && u_addr->personal
302 && str_casecmp (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 str_dup (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 mem_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 mem_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 specification 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 = str_dup ("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 = str_dup ("pkcs7-signature");
785 mutt_set_parameter ("name", "smime.p7s", &t->parameter);
786 t->encoding = ENCBASE64;
788 t->disposition = DISPATTACH;
789 t->d_filename = str_dup ("smime.p7s");
792 t->subtype = str_dup ("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 = str_dup ("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 = str_dup ("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 = str_dup ("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 = str_dup ("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 = str_dup ("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 = str_dup ("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 occurred"), 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 && !str_cmp (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 = mem_malloc (str_len (prefix) + str_len (s) * 4 + 2);
1034 strcpy (buf, prefix); /* __STRCPY_CHECKED__ */
1035 p = buf + str_len (buf);
1036 if (is_pgp && str_len (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[str_len (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 (!str_ncmp ("-----BEGIN PGP ", buf, 15)) {
1660 if (!str_cmp ("MESSAGE-----\n", buf + 15))
1662 else if (!str_cmp ("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 (!str_cmp (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 str_len(buf) */
1801 if (!str_ncmp ("-----BEGIN PGP ", buf, 15)) {
1803 start_pos = last_pos;
1805 if (!str_cmp ("MESSAGE-----\n", buf + 15))
1807 else if (!str_cmp ("SIGNED MESSAGE-----\n", buf + 15)) {
1811 else if (!option (OPTDONTHANDLEPGPKEYS) &&
1812 !str_cmp ("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, str_len (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 str_len(buf) */
1834 gpgme_data_write (armored_data, buf, str_len (buf));
1836 if ((needpass && !str_cmp ("-----END PGP MESSAGE-----\n", buf))
1838 && (!str_cmp ("-----END PGP SIGNATURE-----\n", buf)
1839 || !str_cmp ("-----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);
1920 mem_free (&tmpfname);
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 = str_casecmp ((*s)->uid, (*t)->uid)))
2374 return str_casecmp (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 = str_casecmp (crypt_keyid (*s), crypt_keyid (*t))))
2394 return str_casecmp ((*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 str_casecmp ((*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 = str_casecmp ((*s)->uid, (*t)->uid)))
2467 return (str_casecmp (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 (!str_cmp (dn->key, key)) {
2486 print_utf8 (fp, dn->value, str_len (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 (!str_cmp (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 = mem_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 = mem_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 = mem_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 = mem_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 = mem_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 mem_free (&array[i].key);
2655 mem_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++) {
2688 mem_free (&dn[i].key);
2689 mem_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 fputs (idx ? _(" aka ......: ") :_("Name ......: "), fp);
2759 fputs (_("[Invalid]"), fp);
2763 print_utf8 (fp, s, str_len (s));
2765 parse_and_print_user_id (fp, s);
2769 if (key->subkeys && (key->subkeys->timestamp > 0)) {
2770 tt = key->subkeys->timestamp;
2772 tm = localtime (&tt);
2773 #ifdef HAVE_LANGINFO_D_T_FMT
2774 strftime (shortbuf, sizeof shortbuf, nl_langinfo (D_T_FMT), tm);
2776 strftime (shortbuf, sizeof shortbuf, "%c", tm);
2778 fprintf (fp, _("Valid From : %s\n"), shortbuf);
2781 if (key->subkeys && (key->subkeys->expires > 0)) {
2782 tt = key->subkeys->expires;
2784 tm = localtime (&tt);
2785 #ifdef HAVE_LANGINFO_D_T_FMT
2786 strftime (shortbuf, sizeof shortbuf, nl_langinfo (D_T_FMT), tm);
2788 strftime (shortbuf, sizeof shortbuf, "%c", tm);
2790 fprintf (fp, _("Valid To ..: %s\n"), shortbuf);
2794 s = gpgme_pubkey_algo_name (key->subkeys->pubkey_algo);
2798 s2 = is_pgp ? "PGP" : "X.509";
2801 aval = key->subkeys->length;
2803 fprintf (fp, _("Key Type ..: %s, %lu bit %s\n"), s2, aval, s);
2805 fprintf (fp, _("Key Usage .: "));
2808 if (key_check_cap (key, KEY_CAP_CAN_ENCRYPT)) {
2809 fprintf (fp, "%s%s", delim, _("encryption"));
2812 if (key_check_cap (key, KEY_CAP_CAN_SIGN)) {
2813 fprintf (fp, "%s%s", delim, _("signing"));
2816 if (key_check_cap (key, KEY_CAP_CAN_CERTIFY)) {
2817 fprintf (fp, "%s%s", delim, _("certification"));
2823 s = key->subkeys->fpr;
2824 fputs (_("Fingerprint: "), fp);
2825 if (is_pgp && str_len (s) == 40) {
2826 for (i = 0; *s && s[1] && s[2] && s[3] && s[4]; s += 4, i++) {
2831 putc (is_pgp ? ' ' : ':', fp);
2832 if (is_pgp && i == 4)
2837 for (i = 0; *s && s[1] && s[2]; s += 2, i++) {
2840 putc (is_pgp ? ' ' : ':', fp);
2841 if (is_pgp && i == 7)
2845 fprintf (fp, "%s\n", s);
2848 if (key->issuer_serial) {
2849 s = key->issuer_serial;
2851 fprintf (fp, _("Serial-No .: 0x%s\n"), s);
2854 if (key->issuer_name) {
2855 s = key->issuer_name;
2857 fprintf (fp, _("Issued By .: "));
2858 parse_and_print_user_id (fp, s);
2863 /* For PGP we list all subkeys. */
2865 gpgme_subkey_t subkey = NULL;
2867 for (idx = 1, subkey = key->subkeys; subkey; idx++, subkey = subkey->next) {
2871 if (str_len (s) == 16)
2872 s += 8; /* display only the short keyID */
2873 fprintf (fp, _("Subkey ....: 0x%s"), s);
2874 if (subkey->revoked) {
2876 fputs (_("[Revoked]"), fp);
2878 if (subkey->invalid) {
2880 fputs (_("[Invalid]"), fp);
2882 if (subkey->expired) {
2884 fputs (_("[Expired]"), fp);
2886 if (subkey->disabled) {
2888 fputs (_("[Disabled]"), fp);
2892 if (subkey->timestamp > 0) {
2893 tt = subkey->timestamp;
2895 tm = localtime (&tt);
2896 #ifdef HAVE_LANGINFO_D_T_FMT
2897 strftime (shortbuf, sizeof shortbuf, nl_langinfo (D_T_FMT), tm);
2899 strftime (shortbuf, sizeof shortbuf, "%c", tm);
2901 fprintf (fp, _("Valid From : %s\n"), shortbuf);
2904 if (subkey->expires > 0) {
2905 tt = subkey->expires;
2907 tm = localtime (&tt);
2908 #ifdef HAVE_LANGINFO_D_T_FMT
2909 strftime (shortbuf, sizeof shortbuf, nl_langinfo (D_T_FMT), tm);
2911 strftime (shortbuf, sizeof shortbuf, "%c", tm);
2913 fprintf (fp, _("Valid To ..: %s\n"), shortbuf);
2917 s = gpgme_pubkey_algo_name (subkey->pubkey_algo);
2922 aval = subkey->length;
2926 fprintf (fp, _("Key Type ..: %s, %lu bit %s\n"), "PGP", aval, s);
2928 fprintf (fp, _("Key Usage .: "));
2931 if (subkey->can_encrypt) {
2932 fprintf (fp, "%s%s", delim, _("encryption"));
2935 if (subkey->can_sign) {
2936 fprintf (fp, "%s%s", delim, _("signing"));
2939 if (subkey->can_certify) {
2940 fprintf (fp, "%s%s", delim, _("certification"));
2948 setlocale (LC_TIME, "C");
2952 /* Show detailed information about the selected key */
2953 static void verify_key (crypt_key_t * key)
2956 char cmd[LONG_STRING], tempfile[_POSIX_PATH_MAX];
2958 gpgme_ctx_t listctx = NULL;
2960 gpgme_key_t k = NULL;
2963 mutt_mktemp (tempfile);
2964 if (!(fp = safe_fopen (tempfile, "w"))) {
2965 mutt_perror (_("Can't create temporary file"));
2969 mutt_message _("Collecting data...");
2971 print_key_info (key->kobj, fp);
2973 err = gpgme_new (&listctx);
2975 fprintf (fp, "Internal error: can't create gpgme context: %s\n",
2976 gpgme_strerror (err));
2979 if ((key->flags & KEYFLAG_ISX509))
2980 gpgme_set_protocol (listctx, GPGME_PROTOCOL_CMS);
2984 while ((s = k->chain_id) && k->subkeys && str_cmp (s, k->subkeys->fpr)) {
2986 err = gpgme_op_keylist_start (listctx, s, 0);
2987 gpgme_key_release (k);
2990 err = gpgme_op_keylist_next (listctx, &k);
2992 fprintf (fp, _("Error finding issuer key: %s\n"), gpgme_strerror (err));
2995 gpgme_op_keylist_end (listctx);
2997 print_key_info (k, fp);
3000 fputs (_("Error: certification chain to long - stopping here\n"), fp);
3006 gpgme_key_release (k);
3007 gpgme_release (listctx);
3009 mutt_clear_error ();
3010 snprintf (cmd, sizeof (cmd), _("Key ID: 0x%s"), crypt_keyid (key));
3011 mutt_do_pager (cmd, tempfile, 0, NULL);
3015 * Implementation of `findkeys'.
3019 /* Convert LIST into a pattern string suitable to be passed to GPGME.
3020 We need to convert spaces in an item into a '+' and '%' into
3022 static char *list_to_pattern (LIST * list)
3030 for (l = list; l; l = l->next) {
3031 for (s = l->data; *s; s++) {
3036 n++; /* delimiter or end of string */
3038 n++; /* make sure to allocate at least one byte */
3039 pattern = p = mem_calloc (1, n);
3040 for (l = list; l; l = l->next) {
3045 for (s = l->data; *s; s++) {
3051 else if (*s == '+') {
3067 /* Return a list of keys which are candidates for the selection.
3068 Select by looking at the HINTS list. */
3069 static crypt_key_t *get_candidates (LIST * hints, unsigned int app,
3072 crypt_key_t *db, *k, **kend;
3078 gpgme_user_id_t uid = NULL;
3080 pattern = list_to_pattern (hints);
3084 err = gpgme_new (&ctx);
3086 mutt_error (_("gpgme_new failed: %s"), gpgme_strerror (err));
3087 mem_free (&pattern);
3094 if ((app & APPLICATION_PGP)) {
3095 /* Its all a mess. That old GPGME expects different things
3096 depending on the protocol. For gpg we don' t need percent
3097 escaped pappert but simple strings passed in an array to the
3098 keylist_ext_start function. */
3103 for (l = hints, n = 0; l; l = l->next) {
3104 if (l->data && *l->data)
3110 patarr = mem_calloc (n + 1, sizeof *patarr);
3111 for (l = hints, n = 0; l; l = l->next) {
3112 if (l->data && *l->data)
3113 patarr[n++] = str_dup (l->data);
3116 err = gpgme_op_keylist_ext_start (ctx, (const char **) patarr, secret, 0);
3117 for (n = 0; patarr[n]; n++)
3118 mem_free (&patarr[n]);
3121 mutt_error (_("gpgme_op_keylist_start failed: %s"), gpgme_strerror (err));
3122 gpgme_release (ctx);
3123 mem_free (&pattern);
3127 while (!(err = gpgme_op_keylist_next (ctx, &key))) {
3128 unsigned int flags = 0;
3130 if (key_check_cap (key, KEY_CAP_CAN_ENCRYPT))
3131 flags |= KEYFLAG_CANENCRYPT;
3132 if (key_check_cap (key, KEY_CAP_CAN_SIGN))
3133 flags |= KEYFLAG_CANSIGN;
3135 #if 0 /* DISABLED code */
3137 /* Bug in gpg. Capabilities are not listed for secret
3138 keys. Try to deduce them from the algorithm. */
3140 switch (key->subkeys[0].pubkey_algo) {
3142 flags |= KEYFLAG_CANENCRYPT;
3143 flags |= KEYFLAG_CANSIGN;
3145 case GPGME_PK_ELG_E:
3146 flags |= KEYFLAG_CANENCRYPT;
3149 flags |= KEYFLAG_CANSIGN;
3153 #endif /* DISABLED code */
3155 for (idx = 0, uid = key->uids; uid; idx++, uid = uid->next) {
3156 k = mem_calloc (1, sizeof *k);
3165 if (gpg_err_code (err) != GPG_ERR_EOF)
3166 mutt_error (_("gpgme_op_keylist_next failed: %s"), gpgme_strerror (err));
3167 gpgme_op_keylist_end (ctx);
3172 if ((app & APPLICATION_SMIME)) {
3173 /* and now look for x509 certificates */
3174 gpgme_set_protocol (ctx, GPGME_PROTOCOL_CMS);
3175 err = gpgme_op_keylist_start (ctx, pattern, 0);
3177 mutt_error (_("gpgme_op_keylist_start failed: %s"), gpgme_strerror (err));
3178 gpgme_release (ctx);
3179 mem_free (&pattern);
3183 while (!(err = gpgme_op_keylist_next (ctx, &key))) {
3184 unsigned int flags = KEYFLAG_ISX509;
3186 if (key_check_cap (key, KEY_CAP_CAN_ENCRYPT))
3187 flags |= KEYFLAG_CANENCRYPT;
3188 if (key_check_cap (key, KEY_CAP_CAN_SIGN))
3189 flags |= KEYFLAG_CANSIGN;
3191 for (idx = 0, uid = key->uids; uid; idx++, uid = uid->next) {
3192 k = mem_calloc (1, sizeof *k);
3201 if (gpg_err_code (err) != GPG_ERR_EOF)
3202 mutt_error (_("gpgme_op_keylist_next failed: %s"), gpgme_strerror (err));
3203 gpgme_op_keylist_end (ctx);
3206 gpgme_release (ctx);
3207 mem_free (&pattern);
3211 /* Add the string STR to the list HINTS. This list is later used to
3213 static LIST *crypt_add_string_to_hints (LIST * hints, const char *str)
3218 if ((scratch = str_dup (str)) == NULL)
3221 for (t = strtok (scratch, " ,.:\"()<>\n"); t;
3222 t = strtok (NULL, " ,.:\"()<>\n")) {
3223 if (str_len (t) > 3)
3224 hints = mutt_add_list (hints, t);
3227 mem_free (&scratch);
3231 /* Display a menu to select a key from the array KEYS. FORCED_VALID
3232 will be set to true on return if the user did override the the
3234 static crypt_key_t *crypt_select_key (crypt_key_t * keys,
3235 ADDRESS * p, const char *s,
3236 unsigned int app, int *forced_valid)
3239 crypt_key_t **key_table;
3242 char helpstr[SHORT_STRING], buf[LONG_STRING];
3244 int (*f) (const void *, const void *);
3245 int menu_to_use = 0;
3250 /* build the key table */
3253 for (k = keys; k; k = k->next) {
3254 if (!option (OPTPGPSHOWUNUSABLE) && (k->flags & KEYFLAG_CANTUSE)) {
3261 mem_realloc (&key_table, sizeof (crypt_key_t *) * keymax);
3267 if (!i && unusable) {
3268 mutt_error _("All matching keys are marked expired/revoked.");
3274 switch (PgpSortKeys & SORT_MASK) {
3276 f = crypt_compare_date;
3279 f = crypt_compare_keyid;
3282 f = crypt_compare_address;
3286 f = crypt_compare_trust;
3289 qsort (key_table, i, sizeof (crypt_key_t *), f);
3291 if (app & APPLICATION_PGP)
3292 menu_to_use = MENU_KEY_SELECT_PGP;
3293 else if (app & APPLICATION_SMIME)
3294 menu_to_use = MENU_KEY_SELECT_SMIME;
3297 mutt_make_help (buf, sizeof (buf), _("Exit "), menu_to_use, OP_EXIT);
3298 strcat (helpstr, buf); /* __STRCAT_CHECKED__ */
3299 mutt_make_help (buf, sizeof (buf), _("Select "), menu_to_use,
3300 OP_GENERIC_SELECT_ENTRY);
3301 strcat (helpstr, buf); /* __STRCAT_CHECKED__ */
3302 mutt_make_help (buf, sizeof (buf), _("Check key "),
3303 menu_to_use, OP_VERIFY_KEY);
3304 strcat (helpstr, buf); /* __STRCAT_CHECKED__ */
3305 mutt_make_help (buf, sizeof (buf), _("Help"), menu_to_use, OP_HELP);
3306 strcat (helpstr, buf); /* __STRCAT_CHECKED__ */
3308 menu = mutt_new_menu ();
3310 menu->make_entry = crypt_entry;
3311 menu->menu = menu_to_use;
3312 menu->help = helpstr;
3313 menu->data = key_table;
3318 if ((app & APPLICATION_PGP) && (app & APPLICATION_SMIME))
3319 ts = _("PGP and S/MIME keys matching");
3320 else if ((app & APPLICATION_PGP))
3321 ts = _("PGP keys matching");
3322 else if ((app & APPLICATION_SMIME))
3323 ts = _("S/MIME keys matching");
3325 ts = _("keys matching");
3328 snprintf (buf, sizeof (buf), _("%s <%s>."), ts, p->mailbox);
3330 snprintf (buf, sizeof (buf), _("%s \"%s\"."), ts, s);
3334 mutt_clear_error ();
3338 switch (mutt_menuLoop (menu)) {
3340 verify_key (key_table[menu->current]);
3341 menu->redraw = REDRAW_FULL;
3345 mutt_message ("%s", key_table[menu->current]->uid);
3348 case OP_GENERIC_SELECT_ENTRY:
3349 /* FIXME make error reporting more verbose - this should be
3350 easy because gpgme provides more information */
3351 if (option (OPTPGPCHECKTRUST)) {
3352 if (!crypt_key_is_valid (key_table[menu->current])) {
3353 mutt_error _("This key can't be used: "
3354 "expired/disabled/revoked.");
3359 if (option (OPTPGPCHECKTRUST) &&
3360 (!crypt_id_is_valid (key_table[menu->current])
3361 || !crypt_id_is_strong (key_table[menu->current]))) {
3363 char buff[LONG_STRING];
3365 if (key_table[menu->current]->flags & KEYFLAG_CANTUSE)
3366 s = N_("ID is expired/disabled/revoked.");
3368 gpgme_validity_t val = GPGME_VALIDITY_UNKNOWN;
3369 gpgme_user_id_t uid = NULL;
3374 uid = key_table[menu->current]->kobj->uids;
3375 for (j = 0; (j < key_table[menu->current]->idx) && uid;
3376 j++, uid = uid->next);
3378 val = uid->validity;
3381 case GPGME_VALIDITY_UNKNOWN:
3382 case GPGME_VALIDITY_UNDEFINED:
3383 warn_s = N_("ID has undefined validity.");
3385 case GPGME_VALIDITY_NEVER:
3386 warn_s = N_("ID is not valid.");
3388 case GPGME_VALIDITY_MARGINAL:
3389 warn_s = N_("ID is only marginally valid.");
3391 case GPGME_VALIDITY_FULL:
3392 case GPGME_VALIDITY_ULTIMATE:
3396 snprintf (buff, sizeof (buff),
3397 _("%s Do you really want to use the key?"), _(warn_s));
3399 if (mutt_yesorno (buff, 0) != 1) {
3400 mutt_clear_error ();
3407 k = crypt_copy_key (key_table[menu->current]);
3418 mutt_menuDestroy (&menu);
3419 mem_free (&key_table);
3421 set_option (OPTNEEDREDRAW);
3426 static crypt_key_t *crypt_getkeybyaddr (ADDRESS * a, short abilities,
3427 unsigned int app, int *forced_valid)
3435 int this_key_has_strong;
3436 int this_key_has_weak;
3437 int this_key_has_invalid;
3440 crypt_key_t *keys, *k;
3441 crypt_key_t *the_valid_key = NULL;
3442 crypt_key_t *matches = NULL;
3443 crypt_key_t **matches_endp = &matches;
3447 if (a && a->mailbox)
3448 hints = crypt_add_string_to_hints (hints, a->mailbox);
3449 if (a && a->personal)
3450 hints = crypt_add_string_to_hints (hints, a->personal);
3452 mutt_message (_("Looking for keys matching \"%s\"..."), a->mailbox);
3453 keys = get_candidates (hints, app, (abilities & KEYFLAG_CANSIGN));
3455 mutt_free_list (&hints);
3460 debug_print (5, ("looking for %s <%s>.\n", a->personal, a->mailbox));
3462 for (k = keys; k; k = k->next) {
3463 debug_print (5, (" looking at key: %s `%.15s'\n", crypt_keyid (k), k->uid));
3465 if (abilities && !(k->flags & abilities)) {
3466 debug_print (5, (" insufficient abilities: Has %x, want %x\n", k->flags, abilities));
3470 this_key_has_weak = 0; /* weak but valid match */
3471 this_key_has_invalid = 0; /* invalid match */
3472 this_key_has_strong = 0; /* strong and valid match */
3473 match = 0; /* any match */
3475 r = rfc822_parse_adrlist (NULL, k->uid);
3476 for (p = r; p; p = p->next) {
3477 int validity = crypt_id_matches_addr (a, p, k);
3479 if (validity & CRYPT_KV_MATCH) /* something matches */
3482 /* is this key a strong candidate? */
3483 if ((validity & CRYPT_KV_VALID)
3484 && (validity & CRYPT_KV_STRONGID)
3485 && (validity & CRYPT_KV_ADDR)) {
3486 if (the_valid_key && the_valid_key != k)
3489 this_key_has_strong = 1;
3491 else if ((validity & CRYPT_KV_MATCH)
3492 && !(validity & CRYPT_KV_VALID))
3493 this_key_has_invalid = 1;
3494 else if ((validity & CRYPT_KV_MATCH)
3495 && (!(validity & CRYPT_KV_STRONGID)
3496 || !(validity & CRYPT_KV_ADDR)))
3497 this_key_has_weak = 1;
3499 rfc822_free_address (&r);
3504 if (!this_key_has_strong && this_key_has_invalid)
3506 if (!this_key_has_strong && this_key_has_weak)
3509 *matches_endp = tmp = crypt_copy_key (k);
3510 matches_endp = &tmp->next;
3511 the_valid_key = tmp;
3515 crypt_free_key (&keys);
3518 if (the_valid_key && !multi && !weak
3519 && !(invalid && option (OPTPGPSHOWUNUSABLE))) {
3521 * There was precisely one strong match on a valid ID, there
3522 * were no valid keys with weak matches, and we aren't
3523 * interested in seeing invalid keys.
3525 * Proceed without asking the user.
3527 k = crypt_copy_key (the_valid_key);
3531 * Else: Ask the user.
3533 k = crypt_select_key (matches, a, NULL, app, forced_valid);
3535 crypt_free_key (&matches);
3544 static crypt_key_t *crypt_getkeybystr (char *p, short abilities,
3545 unsigned int app, int *forced_valid)
3549 crypt_key_t *matches = NULL;
3550 crypt_key_t **matches_endp = &matches;
3554 mutt_message (_("Looking for keys matching \"%s\"..."), p);
3558 hints = crypt_add_string_to_hints (hints, p);
3559 keys = get_candidates (hints, app, (abilities & KEYFLAG_CANSIGN));
3560 mutt_free_list (&hints);
3565 for (k = keys; k; k = k->next) {
3566 if (abilities && !(k->flags & abilities))
3570 debug_print (5, ("matching \"%s\" against " "key %s, \"%s\":\n", p, crypt_keyid (k), k->uid));
3572 if (!*p || !str_casecmp (p, crypt_keyid (k))
3573 || (!str_ncasecmp (p, "0x", 2)
3574 && !str_casecmp (p + 2, crypt_keyid (k)))
3575 || (option (OPTPGPLONGIDS)
3576 && !str_ncasecmp (p, "0x", 2)
3577 && !str_casecmp (p + 2, crypt_keyid (k) + 8))
3578 || str_isstr (k->uid, p)) {
3581 debug_print (5, ("match.\n"));
3583 *matches_endp = tmp = crypt_copy_key (k);
3584 matches_endp = &tmp->next;
3588 crypt_free_key (&keys);
3591 k = crypt_select_key (matches, NULL, p, app, forced_valid);
3592 crypt_free_key (&matches);
3599 /* Display TAG as a prompt to ask for a key. If WHATFOR is not null
3600 use it as default and store it under that label as the next
3601 default. ABILITIES describe the required key abilities (sign,
3602 encrypt) and APP the type of the requested key; ether S/MIME or
3603 PGP. Return a copy of the key or NULL if not found. */
3604 static crypt_key_t *crypt_ask_for_key (char *tag,
3607 unsigned int app, int *forced_valid)
3610 char resp[SHORT_STRING];
3611 struct crypt_cache *l = NULL;
3615 forced_valid = &dummy;
3617 mutt_clear_error ();
3623 for (l = id_defaults; l; l = l->next)
3624 if (!str_casecmp (whatfor, l->what)) {
3625 strfcpy (resp, NONULL (l->dflt), sizeof (resp));
3633 if (mutt_get_field (tag, resp, sizeof (resp), M_CLEAR) != 0)
3638 str_replace (&l->dflt, resp);
3640 l = mem_malloc (sizeof (struct crypt_cache));
3641 l->next = id_defaults;
3643 l->what = str_dup (whatfor);
3644 l->dflt = str_dup (resp);
3648 if ((key = crypt_getkeybystr (resp, abilities, app, forced_valid)))
3656 /* This routine attempts to find the keyids of the recipients of a
3657 message. It returns NULL if any of the keys can not be found. */
3658 static char *find_keys (ADDRESS * to, ADDRESS * cc, ADDRESS * bcc,
3661 char *keyID, *keylist = NULL, *t;
3662 size_t keylist_size = 0;
3663 size_t keylist_used = 0;
3664 ADDRESS *tmp = NULL, *addr = NULL;
3665 ADDRESS **last = &tmp;
3668 crypt_key_t *k_info, *key;
3669 const char *fqdn = mutt_fqdn (1);
3672 *r_application = APPLICATION_PGP | APPLICATION_SMIME;
3675 for (i = 0; i < 3; i++) {
3690 *last = rfc822_cpy_adr (p);
3692 last = &((*last)->next);
3696 rfc822_qualify (tmp, fqdn);
3698 tmp = mutt_remove_duplicates (tmp);
3700 for (p = tmp; p; p = p->next) {
3701 char buf[LONG_STRING];
3702 int forced_valid = 0;
3707 if ((keyID = mutt_crypt_hook (p)) != NULL) {
3710 snprintf (buf, sizeof (buf), _("Use keyID = \"%s\" for %s?"),
3712 if ((r = mutt_yesorno (buf, M_YES)) == M_YES) {
3713 /* check for e-mail address */
3714 if ((t = strchr (keyID, '@')) &&
3715 (addr = rfc822_parse_adrlist (NULL, keyID))) {
3717 rfc822_qualify (addr, fqdn);
3722 k_info = crypt_getkeybystr (keyID, KEYFLAG_CANENCRYPT,
3723 *r_application, &forced_valid);
3725 k_info = crypt_getkeybystr (keyID, KEYFLAG_CANENCRYPT,
3726 app, &forced_valid);
3731 mem_free (&keylist);
3732 rfc822_free_address (&tmp);
3733 rfc822_free_address (&addr);
3739 && (k_info = crypt_getkeybyaddr (q, KEYFLAG_CANENCRYPT,
3740 app, &forced_valid)) == NULL) {
3741 snprintf (buf, sizeof (buf), _("Enter keyID for %s: "), q->mailbox);
3743 if ((key = crypt_ask_for_key (buf, q->mailbox, KEYFLAG_CANENCRYPT,
3749 &forced_valid)) == NULL) {
3750 mem_free (&keylist);
3751 rfc822_free_address (&tmp);
3752 rfc822_free_address (&addr);
3760 const char *s = crypt_fpr (key);
3763 if (key->flags & KEYFLAG_ISX509)
3764 *r_application &= ~APPLICATION_PGP;
3765 if (!(key->flags & KEYFLAG_ISX509))
3766 *r_application &= ~APPLICATION_SMIME;
3769 keylist_size += str_len (s) + 4 + 1;
3770 mem_realloc (&keylist, keylist_size);
3771 sprintf (keylist + keylist_used, "%s0x%s%s", /* __SPRINTF_CHECKED__ */
3772 keylist_used ? " " : "", s, forced_valid ? "!" : "");
3774 keylist_used = str_len (keylist);
3776 crypt_free_key (&key);
3777 rfc822_free_address (&addr);
3779 rfc822_free_address (&tmp);
3783 char *pgp_gpgme_findkeys (ADDRESS * to, ADDRESS * cc, ADDRESS * bcc)
3785 return find_keys (to, cc, bcc, APPLICATION_PGP);
3788 char *smime_gpgme_findkeys (ADDRESS * to, ADDRESS * cc, ADDRESS * bcc)
3790 return find_keys (to, cc, bcc, APPLICATION_SMIME);
3794 * Implementation of `init'.
3797 /* Initialization. */
3798 static void init_gpgme (void)
3800 /* Make sure that gpg-agent is running. */
3801 if (!getenv ("GPG_AGENT_INFO")) {
3802 mutt_error ("\nUsing GPGME backend, although no gpg-agent is running");
3803 if (mutt_any_key_to_continue (NULL) == -1)
3808 void pgp_gpgme_init (void)
3813 void smime_gpgme_init (void)
3817 static int gpgme_send_menu (HEADER * msg, int *redraw, int is_smime)
3820 char input_signas[SHORT_STRING];
3823 if (msg->security & APPLICATION_PGP)
3825 else if (msg->security & APPLICATION_SMIME)
3830 mutt_multi_choice (_
3831 ("S/MIME (e)ncrypt, (s)ign, sign (a)s, (b)oth, (p)gp or (c)lear?"),
3835 mutt_multi_choice (_
3836 ("PGP (e)ncrypt, (s)ign, sign (a)s, (b)oth, s/(m)ime or (c)lear?"),
3840 case 1: /* (e)ncrypt */
3841 msg->security |= (is_smime ? SMIMEENCRYPT : PGPENCRYPT);
3842 msg->security &= ~(is_smime ? SMIMESIGN : PGPSIGN);
3845 case 2: /* (s)ign */
3846 msg->security |= (is_smime ? SMIMESIGN : PGPSIGN);
3847 msg->security &= ~(is_smime ? SMIMEENCRYPT : PGPENCRYPT);
3850 case 3: /* sign (a)s */
3851 /* unset_option(OPTCRYPTCHECKTRUST); */
3852 if ((p = crypt_ask_for_key (_("Sign as: "), NULL, KEYFLAG_CANSIGN,
3853 is_smime ? APPLICATION_SMIME :
3854 APPLICATION_PGP, NULL))) {
3855 snprintf (input_signas, sizeof (input_signas), "0x%s", crypt_keyid (p));
3856 str_replace (is_smime ? &SmimeDefaultKey : &PgpSignAs,
3858 crypt_free_key (&p);
3860 msg->security |= (is_smime ? SMIMESIGN : PGPSIGN);
3864 msg->security &= (is_smime ? ~SMIMESIGN : ~PGPSIGN);
3867 *redraw = REDRAW_FULL;
3870 case 4: /* (b)oth */
3872 (is_smime ? (SMIMEENCRYPT | SMIMESIGN) : (PGPENCRYPT | PGPSIGN));
3875 case 5: /* (p)gp or s/(m)ime */
3876 is_smime = !is_smime;
3879 case 6: /* (c)lear */
3884 if (choice == 6 || choice == 7);
3885 else if (is_smime) {
3886 msg->security &= ~APPLICATION_PGP;
3887 msg->security |= APPLICATION_SMIME;
3890 msg->security &= ~APPLICATION_SMIME;
3891 msg->security |= APPLICATION_PGP;
3894 return (msg->security);
3897 int pgp_gpgme_send_menu (HEADER * msg, int *redraw)
3899 return gpgme_send_menu (msg, redraw, 0);
3902 int smime_gpgme_send_menu (HEADER * msg, int *redraw)
3904 return gpgme_send_menu (msg, redraw, 1);
3907 static int verify_sender (HEADER * h, gpgme_protocol_t protocol)
3909 ADDRESS *sender = NULL;
3910 unsigned int ret = 1;
3913 h->env->from = mutt_expand_aliases (h->env->from);
3914 sender = h->env->from;
3916 else if (h->env->sender) {
3917 h->env->sender = mutt_expand_aliases (h->env->sender);
3918 sender = h->env->sender;
3922 if (signature_key) {
3923 gpgme_key_t key = signature_key;
3924 gpgme_user_id_t uid = NULL;
3925 int sender_length = 0;
3928 sender_length = str_len (sender->mailbox);
3929 for (uid = key->uids; uid && ret; uid = uid->next) {
3930 uid_length = str_len (uid->email);
3931 if (1 && (uid->email[0] == '<')
3932 && (uid->email[uid_length - 1] == '>')
3933 && (uid_length == sender_length + 2)
3934 && (!strncmp (uid->email + 1, sender->mailbox, sender_length)))
3939 mutt_any_key_to_continue ("Failed to verify sender");
3942 mutt_any_key_to_continue ("Failed to figure out sender");
3944 if (signature_key) {
3945 gpgme_key_release (signature_key);
3946 signature_key = NULL;
3952 int smime_gpgme_verify_sender (HEADER * h)
3954 return verify_sender (h, GPGME_PROTOCOL_CMS);