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
11 * Copyright © 2006 Pierre Habouzit
14 #include <lib-lib/lib-lib.h>
18 #include <lib-mime/mime.h>
19 #include <lib-ui/curses.h>
20 #include <lib-ui/enter.h>
21 #include <lib-ui/menu.h>
30 #include "recvattach.h"
33 /* Values used for comparing addresses. */
34 #define CRYPT_KV_VALID 1
35 #define CRYPT_KV_ADDR 2
36 #define CRYPT_KV_STRING 4
37 #define CRYPT_KV_STRONGID 8
38 #define CRYPT_KV_MATCH (CRYPT_KV_ADDR|CRYPT_KV_STRING)
47 struct crypt_cache *next;
55 /* We work based on user IDs, getting from a user ID to the key is
56 check and does not need any memory (gpgme uses reference counting). */
57 typedef struct crypt_keyinfo {
58 struct crypt_keyinfo *next;
60 int idx; /* and the user ID at this index */
61 const char *uid; /* and for convenience point to this user ID */
62 unsigned int flags; /* global and per uid flags (for convenience) */
65 typedef struct crypt_entry {
71 static struct crypt_cache *id_defaults = NULL;
72 static gpgme_key_t signature_key = NULL;
75 * General helper functions.
78 /* return true when S points to a didgit or letter. */
79 static int digit_or_letter (const unsigned char *s)
81 return ((*s >= '0' && *s <= '9')
82 || (*s >= 'A' && *s <= 'Z')
83 || (*s >= 'a' && *s <= 'z'));
87 /* Print the utf-8 encoded string BUF of length LEN bytes to stream
88 FP. Convert the character set. */
89 static void print_utf8 (FILE * fp, const char *buf, ssize_t len)
93 tstr = p_dupstr(buf, len);
94 mutt_convert_string (&tstr, "utf-8", MCharset.charset, M_ICONV_HOOK_FROM);
104 /* Return the keyID for the key K. Note that this string is valid as
105 long as K is valid */
106 static const char *crypt_keyid (crypt_key_t * k)
108 const char *s = "????????";
110 if (k->kobj && k->kobj->subkeys) {
111 s = k->kobj->subkeys->keyid;
112 if ((!option (OPTPGPLONGIDS)) && (m_strlen(s) == 16))
113 /* Return only the short keyID. */
120 /* Return the hexstring fingerprint from the key K. */
121 static const char *crypt_fpr (crypt_key_t * k)
125 if (k->kobj && k->kobj->subkeys)
126 s = k->kobj->subkeys->fpr;
131 /* Parse FLAGS and return a statically allocated(!) string with them. */
132 static char *crypt_key_abilities (int flags)
136 if (!(flags & KEYFLAG_CANENCRYPT))
138 else if (flags & KEYFLAG_PREFER_SIGNING)
143 if (!(flags & KEYFLAG_CANSIGN))
145 else if (flags & KEYFLAG_PREFER_ENCRYPTION)
155 /* Parse FLAGS and return a character describing the most important flag. */
156 static char crypt_flags (int flags)
158 if (flags & KEYFLAG_REVOKED)
160 else if (flags & KEYFLAG_EXPIRED)
162 else if (flags & KEYFLAG_DISABLED)
164 else if (flags & KEYFLAG_CRITICAL)
170 /* Return a copy of KEY. */
171 static crypt_key_t *crypt_copy_key (crypt_key_t *key)
175 k = p_new(crypt_key_t, 1);
177 gpgme_key_ref (key->kobj);
180 k->flags = key->flags;
185 /* Release all the keys at the address of KEYLIST and set the address
187 static void crypt_free_key (crypt_key_t ** keylist)
190 crypt_key_t *k = (*keylist)->next;
197 /* Return trute when key K is valid. */
198 static int crypt_key_is_valid (crypt_key_t * k)
200 if (k->flags & KEYFLAG_CANTUSE)
205 /* Return true whe validity of KEY is sufficient. */
206 static int crypt_id_is_strong (crypt_key_t * key)
208 gpgme_validity_t val = GPGME_VALIDITY_UNKNOWN;
209 gpgme_user_id_t uid = NULL;
213 if ((key->flags & KEYFLAG_ISX509))
216 for (i = 0, uid = key->kobj->uids; (i < key->idx) && uid;
217 i++, uid = uid->next);
222 case GPGME_VALIDITY_UNKNOWN:
223 case GPGME_VALIDITY_UNDEFINED:
224 case GPGME_VALIDITY_NEVER:
225 case GPGME_VALIDITY_MARGINAL:
229 case GPGME_VALIDITY_FULL:
230 case GPGME_VALIDITY_ULTIMATE:
238 /* Return true when the KEY is valid, i.e. not marked as unusable. */
239 static int crypt_id_is_valid (crypt_key_t * key)
241 return !(key->flags & KEYFLAG_CANTUSE);
244 /* Return a bit vector describing how well the addresses ADDR and
245 U_ADDR match and whether KEY is valid. */
246 static int crypt_id_matches_addr (address_t * addr, address_t * u_addr,
251 if (crypt_id_is_valid (key))
252 rv |= CRYPT_KV_VALID;
254 if (crypt_id_is_strong (key))
255 rv |= CRYPT_KV_STRONGID;
257 if (addr->mailbox && u_addr->mailbox
258 && m_strcasecmp(addr->mailbox, u_addr->mailbox) == 0)
261 if (addr->personal && u_addr->personal
262 && m_strcasecmp(addr->personal, u_addr->personal) == 0)
263 rv |= CRYPT_KV_STRING;
270 * GPGME convenient functions.
273 /* Create a new gpgme context and return it. With FOR_SMIME set to
274 true, the protocol of the context is set to CMS. */
275 static gpgme_ctx_t create_gpgme_context (int for_smime)
280 err = gpgme_new (&ctx);
282 mutt_error (_("error creating gpgme context: %s\n"), gpgme_strerror (err));
288 err = gpgme_set_protocol (ctx, GPGME_PROTOCOL_CMS);
290 mutt_error (_("error enabling CMS protocol: %s\n"), gpgme_strerror (err));
299 /* Create a new gpgme data object. This is a wrapper to die on
301 static gpgme_data_t create_gpgme_data (void)
306 err = gpgme_data_new (&data);
308 mutt_error (_("error creating gpgme data object: %s\n"),
309 gpgme_strerror (err));
316 /* Create a new GPGME Data object from the mail body A. With CONVERT
317 passed as true, the lines are converted to CR,LF if required.
318 Return NULL on error or the gpgme_data_t object on success. */
319 static gpgme_data_t body_to_data_object (BODY * a, int convert)
321 char tempfile[_POSIX_PATH_MAX];
326 fptmp = m_tempfile(tempfile, sizeof(tempfile), NONULL(MCore.tmpdir), NULL);
328 mutt_perror (_("Can't create temporary file"));
332 mutt_write_mime_header (a, fptmp);
334 mutt_write_mime_body (a, fptmp);
338 unsigned char buf[1];
340 data = create_gpgme_data ();
342 while ((c = fgetc (fptmp)) != EOF) {
346 if (c == '\n' && !hadcr) {
348 gpgme_data_write (data, buf, 1);
353 /* FIXME: This is quite suboptimal */
355 gpgme_data_write (data, buf, 1);
357 gpgme_data_seek (data, 0, SEEK_SET);
359 err = gpgme_data_new_from_file (&data, tempfile, 1);
364 mutt_error (_("error allocating data object: %s\n"), gpgme_strerror (err));
371 /* Create a GPGME data object from the stream FP but limit the object
372 to LENGTH bytes starting at OFFSET bytes from the beginning of the
374 static gpgme_data_t file_to_data_object (FILE * fp, long offset, long length)
379 err = gpgme_data_new_from_filepart (&data, NULL, fp, offset, length);
381 mutt_error (_("error allocating data object: %s\n"), gpgme_strerror (err));
388 /* Write a GPGME data object to the stream FP. */
389 static int data_object_to_stream (gpgme_data_t data, FILE * fp)
395 err = ((gpgme_data_seek (data, 0, SEEK_SET) == -1)
396 ? gpgme_error_from_errno (errno) : 0);
398 mutt_error (_("error rewinding data object: %s\n"), gpgme_strerror (err));
402 while ((nread = gpgme_data_read (data, buf, sizeof (buf)))) {
403 /* fixme: we are not really converting CRLF to LF but just
404 skipping CR. Doing it correctly needs a more complex logic */
405 for (p = buf; nread; p++, nread--) {
411 mutt_perror ("[tempfile]");
416 mutt_error (_("error reading data object: %s\n"), strerror (errno));
422 /* Copy a data object to a newly created temporay file and return that
423 filename. Caller must free. With RET_FP not NULL, don't close the
424 stream but return it there. */
425 static char *data_object_to_tempfile (gpgme_data_t data, FILE ** ret_fp)
428 char tempfile[_POSIX_PATH_MAX];
432 fp = m_tempfile(tempfile, sizeof(tempfile), NONULL(MCore.tmpdir), NULL);
434 mutt_perror (_("Can't create temporary file"));
438 err = ((gpgme_data_seek (data, 0, SEEK_SET) == -1)
439 ? gpgme_error_from_errno (errno) : 0);
443 while ((nread = gpgme_data_read (data, buf, sizeof (buf)))) {
444 if (fwrite (buf, nread, 1, fp) != 1) {
445 mutt_perror (_("Can't create temporary file"));
457 mutt_error (_("error reading data object: %s\n"), gpgme_strerror (err));
464 return m_strdup(tempfile);
468 /* FIXME: stolen from gpgme to avoid "ambiguous identity" errors */
470 gpgme_get_key2 (gpgme_ctx_t ctx, const char *fpr, gpgme_key_t *r_key,
476 if (!ctx || !r_key || !fpr)
477 return gpg_error (GPG_ERR_INV_VALUE);
479 if (strlen (fpr) < 8) /* We have at least a key ID. */
480 return gpg_error (GPG_ERR_INV_VALUE);
482 /* FIXME: We use our own context because we have to avoid the user's
483 I/O callback handlers. */
484 err = gpgme_new (&listctx);
487 gpgme_set_protocol (listctx, gpgme_get_protocol (ctx));
488 err = gpgme_op_keylist_start (listctx, fpr, secret);
490 err = gpgme_op_keylist_next (listctx, r_key);
491 gpgme_release (listctx);
495 /* Create a GpgmeRecipientSet from the keys in the string KEYLIST.
496 The keys must be space delimited. */
497 static gpgme_key_t *create_recipient_set (const char *keylist,
498 gpgme_protocol_t protocol)
504 gpgme_key_t *rset = NULL;
505 unsigned int rset_n = 0;
506 gpgme_key_t key = NULL;
507 gpgme_ctx_t context = NULL;
509 err = gpgme_new (&context);
511 err = gpgme_set_protocol (context, protocol);
518 for (i = 0; *s && *s != ' ' && i < ssizeof(buf) - 1;)
522 if (i > 1 && buf[i - 1] == '!') {
523 /* The user selected to override the valididy of that
527 err = gpgme_get_key2 (context, buf, &key, 0);
529 key->uids->validity = GPGME_VALIDITY_FULL;
533 err = gpgme_get_key2 (context, buf, &key, 0);
536 p_realloc(&rset, rset_n + 1);
537 rset[rset_n++] = key;
540 mutt_error (_("error adding recipient `%s': %s\n"),
541 buf, gpgme_strerror (err));
549 /* NULL terminate. */
550 p_realloc(&rset, rset_n + 1);
551 rset[rset_n++] = NULL;
554 gpgme_release (context);
560 /* Make sure that the correct signer is set. Returns 0 on success. */
561 static int set_signer (gpgme_ctx_t ctx, int for_smime)
563 char *signid = for_smime ? SmimeDefaultKey : PgpSignAs;
566 gpgme_key_t key, key2;
568 if (!signid || !*signid)
571 listctx = create_gpgme_context (for_smime);
572 err = gpgme_op_keylist_start (listctx, signid, 1);
574 err = gpgme_op_keylist_next (listctx, &key);
576 gpgme_release (listctx);
577 mutt_error (_("secret key `%s' not found: %s\n"),
578 signid, gpgme_strerror (err));
581 err = gpgme_op_keylist_next (listctx, &key2);
583 gpgme_key_release (key);
584 gpgme_key_release (key2);
585 gpgme_release (listctx);
586 mutt_error (_("ambiguous specification of secret key `%s'\n"), signid);
589 gpgme_op_keylist_end (listctx);
590 gpgme_release (listctx);
592 gpgme_signers_clear (ctx);
593 err = gpgme_signers_add (ctx, key);
594 gpgme_key_release (key);
596 mutt_error (_("error setting secret key `%s': %s\n"),
597 signid, gpgme_strerror (err));
604 /* Encrypt the gpgme data object PLAINTEXT to the recipients in RSET
605 and return an allocated filename to a temporary file containing the
606 enciphered text. With USE_SMIME set to true, the smime backend is
607 used. With COMBINED_SIGNED a PGP message is signed and
608 encrypted. Returns NULL in case of error */
609 static char *encrypt_gpgme_object (gpgme_data_t plaintext, gpgme_key_t * rset,
610 int use_smime, int combined_signed)
614 gpgme_data_t ciphertext;
617 ctx = create_gpgme_context (use_smime);
619 gpgme_set_armor (ctx, 1);
621 ciphertext = create_gpgme_data ();
623 if (combined_signed) {
624 if (set_signer (ctx, use_smime)) {
625 gpgme_data_release (ciphertext);
629 err = gpgme_op_encrypt_sign (ctx, rset, GPGME_ENCRYPT_ALWAYS_TRUST,
630 plaintext, ciphertext);
633 err = gpgme_op_encrypt (ctx, rset, GPGME_ENCRYPT_ALWAYS_TRUST,
634 plaintext, ciphertext);
635 mutt_need_hard_redraw ();
637 mutt_error (_("error encrypting data: %s\n"), gpgme_strerror (err));
638 gpgme_data_release (ciphertext);
645 outfile = data_object_to_tempfile (ciphertext, NULL);
646 gpgme_data_release (ciphertext);
650 /* Find the "micalg" parameter from the last Gpgme operation on
651 context CTX. It is expected that this operation was a sign
652 operation. Return the algorithm name as a C string in buffer BUF
653 which must have been allocated by the caller with size BUFLEN.
654 Returns 0 on success or -1 in case of an error. The return string
655 is truncted to BUFLEN - 1. */
656 static int get_micalg (gpgme_ctx_t ctx, char *buf, ssize_t buflen)
658 gpgme_sign_result_t result = NULL;
659 const char *algorithm_name = NULL;
665 result = gpgme_op_sign_result (ctx);
667 algorithm_name = gpgme_hash_algo_name (result->signatures->hash_algo);
668 if (algorithm_name) {
669 m_strcpy(buf, buflen, algorithm_name);
673 return *buf ? 0 : -1;
676 static void print_time (time_t t, STATE * s)
680 setlocale (LC_TIME, "");
681 #ifdef HAVE_LANGINFO_D_T_FMT
682 strftime (p, sizeof (p), nl_langinfo (D_T_FMT), localtime (&t));
684 strftime (p, sizeof (p), "%c", localtime (&t));
686 setlocale (LC_TIME, "C");
687 state_attach_puts (p, s);
690 /* 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 *crypt_pgp_sign_message (BODY * a)
786 return sign_message (a, 0);
789 BODY *crypt_smime_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 *crypt_pgp_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 *crypt_smime_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 */
901 /* Implementation of `verify_one'. */
903 /* Display the common attributes of the signature summary SUM.
904 Return 1 if there is is a severe warning.
906 static int show_sig_summary (unsigned long sum,
907 gpgme_ctx_t ctx, gpgme_key_t key, int idx,
912 if ((sum & GPGME_SIGSUM_KEY_REVOKED)) {
913 state_attach_puts (_("Warning: One of the keys has been revoked\n"), s);
917 if ((sum & GPGME_SIGSUM_KEY_EXPIRED)) {
918 time_t at = key->subkeys->expires ? key->subkeys->expires : 0;
921 state_attach_puts (_("Warning: The key used to create the "
922 "signature expired at: "), s);
924 state_attach_puts ("\n", s);
927 state_attach_puts (_("Warning: At least one certification key "
928 "has expired\n"), s);
931 if ((sum & GPGME_SIGSUM_SIG_EXPIRED)) {
932 gpgme_verify_result_t result;
933 gpgme_signature_t sig;
936 result = gpgme_op_verify_result (ctx);
938 for (sig = result->signatures, i = 0; sig && (i < idx);
939 sig = sig->next, i++);
941 state_attach_puts (_("Warning: The signature expired at: "), s);
942 print_time (sig ? sig->exp_timestamp : 0, s);
943 state_attach_puts ("\n", s);
946 if ((sum & GPGME_SIGSUM_KEY_MISSING))
947 state_attach_puts (_("Can't verify due to a missing "
948 "key or certificate\n"), s);
950 if ((sum & GPGME_SIGSUM_CRL_MISSING)) {
951 state_attach_puts (_("The CRL is not available\n"), s);
955 if ((sum & GPGME_SIGSUM_CRL_TOO_OLD)) {
956 state_attach_puts (_("Available CRL is too old\n"), s);
960 if ((sum & GPGME_SIGSUM_BAD_POLICY))
961 state_attach_puts (_("A policy requirement was not met\n"), s);
963 if ((sum & GPGME_SIGSUM_SYS_ERROR)) {
964 const char *t0 = NULL, *t1 = NULL;
965 gpgme_verify_result_t result;
966 gpgme_signature_t sig;
969 state_attach_puts (_("A system error occurred"), s);
971 /* Try to figure out some more detailed system error information. */
972 result = gpgme_op_verify_result (ctx);
973 for (sig = result->signatures, i = 0; sig && (i < idx);
974 sig = sig->next, i++);
977 t1 = sig->wrong_key_usage ? "Wrong_Key_Usage" : "";
981 state_attach_puts (": ", s);
983 state_attach_puts (t0, s);
984 if (t1 && !(t0 && !m_strcmp(t0, t1))) {
986 state_attach_puts (",", s);
987 state_attach_puts (t1, s);
990 state_attach_puts ("\n", s);
997 static void show_fingerprint (gpgme_key_t key, STATE * state)
1002 const char *prefix = _("Fingerprint: ");
1007 s = key->subkeys ? key->subkeys->fpr : NULL;
1010 is_pgp = (key->protocol == GPGME_PROTOCOL_OpenPGP);
1012 bufsize = m_strlen(prefix) + m_strlen(s) * 4 + 2;
1013 buf = p_new(char, bufsize);
1014 m_strcpy(buf, bufsize, prefix);
1015 p = buf + m_strlen(buf);
1016 if (is_pgp && m_strlen(s) == 40) { /* PGP v4 style formatted. */
1017 for (i = 0; *s && s[1] && s[2] && s[3] && s[4]; s += 4, i++) {
1028 for (i = 0; *s && s[1] && s[2]; s += 2, i++) {
1031 *p++ = is_pgp ? ' ' : ':';
1032 if (is_pgp && i == 7)
1037 /* just in case print remaining odd digits */
1042 state_attach_puts (buf, state);
1046 /* Show the valididy of a key used for one signature. */
1047 static void show_one_sig_validity (gpgme_ctx_t ctx, int idx, STATE * s)
1049 gpgme_verify_result_t result = NULL;
1050 gpgme_signature_t sig = NULL;
1051 const char *txt = NULL;
1053 result = gpgme_op_verify_result (ctx);
1055 for (sig = result->signatures; sig && (idx > 0); sig = sig->next, idx--);
1057 switch (sig ? sig->validity : 0) {
1058 case GPGME_VALIDITY_UNKNOWN:
1059 txt = _("WARNING: We have NO indication whether "
1060 "the key belongs to the person named " "as shown above\n");
1062 case GPGME_VALIDITY_UNDEFINED:
1064 case GPGME_VALIDITY_NEVER:
1065 txt = _("WARNING: The key does NOT BELONG to "
1066 "the person named as shown above\n");
1068 case GPGME_VALIDITY_MARGINAL:
1069 txt = _("WARNING: It is NOT certain that the key "
1070 "belongs to the person named as shown above\n");
1072 case GPGME_VALIDITY_FULL:
1073 case GPGME_VALIDITY_ULTIMATE:
1078 state_attach_puts (txt, s);
1081 /* Show information about one signature. This fucntion is called with
1082 the context CTX of a sucessful verification operation and the
1083 enumerator IDX which should start at 0 and incremete for each
1086 Return values are: 0 for normal procession, 1 for a bad signature,
1087 2 for a signature with a warning or -1 for no more signature. */
1088 static int show_one_sig_status (gpgme_ctx_t ctx, int idx, STATE * s)
1091 const char *fpr, *uid;
1092 gpgme_key_t key = NULL;
1093 int i, anybad = 0, anywarn = 0;
1095 gpgme_user_id_t uids = NULL;
1096 gpgme_verify_result_t result;
1097 gpgme_signature_t sig;
1098 gpgme_error_t err = GPG_ERR_NO_ERROR;
1100 result = gpgme_op_verify_result (ctx);
1102 /* FIXME: this code should use a static variable and remember
1103 the current position in the list of signatures, IMHO.
1106 for (i = 0, sig = result->signatures; sig && (i < idx);
1107 i++, sig = sig->next);
1109 return -1; /* Signature not found. */
1111 if (signature_key) {
1112 gpgme_key_release (signature_key);
1113 signature_key = NULL;
1116 created = sig->timestamp;
1120 if (gpg_err_code (sig->status) != GPG_ERR_NO_ERROR)
1123 err = gpgme_get_key2 (ctx, fpr, &key, 0); /* secret key? */
1125 uid = (key->uids && key->uids->uid) ? key->uids->uid : "[?]";
1127 signature_key = key;
1130 key = NULL; /* Old gpgme versions did not set KEY to NULL on
1131 error. Do it here to avoid a double free. */
1135 if (!s || !s->fpout || !(s->flags & M_DISPLAY)); /* No state information so no way to print anything. */
1137 state_attach_puts (_("Error getting key information: "), s);
1138 state_attach_puts (gpg_strerror (err), s);
1139 state_attach_puts ("\n", s);
1142 else if ((sum & GPGME_SIGSUM_GREEN)) {
1143 state_attach_puts (_("Good signature from: "), s);
1144 state_attach_puts (uid, s);
1145 state_attach_puts ("\n", s);
1146 for (i = 1, uids = key->uids; uids; i++, uids = uids->next) {
1148 /* Skip primary UID. */
1152 state_attach_puts (_(" aka: "), s);
1153 state_attach_puts (uids->uid, s);
1154 state_attach_puts ("\n", s);
1156 state_attach_puts (_(" created: "), s);
1157 print_time (created, s);
1158 state_attach_puts ("\n", s);
1159 if (show_sig_summary (sum, ctx, key, idx, s))
1161 show_one_sig_validity (ctx, idx, s);
1163 else if ((sum & GPGME_SIGSUM_RED)) {
1164 state_attach_puts (_("*BAD* signature claimed to be from: "), s);
1165 state_attach_puts (uid, s);
1166 state_attach_puts ("\n", s);
1167 show_sig_summary (sum, ctx, key, idx, s);
1169 else if (!anybad && key && (key->protocol == GPGME_PROTOCOL_OpenPGP)) { /* We can't decide (yellow) but this is a PGP key with a good
1170 signature, so we display what a PGP user expects: The name,
1171 fingerprint and the key validity (which is neither fully or
1173 state_attach_puts (_("Good signature from: "), s);
1174 state_attach_puts (uid, s);
1175 state_attach_puts ("\n", s);
1176 state_attach_puts (_(" created: "), s);
1177 print_time (created, s);
1178 state_attach_puts ("\n", s);
1179 show_one_sig_validity (ctx, idx, s);
1180 show_fingerprint (key, s);
1181 if (show_sig_summary (sum, ctx, key, idx, s))
1184 else { /* can't decide (yellow) */
1186 state_attach_puts (_("Error checking signature"), s);
1187 state_attach_puts ("\n", s);
1188 show_sig_summary (sum, ctx, key, idx, s);
1191 if (key != signature_key)
1192 gpgme_key_release (key);
1195 return anybad ? 1 : anywarn ? 2 : 0;
1198 /* Do the actual verification step. With IS_SMIME set to true we
1199 assume S/MIME (surprise!) */
1200 int crypt_verify_one(BODY *sigbdy, STATE *s, FILE *fp, int is_smime)
1206 gpgme_data_t signature, message;
1208 signature = file_to_data_object (s->fpin, sigbdy->offset, sigbdy->length);
1212 /* We need to tell gpgme about the encoding because the backend can't
1213 auto-detect plain base-64 encoding which is used by S/MIME. */
1215 gpgme_data_set_encoding (signature, GPGME_DATA_ENCODING_BASE64);
1217 err = gpgme_data_new_from_stream(&message, fp);
1219 gpgme_data_release (signature);
1220 mutt_error (_("error allocating data object: %s\n"), gpgme_strerror (err));
1223 ctx = create_gpgme_context (is_smime);
1225 /* Note: We don't need a current time output because GPGME avoids
1226 such an attack by separating the meta information from the
1228 state_attach_puts (_("[-- Begin signature information --]\n"), s);
1230 err = gpgme_op_verify (ctx, signature, message, NULL);
1231 mutt_need_hard_redraw ();
1235 snprintf (buf, sizeof (buf) - 1,
1236 _("Error: verification failed: %s\n"), gpgme_strerror (err));
1237 state_attach_puts (buf, s);
1239 else { /* Verification succeeded, see what the result is. */
1243 if (signature_key) {
1244 gpgme_key_release (signature_key);
1245 signature_key = NULL;
1248 for (idx = 0; (res = show_one_sig_status (ctx, idx, s)) != -1; idx++) {
1259 gpgme_verify_result_t result;
1260 gpgme_sig_notation_t notation;
1261 gpgme_signature_t sig;
1263 result = gpgme_op_verify_result (ctx);
1265 for (sig = result->signatures; sig; sig = sig->next) {
1266 if (sig->notations) {
1267 state_attach_puts ("*** Begin Notation (signature by: ", s);
1268 state_attach_puts (sig->fpr, s);
1269 state_attach_puts (") ***\n", s);
1270 for (notation = sig->notations; notation; notation = notation->next)
1272 if (notation->name) {
1273 state_attach_puts (notation->name, s);
1274 state_attach_puts ("=", s);
1276 if (notation->value) {
1277 state_attach_puts (notation->value, s);
1278 if (!(*notation->value
1279 && (notation->value[m_strlen(notation->value) - 1] ==
1281 state_attach_puts ("\n", s);
1284 state_attach_puts ("*** End Notation ***\n", s);
1290 gpgme_release (ctx);
1292 state_attach_puts (_("[-- End signature information --]\n\n"), s);
1294 return badsig ? 1 : anywarn ? 2 : 0;
1298 * Implementation of `decrypt_part'.
1301 /* Decrypt a PGP or SMIME message (depending on the boolean flag
1302 IS_SMIME) with body A described further by state S. Write
1303 plaintext out to file FPOUT and return a new body. For PGP returns
1304 a flag in R_IS_SIGNED to indicate whether this is a combined
1305 encrypted and signed message, for S/MIME it returns true when it is
1306 not a encrypted but a signed message. */
1307 static BODY *decrypt_part (BODY * a, STATE * s, FILE * fpout, int is_smime,
1314 gpgme_data_t ciphertext, plaintext;
1315 int maybe_signed = 0;
1322 ctx = create_gpgme_context (is_smime);
1325 /* Make a data object from the body, create context etc. */
1326 ciphertext = file_to_data_object (s->fpin, a->offset, a->length);
1329 plaintext = create_gpgme_data ();
1331 /* Do the decryption or the verification in case of the S/MIME hack. */
1332 if ((!is_smime) || maybe_signed) {
1334 err = gpgme_op_decrypt_verify (ctx, ciphertext, plaintext);
1335 else if (maybe_signed)
1336 err = gpgme_op_verify (ctx, ciphertext, NULL, plaintext);
1339 /* Check wether signatures have been verified. */
1340 gpgme_verify_result_t verify_result = gpgme_op_verify_result (ctx);
1342 if (verify_result->signatures)
1347 err = gpgme_op_decrypt (ctx, ciphertext, plaintext);
1348 gpgme_data_release (ciphertext);
1350 if (is_smime && !maybe_signed && gpg_err_code (err) == GPG_ERR_NO_DATA) {
1351 /* Check whether this might be a signed message despite what
1352 the mime header told us. Retry then. gpgsm returns the
1353 error information "unsupported Algorithm '?'" but gpgme
1354 will not store this unknown algorithm, thus we test that
1355 it has not been set. */
1356 gpgme_decrypt_result_t result;
1358 result = gpgme_op_decrypt_result (ctx);
1359 if (!result->unsupported_algorithm) {
1361 gpgme_data_release (plaintext);
1365 mutt_need_hard_redraw ();
1366 if ((s->flags & M_DISPLAY)) {
1369 snprintf (buf, sizeof (buf) - 1,
1370 _("[-- Error: decryption failed: %s --]\n\n"),
1371 gpgme_strerror (err));
1372 state_attach_puts (buf, s);
1374 gpgme_data_release (plaintext);
1375 gpgme_release (ctx);
1378 mutt_need_hard_redraw ();
1380 /* Read the output from GPGME, and make sure to change CRLF to LF,
1381 otherwise read_mime_header has a hard time parsing the message. */
1382 if (data_object_to_stream (plaintext, fpout)) {
1383 gpgme_data_release (plaintext);
1384 gpgme_release (ctx);
1387 gpgme_data_release (plaintext);
1389 a->is_signed_data = 0;
1395 a->is_signed_data = 1;
1397 *r_is_signed = -1; /* A signature exists. */
1399 if ((s->flags & M_DISPLAY))
1400 state_attach_puts (_("[-- Begin signature " "information --]\n"), s);
1401 for (idx = 0; (res = show_one_sig_status (ctx, idx, s)) != -1; idx++) {
1407 if (!anybad && idx && r_is_signed && *r_is_signed)
1408 *r_is_signed = anywarn ? 2 : 1; /* Good signature. */
1410 if ((s->flags & M_DISPLAY))
1411 state_attach_puts (_("[-- End signature " "information --]\n\n"), s);
1413 gpgme_release (ctx);
1418 tattach = mutt_read_mime_header (fpout, 0);
1421 * Need to set the length of this body part.
1423 fstat (fileno (fpout), &info);
1424 tattach->length = info.st_size - tattach->offset;
1426 tattach->warnsig = anywarn;
1428 /* See if we need to recurse on this MIME part. */
1429 mutt_parse_part (fpout, tattach);
1435 /* Decrypt a PGP/MIME message in FPIN and B and return a new body and
1436 the stream in CUR and FPOUT. Returns 0 on success. */
1437 int crypt_pgp_decrypt_mime (FILE * fpin, FILE ** fpout, BODY * b, BODY ** cur)
1439 char tempfile[_POSIX_PATH_MAX];
1441 BODY *first_part = b;
1444 first_part->goodsig = 0;
1445 first_part->warnsig = 0;
1447 if (!mutt_is_multipart_encrypted (b))
1450 if (!b->parts || !b->parts->next)
1457 *fpout = m_tempfile(tempfile, sizeof(tempfile), NONULL(MCore.tmpdir), NULL);
1459 mutt_perror (_("Can't create temporary file"));
1464 *cur = decrypt_part (b, &s, *fpout, 0, &is_signed);
1467 first_part->goodsig = 1;
1469 return *cur ? 0 : -1;
1473 /* Decrypt a S/MIME message in FPIN and B and return a new body and
1474 the stream in CUR and FPOUT. Returns 0 on success. */
1475 int crypt_smime_decrypt_mime (FILE * fpin, FILE ** fpout, BODY * b,
1478 char tempfile[_POSIX_PATH_MAX];
1482 long saved_b_offset;
1483 ssize_t saved_b_length;
1486 if (!mutt_is_application_smime (b))
1492 /* Decode the body - we need to pass binary CMS to the
1493 backend. The backend allows for Base64 encoded data but it does
1494 not allow for QP which I have seen in some messages. So better
1496 saved_b_type = b->type;
1497 saved_b_offset = b->offset;
1498 saved_b_length = b->length;
1501 fseeko (s.fpin, b->offset, 0);
1502 tmpfp = m_tempfile (tempfile, sizeof(tempfile), NONULL(MCore.tmpdir), NULL);
1504 mutt_perror (_("Can't create temporary file"));
1507 mutt_unlink (tempfile);
1510 mutt_decode_attachment (b, &s);
1512 b->length = ftello (s.fpout);
1519 *fpout = m_tempfile(tempfile, sizeof(tempfile), NONULL(MCore.tmpdir), NULL);
1521 mutt_perror (_("Can't create temporary file"));
1524 mutt_unlink (tempfile);
1526 *cur = decrypt_part (b, &s, *fpout, 1, &is_signed);
1528 (*cur)->goodsig = is_signed > 0;
1529 b->type = saved_b_type;
1530 b->length = saved_b_length;
1531 b->offset = saved_b_offset;
1534 if (*cur && !is_signed && !(*cur)->parts
1535 && mutt_is_application_smime (*cur)) {
1536 /* Assume that this is a opaque signed s/mime message. This is
1537 an ugly way of doing it but we have anyway a problem with
1538 arbitrary encoded S/MIME messages: Only the outer part may be
1539 encrypted. The entire mime parsing should be revamped,
1540 probably by keeping the temportary files so that we don't
1541 need to decrypt them all the time. Inner parts of an
1542 encrypted part can then pint into this file and tehre won't
1543 never be a need to decrypt again. This needs a partial
1544 rewrite of the MIME engine. */
1548 saved_b_type = bb->type;
1549 saved_b_offset = bb->offset;
1550 saved_b_length = bb->length;
1553 fseeko (s.fpin, bb->offset, 0);
1554 tmpfp = m_tempfile (tempfile, sizeof(tempfile), NONULL(MCore.tmpdir), NULL);
1556 mutt_perror (_("Can't create temporary file"));
1559 mutt_unlink (tempfile);
1562 mutt_decode_attachment (bb, &s);
1564 bb->length = ftello (s.fpout);
1572 *fpout = m_tempfile(tempfile, sizeof(tempfile), NONULL(MCore.tmpdir), NULL);
1574 mutt_perror (_("Can't create temporary file"));
1577 mutt_unlink (tempfile);
1579 tmp_b = decrypt_part (bb, &s, *fpout, 1, &is_signed);
1581 tmp_b->goodsig = is_signed > 0;
1582 bb->type = saved_b_type;
1583 bb->length = saved_b_length;
1584 bb->offset = saved_b_offset;
1587 body_list_wipe(cur);
1590 return *cur ? 0 : -1;
1595 * Implementation of `pgp_check_traditional'.
1598 static int pgp_check_traditional_one_body (FILE * fp, BODY * b,
1601 char tempfile[_POSIX_PATH_MAX];
1602 char buf[HUGE_STRING];
1609 if (b->type != TYPETEXT)
1612 if (tagged_only && !b->tagged)
1615 tempfd = m_tempfd(tempfile, sizeof(tempfile), NONULL(MCore.tmpdir), NULL);
1616 if (mutt_decode_save_attachment (fp, b, tempfd, 0) != 0) {
1621 if ((tfp = fopen(tempfile, "r")) == NULL) {
1626 while (fgets (buf, sizeof (buf), tfp)) {
1627 if (!m_strncmp("-----BEGIN PGP ", buf, 15)) {
1628 if (!m_strcmp("MESSAGE-----\n", buf + 15))
1630 else if (!m_strcmp("SIGNED MESSAGE-----\n", buf + 15))
1640 /* fix the content type */
1642 parameter_setval(&b->parameter, "format", "fixed");
1643 parameter_setval(&b->parameter, "x-action",
1644 enc ? "pgp-encrypted" : "pgp-signed");
1648 int crypt_pgp_check_traditional (FILE * fp, BODY * b, int tagged_only)
1653 for (; b; b = b->next) {
1654 if (is_multipart (b))
1655 rv = (crypt_pgp_check_traditional (fp, b->parts, tagged_only) || rv);
1656 else if (b->type == TYPETEXT) {
1657 if ((r = mutt_is_application_pgp (b)))
1660 rv = (pgp_check_traditional_one_body (fp, b, tagged_only) || rv);
1667 /* Implementation of `application_handler'. */
1670 Copy a clearsigned message, and strip the signature and PGP's
1673 XXX - charset handling: We assume that it is safe to do
1674 character set decoding first, dash decoding second here, while
1675 we do it the other way around in the main handler.
1677 (Note that we aren't worse than Outlook & Cie in this, and also
1678 note that we can successfully handle anything produced by any
1679 existing versions of mutt.) */
1681 static void copy_clearsigned (gpgme_data_t data, STATE * s, char *charset)
1683 char buf[HUGE_STRING];
1684 short complete, armor_header;
1689 fname = data_object_to_tempfile (data, &fp);
1695 fc = fgetconv_open (fp, charset, MCharset.charset, M_ICONV_HOOK_FROM);
1697 for (complete = 1, armor_header = 1;
1698 fgetconvs (buf, sizeof (buf), fc) != NULL;
1699 complete = strchr (buf, '\n') != NULL) {
1702 state_puts (buf, s);
1706 if (!m_strcmp(buf, "-----BEGIN PGP SIGNATURE-----\n"))
1716 state_puts (s->prefix, s);
1718 if (buf[0] == '-' && buf[1] == ' ')
1719 state_puts (buf + 2, s);
1721 state_puts (buf, s);
1724 fgetconv_close (&fc);
1729 /* Support for classic_application/pgp */
1730 int crypt_pgp_application_pgp_handler (BODY * m, STATE * s)
1732 int needpass = -1, pgp_keyblock = 0;
1736 off_t last_pos, offset;
1737 char buf[HUGE_STRING];
1738 FILE *pgpout = NULL;
1740 gpgme_error_t err = 0;
1741 gpgme_data_t armored_data = NULL;
1743 short maybe_goodsig = 1;
1744 short have_any_sigs = 0;
1746 char body_charset[STRING]; /* Only used for clearsigned messages. */
1748 /* For clearsigned messages we won't be able to get a character set
1749 but we know that this may only be text thus we assume Latin-1
1751 if (!mutt_get_body_charset (body_charset, sizeof (body_charset), m))
1752 m_strcpy(body_charset, sizeof(body_charset), "iso-8859-1");
1754 fseeko (s->fpin, m->offset, 0);
1755 last_pos = m->offset;
1757 for (bytes = m->length; bytes > 0;) {
1758 if (fgets (buf, sizeof (buf), s->fpin) == NULL)
1761 offset = ftello (s->fpin);
1762 bytes -= (offset - last_pos); /* don't rely on m_strlen(buf) */
1765 if (!m_strncmp("-----BEGIN PGP ", buf, 15)) {
1767 start_pos = last_pos;
1769 if (!m_strcmp("MESSAGE-----\n", buf + 15))
1771 else if (!m_strcmp("SIGNED MESSAGE-----\n", buf + 15)) {
1775 else if (!option (OPTDONTHANDLEPGPKEYS) &&
1776 !m_strcmp("PUBLIC KEY BLOCK-----\n", buf + 15)) {
1781 /* XXX - we may wish to recode here */
1783 state_puts (s->prefix, s);
1784 state_puts (buf, s);
1788 have_any_sigs = (have_any_sigs || (clearsign && (s->flags & M_VERIFY)));
1790 /* Copy PGP material to an data container */
1791 armored_data = create_gpgme_data ();
1792 gpgme_data_write (armored_data, buf, m_strlen(buf));
1793 while (bytes > 0 && fgets (buf, sizeof (buf) - 1, s->fpin) != NULL) {
1794 offset = ftello (s->fpin);
1795 bytes -= (offset - last_pos); /* don't rely on m_strlen(buf) */
1798 gpgme_data_write (armored_data, buf, m_strlen(buf));
1800 if ((needpass && !m_strcmp("-----END PGP MESSAGE-----\n", buf))
1802 && (!m_strcmp("-----END PGP SIGNATURE-----\n", buf)
1803 || !m_strcmp("-----END PGP PUBLIC KEY BLOCK-----\n",
1808 /* Invoke PGP if needed */
1809 if (!clearsign || (s->flags & M_VERIFY)) {
1810 unsigned int sig_stat = 0;
1811 gpgme_data_t plaintext;
1814 plaintext = create_gpgme_data ();
1815 ctx = create_gpgme_context (0);
1818 err = gpgme_op_verify (ctx, armored_data, NULL, plaintext);
1820 err = gpgme_op_decrypt_verify (ctx, armored_data, plaintext);
1821 if (gpg_err_code (err) == GPG_ERR_NO_DATA) {
1822 /* Decrypt verify can't handle signed only messages. */
1823 err = (gpgme_data_seek (armored_data, 0, SEEK_SET) == -1)
1824 ? gpgme_error_from_errno (errno) : 0;
1825 /* Must release plaintext so that we supply an
1826 uninitialized object. */
1827 gpgme_data_release (plaintext);
1828 plaintext = create_gpgme_data ();
1829 err = gpgme_op_verify (ctx, armored_data, NULL, plaintext);
1836 snprintf (errbuf, sizeof (errbuf) - 1,
1837 _("Error: decryption/verification failed: %s\n"),
1838 gpgme_strerror (err));
1839 state_attach_puts (errbuf, s);
1841 else { /* Decryption/Verification succeeded */
1845 /* Check wether signatures have been verified. */
1846 gpgme_verify_result_t verify_result;
1848 verify_result = gpgme_op_verify_result (ctx);
1849 if (verify_result->signatures)
1855 if ((s->flags & M_DISPLAY) && sig_stat) {
1860 state_attach_puts (_("[-- Begin signature "
1861 "information --]\n"), s);
1864 (res = show_one_sig_status (ctx, idx, s)) != -1; idx++) {
1873 state_attach_puts (_("[-- End signature "
1874 "information --]\n\n"), s);
1877 tmpfname = data_object_to_tempfile (plaintext, &pgpout);
1880 state_attach_puts (_("Error: copy data failed\n"), s);
1884 p_delete(&tmpfname);
1887 gpgme_release (ctx);
1891 * Now, copy cleartext to the screen. NOTE - we expect that PGP
1892 * outputs utf-8 cleartext. This may not always be true, but it
1893 * seems to be a reasonable guess.
1896 if (s->flags & M_DISPLAY) {
1898 state_attach_puts (_("[-- BEGIN PGP MESSAGE --]\n\n"), s);
1899 else if (pgp_keyblock)
1900 state_attach_puts (_("[-- BEGIN PGP PUBLIC KEY BLOCK --]\n"), s);
1902 state_attach_puts (_("[-- BEGIN PGP SIGNED MESSAGE --]\n\n"), s);
1906 copy_clearsigned (armored_data, s, body_charset);
1913 fc = fgetconv_open (pgpout, "utf-8", MCharset.charset, 0);
1914 while ((c = fgetconv (fc)) != EOF) {
1916 if (c == '\n' && s->prefix)
1917 state_puts (s->prefix, s);
1919 fgetconv_close (&fc);
1922 if (s->flags & M_DISPLAY) {
1923 state_putc ('\n', s);
1925 state_attach_puts (_("[-- END PGP MESSAGE --]\n"), s);
1926 else if (pgp_keyblock)
1927 state_attach_puts (_("[-- END PGP PUBLIC KEY BLOCK --]\n"), s);
1929 state_attach_puts (_("[-- END PGP SIGNED MESSAGE --]\n"), s);
1937 /* XXX - we may wish to recode here */
1939 state_puts (s->prefix, s);
1940 state_puts (buf, s);
1944 m->goodsig = (maybe_goodsig && have_any_sigs);
1946 if (needpass == -1) {
1947 state_attach_puts (_("[-- Error: could not find beginning"
1948 " of PGP message! --]\n\n"), s);
1954 /* Implementation of `encrypted_handler'. */
1956 /* MIME handler for pgp/mime encrypted messages. */
1957 int crypt_pgp_encrypted_handler (BODY * a, STATE * s)
1959 char tempfile[_POSIX_PATH_MAX];
1962 BODY *orig_body = a;
1967 if (!a || a->type != TYPEAPPLICATION || !a->subtype
1968 || ascii_strcasecmp ("pgp-encrypted", a->subtype)
1969 || !a->next || a->next->type != TYPEAPPLICATION || !a->next->subtype
1970 || ascii_strcasecmp ("octet-stream", a->next->subtype)) {
1971 if (s->flags & M_DISPLAY)
1972 state_attach_puts (_("[-- Error: malformed PGP/MIME message! --]\n\n"),
1977 /* Move forward to the application/pgp-encrypted body. */
1980 fpout = m_tempfile(tempfile, sizeof(tempfile), NONULL(MCore.tmpdir), NULL);
1982 if (s->flags & M_DISPLAY)
1983 state_attach_puts (_("[-- Error: could not create temporary file! "
1988 tattach = decrypt_part (a, s, fpout, 0, &is_signed);
1990 tattach->goodsig = is_signed > 0;
1992 if (s->flags & M_DISPLAY)
1993 state_attach_puts (is_signed ?
1995 ("[-- The following data is PGP/MIME signed and encrypted --]\n\n") :
1996 _("[-- The following data is PGP/MIME encrypted --]\n\n"), s);
1999 FILE *savefp = s->fpin;
2002 rc = mutt_body_handler (tattach, s);
2007 * if a multipart/signed is the _only_ sub-part of a
2008 * multipart/encrypted, cache signature verification
2011 if (mutt_is_multipart_signed (tattach) && !tattach->next)
2012 orig_body->goodsig |= tattach->goodsig;
2014 if (s->flags & M_DISPLAY) {
2015 state_puts ("\n", s);
2016 state_attach_puts (is_signed ?
2018 ("[-- End of PGP/MIME signed and encrypted data --]\n")
2019 : _("[-- End of PGP/MIME encrypted data --]\n"), s);
2022 body_list_wipe(&tattach);
2026 mutt_unlink (tempfile);
2030 /* Support for application/smime */
2031 int crypt_smime_application_smime_handler (BODY * a, STATE * s)
2033 char tempfile[_POSIX_PATH_MAX];
2040 fpout = m_tempfile(tempfile, sizeof(tempfile), NONULL(MCore.tmpdir), NULL);
2042 if (s->flags & M_DISPLAY)
2043 state_attach_puts (_("[-- Error: could not create temporary file! "
2048 tattach = decrypt_part (a, s, fpout, 1, &is_signed);
2050 tattach->goodsig = is_signed > 0;
2052 if (s->flags & M_DISPLAY)
2053 state_attach_puts (is_signed ?
2054 _("[-- The following data is S/MIME signed --]\n\n") :
2055 _("[-- The following data is S/MIME encrypted --]\n\n"), s);
2058 FILE *savefp = s->fpin;
2061 rc = mutt_body_handler (tattach, s);
2066 * if a multipart/signed is the _only_ sub-part of a
2067 * multipart/encrypted, cache signature verification
2070 if (mutt_is_multipart_signed (tattach) && !tattach->next) {
2071 if (!(a->goodsig = tattach->goodsig))
2072 a->warnsig = tattach->warnsig;
2074 else if (tattach->goodsig) {
2076 a->warnsig = tattach->warnsig;
2079 if (s->flags & M_DISPLAY) {
2080 state_puts ("\n", s);
2081 state_attach_puts (is_signed ?
2082 _("[-- End of S/MIME signed data --]\n") :
2083 _("[-- End of S/MIME encrypted data --]\n"), s);
2086 body_list_wipe(&tattach);
2090 mutt_unlink (tempfile);
2096 * Format an entry on the CRYPT key selection menu.
2099 * %k key id %K key id of the principal key
2101 * %a algorithm %A algorithm of the princ. key
2102 * %l length %L length of the princ. key
2103 * %f flags %F flags of the princ. key
2104 * %c capabilities %C capabilities of the princ. key
2105 * %t trust/validity of the key-uid association
2107 * %[...] date of key using strftime(3)
2111 crypt_entry_fmt (char *dest, ssize_t destlen, char op,
2112 const char *src, const char *prefix,
2113 const char *ifstr, const char *elstr,
2114 anytype data, format_flag flags)
2117 crypt_entry_t *entry;
2120 int optional = (flags & M_FORMAT_OPTIONAL);
2121 const char *s = NULL;
2127 /* if (isupper ((unsigned char) op)) */
2130 kflags = (key->flags /*| (pkey->flags & KEYFLAG_RESTRICTIONS)
2133 switch (ascii_tolower (op)) {
2137 char buf2[STRING], *p;
2153 while (len > 0 && *cp != ']') {
2162 break; /* not enough space */
2172 if (do_locales && Locale)
2173 setlocale (LC_TIME, Locale);
2178 if (key->kobj->subkeys && (key->kobj->subkeys->timestamp > 0))
2179 tt = key->kobj->subkeys->timestamp;
2181 tm = localtime (&tt);
2183 strftime (buf2, sizeof (buf2), dest, tm);
2186 setlocale (LC_TIME, "C");
2188 snprintf (fmt, sizeof (fmt), "%%%ss", prefix);
2189 snprintf (dest, destlen, fmt, buf2);
2196 snprintf (fmt, sizeof (fmt), "%%%sd", prefix);
2197 snprintf (dest, destlen, fmt, entry->num);
2202 /* fixme: we need a way to distinguish between main and subkeys.
2203 Store the idx in entry? */
2204 snprintf (fmt, sizeof (fmt), "%%%ss", prefix);
2205 snprintf (dest, destlen, fmt, crypt_keyid (key));
2210 snprintf (fmt, sizeof (fmt), "%%%ss", prefix);
2211 snprintf (dest, destlen, fmt, key->uid);
2216 snprintf (fmt, sizeof (fmt), "%%%s.3s", prefix);
2217 if (key->kobj->subkeys)
2218 s = gpgme_pubkey_algo_name (key->kobj->subkeys->pubkey_algo);
2221 snprintf (dest, destlen, fmt, s);
2226 snprintf (fmt, sizeof (fmt), "%%%slu", prefix);
2227 if (key->kobj->subkeys)
2228 val = key->kobj->subkeys->length;
2231 snprintf (dest, destlen, fmt, val);
2236 snprintf (fmt, sizeof (fmt), "%%%sc", prefix);
2237 snprintf (dest, destlen, fmt, crypt_flags (kflags));
2239 else if (!(kflags & (KEYFLAG_RESTRICTIONS)))
2244 snprintf (fmt, sizeof (fmt), "%%%ss", prefix);
2245 snprintf (dest, destlen, fmt, crypt_key_abilities (kflags));
2247 else if (!(kflags & (KEYFLAG_ABILITIES)))
2251 if ((kflags & KEYFLAG_ISX509))
2254 gpgme_user_id_t uid = NULL;
2257 for (i = 0, uid = key->kobj->uids; uid && (i < key->idx);
2258 i++, uid = uid->next);
2260 switch (uid->validity) {
2261 case GPGME_VALIDITY_UNDEFINED:
2264 case GPGME_VALIDITY_NEVER:
2267 case GPGME_VALIDITY_MARGINAL:
2270 case GPGME_VALIDITY_FULL:
2273 case GPGME_VALIDITY_ULTIMATE:
2276 case GPGME_VALIDITY_UNKNOWN:
2282 snprintf (fmt, sizeof (fmt), "%%%sc", prefix);
2283 snprintf (dest, destlen, fmt, s ? *s : 'B');
2286 snprintf (fmt, sizeof (fmt), "%%%ss", prefix);
2287 snprintf (dest, destlen, fmt,
2288 gpgme_get_protocol_name (key->kobj->protocol));
2295 if (flags & M_FORMAT_OPTIONAL)
2296 m_strformat(dest, destlen, 0, optional ? ifstr: elstr,
2297 mutt_attach_fmt, data, 0);
2301 /* Used by the display fucntion to format a line. */
2302 static void crypt_entry (char *s, ssize_t l, MUTTMENU * menu, int num)
2304 crypt_key_t **key_table = (crypt_key_t **) menu->data;
2305 crypt_entry_t entry;
2307 entry.key = key_table[num];
2308 entry.num = num + 1;
2310 m_strformat(s, l, COLS - SW, PgpEntryFormat, crypt_entry_fmt, &entry,
2311 option(OPTARROWCURSOR) ? M_FORMAT_ARROWCURSOR : 0);
2314 /* Compare two addresses and the keyid to be used for sorting. */
2315 static int _crypt_compare_address (const void *a, const void *b)
2317 crypt_key_t **s = (crypt_key_t **) a;
2318 crypt_key_t **t = (crypt_key_t **) b;
2321 if ((r = m_strcasecmp((*s)->uid, (*t)->uid)))
2324 return m_strcasecmp(crypt_keyid (*s), crypt_keyid (*t)) > 0;
2327 static int crypt_compare_address (const void *a, const void *b)
2329 return ((PgpSortKeys & SORT_REVERSE) ? !_crypt_compare_address (a, b)
2330 : _crypt_compare_address (a, b));
2334 /* Compare two key IDs and the addresses to be used for sorting. */
2335 static int _crypt_compare_keyid (const void *a, const void *b)
2337 crypt_key_t **s = (crypt_key_t **) a;
2338 crypt_key_t **t = (crypt_key_t **) b;
2341 if ((r = m_strcasecmp(crypt_keyid (*s), crypt_keyid (*t))))
2344 return m_strcasecmp((*s)->uid, (*t)->uid) > 0;
2347 static int crypt_compare_keyid (const void *a, const void *b)
2349 return ((PgpSortKeys & SORT_REVERSE) ? !_crypt_compare_keyid (a, b)
2350 : _crypt_compare_keyid (a, b));
2353 /* Compare 2 creation dates and the addresses. For sorting. */
2354 static int _crypt_compare_date (const void *a, const void *b)
2356 crypt_key_t **s = (crypt_key_t **) a;
2357 crypt_key_t **t = (crypt_key_t **) b;
2358 unsigned long ts = 0, tt = 0;
2360 if ((*s)->kobj->subkeys && ((*s)->kobj->subkeys->timestamp > 0))
2361 ts = (*s)->kobj->subkeys->timestamp;
2362 if ((*t)->kobj->subkeys && ((*t)->kobj->subkeys->timestamp > 0))
2363 tt = (*t)->kobj->subkeys->timestamp;
2370 return m_strcasecmp((*s)->uid, (*t)->uid) > 0;
2373 static int crypt_compare_date (const void *a, const void *b)
2375 return ((PgpSortKeys & SORT_REVERSE) ? !_crypt_compare_date (a, b)
2376 : _crypt_compare_date (a, b));
2379 /* Compare two trust values, the key length, the creation dates. the
2380 addresses and the key IDs. For sorting. */
2381 static int _crypt_compare_trust (const void *a, const void *b)
2383 crypt_key_t **s = (crypt_key_t **) a;
2384 crypt_key_t **t = (crypt_key_t **) b;
2385 unsigned long ts = 0, tt = 0;
2388 if ((r = (((*s)->flags & (KEYFLAG_RESTRICTIONS))
2389 - ((*t)->flags & (KEYFLAG_RESTRICTIONS)))))
2392 if ((*s)->kobj->uids)
2393 ts = (*s)->kobj->uids->validity;
2394 if ((*t)->kobj->uids)
2395 tt = (*t)->kobj->uids->validity;
2396 if ((r = (tt - ts)))
2399 if ((*s)->kobj->subkeys)
2400 ts = (*s)->kobj->subkeys->length;
2401 if ((*t)->kobj->subkeys)
2402 tt = (*t)->kobj->subkeys->length;
2406 if ((*s)->kobj->subkeys && ((*s)->kobj->subkeys->timestamp > 0))
2407 ts = (*s)->kobj->subkeys->timestamp;
2408 if ((*t)->kobj->subkeys && ((*t)->kobj->subkeys->timestamp > 0))
2409 tt = (*t)->kobj->subkeys->timestamp;
2415 if ((r = m_strcasecmp((*s)->uid, (*t)->uid)))
2417 return (m_strcasecmp(crypt_keyid ((*s)), crypt_keyid ((*t)))) > 0;
2420 static int crypt_compare_trust (const void *a, const void *b)
2422 return ((PgpSortKeys & SORT_REVERSE) ? !_crypt_compare_trust (a, b)
2423 : _crypt_compare_trust (a, b));
2426 /* Print the X.500 Distinguished Name part KEY from the array of parts
2428 static int print_dn_part (FILE * fp, struct dn_array_s *dn, const char *key)
2432 for (; dn->key; dn++) {
2433 if (!m_strcmp(dn->key, key)) {
2436 print_utf8 (fp, dn->value, m_strlen(dn->value));
2443 /* Print all parts of a DN in a standard sequence. */
2444 static void print_dn_parts (FILE * fp, struct dn_array_s *dn)
2446 const char *stdpart[] = {
2447 "CN", "OU", "O", "STREET", "L", "ST", "C", NULL
2449 int any = 0, any2 = 0, i;
2451 for (i = 0; stdpart[i]; i++) {
2454 any = print_dn_part (fp, dn, stdpart[i]);
2456 /* now print the rest without any specific ordering */
2457 for (; dn->key; dn++) {
2458 for (i = 0; stdpart[i]; i++) {
2459 if (!m_strcmp(dn->key, stdpart[i]))
2467 any = print_dn_part (fp, dn, dn->key);
2476 /* Parse an RDN; this is a helper to parse_dn(). */
2477 static const unsigned char *parse_dn_part (struct dn_array_s *array,
2478 const unsigned char *string)
2480 const unsigned char *s, *s1;
2484 /* parse attributeType */
2485 for (s = string + 1; *s && *s != '='; s++);
2487 return NULL; /* error */
2490 return NULL; /* empty key */
2491 array->key = p_dupstr(string, n );
2492 p = (unsigned char *) array->key;
2495 if (*string == '#') { /* hexstring */
2497 for (s = string; hexval(*s) >= 0; s++)
2501 return NULL; /* empty or odd number of digits */
2503 p = p_new(unsigned char, n + 1);
2504 array->value = (char *) p;
2505 for (s1 = string; n; s1 += 2, n--)
2506 *p++ = (hexval(*s1) << 8) | hexval(*s1);
2509 else { /* regular v3 quoted string */
2510 for (n = 0, s = string; *s; s++) {
2511 if (*s == '\\') { /* pair */
2513 if (*s == ',' || *s == '=' || *s == '+'
2514 || *s == '<' || *s == '>' || *s == '#' || *s == ';'
2515 || *s == '\\' || *s == '\"' || *s == ' ')
2517 else if (hexval(*s) >= 0 && hexval(*s + 1) >= 0) {
2522 return NULL; /* invalid escape sequence */
2524 else if (*s == '\"')
2525 return NULL; /* invalid encoding */
2526 else if (*s == ',' || *s == '=' || *s == '+'
2527 || *s == '<' || *s == '>' || *s == '#' || *s == ';')
2533 p = p_new(unsigned char, n + 1);
2534 array->value = (char *) p;
2535 for (s = string; n; s++, n--) {
2538 if (hexval(*s) >= 0) {
2539 *p++ = (hexval(*s) << 8) | hexval(*s + 1);
2554 /* Parse a DN and return an array-ized one. This is not a validating
2555 parser and it does not support any old-stylish syntax; gpgme is
2556 expected to return only rfc2253 compatible strings. */
2557 static struct dn_array_s *parse_dn (const unsigned char *string)
2559 struct dn_array_s *array;
2560 ssize_t arrayidx, arraysize;
2563 arraysize = 7; /* C,ST,L,O,OU,CN,email */
2564 array = p_new(struct dn_array_s, arraysize + 1);
2567 while (*string == ' ')
2571 if (arrayidx >= arraysize) { /* mutt lacks a real safe_realoc - so we need to copy */
2572 struct dn_array_s *a2;
2575 a2 = p_new(struct dn_array_s, arraysize + 1);
2576 for (i = 0; i < arrayidx; i++) {
2577 a2[i].key = array[i].key;
2578 a2[i].value = array[i].value;
2583 array[arrayidx].key = NULL;
2584 array[arrayidx].value = NULL;
2585 string = parse_dn_part (array + arrayidx, string);
2589 while (*string == ' ')
2591 if (*string && *string != ',' && *string != ';' && *string != '+')
2592 goto failure; /* invalid delimiter */
2596 array[arrayidx].key = NULL;
2597 array[arrayidx].value = NULL;
2601 for (i = 0; i < arrayidx; i++) {
2602 p_delete(&array[i].key);
2603 p_delete(&array[i].value);
2610 /* Print a nice representation of the USERID and make sure it is
2611 displayed in a proper way, which does mean to reorder some parts
2612 for S/MIME's DNs. USERID is a string as returned by the gpgme key
2613 functions. It is utf-8 encoded. */
2614 static void parse_and_print_user_id (FILE * fp, const char *userid)
2619 if (*userid == '<') {
2620 s = strchr (userid + 1, '>');
2622 print_utf8 (fp, userid + 1, s - userid - 1);
2624 else if (*userid == '(')
2625 fputs (_("[Can't display this user ID (unknown encoding)]"), fp);
2626 else if (!digit_or_letter ((const unsigned char *) userid))
2627 fputs (_("[Can't display this user ID (invalid encoding)]"), fp);
2629 struct dn_array_s *dn = parse_dn ((const unsigned char *) userid);
2632 fputs (_("[Can't display this user ID (invalid DN)]"), fp);
2634 print_dn_parts (fp, dn);
2635 for (i = 0; dn[i].key; i++) {
2636 p_delete(&dn[i].key);
2637 p_delete(&dn[i].value);
2645 KEY_CAP_CAN_ENCRYPT,
2650 static unsigned int key_check_cap (gpgme_key_t key, key_cap_t cap)
2652 gpgme_subkey_t subkey = NULL;
2653 unsigned int ret = 0;
2656 case KEY_CAP_CAN_ENCRYPT:
2657 if (!(ret = key->can_encrypt))
2658 for (subkey = key->subkeys; subkey; subkey = subkey->next)
2659 if ((ret = subkey->can_encrypt))
2662 case KEY_CAP_CAN_SIGN:
2663 if (!(ret = key->can_sign))
2664 for (subkey = key->subkeys; subkey; subkey = subkey->next)
2665 if ((ret = subkey->can_sign))
2668 case KEY_CAP_CAN_CERTIFY:
2669 if (!(ret = key->can_certify))
2670 for (subkey = key->subkeys; subkey; subkey = subkey->next)
2671 if ((ret = subkey->can_certify))
2680 /* Print verbose information about a key or certificate to FP. */
2681 static void print_key_info (gpgme_key_t key, FILE * fp)
2684 const char *s = NULL, *s2 = NULL;
2687 char shortbuf[STRING];
2688 unsigned long aval = 0;
2692 gpgme_user_id_t uid = NULL;
2695 setlocale (LC_TIME, Locale);
2697 is_pgp = key->protocol == GPGME_PROTOCOL_OpenPGP;
2699 for (idx = 0, uid = key->uids; uid; idx++, uid = uid->next) {
2704 fputs (idx ? _(" aka ......: ") :_("Name ......: "), fp);
2707 fputs (_("[Invalid]"), fp);
2711 print_utf8 (fp, s, m_strlen(s));
2713 parse_and_print_user_id (fp, s);
2717 if (key->subkeys && (key->subkeys->timestamp > 0)) {
2718 tt = key->subkeys->timestamp;
2720 tm = localtime (&tt);
2721 #ifdef HAVE_LANGINFO_D_T_FMT
2722 strftime (shortbuf, sizeof shortbuf, nl_langinfo (D_T_FMT), tm);
2724 strftime (shortbuf, sizeof shortbuf, "%c", tm);
2726 fprintf (fp, _("Valid From : %s\n"), shortbuf);
2729 if (key->subkeys && (key->subkeys->expires > 0)) {
2730 tt = key->subkeys->expires;
2732 tm = localtime (&tt);
2733 #ifdef HAVE_LANGINFO_D_T_FMT
2734 strftime (shortbuf, sizeof shortbuf, nl_langinfo (D_T_FMT), tm);
2736 strftime (shortbuf, sizeof shortbuf, "%c", tm);
2738 fprintf (fp, _("Valid To ..: %s\n"), shortbuf);
2742 s = gpgme_pubkey_algo_name (key->subkeys->pubkey_algo);
2746 s2 = is_pgp ? "PGP" : "X.509";
2749 aval = key->subkeys->length;
2751 fprintf (fp, _("Key Type ..: %s, %lu bit %s\n"), s2, aval, s);
2753 fprintf (fp, _("Key Usage .: "));
2756 if (key_check_cap (key, KEY_CAP_CAN_ENCRYPT)) {
2757 fprintf (fp, "%s%s", delim, _("encryption"));
2760 if (key_check_cap (key, KEY_CAP_CAN_SIGN)) {
2761 fprintf (fp, "%s%s", delim, _("signing"));
2764 if (key_check_cap (key, KEY_CAP_CAN_CERTIFY)) {
2765 fprintf (fp, "%s%s", delim, _("certification"));
2771 s = key->subkeys->fpr;
2772 fputs (_("Fingerprint: "), fp);
2773 if (is_pgp && m_strlen(s) == 40) {
2774 for (i = 0; *s && s[1] && s[2] && s[3] && s[4]; s += 4, i++) {
2779 putc (is_pgp ? ' ' : ':', fp);
2780 if (is_pgp && i == 4)
2785 for (i = 0; *s && s[1] && s[2]; s += 2, i++) {
2788 putc (is_pgp ? ' ' : ':', fp);
2789 if (is_pgp && i == 7)
2793 fprintf (fp, "%s\n", s);
2796 if (key->issuer_serial) {
2797 s = key->issuer_serial;
2799 fprintf (fp, _("Serial-No .: 0x%s\n"), s);
2802 if (key->issuer_name) {
2803 s = key->issuer_name;
2805 fprintf (fp, _("Issued By .: "));
2806 parse_and_print_user_id (fp, s);
2811 /* For PGP we list all subkeys. */
2813 gpgme_subkey_t subkey = NULL;
2815 for (idx = 1, subkey = key->subkeys; subkey; idx++, subkey = subkey->next) {
2819 if (m_strlen(s) == 16)
2820 s += 8; /* display only the short keyID */
2821 fprintf (fp, _("Subkey ....: 0x%s"), s);
2822 if (subkey->revoked) {
2824 fputs (_("[Revoked]"), fp);
2826 if (subkey->invalid) {
2828 fputs (_("[Invalid]"), fp);
2830 if (subkey->expired) {
2832 fputs (_("[Expired]"), fp);
2834 if (subkey->disabled) {
2836 fputs (_("[Disabled]"), fp);
2840 if (subkey->timestamp > 0) {
2841 tt = subkey->timestamp;
2843 tm = localtime (&tt);
2844 #ifdef HAVE_LANGINFO_D_T_FMT
2845 strftime (shortbuf, sizeof shortbuf, nl_langinfo (D_T_FMT), tm);
2847 strftime (shortbuf, sizeof shortbuf, "%c", tm);
2849 fprintf (fp, _("Valid From : %s\n"), shortbuf);
2852 if (subkey->expires > 0) {
2853 tt = subkey->expires;
2855 tm = localtime (&tt);
2856 #ifdef HAVE_LANGINFO_D_T_FMT
2857 strftime (shortbuf, sizeof shortbuf, nl_langinfo (D_T_FMT), tm);
2859 strftime (shortbuf, sizeof shortbuf, "%c", tm);
2861 fprintf (fp, _("Valid To ..: %s\n"), shortbuf);
2865 s = gpgme_pubkey_algo_name (subkey->pubkey_algo);
2870 aval = subkey->length;
2874 fprintf (fp, _("Key Type ..: %s, %lu bit %s\n"), "PGP", aval, s);
2876 fprintf (fp, _("Key Usage .: "));
2879 if (subkey->can_encrypt) {
2880 fprintf (fp, "%s%s", delim, _("encryption"));
2883 if (subkey->can_sign) {
2884 fprintf (fp, "%s%s", delim, _("signing"));
2887 if (subkey->can_certify) {
2888 fprintf (fp, "%s%s", delim, _("certification"));
2896 setlocale (LC_TIME, "C");
2900 /* Show detailed information about the selected key */
2901 static void verify_key (crypt_key_t * key)
2904 char cmd[LONG_STRING], tempfile[_POSIX_PATH_MAX];
2906 gpgme_ctx_t listctx = NULL;
2908 gpgme_key_t k = NULL;
2911 fp = m_tempfile (tempfile, sizeof(tempfile), NONULL(MCore.tmpdir), NULL);
2913 mutt_perror (_("Can't create temporary file"));
2916 mutt_message _("Collecting data...");
2918 print_key_info (key->kobj, fp);
2920 err = gpgme_new (&listctx);
2922 fprintf (fp, "Internal error: can't create gpgme context: %s\n",
2923 gpgme_strerror (err));
2926 if ((key->flags & KEYFLAG_ISX509))
2927 gpgme_set_protocol (listctx, GPGME_PROTOCOL_CMS);
2931 while ((s = k->chain_id) && k->subkeys && m_strcmp(s, k->subkeys->fpr)) {
2933 err = gpgme_op_keylist_start (listctx, s, 0);
2934 gpgme_key_release (k);
2937 err = gpgme_op_keylist_next (listctx, &k);
2939 fprintf (fp, _("Error finding issuer key: %s\n"), gpgme_strerror (err));
2942 gpgme_op_keylist_end (listctx);
2944 print_key_info (k, fp);
2947 fputs (_("Error: certification chain to long - stopping here\n"), fp);
2953 gpgme_key_release (k);
2954 gpgme_release (listctx);
2956 mutt_clear_error ();
2957 snprintf (cmd, sizeof (cmd), _("Key ID: 0x%s"), crypt_keyid (key));
2958 mutt_do_pager (cmd, tempfile, 0, NULL);
2961 /* Implementation of `findkeys'. */
2963 /* Convert string_list_t into a pattern string suitable to be passed to GPGME.
2964 We need to convert spaces in an item into a '+' and '%' into
2966 static char *list_to_pattern (string_list_t * list)
2974 for (l = list; l; l = l->next) {
2975 for (s = l->data; *s; s++) {
2980 n++; /* delimiter or end of string */
2982 n++; /* make sure to allocate at least one byte */
2983 pattern = p = p_new(char, n);
2984 for (l = list; l; l = l->next) {
2989 for (s = l->data; *s; s++) {
2995 else if (*s == '+') {
3011 /* Return a list of keys which are candidates for the selection.
3012 Select by looking at the HINTS list. */
3013 static crypt_key_t *get_candidates (string_list_t * hints, unsigned int app,
3016 crypt_key_t *db, *k, **kend;
3022 gpgme_user_id_t uid = NULL;
3024 pattern = list_to_pattern (hints);
3028 err = gpgme_new (&ctx);
3030 mutt_error (_("gpgme_new failed: %s"), gpgme_strerror (err));
3038 if ((app & APPLICATION_PGP)) {
3039 /* Its all a mess. That old GPGME expects different things
3040 depending on the protocol. For gpg we don' t need percent
3041 escaped pappert but simple strings passed in an array to the
3042 keylist_ext_start function. */
3047 for (l = hints, n = 0; l; l = l->next) {
3048 if (l->data && *l->data)
3054 patarr = p_new(char *, n + 1);
3055 for (l = hints, n = 0; l; l = l->next) {
3056 if (l->data && *l->data)
3057 patarr[n++] = m_strdup(l->data);
3060 err = gpgme_op_keylist_ext_start (ctx, (const char **) patarr, secret, 0);
3061 for (n = 0; patarr[n]; n++)
3062 p_delete(&patarr[n]);
3065 mutt_error (_("gpgme_op_keylist_start failed: %s"), gpgme_strerror (err));
3066 gpgme_release (ctx);
3071 while (!(err = gpgme_op_keylist_next (ctx, &key))) {
3072 unsigned int flags = 0;
3074 if (key_check_cap (key, KEY_CAP_CAN_ENCRYPT))
3075 flags |= KEYFLAG_CANENCRYPT;
3076 if (key_check_cap (key, KEY_CAP_CAN_SIGN))
3077 flags |= KEYFLAG_CANSIGN;
3079 for (idx = 0, uid = key->uids; uid; idx++, uid = uid->next) {
3080 k = p_new(crypt_key_t, 1);
3089 if (gpg_err_code (err) != GPG_ERR_EOF)
3090 mutt_error (_("gpgme_op_keylist_next failed: %s"), gpgme_strerror (err));
3091 gpgme_op_keylist_end (ctx);
3096 if ((app & APPLICATION_SMIME)) {
3097 /* and now look for x509 certificates */
3098 gpgme_set_protocol (ctx, GPGME_PROTOCOL_CMS);
3099 err = gpgme_op_keylist_start (ctx, pattern, 0);
3101 mutt_error (_("gpgme_op_keylist_start failed: %s"), gpgme_strerror (err));
3102 gpgme_release (ctx);
3107 while (!(err = gpgme_op_keylist_next (ctx, &key))) {
3108 unsigned int flags = KEYFLAG_ISX509;
3110 if (key_check_cap (key, KEY_CAP_CAN_ENCRYPT))
3111 flags |= KEYFLAG_CANENCRYPT;
3112 if (key_check_cap (key, KEY_CAP_CAN_SIGN))
3113 flags |= KEYFLAG_CANSIGN;
3115 for (idx = 0, uid = key->uids; uid; idx++, uid = uid->next) {
3116 k = p_new(crypt_key_t, 1);
3125 if (gpg_err_code (err) != GPG_ERR_EOF)
3126 mutt_error (_("gpgme_op_keylist_next failed: %s"), gpgme_strerror (err));
3127 gpgme_op_keylist_end (ctx);
3130 gpgme_release (ctx);
3135 /* Add the string STR to the list HINTS. This list is later used to
3137 static string_list_t *crypt_add_string_to_hints (string_list_t * hints, const char *str)
3142 if ((scratch = m_strdup(str)) == NULL)
3145 for (t = strtok (scratch, " ,.:\"()<>\n"); t;
3146 t = strtok (NULL, " ,.:\"()<>\n")) {
3147 if (m_strlen(t) > 3)
3148 hints = mutt_add_list(hints, t);
3155 /* Display a menu to select a key from the array KEYS. FORCED_VALID
3156 will be set to true on return if the user did override the the
3158 static crypt_key_t *crypt_select_key (crypt_key_t * keys,
3159 address_t * p, const char *s,
3160 unsigned int app, int *forced_valid)
3163 crypt_key_t **key_table;
3166 char helpstr[STRING], buf[LONG_STRING];
3168 int (*f) (const void *, const void *);
3169 int menu_to_use = 0;
3174 /* build the key table */
3177 for (k = keys; k; k = k->next) {
3178 if (!option (OPTPGPSHOWUNUSABLE) && (k->flags & KEYFLAG_CANTUSE)) {
3185 p_realloc(&key_table, keymax);
3191 if (!i && unusable) {
3192 mutt_error _("All matching keys are marked expired/revoked.");
3198 switch (PgpSortKeys & SORT_MASK) {
3200 f = crypt_compare_date;
3203 f = crypt_compare_keyid;
3206 f = crypt_compare_address;
3210 f = crypt_compare_trust;
3213 qsort (key_table, i, sizeof (crypt_key_t *), f);
3215 if (app & APPLICATION_PGP)
3216 menu_to_use = MENU_KEY_SELECT_PGP;
3217 else if (app & APPLICATION_SMIME)
3218 menu_to_use = MENU_KEY_SELECT_SMIME;
3221 mutt_make_help (buf, sizeof (buf), _("Exit "), menu_to_use, OP_EXIT);
3222 m_strcat(helpstr, sizeof(helpstr), buf);
3223 mutt_make_help (buf, sizeof (buf), _("Select "), menu_to_use,
3224 OP_GENERIC_SELECT_ENTRY);
3225 m_strcat(helpstr, sizeof(helpstr), buf);
3226 mutt_make_help (buf, sizeof (buf), _("Check key "),
3227 menu_to_use, OP_VERIFY_KEY);
3228 m_strcat(helpstr, sizeof(helpstr), buf);
3229 mutt_make_help (buf, sizeof (buf), _("Help"), menu_to_use, OP_HELP);
3230 m_strcat(helpstr, sizeof(helpstr), buf);
3232 menu = mutt_new_menu ();
3234 menu->make_entry = crypt_entry;
3235 menu->menu = menu_to_use;
3236 menu->help = helpstr;
3237 menu->data = key_table;
3242 if ((app & APPLICATION_PGP) && (app & APPLICATION_SMIME))
3243 ts = _("PGP and S/MIME keys matching");
3244 else if ((app & APPLICATION_PGP))
3245 ts = _("PGP keys matching");
3246 else if ((app & APPLICATION_SMIME))
3247 ts = _("S/MIME keys matching");
3249 ts = _("keys matching");
3252 snprintf (buf, sizeof (buf), _("%s <%s>."), ts, p->mailbox);
3254 snprintf (buf, sizeof (buf), _("%s \"%s\"."), ts, s);
3258 mutt_clear_error ();
3262 switch (mutt_menuLoop (menu)) {
3264 verify_key (key_table[menu->current]);
3265 menu->redraw = REDRAW_FULL;
3269 mutt_message ("%s", key_table[menu->current]->uid);
3272 case OP_GENERIC_SELECT_ENTRY:
3273 /* FIXME make error reporting more verbose - this should be
3274 easy because gpgme provides more information */
3275 if (option (OPTPGPCHECKTRUST)) {
3276 if (!crypt_key_is_valid (key_table[menu->current])) {
3277 mutt_error _("This key can't be used: "
3278 "expired/disabled/revoked.");
3283 if (option (OPTPGPCHECKTRUST) &&
3284 (!crypt_id_is_valid (key_table[menu->current])
3285 || !crypt_id_is_strong (key_table[menu->current]))) {
3287 char buff[LONG_STRING];
3289 if (key_table[menu->current]->flags & KEYFLAG_CANTUSE)
3290 s = N_("ID is expired/disabled/revoked.");
3292 gpgme_validity_t val = GPGME_VALIDITY_UNKNOWN;
3293 gpgme_user_id_t uid = NULL;
3298 uid = key_table[menu->current]->kobj->uids;
3299 for (j = 0; (j < key_table[menu->current]->idx) && uid;
3300 j++, uid = uid->next);
3302 val = uid->validity;
3305 case GPGME_VALIDITY_UNKNOWN:
3306 case GPGME_VALIDITY_UNDEFINED:
3307 warn_s = N_("ID has undefined validity.");
3309 case GPGME_VALIDITY_NEVER:
3310 warn_s = N_("ID is not valid.");
3312 case GPGME_VALIDITY_MARGINAL:
3313 warn_s = N_("ID is only marginally valid.");
3315 case GPGME_VALIDITY_FULL:
3316 case GPGME_VALIDITY_ULTIMATE:
3320 snprintf (buff, sizeof (buff),
3321 _("%s Do you really want to use the key?"), _(warn_s));
3323 if (mutt_yesorno (buff, 0) != 1) {
3324 mutt_clear_error ();
3331 k = crypt_copy_key (key_table[menu->current]);
3342 mutt_menuDestroy (&menu);
3343 p_delete(&key_table);
3345 set_option (OPTNEEDREDRAW);
3350 static crypt_key_t *crypt_getkeybyaddr (address_t * a, short abilities,
3351 unsigned int app, int *forced_valid)
3354 string_list_t *hints = NULL;
3359 int this_key_has_strong;
3360 int this_key_has_weak;
3361 int this_key_has_invalid;
3364 crypt_key_t *keys, *k;
3365 crypt_key_t *the_valid_key = NULL;
3366 crypt_key_t *matches = NULL;
3367 crypt_key_t **matches_endp = &matches;
3371 if (a && a->mailbox)
3372 hints = crypt_add_string_to_hints (hints, a->mailbox);
3373 if (a && a->personal)
3374 hints = crypt_add_string_to_hints (hints, a->personal);
3376 mutt_message (_("Looking for keys matching \"%s\"..."), a->mailbox);
3377 keys = get_candidates (hints, app, (abilities & KEYFLAG_CANSIGN));
3379 string_list_wipe(&hints);
3384 for (k = keys; k; k = k->next) {
3385 if (abilities && !(k->flags & abilities)) {
3389 this_key_has_weak = 0; /* weak but valid match */
3390 this_key_has_invalid = 0; /* invalid match */
3391 this_key_has_strong = 0; /* strong and valid match */
3392 match = 0; /* any match */
3394 r = rfc822_parse_adrlist (NULL, k->uid);
3395 for (p = r; p; p = p->next) {
3396 int validity = crypt_id_matches_addr (a, p, k);
3398 if (validity & CRYPT_KV_MATCH) /* something matches */
3401 /* is this key a strong candidate? */
3402 if ((validity & CRYPT_KV_VALID)
3403 && (validity & CRYPT_KV_STRONGID)
3404 && (validity & CRYPT_KV_ADDR)) {
3405 if (the_valid_key && the_valid_key != k)
3408 this_key_has_strong = 1;
3410 else if ((validity & CRYPT_KV_MATCH)
3411 && !(validity & CRYPT_KV_VALID))
3412 this_key_has_invalid = 1;
3413 else if ((validity & CRYPT_KV_MATCH)
3414 && (!(validity & CRYPT_KV_STRONGID)
3415 || !(validity & CRYPT_KV_ADDR)))
3416 this_key_has_weak = 1;
3418 address_list_wipe(&r);
3423 if (!this_key_has_strong && this_key_has_invalid)
3425 if (!this_key_has_strong && this_key_has_weak)
3428 *matches_endp = tmp = crypt_copy_key (k);
3429 matches_endp = &tmp->next;
3430 the_valid_key = tmp;
3434 crypt_free_key (&keys);
3437 if (the_valid_key && !multi && !weak
3438 && !(invalid && option (OPTPGPSHOWUNUSABLE))) {
3440 * There was precisely one strong match on a valid ID, there
3441 * were no valid keys with weak matches, and we aren't
3442 * interested in seeing invalid keys.
3444 * Proceed without asking the user.
3446 k = crypt_copy_key (the_valid_key);
3450 * Else: Ask the user.
3452 k = crypt_select_key (matches, a, NULL, app, forced_valid);
3454 crypt_free_key (&matches);
3463 static crypt_key_t *crypt_getkeybystr (const char *p, short abilities,
3464 unsigned int app, int *forced_valid)
3466 string_list_t *hints = NULL;
3468 crypt_key_t *matches = NULL;
3469 crypt_key_t **matches_endp = &matches;
3473 mutt_message (_("Looking for keys matching \"%s\"..."), p);
3477 hints = crypt_add_string_to_hints (hints, p);
3478 keys = get_candidates (hints, app, (abilities & KEYFLAG_CANSIGN));
3479 string_list_wipe(&hints);
3484 for (k = keys; k; k = k->next) {
3485 if (abilities && !(k->flags & abilities))
3490 if (!*p || !m_strcasecmp(p, crypt_keyid (k))
3491 || (!m_strncasecmp(p, "0x", 2)
3492 && !m_strcasecmp(p + 2, crypt_keyid (k)))
3493 || (option (OPTPGPLONGIDS)
3494 && !m_strncasecmp(p, "0x", 2)
3495 && !m_strcasecmp(p + 2, crypt_keyid (k) + 8))
3496 || m_stristr(k->uid, p)) {
3499 *matches_endp = tmp = crypt_copy_key (k);
3500 matches_endp = &tmp->next;
3504 crypt_free_key (&keys);
3507 k = crypt_select_key (matches, NULL, p, app, forced_valid);
3508 crypt_free_key (&matches);
3515 /* Display TAG as a prompt to ask for a key. If WHATFOR is not null
3516 use it as default and store it under that label as the next
3517 default. ABILITIES describe the required key abilities (sign,
3518 encrypt) and APP the type of the requested key; ether S/MIME or
3519 PGP. Return a copy of the key or NULL if not found. */
3520 static crypt_key_t *crypt_ask_for_key (char *tag,
3523 unsigned int app, int *forced_valid)
3527 struct crypt_cache *l = NULL;
3531 forced_valid = &dummy;
3533 mutt_clear_error ();
3539 for (l = id_defaults; l; l = l->next)
3540 if (!m_strcasecmp(whatfor, l->what)) {
3541 m_strcpy(resp, sizeof(resp), NONULL(l->dflt));
3549 if (mutt_get_field (tag, resp, sizeof (resp), M_CLEAR) != 0)
3554 m_strreplace(&l->dflt, resp);
3556 l = p_new(struct crypt_cache, 1);
3557 l->next = id_defaults;
3559 l->what = m_strdup(whatfor);
3560 l->dflt = m_strdup(resp);
3564 if ((key = crypt_getkeybystr (resp, abilities, app, forced_valid)))
3572 /* This routine attempts to find the keyids of the recipients of a
3573 message. It returns NULL if any of the keys can not be found. */
3574 static char *find_keys (address_t * to, address_t * cc, address_t * bcc,
3577 char *keylist = NULL, *t;
3579 ssize_t keylist_size = 0;
3580 ssize_t keylist_used = 0;
3581 address_t *tmp = NULL, *addr = NULL;
3582 address_t **last = &tmp;
3585 crypt_key_t *k_info, *key;
3586 const char *fqdn = mutt_fqdn (1);
3589 *r_application = APPLICATION_PGP | APPLICATION_SMIME;
3592 for (i = 0; i < 3; i++) {
3607 *last = address_list_dup (p);
3609 last = &((*last)->next);
3612 rfc822_qualify(tmp, fqdn);
3613 address_list_uniq(tmp);
3615 for (p = tmp; p; p = p->next) {
3616 char buf[LONG_STRING];
3617 int forced_valid = 0;
3622 if ((keyID = mutt_crypt_hook (p)) != NULL) {
3625 snprintf (buf, sizeof (buf), _("Use keyID = \"%s\" for %s?"),
3627 if ((r = mutt_yesorno (buf, M_YES)) == M_YES) {
3628 /* check for e-mail address */
3629 if ((t = strchr (keyID, '@')) &&
3630 (addr = rfc822_parse_adrlist (NULL, keyID))) {
3631 rfc822_qualify(addr, fqdn);
3635 k_info = crypt_getkeybystr (keyID, KEYFLAG_CANENCRYPT,
3636 app, &forced_valid);
3641 address_list_wipe(&tmp);
3642 address_list_wipe(&addr);
3648 && (k_info = crypt_getkeybyaddr (q, KEYFLAG_CANENCRYPT,
3649 app, &forced_valid)) == NULL) {
3650 snprintf (buf, sizeof (buf), _("Enter keyID for %s: "), q->mailbox);
3652 if ((key = crypt_ask_for_key (buf, q->mailbox, KEYFLAG_CANENCRYPT,
3654 &forced_valid)) == NULL) {
3656 address_list_wipe(&tmp);
3657 address_list_wipe(&addr);
3665 const char *s = crypt_fpr (key);
3667 keylist_size += m_strlen(s) + 4 + 1;
3668 p_realloc(&keylist, keylist_size);
3669 sprintf (keylist + keylist_used, "%s0x%s%s",
3670 keylist_used ? " " : "", s, forced_valid ? "!" : "");
3672 keylist_used = m_strlen(keylist);
3674 crypt_free_key (&key);
3675 address_list_wipe(&addr);
3677 address_list_wipe(&tmp);
3681 int crypt_get_keys (HEADER * msg, char **keylist)
3683 /* Do a quick check to make sure that we can find all of the encryption
3684 * keys if the user has requested this service.
3689 if (msg->security & ENCRYPT) {
3690 if (msg->security & APPLICATION_PGP) {
3691 set_option(OPTPGPCHECKTRUST);
3692 *keylist = find_keys(msg->env->to, msg->env->cc, msg->env->bcc,
3694 unset_option(OPTPGPCHECKTRUST);
3699 if (msg->security & APPLICATION_SMIME) {
3700 *keylist = find_keys(msg->env->to, msg->env->cc, msg->env->bcc,
3711 int crypt_send_menu (HEADER * msg, int *redraw, int is_smime)
3714 char input_signas[STRING];
3717 if (msg->security & APPLICATION_PGP)
3719 else if (msg->security & APPLICATION_SMIME)
3724 mutt_multi_choice (_
3725 ("S/MIME (e)ncrypt, (s)ign, sign (a)s, (b)oth, (p)gp or (c)lear?"),
3729 mutt_multi_choice (_
3730 ("PGP (e)ncrypt, (s)ign, sign (a)s, (b)oth, s/(m)ime or (c)lear?"),
3734 case 1: /* (e)ncrypt */
3735 msg->security |= (is_smime ? SMIMEENCRYPT : PGPENCRYPT);
3736 msg->security &= ~(is_smime ? SMIMESIGN : PGPSIGN);
3739 case 2: /* (s)ign */
3740 msg->security |= (is_smime ? SMIMESIGN : PGPSIGN);
3741 msg->security &= ~(is_smime ? SMIMEENCRYPT : PGPENCRYPT);
3744 case 3: /* sign (a)s */
3745 if ((p = crypt_ask_for_key (_("Sign as: "), NULL, KEYFLAG_CANSIGN,
3746 is_smime ? APPLICATION_SMIME :
3747 APPLICATION_PGP, NULL))) {
3748 snprintf (input_signas, sizeof (input_signas), "0x%s", crypt_keyid (p));
3749 m_strreplace(is_smime ? &SmimeDefaultKey : &PgpSignAs,
3751 crypt_free_key (&p);
3753 msg->security |= (is_smime ? SMIMESIGN : PGPSIGN);
3755 *redraw = REDRAW_FULL;
3758 case 4: /* (b)oth */
3760 (is_smime ? (SMIMEENCRYPT | SMIMESIGN) : (PGPENCRYPT | PGPSIGN));
3763 case 5: /* (p)gp or s/(m)ime */
3764 is_smime = !is_smime;
3767 case 6: /* (c)lear */
3768 return msg->security = 0;
3772 msg->security &= ~APPLICATION_PGP;
3773 msg->security |= APPLICATION_SMIME;
3775 msg->security &= ~APPLICATION_SMIME;
3776 msg->security |= APPLICATION_PGP;
3779 return msg->security;
3782 int crypt_smime_verify_sender (HEADER * h)
3784 address_t *sender = NULL;
3785 unsigned int ret = 1;
3788 h->env->from = mutt_expand_aliases (h->env->from);
3789 sender = h->env->from;
3791 else if (h->env->sender) {
3792 h->env->sender = mutt_expand_aliases (h->env->sender);
3793 sender = h->env->sender;
3797 if (signature_key) {
3798 gpgme_key_t key = signature_key;
3799 gpgme_user_id_t uid = NULL;
3800 int sender_length = 0;
3803 sender_length = m_strlen(sender->mailbox);
3804 for (uid = key->uids; uid && ret; uid = uid->next) {
3805 uid_length = m_strlen(uid->email);
3806 if (1 && (uid->email[0] == '<')
3807 && (uid->email[uid_length - 1] == '>')
3808 && (uid_length == sender_length + 2)
3809 && (!m_strncmp (uid->email + 1, sender->mailbox, sender_length)))
3814 mutt_any_key_to_continue ("Failed to verify sender");
3817 mutt_any_key_to_continue ("Failed to figure out sender");
3819 if (signature_key) {
3820 gpgme_key_release (signature_key);
3821 signature_key = NULL;
3827 void crypt_invoke_import(FILE *stream, int smime)
3829 gpgme_ctx_t ctx = create_gpgme_context(smime);
3833 err = gpgme_data_new_from_stream(&data, stream);
3835 mutt_error (_("error allocating data object: %s\n"), gpgme_strerror (err));
3840 err = gpgme_op_import(ctx, data);
3842 mutt_error(_("error importing gpg data: %s\n"), gpgme_strerror(err));
3843 gpgme_data_release(data);
3848 gpgme_data_release(data);
3853 static void pgp_extract_keys_from_attachment(FILE * fp, BODY * top)
3856 FILE *tmpfp = tmpfile();
3858 if (tmpfp == NULL) {
3859 mutt_perror (_("Can't create temporary file"));
3866 mutt_body_handler(top, &s);
3869 crypt_invoke_import(tmpfp, 0);
3873 void crypt_pgp_extract_keys_from_attachment_list(FILE * fp, int tag, BODY * top)
3876 set_option (OPTDONTHANDLEPGPKEYS);
3878 for (; top; top = top->next) {
3879 if (!tag || top->tagged)
3880 pgp_extract_keys_from_attachment (fp, top);
3886 unset_option (OPTDONTHANDLEPGPKEYS);
3892 /* fixme: needs documentation. */
3893 void crypt_pgp_invoke_getkeys (address_t * addr)
3897 /* Generate a PGP public key attachment. */
3898 BODY *crypt_pgp_make_key_attachment (char *tempf)
3905 /* fixme: Needs documentation. */
3906 void crypt_smime_getkeys (ENVELOPE * env)