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 static int verify_one (BODY * sigbdy, STATE * s,
1201 const char *tempfile, int is_smime)
1207 gpgme_data_t signature, message;
1209 signature = file_to_data_object (s->fpin, sigbdy->offset, sigbdy->length);
1213 /* We need to tell gpgme about the encoding because the backend can't
1214 auto-detect plain base-64 encoding which is used by S/MIME. */
1216 gpgme_data_set_encoding (signature, GPGME_DATA_ENCODING_BASE64);
1218 err = gpgme_data_new_from_file (&message, tempfile, 1);
1220 gpgme_data_release (signature);
1221 mutt_error (_("error allocating data object: %s\n"), gpgme_strerror (err));
1224 ctx = create_gpgme_context (is_smime);
1226 /* Note: We don't need a current time output because GPGME avoids
1227 such an attack by separating the meta information from the
1229 state_attach_puts (_("[-- Begin signature information --]\n"), s);
1231 err = gpgme_op_verify (ctx, signature, message, NULL);
1232 mutt_need_hard_redraw ();
1236 snprintf (buf, sizeof (buf) - 1,
1237 _("Error: verification failed: %s\n"), gpgme_strerror (err));
1238 state_attach_puts (buf, s);
1240 else { /* Verification succeeded, see what the result is. */
1244 if (signature_key) {
1245 gpgme_key_release (signature_key);
1246 signature_key = NULL;
1249 for (idx = 0; (res = show_one_sig_status (ctx, idx, s)) != -1; idx++) {
1260 gpgme_verify_result_t result;
1261 gpgme_sig_notation_t notation;
1262 gpgme_signature_t sig;
1264 result = gpgme_op_verify_result (ctx);
1266 for (sig = result->signatures; sig; sig = sig->next) {
1267 if (sig->notations) {
1268 state_attach_puts ("*** Begin Notation (signature by: ", s);
1269 state_attach_puts (sig->fpr, s);
1270 state_attach_puts (") ***\n", s);
1271 for (notation = sig->notations; notation; notation = notation->next)
1273 if (notation->name) {
1274 state_attach_puts (notation->name, s);
1275 state_attach_puts ("=", s);
1277 if (notation->value) {
1278 state_attach_puts (notation->value, s);
1279 if (!(*notation->value
1280 && (notation->value[m_strlen(notation->value) - 1] ==
1282 state_attach_puts ("\n", s);
1285 state_attach_puts ("*** End Notation ***\n", s);
1291 gpgme_release (ctx);
1293 state_attach_puts (_("[-- End signature information --]\n\n"), s);
1295 return badsig ? 1 : anywarn ? 2 : 0;
1298 int crypt_pgp_verify_one (BODY * sigbdy, STATE * s, const char *tempfile)
1300 return verify_one (sigbdy, s, tempfile, 0);
1303 int crypt_smime_verify_one (BODY * sigbdy, STATE * s, const char *tempfile)
1305 return verify_one (sigbdy, s, tempfile, 1);
1309 * Implementation of `decrypt_part'.
1312 /* Decrypt a PGP or SMIME message (depending on the boolean flag
1313 IS_SMIME) with body A described further by state S. Write
1314 plaintext out to file FPOUT and return a new body. For PGP returns
1315 a flag in R_IS_SIGNED to indicate whether this is a combined
1316 encrypted and signed message, for S/MIME it returns true when it is
1317 not a encrypted but a signed message. */
1318 static BODY *decrypt_part (BODY * a, STATE * s, FILE * fpout, int is_smime,
1325 gpgme_data_t ciphertext, plaintext;
1326 int maybe_signed = 0;
1333 ctx = create_gpgme_context (is_smime);
1336 /* Make a data object from the body, create context etc. */
1337 ciphertext = file_to_data_object (s->fpin, a->offset, a->length);
1340 plaintext = create_gpgme_data ();
1342 /* Do the decryption or the verification in case of the S/MIME hack. */
1343 if ((!is_smime) || maybe_signed) {
1345 err = gpgme_op_decrypt_verify (ctx, ciphertext, plaintext);
1346 else if (maybe_signed)
1347 err = gpgme_op_verify (ctx, ciphertext, NULL, plaintext);
1350 /* Check wether signatures have been verified. */
1351 gpgme_verify_result_t verify_result = gpgme_op_verify_result (ctx);
1353 if (verify_result->signatures)
1358 err = gpgme_op_decrypt (ctx, ciphertext, plaintext);
1359 gpgme_data_release (ciphertext);
1361 if (is_smime && !maybe_signed && gpg_err_code (err) == GPG_ERR_NO_DATA) {
1362 /* Check whether this might be a signed message despite what
1363 the mime header told us. Retry then. gpgsm returns the
1364 error information "unsupported Algorithm '?'" but gpgme
1365 will not store this unknown algorithm, thus we test that
1366 it has not been set. */
1367 gpgme_decrypt_result_t result;
1369 result = gpgme_op_decrypt_result (ctx);
1370 if (!result->unsupported_algorithm) {
1372 gpgme_data_release (plaintext);
1376 mutt_need_hard_redraw ();
1377 if ((s->flags & M_DISPLAY)) {
1380 snprintf (buf, sizeof (buf) - 1,
1381 _("[-- Error: decryption failed: %s --]\n\n"),
1382 gpgme_strerror (err));
1383 state_attach_puts (buf, s);
1385 gpgme_data_release (plaintext);
1386 gpgme_release (ctx);
1389 mutt_need_hard_redraw ();
1391 /* Read the output from GPGME, and make sure to change CRLF to LF,
1392 otherwise read_mime_header has a hard time parsing the message. */
1393 if (data_object_to_stream (plaintext, fpout)) {
1394 gpgme_data_release (plaintext);
1395 gpgme_release (ctx);
1398 gpgme_data_release (plaintext);
1400 a->is_signed_data = 0;
1406 a->is_signed_data = 1;
1408 *r_is_signed = -1; /* A signature exists. */
1410 if ((s->flags & M_DISPLAY))
1411 state_attach_puts (_("[-- Begin signature " "information --]\n"), s);
1412 for (idx = 0; (res = show_one_sig_status (ctx, idx, s)) != -1; idx++) {
1418 if (!anybad && idx && r_is_signed && *r_is_signed)
1419 *r_is_signed = anywarn ? 2 : 1; /* Good signature. */
1421 if ((s->flags & M_DISPLAY))
1422 state_attach_puts (_("[-- End signature " "information --]\n\n"), s);
1424 gpgme_release (ctx);
1429 tattach = mutt_read_mime_header (fpout, 0);
1432 * Need to set the length of this body part.
1434 fstat (fileno (fpout), &info);
1435 tattach->length = info.st_size - tattach->offset;
1437 tattach->warnsig = anywarn;
1439 /* See if we need to recurse on this MIME part. */
1440 mutt_parse_part (fpout, tattach);
1446 /* Decrypt a PGP/MIME message in FPIN and B and return a new body and
1447 the stream in CUR and FPOUT. Returns 0 on success. */
1448 int crypt_pgp_decrypt_mime (FILE * fpin, FILE ** fpout, BODY * b, BODY ** cur)
1450 char tempfile[_POSIX_PATH_MAX];
1452 BODY *first_part = b;
1455 first_part->goodsig = 0;
1456 first_part->warnsig = 0;
1458 if (!mutt_is_multipart_encrypted (b))
1461 if (!b->parts || !b->parts->next)
1468 *fpout = m_tempfile(tempfile, sizeof(tempfile), NONULL(MCore.tmpdir), NULL);
1470 mutt_perror (_("Can't create temporary file"));
1475 *cur = decrypt_part (b, &s, *fpout, 0, &is_signed);
1478 first_part->goodsig = 1;
1480 return *cur ? 0 : -1;
1484 /* Decrypt a S/MIME message in FPIN and B and return a new body and
1485 the stream in CUR and FPOUT. Returns 0 on success. */
1486 int crypt_smime_decrypt_mime (FILE * fpin, FILE ** fpout, BODY * b,
1489 char tempfile[_POSIX_PATH_MAX];
1493 long saved_b_offset;
1494 ssize_t saved_b_length;
1497 if (!mutt_is_application_smime (b))
1503 /* Decode the body - we need to pass binary CMS to the
1504 backend. The backend allows for Base64 encoded data but it does
1505 not allow for QP which I have seen in some messages. So better
1507 saved_b_type = b->type;
1508 saved_b_offset = b->offset;
1509 saved_b_length = b->length;
1512 fseeko (s.fpin, b->offset, 0);
1513 tmpfp = m_tempfile (tempfile, sizeof(tempfile), NONULL(MCore.tmpdir), NULL);
1515 mutt_perror (_("Can't create temporary file"));
1518 mutt_unlink (tempfile);
1521 mutt_decode_attachment (b, &s);
1523 b->length = ftello (s.fpout);
1530 *fpout = m_tempfile(tempfile, sizeof(tempfile), NONULL(MCore.tmpdir), NULL);
1532 mutt_perror (_("Can't create temporary file"));
1535 mutt_unlink (tempfile);
1537 *cur = decrypt_part (b, &s, *fpout, 1, &is_signed);
1539 (*cur)->goodsig = is_signed > 0;
1540 b->type = saved_b_type;
1541 b->length = saved_b_length;
1542 b->offset = saved_b_offset;
1545 if (*cur && !is_signed && !(*cur)->parts
1546 && mutt_is_application_smime (*cur)) {
1547 /* Assume that this is a opaque signed s/mime message. This is
1548 an ugly way of doing it but we have anyway a problem with
1549 arbitrary encoded S/MIME messages: Only the outer part may be
1550 encrypted. The entire mime parsing should be revamped,
1551 probably by keeping the temportary files so that we don't
1552 need to decrypt them all the time. Inner parts of an
1553 encrypted part can then pint into this file and tehre won't
1554 never be a need to decrypt again. This needs a partial
1555 rewrite of the MIME engine. */
1559 saved_b_type = bb->type;
1560 saved_b_offset = bb->offset;
1561 saved_b_length = bb->length;
1564 fseeko (s.fpin, bb->offset, 0);
1565 tmpfp = m_tempfile (tempfile, sizeof(tempfile), NONULL(MCore.tmpdir), NULL);
1567 mutt_perror (_("Can't create temporary file"));
1570 mutt_unlink (tempfile);
1573 mutt_decode_attachment (bb, &s);
1575 bb->length = ftello (s.fpout);
1583 *fpout = m_tempfile(tempfile, sizeof(tempfile), NONULL(MCore.tmpdir), NULL);
1585 mutt_perror (_("Can't create temporary file"));
1588 mutt_unlink (tempfile);
1590 tmp_b = decrypt_part (bb, &s, *fpout, 1, &is_signed);
1592 tmp_b->goodsig = is_signed > 0;
1593 bb->type = saved_b_type;
1594 bb->length = saved_b_length;
1595 bb->offset = saved_b_offset;
1598 body_list_wipe(cur);
1601 return *cur ? 0 : -1;
1606 * Implementation of `pgp_check_traditional'.
1609 static int pgp_check_traditional_one_body (FILE * fp, BODY * b,
1612 char tempfile[_POSIX_PATH_MAX];
1613 char buf[HUGE_STRING];
1620 if (b->type != TYPETEXT)
1623 if (tagged_only && !b->tagged)
1626 tempfd = m_tempfd(tempfile, sizeof(tempfile), NONULL(MCore.tmpdir), NULL);
1627 if (mutt_decode_save_attachment (fp, b, tempfd, 0) != 0) {
1632 if ((tfp = fopen(tempfile, "r")) == NULL) {
1637 while (fgets (buf, sizeof (buf), tfp)) {
1638 if (!m_strncmp("-----BEGIN PGP ", buf, 15)) {
1639 if (!m_strcmp("MESSAGE-----\n", buf + 15))
1641 else if (!m_strcmp("SIGNED MESSAGE-----\n", buf + 15))
1651 /* fix the content type */
1653 parameter_setval(&b->parameter, "format", "fixed");
1654 parameter_setval(&b->parameter, "x-action",
1655 enc ? "pgp-encrypted" : "pgp-signed");
1659 int crypt_pgp_check_traditional (FILE * fp, BODY * b, int tagged_only)
1664 for (; b; b = b->next) {
1665 if (is_multipart (b))
1666 rv = (crypt_pgp_check_traditional (fp, b->parts, tagged_only) || rv);
1667 else if (b->type == TYPETEXT) {
1668 if ((r = mutt_is_application_pgp (b)))
1671 rv = (pgp_check_traditional_one_body (fp, b, tagged_only) || rv);
1678 /* Implementation of `application_handler'. */
1681 Copy a clearsigned message, and strip the signature and PGP's
1684 XXX - charset handling: We assume that it is safe to do
1685 character set decoding first, dash decoding second here, while
1686 we do it the other way around in the main handler.
1688 (Note that we aren't worse than Outlook & Cie in this, and also
1689 note that we can successfully handle anything produced by any
1690 existing versions of mutt.) */
1692 static void copy_clearsigned (gpgme_data_t data, STATE * s, char *charset)
1694 char buf[HUGE_STRING];
1695 short complete, armor_header;
1700 fname = data_object_to_tempfile (data, &fp);
1706 fc = fgetconv_open (fp, charset, MCharset.charset, M_ICONV_HOOK_FROM);
1708 for (complete = 1, armor_header = 1;
1709 fgetconvs (buf, sizeof (buf), fc) != NULL;
1710 complete = strchr (buf, '\n') != NULL) {
1713 state_puts (buf, s);
1717 if (!m_strcmp(buf, "-----BEGIN PGP SIGNATURE-----\n"))
1727 state_puts (s->prefix, s);
1729 if (buf[0] == '-' && buf[1] == ' ')
1730 state_puts (buf + 2, s);
1732 state_puts (buf, s);
1735 fgetconv_close (&fc);
1740 /* Support for classic_application/pgp */
1741 int crypt_pgp_application_pgp_handler (BODY * m, STATE * s)
1743 int needpass = -1, pgp_keyblock = 0;
1747 off_t last_pos, offset;
1748 char buf[HUGE_STRING];
1749 FILE *pgpout = NULL;
1751 gpgme_error_t err = 0;
1752 gpgme_data_t armored_data = NULL;
1754 short maybe_goodsig = 1;
1755 short have_any_sigs = 0;
1757 char body_charset[STRING]; /* Only used for clearsigned messages. */
1759 /* For clearsigned messages we won't be able to get a character set
1760 but we know that this may only be text thus we assume Latin-1
1762 if (!mutt_get_body_charset (body_charset, sizeof (body_charset), m))
1763 m_strcpy(body_charset, sizeof(body_charset), "iso-8859-1");
1765 fseeko (s->fpin, m->offset, 0);
1766 last_pos = m->offset;
1768 for (bytes = m->length; bytes > 0;) {
1769 if (fgets (buf, sizeof (buf), s->fpin) == NULL)
1772 offset = ftello (s->fpin);
1773 bytes -= (offset - last_pos); /* don't rely on m_strlen(buf) */
1776 if (!m_strncmp("-----BEGIN PGP ", buf, 15)) {
1778 start_pos = last_pos;
1780 if (!m_strcmp("MESSAGE-----\n", buf + 15))
1782 else if (!m_strcmp("SIGNED MESSAGE-----\n", buf + 15)) {
1786 else if (!option (OPTDONTHANDLEPGPKEYS) &&
1787 !m_strcmp("PUBLIC KEY BLOCK-----\n", buf + 15)) {
1792 /* XXX - we may wish to recode here */
1794 state_puts (s->prefix, s);
1795 state_puts (buf, s);
1799 have_any_sigs = (have_any_sigs || (clearsign && (s->flags & M_VERIFY)));
1801 /* Copy PGP material to an data container */
1802 armored_data = create_gpgme_data ();
1803 gpgme_data_write (armored_data, buf, m_strlen(buf));
1804 while (bytes > 0 && fgets (buf, sizeof (buf) - 1, s->fpin) != NULL) {
1805 offset = ftello (s->fpin);
1806 bytes -= (offset - last_pos); /* don't rely on m_strlen(buf) */
1809 gpgme_data_write (armored_data, buf, m_strlen(buf));
1811 if ((needpass && !m_strcmp("-----END PGP MESSAGE-----\n", buf))
1813 && (!m_strcmp("-----END PGP SIGNATURE-----\n", buf)
1814 || !m_strcmp("-----END PGP PUBLIC KEY BLOCK-----\n",
1819 /* Invoke PGP if needed */
1820 if (!clearsign || (s->flags & M_VERIFY)) {
1821 unsigned int sig_stat = 0;
1822 gpgme_data_t plaintext;
1825 plaintext = create_gpgme_data ();
1826 ctx = create_gpgme_context (0);
1829 err = gpgme_op_verify (ctx, armored_data, NULL, plaintext);
1831 err = gpgme_op_decrypt_verify (ctx, armored_data, plaintext);
1832 if (gpg_err_code (err) == GPG_ERR_NO_DATA) {
1833 /* Decrypt verify can't handle signed only messages. */
1834 err = (gpgme_data_seek (armored_data, 0, SEEK_SET) == -1)
1835 ? gpgme_error_from_errno (errno) : 0;
1836 /* Must release plaintext so that we supply an
1837 uninitialized object. */
1838 gpgme_data_release (plaintext);
1839 plaintext = create_gpgme_data ();
1840 err = gpgme_op_verify (ctx, armored_data, NULL, plaintext);
1847 snprintf (errbuf, sizeof (errbuf) - 1,
1848 _("Error: decryption/verification failed: %s\n"),
1849 gpgme_strerror (err));
1850 state_attach_puts (errbuf, s);
1852 else { /* Decryption/Verification succeeded */
1856 /* Check wether signatures have been verified. */
1857 gpgme_verify_result_t verify_result;
1859 verify_result = gpgme_op_verify_result (ctx);
1860 if (verify_result->signatures)
1866 if ((s->flags & M_DISPLAY) && sig_stat) {
1871 state_attach_puts (_("[-- Begin signature "
1872 "information --]\n"), s);
1875 (res = show_one_sig_status (ctx, idx, s)) != -1; idx++) {
1884 state_attach_puts (_("[-- End signature "
1885 "information --]\n\n"), s);
1888 tmpfname = data_object_to_tempfile (plaintext, &pgpout);
1891 state_attach_puts (_("Error: copy data failed\n"), s);
1895 p_delete(&tmpfname);
1898 gpgme_release (ctx);
1902 * Now, copy cleartext to the screen. NOTE - we expect that PGP
1903 * outputs utf-8 cleartext. This may not always be true, but it
1904 * seems to be a reasonable guess.
1907 if (s->flags & M_DISPLAY) {
1909 state_attach_puts (_("[-- BEGIN PGP MESSAGE --]\n\n"), s);
1910 else if (pgp_keyblock)
1911 state_attach_puts (_("[-- BEGIN PGP PUBLIC KEY BLOCK --]\n"), s);
1913 state_attach_puts (_("[-- BEGIN PGP SIGNED MESSAGE --]\n\n"), s);
1917 copy_clearsigned (armored_data, s, body_charset);
1924 fc = fgetconv_open (pgpout, "utf-8", MCharset.charset, 0);
1925 while ((c = fgetconv (fc)) != EOF) {
1927 if (c == '\n' && s->prefix)
1928 state_puts (s->prefix, s);
1930 fgetconv_close (&fc);
1933 if (s->flags & M_DISPLAY) {
1934 state_putc ('\n', s);
1936 state_attach_puts (_("[-- END PGP MESSAGE --]\n"), s);
1937 else if (pgp_keyblock)
1938 state_attach_puts (_("[-- END PGP PUBLIC KEY BLOCK --]\n"), s);
1940 state_attach_puts (_("[-- END PGP SIGNED MESSAGE --]\n"), s);
1948 /* XXX - we may wish to recode here */
1950 state_puts (s->prefix, s);
1951 state_puts (buf, s);
1955 m->goodsig = (maybe_goodsig && have_any_sigs);
1957 if (needpass == -1) {
1958 state_attach_puts (_("[-- Error: could not find beginning"
1959 " of PGP message! --]\n\n"), s);
1965 /* Implementation of `encrypted_handler'. */
1967 /* MIME handler for pgp/mime encrypted messages. */
1968 int crypt_pgp_encrypted_handler (BODY * a, STATE * s)
1970 char tempfile[_POSIX_PATH_MAX];
1973 BODY *orig_body = a;
1978 if (!a || a->type != TYPEAPPLICATION || !a->subtype
1979 || ascii_strcasecmp ("pgp-encrypted", a->subtype)
1980 || !a->next || a->next->type != TYPEAPPLICATION || !a->next->subtype
1981 || ascii_strcasecmp ("octet-stream", a->next->subtype)) {
1982 if (s->flags & M_DISPLAY)
1983 state_attach_puts (_("[-- Error: malformed PGP/MIME message! --]\n\n"),
1988 /* Move forward to the application/pgp-encrypted body. */
1991 fpout = m_tempfile(tempfile, sizeof(tempfile), NONULL(MCore.tmpdir), NULL);
1993 if (s->flags & M_DISPLAY)
1994 state_attach_puts (_("[-- Error: could not create temporary file! "
1999 tattach = decrypt_part (a, s, fpout, 0, &is_signed);
2001 tattach->goodsig = is_signed > 0;
2003 if (s->flags & M_DISPLAY)
2004 state_attach_puts (is_signed ?
2006 ("[-- The following data is PGP/MIME signed and encrypted --]\n\n") :
2007 _("[-- The following data is PGP/MIME encrypted --]\n\n"), s);
2010 FILE *savefp = s->fpin;
2013 rc = mutt_body_handler (tattach, s);
2018 * if a multipart/signed is the _only_ sub-part of a
2019 * multipart/encrypted, cache signature verification
2022 if (mutt_is_multipart_signed (tattach) && !tattach->next)
2023 orig_body->goodsig |= tattach->goodsig;
2025 if (s->flags & M_DISPLAY) {
2026 state_puts ("\n", s);
2027 state_attach_puts (is_signed ?
2029 ("[-- End of PGP/MIME signed and encrypted data --]\n")
2030 : _("[-- End of PGP/MIME encrypted data --]\n"), s);
2033 body_list_wipe(&tattach);
2037 mutt_unlink (tempfile);
2041 /* Support for application/smime */
2042 int crypt_smime_application_smime_handler (BODY * a, STATE * s)
2044 char tempfile[_POSIX_PATH_MAX];
2051 fpout = m_tempfile(tempfile, sizeof(tempfile), NONULL(MCore.tmpdir), NULL);
2053 if (s->flags & M_DISPLAY)
2054 state_attach_puts (_("[-- Error: could not create temporary file! "
2059 tattach = decrypt_part (a, s, fpout, 1, &is_signed);
2061 tattach->goodsig = is_signed > 0;
2063 if (s->flags & M_DISPLAY)
2064 state_attach_puts (is_signed ?
2065 _("[-- The following data is S/MIME signed --]\n\n") :
2066 _("[-- The following data is S/MIME encrypted --]\n\n"), s);
2069 FILE *savefp = s->fpin;
2072 rc = mutt_body_handler (tattach, s);
2077 * if a multipart/signed is the _only_ sub-part of a
2078 * multipart/encrypted, cache signature verification
2081 if (mutt_is_multipart_signed (tattach) && !tattach->next) {
2082 if (!(a->goodsig = tattach->goodsig))
2083 a->warnsig = tattach->warnsig;
2085 else if (tattach->goodsig) {
2087 a->warnsig = tattach->warnsig;
2090 if (s->flags & M_DISPLAY) {
2091 state_puts ("\n", s);
2092 state_attach_puts (is_signed ?
2093 _("[-- End of S/MIME signed data --]\n") :
2094 _("[-- End of S/MIME encrypted data --]\n"), s);
2097 body_list_wipe(&tattach);
2101 mutt_unlink (tempfile);
2107 * Format an entry on the CRYPT key selection menu.
2110 * %k key id %K key id of the principal key
2112 * %a algorithm %A algorithm of the princ. key
2113 * %l length %L length of the princ. key
2114 * %f flags %F flags of the princ. key
2115 * %c capabilities %C capabilities of the princ. key
2116 * %t trust/validity of the key-uid association
2118 * %[...] date of key using strftime(3)
2122 crypt_entry_fmt (char *dest, ssize_t destlen, char op,
2123 const char *src, const char *prefix,
2124 const char *ifstr, const char *elstr,
2125 anytype data, format_flag flags)
2128 crypt_entry_t *entry;
2131 int optional = (flags & M_FORMAT_OPTIONAL);
2132 const char *s = NULL;
2138 /* if (isupper ((unsigned char) op)) */
2141 kflags = (key->flags /*| (pkey->flags & KEYFLAG_RESTRICTIONS)
2144 switch (ascii_tolower (op)) {
2148 char buf2[STRING], *p;
2164 while (len > 0 && *cp != ']') {
2173 break; /* not enough space */
2183 if (do_locales && Locale)
2184 setlocale (LC_TIME, Locale);
2189 if (key->kobj->subkeys && (key->kobj->subkeys->timestamp > 0))
2190 tt = key->kobj->subkeys->timestamp;
2192 tm = localtime (&tt);
2194 strftime (buf2, sizeof (buf2), dest, tm);
2197 setlocale (LC_TIME, "C");
2199 snprintf (fmt, sizeof (fmt), "%%%ss", prefix);
2200 snprintf (dest, destlen, fmt, buf2);
2207 snprintf (fmt, sizeof (fmt), "%%%sd", prefix);
2208 snprintf (dest, destlen, fmt, entry->num);
2213 /* fixme: we need a way to distinguish between main and subkeys.
2214 Store the idx in entry? */
2215 snprintf (fmt, sizeof (fmt), "%%%ss", prefix);
2216 snprintf (dest, destlen, fmt, crypt_keyid (key));
2221 snprintf (fmt, sizeof (fmt), "%%%ss", prefix);
2222 snprintf (dest, destlen, fmt, key->uid);
2227 snprintf (fmt, sizeof (fmt), "%%%s.3s", prefix);
2228 if (key->kobj->subkeys)
2229 s = gpgme_pubkey_algo_name (key->kobj->subkeys->pubkey_algo);
2232 snprintf (dest, destlen, fmt, s);
2237 snprintf (fmt, sizeof (fmt), "%%%slu", prefix);
2238 if (key->kobj->subkeys)
2239 val = key->kobj->subkeys->length;
2242 snprintf (dest, destlen, fmt, val);
2247 snprintf (fmt, sizeof (fmt), "%%%sc", prefix);
2248 snprintf (dest, destlen, fmt, crypt_flags (kflags));
2250 else if (!(kflags & (KEYFLAG_RESTRICTIONS)))
2255 snprintf (fmt, sizeof (fmt), "%%%ss", prefix);
2256 snprintf (dest, destlen, fmt, crypt_key_abilities (kflags));
2258 else if (!(kflags & (KEYFLAG_ABILITIES)))
2262 if ((kflags & KEYFLAG_ISX509))
2265 gpgme_user_id_t uid = NULL;
2268 for (i = 0, uid = key->kobj->uids; uid && (i < key->idx);
2269 i++, uid = uid->next);
2271 switch (uid->validity) {
2272 case GPGME_VALIDITY_UNDEFINED:
2275 case GPGME_VALIDITY_NEVER:
2278 case GPGME_VALIDITY_MARGINAL:
2281 case GPGME_VALIDITY_FULL:
2284 case GPGME_VALIDITY_ULTIMATE:
2287 case GPGME_VALIDITY_UNKNOWN:
2293 snprintf (fmt, sizeof (fmt), "%%%sc", prefix);
2294 snprintf (dest, destlen, fmt, s ? *s : 'B');
2297 snprintf (fmt, sizeof (fmt), "%%%ss", prefix);
2298 snprintf (dest, destlen, fmt,
2299 gpgme_get_protocol_name (key->kobj->protocol));
2306 if (flags & M_FORMAT_OPTIONAL)
2307 m_strformat(dest, destlen, 0, optional ? ifstr: elstr,
2308 mutt_attach_fmt, data, 0);
2312 /* Used by the display fucntion to format a line. */
2313 static void crypt_entry (char *s, ssize_t l, MUTTMENU * menu, int num)
2315 crypt_key_t **key_table = (crypt_key_t **) menu->data;
2316 crypt_entry_t entry;
2318 entry.key = key_table[num];
2319 entry.num = num + 1;
2321 m_strformat(s, l, COLS - SW, PgpEntryFormat, crypt_entry_fmt, &entry,
2322 option(OPTARROWCURSOR) ? M_FORMAT_ARROWCURSOR : 0);
2325 /* Compare two addresses and the keyid to be used for sorting. */
2326 static int _crypt_compare_address (const void *a, const void *b)
2328 crypt_key_t **s = (crypt_key_t **) a;
2329 crypt_key_t **t = (crypt_key_t **) b;
2332 if ((r = m_strcasecmp((*s)->uid, (*t)->uid)))
2335 return m_strcasecmp(crypt_keyid (*s), crypt_keyid (*t)) > 0;
2338 static int crypt_compare_address (const void *a, const void *b)
2340 return ((PgpSortKeys & SORT_REVERSE) ? !_crypt_compare_address (a, b)
2341 : _crypt_compare_address (a, b));
2345 /* Compare two key IDs and the addresses to be used for sorting. */
2346 static int _crypt_compare_keyid (const void *a, const void *b)
2348 crypt_key_t **s = (crypt_key_t **) a;
2349 crypt_key_t **t = (crypt_key_t **) b;
2352 if ((r = m_strcasecmp(crypt_keyid (*s), crypt_keyid (*t))))
2355 return m_strcasecmp((*s)->uid, (*t)->uid) > 0;
2358 static int crypt_compare_keyid (const void *a, const void *b)
2360 return ((PgpSortKeys & SORT_REVERSE) ? !_crypt_compare_keyid (a, b)
2361 : _crypt_compare_keyid (a, b));
2364 /* Compare 2 creation dates and the addresses. For sorting. */
2365 static int _crypt_compare_date (const void *a, const void *b)
2367 crypt_key_t **s = (crypt_key_t **) a;
2368 crypt_key_t **t = (crypt_key_t **) b;
2369 unsigned long ts = 0, tt = 0;
2371 if ((*s)->kobj->subkeys && ((*s)->kobj->subkeys->timestamp > 0))
2372 ts = (*s)->kobj->subkeys->timestamp;
2373 if ((*t)->kobj->subkeys && ((*t)->kobj->subkeys->timestamp > 0))
2374 tt = (*t)->kobj->subkeys->timestamp;
2381 return m_strcasecmp((*s)->uid, (*t)->uid) > 0;
2384 static int crypt_compare_date (const void *a, const void *b)
2386 return ((PgpSortKeys & SORT_REVERSE) ? !_crypt_compare_date (a, b)
2387 : _crypt_compare_date (a, b));
2390 /* Compare two trust values, the key length, the creation dates. the
2391 addresses and the key IDs. For sorting. */
2392 static int _crypt_compare_trust (const void *a, const void *b)
2394 crypt_key_t **s = (crypt_key_t **) a;
2395 crypt_key_t **t = (crypt_key_t **) b;
2396 unsigned long ts = 0, tt = 0;
2399 if ((r = (((*s)->flags & (KEYFLAG_RESTRICTIONS))
2400 - ((*t)->flags & (KEYFLAG_RESTRICTIONS)))))
2403 if ((*s)->kobj->uids)
2404 ts = (*s)->kobj->uids->validity;
2405 if ((*t)->kobj->uids)
2406 tt = (*t)->kobj->uids->validity;
2407 if ((r = (tt - ts)))
2410 if ((*s)->kobj->subkeys)
2411 ts = (*s)->kobj->subkeys->length;
2412 if ((*t)->kobj->subkeys)
2413 tt = (*t)->kobj->subkeys->length;
2417 if ((*s)->kobj->subkeys && ((*s)->kobj->subkeys->timestamp > 0))
2418 ts = (*s)->kobj->subkeys->timestamp;
2419 if ((*t)->kobj->subkeys && ((*t)->kobj->subkeys->timestamp > 0))
2420 tt = (*t)->kobj->subkeys->timestamp;
2426 if ((r = m_strcasecmp((*s)->uid, (*t)->uid)))
2428 return (m_strcasecmp(crypt_keyid ((*s)), crypt_keyid ((*t)))) > 0;
2431 static int crypt_compare_trust (const void *a, const void *b)
2433 return ((PgpSortKeys & SORT_REVERSE) ? !_crypt_compare_trust (a, b)
2434 : _crypt_compare_trust (a, b));
2437 /* Print the X.500 Distinguished Name part KEY from the array of parts
2439 static int print_dn_part (FILE * fp, struct dn_array_s *dn, const char *key)
2443 for (; dn->key; dn++) {
2444 if (!m_strcmp(dn->key, key)) {
2447 print_utf8 (fp, dn->value, m_strlen(dn->value));
2454 /* Print all parts of a DN in a standard sequence. */
2455 static void print_dn_parts (FILE * fp, struct dn_array_s *dn)
2457 const char *stdpart[] = {
2458 "CN", "OU", "O", "STREET", "L", "ST", "C", NULL
2460 int any = 0, any2 = 0, i;
2462 for (i = 0; stdpart[i]; i++) {
2465 any = print_dn_part (fp, dn, stdpart[i]);
2467 /* now print the rest without any specific ordering */
2468 for (; dn->key; dn++) {
2469 for (i = 0; stdpart[i]; i++) {
2470 if (!m_strcmp(dn->key, stdpart[i]))
2478 any = print_dn_part (fp, dn, dn->key);
2487 /* Parse an RDN; this is a helper to parse_dn(). */
2488 static const unsigned char *parse_dn_part (struct dn_array_s *array,
2489 const unsigned char *string)
2491 const unsigned char *s, *s1;
2495 /* parse attributeType */
2496 for (s = string + 1; *s && *s != '='; s++);
2498 return NULL; /* error */
2501 return NULL; /* empty key */
2502 array->key = p_dupstr(string, n );
2503 p = (unsigned char *) array->key;
2506 if (*string == '#') { /* hexstring */
2508 for (s = string; hexval(*s) >= 0; s++)
2512 return NULL; /* empty or odd number of digits */
2514 p = p_new(unsigned char, n + 1);
2515 array->value = (char *) p;
2516 for (s1 = string; n; s1 += 2, n--)
2517 *p++ = (hexval(*s1) << 8) | hexval(*s1);
2520 else { /* regular v3 quoted string */
2521 for (n = 0, s = string; *s; s++) {
2522 if (*s == '\\') { /* pair */
2524 if (*s == ',' || *s == '=' || *s == '+'
2525 || *s == '<' || *s == '>' || *s == '#' || *s == ';'
2526 || *s == '\\' || *s == '\"' || *s == ' ')
2528 else if (hexval(*s) >= 0 && hexval(*s + 1) >= 0) {
2533 return NULL; /* invalid escape sequence */
2535 else if (*s == '\"')
2536 return NULL; /* invalid encoding */
2537 else if (*s == ',' || *s == '=' || *s == '+'
2538 || *s == '<' || *s == '>' || *s == '#' || *s == ';')
2544 p = p_new(unsigned char, n + 1);
2545 array->value = (char *) p;
2546 for (s = string; n; s++, n--) {
2549 if (hexval(*s) >= 0) {
2550 *p++ = (hexval(*s) << 8) | hexval(*s + 1);
2565 /* Parse a DN and return an array-ized one. This is not a validating
2566 parser and it does not support any old-stylish syntax; gpgme is
2567 expected to return only rfc2253 compatible strings. */
2568 static struct dn_array_s *parse_dn (const unsigned char *string)
2570 struct dn_array_s *array;
2571 ssize_t arrayidx, arraysize;
2574 arraysize = 7; /* C,ST,L,O,OU,CN,email */
2575 array = p_new(struct dn_array_s, arraysize + 1);
2578 while (*string == ' ')
2582 if (arrayidx >= arraysize) { /* mutt lacks a real safe_realoc - so we need to copy */
2583 struct dn_array_s *a2;
2586 a2 = p_new(struct dn_array_s, arraysize + 1);
2587 for (i = 0; i < arrayidx; i++) {
2588 a2[i].key = array[i].key;
2589 a2[i].value = array[i].value;
2594 array[arrayidx].key = NULL;
2595 array[arrayidx].value = NULL;
2596 string = parse_dn_part (array + arrayidx, string);
2600 while (*string == ' ')
2602 if (*string && *string != ',' && *string != ';' && *string != '+')
2603 goto failure; /* invalid delimiter */
2607 array[arrayidx].key = NULL;
2608 array[arrayidx].value = NULL;
2612 for (i = 0; i < arrayidx; i++) {
2613 p_delete(&array[i].key);
2614 p_delete(&array[i].value);
2621 /* Print a nice representation of the USERID and make sure it is
2622 displayed in a proper way, which does mean to reorder some parts
2623 for S/MIME's DNs. USERID is a string as returned by the gpgme key
2624 functions. It is utf-8 encoded. */
2625 static void parse_and_print_user_id (FILE * fp, const char *userid)
2630 if (*userid == '<') {
2631 s = strchr (userid + 1, '>');
2633 print_utf8 (fp, userid + 1, s - userid - 1);
2635 else if (*userid == '(')
2636 fputs (_("[Can't display this user ID (unknown encoding)]"), fp);
2637 else if (!digit_or_letter ((const unsigned char *) userid))
2638 fputs (_("[Can't display this user ID (invalid encoding)]"), fp);
2640 struct dn_array_s *dn = parse_dn ((const unsigned char *) userid);
2643 fputs (_("[Can't display this user ID (invalid DN)]"), fp);
2645 print_dn_parts (fp, dn);
2646 for (i = 0; dn[i].key; i++) {
2647 p_delete(&dn[i].key);
2648 p_delete(&dn[i].value);
2656 KEY_CAP_CAN_ENCRYPT,
2661 static unsigned int key_check_cap (gpgme_key_t key, key_cap_t cap)
2663 gpgme_subkey_t subkey = NULL;
2664 unsigned int ret = 0;
2667 case KEY_CAP_CAN_ENCRYPT:
2668 if (!(ret = key->can_encrypt))
2669 for (subkey = key->subkeys; subkey; subkey = subkey->next)
2670 if ((ret = subkey->can_encrypt))
2673 case KEY_CAP_CAN_SIGN:
2674 if (!(ret = key->can_sign))
2675 for (subkey = key->subkeys; subkey; subkey = subkey->next)
2676 if ((ret = subkey->can_sign))
2679 case KEY_CAP_CAN_CERTIFY:
2680 if (!(ret = key->can_certify))
2681 for (subkey = key->subkeys; subkey; subkey = subkey->next)
2682 if ((ret = subkey->can_certify))
2691 /* Print verbose information about a key or certificate to FP. */
2692 static void print_key_info (gpgme_key_t key, FILE * fp)
2695 const char *s = NULL, *s2 = NULL;
2698 char shortbuf[STRING];
2699 unsigned long aval = 0;
2703 gpgme_user_id_t uid = NULL;
2706 setlocale (LC_TIME, Locale);
2708 is_pgp = key->protocol == GPGME_PROTOCOL_OpenPGP;
2710 for (idx = 0, uid = key->uids; uid; idx++, uid = uid->next) {
2715 fputs (idx ? _(" aka ......: ") :_("Name ......: "), fp);
2718 fputs (_("[Invalid]"), fp);
2722 print_utf8 (fp, s, m_strlen(s));
2724 parse_and_print_user_id (fp, s);
2728 if (key->subkeys && (key->subkeys->timestamp > 0)) {
2729 tt = key->subkeys->timestamp;
2731 tm = localtime (&tt);
2732 #ifdef HAVE_LANGINFO_D_T_FMT
2733 strftime (shortbuf, sizeof shortbuf, nl_langinfo (D_T_FMT), tm);
2735 strftime (shortbuf, sizeof shortbuf, "%c", tm);
2737 fprintf (fp, _("Valid From : %s\n"), shortbuf);
2740 if (key->subkeys && (key->subkeys->expires > 0)) {
2741 tt = key->subkeys->expires;
2743 tm = localtime (&tt);
2744 #ifdef HAVE_LANGINFO_D_T_FMT
2745 strftime (shortbuf, sizeof shortbuf, nl_langinfo (D_T_FMT), tm);
2747 strftime (shortbuf, sizeof shortbuf, "%c", tm);
2749 fprintf (fp, _("Valid To ..: %s\n"), shortbuf);
2753 s = gpgme_pubkey_algo_name (key->subkeys->pubkey_algo);
2757 s2 = is_pgp ? "PGP" : "X.509";
2760 aval = key->subkeys->length;
2762 fprintf (fp, _("Key Type ..: %s, %lu bit %s\n"), s2, aval, s);
2764 fprintf (fp, _("Key Usage .: "));
2767 if (key_check_cap (key, KEY_CAP_CAN_ENCRYPT)) {
2768 fprintf (fp, "%s%s", delim, _("encryption"));
2771 if (key_check_cap (key, KEY_CAP_CAN_SIGN)) {
2772 fprintf (fp, "%s%s", delim, _("signing"));
2775 if (key_check_cap (key, KEY_CAP_CAN_CERTIFY)) {
2776 fprintf (fp, "%s%s", delim, _("certification"));
2782 s = key->subkeys->fpr;
2783 fputs (_("Fingerprint: "), fp);
2784 if (is_pgp && m_strlen(s) == 40) {
2785 for (i = 0; *s && s[1] && s[2] && s[3] && s[4]; s += 4, i++) {
2790 putc (is_pgp ? ' ' : ':', fp);
2791 if (is_pgp && i == 4)
2796 for (i = 0; *s && s[1] && s[2]; s += 2, i++) {
2799 putc (is_pgp ? ' ' : ':', fp);
2800 if (is_pgp && i == 7)
2804 fprintf (fp, "%s\n", s);
2807 if (key->issuer_serial) {
2808 s = key->issuer_serial;
2810 fprintf (fp, _("Serial-No .: 0x%s\n"), s);
2813 if (key->issuer_name) {
2814 s = key->issuer_name;
2816 fprintf (fp, _("Issued By .: "));
2817 parse_and_print_user_id (fp, s);
2822 /* For PGP we list all subkeys. */
2824 gpgme_subkey_t subkey = NULL;
2826 for (idx = 1, subkey = key->subkeys; subkey; idx++, subkey = subkey->next) {
2830 if (m_strlen(s) == 16)
2831 s += 8; /* display only the short keyID */
2832 fprintf (fp, _("Subkey ....: 0x%s"), s);
2833 if (subkey->revoked) {
2835 fputs (_("[Revoked]"), fp);
2837 if (subkey->invalid) {
2839 fputs (_("[Invalid]"), fp);
2841 if (subkey->expired) {
2843 fputs (_("[Expired]"), fp);
2845 if (subkey->disabled) {
2847 fputs (_("[Disabled]"), fp);
2851 if (subkey->timestamp > 0) {
2852 tt = subkey->timestamp;
2854 tm = localtime (&tt);
2855 #ifdef HAVE_LANGINFO_D_T_FMT
2856 strftime (shortbuf, sizeof shortbuf, nl_langinfo (D_T_FMT), tm);
2858 strftime (shortbuf, sizeof shortbuf, "%c", tm);
2860 fprintf (fp, _("Valid From : %s\n"), shortbuf);
2863 if (subkey->expires > 0) {
2864 tt = subkey->expires;
2866 tm = localtime (&tt);
2867 #ifdef HAVE_LANGINFO_D_T_FMT
2868 strftime (shortbuf, sizeof shortbuf, nl_langinfo (D_T_FMT), tm);
2870 strftime (shortbuf, sizeof shortbuf, "%c", tm);
2872 fprintf (fp, _("Valid To ..: %s\n"), shortbuf);
2876 s = gpgme_pubkey_algo_name (subkey->pubkey_algo);
2881 aval = subkey->length;
2885 fprintf (fp, _("Key Type ..: %s, %lu bit %s\n"), "PGP", aval, s);
2887 fprintf (fp, _("Key Usage .: "));
2890 if (subkey->can_encrypt) {
2891 fprintf (fp, "%s%s", delim, _("encryption"));
2894 if (subkey->can_sign) {
2895 fprintf (fp, "%s%s", delim, _("signing"));
2898 if (subkey->can_certify) {
2899 fprintf (fp, "%s%s", delim, _("certification"));
2907 setlocale (LC_TIME, "C");
2911 /* Show detailed information about the selected key */
2912 static void verify_key (crypt_key_t * key)
2915 char cmd[LONG_STRING], tempfile[_POSIX_PATH_MAX];
2917 gpgme_ctx_t listctx = NULL;
2919 gpgme_key_t k = NULL;
2922 fp = m_tempfile (tempfile, sizeof(tempfile), NONULL(MCore.tmpdir), NULL);
2924 mutt_perror (_("Can't create temporary file"));
2927 mutt_message _("Collecting data...");
2929 print_key_info (key->kobj, fp);
2931 err = gpgme_new (&listctx);
2933 fprintf (fp, "Internal error: can't create gpgme context: %s\n",
2934 gpgme_strerror (err));
2937 if ((key->flags & KEYFLAG_ISX509))
2938 gpgme_set_protocol (listctx, GPGME_PROTOCOL_CMS);
2942 while ((s = k->chain_id) && k->subkeys && m_strcmp(s, k->subkeys->fpr)) {
2944 err = gpgme_op_keylist_start (listctx, s, 0);
2945 gpgme_key_release (k);
2948 err = gpgme_op_keylist_next (listctx, &k);
2950 fprintf (fp, _("Error finding issuer key: %s\n"), gpgme_strerror (err));
2953 gpgme_op_keylist_end (listctx);
2955 print_key_info (k, fp);
2958 fputs (_("Error: certification chain to long - stopping here\n"), fp);
2964 gpgme_key_release (k);
2965 gpgme_release (listctx);
2967 mutt_clear_error ();
2968 snprintf (cmd, sizeof (cmd), _("Key ID: 0x%s"), crypt_keyid (key));
2969 mutt_do_pager (cmd, tempfile, 0, NULL);
2972 /* Implementation of `findkeys'. */
2974 /* Convert string_list_t into a pattern string suitable to be passed to GPGME.
2975 We need to convert spaces in an item into a '+' and '%' into
2977 static char *list_to_pattern (string_list_t * list)
2985 for (l = list; l; l = l->next) {
2986 for (s = l->data; *s; s++) {
2991 n++; /* delimiter or end of string */
2993 n++; /* make sure to allocate at least one byte */
2994 pattern = p = p_new(char, n);
2995 for (l = list; l; l = l->next) {
3000 for (s = l->data; *s; s++) {
3006 else if (*s == '+') {
3022 /* Return a list of keys which are candidates for the selection.
3023 Select by looking at the HINTS list. */
3024 static crypt_key_t *get_candidates (string_list_t * hints, unsigned int app,
3027 crypt_key_t *db, *k, **kend;
3033 gpgme_user_id_t uid = NULL;
3035 pattern = list_to_pattern (hints);
3039 err = gpgme_new (&ctx);
3041 mutt_error (_("gpgme_new failed: %s"), gpgme_strerror (err));
3049 if ((app & APPLICATION_PGP)) {
3050 /* Its all a mess. That old GPGME expects different things
3051 depending on the protocol. For gpg we don' t need percent
3052 escaped pappert but simple strings passed in an array to the
3053 keylist_ext_start function. */
3058 for (l = hints, n = 0; l; l = l->next) {
3059 if (l->data && *l->data)
3065 patarr = p_new(char *, n + 1);
3066 for (l = hints, n = 0; l; l = l->next) {
3067 if (l->data && *l->data)
3068 patarr[n++] = m_strdup(l->data);
3071 err = gpgme_op_keylist_ext_start (ctx, (const char **) patarr, secret, 0);
3072 for (n = 0; patarr[n]; n++)
3073 p_delete(&patarr[n]);
3076 mutt_error (_("gpgme_op_keylist_start failed: %s"), gpgme_strerror (err));
3077 gpgme_release (ctx);
3082 while (!(err = gpgme_op_keylist_next (ctx, &key))) {
3083 unsigned int flags = 0;
3085 if (key_check_cap (key, KEY_CAP_CAN_ENCRYPT))
3086 flags |= KEYFLAG_CANENCRYPT;
3087 if (key_check_cap (key, KEY_CAP_CAN_SIGN))
3088 flags |= KEYFLAG_CANSIGN;
3090 for (idx = 0, uid = key->uids; uid; idx++, uid = uid->next) {
3091 k = p_new(crypt_key_t, 1);
3100 if (gpg_err_code (err) != GPG_ERR_EOF)
3101 mutt_error (_("gpgme_op_keylist_next failed: %s"), gpgme_strerror (err));
3102 gpgme_op_keylist_end (ctx);
3107 if ((app & APPLICATION_SMIME)) {
3108 /* and now look for x509 certificates */
3109 gpgme_set_protocol (ctx, GPGME_PROTOCOL_CMS);
3110 err = gpgme_op_keylist_start (ctx, pattern, 0);
3112 mutt_error (_("gpgme_op_keylist_start failed: %s"), gpgme_strerror (err));
3113 gpgme_release (ctx);
3118 while (!(err = gpgme_op_keylist_next (ctx, &key))) {
3119 unsigned int flags = KEYFLAG_ISX509;
3121 if (key_check_cap (key, KEY_CAP_CAN_ENCRYPT))
3122 flags |= KEYFLAG_CANENCRYPT;
3123 if (key_check_cap (key, KEY_CAP_CAN_SIGN))
3124 flags |= KEYFLAG_CANSIGN;
3126 for (idx = 0, uid = key->uids; uid; idx++, uid = uid->next) {
3127 k = p_new(crypt_key_t, 1);
3136 if (gpg_err_code (err) != GPG_ERR_EOF)
3137 mutt_error (_("gpgme_op_keylist_next failed: %s"), gpgme_strerror (err));
3138 gpgme_op_keylist_end (ctx);
3141 gpgme_release (ctx);
3146 /* Add the string STR to the list HINTS. This list is later used to
3148 static string_list_t *crypt_add_string_to_hints (string_list_t * hints, const char *str)
3153 if ((scratch = m_strdup(str)) == NULL)
3156 for (t = strtok (scratch, " ,.:\"()<>\n"); t;
3157 t = strtok (NULL, " ,.:\"()<>\n")) {
3158 if (m_strlen(t) > 3)
3159 hints = mutt_add_list(hints, t);
3166 /* Display a menu to select a key from the array KEYS. FORCED_VALID
3167 will be set to true on return if the user did override the the
3169 static crypt_key_t *crypt_select_key (crypt_key_t * keys,
3170 address_t * p, const char *s,
3171 unsigned int app, int *forced_valid)
3174 crypt_key_t **key_table;
3177 char helpstr[STRING], buf[LONG_STRING];
3179 int (*f) (const void *, const void *);
3180 int menu_to_use = 0;
3185 /* build the key table */
3188 for (k = keys; k; k = k->next) {
3189 if (!option (OPTPGPSHOWUNUSABLE) && (k->flags & KEYFLAG_CANTUSE)) {
3196 p_realloc(&key_table, keymax);
3202 if (!i && unusable) {
3203 mutt_error _("All matching keys are marked expired/revoked.");
3209 switch (PgpSortKeys & SORT_MASK) {
3211 f = crypt_compare_date;
3214 f = crypt_compare_keyid;
3217 f = crypt_compare_address;
3221 f = crypt_compare_trust;
3224 qsort (key_table, i, sizeof (crypt_key_t *), f);
3226 if (app & APPLICATION_PGP)
3227 menu_to_use = MENU_KEY_SELECT_PGP;
3228 else if (app & APPLICATION_SMIME)
3229 menu_to_use = MENU_KEY_SELECT_SMIME;
3232 mutt_make_help (buf, sizeof (buf), _("Exit "), menu_to_use, OP_EXIT);
3233 m_strcat(helpstr, sizeof(helpstr), buf);
3234 mutt_make_help (buf, sizeof (buf), _("Select "), menu_to_use,
3235 OP_GENERIC_SELECT_ENTRY);
3236 m_strcat(helpstr, sizeof(helpstr), buf);
3237 mutt_make_help (buf, sizeof (buf), _("Check key "),
3238 menu_to_use, OP_VERIFY_KEY);
3239 m_strcat(helpstr, sizeof(helpstr), buf);
3240 mutt_make_help (buf, sizeof (buf), _("Help"), menu_to_use, OP_HELP);
3241 m_strcat(helpstr, sizeof(helpstr), buf);
3243 menu = mutt_new_menu ();
3245 menu->make_entry = crypt_entry;
3246 menu->menu = menu_to_use;
3247 menu->help = helpstr;
3248 menu->data = key_table;
3253 if ((app & APPLICATION_PGP) && (app & APPLICATION_SMIME))
3254 ts = _("PGP and S/MIME keys matching");
3255 else if ((app & APPLICATION_PGP))
3256 ts = _("PGP keys matching");
3257 else if ((app & APPLICATION_SMIME))
3258 ts = _("S/MIME keys matching");
3260 ts = _("keys matching");
3263 snprintf (buf, sizeof (buf), _("%s <%s>."), ts, p->mailbox);
3265 snprintf (buf, sizeof (buf), _("%s \"%s\"."), ts, s);
3269 mutt_clear_error ();
3273 switch (mutt_menuLoop (menu)) {
3275 verify_key (key_table[menu->current]);
3276 menu->redraw = REDRAW_FULL;
3280 mutt_message ("%s", key_table[menu->current]->uid);
3283 case OP_GENERIC_SELECT_ENTRY:
3284 /* FIXME make error reporting more verbose - this should be
3285 easy because gpgme provides more information */
3286 if (option (OPTPGPCHECKTRUST)) {
3287 if (!crypt_key_is_valid (key_table[menu->current])) {
3288 mutt_error _("This key can't be used: "
3289 "expired/disabled/revoked.");
3294 if (option (OPTPGPCHECKTRUST) &&
3295 (!crypt_id_is_valid (key_table[menu->current])
3296 || !crypt_id_is_strong (key_table[menu->current]))) {
3298 char buff[LONG_STRING];
3300 if (key_table[menu->current]->flags & KEYFLAG_CANTUSE)
3301 s = N_("ID is expired/disabled/revoked.");
3303 gpgme_validity_t val = GPGME_VALIDITY_UNKNOWN;
3304 gpgme_user_id_t uid = NULL;
3309 uid = key_table[menu->current]->kobj->uids;
3310 for (j = 0; (j < key_table[menu->current]->idx) && uid;
3311 j++, uid = uid->next);
3313 val = uid->validity;
3316 case GPGME_VALIDITY_UNKNOWN:
3317 case GPGME_VALIDITY_UNDEFINED:
3318 warn_s = N_("ID has undefined validity.");
3320 case GPGME_VALIDITY_NEVER:
3321 warn_s = N_("ID is not valid.");
3323 case GPGME_VALIDITY_MARGINAL:
3324 warn_s = N_("ID is only marginally valid.");
3326 case GPGME_VALIDITY_FULL:
3327 case GPGME_VALIDITY_ULTIMATE:
3331 snprintf (buff, sizeof (buff),
3332 _("%s Do you really want to use the key?"), _(warn_s));
3334 if (mutt_yesorno (buff, 0) != 1) {
3335 mutt_clear_error ();
3342 k = crypt_copy_key (key_table[menu->current]);
3353 mutt_menuDestroy (&menu);
3354 p_delete(&key_table);
3356 set_option (OPTNEEDREDRAW);
3361 static crypt_key_t *crypt_getkeybyaddr (address_t * a, short abilities,
3362 unsigned int app, int *forced_valid)
3365 string_list_t *hints = NULL;
3370 int this_key_has_strong;
3371 int this_key_has_weak;
3372 int this_key_has_invalid;
3375 crypt_key_t *keys, *k;
3376 crypt_key_t *the_valid_key = NULL;
3377 crypt_key_t *matches = NULL;
3378 crypt_key_t **matches_endp = &matches;
3382 if (a && a->mailbox)
3383 hints = crypt_add_string_to_hints (hints, a->mailbox);
3384 if (a && a->personal)
3385 hints = crypt_add_string_to_hints (hints, a->personal);
3387 mutt_message (_("Looking for keys matching \"%s\"..."), a->mailbox);
3388 keys = get_candidates (hints, app, (abilities & KEYFLAG_CANSIGN));
3390 string_list_wipe(&hints);
3395 for (k = keys; k; k = k->next) {
3396 if (abilities && !(k->flags & abilities)) {
3400 this_key_has_weak = 0; /* weak but valid match */
3401 this_key_has_invalid = 0; /* invalid match */
3402 this_key_has_strong = 0; /* strong and valid match */
3403 match = 0; /* any match */
3405 r = rfc822_parse_adrlist (NULL, k->uid);
3406 for (p = r; p; p = p->next) {
3407 int validity = crypt_id_matches_addr (a, p, k);
3409 if (validity & CRYPT_KV_MATCH) /* something matches */
3412 /* is this key a strong candidate? */
3413 if ((validity & CRYPT_KV_VALID)
3414 && (validity & CRYPT_KV_STRONGID)
3415 && (validity & CRYPT_KV_ADDR)) {
3416 if (the_valid_key && the_valid_key != k)
3419 this_key_has_strong = 1;
3421 else if ((validity & CRYPT_KV_MATCH)
3422 && !(validity & CRYPT_KV_VALID))
3423 this_key_has_invalid = 1;
3424 else if ((validity & CRYPT_KV_MATCH)
3425 && (!(validity & CRYPT_KV_STRONGID)
3426 || !(validity & CRYPT_KV_ADDR)))
3427 this_key_has_weak = 1;
3429 address_list_wipe(&r);
3434 if (!this_key_has_strong && this_key_has_invalid)
3436 if (!this_key_has_strong && this_key_has_weak)
3439 *matches_endp = tmp = crypt_copy_key (k);
3440 matches_endp = &tmp->next;
3441 the_valid_key = tmp;
3445 crypt_free_key (&keys);
3448 if (the_valid_key && !multi && !weak
3449 && !(invalid && option (OPTPGPSHOWUNUSABLE))) {
3451 * There was precisely one strong match on a valid ID, there
3452 * were no valid keys with weak matches, and we aren't
3453 * interested in seeing invalid keys.
3455 * Proceed without asking the user.
3457 k = crypt_copy_key (the_valid_key);
3461 * Else: Ask the user.
3463 k = crypt_select_key (matches, a, NULL, app, forced_valid);
3465 crypt_free_key (&matches);
3474 static crypt_key_t *crypt_getkeybystr (const char *p, short abilities,
3475 unsigned int app, int *forced_valid)
3477 string_list_t *hints = NULL;
3479 crypt_key_t *matches = NULL;
3480 crypt_key_t **matches_endp = &matches;
3484 mutt_message (_("Looking for keys matching \"%s\"..."), p);
3488 hints = crypt_add_string_to_hints (hints, p);
3489 keys = get_candidates (hints, app, (abilities & KEYFLAG_CANSIGN));
3490 string_list_wipe(&hints);
3495 for (k = keys; k; k = k->next) {
3496 if (abilities && !(k->flags & abilities))
3501 if (!*p || !m_strcasecmp(p, crypt_keyid (k))
3502 || (!m_strncasecmp(p, "0x", 2)
3503 && !m_strcasecmp(p + 2, crypt_keyid (k)))
3504 || (option (OPTPGPLONGIDS)
3505 && !m_strncasecmp(p, "0x", 2)
3506 && !m_strcasecmp(p + 2, crypt_keyid (k) + 8))
3507 || m_stristr(k->uid, p)) {
3510 *matches_endp = tmp = crypt_copy_key (k);
3511 matches_endp = &tmp->next;
3515 crypt_free_key (&keys);
3518 k = crypt_select_key (matches, NULL, p, app, forced_valid);
3519 crypt_free_key (&matches);
3526 /* Display TAG as a prompt to ask for a key. If WHATFOR is not null
3527 use it as default and store it under that label as the next
3528 default. ABILITIES describe the required key abilities (sign,
3529 encrypt) and APP the type of the requested key; ether S/MIME or
3530 PGP. Return a copy of the key or NULL if not found. */
3531 static crypt_key_t *crypt_ask_for_key (char *tag,
3534 unsigned int app, int *forced_valid)
3538 struct crypt_cache *l = NULL;
3542 forced_valid = &dummy;
3544 mutt_clear_error ();
3550 for (l = id_defaults; l; l = l->next)
3551 if (!m_strcasecmp(whatfor, l->what)) {
3552 m_strcpy(resp, sizeof(resp), NONULL(l->dflt));
3560 if (mutt_get_field (tag, resp, sizeof (resp), M_CLEAR) != 0)
3565 m_strreplace(&l->dflt, resp);
3567 l = p_new(struct crypt_cache, 1);
3568 l->next = id_defaults;
3570 l->what = m_strdup(whatfor);
3571 l->dflt = m_strdup(resp);
3575 if ((key = crypt_getkeybystr (resp, abilities, app, forced_valid)))
3583 /* This routine attempts to find the keyids of the recipients of a
3584 message. It returns NULL if any of the keys can not be found. */
3585 static char *find_keys (address_t * to, address_t * cc, address_t * bcc,
3588 char *keylist = NULL, *t;
3590 ssize_t keylist_size = 0;
3591 ssize_t keylist_used = 0;
3592 address_t *tmp = NULL, *addr = NULL;
3593 address_t **last = &tmp;
3596 crypt_key_t *k_info, *key;
3597 const char *fqdn = mutt_fqdn (1);
3600 *r_application = APPLICATION_PGP | APPLICATION_SMIME;
3603 for (i = 0; i < 3; i++) {
3618 *last = address_list_dup (p);
3620 last = &((*last)->next);
3623 rfc822_qualify(tmp, fqdn);
3624 address_list_uniq(tmp);
3626 for (p = tmp; p; p = p->next) {
3627 char buf[LONG_STRING];
3628 int forced_valid = 0;
3633 if ((keyID = mutt_crypt_hook (p)) != NULL) {
3636 snprintf (buf, sizeof (buf), _("Use keyID = \"%s\" for %s?"),
3638 if ((r = mutt_yesorno (buf, M_YES)) == M_YES) {
3639 /* check for e-mail address */
3640 if ((t = strchr (keyID, '@')) &&
3641 (addr = rfc822_parse_adrlist (NULL, keyID))) {
3642 rfc822_qualify(addr, fqdn);
3646 k_info = crypt_getkeybystr (keyID, KEYFLAG_CANENCRYPT,
3647 app, &forced_valid);
3652 address_list_wipe(&tmp);
3653 address_list_wipe(&addr);
3659 && (k_info = crypt_getkeybyaddr (q, KEYFLAG_CANENCRYPT,
3660 app, &forced_valid)) == NULL) {
3661 snprintf (buf, sizeof (buf), _("Enter keyID for %s: "), q->mailbox);
3663 if ((key = crypt_ask_for_key (buf, q->mailbox, KEYFLAG_CANENCRYPT,
3665 &forced_valid)) == NULL) {
3667 address_list_wipe(&tmp);
3668 address_list_wipe(&addr);
3676 const char *s = crypt_fpr (key);
3678 keylist_size += m_strlen(s) + 4 + 1;
3679 p_realloc(&keylist, keylist_size);
3680 sprintf (keylist + keylist_used, "%s0x%s%s",
3681 keylist_used ? " " : "", s, forced_valid ? "!" : "");
3683 keylist_used = m_strlen(keylist);
3685 crypt_free_key (&key);
3686 address_list_wipe(&addr);
3688 address_list_wipe(&tmp);
3692 char *crypt_pgp_findkeys (address_t * to, address_t * cc, address_t * bcc)
3694 return find_keys (to, cc, bcc, APPLICATION_PGP);
3697 char *crypt_smime_findkeys (address_t * to, address_t * cc, address_t * bcc)
3699 return find_keys (to, cc, bcc, APPLICATION_SMIME);
3702 int crypt_send_menu (HEADER * msg, int *redraw, int is_smime)
3705 char input_signas[STRING];
3708 if (msg->security & APPLICATION_PGP)
3710 else if (msg->security & APPLICATION_SMIME)
3715 mutt_multi_choice (_
3716 ("S/MIME (e)ncrypt, (s)ign, sign (a)s, (b)oth, (p)gp or (c)lear?"),
3720 mutt_multi_choice (_
3721 ("PGP (e)ncrypt, (s)ign, sign (a)s, (b)oth, s/(m)ime or (c)lear?"),
3725 case 1: /* (e)ncrypt */
3726 msg->security |= (is_smime ? SMIMEENCRYPT : PGPENCRYPT);
3727 msg->security &= ~(is_smime ? SMIMESIGN : PGPSIGN);
3730 case 2: /* (s)ign */
3731 msg->security |= (is_smime ? SMIMESIGN : PGPSIGN);
3732 msg->security &= ~(is_smime ? SMIMEENCRYPT : PGPENCRYPT);
3735 case 3: /* sign (a)s */
3736 if ((p = crypt_ask_for_key (_("Sign as: "), NULL, KEYFLAG_CANSIGN,
3737 is_smime ? APPLICATION_SMIME :
3738 APPLICATION_PGP, NULL))) {
3739 snprintf (input_signas, sizeof (input_signas), "0x%s", crypt_keyid (p));
3740 m_strreplace(is_smime ? &SmimeDefaultKey : &PgpSignAs,
3742 crypt_free_key (&p);
3744 msg->security |= (is_smime ? SMIMESIGN : PGPSIGN);
3746 *redraw = REDRAW_FULL;
3749 case 4: /* (b)oth */
3751 (is_smime ? (SMIMEENCRYPT | SMIMESIGN) : (PGPENCRYPT | PGPSIGN));
3754 case 5: /* (p)gp or s/(m)ime */
3755 is_smime = !is_smime;
3758 case 6: /* (c)lear */
3759 return msg->security = 0;
3763 msg->security &= ~APPLICATION_PGP;
3764 msg->security |= APPLICATION_SMIME;
3766 msg->security &= ~APPLICATION_SMIME;
3767 msg->security |= APPLICATION_PGP;
3770 return msg->security;
3773 int crypt_smime_verify_sender (HEADER * h)
3775 address_t *sender = NULL;
3776 unsigned int ret = 1;
3779 h->env->from = mutt_expand_aliases (h->env->from);
3780 sender = h->env->from;
3782 else if (h->env->sender) {
3783 h->env->sender = mutt_expand_aliases (h->env->sender);
3784 sender = h->env->sender;
3788 if (signature_key) {
3789 gpgme_key_t key = signature_key;
3790 gpgme_user_id_t uid = NULL;
3791 int sender_length = 0;
3794 sender_length = m_strlen(sender->mailbox);
3795 for (uid = key->uids; uid && ret; uid = uid->next) {
3796 uid_length = m_strlen(uid->email);
3797 if (1 && (uid->email[0] == '<')
3798 && (uid->email[uid_length - 1] == '>')
3799 && (uid_length == sender_length + 2)
3800 && (!m_strncmp (uid->email + 1, sender->mailbox, sender_length)))
3805 mutt_any_key_to_continue ("Failed to verify sender");
3808 mutt_any_key_to_continue ("Failed to figure out sender");
3810 if (signature_key) {
3811 gpgme_key_release (signature_key);
3812 signature_key = NULL;
3818 void crypt_invoke_import(FILE *stream, int smime)
3820 gpgme_ctx_t ctx = create_gpgme_context(smime);
3824 err = gpgme_data_new_from_stream(&data, stream);
3826 mutt_error (_("error allocating data object: %s\n"), gpgme_strerror (err));
3831 err = gpgme_op_import(ctx, data);
3833 mutt_error(_("error importing gpg data: %s\n"), gpgme_strerror(err));
3834 gpgme_data_release(data);
3839 gpgme_data_release(data);
3844 static void pgp_extract_keys_from_attachment(FILE * fp, BODY * top)
3847 FILE *tmpfp = tmpfile();
3849 if (tmpfp == NULL) {
3850 mutt_perror (_("Can't create temporary file"));
3857 mutt_body_handler(top, &s);
3860 crypt_invoke_import(tmpfp, 0);
3864 void crypt_pgp_extract_keys_from_attachment_list(FILE * fp, int tag, BODY * top)
3867 set_option (OPTDONTHANDLEPGPKEYS);
3869 for (; top; top = top->next) {
3870 if (!tag || top->tagged)
3871 pgp_extract_keys_from_attachment (fp, top);
3877 unset_option (OPTDONTHANDLEPGPKEYS);
3883 /* fixme: needs documentation. */
3884 void crypt_pgp_invoke_getkeys (address_t * addr)
3888 /* Generate a PGP public key attachment. */
3889 BODY *crypt_pgp_make_key_attachment (char *tempf)
3896 /* fixme: Needs documentation. */
3897 void crypt_smime_getkeys (ENVELOPE * env)