2 * Copyright notice from original mutt:
3 * crypt-gpgme.c - GPGME based crypto operations
4 * Copyright (C) 1996,1997 Michael R. Elkins <me@cs.hmc.edu>
5 * Copyright (C) 1998,1999,2000 Thomas Roessler <roessler@guug.de>
6 * Copyright (C) 2001 Thomas Roessler <roessler@guug.de>
7 * Oliver Ehli <elmy@acm.org>
8 * Copyright (C) 2002, 2003, 2004 g10 Code GmbH
10 * This file is part of mutt-ng, see http://www.muttng.org/.
11 * It's licensed under the GNU General Public License,
12 * please see the file GPL in the top level source directory.
19 #ifdef CRYPT_BACKEND_GPGME
21 #include <lib-lib/mem.h>
22 #include <lib-lib/str.h>
23 #include <lib-lib/ascii.h>
24 #include <lib-lib/macros.h>
25 #include <lib-lib/file.h>
27 #include <lib-mime/mime.h>
30 #include "mutt_crypt.h"
31 #include "mutt_menu.h"
32 #include "mutt_curses.h"
37 #include "recvattach.h"
40 #include "lib/debug.h"
55 #ifdef HAVE_LANGINFO_D_T_FMT
59 #ifdef HAVE_SYS_TIME_H
60 # include <sys/time.h>
63 #ifdef HAVE_SYS_RESOURCE_H
64 # include <sys/resource.h>
70 #define digitp(p) (*(p) >= '0' && *(p) <= '9')
71 #define hexdigitp(a) (digitp (a) \
72 || (*(a) >= 'A' && *(a) <= 'F') \
73 || (*(a) >= 'a' && *(a) <= 'f'))
74 #define xtoi_1(p) (*(p) <= '9'? (*(p)- '0'): \
75 *(p) <= 'F'? (*(p)-'A'+10):(*(p)-'a'+10))
76 #define xtoi_2(p) ((xtoi_1(p) * 16) + xtoi_1((p)+1))
78 /* Values used for comparing addresses. */
79 #define CRYPT_KV_VALID 1
80 #define CRYPT_KV_ADDR 2
81 #define CRYPT_KV_STRING 4
82 #define CRYPT_KV_STRONGID 8
83 #define CRYPT_KV_MATCH (CRYPT_KV_ADDR|CRYPT_KV_STRING)
92 struct crypt_cache *next;
100 /* We work based on user IDs, getting from a user ID to the key is
101 check and does not need any memory (gpgme uses reference counting). */
102 typedef struct crypt_keyinfo {
103 struct crypt_keyinfo *next;
105 int idx; /* and the user ID at this index */
106 const char *uid; /* and for convenience point to this user ID */
107 unsigned int flags; /* global and per uid flags (for convenience) */
110 typedef struct crypt_entry {
116 static struct crypt_cache *id_defaults = NULL;
117 static gpgme_key_t signature_key = NULL;
120 * General helper functions.
123 /* return true when S points to a didgit or letter. */
124 static int digit_or_letter (const unsigned char *s)
126 return ((*s >= '0' && *s <= '9')
127 || (*s >= 'A' && *s <= 'Z')
128 || (*s >= 'a' && *s <= 'z'));
132 /* Print the utf-8 encoded string BUF of length LEN bytes to stream
133 FP. Convert the character set. */
134 static void print_utf8 (FILE * fp, const char *buf, size_t len)
138 tstr = p_dupstr(buf, len);
139 mutt_convert_string (&tstr, "utf-8", Charset, M_ICONV_HOOK_FROM);
149 /* Return the keyID for the key K. Note that this string is valid as
150 long as K is valid */
151 static const char *crypt_keyid (crypt_key_t * k)
153 const char *s = "????????";
155 if (k->kobj && k->kobj->subkeys) {
156 s = k->kobj->subkeys->keyid;
157 if ((!option (OPTPGPLONGIDS)) && (m_strlen(s) == 16))
158 /* Return only the short keyID. */
165 /* Return the hexstring fingerprint from the key K. */
166 static const char *crypt_fpr (crypt_key_t * k)
170 if (k->kobj && k->kobj->subkeys)
171 s = k->kobj->subkeys->fpr;
176 /* Parse FLAGS and return a statically allocated(!) string with them. */
177 static char *crypt_key_abilities (int flags)
181 if (!(flags & KEYFLAG_CANENCRYPT))
183 else if (flags & KEYFLAG_PREFER_SIGNING)
188 if (!(flags & KEYFLAG_CANSIGN))
190 else if (flags & KEYFLAG_PREFER_ENCRYPTION)
200 /* Parse FLAGS and return a character describing the most important flag. */
201 static char crypt_flags (int flags)
203 if (flags & KEYFLAG_REVOKED)
205 else if (flags & KEYFLAG_EXPIRED)
207 else if (flags & KEYFLAG_DISABLED)
209 else if (flags & KEYFLAG_CRITICAL)
215 /* Return a copy of KEY. */
216 static crypt_key_t *crypt_copy_key (crypt_key_t *key)
220 k = p_new(crypt_key_t, 1);
222 gpgme_key_ref (key->kobj);
225 k->flags = key->flags;
230 /* Release all the keys at the address of KEYLIST and set the address
232 static void crypt_free_key (crypt_key_t ** keylist)
235 crypt_key_t *k = (*keylist)->next;
242 /* Return trute when key K is valid. */
243 static int crypt_key_is_valid (crypt_key_t * k)
245 if (k->flags & KEYFLAG_CANTUSE)
250 /* Return true whe validity of KEY is sufficient. */
251 static int crypt_id_is_strong (crypt_key_t * key)
253 gpgme_validity_t val = GPGME_VALIDITY_UNKNOWN;
254 gpgme_user_id_t uid = NULL;
255 unsigned int is_strong = 0;
258 if ((key->flags & KEYFLAG_ISX509))
261 for (i = 0, uid = key->kobj->uids; (i < key->idx) && uid;
262 i++, uid = uid->next);
267 case GPGME_VALIDITY_UNKNOWN:
268 case GPGME_VALIDITY_UNDEFINED:
269 case GPGME_VALIDITY_NEVER:
270 case GPGME_VALIDITY_MARGINAL:
274 case GPGME_VALIDITY_FULL:
275 case GPGME_VALIDITY_ULTIMATE:
283 /* Return true when the KEY is valid, i.e. not marked as unusable. */
284 static int crypt_id_is_valid (crypt_key_t * key)
286 return !(key->flags & KEYFLAG_CANTUSE);
289 /* Return a bit vector describing how well the addresses ADDR and
290 U_ADDR match and whether KEY is valid. */
291 static int crypt_id_matches_addr (ADDRESS * addr, ADDRESS * u_addr,
296 if (crypt_id_is_valid (key))
297 rv |= CRYPT_KV_VALID;
299 if (crypt_id_is_strong (key))
300 rv |= CRYPT_KV_STRONGID;
302 if (addr->mailbox && u_addr->mailbox
303 && m_strcasecmp(addr->mailbox, u_addr->mailbox) == 0)
306 if (addr->personal && u_addr->personal
307 && m_strcasecmp(addr->personal, u_addr->personal) == 0)
308 rv |= CRYPT_KV_STRING;
315 * GPGME convenient functions.
318 /* Create a new gpgme context and return it. With FOR_SMIME set to
319 true, the protocol of the context is set to CMS. */
320 static gpgme_ctx_t create_gpgme_context (int for_smime)
325 err = gpgme_new (&ctx);
327 mutt_error (_("error creating gpgme context: %s\n"), gpgme_strerror (err));
333 err = gpgme_set_protocol (ctx, GPGME_PROTOCOL_CMS);
335 mutt_error (_("error enabling CMS protocol: %s\n"), gpgme_strerror (err));
344 /* Create a new gpgme data object. This is a wrapper to die on
346 static gpgme_data_t create_gpgme_data (void)
351 err = gpgme_data_new (&data);
353 mutt_error (_("error creating gpgme data object: %s\n"),
354 gpgme_strerror (err));
361 /* Create a new GPGME Data object from the mail body A. With CONVERT
362 passed as true, the lines are converted to CR,LF if required.
363 Return NULL on error or the gpgme_data_t object on success. */
364 static gpgme_data_t body_to_data_object (BODY * a, int convert)
366 char tempfile[_POSIX_PATH_MAX];
371 mutt_mktemp (tempfile);
372 fptmp = safe_fopen (tempfile, "w+");
374 mutt_perror (tempfile);
378 mutt_write_mime_header (a, fptmp);
380 mutt_write_mime_body (a, fptmp);
384 unsigned char buf[1];
386 data = create_gpgme_data ();
388 while ((c = fgetc (fptmp)) != EOF) {
392 if (c == '\n' && !hadcr) {
394 gpgme_data_write (data, buf, 1);
399 /* FIXME: This is quite suboptimal */
401 gpgme_data_write (data, buf, 1);
404 gpgme_data_seek (data, 0, SEEK_SET);
408 err = gpgme_data_new_from_file (&data, tempfile, 1);
412 mutt_error (_("error allocating data object: %s\n"), gpgme_strerror (err));
419 /* Create a GPGME data object from the stream FP but limit the object
420 to LENGTH bytes starting at OFFSET bytes from the beginning of the
422 static gpgme_data_t file_to_data_object (FILE * fp, long offset, long length)
427 err = gpgme_data_new_from_filepart (&data, NULL, fp, offset, length);
429 mutt_error (_("error allocating data object: %s\n"), gpgme_strerror (err));
436 /* Write a GPGME data object to the stream FP. */
437 static int data_object_to_stream (gpgme_data_t data, FILE * fp)
443 err = ((gpgme_data_seek (data, 0, SEEK_SET) == -1)
444 ? gpgme_error_from_errno (errno) : 0);
446 mutt_error (_("error rewinding data object: %s\n"), gpgme_strerror (err));
450 while ((nread = gpgme_data_read (data, buf, sizeof (buf)))) {
451 /* fixme: we are not really converting CRLF to LF but just
452 skipping CR. Doing it correctly needs a more complex logic */
453 for (p = buf; nread; p++, nread--) {
459 mutt_perror ("[tempfile]");
464 mutt_error (_("error reading data object: %s\n"), strerror (errno));
470 /* Copy a data object to a newly created temporay file and return that
471 filename. Caller must free. With RET_FP not NULL, don't close the
472 stream but return it there. */
473 static char *data_object_to_tempfile (gpgme_data_t data, FILE ** ret_fp)
476 char tempfile[_POSIX_PATH_MAX];
480 mutt_mktemp (tempfile);
481 fp = safe_fopen (tempfile, "w+");
483 mutt_perror (tempfile);
487 err = ((gpgme_data_seek (data, 0, SEEK_SET) == -1)
488 ? gpgme_error_from_errno (errno) : 0);
492 while ((nread = gpgme_data_read (data, buf, sizeof (buf)))) {
493 if (fwrite (buf, nread, 1, fp) != 1) {
494 mutt_perror (tempfile);
506 mutt_error (_("error reading data object: %s\n"), gpgme_strerror (err));
513 return m_strdup(tempfile);
517 /* Create a GpgmeRecipientSet from the keys in the string KEYLIST.
518 The keys must be space delimited. */
519 static gpgme_key_t *create_recipient_set (const char *keylist,
520 gpgme_protocol_t protocol)
526 gpgme_key_t *rset = NULL;
527 unsigned int rset_n = 0;
528 gpgme_key_t key = NULL;
529 gpgme_ctx_t context = NULL;
531 err = gpgme_new (&context);
533 err = gpgme_set_protocol (context, protocol);
540 for (i = 0; *s && *s != ' ' && i < sizeof (buf) - 1;)
544 if (i > 1 && buf[i - 1] == '!') {
545 /* The user selected to override the valididy of that
549 err = gpgme_get_key (context, buf, &key, 0);
551 key->uids->validity = GPGME_VALIDITY_FULL;
555 err = gpgme_get_key (context, buf, &key, 0);
558 p_realloc(&rset, rset_n + 1);
559 rset[rset_n++] = key;
562 mutt_error (_("error adding recipient `%s': %s\n"),
563 buf, gpgme_strerror (err));
571 /* NULL terminate. */
572 p_realloc(&rset, rset_n + 1);
573 rset[rset_n++] = NULL;
576 gpgme_release (context);
582 /* Make sure that the correct signer is set. Returns 0 on success. */
583 static int set_signer (gpgme_ctx_t ctx, int for_smime)
585 char *signid = for_smime ? SmimeDefaultKey : PgpSignAs;
588 gpgme_key_t key, key2;
590 if (!signid || !*signid)
593 listctx = create_gpgme_context (for_smime);
594 err = gpgme_op_keylist_start (listctx, signid, 1);
596 err = gpgme_op_keylist_next (listctx, &key);
598 gpgme_release (listctx);
599 mutt_error (_("secret key `%s' not found: %s\n"),
600 signid, gpgme_strerror (err));
603 err = gpgme_op_keylist_next (listctx, &key2);
605 gpgme_key_release (key);
606 gpgme_key_release (key2);
607 gpgme_release (listctx);
608 mutt_error (_("ambiguous specification of secret key `%s'\n"), signid);
611 gpgme_op_keylist_end (listctx);
612 gpgme_release (listctx);
614 gpgme_signers_clear (ctx);
615 err = gpgme_signers_add (ctx, key);
616 gpgme_key_release (key);
618 mutt_error (_("error setting secret key `%s': %s\n"),
619 signid, gpgme_strerror (err));
626 /* Encrypt the gpgme data object PLAINTEXT to the recipients in RSET
627 and return an allocated filename to a temporary file containing the
628 enciphered text. With USE_SMIME set to true, the smime backend is
629 used. With COMBINED_SIGNED a PGP message is signed and
630 encrypted. Returns NULL in case of error */
631 static char *encrypt_gpgme_object (gpgme_data_t plaintext, gpgme_key_t * rset,
632 int use_smime, int combined_signed)
636 gpgme_data_t ciphertext;
639 ctx = create_gpgme_context (use_smime);
641 gpgme_set_armor (ctx, 1);
643 ciphertext = create_gpgme_data ();
645 if (combined_signed) {
646 if (set_signer (ctx, use_smime)) {
647 gpgme_data_release (ciphertext);
651 err = gpgme_op_encrypt_sign (ctx, rset, GPGME_ENCRYPT_ALWAYS_TRUST,
652 plaintext, ciphertext);
655 err = gpgme_op_encrypt (ctx, rset, GPGME_ENCRYPT_ALWAYS_TRUST,
656 plaintext, ciphertext);
657 mutt_need_hard_redraw ();
659 mutt_error (_("error encrypting data: %s\n"), gpgme_strerror (err));
660 gpgme_data_release (ciphertext);
667 outfile = data_object_to_tempfile (ciphertext, NULL);
668 gpgme_data_release (ciphertext);
672 /* Find the "micalg" parameter from the last Gpgme operation on
673 context CTX. It is expected that this operation was a sign
674 operation. Return the algorithm name as a C string in buffer BUF
675 which must have been allocated by the caller with size BUFLEN.
676 Returns 0 on success or -1 in case of an error. The return string
677 is truncted to BUFLEN - 1. */
678 static int get_micalg (gpgme_ctx_t ctx, char *buf, size_t buflen)
680 gpgme_sign_result_t result = NULL;
681 const char *algorithm_name = NULL;
687 result = gpgme_op_sign_result (ctx);
689 algorithm_name = gpgme_hash_algo_name (result->signatures->hash_algo);
690 if (algorithm_name) {
691 m_strcpy(buf, buflen, algorithm_name);
695 return *buf ? 0 : -1;
698 static void print_time (time_t t, STATE * s)
702 setlocale (LC_TIME, "");
703 #ifdef HAVE_LANGINFO_D_T_FMT
704 strftime (p, sizeof (p), nl_langinfo (D_T_FMT), localtime (&t));
706 strftime (p, sizeof (p), "%c", localtime (&t));
708 setlocale (LC_TIME, "C");
709 state_attach_puts (p, s);
713 * Implementation of `sign_message'.
716 /* Sign the MESSAGE in body A either using OpenPGP or S/MIME when
717 USE_SMIME is passed as true. Returns the new body or NULL on
719 static BODY *sign_message (BODY * a, int use_smime)
726 gpgme_data_t message, signature;
728 convert_to_7bit (a); /* Signed data _must_ be in 7-bit format. */
730 message = body_to_data_object (a, 1);
733 signature = create_gpgme_data ();
735 ctx = create_gpgme_context (use_smime);
737 gpgme_set_armor (ctx, 1);
739 if (set_signer (ctx, use_smime)) {
740 gpgme_data_release (signature);
745 err = gpgme_op_sign (ctx, message, signature, GPGME_SIG_MODE_DETACH);
746 mutt_need_hard_redraw ();
747 gpgme_data_release (message);
749 gpgme_data_release (signature);
751 mutt_error (_("error signing data: %s\n"), gpgme_strerror (err));
755 sigfile = data_object_to_tempfile (signature, NULL);
756 gpgme_data_release (signature);
762 t = mutt_new_body ();
763 t->type = TYPEMULTIPART;
764 t->subtype = m_strdup("signed");
765 t->encoding = ENC7BIT;
767 t->disposition = DISPINLINE;
769 mutt_generate_boundary (&t->parameter);
770 mutt_set_parameter ("protocol",
771 use_smime ? "application/pkcs7-signature"
772 : "application/pgp-signature", &t->parameter);
773 /* Get the micalg from gpgme. Old gpgme versions don't support this
774 for S/MIME so we assume sha-1 in this case. */
775 if (!get_micalg (ctx, buf, sizeof buf))
776 mutt_set_parameter ("micalg", buf, &t->parameter);
778 mutt_set_parameter ("micalg", "sha1", &t->parameter);
784 t->parts->next = mutt_new_body ();
786 t->type = TYPEAPPLICATION;
788 t->subtype = m_strdup("pkcs7-signature");
789 mutt_set_parameter ("name", "smime.p7s", &t->parameter);
790 t->encoding = ENCBASE64;
792 t->disposition = DISPATTACH;
793 t->d_filename = m_strdup("smime.p7s");
796 t->subtype = m_strdup("pgp-signature");
798 t->disposition = DISPINLINE;
799 t->encoding = ENC7BIT;
801 t->filename = sigfile;
802 t->unlink = 1; /* ok to remove this file after sending. */
808 BODY *pgp_gpgme_sign_message (BODY * a)
810 return sign_message (a, 0);
813 BODY *smime_gpgme_sign_message (BODY * a)
815 return sign_message (a, 1);
819 * Implementation of `encrypt_message'.
822 /* Encrypt the mail body A to all keys given as space separated keyids
823 or fingerprints in KEYLIST and return the encrypted body. */
824 BODY *pgp_gpgme_encrypt_message (BODY * a, char *keylist, int sign)
826 char *outfile = NULL;
828 gpgme_key_t *rset = NULL;
829 gpgme_data_t plaintext;
831 rset = create_recipient_set (keylist, GPGME_PROTOCOL_OpenPGP);
837 plaintext = body_to_data_object (a, 0);
843 outfile = encrypt_gpgme_object (plaintext, rset, 0, sign);
844 gpgme_data_release (plaintext);
849 t = mutt_new_body ();
850 t->type = TYPEMULTIPART;
851 t->subtype = m_strdup("encrypted");
852 t->encoding = ENC7BIT;
854 t->disposition = DISPINLINE;
856 mutt_generate_boundary (&t->parameter);
857 mutt_set_parameter ("protocol", "application/pgp-encrypted", &t->parameter);
859 t->parts = mutt_new_body ();
860 t->parts->type = TYPEAPPLICATION;
861 t->parts->subtype = m_strdup("pgp-encrypted");
862 t->parts->encoding = ENC7BIT;
864 t->parts->next = mutt_new_body ();
865 t->parts->next->type = TYPEAPPLICATION;
866 t->parts->next->subtype = m_strdup("octet-stream");
867 t->parts->next->encoding = ENC7BIT;
868 t->parts->next->filename = outfile;
869 t->parts->next->use_disp = 1;
870 t->parts->next->disposition = DISPINLINE;
871 t->parts->next->unlink = 1; /* delete after sending the message */
872 t->parts->next->d_filename = m_strdup("msg.asc"); /* non pgp/mime
879 * Implementation of `smime_build_smime_entity'.
882 /* Encrypt the mail body A to all keys given as space separated
883 fingerprints in KEYLIST and return the S/MIME encrypted body. */
884 BODY *smime_gpgme_build_smime_entity (BODY * a, char *keylist)
886 char *outfile = NULL;
888 gpgme_key_t *rset = NULL;
889 gpgme_data_t plaintext;
891 rset = create_recipient_set (keylist, GPGME_PROTOCOL_CMS);
895 plaintext = body_to_data_object (a, 0);
901 outfile = encrypt_gpgme_object (plaintext, rset, 1, 0);
902 gpgme_data_release (plaintext);
907 t = mutt_new_body ();
908 t->type = TYPEAPPLICATION;
909 t->subtype = m_strdup("pkcs7-mime");
910 mutt_set_parameter ("name", "smime.p7m", &t->parameter);
911 mutt_set_parameter ("smime-type", "enveloped-data", &t->parameter);
912 t->encoding = ENCBASE64; /* The output of OpenSSL SHOULD be binary */
914 t->disposition = DISPATTACH;
915 t->d_filename = m_strdup("smime.p7m");
916 t->filename = outfile;
917 t->unlink = 1; /*delete after sending the message */
926 * Implementation of `verify_one'.
929 /* Display the common attributes of the signature summary SUM.
930 Return 1 if there is is a severe warning.
932 static int show_sig_summary (unsigned long sum,
933 gpgme_ctx_t ctx, gpgme_key_t key, int idx,
938 if ((sum & GPGME_SIGSUM_KEY_REVOKED)) {
939 state_attach_puts (_("Warning: One of the keys has been revoked\n"), s);
943 if ((sum & GPGME_SIGSUM_KEY_EXPIRED)) {
944 time_t at = key->subkeys->expires ? key->subkeys->expires : 0;
947 state_attach_puts (_("Warning: The key used to create the "
948 "signature expired at: "), s);
950 state_attach_puts ("\n", s);
953 state_attach_puts (_("Warning: At least one certification key "
954 "has expired\n"), s);
957 if ((sum & GPGME_SIGSUM_SIG_EXPIRED)) {
958 gpgme_verify_result_t result;
959 gpgme_signature_t sig;
962 result = gpgme_op_verify_result (ctx);
964 for (sig = result->signatures, i = 0; sig && (i < idx);
965 sig = sig->next, i++);
967 state_attach_puts (_("Warning: The signature expired at: "), s);
968 print_time (sig ? sig->exp_timestamp : 0, s);
969 state_attach_puts ("\n", s);
972 if ((sum & GPGME_SIGSUM_KEY_MISSING))
973 state_attach_puts (_("Can't verify due to a missing "
974 "key or certificate\n"), s);
976 if ((sum & GPGME_SIGSUM_CRL_MISSING)) {
977 state_attach_puts (_("The CRL is not available\n"), s);
981 if ((sum & GPGME_SIGSUM_CRL_TOO_OLD)) {
982 state_attach_puts (_("Available CRL is too old\n"), s);
986 if ((sum & GPGME_SIGSUM_BAD_POLICY))
987 state_attach_puts (_("A policy requirement was not met\n"), s);
989 if ((sum & GPGME_SIGSUM_SYS_ERROR)) {
990 const char *t0 = NULL, *t1 = NULL;
991 gpgme_verify_result_t result;
992 gpgme_signature_t sig;
995 state_attach_puts (_("A system error occurred"), s);
997 /* Try to figure out some more detailed system error information. */
998 result = gpgme_op_verify_result (ctx);
999 for (sig = result->signatures, i = 0; sig && (i < idx);
1000 sig = sig->next, i++);
1003 t1 = sig->wrong_key_usage ? "Wrong_Key_Usage" : "";
1007 state_attach_puts (": ", s);
1009 state_attach_puts (t0, s);
1010 if (t1 && !(t0 && !m_strcmp(t0, t1))) {
1012 state_attach_puts (",", s);
1013 state_attach_puts (t1, s);
1016 state_attach_puts ("\n", s);
1023 static void show_fingerprint (gpgme_key_t key, STATE * state)
1028 const char *prefix = _("Fingerprint: ");
1032 s = key->subkeys ? key->subkeys->fpr : NULL;
1035 is_pgp = (key->protocol == GPGME_PROTOCOL_OpenPGP);
1037 buf = xmalloc(m_strlen(prefix) + m_strlen(s) * 4 + 2);
1038 strcpy (buf, prefix); /* __STRCPY_CHECKED__ */
1039 p = buf + m_strlen(buf);
1040 if (is_pgp && m_strlen(s) == 40) { /* PGP v4 style formatted. */
1041 for (i = 0; *s && s[1] && s[2] && s[3] && s[4]; s += 4, i++) {
1052 for (i = 0; *s && s[1] && s[2]; s += 2, i++) {
1055 *p++ = is_pgp ? ' ' : ':';
1056 if (is_pgp && i == 7)
1061 /* just in case print remaining odd digits */
1066 state_attach_puts (buf, state);
1070 /* Show the valididy of a key used for one signature. */
1071 static void show_one_sig_validity (gpgme_ctx_t ctx, int idx, STATE * s)
1073 gpgme_verify_result_t result = NULL;
1074 gpgme_signature_t sig = NULL;
1075 const char *txt = NULL;
1077 result = gpgme_op_verify_result (ctx);
1079 for (sig = result->signatures; sig && (idx > 0); sig = sig->next, idx--);
1081 switch (sig ? sig->validity : 0) {
1082 case GPGME_VALIDITY_UNKNOWN:
1083 txt = _("WARNING: We have NO indication whether "
1084 "the key belongs to the person named " "as shown above\n");
1086 case GPGME_VALIDITY_UNDEFINED:
1088 case GPGME_VALIDITY_NEVER:
1089 txt = _("WARNING: The key does NOT BELONG to "
1090 "the person named as shown above\n");
1092 case GPGME_VALIDITY_MARGINAL:
1093 txt = _("WARNING: It is NOT certain that the key "
1094 "belongs to the person named as shown above\n");
1096 case GPGME_VALIDITY_FULL:
1097 case GPGME_VALIDITY_ULTIMATE:
1102 state_attach_puts (txt, s);
1105 /* Show information about one signature. This fucntion is called with
1106 the context CTX of a sucessful verification operation and the
1107 enumerator IDX which should start at 0 and incremete for each
1110 Return values are: 0 for normal procession, 1 for a bad signature,
1111 2 for a signature with a warning or -1 for no more signature. */
1112 static int show_one_sig_status (gpgme_ctx_t ctx, int idx, STATE * s)
1115 const char *fpr, *uid;
1116 gpgme_key_t key = NULL;
1117 int i, anybad = 0, anywarn = 0;
1119 gpgme_user_id_t uids = NULL;
1120 gpgme_verify_result_t result;
1121 gpgme_signature_t sig;
1122 gpgme_error_t err = GPG_ERR_NO_ERROR;
1124 result = gpgme_op_verify_result (ctx);
1126 /* FIXME: this code should use a static variable and remember
1127 the current position in the list of signatures, IMHO.
1130 for (i = 0, sig = result->signatures; sig && (i < idx);
1131 i++, sig = sig->next);
1133 return -1; /* Signature not found. */
1135 if (signature_key) {
1136 gpgme_key_release (signature_key);
1137 signature_key = NULL;
1140 created = sig->timestamp;
1144 if (gpg_err_code (sig->status) != GPG_ERR_NO_ERROR)
1147 err = gpgme_get_key (ctx, fpr, &key, 0); /* secret key? */
1149 uid = (key->uids && key->uids->uid) ? key->uids->uid : "[?]";
1151 signature_key = key;
1154 key = NULL; /* Old gpgme versions did not set KEY to NULL on
1155 error. Do it here to avoid a double free. */
1159 if (!s || !s->fpout || !(s->flags & M_DISPLAY)); /* No state information so no way to print anything. */
1161 state_attach_puts (_("Error getting key information: "), s);
1162 state_attach_puts (gpg_strerror (err), s);
1163 state_attach_puts ("\n", s);
1166 else if ((sum & GPGME_SIGSUM_GREEN)) {
1167 state_attach_puts (_("Good signature from: "), s);
1168 state_attach_puts (uid, s);
1169 state_attach_puts ("\n", s);
1170 for (i = 1, uids = key->uids; uids; i++, uids = uids->next) {
1172 /* Skip primary UID. */
1176 state_attach_puts (_(" aka: "), s);
1177 state_attach_puts (uids->uid, s);
1178 state_attach_puts ("\n", s);
1180 state_attach_puts (_(" created: "), s);
1181 print_time (created, s);
1182 state_attach_puts ("\n", s);
1183 if (show_sig_summary (sum, ctx, key, idx, s))
1185 show_one_sig_validity (ctx, idx, s);
1187 else if ((sum & GPGME_SIGSUM_RED)) {
1188 state_attach_puts (_("*BAD* signature claimed to be from: "), s);
1189 state_attach_puts (uid, s);
1190 state_attach_puts ("\n", s);
1191 show_sig_summary (sum, ctx, key, idx, s);
1193 else if (!anybad && key && (key->protocol == GPGME_PROTOCOL_OpenPGP)) { /* We can't decide (yellow) but this is a PGP key with a good
1194 signature, so we display what a PGP user expects: The name,
1195 fingerprint and the key validity (which is neither fully or
1197 state_attach_puts (_("Good signature from: "), s);
1198 state_attach_puts (uid, s);
1199 state_attach_puts ("\n", s);
1200 state_attach_puts (_(" created: "), s);
1201 print_time (created, s);
1202 state_attach_puts ("\n", s);
1203 show_one_sig_validity (ctx, idx, s);
1204 show_fingerprint (key, s);
1205 if (show_sig_summary (sum, ctx, key, idx, s))
1208 else { /* can't decide (yellow) */
1210 state_attach_puts (_("Error checking signature"), s);
1211 state_attach_puts ("\n", s);
1212 show_sig_summary (sum, ctx, key, idx, s);
1215 if (key != signature_key)
1216 gpgme_key_release (key);
1219 return anybad ? 1 : anywarn ? 2 : 0;
1222 /* Do the actual verification step. With IS_SMIME set to true we
1223 assume S/MIME (surprise!) */
1224 static int verify_one (BODY * sigbdy, STATE * s,
1225 const char *tempfile, int is_smime)
1231 gpgme_data_t signature, message;
1233 signature = file_to_data_object (s->fpin, sigbdy->offset, sigbdy->length);
1237 /* We need to tell gpgme about the encoding because the backend can't
1238 auto-detect plain base-64 encoding which is used by S/MIME. */
1240 gpgme_data_set_encoding (signature, GPGME_DATA_ENCODING_BASE64);
1242 err = gpgme_data_new_from_file (&message, tempfile, 1);
1244 gpgme_data_release (signature);
1245 mutt_error (_("error allocating data object: %s\n"), gpgme_strerror (err));
1248 ctx = create_gpgme_context (is_smime);
1250 /* Note: We don't need a current time output because GPGME avoids
1251 such an attack by separating the meta information from the
1253 state_attach_puts (_("[-- Begin signature information --]\n"), s);
1255 err = gpgme_op_verify (ctx, signature, message, NULL);
1256 mutt_need_hard_redraw ();
1260 snprintf (buf, sizeof (buf) - 1,
1261 _("Error: verification failed: %s\n"), gpgme_strerror (err));
1262 state_attach_puts (buf, s);
1264 else { /* Verification succeeded, see what the result is. */
1268 if (signature_key) {
1269 gpgme_key_release (signature_key);
1270 signature_key = NULL;
1273 for (idx = 0; (res = show_one_sig_status (ctx, idx, s)) != -1; idx++) {
1284 gpgme_verify_result_t result;
1285 gpgme_sig_notation_t notation;
1286 gpgme_signature_t signature;
1288 result = gpgme_op_verify_result (ctx);
1290 for (signature = result->signatures; signature;
1291 signature = signature->next) {
1292 if (signature->notations) {
1293 state_attach_puts ("*** Begin Notation (signature by: ", s);
1294 state_attach_puts (signature->fpr, s);
1295 state_attach_puts (") ***\n", s);
1296 for (notation = signature->notations; notation;
1297 notation = notation->next) {
1298 if (notation->name) {
1299 state_attach_puts (notation->name, s);
1300 state_attach_puts ("=", s);
1302 if (notation->value) {
1303 state_attach_puts (notation->value, s);
1304 if (!(*notation->value
1305 && (notation->value[m_strlen(notation->value) - 1] ==
1307 state_attach_puts ("\n", s);
1310 state_attach_puts ("*** End Notation ***\n", s);
1316 gpgme_release (ctx);
1318 state_attach_puts (_("[-- End signature information --]\n\n"), s);
1319 debug_print (1, ("returning %d.\n", badsig));
1321 return badsig ? 1 : anywarn ? 2 : 0;
1324 int pgp_gpgme_verify_one (BODY * sigbdy, STATE * s, const char *tempfile)
1326 return verify_one (sigbdy, s, tempfile, 0);
1329 int smime_gpgme_verify_one (BODY * sigbdy, STATE * s, const char *tempfile)
1331 return verify_one (sigbdy, s, tempfile, 1);
1335 * Implementation of `decrypt_part'.
1338 /* Decrypt a PGP or SMIME message (depending on the boolean flag
1339 IS_SMIME) with body A described further by state S. Write
1340 plaintext out to file FPOUT and return a new body. For PGP returns
1341 a flag in R_IS_SIGNED to indicate whether this is a combined
1342 encrypted and signed message, for S/MIME it returns true when it is
1343 not a encrypted but a signed message. */
1344 static BODY *decrypt_part (BODY * a, STATE * s, FILE * fpout, int is_smime,
1351 gpgme_data_t ciphertext, plaintext;
1352 int maybe_signed = 0;
1359 ctx = create_gpgme_context (is_smime);
1362 /* Make a data object from the body, create context etc. */
1363 ciphertext = file_to_data_object (s->fpin, a->offset, a->length);
1366 plaintext = create_gpgme_data ();
1368 /* Do the decryption or the verification in case of the S/MIME hack. */
1369 if ((!is_smime) || maybe_signed) {
1371 err = gpgme_op_decrypt_verify (ctx, ciphertext, plaintext);
1372 else if (maybe_signed)
1373 err = gpgme_op_verify (ctx, ciphertext, NULL, plaintext);
1376 /* Check wether signatures have been verified. */
1377 gpgme_verify_result_t verify_result = gpgme_op_verify_result (ctx);
1379 if (verify_result->signatures)
1384 err = gpgme_op_decrypt (ctx, ciphertext, plaintext);
1385 gpgme_data_release (ciphertext);
1387 if (is_smime && !maybe_signed && gpg_err_code (err) == GPG_ERR_NO_DATA) {
1388 /* Check whether this might be a signed message despite what
1389 the mime header told us. Retry then. gpgsm returns the
1390 error information "unsupported Algorithm '?'" but gpgme
1391 will not store this unknown algorithm, thus we test that
1392 it has not been set. */
1393 gpgme_decrypt_result_t result;
1395 result = gpgme_op_decrypt_result (ctx);
1396 if (!result->unsupported_algorithm) {
1398 gpgme_data_release (plaintext);
1402 mutt_need_hard_redraw ();
1403 if ((s->flags & M_DISPLAY)) {
1406 snprintf (buf, sizeof (buf) - 1,
1407 _("[-- Error: decryption failed: %s --]\n\n"),
1408 gpgme_strerror (err));
1409 state_attach_puts (buf, s);
1411 gpgme_data_release (plaintext);
1412 gpgme_release (ctx);
1415 mutt_need_hard_redraw ();
1417 /* Read the output from GPGME, and make sure to change CRLF to LF,
1418 otherwise read_mime_header has a hard time parsing the message. */
1419 if (data_object_to_stream (plaintext, fpout)) {
1420 gpgme_data_release (plaintext);
1421 gpgme_release (ctx);
1424 gpgme_data_release (plaintext);
1426 a->is_signed_data = 0;
1432 a->is_signed_data = 1;
1434 *r_is_signed = -1; /* A signature exists. */
1436 if ((s->flags & M_DISPLAY))
1437 state_attach_puts (_("[-- Begin signature " "information --]\n"), s);
1438 for (idx = 0; (res = show_one_sig_status (ctx, idx, s)) != -1; idx++) {
1444 if (!anybad && idx && r_is_signed && *r_is_signed)
1445 *r_is_signed = anywarn ? 2 : 1; /* Good signature. */
1447 if ((s->flags & M_DISPLAY))
1448 state_attach_puts (_("[-- End signature " "information --]\n\n"), s);
1450 gpgme_release (ctx);
1455 tattach = mutt_read_mime_header (fpout, 0);
1458 * Need to set the length of this body part.
1460 fstat (fileno (fpout), &info);
1461 tattach->length = info.st_size - tattach->offset;
1463 tattach->warnsig = anywarn;
1465 /* See if we need to recurse on this MIME part. */
1466 mutt_parse_part (fpout, tattach);
1472 /* Decrypt a PGP/MIME message in FPIN and B and return a new body and
1473 the stream in CUR and FPOUT. Returns 0 on success. */
1474 int pgp_gpgme_decrypt_mime (FILE * fpin, FILE ** fpout, BODY * b, BODY ** cur)
1476 char tempfile[_POSIX_PATH_MAX];
1478 BODY *first_part = b;
1481 first_part->goodsig = 0;
1482 first_part->warnsig = 0;
1484 if (!mutt_is_multipart_encrypted (b))
1487 if (!b->parts || !b->parts->next)
1494 mutt_mktemp (tempfile);
1495 if (!(*fpout = safe_fopen (tempfile, "w+"))) {
1496 mutt_perror (tempfile);
1501 *cur = decrypt_part (b, &s, *fpout, 0, &is_signed);
1504 first_part->goodsig = 1;
1506 return *cur ? 0 : -1;
1510 /* Decrypt a S/MIME message in FPIN and B and return a new body and
1511 the stream in CUR and FPOUT. Returns 0 on success. */
1512 int smime_gpgme_decrypt_mime (FILE * fpin, FILE ** fpout, BODY * b,
1515 char tempfile[_POSIX_PATH_MAX];
1519 long saved_b_offset;
1520 size_t saved_b_length;
1523 if (!mutt_is_application_smime (b))
1529 /* Decode the body - we need to pass binary CMS to the
1530 backend. The backend allows for Base64 encoded data but it does
1531 not allow for QP which I have seen in some messages. So better
1533 saved_b_type = b->type;
1534 saved_b_offset = b->offset;
1535 saved_b_length = b->length;
1538 fseeko (s.fpin, b->offset, 0);
1539 mutt_mktemp (tempfile);
1540 if (!(tmpfp = safe_fopen (tempfile, "w+"))) {
1541 mutt_perror (tempfile);
1544 mutt_unlink (tempfile);
1547 mutt_decode_attachment (b, &s);
1549 b->length = ftello (s.fpout);
1556 mutt_mktemp (tempfile);
1557 if (!(*fpout = safe_fopen (tempfile, "w+"))) {
1558 mutt_perror (tempfile);
1561 mutt_unlink (tempfile);
1563 *cur = decrypt_part (b, &s, *fpout, 1, &is_signed);
1565 (*cur)->goodsig = is_signed > 0;
1566 b->type = saved_b_type;
1567 b->length = saved_b_length;
1568 b->offset = saved_b_offset;
1571 if (*cur && !is_signed && !(*cur)->parts
1572 && mutt_is_application_smime (*cur)) {
1573 /* Assume that this is a opaque signed s/mime message. This is
1574 an ugly way of doing it but we have anyway a problem with
1575 arbitrary encoded S/MIME messages: Only the outer part may be
1576 encrypted. The entire mime parsing should be revamped,
1577 probably by keeping the temportary files so that we don't
1578 need to decrypt them all the time. Inner parts of an
1579 encrypted part can then pint into this file and tehre won't
1580 never be a need to decrypt again. This needs a partial
1581 rewrite of the MIME engine. */
1585 saved_b_type = bb->type;
1586 saved_b_offset = bb->offset;
1587 saved_b_length = bb->length;
1590 fseeko (s.fpin, bb->offset, 0);
1591 mutt_mktemp (tempfile);
1592 if (!(tmpfp = safe_fopen (tempfile, "w+"))) {
1593 mutt_perror (tempfile);
1596 mutt_unlink (tempfile);
1599 mutt_decode_attachment (bb, &s);
1601 bb->length = ftello (s.fpout);
1609 mutt_mktemp (tempfile);
1610 if (!(*fpout = safe_fopen (tempfile, "w+"))) {
1611 mutt_perror (tempfile);
1614 mutt_unlink (tempfile);
1616 tmp_b = decrypt_part (bb, &s, *fpout, 1, &is_signed);
1618 tmp_b->goodsig = is_signed > 0;
1619 bb->type = saved_b_type;
1620 bb->length = saved_b_length;
1621 bb->offset = saved_b_offset;
1624 mutt_free_body (cur);
1627 return *cur ? 0 : -1;
1632 * Implementation of `pgp_check_traditional'.
1635 static int pgp_check_traditional_one_body (FILE * fp, BODY * b,
1638 char tempfile[_POSIX_PATH_MAX];
1639 char buf[HUGE_STRING];
1645 if (b->type != TYPETEXT)
1648 if (tagged_only && !b->tagged)
1651 mutt_mktemp (tempfile);
1652 if (mutt_decode_save_attachment (fp, b, tempfile, 0, 0) != 0) {
1657 if ((tfp = fopen (tempfile, "r")) == NULL) {
1662 while (fgets (buf, sizeof (buf), tfp)) {
1663 if (!m_strncmp("-----BEGIN PGP ", buf, 15)) {
1664 if (!m_strcmp("MESSAGE-----\n", buf + 15))
1666 else if (!m_strcmp("SIGNED MESSAGE-----\n", buf + 15))
1676 /* fix the content type */
1678 mutt_set_parameter ("format", "fixed", &b->parameter);
1679 mutt_set_parameter ("x-action", enc ? "pgp-encrypted" : "pgp-signed",
1685 int pgp_gpgme_check_traditional (FILE * fp, BODY * b, int tagged_only)
1690 for (; b; b = b->next) {
1691 if (is_multipart (b))
1692 rv = (pgp_gpgme_check_traditional (fp, b->parts, tagged_only) || rv);
1693 else if (b->type == TYPETEXT) {
1694 if ((r = mutt_is_application_pgp (b)))
1697 rv = (pgp_check_traditional_one_body (fp, b, tagged_only) || rv);
1705 * Implementation of `application_handler'.
1709 Copy a clearsigned message, and strip the signature and PGP's
1712 XXX - charset handling: We assume that it is safe to do
1713 character set decoding first, dash decoding second here, while
1714 we do it the other way around in the main handler.
1716 (Note that we aren't worse than Outlook & Cie in this, and also
1717 note that we can successfully handle anything produced by any
1718 existing versions of mutt.) */
1720 static void copy_clearsigned (gpgme_data_t data, STATE * s, char *charset)
1722 char buf[HUGE_STRING];
1723 short complete, armor_header;
1728 fname = data_object_to_tempfile (data, &fp);
1734 fc = fgetconv_open (fp, charset, Charset, M_ICONV_HOOK_FROM);
1736 for (complete = 1, armor_header = 1;
1737 fgetconvs (buf, sizeof (buf), fc) != NULL;
1738 complete = strchr (buf, '\n') != NULL) {
1741 state_puts (buf, s);
1745 if (!m_strcmp(buf, "-----BEGIN PGP SIGNATURE-----\n"))
1755 state_puts (s->prefix, s);
1757 if (buf[0] == '-' && buf[1] == ' ')
1758 state_puts (buf + 2, s);
1760 state_puts (buf, s);
1763 fgetconv_close (&fc);
1768 /* Support for classic_application/pgp */
1769 int pgp_gpgme_application_handler (BODY * m, STATE * s)
1771 int needpass = -1, pgp_keyblock = 0;
1775 off_t last_pos, offset;
1776 char buf[HUGE_STRING];
1777 FILE *pgpout = NULL;
1779 gpgme_error_t err = 0;
1780 gpgme_data_t armored_data = NULL;
1782 short maybe_goodsig = 1;
1783 short have_any_sigs = 0;
1785 char body_charset[STRING]; /* Only used for clearsigned messages. */
1787 debug_print (2, ("Entering pgp_application_pgp handler\n"));
1789 /* For clearsigned messages we won't be able to get a character set
1790 but we know that this may only be text thus we assume Latin-1
1792 if (!mutt_get_body_charset (body_charset, sizeof (body_charset), m))
1793 m_strcpy(body_charset, sizeof(body_charset), "iso-8859-1");
1795 fseeko (s->fpin, m->offset, 0);
1796 last_pos = m->offset;
1798 for (bytes = m->length; bytes > 0;) {
1799 if (fgets (buf, sizeof (buf), s->fpin) == NULL)
1802 offset = ftello (s->fpin);
1803 bytes -= (offset - last_pos); /* don't rely on m_strlen(buf) */
1806 if (!m_strncmp("-----BEGIN PGP ", buf, 15)) {
1808 start_pos = last_pos;
1810 if (!m_strcmp("MESSAGE-----\n", buf + 15))
1812 else if (!m_strcmp("SIGNED MESSAGE-----\n", buf + 15)) {
1816 else if (!option (OPTDONTHANDLEPGPKEYS) &&
1817 !m_strcmp("PUBLIC KEY BLOCK-----\n", buf + 15)) {
1822 /* XXX - we may wish to recode here */
1824 state_puts (s->prefix, s);
1825 state_puts (buf, s);
1829 have_any_sigs = (have_any_sigs || (clearsign && (s->flags & M_VERIFY)));
1831 /* Copy PGP material to an data container */
1832 armored_data = create_gpgme_data ();
1833 gpgme_data_write (armored_data, buf, m_strlen(buf));
1834 while (bytes > 0 && fgets (buf, sizeof (buf) - 1, s->fpin) != NULL) {
1835 offset = ftello (s->fpin);
1836 bytes -= (offset - last_pos); /* don't rely on m_strlen(buf) */
1839 gpgme_data_write (armored_data, buf, m_strlen(buf));
1841 if ((needpass && !m_strcmp("-----END PGP MESSAGE-----\n", buf))
1843 && (!m_strcmp("-----END PGP SIGNATURE-----\n", buf)
1844 || !m_strcmp("-----END PGP PUBLIC KEY BLOCK-----\n",
1849 /* Invoke PGP if needed */
1850 if (!clearsign || (s->flags & M_VERIFY)) {
1851 unsigned int sig_stat = 0;
1852 gpgme_data_t plaintext;
1855 plaintext = create_gpgme_data ();
1856 ctx = create_gpgme_context (0);
1859 err = gpgme_op_verify (ctx, armored_data, NULL, plaintext);
1861 err = gpgme_op_decrypt_verify (ctx, armored_data, plaintext);
1862 if (gpg_err_code (err) == GPG_ERR_NO_DATA) {
1863 /* Decrypt verify can't handle signed only messages. */
1864 err = (gpgme_data_seek (armored_data, 0, SEEK_SET) == -1)
1865 ? gpgme_error_from_errno (errno) : 0;
1866 /* Must release plaintext so that we supply an
1867 uninitialized object. */
1868 gpgme_data_release (plaintext);
1869 plaintext = create_gpgme_data ();
1870 err = gpgme_op_verify (ctx, armored_data, NULL, plaintext);
1877 snprintf (errbuf, sizeof (errbuf) - 1,
1878 _("Error: decryption/verification failed: %s\n"),
1879 gpgme_strerror (err));
1880 state_attach_puts (errbuf, s);
1882 else { /* Decryption/Verification succeeded */
1886 /* Check wether signatures have been verified. */
1887 gpgme_verify_result_t verify_result;
1889 verify_result = gpgme_op_verify_result (ctx);
1890 if (verify_result->signatures)
1896 if ((s->flags & M_DISPLAY) && sig_stat) {
1901 state_attach_puts (_("[-- Begin signature "
1902 "information --]\n"), s);
1905 (res = show_one_sig_status (ctx, idx, s)) != -1; idx++) {
1914 state_attach_puts (_("[-- End signature "
1915 "information --]\n\n"), s);
1918 tmpfname = data_object_to_tempfile (plaintext, &pgpout);
1921 state_attach_puts (_("Error: copy data failed\n"), s);
1925 p_delete(&tmpfname);
1928 gpgme_release (ctx);
1932 * Now, copy cleartext to the screen. NOTE - we expect that PGP
1933 * outputs utf-8 cleartext. This may not always be true, but it
1934 * seems to be a reasonable guess.
1937 if (s->flags & M_DISPLAY) {
1939 state_attach_puts (_("[-- BEGIN PGP MESSAGE --]\n\n"), s);
1940 else if (pgp_keyblock)
1941 state_attach_puts (_("[-- BEGIN PGP PUBLIC KEY BLOCK --]\n"), s);
1943 state_attach_puts (_("[-- BEGIN PGP SIGNED MESSAGE --]\n\n"), s);
1947 copy_clearsigned (armored_data, s, body_charset);
1954 fc = fgetconv_open (pgpout, "utf-8", Charset, 0);
1955 while ((c = fgetconv (fc)) != EOF) {
1957 if (c == '\n' && s->prefix)
1958 state_puts (s->prefix, s);
1960 fgetconv_close (&fc);
1963 if (s->flags & M_DISPLAY) {
1964 state_putc ('\n', s);
1966 state_attach_puts (_("[-- END PGP MESSAGE --]\n"), s);
1967 else if (pgp_keyblock)
1968 state_attach_puts (_("[-- END PGP PUBLIC KEY BLOCK --]\n"), s);
1970 state_attach_puts (_("[-- END PGP SIGNED MESSAGE --]\n"), s);
1974 safe_fclose (&pgpout);
1978 /* XXX - we may wish to recode here */
1980 state_puts (s->prefix, s);
1981 state_puts (buf, s);
1985 m->goodsig = (maybe_goodsig && have_any_sigs);
1987 if (needpass == -1) {
1988 state_attach_puts (_("[-- Error: could not find beginning"
1989 " of PGP message! --]\n\n"), s);
1992 debug_print (2, ("Leaving pgp_application_pgp handler\n"));
1997 * Implementation of `encrypted_handler'.
2000 /* MIME handler for pgp/mime encrypted messages. */
2001 int pgp_gpgme_encrypted_handler (BODY * a, STATE * s)
2003 char tempfile[_POSIX_PATH_MAX];
2006 BODY *orig_body = a;
2010 debug_print (2, ("Entering pgp_encrypted handler\n"));
2012 if (!a || a->type != TYPEAPPLICATION || !a->subtype
2013 || ascii_strcasecmp ("pgp-encrypted", a->subtype)
2014 || !a->next || a->next->type != TYPEAPPLICATION || !a->next->subtype
2015 || ascii_strcasecmp ("octet-stream", a->next->subtype)) {
2016 if (s->flags & M_DISPLAY)
2017 state_attach_puts (_("[-- Error: malformed PGP/MIME message! --]\n\n"),
2022 /* Move forward to the application/pgp-encrypted body. */
2025 mutt_mktemp (tempfile);
2026 if (!(fpout = safe_fopen (tempfile, "w+"))) {
2027 if (s->flags & M_DISPLAY)
2028 state_attach_puts (_("[-- Error: could not create temporary file! "
2033 tattach = decrypt_part (a, s, fpout, 0, &is_signed);
2035 tattach->goodsig = is_signed > 0;
2037 if (s->flags & M_DISPLAY)
2038 state_attach_puts (is_signed ?
2040 ("[-- The following data is PGP/MIME signed and encrypted --]\n\n") :
2041 _("[-- The following data is PGP/MIME encrypted --]\n\n"), s);
2044 FILE *savefp = s->fpin;
2047 rc = mutt_body_handler (tattach, s);
2052 * if a multipart/signed is the _only_ sub-part of a
2053 * multipart/encrypted, cache signature verification
2056 if (mutt_is_multipart_signed (tattach) && !tattach->next)
2057 orig_body->goodsig |= tattach->goodsig;
2059 if (s->flags & M_DISPLAY) {
2060 state_puts ("\n", s);
2061 state_attach_puts (is_signed ?
2063 ("[-- End of PGP/MIME signed and encrypted data --]\n")
2064 : _("[-- End of PGP/MIME encrypted data --]\n"), s);
2067 mutt_free_body (&tattach);
2071 mutt_unlink (tempfile);
2072 debug_print (2, ("Leaving pgp_encrypted handler\n"));
2076 /* Support for application/smime */
2077 int smime_gpgme_application_handler (BODY * a, STATE * s)
2079 char tempfile[_POSIX_PATH_MAX];
2085 debug_print (2, ("Entering smime_encrypted handler\n"));
2088 mutt_mktemp (tempfile);
2089 if (!(fpout = safe_fopen (tempfile, "w+"))) {
2090 if (s->flags & M_DISPLAY)
2091 state_attach_puts (_("[-- Error: could not create temporary file! "
2096 tattach = decrypt_part (a, s, fpout, 1, &is_signed);
2098 tattach->goodsig = is_signed > 0;
2100 if (s->flags & M_DISPLAY)
2101 state_attach_puts (is_signed ?
2102 _("[-- The following data is S/MIME signed --]\n\n") :
2103 _("[-- The following data is S/MIME encrypted --]\n\n"), s);
2106 FILE *savefp = s->fpin;
2109 rc = mutt_body_handler (tattach, s);
2114 * if a multipart/signed is the _only_ sub-part of a
2115 * multipart/encrypted, cache signature verification
2118 if (mutt_is_multipart_signed (tattach) && !tattach->next) {
2119 if (!(a->goodsig = tattach->goodsig))
2120 a->warnsig = tattach->warnsig;
2122 else if (tattach->goodsig) {
2124 a->warnsig = tattach->warnsig;
2127 if (s->flags & M_DISPLAY) {
2128 state_puts ("\n", s);
2129 state_attach_puts (is_signed ?
2130 _("[-- End of S/MIME signed data --]\n") :
2131 _("[-- End of S/MIME encrypted data --]\n"), s);
2134 mutt_free_body (&tattach);
2138 mutt_unlink (tempfile);
2139 debug_print (2, ("Leaving smime_encrypted handler\n"));
2145 * Format an entry on the CRYPT key selection menu.
2148 * %k key id %K key id of the principal key
2150 * %a algorithm %A algorithm of the princ. key
2151 * %l length %L length of the princ. key
2152 * %f flags %F flags of the princ. key
2153 * %c capabilities %C capabilities of the princ. key
2154 * %t trust/validity of the key-uid association
2156 * %[...] date of key using strftime(3)
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 = m_strcasecmp((*s)->uid, (*t)->uid)))
2377 return m_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 = m_strcasecmp(crypt_keyid (*s), crypt_keyid (*t))))
2397 return m_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 m_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 = m_strcasecmp((*s)->uid, (*t)->uid)))
2470 return (m_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 (!m_strcmp(dn->key, key)) {
2489 print_utf8 (fp, dn->value, m_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 (!m_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 = p_dupstr(string, n );
2545 p = (unsigned char *) array->key;
2548 if (*string == '#') { /* hexstring */
2550 for (s = string; hexdigitp (s); s++)
2554 return NULL; /* empty or odd number of digits */
2557 array->value = (char *) p;
2558 for (s1 = string; n; s1 += 2, n--)
2562 else { /* regular v3 quoted string */
2563 for (n = 0, s = string; *s; s++) {
2564 if (*s == '\\') { /* pair */
2566 if (*s == ',' || *s == '=' || *s == '+'
2567 || *s == '<' || *s == '>' || *s == '#' || *s == ';'
2568 || *s == '\\' || *s == '\"' || *s == ' ')
2570 else if (hexdigitp (s) && hexdigitp (s + 1)) {
2575 return NULL; /* invalid escape sequence */
2577 else if (*s == '\"')
2578 return NULL; /* invalid encoding */
2579 else if (*s == ',' || *s == '=' || *s == '+'
2580 || *s == '<' || *s == '>' || *s == '#' || *s == ';')
2587 array->value = (char *) p;
2588 for (s = string; n; s++, n--) {
2591 if (hexdigitp (s)) {
2607 /* Parse a DN and return an array-ized one. This is not a validating
2608 parser and it does not support any old-stylish syntax; gpgme is
2609 expected to return only rfc2253 compatible strings. */
2610 static struct dn_array_s *parse_dn (const unsigned char *string)
2612 struct dn_array_s *array;
2613 size_t arrayidx, arraysize;
2616 arraysize = 7; /* C,ST,L,O,OU,CN,email */
2617 array = p_new(struct dn_array_s, arraysize + 1);
2620 while (*string == ' ')
2624 if (arrayidx >= arraysize) { /* mutt lacks a real safe_realoc - so we need to copy */
2625 struct dn_array_s *a2;
2628 a2 = p_new(struct dn_array_s, arraysize + 1);
2629 for (i = 0; i < arrayidx; i++) {
2630 a2[i].key = array[i].key;
2631 a2[i].value = array[i].value;
2636 array[arrayidx].key = NULL;
2637 array[arrayidx].value = NULL;
2638 string = parse_dn_part (array + arrayidx, string);
2642 while (*string == ' ')
2644 if (*string && *string != ',' && *string != ';' && *string != '+')
2645 goto failure; /* invalid delimiter */
2649 array[arrayidx].key = NULL;
2650 array[arrayidx].value = NULL;
2654 for (i = 0; i < arrayidx; i++) {
2655 p_delete(&array[i].key);
2656 p_delete(&array[i].value);
2663 /* Print a nice representation of the USERID and make sure it is
2664 displayed in a proper way, which does mean to reorder some parts
2665 for S/MIME's DNs. USERID is a string as returned by the gpgme key
2666 functions. It is utf-8 encoded. */
2667 static void parse_and_print_user_id (FILE * fp, const char *userid)
2672 if (*userid == '<') {
2673 s = strchr (userid + 1, '>');
2675 print_utf8 (fp, userid + 1, s - userid - 1);
2677 else if (*userid == '(')
2678 fputs (_("[Can't display this user ID (unknown encoding)]"), fp);
2679 else if (!digit_or_letter ((const unsigned char *) userid))
2680 fputs (_("[Can't display this user ID (invalid encoding)]"), fp);
2682 struct dn_array_s *dn = parse_dn ((const unsigned char *) userid);
2685 fputs (_("[Can't display this user ID (invalid DN)]"), fp);
2687 print_dn_parts (fp, dn);
2688 for (i = 0; dn[i].key; i++) {
2689 p_delete(&dn[i].key);
2690 p_delete(&dn[i].value);
2698 KEY_CAP_CAN_ENCRYPT,
2703 static unsigned int key_check_cap (gpgme_key_t key, key_cap_t cap)
2705 gpgme_subkey_t subkey = NULL;
2706 unsigned int ret = 0;
2709 case KEY_CAP_CAN_ENCRYPT:
2710 if (!(ret = key->can_encrypt))
2711 for (subkey = key->subkeys; subkey; subkey = subkey->next)
2712 if ((ret = subkey->can_encrypt))
2715 case KEY_CAP_CAN_SIGN:
2716 if (!(ret = key->can_sign))
2717 for (subkey = key->subkeys; subkey; subkey = subkey->next)
2718 if ((ret = subkey->can_sign))
2721 case KEY_CAP_CAN_CERTIFY:
2722 if (!(ret = key->can_certify))
2723 for (subkey = key->subkeys; subkey; subkey = subkey->next)
2724 if ((ret = subkey->can_certify))
2733 /* Print verbose information about a key or certificate to FP. */
2734 static void print_key_info (gpgme_key_t key, FILE * fp)
2737 const char *s = NULL, *s2 = NULL;
2740 char shortbuf[SHORT_STRING];
2741 unsigned long aval = 0;
2745 gpgme_user_id_t uid = NULL;
2748 setlocale (LC_TIME, Locale);
2750 is_pgp = key->protocol == GPGME_PROTOCOL_OpenPGP;
2752 for (idx = 0, uid = key->uids; uid; idx++, uid = uid->next) {
2757 fputs (idx ? _(" aka ......: ") :_("Name ......: "), fp);
2760 fputs (_("[Invalid]"), fp);
2764 print_utf8 (fp, s, m_strlen(s));
2766 parse_and_print_user_id (fp, s);
2770 if (key->subkeys && (key->subkeys->timestamp > 0)) {
2771 tt = key->subkeys->timestamp;
2773 tm = localtime (&tt);
2774 #ifdef HAVE_LANGINFO_D_T_FMT
2775 strftime (shortbuf, sizeof shortbuf, nl_langinfo (D_T_FMT), tm);
2777 strftime (shortbuf, sizeof shortbuf, "%c", tm);
2779 fprintf (fp, _("Valid From : %s\n"), shortbuf);
2782 if (key->subkeys && (key->subkeys->expires > 0)) {
2783 tt = key->subkeys->expires;
2785 tm = localtime (&tt);
2786 #ifdef HAVE_LANGINFO_D_T_FMT
2787 strftime (shortbuf, sizeof shortbuf, nl_langinfo (D_T_FMT), tm);
2789 strftime (shortbuf, sizeof shortbuf, "%c", tm);
2791 fprintf (fp, _("Valid To ..: %s\n"), shortbuf);
2795 s = gpgme_pubkey_algo_name (key->subkeys->pubkey_algo);
2799 s2 = is_pgp ? "PGP" : "X.509";
2802 aval = key->subkeys->length;
2804 fprintf (fp, _("Key Type ..: %s, %lu bit %s\n"), s2, aval, s);
2806 fprintf (fp, _("Key Usage .: "));
2809 if (key_check_cap (key, KEY_CAP_CAN_ENCRYPT)) {
2810 fprintf (fp, "%s%s", delim, _("encryption"));
2813 if (key_check_cap (key, KEY_CAP_CAN_SIGN)) {
2814 fprintf (fp, "%s%s", delim, _("signing"));
2817 if (key_check_cap (key, KEY_CAP_CAN_CERTIFY)) {
2818 fprintf (fp, "%s%s", delim, _("certification"));
2824 s = key->subkeys->fpr;
2825 fputs (_("Fingerprint: "), fp);
2826 if (is_pgp && m_strlen(s) == 40) {
2827 for (i = 0; *s && s[1] && s[2] && s[3] && s[4]; s += 4, i++) {
2832 putc (is_pgp ? ' ' : ':', fp);
2833 if (is_pgp && i == 4)
2838 for (i = 0; *s && s[1] && s[2]; s += 2, i++) {
2841 putc (is_pgp ? ' ' : ':', fp);
2842 if (is_pgp && i == 7)
2846 fprintf (fp, "%s\n", s);
2849 if (key->issuer_serial) {
2850 s = key->issuer_serial;
2852 fprintf (fp, _("Serial-No .: 0x%s\n"), s);
2855 if (key->issuer_name) {
2856 s = key->issuer_name;
2858 fprintf (fp, _("Issued By .: "));
2859 parse_and_print_user_id (fp, s);
2864 /* For PGP we list all subkeys. */
2866 gpgme_subkey_t subkey = NULL;
2868 for (idx = 1, subkey = key->subkeys; subkey; idx++, subkey = subkey->next) {
2872 if (m_strlen(s) == 16)
2873 s += 8; /* display only the short keyID */
2874 fprintf (fp, _("Subkey ....: 0x%s"), s);
2875 if (subkey->revoked) {
2877 fputs (_("[Revoked]"), fp);
2879 if (subkey->invalid) {
2881 fputs (_("[Invalid]"), fp);
2883 if (subkey->expired) {
2885 fputs (_("[Expired]"), fp);
2887 if (subkey->disabled) {
2889 fputs (_("[Disabled]"), fp);
2893 if (subkey->timestamp > 0) {
2894 tt = subkey->timestamp;
2896 tm = localtime (&tt);
2897 #ifdef HAVE_LANGINFO_D_T_FMT
2898 strftime (shortbuf, sizeof shortbuf, nl_langinfo (D_T_FMT), tm);
2900 strftime (shortbuf, sizeof shortbuf, "%c", tm);
2902 fprintf (fp, _("Valid From : %s\n"), shortbuf);
2905 if (subkey->expires > 0) {
2906 tt = subkey->expires;
2908 tm = localtime (&tt);
2909 #ifdef HAVE_LANGINFO_D_T_FMT
2910 strftime (shortbuf, sizeof shortbuf, nl_langinfo (D_T_FMT), tm);
2912 strftime (shortbuf, sizeof shortbuf, "%c", tm);
2914 fprintf (fp, _("Valid To ..: %s\n"), shortbuf);
2918 s = gpgme_pubkey_algo_name (subkey->pubkey_algo);
2923 aval = subkey->length;
2927 fprintf (fp, _("Key Type ..: %s, %lu bit %s\n"), "PGP", aval, s);
2929 fprintf (fp, _("Key Usage .: "));
2932 if (subkey->can_encrypt) {
2933 fprintf (fp, "%s%s", delim, _("encryption"));
2936 if (subkey->can_sign) {
2937 fprintf (fp, "%s%s", delim, _("signing"));
2940 if (subkey->can_certify) {
2941 fprintf (fp, "%s%s", delim, _("certification"));
2949 setlocale (LC_TIME, "C");
2953 /* Show detailed information about the selected key */
2954 static void verify_key (crypt_key_t * key)
2957 char cmd[LONG_STRING], tempfile[_POSIX_PATH_MAX];
2959 gpgme_ctx_t listctx = NULL;
2961 gpgme_key_t k = NULL;
2964 mutt_mktemp (tempfile);
2965 if (!(fp = safe_fopen (tempfile, "w"))) {
2966 mutt_perror (_("Can't create temporary file"));
2970 mutt_message _("Collecting data...");
2972 print_key_info (key->kobj, fp);
2974 err = gpgme_new (&listctx);
2976 fprintf (fp, "Internal error: can't create gpgme context: %s\n",
2977 gpgme_strerror (err));
2980 if ((key->flags & KEYFLAG_ISX509))
2981 gpgme_set_protocol (listctx, GPGME_PROTOCOL_CMS);
2985 while ((s = k->chain_id) && k->subkeys && m_strcmp(s, k->subkeys->fpr)) {
2987 err = gpgme_op_keylist_start (listctx, s, 0);
2988 gpgme_key_release (k);
2991 err = gpgme_op_keylist_next (listctx, &k);
2993 fprintf (fp, _("Error finding issuer key: %s\n"), gpgme_strerror (err));
2996 gpgme_op_keylist_end (listctx);
2998 print_key_info (k, fp);
3001 fputs (_("Error: certification chain to long - stopping here\n"), fp);
3007 gpgme_key_release (k);
3008 gpgme_release (listctx);
3010 mutt_clear_error ();
3011 snprintf (cmd, sizeof (cmd), _("Key ID: 0x%s"), crypt_keyid (key));
3012 mutt_do_pager (cmd, tempfile, 0, NULL);
3016 * Implementation of `findkeys'.
3020 /* Convert LIST into a pattern string suitable to be passed to GPGME.
3021 We need to convert spaces in an item into a '+' and '%' into
3023 static char *list_to_pattern (LIST * list)
3031 for (l = list; l; l = l->next) {
3032 for (s = l->data; *s; s++) {
3037 n++; /* delimiter or end of string */
3039 n++; /* make sure to allocate at least one byte */
3040 pattern = p = p_new(char, n);
3041 for (l = list; l; l = l->next) {
3046 for (s = l->data; *s; s++) {
3052 else if (*s == '+') {
3068 /* Return a list of keys which are candidates for the selection.
3069 Select by looking at the HINTS list. */
3070 static crypt_key_t *get_candidates (LIST * hints, unsigned int app,
3073 crypt_key_t *db, *k, **kend;
3079 gpgme_user_id_t uid = NULL;
3081 pattern = list_to_pattern (hints);
3085 err = gpgme_new (&ctx);
3087 mutt_error (_("gpgme_new failed: %s"), gpgme_strerror (err));
3095 if ((app & APPLICATION_PGP)) {
3096 /* Its all a mess. That old GPGME expects different things
3097 depending on the protocol. For gpg we don' t need percent
3098 escaped pappert but simple strings passed in an array to the
3099 keylist_ext_start function. */
3104 for (l = hints, n = 0; l; l = l->next) {
3105 if (l->data && *l->data)
3111 patarr = p_new(char *, n + 1);
3112 for (l = hints, n = 0; l; l = l->next) {
3113 if (l->data && *l->data)
3114 patarr[n++] = m_strdup(l->data);
3117 err = gpgme_op_keylist_ext_start (ctx, (const char **) patarr, secret, 0);
3118 for (n = 0; patarr[n]; n++)
3119 p_delete(&patarr[n]);
3122 mutt_error (_("gpgme_op_keylist_start failed: %s"), gpgme_strerror (err));
3123 gpgme_release (ctx);
3128 while (!(err = gpgme_op_keylist_next (ctx, &key))) {
3129 unsigned int flags = 0;
3131 if (key_check_cap (key, KEY_CAP_CAN_ENCRYPT))
3132 flags |= KEYFLAG_CANENCRYPT;
3133 if (key_check_cap (key, KEY_CAP_CAN_SIGN))
3134 flags |= KEYFLAG_CANSIGN;
3136 #if 0 /* DISABLED code */
3138 /* Bug in gpg. Capabilities are not listed for secret
3139 keys. Try to deduce them from the algorithm. */
3141 switch (key->subkeys[0].pubkey_algo) {
3143 flags |= KEYFLAG_CANENCRYPT;
3144 flags |= KEYFLAG_CANSIGN;
3146 case GPGME_PK_ELG_E:
3147 flags |= KEYFLAG_CANENCRYPT;
3150 flags |= KEYFLAG_CANSIGN;
3154 #endif /* DISABLED code */
3156 for (idx = 0, uid = key->uids; uid; idx++, uid = uid->next) {
3157 k = p_new(crypt_key_t, 1);
3166 if (gpg_err_code (err) != GPG_ERR_EOF)
3167 mutt_error (_("gpgme_op_keylist_next failed: %s"), gpgme_strerror (err));
3168 gpgme_op_keylist_end (ctx);
3173 if ((app & APPLICATION_SMIME)) {
3174 /* and now look for x509 certificates */
3175 gpgme_set_protocol (ctx, GPGME_PROTOCOL_CMS);
3176 err = gpgme_op_keylist_start (ctx, pattern, 0);
3178 mutt_error (_("gpgme_op_keylist_start failed: %s"), gpgme_strerror (err));
3179 gpgme_release (ctx);
3184 while (!(err = gpgme_op_keylist_next (ctx, &key))) {
3185 unsigned int flags = KEYFLAG_ISX509;
3187 if (key_check_cap (key, KEY_CAP_CAN_ENCRYPT))
3188 flags |= KEYFLAG_CANENCRYPT;
3189 if (key_check_cap (key, KEY_CAP_CAN_SIGN))
3190 flags |= KEYFLAG_CANSIGN;
3192 for (idx = 0, uid = key->uids; uid; idx++, uid = uid->next) {
3193 k = p_new(crypt_key_t, 1);
3202 if (gpg_err_code (err) != GPG_ERR_EOF)
3203 mutt_error (_("gpgme_op_keylist_next failed: %s"), gpgme_strerror (err));
3204 gpgme_op_keylist_end (ctx);
3207 gpgme_release (ctx);
3212 /* Add the string STR to the list HINTS. This list is later used to
3214 static LIST *crypt_add_string_to_hints (LIST * hints, const char *str)
3219 if ((scratch = m_strdup(str)) == NULL)
3222 for (t = strtok (scratch, " ,.:\"()<>\n"); t;
3223 t = strtok (NULL, " ,.:\"()<>\n")) {
3224 if (m_strlen(t) > 3)
3225 hints = mutt_add_list(hints, t);
3232 /* Display a menu to select a key from the array KEYS. FORCED_VALID
3233 will be set to true on return if the user did override the the
3235 static crypt_key_t *crypt_select_key (crypt_key_t * keys,
3236 ADDRESS * p, const char *s,
3237 unsigned int app, int *forced_valid)
3240 crypt_key_t **key_table;
3243 char helpstr[SHORT_STRING], buf[LONG_STRING];
3245 int (*f) (const void *, const void *);
3246 int menu_to_use = 0;
3251 /* build the key table */
3254 for (k = keys; k; k = k->next) {
3255 if (!option (OPTPGPSHOWUNUSABLE) && (k->flags & KEYFLAG_CANTUSE)) {
3262 p_realloc(&key_table, keymax);
3268 if (!i && unusable) {
3269 mutt_error _("All matching keys are marked expired/revoked.");
3275 switch (PgpSortKeys & SORT_MASK) {
3277 f = crypt_compare_date;
3280 f = crypt_compare_keyid;
3283 f = crypt_compare_address;
3287 f = crypt_compare_trust;
3290 qsort (key_table, i, sizeof (crypt_key_t *), f);
3292 if (app & APPLICATION_PGP)
3293 menu_to_use = MENU_KEY_SELECT_PGP;
3294 else if (app & APPLICATION_SMIME)
3295 menu_to_use = MENU_KEY_SELECT_SMIME;
3298 mutt_make_help (buf, sizeof (buf), _("Exit "), menu_to_use, OP_EXIT);
3299 strcat (helpstr, buf); /* __STRCAT_CHECKED__ */
3300 mutt_make_help (buf, sizeof (buf), _("Select "), menu_to_use,
3301 OP_GENERIC_SELECT_ENTRY);
3302 strcat (helpstr, buf); /* __STRCAT_CHECKED__ */
3303 mutt_make_help (buf, sizeof (buf), _("Check key "),
3304 menu_to_use, OP_VERIFY_KEY);
3305 strcat (helpstr, buf); /* __STRCAT_CHECKED__ */
3306 mutt_make_help (buf, sizeof (buf), _("Help"), menu_to_use, OP_HELP);
3307 strcat (helpstr, buf); /* __STRCAT_CHECKED__ */
3309 menu = mutt_new_menu ();
3311 menu->make_entry = crypt_entry;
3312 menu->menu = menu_to_use;
3313 menu->help = helpstr;
3314 menu->data = key_table;
3319 if ((app & APPLICATION_PGP) && (app & APPLICATION_SMIME))
3320 ts = _("PGP and S/MIME keys matching");
3321 else if ((app & APPLICATION_PGP))
3322 ts = _("PGP keys matching");
3323 else if ((app & APPLICATION_SMIME))
3324 ts = _("S/MIME keys matching");
3326 ts = _("keys matching");
3329 snprintf (buf, sizeof (buf), _("%s <%s>."), ts, p->mailbox);
3331 snprintf (buf, sizeof (buf), _("%s \"%s\"."), ts, s);
3335 mutt_clear_error ();
3339 switch (mutt_menuLoop (menu)) {
3341 verify_key (key_table[menu->current]);
3342 menu->redraw = REDRAW_FULL;
3346 mutt_message ("%s", key_table[menu->current]->uid);
3349 case OP_GENERIC_SELECT_ENTRY:
3350 /* FIXME make error reporting more verbose - this should be
3351 easy because gpgme provides more information */
3352 if (option (OPTPGPCHECKTRUST)) {
3353 if (!crypt_key_is_valid (key_table[menu->current])) {
3354 mutt_error _("This key can't be used: "
3355 "expired/disabled/revoked.");
3360 if (option (OPTPGPCHECKTRUST) &&
3361 (!crypt_id_is_valid (key_table[menu->current])
3362 || !crypt_id_is_strong (key_table[menu->current]))) {
3364 char buff[LONG_STRING];
3366 if (key_table[menu->current]->flags & KEYFLAG_CANTUSE)
3367 s = N_("ID is expired/disabled/revoked.");
3369 gpgme_validity_t val = GPGME_VALIDITY_UNKNOWN;
3370 gpgme_user_id_t uid = NULL;
3375 uid = key_table[menu->current]->kobj->uids;
3376 for (j = 0; (j < key_table[menu->current]->idx) && uid;
3377 j++, uid = uid->next);
3379 val = uid->validity;
3382 case GPGME_VALIDITY_UNKNOWN:
3383 case GPGME_VALIDITY_UNDEFINED:
3384 warn_s = N_("ID has undefined validity.");
3386 case GPGME_VALIDITY_NEVER:
3387 warn_s = N_("ID is not valid.");
3389 case GPGME_VALIDITY_MARGINAL:
3390 warn_s = N_("ID is only marginally valid.");
3392 case GPGME_VALIDITY_FULL:
3393 case GPGME_VALIDITY_ULTIMATE:
3397 snprintf (buff, sizeof (buff),
3398 _("%s Do you really want to use the key?"), _(warn_s));
3400 if (mutt_yesorno (buff, 0) != 1) {
3401 mutt_clear_error ();
3408 k = crypt_copy_key (key_table[menu->current]);
3419 mutt_menuDestroy (&menu);
3420 p_delete(&key_table);
3422 set_option (OPTNEEDREDRAW);
3427 static crypt_key_t *crypt_getkeybyaddr (ADDRESS * a, short abilities,
3428 unsigned int app, int *forced_valid)
3436 int this_key_has_strong;
3437 int this_key_has_weak;
3438 int this_key_has_invalid;
3441 crypt_key_t *keys, *k;
3442 crypt_key_t *the_valid_key = NULL;
3443 crypt_key_t *matches = NULL;
3444 crypt_key_t **matches_endp = &matches;
3448 if (a && a->mailbox)
3449 hints = crypt_add_string_to_hints (hints, a->mailbox);
3450 if (a && a->personal)
3451 hints = crypt_add_string_to_hints (hints, a->personal);
3453 mutt_message (_("Looking for keys matching \"%s\"..."), a->mailbox);
3454 keys = get_candidates (hints, app, (abilities & KEYFLAG_CANSIGN));
3456 mutt_free_list (&hints);
3461 debug_print (5, ("looking for %s <%s>.\n", a->personal, a->mailbox));
3463 for (k = keys; k; k = k->next) {
3464 debug_print (5, (" looking at key: %s `%.15s'\n", crypt_keyid (k), k->uid));
3466 if (abilities && !(k->flags & abilities)) {
3467 debug_print (5, (" insufficient abilities: Has %x, want %x\n", k->flags, abilities));
3471 this_key_has_weak = 0; /* weak but valid match */
3472 this_key_has_invalid = 0; /* invalid match */
3473 this_key_has_strong = 0; /* strong and valid match */
3474 match = 0; /* any match */
3476 r = rfc822_parse_adrlist (NULL, k->uid);
3477 for (p = r; p; p = p->next) {
3478 int validity = crypt_id_matches_addr (a, p, k);
3480 if (validity & CRYPT_KV_MATCH) /* something matches */
3483 /* is this key a strong candidate? */
3484 if ((validity & CRYPT_KV_VALID)
3485 && (validity & CRYPT_KV_STRONGID)
3486 && (validity & CRYPT_KV_ADDR)) {
3487 if (the_valid_key && the_valid_key != k)
3490 this_key_has_strong = 1;
3492 else if ((validity & CRYPT_KV_MATCH)
3493 && !(validity & CRYPT_KV_VALID))
3494 this_key_has_invalid = 1;
3495 else if ((validity & CRYPT_KV_MATCH)
3496 && (!(validity & CRYPT_KV_STRONGID)
3497 || !(validity & CRYPT_KV_ADDR)))
3498 this_key_has_weak = 1;
3500 rfc822_free_address (&r);
3505 if (!this_key_has_strong && this_key_has_invalid)
3507 if (!this_key_has_strong && this_key_has_weak)
3510 *matches_endp = tmp = crypt_copy_key (k);
3511 matches_endp = &tmp->next;
3512 the_valid_key = tmp;
3516 crypt_free_key (&keys);
3519 if (the_valid_key && !multi && !weak
3520 && !(invalid && option (OPTPGPSHOWUNUSABLE))) {
3522 * There was precisely one strong match on a valid ID, there
3523 * were no valid keys with weak matches, and we aren't
3524 * interested in seeing invalid keys.
3526 * Proceed without asking the user.
3528 k = crypt_copy_key (the_valid_key);
3532 * Else: Ask the user.
3534 k = crypt_select_key (matches, a, NULL, app, forced_valid);
3536 crypt_free_key (&matches);
3545 static crypt_key_t *crypt_getkeybystr (char *p, short abilities,
3546 unsigned int app, int *forced_valid)
3550 crypt_key_t *matches = NULL;
3551 crypt_key_t **matches_endp = &matches;
3555 mutt_message (_("Looking for keys matching \"%s\"..."), p);
3559 hints = crypt_add_string_to_hints (hints, p);
3560 keys = get_candidates (hints, app, (abilities & KEYFLAG_CANSIGN));
3561 mutt_free_list (&hints);
3566 for (k = keys; k; k = k->next) {
3567 if (abilities && !(k->flags & abilities))
3571 debug_print (5, ("matching \"%s\" against " "key %s, \"%s\":\n", p, crypt_keyid (k), k->uid));
3573 if (!*p || !m_strcasecmp(p, crypt_keyid (k))
3574 || (!m_strncasecmp(p, "0x", 2)
3575 && !m_strcasecmp(p + 2, crypt_keyid (k)))
3576 || (option (OPTPGPLONGIDS)
3577 && !m_strncasecmp(p, "0x", 2)
3578 && !m_strcasecmp(p + 2, crypt_keyid (k) + 8))
3579 || str_isstr (k->uid, p)) {
3582 debug_print (5, ("match.\n"));
3584 *matches_endp = tmp = crypt_copy_key (k);
3585 matches_endp = &tmp->next;
3589 crypt_free_key (&keys);
3592 k = crypt_select_key (matches, NULL, p, app, forced_valid);
3593 crypt_free_key (&matches);
3600 /* Display TAG as a prompt to ask for a key. If WHATFOR is not null
3601 use it as default and store it under that label as the next
3602 default. ABILITIES describe the required key abilities (sign,
3603 encrypt) and APP the type of the requested key; ether S/MIME or
3604 PGP. Return a copy of the key or NULL if not found. */
3605 static crypt_key_t *crypt_ask_for_key (char *tag,
3608 unsigned int app, int *forced_valid)
3611 char resp[SHORT_STRING];
3612 struct crypt_cache *l = NULL;
3616 forced_valid = &dummy;
3618 mutt_clear_error ();
3624 for (l = id_defaults; l; l = l->next)
3625 if (!m_strcasecmp(whatfor, l->what)) {
3626 m_strcpy(resp, sizeof(resp), NONULL(l->dflt));
3634 if (mutt_get_field (tag, resp, sizeof (resp), M_CLEAR) != 0)
3639 str_replace (&l->dflt, resp);
3641 l = p_new(struct crypt_cache, 1);
3642 l->next = id_defaults;
3644 l->what = m_strdup(whatfor);
3645 l->dflt = m_strdup(resp);
3649 if ((key = crypt_getkeybystr (resp, abilities, app, forced_valid)))
3657 /* This routine attempts to find the keyids of the recipients of a
3658 message. It returns NULL if any of the keys can not be found. */
3659 static char *find_keys (ADDRESS * to, ADDRESS * cc, ADDRESS * bcc,
3662 char *keyID, *keylist = NULL, *t;
3663 size_t keylist_size = 0;
3664 size_t keylist_used = 0;
3665 ADDRESS *tmp = NULL, *addr = NULL;
3666 ADDRESS **last = &tmp;
3669 crypt_key_t *k_info, *key;
3670 const char *fqdn = mutt_fqdn (1);
3673 *r_application = APPLICATION_PGP | APPLICATION_SMIME;
3676 for (i = 0; i < 3; i++) {
3691 *last = rfc822_cpy_adr (p);
3693 last = &((*last)->next);
3697 rfc822_qualify (tmp, fqdn);
3699 tmp = mutt_remove_duplicates (tmp);
3701 for (p = tmp; p; p = p->next) {
3702 char buf[LONG_STRING];
3703 int forced_valid = 0;
3708 if ((keyID = mutt_crypt_hook (p)) != NULL) {
3711 snprintf (buf, sizeof (buf), _("Use keyID = \"%s\" for %s?"),
3713 if ((r = mutt_yesorno (buf, M_YES)) == M_YES) {
3714 /* check for e-mail address */
3715 if ((t = strchr (keyID, '@')) &&
3716 (addr = rfc822_parse_adrlist (NULL, keyID))) {
3718 rfc822_qualify (addr, fqdn);
3723 k_info = crypt_getkeybystr (keyID, KEYFLAG_CANENCRYPT,
3724 *r_application, &forced_valid);
3726 k_info = crypt_getkeybystr (keyID, KEYFLAG_CANENCRYPT,
3727 app, &forced_valid);
3733 rfc822_free_address (&tmp);
3734 rfc822_free_address (&addr);
3740 && (k_info = crypt_getkeybyaddr (q, KEYFLAG_CANENCRYPT,
3741 app, &forced_valid)) == NULL) {
3742 snprintf (buf, sizeof (buf), _("Enter keyID for %s: "), q->mailbox);
3744 if ((key = crypt_ask_for_key (buf, q->mailbox, KEYFLAG_CANENCRYPT,
3750 &forced_valid)) == NULL) {
3752 rfc822_free_address (&tmp);
3753 rfc822_free_address (&addr);
3761 const char *s = crypt_fpr (key);
3764 if (key->flags & KEYFLAG_ISX509)
3765 *r_application &= ~APPLICATION_PGP;
3766 if (!(key->flags & KEYFLAG_ISX509))
3767 *r_application &= ~APPLICATION_SMIME;
3770 keylist_size += m_strlen(s) + 4 + 1;
3771 p_realloc(&keylist, keylist_size);
3772 sprintf (keylist + keylist_used, "%s0x%s%s", /* __SPRINTF_CHECKED__ */
3773 keylist_used ? " " : "", s, forced_valid ? "!" : "");
3775 keylist_used = m_strlen(keylist);
3777 crypt_free_key (&key);
3778 rfc822_free_address (&addr);
3780 rfc822_free_address (&tmp);
3784 char *pgp_gpgme_findkeys (ADDRESS * to, ADDRESS * cc, ADDRESS * bcc)
3786 return find_keys (to, cc, bcc, APPLICATION_PGP);
3789 char *smime_gpgme_findkeys (ADDRESS * to, ADDRESS * cc, ADDRESS * bcc)
3791 return find_keys (to, cc, bcc, APPLICATION_SMIME);
3795 * Implementation of `init'.
3798 /* Initialization. */
3799 static void init_gpgme (void)
3801 /* Make sure that gpg-agent is running. */
3802 if (!getenv ("GPG_AGENT_INFO")) {
3803 mutt_error ("\nUsing GPGME backend, although no gpg-agent is running");
3804 if (mutt_any_key_to_continue (NULL) == -1)
3809 void pgp_gpgme_init (void)
3814 void smime_gpgme_init (void)
3818 static int gpgme_send_menu (HEADER * msg, int *redraw, int is_smime)
3821 char input_signas[SHORT_STRING];
3824 if (msg->security & APPLICATION_PGP)
3826 else if (msg->security & APPLICATION_SMIME)
3831 mutt_multi_choice (_
3832 ("S/MIME (e)ncrypt, (s)ign, sign (a)s, (b)oth, (p)gp or (c)lear?"),
3836 mutt_multi_choice (_
3837 ("PGP (e)ncrypt, (s)ign, sign (a)s, (b)oth, s/(m)ime or (c)lear?"),
3841 case 1: /* (e)ncrypt */
3842 msg->security |= (is_smime ? SMIMEENCRYPT : PGPENCRYPT);
3843 msg->security &= ~(is_smime ? SMIMESIGN : PGPSIGN);
3846 case 2: /* (s)ign */
3847 msg->security |= (is_smime ? SMIMESIGN : PGPSIGN);
3848 msg->security &= ~(is_smime ? SMIMEENCRYPT : PGPENCRYPT);
3851 case 3: /* sign (a)s */
3852 /* unset_option(OPTCRYPTCHECKTRUST); */
3853 if ((p = crypt_ask_for_key (_("Sign as: "), NULL, KEYFLAG_CANSIGN,
3854 is_smime ? APPLICATION_SMIME :
3855 APPLICATION_PGP, NULL))) {
3856 snprintf (input_signas, sizeof (input_signas), "0x%s", crypt_keyid (p));
3857 str_replace (is_smime ? &SmimeDefaultKey : &PgpSignAs,
3859 crypt_free_key (&p);
3861 msg->security |= (is_smime ? SMIMESIGN : PGPSIGN);
3865 msg->security &= (is_smime ? ~SMIMESIGN : ~PGPSIGN);
3868 *redraw = REDRAW_FULL;
3871 case 4: /* (b)oth */
3873 (is_smime ? (SMIMEENCRYPT | SMIMESIGN) : (PGPENCRYPT | PGPSIGN));
3876 case 5: /* (p)gp or s/(m)ime */
3877 is_smime = !is_smime;
3880 case 6: /* (c)lear */
3885 if (choice == 6 || choice == 7);
3886 else if (is_smime) {
3887 msg->security &= ~APPLICATION_PGP;
3888 msg->security |= APPLICATION_SMIME;
3891 msg->security &= ~APPLICATION_SMIME;
3892 msg->security |= APPLICATION_PGP;
3895 return (msg->security);
3898 int pgp_gpgme_send_menu (HEADER * msg, int *redraw)
3900 return gpgme_send_menu (msg, redraw, 0);
3903 int smime_gpgme_send_menu (HEADER * msg, int *redraw)
3905 return gpgme_send_menu (msg, redraw, 1);
3908 static int verify_sender (HEADER * h, gpgme_protocol_t protocol)
3910 ADDRESS *sender = NULL;
3911 unsigned int ret = 1;
3914 h->env->from = mutt_expand_aliases (h->env->from);
3915 sender = h->env->from;
3917 else if (h->env->sender) {
3918 h->env->sender = mutt_expand_aliases (h->env->sender);
3919 sender = h->env->sender;
3923 if (signature_key) {
3924 gpgme_key_t key = signature_key;
3925 gpgme_user_id_t uid = NULL;
3926 int sender_length = 0;
3929 sender_length = m_strlen(sender->mailbox);
3930 for (uid = key->uids; uid && ret; uid = uid->next) {
3931 uid_length = m_strlen(uid->email);
3932 if (1 && (uid->email[0] == '<')
3933 && (uid->email[uid_length - 1] == '>')
3934 && (uid_length == sender_length + 2)
3935 && (!strncmp (uid->email + 1, sender->mailbox, sender_length)))
3940 mutt_any_key_to_continue ("Failed to verify sender");
3943 mutt_any_key_to_continue ("Failed to figure out sender");
3945 if (signature_key) {
3946 gpgme_key_release (signature_key);
3947 signature_key = NULL;
3953 int smime_gpgme_verify_sender (HEADER * h)
3955 return verify_sender (h, GPGME_PROTOCOL_CMS);