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
21 #include <lib-lib/mem.h>
22 #include <lib-lib/str.h>
23 #include <lib-lib/ascii.h>
24 #include <lib-lib/macros.h>
25 #include <lib-lib/file.h>
26 #include <lib-lib/debug.h>
28 #include <lib-mime/mime.h>
30 #include <lib-ui/curses.h>
31 #include <lib-ui/enter.h>
32 #include <lib-ui/menu.h>
35 #include <lib-crypt/crypt.h>
39 #include "recvattach.h"
56 #ifdef HAVE_LANGINFO_D_T_FMT
60 #ifdef HAVE_SYS_TIME_H
61 # include <sys/time.h>
64 #ifdef HAVE_SYS_RESOURCE_H
65 # include <sys/resource.h>
71 #define digitp(p) (*(p) >= '0' && *(p) <= '9')
72 #define hexdigitp(a) (digitp (a) \
73 || (*(a) >= 'A' && *(a) <= 'F') \
74 || (*(a) >= 'a' && *(a) <= 'f'))
75 #define xtoi_1(p) (*(p) <= '9'? (*(p)- '0'): \
76 *(p) <= 'F'? (*(p)-'A'+10):(*(p)-'a'+10))
77 #define xtoi_2(p) ((xtoi_1(p) * 16) + xtoi_1((p)+1))
79 /* Values used for comparing addresses. */
80 #define CRYPT_KV_VALID 1
81 #define CRYPT_KV_ADDR 2
82 #define CRYPT_KV_STRING 4
83 #define CRYPT_KV_STRONGID 8
84 #define CRYPT_KV_MATCH (CRYPT_KV_ADDR|CRYPT_KV_STRING)
93 struct crypt_cache *next;
101 /* We work based on user IDs, getting from a user ID to the key is
102 check and does not need any memory (gpgme uses reference counting). */
103 typedef struct crypt_keyinfo {
104 struct crypt_keyinfo *next;
106 int idx; /* and the user ID at this index */
107 const char *uid; /* and for convenience point to this user ID */
108 unsigned int flags; /* global and per uid flags (for convenience) */
111 typedef struct crypt_entry {
117 static struct crypt_cache *id_defaults = NULL;
118 static gpgme_key_t signature_key = NULL;
121 * General helper functions.
124 /* return true when S points to a didgit or letter. */
125 static int digit_or_letter (const unsigned char *s)
127 return ((*s >= '0' && *s <= '9')
128 || (*s >= 'A' && *s <= 'Z')
129 || (*s >= 'a' && *s <= 'z'));
133 /* Print the utf-8 encoded string BUF of length LEN bytes to stream
134 FP. Convert the character set. */
135 static void print_utf8 (FILE * fp, const char *buf, ssize_t len)
139 tstr = p_dupstr(buf, len);
140 mutt_convert_string (&tstr, "utf-8", Charset, M_ICONV_HOOK_FROM);
150 /* Return the keyID for the key K. Note that this string is valid as
151 long as K is valid */
152 static const char *crypt_keyid (crypt_key_t * k)
154 const char *s = "????????";
156 if (k->kobj && k->kobj->subkeys) {
157 s = k->kobj->subkeys->keyid;
158 if ((!option (OPTPGPLONGIDS)) && (m_strlen(s) == 16))
159 /* Return only the short keyID. */
166 /* Return the hexstring fingerprint from the key K. */
167 static const char *crypt_fpr (crypt_key_t * k)
171 if (k->kobj && k->kobj->subkeys)
172 s = k->kobj->subkeys->fpr;
177 /* Parse FLAGS and return a statically allocated(!) string with them. */
178 static char *crypt_key_abilities (int flags)
182 if (!(flags & KEYFLAG_CANENCRYPT))
184 else if (flags & KEYFLAG_PREFER_SIGNING)
189 if (!(flags & KEYFLAG_CANSIGN))
191 else if (flags & KEYFLAG_PREFER_ENCRYPTION)
201 /* Parse FLAGS and return a character describing the most important flag. */
202 static char crypt_flags (int flags)
204 if (flags & KEYFLAG_REVOKED)
206 else if (flags & KEYFLAG_EXPIRED)
208 else if (flags & KEYFLAG_DISABLED)
210 else if (flags & KEYFLAG_CRITICAL)
216 /* Return a copy of KEY. */
217 static crypt_key_t *crypt_copy_key (crypt_key_t *key)
221 k = p_new(crypt_key_t, 1);
223 gpgme_key_ref (key->kobj);
226 k->flags = key->flags;
231 /* Release all the keys at the address of KEYLIST and set the address
233 static void crypt_free_key (crypt_key_t ** keylist)
236 crypt_key_t *k = (*keylist)->next;
243 /* Return trute when key K is valid. */
244 static int crypt_key_is_valid (crypt_key_t * k)
246 if (k->flags & KEYFLAG_CANTUSE)
251 /* Return true whe validity of KEY is sufficient. */
252 static int crypt_id_is_strong (crypt_key_t * key)
254 gpgme_validity_t val = GPGME_VALIDITY_UNKNOWN;
255 gpgme_user_id_t uid = NULL;
259 if ((key->flags & KEYFLAG_ISX509))
262 for (i = 0, uid = key->kobj->uids; (i < key->idx) && uid;
263 i++, uid = uid->next);
268 case GPGME_VALIDITY_UNKNOWN:
269 case GPGME_VALIDITY_UNDEFINED:
270 case GPGME_VALIDITY_NEVER:
271 case GPGME_VALIDITY_MARGINAL:
275 case GPGME_VALIDITY_FULL:
276 case GPGME_VALIDITY_ULTIMATE:
284 /* Return true when the KEY is valid, i.e. not marked as unusable. */
285 static int crypt_id_is_valid (crypt_key_t * key)
287 return !(key->flags & KEYFLAG_CANTUSE);
290 /* Return a bit vector describing how well the addresses ADDR and
291 U_ADDR match and whether KEY is valid. */
292 static int crypt_id_matches_addr (address_t * addr, address_t * u_addr,
297 if (crypt_id_is_valid (key))
298 rv |= CRYPT_KV_VALID;
300 if (crypt_id_is_strong (key))
301 rv |= CRYPT_KV_STRONGID;
303 if (addr->mailbox && u_addr->mailbox
304 && m_strcasecmp(addr->mailbox, u_addr->mailbox) == 0)
307 if (addr->personal && u_addr->personal
308 && m_strcasecmp(addr->personal, u_addr->personal) == 0)
309 rv |= CRYPT_KV_STRING;
316 * GPGME convenient functions.
319 /* Create a new gpgme context and return it. With FOR_SMIME set to
320 true, the protocol of the context is set to CMS. */
321 static gpgme_ctx_t create_gpgme_context (int for_smime)
326 err = gpgme_new (&ctx);
328 mutt_error (_("error creating gpgme context: %s\n"), gpgme_strerror (err));
334 err = gpgme_set_protocol (ctx, GPGME_PROTOCOL_CMS);
336 mutt_error (_("error enabling CMS protocol: %s\n"), gpgme_strerror (err));
345 /* Create a new gpgme data object. This is a wrapper to die on
347 static gpgme_data_t create_gpgme_data (void)
352 err = gpgme_data_new (&data);
354 mutt_error (_("error creating gpgme data object: %s\n"),
355 gpgme_strerror (err));
362 /* Create a new GPGME Data object from the mail body A. With CONVERT
363 passed as true, the lines are converted to CR,LF if required.
364 Return NULL on error or the gpgme_data_t object on success. */
365 static gpgme_data_t body_to_data_object (BODY * a, int convert)
367 char tempfile[_POSIX_PATH_MAX];
372 mutt_mktemp (tempfile);
373 fptmp = safe_fopen (tempfile, "w+");
375 mutt_perror (tempfile);
379 mutt_write_mime_header (a, fptmp);
381 mutt_write_mime_body (a, fptmp);
385 unsigned char buf[1];
387 data = create_gpgme_data ();
389 while ((c = fgetc (fptmp)) != EOF) {
393 if (c == '\n' && !hadcr) {
395 gpgme_data_write (data, buf, 1);
400 /* FIXME: This is quite suboptimal */
402 gpgme_data_write (data, buf, 1);
405 gpgme_data_seek (data, 0, SEEK_SET);
409 err = gpgme_data_new_from_file (&data, tempfile, 1);
413 mutt_error (_("error allocating data object: %s\n"), gpgme_strerror (err));
420 /* Create a GPGME data object from the stream FP but limit the object
421 to LENGTH bytes starting at OFFSET bytes from the beginning of the
423 static gpgme_data_t file_to_data_object (FILE * fp, long offset, long length)
428 err = gpgme_data_new_from_filepart (&data, NULL, fp, offset, length);
430 mutt_error (_("error allocating data object: %s\n"), gpgme_strerror (err));
437 /* Write a GPGME data object to the stream FP. */
438 static int data_object_to_stream (gpgme_data_t data, FILE * fp)
444 err = ((gpgme_data_seek (data, 0, SEEK_SET) == -1)
445 ? gpgme_error_from_errno (errno) : 0);
447 mutt_error (_("error rewinding data object: %s\n"), gpgme_strerror (err));
451 while ((nread = gpgme_data_read (data, buf, sizeof (buf)))) {
452 /* fixme: we are not really converting CRLF to LF but just
453 skipping CR. Doing it correctly needs a more complex logic */
454 for (p = buf; nread; p++, nread--) {
460 mutt_perror ("[tempfile]");
465 mutt_error (_("error reading data object: %s\n"), strerror (errno));
471 /* Copy a data object to a newly created temporay file and return that
472 filename. Caller must free. With RET_FP not NULL, don't close the
473 stream but return it there. */
474 static char *data_object_to_tempfile (gpgme_data_t data, FILE ** ret_fp)
477 char tempfile[_POSIX_PATH_MAX];
481 mutt_mktemp (tempfile);
482 fp = safe_fopen (tempfile, "w+");
484 mutt_perror (tempfile);
488 err = ((gpgme_data_seek (data, 0, SEEK_SET) == -1)
489 ? gpgme_error_from_errno (errno) : 0);
493 while ((nread = gpgme_data_read (data, buf, sizeof (buf)))) {
494 if (fwrite (buf, nread, 1, fp) != 1) {
495 mutt_perror (tempfile);
507 mutt_error (_("error reading data object: %s\n"), gpgme_strerror (err));
514 return m_strdup(tempfile);
518 /* Create a GpgmeRecipientSet from the keys in the string KEYLIST.
519 The keys must be space delimited. */
520 static gpgme_key_t *create_recipient_set (const char *keylist,
521 gpgme_protocol_t protocol)
527 gpgme_key_t *rset = NULL;
528 unsigned int rset_n = 0;
529 gpgme_key_t key = NULL;
530 gpgme_ctx_t context = NULL;
532 err = gpgme_new (&context);
534 err = gpgme_set_protocol (context, protocol);
541 for (i = 0; *s && *s != ' ' && i < ssizeof(buf) - 1;)
545 if (i > 1 && buf[i - 1] == '!') {
546 /* The user selected to override the valididy of that
550 err = gpgme_get_key (context, buf, &key, 0);
552 key->uids->validity = GPGME_VALIDITY_FULL;
556 err = gpgme_get_key (context, buf, &key, 0);
559 p_realloc(&rset, rset_n + 1);
560 rset[rset_n++] = key;
563 mutt_error (_("error adding recipient `%s': %s\n"),
564 buf, gpgme_strerror (err));
572 /* NULL terminate. */
573 p_realloc(&rset, rset_n + 1);
574 rset[rset_n++] = NULL;
577 gpgme_release (context);
583 /* Make sure that the correct signer is set. Returns 0 on success. */
584 static int set_signer (gpgme_ctx_t ctx, int for_smime)
586 char *signid = for_smime ? SmimeDefaultKey : PgpSignAs;
589 gpgme_key_t key, key2;
591 if (!signid || !*signid)
594 listctx = create_gpgme_context (for_smime);
595 err = gpgme_op_keylist_start (listctx, signid, 1);
597 err = gpgme_op_keylist_next (listctx, &key);
599 gpgme_release (listctx);
600 mutt_error (_("secret key `%s' not found: %s\n"),
601 signid, gpgme_strerror (err));
604 err = gpgme_op_keylist_next (listctx, &key2);
606 gpgme_key_release (key);
607 gpgme_key_release (key2);
608 gpgme_release (listctx);
609 mutt_error (_("ambiguous specification of secret key `%s'\n"), signid);
612 gpgme_op_keylist_end (listctx);
613 gpgme_release (listctx);
615 gpgme_signers_clear (ctx);
616 err = gpgme_signers_add (ctx, key);
617 gpgme_key_release (key);
619 mutt_error (_("error setting secret key `%s': %s\n"),
620 signid, gpgme_strerror (err));
627 /* Encrypt the gpgme data object PLAINTEXT to the recipients in RSET
628 and return an allocated filename to a temporary file containing the
629 enciphered text. With USE_SMIME set to true, the smime backend is
630 used. With COMBINED_SIGNED a PGP message is signed and
631 encrypted. Returns NULL in case of error */
632 static char *encrypt_gpgme_object (gpgme_data_t plaintext, gpgme_key_t * rset,
633 int use_smime, int combined_signed)
637 gpgme_data_t ciphertext;
640 ctx = create_gpgme_context (use_smime);
642 gpgme_set_armor (ctx, 1);
644 ciphertext = create_gpgme_data ();
646 if (combined_signed) {
647 if (set_signer (ctx, use_smime)) {
648 gpgme_data_release (ciphertext);
652 err = gpgme_op_encrypt_sign (ctx, rset, GPGME_ENCRYPT_ALWAYS_TRUST,
653 plaintext, ciphertext);
656 err = gpgme_op_encrypt (ctx, rset, GPGME_ENCRYPT_ALWAYS_TRUST,
657 plaintext, ciphertext);
658 mutt_need_hard_redraw ();
660 mutt_error (_("error encrypting data: %s\n"), gpgme_strerror (err));
661 gpgme_data_release (ciphertext);
668 outfile = data_object_to_tempfile (ciphertext, NULL);
669 gpgme_data_release (ciphertext);
673 /* Find the "micalg" parameter from the last Gpgme operation on
674 context CTX. It is expected that this operation was a sign
675 operation. Return the algorithm name as a C string in buffer BUF
676 which must have been allocated by the caller with size BUFLEN.
677 Returns 0 on success or -1 in case of an error. The return string
678 is truncted to BUFLEN - 1. */
679 static int get_micalg (gpgme_ctx_t ctx, char *buf, ssize_t buflen)
681 gpgme_sign_result_t result = NULL;
682 const char *algorithm_name = NULL;
688 result = gpgme_op_sign_result (ctx);
690 algorithm_name = gpgme_hash_algo_name (result->signatures->hash_algo);
691 if (algorithm_name) {
692 m_strcpy(buf, buflen, algorithm_name);
696 return *buf ? 0 : -1;
699 static void print_time (time_t t, STATE * s)
703 setlocale (LC_TIME, "");
704 #ifdef HAVE_LANGINFO_D_T_FMT
705 strftime (p, sizeof (p), nl_langinfo (D_T_FMT), localtime (&t));
707 strftime (p, sizeof (p), "%c", localtime (&t));
709 setlocale (LC_TIME, "C");
710 state_attach_puts (p, s);
714 * Implementation of `sign_message'.
717 /* Sign the MESSAGE in body A either using OpenPGP or S/MIME when
718 USE_SMIME is passed as true. Returns the new body or NULL on
720 static BODY *sign_message (BODY * a, int use_smime)
727 gpgme_data_t message, signature;
729 convert_to_7bit (a); /* Signed data _must_ be in 7-bit format. */
731 message = body_to_data_object (a, 1);
734 signature = create_gpgme_data ();
736 ctx = create_gpgme_context (use_smime);
738 gpgme_set_armor (ctx, 1);
740 if (set_signer (ctx, use_smime)) {
741 gpgme_data_release (signature);
746 err = gpgme_op_sign (ctx, message, signature, GPGME_SIG_MODE_DETACH);
747 mutt_need_hard_redraw ();
748 gpgme_data_release (message);
750 gpgme_data_release (signature);
752 mutt_error (_("error signing data: %s\n"), gpgme_strerror (err));
756 sigfile = data_object_to_tempfile (signature, NULL);
757 gpgme_data_release (signature);
763 t = mutt_new_body ();
764 t->type = TYPEMULTIPART;
765 t->subtype = m_strdup("signed");
766 t->encoding = ENC7BIT;
768 t->disposition = DISPINLINE;
770 mutt_generate_boundary (&t->parameter);
771 mutt_set_parameter ("protocol",
772 use_smime ? "application/pkcs7-signature"
773 : "application/pgp-signature", &t->parameter);
774 /* Get the micalg from gpgme. Old gpgme versions don't support this
775 for S/MIME so we assume sha-1 in this case. */
776 if (!get_micalg (ctx, buf, sizeof buf))
777 mutt_set_parameter ("micalg", buf, &t->parameter);
779 mutt_set_parameter ("micalg", "sha1", &t->parameter);
785 t->parts->next = mutt_new_body ();
787 t->type = TYPEAPPLICATION;
789 t->subtype = m_strdup("pkcs7-signature");
790 mutt_set_parameter ("name", "smime.p7s", &t->parameter);
791 t->encoding = ENCBASE64;
793 t->disposition = DISPATTACH;
794 t->d_filename = m_strdup("smime.p7s");
797 t->subtype = m_strdup("pgp-signature");
799 t->disposition = DISPINLINE;
800 t->encoding = ENC7BIT;
802 t->filename = sigfile;
803 t->unlink = 1; /* ok to remove this file after sending. */
809 BODY *pgp_gpgme_sign_message (BODY * a)
811 return sign_message (a, 0);
814 BODY *smime_gpgme_sign_message (BODY * a)
816 return sign_message (a, 1);
820 * Implementation of `encrypt_message'.
823 /* Encrypt the mail body A to all keys given as space separated keyids
824 or fingerprints in KEYLIST and return the encrypted body. */
825 BODY *pgp_gpgme_encrypt_message (BODY * a, char *keylist, int sign)
827 char *outfile = NULL;
829 gpgme_key_t *rset = NULL;
830 gpgme_data_t plaintext;
832 rset = create_recipient_set (keylist, GPGME_PROTOCOL_OpenPGP);
838 plaintext = body_to_data_object (a, 0);
844 outfile = encrypt_gpgme_object (plaintext, rset, 0, sign);
845 gpgme_data_release (plaintext);
850 t = mutt_new_body ();
851 t->type = TYPEMULTIPART;
852 t->subtype = m_strdup("encrypted");
853 t->encoding = ENC7BIT;
855 t->disposition = DISPINLINE;
857 mutt_generate_boundary (&t->parameter);
858 mutt_set_parameter ("protocol", "application/pgp-encrypted", &t->parameter);
860 t->parts = mutt_new_body ();
861 t->parts->type = TYPEAPPLICATION;
862 t->parts->subtype = m_strdup("pgp-encrypted");
863 t->parts->encoding = ENC7BIT;
865 t->parts->next = mutt_new_body ();
866 t->parts->next->type = TYPEAPPLICATION;
867 t->parts->next->subtype = m_strdup("octet-stream");
868 t->parts->next->encoding = ENC7BIT;
869 t->parts->next->filename = outfile;
870 t->parts->next->use_disp = 1;
871 t->parts->next->disposition = DISPINLINE;
872 t->parts->next->unlink = 1; /* delete after sending the message */
873 t->parts->next->d_filename = m_strdup("msg.asc"); /* non pgp/mime
880 * Implementation of `smime_build_smime_entity'.
883 /* Encrypt the mail body A to all keys given as space separated
884 fingerprints in KEYLIST and return the S/MIME encrypted body. */
885 BODY *smime_gpgme_build_smime_entity (BODY * a, char *keylist)
887 char *outfile = NULL;
889 gpgme_key_t *rset = NULL;
890 gpgme_data_t plaintext;
892 rset = create_recipient_set (keylist, GPGME_PROTOCOL_CMS);
896 plaintext = body_to_data_object (a, 0);
902 outfile = encrypt_gpgme_object (plaintext, rset, 1, 0);
903 gpgme_data_release (plaintext);
908 t = mutt_new_body ();
909 t->type = TYPEAPPLICATION;
910 t->subtype = m_strdup("pkcs7-mime");
911 mutt_set_parameter ("name", "smime.p7m", &t->parameter);
912 mutt_set_parameter ("smime-type", "enveloped-data", &t->parameter);
913 t->encoding = ENCBASE64; /* The output of OpenSSL SHOULD be binary */
915 t->disposition = DISPATTACH;
916 t->d_filename = m_strdup("smime.p7m");
917 t->filename = outfile;
918 t->unlink = 1; /*delete after sending the message */
927 * Implementation of `verify_one'.
930 /* Display the common attributes of the signature summary SUM.
931 Return 1 if there is is a severe warning.
933 static int show_sig_summary (unsigned long sum,
934 gpgme_ctx_t ctx, gpgme_key_t key, int idx,
939 if ((sum & GPGME_SIGSUM_KEY_REVOKED)) {
940 state_attach_puts (_("Warning: One of the keys has been revoked\n"), s);
944 if ((sum & GPGME_SIGSUM_KEY_EXPIRED)) {
945 time_t at = key->subkeys->expires ? key->subkeys->expires : 0;
948 state_attach_puts (_("Warning: The key used to create the "
949 "signature expired at: "), s);
951 state_attach_puts ("\n", s);
954 state_attach_puts (_("Warning: At least one certification key "
955 "has expired\n"), s);
958 if ((sum & GPGME_SIGSUM_SIG_EXPIRED)) {
959 gpgme_verify_result_t result;
960 gpgme_signature_t sig;
963 result = gpgme_op_verify_result (ctx);
965 for (sig = result->signatures, i = 0; sig && (i < idx);
966 sig = sig->next, i++);
968 state_attach_puts (_("Warning: The signature expired at: "), s);
969 print_time (sig ? sig->exp_timestamp : 0, s);
970 state_attach_puts ("\n", s);
973 if ((sum & GPGME_SIGSUM_KEY_MISSING))
974 state_attach_puts (_("Can't verify due to a missing "
975 "key or certificate\n"), s);
977 if ((sum & GPGME_SIGSUM_CRL_MISSING)) {
978 state_attach_puts (_("The CRL is not available\n"), s);
982 if ((sum & GPGME_SIGSUM_CRL_TOO_OLD)) {
983 state_attach_puts (_("Available CRL is too old\n"), s);
987 if ((sum & GPGME_SIGSUM_BAD_POLICY))
988 state_attach_puts (_("A policy requirement was not met\n"), s);
990 if ((sum & GPGME_SIGSUM_SYS_ERROR)) {
991 const char *t0 = NULL, *t1 = NULL;
992 gpgme_verify_result_t result;
993 gpgme_signature_t sig;
996 state_attach_puts (_("A system error occurred"), s);
998 /* Try to figure out some more detailed system error information. */
999 result = gpgme_op_verify_result (ctx);
1000 for (sig = result->signatures, i = 0; sig && (i < idx);
1001 sig = sig->next, i++);
1004 t1 = sig->wrong_key_usage ? "Wrong_Key_Usage" : "";
1008 state_attach_puts (": ", s);
1010 state_attach_puts (t0, s);
1011 if (t1 && !(t0 && !m_strcmp(t0, t1))) {
1013 state_attach_puts (",", s);
1014 state_attach_puts (t1, s);
1017 state_attach_puts ("\n", s);
1024 static void show_fingerprint (gpgme_key_t key, STATE * state)
1029 const char *prefix = _("Fingerprint: ");
1033 s = key->subkeys ? key->subkeys->fpr : NULL;
1036 is_pgp = (key->protocol == GPGME_PROTOCOL_OpenPGP);
1038 buf = xmalloc(m_strlen(prefix) + m_strlen(s) * 4 + 2);
1039 strcpy (buf, prefix); /* __STRCPY_CHECKED__ */
1040 p = buf + m_strlen(buf);
1041 if (is_pgp && m_strlen(s) == 40) { /* PGP v4 style formatted. */
1042 for (i = 0; *s && s[1] && s[2] && s[3] && s[4]; s += 4, i++) {
1053 for (i = 0; *s && s[1] && s[2]; s += 2, i++) {
1056 *p++ = is_pgp ? ' ' : ':';
1057 if (is_pgp && i == 7)
1062 /* just in case print remaining odd digits */
1067 state_attach_puts (buf, state);
1071 /* Show the valididy of a key used for one signature. */
1072 static void show_one_sig_validity (gpgme_ctx_t ctx, int idx, STATE * s)
1074 gpgme_verify_result_t result = NULL;
1075 gpgme_signature_t sig = NULL;
1076 const char *txt = NULL;
1078 result = gpgme_op_verify_result (ctx);
1080 for (sig = result->signatures; sig && (idx > 0); sig = sig->next, idx--);
1082 switch (sig ? sig->validity : 0) {
1083 case GPGME_VALIDITY_UNKNOWN:
1084 txt = _("WARNING: We have NO indication whether "
1085 "the key belongs to the person named " "as shown above\n");
1087 case GPGME_VALIDITY_UNDEFINED:
1089 case GPGME_VALIDITY_NEVER:
1090 txt = _("WARNING: The key does NOT BELONG to "
1091 "the person named as shown above\n");
1093 case GPGME_VALIDITY_MARGINAL:
1094 txt = _("WARNING: It is NOT certain that the key "
1095 "belongs to the person named as shown above\n");
1097 case GPGME_VALIDITY_FULL:
1098 case GPGME_VALIDITY_ULTIMATE:
1103 state_attach_puts (txt, s);
1106 /* Show information about one signature. This fucntion is called with
1107 the context CTX of a sucessful verification operation and the
1108 enumerator IDX which should start at 0 and incremete for each
1111 Return values are: 0 for normal procession, 1 for a bad signature,
1112 2 for a signature with a warning or -1 for no more signature. */
1113 static int show_one_sig_status (gpgme_ctx_t ctx, int idx, STATE * s)
1116 const char *fpr, *uid;
1117 gpgme_key_t key = NULL;
1118 int i, anybad = 0, anywarn = 0;
1120 gpgme_user_id_t uids = NULL;
1121 gpgme_verify_result_t result;
1122 gpgme_signature_t sig;
1123 gpgme_error_t err = GPG_ERR_NO_ERROR;
1125 result = gpgme_op_verify_result (ctx);
1127 /* FIXME: this code should use a static variable and remember
1128 the current position in the list of signatures, IMHO.
1131 for (i = 0, sig = result->signatures; sig && (i < idx);
1132 i++, sig = sig->next);
1134 return -1; /* Signature not found. */
1136 if (signature_key) {
1137 gpgme_key_release (signature_key);
1138 signature_key = NULL;
1141 created = sig->timestamp;
1145 if (gpg_err_code (sig->status) != GPG_ERR_NO_ERROR)
1148 err = gpgme_get_key (ctx, fpr, &key, 0); /* secret key? */
1150 uid = (key->uids && key->uids->uid) ? key->uids->uid : "[?]";
1152 signature_key = key;
1155 key = NULL; /* Old gpgme versions did not set KEY to NULL on
1156 error. Do it here to avoid a double free. */
1160 if (!s || !s->fpout || !(s->flags & M_DISPLAY)); /* No state information so no way to print anything. */
1162 state_attach_puts (_("Error getting key information: "), s);
1163 state_attach_puts (gpg_strerror (err), s);
1164 state_attach_puts ("\n", s);
1167 else if ((sum & GPGME_SIGSUM_GREEN)) {
1168 state_attach_puts (_("Good signature from: "), s);
1169 state_attach_puts (uid, s);
1170 state_attach_puts ("\n", s);
1171 for (i = 1, uids = key->uids; uids; i++, uids = uids->next) {
1173 /* Skip primary UID. */
1177 state_attach_puts (_(" aka: "), s);
1178 state_attach_puts (uids->uid, s);
1179 state_attach_puts ("\n", s);
1181 state_attach_puts (_(" created: "), s);
1182 print_time (created, s);
1183 state_attach_puts ("\n", s);
1184 if (show_sig_summary (sum, ctx, key, idx, s))
1186 show_one_sig_validity (ctx, idx, s);
1188 else if ((sum & GPGME_SIGSUM_RED)) {
1189 state_attach_puts (_("*BAD* signature claimed to be from: "), s);
1190 state_attach_puts (uid, s);
1191 state_attach_puts ("\n", s);
1192 show_sig_summary (sum, ctx, key, idx, s);
1194 else if (!anybad && key && (key->protocol == GPGME_PROTOCOL_OpenPGP)) { /* We can't decide (yellow) but this is a PGP key with a good
1195 signature, so we display what a PGP user expects: The name,
1196 fingerprint and the key validity (which is neither fully or
1198 state_attach_puts (_("Good signature from: "), s);
1199 state_attach_puts (uid, s);
1200 state_attach_puts ("\n", s);
1201 state_attach_puts (_(" created: "), s);
1202 print_time (created, s);
1203 state_attach_puts ("\n", s);
1204 show_one_sig_validity (ctx, idx, s);
1205 show_fingerprint (key, s);
1206 if (show_sig_summary (sum, ctx, key, idx, s))
1209 else { /* can't decide (yellow) */
1211 state_attach_puts (_("Error checking signature"), s);
1212 state_attach_puts ("\n", s);
1213 show_sig_summary (sum, ctx, key, idx, s);
1216 if (key != signature_key)
1217 gpgme_key_release (key);
1220 return anybad ? 1 : anywarn ? 2 : 0;
1223 /* Do the actual verification step. With IS_SMIME set to true we
1224 assume S/MIME (surprise!) */
1225 static int verify_one (BODY * sigbdy, STATE * s,
1226 const char *tempfile, int is_smime)
1232 gpgme_data_t signature, message;
1234 signature = file_to_data_object (s->fpin, sigbdy->offset, sigbdy->length);
1238 /* We need to tell gpgme about the encoding because the backend can't
1239 auto-detect plain base-64 encoding which is used by S/MIME. */
1241 gpgme_data_set_encoding (signature, GPGME_DATA_ENCODING_BASE64);
1243 err = gpgme_data_new_from_file (&message, tempfile, 1);
1245 gpgme_data_release (signature);
1246 mutt_error (_("error allocating data object: %s\n"), gpgme_strerror (err));
1249 ctx = create_gpgme_context (is_smime);
1251 /* Note: We don't need a current time output because GPGME avoids
1252 such an attack by separating the meta information from the
1254 state_attach_puts (_("[-- Begin signature information --]\n"), s);
1256 err = gpgme_op_verify (ctx, signature, message, NULL);
1257 mutt_need_hard_redraw ();
1261 snprintf (buf, sizeof (buf) - 1,
1262 _("Error: verification failed: %s\n"), gpgme_strerror (err));
1263 state_attach_puts (buf, s);
1265 else { /* Verification succeeded, see what the result is. */
1269 if (signature_key) {
1270 gpgme_key_release (signature_key);
1271 signature_key = NULL;
1274 for (idx = 0; (res = show_one_sig_status (ctx, idx, s)) != -1; idx++) {
1285 gpgme_verify_result_t result;
1286 gpgme_sig_notation_t notation;
1287 gpgme_signature_t sig;
1289 result = gpgme_op_verify_result (ctx);
1291 for (sig = result->signatures; sig; sig = sig->next) {
1292 if (sig->notations) {
1293 state_attach_puts ("*** Begin Notation (signature by: ", s);
1294 state_attach_puts (sig->fpr, s);
1295 state_attach_puts (") ***\n", s);
1296 for (notation = sig->notations; notation; 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[m_strlen(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)
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 ssize_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;
1538 fseeko (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 = ftello (s.fpout);
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;
1590 fseeko (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 = ftello (s.fpout);
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 (!m_strncmp("-----BEGIN PGP ", buf, 15)) {
1664 if (!m_strcmp("MESSAGE-----\n", buf + 15))
1666 else if (!m_strcmp("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 (!m_strcmp(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;
1775 off_t last_pos, offset;
1776 char buf[HUGE_STRING];
1777 FILE *pgpout = NULL;
1779 gpgme_error_t err = 0;
1780 gpgme_data_t armored_data = NULL;
1782 short maybe_goodsig = 1;
1783 short have_any_sigs = 0;
1785 char body_charset[STRING]; /* Only used for clearsigned messages. */
1787 debug_print (2, ("Entering pgp_application_pgp handler\n"));
1789 /* For clearsigned messages we won't be able to get a character set
1790 but we know that this may only be text thus we assume Latin-1
1792 if (!mutt_get_body_charset (body_charset, sizeof (body_charset), m))
1793 m_strcpy(body_charset, sizeof(body_charset), "iso-8859-1");
1795 fseeko (s->fpin, m->offset, 0);
1796 last_pos = m->offset;
1798 for (bytes = m->length; bytes > 0;) {
1799 if (fgets (buf, sizeof (buf), s->fpin) == NULL)
1802 offset = ftello (s->fpin);
1803 bytes -= (offset - last_pos); /* don't rely on m_strlen(buf) */
1806 if (!m_strncmp("-----BEGIN PGP ", buf, 15)) {
1808 start_pos = last_pos;
1810 if (!m_strcmp("MESSAGE-----\n", buf + 15))
1812 else if (!m_strcmp("SIGNED MESSAGE-----\n", buf + 15)) {
1816 else if (!option (OPTDONTHANDLEPGPKEYS) &&
1817 !m_strcmp("PUBLIC KEY BLOCK-----\n", buf + 15)) {
1822 /* XXX - we may wish to recode here */
1824 state_puts (s->prefix, s);
1825 state_puts (buf, s);
1829 have_any_sigs = (have_any_sigs || (clearsign && (s->flags & M_VERIFY)));
1831 /* Copy PGP material to an data container */
1832 armored_data = create_gpgme_data ();
1833 gpgme_data_write (armored_data, buf, m_strlen(buf));
1834 while (bytes > 0 && fgets (buf, sizeof (buf) - 1, s->fpin) != NULL) {
1835 offset = ftello (s->fpin);
1836 bytes -= (offset - last_pos); /* don't rely on m_strlen(buf) */
1839 gpgme_data_write (armored_data, buf, m_strlen(buf));
1841 if ((needpass && !m_strcmp("-----END PGP MESSAGE-----\n", buf))
1843 && (!m_strcmp("-----END PGP SIGNATURE-----\n", buf)
1844 || !m_strcmp("-----END PGP PUBLIC KEY BLOCK-----\n",
1849 /* Invoke PGP if needed */
1850 if (!clearsign || (s->flags & M_VERIFY)) {
1851 unsigned int sig_stat = 0;
1852 gpgme_data_t plaintext;
1855 plaintext = create_gpgme_data ();
1856 ctx = create_gpgme_context (0);
1859 err = gpgme_op_verify (ctx, armored_data, NULL, plaintext);
1861 err = gpgme_op_decrypt_verify (ctx, armored_data, plaintext);
1862 if (gpg_err_code (err) == GPG_ERR_NO_DATA) {
1863 /* Decrypt verify can't handle signed only messages. */
1864 err = (gpgme_data_seek (armored_data, 0, SEEK_SET) == -1)
1865 ? gpgme_error_from_errno (errno) : 0;
1866 /* Must release plaintext so that we supply an
1867 uninitialized object. */
1868 gpgme_data_release (plaintext);
1869 plaintext = create_gpgme_data ();
1870 err = gpgme_op_verify (ctx, armored_data, NULL, plaintext);
1877 snprintf (errbuf, sizeof (errbuf) - 1,
1878 _("Error: decryption/verification failed: %s\n"),
1879 gpgme_strerror (err));
1880 state_attach_puts (errbuf, s);
1882 else { /* Decryption/Verification succeeded */
1886 /* Check wether signatures have been verified. */
1887 gpgme_verify_result_t verify_result;
1889 verify_result = gpgme_op_verify_result (ctx);
1890 if (verify_result->signatures)
1896 if ((s->flags & M_DISPLAY) && sig_stat) {
1901 state_attach_puts (_("[-- Begin signature "
1902 "information --]\n"), s);
1905 (res = show_one_sig_status (ctx, idx, s)) != -1; idx++) {
1914 state_attach_puts (_("[-- End signature "
1915 "information --]\n\n"), s);
1918 tmpfname = data_object_to_tempfile (plaintext, &pgpout);
1921 state_attach_puts (_("Error: copy data failed\n"), s);
1925 p_delete(&tmpfname);
1928 gpgme_release (ctx);
1932 * Now, copy cleartext to the screen. NOTE - we expect that PGP
1933 * outputs utf-8 cleartext. This may not always be true, but it
1934 * seems to be a reasonable guess.
1937 if (s->flags & M_DISPLAY) {
1939 state_attach_puts (_("[-- BEGIN PGP MESSAGE --]\n\n"), s);
1940 else if (pgp_keyblock)
1941 state_attach_puts (_("[-- BEGIN PGP PUBLIC KEY BLOCK --]\n"), s);
1943 state_attach_puts (_("[-- BEGIN PGP SIGNED MESSAGE --]\n\n"), s);
1947 copy_clearsigned (armored_data, s, body_charset);
1954 fc = fgetconv_open (pgpout, "utf-8", Charset, 0);
1955 while ((c = fgetconv (fc)) != EOF) {
1957 if (c == '\n' && s->prefix)
1958 state_puts (s->prefix, s);
1960 fgetconv_close (&fc);
1963 if (s->flags & M_DISPLAY) {
1964 state_putc ('\n', s);
1966 state_attach_puts (_("[-- END PGP MESSAGE --]\n"), s);
1967 else if (pgp_keyblock)
1968 state_attach_puts (_("[-- END PGP PUBLIC KEY BLOCK --]\n"), s);
1970 state_attach_puts (_("[-- END PGP SIGNED MESSAGE --]\n"), s);
1974 safe_fclose (&pgpout);
1978 /* XXX - we may wish to recode here */
1980 state_puts (s->prefix, s);
1981 state_puts (buf, s);
1985 m->goodsig = (maybe_goodsig && have_any_sigs);
1987 if (needpass == -1) {
1988 state_attach_puts (_("[-- Error: could not find beginning"
1989 " of PGP message! --]\n\n"), s);
1992 debug_print (2, ("Leaving pgp_application_pgp handler\n"));
1997 * Implementation of `encrypted_handler'.
2000 /* MIME handler for pgp/mime encrypted messages. */
2001 int pgp_gpgme_encrypted_handler (BODY * a, STATE * s)
2003 char tempfile[_POSIX_PATH_MAX];
2006 BODY *orig_body = a;
2010 debug_print (2, ("Entering pgp_encrypted handler\n"));
2012 if (!a || a->type != TYPEAPPLICATION || !a->subtype
2013 || ascii_strcasecmp ("pgp-encrypted", a->subtype)
2014 || !a->next || a->next->type != TYPEAPPLICATION || !a->next->subtype
2015 || ascii_strcasecmp ("octet-stream", a->next->subtype)) {
2016 if (s->flags & M_DISPLAY)
2017 state_attach_puts (_("[-- Error: malformed PGP/MIME message! --]\n\n"),
2022 /* Move forward to the application/pgp-encrypted body. */
2025 mutt_mktemp (tempfile);
2026 if (!(fpout = safe_fopen (tempfile, "w+"))) {
2027 if (s->flags & M_DISPLAY)
2028 state_attach_puts (_("[-- Error: could not create temporary file! "
2033 tattach = decrypt_part (a, s, fpout, 0, &is_signed);
2035 tattach->goodsig = is_signed > 0;
2037 if (s->flags & M_DISPLAY)
2038 state_attach_puts (is_signed ?
2040 ("[-- The following data is PGP/MIME signed and encrypted --]\n\n") :
2041 _("[-- The following data is PGP/MIME encrypted --]\n\n"), s);
2044 FILE *savefp = s->fpin;
2047 rc = mutt_body_handler (tattach, s);
2052 * if a multipart/signed is the _only_ sub-part of a
2053 * multipart/encrypted, cache signature verification
2056 if (mutt_is_multipart_signed (tattach) && !tattach->next)
2057 orig_body->goodsig |= tattach->goodsig;
2059 if (s->flags & M_DISPLAY) {
2060 state_puts ("\n", s);
2061 state_attach_puts (is_signed ?
2063 ("[-- End of PGP/MIME signed and encrypted data --]\n")
2064 : _("[-- End of PGP/MIME encrypted data --]\n"), s);
2067 mutt_free_body (&tattach);
2071 mutt_unlink (tempfile);
2072 debug_print (2, ("Leaving pgp_encrypted handler\n"));
2076 /* Support for application/smime */
2077 int smime_gpgme_application_handler (BODY * a, STATE * s)
2079 char tempfile[_POSIX_PATH_MAX];
2085 debug_print (2, ("Entering smime_encrypted handler\n"));
2088 mutt_mktemp (tempfile);
2089 if (!(fpout = safe_fopen (tempfile, "w+"))) {
2090 if (s->flags & M_DISPLAY)
2091 state_attach_puts (_("[-- Error: could not create temporary file! "
2096 tattach = decrypt_part (a, s, fpout, 1, &is_signed);
2098 tattach->goodsig = is_signed > 0;
2100 if (s->flags & M_DISPLAY)
2101 state_attach_puts (is_signed ?
2102 _("[-- The following data is S/MIME signed --]\n\n") :
2103 _("[-- The following data is S/MIME encrypted --]\n\n"), s);
2106 FILE *savefp = s->fpin;
2109 rc = mutt_body_handler (tattach, s);
2114 * if a multipart/signed is the _only_ sub-part of a
2115 * multipart/encrypted, cache signature verification
2118 if (mutt_is_multipart_signed (tattach) && !tattach->next) {
2119 if (!(a->goodsig = tattach->goodsig))
2120 a->warnsig = tattach->warnsig;
2122 else if (tattach->goodsig) {
2124 a->warnsig = tattach->warnsig;
2127 if (s->flags & M_DISPLAY) {
2128 state_puts ("\n", s);
2129 state_attach_puts (is_signed ?
2130 _("[-- End of S/MIME signed data --]\n") :
2131 _("[-- End of S/MIME encrypted data --]\n"), s);
2134 mutt_free_body (&tattach);
2138 mutt_unlink (tempfile);
2139 debug_print (2, ("Leaving smime_encrypted handler\n"));
2145 * Format an entry on the CRYPT key selection menu.
2148 * %k key id %K key id of the principal key
2150 * %a algorithm %A algorithm of the princ. key
2151 * %l length %L length of the princ. key
2152 * %f flags %F flags of the princ. key
2153 * %c capabilities %C capabilities of the princ. key
2154 * %t trust/validity of the key-uid association
2156 * %[...] date of key using strftime(3)
2160 crypt_entry_fmt (char *dest, ssize_t destlen, char op,
2161 const char *src, const char *prefix,
2162 const char *ifstring, const char *elsestring,
2163 unsigned long data, format_flag flags)
2166 crypt_entry_t *entry;
2169 int optional = (flags & M_FORMAT_OPTIONAL);
2170 const char *s = NULL;
2173 entry = (crypt_entry_t *) data;
2176 /* if (isupper ((unsigned char) op)) */
2179 kflags = (key->flags /*| (pkey->flags & KEYFLAG_RESTRICTIONS)
2182 switch (ascii_tolower (op)) {
2186 char buf2[SHORT_STRING], *p;
2202 while (len > 0 && *cp != ']') {
2211 break; /* not enough space */
2221 if (do_locales && Locale)
2222 setlocale (LC_TIME, Locale);
2227 if (key->kobj->subkeys && (key->kobj->subkeys->timestamp > 0))
2228 tt = key->kobj->subkeys->timestamp;
2230 tm = localtime (&tt);
2232 strftime (buf2, sizeof (buf2), dest, tm);
2235 setlocale (LC_TIME, "C");
2237 snprintf (fmt, sizeof (fmt), "%%%ss", prefix);
2238 snprintf (dest, destlen, fmt, buf2);
2245 snprintf (fmt, sizeof (fmt), "%%%sd", prefix);
2246 snprintf (dest, destlen, fmt, entry->num);
2251 /* fixme: we need a way to distinguish between main and subkeys.
2252 Store the idx in entry? */
2253 snprintf (fmt, sizeof (fmt), "%%%ss", prefix);
2254 snprintf (dest, destlen, fmt, crypt_keyid (key));
2259 snprintf (fmt, sizeof (fmt), "%%%ss", prefix);
2260 snprintf (dest, destlen, fmt, key->uid);
2265 snprintf (fmt, sizeof (fmt), "%%%s.3s", prefix);
2266 if (key->kobj->subkeys)
2267 s = gpgme_pubkey_algo_name (key->kobj->subkeys->pubkey_algo);
2270 snprintf (dest, destlen, fmt, s);
2275 snprintf (fmt, sizeof (fmt), "%%%slu", prefix);
2276 if (key->kobj->subkeys)
2277 val = key->kobj->subkeys->length;
2280 snprintf (dest, destlen, fmt, val);
2285 snprintf (fmt, sizeof (fmt), "%%%sc", prefix);
2286 snprintf (dest, destlen, fmt, crypt_flags (kflags));
2288 else if (!(kflags & (KEYFLAG_RESTRICTIONS)))
2293 snprintf (fmt, sizeof (fmt), "%%%ss", prefix);
2294 snprintf (dest, destlen, fmt, crypt_key_abilities (kflags));
2296 else if (!(kflags & (KEYFLAG_ABILITIES)))
2300 if ((kflags & KEYFLAG_ISX509))
2303 gpgme_user_id_t uid = NULL;
2306 for (i = 0, uid = key->kobj->uids; uid && (i < key->idx);
2307 i++, uid = uid->next);
2309 switch (uid->validity) {
2310 case GPGME_VALIDITY_UNDEFINED:
2313 case GPGME_VALIDITY_NEVER:
2316 case GPGME_VALIDITY_MARGINAL:
2319 case GPGME_VALIDITY_FULL:
2322 case GPGME_VALIDITY_ULTIMATE:
2325 case GPGME_VALIDITY_UNKNOWN:
2331 snprintf (fmt, sizeof (fmt), "%%%sc", prefix);
2332 snprintf (dest, destlen, fmt, s ? *s : 'B');
2335 snprintf (fmt, sizeof (fmt), "%%%ss", prefix);
2336 snprintf (dest, destlen, fmt,
2337 gpgme_get_protocol_name (key->kobj->protocol));
2345 mutt_FormatString (dest, destlen, ifstring, mutt_attach_fmt, data, 0);
2346 else if (flags & M_FORMAT_OPTIONAL)
2347 mutt_FormatString (dest, destlen, elsestring, mutt_attach_fmt, data, 0);
2351 /* Used by the display fucntion to format a line. */
2352 static void crypt_entry (char *s, ssize_t l, MUTTMENU * menu, int num)
2354 crypt_key_t **key_table = (crypt_key_t **) menu->data;
2355 crypt_entry_t entry;
2357 entry.key = key_table[num];
2358 entry.num = num + 1;
2360 mutt_FormatString (s, l, NONULL (PgpEntryFormat), crypt_entry_fmt,
2361 (unsigned long) &entry, M_FORMAT_ARROWCURSOR);
2364 /* Compare two addresses and the keyid to be used for sorting. */
2365 static int _crypt_compare_address (const void *a, const void *b)
2367 crypt_key_t **s = (crypt_key_t **) a;
2368 crypt_key_t **t = (crypt_key_t **) b;
2371 if ((r = m_strcasecmp((*s)->uid, (*t)->uid)))
2374 return m_strcasecmp(crypt_keyid (*s), crypt_keyid (*t)) > 0;
2377 static int crypt_compare_address (const void *a, const void *b)
2379 return ((PgpSortKeys & SORT_REVERSE) ? !_crypt_compare_address (a, b)
2380 : _crypt_compare_address (a, b));
2384 /* Compare two key IDs and the addresses to be used for sorting. */
2385 static int _crypt_compare_keyid (const void *a, const void *b)
2387 crypt_key_t **s = (crypt_key_t **) a;
2388 crypt_key_t **t = (crypt_key_t **) b;
2391 if ((r = m_strcasecmp(crypt_keyid (*s), crypt_keyid (*t))))
2394 return m_strcasecmp((*s)->uid, (*t)->uid) > 0;
2397 static int crypt_compare_keyid (const void *a, const void *b)
2399 return ((PgpSortKeys & SORT_REVERSE) ? !_crypt_compare_keyid (a, b)
2400 : _crypt_compare_keyid (a, b));
2403 /* Compare 2 creation dates and the addresses. For sorting. */
2404 static int _crypt_compare_date (const void *a, const void *b)
2406 crypt_key_t **s = (crypt_key_t **) a;
2407 crypt_key_t **t = (crypt_key_t **) b;
2408 unsigned long ts = 0, tt = 0;
2410 if ((*s)->kobj->subkeys && ((*s)->kobj->subkeys->timestamp > 0))
2411 ts = (*s)->kobj->subkeys->timestamp;
2412 if ((*t)->kobj->subkeys && ((*t)->kobj->subkeys->timestamp > 0))
2413 tt = (*t)->kobj->subkeys->timestamp;
2420 return m_strcasecmp((*s)->uid, (*t)->uid) > 0;
2423 static int crypt_compare_date (const void *a, const void *b)
2425 return ((PgpSortKeys & SORT_REVERSE) ? !_crypt_compare_date (a, b)
2426 : _crypt_compare_date (a, b));
2429 /* Compare two trust values, the key length, the creation dates. the
2430 addresses and the key IDs. For sorting. */
2431 static int _crypt_compare_trust (const void *a, const void *b)
2433 crypt_key_t **s = (crypt_key_t **) a;
2434 crypt_key_t **t = (crypt_key_t **) b;
2435 unsigned long ts = 0, tt = 0;
2438 if ((r = (((*s)->flags & (KEYFLAG_RESTRICTIONS))
2439 - ((*t)->flags & (KEYFLAG_RESTRICTIONS)))))
2442 if ((*s)->kobj->uids)
2443 ts = (*s)->kobj->uids->validity;
2444 if ((*t)->kobj->uids)
2445 tt = (*t)->kobj->uids->validity;
2446 if ((r = (tt - ts)))
2449 if ((*s)->kobj->subkeys)
2450 ts = (*s)->kobj->subkeys->length;
2451 if ((*t)->kobj->subkeys)
2452 tt = (*t)->kobj->subkeys->length;
2456 if ((*s)->kobj->subkeys && ((*s)->kobj->subkeys->timestamp > 0))
2457 ts = (*s)->kobj->subkeys->timestamp;
2458 if ((*t)->kobj->subkeys && ((*t)->kobj->subkeys->timestamp > 0))
2459 tt = (*t)->kobj->subkeys->timestamp;
2465 if ((r = m_strcasecmp((*s)->uid, (*t)->uid)))
2467 return (m_strcasecmp(crypt_keyid ((*s)), crypt_keyid ((*t)))) > 0;
2470 static int crypt_compare_trust (const void *a, const void *b)
2472 return ((PgpSortKeys & SORT_REVERSE) ? !_crypt_compare_trust (a, b)
2473 : _crypt_compare_trust (a, b));
2476 /* Print the X.500 Distinguished Name part KEY from the array of parts
2478 static int print_dn_part (FILE * fp, struct dn_array_s *dn, const char *key)
2482 for (; dn->key; dn++) {
2483 if (!m_strcmp(dn->key, key)) {
2486 print_utf8 (fp, dn->value, m_strlen(dn->value));
2493 /* Print all parts of a DN in a standard sequence. */
2494 static void print_dn_parts (FILE * fp, struct dn_array_s *dn)
2496 const char *stdpart[] = {
2497 "CN", "OU", "O", "STREET", "L", "ST", "C", NULL
2499 int any = 0, any2 = 0, i;
2501 for (i = 0; stdpart[i]; i++) {
2504 any = print_dn_part (fp, dn, stdpart[i]);
2506 /* now print the rest without any specific ordering */
2507 for (; dn->key; dn++) {
2508 for (i = 0; stdpart[i]; i++) {
2509 if (!m_strcmp(dn->key, stdpart[i]))
2517 any = print_dn_part (fp, dn, dn->key);
2526 /* Parse an RDN; this is a helper to parse_dn(). */
2527 static const unsigned char *parse_dn_part (struct dn_array_s *array,
2528 const unsigned char *string)
2530 const unsigned char *s, *s1;
2534 /* parse attributeType */
2535 for (s = string + 1; *s && *s != '='; s++);
2537 return NULL; /* error */
2540 return NULL; /* empty key */
2541 array->key = p_dupstr(string, n );
2542 p = (unsigned char *) array->key;
2545 if (*string == '#') { /* hexstring */
2547 for (s = string; hexdigitp (s); s++)
2551 return NULL; /* empty or odd number of digits */
2554 array->value = (char *) p;
2555 for (s1 = string; n; s1 += 2, n--)
2559 else { /* regular v3 quoted string */
2560 for (n = 0, s = string; *s; s++) {
2561 if (*s == '\\') { /* pair */
2563 if (*s == ',' || *s == '=' || *s == '+'
2564 || *s == '<' || *s == '>' || *s == '#' || *s == ';'
2565 || *s == '\\' || *s == '\"' || *s == ' ')
2567 else if (hexdigitp (s) && hexdigitp (s + 1)) {
2572 return NULL; /* invalid escape sequence */
2574 else if (*s == '\"')
2575 return NULL; /* invalid encoding */
2576 else if (*s == ',' || *s == '=' || *s == '+'
2577 || *s == '<' || *s == '>' || *s == '#' || *s == ';')
2584 array->value = (char *) p;
2585 for (s = string; n; s++, n--) {
2588 if (hexdigitp (s)) {
2604 /* Parse a DN and return an array-ized one. This is not a validating
2605 parser and it does not support any old-stylish syntax; gpgme is
2606 expected to return only rfc2253 compatible strings. */
2607 static struct dn_array_s *parse_dn (const unsigned char *string)
2609 struct dn_array_s *array;
2610 ssize_t arrayidx, arraysize;
2613 arraysize = 7; /* C,ST,L,O,OU,CN,email */
2614 array = p_new(struct dn_array_s, arraysize + 1);
2617 while (*string == ' ')
2621 if (arrayidx >= arraysize) { /* mutt lacks a real safe_realoc - so we need to copy */
2622 struct dn_array_s *a2;
2625 a2 = p_new(struct dn_array_s, arraysize + 1);
2626 for (i = 0; i < arrayidx; i++) {
2627 a2[i].key = array[i].key;
2628 a2[i].value = array[i].value;
2633 array[arrayidx].key = NULL;
2634 array[arrayidx].value = NULL;
2635 string = parse_dn_part (array + arrayidx, string);
2639 while (*string == ' ')
2641 if (*string && *string != ',' && *string != ';' && *string != '+')
2642 goto failure; /* invalid delimiter */
2646 array[arrayidx].key = NULL;
2647 array[arrayidx].value = NULL;
2651 for (i = 0; i < arrayidx; i++) {
2652 p_delete(&array[i].key);
2653 p_delete(&array[i].value);
2660 /* Print a nice representation of the USERID and make sure it is
2661 displayed in a proper way, which does mean to reorder some parts
2662 for S/MIME's DNs. USERID is a string as returned by the gpgme key
2663 functions. It is utf-8 encoded. */
2664 static void parse_and_print_user_id (FILE * fp, const char *userid)
2669 if (*userid == '<') {
2670 s = strchr (userid + 1, '>');
2672 print_utf8 (fp, userid + 1, s - userid - 1);
2674 else if (*userid == '(')
2675 fputs (_("[Can't display this user ID (unknown encoding)]"), fp);
2676 else if (!digit_or_letter ((const unsigned char *) userid))
2677 fputs (_("[Can't display this user ID (invalid encoding)]"), fp);
2679 struct dn_array_s *dn = parse_dn ((const unsigned char *) userid);
2682 fputs (_("[Can't display this user ID (invalid DN)]"), fp);
2684 print_dn_parts (fp, dn);
2685 for (i = 0; dn[i].key; i++) {
2686 p_delete(&dn[i].key);
2687 p_delete(&dn[i].value);
2695 KEY_CAP_CAN_ENCRYPT,
2700 static unsigned int key_check_cap (gpgme_key_t key, key_cap_t cap)
2702 gpgme_subkey_t subkey = NULL;
2703 unsigned int ret = 0;
2706 case KEY_CAP_CAN_ENCRYPT:
2707 if (!(ret = key->can_encrypt))
2708 for (subkey = key->subkeys; subkey; subkey = subkey->next)
2709 if ((ret = subkey->can_encrypt))
2712 case KEY_CAP_CAN_SIGN:
2713 if (!(ret = key->can_sign))
2714 for (subkey = key->subkeys; subkey; subkey = subkey->next)
2715 if ((ret = subkey->can_sign))
2718 case KEY_CAP_CAN_CERTIFY:
2719 if (!(ret = key->can_certify))
2720 for (subkey = key->subkeys; subkey; subkey = subkey->next)
2721 if ((ret = subkey->can_certify))
2730 /* Print verbose information about a key or certificate to FP. */
2731 static void print_key_info (gpgme_key_t key, FILE * fp)
2734 const char *s = NULL, *s2 = NULL;
2737 char shortbuf[SHORT_STRING];
2738 unsigned long aval = 0;
2742 gpgme_user_id_t uid = NULL;
2745 setlocale (LC_TIME, Locale);
2747 is_pgp = key->protocol == GPGME_PROTOCOL_OpenPGP;
2749 for (idx = 0, uid = key->uids; uid; idx++, uid = uid->next) {
2754 fputs (idx ? _(" aka ......: ") :_("Name ......: "), fp);
2757 fputs (_("[Invalid]"), fp);
2761 print_utf8 (fp, s, m_strlen(s));
2763 parse_and_print_user_id (fp, s);
2767 if (key->subkeys && (key->subkeys->timestamp > 0)) {
2768 tt = key->subkeys->timestamp;
2770 tm = localtime (&tt);
2771 #ifdef HAVE_LANGINFO_D_T_FMT
2772 strftime (shortbuf, sizeof shortbuf, nl_langinfo (D_T_FMT), tm);
2774 strftime (shortbuf, sizeof shortbuf, "%c", tm);
2776 fprintf (fp, _("Valid From : %s\n"), shortbuf);
2779 if (key->subkeys && (key->subkeys->expires > 0)) {
2780 tt = key->subkeys->expires;
2782 tm = localtime (&tt);
2783 #ifdef HAVE_LANGINFO_D_T_FMT
2784 strftime (shortbuf, sizeof shortbuf, nl_langinfo (D_T_FMT), tm);
2786 strftime (shortbuf, sizeof shortbuf, "%c", tm);
2788 fprintf (fp, _("Valid To ..: %s\n"), shortbuf);
2792 s = gpgme_pubkey_algo_name (key->subkeys->pubkey_algo);
2796 s2 = is_pgp ? "PGP" : "X.509";
2799 aval = key->subkeys->length;
2801 fprintf (fp, _("Key Type ..: %s, %lu bit %s\n"), s2, aval, s);
2803 fprintf (fp, _("Key Usage .: "));
2806 if (key_check_cap (key, KEY_CAP_CAN_ENCRYPT)) {
2807 fprintf (fp, "%s%s", delim, _("encryption"));
2810 if (key_check_cap (key, KEY_CAP_CAN_SIGN)) {
2811 fprintf (fp, "%s%s", delim, _("signing"));
2814 if (key_check_cap (key, KEY_CAP_CAN_CERTIFY)) {
2815 fprintf (fp, "%s%s", delim, _("certification"));
2821 s = key->subkeys->fpr;
2822 fputs (_("Fingerprint: "), fp);
2823 if (is_pgp && m_strlen(s) == 40) {
2824 for (i = 0; *s && s[1] && s[2] && s[3] && s[4]; s += 4, i++) {
2829 putc (is_pgp ? ' ' : ':', fp);
2830 if (is_pgp && i == 4)
2835 for (i = 0; *s && s[1] && s[2]; s += 2, i++) {
2838 putc (is_pgp ? ' ' : ':', fp);
2839 if (is_pgp && i == 7)
2843 fprintf (fp, "%s\n", s);
2846 if (key->issuer_serial) {
2847 s = key->issuer_serial;
2849 fprintf (fp, _("Serial-No .: 0x%s\n"), s);
2852 if (key->issuer_name) {
2853 s = key->issuer_name;
2855 fprintf (fp, _("Issued By .: "));
2856 parse_and_print_user_id (fp, s);
2861 /* For PGP we list all subkeys. */
2863 gpgme_subkey_t subkey = NULL;
2865 for (idx = 1, subkey = key->subkeys; subkey; idx++, subkey = subkey->next) {
2869 if (m_strlen(s) == 16)
2870 s += 8; /* display only the short keyID */
2871 fprintf (fp, _("Subkey ....: 0x%s"), s);
2872 if (subkey->revoked) {
2874 fputs (_("[Revoked]"), fp);
2876 if (subkey->invalid) {
2878 fputs (_("[Invalid]"), fp);
2880 if (subkey->expired) {
2882 fputs (_("[Expired]"), fp);
2884 if (subkey->disabled) {
2886 fputs (_("[Disabled]"), fp);
2890 if (subkey->timestamp > 0) {
2891 tt = subkey->timestamp;
2893 tm = localtime (&tt);
2894 #ifdef HAVE_LANGINFO_D_T_FMT
2895 strftime (shortbuf, sizeof shortbuf, nl_langinfo (D_T_FMT), tm);
2897 strftime (shortbuf, sizeof shortbuf, "%c", tm);
2899 fprintf (fp, _("Valid From : %s\n"), shortbuf);
2902 if (subkey->expires > 0) {
2903 tt = subkey->expires;
2905 tm = localtime (&tt);
2906 #ifdef HAVE_LANGINFO_D_T_FMT
2907 strftime (shortbuf, sizeof shortbuf, nl_langinfo (D_T_FMT), tm);
2909 strftime (shortbuf, sizeof shortbuf, "%c", tm);
2911 fprintf (fp, _("Valid To ..: %s\n"), shortbuf);
2915 s = gpgme_pubkey_algo_name (subkey->pubkey_algo);
2920 aval = subkey->length;
2924 fprintf (fp, _("Key Type ..: %s, %lu bit %s\n"), "PGP", aval, s);
2926 fprintf (fp, _("Key Usage .: "));
2929 if (subkey->can_encrypt) {
2930 fprintf (fp, "%s%s", delim, _("encryption"));
2933 if (subkey->can_sign) {
2934 fprintf (fp, "%s%s", delim, _("signing"));
2937 if (subkey->can_certify) {
2938 fprintf (fp, "%s%s", delim, _("certification"));
2946 setlocale (LC_TIME, "C");
2950 /* Show detailed information about the selected key */
2951 static void verify_key (crypt_key_t * key)
2954 char cmd[LONG_STRING], tempfile[_POSIX_PATH_MAX];
2956 gpgme_ctx_t listctx = NULL;
2958 gpgme_key_t k = NULL;
2961 mutt_mktemp (tempfile);
2962 if (!(fp = safe_fopen (tempfile, "w"))) {
2963 mutt_perror (_("Can't create temporary file"));
2967 mutt_message _("Collecting data...");
2969 print_key_info (key->kobj, fp);
2971 err = gpgme_new (&listctx);
2973 fprintf (fp, "Internal error: can't create gpgme context: %s\n",
2974 gpgme_strerror (err));
2977 if ((key->flags & KEYFLAG_ISX509))
2978 gpgme_set_protocol (listctx, GPGME_PROTOCOL_CMS);
2982 while ((s = k->chain_id) && k->subkeys && m_strcmp(s, k->subkeys->fpr)) {
2984 err = gpgme_op_keylist_start (listctx, s, 0);
2985 gpgme_key_release (k);
2988 err = gpgme_op_keylist_next (listctx, &k);
2990 fprintf (fp, _("Error finding issuer key: %s\n"), gpgme_strerror (err));
2993 gpgme_op_keylist_end (listctx);
2995 print_key_info (k, fp);
2998 fputs (_("Error: certification chain to long - stopping here\n"), fp);
3004 gpgme_key_release (k);
3005 gpgme_release (listctx);
3007 mutt_clear_error ();
3008 snprintf (cmd, sizeof (cmd), _("Key ID: 0x%s"), crypt_keyid (key));
3009 mutt_do_pager (cmd, tempfile, 0, NULL);
3013 * Implementation of `findkeys'.
3017 /* Convert string_list_t into a pattern string suitable to be passed to GPGME.
3018 We need to convert spaces in an item into a '+' and '%' into
3020 static char *list_to_pattern (string_list_t * list)
3028 for (l = list; l; l = l->next) {
3029 for (s = l->data; *s; s++) {
3034 n++; /* delimiter or end of string */
3036 n++; /* make sure to allocate at least one byte */
3037 pattern = p = p_new(char, n);
3038 for (l = list; l; l = l->next) {
3043 for (s = l->data; *s; s++) {
3049 else if (*s == '+') {
3065 /* Return a list of keys which are candidates for the selection.
3066 Select by looking at the HINTS list. */
3067 static crypt_key_t *get_candidates (string_list_t * hints, unsigned int app,
3070 crypt_key_t *db, *k, **kend;
3076 gpgme_user_id_t uid = NULL;
3078 pattern = list_to_pattern (hints);
3082 err = gpgme_new (&ctx);
3084 mutt_error (_("gpgme_new failed: %s"), gpgme_strerror (err));
3092 if ((app & APPLICATION_PGP)) {
3093 /* Its all a mess. That old GPGME expects different things
3094 depending on the protocol. For gpg we don' t need percent
3095 escaped pappert but simple strings passed in an array to the
3096 keylist_ext_start function. */
3101 for (l = hints, n = 0; l; l = l->next) {
3102 if (l->data && *l->data)
3108 patarr = p_new(char *, n + 1);
3109 for (l = hints, n = 0; l; l = l->next) {
3110 if (l->data && *l->data)
3111 patarr[n++] = m_strdup(l->data);
3114 err = gpgme_op_keylist_ext_start (ctx, (const char **) patarr, secret, 0);
3115 for (n = 0; patarr[n]; n++)
3116 p_delete(&patarr[n]);
3119 mutt_error (_("gpgme_op_keylist_start failed: %s"), gpgme_strerror (err));
3120 gpgme_release (ctx);
3125 while (!(err = gpgme_op_keylist_next (ctx, &key))) {
3126 unsigned int flags = 0;
3128 if (key_check_cap (key, KEY_CAP_CAN_ENCRYPT))
3129 flags |= KEYFLAG_CANENCRYPT;
3130 if (key_check_cap (key, KEY_CAP_CAN_SIGN))
3131 flags |= KEYFLAG_CANSIGN;
3133 #if 0 /* DISABLED code */
3135 /* Bug in gpg. Capabilities are not listed for secret
3136 keys. Try to deduce them from the algorithm. */
3138 switch (key->subkeys[0].pubkey_algo) {
3140 flags |= KEYFLAG_CANENCRYPT;
3141 flags |= KEYFLAG_CANSIGN;
3143 case GPGME_PK_ELG_E:
3144 flags |= KEYFLAG_CANENCRYPT;
3147 flags |= KEYFLAG_CANSIGN;
3151 #endif /* DISABLED code */
3153 for (idx = 0, uid = key->uids; uid; idx++, uid = uid->next) {
3154 k = p_new(crypt_key_t, 1);
3163 if (gpg_err_code (err) != GPG_ERR_EOF)
3164 mutt_error (_("gpgme_op_keylist_next failed: %s"), gpgme_strerror (err));
3165 gpgme_op_keylist_end (ctx);
3170 if ((app & APPLICATION_SMIME)) {
3171 /* and now look for x509 certificates */
3172 gpgme_set_protocol (ctx, GPGME_PROTOCOL_CMS);
3173 err = gpgme_op_keylist_start (ctx, pattern, 0);
3175 mutt_error (_("gpgme_op_keylist_start failed: %s"), gpgme_strerror (err));
3176 gpgme_release (ctx);
3181 while (!(err = gpgme_op_keylist_next (ctx, &key))) {
3182 unsigned int flags = KEYFLAG_ISX509;
3184 if (key_check_cap (key, KEY_CAP_CAN_ENCRYPT))
3185 flags |= KEYFLAG_CANENCRYPT;
3186 if (key_check_cap (key, KEY_CAP_CAN_SIGN))
3187 flags |= KEYFLAG_CANSIGN;
3189 for (idx = 0, uid = key->uids; uid; idx++, uid = uid->next) {
3190 k = p_new(crypt_key_t, 1);
3199 if (gpg_err_code (err) != GPG_ERR_EOF)
3200 mutt_error (_("gpgme_op_keylist_next failed: %s"), gpgme_strerror (err));
3201 gpgme_op_keylist_end (ctx);
3204 gpgme_release (ctx);
3209 /* Add the string STR to the list HINTS. This list is later used to
3211 static string_list_t *crypt_add_string_to_hints (string_list_t * hints, const char *str)
3216 if ((scratch = m_strdup(str)) == NULL)
3219 for (t = strtok (scratch, " ,.:\"()<>\n"); t;
3220 t = strtok (NULL, " ,.:\"()<>\n")) {
3221 if (m_strlen(t) > 3)
3222 hints = mutt_add_list(hints, t);
3229 /* Display a menu to select a key from the array KEYS. FORCED_VALID
3230 will be set to true on return if the user did override the the
3232 static crypt_key_t *crypt_select_key (crypt_key_t * keys,
3233 address_t * p, const char *s,
3234 unsigned int app, int *forced_valid)
3237 crypt_key_t **key_table;
3240 char helpstr[SHORT_STRING], buf[LONG_STRING];
3242 int (*f) (const void *, const void *);
3243 int menu_to_use = 0;
3248 /* build the key table */
3251 for (k = keys; k; k = k->next) {
3252 if (!option (OPTPGPSHOWUNUSABLE) && (k->flags & KEYFLAG_CANTUSE)) {
3259 p_realloc(&key_table, keymax);
3265 if (!i && unusable) {
3266 mutt_error _("All matching keys are marked expired/revoked.");
3272 switch (PgpSortKeys & SORT_MASK) {
3274 f = crypt_compare_date;
3277 f = crypt_compare_keyid;
3280 f = crypt_compare_address;
3284 f = crypt_compare_trust;
3287 qsort (key_table, i, sizeof (crypt_key_t *), f);
3289 if (app & APPLICATION_PGP)
3290 menu_to_use = MENU_KEY_SELECT_PGP;
3291 else if (app & APPLICATION_SMIME)
3292 menu_to_use = MENU_KEY_SELECT_SMIME;
3295 mutt_make_help (buf, sizeof (buf), _("Exit "), menu_to_use, OP_EXIT);
3296 strcat (helpstr, buf); /* __STRCAT_CHECKED__ */
3297 mutt_make_help (buf, sizeof (buf), _("Select "), menu_to_use,
3298 OP_GENERIC_SELECT_ENTRY);
3299 strcat (helpstr, buf); /* __STRCAT_CHECKED__ */
3300 mutt_make_help (buf, sizeof (buf), _("Check key "),
3301 menu_to_use, OP_VERIFY_KEY);
3302 strcat (helpstr, buf); /* __STRCAT_CHECKED__ */
3303 mutt_make_help (buf, sizeof (buf), _("Help"), menu_to_use, OP_HELP);
3304 strcat (helpstr, buf); /* __STRCAT_CHECKED__ */
3306 menu = mutt_new_menu ();
3308 menu->make_entry = crypt_entry;
3309 menu->menu = menu_to_use;
3310 menu->help = helpstr;
3311 menu->data = key_table;
3316 if ((app & APPLICATION_PGP) && (app & APPLICATION_SMIME))
3317 ts = _("PGP and S/MIME keys matching");
3318 else if ((app & APPLICATION_PGP))
3319 ts = _("PGP keys matching");
3320 else if ((app & APPLICATION_SMIME))
3321 ts = _("S/MIME keys matching");
3323 ts = _("keys matching");
3326 snprintf (buf, sizeof (buf), _("%s <%s>."), ts, p->mailbox);
3328 snprintf (buf, sizeof (buf), _("%s \"%s\"."), ts, s);
3332 mutt_clear_error ();
3336 switch (mutt_menuLoop (menu)) {
3338 verify_key (key_table[menu->current]);
3339 menu->redraw = REDRAW_FULL;
3343 mutt_message ("%s", key_table[menu->current]->uid);
3346 case OP_GENERIC_SELECT_ENTRY:
3347 /* FIXME make error reporting more verbose - this should be
3348 easy because gpgme provides more information */
3349 if (option (OPTPGPCHECKTRUST)) {
3350 if (!crypt_key_is_valid (key_table[menu->current])) {
3351 mutt_error _("This key can't be used: "
3352 "expired/disabled/revoked.");
3357 if (option (OPTPGPCHECKTRUST) &&
3358 (!crypt_id_is_valid (key_table[menu->current])
3359 || !crypt_id_is_strong (key_table[menu->current]))) {
3361 char buff[LONG_STRING];
3363 if (key_table[menu->current]->flags & KEYFLAG_CANTUSE)
3364 s = N_("ID is expired/disabled/revoked.");
3366 gpgme_validity_t val = GPGME_VALIDITY_UNKNOWN;
3367 gpgme_user_id_t uid = NULL;
3372 uid = key_table[menu->current]->kobj->uids;
3373 for (j = 0; (j < key_table[menu->current]->idx) && uid;
3374 j++, uid = uid->next);
3376 val = uid->validity;
3379 case GPGME_VALIDITY_UNKNOWN:
3380 case GPGME_VALIDITY_UNDEFINED:
3381 warn_s = N_("ID has undefined validity.");
3383 case GPGME_VALIDITY_NEVER:
3384 warn_s = N_("ID is not valid.");
3386 case GPGME_VALIDITY_MARGINAL:
3387 warn_s = N_("ID is only marginally valid.");
3389 case GPGME_VALIDITY_FULL:
3390 case GPGME_VALIDITY_ULTIMATE:
3394 snprintf (buff, sizeof (buff),
3395 _("%s Do you really want to use the key?"), _(warn_s));
3397 if (mutt_yesorno (buff, 0) != 1) {
3398 mutt_clear_error ();
3405 k = crypt_copy_key (key_table[menu->current]);
3416 mutt_menuDestroy (&menu);
3417 p_delete(&key_table);
3419 set_option (OPTNEEDREDRAW);
3424 static crypt_key_t *crypt_getkeybyaddr (address_t * a, short abilities,
3425 unsigned int app, int *forced_valid)
3428 string_list_t *hints = NULL;
3433 int this_key_has_strong;
3434 int this_key_has_weak;
3435 int this_key_has_invalid;
3438 crypt_key_t *keys, *k;
3439 crypt_key_t *the_valid_key = NULL;
3440 crypt_key_t *matches = NULL;
3441 crypt_key_t **matches_endp = &matches;
3445 if (a && a->mailbox)
3446 hints = crypt_add_string_to_hints (hints, a->mailbox);
3447 if (a && a->personal)
3448 hints = crypt_add_string_to_hints (hints, a->personal);
3450 mutt_message (_("Looking for keys matching \"%s\"..."), a->mailbox);
3451 keys = get_candidates (hints, app, (abilities & KEYFLAG_CANSIGN));
3453 string_list_wipe(&hints);
3458 debug_print (5, ("looking for %s <%s>.\n", a->personal, a->mailbox));
3460 for (k = keys; k; k = k->next) {
3461 debug_print (5, (" looking at key: %s `%.15s'\n", crypt_keyid (k), k->uid));
3463 if (abilities && !(k->flags & abilities)) {
3464 debug_print (5, (" insufficient abilities: Has %x, want %x\n", k->flags, abilities));
3468 this_key_has_weak = 0; /* weak but valid match */
3469 this_key_has_invalid = 0; /* invalid match */
3470 this_key_has_strong = 0; /* strong and valid match */
3471 match = 0; /* any match */
3473 r = rfc822_parse_adrlist (NULL, k->uid);
3474 for (p = r; p; p = p->next) {
3475 int validity = crypt_id_matches_addr (a, p, k);
3477 if (validity & CRYPT_KV_MATCH) /* something matches */
3480 /* is this key a strong candidate? */
3481 if ((validity & CRYPT_KV_VALID)
3482 && (validity & CRYPT_KV_STRONGID)
3483 && (validity & CRYPT_KV_ADDR)) {
3484 if (the_valid_key && the_valid_key != k)
3487 this_key_has_strong = 1;
3489 else if ((validity & CRYPT_KV_MATCH)
3490 && !(validity & CRYPT_KV_VALID))
3491 this_key_has_invalid = 1;
3492 else if ((validity & CRYPT_KV_MATCH)
3493 && (!(validity & CRYPT_KV_STRONGID)
3494 || !(validity & CRYPT_KV_ADDR)))
3495 this_key_has_weak = 1;
3497 address_list_wipe(&r);
3502 if (!this_key_has_strong && this_key_has_invalid)
3504 if (!this_key_has_strong && this_key_has_weak)
3507 *matches_endp = tmp = crypt_copy_key (k);
3508 matches_endp = &tmp->next;
3509 the_valid_key = tmp;
3513 crypt_free_key (&keys);
3516 if (the_valid_key && !multi && !weak
3517 && !(invalid && option (OPTPGPSHOWUNUSABLE))) {
3519 * There was precisely one strong match on a valid ID, there
3520 * were no valid keys with weak matches, and we aren't
3521 * interested in seeing invalid keys.
3523 * Proceed without asking the user.
3525 k = crypt_copy_key (the_valid_key);
3529 * Else: Ask the user.
3531 k = crypt_select_key (matches, a, NULL, app, forced_valid);
3533 crypt_free_key (&matches);
3542 static crypt_key_t *crypt_getkeybystr (char *p, short abilities,
3543 unsigned int app, int *forced_valid)
3545 string_list_t *hints = NULL;
3547 crypt_key_t *matches = NULL;
3548 crypt_key_t **matches_endp = &matches;
3552 mutt_message (_("Looking for keys matching \"%s\"..."), p);
3556 hints = crypt_add_string_to_hints (hints, p);
3557 keys = get_candidates (hints, app, (abilities & KEYFLAG_CANSIGN));
3558 string_list_wipe(&hints);
3563 for (k = keys; k; k = k->next) {
3564 if (abilities && !(k->flags & abilities))
3568 debug_print (5, ("matching \"%s\" against " "key %s, \"%s\":\n", p, crypt_keyid (k), k->uid));
3570 if (!*p || !m_strcasecmp(p, crypt_keyid (k))
3571 || (!m_strncasecmp(p, "0x", 2)
3572 && !m_strcasecmp(p + 2, crypt_keyid (k)))
3573 || (option (OPTPGPLONGIDS)
3574 && !m_strncasecmp(p, "0x", 2)
3575 && !m_strcasecmp(p + 2, crypt_keyid (k) + 8))
3576 || m_stristr(k->uid, p)) {
3579 debug_print (5, ("match.\n"));
3581 *matches_endp = tmp = crypt_copy_key (k);
3582 matches_endp = &tmp->next;
3586 crypt_free_key (&keys);
3589 k = crypt_select_key (matches, NULL, p, app, forced_valid);
3590 crypt_free_key (&matches);
3597 /* Display TAG as a prompt to ask for a key. If WHATFOR is not null
3598 use it as default and store it under that label as the next
3599 default. ABILITIES describe the required key abilities (sign,
3600 encrypt) and APP the type of the requested key; ether S/MIME or
3601 PGP. Return a copy of the key or NULL if not found. */
3602 static crypt_key_t *crypt_ask_for_key (char *tag,
3605 unsigned int app, int *forced_valid)
3608 char resp[SHORT_STRING];
3609 struct crypt_cache *l = NULL;
3613 forced_valid = &dummy;
3615 mutt_clear_error ();
3621 for (l = id_defaults; l; l = l->next)
3622 if (!m_strcasecmp(whatfor, l->what)) {
3623 m_strcpy(resp, sizeof(resp), NONULL(l->dflt));
3631 if (mutt_get_field (tag, resp, sizeof (resp), M_CLEAR) != 0)
3636 m_strreplace(&l->dflt, resp);
3638 l = p_new(struct crypt_cache, 1);
3639 l->next = id_defaults;
3641 l->what = m_strdup(whatfor);
3642 l->dflt = m_strdup(resp);
3646 if ((key = crypt_getkeybystr (resp, abilities, app, forced_valid)))
3654 /* This routine attempts to find the keyids of the recipients of a
3655 message. It returns NULL if any of the keys can not be found. */
3656 static char *find_keys (address_t * to, address_t * cc, address_t * bcc,
3659 char *keyID, *keylist = NULL, *t;
3660 ssize_t keylist_size = 0;
3661 ssize_t keylist_used = 0;
3662 address_t *tmp = NULL, *addr = NULL;
3663 address_t **last = &tmp;
3666 crypt_key_t *k_info, *key;
3667 const char *fqdn = mutt_fqdn (1);
3670 *r_application = APPLICATION_PGP | APPLICATION_SMIME;
3673 for (i = 0; i < 3; i++) {
3688 *last = address_list_dup (p);
3690 last = &((*last)->next);
3694 rfc822_qualify (tmp, fqdn);
3696 tmp = mutt_remove_duplicates (tmp);
3698 for (p = tmp; p; p = p->next) {
3699 char buf[LONG_STRING];
3700 int forced_valid = 0;
3705 if ((keyID = mutt_crypt_hook (p)) != NULL) {
3708 snprintf (buf, sizeof (buf), _("Use keyID = \"%s\" for %s?"),
3710 if ((r = mutt_yesorno (buf, M_YES)) == M_YES) {
3711 /* check for e-mail address */
3712 if ((t = strchr (keyID, '@')) &&
3713 (addr = rfc822_parse_adrlist (NULL, keyID))) {
3715 rfc822_qualify (addr, fqdn);
3720 k_info = crypt_getkeybystr (keyID, KEYFLAG_CANENCRYPT,
3721 *r_application, &forced_valid);
3723 k_info = crypt_getkeybystr (keyID, KEYFLAG_CANENCRYPT,
3724 app, &forced_valid);
3730 address_list_wipe(&tmp);
3731 address_list_wipe(&addr);
3737 && (k_info = crypt_getkeybyaddr (q, KEYFLAG_CANENCRYPT,
3738 app, &forced_valid)) == NULL) {
3739 snprintf (buf, sizeof (buf), _("Enter keyID for %s: "), q->mailbox);
3741 if ((key = crypt_ask_for_key (buf, q->mailbox, KEYFLAG_CANENCRYPT,
3747 &forced_valid)) == NULL) {
3749 address_list_wipe(&tmp);
3750 address_list_wipe(&addr);
3758 const char *s = crypt_fpr (key);
3761 if (key->flags & KEYFLAG_ISX509)
3762 *r_application &= ~APPLICATION_PGP;
3763 if (!(key->flags & KEYFLAG_ISX509))
3764 *r_application &= ~APPLICATION_SMIME;
3767 keylist_size += m_strlen(s) + 4 + 1;
3768 p_realloc(&keylist, keylist_size);
3769 sprintf (keylist + keylist_used, "%s0x%s%s", /* __SPRINTF_CHECKED__ */
3770 keylist_used ? " " : "", s, forced_valid ? "!" : "");
3772 keylist_used = m_strlen(keylist);
3774 crypt_free_key (&key);
3775 address_list_wipe(&addr);
3777 address_list_wipe(&tmp);
3781 char *pgp_gpgme_findkeys (address_t * to, address_t * cc, address_t * bcc)
3783 return find_keys (to, cc, bcc, APPLICATION_PGP);
3786 char *smime_gpgme_findkeys (address_t * to, address_t * cc, address_t * bcc)
3788 return find_keys (to, cc, bcc, APPLICATION_SMIME);
3792 * Implementation of `init'.
3795 /* Initialization. */
3796 static void init_gpgme (void)
3798 /* Make sure that gpg-agent is running. */
3799 if (!getenv ("GPG_AGENT_INFO")) {
3800 mutt_error ("\nUsing GPGME backend, although no gpg-agent is running");
3801 if (mutt_any_key_to_continue (NULL) == -1)
3806 void pgp_gpgme_init (void)
3811 void smime_gpgme_init (void)
3815 static int gpgme_send_menu (HEADER * msg, int *redraw, int is_smime)
3818 char input_signas[SHORT_STRING];
3821 if (msg->security & APPLICATION_PGP)
3823 else if (msg->security & APPLICATION_SMIME)
3828 mutt_multi_choice (_
3829 ("S/MIME (e)ncrypt, (s)ign, sign (a)s, (b)oth, (p)gp or (c)lear?"),
3833 mutt_multi_choice (_
3834 ("PGP (e)ncrypt, (s)ign, sign (a)s, (b)oth, s/(m)ime or (c)lear?"),
3838 case 1: /* (e)ncrypt */
3839 msg->security |= (is_smime ? SMIMEENCRYPT : PGPENCRYPT);
3840 msg->security &= ~(is_smime ? SMIMESIGN : PGPSIGN);
3843 case 2: /* (s)ign */
3844 msg->security |= (is_smime ? SMIMESIGN : PGPSIGN);
3845 msg->security &= ~(is_smime ? SMIMEENCRYPT : PGPENCRYPT);
3848 case 3: /* sign (a)s */
3849 /* unset_option(OPTCRYPTCHECKTRUST); */
3850 if ((p = crypt_ask_for_key (_("Sign as: "), NULL, KEYFLAG_CANSIGN,
3851 is_smime ? APPLICATION_SMIME :
3852 APPLICATION_PGP, NULL))) {
3853 snprintf (input_signas, sizeof (input_signas), "0x%s", crypt_keyid (p));
3854 m_strreplace(is_smime ? &SmimeDefaultKey : &PgpSignAs,
3856 crypt_free_key (&p);
3858 msg->security |= (is_smime ? SMIMESIGN : PGPSIGN);
3862 msg->security &= (is_smime ? ~SMIMESIGN : ~PGPSIGN);
3865 *redraw = REDRAW_FULL;
3868 case 4: /* (b)oth */
3870 (is_smime ? (SMIMEENCRYPT | SMIMESIGN) : (PGPENCRYPT | PGPSIGN));
3873 case 5: /* (p)gp or s/(m)ime */
3874 is_smime = !is_smime;
3877 case 6: /* (c)lear */
3882 if (choice == 6 || choice == 7);
3883 else if (is_smime) {
3884 msg->security &= ~APPLICATION_PGP;
3885 msg->security |= APPLICATION_SMIME;
3888 msg->security &= ~APPLICATION_SMIME;
3889 msg->security |= APPLICATION_PGP;
3892 return (msg->security);
3895 int pgp_gpgme_send_menu (HEADER * msg, int *redraw)
3897 return gpgme_send_menu (msg, redraw, 0);
3900 int smime_gpgme_send_menu (HEADER * msg, int *redraw)
3902 return gpgme_send_menu (msg, redraw, 1);
3905 static int verify_sender (HEADER * h, gpgme_protocol_t protocol __attribute__((unused)))
3907 address_t *sender = NULL;
3908 unsigned int ret = 1;
3911 h->env->from = mutt_expand_aliases (h->env->from);
3912 sender = h->env->from;
3914 else if (h->env->sender) {
3915 h->env->sender = mutt_expand_aliases (h->env->sender);
3916 sender = h->env->sender;
3920 if (signature_key) {
3921 gpgme_key_t key = signature_key;
3922 gpgme_user_id_t uid = NULL;
3923 int sender_length = 0;
3926 sender_length = m_strlen(sender->mailbox);
3927 for (uid = key->uids; uid && ret; uid = uid->next) {
3928 uid_length = m_strlen(uid->email);
3929 if (1 && (uid->email[0] == '<')
3930 && (uid->email[uid_length - 1] == '>')
3931 && (uid_length == sender_length + 2)
3932 && (!strncmp (uid->email + 1, sender->mailbox, sender_length)))
3937 mutt_any_key_to_continue ("Failed to verify sender");
3940 mutt_any_key_to_continue ("Failed to figure out sender");
3942 if (signature_key) {
3943 gpgme_key_release (signature_key);
3944 signature_key = NULL;
3950 int smime_gpgme_verify_sender (HEADER * h)
3952 return verify_sender (h, GPGME_PROTOCOL_CMS);