1 /* crypt-gpgme.c - GPGME based crypto operations
2 * Copyright (C) 1996,1997 Michael R. Elkins <me@cs.hmc.edu>
3 * Copyright (C) 1998,1999,2000 Thomas Roessler <roessler@guug.de>
4 * Copyright (C) 2001 Thomas Roessler <roessler@guug.de>
5 * Oliver Ehli <elmy@acm.org>
6 * Copyright (C) 2002, 2003, 2004 g10 Code GmbH
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 2 of the License, or
11 * (at your option) any later version.
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, write to the Free Software
20 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA.
27 #ifdef CRYPT_BACKEND_GPGME
30 #include "mutt_crypt.h"
31 #include "mutt_menu.h"
32 #include "mutt_curses.h"
51 #ifdef HAVE_LANGINFO_D_T_FMT
55 #ifdef HAVE_SYS_TIME_H
56 # include <sys/time.h>
59 #ifdef HAVE_SYS_RESOURCE_H
60 # include <sys/resource.h>
66 #define digitp(p) (*(p) >= '0' && *(p) <= '9')
67 #define hexdigitp(a) (digitp (a) \
68 || (*(a) >= 'A' && *(a) <= 'F') \
69 || (*(a) >= 'a' && *(a) <= 'f'))
70 #define xtoi_1(p) (*(p) <= '9'? (*(p)- '0'): \
71 *(p) <= 'F'? (*(p)-'A'+10):(*(p)-'a'+10))
72 #define xtoi_2(p) ((xtoi_1(p) * 16) + xtoi_1((p)+1))
74 /* Values used for comparing addresses. */
75 #define CRYPT_KV_VALID 1
76 #define CRYPT_KV_ADDR 2
77 #define CRYPT_KV_STRING 4
78 #define CRYPT_KV_STRONGID 8
79 #define CRYPT_KV_MATCH (CRYPT_KV_ADDR|CRYPT_KV_STRING)
88 struct crypt_cache *next;
96 /* We work based on user IDs, getting from a user ID to the key is
97 check and does not need any memory (gpgme uses reference counting). */
98 typedef struct crypt_keyinfo {
99 struct crypt_keyinfo *next;
101 int idx; /* and the user ID at this index */
102 const char *uid; /* and for convenience point to this user ID */
103 unsigned int flags; /* global and per uid flags (for convenience) */
106 typedef struct crypt_entry {
112 static struct crypt_cache *id_defaults = NULL;
113 static gpgme_key_t signature_key = NULL;
116 * General helper functions.
119 /* return true when S pints to a didgit or letter. */
120 static int digit_or_letter (const unsigned char *s)
122 return ((*s >= '0' && *s < '9')
123 || (*s >= 'A' && *s <= 'Z')
124 || (*s >= 'a' && *s <= 'z'));
128 /* Print the utf-8 encoded string BUF of length LEN bytes to stream
129 FP. Convert the character set. */
130 static void print_utf8 (FILE * fp, const char *buf, size_t len)
134 tstr = safe_malloc (len + 1);
135 memcpy (tstr, buf, len);
137 mutt_convert_string (&tstr, "utf-8", Charset, M_ICONV_HOOK_FROM);
147 /* Return the keyID for the key K. Note that this string is valid as
148 long as K is valid */
149 static const char *crypt_keyid (crypt_key_t * k)
151 const char *s = "????????";
153 if (k->kobj && k->kobj->subkeys) {
154 s = k->kobj->subkeys->keyid;
155 if ((!option (OPTPGPLONGIDS)) && (strlen (s) == 16))
156 /* Return only the short keyID. */
163 /* Return the hexstring fingerprint from the key K. */
164 static const char *crypt_fpr (crypt_key_t * k)
168 if (k->kobj && k->kobj->subkeys)
169 s = k->kobj->subkeys->fpr;
174 /* Parse FLAGS and return a statically allocated(!) string with them. */
175 static char *crypt_key_abilities (int flags)
179 if (!(flags & KEYFLAG_CANENCRYPT))
181 else if (flags & KEYFLAG_PREFER_SIGNING)
186 if (!(flags & KEYFLAG_CANSIGN))
188 else if (flags & KEYFLAG_PREFER_ENCRYPTION)
198 /* Parse FLAGS and return a character describing the most important flag. */
199 static char crypt_flags (int flags)
201 if (flags & KEYFLAG_REVOKED)
203 else if (flags & KEYFLAG_EXPIRED)
205 else if (flags & KEYFLAG_DISABLED)
207 else if (flags & KEYFLAG_CRITICAL)
213 /* Return a copy of KEY. */
214 static crypt_key_t *crypt_copy_key (crypt_key_t * key)
218 k = safe_calloc (1, sizeof *k);
220 gpgme_key_ref (key->kobj);
223 k->flags = key->flags;
228 /* Release all the keys at the address of KEYLIST and set the address
230 static void crypt_free_key (crypt_key_t ** keylist)
233 crypt_key_t *k = (*keylist)->next;
240 /* Return trute when key K is valid. */
241 static int crypt_key_is_valid (crypt_key_t * k)
243 if (k->flags & KEYFLAG_CANTUSE)
248 /* Return true whe validity of KEY is sufficient. */
249 static int crypt_id_is_strong (crypt_key_t * key)
251 gpgme_validity_t val = GPGME_VALIDITY_UNKNOWN;
252 gpgme_user_id_t uid = NULL;
253 unsigned int is_strong = 0;
256 if ((key->flags & KEYFLAG_ISX509))
259 for (i = 0, uid = key->kobj->uids; (i < key->idx) && uid;
260 i++, uid = uid->next);
265 case GPGME_VALIDITY_UNKNOWN:
266 case GPGME_VALIDITY_UNDEFINED:
267 case GPGME_VALIDITY_NEVER:
268 case GPGME_VALIDITY_MARGINAL:
272 case GPGME_VALIDITY_FULL:
273 case GPGME_VALIDITY_ULTIMATE:
281 /* Return true when the KEY is valid, i.e. not marked as unusable. */
282 static int crypt_id_is_valid (crypt_key_t * key)
284 return !(key->flags & KEYFLAG_CANTUSE);
287 /* Return a bit vector describing how well the addresses ADDR and
288 U_ADDR match and whether KEY is valid. */
289 static int crypt_id_matches_addr (ADDRESS * addr, ADDRESS * u_addr,
294 if (crypt_id_is_valid (key))
295 rv |= CRYPT_KV_VALID;
297 if (crypt_id_is_strong (key))
298 rv |= CRYPT_KV_STRONGID;
300 if (addr->mailbox && u_addr->mailbox
301 && mutt_strcasecmp (addr->mailbox, u_addr->mailbox) == 0)
304 if (addr->personal && u_addr->personal
305 && mutt_strcasecmp (addr->personal, u_addr->personal) == 0)
306 rv |= CRYPT_KV_STRING;
313 * GPGME convenient functions.
316 /* Create a new gpgme context and return it. With FOR_SMIME set to
317 true, the protocol of the context is set to CMS. */
318 static gpgme_ctx_t create_gpgme_context (int for_smime)
323 err = gpgme_new (&ctx);
325 mutt_error ("error creating gpgme context: %s\n", gpgme_strerror (err));
331 err = gpgme_set_protocol (ctx, GPGME_PROTOCOL_CMS);
333 mutt_error ("error enabling CMS protocol: %s\n", gpgme_strerror (err));
342 /* Create a new gpgme data object. This is a wrapper to die on
344 static gpgme_data_t create_gpgme_data (void)
349 err = gpgme_data_new (&data);
351 mutt_error ("error creating gpgme data object: %s\n",
352 gpgme_strerror (err));
359 /* Create a new GPGME Data object from the mail body A. With CONVERT
360 passed as true, the lines are converted to CR,LF if required.
361 Return NULL on error or the gpgme_data_t object on success. */
362 static gpgme_data_t body_to_data_object (BODY * a, int convert)
364 char tempfile[_POSIX_PATH_MAX];
369 mutt_mktemp (tempfile);
370 fptmp = safe_fopen (tempfile, "w+");
372 mutt_perror (tempfile);
376 mutt_write_mime_header (a, fptmp);
378 mutt_write_mime_body (a, fptmp);
382 unsigned char buf[1];
384 data = create_gpgme_data ();
386 while ((c = fgetc (fptmp)) != EOF) {
390 if (c == '\n' && !hadcr) {
392 gpgme_data_write (data, buf, 1);
397 /* FIXME: This is quite suboptimal */
399 gpgme_data_write (data, buf, 1);
402 gpgme_data_seek (data, 0, SEEK_SET);
406 err = gpgme_data_new_from_file (&data, tempfile, 1);
410 mutt_error ("error allocating data object: %s\n", gpgme_strerror (err));
417 /* Create a GPGME data object from the stream FP but limit the object
418 to LENGTH bytes starting at OFFSET bytes from the beginning of the
420 static gpgme_data_t file_to_data_object (FILE * fp, long offset, long length)
425 err = gpgme_data_new_from_filepart (&data, NULL, fp, offset, length);
427 mutt_error ("error allocating data object: %s\n", gpgme_strerror (err));
434 /* Write a GPGME data object to the stream FP. */
435 static int data_object_to_stream (gpgme_data_t data, FILE * fp)
441 err = ((gpgme_data_seek (data, 0, SEEK_SET) == -1)
442 ? gpgme_error_from_errno (errno) : 0);
444 mutt_error ("error rewinding data object: %s\n", gpgme_strerror (err));
448 while ((nread = gpgme_data_read (data, buf, sizeof (buf)))) {
449 /* fixme: we are not really converting CRLF to LF but just
450 skipping CR. Doing it correctly needs a more complex logic */
451 for (p = buf; nread; p++, nread--) {
457 mutt_perror ("[tempfile]");
462 mutt_error ("error reading data object: %s\n", strerror (errno));
468 /* Copy a data object to a newly created temporay file and return that
469 filename. Caller must free. With RET_FP not NULL, don't close the
470 stream but return it there. */
471 static char *data_object_to_tempfile (gpgme_data_t data, FILE ** ret_fp)
474 char tempfile[_POSIX_PATH_MAX];
478 mutt_mktemp (tempfile);
479 fp = safe_fopen (tempfile, "w+");
481 mutt_perror (tempfile);
485 err = ((gpgme_data_seek (data, 0, SEEK_SET) == -1)
486 ? gpgme_error_from_errno (errno) : 0);
490 while ((nread = gpgme_data_read (data, buf, sizeof (buf)))) {
491 if (fwrite (buf, nread, 1, fp) != 1) {
492 mutt_perror (tempfile);
504 mutt_error ("error reading data object: %s\n", gpgme_strerror (err));
511 return safe_strdup (tempfile);
515 /* Create a GpgmeRecipientSet from the keys in the string KEYLIST.
516 The keys must be space delimited. */
517 static gpgme_key_t *create_recipient_set (const char *keylist,
518 gpgme_protocol_t protocol)
524 gpgme_key_t *rset = NULL;
525 unsigned int rset_n = 0;
526 gpgme_key_t key = NULL;
527 gpgme_ctx_t context = NULL;
529 err = gpgme_new (&context);
531 err = gpgme_set_protocol (context, protocol);
538 for (i = 0; *s && *s != ' ' && i < sizeof (buf) - 1;)
542 if (i > 1 && buf[i - 1] == '!') {
543 /* The user selected to override the valididy of that
547 err = gpgme_get_key (context, buf, &key, 0);
549 key->uids->validity = GPGME_VALIDITY_FULL;
553 err = gpgme_get_key (context, buf, &key, 0);
556 safe_realloc (&rset, sizeof (*rset) * (rset_n + 1));
557 rset[rset_n++] = key;
560 mutt_error ("error adding recipient `%s': %s\n",
561 buf, gpgme_strerror (err));
569 /* NULL terminate. */
570 safe_realloc (&rset, sizeof (*rset) * (rset_n + 1));
571 rset[rset_n++] = NULL;
574 gpgme_release (context);
580 /* Make sure that the correct signer is set. Returns 0 on success. */
581 static int set_signer (gpgme_ctx_t ctx, int for_smime)
583 char *signid = for_smime ? SmimeDefaultKey : PgpSignAs;
586 gpgme_key_t key, key2;
588 if (!signid || !*signid)
591 listctx = create_gpgme_context (for_smime);
592 err = gpgme_op_keylist_start (listctx, signid, 1);
594 err = gpgme_op_keylist_next (listctx, &key);
596 gpgme_release (listctx);
597 mutt_error (_("secret key `%s' not found: %s\n"),
598 signid, gpgme_strerror (err));
601 err = gpgme_op_keylist_next (listctx, &key2);
603 gpgme_key_release (key);
604 gpgme_key_release (key2);
605 gpgme_release (listctx);
606 mutt_error (_("ambiguous specfication of secret key `%s'\n"), signid);
609 gpgme_op_keylist_end (listctx);
610 gpgme_release (listctx);
612 gpgme_signers_clear (ctx);
613 err = gpgme_signers_add (ctx, key);
614 gpgme_key_release (key);
616 mutt_error (_("error setting secret key `%s': %s\n"),
617 signid, gpgme_strerror (err));
624 /* Encrypt the gpgme data object PLAINTEXT to the recipients in RSET
625 and return an allocated filename to a temporary file containing the
626 enciphered text. With USE_SMIME set to true, the smime backend is
627 used. With COMBINED_SIGNED a PGP message is signed and
628 encrypted. Returns NULL in case of error */
629 static char *encrypt_gpgme_object (gpgme_data_t plaintext, gpgme_key_t * rset,
630 int use_smime, int combined_signed)
634 gpgme_data_t ciphertext;
637 ctx = create_gpgme_context (use_smime);
639 gpgme_set_armor (ctx, 1);
641 ciphertext = create_gpgme_data ();
643 if (combined_signed) {
644 if (set_signer (ctx, use_smime)) {
645 gpgme_data_release (ciphertext);
649 err = gpgme_op_encrypt_sign (ctx, rset, GPGME_ENCRYPT_ALWAYS_TRUST,
650 plaintext, ciphertext);
653 err = gpgme_op_encrypt (ctx, rset, GPGME_ENCRYPT_ALWAYS_TRUST,
654 plaintext, ciphertext);
655 mutt_need_hard_redraw ();
657 mutt_error ("error encrypting data: %s\n", gpgme_strerror (err));
658 gpgme_data_release (ciphertext);
665 outfile = data_object_to_tempfile (ciphertext, NULL);
666 gpgme_data_release (ciphertext);
670 /* Find the "micalg" parameter from the last Gpgme operation on
671 context CTX. It is expected that this operation was a sign
672 operation. Return the algorithm name as a C string in buffer BUF
673 which must have been allocated by the caller with size BUFLEN.
674 Returns 0 on success or -1 in case of an error. The return string
675 is truncted to BUFLEN - 1. */
676 static int get_micalg (gpgme_ctx_t ctx, char *buf, size_t buflen)
678 gpgme_sign_result_t result = NULL;
679 const char *algorithm_name = NULL;
685 result = gpgme_op_sign_result (ctx);
687 algorithm_name = gpgme_hash_algo_name (result->signatures->hash_algo);
688 if (algorithm_name) {
689 strncpy (buf, algorithm_name, buflen - 1);
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 = safe_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 = safe_strdup ("pkcs7-signature");
788 mutt_set_parameter ("name", "smime.p7s", &t->parameter);
789 t->encoding = ENCBASE64;
791 t->disposition = DISPATTACH;
792 t->d_filename = safe_strdup ("smime.p7s");
795 t->subtype = safe_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 = safe_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 = safe_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 = safe_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 = safe_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 = safe_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 = safe_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 occured"), 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 && !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 = safe_malloc (strlen (prefix) + strlen (s) * 4 + 2);
1037 strcpy (buf, prefix); /* __STRCPY_CHECKED__ */
1038 p = buf + strlen (buf);
1039 if (is_pgp && 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 signature;
1287 result = gpgme_op_verify_result (ctx);
1289 for (signature = result->signatures; signature;
1290 signature = signature->next) {
1291 if (signature->notations) {
1292 state_attach_puts ("*** Begin Notation (signature by: ", s);
1293 state_attach_puts (signature->fpr, s);
1294 state_attach_puts (") ***\n", s);
1295 for (notation = signature->notations; notation;
1296 notation = notation->next) {
1297 if (notation->name) {
1298 state_attach_puts (notation->name, s);
1299 state_attach_puts ("=", s);
1301 if (notation->value) {
1302 state_attach_puts (notation->value, s);
1303 if (!(*notation->value
1304 && (notation->value[strlen (notation->value) - 1] ==
1306 state_attach_puts ("\n", s);
1309 state_attach_puts ("*** End Notation ***\n", s);
1315 gpgme_release (ctx);
1317 state_attach_puts (_("[-- End signature information --]\n\n"), s);
1318 dprint (1, (debugfile, "verify_one: returning %d.\n", badsig));
1320 return badsig ? 1 : anywarn ? 2 : 0;
1323 int pgp_gpgme_verify_one (BODY * sigbdy, STATE * s, const char *tempfile)
1325 return verify_one (sigbdy, s, tempfile, 0);
1328 int smime_gpgme_verify_one (BODY * sigbdy, STATE * s, const char *tempfile)
1330 return verify_one (sigbdy, s, tempfile, 1);
1334 * Implementation of `decrypt_part'.
1337 /* Decrypt a PGP or SMIME message (depending on the boolean flag
1338 IS_SMIME) with body A described further by state S. Write
1339 plaintext out to file FPOUT and return a new body. For PGP returns
1340 a flag in R_IS_SIGNED to indicate whether this is a combined
1341 encrypted and signed message, for S/MIME it returns true when it is
1342 not a encrypted but a signed message. */
1343 static BODY *decrypt_part (BODY * a, STATE * s, FILE * fpout, int is_smime,
1350 gpgme_data_t ciphertext, plaintext;
1351 int maybe_signed = 0;
1358 ctx = create_gpgme_context (is_smime);
1361 /* Make a data object from the body, create context etc. */
1362 ciphertext = file_to_data_object (s->fpin, a->offset, a->length);
1365 plaintext = create_gpgme_data ();
1367 /* Do the decryption or the verification in case of the S/MIME hack. */
1368 if ((!is_smime) || maybe_signed) {
1370 err = gpgme_op_decrypt_verify (ctx, ciphertext, plaintext);
1371 else if (maybe_signed)
1372 err = gpgme_op_verify (ctx, ciphertext, NULL, plaintext);
1375 /* Check wether signatures have been verified. */
1376 gpgme_verify_result_t verify_result = gpgme_op_verify_result (ctx);
1378 if (verify_result->signatures)
1383 err = gpgme_op_decrypt (ctx, ciphertext, plaintext);
1384 gpgme_data_release (ciphertext);
1386 if (is_smime && !maybe_signed && gpg_err_code (err) == GPG_ERR_NO_DATA) {
1387 /* Check whether this might be a signed message despite what
1388 the mime header told us. Retry then. gpgsm returns the
1389 error information "unsupported Algorithm '?'" but gpgme
1390 will not store this unknown algorithm, thus we test that
1391 it has not been set. */
1392 gpgme_decrypt_result_t result;
1394 result = gpgme_op_decrypt_result (ctx);
1395 if (!result->unsupported_algorithm) {
1397 gpgme_data_release (plaintext);
1401 mutt_need_hard_redraw ();
1402 if ((s->flags & M_DISPLAY)) {
1405 snprintf (buf, sizeof (buf) - 1,
1406 _("[-- Error: decryption failed: %s --]\n\n"),
1407 gpgme_strerror (err));
1408 state_attach_puts (buf, s);
1410 gpgme_data_release (plaintext);
1411 gpgme_release (ctx);
1414 mutt_need_hard_redraw ();
1416 /* Read the output from GPGME, and make sure to change CRLF to LF,
1417 otherwise read_mime_header has a hard time parsing the message. */
1418 if (data_object_to_stream (plaintext, fpout)) {
1419 gpgme_data_release (plaintext);
1420 gpgme_release (ctx);
1423 gpgme_data_release (plaintext);
1425 a->is_signed_data = 0;
1431 a->is_signed_data = 1;
1433 *r_is_signed = -1; /* A signature exists. */
1435 if ((s->flags & M_DISPLAY))
1436 state_attach_puts (_("[-- Begin signature " "information --]\n"), s);
1437 for (idx = 0; (res = show_one_sig_status (ctx, idx, s)) != -1; idx++) {
1443 if (!anybad && idx && r_is_signed && *r_is_signed)
1444 *r_is_signed = anywarn ? 2 : 1; /* Good signature. */
1446 if ((s->flags & M_DISPLAY))
1447 state_attach_puts (_("[-- End signature " "information --]\n\n"), s);
1449 gpgme_release (ctx);
1454 tattach = mutt_read_mime_header (fpout, 0);
1457 * Need to set the length of this body part.
1459 fstat (fileno (fpout), &info);
1460 tattach->length = info.st_size - tattach->offset;
1462 tattach->warnsig = anywarn;
1464 /* See if we need to recurse on this MIME part. */
1465 mutt_parse_part (fpout, tattach);
1471 /* Decrypt a PGP/MIME message in FPIN and B and return a new body and
1472 the stream in CUR and FPOUT. Returns 0 on success. */
1473 int pgp_gpgme_decrypt_mime (FILE * fpin, FILE ** fpout, BODY * b, BODY ** cur)
1475 char tempfile[_POSIX_PATH_MAX];
1477 BODY *first_part = b;
1480 first_part->goodsig = 0;
1481 first_part->warnsig = 0;
1483 if (!mutt_is_multipart_encrypted (b))
1486 if (!b->parts || !b->parts->next)
1491 memset (&s, 0, sizeof (s));
1493 mutt_mktemp (tempfile);
1494 if (!(*fpout = safe_fopen (tempfile, "w+"))) {
1495 mutt_perror (tempfile);
1500 *cur = decrypt_part (b, &s, *fpout, 0, &is_signed);
1503 first_part->goodsig = 1;
1505 return *cur ? 0 : -1;
1509 /* Decrypt a S/MIME message in FPIN and B and return a new body and
1510 the stream in CUR and FPOUT. Returns 0 on success. */
1511 int smime_gpgme_decrypt_mime (FILE * fpin, FILE ** fpout, BODY * b,
1514 char tempfile[_POSIX_PATH_MAX];
1518 long saved_b_offset;
1519 size_t saved_b_length;
1522 if (!mutt_is_application_smime (b))
1528 /* Decode the body - we need to pass binary CMS to the
1529 backend. The backend allows for Base64 encoded data but it does
1530 not allow for QP which I have seen in some messages. So better
1532 saved_b_type = b->type;
1533 saved_b_offset = b->offset;
1534 saved_b_length = b->length;
1535 memset (&s, 0, sizeof (s));
1537 fseek (s.fpin, b->offset, 0);
1538 mutt_mktemp (tempfile);
1539 if (!(tmpfp = safe_fopen (tempfile, "w+"))) {
1540 mutt_perror (tempfile);
1543 mutt_unlink (tempfile);
1546 mutt_decode_attachment (b, &s);
1548 b->length = ftell (s.fpout);
1552 memset (&s, 0, sizeof (s));
1555 mutt_mktemp (tempfile);
1556 if (!(*fpout = safe_fopen (tempfile, "w+"))) {
1557 mutt_perror (tempfile);
1560 mutt_unlink (tempfile);
1562 *cur = decrypt_part (b, &s, *fpout, 1, &is_signed);
1564 (*cur)->goodsig = is_signed > 0;
1565 b->type = saved_b_type;
1566 b->length = saved_b_length;
1567 b->offset = saved_b_offset;
1570 if (*cur && !is_signed && !(*cur)->parts
1571 && mutt_is_application_smime (*cur)) {
1572 /* Assume that this is a opaque signed s/mime message. This is
1573 an ugly way of doing it but we have anyway a problem with
1574 arbitrary encoded S/MIME messages: Only the outer part may be
1575 encrypted. The entire mime parsing should be revamped,
1576 probably by keeping the temportary files so that we don't
1577 need to decrypt them all the time. Inner parts of an
1578 encrypted part can then pint into this file and tehre won't
1579 never be a need to decrypt again. This needs a partial
1580 rewrite of the MIME engine. */
1584 saved_b_type = bb->type;
1585 saved_b_offset = bb->offset;
1586 saved_b_length = bb->length;
1587 memset (&s, 0, sizeof (s));
1589 fseek (s.fpin, bb->offset, 0);
1590 mutt_mktemp (tempfile);
1591 if (!(tmpfp = safe_fopen (tempfile, "w+"))) {
1592 mutt_perror (tempfile);
1595 mutt_unlink (tempfile);
1598 mutt_decode_attachment (bb, &s);
1600 bb->length = ftell (s.fpout);
1605 memset (&s, 0, sizeof (s));
1608 mutt_mktemp (tempfile);
1609 if (!(*fpout = safe_fopen (tempfile, "w+"))) {
1610 mutt_perror (tempfile);
1613 mutt_unlink (tempfile);
1615 tmp_b = decrypt_part (bb, &s, *fpout, 1, &is_signed);
1617 tmp_b->goodsig = is_signed > 0;
1618 bb->type = saved_b_type;
1619 bb->length = saved_b_length;
1620 bb->offset = saved_b_offset;
1623 mutt_free_body (cur);
1626 return *cur ? 0 : -1;
1631 * Implementation of `pgp_check_traditional'.
1634 static int pgp_check_traditional_one_body (FILE * fp, BODY * b,
1637 char tempfile[_POSIX_PATH_MAX];
1638 char buf[HUGE_STRING];
1644 if (b->type != TYPETEXT)
1647 if (tagged_only && !b->tagged)
1650 mutt_mktemp (tempfile);
1651 if (mutt_decode_save_attachment (fp, b, tempfile, 0, 0) != 0) {
1656 if ((tfp = fopen (tempfile, "r")) == NULL) {
1661 while (fgets (buf, sizeof (buf), tfp)) {
1662 if (!mutt_strncmp ("-----BEGIN PGP ", buf, 15)) {
1663 if (!mutt_strcmp ("MESSAGE-----\n", buf + 15))
1665 else if (!mutt_strcmp ("SIGNED MESSAGE-----\n", buf + 15))
1675 /* fix the content type */
1677 mutt_set_parameter ("format", "fixed", &b->parameter);
1678 mutt_set_parameter ("x-action", enc ? "pgp-encrypted" : "pgp-signed",
1684 int pgp_gpgme_check_traditional (FILE * fp, BODY * b, int tagged_only)
1689 for (; b; b = b->next) {
1690 if (is_multipart (b))
1691 rv = (pgp_gpgme_check_traditional (fp, b->parts, tagged_only) || rv);
1692 else if (b->type == TYPETEXT) {
1693 if ((r = mutt_is_application_pgp (b)))
1696 rv = (pgp_check_traditional_one_body (fp, b, tagged_only) || rv);
1704 * Implementation of `application_handler'.
1708 Copy a clearsigned message, and strip the signature and PGP's
1711 XXX - charset handling: We assume that it is safe to do
1712 character set decoding first, dash decoding second here, while
1713 we do it the other way around in the main handler.
1715 (Note that we aren't worse than Outlook & Cie in this, and also
1716 note that we can successfully handle anything produced by any
1717 existing versions of mutt.) */
1719 static void copy_clearsigned (gpgme_data_t data, STATE * s, char *charset)
1721 char buf[HUGE_STRING];
1722 short complete, armor_header;
1727 fname = data_object_to_tempfile (data, &fp);
1733 fc = fgetconv_open (fp, charset, Charset, M_ICONV_HOOK_FROM);
1735 for (complete = 1, armor_header = 1;
1736 fgetconvs (buf, sizeof (buf), fc) != NULL;
1737 complete = strchr (buf, '\n') != NULL) {
1740 state_puts (buf, s);
1744 if (!mutt_strcmp (buf, "-----BEGIN PGP SIGNATURE-----\n"))
1754 state_puts (s->prefix, s);
1756 if (buf[0] == '-' && buf[1] == ' ')
1757 state_puts (buf + 2, s);
1759 state_puts (buf, s);
1762 fgetconv_close (&fc);
1767 /* Support for classic_application/pgp */
1768 void pgp_gpgme_application_handler (BODY * m, STATE * s)
1770 int needpass = -1, pgp_keyblock = 0;
1773 long bytes, last_pos, offset;
1774 char buf[HUGE_STRING];
1775 FILE *pgpout = NULL;
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 dprint (2, (debugfile, "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 strfcpy (body_charset, "iso-8859-1", sizeof body_charset);
1793 fseek (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 = ftell (s->fpin);
1801 bytes -= (offset - last_pos); /* don't rely on mutt_strlen(buf) */
1804 if (!mutt_strncmp ("-----BEGIN PGP ", buf, 15)) {
1806 start_pos = last_pos;
1808 if (!mutt_strcmp ("MESSAGE-----\n", buf + 15))
1810 else if (!mutt_strcmp ("SIGNED MESSAGE-----\n", buf + 15)) {
1814 else if (!option (OPTDONTHANDLEPGPKEYS) &&
1815 !mutt_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, strlen (buf));
1832 while (bytes > 0 && fgets (buf, sizeof (buf) - 1, s->fpin) != NULL) {
1833 offset = ftell (s->fpin);
1834 bytes -= (offset - last_pos); /* don't rely on mutt_strlen(buf) */
1837 gpgme_data_write (armored_data, buf, strlen (buf));
1839 if ((needpass && !mutt_strcmp ("-----END PGP MESSAGE-----\n", buf))
1841 && (!mutt_strcmp ("-----END PGP SIGNATURE-----\n", buf)
1842 || !mutt_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);
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 dprint (2, (debugfile, "Leaving pgp_application_pgp handler\n"));
1994 * Implementation of `encrypted_handler'.
1997 /* MIME handler for pgp/mime encrypted messages. */
1998 void pgp_gpgme_encrypted_handler (BODY * a, STATE * s)
2000 char tempfile[_POSIX_PATH_MAX];
2003 BODY *orig_body = a;
2006 dprint (2, (debugfile, "Entering pgp_encrypted handler\n"));
2008 if (!a || a->type != TYPEAPPLICATION || !a->subtype
2009 || ascii_strcasecmp ("pgp-encrypted", a->subtype)
2010 || !a->next || a->next->type != TYPEAPPLICATION || !a->next->subtype
2011 || ascii_strcasecmp ("octet-stream", a->next->subtype)) {
2012 if (s->flags & M_DISPLAY)
2013 state_attach_puts (_("[-- Error: malformed PGP/MIME message! --]\n\n"),
2018 /* Move forward to the application/pgp-encrypted body. */
2021 mutt_mktemp (tempfile);
2022 if (!(fpout = safe_fopen (tempfile, "w+"))) {
2023 if (s->flags & M_DISPLAY)
2024 state_attach_puts (_("[-- Error: could not create temporary file! "
2029 tattach = decrypt_part (a, s, fpout, 0, &is_signed);
2031 tattach->goodsig = is_signed > 0;
2033 if (s->flags & M_DISPLAY)
2034 state_attach_puts (is_signed ?
2036 ("[-- The following data is PGP/MIME signed and encrypted --]\n\n")
2039 ("[-- The following data is PGP/MIME encrypted --]\n\n"),
2043 FILE *savefp = s->fpin;
2046 mutt_body_handler (tattach, s);
2051 * if a multipart/signed is the _only_ sub-part of a
2052 * multipart/encrypted, cache signature verification
2055 if (mutt_is_multipart_signed (tattach) && !tattach->next)
2056 orig_body->goodsig |= tattach->goodsig;
2058 if (s->flags & M_DISPLAY) {
2059 state_puts ("\n", s);
2060 state_attach_puts (is_signed ?
2062 ("[-- End of PGP/MIME signed and encrypted data --]\n")
2063 : _("[-- End of PGP/MIME encrypted data --]\n"), s);
2066 mutt_free_body (&tattach);
2070 mutt_unlink (tempfile);
2071 dprint (2, (debugfile, "Leaving pgp_encrypted handler\n"));
2074 /* Support for application/smime */
2075 void smime_gpgme_application_handler (BODY * a, STATE * s)
2077 char tempfile[_POSIX_PATH_MAX];
2083 dprint (2, (debugfile, "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")
2103 ("[-- The following data is S/MIME encrypted --]\n\n"),
2107 FILE *savefp = s->fpin;
2110 mutt_body_handler (tattach, s);
2115 * if a multipart/signed is the _only_ sub-part of a
2116 * multipart/encrypted, cache signature verification
2119 if (mutt_is_multipart_signed (tattach) && !tattach->next) {
2120 if (!(a->goodsig = tattach->goodsig))
2121 a->warnsig = tattach->warnsig;
2123 else if (tattach->goodsig) {
2125 a->warnsig = tattach->warnsig;
2128 if (s->flags & M_DISPLAY) {
2129 state_puts ("\n", s);
2130 state_attach_puts (is_signed ?
2131 _("[-- End of S/MIME signed data --]\n") :
2132 _("[-- End of S/MIME encrypted data --]\n"), s);
2135 mutt_free_body (&tattach);
2139 mutt_unlink (tempfile);
2140 dprint (2, (debugfile, "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 = mutt_strcasecmp ((*s)->uid, (*t)->uid)))
2377 return mutt_strcasecmp (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 = mutt_strcasecmp (crypt_keyid (*s), crypt_keyid (*t))))
2397 return mutt_strcasecmp ((*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 mutt_strcasecmp ((*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 = mutt_strcasecmp ((*s)->uid, (*t)->uid)))
2470 return (mutt_strcasecmp (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 (!strcmp (dn->key, key)) {
2489 print_utf8 (fp, dn->value, strlen (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 (!strcmp (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 = safe_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 = safe_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 = safe_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 = safe_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 = safe_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 FREE (&array[i].key);
2658 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++) {
2692 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 fprintf (fp, "%s ......: ", idx ? _(" aka") : _("Name"));
2761 fputs (_("[Invalid]"), fp);
2765 print_utf8 (fp, s, strlen (s));
2767 parse_and_print_user_id (fp, s);
2771 if (key->subkeys && (key->subkeys->timestamp > 0)) {
2772 tt = key->subkeys->timestamp;
2774 tm = localtime (&tt);
2775 #ifdef HAVE_LANGINFO_D_T_FMT
2776 strftime (shortbuf, sizeof shortbuf, nl_langinfo (D_T_FMT), tm);
2778 strftime (shortbuf, sizeof shortbuf, "%c", tm);
2780 fprintf (fp, "Valid From : %s\n", shortbuf);
2783 if (key->subkeys && (key->subkeys->expires > 0)) {
2784 tt = key->subkeys->expires;
2786 tm = localtime (&tt);
2787 #ifdef HAVE_LANGINFO_D_T_FMT
2788 strftime (shortbuf, sizeof shortbuf, nl_langinfo (D_T_FMT), tm);
2790 strftime (shortbuf, sizeof shortbuf, "%c", tm);
2792 fprintf (fp, "Valid To ..: %s\n", shortbuf);
2796 s = gpgme_pubkey_algo_name (key->subkeys->pubkey_algo);
2800 s2 = is_pgp ? "PGP" : "X.509";
2803 aval = key->subkeys->length;
2805 fprintf (fp, "Key Type ..: %s, %lu bit %s\n", s2, aval, s);
2807 fprintf (fp, "Key Usage .: ");
2810 if (key_check_cap (key, KEY_CAP_CAN_ENCRYPT)) {
2811 fprintf (fp, "%s%s", delim, _("encryption"));
2814 if (key_check_cap (key, KEY_CAP_CAN_SIGN)) {
2815 fprintf (fp, "%s%s", delim, _("signing"));
2818 if (key_check_cap (key, KEY_CAP_CAN_CERTIFY)) {
2819 fprintf (fp, "%s%s", delim, _("certification"));
2825 s = key->subkeys->fpr;
2826 fputs (_("Fingerprint: "), fp);
2827 if (is_pgp && strlen (s) == 40) {
2828 for (i = 0; *s && s[1] && s[2] && s[3] && s[4]; s += 4, i++) {
2833 putc (is_pgp ? ' ' : ':', fp);
2834 if (is_pgp && i == 4)
2839 for (i = 0; *s && s[1] && s[2]; s += 2, i++) {
2842 putc (is_pgp ? ' ' : ':', fp);
2843 if (is_pgp && i == 7)
2847 fprintf (fp, "%s\n", s);
2850 if (key->issuer_serial) {
2851 s = key->issuer_serial;
2853 fprintf (fp, "Serial-No .: 0x%s\n", s);
2856 if (key->issuer_name) {
2857 s = key->issuer_name;
2859 fprintf (fp, "Issued By .: ");
2860 parse_and_print_user_id (fp, s);
2865 /* For PGP we list all subkeys. */
2867 gpgme_subkey_t subkey = NULL;
2869 for (idx = 1, subkey = key->subkeys; subkey; idx++, subkey = subkey->next) {
2873 if (strlen (s) == 16)
2874 s += 8; /* display only the short keyID */
2875 fprintf (fp, "Subkey ....: 0x%s", s);
2876 if (subkey->revoked) {
2878 fputs (_("[Revoked]"), fp);
2880 if (subkey->invalid) {
2882 fputs (_("[Invalid]"), fp);
2884 if (subkey->expired) {
2886 fputs (_("[Expired]"), fp);
2888 if (subkey->disabled) {
2890 fputs (_("[Disabled]"), fp);
2894 if (subkey->timestamp > 0) {
2895 tt = subkey->timestamp;
2897 tm = localtime (&tt);
2898 #ifdef HAVE_LANGINFO_D_T_FMT
2899 strftime (shortbuf, sizeof shortbuf, nl_langinfo (D_T_FMT), tm);
2901 strftime (shortbuf, sizeof shortbuf, "%c", tm);
2903 fprintf (fp, "Valid From : %s\n", shortbuf);
2906 if (subkey->expires > 0) {
2907 tt = subkey->expires;
2909 tm = localtime (&tt);
2910 #ifdef HAVE_LANGINFO_D_T_FMT
2911 strftime (shortbuf, sizeof shortbuf, nl_langinfo (D_T_FMT), tm);
2913 strftime (shortbuf, sizeof shortbuf, "%c", tm);
2915 fprintf (fp, "Valid To ..: %s\n", shortbuf);
2919 s = gpgme_pubkey_algo_name (subkey->pubkey_algo);
2924 aval = subkey->length;
2928 fprintf (fp, "Key Type ..: %s, %lu bit %s\n", "PGP", aval, s);
2930 fprintf (fp, "Key Usage .: ");
2933 if (subkey->can_encrypt) {
2934 fprintf (fp, "%s%s", delim, _("encryption"));
2937 if (subkey->can_sign) {
2938 fprintf (fp, "%s%s", delim, _("signing"));
2941 if (subkey->can_certify) {
2942 fprintf (fp, "%s%s", delim, _("certification"));
2950 setlocale (LC_TIME, "C");
2954 /* Show detailed information about the selected key */
2955 static void verify_key (crypt_key_t * key)
2958 char cmd[LONG_STRING], tempfile[_POSIX_PATH_MAX];
2960 gpgme_ctx_t listctx = NULL;
2962 gpgme_key_t k = NULL;
2965 mutt_mktemp (tempfile);
2966 if (!(fp = safe_fopen (tempfile, "w"))) {
2967 mutt_perror _("Can't create temporary file");
2971 mutt_message _("Collecting data...");
2973 print_key_info (key->kobj, fp);
2975 err = gpgme_new (&listctx);
2977 fprintf (fp, "Internal error: can't create gpgme context: %s\n",
2978 gpgme_strerror (err));
2981 if ((key->flags & KEYFLAG_ISX509))
2982 gpgme_set_protocol (listctx, GPGME_PROTOCOL_CMS);
2986 while ((s = k->chain_id) && k->subkeys && strcmp (s, k->subkeys->fpr)) {
2988 err = gpgme_op_keylist_start (listctx, s, 0);
2989 gpgme_key_release (k);
2992 err = gpgme_op_keylist_next (listctx, &k);
2994 fprintf (fp, _("Error finding issuer key: %s\n"), gpgme_strerror (err));
2997 gpgme_op_keylist_end (listctx);
2999 print_key_info (k, fp);
3002 fputs (_("Error: certification chain to long - stopping here\n"), fp);
3008 gpgme_key_release (k);
3009 gpgme_release (listctx);
3011 mutt_clear_error ();
3012 snprintf (cmd, sizeof (cmd), _("Key ID: 0x%s"), crypt_keyid (key));
3013 mutt_do_pager (cmd, tempfile, 0, NULL);
3017 * Implementation of `findkeys'.
3021 /* Convert LIST into a pattern string suitable to be passed to GPGME.
3022 We need to convert spaces in an item into a '+' and '%' into
3024 static char *list_to_pattern (LIST * list)
3032 for (l = list; l; l = l->next) {
3033 for (s = l->data; *s; s++) {
3038 n++; /* delimiter or end of string */
3040 n++; /* make sure to allocate at least one byte */
3041 pattern = p = safe_calloc (1, n);
3042 for (l = list; l; l = l->next) {
3047 for (s = l->data; *s; s++) {
3053 else if (*s == '+') {
3069 /* Return a list of keys which are candidates for the selection.
3070 Select by looking at the HINTS list. */
3071 static crypt_key_t *get_candidates (LIST * hints, unsigned int app,
3074 crypt_key_t *db, *k, **kend;
3080 gpgme_user_id_t uid = NULL;
3082 pattern = list_to_pattern (hints);
3086 err = gpgme_new (&ctx);
3088 mutt_error ("gpgme_new failed: %s", gpgme_strerror (err));
3096 if ((app & APPLICATION_PGP)) {
3097 /* Its all a mess. That old GPGME expects different things
3098 depending on the protocol. For gpg we don' t need percent
3099 escaped pappert but simple strings passed in an array to the
3100 keylist_ext_start function. */
3105 for (l = hints, n = 0; l; l = l->next) {
3106 if (l->data && *l->data)
3112 patarr = safe_calloc (n + 1, sizeof *patarr);
3113 for (l = hints, n = 0; l; l = l->next) {
3114 if (l->data && *l->data)
3115 patarr[n++] = safe_strdup (l->data);
3118 err = gpgme_op_keylist_ext_start (ctx, (const char **) patarr, secret, 0);
3119 for (n = 0; patarr[n]; n++)
3123 mutt_error ("gpgme_op_keylist_start failed: %s", gpgme_strerror (err));
3124 gpgme_release (ctx);
3129 while (!(err = gpgme_op_keylist_next (ctx, &key))) {
3130 unsigned int flags = 0;
3132 if (key_check_cap (key, KEY_CAP_CAN_ENCRYPT))
3133 flags |= KEYFLAG_CANENCRYPT;
3134 if (key_check_cap (key, KEY_CAP_CAN_SIGN))
3135 flags |= KEYFLAG_CANSIGN;
3137 #if 0 /* DISABLED code */
3139 /* Bug in gpg. Capabilities are not listed for secret
3140 keys. Try to deduce them from the algorithm. */
3142 switch (key->subkeys[0].pubkey_algo) {
3144 flags |= KEYFLAG_CANENCRYPT;
3145 flags |= KEYFLAG_CANSIGN;
3147 case GPGME_PK_ELG_E:
3148 flags |= KEYFLAG_CANENCRYPT;
3151 flags |= KEYFLAG_CANSIGN;
3155 #endif /* DISABLED code */
3157 for (idx = 0, uid = key->uids; uid; idx++, uid = uid->next) {
3158 k = safe_calloc (1, sizeof *k);
3167 if (gpg_err_code (err) != GPG_ERR_EOF)
3168 mutt_error ("gpgme_op_keylist_next failed: %s", gpgme_strerror (err));
3169 gpgme_op_keylist_end (ctx);
3174 if ((app & APPLICATION_SMIME)) {
3175 /* and now look for x509 certificates */
3176 gpgme_set_protocol (ctx, GPGME_PROTOCOL_CMS);
3177 err = gpgme_op_keylist_start (ctx, pattern, 0);
3179 mutt_error ("gpgme_op_keylist_start failed: %s", gpgme_strerror (err));
3180 gpgme_release (ctx);
3185 while (!(err = gpgme_op_keylist_next (ctx, &key))) {
3186 unsigned int flags = KEYFLAG_ISX509;
3188 if (key_check_cap (key, KEY_CAP_CAN_ENCRYPT))
3189 flags |= KEYFLAG_CANENCRYPT;
3190 if (key_check_cap (key, KEY_CAP_CAN_SIGN))
3191 flags |= KEYFLAG_CANSIGN;
3193 for (idx = 0, uid = key->uids; uid; idx++, uid = uid->next) {
3194 k = safe_calloc (1, sizeof *k);
3203 if (gpg_err_code (err) != GPG_ERR_EOF)
3204 mutt_error ("gpgme_op_keylist_next failed: %s", gpgme_strerror (err));
3205 gpgme_op_keylist_end (ctx);
3208 gpgme_release (ctx);
3213 /* Add the string STR to the list HINTS. This list is later used to
3215 static LIST *crypt_add_string_to_hints (LIST * hints, const char *str)
3220 if ((scratch = safe_strdup (str)) == NULL)
3223 for (t = strtok (scratch, " ,.:\"()<>\n"); t;
3224 t = strtok (NULL, " ,.:\"()<>\n")) {
3226 hints = mutt_add_list (hints, t);
3233 /* Display a menu to select a key from the array KEYS. FORCED_VALID
3234 will be set to true on return if the user did override the the
3236 static crypt_key_t *crypt_select_key (crypt_key_t * keys,
3237 ADDRESS * p, const char *s,
3238 unsigned int app, int *forced_valid)
3241 crypt_key_t **key_table;
3244 char helpstr[SHORT_STRING], buf[LONG_STRING];
3246 int (*f) (const void *, const void *);
3247 int menu_to_use = 0;
3252 /* build the key table */
3255 for (k = keys; k; k = k->next) {
3256 if (!option (OPTPGPSHOWUNUSABLE) && (k->flags & KEYFLAG_CANTUSE)) {
3263 safe_realloc (&key_table, sizeof (crypt_key_t *) * keymax);
3269 if (!i && unusable) {
3270 mutt_error _("All matching keys are marked expired/revoked.");
3276 switch (PgpSortKeys & SORT_MASK) {
3278 f = crypt_compare_date;
3281 f = crypt_compare_keyid;
3284 f = crypt_compare_address;
3288 f = crypt_compare_trust;
3291 qsort (key_table, i, sizeof (crypt_key_t *), f);
3293 if (app & APPLICATION_PGP)
3294 menu_to_use = MENU_KEY_SELECT_PGP;
3295 else if (app & APPLICATION_SMIME)
3296 menu_to_use = MENU_KEY_SELECT_SMIME;
3299 mutt_make_help (buf, sizeof (buf), _("Exit "), menu_to_use, OP_EXIT);
3300 strcat (helpstr, buf); /* __STRCAT_CHECKED__ */
3301 mutt_make_help (buf, sizeof (buf), _("Select "), menu_to_use,
3302 OP_GENERIC_SELECT_ENTRY);
3303 strcat (helpstr, buf); /* __STRCAT_CHECKED__ */
3304 mutt_make_help (buf, sizeof (buf), _("Check key "),
3305 menu_to_use, OP_VERIFY_KEY);
3306 strcat (helpstr, buf); /* __STRCAT_CHECKED__ */
3307 mutt_make_help (buf, sizeof (buf), _("Help"), menu_to_use, OP_HELP);
3308 strcat (helpstr, buf); /* __STRCAT_CHECKED__ */
3310 menu = mutt_new_menu ();
3312 menu->make_entry = crypt_entry;
3313 menu->menu = menu_to_use;
3314 menu->help = helpstr;
3315 menu->data = key_table;
3320 if ((app & APPLICATION_PGP) && (app & APPLICATION_SMIME))
3321 ts = _("PGP and S/MIME keys matching");
3322 else if ((app & APPLICATION_PGP))
3323 ts = _("PGP keys matching");
3324 else if ((app & APPLICATION_SMIME))
3325 ts = _("S/MIME keys matching");
3327 ts = _("keys matching");
3330 snprintf (buf, sizeof (buf), _("%s <%s>."), ts, p->mailbox);
3332 snprintf (buf, sizeof (buf), _("%s \"%s\"."), ts, s);
3336 mutt_clear_error ();
3340 switch (mutt_menuLoop (menu)) {
3342 verify_key (key_table[menu->current]);
3343 menu->redraw = REDRAW_FULL;
3347 mutt_message ("%s", key_table[menu->current]->uid);
3350 case OP_GENERIC_SELECT_ENTRY:
3351 /* FIXME make error reporting more verbose - this should be
3352 easy because gpgme provides more information */
3353 if (option (OPTPGPCHECKTRUST)) {
3354 if (!crypt_key_is_valid (key_table[menu->current])) {
3355 mutt_error _("This key can't be used: "
3356 "expired/disabled/revoked.");
3361 if (option (OPTPGPCHECKTRUST) &&
3362 (!crypt_id_is_valid (key_table[menu->current])
3363 || !crypt_id_is_strong (key_table[menu->current]))) {
3365 char buff[LONG_STRING];
3367 if (key_table[menu->current]->flags & KEYFLAG_CANTUSE)
3368 s = N_("ID is expired/disabled/revoked.");
3370 gpgme_validity_t val = GPGME_VALIDITY_UNKNOWN;
3371 gpgme_user_id_t uid = NULL;
3376 uid = key_table[menu->current]->kobj->uids;
3377 for (j = 0; (j < key_table[menu->current]->idx) && uid;
3378 j++, uid = uid->next);
3380 val = uid->validity;
3383 case GPGME_VALIDITY_UNKNOWN:
3384 case GPGME_VALIDITY_UNDEFINED:
3385 warn_s = N_("ID has undefined validity.");
3387 case GPGME_VALIDITY_NEVER:
3388 warn_s = N_("ID is not valid.");
3390 case GPGME_VALIDITY_MARGINAL:
3391 warn_s = N_("ID is only marginally valid.");
3393 case GPGME_VALIDITY_FULL:
3394 case GPGME_VALIDITY_ULTIMATE:
3398 snprintf (buff, sizeof (buff),
3399 _("%s Do you really want to use the key?"), _(warn_s));
3401 if (mutt_yesorno (buff, 0) != 1) {
3402 mutt_clear_error ();
3409 k = crypt_copy_key (key_table[menu->current]);
3420 mutt_menuDestroy (&menu);
3423 set_option (OPTNEEDREDRAW);
3428 static crypt_key_t *crypt_getkeybyaddr (ADDRESS * a, short abilities,
3429 unsigned int app, int *forced_valid)
3437 int this_key_has_strong;
3438 int this_key_has_weak;
3439 int this_key_has_invalid;
3442 crypt_key_t *keys, *k;
3443 crypt_key_t *the_valid_key = NULL;
3444 crypt_key_t *matches = NULL;
3445 crypt_key_t **matches_endp = &matches;
3449 if (a && a->mailbox)
3450 hints = crypt_add_string_to_hints (hints, a->mailbox);
3451 if (a && a->personal)
3452 hints = crypt_add_string_to_hints (hints, a->personal);
3454 mutt_message (_("Looking for keys matching \"%s\"..."), a->mailbox);
3455 keys = get_candidates (hints, app, (abilities & KEYFLAG_CANSIGN));
3457 mutt_free_list (&hints);
3462 dprint (5, (debugfile, "crypt_getkeybyaddr: looking for %s <%s>.",
3463 a->personal, a->mailbox));
3465 for (k = keys; k; k = k->next) {
3466 dprint (5, (debugfile, " looking at key: %s `%.15s'\n",
3467 crypt_keyid (k), k->uid));
3469 if (abilities && !(k->flags & abilities)) {
3470 dprint (5, (debugfile, " insufficient abilities: Has %x, want %x\n",
3471 k->flags, abilities));
3475 this_key_has_weak = 0; /* weak but valid match */
3476 this_key_has_invalid = 0; /* invalid match */
3477 this_key_has_strong = 0; /* strong and valid match */
3478 match = 0; /* any match */
3480 r = rfc822_parse_adrlist (NULL, k->uid);
3481 for (p = r; p; p = p->next) {
3482 int validity = crypt_id_matches_addr (a, p, k);
3484 if (validity & CRYPT_KV_MATCH) /* something matches */
3487 /* is this key a strong candidate? */
3488 if ((validity & CRYPT_KV_VALID)
3489 && (validity & CRYPT_KV_STRONGID)
3490 && (validity & CRYPT_KV_ADDR)) {
3491 if (the_valid_key && the_valid_key != k)
3494 this_key_has_strong = 1;
3496 else if ((validity & CRYPT_KV_MATCH)
3497 && !(validity & CRYPT_KV_VALID))
3498 this_key_has_invalid = 1;
3499 else if ((validity & CRYPT_KV_MATCH)
3500 && (!(validity & CRYPT_KV_STRONGID)
3501 || !(validity & CRYPT_KV_ADDR)))
3502 this_key_has_weak = 1;
3504 rfc822_free_address (&r);
3509 if (!this_key_has_strong && this_key_has_invalid)
3511 if (!this_key_has_strong && this_key_has_weak)
3514 *matches_endp = tmp = crypt_copy_key (k);
3515 matches_endp = &tmp->next;
3516 the_valid_key = tmp;
3520 crypt_free_key (&keys);
3523 if (the_valid_key && !multi && !weak
3524 && !(invalid && option (OPTPGPSHOWUNUSABLE))) {
3526 * There was precisely one strong match on a valid ID, there
3527 * were no valid keys with weak matches, and we aren't
3528 * interested in seeing invalid keys.
3530 * Proceed without asking the user.
3532 k = crypt_copy_key (the_valid_key);
3536 * Else: Ask the user.
3538 k = crypt_select_key (matches, a, NULL, app, forced_valid);
3540 crypt_free_key (&matches);
3549 static crypt_key_t *crypt_getkeybystr (char *p, short abilities,
3550 unsigned int app, int *forced_valid)
3554 crypt_key_t *matches = NULL;
3555 crypt_key_t **matches_endp = &matches;
3559 mutt_message (_("Looking for keys matching \"%s\"..."), p);
3563 hints = crypt_add_string_to_hints (hints, p);
3564 keys = get_candidates (hints, app, (abilities & KEYFLAG_CANSIGN));
3565 mutt_free_list (&hints);
3570 for (k = keys; k; k = k->next) {
3571 if (abilities && !(k->flags & abilities))
3575 dprint (5, (debugfile, "crypt_getkeybystr: matching \"%s\" against "
3576 "key %s, \"%s\": ", p, crypt_keyid (k), k->uid));
3578 if (!*p || !mutt_strcasecmp (p, crypt_keyid (k))
3579 || (!mutt_strncasecmp (p, "0x", 2)
3580 && !mutt_strcasecmp (p + 2, crypt_keyid (k)))
3581 || (option (OPTPGPLONGIDS)
3582 && !mutt_strncasecmp (p, "0x", 2)
3583 && !mutt_strcasecmp (p + 2, crypt_keyid (k) + 8))
3584 || mutt_stristr (k->uid, p)) {
3587 dprint (5, (debugfile, "match.\n"));
3589 *matches_endp = tmp = crypt_copy_key (k);
3590 matches_endp = &tmp->next;
3594 crypt_free_key (&keys);
3597 k = crypt_select_key (matches, NULL, p, app, forced_valid);
3598 crypt_free_key (&matches);
3605 /* Display TAG as a prompt to ask for a key. If WHATFOR is not null
3606 use it as default and store it under that label as the next
3607 default. ABILITIES describe the required key abilities (sign,
3608 encrypt) and APP the type of the requested key; ether S/MIME or
3609 PGP. Return a copy of the key or NULL if not found. */
3610 static crypt_key_t *crypt_ask_for_key (char *tag,
3613 unsigned int app, int *forced_valid)
3616 char resp[SHORT_STRING];
3617 struct crypt_cache *l = NULL;
3621 forced_valid = &dummy;
3623 mutt_clear_error ();
3629 for (l = id_defaults; l; l = l->next)
3630 if (!mutt_strcasecmp (whatfor, l->what)) {
3631 strfcpy (resp, NONULL (l->dflt), sizeof (resp));
3639 if (mutt_get_field (tag, resp, sizeof (resp), M_CLEAR) != 0)
3644 mutt_str_replace (&l->dflt, resp);
3646 l = safe_malloc (sizeof (struct crypt_cache));
3647 l->next = id_defaults;
3649 l->what = safe_strdup (whatfor);
3650 l->dflt = safe_strdup (resp);
3654 if ((key = crypt_getkeybystr (resp, abilities, app, forced_valid)))
3662 /* This routine attempts to find the keyids of the recipients of a
3663 message. It returns NULL if any of the keys can not be found. */
3664 static char *find_keys (ADDRESS * to, ADDRESS * cc, ADDRESS * bcc,
3667 char *keyID, *keylist = NULL, *t;
3668 size_t keylist_size = 0;
3669 size_t keylist_used = 0;
3670 ADDRESS *tmp = NULL, *addr = NULL;
3671 ADDRESS **last = &tmp;
3674 crypt_key_t *k_info, *key;
3675 const char *fqdn = mutt_fqdn (1);
3678 *r_application = APPLICATION_PGP | APPLICATION_SMIME;
3681 for (i = 0; i < 3; i++) {
3696 *last = rfc822_cpy_adr (p);
3698 last = &((*last)->next);
3702 rfc822_qualify (tmp, fqdn);
3704 tmp = mutt_remove_duplicates (tmp);
3706 for (p = tmp; p; p = p->next) {
3707 char buf[LONG_STRING];
3708 int forced_valid = 0;
3713 if ((keyID = mutt_crypt_hook (p)) != NULL) {
3716 snprintf (buf, sizeof (buf), _("Use keyID = \"%s\" for %s?"),
3718 if ((r = mutt_yesorno (buf, M_YES)) == M_YES) {
3719 /* check for e-mail address */
3720 if ((t = strchr (keyID, '@')) &&
3721 (addr = rfc822_parse_adrlist (NULL, keyID))) {
3723 rfc822_qualify (addr, fqdn);
3728 k_info = crypt_getkeybystr (keyID, KEYFLAG_CANENCRYPT,
3729 *r_application, &forced_valid);
3731 k_info = crypt_getkeybystr (keyID, KEYFLAG_CANENCRYPT,
3732 app, &forced_valid);
3738 rfc822_free_address (&tmp);
3739 rfc822_free_address (&addr);
3745 && (k_info = crypt_getkeybyaddr (q, KEYFLAG_CANENCRYPT,
3746 app, &forced_valid)) == NULL) {
3747 snprintf (buf, sizeof (buf), _("Enter keyID for %s: "), q->mailbox);
3749 if ((key = crypt_ask_for_key (buf, q->mailbox, KEYFLAG_CANENCRYPT,
3755 &forced_valid)) == NULL) {
3757 rfc822_free_address (&tmp);
3758 rfc822_free_address (&addr);
3766 const char *s = crypt_fpr (key);
3769 if (key->flags & KEYFLAG_ISX509)
3770 *r_application &= ~APPLICATION_PGP;
3771 if (!(key->flags & KEYFLAG_ISX509))
3772 *r_application &= ~APPLICATION_SMIME;
3775 keylist_size += mutt_strlen (s) + 4 + 1;
3776 safe_realloc (&keylist, keylist_size);
3777 sprintf (keylist + keylist_used, "%s0x%s%s", /* __SPRINTF_CHECKED__ */
3778 keylist_used ? " " : "", s, forced_valid ? "!" : "");
3780 keylist_used = mutt_strlen (keylist);
3782 crypt_free_key (&key);
3783 rfc822_free_address (&addr);
3785 rfc822_free_address (&tmp);
3789 char *pgp_gpgme_findkeys (ADDRESS * to, ADDRESS * cc, ADDRESS * bcc)
3791 return find_keys (to, cc, bcc, APPLICATION_PGP);
3794 char *smime_gpgme_findkeys (ADDRESS * to, ADDRESS * cc, ADDRESS * bcc)
3796 return find_keys (to, cc, bcc, APPLICATION_SMIME);
3800 * Implementation of `init'.
3803 /* Initialization. */
3804 static void init_gpgme (void)
3806 /* Make sure that gpg-agent is running. */
3807 if (!getenv ("GPG_AGENT_INFO")) {
3808 mutt_error ("\nUsing GPGME backend, although no gpg-agent is running");
3809 if (mutt_any_key_to_continue (NULL) == -1)
3814 void pgp_gpgme_init (void)
3819 void smime_gpgme_init (void)
3823 static int gpgme_send_menu (HEADER * msg, int *redraw, int is_smime)
3826 char input_signas[SHORT_STRING];
3829 if (msg->security & APPLICATION_PGP)
3831 else if (msg->security & APPLICATION_SMIME)
3836 mutt_multi_choice (_
3837 ("S/MIME (e)ncrypt, (s)ign, sign (a)s, (b)oth, (t)oggle or (f)orget it?"),
3841 mutt_multi_choice (_
3842 ("PGP (e)ncrypt, (s)ign, sign (a)s, (b)oth, (t)oggle or (f)orget it?"),
3846 case 1: /* (e)ncrypt */
3847 msg->security |= (is_smime ? SMIMEENCRYPT : PGPENCRYPT);
3850 case 2: /* (s)ign */
3851 msg->security |= (is_smime ? SMIMESIGN : PGPSIGN);
3854 case 3: /* sign (a)s */
3855 /* unset_option(OPTCRYPTCHECKTRUST); */
3856 if ((p = crypt_ask_for_key (_("Sign as: "), NULL, KEYFLAG_CANSIGN,
3857 is_smime ? APPLICATION_SMIME :
3858 APPLICATION_PGP, NULL))) {
3859 snprintf (input_signas, sizeof (input_signas), "0x%s", crypt_keyid (p));
3860 mutt_str_replace (is_smime ? &SmimeDefaultKey : &PgpSignAs,
3862 crypt_free_key (&p);
3864 msg->security |= (is_smime ? SMIMESIGN : PGPSIGN);
3867 msg->security &= (is_smime ? ~SMIMESIGN : ~PGPSIGN);
3869 *redraw = REDRAW_FULL;
3872 case 4: /* (b)oth */
3874 (is_smime ? (SMIMEENCRYPT | SMIMESIGN) : (PGPENCRYPT | PGPSIGN));
3877 case 5: /* (t)oggle */
3878 is_smime = !is_smime;
3881 case 6: /* (f)orget it */
3887 else if (is_smime) {
3888 msg->security &= ~APPLICATION_PGP;
3889 msg->security |= APPLICATION_SMIME;
3892 msg->security &= ~APPLICATION_SMIME;
3893 msg->security |= APPLICATION_PGP;
3896 return (msg->security);
3899 int pgp_gpgme_send_menu (HEADER * msg, int *redraw)
3901 return gpgme_send_menu (msg, redraw, 0);
3904 int smime_gpgme_send_menu (HEADER * msg, int *redraw)
3906 return gpgme_send_menu (msg, redraw, 1);
3909 static int verify_sender (HEADER * h, gpgme_protocol_t protocol)
3911 ADDRESS *sender = NULL;
3912 unsigned int ret = 1;
3915 h->env->from = mutt_expand_aliases (h->env->from);
3916 sender = h->env->from;
3918 else if (h->env->sender) {
3919 h->env->sender = mutt_expand_aliases (h->env->sender);
3920 sender = h->env->sender;
3924 if (signature_key) {
3925 gpgme_key_t key = signature_key;
3926 gpgme_user_id_t uid = NULL;
3927 int sender_length = 0;
3930 sender_length = strlen (sender->mailbox);
3931 for (uid = key->uids; uid && ret; uid = uid->next) {
3932 uid_length = strlen (uid->email);
3933 if (1 && (uid->email[0] == '<')
3934 && (uid->email[uid_length - 1] == '>')
3935 && (uid_length == sender_length + 2)
3936 && (!strncmp (uid->email + 1, sender->mailbox, sender_length)))
3941 mutt_any_key_to_continue ("Failed to verify sender");
3944 mutt_any_key_to_continue ("Failed to figure out sender");
3946 if (signature_key) {
3947 gpgme_key_release (signature_key);
3948 signature_key = NULL;
3954 int smime_gpgme_verify_sender (HEADER * h)
3956 return verify_sender (h, GPGME_PROTOCOL_CMS);