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"
47 #ifdef HAVE_LANGINFO_D_T_FMT
51 #ifdef HAVE_SYS_TIME_H
52 # include <sys/time.h>
55 #ifdef HAVE_SYS_RESOURCE_H
56 # include <sys/resource.h>
62 #define digitp(p) (*(p) >= '0' && *(p) <= '9')
63 #define hexdigitp(a) (digitp (a) \
64 || (*(a) >= 'A' && *(a) <= 'F') \
65 || (*(a) >= 'a' && *(a) <= 'f'))
66 #define xtoi_1(p) (*(p) <= '9'? (*(p)- '0'): \
67 *(p) <= 'F'? (*(p)-'A'+10):(*(p)-'a'+10))
68 #define xtoi_2(p) ((xtoi_1(p) * 16) + xtoi_1((p)+1))
70 /* Values used for comparing addresses. */
71 #define CRYPT_KV_VALID 1
72 #define CRYPT_KV_ADDR 2
73 #define CRYPT_KV_STRING 4
74 #define CRYPT_KV_STRONGID 8
75 #define CRYPT_KV_MATCH (CRYPT_KV_ADDR|CRYPT_KV_STRING)
84 struct crypt_cache *next;
92 /* We work based on user IDs, getting from a user ID to the key is
93 check and does not need any memory (gpgme uses reference counting). */
94 typedef struct crypt_keyinfo {
95 struct crypt_keyinfo *next;
97 int idx; /* and the user ID at this index */
98 const char *uid; /* and for convenience point to this user ID */
99 unsigned int flags; /* global and per uid flags (for convenience) */
102 typedef struct crypt_entry {
108 static struct crypt_cache *id_defaults = NULL;
109 static gpgme_key_t signature_key = NULL;
112 * General helper functions.
115 /* return true when S pints to a didgit or letter. */
116 static int digit_or_letter (const unsigned char *s)
118 return ((*s >= '0' && *s < '9')
119 || (*s >= 'A' && *s <= 'Z')
120 || (*s >= 'a' && *s <= 'z'));
124 /* Print the utf-8 encoded string BUF of length LEN bytes to stream
125 FP. Convert the character set. */
126 static void print_utf8 (FILE * fp, const char *buf, size_t len)
130 tstr = safe_malloc (len + 1);
131 memcpy (tstr, buf, len);
133 mutt_convert_string (&tstr, "utf-8", Charset, M_ICONV_HOOK_FROM);
143 /* Return the keyID for the key K. Note that this string is valid as
144 long as K is valid */
145 static const char *crypt_keyid (crypt_key_t * k)
147 const char *s = "????????";
149 if (k->kobj && k->kobj->subkeys) {
150 s = k->kobj->subkeys->keyid;
151 if ((!option (OPTPGPLONGIDS)) && (mutt_strlen (s) == 16))
152 /* Return only the short keyID. */
159 /* Return the hexstring fingerprint from the key K. */
160 static const char *crypt_fpr (crypt_key_t * k)
164 if (k->kobj && k->kobj->subkeys)
165 s = k->kobj->subkeys->fpr;
170 /* Parse FLAGS and return a statically allocated(!) string with them. */
171 static char *crypt_key_abilities (int flags)
175 if (!(flags & KEYFLAG_CANENCRYPT))
177 else if (flags & KEYFLAG_PREFER_SIGNING)
182 if (!(flags & KEYFLAG_CANSIGN))
184 else if (flags & KEYFLAG_PREFER_ENCRYPTION)
194 /* Parse FLAGS and return a character describing the most important flag. */
195 static char crypt_flags (int flags)
197 if (flags & KEYFLAG_REVOKED)
199 else if (flags & KEYFLAG_EXPIRED)
201 else if (flags & KEYFLAG_DISABLED)
203 else if (flags & KEYFLAG_CRITICAL)
209 /* Return a copy of KEY. */
210 static crypt_key_t *crypt_copy_key (crypt_key_t * key)
214 k = safe_calloc (1, sizeof *k);
216 gpgme_key_ref (key->kobj);
219 k->flags = key->flags;
224 /* Release all the keys at the address of KEYLIST and set the address
226 static void crypt_free_key (crypt_key_t ** keylist)
229 crypt_key_t *k = (*keylist)->next;
236 /* Return trute when key K is valid. */
237 static int crypt_key_is_valid (crypt_key_t * k)
239 if (k->flags & KEYFLAG_CANTUSE)
244 /* Return true whe validity of KEY is sufficient. */
245 static int crypt_id_is_strong (crypt_key_t * key)
247 gpgme_validity_t val = GPGME_VALIDITY_UNKNOWN;
248 gpgme_user_id_t uid = NULL;
249 unsigned int is_strong = 0;
252 if ((key->flags & KEYFLAG_ISX509))
255 for (i = 0, uid = key->kobj->uids; (i < key->idx) && uid;
256 i++, uid = uid->next);
261 case GPGME_VALIDITY_UNKNOWN:
262 case GPGME_VALIDITY_UNDEFINED:
263 case GPGME_VALIDITY_NEVER:
264 case GPGME_VALIDITY_MARGINAL:
268 case GPGME_VALIDITY_FULL:
269 case GPGME_VALIDITY_ULTIMATE:
277 /* Return true when the KEY is valid, i.e. not marked as unusable. */
278 static int crypt_id_is_valid (crypt_key_t * key)
280 return !(key->flags & KEYFLAG_CANTUSE);
283 /* Return a bit vector describing how well the addresses ADDR and
284 U_ADDR match and whether KEY is valid. */
285 static int crypt_id_matches_addr (ADDRESS * addr, ADDRESS * u_addr,
290 if (crypt_id_is_valid (key))
291 rv |= CRYPT_KV_VALID;
293 if (crypt_id_is_strong (key))
294 rv |= CRYPT_KV_STRONGID;
296 if (addr->mailbox && u_addr->mailbox
297 && mutt_strcasecmp (addr->mailbox, u_addr->mailbox) == 0)
300 if (addr->personal && u_addr->personal
301 && mutt_strcasecmp (addr->personal, u_addr->personal) == 0)
302 rv |= CRYPT_KV_STRING;
309 * GPGME convenient functions.
312 /* Create a new gpgme context and return it. With FOR_SMIME set to
313 true, the protocol of the context is set to CMS. */
314 static gpgme_ctx_t create_gpgme_context (int for_smime)
319 err = gpgme_new (&ctx);
321 mutt_error ("error creating gpgme context: %s\n", gpgme_strerror (err));
327 err = gpgme_set_protocol (ctx, GPGME_PROTOCOL_CMS);
329 mutt_error ("error enabling CMS protocol: %s\n", gpgme_strerror (err));
338 /* Create a new gpgme data object. This is a wrapper to die on
340 static gpgme_data_t create_gpgme_data (void)
345 err = gpgme_data_new (&data);
347 mutt_error ("error creating gpgme data object: %s\n",
348 gpgme_strerror (err));
355 /* Create a new GPGME Data object from the mail body A. With CONVERT
356 passed as true, the lines are converted to CR,LF if required.
357 Return NULL on error or the gpgme_data_t object on success. */
358 static gpgme_data_t body_to_data_object (BODY * a, int convert)
360 char tempfile[_POSIX_PATH_MAX];
365 mutt_mktemp (tempfile);
366 fptmp = safe_fopen (tempfile, "w+");
368 mutt_perror (tempfile);
372 mutt_write_mime_header (a, fptmp);
374 mutt_write_mime_body (a, fptmp);
378 unsigned char buf[1];
380 data = create_gpgme_data ();
382 while ((c = fgetc (fptmp)) != EOF) {
386 if (c == '\n' && !hadcr) {
388 gpgme_data_write (data, buf, 1);
393 /* FIXME: This is quite suboptimal */
395 gpgme_data_write (data, buf, 1);
398 gpgme_data_seek (data, 0, SEEK_SET);
402 err = gpgme_data_new_from_file (&data, tempfile, 1);
406 mutt_error ("error allocating data object: %s\n", gpgme_strerror (err));
413 /* Create a GPGME data object from the stream FP but limit the object
414 to LENGTH bytes starting at OFFSET bytes from the beginning of the
416 static gpgme_data_t file_to_data_object (FILE * fp, long offset, long length)
421 err = gpgme_data_new_from_filepart (&data, NULL, fp, offset, length);
423 mutt_error ("error allocating data object: %s\n", gpgme_strerror (err));
430 /* Write a GPGME data object to the stream FP. */
431 static int data_object_to_stream (gpgme_data_t data, FILE * fp)
437 err = ((gpgme_data_seek (data, 0, SEEK_SET) == -1)
438 ? gpgme_error_from_errno (errno) : 0);
440 mutt_error ("error rewinding data object: %s\n", gpgme_strerror (err));
444 while ((nread = gpgme_data_read (data, buf, sizeof (buf)))) {
445 /* fixme: we are not really converting CRLF to LF but just
446 skipping CR. Doing it correctly needs a more complex logic */
447 for (p = buf; nread; p++, nread--) {
453 mutt_perror ("[tempfile]");
458 mutt_error ("error reading data object: %s\n", strerror (errno));
464 /* Copy a data object to a newly created temporay file and return that
465 filename. Caller must free. With RET_FP not NULL, don't close the
466 stream but return it there. */
467 static char *data_object_to_tempfile (gpgme_data_t data, FILE ** ret_fp)
470 char tempfile[_POSIX_PATH_MAX];
474 mutt_mktemp (tempfile);
475 fp = safe_fopen (tempfile, "w+");
477 mutt_perror (tempfile);
481 err = ((gpgme_data_seek (data, 0, SEEK_SET) == -1)
482 ? gpgme_error_from_errno (errno) : 0);
486 while ((nread = gpgme_data_read (data, buf, sizeof (buf)))) {
487 if (fwrite (buf, nread, 1, fp) != 1) {
488 mutt_perror (tempfile);
500 mutt_error ("error reading data object: %s\n", gpgme_strerror (err));
507 return safe_strdup (tempfile);
511 /* Create a GpgmeRecipientSet from the keys in the string KEYLIST.
512 The keys must be space delimited. */
513 static gpgme_key_t *create_recipient_set (const char *keylist,
514 gpgme_protocol_t protocol)
520 gpgme_key_t *rset = NULL;
521 unsigned int rset_n = 0;
522 gpgme_key_t key = NULL;
523 gpgme_ctx_t context = NULL;
525 err = gpgme_new (&context);
527 err = gpgme_set_protocol (context, protocol);
534 for (i = 0; *s && *s != ' ' && i < sizeof (buf) - 1;)
538 if (i > 1 && buf[i - 1] == '!') {
539 /* The user selected to override the valididy of that
543 err = gpgme_get_key (context, buf, &key, 0);
545 key->uids->validity = GPGME_VALIDITY_FULL;
549 err = gpgme_get_key (context, buf, &key, 0);
552 safe_realloc (&rset, sizeof (*rset) * (rset_n + 1));
553 rset[rset_n++] = key;
556 mutt_error ("error adding recipient `%s': %s\n",
557 buf, gpgme_strerror (err));
565 /* NULL terminate. */
566 safe_realloc (&rset, sizeof (*rset) * (rset_n + 1));
567 rset[rset_n++] = NULL;
570 gpgme_release (context);
576 /* Make sure that the correct signer is set. Returns 0 on success. */
577 static int set_signer (gpgme_ctx_t ctx, int for_smime)
579 char *signid = for_smime ? SmimeDefaultKey : PgpSignAs;
582 gpgme_key_t key, key2;
584 if (!signid || !*signid)
587 listctx = create_gpgme_context (for_smime);
588 err = gpgme_op_keylist_start (listctx, signid, 1);
590 err = gpgme_op_keylist_next (listctx, &key);
592 gpgme_release (listctx);
593 mutt_error (_("secret key `%s' not found: %s\n"),
594 signid, gpgme_strerror (err));
597 err = gpgme_op_keylist_next (listctx, &key2);
599 gpgme_key_release (key);
600 gpgme_key_release (key2);
601 gpgme_release (listctx);
602 mutt_error (_("ambiguous specfication of secret key `%s'\n"), signid);
605 gpgme_op_keylist_end (listctx);
606 gpgme_release (listctx);
608 gpgme_signers_clear (ctx);
609 err = gpgme_signers_add (ctx, key);
610 gpgme_key_release (key);
612 mutt_error (_("error setting secret key `%s': %s\n"),
613 signid, gpgme_strerror (err));
620 /* Encrypt the gpgme data object PLAINTEXT to the recipients in RSET
621 and return an allocated filename to a temporary file containing the
622 enciphered text. With USE_SMIME set to true, the smime backend is
623 used. With COMBINED_SIGNED a PGP message is signed and
624 encrypted. Returns NULL in case of error */
625 static char *encrypt_gpgme_object (gpgme_data_t plaintext, gpgme_key_t * rset,
626 int use_smime, int combined_signed)
630 gpgme_data_t ciphertext;
633 ctx = create_gpgme_context (use_smime);
635 gpgme_set_armor (ctx, 1);
637 ciphertext = create_gpgme_data ();
639 if (combined_signed) {
640 if (set_signer (ctx, use_smime)) {
641 gpgme_data_release (ciphertext);
645 err = gpgme_op_encrypt_sign (ctx, rset, GPGME_ENCRYPT_ALWAYS_TRUST,
646 plaintext, ciphertext);
649 err = gpgme_op_encrypt (ctx, rset, GPGME_ENCRYPT_ALWAYS_TRUST,
650 plaintext, ciphertext);
651 mutt_need_hard_redraw ();
653 mutt_error ("error encrypting data: %s\n", gpgme_strerror (err));
654 gpgme_data_release (ciphertext);
661 outfile = data_object_to_tempfile (ciphertext, NULL);
662 gpgme_data_release (ciphertext);
666 /* Find the "micalg" parameter from the last Gpgme operation on
667 context CTX. It is expected that this operation was a sign
668 operation. Return the algorithm name as a C string in buffer BUF
669 which must have been allocated by the caller with size BUFLEN.
670 Returns 0 on success or -1 in case of an error. The return string
671 is truncted to BUFLEN - 1. */
672 static int get_micalg (gpgme_ctx_t ctx, char *buf, size_t buflen)
674 gpgme_sign_result_t result = NULL;
675 const char *algorithm_name = NULL;
681 result = gpgme_op_sign_result (ctx);
683 algorithm_name = gpgme_hash_algo_name (result->signatures->hash_algo);
684 if (algorithm_name) {
685 strncpy (buf, algorithm_name, buflen - 1);
690 return *buf ? 0 : -1;
693 static void print_time (time_t t, STATE * s)
697 setlocale (LC_TIME, "");
698 #ifdef HAVE_LANGINFO_D_T_FMT
699 strftime (p, sizeof (p), nl_langinfo (D_T_FMT), localtime (&t));
701 strftime (p, sizeof (p), "%c", localtime (&t));
703 setlocale (LC_TIME, "C");
704 state_attach_puts (p, s);
708 * Implementation of `sign_message'.
711 /* Sign the MESSAGE in body A either using OpenPGP or S/MIME when
712 USE_SMIME is passed as true. Returns the new body or NULL on
714 static BODY *sign_message (BODY * a, int use_smime)
721 gpgme_data_t message, signature;
723 convert_to_7bit (a); /* Signed data _must_ be in 7-bit format. */
725 message = body_to_data_object (a, 1);
728 signature = create_gpgme_data ();
730 ctx = create_gpgme_context (use_smime);
732 gpgme_set_armor (ctx, 1);
734 if (set_signer (ctx, use_smime)) {
735 gpgme_data_release (signature);
740 err = gpgme_op_sign (ctx, message, signature, GPGME_SIG_MODE_DETACH);
741 mutt_need_hard_redraw ();
742 gpgme_data_release (message);
744 gpgme_data_release (signature);
746 mutt_error ("error signing data: %s\n", gpgme_strerror (err));
750 sigfile = data_object_to_tempfile (signature, NULL);
751 gpgme_data_release (signature);
757 t = mutt_new_body ();
758 t->type = TYPEMULTIPART;
759 t->subtype = safe_strdup ("signed");
760 t->encoding = ENC7BIT;
762 t->disposition = DISPINLINE;
764 mutt_generate_boundary (&t->parameter);
765 mutt_set_parameter ("protocol",
766 use_smime ? "application/pkcs7-signature"
767 : "application/pgp-signature", &t->parameter);
768 /* Get the micalg from gpgme. Old gpgme versions don't support this
769 for S/MIME so we assume sha-1 in this case. */
770 if (!get_micalg (ctx, buf, sizeof buf))
771 mutt_set_parameter ("micalg", buf, &t->parameter);
773 mutt_set_parameter ("micalg", "sha1", &t->parameter);
779 t->parts->next = mutt_new_body ();
781 t->type = TYPEAPPLICATION;
783 t->subtype = safe_strdup ("pkcs7-signature");
784 mutt_set_parameter ("name", "smime.p7s", &t->parameter);
785 t->encoding = ENCBASE64;
787 t->disposition = DISPATTACH;
788 t->d_filename = safe_strdup ("smime.p7s");
791 t->subtype = safe_strdup ("pgp-signature");
793 t->disposition = DISPINLINE;
794 t->encoding = ENC7BIT;
796 t->filename = sigfile;
797 t->unlink = 1; /* ok to remove this file after sending. */
803 BODY *pgp_gpgme_sign_message (BODY * a)
805 return sign_message (a, 0);
808 BODY *smime_gpgme_sign_message (BODY * a)
810 return sign_message (a, 1);
814 * Implementation of `encrypt_message'.
817 /* Encrypt the mail body A to all keys given as space separated keyids
818 or fingerprints in KEYLIST and return the encrypted body. */
819 BODY *pgp_gpgme_encrypt_message (BODY * a, char *keylist, int sign)
821 char *outfile = NULL;
823 gpgme_key_t *rset = NULL;
824 gpgme_data_t plaintext;
826 rset = create_recipient_set (keylist, GPGME_PROTOCOL_OpenPGP);
832 plaintext = body_to_data_object (a, 0);
838 outfile = encrypt_gpgme_object (plaintext, rset, 0, sign);
839 gpgme_data_release (plaintext);
844 t = mutt_new_body ();
845 t->type = TYPEMULTIPART;
846 t->subtype = safe_strdup ("encrypted");
847 t->encoding = ENC7BIT;
849 t->disposition = DISPINLINE;
851 mutt_generate_boundary (&t->parameter);
852 mutt_set_parameter ("protocol", "application/pgp-encrypted", &t->parameter);
854 t->parts = mutt_new_body ();
855 t->parts->type = TYPEAPPLICATION;
856 t->parts->subtype = safe_strdup ("pgp-encrypted");
857 t->parts->encoding = ENC7BIT;
859 t->parts->next = mutt_new_body ();
860 t->parts->next->type = TYPEAPPLICATION;
861 t->parts->next->subtype = safe_strdup ("octet-stream");
862 t->parts->next->encoding = ENC7BIT;
863 t->parts->next->filename = outfile;
864 t->parts->next->use_disp = 1;
865 t->parts->next->disposition = DISPINLINE;
866 t->parts->next->unlink = 1; /* delete after sending the message */
867 t->parts->next->d_filename = safe_strdup ("msg.asc"); /* non pgp/mime
874 * Implementation of `smime_build_smime_entity'.
877 /* Encrypt the mail body A to all keys given as space separated
878 fingerprints in KEYLIST and return the S/MIME encrypted body. */
879 BODY *smime_gpgme_build_smime_entity (BODY * a, char *keylist)
881 char *outfile = NULL;
883 gpgme_key_t *rset = NULL;
884 gpgme_data_t plaintext;
886 rset = create_recipient_set (keylist, GPGME_PROTOCOL_CMS);
890 plaintext = body_to_data_object (a, 0);
896 outfile = encrypt_gpgme_object (plaintext, rset, 1, 0);
897 gpgme_data_release (plaintext);
902 t = mutt_new_body ();
903 t->type = TYPEAPPLICATION;
904 t->subtype = safe_strdup ("pkcs7-mime");
905 mutt_set_parameter ("name", "smime.p7m", &t->parameter);
906 mutt_set_parameter ("smime-type", "enveloped-data", &t->parameter);
907 t->encoding = ENCBASE64; /* The output of OpenSSL SHOULD be binary */
909 t->disposition = DISPATTACH;
910 t->d_filename = safe_strdup ("smime.p7m");
911 t->filename = outfile;
912 t->unlink = 1; /*delete after sending the message */
921 * Implementation of `verify_one'.
924 /* Display the common attributes of the signature summary SUM.
925 Return 1 if there is is a severe warning.
927 static int show_sig_summary (unsigned long sum,
928 gpgme_ctx_t ctx, gpgme_key_t key, int idx,
933 if ((sum & GPGME_SIGSUM_KEY_REVOKED)) {
934 state_attach_puts (_("Warning: One of the keys has been revoked\n"), s);
938 if ((sum & GPGME_SIGSUM_KEY_EXPIRED)) {
939 time_t at = key->subkeys->expires ? key->subkeys->expires : 0;
942 state_attach_puts (_("Warning: The key used to create the "
943 "signature expired at: "), s);
945 state_attach_puts ("\n", s);
948 state_attach_puts (_("Warning: At least one certification key "
949 "has expired\n"), s);
952 if ((sum & GPGME_SIGSUM_SIG_EXPIRED)) {
953 gpgme_verify_result_t result;
954 gpgme_signature_t sig;
957 result = gpgme_op_verify_result (ctx);
959 for (sig = result->signatures, i = 0; sig && (i < idx);
960 sig = sig->next, i++);
962 state_attach_puts (_("Warning: The signature expired at: "), s);
963 print_time (sig ? sig->exp_timestamp : 0, s);
964 state_attach_puts ("\n", s);
967 if ((sum & GPGME_SIGSUM_KEY_MISSING))
968 state_attach_puts (_("Can't verify due to a missing "
969 "key or certificate\n"), s);
971 if ((sum & GPGME_SIGSUM_CRL_MISSING)) {
972 state_attach_puts (_("The CRL is not available\n"), s);
976 if ((sum & GPGME_SIGSUM_CRL_TOO_OLD)) {
977 state_attach_puts (_("Available CRL is too old\n"), s);
981 if ((sum & GPGME_SIGSUM_BAD_POLICY))
982 state_attach_puts (_("A policy requirement was not met\n"), s);
984 if ((sum & GPGME_SIGSUM_SYS_ERROR)) {
985 const char *t0 = NULL, *t1 = NULL;
986 gpgme_verify_result_t result;
987 gpgme_signature_t sig;
990 state_attach_puts (_("A system error occured"), s);
992 /* Try to figure out some more detailed system error information. */
993 result = gpgme_op_verify_result (ctx);
994 for (sig = result->signatures, i = 0; sig && (i < idx);
995 sig = sig->next, i++);
998 t1 = sig->wrong_key_usage ? "Wrong_Key_Usage" : "";
1002 state_attach_puts (": ", s);
1004 state_attach_puts (t0, s);
1005 if (t1 && !(t0 && !strcmp (t0, t1))) {
1007 state_attach_puts (",", s);
1008 state_attach_puts (t1, s);
1011 state_attach_puts ("\n", s);
1018 static void show_fingerprint (gpgme_key_t key, STATE * state)
1023 const char *prefix = _("Fingerprint: ");
1027 s = key->subkeys ? key->subkeys->fpr : NULL;
1030 is_pgp = (key->protocol == GPGME_PROTOCOL_OpenPGP);
1032 buf = safe_malloc (mutt_strlen (prefix) + mutt_strlen (s) * 4 + 2);
1033 strcpy (buf, prefix); /* __STRCPY_CHECKED__ */
1034 p = buf + mutt_strlen (buf);
1035 if (is_pgp && mutt_strlen (s) == 40) { /* PGP v4 style formatted. */
1036 for (i = 0; *s && s[1] && s[2] && s[3] && s[4]; s += 4, i++) {
1047 for (i = 0; *s && s[1] && s[2]; s += 2, i++) {
1050 *p++ = is_pgp ? ' ' : ':';
1051 if (is_pgp && i == 7)
1056 /* just in case print remaining odd digits */
1061 state_attach_puts (buf, state);
1065 /* Show the valididy of a key used for one signature. */
1066 static void show_one_sig_validity (gpgme_ctx_t ctx, int idx, STATE * s)
1068 gpgme_verify_result_t result = NULL;
1069 gpgme_signature_t sig = NULL;
1070 const char *txt = NULL;
1072 result = gpgme_op_verify_result (ctx);
1074 for (sig = result->signatures; sig && (idx > 0); sig = sig->next, idx--);
1076 switch (sig ? sig->validity : 0) {
1077 case GPGME_VALIDITY_UNKNOWN:
1078 txt = _("WARNING: We have NO indication whether "
1079 "the key belongs to the person named " "as shown above\n");
1081 case GPGME_VALIDITY_UNDEFINED:
1083 case GPGME_VALIDITY_NEVER:
1084 txt = _("WARNING: The key does NOT BELONG to "
1085 "the person named as shown above\n");
1087 case GPGME_VALIDITY_MARGINAL:
1088 txt = _("WARNING: It is NOT certain that the key "
1089 "belongs to the person named as shown above\n");
1091 case GPGME_VALIDITY_FULL:
1092 case GPGME_VALIDITY_ULTIMATE:
1097 state_attach_puts (txt, s);
1100 /* Show information about one signature. This fucntion is called with
1101 the context CTX of a sucessful verification operation and the
1102 enumerator IDX which should start at 0 and incremete for each
1105 Return values are: 0 for normal procession, 1 for a bad signature,
1106 2 for a signature with a warning or -1 for no more signature. */
1107 static int show_one_sig_status (gpgme_ctx_t ctx, int idx, STATE * s)
1110 const char *fpr, *uid;
1111 gpgme_key_t key = NULL;
1112 int i, anybad = 0, anywarn = 0;
1114 gpgme_user_id_t uids = NULL;
1115 gpgme_verify_result_t result;
1116 gpgme_signature_t sig;
1117 gpgme_error_t err = GPG_ERR_NO_ERROR;
1119 result = gpgme_op_verify_result (ctx);
1121 /* FIXME: this code should use a static variable and remember
1122 the current position in the list of signatures, IMHO.
1125 for (i = 0, sig = result->signatures; sig && (i < idx);
1126 i++, sig = sig->next);
1128 return -1; /* Signature not found. */
1130 if (signature_key) {
1131 gpgme_key_release (signature_key);
1132 signature_key = NULL;
1135 created = sig->timestamp;
1139 if (gpg_err_code (sig->status) != GPG_ERR_NO_ERROR)
1142 err = gpgme_get_key (ctx, fpr, &key, 0); /* secret key? */
1144 uid = (key->uids && key->uids->uid) ? key->uids->uid : "[?]";
1146 signature_key = key;
1149 key = NULL; /* Old gpgme versions did not set KEY to NULL on
1150 error. Do it here to avoid a double free. */
1154 if (!s || !s->fpout || !(s->flags & M_DISPLAY)); /* No state information so no way to print anything. */
1156 state_attach_puts (_("Error getting key information: "), s);
1157 state_attach_puts (gpg_strerror (err), s);
1158 state_attach_puts ("\n", s);
1161 else if ((sum & GPGME_SIGSUM_GREEN)) {
1162 state_attach_puts (_("Good signature from: "), s);
1163 state_attach_puts (uid, s);
1164 state_attach_puts ("\n", s);
1165 for (i = 1, uids = key->uids; uids; i++, uids = uids->next) {
1167 /* Skip primary UID. */
1171 state_attach_puts (_(" aka: "), s);
1172 state_attach_puts (uids->uid, s);
1173 state_attach_puts ("\n", s);
1175 state_attach_puts (_(" created: "), s);
1176 print_time (created, s);
1177 state_attach_puts ("\n", s);
1178 if (show_sig_summary (sum, ctx, key, idx, s))
1180 show_one_sig_validity (ctx, idx, s);
1182 else if ((sum & GPGME_SIGSUM_RED)) {
1183 state_attach_puts (_("*BAD* signature claimed to be from: "), s);
1184 state_attach_puts (uid, s);
1185 state_attach_puts ("\n", s);
1186 show_sig_summary (sum, ctx, key, idx, s);
1188 else if (!anybad && key && (key->protocol == GPGME_PROTOCOL_OpenPGP)) { /* We can't decide (yellow) but this is a PGP key with a good
1189 signature, so we display what a PGP user expects: The name,
1190 fingerprint and the key validity (which is neither fully or
1192 state_attach_puts (_("Good signature from: "), s);
1193 state_attach_puts (uid, s);
1194 state_attach_puts ("\n", s);
1195 state_attach_puts (_(" created: "), s);
1196 print_time (created, s);
1197 state_attach_puts ("\n", s);
1198 show_one_sig_validity (ctx, idx, s);
1199 show_fingerprint (key, s);
1200 if (show_sig_summary (sum, ctx, key, idx, s))
1203 else { /* can't decide (yellow) */
1205 state_attach_puts (_("Error checking signature"), s);
1206 state_attach_puts ("\n", s);
1207 show_sig_summary (sum, ctx, key, idx, s);
1210 if (key != signature_key)
1211 gpgme_key_release (key);
1214 return anybad ? 1 : anywarn ? 2 : 0;
1217 /* Do the actual verification step. With IS_SMIME set to true we
1218 assume S/MIME (surprise!) */
1219 static int verify_one (BODY * sigbdy, STATE * s,
1220 const char *tempfile, int is_smime)
1226 gpgme_data_t signature, message;
1228 signature = file_to_data_object (s->fpin, sigbdy->offset, sigbdy->length);
1232 /* We need to tell gpgme about the encoding because the backend can't
1233 auto-detect plain base-64 encoding which is used by S/MIME. */
1235 gpgme_data_set_encoding (signature, GPGME_DATA_ENCODING_BASE64);
1237 err = gpgme_data_new_from_file (&message, tempfile, 1);
1239 gpgme_data_release (signature);
1240 mutt_error ("error allocating data object: %s\n", gpgme_strerror (err));
1243 ctx = create_gpgme_context (is_smime);
1245 /* Note: We don't need a current time output because GPGME avoids
1246 such an attack by separating the meta information from the
1248 state_attach_puts (_("[-- Begin signature information --]\n"), s);
1250 err = gpgme_op_verify (ctx, signature, message, NULL);
1251 mutt_need_hard_redraw ();
1255 snprintf (buf, sizeof (buf) - 1,
1256 _("Error: verification failed: %s\n"), gpgme_strerror (err));
1257 state_attach_puts (buf, s);
1259 else { /* Verification succeeded, see what the result is. */
1263 if (signature_key) {
1264 gpgme_key_release (signature_key);
1265 signature_key = NULL;
1268 for (idx = 0; (res = show_one_sig_status (ctx, idx, s)) != -1; idx++) {
1279 gpgme_verify_result_t result;
1280 gpgme_sig_notation_t notation;
1281 gpgme_signature_t signature;
1283 result = gpgme_op_verify_result (ctx);
1285 for (signature = result->signatures; signature;
1286 signature = signature->next) {
1287 if (signature->notations) {
1288 state_attach_puts ("*** Begin Notation (signature by: ", s);
1289 state_attach_puts (signature->fpr, s);
1290 state_attach_puts (") ***\n", s);
1291 for (notation = signature->notations; notation;
1292 notation = notation->next) {
1293 if (notation->name) {
1294 state_attach_puts (notation->name, s);
1295 state_attach_puts ("=", s);
1297 if (notation->value) {
1298 state_attach_puts (notation->value, s);
1299 if (!(*notation->value
1300 && (notation->value[mutt_strlen (notation->value) - 1] ==
1302 state_attach_puts ("\n", s);
1305 state_attach_puts ("*** End Notation ***\n", s);
1311 gpgme_release (ctx);
1313 state_attach_puts (_("[-- End signature information --]\n\n"), s);
1314 dprint (1, (debugfile, "verify_one: returning %d.\n", badsig));
1316 return badsig ? 1 : anywarn ? 2 : 0;
1319 int pgp_gpgme_verify_one (BODY * sigbdy, STATE * s, const char *tempfile)
1321 return verify_one (sigbdy, s, tempfile, 0);
1324 int smime_gpgme_verify_one (BODY * sigbdy, STATE * s, const char *tempfile)
1326 return verify_one (sigbdy, s, tempfile, 1);
1330 * Implementation of `decrypt_part'.
1333 /* Decrypt a PGP or SMIME message (depending on the boolean flag
1334 IS_SMIME) with body A described further by state S. Write
1335 plaintext out to file FPOUT and return a new body. For PGP returns
1336 a flag in R_IS_SIGNED to indicate whether this is a combined
1337 encrypted and signed message, for S/MIME it returns true when it is
1338 not a encrypted but a signed message. */
1339 static BODY *decrypt_part (BODY * a, STATE * s, FILE * fpout, int is_smime,
1346 gpgme_data_t ciphertext, plaintext;
1347 int maybe_signed = 0;
1354 ctx = create_gpgme_context (is_smime);
1357 /* Make a data object from the body, create context etc. */
1358 ciphertext = file_to_data_object (s->fpin, a->offset, a->length);
1361 plaintext = create_gpgme_data ();
1363 /* Do the decryption or the verification in case of the S/MIME hack. */
1364 if ((!is_smime) || maybe_signed) {
1366 err = gpgme_op_decrypt_verify (ctx, ciphertext, plaintext);
1367 else if (maybe_signed)
1368 err = gpgme_op_verify (ctx, ciphertext, NULL, plaintext);
1371 /* Check wether signatures have been verified. */
1372 gpgme_verify_result_t verify_result = gpgme_op_verify_result (ctx);
1374 if (verify_result->signatures)
1379 err = gpgme_op_decrypt (ctx, ciphertext, plaintext);
1380 gpgme_data_release (ciphertext);
1382 if (is_smime && !maybe_signed && gpg_err_code (err) == GPG_ERR_NO_DATA) {
1383 /* Check whether this might be a signed message despite what
1384 the mime header told us. Retry then. gpgsm returns the
1385 error information "unsupported Algorithm '?'" but gpgme
1386 will not store this unknown algorithm, thus we test that
1387 it has not been set. */
1388 gpgme_decrypt_result_t result;
1390 result = gpgme_op_decrypt_result (ctx);
1391 if (!result->unsupported_algorithm) {
1393 gpgme_data_release (plaintext);
1397 mutt_need_hard_redraw ();
1398 if ((s->flags & M_DISPLAY)) {
1401 snprintf (buf, sizeof (buf) - 1,
1402 _("[-- Error: decryption failed: %s --]\n\n"),
1403 gpgme_strerror (err));
1404 state_attach_puts (buf, s);
1406 gpgme_data_release (plaintext);
1407 gpgme_release (ctx);
1410 mutt_need_hard_redraw ();
1412 /* Read the output from GPGME, and make sure to change CRLF to LF,
1413 otherwise read_mime_header has a hard time parsing the message. */
1414 if (data_object_to_stream (plaintext, fpout)) {
1415 gpgme_data_release (plaintext);
1416 gpgme_release (ctx);
1419 gpgme_data_release (plaintext);
1421 a->is_signed_data = 0;
1427 a->is_signed_data = 1;
1429 *r_is_signed = -1; /* A signature exists. */
1431 if ((s->flags & M_DISPLAY))
1432 state_attach_puts (_("[-- Begin signature " "information --]\n"), s);
1433 for (idx = 0; (res = show_one_sig_status (ctx, idx, s)) != -1; idx++) {
1439 if (!anybad && idx && r_is_signed && *r_is_signed)
1440 *r_is_signed = anywarn ? 2 : 1; /* Good signature. */
1442 if ((s->flags & M_DISPLAY))
1443 state_attach_puts (_("[-- End signature " "information --]\n\n"), s);
1445 gpgme_release (ctx);
1450 tattach = mutt_read_mime_header (fpout, 0);
1453 * Need to set the length of this body part.
1455 fstat (fileno (fpout), &info);
1456 tattach->length = info.st_size - tattach->offset;
1458 tattach->warnsig = anywarn;
1460 /* See if we need to recurse on this MIME part. */
1461 mutt_parse_part (fpout, tattach);
1467 /* Decrypt a PGP/MIME message in FPIN and B and return a new body and
1468 the stream in CUR and FPOUT. Returns 0 on success. */
1469 int pgp_gpgme_decrypt_mime (FILE * fpin, FILE ** fpout, BODY * b, BODY ** cur)
1471 char tempfile[_POSIX_PATH_MAX];
1473 BODY *first_part = b;
1476 first_part->goodsig = 0;
1477 first_part->warnsig = 0;
1479 if (!mutt_is_multipart_encrypted (b))
1482 if (!b->parts || !b->parts->next)
1487 memset (&s, 0, sizeof (s));
1489 mutt_mktemp (tempfile);
1490 if (!(*fpout = safe_fopen (tempfile, "w+"))) {
1491 mutt_perror (tempfile);
1496 *cur = decrypt_part (b, &s, *fpout, 0, &is_signed);
1499 first_part->goodsig = 1;
1501 return *cur ? 0 : -1;
1505 /* Decrypt a S/MIME message in FPIN and B and return a new body and
1506 the stream in CUR and FPOUT. Returns 0 on success. */
1507 int smime_gpgme_decrypt_mime (FILE * fpin, FILE ** fpout, BODY * b,
1510 char tempfile[_POSIX_PATH_MAX];
1514 long saved_b_offset;
1515 size_t saved_b_length;
1518 if (!mutt_is_application_smime (b))
1524 /* Decode the body - we need to pass binary CMS to the
1525 backend. The backend allows for Base64 encoded data but it does
1526 not allow for QP which I have seen in some messages. So better
1528 saved_b_type = b->type;
1529 saved_b_offset = b->offset;
1530 saved_b_length = b->length;
1531 memset (&s, 0, sizeof (s));
1533 fseek (s.fpin, b->offset, 0);
1534 mutt_mktemp (tempfile);
1535 if (!(tmpfp = safe_fopen (tempfile, "w+"))) {
1536 mutt_perror (tempfile);
1539 mutt_unlink (tempfile);
1542 mutt_decode_attachment (b, &s);
1544 b->length = ftell (s.fpout);
1548 memset (&s, 0, sizeof (s));
1551 mutt_mktemp (tempfile);
1552 if (!(*fpout = safe_fopen (tempfile, "w+"))) {
1553 mutt_perror (tempfile);
1556 mutt_unlink (tempfile);
1558 *cur = decrypt_part (b, &s, *fpout, 1, &is_signed);
1560 (*cur)->goodsig = is_signed > 0;
1561 b->type = saved_b_type;
1562 b->length = saved_b_length;
1563 b->offset = saved_b_offset;
1566 if (*cur && !is_signed && !(*cur)->parts
1567 && mutt_is_application_smime (*cur)) {
1568 /* Assume that this is a opaque signed s/mime message. This is
1569 an ugly way of doing it but we have anyway a problem with
1570 arbitrary encoded S/MIME messages: Only the outer part may be
1571 encrypted. The entire mime parsing should be revamped,
1572 probably by keeping the temportary files so that we don't
1573 need to decrypt them all the time. Inner parts of an
1574 encrypted part can then pint into this file and tehre won't
1575 never be a need to decrypt again. This needs a partial
1576 rewrite of the MIME engine. */
1580 saved_b_type = bb->type;
1581 saved_b_offset = bb->offset;
1582 saved_b_length = bb->length;
1583 memset (&s, 0, sizeof (s));
1585 fseek (s.fpin, bb->offset, 0);
1586 mutt_mktemp (tempfile);
1587 if (!(tmpfp = safe_fopen (tempfile, "w+"))) {
1588 mutt_perror (tempfile);
1591 mutt_unlink (tempfile);
1594 mutt_decode_attachment (bb, &s);
1596 bb->length = ftell (s.fpout);
1601 memset (&s, 0, sizeof (s));
1604 mutt_mktemp (tempfile);
1605 if (!(*fpout = safe_fopen (tempfile, "w+"))) {
1606 mutt_perror (tempfile);
1609 mutt_unlink (tempfile);
1611 tmp_b = decrypt_part (bb, &s, *fpout, 1, &is_signed);
1613 tmp_b->goodsig = is_signed > 0;
1614 bb->type = saved_b_type;
1615 bb->length = saved_b_length;
1616 bb->offset = saved_b_offset;
1619 mutt_free_body (cur);
1622 return *cur ? 0 : -1;
1627 * Implementation of `pgp_check_traditional'.
1630 static int pgp_check_traditional_one_body (FILE * fp, BODY * b,
1633 char tempfile[_POSIX_PATH_MAX];
1634 char buf[HUGE_STRING];
1640 if (b->type != TYPETEXT)
1643 if (tagged_only && !b->tagged)
1646 mutt_mktemp (tempfile);
1647 if (mutt_decode_save_attachment (fp, b, tempfile, 0, 0) != 0) {
1652 if ((tfp = fopen (tempfile, "r")) == NULL) {
1657 while (fgets (buf, sizeof (buf), tfp)) {
1658 if (!mutt_strncmp ("-----BEGIN PGP ", buf, 15)) {
1659 if (!mutt_strcmp ("MESSAGE-----\n", buf + 15))
1661 else if (!mutt_strcmp ("SIGNED MESSAGE-----\n", buf + 15))
1671 /* fix the content type */
1673 mutt_set_parameter ("format", "fixed", &b->parameter);
1674 mutt_set_parameter ("x-action", enc ? "pgp-encrypted" : "pgp-signed",
1680 int pgp_gpgme_check_traditional (FILE * fp, BODY * b, int tagged_only)
1685 for (; b; b = b->next) {
1686 if (is_multipart (b))
1687 rv = (pgp_gpgme_check_traditional (fp, b->parts, tagged_only) || rv);
1688 else if (b->type == TYPETEXT) {
1689 if ((r = mutt_is_application_pgp (b)))
1692 rv = (pgp_check_traditional_one_body (fp, b, tagged_only) || rv);
1700 * Implementation of `application_handler'.
1704 Copy a clearsigned message, and strip the signature and PGP's
1707 XXX - charset handling: We assume that it is safe to do
1708 character set decoding first, dash decoding second here, while
1709 we do it the other way around in the main handler.
1711 (Note that we aren't worse than Outlook & Cie in this, and also
1712 note that we can successfully handle anything produced by any
1713 existing versions of mutt.) */
1715 static void copy_clearsigned (gpgme_data_t data, STATE * s, char *charset)
1717 char buf[HUGE_STRING];
1718 short complete, armor_header;
1723 fname = data_object_to_tempfile (data, &fp);
1729 fc = fgetconv_open (fp, charset, Charset, M_ICONV_HOOK_FROM);
1731 for (complete = 1, armor_header = 1;
1732 fgetconvs (buf, sizeof (buf), fc) != NULL;
1733 complete = strchr (buf, '\n') != NULL) {
1736 state_puts (buf, s);
1740 if (!mutt_strcmp (buf, "-----BEGIN PGP SIGNATURE-----\n"))
1750 state_puts (s->prefix, s);
1752 if (buf[0] == '-' && buf[1] == ' ')
1753 state_puts (buf + 2, s);
1755 state_puts (buf, s);
1758 fgetconv_close (&fc);
1763 /* Support for classic_application/pgp */
1764 void pgp_gpgme_application_handler (BODY * m, STATE * s)
1766 int needpass = -1, pgp_keyblock = 0;
1769 long bytes, last_pos, offset;
1770 char buf[HUGE_STRING];
1771 FILE *pgpout = NULL;
1774 gpgme_data_t armored_data = NULL;
1776 short maybe_goodsig = 1;
1777 short have_any_sigs = 0;
1779 char body_charset[STRING]; /* Only used for clearsigned messages. */
1781 dprint (2, (debugfile, "Entering pgp_application_pgp handler\n"));
1783 /* For clearsigned messages we won't be able to get a character set
1784 but we know that this may only be text thus we assume Latin-1
1786 if (!mutt_get_body_charset (body_charset, sizeof (body_charset), m))
1787 strfcpy (body_charset, "iso-8859-1", sizeof body_charset);
1789 fseek (s->fpin, m->offset, 0);
1790 last_pos = m->offset;
1792 for (bytes = m->length; bytes > 0;) {
1793 if (fgets (buf, sizeof (buf), s->fpin) == NULL)
1796 offset = ftell (s->fpin);
1797 bytes -= (offset - last_pos); /* don't rely on mutt_strlen(buf) */
1800 if (!mutt_strncmp ("-----BEGIN PGP ", buf, 15)) {
1802 start_pos = last_pos;
1804 if (!mutt_strcmp ("MESSAGE-----\n", buf + 15))
1806 else if (!mutt_strcmp ("SIGNED MESSAGE-----\n", buf + 15)) {
1810 else if (!option (OPTDONTHANDLEPGPKEYS) &&
1811 !mutt_strcmp ("PUBLIC KEY BLOCK-----\n", buf + 15)) {
1816 /* XXX - we may wish to recode here */
1818 state_puts (s->prefix, s);
1819 state_puts (buf, s);
1823 have_any_sigs = (have_any_sigs || (clearsign && (s->flags & M_VERIFY)));
1825 /* Copy PGP material to an data container */
1826 armored_data = create_gpgme_data ();
1827 gpgme_data_write (armored_data, buf, mutt_strlen (buf));
1828 while (bytes > 0 && fgets (buf, sizeof (buf) - 1, s->fpin) != NULL) {
1829 offset = ftell (s->fpin);
1830 bytes -= (offset - last_pos); /* don't rely on mutt_strlen(buf) */
1833 gpgme_data_write (armored_data, buf, mutt_strlen (buf));
1835 if ((needpass && !mutt_strcmp ("-----END PGP MESSAGE-----\n", buf))
1837 && (!mutt_strcmp ("-----END PGP SIGNATURE-----\n", buf)
1838 || !mutt_strcmp ("-----END PGP PUBLIC KEY BLOCK-----\n",
1843 /* Invoke PGP if needed */
1844 if (!clearsign || (s->flags & M_VERIFY)) {
1845 unsigned int sig_stat = 0;
1846 gpgme_data_t plaintext;
1849 plaintext = create_gpgme_data ();
1850 ctx = create_gpgme_context (0);
1853 err = gpgme_op_verify (ctx, armored_data, NULL, plaintext);
1855 err = gpgme_op_decrypt_verify (ctx, armored_data, plaintext);
1856 if (gpg_err_code (err) == GPG_ERR_NO_DATA) {
1857 /* Decrypt verify can't handle signed only messages. */
1858 err = (gpgme_data_seek (armored_data, 0, SEEK_SET) == -1)
1859 ? gpgme_error_from_errno (errno) : 0;
1860 /* Must release plaintext so that we supply an
1861 uninitialized object. */
1862 gpgme_data_release (plaintext);
1863 plaintext = create_gpgme_data ();
1864 err = gpgme_op_verify (ctx, armored_data, NULL, plaintext);
1871 snprintf (errbuf, sizeof (errbuf) - 1,
1872 _("Error: decryption/verification failed: %s\n"),
1873 gpgme_strerror (err));
1874 state_attach_puts (errbuf, s);
1876 else { /* Decryption/Verification succeeded */
1880 /* Check wether signatures have been verified. */
1881 gpgme_verify_result_t verify_result;
1883 verify_result = gpgme_op_verify_result (ctx);
1884 if (verify_result->signatures)
1890 if ((s->flags & M_DISPLAY) && sig_stat) {
1895 state_attach_puts (_("[-- Begin signature "
1896 "information --]\n"), s);
1899 (res = show_one_sig_status (ctx, idx, s)) != -1; idx++) {
1908 state_attach_puts (_("[-- End signature "
1909 "information --]\n\n"), s);
1912 tmpfname = data_object_to_tempfile (plaintext, &pgpout);
1915 state_attach_puts (_("Error: copy data failed\n"), s);
1922 gpgme_release (ctx);
1926 * Now, copy cleartext to the screen. NOTE - we expect that PGP
1927 * outputs utf-8 cleartext. This may not always be true, but it
1928 * seems to be a reasonable guess.
1931 if (s->flags & M_DISPLAY) {
1933 state_attach_puts (_("[-- BEGIN PGP MESSAGE --]\n\n"), s);
1934 else if (pgp_keyblock)
1935 state_attach_puts (_("[-- BEGIN PGP PUBLIC KEY BLOCK --]\n"), s);
1937 state_attach_puts (_("[-- BEGIN PGP SIGNED MESSAGE --]\n\n"), s);
1941 copy_clearsigned (armored_data, s, body_charset);
1948 fc = fgetconv_open (pgpout, "utf-8", Charset, 0);
1949 while ((c = fgetconv (fc)) != EOF) {
1951 if (c == '\n' && s->prefix)
1952 state_puts (s->prefix, s);
1954 fgetconv_close (&fc);
1957 if (s->flags & M_DISPLAY) {
1958 state_putc ('\n', s);
1960 state_attach_puts (_("[-- END PGP MESSAGE --]\n"), s);
1961 else if (pgp_keyblock)
1962 state_attach_puts (_("[-- END PGP PUBLIC KEY BLOCK --]\n"), s);
1964 state_attach_puts (_("[-- END PGP SIGNED MESSAGE --]\n"), s);
1968 safe_fclose (&pgpout);
1972 /* XXX - we may wish to recode here */
1974 state_puts (s->prefix, s);
1975 state_puts (buf, s);
1979 m->goodsig = (maybe_goodsig && have_any_sigs);
1981 if (needpass == -1) {
1982 state_attach_puts (_("[-- Error: could not find beginning"
1983 " of PGP message! --]\n\n"), s);
1986 dprint (2, (debugfile, "Leaving pgp_application_pgp handler\n"));
1990 * Implementation of `encrypted_handler'.
1993 /* MIME handler for pgp/mime encrypted messages. */
1994 void pgp_gpgme_encrypted_handler (BODY * a, STATE * s)
1996 char tempfile[_POSIX_PATH_MAX];
1999 BODY *orig_body = a;
2002 dprint (2, (debugfile, "Entering pgp_encrypted handler\n"));
2004 if (!a || a->type != TYPEAPPLICATION || !a->subtype
2005 || ascii_strcasecmp ("pgp-encrypted", a->subtype)
2006 || !a->next || a->next->type != TYPEAPPLICATION || !a->next->subtype
2007 || ascii_strcasecmp ("octet-stream", a->next->subtype)) {
2008 if (s->flags & M_DISPLAY)
2009 state_attach_puts (_("[-- Error: malformed PGP/MIME message! --]\n\n"),
2014 /* Move forward to the application/pgp-encrypted body. */
2017 mutt_mktemp (tempfile);
2018 if (!(fpout = safe_fopen (tempfile, "w+"))) {
2019 if (s->flags & M_DISPLAY)
2020 state_attach_puts (_("[-- Error: could not create temporary file! "
2025 tattach = decrypt_part (a, s, fpout, 0, &is_signed);
2027 tattach->goodsig = is_signed > 0;
2029 if (s->flags & M_DISPLAY)
2030 state_attach_puts (is_signed ?
2032 ("[-- The following data is PGP/MIME signed and encrypted --]\n\n")
2035 ("[-- The following data is PGP/MIME encrypted --]\n\n"),
2039 FILE *savefp = s->fpin;
2042 mutt_body_handler (tattach, s);
2047 * if a multipart/signed is the _only_ sub-part of a
2048 * multipart/encrypted, cache signature verification
2051 if (mutt_is_multipart_signed (tattach) && !tattach->next)
2052 orig_body->goodsig |= tattach->goodsig;
2054 if (s->flags & M_DISPLAY) {
2055 state_puts ("\n", s);
2056 state_attach_puts (is_signed ?
2058 ("[-- End of PGP/MIME signed and encrypted data --]\n")
2059 : _("[-- End of PGP/MIME encrypted data --]\n"), s);
2062 mutt_free_body (&tattach);
2066 mutt_unlink (tempfile);
2067 dprint (2, (debugfile, "Leaving pgp_encrypted handler\n"));
2070 /* Support for application/smime */
2071 void smime_gpgme_application_handler (BODY * a, STATE * s)
2073 char tempfile[_POSIX_PATH_MAX];
2079 dprint (2, (debugfile, "Entering smime_encrypted handler\n"));
2082 mutt_mktemp (tempfile);
2083 if (!(fpout = safe_fopen (tempfile, "w+"))) {
2084 if (s->flags & M_DISPLAY)
2085 state_attach_puts (_("[-- Error: could not create temporary file! "
2090 tattach = decrypt_part (a, s, fpout, 1, &is_signed);
2092 tattach->goodsig = is_signed > 0;
2094 if (s->flags & M_DISPLAY)
2095 state_attach_puts (is_signed ?
2096 _("[-- The following data is S/MIME signed --]\n\n")
2099 ("[-- The following data is S/MIME encrypted --]\n\n"),
2103 FILE *savefp = s->fpin;
2106 mutt_body_handler (tattach, s);
2111 * if a multipart/signed is the _only_ sub-part of a
2112 * multipart/encrypted, cache signature verification
2115 if (mutt_is_multipart_signed (tattach) && !tattach->next) {
2116 if (!(a->goodsig = tattach->goodsig))
2117 a->warnsig = tattach->warnsig;
2119 else if (tattach->goodsig) {
2121 a->warnsig = tattach->warnsig;
2124 if (s->flags & M_DISPLAY) {
2125 state_puts ("\n", s);
2126 state_attach_puts (is_signed ?
2127 _("[-- End of S/MIME signed data --]\n") :
2128 _("[-- End of S/MIME encrypted data --]\n"), s);
2131 mutt_free_body (&tattach);
2135 mutt_unlink (tempfile);
2136 dprint (2, (debugfile, "Leaving smime_encrypted handler\n"));
2141 * Format an entry on the CRYPT key selection menu.
2144 * %k key id %K key id of the principal key
2146 * %a algorithm %A algorithm of the princ. key
2147 * %l length %L length of the princ. key
2148 * %f flags %F flags of the princ. key
2149 * %c capabilities %C capabilities of the princ. key
2150 * %t trust/validity of the key-uid association
2152 * %[...] date of key using strftime(3)
2155 static const char *crypt_entry_fmt (char *dest,
2160 const char *ifstring,
2161 const char *elsestring,
2162 unsigned long data, format_flag flags)
2165 crypt_entry_t *entry;
2168 int optional = (flags & M_FORMAT_OPTIONAL);
2169 const char *s = NULL;
2172 entry = (crypt_entry_t *) data;
2175 /* if (isupper ((unsigned char) op)) */
2178 kflags = (key->flags /*| (pkey->flags & KEYFLAG_RESTRICTIONS)
2181 switch (ascii_tolower (op)) {
2185 char buf2[SHORT_STRING], *p;
2201 while (len > 0 && *cp != ']') {
2210 break; /* not enough space */
2220 if (do_locales && Locale)
2221 setlocale (LC_TIME, Locale);
2226 if (key->kobj->subkeys && (key->kobj->subkeys->timestamp > 0))
2227 tt = key->kobj->subkeys->timestamp;
2229 tm = localtime (&tt);
2231 strftime (buf2, sizeof (buf2), dest, tm);
2234 setlocale (LC_TIME, "C");
2236 snprintf (fmt, sizeof (fmt), "%%%ss", prefix);
2237 snprintf (dest, destlen, fmt, buf2);
2244 snprintf (fmt, sizeof (fmt), "%%%sd", prefix);
2245 snprintf (dest, destlen, fmt, entry->num);
2250 /* fixme: we need a way to distinguish between main and subkeys.
2251 Store the idx in entry? */
2252 snprintf (fmt, sizeof (fmt), "%%%ss", prefix);
2253 snprintf (dest, destlen, fmt, crypt_keyid (key));
2258 snprintf (fmt, sizeof (fmt), "%%%ss", prefix);
2259 snprintf (dest, destlen, fmt, key->uid);
2264 snprintf (fmt, sizeof (fmt), "%%%s.3s", prefix);
2265 if (key->kobj->subkeys)
2266 s = gpgme_pubkey_algo_name (key->kobj->subkeys->pubkey_algo);
2269 snprintf (dest, destlen, fmt, s);
2274 snprintf (fmt, sizeof (fmt), "%%%slu", prefix);
2275 if (key->kobj->subkeys)
2276 val = key->kobj->subkeys->length;
2279 snprintf (dest, destlen, fmt, val);
2284 snprintf (fmt, sizeof (fmt), "%%%sc", prefix);
2285 snprintf (dest, destlen, fmt, crypt_flags (kflags));
2287 else if (!(kflags & (KEYFLAG_RESTRICTIONS)))
2292 snprintf (fmt, sizeof (fmt), "%%%ss", prefix);
2293 snprintf (dest, destlen, fmt, crypt_key_abilities (kflags));
2295 else if (!(kflags & (KEYFLAG_ABILITIES)))
2299 if ((kflags & KEYFLAG_ISX509))
2302 gpgme_user_id_t uid = NULL;
2305 for (i = 0, uid = key->kobj->uids; uid && (i < key->idx);
2306 i++, uid = uid->next);
2308 switch (uid->validity) {
2309 case GPGME_VALIDITY_UNDEFINED:
2312 case GPGME_VALIDITY_NEVER:
2315 case GPGME_VALIDITY_MARGINAL:
2318 case GPGME_VALIDITY_FULL:
2321 case GPGME_VALIDITY_ULTIMATE:
2324 case GPGME_VALIDITY_UNKNOWN:
2330 snprintf (fmt, sizeof (fmt), "%%%sc", prefix);
2331 snprintf (dest, destlen, fmt, s ? *s : 'B');
2334 snprintf (fmt, sizeof (fmt), "%%%ss", prefix);
2335 snprintf (dest, destlen, fmt,
2336 gpgme_get_protocol_name (key->kobj->protocol));
2344 mutt_FormatString (dest, destlen, ifstring, mutt_attach_fmt, data, 0);
2345 else if (flags & M_FORMAT_OPTIONAL)
2346 mutt_FormatString (dest, destlen, elsestring, mutt_attach_fmt, data, 0);
2350 /* Used by the display fucntion to format a line. */
2351 static void crypt_entry (char *s, size_t l, MUTTMENU * menu, int num)
2353 crypt_key_t **key_table = (crypt_key_t **) menu->data;
2354 crypt_entry_t entry;
2356 entry.key = key_table[num];
2357 entry.num = num + 1;
2359 mutt_FormatString (s, l, NONULL (PgpEntryFormat), crypt_entry_fmt,
2360 (unsigned long) &entry, M_FORMAT_ARROWCURSOR);
2363 /* Compare two addresses and the keyid to be used for sorting. */
2364 static int _crypt_compare_address (const void *a, const void *b)
2366 crypt_key_t **s = (crypt_key_t **) a;
2367 crypt_key_t **t = (crypt_key_t **) b;
2370 if ((r = mutt_strcasecmp ((*s)->uid, (*t)->uid)))
2373 return mutt_strcasecmp (crypt_keyid (*s), crypt_keyid (*t)) > 0;
2376 static int crypt_compare_address (const void *a, const void *b)
2378 return ((PgpSortKeys & SORT_REVERSE) ? !_crypt_compare_address (a, b)
2379 : _crypt_compare_address (a, b));
2383 /* Compare two key IDs and the addresses to be used for sorting. */
2384 static int _crypt_compare_keyid (const void *a, const void *b)
2386 crypt_key_t **s = (crypt_key_t **) a;
2387 crypt_key_t **t = (crypt_key_t **) b;
2390 if ((r = mutt_strcasecmp (crypt_keyid (*s), crypt_keyid (*t))))
2393 return mutt_strcasecmp ((*s)->uid, (*t)->uid) > 0;
2396 static int crypt_compare_keyid (const void *a, const void *b)
2398 return ((PgpSortKeys & SORT_REVERSE) ? !_crypt_compare_keyid (a, b)
2399 : _crypt_compare_keyid (a, b));
2402 /* Compare 2 creation dates and the addresses. For sorting. */
2403 static int _crypt_compare_date (const void *a, const void *b)
2405 crypt_key_t **s = (crypt_key_t **) a;
2406 crypt_key_t **t = (crypt_key_t **) b;
2407 unsigned long ts = 0, tt = 0;
2409 if ((*s)->kobj->subkeys && ((*s)->kobj->subkeys->timestamp > 0))
2410 ts = (*s)->kobj->subkeys->timestamp;
2411 if ((*t)->kobj->subkeys && ((*t)->kobj->subkeys->timestamp > 0))
2412 tt = (*t)->kobj->subkeys->timestamp;
2419 return mutt_strcasecmp ((*s)->uid, (*t)->uid) > 0;
2422 static int crypt_compare_date (const void *a, const void *b)
2424 return ((PgpSortKeys & SORT_REVERSE) ? !_crypt_compare_date (a, b)
2425 : _crypt_compare_date (a, b));
2428 /* Compare two trust values, the key length, the creation dates. the
2429 addresses and the key IDs. For sorting. */
2430 static int _crypt_compare_trust (const void *a, const void *b)
2432 crypt_key_t **s = (crypt_key_t **) a;
2433 crypt_key_t **t = (crypt_key_t **) b;
2434 unsigned long ts = 0, tt = 0;
2437 if ((r = (((*s)->flags & (KEYFLAG_RESTRICTIONS))
2438 - ((*t)->flags & (KEYFLAG_RESTRICTIONS)))))
2441 if ((*s)->kobj->uids)
2442 ts = (*s)->kobj->uids->validity;
2443 if ((*t)->kobj->uids)
2444 tt = (*t)->kobj->uids->validity;
2445 if ((r = (tt - ts)))
2448 if ((*s)->kobj->subkeys)
2449 ts = (*s)->kobj->subkeys->length;
2450 if ((*t)->kobj->subkeys)
2451 tt = (*t)->kobj->subkeys->length;
2455 if ((*s)->kobj->subkeys && ((*s)->kobj->subkeys->timestamp > 0))
2456 ts = (*s)->kobj->subkeys->timestamp;
2457 if ((*t)->kobj->subkeys && ((*t)->kobj->subkeys->timestamp > 0))
2458 tt = (*t)->kobj->subkeys->timestamp;
2464 if ((r = mutt_strcasecmp ((*s)->uid, (*t)->uid)))
2466 return (mutt_strcasecmp (crypt_keyid ((*s)), crypt_keyid ((*t)))) > 0;
2469 static int crypt_compare_trust (const void *a, const void *b)
2471 return ((PgpSortKeys & SORT_REVERSE) ? !_crypt_compare_trust (a, b)
2472 : _crypt_compare_trust (a, b));
2475 /* Print the X.500 Distinguished Name part KEY from the array of parts
2477 static int print_dn_part (FILE * fp, struct dn_array_s *dn, const char *key)
2481 for (; dn->key; dn++) {
2482 if (!strcmp (dn->key, key)) {
2485 print_utf8 (fp, dn->value, mutt_strlen (dn->value));
2492 /* Print all parts of a DN in a standard sequence. */
2493 static void print_dn_parts (FILE * fp, struct dn_array_s *dn)
2495 const char *stdpart[] = {
2496 "CN", "OU", "O", "STREET", "L", "ST", "C", NULL
2498 int any = 0, any2 = 0, i;
2500 for (i = 0; stdpart[i]; i++) {
2503 any = print_dn_part (fp, dn, stdpart[i]);
2505 /* now print the rest without any specific ordering */
2506 for (; dn->key; dn++) {
2507 for (i = 0; stdpart[i]; i++) {
2508 if (!strcmp (dn->key, stdpart[i]))
2516 any = print_dn_part (fp, dn, dn->key);
2525 /* Parse an RDN; this is a helper to parse_dn(). */
2526 static const unsigned char *parse_dn_part (struct dn_array_s *array,
2527 const unsigned char *string)
2529 const unsigned char *s, *s1;
2533 /* parse attributeType */
2534 for (s = string + 1; *s && *s != '='; s++);
2536 return NULL; /* error */
2539 return NULL; /* empty key */
2540 array->key = safe_malloc (n + 1);
2541 p = (unsigned char *) array->key;
2542 memcpy (p, string, n); /* fixme: trim trailing spaces */
2546 if (*string == '#') { /* hexstring */
2548 for (s = string; hexdigitp (s); s++)
2552 return NULL; /* empty or odd number of digits */
2554 p = safe_malloc (n + 1);
2555 array->value = (char *) p;
2556 for (s1 = string; n; s1 += 2, n--)
2560 else { /* regular v3 quoted string */
2561 for (n = 0, s = string; *s; s++) {
2562 if (*s == '\\') { /* pair */
2564 if (*s == ',' || *s == '=' || *s == '+'
2565 || *s == '<' || *s == '>' || *s == '#' || *s == ';'
2566 || *s == '\\' || *s == '\"' || *s == ' ')
2568 else if (hexdigitp (s) && hexdigitp (s + 1)) {
2573 return NULL; /* invalid escape sequence */
2575 else if (*s == '\"')
2576 return NULL; /* invalid encoding */
2577 else if (*s == ',' || *s == '=' || *s == '+'
2578 || *s == '<' || *s == '>' || *s == '#' || *s == ';')
2584 p = safe_malloc (n + 1);
2585 array->value = (char *) p;
2586 for (s = string; n; s++, n--) {
2589 if (hexdigitp (s)) {
2605 /* Parse a DN and return an array-ized one. This is not a validating
2606 parser and it does not support any old-stylish syntax; gpgme is
2607 expected to return only rfc2253 compatible strings. */
2608 static struct dn_array_s *parse_dn (const unsigned char *string)
2610 struct dn_array_s *array;
2611 size_t arrayidx, arraysize;
2614 arraysize = 7; /* C,ST,L,O,OU,CN,email */
2615 array = safe_malloc ((arraysize + 1) * sizeof *array);
2618 while (*string == ' ')
2622 if (arrayidx >= arraysize) { /* mutt lacks a real safe_realoc - so we need to copy */
2623 struct dn_array_s *a2;
2626 a2 = safe_malloc ((arraysize + 1) * sizeof *array);
2627 for (i = 0; i < arrayidx; i++) {
2628 a2[i].key = array[i].key;
2629 a2[i].value = array[i].value;
2634 array[arrayidx].key = NULL;
2635 array[arrayidx].value = NULL;
2636 string = parse_dn_part (array + arrayidx, string);
2640 while (*string == ' ')
2642 if (*string && *string != ',' && *string != ';' && *string != '+')
2643 goto failure; /* invalid delimiter */
2647 array[arrayidx].key = NULL;
2648 array[arrayidx].value = NULL;
2652 for (i = 0; i < arrayidx; i++) {
2653 FREE (&array[i].key);
2654 FREE (&array[i].value);
2661 /* Print a nice representation of the USERID and make sure it is
2662 displayed in a proper way, which does mean to reorder some parts
2663 for S/MIME's DNs. USERID is a string as returned by the gpgme key
2664 functions. It is utf-8 encoded. */
2665 static void parse_and_print_user_id (FILE * fp, const char *userid)
2670 if (*userid == '<') {
2671 s = strchr (userid + 1, '>');
2673 print_utf8 (fp, userid + 1, s - userid - 1);
2675 else if (*userid == '(')
2676 fputs (_("[Can't display this user ID (unknown encoding)]"), fp);
2677 else if (!digit_or_letter ((const unsigned char *) userid))
2678 fputs (_("[Can't display this user ID (invalid encoding)]"), fp);
2680 struct dn_array_s *dn = parse_dn ((const unsigned char *) userid);
2683 fputs (_("[Can't display this user ID (invalid DN)]"), fp);
2685 print_dn_parts (fp, dn);
2686 for (i = 0; dn[i].key; i++) {
2688 FREE (&dn[i].value);
2696 KEY_CAP_CAN_ENCRYPT,
2701 static unsigned int key_check_cap (gpgme_key_t key, key_cap_t cap)
2703 gpgme_subkey_t subkey = NULL;
2704 unsigned int ret = 0;
2707 case KEY_CAP_CAN_ENCRYPT:
2708 if (!(ret = key->can_encrypt))
2709 for (subkey = key->subkeys; subkey; subkey = subkey->next)
2710 if ((ret = subkey->can_encrypt))
2713 case KEY_CAP_CAN_SIGN:
2714 if (!(ret = key->can_sign))
2715 for (subkey = key->subkeys; subkey; subkey = subkey->next)
2716 if ((ret = subkey->can_sign))
2719 case KEY_CAP_CAN_CERTIFY:
2720 if (!(ret = key->can_certify))
2721 for (subkey = key->subkeys; subkey; subkey = subkey->next)
2722 if ((ret = subkey->can_certify))
2731 /* Print verbose information about a key or certificate to FP. */
2732 static void print_key_info (gpgme_key_t key, FILE * fp)
2735 const char *s = NULL, *s2 = NULL;
2738 char shortbuf[SHORT_STRING];
2739 unsigned long aval = 0;
2743 gpgme_user_id_t uid = NULL;
2746 setlocale (LC_TIME, Locale);
2748 is_pgp = key->protocol == GPGME_PROTOCOL_OpenPGP;
2750 for (idx = 0, uid = key->uids; uid; idx++, uid = uid->next) {
2755 fprintf (fp, "%s ......: ", idx ? _(" aka") : _("Name"));
2757 fputs (_("[Invalid]"), fp);
2761 print_utf8 (fp, s, mutt_strlen (s));
2763 parse_and_print_user_id (fp, s);
2767 if (key->subkeys && (key->subkeys->timestamp > 0)) {
2768 tt = key->subkeys->timestamp;
2770 tm = localtime (&tt);
2771 #ifdef HAVE_LANGINFO_D_T_FMT
2772 strftime (shortbuf, sizeof shortbuf, nl_langinfo (D_T_FMT), tm);
2774 strftime (shortbuf, sizeof shortbuf, "%c", tm);
2776 fprintf (fp, "Valid From : %s\n", shortbuf);
2779 if (key->subkeys && (key->subkeys->expires > 0)) {
2780 tt = key->subkeys->expires;
2782 tm = localtime (&tt);
2783 #ifdef HAVE_LANGINFO_D_T_FMT
2784 strftime (shortbuf, sizeof shortbuf, nl_langinfo (D_T_FMT), tm);
2786 strftime (shortbuf, sizeof shortbuf, "%c", tm);
2788 fprintf (fp, "Valid To ..: %s\n", shortbuf);
2792 s = gpgme_pubkey_algo_name (key->subkeys->pubkey_algo);
2796 s2 = is_pgp ? "PGP" : "X.509";
2799 aval = key->subkeys->length;
2801 fprintf (fp, "Key Type ..: %s, %lu bit %s\n", s2, aval, s);
2803 fprintf (fp, "Key Usage .: ");
2806 if (key_check_cap (key, KEY_CAP_CAN_ENCRYPT)) {
2807 fprintf (fp, "%s%s", delim, _("encryption"));
2810 if (key_check_cap (key, KEY_CAP_CAN_SIGN)) {
2811 fprintf (fp, "%s%s", delim, _("signing"));
2814 if (key_check_cap (key, KEY_CAP_CAN_CERTIFY)) {
2815 fprintf (fp, "%s%s", delim, _("certification"));
2821 s = key->subkeys->fpr;
2822 fputs (_("Fingerprint: "), fp);
2823 if (is_pgp && mutt_strlen (s) == 40) {
2824 for (i = 0; *s && s[1] && s[2] && s[3] && s[4]; s += 4, i++) {
2829 putc (is_pgp ? ' ' : ':', fp);
2830 if (is_pgp && i == 4)
2835 for (i = 0; *s && s[1] && s[2]; s += 2, i++) {
2838 putc (is_pgp ? ' ' : ':', fp);
2839 if (is_pgp && i == 7)
2843 fprintf (fp, "%s\n", s);
2846 if (key->issuer_serial) {
2847 s = key->issuer_serial;
2849 fprintf (fp, "Serial-No .: 0x%s\n", s);
2852 if (key->issuer_name) {
2853 s = key->issuer_name;
2855 fprintf (fp, "Issued By .: ");
2856 parse_and_print_user_id (fp, s);
2861 /* For PGP we list all subkeys. */
2863 gpgme_subkey_t subkey = NULL;
2865 for (idx = 1, subkey = key->subkeys; subkey; idx++, subkey = subkey->next) {
2869 if (mutt_strlen (s) == 16)
2870 s += 8; /* display only the short keyID */
2871 fprintf (fp, "Subkey ....: 0x%s", s);
2872 if (subkey->revoked) {
2874 fputs (_("[Revoked]"), fp);
2876 if (subkey->invalid) {
2878 fputs (_("[Invalid]"), fp);
2880 if (subkey->expired) {
2882 fputs (_("[Expired]"), fp);
2884 if (subkey->disabled) {
2886 fputs (_("[Disabled]"), fp);
2890 if (subkey->timestamp > 0) {
2891 tt = subkey->timestamp;
2893 tm = localtime (&tt);
2894 #ifdef HAVE_LANGINFO_D_T_FMT
2895 strftime (shortbuf, sizeof shortbuf, nl_langinfo (D_T_FMT), tm);
2897 strftime (shortbuf, sizeof shortbuf, "%c", tm);
2899 fprintf (fp, "Valid From : %s\n", shortbuf);
2902 if (subkey->expires > 0) {
2903 tt = subkey->expires;
2905 tm = localtime (&tt);
2906 #ifdef HAVE_LANGINFO_D_T_FMT
2907 strftime (shortbuf, sizeof shortbuf, nl_langinfo (D_T_FMT), tm);
2909 strftime (shortbuf, sizeof shortbuf, "%c", tm);
2911 fprintf (fp, "Valid To ..: %s\n", shortbuf);
2915 s = gpgme_pubkey_algo_name (subkey->pubkey_algo);
2920 aval = subkey->length;
2924 fprintf (fp, "Key Type ..: %s, %lu bit %s\n", "PGP", aval, s);
2926 fprintf (fp, "Key Usage .: ");
2929 if (subkey->can_encrypt) {
2930 fprintf (fp, "%s%s", delim, _("encryption"));
2933 if (subkey->can_sign) {
2934 fprintf (fp, "%s%s", delim, _("signing"));
2937 if (subkey->can_certify) {
2938 fprintf (fp, "%s%s", delim, _("certification"));
2946 setlocale (LC_TIME, "C");
2950 /* Show detailed information about the selected key */
2951 static void verify_key (crypt_key_t * key)
2954 char cmd[LONG_STRING], tempfile[_POSIX_PATH_MAX];
2956 gpgme_ctx_t listctx = NULL;
2958 gpgme_key_t k = NULL;
2961 mutt_mktemp (tempfile);
2962 if (!(fp = safe_fopen (tempfile, "w"))) {
2963 mutt_perror _("Can't create temporary file");
2967 mutt_message _("Collecting data...");
2969 print_key_info (key->kobj, fp);
2971 err = gpgme_new (&listctx);
2973 fprintf (fp, "Internal error: can't create gpgme context: %s\n",
2974 gpgme_strerror (err));
2977 if ((key->flags & KEYFLAG_ISX509))
2978 gpgme_set_protocol (listctx, GPGME_PROTOCOL_CMS);
2982 while ((s = k->chain_id) && k->subkeys && strcmp (s, k->subkeys->fpr)) {
2984 err = gpgme_op_keylist_start (listctx, s, 0);
2985 gpgme_key_release (k);
2988 err = gpgme_op_keylist_next (listctx, &k);
2990 fprintf (fp, _("Error finding issuer key: %s\n"), gpgme_strerror (err));
2993 gpgme_op_keylist_end (listctx);
2995 print_key_info (k, fp);
2998 fputs (_("Error: certification chain to long - stopping here\n"), fp);
3004 gpgme_key_release (k);
3005 gpgme_release (listctx);
3007 mutt_clear_error ();
3008 snprintf (cmd, sizeof (cmd), _("Key ID: 0x%s"), crypt_keyid (key));
3009 mutt_do_pager (cmd, tempfile, 0, NULL);
3013 * Implementation of `findkeys'.
3017 /* Convert LIST into a pattern string suitable to be passed to GPGME.
3018 We need to convert spaces in an item into a '+' and '%' into
3020 static char *list_to_pattern (LIST * list)
3028 for (l = list; l; l = l->next) {
3029 for (s = l->data; *s; s++) {
3034 n++; /* delimiter or end of string */
3036 n++; /* make sure to allocate at least one byte */
3037 pattern = p = safe_calloc (1, n);
3038 for (l = list; l; l = l->next) {
3043 for (s = l->data; *s; s++) {
3049 else if (*s == '+') {
3065 /* Return a list of keys which are candidates for the selection.
3066 Select by looking at the HINTS list. */
3067 static crypt_key_t *get_candidates (LIST * hints, unsigned int app,
3070 crypt_key_t *db, *k, **kend;
3076 gpgme_user_id_t uid = NULL;
3078 pattern = list_to_pattern (hints);
3082 err = gpgme_new (&ctx);
3084 mutt_error ("gpgme_new failed: %s", gpgme_strerror (err));
3092 if ((app & APPLICATION_PGP)) {
3093 /* Its all a mess. That old GPGME expects different things
3094 depending on the protocol. For gpg we don' t need percent
3095 escaped pappert but simple strings passed in an array to the
3096 keylist_ext_start function. */
3101 for (l = hints, n = 0; l; l = l->next) {
3102 if (l->data && *l->data)
3108 patarr = safe_calloc (n + 1, sizeof *patarr);
3109 for (l = hints, n = 0; l; l = l->next) {
3110 if (l->data && *l->data)
3111 patarr[n++] = safe_strdup (l->data);
3114 err = gpgme_op_keylist_ext_start (ctx, (const char **) patarr, secret, 0);
3115 for (n = 0; patarr[n]; n++)
3119 mutt_error ("gpgme_op_keylist_start failed: %s", gpgme_strerror (err));
3120 gpgme_release (ctx);
3125 while (!(err = gpgme_op_keylist_next (ctx, &key))) {
3126 unsigned int flags = 0;
3128 if (key_check_cap (key, KEY_CAP_CAN_ENCRYPT))
3129 flags |= KEYFLAG_CANENCRYPT;
3130 if (key_check_cap (key, KEY_CAP_CAN_SIGN))
3131 flags |= KEYFLAG_CANSIGN;
3133 #if 0 /* DISABLED code */
3135 /* Bug in gpg. Capabilities are not listed for secret
3136 keys. Try to deduce them from the algorithm. */
3138 switch (key->subkeys[0].pubkey_algo) {
3140 flags |= KEYFLAG_CANENCRYPT;
3141 flags |= KEYFLAG_CANSIGN;
3143 case GPGME_PK_ELG_E:
3144 flags |= KEYFLAG_CANENCRYPT;
3147 flags |= KEYFLAG_CANSIGN;
3151 #endif /* DISABLED code */
3153 for (idx = 0, uid = key->uids; uid; idx++, uid = uid->next) {
3154 k = safe_calloc (1, sizeof *k);
3163 if (gpg_err_code (err) != GPG_ERR_EOF)
3164 mutt_error ("gpgme_op_keylist_next failed: %s", gpgme_strerror (err));
3165 gpgme_op_keylist_end (ctx);
3170 if ((app & APPLICATION_SMIME)) {
3171 /* and now look for x509 certificates */
3172 gpgme_set_protocol (ctx, GPGME_PROTOCOL_CMS);
3173 err = gpgme_op_keylist_start (ctx, pattern, 0);
3175 mutt_error ("gpgme_op_keylist_start failed: %s", gpgme_strerror (err));
3176 gpgme_release (ctx);
3181 while (!(err = gpgme_op_keylist_next (ctx, &key))) {
3182 unsigned int flags = KEYFLAG_ISX509;
3184 if (key_check_cap (key, KEY_CAP_CAN_ENCRYPT))
3185 flags |= KEYFLAG_CANENCRYPT;
3186 if (key_check_cap (key, KEY_CAP_CAN_SIGN))
3187 flags |= KEYFLAG_CANSIGN;
3189 for (idx = 0, uid = key->uids; uid; idx++, uid = uid->next) {
3190 k = safe_calloc (1, sizeof *k);
3199 if (gpg_err_code (err) != GPG_ERR_EOF)
3200 mutt_error ("gpgme_op_keylist_next failed: %s", gpgme_strerror (err));
3201 gpgme_op_keylist_end (ctx);
3204 gpgme_release (ctx);
3209 /* Add the string STR to the list HINTS. This list is later used to
3211 static LIST *crypt_add_string_to_hints (LIST * hints, const char *str)
3216 if ((scratch = safe_strdup (str)) == NULL)
3219 for (t = strtok (scratch, " ,.:\"()<>\n"); t;
3220 t = strtok (NULL, " ,.:\"()<>\n")) {
3221 if (mutt_strlen (t) > 3)
3222 hints = mutt_add_list (hints, t);
3229 /* Display a menu to select a key from the array KEYS. FORCED_VALID
3230 will be set to true on return if the user did override the the
3232 static crypt_key_t *crypt_select_key (crypt_key_t * keys,
3233 ADDRESS * p, const char *s,
3234 unsigned int app, int *forced_valid)
3237 crypt_key_t **key_table;
3240 char helpstr[SHORT_STRING], buf[LONG_STRING];
3242 int (*f) (const void *, const void *);
3243 int menu_to_use = 0;
3248 /* build the key table */
3251 for (k = keys; k; k = k->next) {
3252 if (!option (OPTPGPSHOWUNUSABLE) && (k->flags & KEYFLAG_CANTUSE)) {
3259 safe_realloc (&key_table, sizeof (crypt_key_t *) * keymax);
3265 if (!i && unusable) {
3266 mutt_error _("All matching keys are marked expired/revoked.");
3272 switch (PgpSortKeys & SORT_MASK) {
3274 f = crypt_compare_date;
3277 f = crypt_compare_keyid;
3280 f = crypt_compare_address;
3284 f = crypt_compare_trust;
3287 qsort (key_table, i, sizeof (crypt_key_t *), f);
3289 if (app & APPLICATION_PGP)
3290 menu_to_use = MENU_KEY_SELECT_PGP;
3291 else if (app & APPLICATION_SMIME)
3292 menu_to_use = MENU_KEY_SELECT_SMIME;
3295 mutt_make_help (buf, sizeof (buf), _("Exit "), menu_to_use, OP_EXIT);
3296 strcat (helpstr, buf); /* __STRCAT_CHECKED__ */
3297 mutt_make_help (buf, sizeof (buf), _("Select "), menu_to_use,
3298 OP_GENERIC_SELECT_ENTRY);
3299 strcat (helpstr, buf); /* __STRCAT_CHECKED__ */
3300 mutt_make_help (buf, sizeof (buf), _("Check key "),
3301 menu_to_use, OP_VERIFY_KEY);
3302 strcat (helpstr, buf); /* __STRCAT_CHECKED__ */
3303 mutt_make_help (buf, sizeof (buf), _("Help"), menu_to_use, OP_HELP);
3304 strcat (helpstr, buf); /* __STRCAT_CHECKED__ */
3306 menu = mutt_new_menu ();
3308 menu->make_entry = crypt_entry;
3309 menu->menu = menu_to_use;
3310 menu->help = helpstr;
3311 menu->data = key_table;
3316 if ((app & APPLICATION_PGP) && (app & APPLICATION_SMIME))
3317 ts = _("PGP and S/MIME keys matching");
3318 else if ((app & APPLICATION_PGP))
3319 ts = _("PGP keys matching");
3320 else if ((app & APPLICATION_SMIME))
3321 ts = _("S/MIME keys matching");
3323 ts = _("keys matching");
3326 snprintf (buf, sizeof (buf), _("%s <%s>."), ts, p->mailbox);
3328 snprintf (buf, sizeof (buf), _("%s \"%s\"."), ts, s);
3332 mutt_clear_error ();
3336 switch (mutt_menuLoop (menu)) {
3338 verify_key (key_table[menu->current]);
3339 menu->redraw = REDRAW_FULL;
3343 mutt_message ("%s", key_table[menu->current]->uid);
3346 case OP_GENERIC_SELECT_ENTRY:
3347 /* FIXME make error reporting more verbose - this should be
3348 easy because gpgme provides more information */
3349 if (option (OPTPGPCHECKTRUST)) {
3350 if (!crypt_key_is_valid (key_table[menu->current])) {
3351 mutt_error _("This key can't be used: "
3352 "expired/disabled/revoked.");
3357 if (option (OPTPGPCHECKTRUST) &&
3358 (!crypt_id_is_valid (key_table[menu->current])
3359 || !crypt_id_is_strong (key_table[menu->current]))) {
3361 char buff[LONG_STRING];
3363 if (key_table[menu->current]->flags & KEYFLAG_CANTUSE)
3364 s = N_("ID is expired/disabled/revoked.");
3366 gpgme_validity_t val = GPGME_VALIDITY_UNKNOWN;
3367 gpgme_user_id_t uid = NULL;
3372 uid = key_table[menu->current]->kobj->uids;
3373 for (j = 0; (j < key_table[menu->current]->idx) && uid;
3374 j++, uid = uid->next);
3376 val = uid->validity;
3379 case GPGME_VALIDITY_UNKNOWN:
3380 case GPGME_VALIDITY_UNDEFINED:
3381 warn_s = N_("ID has undefined validity.");
3383 case GPGME_VALIDITY_NEVER:
3384 warn_s = N_("ID is not valid.");
3386 case GPGME_VALIDITY_MARGINAL:
3387 warn_s = N_("ID is only marginally valid.");
3389 case GPGME_VALIDITY_FULL:
3390 case GPGME_VALIDITY_ULTIMATE:
3394 snprintf (buff, sizeof (buff),
3395 _("%s Do you really want to use the key?"), _(warn_s));
3397 if (mutt_yesorno (buff, 0) != 1) {
3398 mutt_clear_error ();
3405 k = crypt_copy_key (key_table[menu->current]);
3416 mutt_menuDestroy (&menu);
3419 set_option (OPTNEEDREDRAW);
3424 static crypt_key_t *crypt_getkeybyaddr (ADDRESS * a, short abilities,
3425 unsigned int app, int *forced_valid)
3433 int this_key_has_strong;
3434 int this_key_has_weak;
3435 int this_key_has_invalid;
3438 crypt_key_t *keys, *k;
3439 crypt_key_t *the_valid_key = NULL;
3440 crypt_key_t *matches = NULL;
3441 crypt_key_t **matches_endp = &matches;
3445 if (a && a->mailbox)
3446 hints = crypt_add_string_to_hints (hints, a->mailbox);
3447 if (a && a->personal)
3448 hints = crypt_add_string_to_hints (hints, a->personal);
3450 mutt_message (_("Looking for keys matching \"%s\"..."), a->mailbox);
3451 keys = get_candidates (hints, app, (abilities & KEYFLAG_CANSIGN));
3453 mutt_free_list (&hints);
3458 dprint (5, (debugfile, "crypt_getkeybyaddr: looking for %s <%s>.",
3459 a->personal, a->mailbox));
3461 for (k = keys; k; k = k->next) {
3462 dprint (5, (debugfile, " looking at key: %s `%.15s'\n",
3463 crypt_keyid (k), k->uid));
3465 if (abilities && !(k->flags & abilities)) {
3466 dprint (5, (debugfile, " insufficient abilities: Has %x, want %x\n",
3467 k->flags, abilities));
3471 this_key_has_weak = 0; /* weak but valid match */
3472 this_key_has_invalid = 0; /* invalid match */
3473 this_key_has_strong = 0; /* strong and valid match */
3474 match = 0; /* any match */
3476 r = rfc822_parse_adrlist (NULL, k->uid);
3477 for (p = r; p; p = p->next) {
3478 int validity = crypt_id_matches_addr (a, p, k);
3480 if (validity & CRYPT_KV_MATCH) /* something matches */
3483 /* is this key a strong candidate? */
3484 if ((validity & CRYPT_KV_VALID)
3485 && (validity & CRYPT_KV_STRONGID)
3486 && (validity & CRYPT_KV_ADDR)) {
3487 if (the_valid_key && the_valid_key != k)
3490 this_key_has_strong = 1;
3492 else if ((validity & CRYPT_KV_MATCH)
3493 && !(validity & CRYPT_KV_VALID))
3494 this_key_has_invalid = 1;
3495 else if ((validity & CRYPT_KV_MATCH)
3496 && (!(validity & CRYPT_KV_STRONGID)
3497 || !(validity & CRYPT_KV_ADDR)))
3498 this_key_has_weak = 1;
3500 rfc822_free_address (&r);
3505 if (!this_key_has_strong && this_key_has_invalid)
3507 if (!this_key_has_strong && this_key_has_weak)
3510 *matches_endp = tmp = crypt_copy_key (k);
3511 matches_endp = &tmp->next;
3512 the_valid_key = tmp;
3516 crypt_free_key (&keys);
3519 if (the_valid_key && !multi && !weak
3520 && !(invalid && option (OPTPGPSHOWUNUSABLE))) {
3522 * There was precisely one strong match on a valid ID, there
3523 * were no valid keys with weak matches, and we aren't
3524 * interested in seeing invalid keys.
3526 * Proceed without asking the user.
3528 k = crypt_copy_key (the_valid_key);
3532 * Else: Ask the user.
3534 k = crypt_select_key (matches, a, NULL, app, forced_valid);
3536 crypt_free_key (&matches);
3545 static crypt_key_t *crypt_getkeybystr (char *p, short abilities,
3546 unsigned int app, int *forced_valid)
3550 crypt_key_t *matches = NULL;
3551 crypt_key_t **matches_endp = &matches;
3555 mutt_message (_("Looking for keys matching \"%s\"..."), p);
3559 hints = crypt_add_string_to_hints (hints, p);
3560 keys = get_candidates (hints, app, (abilities & KEYFLAG_CANSIGN));
3561 mutt_free_list (&hints);
3566 for (k = keys; k; k = k->next) {
3567 if (abilities && !(k->flags & abilities))
3571 dprint (5, (debugfile, "crypt_getkeybystr: matching \"%s\" against "
3572 "key %s, \"%s\": ", p, crypt_keyid (k), k->uid));
3574 if (!*p || !mutt_strcasecmp (p, crypt_keyid (k))
3575 || (!mutt_strncasecmp (p, "0x", 2)
3576 && !mutt_strcasecmp (p + 2, crypt_keyid (k)))
3577 || (option (OPTPGPLONGIDS)
3578 && !mutt_strncasecmp (p, "0x", 2)
3579 && !mutt_strcasecmp (p + 2, crypt_keyid (k) + 8))
3580 || mutt_stristr (k->uid, p)) {
3583 dprint (5, (debugfile, "match.\n"));
3585 *matches_endp = tmp = crypt_copy_key (k);
3586 matches_endp = &tmp->next;
3590 crypt_free_key (&keys);
3593 k = crypt_select_key (matches, NULL, p, app, forced_valid);
3594 crypt_free_key (&matches);
3601 /* Display TAG as a prompt to ask for a key. If WHATFOR is not null
3602 use it as default and store it under that label as the next
3603 default. ABILITIES describe the required key abilities (sign,
3604 encrypt) and APP the type of the requested key; ether S/MIME or
3605 PGP. Return a copy of the key or NULL if not found. */
3606 static crypt_key_t *crypt_ask_for_key (char *tag,
3609 unsigned int app, int *forced_valid)
3612 char resp[SHORT_STRING];
3613 struct crypt_cache *l = NULL;
3617 forced_valid = &dummy;
3619 mutt_clear_error ();
3625 for (l = id_defaults; l; l = l->next)
3626 if (!mutt_strcasecmp (whatfor, l->what)) {
3627 strfcpy (resp, NONULL (l->dflt), sizeof (resp));
3635 if (mutt_get_field (tag, resp, sizeof (resp), M_CLEAR) != 0)
3640 mutt_str_replace (&l->dflt, resp);
3642 l = safe_malloc (sizeof (struct crypt_cache));
3643 l->next = id_defaults;
3645 l->what = safe_strdup (whatfor);
3646 l->dflt = safe_strdup (resp);
3650 if ((key = crypt_getkeybystr (resp, abilities, app, forced_valid)))
3658 /* This routine attempts to find the keyids of the recipients of a
3659 message. It returns NULL if any of the keys can not be found. */
3660 static char *find_keys (ADDRESS * to, ADDRESS * cc, ADDRESS * bcc,
3663 char *keyID, *keylist = NULL, *t;
3664 size_t keylist_size = 0;
3665 size_t keylist_used = 0;
3666 ADDRESS *tmp = NULL, *addr = NULL;
3667 ADDRESS **last = &tmp;
3670 crypt_key_t *k_info, *key;
3671 const char *fqdn = mutt_fqdn (1);
3674 *r_application = APPLICATION_PGP | APPLICATION_SMIME;
3677 for (i = 0; i < 3; i++) {
3692 *last = rfc822_cpy_adr (p);
3694 last = &((*last)->next);
3698 rfc822_qualify (tmp, fqdn);
3700 tmp = mutt_remove_duplicates (tmp);
3702 for (p = tmp; p; p = p->next) {
3703 char buf[LONG_STRING];
3704 int forced_valid = 0;
3709 if ((keyID = mutt_crypt_hook (p)) != NULL) {
3712 snprintf (buf, sizeof (buf), _("Use keyID = \"%s\" for %s?"),
3714 if ((r = mutt_yesorno (buf, M_YES)) == M_YES) {
3715 /* check for e-mail address */
3716 if ((t = strchr (keyID, '@')) &&
3717 (addr = rfc822_parse_adrlist (NULL, keyID))) {
3719 rfc822_qualify (addr, fqdn);
3724 k_info = crypt_getkeybystr (keyID, KEYFLAG_CANENCRYPT,
3725 *r_application, &forced_valid);
3727 k_info = crypt_getkeybystr (keyID, KEYFLAG_CANENCRYPT,
3728 app, &forced_valid);
3734 rfc822_free_address (&tmp);
3735 rfc822_free_address (&addr);
3741 && (k_info = crypt_getkeybyaddr (q, KEYFLAG_CANENCRYPT,
3742 app, &forced_valid)) == NULL) {
3743 snprintf (buf, sizeof (buf), _("Enter keyID for %s: "), q->mailbox);
3745 if ((key = crypt_ask_for_key (buf, q->mailbox, KEYFLAG_CANENCRYPT,
3751 &forced_valid)) == NULL) {
3753 rfc822_free_address (&tmp);
3754 rfc822_free_address (&addr);
3762 const char *s = crypt_fpr (key);
3765 if (key->flags & KEYFLAG_ISX509)
3766 *r_application &= ~APPLICATION_PGP;
3767 if (!(key->flags & KEYFLAG_ISX509))
3768 *r_application &= ~APPLICATION_SMIME;
3771 keylist_size += mutt_strlen (s) + 4 + 1;
3772 safe_realloc (&keylist, keylist_size);
3773 sprintf (keylist + keylist_used, "%s0x%s%s", /* __SPRINTF_CHECKED__ */
3774 keylist_used ? " " : "", s, forced_valid ? "!" : "");
3776 keylist_used = mutt_strlen (keylist);
3778 crypt_free_key (&key);
3779 rfc822_free_address (&addr);
3781 rfc822_free_address (&tmp);
3785 char *pgp_gpgme_findkeys (ADDRESS * to, ADDRESS * cc, ADDRESS * bcc)
3787 return find_keys (to, cc, bcc, APPLICATION_PGP);
3790 char *smime_gpgme_findkeys (ADDRESS * to, ADDRESS * cc, ADDRESS * bcc)
3792 return find_keys (to, cc, bcc, APPLICATION_SMIME);
3796 * Implementation of `init'.
3799 /* Initialization. */
3800 static void init_gpgme (void)
3802 /* Make sure that gpg-agent is running. */
3803 if (!getenv ("GPG_AGENT_INFO")) {
3804 mutt_error ("\nUsing GPGME backend, although no gpg-agent is running");
3805 if (mutt_any_key_to_continue (NULL) == -1)
3810 void pgp_gpgme_init (void)
3815 void smime_gpgme_init (void)
3819 static int gpgme_send_menu (HEADER * msg, int *redraw, int is_smime)
3822 char input_signas[SHORT_STRING];
3825 if (msg->security & APPLICATION_PGP)
3827 else if (msg->security & APPLICATION_SMIME)
3832 mutt_multi_choice (_
3833 ("S/MIME (e)ncrypt, (s)ign, sign (a)s, (b)oth, (t)oggle or (f)orget it?"),
3837 mutt_multi_choice (_
3838 ("PGP (e)ncrypt, (s)ign, sign (a)s, (b)oth, (t)oggle or (f)orget it?"),
3842 case 1: /* (e)ncrypt */
3843 msg->security |= (is_smime ? SMIMEENCRYPT : PGPENCRYPT);
3846 case 2: /* (s)ign */
3847 msg->security |= (is_smime ? SMIMESIGN : PGPSIGN);
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 mutt_str_replace (is_smime ? &SmimeDefaultKey : &PgpSignAs,
3858 crypt_free_key (&p);
3860 msg->security |= (is_smime ? SMIMESIGN : PGPSIGN);
3863 msg->security &= (is_smime ? ~SMIMESIGN : ~PGPSIGN);
3865 *redraw = REDRAW_FULL;
3868 case 4: /* (b)oth */
3870 (is_smime ? (SMIMEENCRYPT | SMIMESIGN) : (PGPENCRYPT | PGPSIGN));
3873 case 5: /* (t)oggle */
3874 is_smime = !is_smime;
3877 case 6: /* (f)orget it */
3883 else if (is_smime) {
3884 msg->security &= ~APPLICATION_PGP;
3885 msg->security |= APPLICATION_SMIME;
3888 msg->security &= ~APPLICATION_SMIME;
3889 msg->security |= APPLICATION_PGP;
3892 return (msg->security);
3895 int pgp_gpgme_send_menu (HEADER * msg, int *redraw)
3897 return gpgme_send_menu (msg, redraw, 0);
3900 int smime_gpgme_send_menu (HEADER * msg, int *redraw)
3902 return gpgme_send_menu (msg, redraw, 1);
3905 static int verify_sender (HEADER * h, gpgme_protocol_t protocol)
3907 ADDRESS *sender = NULL;
3908 unsigned int ret = 1;
3911 h->env->from = mutt_expand_aliases (h->env->from);
3912 sender = h->env->from;
3914 else if (h->env->sender) {
3915 h->env->sender = mutt_expand_aliases (h->env->sender);
3916 sender = h->env->sender;
3920 if (signature_key) {
3921 gpgme_key_t key = signature_key;
3922 gpgme_user_id_t uid = NULL;
3923 int sender_length = 0;
3926 sender_length = mutt_strlen (sender->mailbox);
3927 for (uid = key->uids; uid && ret; uid = uid->next) {
3928 uid_length = mutt_strlen (uid->email);
3929 if (1 && (uid->email[0] == '<')
3930 && (uid->email[uid_length - 1] == '>')
3931 && (uid_length == sender_length + 2)
3932 && (!strncmp (uid->email + 1, sender->mailbox, sender_length)))
3937 mutt_any_key_to_continue ("Failed to verify sender");
3940 mutt_any_key_to_continue ("Failed to figure out sender");
3942 if (signature_key) {
3943 gpgme_key_release (signature_key);
3944 signature_key = NULL;
3950 int smime_gpgme_verify_sender (HEADER * h)
3952 return verify_sender (h, GPGME_PROTOCOL_CMS);