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"
31 #include "recvattach.h"
37 #include "lib/debug.h"
52 #ifdef HAVE_LANGINFO_D_T_FMT
56 #ifdef HAVE_SYS_TIME_H
57 # include <sys/time.h>
60 #ifdef HAVE_SYS_RESOURCE_H
61 # include <sys/resource.h>
67 #define digitp(p) (*(p) >= '0' && *(p) <= '9')
68 #define hexdigitp(a) (digitp (a) \
69 || (*(a) >= 'A' && *(a) <= 'F') \
70 || (*(a) >= 'a' && *(a) <= 'f'))
71 #define xtoi_1(p) (*(p) <= '9'? (*(p)- '0'): \
72 *(p) <= 'F'? (*(p)-'A'+10):(*(p)-'a'+10))
73 #define xtoi_2(p) ((xtoi_1(p) * 16) + xtoi_1((p)+1))
75 /* Values used for comparing addresses. */
76 #define CRYPT_KV_VALID 1
77 #define CRYPT_KV_ADDR 2
78 #define CRYPT_KV_STRING 4
79 #define CRYPT_KV_STRONGID 8
80 #define CRYPT_KV_MATCH (CRYPT_KV_ADDR|CRYPT_KV_STRING)
89 struct crypt_cache *next;
97 /* We work based on user IDs, getting from a user ID to the key is
98 check and does not need any memory (gpgme uses reference counting). */
99 typedef struct crypt_keyinfo {
100 struct crypt_keyinfo *next;
102 int idx; /* and the user ID at this index */
103 const char *uid; /* and for convenience point to this user ID */
104 unsigned int flags; /* global and per uid flags (for convenience) */
107 typedef struct crypt_entry {
113 static struct crypt_cache *id_defaults = NULL;
114 static gpgme_key_t signature_key = NULL;
117 * General helper functions.
120 /* return true when S points to a didgit or letter. */
121 static int digit_or_letter (const unsigned char *s)
123 return ((*s >= '0' && *s <= '9')
124 || (*s >= 'A' && *s <= 'Z')
125 || (*s >= 'a' && *s <= 'z'));
129 /* Print the utf-8 encoded string BUF of length LEN bytes to stream
130 FP. Convert the character set. */
131 static void print_utf8 (FILE * fp, const char *buf, size_t len)
135 tstr = mem_malloc (len + 1);
136 memcpy (tstr, buf, len);
138 mutt_convert_string (&tstr, "utf-8", Charset, M_ICONV_HOOK_FROM);
148 /* Return the keyID for the key K. Note that this string is valid as
149 long as K is valid */
150 static const char *crypt_keyid (crypt_key_t * k)
152 const char *s = "????????";
154 if (k->kobj && k->kobj->subkeys) {
155 s = k->kobj->subkeys->keyid;
156 if ((!option (OPTPGPLONGIDS)) && (str_len (s) == 16))
157 /* Return only the short keyID. */
164 /* Return the hexstring fingerprint from the key K. */
165 static const char *crypt_fpr (crypt_key_t * k)
169 if (k->kobj && k->kobj->subkeys)
170 s = k->kobj->subkeys->fpr;
175 /* Parse FLAGS and return a statically allocated(!) string with them. */
176 static char *crypt_key_abilities (int flags)
180 if (!(flags & KEYFLAG_CANENCRYPT))
182 else if (flags & KEYFLAG_PREFER_SIGNING)
187 if (!(flags & KEYFLAG_CANSIGN))
189 else if (flags & KEYFLAG_PREFER_ENCRYPTION)
199 /* Parse FLAGS and return a character describing the most important flag. */
200 static char crypt_flags (int flags)
202 if (flags & KEYFLAG_REVOKED)
204 else if (flags & KEYFLAG_EXPIRED)
206 else if (flags & KEYFLAG_DISABLED)
208 else if (flags & KEYFLAG_CRITICAL)
214 /* Return a copy of KEY. */
215 static crypt_key_t *crypt_copy_key (crypt_key_t * key)
219 k = mem_calloc (1, sizeof *k);
221 gpgme_key_ref (key->kobj);
224 k->flags = key->flags;
229 /* Release all the keys at the address of KEYLIST and set the address
231 static void crypt_free_key (crypt_key_t ** keylist)
234 crypt_key_t *k = (*keylist)->next;
241 /* Return trute when key K is valid. */
242 static int crypt_key_is_valid (crypt_key_t * k)
244 if (k->flags & KEYFLAG_CANTUSE)
249 /* Return true whe validity of KEY is sufficient. */
250 static int crypt_id_is_strong (crypt_key_t * key)
252 gpgme_validity_t val = GPGME_VALIDITY_UNKNOWN;
253 gpgme_user_id_t uid = NULL;
254 unsigned int is_strong = 0;
257 if ((key->flags & KEYFLAG_ISX509))
260 for (i = 0, uid = key->kobj->uids; (i < key->idx) && uid;
261 i++, uid = uid->next);
266 case GPGME_VALIDITY_UNKNOWN:
267 case GPGME_VALIDITY_UNDEFINED:
268 case GPGME_VALIDITY_NEVER:
269 case GPGME_VALIDITY_MARGINAL:
273 case GPGME_VALIDITY_FULL:
274 case GPGME_VALIDITY_ULTIMATE:
282 /* Return true when the KEY is valid, i.e. not marked as unusable. */
283 static int crypt_id_is_valid (crypt_key_t * key)
285 return !(key->flags & KEYFLAG_CANTUSE);
288 /* Return a bit vector describing how well the addresses ADDR and
289 U_ADDR match and whether KEY is valid. */
290 static int crypt_id_matches_addr (ADDRESS * addr, ADDRESS * u_addr,
295 if (crypt_id_is_valid (key))
296 rv |= CRYPT_KV_VALID;
298 if (crypt_id_is_strong (key))
299 rv |= CRYPT_KV_STRONGID;
301 if (addr->mailbox && u_addr->mailbox
302 && str_casecmp (addr->mailbox, u_addr->mailbox) == 0)
305 if (addr->personal && u_addr->personal
306 && str_casecmp (addr->personal, u_addr->personal) == 0)
307 rv |= CRYPT_KV_STRING;
314 * GPGME convenient functions.
317 /* Create a new gpgme context and return it. With FOR_SMIME set to
318 true, the protocol of the context is set to CMS. */
319 static gpgme_ctx_t create_gpgme_context (int for_smime)
324 err = gpgme_new (&ctx);
326 mutt_error (_("error creating gpgme context: %s\n"), gpgme_strerror (err));
332 err = gpgme_set_protocol (ctx, GPGME_PROTOCOL_CMS);
334 mutt_error (_("error enabling CMS protocol: %s\n"), gpgme_strerror (err));
343 /* Create a new gpgme data object. This is a wrapper to die on
345 static gpgme_data_t create_gpgme_data (void)
350 err = gpgme_data_new (&data);
352 mutt_error (_("error creating gpgme data object: %s\n"),
353 gpgme_strerror (err));
360 /* Create a new GPGME Data object from the mail body A. With CONVERT
361 passed as true, the lines are converted to CR,LF if required.
362 Return NULL on error or the gpgme_data_t object on success. */
363 static gpgme_data_t body_to_data_object (BODY * a, int convert)
365 char tempfile[_POSIX_PATH_MAX];
370 mutt_mktemp (tempfile);
371 fptmp = safe_fopen (tempfile, "w+");
373 mutt_perror (tempfile);
377 mutt_write_mime_header (a, fptmp);
379 mutt_write_mime_body (a, fptmp);
383 unsigned char buf[1];
385 data = create_gpgme_data ();
387 while ((c = fgetc (fptmp)) != EOF) {
391 if (c == '\n' && !hadcr) {
393 gpgme_data_write (data, buf, 1);
398 /* FIXME: This is quite suboptimal */
400 gpgme_data_write (data, buf, 1);
403 gpgme_data_seek (data, 0, SEEK_SET);
407 err = gpgme_data_new_from_file (&data, tempfile, 1);
411 mutt_error (_("error allocating data object: %s\n"), gpgme_strerror (err));
418 /* Create a GPGME data object from the stream FP but limit the object
419 to LENGTH bytes starting at OFFSET bytes from the beginning of the
421 static gpgme_data_t file_to_data_object (FILE * fp, long offset, long length)
426 err = gpgme_data_new_from_filepart (&data, NULL, fp, offset, length);
428 mutt_error (_("error allocating data object: %s\n"), gpgme_strerror (err));
435 /* Write a GPGME data object to the stream FP. */
436 static int data_object_to_stream (gpgme_data_t data, FILE * fp)
442 err = ((gpgme_data_seek (data, 0, SEEK_SET) == -1)
443 ? gpgme_error_from_errno (errno) : 0);
445 mutt_error (_("error rewinding data object: %s\n"), gpgme_strerror (err));
449 while ((nread = gpgme_data_read (data, buf, sizeof (buf)))) {
450 /* fixme: we are not really converting CRLF to LF but just
451 skipping CR. Doing it correctly needs a more complex logic */
452 for (p = buf; nread; p++, nread--) {
458 mutt_perror ("[tempfile]");
463 mutt_error (_("error reading data object: %s\n"), strerror (errno));
469 /* Copy a data object to a newly created temporay file and return that
470 filename. Caller must free. With RET_FP not NULL, don't close the
471 stream but return it there. */
472 static char *data_object_to_tempfile (gpgme_data_t data, FILE ** ret_fp)
475 char tempfile[_POSIX_PATH_MAX];
479 mutt_mktemp (tempfile);
480 fp = safe_fopen (tempfile, "w+");
482 mutt_perror (tempfile);
486 err = ((gpgme_data_seek (data, 0, SEEK_SET) == -1)
487 ? gpgme_error_from_errno (errno) : 0);
491 while ((nread = gpgme_data_read (data, buf, sizeof (buf)))) {
492 if (fwrite (buf, nread, 1, fp) != 1) {
493 mutt_perror (tempfile);
505 mutt_error (_("error reading data object: %s\n"), gpgme_strerror (err));
512 return str_dup (tempfile);
516 /* Create a GpgmeRecipientSet from the keys in the string KEYLIST.
517 The keys must be space delimited. */
518 static gpgme_key_t *create_recipient_set (const char *keylist,
519 gpgme_protocol_t protocol)
525 gpgme_key_t *rset = NULL;
526 unsigned int rset_n = 0;
527 gpgme_key_t key = NULL;
528 gpgme_ctx_t context = NULL;
530 err = gpgme_new (&context);
532 err = gpgme_set_protocol (context, protocol);
539 for (i = 0; *s && *s != ' ' && i < sizeof (buf) - 1;)
543 if (i > 1 && buf[i - 1] == '!') {
544 /* The user selected to override the valididy of that
548 err = gpgme_get_key (context, buf, &key, 0);
550 key->uids->validity = GPGME_VALIDITY_FULL;
554 err = gpgme_get_key (context, buf, &key, 0);
557 mem_realloc (&rset, sizeof (*rset) * (rset_n + 1));
558 rset[rset_n++] = key;
561 mutt_error (_("error adding recipient `%s': %s\n"),
562 buf, gpgme_strerror (err));
570 /* NULL terminate. */
571 mem_realloc (&rset, sizeof (*rset) * (rset_n + 1));
572 rset[rset_n++] = NULL;
575 gpgme_release (context);
581 /* Make sure that the correct signer is set. Returns 0 on success. */
582 static int set_signer (gpgme_ctx_t ctx, int for_smime)
584 char *signid = for_smime ? SmimeDefaultKey : PgpSignAs;
587 gpgme_key_t key, key2;
589 if (!signid || !*signid)
592 listctx = create_gpgme_context (for_smime);
593 err = gpgme_op_keylist_start (listctx, signid, 1);
595 err = gpgme_op_keylist_next (listctx, &key);
597 gpgme_release (listctx);
598 mutt_error (_("secret key `%s' not found: %s\n"),
599 signid, gpgme_strerror (err));
602 err = gpgme_op_keylist_next (listctx, &key2);
604 gpgme_key_release (key);
605 gpgme_key_release (key2);
606 gpgme_release (listctx);
607 mutt_error (_("ambiguous specification of secret key `%s'\n"), signid);
610 gpgme_op_keylist_end (listctx);
611 gpgme_release (listctx);
613 gpgme_signers_clear (ctx);
614 err = gpgme_signers_add (ctx, key);
615 gpgme_key_release (key);
617 mutt_error (_("error setting secret key `%s': %s\n"),
618 signid, gpgme_strerror (err));
625 /* Encrypt the gpgme data object PLAINTEXT to the recipients in RSET
626 and return an allocated filename to a temporary file containing the
627 enciphered text. With USE_SMIME set to true, the smime backend is
628 used. With COMBINED_SIGNED a PGP message is signed and
629 encrypted. Returns NULL in case of error */
630 static char *encrypt_gpgme_object (gpgme_data_t plaintext, gpgme_key_t * rset,
631 int use_smime, int combined_signed)
635 gpgme_data_t ciphertext;
638 ctx = create_gpgme_context (use_smime);
640 gpgme_set_armor (ctx, 1);
642 ciphertext = create_gpgme_data ();
644 if (combined_signed) {
645 if (set_signer (ctx, use_smime)) {
646 gpgme_data_release (ciphertext);
650 err = gpgme_op_encrypt_sign (ctx, rset, GPGME_ENCRYPT_ALWAYS_TRUST,
651 plaintext, ciphertext);
654 err = gpgme_op_encrypt (ctx, rset, GPGME_ENCRYPT_ALWAYS_TRUST,
655 plaintext, ciphertext);
656 mutt_need_hard_redraw ();
658 mutt_error (_("error encrypting data: %s\n"), gpgme_strerror (err));
659 gpgme_data_release (ciphertext);
666 outfile = data_object_to_tempfile (ciphertext, NULL);
667 gpgme_data_release (ciphertext);
671 /* Find the "micalg" parameter from the last Gpgme operation on
672 context CTX. It is expected that this operation was a sign
673 operation. Return the algorithm name as a C string in buffer BUF
674 which must have been allocated by the caller with size BUFLEN.
675 Returns 0 on success or -1 in case of an error. The return string
676 is truncted to BUFLEN - 1. */
677 static int get_micalg (gpgme_ctx_t ctx, char *buf, size_t buflen)
679 gpgme_sign_result_t result = NULL;
680 const char *algorithm_name = NULL;
686 result = gpgme_op_sign_result (ctx);
688 algorithm_name = gpgme_hash_algo_name (result->signatures->hash_algo);
689 if (algorithm_name) {
690 strncpy (buf, algorithm_name, buflen - 1);
695 return *buf ? 0 : -1;
698 static void print_time (time_t t, STATE * s)
702 setlocale (LC_TIME, "");
703 #ifdef HAVE_LANGINFO_D_T_FMT
704 strftime (p, sizeof (p), nl_langinfo (D_T_FMT), localtime (&t));
706 strftime (p, sizeof (p), "%c", localtime (&t));
708 setlocale (LC_TIME, "C");
709 state_attach_puts (p, s);
713 * Implementation of `sign_message'.
716 /* Sign the MESSAGE in body A either using OpenPGP or S/MIME when
717 USE_SMIME is passed as true. Returns the new body or NULL on
719 static BODY *sign_message (BODY * a, int use_smime)
726 gpgme_data_t message, signature;
728 convert_to_7bit (a); /* Signed data _must_ be in 7-bit format. */
730 message = body_to_data_object (a, 1);
733 signature = create_gpgme_data ();
735 ctx = create_gpgme_context (use_smime);
737 gpgme_set_armor (ctx, 1);
739 if (set_signer (ctx, use_smime)) {
740 gpgme_data_release (signature);
745 err = gpgme_op_sign (ctx, message, signature, GPGME_SIG_MODE_DETACH);
746 mutt_need_hard_redraw ();
747 gpgme_data_release (message);
749 gpgme_data_release (signature);
751 mutt_error (_("error signing data: %s\n"), gpgme_strerror (err));
755 sigfile = data_object_to_tempfile (signature, NULL);
756 gpgme_data_release (signature);
762 t = mutt_new_body ();
763 t->type = TYPEMULTIPART;
764 t->subtype = str_dup ("signed");
765 t->encoding = ENC7BIT;
767 t->disposition = DISPINLINE;
769 mutt_generate_boundary (&t->parameter);
770 mutt_set_parameter ("protocol",
771 use_smime ? "application/pkcs7-signature"
772 : "application/pgp-signature", &t->parameter);
773 /* Get the micalg from gpgme. Old gpgme versions don't support this
774 for S/MIME so we assume sha-1 in this case. */
775 if (!get_micalg (ctx, buf, sizeof buf))
776 mutt_set_parameter ("micalg", buf, &t->parameter);
778 mutt_set_parameter ("micalg", "sha1", &t->parameter);
784 t->parts->next = mutt_new_body ();
786 t->type = TYPEAPPLICATION;
788 t->subtype = str_dup ("pkcs7-signature");
789 mutt_set_parameter ("name", "smime.p7s", &t->parameter);
790 t->encoding = ENCBASE64;
792 t->disposition = DISPATTACH;
793 t->d_filename = str_dup ("smime.p7s");
796 t->subtype = str_dup ("pgp-signature");
798 t->disposition = DISPINLINE;
799 t->encoding = ENC7BIT;
801 t->filename = sigfile;
802 t->unlink = 1; /* ok to remove this file after sending. */
808 BODY *pgp_gpgme_sign_message (BODY * a)
810 return sign_message (a, 0);
813 BODY *smime_gpgme_sign_message (BODY * a)
815 return sign_message (a, 1);
819 * Implementation of `encrypt_message'.
822 /* Encrypt the mail body A to all keys given as space separated keyids
823 or fingerprints in KEYLIST and return the encrypted body. */
824 BODY *pgp_gpgme_encrypt_message (BODY * a, char *keylist, int sign)
826 char *outfile = NULL;
828 gpgme_key_t *rset = NULL;
829 gpgme_data_t plaintext;
831 rset = create_recipient_set (keylist, GPGME_PROTOCOL_OpenPGP);
837 plaintext = body_to_data_object (a, 0);
843 outfile = encrypt_gpgme_object (plaintext, rset, 0, sign);
844 gpgme_data_release (plaintext);
849 t = mutt_new_body ();
850 t->type = TYPEMULTIPART;
851 t->subtype = str_dup ("encrypted");
852 t->encoding = ENC7BIT;
854 t->disposition = DISPINLINE;
856 mutt_generate_boundary (&t->parameter);
857 mutt_set_parameter ("protocol", "application/pgp-encrypted", &t->parameter);
859 t->parts = mutt_new_body ();
860 t->parts->type = TYPEAPPLICATION;
861 t->parts->subtype = str_dup ("pgp-encrypted");
862 t->parts->encoding = ENC7BIT;
864 t->parts->next = mutt_new_body ();
865 t->parts->next->type = TYPEAPPLICATION;
866 t->parts->next->subtype = str_dup ("octet-stream");
867 t->parts->next->encoding = ENC7BIT;
868 t->parts->next->filename = outfile;
869 t->parts->next->use_disp = 1;
870 t->parts->next->disposition = DISPINLINE;
871 t->parts->next->unlink = 1; /* delete after sending the message */
872 t->parts->next->d_filename = str_dup ("msg.asc"); /* non pgp/mime
879 * Implementation of `smime_build_smime_entity'.
882 /* Encrypt the mail body A to all keys given as space separated
883 fingerprints in KEYLIST and return the S/MIME encrypted body. */
884 BODY *smime_gpgme_build_smime_entity (BODY * a, char *keylist)
886 char *outfile = NULL;
888 gpgme_key_t *rset = NULL;
889 gpgme_data_t plaintext;
891 rset = create_recipient_set (keylist, GPGME_PROTOCOL_CMS);
895 plaintext = body_to_data_object (a, 0);
901 outfile = encrypt_gpgme_object (plaintext, rset, 1, 0);
902 gpgme_data_release (plaintext);
907 t = mutt_new_body ();
908 t->type = TYPEAPPLICATION;
909 t->subtype = str_dup ("pkcs7-mime");
910 mutt_set_parameter ("name", "smime.p7m", &t->parameter);
911 mutt_set_parameter ("smime-type", "enveloped-data", &t->parameter);
912 t->encoding = ENCBASE64; /* The output of OpenSSL SHOULD be binary */
914 t->disposition = DISPATTACH;
915 t->d_filename = str_dup ("smime.p7m");
916 t->filename = outfile;
917 t->unlink = 1; /*delete after sending the message */
926 * Implementation of `verify_one'.
929 /* Display the common attributes of the signature summary SUM.
930 Return 1 if there is is a severe warning.
932 static int show_sig_summary (unsigned long sum,
933 gpgme_ctx_t ctx, gpgme_key_t key, int idx,
938 if ((sum & GPGME_SIGSUM_KEY_REVOKED)) {
939 state_attach_puts (_("Warning: One of the keys has been revoked\n"), s);
943 if ((sum & GPGME_SIGSUM_KEY_EXPIRED)) {
944 time_t at = key->subkeys->expires ? key->subkeys->expires : 0;
947 state_attach_puts (_("Warning: The key used to create the "
948 "signature expired at: "), s);
950 state_attach_puts ("\n", s);
953 state_attach_puts (_("Warning: At least one certification key "
954 "has expired\n"), s);
957 if ((sum & GPGME_SIGSUM_SIG_EXPIRED)) {
958 gpgme_verify_result_t result;
959 gpgme_signature_t sig;
962 result = gpgme_op_verify_result (ctx);
964 for (sig = result->signatures, i = 0; sig && (i < idx);
965 sig = sig->next, i++);
967 state_attach_puts (_("Warning: The signature expired at: "), s);
968 print_time (sig ? sig->exp_timestamp : 0, s);
969 state_attach_puts ("\n", s);
972 if ((sum & GPGME_SIGSUM_KEY_MISSING))
973 state_attach_puts (_("Can't verify due to a missing "
974 "key or certificate\n"), s);
976 if ((sum & GPGME_SIGSUM_CRL_MISSING)) {
977 state_attach_puts (_("The CRL is not available\n"), s);
981 if ((sum & GPGME_SIGSUM_CRL_TOO_OLD)) {
982 state_attach_puts (_("Available CRL is too old\n"), s);
986 if ((sum & GPGME_SIGSUM_BAD_POLICY))
987 state_attach_puts (_("A policy requirement was not met\n"), s);
989 if ((sum & GPGME_SIGSUM_SYS_ERROR)) {
990 const char *t0 = NULL, *t1 = NULL;
991 gpgme_verify_result_t result;
992 gpgme_signature_t sig;
995 state_attach_puts (_("A system error occurred"), s);
997 /* Try to figure out some more detailed system error information. */
998 result = gpgme_op_verify_result (ctx);
999 for (sig = result->signatures, i = 0; sig && (i < idx);
1000 sig = sig->next, i++);
1003 t1 = sig->wrong_key_usage ? "Wrong_Key_Usage" : "";
1007 state_attach_puts (": ", s);
1009 state_attach_puts (t0, s);
1010 if (t1 && !(t0 && !str_cmp (t0, t1))) {
1012 state_attach_puts (",", s);
1013 state_attach_puts (t1, s);
1016 state_attach_puts ("\n", s);
1023 static void show_fingerprint (gpgme_key_t key, STATE * state)
1028 const char *prefix = _("Fingerprint: ");
1032 s = key->subkeys ? key->subkeys->fpr : NULL;
1035 is_pgp = (key->protocol == GPGME_PROTOCOL_OpenPGP);
1037 buf = mem_malloc (str_len (prefix) + str_len (s) * 4 + 2);
1038 strcpy (buf, prefix); /* __STRCPY_CHECKED__ */
1039 p = buf + str_len (buf);
1040 if (is_pgp && str_len (s) == 40) { /* PGP v4 style formatted. */
1041 for (i = 0; *s && s[1] && s[2] && s[3] && s[4]; s += 4, i++) {
1052 for (i = 0; *s && s[1] && s[2]; s += 2, i++) {
1055 *p++ = is_pgp ? ' ' : ':';
1056 if (is_pgp && i == 7)
1061 /* just in case print remaining odd digits */
1066 state_attach_puts (buf, state);
1070 /* Show the valididy of a key used for one signature. */
1071 static void show_one_sig_validity (gpgme_ctx_t ctx, int idx, STATE * s)
1073 gpgme_verify_result_t result = NULL;
1074 gpgme_signature_t sig = NULL;
1075 const char *txt = NULL;
1077 result = gpgme_op_verify_result (ctx);
1079 for (sig = result->signatures; sig && (idx > 0); sig = sig->next, idx--);
1081 switch (sig ? sig->validity : 0) {
1082 case GPGME_VALIDITY_UNKNOWN:
1083 txt = _("WARNING: We have NO indication whether "
1084 "the key belongs to the person named " "as shown above\n");
1086 case GPGME_VALIDITY_UNDEFINED:
1088 case GPGME_VALIDITY_NEVER:
1089 txt = _("WARNING: The key does NOT BELONG to "
1090 "the person named as shown above\n");
1092 case GPGME_VALIDITY_MARGINAL:
1093 txt = _("WARNING: It is NOT certain that the key "
1094 "belongs to the person named as shown above\n");
1096 case GPGME_VALIDITY_FULL:
1097 case GPGME_VALIDITY_ULTIMATE:
1102 state_attach_puts (txt, s);
1105 /* Show information about one signature. This fucntion is called with
1106 the context CTX of a sucessful verification operation and the
1107 enumerator IDX which should start at 0 and incremete for each
1110 Return values are: 0 for normal procession, 1 for a bad signature,
1111 2 for a signature with a warning or -1 for no more signature. */
1112 static int show_one_sig_status (gpgme_ctx_t ctx, int idx, STATE * s)
1115 const char *fpr, *uid;
1116 gpgme_key_t key = NULL;
1117 int i, anybad = 0, anywarn = 0;
1119 gpgme_user_id_t uids = NULL;
1120 gpgme_verify_result_t result;
1121 gpgme_signature_t sig;
1122 gpgme_error_t err = GPG_ERR_NO_ERROR;
1124 result = gpgme_op_verify_result (ctx);
1126 /* FIXME: this code should use a static variable and remember
1127 the current position in the list of signatures, IMHO.
1130 for (i = 0, sig = result->signatures; sig && (i < idx);
1131 i++, sig = sig->next);
1133 return -1; /* Signature not found. */
1135 if (signature_key) {
1136 gpgme_key_release (signature_key);
1137 signature_key = NULL;
1140 created = sig->timestamp;
1144 if (gpg_err_code (sig->status) != GPG_ERR_NO_ERROR)
1147 err = gpgme_get_key (ctx, fpr, &key, 0); /* secret key? */
1149 uid = (key->uids && key->uids->uid) ? key->uids->uid : "[?]";
1151 signature_key = key;
1154 key = NULL; /* Old gpgme versions did not set KEY to NULL on
1155 error. Do it here to avoid a double free. */
1159 if (!s || !s->fpout || !(s->flags & M_DISPLAY)); /* No state information so no way to print anything. */
1161 state_attach_puts (_("Error getting key information: "), s);
1162 state_attach_puts (gpg_strerror (err), s);
1163 state_attach_puts ("\n", s);
1166 else if ((sum & GPGME_SIGSUM_GREEN)) {
1167 state_attach_puts (_("Good signature from: "), s);
1168 state_attach_puts (uid, s);
1169 state_attach_puts ("\n", s);
1170 for (i = 1, uids = key->uids; uids; i++, uids = uids->next) {
1172 /* Skip primary UID. */
1176 state_attach_puts (_(" aka: "), s);
1177 state_attach_puts (uids->uid, s);
1178 state_attach_puts ("\n", s);
1180 state_attach_puts (_(" created: "), s);
1181 print_time (created, s);
1182 state_attach_puts ("\n", s);
1183 if (show_sig_summary (sum, ctx, key, idx, s))
1185 show_one_sig_validity (ctx, idx, s);
1187 else if ((sum & GPGME_SIGSUM_RED)) {
1188 state_attach_puts (_("*BAD* signature claimed to be from: "), s);
1189 state_attach_puts (uid, s);
1190 state_attach_puts ("\n", s);
1191 show_sig_summary (sum, ctx, key, idx, s);
1193 else if (!anybad && key && (key->protocol == GPGME_PROTOCOL_OpenPGP)) { /* We can't decide (yellow) but this is a PGP key with a good
1194 signature, so we display what a PGP user expects: The name,
1195 fingerprint and the key validity (which is neither fully or
1197 state_attach_puts (_("Good signature from: "), s);
1198 state_attach_puts (uid, s);
1199 state_attach_puts ("\n", s);
1200 state_attach_puts (_(" created: "), s);
1201 print_time (created, s);
1202 state_attach_puts ("\n", s);
1203 show_one_sig_validity (ctx, idx, s);
1204 show_fingerprint (key, s);
1205 if (show_sig_summary (sum, ctx, key, idx, s))
1208 else { /* can't decide (yellow) */
1210 state_attach_puts (_("Error checking signature"), s);
1211 state_attach_puts ("\n", s);
1212 show_sig_summary (sum, ctx, key, idx, s);
1215 if (key != signature_key)
1216 gpgme_key_release (key);
1219 return anybad ? 1 : anywarn ? 2 : 0;
1222 /* Do the actual verification step. With IS_SMIME set to true we
1223 assume S/MIME (surprise!) */
1224 static int verify_one (BODY * sigbdy, STATE * s,
1225 const char *tempfile, int is_smime)
1231 gpgme_data_t signature, message;
1233 signature = file_to_data_object (s->fpin, sigbdy->offset, sigbdy->length);
1237 /* We need to tell gpgme about the encoding because the backend can't
1238 auto-detect plain base-64 encoding which is used by S/MIME. */
1240 gpgme_data_set_encoding (signature, GPGME_DATA_ENCODING_BASE64);
1242 err = gpgme_data_new_from_file (&message, tempfile, 1);
1244 gpgme_data_release (signature);
1245 mutt_error (_("error allocating data object: %s\n"), gpgme_strerror (err));
1248 ctx = create_gpgme_context (is_smime);
1250 /* Note: We don't need a current time output because GPGME avoids
1251 such an attack by separating the meta information from the
1253 state_attach_puts (_("[-- Begin signature information --]\n"), s);
1255 err = gpgme_op_verify (ctx, signature, message, NULL);
1256 mutt_need_hard_redraw ();
1260 snprintf (buf, sizeof (buf) - 1,
1261 _("Error: verification failed: %s\n"), gpgme_strerror (err));
1262 state_attach_puts (buf, s);
1264 else { /* Verification succeeded, see what the result is. */
1268 if (signature_key) {
1269 gpgme_key_release (signature_key);
1270 signature_key = NULL;
1273 for (idx = 0; (res = show_one_sig_status (ctx, idx, s)) != -1; idx++) {
1284 gpgme_verify_result_t result;
1285 gpgme_sig_notation_t notation;
1286 gpgme_signature_t signature;
1288 result = gpgme_op_verify_result (ctx);
1290 for (signature = result->signatures; signature;
1291 signature = signature->next) {
1292 if (signature->notations) {
1293 state_attach_puts ("*** Begin Notation (signature by: ", s);
1294 state_attach_puts (signature->fpr, s);
1295 state_attach_puts (") ***\n", s);
1296 for (notation = signature->notations; notation;
1297 notation = notation->next) {
1298 if (notation->name) {
1299 state_attach_puts (notation->name, s);
1300 state_attach_puts ("=", s);
1302 if (notation->value) {
1303 state_attach_puts (notation->value, s);
1304 if (!(*notation->value
1305 && (notation->value[str_len (notation->value) - 1] ==
1307 state_attach_puts ("\n", s);
1310 state_attach_puts ("*** End Notation ***\n", s);
1316 gpgme_release (ctx);
1318 state_attach_puts (_("[-- End signature information --]\n\n"), s);
1319 debug_print (1, ("returning %d.\n", badsig));
1321 return badsig ? 1 : anywarn ? 2 : 0;
1324 int pgp_gpgme_verify_one (BODY * sigbdy, STATE * s, const char *tempfile)
1326 return verify_one (sigbdy, s, tempfile, 0);
1329 int smime_gpgme_verify_one (BODY * sigbdy, STATE * s, const char *tempfile)
1331 return verify_one (sigbdy, s, tempfile, 1);
1335 * Implementation of `decrypt_part'.
1338 /* Decrypt a PGP or SMIME message (depending on the boolean flag
1339 IS_SMIME) with body A described further by state S. Write
1340 plaintext out to file FPOUT and return a new body. For PGP returns
1341 a flag in R_IS_SIGNED to indicate whether this is a combined
1342 encrypted and signed message, for S/MIME it returns true when it is
1343 not a encrypted but a signed message. */
1344 static BODY *decrypt_part (BODY * a, STATE * s, FILE * fpout, int is_smime,
1351 gpgme_data_t ciphertext, plaintext;
1352 int maybe_signed = 0;
1359 ctx = create_gpgme_context (is_smime);
1362 /* Make a data object from the body, create context etc. */
1363 ciphertext = file_to_data_object (s->fpin, a->offset, a->length);
1366 plaintext = create_gpgme_data ();
1368 /* Do the decryption or the verification in case of the S/MIME hack. */
1369 if ((!is_smime) || maybe_signed) {
1371 err = gpgme_op_decrypt_verify (ctx, ciphertext, plaintext);
1372 else if (maybe_signed)
1373 err = gpgme_op_verify (ctx, ciphertext, NULL, plaintext);
1376 /* Check wether signatures have been verified. */
1377 gpgme_verify_result_t verify_result = gpgme_op_verify_result (ctx);
1379 if (verify_result->signatures)
1384 err = gpgme_op_decrypt (ctx, ciphertext, plaintext);
1385 gpgme_data_release (ciphertext);
1387 if (is_smime && !maybe_signed && gpg_err_code (err) == GPG_ERR_NO_DATA) {
1388 /* Check whether this might be a signed message despite what
1389 the mime header told us. Retry then. gpgsm returns the
1390 error information "unsupported Algorithm '?'" but gpgme
1391 will not store this unknown algorithm, thus we test that
1392 it has not been set. */
1393 gpgme_decrypt_result_t result;
1395 result = gpgme_op_decrypt_result (ctx);
1396 if (!result->unsupported_algorithm) {
1398 gpgme_data_release (plaintext);
1402 mutt_need_hard_redraw ();
1403 if ((s->flags & M_DISPLAY)) {
1406 snprintf (buf, sizeof (buf) - 1,
1407 _("[-- Error: decryption failed: %s --]\n\n"),
1408 gpgme_strerror (err));
1409 state_attach_puts (buf, s);
1411 gpgme_data_release (plaintext);
1412 gpgme_release (ctx);
1415 mutt_need_hard_redraw ();
1417 /* Read the output from GPGME, and make sure to change CRLF to LF,
1418 otherwise read_mime_header has a hard time parsing the message. */
1419 if (data_object_to_stream (plaintext, fpout)) {
1420 gpgme_data_release (plaintext);
1421 gpgme_release (ctx);
1424 gpgme_data_release (plaintext);
1426 a->is_signed_data = 0;
1432 a->is_signed_data = 1;
1434 *r_is_signed = -1; /* A signature exists. */
1436 if ((s->flags & M_DISPLAY))
1437 state_attach_puts (_("[-- Begin signature " "information --]\n"), s);
1438 for (idx = 0; (res = show_one_sig_status (ctx, idx, s)) != -1; idx++) {
1444 if (!anybad && idx && r_is_signed && *r_is_signed)
1445 *r_is_signed = anywarn ? 2 : 1; /* Good signature. */
1447 if ((s->flags & M_DISPLAY))
1448 state_attach_puts (_("[-- End signature " "information --]\n\n"), s);
1450 gpgme_release (ctx);
1455 tattach = mutt_read_mime_header (fpout, 0);
1458 * Need to set the length of this body part.
1460 fstat (fileno (fpout), &info);
1461 tattach->length = info.st_size - tattach->offset;
1463 tattach->warnsig = anywarn;
1465 /* See if we need to recurse on this MIME part. */
1466 mutt_parse_part (fpout, tattach);
1472 /* Decrypt a PGP/MIME message in FPIN and B and return a new body and
1473 the stream in CUR and FPOUT. Returns 0 on success. */
1474 int pgp_gpgme_decrypt_mime (FILE * fpin, FILE ** fpout, BODY * b, BODY ** cur)
1476 char tempfile[_POSIX_PATH_MAX];
1478 BODY *first_part = b;
1481 first_part->goodsig = 0;
1482 first_part->warnsig = 0;
1484 if (!mutt_is_multipart_encrypted (b))
1487 if (!b->parts || !b->parts->next)
1492 memset (&s, 0, sizeof (s));
1494 mutt_mktemp (tempfile);
1495 if (!(*fpout = safe_fopen (tempfile, "w+"))) {
1496 mutt_perror (tempfile);
1501 *cur = decrypt_part (b, &s, *fpout, 0, &is_signed);
1504 first_part->goodsig = 1;
1506 return *cur ? 0 : -1;
1510 /* Decrypt a S/MIME message in FPIN and B and return a new body and
1511 the stream in CUR and FPOUT. Returns 0 on success. */
1512 int smime_gpgme_decrypt_mime (FILE * fpin, FILE ** fpout, BODY * b,
1515 char tempfile[_POSIX_PATH_MAX];
1519 long saved_b_offset;
1520 size_t saved_b_length;
1523 if (!mutt_is_application_smime (b))
1529 /* Decode the body - we need to pass binary CMS to the
1530 backend. The backend allows for Base64 encoded data but it does
1531 not allow for QP which I have seen in some messages. So better
1533 saved_b_type = b->type;
1534 saved_b_offset = b->offset;
1535 saved_b_length = b->length;
1536 memset (&s, 0, sizeof (s));
1538 fseek (s.fpin, b->offset, 0);
1539 mutt_mktemp (tempfile);
1540 if (!(tmpfp = safe_fopen (tempfile, "w+"))) {
1541 mutt_perror (tempfile);
1544 mutt_unlink (tempfile);
1547 mutt_decode_attachment (b, &s);
1549 b->length = ftell (s.fpout);
1553 memset (&s, 0, sizeof (s));
1556 mutt_mktemp (tempfile);
1557 if (!(*fpout = safe_fopen (tempfile, "w+"))) {
1558 mutt_perror (tempfile);
1561 mutt_unlink (tempfile);
1563 *cur = decrypt_part (b, &s, *fpout, 1, &is_signed);
1565 (*cur)->goodsig = is_signed > 0;
1566 b->type = saved_b_type;
1567 b->length = saved_b_length;
1568 b->offset = saved_b_offset;
1571 if (*cur && !is_signed && !(*cur)->parts
1572 && mutt_is_application_smime (*cur)) {
1573 /* Assume that this is a opaque signed s/mime message. This is
1574 an ugly way of doing it but we have anyway a problem with
1575 arbitrary encoded S/MIME messages: Only the outer part may be
1576 encrypted. The entire mime parsing should be revamped,
1577 probably by keeping the temportary files so that we don't
1578 need to decrypt them all the time. Inner parts of an
1579 encrypted part can then pint into this file and tehre won't
1580 never be a need to decrypt again. This needs a partial
1581 rewrite of the MIME engine. */
1585 saved_b_type = bb->type;
1586 saved_b_offset = bb->offset;
1587 saved_b_length = bb->length;
1588 memset (&s, 0, sizeof (s));
1590 fseek (s.fpin, bb->offset, 0);
1591 mutt_mktemp (tempfile);
1592 if (!(tmpfp = safe_fopen (tempfile, "w+"))) {
1593 mutt_perror (tempfile);
1596 mutt_unlink (tempfile);
1599 mutt_decode_attachment (bb, &s);
1601 bb->length = ftell (s.fpout);
1606 memset (&s, 0, sizeof (s));
1609 mutt_mktemp (tempfile);
1610 if (!(*fpout = safe_fopen (tempfile, "w+"))) {
1611 mutt_perror (tempfile);
1614 mutt_unlink (tempfile);
1616 tmp_b = decrypt_part (bb, &s, *fpout, 1, &is_signed);
1618 tmp_b->goodsig = is_signed > 0;
1619 bb->type = saved_b_type;
1620 bb->length = saved_b_length;
1621 bb->offset = saved_b_offset;
1624 mutt_free_body (cur);
1627 return *cur ? 0 : -1;
1632 * Implementation of `pgp_check_traditional'.
1635 static int pgp_check_traditional_one_body (FILE * fp, BODY * b,
1638 char tempfile[_POSIX_PATH_MAX];
1639 char buf[HUGE_STRING];
1645 if (b->type != TYPETEXT)
1648 if (tagged_only && !b->tagged)
1651 mutt_mktemp (tempfile);
1652 if (mutt_decode_save_attachment (fp, b, tempfile, 0, 0) != 0) {
1657 if ((tfp = fopen (tempfile, "r")) == NULL) {
1662 while (fgets (buf, sizeof (buf), tfp)) {
1663 if (!str_ncmp ("-----BEGIN PGP ", buf, 15)) {
1664 if (!str_cmp ("MESSAGE-----\n", buf + 15))
1666 else if (!str_cmp ("SIGNED MESSAGE-----\n", buf + 15))
1676 /* fix the content type */
1678 mutt_set_parameter ("format", "fixed", &b->parameter);
1679 mutt_set_parameter ("x-action", enc ? "pgp-encrypted" : "pgp-signed",
1685 int pgp_gpgme_check_traditional (FILE * fp, BODY * b, int tagged_only)
1690 for (; b; b = b->next) {
1691 if (is_multipart (b))
1692 rv = (pgp_gpgme_check_traditional (fp, b->parts, tagged_only) || rv);
1693 else if (b->type == TYPETEXT) {
1694 if ((r = mutt_is_application_pgp (b)))
1697 rv = (pgp_check_traditional_one_body (fp, b, tagged_only) || rv);
1705 * Implementation of `application_handler'.
1709 Copy a clearsigned message, and strip the signature and PGP's
1712 XXX - charset handling: We assume that it is safe to do
1713 character set decoding first, dash decoding second here, while
1714 we do it the other way around in the main handler.
1716 (Note that we aren't worse than Outlook & Cie in this, and also
1717 note that we can successfully handle anything produced by any
1718 existing versions of mutt.) */
1720 static void copy_clearsigned (gpgme_data_t data, STATE * s, char *charset)
1722 char buf[HUGE_STRING];
1723 short complete, armor_header;
1728 fname = data_object_to_tempfile (data, &fp);
1734 fc = fgetconv_open (fp, charset, Charset, M_ICONV_HOOK_FROM);
1736 for (complete = 1, armor_header = 1;
1737 fgetconvs (buf, sizeof (buf), fc) != NULL;
1738 complete = strchr (buf, '\n') != NULL) {
1741 state_puts (buf, s);
1745 if (!str_cmp (buf, "-----BEGIN PGP SIGNATURE-----\n"))
1755 state_puts (s->prefix, s);
1757 if (buf[0] == '-' && buf[1] == ' ')
1758 state_puts (buf + 2, s);
1760 state_puts (buf, s);
1763 fgetconv_close (&fc);
1768 /* Support for classic_application/pgp */
1769 void pgp_gpgme_application_handler (BODY * m, STATE * s)
1771 int needpass = -1, pgp_keyblock = 0;
1774 long bytes, last_pos, offset;
1775 char buf[HUGE_STRING];
1776 FILE *pgpout = NULL;
1779 gpgme_data_t armored_data = NULL;
1781 short maybe_goodsig = 1;
1782 short have_any_sigs = 0;
1784 char body_charset[STRING]; /* Only used for clearsigned messages. */
1786 debug_print (2, ("Entering pgp_application_pgp handler\n"));
1788 /* For clearsigned messages we won't be able to get a character set
1789 but we know that this may only be text thus we assume Latin-1
1791 if (!mutt_get_body_charset (body_charset, sizeof (body_charset), m))
1792 strfcpy (body_charset, "iso-8859-1", sizeof body_charset);
1794 fseek (s->fpin, m->offset, 0);
1795 last_pos = m->offset;
1797 for (bytes = m->length; bytes > 0;) {
1798 if (fgets (buf, sizeof (buf), s->fpin) == NULL)
1801 offset = ftell (s->fpin);
1802 bytes -= (offset - last_pos); /* don't rely on str_len(buf) */
1805 if (!str_ncmp ("-----BEGIN PGP ", buf, 15)) {
1807 start_pos = last_pos;
1809 if (!str_cmp ("MESSAGE-----\n", buf + 15))
1811 else if (!str_cmp ("SIGNED MESSAGE-----\n", buf + 15)) {
1815 else if (!option (OPTDONTHANDLEPGPKEYS) &&
1816 !str_cmp ("PUBLIC KEY BLOCK-----\n", buf + 15)) {
1821 /* XXX - we may wish to recode here */
1823 state_puts (s->prefix, s);
1824 state_puts (buf, s);
1828 have_any_sigs = (have_any_sigs || (clearsign && (s->flags & M_VERIFY)));
1830 /* Copy PGP material to an data container */
1831 armored_data = create_gpgme_data ();
1832 gpgme_data_write (armored_data, buf, str_len (buf));
1833 while (bytes > 0 && fgets (buf, sizeof (buf) - 1, s->fpin) != NULL) {
1834 offset = ftell (s->fpin);
1835 bytes -= (offset - last_pos); /* don't rely on str_len(buf) */
1838 gpgme_data_write (armored_data, buf, str_len (buf));
1840 if ((needpass && !str_cmp ("-----END PGP MESSAGE-----\n", buf))
1842 && (!str_cmp ("-----END PGP SIGNATURE-----\n", buf)
1843 || !str_cmp ("-----END PGP PUBLIC KEY BLOCK-----\n",
1848 /* Invoke PGP if needed */
1849 if (!clearsign || (s->flags & M_VERIFY)) {
1850 unsigned int sig_stat = 0;
1851 gpgme_data_t plaintext;
1854 plaintext = create_gpgme_data ();
1855 ctx = create_gpgme_context (0);
1858 err = gpgme_op_verify (ctx, armored_data, NULL, plaintext);
1860 err = gpgme_op_decrypt_verify (ctx, armored_data, plaintext);
1861 if (gpg_err_code (err) == GPG_ERR_NO_DATA) {
1862 /* Decrypt verify can't handle signed only messages. */
1863 err = (gpgme_data_seek (armored_data, 0, SEEK_SET) == -1)
1864 ? gpgme_error_from_errno (errno) : 0;
1865 /* Must release plaintext so that we supply an
1866 uninitialized object. */
1867 gpgme_data_release (plaintext);
1868 plaintext = create_gpgme_data ();
1869 err = gpgme_op_verify (ctx, armored_data, NULL, plaintext);
1876 snprintf (errbuf, sizeof (errbuf) - 1,
1877 _("Error: decryption/verification failed: %s\n"),
1878 gpgme_strerror (err));
1879 state_attach_puts (errbuf, s);
1881 else { /* Decryption/Verification succeeded */
1885 /* Check wether signatures have been verified. */
1886 gpgme_verify_result_t verify_result;
1888 verify_result = gpgme_op_verify_result (ctx);
1889 if (verify_result->signatures)
1895 if ((s->flags & M_DISPLAY) && sig_stat) {
1900 state_attach_puts (_("[-- Begin signature "
1901 "information --]\n"), s);
1904 (res = show_one_sig_status (ctx, idx, s)) != -1; idx++) {
1913 state_attach_puts (_("[-- End signature "
1914 "information --]\n\n"), s);
1917 tmpfname = data_object_to_tempfile (plaintext, &pgpout);
1920 state_attach_puts (_("Error: copy data failed\n"), s);
1924 mem_free (&tmpfname);
1927 gpgme_release (ctx);
1931 * Now, copy cleartext to the screen. NOTE - we expect that PGP
1932 * outputs utf-8 cleartext. This may not always be true, but it
1933 * seems to be a reasonable guess.
1936 if (s->flags & M_DISPLAY) {
1938 state_attach_puts (_("[-- BEGIN PGP MESSAGE --]\n\n"), s);
1939 else if (pgp_keyblock)
1940 state_attach_puts (_("[-- BEGIN PGP PUBLIC KEY BLOCK --]\n"), s);
1942 state_attach_puts (_("[-- BEGIN PGP SIGNED MESSAGE --]\n\n"), s);
1946 copy_clearsigned (armored_data, s, body_charset);
1953 fc = fgetconv_open (pgpout, "utf-8", Charset, 0);
1954 while ((c = fgetconv (fc)) != EOF) {
1956 if (c == '\n' && s->prefix)
1957 state_puts (s->prefix, s);
1959 fgetconv_close (&fc);
1962 if (s->flags & M_DISPLAY) {
1963 state_putc ('\n', s);
1965 state_attach_puts (_("[-- END PGP MESSAGE --]\n"), s);
1966 else if (pgp_keyblock)
1967 state_attach_puts (_("[-- END PGP PUBLIC KEY BLOCK --]\n"), s);
1969 state_attach_puts (_("[-- END PGP SIGNED MESSAGE --]\n"), s);
1973 safe_fclose (&pgpout);
1977 /* XXX - we may wish to recode here */
1979 state_puts (s->prefix, s);
1980 state_puts (buf, s);
1984 m->goodsig = (maybe_goodsig && have_any_sigs);
1986 if (needpass == -1) {
1987 state_attach_puts (_("[-- Error: could not find beginning"
1988 " of PGP message! --]\n\n"), s);
1991 debug_print (2, ("Leaving pgp_application_pgp handler\n"));
1995 * Implementation of `encrypted_handler'.
1998 /* MIME handler for pgp/mime encrypted messages. */
1999 void pgp_gpgme_encrypted_handler (BODY * a, STATE * s)
2001 char tempfile[_POSIX_PATH_MAX];
2004 BODY *orig_body = a;
2007 debug_print (2, ("Entering pgp_encrypted handler\n"));
2009 if (!a || a->type != TYPEAPPLICATION || !a->subtype
2010 || ascii_strcasecmp ("pgp-encrypted", a->subtype)
2011 || !a->next || a->next->type != TYPEAPPLICATION || !a->next->subtype
2012 || ascii_strcasecmp ("octet-stream", a->next->subtype)) {
2013 if (s->flags & M_DISPLAY)
2014 state_attach_puts (_("[-- Error: malformed PGP/MIME message! --]\n\n"),
2019 /* Move forward to the application/pgp-encrypted body. */
2022 mutt_mktemp (tempfile);
2023 if (!(fpout = safe_fopen (tempfile, "w+"))) {
2024 if (s->flags & M_DISPLAY)
2025 state_attach_puts (_("[-- Error: could not create temporary file! "
2030 tattach = decrypt_part (a, s, fpout, 0, &is_signed);
2032 tattach->goodsig = is_signed > 0;
2034 if (s->flags & M_DISPLAY)
2035 state_attach_puts (is_signed ?
2037 ("[-- The following data is PGP/MIME signed and encrypted --]\n\n")
2040 ("[-- The following data is PGP/MIME encrypted --]\n\n"),
2044 FILE *savefp = s->fpin;
2047 mutt_body_handler (tattach, s);
2052 * if a multipart/signed is the _only_ sub-part of a
2053 * multipart/encrypted, cache signature verification
2056 if (mutt_is_multipart_signed (tattach) && !tattach->next)
2057 orig_body->goodsig |= tattach->goodsig;
2059 if (s->flags & M_DISPLAY) {
2060 state_puts ("\n", s);
2061 state_attach_puts (is_signed ?
2063 ("[-- End of PGP/MIME signed and encrypted data --]\n")
2064 : _("[-- End of PGP/MIME encrypted data --]\n"), s);
2067 mutt_free_body (&tattach);
2071 mutt_unlink (tempfile);
2072 debug_print (2, ("Leaving pgp_encrypted handler\n"));
2075 /* Support for application/smime */
2076 void smime_gpgme_application_handler (BODY * a, STATE * s)
2078 char tempfile[_POSIX_PATH_MAX];
2084 debug_print (2, ("Entering smime_encrypted handler\n"));
2087 mutt_mktemp (tempfile);
2088 if (!(fpout = safe_fopen (tempfile, "w+"))) {
2089 if (s->flags & M_DISPLAY)
2090 state_attach_puts (_("[-- Error: could not create temporary file! "
2095 tattach = decrypt_part (a, s, fpout, 1, &is_signed);
2097 tattach->goodsig = is_signed > 0;
2099 if (s->flags & M_DISPLAY)
2100 state_attach_puts (is_signed ?
2101 _("[-- The following data is S/MIME signed --]\n\n")
2104 ("[-- The following data is S/MIME encrypted --]\n\n"),
2108 FILE *savefp = s->fpin;
2111 mutt_body_handler (tattach, s);
2116 * if a multipart/signed is the _only_ sub-part of a
2117 * multipart/encrypted, cache signature verification
2120 if (mutt_is_multipart_signed (tattach) && !tattach->next) {
2121 if (!(a->goodsig = tattach->goodsig))
2122 a->warnsig = tattach->warnsig;
2124 else if (tattach->goodsig) {
2126 a->warnsig = tattach->warnsig;
2129 if (s->flags & M_DISPLAY) {
2130 state_puts ("\n", s);
2131 state_attach_puts (is_signed ?
2132 _("[-- End of S/MIME signed data --]\n") :
2133 _("[-- End of S/MIME encrypted data --]\n"), s);
2136 mutt_free_body (&tattach);
2140 mutt_unlink (tempfile);
2141 debug_print (2, ("Leaving smime_encrypted handler\n"));
2146 * Format an entry on the CRYPT key selection menu.
2149 * %k key id %K key id of the principal key
2151 * %a algorithm %A algorithm of the princ. key
2152 * %l length %L length of the princ. key
2153 * %f flags %F flags of the princ. key
2154 * %c capabilities %C capabilities of the princ. key
2155 * %t trust/validity of the key-uid association
2157 * %[...] date of key using strftime(3)
2160 static const char *crypt_entry_fmt (char *dest,
2165 const char *ifstring,
2166 const char *elsestring,
2167 unsigned long data, format_flag flags)
2170 crypt_entry_t *entry;
2173 int optional = (flags & M_FORMAT_OPTIONAL);
2174 const char *s = NULL;
2177 entry = (crypt_entry_t *) data;
2180 /* if (isupper ((unsigned char) op)) */
2183 kflags = (key->flags /*| (pkey->flags & KEYFLAG_RESTRICTIONS)
2186 switch (ascii_tolower (op)) {
2190 char buf2[SHORT_STRING], *p;
2206 while (len > 0 && *cp != ']') {
2215 break; /* not enough space */
2225 if (do_locales && Locale)
2226 setlocale (LC_TIME, Locale);
2231 if (key->kobj->subkeys && (key->kobj->subkeys->timestamp > 0))
2232 tt = key->kobj->subkeys->timestamp;
2234 tm = localtime (&tt);
2236 strftime (buf2, sizeof (buf2), dest, tm);
2239 setlocale (LC_TIME, "C");
2241 snprintf (fmt, sizeof (fmt), "%%%ss", prefix);
2242 snprintf (dest, destlen, fmt, buf2);
2249 snprintf (fmt, sizeof (fmt), "%%%sd", prefix);
2250 snprintf (dest, destlen, fmt, entry->num);
2255 /* fixme: we need a way to distinguish between main and subkeys.
2256 Store the idx in entry? */
2257 snprintf (fmt, sizeof (fmt), "%%%ss", prefix);
2258 snprintf (dest, destlen, fmt, crypt_keyid (key));
2263 snprintf (fmt, sizeof (fmt), "%%%ss", prefix);
2264 snprintf (dest, destlen, fmt, key->uid);
2269 snprintf (fmt, sizeof (fmt), "%%%s.3s", prefix);
2270 if (key->kobj->subkeys)
2271 s = gpgme_pubkey_algo_name (key->kobj->subkeys->pubkey_algo);
2274 snprintf (dest, destlen, fmt, s);
2279 snprintf (fmt, sizeof (fmt), "%%%slu", prefix);
2280 if (key->kobj->subkeys)
2281 val = key->kobj->subkeys->length;
2284 snprintf (dest, destlen, fmt, val);
2289 snprintf (fmt, sizeof (fmt), "%%%sc", prefix);
2290 snprintf (dest, destlen, fmt, crypt_flags (kflags));
2292 else if (!(kflags & (KEYFLAG_RESTRICTIONS)))
2297 snprintf (fmt, sizeof (fmt), "%%%ss", prefix);
2298 snprintf (dest, destlen, fmt, crypt_key_abilities (kflags));
2300 else if (!(kflags & (KEYFLAG_ABILITIES)))
2304 if ((kflags & KEYFLAG_ISX509))
2307 gpgme_user_id_t uid = NULL;
2310 for (i = 0, uid = key->kobj->uids; uid && (i < key->idx);
2311 i++, uid = uid->next);
2313 switch (uid->validity) {
2314 case GPGME_VALIDITY_UNDEFINED:
2317 case GPGME_VALIDITY_NEVER:
2320 case GPGME_VALIDITY_MARGINAL:
2323 case GPGME_VALIDITY_FULL:
2326 case GPGME_VALIDITY_ULTIMATE:
2329 case GPGME_VALIDITY_UNKNOWN:
2335 snprintf (fmt, sizeof (fmt), "%%%sc", prefix);
2336 snprintf (dest, destlen, fmt, s ? *s : 'B');
2339 snprintf (fmt, sizeof (fmt), "%%%ss", prefix);
2340 snprintf (dest, destlen, fmt,
2341 gpgme_get_protocol_name (key->kobj->protocol));
2349 mutt_FormatString (dest, destlen, ifstring, mutt_attach_fmt, data, 0);
2350 else if (flags & M_FORMAT_OPTIONAL)
2351 mutt_FormatString (dest, destlen, elsestring, mutt_attach_fmt, data, 0);
2355 /* Used by the display fucntion to format a line. */
2356 static void crypt_entry (char *s, size_t l, MUTTMENU * menu, int num)
2358 crypt_key_t **key_table = (crypt_key_t **) menu->data;
2359 crypt_entry_t entry;
2361 entry.key = key_table[num];
2362 entry.num = num + 1;
2364 mutt_FormatString (s, l, NONULL (PgpEntryFormat), crypt_entry_fmt,
2365 (unsigned long) &entry, M_FORMAT_ARROWCURSOR);
2368 /* Compare two addresses and the keyid to be used for sorting. */
2369 static int _crypt_compare_address (const void *a, const void *b)
2371 crypt_key_t **s = (crypt_key_t **) a;
2372 crypt_key_t **t = (crypt_key_t **) b;
2375 if ((r = str_casecmp ((*s)->uid, (*t)->uid)))
2378 return str_casecmp (crypt_keyid (*s), crypt_keyid (*t)) > 0;
2381 static int crypt_compare_address (const void *a, const void *b)
2383 return ((PgpSortKeys & SORT_REVERSE) ? !_crypt_compare_address (a, b)
2384 : _crypt_compare_address (a, b));
2388 /* Compare two key IDs and the addresses to be used for sorting. */
2389 static int _crypt_compare_keyid (const void *a, const void *b)
2391 crypt_key_t **s = (crypt_key_t **) a;
2392 crypt_key_t **t = (crypt_key_t **) b;
2395 if ((r = str_casecmp (crypt_keyid (*s), crypt_keyid (*t))))
2398 return str_casecmp ((*s)->uid, (*t)->uid) > 0;
2401 static int crypt_compare_keyid (const void *a, const void *b)
2403 return ((PgpSortKeys & SORT_REVERSE) ? !_crypt_compare_keyid (a, b)
2404 : _crypt_compare_keyid (a, b));
2407 /* Compare 2 creation dates and the addresses. For sorting. */
2408 static int _crypt_compare_date (const void *a, const void *b)
2410 crypt_key_t **s = (crypt_key_t **) a;
2411 crypt_key_t **t = (crypt_key_t **) b;
2412 unsigned long ts = 0, tt = 0;
2414 if ((*s)->kobj->subkeys && ((*s)->kobj->subkeys->timestamp > 0))
2415 ts = (*s)->kobj->subkeys->timestamp;
2416 if ((*t)->kobj->subkeys && ((*t)->kobj->subkeys->timestamp > 0))
2417 tt = (*t)->kobj->subkeys->timestamp;
2424 return str_casecmp ((*s)->uid, (*t)->uid) > 0;
2427 static int crypt_compare_date (const void *a, const void *b)
2429 return ((PgpSortKeys & SORT_REVERSE) ? !_crypt_compare_date (a, b)
2430 : _crypt_compare_date (a, b));
2433 /* Compare two trust values, the key length, the creation dates. the
2434 addresses and the key IDs. For sorting. */
2435 static int _crypt_compare_trust (const void *a, const void *b)
2437 crypt_key_t **s = (crypt_key_t **) a;
2438 crypt_key_t **t = (crypt_key_t **) b;
2439 unsigned long ts = 0, tt = 0;
2442 if ((r = (((*s)->flags & (KEYFLAG_RESTRICTIONS))
2443 - ((*t)->flags & (KEYFLAG_RESTRICTIONS)))))
2446 if ((*s)->kobj->uids)
2447 ts = (*s)->kobj->uids->validity;
2448 if ((*t)->kobj->uids)
2449 tt = (*t)->kobj->uids->validity;
2450 if ((r = (tt - ts)))
2453 if ((*s)->kobj->subkeys)
2454 ts = (*s)->kobj->subkeys->length;
2455 if ((*t)->kobj->subkeys)
2456 tt = (*t)->kobj->subkeys->length;
2460 if ((*s)->kobj->subkeys && ((*s)->kobj->subkeys->timestamp > 0))
2461 ts = (*s)->kobj->subkeys->timestamp;
2462 if ((*t)->kobj->subkeys && ((*t)->kobj->subkeys->timestamp > 0))
2463 tt = (*t)->kobj->subkeys->timestamp;
2469 if ((r = str_casecmp ((*s)->uid, (*t)->uid)))
2471 return (str_casecmp (crypt_keyid ((*s)), crypt_keyid ((*t)))) > 0;
2474 static int crypt_compare_trust (const void *a, const void *b)
2476 return ((PgpSortKeys & SORT_REVERSE) ? !_crypt_compare_trust (a, b)
2477 : _crypt_compare_trust (a, b));
2480 /* Print the X.500 Distinguished Name part KEY from the array of parts
2482 static int print_dn_part (FILE * fp, struct dn_array_s *dn, const char *key)
2486 for (; dn->key; dn++) {
2487 if (!str_cmp (dn->key, key)) {
2490 print_utf8 (fp, dn->value, str_len (dn->value));
2497 /* Print all parts of a DN in a standard sequence. */
2498 static void print_dn_parts (FILE * fp, struct dn_array_s *dn)
2500 const char *stdpart[] = {
2501 "CN", "OU", "O", "STREET", "L", "ST", "C", NULL
2503 int any = 0, any2 = 0, i;
2505 for (i = 0; stdpart[i]; i++) {
2508 any = print_dn_part (fp, dn, stdpart[i]);
2510 /* now print the rest without any specific ordering */
2511 for (; dn->key; dn++) {
2512 for (i = 0; stdpart[i]; i++) {
2513 if (!str_cmp (dn->key, stdpart[i]))
2521 any = print_dn_part (fp, dn, dn->key);
2530 /* Parse an RDN; this is a helper to parse_dn(). */
2531 static const unsigned char *parse_dn_part (struct dn_array_s *array,
2532 const unsigned char *string)
2534 const unsigned char *s, *s1;
2538 /* parse attributeType */
2539 for (s = string + 1; *s && *s != '='; s++);
2541 return NULL; /* error */
2544 return NULL; /* empty key */
2545 array->key = mem_malloc (n + 1);
2546 p = (unsigned char *) array->key;
2547 memcpy (p, string, n); /* fixme: trim trailing spaces */
2551 if (*string == '#') { /* hexstring */
2553 for (s = string; hexdigitp (s); s++)
2557 return NULL; /* empty or odd number of digits */
2559 p = mem_malloc (n + 1);
2560 array->value = (char *) p;
2561 for (s1 = string; n; s1 += 2, n--)
2565 else { /* regular v3 quoted string */
2566 for (n = 0, s = string; *s; s++) {
2567 if (*s == '\\') { /* pair */
2569 if (*s == ',' || *s == '=' || *s == '+'
2570 || *s == '<' || *s == '>' || *s == '#' || *s == ';'
2571 || *s == '\\' || *s == '\"' || *s == ' ')
2573 else if (hexdigitp (s) && hexdigitp (s + 1)) {
2578 return NULL; /* invalid escape sequence */
2580 else if (*s == '\"')
2581 return NULL; /* invalid encoding */
2582 else if (*s == ',' || *s == '=' || *s == '+'
2583 || *s == '<' || *s == '>' || *s == '#' || *s == ';')
2589 p = mem_malloc (n + 1);
2590 array->value = (char *) p;
2591 for (s = string; n; s++, n--) {
2594 if (hexdigitp (s)) {
2610 /* Parse a DN and return an array-ized one. This is not a validating
2611 parser and it does not support any old-stylish syntax; gpgme is
2612 expected to return only rfc2253 compatible strings. */
2613 static struct dn_array_s *parse_dn (const unsigned char *string)
2615 struct dn_array_s *array;
2616 size_t arrayidx, arraysize;
2619 arraysize = 7; /* C,ST,L,O,OU,CN,email */
2620 array = mem_malloc ((arraysize + 1) * sizeof *array);
2623 while (*string == ' ')
2627 if (arrayidx >= arraysize) { /* mutt lacks a real safe_realoc - so we need to copy */
2628 struct dn_array_s *a2;
2631 a2 = mem_malloc ((arraysize + 1) * sizeof *array);
2632 for (i = 0; i < arrayidx; i++) {
2633 a2[i].key = array[i].key;
2634 a2[i].value = array[i].value;
2639 array[arrayidx].key = NULL;
2640 array[arrayidx].value = NULL;
2641 string = parse_dn_part (array + arrayidx, string);
2645 while (*string == ' ')
2647 if (*string && *string != ',' && *string != ';' && *string != '+')
2648 goto failure; /* invalid delimiter */
2652 array[arrayidx].key = NULL;
2653 array[arrayidx].value = NULL;
2657 for (i = 0; i < arrayidx; i++) {
2658 mem_free (&array[i].key);
2659 mem_free (&array[i].value);
2666 /* Print a nice representation of the USERID and make sure it is
2667 displayed in a proper way, which does mean to reorder some parts
2668 for S/MIME's DNs. USERID is a string as returned by the gpgme key
2669 functions. It is utf-8 encoded. */
2670 static void parse_and_print_user_id (FILE * fp, const char *userid)
2675 if (*userid == '<') {
2676 s = strchr (userid + 1, '>');
2678 print_utf8 (fp, userid + 1, s - userid - 1);
2680 else if (*userid == '(')
2681 fputs (_("[Can't display this user ID (unknown encoding)]"), fp);
2682 else if (!digit_or_letter ((const unsigned char *) userid))
2683 fputs (_("[Can't display this user ID (invalid encoding)]"), fp);
2685 struct dn_array_s *dn = parse_dn ((const unsigned char *) userid);
2688 fputs (_("[Can't display this user ID (invalid DN)]"), fp);
2690 print_dn_parts (fp, dn);
2691 for (i = 0; dn[i].key; i++) {
2692 mem_free (&dn[i].key);
2693 mem_free (&dn[i].value);
2701 KEY_CAP_CAN_ENCRYPT,
2706 static unsigned int key_check_cap (gpgme_key_t key, key_cap_t cap)
2708 gpgme_subkey_t subkey = NULL;
2709 unsigned int ret = 0;
2712 case KEY_CAP_CAN_ENCRYPT:
2713 if (!(ret = key->can_encrypt))
2714 for (subkey = key->subkeys; subkey; subkey = subkey->next)
2715 if ((ret = subkey->can_encrypt))
2718 case KEY_CAP_CAN_SIGN:
2719 if (!(ret = key->can_sign))
2720 for (subkey = key->subkeys; subkey; subkey = subkey->next)
2721 if ((ret = subkey->can_sign))
2724 case KEY_CAP_CAN_CERTIFY:
2725 if (!(ret = key->can_certify))
2726 for (subkey = key->subkeys; subkey; subkey = subkey->next)
2727 if ((ret = subkey->can_certify))
2736 /* Print verbose information about a key or certificate to FP. */
2737 static void print_key_info (gpgme_key_t key, FILE * fp)
2740 const char *s = NULL, *s2 = NULL;
2743 char shortbuf[SHORT_STRING];
2744 unsigned long aval = 0;
2748 gpgme_user_id_t uid = NULL;
2751 setlocale (LC_TIME, Locale);
2753 is_pgp = key->protocol == GPGME_PROTOCOL_OpenPGP;
2755 for (idx = 0, uid = key->uids; uid; idx++, uid = uid->next) {
2760 fputs (idx ? _(" aka ......: ") :_("Name ......: "), fp);
2763 fputs (_("[Invalid]"), fp);
2767 print_utf8 (fp, s, str_len (s));
2769 parse_and_print_user_id (fp, s);
2773 if (key->subkeys && (key->subkeys->timestamp > 0)) {
2774 tt = key->subkeys->timestamp;
2776 tm = localtime (&tt);
2777 #ifdef HAVE_LANGINFO_D_T_FMT
2778 strftime (shortbuf, sizeof shortbuf, nl_langinfo (D_T_FMT), tm);
2780 strftime (shortbuf, sizeof shortbuf, "%c", tm);
2782 fprintf (fp, _("Valid From : %s\n"), shortbuf);
2785 if (key->subkeys && (key->subkeys->expires > 0)) {
2786 tt = key->subkeys->expires;
2788 tm = localtime (&tt);
2789 #ifdef HAVE_LANGINFO_D_T_FMT
2790 strftime (shortbuf, sizeof shortbuf, nl_langinfo (D_T_FMT), tm);
2792 strftime (shortbuf, sizeof shortbuf, "%c", tm);
2794 fprintf (fp, _("Valid To ..: %s\n"), shortbuf);
2798 s = gpgme_pubkey_algo_name (key->subkeys->pubkey_algo);
2802 s2 = is_pgp ? "PGP" : "X.509";
2805 aval = key->subkeys->length;
2807 fprintf (fp, _("Key Type ..: %s, %lu bit %s\n"), s2, aval, s);
2809 fprintf (fp, _("Key Usage .: "));
2812 if (key_check_cap (key, KEY_CAP_CAN_ENCRYPT)) {
2813 fprintf (fp, "%s%s", delim, _("encryption"));
2816 if (key_check_cap (key, KEY_CAP_CAN_SIGN)) {
2817 fprintf (fp, "%s%s", delim, _("signing"));
2820 if (key_check_cap (key, KEY_CAP_CAN_CERTIFY)) {
2821 fprintf (fp, "%s%s", delim, _("certification"));
2827 s = key->subkeys->fpr;
2828 fputs (_("Fingerprint: "), fp);
2829 if (is_pgp && str_len (s) == 40) {
2830 for (i = 0; *s && s[1] && s[2] && s[3] && s[4]; s += 4, i++) {
2835 putc (is_pgp ? ' ' : ':', fp);
2836 if (is_pgp && i == 4)
2841 for (i = 0; *s && s[1] && s[2]; s += 2, i++) {
2844 putc (is_pgp ? ' ' : ':', fp);
2845 if (is_pgp && i == 7)
2849 fprintf (fp, "%s\n", s);
2852 if (key->issuer_serial) {
2853 s = key->issuer_serial;
2855 fprintf (fp, _("Serial-No .: 0x%s\n"), s);
2858 if (key->issuer_name) {
2859 s = key->issuer_name;
2861 fprintf (fp, _("Issued By .: "));
2862 parse_and_print_user_id (fp, s);
2867 /* For PGP we list all subkeys. */
2869 gpgme_subkey_t subkey = NULL;
2871 for (idx = 1, subkey = key->subkeys; subkey; idx++, subkey = subkey->next) {
2875 if (str_len (s) == 16)
2876 s += 8; /* display only the short keyID */
2877 fprintf (fp, _("Subkey ....: 0x%s"), s);
2878 if (subkey->revoked) {
2880 fputs (_("[Revoked]"), fp);
2882 if (subkey->invalid) {
2884 fputs (_("[Invalid]"), fp);
2886 if (subkey->expired) {
2888 fputs (_("[Expired]"), fp);
2890 if (subkey->disabled) {
2892 fputs (_("[Disabled]"), fp);
2896 if (subkey->timestamp > 0) {
2897 tt = subkey->timestamp;
2899 tm = localtime (&tt);
2900 #ifdef HAVE_LANGINFO_D_T_FMT
2901 strftime (shortbuf, sizeof shortbuf, nl_langinfo (D_T_FMT), tm);
2903 strftime (shortbuf, sizeof shortbuf, "%c", tm);
2905 fprintf (fp, _("Valid From : %s\n"), shortbuf);
2908 if (subkey->expires > 0) {
2909 tt = subkey->expires;
2911 tm = localtime (&tt);
2912 #ifdef HAVE_LANGINFO_D_T_FMT
2913 strftime (shortbuf, sizeof shortbuf, nl_langinfo (D_T_FMT), tm);
2915 strftime (shortbuf, sizeof shortbuf, "%c", tm);
2917 fprintf (fp, _("Valid To ..: %s\n"), shortbuf);
2921 s = gpgme_pubkey_algo_name (subkey->pubkey_algo);
2926 aval = subkey->length;
2930 fprintf (fp, _("Key Type ..: %s, %lu bit %s\n"), "PGP", aval, s);
2932 fprintf (fp, _("Key Usage .: "));
2935 if (subkey->can_encrypt) {
2936 fprintf (fp, "%s%s", delim, _("encryption"));
2939 if (subkey->can_sign) {
2940 fprintf (fp, "%s%s", delim, _("signing"));
2943 if (subkey->can_certify) {
2944 fprintf (fp, "%s%s", delim, _("certification"));
2952 setlocale (LC_TIME, "C");
2956 /* Show detailed information about the selected key */
2957 static void verify_key (crypt_key_t * key)
2960 char cmd[LONG_STRING], tempfile[_POSIX_PATH_MAX];
2962 gpgme_ctx_t listctx = NULL;
2964 gpgme_key_t k = NULL;
2967 mutt_mktemp (tempfile);
2968 if (!(fp = safe_fopen (tempfile, "w"))) {
2969 mutt_perror (_("Can't create temporary file"));
2973 mutt_message _("Collecting data...");
2975 print_key_info (key->kobj, fp);
2977 err = gpgme_new (&listctx);
2979 fprintf (fp, "Internal error: can't create gpgme context: %s\n",
2980 gpgme_strerror (err));
2983 if ((key->flags & KEYFLAG_ISX509))
2984 gpgme_set_protocol (listctx, GPGME_PROTOCOL_CMS);
2988 while ((s = k->chain_id) && k->subkeys && str_cmp (s, k->subkeys->fpr)) {
2990 err = gpgme_op_keylist_start (listctx, s, 0);
2991 gpgme_key_release (k);
2994 err = gpgme_op_keylist_next (listctx, &k);
2996 fprintf (fp, _("Error finding issuer key: %s\n"), gpgme_strerror (err));
2999 gpgme_op_keylist_end (listctx);
3001 print_key_info (k, fp);
3004 fputs (_("Error: certification chain to long - stopping here\n"), fp);
3010 gpgme_key_release (k);
3011 gpgme_release (listctx);
3013 mutt_clear_error ();
3014 snprintf (cmd, sizeof (cmd), _("Key ID: 0x%s"), crypt_keyid (key));
3015 mutt_do_pager (cmd, tempfile, 0, NULL);
3019 * Implementation of `findkeys'.
3023 /* Convert LIST into a pattern string suitable to be passed to GPGME.
3024 We need to convert spaces in an item into a '+' and '%' into
3026 static char *list_to_pattern (LIST * list)
3034 for (l = list; l; l = l->next) {
3035 for (s = l->data; *s; s++) {
3040 n++; /* delimiter or end of string */
3042 n++; /* make sure to allocate at least one byte */
3043 pattern = p = mem_calloc (1, n);
3044 for (l = list; l; l = l->next) {
3049 for (s = l->data; *s; s++) {
3055 else if (*s == '+') {
3071 /* Return a list of keys which are candidates for the selection.
3072 Select by looking at the HINTS list. */
3073 static crypt_key_t *get_candidates (LIST * hints, unsigned int app,
3076 crypt_key_t *db, *k, **kend;
3082 gpgme_user_id_t uid = NULL;
3084 pattern = list_to_pattern (hints);
3088 err = gpgme_new (&ctx);
3090 mutt_error (_("gpgme_new failed: %s"), gpgme_strerror (err));
3091 mem_free (&pattern);
3098 if ((app & APPLICATION_PGP)) {
3099 /* Its all a mess. That old GPGME expects different things
3100 depending on the protocol. For gpg we don' t need percent
3101 escaped pappert but simple strings passed in an array to the
3102 keylist_ext_start function. */
3107 for (l = hints, n = 0; l; l = l->next) {
3108 if (l->data && *l->data)
3114 patarr = mem_calloc (n + 1, sizeof *patarr);
3115 for (l = hints, n = 0; l; l = l->next) {
3116 if (l->data && *l->data)
3117 patarr[n++] = str_dup (l->data);
3120 err = gpgme_op_keylist_ext_start (ctx, (const char **) patarr, secret, 0);
3121 for (n = 0; patarr[n]; n++)
3122 mem_free (&patarr[n]);
3125 mutt_error (_("gpgme_op_keylist_start failed: %s"), gpgme_strerror (err));
3126 gpgme_release (ctx);
3127 mem_free (&pattern);
3131 while (!(err = gpgme_op_keylist_next (ctx, &key))) {
3132 unsigned int flags = 0;
3134 if (key_check_cap (key, KEY_CAP_CAN_ENCRYPT))
3135 flags |= KEYFLAG_CANENCRYPT;
3136 if (key_check_cap (key, KEY_CAP_CAN_SIGN))
3137 flags |= KEYFLAG_CANSIGN;
3139 #if 0 /* DISABLED code */
3141 /* Bug in gpg. Capabilities are not listed for secret
3142 keys. Try to deduce them from the algorithm. */
3144 switch (key->subkeys[0].pubkey_algo) {
3146 flags |= KEYFLAG_CANENCRYPT;
3147 flags |= KEYFLAG_CANSIGN;
3149 case GPGME_PK_ELG_E:
3150 flags |= KEYFLAG_CANENCRYPT;
3153 flags |= KEYFLAG_CANSIGN;
3157 #endif /* DISABLED code */
3159 for (idx = 0, uid = key->uids; uid; idx++, uid = uid->next) {
3160 k = mem_calloc (1, sizeof *k);
3169 if (gpg_err_code (err) != GPG_ERR_EOF)
3170 mutt_error (_("gpgme_op_keylist_next failed: %s"), gpgme_strerror (err));
3171 gpgme_op_keylist_end (ctx);
3176 if ((app & APPLICATION_SMIME)) {
3177 /* and now look for x509 certificates */
3178 gpgme_set_protocol (ctx, GPGME_PROTOCOL_CMS);
3179 err = gpgme_op_keylist_start (ctx, pattern, 0);
3181 mutt_error (_("gpgme_op_keylist_start failed: %s"), gpgme_strerror (err));
3182 gpgme_release (ctx);
3183 mem_free (&pattern);
3187 while (!(err = gpgme_op_keylist_next (ctx, &key))) {
3188 unsigned int flags = KEYFLAG_ISX509;
3190 if (key_check_cap (key, KEY_CAP_CAN_ENCRYPT))
3191 flags |= KEYFLAG_CANENCRYPT;
3192 if (key_check_cap (key, KEY_CAP_CAN_SIGN))
3193 flags |= KEYFLAG_CANSIGN;
3195 for (idx = 0, uid = key->uids; uid; idx++, uid = uid->next) {
3196 k = mem_calloc (1, sizeof *k);
3205 if (gpg_err_code (err) != GPG_ERR_EOF)
3206 mutt_error (_("gpgme_op_keylist_next failed: %s"), gpgme_strerror (err));
3207 gpgme_op_keylist_end (ctx);
3210 gpgme_release (ctx);
3211 mem_free (&pattern);
3215 /* Add the string STR to the list HINTS. This list is later used to
3217 static LIST *crypt_add_string_to_hints (LIST * hints, const char *str)
3222 if ((scratch = str_dup (str)) == NULL)
3225 for (t = strtok (scratch, " ,.:\"()<>\n"); t;
3226 t = strtok (NULL, " ,.:\"()<>\n")) {
3227 if (str_len (t) > 3)
3228 hints = mutt_add_list (hints, t);
3231 mem_free (&scratch);
3235 /* Display a menu to select a key from the array KEYS. FORCED_VALID
3236 will be set to true on return if the user did override the the
3238 static crypt_key_t *crypt_select_key (crypt_key_t * keys,
3239 ADDRESS * p, const char *s,
3240 unsigned int app, int *forced_valid)
3243 crypt_key_t **key_table;
3246 char helpstr[SHORT_STRING], buf[LONG_STRING];
3248 int (*f) (const void *, const void *);
3249 int menu_to_use = 0;
3254 /* build the key table */
3257 for (k = keys; k; k = k->next) {
3258 if (!option (OPTPGPSHOWUNUSABLE) && (k->flags & KEYFLAG_CANTUSE)) {
3265 mem_realloc (&key_table, sizeof (crypt_key_t *) * keymax);
3271 if (!i && unusable) {
3272 mutt_error _("All matching keys are marked expired/revoked.");
3278 switch (PgpSortKeys & SORT_MASK) {
3280 f = crypt_compare_date;
3283 f = crypt_compare_keyid;
3286 f = crypt_compare_address;
3290 f = crypt_compare_trust;
3293 qsort (key_table, i, sizeof (crypt_key_t *), f);
3295 if (app & APPLICATION_PGP)
3296 menu_to_use = MENU_KEY_SELECT_PGP;
3297 else if (app & APPLICATION_SMIME)
3298 menu_to_use = MENU_KEY_SELECT_SMIME;
3301 mutt_make_help (buf, sizeof (buf), _("Exit "), menu_to_use, OP_EXIT);
3302 strcat (helpstr, buf); /* __STRCAT_CHECKED__ */
3303 mutt_make_help (buf, sizeof (buf), _("Select "), menu_to_use,
3304 OP_GENERIC_SELECT_ENTRY);
3305 strcat (helpstr, buf); /* __STRCAT_CHECKED__ */
3306 mutt_make_help (buf, sizeof (buf), _("Check key "),
3307 menu_to_use, OP_VERIFY_KEY);
3308 strcat (helpstr, buf); /* __STRCAT_CHECKED__ */
3309 mutt_make_help (buf, sizeof (buf), _("Help"), menu_to_use, OP_HELP);
3310 strcat (helpstr, buf); /* __STRCAT_CHECKED__ */
3312 menu = mutt_new_menu ();
3314 menu->make_entry = crypt_entry;
3315 menu->menu = menu_to_use;
3316 menu->help = helpstr;
3317 menu->data = key_table;
3322 if ((app & APPLICATION_PGP) && (app & APPLICATION_SMIME))
3323 ts = _("PGP and S/MIME keys matching");
3324 else if ((app & APPLICATION_PGP))
3325 ts = _("PGP keys matching");
3326 else if ((app & APPLICATION_SMIME))
3327 ts = _("S/MIME keys matching");
3329 ts = _("keys matching");
3332 snprintf (buf, sizeof (buf), _("%s <%s>."), ts, p->mailbox);
3334 snprintf (buf, sizeof (buf), _("%s \"%s\"."), ts, s);
3338 mutt_clear_error ();
3342 switch (mutt_menuLoop (menu)) {
3344 verify_key (key_table[menu->current]);
3345 menu->redraw = REDRAW_FULL;
3349 mutt_message ("%s", key_table[menu->current]->uid);
3352 case OP_GENERIC_SELECT_ENTRY:
3353 /* FIXME make error reporting more verbose - this should be
3354 easy because gpgme provides more information */
3355 if (option (OPTPGPCHECKTRUST)) {
3356 if (!crypt_key_is_valid (key_table[menu->current])) {
3357 mutt_error _("This key can't be used: "
3358 "expired/disabled/revoked.");
3363 if (option (OPTPGPCHECKTRUST) &&
3364 (!crypt_id_is_valid (key_table[menu->current])
3365 || !crypt_id_is_strong (key_table[menu->current]))) {
3367 char buff[LONG_STRING];
3369 if (key_table[menu->current]->flags & KEYFLAG_CANTUSE)
3370 s = N_("ID is expired/disabled/revoked.");
3372 gpgme_validity_t val = GPGME_VALIDITY_UNKNOWN;
3373 gpgme_user_id_t uid = NULL;
3378 uid = key_table[menu->current]->kobj->uids;
3379 for (j = 0; (j < key_table[menu->current]->idx) && uid;
3380 j++, uid = uid->next);
3382 val = uid->validity;
3385 case GPGME_VALIDITY_UNKNOWN:
3386 case GPGME_VALIDITY_UNDEFINED:
3387 warn_s = N_("ID has undefined validity.");
3389 case GPGME_VALIDITY_NEVER:
3390 warn_s = N_("ID is not valid.");
3392 case GPGME_VALIDITY_MARGINAL:
3393 warn_s = N_("ID is only marginally valid.");
3395 case GPGME_VALIDITY_FULL:
3396 case GPGME_VALIDITY_ULTIMATE:
3400 snprintf (buff, sizeof (buff),
3401 _("%s Do you really want to use the key?"), _(warn_s));
3403 if (mutt_yesorno (buff, 0) != 1) {
3404 mutt_clear_error ();
3411 k = crypt_copy_key (key_table[menu->current]);
3422 mutt_menuDestroy (&menu);
3423 mem_free (&key_table);
3425 set_option (OPTNEEDREDRAW);
3430 static crypt_key_t *crypt_getkeybyaddr (ADDRESS * a, short abilities,
3431 unsigned int app, int *forced_valid)
3439 int this_key_has_strong;
3440 int this_key_has_weak;
3441 int this_key_has_invalid;
3444 crypt_key_t *keys, *k;
3445 crypt_key_t *the_valid_key = NULL;
3446 crypt_key_t *matches = NULL;
3447 crypt_key_t **matches_endp = &matches;
3451 if (a && a->mailbox)
3452 hints = crypt_add_string_to_hints (hints, a->mailbox);
3453 if (a && a->personal)
3454 hints = crypt_add_string_to_hints (hints, a->personal);
3456 mutt_message (_("Looking for keys matching \"%s\"..."), a->mailbox);
3457 keys = get_candidates (hints, app, (abilities & KEYFLAG_CANSIGN));
3459 mutt_free_list (&hints);
3464 debug_print (5, ("looking for %s <%s>.\n", a->personal, a->mailbox));
3466 for (k = keys; k; k = k->next) {
3467 debug_print (5, (" looking at key: %s `%.15s'\n", crypt_keyid (k), k->uid));
3469 if (abilities && !(k->flags & abilities)) {
3470 debug_print (5, (" insufficient abilities: Has %x, want %x\n", k->flags, abilities));
3474 this_key_has_weak = 0; /* weak but valid match */
3475 this_key_has_invalid = 0; /* invalid match */
3476 this_key_has_strong = 0; /* strong and valid match */
3477 match = 0; /* any match */
3479 r = rfc822_parse_adrlist (NULL, k->uid);
3480 for (p = r; p; p = p->next) {
3481 int validity = crypt_id_matches_addr (a, p, k);
3483 if (validity & CRYPT_KV_MATCH) /* something matches */
3486 /* is this key a strong candidate? */
3487 if ((validity & CRYPT_KV_VALID)
3488 && (validity & CRYPT_KV_STRONGID)
3489 && (validity & CRYPT_KV_ADDR)) {
3490 if (the_valid_key && the_valid_key != k)
3493 this_key_has_strong = 1;
3495 else if ((validity & CRYPT_KV_MATCH)
3496 && !(validity & CRYPT_KV_VALID))
3497 this_key_has_invalid = 1;
3498 else if ((validity & CRYPT_KV_MATCH)
3499 && (!(validity & CRYPT_KV_STRONGID)
3500 || !(validity & CRYPT_KV_ADDR)))
3501 this_key_has_weak = 1;
3503 rfc822_free_address (&r);
3508 if (!this_key_has_strong && this_key_has_invalid)
3510 if (!this_key_has_strong && this_key_has_weak)
3513 *matches_endp = tmp = crypt_copy_key (k);
3514 matches_endp = &tmp->next;
3515 the_valid_key = tmp;
3519 crypt_free_key (&keys);
3522 if (the_valid_key && !multi && !weak
3523 && !(invalid && option (OPTPGPSHOWUNUSABLE))) {
3525 * There was precisely one strong match on a valid ID, there
3526 * were no valid keys with weak matches, and we aren't
3527 * interested in seeing invalid keys.
3529 * Proceed without asking the user.
3531 k = crypt_copy_key (the_valid_key);
3535 * Else: Ask the user.
3537 k = crypt_select_key (matches, a, NULL, app, forced_valid);
3539 crypt_free_key (&matches);
3548 static crypt_key_t *crypt_getkeybystr (char *p, short abilities,
3549 unsigned int app, int *forced_valid)
3553 crypt_key_t *matches = NULL;
3554 crypt_key_t **matches_endp = &matches;
3558 mutt_message (_("Looking for keys matching \"%s\"..."), p);
3562 hints = crypt_add_string_to_hints (hints, p);
3563 keys = get_candidates (hints, app, (abilities & KEYFLAG_CANSIGN));
3564 mutt_free_list (&hints);
3569 for (k = keys; k; k = k->next) {
3570 if (abilities && !(k->flags & abilities))
3574 debug_print (5, ("matching \"%s\" against " "key %s, \"%s\":\n", p, crypt_keyid (k), k->uid));
3576 if (!*p || !str_casecmp (p, crypt_keyid (k))
3577 || (!str_ncasecmp (p, "0x", 2)
3578 && !str_casecmp (p + 2, crypt_keyid (k)))
3579 || (option (OPTPGPLONGIDS)
3580 && !str_ncasecmp (p, "0x", 2)
3581 && !str_casecmp (p + 2, crypt_keyid (k) + 8))
3582 || str_isstr (k->uid, p)) {
3585 debug_print (5, ("match.\n"));
3587 *matches_endp = tmp = crypt_copy_key (k);
3588 matches_endp = &tmp->next;
3592 crypt_free_key (&keys);
3595 k = crypt_select_key (matches, NULL, p, app, forced_valid);
3596 crypt_free_key (&matches);
3603 /* Display TAG as a prompt to ask for a key. If WHATFOR is not null
3604 use it as default and store it under that label as the next
3605 default. ABILITIES describe the required key abilities (sign,
3606 encrypt) and APP the type of the requested key; ether S/MIME or
3607 PGP. Return a copy of the key or NULL if not found. */
3608 static crypt_key_t *crypt_ask_for_key (char *tag,
3611 unsigned int app, int *forced_valid)
3614 char resp[SHORT_STRING];
3615 struct crypt_cache *l = NULL;
3619 forced_valid = &dummy;
3621 mutt_clear_error ();
3627 for (l = id_defaults; l; l = l->next)
3628 if (!str_casecmp (whatfor, l->what)) {
3629 strfcpy (resp, NONULL (l->dflt), sizeof (resp));
3637 if (mutt_get_field (tag, resp, sizeof (resp), M_CLEAR) != 0)
3642 str_replace (&l->dflt, resp);
3644 l = mem_malloc (sizeof (struct crypt_cache));
3645 l->next = id_defaults;
3647 l->what = str_dup (whatfor);
3648 l->dflt = str_dup (resp);
3652 if ((key = crypt_getkeybystr (resp, abilities, app, forced_valid)))
3660 /* This routine attempts to find the keyids of the recipients of a
3661 message. It returns NULL if any of the keys can not be found. */
3662 static char *find_keys (ADDRESS * to, ADDRESS * cc, ADDRESS * bcc,
3665 char *keyID, *keylist = NULL, *t;
3666 size_t keylist_size = 0;
3667 size_t keylist_used = 0;
3668 ADDRESS *tmp = NULL, *addr = NULL;
3669 ADDRESS **last = &tmp;
3672 crypt_key_t *k_info, *key;
3673 const char *fqdn = mutt_fqdn (1);
3676 *r_application = APPLICATION_PGP | APPLICATION_SMIME;
3679 for (i = 0; i < 3; i++) {
3694 *last = rfc822_cpy_adr (p);
3696 last = &((*last)->next);
3700 rfc822_qualify (tmp, fqdn);
3702 tmp = mutt_remove_duplicates (tmp);
3704 for (p = tmp; p; p = p->next) {
3705 char buf[LONG_STRING];
3706 int forced_valid = 0;
3711 if ((keyID = mutt_crypt_hook (p)) != NULL) {
3714 snprintf (buf, sizeof (buf), _("Use keyID = \"%s\" for %s?"),
3716 if ((r = mutt_yesorno (buf, M_YES)) == M_YES) {
3717 /* check for e-mail address */
3718 if ((t = strchr (keyID, '@')) &&
3719 (addr = rfc822_parse_adrlist (NULL, keyID))) {
3721 rfc822_qualify (addr, fqdn);
3726 k_info = crypt_getkeybystr (keyID, KEYFLAG_CANENCRYPT,
3727 *r_application, &forced_valid);
3729 k_info = crypt_getkeybystr (keyID, KEYFLAG_CANENCRYPT,
3730 app, &forced_valid);
3735 mem_free (&keylist);
3736 rfc822_free_address (&tmp);
3737 rfc822_free_address (&addr);
3743 && (k_info = crypt_getkeybyaddr (q, KEYFLAG_CANENCRYPT,
3744 app, &forced_valid)) == NULL) {
3745 snprintf (buf, sizeof (buf), _("Enter keyID for %s: "), q->mailbox);
3747 if ((key = crypt_ask_for_key (buf, q->mailbox, KEYFLAG_CANENCRYPT,
3753 &forced_valid)) == NULL) {
3754 mem_free (&keylist);
3755 rfc822_free_address (&tmp);
3756 rfc822_free_address (&addr);
3764 const char *s = crypt_fpr (key);
3767 if (key->flags & KEYFLAG_ISX509)
3768 *r_application &= ~APPLICATION_PGP;
3769 if (!(key->flags & KEYFLAG_ISX509))
3770 *r_application &= ~APPLICATION_SMIME;
3773 keylist_size += str_len (s) + 4 + 1;
3774 mem_realloc (&keylist, keylist_size);
3775 sprintf (keylist + keylist_used, "%s0x%s%s", /* __SPRINTF_CHECKED__ */
3776 keylist_used ? " " : "", s, forced_valid ? "!" : "");
3778 keylist_used = str_len (keylist);
3780 crypt_free_key (&key);
3781 rfc822_free_address (&addr);
3783 rfc822_free_address (&tmp);
3787 char *pgp_gpgme_findkeys (ADDRESS * to, ADDRESS * cc, ADDRESS * bcc)
3789 return find_keys (to, cc, bcc, APPLICATION_PGP);
3792 char *smime_gpgme_findkeys (ADDRESS * to, ADDRESS * cc, ADDRESS * bcc)
3794 return find_keys (to, cc, bcc, APPLICATION_SMIME);
3798 * Implementation of `init'.
3801 /* Initialization. */
3802 static void init_gpgme (void)
3804 /* Make sure that gpg-agent is running. */
3805 if (!getenv ("GPG_AGENT_INFO")) {
3806 mutt_error ("\nUsing GPGME backend, although no gpg-agent is running");
3807 if (mutt_any_key_to_continue (NULL) == -1)
3812 void pgp_gpgme_init (void)
3817 void smime_gpgme_init (void)
3821 static int gpgme_send_menu (HEADER * msg, int *redraw, int is_smime)
3824 char input_signas[SHORT_STRING];
3827 if (msg->security & APPLICATION_PGP)
3829 else if (msg->security & APPLICATION_SMIME)
3834 mutt_multi_choice (_
3835 ("S/MIME (e)ncrypt, (s)ign, sign (a)s, (b)oth, (p)gp or (c)lear?"),
3839 mutt_multi_choice (_
3840 ("PGP (e)ncrypt, (s)ign, sign (a)s, (b)oth, s/(m)ime or (c)lear?"),
3844 case 1: /* (e)ncrypt */
3845 msg->security |= (is_smime ? SMIMEENCRYPT : PGPENCRYPT);
3846 msg->security &= ~(is_smime ? SMIMESIGN : PGPSIGN);
3849 case 2: /* (s)ign */
3850 msg->security |= (is_smime ? SMIMESIGN : PGPSIGN);
3851 msg->security &= ~(is_smime ? SMIMEENCRYPT : PGPENCRYPT);
3854 case 3: /* sign (a)s */
3855 /* unset_option(OPTCRYPTCHECKTRUST); */
3856 if ((p = crypt_ask_for_key (_("Sign as: "), NULL, KEYFLAG_CANSIGN,
3857 is_smime ? APPLICATION_SMIME :
3858 APPLICATION_PGP, NULL))) {
3859 snprintf (input_signas, sizeof (input_signas), "0x%s", crypt_keyid (p));
3860 str_replace (is_smime ? &SmimeDefaultKey : &PgpSignAs,
3862 crypt_free_key (&p);
3864 msg->security |= (is_smime ? SMIMESIGN : PGPSIGN);
3868 msg->security &= (is_smime ? ~SMIMESIGN : ~PGPSIGN);
3871 *redraw = REDRAW_FULL;
3874 case 4: /* (b)oth */
3876 (is_smime ? (SMIMEENCRYPT | SMIMESIGN) : (PGPENCRYPT | PGPSIGN));
3879 case 5: /* (p)gp or s/(m)ime */
3880 is_smime = !is_smime;
3883 case 6: /* (c)lear */
3888 if (choice == 6 || choice == 7);
3889 else if (is_smime) {
3890 msg->security &= ~APPLICATION_PGP;
3891 msg->security |= APPLICATION_SMIME;
3894 msg->security &= ~APPLICATION_SMIME;
3895 msg->security |= APPLICATION_PGP;
3898 return (msg->security);
3901 int pgp_gpgme_send_menu (HEADER * msg, int *redraw)
3903 return gpgme_send_menu (msg, redraw, 0);
3906 int smime_gpgme_send_menu (HEADER * msg, int *redraw)
3908 return gpgme_send_menu (msg, redraw, 1);
3911 static int verify_sender (HEADER * h, gpgme_protocol_t protocol)
3913 ADDRESS *sender = NULL;
3914 unsigned int ret = 1;
3917 h->env->from = mutt_expand_aliases (h->env->from);
3918 sender = h->env->from;
3920 else if (h->env->sender) {
3921 h->env->sender = mutt_expand_aliases (h->env->sender);
3922 sender = h->env->sender;
3926 if (signature_key) {
3927 gpgme_key_t key = signature_key;
3928 gpgme_user_id_t uid = NULL;
3929 int sender_length = 0;
3932 sender_length = str_len (sender->mailbox);
3933 for (uid = key->uids; uid && ret; uid = uid->next) {
3934 uid_length = str_len (uid->email);
3935 if (1 && (uid->email[0] == '<')
3936 && (uid->email[uid_length - 1] == '>')
3937 && (uid_length == sender_length + 2)
3938 && (!strncmp (uid->email + 1, sender->mailbox, sender_length)))
3943 mutt_any_key_to_continue ("Failed to verify sender");
3946 mutt_any_key_to_continue ("Failed to figure out sender");
3948 if (signature_key) {
3949 gpgme_key_release (signature_key);
3950 signature_key = NULL;
3956 int smime_gpgme_verify_sender (HEADER * h)
3958 return verify_sender (h, GPGME_PROTOCOL_CMS);