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>
59 #include <lib-crypt/crypt.h>
63 #include "recvattach.h"
69 #define digitp(p) (*(p) >= '0' && *(p) <= '9')
70 #define hexdigitp(a) (digitp (a) \
71 || (*(a) >= 'A' && *(a) <= 'F') \
72 || (*(a) >= 'a' && *(a) <= 'f'))
73 #define xtoi_1(p) (*(p) <= '9'? (*(p)- '0'): \
74 *(p) <= 'F'? (*(p)-'A'+10):(*(p)-'a'+10))
75 #define xtoi_2(p) ((xtoi_1(p) * 16) + xtoi_1((p)+1))
77 /* Values used for comparing addresses. */
78 #define CRYPT_KV_VALID 1
79 #define CRYPT_KV_ADDR 2
80 #define CRYPT_KV_STRING 4
81 #define CRYPT_KV_STRONGID 8
82 #define CRYPT_KV_MATCH (CRYPT_KV_ADDR|CRYPT_KV_STRING)
91 struct crypt_cache *next;
99 /* We work based on user IDs, getting from a user ID to the key is
100 check and does not need any memory (gpgme uses reference counting). */
101 typedef struct crypt_keyinfo {
102 struct crypt_keyinfo *next;
104 int idx; /* and the user ID at this index */
105 const char *uid; /* and for convenience point to this user ID */
106 unsigned int flags; /* global and per uid flags (for convenience) */
109 typedef struct crypt_entry {
115 static struct crypt_cache *id_defaults = NULL;
116 static gpgme_key_t signature_key = NULL;
119 * General helper functions.
122 /* return true when S points to a didgit or letter. */
123 static int digit_or_letter (const unsigned char *s)
125 return ((*s >= '0' && *s <= '9')
126 || (*s >= 'A' && *s <= 'Z')
127 || (*s >= 'a' && *s <= 'z'));
131 /* Print the utf-8 encoded string BUF of length LEN bytes to stream
132 FP. Convert the character set. */
133 static void print_utf8 (FILE * fp, const char *buf, ssize_t len)
137 tstr = p_dupstr(buf, len);
138 mutt_convert_string (&tstr, "utf-8", Charset, M_ICONV_HOOK_FROM);
148 /* Return the keyID for the key K. Note that this string is valid as
149 long as K is valid */
150 static const char *crypt_keyid (crypt_key_t * k)
152 const char *s = "????????";
154 if (k->kobj && k->kobj->subkeys) {
155 s = k->kobj->subkeys->keyid;
156 if ((!option (OPTPGPLONGIDS)) && (m_strlen(s) == 16))
157 /* Return only the short keyID. */
164 /* Return the hexstring fingerprint from the key K. */
165 static const char *crypt_fpr (crypt_key_t * k)
169 if (k->kobj && k->kobj->subkeys)
170 s = k->kobj->subkeys->fpr;
175 /* Parse FLAGS and return a statically allocated(!) string with them. */
176 static char *crypt_key_abilities (int flags)
180 if (!(flags & KEYFLAG_CANENCRYPT))
182 else if (flags & KEYFLAG_PREFER_SIGNING)
187 if (!(flags & KEYFLAG_CANSIGN))
189 else if (flags & KEYFLAG_PREFER_ENCRYPTION)
199 /* Parse FLAGS and return a character describing the most important flag. */
200 static char crypt_flags (int flags)
202 if (flags & KEYFLAG_REVOKED)
204 else if (flags & KEYFLAG_EXPIRED)
206 else if (flags & KEYFLAG_DISABLED)
208 else if (flags & KEYFLAG_CRITICAL)
214 /* Return a copy of KEY. */
215 static crypt_key_t *crypt_copy_key (crypt_key_t *key)
219 k = p_new(crypt_key_t, 1);
221 gpgme_key_ref (key->kobj);
224 k->flags = key->flags;
229 /* Release all the keys at the address of KEYLIST and set the address
231 static void crypt_free_key (crypt_key_t ** keylist)
234 crypt_key_t *k = (*keylist)->next;
241 /* Return trute when key K is valid. */
242 static int crypt_key_is_valid (crypt_key_t * k)
244 if (k->flags & KEYFLAG_CANTUSE)
249 /* Return true whe validity of KEY is sufficient. */
250 static int crypt_id_is_strong (crypt_key_t * key)
252 gpgme_validity_t val = GPGME_VALIDITY_UNKNOWN;
253 gpgme_user_id_t uid = NULL;
257 if ((key->flags & KEYFLAG_ISX509))
260 for (i = 0, uid = key->kobj->uids; (i < key->idx) && uid;
261 i++, uid = uid->next);
266 case GPGME_VALIDITY_UNKNOWN:
267 case GPGME_VALIDITY_UNDEFINED:
268 case GPGME_VALIDITY_NEVER:
269 case GPGME_VALIDITY_MARGINAL:
273 case GPGME_VALIDITY_FULL:
274 case GPGME_VALIDITY_ULTIMATE:
282 /* Return true when the KEY is valid, i.e. not marked as unusable. */
283 static int crypt_id_is_valid (crypt_key_t * key)
285 return !(key->flags & KEYFLAG_CANTUSE);
288 /* Return a bit vector describing how well the addresses ADDR and
289 U_ADDR match and whether KEY is valid. */
290 static int crypt_id_matches_addr (address_t * addr, address_t * u_addr,
295 if (crypt_id_is_valid (key))
296 rv |= CRYPT_KV_VALID;
298 if (crypt_id_is_strong (key))
299 rv |= CRYPT_KV_STRONGID;
301 if (addr->mailbox && u_addr->mailbox
302 && m_strcasecmp(addr->mailbox, u_addr->mailbox) == 0)
305 if (addr->personal && u_addr->personal
306 && m_strcasecmp(addr->personal, u_addr->personal) == 0)
307 rv |= CRYPT_KV_STRING;
314 * GPGME convenient functions.
317 /* Create a new gpgme context and return it. With FOR_SMIME set to
318 true, the protocol of the context is set to CMS. */
319 static gpgme_ctx_t create_gpgme_context (int for_smime)
324 err = gpgme_new (&ctx);
326 mutt_error (_("error creating gpgme context: %s\n"), gpgme_strerror (err));
332 err = gpgme_set_protocol (ctx, GPGME_PROTOCOL_CMS);
334 mutt_error (_("error enabling CMS protocol: %s\n"), gpgme_strerror (err));
343 /* Create a new gpgme data object. This is a wrapper to die on
345 static gpgme_data_t create_gpgme_data (void)
350 err = gpgme_data_new (&data);
352 mutt_error (_("error creating gpgme data object: %s\n"),
353 gpgme_strerror (err));
360 /* Create a new GPGME Data object from the mail body A. With CONVERT
361 passed as true, the lines are converted to CR,LF if required.
362 Return NULL on error or the gpgme_data_t object on success. */
363 static gpgme_data_t body_to_data_object (BODY * a, int convert)
365 char tempfile[_POSIX_PATH_MAX];
370 mutt_mktemp (tempfile);
371 fptmp = safe_fopen (tempfile, "w+");
373 mutt_perror (tempfile);
377 mutt_write_mime_header (a, fptmp);
379 mutt_write_mime_body (a, fptmp);
383 unsigned char buf[1];
385 data = create_gpgme_data ();
387 while ((c = fgetc (fptmp)) != EOF) {
391 if (c == '\n' && !hadcr) {
393 gpgme_data_write (data, buf, 1);
398 /* FIXME: This is quite suboptimal */
400 gpgme_data_write (data, buf, 1);
403 gpgme_data_seek (data, 0, SEEK_SET);
407 err = gpgme_data_new_from_file (&data, tempfile, 1);
411 mutt_error (_("error allocating data object: %s\n"), gpgme_strerror (err));
418 /* Create a GPGME data object from the stream FP but limit the object
419 to LENGTH bytes starting at OFFSET bytes from the beginning of the
421 static gpgme_data_t file_to_data_object (FILE * fp, long offset, long length)
426 err = gpgme_data_new_from_filepart (&data, NULL, fp, offset, length);
428 mutt_error (_("error allocating data object: %s\n"), gpgme_strerror (err));
435 /* Write a GPGME data object to the stream FP. */
436 static int data_object_to_stream (gpgme_data_t data, FILE * fp)
442 err = ((gpgme_data_seek (data, 0, SEEK_SET) == -1)
443 ? gpgme_error_from_errno (errno) : 0);
445 mutt_error (_("error rewinding data object: %s\n"), gpgme_strerror (err));
449 while ((nread = gpgme_data_read (data, buf, sizeof (buf)))) {
450 /* fixme: we are not really converting CRLF to LF but just
451 skipping CR. Doing it correctly needs a more complex logic */
452 for (p = buf; nread; p++, nread--) {
458 mutt_perror ("[tempfile]");
463 mutt_error (_("error reading data object: %s\n"), strerror (errno));
469 /* Copy a data object to a newly created temporay file and return that
470 filename. Caller must free. With RET_FP not NULL, don't close the
471 stream but return it there. */
472 static char *data_object_to_tempfile (gpgme_data_t data, FILE ** ret_fp)
475 char tempfile[_POSIX_PATH_MAX];
479 mutt_mktemp (tempfile);
480 fp = safe_fopen (tempfile, "w+");
482 mutt_perror (tempfile);
486 err = ((gpgme_data_seek (data, 0, SEEK_SET) == -1)
487 ? gpgme_error_from_errno (errno) : 0);
491 while ((nread = gpgme_data_read (data, buf, sizeof (buf)))) {
492 if (fwrite (buf, nread, 1, fp) != 1) {
493 mutt_perror (tempfile);
505 mutt_error (_("error reading data object: %s\n"), gpgme_strerror (err));
512 return m_strdup(tempfile);
516 /* Create a GpgmeRecipientSet from the keys in the string KEYLIST.
517 The keys must be space delimited. */
518 static gpgme_key_t *create_recipient_set (const char *keylist,
519 gpgme_protocol_t protocol)
525 gpgme_key_t *rset = NULL;
526 unsigned int rset_n = 0;
527 gpgme_key_t key = NULL;
528 gpgme_ctx_t context = NULL;
530 err = gpgme_new (&context);
532 err = gpgme_set_protocol (context, protocol);
539 for (i = 0; *s && *s != ' ' && i < ssizeof(buf) - 1;)
543 if (i > 1 && buf[i - 1] == '!') {
544 /* The user selected to override the valididy of that
548 err = gpgme_get_key (context, buf, &key, 0);
550 key->uids->validity = GPGME_VALIDITY_FULL;
554 err = gpgme_get_key (context, buf, &key, 0);
557 p_realloc(&rset, rset_n + 1);
558 rset[rset_n++] = key;
561 mutt_error (_("error adding recipient `%s': %s\n"),
562 buf, gpgme_strerror (err));
570 /* NULL terminate. */
571 p_realloc(&rset, rset_n + 1);
572 rset[rset_n++] = NULL;
575 gpgme_release (context);
581 /* Make sure that the correct signer is set. Returns 0 on success. */
582 static int set_signer (gpgme_ctx_t ctx, int for_smime)
584 char *signid = for_smime ? SmimeDefaultKey : PgpSignAs;
587 gpgme_key_t key, key2;
589 if (!signid || !*signid)
592 listctx = create_gpgme_context (for_smime);
593 err = gpgme_op_keylist_start (listctx, signid, 1);
595 err = gpgme_op_keylist_next (listctx, &key);
597 gpgme_release (listctx);
598 mutt_error (_("secret key `%s' not found: %s\n"),
599 signid, gpgme_strerror (err));
602 err = gpgme_op_keylist_next (listctx, &key2);
604 gpgme_key_release (key);
605 gpgme_key_release (key2);
606 gpgme_release (listctx);
607 mutt_error (_("ambiguous specification of secret key `%s'\n"), signid);
610 gpgme_op_keylist_end (listctx);
611 gpgme_release (listctx);
613 gpgme_signers_clear (ctx);
614 err = gpgme_signers_add (ctx, key);
615 gpgme_key_release (key);
617 mutt_error (_("error setting secret key `%s': %s\n"),
618 signid, gpgme_strerror (err));
625 /* Encrypt the gpgme data object PLAINTEXT to the recipients in RSET
626 and return an allocated filename to a temporary file containing the
627 enciphered text. With USE_SMIME set to true, the smime backend is
628 used. With COMBINED_SIGNED a PGP message is signed and
629 encrypted. Returns NULL in case of error */
630 static char *encrypt_gpgme_object (gpgme_data_t plaintext, gpgme_key_t * rset,
631 int use_smime, int combined_signed)
635 gpgme_data_t ciphertext;
638 ctx = create_gpgme_context (use_smime);
640 gpgme_set_armor (ctx, 1);
642 ciphertext = create_gpgme_data ();
644 if (combined_signed) {
645 if (set_signer (ctx, use_smime)) {
646 gpgme_data_release (ciphertext);
650 err = gpgme_op_encrypt_sign (ctx, rset, GPGME_ENCRYPT_ALWAYS_TRUST,
651 plaintext, ciphertext);
654 err = gpgme_op_encrypt (ctx, rset, GPGME_ENCRYPT_ALWAYS_TRUST,
655 plaintext, ciphertext);
656 mutt_need_hard_redraw ();
658 mutt_error (_("error encrypting data: %s\n"), gpgme_strerror (err));
659 gpgme_data_release (ciphertext);
666 outfile = data_object_to_tempfile (ciphertext, NULL);
667 gpgme_data_release (ciphertext);
671 /* Find the "micalg" parameter from the last Gpgme operation on
672 context CTX. It is expected that this operation was a sign
673 operation. Return the algorithm name as a C string in buffer BUF
674 which must have been allocated by the caller with size BUFLEN.
675 Returns 0 on success or -1 in case of an error. The return string
676 is truncted to BUFLEN - 1. */
677 static int get_micalg (gpgme_ctx_t ctx, char *buf, ssize_t buflen)
679 gpgme_sign_result_t result = NULL;
680 const char *algorithm_name = NULL;
686 result = gpgme_op_sign_result (ctx);
688 algorithm_name = gpgme_hash_algo_name (result->signatures->hash_algo);
689 if (algorithm_name) {
690 m_strcpy(buf, buflen, algorithm_name);
694 return *buf ? 0 : -1;
697 static void print_time (time_t t, STATE * s)
701 setlocale (LC_TIME, "");
702 #ifdef HAVE_LANGINFO_D_T_FMT
703 strftime (p, sizeof (p), nl_langinfo (D_T_FMT), localtime (&t));
705 strftime (p, sizeof (p), "%c", localtime (&t));
707 setlocale (LC_TIME, "C");
708 state_attach_puts (p, s);
712 * Implementation of `sign_message'.
715 /* Sign the MESSAGE in body A either using OpenPGP or S/MIME when
716 USE_SMIME is passed as true. Returns the new body or NULL on
718 static BODY *sign_message (BODY * a, int use_smime)
725 gpgme_data_t message, signature;
727 convert_to_7bit (a); /* Signed data _must_ be in 7-bit format. */
729 message = body_to_data_object (a, 1);
732 signature = create_gpgme_data ();
734 ctx = create_gpgme_context (use_smime);
736 gpgme_set_armor (ctx, 1);
738 if (set_signer (ctx, use_smime)) {
739 gpgme_data_release (signature);
744 err = gpgme_op_sign (ctx, message, signature, GPGME_SIG_MODE_DETACH);
745 mutt_need_hard_redraw ();
746 gpgme_data_release (message);
748 gpgme_data_release (signature);
750 mutt_error (_("error signing data: %s\n"), gpgme_strerror (err));
754 sigfile = data_object_to_tempfile (signature, NULL);
755 gpgme_data_release (signature);
761 t = mutt_new_body ();
762 t->type = TYPEMULTIPART;
763 t->subtype = m_strdup("signed");
764 t->encoding = ENC7BIT;
766 t->disposition = DISPINLINE;
768 mutt_generate_boundary (&t->parameter);
769 mutt_set_parameter ("protocol",
770 use_smime ? "application/pkcs7-signature"
771 : "application/pgp-signature", &t->parameter);
772 /* Get the micalg from gpgme. Old gpgme versions don't support this
773 for S/MIME so we assume sha-1 in this case. */
774 if (!get_micalg (ctx, buf, sizeof buf))
775 mutt_set_parameter ("micalg", buf, &t->parameter);
777 mutt_set_parameter ("micalg", "sha1", &t->parameter);
783 t->parts->next = mutt_new_body ();
785 t->type = TYPEAPPLICATION;
787 t->subtype = m_strdup("pkcs7-signature");
788 mutt_set_parameter ("name", "smime.p7s", &t->parameter);
789 t->encoding = ENCBASE64;
791 t->disposition = DISPATTACH;
792 t->d_filename = m_strdup("smime.p7s");
795 t->subtype = m_strdup("pgp-signature");
797 t->disposition = DISPINLINE;
798 t->encoding = ENC7BIT;
800 t->filename = sigfile;
801 t->unlink = 1; /* ok to remove this file after sending. */
807 BODY *pgp_gpgme_sign_message (BODY * a)
809 return sign_message (a, 0);
812 BODY *smime_gpgme_sign_message (BODY * a)
814 return sign_message (a, 1);
818 * Implementation of `encrypt_message'.
821 /* Encrypt the mail body A to all keys given as space separated keyids
822 or fingerprints in KEYLIST and return the encrypted body. */
823 BODY *pgp_gpgme_encrypt_message (BODY * a, char *keylist, int sign)
825 char *outfile = NULL;
827 gpgme_key_t *rset = NULL;
828 gpgme_data_t plaintext;
830 rset = create_recipient_set (keylist, GPGME_PROTOCOL_OpenPGP);
836 plaintext = body_to_data_object (a, 0);
842 outfile = encrypt_gpgme_object (plaintext, rset, 0, sign);
843 gpgme_data_release (plaintext);
848 t = mutt_new_body ();
849 t->type = TYPEMULTIPART;
850 t->subtype = m_strdup("encrypted");
851 t->encoding = ENC7BIT;
853 t->disposition = DISPINLINE;
855 mutt_generate_boundary (&t->parameter);
856 mutt_set_parameter ("protocol", "application/pgp-encrypted", &t->parameter);
858 t->parts = mutt_new_body ();
859 t->parts->type = TYPEAPPLICATION;
860 t->parts->subtype = m_strdup("pgp-encrypted");
861 t->parts->encoding = ENC7BIT;
863 t->parts->next = mutt_new_body ();
864 t->parts->next->type = TYPEAPPLICATION;
865 t->parts->next->subtype = m_strdup("octet-stream");
866 t->parts->next->encoding = ENC7BIT;
867 t->parts->next->filename = outfile;
868 t->parts->next->use_disp = 1;
869 t->parts->next->disposition = DISPINLINE;
870 t->parts->next->unlink = 1; /* delete after sending the message */
871 t->parts->next->d_filename = m_strdup("msg.asc"); /* non pgp/mime
878 * Implementation of `smime_build_smime_entity'.
881 /* Encrypt the mail body A to all keys given as space separated
882 fingerprints in KEYLIST and return the S/MIME encrypted body. */
883 BODY *smime_gpgme_build_smime_entity (BODY * a, char *keylist)
885 char *outfile = NULL;
887 gpgme_key_t *rset = NULL;
888 gpgme_data_t plaintext;
890 rset = create_recipient_set (keylist, GPGME_PROTOCOL_CMS);
894 plaintext = body_to_data_object (a, 0);
900 outfile = encrypt_gpgme_object (plaintext, rset, 1, 0);
901 gpgme_data_release (plaintext);
906 t = mutt_new_body ();
907 t->type = TYPEAPPLICATION;
908 t->subtype = m_strdup("pkcs7-mime");
909 mutt_set_parameter ("name", "smime.p7m", &t->parameter);
910 mutt_set_parameter ("smime-type", "enveloped-data", &t->parameter);
911 t->encoding = ENCBASE64; /* The output of OpenSSL SHOULD be binary */
913 t->disposition = DISPATTACH;
914 t->d_filename = m_strdup("smime.p7m");
915 t->filename = outfile;
916 t->unlink = 1; /*delete after sending the message */
925 * Implementation of `verify_one'.
928 /* Display the common attributes of the signature summary SUM.
929 Return 1 if there is is a severe warning.
931 static int show_sig_summary (unsigned long sum,
932 gpgme_ctx_t ctx, gpgme_key_t key, int idx,
937 if ((sum & GPGME_SIGSUM_KEY_REVOKED)) {
938 state_attach_puts (_("Warning: One of the keys has been revoked\n"), s);
942 if ((sum & GPGME_SIGSUM_KEY_EXPIRED)) {
943 time_t at = key->subkeys->expires ? key->subkeys->expires : 0;
946 state_attach_puts (_("Warning: The key used to create the "
947 "signature expired at: "), s);
949 state_attach_puts ("\n", s);
952 state_attach_puts (_("Warning: At least one certification key "
953 "has expired\n"), s);
956 if ((sum & GPGME_SIGSUM_SIG_EXPIRED)) {
957 gpgme_verify_result_t result;
958 gpgme_signature_t sig;
961 result = gpgme_op_verify_result (ctx);
963 for (sig = result->signatures, i = 0; sig && (i < idx);
964 sig = sig->next, i++);
966 state_attach_puts (_("Warning: The signature expired at: "), s);
967 print_time (sig ? sig->exp_timestamp : 0, s);
968 state_attach_puts ("\n", s);
971 if ((sum & GPGME_SIGSUM_KEY_MISSING))
972 state_attach_puts (_("Can't verify due to a missing "
973 "key or certificate\n"), s);
975 if ((sum & GPGME_SIGSUM_CRL_MISSING)) {
976 state_attach_puts (_("The CRL is not available\n"), s);
980 if ((sum & GPGME_SIGSUM_CRL_TOO_OLD)) {
981 state_attach_puts (_("Available CRL is too old\n"), s);
985 if ((sum & GPGME_SIGSUM_BAD_POLICY))
986 state_attach_puts (_("A policy requirement was not met\n"), s);
988 if ((sum & GPGME_SIGSUM_SYS_ERROR)) {
989 const char *t0 = NULL, *t1 = NULL;
990 gpgme_verify_result_t result;
991 gpgme_signature_t sig;
994 state_attach_puts (_("A system error occurred"), s);
996 /* Try to figure out some more detailed system error information. */
997 result = gpgme_op_verify_result (ctx);
998 for (sig = result->signatures, i = 0; sig && (i < idx);
999 sig = sig->next, i++);
1002 t1 = sig->wrong_key_usage ? "Wrong_Key_Usage" : "";
1006 state_attach_puts (": ", s);
1008 state_attach_puts (t0, s);
1009 if (t1 && !(t0 && !m_strcmp(t0, t1))) {
1011 state_attach_puts (",", s);
1012 state_attach_puts (t1, s);
1015 state_attach_puts ("\n", s);
1022 static void show_fingerprint (gpgme_key_t key, STATE * state)
1027 const char *prefix = _("Fingerprint: ");
1031 s = key->subkeys ? key->subkeys->fpr : NULL;
1034 is_pgp = (key->protocol == GPGME_PROTOCOL_OpenPGP);
1036 buf = xmalloc(m_strlen(prefix) + m_strlen(s) * 4 + 2);
1037 strcpy (buf, prefix); /* __STRCPY_CHECKED__ */
1038 p = buf + m_strlen(buf);
1039 if (is_pgp && m_strlen(s) == 40) { /* PGP v4 style formatted. */
1040 for (i = 0; *s && s[1] && s[2] && s[3] && s[4]; s += 4, i++) {
1051 for (i = 0; *s && s[1] && s[2]; s += 2, i++) {
1054 *p++ = is_pgp ? ' ' : ':';
1055 if (is_pgp && i == 7)
1060 /* just in case print remaining odd digits */
1065 state_attach_puts (buf, state);
1069 /* Show the valididy of a key used for one signature. */
1070 static void show_one_sig_validity (gpgme_ctx_t ctx, int idx, STATE * s)
1072 gpgme_verify_result_t result = NULL;
1073 gpgme_signature_t sig = NULL;
1074 const char *txt = NULL;
1076 result = gpgme_op_verify_result (ctx);
1078 for (sig = result->signatures; sig && (idx > 0); sig = sig->next, idx--);
1080 switch (sig ? sig->validity : 0) {
1081 case GPGME_VALIDITY_UNKNOWN:
1082 txt = _("WARNING: We have NO indication whether "
1083 "the key belongs to the person named " "as shown above\n");
1085 case GPGME_VALIDITY_UNDEFINED:
1087 case GPGME_VALIDITY_NEVER:
1088 txt = _("WARNING: The key does NOT BELONG to "
1089 "the person named as shown above\n");
1091 case GPGME_VALIDITY_MARGINAL:
1092 txt = _("WARNING: It is NOT certain that the key "
1093 "belongs to the person named as shown above\n");
1095 case GPGME_VALIDITY_FULL:
1096 case GPGME_VALIDITY_ULTIMATE:
1101 state_attach_puts (txt, s);
1104 /* Show information about one signature. This fucntion is called with
1105 the context CTX of a sucessful verification operation and the
1106 enumerator IDX which should start at 0 and incremete for each
1109 Return values are: 0 for normal procession, 1 for a bad signature,
1110 2 for a signature with a warning or -1 for no more signature. */
1111 static int show_one_sig_status (gpgme_ctx_t ctx, int idx, STATE * s)
1114 const char *fpr, *uid;
1115 gpgme_key_t key = NULL;
1116 int i, anybad = 0, anywarn = 0;
1118 gpgme_user_id_t uids = NULL;
1119 gpgme_verify_result_t result;
1120 gpgme_signature_t sig;
1121 gpgme_error_t err = GPG_ERR_NO_ERROR;
1123 result = gpgme_op_verify_result (ctx);
1125 /* FIXME: this code should use a static variable and remember
1126 the current position in the list of signatures, IMHO.
1129 for (i = 0, sig = result->signatures; sig && (i < idx);
1130 i++, sig = sig->next);
1132 return -1; /* Signature not found. */
1134 if (signature_key) {
1135 gpgme_key_release (signature_key);
1136 signature_key = NULL;
1139 created = sig->timestamp;
1143 if (gpg_err_code (sig->status) != GPG_ERR_NO_ERROR)
1146 err = gpgme_get_key (ctx, fpr, &key, 0); /* secret key? */
1148 uid = (key->uids && key->uids->uid) ? key->uids->uid : "[?]";
1150 signature_key = key;
1153 key = NULL; /* Old gpgme versions did not set KEY to NULL on
1154 error. Do it here to avoid a double free. */
1158 if (!s || !s->fpout || !(s->flags & M_DISPLAY)); /* No state information so no way to print anything. */
1160 state_attach_puts (_("Error getting key information: "), s);
1161 state_attach_puts (gpg_strerror (err), s);
1162 state_attach_puts ("\n", s);
1165 else if ((sum & GPGME_SIGSUM_GREEN)) {
1166 state_attach_puts (_("Good signature from: "), s);
1167 state_attach_puts (uid, s);
1168 state_attach_puts ("\n", s);
1169 for (i = 1, uids = key->uids; uids; i++, uids = uids->next) {
1171 /* Skip primary UID. */
1175 state_attach_puts (_(" aka: "), s);
1176 state_attach_puts (uids->uid, s);
1177 state_attach_puts ("\n", s);
1179 state_attach_puts (_(" created: "), s);
1180 print_time (created, s);
1181 state_attach_puts ("\n", s);
1182 if (show_sig_summary (sum, ctx, key, idx, s))
1184 show_one_sig_validity (ctx, idx, s);
1186 else if ((sum & GPGME_SIGSUM_RED)) {
1187 state_attach_puts (_("*BAD* signature claimed to be from: "), s);
1188 state_attach_puts (uid, s);
1189 state_attach_puts ("\n", s);
1190 show_sig_summary (sum, ctx, key, idx, s);
1192 else if (!anybad && key && (key->protocol == GPGME_PROTOCOL_OpenPGP)) { /* We can't decide (yellow) but this is a PGP key with a good
1193 signature, so we display what a PGP user expects: The name,
1194 fingerprint and the key validity (which is neither fully or
1196 state_attach_puts (_("Good signature from: "), s);
1197 state_attach_puts (uid, s);
1198 state_attach_puts ("\n", s);
1199 state_attach_puts (_(" created: "), s);
1200 print_time (created, s);
1201 state_attach_puts ("\n", s);
1202 show_one_sig_validity (ctx, idx, s);
1203 show_fingerprint (key, s);
1204 if (show_sig_summary (sum, ctx, key, idx, s))
1207 else { /* can't decide (yellow) */
1209 state_attach_puts (_("Error checking signature"), s);
1210 state_attach_puts ("\n", s);
1211 show_sig_summary (sum, ctx, key, idx, s);
1214 if (key != signature_key)
1215 gpgme_key_release (key);
1218 return anybad ? 1 : anywarn ? 2 : 0;
1221 /* Do the actual verification step. With IS_SMIME set to true we
1222 assume S/MIME (surprise!) */
1223 static int verify_one (BODY * sigbdy, STATE * s,
1224 const char *tempfile, int is_smime)
1230 gpgme_data_t signature, message;
1232 signature = file_to_data_object (s->fpin, sigbdy->offset, sigbdy->length);
1236 /* We need to tell gpgme about the encoding because the backend can't
1237 auto-detect plain base-64 encoding which is used by S/MIME. */
1239 gpgme_data_set_encoding (signature, GPGME_DATA_ENCODING_BASE64);
1241 err = gpgme_data_new_from_file (&message, tempfile, 1);
1243 gpgme_data_release (signature);
1244 mutt_error (_("error allocating data object: %s\n"), gpgme_strerror (err));
1247 ctx = create_gpgme_context (is_smime);
1249 /* Note: We don't need a current time output because GPGME avoids
1250 such an attack by separating the meta information from the
1252 state_attach_puts (_("[-- Begin signature information --]\n"), s);
1254 err = gpgme_op_verify (ctx, signature, message, NULL);
1255 mutt_need_hard_redraw ();
1259 snprintf (buf, sizeof (buf) - 1,
1260 _("Error: verification failed: %s\n"), gpgme_strerror (err));
1261 state_attach_puts (buf, s);
1263 else { /* Verification succeeded, see what the result is. */
1267 if (signature_key) {
1268 gpgme_key_release (signature_key);
1269 signature_key = NULL;
1272 for (idx = 0; (res = show_one_sig_status (ctx, idx, s)) != -1; idx++) {
1283 gpgme_verify_result_t result;
1284 gpgme_sig_notation_t notation;
1285 gpgme_signature_t sig;
1287 result = gpgme_op_verify_result (ctx);
1289 for (sig = result->signatures; sig; sig = sig->next) {
1290 if (sig->notations) {
1291 state_attach_puts ("*** Begin Notation (signature by: ", s);
1292 state_attach_puts (sig->fpr, s);
1293 state_attach_puts (") ***\n", s);
1294 for (notation = sig->notations; notation; notation = notation->next)
1296 if (notation->name) {
1297 state_attach_puts (notation->name, s);
1298 state_attach_puts ("=", s);
1300 if (notation->value) {
1301 state_attach_puts (notation->value, s);
1302 if (!(*notation->value
1303 && (notation->value[m_strlen(notation->value) - 1] ==
1305 state_attach_puts ("\n", s);
1308 state_attach_puts ("*** End Notation ***\n", s);
1314 gpgme_release (ctx);
1316 state_attach_puts (_("[-- End signature information --]\n\n"), s);
1317 debug_print (1, ("returning %d.\n", badsig));
1319 return badsig ? 1 : anywarn ? 2 : 0;
1322 int pgp_gpgme_verify_one (BODY * sigbdy, STATE * s, const char *tempfile)
1324 return verify_one (sigbdy, s, tempfile, 0);
1327 int smime_gpgme_verify_one (BODY * sigbdy, STATE * s, const char *tempfile)
1329 return verify_one (sigbdy, s, tempfile, 1);
1333 * Implementation of `decrypt_part'.
1336 /* Decrypt a PGP or SMIME message (depending on the boolean flag
1337 IS_SMIME) with body A described further by state S. Write
1338 plaintext out to file FPOUT and return a new body. For PGP returns
1339 a flag in R_IS_SIGNED to indicate whether this is a combined
1340 encrypted and signed message, for S/MIME it returns true when it is
1341 not a encrypted but a signed message. */
1342 static BODY *decrypt_part (BODY * a, STATE * s, FILE * fpout, int is_smime,
1349 gpgme_data_t ciphertext, plaintext;
1350 int maybe_signed = 0;
1357 ctx = create_gpgme_context (is_smime);
1360 /* Make a data object from the body, create context etc. */
1361 ciphertext = file_to_data_object (s->fpin, a->offset, a->length);
1364 plaintext = create_gpgme_data ();
1366 /* Do the decryption or the verification in case of the S/MIME hack. */
1367 if ((!is_smime) || maybe_signed) {
1369 err = gpgme_op_decrypt_verify (ctx, ciphertext, plaintext);
1370 else if (maybe_signed)
1371 err = gpgme_op_verify (ctx, ciphertext, NULL, plaintext);
1374 /* Check wether signatures have been verified. */
1375 gpgme_verify_result_t verify_result = gpgme_op_verify_result (ctx);
1377 if (verify_result->signatures)
1382 err = gpgme_op_decrypt (ctx, ciphertext, plaintext);
1383 gpgme_data_release (ciphertext);
1385 if (is_smime && !maybe_signed && gpg_err_code (err) == GPG_ERR_NO_DATA) {
1386 /* Check whether this might be a signed message despite what
1387 the mime header told us. Retry then. gpgsm returns the
1388 error information "unsupported Algorithm '?'" but gpgme
1389 will not store this unknown algorithm, thus we test that
1390 it has not been set. */
1391 gpgme_decrypt_result_t result;
1393 result = gpgme_op_decrypt_result (ctx);
1394 if (!result->unsupported_algorithm) {
1396 gpgme_data_release (plaintext);
1400 mutt_need_hard_redraw ();
1401 if ((s->flags & M_DISPLAY)) {
1404 snprintf (buf, sizeof (buf) - 1,
1405 _("[-- Error: decryption failed: %s --]\n\n"),
1406 gpgme_strerror (err));
1407 state_attach_puts (buf, s);
1409 gpgme_data_release (plaintext);
1410 gpgme_release (ctx);
1413 mutt_need_hard_redraw ();
1415 /* Read the output from GPGME, and make sure to change CRLF to LF,
1416 otherwise read_mime_header has a hard time parsing the message. */
1417 if (data_object_to_stream (plaintext, fpout)) {
1418 gpgme_data_release (plaintext);
1419 gpgme_release (ctx);
1422 gpgme_data_release (plaintext);
1424 a->is_signed_data = 0;
1430 a->is_signed_data = 1;
1432 *r_is_signed = -1; /* A signature exists. */
1434 if ((s->flags & M_DISPLAY))
1435 state_attach_puts (_("[-- Begin signature " "information --]\n"), s);
1436 for (idx = 0; (res = show_one_sig_status (ctx, idx, s)) != -1; idx++) {
1442 if (!anybad && idx && r_is_signed && *r_is_signed)
1443 *r_is_signed = anywarn ? 2 : 1; /* Good signature. */
1445 if ((s->flags & M_DISPLAY))
1446 state_attach_puts (_("[-- End signature " "information --]\n\n"), s);
1448 gpgme_release (ctx);
1453 tattach = mutt_read_mime_header (fpout, 0);
1456 * Need to set the length of this body part.
1458 fstat (fileno (fpout), &info);
1459 tattach->length = info.st_size - tattach->offset;
1461 tattach->warnsig = anywarn;
1463 /* See if we need to recurse on this MIME part. */
1464 mutt_parse_part (fpout, tattach);
1470 /* Decrypt a PGP/MIME message in FPIN and B and return a new body and
1471 the stream in CUR and FPOUT. Returns 0 on success. */
1472 int pgp_gpgme_decrypt_mime (FILE * fpin, FILE ** fpout, BODY * b, BODY ** cur)
1474 char tempfile[_POSIX_PATH_MAX];
1476 BODY *first_part = b;
1479 first_part->goodsig = 0;
1480 first_part->warnsig = 0;
1482 if (!mutt_is_multipart_encrypted (b))
1485 if (!b->parts || !b->parts->next)
1492 mutt_mktemp (tempfile);
1493 if (!(*fpout = safe_fopen (tempfile, "w+"))) {
1494 mutt_perror (tempfile);
1499 *cur = decrypt_part (b, &s, *fpout, 0, &is_signed);
1502 first_part->goodsig = 1;
1504 return *cur ? 0 : -1;
1508 /* Decrypt a S/MIME message in FPIN and B and return a new body and
1509 the stream in CUR and FPOUT. Returns 0 on success. */
1510 int smime_gpgme_decrypt_mime (FILE * fpin, FILE ** fpout, BODY * b,
1513 char tempfile[_POSIX_PATH_MAX];
1517 long saved_b_offset;
1518 ssize_t saved_b_length;
1521 if (!mutt_is_application_smime (b))
1527 /* Decode the body - we need to pass binary CMS to the
1528 backend. The backend allows for Base64 encoded data but it does
1529 not allow for QP which I have seen in some messages. So better
1531 saved_b_type = b->type;
1532 saved_b_offset = b->offset;
1533 saved_b_length = b->length;
1536 fseeko (s.fpin, b->offset, 0);
1537 mutt_mktemp (tempfile);
1538 if (!(tmpfp = safe_fopen (tempfile, "w+"))) {
1539 mutt_perror (tempfile);
1542 mutt_unlink (tempfile);
1545 mutt_decode_attachment (b, &s);
1547 b->length = ftello (s.fpout);
1554 mutt_mktemp (tempfile);
1555 if (!(*fpout = safe_fopen (tempfile, "w+"))) {
1556 mutt_perror (tempfile);
1559 mutt_unlink (tempfile);
1561 *cur = decrypt_part (b, &s, *fpout, 1, &is_signed);
1563 (*cur)->goodsig = is_signed > 0;
1564 b->type = saved_b_type;
1565 b->length = saved_b_length;
1566 b->offset = saved_b_offset;
1569 if (*cur && !is_signed && !(*cur)->parts
1570 && mutt_is_application_smime (*cur)) {
1571 /* Assume that this is a opaque signed s/mime message. This is
1572 an ugly way of doing it but we have anyway a problem with
1573 arbitrary encoded S/MIME messages: Only the outer part may be
1574 encrypted. The entire mime parsing should be revamped,
1575 probably by keeping the temportary files so that we don't
1576 need to decrypt them all the time. Inner parts of an
1577 encrypted part can then pint into this file and tehre won't
1578 never be a need to decrypt again. This needs a partial
1579 rewrite of the MIME engine. */
1583 saved_b_type = bb->type;
1584 saved_b_offset = bb->offset;
1585 saved_b_length = bb->length;
1588 fseeko (s.fpin, bb->offset, 0);
1589 mutt_mktemp (tempfile);
1590 if (!(tmpfp = safe_fopen (tempfile, "w+"))) {
1591 mutt_perror (tempfile);
1594 mutt_unlink (tempfile);
1597 mutt_decode_attachment (bb, &s);
1599 bb->length = ftello (s.fpout);
1607 mutt_mktemp (tempfile);
1608 if (!(*fpout = safe_fopen (tempfile, "w+"))) {
1609 mutt_perror (tempfile);
1612 mutt_unlink (tempfile);
1614 tmp_b = decrypt_part (bb, &s, *fpout, 1, &is_signed);
1616 tmp_b->goodsig = is_signed > 0;
1617 bb->type = saved_b_type;
1618 bb->length = saved_b_length;
1619 bb->offset = saved_b_offset;
1622 mutt_free_body (cur);
1625 return *cur ? 0 : -1;
1630 * Implementation of `pgp_check_traditional'.
1633 static int pgp_check_traditional_one_body (FILE * fp, BODY * b,
1636 char tempfile[_POSIX_PATH_MAX];
1637 char buf[HUGE_STRING];
1643 if (b->type != TYPETEXT)
1646 if (tagged_only && !b->tagged)
1649 mutt_mktemp (tempfile);
1650 if (mutt_decode_save_attachment (fp, b, tempfile, 0, 0) != 0) {
1655 if ((tfp = fopen (tempfile, "r")) == NULL) {
1660 while (fgets (buf, sizeof (buf), tfp)) {
1661 if (!m_strncmp("-----BEGIN PGP ", buf, 15)) {
1662 if (!m_strcmp("MESSAGE-----\n", buf + 15))
1664 else if (!m_strcmp("SIGNED MESSAGE-----\n", buf + 15))
1674 /* fix the content type */
1676 mutt_set_parameter ("format", "fixed", &b->parameter);
1677 mutt_set_parameter ("x-action", enc ? "pgp-encrypted" : "pgp-signed",
1683 int pgp_gpgme_check_traditional (FILE * fp, BODY * b, int tagged_only)
1688 for (; b; b = b->next) {
1689 if (is_multipart (b))
1690 rv = (pgp_gpgme_check_traditional (fp, b->parts, tagged_only) || rv);
1691 else if (b->type == TYPETEXT) {
1692 if ((r = mutt_is_application_pgp (b)))
1695 rv = (pgp_check_traditional_one_body (fp, b, tagged_only) || rv);
1703 * Implementation of `application_handler'.
1707 Copy a clearsigned message, and strip the signature and PGP's
1710 XXX - charset handling: We assume that it is safe to do
1711 character set decoding first, dash decoding second here, while
1712 we do it the other way around in the main handler.
1714 (Note that we aren't worse than Outlook & Cie in this, and also
1715 note that we can successfully handle anything produced by any
1716 existing versions of mutt.) */
1718 static void copy_clearsigned (gpgme_data_t data, STATE * s, char *charset)
1720 char buf[HUGE_STRING];
1721 short complete, armor_header;
1726 fname = data_object_to_tempfile (data, &fp);
1732 fc = fgetconv_open (fp, charset, Charset, M_ICONV_HOOK_FROM);
1734 for (complete = 1, armor_header = 1;
1735 fgetconvs (buf, sizeof (buf), fc) != NULL;
1736 complete = strchr (buf, '\n') != NULL) {
1739 state_puts (buf, s);
1743 if (!m_strcmp(buf, "-----BEGIN PGP SIGNATURE-----\n"))
1753 state_puts (s->prefix, s);
1755 if (buf[0] == '-' && buf[1] == ' ')
1756 state_puts (buf + 2, s);
1758 state_puts (buf, s);
1761 fgetconv_close (&fc);
1766 /* Support for classic_application/pgp */
1767 int pgp_gpgme_application_handler (BODY * m, STATE * s)
1769 int needpass = -1, pgp_keyblock = 0;
1773 off_t last_pos, offset;
1774 char buf[HUGE_STRING];
1775 FILE *pgpout = NULL;
1777 gpgme_error_t err = 0;
1778 gpgme_data_t armored_data = NULL;
1780 short maybe_goodsig = 1;
1781 short have_any_sigs = 0;
1783 char body_charset[STRING]; /* Only used for clearsigned messages. */
1785 debug_print (2, ("Entering pgp_application_pgp handler\n"));
1787 /* For clearsigned messages we won't be able to get a character set
1788 but we know that this may only be text thus we assume Latin-1
1790 if (!mutt_get_body_charset (body_charset, sizeof (body_charset), m))
1791 m_strcpy(body_charset, sizeof(body_charset), "iso-8859-1");
1793 fseeko (s->fpin, m->offset, 0);
1794 last_pos = m->offset;
1796 for (bytes = m->length; bytes > 0;) {
1797 if (fgets (buf, sizeof (buf), s->fpin) == NULL)
1800 offset = ftello (s->fpin);
1801 bytes -= (offset - last_pos); /* don't rely on m_strlen(buf) */
1804 if (!m_strncmp("-----BEGIN PGP ", buf, 15)) {
1806 start_pos = last_pos;
1808 if (!m_strcmp("MESSAGE-----\n", buf + 15))
1810 else if (!m_strcmp("SIGNED MESSAGE-----\n", buf + 15)) {
1814 else if (!option (OPTDONTHANDLEPGPKEYS) &&
1815 !m_strcmp("PUBLIC KEY BLOCK-----\n", buf + 15)) {
1820 /* XXX - we may wish to recode here */
1822 state_puts (s->prefix, s);
1823 state_puts (buf, s);
1827 have_any_sigs = (have_any_sigs || (clearsign && (s->flags & M_VERIFY)));
1829 /* Copy PGP material to an data container */
1830 armored_data = create_gpgme_data ();
1831 gpgme_data_write (armored_data, buf, m_strlen(buf));
1832 while (bytes > 0 && fgets (buf, sizeof (buf) - 1, s->fpin) != NULL) {
1833 offset = ftello (s->fpin);
1834 bytes -= (offset - last_pos); /* don't rely on m_strlen(buf) */
1837 gpgme_data_write (armored_data, buf, m_strlen(buf));
1839 if ((needpass && !m_strcmp("-----END PGP MESSAGE-----\n", buf))
1841 && (!m_strcmp("-----END PGP SIGNATURE-----\n", buf)
1842 || !m_strcmp("-----END PGP PUBLIC KEY BLOCK-----\n",
1847 /* Invoke PGP if needed */
1848 if (!clearsign || (s->flags & M_VERIFY)) {
1849 unsigned int sig_stat = 0;
1850 gpgme_data_t plaintext;
1853 plaintext = create_gpgme_data ();
1854 ctx = create_gpgme_context (0);
1857 err = gpgme_op_verify (ctx, armored_data, NULL, plaintext);
1859 err = gpgme_op_decrypt_verify (ctx, armored_data, plaintext);
1860 if (gpg_err_code (err) == GPG_ERR_NO_DATA) {
1861 /* Decrypt verify can't handle signed only messages. */
1862 err = (gpgme_data_seek (armored_data, 0, SEEK_SET) == -1)
1863 ? gpgme_error_from_errno (errno) : 0;
1864 /* Must release plaintext so that we supply an
1865 uninitialized object. */
1866 gpgme_data_release (plaintext);
1867 plaintext = create_gpgme_data ();
1868 err = gpgme_op_verify (ctx, armored_data, NULL, plaintext);
1875 snprintf (errbuf, sizeof (errbuf) - 1,
1876 _("Error: decryption/verification failed: %s\n"),
1877 gpgme_strerror (err));
1878 state_attach_puts (errbuf, s);
1880 else { /* Decryption/Verification succeeded */
1884 /* Check wether signatures have been verified. */
1885 gpgme_verify_result_t verify_result;
1887 verify_result = gpgme_op_verify_result (ctx);
1888 if (verify_result->signatures)
1894 if ((s->flags & M_DISPLAY) && sig_stat) {
1899 state_attach_puts (_("[-- Begin signature "
1900 "information --]\n"), s);
1903 (res = show_one_sig_status (ctx, idx, s)) != -1; idx++) {
1912 state_attach_puts (_("[-- End signature "
1913 "information --]\n\n"), s);
1916 tmpfname = data_object_to_tempfile (plaintext, &pgpout);
1919 state_attach_puts (_("Error: copy data failed\n"), s);
1923 p_delete(&tmpfname);
1926 gpgme_release (ctx);
1930 * Now, copy cleartext to the screen. NOTE - we expect that PGP
1931 * outputs utf-8 cleartext. This may not always be true, but it
1932 * seems to be a reasonable guess.
1935 if (s->flags & M_DISPLAY) {
1937 state_attach_puts (_("[-- BEGIN PGP MESSAGE --]\n\n"), s);
1938 else if (pgp_keyblock)
1939 state_attach_puts (_("[-- BEGIN PGP PUBLIC KEY BLOCK --]\n"), s);
1941 state_attach_puts (_("[-- BEGIN PGP SIGNED MESSAGE --]\n\n"), s);
1945 copy_clearsigned (armored_data, s, body_charset);
1952 fc = fgetconv_open (pgpout, "utf-8", Charset, 0);
1953 while ((c = fgetconv (fc)) != EOF) {
1955 if (c == '\n' && s->prefix)
1956 state_puts (s->prefix, s);
1958 fgetconv_close (&fc);
1961 if (s->flags & M_DISPLAY) {
1962 state_putc ('\n', s);
1964 state_attach_puts (_("[-- END PGP MESSAGE --]\n"), s);
1965 else if (pgp_keyblock)
1966 state_attach_puts (_("[-- END PGP PUBLIC KEY BLOCK --]\n"), s);
1968 state_attach_puts (_("[-- END PGP SIGNED MESSAGE --]\n"), s);
1972 safe_fclose (&pgpout);
1976 /* XXX - we may wish to recode here */
1978 state_puts (s->prefix, s);
1979 state_puts (buf, s);
1983 m->goodsig = (maybe_goodsig && have_any_sigs);
1985 if (needpass == -1) {
1986 state_attach_puts (_("[-- Error: could not find beginning"
1987 " of PGP message! --]\n\n"), s);
1990 debug_print (2, ("Leaving pgp_application_pgp handler\n"));
1995 * Implementation of `encrypted_handler'.
1998 /* MIME handler for pgp/mime encrypted messages. */
1999 int pgp_gpgme_encrypted_handler (BODY * a, STATE * s)
2001 char tempfile[_POSIX_PATH_MAX];
2004 BODY *orig_body = a;
2008 debug_print (2, ("Entering pgp_encrypted handler\n"));
2010 if (!a || a->type != TYPEAPPLICATION || !a->subtype
2011 || ascii_strcasecmp ("pgp-encrypted", a->subtype)
2012 || !a->next || a->next->type != TYPEAPPLICATION || !a->next->subtype
2013 || ascii_strcasecmp ("octet-stream", a->next->subtype)) {
2014 if (s->flags & M_DISPLAY)
2015 state_attach_puts (_("[-- Error: malformed PGP/MIME message! --]\n\n"),
2020 /* Move forward to the application/pgp-encrypted body. */
2023 mutt_mktemp (tempfile);
2024 if (!(fpout = safe_fopen (tempfile, "w+"))) {
2025 if (s->flags & M_DISPLAY)
2026 state_attach_puts (_("[-- Error: could not create temporary file! "
2031 tattach = decrypt_part (a, s, fpout, 0, &is_signed);
2033 tattach->goodsig = is_signed > 0;
2035 if (s->flags & M_DISPLAY)
2036 state_attach_puts (is_signed ?
2038 ("[-- The following data is PGP/MIME signed and encrypted --]\n\n") :
2039 _("[-- The following data is PGP/MIME encrypted --]\n\n"), s);
2042 FILE *savefp = s->fpin;
2045 rc = mutt_body_handler (tattach, s);
2050 * if a multipart/signed is the _only_ sub-part of a
2051 * multipart/encrypted, cache signature verification
2054 if (mutt_is_multipart_signed (tattach) && !tattach->next)
2055 orig_body->goodsig |= tattach->goodsig;
2057 if (s->flags & M_DISPLAY) {
2058 state_puts ("\n", s);
2059 state_attach_puts (is_signed ?
2061 ("[-- End of PGP/MIME signed and encrypted data --]\n")
2062 : _("[-- End of PGP/MIME encrypted data --]\n"), s);
2065 mutt_free_body (&tattach);
2069 mutt_unlink (tempfile);
2070 debug_print (2, ("Leaving pgp_encrypted handler\n"));
2074 /* Support for application/smime */
2075 int smime_gpgme_application_handler (BODY * a, STATE * s)
2077 char tempfile[_POSIX_PATH_MAX];
2083 debug_print (2, ("Entering smime_encrypted handler\n"));
2086 mutt_mktemp (tempfile);
2087 if (!(fpout = safe_fopen (tempfile, "w+"))) {
2088 if (s->flags & M_DISPLAY)
2089 state_attach_puts (_("[-- Error: could not create temporary file! "
2094 tattach = decrypt_part (a, s, fpout, 1, &is_signed);
2096 tattach->goodsig = is_signed > 0;
2098 if (s->flags & M_DISPLAY)
2099 state_attach_puts (is_signed ?
2100 _("[-- The following data is S/MIME signed --]\n\n") :
2101 _("[-- The following data is S/MIME encrypted --]\n\n"), s);
2104 FILE *savefp = s->fpin;
2107 rc = mutt_body_handler (tattach, s);
2112 * if a multipart/signed is the _only_ sub-part of a
2113 * multipart/encrypted, cache signature verification
2116 if (mutt_is_multipart_signed (tattach) && !tattach->next) {
2117 if (!(a->goodsig = tattach->goodsig))
2118 a->warnsig = tattach->warnsig;
2120 else if (tattach->goodsig) {
2122 a->warnsig = tattach->warnsig;
2125 if (s->flags & M_DISPLAY) {
2126 state_puts ("\n", s);
2127 state_attach_puts (is_signed ?
2128 _("[-- End of S/MIME signed data --]\n") :
2129 _("[-- End of S/MIME encrypted data --]\n"), s);
2132 mutt_free_body (&tattach);
2136 mutt_unlink (tempfile);
2137 debug_print (2, ("Leaving smime_encrypted handler\n"));
2143 * Format an entry on the CRYPT key selection menu.
2146 * %k key id %K key id of the principal key
2148 * %a algorithm %A algorithm of the princ. key
2149 * %l length %L length of the princ. key
2150 * %f flags %F flags of the princ. key
2151 * %c capabilities %C capabilities of the princ. key
2152 * %t trust/validity of the key-uid association
2154 * %[...] date of key using strftime(3)
2158 crypt_entry_fmt (char *dest, ssize_t destlen, char op,
2159 const char *src, const char *prefix,
2160 const char *ifstring, const char *elsestring,
2161 unsigned long data, format_flag flags)
2164 crypt_entry_t *entry;
2167 int optional = (flags & M_FORMAT_OPTIONAL);
2168 const char *s = NULL;
2171 entry = (crypt_entry_t *) data;
2174 /* if (isupper ((unsigned char) op)) */
2177 kflags = (key->flags /*| (pkey->flags & KEYFLAG_RESTRICTIONS)
2180 switch (ascii_tolower (op)) {
2184 char buf2[SHORT_STRING], *p;
2200 while (len > 0 && *cp != ']') {
2209 break; /* not enough space */
2219 if (do_locales && Locale)
2220 setlocale (LC_TIME, Locale);
2225 if (key->kobj->subkeys && (key->kobj->subkeys->timestamp > 0))
2226 tt = key->kobj->subkeys->timestamp;
2228 tm = localtime (&tt);
2230 strftime (buf2, sizeof (buf2), dest, tm);
2233 setlocale (LC_TIME, "C");
2235 snprintf (fmt, sizeof (fmt), "%%%ss", prefix);
2236 snprintf (dest, destlen, fmt, buf2);
2243 snprintf (fmt, sizeof (fmt), "%%%sd", prefix);
2244 snprintf (dest, destlen, fmt, entry->num);
2249 /* fixme: we need a way to distinguish between main and subkeys.
2250 Store the idx in entry? */
2251 snprintf (fmt, sizeof (fmt), "%%%ss", prefix);
2252 snprintf (dest, destlen, fmt, crypt_keyid (key));
2257 snprintf (fmt, sizeof (fmt), "%%%ss", prefix);
2258 snprintf (dest, destlen, fmt, key->uid);
2263 snprintf (fmt, sizeof (fmt), "%%%s.3s", prefix);
2264 if (key->kobj->subkeys)
2265 s = gpgme_pubkey_algo_name (key->kobj->subkeys->pubkey_algo);
2268 snprintf (dest, destlen, fmt, s);
2273 snprintf (fmt, sizeof (fmt), "%%%slu", prefix);
2274 if (key->kobj->subkeys)
2275 val = key->kobj->subkeys->length;
2278 snprintf (dest, destlen, fmt, val);
2283 snprintf (fmt, sizeof (fmt), "%%%sc", prefix);
2284 snprintf (dest, destlen, fmt, crypt_flags (kflags));
2286 else if (!(kflags & (KEYFLAG_RESTRICTIONS)))
2291 snprintf (fmt, sizeof (fmt), "%%%ss", prefix);
2292 snprintf (dest, destlen, fmt, crypt_key_abilities (kflags));
2294 else if (!(kflags & (KEYFLAG_ABILITIES)))
2298 if ((kflags & KEYFLAG_ISX509))
2301 gpgme_user_id_t uid = NULL;
2304 for (i = 0, uid = key->kobj->uids; uid && (i < key->idx);
2305 i++, uid = uid->next);
2307 switch (uid->validity) {
2308 case GPGME_VALIDITY_UNDEFINED:
2311 case GPGME_VALIDITY_NEVER:
2314 case GPGME_VALIDITY_MARGINAL:
2317 case GPGME_VALIDITY_FULL:
2320 case GPGME_VALIDITY_ULTIMATE:
2323 case GPGME_VALIDITY_UNKNOWN:
2329 snprintf (fmt, sizeof (fmt), "%%%sc", prefix);
2330 snprintf (dest, destlen, fmt, s ? *s : 'B');
2333 snprintf (fmt, sizeof (fmt), "%%%ss", prefix);
2334 snprintf (dest, destlen, fmt,
2335 gpgme_get_protocol_name (key->kobj->protocol));
2343 mutt_FormatString (dest, destlen, ifstring, mutt_attach_fmt, data, 0);
2344 else if (flags & M_FORMAT_OPTIONAL)
2345 mutt_FormatString (dest, destlen, elsestring, mutt_attach_fmt, data, 0);
2349 /* Used by the display fucntion to format a line. */
2350 static void crypt_entry (char *s, ssize_t l, MUTTMENU * menu, int num)
2352 crypt_key_t **key_table = (crypt_key_t **) menu->data;
2353 crypt_entry_t entry;
2355 entry.key = key_table[num];
2356 entry.num = num + 1;
2358 mutt_FormatString (s, l, NONULL (PgpEntryFormat), crypt_entry_fmt,
2359 (unsigned long) &entry, M_FORMAT_ARROWCURSOR);
2362 /* Compare two addresses and the keyid to be used for sorting. */
2363 static int _crypt_compare_address (const void *a, const void *b)
2365 crypt_key_t **s = (crypt_key_t **) a;
2366 crypt_key_t **t = (crypt_key_t **) b;
2369 if ((r = m_strcasecmp((*s)->uid, (*t)->uid)))
2372 return m_strcasecmp(crypt_keyid (*s), crypt_keyid (*t)) > 0;
2375 static int crypt_compare_address (const void *a, const void *b)
2377 return ((PgpSortKeys & SORT_REVERSE) ? !_crypt_compare_address (a, b)
2378 : _crypt_compare_address (a, b));
2382 /* Compare two key IDs and the addresses to be used for sorting. */
2383 static int _crypt_compare_keyid (const void *a, const void *b)
2385 crypt_key_t **s = (crypt_key_t **) a;
2386 crypt_key_t **t = (crypt_key_t **) b;
2389 if ((r = m_strcasecmp(crypt_keyid (*s), crypt_keyid (*t))))
2392 return m_strcasecmp((*s)->uid, (*t)->uid) > 0;
2395 static int crypt_compare_keyid (const void *a, const void *b)
2397 return ((PgpSortKeys & SORT_REVERSE) ? !_crypt_compare_keyid (a, b)
2398 : _crypt_compare_keyid (a, b));
2401 /* Compare 2 creation dates and the addresses. For sorting. */
2402 static int _crypt_compare_date (const void *a, const void *b)
2404 crypt_key_t **s = (crypt_key_t **) a;
2405 crypt_key_t **t = (crypt_key_t **) b;
2406 unsigned long ts = 0, tt = 0;
2408 if ((*s)->kobj->subkeys && ((*s)->kobj->subkeys->timestamp > 0))
2409 ts = (*s)->kobj->subkeys->timestamp;
2410 if ((*t)->kobj->subkeys && ((*t)->kobj->subkeys->timestamp > 0))
2411 tt = (*t)->kobj->subkeys->timestamp;
2418 return m_strcasecmp((*s)->uid, (*t)->uid) > 0;
2421 static int crypt_compare_date (const void *a, const void *b)
2423 return ((PgpSortKeys & SORT_REVERSE) ? !_crypt_compare_date (a, b)
2424 : _crypt_compare_date (a, b));
2427 /* Compare two trust values, the key length, the creation dates. the
2428 addresses and the key IDs. For sorting. */
2429 static int _crypt_compare_trust (const void *a, const void *b)
2431 crypt_key_t **s = (crypt_key_t **) a;
2432 crypt_key_t **t = (crypt_key_t **) b;
2433 unsigned long ts = 0, tt = 0;
2436 if ((r = (((*s)->flags & (KEYFLAG_RESTRICTIONS))
2437 - ((*t)->flags & (KEYFLAG_RESTRICTIONS)))))
2440 if ((*s)->kobj->uids)
2441 ts = (*s)->kobj->uids->validity;
2442 if ((*t)->kobj->uids)
2443 tt = (*t)->kobj->uids->validity;
2444 if ((r = (tt - ts)))
2447 if ((*s)->kobj->subkeys)
2448 ts = (*s)->kobj->subkeys->length;
2449 if ((*t)->kobj->subkeys)
2450 tt = (*t)->kobj->subkeys->length;
2454 if ((*s)->kobj->subkeys && ((*s)->kobj->subkeys->timestamp > 0))
2455 ts = (*s)->kobj->subkeys->timestamp;
2456 if ((*t)->kobj->subkeys && ((*t)->kobj->subkeys->timestamp > 0))
2457 tt = (*t)->kobj->subkeys->timestamp;
2463 if ((r = m_strcasecmp((*s)->uid, (*t)->uid)))
2465 return (m_strcasecmp(crypt_keyid ((*s)), crypt_keyid ((*t)))) > 0;
2468 static int crypt_compare_trust (const void *a, const void *b)
2470 return ((PgpSortKeys & SORT_REVERSE) ? !_crypt_compare_trust (a, b)
2471 : _crypt_compare_trust (a, b));
2474 /* Print the X.500 Distinguished Name part KEY from the array of parts
2476 static int print_dn_part (FILE * fp, struct dn_array_s *dn, const char *key)
2480 for (; dn->key; dn++) {
2481 if (!m_strcmp(dn->key, key)) {
2484 print_utf8 (fp, dn->value, m_strlen(dn->value));
2491 /* Print all parts of a DN in a standard sequence. */
2492 static void print_dn_parts (FILE * fp, struct dn_array_s *dn)
2494 const char *stdpart[] = {
2495 "CN", "OU", "O", "STREET", "L", "ST", "C", NULL
2497 int any = 0, any2 = 0, i;
2499 for (i = 0; stdpart[i]; i++) {
2502 any = print_dn_part (fp, dn, stdpart[i]);
2504 /* now print the rest without any specific ordering */
2505 for (; dn->key; dn++) {
2506 for (i = 0; stdpart[i]; i++) {
2507 if (!m_strcmp(dn->key, stdpart[i]))
2515 any = print_dn_part (fp, dn, dn->key);
2524 /* Parse an RDN; this is a helper to parse_dn(). */
2525 static const unsigned char *parse_dn_part (struct dn_array_s *array,
2526 const unsigned char *string)
2528 const unsigned char *s, *s1;
2532 /* parse attributeType */
2533 for (s = string + 1; *s && *s != '='; s++);
2535 return NULL; /* error */
2538 return NULL; /* empty key */
2539 array->key = p_dupstr(string, n );
2540 p = (unsigned char *) array->key;
2543 if (*string == '#') { /* hexstring */
2545 for (s = string; hexdigitp (s); s++)
2549 return NULL; /* empty or odd number of digits */
2552 array->value = (char *) p;
2553 for (s1 = string; n; s1 += 2, n--)
2557 else { /* regular v3 quoted string */
2558 for (n = 0, s = string; *s; s++) {
2559 if (*s == '\\') { /* pair */
2561 if (*s == ',' || *s == '=' || *s == '+'
2562 || *s == '<' || *s == '>' || *s == '#' || *s == ';'
2563 || *s == '\\' || *s == '\"' || *s == ' ')
2565 else if (hexdigitp (s) && hexdigitp (s + 1)) {
2570 return NULL; /* invalid escape sequence */
2572 else if (*s == '\"')
2573 return NULL; /* invalid encoding */
2574 else if (*s == ',' || *s == '=' || *s == '+'
2575 || *s == '<' || *s == '>' || *s == '#' || *s == ';')
2582 array->value = (char *) p;
2583 for (s = string; n; s++, n--) {
2586 if (hexdigitp (s)) {
2602 /* Parse a DN and return an array-ized one. This is not a validating
2603 parser and it does not support any old-stylish syntax; gpgme is
2604 expected to return only rfc2253 compatible strings. */
2605 static struct dn_array_s *parse_dn (const unsigned char *string)
2607 struct dn_array_s *array;
2608 ssize_t arrayidx, arraysize;
2611 arraysize = 7; /* C,ST,L,O,OU,CN,email */
2612 array = p_new(struct dn_array_s, arraysize + 1);
2615 while (*string == ' ')
2619 if (arrayidx >= arraysize) { /* mutt lacks a real safe_realoc - so we need to copy */
2620 struct dn_array_s *a2;
2623 a2 = p_new(struct dn_array_s, arraysize + 1);
2624 for (i = 0; i < arrayidx; i++) {
2625 a2[i].key = array[i].key;
2626 a2[i].value = array[i].value;
2631 array[arrayidx].key = NULL;
2632 array[arrayidx].value = NULL;
2633 string = parse_dn_part (array + arrayidx, string);
2637 while (*string == ' ')
2639 if (*string && *string != ',' && *string != ';' && *string != '+')
2640 goto failure; /* invalid delimiter */
2644 array[arrayidx].key = NULL;
2645 array[arrayidx].value = NULL;
2649 for (i = 0; i < arrayidx; i++) {
2650 p_delete(&array[i].key);
2651 p_delete(&array[i].value);
2658 /* Print a nice representation of the USERID and make sure it is
2659 displayed in a proper way, which does mean to reorder some parts
2660 for S/MIME's DNs. USERID is a string as returned by the gpgme key
2661 functions. It is utf-8 encoded. */
2662 static void parse_and_print_user_id (FILE * fp, const char *userid)
2667 if (*userid == '<') {
2668 s = strchr (userid + 1, '>');
2670 print_utf8 (fp, userid + 1, s - userid - 1);
2672 else if (*userid == '(')
2673 fputs (_("[Can't display this user ID (unknown encoding)]"), fp);
2674 else if (!digit_or_letter ((const unsigned char *) userid))
2675 fputs (_("[Can't display this user ID (invalid encoding)]"), fp);
2677 struct dn_array_s *dn = parse_dn ((const unsigned char *) userid);
2680 fputs (_("[Can't display this user ID (invalid DN)]"), fp);
2682 print_dn_parts (fp, dn);
2683 for (i = 0; dn[i].key; i++) {
2684 p_delete(&dn[i].key);
2685 p_delete(&dn[i].value);
2693 KEY_CAP_CAN_ENCRYPT,
2698 static unsigned int key_check_cap (gpgme_key_t key, key_cap_t cap)
2700 gpgme_subkey_t subkey = NULL;
2701 unsigned int ret = 0;
2704 case KEY_CAP_CAN_ENCRYPT:
2705 if (!(ret = key->can_encrypt))
2706 for (subkey = key->subkeys; subkey; subkey = subkey->next)
2707 if ((ret = subkey->can_encrypt))
2710 case KEY_CAP_CAN_SIGN:
2711 if (!(ret = key->can_sign))
2712 for (subkey = key->subkeys; subkey; subkey = subkey->next)
2713 if ((ret = subkey->can_sign))
2716 case KEY_CAP_CAN_CERTIFY:
2717 if (!(ret = key->can_certify))
2718 for (subkey = key->subkeys; subkey; subkey = subkey->next)
2719 if ((ret = subkey->can_certify))
2728 /* Print verbose information about a key or certificate to FP. */
2729 static void print_key_info (gpgme_key_t key, FILE * fp)
2732 const char *s = NULL, *s2 = NULL;
2735 char shortbuf[SHORT_STRING];
2736 unsigned long aval = 0;
2740 gpgme_user_id_t uid = NULL;
2743 setlocale (LC_TIME, Locale);
2745 is_pgp = key->protocol == GPGME_PROTOCOL_OpenPGP;
2747 for (idx = 0, uid = key->uids; uid; idx++, uid = uid->next) {
2752 fputs (idx ? _(" aka ......: ") :_("Name ......: "), fp);
2755 fputs (_("[Invalid]"), fp);
2759 print_utf8 (fp, s, m_strlen(s));
2761 parse_and_print_user_id (fp, s);
2765 if (key->subkeys && (key->subkeys->timestamp > 0)) {
2766 tt = key->subkeys->timestamp;
2768 tm = localtime (&tt);
2769 #ifdef HAVE_LANGINFO_D_T_FMT
2770 strftime (shortbuf, sizeof shortbuf, nl_langinfo (D_T_FMT), tm);
2772 strftime (shortbuf, sizeof shortbuf, "%c", tm);
2774 fprintf (fp, _("Valid From : %s\n"), shortbuf);
2777 if (key->subkeys && (key->subkeys->expires > 0)) {
2778 tt = key->subkeys->expires;
2780 tm = localtime (&tt);
2781 #ifdef HAVE_LANGINFO_D_T_FMT
2782 strftime (shortbuf, sizeof shortbuf, nl_langinfo (D_T_FMT), tm);
2784 strftime (shortbuf, sizeof shortbuf, "%c", tm);
2786 fprintf (fp, _("Valid To ..: %s\n"), shortbuf);
2790 s = gpgme_pubkey_algo_name (key->subkeys->pubkey_algo);
2794 s2 = is_pgp ? "PGP" : "X.509";
2797 aval = key->subkeys->length;
2799 fprintf (fp, _("Key Type ..: %s, %lu bit %s\n"), s2, aval, s);
2801 fprintf (fp, _("Key Usage .: "));
2804 if (key_check_cap (key, KEY_CAP_CAN_ENCRYPT)) {
2805 fprintf (fp, "%s%s", delim, _("encryption"));
2808 if (key_check_cap (key, KEY_CAP_CAN_SIGN)) {
2809 fprintf (fp, "%s%s", delim, _("signing"));
2812 if (key_check_cap (key, KEY_CAP_CAN_CERTIFY)) {
2813 fprintf (fp, "%s%s", delim, _("certification"));
2819 s = key->subkeys->fpr;
2820 fputs (_("Fingerprint: "), fp);
2821 if (is_pgp && m_strlen(s) == 40) {
2822 for (i = 0; *s && s[1] && s[2] && s[3] && s[4]; s += 4, i++) {
2827 putc (is_pgp ? ' ' : ':', fp);
2828 if (is_pgp && i == 4)
2833 for (i = 0; *s && s[1] && s[2]; s += 2, i++) {
2836 putc (is_pgp ? ' ' : ':', fp);
2837 if (is_pgp && i == 7)
2841 fprintf (fp, "%s\n", s);
2844 if (key->issuer_serial) {
2845 s = key->issuer_serial;
2847 fprintf (fp, _("Serial-No .: 0x%s\n"), s);
2850 if (key->issuer_name) {
2851 s = key->issuer_name;
2853 fprintf (fp, _("Issued By .: "));
2854 parse_and_print_user_id (fp, s);
2859 /* For PGP we list all subkeys. */
2861 gpgme_subkey_t subkey = NULL;
2863 for (idx = 1, subkey = key->subkeys; subkey; idx++, subkey = subkey->next) {
2867 if (m_strlen(s) == 16)
2868 s += 8; /* display only the short keyID */
2869 fprintf (fp, _("Subkey ....: 0x%s"), s);
2870 if (subkey->revoked) {
2872 fputs (_("[Revoked]"), fp);
2874 if (subkey->invalid) {
2876 fputs (_("[Invalid]"), fp);
2878 if (subkey->expired) {
2880 fputs (_("[Expired]"), fp);
2882 if (subkey->disabled) {
2884 fputs (_("[Disabled]"), fp);
2888 if (subkey->timestamp > 0) {
2889 tt = subkey->timestamp;
2891 tm = localtime (&tt);
2892 #ifdef HAVE_LANGINFO_D_T_FMT
2893 strftime (shortbuf, sizeof shortbuf, nl_langinfo (D_T_FMT), tm);
2895 strftime (shortbuf, sizeof shortbuf, "%c", tm);
2897 fprintf (fp, _("Valid From : %s\n"), shortbuf);
2900 if (subkey->expires > 0) {
2901 tt = subkey->expires;
2903 tm = localtime (&tt);
2904 #ifdef HAVE_LANGINFO_D_T_FMT
2905 strftime (shortbuf, sizeof shortbuf, nl_langinfo (D_T_FMT), tm);
2907 strftime (shortbuf, sizeof shortbuf, "%c", tm);
2909 fprintf (fp, _("Valid To ..: %s\n"), shortbuf);
2913 s = gpgme_pubkey_algo_name (subkey->pubkey_algo);
2918 aval = subkey->length;
2922 fprintf (fp, _("Key Type ..: %s, %lu bit %s\n"), "PGP", aval, s);
2924 fprintf (fp, _("Key Usage .: "));
2927 if (subkey->can_encrypt) {
2928 fprintf (fp, "%s%s", delim, _("encryption"));
2931 if (subkey->can_sign) {
2932 fprintf (fp, "%s%s", delim, _("signing"));
2935 if (subkey->can_certify) {
2936 fprintf (fp, "%s%s", delim, _("certification"));
2944 setlocale (LC_TIME, "C");
2948 /* Show detailed information about the selected key */
2949 static void verify_key (crypt_key_t * key)
2952 char cmd[LONG_STRING], tempfile[_POSIX_PATH_MAX];
2954 gpgme_ctx_t listctx = NULL;
2956 gpgme_key_t k = NULL;
2959 mutt_mktemp (tempfile);
2960 if (!(fp = safe_fopen (tempfile, "w"))) {
2961 mutt_perror (_("Can't create temporary file"));
2965 mutt_message _("Collecting data...");
2967 print_key_info (key->kobj, fp);
2969 err = gpgme_new (&listctx);
2971 fprintf (fp, "Internal error: can't create gpgme context: %s\n",
2972 gpgme_strerror (err));
2975 if ((key->flags & KEYFLAG_ISX509))
2976 gpgme_set_protocol (listctx, GPGME_PROTOCOL_CMS);
2980 while ((s = k->chain_id) && k->subkeys && m_strcmp(s, k->subkeys->fpr)) {
2982 err = gpgme_op_keylist_start (listctx, s, 0);
2983 gpgme_key_release (k);
2986 err = gpgme_op_keylist_next (listctx, &k);
2988 fprintf (fp, _("Error finding issuer key: %s\n"), gpgme_strerror (err));
2991 gpgme_op_keylist_end (listctx);
2993 print_key_info (k, fp);
2996 fputs (_("Error: certification chain to long - stopping here\n"), fp);
3002 gpgme_key_release (k);
3003 gpgme_release (listctx);
3005 mutt_clear_error ();
3006 snprintf (cmd, sizeof (cmd), _("Key ID: 0x%s"), crypt_keyid (key));
3007 mutt_do_pager (cmd, tempfile, 0, NULL);
3011 * Implementation of `findkeys'.
3015 /* Convert string_list_t into a pattern string suitable to be passed to GPGME.
3016 We need to convert spaces in an item into a '+' and '%' into
3018 static char *list_to_pattern (string_list_t * list)
3026 for (l = list; l; l = l->next) {
3027 for (s = l->data; *s; s++) {
3032 n++; /* delimiter or end of string */
3034 n++; /* make sure to allocate at least one byte */
3035 pattern = p = p_new(char, n);
3036 for (l = list; l; l = l->next) {
3041 for (s = l->data; *s; s++) {
3047 else if (*s == '+') {
3063 /* Return a list of keys which are candidates for the selection.
3064 Select by looking at the HINTS list. */
3065 static crypt_key_t *get_candidates (string_list_t * hints, unsigned int app,
3068 crypt_key_t *db, *k, **kend;
3074 gpgme_user_id_t uid = NULL;
3076 pattern = list_to_pattern (hints);
3080 err = gpgme_new (&ctx);
3082 mutt_error (_("gpgme_new failed: %s"), gpgme_strerror (err));
3090 if ((app & APPLICATION_PGP)) {
3091 /* Its all a mess. That old GPGME expects different things
3092 depending on the protocol. For gpg we don' t need percent
3093 escaped pappert but simple strings passed in an array to the
3094 keylist_ext_start function. */
3099 for (l = hints, n = 0; l; l = l->next) {
3100 if (l->data && *l->data)
3106 patarr = p_new(char *, n + 1);
3107 for (l = hints, n = 0; l; l = l->next) {
3108 if (l->data && *l->data)
3109 patarr[n++] = m_strdup(l->data);
3112 err = gpgme_op_keylist_ext_start (ctx, (const char **) patarr, secret, 0);
3113 for (n = 0; patarr[n]; n++)
3114 p_delete(&patarr[n]);
3117 mutt_error (_("gpgme_op_keylist_start failed: %s"), gpgme_strerror (err));
3118 gpgme_release (ctx);
3123 while (!(err = gpgme_op_keylist_next (ctx, &key))) {
3124 unsigned int flags = 0;
3126 if (key_check_cap (key, KEY_CAP_CAN_ENCRYPT))
3127 flags |= KEYFLAG_CANENCRYPT;
3128 if (key_check_cap (key, KEY_CAP_CAN_SIGN))
3129 flags |= KEYFLAG_CANSIGN;
3131 #if 0 /* DISABLED code */
3133 /* Bug in gpg. Capabilities are not listed for secret
3134 keys. Try to deduce them from the algorithm. */
3136 switch (key->subkeys[0].pubkey_algo) {
3138 flags |= KEYFLAG_CANENCRYPT;
3139 flags |= KEYFLAG_CANSIGN;
3141 case GPGME_PK_ELG_E:
3142 flags |= KEYFLAG_CANENCRYPT;
3145 flags |= KEYFLAG_CANSIGN;
3149 #endif /* DISABLED code */
3151 for (idx = 0, uid = key->uids; uid; idx++, uid = uid->next) {
3152 k = p_new(crypt_key_t, 1);
3161 if (gpg_err_code (err) != GPG_ERR_EOF)
3162 mutt_error (_("gpgme_op_keylist_next failed: %s"), gpgme_strerror (err));
3163 gpgme_op_keylist_end (ctx);
3168 if ((app & APPLICATION_SMIME)) {
3169 /* and now look for x509 certificates */
3170 gpgme_set_protocol (ctx, GPGME_PROTOCOL_CMS);
3171 err = gpgme_op_keylist_start (ctx, pattern, 0);
3173 mutt_error (_("gpgme_op_keylist_start failed: %s"), gpgme_strerror (err));
3174 gpgme_release (ctx);
3179 while (!(err = gpgme_op_keylist_next (ctx, &key))) {
3180 unsigned int flags = KEYFLAG_ISX509;
3182 if (key_check_cap (key, KEY_CAP_CAN_ENCRYPT))
3183 flags |= KEYFLAG_CANENCRYPT;
3184 if (key_check_cap (key, KEY_CAP_CAN_SIGN))
3185 flags |= KEYFLAG_CANSIGN;
3187 for (idx = 0, uid = key->uids; uid; idx++, uid = uid->next) {
3188 k = p_new(crypt_key_t, 1);
3197 if (gpg_err_code (err) != GPG_ERR_EOF)
3198 mutt_error (_("gpgme_op_keylist_next failed: %s"), gpgme_strerror (err));
3199 gpgme_op_keylist_end (ctx);
3202 gpgme_release (ctx);
3207 /* Add the string STR to the list HINTS. This list is later used to
3209 static string_list_t *crypt_add_string_to_hints (string_list_t * hints, const char *str)
3214 if ((scratch = m_strdup(str)) == NULL)
3217 for (t = strtok (scratch, " ,.:\"()<>\n"); t;
3218 t = strtok (NULL, " ,.:\"()<>\n")) {
3219 if (m_strlen(t) > 3)
3220 hints = mutt_add_list(hints, t);
3227 /* Display a menu to select a key from the array KEYS. FORCED_VALID
3228 will be set to true on return if the user did override the the
3230 static crypt_key_t *crypt_select_key (crypt_key_t * keys,
3231 address_t * p, const char *s,
3232 unsigned int app, int *forced_valid)
3235 crypt_key_t **key_table;
3238 char helpstr[SHORT_STRING], buf[LONG_STRING];
3240 int (*f) (const void *, const void *);
3241 int menu_to_use = 0;
3246 /* build the key table */
3249 for (k = keys; k; k = k->next) {
3250 if (!option (OPTPGPSHOWUNUSABLE) && (k->flags & KEYFLAG_CANTUSE)) {
3257 p_realloc(&key_table, keymax);
3263 if (!i && unusable) {
3264 mutt_error _("All matching keys are marked expired/revoked.");
3270 switch (PgpSortKeys & SORT_MASK) {
3272 f = crypt_compare_date;
3275 f = crypt_compare_keyid;
3278 f = crypt_compare_address;
3282 f = crypt_compare_trust;
3285 qsort (key_table, i, sizeof (crypt_key_t *), f);
3287 if (app & APPLICATION_PGP)
3288 menu_to_use = MENU_KEY_SELECT_PGP;
3289 else if (app & APPLICATION_SMIME)
3290 menu_to_use = MENU_KEY_SELECT_SMIME;
3293 mutt_make_help (buf, sizeof (buf), _("Exit "), menu_to_use, OP_EXIT);
3294 strcat (helpstr, buf); /* __STRCAT_CHECKED__ */
3295 mutt_make_help (buf, sizeof (buf), _("Select "), menu_to_use,
3296 OP_GENERIC_SELECT_ENTRY);
3297 strcat (helpstr, buf); /* __STRCAT_CHECKED__ */
3298 mutt_make_help (buf, sizeof (buf), _("Check key "),
3299 menu_to_use, OP_VERIFY_KEY);
3300 strcat (helpstr, buf); /* __STRCAT_CHECKED__ */
3301 mutt_make_help (buf, sizeof (buf), _("Help"), menu_to_use, OP_HELP);
3302 strcat (helpstr, buf); /* __STRCAT_CHECKED__ */
3304 menu = mutt_new_menu ();
3306 menu->make_entry = crypt_entry;
3307 menu->menu = menu_to_use;
3308 menu->help = helpstr;
3309 menu->data = key_table;
3314 if ((app & APPLICATION_PGP) && (app & APPLICATION_SMIME))
3315 ts = _("PGP and S/MIME keys matching");
3316 else if ((app & APPLICATION_PGP))
3317 ts = _("PGP keys matching");
3318 else if ((app & APPLICATION_SMIME))
3319 ts = _("S/MIME keys matching");
3321 ts = _("keys matching");
3324 snprintf (buf, sizeof (buf), _("%s <%s>."), ts, p->mailbox);
3326 snprintf (buf, sizeof (buf), _("%s \"%s\"."), ts, s);
3330 mutt_clear_error ();
3334 switch (mutt_menuLoop (menu)) {
3336 verify_key (key_table[menu->current]);
3337 menu->redraw = REDRAW_FULL;
3341 mutt_message ("%s", key_table[menu->current]->uid);
3344 case OP_GENERIC_SELECT_ENTRY:
3345 /* FIXME make error reporting more verbose - this should be
3346 easy because gpgme provides more information */
3347 if (option (OPTPGPCHECKTRUST)) {
3348 if (!crypt_key_is_valid (key_table[menu->current])) {
3349 mutt_error _("This key can't be used: "
3350 "expired/disabled/revoked.");
3355 if (option (OPTPGPCHECKTRUST) &&
3356 (!crypt_id_is_valid (key_table[menu->current])
3357 || !crypt_id_is_strong (key_table[menu->current]))) {
3359 char buff[LONG_STRING];
3361 if (key_table[menu->current]->flags & KEYFLAG_CANTUSE)
3362 s = N_("ID is expired/disabled/revoked.");
3364 gpgme_validity_t val = GPGME_VALIDITY_UNKNOWN;
3365 gpgme_user_id_t uid = NULL;
3370 uid = key_table[menu->current]->kobj->uids;
3371 for (j = 0; (j < key_table[menu->current]->idx) && uid;
3372 j++, uid = uid->next);
3374 val = uid->validity;
3377 case GPGME_VALIDITY_UNKNOWN:
3378 case GPGME_VALIDITY_UNDEFINED:
3379 warn_s = N_("ID has undefined validity.");
3381 case GPGME_VALIDITY_NEVER:
3382 warn_s = N_("ID is not valid.");
3384 case GPGME_VALIDITY_MARGINAL:
3385 warn_s = N_("ID is only marginally valid.");
3387 case GPGME_VALIDITY_FULL:
3388 case GPGME_VALIDITY_ULTIMATE:
3392 snprintf (buff, sizeof (buff),
3393 _("%s Do you really want to use the key?"), _(warn_s));
3395 if (mutt_yesorno (buff, 0) != 1) {
3396 mutt_clear_error ();
3403 k = crypt_copy_key (key_table[menu->current]);
3414 mutt_menuDestroy (&menu);
3415 p_delete(&key_table);
3417 set_option (OPTNEEDREDRAW);
3422 static crypt_key_t *crypt_getkeybyaddr (address_t * a, short abilities,
3423 unsigned int app, int *forced_valid)
3426 string_list_t *hints = NULL;
3431 int this_key_has_strong;
3432 int this_key_has_weak;
3433 int this_key_has_invalid;
3436 crypt_key_t *keys, *k;
3437 crypt_key_t *the_valid_key = NULL;
3438 crypt_key_t *matches = NULL;
3439 crypt_key_t **matches_endp = &matches;
3443 if (a && a->mailbox)
3444 hints = crypt_add_string_to_hints (hints, a->mailbox);
3445 if (a && a->personal)
3446 hints = crypt_add_string_to_hints (hints, a->personal);
3448 mutt_message (_("Looking for keys matching \"%s\"..."), a->mailbox);
3449 keys = get_candidates (hints, app, (abilities & KEYFLAG_CANSIGN));
3451 string_list_wipe(&hints);
3456 debug_print (5, ("looking for %s <%s>.\n", a->personal, a->mailbox));
3458 for (k = keys; k; k = k->next) {
3459 debug_print (5, (" looking at key: %s `%.15s'\n", crypt_keyid (k), k->uid));
3461 if (abilities && !(k->flags & abilities)) {
3462 debug_print (5, (" insufficient abilities: Has %x, want %x\n", k->flags, abilities));
3466 this_key_has_weak = 0; /* weak but valid match */
3467 this_key_has_invalid = 0; /* invalid match */
3468 this_key_has_strong = 0; /* strong and valid match */
3469 match = 0; /* any match */
3471 r = rfc822_parse_adrlist (NULL, k->uid);
3472 for (p = r; p; p = p->next) {
3473 int validity = crypt_id_matches_addr (a, p, k);
3475 if (validity & CRYPT_KV_MATCH) /* something matches */
3478 /* is this key a strong candidate? */
3479 if ((validity & CRYPT_KV_VALID)
3480 && (validity & CRYPT_KV_STRONGID)
3481 && (validity & CRYPT_KV_ADDR)) {
3482 if (the_valid_key && the_valid_key != k)
3485 this_key_has_strong = 1;
3487 else if ((validity & CRYPT_KV_MATCH)
3488 && !(validity & CRYPT_KV_VALID))
3489 this_key_has_invalid = 1;
3490 else if ((validity & CRYPT_KV_MATCH)
3491 && (!(validity & CRYPT_KV_STRONGID)
3492 || !(validity & CRYPT_KV_ADDR)))
3493 this_key_has_weak = 1;
3495 address_list_wipe(&r);
3500 if (!this_key_has_strong && this_key_has_invalid)
3502 if (!this_key_has_strong && this_key_has_weak)
3505 *matches_endp = tmp = crypt_copy_key (k);
3506 matches_endp = &tmp->next;
3507 the_valid_key = tmp;
3511 crypt_free_key (&keys);
3514 if (the_valid_key && !multi && !weak
3515 && !(invalid && option (OPTPGPSHOWUNUSABLE))) {
3517 * There was precisely one strong match on a valid ID, there
3518 * were no valid keys with weak matches, and we aren't
3519 * interested in seeing invalid keys.
3521 * Proceed without asking the user.
3523 k = crypt_copy_key (the_valid_key);
3527 * Else: Ask the user.
3529 k = crypt_select_key (matches, a, NULL, app, forced_valid);
3531 crypt_free_key (&matches);
3540 static crypt_key_t *crypt_getkeybystr (char *p, short abilities,
3541 unsigned int app, int *forced_valid)
3543 string_list_t *hints = NULL;
3545 crypt_key_t *matches = NULL;
3546 crypt_key_t **matches_endp = &matches;
3550 mutt_message (_("Looking for keys matching \"%s\"..."), p);
3554 hints = crypt_add_string_to_hints (hints, p);
3555 keys = get_candidates (hints, app, (abilities & KEYFLAG_CANSIGN));
3556 string_list_wipe(&hints);
3561 for (k = keys; k; k = k->next) {
3562 if (abilities && !(k->flags & abilities))
3566 debug_print (5, ("matching \"%s\" against " "key %s, \"%s\":\n", p, crypt_keyid (k), k->uid));
3568 if (!*p || !m_strcasecmp(p, crypt_keyid (k))
3569 || (!m_strncasecmp(p, "0x", 2)
3570 && !m_strcasecmp(p + 2, crypt_keyid (k)))
3571 || (option (OPTPGPLONGIDS)
3572 && !m_strncasecmp(p, "0x", 2)
3573 && !m_strcasecmp(p + 2, crypt_keyid (k) + 8))
3574 || m_stristr(k->uid, p)) {
3577 debug_print (5, ("match.\n"));
3579 *matches_endp = tmp = crypt_copy_key (k);
3580 matches_endp = &tmp->next;
3584 crypt_free_key (&keys);
3587 k = crypt_select_key (matches, NULL, p, app, forced_valid);
3588 crypt_free_key (&matches);
3595 /* Display TAG as a prompt to ask for a key. If WHATFOR is not null
3596 use it as default and store it under that label as the next
3597 default. ABILITIES describe the required key abilities (sign,
3598 encrypt) and APP the type of the requested key; ether S/MIME or
3599 PGP. Return a copy of the key or NULL if not found. */
3600 static crypt_key_t *crypt_ask_for_key (char *tag,
3603 unsigned int app, int *forced_valid)
3606 char resp[SHORT_STRING];
3607 struct crypt_cache *l = NULL;
3611 forced_valid = &dummy;
3613 mutt_clear_error ();
3619 for (l = id_defaults; l; l = l->next)
3620 if (!m_strcasecmp(whatfor, l->what)) {
3621 m_strcpy(resp, sizeof(resp), NONULL(l->dflt));
3629 if (mutt_get_field (tag, resp, sizeof (resp), M_CLEAR) != 0)
3634 m_strreplace(&l->dflt, resp);
3636 l = p_new(struct crypt_cache, 1);
3637 l->next = id_defaults;
3639 l->what = m_strdup(whatfor);
3640 l->dflt = m_strdup(resp);
3644 if ((key = crypt_getkeybystr (resp, abilities, app, forced_valid)))
3652 /* This routine attempts to find the keyids of the recipients of a
3653 message. It returns NULL if any of the keys can not be found. */
3654 static char *find_keys (address_t * to, address_t * cc, address_t * bcc,
3657 char *keyID, *keylist = NULL, *t;
3658 ssize_t keylist_size = 0;
3659 ssize_t keylist_used = 0;
3660 address_t *tmp = NULL, *addr = NULL;
3661 address_t **last = &tmp;
3664 crypt_key_t *k_info, *key;
3665 const char *fqdn = mutt_fqdn (1);
3668 *r_application = APPLICATION_PGP | APPLICATION_SMIME;
3671 for (i = 0; i < 3; i++) {
3686 *last = address_list_dup (p);
3688 last = &((*last)->next);
3692 rfc822_qualify (tmp, fqdn);
3694 tmp = mutt_remove_duplicates (tmp);
3696 for (p = tmp; p; p = p->next) {
3697 char buf[LONG_STRING];
3698 int forced_valid = 0;
3703 if ((keyID = mutt_crypt_hook (p)) != NULL) {
3706 snprintf (buf, sizeof (buf), _("Use keyID = \"%s\" for %s?"),
3708 if ((r = mutt_yesorno (buf, M_YES)) == M_YES) {
3709 /* check for e-mail address */
3710 if ((t = strchr (keyID, '@')) &&
3711 (addr = rfc822_parse_adrlist (NULL, keyID))) {
3713 rfc822_qualify (addr, fqdn);
3718 k_info = crypt_getkeybystr (keyID, KEYFLAG_CANENCRYPT,
3719 *r_application, &forced_valid);
3721 k_info = crypt_getkeybystr (keyID, KEYFLAG_CANENCRYPT,
3722 app, &forced_valid);
3728 address_list_wipe(&tmp);
3729 address_list_wipe(&addr);
3735 && (k_info = crypt_getkeybyaddr (q, KEYFLAG_CANENCRYPT,
3736 app, &forced_valid)) == NULL) {
3737 snprintf (buf, sizeof (buf), _("Enter keyID for %s: "), q->mailbox);
3739 if ((key = crypt_ask_for_key (buf, q->mailbox, KEYFLAG_CANENCRYPT,
3745 &forced_valid)) == NULL) {
3747 address_list_wipe(&tmp);
3748 address_list_wipe(&addr);
3756 const char *s = crypt_fpr (key);
3759 if (key->flags & KEYFLAG_ISX509)
3760 *r_application &= ~APPLICATION_PGP;
3761 if (!(key->flags & KEYFLAG_ISX509))
3762 *r_application &= ~APPLICATION_SMIME;
3765 keylist_size += m_strlen(s) + 4 + 1;
3766 p_realloc(&keylist, keylist_size);
3767 sprintf (keylist + keylist_used, "%s0x%s%s", /* __SPRINTF_CHECKED__ */
3768 keylist_used ? " " : "", s, forced_valid ? "!" : "");
3770 keylist_used = m_strlen(keylist);
3772 crypt_free_key (&key);
3773 address_list_wipe(&addr);
3775 address_list_wipe(&tmp);
3779 char *pgp_gpgme_findkeys (address_t * to, address_t * cc, address_t * bcc)
3781 return find_keys (to, cc, bcc, APPLICATION_PGP);
3784 char *smime_gpgme_findkeys (address_t * to, address_t * cc, address_t * bcc)
3786 return find_keys (to, cc, bcc, APPLICATION_SMIME);
3790 * Implementation of `init'.
3793 /* Initialization. */
3794 static void init_gpgme (void)
3796 /* Make sure that gpg-agent is running. */
3797 if (!getenv ("GPG_AGENT_INFO")) {
3798 mutt_error ("\nUsing GPGME backend, although no gpg-agent is running");
3799 if (mutt_any_key_to_continue (NULL) == -1)
3804 void pgp_gpgme_init (void)
3809 void smime_gpgme_init (void)
3813 static int gpgme_send_menu (HEADER * msg, int *redraw, int is_smime)
3816 char input_signas[SHORT_STRING];
3819 if (msg->security & APPLICATION_PGP)
3821 else if (msg->security & APPLICATION_SMIME)
3826 mutt_multi_choice (_
3827 ("S/MIME (e)ncrypt, (s)ign, sign (a)s, (b)oth, (p)gp or (c)lear?"),
3831 mutt_multi_choice (_
3832 ("PGP (e)ncrypt, (s)ign, sign (a)s, (b)oth, s/(m)ime or (c)lear?"),
3836 case 1: /* (e)ncrypt */
3837 msg->security |= (is_smime ? SMIMEENCRYPT : PGPENCRYPT);
3838 msg->security &= ~(is_smime ? SMIMESIGN : PGPSIGN);
3841 case 2: /* (s)ign */
3842 msg->security |= (is_smime ? SMIMESIGN : PGPSIGN);
3843 msg->security &= ~(is_smime ? SMIMEENCRYPT : PGPENCRYPT);
3846 case 3: /* sign (a)s */
3847 /* unset_option(OPTCRYPTCHECKTRUST); */
3848 if ((p = crypt_ask_for_key (_("Sign as: "), NULL, KEYFLAG_CANSIGN,
3849 is_smime ? APPLICATION_SMIME :
3850 APPLICATION_PGP, NULL))) {
3851 snprintf (input_signas, sizeof (input_signas), "0x%s", crypt_keyid (p));
3852 m_strreplace(is_smime ? &SmimeDefaultKey : &PgpSignAs,
3854 crypt_free_key (&p);
3856 msg->security |= (is_smime ? SMIMESIGN : PGPSIGN);
3860 msg->security &= (is_smime ? ~SMIMESIGN : ~PGPSIGN);
3863 *redraw = REDRAW_FULL;
3866 case 4: /* (b)oth */
3868 (is_smime ? (SMIMEENCRYPT | SMIMESIGN) : (PGPENCRYPT | PGPSIGN));
3871 case 5: /* (p)gp or s/(m)ime */
3872 is_smime = !is_smime;
3875 case 6: /* (c)lear */
3880 if (choice == 6 || choice == 7);
3881 else if (is_smime) {
3882 msg->security &= ~APPLICATION_PGP;
3883 msg->security |= APPLICATION_SMIME;
3886 msg->security &= ~APPLICATION_SMIME;
3887 msg->security |= APPLICATION_PGP;
3890 return (msg->security);
3893 int pgp_gpgme_send_menu (HEADER * msg, int *redraw)
3895 return gpgme_send_menu (msg, redraw, 0);
3898 int smime_gpgme_send_menu (HEADER * msg, int *redraw)
3900 return gpgme_send_menu (msg, redraw, 1);
3903 static int verify_sender (HEADER * h, gpgme_protocol_t protocol __attribute__((unused)))
3905 address_t *sender = NULL;
3906 unsigned int ret = 1;
3909 h->env->from = mutt_expand_aliases (h->env->from);
3910 sender = h->env->from;
3912 else if (h->env->sender) {
3913 h->env->sender = mutt_expand_aliases (h->env->sender);
3914 sender = h->env->sender;
3918 if (signature_key) {
3919 gpgme_key_t key = signature_key;
3920 gpgme_user_id_t uid = NULL;
3921 int sender_length = 0;
3924 sender_length = m_strlen(sender->mailbox);
3925 for (uid = key->uids; uid && ret; uid = uid->next) {
3926 uid_length = m_strlen(uid->email);
3927 if (1 && (uid->email[0] == '<')
3928 && (uid->email[uid_length - 1] == '>')
3929 && (uid_length == sender_length + 2)
3930 && (!strncmp (uid->email + 1, sender->mailbox, sender_length)))
3935 mutt_any_key_to_continue ("Failed to verify sender");
3938 mutt_any_key_to_continue ("Failed to figure out sender");
3940 if (signature_key) {
3941 gpgme_key_release (signature_key);
3942 signature_key = NULL;
3948 int smime_gpgme_verify_sender (HEADER * h)
3950 return verify_sender (h, GPGME_PROTOCOL_CMS);