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
32 #ifdef HAVE_LANGINFO_D_T_FMT
33 # include <langinfo.h>
35 #ifdef HAVE_SYS_TIME_H
36 # include <sys/time.h>
38 #ifdef HAVE_SYS_RESOURCE_H
39 # include <sys/resource.h>
44 #include <lib-lib/mem.h>
45 #include <lib-lib/str.h>
46 #include <lib-lib/ascii.h>
47 #include <lib-lib/macros.h>
48 #include <lib-lib/file.h>
49 #include <lib-lib/debug.h>
51 #include <lib-mime/mime.h>
53 #include <lib-ui/curses.h>
54 #include <lib-ui/enter.h>
55 #include <lib-ui/menu.h>
60 #include <lib-crypt/crypt.h>
64 #include "recvattach.h"
70 #define digitp(p) (*(p) >= '0' && *(p) <= '9')
71 #define hexdigitp(a) (digitp (a) \
72 || (*(a) >= 'A' && *(a) <= 'F') \
73 || (*(a) >= 'a' && *(a) <= 'f'))
74 #define xtoi_1(p) (*(p) <= '9'? (*(p)- '0'): \
75 *(p) <= 'F'? (*(p)-'A'+10):(*(p)-'a'+10))
76 #define xtoi_2(p) ((xtoi_1(p) * 16) + xtoi_1((p)+1))
78 /* Values used for comparing addresses. */
79 #define CRYPT_KV_VALID 1
80 #define CRYPT_KV_ADDR 2
81 #define CRYPT_KV_STRING 4
82 #define CRYPT_KV_STRONGID 8
83 #define CRYPT_KV_MATCH (CRYPT_KV_ADDR|CRYPT_KV_STRING)
92 struct crypt_cache *next;
100 /* We work based on user IDs, getting from a user ID to the key is
101 check and does not need any memory (gpgme uses reference counting). */
102 typedef struct crypt_keyinfo {
103 struct crypt_keyinfo *next;
105 int idx; /* and the user ID at this index */
106 const char *uid; /* and for convenience point to this user ID */
107 unsigned int flags; /* global and per uid flags (for convenience) */
110 typedef struct crypt_entry {
116 static struct crypt_cache *id_defaults = NULL;
117 static gpgme_key_t signature_key = NULL;
120 * General helper functions.
123 /* return true when S points to a didgit or letter. */
124 static int digit_or_letter (const unsigned char *s)
126 return ((*s >= '0' && *s <= '9')
127 || (*s >= 'A' && *s <= 'Z')
128 || (*s >= 'a' && *s <= 'z'));
132 /* Print the utf-8 encoded string BUF of length LEN bytes to stream
133 FP. Convert the character set. */
134 static void print_utf8 (FILE * fp, const char *buf, ssize_t len)
138 tstr = p_dupstr(buf, len);
139 mutt_convert_string (&tstr, "utf-8", Charset, M_ICONV_HOOK_FROM);
149 /* Return the keyID for the key K. Note that this string is valid as
150 long as K is valid */
151 static const char *crypt_keyid (crypt_key_t * k)
153 const char *s = "????????";
155 if (k->kobj && k->kobj->subkeys) {
156 s = k->kobj->subkeys->keyid;
157 if ((!option (OPTPGPLONGIDS)) && (m_strlen(s) == 16))
158 /* Return only the short keyID. */
165 /* Return the hexstring fingerprint from the key K. */
166 static const char *crypt_fpr (crypt_key_t * k)
170 if (k->kobj && k->kobj->subkeys)
171 s = k->kobj->subkeys->fpr;
176 /* Parse FLAGS and return a statically allocated(!) string with them. */
177 static char *crypt_key_abilities (int flags)
181 if (!(flags & KEYFLAG_CANENCRYPT))
183 else if (flags & KEYFLAG_PREFER_SIGNING)
188 if (!(flags & KEYFLAG_CANSIGN))
190 else if (flags & KEYFLAG_PREFER_ENCRYPTION)
200 /* Parse FLAGS and return a character describing the most important flag. */
201 static char crypt_flags (int flags)
203 if (flags & KEYFLAG_REVOKED)
205 else if (flags & KEYFLAG_EXPIRED)
207 else if (flags & KEYFLAG_DISABLED)
209 else if (flags & KEYFLAG_CRITICAL)
215 /* Return a copy of KEY. */
216 static crypt_key_t *crypt_copy_key (crypt_key_t *key)
220 k = p_new(crypt_key_t, 1);
222 gpgme_key_ref (key->kobj);
225 k->flags = key->flags;
230 /* Release all the keys at the address of KEYLIST and set the address
232 static void crypt_free_key (crypt_key_t ** keylist)
235 crypt_key_t *k = (*keylist)->next;
242 /* Return trute when key K is valid. */
243 static int crypt_key_is_valid (crypt_key_t * k)
245 if (k->flags & KEYFLAG_CANTUSE)
250 /* Return true whe validity of KEY is sufficient. */
251 static int crypt_id_is_strong (crypt_key_t * key)
253 gpgme_validity_t val = GPGME_VALIDITY_UNKNOWN;
254 gpgme_user_id_t uid = NULL;
258 if ((key->flags & KEYFLAG_ISX509))
261 for (i = 0, uid = key->kobj->uids; (i < key->idx) && uid;
262 i++, uid = uid->next);
267 case GPGME_VALIDITY_UNKNOWN:
268 case GPGME_VALIDITY_UNDEFINED:
269 case GPGME_VALIDITY_NEVER:
270 case GPGME_VALIDITY_MARGINAL:
274 case GPGME_VALIDITY_FULL:
275 case GPGME_VALIDITY_ULTIMATE:
283 /* Return true when the KEY is valid, i.e. not marked as unusable. */
284 static int crypt_id_is_valid (crypt_key_t * key)
286 return !(key->flags & KEYFLAG_CANTUSE);
289 /* Return a bit vector describing how well the addresses ADDR and
290 U_ADDR match and whether KEY is valid. */
291 static int crypt_id_matches_addr (address_t * addr, address_t * u_addr,
296 if (crypt_id_is_valid (key))
297 rv |= CRYPT_KV_VALID;
299 if (crypt_id_is_strong (key))
300 rv |= CRYPT_KV_STRONGID;
302 if (addr->mailbox && u_addr->mailbox
303 && m_strcasecmp(addr->mailbox, u_addr->mailbox) == 0)
306 if (addr->personal && u_addr->personal
307 && m_strcasecmp(addr->personal, u_addr->personal) == 0)
308 rv |= CRYPT_KV_STRING;
315 * GPGME convenient functions.
318 /* Create a new gpgme context and return it. With FOR_SMIME set to
319 true, the protocol of the context is set to CMS. */
320 static gpgme_ctx_t create_gpgme_context (int for_smime)
325 err = gpgme_new (&ctx);
327 mutt_error (_("error creating gpgme context: %s\n"), gpgme_strerror (err));
333 err = gpgme_set_protocol (ctx, GPGME_PROTOCOL_CMS);
335 mutt_error (_("error enabling CMS protocol: %s\n"), gpgme_strerror (err));
344 /* Create a new gpgme data object. This is a wrapper to die on
346 static gpgme_data_t create_gpgme_data (void)
351 err = gpgme_data_new (&data);
353 mutt_error (_("error creating gpgme data object: %s\n"),
354 gpgme_strerror (err));
361 /* Create a new GPGME Data object from the mail body A. With CONVERT
362 passed as true, the lines are converted to CR,LF if required.
363 Return NULL on error or the gpgme_data_t object on success. */
364 static gpgme_data_t body_to_data_object (BODY * a, int convert)
366 char tempfile[_POSIX_PATH_MAX];
371 mutt_mktemp (tempfile);
372 fptmp = safe_fopen (tempfile, "w+");
374 mutt_perror (tempfile);
378 mutt_write_mime_header (a, fptmp);
380 mutt_write_mime_body (a, fptmp);
384 unsigned char buf[1];
386 data = create_gpgme_data ();
388 while ((c = fgetc (fptmp)) != EOF) {
392 if (c == '\n' && !hadcr) {
394 gpgme_data_write (data, buf, 1);
399 /* FIXME: This is quite suboptimal */
401 gpgme_data_write (data, buf, 1);
404 gpgme_data_seek (data, 0, SEEK_SET);
408 err = gpgme_data_new_from_file (&data, tempfile, 1);
412 mutt_error (_("error allocating data object: %s\n"), gpgme_strerror (err));
419 /* Create a GPGME data object from the stream FP but limit the object
420 to LENGTH bytes starting at OFFSET bytes from the beginning of the
422 static gpgme_data_t file_to_data_object (FILE * fp, long offset, long length)
427 err = gpgme_data_new_from_filepart (&data, NULL, fp, offset, length);
429 mutt_error (_("error allocating data object: %s\n"), gpgme_strerror (err));
436 /* Write a GPGME data object to the stream FP. */
437 static int data_object_to_stream (gpgme_data_t data, FILE * fp)
443 err = ((gpgme_data_seek (data, 0, SEEK_SET) == -1)
444 ? gpgme_error_from_errno (errno) : 0);
446 mutt_error (_("error rewinding data object: %s\n"), gpgme_strerror (err));
450 while ((nread = gpgme_data_read (data, buf, sizeof (buf)))) {
451 /* fixme: we are not really converting CRLF to LF but just
452 skipping CR. Doing it correctly needs a more complex logic */
453 for (p = buf; nread; p++, nread--) {
459 mutt_perror ("[tempfile]");
464 mutt_error (_("error reading data object: %s\n"), strerror (errno));
470 /* Copy a data object to a newly created temporay file and return that
471 filename. Caller must free. With RET_FP not NULL, don't close the
472 stream but return it there. */
473 static char *data_object_to_tempfile (gpgme_data_t data, FILE ** ret_fp)
476 char tempfile[_POSIX_PATH_MAX];
480 mutt_mktemp (tempfile);
481 fp = safe_fopen (tempfile, "w+");
483 mutt_perror (tempfile);
487 err = ((gpgme_data_seek (data, 0, SEEK_SET) == -1)
488 ? gpgme_error_from_errno (errno) : 0);
492 while ((nread = gpgme_data_read (data, buf, sizeof (buf)))) {
493 if (fwrite (buf, nread, 1, fp) != 1) {
494 mutt_perror (tempfile);
506 mutt_error (_("error reading data object: %s\n"), gpgme_strerror (err));
513 return m_strdup(tempfile);
517 /* Create a GpgmeRecipientSet from the keys in the string KEYLIST.
518 The keys must be space delimited. */
519 static gpgme_key_t *create_recipient_set (const char *keylist,
520 gpgme_protocol_t protocol)
526 gpgme_key_t *rset = NULL;
527 unsigned int rset_n = 0;
528 gpgme_key_t key = NULL;
529 gpgme_ctx_t context = NULL;
531 err = gpgme_new (&context);
533 err = gpgme_set_protocol (context, protocol);
540 for (i = 0; *s && *s != ' ' && i < ssizeof(buf) - 1;)
544 if (i > 1 && buf[i - 1] == '!') {
545 /* The user selected to override the valididy of that
549 err = gpgme_get_key (context, buf, &key, 0);
551 key->uids->validity = GPGME_VALIDITY_FULL;
555 err = gpgme_get_key (context, buf, &key, 0);
558 p_realloc(&rset, rset_n + 1);
559 rset[rset_n++] = key;
562 mutt_error (_("error adding recipient `%s': %s\n"),
563 buf, gpgme_strerror (err));
571 /* NULL terminate. */
572 p_realloc(&rset, rset_n + 1);
573 rset[rset_n++] = NULL;
576 gpgme_release (context);
582 /* Make sure that the correct signer is set. Returns 0 on success. */
583 static int set_signer (gpgme_ctx_t ctx, int for_smime)
585 char *signid = for_smime ? SmimeDefaultKey : PgpSignAs;
588 gpgme_key_t key, key2;
590 if (!signid || !*signid)
593 listctx = create_gpgme_context (for_smime);
594 err = gpgme_op_keylist_start (listctx, signid, 1);
596 err = gpgme_op_keylist_next (listctx, &key);
598 gpgme_release (listctx);
599 mutt_error (_("secret key `%s' not found: %s\n"),
600 signid, gpgme_strerror (err));
603 err = gpgme_op_keylist_next (listctx, &key2);
605 gpgme_key_release (key);
606 gpgme_key_release (key2);
607 gpgme_release (listctx);
608 mutt_error (_("ambiguous specification of secret key `%s'\n"), signid);
611 gpgme_op_keylist_end (listctx);
612 gpgme_release (listctx);
614 gpgme_signers_clear (ctx);
615 err = gpgme_signers_add (ctx, key);
616 gpgme_key_release (key);
618 mutt_error (_("error setting secret key `%s': %s\n"),
619 signid, gpgme_strerror (err));
626 /* Encrypt the gpgme data object PLAINTEXT to the recipients in RSET
627 and return an allocated filename to a temporary file containing the
628 enciphered text. With USE_SMIME set to true, the smime backend is
629 used. With COMBINED_SIGNED a PGP message is signed and
630 encrypted. Returns NULL in case of error */
631 static char *encrypt_gpgme_object (gpgme_data_t plaintext, gpgme_key_t * rset,
632 int use_smime, int combined_signed)
636 gpgme_data_t ciphertext;
639 ctx = create_gpgme_context (use_smime);
641 gpgme_set_armor (ctx, 1);
643 ciphertext = create_gpgme_data ();
645 if (combined_signed) {
646 if (set_signer (ctx, use_smime)) {
647 gpgme_data_release (ciphertext);
651 err = gpgme_op_encrypt_sign (ctx, rset, GPGME_ENCRYPT_ALWAYS_TRUST,
652 plaintext, ciphertext);
655 err = gpgme_op_encrypt (ctx, rset, GPGME_ENCRYPT_ALWAYS_TRUST,
656 plaintext, ciphertext);
657 mutt_need_hard_redraw ();
659 mutt_error (_("error encrypting data: %s\n"), gpgme_strerror (err));
660 gpgme_data_release (ciphertext);
667 outfile = data_object_to_tempfile (ciphertext, NULL);
668 gpgme_data_release (ciphertext);
672 /* Find the "micalg" parameter from the last Gpgme operation on
673 context CTX. It is expected that this operation was a sign
674 operation. Return the algorithm name as a C string in buffer BUF
675 which must have been allocated by the caller with size BUFLEN.
676 Returns 0 on success or -1 in case of an error. The return string
677 is truncted to BUFLEN - 1. */
678 static int get_micalg (gpgme_ctx_t ctx, char *buf, ssize_t buflen)
680 gpgme_sign_result_t result = NULL;
681 const char *algorithm_name = NULL;
687 result = gpgme_op_sign_result (ctx);
689 algorithm_name = gpgme_hash_algo_name (result->signatures->hash_algo);
690 if (algorithm_name) {
691 m_strcpy(buf, buflen, algorithm_name);
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 = m_strdup("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 = m_strdup("pkcs7-signature");
789 mutt_set_parameter ("name", "smime.p7s", &t->parameter);
790 t->encoding = ENCBASE64;
792 t->disposition = DISPATTACH;
793 t->d_filename = m_strdup("smime.p7s");
796 t->subtype = m_strdup("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 = m_strdup("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 = m_strdup("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 = m_strdup("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 = m_strdup("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 = m_strdup("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 = m_strdup("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 && !m_strcmp(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 = xmalloc(m_strlen(prefix) + m_strlen(s) * 4 + 2);
1038 strcpy (buf, prefix); /* __STRCPY_CHECKED__ */
1039 p = buf + m_strlen(buf);
1040 if (is_pgp && m_strlen(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 sig;
1288 result = gpgme_op_verify_result (ctx);
1290 for (sig = result->signatures; sig; sig = sig->next) {
1291 if (sig->notations) {
1292 state_attach_puts ("*** Begin Notation (signature by: ", s);
1293 state_attach_puts (sig->fpr, s);
1294 state_attach_puts (") ***\n", s);
1295 for (notation = sig->notations; notation; notation = notation->next)
1297 if (notation->name) {
1298 state_attach_puts (notation->name, s);
1299 state_attach_puts ("=", s);
1301 if (notation->value) {
1302 state_attach_puts (notation->value, s);
1303 if (!(*notation->value
1304 && (notation->value[m_strlen(notation->value) - 1] ==
1306 state_attach_puts ("\n", s);
1309 state_attach_puts ("*** End Notation ***\n", s);
1315 gpgme_release (ctx);
1317 state_attach_puts (_("[-- End signature information --]\n\n"), s);
1318 debug_print (1, ("returning %d.\n", badsig));
1320 return badsig ? 1 : anywarn ? 2 : 0;
1323 int pgp_gpgme_verify_one (BODY * sigbdy, STATE * s, const char *tempfile)
1325 return verify_one (sigbdy, s, tempfile, 0);
1328 int smime_gpgme_verify_one (BODY * sigbdy, STATE * s, const char *tempfile)
1330 return verify_one (sigbdy, s, tempfile, 1);
1334 * Implementation of `decrypt_part'.
1337 /* Decrypt a PGP or SMIME message (depending on the boolean flag
1338 IS_SMIME) with body A described further by state S. Write
1339 plaintext out to file FPOUT and return a new body. For PGP returns
1340 a flag in R_IS_SIGNED to indicate whether this is a combined
1341 encrypted and signed message, for S/MIME it returns true when it is
1342 not a encrypted but a signed message. */
1343 static BODY *decrypt_part (BODY * a, STATE * s, FILE * fpout, int is_smime,
1350 gpgme_data_t ciphertext, plaintext;
1351 int maybe_signed = 0;
1358 ctx = create_gpgme_context (is_smime);
1361 /* Make a data object from the body, create context etc. */
1362 ciphertext = file_to_data_object (s->fpin, a->offset, a->length);
1365 plaintext = create_gpgme_data ();
1367 /* Do the decryption or the verification in case of the S/MIME hack. */
1368 if ((!is_smime) || maybe_signed) {
1370 err = gpgme_op_decrypt_verify (ctx, ciphertext, plaintext);
1371 else if (maybe_signed)
1372 err = gpgme_op_verify (ctx, ciphertext, NULL, plaintext);
1375 /* Check wether signatures have been verified. */
1376 gpgme_verify_result_t verify_result = gpgme_op_verify_result (ctx);
1378 if (verify_result->signatures)
1383 err = gpgme_op_decrypt (ctx, ciphertext, plaintext);
1384 gpgme_data_release (ciphertext);
1386 if (is_smime && !maybe_signed && gpg_err_code (err) == GPG_ERR_NO_DATA) {
1387 /* Check whether this might be a signed message despite what
1388 the mime header told us. Retry then. gpgsm returns the
1389 error information "unsupported Algorithm '?'" but gpgme
1390 will not store this unknown algorithm, thus we test that
1391 it has not been set. */
1392 gpgme_decrypt_result_t result;
1394 result = gpgme_op_decrypt_result (ctx);
1395 if (!result->unsupported_algorithm) {
1397 gpgme_data_release (plaintext);
1401 mutt_need_hard_redraw ();
1402 if ((s->flags & M_DISPLAY)) {
1405 snprintf (buf, sizeof (buf) - 1,
1406 _("[-- Error: decryption failed: %s --]\n\n"),
1407 gpgme_strerror (err));
1408 state_attach_puts (buf, s);
1410 gpgme_data_release (plaintext);
1411 gpgme_release (ctx);
1414 mutt_need_hard_redraw ();
1416 /* Read the output from GPGME, and make sure to change CRLF to LF,
1417 otherwise read_mime_header has a hard time parsing the message. */
1418 if (data_object_to_stream (plaintext, fpout)) {
1419 gpgme_data_release (plaintext);
1420 gpgme_release (ctx);
1423 gpgme_data_release (plaintext);
1425 a->is_signed_data = 0;
1431 a->is_signed_data = 1;
1433 *r_is_signed = -1; /* A signature exists. */
1435 if ((s->flags & M_DISPLAY))
1436 state_attach_puts (_("[-- Begin signature " "information --]\n"), s);
1437 for (idx = 0; (res = show_one_sig_status (ctx, idx, s)) != -1; idx++) {
1443 if (!anybad && idx && r_is_signed && *r_is_signed)
1444 *r_is_signed = anywarn ? 2 : 1; /* Good signature. */
1446 if ((s->flags & M_DISPLAY))
1447 state_attach_puts (_("[-- End signature " "information --]\n\n"), s);
1449 gpgme_release (ctx);
1454 tattach = mutt_read_mime_header (fpout, 0);
1457 * Need to set the length of this body part.
1459 fstat (fileno (fpout), &info);
1460 tattach->length = info.st_size - tattach->offset;
1462 tattach->warnsig = anywarn;
1464 /* See if we need to recurse on this MIME part. */
1465 mutt_parse_part (fpout, tattach);
1471 /* Decrypt a PGP/MIME message in FPIN and B and return a new body and
1472 the stream in CUR and FPOUT. Returns 0 on success. */
1473 int pgp_gpgme_decrypt_mime (FILE * fpin, FILE ** fpout, BODY * b, BODY ** cur)
1475 char tempfile[_POSIX_PATH_MAX];
1477 BODY *first_part = b;
1480 first_part->goodsig = 0;
1481 first_part->warnsig = 0;
1483 if (!mutt_is_multipart_encrypted (b))
1486 if (!b->parts || !b->parts->next)
1493 mutt_mktemp (tempfile);
1494 if (!(*fpout = safe_fopen (tempfile, "w+"))) {
1495 mutt_perror (tempfile);
1500 *cur = decrypt_part (b, &s, *fpout, 0, &is_signed);
1503 first_part->goodsig = 1;
1505 return *cur ? 0 : -1;
1509 /* Decrypt a S/MIME message in FPIN and B and return a new body and
1510 the stream in CUR and FPOUT. Returns 0 on success. */
1511 int smime_gpgme_decrypt_mime (FILE * fpin, FILE ** fpout, BODY * b,
1514 char tempfile[_POSIX_PATH_MAX];
1518 long saved_b_offset;
1519 ssize_t saved_b_length;
1522 if (!mutt_is_application_smime (b))
1528 /* Decode the body - we need to pass binary CMS to the
1529 backend. The backend allows for Base64 encoded data but it does
1530 not allow for QP which I have seen in some messages. So better
1532 saved_b_type = b->type;
1533 saved_b_offset = b->offset;
1534 saved_b_length = b->length;
1537 fseeko (s.fpin, b->offset, 0);
1538 mutt_mktemp (tempfile);
1539 if (!(tmpfp = safe_fopen (tempfile, "w+"))) {
1540 mutt_perror (tempfile);
1543 mutt_unlink (tempfile);
1546 mutt_decode_attachment (b, &s);
1548 b->length = ftello (s.fpout);
1555 mutt_mktemp (tempfile);
1556 if (!(*fpout = safe_fopen (tempfile, "w+"))) {
1557 mutt_perror (tempfile);
1560 mutt_unlink (tempfile);
1562 *cur = decrypt_part (b, &s, *fpout, 1, &is_signed);
1564 (*cur)->goodsig = is_signed > 0;
1565 b->type = saved_b_type;
1566 b->length = saved_b_length;
1567 b->offset = saved_b_offset;
1570 if (*cur && !is_signed && !(*cur)->parts
1571 && mutt_is_application_smime (*cur)) {
1572 /* Assume that this is a opaque signed s/mime message. This is
1573 an ugly way of doing it but we have anyway a problem with
1574 arbitrary encoded S/MIME messages: Only the outer part may be
1575 encrypted. The entire mime parsing should be revamped,
1576 probably by keeping the temportary files so that we don't
1577 need to decrypt them all the time. Inner parts of an
1578 encrypted part can then pint into this file and tehre won't
1579 never be a need to decrypt again. This needs a partial
1580 rewrite of the MIME engine. */
1584 saved_b_type = bb->type;
1585 saved_b_offset = bb->offset;
1586 saved_b_length = bb->length;
1589 fseeko (s.fpin, bb->offset, 0);
1590 mutt_mktemp (tempfile);
1591 if (!(tmpfp = safe_fopen (tempfile, "w+"))) {
1592 mutt_perror (tempfile);
1595 mutt_unlink (tempfile);
1598 mutt_decode_attachment (bb, &s);
1600 bb->length = ftello (s.fpout);
1608 mutt_mktemp (tempfile);
1609 if (!(*fpout = safe_fopen (tempfile, "w+"))) {
1610 mutt_perror (tempfile);
1613 mutt_unlink (tempfile);
1615 tmp_b = decrypt_part (bb, &s, *fpout, 1, &is_signed);
1617 tmp_b->goodsig = is_signed > 0;
1618 bb->type = saved_b_type;
1619 bb->length = saved_b_length;
1620 bb->offset = saved_b_offset;
1623 mutt_free_body (cur);
1626 return *cur ? 0 : -1;
1631 * Implementation of `pgp_check_traditional'.
1634 static int pgp_check_traditional_one_body (FILE * fp, BODY * b,
1637 char tempfile[_POSIX_PATH_MAX];
1638 char buf[HUGE_STRING];
1644 if (b->type != TYPETEXT)
1647 if (tagged_only && !b->tagged)
1650 mutt_mktemp (tempfile);
1651 if (mutt_decode_save_attachment (fp, b, tempfile, 0, 0) != 0) {
1656 if ((tfp = fopen (tempfile, "r")) == NULL) {
1661 while (fgets (buf, sizeof (buf), tfp)) {
1662 if (!m_strncmp("-----BEGIN PGP ", buf, 15)) {
1663 if (!m_strcmp("MESSAGE-----\n", buf + 15))
1665 else if (!m_strcmp("SIGNED MESSAGE-----\n", buf + 15))
1675 /* fix the content type */
1677 mutt_set_parameter ("format", "fixed", &b->parameter);
1678 mutt_set_parameter ("x-action", enc ? "pgp-encrypted" : "pgp-signed",
1684 int pgp_gpgme_check_traditional (FILE * fp, BODY * b, int tagged_only)
1689 for (; b; b = b->next) {
1690 if (is_multipart (b))
1691 rv = (pgp_gpgme_check_traditional (fp, b->parts, tagged_only) || rv);
1692 else if (b->type == TYPETEXT) {
1693 if ((r = mutt_is_application_pgp (b)))
1696 rv = (pgp_check_traditional_one_body (fp, b, tagged_only) || rv);
1704 * Implementation of `application_handler'.
1708 Copy a clearsigned message, and strip the signature and PGP's
1711 XXX - charset handling: We assume that it is safe to do
1712 character set decoding first, dash decoding second here, while
1713 we do it the other way around in the main handler.
1715 (Note that we aren't worse than Outlook & Cie in this, and also
1716 note that we can successfully handle anything produced by any
1717 existing versions of mutt.) */
1719 static void copy_clearsigned (gpgme_data_t data, STATE * s, char *charset)
1721 char buf[HUGE_STRING];
1722 short complete, armor_header;
1727 fname = data_object_to_tempfile (data, &fp);
1733 fc = fgetconv_open (fp, charset, Charset, M_ICONV_HOOK_FROM);
1735 for (complete = 1, armor_header = 1;
1736 fgetconvs (buf, sizeof (buf), fc) != NULL;
1737 complete = strchr (buf, '\n') != NULL) {
1740 state_puts (buf, s);
1744 if (!m_strcmp(buf, "-----BEGIN PGP SIGNATURE-----\n"))
1754 state_puts (s->prefix, s);
1756 if (buf[0] == '-' && buf[1] == ' ')
1757 state_puts (buf + 2, s);
1759 state_puts (buf, s);
1762 fgetconv_close (&fc);
1767 /* Support for classic_application/pgp */
1768 int pgp_gpgme_application_handler (BODY * m, STATE * s)
1770 int needpass = -1, pgp_keyblock = 0;
1774 off_t 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 m_strcpy(body_charset, sizeof(body_charset), "iso-8859-1");
1794 fseeko (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 = ftello (s->fpin);
1802 bytes -= (offset - last_pos); /* don't rely on m_strlen(buf) */
1805 if (!m_strncmp("-----BEGIN PGP ", buf, 15)) {
1807 start_pos = last_pos;
1809 if (!m_strcmp("MESSAGE-----\n", buf + 15))
1811 else if (!m_strcmp("SIGNED MESSAGE-----\n", buf + 15)) {
1815 else if (!option (OPTDONTHANDLEPGPKEYS) &&
1816 !m_strcmp("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, m_strlen(buf));
1833 while (bytes > 0 && fgets (buf, sizeof (buf) - 1, s->fpin) != NULL) {
1834 offset = ftello (s->fpin);
1835 bytes -= (offset - last_pos); /* don't rely on m_strlen(buf) */
1838 gpgme_data_write (armored_data, buf, m_strlen(buf));
1840 if ((needpass && !m_strcmp("-----END PGP MESSAGE-----\n", buf))
1842 && (!m_strcmp("-----END PGP SIGNATURE-----\n", buf)
1843 || !m_strcmp("-----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 p_delete(&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)
2159 crypt_entry_fmt (char *dest, ssize_t destlen, char op,
2160 const char *src, const char *prefix,
2161 const char *ifstring, const char *elsestring,
2162 unsigned long data, format_flag flags)
2165 crypt_entry_t *entry;
2168 int optional = (flags & M_FORMAT_OPTIONAL);
2169 const char *s = NULL;
2172 entry = (crypt_entry_t *) data;
2175 /* if (isupper ((unsigned char) op)) */
2178 kflags = (key->flags /*| (pkey->flags & KEYFLAG_RESTRICTIONS)
2181 switch (ascii_tolower (op)) {
2185 char buf2[SHORT_STRING], *p;
2201 while (len > 0 && *cp != ']') {
2210 break; /* not enough space */
2220 if (do_locales && Locale)
2221 setlocale (LC_TIME, Locale);
2226 if (key->kobj->subkeys && (key->kobj->subkeys->timestamp > 0))
2227 tt = key->kobj->subkeys->timestamp;
2229 tm = localtime (&tt);
2231 strftime (buf2, sizeof (buf2), dest, tm);
2234 setlocale (LC_TIME, "C");
2236 snprintf (fmt, sizeof (fmt), "%%%ss", prefix);
2237 snprintf (dest, destlen, fmt, buf2);
2244 snprintf (fmt, sizeof (fmt), "%%%sd", prefix);
2245 snprintf (dest, destlen, fmt, entry->num);
2250 /* fixme: we need a way to distinguish between main and subkeys.
2251 Store the idx in entry? */
2252 snprintf (fmt, sizeof (fmt), "%%%ss", prefix);
2253 snprintf (dest, destlen, fmt, crypt_keyid (key));
2258 snprintf (fmt, sizeof (fmt), "%%%ss", prefix);
2259 snprintf (dest, destlen, fmt, key->uid);
2264 snprintf (fmt, sizeof (fmt), "%%%s.3s", prefix);
2265 if (key->kobj->subkeys)
2266 s = gpgme_pubkey_algo_name (key->kobj->subkeys->pubkey_algo);
2269 snprintf (dest, destlen, fmt, s);
2274 snprintf (fmt, sizeof (fmt), "%%%slu", prefix);
2275 if (key->kobj->subkeys)
2276 val = key->kobj->subkeys->length;
2279 snprintf (dest, destlen, fmt, val);
2284 snprintf (fmt, sizeof (fmt), "%%%sc", prefix);
2285 snprintf (dest, destlen, fmt, crypt_flags (kflags));
2287 else if (!(kflags & (KEYFLAG_RESTRICTIONS)))
2292 snprintf (fmt, sizeof (fmt), "%%%ss", prefix);
2293 snprintf (dest, destlen, fmt, crypt_key_abilities (kflags));
2295 else if (!(kflags & (KEYFLAG_ABILITIES)))
2299 if ((kflags & KEYFLAG_ISX509))
2302 gpgme_user_id_t uid = NULL;
2305 for (i = 0, uid = key->kobj->uids; uid && (i < key->idx);
2306 i++, uid = uid->next);
2308 switch (uid->validity) {
2309 case GPGME_VALIDITY_UNDEFINED:
2312 case GPGME_VALIDITY_NEVER:
2315 case GPGME_VALIDITY_MARGINAL:
2318 case GPGME_VALIDITY_FULL:
2321 case GPGME_VALIDITY_ULTIMATE:
2324 case GPGME_VALIDITY_UNKNOWN:
2330 snprintf (fmt, sizeof (fmt), "%%%sc", prefix);
2331 snprintf (dest, destlen, fmt, s ? *s : 'B');
2334 snprintf (fmt, sizeof (fmt), "%%%ss", prefix);
2335 snprintf (dest, destlen, fmt,
2336 gpgme_get_protocol_name (key->kobj->protocol));
2344 mutt_FormatString (dest, destlen, ifstring, mutt_attach_fmt, data, 0);
2345 else if (flags & M_FORMAT_OPTIONAL)
2346 mutt_FormatString (dest, destlen, elsestring, mutt_attach_fmt, data, 0);
2350 /* Used by the display fucntion to format a line. */
2351 static void crypt_entry (char *s, ssize_t l, MUTTMENU * menu, int num)
2353 crypt_key_t **key_table = (crypt_key_t **) menu->data;
2354 crypt_entry_t entry;
2356 entry.key = key_table[num];
2357 entry.num = num + 1;
2359 mutt_FormatString (s, l, NONULL (PgpEntryFormat), crypt_entry_fmt,
2360 (unsigned long) &entry, M_FORMAT_ARROWCURSOR);
2363 /* Compare two addresses and the keyid to be used for sorting. */
2364 static int _crypt_compare_address (const void *a, const void *b)
2366 crypt_key_t **s = (crypt_key_t **) a;
2367 crypt_key_t **t = (crypt_key_t **) b;
2370 if ((r = m_strcasecmp((*s)->uid, (*t)->uid)))
2373 return m_strcasecmp(crypt_keyid (*s), crypt_keyid (*t)) > 0;
2376 static int crypt_compare_address (const void *a, const void *b)
2378 return ((PgpSortKeys & SORT_REVERSE) ? !_crypt_compare_address (a, b)
2379 : _crypt_compare_address (a, b));
2383 /* Compare two key IDs and the addresses to be used for sorting. */
2384 static int _crypt_compare_keyid (const void *a, const void *b)
2386 crypt_key_t **s = (crypt_key_t **) a;
2387 crypt_key_t **t = (crypt_key_t **) b;
2390 if ((r = m_strcasecmp(crypt_keyid (*s), crypt_keyid (*t))))
2393 return m_strcasecmp((*s)->uid, (*t)->uid) > 0;
2396 static int crypt_compare_keyid (const void *a, const void *b)
2398 return ((PgpSortKeys & SORT_REVERSE) ? !_crypt_compare_keyid (a, b)
2399 : _crypt_compare_keyid (a, b));
2402 /* Compare 2 creation dates and the addresses. For sorting. */
2403 static int _crypt_compare_date (const void *a, const void *b)
2405 crypt_key_t **s = (crypt_key_t **) a;
2406 crypt_key_t **t = (crypt_key_t **) b;
2407 unsigned long ts = 0, tt = 0;
2409 if ((*s)->kobj->subkeys && ((*s)->kobj->subkeys->timestamp > 0))
2410 ts = (*s)->kobj->subkeys->timestamp;
2411 if ((*t)->kobj->subkeys && ((*t)->kobj->subkeys->timestamp > 0))
2412 tt = (*t)->kobj->subkeys->timestamp;
2419 return m_strcasecmp((*s)->uid, (*t)->uid) > 0;
2422 static int crypt_compare_date (const void *a, const void *b)
2424 return ((PgpSortKeys & SORT_REVERSE) ? !_crypt_compare_date (a, b)
2425 : _crypt_compare_date (a, b));
2428 /* Compare two trust values, the key length, the creation dates. the
2429 addresses and the key IDs. For sorting. */
2430 static int _crypt_compare_trust (const void *a, const void *b)
2432 crypt_key_t **s = (crypt_key_t **) a;
2433 crypt_key_t **t = (crypt_key_t **) b;
2434 unsigned long ts = 0, tt = 0;
2437 if ((r = (((*s)->flags & (KEYFLAG_RESTRICTIONS))
2438 - ((*t)->flags & (KEYFLAG_RESTRICTIONS)))))
2441 if ((*s)->kobj->uids)
2442 ts = (*s)->kobj->uids->validity;
2443 if ((*t)->kobj->uids)
2444 tt = (*t)->kobj->uids->validity;
2445 if ((r = (tt - ts)))
2448 if ((*s)->kobj->subkeys)
2449 ts = (*s)->kobj->subkeys->length;
2450 if ((*t)->kobj->subkeys)
2451 tt = (*t)->kobj->subkeys->length;
2455 if ((*s)->kobj->subkeys && ((*s)->kobj->subkeys->timestamp > 0))
2456 ts = (*s)->kobj->subkeys->timestamp;
2457 if ((*t)->kobj->subkeys && ((*t)->kobj->subkeys->timestamp > 0))
2458 tt = (*t)->kobj->subkeys->timestamp;
2464 if ((r = m_strcasecmp((*s)->uid, (*t)->uid)))
2466 return (m_strcasecmp(crypt_keyid ((*s)), crypt_keyid ((*t)))) > 0;
2469 static int crypt_compare_trust (const void *a, const void *b)
2471 return ((PgpSortKeys & SORT_REVERSE) ? !_crypt_compare_trust (a, b)
2472 : _crypt_compare_trust (a, b));
2475 /* Print the X.500 Distinguished Name part KEY from the array of parts
2477 static int print_dn_part (FILE * fp, struct dn_array_s *dn, const char *key)
2481 for (; dn->key; dn++) {
2482 if (!m_strcmp(dn->key, key)) {
2485 print_utf8 (fp, dn->value, m_strlen(dn->value));
2492 /* Print all parts of a DN in a standard sequence. */
2493 static void print_dn_parts (FILE * fp, struct dn_array_s *dn)
2495 const char *stdpart[] = {
2496 "CN", "OU", "O", "STREET", "L", "ST", "C", NULL
2498 int any = 0, any2 = 0, i;
2500 for (i = 0; stdpart[i]; i++) {
2503 any = print_dn_part (fp, dn, stdpart[i]);
2505 /* now print the rest without any specific ordering */
2506 for (; dn->key; dn++) {
2507 for (i = 0; stdpart[i]; i++) {
2508 if (!m_strcmp(dn->key, stdpart[i]))
2516 any = print_dn_part (fp, dn, dn->key);
2525 /* Parse an RDN; this is a helper to parse_dn(). */
2526 static const unsigned char *parse_dn_part (struct dn_array_s *array,
2527 const unsigned char *string)
2529 const unsigned char *s, *s1;
2533 /* parse attributeType */
2534 for (s = string + 1; *s && *s != '='; s++);
2536 return NULL; /* error */
2539 return NULL; /* empty key */
2540 array->key = p_dupstr(string, n );
2541 p = (unsigned char *) array->key;
2544 if (*string == '#') { /* hexstring */
2546 for (s = string; hexdigitp (s); s++)
2550 return NULL; /* empty or odd number of digits */
2553 array->value = (char *) p;
2554 for (s1 = string; n; s1 += 2, n--)
2558 else { /* regular v3 quoted string */
2559 for (n = 0, s = string; *s; s++) {
2560 if (*s == '\\') { /* pair */
2562 if (*s == ',' || *s == '=' || *s == '+'
2563 || *s == '<' || *s == '>' || *s == '#' || *s == ';'
2564 || *s == '\\' || *s == '\"' || *s == ' ')
2566 else if (hexdigitp (s) && hexdigitp (s + 1)) {
2571 return NULL; /* invalid escape sequence */
2573 else if (*s == '\"')
2574 return NULL; /* invalid encoding */
2575 else if (*s == ',' || *s == '=' || *s == '+'
2576 || *s == '<' || *s == '>' || *s == '#' || *s == ';')
2583 array->value = (char *) p;
2584 for (s = string; n; s++, n--) {
2587 if (hexdigitp (s)) {
2603 /* Parse a DN and return an array-ized one. This is not a validating
2604 parser and it does not support any old-stylish syntax; gpgme is
2605 expected to return only rfc2253 compatible strings. */
2606 static struct dn_array_s *parse_dn (const unsigned char *string)
2608 struct dn_array_s *array;
2609 ssize_t arrayidx, arraysize;
2612 arraysize = 7; /* C,ST,L,O,OU,CN,email */
2613 array = p_new(struct dn_array_s, arraysize + 1);
2616 while (*string == ' ')
2620 if (arrayidx >= arraysize) { /* mutt lacks a real safe_realoc - so we need to copy */
2621 struct dn_array_s *a2;
2624 a2 = p_new(struct dn_array_s, arraysize + 1);
2625 for (i = 0; i < arrayidx; i++) {
2626 a2[i].key = array[i].key;
2627 a2[i].value = array[i].value;
2632 array[arrayidx].key = NULL;
2633 array[arrayidx].value = NULL;
2634 string = parse_dn_part (array + arrayidx, string);
2638 while (*string == ' ')
2640 if (*string && *string != ',' && *string != ';' && *string != '+')
2641 goto failure; /* invalid delimiter */
2645 array[arrayidx].key = NULL;
2646 array[arrayidx].value = NULL;
2650 for (i = 0; i < arrayidx; i++) {
2651 p_delete(&array[i].key);
2652 p_delete(&array[i].value);
2659 /* Print a nice representation of the USERID and make sure it is
2660 displayed in a proper way, which does mean to reorder some parts
2661 for S/MIME's DNs. USERID is a string as returned by the gpgme key
2662 functions. It is utf-8 encoded. */
2663 static void parse_and_print_user_id (FILE * fp, const char *userid)
2668 if (*userid == '<') {
2669 s = strchr (userid + 1, '>');
2671 print_utf8 (fp, userid + 1, s - userid - 1);
2673 else if (*userid == '(')
2674 fputs (_("[Can't display this user ID (unknown encoding)]"), fp);
2675 else if (!digit_or_letter ((const unsigned char *) userid))
2676 fputs (_("[Can't display this user ID (invalid encoding)]"), fp);
2678 struct dn_array_s *dn = parse_dn ((const unsigned char *) userid);
2681 fputs (_("[Can't display this user ID (invalid DN)]"), fp);
2683 print_dn_parts (fp, dn);
2684 for (i = 0; dn[i].key; i++) {
2685 p_delete(&dn[i].key);
2686 p_delete(&dn[i].value);
2694 KEY_CAP_CAN_ENCRYPT,
2699 static unsigned int key_check_cap (gpgme_key_t key, key_cap_t cap)
2701 gpgme_subkey_t subkey = NULL;
2702 unsigned int ret = 0;
2705 case KEY_CAP_CAN_ENCRYPT:
2706 if (!(ret = key->can_encrypt))
2707 for (subkey = key->subkeys; subkey; subkey = subkey->next)
2708 if ((ret = subkey->can_encrypt))
2711 case KEY_CAP_CAN_SIGN:
2712 if (!(ret = key->can_sign))
2713 for (subkey = key->subkeys; subkey; subkey = subkey->next)
2714 if ((ret = subkey->can_sign))
2717 case KEY_CAP_CAN_CERTIFY:
2718 if (!(ret = key->can_certify))
2719 for (subkey = key->subkeys; subkey; subkey = subkey->next)
2720 if ((ret = subkey->can_certify))
2729 /* Print verbose information about a key or certificate to FP. */
2730 static void print_key_info (gpgme_key_t key, FILE * fp)
2733 const char *s = NULL, *s2 = NULL;
2736 char shortbuf[SHORT_STRING];
2737 unsigned long aval = 0;
2741 gpgme_user_id_t uid = NULL;
2744 setlocale (LC_TIME, Locale);
2746 is_pgp = key->protocol == GPGME_PROTOCOL_OpenPGP;
2748 for (idx = 0, uid = key->uids; uid; idx++, uid = uid->next) {
2753 fputs (idx ? _(" aka ......: ") :_("Name ......: "), fp);
2756 fputs (_("[Invalid]"), fp);
2760 print_utf8 (fp, s, m_strlen(s));
2762 parse_and_print_user_id (fp, s);
2766 if (key->subkeys && (key->subkeys->timestamp > 0)) {
2767 tt = key->subkeys->timestamp;
2769 tm = localtime (&tt);
2770 #ifdef HAVE_LANGINFO_D_T_FMT
2771 strftime (shortbuf, sizeof shortbuf, nl_langinfo (D_T_FMT), tm);
2773 strftime (shortbuf, sizeof shortbuf, "%c", tm);
2775 fprintf (fp, _("Valid From : %s\n"), shortbuf);
2778 if (key->subkeys && (key->subkeys->expires > 0)) {
2779 tt = key->subkeys->expires;
2781 tm = localtime (&tt);
2782 #ifdef HAVE_LANGINFO_D_T_FMT
2783 strftime (shortbuf, sizeof shortbuf, nl_langinfo (D_T_FMT), tm);
2785 strftime (shortbuf, sizeof shortbuf, "%c", tm);
2787 fprintf (fp, _("Valid To ..: %s\n"), shortbuf);
2791 s = gpgme_pubkey_algo_name (key->subkeys->pubkey_algo);
2795 s2 = is_pgp ? "PGP" : "X.509";
2798 aval = key->subkeys->length;
2800 fprintf (fp, _("Key Type ..: %s, %lu bit %s\n"), s2, aval, s);
2802 fprintf (fp, _("Key Usage .: "));
2805 if (key_check_cap (key, KEY_CAP_CAN_ENCRYPT)) {
2806 fprintf (fp, "%s%s", delim, _("encryption"));
2809 if (key_check_cap (key, KEY_CAP_CAN_SIGN)) {
2810 fprintf (fp, "%s%s", delim, _("signing"));
2813 if (key_check_cap (key, KEY_CAP_CAN_CERTIFY)) {
2814 fprintf (fp, "%s%s", delim, _("certification"));
2820 s = key->subkeys->fpr;
2821 fputs (_("Fingerprint: "), fp);
2822 if (is_pgp && m_strlen(s) == 40) {
2823 for (i = 0; *s && s[1] && s[2] && s[3] && s[4]; s += 4, i++) {
2828 putc (is_pgp ? ' ' : ':', fp);
2829 if (is_pgp && i == 4)
2834 for (i = 0; *s && s[1] && s[2]; s += 2, i++) {
2837 putc (is_pgp ? ' ' : ':', fp);
2838 if (is_pgp && i == 7)
2842 fprintf (fp, "%s\n", s);
2845 if (key->issuer_serial) {
2846 s = key->issuer_serial;
2848 fprintf (fp, _("Serial-No .: 0x%s\n"), s);
2851 if (key->issuer_name) {
2852 s = key->issuer_name;
2854 fprintf (fp, _("Issued By .: "));
2855 parse_and_print_user_id (fp, s);
2860 /* For PGP we list all subkeys. */
2862 gpgme_subkey_t subkey = NULL;
2864 for (idx = 1, subkey = key->subkeys; subkey; idx++, subkey = subkey->next) {
2868 if (m_strlen(s) == 16)
2869 s += 8; /* display only the short keyID */
2870 fprintf (fp, _("Subkey ....: 0x%s"), s);
2871 if (subkey->revoked) {
2873 fputs (_("[Revoked]"), fp);
2875 if (subkey->invalid) {
2877 fputs (_("[Invalid]"), fp);
2879 if (subkey->expired) {
2881 fputs (_("[Expired]"), fp);
2883 if (subkey->disabled) {
2885 fputs (_("[Disabled]"), fp);
2889 if (subkey->timestamp > 0) {
2890 tt = subkey->timestamp;
2892 tm = localtime (&tt);
2893 #ifdef HAVE_LANGINFO_D_T_FMT
2894 strftime (shortbuf, sizeof shortbuf, nl_langinfo (D_T_FMT), tm);
2896 strftime (shortbuf, sizeof shortbuf, "%c", tm);
2898 fprintf (fp, _("Valid From : %s\n"), shortbuf);
2901 if (subkey->expires > 0) {
2902 tt = subkey->expires;
2904 tm = localtime (&tt);
2905 #ifdef HAVE_LANGINFO_D_T_FMT
2906 strftime (shortbuf, sizeof shortbuf, nl_langinfo (D_T_FMT), tm);
2908 strftime (shortbuf, sizeof shortbuf, "%c", tm);
2910 fprintf (fp, _("Valid To ..: %s\n"), shortbuf);
2914 s = gpgme_pubkey_algo_name (subkey->pubkey_algo);
2919 aval = subkey->length;
2923 fprintf (fp, _("Key Type ..: %s, %lu bit %s\n"), "PGP", aval, s);
2925 fprintf (fp, _("Key Usage .: "));
2928 if (subkey->can_encrypt) {
2929 fprintf (fp, "%s%s", delim, _("encryption"));
2932 if (subkey->can_sign) {
2933 fprintf (fp, "%s%s", delim, _("signing"));
2936 if (subkey->can_certify) {
2937 fprintf (fp, "%s%s", delim, _("certification"));
2945 setlocale (LC_TIME, "C");
2949 /* Show detailed information about the selected key */
2950 static void verify_key (crypt_key_t * key)
2953 char cmd[LONG_STRING], tempfile[_POSIX_PATH_MAX];
2955 gpgme_ctx_t listctx = NULL;
2957 gpgme_key_t k = NULL;
2960 mutt_mktemp (tempfile);
2961 if (!(fp = safe_fopen (tempfile, "w"))) {
2962 mutt_perror (_("Can't create temporary file"));
2966 mutt_message _("Collecting data...");
2968 print_key_info (key->kobj, fp);
2970 err = gpgme_new (&listctx);
2972 fprintf (fp, "Internal error: can't create gpgme context: %s\n",
2973 gpgme_strerror (err));
2976 if ((key->flags & KEYFLAG_ISX509))
2977 gpgme_set_protocol (listctx, GPGME_PROTOCOL_CMS);
2981 while ((s = k->chain_id) && k->subkeys && m_strcmp(s, k->subkeys->fpr)) {
2983 err = gpgme_op_keylist_start (listctx, s, 0);
2984 gpgme_key_release (k);
2987 err = gpgme_op_keylist_next (listctx, &k);
2989 fprintf (fp, _("Error finding issuer key: %s\n"), gpgme_strerror (err));
2992 gpgme_op_keylist_end (listctx);
2994 print_key_info (k, fp);
2997 fputs (_("Error: certification chain to long - stopping here\n"), fp);
3003 gpgme_key_release (k);
3004 gpgme_release (listctx);
3006 mutt_clear_error ();
3007 snprintf (cmd, sizeof (cmd), _("Key ID: 0x%s"), crypt_keyid (key));
3008 mutt_do_pager (cmd, tempfile, 0, NULL);
3012 * Implementation of `findkeys'.
3016 /* Convert string_list_t into a pattern string suitable to be passed to GPGME.
3017 We need to convert spaces in an item into a '+' and '%' into
3019 static char *list_to_pattern (string_list_t * list)
3027 for (l = list; l; l = l->next) {
3028 for (s = l->data; *s; s++) {
3033 n++; /* delimiter or end of string */
3035 n++; /* make sure to allocate at least one byte */
3036 pattern = p = p_new(char, n);
3037 for (l = list; l; l = l->next) {
3042 for (s = l->data; *s; s++) {
3048 else if (*s == '+') {
3064 /* Return a list of keys which are candidates for the selection.
3065 Select by looking at the HINTS list. */
3066 static crypt_key_t *get_candidates (string_list_t * hints, unsigned int app,
3069 crypt_key_t *db, *k, **kend;
3075 gpgme_user_id_t uid = NULL;
3077 pattern = list_to_pattern (hints);
3081 err = gpgme_new (&ctx);
3083 mutt_error (_("gpgme_new failed: %s"), gpgme_strerror (err));
3091 if ((app & APPLICATION_PGP)) {
3092 /* Its all a mess. That old GPGME expects different things
3093 depending on the protocol. For gpg we don' t need percent
3094 escaped pappert but simple strings passed in an array to the
3095 keylist_ext_start function. */
3100 for (l = hints, n = 0; l; l = l->next) {
3101 if (l->data && *l->data)
3107 patarr = p_new(char *, n + 1);
3108 for (l = hints, n = 0; l; l = l->next) {
3109 if (l->data && *l->data)
3110 patarr[n++] = m_strdup(l->data);
3113 err = gpgme_op_keylist_ext_start (ctx, (const char **) patarr, secret, 0);
3114 for (n = 0; patarr[n]; n++)
3115 p_delete(&patarr[n]);
3118 mutt_error (_("gpgme_op_keylist_start failed: %s"), gpgme_strerror (err));
3119 gpgme_release (ctx);
3124 while (!(err = gpgme_op_keylist_next (ctx, &key))) {
3125 unsigned int flags = 0;
3127 if (key_check_cap (key, KEY_CAP_CAN_ENCRYPT))
3128 flags |= KEYFLAG_CANENCRYPT;
3129 if (key_check_cap (key, KEY_CAP_CAN_SIGN))
3130 flags |= KEYFLAG_CANSIGN;
3132 #if 0 /* DISABLED code */
3134 /* Bug in gpg. Capabilities are not listed for secret
3135 keys. Try to deduce them from the algorithm. */
3137 switch (key->subkeys[0].pubkey_algo) {
3139 flags |= KEYFLAG_CANENCRYPT;
3140 flags |= KEYFLAG_CANSIGN;
3142 case GPGME_PK_ELG_E:
3143 flags |= KEYFLAG_CANENCRYPT;
3146 flags |= KEYFLAG_CANSIGN;
3150 #endif /* DISABLED code */
3152 for (idx = 0, uid = key->uids; uid; idx++, uid = uid->next) {
3153 k = p_new(crypt_key_t, 1);
3162 if (gpg_err_code (err) != GPG_ERR_EOF)
3163 mutt_error (_("gpgme_op_keylist_next failed: %s"), gpgme_strerror (err));
3164 gpgme_op_keylist_end (ctx);
3169 if ((app & APPLICATION_SMIME)) {
3170 /* and now look for x509 certificates */
3171 gpgme_set_protocol (ctx, GPGME_PROTOCOL_CMS);
3172 err = gpgme_op_keylist_start (ctx, pattern, 0);
3174 mutt_error (_("gpgme_op_keylist_start failed: %s"), gpgme_strerror (err));
3175 gpgme_release (ctx);
3180 while (!(err = gpgme_op_keylist_next (ctx, &key))) {
3181 unsigned int flags = KEYFLAG_ISX509;
3183 if (key_check_cap (key, KEY_CAP_CAN_ENCRYPT))
3184 flags |= KEYFLAG_CANENCRYPT;
3185 if (key_check_cap (key, KEY_CAP_CAN_SIGN))
3186 flags |= KEYFLAG_CANSIGN;
3188 for (idx = 0, uid = key->uids; uid; idx++, uid = uid->next) {
3189 k = p_new(crypt_key_t, 1);
3198 if (gpg_err_code (err) != GPG_ERR_EOF)
3199 mutt_error (_("gpgme_op_keylist_next failed: %s"), gpgme_strerror (err));
3200 gpgme_op_keylist_end (ctx);
3203 gpgme_release (ctx);
3208 /* Add the string STR to the list HINTS. This list is later used to
3210 static string_list_t *crypt_add_string_to_hints (string_list_t * hints, const char *str)
3215 if ((scratch = m_strdup(str)) == NULL)
3218 for (t = strtok (scratch, " ,.:\"()<>\n"); t;
3219 t = strtok (NULL, " ,.:\"()<>\n")) {
3220 if (m_strlen(t) > 3)
3221 hints = mutt_add_list(hints, t);
3228 /* Display a menu to select a key from the array KEYS. FORCED_VALID
3229 will be set to true on return if the user did override the the
3231 static crypt_key_t *crypt_select_key (crypt_key_t * keys,
3232 address_t * p, const char *s,
3233 unsigned int app, int *forced_valid)
3236 crypt_key_t **key_table;
3239 char helpstr[SHORT_STRING], buf[LONG_STRING];
3241 int (*f) (const void *, const void *);
3242 int menu_to_use = 0;
3247 /* build the key table */
3250 for (k = keys; k; k = k->next) {
3251 if (!option (OPTPGPSHOWUNUSABLE) && (k->flags & KEYFLAG_CANTUSE)) {
3258 p_realloc(&key_table, keymax);
3264 if (!i && unusable) {
3265 mutt_error _("All matching keys are marked expired/revoked.");
3271 switch (PgpSortKeys & SORT_MASK) {
3273 f = crypt_compare_date;
3276 f = crypt_compare_keyid;
3279 f = crypt_compare_address;
3283 f = crypt_compare_trust;
3286 qsort (key_table, i, sizeof (crypt_key_t *), f);
3288 if (app & APPLICATION_PGP)
3289 menu_to_use = MENU_KEY_SELECT_PGP;
3290 else if (app & APPLICATION_SMIME)
3291 menu_to_use = MENU_KEY_SELECT_SMIME;
3294 mutt_make_help (buf, sizeof (buf), _("Exit "), menu_to_use, OP_EXIT);
3295 strcat (helpstr, buf); /* __STRCAT_CHECKED__ */
3296 mutt_make_help (buf, sizeof (buf), _("Select "), menu_to_use,
3297 OP_GENERIC_SELECT_ENTRY);
3298 strcat (helpstr, buf); /* __STRCAT_CHECKED__ */
3299 mutt_make_help (buf, sizeof (buf), _("Check key "),
3300 menu_to_use, OP_VERIFY_KEY);
3301 strcat (helpstr, buf); /* __STRCAT_CHECKED__ */
3302 mutt_make_help (buf, sizeof (buf), _("Help"), menu_to_use, OP_HELP);
3303 strcat (helpstr, buf); /* __STRCAT_CHECKED__ */
3305 menu = mutt_new_menu ();
3307 menu->make_entry = crypt_entry;
3308 menu->menu = menu_to_use;
3309 menu->help = helpstr;
3310 menu->data = key_table;
3315 if ((app & APPLICATION_PGP) && (app & APPLICATION_SMIME))
3316 ts = _("PGP and S/MIME keys matching");
3317 else if ((app & APPLICATION_PGP))
3318 ts = _("PGP keys matching");
3319 else if ((app & APPLICATION_SMIME))
3320 ts = _("S/MIME keys matching");
3322 ts = _("keys matching");
3325 snprintf (buf, sizeof (buf), _("%s <%s>."), ts, p->mailbox);
3327 snprintf (buf, sizeof (buf), _("%s \"%s\"."), ts, s);
3331 mutt_clear_error ();
3335 switch (mutt_menuLoop (menu)) {
3337 verify_key (key_table[menu->current]);
3338 menu->redraw = REDRAW_FULL;
3342 mutt_message ("%s", key_table[menu->current]->uid);
3345 case OP_GENERIC_SELECT_ENTRY:
3346 /* FIXME make error reporting more verbose - this should be
3347 easy because gpgme provides more information */
3348 if (option (OPTPGPCHECKTRUST)) {
3349 if (!crypt_key_is_valid (key_table[menu->current])) {
3350 mutt_error _("This key can't be used: "
3351 "expired/disabled/revoked.");
3356 if (option (OPTPGPCHECKTRUST) &&
3357 (!crypt_id_is_valid (key_table[menu->current])
3358 || !crypt_id_is_strong (key_table[menu->current]))) {
3360 char buff[LONG_STRING];
3362 if (key_table[menu->current]->flags & KEYFLAG_CANTUSE)
3363 s = N_("ID is expired/disabled/revoked.");
3365 gpgme_validity_t val = GPGME_VALIDITY_UNKNOWN;
3366 gpgme_user_id_t uid = NULL;
3371 uid = key_table[menu->current]->kobj->uids;
3372 for (j = 0; (j < key_table[menu->current]->idx) && uid;
3373 j++, uid = uid->next);
3375 val = uid->validity;
3378 case GPGME_VALIDITY_UNKNOWN:
3379 case GPGME_VALIDITY_UNDEFINED:
3380 warn_s = N_("ID has undefined validity.");
3382 case GPGME_VALIDITY_NEVER:
3383 warn_s = N_("ID is not valid.");
3385 case GPGME_VALIDITY_MARGINAL:
3386 warn_s = N_("ID is only marginally valid.");
3388 case GPGME_VALIDITY_FULL:
3389 case GPGME_VALIDITY_ULTIMATE:
3393 snprintf (buff, sizeof (buff),
3394 _("%s Do you really want to use the key?"), _(warn_s));
3396 if (mutt_yesorno (buff, 0) != 1) {
3397 mutt_clear_error ();
3404 k = crypt_copy_key (key_table[menu->current]);
3415 mutt_menuDestroy (&menu);
3416 p_delete(&key_table);
3418 set_option (OPTNEEDREDRAW);
3423 static crypt_key_t *crypt_getkeybyaddr (address_t * a, short abilities,
3424 unsigned int app, int *forced_valid)
3427 string_list_t *hints = NULL;
3432 int this_key_has_strong;
3433 int this_key_has_weak;
3434 int this_key_has_invalid;
3437 crypt_key_t *keys, *k;
3438 crypt_key_t *the_valid_key = NULL;
3439 crypt_key_t *matches = NULL;
3440 crypt_key_t **matches_endp = &matches;
3444 if (a && a->mailbox)
3445 hints = crypt_add_string_to_hints (hints, a->mailbox);
3446 if (a && a->personal)
3447 hints = crypt_add_string_to_hints (hints, a->personal);
3449 mutt_message (_("Looking for keys matching \"%s\"..."), a->mailbox);
3450 keys = get_candidates (hints, app, (abilities & KEYFLAG_CANSIGN));
3452 string_list_wipe(&hints);
3457 debug_print (5, ("looking for %s <%s>.\n", a->personal, a->mailbox));
3459 for (k = keys; k; k = k->next) {
3460 debug_print (5, (" looking at key: %s `%.15s'\n", crypt_keyid (k), k->uid));
3462 if (abilities && !(k->flags & abilities)) {
3463 debug_print (5, (" insufficient abilities: Has %x, want %x\n", k->flags, abilities));
3467 this_key_has_weak = 0; /* weak but valid match */
3468 this_key_has_invalid = 0; /* invalid match */
3469 this_key_has_strong = 0; /* strong and valid match */
3470 match = 0; /* any match */
3472 r = rfc822_parse_adrlist (NULL, k->uid);
3473 for (p = r; p; p = p->next) {
3474 int validity = crypt_id_matches_addr (a, p, k);
3476 if (validity & CRYPT_KV_MATCH) /* something matches */
3479 /* is this key a strong candidate? */
3480 if ((validity & CRYPT_KV_VALID)
3481 && (validity & CRYPT_KV_STRONGID)
3482 && (validity & CRYPT_KV_ADDR)) {
3483 if (the_valid_key && the_valid_key != k)
3486 this_key_has_strong = 1;
3488 else if ((validity & CRYPT_KV_MATCH)
3489 && !(validity & CRYPT_KV_VALID))
3490 this_key_has_invalid = 1;
3491 else if ((validity & CRYPT_KV_MATCH)
3492 && (!(validity & CRYPT_KV_STRONGID)
3493 || !(validity & CRYPT_KV_ADDR)))
3494 this_key_has_weak = 1;
3496 address_list_wipe(&r);
3501 if (!this_key_has_strong && this_key_has_invalid)
3503 if (!this_key_has_strong && this_key_has_weak)
3506 *matches_endp = tmp = crypt_copy_key (k);
3507 matches_endp = &tmp->next;
3508 the_valid_key = tmp;
3512 crypt_free_key (&keys);
3515 if (the_valid_key && !multi && !weak
3516 && !(invalid && option (OPTPGPSHOWUNUSABLE))) {
3518 * There was precisely one strong match on a valid ID, there
3519 * were no valid keys with weak matches, and we aren't
3520 * interested in seeing invalid keys.
3522 * Proceed without asking the user.
3524 k = crypt_copy_key (the_valid_key);
3528 * Else: Ask the user.
3530 k = crypt_select_key (matches, a, NULL, app, forced_valid);
3532 crypt_free_key (&matches);
3541 static crypt_key_t *crypt_getkeybystr (char *p, short abilities,
3542 unsigned int app, int *forced_valid)
3544 string_list_t *hints = NULL;
3546 crypt_key_t *matches = NULL;
3547 crypt_key_t **matches_endp = &matches;
3551 mutt_message (_("Looking for keys matching \"%s\"..."), p);
3555 hints = crypt_add_string_to_hints (hints, p);
3556 keys = get_candidates (hints, app, (abilities & KEYFLAG_CANSIGN));
3557 string_list_wipe(&hints);
3562 for (k = keys; k; k = k->next) {
3563 if (abilities && !(k->flags & abilities))
3567 debug_print (5, ("matching \"%s\" against " "key %s, \"%s\":\n", p, crypt_keyid (k), k->uid));
3569 if (!*p || !m_strcasecmp(p, crypt_keyid (k))
3570 || (!m_strncasecmp(p, "0x", 2)
3571 && !m_strcasecmp(p + 2, crypt_keyid (k)))
3572 || (option (OPTPGPLONGIDS)
3573 && !m_strncasecmp(p, "0x", 2)
3574 && !m_strcasecmp(p + 2, crypt_keyid (k) + 8))
3575 || m_stristr(k->uid, p)) {
3578 debug_print (5, ("match.\n"));
3580 *matches_endp = tmp = crypt_copy_key (k);
3581 matches_endp = &tmp->next;
3585 crypt_free_key (&keys);
3588 k = crypt_select_key (matches, NULL, p, app, forced_valid);
3589 crypt_free_key (&matches);
3596 /* Display TAG as a prompt to ask for a key. If WHATFOR is not null
3597 use it as default and store it under that label as the next
3598 default. ABILITIES describe the required key abilities (sign,
3599 encrypt) and APP the type of the requested key; ether S/MIME or
3600 PGP. Return a copy of the key or NULL if not found. */
3601 static crypt_key_t *crypt_ask_for_key (char *tag,
3604 unsigned int app, int *forced_valid)
3607 char resp[SHORT_STRING];
3608 struct crypt_cache *l = NULL;
3612 forced_valid = &dummy;
3614 mutt_clear_error ();
3620 for (l = id_defaults; l; l = l->next)
3621 if (!m_strcasecmp(whatfor, l->what)) {
3622 m_strcpy(resp, sizeof(resp), NONULL(l->dflt));
3630 if (mutt_get_field (tag, resp, sizeof (resp), M_CLEAR) != 0)
3635 m_strreplace(&l->dflt, resp);
3637 l = p_new(struct crypt_cache, 1);
3638 l->next = id_defaults;
3640 l->what = m_strdup(whatfor);
3641 l->dflt = m_strdup(resp);
3645 if ((key = crypt_getkeybystr (resp, abilities, app, forced_valid)))
3653 /* This routine attempts to find the keyids of the recipients of a
3654 message. It returns NULL if any of the keys can not be found. */
3655 static char *find_keys (address_t * to, address_t * cc, address_t * bcc,
3658 char *keyID, *keylist = NULL, *t;
3659 ssize_t keylist_size = 0;
3660 ssize_t keylist_used = 0;
3661 address_t *tmp = NULL, *addr = NULL;
3662 address_t **last = &tmp;
3665 crypt_key_t *k_info, *key;
3666 const char *fqdn = mutt_fqdn (1);
3669 *r_application = APPLICATION_PGP | APPLICATION_SMIME;
3672 for (i = 0; i < 3; i++) {
3687 *last = address_list_dup (p);
3689 last = &((*last)->next);
3693 rfc822_qualify (tmp, fqdn);
3695 tmp = mutt_remove_duplicates (tmp);
3697 for (p = tmp; p; p = p->next) {
3698 char buf[LONG_STRING];
3699 int forced_valid = 0;
3704 if ((keyID = mutt_crypt_hook (p)) != NULL) {
3707 snprintf (buf, sizeof (buf), _("Use keyID = \"%s\" for %s?"),
3709 if ((r = mutt_yesorno (buf, M_YES)) == M_YES) {
3710 /* check for e-mail address */
3711 if ((t = strchr (keyID, '@')) &&
3712 (addr = rfc822_parse_adrlist (NULL, keyID))) {
3714 rfc822_qualify (addr, fqdn);
3719 k_info = crypt_getkeybystr (keyID, KEYFLAG_CANENCRYPT,
3720 *r_application, &forced_valid);
3722 k_info = crypt_getkeybystr (keyID, KEYFLAG_CANENCRYPT,
3723 app, &forced_valid);
3729 address_list_wipe(&tmp);
3730 address_list_wipe(&addr);
3736 && (k_info = crypt_getkeybyaddr (q, KEYFLAG_CANENCRYPT,
3737 app, &forced_valid)) == NULL) {
3738 snprintf (buf, sizeof (buf), _("Enter keyID for %s: "), q->mailbox);
3740 if ((key = crypt_ask_for_key (buf, q->mailbox, KEYFLAG_CANENCRYPT,
3746 &forced_valid)) == NULL) {
3748 address_list_wipe(&tmp);
3749 address_list_wipe(&addr);
3757 const char *s = crypt_fpr (key);
3760 if (key->flags & KEYFLAG_ISX509)
3761 *r_application &= ~APPLICATION_PGP;
3762 if (!(key->flags & KEYFLAG_ISX509))
3763 *r_application &= ~APPLICATION_SMIME;
3766 keylist_size += m_strlen(s) + 4 + 1;
3767 p_realloc(&keylist, keylist_size);
3768 sprintf (keylist + keylist_used, "%s0x%s%s", /* __SPRINTF_CHECKED__ */
3769 keylist_used ? " " : "", s, forced_valid ? "!" : "");
3771 keylist_used = m_strlen(keylist);
3773 crypt_free_key (&key);
3774 address_list_wipe(&addr);
3776 address_list_wipe(&tmp);
3780 char *pgp_gpgme_findkeys (address_t * to, address_t * cc, address_t * bcc)
3782 return find_keys (to, cc, bcc, APPLICATION_PGP);
3785 char *smime_gpgme_findkeys (address_t * to, address_t * cc, address_t * bcc)
3787 return find_keys (to, cc, bcc, APPLICATION_SMIME);
3791 * Implementation of `init'.
3794 /* Initialization. */
3795 static void init_gpgme (void)
3797 /* Make sure that gpg-agent is running. */
3798 if (!getenv ("GPG_AGENT_INFO")) {
3799 mutt_error ("\nUsing GPGME backend, although no gpg-agent is running");
3800 if (mutt_any_key_to_continue (NULL) == -1)
3805 void pgp_gpgme_init (void)
3810 void smime_gpgme_init (void)
3814 static int gpgme_send_menu (HEADER * msg, int *redraw, int is_smime)
3817 char input_signas[SHORT_STRING];
3820 if (msg->security & APPLICATION_PGP)
3822 else if (msg->security & APPLICATION_SMIME)
3827 mutt_multi_choice (_
3828 ("S/MIME (e)ncrypt, (s)ign, sign (a)s, (b)oth, (p)gp or (c)lear?"),
3832 mutt_multi_choice (_
3833 ("PGP (e)ncrypt, (s)ign, sign (a)s, (b)oth, s/(m)ime or (c)lear?"),
3837 case 1: /* (e)ncrypt */
3838 msg->security |= (is_smime ? SMIMEENCRYPT : PGPENCRYPT);
3839 msg->security &= ~(is_smime ? SMIMESIGN : PGPSIGN);
3842 case 2: /* (s)ign */
3843 msg->security |= (is_smime ? SMIMESIGN : PGPSIGN);
3844 msg->security &= ~(is_smime ? SMIMEENCRYPT : PGPENCRYPT);
3847 case 3: /* sign (a)s */
3848 /* unset_option(OPTCRYPTCHECKTRUST); */
3849 if ((p = crypt_ask_for_key (_("Sign as: "), NULL, KEYFLAG_CANSIGN,
3850 is_smime ? APPLICATION_SMIME :
3851 APPLICATION_PGP, NULL))) {
3852 snprintf (input_signas, sizeof (input_signas), "0x%s", crypt_keyid (p));
3853 m_strreplace(is_smime ? &SmimeDefaultKey : &PgpSignAs,
3855 crypt_free_key (&p);
3857 msg->security |= (is_smime ? SMIMESIGN : PGPSIGN);
3861 msg->security &= (is_smime ? ~SMIMESIGN : ~PGPSIGN);
3864 *redraw = REDRAW_FULL;
3867 case 4: /* (b)oth */
3869 (is_smime ? (SMIMEENCRYPT | SMIMESIGN) : (PGPENCRYPT | PGPSIGN));
3872 case 5: /* (p)gp or s/(m)ime */
3873 is_smime = !is_smime;
3876 case 6: /* (c)lear */
3881 if (choice == 6 || choice == 7);
3882 else if (is_smime) {
3883 msg->security &= ~APPLICATION_PGP;
3884 msg->security |= APPLICATION_SMIME;
3887 msg->security &= ~APPLICATION_SMIME;
3888 msg->security |= APPLICATION_PGP;
3891 return (msg->security);
3894 int pgp_gpgme_send_menu (HEADER * msg, int *redraw)
3896 return gpgme_send_menu (msg, redraw, 0);
3899 int smime_gpgme_send_menu (HEADER * msg, int *redraw)
3901 return gpgme_send_menu (msg, redraw, 1);
3904 static int verify_sender (HEADER * h, gpgme_protocol_t protocol __attribute__((unused)))
3906 address_t *sender = NULL;
3907 unsigned int ret = 1;
3910 h->env->from = mutt_expand_aliases (h->env->from);
3911 sender = h->env->from;
3913 else if (h->env->sender) {
3914 h->env->sender = mutt_expand_aliases (h->env->sender);
3915 sender = h->env->sender;
3919 if (signature_key) {
3920 gpgme_key_t key = signature_key;
3921 gpgme_user_id_t uid = NULL;
3922 int sender_length = 0;
3925 sender_length = m_strlen(sender->mailbox);
3926 for (uid = key->uids; uid && ret; uid = uid->next) {
3927 uid_length = m_strlen(uid->email);
3928 if (1 && (uid->email[0] == '<')
3929 && (uid->email[uid_length - 1] == '>')
3930 && (uid_length == sender_length + 2)
3931 && (!strncmp (uid->email + 1, sender->mailbox, sender_length)))
3936 mutt_any_key_to_continue ("Failed to verify sender");
3939 mutt_any_key_to_continue ("Failed to figure out sender");
3941 if (signature_key) {
3942 gpgme_key_release (signature_key);
3943 signature_key = NULL;
3949 int smime_gpgme_verify_sender (HEADER * h)
3951 return verify_sender (h, GPGME_PROTOCOL_CMS);