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>
26 #include <lib-lib/debug.h>
28 #include <lib-mime/mime.h>
30 #include <lib-ui/curses.h>
31 #include <lib-ui/enter.h>
32 #include <lib-ui/menu.h>
35 #include <lib-crypt/crypt.h>
39 #include "recvattach.h"
56 #ifdef HAVE_LANGINFO_D_T_FMT
60 #ifdef HAVE_SYS_TIME_H
61 # include <sys/time.h>
64 #ifdef HAVE_SYS_RESOURCE_H
65 # include <sys/resource.h>
71 #define digitp(p) (*(p) >= '0' && *(p) <= '9')
72 #define hexdigitp(a) (digitp (a) \
73 || (*(a) >= 'A' && *(a) <= 'F') \
74 || (*(a) >= 'a' && *(a) <= 'f'))
75 #define xtoi_1(p) (*(p) <= '9'? (*(p)- '0'): \
76 *(p) <= 'F'? (*(p)-'A'+10):(*(p)-'a'+10))
77 #define xtoi_2(p) ((xtoi_1(p) * 16) + xtoi_1((p)+1))
79 /* Values used for comparing addresses. */
80 #define CRYPT_KV_VALID 1
81 #define CRYPT_KV_ADDR 2
82 #define CRYPT_KV_STRING 4
83 #define CRYPT_KV_STRONGID 8
84 #define CRYPT_KV_MATCH (CRYPT_KV_ADDR|CRYPT_KV_STRING)
93 struct crypt_cache *next;
101 /* We work based on user IDs, getting from a user ID to the key is
102 check and does not need any memory (gpgme uses reference counting). */
103 typedef struct crypt_keyinfo {
104 struct crypt_keyinfo *next;
106 int idx; /* and the user ID at this index */
107 const char *uid; /* and for convenience point to this user ID */
108 unsigned int flags; /* global and per uid flags (for convenience) */
111 typedef struct crypt_entry {
117 static struct crypt_cache *id_defaults = NULL;
118 static gpgme_key_t signature_key = NULL;
121 * General helper functions.
124 /* return true when S points to a didgit or letter. */
125 static int digit_or_letter (const unsigned char *s)
127 return ((*s >= '0' && *s <= '9')
128 || (*s >= 'A' && *s <= 'Z')
129 || (*s >= 'a' && *s <= 'z'));
133 /* Print the utf-8 encoded string BUF of length LEN bytes to stream
134 FP. Convert the character set. */
135 static void print_utf8 (FILE * fp, const char *buf, size_t len)
139 tstr = p_dupstr(buf, len);
140 mutt_convert_string (&tstr, "utf-8", Charset, M_ICONV_HOOK_FROM);
150 /* Return the keyID for the key K. Note that this string is valid as
151 long as K is valid */
152 static const char *crypt_keyid (crypt_key_t * k)
154 const char *s = "????????";
156 if (k->kobj && k->kobj->subkeys) {
157 s = k->kobj->subkeys->keyid;
158 if ((!option (OPTPGPLONGIDS)) && (m_strlen(s) == 16))
159 /* Return only the short keyID. */
166 /* Return the hexstring fingerprint from the key K. */
167 static const char *crypt_fpr (crypt_key_t * k)
171 if (k->kobj && k->kobj->subkeys)
172 s = k->kobj->subkeys->fpr;
177 /* Parse FLAGS and return a statically allocated(!) string with them. */
178 static char *crypt_key_abilities (int flags)
182 if (!(flags & KEYFLAG_CANENCRYPT))
184 else if (flags & KEYFLAG_PREFER_SIGNING)
189 if (!(flags & KEYFLAG_CANSIGN))
191 else if (flags & KEYFLAG_PREFER_ENCRYPTION)
201 /* Parse FLAGS and return a character describing the most important flag. */
202 static char crypt_flags (int flags)
204 if (flags & KEYFLAG_REVOKED)
206 else if (flags & KEYFLAG_EXPIRED)
208 else if (flags & KEYFLAG_DISABLED)
210 else if (flags & KEYFLAG_CRITICAL)
216 /* Return a copy of KEY. */
217 static crypt_key_t *crypt_copy_key (crypt_key_t *key)
221 k = p_new(crypt_key_t, 1);
223 gpgme_key_ref (key->kobj);
226 k->flags = key->flags;
231 /* Release all the keys at the address of KEYLIST and set the address
233 static void crypt_free_key (crypt_key_t ** keylist)
236 crypt_key_t *k = (*keylist)->next;
243 /* Return trute when key K is valid. */
244 static int crypt_key_is_valid (crypt_key_t * k)
246 if (k->flags & KEYFLAG_CANTUSE)
251 /* Return true whe validity of KEY is sufficient. */
252 static int crypt_id_is_strong (crypt_key_t * key)
254 gpgme_validity_t val = GPGME_VALIDITY_UNKNOWN;
255 gpgme_user_id_t uid = NULL;
256 unsigned int is_strong = 0;
259 if ((key->flags & KEYFLAG_ISX509))
262 for (i = 0, uid = key->kobj->uids; (i < key->idx) && uid;
263 i++, uid = uid->next);
268 case GPGME_VALIDITY_UNKNOWN:
269 case GPGME_VALIDITY_UNDEFINED:
270 case GPGME_VALIDITY_NEVER:
271 case GPGME_VALIDITY_MARGINAL:
275 case GPGME_VALIDITY_FULL:
276 case GPGME_VALIDITY_ULTIMATE:
284 /* Return true when the KEY is valid, i.e. not marked as unusable. */
285 static int crypt_id_is_valid (crypt_key_t * key)
287 return !(key->flags & KEYFLAG_CANTUSE);
290 /* Return a bit vector describing how well the addresses ADDR and
291 U_ADDR match and whether KEY is valid. */
292 static int crypt_id_matches_addr (address_t * addr, address_t * u_addr,
297 if (crypt_id_is_valid (key))
298 rv |= CRYPT_KV_VALID;
300 if (crypt_id_is_strong (key))
301 rv |= CRYPT_KV_STRONGID;
303 if (addr->mailbox && u_addr->mailbox
304 && m_strcasecmp(addr->mailbox, u_addr->mailbox) == 0)
307 if (addr->personal && u_addr->personal
308 && m_strcasecmp(addr->personal, u_addr->personal) == 0)
309 rv |= CRYPT_KV_STRING;
316 * GPGME convenient functions.
319 /* Create a new gpgme context and return it. With FOR_SMIME set to
320 true, the protocol of the context is set to CMS. */
321 static gpgme_ctx_t create_gpgme_context (int for_smime)
326 err = gpgme_new (&ctx);
328 mutt_error (_("error creating gpgme context: %s\n"), gpgme_strerror (err));
334 err = gpgme_set_protocol (ctx, GPGME_PROTOCOL_CMS);
336 mutt_error (_("error enabling CMS protocol: %s\n"), gpgme_strerror (err));
345 /* Create a new gpgme data object. This is a wrapper to die on
347 static gpgme_data_t create_gpgme_data (void)
352 err = gpgme_data_new (&data);
354 mutt_error (_("error creating gpgme data object: %s\n"),
355 gpgme_strerror (err));
362 /* Create a new GPGME Data object from the mail body A. With CONVERT
363 passed as true, the lines are converted to CR,LF if required.
364 Return NULL on error or the gpgme_data_t object on success. */
365 static gpgme_data_t body_to_data_object (BODY * a, int convert)
367 char tempfile[_POSIX_PATH_MAX];
372 mutt_mktemp (tempfile);
373 fptmp = safe_fopen (tempfile, "w+");
375 mutt_perror (tempfile);
379 mutt_write_mime_header (a, fptmp);
381 mutt_write_mime_body (a, fptmp);
385 unsigned char buf[1];
387 data = create_gpgme_data ();
389 while ((c = fgetc (fptmp)) != EOF) {
393 if (c == '\n' && !hadcr) {
395 gpgme_data_write (data, buf, 1);
400 /* FIXME: This is quite suboptimal */
402 gpgme_data_write (data, buf, 1);
405 gpgme_data_seek (data, 0, SEEK_SET);
409 err = gpgme_data_new_from_file (&data, tempfile, 1);
413 mutt_error (_("error allocating data object: %s\n"), gpgme_strerror (err));
420 /* Create a GPGME data object from the stream FP but limit the object
421 to LENGTH bytes starting at OFFSET bytes from the beginning of the
423 static gpgme_data_t file_to_data_object (FILE * fp, long offset, long length)
428 err = gpgme_data_new_from_filepart (&data, NULL, fp, offset, length);
430 mutt_error (_("error allocating data object: %s\n"), gpgme_strerror (err));
437 /* Write a GPGME data object to the stream FP. */
438 static int data_object_to_stream (gpgme_data_t data, FILE * fp)
444 err = ((gpgme_data_seek (data, 0, SEEK_SET) == -1)
445 ? gpgme_error_from_errno (errno) : 0);
447 mutt_error (_("error rewinding data object: %s\n"), gpgme_strerror (err));
451 while ((nread = gpgme_data_read (data, buf, sizeof (buf)))) {
452 /* fixme: we are not really converting CRLF to LF but just
453 skipping CR. Doing it correctly needs a more complex logic */
454 for (p = buf; nread; p++, nread--) {
460 mutt_perror ("[tempfile]");
465 mutt_error (_("error reading data object: %s\n"), strerror (errno));
471 /* Copy a data object to a newly created temporay file and return that
472 filename. Caller must free. With RET_FP not NULL, don't close the
473 stream but return it there. */
474 static char *data_object_to_tempfile (gpgme_data_t data, FILE ** ret_fp)
477 char tempfile[_POSIX_PATH_MAX];
481 mutt_mktemp (tempfile);
482 fp = safe_fopen (tempfile, "w+");
484 mutt_perror (tempfile);
488 err = ((gpgme_data_seek (data, 0, SEEK_SET) == -1)
489 ? gpgme_error_from_errno (errno) : 0);
493 while ((nread = gpgme_data_read (data, buf, sizeof (buf)))) {
494 if (fwrite (buf, nread, 1, fp) != 1) {
495 mutt_perror (tempfile);
507 mutt_error (_("error reading data object: %s\n"), gpgme_strerror (err));
514 return m_strdup(tempfile);
518 /* Create a GpgmeRecipientSet from the keys in the string KEYLIST.
519 The keys must be space delimited. */
520 static gpgme_key_t *create_recipient_set (const char *keylist,
521 gpgme_protocol_t protocol)
527 gpgme_key_t *rset = NULL;
528 unsigned int rset_n = 0;
529 gpgme_key_t key = NULL;
530 gpgme_ctx_t context = NULL;
532 err = gpgme_new (&context);
534 err = gpgme_set_protocol (context, protocol);
541 for (i = 0; *s && *s != ' ' && i < sizeof (buf) - 1;)
545 if (i > 1 && buf[i - 1] == '!') {
546 /* The user selected to override the valididy of that
550 err = gpgme_get_key (context, buf, &key, 0);
552 key->uids->validity = GPGME_VALIDITY_FULL;
556 err = gpgme_get_key (context, buf, &key, 0);
559 p_realloc(&rset, rset_n + 1);
560 rset[rset_n++] = key;
563 mutt_error (_("error adding recipient `%s': %s\n"),
564 buf, gpgme_strerror (err));
572 /* NULL terminate. */
573 p_realloc(&rset, rset_n + 1);
574 rset[rset_n++] = NULL;
577 gpgme_release (context);
583 /* Make sure that the correct signer is set. Returns 0 on success. */
584 static int set_signer (gpgme_ctx_t ctx, int for_smime)
586 char *signid = for_smime ? SmimeDefaultKey : PgpSignAs;
589 gpgme_key_t key, key2;
591 if (!signid || !*signid)
594 listctx = create_gpgme_context (for_smime);
595 err = gpgme_op_keylist_start (listctx, signid, 1);
597 err = gpgme_op_keylist_next (listctx, &key);
599 gpgme_release (listctx);
600 mutt_error (_("secret key `%s' not found: %s\n"),
601 signid, gpgme_strerror (err));
604 err = gpgme_op_keylist_next (listctx, &key2);
606 gpgme_key_release (key);
607 gpgme_key_release (key2);
608 gpgme_release (listctx);
609 mutt_error (_("ambiguous specification of secret key `%s'\n"), signid);
612 gpgme_op_keylist_end (listctx);
613 gpgme_release (listctx);
615 gpgme_signers_clear (ctx);
616 err = gpgme_signers_add (ctx, key);
617 gpgme_key_release (key);
619 mutt_error (_("error setting secret key `%s': %s\n"),
620 signid, gpgme_strerror (err));
627 /* Encrypt the gpgme data object PLAINTEXT to the recipients in RSET
628 and return an allocated filename to a temporary file containing the
629 enciphered text. With USE_SMIME set to true, the smime backend is
630 used. With COMBINED_SIGNED a PGP message is signed and
631 encrypted. Returns NULL in case of error */
632 static char *encrypt_gpgme_object (gpgme_data_t plaintext, gpgme_key_t * rset,
633 int use_smime, int combined_signed)
637 gpgme_data_t ciphertext;
640 ctx = create_gpgme_context (use_smime);
642 gpgme_set_armor (ctx, 1);
644 ciphertext = create_gpgme_data ();
646 if (combined_signed) {
647 if (set_signer (ctx, use_smime)) {
648 gpgme_data_release (ciphertext);
652 err = gpgme_op_encrypt_sign (ctx, rset, GPGME_ENCRYPT_ALWAYS_TRUST,
653 plaintext, ciphertext);
656 err = gpgme_op_encrypt (ctx, rset, GPGME_ENCRYPT_ALWAYS_TRUST,
657 plaintext, ciphertext);
658 mutt_need_hard_redraw ();
660 mutt_error (_("error encrypting data: %s\n"), gpgme_strerror (err));
661 gpgme_data_release (ciphertext);
668 outfile = data_object_to_tempfile (ciphertext, NULL);
669 gpgme_data_release (ciphertext);
673 /* Find the "micalg" parameter from the last Gpgme operation on
674 context CTX. It is expected that this operation was a sign
675 operation. Return the algorithm name as a C string in buffer BUF
676 which must have been allocated by the caller with size BUFLEN.
677 Returns 0 on success or -1 in case of an error. The return string
678 is truncted to BUFLEN - 1. */
679 static int get_micalg (gpgme_ctx_t ctx, char *buf, size_t buflen)
681 gpgme_sign_result_t result = NULL;
682 const char *algorithm_name = NULL;
688 result = gpgme_op_sign_result (ctx);
690 algorithm_name = gpgme_hash_algo_name (result->signatures->hash_algo);
691 if (algorithm_name) {
692 m_strcpy(buf, buflen, algorithm_name);
696 return *buf ? 0 : -1;
699 static void print_time (time_t t, STATE * s)
703 setlocale (LC_TIME, "");
704 #ifdef HAVE_LANGINFO_D_T_FMT
705 strftime (p, sizeof (p), nl_langinfo (D_T_FMT), localtime (&t));
707 strftime (p, sizeof (p), "%c", localtime (&t));
709 setlocale (LC_TIME, "C");
710 state_attach_puts (p, s);
714 * Implementation of `sign_message'.
717 /* Sign the MESSAGE in body A either using OpenPGP or S/MIME when
718 USE_SMIME is passed as true. Returns the new body or NULL on
720 static BODY *sign_message (BODY * a, int use_smime)
727 gpgme_data_t message, signature;
729 convert_to_7bit (a); /* Signed data _must_ be in 7-bit format. */
731 message = body_to_data_object (a, 1);
734 signature = create_gpgme_data ();
736 ctx = create_gpgme_context (use_smime);
738 gpgme_set_armor (ctx, 1);
740 if (set_signer (ctx, use_smime)) {
741 gpgme_data_release (signature);
746 err = gpgme_op_sign (ctx, message, signature, GPGME_SIG_MODE_DETACH);
747 mutt_need_hard_redraw ();
748 gpgme_data_release (message);
750 gpgme_data_release (signature);
752 mutt_error (_("error signing data: %s\n"), gpgme_strerror (err));
756 sigfile = data_object_to_tempfile (signature, NULL);
757 gpgme_data_release (signature);
763 t = mutt_new_body ();
764 t->type = TYPEMULTIPART;
765 t->subtype = m_strdup("signed");
766 t->encoding = ENC7BIT;
768 t->disposition = DISPINLINE;
770 mutt_generate_boundary (&t->parameter);
771 mutt_set_parameter ("protocol",
772 use_smime ? "application/pkcs7-signature"
773 : "application/pgp-signature", &t->parameter);
774 /* Get the micalg from gpgme. Old gpgme versions don't support this
775 for S/MIME so we assume sha-1 in this case. */
776 if (!get_micalg (ctx, buf, sizeof buf))
777 mutt_set_parameter ("micalg", buf, &t->parameter);
779 mutt_set_parameter ("micalg", "sha1", &t->parameter);
785 t->parts->next = mutt_new_body ();
787 t->type = TYPEAPPLICATION;
789 t->subtype = m_strdup("pkcs7-signature");
790 mutt_set_parameter ("name", "smime.p7s", &t->parameter);
791 t->encoding = ENCBASE64;
793 t->disposition = DISPATTACH;
794 t->d_filename = m_strdup("smime.p7s");
797 t->subtype = m_strdup("pgp-signature");
799 t->disposition = DISPINLINE;
800 t->encoding = ENC7BIT;
802 t->filename = sigfile;
803 t->unlink = 1; /* ok to remove this file after sending. */
809 BODY *pgp_gpgme_sign_message (BODY * a)
811 return sign_message (a, 0);
814 BODY *smime_gpgme_sign_message (BODY * a)
816 return sign_message (a, 1);
820 * Implementation of `encrypt_message'.
823 /* Encrypt the mail body A to all keys given as space separated keyids
824 or fingerprints in KEYLIST and return the encrypted body. */
825 BODY *pgp_gpgme_encrypt_message (BODY * a, char *keylist, int sign)
827 char *outfile = NULL;
829 gpgme_key_t *rset = NULL;
830 gpgme_data_t plaintext;
832 rset = create_recipient_set (keylist, GPGME_PROTOCOL_OpenPGP);
838 plaintext = body_to_data_object (a, 0);
844 outfile = encrypt_gpgme_object (plaintext, rset, 0, sign);
845 gpgme_data_release (plaintext);
850 t = mutt_new_body ();
851 t->type = TYPEMULTIPART;
852 t->subtype = m_strdup("encrypted");
853 t->encoding = ENC7BIT;
855 t->disposition = DISPINLINE;
857 mutt_generate_boundary (&t->parameter);
858 mutt_set_parameter ("protocol", "application/pgp-encrypted", &t->parameter);
860 t->parts = mutt_new_body ();
861 t->parts->type = TYPEAPPLICATION;
862 t->parts->subtype = m_strdup("pgp-encrypted");
863 t->parts->encoding = ENC7BIT;
865 t->parts->next = mutt_new_body ();
866 t->parts->next->type = TYPEAPPLICATION;
867 t->parts->next->subtype = m_strdup("octet-stream");
868 t->parts->next->encoding = ENC7BIT;
869 t->parts->next->filename = outfile;
870 t->parts->next->use_disp = 1;
871 t->parts->next->disposition = DISPINLINE;
872 t->parts->next->unlink = 1; /* delete after sending the message */
873 t->parts->next->d_filename = m_strdup("msg.asc"); /* non pgp/mime
880 * Implementation of `smime_build_smime_entity'.
883 /* Encrypt the mail body A to all keys given as space separated
884 fingerprints in KEYLIST and return the S/MIME encrypted body. */
885 BODY *smime_gpgme_build_smime_entity (BODY * a, char *keylist)
887 char *outfile = NULL;
889 gpgme_key_t *rset = NULL;
890 gpgme_data_t plaintext;
892 rset = create_recipient_set (keylist, GPGME_PROTOCOL_CMS);
896 plaintext = body_to_data_object (a, 0);
902 outfile = encrypt_gpgme_object (plaintext, rset, 1, 0);
903 gpgme_data_release (plaintext);
908 t = mutt_new_body ();
909 t->type = TYPEAPPLICATION;
910 t->subtype = m_strdup("pkcs7-mime");
911 mutt_set_parameter ("name", "smime.p7m", &t->parameter);
912 mutt_set_parameter ("smime-type", "enveloped-data", &t->parameter);
913 t->encoding = ENCBASE64; /* The output of OpenSSL SHOULD be binary */
915 t->disposition = DISPATTACH;
916 t->d_filename = m_strdup("smime.p7m");
917 t->filename = outfile;
918 t->unlink = 1; /*delete after sending the message */
927 * Implementation of `verify_one'.
930 /* Display the common attributes of the signature summary SUM.
931 Return 1 if there is is a severe warning.
933 static int show_sig_summary (unsigned long sum,
934 gpgme_ctx_t ctx, gpgme_key_t key, int idx,
939 if ((sum & GPGME_SIGSUM_KEY_REVOKED)) {
940 state_attach_puts (_("Warning: One of the keys has been revoked\n"), s);
944 if ((sum & GPGME_SIGSUM_KEY_EXPIRED)) {
945 time_t at = key->subkeys->expires ? key->subkeys->expires : 0;
948 state_attach_puts (_("Warning: The key used to create the "
949 "signature expired at: "), s);
951 state_attach_puts ("\n", s);
954 state_attach_puts (_("Warning: At least one certification key "
955 "has expired\n"), s);
958 if ((sum & GPGME_SIGSUM_SIG_EXPIRED)) {
959 gpgme_verify_result_t result;
960 gpgme_signature_t sig;
963 result = gpgme_op_verify_result (ctx);
965 for (sig = result->signatures, i = 0; sig && (i < idx);
966 sig = sig->next, i++);
968 state_attach_puts (_("Warning: The signature expired at: "), s);
969 print_time (sig ? sig->exp_timestamp : 0, s);
970 state_attach_puts ("\n", s);
973 if ((sum & GPGME_SIGSUM_KEY_MISSING))
974 state_attach_puts (_("Can't verify due to a missing "
975 "key or certificate\n"), s);
977 if ((sum & GPGME_SIGSUM_CRL_MISSING)) {
978 state_attach_puts (_("The CRL is not available\n"), s);
982 if ((sum & GPGME_SIGSUM_CRL_TOO_OLD)) {
983 state_attach_puts (_("Available CRL is too old\n"), s);
987 if ((sum & GPGME_SIGSUM_BAD_POLICY))
988 state_attach_puts (_("A policy requirement was not met\n"), s);
990 if ((sum & GPGME_SIGSUM_SYS_ERROR)) {
991 const char *t0 = NULL, *t1 = NULL;
992 gpgme_verify_result_t result;
993 gpgme_signature_t sig;
996 state_attach_puts (_("A system error occurred"), s);
998 /* Try to figure out some more detailed system error information. */
999 result = gpgme_op_verify_result (ctx);
1000 for (sig = result->signatures, i = 0; sig && (i < idx);
1001 sig = sig->next, i++);
1004 t1 = sig->wrong_key_usage ? "Wrong_Key_Usage" : "";
1008 state_attach_puts (": ", s);
1010 state_attach_puts (t0, s);
1011 if (t1 && !(t0 && !m_strcmp(t0, t1))) {
1013 state_attach_puts (",", s);
1014 state_attach_puts (t1, s);
1017 state_attach_puts ("\n", s);
1024 static void show_fingerprint (gpgme_key_t key, STATE * state)
1029 const char *prefix = _("Fingerprint: ");
1033 s = key->subkeys ? key->subkeys->fpr : NULL;
1036 is_pgp = (key->protocol == GPGME_PROTOCOL_OpenPGP);
1038 buf = xmalloc(m_strlen(prefix) + m_strlen(s) * 4 + 2);
1039 strcpy (buf, prefix); /* __STRCPY_CHECKED__ */
1040 p = buf + m_strlen(buf);
1041 if (is_pgp && m_strlen(s) == 40) { /* PGP v4 style formatted. */
1042 for (i = 0; *s && s[1] && s[2] && s[3] && s[4]; s += 4, i++) {
1053 for (i = 0; *s && s[1] && s[2]; s += 2, i++) {
1056 *p++ = is_pgp ? ' ' : ':';
1057 if (is_pgp && i == 7)
1062 /* just in case print remaining odd digits */
1067 state_attach_puts (buf, state);
1071 /* Show the valididy of a key used for one signature. */
1072 static void show_one_sig_validity (gpgme_ctx_t ctx, int idx, STATE * s)
1074 gpgme_verify_result_t result = NULL;
1075 gpgme_signature_t sig = NULL;
1076 const char *txt = NULL;
1078 result = gpgme_op_verify_result (ctx);
1080 for (sig = result->signatures; sig && (idx > 0); sig = sig->next, idx--);
1082 switch (sig ? sig->validity : 0) {
1083 case GPGME_VALIDITY_UNKNOWN:
1084 txt = _("WARNING: We have NO indication whether "
1085 "the key belongs to the person named " "as shown above\n");
1087 case GPGME_VALIDITY_UNDEFINED:
1089 case GPGME_VALIDITY_NEVER:
1090 txt = _("WARNING: The key does NOT BELONG to "
1091 "the person named as shown above\n");
1093 case GPGME_VALIDITY_MARGINAL:
1094 txt = _("WARNING: It is NOT certain that the key "
1095 "belongs to the person named as shown above\n");
1097 case GPGME_VALIDITY_FULL:
1098 case GPGME_VALIDITY_ULTIMATE:
1103 state_attach_puts (txt, s);
1106 /* Show information about one signature. This fucntion is called with
1107 the context CTX of a sucessful verification operation and the
1108 enumerator IDX which should start at 0 and incremete for each
1111 Return values are: 0 for normal procession, 1 for a bad signature,
1112 2 for a signature with a warning or -1 for no more signature. */
1113 static int show_one_sig_status (gpgme_ctx_t ctx, int idx, STATE * s)
1116 const char *fpr, *uid;
1117 gpgme_key_t key = NULL;
1118 int i, anybad = 0, anywarn = 0;
1120 gpgme_user_id_t uids = NULL;
1121 gpgme_verify_result_t result;
1122 gpgme_signature_t sig;
1123 gpgme_error_t err = GPG_ERR_NO_ERROR;
1125 result = gpgme_op_verify_result (ctx);
1127 /* FIXME: this code should use a static variable and remember
1128 the current position in the list of signatures, IMHO.
1131 for (i = 0, sig = result->signatures; sig && (i < idx);
1132 i++, sig = sig->next);
1134 return -1; /* Signature not found. */
1136 if (signature_key) {
1137 gpgme_key_release (signature_key);
1138 signature_key = NULL;
1141 created = sig->timestamp;
1145 if (gpg_err_code (sig->status) != GPG_ERR_NO_ERROR)
1148 err = gpgme_get_key (ctx, fpr, &key, 0); /* secret key? */
1150 uid = (key->uids && key->uids->uid) ? key->uids->uid : "[?]";
1152 signature_key = key;
1155 key = NULL; /* Old gpgme versions did not set KEY to NULL on
1156 error. Do it here to avoid a double free. */
1160 if (!s || !s->fpout || !(s->flags & M_DISPLAY)); /* No state information so no way to print anything. */
1162 state_attach_puts (_("Error getting key information: "), s);
1163 state_attach_puts (gpg_strerror (err), s);
1164 state_attach_puts ("\n", s);
1167 else if ((sum & GPGME_SIGSUM_GREEN)) {
1168 state_attach_puts (_("Good signature from: "), s);
1169 state_attach_puts (uid, s);
1170 state_attach_puts ("\n", s);
1171 for (i = 1, uids = key->uids; uids; i++, uids = uids->next) {
1173 /* Skip primary UID. */
1177 state_attach_puts (_(" aka: "), s);
1178 state_attach_puts (uids->uid, s);
1179 state_attach_puts ("\n", s);
1181 state_attach_puts (_(" created: "), s);
1182 print_time (created, s);
1183 state_attach_puts ("\n", s);
1184 if (show_sig_summary (sum, ctx, key, idx, s))
1186 show_one_sig_validity (ctx, idx, s);
1188 else if ((sum & GPGME_SIGSUM_RED)) {
1189 state_attach_puts (_("*BAD* signature claimed to be from: "), s);
1190 state_attach_puts (uid, s);
1191 state_attach_puts ("\n", s);
1192 show_sig_summary (sum, ctx, key, idx, s);
1194 else if (!anybad && key && (key->protocol == GPGME_PROTOCOL_OpenPGP)) { /* We can't decide (yellow) but this is a PGP key with a good
1195 signature, so we display what a PGP user expects: The name,
1196 fingerprint and the key validity (which is neither fully or
1198 state_attach_puts (_("Good signature from: "), s);
1199 state_attach_puts (uid, s);
1200 state_attach_puts ("\n", s);
1201 state_attach_puts (_(" created: "), s);
1202 print_time (created, s);
1203 state_attach_puts ("\n", s);
1204 show_one_sig_validity (ctx, idx, s);
1205 show_fingerprint (key, s);
1206 if (show_sig_summary (sum, ctx, key, idx, s))
1209 else { /* can't decide (yellow) */
1211 state_attach_puts (_("Error checking signature"), s);
1212 state_attach_puts ("\n", s);
1213 show_sig_summary (sum, ctx, key, idx, s);
1216 if (key != signature_key)
1217 gpgme_key_release (key);
1220 return anybad ? 1 : anywarn ? 2 : 0;
1223 /* Do the actual verification step. With IS_SMIME set to true we
1224 assume S/MIME (surprise!) */
1225 static int verify_one (BODY * sigbdy, STATE * s,
1226 const char *tempfile, int is_smime)
1232 gpgme_data_t signature, message;
1234 signature = file_to_data_object (s->fpin, sigbdy->offset, sigbdy->length);
1238 /* We need to tell gpgme about the encoding because the backend can't
1239 auto-detect plain base-64 encoding which is used by S/MIME. */
1241 gpgme_data_set_encoding (signature, GPGME_DATA_ENCODING_BASE64);
1243 err = gpgme_data_new_from_file (&message, tempfile, 1);
1245 gpgme_data_release (signature);
1246 mutt_error (_("error allocating data object: %s\n"), gpgme_strerror (err));
1249 ctx = create_gpgme_context (is_smime);
1251 /* Note: We don't need a current time output because GPGME avoids
1252 such an attack by separating the meta information from the
1254 state_attach_puts (_("[-- Begin signature information --]\n"), s);
1256 err = gpgme_op_verify (ctx, signature, message, NULL);
1257 mutt_need_hard_redraw ();
1261 snprintf (buf, sizeof (buf) - 1,
1262 _("Error: verification failed: %s\n"), gpgme_strerror (err));
1263 state_attach_puts (buf, s);
1265 else { /* Verification succeeded, see what the result is. */
1269 if (signature_key) {
1270 gpgme_key_release (signature_key);
1271 signature_key = NULL;
1274 for (idx = 0; (res = show_one_sig_status (ctx, idx, s)) != -1; idx++) {
1285 gpgme_verify_result_t result;
1286 gpgme_sig_notation_t notation;
1287 gpgme_signature_t signature;
1289 result = gpgme_op_verify_result (ctx);
1291 for (signature = result->signatures; signature;
1292 signature = signature->next) {
1293 if (signature->notations) {
1294 state_attach_puts ("*** Begin Notation (signature by: ", s);
1295 state_attach_puts (signature->fpr, s);
1296 state_attach_puts (") ***\n", s);
1297 for (notation = signature->notations; notation;
1298 notation = notation->next) {
1299 if (notation->name) {
1300 state_attach_puts (notation->name, s);
1301 state_attach_puts ("=", s);
1303 if (notation->value) {
1304 state_attach_puts (notation->value, s);
1305 if (!(*notation->value
1306 && (notation->value[m_strlen(notation->value) - 1] ==
1308 state_attach_puts ("\n", s);
1311 state_attach_puts ("*** End Notation ***\n", s);
1317 gpgme_release (ctx);
1319 state_attach_puts (_("[-- End signature information --]\n\n"), s);
1320 debug_print (1, ("returning %d.\n", badsig));
1322 return badsig ? 1 : anywarn ? 2 : 0;
1325 int pgp_gpgme_verify_one (BODY * sigbdy, STATE * s, const char *tempfile)
1327 return verify_one (sigbdy, s, tempfile, 0);
1330 int smime_gpgme_verify_one (BODY * sigbdy, STATE * s, const char *tempfile)
1332 return verify_one (sigbdy, s, tempfile, 1);
1336 * Implementation of `decrypt_part'.
1339 /* Decrypt a PGP or SMIME message (depending on the boolean flag
1340 IS_SMIME) with body A described further by state S. Write
1341 plaintext out to file FPOUT and return a new body. For PGP returns
1342 a flag in R_IS_SIGNED to indicate whether this is a combined
1343 encrypted and signed message, for S/MIME it returns true when it is
1344 not a encrypted but a signed message. */
1345 static BODY *decrypt_part (BODY * a, STATE * s, FILE * fpout, int is_smime,
1352 gpgme_data_t ciphertext, plaintext;
1353 int maybe_signed = 0;
1360 ctx = create_gpgme_context (is_smime);
1363 /* Make a data object from the body, create context etc. */
1364 ciphertext = file_to_data_object (s->fpin, a->offset, a->length);
1367 plaintext = create_gpgme_data ();
1369 /* Do the decryption or the verification in case of the S/MIME hack. */
1370 if ((!is_smime) || maybe_signed) {
1372 err = gpgme_op_decrypt_verify (ctx, ciphertext, plaintext);
1373 else if (maybe_signed)
1374 err = gpgme_op_verify (ctx, ciphertext, NULL, plaintext);
1377 /* Check wether signatures have been verified. */
1378 gpgme_verify_result_t verify_result = gpgme_op_verify_result (ctx);
1380 if (verify_result->signatures)
1385 err = gpgme_op_decrypt (ctx, ciphertext, plaintext);
1386 gpgme_data_release (ciphertext);
1388 if (is_smime && !maybe_signed && gpg_err_code (err) == GPG_ERR_NO_DATA) {
1389 /* Check whether this might be a signed message despite what
1390 the mime header told us. Retry then. gpgsm returns the
1391 error information "unsupported Algorithm '?'" but gpgme
1392 will not store this unknown algorithm, thus we test that
1393 it has not been set. */
1394 gpgme_decrypt_result_t result;
1396 result = gpgme_op_decrypt_result (ctx);
1397 if (!result->unsupported_algorithm) {
1399 gpgme_data_release (plaintext);
1403 mutt_need_hard_redraw ();
1404 if ((s->flags & M_DISPLAY)) {
1407 snprintf (buf, sizeof (buf) - 1,
1408 _("[-- Error: decryption failed: %s --]\n\n"),
1409 gpgme_strerror (err));
1410 state_attach_puts (buf, s);
1412 gpgme_data_release (plaintext);
1413 gpgme_release (ctx);
1416 mutt_need_hard_redraw ();
1418 /* Read the output from GPGME, and make sure to change CRLF to LF,
1419 otherwise read_mime_header has a hard time parsing the message. */
1420 if (data_object_to_stream (plaintext, fpout)) {
1421 gpgme_data_release (plaintext);
1422 gpgme_release (ctx);
1425 gpgme_data_release (plaintext);
1427 a->is_signed_data = 0;
1433 a->is_signed_data = 1;
1435 *r_is_signed = -1; /* A signature exists. */
1437 if ((s->flags & M_DISPLAY))
1438 state_attach_puts (_("[-- Begin signature " "information --]\n"), s);
1439 for (idx = 0; (res = show_one_sig_status (ctx, idx, s)) != -1; idx++) {
1445 if (!anybad && idx && r_is_signed && *r_is_signed)
1446 *r_is_signed = anywarn ? 2 : 1; /* Good signature. */
1448 if ((s->flags & M_DISPLAY))
1449 state_attach_puts (_("[-- End signature " "information --]\n\n"), s);
1451 gpgme_release (ctx);
1456 tattach = mutt_read_mime_header (fpout, 0);
1459 * Need to set the length of this body part.
1461 fstat (fileno (fpout), &info);
1462 tattach->length = info.st_size - tattach->offset;
1464 tattach->warnsig = anywarn;
1466 /* See if we need to recurse on this MIME part. */
1467 mutt_parse_part (fpout, tattach);
1473 /* Decrypt a PGP/MIME message in FPIN and B and return a new body and
1474 the stream in CUR and FPOUT. Returns 0 on success. */
1475 int pgp_gpgme_decrypt_mime (FILE * fpin, FILE ** fpout, BODY * b, BODY ** cur)
1477 char tempfile[_POSIX_PATH_MAX];
1479 BODY *first_part = b;
1482 first_part->goodsig = 0;
1483 first_part->warnsig = 0;
1485 if (!mutt_is_multipart_encrypted (b))
1488 if (!b->parts || !b->parts->next)
1495 mutt_mktemp (tempfile);
1496 if (!(*fpout = safe_fopen (tempfile, "w+"))) {
1497 mutt_perror (tempfile);
1502 *cur = decrypt_part (b, &s, *fpout, 0, &is_signed);
1505 first_part->goodsig = 1;
1507 return *cur ? 0 : -1;
1511 /* Decrypt a S/MIME message in FPIN and B and return a new body and
1512 the stream in CUR and FPOUT. Returns 0 on success. */
1513 int smime_gpgme_decrypt_mime (FILE * fpin, FILE ** fpout, BODY * b,
1516 char tempfile[_POSIX_PATH_MAX];
1520 long saved_b_offset;
1521 size_t saved_b_length;
1524 if (!mutt_is_application_smime (b))
1530 /* Decode the body - we need to pass binary CMS to the
1531 backend. The backend allows for Base64 encoded data but it does
1532 not allow for QP which I have seen in some messages. So better
1534 saved_b_type = b->type;
1535 saved_b_offset = b->offset;
1536 saved_b_length = b->length;
1539 fseeko (s.fpin, b->offset, 0);
1540 mutt_mktemp (tempfile);
1541 if (!(tmpfp = safe_fopen (tempfile, "w+"))) {
1542 mutt_perror (tempfile);
1545 mutt_unlink (tempfile);
1548 mutt_decode_attachment (b, &s);
1550 b->length = ftello (s.fpout);
1557 mutt_mktemp (tempfile);
1558 if (!(*fpout = safe_fopen (tempfile, "w+"))) {
1559 mutt_perror (tempfile);
1562 mutt_unlink (tempfile);
1564 *cur = decrypt_part (b, &s, *fpout, 1, &is_signed);
1566 (*cur)->goodsig = is_signed > 0;
1567 b->type = saved_b_type;
1568 b->length = saved_b_length;
1569 b->offset = saved_b_offset;
1572 if (*cur && !is_signed && !(*cur)->parts
1573 && mutt_is_application_smime (*cur)) {
1574 /* Assume that this is a opaque signed s/mime message. This is
1575 an ugly way of doing it but we have anyway a problem with
1576 arbitrary encoded S/MIME messages: Only the outer part may be
1577 encrypted. The entire mime parsing should be revamped,
1578 probably by keeping the temportary files so that we don't
1579 need to decrypt them all the time. Inner parts of an
1580 encrypted part can then pint into this file and tehre won't
1581 never be a need to decrypt again. This needs a partial
1582 rewrite of the MIME engine. */
1586 saved_b_type = bb->type;
1587 saved_b_offset = bb->offset;
1588 saved_b_length = bb->length;
1591 fseeko (s.fpin, bb->offset, 0);
1592 mutt_mktemp (tempfile);
1593 if (!(tmpfp = safe_fopen (tempfile, "w+"))) {
1594 mutt_perror (tempfile);
1597 mutt_unlink (tempfile);
1600 mutt_decode_attachment (bb, &s);
1602 bb->length = ftello (s.fpout);
1610 mutt_mktemp (tempfile);
1611 if (!(*fpout = safe_fopen (tempfile, "w+"))) {
1612 mutt_perror (tempfile);
1615 mutt_unlink (tempfile);
1617 tmp_b = decrypt_part (bb, &s, *fpout, 1, &is_signed);
1619 tmp_b->goodsig = is_signed > 0;
1620 bb->type = saved_b_type;
1621 bb->length = saved_b_length;
1622 bb->offset = saved_b_offset;
1625 mutt_free_body (cur);
1628 return *cur ? 0 : -1;
1633 * Implementation of `pgp_check_traditional'.
1636 static int pgp_check_traditional_one_body (FILE * fp, BODY * b,
1639 char tempfile[_POSIX_PATH_MAX];
1640 char buf[HUGE_STRING];
1646 if (b->type != TYPETEXT)
1649 if (tagged_only && !b->tagged)
1652 mutt_mktemp (tempfile);
1653 if (mutt_decode_save_attachment (fp, b, tempfile, 0, 0) != 0) {
1658 if ((tfp = fopen (tempfile, "r")) == NULL) {
1663 while (fgets (buf, sizeof (buf), tfp)) {
1664 if (!m_strncmp("-----BEGIN PGP ", buf, 15)) {
1665 if (!m_strcmp("MESSAGE-----\n", buf + 15))
1667 else if (!m_strcmp("SIGNED MESSAGE-----\n", buf + 15))
1677 /* fix the content type */
1679 mutt_set_parameter ("format", "fixed", &b->parameter);
1680 mutt_set_parameter ("x-action", enc ? "pgp-encrypted" : "pgp-signed",
1686 int pgp_gpgme_check_traditional (FILE * fp, BODY * b, int tagged_only)
1691 for (; b; b = b->next) {
1692 if (is_multipart (b))
1693 rv = (pgp_gpgme_check_traditional (fp, b->parts, tagged_only) || rv);
1694 else if (b->type == TYPETEXT) {
1695 if ((r = mutt_is_application_pgp (b)))
1698 rv = (pgp_check_traditional_one_body (fp, b, tagged_only) || rv);
1706 * Implementation of `application_handler'.
1710 Copy a clearsigned message, and strip the signature and PGP's
1713 XXX - charset handling: We assume that it is safe to do
1714 character set decoding first, dash decoding second here, while
1715 we do it the other way around in the main handler.
1717 (Note that we aren't worse than Outlook & Cie in this, and also
1718 note that we can successfully handle anything produced by any
1719 existing versions of mutt.) */
1721 static void copy_clearsigned (gpgme_data_t data, STATE * s, char *charset)
1723 char buf[HUGE_STRING];
1724 short complete, armor_header;
1729 fname = data_object_to_tempfile (data, &fp);
1735 fc = fgetconv_open (fp, charset, Charset, M_ICONV_HOOK_FROM);
1737 for (complete = 1, armor_header = 1;
1738 fgetconvs (buf, sizeof (buf), fc) != NULL;
1739 complete = strchr (buf, '\n') != NULL) {
1742 state_puts (buf, s);
1746 if (!m_strcmp(buf, "-----BEGIN PGP SIGNATURE-----\n"))
1756 state_puts (s->prefix, s);
1758 if (buf[0] == '-' && buf[1] == ' ')
1759 state_puts (buf + 2, s);
1761 state_puts (buf, s);
1764 fgetconv_close (&fc);
1769 /* Support for classic_application/pgp */
1770 int pgp_gpgme_application_handler (BODY * m, STATE * s)
1772 int needpass = -1, pgp_keyblock = 0;
1776 off_t last_pos, offset;
1777 char buf[HUGE_STRING];
1778 FILE *pgpout = NULL;
1780 gpgme_error_t err = 0;
1781 gpgme_data_t armored_data = NULL;
1783 short maybe_goodsig = 1;
1784 short have_any_sigs = 0;
1786 char body_charset[STRING]; /* Only used for clearsigned messages. */
1788 debug_print (2, ("Entering pgp_application_pgp handler\n"));
1790 /* For clearsigned messages we won't be able to get a character set
1791 but we know that this may only be text thus we assume Latin-1
1793 if (!mutt_get_body_charset (body_charset, sizeof (body_charset), m))
1794 m_strcpy(body_charset, sizeof(body_charset), "iso-8859-1");
1796 fseeko (s->fpin, m->offset, 0);
1797 last_pos = m->offset;
1799 for (bytes = m->length; bytes > 0;) {
1800 if (fgets (buf, sizeof (buf), s->fpin) == NULL)
1803 offset = ftello (s->fpin);
1804 bytes -= (offset - last_pos); /* don't rely on m_strlen(buf) */
1807 if (!m_strncmp("-----BEGIN PGP ", buf, 15)) {
1809 start_pos = last_pos;
1811 if (!m_strcmp("MESSAGE-----\n", buf + 15))
1813 else if (!m_strcmp("SIGNED MESSAGE-----\n", buf + 15)) {
1817 else if (!option (OPTDONTHANDLEPGPKEYS) &&
1818 !m_strcmp("PUBLIC KEY BLOCK-----\n", buf + 15)) {
1823 /* XXX - we may wish to recode here */
1825 state_puts (s->prefix, s);
1826 state_puts (buf, s);
1830 have_any_sigs = (have_any_sigs || (clearsign && (s->flags & M_VERIFY)));
1832 /* Copy PGP material to an data container */
1833 armored_data = create_gpgme_data ();
1834 gpgme_data_write (armored_data, buf, m_strlen(buf));
1835 while (bytes > 0 && fgets (buf, sizeof (buf) - 1, s->fpin) != NULL) {
1836 offset = ftello (s->fpin);
1837 bytes -= (offset - last_pos); /* don't rely on m_strlen(buf) */
1840 gpgme_data_write (armored_data, buf, m_strlen(buf));
1842 if ((needpass && !m_strcmp("-----END PGP MESSAGE-----\n", buf))
1844 && (!m_strcmp("-----END PGP SIGNATURE-----\n", buf)
1845 || !m_strcmp("-----END PGP PUBLIC KEY BLOCK-----\n",
1850 /* Invoke PGP if needed */
1851 if (!clearsign || (s->flags & M_VERIFY)) {
1852 unsigned int sig_stat = 0;
1853 gpgme_data_t plaintext;
1856 plaintext = create_gpgme_data ();
1857 ctx = create_gpgme_context (0);
1860 err = gpgme_op_verify (ctx, armored_data, NULL, plaintext);
1862 err = gpgme_op_decrypt_verify (ctx, armored_data, plaintext);
1863 if (gpg_err_code (err) == GPG_ERR_NO_DATA) {
1864 /* Decrypt verify can't handle signed only messages. */
1865 err = (gpgme_data_seek (armored_data, 0, SEEK_SET) == -1)
1866 ? gpgme_error_from_errno (errno) : 0;
1867 /* Must release plaintext so that we supply an
1868 uninitialized object. */
1869 gpgme_data_release (plaintext);
1870 plaintext = create_gpgme_data ();
1871 err = gpgme_op_verify (ctx, armored_data, NULL, plaintext);
1878 snprintf (errbuf, sizeof (errbuf) - 1,
1879 _("Error: decryption/verification failed: %s\n"),
1880 gpgme_strerror (err));
1881 state_attach_puts (errbuf, s);
1883 else { /* Decryption/Verification succeeded */
1887 /* Check wether signatures have been verified. */
1888 gpgme_verify_result_t verify_result;
1890 verify_result = gpgme_op_verify_result (ctx);
1891 if (verify_result->signatures)
1897 if ((s->flags & M_DISPLAY) && sig_stat) {
1902 state_attach_puts (_("[-- Begin signature "
1903 "information --]\n"), s);
1906 (res = show_one_sig_status (ctx, idx, s)) != -1; idx++) {
1915 state_attach_puts (_("[-- End signature "
1916 "information --]\n\n"), s);
1919 tmpfname = data_object_to_tempfile (plaintext, &pgpout);
1922 state_attach_puts (_("Error: copy data failed\n"), s);
1926 p_delete(&tmpfname);
1929 gpgme_release (ctx);
1933 * Now, copy cleartext to the screen. NOTE - we expect that PGP
1934 * outputs utf-8 cleartext. This may not always be true, but it
1935 * seems to be a reasonable guess.
1938 if (s->flags & M_DISPLAY) {
1940 state_attach_puts (_("[-- BEGIN PGP MESSAGE --]\n\n"), s);
1941 else if (pgp_keyblock)
1942 state_attach_puts (_("[-- BEGIN PGP PUBLIC KEY BLOCK --]\n"), s);
1944 state_attach_puts (_("[-- BEGIN PGP SIGNED MESSAGE --]\n\n"), s);
1948 copy_clearsigned (armored_data, s, body_charset);
1955 fc = fgetconv_open (pgpout, "utf-8", Charset, 0);
1956 while ((c = fgetconv (fc)) != EOF) {
1958 if (c == '\n' && s->prefix)
1959 state_puts (s->prefix, s);
1961 fgetconv_close (&fc);
1964 if (s->flags & M_DISPLAY) {
1965 state_putc ('\n', s);
1967 state_attach_puts (_("[-- END PGP MESSAGE --]\n"), s);
1968 else if (pgp_keyblock)
1969 state_attach_puts (_("[-- END PGP PUBLIC KEY BLOCK --]\n"), s);
1971 state_attach_puts (_("[-- END PGP SIGNED MESSAGE --]\n"), s);
1975 safe_fclose (&pgpout);
1979 /* XXX - we may wish to recode here */
1981 state_puts (s->prefix, s);
1982 state_puts (buf, s);
1986 m->goodsig = (maybe_goodsig && have_any_sigs);
1988 if (needpass == -1) {
1989 state_attach_puts (_("[-- Error: could not find beginning"
1990 " of PGP message! --]\n\n"), s);
1993 debug_print (2, ("Leaving pgp_application_pgp handler\n"));
1998 * Implementation of `encrypted_handler'.
2001 /* MIME handler for pgp/mime encrypted messages. */
2002 int pgp_gpgme_encrypted_handler (BODY * a, STATE * s)
2004 char tempfile[_POSIX_PATH_MAX];
2007 BODY *orig_body = a;
2011 debug_print (2, ("Entering pgp_encrypted handler\n"));
2013 if (!a || a->type != TYPEAPPLICATION || !a->subtype
2014 || ascii_strcasecmp ("pgp-encrypted", a->subtype)
2015 || !a->next || a->next->type != TYPEAPPLICATION || !a->next->subtype
2016 || ascii_strcasecmp ("octet-stream", a->next->subtype)) {
2017 if (s->flags & M_DISPLAY)
2018 state_attach_puts (_("[-- Error: malformed PGP/MIME message! --]\n\n"),
2023 /* Move forward to the application/pgp-encrypted body. */
2026 mutt_mktemp (tempfile);
2027 if (!(fpout = safe_fopen (tempfile, "w+"))) {
2028 if (s->flags & M_DISPLAY)
2029 state_attach_puts (_("[-- Error: could not create temporary file! "
2034 tattach = decrypt_part (a, s, fpout, 0, &is_signed);
2036 tattach->goodsig = is_signed > 0;
2038 if (s->flags & M_DISPLAY)
2039 state_attach_puts (is_signed ?
2041 ("[-- The following data is PGP/MIME signed and encrypted --]\n\n") :
2042 _("[-- The following data is PGP/MIME encrypted --]\n\n"), s);
2045 FILE *savefp = s->fpin;
2048 rc = mutt_body_handler (tattach, s);
2053 * if a multipart/signed is the _only_ sub-part of a
2054 * multipart/encrypted, cache signature verification
2057 if (mutt_is_multipart_signed (tattach) && !tattach->next)
2058 orig_body->goodsig |= tattach->goodsig;
2060 if (s->flags & M_DISPLAY) {
2061 state_puts ("\n", s);
2062 state_attach_puts (is_signed ?
2064 ("[-- End of PGP/MIME signed and encrypted data --]\n")
2065 : _("[-- End of PGP/MIME encrypted data --]\n"), s);
2068 mutt_free_body (&tattach);
2072 mutt_unlink (tempfile);
2073 debug_print (2, ("Leaving pgp_encrypted handler\n"));
2077 /* Support for application/smime */
2078 int smime_gpgme_application_handler (BODY * a, STATE * s)
2080 char tempfile[_POSIX_PATH_MAX];
2086 debug_print (2, ("Entering smime_encrypted handler\n"));
2089 mutt_mktemp (tempfile);
2090 if (!(fpout = safe_fopen (tempfile, "w+"))) {
2091 if (s->flags & M_DISPLAY)
2092 state_attach_puts (_("[-- Error: could not create temporary file! "
2097 tattach = decrypt_part (a, s, fpout, 1, &is_signed);
2099 tattach->goodsig = is_signed > 0;
2101 if (s->flags & M_DISPLAY)
2102 state_attach_puts (is_signed ?
2103 _("[-- The following data is S/MIME signed --]\n\n") :
2104 _("[-- The following data is S/MIME encrypted --]\n\n"), s);
2107 FILE *savefp = s->fpin;
2110 rc = mutt_body_handler (tattach, s);
2115 * if a multipart/signed is the _only_ sub-part of a
2116 * multipart/encrypted, cache signature verification
2119 if (mutt_is_multipart_signed (tattach) && !tattach->next) {
2120 if (!(a->goodsig = tattach->goodsig))
2121 a->warnsig = tattach->warnsig;
2123 else if (tattach->goodsig) {
2125 a->warnsig = tattach->warnsig;
2128 if (s->flags & M_DISPLAY) {
2129 state_puts ("\n", s);
2130 state_attach_puts (is_signed ?
2131 _("[-- End of S/MIME signed data --]\n") :
2132 _("[-- End of S/MIME encrypted data --]\n"), s);
2135 mutt_free_body (&tattach);
2139 mutt_unlink (tempfile);
2140 debug_print (2, ("Leaving smime_encrypted handler\n"));
2146 * Format an entry on the CRYPT key selection menu.
2149 * %k key id %K key id of the principal key
2151 * %a algorithm %A algorithm of the princ. key
2152 * %l length %L length of the princ. key
2153 * %f flags %F flags of the princ. key
2154 * %c capabilities %C capabilities of the princ. key
2155 * %t trust/validity of the key-uid association
2157 * %[...] date of key using strftime(3)
2160 static const char *crypt_entry_fmt (char *dest,
2165 const char *ifstring,
2166 const char *elsestring,
2167 unsigned long data, format_flag flags)
2170 crypt_entry_t *entry;
2173 int optional = (flags & M_FORMAT_OPTIONAL);
2174 const char *s = NULL;
2177 entry = (crypt_entry_t *) data;
2180 /* if (isupper ((unsigned char) op)) */
2183 kflags = (key->flags /*| (pkey->flags & KEYFLAG_RESTRICTIONS)
2186 switch (ascii_tolower (op)) {
2190 char buf2[SHORT_STRING], *p;
2206 while (len > 0 && *cp != ']') {
2215 break; /* not enough space */
2225 if (do_locales && Locale)
2226 setlocale (LC_TIME, Locale);
2231 if (key->kobj->subkeys && (key->kobj->subkeys->timestamp > 0))
2232 tt = key->kobj->subkeys->timestamp;
2234 tm = localtime (&tt);
2236 strftime (buf2, sizeof (buf2), dest, tm);
2239 setlocale (LC_TIME, "C");
2241 snprintf (fmt, sizeof (fmt), "%%%ss", prefix);
2242 snprintf (dest, destlen, fmt, buf2);
2249 snprintf (fmt, sizeof (fmt), "%%%sd", prefix);
2250 snprintf (dest, destlen, fmt, entry->num);
2255 /* fixme: we need a way to distinguish between main and subkeys.
2256 Store the idx in entry? */
2257 snprintf (fmt, sizeof (fmt), "%%%ss", prefix);
2258 snprintf (dest, destlen, fmt, crypt_keyid (key));
2263 snprintf (fmt, sizeof (fmt), "%%%ss", prefix);
2264 snprintf (dest, destlen, fmt, key->uid);
2269 snprintf (fmt, sizeof (fmt), "%%%s.3s", prefix);
2270 if (key->kobj->subkeys)
2271 s = gpgme_pubkey_algo_name (key->kobj->subkeys->pubkey_algo);
2274 snprintf (dest, destlen, fmt, s);
2279 snprintf (fmt, sizeof (fmt), "%%%slu", prefix);
2280 if (key->kobj->subkeys)
2281 val = key->kobj->subkeys->length;
2284 snprintf (dest, destlen, fmt, val);
2289 snprintf (fmt, sizeof (fmt), "%%%sc", prefix);
2290 snprintf (dest, destlen, fmt, crypt_flags (kflags));
2292 else if (!(kflags & (KEYFLAG_RESTRICTIONS)))
2297 snprintf (fmt, sizeof (fmt), "%%%ss", prefix);
2298 snprintf (dest, destlen, fmt, crypt_key_abilities (kflags));
2300 else if (!(kflags & (KEYFLAG_ABILITIES)))
2304 if ((kflags & KEYFLAG_ISX509))
2307 gpgme_user_id_t uid = NULL;
2310 for (i = 0, uid = key->kobj->uids; uid && (i < key->idx);
2311 i++, uid = uid->next);
2313 switch (uid->validity) {
2314 case GPGME_VALIDITY_UNDEFINED:
2317 case GPGME_VALIDITY_NEVER:
2320 case GPGME_VALIDITY_MARGINAL:
2323 case GPGME_VALIDITY_FULL:
2326 case GPGME_VALIDITY_ULTIMATE:
2329 case GPGME_VALIDITY_UNKNOWN:
2335 snprintf (fmt, sizeof (fmt), "%%%sc", prefix);
2336 snprintf (dest, destlen, fmt, s ? *s : 'B');
2339 snprintf (fmt, sizeof (fmt), "%%%ss", prefix);
2340 snprintf (dest, destlen, fmt,
2341 gpgme_get_protocol_name (key->kobj->protocol));
2349 mutt_FormatString (dest, destlen, ifstring, mutt_attach_fmt, data, 0);
2350 else if (flags & M_FORMAT_OPTIONAL)
2351 mutt_FormatString (dest, destlen, elsestring, mutt_attach_fmt, data, 0);
2355 /* Used by the display fucntion to format a line. */
2356 static void crypt_entry (char *s, size_t l, MUTTMENU * menu, int num)
2358 crypt_key_t **key_table = (crypt_key_t **) menu->data;
2359 crypt_entry_t entry;
2361 entry.key = key_table[num];
2362 entry.num = num + 1;
2364 mutt_FormatString (s, l, NONULL (PgpEntryFormat), crypt_entry_fmt,
2365 (unsigned long) &entry, M_FORMAT_ARROWCURSOR);
2368 /* Compare two addresses and the keyid to be used for sorting. */
2369 static int _crypt_compare_address (const void *a, const void *b)
2371 crypt_key_t **s = (crypt_key_t **) a;
2372 crypt_key_t **t = (crypt_key_t **) b;
2375 if ((r = m_strcasecmp((*s)->uid, (*t)->uid)))
2378 return m_strcasecmp(crypt_keyid (*s), crypt_keyid (*t)) > 0;
2381 static int crypt_compare_address (const void *a, const void *b)
2383 return ((PgpSortKeys & SORT_REVERSE) ? !_crypt_compare_address (a, b)
2384 : _crypt_compare_address (a, b));
2388 /* Compare two key IDs and the addresses to be used for sorting. */
2389 static int _crypt_compare_keyid (const void *a, const void *b)
2391 crypt_key_t **s = (crypt_key_t **) a;
2392 crypt_key_t **t = (crypt_key_t **) b;
2395 if ((r = m_strcasecmp(crypt_keyid (*s), crypt_keyid (*t))))
2398 return m_strcasecmp((*s)->uid, (*t)->uid) > 0;
2401 static int crypt_compare_keyid (const void *a, const void *b)
2403 return ((PgpSortKeys & SORT_REVERSE) ? !_crypt_compare_keyid (a, b)
2404 : _crypt_compare_keyid (a, b));
2407 /* Compare 2 creation dates and the addresses. For sorting. */
2408 static int _crypt_compare_date (const void *a, const void *b)
2410 crypt_key_t **s = (crypt_key_t **) a;
2411 crypt_key_t **t = (crypt_key_t **) b;
2412 unsigned long ts = 0, tt = 0;
2414 if ((*s)->kobj->subkeys && ((*s)->kobj->subkeys->timestamp > 0))
2415 ts = (*s)->kobj->subkeys->timestamp;
2416 if ((*t)->kobj->subkeys && ((*t)->kobj->subkeys->timestamp > 0))
2417 tt = (*t)->kobj->subkeys->timestamp;
2424 return m_strcasecmp((*s)->uid, (*t)->uid) > 0;
2427 static int crypt_compare_date (const void *a, const void *b)
2429 return ((PgpSortKeys & SORT_REVERSE) ? !_crypt_compare_date (a, b)
2430 : _crypt_compare_date (a, b));
2433 /* Compare two trust values, the key length, the creation dates. the
2434 addresses and the key IDs. For sorting. */
2435 static int _crypt_compare_trust (const void *a, const void *b)
2437 crypt_key_t **s = (crypt_key_t **) a;
2438 crypt_key_t **t = (crypt_key_t **) b;
2439 unsigned long ts = 0, tt = 0;
2442 if ((r = (((*s)->flags & (KEYFLAG_RESTRICTIONS))
2443 - ((*t)->flags & (KEYFLAG_RESTRICTIONS)))))
2446 if ((*s)->kobj->uids)
2447 ts = (*s)->kobj->uids->validity;
2448 if ((*t)->kobj->uids)
2449 tt = (*t)->kobj->uids->validity;
2450 if ((r = (tt - ts)))
2453 if ((*s)->kobj->subkeys)
2454 ts = (*s)->kobj->subkeys->length;
2455 if ((*t)->kobj->subkeys)
2456 tt = (*t)->kobj->subkeys->length;
2460 if ((*s)->kobj->subkeys && ((*s)->kobj->subkeys->timestamp > 0))
2461 ts = (*s)->kobj->subkeys->timestamp;
2462 if ((*t)->kobj->subkeys && ((*t)->kobj->subkeys->timestamp > 0))
2463 tt = (*t)->kobj->subkeys->timestamp;
2469 if ((r = m_strcasecmp((*s)->uid, (*t)->uid)))
2471 return (m_strcasecmp(crypt_keyid ((*s)), crypt_keyid ((*t)))) > 0;
2474 static int crypt_compare_trust (const void *a, const void *b)
2476 return ((PgpSortKeys & SORT_REVERSE) ? !_crypt_compare_trust (a, b)
2477 : _crypt_compare_trust (a, b));
2480 /* Print the X.500 Distinguished Name part KEY from the array of parts
2482 static int print_dn_part (FILE * fp, struct dn_array_s *dn, const char *key)
2486 for (; dn->key; dn++) {
2487 if (!m_strcmp(dn->key, key)) {
2490 print_utf8 (fp, dn->value, m_strlen(dn->value));
2497 /* Print all parts of a DN in a standard sequence. */
2498 static void print_dn_parts (FILE * fp, struct dn_array_s *dn)
2500 const char *stdpart[] = {
2501 "CN", "OU", "O", "STREET", "L", "ST", "C", NULL
2503 int any = 0, any2 = 0, i;
2505 for (i = 0; stdpart[i]; i++) {
2508 any = print_dn_part (fp, dn, stdpart[i]);
2510 /* now print the rest without any specific ordering */
2511 for (; dn->key; dn++) {
2512 for (i = 0; stdpart[i]; i++) {
2513 if (!m_strcmp(dn->key, stdpart[i]))
2521 any = print_dn_part (fp, dn, dn->key);
2530 /* Parse an RDN; this is a helper to parse_dn(). */
2531 static const unsigned char *parse_dn_part (struct dn_array_s *array,
2532 const unsigned char *string)
2534 const unsigned char *s, *s1;
2538 /* parse attributeType */
2539 for (s = string + 1; *s && *s != '='; s++);
2541 return NULL; /* error */
2544 return NULL; /* empty key */
2545 array->key = p_dupstr(string, n );
2546 p = (unsigned char *) array->key;
2549 if (*string == '#') { /* hexstring */
2551 for (s = string; hexdigitp (s); s++)
2555 return NULL; /* empty or odd number of digits */
2558 array->value = (char *) p;
2559 for (s1 = string; n; s1 += 2, n--)
2563 else { /* regular v3 quoted string */
2564 for (n = 0, s = string; *s; s++) {
2565 if (*s == '\\') { /* pair */
2567 if (*s == ',' || *s == '=' || *s == '+'
2568 || *s == '<' || *s == '>' || *s == '#' || *s == ';'
2569 || *s == '\\' || *s == '\"' || *s == ' ')
2571 else if (hexdigitp (s) && hexdigitp (s + 1)) {
2576 return NULL; /* invalid escape sequence */
2578 else if (*s == '\"')
2579 return NULL; /* invalid encoding */
2580 else if (*s == ',' || *s == '=' || *s == '+'
2581 || *s == '<' || *s == '>' || *s == '#' || *s == ';')
2588 array->value = (char *) p;
2589 for (s = string; n; s++, n--) {
2592 if (hexdigitp (s)) {
2608 /* Parse a DN and return an array-ized one. This is not a validating
2609 parser and it does not support any old-stylish syntax; gpgme is
2610 expected to return only rfc2253 compatible strings. */
2611 static struct dn_array_s *parse_dn (const unsigned char *string)
2613 struct dn_array_s *array;
2614 size_t arrayidx, arraysize;
2617 arraysize = 7; /* C,ST,L,O,OU,CN,email */
2618 array = p_new(struct dn_array_s, arraysize + 1);
2621 while (*string == ' ')
2625 if (arrayidx >= arraysize) { /* mutt lacks a real safe_realoc - so we need to copy */
2626 struct dn_array_s *a2;
2629 a2 = p_new(struct dn_array_s, arraysize + 1);
2630 for (i = 0; i < arrayidx; i++) {
2631 a2[i].key = array[i].key;
2632 a2[i].value = array[i].value;
2637 array[arrayidx].key = NULL;
2638 array[arrayidx].value = NULL;
2639 string = parse_dn_part (array + arrayidx, string);
2643 while (*string == ' ')
2645 if (*string && *string != ',' && *string != ';' && *string != '+')
2646 goto failure; /* invalid delimiter */
2650 array[arrayidx].key = NULL;
2651 array[arrayidx].value = NULL;
2655 for (i = 0; i < arrayidx; i++) {
2656 p_delete(&array[i].key);
2657 p_delete(&array[i].value);
2664 /* Print a nice representation of the USERID and make sure it is
2665 displayed in a proper way, which does mean to reorder some parts
2666 for S/MIME's DNs. USERID is a string as returned by the gpgme key
2667 functions. It is utf-8 encoded. */
2668 static void parse_and_print_user_id (FILE * fp, const char *userid)
2673 if (*userid == '<') {
2674 s = strchr (userid + 1, '>');
2676 print_utf8 (fp, userid + 1, s - userid - 1);
2678 else if (*userid == '(')
2679 fputs (_("[Can't display this user ID (unknown encoding)]"), fp);
2680 else if (!digit_or_letter ((const unsigned char *) userid))
2681 fputs (_("[Can't display this user ID (invalid encoding)]"), fp);
2683 struct dn_array_s *dn = parse_dn ((const unsigned char *) userid);
2686 fputs (_("[Can't display this user ID (invalid DN)]"), fp);
2688 print_dn_parts (fp, dn);
2689 for (i = 0; dn[i].key; i++) {
2690 p_delete(&dn[i].key);
2691 p_delete(&dn[i].value);
2699 KEY_CAP_CAN_ENCRYPT,
2704 static unsigned int key_check_cap (gpgme_key_t key, key_cap_t cap)
2706 gpgme_subkey_t subkey = NULL;
2707 unsigned int ret = 0;
2710 case KEY_CAP_CAN_ENCRYPT:
2711 if (!(ret = key->can_encrypt))
2712 for (subkey = key->subkeys; subkey; subkey = subkey->next)
2713 if ((ret = subkey->can_encrypt))
2716 case KEY_CAP_CAN_SIGN:
2717 if (!(ret = key->can_sign))
2718 for (subkey = key->subkeys; subkey; subkey = subkey->next)
2719 if ((ret = subkey->can_sign))
2722 case KEY_CAP_CAN_CERTIFY:
2723 if (!(ret = key->can_certify))
2724 for (subkey = key->subkeys; subkey; subkey = subkey->next)
2725 if ((ret = subkey->can_certify))
2734 /* Print verbose information about a key or certificate to FP. */
2735 static void print_key_info (gpgme_key_t key, FILE * fp)
2738 const char *s = NULL, *s2 = NULL;
2741 char shortbuf[SHORT_STRING];
2742 unsigned long aval = 0;
2746 gpgme_user_id_t uid = NULL;
2749 setlocale (LC_TIME, Locale);
2751 is_pgp = key->protocol == GPGME_PROTOCOL_OpenPGP;
2753 for (idx = 0, uid = key->uids; uid; idx++, uid = uid->next) {
2758 fputs (idx ? _(" aka ......: ") :_("Name ......: "), fp);
2761 fputs (_("[Invalid]"), fp);
2765 print_utf8 (fp, s, m_strlen(s));
2767 parse_and_print_user_id (fp, s);
2771 if (key->subkeys && (key->subkeys->timestamp > 0)) {
2772 tt = key->subkeys->timestamp;
2774 tm = localtime (&tt);
2775 #ifdef HAVE_LANGINFO_D_T_FMT
2776 strftime (shortbuf, sizeof shortbuf, nl_langinfo (D_T_FMT), tm);
2778 strftime (shortbuf, sizeof shortbuf, "%c", tm);
2780 fprintf (fp, _("Valid From : %s\n"), shortbuf);
2783 if (key->subkeys && (key->subkeys->expires > 0)) {
2784 tt = key->subkeys->expires;
2786 tm = localtime (&tt);
2787 #ifdef HAVE_LANGINFO_D_T_FMT
2788 strftime (shortbuf, sizeof shortbuf, nl_langinfo (D_T_FMT), tm);
2790 strftime (shortbuf, sizeof shortbuf, "%c", tm);
2792 fprintf (fp, _("Valid To ..: %s\n"), shortbuf);
2796 s = gpgme_pubkey_algo_name (key->subkeys->pubkey_algo);
2800 s2 = is_pgp ? "PGP" : "X.509";
2803 aval = key->subkeys->length;
2805 fprintf (fp, _("Key Type ..: %s, %lu bit %s\n"), s2, aval, s);
2807 fprintf (fp, _("Key Usage .: "));
2810 if (key_check_cap (key, KEY_CAP_CAN_ENCRYPT)) {
2811 fprintf (fp, "%s%s", delim, _("encryption"));
2814 if (key_check_cap (key, KEY_CAP_CAN_SIGN)) {
2815 fprintf (fp, "%s%s", delim, _("signing"));
2818 if (key_check_cap (key, KEY_CAP_CAN_CERTIFY)) {
2819 fprintf (fp, "%s%s", delim, _("certification"));
2825 s = key->subkeys->fpr;
2826 fputs (_("Fingerprint: "), fp);
2827 if (is_pgp && m_strlen(s) == 40) {
2828 for (i = 0; *s && s[1] && s[2] && s[3] && s[4]; s += 4, i++) {
2833 putc (is_pgp ? ' ' : ':', fp);
2834 if (is_pgp && i == 4)
2839 for (i = 0; *s && s[1] && s[2]; s += 2, i++) {
2842 putc (is_pgp ? ' ' : ':', fp);
2843 if (is_pgp && i == 7)
2847 fprintf (fp, "%s\n", s);
2850 if (key->issuer_serial) {
2851 s = key->issuer_serial;
2853 fprintf (fp, _("Serial-No .: 0x%s\n"), s);
2856 if (key->issuer_name) {
2857 s = key->issuer_name;
2859 fprintf (fp, _("Issued By .: "));
2860 parse_and_print_user_id (fp, s);
2865 /* For PGP we list all subkeys. */
2867 gpgme_subkey_t subkey = NULL;
2869 for (idx = 1, subkey = key->subkeys; subkey; idx++, subkey = subkey->next) {
2873 if (m_strlen(s) == 16)
2874 s += 8; /* display only the short keyID */
2875 fprintf (fp, _("Subkey ....: 0x%s"), s);
2876 if (subkey->revoked) {
2878 fputs (_("[Revoked]"), fp);
2880 if (subkey->invalid) {
2882 fputs (_("[Invalid]"), fp);
2884 if (subkey->expired) {
2886 fputs (_("[Expired]"), fp);
2888 if (subkey->disabled) {
2890 fputs (_("[Disabled]"), fp);
2894 if (subkey->timestamp > 0) {
2895 tt = subkey->timestamp;
2897 tm = localtime (&tt);
2898 #ifdef HAVE_LANGINFO_D_T_FMT
2899 strftime (shortbuf, sizeof shortbuf, nl_langinfo (D_T_FMT), tm);
2901 strftime (shortbuf, sizeof shortbuf, "%c", tm);
2903 fprintf (fp, _("Valid From : %s\n"), shortbuf);
2906 if (subkey->expires > 0) {
2907 tt = subkey->expires;
2909 tm = localtime (&tt);
2910 #ifdef HAVE_LANGINFO_D_T_FMT
2911 strftime (shortbuf, sizeof shortbuf, nl_langinfo (D_T_FMT), tm);
2913 strftime (shortbuf, sizeof shortbuf, "%c", tm);
2915 fprintf (fp, _("Valid To ..: %s\n"), shortbuf);
2919 s = gpgme_pubkey_algo_name (subkey->pubkey_algo);
2924 aval = subkey->length;
2928 fprintf (fp, _("Key Type ..: %s, %lu bit %s\n"), "PGP", aval, s);
2930 fprintf (fp, _("Key Usage .: "));
2933 if (subkey->can_encrypt) {
2934 fprintf (fp, "%s%s", delim, _("encryption"));
2937 if (subkey->can_sign) {
2938 fprintf (fp, "%s%s", delim, _("signing"));
2941 if (subkey->can_certify) {
2942 fprintf (fp, "%s%s", delim, _("certification"));
2950 setlocale (LC_TIME, "C");
2954 /* Show detailed information about the selected key */
2955 static void verify_key (crypt_key_t * key)
2958 char cmd[LONG_STRING], tempfile[_POSIX_PATH_MAX];
2960 gpgme_ctx_t listctx = NULL;
2962 gpgme_key_t k = NULL;
2965 mutt_mktemp (tempfile);
2966 if (!(fp = safe_fopen (tempfile, "w"))) {
2967 mutt_perror (_("Can't create temporary file"));
2971 mutt_message _("Collecting data...");
2973 print_key_info (key->kobj, fp);
2975 err = gpgme_new (&listctx);
2977 fprintf (fp, "Internal error: can't create gpgme context: %s\n",
2978 gpgme_strerror (err));
2981 if ((key->flags & KEYFLAG_ISX509))
2982 gpgme_set_protocol (listctx, GPGME_PROTOCOL_CMS);
2986 while ((s = k->chain_id) && k->subkeys && m_strcmp(s, k->subkeys->fpr)) {
2988 err = gpgme_op_keylist_start (listctx, s, 0);
2989 gpgme_key_release (k);
2992 err = gpgme_op_keylist_next (listctx, &k);
2994 fprintf (fp, _("Error finding issuer key: %s\n"), gpgme_strerror (err));
2997 gpgme_op_keylist_end (listctx);
2999 print_key_info (k, fp);
3002 fputs (_("Error: certification chain to long - stopping here\n"), fp);
3008 gpgme_key_release (k);
3009 gpgme_release (listctx);
3011 mutt_clear_error ();
3012 snprintf (cmd, sizeof (cmd), _("Key ID: 0x%s"), crypt_keyid (key));
3013 mutt_do_pager (cmd, tempfile, 0, NULL);
3017 * Implementation of `findkeys'.
3021 /* Convert string_list_t into a pattern string suitable to be passed to GPGME.
3022 We need to convert spaces in an item into a '+' and '%' into
3024 static char *list_to_pattern (string_list_t * list)
3032 for (l = list; l; l = l->next) {
3033 for (s = l->data; *s; s++) {
3038 n++; /* delimiter or end of string */
3040 n++; /* make sure to allocate at least one byte */
3041 pattern = p = p_new(char, n);
3042 for (l = list; l; l = l->next) {
3047 for (s = l->data; *s; s++) {
3053 else if (*s == '+') {
3069 /* Return a list of keys which are candidates for the selection.
3070 Select by looking at the HINTS list. */
3071 static crypt_key_t *get_candidates (string_list_t * hints, unsigned int app,
3074 crypt_key_t *db, *k, **kend;
3080 gpgme_user_id_t uid = NULL;
3082 pattern = list_to_pattern (hints);
3086 err = gpgme_new (&ctx);
3088 mutt_error (_("gpgme_new failed: %s"), gpgme_strerror (err));
3096 if ((app & APPLICATION_PGP)) {
3097 /* Its all a mess. That old GPGME expects different things
3098 depending on the protocol. For gpg we don' t need percent
3099 escaped pappert but simple strings passed in an array to the
3100 keylist_ext_start function. */
3105 for (l = hints, n = 0; l; l = l->next) {
3106 if (l->data && *l->data)
3112 patarr = p_new(char *, n + 1);
3113 for (l = hints, n = 0; l; l = l->next) {
3114 if (l->data && *l->data)
3115 patarr[n++] = m_strdup(l->data);
3118 err = gpgme_op_keylist_ext_start (ctx, (const char **) patarr, secret, 0);
3119 for (n = 0; patarr[n]; n++)
3120 p_delete(&patarr[n]);
3123 mutt_error (_("gpgme_op_keylist_start failed: %s"), gpgme_strerror (err));
3124 gpgme_release (ctx);
3129 while (!(err = gpgme_op_keylist_next (ctx, &key))) {
3130 unsigned int flags = 0;
3132 if (key_check_cap (key, KEY_CAP_CAN_ENCRYPT))
3133 flags |= KEYFLAG_CANENCRYPT;
3134 if (key_check_cap (key, KEY_CAP_CAN_SIGN))
3135 flags |= KEYFLAG_CANSIGN;
3137 #if 0 /* DISABLED code */
3139 /* Bug in gpg. Capabilities are not listed for secret
3140 keys. Try to deduce them from the algorithm. */
3142 switch (key->subkeys[0].pubkey_algo) {
3144 flags |= KEYFLAG_CANENCRYPT;
3145 flags |= KEYFLAG_CANSIGN;
3147 case GPGME_PK_ELG_E:
3148 flags |= KEYFLAG_CANENCRYPT;
3151 flags |= KEYFLAG_CANSIGN;
3155 #endif /* DISABLED code */
3157 for (idx = 0, uid = key->uids; uid; idx++, uid = uid->next) {
3158 k = p_new(crypt_key_t, 1);
3167 if (gpg_err_code (err) != GPG_ERR_EOF)
3168 mutt_error (_("gpgme_op_keylist_next failed: %s"), gpgme_strerror (err));
3169 gpgme_op_keylist_end (ctx);
3174 if ((app & APPLICATION_SMIME)) {
3175 /* and now look for x509 certificates */
3176 gpgme_set_protocol (ctx, GPGME_PROTOCOL_CMS);
3177 err = gpgme_op_keylist_start (ctx, pattern, 0);
3179 mutt_error (_("gpgme_op_keylist_start failed: %s"), gpgme_strerror (err));
3180 gpgme_release (ctx);
3185 while (!(err = gpgme_op_keylist_next (ctx, &key))) {
3186 unsigned int flags = KEYFLAG_ISX509;
3188 if (key_check_cap (key, KEY_CAP_CAN_ENCRYPT))
3189 flags |= KEYFLAG_CANENCRYPT;
3190 if (key_check_cap (key, KEY_CAP_CAN_SIGN))
3191 flags |= KEYFLAG_CANSIGN;
3193 for (idx = 0, uid = key->uids; uid; idx++, uid = uid->next) {
3194 k = p_new(crypt_key_t, 1);
3203 if (gpg_err_code (err) != GPG_ERR_EOF)
3204 mutt_error (_("gpgme_op_keylist_next failed: %s"), gpgme_strerror (err));
3205 gpgme_op_keylist_end (ctx);
3208 gpgme_release (ctx);
3213 /* Add the string STR to the list HINTS. This list is later used to
3215 static string_list_t *crypt_add_string_to_hints (string_list_t * hints, const char *str)
3220 if ((scratch = m_strdup(str)) == NULL)
3223 for (t = strtok (scratch, " ,.:\"()<>\n"); t;
3224 t = strtok (NULL, " ,.:\"()<>\n")) {
3225 if (m_strlen(t) > 3)
3226 hints = mutt_add_list(hints, t);
3233 /* Display a menu to select a key from the array KEYS. FORCED_VALID
3234 will be set to true on return if the user did override the the
3236 static crypt_key_t *crypt_select_key (crypt_key_t * keys,
3237 address_t * p, const char *s,
3238 unsigned int app, int *forced_valid)
3241 crypt_key_t **key_table;
3244 char helpstr[SHORT_STRING], buf[LONG_STRING];
3246 int (*f) (const void *, const void *);
3247 int menu_to_use = 0;
3252 /* build the key table */
3255 for (k = keys; k; k = k->next) {
3256 if (!option (OPTPGPSHOWUNUSABLE) && (k->flags & KEYFLAG_CANTUSE)) {
3263 p_realloc(&key_table, keymax);
3269 if (!i && unusable) {
3270 mutt_error _("All matching keys are marked expired/revoked.");
3276 switch (PgpSortKeys & SORT_MASK) {
3278 f = crypt_compare_date;
3281 f = crypt_compare_keyid;
3284 f = crypt_compare_address;
3288 f = crypt_compare_trust;
3291 qsort (key_table, i, sizeof (crypt_key_t *), f);
3293 if (app & APPLICATION_PGP)
3294 menu_to_use = MENU_KEY_SELECT_PGP;
3295 else if (app & APPLICATION_SMIME)
3296 menu_to_use = MENU_KEY_SELECT_SMIME;
3299 mutt_make_help (buf, sizeof (buf), _("Exit "), menu_to_use, OP_EXIT);
3300 strcat (helpstr, buf); /* __STRCAT_CHECKED__ */
3301 mutt_make_help (buf, sizeof (buf), _("Select "), menu_to_use,
3302 OP_GENERIC_SELECT_ENTRY);
3303 strcat (helpstr, buf); /* __STRCAT_CHECKED__ */
3304 mutt_make_help (buf, sizeof (buf), _("Check key "),
3305 menu_to_use, OP_VERIFY_KEY);
3306 strcat (helpstr, buf); /* __STRCAT_CHECKED__ */
3307 mutt_make_help (buf, sizeof (buf), _("Help"), menu_to_use, OP_HELP);
3308 strcat (helpstr, buf); /* __STRCAT_CHECKED__ */
3310 menu = mutt_new_menu ();
3312 menu->make_entry = crypt_entry;
3313 menu->menu = menu_to_use;
3314 menu->help = helpstr;
3315 menu->data = key_table;
3320 if ((app & APPLICATION_PGP) && (app & APPLICATION_SMIME))
3321 ts = _("PGP and S/MIME keys matching");
3322 else if ((app & APPLICATION_PGP))
3323 ts = _("PGP keys matching");
3324 else if ((app & APPLICATION_SMIME))
3325 ts = _("S/MIME keys matching");
3327 ts = _("keys matching");
3330 snprintf (buf, sizeof (buf), _("%s <%s>."), ts, p->mailbox);
3332 snprintf (buf, sizeof (buf), _("%s \"%s\"."), ts, s);
3336 mutt_clear_error ();
3340 switch (mutt_menuLoop (menu)) {
3342 verify_key (key_table[menu->current]);
3343 menu->redraw = REDRAW_FULL;
3347 mutt_message ("%s", key_table[menu->current]->uid);
3350 case OP_GENERIC_SELECT_ENTRY:
3351 /* FIXME make error reporting more verbose - this should be
3352 easy because gpgme provides more information */
3353 if (option (OPTPGPCHECKTRUST)) {
3354 if (!crypt_key_is_valid (key_table[menu->current])) {
3355 mutt_error _("This key can't be used: "
3356 "expired/disabled/revoked.");
3361 if (option (OPTPGPCHECKTRUST) &&
3362 (!crypt_id_is_valid (key_table[menu->current])
3363 || !crypt_id_is_strong (key_table[menu->current]))) {
3365 char buff[LONG_STRING];
3367 if (key_table[menu->current]->flags & KEYFLAG_CANTUSE)
3368 s = N_("ID is expired/disabled/revoked.");
3370 gpgme_validity_t val = GPGME_VALIDITY_UNKNOWN;
3371 gpgme_user_id_t uid = NULL;
3376 uid = key_table[menu->current]->kobj->uids;
3377 for (j = 0; (j < key_table[menu->current]->idx) && uid;
3378 j++, uid = uid->next);
3380 val = uid->validity;
3383 case GPGME_VALIDITY_UNKNOWN:
3384 case GPGME_VALIDITY_UNDEFINED:
3385 warn_s = N_("ID has undefined validity.");
3387 case GPGME_VALIDITY_NEVER:
3388 warn_s = N_("ID is not valid.");
3390 case GPGME_VALIDITY_MARGINAL:
3391 warn_s = N_("ID is only marginally valid.");
3393 case GPGME_VALIDITY_FULL:
3394 case GPGME_VALIDITY_ULTIMATE:
3398 snprintf (buff, sizeof (buff),
3399 _("%s Do you really want to use the key?"), _(warn_s));
3401 if (mutt_yesorno (buff, 0) != 1) {
3402 mutt_clear_error ();
3409 k = crypt_copy_key (key_table[menu->current]);
3420 mutt_menuDestroy (&menu);
3421 p_delete(&key_table);
3423 set_option (OPTNEEDREDRAW);
3428 static crypt_key_t *crypt_getkeybyaddr (address_t * a, short abilities,
3429 unsigned int app, int *forced_valid)
3432 string_list_t *hints = NULL;
3437 int this_key_has_strong;
3438 int this_key_has_weak;
3439 int this_key_has_invalid;
3442 crypt_key_t *keys, *k;
3443 crypt_key_t *the_valid_key = NULL;
3444 crypt_key_t *matches = NULL;
3445 crypt_key_t **matches_endp = &matches;
3449 if (a && a->mailbox)
3450 hints = crypt_add_string_to_hints (hints, a->mailbox);
3451 if (a && a->personal)
3452 hints = crypt_add_string_to_hints (hints, a->personal);
3454 mutt_message (_("Looking for keys matching \"%s\"..."), a->mailbox);
3455 keys = get_candidates (hints, app, (abilities & KEYFLAG_CANSIGN));
3457 string_list_wipe(&hints);
3462 debug_print (5, ("looking for %s <%s>.\n", a->personal, a->mailbox));
3464 for (k = keys; k; k = k->next) {
3465 debug_print (5, (" looking at key: %s `%.15s'\n", crypt_keyid (k), k->uid));
3467 if (abilities && !(k->flags & abilities)) {
3468 debug_print (5, (" insufficient abilities: Has %x, want %x\n", k->flags, abilities));
3472 this_key_has_weak = 0; /* weak but valid match */
3473 this_key_has_invalid = 0; /* invalid match */
3474 this_key_has_strong = 0; /* strong and valid match */
3475 match = 0; /* any match */
3477 r = rfc822_parse_adrlist (NULL, k->uid);
3478 for (p = r; p; p = p->next) {
3479 int validity = crypt_id_matches_addr (a, p, k);
3481 if (validity & CRYPT_KV_MATCH) /* something matches */
3484 /* is this key a strong candidate? */
3485 if ((validity & CRYPT_KV_VALID)
3486 && (validity & CRYPT_KV_STRONGID)
3487 && (validity & CRYPT_KV_ADDR)) {
3488 if (the_valid_key && the_valid_key != k)
3491 this_key_has_strong = 1;
3493 else if ((validity & CRYPT_KV_MATCH)
3494 && !(validity & CRYPT_KV_VALID))
3495 this_key_has_invalid = 1;
3496 else if ((validity & CRYPT_KV_MATCH)
3497 && (!(validity & CRYPT_KV_STRONGID)
3498 || !(validity & CRYPT_KV_ADDR)))
3499 this_key_has_weak = 1;
3501 address_list_wipe(&r);
3506 if (!this_key_has_strong && this_key_has_invalid)
3508 if (!this_key_has_strong && this_key_has_weak)
3511 *matches_endp = tmp = crypt_copy_key (k);
3512 matches_endp = &tmp->next;
3513 the_valid_key = tmp;
3517 crypt_free_key (&keys);
3520 if (the_valid_key && !multi && !weak
3521 && !(invalid && option (OPTPGPSHOWUNUSABLE))) {
3523 * There was precisely one strong match on a valid ID, there
3524 * were no valid keys with weak matches, and we aren't
3525 * interested in seeing invalid keys.
3527 * Proceed without asking the user.
3529 k = crypt_copy_key (the_valid_key);
3533 * Else: Ask the user.
3535 k = crypt_select_key (matches, a, NULL, app, forced_valid);
3537 crypt_free_key (&matches);
3546 static crypt_key_t *crypt_getkeybystr (char *p, short abilities,
3547 unsigned int app, int *forced_valid)
3549 string_list_t *hints = NULL;
3551 crypt_key_t *matches = NULL;
3552 crypt_key_t **matches_endp = &matches;
3556 mutt_message (_("Looking for keys matching \"%s\"..."), p);
3560 hints = crypt_add_string_to_hints (hints, p);
3561 keys = get_candidates (hints, app, (abilities & KEYFLAG_CANSIGN));
3562 string_list_wipe(&hints);
3567 for (k = keys; k; k = k->next) {
3568 if (abilities && !(k->flags & abilities))
3572 debug_print (5, ("matching \"%s\" against " "key %s, \"%s\":\n", p, crypt_keyid (k), k->uid));
3574 if (!*p || !m_strcasecmp(p, crypt_keyid (k))
3575 || (!m_strncasecmp(p, "0x", 2)
3576 && !m_strcasecmp(p + 2, crypt_keyid (k)))
3577 || (option (OPTPGPLONGIDS)
3578 && !m_strncasecmp(p, "0x", 2)
3579 && !m_strcasecmp(p + 2, crypt_keyid (k) + 8))
3580 || m_stristr(k->uid, p)) {
3583 debug_print (5, ("match.\n"));
3585 *matches_endp = tmp = crypt_copy_key (k);
3586 matches_endp = &tmp->next;
3590 crypt_free_key (&keys);
3593 k = crypt_select_key (matches, NULL, p, app, forced_valid);
3594 crypt_free_key (&matches);
3601 /* Display TAG as a prompt to ask for a key. If WHATFOR is not null
3602 use it as default and store it under that label as the next
3603 default. ABILITIES describe the required key abilities (sign,
3604 encrypt) and APP the type of the requested key; ether S/MIME or
3605 PGP. Return a copy of the key or NULL if not found. */
3606 static crypt_key_t *crypt_ask_for_key (char *tag,
3609 unsigned int app, int *forced_valid)
3612 char resp[SHORT_STRING];
3613 struct crypt_cache *l = NULL;
3617 forced_valid = &dummy;
3619 mutt_clear_error ();
3625 for (l = id_defaults; l; l = l->next)
3626 if (!m_strcasecmp(whatfor, l->what)) {
3627 m_strcpy(resp, sizeof(resp), NONULL(l->dflt));
3635 if (mutt_get_field (tag, resp, sizeof (resp), M_CLEAR) != 0)
3640 m_strreplace(&l->dflt, resp);
3642 l = p_new(struct crypt_cache, 1);
3643 l->next = id_defaults;
3645 l->what = m_strdup(whatfor);
3646 l->dflt = m_strdup(resp);
3650 if ((key = crypt_getkeybystr (resp, abilities, app, forced_valid)))
3658 /* This routine attempts to find the keyids of the recipients of a
3659 message. It returns NULL if any of the keys can not be found. */
3660 static char *find_keys (address_t * to, address_t * cc, address_t * bcc,
3663 char *keyID, *keylist = NULL, *t;
3664 size_t keylist_size = 0;
3665 size_t keylist_used = 0;
3666 address_t *tmp = NULL, *addr = NULL;
3667 address_t **last = &tmp;
3670 crypt_key_t *k_info, *key;
3671 const char *fqdn = mutt_fqdn (1);
3674 *r_application = APPLICATION_PGP | APPLICATION_SMIME;
3677 for (i = 0; i < 3; i++) {
3692 *last = address_list_dup (p);
3694 last = &((*last)->next);
3698 rfc822_qualify (tmp, fqdn);
3700 tmp = mutt_remove_duplicates (tmp);
3702 for (p = tmp; p; p = p->next) {
3703 char buf[LONG_STRING];
3704 int forced_valid = 0;
3709 if ((keyID = mutt_crypt_hook (p)) != NULL) {
3712 snprintf (buf, sizeof (buf), _("Use keyID = \"%s\" for %s?"),
3714 if ((r = mutt_yesorno (buf, M_YES)) == M_YES) {
3715 /* check for e-mail address */
3716 if ((t = strchr (keyID, '@')) &&
3717 (addr = rfc822_parse_adrlist (NULL, keyID))) {
3719 rfc822_qualify (addr, fqdn);
3724 k_info = crypt_getkeybystr (keyID, KEYFLAG_CANENCRYPT,
3725 *r_application, &forced_valid);
3727 k_info = crypt_getkeybystr (keyID, KEYFLAG_CANENCRYPT,
3728 app, &forced_valid);
3734 address_list_wipe(&tmp);
3735 address_list_wipe(&addr);
3741 && (k_info = crypt_getkeybyaddr (q, KEYFLAG_CANENCRYPT,
3742 app, &forced_valid)) == NULL) {
3743 snprintf (buf, sizeof (buf), _("Enter keyID for %s: "), q->mailbox);
3745 if ((key = crypt_ask_for_key (buf, q->mailbox, KEYFLAG_CANENCRYPT,
3751 &forced_valid)) == NULL) {
3753 address_list_wipe(&tmp);
3754 address_list_wipe(&addr);
3762 const char *s = crypt_fpr (key);
3765 if (key->flags & KEYFLAG_ISX509)
3766 *r_application &= ~APPLICATION_PGP;
3767 if (!(key->flags & KEYFLAG_ISX509))
3768 *r_application &= ~APPLICATION_SMIME;
3771 keylist_size += m_strlen(s) + 4 + 1;
3772 p_realloc(&keylist, keylist_size);
3773 sprintf (keylist + keylist_used, "%s0x%s%s", /* __SPRINTF_CHECKED__ */
3774 keylist_used ? " " : "", s, forced_valid ? "!" : "");
3776 keylist_used = m_strlen(keylist);
3778 crypt_free_key (&key);
3779 address_list_wipe(&addr);
3781 address_list_wipe(&tmp);
3785 char *pgp_gpgme_findkeys (address_t * to, address_t * cc, address_t * bcc)
3787 return find_keys (to, cc, bcc, APPLICATION_PGP);
3790 char *smime_gpgme_findkeys (address_t * to, address_t * cc, address_t * bcc)
3792 return find_keys (to, cc, bcc, APPLICATION_SMIME);
3796 * Implementation of `init'.
3799 /* Initialization. */
3800 static void init_gpgme (void)
3802 /* Make sure that gpg-agent is running. */
3803 if (!getenv ("GPG_AGENT_INFO")) {
3804 mutt_error ("\nUsing GPGME backend, although no gpg-agent is running");
3805 if (mutt_any_key_to_continue (NULL) == -1)
3810 void pgp_gpgme_init (void)
3815 void smime_gpgme_init (void)
3819 static int gpgme_send_menu (HEADER * msg, int *redraw, int is_smime)
3822 char input_signas[SHORT_STRING];
3825 if (msg->security & APPLICATION_PGP)
3827 else if (msg->security & APPLICATION_SMIME)
3832 mutt_multi_choice (_
3833 ("S/MIME (e)ncrypt, (s)ign, sign (a)s, (b)oth, (p)gp or (c)lear?"),
3837 mutt_multi_choice (_
3838 ("PGP (e)ncrypt, (s)ign, sign (a)s, (b)oth, s/(m)ime or (c)lear?"),
3842 case 1: /* (e)ncrypt */
3843 msg->security |= (is_smime ? SMIMEENCRYPT : PGPENCRYPT);
3844 msg->security &= ~(is_smime ? SMIMESIGN : PGPSIGN);
3847 case 2: /* (s)ign */
3848 msg->security |= (is_smime ? SMIMESIGN : PGPSIGN);
3849 msg->security &= ~(is_smime ? SMIMEENCRYPT : PGPENCRYPT);
3852 case 3: /* sign (a)s */
3853 /* unset_option(OPTCRYPTCHECKTRUST); */
3854 if ((p = crypt_ask_for_key (_("Sign as: "), NULL, KEYFLAG_CANSIGN,
3855 is_smime ? APPLICATION_SMIME :
3856 APPLICATION_PGP, NULL))) {
3857 snprintf (input_signas, sizeof (input_signas), "0x%s", crypt_keyid (p));
3858 m_strreplace(is_smime ? &SmimeDefaultKey : &PgpSignAs,
3860 crypt_free_key (&p);
3862 msg->security |= (is_smime ? SMIMESIGN : PGPSIGN);
3866 msg->security &= (is_smime ? ~SMIMESIGN : ~PGPSIGN);
3869 *redraw = REDRAW_FULL;
3872 case 4: /* (b)oth */
3874 (is_smime ? (SMIMEENCRYPT | SMIMESIGN) : (PGPENCRYPT | PGPSIGN));
3877 case 5: /* (p)gp or s/(m)ime */
3878 is_smime = !is_smime;
3881 case 6: /* (c)lear */
3886 if (choice == 6 || choice == 7);
3887 else if (is_smime) {
3888 msg->security &= ~APPLICATION_PGP;
3889 msg->security |= APPLICATION_SMIME;
3892 msg->security &= ~APPLICATION_SMIME;
3893 msg->security |= APPLICATION_PGP;
3896 return (msg->security);
3899 int pgp_gpgme_send_menu (HEADER * msg, int *redraw)
3901 return gpgme_send_menu (msg, redraw, 0);
3904 int smime_gpgme_send_menu (HEADER * msg, int *redraw)
3906 return gpgme_send_menu (msg, redraw, 1);
3909 static int verify_sender (HEADER * h, gpgme_protocol_t protocol)
3911 address_t *sender = NULL;
3912 unsigned int ret = 1;
3915 h->env->from = mutt_expand_aliases (h->env->from);
3916 sender = h->env->from;
3918 else if (h->env->sender) {
3919 h->env->sender = mutt_expand_aliases (h->env->sender);
3920 sender = h->env->sender;
3924 if (signature_key) {
3925 gpgme_key_t key = signature_key;
3926 gpgme_user_id_t uid = NULL;
3927 int sender_length = 0;
3930 sender_length = m_strlen(sender->mailbox);
3931 for (uid = key->uids; uid && ret; uid = uid->next) {
3932 uid_length = m_strlen(uid->email);
3933 if (1 && (uid->email[0] == '<')
3934 && (uid->email[uid_length - 1] == '>')
3935 && (uid_length == sender_length + 2)
3936 && (!strncmp (uid->email + 1, sender->mailbox, sender_length)))
3941 mutt_any_key_to_continue ("Failed to verify sender");
3944 mutt_any_key_to_continue ("Failed to figure out sender");
3946 if (signature_key) {
3947 gpgme_key_release (signature_key);
3948 signature_key = NULL;
3954 int smime_gpgme_verify_sender (HEADER * h)
3956 return verify_sender (h, GPGME_PROTOCOL_CMS);