2 * Copyright notice from original mutt:
3 * crypt-gpgme.c - GPGME based crypto operations
4 * Copyright (C) 1996,1997 Michael R. Elkins <me@cs.hmc.edu>
5 * Copyright (C) 1998,1999,2000 Thomas Roessler <roessler@guug.de>
6 * Copyright (C) 2001 Thomas Roessler <roessler@guug.de>
7 * Oliver Ehli <elmy@acm.org>
8 * Copyright (C) 2002, 2003, 2004 g10 Code GmbH
10 * This file is part of mutt-ng, see http://www.muttng.org/.
11 * It's licensed under the GNU General Public License,
12 * please see the file GPL in the top level source directory.
15 #include <lib-lib/lib-lib.h>
20 #ifdef HAVE_LANGINFO_D_T_FMT
21 # include <langinfo.h>
23 #ifdef HAVE_SYS_RESOURCE_H
24 # include <sys/resource.h>
29 #include <lib-mime/mime.h>
30 #include <lib-ui/curses.h>
31 #include <lib-ui/enter.h>
32 #include <lib-ui/menu.h>
41 #include "recvattach.h"
44 /* Values used for comparing addresses. */
45 #define CRYPT_KV_VALID 1
46 #define CRYPT_KV_ADDR 2
47 #define CRYPT_KV_STRING 4
48 #define CRYPT_KV_STRONGID 8
49 #define CRYPT_KV_MATCH (CRYPT_KV_ADDR|CRYPT_KV_STRING)
58 struct crypt_cache *next;
66 /* We work based on user IDs, getting from a user ID to the key is
67 check and does not need any memory (gpgme uses reference counting). */
68 typedef struct crypt_keyinfo {
69 struct crypt_keyinfo *next;
71 int idx; /* and the user ID at this index */
72 const char *uid; /* and for convenience point to this user ID */
73 unsigned int flags; /* global and per uid flags (for convenience) */
76 typedef struct crypt_entry {
82 static struct crypt_cache *id_defaults = NULL;
83 static gpgme_key_t signature_key = NULL;
85 /* Show a message that a backend will be invoked. */
86 void crypt_invoke_message (int type)
88 if (type & APPLICATION_PGP) {
89 mutt_message _("Invoking PGP...");
91 else if (type & APPLICATION_SMIME) {
92 mutt_message _("Invoking S/MIME...");
97 * General helper functions.
100 /* return true when S points to a didgit or letter. */
101 static int digit_or_letter (const unsigned char *s)
103 return ((*s >= '0' && *s <= '9')
104 || (*s >= 'A' && *s <= 'Z')
105 || (*s >= 'a' && *s <= 'z'));
109 /* Print the utf-8 encoded string BUF of length LEN bytes to stream
110 FP. Convert the character set. */
111 static void print_utf8 (FILE * fp, const char *buf, ssize_t len)
115 tstr = p_dupstr(buf, len);
116 mutt_convert_string (&tstr, "utf-8", MCharset.charset, M_ICONV_HOOK_FROM);
126 /* Return the keyID for the key K. Note that this string is valid as
127 long as K is valid */
128 static const char *crypt_keyid (crypt_key_t * k)
130 const char *s = "????????";
132 if (k->kobj && k->kobj->subkeys) {
133 s = k->kobj->subkeys->keyid;
134 if ((!option (OPTPGPLONGIDS)) && (m_strlen(s) == 16))
135 /* Return only the short keyID. */
142 /* Return the hexstring fingerprint from the key K. */
143 static const char *crypt_fpr (crypt_key_t * k)
147 if (k->kobj && k->kobj->subkeys)
148 s = k->kobj->subkeys->fpr;
153 /* Parse FLAGS and return a statically allocated(!) string with them. */
154 static char *crypt_key_abilities (int flags)
158 if (!(flags & KEYFLAG_CANENCRYPT))
160 else if (flags & KEYFLAG_PREFER_SIGNING)
165 if (!(flags & KEYFLAG_CANSIGN))
167 else if (flags & KEYFLAG_PREFER_ENCRYPTION)
177 /* Parse FLAGS and return a character describing the most important flag. */
178 static char crypt_flags (int flags)
180 if (flags & KEYFLAG_REVOKED)
182 else if (flags & KEYFLAG_EXPIRED)
184 else if (flags & KEYFLAG_DISABLED)
186 else if (flags & KEYFLAG_CRITICAL)
192 /* Return a copy of KEY. */
193 static crypt_key_t *crypt_copy_key (crypt_key_t *key)
197 k = p_new(crypt_key_t, 1);
199 gpgme_key_ref (key->kobj);
202 k->flags = key->flags;
207 /* Release all the keys at the address of KEYLIST and set the address
209 static void crypt_free_key (crypt_key_t ** keylist)
212 crypt_key_t *k = (*keylist)->next;
219 /* Return trute when key K is valid. */
220 static int crypt_key_is_valid (crypt_key_t * k)
222 if (k->flags & KEYFLAG_CANTUSE)
227 /* Return true whe validity of KEY is sufficient. */
228 static int crypt_id_is_strong (crypt_key_t * key)
230 gpgme_validity_t val = GPGME_VALIDITY_UNKNOWN;
231 gpgme_user_id_t uid = NULL;
235 if ((key->flags & KEYFLAG_ISX509))
238 for (i = 0, uid = key->kobj->uids; (i < key->idx) && uid;
239 i++, uid = uid->next);
244 case GPGME_VALIDITY_UNKNOWN:
245 case GPGME_VALIDITY_UNDEFINED:
246 case GPGME_VALIDITY_NEVER:
247 case GPGME_VALIDITY_MARGINAL:
251 case GPGME_VALIDITY_FULL:
252 case GPGME_VALIDITY_ULTIMATE:
260 /* Return true when the KEY is valid, i.e. not marked as unusable. */
261 static int crypt_id_is_valid (crypt_key_t * key)
263 return !(key->flags & KEYFLAG_CANTUSE);
266 /* Return a bit vector describing how well the addresses ADDR and
267 U_ADDR match and whether KEY is valid. */
268 static int crypt_id_matches_addr (address_t * addr, address_t * u_addr,
273 if (crypt_id_is_valid (key))
274 rv |= CRYPT_KV_VALID;
276 if (crypt_id_is_strong (key))
277 rv |= CRYPT_KV_STRONGID;
279 if (addr->mailbox && u_addr->mailbox
280 && m_strcasecmp(addr->mailbox, u_addr->mailbox) == 0)
283 if (addr->personal && u_addr->personal
284 && m_strcasecmp(addr->personal, u_addr->personal) == 0)
285 rv |= CRYPT_KV_STRING;
292 * GPGME convenient functions.
295 /* Create a new gpgme context and return it. With FOR_SMIME set to
296 true, the protocol of the context is set to CMS. */
297 static gpgme_ctx_t create_gpgme_context (int for_smime)
302 err = gpgme_new (&ctx);
304 mutt_error (_("error creating gpgme context: %s\n"), gpgme_strerror (err));
310 err = gpgme_set_protocol (ctx, GPGME_PROTOCOL_CMS);
312 mutt_error (_("error enabling CMS protocol: %s\n"), gpgme_strerror (err));
321 /* Create a new gpgme data object. This is a wrapper to die on
323 static gpgme_data_t create_gpgme_data (void)
328 err = gpgme_data_new (&data);
330 mutt_error (_("error creating gpgme data object: %s\n"),
331 gpgme_strerror (err));
338 /* Create a new GPGME Data object from the mail body A. With CONVERT
339 passed as true, the lines are converted to CR,LF if required.
340 Return NULL on error or the gpgme_data_t object on success. */
341 static gpgme_data_t body_to_data_object (BODY * a, int convert)
343 char tempfile[_POSIX_PATH_MAX];
348 fptmp = m_tempfile(tempfile, sizeof(tempfile), NONULL(MCore.tmpdir), NULL);
350 mutt_perror (_("Can't create temporary file"));
354 mutt_write_mime_header (a, fptmp);
356 mutt_write_mime_body (a, fptmp);
360 unsigned char buf[1];
362 data = create_gpgme_data ();
364 while ((c = fgetc (fptmp)) != EOF) {
368 if (c == '\n' && !hadcr) {
370 gpgme_data_write (data, buf, 1);
375 /* FIXME: This is quite suboptimal */
377 gpgme_data_write (data, buf, 1);
379 gpgme_data_seek (data, 0, SEEK_SET);
381 err = gpgme_data_new_from_file (&data, tempfile, 1);
386 mutt_error (_("error allocating data object: %s\n"), gpgme_strerror (err));
393 /* Create a GPGME data object from the stream FP but limit the object
394 to LENGTH bytes starting at OFFSET bytes from the beginning of the
396 static gpgme_data_t file_to_data_object (FILE * fp, long offset, long length)
401 err = gpgme_data_new_from_filepart (&data, NULL, fp, offset, length);
403 mutt_error (_("error allocating data object: %s\n"), gpgme_strerror (err));
410 /* Write a GPGME data object to the stream FP. */
411 static int data_object_to_stream (gpgme_data_t data, FILE * fp)
417 err = ((gpgme_data_seek (data, 0, SEEK_SET) == -1)
418 ? gpgme_error_from_errno (errno) : 0);
420 mutt_error (_("error rewinding data object: %s\n"), gpgme_strerror (err));
424 while ((nread = gpgme_data_read (data, buf, sizeof (buf)))) {
425 /* fixme: we are not really converting CRLF to LF but just
426 skipping CR. Doing it correctly needs a more complex logic */
427 for (p = buf; nread; p++, nread--) {
433 mutt_perror ("[tempfile]");
438 mutt_error (_("error reading data object: %s\n"), strerror (errno));
444 /* Copy a data object to a newly created temporay file and return that
445 filename. Caller must free. With RET_FP not NULL, don't close the
446 stream but return it there. */
447 static char *data_object_to_tempfile (gpgme_data_t data, FILE ** ret_fp)
450 char tempfile[_POSIX_PATH_MAX];
454 fp = m_tempfile(tempfile, sizeof(tempfile), NONULL(MCore.tmpdir), NULL);
456 mutt_perror (_("Can't create temporary file"));
460 err = ((gpgme_data_seek (data, 0, SEEK_SET) == -1)
461 ? gpgme_error_from_errno (errno) : 0);
465 while ((nread = gpgme_data_read (data, buf, sizeof (buf)))) {
466 if (fwrite (buf, nread, 1, fp) != 1) {
467 mutt_perror (_("Can't create temporary file"));
479 mutt_error (_("error reading data object: %s\n"), gpgme_strerror (err));
486 return m_strdup(tempfile);
490 /* Create a GpgmeRecipientSet from the keys in the string KEYLIST.
491 The keys must be space delimited. */
492 static gpgme_key_t *create_recipient_set (const char *keylist,
493 gpgme_protocol_t protocol)
499 gpgme_key_t *rset = NULL;
500 unsigned int rset_n = 0;
501 gpgme_key_t key = NULL;
502 gpgme_ctx_t context = NULL;
504 err = gpgme_new (&context);
506 err = gpgme_set_protocol (context, protocol);
513 for (i = 0; *s && *s != ' ' && i < ssizeof(buf) - 1;)
517 if (i > 1 && buf[i - 1] == '!') {
518 /* The user selected to override the valididy of that
522 err = gpgme_get_key (context, buf, &key, 0);
524 key->uids->validity = GPGME_VALIDITY_FULL;
528 err = gpgme_get_key (context, buf, &key, 0);
531 p_realloc(&rset, rset_n + 1);
532 rset[rset_n++] = key;
535 mutt_error (_("error adding recipient `%s': %s\n"),
536 buf, gpgme_strerror (err));
544 /* NULL terminate. */
545 p_realloc(&rset, rset_n + 1);
546 rset[rset_n++] = NULL;
549 gpgme_release (context);
555 /* Make sure that the correct signer is set. Returns 0 on success. */
556 static int set_signer (gpgme_ctx_t ctx, int for_smime)
558 char *signid = for_smime ? SmimeDefaultKey : PgpSignAs;
561 gpgme_key_t key, key2;
563 if (!signid || !*signid)
566 listctx = create_gpgme_context (for_smime);
567 err = gpgme_op_keylist_start (listctx, signid, 1);
569 err = gpgme_op_keylist_next (listctx, &key);
571 gpgme_release (listctx);
572 mutt_error (_("secret key `%s' not found: %s\n"),
573 signid, gpgme_strerror (err));
576 err = gpgme_op_keylist_next (listctx, &key2);
578 gpgme_key_release (key);
579 gpgme_key_release (key2);
580 gpgme_release (listctx);
581 mutt_error (_("ambiguous specification of secret key `%s'\n"), signid);
584 gpgme_op_keylist_end (listctx);
585 gpgme_release (listctx);
587 gpgme_signers_clear (ctx);
588 err = gpgme_signers_add (ctx, key);
589 gpgme_key_release (key);
591 mutt_error (_("error setting secret key `%s': %s\n"),
592 signid, gpgme_strerror (err));
599 /* Encrypt the gpgme data object PLAINTEXT to the recipients in RSET
600 and return an allocated filename to a temporary file containing the
601 enciphered text. With USE_SMIME set to true, the smime backend is
602 used. With COMBINED_SIGNED a PGP message is signed and
603 encrypted. Returns NULL in case of error */
604 static char *encrypt_gpgme_object (gpgme_data_t plaintext, gpgme_key_t * rset,
605 int use_smime, int combined_signed)
609 gpgme_data_t ciphertext;
612 ctx = create_gpgme_context (use_smime);
614 gpgme_set_armor (ctx, 1);
616 ciphertext = create_gpgme_data ();
618 if (combined_signed) {
619 if (set_signer (ctx, use_smime)) {
620 gpgme_data_release (ciphertext);
624 err = gpgme_op_encrypt_sign (ctx, rset, GPGME_ENCRYPT_ALWAYS_TRUST,
625 plaintext, ciphertext);
628 err = gpgme_op_encrypt (ctx, rset, GPGME_ENCRYPT_ALWAYS_TRUST,
629 plaintext, ciphertext);
630 mutt_need_hard_redraw ();
632 mutt_error (_("error encrypting data: %s\n"), gpgme_strerror (err));
633 gpgme_data_release (ciphertext);
640 outfile = data_object_to_tempfile (ciphertext, NULL);
641 gpgme_data_release (ciphertext);
645 /* Find the "micalg" parameter from the last Gpgme operation on
646 context CTX. It is expected that this operation was a sign
647 operation. Return the algorithm name as a C string in buffer BUF
648 which must have been allocated by the caller with size BUFLEN.
649 Returns 0 on success or -1 in case of an error. The return string
650 is truncted to BUFLEN - 1. */
651 static int get_micalg (gpgme_ctx_t ctx, char *buf, ssize_t buflen)
653 gpgme_sign_result_t result = NULL;
654 const char *algorithm_name = NULL;
660 result = gpgme_op_sign_result (ctx);
662 algorithm_name = gpgme_hash_algo_name (result->signatures->hash_algo);
663 if (algorithm_name) {
664 m_strcpy(buf, buflen, algorithm_name);
668 return *buf ? 0 : -1;
671 static void print_time (time_t t, STATE * s)
675 setlocale (LC_TIME, "");
676 #ifdef HAVE_LANGINFO_D_T_FMT
677 strftime (p, sizeof (p), nl_langinfo (D_T_FMT), localtime (&t));
679 strftime (p, sizeof (p), "%c", localtime (&t));
681 setlocale (LC_TIME, "C");
682 state_attach_puts (p, s);
685 /* Implementation of `sign_message'. */
687 /* Sign the MESSAGE in body A either using OpenPGP or S/MIME when
688 USE_SMIME is passed as true. Returns the new body or NULL on
690 static BODY *sign_message (BODY * a, int use_smime)
697 gpgme_data_t message, signature;
699 convert_to_7bit (a); /* Signed data _must_ be in 7-bit format. */
701 message = body_to_data_object (a, 1);
704 signature = create_gpgme_data ();
706 ctx = create_gpgme_context (use_smime);
708 gpgme_set_armor (ctx, 1);
710 if (set_signer (ctx, use_smime)) {
711 gpgme_data_release (signature);
716 err = gpgme_op_sign (ctx, message, signature, GPGME_SIG_MODE_DETACH);
717 mutt_need_hard_redraw ();
718 gpgme_data_release (message);
720 gpgme_data_release (signature);
722 mutt_error (_("error signing data: %s\n"), gpgme_strerror (err));
726 sigfile = data_object_to_tempfile (signature, NULL);
727 gpgme_data_release (signature);
734 t->type = TYPEMULTIPART;
735 t->subtype = m_strdup("signed");
736 t->encoding = ENC7BIT;
738 t->disposition = DISPINLINE;
740 parameter_set_boundary(&t->parameter);
741 parameter_setval(&t->parameter, "protocol",
742 use_smime ? "application/pkcs7-signature"
743 : "application/pgp-signature");
744 /* Get the micalg from gpgme. Old gpgme versions don't support this
745 for S/MIME so we assume sha-1 in this case. */
746 if (!get_micalg (ctx, buf, sizeof buf))
747 parameter_setval(&t->parameter, "micalg", buf);
749 parameter_setval(&t->parameter, "micalg", "sha1");
755 t->parts->next = body_new();
757 t->type = TYPEAPPLICATION;
759 t->subtype = m_strdup("pkcs7-signature");
760 parameter_setval(&t->parameter, "name", "smime.p7s");
761 t->encoding = ENCBASE64;
763 t->disposition = DISPATTACH;
764 t->d_filename = m_strdup("smime.p7s");
767 t->subtype = m_strdup("pgp-signature");
769 t->disposition = DISPINLINE;
770 t->encoding = ENC7BIT;
772 t->filename = sigfile;
773 t->unlink = 1; /* ok to remove this file after sending. */
779 BODY *crypt_pgp_sign_message (BODY * a)
781 return sign_message (a, 0);
784 BODY *crypt_smime_sign_message (BODY * a)
786 return sign_message (a, 1);
790 * Implementation of `encrypt_message'.
793 /* Encrypt the mail body A to all keys given as space separated keyids
794 or fingerprints in KEYLIST and return the encrypted body. */
795 BODY *crypt_pgp_encrypt_message (BODY * a, char *keylist, int sign)
797 char *outfile = NULL;
799 gpgme_key_t *rset = NULL;
800 gpgme_data_t plaintext;
802 rset = create_recipient_set (keylist, GPGME_PROTOCOL_OpenPGP);
808 plaintext = body_to_data_object (a, 0);
814 outfile = encrypt_gpgme_object (plaintext, rset, 0, sign);
815 gpgme_data_release (plaintext);
821 t->type = TYPEMULTIPART;
822 t->subtype = m_strdup("encrypted");
823 t->encoding = ENC7BIT;
825 t->disposition = DISPINLINE;
827 parameter_set_boundary(&t->parameter);
828 parameter_setval(&t->parameter, "protocol", "application/pgp-encrypted");
830 t->parts = body_new();
831 t->parts->type = TYPEAPPLICATION;
832 t->parts->subtype = m_strdup("pgp-encrypted");
833 t->parts->encoding = ENC7BIT;
835 t->parts->next = body_new();
836 t->parts->next->type = TYPEAPPLICATION;
837 t->parts->next->subtype = m_strdup("octet-stream");
838 t->parts->next->encoding = ENC7BIT;
839 t->parts->next->filename = outfile;
840 t->parts->next->use_disp = 1;
841 t->parts->next->disposition = DISPINLINE;
842 t->parts->next->unlink = 1; /* delete after sending the message */
843 t->parts->next->d_filename = m_strdup("msg.asc"); /* non pgp/mime
850 * Implementation of `smime_build_smime_entity'.
853 /* Encrypt the mail body A to all keys given as space separated
854 fingerprints in KEYLIST and return the S/MIME encrypted body. */
855 BODY *crypt_smime_build_smime_entity (BODY * a, char *keylist)
857 char *outfile = NULL;
859 gpgme_key_t *rset = NULL;
860 gpgme_data_t plaintext;
862 rset = create_recipient_set (keylist, GPGME_PROTOCOL_CMS);
866 plaintext = body_to_data_object (a, 0);
872 outfile = encrypt_gpgme_object (plaintext, rset, 1, 0);
873 gpgme_data_release (plaintext);
879 t->type = TYPEAPPLICATION;
880 t->subtype = m_strdup("pkcs7-mime");
881 parameter_setval(&t->parameter, "name", "smime.p7m");
882 parameter_setval(&t->parameter, "smime-type", "enveloped-data");
883 t->encoding = ENCBASE64; /* The output of OpenSSL SHOULD be binary */
885 t->disposition = DISPATTACH;
886 t->d_filename = m_strdup("smime.p7m");
887 t->filename = outfile;
888 t->unlink = 1; /*delete after sending the message */
896 /* Implementation of `verify_one'. */
898 /* Display the common attributes of the signature summary SUM.
899 Return 1 if there is is a severe warning.
901 static int show_sig_summary (unsigned long sum,
902 gpgme_ctx_t ctx, gpgme_key_t key, int idx,
907 if ((sum & GPGME_SIGSUM_KEY_REVOKED)) {
908 state_attach_puts (_("Warning: One of the keys has been revoked\n"), s);
912 if ((sum & GPGME_SIGSUM_KEY_EXPIRED)) {
913 time_t at = key->subkeys->expires ? key->subkeys->expires : 0;
916 state_attach_puts (_("Warning: The key used to create the "
917 "signature expired at: "), s);
919 state_attach_puts ("\n", s);
922 state_attach_puts (_("Warning: At least one certification key "
923 "has expired\n"), s);
926 if ((sum & GPGME_SIGSUM_SIG_EXPIRED)) {
927 gpgme_verify_result_t result;
928 gpgme_signature_t sig;
931 result = gpgme_op_verify_result (ctx);
933 for (sig = result->signatures, i = 0; sig && (i < idx);
934 sig = sig->next, i++);
936 state_attach_puts (_("Warning: The signature expired at: "), s);
937 print_time (sig ? sig->exp_timestamp : 0, s);
938 state_attach_puts ("\n", s);
941 if ((sum & GPGME_SIGSUM_KEY_MISSING))
942 state_attach_puts (_("Can't verify due to a missing "
943 "key or certificate\n"), s);
945 if ((sum & GPGME_SIGSUM_CRL_MISSING)) {
946 state_attach_puts (_("The CRL is not available\n"), s);
950 if ((sum & GPGME_SIGSUM_CRL_TOO_OLD)) {
951 state_attach_puts (_("Available CRL is too old\n"), s);
955 if ((sum & GPGME_SIGSUM_BAD_POLICY))
956 state_attach_puts (_("A policy requirement was not met\n"), s);
958 if ((sum & GPGME_SIGSUM_SYS_ERROR)) {
959 const char *t0 = NULL, *t1 = NULL;
960 gpgme_verify_result_t result;
961 gpgme_signature_t sig;
964 state_attach_puts (_("A system error occurred"), s);
966 /* Try to figure out some more detailed system error information. */
967 result = gpgme_op_verify_result (ctx);
968 for (sig = result->signatures, i = 0; sig && (i < idx);
969 sig = sig->next, i++);
972 t1 = sig->wrong_key_usage ? "Wrong_Key_Usage" : "";
976 state_attach_puts (": ", s);
978 state_attach_puts (t0, s);
979 if (t1 && !(t0 && !m_strcmp(t0, t1))) {
981 state_attach_puts (",", s);
982 state_attach_puts (t1, s);
985 state_attach_puts ("\n", s);
992 static void show_fingerprint (gpgme_key_t key, STATE * state)
997 const char *prefix = _("Fingerprint: ");
1002 s = key->subkeys ? key->subkeys->fpr : NULL;
1005 is_pgp = (key->protocol == GPGME_PROTOCOL_OpenPGP);
1007 bufsize = m_strlen(prefix) + m_strlen(s) * 4 + 2;
1008 buf = p_new(char, bufsize);
1009 m_strcpy(buf, bufsize, prefix);
1010 p = buf + m_strlen(buf);
1011 if (is_pgp && m_strlen(s) == 40) { /* PGP v4 style formatted. */
1012 for (i = 0; *s && s[1] && s[2] && s[3] && s[4]; s += 4, i++) {
1023 for (i = 0; *s && s[1] && s[2]; s += 2, i++) {
1026 *p++ = is_pgp ? ' ' : ':';
1027 if (is_pgp && i == 7)
1032 /* just in case print remaining odd digits */
1037 state_attach_puts (buf, state);
1041 /* Show the valididy of a key used for one signature. */
1042 static void show_one_sig_validity (gpgme_ctx_t ctx, int idx, STATE * s)
1044 gpgme_verify_result_t result = NULL;
1045 gpgme_signature_t sig = NULL;
1046 const char *txt = NULL;
1048 result = gpgme_op_verify_result (ctx);
1050 for (sig = result->signatures; sig && (idx > 0); sig = sig->next, idx--);
1052 switch (sig ? sig->validity : 0) {
1053 case GPGME_VALIDITY_UNKNOWN:
1054 txt = _("WARNING: We have NO indication whether "
1055 "the key belongs to the person named " "as shown above\n");
1057 case GPGME_VALIDITY_UNDEFINED:
1059 case GPGME_VALIDITY_NEVER:
1060 txt = _("WARNING: The key does NOT BELONG to "
1061 "the person named as shown above\n");
1063 case GPGME_VALIDITY_MARGINAL:
1064 txt = _("WARNING: It is NOT certain that the key "
1065 "belongs to the person named as shown above\n");
1067 case GPGME_VALIDITY_FULL:
1068 case GPGME_VALIDITY_ULTIMATE:
1073 state_attach_puts (txt, s);
1076 /* Show information about one signature. This fucntion is called with
1077 the context CTX of a sucessful verification operation and the
1078 enumerator IDX which should start at 0 and incremete for each
1081 Return values are: 0 for normal procession, 1 for a bad signature,
1082 2 for a signature with a warning or -1 for no more signature. */
1083 static int show_one_sig_status (gpgme_ctx_t ctx, int idx, STATE * s)
1086 const char *fpr, *uid;
1087 gpgme_key_t key = NULL;
1088 int i, anybad = 0, anywarn = 0;
1090 gpgme_user_id_t uids = NULL;
1091 gpgme_verify_result_t result;
1092 gpgme_signature_t sig;
1093 gpgme_error_t err = GPG_ERR_NO_ERROR;
1095 result = gpgme_op_verify_result (ctx);
1097 /* FIXME: this code should use a static variable and remember
1098 the current position in the list of signatures, IMHO.
1101 for (i = 0, sig = result->signatures; sig && (i < idx);
1102 i++, sig = sig->next);
1104 return -1; /* Signature not found. */
1106 if (signature_key) {
1107 gpgme_key_release (signature_key);
1108 signature_key = NULL;
1111 created = sig->timestamp;
1115 if (gpg_err_code (sig->status) != GPG_ERR_NO_ERROR)
1118 err = gpgme_get_key (ctx, fpr, &key, 0); /* secret key? */
1120 uid = (key->uids && key->uids->uid) ? key->uids->uid : "[?]";
1122 signature_key = key;
1125 key = NULL; /* Old gpgme versions did not set KEY to NULL on
1126 error. Do it here to avoid a double free. */
1130 if (!s || !s->fpout || !(s->flags & M_DISPLAY)); /* No state information so no way to print anything. */
1132 state_attach_puts (_("Error getting key information: "), s);
1133 state_attach_puts (gpg_strerror (err), s);
1134 state_attach_puts ("\n", s);
1137 else if ((sum & GPGME_SIGSUM_GREEN)) {
1138 state_attach_puts (_("Good signature from: "), s);
1139 state_attach_puts (uid, s);
1140 state_attach_puts ("\n", s);
1141 for (i = 1, uids = key->uids; uids; i++, uids = uids->next) {
1143 /* Skip primary UID. */
1147 state_attach_puts (_(" aka: "), s);
1148 state_attach_puts (uids->uid, s);
1149 state_attach_puts ("\n", s);
1151 state_attach_puts (_(" created: "), s);
1152 print_time (created, s);
1153 state_attach_puts ("\n", s);
1154 if (show_sig_summary (sum, ctx, key, idx, s))
1156 show_one_sig_validity (ctx, idx, s);
1158 else if ((sum & GPGME_SIGSUM_RED)) {
1159 state_attach_puts (_("*BAD* signature claimed to be from: "), s);
1160 state_attach_puts (uid, s);
1161 state_attach_puts ("\n", s);
1162 show_sig_summary (sum, ctx, key, idx, s);
1164 else if (!anybad && key && (key->protocol == GPGME_PROTOCOL_OpenPGP)) { /* We can't decide (yellow) but this is a PGP key with a good
1165 signature, so we display what a PGP user expects: The name,
1166 fingerprint and the key validity (which is neither fully or
1168 state_attach_puts (_("Good signature from: "), s);
1169 state_attach_puts (uid, s);
1170 state_attach_puts ("\n", s);
1171 state_attach_puts (_(" created: "), s);
1172 print_time (created, s);
1173 state_attach_puts ("\n", s);
1174 show_one_sig_validity (ctx, idx, s);
1175 show_fingerprint (key, s);
1176 if (show_sig_summary (sum, ctx, key, idx, s))
1179 else { /* can't decide (yellow) */
1181 state_attach_puts (_("Error checking signature"), s);
1182 state_attach_puts ("\n", s);
1183 show_sig_summary (sum, ctx, key, idx, s);
1186 if (key != signature_key)
1187 gpgme_key_release (key);
1190 return anybad ? 1 : anywarn ? 2 : 0;
1193 /* Do the actual verification step. With IS_SMIME set to true we
1194 assume S/MIME (surprise!) */
1195 static int verify_one (BODY * sigbdy, STATE * s,
1196 const char *tempfile, int is_smime)
1202 gpgme_data_t signature, message;
1204 signature = file_to_data_object (s->fpin, sigbdy->offset, sigbdy->length);
1208 /* We need to tell gpgme about the encoding because the backend can't
1209 auto-detect plain base-64 encoding which is used by S/MIME. */
1211 gpgme_data_set_encoding (signature, GPGME_DATA_ENCODING_BASE64);
1213 err = gpgme_data_new_from_file (&message, tempfile, 1);
1215 gpgme_data_release (signature);
1216 mutt_error (_("error allocating data object: %s\n"), gpgme_strerror (err));
1219 ctx = create_gpgme_context (is_smime);
1221 /* Note: We don't need a current time output because GPGME avoids
1222 such an attack by separating the meta information from the
1224 state_attach_puts (_("[-- Begin signature information --]\n"), s);
1226 err = gpgme_op_verify (ctx, signature, message, NULL);
1227 mutt_need_hard_redraw ();
1231 snprintf (buf, sizeof (buf) - 1,
1232 _("Error: verification failed: %s\n"), gpgme_strerror (err));
1233 state_attach_puts (buf, s);
1235 else { /* Verification succeeded, see what the result is. */
1239 if (signature_key) {
1240 gpgme_key_release (signature_key);
1241 signature_key = NULL;
1244 for (idx = 0; (res = show_one_sig_status (ctx, idx, s)) != -1; idx++) {
1255 gpgme_verify_result_t result;
1256 gpgme_sig_notation_t notation;
1257 gpgme_signature_t sig;
1259 result = gpgme_op_verify_result (ctx);
1261 for (sig = result->signatures; sig; sig = sig->next) {
1262 if (sig->notations) {
1263 state_attach_puts ("*** Begin Notation (signature by: ", s);
1264 state_attach_puts (sig->fpr, s);
1265 state_attach_puts (") ***\n", s);
1266 for (notation = sig->notations; notation; notation = notation->next)
1268 if (notation->name) {
1269 state_attach_puts (notation->name, s);
1270 state_attach_puts ("=", s);
1272 if (notation->value) {
1273 state_attach_puts (notation->value, s);
1274 if (!(*notation->value
1275 && (notation->value[m_strlen(notation->value) - 1] ==
1277 state_attach_puts ("\n", s);
1280 state_attach_puts ("*** End Notation ***\n", s);
1286 gpgme_release (ctx);
1288 state_attach_puts (_("[-- End signature information --]\n\n"), s);
1290 return badsig ? 1 : anywarn ? 2 : 0;
1293 int crypt_pgp_verify_one (BODY * sigbdy, STATE * s, const char *tempfile)
1295 return verify_one (sigbdy, s, tempfile, 0);
1298 int crypt_smime_verify_one (BODY * sigbdy, STATE * s, const char *tempfile)
1300 return verify_one (sigbdy, s, tempfile, 1);
1304 * Implementation of `decrypt_part'.
1307 /* Decrypt a PGP or SMIME message (depending on the boolean flag
1308 IS_SMIME) with body A described further by state S. Write
1309 plaintext out to file FPOUT and return a new body. For PGP returns
1310 a flag in R_IS_SIGNED to indicate whether this is a combined
1311 encrypted and signed message, for S/MIME it returns true when it is
1312 not a encrypted but a signed message. */
1313 static BODY *decrypt_part (BODY * a, STATE * s, FILE * fpout, int is_smime,
1320 gpgme_data_t ciphertext, plaintext;
1321 int maybe_signed = 0;
1328 ctx = create_gpgme_context (is_smime);
1331 /* Make a data object from the body, create context etc. */
1332 ciphertext = file_to_data_object (s->fpin, a->offset, a->length);
1335 plaintext = create_gpgme_data ();
1337 /* Do the decryption or the verification in case of the S/MIME hack. */
1338 if ((!is_smime) || maybe_signed) {
1340 err = gpgme_op_decrypt_verify (ctx, ciphertext, plaintext);
1341 else if (maybe_signed)
1342 err = gpgme_op_verify (ctx, ciphertext, NULL, plaintext);
1345 /* Check wether signatures have been verified. */
1346 gpgme_verify_result_t verify_result = gpgme_op_verify_result (ctx);
1348 if (verify_result->signatures)
1353 err = gpgme_op_decrypt (ctx, ciphertext, plaintext);
1354 gpgme_data_release (ciphertext);
1356 if (is_smime && !maybe_signed && gpg_err_code (err) == GPG_ERR_NO_DATA) {
1357 /* Check whether this might be a signed message despite what
1358 the mime header told us. Retry then. gpgsm returns the
1359 error information "unsupported Algorithm '?'" but gpgme
1360 will not store this unknown algorithm, thus we test that
1361 it has not been set. */
1362 gpgme_decrypt_result_t result;
1364 result = gpgme_op_decrypt_result (ctx);
1365 if (!result->unsupported_algorithm) {
1367 gpgme_data_release (plaintext);
1371 mutt_need_hard_redraw ();
1372 if ((s->flags & M_DISPLAY)) {
1375 snprintf (buf, sizeof (buf) - 1,
1376 _("[-- Error: decryption failed: %s --]\n\n"),
1377 gpgme_strerror (err));
1378 state_attach_puts (buf, s);
1380 gpgme_data_release (plaintext);
1381 gpgme_release (ctx);
1384 mutt_need_hard_redraw ();
1386 /* Read the output from GPGME, and make sure to change CRLF to LF,
1387 otherwise read_mime_header has a hard time parsing the message. */
1388 if (data_object_to_stream (plaintext, fpout)) {
1389 gpgme_data_release (plaintext);
1390 gpgme_release (ctx);
1393 gpgme_data_release (plaintext);
1395 a->is_signed_data = 0;
1401 a->is_signed_data = 1;
1403 *r_is_signed = -1; /* A signature exists. */
1405 if ((s->flags & M_DISPLAY))
1406 state_attach_puts (_("[-- Begin signature " "information --]\n"), s);
1407 for (idx = 0; (res = show_one_sig_status (ctx, idx, s)) != -1; idx++) {
1413 if (!anybad && idx && r_is_signed && *r_is_signed)
1414 *r_is_signed = anywarn ? 2 : 1; /* Good signature. */
1416 if ((s->flags & M_DISPLAY))
1417 state_attach_puts (_("[-- End signature " "information --]\n\n"), s);
1419 gpgme_release (ctx);
1424 tattach = mutt_read_mime_header (fpout, 0);
1427 * Need to set the length of this body part.
1429 fstat (fileno (fpout), &info);
1430 tattach->length = info.st_size - tattach->offset;
1432 tattach->warnsig = anywarn;
1434 /* See if we need to recurse on this MIME part. */
1435 mutt_parse_part (fpout, tattach);
1441 /* Decrypt a PGP/MIME message in FPIN and B and return a new body and
1442 the stream in CUR and FPOUT. Returns 0 on success. */
1443 int crypt_pgp_decrypt_mime (FILE * fpin, FILE ** fpout, BODY * b, BODY ** cur)
1445 char tempfile[_POSIX_PATH_MAX];
1447 BODY *first_part = b;
1450 first_part->goodsig = 0;
1451 first_part->warnsig = 0;
1453 if (!mutt_is_multipart_encrypted (b))
1456 if (!b->parts || !b->parts->next)
1463 *fpout = m_tempfile(tempfile, sizeof(tempfile), NONULL(MCore.tmpdir), NULL);
1465 mutt_perror (_("Can't create temporary file"));
1470 *cur = decrypt_part (b, &s, *fpout, 0, &is_signed);
1473 first_part->goodsig = 1;
1475 return *cur ? 0 : -1;
1479 /* Decrypt a S/MIME message in FPIN and B and return a new body and
1480 the stream in CUR and FPOUT. Returns 0 on success. */
1481 int crypt_smime_decrypt_mime (FILE * fpin, FILE ** fpout, BODY * b,
1484 char tempfile[_POSIX_PATH_MAX];
1488 long saved_b_offset;
1489 ssize_t saved_b_length;
1492 if (!mutt_is_application_smime (b))
1498 /* Decode the body - we need to pass binary CMS to the
1499 backend. The backend allows for Base64 encoded data but it does
1500 not allow for QP which I have seen in some messages. So better
1502 saved_b_type = b->type;
1503 saved_b_offset = b->offset;
1504 saved_b_length = b->length;
1507 fseeko (s.fpin, b->offset, 0);
1508 tmpfp = m_tempfile (tempfile, sizeof(tempfile), NONULL(MCore.tmpdir), NULL);
1510 mutt_perror (_("Can't create temporary file"));
1513 mutt_unlink (tempfile);
1516 mutt_decode_attachment (b, &s);
1518 b->length = ftello (s.fpout);
1525 *fpout = m_tempfile(tempfile, sizeof(tempfile), NONULL(MCore.tmpdir), NULL);
1527 mutt_perror (_("Can't create temporary file"));
1530 mutt_unlink (tempfile);
1532 *cur = decrypt_part (b, &s, *fpout, 1, &is_signed);
1534 (*cur)->goodsig = is_signed > 0;
1535 b->type = saved_b_type;
1536 b->length = saved_b_length;
1537 b->offset = saved_b_offset;
1540 if (*cur && !is_signed && !(*cur)->parts
1541 && mutt_is_application_smime (*cur)) {
1542 /* Assume that this is a opaque signed s/mime message. This is
1543 an ugly way of doing it but we have anyway a problem with
1544 arbitrary encoded S/MIME messages: Only the outer part may be
1545 encrypted. The entire mime parsing should be revamped,
1546 probably by keeping the temportary files so that we don't
1547 need to decrypt them all the time. Inner parts of an
1548 encrypted part can then pint into this file and tehre won't
1549 never be a need to decrypt again. This needs a partial
1550 rewrite of the MIME engine. */
1554 saved_b_type = bb->type;
1555 saved_b_offset = bb->offset;
1556 saved_b_length = bb->length;
1559 fseeko (s.fpin, bb->offset, 0);
1560 tmpfp = m_tempfile (tempfile, sizeof(tempfile), NONULL(MCore.tmpdir), NULL);
1562 mutt_perror (_("Can't create temporary file"));
1565 mutt_unlink (tempfile);
1568 mutt_decode_attachment (bb, &s);
1570 bb->length = ftello (s.fpout);
1578 *fpout = m_tempfile(tempfile, sizeof(tempfile), NONULL(MCore.tmpdir), NULL);
1580 mutt_perror (_("Can't create temporary file"));
1583 mutt_unlink (tempfile);
1585 tmp_b = decrypt_part (bb, &s, *fpout, 1, &is_signed);
1587 tmp_b->goodsig = is_signed > 0;
1588 bb->type = saved_b_type;
1589 bb->length = saved_b_length;
1590 bb->offset = saved_b_offset;
1593 body_list_wipe(cur);
1596 return *cur ? 0 : -1;
1601 * Implementation of `pgp_check_traditional'.
1604 static int pgp_check_traditional_one_body (FILE * fp, BODY * b,
1607 char tempfile[_POSIX_PATH_MAX];
1608 char buf[HUGE_STRING];
1615 if (b->type != TYPETEXT)
1618 if (tagged_only && !b->tagged)
1621 tempfd = m_tempfd(tempfile, sizeof(tempfile), NONULL(MCore.tmpdir), NULL);
1622 if (mutt_decode_save_attachment (fp, b, tempfd, 0) != 0) {
1627 if ((tfp = fopen(tempfile, "r")) == NULL) {
1632 while (fgets (buf, sizeof (buf), tfp)) {
1633 if (!m_strncmp("-----BEGIN PGP ", buf, 15)) {
1634 if (!m_strcmp("MESSAGE-----\n", buf + 15))
1636 else if (!m_strcmp("SIGNED MESSAGE-----\n", buf + 15))
1646 /* fix the content type */
1648 parameter_setval(&b->parameter, "format", "fixed");
1649 parameter_setval(&b->parameter, "x-action",
1650 enc ? "pgp-encrypted" : "pgp-signed");
1654 int crypt_pgp_check_traditional (FILE * fp, BODY * b, int tagged_only)
1659 for (; b; b = b->next) {
1660 if (is_multipart (b))
1661 rv = (crypt_pgp_check_traditional (fp, b->parts, tagged_only) || rv);
1662 else if (b->type == TYPETEXT) {
1663 if ((r = mutt_is_application_pgp (b)))
1666 rv = (pgp_check_traditional_one_body (fp, b, tagged_only) || rv);
1673 /* Implementation of `application_handler'. */
1676 Copy a clearsigned message, and strip the signature and PGP's
1679 XXX - charset handling: We assume that it is safe to do
1680 character set decoding first, dash decoding second here, while
1681 we do it the other way around in the main handler.
1683 (Note that we aren't worse than Outlook & Cie in this, and also
1684 note that we can successfully handle anything produced by any
1685 existing versions of mutt.) */
1687 static void copy_clearsigned (gpgme_data_t data, STATE * s, char *charset)
1689 char buf[HUGE_STRING];
1690 short complete, armor_header;
1695 fname = data_object_to_tempfile (data, &fp);
1701 fc = fgetconv_open (fp, charset, MCharset.charset, M_ICONV_HOOK_FROM);
1703 for (complete = 1, armor_header = 1;
1704 fgetconvs (buf, sizeof (buf), fc) != NULL;
1705 complete = strchr (buf, '\n') != NULL) {
1708 state_puts (buf, s);
1712 if (!m_strcmp(buf, "-----BEGIN PGP SIGNATURE-----\n"))
1722 state_puts (s->prefix, s);
1724 if (buf[0] == '-' && buf[1] == ' ')
1725 state_puts (buf + 2, s);
1727 state_puts (buf, s);
1730 fgetconv_close (&fc);
1735 /* Support for classic_application/pgp */
1736 int crypt_pgp_application_pgp_handler (BODY * m, STATE * s)
1738 int needpass = -1, pgp_keyblock = 0;
1742 off_t last_pos, offset;
1743 char buf[HUGE_STRING];
1744 FILE *pgpout = NULL;
1746 gpgme_error_t err = 0;
1747 gpgme_data_t armored_data = NULL;
1749 short maybe_goodsig = 1;
1750 short have_any_sigs = 0;
1752 char body_charset[STRING]; /* Only used for clearsigned messages. */
1754 /* For clearsigned messages we won't be able to get a character set
1755 but we know that this may only be text thus we assume Latin-1
1757 if (!mutt_get_body_charset (body_charset, sizeof (body_charset), m))
1758 m_strcpy(body_charset, sizeof(body_charset), "iso-8859-1");
1760 fseeko (s->fpin, m->offset, 0);
1761 last_pos = m->offset;
1763 for (bytes = m->length; bytes > 0;) {
1764 if (fgets (buf, sizeof (buf), s->fpin) == NULL)
1767 offset = ftello (s->fpin);
1768 bytes -= (offset - last_pos); /* don't rely on m_strlen(buf) */
1771 if (!m_strncmp("-----BEGIN PGP ", buf, 15)) {
1773 start_pos = last_pos;
1775 if (!m_strcmp("MESSAGE-----\n", buf + 15))
1777 else if (!m_strcmp("SIGNED MESSAGE-----\n", buf + 15)) {
1781 else if (!option (OPTDONTHANDLEPGPKEYS) &&
1782 !m_strcmp("PUBLIC KEY BLOCK-----\n", buf + 15)) {
1787 /* XXX - we may wish to recode here */
1789 state_puts (s->prefix, s);
1790 state_puts (buf, s);
1794 have_any_sigs = (have_any_sigs || (clearsign && (s->flags & M_VERIFY)));
1796 /* Copy PGP material to an data container */
1797 armored_data = create_gpgme_data ();
1798 gpgme_data_write (armored_data, buf, m_strlen(buf));
1799 while (bytes > 0 && fgets (buf, sizeof (buf) - 1, s->fpin) != NULL) {
1800 offset = ftello (s->fpin);
1801 bytes -= (offset - last_pos); /* don't rely on m_strlen(buf) */
1804 gpgme_data_write (armored_data, buf, m_strlen(buf));
1806 if ((needpass && !m_strcmp("-----END PGP MESSAGE-----\n", buf))
1808 && (!m_strcmp("-----END PGP SIGNATURE-----\n", buf)
1809 || !m_strcmp("-----END PGP PUBLIC KEY BLOCK-----\n",
1814 /* Invoke PGP if needed */
1815 if (!clearsign || (s->flags & M_VERIFY)) {
1816 unsigned int sig_stat = 0;
1817 gpgme_data_t plaintext;
1820 plaintext = create_gpgme_data ();
1821 ctx = create_gpgme_context (0);
1824 err = gpgme_op_verify (ctx, armored_data, NULL, plaintext);
1826 err = gpgme_op_decrypt_verify (ctx, armored_data, plaintext);
1827 if (gpg_err_code (err) == GPG_ERR_NO_DATA) {
1828 /* Decrypt verify can't handle signed only messages. */
1829 err = (gpgme_data_seek (armored_data, 0, SEEK_SET) == -1)
1830 ? gpgme_error_from_errno (errno) : 0;
1831 /* Must release plaintext so that we supply an
1832 uninitialized object. */
1833 gpgme_data_release (plaintext);
1834 plaintext = create_gpgme_data ();
1835 err = gpgme_op_verify (ctx, armored_data, NULL, plaintext);
1842 snprintf (errbuf, sizeof (errbuf) - 1,
1843 _("Error: decryption/verification failed: %s\n"),
1844 gpgme_strerror (err));
1845 state_attach_puts (errbuf, s);
1847 else { /* Decryption/Verification succeeded */
1851 /* Check wether signatures have been verified. */
1852 gpgme_verify_result_t verify_result;
1854 verify_result = gpgme_op_verify_result (ctx);
1855 if (verify_result->signatures)
1861 if ((s->flags & M_DISPLAY) && sig_stat) {
1866 state_attach_puts (_("[-- Begin signature "
1867 "information --]\n"), s);
1870 (res = show_one_sig_status (ctx, idx, s)) != -1; idx++) {
1879 state_attach_puts (_("[-- End signature "
1880 "information --]\n\n"), s);
1883 tmpfname = data_object_to_tempfile (plaintext, &pgpout);
1886 state_attach_puts (_("Error: copy data failed\n"), s);
1890 p_delete(&tmpfname);
1893 gpgme_release (ctx);
1897 * Now, copy cleartext to the screen. NOTE - we expect that PGP
1898 * outputs utf-8 cleartext. This may not always be true, but it
1899 * seems to be a reasonable guess.
1902 if (s->flags & M_DISPLAY) {
1904 state_attach_puts (_("[-- BEGIN PGP MESSAGE --]\n\n"), s);
1905 else if (pgp_keyblock)
1906 state_attach_puts (_("[-- BEGIN PGP PUBLIC KEY BLOCK --]\n"), s);
1908 state_attach_puts (_("[-- BEGIN PGP SIGNED MESSAGE --]\n\n"), s);
1912 copy_clearsigned (armored_data, s, body_charset);
1919 fc = fgetconv_open (pgpout, "utf-8", MCharset.charset, 0);
1920 while ((c = fgetconv (fc)) != EOF) {
1922 if (c == '\n' && s->prefix)
1923 state_puts (s->prefix, s);
1925 fgetconv_close (&fc);
1928 if (s->flags & M_DISPLAY) {
1929 state_putc ('\n', s);
1931 state_attach_puts (_("[-- END PGP MESSAGE --]\n"), s);
1932 else if (pgp_keyblock)
1933 state_attach_puts (_("[-- END PGP PUBLIC KEY BLOCK --]\n"), s);
1935 state_attach_puts (_("[-- END PGP SIGNED MESSAGE --]\n"), s);
1943 /* XXX - we may wish to recode here */
1945 state_puts (s->prefix, s);
1946 state_puts (buf, s);
1950 m->goodsig = (maybe_goodsig && have_any_sigs);
1952 if (needpass == -1) {
1953 state_attach_puts (_("[-- Error: could not find beginning"
1954 " of PGP message! --]\n\n"), s);
1960 /* Implementation of `encrypted_handler'. */
1962 /* MIME handler for pgp/mime encrypted messages. */
1963 int crypt_pgp_encrypted_handler (BODY * a, STATE * s)
1965 char tempfile[_POSIX_PATH_MAX];
1968 BODY *orig_body = a;
1973 if (!a || a->type != TYPEAPPLICATION || !a->subtype
1974 || ascii_strcasecmp ("pgp-encrypted", a->subtype)
1975 || !a->next || a->next->type != TYPEAPPLICATION || !a->next->subtype
1976 || ascii_strcasecmp ("octet-stream", a->next->subtype)) {
1977 if (s->flags & M_DISPLAY)
1978 state_attach_puts (_("[-- Error: malformed PGP/MIME message! --]\n\n"),
1983 /* Move forward to the application/pgp-encrypted body. */
1986 fpout = m_tempfile(tempfile, sizeof(tempfile), NONULL(MCore.tmpdir), NULL);
1988 if (s->flags & M_DISPLAY)
1989 state_attach_puts (_("[-- Error: could not create temporary file! "
1994 tattach = decrypt_part (a, s, fpout, 0, &is_signed);
1996 tattach->goodsig = is_signed > 0;
1998 if (s->flags & M_DISPLAY)
1999 state_attach_puts (is_signed ?
2001 ("[-- The following data is PGP/MIME signed and encrypted --]\n\n") :
2002 _("[-- The following data is PGP/MIME encrypted --]\n\n"), s);
2005 FILE *savefp = s->fpin;
2008 rc = mutt_body_handler (tattach, s);
2013 * if a multipart/signed is the _only_ sub-part of a
2014 * multipart/encrypted, cache signature verification
2017 if (mutt_is_multipart_signed (tattach) && !tattach->next)
2018 orig_body->goodsig |= tattach->goodsig;
2020 if (s->flags & M_DISPLAY) {
2021 state_puts ("\n", s);
2022 state_attach_puts (is_signed ?
2024 ("[-- End of PGP/MIME signed and encrypted data --]\n")
2025 : _("[-- End of PGP/MIME encrypted data --]\n"), s);
2028 body_list_wipe(&tattach);
2032 mutt_unlink (tempfile);
2036 /* Support for application/smime */
2037 int crypt_smime_application_smime_handler (BODY * a, STATE * s)
2039 char tempfile[_POSIX_PATH_MAX];
2046 fpout = m_tempfile(tempfile, sizeof(tempfile), NONULL(MCore.tmpdir), NULL);
2048 if (s->flags & M_DISPLAY)
2049 state_attach_puts (_("[-- Error: could not create temporary file! "
2054 tattach = decrypt_part (a, s, fpout, 1, &is_signed);
2056 tattach->goodsig = is_signed > 0;
2058 if (s->flags & M_DISPLAY)
2059 state_attach_puts (is_signed ?
2060 _("[-- The following data is S/MIME signed --]\n\n") :
2061 _("[-- The following data is S/MIME encrypted --]\n\n"), s);
2064 FILE *savefp = s->fpin;
2067 rc = mutt_body_handler (tattach, s);
2072 * if a multipart/signed is the _only_ sub-part of a
2073 * multipart/encrypted, cache signature verification
2076 if (mutt_is_multipart_signed (tattach) && !tattach->next) {
2077 if (!(a->goodsig = tattach->goodsig))
2078 a->warnsig = tattach->warnsig;
2080 else if (tattach->goodsig) {
2082 a->warnsig = tattach->warnsig;
2085 if (s->flags & M_DISPLAY) {
2086 state_puts ("\n", s);
2087 state_attach_puts (is_signed ?
2088 _("[-- End of S/MIME signed data --]\n") :
2089 _("[-- End of S/MIME encrypted data --]\n"), s);
2092 body_list_wipe(&tattach);
2096 mutt_unlink (tempfile);
2102 * Format an entry on the CRYPT key selection menu.
2105 * %k key id %K key id of the principal key
2107 * %a algorithm %A algorithm of the princ. key
2108 * %l length %L length of the princ. key
2109 * %f flags %F flags of the princ. key
2110 * %c capabilities %C capabilities of the princ. key
2111 * %t trust/validity of the key-uid association
2113 * %[...] date of key using strftime(3)
2117 crypt_entry_fmt (char *dest, ssize_t destlen, char op,
2118 const char *src, const char *prefix,
2119 const char *ifstr, const char *elstr,
2120 anytype data, format_flag flags)
2123 crypt_entry_t *entry;
2126 int optional = (flags & M_FORMAT_OPTIONAL);
2127 const char *s = NULL;
2133 /* if (isupper ((unsigned char) op)) */
2136 kflags = (key->flags /*| (pkey->flags & KEYFLAG_RESTRICTIONS)
2139 switch (ascii_tolower (op)) {
2143 char buf2[STRING], *p;
2159 while (len > 0 && *cp != ']') {
2168 break; /* not enough space */
2178 if (do_locales && Locale)
2179 setlocale (LC_TIME, Locale);
2184 if (key->kobj->subkeys && (key->kobj->subkeys->timestamp > 0))
2185 tt = key->kobj->subkeys->timestamp;
2187 tm = localtime (&tt);
2189 strftime (buf2, sizeof (buf2), dest, tm);
2192 setlocale (LC_TIME, "C");
2194 snprintf (fmt, sizeof (fmt), "%%%ss", prefix);
2195 snprintf (dest, destlen, fmt, buf2);
2202 snprintf (fmt, sizeof (fmt), "%%%sd", prefix);
2203 snprintf (dest, destlen, fmt, entry->num);
2208 /* fixme: we need a way to distinguish between main and subkeys.
2209 Store the idx in entry? */
2210 snprintf (fmt, sizeof (fmt), "%%%ss", prefix);
2211 snprintf (dest, destlen, fmt, crypt_keyid (key));
2216 snprintf (fmt, sizeof (fmt), "%%%ss", prefix);
2217 snprintf (dest, destlen, fmt, key->uid);
2222 snprintf (fmt, sizeof (fmt), "%%%s.3s", prefix);
2223 if (key->kobj->subkeys)
2224 s = gpgme_pubkey_algo_name (key->kobj->subkeys->pubkey_algo);
2227 snprintf (dest, destlen, fmt, s);
2232 snprintf (fmt, sizeof (fmt), "%%%slu", prefix);
2233 if (key->kobj->subkeys)
2234 val = key->kobj->subkeys->length;
2237 snprintf (dest, destlen, fmt, val);
2242 snprintf (fmt, sizeof (fmt), "%%%sc", prefix);
2243 snprintf (dest, destlen, fmt, crypt_flags (kflags));
2245 else if (!(kflags & (KEYFLAG_RESTRICTIONS)))
2250 snprintf (fmt, sizeof (fmt), "%%%ss", prefix);
2251 snprintf (dest, destlen, fmt, crypt_key_abilities (kflags));
2253 else if (!(kflags & (KEYFLAG_ABILITIES)))
2257 if ((kflags & KEYFLAG_ISX509))
2260 gpgme_user_id_t uid = NULL;
2263 for (i = 0, uid = key->kobj->uids; uid && (i < key->idx);
2264 i++, uid = uid->next);
2266 switch (uid->validity) {
2267 case GPGME_VALIDITY_UNDEFINED:
2270 case GPGME_VALIDITY_NEVER:
2273 case GPGME_VALIDITY_MARGINAL:
2276 case GPGME_VALIDITY_FULL:
2279 case GPGME_VALIDITY_ULTIMATE:
2282 case GPGME_VALIDITY_UNKNOWN:
2288 snprintf (fmt, sizeof (fmt), "%%%sc", prefix);
2289 snprintf (dest, destlen, fmt, s ? *s : 'B');
2292 snprintf (fmt, sizeof (fmt), "%%%ss", prefix);
2293 snprintf (dest, destlen, fmt,
2294 gpgme_get_protocol_name (key->kobj->protocol));
2301 if (flags & M_FORMAT_OPTIONAL)
2302 m_strformat(dest, destlen, 0, optional ? ifstr: elstr,
2303 mutt_attach_fmt, data, 0);
2307 /* Used by the display fucntion to format a line. */
2308 static void crypt_entry (char *s, ssize_t l, MUTTMENU * menu, int num)
2310 crypt_key_t **key_table = (crypt_key_t **) menu->data;
2311 crypt_entry_t entry;
2313 entry.key = key_table[num];
2314 entry.num = num + 1;
2316 m_strformat(s, l, COLS - SW, PgpEntryFormat, crypt_entry_fmt, &entry,
2317 option(OPTARROWCURSOR) ? M_FORMAT_ARROWCURSOR : 0);
2320 /* Compare two addresses and the keyid to be used for sorting. */
2321 static int _crypt_compare_address (const void *a, const void *b)
2323 crypt_key_t **s = (crypt_key_t **) a;
2324 crypt_key_t **t = (crypt_key_t **) b;
2327 if ((r = m_strcasecmp((*s)->uid, (*t)->uid)))
2330 return m_strcasecmp(crypt_keyid (*s), crypt_keyid (*t)) > 0;
2333 static int crypt_compare_address (const void *a, const void *b)
2335 return ((PgpSortKeys & SORT_REVERSE) ? !_crypt_compare_address (a, b)
2336 : _crypt_compare_address (a, b));
2340 /* Compare two key IDs and the addresses to be used for sorting. */
2341 static int _crypt_compare_keyid (const void *a, const void *b)
2343 crypt_key_t **s = (crypt_key_t **) a;
2344 crypt_key_t **t = (crypt_key_t **) b;
2347 if ((r = m_strcasecmp(crypt_keyid (*s), crypt_keyid (*t))))
2350 return m_strcasecmp((*s)->uid, (*t)->uid) > 0;
2353 static int crypt_compare_keyid (const void *a, const void *b)
2355 return ((PgpSortKeys & SORT_REVERSE) ? !_crypt_compare_keyid (a, b)
2356 : _crypt_compare_keyid (a, b));
2359 /* Compare 2 creation dates and the addresses. For sorting. */
2360 static int _crypt_compare_date (const void *a, const void *b)
2362 crypt_key_t **s = (crypt_key_t **) a;
2363 crypt_key_t **t = (crypt_key_t **) b;
2364 unsigned long ts = 0, tt = 0;
2366 if ((*s)->kobj->subkeys && ((*s)->kobj->subkeys->timestamp > 0))
2367 ts = (*s)->kobj->subkeys->timestamp;
2368 if ((*t)->kobj->subkeys && ((*t)->kobj->subkeys->timestamp > 0))
2369 tt = (*t)->kobj->subkeys->timestamp;
2376 return m_strcasecmp((*s)->uid, (*t)->uid) > 0;
2379 static int crypt_compare_date (const void *a, const void *b)
2381 return ((PgpSortKeys & SORT_REVERSE) ? !_crypt_compare_date (a, b)
2382 : _crypt_compare_date (a, b));
2385 /* Compare two trust values, the key length, the creation dates. the
2386 addresses and the key IDs. For sorting. */
2387 static int _crypt_compare_trust (const void *a, const void *b)
2389 crypt_key_t **s = (crypt_key_t **) a;
2390 crypt_key_t **t = (crypt_key_t **) b;
2391 unsigned long ts = 0, tt = 0;
2394 if ((r = (((*s)->flags & (KEYFLAG_RESTRICTIONS))
2395 - ((*t)->flags & (KEYFLAG_RESTRICTIONS)))))
2398 if ((*s)->kobj->uids)
2399 ts = (*s)->kobj->uids->validity;
2400 if ((*t)->kobj->uids)
2401 tt = (*t)->kobj->uids->validity;
2402 if ((r = (tt - ts)))
2405 if ((*s)->kobj->subkeys)
2406 ts = (*s)->kobj->subkeys->length;
2407 if ((*t)->kobj->subkeys)
2408 tt = (*t)->kobj->subkeys->length;
2412 if ((*s)->kobj->subkeys && ((*s)->kobj->subkeys->timestamp > 0))
2413 ts = (*s)->kobj->subkeys->timestamp;
2414 if ((*t)->kobj->subkeys && ((*t)->kobj->subkeys->timestamp > 0))
2415 tt = (*t)->kobj->subkeys->timestamp;
2421 if ((r = m_strcasecmp((*s)->uid, (*t)->uid)))
2423 return (m_strcasecmp(crypt_keyid ((*s)), crypt_keyid ((*t)))) > 0;
2426 static int crypt_compare_trust (const void *a, const void *b)
2428 return ((PgpSortKeys & SORT_REVERSE) ? !_crypt_compare_trust (a, b)
2429 : _crypt_compare_trust (a, b));
2432 /* Print the X.500 Distinguished Name part KEY from the array of parts
2434 static int print_dn_part (FILE * fp, struct dn_array_s *dn, const char *key)
2438 for (; dn->key; dn++) {
2439 if (!m_strcmp(dn->key, key)) {
2442 print_utf8 (fp, dn->value, m_strlen(dn->value));
2449 /* Print all parts of a DN in a standard sequence. */
2450 static void print_dn_parts (FILE * fp, struct dn_array_s *dn)
2452 const char *stdpart[] = {
2453 "CN", "OU", "O", "STREET", "L", "ST", "C", NULL
2455 int any = 0, any2 = 0, i;
2457 for (i = 0; stdpart[i]; i++) {
2460 any = print_dn_part (fp, dn, stdpart[i]);
2462 /* now print the rest without any specific ordering */
2463 for (; dn->key; dn++) {
2464 for (i = 0; stdpart[i]; i++) {
2465 if (!m_strcmp(dn->key, stdpart[i]))
2473 any = print_dn_part (fp, dn, dn->key);
2482 /* Parse an RDN; this is a helper to parse_dn(). */
2483 static const unsigned char *parse_dn_part (struct dn_array_s *array,
2484 const unsigned char *string)
2486 const unsigned char *s, *s1;
2490 /* parse attributeType */
2491 for (s = string + 1; *s && *s != '='; s++);
2493 return NULL; /* error */
2496 return NULL; /* empty key */
2497 array->key = p_dupstr(string, n );
2498 p = (unsigned char *) array->key;
2501 if (*string == '#') { /* hexstring */
2503 for (s = string; hexval(*s) >= 0; s++)
2507 return NULL; /* empty or odd number of digits */
2509 p = p_new(unsigned char, n + 1);
2510 array->value = (char *) p;
2511 for (s1 = string; n; s1 += 2, n--)
2512 *p++ = (hexval(*s1) << 8) | hexval(*s1);
2515 else { /* regular v3 quoted string */
2516 for (n = 0, s = string; *s; s++) {
2517 if (*s == '\\') { /* pair */
2519 if (*s == ',' || *s == '=' || *s == '+'
2520 || *s == '<' || *s == '>' || *s == '#' || *s == ';'
2521 || *s == '\\' || *s == '\"' || *s == ' ')
2523 else if (hexval(*s) >= 0 && hexval(*s + 1) >= 0) {
2528 return NULL; /* invalid escape sequence */
2530 else if (*s == '\"')
2531 return NULL; /* invalid encoding */
2532 else if (*s == ',' || *s == '=' || *s == '+'
2533 || *s == '<' || *s == '>' || *s == '#' || *s == ';')
2539 p = p_new(unsigned char, n + 1);
2540 array->value = (char *) p;
2541 for (s = string; n; s++, n--) {
2544 if (hexval(*s) >= 0) {
2545 *p++ = (hexval(*s) << 8) | hexval(*s + 1);
2560 /* Parse a DN and return an array-ized one. This is not a validating
2561 parser and it does not support any old-stylish syntax; gpgme is
2562 expected to return only rfc2253 compatible strings. */
2563 static struct dn_array_s *parse_dn (const unsigned char *string)
2565 struct dn_array_s *array;
2566 ssize_t arrayidx, arraysize;
2569 arraysize = 7; /* C,ST,L,O,OU,CN,email */
2570 array = p_new(struct dn_array_s, arraysize + 1);
2573 while (*string == ' ')
2577 if (arrayidx >= arraysize) { /* mutt lacks a real safe_realoc - so we need to copy */
2578 struct dn_array_s *a2;
2581 a2 = p_new(struct dn_array_s, arraysize + 1);
2582 for (i = 0; i < arrayidx; i++) {
2583 a2[i].key = array[i].key;
2584 a2[i].value = array[i].value;
2589 array[arrayidx].key = NULL;
2590 array[arrayidx].value = NULL;
2591 string = parse_dn_part (array + arrayidx, string);
2595 while (*string == ' ')
2597 if (*string && *string != ',' && *string != ';' && *string != '+')
2598 goto failure; /* invalid delimiter */
2602 array[arrayidx].key = NULL;
2603 array[arrayidx].value = NULL;
2607 for (i = 0; i < arrayidx; i++) {
2608 p_delete(&array[i].key);
2609 p_delete(&array[i].value);
2616 /* Print a nice representation of the USERID and make sure it is
2617 displayed in a proper way, which does mean to reorder some parts
2618 for S/MIME's DNs. USERID is a string as returned by the gpgme key
2619 functions. It is utf-8 encoded. */
2620 static void parse_and_print_user_id (FILE * fp, const char *userid)
2625 if (*userid == '<') {
2626 s = strchr (userid + 1, '>');
2628 print_utf8 (fp, userid + 1, s - userid - 1);
2630 else if (*userid == '(')
2631 fputs (_("[Can't display this user ID (unknown encoding)]"), fp);
2632 else if (!digit_or_letter ((const unsigned char *) userid))
2633 fputs (_("[Can't display this user ID (invalid encoding)]"), fp);
2635 struct dn_array_s *dn = parse_dn ((const unsigned char *) userid);
2638 fputs (_("[Can't display this user ID (invalid DN)]"), fp);
2640 print_dn_parts (fp, dn);
2641 for (i = 0; dn[i].key; i++) {
2642 p_delete(&dn[i].key);
2643 p_delete(&dn[i].value);
2651 KEY_CAP_CAN_ENCRYPT,
2656 static unsigned int key_check_cap (gpgme_key_t key, key_cap_t cap)
2658 gpgme_subkey_t subkey = NULL;
2659 unsigned int ret = 0;
2662 case KEY_CAP_CAN_ENCRYPT:
2663 if (!(ret = key->can_encrypt))
2664 for (subkey = key->subkeys; subkey; subkey = subkey->next)
2665 if ((ret = subkey->can_encrypt))
2668 case KEY_CAP_CAN_SIGN:
2669 if (!(ret = key->can_sign))
2670 for (subkey = key->subkeys; subkey; subkey = subkey->next)
2671 if ((ret = subkey->can_sign))
2674 case KEY_CAP_CAN_CERTIFY:
2675 if (!(ret = key->can_certify))
2676 for (subkey = key->subkeys; subkey; subkey = subkey->next)
2677 if ((ret = subkey->can_certify))
2686 /* Print verbose information about a key or certificate to FP. */
2687 static void print_key_info (gpgme_key_t key, FILE * fp)
2690 const char *s = NULL, *s2 = NULL;
2693 char shortbuf[STRING];
2694 unsigned long aval = 0;
2698 gpgme_user_id_t uid = NULL;
2701 setlocale (LC_TIME, Locale);
2703 is_pgp = key->protocol == GPGME_PROTOCOL_OpenPGP;
2705 for (idx = 0, uid = key->uids; uid; idx++, uid = uid->next) {
2710 fputs (idx ? _(" aka ......: ") :_("Name ......: "), fp);
2713 fputs (_("[Invalid]"), fp);
2717 print_utf8 (fp, s, m_strlen(s));
2719 parse_and_print_user_id (fp, s);
2723 if (key->subkeys && (key->subkeys->timestamp > 0)) {
2724 tt = key->subkeys->timestamp;
2726 tm = localtime (&tt);
2727 #ifdef HAVE_LANGINFO_D_T_FMT
2728 strftime (shortbuf, sizeof shortbuf, nl_langinfo (D_T_FMT), tm);
2730 strftime (shortbuf, sizeof shortbuf, "%c", tm);
2732 fprintf (fp, _("Valid From : %s\n"), shortbuf);
2735 if (key->subkeys && (key->subkeys->expires > 0)) {
2736 tt = key->subkeys->expires;
2738 tm = localtime (&tt);
2739 #ifdef HAVE_LANGINFO_D_T_FMT
2740 strftime (shortbuf, sizeof shortbuf, nl_langinfo (D_T_FMT), tm);
2742 strftime (shortbuf, sizeof shortbuf, "%c", tm);
2744 fprintf (fp, _("Valid To ..: %s\n"), shortbuf);
2748 s = gpgme_pubkey_algo_name (key->subkeys->pubkey_algo);
2752 s2 = is_pgp ? "PGP" : "X.509";
2755 aval = key->subkeys->length;
2757 fprintf (fp, _("Key Type ..: %s, %lu bit %s\n"), s2, aval, s);
2759 fprintf (fp, _("Key Usage .: "));
2762 if (key_check_cap (key, KEY_CAP_CAN_ENCRYPT)) {
2763 fprintf (fp, "%s%s", delim, _("encryption"));
2766 if (key_check_cap (key, KEY_CAP_CAN_SIGN)) {
2767 fprintf (fp, "%s%s", delim, _("signing"));
2770 if (key_check_cap (key, KEY_CAP_CAN_CERTIFY)) {
2771 fprintf (fp, "%s%s", delim, _("certification"));
2777 s = key->subkeys->fpr;
2778 fputs (_("Fingerprint: "), fp);
2779 if (is_pgp && m_strlen(s) == 40) {
2780 for (i = 0; *s && s[1] && s[2] && s[3] && s[4]; s += 4, i++) {
2785 putc (is_pgp ? ' ' : ':', fp);
2786 if (is_pgp && i == 4)
2791 for (i = 0; *s && s[1] && s[2]; s += 2, i++) {
2794 putc (is_pgp ? ' ' : ':', fp);
2795 if (is_pgp && i == 7)
2799 fprintf (fp, "%s\n", s);
2802 if (key->issuer_serial) {
2803 s = key->issuer_serial;
2805 fprintf (fp, _("Serial-No .: 0x%s\n"), s);
2808 if (key->issuer_name) {
2809 s = key->issuer_name;
2811 fprintf (fp, _("Issued By .: "));
2812 parse_and_print_user_id (fp, s);
2817 /* For PGP we list all subkeys. */
2819 gpgme_subkey_t subkey = NULL;
2821 for (idx = 1, subkey = key->subkeys; subkey; idx++, subkey = subkey->next) {
2825 if (m_strlen(s) == 16)
2826 s += 8; /* display only the short keyID */
2827 fprintf (fp, _("Subkey ....: 0x%s"), s);
2828 if (subkey->revoked) {
2830 fputs (_("[Revoked]"), fp);
2832 if (subkey->invalid) {
2834 fputs (_("[Invalid]"), fp);
2836 if (subkey->expired) {
2838 fputs (_("[Expired]"), fp);
2840 if (subkey->disabled) {
2842 fputs (_("[Disabled]"), fp);
2846 if (subkey->timestamp > 0) {
2847 tt = subkey->timestamp;
2849 tm = localtime (&tt);
2850 #ifdef HAVE_LANGINFO_D_T_FMT
2851 strftime (shortbuf, sizeof shortbuf, nl_langinfo (D_T_FMT), tm);
2853 strftime (shortbuf, sizeof shortbuf, "%c", tm);
2855 fprintf (fp, _("Valid From : %s\n"), shortbuf);
2858 if (subkey->expires > 0) {
2859 tt = subkey->expires;
2861 tm = localtime (&tt);
2862 #ifdef HAVE_LANGINFO_D_T_FMT
2863 strftime (shortbuf, sizeof shortbuf, nl_langinfo (D_T_FMT), tm);
2865 strftime (shortbuf, sizeof shortbuf, "%c", tm);
2867 fprintf (fp, _("Valid To ..: %s\n"), shortbuf);
2871 s = gpgme_pubkey_algo_name (subkey->pubkey_algo);
2876 aval = subkey->length;
2880 fprintf (fp, _("Key Type ..: %s, %lu bit %s\n"), "PGP", aval, s);
2882 fprintf (fp, _("Key Usage .: "));
2885 if (subkey->can_encrypt) {
2886 fprintf (fp, "%s%s", delim, _("encryption"));
2889 if (subkey->can_sign) {
2890 fprintf (fp, "%s%s", delim, _("signing"));
2893 if (subkey->can_certify) {
2894 fprintf (fp, "%s%s", delim, _("certification"));
2902 setlocale (LC_TIME, "C");
2906 /* Show detailed information about the selected key */
2907 static void verify_key (crypt_key_t * key)
2910 char cmd[LONG_STRING], tempfile[_POSIX_PATH_MAX];
2912 gpgme_ctx_t listctx = NULL;
2914 gpgme_key_t k = NULL;
2917 fp = m_tempfile (tempfile, sizeof(tempfile), NONULL(MCore.tmpdir), NULL);
2919 mutt_perror (_("Can't create temporary file"));
2922 mutt_message _("Collecting data...");
2924 print_key_info (key->kobj, fp);
2926 err = gpgme_new (&listctx);
2928 fprintf (fp, "Internal error: can't create gpgme context: %s\n",
2929 gpgme_strerror (err));
2932 if ((key->flags & KEYFLAG_ISX509))
2933 gpgme_set_protocol (listctx, GPGME_PROTOCOL_CMS);
2937 while ((s = k->chain_id) && k->subkeys && m_strcmp(s, k->subkeys->fpr)) {
2939 err = gpgme_op_keylist_start (listctx, s, 0);
2940 gpgme_key_release (k);
2943 err = gpgme_op_keylist_next (listctx, &k);
2945 fprintf (fp, _("Error finding issuer key: %s\n"), gpgme_strerror (err));
2948 gpgme_op_keylist_end (listctx);
2950 print_key_info (k, fp);
2953 fputs (_("Error: certification chain to long - stopping here\n"), fp);
2959 gpgme_key_release (k);
2960 gpgme_release (listctx);
2962 mutt_clear_error ();
2963 snprintf (cmd, sizeof (cmd), _("Key ID: 0x%s"), crypt_keyid (key));
2964 mutt_do_pager (cmd, tempfile, 0, NULL);
2967 /* Implementation of `findkeys'. */
2969 /* Convert string_list_t into a pattern string suitable to be passed to GPGME.
2970 We need to convert spaces in an item into a '+' and '%' into
2972 static char *list_to_pattern (string_list_t * list)
2980 for (l = list; l; l = l->next) {
2981 for (s = l->data; *s; s++) {
2986 n++; /* delimiter or end of string */
2988 n++; /* make sure to allocate at least one byte */
2989 pattern = p = p_new(char, n);
2990 for (l = list; l; l = l->next) {
2995 for (s = l->data; *s; s++) {
3001 else if (*s == '+') {
3017 /* Return a list of keys which are candidates for the selection.
3018 Select by looking at the HINTS list. */
3019 static crypt_key_t *get_candidates (string_list_t * hints, unsigned int app,
3022 crypt_key_t *db, *k, **kend;
3028 gpgme_user_id_t uid = NULL;
3030 pattern = list_to_pattern (hints);
3034 err = gpgme_new (&ctx);
3036 mutt_error (_("gpgme_new failed: %s"), gpgme_strerror (err));
3044 if ((app & APPLICATION_PGP)) {
3045 /* Its all a mess. That old GPGME expects different things
3046 depending on the protocol. For gpg we don' t need percent
3047 escaped pappert but simple strings passed in an array to the
3048 keylist_ext_start function. */
3053 for (l = hints, n = 0; l; l = l->next) {
3054 if (l->data && *l->data)
3060 patarr = p_new(char *, n + 1);
3061 for (l = hints, n = 0; l; l = l->next) {
3062 if (l->data && *l->data)
3063 patarr[n++] = m_strdup(l->data);
3066 err = gpgme_op_keylist_ext_start (ctx, (const char **) patarr, secret, 0);
3067 for (n = 0; patarr[n]; n++)
3068 p_delete(&patarr[n]);
3071 mutt_error (_("gpgme_op_keylist_start failed: %s"), gpgme_strerror (err));
3072 gpgme_release (ctx);
3077 while (!(err = gpgme_op_keylist_next (ctx, &key))) {
3078 unsigned int flags = 0;
3080 if (key_check_cap (key, KEY_CAP_CAN_ENCRYPT))
3081 flags |= KEYFLAG_CANENCRYPT;
3082 if (key_check_cap (key, KEY_CAP_CAN_SIGN))
3083 flags |= KEYFLAG_CANSIGN;
3085 #if 0 /* DISABLED code */
3087 /* Bug in gpg. Capabilities are not listed for secret
3088 keys. Try to deduce them from the algorithm. */
3090 switch (key->subkeys[0].pubkey_algo) {
3092 flags |= KEYFLAG_CANENCRYPT;
3093 flags |= KEYFLAG_CANSIGN;
3095 case GPGME_PK_ELG_E:
3096 flags |= KEYFLAG_CANENCRYPT;
3099 flags |= KEYFLAG_CANSIGN;
3103 #endif /* DISABLED code */
3105 for (idx = 0, uid = key->uids; uid; idx++, uid = uid->next) {
3106 k = p_new(crypt_key_t, 1);
3115 if (gpg_err_code (err) != GPG_ERR_EOF)
3116 mutt_error (_("gpgme_op_keylist_next failed: %s"), gpgme_strerror (err));
3117 gpgme_op_keylist_end (ctx);
3122 if ((app & APPLICATION_SMIME)) {
3123 /* and now look for x509 certificates */
3124 gpgme_set_protocol (ctx, GPGME_PROTOCOL_CMS);
3125 err = gpgme_op_keylist_start (ctx, pattern, 0);
3127 mutt_error (_("gpgme_op_keylist_start failed: %s"), gpgme_strerror (err));
3128 gpgme_release (ctx);
3133 while (!(err = gpgme_op_keylist_next (ctx, &key))) {
3134 unsigned int flags = KEYFLAG_ISX509;
3136 if (key_check_cap (key, KEY_CAP_CAN_ENCRYPT))
3137 flags |= KEYFLAG_CANENCRYPT;
3138 if (key_check_cap (key, KEY_CAP_CAN_SIGN))
3139 flags |= KEYFLAG_CANSIGN;
3141 for (idx = 0, uid = key->uids; uid; idx++, uid = uid->next) {
3142 k = p_new(crypt_key_t, 1);
3151 if (gpg_err_code (err) != GPG_ERR_EOF)
3152 mutt_error (_("gpgme_op_keylist_next failed: %s"), gpgme_strerror (err));
3153 gpgme_op_keylist_end (ctx);
3156 gpgme_release (ctx);
3161 /* Add the string STR to the list HINTS. This list is later used to
3163 static string_list_t *crypt_add_string_to_hints (string_list_t * hints, const char *str)
3168 if ((scratch = m_strdup(str)) == NULL)
3171 for (t = strtok (scratch, " ,.:\"()<>\n"); t;
3172 t = strtok (NULL, " ,.:\"()<>\n")) {
3173 if (m_strlen(t) > 3)
3174 hints = mutt_add_list(hints, t);
3181 /* Display a menu to select a key from the array KEYS. FORCED_VALID
3182 will be set to true on return if the user did override the the
3184 static crypt_key_t *crypt_select_key (crypt_key_t * keys,
3185 address_t * p, const char *s,
3186 unsigned int app, int *forced_valid)
3189 crypt_key_t **key_table;
3192 char helpstr[STRING], buf[LONG_STRING];
3194 int (*f) (const void *, const void *);
3195 int menu_to_use = 0;
3200 /* build the key table */
3203 for (k = keys; k; k = k->next) {
3204 if (!option (OPTPGPSHOWUNUSABLE) && (k->flags & KEYFLAG_CANTUSE)) {
3211 p_realloc(&key_table, keymax);
3217 if (!i && unusable) {
3218 mutt_error _("All matching keys are marked expired/revoked.");
3224 switch (PgpSortKeys & SORT_MASK) {
3226 f = crypt_compare_date;
3229 f = crypt_compare_keyid;
3232 f = crypt_compare_address;
3236 f = crypt_compare_trust;
3239 qsort (key_table, i, sizeof (crypt_key_t *), f);
3241 if (app & APPLICATION_PGP)
3242 menu_to_use = MENU_KEY_SELECT_PGP;
3243 else if (app & APPLICATION_SMIME)
3244 menu_to_use = MENU_KEY_SELECT_SMIME;
3247 mutt_make_help (buf, sizeof (buf), _("Exit "), menu_to_use, OP_EXIT);
3248 m_strcat(helpstr, sizeof(helpstr), buf);
3249 mutt_make_help (buf, sizeof (buf), _("Select "), menu_to_use,
3250 OP_GENERIC_SELECT_ENTRY);
3251 m_strcat(helpstr, sizeof(helpstr), buf);
3252 mutt_make_help (buf, sizeof (buf), _("Check key "),
3253 menu_to_use, OP_VERIFY_KEY);
3254 m_strcat(helpstr, sizeof(helpstr), buf);
3255 mutt_make_help (buf, sizeof (buf), _("Help"), menu_to_use, OP_HELP);
3256 m_strcat(helpstr, sizeof(helpstr), buf);
3258 menu = mutt_new_menu ();
3260 menu->make_entry = crypt_entry;
3261 menu->menu = menu_to_use;
3262 menu->help = helpstr;
3263 menu->data = key_table;
3268 if ((app & APPLICATION_PGP) && (app & APPLICATION_SMIME))
3269 ts = _("PGP and S/MIME keys matching");
3270 else if ((app & APPLICATION_PGP))
3271 ts = _("PGP keys matching");
3272 else if ((app & APPLICATION_SMIME))
3273 ts = _("S/MIME keys matching");
3275 ts = _("keys matching");
3278 snprintf (buf, sizeof (buf), _("%s <%s>."), ts, p->mailbox);
3280 snprintf (buf, sizeof (buf), _("%s \"%s\"."), ts, s);
3284 mutt_clear_error ();
3288 switch (mutt_menuLoop (menu)) {
3290 verify_key (key_table[menu->current]);
3291 menu->redraw = REDRAW_FULL;
3295 mutt_message ("%s", key_table[menu->current]->uid);
3298 case OP_GENERIC_SELECT_ENTRY:
3299 /* FIXME make error reporting more verbose - this should be
3300 easy because gpgme provides more information */
3301 if (option (OPTPGPCHECKTRUST)) {
3302 if (!crypt_key_is_valid (key_table[menu->current])) {
3303 mutt_error _("This key can't be used: "
3304 "expired/disabled/revoked.");
3309 if (option (OPTPGPCHECKTRUST) &&
3310 (!crypt_id_is_valid (key_table[menu->current])
3311 || !crypt_id_is_strong (key_table[menu->current]))) {
3313 char buff[LONG_STRING];
3315 if (key_table[menu->current]->flags & KEYFLAG_CANTUSE)
3316 s = N_("ID is expired/disabled/revoked.");
3318 gpgme_validity_t val = GPGME_VALIDITY_UNKNOWN;
3319 gpgme_user_id_t uid = NULL;
3324 uid = key_table[menu->current]->kobj->uids;
3325 for (j = 0; (j < key_table[menu->current]->idx) && uid;
3326 j++, uid = uid->next);
3328 val = uid->validity;
3331 case GPGME_VALIDITY_UNKNOWN:
3332 case GPGME_VALIDITY_UNDEFINED:
3333 warn_s = N_("ID has undefined validity.");
3335 case GPGME_VALIDITY_NEVER:
3336 warn_s = N_("ID is not valid.");
3338 case GPGME_VALIDITY_MARGINAL:
3339 warn_s = N_("ID is only marginally valid.");
3341 case GPGME_VALIDITY_FULL:
3342 case GPGME_VALIDITY_ULTIMATE:
3346 snprintf (buff, sizeof (buff),
3347 _("%s Do you really want to use the key?"), _(warn_s));
3349 if (mutt_yesorno (buff, 0) != 1) {
3350 mutt_clear_error ();
3357 k = crypt_copy_key (key_table[menu->current]);
3368 mutt_menuDestroy (&menu);
3369 p_delete(&key_table);
3371 set_option (OPTNEEDREDRAW);
3376 static crypt_key_t *crypt_getkeybyaddr (address_t * a, short abilities,
3377 unsigned int app, int *forced_valid)
3380 string_list_t *hints = NULL;
3385 int this_key_has_strong;
3386 int this_key_has_weak;
3387 int this_key_has_invalid;
3390 crypt_key_t *keys, *k;
3391 crypt_key_t *the_valid_key = NULL;
3392 crypt_key_t *matches = NULL;
3393 crypt_key_t **matches_endp = &matches;
3397 if (a && a->mailbox)
3398 hints = crypt_add_string_to_hints (hints, a->mailbox);
3399 if (a && a->personal)
3400 hints = crypt_add_string_to_hints (hints, a->personal);
3402 mutt_message (_("Looking for keys matching \"%s\"..."), a->mailbox);
3403 keys = get_candidates (hints, app, (abilities & KEYFLAG_CANSIGN));
3405 string_list_wipe(&hints);
3410 for (k = keys; k; k = k->next) {
3411 if (abilities && !(k->flags & abilities)) {
3415 this_key_has_weak = 0; /* weak but valid match */
3416 this_key_has_invalid = 0; /* invalid match */
3417 this_key_has_strong = 0; /* strong and valid match */
3418 match = 0; /* any match */
3420 r = rfc822_parse_adrlist (NULL, k->uid);
3421 for (p = r; p; p = p->next) {
3422 int validity = crypt_id_matches_addr (a, p, k);
3424 if (validity & CRYPT_KV_MATCH) /* something matches */
3427 /* is this key a strong candidate? */
3428 if ((validity & CRYPT_KV_VALID)
3429 && (validity & CRYPT_KV_STRONGID)
3430 && (validity & CRYPT_KV_ADDR)) {
3431 if (the_valid_key && the_valid_key != k)
3434 this_key_has_strong = 1;
3436 else if ((validity & CRYPT_KV_MATCH)
3437 && !(validity & CRYPT_KV_VALID))
3438 this_key_has_invalid = 1;
3439 else if ((validity & CRYPT_KV_MATCH)
3440 && (!(validity & CRYPT_KV_STRONGID)
3441 || !(validity & CRYPT_KV_ADDR)))
3442 this_key_has_weak = 1;
3444 address_list_wipe(&r);
3449 if (!this_key_has_strong && this_key_has_invalid)
3451 if (!this_key_has_strong && this_key_has_weak)
3454 *matches_endp = tmp = crypt_copy_key (k);
3455 matches_endp = &tmp->next;
3456 the_valid_key = tmp;
3460 crypt_free_key (&keys);
3463 if (the_valid_key && !multi && !weak
3464 && !(invalid && option (OPTPGPSHOWUNUSABLE))) {
3466 * There was precisely one strong match on a valid ID, there
3467 * were no valid keys with weak matches, and we aren't
3468 * interested in seeing invalid keys.
3470 * Proceed without asking the user.
3472 k = crypt_copy_key (the_valid_key);
3476 * Else: Ask the user.
3478 k = crypt_select_key (matches, a, NULL, app, forced_valid);
3480 crypt_free_key (&matches);
3489 static crypt_key_t *crypt_getkeybystr (const char *p, short abilities,
3490 unsigned int app, int *forced_valid)
3492 string_list_t *hints = NULL;
3494 crypt_key_t *matches = NULL;
3495 crypt_key_t **matches_endp = &matches;
3499 mutt_message (_("Looking for keys matching \"%s\"..."), p);
3503 hints = crypt_add_string_to_hints (hints, p);
3504 keys = get_candidates (hints, app, (abilities & KEYFLAG_CANSIGN));
3505 string_list_wipe(&hints);
3510 for (k = keys; k; k = k->next) {
3511 if (abilities && !(k->flags & abilities))
3516 if (!*p || !m_strcasecmp(p, crypt_keyid (k))
3517 || (!m_strncasecmp(p, "0x", 2)
3518 && !m_strcasecmp(p + 2, crypt_keyid (k)))
3519 || (option (OPTPGPLONGIDS)
3520 && !m_strncasecmp(p, "0x", 2)
3521 && !m_strcasecmp(p + 2, crypt_keyid (k) + 8))
3522 || m_stristr(k->uid, p)) {
3525 *matches_endp = tmp = crypt_copy_key (k);
3526 matches_endp = &tmp->next;
3530 crypt_free_key (&keys);
3533 k = crypt_select_key (matches, NULL, p, app, forced_valid);
3534 crypt_free_key (&matches);
3541 /* Display TAG as a prompt to ask for a key. If WHATFOR is not null
3542 use it as default and store it under that label as the next
3543 default. ABILITIES describe the required key abilities (sign,
3544 encrypt) and APP the type of the requested key; ether S/MIME or
3545 PGP. Return a copy of the key or NULL if not found. */
3546 static crypt_key_t *crypt_ask_for_key (char *tag,
3549 unsigned int app, int *forced_valid)
3553 struct crypt_cache *l = NULL;
3557 forced_valid = &dummy;
3559 mutt_clear_error ();
3565 for (l = id_defaults; l; l = l->next)
3566 if (!m_strcasecmp(whatfor, l->what)) {
3567 m_strcpy(resp, sizeof(resp), NONULL(l->dflt));
3575 if (mutt_get_field (tag, resp, sizeof (resp), M_CLEAR) != 0)
3580 m_strreplace(&l->dflt, resp);
3582 l = p_new(struct crypt_cache, 1);
3583 l->next = id_defaults;
3585 l->what = m_strdup(whatfor);
3586 l->dflt = m_strdup(resp);
3590 if ((key = crypt_getkeybystr (resp, abilities, app, forced_valid)))
3598 /* This routine attempts to find the keyids of the recipients of a
3599 message. It returns NULL if any of the keys can not be found. */
3600 static char *find_keys (address_t * to, address_t * cc, address_t * bcc,
3603 char *keylist = NULL, *t;
3605 ssize_t keylist_size = 0;
3606 ssize_t keylist_used = 0;
3607 address_t *tmp = NULL, *addr = NULL;
3608 address_t **last = &tmp;
3611 crypt_key_t *k_info, *key;
3612 const char *fqdn = mutt_fqdn (1);
3615 *r_application = APPLICATION_PGP | APPLICATION_SMIME;
3618 for (i = 0; i < 3; i++) {
3633 *last = address_list_dup (p);
3635 last = &((*last)->next);
3638 rfc822_qualify(tmp, fqdn);
3639 address_list_uniq(tmp);
3641 for (p = tmp; p; p = p->next) {
3642 char buf[LONG_STRING];
3643 int forced_valid = 0;
3648 if ((keyID = mutt_crypt_hook (p)) != NULL) {
3651 snprintf (buf, sizeof (buf), _("Use keyID = \"%s\" for %s?"),
3653 if ((r = mutt_yesorno (buf, M_YES)) == M_YES) {
3654 /* check for e-mail address */
3655 if ((t = strchr (keyID, '@')) &&
3656 (addr = rfc822_parse_adrlist (NULL, keyID))) {
3657 rfc822_qualify(addr, fqdn);
3661 k_info = crypt_getkeybystr (keyID, KEYFLAG_CANENCRYPT,
3662 app, &forced_valid);
3667 address_list_wipe(&tmp);
3668 address_list_wipe(&addr);
3674 && (k_info = crypt_getkeybyaddr (q, KEYFLAG_CANENCRYPT,
3675 app, &forced_valid)) == NULL) {
3676 snprintf (buf, sizeof (buf), _("Enter keyID for %s: "), q->mailbox);
3678 if ((key = crypt_ask_for_key (buf, q->mailbox, KEYFLAG_CANENCRYPT,
3680 &forced_valid)) == NULL) {
3682 address_list_wipe(&tmp);
3683 address_list_wipe(&addr);
3691 const char *s = crypt_fpr (key);
3693 keylist_size += m_strlen(s) + 4 + 1;
3694 p_realloc(&keylist, keylist_size);
3695 sprintf (keylist + keylist_used, "%s0x%s%s",
3696 keylist_used ? " " : "", s, forced_valid ? "!" : "");
3698 keylist_used = m_strlen(keylist);
3700 crypt_free_key (&key);
3701 address_list_wipe(&addr);
3703 address_list_wipe(&tmp);
3707 char *crypt_pgp_findkeys (address_t * to, address_t * cc, address_t * bcc)
3709 return find_keys (to, cc, bcc, APPLICATION_PGP);
3712 char *crypt_smime_findkeys (address_t * to, address_t * cc, address_t * bcc)
3714 return find_keys (to, cc, bcc, APPLICATION_SMIME);
3717 static int gpgme_send_menu (HEADER * msg, int *redraw, int is_smime)
3720 char input_signas[STRING];
3723 if (msg->security & APPLICATION_PGP)
3725 else if (msg->security & APPLICATION_SMIME)
3730 mutt_multi_choice (_
3731 ("S/MIME (e)ncrypt, (s)ign, sign (a)s, (b)oth, (p)gp or (c)lear?"),
3735 mutt_multi_choice (_
3736 ("PGP (e)ncrypt, (s)ign, sign (a)s, (b)oth, s/(m)ime or (c)lear?"),
3740 case 1: /* (e)ncrypt */
3741 msg->security |= (is_smime ? SMIMEENCRYPT : PGPENCRYPT);
3742 msg->security &= ~(is_smime ? SMIMESIGN : PGPSIGN);
3745 case 2: /* (s)ign */
3746 msg->security |= (is_smime ? SMIMESIGN : PGPSIGN);
3747 msg->security &= ~(is_smime ? SMIMEENCRYPT : PGPENCRYPT);
3750 case 3: /* sign (a)s */
3751 /* unset_option(OPTCRYPTCHECKTRUST); */
3752 if ((p = crypt_ask_for_key (_("Sign as: "), NULL, KEYFLAG_CANSIGN,
3753 is_smime ? APPLICATION_SMIME :
3754 APPLICATION_PGP, NULL))) {
3755 snprintf (input_signas, sizeof (input_signas), "0x%s", crypt_keyid (p));
3756 m_strreplace(is_smime ? &SmimeDefaultKey : &PgpSignAs,
3758 crypt_free_key (&p);
3760 msg->security |= (is_smime ? SMIMESIGN : PGPSIGN);
3762 *redraw = REDRAW_FULL;
3765 case 4: /* (b)oth */
3767 (is_smime ? (SMIMEENCRYPT | SMIMESIGN) : (PGPENCRYPT | PGPSIGN));
3770 case 5: /* (p)gp or s/(m)ime */
3771 is_smime = !is_smime;
3774 case 6: /* (c)lear */
3779 if (choice == 6 || choice == 7);
3780 else if (is_smime) {
3781 msg->security &= ~APPLICATION_PGP;
3782 msg->security |= APPLICATION_SMIME;
3785 msg->security &= ~APPLICATION_SMIME;
3786 msg->security |= APPLICATION_PGP;
3789 return (msg->security);
3792 int crypt_pgp_send_menu(HEADER * msg, int *redraw)
3794 return gpgme_send_menu(msg, redraw, 0);
3797 int crypt_smime_send_menu(HEADER * msg, int *redraw)
3799 return gpgme_send_menu (msg, redraw, 1);
3802 int crypt_smime_verify_sender (HEADER * h)
3804 address_t *sender = NULL;
3805 unsigned int ret = 1;
3808 h->env->from = mutt_expand_aliases (h->env->from);
3809 sender = h->env->from;
3811 else if (h->env->sender) {
3812 h->env->sender = mutt_expand_aliases (h->env->sender);
3813 sender = h->env->sender;
3817 if (signature_key) {
3818 gpgme_key_t key = signature_key;
3819 gpgme_user_id_t uid = NULL;
3820 int sender_length = 0;
3823 sender_length = m_strlen(sender->mailbox);
3824 for (uid = key->uids; uid && ret; uid = uid->next) {
3825 uid_length = m_strlen(uid->email);
3826 if (1 && (uid->email[0] == '<')
3827 && (uid->email[uid_length - 1] == '>')
3828 && (uid_length == sender_length + 2)
3829 && (!m_strncmp (uid->email + 1, sender->mailbox, sender_length)))
3834 mutt_any_key_to_continue ("Failed to verify sender");
3837 mutt_any_key_to_continue ("Failed to figure out sender");
3839 if (signature_key) {
3840 gpgme_key_release (signature_key);
3841 signature_key = NULL;
3847 static void invoke_import(const char *fname, int smime)
3849 gpgme_ctx_t ctx = create_gpgme_context(smime);
3853 err = gpgme_data_new_from_file(&data, fname, 1);
3855 mutt_error (_("error allocating data object: %s\n"), gpgme_strerror (err));
3860 err = gpgme_op_import(ctx, data);
3862 mutt_error(_("error importing gpg data: %s\n"), gpgme_strerror(err));
3863 gpgme_data_release(data);
3868 gpgme_data_release(data);
3873 void crypt_pgp_invoke_import(const char *fname)
3875 invoke_import(fname, 0);
3878 void crypt_smime_invoke_import(const char *fname)
3880 invoke_import(fname, 1);
3883 static void pgp_extract_keys_from_attachment (FILE * fp, BODY * top)
3887 char tempfname[_POSIX_PATH_MAX];
3889 tempfp = m_tempfile(tempfname, sizeof(tempfname), NONULL(MCore.tmpdir), NULL);
3890 if (tempfp == NULL) {
3891 mutt_perror (_("Can't create temporary file"));
3900 mutt_body_handler (top, &s);
3903 crypt_pgp_invoke_import(tempfname);
3904 mutt_unlink (tempfname);
3907 void crypt_pgp_extract_keys_from_attachment_list(FILE * fp, int tag, BODY * top)
3910 set_option (OPTDONTHANDLEPGPKEYS);
3912 for (; top; top = top->next) {
3913 if (!tag || top->tagged)
3914 pgp_extract_keys_from_attachment (fp, top);
3920 unset_option (OPTDONTHANDLEPGPKEYS);