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 int 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;
1778 gpgme_error_t err = 0;
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"));
1996 * Implementation of `encrypted_handler'.
1999 /* MIME handler for pgp/mime encrypted messages. */
2000 int pgp_gpgme_encrypted_handler (BODY * a, STATE * s)
2002 char tempfile[_POSIX_PATH_MAX];
2005 BODY *orig_body = a;
2009 debug_print (2, ("Entering pgp_encrypted handler\n"));
2011 if (!a || a->type != TYPEAPPLICATION || !a->subtype
2012 || ascii_strcasecmp ("pgp-encrypted", a->subtype)
2013 || !a->next || a->next->type != TYPEAPPLICATION || !a->next->subtype
2014 || ascii_strcasecmp ("octet-stream", a->next->subtype)) {
2015 if (s->flags & M_DISPLAY)
2016 state_attach_puts (_("[-- Error: malformed PGP/MIME message! --]\n\n"),
2021 /* Move forward to the application/pgp-encrypted body. */
2024 mutt_mktemp (tempfile);
2025 if (!(fpout = safe_fopen (tempfile, "w+"))) {
2026 if (s->flags & M_DISPLAY)
2027 state_attach_puts (_("[-- Error: could not create temporary file! "
2032 tattach = decrypt_part (a, s, fpout, 0, &is_signed);
2034 tattach->goodsig = is_signed > 0;
2036 if (s->flags & M_DISPLAY)
2037 state_attach_puts (is_signed ?
2039 ("[-- The following data is PGP/MIME signed and encrypted --]\n\n") :
2040 _("[-- The following data is PGP/MIME encrypted --]\n\n"), s);
2043 FILE *savefp = s->fpin;
2046 rc = mutt_body_handler (tattach, s);
2051 * if a multipart/signed is the _only_ sub-part of a
2052 * multipart/encrypted, cache signature verification
2055 if (mutt_is_multipart_signed (tattach) && !tattach->next)
2056 orig_body->goodsig |= tattach->goodsig;
2058 if (s->flags & M_DISPLAY) {
2059 state_puts ("\n", s);
2060 state_attach_puts (is_signed ?
2062 ("[-- End of PGP/MIME signed and encrypted data --]\n")
2063 : _("[-- End of PGP/MIME encrypted data --]\n"), s);
2066 mutt_free_body (&tattach);
2070 mutt_unlink (tempfile);
2071 debug_print (2, ("Leaving pgp_encrypted handler\n"));
2075 /* Support for application/smime */
2076 int 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") :
2102 _("[-- The following data is S/MIME encrypted --]\n\n"), s);
2105 FILE *savefp = s->fpin;
2108 rc = mutt_body_handler (tattach, s);
2113 * if a multipart/signed is the _only_ sub-part of a
2114 * multipart/encrypted, cache signature verification
2117 if (mutt_is_multipart_signed (tattach) && !tattach->next) {
2118 if (!(a->goodsig = tattach->goodsig))
2119 a->warnsig = tattach->warnsig;
2121 else if (tattach->goodsig) {
2123 a->warnsig = tattach->warnsig;
2126 if (s->flags & M_DISPLAY) {
2127 state_puts ("\n", s);
2128 state_attach_puts (is_signed ?
2129 _("[-- End of S/MIME signed data --]\n") :
2130 _("[-- End of S/MIME encrypted data --]\n"), s);
2133 mutt_free_body (&tattach);
2137 mutt_unlink (tempfile);
2138 debug_print (2, ("Leaving smime_encrypted handler\n"));
2144 * Format an entry on the CRYPT key selection menu.
2147 * %k key id %K key id of the principal key
2149 * %a algorithm %A algorithm of the princ. key
2150 * %l length %L length of the princ. key
2151 * %f flags %F flags of the princ. key
2152 * %c capabilities %C capabilities of the princ. key
2153 * %t trust/validity of the key-uid association
2155 * %[...] date of key using strftime(3)
2158 static const char *crypt_entry_fmt (char *dest,
2163 const char *ifstring,
2164 const char *elsestring,
2165 unsigned long data, format_flag flags)
2168 crypt_entry_t *entry;
2171 int optional = (flags & M_FORMAT_OPTIONAL);
2172 const char *s = NULL;
2175 entry = (crypt_entry_t *) data;
2178 /* if (isupper ((unsigned char) op)) */
2181 kflags = (key->flags /*| (pkey->flags & KEYFLAG_RESTRICTIONS)
2184 switch (ascii_tolower (op)) {
2188 char buf2[SHORT_STRING], *p;
2204 while (len > 0 && *cp != ']') {
2213 break; /* not enough space */
2223 if (do_locales && Locale)
2224 setlocale (LC_TIME, Locale);
2229 if (key->kobj->subkeys && (key->kobj->subkeys->timestamp > 0))
2230 tt = key->kobj->subkeys->timestamp;
2232 tm = localtime (&tt);
2234 strftime (buf2, sizeof (buf2), dest, tm);
2237 setlocale (LC_TIME, "C");
2239 snprintf (fmt, sizeof (fmt), "%%%ss", prefix);
2240 snprintf (dest, destlen, fmt, buf2);
2247 snprintf (fmt, sizeof (fmt), "%%%sd", prefix);
2248 snprintf (dest, destlen, fmt, entry->num);
2253 /* fixme: we need a way to distinguish between main and subkeys.
2254 Store the idx in entry? */
2255 snprintf (fmt, sizeof (fmt), "%%%ss", prefix);
2256 snprintf (dest, destlen, fmt, crypt_keyid (key));
2261 snprintf (fmt, sizeof (fmt), "%%%ss", prefix);
2262 snprintf (dest, destlen, fmt, key->uid);
2267 snprintf (fmt, sizeof (fmt), "%%%s.3s", prefix);
2268 if (key->kobj->subkeys)
2269 s = gpgme_pubkey_algo_name (key->kobj->subkeys->pubkey_algo);
2272 snprintf (dest, destlen, fmt, s);
2277 snprintf (fmt, sizeof (fmt), "%%%slu", prefix);
2278 if (key->kobj->subkeys)
2279 val = key->kobj->subkeys->length;
2282 snprintf (dest, destlen, fmt, val);
2287 snprintf (fmt, sizeof (fmt), "%%%sc", prefix);
2288 snprintf (dest, destlen, fmt, crypt_flags (kflags));
2290 else if (!(kflags & (KEYFLAG_RESTRICTIONS)))
2295 snprintf (fmt, sizeof (fmt), "%%%ss", prefix);
2296 snprintf (dest, destlen, fmt, crypt_key_abilities (kflags));
2298 else if (!(kflags & (KEYFLAG_ABILITIES)))
2302 if ((kflags & KEYFLAG_ISX509))
2305 gpgme_user_id_t uid = NULL;
2308 for (i = 0, uid = key->kobj->uids; uid && (i < key->idx);
2309 i++, uid = uid->next);
2311 switch (uid->validity) {
2312 case GPGME_VALIDITY_UNDEFINED:
2315 case GPGME_VALIDITY_NEVER:
2318 case GPGME_VALIDITY_MARGINAL:
2321 case GPGME_VALIDITY_FULL:
2324 case GPGME_VALIDITY_ULTIMATE:
2327 case GPGME_VALIDITY_UNKNOWN:
2333 snprintf (fmt, sizeof (fmt), "%%%sc", prefix);
2334 snprintf (dest, destlen, fmt, s ? *s : 'B');
2337 snprintf (fmt, sizeof (fmt), "%%%ss", prefix);
2338 snprintf (dest, destlen, fmt,
2339 gpgme_get_protocol_name (key->kobj->protocol));
2347 mutt_FormatString (dest, destlen, ifstring, mutt_attach_fmt, data, 0);
2348 else if (flags & M_FORMAT_OPTIONAL)
2349 mutt_FormatString (dest, destlen, elsestring, mutt_attach_fmt, data, 0);
2353 /* Used by the display fucntion to format a line. */
2354 static void crypt_entry (char *s, size_t l, MUTTMENU * menu, int num)
2356 crypt_key_t **key_table = (crypt_key_t **) menu->data;
2357 crypt_entry_t entry;
2359 entry.key = key_table[num];
2360 entry.num = num + 1;
2362 mutt_FormatString (s, l, NONULL (PgpEntryFormat), crypt_entry_fmt,
2363 (unsigned long) &entry, M_FORMAT_ARROWCURSOR);
2366 /* Compare two addresses and the keyid to be used for sorting. */
2367 static int _crypt_compare_address (const void *a, const void *b)
2369 crypt_key_t **s = (crypt_key_t **) a;
2370 crypt_key_t **t = (crypt_key_t **) b;
2373 if ((r = str_casecmp ((*s)->uid, (*t)->uid)))
2376 return str_casecmp (crypt_keyid (*s), crypt_keyid (*t)) > 0;
2379 static int crypt_compare_address (const void *a, const void *b)
2381 return ((PgpSortKeys & SORT_REVERSE) ? !_crypt_compare_address (a, b)
2382 : _crypt_compare_address (a, b));
2386 /* Compare two key IDs and the addresses to be used for sorting. */
2387 static int _crypt_compare_keyid (const void *a, const void *b)
2389 crypt_key_t **s = (crypt_key_t **) a;
2390 crypt_key_t **t = (crypt_key_t **) b;
2393 if ((r = str_casecmp (crypt_keyid (*s), crypt_keyid (*t))))
2396 return str_casecmp ((*s)->uid, (*t)->uid) > 0;
2399 static int crypt_compare_keyid (const void *a, const void *b)
2401 return ((PgpSortKeys & SORT_REVERSE) ? !_crypt_compare_keyid (a, b)
2402 : _crypt_compare_keyid (a, b));
2405 /* Compare 2 creation dates and the addresses. For sorting. */
2406 static int _crypt_compare_date (const void *a, const void *b)
2408 crypt_key_t **s = (crypt_key_t **) a;
2409 crypt_key_t **t = (crypt_key_t **) b;
2410 unsigned long ts = 0, tt = 0;
2412 if ((*s)->kobj->subkeys && ((*s)->kobj->subkeys->timestamp > 0))
2413 ts = (*s)->kobj->subkeys->timestamp;
2414 if ((*t)->kobj->subkeys && ((*t)->kobj->subkeys->timestamp > 0))
2415 tt = (*t)->kobj->subkeys->timestamp;
2422 return str_casecmp ((*s)->uid, (*t)->uid) > 0;
2425 static int crypt_compare_date (const void *a, const void *b)
2427 return ((PgpSortKeys & SORT_REVERSE) ? !_crypt_compare_date (a, b)
2428 : _crypt_compare_date (a, b));
2431 /* Compare two trust values, the key length, the creation dates. the
2432 addresses and the key IDs. For sorting. */
2433 static int _crypt_compare_trust (const void *a, const void *b)
2435 crypt_key_t **s = (crypt_key_t **) a;
2436 crypt_key_t **t = (crypt_key_t **) b;
2437 unsigned long ts = 0, tt = 0;
2440 if ((r = (((*s)->flags & (KEYFLAG_RESTRICTIONS))
2441 - ((*t)->flags & (KEYFLAG_RESTRICTIONS)))))
2444 if ((*s)->kobj->uids)
2445 ts = (*s)->kobj->uids->validity;
2446 if ((*t)->kobj->uids)
2447 tt = (*t)->kobj->uids->validity;
2448 if ((r = (tt - ts)))
2451 if ((*s)->kobj->subkeys)
2452 ts = (*s)->kobj->subkeys->length;
2453 if ((*t)->kobj->subkeys)
2454 tt = (*t)->kobj->subkeys->length;
2458 if ((*s)->kobj->subkeys && ((*s)->kobj->subkeys->timestamp > 0))
2459 ts = (*s)->kobj->subkeys->timestamp;
2460 if ((*t)->kobj->subkeys && ((*t)->kobj->subkeys->timestamp > 0))
2461 tt = (*t)->kobj->subkeys->timestamp;
2467 if ((r = str_casecmp ((*s)->uid, (*t)->uid)))
2469 return (str_casecmp (crypt_keyid ((*s)), crypt_keyid ((*t)))) > 0;
2472 static int crypt_compare_trust (const void *a, const void *b)
2474 return ((PgpSortKeys & SORT_REVERSE) ? !_crypt_compare_trust (a, b)
2475 : _crypt_compare_trust (a, b));
2478 /* Print the X.500 Distinguished Name part KEY from the array of parts
2480 static int print_dn_part (FILE * fp, struct dn_array_s *dn, const char *key)
2484 for (; dn->key; dn++) {
2485 if (!str_cmp (dn->key, key)) {
2488 print_utf8 (fp, dn->value, str_len (dn->value));
2495 /* Print all parts of a DN in a standard sequence. */
2496 static void print_dn_parts (FILE * fp, struct dn_array_s *dn)
2498 const char *stdpart[] = {
2499 "CN", "OU", "O", "STREET", "L", "ST", "C", NULL
2501 int any = 0, any2 = 0, i;
2503 for (i = 0; stdpart[i]; i++) {
2506 any = print_dn_part (fp, dn, stdpart[i]);
2508 /* now print the rest without any specific ordering */
2509 for (; dn->key; dn++) {
2510 for (i = 0; stdpart[i]; i++) {
2511 if (!str_cmp (dn->key, stdpart[i]))
2519 any = print_dn_part (fp, dn, dn->key);
2528 /* Parse an RDN; this is a helper to parse_dn(). */
2529 static const unsigned char *parse_dn_part (struct dn_array_s *array,
2530 const unsigned char *string)
2532 const unsigned char *s, *s1;
2536 /* parse attributeType */
2537 for (s = string + 1; *s && *s != '='; s++);
2539 return NULL; /* error */
2542 return NULL; /* empty key */
2543 array->key = mem_malloc (n + 1);
2544 p = (unsigned char *) array->key;
2545 memcpy (p, string, n); /* fixme: trim trailing spaces */
2549 if (*string == '#') { /* hexstring */
2551 for (s = string; hexdigitp (s); s++)
2555 return NULL; /* empty or odd number of digits */
2557 p = mem_malloc (n + 1);
2558 array->value = (char *) p;
2559 for (s1 = string; n; s1 += 2, n--)
2563 else { /* regular v3 quoted string */
2564 for (n = 0, s = string; *s; s++) {
2565 if (*s == '\\') { /* pair */
2567 if (*s == ',' || *s == '=' || *s == '+'
2568 || *s == '<' || *s == '>' || *s == '#' || *s == ';'
2569 || *s == '\\' || *s == '\"' || *s == ' ')
2571 else if (hexdigitp (s) && hexdigitp (s + 1)) {
2576 return NULL; /* invalid escape sequence */
2578 else if (*s == '\"')
2579 return NULL; /* invalid encoding */
2580 else if (*s == ',' || *s == '=' || *s == '+'
2581 || *s == '<' || *s == '>' || *s == '#' || *s == ';')
2587 p = mem_malloc (n + 1);
2588 array->value = (char *) p;
2589 for (s = string; n; s++, n--) {
2592 if (hexdigitp (s)) {
2608 /* Parse a DN and return an array-ized one. This is not a validating
2609 parser and it does not support any old-stylish syntax; gpgme is
2610 expected to return only rfc2253 compatible strings. */
2611 static struct dn_array_s *parse_dn (const unsigned char *string)
2613 struct dn_array_s *array;
2614 size_t arrayidx, arraysize;
2617 arraysize = 7; /* C,ST,L,O,OU,CN,email */
2618 array = mem_malloc ((arraysize + 1) * sizeof *array);
2621 while (*string == ' ')
2625 if (arrayidx >= arraysize) { /* mutt lacks a real safe_realoc - so we need to copy */
2626 struct dn_array_s *a2;
2629 a2 = mem_malloc ((arraysize + 1) * sizeof *array);
2630 for (i = 0; i < arrayidx; i++) {
2631 a2[i].key = array[i].key;
2632 a2[i].value = array[i].value;
2637 array[arrayidx].key = NULL;
2638 array[arrayidx].value = NULL;
2639 string = parse_dn_part (array + arrayidx, string);
2643 while (*string == ' ')
2645 if (*string && *string != ',' && *string != ';' && *string != '+')
2646 goto failure; /* invalid delimiter */
2650 array[arrayidx].key = NULL;
2651 array[arrayidx].value = NULL;
2655 for (i = 0; i < arrayidx; i++) {
2656 mem_free (&array[i].key);
2657 mem_free (&array[i].value);
2664 /* Print a nice representation of the USERID and make sure it is
2665 displayed in a proper way, which does mean to reorder some parts
2666 for S/MIME's DNs. USERID is a string as returned by the gpgme key
2667 functions. It is utf-8 encoded. */
2668 static void parse_and_print_user_id (FILE * fp, const char *userid)
2673 if (*userid == '<') {
2674 s = strchr (userid + 1, '>');
2676 print_utf8 (fp, userid + 1, s - userid - 1);
2678 else if (*userid == '(')
2679 fputs (_("[Can't display this user ID (unknown encoding)]"), fp);
2680 else if (!digit_or_letter ((const unsigned char *) userid))
2681 fputs (_("[Can't display this user ID (invalid encoding)]"), fp);
2683 struct dn_array_s *dn = parse_dn ((const unsigned char *) userid);
2686 fputs (_("[Can't display this user ID (invalid DN)]"), fp);
2688 print_dn_parts (fp, dn);
2689 for (i = 0; dn[i].key; i++) {
2690 mem_free (&dn[i].key);
2691 mem_free (&dn[i].value);
2699 KEY_CAP_CAN_ENCRYPT,
2704 static unsigned int key_check_cap (gpgme_key_t key, key_cap_t cap)
2706 gpgme_subkey_t subkey = NULL;
2707 unsigned int ret = 0;
2710 case KEY_CAP_CAN_ENCRYPT:
2711 if (!(ret = key->can_encrypt))
2712 for (subkey = key->subkeys; subkey; subkey = subkey->next)
2713 if ((ret = subkey->can_encrypt))
2716 case KEY_CAP_CAN_SIGN:
2717 if (!(ret = key->can_sign))
2718 for (subkey = key->subkeys; subkey; subkey = subkey->next)
2719 if ((ret = subkey->can_sign))
2722 case KEY_CAP_CAN_CERTIFY:
2723 if (!(ret = key->can_certify))
2724 for (subkey = key->subkeys; subkey; subkey = subkey->next)
2725 if ((ret = subkey->can_certify))
2734 /* Print verbose information about a key or certificate to FP. */
2735 static void print_key_info (gpgme_key_t key, FILE * fp)
2738 const char *s = NULL, *s2 = NULL;
2741 char shortbuf[SHORT_STRING];
2742 unsigned long aval = 0;
2746 gpgme_user_id_t uid = NULL;
2749 setlocale (LC_TIME, Locale);
2751 is_pgp = key->protocol == GPGME_PROTOCOL_OpenPGP;
2753 for (idx = 0, uid = key->uids; uid; idx++, uid = uid->next) {
2758 fputs (idx ? _(" aka ......: ") :_("Name ......: "), fp);
2761 fputs (_("[Invalid]"), fp);
2765 print_utf8 (fp, s, str_len (s));
2767 parse_and_print_user_id (fp, s);
2771 if (key->subkeys && (key->subkeys->timestamp > 0)) {
2772 tt = key->subkeys->timestamp;
2774 tm = localtime (&tt);
2775 #ifdef HAVE_LANGINFO_D_T_FMT
2776 strftime (shortbuf, sizeof shortbuf, nl_langinfo (D_T_FMT), tm);
2778 strftime (shortbuf, sizeof shortbuf, "%c", tm);
2780 fprintf (fp, _("Valid From : %s\n"), shortbuf);
2783 if (key->subkeys && (key->subkeys->expires > 0)) {
2784 tt = key->subkeys->expires;
2786 tm = localtime (&tt);
2787 #ifdef HAVE_LANGINFO_D_T_FMT
2788 strftime (shortbuf, sizeof shortbuf, nl_langinfo (D_T_FMT), tm);
2790 strftime (shortbuf, sizeof shortbuf, "%c", tm);
2792 fprintf (fp, _("Valid To ..: %s\n"), shortbuf);
2796 s = gpgme_pubkey_algo_name (key->subkeys->pubkey_algo);
2800 s2 = is_pgp ? "PGP" : "X.509";
2803 aval = key->subkeys->length;
2805 fprintf (fp, _("Key Type ..: %s, %lu bit %s\n"), s2, aval, s);
2807 fprintf (fp, _("Key Usage .: "));
2810 if (key_check_cap (key, KEY_CAP_CAN_ENCRYPT)) {
2811 fprintf (fp, "%s%s", delim, _("encryption"));
2814 if (key_check_cap (key, KEY_CAP_CAN_SIGN)) {
2815 fprintf (fp, "%s%s", delim, _("signing"));
2818 if (key_check_cap (key, KEY_CAP_CAN_CERTIFY)) {
2819 fprintf (fp, "%s%s", delim, _("certification"));
2825 s = key->subkeys->fpr;
2826 fputs (_("Fingerprint: "), fp);
2827 if (is_pgp && str_len (s) == 40) {
2828 for (i = 0; *s && s[1] && s[2] && s[3] && s[4]; s += 4, i++) {
2833 putc (is_pgp ? ' ' : ':', fp);
2834 if (is_pgp && i == 4)
2839 for (i = 0; *s && s[1] && s[2]; s += 2, i++) {
2842 putc (is_pgp ? ' ' : ':', fp);
2843 if (is_pgp && i == 7)
2847 fprintf (fp, "%s\n", s);
2850 if (key->issuer_serial) {
2851 s = key->issuer_serial;
2853 fprintf (fp, _("Serial-No .: 0x%s\n"), s);
2856 if (key->issuer_name) {
2857 s = key->issuer_name;
2859 fprintf (fp, _("Issued By .: "));
2860 parse_and_print_user_id (fp, s);
2865 /* For PGP we list all subkeys. */
2867 gpgme_subkey_t subkey = NULL;
2869 for (idx = 1, subkey = key->subkeys; subkey; idx++, subkey = subkey->next) {
2873 if (str_len (s) == 16)
2874 s += 8; /* display only the short keyID */
2875 fprintf (fp, _("Subkey ....: 0x%s"), s);
2876 if (subkey->revoked) {
2878 fputs (_("[Revoked]"), fp);
2880 if (subkey->invalid) {
2882 fputs (_("[Invalid]"), fp);
2884 if (subkey->expired) {
2886 fputs (_("[Expired]"), fp);
2888 if (subkey->disabled) {
2890 fputs (_("[Disabled]"), fp);
2894 if (subkey->timestamp > 0) {
2895 tt = subkey->timestamp;
2897 tm = localtime (&tt);
2898 #ifdef HAVE_LANGINFO_D_T_FMT
2899 strftime (shortbuf, sizeof shortbuf, nl_langinfo (D_T_FMT), tm);
2901 strftime (shortbuf, sizeof shortbuf, "%c", tm);
2903 fprintf (fp, _("Valid From : %s\n"), shortbuf);
2906 if (subkey->expires > 0) {
2907 tt = subkey->expires;
2909 tm = localtime (&tt);
2910 #ifdef HAVE_LANGINFO_D_T_FMT
2911 strftime (shortbuf, sizeof shortbuf, nl_langinfo (D_T_FMT), tm);
2913 strftime (shortbuf, sizeof shortbuf, "%c", tm);
2915 fprintf (fp, _("Valid To ..: %s\n"), shortbuf);
2919 s = gpgme_pubkey_algo_name (subkey->pubkey_algo);
2924 aval = subkey->length;
2928 fprintf (fp, _("Key Type ..: %s, %lu bit %s\n"), "PGP", aval, s);
2930 fprintf (fp, _("Key Usage .: "));
2933 if (subkey->can_encrypt) {
2934 fprintf (fp, "%s%s", delim, _("encryption"));
2937 if (subkey->can_sign) {
2938 fprintf (fp, "%s%s", delim, _("signing"));
2941 if (subkey->can_certify) {
2942 fprintf (fp, "%s%s", delim, _("certification"));
2950 setlocale (LC_TIME, "C");
2954 /* Show detailed information about the selected key */
2955 static void verify_key (crypt_key_t * key)
2958 char cmd[LONG_STRING], tempfile[_POSIX_PATH_MAX];
2960 gpgme_ctx_t listctx = NULL;
2962 gpgme_key_t k = NULL;
2965 mutt_mktemp (tempfile);
2966 if (!(fp = safe_fopen (tempfile, "w"))) {
2967 mutt_perror (_("Can't create temporary file"));
2971 mutt_message _("Collecting data...");
2973 print_key_info (key->kobj, fp);
2975 err = gpgme_new (&listctx);
2977 fprintf (fp, "Internal error: can't create gpgme context: %s\n",
2978 gpgme_strerror (err));
2981 if ((key->flags & KEYFLAG_ISX509))
2982 gpgme_set_protocol (listctx, GPGME_PROTOCOL_CMS);
2986 while ((s = k->chain_id) && k->subkeys && str_cmp (s, k->subkeys->fpr)) {
2988 err = gpgme_op_keylist_start (listctx, s, 0);
2989 gpgme_key_release (k);
2992 err = gpgme_op_keylist_next (listctx, &k);
2994 fprintf (fp, _("Error finding issuer key: %s\n"), gpgme_strerror (err));
2997 gpgme_op_keylist_end (listctx);
2999 print_key_info (k, fp);
3002 fputs (_("Error: certification chain to long - stopping here\n"), fp);
3008 gpgme_key_release (k);
3009 gpgme_release (listctx);
3011 mutt_clear_error ();
3012 snprintf (cmd, sizeof (cmd), _("Key ID: 0x%s"), crypt_keyid (key));
3013 mutt_do_pager (cmd, tempfile, 0, NULL);
3017 * Implementation of `findkeys'.
3021 /* Convert LIST into a pattern string suitable to be passed to GPGME.
3022 We need to convert spaces in an item into a '+' and '%' into
3024 static char *list_to_pattern (LIST * list)
3032 for (l = list; l; l = l->next) {
3033 for (s = l->data; *s; s++) {
3038 n++; /* delimiter or end of string */
3040 n++; /* make sure to allocate at least one byte */
3041 pattern = p = mem_calloc (1, n);
3042 for (l = list; l; l = l->next) {
3047 for (s = l->data; *s; s++) {
3053 else if (*s == '+') {
3069 /* Return a list of keys which are candidates for the selection.
3070 Select by looking at the HINTS list. */
3071 static crypt_key_t *get_candidates (LIST * hints, unsigned int app,
3074 crypt_key_t *db, *k, **kend;
3080 gpgme_user_id_t uid = NULL;
3082 pattern = list_to_pattern (hints);
3086 err = gpgme_new (&ctx);
3088 mutt_error (_("gpgme_new failed: %s"), gpgme_strerror (err));
3089 mem_free (&pattern);
3096 if ((app & APPLICATION_PGP)) {
3097 /* Its all a mess. That old GPGME expects different things
3098 depending on the protocol. For gpg we don' t need percent
3099 escaped pappert but simple strings passed in an array to the
3100 keylist_ext_start function. */
3105 for (l = hints, n = 0; l; l = l->next) {
3106 if (l->data && *l->data)
3112 patarr = mem_calloc (n + 1, sizeof *patarr);
3113 for (l = hints, n = 0; l; l = l->next) {
3114 if (l->data && *l->data)
3115 patarr[n++] = str_dup (l->data);
3118 err = gpgme_op_keylist_ext_start (ctx, (const char **) patarr, secret, 0);
3119 for (n = 0; patarr[n]; n++)
3120 mem_free (&patarr[n]);
3123 mutt_error (_("gpgme_op_keylist_start failed: %s"), gpgme_strerror (err));
3124 gpgme_release (ctx);
3125 mem_free (&pattern);
3129 while (!(err = gpgme_op_keylist_next (ctx, &key))) {
3130 unsigned int flags = 0;
3132 if (key_check_cap (key, KEY_CAP_CAN_ENCRYPT))
3133 flags |= KEYFLAG_CANENCRYPT;
3134 if (key_check_cap (key, KEY_CAP_CAN_SIGN))
3135 flags |= KEYFLAG_CANSIGN;
3137 #if 0 /* DISABLED code */
3139 /* Bug in gpg. Capabilities are not listed for secret
3140 keys. Try to deduce them from the algorithm. */
3142 switch (key->subkeys[0].pubkey_algo) {
3144 flags |= KEYFLAG_CANENCRYPT;
3145 flags |= KEYFLAG_CANSIGN;
3147 case GPGME_PK_ELG_E:
3148 flags |= KEYFLAG_CANENCRYPT;
3151 flags |= KEYFLAG_CANSIGN;
3155 #endif /* DISABLED code */
3157 for (idx = 0, uid = key->uids; uid; idx++, uid = uid->next) {
3158 k = mem_calloc (1, sizeof *k);
3167 if (gpg_err_code (err) != GPG_ERR_EOF)
3168 mutt_error (_("gpgme_op_keylist_next failed: %s"), gpgme_strerror (err));
3169 gpgme_op_keylist_end (ctx);
3174 if ((app & APPLICATION_SMIME)) {
3175 /* and now look for x509 certificates */
3176 gpgme_set_protocol (ctx, GPGME_PROTOCOL_CMS);
3177 err = gpgme_op_keylist_start (ctx, pattern, 0);
3179 mutt_error (_("gpgme_op_keylist_start failed: %s"), gpgme_strerror (err));
3180 gpgme_release (ctx);
3181 mem_free (&pattern);
3185 while (!(err = gpgme_op_keylist_next (ctx, &key))) {
3186 unsigned int flags = KEYFLAG_ISX509;
3188 if (key_check_cap (key, KEY_CAP_CAN_ENCRYPT))
3189 flags |= KEYFLAG_CANENCRYPT;
3190 if (key_check_cap (key, KEY_CAP_CAN_SIGN))
3191 flags |= KEYFLAG_CANSIGN;
3193 for (idx = 0, uid = key->uids; uid; idx++, uid = uid->next) {
3194 k = mem_calloc (1, sizeof *k);
3203 if (gpg_err_code (err) != GPG_ERR_EOF)
3204 mutt_error (_("gpgme_op_keylist_next failed: %s"), gpgme_strerror (err));
3205 gpgme_op_keylist_end (ctx);
3208 gpgme_release (ctx);
3209 mem_free (&pattern);
3213 /* Add the string STR to the list HINTS. This list is later used to
3215 static LIST *crypt_add_string_to_hints (LIST * hints, const char *str)
3220 if ((scratch = str_dup (str)) == NULL)
3223 for (t = strtok (scratch, " ,.:\"()<>\n"); t;
3224 t = strtok (NULL, " ,.:\"()<>\n")) {
3225 if (str_len (t) > 3)
3226 hints = mutt_add_list (hints, t);
3229 mem_free (&scratch);
3233 /* Display a menu to select a key from the array KEYS. FORCED_VALID
3234 will be set to true on return if the user did override the the
3236 static crypt_key_t *crypt_select_key (crypt_key_t * keys,
3237 ADDRESS * p, const char *s,
3238 unsigned int app, int *forced_valid)
3241 crypt_key_t **key_table;
3244 char helpstr[SHORT_STRING], buf[LONG_STRING];
3246 int (*f) (const void *, const void *);
3247 int menu_to_use = 0;
3252 /* build the key table */
3255 for (k = keys; k; k = k->next) {
3256 if (!option (OPTPGPSHOWUNUSABLE) && (k->flags & KEYFLAG_CANTUSE)) {
3263 mem_realloc (&key_table, sizeof (crypt_key_t *) * keymax);
3269 if (!i && unusable) {
3270 mutt_error _("All matching keys are marked expired/revoked.");
3276 switch (PgpSortKeys & SORT_MASK) {
3278 f = crypt_compare_date;
3281 f = crypt_compare_keyid;
3284 f = crypt_compare_address;
3288 f = crypt_compare_trust;
3291 qsort (key_table, i, sizeof (crypt_key_t *), f);
3293 if (app & APPLICATION_PGP)
3294 menu_to_use = MENU_KEY_SELECT_PGP;
3295 else if (app & APPLICATION_SMIME)
3296 menu_to_use = MENU_KEY_SELECT_SMIME;
3299 mutt_make_help (buf, sizeof (buf), _("Exit "), menu_to_use, OP_EXIT);
3300 strcat (helpstr, buf); /* __STRCAT_CHECKED__ */
3301 mutt_make_help (buf, sizeof (buf), _("Select "), menu_to_use,
3302 OP_GENERIC_SELECT_ENTRY);
3303 strcat (helpstr, buf); /* __STRCAT_CHECKED__ */
3304 mutt_make_help (buf, sizeof (buf), _("Check key "),
3305 menu_to_use, OP_VERIFY_KEY);
3306 strcat (helpstr, buf); /* __STRCAT_CHECKED__ */
3307 mutt_make_help (buf, sizeof (buf), _("Help"), menu_to_use, OP_HELP);
3308 strcat (helpstr, buf); /* __STRCAT_CHECKED__ */
3310 menu = mutt_new_menu ();
3312 menu->make_entry = crypt_entry;
3313 menu->menu = menu_to_use;
3314 menu->help = helpstr;
3315 menu->data = key_table;
3320 if ((app & APPLICATION_PGP) && (app & APPLICATION_SMIME))
3321 ts = _("PGP and S/MIME keys matching");
3322 else if ((app & APPLICATION_PGP))
3323 ts = _("PGP keys matching");
3324 else if ((app & APPLICATION_SMIME))
3325 ts = _("S/MIME keys matching");
3327 ts = _("keys matching");
3330 snprintf (buf, sizeof (buf), _("%s <%s>."), ts, p->mailbox);
3332 snprintf (buf, sizeof (buf), _("%s \"%s\"."), ts, s);
3336 mutt_clear_error ();
3340 switch (mutt_menuLoop (menu)) {
3342 verify_key (key_table[menu->current]);
3343 menu->redraw = REDRAW_FULL;
3347 mutt_message ("%s", key_table[menu->current]->uid);
3350 case OP_GENERIC_SELECT_ENTRY:
3351 /* FIXME make error reporting more verbose - this should be
3352 easy because gpgme provides more information */
3353 if (option (OPTPGPCHECKTRUST)) {
3354 if (!crypt_key_is_valid (key_table[menu->current])) {
3355 mutt_error _("This key can't be used: "
3356 "expired/disabled/revoked.");
3361 if (option (OPTPGPCHECKTRUST) &&
3362 (!crypt_id_is_valid (key_table[menu->current])
3363 || !crypt_id_is_strong (key_table[menu->current]))) {
3365 char buff[LONG_STRING];
3367 if (key_table[menu->current]->flags & KEYFLAG_CANTUSE)
3368 s = N_("ID is expired/disabled/revoked.");
3370 gpgme_validity_t val = GPGME_VALIDITY_UNKNOWN;
3371 gpgme_user_id_t uid = NULL;
3376 uid = key_table[menu->current]->kobj->uids;
3377 for (j = 0; (j < key_table[menu->current]->idx) && uid;
3378 j++, uid = uid->next);
3380 val = uid->validity;
3383 case GPGME_VALIDITY_UNKNOWN:
3384 case GPGME_VALIDITY_UNDEFINED:
3385 warn_s = N_("ID has undefined validity.");
3387 case GPGME_VALIDITY_NEVER:
3388 warn_s = N_("ID is not valid.");
3390 case GPGME_VALIDITY_MARGINAL:
3391 warn_s = N_("ID is only marginally valid.");
3393 case GPGME_VALIDITY_FULL:
3394 case GPGME_VALIDITY_ULTIMATE:
3398 snprintf (buff, sizeof (buff),
3399 _("%s Do you really want to use the key?"), _(warn_s));
3401 if (mutt_yesorno (buff, 0) != 1) {
3402 mutt_clear_error ();
3409 k = crypt_copy_key (key_table[menu->current]);
3420 mutt_menuDestroy (&menu);
3421 mem_free (&key_table);
3423 set_option (OPTNEEDREDRAW);
3428 static crypt_key_t *crypt_getkeybyaddr (ADDRESS * a, short abilities,
3429 unsigned int app, int *forced_valid)
3437 int this_key_has_strong;
3438 int this_key_has_weak;
3439 int this_key_has_invalid;
3442 crypt_key_t *keys, *k;
3443 crypt_key_t *the_valid_key = NULL;
3444 crypt_key_t *matches = NULL;
3445 crypt_key_t **matches_endp = &matches;
3449 if (a && a->mailbox)
3450 hints = crypt_add_string_to_hints (hints, a->mailbox);
3451 if (a && a->personal)
3452 hints = crypt_add_string_to_hints (hints, a->personal);
3454 mutt_message (_("Looking for keys matching \"%s\"..."), a->mailbox);
3455 keys = get_candidates (hints, app, (abilities & KEYFLAG_CANSIGN));
3457 mutt_free_list (&hints);
3462 debug_print (5, ("looking for %s <%s>.\n", a->personal, a->mailbox));
3464 for (k = keys; k; k = k->next) {
3465 debug_print (5, (" looking at key: %s `%.15s'\n", crypt_keyid (k), k->uid));
3467 if (abilities && !(k->flags & abilities)) {
3468 debug_print (5, (" insufficient abilities: Has %x, want %x\n", k->flags, abilities));
3472 this_key_has_weak = 0; /* weak but valid match */
3473 this_key_has_invalid = 0; /* invalid match */
3474 this_key_has_strong = 0; /* strong and valid match */
3475 match = 0; /* any match */
3477 r = rfc822_parse_adrlist (NULL, k->uid);
3478 for (p = r; p; p = p->next) {
3479 int validity = crypt_id_matches_addr (a, p, k);
3481 if (validity & CRYPT_KV_MATCH) /* something matches */
3484 /* is this key a strong candidate? */
3485 if ((validity & CRYPT_KV_VALID)
3486 && (validity & CRYPT_KV_STRONGID)
3487 && (validity & CRYPT_KV_ADDR)) {
3488 if (the_valid_key && the_valid_key != k)
3491 this_key_has_strong = 1;
3493 else if ((validity & CRYPT_KV_MATCH)
3494 && !(validity & CRYPT_KV_VALID))
3495 this_key_has_invalid = 1;
3496 else if ((validity & CRYPT_KV_MATCH)
3497 && (!(validity & CRYPT_KV_STRONGID)
3498 || !(validity & CRYPT_KV_ADDR)))
3499 this_key_has_weak = 1;
3501 rfc822_free_address (&r);
3506 if (!this_key_has_strong && this_key_has_invalid)
3508 if (!this_key_has_strong && this_key_has_weak)
3511 *matches_endp = tmp = crypt_copy_key (k);
3512 matches_endp = &tmp->next;
3513 the_valid_key = tmp;
3517 crypt_free_key (&keys);
3520 if (the_valid_key && !multi && !weak
3521 && !(invalid && option (OPTPGPSHOWUNUSABLE))) {
3523 * There was precisely one strong match on a valid ID, there
3524 * were no valid keys with weak matches, and we aren't
3525 * interested in seeing invalid keys.
3527 * Proceed without asking the user.
3529 k = crypt_copy_key (the_valid_key);
3533 * Else: Ask the user.
3535 k = crypt_select_key (matches, a, NULL, app, forced_valid);
3537 crypt_free_key (&matches);
3546 static crypt_key_t *crypt_getkeybystr (char *p, short abilities,
3547 unsigned int app, int *forced_valid)
3551 crypt_key_t *matches = NULL;
3552 crypt_key_t **matches_endp = &matches;
3556 mutt_message (_("Looking for keys matching \"%s\"..."), p);
3560 hints = crypt_add_string_to_hints (hints, p);
3561 keys = get_candidates (hints, app, (abilities & KEYFLAG_CANSIGN));
3562 mutt_free_list (&hints);
3567 for (k = keys; k; k = k->next) {
3568 if (abilities && !(k->flags & abilities))
3572 debug_print (5, ("matching \"%s\" against " "key %s, \"%s\":\n", p, crypt_keyid (k), k->uid));
3574 if (!*p || !str_casecmp (p, crypt_keyid (k))
3575 || (!str_ncasecmp (p, "0x", 2)
3576 && !str_casecmp (p + 2, crypt_keyid (k)))
3577 || (option (OPTPGPLONGIDS)
3578 && !str_ncasecmp (p, "0x", 2)
3579 && !str_casecmp (p + 2, crypt_keyid (k) + 8))
3580 || str_isstr (k->uid, p)) {
3583 debug_print (5, ("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 (!str_casecmp (whatfor, l->what)) {
3627 strfcpy (resp, NONULL (l->dflt), sizeof (resp));
3635 if (mutt_get_field (tag, resp, sizeof (resp), M_CLEAR) != 0)
3640 str_replace (&l->dflt, resp);
3642 l = mem_malloc (sizeof (struct crypt_cache));
3643 l->next = id_defaults;
3645 l->what = str_dup (whatfor);
3646 l->dflt = str_dup (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);
3733 mem_free (&keylist);
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) {
3752 mem_free (&keylist);
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 += str_len (s) + 4 + 1;
3772 mem_realloc (&keylist, keylist_size);
3773 sprintf (keylist + keylist_used, "%s0x%s%s", /* __SPRINTF_CHECKED__ */
3774 keylist_used ? " " : "", s, forced_valid ? "!" : "");
3776 keylist_used = str_len (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, (p)gp or (c)lear?"),
3837 mutt_multi_choice (_
3838 ("PGP (e)ncrypt, (s)ign, sign (a)s, (b)oth, s/(m)ime or (c)lear?"),
3842 case 1: /* (e)ncrypt */
3843 msg->security |= (is_smime ? SMIMEENCRYPT : PGPENCRYPT);
3844 msg->security &= ~(is_smime ? SMIMESIGN : PGPSIGN);
3847 case 2: /* (s)ign */
3848 msg->security |= (is_smime ? SMIMESIGN : PGPSIGN);
3849 msg->security &= ~(is_smime ? SMIMEENCRYPT : PGPENCRYPT);
3852 case 3: /* sign (a)s */
3853 /* unset_option(OPTCRYPTCHECKTRUST); */
3854 if ((p = crypt_ask_for_key (_("Sign as: "), NULL, KEYFLAG_CANSIGN,
3855 is_smime ? APPLICATION_SMIME :
3856 APPLICATION_PGP, NULL))) {
3857 snprintf (input_signas, sizeof (input_signas), "0x%s", crypt_keyid (p));
3858 str_replace (is_smime ? &SmimeDefaultKey : &PgpSignAs,
3860 crypt_free_key (&p);
3862 msg->security |= (is_smime ? SMIMESIGN : PGPSIGN);
3866 msg->security &= (is_smime ? ~SMIMESIGN : ~PGPSIGN);
3869 *redraw = REDRAW_FULL;
3872 case 4: /* (b)oth */
3874 (is_smime ? (SMIMEENCRYPT | SMIMESIGN) : (PGPENCRYPT | PGPSIGN));
3877 case 5: /* (p)gp or s/(m)ime */
3878 is_smime = !is_smime;
3881 case 6: /* (c)lear */
3886 if (choice == 6 || choice == 7);
3887 else if (is_smime) {
3888 msg->security &= ~APPLICATION_PGP;
3889 msg->security |= APPLICATION_SMIME;
3892 msg->security &= ~APPLICATION_SMIME;
3893 msg->security |= APPLICATION_PGP;
3896 return (msg->security);
3899 int pgp_gpgme_send_menu (HEADER * msg, int *redraw)
3901 return gpgme_send_menu (msg, redraw, 0);
3904 int smime_gpgme_send_menu (HEADER * msg, int *redraw)
3906 return gpgme_send_menu (msg, redraw, 1);
3909 static int verify_sender (HEADER * h, gpgme_protocol_t protocol)
3911 ADDRESS *sender = NULL;
3912 unsigned int ret = 1;
3915 h->env->from = mutt_expand_aliases (h->env->from);
3916 sender = h->env->from;
3918 else if (h->env->sender) {
3919 h->env->sender = mutt_expand_aliases (h->env->sender);
3920 sender = h->env->sender;
3924 if (signature_key) {
3925 gpgme_key_t key = signature_key;
3926 gpgme_user_id_t uid = NULL;
3927 int sender_length = 0;
3930 sender_length = str_len (sender->mailbox);
3931 for (uid = key->uids; uid && ret; uid = uid->next) {
3932 uid_length = str_len (uid->email);
3933 if (1 && (uid->email[0] == '<')
3934 && (uid->email[uid_length - 1] == '>')
3935 && (uid_length == sender_length + 2)
3936 && (!strncmp (uid->email + 1, sender->mailbox, sender_length)))
3941 mutt_any_key_to_continue ("Failed to verify sender");
3944 mutt_any_key_to_continue ("Failed to figure out sender");
3946 if (signature_key) {
3947 gpgme_key_release (signature_key);
3948 signature_key = NULL;
3954 int smime_gpgme_verify_sender (HEADER * h)
3956 return verify_sender (h, GPGME_PROTOCOL_CMS);