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"
43 #ifdef HAVE_LANGINFO_D_T_FMT
47 #ifdef HAVE_SYS_TIME_H
48 # include <sys/time.h>
51 #ifdef HAVE_SYS_RESOURCE_H
52 # include <sys/resource.h>
58 #define digitp(p) (*(p) >= '0' && *(p) <= '9')
59 #define hexdigitp(a) (digitp (a) \
60 || (*(a) >= 'A' && *(a) <= 'F') \
61 || (*(a) >= 'a' && *(a) <= 'f'))
62 #define xtoi_1(p) (*(p) <= '9'? (*(p)- '0'): \
63 *(p) <= 'F'? (*(p)-'A'+10):(*(p)-'a'+10))
64 #define xtoi_2(p) ((xtoi_1(p) * 16) + xtoi_1((p)+1))
66 /* Values used for comparing addresses. */
67 #define CRYPT_KV_VALID 1
68 #define CRYPT_KV_ADDR 2
69 #define CRYPT_KV_STRING 4
70 #define CRYPT_KV_STRONGID 8
71 #define CRYPT_KV_MATCH (CRYPT_KV_ADDR|CRYPT_KV_STRING)
80 struct crypt_cache *next;
88 /* We work based on user IDs, getting from a user ID to the key is
89 check and does not need any memory (gpgme uses reference counting). */
90 typedef struct crypt_keyinfo {
91 struct crypt_keyinfo *next;
93 int idx; /* and the user ID at this index */
94 const char *uid; /* and for convenience point to this user ID */
95 unsigned int flags; /* global and per uid flags (for convenience) */
98 typedef struct crypt_entry {
104 static struct crypt_cache *id_defaults = NULL;
105 static gpgme_key_t signature_key = NULL;
108 * General helper functions.
111 /* return true when S pints to a didgit or letter. */
112 static int digit_or_letter (const unsigned char *s)
114 return ((*s >= '0' && *s < '9')
115 || (*s >= 'A' && *s <= 'Z')
116 || (*s >= 'a' && *s <= 'z'));
120 /* Print the utf-8 encoded string BUF of length LEN bytes to stream
121 FP. Convert the character set. */
122 static void print_utf8 (FILE * fp, const char *buf, size_t len)
126 tstr = safe_malloc (len + 1);
127 memcpy (tstr, buf, len);
129 mutt_convert_string (&tstr, "utf-8", Charset, M_ICONV_HOOK_FROM);
139 /* Return the keyID for the key K. Note that this string is valid as
140 long as K is valid */
141 static const char *crypt_keyid (crypt_key_t * k)
143 const char *s = "????????";
145 if (k->kobj && k->kobj->subkeys) {
146 s = k->kobj->subkeys->keyid;
147 if ((!option (OPTPGPLONGIDS)) && (strlen (s) == 16))
148 /* Return only the short keyID. */
155 /* Return the hexstring fingerprint from the key K. */
156 static const char *crypt_fpr (crypt_key_t * k)
160 if (k->kobj && k->kobj->subkeys)
161 s = k->kobj->subkeys->fpr;
166 /* Parse FLAGS and return a statically allocated(!) string with them. */
167 static char *crypt_key_abilities (int flags)
171 if (!(flags & KEYFLAG_CANENCRYPT))
173 else if (flags & KEYFLAG_PREFER_SIGNING)
178 if (!(flags & KEYFLAG_CANSIGN))
180 else if (flags & KEYFLAG_PREFER_ENCRYPTION)
190 /* Parse FLAGS and return a character describing the most important flag. */
191 static char crypt_flags (int flags)
193 if (flags & KEYFLAG_REVOKED)
195 else if (flags & KEYFLAG_EXPIRED)
197 else if (flags & KEYFLAG_DISABLED)
199 else if (flags & KEYFLAG_CRITICAL)
205 /* Return a copy of KEY. */
206 static crypt_key_t *crypt_copy_key (crypt_key_t * key)
210 k = safe_calloc (1, sizeof *k);
212 gpgme_key_ref (key->kobj);
215 k->flags = key->flags;
220 /* Release all the keys at the address of KEYLIST and set the address
222 static void crypt_free_key (crypt_key_t ** keylist)
225 crypt_key_t *k = (*keylist)->next;
232 /* Return trute when key K is valid. */
233 static int crypt_key_is_valid (crypt_key_t * k)
235 if (k->flags & KEYFLAG_CANTUSE)
240 /* Return true whe validity of KEY is sufficient. */
241 static int crypt_id_is_strong (crypt_key_t * key)
243 gpgme_validity_t val = GPGME_VALIDITY_UNKNOWN;
244 gpgme_user_id_t uid = NULL;
245 unsigned int is_strong = 0;
248 if ((key->flags & KEYFLAG_ISX509))
251 for (i = 0, uid = key->kobj->uids; (i < key->idx) && uid;
252 i++, uid = uid->next);
257 case GPGME_VALIDITY_UNKNOWN:
258 case GPGME_VALIDITY_UNDEFINED:
259 case GPGME_VALIDITY_NEVER:
260 case GPGME_VALIDITY_MARGINAL:
264 case GPGME_VALIDITY_FULL:
265 case GPGME_VALIDITY_ULTIMATE:
273 /* Return true when the KEY is valid, i.e. not marked as unusable. */
274 static int crypt_id_is_valid (crypt_key_t * key)
276 return !(key->flags & KEYFLAG_CANTUSE);
279 /* Return a bit vector describing how well the addresses ADDR and
280 U_ADDR match and whether KEY is valid. */
281 static int crypt_id_matches_addr (ADDRESS * addr, ADDRESS * u_addr,
286 if (crypt_id_is_valid (key))
287 rv |= CRYPT_KV_VALID;
289 if (crypt_id_is_strong (key))
290 rv |= CRYPT_KV_STRONGID;
292 if (addr->mailbox && u_addr->mailbox
293 && mutt_strcasecmp (addr->mailbox, u_addr->mailbox) == 0)
296 if (addr->personal && u_addr->personal
297 && mutt_strcasecmp (addr->personal, u_addr->personal) == 0)
298 rv |= CRYPT_KV_STRING;
305 * GPGME convenient functions.
308 /* Create a new gpgme context and return it. With FOR_SMIME set to
309 true, the protocol of the context is set to CMS. */
310 static gpgme_ctx_t create_gpgme_context (int for_smime)
315 err = gpgme_new (&ctx);
317 mutt_error ("error creating gpgme context: %s\n", gpgme_strerror (err));
323 err = gpgme_set_protocol (ctx, GPGME_PROTOCOL_CMS);
325 mutt_error ("error enabling CMS protocol: %s\n", gpgme_strerror (err));
334 /* Create a new gpgme data object. This is a wrapper to die on
336 static gpgme_data_t create_gpgme_data (void)
341 err = gpgme_data_new (&data);
343 mutt_error ("error creating gpgme data object: %s\n",
344 gpgme_strerror (err));
351 /* Create a new GPGME Data object from the mail body A. With CONVERT
352 passed as true, the lines are converted to CR,LF if required.
353 Return NULL on error or the gpgme_data_t object on success. */
354 static gpgme_data_t body_to_data_object (BODY * a, int convert)
356 char tempfile[_POSIX_PATH_MAX];
361 mutt_mktemp (tempfile);
362 fptmp = safe_fopen (tempfile, "w+");
364 mutt_perror (tempfile);
368 mutt_write_mime_header (a, fptmp);
370 mutt_write_mime_body (a, fptmp);
374 unsigned char buf[1];
376 data = create_gpgme_data ();
378 while ((c = fgetc (fptmp)) != EOF) {
382 if (c == '\n' && !hadcr) {
384 gpgme_data_write (data, buf, 1);
389 /* FIXME: This is quite suboptimal */
391 gpgme_data_write (data, buf, 1);
394 gpgme_data_seek (data, 0, SEEK_SET);
398 err = gpgme_data_new_from_file (&data, tempfile, 1);
402 mutt_error ("error allocating data object: %s\n", gpgme_strerror (err));
409 /* Create a GPGME data object from the stream FP but limit the object
410 to LENGTH bytes starting at OFFSET bytes from the beginning of the
412 static gpgme_data_t file_to_data_object (FILE * fp, long offset, long length)
417 err = gpgme_data_new_from_filepart (&data, NULL, fp, offset, length);
419 mutt_error ("error allocating data object: %s\n", gpgme_strerror (err));
426 /* Write a GPGME data object to the stream FP. */
427 static int data_object_to_stream (gpgme_data_t data, FILE * fp)
433 err = ((gpgme_data_seek (data, 0, SEEK_SET) == -1)
434 ? gpgme_error_from_errno (errno) : 0);
436 mutt_error ("error rewinding data object: %s\n", gpgme_strerror (err));
440 while ((nread = gpgme_data_read (data, buf, sizeof (buf)))) {
441 /* fixme: we are not really converting CRLF to LF but just
442 skipping CR. Doing it correctly needs a more complex logic */
443 for (p = buf; nread; p++, nread--) {
449 mutt_perror ("[tempfile]");
454 mutt_error ("error reading data object: %s\n", strerror (errno));
460 /* Copy a data object to a newly created temporay file and return that
461 filename. Caller must free. With RET_FP not NULL, don't close the
462 stream but return it there. */
463 static char *data_object_to_tempfile (gpgme_data_t data, FILE ** ret_fp)
466 char tempfile[_POSIX_PATH_MAX];
470 mutt_mktemp (tempfile);
471 fp = safe_fopen (tempfile, "w+");
473 mutt_perror (tempfile);
477 err = ((gpgme_data_seek (data, 0, SEEK_SET) == -1)
478 ? gpgme_error_from_errno (errno) : 0);
482 while ((nread = gpgme_data_read (data, buf, sizeof (buf)))) {
483 if (fwrite (buf, nread, 1, fp) != 1) {
484 mutt_perror (tempfile);
496 mutt_error ("error reading data object: %s\n", gpgme_strerror (err));
503 return safe_strdup (tempfile);
507 /* Create a GpgmeRecipientSet from the keys in the string KEYLIST.
508 The keys must be space delimited. */
509 static gpgme_key_t *create_recipient_set (const char *keylist,
510 gpgme_protocol_t protocol)
516 gpgme_key_t *rset = NULL;
517 unsigned int rset_n = 0;
518 gpgme_key_t key = NULL;
519 gpgme_ctx_t context = NULL;
521 err = gpgme_new (&context);
523 err = gpgme_set_protocol (context, protocol);
530 for (i = 0; *s && *s != ' ' && i < sizeof (buf) - 1;)
534 if (i > 1 && buf[i - 1] == '!') {
535 /* The user selected to override the valididy of that
539 err = gpgme_get_key (context, buf, &key, 0);
541 key->uids->validity = GPGME_VALIDITY_FULL;
545 err = gpgme_get_key (context, buf, &key, 0);
548 safe_realloc (&rset, sizeof (*rset) * (rset_n + 1));
549 rset[rset_n++] = key;
552 mutt_error ("error adding recipient `%s': %s\n",
553 buf, gpgme_strerror (err));
561 /* NULL terminate. */
562 safe_realloc (&rset, sizeof (*rset) * (rset_n + 1));
563 rset[rset_n++] = NULL;
566 gpgme_release (context);
572 /* Make sure that the correct signer is set. Returns 0 on success. */
573 static int set_signer (gpgme_ctx_t ctx, int for_smime)
575 char *signid = for_smime ? SmimeDefaultKey : PgpSignAs;
578 gpgme_key_t key, key2;
580 if (!signid || !*signid)
583 listctx = create_gpgme_context (for_smime);
584 err = gpgme_op_keylist_start (listctx, signid, 1);
586 err = gpgme_op_keylist_next (listctx, &key);
588 gpgme_release (listctx);
589 mutt_error (_("secret key `%s' not found: %s\n"),
590 signid, gpgme_strerror (err));
593 err = gpgme_op_keylist_next (listctx, &key2);
595 gpgme_key_release (key);
596 gpgme_key_release (key2);
597 gpgme_release (listctx);
598 mutt_error (_("ambiguous specfication of secret key `%s'\n"), signid);
601 gpgme_op_keylist_end (listctx);
602 gpgme_release (listctx);
604 gpgme_signers_clear (ctx);
605 err = gpgme_signers_add (ctx, key);
606 gpgme_key_release (key);
608 mutt_error (_("error setting secret key `%s': %s\n"),
609 signid, gpgme_strerror (err));
616 /* Encrypt the gpgme data object PLAINTEXT to the recipients in RSET
617 and return an allocated filename to a temporary file containing the
618 enciphered text. With USE_SMIME set to true, the smime backend is
619 used. With COMBINED_SIGNED a PGP message is signed and
620 encrypted. Returns NULL in case of error */
621 static char *encrypt_gpgme_object (gpgme_data_t plaintext, gpgme_key_t * rset,
622 int use_smime, int combined_signed)
626 gpgme_data_t ciphertext;
629 ctx = create_gpgme_context (use_smime);
631 gpgme_set_armor (ctx, 1);
633 ciphertext = create_gpgme_data ();
635 if (combined_signed) {
636 if (set_signer (ctx, use_smime)) {
637 gpgme_data_release (ciphertext);
641 err = gpgme_op_encrypt_sign (ctx, rset, GPGME_ENCRYPT_ALWAYS_TRUST,
642 plaintext, ciphertext);
645 err = gpgme_op_encrypt (ctx, rset, GPGME_ENCRYPT_ALWAYS_TRUST,
646 plaintext, ciphertext);
647 mutt_need_hard_redraw ();
649 mutt_error ("error encrypting data: %s\n", gpgme_strerror (err));
650 gpgme_data_release (ciphertext);
657 outfile = data_object_to_tempfile (ciphertext, NULL);
658 gpgme_data_release (ciphertext);
662 /* Find the "micalg" parameter from the last Gpgme operation on
663 context CTX. It is expected that this operation was a sign
664 operation. Return the algorithm name as a C string in buffer BUF
665 which must have been allocated by the caller with size BUFLEN.
666 Returns 0 on success or -1 in case of an error. The return string
667 is truncted to BUFLEN - 1. */
668 static int get_micalg (gpgme_ctx_t ctx, char *buf, size_t buflen)
670 gpgme_sign_result_t result = NULL;
671 const char *algorithm_name = NULL;
677 result = gpgme_op_sign_result (ctx);
679 algorithm_name = gpgme_hash_algo_name (result->signatures->hash_algo);
680 if (algorithm_name) {
681 strncpy (buf, algorithm_name, buflen - 1);
686 return *buf ? 0 : -1;
689 static void print_time (time_t t, STATE * s)
693 setlocale (LC_TIME, "");
694 #ifdef HAVE_LANGINFO_D_T_FMT
695 strftime (p, sizeof (p), nl_langinfo (D_T_FMT), localtime (&t));
697 strftime (p, sizeof (p), "%c", localtime (&t));
699 setlocale (LC_TIME, "C");
700 state_attach_puts (p, s);
704 * Implementation of `sign_message'.
707 /* Sign the MESSAGE in body A either using OpenPGP or S/MIME when
708 USE_SMIME is passed as true. Returns the new body or NULL on
710 static BODY *sign_message (BODY * a, int use_smime)
717 gpgme_data_t message, signature;
719 convert_to_7bit (a); /* Signed data _must_ be in 7-bit format. */
721 message = body_to_data_object (a, 1);
724 signature = create_gpgme_data ();
726 ctx = create_gpgme_context (use_smime);
728 gpgme_set_armor (ctx, 1);
730 if (set_signer (ctx, use_smime)) {
731 gpgme_data_release (signature);
736 err = gpgme_op_sign (ctx, message, signature, GPGME_SIG_MODE_DETACH);
737 mutt_need_hard_redraw ();
738 gpgme_data_release (message);
740 gpgme_data_release (signature);
742 mutt_error ("error signing data: %s\n", gpgme_strerror (err));
746 sigfile = data_object_to_tempfile (signature, NULL);
747 gpgme_data_release (signature);
753 t = mutt_new_body ();
754 t->type = TYPEMULTIPART;
755 t->subtype = safe_strdup ("signed");
756 t->encoding = ENC7BIT;
758 t->disposition = DISPINLINE;
760 mutt_generate_boundary (&t->parameter);
761 mutt_set_parameter ("protocol",
762 use_smime ? "application/pkcs7-signature"
763 : "application/pgp-signature", &t->parameter);
764 /* Get the micalg from gpgme. Old gpgme versions don't support this
765 for S/MIME so we assume sha-1 in this case. */
766 if (!get_micalg (ctx, buf, sizeof buf))
767 mutt_set_parameter ("micalg", buf, &t->parameter);
769 mutt_set_parameter ("micalg", "sha1", &t->parameter);
775 t->parts->next = mutt_new_body ();
777 t->type = TYPEAPPLICATION;
779 t->subtype = safe_strdup ("pkcs7-signature");
780 mutt_set_parameter ("name", "smime.p7s", &t->parameter);
781 t->encoding = ENCBASE64;
783 t->disposition = DISPATTACH;
784 t->d_filename = safe_strdup ("smime.p7s");
787 t->subtype = safe_strdup ("pgp-signature");
789 t->disposition = DISPINLINE;
790 t->encoding = ENC7BIT;
792 t->filename = sigfile;
793 t->unlink = 1; /* ok to remove this file after sending. */
799 BODY *pgp_gpgme_sign_message (BODY * a)
801 return sign_message (a, 0);
804 BODY *smime_gpgme_sign_message (BODY * a)
806 return sign_message (a, 1);
810 * Implementation of `encrypt_message'.
813 /* Encrypt the mail body A to all keys given as space separated keyids
814 or fingerprints in KEYLIST and return the encrypted body. */
815 BODY *pgp_gpgme_encrypt_message (BODY * a, char *keylist, int sign)
817 char *outfile = NULL;
819 gpgme_key_t *rset = NULL;
820 gpgme_data_t plaintext;
822 rset = create_recipient_set (keylist, GPGME_PROTOCOL_OpenPGP);
828 plaintext = body_to_data_object (a, 0);
834 outfile = encrypt_gpgme_object (plaintext, rset, 0, sign);
835 gpgme_data_release (plaintext);
840 t = mutt_new_body ();
841 t->type = TYPEMULTIPART;
842 t->subtype = safe_strdup ("encrypted");
843 t->encoding = ENC7BIT;
845 t->disposition = DISPINLINE;
847 mutt_generate_boundary (&t->parameter);
848 mutt_set_parameter ("protocol", "application/pgp-encrypted", &t->parameter);
850 t->parts = mutt_new_body ();
851 t->parts->type = TYPEAPPLICATION;
852 t->parts->subtype = safe_strdup ("pgp-encrypted");
853 t->parts->encoding = ENC7BIT;
855 t->parts->next = mutt_new_body ();
856 t->parts->next->type = TYPEAPPLICATION;
857 t->parts->next->subtype = safe_strdup ("octet-stream");
858 t->parts->next->encoding = ENC7BIT;
859 t->parts->next->filename = outfile;
860 t->parts->next->use_disp = 1;
861 t->parts->next->disposition = DISPINLINE;
862 t->parts->next->unlink = 1; /* delete after sending the message */
863 t->parts->next->d_filename = safe_strdup ("msg.asc"); /* non pgp/mime
870 * Implementation of `smime_build_smime_entity'.
873 /* Encrypt the mail body A to all keys given as space separated
874 fingerprints in KEYLIST and return the S/MIME encrypted body. */
875 BODY *smime_gpgme_build_smime_entity (BODY * a, char *keylist)
877 char *outfile = NULL;
879 gpgme_key_t *rset = NULL;
880 gpgme_data_t plaintext;
882 rset = create_recipient_set (keylist, GPGME_PROTOCOL_CMS);
886 plaintext = body_to_data_object (a, 0);
892 outfile = encrypt_gpgme_object (plaintext, rset, 1, 0);
893 gpgme_data_release (plaintext);
898 t = mutt_new_body ();
899 t->type = TYPEAPPLICATION;
900 t->subtype = safe_strdup ("pkcs7-mime");
901 mutt_set_parameter ("name", "smime.p7m", &t->parameter);
902 mutt_set_parameter ("smime-type", "enveloped-data", &t->parameter);
903 t->encoding = ENCBASE64; /* The output of OpenSSL SHOULD be binary */
905 t->disposition = DISPATTACH;
906 t->d_filename = safe_strdup ("smime.p7m");
907 t->filename = outfile;
908 t->unlink = 1; /*delete after sending the message */
917 * Implementation of `verify_one'.
920 /* Display the common attributes of the signature summary SUM.
921 Return 1 if there is is a severe warning.
923 static int show_sig_summary (unsigned long sum,
924 gpgme_ctx_t ctx, gpgme_key_t key, int idx,
929 if ((sum & GPGME_SIGSUM_KEY_REVOKED)) {
930 state_attach_puts (_("Warning: One of the keys has been revoked\n"), s);
934 if ((sum & GPGME_SIGSUM_KEY_EXPIRED)) {
935 time_t at = key->subkeys->expires ? key->subkeys->expires : 0;
938 state_attach_puts (_("Warning: The key used to create the "
939 "signature expired at: "), s);
941 state_attach_puts ("\n", s);
944 state_attach_puts (_("Warning: At least one certification key "
945 "has expired\n"), s);
948 if ((sum & GPGME_SIGSUM_SIG_EXPIRED)) {
949 gpgme_verify_result_t result;
950 gpgme_signature_t sig;
953 result = gpgme_op_verify_result (ctx);
955 for (sig = result->signatures, i = 0; sig && (i < idx);
956 sig = sig->next, i++);
958 state_attach_puts (_("Warning: The signature expired at: "), s);
959 print_time (sig ? sig->exp_timestamp : 0, s);
960 state_attach_puts ("\n", s);
963 if ((sum & GPGME_SIGSUM_KEY_MISSING))
964 state_attach_puts (_("Can't verify due to a missing "
965 "key or certificate\n"), s);
967 if ((sum & GPGME_SIGSUM_CRL_MISSING)) {
968 state_attach_puts (_("The CRL is not available\n"), s);
972 if ((sum & GPGME_SIGSUM_CRL_TOO_OLD)) {
973 state_attach_puts (_("Available CRL is too old\n"), s);
977 if ((sum & GPGME_SIGSUM_BAD_POLICY))
978 state_attach_puts (_("A policy requirement was not met\n"), s);
980 if ((sum & GPGME_SIGSUM_SYS_ERROR)) {
981 const char *t0 = NULL, *t1 = NULL;
982 gpgme_verify_result_t result;
983 gpgme_signature_t sig;
986 state_attach_puts (_("A system error occured"), s);
988 /* Try to figure out some more detailed system error information. */
989 result = gpgme_op_verify_result (ctx);
990 for (sig = result->signatures, i = 0; sig && (i < idx);
991 sig = sig->next, i++);
994 t1 = sig->wrong_key_usage ? "Wrong_Key_Usage" : "";
998 state_attach_puts (": ", s);
1000 state_attach_puts (t0, s);
1001 if (t1 && !(t0 && !strcmp (t0, t1))) {
1003 state_attach_puts (",", s);
1004 state_attach_puts (t1, s);
1007 state_attach_puts ("\n", s);
1014 static void show_fingerprint (gpgme_key_t key, STATE * state)
1019 const char *prefix = _("Fingerprint: ");
1023 s = key->subkeys ? key->subkeys->fpr : NULL;
1026 is_pgp = (key->protocol == GPGME_PROTOCOL_OpenPGP);
1028 buf = safe_malloc (strlen (prefix) + strlen (s) * 4 + 2);
1029 strcpy (buf, prefix); /* __STRCPY_CHECKED__ */
1030 p = buf + strlen (buf);
1031 if (is_pgp && strlen (s) == 40) { /* PGP v4 style formatted. */
1032 for (i = 0; *s && s[1] && s[2] && s[3] && s[4]; s += 4, i++) {
1043 for (i = 0; *s && s[1] && s[2]; s += 2, i++) {
1046 *p++ = is_pgp ? ' ' : ':';
1047 if (is_pgp && i == 7)
1052 /* just in case print remaining odd digits */
1057 state_attach_puts (buf, state);
1061 /* Show the valididy of a key used for one signature. */
1062 static void show_one_sig_validity (gpgme_ctx_t ctx, int idx, STATE * s)
1064 gpgme_verify_result_t result = NULL;
1065 gpgme_signature_t sig = NULL;
1066 const char *txt = NULL;
1068 result = gpgme_op_verify_result (ctx);
1070 for (sig = result->signatures; sig && (idx > 0); sig = sig->next, idx--);
1072 switch (sig ? sig->validity : 0) {
1073 case GPGME_VALIDITY_UNKNOWN:
1074 txt = _("WARNING: We have NO indication whether "
1075 "the key belongs to the person named " "as shown above\n");
1077 case GPGME_VALIDITY_UNDEFINED:
1079 case GPGME_VALIDITY_NEVER:
1080 txt = _("WARNING: The key does NOT BELONG to "
1081 "the person named as shown above\n");
1083 case GPGME_VALIDITY_MARGINAL:
1084 txt = _("WARNING: It is NOT certain that the key "
1085 "belongs to the person named as shown above\n");
1087 case GPGME_VALIDITY_FULL:
1088 case GPGME_VALIDITY_ULTIMATE:
1093 state_attach_puts (txt, s);
1096 /* Show information about one signature. This fucntion is called with
1097 the context CTX of a sucessful verification operation and the
1098 enumerator IDX which should start at 0 and incremete for each
1101 Return values are: 0 for normal procession, 1 for a bad signature,
1102 2 for a signature with a warning or -1 for no more signature. */
1103 static int show_one_sig_status (gpgme_ctx_t ctx, int idx, STATE * s)
1106 const char *fpr, *uid;
1107 gpgme_key_t key = NULL;
1108 int i, anybad = 0, anywarn = 0;
1110 gpgme_user_id_t uids = NULL;
1111 gpgme_verify_result_t result;
1112 gpgme_signature_t sig;
1113 gpgme_error_t err = GPG_ERR_NO_ERROR;
1115 result = gpgme_op_verify_result (ctx);
1117 /* FIXME: this code should use a static variable and remember
1118 the current position in the list of signatures, IMHO.
1121 for (i = 0, sig = result->signatures; sig && (i < idx);
1122 i++, sig = sig->next);
1124 return -1; /* Signature not found. */
1126 if (signature_key) {
1127 gpgme_key_release (signature_key);
1128 signature_key = NULL;
1131 created = sig->timestamp;
1135 if (gpg_err_code (sig->status) != GPG_ERR_NO_ERROR)
1138 err = gpgme_get_key (ctx, fpr, &key, 0); /* secret key? */
1140 uid = (key->uids && key->uids->uid) ? key->uids->uid : "[?]";
1142 signature_key = key;
1145 key = NULL; /* Old gpgme versions did not set KEY to NULL on
1146 error. Do it here to avoid a double free. */
1150 if (!s || !s->fpout || !(s->flags & M_DISPLAY)); /* No state information so no way to print anything. */
1152 state_attach_puts (_("Error getting key information: "), s);
1153 state_attach_puts (gpg_strerror (err), s);
1154 state_attach_puts ("\n", s);
1157 else if ((sum & GPGME_SIGSUM_GREEN)) {
1158 state_attach_puts (_("Good signature from: "), s);
1159 state_attach_puts (uid, s);
1160 state_attach_puts ("\n", s);
1161 for (i = 1, uids = key->uids; uids; i++, uids = uids->next) {
1163 /* Skip primary UID. */
1167 state_attach_puts (_(" aka: "), s);
1168 state_attach_puts (uids->uid, s);
1169 state_attach_puts ("\n", s);
1171 state_attach_puts (_(" created: "), s);
1172 print_time (created, s);
1173 state_attach_puts ("\n", s);
1174 if (show_sig_summary (sum, ctx, key, idx, s))
1176 show_one_sig_validity (ctx, idx, s);
1178 else if ((sum & GPGME_SIGSUM_RED)) {
1179 state_attach_puts (_("*BAD* signature claimed to be from: "), s);
1180 state_attach_puts (uid, s);
1181 state_attach_puts ("\n", s);
1182 show_sig_summary (sum, ctx, key, idx, s);
1184 else if (!anybad && key && (key->protocol == GPGME_PROTOCOL_OpenPGP)) { /* We can't decide (yellow) but this is a PGP key with a good
1185 signature, so we display what a PGP user expects: The name,
1186 fingerprint and the key validity (which is neither fully or
1188 state_attach_puts (_("Good signature from: "), s);
1189 state_attach_puts (uid, s);
1190 state_attach_puts ("\n", s);
1191 state_attach_puts (_(" created: "), s);
1192 print_time (created, s);
1193 state_attach_puts ("\n", s);
1194 show_one_sig_validity (ctx, idx, s);
1195 show_fingerprint (key, s);
1196 if (show_sig_summary (sum, ctx, key, idx, s))
1199 else { /* can't decide (yellow) */
1201 state_attach_puts (_("Error checking signature"), s);
1202 state_attach_puts ("\n", s);
1203 show_sig_summary (sum, ctx, key, idx, s);
1206 if (key != signature_key)
1207 gpgme_key_release (key);
1210 return anybad ? 1 : anywarn ? 2 : 0;
1213 /* Do the actual verification step. With IS_SMIME set to true we
1214 assume S/MIME (surprise!) */
1215 static int verify_one (BODY * sigbdy, STATE * s,
1216 const char *tempfile, int is_smime)
1222 gpgme_data_t signature, message;
1224 signature = file_to_data_object (s->fpin, sigbdy->offset, sigbdy->length);
1228 /* We need to tell gpgme about the encoding because the backend can't
1229 auto-detect plain base-64 encoding which is used by S/MIME. */
1231 gpgme_data_set_encoding (signature, GPGME_DATA_ENCODING_BASE64);
1233 err = gpgme_data_new_from_file (&message, tempfile, 1);
1235 gpgme_data_release (signature);
1236 mutt_error ("error allocating data object: %s\n", gpgme_strerror (err));
1239 ctx = create_gpgme_context (is_smime);
1241 /* Note: We don't need a current time output because GPGME avoids
1242 such an attack by separating the meta information from the
1244 state_attach_puts (_("[-- Begin signature information --]\n"), s);
1246 err = gpgme_op_verify (ctx, signature, message, NULL);
1247 mutt_need_hard_redraw ();
1251 snprintf (buf, sizeof (buf) - 1,
1252 _("Error: verification failed: %s\n"), gpgme_strerror (err));
1253 state_attach_puts (buf, s);
1255 else { /* Verification succeeded, see what the result is. */
1259 if (signature_key) {
1260 gpgme_key_release (signature_key);
1261 signature_key = NULL;
1264 for (idx = 0; (res = show_one_sig_status (ctx, idx, s)) != -1; idx++) {
1275 gpgme_verify_result_t result;
1276 gpgme_sig_notation_t notation;
1277 gpgme_signature_t signature;
1279 result = gpgme_op_verify_result (ctx);
1281 for (signature = result->signatures; signature;
1282 signature = signature->next) {
1283 if (signature->notations) {
1284 state_attach_puts ("*** Begin Notation (signature by: ", s);
1285 state_attach_puts (signature->fpr, s);
1286 state_attach_puts (") ***\n", s);
1287 for (notation = signature->notations; notation;
1288 notation = notation->next) {
1289 if (notation->name) {
1290 state_attach_puts (notation->name, s);
1291 state_attach_puts ("=", s);
1293 if (notation->value) {
1294 state_attach_puts (notation->value, s);
1295 if (!(*notation->value
1296 && (notation->value[strlen (notation->value) - 1] ==
1298 state_attach_puts ("\n", s);
1301 state_attach_puts ("*** End Notation ***\n", s);
1307 gpgme_release (ctx);
1309 state_attach_puts (_("[-- End signature information --]\n\n"), s);
1310 dprint (1, (debugfile, "verify_one: returning %d.\n", badsig));
1312 return badsig ? 1 : anywarn ? 2 : 0;
1315 int pgp_gpgme_verify_one (BODY * sigbdy, STATE * s, const char *tempfile)
1317 return verify_one (sigbdy, s, tempfile, 0);
1320 int smime_gpgme_verify_one (BODY * sigbdy, STATE * s, const char *tempfile)
1322 return verify_one (sigbdy, s, tempfile, 1);
1326 * Implementation of `decrypt_part'.
1329 /* Decrypt a PGP or SMIME message (depending on the boolean flag
1330 IS_SMIME) with body A described further by state S. Write
1331 plaintext out to file FPOUT and return a new body. For PGP returns
1332 a flag in R_IS_SIGNED to indicate whether this is a combined
1333 encrypted and signed message, for S/MIME it returns true when it is
1334 not a encrypted but a signed message. */
1335 static BODY *decrypt_part (BODY * a, STATE * s, FILE * fpout, int is_smime,
1342 gpgme_data_t ciphertext, plaintext;
1343 int maybe_signed = 0;
1350 ctx = create_gpgme_context (is_smime);
1353 /* Make a data object from the body, create context etc. */
1354 ciphertext = file_to_data_object (s->fpin, a->offset, a->length);
1357 plaintext = create_gpgme_data ();
1359 /* Do the decryption or the verification in case of the S/MIME hack. */
1360 if ((!is_smime) || maybe_signed) {
1362 err = gpgme_op_decrypt_verify (ctx, ciphertext, plaintext);
1363 else if (maybe_signed)
1364 err = gpgme_op_verify (ctx, ciphertext, NULL, plaintext);
1367 /* Check wether signatures have been verified. */
1368 gpgme_verify_result_t verify_result = gpgme_op_verify_result (ctx);
1370 if (verify_result->signatures)
1375 err = gpgme_op_decrypt (ctx, ciphertext, plaintext);
1376 gpgme_data_release (ciphertext);
1378 if (is_smime && !maybe_signed && gpg_err_code (err) == GPG_ERR_NO_DATA) {
1379 /* Check whether this might be a signed message despite what
1380 the mime header told us. Retry then. gpgsm returns the
1381 error information "unsupported Algorithm '?'" but gpgme
1382 will not store this unknown algorithm, thus we test that
1383 it has not been set. */
1384 gpgme_decrypt_result_t result;
1386 result = gpgme_op_decrypt_result (ctx);
1387 if (!result->unsupported_algorithm) {
1389 gpgme_data_release (plaintext);
1393 mutt_need_hard_redraw ();
1394 if ((s->flags & M_DISPLAY)) {
1397 snprintf (buf, sizeof (buf) - 1,
1398 _("[-- Error: decryption failed: %s --]\n\n"),
1399 gpgme_strerror (err));
1400 state_attach_puts (buf, s);
1402 gpgme_data_release (plaintext);
1403 gpgme_release (ctx);
1406 mutt_need_hard_redraw ();
1408 /* Read the output from GPGME, and make sure to change CRLF to LF,
1409 otherwise read_mime_header has a hard time parsing the message. */
1410 if (data_object_to_stream (plaintext, fpout)) {
1411 gpgme_data_release (plaintext);
1412 gpgme_release (ctx);
1415 gpgme_data_release (plaintext);
1417 a->is_signed_data = 0;
1423 a->is_signed_data = 1;
1425 *r_is_signed = -1; /* A signature exists. */
1427 if ((s->flags & M_DISPLAY))
1428 state_attach_puts (_("[-- Begin signature " "information --]\n"), s);
1429 for (idx = 0; (res = show_one_sig_status (ctx, idx, s)) != -1; idx++) {
1435 if (!anybad && idx && r_is_signed && *r_is_signed)
1436 *r_is_signed = anywarn ? 2 : 1; /* Good signature. */
1438 if ((s->flags & M_DISPLAY))
1439 state_attach_puts (_("[-- End signature " "information --]\n\n"), s);
1441 gpgme_release (ctx);
1446 tattach = mutt_read_mime_header (fpout, 0);
1449 * Need to set the length of this body part.
1451 fstat (fileno (fpout), &info);
1452 tattach->length = info.st_size - tattach->offset;
1454 tattach->warnsig = anywarn;
1456 /* See if we need to recurse on this MIME part. */
1457 mutt_parse_part (fpout, tattach);
1463 /* Decrypt a PGP/MIME message in FPIN and B and return a new body and
1464 the stream in CUR and FPOUT. Returns 0 on success. */
1465 int pgp_gpgme_decrypt_mime (FILE * fpin, FILE ** fpout, BODY * b, BODY ** cur)
1467 char tempfile[_POSIX_PATH_MAX];
1469 BODY *first_part = b;
1472 first_part->goodsig = 0;
1473 first_part->warnsig = 0;
1475 if (!mutt_is_multipart_encrypted (b))
1478 if (!b->parts || !b->parts->next)
1483 memset (&s, 0, sizeof (s));
1485 mutt_mktemp (tempfile);
1486 if (!(*fpout = safe_fopen (tempfile, "w+"))) {
1487 mutt_perror (tempfile);
1492 *cur = decrypt_part (b, &s, *fpout, 0, &is_signed);
1495 first_part->goodsig = 1;
1497 return *cur ? 0 : -1;
1501 /* Decrypt a S/MIME message in FPIN and B and return a new body and
1502 the stream in CUR and FPOUT. Returns 0 on success. */
1503 int smime_gpgme_decrypt_mime (FILE * fpin, FILE ** fpout, BODY * b,
1506 char tempfile[_POSIX_PATH_MAX];
1510 long saved_b_offset;
1511 size_t saved_b_length;
1514 if (!mutt_is_application_smime (b))
1520 /* Decode the body - we need to pass binary CMS to the
1521 backend. The backend allows for Base64 encoded data but it does
1522 not allow for QP which I have seen in some messages. So better
1524 saved_b_type = b->type;
1525 saved_b_offset = b->offset;
1526 saved_b_length = b->length;
1527 memset (&s, 0, sizeof (s));
1529 fseek (s.fpin, b->offset, 0);
1530 mutt_mktemp (tempfile);
1531 if (!(tmpfp = safe_fopen (tempfile, "w+"))) {
1532 mutt_perror (tempfile);
1535 mutt_unlink (tempfile);
1538 mutt_decode_attachment (b, &s);
1540 b->length = ftell (s.fpout);
1544 memset (&s, 0, sizeof (s));
1547 mutt_mktemp (tempfile);
1548 if (!(*fpout = safe_fopen (tempfile, "w+"))) {
1549 mutt_perror (tempfile);
1552 mutt_unlink (tempfile);
1554 *cur = decrypt_part (b, &s, *fpout, 1, &is_signed);
1556 (*cur)->goodsig = is_signed > 0;
1557 b->type = saved_b_type;
1558 b->length = saved_b_length;
1559 b->offset = saved_b_offset;
1562 if (*cur && !is_signed && !(*cur)->parts
1563 && mutt_is_application_smime (*cur)) {
1564 /* Assume that this is a opaque signed s/mime message. This is
1565 an ugly way of doing it but we have anyway a problem with
1566 arbitrary encoded S/MIME messages: Only the outer part may be
1567 encrypted. The entire mime parsing should be revamped,
1568 probably by keeping the temportary files so that we don't
1569 need to decrypt them all the time. Inner parts of an
1570 encrypted part can then pint into this file and tehre won't
1571 never be a need to decrypt again. This needs a partial
1572 rewrite of the MIME engine. */
1576 saved_b_type = bb->type;
1577 saved_b_offset = bb->offset;
1578 saved_b_length = bb->length;
1579 memset (&s, 0, sizeof (s));
1581 fseek (s.fpin, bb->offset, 0);
1582 mutt_mktemp (tempfile);
1583 if (!(tmpfp = safe_fopen (tempfile, "w+"))) {
1584 mutt_perror (tempfile);
1587 mutt_unlink (tempfile);
1590 mutt_decode_attachment (bb, &s);
1592 bb->length = ftell (s.fpout);
1597 memset (&s, 0, sizeof (s));
1600 mutt_mktemp (tempfile);
1601 if (!(*fpout = safe_fopen (tempfile, "w+"))) {
1602 mutt_perror (tempfile);
1605 mutt_unlink (tempfile);
1607 tmp_b = decrypt_part (bb, &s, *fpout, 1, &is_signed);
1609 tmp_b->goodsig = is_signed > 0;
1610 bb->type = saved_b_type;
1611 bb->length = saved_b_length;
1612 bb->offset = saved_b_offset;
1615 mutt_free_body (cur);
1618 return *cur ? 0 : -1;
1623 * Implementation of `pgp_check_traditional'.
1626 static int pgp_check_traditional_one_body (FILE * fp, BODY * b,
1629 char tempfile[_POSIX_PATH_MAX];
1630 char buf[HUGE_STRING];
1636 if (b->type != TYPETEXT)
1639 if (tagged_only && !b->tagged)
1642 mutt_mktemp (tempfile);
1643 if (mutt_decode_save_attachment (fp, b, tempfile, 0, 0) != 0) {
1648 if ((tfp = fopen (tempfile, "r")) == NULL) {
1653 while (fgets (buf, sizeof (buf), tfp)) {
1654 if (!mutt_strncmp ("-----BEGIN PGP ", buf, 15)) {
1655 if (!mutt_strcmp ("MESSAGE-----\n", buf + 15))
1657 else if (!mutt_strcmp ("SIGNED MESSAGE-----\n", buf + 15))
1667 /* fix the content type */
1669 mutt_set_parameter ("format", "fixed", &b->parameter);
1670 mutt_set_parameter ("x-action", enc ? "pgp-encrypted" : "pgp-signed",
1676 int pgp_gpgme_check_traditional (FILE * fp, BODY * b, int tagged_only)
1681 for (; b; b = b->next) {
1682 if (is_multipart (b))
1683 rv = (pgp_gpgme_check_traditional (fp, b->parts, tagged_only) || rv);
1684 else if (b->type == TYPETEXT) {
1685 if ((r = mutt_is_application_pgp (b)))
1688 rv = (pgp_check_traditional_one_body (fp, b, tagged_only) || rv);
1696 * Implementation of `application_handler'.
1700 Copy a clearsigned message, and strip the signature and PGP's
1703 XXX - charset handling: We assume that it is safe to do
1704 character set decoding first, dash decoding second here, while
1705 we do it the other way around in the main handler.
1707 (Note that we aren't worse than Outlook & Cie in this, and also
1708 note that we can successfully handle anything produced by any
1709 existing versions of mutt.) */
1711 static void copy_clearsigned (gpgme_data_t data, STATE * s, char *charset)
1713 char buf[HUGE_STRING];
1714 short complete, armor_header;
1719 fname = data_object_to_tempfile (data, &fp);
1725 fc = fgetconv_open (fp, charset, Charset, M_ICONV_HOOK_FROM);
1727 for (complete = 1, armor_header = 1;
1728 fgetconvs (buf, sizeof (buf), fc) != NULL;
1729 complete = strchr (buf, '\n') != NULL) {
1732 state_puts (buf, s);
1736 if (!mutt_strcmp (buf, "-----BEGIN PGP SIGNATURE-----\n"))
1746 state_puts (s->prefix, s);
1748 if (buf[0] == '-' && buf[1] == ' ')
1749 state_puts (buf + 2, s);
1751 state_puts (buf, s);
1754 fgetconv_close (&fc);
1759 /* Support for classic_application/pgp */
1760 void pgp_gpgme_application_handler (BODY * m, STATE * s)
1762 int needpass = -1, pgp_keyblock = 0;
1765 long bytes, last_pos, offset;
1766 char buf[HUGE_STRING];
1767 FILE *pgpout = NULL;
1770 gpgme_data_t armored_data = NULL;
1772 short maybe_goodsig = 1;
1773 short have_any_sigs = 0;
1775 char body_charset[STRING]; /* Only used for clearsigned messages. */
1777 dprint (2, (debugfile, "Entering pgp_application_pgp handler\n"));
1779 /* For clearsigned messages we won't be able to get a character set
1780 but we know that this may only be text thus we assume Latin-1
1782 if (!mutt_get_body_charset (body_charset, sizeof (body_charset), m))
1783 strfcpy (body_charset, "iso-8859-1", sizeof body_charset);
1785 fseek (s->fpin, m->offset, 0);
1786 last_pos = m->offset;
1788 for (bytes = m->length; bytes > 0;) {
1789 if (fgets (buf, sizeof (buf), s->fpin) == NULL)
1792 offset = ftell (s->fpin);
1793 bytes -= (offset - last_pos); /* don't rely on mutt_strlen(buf) */
1796 if (!mutt_strncmp ("-----BEGIN PGP ", buf, 15)) {
1798 start_pos = last_pos;
1800 if (!mutt_strcmp ("MESSAGE-----\n", buf + 15))
1802 else if (!mutt_strcmp ("SIGNED MESSAGE-----\n", buf + 15)) {
1806 else if (!option (OPTDONTHANDLEPGPKEYS) &&
1807 !mutt_strcmp ("PUBLIC KEY BLOCK-----\n", buf + 15)) {
1812 /* XXX - we may wish to recode here */
1814 state_puts (s->prefix, s);
1815 state_puts (buf, s);
1819 have_any_sigs = (have_any_sigs || (clearsign && (s->flags & M_VERIFY)));
1821 /* Copy PGP material to an data container */
1822 armored_data = create_gpgme_data ();
1823 gpgme_data_write (armored_data, buf, strlen (buf));
1824 while (bytes > 0 && fgets (buf, sizeof (buf) - 1, s->fpin) != NULL) {
1825 offset = ftell (s->fpin);
1826 bytes -= (offset - last_pos); /* don't rely on mutt_strlen(buf) */
1829 gpgme_data_write (armored_data, buf, strlen (buf));
1831 if ((needpass && !mutt_strcmp ("-----END PGP MESSAGE-----\n", buf))
1833 && (!mutt_strcmp ("-----END PGP SIGNATURE-----\n", buf)
1834 || !mutt_strcmp ("-----END PGP PUBLIC KEY BLOCK-----\n",
1839 /* Invoke PGP if needed */
1840 if (!clearsign || (s->flags & M_VERIFY)) {
1841 unsigned int sig_stat = 0;
1842 gpgme_data_t plaintext;
1845 plaintext = create_gpgme_data ();
1846 ctx = create_gpgme_context (0);
1849 err = gpgme_op_verify (ctx, armored_data, NULL, plaintext);
1851 err = gpgme_op_decrypt_verify (ctx, armored_data, plaintext);
1852 if (gpg_err_code (err) == GPG_ERR_NO_DATA) {
1853 /* Decrypt verify can't handle signed only messages. */
1854 err = (gpgme_data_seek (armored_data, 0, SEEK_SET) == -1)
1855 ? gpgme_error_from_errno (errno) : 0;
1856 /* Must release plaintext so that we supply an
1857 uninitialized object. */
1858 gpgme_data_release (plaintext);
1859 plaintext = create_gpgme_data ();
1860 err = gpgme_op_verify (ctx, armored_data, NULL, plaintext);
1867 snprintf (errbuf, sizeof (errbuf) - 1,
1868 _("Error: decryption/verification failed: %s\n"),
1869 gpgme_strerror (err));
1870 state_attach_puts (errbuf, s);
1872 else { /* Decryption/Verification succeeded */
1876 /* Check wether signatures have been verified. */
1877 gpgme_verify_result_t verify_result;
1879 verify_result = gpgme_op_verify_result (ctx);
1880 if (verify_result->signatures)
1886 if ((s->flags & M_DISPLAY) && sig_stat) {
1891 state_attach_puts (_("[-- Begin signature "
1892 "information --]\n"), s);
1895 (res = show_one_sig_status (ctx, idx, s)) != -1; idx++) {
1904 state_attach_puts (_("[-- End signature "
1905 "information --]\n\n"), s);
1908 tmpfname = data_object_to_tempfile (plaintext, &pgpout);
1911 state_attach_puts (_("Error: copy data failed\n"), s);
1918 gpgme_release (ctx);
1922 * Now, copy cleartext to the screen. NOTE - we expect that PGP
1923 * outputs utf-8 cleartext. This may not always be true, but it
1924 * seems to be a reasonable guess.
1927 if (s->flags & M_DISPLAY) {
1929 state_attach_puts (_("[-- BEGIN PGP MESSAGE --]\n\n"), s);
1930 else if (pgp_keyblock)
1931 state_attach_puts (_("[-- BEGIN PGP PUBLIC KEY BLOCK --]\n"), s);
1933 state_attach_puts (_("[-- BEGIN PGP SIGNED MESSAGE --]\n\n"), s);
1937 copy_clearsigned (armored_data, s, body_charset);
1944 fc = fgetconv_open (pgpout, "utf-8", Charset, 0);
1945 while ((c = fgetconv (fc)) != EOF) {
1947 if (c == '\n' && s->prefix)
1948 state_puts (s->prefix, s);
1950 fgetconv_close (&fc);
1953 if (s->flags & M_DISPLAY) {
1954 state_putc ('\n', s);
1956 state_attach_puts (_("[-- END PGP MESSAGE --]\n"), s);
1957 else if (pgp_keyblock)
1958 state_attach_puts (_("[-- END PGP PUBLIC KEY BLOCK --]\n"), s);
1960 state_attach_puts (_("[-- END PGP SIGNED MESSAGE --]\n"), s);
1964 safe_fclose (&pgpout);
1968 /* XXX - we may wish to recode here */
1970 state_puts (s->prefix, s);
1971 state_puts (buf, s);
1975 m->goodsig = (maybe_goodsig && have_any_sigs);
1977 if (needpass == -1) {
1978 state_attach_puts (_("[-- Error: could not find beginning"
1979 " of PGP message! --]\n\n"), s);
1982 dprint (2, (debugfile, "Leaving pgp_application_pgp handler\n"));
1986 * Implementation of `encrypted_handler'.
1989 /* MIME handler for pgp/mime encrypted messages. */
1990 void pgp_gpgme_encrypted_handler (BODY * a, STATE * s)
1992 char tempfile[_POSIX_PATH_MAX];
1995 BODY *orig_body = a;
1998 dprint (2, (debugfile, "Entering pgp_encrypted handler\n"));
2000 if (!a || a->type != TYPEAPPLICATION || !a->subtype
2001 || ascii_strcasecmp ("pgp-encrypted", a->subtype)
2002 || !a->next || a->next->type != TYPEAPPLICATION || !a->next->subtype
2003 || ascii_strcasecmp ("octet-stream", a->next->subtype)) {
2004 if (s->flags & M_DISPLAY)
2005 state_attach_puts (_("[-- Error: malformed PGP/MIME message! --]\n\n"),
2010 /* Move forward to the application/pgp-encrypted body. */
2013 mutt_mktemp (tempfile);
2014 if (!(fpout = safe_fopen (tempfile, "w+"))) {
2015 if (s->flags & M_DISPLAY)
2016 state_attach_puts (_("[-- Error: could not create temporary file! "
2021 tattach = decrypt_part (a, s, fpout, 0, &is_signed);
2023 tattach->goodsig = is_signed > 0;
2025 if (s->flags & M_DISPLAY)
2026 state_attach_puts (is_signed ?
2028 ("[-- The following data is PGP/MIME signed and encrypted --]\n\n")
2031 ("[-- The following data is PGP/MIME encrypted --]\n\n"),
2035 FILE *savefp = s->fpin;
2038 mutt_body_handler (tattach, s);
2043 * if a multipart/signed is the _only_ sub-part of a
2044 * multipart/encrypted, cache signature verification
2047 if (mutt_is_multipart_signed (tattach) && !tattach->next)
2048 orig_body->goodsig |= tattach->goodsig;
2050 if (s->flags & M_DISPLAY) {
2051 state_puts ("\n", s);
2052 state_attach_puts (is_signed ?
2054 ("[-- End of PGP/MIME signed and encrypted data --]\n")
2055 : _("[-- End of PGP/MIME encrypted data --]\n"), s);
2058 mutt_free_body (&tattach);
2062 mutt_unlink (tempfile);
2063 dprint (2, (debugfile, "Leaving pgp_encrypted handler\n"));
2066 /* Support for application/smime */
2067 void smime_gpgme_application_handler (BODY * a, STATE * s)
2069 char tempfile[_POSIX_PATH_MAX];
2075 dprint (2, (debugfile, "Entering smime_encrypted handler\n"));
2078 mutt_mktemp (tempfile);
2079 if (!(fpout = safe_fopen (tempfile, "w+"))) {
2080 if (s->flags & M_DISPLAY)
2081 state_attach_puts (_("[-- Error: could not create temporary file! "
2086 tattach = decrypt_part (a, s, fpout, 1, &is_signed);
2088 tattach->goodsig = is_signed > 0;
2090 if (s->flags & M_DISPLAY)
2091 state_attach_puts (is_signed ?
2092 _("[-- The following data is S/MIME signed --]\n\n")
2095 ("[-- The following data is S/MIME encrypted --]\n\n"),
2099 FILE *savefp = s->fpin;
2102 mutt_body_handler (tattach, s);
2107 * if a multipart/signed is the _only_ sub-part of a
2108 * multipart/encrypted, cache signature verification
2111 if (mutt_is_multipart_signed (tattach) && !tattach->next) {
2112 if (!(a->goodsig = tattach->goodsig))
2113 a->warnsig = tattach->warnsig;
2115 else if (tattach->goodsig) {
2117 a->warnsig = tattach->warnsig;
2120 if (s->flags & M_DISPLAY) {
2121 state_puts ("\n", s);
2122 state_attach_puts (is_signed ?
2123 _("[-- End of S/MIME signed data --]\n") :
2124 _("[-- End of S/MIME encrypted data --]\n"), s);
2127 mutt_free_body (&tattach);
2131 mutt_unlink (tempfile);
2132 dprint (2, (debugfile, "Leaving smime_encrypted handler\n"));
2137 * Format an entry on the CRYPT key selection menu.
2140 * %k key id %K key id of the principal key
2142 * %a algorithm %A algorithm of the princ. key
2143 * %l length %L length of the princ. key
2144 * %f flags %F flags of the princ. key
2145 * %c capabilities %C capabilities of the princ. key
2146 * %t trust/validity of the key-uid association
2148 * %[...] date of key using strftime(3)
2151 static const char *crypt_entry_fmt (char *dest,
2156 const char *ifstring,
2157 const char *elsestring,
2158 unsigned long data, format_flag flags)
2161 crypt_entry_t *entry;
2164 int optional = (flags & M_FORMAT_OPTIONAL);
2165 const char *s = NULL;
2168 entry = (crypt_entry_t *) data;
2171 /* if (isupper ((unsigned char) op)) */
2174 kflags = (key->flags /*| (pkey->flags & KEYFLAG_RESTRICTIONS)
2177 switch (ascii_tolower (op)) {
2181 char buf2[SHORT_STRING], *p;
2197 while (len > 0 && *cp != ']') {
2206 break; /* not enough space */
2216 if (do_locales && Locale)
2217 setlocale (LC_TIME, Locale);
2222 if (key->kobj->subkeys && (key->kobj->subkeys->timestamp > 0))
2223 tt = key->kobj->subkeys->timestamp;
2225 tm = localtime (&tt);
2227 strftime (buf2, sizeof (buf2), dest, tm);
2230 setlocale (LC_TIME, "C");
2232 snprintf (fmt, sizeof (fmt), "%%%ss", prefix);
2233 snprintf (dest, destlen, fmt, buf2);
2240 snprintf (fmt, sizeof (fmt), "%%%sd", prefix);
2241 snprintf (dest, destlen, fmt, entry->num);
2246 /* fixme: we need a way to distinguish between main and subkeys.
2247 Store the idx in entry? */
2248 snprintf (fmt, sizeof (fmt), "%%%ss", prefix);
2249 snprintf (dest, destlen, fmt, crypt_keyid (key));
2254 snprintf (fmt, sizeof (fmt), "%%%ss", prefix);
2255 snprintf (dest, destlen, fmt, key->uid);
2260 snprintf (fmt, sizeof (fmt), "%%%s.3s", prefix);
2261 if (key->kobj->subkeys)
2262 s = gpgme_pubkey_algo_name (key->kobj->subkeys->pubkey_algo);
2265 snprintf (dest, destlen, fmt, s);
2270 snprintf (fmt, sizeof (fmt), "%%%slu", prefix);
2271 if (key->kobj->subkeys)
2272 val = key->kobj->subkeys->length;
2275 snprintf (dest, destlen, fmt, val);
2280 snprintf (fmt, sizeof (fmt), "%%%sc", prefix);
2281 snprintf (dest, destlen, fmt, crypt_flags (kflags));
2283 else if (!(kflags & (KEYFLAG_RESTRICTIONS)))
2288 snprintf (fmt, sizeof (fmt), "%%%ss", prefix);
2289 snprintf (dest, destlen, fmt, crypt_key_abilities (kflags));
2291 else if (!(kflags & (KEYFLAG_ABILITIES)))
2295 if ((kflags & KEYFLAG_ISX509))
2298 gpgme_user_id_t uid = NULL;
2301 for (i = 0, uid = key->kobj->uids; uid && (i < key->idx);
2302 i++, uid = uid->next);
2304 switch (uid->validity) {
2305 case GPGME_VALIDITY_UNDEFINED:
2308 case GPGME_VALIDITY_NEVER:
2311 case GPGME_VALIDITY_MARGINAL:
2314 case GPGME_VALIDITY_FULL:
2317 case GPGME_VALIDITY_ULTIMATE:
2320 case GPGME_VALIDITY_UNKNOWN:
2326 snprintf (fmt, sizeof (fmt), "%%%sc", prefix);
2327 snprintf (dest, destlen, fmt, s ? *s : 'B');
2330 snprintf (fmt, sizeof (fmt), "%%%ss", prefix);
2331 snprintf (dest, destlen, fmt,
2332 gpgme_get_protocol_name (key->kobj->protocol));
2340 mutt_FormatString (dest, destlen, ifstring, mutt_attach_fmt, data, 0);
2341 else if (flags & M_FORMAT_OPTIONAL)
2342 mutt_FormatString (dest, destlen, elsestring, mutt_attach_fmt, data, 0);
2346 /* Used by the display fucntion to format a line. */
2347 static void crypt_entry (char *s, size_t l, MUTTMENU * menu, int num)
2349 crypt_key_t **key_table = (crypt_key_t **) menu->data;
2350 crypt_entry_t entry;
2352 entry.key = key_table[num];
2353 entry.num = num + 1;
2355 mutt_FormatString (s, l, NONULL (PgpEntryFormat), crypt_entry_fmt,
2356 (unsigned long) &entry, M_FORMAT_ARROWCURSOR);
2359 /* Compare two addresses and the keyid to be used for sorting. */
2360 static int _crypt_compare_address (const void *a, const void *b)
2362 crypt_key_t **s = (crypt_key_t **) a;
2363 crypt_key_t **t = (crypt_key_t **) b;
2366 if ((r = mutt_strcasecmp ((*s)->uid, (*t)->uid)))
2369 return mutt_strcasecmp (crypt_keyid (*s), crypt_keyid (*t)) > 0;
2372 static int crypt_compare_address (const void *a, const void *b)
2374 return ((PgpSortKeys & SORT_REVERSE) ? !_crypt_compare_address (a, b)
2375 : _crypt_compare_address (a, b));
2379 /* Compare two key IDs and the addresses to be used for sorting. */
2380 static int _crypt_compare_keyid (const void *a, const void *b)
2382 crypt_key_t **s = (crypt_key_t **) a;
2383 crypt_key_t **t = (crypt_key_t **) b;
2386 if ((r = mutt_strcasecmp (crypt_keyid (*s), crypt_keyid (*t))))
2389 return mutt_strcasecmp ((*s)->uid, (*t)->uid) > 0;
2392 static int crypt_compare_keyid (const void *a, const void *b)
2394 return ((PgpSortKeys & SORT_REVERSE) ? !_crypt_compare_keyid (a, b)
2395 : _crypt_compare_keyid (a, b));
2398 /* Compare 2 creation dates and the addresses. For sorting. */
2399 static int _crypt_compare_date (const void *a, const void *b)
2401 crypt_key_t **s = (crypt_key_t **) a;
2402 crypt_key_t **t = (crypt_key_t **) b;
2403 unsigned long ts = 0, tt = 0;
2405 if ((*s)->kobj->subkeys && ((*s)->kobj->subkeys->timestamp > 0))
2406 ts = (*s)->kobj->subkeys->timestamp;
2407 if ((*t)->kobj->subkeys && ((*t)->kobj->subkeys->timestamp > 0))
2408 tt = (*t)->kobj->subkeys->timestamp;
2415 return mutt_strcasecmp ((*s)->uid, (*t)->uid) > 0;
2418 static int crypt_compare_date (const void *a, const void *b)
2420 return ((PgpSortKeys & SORT_REVERSE) ? !_crypt_compare_date (a, b)
2421 : _crypt_compare_date (a, b));
2424 /* Compare two trust values, the key length, the creation dates. the
2425 addresses and the key IDs. For sorting. */
2426 static int _crypt_compare_trust (const void *a, const void *b)
2428 crypt_key_t **s = (crypt_key_t **) a;
2429 crypt_key_t **t = (crypt_key_t **) b;
2430 unsigned long ts = 0, tt = 0;
2433 if ((r = (((*s)->flags & (KEYFLAG_RESTRICTIONS))
2434 - ((*t)->flags & (KEYFLAG_RESTRICTIONS)))))
2437 if ((*s)->kobj->uids)
2438 ts = (*s)->kobj->uids->validity;
2439 if ((*t)->kobj->uids)
2440 tt = (*t)->kobj->uids->validity;
2441 if ((r = (tt - ts)))
2444 if ((*s)->kobj->subkeys)
2445 ts = (*s)->kobj->subkeys->length;
2446 if ((*t)->kobj->subkeys)
2447 tt = (*t)->kobj->subkeys->length;
2451 if ((*s)->kobj->subkeys && ((*s)->kobj->subkeys->timestamp > 0))
2452 ts = (*s)->kobj->subkeys->timestamp;
2453 if ((*t)->kobj->subkeys && ((*t)->kobj->subkeys->timestamp > 0))
2454 tt = (*t)->kobj->subkeys->timestamp;
2460 if ((r = mutt_strcasecmp ((*s)->uid, (*t)->uid)))
2462 return (mutt_strcasecmp (crypt_keyid ((*s)), crypt_keyid ((*t)))) > 0;
2465 static int crypt_compare_trust (const void *a, const void *b)
2467 return ((PgpSortKeys & SORT_REVERSE) ? !_crypt_compare_trust (a, b)
2468 : _crypt_compare_trust (a, b));
2471 /* Print the X.500 Distinguished Name part KEY from the array of parts
2473 static int print_dn_part (FILE * fp, struct dn_array_s *dn, const char *key)
2477 for (; dn->key; dn++) {
2478 if (!strcmp (dn->key, key)) {
2481 print_utf8 (fp, dn->value, strlen (dn->value));
2488 /* Print all parts of a DN in a standard sequence. */
2489 static void print_dn_parts (FILE * fp, struct dn_array_s *dn)
2491 const char *stdpart[] = {
2492 "CN", "OU", "O", "STREET", "L", "ST", "C", NULL
2494 int any = 0, any2 = 0, i;
2496 for (i = 0; stdpart[i]; i++) {
2499 any = print_dn_part (fp, dn, stdpart[i]);
2501 /* now print the rest without any specific ordering */
2502 for (; dn->key; dn++) {
2503 for (i = 0; stdpart[i]; i++) {
2504 if (!strcmp (dn->key, stdpart[i]))
2512 any = print_dn_part (fp, dn, dn->key);
2521 /* Parse an RDN; this is a helper to parse_dn(). */
2522 static const unsigned char *parse_dn_part (struct dn_array_s *array,
2523 const unsigned char *string)
2525 const unsigned char *s, *s1;
2529 /* parse attributeType */
2530 for (s = string + 1; *s && *s != '='; s++);
2532 return NULL; /* error */
2535 return NULL; /* empty key */
2536 array->key = safe_malloc (n + 1);
2537 p = (unsigned char *) array->key;
2538 memcpy (p, string, n); /* fixme: trim trailing spaces */
2542 if (*string == '#') { /* hexstring */
2544 for (s = string; hexdigitp (s); s++)
2548 return NULL; /* empty or odd number of digits */
2550 p = safe_malloc (n + 1);
2551 array->value = (char *) p;
2552 for (s1 = string; n; s1 += 2, n--)
2556 else { /* regular v3 quoted string */
2557 for (n = 0, s = string; *s; s++) {
2558 if (*s == '\\') { /* pair */
2560 if (*s == ',' || *s == '=' || *s == '+'
2561 || *s == '<' || *s == '>' || *s == '#' || *s == ';'
2562 || *s == '\\' || *s == '\"' || *s == ' ')
2564 else if (hexdigitp (s) && hexdigitp (s + 1)) {
2569 return NULL; /* invalid escape sequence */
2571 else if (*s == '\"')
2572 return NULL; /* invalid encoding */
2573 else if (*s == ',' || *s == '=' || *s == '+'
2574 || *s == '<' || *s == '>' || *s == '#' || *s == ';')
2580 p = safe_malloc (n + 1);
2581 array->value = (char *) p;
2582 for (s = string; n; s++, n--) {
2585 if (hexdigitp (s)) {
2601 /* Parse a DN and return an array-ized one. This is not a validating
2602 parser and it does not support any old-stylish syntax; gpgme is
2603 expected to return only rfc2253 compatible strings. */
2604 static struct dn_array_s *parse_dn (const unsigned char *string)
2606 struct dn_array_s *array;
2607 size_t arrayidx, arraysize;
2610 arraysize = 7; /* C,ST,L,O,OU,CN,email */
2611 array = safe_malloc ((arraysize + 1) * sizeof *array);
2614 while (*string == ' ')
2618 if (arrayidx >= arraysize) { /* mutt lacks a real safe_realoc - so we need to copy */
2619 struct dn_array_s *a2;
2622 a2 = safe_malloc ((arraysize + 1) * sizeof *array);
2623 for (i = 0; i < arrayidx; i++) {
2624 a2[i].key = array[i].key;
2625 a2[i].value = array[i].value;
2630 array[arrayidx].key = NULL;
2631 array[arrayidx].value = NULL;
2632 string = parse_dn_part (array + arrayidx, string);
2636 while (*string == ' ')
2638 if (*string && *string != ',' && *string != ';' && *string != '+')
2639 goto failure; /* invalid delimiter */
2643 array[arrayidx].key = NULL;
2644 array[arrayidx].value = NULL;
2648 for (i = 0; i < arrayidx; i++) {
2649 FREE (&array[i].key);
2650 FREE (&array[i].value);
2657 /* Print a nice representation of the USERID and make sure it is
2658 displayed in a proper way, which does mean to reorder some parts
2659 for S/MIME's DNs. USERID is a string as returned by the gpgme key
2660 functions. It is utf-8 encoded. */
2661 static void parse_and_print_user_id (FILE * fp, const char *userid)
2666 if (*userid == '<') {
2667 s = strchr (userid + 1, '>');
2669 print_utf8 (fp, userid + 1, s - userid - 1);
2671 else if (*userid == '(')
2672 fputs (_("[Can't display this user ID (unknown encoding)]"), fp);
2673 else if (!digit_or_letter ((const unsigned char *) userid))
2674 fputs (_("[Can't display this user ID (invalid encoding)]"), fp);
2676 struct dn_array_s *dn = parse_dn ((const unsigned char *) userid);
2679 fputs (_("[Can't display this user ID (invalid DN)]"), fp);
2681 print_dn_parts (fp, dn);
2682 for (i = 0; dn[i].key; i++) {
2684 FREE (&dn[i].value);
2692 KEY_CAP_CAN_ENCRYPT,
2697 static unsigned int key_check_cap (gpgme_key_t key, key_cap_t cap)
2699 gpgme_subkey_t subkey = NULL;
2700 unsigned int ret = 0;
2703 case KEY_CAP_CAN_ENCRYPT:
2704 if (!(ret = key->can_encrypt))
2705 for (subkey = key->subkeys; subkey; subkey = subkey->next)
2706 if ((ret = subkey->can_encrypt))
2709 case KEY_CAP_CAN_SIGN:
2710 if (!(ret = key->can_sign))
2711 for (subkey = key->subkeys; subkey; subkey = subkey->next)
2712 if ((ret = subkey->can_sign))
2715 case KEY_CAP_CAN_CERTIFY:
2716 if (!(ret = key->can_certify))
2717 for (subkey = key->subkeys; subkey; subkey = subkey->next)
2718 if ((ret = subkey->can_certify))
2727 /* Print verbose information about a key or certificate to FP. */
2728 static void print_key_info (gpgme_key_t key, FILE * fp)
2731 const char *s = NULL, *s2 = NULL;
2734 char shortbuf[SHORT_STRING];
2735 unsigned long aval = 0;
2739 gpgme_user_id_t uid = NULL;
2742 setlocale (LC_TIME, Locale);
2744 is_pgp = key->protocol == GPGME_PROTOCOL_OpenPGP;
2746 for (idx = 0, uid = key->uids; uid; idx++, uid = uid->next) {
2751 fprintf (fp, "%s ......: ", idx ? _(" aka") : _("Name"));
2753 fputs (_("[Invalid]"), fp);
2757 print_utf8 (fp, s, strlen (s));
2759 parse_and_print_user_id (fp, s);
2763 if (key->subkeys && (key->subkeys->timestamp > 0)) {
2764 tt = key->subkeys->timestamp;
2766 tm = localtime (&tt);
2767 #ifdef HAVE_LANGINFO_D_T_FMT
2768 strftime (shortbuf, sizeof shortbuf, nl_langinfo (D_T_FMT), tm);
2770 strftime (shortbuf, sizeof shortbuf, "%c", tm);
2772 fprintf (fp, "Valid From : %s\n", shortbuf);
2775 if (key->subkeys && (key->subkeys->expires > 0)) {
2776 tt = key->subkeys->expires;
2778 tm = localtime (&tt);
2779 #ifdef HAVE_LANGINFO_D_T_FMT
2780 strftime (shortbuf, sizeof shortbuf, nl_langinfo (D_T_FMT), tm);
2782 strftime (shortbuf, sizeof shortbuf, "%c", tm);
2784 fprintf (fp, "Valid To ..: %s\n", shortbuf);
2788 s = gpgme_pubkey_algo_name (key->subkeys->pubkey_algo);
2792 s2 = is_pgp ? "PGP" : "X.509";
2795 aval = key->subkeys->length;
2797 fprintf (fp, "Key Type ..: %s, %lu bit %s\n", s2, aval, s);
2799 fprintf (fp, "Key Usage .: ");
2802 if (key_check_cap (key, KEY_CAP_CAN_ENCRYPT)) {
2803 fprintf (fp, "%s%s", delim, _("encryption"));
2806 if (key_check_cap (key, KEY_CAP_CAN_SIGN)) {
2807 fprintf (fp, "%s%s", delim, _("signing"));
2810 if (key_check_cap (key, KEY_CAP_CAN_CERTIFY)) {
2811 fprintf (fp, "%s%s", delim, _("certification"));
2817 s = key->subkeys->fpr;
2818 fputs (_("Fingerprint: "), fp);
2819 if (is_pgp && strlen (s) == 40) {
2820 for (i = 0; *s && s[1] && s[2] && s[3] && s[4]; s += 4, i++) {
2825 putc (is_pgp ? ' ' : ':', fp);
2826 if (is_pgp && i == 4)
2831 for (i = 0; *s && s[1] && s[2]; s += 2, i++) {
2834 putc (is_pgp ? ' ' : ':', fp);
2835 if (is_pgp && i == 7)
2839 fprintf (fp, "%s\n", s);
2842 if (key->issuer_serial) {
2843 s = key->issuer_serial;
2845 fprintf (fp, "Serial-No .: 0x%s\n", s);
2848 if (key->issuer_name) {
2849 s = key->issuer_name;
2851 fprintf (fp, "Issued By .: ");
2852 parse_and_print_user_id (fp, s);
2857 /* For PGP we list all subkeys. */
2859 gpgme_subkey_t subkey = NULL;
2861 for (idx = 1, subkey = key->subkeys; subkey; idx++, subkey = subkey->next) {
2865 if (strlen (s) == 16)
2866 s += 8; /* display only the short keyID */
2867 fprintf (fp, "Subkey ....: 0x%s", s);
2868 if (subkey->revoked) {
2870 fputs (_("[Revoked]"), fp);
2872 if (subkey->invalid) {
2874 fputs (_("[Invalid]"), fp);
2876 if (subkey->expired) {
2878 fputs (_("[Expired]"), fp);
2880 if (subkey->disabled) {
2882 fputs (_("[Disabled]"), fp);
2886 if (subkey->timestamp > 0) {
2887 tt = subkey->timestamp;
2889 tm = localtime (&tt);
2890 #ifdef HAVE_LANGINFO_D_T_FMT
2891 strftime (shortbuf, sizeof shortbuf, nl_langinfo (D_T_FMT), tm);
2893 strftime (shortbuf, sizeof shortbuf, "%c", tm);
2895 fprintf (fp, "Valid From : %s\n", shortbuf);
2898 if (subkey->expires > 0) {
2899 tt = subkey->expires;
2901 tm = localtime (&tt);
2902 #ifdef HAVE_LANGINFO_D_T_FMT
2903 strftime (shortbuf, sizeof shortbuf, nl_langinfo (D_T_FMT), tm);
2905 strftime (shortbuf, sizeof shortbuf, "%c", tm);
2907 fprintf (fp, "Valid To ..: %s\n", shortbuf);
2911 s = gpgme_pubkey_algo_name (subkey->pubkey_algo);
2916 aval = subkey->length;
2920 fprintf (fp, "Key Type ..: %s, %lu bit %s\n", "PGP", aval, s);
2922 fprintf (fp, "Key Usage .: ");
2925 if (subkey->can_encrypt) {
2926 fprintf (fp, "%s%s", delim, _("encryption"));
2929 if (subkey->can_sign) {
2930 fprintf (fp, "%s%s", delim, _("signing"));
2933 if (subkey->can_certify) {
2934 fprintf (fp, "%s%s", delim, _("certification"));
2942 setlocale (LC_TIME, "C");
2946 /* Show detailed information about the selected key */
2947 static void verify_key (crypt_key_t * key)
2950 char cmd[LONG_STRING], tempfile[_POSIX_PATH_MAX];
2952 gpgme_ctx_t listctx = NULL;
2954 gpgme_key_t k = NULL;
2957 mutt_mktemp (tempfile);
2958 if (!(fp = safe_fopen (tempfile, "w"))) {
2959 mutt_perror _("Can't create temporary file");
2963 mutt_message _("Collecting data...");
2965 print_key_info (key->kobj, fp);
2967 err = gpgme_new (&listctx);
2969 fprintf (fp, "Internal error: can't create gpgme context: %s\n",
2970 gpgme_strerror (err));
2973 if ((key->flags & KEYFLAG_ISX509))
2974 gpgme_set_protocol (listctx, GPGME_PROTOCOL_CMS);
2978 while ((s = k->chain_id) && k->subkeys && strcmp (s, k->subkeys->fpr)) {
2980 err = gpgme_op_keylist_start (listctx, s, 0);
2981 gpgme_key_release (k);
2984 err = gpgme_op_keylist_next (listctx, &k);
2986 fprintf (fp, _("Error finding issuer key: %s\n"), gpgme_strerror (err));
2989 gpgme_op_keylist_end (listctx);
2991 print_key_info (k, fp);
2994 fputs (_("Error: certification chain to long - stopping here\n"), fp);
3000 gpgme_key_release (k);
3001 gpgme_release (listctx);
3003 mutt_clear_error ();
3004 snprintf (cmd, sizeof (cmd), _("Key ID: 0x%s"), crypt_keyid (key));
3005 mutt_do_pager (cmd, tempfile, 0, NULL);
3009 * Implementation of `findkeys'.
3013 /* Convert LIST into a pattern string suitable to be passed to GPGME.
3014 We need to convert spaces in an item into a '+' and '%' into
3016 static char *list_to_pattern (LIST * list)
3024 for (l = list; l; l = l->next) {
3025 for (s = l->data; *s; s++) {
3030 n++; /* delimiter or end of string */
3032 n++; /* make sure to allocate at least one byte */
3033 pattern = p = safe_calloc (1, n);
3034 for (l = list; l; l = l->next) {
3039 for (s = l->data; *s; s++) {
3045 else if (*s == '+') {
3061 /* Return a list of keys which are candidates for the selection.
3062 Select by looking at the HINTS list. */
3063 static crypt_key_t *get_candidates (LIST * hints, unsigned int app,
3066 crypt_key_t *db, *k, **kend;
3072 gpgme_user_id_t uid = NULL;
3074 pattern = list_to_pattern (hints);
3078 err = gpgme_new (&ctx);
3080 mutt_error ("gpgme_new failed: %s", gpgme_strerror (err));
3088 if ((app & APPLICATION_PGP)) {
3089 /* Its all a mess. That old GPGME expects different things
3090 depending on the protocol. For gpg we don' t need percent
3091 escaped pappert but simple strings passed in an array to the
3092 keylist_ext_start function. */
3097 for (l = hints, n = 0; l; l = l->next) {
3098 if (l->data && *l->data)
3104 patarr = safe_calloc (n + 1, sizeof *patarr);
3105 for (l = hints, n = 0; l; l = l->next) {
3106 if (l->data && *l->data)
3107 patarr[n++] = safe_strdup (l->data);
3110 err = gpgme_op_keylist_ext_start (ctx, (const char **) patarr, secret, 0);
3111 for (n = 0; patarr[n]; n++)
3115 mutt_error ("gpgme_op_keylist_start failed: %s", gpgme_strerror (err));
3116 gpgme_release (ctx);
3121 while (!(err = gpgme_op_keylist_next (ctx, &key))) {
3122 unsigned int flags = 0;
3124 if (key_check_cap (key, KEY_CAP_CAN_ENCRYPT))
3125 flags |= KEYFLAG_CANENCRYPT;
3126 if (key_check_cap (key, KEY_CAP_CAN_SIGN))
3127 flags |= KEYFLAG_CANSIGN;
3129 #if 0 /* DISABLED code */
3131 /* Bug in gpg. Capabilities are not listed for secret
3132 keys. Try to deduce them from the algorithm. */
3134 switch (key->subkeys[0].pubkey_algo) {
3136 flags |= KEYFLAG_CANENCRYPT;
3137 flags |= KEYFLAG_CANSIGN;
3139 case GPGME_PK_ELG_E:
3140 flags |= KEYFLAG_CANENCRYPT;
3143 flags |= KEYFLAG_CANSIGN;
3147 #endif /* DISABLED code */
3149 for (idx = 0, uid = key->uids; uid; idx++, uid = uid->next) {
3150 k = safe_calloc (1, sizeof *k);
3159 if (gpg_err_code (err) != GPG_ERR_EOF)
3160 mutt_error ("gpgme_op_keylist_next failed: %s", gpgme_strerror (err));
3161 gpgme_op_keylist_end (ctx);
3166 if ((app & APPLICATION_SMIME)) {
3167 /* and now look for x509 certificates */
3168 gpgme_set_protocol (ctx, GPGME_PROTOCOL_CMS);
3169 err = gpgme_op_keylist_start (ctx, pattern, 0);
3171 mutt_error ("gpgme_op_keylist_start failed: %s", gpgme_strerror (err));
3172 gpgme_release (ctx);
3177 while (!(err = gpgme_op_keylist_next (ctx, &key))) {
3178 unsigned int flags = KEYFLAG_ISX509;
3180 if (key_check_cap (key, KEY_CAP_CAN_ENCRYPT))
3181 flags |= KEYFLAG_CANENCRYPT;
3182 if (key_check_cap (key, KEY_CAP_CAN_SIGN))
3183 flags |= KEYFLAG_CANSIGN;
3185 for (idx = 0, uid = key->uids; uid; idx++, uid = uid->next) {
3186 k = safe_calloc (1, sizeof *k);
3195 if (gpg_err_code (err) != GPG_ERR_EOF)
3196 mutt_error ("gpgme_op_keylist_next failed: %s", gpgme_strerror (err));
3197 gpgme_op_keylist_end (ctx);
3200 gpgme_release (ctx);
3205 /* Add the string STR to the list HINTS. This list is later used to
3207 static LIST *crypt_add_string_to_hints (LIST * hints, const char *str)
3212 if ((scratch = safe_strdup (str)) == NULL)
3215 for (t = strtok (scratch, " ,.:\"()<>\n"); t;
3216 t = strtok (NULL, " ,.:\"()<>\n")) {
3218 hints = mutt_add_list (hints, t);
3225 /* Display a menu to select a key from the array KEYS. FORCED_VALID
3226 will be set to true on return if the user did override the the
3228 static crypt_key_t *crypt_select_key (crypt_key_t * keys,
3229 ADDRESS * p, const char *s,
3230 unsigned int app, int *forced_valid)
3233 crypt_key_t **key_table;
3236 char helpstr[SHORT_STRING], buf[LONG_STRING];
3238 int (*f) (const void *, const void *);
3239 int menu_to_use = 0;
3244 /* build the key table */
3247 for (k = keys; k; k = k->next) {
3248 if (!option (OPTPGPSHOWUNUSABLE) && (k->flags & KEYFLAG_CANTUSE)) {
3255 safe_realloc (&key_table, sizeof (crypt_key_t *) * keymax);
3261 if (!i && unusable) {
3262 mutt_error _("All matching keys are marked expired/revoked.");
3268 switch (PgpSortKeys & SORT_MASK) {
3270 f = crypt_compare_date;
3273 f = crypt_compare_keyid;
3276 f = crypt_compare_address;
3280 f = crypt_compare_trust;
3283 qsort (key_table, i, sizeof (crypt_key_t *), f);
3285 if (app & APPLICATION_PGP)
3286 menu_to_use = MENU_KEY_SELECT_PGP;
3287 else if (app & APPLICATION_SMIME)
3288 menu_to_use = MENU_KEY_SELECT_SMIME;
3291 mutt_make_help (buf, sizeof (buf), _("Exit "), menu_to_use, OP_EXIT);
3292 strcat (helpstr, buf); /* __STRCAT_CHECKED__ */
3293 mutt_make_help (buf, sizeof (buf), _("Select "), menu_to_use,
3294 OP_GENERIC_SELECT_ENTRY);
3295 strcat (helpstr, buf); /* __STRCAT_CHECKED__ */
3296 mutt_make_help (buf, sizeof (buf), _("Check key "),
3297 menu_to_use, OP_VERIFY_KEY);
3298 strcat (helpstr, buf); /* __STRCAT_CHECKED__ */
3299 mutt_make_help (buf, sizeof (buf), _("Help"), menu_to_use, OP_HELP);
3300 strcat (helpstr, buf); /* __STRCAT_CHECKED__ */
3302 menu = mutt_new_menu ();
3304 menu->make_entry = crypt_entry;
3305 menu->menu = menu_to_use;
3306 menu->help = helpstr;
3307 menu->data = key_table;
3312 if ((app & APPLICATION_PGP) && (app & APPLICATION_SMIME))
3313 ts = _("PGP and S/MIME keys matching");
3314 else if ((app & APPLICATION_PGP))
3315 ts = _("PGP keys matching");
3316 else if ((app & APPLICATION_SMIME))
3317 ts = _("S/MIME keys matching");
3319 ts = _("keys matching");
3322 snprintf (buf, sizeof (buf), _("%s <%s>."), ts, p->mailbox);
3324 snprintf (buf, sizeof (buf), _("%s \"%s\"."), ts, s);
3328 mutt_clear_error ();
3332 switch (mutt_menuLoop (menu)) {
3334 verify_key (key_table[menu->current]);
3335 menu->redraw = REDRAW_FULL;
3339 mutt_message ("%s", key_table[menu->current]->uid);
3342 case OP_GENERIC_SELECT_ENTRY:
3343 /* FIXME make error reporting more verbose - this should be
3344 easy because gpgme provides more information */
3345 if (option (OPTPGPCHECKTRUST)) {
3346 if (!crypt_key_is_valid (key_table[menu->current])) {
3347 mutt_error _("This key can't be used: "
3348 "expired/disabled/revoked.");
3353 if (option (OPTPGPCHECKTRUST) &&
3354 (!crypt_id_is_valid (key_table[menu->current])
3355 || !crypt_id_is_strong (key_table[menu->current]))) {
3357 char buff[LONG_STRING];
3359 if (key_table[menu->current]->flags & KEYFLAG_CANTUSE)
3360 s = N_("ID is expired/disabled/revoked.");
3362 gpgme_validity_t val = GPGME_VALIDITY_UNKNOWN;
3363 gpgme_user_id_t uid = NULL;
3368 uid = key_table[menu->current]->kobj->uids;
3369 for (j = 0; (j < key_table[menu->current]->idx) && uid;
3370 j++, uid = uid->next);
3372 val = uid->validity;
3375 case GPGME_VALIDITY_UNKNOWN:
3376 case GPGME_VALIDITY_UNDEFINED:
3377 warn_s = N_("ID has undefined validity.");
3379 case GPGME_VALIDITY_NEVER:
3380 warn_s = N_("ID is not valid.");
3382 case GPGME_VALIDITY_MARGINAL:
3383 warn_s = N_("ID is only marginally valid.");
3385 case GPGME_VALIDITY_FULL:
3386 case GPGME_VALIDITY_ULTIMATE:
3390 snprintf (buff, sizeof (buff),
3391 _("%s Do you really want to use the key?"), _(warn_s));
3393 if (mutt_yesorno (buff, 0) != 1) {
3394 mutt_clear_error ();
3401 k = crypt_copy_key (key_table[menu->current]);
3412 mutt_menuDestroy (&menu);
3415 set_option (OPTNEEDREDRAW);
3420 static crypt_key_t *crypt_getkeybyaddr (ADDRESS * a, short abilities,
3421 unsigned int app, int *forced_valid)
3429 int this_key_has_strong;
3430 int this_key_has_weak;
3431 int this_key_has_invalid;
3434 crypt_key_t *keys, *k;
3435 crypt_key_t *the_valid_key = NULL;
3436 crypt_key_t *matches = NULL;
3437 crypt_key_t **matches_endp = &matches;
3441 if (a && a->mailbox)
3442 hints = crypt_add_string_to_hints (hints, a->mailbox);
3443 if (a && a->personal)
3444 hints = crypt_add_string_to_hints (hints, a->personal);
3446 mutt_message (_("Looking for keys matching \"%s\"..."), a->mailbox);
3447 keys = get_candidates (hints, app, (abilities & KEYFLAG_CANSIGN));
3449 mutt_free_list (&hints);
3454 dprint (5, (debugfile, "crypt_getkeybyaddr: looking for %s <%s>.",
3455 a->personal, a->mailbox));
3457 for (k = keys; k; k = k->next) {
3458 dprint (5, (debugfile, " looking at key: %s `%.15s'\n",
3459 crypt_keyid (k), k->uid));
3461 if (abilities && !(k->flags & abilities)) {
3462 dprint (5, (debugfile, " insufficient abilities: Has %x, want %x\n",
3463 k->flags, abilities));
3467 this_key_has_weak = 0; /* weak but valid match */
3468 this_key_has_invalid = 0; /* invalid match */
3469 this_key_has_strong = 0; /* strong and valid match */
3470 match = 0; /* any match */
3472 r = rfc822_parse_adrlist (NULL, k->uid);
3473 for (p = r; p; p = p->next) {
3474 int validity = crypt_id_matches_addr (a, p, k);
3476 if (validity & CRYPT_KV_MATCH) /* something matches */
3479 /* is this key a strong candidate? */
3480 if ((validity & CRYPT_KV_VALID)
3481 && (validity & CRYPT_KV_STRONGID)
3482 && (validity & CRYPT_KV_ADDR)) {
3483 if (the_valid_key && the_valid_key != k)
3486 this_key_has_strong = 1;
3488 else if ((validity & CRYPT_KV_MATCH)
3489 && !(validity & CRYPT_KV_VALID))
3490 this_key_has_invalid = 1;
3491 else if ((validity & CRYPT_KV_MATCH)
3492 && (!(validity & CRYPT_KV_STRONGID)
3493 || !(validity & CRYPT_KV_ADDR)))
3494 this_key_has_weak = 1;
3496 rfc822_free_address (&r);
3501 if (!this_key_has_strong && this_key_has_invalid)
3503 if (!this_key_has_strong && this_key_has_weak)
3506 *matches_endp = tmp = crypt_copy_key (k);
3507 matches_endp = &tmp->next;
3508 the_valid_key = tmp;
3512 crypt_free_key (&keys);
3515 if (the_valid_key && !multi && !weak
3516 && !(invalid && option (OPTPGPSHOWUNUSABLE))) {
3518 * There was precisely one strong match on a valid ID, there
3519 * were no valid keys with weak matches, and we aren't
3520 * interested in seeing invalid keys.
3522 * Proceed without asking the user.
3524 k = crypt_copy_key (the_valid_key);
3528 * Else: Ask the user.
3530 k = crypt_select_key (matches, a, NULL, app, forced_valid);
3532 crypt_free_key (&matches);
3541 static crypt_key_t *crypt_getkeybystr (char *p, short abilities,
3542 unsigned int app, int *forced_valid)
3546 crypt_key_t *matches = NULL;
3547 crypt_key_t **matches_endp = &matches;
3551 mutt_message (_("Looking for keys matching \"%s\"..."), p);
3555 hints = crypt_add_string_to_hints (hints, p);
3556 keys = get_candidates (hints, app, (abilities & KEYFLAG_CANSIGN));
3557 mutt_free_list (&hints);
3562 for (k = keys; k; k = k->next) {
3563 if (abilities && !(k->flags & abilities))
3567 dprint (5, (debugfile, "crypt_getkeybystr: matching \"%s\" against "
3568 "key %s, \"%s\": ", p, crypt_keyid (k), k->uid));
3570 if (!*p || !mutt_strcasecmp (p, crypt_keyid (k))
3571 || (!mutt_strncasecmp (p, "0x", 2)
3572 && !mutt_strcasecmp (p + 2, crypt_keyid (k)))
3573 || (option (OPTPGPLONGIDS)
3574 && !mutt_strncasecmp (p, "0x", 2)
3575 && !mutt_strcasecmp (p + 2, crypt_keyid (k) + 8))
3576 || mutt_stristr (k->uid, p)) {
3579 dprint (5, (debugfile, "match.\n"));
3581 *matches_endp = tmp = crypt_copy_key (k);
3582 matches_endp = &tmp->next;
3586 crypt_free_key (&keys);
3589 k = crypt_select_key (matches, NULL, p, app, forced_valid);
3590 crypt_free_key (&matches);
3597 /* Display TAG as a prompt to ask for a key. If WHATFOR is not null
3598 use it as default and store it under that label as the next
3599 default. ABILITIES describe the required key abilities (sign,
3600 encrypt) and APP the type of the requested key; ether S/MIME or
3601 PGP. Return a copy of the key or NULL if not found. */
3602 static crypt_key_t *crypt_ask_for_key (char *tag,
3605 unsigned int app, int *forced_valid)
3608 char resp[SHORT_STRING];
3609 struct crypt_cache *l = NULL;
3613 forced_valid = &dummy;
3615 mutt_clear_error ();
3621 for (l = id_defaults; l; l = l->next)
3622 if (!mutt_strcasecmp (whatfor, l->what)) {
3623 strfcpy (resp, NONULL (l->dflt), sizeof (resp));
3631 if (mutt_get_field (tag, resp, sizeof (resp), M_CLEAR) != 0)
3636 mutt_str_replace (&l->dflt, resp);
3638 l = safe_malloc (sizeof (struct crypt_cache));
3639 l->next = id_defaults;
3641 l->what = safe_strdup (whatfor);
3642 l->dflt = safe_strdup (resp);
3646 if ((key = crypt_getkeybystr (resp, abilities, app, forced_valid)))
3654 /* This routine attempts to find the keyids of the recipients of a
3655 message. It returns NULL if any of the keys can not be found. */
3656 static char *find_keys (ADDRESS * to, ADDRESS * cc, ADDRESS * bcc,
3659 char *keyID, *keylist = NULL, *t;
3660 size_t keylist_size = 0;
3661 size_t keylist_used = 0;
3662 ADDRESS *tmp = NULL, *addr = NULL;
3663 ADDRESS **last = &tmp;
3666 crypt_key_t *k_info, *key;
3667 const char *fqdn = mutt_fqdn (1);
3670 *r_application = APPLICATION_PGP | APPLICATION_SMIME;
3673 for (i = 0; i < 3; i++) {
3688 *last = rfc822_cpy_adr (p);
3690 last = &((*last)->next);
3694 rfc822_qualify (tmp, fqdn);
3696 tmp = mutt_remove_duplicates (tmp);
3698 for (p = tmp; p; p = p->next) {
3699 char buf[LONG_STRING];
3700 int forced_valid = 0;
3705 if ((keyID = mutt_crypt_hook (p)) != NULL) {
3708 snprintf (buf, sizeof (buf), _("Use keyID = \"%s\" for %s?"),
3710 if ((r = mutt_yesorno (buf, M_YES)) == M_YES) {
3711 /* check for e-mail address */
3712 if ((t = strchr (keyID, '@')) &&
3713 (addr = rfc822_parse_adrlist (NULL, keyID))) {
3715 rfc822_qualify (addr, fqdn);
3720 k_info = crypt_getkeybystr (keyID, KEYFLAG_CANENCRYPT,
3721 *r_application, &forced_valid);
3723 k_info = crypt_getkeybystr (keyID, KEYFLAG_CANENCRYPT,
3724 app, &forced_valid);
3730 rfc822_free_address (&tmp);
3731 rfc822_free_address (&addr);
3737 && (k_info = crypt_getkeybyaddr (q, KEYFLAG_CANENCRYPT,
3738 app, &forced_valid)) == NULL) {
3739 snprintf (buf, sizeof (buf), _("Enter keyID for %s: "), q->mailbox);
3741 if ((key = crypt_ask_for_key (buf, q->mailbox, KEYFLAG_CANENCRYPT,
3747 &forced_valid)) == NULL) {
3749 rfc822_free_address (&tmp);
3750 rfc822_free_address (&addr);
3758 const char *s = crypt_fpr (key);
3761 if (key->flags & KEYFLAG_ISX509)
3762 *r_application &= ~APPLICATION_PGP;
3763 if (!(key->flags & KEYFLAG_ISX509))
3764 *r_application &= ~APPLICATION_SMIME;
3767 keylist_size += mutt_strlen (s) + 4 + 1;
3768 safe_realloc (&keylist, keylist_size);
3769 sprintf (keylist + keylist_used, "%s0x%s%s", /* __SPRINTF_CHECKED__ */
3770 keylist_used ? " " : "", s, forced_valid ? "!" : "");
3772 keylist_used = mutt_strlen (keylist);
3774 crypt_free_key (&key);
3775 rfc822_free_address (&addr);
3777 rfc822_free_address (&tmp);
3781 char *pgp_gpgme_findkeys (ADDRESS * to, ADDRESS * cc, ADDRESS * bcc)
3783 return find_keys (to, cc, bcc, APPLICATION_PGP);
3786 char *smime_gpgme_findkeys (ADDRESS * to, ADDRESS * cc, ADDRESS * bcc)
3788 return find_keys (to, cc, bcc, APPLICATION_SMIME);
3792 * Implementation of `init'.
3795 /* Initialization. */
3796 static void init_gpgme (void)
3798 /* Make sure that gpg-agent is running. */
3799 if (!getenv ("GPG_AGENT_INFO")) {
3800 mutt_error ("\nUsing GPGME backend, although no gpg-agent is running");
3801 if (mutt_any_key_to_continue (NULL) == -1)
3806 void pgp_gpgme_init (void)
3811 void smime_gpgme_init (void)
3815 static int gpgme_send_menu (HEADER * msg, int *redraw, int is_smime)
3818 char input_signas[SHORT_STRING];
3821 if (msg->security & APPLICATION_PGP)
3823 else if (msg->security & APPLICATION_SMIME)
3828 mutt_multi_choice (_
3829 ("S/MIME (e)ncrypt, (s)ign, sign (a)s, (b)oth, (t)oggle or (f)orget it?"),
3833 mutt_multi_choice (_
3834 ("PGP (e)ncrypt, (s)ign, sign (a)s, (b)oth, (t)oggle or (f)orget it?"),
3838 case 1: /* (e)ncrypt */
3839 msg->security |= (is_smime ? SMIMEENCRYPT : PGPENCRYPT);
3842 case 2: /* (s)ign */
3843 msg->security |= (is_smime ? SMIMESIGN : PGPSIGN);
3846 case 3: /* sign (a)s */
3847 /* unset_option(OPTCRYPTCHECKTRUST); */
3848 if ((p = crypt_ask_for_key (_("Sign as: "), NULL, KEYFLAG_CANSIGN,
3849 is_smime ? APPLICATION_SMIME :
3850 APPLICATION_PGP, NULL))) {
3851 snprintf (input_signas, sizeof (input_signas), "0x%s", crypt_keyid (p));
3852 mutt_str_replace (is_smime ? &SmimeDefaultKey : &PgpSignAs,
3854 crypt_free_key (&p);
3856 msg->security |= (is_smime ? SMIMESIGN : PGPSIGN);
3859 msg->security &= (is_smime ? ~SMIMESIGN : ~PGPSIGN);
3861 *redraw = REDRAW_FULL;
3864 case 4: /* (b)oth */
3866 (is_smime ? (SMIMEENCRYPT | SMIMESIGN) : (PGPENCRYPT | PGPSIGN));
3869 case 5: /* (t)oggle */
3870 is_smime = !is_smime;
3873 case 6: /* (f)orget it */
3879 else if (is_smime) {
3880 msg->security &= ~APPLICATION_PGP;
3881 msg->security |= APPLICATION_SMIME;
3884 msg->security &= ~APPLICATION_SMIME;
3885 msg->security |= APPLICATION_PGP;
3888 return (msg->security);
3891 int pgp_gpgme_send_menu (HEADER * msg, int *redraw)
3893 return gpgme_send_menu (msg, redraw, 0);
3896 int smime_gpgme_send_menu (HEADER * msg, int *redraw)
3898 return gpgme_send_menu (msg, redraw, 1);
3901 static int verify_sender (HEADER * h, gpgme_protocol_t protocol)
3903 ADDRESS *sender = NULL;
3904 unsigned int ret = 1;
3907 h->env->from = mutt_expand_aliases (h->env->from);
3908 sender = h->env->from;
3910 else if (h->env->sender) {
3911 h->env->sender = mutt_expand_aliases (h->env->sender);
3912 sender = h->env->sender;
3916 if (signature_key) {
3917 gpgme_key_t key = signature_key;
3918 gpgme_user_id_t uid = NULL;
3919 int sender_length = 0;
3922 sender_length = strlen (sender->mailbox);
3923 for (uid = key->uids; uid && ret; uid = uid->next) {
3924 uid_length = strlen (uid->email);
3925 if (1 && (uid->email[0] == '<')
3926 && (uid->email[uid_length - 1] == '>')
3927 && (uid_length == sender_length + 2)
3928 && (!strncmp (uid->email + 1, sender->mailbox, sender_length)))
3933 mutt_any_key_to_continue ("Failed to verify sender");
3936 mutt_any_key_to_continue ("Failed to figure out sender");
3938 if (signature_key) {
3939 gpgme_key_release (signature_key);
3940 signature_key = NULL;
3946 int smime_gpgme_verify_sender (HEADER * h)
3948 return verify_sender (h, GPGME_PROTOCOL_CMS);