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>
27 #include "mutt_crypt.h"
28 #include "mutt_menu.h"
29 #include "mutt_curses.h"
35 #include "recvattach.h"
38 #include "lib/debug.h"
53 #ifdef HAVE_LANGINFO_D_T_FMT
57 #ifdef HAVE_SYS_TIME_H
58 # include <sys/time.h>
61 #ifdef HAVE_SYS_RESOURCE_H
62 # include <sys/resource.h>
68 #define digitp(p) (*(p) >= '0' && *(p) <= '9')
69 #define hexdigitp(a) (digitp (a) \
70 || (*(a) >= 'A' && *(a) <= 'F') \
71 || (*(a) >= 'a' && *(a) <= 'f'))
72 #define xtoi_1(p) (*(p) <= '9'? (*(p)- '0'): \
73 *(p) <= 'F'? (*(p)-'A'+10):(*(p)-'a'+10))
74 #define xtoi_2(p) ((xtoi_1(p) * 16) + xtoi_1((p)+1))
76 /* Values used for comparing addresses. */
77 #define CRYPT_KV_VALID 1
78 #define CRYPT_KV_ADDR 2
79 #define CRYPT_KV_STRING 4
80 #define CRYPT_KV_STRONGID 8
81 #define CRYPT_KV_MATCH (CRYPT_KV_ADDR|CRYPT_KV_STRING)
90 struct crypt_cache *next;
98 /* We work based on user IDs, getting from a user ID to the key is
99 check and does not need any memory (gpgme uses reference counting). */
100 typedef struct crypt_keyinfo {
101 struct crypt_keyinfo *next;
103 int idx; /* and the user ID at this index */
104 const char *uid; /* and for convenience point to this user ID */
105 unsigned int flags; /* global and per uid flags (for convenience) */
108 typedef struct crypt_entry {
114 static struct crypt_cache *id_defaults = NULL;
115 static gpgme_key_t signature_key = NULL;
118 * General helper functions.
121 /* return true when S points to a didgit or letter. */
122 static int digit_or_letter (const unsigned char *s)
124 return ((*s >= '0' && *s <= '9')
125 || (*s >= 'A' && *s <= 'Z')
126 || (*s >= 'a' && *s <= 'z'));
130 /* Print the utf-8 encoded string BUF of length LEN bytes to stream
131 FP. Convert the character set. */
132 static void print_utf8 (FILE * fp, const char *buf, size_t len)
136 tstr = p_dupstr(buf, len);
137 mutt_convert_string (&tstr, "utf-8", Charset, M_ICONV_HOOK_FROM);
147 /* Return the keyID for the key K. Note that this string is valid as
148 long as K is valid */
149 static const char *crypt_keyid (crypt_key_t * k)
151 const char *s = "????????";
153 if (k->kobj && k->kobj->subkeys) {
154 s = k->kobj->subkeys->keyid;
155 if ((!option (OPTPGPLONGIDS)) && (m_strlen(s) == 16))
156 /* Return only the short keyID. */
163 /* Return the hexstring fingerprint from the key K. */
164 static const char *crypt_fpr (crypt_key_t * k)
168 if (k->kobj && k->kobj->subkeys)
169 s = k->kobj->subkeys->fpr;
174 /* Parse FLAGS and return a statically allocated(!) string with them. */
175 static char *crypt_key_abilities (int flags)
179 if (!(flags & KEYFLAG_CANENCRYPT))
181 else if (flags & KEYFLAG_PREFER_SIGNING)
186 if (!(flags & KEYFLAG_CANSIGN))
188 else if (flags & KEYFLAG_PREFER_ENCRYPTION)
198 /* Parse FLAGS and return a character describing the most important flag. */
199 static char crypt_flags (int flags)
201 if (flags & KEYFLAG_REVOKED)
203 else if (flags & KEYFLAG_EXPIRED)
205 else if (flags & KEYFLAG_DISABLED)
207 else if (flags & KEYFLAG_CRITICAL)
213 /* Return a copy of KEY. */
214 static crypt_key_t *crypt_copy_key (crypt_key_t *key)
218 k = p_new(crypt_key_t, 1);
220 gpgme_key_ref (key->kobj);
223 k->flags = key->flags;
228 /* Release all the keys at the address of KEYLIST and set the address
230 static void crypt_free_key (crypt_key_t ** keylist)
233 crypt_key_t *k = (*keylist)->next;
240 /* Return trute when key K is valid. */
241 static int crypt_key_is_valid (crypt_key_t * k)
243 if (k->flags & KEYFLAG_CANTUSE)
248 /* Return true whe validity of KEY is sufficient. */
249 static int crypt_id_is_strong (crypt_key_t * key)
251 gpgme_validity_t val = GPGME_VALIDITY_UNKNOWN;
252 gpgme_user_id_t uid = NULL;
253 unsigned int is_strong = 0;
256 if ((key->flags & KEYFLAG_ISX509))
259 for (i = 0, uid = key->kobj->uids; (i < key->idx) && uid;
260 i++, uid = uid->next);
265 case GPGME_VALIDITY_UNKNOWN:
266 case GPGME_VALIDITY_UNDEFINED:
267 case GPGME_VALIDITY_NEVER:
268 case GPGME_VALIDITY_MARGINAL:
272 case GPGME_VALIDITY_FULL:
273 case GPGME_VALIDITY_ULTIMATE:
281 /* Return true when the KEY is valid, i.e. not marked as unusable. */
282 static int crypt_id_is_valid (crypt_key_t * key)
284 return !(key->flags & KEYFLAG_CANTUSE);
287 /* Return a bit vector describing how well the addresses ADDR and
288 U_ADDR match and whether KEY is valid. */
289 static int crypt_id_matches_addr (ADDRESS * addr, ADDRESS * u_addr,
294 if (crypt_id_is_valid (key))
295 rv |= CRYPT_KV_VALID;
297 if (crypt_id_is_strong (key))
298 rv |= CRYPT_KV_STRONGID;
300 if (addr->mailbox && u_addr->mailbox
301 && str_casecmp (addr->mailbox, u_addr->mailbox) == 0)
304 if (addr->personal && u_addr->personal
305 && str_casecmp (addr->personal, u_addr->personal) == 0)
306 rv |= CRYPT_KV_STRING;
313 * GPGME convenient functions.
316 /* Create a new gpgme context and return it. With FOR_SMIME set to
317 true, the protocol of the context is set to CMS. */
318 static gpgme_ctx_t create_gpgme_context (int for_smime)
323 err = gpgme_new (&ctx);
325 mutt_error (_("error creating gpgme context: %s\n"), gpgme_strerror (err));
331 err = gpgme_set_protocol (ctx, GPGME_PROTOCOL_CMS);
333 mutt_error (_("error enabling CMS protocol: %s\n"), gpgme_strerror (err));
342 /* Create a new gpgme data object. This is a wrapper to die on
344 static gpgme_data_t create_gpgme_data (void)
349 err = gpgme_data_new (&data);
351 mutt_error (_("error creating gpgme data object: %s\n"),
352 gpgme_strerror (err));
359 /* Create a new GPGME Data object from the mail body A. With CONVERT
360 passed as true, the lines are converted to CR,LF if required.
361 Return NULL on error or the gpgme_data_t object on success. */
362 static gpgme_data_t body_to_data_object (BODY * a, int convert)
364 char tempfile[_POSIX_PATH_MAX];
369 mutt_mktemp (tempfile);
370 fptmp = safe_fopen (tempfile, "w+");
372 mutt_perror (tempfile);
376 mutt_write_mime_header (a, fptmp);
378 mutt_write_mime_body (a, fptmp);
382 unsigned char buf[1];
384 data = create_gpgme_data ();
386 while ((c = fgetc (fptmp)) != EOF) {
390 if (c == '\n' && !hadcr) {
392 gpgme_data_write (data, buf, 1);
397 /* FIXME: This is quite suboptimal */
399 gpgme_data_write (data, buf, 1);
402 gpgme_data_seek (data, 0, SEEK_SET);
406 err = gpgme_data_new_from_file (&data, tempfile, 1);
410 mutt_error (_("error allocating data object: %s\n"), gpgme_strerror (err));
417 /* Create a GPGME data object from the stream FP but limit the object
418 to LENGTH bytes starting at OFFSET bytes from the beginning of the
420 static gpgme_data_t file_to_data_object (FILE * fp, long offset, long length)
425 err = gpgme_data_new_from_filepart (&data, NULL, fp, offset, length);
427 mutt_error (_("error allocating data object: %s\n"), gpgme_strerror (err));
434 /* Write a GPGME data object to the stream FP. */
435 static int data_object_to_stream (gpgme_data_t data, FILE * fp)
441 err = ((gpgme_data_seek (data, 0, SEEK_SET) == -1)
442 ? gpgme_error_from_errno (errno) : 0);
444 mutt_error (_("error rewinding data object: %s\n"), gpgme_strerror (err));
448 while ((nread = gpgme_data_read (data, buf, sizeof (buf)))) {
449 /* fixme: we are not really converting CRLF to LF but just
450 skipping CR. Doing it correctly needs a more complex logic */
451 for (p = buf; nread; p++, nread--) {
457 mutt_perror ("[tempfile]");
462 mutt_error (_("error reading data object: %s\n"), strerror (errno));
468 /* Copy a data object to a newly created temporay file and return that
469 filename. Caller must free. With RET_FP not NULL, don't close the
470 stream but return it there. */
471 static char *data_object_to_tempfile (gpgme_data_t data, FILE ** ret_fp)
474 char tempfile[_POSIX_PATH_MAX];
478 mutt_mktemp (tempfile);
479 fp = safe_fopen (tempfile, "w+");
481 mutt_perror (tempfile);
485 err = ((gpgme_data_seek (data, 0, SEEK_SET) == -1)
486 ? gpgme_error_from_errno (errno) : 0);
490 while ((nread = gpgme_data_read (data, buf, sizeof (buf)))) {
491 if (fwrite (buf, nread, 1, fp) != 1) {
492 mutt_perror (tempfile);
504 mutt_error (_("error reading data object: %s\n"), gpgme_strerror (err));
511 return m_strdup(tempfile);
515 /* Create a GpgmeRecipientSet from the keys in the string KEYLIST.
516 The keys must be space delimited. */
517 static gpgme_key_t *create_recipient_set (const char *keylist,
518 gpgme_protocol_t protocol)
524 gpgme_key_t *rset = NULL;
525 unsigned int rset_n = 0;
526 gpgme_key_t key = NULL;
527 gpgme_ctx_t context = NULL;
529 err = gpgme_new (&context);
531 err = gpgme_set_protocol (context, protocol);
538 for (i = 0; *s && *s != ' ' && i < sizeof (buf) - 1;)
542 if (i > 1 && buf[i - 1] == '!') {
543 /* The user selected to override the valididy of that
547 err = gpgme_get_key (context, buf, &key, 0);
549 key->uids->validity = GPGME_VALIDITY_FULL;
553 err = gpgme_get_key (context, buf, &key, 0);
556 p_realloc(&rset, rset_n + 1);
557 rset[rset_n++] = key;
560 mutt_error (_("error adding recipient `%s': %s\n"),
561 buf, gpgme_strerror (err));
569 /* NULL terminate. */
570 p_realloc(&rset, rset_n + 1);
571 rset[rset_n++] = NULL;
574 gpgme_release (context);
580 /* Make sure that the correct signer is set. Returns 0 on success. */
581 static int set_signer (gpgme_ctx_t ctx, int for_smime)
583 char *signid = for_smime ? SmimeDefaultKey : PgpSignAs;
586 gpgme_key_t key, key2;
588 if (!signid || !*signid)
591 listctx = create_gpgme_context (for_smime);
592 err = gpgme_op_keylist_start (listctx, signid, 1);
594 err = gpgme_op_keylist_next (listctx, &key);
596 gpgme_release (listctx);
597 mutt_error (_("secret key `%s' not found: %s\n"),
598 signid, gpgme_strerror (err));
601 err = gpgme_op_keylist_next (listctx, &key2);
603 gpgme_key_release (key);
604 gpgme_key_release (key2);
605 gpgme_release (listctx);
606 mutt_error (_("ambiguous specification of secret key `%s'\n"), signid);
609 gpgme_op_keylist_end (listctx);
610 gpgme_release (listctx);
612 gpgme_signers_clear (ctx);
613 err = gpgme_signers_add (ctx, key);
614 gpgme_key_release (key);
616 mutt_error (_("error setting secret key `%s': %s\n"),
617 signid, gpgme_strerror (err));
624 /* Encrypt the gpgme data object PLAINTEXT to the recipients in RSET
625 and return an allocated filename to a temporary file containing the
626 enciphered text. With USE_SMIME set to true, the smime backend is
627 used. With COMBINED_SIGNED a PGP message is signed and
628 encrypted. Returns NULL in case of error */
629 static char *encrypt_gpgme_object (gpgme_data_t plaintext, gpgme_key_t * rset,
630 int use_smime, int combined_signed)
634 gpgme_data_t ciphertext;
637 ctx = create_gpgme_context (use_smime);
639 gpgme_set_armor (ctx, 1);
641 ciphertext = create_gpgme_data ();
643 if (combined_signed) {
644 if (set_signer (ctx, use_smime)) {
645 gpgme_data_release (ciphertext);
649 err = gpgme_op_encrypt_sign (ctx, rset, GPGME_ENCRYPT_ALWAYS_TRUST,
650 plaintext, ciphertext);
653 err = gpgme_op_encrypt (ctx, rset, GPGME_ENCRYPT_ALWAYS_TRUST,
654 plaintext, ciphertext);
655 mutt_need_hard_redraw ();
657 mutt_error (_("error encrypting data: %s\n"), gpgme_strerror (err));
658 gpgme_data_release (ciphertext);
665 outfile = data_object_to_tempfile (ciphertext, NULL);
666 gpgme_data_release (ciphertext);
670 /* Find the "micalg" parameter from the last Gpgme operation on
671 context CTX. It is expected that this operation was a sign
672 operation. Return the algorithm name as a C string in buffer BUF
673 which must have been allocated by the caller with size BUFLEN.
674 Returns 0 on success or -1 in case of an error. The return string
675 is truncted to BUFLEN - 1. */
676 static int get_micalg (gpgme_ctx_t ctx, char *buf, size_t buflen)
678 gpgme_sign_result_t result = NULL;
679 const char *algorithm_name = NULL;
685 result = gpgme_op_sign_result (ctx);
687 algorithm_name = gpgme_hash_algo_name (result->signatures->hash_algo);
688 if (algorithm_name) {
689 strncpy (buf, algorithm_name, buflen - 1);
694 return *buf ? 0 : -1;
697 static void print_time (time_t t, STATE * s)
701 setlocale (LC_TIME, "");
702 #ifdef HAVE_LANGINFO_D_T_FMT
703 strftime (p, sizeof (p), nl_langinfo (D_T_FMT), localtime (&t));
705 strftime (p, sizeof (p), "%c", localtime (&t));
707 setlocale (LC_TIME, "C");
708 state_attach_puts (p, s);
712 * Implementation of `sign_message'.
715 /* Sign the MESSAGE in body A either using OpenPGP or S/MIME when
716 USE_SMIME is passed as true. Returns the new body or NULL on
718 static BODY *sign_message (BODY * a, int use_smime)
725 gpgme_data_t message, signature;
727 convert_to_7bit (a); /* Signed data _must_ be in 7-bit format. */
729 message = body_to_data_object (a, 1);
732 signature = create_gpgme_data ();
734 ctx = create_gpgme_context (use_smime);
736 gpgme_set_armor (ctx, 1);
738 if (set_signer (ctx, use_smime)) {
739 gpgme_data_release (signature);
744 err = gpgme_op_sign (ctx, message, signature, GPGME_SIG_MODE_DETACH);
745 mutt_need_hard_redraw ();
746 gpgme_data_release (message);
748 gpgme_data_release (signature);
750 mutt_error (_("error signing data: %s\n"), gpgme_strerror (err));
754 sigfile = data_object_to_tempfile (signature, NULL);
755 gpgme_data_release (signature);
761 t = mutt_new_body ();
762 t->type = TYPEMULTIPART;
763 t->subtype = m_strdup("signed");
764 t->encoding = ENC7BIT;
766 t->disposition = DISPINLINE;
768 mutt_generate_boundary (&t->parameter);
769 mutt_set_parameter ("protocol",
770 use_smime ? "application/pkcs7-signature"
771 : "application/pgp-signature", &t->parameter);
772 /* Get the micalg from gpgme. Old gpgme versions don't support this
773 for S/MIME so we assume sha-1 in this case. */
774 if (!get_micalg (ctx, buf, sizeof buf))
775 mutt_set_parameter ("micalg", buf, &t->parameter);
777 mutt_set_parameter ("micalg", "sha1", &t->parameter);
783 t->parts->next = mutt_new_body ();
785 t->type = TYPEAPPLICATION;
787 t->subtype = m_strdup("pkcs7-signature");
788 mutt_set_parameter ("name", "smime.p7s", &t->parameter);
789 t->encoding = ENCBASE64;
791 t->disposition = DISPATTACH;
792 t->d_filename = m_strdup("smime.p7s");
795 t->subtype = m_strdup("pgp-signature");
797 t->disposition = DISPINLINE;
798 t->encoding = ENC7BIT;
800 t->filename = sigfile;
801 t->unlink = 1; /* ok to remove this file after sending. */
807 BODY *pgp_gpgme_sign_message (BODY * a)
809 return sign_message (a, 0);
812 BODY *smime_gpgme_sign_message (BODY * a)
814 return sign_message (a, 1);
818 * Implementation of `encrypt_message'.
821 /* Encrypt the mail body A to all keys given as space separated keyids
822 or fingerprints in KEYLIST and return the encrypted body. */
823 BODY *pgp_gpgme_encrypt_message (BODY * a, char *keylist, int sign)
825 char *outfile = NULL;
827 gpgme_key_t *rset = NULL;
828 gpgme_data_t plaintext;
830 rset = create_recipient_set (keylist, GPGME_PROTOCOL_OpenPGP);
836 plaintext = body_to_data_object (a, 0);
842 outfile = encrypt_gpgme_object (plaintext, rset, 0, sign);
843 gpgme_data_release (plaintext);
848 t = mutt_new_body ();
849 t->type = TYPEMULTIPART;
850 t->subtype = m_strdup("encrypted");
851 t->encoding = ENC7BIT;
853 t->disposition = DISPINLINE;
855 mutt_generate_boundary (&t->parameter);
856 mutt_set_parameter ("protocol", "application/pgp-encrypted", &t->parameter);
858 t->parts = mutt_new_body ();
859 t->parts->type = TYPEAPPLICATION;
860 t->parts->subtype = m_strdup("pgp-encrypted");
861 t->parts->encoding = ENC7BIT;
863 t->parts->next = mutt_new_body ();
864 t->parts->next->type = TYPEAPPLICATION;
865 t->parts->next->subtype = m_strdup("octet-stream");
866 t->parts->next->encoding = ENC7BIT;
867 t->parts->next->filename = outfile;
868 t->parts->next->use_disp = 1;
869 t->parts->next->disposition = DISPINLINE;
870 t->parts->next->unlink = 1; /* delete after sending the message */
871 t->parts->next->d_filename = m_strdup("msg.asc"); /* non pgp/mime
878 * Implementation of `smime_build_smime_entity'.
881 /* Encrypt the mail body A to all keys given as space separated
882 fingerprints in KEYLIST and return the S/MIME encrypted body. */
883 BODY *smime_gpgme_build_smime_entity (BODY * a, char *keylist)
885 char *outfile = NULL;
887 gpgme_key_t *rset = NULL;
888 gpgme_data_t plaintext;
890 rset = create_recipient_set (keylist, GPGME_PROTOCOL_CMS);
894 plaintext = body_to_data_object (a, 0);
900 outfile = encrypt_gpgme_object (plaintext, rset, 1, 0);
901 gpgme_data_release (plaintext);
906 t = mutt_new_body ();
907 t->type = TYPEAPPLICATION;
908 t->subtype = m_strdup("pkcs7-mime");
909 mutt_set_parameter ("name", "smime.p7m", &t->parameter);
910 mutt_set_parameter ("smime-type", "enveloped-data", &t->parameter);
911 t->encoding = ENCBASE64; /* The output of OpenSSL SHOULD be binary */
913 t->disposition = DISPATTACH;
914 t->d_filename = m_strdup("smime.p7m");
915 t->filename = outfile;
916 t->unlink = 1; /*delete after sending the message */
925 * Implementation of `verify_one'.
928 /* Display the common attributes of the signature summary SUM.
929 Return 1 if there is is a severe warning.
931 static int show_sig_summary (unsigned long sum,
932 gpgme_ctx_t ctx, gpgme_key_t key, int idx,
937 if ((sum & GPGME_SIGSUM_KEY_REVOKED)) {
938 state_attach_puts (_("Warning: One of the keys has been revoked\n"), s);
942 if ((sum & GPGME_SIGSUM_KEY_EXPIRED)) {
943 time_t at = key->subkeys->expires ? key->subkeys->expires : 0;
946 state_attach_puts (_("Warning: The key used to create the "
947 "signature expired at: "), s);
949 state_attach_puts ("\n", s);
952 state_attach_puts (_("Warning: At least one certification key "
953 "has expired\n"), s);
956 if ((sum & GPGME_SIGSUM_SIG_EXPIRED)) {
957 gpgme_verify_result_t result;
958 gpgme_signature_t sig;
961 result = gpgme_op_verify_result (ctx);
963 for (sig = result->signatures, i = 0; sig && (i < idx);
964 sig = sig->next, i++);
966 state_attach_puts (_("Warning: The signature expired at: "), s);
967 print_time (sig ? sig->exp_timestamp : 0, s);
968 state_attach_puts ("\n", s);
971 if ((sum & GPGME_SIGSUM_KEY_MISSING))
972 state_attach_puts (_("Can't verify due to a missing "
973 "key or certificate\n"), s);
975 if ((sum & GPGME_SIGSUM_CRL_MISSING)) {
976 state_attach_puts (_("The CRL is not available\n"), s);
980 if ((sum & GPGME_SIGSUM_CRL_TOO_OLD)) {
981 state_attach_puts (_("Available CRL is too old\n"), s);
985 if ((sum & GPGME_SIGSUM_BAD_POLICY))
986 state_attach_puts (_("A policy requirement was not met\n"), s);
988 if ((sum & GPGME_SIGSUM_SYS_ERROR)) {
989 const char *t0 = NULL, *t1 = NULL;
990 gpgme_verify_result_t result;
991 gpgme_signature_t sig;
994 state_attach_puts (_("A system error occurred"), s);
996 /* Try to figure out some more detailed system error information. */
997 result = gpgme_op_verify_result (ctx);
998 for (sig = result->signatures, i = 0; sig && (i < idx);
999 sig = sig->next, i++);
1002 t1 = sig->wrong_key_usage ? "Wrong_Key_Usage" : "";
1006 state_attach_puts (": ", s);
1008 state_attach_puts (t0, s);
1009 if (t1 && !(t0 && !str_cmp (t0, t1))) {
1011 state_attach_puts (",", s);
1012 state_attach_puts (t1, s);
1015 state_attach_puts ("\n", s);
1022 static void show_fingerprint (gpgme_key_t key, STATE * state)
1027 const char *prefix = _("Fingerprint: ");
1031 s = key->subkeys ? key->subkeys->fpr : NULL;
1034 is_pgp = (key->protocol == GPGME_PROTOCOL_OpenPGP);
1036 buf = xmalloc(m_strlen(prefix) + m_strlen(s) * 4 + 2);
1037 strcpy (buf, prefix); /* __STRCPY_CHECKED__ */
1038 p = buf + m_strlen(buf);
1039 if (is_pgp && m_strlen(s) == 40) { /* PGP v4 style formatted. */
1040 for (i = 0; *s && s[1] && s[2] && s[3] && s[4]; s += 4, i++) {
1051 for (i = 0; *s && s[1] && s[2]; s += 2, i++) {
1054 *p++ = is_pgp ? ' ' : ':';
1055 if (is_pgp && i == 7)
1060 /* just in case print remaining odd digits */
1065 state_attach_puts (buf, state);
1069 /* Show the valididy of a key used for one signature. */
1070 static void show_one_sig_validity (gpgme_ctx_t ctx, int idx, STATE * s)
1072 gpgme_verify_result_t result = NULL;
1073 gpgme_signature_t sig = NULL;
1074 const char *txt = NULL;
1076 result = gpgme_op_verify_result (ctx);
1078 for (sig = result->signatures; sig && (idx > 0); sig = sig->next, idx--);
1080 switch (sig ? sig->validity : 0) {
1081 case GPGME_VALIDITY_UNKNOWN:
1082 txt = _("WARNING: We have NO indication whether "
1083 "the key belongs to the person named " "as shown above\n");
1085 case GPGME_VALIDITY_UNDEFINED:
1087 case GPGME_VALIDITY_NEVER:
1088 txt = _("WARNING: The key does NOT BELONG to "
1089 "the person named as shown above\n");
1091 case GPGME_VALIDITY_MARGINAL:
1092 txt = _("WARNING: It is NOT certain that the key "
1093 "belongs to the person named as shown above\n");
1095 case GPGME_VALIDITY_FULL:
1096 case GPGME_VALIDITY_ULTIMATE:
1101 state_attach_puts (txt, s);
1104 /* Show information about one signature. This fucntion is called with
1105 the context CTX of a sucessful verification operation and the
1106 enumerator IDX which should start at 0 and incremete for each
1109 Return values are: 0 for normal procession, 1 for a bad signature,
1110 2 for a signature with a warning or -1 for no more signature. */
1111 static int show_one_sig_status (gpgme_ctx_t ctx, int idx, STATE * s)
1114 const char *fpr, *uid;
1115 gpgme_key_t key = NULL;
1116 int i, anybad = 0, anywarn = 0;
1118 gpgme_user_id_t uids = NULL;
1119 gpgme_verify_result_t result;
1120 gpgme_signature_t sig;
1121 gpgme_error_t err = GPG_ERR_NO_ERROR;
1123 result = gpgme_op_verify_result (ctx);
1125 /* FIXME: this code should use a static variable and remember
1126 the current position in the list of signatures, IMHO.
1129 for (i = 0, sig = result->signatures; sig && (i < idx);
1130 i++, sig = sig->next);
1132 return -1; /* Signature not found. */
1134 if (signature_key) {
1135 gpgme_key_release (signature_key);
1136 signature_key = NULL;
1139 created = sig->timestamp;
1143 if (gpg_err_code (sig->status) != GPG_ERR_NO_ERROR)
1146 err = gpgme_get_key (ctx, fpr, &key, 0); /* secret key? */
1148 uid = (key->uids && key->uids->uid) ? key->uids->uid : "[?]";
1150 signature_key = key;
1153 key = NULL; /* Old gpgme versions did not set KEY to NULL on
1154 error. Do it here to avoid a double free. */
1158 if (!s || !s->fpout || !(s->flags & M_DISPLAY)); /* No state information so no way to print anything. */
1160 state_attach_puts (_("Error getting key information: "), s);
1161 state_attach_puts (gpg_strerror (err), s);
1162 state_attach_puts ("\n", s);
1165 else if ((sum & GPGME_SIGSUM_GREEN)) {
1166 state_attach_puts (_("Good signature from: "), s);
1167 state_attach_puts (uid, s);
1168 state_attach_puts ("\n", s);
1169 for (i = 1, uids = key->uids; uids; i++, uids = uids->next) {
1171 /* Skip primary UID. */
1175 state_attach_puts (_(" aka: "), s);
1176 state_attach_puts (uids->uid, s);
1177 state_attach_puts ("\n", s);
1179 state_attach_puts (_(" created: "), s);
1180 print_time (created, s);
1181 state_attach_puts ("\n", s);
1182 if (show_sig_summary (sum, ctx, key, idx, s))
1184 show_one_sig_validity (ctx, idx, s);
1186 else if ((sum & GPGME_SIGSUM_RED)) {
1187 state_attach_puts (_("*BAD* signature claimed to be from: "), s);
1188 state_attach_puts (uid, s);
1189 state_attach_puts ("\n", s);
1190 show_sig_summary (sum, ctx, key, idx, s);
1192 else if (!anybad && key && (key->protocol == GPGME_PROTOCOL_OpenPGP)) { /* We can't decide (yellow) but this is a PGP key with a good
1193 signature, so we display what a PGP user expects: The name,
1194 fingerprint and the key validity (which is neither fully or
1196 state_attach_puts (_("Good signature from: "), s);
1197 state_attach_puts (uid, s);
1198 state_attach_puts ("\n", s);
1199 state_attach_puts (_(" created: "), s);
1200 print_time (created, s);
1201 state_attach_puts ("\n", s);
1202 show_one_sig_validity (ctx, idx, s);
1203 show_fingerprint (key, s);
1204 if (show_sig_summary (sum, ctx, key, idx, s))
1207 else { /* can't decide (yellow) */
1209 state_attach_puts (_("Error checking signature"), s);
1210 state_attach_puts ("\n", s);
1211 show_sig_summary (sum, ctx, key, idx, s);
1214 if (key != signature_key)
1215 gpgme_key_release (key);
1218 return anybad ? 1 : anywarn ? 2 : 0;
1221 /* Do the actual verification step. With IS_SMIME set to true we
1222 assume S/MIME (surprise!) */
1223 static int verify_one (BODY * sigbdy, STATE * s,
1224 const char *tempfile, int is_smime)
1230 gpgme_data_t signature, message;
1232 signature = file_to_data_object (s->fpin, sigbdy->offset, sigbdy->length);
1236 /* We need to tell gpgme about the encoding because the backend can't
1237 auto-detect plain base-64 encoding which is used by S/MIME. */
1239 gpgme_data_set_encoding (signature, GPGME_DATA_ENCODING_BASE64);
1241 err = gpgme_data_new_from_file (&message, tempfile, 1);
1243 gpgme_data_release (signature);
1244 mutt_error (_("error allocating data object: %s\n"), gpgme_strerror (err));
1247 ctx = create_gpgme_context (is_smime);
1249 /* Note: We don't need a current time output because GPGME avoids
1250 such an attack by separating the meta information from the
1252 state_attach_puts (_("[-- Begin signature information --]\n"), s);
1254 err = gpgme_op_verify (ctx, signature, message, NULL);
1255 mutt_need_hard_redraw ();
1259 snprintf (buf, sizeof (buf) - 1,
1260 _("Error: verification failed: %s\n"), gpgme_strerror (err));
1261 state_attach_puts (buf, s);
1263 else { /* Verification succeeded, see what the result is. */
1267 if (signature_key) {
1268 gpgme_key_release (signature_key);
1269 signature_key = NULL;
1272 for (idx = 0; (res = show_one_sig_status (ctx, idx, s)) != -1; idx++) {
1283 gpgme_verify_result_t result;
1284 gpgme_sig_notation_t notation;
1285 gpgme_signature_t signature;
1287 result = gpgme_op_verify_result (ctx);
1289 for (signature = result->signatures; signature;
1290 signature = signature->next) {
1291 if (signature->notations) {
1292 state_attach_puts ("*** Begin Notation (signature by: ", s);
1293 state_attach_puts (signature->fpr, s);
1294 state_attach_puts (") ***\n", s);
1295 for (notation = signature->notations; notation;
1296 notation = notation->next) {
1297 if (notation->name) {
1298 state_attach_puts (notation->name, s);
1299 state_attach_puts ("=", s);
1301 if (notation->value) {
1302 state_attach_puts (notation->value, s);
1303 if (!(*notation->value
1304 && (notation->value[m_strlen(notation->value) - 1] ==
1306 state_attach_puts ("\n", s);
1309 state_attach_puts ("*** End Notation ***\n", s);
1315 gpgme_release (ctx);
1317 state_attach_puts (_("[-- End signature information --]\n\n"), s);
1318 debug_print (1, ("returning %d.\n", badsig));
1320 return badsig ? 1 : anywarn ? 2 : 0;
1323 int pgp_gpgme_verify_one (BODY * sigbdy, STATE * s, const char *tempfile)
1325 return verify_one (sigbdy, s, tempfile, 0);
1328 int smime_gpgme_verify_one (BODY * sigbdy, STATE * s, const char *tempfile)
1330 return verify_one (sigbdy, s, tempfile, 1);
1334 * Implementation of `decrypt_part'.
1337 /* Decrypt a PGP or SMIME message (depending on the boolean flag
1338 IS_SMIME) with body A described further by state S. Write
1339 plaintext out to file FPOUT and return a new body. For PGP returns
1340 a flag in R_IS_SIGNED to indicate whether this is a combined
1341 encrypted and signed message, for S/MIME it returns true when it is
1342 not a encrypted but a signed message. */
1343 static BODY *decrypt_part (BODY * a, STATE * s, FILE * fpout, int is_smime,
1350 gpgme_data_t ciphertext, plaintext;
1351 int maybe_signed = 0;
1358 ctx = create_gpgme_context (is_smime);
1361 /* Make a data object from the body, create context etc. */
1362 ciphertext = file_to_data_object (s->fpin, a->offset, a->length);
1365 plaintext = create_gpgme_data ();
1367 /* Do the decryption or the verification in case of the S/MIME hack. */
1368 if ((!is_smime) || maybe_signed) {
1370 err = gpgme_op_decrypt_verify (ctx, ciphertext, plaintext);
1371 else if (maybe_signed)
1372 err = gpgme_op_verify (ctx, ciphertext, NULL, plaintext);
1375 /* Check wether signatures have been verified. */
1376 gpgme_verify_result_t verify_result = gpgme_op_verify_result (ctx);
1378 if (verify_result->signatures)
1383 err = gpgme_op_decrypt (ctx, ciphertext, plaintext);
1384 gpgme_data_release (ciphertext);
1386 if (is_smime && !maybe_signed && gpg_err_code (err) == GPG_ERR_NO_DATA) {
1387 /* Check whether this might be a signed message despite what
1388 the mime header told us. Retry then. gpgsm returns the
1389 error information "unsupported Algorithm '?'" but gpgme
1390 will not store this unknown algorithm, thus we test that
1391 it has not been set. */
1392 gpgme_decrypt_result_t result;
1394 result = gpgme_op_decrypt_result (ctx);
1395 if (!result->unsupported_algorithm) {
1397 gpgme_data_release (plaintext);
1401 mutt_need_hard_redraw ();
1402 if ((s->flags & M_DISPLAY)) {
1405 snprintf (buf, sizeof (buf) - 1,
1406 _("[-- Error: decryption failed: %s --]\n\n"),
1407 gpgme_strerror (err));
1408 state_attach_puts (buf, s);
1410 gpgme_data_release (plaintext);
1411 gpgme_release (ctx);
1414 mutt_need_hard_redraw ();
1416 /* Read the output from GPGME, and make sure to change CRLF to LF,
1417 otherwise read_mime_header has a hard time parsing the message. */
1418 if (data_object_to_stream (plaintext, fpout)) {
1419 gpgme_data_release (plaintext);
1420 gpgme_release (ctx);
1423 gpgme_data_release (plaintext);
1425 a->is_signed_data = 0;
1431 a->is_signed_data = 1;
1433 *r_is_signed = -1; /* A signature exists. */
1435 if ((s->flags & M_DISPLAY))
1436 state_attach_puts (_("[-- Begin signature " "information --]\n"), s);
1437 for (idx = 0; (res = show_one_sig_status (ctx, idx, s)) != -1; idx++) {
1443 if (!anybad && idx && r_is_signed && *r_is_signed)
1444 *r_is_signed = anywarn ? 2 : 1; /* Good signature. */
1446 if ((s->flags & M_DISPLAY))
1447 state_attach_puts (_("[-- End signature " "information --]\n\n"), s);
1449 gpgme_release (ctx);
1454 tattach = mutt_read_mime_header (fpout, 0);
1457 * Need to set the length of this body part.
1459 fstat (fileno (fpout), &info);
1460 tattach->length = info.st_size - tattach->offset;
1462 tattach->warnsig = anywarn;
1464 /* See if we need to recurse on this MIME part. */
1465 mutt_parse_part (fpout, tattach);
1471 /* Decrypt a PGP/MIME message in FPIN and B and return a new body and
1472 the stream in CUR and FPOUT. Returns 0 on success. */
1473 int pgp_gpgme_decrypt_mime (FILE * fpin, FILE ** fpout, BODY * b, BODY ** cur)
1475 char tempfile[_POSIX_PATH_MAX];
1477 BODY *first_part = b;
1480 first_part->goodsig = 0;
1481 first_part->warnsig = 0;
1483 if (!mutt_is_multipart_encrypted (b))
1486 if (!b->parts || !b->parts->next)
1493 mutt_mktemp (tempfile);
1494 if (!(*fpout = safe_fopen (tempfile, "w+"))) {
1495 mutt_perror (tempfile);
1500 *cur = decrypt_part (b, &s, *fpout, 0, &is_signed);
1503 first_part->goodsig = 1;
1505 return *cur ? 0 : -1;
1509 /* Decrypt a S/MIME message in FPIN and B and return a new body and
1510 the stream in CUR and FPOUT. Returns 0 on success. */
1511 int smime_gpgme_decrypt_mime (FILE * fpin, FILE ** fpout, BODY * b,
1514 char tempfile[_POSIX_PATH_MAX];
1518 long saved_b_offset;
1519 size_t saved_b_length;
1522 if (!mutt_is_application_smime (b))
1528 /* Decode the body - we need to pass binary CMS to the
1529 backend. The backend allows for Base64 encoded data but it does
1530 not allow for QP which I have seen in some messages. So better
1532 saved_b_type = b->type;
1533 saved_b_offset = b->offset;
1534 saved_b_length = b->length;
1537 fseeko (s.fpin, b->offset, 0);
1538 mutt_mktemp (tempfile);
1539 if (!(tmpfp = safe_fopen (tempfile, "w+"))) {
1540 mutt_perror (tempfile);
1543 mutt_unlink (tempfile);
1546 mutt_decode_attachment (b, &s);
1548 b->length = ftello (s.fpout);
1555 mutt_mktemp (tempfile);
1556 if (!(*fpout = safe_fopen (tempfile, "w+"))) {
1557 mutt_perror (tempfile);
1560 mutt_unlink (tempfile);
1562 *cur = decrypt_part (b, &s, *fpout, 1, &is_signed);
1564 (*cur)->goodsig = is_signed > 0;
1565 b->type = saved_b_type;
1566 b->length = saved_b_length;
1567 b->offset = saved_b_offset;
1570 if (*cur && !is_signed && !(*cur)->parts
1571 && mutt_is_application_smime (*cur)) {
1572 /* Assume that this is a opaque signed s/mime message. This is
1573 an ugly way of doing it but we have anyway a problem with
1574 arbitrary encoded S/MIME messages: Only the outer part may be
1575 encrypted. The entire mime parsing should be revamped,
1576 probably by keeping the temportary files so that we don't
1577 need to decrypt them all the time. Inner parts of an
1578 encrypted part can then pint into this file and tehre won't
1579 never be a need to decrypt again. This needs a partial
1580 rewrite of the MIME engine. */
1584 saved_b_type = bb->type;
1585 saved_b_offset = bb->offset;
1586 saved_b_length = bb->length;
1589 fseeko (s.fpin, bb->offset, 0);
1590 mutt_mktemp (tempfile);
1591 if (!(tmpfp = safe_fopen (tempfile, "w+"))) {
1592 mutt_perror (tempfile);
1595 mutt_unlink (tempfile);
1598 mutt_decode_attachment (bb, &s);
1600 bb->length = ftello (s.fpout);
1608 mutt_mktemp (tempfile);
1609 if (!(*fpout = safe_fopen (tempfile, "w+"))) {
1610 mutt_perror (tempfile);
1613 mutt_unlink (tempfile);
1615 tmp_b = decrypt_part (bb, &s, *fpout, 1, &is_signed);
1617 tmp_b->goodsig = is_signed > 0;
1618 bb->type = saved_b_type;
1619 bb->length = saved_b_length;
1620 bb->offset = saved_b_offset;
1623 mutt_free_body (cur);
1626 return *cur ? 0 : -1;
1631 * Implementation of `pgp_check_traditional'.
1634 static int pgp_check_traditional_one_body (FILE * fp, BODY * b,
1637 char tempfile[_POSIX_PATH_MAX];
1638 char buf[HUGE_STRING];
1644 if (b->type != TYPETEXT)
1647 if (tagged_only && !b->tagged)
1650 mutt_mktemp (tempfile);
1651 if (mutt_decode_save_attachment (fp, b, tempfile, 0, 0) != 0) {
1656 if ((tfp = fopen (tempfile, "r")) == NULL) {
1661 while (fgets (buf, sizeof (buf), tfp)) {
1662 if (!str_ncmp ("-----BEGIN PGP ", buf, 15)) {
1663 if (!str_cmp ("MESSAGE-----\n", buf + 15))
1665 else if (!str_cmp ("SIGNED MESSAGE-----\n", buf + 15))
1675 /* fix the content type */
1677 mutt_set_parameter ("format", "fixed", &b->parameter);
1678 mutt_set_parameter ("x-action", enc ? "pgp-encrypted" : "pgp-signed",
1684 int pgp_gpgme_check_traditional (FILE * fp, BODY * b, int tagged_only)
1689 for (; b; b = b->next) {
1690 if (is_multipart (b))
1691 rv = (pgp_gpgme_check_traditional (fp, b->parts, tagged_only) || rv);
1692 else if (b->type == TYPETEXT) {
1693 if ((r = mutt_is_application_pgp (b)))
1696 rv = (pgp_check_traditional_one_body (fp, b, tagged_only) || rv);
1704 * Implementation of `application_handler'.
1708 Copy a clearsigned message, and strip the signature and PGP's
1711 XXX - charset handling: We assume that it is safe to do
1712 character set decoding first, dash decoding second here, while
1713 we do it the other way around in the main handler.
1715 (Note that we aren't worse than Outlook & Cie in this, and also
1716 note that we can successfully handle anything produced by any
1717 existing versions of mutt.) */
1719 static void copy_clearsigned (gpgme_data_t data, STATE * s, char *charset)
1721 char buf[HUGE_STRING];
1722 short complete, armor_header;
1727 fname = data_object_to_tempfile (data, &fp);
1733 fc = fgetconv_open (fp, charset, Charset, M_ICONV_HOOK_FROM);
1735 for (complete = 1, armor_header = 1;
1736 fgetconvs (buf, sizeof (buf), fc) != NULL;
1737 complete = strchr (buf, '\n') != NULL) {
1740 state_puts (buf, s);
1744 if (!str_cmp (buf, "-----BEGIN PGP SIGNATURE-----\n"))
1754 state_puts (s->prefix, s);
1756 if (buf[0] == '-' && buf[1] == ' ')
1757 state_puts (buf + 2, s);
1759 state_puts (buf, s);
1762 fgetconv_close (&fc);
1767 /* Support for classic_application/pgp */
1768 int pgp_gpgme_application_handler (BODY * m, STATE * s)
1770 int needpass = -1, pgp_keyblock = 0;
1774 off_t last_pos, offset;
1775 char buf[HUGE_STRING];
1776 FILE *pgpout = NULL;
1778 gpgme_error_t err = 0;
1779 gpgme_data_t armored_data = NULL;
1781 short maybe_goodsig = 1;
1782 short have_any_sigs = 0;
1784 char body_charset[STRING]; /* Only used for clearsigned messages. */
1786 debug_print (2, ("Entering pgp_application_pgp handler\n"));
1788 /* For clearsigned messages we won't be able to get a character set
1789 but we know that this may only be text thus we assume Latin-1
1791 if (!mutt_get_body_charset (body_charset, sizeof (body_charset), m))
1792 strfcpy (body_charset, "iso-8859-1", sizeof body_charset);
1794 fseeko (s->fpin, m->offset, 0);
1795 last_pos = m->offset;
1797 for (bytes = m->length; bytes > 0;) {
1798 if (fgets (buf, sizeof (buf), s->fpin) == NULL)
1801 offset = ftello (s->fpin);
1802 bytes -= (offset - last_pos); /* don't rely on m_strlen(buf) */
1805 if (!str_ncmp ("-----BEGIN PGP ", buf, 15)) {
1807 start_pos = last_pos;
1809 if (!str_cmp ("MESSAGE-----\n", buf + 15))
1811 else if (!str_cmp ("SIGNED MESSAGE-----\n", buf + 15)) {
1815 else if (!option (OPTDONTHANDLEPGPKEYS) &&
1816 !str_cmp ("PUBLIC KEY BLOCK-----\n", buf + 15)) {
1821 /* XXX - we may wish to recode here */
1823 state_puts (s->prefix, s);
1824 state_puts (buf, s);
1828 have_any_sigs = (have_any_sigs || (clearsign && (s->flags & M_VERIFY)));
1830 /* Copy PGP material to an data container */
1831 armored_data = create_gpgme_data ();
1832 gpgme_data_write (armored_data, buf, m_strlen(buf));
1833 while (bytes > 0 && fgets (buf, sizeof (buf) - 1, s->fpin) != NULL) {
1834 offset = ftello (s->fpin);
1835 bytes -= (offset - last_pos); /* don't rely on m_strlen(buf) */
1838 gpgme_data_write (armored_data, buf, m_strlen(buf));
1840 if ((needpass && !str_cmp ("-----END PGP MESSAGE-----\n", buf))
1842 && (!str_cmp ("-----END PGP SIGNATURE-----\n", buf)
1843 || !str_cmp ("-----END PGP PUBLIC KEY BLOCK-----\n",
1848 /* Invoke PGP if needed */
1849 if (!clearsign || (s->flags & M_VERIFY)) {
1850 unsigned int sig_stat = 0;
1851 gpgme_data_t plaintext;
1854 plaintext = create_gpgme_data ();
1855 ctx = create_gpgme_context (0);
1858 err = gpgme_op_verify (ctx, armored_data, NULL, plaintext);
1860 err = gpgme_op_decrypt_verify (ctx, armored_data, plaintext);
1861 if (gpg_err_code (err) == GPG_ERR_NO_DATA) {
1862 /* Decrypt verify can't handle signed only messages. */
1863 err = (gpgme_data_seek (armored_data, 0, SEEK_SET) == -1)
1864 ? gpgme_error_from_errno (errno) : 0;
1865 /* Must release plaintext so that we supply an
1866 uninitialized object. */
1867 gpgme_data_release (plaintext);
1868 plaintext = create_gpgme_data ();
1869 err = gpgme_op_verify (ctx, armored_data, NULL, plaintext);
1876 snprintf (errbuf, sizeof (errbuf) - 1,
1877 _("Error: decryption/verification failed: %s\n"),
1878 gpgme_strerror (err));
1879 state_attach_puts (errbuf, s);
1881 else { /* Decryption/Verification succeeded */
1885 /* Check wether signatures have been verified. */
1886 gpgme_verify_result_t verify_result;
1888 verify_result = gpgme_op_verify_result (ctx);
1889 if (verify_result->signatures)
1895 if ((s->flags & M_DISPLAY) && sig_stat) {
1900 state_attach_puts (_("[-- Begin signature "
1901 "information --]\n"), s);
1904 (res = show_one_sig_status (ctx, idx, s)) != -1; idx++) {
1913 state_attach_puts (_("[-- End signature "
1914 "information --]\n\n"), s);
1917 tmpfname = data_object_to_tempfile (plaintext, &pgpout);
1920 state_attach_puts (_("Error: copy data failed\n"), s);
1924 p_delete(&tmpfname);
1927 gpgme_release (ctx);
1931 * Now, copy cleartext to the screen. NOTE - we expect that PGP
1932 * outputs utf-8 cleartext. This may not always be true, but it
1933 * seems to be a reasonable guess.
1936 if (s->flags & M_DISPLAY) {
1938 state_attach_puts (_("[-- BEGIN PGP MESSAGE --]\n\n"), s);
1939 else if (pgp_keyblock)
1940 state_attach_puts (_("[-- BEGIN PGP PUBLIC KEY BLOCK --]\n"), s);
1942 state_attach_puts (_("[-- BEGIN PGP SIGNED MESSAGE --]\n\n"), s);
1946 copy_clearsigned (armored_data, s, body_charset);
1953 fc = fgetconv_open (pgpout, "utf-8", Charset, 0);
1954 while ((c = fgetconv (fc)) != EOF) {
1956 if (c == '\n' && s->prefix)
1957 state_puts (s->prefix, s);
1959 fgetconv_close (&fc);
1962 if (s->flags & M_DISPLAY) {
1963 state_putc ('\n', s);
1965 state_attach_puts (_("[-- END PGP MESSAGE --]\n"), s);
1966 else if (pgp_keyblock)
1967 state_attach_puts (_("[-- END PGP PUBLIC KEY BLOCK --]\n"), s);
1969 state_attach_puts (_("[-- END PGP SIGNED MESSAGE --]\n"), s);
1973 safe_fclose (&pgpout);
1977 /* XXX - we may wish to recode here */
1979 state_puts (s->prefix, s);
1980 state_puts (buf, s);
1984 m->goodsig = (maybe_goodsig && have_any_sigs);
1986 if (needpass == -1) {
1987 state_attach_puts (_("[-- Error: could not find beginning"
1988 " of PGP message! --]\n\n"), s);
1991 debug_print (2, ("Leaving pgp_application_pgp handler\n"));
1996 * Implementation of `encrypted_handler'.
1999 /* MIME handler for pgp/mime encrypted messages. */
2000 int pgp_gpgme_encrypted_handler (BODY * a, STATE * s)
2002 char tempfile[_POSIX_PATH_MAX];
2005 BODY *orig_body = a;
2009 debug_print (2, ("Entering pgp_encrypted handler\n"));
2011 if (!a || a->type != TYPEAPPLICATION || !a->subtype
2012 || ascii_strcasecmp ("pgp-encrypted", a->subtype)
2013 || !a->next || a->next->type != TYPEAPPLICATION || !a->next->subtype
2014 || ascii_strcasecmp ("octet-stream", a->next->subtype)) {
2015 if (s->flags & M_DISPLAY)
2016 state_attach_puts (_("[-- Error: malformed PGP/MIME message! --]\n\n"),
2021 /* Move forward to the application/pgp-encrypted body. */
2024 mutt_mktemp (tempfile);
2025 if (!(fpout = safe_fopen (tempfile, "w+"))) {
2026 if (s->flags & M_DISPLAY)
2027 state_attach_puts (_("[-- Error: could not create temporary file! "
2032 tattach = decrypt_part (a, s, fpout, 0, &is_signed);
2034 tattach->goodsig = is_signed > 0;
2036 if (s->flags & M_DISPLAY)
2037 state_attach_puts (is_signed ?
2039 ("[-- The following data is PGP/MIME signed and encrypted --]\n\n") :
2040 _("[-- The following data is PGP/MIME encrypted --]\n\n"), s);
2043 FILE *savefp = s->fpin;
2046 rc = mutt_body_handler (tattach, s);
2051 * if a multipart/signed is the _only_ sub-part of a
2052 * multipart/encrypted, cache signature verification
2055 if (mutt_is_multipart_signed (tattach) && !tattach->next)
2056 orig_body->goodsig |= tattach->goodsig;
2058 if (s->flags & M_DISPLAY) {
2059 state_puts ("\n", s);
2060 state_attach_puts (is_signed ?
2062 ("[-- End of PGP/MIME signed and encrypted data --]\n")
2063 : _("[-- End of PGP/MIME encrypted data --]\n"), s);
2066 mutt_free_body (&tattach);
2070 mutt_unlink (tempfile);
2071 debug_print (2, ("Leaving pgp_encrypted handler\n"));
2075 /* Support for application/smime */
2076 int smime_gpgme_application_handler (BODY * a, STATE * s)
2078 char tempfile[_POSIX_PATH_MAX];
2084 debug_print (2, ("Entering smime_encrypted handler\n"));
2087 mutt_mktemp (tempfile);
2088 if (!(fpout = safe_fopen (tempfile, "w+"))) {
2089 if (s->flags & M_DISPLAY)
2090 state_attach_puts (_("[-- Error: could not create temporary file! "
2095 tattach = decrypt_part (a, s, fpout, 1, &is_signed);
2097 tattach->goodsig = is_signed > 0;
2099 if (s->flags & M_DISPLAY)
2100 state_attach_puts (is_signed ?
2101 _("[-- The following data is S/MIME signed --]\n\n") :
2102 _("[-- The following data is S/MIME encrypted --]\n\n"), s);
2105 FILE *savefp = s->fpin;
2108 rc = mutt_body_handler (tattach, s);
2113 * if a multipart/signed is the _only_ sub-part of a
2114 * multipart/encrypted, cache signature verification
2117 if (mutt_is_multipart_signed (tattach) && !tattach->next) {
2118 if (!(a->goodsig = tattach->goodsig))
2119 a->warnsig = tattach->warnsig;
2121 else if (tattach->goodsig) {
2123 a->warnsig = tattach->warnsig;
2126 if (s->flags & M_DISPLAY) {
2127 state_puts ("\n", s);
2128 state_attach_puts (is_signed ?
2129 _("[-- End of S/MIME signed data --]\n") :
2130 _("[-- End of S/MIME encrypted data --]\n"), s);
2133 mutt_free_body (&tattach);
2137 mutt_unlink (tempfile);
2138 debug_print (2, ("Leaving smime_encrypted handler\n"));
2144 * Format an entry on the CRYPT key selection menu.
2147 * %k key id %K key id of the principal key
2149 * %a algorithm %A algorithm of the princ. key
2150 * %l length %L length of the princ. key
2151 * %f flags %F flags of the princ. key
2152 * %c capabilities %C capabilities of the princ. key
2153 * %t trust/validity of the key-uid association
2155 * %[...] date of key using strftime(3)
2158 static const char *crypt_entry_fmt (char *dest,
2163 const char *ifstring,
2164 const char *elsestring,
2165 unsigned long data, format_flag flags)
2168 crypt_entry_t *entry;
2171 int optional = (flags & M_FORMAT_OPTIONAL);
2172 const char *s = NULL;
2175 entry = (crypt_entry_t *) data;
2178 /* if (isupper ((unsigned char) op)) */
2181 kflags = (key->flags /*| (pkey->flags & KEYFLAG_RESTRICTIONS)
2184 switch (ascii_tolower (op)) {
2188 char buf2[SHORT_STRING], *p;
2204 while (len > 0 && *cp != ']') {
2213 break; /* not enough space */
2223 if (do_locales && Locale)
2224 setlocale (LC_TIME, Locale);
2229 if (key->kobj->subkeys && (key->kobj->subkeys->timestamp > 0))
2230 tt = key->kobj->subkeys->timestamp;
2232 tm = localtime (&tt);
2234 strftime (buf2, sizeof (buf2), dest, tm);
2237 setlocale (LC_TIME, "C");
2239 snprintf (fmt, sizeof (fmt), "%%%ss", prefix);
2240 snprintf (dest, destlen, fmt, buf2);
2247 snprintf (fmt, sizeof (fmt), "%%%sd", prefix);
2248 snprintf (dest, destlen, fmt, entry->num);
2253 /* fixme: we need a way to distinguish between main and subkeys.
2254 Store the idx in entry? */
2255 snprintf (fmt, sizeof (fmt), "%%%ss", prefix);
2256 snprintf (dest, destlen, fmt, crypt_keyid (key));
2261 snprintf (fmt, sizeof (fmt), "%%%ss", prefix);
2262 snprintf (dest, destlen, fmt, key->uid);
2267 snprintf (fmt, sizeof (fmt), "%%%s.3s", prefix);
2268 if (key->kobj->subkeys)
2269 s = gpgme_pubkey_algo_name (key->kobj->subkeys->pubkey_algo);
2272 snprintf (dest, destlen, fmt, s);
2277 snprintf (fmt, sizeof (fmt), "%%%slu", prefix);
2278 if (key->kobj->subkeys)
2279 val = key->kobj->subkeys->length;
2282 snprintf (dest, destlen, fmt, val);
2287 snprintf (fmt, sizeof (fmt), "%%%sc", prefix);
2288 snprintf (dest, destlen, fmt, crypt_flags (kflags));
2290 else if (!(kflags & (KEYFLAG_RESTRICTIONS)))
2295 snprintf (fmt, sizeof (fmt), "%%%ss", prefix);
2296 snprintf (dest, destlen, fmt, crypt_key_abilities (kflags));
2298 else if (!(kflags & (KEYFLAG_ABILITIES)))
2302 if ((kflags & KEYFLAG_ISX509))
2305 gpgme_user_id_t uid = NULL;
2308 for (i = 0, uid = key->kobj->uids; uid && (i < key->idx);
2309 i++, uid = uid->next);
2311 switch (uid->validity) {
2312 case GPGME_VALIDITY_UNDEFINED:
2315 case GPGME_VALIDITY_NEVER:
2318 case GPGME_VALIDITY_MARGINAL:
2321 case GPGME_VALIDITY_FULL:
2324 case GPGME_VALIDITY_ULTIMATE:
2327 case GPGME_VALIDITY_UNKNOWN:
2333 snprintf (fmt, sizeof (fmt), "%%%sc", prefix);
2334 snprintf (dest, destlen, fmt, s ? *s : 'B');
2337 snprintf (fmt, sizeof (fmt), "%%%ss", prefix);
2338 snprintf (dest, destlen, fmt,
2339 gpgme_get_protocol_name (key->kobj->protocol));
2347 mutt_FormatString (dest, destlen, ifstring, mutt_attach_fmt, data, 0);
2348 else if (flags & M_FORMAT_OPTIONAL)
2349 mutt_FormatString (dest, destlen, elsestring, mutt_attach_fmt, data, 0);
2353 /* Used by the display fucntion to format a line. */
2354 static void crypt_entry (char *s, size_t l, MUTTMENU * menu, int num)
2356 crypt_key_t **key_table = (crypt_key_t **) menu->data;
2357 crypt_entry_t entry;
2359 entry.key = key_table[num];
2360 entry.num = num + 1;
2362 mutt_FormatString (s, l, NONULL (PgpEntryFormat), crypt_entry_fmt,
2363 (unsigned long) &entry, M_FORMAT_ARROWCURSOR);
2366 /* Compare two addresses and the keyid to be used for sorting. */
2367 static int _crypt_compare_address (const void *a, const void *b)
2369 crypt_key_t **s = (crypt_key_t **) a;
2370 crypt_key_t **t = (crypt_key_t **) b;
2373 if ((r = str_casecmp ((*s)->uid, (*t)->uid)))
2376 return str_casecmp (crypt_keyid (*s), crypt_keyid (*t)) > 0;
2379 static int crypt_compare_address (const void *a, const void *b)
2381 return ((PgpSortKeys & SORT_REVERSE) ? !_crypt_compare_address (a, b)
2382 : _crypt_compare_address (a, b));
2386 /* Compare two key IDs and the addresses to be used for sorting. */
2387 static int _crypt_compare_keyid (const void *a, const void *b)
2389 crypt_key_t **s = (crypt_key_t **) a;
2390 crypt_key_t **t = (crypt_key_t **) b;
2393 if ((r = str_casecmp (crypt_keyid (*s), crypt_keyid (*t))))
2396 return str_casecmp ((*s)->uid, (*t)->uid) > 0;
2399 static int crypt_compare_keyid (const void *a, const void *b)
2401 return ((PgpSortKeys & SORT_REVERSE) ? !_crypt_compare_keyid (a, b)
2402 : _crypt_compare_keyid (a, b));
2405 /* Compare 2 creation dates and the addresses. For sorting. */
2406 static int _crypt_compare_date (const void *a, const void *b)
2408 crypt_key_t **s = (crypt_key_t **) a;
2409 crypt_key_t **t = (crypt_key_t **) b;
2410 unsigned long ts = 0, tt = 0;
2412 if ((*s)->kobj->subkeys && ((*s)->kobj->subkeys->timestamp > 0))
2413 ts = (*s)->kobj->subkeys->timestamp;
2414 if ((*t)->kobj->subkeys && ((*t)->kobj->subkeys->timestamp > 0))
2415 tt = (*t)->kobj->subkeys->timestamp;
2422 return str_casecmp ((*s)->uid, (*t)->uid) > 0;
2425 static int crypt_compare_date (const void *a, const void *b)
2427 return ((PgpSortKeys & SORT_REVERSE) ? !_crypt_compare_date (a, b)
2428 : _crypt_compare_date (a, b));
2431 /* Compare two trust values, the key length, the creation dates. the
2432 addresses and the key IDs. For sorting. */
2433 static int _crypt_compare_trust (const void *a, const void *b)
2435 crypt_key_t **s = (crypt_key_t **) a;
2436 crypt_key_t **t = (crypt_key_t **) b;
2437 unsigned long ts = 0, tt = 0;
2440 if ((r = (((*s)->flags & (KEYFLAG_RESTRICTIONS))
2441 - ((*t)->flags & (KEYFLAG_RESTRICTIONS)))))
2444 if ((*s)->kobj->uids)
2445 ts = (*s)->kobj->uids->validity;
2446 if ((*t)->kobj->uids)
2447 tt = (*t)->kobj->uids->validity;
2448 if ((r = (tt - ts)))
2451 if ((*s)->kobj->subkeys)
2452 ts = (*s)->kobj->subkeys->length;
2453 if ((*t)->kobj->subkeys)
2454 tt = (*t)->kobj->subkeys->length;
2458 if ((*s)->kobj->subkeys && ((*s)->kobj->subkeys->timestamp > 0))
2459 ts = (*s)->kobj->subkeys->timestamp;
2460 if ((*t)->kobj->subkeys && ((*t)->kobj->subkeys->timestamp > 0))
2461 tt = (*t)->kobj->subkeys->timestamp;
2467 if ((r = str_casecmp ((*s)->uid, (*t)->uid)))
2469 return (str_casecmp (crypt_keyid ((*s)), crypt_keyid ((*t)))) > 0;
2472 static int crypt_compare_trust (const void *a, const void *b)
2474 return ((PgpSortKeys & SORT_REVERSE) ? !_crypt_compare_trust (a, b)
2475 : _crypt_compare_trust (a, b));
2478 /* Print the X.500 Distinguished Name part KEY from the array of parts
2480 static int print_dn_part (FILE * fp, struct dn_array_s *dn, const char *key)
2484 for (; dn->key; dn++) {
2485 if (!str_cmp (dn->key, key)) {
2488 print_utf8 (fp, dn->value, m_strlen(dn->value));
2495 /* Print all parts of a DN in a standard sequence. */
2496 static void print_dn_parts (FILE * fp, struct dn_array_s *dn)
2498 const char *stdpart[] = {
2499 "CN", "OU", "O", "STREET", "L", "ST", "C", NULL
2501 int any = 0, any2 = 0, i;
2503 for (i = 0; stdpart[i]; i++) {
2506 any = print_dn_part (fp, dn, stdpart[i]);
2508 /* now print the rest without any specific ordering */
2509 for (; dn->key; dn++) {
2510 for (i = 0; stdpart[i]; i++) {
2511 if (!str_cmp (dn->key, stdpart[i]))
2519 any = print_dn_part (fp, dn, dn->key);
2528 /* Parse an RDN; this is a helper to parse_dn(). */
2529 static const unsigned char *parse_dn_part (struct dn_array_s *array,
2530 const unsigned char *string)
2532 const unsigned char *s, *s1;
2536 /* parse attributeType */
2537 for (s = string + 1; *s && *s != '='; s++);
2539 return NULL; /* error */
2542 return NULL; /* empty key */
2543 array->key = p_dupstr(string, n );
2544 p = (unsigned char *) array->key;
2547 if (*string == '#') { /* hexstring */
2549 for (s = string; hexdigitp (s); s++)
2553 return NULL; /* empty or odd number of digits */
2556 array->value = (char *) p;
2557 for (s1 = string; n; s1 += 2, n--)
2561 else { /* regular v3 quoted string */
2562 for (n = 0, s = string; *s; s++) {
2563 if (*s == '\\') { /* pair */
2565 if (*s == ',' || *s == '=' || *s == '+'
2566 || *s == '<' || *s == '>' || *s == '#' || *s == ';'
2567 || *s == '\\' || *s == '\"' || *s == ' ')
2569 else if (hexdigitp (s) && hexdigitp (s + 1)) {
2574 return NULL; /* invalid escape sequence */
2576 else if (*s == '\"')
2577 return NULL; /* invalid encoding */
2578 else if (*s == ',' || *s == '=' || *s == '+'
2579 || *s == '<' || *s == '>' || *s == '#' || *s == ';')
2586 array->value = (char *) p;
2587 for (s = string; n; s++, n--) {
2590 if (hexdigitp (s)) {
2606 /* Parse a DN and return an array-ized one. This is not a validating
2607 parser and it does not support any old-stylish syntax; gpgme is
2608 expected to return only rfc2253 compatible strings. */
2609 static struct dn_array_s *parse_dn (const unsigned char *string)
2611 struct dn_array_s *array;
2612 size_t arrayidx, arraysize;
2615 arraysize = 7; /* C,ST,L,O,OU,CN,email */
2616 array = p_new(struct dn_array_s, arraysize + 1);
2619 while (*string == ' ')
2623 if (arrayidx >= arraysize) { /* mutt lacks a real safe_realoc - so we need to copy */
2624 struct dn_array_s *a2;
2627 a2 = p_new(struct dn_array_s, arraysize + 1);
2628 for (i = 0; i < arrayidx; i++) {
2629 a2[i].key = array[i].key;
2630 a2[i].value = array[i].value;
2635 array[arrayidx].key = NULL;
2636 array[arrayidx].value = NULL;
2637 string = parse_dn_part (array + arrayidx, string);
2641 while (*string == ' ')
2643 if (*string && *string != ',' && *string != ';' && *string != '+')
2644 goto failure; /* invalid delimiter */
2648 array[arrayidx].key = NULL;
2649 array[arrayidx].value = NULL;
2653 for (i = 0; i < arrayidx; i++) {
2654 p_delete(&array[i].key);
2655 p_delete(&array[i].value);
2662 /* Print a nice representation of the USERID and make sure it is
2663 displayed in a proper way, which does mean to reorder some parts
2664 for S/MIME's DNs. USERID is a string as returned by the gpgme key
2665 functions. It is utf-8 encoded. */
2666 static void parse_and_print_user_id (FILE * fp, const char *userid)
2671 if (*userid == '<') {
2672 s = strchr (userid + 1, '>');
2674 print_utf8 (fp, userid + 1, s - userid - 1);
2676 else if (*userid == '(')
2677 fputs (_("[Can't display this user ID (unknown encoding)]"), fp);
2678 else if (!digit_or_letter ((const unsigned char *) userid))
2679 fputs (_("[Can't display this user ID (invalid encoding)]"), fp);
2681 struct dn_array_s *dn = parse_dn ((const unsigned char *) userid);
2684 fputs (_("[Can't display this user ID (invalid DN)]"), fp);
2686 print_dn_parts (fp, dn);
2687 for (i = 0; dn[i].key; i++) {
2688 p_delete(&dn[i].key);
2689 p_delete(&dn[i].value);
2697 KEY_CAP_CAN_ENCRYPT,
2702 static unsigned int key_check_cap (gpgme_key_t key, key_cap_t cap)
2704 gpgme_subkey_t subkey = NULL;
2705 unsigned int ret = 0;
2708 case KEY_CAP_CAN_ENCRYPT:
2709 if (!(ret = key->can_encrypt))
2710 for (subkey = key->subkeys; subkey; subkey = subkey->next)
2711 if ((ret = subkey->can_encrypt))
2714 case KEY_CAP_CAN_SIGN:
2715 if (!(ret = key->can_sign))
2716 for (subkey = key->subkeys; subkey; subkey = subkey->next)
2717 if ((ret = subkey->can_sign))
2720 case KEY_CAP_CAN_CERTIFY:
2721 if (!(ret = key->can_certify))
2722 for (subkey = key->subkeys; subkey; subkey = subkey->next)
2723 if ((ret = subkey->can_certify))
2732 /* Print verbose information about a key or certificate to FP. */
2733 static void print_key_info (gpgme_key_t key, FILE * fp)
2736 const char *s = NULL, *s2 = NULL;
2739 char shortbuf[SHORT_STRING];
2740 unsigned long aval = 0;
2744 gpgme_user_id_t uid = NULL;
2747 setlocale (LC_TIME, Locale);
2749 is_pgp = key->protocol == GPGME_PROTOCOL_OpenPGP;
2751 for (idx = 0, uid = key->uids; uid; idx++, uid = uid->next) {
2756 fputs (idx ? _(" aka ......: ") :_("Name ......: "), fp);
2759 fputs (_("[Invalid]"), fp);
2763 print_utf8 (fp, s, m_strlen(s));
2765 parse_and_print_user_id (fp, s);
2769 if (key->subkeys && (key->subkeys->timestamp > 0)) {
2770 tt = key->subkeys->timestamp;
2772 tm = localtime (&tt);
2773 #ifdef HAVE_LANGINFO_D_T_FMT
2774 strftime (shortbuf, sizeof shortbuf, nl_langinfo (D_T_FMT), tm);
2776 strftime (shortbuf, sizeof shortbuf, "%c", tm);
2778 fprintf (fp, _("Valid From : %s\n"), shortbuf);
2781 if (key->subkeys && (key->subkeys->expires > 0)) {
2782 tt = key->subkeys->expires;
2784 tm = localtime (&tt);
2785 #ifdef HAVE_LANGINFO_D_T_FMT
2786 strftime (shortbuf, sizeof shortbuf, nl_langinfo (D_T_FMT), tm);
2788 strftime (shortbuf, sizeof shortbuf, "%c", tm);
2790 fprintf (fp, _("Valid To ..: %s\n"), shortbuf);
2794 s = gpgme_pubkey_algo_name (key->subkeys->pubkey_algo);
2798 s2 = is_pgp ? "PGP" : "X.509";
2801 aval = key->subkeys->length;
2803 fprintf (fp, _("Key Type ..: %s, %lu bit %s\n"), s2, aval, s);
2805 fprintf (fp, _("Key Usage .: "));
2808 if (key_check_cap (key, KEY_CAP_CAN_ENCRYPT)) {
2809 fprintf (fp, "%s%s", delim, _("encryption"));
2812 if (key_check_cap (key, KEY_CAP_CAN_SIGN)) {
2813 fprintf (fp, "%s%s", delim, _("signing"));
2816 if (key_check_cap (key, KEY_CAP_CAN_CERTIFY)) {
2817 fprintf (fp, "%s%s", delim, _("certification"));
2823 s = key->subkeys->fpr;
2824 fputs (_("Fingerprint: "), fp);
2825 if (is_pgp && m_strlen(s) == 40) {
2826 for (i = 0; *s && s[1] && s[2] && s[3] && s[4]; s += 4, i++) {
2831 putc (is_pgp ? ' ' : ':', fp);
2832 if (is_pgp && i == 4)
2837 for (i = 0; *s && s[1] && s[2]; s += 2, i++) {
2840 putc (is_pgp ? ' ' : ':', fp);
2841 if (is_pgp && i == 7)
2845 fprintf (fp, "%s\n", s);
2848 if (key->issuer_serial) {
2849 s = key->issuer_serial;
2851 fprintf (fp, _("Serial-No .: 0x%s\n"), s);
2854 if (key->issuer_name) {
2855 s = key->issuer_name;
2857 fprintf (fp, _("Issued By .: "));
2858 parse_and_print_user_id (fp, s);
2863 /* For PGP we list all subkeys. */
2865 gpgme_subkey_t subkey = NULL;
2867 for (idx = 1, subkey = key->subkeys; subkey; idx++, subkey = subkey->next) {
2871 if (m_strlen(s) == 16)
2872 s += 8; /* display only the short keyID */
2873 fprintf (fp, _("Subkey ....: 0x%s"), s);
2874 if (subkey->revoked) {
2876 fputs (_("[Revoked]"), fp);
2878 if (subkey->invalid) {
2880 fputs (_("[Invalid]"), fp);
2882 if (subkey->expired) {
2884 fputs (_("[Expired]"), fp);
2886 if (subkey->disabled) {
2888 fputs (_("[Disabled]"), fp);
2892 if (subkey->timestamp > 0) {
2893 tt = subkey->timestamp;
2895 tm = localtime (&tt);
2896 #ifdef HAVE_LANGINFO_D_T_FMT
2897 strftime (shortbuf, sizeof shortbuf, nl_langinfo (D_T_FMT), tm);
2899 strftime (shortbuf, sizeof shortbuf, "%c", tm);
2901 fprintf (fp, _("Valid From : %s\n"), shortbuf);
2904 if (subkey->expires > 0) {
2905 tt = subkey->expires;
2907 tm = localtime (&tt);
2908 #ifdef HAVE_LANGINFO_D_T_FMT
2909 strftime (shortbuf, sizeof shortbuf, nl_langinfo (D_T_FMT), tm);
2911 strftime (shortbuf, sizeof shortbuf, "%c", tm);
2913 fprintf (fp, _("Valid To ..: %s\n"), shortbuf);
2917 s = gpgme_pubkey_algo_name (subkey->pubkey_algo);
2922 aval = subkey->length;
2926 fprintf (fp, _("Key Type ..: %s, %lu bit %s\n"), "PGP", aval, s);
2928 fprintf (fp, _("Key Usage .: "));
2931 if (subkey->can_encrypt) {
2932 fprintf (fp, "%s%s", delim, _("encryption"));
2935 if (subkey->can_sign) {
2936 fprintf (fp, "%s%s", delim, _("signing"));
2939 if (subkey->can_certify) {
2940 fprintf (fp, "%s%s", delim, _("certification"));
2948 setlocale (LC_TIME, "C");
2952 /* Show detailed information about the selected key */
2953 static void verify_key (crypt_key_t * key)
2956 char cmd[LONG_STRING], tempfile[_POSIX_PATH_MAX];
2958 gpgme_ctx_t listctx = NULL;
2960 gpgme_key_t k = NULL;
2963 mutt_mktemp (tempfile);
2964 if (!(fp = safe_fopen (tempfile, "w"))) {
2965 mutt_perror (_("Can't create temporary file"));
2969 mutt_message _("Collecting data...");
2971 print_key_info (key->kobj, fp);
2973 err = gpgme_new (&listctx);
2975 fprintf (fp, "Internal error: can't create gpgme context: %s\n",
2976 gpgme_strerror (err));
2979 if ((key->flags & KEYFLAG_ISX509))
2980 gpgme_set_protocol (listctx, GPGME_PROTOCOL_CMS);
2984 while ((s = k->chain_id) && k->subkeys && str_cmp (s, k->subkeys->fpr)) {
2986 err = gpgme_op_keylist_start (listctx, s, 0);
2987 gpgme_key_release (k);
2990 err = gpgme_op_keylist_next (listctx, &k);
2992 fprintf (fp, _("Error finding issuer key: %s\n"), gpgme_strerror (err));
2995 gpgme_op_keylist_end (listctx);
2997 print_key_info (k, fp);
3000 fputs (_("Error: certification chain to long - stopping here\n"), fp);
3006 gpgme_key_release (k);
3007 gpgme_release (listctx);
3009 mutt_clear_error ();
3010 snprintf (cmd, sizeof (cmd), _("Key ID: 0x%s"), crypt_keyid (key));
3011 mutt_do_pager (cmd, tempfile, 0, NULL);
3015 * Implementation of `findkeys'.
3019 /* Convert LIST into a pattern string suitable to be passed to GPGME.
3020 We need to convert spaces in an item into a '+' and '%' into
3022 static char *list_to_pattern (LIST * list)
3030 for (l = list; l; l = l->next) {
3031 for (s = l->data; *s; s++) {
3036 n++; /* delimiter or end of string */
3038 n++; /* make sure to allocate at least one byte */
3039 pattern = p = p_new(char, n);
3040 for (l = list; l; l = l->next) {
3045 for (s = l->data; *s; s++) {
3051 else if (*s == '+') {
3067 /* Return a list of keys which are candidates for the selection.
3068 Select by looking at the HINTS list. */
3069 static crypt_key_t *get_candidates (LIST * hints, unsigned int app,
3072 crypt_key_t *db, *k, **kend;
3078 gpgme_user_id_t uid = NULL;
3080 pattern = list_to_pattern (hints);
3084 err = gpgme_new (&ctx);
3086 mutt_error (_("gpgme_new failed: %s"), gpgme_strerror (err));
3094 if ((app & APPLICATION_PGP)) {
3095 /* Its all a mess. That old GPGME expects different things
3096 depending on the protocol. For gpg we don' t need percent
3097 escaped pappert but simple strings passed in an array to the
3098 keylist_ext_start function. */
3103 for (l = hints, n = 0; l; l = l->next) {
3104 if (l->data && *l->data)
3110 patarr = p_new(char *, n + 1);
3111 for (l = hints, n = 0; l; l = l->next) {
3112 if (l->data && *l->data)
3113 patarr[n++] = m_strdup(l->data);
3116 err = gpgme_op_keylist_ext_start (ctx, (const char **) patarr, secret, 0);
3117 for (n = 0; patarr[n]; n++)
3118 p_delete(&patarr[n]);
3121 mutt_error (_("gpgme_op_keylist_start failed: %s"), gpgme_strerror (err));
3122 gpgme_release (ctx);
3127 while (!(err = gpgme_op_keylist_next (ctx, &key))) {
3128 unsigned int flags = 0;
3130 if (key_check_cap (key, KEY_CAP_CAN_ENCRYPT))
3131 flags |= KEYFLAG_CANENCRYPT;
3132 if (key_check_cap (key, KEY_CAP_CAN_SIGN))
3133 flags |= KEYFLAG_CANSIGN;
3135 #if 0 /* DISABLED code */
3137 /* Bug in gpg. Capabilities are not listed for secret
3138 keys. Try to deduce them from the algorithm. */
3140 switch (key->subkeys[0].pubkey_algo) {
3142 flags |= KEYFLAG_CANENCRYPT;
3143 flags |= KEYFLAG_CANSIGN;
3145 case GPGME_PK_ELG_E:
3146 flags |= KEYFLAG_CANENCRYPT;
3149 flags |= KEYFLAG_CANSIGN;
3153 #endif /* DISABLED code */
3155 for (idx = 0, uid = key->uids; uid; idx++, uid = uid->next) {
3156 k = p_new(crypt_key_t, 1);
3165 if (gpg_err_code (err) != GPG_ERR_EOF)
3166 mutt_error (_("gpgme_op_keylist_next failed: %s"), gpgme_strerror (err));
3167 gpgme_op_keylist_end (ctx);
3172 if ((app & APPLICATION_SMIME)) {
3173 /* and now look for x509 certificates */
3174 gpgme_set_protocol (ctx, GPGME_PROTOCOL_CMS);
3175 err = gpgme_op_keylist_start (ctx, pattern, 0);
3177 mutt_error (_("gpgme_op_keylist_start failed: %s"), gpgme_strerror (err));
3178 gpgme_release (ctx);
3183 while (!(err = gpgme_op_keylist_next (ctx, &key))) {
3184 unsigned int flags = KEYFLAG_ISX509;
3186 if (key_check_cap (key, KEY_CAP_CAN_ENCRYPT))
3187 flags |= KEYFLAG_CANENCRYPT;
3188 if (key_check_cap (key, KEY_CAP_CAN_SIGN))
3189 flags |= KEYFLAG_CANSIGN;
3191 for (idx = 0, uid = key->uids; uid; idx++, uid = uid->next) {
3192 k = p_new(crypt_key_t, 1);
3201 if (gpg_err_code (err) != GPG_ERR_EOF)
3202 mutt_error (_("gpgme_op_keylist_next failed: %s"), gpgme_strerror (err));
3203 gpgme_op_keylist_end (ctx);
3206 gpgme_release (ctx);
3211 /* Add the string STR to the list HINTS. This list is later used to
3213 static LIST *crypt_add_string_to_hints (LIST * hints, const char *str)
3218 if ((scratch = m_strdup(str)) == NULL)
3221 for (t = strtok (scratch, " ,.:\"()<>\n"); t;
3222 t = strtok (NULL, " ,.:\"()<>\n")) {
3223 if (m_strlen(t) > 3)
3224 hints = mutt_add_list (hints, t);
3231 /* Display a menu to select a key from the array KEYS. FORCED_VALID
3232 will be set to true on return if the user did override the the
3234 static crypt_key_t *crypt_select_key (crypt_key_t * keys,
3235 ADDRESS * p, const char *s,
3236 unsigned int app, int *forced_valid)
3239 crypt_key_t **key_table;
3242 char helpstr[SHORT_STRING], buf[LONG_STRING];
3244 int (*f) (const void *, const void *);
3245 int menu_to_use = 0;
3250 /* build the key table */
3253 for (k = keys; k; k = k->next) {
3254 if (!option (OPTPGPSHOWUNUSABLE) && (k->flags & KEYFLAG_CANTUSE)) {
3261 p_realloc(&key_table, keymax);
3267 if (!i && unusable) {
3268 mutt_error _("All matching keys are marked expired/revoked.");
3274 switch (PgpSortKeys & SORT_MASK) {
3276 f = crypt_compare_date;
3279 f = crypt_compare_keyid;
3282 f = crypt_compare_address;
3286 f = crypt_compare_trust;
3289 qsort (key_table, i, sizeof (crypt_key_t *), f);
3291 if (app & APPLICATION_PGP)
3292 menu_to_use = MENU_KEY_SELECT_PGP;
3293 else if (app & APPLICATION_SMIME)
3294 menu_to_use = MENU_KEY_SELECT_SMIME;
3297 mutt_make_help (buf, sizeof (buf), _("Exit "), menu_to_use, OP_EXIT);
3298 strcat (helpstr, buf); /* __STRCAT_CHECKED__ */
3299 mutt_make_help (buf, sizeof (buf), _("Select "), menu_to_use,
3300 OP_GENERIC_SELECT_ENTRY);
3301 strcat (helpstr, buf); /* __STRCAT_CHECKED__ */
3302 mutt_make_help (buf, sizeof (buf), _("Check key "),
3303 menu_to_use, OP_VERIFY_KEY);
3304 strcat (helpstr, buf); /* __STRCAT_CHECKED__ */
3305 mutt_make_help (buf, sizeof (buf), _("Help"), menu_to_use, OP_HELP);
3306 strcat (helpstr, buf); /* __STRCAT_CHECKED__ */
3308 menu = mutt_new_menu ();
3310 menu->make_entry = crypt_entry;
3311 menu->menu = menu_to_use;
3312 menu->help = helpstr;
3313 menu->data = key_table;
3318 if ((app & APPLICATION_PGP) && (app & APPLICATION_SMIME))
3319 ts = _("PGP and S/MIME keys matching");
3320 else if ((app & APPLICATION_PGP))
3321 ts = _("PGP keys matching");
3322 else if ((app & APPLICATION_SMIME))
3323 ts = _("S/MIME keys matching");
3325 ts = _("keys matching");
3328 snprintf (buf, sizeof (buf), _("%s <%s>."), ts, p->mailbox);
3330 snprintf (buf, sizeof (buf), _("%s \"%s\"."), ts, s);
3334 mutt_clear_error ();
3338 switch (mutt_menuLoop (menu)) {
3340 verify_key (key_table[menu->current]);
3341 menu->redraw = REDRAW_FULL;
3345 mutt_message ("%s", key_table[menu->current]->uid);
3348 case OP_GENERIC_SELECT_ENTRY:
3349 /* FIXME make error reporting more verbose - this should be
3350 easy because gpgme provides more information */
3351 if (option (OPTPGPCHECKTRUST)) {
3352 if (!crypt_key_is_valid (key_table[menu->current])) {
3353 mutt_error _("This key can't be used: "
3354 "expired/disabled/revoked.");
3359 if (option (OPTPGPCHECKTRUST) &&
3360 (!crypt_id_is_valid (key_table[menu->current])
3361 || !crypt_id_is_strong (key_table[menu->current]))) {
3363 char buff[LONG_STRING];
3365 if (key_table[menu->current]->flags & KEYFLAG_CANTUSE)
3366 s = N_("ID is expired/disabled/revoked.");
3368 gpgme_validity_t val = GPGME_VALIDITY_UNKNOWN;
3369 gpgme_user_id_t uid = NULL;
3374 uid = key_table[menu->current]->kobj->uids;
3375 for (j = 0; (j < key_table[menu->current]->idx) && uid;
3376 j++, uid = uid->next);
3378 val = uid->validity;
3381 case GPGME_VALIDITY_UNKNOWN:
3382 case GPGME_VALIDITY_UNDEFINED:
3383 warn_s = N_("ID has undefined validity.");
3385 case GPGME_VALIDITY_NEVER:
3386 warn_s = N_("ID is not valid.");
3388 case GPGME_VALIDITY_MARGINAL:
3389 warn_s = N_("ID is only marginally valid.");
3391 case GPGME_VALIDITY_FULL:
3392 case GPGME_VALIDITY_ULTIMATE:
3396 snprintf (buff, sizeof (buff),
3397 _("%s Do you really want to use the key?"), _(warn_s));
3399 if (mutt_yesorno (buff, 0) != 1) {
3400 mutt_clear_error ();
3407 k = crypt_copy_key (key_table[menu->current]);
3418 mutt_menuDestroy (&menu);
3419 p_delete(&key_table);
3421 set_option (OPTNEEDREDRAW);
3426 static crypt_key_t *crypt_getkeybyaddr (ADDRESS * a, short abilities,
3427 unsigned int app, int *forced_valid)
3435 int this_key_has_strong;
3436 int this_key_has_weak;
3437 int this_key_has_invalid;
3440 crypt_key_t *keys, *k;
3441 crypt_key_t *the_valid_key = NULL;
3442 crypt_key_t *matches = NULL;
3443 crypt_key_t **matches_endp = &matches;
3447 if (a && a->mailbox)
3448 hints = crypt_add_string_to_hints (hints, a->mailbox);
3449 if (a && a->personal)
3450 hints = crypt_add_string_to_hints (hints, a->personal);
3452 mutt_message (_("Looking for keys matching \"%s\"..."), a->mailbox);
3453 keys = get_candidates (hints, app, (abilities & KEYFLAG_CANSIGN));
3455 mutt_free_list (&hints);
3460 debug_print (5, ("looking for %s <%s>.\n", a->personal, a->mailbox));
3462 for (k = keys; k; k = k->next) {
3463 debug_print (5, (" looking at key: %s `%.15s'\n", crypt_keyid (k), k->uid));
3465 if (abilities && !(k->flags & abilities)) {
3466 debug_print (5, (" insufficient abilities: Has %x, want %x\n", k->flags, abilities));
3470 this_key_has_weak = 0; /* weak but valid match */
3471 this_key_has_invalid = 0; /* invalid match */
3472 this_key_has_strong = 0; /* strong and valid match */
3473 match = 0; /* any match */
3475 r = rfc822_parse_adrlist (NULL, k->uid);
3476 for (p = r; p; p = p->next) {
3477 int validity = crypt_id_matches_addr (a, p, k);
3479 if (validity & CRYPT_KV_MATCH) /* something matches */
3482 /* is this key a strong candidate? */
3483 if ((validity & CRYPT_KV_VALID)
3484 && (validity & CRYPT_KV_STRONGID)
3485 && (validity & CRYPT_KV_ADDR)) {
3486 if (the_valid_key && the_valid_key != k)
3489 this_key_has_strong = 1;
3491 else if ((validity & CRYPT_KV_MATCH)
3492 && !(validity & CRYPT_KV_VALID))
3493 this_key_has_invalid = 1;
3494 else if ((validity & CRYPT_KV_MATCH)
3495 && (!(validity & CRYPT_KV_STRONGID)
3496 || !(validity & CRYPT_KV_ADDR)))
3497 this_key_has_weak = 1;
3499 rfc822_free_address (&r);
3504 if (!this_key_has_strong && this_key_has_invalid)
3506 if (!this_key_has_strong && this_key_has_weak)
3509 *matches_endp = tmp = crypt_copy_key (k);
3510 matches_endp = &tmp->next;
3511 the_valid_key = tmp;
3515 crypt_free_key (&keys);
3518 if (the_valid_key && !multi && !weak
3519 && !(invalid && option (OPTPGPSHOWUNUSABLE))) {
3521 * There was precisely one strong match on a valid ID, there
3522 * were no valid keys with weak matches, and we aren't
3523 * interested in seeing invalid keys.
3525 * Proceed without asking the user.
3527 k = crypt_copy_key (the_valid_key);
3531 * Else: Ask the user.
3533 k = crypt_select_key (matches, a, NULL, app, forced_valid);
3535 crypt_free_key (&matches);
3544 static crypt_key_t *crypt_getkeybystr (char *p, short abilities,
3545 unsigned int app, int *forced_valid)
3549 crypt_key_t *matches = NULL;
3550 crypt_key_t **matches_endp = &matches;
3554 mutt_message (_("Looking for keys matching \"%s\"..."), p);
3558 hints = crypt_add_string_to_hints (hints, p);
3559 keys = get_candidates (hints, app, (abilities & KEYFLAG_CANSIGN));
3560 mutt_free_list (&hints);
3565 for (k = keys; k; k = k->next) {
3566 if (abilities && !(k->flags & abilities))
3570 debug_print (5, ("matching \"%s\" against " "key %s, \"%s\":\n", p, crypt_keyid (k), k->uid));
3572 if (!*p || !str_casecmp (p, crypt_keyid (k))
3573 || (!str_ncasecmp (p, "0x", 2)
3574 && !str_casecmp (p + 2, crypt_keyid (k)))
3575 || (option (OPTPGPLONGIDS)
3576 && !str_ncasecmp (p, "0x", 2)
3577 && !str_casecmp (p + 2, crypt_keyid (k) + 8))
3578 || str_isstr (k->uid, p)) {
3581 debug_print (5, ("match.\n"));
3583 *matches_endp = tmp = crypt_copy_key (k);
3584 matches_endp = &tmp->next;
3588 crypt_free_key (&keys);
3591 k = crypt_select_key (matches, NULL, p, app, forced_valid);
3592 crypt_free_key (&matches);
3599 /* Display TAG as a prompt to ask for a key. If WHATFOR is not null
3600 use it as default and store it under that label as the next
3601 default. ABILITIES describe the required key abilities (sign,
3602 encrypt) and APP the type of the requested key; ether S/MIME or
3603 PGP. Return a copy of the key or NULL if not found. */
3604 static crypt_key_t *crypt_ask_for_key (char *tag,
3607 unsigned int app, int *forced_valid)
3610 char resp[SHORT_STRING];
3611 struct crypt_cache *l = NULL;
3615 forced_valid = &dummy;
3617 mutt_clear_error ();
3623 for (l = id_defaults; l; l = l->next)
3624 if (!str_casecmp (whatfor, l->what)) {
3625 strfcpy (resp, NONULL (l->dflt), sizeof (resp));
3633 if (mutt_get_field (tag, resp, sizeof (resp), M_CLEAR) != 0)
3638 str_replace (&l->dflt, resp);
3640 l = p_new(struct crypt_cache, 1);
3641 l->next = id_defaults;
3643 l->what = m_strdup(whatfor);
3644 l->dflt = m_strdup(resp);
3648 if ((key = crypt_getkeybystr (resp, abilities, app, forced_valid)))
3656 /* This routine attempts to find the keyids of the recipients of a
3657 message. It returns NULL if any of the keys can not be found. */
3658 static char *find_keys (ADDRESS * to, ADDRESS * cc, ADDRESS * bcc,
3661 char *keyID, *keylist = NULL, *t;
3662 size_t keylist_size = 0;
3663 size_t keylist_used = 0;
3664 ADDRESS *tmp = NULL, *addr = NULL;
3665 ADDRESS **last = &tmp;
3668 crypt_key_t *k_info, *key;
3669 const char *fqdn = mutt_fqdn (1);
3672 *r_application = APPLICATION_PGP | APPLICATION_SMIME;
3675 for (i = 0; i < 3; i++) {
3690 *last = rfc822_cpy_adr (p);
3692 last = &((*last)->next);
3696 rfc822_qualify (tmp, fqdn);
3698 tmp = mutt_remove_duplicates (tmp);
3700 for (p = tmp; p; p = p->next) {
3701 char buf[LONG_STRING];
3702 int forced_valid = 0;
3707 if ((keyID = mutt_crypt_hook (p)) != NULL) {
3710 snprintf (buf, sizeof (buf), _("Use keyID = \"%s\" for %s?"),
3712 if ((r = mutt_yesorno (buf, M_YES)) == M_YES) {
3713 /* check for e-mail address */
3714 if ((t = strchr (keyID, '@')) &&
3715 (addr = rfc822_parse_adrlist (NULL, keyID))) {
3717 rfc822_qualify (addr, fqdn);
3722 k_info = crypt_getkeybystr (keyID, KEYFLAG_CANENCRYPT,
3723 *r_application, &forced_valid);
3725 k_info = crypt_getkeybystr (keyID, KEYFLAG_CANENCRYPT,
3726 app, &forced_valid);
3732 rfc822_free_address (&tmp);
3733 rfc822_free_address (&addr);
3739 && (k_info = crypt_getkeybyaddr (q, KEYFLAG_CANENCRYPT,
3740 app, &forced_valid)) == NULL) {
3741 snprintf (buf, sizeof (buf), _("Enter keyID for %s: "), q->mailbox);
3743 if ((key = crypt_ask_for_key (buf, q->mailbox, KEYFLAG_CANENCRYPT,
3749 &forced_valid)) == NULL) {
3751 rfc822_free_address (&tmp);
3752 rfc822_free_address (&addr);
3760 const char *s = crypt_fpr (key);
3763 if (key->flags & KEYFLAG_ISX509)
3764 *r_application &= ~APPLICATION_PGP;
3765 if (!(key->flags & KEYFLAG_ISX509))
3766 *r_application &= ~APPLICATION_SMIME;
3769 keylist_size += m_strlen(s) + 4 + 1;
3770 p_realloc(&keylist, keylist_size);
3771 sprintf (keylist + keylist_used, "%s0x%s%s", /* __SPRINTF_CHECKED__ */
3772 keylist_used ? " " : "", s, forced_valid ? "!" : "");
3774 keylist_used = m_strlen(keylist);
3776 crypt_free_key (&key);
3777 rfc822_free_address (&addr);
3779 rfc822_free_address (&tmp);
3783 char *pgp_gpgme_findkeys (ADDRESS * to, ADDRESS * cc, ADDRESS * bcc)
3785 return find_keys (to, cc, bcc, APPLICATION_PGP);
3788 char *smime_gpgme_findkeys (ADDRESS * to, ADDRESS * cc, ADDRESS * bcc)
3790 return find_keys (to, cc, bcc, APPLICATION_SMIME);
3794 * Implementation of `init'.
3797 /* Initialization. */
3798 static void init_gpgme (void)
3800 /* Make sure that gpg-agent is running. */
3801 if (!getenv ("GPG_AGENT_INFO")) {
3802 mutt_error ("\nUsing GPGME backend, although no gpg-agent is running");
3803 if (mutt_any_key_to_continue (NULL) == -1)
3808 void pgp_gpgme_init (void)
3813 void smime_gpgme_init (void)
3817 static int gpgme_send_menu (HEADER * msg, int *redraw, int is_smime)
3820 char input_signas[SHORT_STRING];
3823 if (msg->security & APPLICATION_PGP)
3825 else if (msg->security & APPLICATION_SMIME)
3830 mutt_multi_choice (_
3831 ("S/MIME (e)ncrypt, (s)ign, sign (a)s, (b)oth, (p)gp or (c)lear?"),
3835 mutt_multi_choice (_
3836 ("PGP (e)ncrypt, (s)ign, sign (a)s, (b)oth, s/(m)ime or (c)lear?"),
3840 case 1: /* (e)ncrypt */
3841 msg->security |= (is_smime ? SMIMEENCRYPT : PGPENCRYPT);
3842 msg->security &= ~(is_smime ? SMIMESIGN : PGPSIGN);
3845 case 2: /* (s)ign */
3846 msg->security |= (is_smime ? SMIMESIGN : PGPSIGN);
3847 msg->security &= ~(is_smime ? SMIMEENCRYPT : PGPENCRYPT);
3850 case 3: /* sign (a)s */
3851 /* unset_option(OPTCRYPTCHECKTRUST); */
3852 if ((p = crypt_ask_for_key (_("Sign as: "), NULL, KEYFLAG_CANSIGN,
3853 is_smime ? APPLICATION_SMIME :
3854 APPLICATION_PGP, NULL))) {
3855 snprintf (input_signas, sizeof (input_signas), "0x%s", crypt_keyid (p));
3856 str_replace (is_smime ? &SmimeDefaultKey : &PgpSignAs,
3858 crypt_free_key (&p);
3860 msg->security |= (is_smime ? SMIMESIGN : PGPSIGN);
3864 msg->security &= (is_smime ? ~SMIMESIGN : ~PGPSIGN);
3867 *redraw = REDRAW_FULL;
3870 case 4: /* (b)oth */
3872 (is_smime ? (SMIMEENCRYPT | SMIMESIGN) : (PGPENCRYPT | PGPSIGN));
3875 case 5: /* (p)gp or s/(m)ime */
3876 is_smime = !is_smime;
3879 case 6: /* (c)lear */
3884 if (choice == 6 || choice == 7);
3885 else if (is_smime) {
3886 msg->security &= ~APPLICATION_PGP;
3887 msg->security |= APPLICATION_SMIME;
3890 msg->security &= ~APPLICATION_SMIME;
3891 msg->security |= APPLICATION_PGP;
3894 return (msg->security);
3897 int pgp_gpgme_send_menu (HEADER * msg, int *redraw)
3899 return gpgme_send_menu (msg, redraw, 0);
3902 int smime_gpgme_send_menu (HEADER * msg, int *redraw)
3904 return gpgme_send_menu (msg, redraw, 1);
3907 static int verify_sender (HEADER * h, gpgme_protocol_t protocol)
3909 ADDRESS *sender = NULL;
3910 unsigned int ret = 1;
3913 h->env->from = mutt_expand_aliases (h->env->from);
3914 sender = h->env->from;
3916 else if (h->env->sender) {
3917 h->env->sender = mutt_expand_aliases (h->env->sender);
3918 sender = h->env->sender;
3922 if (signature_key) {
3923 gpgme_key_t key = signature_key;
3924 gpgme_user_id_t uid = NULL;
3925 int sender_length = 0;
3928 sender_length = m_strlen(sender->mailbox);
3929 for (uid = key->uids; uid && ret; uid = uid->next) {
3930 uid_length = m_strlen(uid->email);
3931 if (1 && (uid->email[0] == '<')
3932 && (uid->email[uid_length - 1] == '>')
3933 && (uid_length == sender_length + 2)
3934 && (!strncmp (uid->email + 1, sender->mailbox, sender_length)))
3939 mutt_any_key_to_continue ("Failed to verify sender");
3942 mutt_any_key_to_continue ("Failed to figure out sender");
3944 if (signature_key) {
3945 gpgme_key_release (signature_key);
3946 signature_key = NULL;
3952 int smime_gpgme_verify_sender (HEADER * h)
3954 return verify_sender (h, GPGME_PROTOCOL_CMS);