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 fptmp = m_tempfile(tempfile, sizeof(tempfile), NONULL(Tempdir), NULL);
353 mutt_perror (_("Can't create temporary file"));
357 mutt_write_mime_header (a, fptmp);
359 mutt_write_mime_body (a, fptmp);
363 unsigned char buf[1];
365 data = create_gpgme_data ();
367 while ((c = fgetc (fptmp)) != EOF) {
371 if (c == '\n' && !hadcr) {
373 gpgme_data_write (data, buf, 1);
378 /* FIXME: This is quite suboptimal */
380 gpgme_data_write (data, buf, 1);
382 gpgme_data_seek (data, 0, SEEK_SET);
384 err = gpgme_data_new_from_file (&data, tempfile, 1);
389 mutt_error (_("error allocating data object: %s\n"), gpgme_strerror (err));
396 /* Create a GPGME data object from the stream FP but limit the object
397 to LENGTH bytes starting at OFFSET bytes from the beginning of the
399 static gpgme_data_t file_to_data_object (FILE * fp, long offset, long length)
404 err = gpgme_data_new_from_filepart (&data, NULL, fp, offset, length);
406 mutt_error (_("error allocating data object: %s\n"), gpgme_strerror (err));
413 /* Write a GPGME data object to the stream FP. */
414 static int data_object_to_stream (gpgme_data_t data, FILE * fp)
420 err = ((gpgme_data_seek (data, 0, SEEK_SET) == -1)
421 ? gpgme_error_from_errno (errno) : 0);
423 mutt_error (_("error rewinding data object: %s\n"), gpgme_strerror (err));
427 while ((nread = gpgme_data_read (data, buf, sizeof (buf)))) {
428 /* fixme: we are not really converting CRLF to LF but just
429 skipping CR. Doing it correctly needs a more complex logic */
430 for (p = buf; nread; p++, nread--) {
436 mutt_perror ("[tempfile]");
441 mutt_error (_("error reading data object: %s\n"), strerror (errno));
447 /* Copy a data object to a newly created temporay file and return that
448 filename. Caller must free. With RET_FP not NULL, don't close the
449 stream but return it there. */
450 static char *data_object_to_tempfile (gpgme_data_t data, FILE ** ret_fp)
453 char tempfile[_POSIX_PATH_MAX];
457 fp = m_tempfile(tempfile, sizeof(tempfile), NONULL(Tempdir), NULL);
459 mutt_perror (_("Can't create temporary file"));
463 err = ((gpgme_data_seek (data, 0, SEEK_SET) == -1)
464 ? gpgme_error_from_errno (errno) : 0);
468 while ((nread = gpgme_data_read (data, buf, sizeof (buf)))) {
469 if (fwrite (buf, nread, 1, fp) != 1) {
470 mutt_perror (_("Can't create temporary file"));
482 mutt_error (_("error reading data object: %s\n"), gpgme_strerror (err));
489 return m_strdup(tempfile);
493 /* Create a GpgmeRecipientSet from the keys in the string KEYLIST.
494 The keys must be space delimited. */
495 static gpgme_key_t *create_recipient_set (const char *keylist,
496 gpgme_protocol_t protocol)
502 gpgme_key_t *rset = NULL;
503 unsigned int rset_n = 0;
504 gpgme_key_t key = NULL;
505 gpgme_ctx_t context = NULL;
507 err = gpgme_new (&context);
509 err = gpgme_set_protocol (context, protocol);
516 for (i = 0; *s && *s != ' ' && i < ssizeof(buf) - 1;)
520 if (i > 1 && buf[i - 1] == '!') {
521 /* The user selected to override the valididy of that
525 err = gpgme_get_key (context, buf, &key, 0);
527 key->uids->validity = GPGME_VALIDITY_FULL;
531 err = gpgme_get_key (context, buf, &key, 0);
534 p_realloc(&rset, rset_n + 1);
535 rset[rset_n++] = key;
538 mutt_error (_("error adding recipient `%s': %s\n"),
539 buf, gpgme_strerror (err));
547 /* NULL terminate. */
548 p_realloc(&rset, rset_n + 1);
549 rset[rset_n++] = NULL;
552 gpgme_release (context);
558 /* Make sure that the correct signer is set. Returns 0 on success. */
559 static int set_signer (gpgme_ctx_t ctx, int for_smime)
561 char *signid = for_smime ? SmimeDefaultKey : PgpSignAs;
564 gpgme_key_t key, key2;
566 if (!signid || !*signid)
569 listctx = create_gpgme_context (for_smime);
570 err = gpgme_op_keylist_start (listctx, signid, 1);
572 err = gpgme_op_keylist_next (listctx, &key);
574 gpgme_release (listctx);
575 mutt_error (_("secret key `%s' not found: %s\n"),
576 signid, gpgme_strerror (err));
579 err = gpgme_op_keylist_next (listctx, &key2);
581 gpgme_key_release (key);
582 gpgme_key_release (key2);
583 gpgme_release (listctx);
584 mutt_error (_("ambiguous specification of secret key `%s'\n"), signid);
587 gpgme_op_keylist_end (listctx);
588 gpgme_release (listctx);
590 gpgme_signers_clear (ctx);
591 err = gpgme_signers_add (ctx, key);
592 gpgme_key_release (key);
594 mutt_error (_("error setting secret key `%s': %s\n"),
595 signid, gpgme_strerror (err));
602 /* Encrypt the gpgme data object PLAINTEXT to the recipients in RSET
603 and return an allocated filename to a temporary file containing the
604 enciphered text. With USE_SMIME set to true, the smime backend is
605 used. With COMBINED_SIGNED a PGP message is signed and
606 encrypted. Returns NULL in case of error */
607 static char *encrypt_gpgme_object (gpgme_data_t plaintext, gpgme_key_t * rset,
608 int use_smime, int combined_signed)
612 gpgme_data_t ciphertext;
615 ctx = create_gpgme_context (use_smime);
617 gpgme_set_armor (ctx, 1);
619 ciphertext = create_gpgme_data ();
621 if (combined_signed) {
622 if (set_signer (ctx, use_smime)) {
623 gpgme_data_release (ciphertext);
627 err = gpgme_op_encrypt_sign (ctx, rset, GPGME_ENCRYPT_ALWAYS_TRUST,
628 plaintext, ciphertext);
631 err = gpgme_op_encrypt (ctx, rset, GPGME_ENCRYPT_ALWAYS_TRUST,
632 plaintext, ciphertext);
633 mutt_need_hard_redraw ();
635 mutt_error (_("error encrypting data: %s\n"), gpgme_strerror (err));
636 gpgme_data_release (ciphertext);
643 outfile = data_object_to_tempfile (ciphertext, NULL);
644 gpgme_data_release (ciphertext);
648 /* Find the "micalg" parameter from the last Gpgme operation on
649 context CTX. It is expected that this operation was a sign
650 operation. Return the algorithm name as a C string in buffer BUF
651 which must have been allocated by the caller with size BUFLEN.
652 Returns 0 on success or -1 in case of an error. The return string
653 is truncted to BUFLEN - 1. */
654 static int get_micalg (gpgme_ctx_t ctx, char *buf, ssize_t buflen)
656 gpgme_sign_result_t result = NULL;
657 const char *algorithm_name = NULL;
663 result = gpgme_op_sign_result (ctx);
665 algorithm_name = gpgme_hash_algo_name (result->signatures->hash_algo);
666 if (algorithm_name) {
667 m_strcpy(buf, buflen, algorithm_name);
671 return *buf ? 0 : -1;
674 static void print_time (time_t t, STATE * s)
678 setlocale (LC_TIME, "");
679 #ifdef HAVE_LANGINFO_D_T_FMT
680 strftime (p, sizeof (p), nl_langinfo (D_T_FMT), localtime (&t));
682 strftime (p, sizeof (p), "%c", localtime (&t));
684 setlocale (LC_TIME, "C");
685 state_attach_puts (p, s);
689 * Implementation of `sign_message'.
692 /* Sign the MESSAGE in body A either using OpenPGP or S/MIME when
693 USE_SMIME is passed as true. Returns the new body or NULL on
695 static BODY *sign_message (BODY * a, int use_smime)
702 gpgme_data_t message, signature;
704 convert_to_7bit (a); /* Signed data _must_ be in 7-bit format. */
706 message = body_to_data_object (a, 1);
709 signature = create_gpgme_data ();
711 ctx = create_gpgme_context (use_smime);
713 gpgme_set_armor (ctx, 1);
715 if (set_signer (ctx, use_smime)) {
716 gpgme_data_release (signature);
721 err = gpgme_op_sign (ctx, message, signature, GPGME_SIG_MODE_DETACH);
722 mutt_need_hard_redraw ();
723 gpgme_data_release (message);
725 gpgme_data_release (signature);
727 mutt_error (_("error signing data: %s\n"), gpgme_strerror (err));
731 sigfile = data_object_to_tempfile (signature, NULL);
732 gpgme_data_release (signature);
739 t->type = TYPEMULTIPART;
740 t->subtype = m_strdup("signed");
741 t->encoding = ENC7BIT;
743 t->disposition = DISPINLINE;
745 parameter_set_boundary(&t->parameter);
746 parameter_setval(&t->parameter, "protocol",
747 use_smime ? "application/pkcs7-signature"
748 : "application/pgp-signature");
749 /* Get the micalg from gpgme. Old gpgme versions don't support this
750 for S/MIME so we assume sha-1 in this case. */
751 if (!get_micalg (ctx, buf, sizeof buf))
752 parameter_setval(&t->parameter, "micalg", buf);
754 parameter_setval(&t->parameter, "micalg", "sha1");
760 t->parts->next = body_new();
762 t->type = TYPEAPPLICATION;
764 t->subtype = m_strdup("pkcs7-signature");
765 parameter_setval(&t->parameter, "name", "smime.p7s");
766 t->encoding = ENCBASE64;
768 t->disposition = DISPATTACH;
769 t->d_filename = m_strdup("smime.p7s");
772 t->subtype = m_strdup("pgp-signature");
774 t->disposition = DISPINLINE;
775 t->encoding = ENC7BIT;
777 t->filename = sigfile;
778 t->unlink = 1; /* ok to remove this file after sending. */
784 BODY *pgp_gpgme_sign_message (BODY * a)
786 return sign_message (a, 0);
789 BODY *smime_gpgme_sign_message (BODY * a)
791 return sign_message (a, 1);
795 * Implementation of `encrypt_message'.
798 /* Encrypt the mail body A to all keys given as space separated keyids
799 or fingerprints in KEYLIST and return the encrypted body. */
800 BODY *pgp_gpgme_encrypt_message (BODY * a, char *keylist, int sign)
802 char *outfile = NULL;
804 gpgme_key_t *rset = NULL;
805 gpgme_data_t plaintext;
807 rset = create_recipient_set (keylist, GPGME_PROTOCOL_OpenPGP);
813 plaintext = body_to_data_object (a, 0);
819 outfile = encrypt_gpgme_object (plaintext, rset, 0, sign);
820 gpgme_data_release (plaintext);
826 t->type = TYPEMULTIPART;
827 t->subtype = m_strdup("encrypted");
828 t->encoding = ENC7BIT;
830 t->disposition = DISPINLINE;
832 parameter_set_boundary(&t->parameter);
833 parameter_setval(&t->parameter, "protocol", "application/pgp-encrypted");
835 t->parts = body_new();
836 t->parts->type = TYPEAPPLICATION;
837 t->parts->subtype = m_strdup("pgp-encrypted");
838 t->parts->encoding = ENC7BIT;
840 t->parts->next = body_new();
841 t->parts->next->type = TYPEAPPLICATION;
842 t->parts->next->subtype = m_strdup("octet-stream");
843 t->parts->next->encoding = ENC7BIT;
844 t->parts->next->filename = outfile;
845 t->parts->next->use_disp = 1;
846 t->parts->next->disposition = DISPINLINE;
847 t->parts->next->unlink = 1; /* delete after sending the message */
848 t->parts->next->d_filename = m_strdup("msg.asc"); /* non pgp/mime
855 * Implementation of `smime_build_smime_entity'.
858 /* Encrypt the mail body A to all keys given as space separated
859 fingerprints in KEYLIST and return the S/MIME encrypted body. */
860 BODY *smime_gpgme_build_smime_entity (BODY * a, char *keylist)
862 char *outfile = NULL;
864 gpgme_key_t *rset = NULL;
865 gpgme_data_t plaintext;
867 rset = create_recipient_set (keylist, GPGME_PROTOCOL_CMS);
871 plaintext = body_to_data_object (a, 0);
877 outfile = encrypt_gpgme_object (plaintext, rset, 1, 0);
878 gpgme_data_release (plaintext);
884 t->type = TYPEAPPLICATION;
885 t->subtype = m_strdup("pkcs7-mime");
886 parameter_setval(&t->parameter, "name", "smime.p7m");
887 parameter_setval(&t->parameter, "smime-type", "enveloped-data");
888 t->encoding = ENCBASE64; /* The output of OpenSSL SHOULD be binary */
890 t->disposition = DISPATTACH;
891 t->d_filename = m_strdup("smime.p7m");
892 t->filename = outfile;
893 t->unlink = 1; /*delete after sending the message */
902 * Implementation of `verify_one'.
905 /* Display the common attributes of the signature summary SUM.
906 Return 1 if there is is a severe warning.
908 static int show_sig_summary (unsigned long sum,
909 gpgme_ctx_t ctx, gpgme_key_t key, int idx,
914 if ((sum & GPGME_SIGSUM_KEY_REVOKED)) {
915 state_attach_puts (_("Warning: One of the keys has been revoked\n"), s);
919 if ((sum & GPGME_SIGSUM_KEY_EXPIRED)) {
920 time_t at = key->subkeys->expires ? key->subkeys->expires : 0;
923 state_attach_puts (_("Warning: The key used to create the "
924 "signature expired at: "), s);
926 state_attach_puts ("\n", s);
929 state_attach_puts (_("Warning: At least one certification key "
930 "has expired\n"), s);
933 if ((sum & GPGME_SIGSUM_SIG_EXPIRED)) {
934 gpgme_verify_result_t result;
935 gpgme_signature_t sig;
938 result = gpgme_op_verify_result (ctx);
940 for (sig = result->signatures, i = 0; sig && (i < idx);
941 sig = sig->next, i++);
943 state_attach_puts (_("Warning: The signature expired at: "), s);
944 print_time (sig ? sig->exp_timestamp : 0, s);
945 state_attach_puts ("\n", s);
948 if ((sum & GPGME_SIGSUM_KEY_MISSING))
949 state_attach_puts (_("Can't verify due to a missing "
950 "key or certificate\n"), s);
952 if ((sum & GPGME_SIGSUM_CRL_MISSING)) {
953 state_attach_puts (_("The CRL is not available\n"), s);
957 if ((sum & GPGME_SIGSUM_CRL_TOO_OLD)) {
958 state_attach_puts (_("Available CRL is too old\n"), s);
962 if ((sum & GPGME_SIGSUM_BAD_POLICY))
963 state_attach_puts (_("A policy requirement was not met\n"), s);
965 if ((sum & GPGME_SIGSUM_SYS_ERROR)) {
966 const char *t0 = NULL, *t1 = NULL;
967 gpgme_verify_result_t result;
968 gpgme_signature_t sig;
971 state_attach_puts (_("A system error occurred"), s);
973 /* Try to figure out some more detailed system error information. */
974 result = gpgme_op_verify_result (ctx);
975 for (sig = result->signatures, i = 0; sig && (i < idx);
976 sig = sig->next, i++);
979 t1 = sig->wrong_key_usage ? "Wrong_Key_Usage" : "";
983 state_attach_puts (": ", s);
985 state_attach_puts (t0, s);
986 if (t1 && !(t0 && !m_strcmp(t0, t1))) {
988 state_attach_puts (",", s);
989 state_attach_puts (t1, s);
992 state_attach_puts ("\n", s);
999 static void show_fingerprint (gpgme_key_t key, STATE * state)
1004 const char *prefix = _("Fingerprint: ");
1009 s = key->subkeys ? key->subkeys->fpr : NULL;
1012 is_pgp = (key->protocol == GPGME_PROTOCOL_OpenPGP);
1014 bufsize = m_strlen(prefix) + m_strlen(s) * 4 + 2;
1015 buf = xmalloc(bufsize);
1016 m_strcpy(buf, bufsize, prefix);
1017 p = buf + m_strlen(buf);
1018 if (is_pgp && m_strlen(s) == 40) { /* PGP v4 style formatted. */
1019 for (i = 0; *s && s[1] && s[2] && s[3] && s[4]; s += 4, i++) {
1030 for (i = 0; *s && s[1] && s[2]; s += 2, i++) {
1033 *p++ = is_pgp ? ' ' : ':';
1034 if (is_pgp && i == 7)
1039 /* just in case print remaining odd digits */
1044 state_attach_puts (buf, state);
1048 /* Show the valididy of a key used for one signature. */
1049 static void show_one_sig_validity (gpgme_ctx_t ctx, int idx, STATE * s)
1051 gpgme_verify_result_t result = NULL;
1052 gpgme_signature_t sig = NULL;
1053 const char *txt = NULL;
1055 result = gpgme_op_verify_result (ctx);
1057 for (sig = result->signatures; sig && (idx > 0); sig = sig->next, idx--);
1059 switch (sig ? sig->validity : 0) {
1060 case GPGME_VALIDITY_UNKNOWN:
1061 txt = _("WARNING: We have NO indication whether "
1062 "the key belongs to the person named " "as shown above\n");
1064 case GPGME_VALIDITY_UNDEFINED:
1066 case GPGME_VALIDITY_NEVER:
1067 txt = _("WARNING: The key does NOT BELONG to "
1068 "the person named as shown above\n");
1070 case GPGME_VALIDITY_MARGINAL:
1071 txt = _("WARNING: It is NOT certain that the key "
1072 "belongs to the person named as shown above\n");
1074 case GPGME_VALIDITY_FULL:
1075 case GPGME_VALIDITY_ULTIMATE:
1080 state_attach_puts (txt, s);
1083 /* Show information about one signature. This fucntion is called with
1084 the context CTX of a sucessful verification operation and the
1085 enumerator IDX which should start at 0 and incremete for each
1088 Return values are: 0 for normal procession, 1 for a bad signature,
1089 2 for a signature with a warning or -1 for no more signature. */
1090 static int show_one_sig_status (gpgme_ctx_t ctx, int idx, STATE * s)
1093 const char *fpr, *uid;
1094 gpgme_key_t key = NULL;
1095 int i, anybad = 0, anywarn = 0;
1097 gpgme_user_id_t uids = NULL;
1098 gpgme_verify_result_t result;
1099 gpgme_signature_t sig;
1100 gpgme_error_t err = GPG_ERR_NO_ERROR;
1102 result = gpgme_op_verify_result (ctx);
1104 /* FIXME: this code should use a static variable and remember
1105 the current position in the list of signatures, IMHO.
1108 for (i = 0, sig = result->signatures; sig && (i < idx);
1109 i++, sig = sig->next);
1111 return -1; /* Signature not found. */
1113 if (signature_key) {
1114 gpgme_key_release (signature_key);
1115 signature_key = NULL;
1118 created = sig->timestamp;
1122 if (gpg_err_code (sig->status) != GPG_ERR_NO_ERROR)
1125 err = gpgme_get_key (ctx, fpr, &key, 0); /* secret key? */
1127 uid = (key->uids && key->uids->uid) ? key->uids->uid : "[?]";
1129 signature_key = key;
1132 key = NULL; /* Old gpgme versions did not set KEY to NULL on
1133 error. Do it here to avoid a double free. */
1137 if (!s || !s->fpout || !(s->flags & M_DISPLAY)); /* No state information so no way to print anything. */
1139 state_attach_puts (_("Error getting key information: "), s);
1140 state_attach_puts (gpg_strerror (err), s);
1141 state_attach_puts ("\n", s);
1144 else if ((sum & GPGME_SIGSUM_GREEN)) {
1145 state_attach_puts (_("Good signature from: "), s);
1146 state_attach_puts (uid, s);
1147 state_attach_puts ("\n", s);
1148 for (i = 1, uids = key->uids; uids; i++, uids = uids->next) {
1150 /* Skip primary UID. */
1154 state_attach_puts (_(" aka: "), s);
1155 state_attach_puts (uids->uid, s);
1156 state_attach_puts ("\n", s);
1158 state_attach_puts (_(" created: "), s);
1159 print_time (created, s);
1160 state_attach_puts ("\n", s);
1161 if (show_sig_summary (sum, ctx, key, idx, s))
1163 show_one_sig_validity (ctx, idx, s);
1165 else if ((sum & GPGME_SIGSUM_RED)) {
1166 state_attach_puts (_("*BAD* signature claimed to be from: "), s);
1167 state_attach_puts (uid, s);
1168 state_attach_puts ("\n", s);
1169 show_sig_summary (sum, ctx, key, idx, s);
1171 else if (!anybad && key && (key->protocol == GPGME_PROTOCOL_OpenPGP)) { /* We can't decide (yellow) but this is a PGP key with a good
1172 signature, so we display what a PGP user expects: The name,
1173 fingerprint and the key validity (which is neither fully or
1175 state_attach_puts (_("Good signature from: "), s);
1176 state_attach_puts (uid, s);
1177 state_attach_puts ("\n", s);
1178 state_attach_puts (_(" created: "), s);
1179 print_time (created, s);
1180 state_attach_puts ("\n", s);
1181 show_one_sig_validity (ctx, idx, s);
1182 show_fingerprint (key, s);
1183 if (show_sig_summary (sum, ctx, key, idx, s))
1186 else { /* can't decide (yellow) */
1188 state_attach_puts (_("Error checking signature"), s);
1189 state_attach_puts ("\n", s);
1190 show_sig_summary (sum, ctx, key, idx, s);
1193 if (key != signature_key)
1194 gpgme_key_release (key);
1197 return anybad ? 1 : anywarn ? 2 : 0;
1200 /* Do the actual verification step. With IS_SMIME set to true we
1201 assume S/MIME (surprise!) */
1202 static int verify_one (BODY * sigbdy, STATE * s,
1203 const char *tempfile, int is_smime)
1209 gpgme_data_t signature, message;
1211 signature = file_to_data_object (s->fpin, sigbdy->offset, sigbdy->length);
1215 /* We need to tell gpgme about the encoding because the backend can't
1216 auto-detect plain base-64 encoding which is used by S/MIME. */
1218 gpgme_data_set_encoding (signature, GPGME_DATA_ENCODING_BASE64);
1220 err = gpgme_data_new_from_file (&message, tempfile, 1);
1222 gpgme_data_release (signature);
1223 mutt_error (_("error allocating data object: %s\n"), gpgme_strerror (err));
1226 ctx = create_gpgme_context (is_smime);
1228 /* Note: We don't need a current time output because GPGME avoids
1229 such an attack by separating the meta information from the
1231 state_attach_puts (_("[-- Begin signature information --]\n"), s);
1233 err = gpgme_op_verify (ctx, signature, message, NULL);
1234 mutt_need_hard_redraw ();
1238 snprintf (buf, sizeof (buf) - 1,
1239 _("Error: verification failed: %s\n"), gpgme_strerror (err));
1240 state_attach_puts (buf, s);
1242 else { /* Verification succeeded, see what the result is. */
1246 if (signature_key) {
1247 gpgme_key_release (signature_key);
1248 signature_key = NULL;
1251 for (idx = 0; (res = show_one_sig_status (ctx, idx, s)) != -1; idx++) {
1262 gpgme_verify_result_t result;
1263 gpgme_sig_notation_t notation;
1264 gpgme_signature_t sig;
1266 result = gpgme_op_verify_result (ctx);
1268 for (sig = result->signatures; sig; sig = sig->next) {
1269 if (sig->notations) {
1270 state_attach_puts ("*** Begin Notation (signature by: ", s);
1271 state_attach_puts (sig->fpr, s);
1272 state_attach_puts (") ***\n", s);
1273 for (notation = sig->notations; notation; notation = notation->next)
1275 if (notation->name) {
1276 state_attach_puts (notation->name, s);
1277 state_attach_puts ("=", s);
1279 if (notation->value) {
1280 state_attach_puts (notation->value, s);
1281 if (!(*notation->value
1282 && (notation->value[m_strlen(notation->value) - 1] ==
1284 state_attach_puts ("\n", s);
1287 state_attach_puts ("*** End Notation ***\n", s);
1293 gpgme_release (ctx);
1295 state_attach_puts (_("[-- End signature information --]\n\n"), s);
1297 return badsig ? 1 : anywarn ? 2 : 0;
1300 int pgp_gpgme_verify_one (BODY * sigbdy, STATE * s, const char *tempfile)
1302 return verify_one (sigbdy, s, tempfile, 0);
1305 int smime_gpgme_verify_one (BODY * sigbdy, STATE * s, const char *tempfile)
1307 return verify_one (sigbdy, s, tempfile, 1);
1311 * Implementation of `decrypt_part'.
1314 /* Decrypt a PGP or SMIME message (depending on the boolean flag
1315 IS_SMIME) with body A described further by state S. Write
1316 plaintext out to file FPOUT and return a new body. For PGP returns
1317 a flag in R_IS_SIGNED to indicate whether this is a combined
1318 encrypted and signed message, for S/MIME it returns true when it is
1319 not a encrypted but a signed message. */
1320 static BODY *decrypt_part (BODY * a, STATE * s, FILE * fpout, int is_smime,
1327 gpgme_data_t ciphertext, plaintext;
1328 int maybe_signed = 0;
1335 ctx = create_gpgme_context (is_smime);
1338 /* Make a data object from the body, create context etc. */
1339 ciphertext = file_to_data_object (s->fpin, a->offset, a->length);
1342 plaintext = create_gpgme_data ();
1344 /* Do the decryption or the verification in case of the S/MIME hack. */
1345 if ((!is_smime) || maybe_signed) {
1347 err = gpgme_op_decrypt_verify (ctx, ciphertext, plaintext);
1348 else if (maybe_signed)
1349 err = gpgme_op_verify (ctx, ciphertext, NULL, plaintext);
1352 /* Check wether signatures have been verified. */
1353 gpgme_verify_result_t verify_result = gpgme_op_verify_result (ctx);
1355 if (verify_result->signatures)
1360 err = gpgme_op_decrypt (ctx, ciphertext, plaintext);
1361 gpgme_data_release (ciphertext);
1363 if (is_smime && !maybe_signed && gpg_err_code (err) == GPG_ERR_NO_DATA) {
1364 /* Check whether this might be a signed message despite what
1365 the mime header told us. Retry then. gpgsm returns the
1366 error information "unsupported Algorithm '?'" but gpgme
1367 will not store this unknown algorithm, thus we test that
1368 it has not been set. */
1369 gpgme_decrypt_result_t result;
1371 result = gpgme_op_decrypt_result (ctx);
1372 if (!result->unsupported_algorithm) {
1374 gpgme_data_release (plaintext);
1378 mutt_need_hard_redraw ();
1379 if ((s->flags & M_DISPLAY)) {
1382 snprintf (buf, sizeof (buf) - 1,
1383 _("[-- Error: decryption failed: %s --]\n\n"),
1384 gpgme_strerror (err));
1385 state_attach_puts (buf, s);
1387 gpgme_data_release (plaintext);
1388 gpgme_release (ctx);
1391 mutt_need_hard_redraw ();
1393 /* Read the output from GPGME, and make sure to change CRLF to LF,
1394 otherwise read_mime_header has a hard time parsing the message. */
1395 if (data_object_to_stream (plaintext, fpout)) {
1396 gpgme_data_release (plaintext);
1397 gpgme_release (ctx);
1400 gpgme_data_release (plaintext);
1402 a->is_signed_data = 0;
1408 a->is_signed_data = 1;
1410 *r_is_signed = -1; /* A signature exists. */
1412 if ((s->flags & M_DISPLAY))
1413 state_attach_puts (_("[-- Begin signature " "information --]\n"), s);
1414 for (idx = 0; (res = show_one_sig_status (ctx, idx, s)) != -1; idx++) {
1420 if (!anybad && idx && r_is_signed && *r_is_signed)
1421 *r_is_signed = anywarn ? 2 : 1; /* Good signature. */
1423 if ((s->flags & M_DISPLAY))
1424 state_attach_puts (_("[-- End signature " "information --]\n\n"), s);
1426 gpgme_release (ctx);
1431 tattach = mutt_read_mime_header (fpout, 0);
1434 * Need to set the length of this body part.
1436 fstat (fileno (fpout), &info);
1437 tattach->length = info.st_size - tattach->offset;
1439 tattach->warnsig = anywarn;
1441 /* See if we need to recurse on this MIME part. */
1442 mutt_parse_part (fpout, tattach);
1448 /* Decrypt a PGP/MIME message in FPIN and B and return a new body and
1449 the stream in CUR and FPOUT. Returns 0 on success. */
1450 int pgp_gpgme_decrypt_mime (FILE * fpin, FILE ** fpout, BODY * b, BODY ** cur)
1452 char tempfile[_POSIX_PATH_MAX];
1454 BODY *first_part = b;
1457 first_part->goodsig = 0;
1458 first_part->warnsig = 0;
1460 if (!mutt_is_multipart_encrypted (b))
1463 if (!b->parts || !b->parts->next)
1470 *fpout = m_tempfile(tempfile, sizeof(tempfile), NONULL(Tempdir), NULL);
1472 mutt_perror (_("Can't create temporary file"));
1477 *cur = decrypt_part (b, &s, *fpout, 0, &is_signed);
1480 first_part->goodsig = 1;
1482 return *cur ? 0 : -1;
1486 /* Decrypt a S/MIME message in FPIN and B and return a new body and
1487 the stream in CUR and FPOUT. Returns 0 on success. */
1488 int smime_gpgme_decrypt_mime (FILE * fpin, FILE ** fpout, BODY * b,
1491 char tempfile[_POSIX_PATH_MAX];
1495 long saved_b_offset;
1496 ssize_t saved_b_length;
1499 if (!mutt_is_application_smime (b))
1505 /* Decode the body - we need to pass binary CMS to the
1506 backend. The backend allows for Base64 encoded data but it does
1507 not allow for QP which I have seen in some messages. So better
1509 saved_b_type = b->type;
1510 saved_b_offset = b->offset;
1511 saved_b_length = b->length;
1514 fseeko (s.fpin, b->offset, 0);
1515 tmpfp = m_tempfile (tempfile, sizeof(tempfile), NONULL(Tempdir), NULL);
1517 mutt_perror (_("Can't create temporary file"));
1520 mutt_unlink (tempfile);
1523 mutt_decode_attachment (b, &s);
1525 b->length = ftello (s.fpout);
1532 *fpout = m_tempfile(tempfile, sizeof(tempfile), NONULL(Tempdir), NULL);
1534 mutt_perror (_("Can't create temporary file"));
1537 mutt_unlink (tempfile);
1539 *cur = decrypt_part (b, &s, *fpout, 1, &is_signed);
1541 (*cur)->goodsig = is_signed > 0;
1542 b->type = saved_b_type;
1543 b->length = saved_b_length;
1544 b->offset = saved_b_offset;
1547 if (*cur && !is_signed && !(*cur)->parts
1548 && mutt_is_application_smime (*cur)) {
1549 /* Assume that this is a opaque signed s/mime message. This is
1550 an ugly way of doing it but we have anyway a problem with
1551 arbitrary encoded S/MIME messages: Only the outer part may be
1552 encrypted. The entire mime parsing should be revamped,
1553 probably by keeping the temportary files so that we don't
1554 need to decrypt them all the time. Inner parts of an
1555 encrypted part can then pint into this file and tehre won't
1556 never be a need to decrypt again. This needs a partial
1557 rewrite of the MIME engine. */
1561 saved_b_type = bb->type;
1562 saved_b_offset = bb->offset;
1563 saved_b_length = bb->length;
1566 fseeko (s.fpin, bb->offset, 0);
1567 tmpfp = m_tempfile (tempfile, sizeof(tempfile), NONULL(Tempdir), NULL);
1569 mutt_perror (_("Can't create temporary file"));
1572 mutt_unlink (tempfile);
1575 mutt_decode_attachment (bb, &s);
1577 bb->length = ftello (s.fpout);
1585 *fpout = m_tempfile(tempfile, sizeof(tempfile), NONULL(Tempdir), NULL);
1587 mutt_perror (_("Can't create temporary file"));
1590 mutt_unlink (tempfile);
1592 tmp_b = decrypt_part (bb, &s, *fpout, 1, &is_signed);
1594 tmp_b->goodsig = is_signed > 0;
1595 bb->type = saved_b_type;
1596 bb->length = saved_b_length;
1597 bb->offset = saved_b_offset;
1600 body_list_wipe(cur);
1603 return *cur ? 0 : -1;
1608 * Implementation of `pgp_check_traditional'.
1611 static int pgp_check_traditional_one_body (FILE * fp, BODY * b,
1614 char tempfile[_POSIX_PATH_MAX];
1615 char buf[HUGE_STRING];
1621 if (b->type != TYPETEXT)
1624 if (tagged_only && !b->tagged)
1627 mutt_mktemp (tempfile);
1628 if (mutt_decode_save_attachment (fp, b, tempfile, 0, 0) != 0) {
1633 if ((tfp = fopen (tempfile, "r")) == NULL) {
1638 while (fgets (buf, sizeof (buf), tfp)) {
1639 if (!m_strncmp("-----BEGIN PGP ", buf, 15)) {
1640 if (!m_strcmp("MESSAGE-----\n", buf + 15))
1642 else if (!m_strcmp("SIGNED MESSAGE-----\n", buf + 15))
1652 /* fix the content type */
1654 parameter_setval(&b->parameter, "format", "fixed");
1655 parameter_setval(&b->parameter, "x-action",
1656 enc ? "pgp-encrypted" : "pgp-signed");
1660 int pgp_gpgme_check_traditional (FILE * fp, BODY * b, int tagged_only)
1665 for (; b; b = b->next) {
1666 if (is_multipart (b))
1667 rv = (pgp_gpgme_check_traditional (fp, b->parts, tagged_only) || rv);
1668 else if (b->type == TYPETEXT) {
1669 if ((r = mutt_is_application_pgp (b)))
1672 rv = (pgp_check_traditional_one_body (fp, b, tagged_only) || rv);
1680 * Implementation of `application_handler'.
1684 Copy a clearsigned message, and strip the signature and PGP's
1687 XXX - charset handling: We assume that it is safe to do
1688 character set decoding first, dash decoding second here, while
1689 we do it the other way around in the main handler.
1691 (Note that we aren't worse than Outlook & Cie in this, and also
1692 note that we can successfully handle anything produced by any
1693 existing versions of mutt.) */
1695 static void copy_clearsigned (gpgme_data_t data, STATE * s, char *charset)
1697 char buf[HUGE_STRING];
1698 short complete, armor_header;
1703 fname = data_object_to_tempfile (data, &fp);
1709 fc = fgetconv_open (fp, charset, Charset, M_ICONV_HOOK_FROM);
1711 for (complete = 1, armor_header = 1;
1712 fgetconvs (buf, sizeof (buf), fc) != NULL;
1713 complete = strchr (buf, '\n') != NULL) {
1716 state_puts (buf, s);
1720 if (!m_strcmp(buf, "-----BEGIN PGP SIGNATURE-----\n"))
1730 state_puts (s->prefix, s);
1732 if (buf[0] == '-' && buf[1] == ' ')
1733 state_puts (buf + 2, s);
1735 state_puts (buf, s);
1738 fgetconv_close (&fc);
1743 /* Support for classic_application/pgp */
1744 int pgp_gpgme_application_handler (BODY * m, STATE * s)
1746 int needpass = -1, pgp_keyblock = 0;
1750 off_t last_pos, offset;
1751 char buf[HUGE_STRING];
1752 FILE *pgpout = NULL;
1754 gpgme_error_t err = 0;
1755 gpgme_data_t armored_data = NULL;
1757 short maybe_goodsig = 1;
1758 short have_any_sigs = 0;
1760 char body_charset[STRING]; /* Only used for clearsigned messages. */
1762 /* For clearsigned messages we won't be able to get a character set
1763 but we know that this may only be text thus we assume Latin-1
1765 if (!mutt_get_body_charset (body_charset, sizeof (body_charset), m))
1766 m_strcpy(body_charset, sizeof(body_charset), "iso-8859-1");
1768 fseeko (s->fpin, m->offset, 0);
1769 last_pos = m->offset;
1771 for (bytes = m->length; bytes > 0;) {
1772 if (fgets (buf, sizeof (buf), s->fpin) == NULL)
1775 offset = ftello (s->fpin);
1776 bytes -= (offset - last_pos); /* don't rely on m_strlen(buf) */
1779 if (!m_strncmp("-----BEGIN PGP ", buf, 15)) {
1781 start_pos = last_pos;
1783 if (!m_strcmp("MESSAGE-----\n", buf + 15))
1785 else if (!m_strcmp("SIGNED MESSAGE-----\n", buf + 15)) {
1789 else if (!option (OPTDONTHANDLEPGPKEYS) &&
1790 !m_strcmp("PUBLIC KEY BLOCK-----\n", buf + 15)) {
1795 /* XXX - we may wish to recode here */
1797 state_puts (s->prefix, s);
1798 state_puts (buf, s);
1802 have_any_sigs = (have_any_sigs || (clearsign && (s->flags & M_VERIFY)));
1804 /* Copy PGP material to an data container */
1805 armored_data = create_gpgme_data ();
1806 gpgme_data_write (armored_data, buf, m_strlen(buf));
1807 while (bytes > 0 && fgets (buf, sizeof (buf) - 1, s->fpin) != NULL) {
1808 offset = ftello (s->fpin);
1809 bytes -= (offset - last_pos); /* don't rely on m_strlen(buf) */
1812 gpgme_data_write (armored_data, buf, m_strlen(buf));
1814 if ((needpass && !m_strcmp("-----END PGP MESSAGE-----\n", buf))
1816 && (!m_strcmp("-----END PGP SIGNATURE-----\n", buf)
1817 || !m_strcmp("-----END PGP PUBLIC KEY BLOCK-----\n",
1822 /* Invoke PGP if needed */
1823 if (!clearsign || (s->flags & M_VERIFY)) {
1824 unsigned int sig_stat = 0;
1825 gpgme_data_t plaintext;
1828 plaintext = create_gpgme_data ();
1829 ctx = create_gpgme_context (0);
1832 err = gpgme_op_verify (ctx, armored_data, NULL, plaintext);
1834 err = gpgme_op_decrypt_verify (ctx, armored_data, plaintext);
1835 if (gpg_err_code (err) == GPG_ERR_NO_DATA) {
1836 /* Decrypt verify can't handle signed only messages. */
1837 err = (gpgme_data_seek (armored_data, 0, SEEK_SET) == -1)
1838 ? gpgme_error_from_errno (errno) : 0;
1839 /* Must release plaintext so that we supply an
1840 uninitialized object. */
1841 gpgme_data_release (plaintext);
1842 plaintext = create_gpgme_data ();
1843 err = gpgme_op_verify (ctx, armored_data, NULL, plaintext);
1850 snprintf (errbuf, sizeof (errbuf) - 1,
1851 _("Error: decryption/verification failed: %s\n"),
1852 gpgme_strerror (err));
1853 state_attach_puts (errbuf, s);
1855 else { /* Decryption/Verification succeeded */
1859 /* Check wether signatures have been verified. */
1860 gpgme_verify_result_t verify_result;
1862 verify_result = gpgme_op_verify_result (ctx);
1863 if (verify_result->signatures)
1869 if ((s->flags & M_DISPLAY) && sig_stat) {
1874 state_attach_puts (_("[-- Begin signature "
1875 "information --]\n"), s);
1878 (res = show_one_sig_status (ctx, idx, s)) != -1; idx++) {
1887 state_attach_puts (_("[-- End signature "
1888 "information --]\n\n"), s);
1891 tmpfname = data_object_to_tempfile (plaintext, &pgpout);
1894 state_attach_puts (_("Error: copy data failed\n"), s);
1898 p_delete(&tmpfname);
1901 gpgme_release (ctx);
1905 * Now, copy cleartext to the screen. NOTE - we expect that PGP
1906 * outputs utf-8 cleartext. This may not always be true, but it
1907 * seems to be a reasonable guess.
1910 if (s->flags & M_DISPLAY) {
1912 state_attach_puts (_("[-- BEGIN PGP MESSAGE --]\n\n"), s);
1913 else if (pgp_keyblock)
1914 state_attach_puts (_("[-- BEGIN PGP PUBLIC KEY BLOCK --]\n"), s);
1916 state_attach_puts (_("[-- BEGIN PGP SIGNED MESSAGE --]\n\n"), s);
1920 copy_clearsigned (armored_data, s, body_charset);
1927 fc = fgetconv_open (pgpout, "utf-8", Charset, 0);
1928 while ((c = fgetconv (fc)) != EOF) {
1930 if (c == '\n' && s->prefix)
1931 state_puts (s->prefix, s);
1933 fgetconv_close (&fc);
1936 if (s->flags & M_DISPLAY) {
1937 state_putc ('\n', s);
1939 state_attach_puts (_("[-- END PGP MESSAGE --]\n"), s);
1940 else if (pgp_keyblock)
1941 state_attach_puts (_("[-- END PGP PUBLIC KEY BLOCK --]\n"), s);
1943 state_attach_puts (_("[-- END PGP SIGNED MESSAGE --]\n"), s);
1951 /* XXX - we may wish to recode here */
1953 state_puts (s->prefix, s);
1954 state_puts (buf, s);
1958 m->goodsig = (maybe_goodsig && have_any_sigs);
1960 if (needpass == -1) {
1961 state_attach_puts (_("[-- Error: could not find beginning"
1962 " of PGP message! --]\n\n"), s);
1969 * Implementation of `encrypted_handler'.
1972 /* MIME handler for pgp/mime encrypted messages. */
1973 int pgp_gpgme_encrypted_handler (BODY * a, STATE * s)
1975 char tempfile[_POSIX_PATH_MAX];
1978 BODY *orig_body = a;
1983 if (!a || a->type != TYPEAPPLICATION || !a->subtype
1984 || ascii_strcasecmp ("pgp-encrypted", a->subtype)
1985 || !a->next || a->next->type != TYPEAPPLICATION || !a->next->subtype
1986 || ascii_strcasecmp ("octet-stream", a->next->subtype)) {
1987 if (s->flags & M_DISPLAY)
1988 state_attach_puts (_("[-- Error: malformed PGP/MIME message! --]\n\n"),
1993 /* Move forward to the application/pgp-encrypted body. */
1996 fpout = m_tempfile(tempfile, sizeof(tempfile), NONULL(Tempdir), NULL);
1998 if (s->flags & M_DISPLAY)
1999 state_attach_puts (_("[-- Error: could not create temporary file! "
2004 tattach = decrypt_part (a, s, fpout, 0, &is_signed);
2006 tattach->goodsig = is_signed > 0;
2008 if (s->flags & M_DISPLAY)
2009 state_attach_puts (is_signed ?
2011 ("[-- The following data is PGP/MIME signed and encrypted --]\n\n") :
2012 _("[-- The following data is PGP/MIME encrypted --]\n\n"), s);
2015 FILE *savefp = s->fpin;
2018 rc = mutt_body_handler (tattach, s);
2023 * if a multipart/signed is the _only_ sub-part of a
2024 * multipart/encrypted, cache signature verification
2027 if (mutt_is_multipart_signed (tattach) && !tattach->next)
2028 orig_body->goodsig |= tattach->goodsig;
2030 if (s->flags & M_DISPLAY) {
2031 state_puts ("\n", s);
2032 state_attach_puts (is_signed ?
2034 ("[-- End of PGP/MIME signed and encrypted data --]\n")
2035 : _("[-- End of PGP/MIME encrypted data --]\n"), s);
2038 body_list_wipe(&tattach);
2042 mutt_unlink (tempfile);
2046 /* Support for application/smime */
2047 int smime_gpgme_application_handler (BODY * a, STATE * s)
2049 char tempfile[_POSIX_PATH_MAX];
2056 fpout = m_tempfile(tempfile, sizeof(tempfile), NONULL(Tempdir), NULL);
2058 if (s->flags & M_DISPLAY)
2059 state_attach_puts (_("[-- Error: could not create temporary file! "
2064 tattach = decrypt_part (a, s, fpout, 1, &is_signed);
2066 tattach->goodsig = is_signed > 0;
2068 if (s->flags & M_DISPLAY)
2069 state_attach_puts (is_signed ?
2070 _("[-- The following data is S/MIME signed --]\n\n") :
2071 _("[-- The following data is S/MIME encrypted --]\n\n"), s);
2074 FILE *savefp = s->fpin;
2077 rc = mutt_body_handler (tattach, s);
2082 * if a multipart/signed is the _only_ sub-part of a
2083 * multipart/encrypted, cache signature verification
2086 if (mutt_is_multipart_signed (tattach) && !tattach->next) {
2087 if (!(a->goodsig = tattach->goodsig))
2088 a->warnsig = tattach->warnsig;
2090 else if (tattach->goodsig) {
2092 a->warnsig = tattach->warnsig;
2095 if (s->flags & M_DISPLAY) {
2096 state_puts ("\n", s);
2097 state_attach_puts (is_signed ?
2098 _("[-- End of S/MIME signed data --]\n") :
2099 _("[-- End of S/MIME encrypted data --]\n"), s);
2102 body_list_wipe(&tattach);
2106 mutt_unlink (tempfile);
2112 * Format an entry on the CRYPT key selection menu.
2115 * %k key id %K key id of the principal key
2117 * %a algorithm %A algorithm of the princ. key
2118 * %l length %L length of the princ. key
2119 * %f flags %F flags of the princ. key
2120 * %c capabilities %C capabilities of the princ. key
2121 * %t trust/validity of the key-uid association
2123 * %[...] date of key using strftime(3)
2127 crypt_entry_fmt (char *dest, ssize_t destlen, char op,
2128 const char *src, const char *prefix,
2129 const char *ifstring, const char *elsestring,
2130 unsigned long data, format_flag flags)
2133 crypt_entry_t *entry;
2136 int optional = (flags & M_FORMAT_OPTIONAL);
2137 const char *s = NULL;
2140 entry = (crypt_entry_t *) data;
2143 /* if (isupper ((unsigned char) op)) */
2146 kflags = (key->flags /*| (pkey->flags & KEYFLAG_RESTRICTIONS)
2149 switch (ascii_tolower (op)) {
2153 char buf2[SHORT_STRING], *p;
2169 while (len > 0 && *cp != ']') {
2178 break; /* not enough space */
2188 if (do_locales && Locale)
2189 setlocale (LC_TIME, Locale);
2194 if (key->kobj->subkeys && (key->kobj->subkeys->timestamp > 0))
2195 tt = key->kobj->subkeys->timestamp;
2197 tm = localtime (&tt);
2199 strftime (buf2, sizeof (buf2), dest, tm);
2202 setlocale (LC_TIME, "C");
2204 snprintf (fmt, sizeof (fmt), "%%%ss", prefix);
2205 snprintf (dest, destlen, fmt, buf2);
2212 snprintf (fmt, sizeof (fmt), "%%%sd", prefix);
2213 snprintf (dest, destlen, fmt, entry->num);
2218 /* fixme: we need a way to distinguish between main and subkeys.
2219 Store the idx in entry? */
2220 snprintf (fmt, sizeof (fmt), "%%%ss", prefix);
2221 snprintf (dest, destlen, fmt, crypt_keyid (key));
2226 snprintf (fmt, sizeof (fmt), "%%%ss", prefix);
2227 snprintf (dest, destlen, fmt, key->uid);
2232 snprintf (fmt, sizeof (fmt), "%%%s.3s", prefix);
2233 if (key->kobj->subkeys)
2234 s = gpgme_pubkey_algo_name (key->kobj->subkeys->pubkey_algo);
2237 snprintf (dest, destlen, fmt, s);
2242 snprintf (fmt, sizeof (fmt), "%%%slu", prefix);
2243 if (key->kobj->subkeys)
2244 val = key->kobj->subkeys->length;
2247 snprintf (dest, destlen, fmt, val);
2252 snprintf (fmt, sizeof (fmt), "%%%sc", prefix);
2253 snprintf (dest, destlen, fmt, crypt_flags (kflags));
2255 else if (!(kflags & (KEYFLAG_RESTRICTIONS)))
2260 snprintf (fmt, sizeof (fmt), "%%%ss", prefix);
2261 snprintf (dest, destlen, fmt, crypt_key_abilities (kflags));
2263 else if (!(kflags & (KEYFLAG_ABILITIES)))
2267 if ((kflags & KEYFLAG_ISX509))
2270 gpgme_user_id_t uid = NULL;
2273 for (i = 0, uid = key->kobj->uids; uid && (i < key->idx);
2274 i++, uid = uid->next);
2276 switch (uid->validity) {
2277 case GPGME_VALIDITY_UNDEFINED:
2280 case GPGME_VALIDITY_NEVER:
2283 case GPGME_VALIDITY_MARGINAL:
2286 case GPGME_VALIDITY_FULL:
2289 case GPGME_VALIDITY_ULTIMATE:
2292 case GPGME_VALIDITY_UNKNOWN:
2298 snprintf (fmt, sizeof (fmt), "%%%sc", prefix);
2299 snprintf (dest, destlen, fmt, s ? *s : 'B');
2302 snprintf (fmt, sizeof (fmt), "%%%ss", prefix);
2303 snprintf (dest, destlen, fmt,
2304 gpgme_get_protocol_name (key->kobj->protocol));
2312 mutt_FormatString (dest, destlen, ifstring, mutt_attach_fmt, data, 0);
2313 else if (flags & M_FORMAT_OPTIONAL)
2314 mutt_FormatString (dest, destlen, elsestring, mutt_attach_fmt, data, 0);
2318 /* Used by the display fucntion to format a line. */
2319 static void crypt_entry (char *s, ssize_t l, MUTTMENU * menu, int num)
2321 crypt_key_t **key_table = (crypt_key_t **) menu->data;
2322 crypt_entry_t entry;
2324 entry.key = key_table[num];
2325 entry.num = num + 1;
2327 mutt_FormatString (s, l, NONULL (PgpEntryFormat), crypt_entry_fmt,
2328 (unsigned long) &entry, M_FORMAT_ARROWCURSOR);
2331 /* Compare two addresses and the keyid to be used for sorting. */
2332 static int _crypt_compare_address (const void *a, const void *b)
2334 crypt_key_t **s = (crypt_key_t **) a;
2335 crypt_key_t **t = (crypt_key_t **) b;
2338 if ((r = m_strcasecmp((*s)->uid, (*t)->uid)))
2341 return m_strcasecmp(crypt_keyid (*s), crypt_keyid (*t)) > 0;
2344 static int crypt_compare_address (const void *a, const void *b)
2346 return ((PgpSortKeys & SORT_REVERSE) ? !_crypt_compare_address (a, b)
2347 : _crypt_compare_address (a, b));
2351 /* Compare two key IDs and the addresses to be used for sorting. */
2352 static int _crypt_compare_keyid (const void *a, const void *b)
2354 crypt_key_t **s = (crypt_key_t **) a;
2355 crypt_key_t **t = (crypt_key_t **) b;
2358 if ((r = m_strcasecmp(crypt_keyid (*s), crypt_keyid (*t))))
2361 return m_strcasecmp((*s)->uid, (*t)->uid) > 0;
2364 static int crypt_compare_keyid (const void *a, const void *b)
2366 return ((PgpSortKeys & SORT_REVERSE) ? !_crypt_compare_keyid (a, b)
2367 : _crypt_compare_keyid (a, b));
2370 /* Compare 2 creation dates and the addresses. For sorting. */
2371 static int _crypt_compare_date (const void *a, const void *b)
2373 crypt_key_t **s = (crypt_key_t **) a;
2374 crypt_key_t **t = (crypt_key_t **) b;
2375 unsigned long ts = 0, tt = 0;
2377 if ((*s)->kobj->subkeys && ((*s)->kobj->subkeys->timestamp > 0))
2378 ts = (*s)->kobj->subkeys->timestamp;
2379 if ((*t)->kobj->subkeys && ((*t)->kobj->subkeys->timestamp > 0))
2380 tt = (*t)->kobj->subkeys->timestamp;
2387 return m_strcasecmp((*s)->uid, (*t)->uid) > 0;
2390 static int crypt_compare_date (const void *a, const void *b)
2392 return ((PgpSortKeys & SORT_REVERSE) ? !_crypt_compare_date (a, b)
2393 : _crypt_compare_date (a, b));
2396 /* Compare two trust values, the key length, the creation dates. the
2397 addresses and the key IDs. For sorting. */
2398 static int _crypt_compare_trust (const void *a, const void *b)
2400 crypt_key_t **s = (crypt_key_t **) a;
2401 crypt_key_t **t = (crypt_key_t **) b;
2402 unsigned long ts = 0, tt = 0;
2405 if ((r = (((*s)->flags & (KEYFLAG_RESTRICTIONS))
2406 - ((*t)->flags & (KEYFLAG_RESTRICTIONS)))))
2409 if ((*s)->kobj->uids)
2410 ts = (*s)->kobj->uids->validity;
2411 if ((*t)->kobj->uids)
2412 tt = (*t)->kobj->uids->validity;
2413 if ((r = (tt - ts)))
2416 if ((*s)->kobj->subkeys)
2417 ts = (*s)->kobj->subkeys->length;
2418 if ((*t)->kobj->subkeys)
2419 tt = (*t)->kobj->subkeys->length;
2423 if ((*s)->kobj->subkeys && ((*s)->kobj->subkeys->timestamp > 0))
2424 ts = (*s)->kobj->subkeys->timestamp;
2425 if ((*t)->kobj->subkeys && ((*t)->kobj->subkeys->timestamp > 0))
2426 tt = (*t)->kobj->subkeys->timestamp;
2432 if ((r = m_strcasecmp((*s)->uid, (*t)->uid)))
2434 return (m_strcasecmp(crypt_keyid ((*s)), crypt_keyid ((*t)))) > 0;
2437 static int crypt_compare_trust (const void *a, const void *b)
2439 return ((PgpSortKeys & SORT_REVERSE) ? !_crypt_compare_trust (a, b)
2440 : _crypt_compare_trust (a, b));
2443 /* Print the X.500 Distinguished Name part KEY from the array of parts
2445 static int print_dn_part (FILE * fp, struct dn_array_s *dn, const char *key)
2449 for (; dn->key; dn++) {
2450 if (!m_strcmp(dn->key, key)) {
2453 print_utf8 (fp, dn->value, m_strlen(dn->value));
2460 /* Print all parts of a DN in a standard sequence. */
2461 static void print_dn_parts (FILE * fp, struct dn_array_s *dn)
2463 const char *stdpart[] = {
2464 "CN", "OU", "O", "STREET", "L", "ST", "C", NULL
2466 int any = 0, any2 = 0, i;
2468 for (i = 0; stdpart[i]; i++) {
2471 any = print_dn_part (fp, dn, stdpart[i]);
2473 /* now print the rest without any specific ordering */
2474 for (; dn->key; dn++) {
2475 for (i = 0; stdpart[i]; i++) {
2476 if (!m_strcmp(dn->key, stdpart[i]))
2484 any = print_dn_part (fp, dn, dn->key);
2493 /* Parse an RDN; this is a helper to parse_dn(). */
2494 static const unsigned char *parse_dn_part (struct dn_array_s *array,
2495 const unsigned char *string)
2497 const unsigned char *s, *s1;
2501 /* parse attributeType */
2502 for (s = string + 1; *s && *s != '='; s++);
2504 return NULL; /* error */
2507 return NULL; /* empty key */
2508 array->key = p_dupstr(string, n );
2509 p = (unsigned char *) array->key;
2512 if (*string == '#') { /* hexstring */
2514 for (s = string; hexdigitp (s); s++)
2518 return NULL; /* empty or odd number of digits */
2521 array->value = (char *) p;
2522 for (s1 = string; n; s1 += 2, n--)
2526 else { /* regular v3 quoted string */
2527 for (n = 0, s = string; *s; s++) {
2528 if (*s == '\\') { /* pair */
2530 if (*s == ',' || *s == '=' || *s == '+'
2531 || *s == '<' || *s == '>' || *s == '#' || *s == ';'
2532 || *s == '\\' || *s == '\"' || *s == ' ')
2534 else if (hexdigitp (s) && hexdigitp (s + 1)) {
2539 return NULL; /* invalid escape sequence */
2541 else if (*s == '\"')
2542 return NULL; /* invalid encoding */
2543 else if (*s == ',' || *s == '=' || *s == '+'
2544 || *s == '<' || *s == '>' || *s == '#' || *s == ';')
2551 array->value = (char *) p;
2552 for (s = string; n; s++, n--) {
2555 if (hexdigitp (s)) {
2571 /* Parse a DN and return an array-ized one. This is not a validating
2572 parser and it does not support any old-stylish syntax; gpgme is
2573 expected to return only rfc2253 compatible strings. */
2574 static struct dn_array_s *parse_dn (const unsigned char *string)
2576 struct dn_array_s *array;
2577 ssize_t arrayidx, arraysize;
2580 arraysize = 7; /* C,ST,L,O,OU,CN,email */
2581 array = p_new(struct dn_array_s, arraysize + 1);
2584 while (*string == ' ')
2588 if (arrayidx >= arraysize) { /* mutt lacks a real safe_realoc - so we need to copy */
2589 struct dn_array_s *a2;
2592 a2 = p_new(struct dn_array_s, arraysize + 1);
2593 for (i = 0; i < arrayidx; i++) {
2594 a2[i].key = array[i].key;
2595 a2[i].value = array[i].value;
2600 array[arrayidx].key = NULL;
2601 array[arrayidx].value = NULL;
2602 string = parse_dn_part (array + arrayidx, string);
2606 while (*string == ' ')
2608 if (*string && *string != ',' && *string != ';' && *string != '+')
2609 goto failure; /* invalid delimiter */
2613 array[arrayidx].key = NULL;
2614 array[arrayidx].value = NULL;
2618 for (i = 0; i < arrayidx; i++) {
2619 p_delete(&array[i].key);
2620 p_delete(&array[i].value);
2627 /* Print a nice representation of the USERID and make sure it is
2628 displayed in a proper way, which does mean to reorder some parts
2629 for S/MIME's DNs. USERID is a string as returned by the gpgme key
2630 functions. It is utf-8 encoded. */
2631 static void parse_and_print_user_id (FILE * fp, const char *userid)
2636 if (*userid == '<') {
2637 s = strchr (userid + 1, '>');
2639 print_utf8 (fp, userid + 1, s - userid - 1);
2641 else if (*userid == '(')
2642 fputs (_("[Can't display this user ID (unknown encoding)]"), fp);
2643 else if (!digit_or_letter ((const unsigned char *) userid))
2644 fputs (_("[Can't display this user ID (invalid encoding)]"), fp);
2646 struct dn_array_s *dn = parse_dn ((const unsigned char *) userid);
2649 fputs (_("[Can't display this user ID (invalid DN)]"), fp);
2651 print_dn_parts (fp, dn);
2652 for (i = 0; dn[i].key; i++) {
2653 p_delete(&dn[i].key);
2654 p_delete(&dn[i].value);
2662 KEY_CAP_CAN_ENCRYPT,
2667 static unsigned int key_check_cap (gpgme_key_t key, key_cap_t cap)
2669 gpgme_subkey_t subkey = NULL;
2670 unsigned int ret = 0;
2673 case KEY_CAP_CAN_ENCRYPT:
2674 if (!(ret = key->can_encrypt))
2675 for (subkey = key->subkeys; subkey; subkey = subkey->next)
2676 if ((ret = subkey->can_encrypt))
2679 case KEY_CAP_CAN_SIGN:
2680 if (!(ret = key->can_sign))
2681 for (subkey = key->subkeys; subkey; subkey = subkey->next)
2682 if ((ret = subkey->can_sign))
2685 case KEY_CAP_CAN_CERTIFY:
2686 if (!(ret = key->can_certify))
2687 for (subkey = key->subkeys; subkey; subkey = subkey->next)
2688 if ((ret = subkey->can_certify))
2697 /* Print verbose information about a key or certificate to FP. */
2698 static void print_key_info (gpgme_key_t key, FILE * fp)
2701 const char *s = NULL, *s2 = NULL;
2704 char shortbuf[SHORT_STRING];
2705 unsigned long aval = 0;
2709 gpgme_user_id_t uid = NULL;
2712 setlocale (LC_TIME, Locale);
2714 is_pgp = key->protocol == GPGME_PROTOCOL_OpenPGP;
2716 for (idx = 0, uid = key->uids; uid; idx++, uid = uid->next) {
2721 fputs (idx ? _(" aka ......: ") :_("Name ......: "), fp);
2724 fputs (_("[Invalid]"), fp);
2728 print_utf8 (fp, s, m_strlen(s));
2730 parse_and_print_user_id (fp, s);
2734 if (key->subkeys && (key->subkeys->timestamp > 0)) {
2735 tt = key->subkeys->timestamp;
2737 tm = localtime (&tt);
2738 #ifdef HAVE_LANGINFO_D_T_FMT
2739 strftime (shortbuf, sizeof shortbuf, nl_langinfo (D_T_FMT), tm);
2741 strftime (shortbuf, sizeof shortbuf, "%c", tm);
2743 fprintf (fp, _("Valid From : %s\n"), shortbuf);
2746 if (key->subkeys && (key->subkeys->expires > 0)) {
2747 tt = key->subkeys->expires;
2749 tm = localtime (&tt);
2750 #ifdef HAVE_LANGINFO_D_T_FMT
2751 strftime (shortbuf, sizeof shortbuf, nl_langinfo (D_T_FMT), tm);
2753 strftime (shortbuf, sizeof shortbuf, "%c", tm);
2755 fprintf (fp, _("Valid To ..: %s\n"), shortbuf);
2759 s = gpgme_pubkey_algo_name (key->subkeys->pubkey_algo);
2763 s2 = is_pgp ? "PGP" : "X.509";
2766 aval = key->subkeys->length;
2768 fprintf (fp, _("Key Type ..: %s, %lu bit %s\n"), s2, aval, s);
2770 fprintf (fp, _("Key Usage .: "));
2773 if (key_check_cap (key, KEY_CAP_CAN_ENCRYPT)) {
2774 fprintf (fp, "%s%s", delim, _("encryption"));
2777 if (key_check_cap (key, KEY_CAP_CAN_SIGN)) {
2778 fprintf (fp, "%s%s", delim, _("signing"));
2781 if (key_check_cap (key, KEY_CAP_CAN_CERTIFY)) {
2782 fprintf (fp, "%s%s", delim, _("certification"));
2788 s = key->subkeys->fpr;
2789 fputs (_("Fingerprint: "), fp);
2790 if (is_pgp && m_strlen(s) == 40) {
2791 for (i = 0; *s && s[1] && s[2] && s[3] && s[4]; s += 4, i++) {
2796 putc (is_pgp ? ' ' : ':', fp);
2797 if (is_pgp && i == 4)
2802 for (i = 0; *s && s[1] && s[2]; s += 2, i++) {
2805 putc (is_pgp ? ' ' : ':', fp);
2806 if (is_pgp && i == 7)
2810 fprintf (fp, "%s\n", s);
2813 if (key->issuer_serial) {
2814 s = key->issuer_serial;
2816 fprintf (fp, _("Serial-No .: 0x%s\n"), s);
2819 if (key->issuer_name) {
2820 s = key->issuer_name;
2822 fprintf (fp, _("Issued By .: "));
2823 parse_and_print_user_id (fp, s);
2828 /* For PGP we list all subkeys. */
2830 gpgme_subkey_t subkey = NULL;
2832 for (idx = 1, subkey = key->subkeys; subkey; idx++, subkey = subkey->next) {
2836 if (m_strlen(s) == 16)
2837 s += 8; /* display only the short keyID */
2838 fprintf (fp, _("Subkey ....: 0x%s"), s);
2839 if (subkey->revoked) {
2841 fputs (_("[Revoked]"), fp);
2843 if (subkey->invalid) {
2845 fputs (_("[Invalid]"), fp);
2847 if (subkey->expired) {
2849 fputs (_("[Expired]"), fp);
2851 if (subkey->disabled) {
2853 fputs (_("[Disabled]"), fp);
2857 if (subkey->timestamp > 0) {
2858 tt = subkey->timestamp;
2860 tm = localtime (&tt);
2861 #ifdef HAVE_LANGINFO_D_T_FMT
2862 strftime (shortbuf, sizeof shortbuf, nl_langinfo (D_T_FMT), tm);
2864 strftime (shortbuf, sizeof shortbuf, "%c", tm);
2866 fprintf (fp, _("Valid From : %s\n"), shortbuf);
2869 if (subkey->expires > 0) {
2870 tt = subkey->expires;
2872 tm = localtime (&tt);
2873 #ifdef HAVE_LANGINFO_D_T_FMT
2874 strftime (shortbuf, sizeof shortbuf, nl_langinfo (D_T_FMT), tm);
2876 strftime (shortbuf, sizeof shortbuf, "%c", tm);
2878 fprintf (fp, _("Valid To ..: %s\n"), shortbuf);
2882 s = gpgme_pubkey_algo_name (subkey->pubkey_algo);
2887 aval = subkey->length;
2891 fprintf (fp, _("Key Type ..: %s, %lu bit %s\n"), "PGP", aval, s);
2893 fprintf (fp, _("Key Usage .: "));
2896 if (subkey->can_encrypt) {
2897 fprintf (fp, "%s%s", delim, _("encryption"));
2900 if (subkey->can_sign) {
2901 fprintf (fp, "%s%s", delim, _("signing"));
2904 if (subkey->can_certify) {
2905 fprintf (fp, "%s%s", delim, _("certification"));
2913 setlocale (LC_TIME, "C");
2917 /* Show detailed information about the selected key */
2918 static void verify_key (crypt_key_t * key)
2921 char cmd[LONG_STRING], tempfile[_POSIX_PATH_MAX];
2923 gpgme_ctx_t listctx = NULL;
2925 gpgme_key_t k = NULL;
2928 fp = m_tempfile (tempfile, sizeof(tempfile), NONULL(Tempdir), NULL);
2930 mutt_perror (_("Can't create temporary file"));
2933 mutt_message _("Collecting data...");
2935 print_key_info (key->kobj, fp);
2937 err = gpgme_new (&listctx);
2939 fprintf (fp, "Internal error: can't create gpgme context: %s\n",
2940 gpgme_strerror (err));
2943 if ((key->flags & KEYFLAG_ISX509))
2944 gpgme_set_protocol (listctx, GPGME_PROTOCOL_CMS);
2948 while ((s = k->chain_id) && k->subkeys && m_strcmp(s, k->subkeys->fpr)) {
2950 err = gpgme_op_keylist_start (listctx, s, 0);
2951 gpgme_key_release (k);
2954 err = gpgme_op_keylist_next (listctx, &k);
2956 fprintf (fp, _("Error finding issuer key: %s\n"), gpgme_strerror (err));
2959 gpgme_op_keylist_end (listctx);
2961 print_key_info (k, fp);
2964 fputs (_("Error: certification chain to long - stopping here\n"), fp);
2970 gpgme_key_release (k);
2971 gpgme_release (listctx);
2973 mutt_clear_error ();
2974 snprintf (cmd, sizeof (cmd), _("Key ID: 0x%s"), crypt_keyid (key));
2975 mutt_do_pager (cmd, tempfile, 0, NULL);
2979 * Implementation of `findkeys'.
2983 /* Convert string_list_t into a pattern string suitable to be passed to GPGME.
2984 We need to convert spaces in an item into a '+' and '%' into
2986 static char *list_to_pattern (string_list_t * list)
2994 for (l = list; l; l = l->next) {
2995 for (s = l->data; *s; s++) {
3000 n++; /* delimiter or end of string */
3002 n++; /* make sure to allocate at least one byte */
3003 pattern = p = p_new(char, n);
3004 for (l = list; l; l = l->next) {
3009 for (s = l->data; *s; s++) {
3015 else if (*s == '+') {
3031 /* Return a list of keys which are candidates for the selection.
3032 Select by looking at the HINTS list. */
3033 static crypt_key_t *get_candidates (string_list_t * hints, unsigned int app,
3036 crypt_key_t *db, *k, **kend;
3042 gpgme_user_id_t uid = NULL;
3044 pattern = list_to_pattern (hints);
3048 err = gpgme_new (&ctx);
3050 mutt_error (_("gpgme_new failed: %s"), gpgme_strerror (err));
3058 if ((app & APPLICATION_PGP)) {
3059 /* Its all a mess. That old GPGME expects different things
3060 depending on the protocol. For gpg we don' t need percent
3061 escaped pappert but simple strings passed in an array to the
3062 keylist_ext_start function. */
3067 for (l = hints, n = 0; l; l = l->next) {
3068 if (l->data && *l->data)
3074 patarr = p_new(char *, n + 1);
3075 for (l = hints, n = 0; l; l = l->next) {
3076 if (l->data && *l->data)
3077 patarr[n++] = m_strdup(l->data);
3080 err = gpgme_op_keylist_ext_start (ctx, (const char **) patarr, secret, 0);
3081 for (n = 0; patarr[n]; n++)
3082 p_delete(&patarr[n]);
3085 mutt_error (_("gpgme_op_keylist_start failed: %s"), gpgme_strerror (err));
3086 gpgme_release (ctx);
3091 while (!(err = gpgme_op_keylist_next (ctx, &key))) {
3092 unsigned int flags = 0;
3094 if (key_check_cap (key, KEY_CAP_CAN_ENCRYPT))
3095 flags |= KEYFLAG_CANENCRYPT;
3096 if (key_check_cap (key, KEY_CAP_CAN_SIGN))
3097 flags |= KEYFLAG_CANSIGN;
3099 #if 0 /* DISABLED code */
3101 /* Bug in gpg. Capabilities are not listed for secret
3102 keys. Try to deduce them from the algorithm. */
3104 switch (key->subkeys[0].pubkey_algo) {
3106 flags |= KEYFLAG_CANENCRYPT;
3107 flags |= KEYFLAG_CANSIGN;
3109 case GPGME_PK_ELG_E:
3110 flags |= KEYFLAG_CANENCRYPT;
3113 flags |= KEYFLAG_CANSIGN;
3117 #endif /* DISABLED code */
3119 for (idx = 0, uid = key->uids; uid; idx++, uid = uid->next) {
3120 k = p_new(crypt_key_t, 1);
3129 if (gpg_err_code (err) != GPG_ERR_EOF)
3130 mutt_error (_("gpgme_op_keylist_next failed: %s"), gpgme_strerror (err));
3131 gpgme_op_keylist_end (ctx);
3136 if ((app & APPLICATION_SMIME)) {
3137 /* and now look for x509 certificates */
3138 gpgme_set_protocol (ctx, GPGME_PROTOCOL_CMS);
3139 err = gpgme_op_keylist_start (ctx, pattern, 0);
3141 mutt_error (_("gpgme_op_keylist_start failed: %s"), gpgme_strerror (err));
3142 gpgme_release (ctx);
3147 while (!(err = gpgme_op_keylist_next (ctx, &key))) {
3148 unsigned int flags = KEYFLAG_ISX509;
3150 if (key_check_cap (key, KEY_CAP_CAN_ENCRYPT))
3151 flags |= KEYFLAG_CANENCRYPT;
3152 if (key_check_cap (key, KEY_CAP_CAN_SIGN))
3153 flags |= KEYFLAG_CANSIGN;
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);
3170 gpgme_release (ctx);
3175 /* Add the string STR to the list HINTS. This list is later used to
3177 static string_list_t *crypt_add_string_to_hints (string_list_t * hints, const char *str)
3182 if ((scratch = m_strdup(str)) == NULL)
3185 for (t = strtok (scratch, " ,.:\"()<>\n"); t;
3186 t = strtok (NULL, " ,.:\"()<>\n")) {
3187 if (m_strlen(t) > 3)
3188 hints = mutt_add_list(hints, t);
3195 /* Display a menu to select a key from the array KEYS. FORCED_VALID
3196 will be set to true on return if the user did override the the
3198 static crypt_key_t *crypt_select_key (crypt_key_t * keys,
3199 address_t * p, const char *s,
3200 unsigned int app, int *forced_valid)
3203 crypt_key_t **key_table;
3206 char helpstr[SHORT_STRING], buf[LONG_STRING];
3208 int (*f) (const void *, const void *);
3209 int menu_to_use = 0;
3214 /* build the key table */
3217 for (k = keys; k; k = k->next) {
3218 if (!option (OPTPGPSHOWUNUSABLE) && (k->flags & KEYFLAG_CANTUSE)) {
3225 p_realloc(&key_table, keymax);
3231 if (!i && unusable) {
3232 mutt_error _("All matching keys are marked expired/revoked.");
3238 switch (PgpSortKeys & SORT_MASK) {
3240 f = crypt_compare_date;
3243 f = crypt_compare_keyid;
3246 f = crypt_compare_address;
3250 f = crypt_compare_trust;
3253 qsort (key_table, i, sizeof (crypt_key_t *), f);
3255 if (app & APPLICATION_PGP)
3256 menu_to_use = MENU_KEY_SELECT_PGP;
3257 else if (app & APPLICATION_SMIME)
3258 menu_to_use = MENU_KEY_SELECT_SMIME;
3261 mutt_make_help (buf, sizeof (buf), _("Exit "), menu_to_use, OP_EXIT);
3262 m_strcat(helpstr, sizeof(helpstr), buf);
3263 mutt_make_help (buf, sizeof (buf), _("Select "), menu_to_use,
3264 OP_GENERIC_SELECT_ENTRY);
3265 m_strcat(helpstr, sizeof(helpstr), buf);
3266 mutt_make_help (buf, sizeof (buf), _("Check key "),
3267 menu_to_use, OP_VERIFY_KEY);
3268 m_strcat(helpstr, sizeof(helpstr), buf);
3269 mutt_make_help (buf, sizeof (buf), _("Help"), menu_to_use, OP_HELP);
3270 m_strcat(helpstr, sizeof(helpstr), buf);
3272 menu = mutt_new_menu ();
3274 menu->make_entry = crypt_entry;
3275 menu->menu = menu_to_use;
3276 menu->help = helpstr;
3277 menu->data = key_table;
3282 if ((app & APPLICATION_PGP) && (app & APPLICATION_SMIME))
3283 ts = _("PGP and S/MIME keys matching");
3284 else if ((app & APPLICATION_PGP))
3285 ts = _("PGP keys matching");
3286 else if ((app & APPLICATION_SMIME))
3287 ts = _("S/MIME keys matching");
3289 ts = _("keys matching");
3292 snprintf (buf, sizeof (buf), _("%s <%s>."), ts, p->mailbox);
3294 snprintf (buf, sizeof (buf), _("%s \"%s\"."), ts, s);
3298 mutt_clear_error ();
3302 switch (mutt_menuLoop (menu)) {
3304 verify_key (key_table[menu->current]);
3305 menu->redraw = REDRAW_FULL;
3309 mutt_message ("%s", key_table[menu->current]->uid);
3312 case OP_GENERIC_SELECT_ENTRY:
3313 /* FIXME make error reporting more verbose - this should be
3314 easy because gpgme provides more information */
3315 if (option (OPTPGPCHECKTRUST)) {
3316 if (!crypt_key_is_valid (key_table[menu->current])) {
3317 mutt_error _("This key can't be used: "
3318 "expired/disabled/revoked.");
3323 if (option (OPTPGPCHECKTRUST) &&
3324 (!crypt_id_is_valid (key_table[menu->current])
3325 || !crypt_id_is_strong (key_table[menu->current]))) {
3327 char buff[LONG_STRING];
3329 if (key_table[menu->current]->flags & KEYFLAG_CANTUSE)
3330 s = N_("ID is expired/disabled/revoked.");
3332 gpgme_validity_t val = GPGME_VALIDITY_UNKNOWN;
3333 gpgme_user_id_t uid = NULL;
3338 uid = key_table[menu->current]->kobj->uids;
3339 for (j = 0; (j < key_table[menu->current]->idx) && uid;
3340 j++, uid = uid->next);
3342 val = uid->validity;
3345 case GPGME_VALIDITY_UNKNOWN:
3346 case GPGME_VALIDITY_UNDEFINED:
3347 warn_s = N_("ID has undefined validity.");
3349 case GPGME_VALIDITY_NEVER:
3350 warn_s = N_("ID is not valid.");
3352 case GPGME_VALIDITY_MARGINAL:
3353 warn_s = N_("ID is only marginally valid.");
3355 case GPGME_VALIDITY_FULL:
3356 case GPGME_VALIDITY_ULTIMATE:
3360 snprintf (buff, sizeof (buff),
3361 _("%s Do you really want to use the key?"), _(warn_s));
3363 if (mutt_yesorno (buff, 0) != 1) {
3364 mutt_clear_error ();
3371 k = crypt_copy_key (key_table[menu->current]);
3382 mutt_menuDestroy (&menu);
3383 p_delete(&key_table);
3385 set_option (OPTNEEDREDRAW);
3390 static crypt_key_t *crypt_getkeybyaddr (address_t * a, short abilities,
3391 unsigned int app, int *forced_valid)
3394 string_list_t *hints = NULL;
3399 int this_key_has_strong;
3400 int this_key_has_weak;
3401 int this_key_has_invalid;
3404 crypt_key_t *keys, *k;
3405 crypt_key_t *the_valid_key = NULL;
3406 crypt_key_t *matches = NULL;
3407 crypt_key_t **matches_endp = &matches;
3411 if (a && a->mailbox)
3412 hints = crypt_add_string_to_hints (hints, a->mailbox);
3413 if (a && a->personal)
3414 hints = crypt_add_string_to_hints (hints, a->personal);
3416 mutt_message (_("Looking for keys matching \"%s\"..."), a->mailbox);
3417 keys = get_candidates (hints, app, (abilities & KEYFLAG_CANSIGN));
3419 string_list_wipe(&hints);
3424 for (k = keys; k; k = k->next) {
3425 if (abilities && !(k->flags & abilities)) {
3429 this_key_has_weak = 0; /* weak but valid match */
3430 this_key_has_invalid = 0; /* invalid match */
3431 this_key_has_strong = 0; /* strong and valid match */
3432 match = 0; /* any match */
3434 r = rfc822_parse_adrlist (NULL, k->uid);
3435 for (p = r; p; p = p->next) {
3436 int validity = crypt_id_matches_addr (a, p, k);
3438 if (validity & CRYPT_KV_MATCH) /* something matches */
3441 /* is this key a strong candidate? */
3442 if ((validity & CRYPT_KV_VALID)
3443 && (validity & CRYPT_KV_STRONGID)
3444 && (validity & CRYPT_KV_ADDR)) {
3445 if (the_valid_key && the_valid_key != k)
3448 this_key_has_strong = 1;
3450 else if ((validity & CRYPT_KV_MATCH)
3451 && !(validity & CRYPT_KV_VALID))
3452 this_key_has_invalid = 1;
3453 else if ((validity & CRYPT_KV_MATCH)
3454 && (!(validity & CRYPT_KV_STRONGID)
3455 || !(validity & CRYPT_KV_ADDR)))
3456 this_key_has_weak = 1;
3458 address_list_wipe(&r);
3463 if (!this_key_has_strong && this_key_has_invalid)
3465 if (!this_key_has_strong && this_key_has_weak)
3468 *matches_endp = tmp = crypt_copy_key (k);
3469 matches_endp = &tmp->next;
3470 the_valid_key = tmp;
3474 crypt_free_key (&keys);
3477 if (the_valid_key && !multi && !weak
3478 && !(invalid && option (OPTPGPSHOWUNUSABLE))) {
3480 * There was precisely one strong match on a valid ID, there
3481 * were no valid keys with weak matches, and we aren't
3482 * interested in seeing invalid keys.
3484 * Proceed without asking the user.
3486 k = crypt_copy_key (the_valid_key);
3490 * Else: Ask the user.
3492 k = crypt_select_key (matches, a, NULL, app, forced_valid);
3494 crypt_free_key (&matches);
3503 static crypt_key_t *crypt_getkeybystr (const char *p, short abilities,
3504 unsigned int app, int *forced_valid)
3506 string_list_t *hints = NULL;
3508 crypt_key_t *matches = NULL;
3509 crypt_key_t **matches_endp = &matches;
3513 mutt_message (_("Looking for keys matching \"%s\"..."), p);
3517 hints = crypt_add_string_to_hints (hints, p);
3518 keys = get_candidates (hints, app, (abilities & KEYFLAG_CANSIGN));
3519 string_list_wipe(&hints);
3524 for (k = keys; k; k = k->next) {
3525 if (abilities && !(k->flags & abilities))
3530 if (!*p || !m_strcasecmp(p, crypt_keyid (k))
3531 || (!m_strncasecmp(p, "0x", 2)
3532 && !m_strcasecmp(p + 2, crypt_keyid (k)))
3533 || (option (OPTPGPLONGIDS)
3534 && !m_strncasecmp(p, "0x", 2)
3535 && !m_strcasecmp(p + 2, crypt_keyid (k) + 8))
3536 || m_stristr(k->uid, p)) {
3539 *matches_endp = tmp = crypt_copy_key (k);
3540 matches_endp = &tmp->next;
3544 crypt_free_key (&keys);
3547 k = crypt_select_key (matches, NULL, p, app, forced_valid);
3548 crypt_free_key (&matches);
3555 /* Display TAG as a prompt to ask for a key. If WHATFOR is not null
3556 use it as default and store it under that label as the next
3557 default. ABILITIES describe the required key abilities (sign,
3558 encrypt) and APP the type of the requested key; ether S/MIME or
3559 PGP. Return a copy of the key or NULL if not found. */
3560 static crypt_key_t *crypt_ask_for_key (char *tag,
3563 unsigned int app, int *forced_valid)
3566 char resp[SHORT_STRING];
3567 struct crypt_cache *l = NULL;
3571 forced_valid = &dummy;
3573 mutt_clear_error ();
3579 for (l = id_defaults; l; l = l->next)
3580 if (!m_strcasecmp(whatfor, l->what)) {
3581 m_strcpy(resp, sizeof(resp), NONULL(l->dflt));
3589 if (mutt_get_field (tag, resp, sizeof (resp), M_CLEAR) != 0)
3594 m_strreplace(&l->dflt, resp);
3596 l = p_new(struct crypt_cache, 1);
3597 l->next = id_defaults;
3599 l->what = m_strdup(whatfor);
3600 l->dflt = m_strdup(resp);
3604 if ((key = crypt_getkeybystr (resp, abilities, app, forced_valid)))
3612 /* This routine attempts to find the keyids of the recipients of a
3613 message. It returns NULL if any of the keys can not be found. */
3614 static char *find_keys (address_t * to, address_t * cc, address_t * bcc,
3617 char *keylist = NULL, *t;
3619 ssize_t keylist_size = 0;
3620 ssize_t keylist_used = 0;
3621 address_t *tmp = NULL, *addr = NULL;
3622 address_t **last = &tmp;
3625 crypt_key_t *k_info, *key;
3626 const char *fqdn = mutt_fqdn (1);
3629 *r_application = APPLICATION_PGP | APPLICATION_SMIME;
3632 for (i = 0; i < 3; i++) {
3647 *last = address_list_dup (p);
3649 last = &((*last)->next);
3652 rfc822_qualify(tmp, fqdn);
3653 address_list_uniq(tmp);
3655 for (p = tmp; p; p = p->next) {
3656 char buf[LONG_STRING];
3657 int forced_valid = 0;
3662 if ((keyID = mutt_crypt_hook (p)) != NULL) {
3665 snprintf (buf, sizeof (buf), _("Use keyID = \"%s\" for %s?"),
3667 if ((r = mutt_yesorno (buf, M_YES)) == M_YES) {
3668 /* check for e-mail address */
3669 if ((t = strchr (keyID, '@')) &&
3670 (addr = rfc822_parse_adrlist (NULL, keyID))) {
3671 rfc822_qualify(addr, fqdn);
3675 k_info = crypt_getkeybystr (keyID, KEYFLAG_CANENCRYPT,
3676 app, &forced_valid);
3681 address_list_wipe(&tmp);
3682 address_list_wipe(&addr);
3688 && (k_info = crypt_getkeybyaddr (q, KEYFLAG_CANENCRYPT,
3689 app, &forced_valid)) == NULL) {
3690 snprintf (buf, sizeof (buf), _("Enter keyID for %s: "), q->mailbox);
3692 if ((key = crypt_ask_for_key (buf, q->mailbox, KEYFLAG_CANENCRYPT,
3694 &forced_valid)) == NULL) {
3696 address_list_wipe(&tmp);
3697 address_list_wipe(&addr);
3705 const char *s = crypt_fpr (key);
3707 keylist_size += m_strlen(s) + 4 + 1;
3708 p_realloc(&keylist, keylist_size);
3709 sprintf (keylist + keylist_used, "%s0x%s%s",
3710 keylist_used ? " " : "", s, forced_valid ? "!" : "");
3712 keylist_used = m_strlen(keylist);
3714 crypt_free_key (&key);
3715 address_list_wipe(&addr);
3717 address_list_wipe(&tmp);
3721 char *pgp_gpgme_findkeys (address_t * to, address_t * cc, address_t * bcc)
3723 return find_keys (to, cc, bcc, APPLICATION_PGP);
3726 char *smime_gpgme_findkeys (address_t * to, address_t * cc, address_t * bcc)
3728 return find_keys (to, cc, bcc, APPLICATION_SMIME);
3732 * Implementation of `init'.
3735 /* Initialization. */
3736 static void init_gpgme (void)
3738 /* Make sure that gpg-agent is running. */
3739 if (!getenv ("GPG_AGENT_INFO")) {
3740 mutt_error ("\nUsing GPGME backend, although no gpg-agent is running");
3741 if (mutt_any_key_to_continue (NULL) == -1)
3746 void pgp_gpgme_init (void)
3751 void smime_gpgme_init (void)
3755 static int gpgme_send_menu (HEADER * msg, int *redraw, int is_smime)
3758 char input_signas[SHORT_STRING];
3761 if (msg->security & APPLICATION_PGP)
3763 else if (msg->security & APPLICATION_SMIME)
3768 mutt_multi_choice (_
3769 ("S/MIME (e)ncrypt, (s)ign, sign (a)s, (b)oth, (p)gp or (c)lear?"),
3773 mutt_multi_choice (_
3774 ("PGP (e)ncrypt, (s)ign, sign (a)s, (b)oth, s/(m)ime or (c)lear?"),
3778 case 1: /* (e)ncrypt */
3779 msg->security |= (is_smime ? SMIMEENCRYPT : PGPENCRYPT);
3780 msg->security &= ~(is_smime ? SMIMESIGN : PGPSIGN);
3783 case 2: /* (s)ign */
3784 msg->security |= (is_smime ? SMIMESIGN : PGPSIGN);
3785 msg->security &= ~(is_smime ? SMIMEENCRYPT : PGPENCRYPT);
3788 case 3: /* sign (a)s */
3789 /* unset_option(OPTCRYPTCHECKTRUST); */
3790 if ((p = crypt_ask_for_key (_("Sign as: "), NULL, KEYFLAG_CANSIGN,
3791 is_smime ? APPLICATION_SMIME :
3792 APPLICATION_PGP, NULL))) {
3793 snprintf (input_signas, sizeof (input_signas), "0x%s", crypt_keyid (p));
3794 m_strreplace(is_smime ? &SmimeDefaultKey : &PgpSignAs,
3796 crypt_free_key (&p);
3798 msg->security |= (is_smime ? SMIMESIGN : PGPSIGN);
3800 *redraw = REDRAW_FULL;
3803 case 4: /* (b)oth */
3805 (is_smime ? (SMIMEENCRYPT | SMIMESIGN) : (PGPENCRYPT | PGPSIGN));
3808 case 5: /* (p)gp or s/(m)ime */
3809 is_smime = !is_smime;
3812 case 6: /* (c)lear */
3817 if (choice == 6 || choice == 7);
3818 else if (is_smime) {
3819 msg->security &= ~APPLICATION_PGP;
3820 msg->security |= APPLICATION_SMIME;
3823 msg->security &= ~APPLICATION_SMIME;
3824 msg->security |= APPLICATION_PGP;
3827 return (msg->security);
3830 int pgp_gpgme_send_menu (HEADER * msg, int *redraw)
3832 return gpgme_send_menu (msg, redraw, 0);
3835 int smime_gpgme_send_menu (HEADER * msg, int *redraw)
3837 return gpgme_send_menu (msg, redraw, 1);
3840 static int verify_sender (HEADER * h, gpgme_protocol_t protocol __attribute__((unused)))
3842 address_t *sender = NULL;
3843 unsigned int ret = 1;
3846 h->env->from = mutt_expand_aliases (h->env->from);
3847 sender = h->env->from;
3849 else if (h->env->sender) {
3850 h->env->sender = mutt_expand_aliases (h->env->sender);
3851 sender = h->env->sender;
3855 if (signature_key) {
3856 gpgme_key_t key = signature_key;
3857 gpgme_user_id_t uid = NULL;
3858 int sender_length = 0;
3861 sender_length = m_strlen(sender->mailbox);
3862 for (uid = key->uids; uid && ret; uid = uid->next) {
3863 uid_length = m_strlen(uid->email);
3864 if (1 && (uid->email[0] == '<')
3865 && (uid->email[uid_length - 1] == '>')
3866 && (uid_length == sender_length + 2)
3867 && (!m_strncmp (uid->email + 1, sender->mailbox, sender_length)))
3872 mutt_any_key_to_continue ("Failed to verify sender");
3875 mutt_any_key_to_continue ("Failed to figure out sender");
3877 if (signature_key) {
3878 gpgme_key_release (signature_key);
3879 signature_key = NULL;
3885 int smime_gpgme_verify_sender (HEADER * h)
3887 return verify_sender (h, GPGME_PROTOCOL_CMS);