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.
15 #include <lib-lib/lib-lib.h>
17 #ifdef CRYPT_BACKEND_GPGME
22 #ifdef HAVE_LANGINFO_D_T_FMT
23 # include <langinfo.h>
25 #ifdef HAVE_SYS_RESOURCE_H
26 # include <sys/resource.h>
31 #include <lib-mime/mime.h>
33 #include <lib-ui/curses.h>
34 #include <lib-ui/enter.h>
35 #include <lib-ui/menu.h>
39 #include <lib-crypt/crypt.h>
43 #include "recvattach.h"
45 #include "crypt-gpgme.h"
50 #define digitp(p) (*(p) >= '0' && *(p) <= '9')
51 #define hexdigitp(a) (digitp (a) \
52 || (*(a) >= 'A' && *(a) <= 'F') \
53 || (*(a) >= 'a' && *(a) <= 'f'))
54 #define xtoi_1(p) (*(p) <= '9'? (*(p)- '0'): \
55 *(p) <= 'F'? (*(p)-'A'+10):(*(p)-'a'+10))
56 #define xtoi_2(p) ((xtoi_1(p) * 16) + xtoi_1((p)+1))
58 /* Values used for comparing addresses. */
59 #define CRYPT_KV_VALID 1
60 #define CRYPT_KV_ADDR 2
61 #define CRYPT_KV_STRING 4
62 #define CRYPT_KV_STRONGID 8
63 #define CRYPT_KV_MATCH (CRYPT_KV_ADDR|CRYPT_KV_STRING)
72 struct crypt_cache *next;
80 /* We work based on user IDs, getting from a user ID to the key is
81 check and does not need any memory (gpgme uses reference counting). */
82 typedef struct crypt_keyinfo {
83 struct crypt_keyinfo *next;
85 int idx; /* and the user ID at this index */
86 const char *uid; /* and for convenience point to this user ID */
87 unsigned int flags; /* global and per uid flags (for convenience) */
90 typedef struct crypt_entry {
96 static struct crypt_cache *id_defaults = NULL;
97 static gpgme_key_t signature_key = NULL;
100 * General helper functions.
103 /* return true when S points to a didgit or letter. */
104 static int digit_or_letter (const unsigned char *s)
106 return ((*s >= '0' && *s <= '9')
107 || (*s >= 'A' && *s <= 'Z')
108 || (*s >= 'a' && *s <= 'z'));
112 /* Print the utf-8 encoded string BUF of length LEN bytes to stream
113 FP. Convert the character set. */
114 static void print_utf8 (FILE * fp, const char *buf, ssize_t len)
118 tstr = p_dupstr(buf, len);
119 mutt_convert_string (&tstr, "utf-8", Charset, M_ICONV_HOOK_FROM);
129 /* Return the keyID for the key K. Note that this string is valid as
130 long as K is valid */
131 static const char *crypt_keyid (crypt_key_t * k)
133 const char *s = "????????";
135 if (k->kobj && k->kobj->subkeys) {
136 s = k->kobj->subkeys->keyid;
137 if ((!option (OPTPGPLONGIDS)) && (m_strlen(s) == 16))
138 /* Return only the short keyID. */
145 /* Return the hexstring fingerprint from the key K. */
146 static const char *crypt_fpr (crypt_key_t * k)
150 if (k->kobj && k->kobj->subkeys)
151 s = k->kobj->subkeys->fpr;
156 /* Parse FLAGS and return a statically allocated(!) string with them. */
157 static char *crypt_key_abilities (int flags)
161 if (!(flags & KEYFLAG_CANENCRYPT))
163 else if (flags & KEYFLAG_PREFER_SIGNING)
168 if (!(flags & KEYFLAG_CANSIGN))
170 else if (flags & KEYFLAG_PREFER_ENCRYPTION)
180 /* Parse FLAGS and return a character describing the most important flag. */
181 static char crypt_flags (int flags)
183 if (flags & KEYFLAG_REVOKED)
185 else if (flags & KEYFLAG_EXPIRED)
187 else if (flags & KEYFLAG_DISABLED)
189 else if (flags & KEYFLAG_CRITICAL)
195 /* Return a copy of KEY. */
196 static crypt_key_t *crypt_copy_key (crypt_key_t *key)
200 k = p_new(crypt_key_t, 1);
202 gpgme_key_ref (key->kobj);
205 k->flags = key->flags;
210 /* Release all the keys at the address of KEYLIST and set the address
212 static void crypt_free_key (crypt_key_t ** keylist)
215 crypt_key_t *k = (*keylist)->next;
222 /* Return trute when key K is valid. */
223 static int crypt_key_is_valid (crypt_key_t * k)
225 if (k->flags & KEYFLAG_CANTUSE)
230 /* Return true whe validity of KEY is sufficient. */
231 static int crypt_id_is_strong (crypt_key_t * key)
233 gpgme_validity_t val = GPGME_VALIDITY_UNKNOWN;
234 gpgme_user_id_t uid = NULL;
238 if ((key->flags & KEYFLAG_ISX509))
241 for (i = 0, uid = key->kobj->uids; (i < key->idx) && uid;
242 i++, uid = uid->next);
247 case GPGME_VALIDITY_UNKNOWN:
248 case GPGME_VALIDITY_UNDEFINED:
249 case GPGME_VALIDITY_NEVER:
250 case GPGME_VALIDITY_MARGINAL:
254 case GPGME_VALIDITY_FULL:
255 case GPGME_VALIDITY_ULTIMATE:
263 /* Return true when the KEY is valid, i.e. not marked as unusable. */
264 static int crypt_id_is_valid (crypt_key_t * key)
266 return !(key->flags & KEYFLAG_CANTUSE);
269 /* Return a bit vector describing how well the addresses ADDR and
270 U_ADDR match and whether KEY is valid. */
271 static int crypt_id_matches_addr (address_t * addr, address_t * u_addr,
276 if (crypt_id_is_valid (key))
277 rv |= CRYPT_KV_VALID;
279 if (crypt_id_is_strong (key))
280 rv |= CRYPT_KV_STRONGID;
282 if (addr->mailbox && u_addr->mailbox
283 && m_strcasecmp(addr->mailbox, u_addr->mailbox) == 0)
286 if (addr->personal && u_addr->personal
287 && m_strcasecmp(addr->personal, u_addr->personal) == 0)
288 rv |= CRYPT_KV_STRING;
295 * GPGME convenient functions.
298 /* Create a new gpgme context and return it. With FOR_SMIME set to
299 true, the protocol of the context is set to CMS. */
300 static gpgme_ctx_t create_gpgme_context (int for_smime)
305 err = gpgme_new (&ctx);
307 mutt_error (_("error creating gpgme context: %s\n"), gpgme_strerror (err));
313 err = gpgme_set_protocol (ctx, GPGME_PROTOCOL_CMS);
315 mutt_error (_("error enabling CMS protocol: %s\n"), gpgme_strerror (err));
324 /* Create a new gpgme data object. This is a wrapper to die on
326 static gpgme_data_t create_gpgme_data (void)
331 err = gpgme_data_new (&data);
333 mutt_error (_("error creating gpgme data object: %s\n"),
334 gpgme_strerror (err));
341 /* Create a new GPGME Data object from the mail body A. With CONVERT
342 passed as true, the lines are converted to CR,LF if required.
343 Return NULL on error or the gpgme_data_t object on success. */
344 static gpgme_data_t body_to_data_object (BODY * a, int convert)
346 char tempfile[_POSIX_PATH_MAX];
351 mutt_mktemp (tempfile);
352 fptmp = safe_fopen (tempfile, "w+");
354 mutt_perror (tempfile);
358 mutt_write_mime_header (a, fptmp);
360 mutt_write_mime_body (a, fptmp);
364 unsigned char buf[1];
366 data = create_gpgme_data ();
368 while ((c = fgetc (fptmp)) != EOF) {
372 if (c == '\n' && !hadcr) {
374 gpgme_data_write (data, buf, 1);
379 /* FIXME: This is quite suboptimal */
381 gpgme_data_write (data, buf, 1);
384 gpgme_data_seek (data, 0, SEEK_SET);
388 err = gpgme_data_new_from_file (&data, tempfile, 1);
392 mutt_error (_("error allocating data object: %s\n"), gpgme_strerror (err));
399 /* Create a GPGME data object from the stream FP but limit the object
400 to LENGTH bytes starting at OFFSET bytes from the beginning of the
402 static gpgme_data_t file_to_data_object (FILE * fp, long offset, long length)
407 err = gpgme_data_new_from_filepart (&data, NULL, fp, offset, length);
409 mutt_error (_("error allocating data object: %s\n"), gpgme_strerror (err));
416 /* Write a GPGME data object to the stream FP. */
417 static int data_object_to_stream (gpgme_data_t data, FILE * fp)
423 err = ((gpgme_data_seek (data, 0, SEEK_SET) == -1)
424 ? gpgme_error_from_errno (errno) : 0);
426 mutt_error (_("error rewinding data object: %s\n"), gpgme_strerror (err));
430 while ((nread = gpgme_data_read (data, buf, sizeof (buf)))) {
431 /* fixme: we are not really converting CRLF to LF but just
432 skipping CR. Doing it correctly needs a more complex logic */
433 for (p = buf; nread; p++, nread--) {
439 mutt_perror ("[tempfile]");
444 mutt_error (_("error reading data object: %s\n"), strerror (errno));
450 /* Copy a data object to a newly created temporay file and return that
451 filename. Caller must free. With RET_FP not NULL, don't close the
452 stream but return it there. */
453 static char *data_object_to_tempfile (gpgme_data_t data, FILE ** ret_fp)
456 char tempfile[_POSIX_PATH_MAX];
460 mutt_mktemp (tempfile);
461 fp = safe_fopen (tempfile, "w+");
463 mutt_perror (tempfile);
467 err = ((gpgme_data_seek (data, 0, SEEK_SET) == -1)
468 ? gpgme_error_from_errno (errno) : 0);
472 while ((nread = gpgme_data_read (data, buf, sizeof (buf)))) {
473 if (fwrite (buf, nread, 1, fp) != 1) {
474 mutt_perror (tempfile);
486 mutt_error (_("error reading data object: %s\n"), gpgme_strerror (err));
493 return m_strdup(tempfile);
497 /* Create a GpgmeRecipientSet from the keys in the string KEYLIST.
498 The keys must be space delimited. */
499 static gpgme_key_t *create_recipient_set (const char *keylist,
500 gpgme_protocol_t protocol)
506 gpgme_key_t *rset = NULL;
507 unsigned int rset_n = 0;
508 gpgme_key_t key = NULL;
509 gpgme_ctx_t context = NULL;
511 err = gpgme_new (&context);
513 err = gpgme_set_protocol (context, protocol);
520 for (i = 0; *s && *s != ' ' && i < ssizeof(buf) - 1;)
524 if (i > 1 && buf[i - 1] == '!') {
525 /* The user selected to override the valididy of that
529 err = gpgme_get_key (context, buf, &key, 0);
531 key->uids->validity = GPGME_VALIDITY_FULL;
535 err = gpgme_get_key (context, buf, &key, 0);
538 p_realloc(&rset, rset_n + 1);
539 rset[rset_n++] = key;
542 mutt_error (_("error adding recipient `%s': %s\n"),
543 buf, gpgme_strerror (err));
551 /* NULL terminate. */
552 p_realloc(&rset, rset_n + 1);
553 rset[rset_n++] = NULL;
556 gpgme_release (context);
562 /* Make sure that the correct signer is set. Returns 0 on success. */
563 static int set_signer (gpgme_ctx_t ctx, int for_smime)
565 char *signid = for_smime ? SmimeDefaultKey : PgpSignAs;
568 gpgme_key_t key, key2;
570 if (!signid || !*signid)
573 listctx = create_gpgme_context (for_smime);
574 err = gpgme_op_keylist_start (listctx, signid, 1);
576 err = gpgme_op_keylist_next (listctx, &key);
578 gpgme_release (listctx);
579 mutt_error (_("secret key `%s' not found: %s\n"),
580 signid, gpgme_strerror (err));
583 err = gpgme_op_keylist_next (listctx, &key2);
585 gpgme_key_release (key);
586 gpgme_key_release (key2);
587 gpgme_release (listctx);
588 mutt_error (_("ambiguous specification of secret key `%s'\n"), signid);
591 gpgme_op_keylist_end (listctx);
592 gpgme_release (listctx);
594 gpgme_signers_clear (ctx);
595 err = gpgme_signers_add (ctx, key);
596 gpgme_key_release (key);
598 mutt_error (_("error setting secret key `%s': %s\n"),
599 signid, gpgme_strerror (err));
606 /* Encrypt the gpgme data object PLAINTEXT to the recipients in RSET
607 and return an allocated filename to a temporary file containing the
608 enciphered text. With USE_SMIME set to true, the smime backend is
609 used. With COMBINED_SIGNED a PGP message is signed and
610 encrypted. Returns NULL in case of error */
611 static char *encrypt_gpgme_object (gpgme_data_t plaintext, gpgme_key_t * rset,
612 int use_smime, int combined_signed)
616 gpgme_data_t ciphertext;
619 ctx = create_gpgme_context (use_smime);
621 gpgme_set_armor (ctx, 1);
623 ciphertext = create_gpgme_data ();
625 if (combined_signed) {
626 if (set_signer (ctx, use_smime)) {
627 gpgme_data_release (ciphertext);
631 err = gpgme_op_encrypt_sign (ctx, rset, GPGME_ENCRYPT_ALWAYS_TRUST,
632 plaintext, ciphertext);
635 err = gpgme_op_encrypt (ctx, rset, GPGME_ENCRYPT_ALWAYS_TRUST,
636 plaintext, ciphertext);
637 mutt_need_hard_redraw ();
639 mutt_error (_("error encrypting data: %s\n"), gpgme_strerror (err));
640 gpgme_data_release (ciphertext);
647 outfile = data_object_to_tempfile (ciphertext, NULL);
648 gpgme_data_release (ciphertext);
652 /* Find the "micalg" parameter from the last Gpgme operation on
653 context CTX. It is expected that this operation was a sign
654 operation. Return the algorithm name as a C string in buffer BUF
655 which must have been allocated by the caller with size BUFLEN.
656 Returns 0 on success or -1 in case of an error. The return string
657 is truncted to BUFLEN - 1. */
658 static int get_micalg (gpgme_ctx_t ctx, char *buf, ssize_t buflen)
660 gpgme_sign_result_t result = NULL;
661 const char *algorithm_name = NULL;
667 result = gpgme_op_sign_result (ctx);
669 algorithm_name = gpgme_hash_algo_name (result->signatures->hash_algo);
670 if (algorithm_name) {
671 m_strcpy(buf, buflen, algorithm_name);
675 return *buf ? 0 : -1;
678 static void print_time (time_t t, STATE * s)
682 setlocale (LC_TIME, "");
683 #ifdef HAVE_LANGINFO_D_T_FMT
684 strftime (p, sizeof (p), nl_langinfo (D_T_FMT), localtime (&t));
686 strftime (p, sizeof (p), "%c", localtime (&t));
688 setlocale (LC_TIME, "C");
689 state_attach_puts (p, s);
693 * Implementation of `sign_message'.
696 /* Sign the MESSAGE in body A either using OpenPGP or S/MIME when
697 USE_SMIME is passed as true. Returns the new body or NULL on
699 static BODY *sign_message (BODY * a, int use_smime)
706 gpgme_data_t message, signature;
708 convert_to_7bit (a); /* Signed data _must_ be in 7-bit format. */
710 message = body_to_data_object (a, 1);
713 signature = create_gpgme_data ();
715 ctx = create_gpgme_context (use_smime);
717 gpgme_set_armor (ctx, 1);
719 if (set_signer (ctx, use_smime)) {
720 gpgme_data_release (signature);
725 err = gpgme_op_sign (ctx, message, signature, GPGME_SIG_MODE_DETACH);
726 mutt_need_hard_redraw ();
727 gpgme_data_release (message);
729 gpgme_data_release (signature);
731 mutt_error (_("error signing data: %s\n"), gpgme_strerror (err));
735 sigfile = data_object_to_tempfile (signature, NULL);
736 gpgme_data_release (signature);
743 t->type = TYPEMULTIPART;
744 t->subtype = m_strdup("signed");
745 t->encoding = ENC7BIT;
747 t->disposition = DISPINLINE;
749 parameter_set_boundary(&t->parameter);
750 parameter_setval(&t->parameter, "protocol",
751 use_smime ? "application/pkcs7-signature"
752 : "application/pgp-signature");
753 /* Get the micalg from gpgme. Old gpgme versions don't support this
754 for S/MIME so we assume sha-1 in this case. */
755 if (!get_micalg (ctx, buf, sizeof buf))
756 parameter_setval(&t->parameter, "micalg", buf);
758 parameter_setval(&t->parameter, "micalg", "sha1");
764 t->parts->next = body_new();
766 t->type = TYPEAPPLICATION;
768 t->subtype = m_strdup("pkcs7-signature");
769 parameter_setval(&t->parameter, "name", "smime.p7s");
770 t->encoding = ENCBASE64;
772 t->disposition = DISPATTACH;
773 t->d_filename = m_strdup("smime.p7s");
776 t->subtype = m_strdup("pgp-signature");
778 t->disposition = DISPINLINE;
779 t->encoding = ENC7BIT;
781 t->filename = sigfile;
782 t->unlink = 1; /* ok to remove this file after sending. */
788 BODY *pgp_gpgme_sign_message (BODY * a)
790 return sign_message (a, 0);
793 BODY *smime_gpgme_sign_message (BODY * a)
795 return sign_message (a, 1);
799 * Implementation of `encrypt_message'.
802 /* Encrypt the mail body A to all keys given as space separated keyids
803 or fingerprints in KEYLIST and return the encrypted body. */
804 BODY *pgp_gpgme_encrypt_message (BODY * a, char *keylist, int sign)
806 char *outfile = NULL;
808 gpgme_key_t *rset = NULL;
809 gpgme_data_t plaintext;
811 rset = create_recipient_set (keylist, GPGME_PROTOCOL_OpenPGP);
817 plaintext = body_to_data_object (a, 0);
823 outfile = encrypt_gpgme_object (plaintext, rset, 0, sign);
824 gpgme_data_release (plaintext);
830 t->type = TYPEMULTIPART;
831 t->subtype = m_strdup("encrypted");
832 t->encoding = ENC7BIT;
834 t->disposition = DISPINLINE;
836 parameter_set_boundary(&t->parameter);
837 parameter_setval(&t->parameter, "protocol", "application/pgp-encrypted");
839 t->parts = body_new();
840 t->parts->type = TYPEAPPLICATION;
841 t->parts->subtype = m_strdup("pgp-encrypted");
842 t->parts->encoding = ENC7BIT;
844 t->parts->next = body_new();
845 t->parts->next->type = TYPEAPPLICATION;
846 t->parts->next->subtype = m_strdup("octet-stream");
847 t->parts->next->encoding = ENC7BIT;
848 t->parts->next->filename = outfile;
849 t->parts->next->use_disp = 1;
850 t->parts->next->disposition = DISPINLINE;
851 t->parts->next->unlink = 1; /* delete after sending the message */
852 t->parts->next->d_filename = m_strdup("msg.asc"); /* non pgp/mime
859 * Implementation of `smime_build_smime_entity'.
862 /* Encrypt the mail body A to all keys given as space separated
863 fingerprints in KEYLIST and return the S/MIME encrypted body. */
864 BODY *smime_gpgme_build_smime_entity (BODY * a, char *keylist)
866 char *outfile = NULL;
868 gpgme_key_t *rset = NULL;
869 gpgme_data_t plaintext;
871 rset = create_recipient_set (keylist, GPGME_PROTOCOL_CMS);
875 plaintext = body_to_data_object (a, 0);
881 outfile = encrypt_gpgme_object (plaintext, rset, 1, 0);
882 gpgme_data_release (plaintext);
888 t->type = TYPEAPPLICATION;
889 t->subtype = m_strdup("pkcs7-mime");
890 parameter_setval(&t->parameter, "name", "smime.p7m");
891 parameter_setval(&t->parameter, "smime-type", "enveloped-data");
892 t->encoding = ENCBASE64; /* The output of OpenSSL SHOULD be binary */
894 t->disposition = DISPATTACH;
895 t->d_filename = m_strdup("smime.p7m");
896 t->filename = outfile;
897 t->unlink = 1; /*delete after sending the message */
906 * Implementation of `verify_one'.
909 /* Display the common attributes of the signature summary SUM.
910 Return 1 if there is is a severe warning.
912 static int show_sig_summary (unsigned long sum,
913 gpgme_ctx_t ctx, gpgme_key_t key, int idx,
918 if ((sum & GPGME_SIGSUM_KEY_REVOKED)) {
919 state_attach_puts (_("Warning: One of the keys has been revoked\n"), s);
923 if ((sum & GPGME_SIGSUM_KEY_EXPIRED)) {
924 time_t at = key->subkeys->expires ? key->subkeys->expires : 0;
927 state_attach_puts (_("Warning: The key used to create the "
928 "signature expired at: "), s);
930 state_attach_puts ("\n", s);
933 state_attach_puts (_("Warning: At least one certification key "
934 "has expired\n"), s);
937 if ((sum & GPGME_SIGSUM_SIG_EXPIRED)) {
938 gpgme_verify_result_t result;
939 gpgme_signature_t sig;
942 result = gpgme_op_verify_result (ctx);
944 for (sig = result->signatures, i = 0; sig && (i < idx);
945 sig = sig->next, i++);
947 state_attach_puts (_("Warning: The signature expired at: "), s);
948 print_time (sig ? sig->exp_timestamp : 0, s);
949 state_attach_puts ("\n", s);
952 if ((sum & GPGME_SIGSUM_KEY_MISSING))
953 state_attach_puts (_("Can't verify due to a missing "
954 "key or certificate\n"), s);
956 if ((sum & GPGME_SIGSUM_CRL_MISSING)) {
957 state_attach_puts (_("The CRL is not available\n"), s);
961 if ((sum & GPGME_SIGSUM_CRL_TOO_OLD)) {
962 state_attach_puts (_("Available CRL is too old\n"), s);
966 if ((sum & GPGME_SIGSUM_BAD_POLICY))
967 state_attach_puts (_("A policy requirement was not met\n"), s);
969 if ((sum & GPGME_SIGSUM_SYS_ERROR)) {
970 const char *t0 = NULL, *t1 = NULL;
971 gpgme_verify_result_t result;
972 gpgme_signature_t sig;
975 state_attach_puts (_("A system error occurred"), s);
977 /* Try to figure out some more detailed system error information. */
978 result = gpgme_op_verify_result (ctx);
979 for (sig = result->signatures, i = 0; sig && (i < idx);
980 sig = sig->next, i++);
983 t1 = sig->wrong_key_usage ? "Wrong_Key_Usage" : "";
987 state_attach_puts (": ", s);
989 state_attach_puts (t0, s);
990 if (t1 && !(t0 && !m_strcmp(t0, t1))) {
992 state_attach_puts (",", s);
993 state_attach_puts (t1, s);
996 state_attach_puts ("\n", s);
1003 static void show_fingerprint (gpgme_key_t key, STATE * state)
1008 const char *prefix = _("Fingerprint: ");
1012 s = key->subkeys ? key->subkeys->fpr : NULL;
1015 is_pgp = (key->protocol == GPGME_PROTOCOL_OpenPGP);
1017 buf = xmalloc(m_strlen(prefix) + m_strlen(s) * 4 + 2);
1018 strcpy (buf, prefix); /* __STRCPY_CHECKED__ */
1019 p = buf + m_strlen(buf);
1020 if (is_pgp && m_strlen(s) == 40) { /* PGP v4 style formatted. */
1021 for (i = 0; *s && s[1] && s[2] && s[3] && s[4]; s += 4, i++) {
1032 for (i = 0; *s && s[1] && s[2]; s += 2, i++) {
1035 *p++ = is_pgp ? ' ' : ':';
1036 if (is_pgp && i == 7)
1041 /* just in case print remaining odd digits */
1046 state_attach_puts (buf, state);
1050 /* Show the valididy of a key used for one signature. */
1051 static void show_one_sig_validity (gpgme_ctx_t ctx, int idx, STATE * s)
1053 gpgme_verify_result_t result = NULL;
1054 gpgme_signature_t sig = NULL;
1055 const char *txt = NULL;
1057 result = gpgme_op_verify_result (ctx);
1059 for (sig = result->signatures; sig && (idx > 0); sig = sig->next, idx--);
1061 switch (sig ? sig->validity : 0) {
1062 case GPGME_VALIDITY_UNKNOWN:
1063 txt = _("WARNING: We have NO indication whether "
1064 "the key belongs to the person named " "as shown above\n");
1066 case GPGME_VALIDITY_UNDEFINED:
1068 case GPGME_VALIDITY_NEVER:
1069 txt = _("WARNING: The key does NOT BELONG to "
1070 "the person named as shown above\n");
1072 case GPGME_VALIDITY_MARGINAL:
1073 txt = _("WARNING: It is NOT certain that the key "
1074 "belongs to the person named as shown above\n");
1076 case GPGME_VALIDITY_FULL:
1077 case GPGME_VALIDITY_ULTIMATE:
1082 state_attach_puts (txt, s);
1085 /* Show information about one signature. This fucntion is called with
1086 the context CTX of a sucessful verification operation and the
1087 enumerator IDX which should start at 0 and incremete for each
1090 Return values are: 0 for normal procession, 1 for a bad signature,
1091 2 for a signature with a warning or -1 for no more signature. */
1092 static int show_one_sig_status (gpgme_ctx_t ctx, int idx, STATE * s)
1095 const char *fpr, *uid;
1096 gpgme_key_t key = NULL;
1097 int i, anybad = 0, anywarn = 0;
1099 gpgme_user_id_t uids = NULL;
1100 gpgme_verify_result_t result;
1101 gpgme_signature_t sig;
1102 gpgme_error_t err = GPG_ERR_NO_ERROR;
1104 result = gpgme_op_verify_result (ctx);
1106 /* FIXME: this code should use a static variable and remember
1107 the current position in the list of signatures, IMHO.
1110 for (i = 0, sig = result->signatures; sig && (i < idx);
1111 i++, sig = sig->next);
1113 return -1; /* Signature not found. */
1115 if (signature_key) {
1116 gpgme_key_release (signature_key);
1117 signature_key = NULL;
1120 created = sig->timestamp;
1124 if (gpg_err_code (sig->status) != GPG_ERR_NO_ERROR)
1127 err = gpgme_get_key (ctx, fpr, &key, 0); /* secret key? */
1129 uid = (key->uids && key->uids->uid) ? key->uids->uid : "[?]";
1131 signature_key = key;
1134 key = NULL; /* Old gpgme versions did not set KEY to NULL on
1135 error. Do it here to avoid a double free. */
1139 if (!s || !s->fpout || !(s->flags & M_DISPLAY)); /* No state information so no way to print anything. */
1141 state_attach_puts (_("Error getting key information: "), s);
1142 state_attach_puts (gpg_strerror (err), s);
1143 state_attach_puts ("\n", s);
1146 else if ((sum & GPGME_SIGSUM_GREEN)) {
1147 state_attach_puts (_("Good signature from: "), s);
1148 state_attach_puts (uid, s);
1149 state_attach_puts ("\n", s);
1150 for (i = 1, uids = key->uids; uids; i++, uids = uids->next) {
1152 /* Skip primary UID. */
1156 state_attach_puts (_(" aka: "), s);
1157 state_attach_puts (uids->uid, s);
1158 state_attach_puts ("\n", s);
1160 state_attach_puts (_(" created: "), s);
1161 print_time (created, s);
1162 state_attach_puts ("\n", s);
1163 if (show_sig_summary (sum, ctx, key, idx, s))
1165 show_one_sig_validity (ctx, idx, s);
1167 else if ((sum & GPGME_SIGSUM_RED)) {
1168 state_attach_puts (_("*BAD* signature claimed to be from: "), s);
1169 state_attach_puts (uid, s);
1170 state_attach_puts ("\n", s);
1171 show_sig_summary (sum, ctx, key, idx, s);
1173 else if (!anybad && key && (key->protocol == GPGME_PROTOCOL_OpenPGP)) { /* We can't decide (yellow) but this is a PGP key with a good
1174 signature, so we display what a PGP user expects: The name,
1175 fingerprint and the key validity (which is neither fully or
1177 state_attach_puts (_("Good signature from: "), s);
1178 state_attach_puts (uid, s);
1179 state_attach_puts ("\n", s);
1180 state_attach_puts (_(" created: "), s);
1181 print_time (created, s);
1182 state_attach_puts ("\n", s);
1183 show_one_sig_validity (ctx, idx, s);
1184 show_fingerprint (key, s);
1185 if (show_sig_summary (sum, ctx, key, idx, s))
1188 else { /* can't decide (yellow) */
1190 state_attach_puts (_("Error checking signature"), s);
1191 state_attach_puts ("\n", s);
1192 show_sig_summary (sum, ctx, key, idx, s);
1195 if (key != signature_key)
1196 gpgme_key_release (key);
1199 return anybad ? 1 : anywarn ? 2 : 0;
1202 /* Do the actual verification step. With IS_SMIME set to true we
1203 assume S/MIME (surprise!) */
1204 static int verify_one (BODY * sigbdy, STATE * s,
1205 const char *tempfile, int is_smime)
1211 gpgme_data_t signature, message;
1213 signature = file_to_data_object (s->fpin, sigbdy->offset, sigbdy->length);
1217 /* We need to tell gpgme about the encoding because the backend can't
1218 auto-detect plain base-64 encoding which is used by S/MIME. */
1220 gpgme_data_set_encoding (signature, GPGME_DATA_ENCODING_BASE64);
1222 err = gpgme_data_new_from_file (&message, tempfile, 1);
1224 gpgme_data_release (signature);
1225 mutt_error (_("error allocating data object: %s\n"), gpgme_strerror (err));
1228 ctx = create_gpgme_context (is_smime);
1230 /* Note: We don't need a current time output because GPGME avoids
1231 such an attack by separating the meta information from the
1233 state_attach_puts (_("[-- Begin signature information --]\n"), s);
1235 err = gpgme_op_verify (ctx, signature, message, NULL);
1236 mutt_need_hard_redraw ();
1240 snprintf (buf, sizeof (buf) - 1,
1241 _("Error: verification failed: %s\n"), gpgme_strerror (err));
1242 state_attach_puts (buf, s);
1244 else { /* Verification succeeded, see what the result is. */
1248 if (signature_key) {
1249 gpgme_key_release (signature_key);
1250 signature_key = NULL;
1253 for (idx = 0; (res = show_one_sig_status (ctx, idx, s)) != -1; idx++) {
1264 gpgme_verify_result_t result;
1265 gpgme_sig_notation_t notation;
1266 gpgme_signature_t sig;
1268 result = gpgme_op_verify_result (ctx);
1270 for (sig = result->signatures; sig; sig = sig->next) {
1271 if (sig->notations) {
1272 state_attach_puts ("*** Begin Notation (signature by: ", s);
1273 state_attach_puts (sig->fpr, s);
1274 state_attach_puts (") ***\n", s);
1275 for (notation = sig->notations; notation; notation = notation->next)
1277 if (notation->name) {
1278 state_attach_puts (notation->name, s);
1279 state_attach_puts ("=", s);
1281 if (notation->value) {
1282 state_attach_puts (notation->value, s);
1283 if (!(*notation->value
1284 && (notation->value[m_strlen(notation->value) - 1] ==
1286 state_attach_puts ("\n", s);
1289 state_attach_puts ("*** End Notation ***\n", s);
1295 gpgme_release (ctx);
1297 state_attach_puts (_("[-- End signature information --]\n\n"), s);
1299 return badsig ? 1 : anywarn ? 2 : 0;
1302 int pgp_gpgme_verify_one (BODY * sigbdy, STATE * s, const char *tempfile)
1304 return verify_one (sigbdy, s, tempfile, 0);
1307 int smime_gpgme_verify_one (BODY * sigbdy, STATE * s, const char *tempfile)
1309 return verify_one (sigbdy, s, tempfile, 1);
1313 * Implementation of `decrypt_part'.
1316 /* Decrypt a PGP or SMIME message (depending on the boolean flag
1317 IS_SMIME) with body A described further by state S. Write
1318 plaintext out to file FPOUT and return a new body. For PGP returns
1319 a flag in R_IS_SIGNED to indicate whether this is a combined
1320 encrypted and signed message, for S/MIME it returns true when it is
1321 not a encrypted but a signed message. */
1322 static BODY *decrypt_part (BODY * a, STATE * s, FILE * fpout, int is_smime,
1329 gpgme_data_t ciphertext, plaintext;
1330 int maybe_signed = 0;
1337 ctx = create_gpgme_context (is_smime);
1340 /* Make a data object from the body, create context etc. */
1341 ciphertext = file_to_data_object (s->fpin, a->offset, a->length);
1344 plaintext = create_gpgme_data ();
1346 /* Do the decryption or the verification in case of the S/MIME hack. */
1347 if ((!is_smime) || maybe_signed) {
1349 err = gpgme_op_decrypt_verify (ctx, ciphertext, plaintext);
1350 else if (maybe_signed)
1351 err = gpgme_op_verify (ctx, ciphertext, NULL, plaintext);
1354 /* Check wether signatures have been verified. */
1355 gpgme_verify_result_t verify_result = gpgme_op_verify_result (ctx);
1357 if (verify_result->signatures)
1362 err = gpgme_op_decrypt (ctx, ciphertext, plaintext);
1363 gpgme_data_release (ciphertext);
1365 if (is_smime && !maybe_signed && gpg_err_code (err) == GPG_ERR_NO_DATA) {
1366 /* Check whether this might be a signed message despite what
1367 the mime header told us. Retry then. gpgsm returns the
1368 error information "unsupported Algorithm '?'" but gpgme
1369 will not store this unknown algorithm, thus we test that
1370 it has not been set. */
1371 gpgme_decrypt_result_t result;
1373 result = gpgme_op_decrypt_result (ctx);
1374 if (!result->unsupported_algorithm) {
1376 gpgme_data_release (plaintext);
1380 mutt_need_hard_redraw ();
1381 if ((s->flags & M_DISPLAY)) {
1384 snprintf (buf, sizeof (buf) - 1,
1385 _("[-- Error: decryption failed: %s --]\n\n"),
1386 gpgme_strerror (err));
1387 state_attach_puts (buf, s);
1389 gpgme_data_release (plaintext);
1390 gpgme_release (ctx);
1393 mutt_need_hard_redraw ();
1395 /* Read the output from GPGME, and make sure to change CRLF to LF,
1396 otherwise read_mime_header has a hard time parsing the message. */
1397 if (data_object_to_stream (plaintext, fpout)) {
1398 gpgme_data_release (plaintext);
1399 gpgme_release (ctx);
1402 gpgme_data_release (plaintext);
1404 a->is_signed_data = 0;
1410 a->is_signed_data = 1;
1412 *r_is_signed = -1; /* A signature exists. */
1414 if ((s->flags & M_DISPLAY))
1415 state_attach_puts (_("[-- Begin signature " "information --]\n"), s);
1416 for (idx = 0; (res = show_one_sig_status (ctx, idx, s)) != -1; idx++) {
1422 if (!anybad && idx && r_is_signed && *r_is_signed)
1423 *r_is_signed = anywarn ? 2 : 1; /* Good signature. */
1425 if ((s->flags & M_DISPLAY))
1426 state_attach_puts (_("[-- End signature " "information --]\n\n"), s);
1428 gpgme_release (ctx);
1433 tattach = mutt_read_mime_header (fpout, 0);
1436 * Need to set the length of this body part.
1438 fstat (fileno (fpout), &info);
1439 tattach->length = info.st_size - tattach->offset;
1441 tattach->warnsig = anywarn;
1443 /* See if we need to recurse on this MIME part. */
1444 mutt_parse_part (fpout, tattach);
1450 /* Decrypt a PGP/MIME message in FPIN and B and return a new body and
1451 the stream in CUR and FPOUT. Returns 0 on success. */
1452 int pgp_gpgme_decrypt_mime (FILE * fpin, FILE ** fpout, BODY * b, BODY ** cur)
1454 char tempfile[_POSIX_PATH_MAX];
1456 BODY *first_part = b;
1459 first_part->goodsig = 0;
1460 first_part->warnsig = 0;
1462 if (!mutt_is_multipart_encrypted (b))
1465 if (!b->parts || !b->parts->next)
1472 mutt_mktemp (tempfile);
1473 if (!(*fpout = safe_fopen (tempfile, "w+"))) {
1474 mutt_perror (tempfile);
1479 *cur = decrypt_part (b, &s, *fpout, 0, &is_signed);
1482 first_part->goodsig = 1;
1484 return *cur ? 0 : -1;
1488 /* Decrypt a S/MIME message in FPIN and B and return a new body and
1489 the stream in CUR and FPOUT. Returns 0 on success. */
1490 int smime_gpgme_decrypt_mime (FILE * fpin, FILE ** fpout, BODY * b,
1493 char tempfile[_POSIX_PATH_MAX];
1497 long saved_b_offset;
1498 ssize_t saved_b_length;
1501 if (!mutt_is_application_smime (b))
1507 /* Decode the body - we need to pass binary CMS to the
1508 backend. The backend allows for Base64 encoded data but it does
1509 not allow for QP which I have seen in some messages. So better
1511 saved_b_type = b->type;
1512 saved_b_offset = b->offset;
1513 saved_b_length = b->length;
1516 fseeko (s.fpin, b->offset, 0);
1517 mutt_mktemp (tempfile);
1518 if (!(tmpfp = safe_fopen (tempfile, "w+"))) {
1519 mutt_perror (tempfile);
1522 mutt_unlink (tempfile);
1525 mutt_decode_attachment (b, &s);
1527 b->length = ftello (s.fpout);
1534 mutt_mktemp (tempfile);
1535 if (!(*fpout = safe_fopen (tempfile, "w+"))) {
1536 mutt_perror (tempfile);
1539 mutt_unlink (tempfile);
1541 *cur = decrypt_part (b, &s, *fpout, 1, &is_signed);
1543 (*cur)->goodsig = is_signed > 0;
1544 b->type = saved_b_type;
1545 b->length = saved_b_length;
1546 b->offset = saved_b_offset;
1549 if (*cur && !is_signed && !(*cur)->parts
1550 && mutt_is_application_smime (*cur)) {
1551 /* Assume that this is a opaque signed s/mime message. This is
1552 an ugly way of doing it but we have anyway a problem with
1553 arbitrary encoded S/MIME messages: Only the outer part may be
1554 encrypted. The entire mime parsing should be revamped,
1555 probably by keeping the temportary files so that we don't
1556 need to decrypt them all the time. Inner parts of an
1557 encrypted part can then pint into this file and tehre won't
1558 never be a need to decrypt again. This needs a partial
1559 rewrite of the MIME engine. */
1563 saved_b_type = bb->type;
1564 saved_b_offset = bb->offset;
1565 saved_b_length = bb->length;
1568 fseeko (s.fpin, bb->offset, 0);
1569 mutt_mktemp (tempfile);
1570 if (!(tmpfp = safe_fopen (tempfile, "w+"))) {
1571 mutt_perror (tempfile);
1574 mutt_unlink (tempfile);
1577 mutt_decode_attachment (bb, &s);
1579 bb->length = ftello (s.fpout);
1587 mutt_mktemp (tempfile);
1588 if (!(*fpout = safe_fopen (tempfile, "w+"))) {
1589 mutt_perror (tempfile);
1592 mutt_unlink (tempfile);
1594 tmp_b = decrypt_part (bb, &s, *fpout, 1, &is_signed);
1596 tmp_b->goodsig = is_signed > 0;
1597 bb->type = saved_b_type;
1598 bb->length = saved_b_length;
1599 bb->offset = saved_b_offset;
1602 body_list_wipe(cur);
1605 return *cur ? 0 : -1;
1610 * Implementation of `pgp_check_traditional'.
1613 static int pgp_check_traditional_one_body (FILE * fp, BODY * b,
1616 char tempfile[_POSIX_PATH_MAX];
1617 char buf[HUGE_STRING];
1623 if (b->type != TYPETEXT)
1626 if (tagged_only && !b->tagged)
1629 mutt_mktemp (tempfile);
1630 if (mutt_decode_save_attachment (fp, b, tempfile, 0, 0) != 0) {
1635 if ((tfp = fopen (tempfile, "r")) == NULL) {
1640 while (fgets (buf, sizeof (buf), tfp)) {
1641 if (!m_strncmp("-----BEGIN PGP ", buf, 15)) {
1642 if (!m_strcmp("MESSAGE-----\n", buf + 15))
1644 else if (!m_strcmp("SIGNED MESSAGE-----\n", buf + 15))
1654 /* fix the content type */
1656 parameter_setval(&b->parameter, "format", "fixed");
1657 parameter_setval(&b->parameter, "x-action",
1658 enc ? "pgp-encrypted" : "pgp-signed");
1662 int pgp_gpgme_check_traditional (FILE * fp, BODY * b, int tagged_only)
1667 for (; b; b = b->next) {
1668 if (is_multipart (b))
1669 rv = (pgp_gpgme_check_traditional (fp, b->parts, tagged_only) || rv);
1670 else if (b->type == TYPETEXT) {
1671 if ((r = mutt_is_application_pgp (b)))
1674 rv = (pgp_check_traditional_one_body (fp, b, tagged_only) || rv);
1682 * Implementation of `application_handler'.
1686 Copy a clearsigned message, and strip the signature and PGP's
1689 XXX - charset handling: We assume that it is safe to do
1690 character set decoding first, dash decoding second here, while
1691 we do it the other way around in the main handler.
1693 (Note that we aren't worse than Outlook & Cie in this, and also
1694 note that we can successfully handle anything produced by any
1695 existing versions of mutt.) */
1697 static void copy_clearsigned (gpgme_data_t data, STATE * s, char *charset)
1699 char buf[HUGE_STRING];
1700 short complete, armor_header;
1705 fname = data_object_to_tempfile (data, &fp);
1711 fc = fgetconv_open (fp, charset, Charset, M_ICONV_HOOK_FROM);
1713 for (complete = 1, armor_header = 1;
1714 fgetconvs (buf, sizeof (buf), fc) != NULL;
1715 complete = strchr (buf, '\n') != NULL) {
1718 state_puts (buf, s);
1722 if (!m_strcmp(buf, "-----BEGIN PGP SIGNATURE-----\n"))
1732 state_puts (s->prefix, s);
1734 if (buf[0] == '-' && buf[1] == ' ')
1735 state_puts (buf + 2, s);
1737 state_puts (buf, s);
1740 fgetconv_close (&fc);
1745 /* Support for classic_application/pgp */
1746 int pgp_gpgme_application_handler (BODY * m, STATE * s)
1748 int needpass = -1, pgp_keyblock = 0;
1752 off_t last_pos, offset;
1753 char buf[HUGE_STRING];
1754 FILE *pgpout = NULL;
1756 gpgme_error_t err = 0;
1757 gpgme_data_t armored_data = NULL;
1759 short maybe_goodsig = 1;
1760 short have_any_sigs = 0;
1762 char body_charset[STRING]; /* Only used for clearsigned messages. */
1764 /* For clearsigned messages we won't be able to get a character set
1765 but we know that this may only be text thus we assume Latin-1
1767 if (!mutt_get_body_charset (body_charset, sizeof (body_charset), m))
1768 m_strcpy(body_charset, sizeof(body_charset), "iso-8859-1");
1770 fseeko (s->fpin, m->offset, 0);
1771 last_pos = m->offset;
1773 for (bytes = m->length; bytes > 0;) {
1774 if (fgets (buf, sizeof (buf), s->fpin) == NULL)
1777 offset = ftello (s->fpin);
1778 bytes -= (offset - last_pos); /* don't rely on m_strlen(buf) */
1781 if (!m_strncmp("-----BEGIN PGP ", buf, 15)) {
1783 start_pos = last_pos;
1785 if (!m_strcmp("MESSAGE-----\n", buf + 15))
1787 else if (!m_strcmp("SIGNED MESSAGE-----\n", buf + 15)) {
1791 else if (!option (OPTDONTHANDLEPGPKEYS) &&
1792 !m_strcmp("PUBLIC KEY BLOCK-----\n", buf + 15)) {
1797 /* XXX - we may wish to recode here */
1799 state_puts (s->prefix, s);
1800 state_puts (buf, s);
1804 have_any_sigs = (have_any_sigs || (clearsign && (s->flags & M_VERIFY)));
1806 /* Copy PGP material to an data container */
1807 armored_data = create_gpgme_data ();
1808 gpgme_data_write (armored_data, buf, m_strlen(buf));
1809 while (bytes > 0 && fgets (buf, sizeof (buf) - 1, s->fpin) != NULL) {
1810 offset = ftello (s->fpin);
1811 bytes -= (offset - last_pos); /* don't rely on m_strlen(buf) */
1814 gpgme_data_write (armored_data, buf, m_strlen(buf));
1816 if ((needpass && !m_strcmp("-----END PGP MESSAGE-----\n", buf))
1818 && (!m_strcmp("-----END PGP SIGNATURE-----\n", buf)
1819 || !m_strcmp("-----END PGP PUBLIC KEY BLOCK-----\n",
1824 /* Invoke PGP if needed */
1825 if (!clearsign || (s->flags & M_VERIFY)) {
1826 unsigned int sig_stat = 0;
1827 gpgme_data_t plaintext;
1830 plaintext = create_gpgme_data ();
1831 ctx = create_gpgme_context (0);
1834 err = gpgme_op_verify (ctx, armored_data, NULL, plaintext);
1836 err = gpgme_op_decrypt_verify (ctx, armored_data, plaintext);
1837 if (gpg_err_code (err) == GPG_ERR_NO_DATA) {
1838 /* Decrypt verify can't handle signed only messages. */
1839 err = (gpgme_data_seek (armored_data, 0, SEEK_SET) == -1)
1840 ? gpgme_error_from_errno (errno) : 0;
1841 /* Must release plaintext so that we supply an
1842 uninitialized object. */
1843 gpgme_data_release (plaintext);
1844 plaintext = create_gpgme_data ();
1845 err = gpgme_op_verify (ctx, armored_data, NULL, plaintext);
1852 snprintf (errbuf, sizeof (errbuf) - 1,
1853 _("Error: decryption/verification failed: %s\n"),
1854 gpgme_strerror (err));
1855 state_attach_puts (errbuf, s);
1857 else { /* Decryption/Verification succeeded */
1861 /* Check wether signatures have been verified. */
1862 gpgme_verify_result_t verify_result;
1864 verify_result = gpgme_op_verify_result (ctx);
1865 if (verify_result->signatures)
1871 if ((s->flags & M_DISPLAY) && sig_stat) {
1876 state_attach_puts (_("[-- Begin signature "
1877 "information --]\n"), s);
1880 (res = show_one_sig_status (ctx, idx, s)) != -1; idx++) {
1889 state_attach_puts (_("[-- End signature "
1890 "information --]\n\n"), s);
1893 tmpfname = data_object_to_tempfile (plaintext, &pgpout);
1896 state_attach_puts (_("Error: copy data failed\n"), s);
1900 p_delete(&tmpfname);
1903 gpgme_release (ctx);
1907 * Now, copy cleartext to the screen. NOTE - we expect that PGP
1908 * outputs utf-8 cleartext. This may not always be true, but it
1909 * seems to be a reasonable guess.
1912 if (s->flags & M_DISPLAY) {
1914 state_attach_puts (_("[-- BEGIN PGP MESSAGE --]\n\n"), s);
1915 else if (pgp_keyblock)
1916 state_attach_puts (_("[-- BEGIN PGP PUBLIC KEY BLOCK --]\n"), s);
1918 state_attach_puts (_("[-- BEGIN PGP SIGNED MESSAGE --]\n\n"), s);
1922 copy_clearsigned (armored_data, s, body_charset);
1929 fc = fgetconv_open (pgpout, "utf-8", Charset, 0);
1930 while ((c = fgetconv (fc)) != EOF) {
1932 if (c == '\n' && s->prefix)
1933 state_puts (s->prefix, s);
1935 fgetconv_close (&fc);
1938 if (s->flags & M_DISPLAY) {
1939 state_putc ('\n', s);
1941 state_attach_puts (_("[-- END PGP MESSAGE --]\n"), s);
1942 else if (pgp_keyblock)
1943 state_attach_puts (_("[-- END PGP PUBLIC KEY BLOCK --]\n"), s);
1945 state_attach_puts (_("[-- END PGP SIGNED MESSAGE --]\n"), s);
1949 safe_fclose (&pgpout);
1953 /* XXX - we may wish to recode here */
1955 state_puts (s->prefix, s);
1956 state_puts (buf, s);
1960 m->goodsig = (maybe_goodsig && have_any_sigs);
1962 if (needpass == -1) {
1963 state_attach_puts (_("[-- Error: could not find beginning"
1964 " of PGP message! --]\n\n"), s);
1971 * Implementation of `encrypted_handler'.
1974 /* MIME handler for pgp/mime encrypted messages. */
1975 int pgp_gpgme_encrypted_handler (BODY * a, STATE * s)
1977 char tempfile[_POSIX_PATH_MAX];
1980 BODY *orig_body = a;
1985 if (!a || a->type != TYPEAPPLICATION || !a->subtype
1986 || ascii_strcasecmp ("pgp-encrypted", a->subtype)
1987 || !a->next || a->next->type != TYPEAPPLICATION || !a->next->subtype
1988 || ascii_strcasecmp ("octet-stream", a->next->subtype)) {
1989 if (s->flags & M_DISPLAY)
1990 state_attach_puts (_("[-- Error: malformed PGP/MIME message! --]\n\n"),
1995 /* Move forward to the application/pgp-encrypted body. */
1998 mutt_mktemp (tempfile);
1999 if (!(fpout = safe_fopen (tempfile, "w+"))) {
2000 if (s->flags & M_DISPLAY)
2001 state_attach_puts (_("[-- Error: could not create temporary file! "
2006 tattach = decrypt_part (a, s, fpout, 0, &is_signed);
2008 tattach->goodsig = is_signed > 0;
2010 if (s->flags & M_DISPLAY)
2011 state_attach_puts (is_signed ?
2013 ("[-- The following data is PGP/MIME signed and encrypted --]\n\n") :
2014 _("[-- The following data is PGP/MIME encrypted --]\n\n"), s);
2017 FILE *savefp = s->fpin;
2020 rc = mutt_body_handler (tattach, s);
2025 * if a multipart/signed is the _only_ sub-part of a
2026 * multipart/encrypted, cache signature verification
2029 if (mutt_is_multipart_signed (tattach) && !tattach->next)
2030 orig_body->goodsig |= tattach->goodsig;
2032 if (s->flags & M_DISPLAY) {
2033 state_puts ("\n", s);
2034 state_attach_puts (is_signed ?
2036 ("[-- End of PGP/MIME signed and encrypted data --]\n")
2037 : _("[-- End of PGP/MIME encrypted data --]\n"), s);
2040 body_list_wipe(&tattach);
2044 mutt_unlink (tempfile);
2048 /* Support for application/smime */
2049 int smime_gpgme_application_handler (BODY * a, STATE * s)
2051 char tempfile[_POSIX_PATH_MAX];
2058 mutt_mktemp (tempfile);
2059 if (!(fpout = safe_fopen (tempfile, "w+"))) {
2060 if (s->flags & M_DISPLAY)
2061 state_attach_puts (_("[-- Error: could not create temporary file! "
2066 tattach = decrypt_part (a, s, fpout, 1, &is_signed);
2068 tattach->goodsig = is_signed > 0;
2070 if (s->flags & M_DISPLAY)
2071 state_attach_puts (is_signed ?
2072 _("[-- The following data is S/MIME signed --]\n\n") :
2073 _("[-- The following data is S/MIME encrypted --]\n\n"), s);
2076 FILE *savefp = s->fpin;
2079 rc = mutt_body_handler (tattach, s);
2084 * if a multipart/signed is the _only_ sub-part of a
2085 * multipart/encrypted, cache signature verification
2088 if (mutt_is_multipart_signed (tattach) && !tattach->next) {
2089 if (!(a->goodsig = tattach->goodsig))
2090 a->warnsig = tattach->warnsig;
2092 else if (tattach->goodsig) {
2094 a->warnsig = tattach->warnsig;
2097 if (s->flags & M_DISPLAY) {
2098 state_puts ("\n", s);
2099 state_attach_puts (is_signed ?
2100 _("[-- End of S/MIME signed data --]\n") :
2101 _("[-- End of S/MIME encrypted data --]\n"), s);
2104 body_list_wipe(&tattach);
2108 mutt_unlink (tempfile);
2114 * Format an entry on the CRYPT key selection menu.
2117 * %k key id %K key id of the principal key
2119 * %a algorithm %A algorithm of the princ. key
2120 * %l length %L length of the princ. key
2121 * %f flags %F flags of the princ. key
2122 * %c capabilities %C capabilities of the princ. key
2123 * %t trust/validity of the key-uid association
2125 * %[...] date of key using strftime(3)
2129 crypt_entry_fmt (char *dest, ssize_t destlen, char op,
2130 const char *src, const char *prefix,
2131 const char *ifstring, const char *elsestring,
2132 unsigned long data, format_flag flags)
2135 crypt_entry_t *entry;
2138 int optional = (flags & M_FORMAT_OPTIONAL);
2139 const char *s = NULL;
2142 entry = (crypt_entry_t *) data;
2145 /* if (isupper ((unsigned char) op)) */
2148 kflags = (key->flags /*| (pkey->flags & KEYFLAG_RESTRICTIONS)
2151 switch (ascii_tolower (op)) {
2155 char buf2[SHORT_STRING], *p;
2171 while (len > 0 && *cp != ']') {
2180 break; /* not enough space */
2190 if (do_locales && Locale)
2191 setlocale (LC_TIME, Locale);
2196 if (key->kobj->subkeys && (key->kobj->subkeys->timestamp > 0))
2197 tt = key->kobj->subkeys->timestamp;
2199 tm = localtime (&tt);
2201 strftime (buf2, sizeof (buf2), dest, tm);
2204 setlocale (LC_TIME, "C");
2206 snprintf (fmt, sizeof (fmt), "%%%ss", prefix);
2207 snprintf (dest, destlen, fmt, buf2);
2214 snprintf (fmt, sizeof (fmt), "%%%sd", prefix);
2215 snprintf (dest, destlen, fmt, entry->num);
2220 /* fixme: we need a way to distinguish between main and subkeys.
2221 Store the idx in entry? */
2222 snprintf (fmt, sizeof (fmt), "%%%ss", prefix);
2223 snprintf (dest, destlen, fmt, crypt_keyid (key));
2228 snprintf (fmt, sizeof (fmt), "%%%ss", prefix);
2229 snprintf (dest, destlen, fmt, key->uid);
2234 snprintf (fmt, sizeof (fmt), "%%%s.3s", prefix);
2235 if (key->kobj->subkeys)
2236 s = gpgme_pubkey_algo_name (key->kobj->subkeys->pubkey_algo);
2239 snprintf (dest, destlen, fmt, s);
2244 snprintf (fmt, sizeof (fmt), "%%%slu", prefix);
2245 if (key->kobj->subkeys)
2246 val = key->kobj->subkeys->length;
2249 snprintf (dest, destlen, fmt, val);
2254 snprintf (fmt, sizeof (fmt), "%%%sc", prefix);
2255 snprintf (dest, destlen, fmt, crypt_flags (kflags));
2257 else if (!(kflags & (KEYFLAG_RESTRICTIONS)))
2262 snprintf (fmt, sizeof (fmt), "%%%ss", prefix);
2263 snprintf (dest, destlen, fmt, crypt_key_abilities (kflags));
2265 else if (!(kflags & (KEYFLAG_ABILITIES)))
2269 if ((kflags & KEYFLAG_ISX509))
2272 gpgme_user_id_t uid = NULL;
2275 for (i = 0, uid = key->kobj->uids; uid && (i < key->idx);
2276 i++, uid = uid->next);
2278 switch (uid->validity) {
2279 case GPGME_VALIDITY_UNDEFINED:
2282 case GPGME_VALIDITY_NEVER:
2285 case GPGME_VALIDITY_MARGINAL:
2288 case GPGME_VALIDITY_FULL:
2291 case GPGME_VALIDITY_ULTIMATE:
2294 case GPGME_VALIDITY_UNKNOWN:
2300 snprintf (fmt, sizeof (fmt), "%%%sc", prefix);
2301 snprintf (dest, destlen, fmt, s ? *s : 'B');
2304 snprintf (fmt, sizeof (fmt), "%%%ss", prefix);
2305 snprintf (dest, destlen, fmt,
2306 gpgme_get_protocol_name (key->kobj->protocol));
2314 mutt_FormatString (dest, destlen, ifstring, mutt_attach_fmt, data, 0);
2315 else if (flags & M_FORMAT_OPTIONAL)
2316 mutt_FormatString (dest, destlen, elsestring, mutt_attach_fmt, data, 0);
2320 /* Used by the display fucntion to format a line. */
2321 static void crypt_entry (char *s, ssize_t l, MUTTMENU * menu, int num)
2323 crypt_key_t **key_table = (crypt_key_t **) menu->data;
2324 crypt_entry_t entry;
2326 entry.key = key_table[num];
2327 entry.num = num + 1;
2329 mutt_FormatString (s, l, NONULL (PgpEntryFormat), crypt_entry_fmt,
2330 (unsigned long) &entry, M_FORMAT_ARROWCURSOR);
2333 /* Compare two addresses and the keyid to be used for sorting. */
2334 static int _crypt_compare_address (const void *a, const void *b)
2336 crypt_key_t **s = (crypt_key_t **) a;
2337 crypt_key_t **t = (crypt_key_t **) b;
2340 if ((r = m_strcasecmp((*s)->uid, (*t)->uid)))
2343 return m_strcasecmp(crypt_keyid (*s), crypt_keyid (*t)) > 0;
2346 static int crypt_compare_address (const void *a, const void *b)
2348 return ((PgpSortKeys & SORT_REVERSE) ? !_crypt_compare_address (a, b)
2349 : _crypt_compare_address (a, b));
2353 /* Compare two key IDs and the addresses to be used for sorting. */
2354 static int _crypt_compare_keyid (const void *a, const void *b)
2356 crypt_key_t **s = (crypt_key_t **) a;
2357 crypt_key_t **t = (crypt_key_t **) b;
2360 if ((r = m_strcasecmp(crypt_keyid (*s), crypt_keyid (*t))))
2363 return m_strcasecmp((*s)->uid, (*t)->uid) > 0;
2366 static int crypt_compare_keyid (const void *a, const void *b)
2368 return ((PgpSortKeys & SORT_REVERSE) ? !_crypt_compare_keyid (a, b)
2369 : _crypt_compare_keyid (a, b));
2372 /* Compare 2 creation dates and the addresses. For sorting. */
2373 static int _crypt_compare_date (const void *a, const void *b)
2375 crypt_key_t **s = (crypt_key_t **) a;
2376 crypt_key_t **t = (crypt_key_t **) b;
2377 unsigned long ts = 0, tt = 0;
2379 if ((*s)->kobj->subkeys && ((*s)->kobj->subkeys->timestamp > 0))
2380 ts = (*s)->kobj->subkeys->timestamp;
2381 if ((*t)->kobj->subkeys && ((*t)->kobj->subkeys->timestamp > 0))
2382 tt = (*t)->kobj->subkeys->timestamp;
2389 return m_strcasecmp((*s)->uid, (*t)->uid) > 0;
2392 static int crypt_compare_date (const void *a, const void *b)
2394 return ((PgpSortKeys & SORT_REVERSE) ? !_crypt_compare_date (a, b)
2395 : _crypt_compare_date (a, b));
2398 /* Compare two trust values, the key length, the creation dates. the
2399 addresses and the key IDs. For sorting. */
2400 static int _crypt_compare_trust (const void *a, const void *b)
2402 crypt_key_t **s = (crypt_key_t **) a;
2403 crypt_key_t **t = (crypt_key_t **) b;
2404 unsigned long ts = 0, tt = 0;
2407 if ((r = (((*s)->flags & (KEYFLAG_RESTRICTIONS))
2408 - ((*t)->flags & (KEYFLAG_RESTRICTIONS)))))
2411 if ((*s)->kobj->uids)
2412 ts = (*s)->kobj->uids->validity;
2413 if ((*t)->kobj->uids)
2414 tt = (*t)->kobj->uids->validity;
2415 if ((r = (tt - ts)))
2418 if ((*s)->kobj->subkeys)
2419 ts = (*s)->kobj->subkeys->length;
2420 if ((*t)->kobj->subkeys)
2421 tt = (*t)->kobj->subkeys->length;
2425 if ((*s)->kobj->subkeys && ((*s)->kobj->subkeys->timestamp > 0))
2426 ts = (*s)->kobj->subkeys->timestamp;
2427 if ((*t)->kobj->subkeys && ((*t)->kobj->subkeys->timestamp > 0))
2428 tt = (*t)->kobj->subkeys->timestamp;
2434 if ((r = m_strcasecmp((*s)->uid, (*t)->uid)))
2436 return (m_strcasecmp(crypt_keyid ((*s)), crypt_keyid ((*t)))) > 0;
2439 static int crypt_compare_trust (const void *a, const void *b)
2441 return ((PgpSortKeys & SORT_REVERSE) ? !_crypt_compare_trust (a, b)
2442 : _crypt_compare_trust (a, b));
2445 /* Print the X.500 Distinguished Name part KEY from the array of parts
2447 static int print_dn_part (FILE * fp, struct dn_array_s *dn, const char *key)
2451 for (; dn->key; dn++) {
2452 if (!m_strcmp(dn->key, key)) {
2455 print_utf8 (fp, dn->value, m_strlen(dn->value));
2462 /* Print all parts of a DN in a standard sequence. */
2463 static void print_dn_parts (FILE * fp, struct dn_array_s *dn)
2465 const char *stdpart[] = {
2466 "CN", "OU", "O", "STREET", "L", "ST", "C", NULL
2468 int any = 0, any2 = 0, i;
2470 for (i = 0; stdpart[i]; i++) {
2473 any = print_dn_part (fp, dn, stdpart[i]);
2475 /* now print the rest without any specific ordering */
2476 for (; dn->key; dn++) {
2477 for (i = 0; stdpart[i]; i++) {
2478 if (!m_strcmp(dn->key, stdpart[i]))
2486 any = print_dn_part (fp, dn, dn->key);
2495 /* Parse an RDN; this is a helper to parse_dn(). */
2496 static const unsigned char *parse_dn_part (struct dn_array_s *array,
2497 const unsigned char *string)
2499 const unsigned char *s, *s1;
2503 /* parse attributeType */
2504 for (s = string + 1; *s && *s != '='; s++);
2506 return NULL; /* error */
2509 return NULL; /* empty key */
2510 array->key = p_dupstr(string, n );
2511 p = (unsigned char *) array->key;
2514 if (*string == '#') { /* hexstring */
2516 for (s = string; hexdigitp (s); s++)
2520 return NULL; /* empty or odd number of digits */
2523 array->value = (char *) p;
2524 for (s1 = string; n; s1 += 2, n--)
2528 else { /* regular v3 quoted string */
2529 for (n = 0, s = string; *s; s++) {
2530 if (*s == '\\') { /* pair */
2532 if (*s == ',' || *s == '=' || *s == '+'
2533 || *s == '<' || *s == '>' || *s == '#' || *s == ';'
2534 || *s == '\\' || *s == '\"' || *s == ' ')
2536 else if (hexdigitp (s) && hexdigitp (s + 1)) {
2541 return NULL; /* invalid escape sequence */
2543 else if (*s == '\"')
2544 return NULL; /* invalid encoding */
2545 else if (*s == ',' || *s == '=' || *s == '+'
2546 || *s == '<' || *s == '>' || *s == '#' || *s == ';')
2553 array->value = (char *) p;
2554 for (s = string; n; s++, n--) {
2557 if (hexdigitp (s)) {
2573 /* Parse a DN and return an array-ized one. This is not a validating
2574 parser and it does not support any old-stylish syntax; gpgme is
2575 expected to return only rfc2253 compatible strings. */
2576 static struct dn_array_s *parse_dn (const unsigned char *string)
2578 struct dn_array_s *array;
2579 ssize_t arrayidx, arraysize;
2582 arraysize = 7; /* C,ST,L,O,OU,CN,email */
2583 array = p_new(struct dn_array_s, arraysize + 1);
2586 while (*string == ' ')
2590 if (arrayidx >= arraysize) { /* mutt lacks a real safe_realoc - so we need to copy */
2591 struct dn_array_s *a2;
2594 a2 = p_new(struct dn_array_s, arraysize + 1);
2595 for (i = 0; i < arrayidx; i++) {
2596 a2[i].key = array[i].key;
2597 a2[i].value = array[i].value;
2602 array[arrayidx].key = NULL;
2603 array[arrayidx].value = NULL;
2604 string = parse_dn_part (array + arrayidx, string);
2608 while (*string == ' ')
2610 if (*string && *string != ',' && *string != ';' && *string != '+')
2611 goto failure; /* invalid delimiter */
2615 array[arrayidx].key = NULL;
2616 array[arrayidx].value = NULL;
2620 for (i = 0; i < arrayidx; i++) {
2621 p_delete(&array[i].key);
2622 p_delete(&array[i].value);
2629 /* Print a nice representation of the USERID and make sure it is
2630 displayed in a proper way, which does mean to reorder some parts
2631 for S/MIME's DNs. USERID is a string as returned by the gpgme key
2632 functions. It is utf-8 encoded. */
2633 static void parse_and_print_user_id (FILE * fp, const char *userid)
2638 if (*userid == '<') {
2639 s = strchr (userid + 1, '>');
2641 print_utf8 (fp, userid + 1, s - userid - 1);
2643 else if (*userid == '(')
2644 fputs (_("[Can't display this user ID (unknown encoding)]"), fp);
2645 else if (!digit_or_letter ((const unsigned char *) userid))
2646 fputs (_("[Can't display this user ID (invalid encoding)]"), fp);
2648 struct dn_array_s *dn = parse_dn ((const unsigned char *) userid);
2651 fputs (_("[Can't display this user ID (invalid DN)]"), fp);
2653 print_dn_parts (fp, dn);
2654 for (i = 0; dn[i].key; i++) {
2655 p_delete(&dn[i].key);
2656 p_delete(&dn[i].value);
2664 KEY_CAP_CAN_ENCRYPT,
2669 static unsigned int key_check_cap (gpgme_key_t key, key_cap_t cap)
2671 gpgme_subkey_t subkey = NULL;
2672 unsigned int ret = 0;
2675 case KEY_CAP_CAN_ENCRYPT:
2676 if (!(ret = key->can_encrypt))
2677 for (subkey = key->subkeys; subkey; subkey = subkey->next)
2678 if ((ret = subkey->can_encrypt))
2681 case KEY_CAP_CAN_SIGN:
2682 if (!(ret = key->can_sign))
2683 for (subkey = key->subkeys; subkey; subkey = subkey->next)
2684 if ((ret = subkey->can_sign))
2687 case KEY_CAP_CAN_CERTIFY:
2688 if (!(ret = key->can_certify))
2689 for (subkey = key->subkeys; subkey; subkey = subkey->next)
2690 if ((ret = subkey->can_certify))
2699 /* Print verbose information about a key or certificate to FP. */
2700 static void print_key_info (gpgme_key_t key, FILE * fp)
2703 const char *s = NULL, *s2 = NULL;
2706 char shortbuf[SHORT_STRING];
2707 unsigned long aval = 0;
2711 gpgme_user_id_t uid = NULL;
2714 setlocale (LC_TIME, Locale);
2716 is_pgp = key->protocol == GPGME_PROTOCOL_OpenPGP;
2718 for (idx = 0, uid = key->uids; uid; idx++, uid = uid->next) {
2723 fputs (idx ? _(" aka ......: ") :_("Name ......: "), fp);
2726 fputs (_("[Invalid]"), fp);
2730 print_utf8 (fp, s, m_strlen(s));
2732 parse_and_print_user_id (fp, s);
2736 if (key->subkeys && (key->subkeys->timestamp > 0)) {
2737 tt = key->subkeys->timestamp;
2739 tm = localtime (&tt);
2740 #ifdef HAVE_LANGINFO_D_T_FMT
2741 strftime (shortbuf, sizeof shortbuf, nl_langinfo (D_T_FMT), tm);
2743 strftime (shortbuf, sizeof shortbuf, "%c", tm);
2745 fprintf (fp, _("Valid From : %s\n"), shortbuf);
2748 if (key->subkeys && (key->subkeys->expires > 0)) {
2749 tt = key->subkeys->expires;
2751 tm = localtime (&tt);
2752 #ifdef HAVE_LANGINFO_D_T_FMT
2753 strftime (shortbuf, sizeof shortbuf, nl_langinfo (D_T_FMT), tm);
2755 strftime (shortbuf, sizeof shortbuf, "%c", tm);
2757 fprintf (fp, _("Valid To ..: %s\n"), shortbuf);
2761 s = gpgme_pubkey_algo_name (key->subkeys->pubkey_algo);
2765 s2 = is_pgp ? "PGP" : "X.509";
2768 aval = key->subkeys->length;
2770 fprintf (fp, _("Key Type ..: %s, %lu bit %s\n"), s2, aval, s);
2772 fprintf (fp, _("Key Usage .: "));
2775 if (key_check_cap (key, KEY_CAP_CAN_ENCRYPT)) {
2776 fprintf (fp, "%s%s", delim, _("encryption"));
2779 if (key_check_cap (key, KEY_CAP_CAN_SIGN)) {
2780 fprintf (fp, "%s%s", delim, _("signing"));
2783 if (key_check_cap (key, KEY_CAP_CAN_CERTIFY)) {
2784 fprintf (fp, "%s%s", delim, _("certification"));
2790 s = key->subkeys->fpr;
2791 fputs (_("Fingerprint: "), fp);
2792 if (is_pgp && m_strlen(s) == 40) {
2793 for (i = 0; *s && s[1] && s[2] && s[3] && s[4]; s += 4, i++) {
2798 putc (is_pgp ? ' ' : ':', fp);
2799 if (is_pgp && i == 4)
2804 for (i = 0; *s && s[1] && s[2]; s += 2, i++) {
2807 putc (is_pgp ? ' ' : ':', fp);
2808 if (is_pgp && i == 7)
2812 fprintf (fp, "%s\n", s);
2815 if (key->issuer_serial) {
2816 s = key->issuer_serial;
2818 fprintf (fp, _("Serial-No .: 0x%s\n"), s);
2821 if (key->issuer_name) {
2822 s = key->issuer_name;
2824 fprintf (fp, _("Issued By .: "));
2825 parse_and_print_user_id (fp, s);
2830 /* For PGP we list all subkeys. */
2832 gpgme_subkey_t subkey = NULL;
2834 for (idx = 1, subkey = key->subkeys; subkey; idx++, subkey = subkey->next) {
2838 if (m_strlen(s) == 16)
2839 s += 8; /* display only the short keyID */
2840 fprintf (fp, _("Subkey ....: 0x%s"), s);
2841 if (subkey->revoked) {
2843 fputs (_("[Revoked]"), fp);
2845 if (subkey->invalid) {
2847 fputs (_("[Invalid]"), fp);
2849 if (subkey->expired) {
2851 fputs (_("[Expired]"), fp);
2853 if (subkey->disabled) {
2855 fputs (_("[Disabled]"), fp);
2859 if (subkey->timestamp > 0) {
2860 tt = subkey->timestamp;
2862 tm = localtime (&tt);
2863 #ifdef HAVE_LANGINFO_D_T_FMT
2864 strftime (shortbuf, sizeof shortbuf, nl_langinfo (D_T_FMT), tm);
2866 strftime (shortbuf, sizeof shortbuf, "%c", tm);
2868 fprintf (fp, _("Valid From : %s\n"), shortbuf);
2871 if (subkey->expires > 0) {
2872 tt = subkey->expires;
2874 tm = localtime (&tt);
2875 #ifdef HAVE_LANGINFO_D_T_FMT
2876 strftime (shortbuf, sizeof shortbuf, nl_langinfo (D_T_FMT), tm);
2878 strftime (shortbuf, sizeof shortbuf, "%c", tm);
2880 fprintf (fp, _("Valid To ..: %s\n"), shortbuf);
2884 s = gpgme_pubkey_algo_name (subkey->pubkey_algo);
2889 aval = subkey->length;
2893 fprintf (fp, _("Key Type ..: %s, %lu bit %s\n"), "PGP", aval, s);
2895 fprintf (fp, _("Key Usage .: "));
2898 if (subkey->can_encrypt) {
2899 fprintf (fp, "%s%s", delim, _("encryption"));
2902 if (subkey->can_sign) {
2903 fprintf (fp, "%s%s", delim, _("signing"));
2906 if (subkey->can_certify) {
2907 fprintf (fp, "%s%s", delim, _("certification"));
2915 setlocale (LC_TIME, "C");
2919 /* Show detailed information about the selected key */
2920 static void verify_key (crypt_key_t * key)
2923 char cmd[LONG_STRING], tempfile[_POSIX_PATH_MAX];
2925 gpgme_ctx_t listctx = NULL;
2927 gpgme_key_t k = NULL;
2930 mutt_mktemp (tempfile);
2931 if (!(fp = safe_fopen (tempfile, "w"))) {
2932 mutt_perror (_("Can't create temporary file"));
2936 mutt_message _("Collecting data...");
2938 print_key_info (key->kobj, fp);
2940 err = gpgme_new (&listctx);
2942 fprintf (fp, "Internal error: can't create gpgme context: %s\n",
2943 gpgme_strerror (err));
2946 if ((key->flags & KEYFLAG_ISX509))
2947 gpgme_set_protocol (listctx, GPGME_PROTOCOL_CMS);
2951 while ((s = k->chain_id) && k->subkeys && m_strcmp(s, k->subkeys->fpr)) {
2953 err = gpgme_op_keylist_start (listctx, s, 0);
2954 gpgme_key_release (k);
2957 err = gpgme_op_keylist_next (listctx, &k);
2959 fprintf (fp, _("Error finding issuer key: %s\n"), gpgme_strerror (err));
2962 gpgme_op_keylist_end (listctx);
2964 print_key_info (k, fp);
2967 fputs (_("Error: certification chain to long - stopping here\n"), fp);
2973 gpgme_key_release (k);
2974 gpgme_release (listctx);
2976 mutt_clear_error ();
2977 snprintf (cmd, sizeof (cmd), _("Key ID: 0x%s"), crypt_keyid (key));
2978 mutt_do_pager (cmd, tempfile, 0, NULL);
2982 * Implementation of `findkeys'.
2986 /* Convert string_list_t into a pattern string suitable to be passed to GPGME.
2987 We need to convert spaces in an item into a '+' and '%' into
2989 static char *list_to_pattern (string_list_t * list)
2997 for (l = list; l; l = l->next) {
2998 for (s = l->data; *s; s++) {
3003 n++; /* delimiter or end of string */
3005 n++; /* make sure to allocate at least one byte */
3006 pattern = p = p_new(char, n);
3007 for (l = list; l; l = l->next) {
3012 for (s = l->data; *s; s++) {
3018 else if (*s == '+') {
3034 /* Return a list of keys which are candidates for the selection.
3035 Select by looking at the HINTS list. */
3036 static crypt_key_t *get_candidates (string_list_t * hints, unsigned int app,
3039 crypt_key_t *db, *k, **kend;
3045 gpgme_user_id_t uid = NULL;
3047 pattern = list_to_pattern (hints);
3051 err = gpgme_new (&ctx);
3053 mutt_error (_("gpgme_new failed: %s"), gpgme_strerror (err));
3061 if ((app & APPLICATION_PGP)) {
3062 /* Its all a mess. That old GPGME expects different things
3063 depending on the protocol. For gpg we don' t need percent
3064 escaped pappert but simple strings passed in an array to the
3065 keylist_ext_start function. */
3070 for (l = hints, n = 0; l; l = l->next) {
3071 if (l->data && *l->data)
3077 patarr = p_new(char *, n + 1);
3078 for (l = hints, n = 0; l; l = l->next) {
3079 if (l->data && *l->data)
3080 patarr[n++] = m_strdup(l->data);
3083 err = gpgme_op_keylist_ext_start (ctx, (const char **) patarr, secret, 0);
3084 for (n = 0; patarr[n]; n++)
3085 p_delete(&patarr[n]);
3088 mutt_error (_("gpgme_op_keylist_start failed: %s"), gpgme_strerror (err));
3089 gpgme_release (ctx);
3094 while (!(err = gpgme_op_keylist_next (ctx, &key))) {
3095 unsigned int flags = 0;
3097 if (key_check_cap (key, KEY_CAP_CAN_ENCRYPT))
3098 flags |= KEYFLAG_CANENCRYPT;
3099 if (key_check_cap (key, KEY_CAP_CAN_SIGN))
3100 flags |= KEYFLAG_CANSIGN;
3102 #if 0 /* DISABLED code */
3104 /* Bug in gpg. Capabilities are not listed for secret
3105 keys. Try to deduce them from the algorithm. */
3107 switch (key->subkeys[0].pubkey_algo) {
3109 flags |= KEYFLAG_CANENCRYPT;
3110 flags |= KEYFLAG_CANSIGN;
3112 case GPGME_PK_ELG_E:
3113 flags |= KEYFLAG_CANENCRYPT;
3116 flags |= KEYFLAG_CANSIGN;
3120 #endif /* DISABLED code */
3122 for (idx = 0, uid = key->uids; uid; idx++, uid = uid->next) {
3123 k = p_new(crypt_key_t, 1);
3132 if (gpg_err_code (err) != GPG_ERR_EOF)
3133 mutt_error (_("gpgme_op_keylist_next failed: %s"), gpgme_strerror (err));
3134 gpgme_op_keylist_end (ctx);
3139 if ((app & APPLICATION_SMIME)) {
3140 /* and now look for x509 certificates */
3141 gpgme_set_protocol (ctx, GPGME_PROTOCOL_CMS);
3142 err = gpgme_op_keylist_start (ctx, pattern, 0);
3144 mutt_error (_("gpgme_op_keylist_start failed: %s"), gpgme_strerror (err));
3145 gpgme_release (ctx);
3150 while (!(err = gpgme_op_keylist_next (ctx, &key))) {
3151 unsigned int flags = KEYFLAG_ISX509;
3153 if (key_check_cap (key, KEY_CAP_CAN_ENCRYPT))
3154 flags |= KEYFLAG_CANENCRYPT;
3155 if (key_check_cap (key, KEY_CAP_CAN_SIGN))
3156 flags |= KEYFLAG_CANSIGN;
3158 for (idx = 0, uid = key->uids; uid; idx++, uid = uid->next) {
3159 k = p_new(crypt_key_t, 1);
3168 if (gpg_err_code (err) != GPG_ERR_EOF)
3169 mutt_error (_("gpgme_op_keylist_next failed: %s"), gpgme_strerror (err));
3170 gpgme_op_keylist_end (ctx);
3173 gpgme_release (ctx);
3178 /* Add the string STR to the list HINTS. This list is later used to
3180 static string_list_t *crypt_add_string_to_hints (string_list_t * hints, const char *str)
3185 if ((scratch = m_strdup(str)) == NULL)
3188 for (t = strtok (scratch, " ,.:\"()<>\n"); t;
3189 t = strtok (NULL, " ,.:\"()<>\n")) {
3190 if (m_strlen(t) > 3)
3191 hints = mutt_add_list(hints, t);
3198 /* Display a menu to select a key from the array KEYS. FORCED_VALID
3199 will be set to true on return if the user did override the the
3201 static crypt_key_t *crypt_select_key (crypt_key_t * keys,
3202 address_t * p, const char *s,
3203 unsigned int app, int *forced_valid)
3206 crypt_key_t **key_table;
3209 char helpstr[SHORT_STRING], buf[LONG_STRING];
3211 int (*f) (const void *, const void *);
3212 int menu_to_use = 0;
3217 /* build the key table */
3220 for (k = keys; k; k = k->next) {
3221 if (!option (OPTPGPSHOWUNUSABLE) && (k->flags & KEYFLAG_CANTUSE)) {
3228 p_realloc(&key_table, keymax);
3234 if (!i && unusable) {
3235 mutt_error _("All matching keys are marked expired/revoked.");
3241 switch (PgpSortKeys & SORT_MASK) {
3243 f = crypt_compare_date;
3246 f = crypt_compare_keyid;
3249 f = crypt_compare_address;
3253 f = crypt_compare_trust;
3256 qsort (key_table, i, sizeof (crypt_key_t *), f);
3258 if (app & APPLICATION_PGP)
3259 menu_to_use = MENU_KEY_SELECT_PGP;
3260 else if (app & APPLICATION_SMIME)
3261 menu_to_use = MENU_KEY_SELECT_SMIME;
3264 mutt_make_help (buf, sizeof (buf), _("Exit "), menu_to_use, OP_EXIT);
3265 strcat (helpstr, buf); /* __STRCAT_CHECKED__ */
3266 mutt_make_help (buf, sizeof (buf), _("Select "), menu_to_use,
3267 OP_GENERIC_SELECT_ENTRY);
3268 strcat (helpstr, buf); /* __STRCAT_CHECKED__ */
3269 mutt_make_help (buf, sizeof (buf), _("Check key "),
3270 menu_to_use, OP_VERIFY_KEY);
3271 strcat (helpstr, buf); /* __STRCAT_CHECKED__ */
3272 mutt_make_help (buf, sizeof (buf), _("Help"), menu_to_use, OP_HELP);
3273 strcat (helpstr, buf); /* __STRCAT_CHECKED__ */
3275 menu = mutt_new_menu ();
3277 menu->make_entry = crypt_entry;
3278 menu->menu = menu_to_use;
3279 menu->help = helpstr;
3280 menu->data = key_table;
3285 if ((app & APPLICATION_PGP) && (app & APPLICATION_SMIME))
3286 ts = _("PGP and S/MIME keys matching");
3287 else if ((app & APPLICATION_PGP))
3288 ts = _("PGP keys matching");
3289 else if ((app & APPLICATION_SMIME))
3290 ts = _("S/MIME keys matching");
3292 ts = _("keys matching");
3295 snprintf (buf, sizeof (buf), _("%s <%s>."), ts, p->mailbox);
3297 snprintf (buf, sizeof (buf), _("%s \"%s\"."), ts, s);
3301 mutt_clear_error ();
3305 switch (mutt_menuLoop (menu)) {
3307 verify_key (key_table[menu->current]);
3308 menu->redraw = REDRAW_FULL;
3312 mutt_message ("%s", key_table[menu->current]->uid);
3315 case OP_GENERIC_SELECT_ENTRY:
3316 /* FIXME make error reporting more verbose - this should be
3317 easy because gpgme provides more information */
3318 if (option (OPTPGPCHECKTRUST)) {
3319 if (!crypt_key_is_valid (key_table[menu->current])) {
3320 mutt_error _("This key can't be used: "
3321 "expired/disabled/revoked.");
3326 if (option (OPTPGPCHECKTRUST) &&
3327 (!crypt_id_is_valid (key_table[menu->current])
3328 || !crypt_id_is_strong (key_table[menu->current]))) {
3330 char buff[LONG_STRING];
3332 if (key_table[menu->current]->flags & KEYFLAG_CANTUSE)
3333 s = N_("ID is expired/disabled/revoked.");
3335 gpgme_validity_t val = GPGME_VALIDITY_UNKNOWN;
3336 gpgme_user_id_t uid = NULL;
3341 uid = key_table[menu->current]->kobj->uids;
3342 for (j = 0; (j < key_table[menu->current]->idx) && uid;
3343 j++, uid = uid->next);
3345 val = uid->validity;
3348 case GPGME_VALIDITY_UNKNOWN:
3349 case GPGME_VALIDITY_UNDEFINED:
3350 warn_s = N_("ID has undefined validity.");
3352 case GPGME_VALIDITY_NEVER:
3353 warn_s = N_("ID is not valid.");
3355 case GPGME_VALIDITY_MARGINAL:
3356 warn_s = N_("ID is only marginally valid.");
3358 case GPGME_VALIDITY_FULL:
3359 case GPGME_VALIDITY_ULTIMATE:
3363 snprintf (buff, sizeof (buff),
3364 _("%s Do you really want to use the key?"), _(warn_s));
3366 if (mutt_yesorno (buff, 0) != 1) {
3367 mutt_clear_error ();
3374 k = crypt_copy_key (key_table[menu->current]);
3385 mutt_menuDestroy (&menu);
3386 p_delete(&key_table);
3388 set_option (OPTNEEDREDRAW);
3393 static crypt_key_t *crypt_getkeybyaddr (address_t * a, short abilities,
3394 unsigned int app, int *forced_valid)
3397 string_list_t *hints = NULL;
3402 int this_key_has_strong;
3403 int this_key_has_weak;
3404 int this_key_has_invalid;
3407 crypt_key_t *keys, *k;
3408 crypt_key_t *the_valid_key = NULL;
3409 crypt_key_t *matches = NULL;
3410 crypt_key_t **matches_endp = &matches;
3414 if (a && a->mailbox)
3415 hints = crypt_add_string_to_hints (hints, a->mailbox);
3416 if (a && a->personal)
3417 hints = crypt_add_string_to_hints (hints, a->personal);
3419 mutt_message (_("Looking for keys matching \"%s\"..."), a->mailbox);
3420 keys = get_candidates (hints, app, (abilities & KEYFLAG_CANSIGN));
3422 string_list_wipe(&hints);
3427 for (k = keys; k; k = k->next) {
3428 if (abilities && !(k->flags & abilities)) {
3432 this_key_has_weak = 0; /* weak but valid match */
3433 this_key_has_invalid = 0; /* invalid match */
3434 this_key_has_strong = 0; /* strong and valid match */
3435 match = 0; /* any match */
3437 r = rfc822_parse_adrlist (NULL, k->uid);
3438 for (p = r; p; p = p->next) {
3439 int validity = crypt_id_matches_addr (a, p, k);
3441 if (validity & CRYPT_KV_MATCH) /* something matches */
3444 /* is this key a strong candidate? */
3445 if ((validity & CRYPT_KV_VALID)
3446 && (validity & CRYPT_KV_STRONGID)
3447 && (validity & CRYPT_KV_ADDR)) {
3448 if (the_valid_key && the_valid_key != k)
3451 this_key_has_strong = 1;
3453 else if ((validity & CRYPT_KV_MATCH)
3454 && !(validity & CRYPT_KV_VALID))
3455 this_key_has_invalid = 1;
3456 else if ((validity & CRYPT_KV_MATCH)
3457 && (!(validity & CRYPT_KV_STRONGID)
3458 || !(validity & CRYPT_KV_ADDR)))
3459 this_key_has_weak = 1;
3461 address_list_wipe(&r);
3466 if (!this_key_has_strong && this_key_has_invalid)
3468 if (!this_key_has_strong && this_key_has_weak)
3471 *matches_endp = tmp = crypt_copy_key (k);
3472 matches_endp = &tmp->next;
3473 the_valid_key = tmp;
3477 crypt_free_key (&keys);
3480 if (the_valid_key && !multi && !weak
3481 && !(invalid && option (OPTPGPSHOWUNUSABLE))) {
3483 * There was precisely one strong match on a valid ID, there
3484 * were no valid keys with weak matches, and we aren't
3485 * interested in seeing invalid keys.
3487 * Proceed without asking the user.
3489 k = crypt_copy_key (the_valid_key);
3493 * Else: Ask the user.
3495 k = crypt_select_key (matches, a, NULL, app, forced_valid);
3497 crypt_free_key (&matches);
3506 static crypt_key_t *crypt_getkeybystr (const char *p, short abilities,
3507 unsigned int app, int *forced_valid)
3509 string_list_t *hints = NULL;
3511 crypt_key_t *matches = NULL;
3512 crypt_key_t **matches_endp = &matches;
3516 mutt_message (_("Looking for keys matching \"%s\"..."), p);
3520 hints = crypt_add_string_to_hints (hints, p);
3521 keys = get_candidates (hints, app, (abilities & KEYFLAG_CANSIGN));
3522 string_list_wipe(&hints);
3527 for (k = keys; k; k = k->next) {
3528 if (abilities && !(k->flags & abilities))
3533 if (!*p || !m_strcasecmp(p, crypt_keyid (k))
3534 || (!m_strncasecmp(p, "0x", 2)
3535 && !m_strcasecmp(p + 2, crypt_keyid (k)))
3536 || (option (OPTPGPLONGIDS)
3537 && !m_strncasecmp(p, "0x", 2)
3538 && !m_strcasecmp(p + 2, crypt_keyid (k) + 8))
3539 || m_stristr(k->uid, p)) {
3542 *matches_endp = tmp = crypt_copy_key (k);
3543 matches_endp = &tmp->next;
3547 crypt_free_key (&keys);
3550 k = crypt_select_key (matches, NULL, p, app, forced_valid);
3551 crypt_free_key (&matches);
3558 /* Display TAG as a prompt to ask for a key. If WHATFOR is not null
3559 use it as default and store it under that label as the next
3560 default. ABILITIES describe the required key abilities (sign,
3561 encrypt) and APP the type of the requested key; ether S/MIME or
3562 PGP. Return a copy of the key or NULL if not found. */
3563 static crypt_key_t *crypt_ask_for_key (char *tag,
3566 unsigned int app, int *forced_valid)
3569 char resp[SHORT_STRING];
3570 struct crypt_cache *l = NULL;
3574 forced_valid = &dummy;
3576 mutt_clear_error ();
3582 for (l = id_defaults; l; l = l->next)
3583 if (!m_strcasecmp(whatfor, l->what)) {
3584 m_strcpy(resp, sizeof(resp), NONULL(l->dflt));
3592 if (mutt_get_field (tag, resp, sizeof (resp), M_CLEAR) != 0)
3597 m_strreplace(&l->dflt, resp);
3599 l = p_new(struct crypt_cache, 1);
3600 l->next = id_defaults;
3602 l->what = m_strdup(whatfor);
3603 l->dflt = m_strdup(resp);
3607 if ((key = crypt_getkeybystr (resp, abilities, app, forced_valid)))
3615 /* This routine attempts to find the keyids of the recipients of a
3616 message. It returns NULL if any of the keys can not be found. */
3617 static char *find_keys (address_t * to, address_t * cc, address_t * bcc,
3620 char *keylist = NULL, *t;
3622 ssize_t keylist_size = 0;
3623 ssize_t keylist_used = 0;
3624 address_t *tmp = NULL, *addr = NULL;
3625 address_t **last = &tmp;
3628 crypt_key_t *k_info, *key;
3629 const char *fqdn = mutt_fqdn (1);
3632 *r_application = APPLICATION_PGP | APPLICATION_SMIME;
3635 for (i = 0; i < 3; i++) {
3650 *last = address_list_dup (p);
3652 last = &((*last)->next);
3656 rfc822_qualify (tmp, fqdn);
3658 address_list_uniq(tmp);
3660 for (p = tmp; p; p = p->next) {
3661 char buf[LONG_STRING];
3662 int forced_valid = 0;
3667 if ((keyID = mutt_crypt_hook (p)) != NULL) {
3670 snprintf (buf, sizeof (buf), _("Use keyID = \"%s\" for %s?"),
3672 if ((r = mutt_yesorno (buf, M_YES)) == M_YES) {
3673 /* check for e-mail address */
3674 if ((t = strchr (keyID, '@')) &&
3675 (addr = rfc822_parse_adrlist (NULL, keyID))) {
3677 rfc822_qualify (addr, fqdn);
3681 k_info = crypt_getkeybystr (keyID, KEYFLAG_CANENCRYPT,
3682 app, &forced_valid);
3687 address_list_wipe(&tmp);
3688 address_list_wipe(&addr);
3694 && (k_info = crypt_getkeybyaddr (q, KEYFLAG_CANENCRYPT,
3695 app, &forced_valid)) == NULL) {
3696 snprintf (buf, sizeof (buf), _("Enter keyID for %s: "), q->mailbox);
3698 if ((key = crypt_ask_for_key (buf, q->mailbox, KEYFLAG_CANENCRYPT,
3700 &forced_valid)) == NULL) {
3702 address_list_wipe(&tmp);
3703 address_list_wipe(&addr);
3711 const char *s = crypt_fpr (key);
3713 keylist_size += m_strlen(s) + 4 + 1;
3714 p_realloc(&keylist, keylist_size);
3715 sprintf (keylist + keylist_used, "%s0x%s%s", /* __SPRINTF_CHECKED__ */
3716 keylist_used ? " " : "", s, forced_valid ? "!" : "");
3718 keylist_used = m_strlen(keylist);
3720 crypt_free_key (&key);
3721 address_list_wipe(&addr);
3723 address_list_wipe(&tmp);
3727 char *pgp_gpgme_findkeys (address_t * to, address_t * cc, address_t * bcc)
3729 return find_keys (to, cc, bcc, APPLICATION_PGP);
3732 char *smime_gpgme_findkeys (address_t * to, address_t * cc, address_t * bcc)
3734 return find_keys (to, cc, bcc, APPLICATION_SMIME);
3738 * Implementation of `init'.
3741 /* Initialization. */
3742 static void init_gpgme (void)
3744 /* Make sure that gpg-agent is running. */
3745 if (!getenv ("GPG_AGENT_INFO")) {
3746 mutt_error ("\nUsing GPGME backend, although no gpg-agent is running");
3747 if (mutt_any_key_to_continue (NULL) == -1)
3752 void pgp_gpgme_init (void)
3757 void smime_gpgme_init (void)
3761 static int gpgme_send_menu (HEADER * msg, int *redraw, int is_smime)
3764 char input_signas[SHORT_STRING];
3767 if (msg->security & APPLICATION_PGP)
3769 else if (msg->security & APPLICATION_SMIME)
3774 mutt_multi_choice (_
3775 ("S/MIME (e)ncrypt, (s)ign, sign (a)s, (b)oth, (p)gp or (c)lear?"),
3779 mutt_multi_choice (_
3780 ("PGP (e)ncrypt, (s)ign, sign (a)s, (b)oth, s/(m)ime or (c)lear?"),
3784 case 1: /* (e)ncrypt */
3785 msg->security |= (is_smime ? SMIMEENCRYPT : PGPENCRYPT);
3786 msg->security &= ~(is_smime ? SMIMESIGN : PGPSIGN);
3789 case 2: /* (s)ign */
3790 msg->security |= (is_smime ? SMIMESIGN : PGPSIGN);
3791 msg->security &= ~(is_smime ? SMIMEENCRYPT : PGPENCRYPT);
3794 case 3: /* sign (a)s */
3795 /* unset_option(OPTCRYPTCHECKTRUST); */
3796 if ((p = crypt_ask_for_key (_("Sign as: "), NULL, KEYFLAG_CANSIGN,
3797 is_smime ? APPLICATION_SMIME :
3798 APPLICATION_PGP, NULL))) {
3799 snprintf (input_signas, sizeof (input_signas), "0x%s", crypt_keyid (p));
3800 m_strreplace(is_smime ? &SmimeDefaultKey : &PgpSignAs,
3802 crypt_free_key (&p);
3804 msg->security |= (is_smime ? SMIMESIGN : PGPSIGN);
3806 *redraw = REDRAW_FULL;
3809 case 4: /* (b)oth */
3811 (is_smime ? (SMIMEENCRYPT | SMIMESIGN) : (PGPENCRYPT | PGPSIGN));
3814 case 5: /* (p)gp or s/(m)ime */
3815 is_smime = !is_smime;
3818 case 6: /* (c)lear */
3823 if (choice == 6 || choice == 7);
3824 else if (is_smime) {
3825 msg->security &= ~APPLICATION_PGP;
3826 msg->security |= APPLICATION_SMIME;
3829 msg->security &= ~APPLICATION_SMIME;
3830 msg->security |= APPLICATION_PGP;
3833 return (msg->security);
3836 int pgp_gpgme_send_menu (HEADER * msg, int *redraw)
3838 return gpgme_send_menu (msg, redraw, 0);
3841 int smime_gpgme_send_menu (HEADER * msg, int *redraw)
3843 return gpgme_send_menu (msg, redraw, 1);
3846 static int verify_sender (HEADER * h, gpgme_protocol_t protocol __attribute__((unused)))
3848 address_t *sender = NULL;
3849 unsigned int ret = 1;
3852 h->env->from = mutt_expand_aliases (h->env->from);
3853 sender = h->env->from;
3855 else if (h->env->sender) {
3856 h->env->sender = mutt_expand_aliases (h->env->sender);
3857 sender = h->env->sender;
3861 if (signature_key) {
3862 gpgme_key_t key = signature_key;
3863 gpgme_user_id_t uid = NULL;
3864 int sender_length = 0;
3867 sender_length = m_strlen(sender->mailbox);
3868 for (uid = key->uids; uid && ret; uid = uid->next) {
3869 uid_length = m_strlen(uid->email);
3870 if (1 && (uid->email[0] == '<')
3871 && (uid->email[uid_length - 1] == '>')
3872 && (uid_length == sender_length + 2)
3873 && (!strncmp (uid->email + 1, sender->mailbox, sender_length)))
3878 mutt_any_key_to_continue ("Failed to verify sender");
3881 mutt_any_key_to_continue ("Failed to figure out sender");
3883 if (signature_key) {
3884 gpgme_key_release (signature_key);
3885 signature_key = NULL;
3891 int smime_gpgme_verify_sender (HEADER * h)
3893 return verify_sender (h, GPGME_PROTOCOL_CMS);