2 * Copyright notice from original mutt:
3 * crypt-gpgme.c - GPGME based crypto operations
4 * Copyright (C) 1996,1997 Michael R. Elkins <me@cs.hmc.edu>
5 * Copyright (C) 1998,1999,2000 Thomas Roessler <roessler@guug.de>
6 * Copyright (C) 2001 Thomas Roessler <roessler@guug.de>
7 * Oliver Ehli <elmy@acm.org>
8 * Copyright (C) 2002, 2003, 2004 g10 Code GmbH
10 * This file is part of mutt-ng, see http://www.muttng.org/.
11 * It's licensed under the GNU General Public License,
12 * please see the file GPL in the top level source directory.
19 #ifdef CRYPT_BACKEND_GPGME
22 #include "mutt_crypt.h"
23 #include "mutt_menu.h"
24 #include "mutt_curses.h"
31 #include "recvattach.h"
37 #include "lib/debug.h"
52 #ifdef HAVE_LANGINFO_D_T_FMT
56 #ifdef HAVE_SYS_TIME_H
57 # include <sys/time.h>
60 #ifdef HAVE_SYS_RESOURCE_H
61 # include <sys/resource.h>
67 #define digitp(p) (*(p) >= '0' && *(p) <= '9')
68 #define hexdigitp(a) (digitp (a) \
69 || (*(a) >= 'A' && *(a) <= 'F') \
70 || (*(a) >= 'a' && *(a) <= 'f'))
71 #define xtoi_1(p) (*(p) <= '9'? (*(p)- '0'): \
72 *(p) <= 'F'? (*(p)-'A'+10):(*(p)-'a'+10))
73 #define xtoi_2(p) ((xtoi_1(p) * 16) + xtoi_1((p)+1))
75 /* Values used for comparing addresses. */
76 #define CRYPT_KV_VALID 1
77 #define CRYPT_KV_ADDR 2
78 #define CRYPT_KV_STRING 4
79 #define CRYPT_KV_STRONGID 8
80 #define CRYPT_KV_MATCH (CRYPT_KV_ADDR|CRYPT_KV_STRING)
89 struct crypt_cache *next;
97 /* We work based on user IDs, getting from a user ID to the key is
98 check and does not need any memory (gpgme uses reference counting). */
99 typedef struct crypt_keyinfo {
100 struct crypt_keyinfo *next;
102 int idx; /* and the user ID at this index */
103 const char *uid; /* and for convenience point to this user ID */
104 unsigned int flags; /* global and per uid flags (for convenience) */
107 typedef struct crypt_entry {
113 static struct crypt_cache *id_defaults = NULL;
114 static gpgme_key_t signature_key = NULL;
117 * General helper functions.
120 /* return true when S points to a didgit or letter. */
121 static int digit_or_letter (const unsigned char *s)
123 return ((*s >= '0' && *s <= '9')
124 || (*s >= 'A' && *s <= 'Z')
125 || (*s >= 'a' && *s <= 'z'));
129 /* Print the utf-8 encoded string BUF of length LEN bytes to stream
130 FP. Convert the character set. */
131 static void print_utf8 (FILE * fp, const char *buf, size_t len)
135 tstr = mem_malloc (len + 1);
136 memcpy (tstr, buf, len);
138 mutt_convert_string (&tstr, "utf-8", Charset, M_ICONV_HOOK_FROM);
148 /* Return the keyID for the key K. Note that this string is valid as
149 long as K is valid */
150 static const char *crypt_keyid (crypt_key_t * k)
152 const char *s = "????????";
154 if (k->kobj && k->kobj->subkeys) {
155 s = k->kobj->subkeys->keyid;
156 if ((!option (OPTPGPLONGIDS)) && (str_len (s) == 16))
157 /* Return only the short keyID. */
164 /* Return the hexstring fingerprint from the key K. */
165 static const char *crypt_fpr (crypt_key_t * k)
169 if (k->kobj && k->kobj->subkeys)
170 s = k->kobj->subkeys->fpr;
175 /* Parse FLAGS and return a statically allocated(!) string with them. */
176 static char *crypt_key_abilities (int flags)
180 if (!(flags & KEYFLAG_CANENCRYPT))
182 else if (flags & KEYFLAG_PREFER_SIGNING)
187 if (!(flags & KEYFLAG_CANSIGN))
189 else if (flags & KEYFLAG_PREFER_ENCRYPTION)
199 /* Parse FLAGS and return a character describing the most important flag. */
200 static char crypt_flags (int flags)
202 if (flags & KEYFLAG_REVOKED)
204 else if (flags & KEYFLAG_EXPIRED)
206 else if (flags & KEYFLAG_DISABLED)
208 else if (flags & KEYFLAG_CRITICAL)
214 /* Return a copy of KEY. */
215 static crypt_key_t *crypt_copy_key (crypt_key_t * key)
219 k = mem_calloc (1, sizeof *k);
221 gpgme_key_ref (key->kobj);
224 k->flags = key->flags;
229 /* Release all the keys at the address of KEYLIST and set the address
231 static void crypt_free_key (crypt_key_t ** keylist)
234 crypt_key_t *k = (*keylist)->next;
241 /* Return trute when key K is valid. */
242 static int crypt_key_is_valid (crypt_key_t * k)
244 if (k->flags & KEYFLAG_CANTUSE)
249 /* Return true whe validity of KEY is sufficient. */
250 static int crypt_id_is_strong (crypt_key_t * key)
252 gpgme_validity_t val = GPGME_VALIDITY_UNKNOWN;
253 gpgme_user_id_t uid = NULL;
254 unsigned int is_strong = 0;
257 if ((key->flags & KEYFLAG_ISX509))
260 for (i = 0, uid = key->kobj->uids; (i < key->idx) && uid;
261 i++, uid = uid->next);
266 case GPGME_VALIDITY_UNKNOWN:
267 case GPGME_VALIDITY_UNDEFINED:
268 case GPGME_VALIDITY_NEVER:
269 case GPGME_VALIDITY_MARGINAL:
273 case GPGME_VALIDITY_FULL:
274 case GPGME_VALIDITY_ULTIMATE:
282 /* Return true when the KEY is valid, i.e. not marked as unusable. */
283 static int crypt_id_is_valid (crypt_key_t * key)
285 return !(key->flags & KEYFLAG_CANTUSE);
288 /* Return a bit vector describing how well the addresses ADDR and
289 U_ADDR match and whether KEY is valid. */
290 static int crypt_id_matches_addr (ADDRESS * addr, ADDRESS * u_addr,
295 if (crypt_id_is_valid (key))
296 rv |= CRYPT_KV_VALID;
298 if (crypt_id_is_strong (key))
299 rv |= CRYPT_KV_STRONGID;
301 if (addr->mailbox && u_addr->mailbox
302 && str_casecmp (addr->mailbox, u_addr->mailbox) == 0)
305 if (addr->personal && u_addr->personal
306 && str_casecmp (addr->personal, u_addr->personal) == 0)
307 rv |= CRYPT_KV_STRING;
314 * GPGME convenient functions.
317 /* Create a new gpgme context and return it. With FOR_SMIME set to
318 true, the protocol of the context is set to CMS. */
319 static gpgme_ctx_t create_gpgme_context (int for_smime)
324 err = gpgme_new (&ctx);
326 mutt_error (_("error creating gpgme context: %s\n"), gpgme_strerror (err));
332 err = gpgme_set_protocol (ctx, GPGME_PROTOCOL_CMS);
334 mutt_error (_("error enabling CMS protocol: %s\n"), gpgme_strerror (err));
343 /* Create a new gpgme data object. This is a wrapper to die on
345 static gpgme_data_t create_gpgme_data (void)
350 err = gpgme_data_new (&data);
352 mutt_error (_("error creating gpgme data object: %s\n"),
353 gpgme_strerror (err));
360 /* Create a new GPGME Data object from the mail body A. With CONVERT
361 passed as true, the lines are converted to CR,LF if required.
362 Return NULL on error or the gpgme_data_t object on success. */
363 static gpgme_data_t body_to_data_object (BODY * a, int convert)
365 char tempfile[_POSIX_PATH_MAX];
370 mutt_mktemp (tempfile);
371 fptmp = safe_fopen (tempfile, "w+");
373 mutt_perror (tempfile);
377 mutt_write_mime_header (a, fptmp);
379 mutt_write_mime_body (a, fptmp);
383 unsigned char buf[1];
385 data = create_gpgme_data ();
387 while ((c = fgetc (fptmp)) != EOF) {
391 if (c == '\n' && !hadcr) {
393 gpgme_data_write (data, buf, 1);
398 /* FIXME: This is quite suboptimal */
400 gpgme_data_write (data, buf, 1);
403 gpgme_data_seek (data, 0, SEEK_SET);
407 err = gpgme_data_new_from_file (&data, tempfile, 1);
411 mutt_error (_("error allocating data object: %s\n"), gpgme_strerror (err));
418 /* Create a GPGME data object from the stream FP but limit the object
419 to LENGTH bytes starting at OFFSET bytes from the beginning of the
421 static gpgme_data_t file_to_data_object (FILE * fp, long offset, long length)
426 err = gpgme_data_new_from_filepart (&data, NULL, fp, offset, length);
428 mutt_error (_("error allocating data object: %s\n"), gpgme_strerror (err));
435 /* Write a GPGME data object to the stream FP. */
436 static int data_object_to_stream (gpgme_data_t data, FILE * fp)
442 err = ((gpgme_data_seek (data, 0, SEEK_SET) == -1)
443 ? gpgme_error_from_errno (errno) : 0);
445 mutt_error (_("error rewinding data object: %s\n"), gpgme_strerror (err));
449 while ((nread = gpgme_data_read (data, buf, sizeof (buf)))) {
450 /* fixme: we are not really converting CRLF to LF but just
451 skipping CR. Doing it correctly needs a more complex logic */
452 for (p = buf; nread; p++, nread--) {
458 mutt_perror ("[tempfile]");
463 mutt_error (_("error reading data object: %s\n"), strerror (errno));
469 /* Copy a data object to a newly created temporay file and return that
470 filename. Caller must free. With RET_FP not NULL, don't close the
471 stream but return it there. */
472 static char *data_object_to_tempfile (gpgme_data_t data, FILE ** ret_fp)
475 char tempfile[_POSIX_PATH_MAX];
479 mutt_mktemp (tempfile);
480 fp = safe_fopen (tempfile, "w+");
482 mutt_perror (tempfile);
486 err = ((gpgme_data_seek (data, 0, SEEK_SET) == -1)
487 ? gpgme_error_from_errno (errno) : 0);
491 while ((nread = gpgme_data_read (data, buf, sizeof (buf)))) {
492 if (fwrite (buf, nread, 1, fp) != 1) {
493 mutt_perror (tempfile);
505 mutt_error (_("error reading data object: %s\n"), gpgme_strerror (err));
512 return str_dup (tempfile);
516 /* Create a GpgmeRecipientSet from the keys in the string KEYLIST.
517 The keys must be space delimited. */
518 static gpgme_key_t *create_recipient_set (const char *keylist,
519 gpgme_protocol_t protocol)
525 gpgme_key_t *rset = NULL;
526 unsigned int rset_n = 0;
527 gpgme_key_t key = NULL;
528 gpgme_ctx_t context = NULL;
530 err = gpgme_new (&context);
532 err = gpgme_set_protocol (context, protocol);
539 for (i = 0; *s && *s != ' ' && i < sizeof (buf) - 1;)
543 if (i > 1 && buf[i - 1] == '!') {
544 /* The user selected to override the valididy of that
548 err = gpgme_get_key (context, buf, &key, 0);
550 key->uids->validity = GPGME_VALIDITY_FULL;
554 err = gpgme_get_key (context, buf, &key, 0);
557 mem_realloc (&rset, sizeof (*rset) * (rset_n + 1));
558 rset[rset_n++] = key;
561 mutt_error (_("error adding recipient `%s': %s\n"),
562 buf, gpgme_strerror (err));
570 /* NULL terminate. */
571 mem_realloc (&rset, sizeof (*rset) * (rset_n + 1));
572 rset[rset_n++] = NULL;
575 gpgme_release (context);
581 /* Make sure that the correct signer is set. Returns 0 on success. */
582 static int set_signer (gpgme_ctx_t ctx, int for_smime)
584 char *signid = for_smime ? SmimeDefaultKey : PgpSignAs;
587 gpgme_key_t key, key2;
589 if (!signid || !*signid)
592 listctx = create_gpgme_context (for_smime);
593 err = gpgme_op_keylist_start (listctx, signid, 1);
595 err = gpgme_op_keylist_next (listctx, &key);
597 gpgme_release (listctx);
598 mutt_error (_("secret key `%s' not found: %s\n"),
599 signid, gpgme_strerror (err));
602 err = gpgme_op_keylist_next (listctx, &key2);
604 gpgme_key_release (key);
605 gpgme_key_release (key2);
606 gpgme_release (listctx);
607 mutt_error (_("ambiguous specification of secret key `%s'\n"), signid);
610 gpgme_op_keylist_end (listctx);
611 gpgme_release (listctx);
613 gpgme_signers_clear (ctx);
614 err = gpgme_signers_add (ctx, key);
615 gpgme_key_release (key);
617 mutt_error (_("error setting secret key `%s': %s\n"),
618 signid, gpgme_strerror (err));
625 /* Encrypt the gpgme data object PLAINTEXT to the recipients in RSET
626 and return an allocated filename to a temporary file containing the
627 enciphered text. With USE_SMIME set to true, the smime backend is
628 used. With COMBINED_SIGNED a PGP message is signed and
629 encrypted. Returns NULL in case of error */
630 static char *encrypt_gpgme_object (gpgme_data_t plaintext, gpgme_key_t * rset,
631 int use_smime, int combined_signed)
635 gpgme_data_t ciphertext;
638 ctx = create_gpgme_context (use_smime);
640 gpgme_set_armor (ctx, 1);
642 ciphertext = create_gpgme_data ();
644 if (combined_signed) {
645 if (set_signer (ctx, use_smime)) {
646 gpgme_data_release (ciphertext);
650 err = gpgme_op_encrypt_sign (ctx, rset, GPGME_ENCRYPT_ALWAYS_TRUST,
651 plaintext, ciphertext);
654 err = gpgme_op_encrypt (ctx, rset, GPGME_ENCRYPT_ALWAYS_TRUST,
655 plaintext, ciphertext);
656 mutt_need_hard_redraw ();
658 mutt_error (_("error encrypting data: %s\n"), gpgme_strerror (err));
659 gpgme_data_release (ciphertext);
666 outfile = data_object_to_tempfile (ciphertext, NULL);
667 gpgme_data_release (ciphertext);
671 /* Find the "micalg" parameter from the last Gpgme operation on
672 context CTX. It is expected that this operation was a sign
673 operation. Return the algorithm name as a C string in buffer BUF
674 which must have been allocated by the caller with size BUFLEN.
675 Returns 0 on success or -1 in case of an error. The return string
676 is truncted to BUFLEN - 1. */
677 static int get_micalg (gpgme_ctx_t ctx, char *buf, size_t buflen)
679 gpgme_sign_result_t result = NULL;
680 const char *algorithm_name = NULL;
686 result = gpgme_op_sign_result (ctx);
688 algorithm_name = gpgme_hash_algo_name (result->signatures->hash_algo);
689 if (algorithm_name) {
690 strncpy (buf, algorithm_name, buflen - 1);
695 return *buf ? 0 : -1;
698 static void print_time (time_t t, STATE * s)
702 setlocale (LC_TIME, "");
703 #ifdef HAVE_LANGINFO_D_T_FMT
704 strftime (p, sizeof (p), nl_langinfo (D_T_FMT), localtime (&t));
706 strftime (p, sizeof (p), "%c", localtime (&t));
708 setlocale (LC_TIME, "C");
709 state_attach_puts (p, s);
713 * Implementation of `sign_message'.
716 /* Sign the MESSAGE in body A either using OpenPGP or S/MIME when
717 USE_SMIME is passed as true. Returns the new body or NULL on
719 static BODY *sign_message (BODY * a, int use_smime)
726 gpgme_data_t message, signature;
728 convert_to_7bit (a); /* Signed data _must_ be in 7-bit format. */
730 message = body_to_data_object (a, 1);
733 signature = create_gpgme_data ();
735 ctx = create_gpgme_context (use_smime);
737 gpgme_set_armor (ctx, 1);
739 if (set_signer (ctx, use_smime)) {
740 gpgme_data_release (signature);
745 err = gpgme_op_sign (ctx, message, signature, GPGME_SIG_MODE_DETACH);
746 mutt_need_hard_redraw ();
747 gpgme_data_release (message);
749 gpgme_data_release (signature);
751 mutt_error (_("error signing data: %s\n"), gpgme_strerror (err));
755 sigfile = data_object_to_tempfile (signature, NULL);
756 gpgme_data_release (signature);
762 t = mutt_new_body ();
763 t->type = TYPEMULTIPART;
764 t->subtype = str_dup ("signed");
765 t->encoding = ENC7BIT;
767 t->disposition = DISPINLINE;
769 mutt_generate_boundary (&t->parameter);
770 mutt_set_parameter ("protocol",
771 use_smime ? "application/pkcs7-signature"
772 : "application/pgp-signature", &t->parameter);
773 /* Get the micalg from gpgme. Old gpgme versions don't support this
774 for S/MIME so we assume sha-1 in this case. */
775 if (!get_micalg (ctx, buf, sizeof buf))
776 mutt_set_parameter ("micalg", buf, &t->parameter);
778 mutt_set_parameter ("micalg", "sha1", &t->parameter);
784 t->parts->next = mutt_new_body ();
786 t->type = TYPEAPPLICATION;
788 t->subtype = str_dup ("pkcs7-signature");
789 mutt_set_parameter ("name", "smime.p7s", &t->parameter);
790 t->encoding = ENCBASE64;
792 t->disposition = DISPATTACH;
793 t->d_filename = str_dup ("smime.p7s");
796 t->subtype = str_dup ("pgp-signature");
798 t->disposition = DISPINLINE;
799 t->encoding = ENC7BIT;
801 t->filename = sigfile;
802 t->unlink = 1; /* ok to remove this file after sending. */
808 BODY *pgp_gpgme_sign_message (BODY * a)
810 return sign_message (a, 0);
813 BODY *smime_gpgme_sign_message (BODY * a)
815 return sign_message (a, 1);
819 * Implementation of `encrypt_message'.
822 /* Encrypt the mail body A to all keys given as space separated keyids
823 or fingerprints in KEYLIST and return the encrypted body. */
824 BODY *pgp_gpgme_encrypt_message (BODY * a, char *keylist, int sign)
826 char *outfile = NULL;
828 gpgme_key_t *rset = NULL;
829 gpgme_data_t plaintext;
831 rset = create_recipient_set (keylist, GPGME_PROTOCOL_OpenPGP);
837 plaintext = body_to_data_object (a, 0);
843 outfile = encrypt_gpgme_object (plaintext, rset, 0, sign);
844 gpgme_data_release (plaintext);
849 t = mutt_new_body ();
850 t->type = TYPEMULTIPART;
851 t->subtype = str_dup ("encrypted");
852 t->encoding = ENC7BIT;
854 t->disposition = DISPINLINE;
856 mutt_generate_boundary (&t->parameter);
857 mutt_set_parameter ("protocol", "application/pgp-encrypted", &t->parameter);
859 t->parts = mutt_new_body ();
860 t->parts->type = TYPEAPPLICATION;
861 t->parts->subtype = str_dup ("pgp-encrypted");
862 t->parts->encoding = ENC7BIT;
864 t->parts->next = mutt_new_body ();
865 t->parts->next->type = TYPEAPPLICATION;
866 t->parts->next->subtype = str_dup ("octet-stream");
867 t->parts->next->encoding = ENC7BIT;
868 t->parts->next->filename = outfile;
869 t->parts->next->use_disp = 1;
870 t->parts->next->disposition = DISPINLINE;
871 t->parts->next->unlink = 1; /* delete after sending the message */
872 t->parts->next->d_filename = str_dup ("msg.asc"); /* non pgp/mime
879 * Implementation of `smime_build_smime_entity'.
882 /* Encrypt the mail body A to all keys given as space separated
883 fingerprints in KEYLIST and return the S/MIME encrypted body. */
884 BODY *smime_gpgme_build_smime_entity (BODY * a, char *keylist)
886 char *outfile = NULL;
888 gpgme_key_t *rset = NULL;
889 gpgme_data_t plaintext;
891 rset = create_recipient_set (keylist, GPGME_PROTOCOL_CMS);
895 plaintext = body_to_data_object (a, 0);
901 outfile = encrypt_gpgme_object (plaintext, rset, 1, 0);
902 gpgme_data_release (plaintext);
907 t = mutt_new_body ();
908 t->type = TYPEAPPLICATION;
909 t->subtype = str_dup ("pkcs7-mime");
910 mutt_set_parameter ("name", "smime.p7m", &t->parameter);
911 mutt_set_parameter ("smime-type", "enveloped-data", &t->parameter);
912 t->encoding = ENCBASE64; /* The output of OpenSSL SHOULD be binary */
914 t->disposition = DISPATTACH;
915 t->d_filename = str_dup ("smime.p7m");
916 t->filename = outfile;
917 t->unlink = 1; /*delete after sending the message */
926 * Implementation of `verify_one'.
929 /* Display the common attributes of the signature summary SUM.
930 Return 1 if there is is a severe warning.
932 static int show_sig_summary (unsigned long sum,
933 gpgme_ctx_t ctx, gpgme_key_t key, int idx,
938 if ((sum & GPGME_SIGSUM_KEY_REVOKED)) {
939 state_attach_puts (_("Warning: One of the keys has been revoked\n"), s);
943 if ((sum & GPGME_SIGSUM_KEY_EXPIRED)) {
944 time_t at = key->subkeys->expires ? key->subkeys->expires : 0;
947 state_attach_puts (_("Warning: The key used to create the "
948 "signature expired at: "), s);
950 state_attach_puts ("\n", s);
953 state_attach_puts (_("Warning: At least one certification key "
954 "has expired\n"), s);
957 if ((sum & GPGME_SIGSUM_SIG_EXPIRED)) {
958 gpgme_verify_result_t result;
959 gpgme_signature_t sig;
962 result = gpgme_op_verify_result (ctx);
964 for (sig = result->signatures, i = 0; sig && (i < idx);
965 sig = sig->next, i++);
967 state_attach_puts (_("Warning: The signature expired at: "), s);
968 print_time (sig ? sig->exp_timestamp : 0, s);
969 state_attach_puts ("\n", s);
972 if ((sum & GPGME_SIGSUM_KEY_MISSING))
973 state_attach_puts (_("Can't verify due to a missing "
974 "key or certificate\n"), s);
976 if ((sum & GPGME_SIGSUM_CRL_MISSING)) {
977 state_attach_puts (_("The CRL is not available\n"), s);
981 if ((sum & GPGME_SIGSUM_CRL_TOO_OLD)) {
982 state_attach_puts (_("Available CRL is too old\n"), s);
986 if ((sum & GPGME_SIGSUM_BAD_POLICY))
987 state_attach_puts (_("A policy requirement was not met\n"), s);
989 if ((sum & GPGME_SIGSUM_SYS_ERROR)) {
990 const char *t0 = NULL, *t1 = NULL;
991 gpgme_verify_result_t result;
992 gpgme_signature_t sig;
995 state_attach_puts (_("A system error occurred"), s);
997 /* Try to figure out some more detailed system error information. */
998 result = gpgme_op_verify_result (ctx);
999 for (sig = result->signatures, i = 0; sig && (i < idx);
1000 sig = sig->next, i++);
1003 t1 = sig->wrong_key_usage ? "Wrong_Key_Usage" : "";
1007 state_attach_puts (": ", s);
1009 state_attach_puts (t0, s);
1010 if (t1 && !(t0 && !str_cmp (t0, t1))) {
1012 state_attach_puts (",", s);
1013 state_attach_puts (t1, s);
1016 state_attach_puts ("\n", s);
1023 static void show_fingerprint (gpgme_key_t key, STATE * state)
1028 const char *prefix = _("Fingerprint: ");
1032 s = key->subkeys ? key->subkeys->fpr : NULL;
1035 is_pgp = (key->protocol == GPGME_PROTOCOL_OpenPGP);
1037 buf = mem_malloc (str_len (prefix) + str_len (s) * 4 + 2);
1038 strcpy (buf, prefix); /* __STRCPY_CHECKED__ */
1039 p = buf + str_len (buf);
1040 if (is_pgp && str_len (s) == 40) { /* PGP v4 style formatted. */
1041 for (i = 0; *s && s[1] && s[2] && s[3] && s[4]; s += 4, i++) {
1052 for (i = 0; *s && s[1] && s[2]; s += 2, i++) {
1055 *p++ = is_pgp ? ' ' : ':';
1056 if (is_pgp && i == 7)
1061 /* just in case print remaining odd digits */
1066 state_attach_puts (buf, state);
1070 /* Show the valididy of a key used for one signature. */
1071 static void show_one_sig_validity (gpgme_ctx_t ctx, int idx, STATE * s)
1073 gpgme_verify_result_t result = NULL;
1074 gpgme_signature_t sig = NULL;
1075 const char *txt = NULL;
1077 result = gpgme_op_verify_result (ctx);
1079 for (sig = result->signatures; sig && (idx > 0); sig = sig->next, idx--);
1081 switch (sig ? sig->validity : 0) {
1082 case GPGME_VALIDITY_UNKNOWN:
1083 txt = _("WARNING: We have NO indication whether "
1084 "the key belongs to the person named " "as shown above\n");
1086 case GPGME_VALIDITY_UNDEFINED:
1088 case GPGME_VALIDITY_NEVER:
1089 txt = _("WARNING: The key does NOT BELONG to "
1090 "the person named as shown above\n");
1092 case GPGME_VALIDITY_MARGINAL:
1093 txt = _("WARNING: It is NOT certain that the key "
1094 "belongs to the person named as shown above\n");
1096 case GPGME_VALIDITY_FULL:
1097 case GPGME_VALIDITY_ULTIMATE:
1102 state_attach_puts (txt, s);
1105 /* Show information about one signature. This fucntion is called with
1106 the context CTX of a sucessful verification operation and the
1107 enumerator IDX which should start at 0 and incremete for each
1110 Return values are: 0 for normal procession, 1 for a bad signature,
1111 2 for a signature with a warning or -1 for no more signature. */
1112 static int show_one_sig_status (gpgme_ctx_t ctx, int idx, STATE * s)
1115 const char *fpr, *uid;
1116 gpgme_key_t key = NULL;
1117 int i, anybad = 0, anywarn = 0;
1119 gpgme_user_id_t uids = NULL;
1120 gpgme_verify_result_t result;
1121 gpgme_signature_t sig;
1122 gpgme_error_t err = GPG_ERR_NO_ERROR;
1124 result = gpgme_op_verify_result (ctx);
1126 /* FIXME: this code should use a static variable and remember
1127 the current position in the list of signatures, IMHO.
1130 for (i = 0, sig = result->signatures; sig && (i < idx);
1131 i++, sig = sig->next);
1133 return -1; /* Signature not found. */
1135 if (signature_key) {
1136 gpgme_key_release (signature_key);
1137 signature_key = NULL;
1140 created = sig->timestamp;
1144 if (gpg_err_code (sig->status) != GPG_ERR_NO_ERROR)
1147 err = gpgme_get_key (ctx, fpr, &key, 0); /* secret key? */
1149 uid = (key->uids && key->uids->uid) ? key->uids->uid : "[?]";
1151 signature_key = key;
1154 key = NULL; /* Old gpgme versions did not set KEY to NULL on
1155 error. Do it here to avoid a double free. */
1159 if (!s || !s->fpout || !(s->flags & M_DISPLAY)); /* No state information so no way to print anything. */
1161 state_attach_puts (_("Error getting key information: "), s);
1162 state_attach_puts (gpg_strerror (err), s);
1163 state_attach_puts ("\n", s);
1166 else if ((sum & GPGME_SIGSUM_GREEN)) {
1167 state_attach_puts (_("Good signature from: "), s);
1168 state_attach_puts (uid, s);
1169 state_attach_puts ("\n", s);
1170 for (i = 1, uids = key->uids; uids; i++, uids = uids->next) {
1172 /* Skip primary UID. */
1176 state_attach_puts (_(" aka: "), s);
1177 state_attach_puts (uids->uid, s);
1178 state_attach_puts ("\n", s);
1180 state_attach_puts (_(" created: "), s);
1181 print_time (created, s);
1182 state_attach_puts ("\n", s);
1183 if (show_sig_summary (sum, ctx, key, idx, s))
1185 show_one_sig_validity (ctx, idx, s);
1187 else if ((sum & GPGME_SIGSUM_RED)) {
1188 state_attach_puts (_("*BAD* signature claimed to be from: "), s);
1189 state_attach_puts (uid, s);
1190 state_attach_puts ("\n", s);
1191 show_sig_summary (sum, ctx, key, idx, s);
1193 else if (!anybad && key && (key->protocol == GPGME_PROTOCOL_OpenPGP)) { /* We can't decide (yellow) but this is a PGP key with a good
1194 signature, so we display what a PGP user expects: The name,
1195 fingerprint and the key validity (which is neither fully or
1197 state_attach_puts (_("Good signature from: "), s);
1198 state_attach_puts (uid, s);
1199 state_attach_puts ("\n", s);
1200 state_attach_puts (_(" created: "), s);
1201 print_time (created, s);
1202 state_attach_puts ("\n", s);
1203 show_one_sig_validity (ctx, idx, s);
1204 show_fingerprint (key, s);
1205 if (show_sig_summary (sum, ctx, key, idx, s))
1208 else { /* can't decide (yellow) */
1210 state_attach_puts (_("Error checking signature"), s);
1211 state_attach_puts ("\n", s);
1212 show_sig_summary (sum, ctx, key, idx, s);
1215 if (key != signature_key)
1216 gpgme_key_release (key);
1219 return anybad ? 1 : anywarn ? 2 : 0;
1222 /* Do the actual verification step. With IS_SMIME set to true we
1223 assume S/MIME (surprise!) */
1224 static int verify_one (BODY * sigbdy, STATE * s,
1225 const char *tempfile, int is_smime)
1231 gpgme_data_t signature, message;
1233 signature = file_to_data_object (s->fpin, sigbdy->offset, sigbdy->length);
1237 /* We need to tell gpgme about the encoding because the backend can't
1238 auto-detect plain base-64 encoding which is used by S/MIME. */
1240 gpgme_data_set_encoding (signature, GPGME_DATA_ENCODING_BASE64);
1242 err = gpgme_data_new_from_file (&message, tempfile, 1);
1244 gpgme_data_release (signature);
1245 mutt_error (_("error allocating data object: %s\n"), gpgme_strerror (err));
1248 ctx = create_gpgme_context (is_smime);
1250 /* Note: We don't need a current time output because GPGME avoids
1251 such an attack by separating the meta information from the
1253 state_attach_puts (_("[-- Begin signature information --]\n"), s);
1255 err = gpgme_op_verify (ctx, signature, message, NULL);
1256 mutt_need_hard_redraw ();
1260 snprintf (buf, sizeof (buf) - 1,
1261 _("Error: verification failed: %s\n"), gpgme_strerror (err));
1262 state_attach_puts (buf, s);
1264 else { /* Verification succeeded, see what the result is. */
1268 if (signature_key) {
1269 gpgme_key_release (signature_key);
1270 signature_key = NULL;
1273 for (idx = 0; (res = show_one_sig_status (ctx, idx, s)) != -1; idx++) {
1284 gpgme_verify_result_t result;
1285 gpgme_sig_notation_t notation;
1286 gpgme_signature_t signature;
1288 result = gpgme_op_verify_result (ctx);
1290 for (signature = result->signatures; signature;
1291 signature = signature->next) {
1292 if (signature->notations) {
1293 state_attach_puts ("*** Begin Notation (signature by: ", s);
1294 state_attach_puts (signature->fpr, s);
1295 state_attach_puts (") ***\n", s);
1296 for (notation = signature->notations; notation;
1297 notation = notation->next) {
1298 if (notation->name) {
1299 state_attach_puts (notation->name, s);
1300 state_attach_puts ("=", s);
1302 if (notation->value) {
1303 state_attach_puts (notation->value, s);
1304 if (!(*notation->value
1305 && (notation->value[str_len (notation->value) - 1] ==
1307 state_attach_puts ("\n", s);
1310 state_attach_puts ("*** End Notation ***\n", s);
1316 gpgme_release (ctx);
1318 state_attach_puts (_("[-- End signature information --]\n\n"), s);
1319 debug_print (1, ("returning %d.\n", badsig));
1321 return badsig ? 1 : anywarn ? 2 : 0;
1324 int pgp_gpgme_verify_one (BODY * sigbdy, STATE * s, const char *tempfile)
1326 return verify_one (sigbdy, s, tempfile, 0);
1329 int smime_gpgme_verify_one (BODY * sigbdy, STATE * s, const char *tempfile)
1331 return verify_one (sigbdy, s, tempfile, 1);
1335 * Implementation of `decrypt_part'.
1338 /* Decrypt a PGP or SMIME message (depending on the boolean flag
1339 IS_SMIME) with body A described further by state S. Write
1340 plaintext out to file FPOUT and return a new body. For PGP returns
1341 a flag in R_IS_SIGNED to indicate whether this is a combined
1342 encrypted and signed message, for S/MIME it returns true when it is
1343 not a encrypted but a signed message. */
1344 static BODY *decrypt_part (BODY * a, STATE * s, FILE * fpout, int is_smime,
1351 gpgme_data_t ciphertext, plaintext;
1352 int maybe_signed = 0;
1359 ctx = create_gpgme_context (is_smime);
1362 /* Make a data object from the body, create context etc. */
1363 ciphertext = file_to_data_object (s->fpin, a->offset, a->length);
1366 plaintext = create_gpgme_data ();
1368 /* Do the decryption or the verification in case of the S/MIME hack. */
1369 if ((!is_smime) || maybe_signed) {
1371 err = gpgme_op_decrypt_verify (ctx, ciphertext, plaintext);
1372 else if (maybe_signed)
1373 err = gpgme_op_verify (ctx, ciphertext, NULL, plaintext);
1376 /* Check wether signatures have been verified. */
1377 gpgme_verify_result_t verify_result = gpgme_op_verify_result (ctx);
1379 if (verify_result->signatures)
1384 err = gpgme_op_decrypt (ctx, ciphertext, plaintext);
1385 gpgme_data_release (ciphertext);
1387 if (is_smime && !maybe_signed && gpg_err_code (err) == GPG_ERR_NO_DATA) {
1388 /* Check whether this might be a signed message despite what
1389 the mime header told us. Retry then. gpgsm returns the
1390 error information "unsupported Algorithm '?'" but gpgme
1391 will not store this unknown algorithm, thus we test that
1392 it has not been set. */
1393 gpgme_decrypt_result_t result;
1395 result = gpgme_op_decrypt_result (ctx);
1396 if (!result->unsupported_algorithm) {
1398 gpgme_data_release (plaintext);
1402 mutt_need_hard_redraw ();
1403 if ((s->flags & M_DISPLAY)) {
1406 snprintf (buf, sizeof (buf) - 1,
1407 _("[-- Error: decryption failed: %s --]\n\n"),
1408 gpgme_strerror (err));
1409 state_attach_puts (buf, s);
1411 gpgme_data_release (plaintext);
1412 gpgme_release (ctx);
1415 mutt_need_hard_redraw ();
1417 /* Read the output from GPGME, and make sure to change CRLF to LF,
1418 otherwise read_mime_header has a hard time parsing the message. */
1419 if (data_object_to_stream (plaintext, fpout)) {
1420 gpgme_data_release (plaintext);
1421 gpgme_release (ctx);
1424 gpgme_data_release (plaintext);
1426 a->is_signed_data = 0;
1432 a->is_signed_data = 1;
1434 *r_is_signed = -1; /* A signature exists. */
1436 if ((s->flags & M_DISPLAY))
1437 state_attach_puts (_("[-- Begin signature " "information --]\n"), s);
1438 for (idx = 0; (res = show_one_sig_status (ctx, idx, s)) != -1; idx++) {
1444 if (!anybad && idx && r_is_signed && *r_is_signed)
1445 *r_is_signed = anywarn ? 2 : 1; /* Good signature. */
1447 if ((s->flags & M_DISPLAY))
1448 state_attach_puts (_("[-- End signature " "information --]\n\n"), s);
1450 gpgme_release (ctx);
1455 tattach = mutt_read_mime_header (fpout, 0);
1458 * Need to set the length of this body part.
1460 fstat (fileno (fpout), &info);
1461 tattach->length = info.st_size - tattach->offset;
1463 tattach->warnsig = anywarn;
1465 /* See if we need to recurse on this MIME part. */
1466 mutt_parse_part (fpout, tattach);
1472 /* Decrypt a PGP/MIME message in FPIN and B and return a new body and
1473 the stream in CUR and FPOUT. Returns 0 on success. */
1474 int pgp_gpgme_decrypt_mime (FILE * fpin, FILE ** fpout, BODY * b, BODY ** cur)
1476 char tempfile[_POSIX_PATH_MAX];
1478 BODY *first_part = b;
1481 first_part->goodsig = 0;
1482 first_part->warnsig = 0;
1484 if (!mutt_is_multipart_encrypted (b))
1487 if (!b->parts || !b->parts->next)
1492 memset (&s, 0, sizeof (s));
1494 mutt_mktemp (tempfile);
1495 if (!(*fpout = safe_fopen (tempfile, "w+"))) {
1496 mutt_perror (tempfile);
1501 *cur = decrypt_part (b, &s, *fpout, 0, &is_signed);
1504 first_part->goodsig = 1;
1506 return *cur ? 0 : -1;
1510 /* Decrypt a S/MIME message in FPIN and B and return a new body and
1511 the stream in CUR and FPOUT. Returns 0 on success. */
1512 int smime_gpgme_decrypt_mime (FILE * fpin, FILE ** fpout, BODY * b,
1515 char tempfile[_POSIX_PATH_MAX];
1519 long saved_b_offset;
1520 size_t saved_b_length;
1523 if (!mutt_is_application_smime (b))
1529 /* Decode the body - we need to pass binary CMS to the
1530 backend. The backend allows for Base64 encoded data but it does
1531 not allow for QP which I have seen in some messages. So better
1533 saved_b_type = b->type;
1534 saved_b_offset = b->offset;
1535 saved_b_length = b->length;
1536 memset (&s, 0, sizeof (s));
1538 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);
1553 memset (&s, 0, sizeof (s));
1556 mutt_mktemp (tempfile);
1557 if (!(*fpout = safe_fopen (tempfile, "w+"))) {
1558 mutt_perror (tempfile);
1561 mutt_unlink (tempfile);
1563 *cur = decrypt_part (b, &s, *fpout, 1, &is_signed);
1565 (*cur)->goodsig = is_signed > 0;
1566 b->type = saved_b_type;
1567 b->length = saved_b_length;
1568 b->offset = saved_b_offset;
1571 if (*cur && !is_signed && !(*cur)->parts
1572 && mutt_is_application_smime (*cur)) {
1573 /* Assume that this is a opaque signed s/mime message. This is
1574 an ugly way of doing it but we have anyway a problem with
1575 arbitrary encoded S/MIME messages: Only the outer part may be
1576 encrypted. The entire mime parsing should be revamped,
1577 probably by keeping the temportary files so that we don't
1578 need to decrypt them all the time. Inner parts of an
1579 encrypted part can then pint into this file and tehre won't
1580 never be a need to decrypt again. This needs a partial
1581 rewrite of the MIME engine. */
1585 saved_b_type = bb->type;
1586 saved_b_offset = bb->offset;
1587 saved_b_length = bb->length;
1588 memset (&s, 0, sizeof (s));
1590 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);
1606 memset (&s, 0, sizeof (s));
1609 mutt_mktemp (tempfile);
1610 if (!(*fpout = safe_fopen (tempfile, "w+"))) {
1611 mutt_perror (tempfile);
1614 mutt_unlink (tempfile);
1616 tmp_b = decrypt_part (bb, &s, *fpout, 1, &is_signed);
1618 tmp_b->goodsig = is_signed > 0;
1619 bb->type = saved_b_type;
1620 bb->length = saved_b_length;
1621 bb->offset = saved_b_offset;
1624 mutt_free_body (cur);
1627 return *cur ? 0 : -1;
1632 * Implementation of `pgp_check_traditional'.
1635 static int pgp_check_traditional_one_body (FILE * fp, BODY * b,
1638 char tempfile[_POSIX_PATH_MAX];
1639 char buf[HUGE_STRING];
1645 if (b->type != TYPETEXT)
1648 if (tagged_only && !b->tagged)
1651 mutt_mktemp (tempfile);
1652 if (mutt_decode_save_attachment (fp, b, tempfile, 0, 0) != 0) {
1657 if ((tfp = fopen (tempfile, "r")) == NULL) {
1662 while (fgets (buf, sizeof (buf), tfp)) {
1663 if (!str_ncmp ("-----BEGIN PGP ", buf, 15)) {
1664 if (!str_cmp ("MESSAGE-----\n", buf + 15))
1666 else if (!str_cmp ("SIGNED MESSAGE-----\n", buf + 15))
1676 /* fix the content type */
1678 mutt_set_parameter ("format", "fixed", &b->parameter);
1679 mutt_set_parameter ("x-action", enc ? "pgp-encrypted" : "pgp-signed",
1685 int pgp_gpgme_check_traditional (FILE * fp, BODY * b, int tagged_only)
1690 for (; b; b = b->next) {
1691 if (is_multipart (b))
1692 rv = (pgp_gpgme_check_traditional (fp, b->parts, tagged_only) || rv);
1693 else if (b->type == TYPETEXT) {
1694 if ((r = mutt_is_application_pgp (b)))
1697 rv = (pgp_check_traditional_one_body (fp, b, tagged_only) || rv);
1705 * Implementation of `application_handler'.
1709 Copy a clearsigned message, and strip the signature and PGP's
1712 XXX - charset handling: We assume that it is safe to do
1713 character set decoding first, dash decoding second here, while
1714 we do it the other way around in the main handler.
1716 (Note that we aren't worse than Outlook & Cie in this, and also
1717 note that we can successfully handle anything produced by any
1718 existing versions of mutt.) */
1720 static void copy_clearsigned (gpgme_data_t data, STATE * s, char *charset)
1722 char buf[HUGE_STRING];
1723 short complete, armor_header;
1728 fname = data_object_to_tempfile (data, &fp);
1734 fc = fgetconv_open (fp, charset, Charset, M_ICONV_HOOK_FROM);
1736 for (complete = 1, armor_header = 1;
1737 fgetconvs (buf, sizeof (buf), fc) != NULL;
1738 complete = strchr (buf, '\n') != NULL) {
1741 state_puts (buf, s);
1745 if (!str_cmp (buf, "-----BEGIN PGP SIGNATURE-----\n"))
1755 state_puts (s->prefix, s);
1757 if (buf[0] == '-' && buf[1] == ' ')
1758 state_puts (buf + 2, s);
1760 state_puts (buf, s);
1763 fgetconv_close (&fc);
1768 /* Support for classic_application/pgp */
1769 int pgp_gpgme_application_handler (BODY * m, STATE * s)
1771 int needpass = -1, pgp_keyblock = 0;
1775 LOFF_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 strfcpy (body_charset, "iso-8859-1", sizeof body_charset);
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 str_len(buf) */
1806 if (!str_ncmp ("-----BEGIN PGP ", buf, 15)) {
1808 start_pos = last_pos;
1810 if (!str_cmp ("MESSAGE-----\n", buf + 15))
1812 else if (!str_cmp ("SIGNED MESSAGE-----\n", buf + 15)) {
1816 else if (!option (OPTDONTHANDLEPGPKEYS) &&
1817 !str_cmp ("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, str_len (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 str_len(buf) */
1839 gpgme_data_write (armored_data, buf, str_len (buf));
1841 if ((needpass && !str_cmp ("-----END PGP MESSAGE-----\n", buf))
1843 && (!str_cmp ("-----END PGP SIGNATURE-----\n", buf)
1844 || !str_cmp ("-----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 mem_free (&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)
2159 static const char *crypt_entry_fmt (char *dest,
2164 const char *ifstring,
2165 const char *elsestring,
2166 unsigned long data, format_flag flags)
2169 crypt_entry_t *entry;
2172 int optional = (flags & M_FORMAT_OPTIONAL);
2173 const char *s = NULL;
2176 entry = (crypt_entry_t *) data;
2179 /* if (isupper ((unsigned char) op)) */
2182 kflags = (key->flags /*| (pkey->flags & KEYFLAG_RESTRICTIONS)
2185 switch (ascii_tolower (op)) {
2189 char buf2[SHORT_STRING], *p;
2205 while (len > 0 && *cp != ']') {
2214 break; /* not enough space */
2224 if (do_locales && Locale)
2225 setlocale (LC_TIME, Locale);
2230 if (key->kobj->subkeys && (key->kobj->subkeys->timestamp > 0))
2231 tt = key->kobj->subkeys->timestamp;
2233 tm = localtime (&tt);
2235 strftime (buf2, sizeof (buf2), dest, tm);
2238 setlocale (LC_TIME, "C");
2240 snprintf (fmt, sizeof (fmt), "%%%ss", prefix);
2241 snprintf (dest, destlen, fmt, buf2);
2248 snprintf (fmt, sizeof (fmt), "%%%sd", prefix);
2249 snprintf (dest, destlen, fmt, entry->num);
2254 /* fixme: we need a way to distinguish between main and subkeys.
2255 Store the idx in entry? */
2256 snprintf (fmt, sizeof (fmt), "%%%ss", prefix);
2257 snprintf (dest, destlen, fmt, crypt_keyid (key));
2262 snprintf (fmt, sizeof (fmt), "%%%ss", prefix);
2263 snprintf (dest, destlen, fmt, key->uid);
2268 snprintf (fmt, sizeof (fmt), "%%%s.3s", prefix);
2269 if (key->kobj->subkeys)
2270 s = gpgme_pubkey_algo_name (key->kobj->subkeys->pubkey_algo);
2273 snprintf (dest, destlen, fmt, s);
2278 snprintf (fmt, sizeof (fmt), "%%%slu", prefix);
2279 if (key->kobj->subkeys)
2280 val = key->kobj->subkeys->length;
2283 snprintf (dest, destlen, fmt, val);
2288 snprintf (fmt, sizeof (fmt), "%%%sc", prefix);
2289 snprintf (dest, destlen, fmt, crypt_flags (kflags));
2291 else if (!(kflags & (KEYFLAG_RESTRICTIONS)))
2296 snprintf (fmt, sizeof (fmt), "%%%ss", prefix);
2297 snprintf (dest, destlen, fmt, crypt_key_abilities (kflags));
2299 else if (!(kflags & (KEYFLAG_ABILITIES)))
2303 if ((kflags & KEYFLAG_ISX509))
2306 gpgme_user_id_t uid = NULL;
2309 for (i = 0, uid = key->kobj->uids; uid && (i < key->idx);
2310 i++, uid = uid->next);
2312 switch (uid->validity) {
2313 case GPGME_VALIDITY_UNDEFINED:
2316 case GPGME_VALIDITY_NEVER:
2319 case GPGME_VALIDITY_MARGINAL:
2322 case GPGME_VALIDITY_FULL:
2325 case GPGME_VALIDITY_ULTIMATE:
2328 case GPGME_VALIDITY_UNKNOWN:
2334 snprintf (fmt, sizeof (fmt), "%%%sc", prefix);
2335 snprintf (dest, destlen, fmt, s ? *s : 'B');
2338 snprintf (fmt, sizeof (fmt), "%%%ss", prefix);
2339 snprintf (dest, destlen, fmt,
2340 gpgme_get_protocol_name (key->kobj->protocol));
2348 mutt_FormatString (dest, destlen, ifstring, mutt_attach_fmt, data, 0);
2349 else if (flags & M_FORMAT_OPTIONAL)
2350 mutt_FormatString (dest, destlen, elsestring, mutt_attach_fmt, data, 0);
2354 /* Used by the display fucntion to format a line. */
2355 static void crypt_entry (char *s, size_t l, MUTTMENU * menu, int num)
2357 crypt_key_t **key_table = (crypt_key_t **) menu->data;
2358 crypt_entry_t entry;
2360 entry.key = key_table[num];
2361 entry.num = num + 1;
2363 mutt_FormatString (s, l, NONULL (PgpEntryFormat), crypt_entry_fmt,
2364 (unsigned long) &entry, M_FORMAT_ARROWCURSOR);
2367 /* Compare two addresses and the keyid to be used for sorting. */
2368 static int _crypt_compare_address (const void *a, const void *b)
2370 crypt_key_t **s = (crypt_key_t **) a;
2371 crypt_key_t **t = (crypt_key_t **) b;
2374 if ((r = str_casecmp ((*s)->uid, (*t)->uid)))
2377 return str_casecmp (crypt_keyid (*s), crypt_keyid (*t)) > 0;
2380 static int crypt_compare_address (const void *a, const void *b)
2382 return ((PgpSortKeys & SORT_REVERSE) ? !_crypt_compare_address (a, b)
2383 : _crypt_compare_address (a, b));
2387 /* Compare two key IDs and the addresses to be used for sorting. */
2388 static int _crypt_compare_keyid (const void *a, const void *b)
2390 crypt_key_t **s = (crypt_key_t **) a;
2391 crypt_key_t **t = (crypt_key_t **) b;
2394 if ((r = str_casecmp (crypt_keyid (*s), crypt_keyid (*t))))
2397 return str_casecmp ((*s)->uid, (*t)->uid) > 0;
2400 static int crypt_compare_keyid (const void *a, const void *b)
2402 return ((PgpSortKeys & SORT_REVERSE) ? !_crypt_compare_keyid (a, b)
2403 : _crypt_compare_keyid (a, b));
2406 /* Compare 2 creation dates and the addresses. For sorting. */
2407 static int _crypt_compare_date (const void *a, const void *b)
2409 crypt_key_t **s = (crypt_key_t **) a;
2410 crypt_key_t **t = (crypt_key_t **) b;
2411 unsigned long ts = 0, tt = 0;
2413 if ((*s)->kobj->subkeys && ((*s)->kobj->subkeys->timestamp > 0))
2414 ts = (*s)->kobj->subkeys->timestamp;
2415 if ((*t)->kobj->subkeys && ((*t)->kobj->subkeys->timestamp > 0))
2416 tt = (*t)->kobj->subkeys->timestamp;
2423 return str_casecmp ((*s)->uid, (*t)->uid) > 0;
2426 static int crypt_compare_date (const void *a, const void *b)
2428 return ((PgpSortKeys & SORT_REVERSE) ? !_crypt_compare_date (a, b)
2429 : _crypt_compare_date (a, b));
2432 /* Compare two trust values, the key length, the creation dates. the
2433 addresses and the key IDs. For sorting. */
2434 static int _crypt_compare_trust (const void *a, const void *b)
2436 crypt_key_t **s = (crypt_key_t **) a;
2437 crypt_key_t **t = (crypt_key_t **) b;
2438 unsigned long ts = 0, tt = 0;
2441 if ((r = (((*s)->flags & (KEYFLAG_RESTRICTIONS))
2442 - ((*t)->flags & (KEYFLAG_RESTRICTIONS)))))
2445 if ((*s)->kobj->uids)
2446 ts = (*s)->kobj->uids->validity;
2447 if ((*t)->kobj->uids)
2448 tt = (*t)->kobj->uids->validity;
2449 if ((r = (tt - ts)))
2452 if ((*s)->kobj->subkeys)
2453 ts = (*s)->kobj->subkeys->length;
2454 if ((*t)->kobj->subkeys)
2455 tt = (*t)->kobj->subkeys->length;
2459 if ((*s)->kobj->subkeys && ((*s)->kobj->subkeys->timestamp > 0))
2460 ts = (*s)->kobj->subkeys->timestamp;
2461 if ((*t)->kobj->subkeys && ((*t)->kobj->subkeys->timestamp > 0))
2462 tt = (*t)->kobj->subkeys->timestamp;
2468 if ((r = str_casecmp ((*s)->uid, (*t)->uid)))
2470 return (str_casecmp (crypt_keyid ((*s)), crypt_keyid ((*t)))) > 0;
2473 static int crypt_compare_trust (const void *a, const void *b)
2475 return ((PgpSortKeys & SORT_REVERSE) ? !_crypt_compare_trust (a, b)
2476 : _crypt_compare_trust (a, b));
2479 /* Print the X.500 Distinguished Name part KEY from the array of parts
2481 static int print_dn_part (FILE * fp, struct dn_array_s *dn, const char *key)
2485 for (; dn->key; dn++) {
2486 if (!str_cmp (dn->key, key)) {
2489 print_utf8 (fp, dn->value, str_len (dn->value));
2496 /* Print all parts of a DN in a standard sequence. */
2497 static void print_dn_parts (FILE * fp, struct dn_array_s *dn)
2499 const char *stdpart[] = {
2500 "CN", "OU", "O", "STREET", "L", "ST", "C", NULL
2502 int any = 0, any2 = 0, i;
2504 for (i = 0; stdpart[i]; i++) {
2507 any = print_dn_part (fp, dn, stdpart[i]);
2509 /* now print the rest without any specific ordering */
2510 for (; dn->key; dn++) {
2511 for (i = 0; stdpart[i]; i++) {
2512 if (!str_cmp (dn->key, stdpart[i]))
2520 any = print_dn_part (fp, dn, dn->key);
2529 /* Parse an RDN; this is a helper to parse_dn(). */
2530 static const unsigned char *parse_dn_part (struct dn_array_s *array,
2531 const unsigned char *string)
2533 const unsigned char *s, *s1;
2537 /* parse attributeType */
2538 for (s = string + 1; *s && *s != '='; s++);
2540 return NULL; /* error */
2543 return NULL; /* empty key */
2544 array->key = mem_malloc (n + 1);
2545 p = (unsigned char *) array->key;
2546 memcpy (p, string, n); /* fixme: trim trailing spaces */
2550 if (*string == '#') { /* hexstring */
2552 for (s = string; hexdigitp (s); s++)
2556 return NULL; /* empty or odd number of digits */
2558 p = mem_malloc (n + 1);
2559 array->value = (char *) p;
2560 for (s1 = string; n; s1 += 2, n--)
2564 else { /* regular v3 quoted string */
2565 for (n = 0, s = string; *s; s++) {
2566 if (*s == '\\') { /* pair */
2568 if (*s == ',' || *s == '=' || *s == '+'
2569 || *s == '<' || *s == '>' || *s == '#' || *s == ';'
2570 || *s == '\\' || *s == '\"' || *s == ' ')
2572 else if (hexdigitp (s) && hexdigitp (s + 1)) {
2577 return NULL; /* invalid escape sequence */
2579 else if (*s == '\"')
2580 return NULL; /* invalid encoding */
2581 else if (*s == ',' || *s == '=' || *s == '+'
2582 || *s == '<' || *s == '>' || *s == '#' || *s == ';')
2588 p = mem_malloc (n + 1);
2589 array->value = (char *) p;
2590 for (s = string; n; s++, n--) {
2593 if (hexdigitp (s)) {
2609 /* Parse a DN and return an array-ized one. This is not a validating
2610 parser and it does not support any old-stylish syntax; gpgme is
2611 expected to return only rfc2253 compatible strings. */
2612 static struct dn_array_s *parse_dn (const unsigned char *string)
2614 struct dn_array_s *array;
2615 size_t arrayidx, arraysize;
2618 arraysize = 7; /* C,ST,L,O,OU,CN,email */
2619 array = mem_malloc ((arraysize + 1) * sizeof *array);
2622 while (*string == ' ')
2626 if (arrayidx >= arraysize) { /* mutt lacks a real safe_realoc - so we need to copy */
2627 struct dn_array_s *a2;
2630 a2 = mem_malloc ((arraysize + 1) * sizeof *array);
2631 for (i = 0; i < arrayidx; i++) {
2632 a2[i].key = array[i].key;
2633 a2[i].value = array[i].value;
2638 array[arrayidx].key = NULL;
2639 array[arrayidx].value = NULL;
2640 string = parse_dn_part (array + arrayidx, string);
2644 while (*string == ' ')
2646 if (*string && *string != ',' && *string != ';' && *string != '+')
2647 goto failure; /* invalid delimiter */
2651 array[arrayidx].key = NULL;
2652 array[arrayidx].value = NULL;
2656 for (i = 0; i < arrayidx; i++) {
2657 mem_free (&array[i].key);
2658 mem_free (&array[i].value);
2665 /* Print a nice representation of the USERID and make sure it is
2666 displayed in a proper way, which does mean to reorder some parts
2667 for S/MIME's DNs. USERID is a string as returned by the gpgme key
2668 functions. It is utf-8 encoded. */
2669 static void parse_and_print_user_id (FILE * fp, const char *userid)
2674 if (*userid == '<') {
2675 s = strchr (userid + 1, '>');
2677 print_utf8 (fp, userid + 1, s - userid - 1);
2679 else if (*userid == '(')
2680 fputs (_("[Can't display this user ID (unknown encoding)]"), fp);
2681 else if (!digit_or_letter ((const unsigned char *) userid))
2682 fputs (_("[Can't display this user ID (invalid encoding)]"), fp);
2684 struct dn_array_s *dn = parse_dn ((const unsigned char *) userid);
2687 fputs (_("[Can't display this user ID (invalid DN)]"), fp);
2689 print_dn_parts (fp, dn);
2690 for (i = 0; dn[i].key; i++) {
2691 mem_free (&dn[i].key);
2692 mem_free (&dn[i].value);
2700 KEY_CAP_CAN_ENCRYPT,
2705 static unsigned int key_check_cap (gpgme_key_t key, key_cap_t cap)
2707 gpgme_subkey_t subkey = NULL;
2708 unsigned int ret = 0;
2711 case KEY_CAP_CAN_ENCRYPT:
2712 if (!(ret = key->can_encrypt))
2713 for (subkey = key->subkeys; subkey; subkey = subkey->next)
2714 if ((ret = subkey->can_encrypt))
2717 case KEY_CAP_CAN_SIGN:
2718 if (!(ret = key->can_sign))
2719 for (subkey = key->subkeys; subkey; subkey = subkey->next)
2720 if ((ret = subkey->can_sign))
2723 case KEY_CAP_CAN_CERTIFY:
2724 if (!(ret = key->can_certify))
2725 for (subkey = key->subkeys; subkey; subkey = subkey->next)
2726 if ((ret = subkey->can_certify))
2735 /* Print verbose information about a key or certificate to FP. */
2736 static void print_key_info (gpgme_key_t key, FILE * fp)
2739 const char *s = NULL, *s2 = NULL;
2742 char shortbuf[SHORT_STRING];
2743 unsigned long aval = 0;
2747 gpgme_user_id_t uid = NULL;
2750 setlocale (LC_TIME, Locale);
2752 is_pgp = key->protocol == GPGME_PROTOCOL_OpenPGP;
2754 for (idx = 0, uid = key->uids; uid; idx++, uid = uid->next) {
2759 fputs (idx ? _(" aka ......: ") :_("Name ......: "), fp);
2762 fputs (_("[Invalid]"), fp);
2766 print_utf8 (fp, s, str_len (s));
2768 parse_and_print_user_id (fp, s);
2772 if (key->subkeys && (key->subkeys->timestamp > 0)) {
2773 tt = key->subkeys->timestamp;
2775 tm = localtime (&tt);
2776 #ifdef HAVE_LANGINFO_D_T_FMT
2777 strftime (shortbuf, sizeof shortbuf, nl_langinfo (D_T_FMT), tm);
2779 strftime (shortbuf, sizeof shortbuf, "%c", tm);
2781 fprintf (fp, _("Valid From : %s\n"), shortbuf);
2784 if (key->subkeys && (key->subkeys->expires > 0)) {
2785 tt = key->subkeys->expires;
2787 tm = localtime (&tt);
2788 #ifdef HAVE_LANGINFO_D_T_FMT
2789 strftime (shortbuf, sizeof shortbuf, nl_langinfo (D_T_FMT), tm);
2791 strftime (shortbuf, sizeof shortbuf, "%c", tm);
2793 fprintf (fp, _("Valid To ..: %s\n"), shortbuf);
2797 s = gpgme_pubkey_algo_name (key->subkeys->pubkey_algo);
2801 s2 = is_pgp ? "PGP" : "X.509";
2804 aval = key->subkeys->length;
2806 fprintf (fp, _("Key Type ..: %s, %lu bit %s\n"), s2, aval, s);
2808 fprintf (fp, _("Key Usage .: "));
2811 if (key_check_cap (key, KEY_CAP_CAN_ENCRYPT)) {
2812 fprintf (fp, "%s%s", delim, _("encryption"));
2815 if (key_check_cap (key, KEY_CAP_CAN_SIGN)) {
2816 fprintf (fp, "%s%s", delim, _("signing"));
2819 if (key_check_cap (key, KEY_CAP_CAN_CERTIFY)) {
2820 fprintf (fp, "%s%s", delim, _("certification"));
2826 s = key->subkeys->fpr;
2827 fputs (_("Fingerprint: "), fp);
2828 if (is_pgp && str_len (s) == 40) {
2829 for (i = 0; *s && s[1] && s[2] && s[3] && s[4]; s += 4, i++) {
2834 putc (is_pgp ? ' ' : ':', fp);
2835 if (is_pgp && i == 4)
2840 for (i = 0; *s && s[1] && s[2]; s += 2, i++) {
2843 putc (is_pgp ? ' ' : ':', fp);
2844 if (is_pgp && i == 7)
2848 fprintf (fp, "%s\n", s);
2851 if (key->issuer_serial) {
2852 s = key->issuer_serial;
2854 fprintf (fp, _("Serial-No .: 0x%s\n"), s);
2857 if (key->issuer_name) {
2858 s = key->issuer_name;
2860 fprintf (fp, _("Issued By .: "));
2861 parse_and_print_user_id (fp, s);
2866 /* For PGP we list all subkeys. */
2868 gpgme_subkey_t subkey = NULL;
2870 for (idx = 1, subkey = key->subkeys; subkey; idx++, subkey = subkey->next) {
2874 if (str_len (s) == 16)
2875 s += 8; /* display only the short keyID */
2876 fprintf (fp, _("Subkey ....: 0x%s"), s);
2877 if (subkey->revoked) {
2879 fputs (_("[Revoked]"), fp);
2881 if (subkey->invalid) {
2883 fputs (_("[Invalid]"), fp);
2885 if (subkey->expired) {
2887 fputs (_("[Expired]"), fp);
2889 if (subkey->disabled) {
2891 fputs (_("[Disabled]"), fp);
2895 if (subkey->timestamp > 0) {
2896 tt = subkey->timestamp;
2898 tm = localtime (&tt);
2899 #ifdef HAVE_LANGINFO_D_T_FMT
2900 strftime (shortbuf, sizeof shortbuf, nl_langinfo (D_T_FMT), tm);
2902 strftime (shortbuf, sizeof shortbuf, "%c", tm);
2904 fprintf (fp, _("Valid From : %s\n"), shortbuf);
2907 if (subkey->expires > 0) {
2908 tt = subkey->expires;
2910 tm = localtime (&tt);
2911 #ifdef HAVE_LANGINFO_D_T_FMT
2912 strftime (shortbuf, sizeof shortbuf, nl_langinfo (D_T_FMT), tm);
2914 strftime (shortbuf, sizeof shortbuf, "%c", tm);
2916 fprintf (fp, _("Valid To ..: %s\n"), shortbuf);
2920 s = gpgme_pubkey_algo_name (subkey->pubkey_algo);
2925 aval = subkey->length;
2929 fprintf (fp, _("Key Type ..: %s, %lu bit %s\n"), "PGP", aval, s);
2931 fprintf (fp, _("Key Usage .: "));
2934 if (subkey->can_encrypt) {
2935 fprintf (fp, "%s%s", delim, _("encryption"));
2938 if (subkey->can_sign) {
2939 fprintf (fp, "%s%s", delim, _("signing"));
2942 if (subkey->can_certify) {
2943 fprintf (fp, "%s%s", delim, _("certification"));
2951 setlocale (LC_TIME, "C");
2955 /* Show detailed information about the selected key */
2956 static void verify_key (crypt_key_t * key)
2959 char cmd[LONG_STRING], tempfile[_POSIX_PATH_MAX];
2961 gpgme_ctx_t listctx = NULL;
2963 gpgme_key_t k = NULL;
2966 mutt_mktemp (tempfile);
2967 if (!(fp = safe_fopen (tempfile, "w"))) {
2968 mutt_perror (_("Can't create temporary file"));
2972 mutt_message _("Collecting data...");
2974 print_key_info (key->kobj, fp);
2976 err = gpgme_new (&listctx);
2978 fprintf (fp, "Internal error: can't create gpgme context: %s\n",
2979 gpgme_strerror (err));
2982 if ((key->flags & KEYFLAG_ISX509))
2983 gpgme_set_protocol (listctx, GPGME_PROTOCOL_CMS);
2987 while ((s = k->chain_id) && k->subkeys && str_cmp (s, k->subkeys->fpr)) {
2989 err = gpgme_op_keylist_start (listctx, s, 0);
2990 gpgme_key_release (k);
2993 err = gpgme_op_keylist_next (listctx, &k);
2995 fprintf (fp, _("Error finding issuer key: %s\n"), gpgme_strerror (err));
2998 gpgme_op_keylist_end (listctx);
3000 print_key_info (k, fp);
3003 fputs (_("Error: certification chain to long - stopping here\n"), fp);
3009 gpgme_key_release (k);
3010 gpgme_release (listctx);
3012 mutt_clear_error ();
3013 snprintf (cmd, sizeof (cmd), _("Key ID: 0x%s"), crypt_keyid (key));
3014 mutt_do_pager (cmd, tempfile, 0, NULL);
3018 * Implementation of `findkeys'.
3022 /* Convert LIST into a pattern string suitable to be passed to GPGME.
3023 We need to convert spaces in an item into a '+' and '%' into
3025 static char *list_to_pattern (LIST * list)
3033 for (l = list; l; l = l->next) {
3034 for (s = l->data; *s; s++) {
3039 n++; /* delimiter or end of string */
3041 n++; /* make sure to allocate at least one byte */
3042 pattern = p = mem_calloc (1, n);
3043 for (l = list; l; l = l->next) {
3048 for (s = l->data; *s; s++) {
3054 else if (*s == '+') {
3070 /* Return a list of keys which are candidates for the selection.
3071 Select by looking at the HINTS list. */
3072 static crypt_key_t *get_candidates (LIST * hints, unsigned int app,
3075 crypt_key_t *db, *k, **kend;
3081 gpgme_user_id_t uid = NULL;
3083 pattern = list_to_pattern (hints);
3087 err = gpgme_new (&ctx);
3089 mutt_error (_("gpgme_new failed: %s"), gpgme_strerror (err));
3090 mem_free (&pattern);
3097 if ((app & APPLICATION_PGP)) {
3098 /* Its all a mess. That old GPGME expects different things
3099 depending on the protocol. For gpg we don' t need percent
3100 escaped pappert but simple strings passed in an array to the
3101 keylist_ext_start function. */
3106 for (l = hints, n = 0; l; l = l->next) {
3107 if (l->data && *l->data)
3113 patarr = mem_calloc (n + 1, sizeof *patarr);
3114 for (l = hints, n = 0; l; l = l->next) {
3115 if (l->data && *l->data)
3116 patarr[n++] = str_dup (l->data);
3119 err = gpgme_op_keylist_ext_start (ctx, (const char **) patarr, secret, 0);
3120 for (n = 0; patarr[n]; n++)
3121 mem_free (&patarr[n]);
3124 mutt_error (_("gpgme_op_keylist_start failed: %s"), gpgme_strerror (err));
3125 gpgme_release (ctx);
3126 mem_free (&pattern);
3130 while (!(err = gpgme_op_keylist_next (ctx, &key))) {
3131 unsigned int flags = 0;
3133 if (key_check_cap (key, KEY_CAP_CAN_ENCRYPT))
3134 flags |= KEYFLAG_CANENCRYPT;
3135 if (key_check_cap (key, KEY_CAP_CAN_SIGN))
3136 flags |= KEYFLAG_CANSIGN;
3138 #if 0 /* DISABLED code */
3140 /* Bug in gpg. Capabilities are not listed for secret
3141 keys. Try to deduce them from the algorithm. */
3143 switch (key->subkeys[0].pubkey_algo) {
3145 flags |= KEYFLAG_CANENCRYPT;
3146 flags |= KEYFLAG_CANSIGN;
3148 case GPGME_PK_ELG_E:
3149 flags |= KEYFLAG_CANENCRYPT;
3152 flags |= KEYFLAG_CANSIGN;
3156 #endif /* DISABLED code */
3158 for (idx = 0, uid = key->uids; uid; idx++, uid = uid->next) {
3159 k = mem_calloc (1, sizeof *k);
3168 if (gpg_err_code (err) != GPG_ERR_EOF)
3169 mutt_error (_("gpgme_op_keylist_next failed: %s"), gpgme_strerror (err));
3170 gpgme_op_keylist_end (ctx);
3175 if ((app & APPLICATION_SMIME)) {
3176 /* and now look for x509 certificates */
3177 gpgme_set_protocol (ctx, GPGME_PROTOCOL_CMS);
3178 err = gpgme_op_keylist_start (ctx, pattern, 0);
3180 mutt_error (_("gpgme_op_keylist_start failed: %s"), gpgme_strerror (err));
3181 gpgme_release (ctx);
3182 mem_free (&pattern);
3186 while (!(err = gpgme_op_keylist_next (ctx, &key))) {
3187 unsigned int flags = KEYFLAG_ISX509;
3189 if (key_check_cap (key, KEY_CAP_CAN_ENCRYPT))
3190 flags |= KEYFLAG_CANENCRYPT;
3191 if (key_check_cap (key, KEY_CAP_CAN_SIGN))
3192 flags |= KEYFLAG_CANSIGN;
3194 for (idx = 0, uid = key->uids; uid; idx++, uid = uid->next) {
3195 k = mem_calloc (1, sizeof *k);
3204 if (gpg_err_code (err) != GPG_ERR_EOF)
3205 mutt_error (_("gpgme_op_keylist_next failed: %s"), gpgme_strerror (err));
3206 gpgme_op_keylist_end (ctx);
3209 gpgme_release (ctx);
3210 mem_free (&pattern);
3214 /* Add the string STR to the list HINTS. This list is later used to
3216 static LIST *crypt_add_string_to_hints (LIST * hints, const char *str)
3221 if ((scratch = str_dup (str)) == NULL)
3224 for (t = strtok (scratch, " ,.:\"()<>\n"); t;
3225 t = strtok (NULL, " ,.:\"()<>\n")) {
3226 if (str_len (t) > 3)
3227 hints = mutt_add_list (hints, t);
3230 mem_free (&scratch);
3234 /* Display a menu to select a key from the array KEYS. FORCED_VALID
3235 will be set to true on return if the user did override the the
3237 static crypt_key_t *crypt_select_key (crypt_key_t * keys,
3238 ADDRESS * p, const char *s,
3239 unsigned int app, int *forced_valid)
3242 crypt_key_t **key_table;
3245 char helpstr[SHORT_STRING], buf[LONG_STRING];
3247 int (*f) (const void *, const void *);
3248 int menu_to_use = 0;
3253 /* build the key table */
3256 for (k = keys; k; k = k->next) {
3257 if (!option (OPTPGPSHOWUNUSABLE) && (k->flags & KEYFLAG_CANTUSE)) {
3264 mem_realloc (&key_table, sizeof (crypt_key_t *) * keymax);
3270 if (!i && unusable) {
3271 mutt_error _("All matching keys are marked expired/revoked.");
3277 switch (PgpSortKeys & SORT_MASK) {
3279 f = crypt_compare_date;
3282 f = crypt_compare_keyid;
3285 f = crypt_compare_address;
3289 f = crypt_compare_trust;
3292 qsort (key_table, i, sizeof (crypt_key_t *), f);
3294 if (app & APPLICATION_PGP)
3295 menu_to_use = MENU_KEY_SELECT_PGP;
3296 else if (app & APPLICATION_SMIME)
3297 menu_to_use = MENU_KEY_SELECT_SMIME;
3300 mutt_make_help (buf, sizeof (buf), _("Exit "), menu_to_use, OP_EXIT);
3301 strcat (helpstr, buf); /* __STRCAT_CHECKED__ */
3302 mutt_make_help (buf, sizeof (buf), _("Select "), menu_to_use,
3303 OP_GENERIC_SELECT_ENTRY);
3304 strcat (helpstr, buf); /* __STRCAT_CHECKED__ */
3305 mutt_make_help (buf, sizeof (buf), _("Check key "),
3306 menu_to_use, OP_VERIFY_KEY);
3307 strcat (helpstr, buf); /* __STRCAT_CHECKED__ */
3308 mutt_make_help (buf, sizeof (buf), _("Help"), menu_to_use, OP_HELP);
3309 strcat (helpstr, buf); /* __STRCAT_CHECKED__ */
3311 menu = mutt_new_menu ();
3313 menu->make_entry = crypt_entry;
3314 menu->menu = menu_to_use;
3315 menu->help = helpstr;
3316 menu->data = key_table;
3321 if ((app & APPLICATION_PGP) && (app & APPLICATION_SMIME))
3322 ts = _("PGP and S/MIME keys matching");
3323 else if ((app & APPLICATION_PGP))
3324 ts = _("PGP keys matching");
3325 else if ((app & APPLICATION_SMIME))
3326 ts = _("S/MIME keys matching");
3328 ts = _("keys matching");
3331 snprintf (buf, sizeof (buf), _("%s <%s>."), ts, p->mailbox);
3333 snprintf (buf, sizeof (buf), _("%s \"%s\"."), ts, s);
3337 mutt_clear_error ();
3341 switch (mutt_menuLoop (menu)) {
3343 verify_key (key_table[menu->current]);
3344 menu->redraw = REDRAW_FULL;
3348 mutt_message ("%s", key_table[menu->current]->uid);
3351 case OP_GENERIC_SELECT_ENTRY:
3352 /* FIXME make error reporting more verbose - this should be
3353 easy because gpgme provides more information */
3354 if (option (OPTPGPCHECKTRUST)) {
3355 if (!crypt_key_is_valid (key_table[menu->current])) {
3356 mutt_error _("This key can't be used: "
3357 "expired/disabled/revoked.");
3362 if (option (OPTPGPCHECKTRUST) &&
3363 (!crypt_id_is_valid (key_table[menu->current])
3364 || !crypt_id_is_strong (key_table[menu->current]))) {
3366 char buff[LONG_STRING];
3368 if (key_table[menu->current]->flags & KEYFLAG_CANTUSE)
3369 s = N_("ID is expired/disabled/revoked.");
3371 gpgme_validity_t val = GPGME_VALIDITY_UNKNOWN;
3372 gpgme_user_id_t uid = NULL;
3377 uid = key_table[menu->current]->kobj->uids;
3378 for (j = 0; (j < key_table[menu->current]->idx) && uid;
3379 j++, uid = uid->next);
3381 val = uid->validity;
3384 case GPGME_VALIDITY_UNKNOWN:
3385 case GPGME_VALIDITY_UNDEFINED:
3386 warn_s = N_("ID has undefined validity.");
3388 case GPGME_VALIDITY_NEVER:
3389 warn_s = N_("ID is not valid.");
3391 case GPGME_VALIDITY_MARGINAL:
3392 warn_s = N_("ID is only marginally valid.");
3394 case GPGME_VALIDITY_FULL:
3395 case GPGME_VALIDITY_ULTIMATE:
3399 snprintf (buff, sizeof (buff),
3400 _("%s Do you really want to use the key?"), _(warn_s));
3402 if (mutt_yesorno (buff, 0) != 1) {
3403 mutt_clear_error ();
3410 k = crypt_copy_key (key_table[menu->current]);
3421 mutt_menuDestroy (&menu);
3422 mem_free (&key_table);
3424 set_option (OPTNEEDREDRAW);
3429 static crypt_key_t *crypt_getkeybyaddr (ADDRESS * a, short abilities,
3430 unsigned int app, int *forced_valid)
3438 int this_key_has_strong;
3439 int this_key_has_weak;
3440 int this_key_has_invalid;
3443 crypt_key_t *keys, *k;
3444 crypt_key_t *the_valid_key = NULL;
3445 crypt_key_t *matches = NULL;
3446 crypt_key_t **matches_endp = &matches;
3450 if (a && a->mailbox)
3451 hints = crypt_add_string_to_hints (hints, a->mailbox);
3452 if (a && a->personal)
3453 hints = crypt_add_string_to_hints (hints, a->personal);
3455 mutt_message (_("Looking for keys matching \"%s\"..."), a->mailbox);
3456 keys = get_candidates (hints, app, (abilities & KEYFLAG_CANSIGN));
3458 mutt_free_list (&hints);
3463 debug_print (5, ("looking for %s <%s>.\n", a->personal, a->mailbox));
3465 for (k = keys; k; k = k->next) {
3466 debug_print (5, (" looking at key: %s `%.15s'\n", crypt_keyid (k), k->uid));
3468 if (abilities && !(k->flags & abilities)) {
3469 debug_print (5, (" insufficient abilities: Has %x, want %x\n", k->flags, abilities));
3473 this_key_has_weak = 0; /* weak but valid match */
3474 this_key_has_invalid = 0; /* invalid match */
3475 this_key_has_strong = 0; /* strong and valid match */
3476 match = 0; /* any match */
3478 r = rfc822_parse_adrlist (NULL, k->uid);
3479 for (p = r; p; p = p->next) {
3480 int validity = crypt_id_matches_addr (a, p, k);
3482 if (validity & CRYPT_KV_MATCH) /* something matches */
3485 /* is this key a strong candidate? */
3486 if ((validity & CRYPT_KV_VALID)
3487 && (validity & CRYPT_KV_STRONGID)
3488 && (validity & CRYPT_KV_ADDR)) {
3489 if (the_valid_key && the_valid_key != k)
3492 this_key_has_strong = 1;
3494 else if ((validity & CRYPT_KV_MATCH)
3495 && !(validity & CRYPT_KV_VALID))
3496 this_key_has_invalid = 1;
3497 else if ((validity & CRYPT_KV_MATCH)
3498 && (!(validity & CRYPT_KV_STRONGID)
3499 || !(validity & CRYPT_KV_ADDR)))
3500 this_key_has_weak = 1;
3502 rfc822_free_address (&r);
3507 if (!this_key_has_strong && this_key_has_invalid)
3509 if (!this_key_has_strong && this_key_has_weak)
3512 *matches_endp = tmp = crypt_copy_key (k);
3513 matches_endp = &tmp->next;
3514 the_valid_key = tmp;
3518 crypt_free_key (&keys);
3521 if (the_valid_key && !multi && !weak
3522 && !(invalid && option (OPTPGPSHOWUNUSABLE))) {
3524 * There was precisely one strong match on a valid ID, there
3525 * were no valid keys with weak matches, and we aren't
3526 * interested in seeing invalid keys.
3528 * Proceed without asking the user.
3530 k = crypt_copy_key (the_valid_key);
3534 * Else: Ask the user.
3536 k = crypt_select_key (matches, a, NULL, app, forced_valid);
3538 crypt_free_key (&matches);
3547 static crypt_key_t *crypt_getkeybystr (char *p, short abilities,
3548 unsigned int app, int *forced_valid)
3552 crypt_key_t *matches = NULL;
3553 crypt_key_t **matches_endp = &matches;
3557 mutt_message (_("Looking for keys matching \"%s\"..."), p);
3561 hints = crypt_add_string_to_hints (hints, p);
3562 keys = get_candidates (hints, app, (abilities & KEYFLAG_CANSIGN));
3563 mutt_free_list (&hints);
3568 for (k = keys; k; k = k->next) {
3569 if (abilities && !(k->flags & abilities))
3573 debug_print (5, ("matching \"%s\" against " "key %s, \"%s\":\n", p, crypt_keyid (k), k->uid));
3575 if (!*p || !str_casecmp (p, crypt_keyid (k))
3576 || (!str_ncasecmp (p, "0x", 2)
3577 && !str_casecmp (p + 2, crypt_keyid (k)))
3578 || (option (OPTPGPLONGIDS)
3579 && !str_ncasecmp (p, "0x", 2)
3580 && !str_casecmp (p + 2, crypt_keyid (k) + 8))
3581 || str_isstr (k->uid, p)) {
3584 debug_print (5, ("match.\n"));
3586 *matches_endp = tmp = crypt_copy_key (k);
3587 matches_endp = &tmp->next;
3591 crypt_free_key (&keys);
3594 k = crypt_select_key (matches, NULL, p, app, forced_valid);
3595 crypt_free_key (&matches);
3602 /* Display TAG as a prompt to ask for a key. If WHATFOR is not null
3603 use it as default and store it under that label as the next
3604 default. ABILITIES describe the required key abilities (sign,
3605 encrypt) and APP the type of the requested key; ether S/MIME or
3606 PGP. Return a copy of the key or NULL if not found. */
3607 static crypt_key_t *crypt_ask_for_key (char *tag,
3610 unsigned int app, int *forced_valid)
3613 char resp[SHORT_STRING];
3614 struct crypt_cache *l = NULL;
3618 forced_valid = &dummy;
3620 mutt_clear_error ();
3626 for (l = id_defaults; l; l = l->next)
3627 if (!str_casecmp (whatfor, l->what)) {
3628 strfcpy (resp, NONULL (l->dflt), sizeof (resp));
3636 if (mutt_get_field (tag, resp, sizeof (resp), M_CLEAR) != 0)
3641 str_replace (&l->dflt, resp);
3643 l = mem_malloc (sizeof (struct crypt_cache));
3644 l->next = id_defaults;
3646 l->what = str_dup (whatfor);
3647 l->dflt = str_dup (resp);
3651 if ((key = crypt_getkeybystr (resp, abilities, app, forced_valid)))
3659 /* This routine attempts to find the keyids of the recipients of a
3660 message. It returns NULL if any of the keys can not be found. */
3661 static char *find_keys (ADDRESS * to, ADDRESS * cc, ADDRESS * bcc,
3664 char *keyID, *keylist = NULL, *t;
3665 size_t keylist_size = 0;
3666 size_t keylist_used = 0;
3667 ADDRESS *tmp = NULL, *addr = NULL;
3668 ADDRESS **last = &tmp;
3671 crypt_key_t *k_info, *key;
3672 const char *fqdn = mutt_fqdn (1);
3675 *r_application = APPLICATION_PGP | APPLICATION_SMIME;
3678 for (i = 0; i < 3; i++) {
3693 *last = rfc822_cpy_adr (p);
3695 last = &((*last)->next);
3699 rfc822_qualify (tmp, fqdn);
3701 tmp = mutt_remove_duplicates (tmp);
3703 for (p = tmp; p; p = p->next) {
3704 char buf[LONG_STRING];
3705 int forced_valid = 0;
3710 if ((keyID = mutt_crypt_hook (p)) != NULL) {
3713 snprintf (buf, sizeof (buf), _("Use keyID = \"%s\" for %s?"),
3715 if ((r = mutt_yesorno (buf, M_YES)) == M_YES) {
3716 /* check for e-mail address */
3717 if ((t = strchr (keyID, '@')) &&
3718 (addr = rfc822_parse_adrlist (NULL, keyID))) {
3720 rfc822_qualify (addr, fqdn);
3725 k_info = crypt_getkeybystr (keyID, KEYFLAG_CANENCRYPT,
3726 *r_application, &forced_valid);
3728 k_info = crypt_getkeybystr (keyID, KEYFLAG_CANENCRYPT,
3729 app, &forced_valid);
3734 mem_free (&keylist);
3735 rfc822_free_address (&tmp);
3736 rfc822_free_address (&addr);
3742 && (k_info = crypt_getkeybyaddr (q, KEYFLAG_CANENCRYPT,
3743 app, &forced_valid)) == NULL) {
3744 snprintf (buf, sizeof (buf), _("Enter keyID for %s: "), q->mailbox);
3746 if ((key = crypt_ask_for_key (buf, q->mailbox, KEYFLAG_CANENCRYPT,
3752 &forced_valid)) == NULL) {
3753 mem_free (&keylist);
3754 rfc822_free_address (&tmp);
3755 rfc822_free_address (&addr);
3763 const char *s = crypt_fpr (key);
3766 if (key->flags & KEYFLAG_ISX509)
3767 *r_application &= ~APPLICATION_PGP;
3768 if (!(key->flags & KEYFLAG_ISX509))
3769 *r_application &= ~APPLICATION_SMIME;
3772 keylist_size += str_len (s) + 4 + 1;
3773 mem_realloc (&keylist, keylist_size);
3774 sprintf (keylist + keylist_used, "%s0x%s%s", /* __SPRINTF_CHECKED__ */
3775 keylist_used ? " " : "", s, forced_valid ? "!" : "");
3777 keylist_used = str_len (keylist);
3779 crypt_free_key (&key);
3780 rfc822_free_address (&addr);
3782 rfc822_free_address (&tmp);
3786 char *pgp_gpgme_findkeys (ADDRESS * to, ADDRESS * cc, ADDRESS * bcc)
3788 return find_keys (to, cc, bcc, APPLICATION_PGP);
3791 char *smime_gpgme_findkeys (ADDRESS * to, ADDRESS * cc, ADDRESS * bcc)
3793 return find_keys (to, cc, bcc, APPLICATION_SMIME);
3797 * Implementation of `init'.
3800 /* Initialization. */
3801 static void init_gpgme (void)
3803 /* Make sure that gpg-agent is running. */
3804 if (!getenv ("GPG_AGENT_INFO")) {
3805 mutt_error ("\nUsing GPGME backend, although no gpg-agent is running");
3806 if (mutt_any_key_to_continue (NULL) == -1)
3811 void pgp_gpgme_init (void)
3816 void smime_gpgme_init (void)
3820 static int gpgme_send_menu (HEADER * msg, int *redraw, int is_smime)
3823 char input_signas[SHORT_STRING];
3826 if (msg->security & APPLICATION_PGP)
3828 else if (msg->security & APPLICATION_SMIME)
3833 mutt_multi_choice (_
3834 ("S/MIME (e)ncrypt, (s)ign, sign (a)s, (b)oth, (p)gp or (c)lear?"),
3838 mutt_multi_choice (_
3839 ("PGP (e)ncrypt, (s)ign, sign (a)s, (b)oth, s/(m)ime or (c)lear?"),
3843 case 1: /* (e)ncrypt */
3844 msg->security |= (is_smime ? SMIMEENCRYPT : PGPENCRYPT);
3845 msg->security &= ~(is_smime ? SMIMESIGN : PGPSIGN);
3848 case 2: /* (s)ign */
3849 msg->security |= (is_smime ? SMIMESIGN : PGPSIGN);
3850 msg->security &= ~(is_smime ? SMIMEENCRYPT : PGPENCRYPT);
3853 case 3: /* sign (a)s */
3854 /* unset_option(OPTCRYPTCHECKTRUST); */
3855 if ((p = crypt_ask_for_key (_("Sign as: "), NULL, KEYFLAG_CANSIGN,
3856 is_smime ? APPLICATION_SMIME :
3857 APPLICATION_PGP, NULL))) {
3858 snprintf (input_signas, sizeof (input_signas), "0x%s", crypt_keyid (p));
3859 str_replace (is_smime ? &SmimeDefaultKey : &PgpSignAs,
3861 crypt_free_key (&p);
3863 msg->security |= (is_smime ? SMIMESIGN : PGPSIGN);
3867 msg->security &= (is_smime ? ~SMIMESIGN : ~PGPSIGN);
3870 *redraw = REDRAW_FULL;
3873 case 4: /* (b)oth */
3875 (is_smime ? (SMIMEENCRYPT | SMIMESIGN) : (PGPENCRYPT | PGPSIGN));
3878 case 5: /* (p)gp or s/(m)ime */
3879 is_smime = !is_smime;
3882 case 6: /* (c)lear */
3887 if (choice == 6 || choice == 7);
3888 else if (is_smime) {
3889 msg->security &= ~APPLICATION_PGP;
3890 msg->security |= APPLICATION_SMIME;
3893 msg->security &= ~APPLICATION_SMIME;
3894 msg->security |= APPLICATION_PGP;
3897 return (msg->security);
3900 int pgp_gpgme_send_menu (HEADER * msg, int *redraw)
3902 return gpgme_send_menu (msg, redraw, 0);
3905 int smime_gpgme_send_menu (HEADER * msg, int *redraw)
3907 return gpgme_send_menu (msg, redraw, 1);
3910 static int verify_sender (HEADER * h, gpgme_protocol_t protocol)
3912 ADDRESS *sender = NULL;
3913 unsigned int ret = 1;
3916 h->env->from = mutt_expand_aliases (h->env->from);
3917 sender = h->env->from;
3919 else if (h->env->sender) {
3920 h->env->sender = mutt_expand_aliases (h->env->sender);
3921 sender = h->env->sender;
3925 if (signature_key) {
3926 gpgme_key_t key = signature_key;
3927 gpgme_user_id_t uid = NULL;
3928 int sender_length = 0;
3931 sender_length = str_len (sender->mailbox);
3932 for (uid = key->uids; uid && ret; uid = uid->next) {
3933 uid_length = str_len (uid->email);
3934 if (1 && (uid->email[0] == '<')
3935 && (uid->email[uid_length - 1] == '>')
3936 && (uid_length == sender_length + 2)
3937 && (!strncmp (uid->email + 1, sender->mailbox, sender_length)))
3942 mutt_any_key_to_continue ("Failed to verify sender");
3945 mutt_any_key_to_continue ("Failed to figure out sender");
3947 if (signature_key) {
3948 gpgme_key_release (signature_key);
3949 signature_key = NULL;
3955 int smime_gpgme_verify_sender (HEADER * h)
3957 return verify_sender (h, GPGME_PROTOCOL_CMS);