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>
22 #include <lib-mx/mx.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 static void convert_to_7bit (BODY * a)
81 if (a->type == TYPEMULTIPART) {
82 if (a->encoding != ENC7BIT) {
83 a->encoding = ENC7BIT;
84 convert_to_7bit (a->parts);
86 convert_to_7bit (a->parts);
89 else if (a->type == TYPEMESSAGE &&
90 m_strcasecmp(a->subtype, "delivery-status")) {
91 if (a->encoding != ENC7BIT)
92 mutt_message_to_7bit (a, NULL);
94 else if (a->encoding == ENC8BIT)
95 a->encoding = ENCQUOTEDPRINTABLE;
96 else if (a->encoding == ENCBINARY)
97 a->encoding = ENCBASE64;
98 else if (a->content && a->encoding != ENCBASE64 &&
99 (a->content->from || a->content->space))
100 a->encoding = ENCQUOTEDPRINTABLE;
105 /* Print the utf-8 encoded string BUF of length LEN bytes to stream
106 FP. Convert the character set. */
107 static void print_utf8 (FILE * fp, const char *buf, ssize_t len)
111 tstr = p_dupstr(buf, len);
112 mutt_convert_string (&tstr, "utf-8", MCharset.charset, M_ICONV_HOOK_FROM);
122 /* Return the keyID for the key K. Note that this string is valid as
123 long as K is valid */
124 static const char *crypt_keyid (crypt_key_t * k)
126 const char *s = "????????";
128 if (k->kobj && k->kobj->subkeys) {
129 s = k->kobj->subkeys->keyid;
130 if ((!option (OPTPGPLONGIDS)) && (m_strlen(s) == 16))
131 /* Return only the short keyID. */
138 /* Return the hexstring fingerprint from the key K. */
139 static const char *crypt_fpr (crypt_key_t * k)
143 if (k->kobj && k->kobj->subkeys)
144 s = k->kobj->subkeys->fpr;
149 /* Parse FLAGS and return a statically allocated(!) string with them. */
150 static char *crypt_key_abilities (int flags)
154 if (!(flags & KEYFLAG_CANENCRYPT))
156 else if (flags & KEYFLAG_PREFER_SIGNING)
161 if (!(flags & KEYFLAG_CANSIGN))
163 else if (flags & KEYFLAG_PREFER_ENCRYPTION)
173 /* Parse FLAGS and return a character describing the most important flag. */
174 static char crypt_flags (int flags)
176 if (flags & KEYFLAG_REVOKED)
178 else if (flags & KEYFLAG_EXPIRED)
180 else if (flags & KEYFLAG_DISABLED)
182 else if (flags & KEYFLAG_CRITICAL)
188 /* Return a copy of KEY. */
189 static crypt_key_t *crypt_copy_key (crypt_key_t *key)
193 k = p_new(crypt_key_t, 1);
195 gpgme_key_ref (key->kobj);
198 k->flags = key->flags;
203 /* Release all the keys at the address of KEYLIST and set the address
205 static void crypt_free_key (crypt_key_t ** keylist)
208 crypt_key_t *k = (*keylist)->next;
215 /* Return trute when key K is valid. */
216 static int crypt_key_is_valid (crypt_key_t * k)
218 if (k->flags & KEYFLAG_CANTUSE)
223 /* Return true whe validity of KEY is sufficient. */
224 static int crypt_id_is_strong (crypt_key_t * key)
226 gpgme_validity_t val = GPGME_VALIDITY_UNKNOWN;
227 gpgme_user_id_t uid = NULL;
231 if ((key->flags & KEYFLAG_ISX509))
234 for (i = 0, uid = key->kobj->uids; (i < key->idx) && uid;
235 i++, uid = uid->next);
240 case GPGME_VALIDITY_UNKNOWN:
241 case GPGME_VALIDITY_UNDEFINED:
242 case GPGME_VALIDITY_NEVER:
243 case GPGME_VALIDITY_MARGINAL:
247 case GPGME_VALIDITY_FULL:
248 case GPGME_VALIDITY_ULTIMATE:
256 /* Return true when the KEY is valid, i.e. not marked as unusable. */
257 static int crypt_id_is_valid (crypt_key_t * key)
259 return !(key->flags & KEYFLAG_CANTUSE);
262 /* Return a bit vector describing how well the addresses ADDR and
263 U_ADDR match and whether KEY is valid. */
264 static int crypt_id_matches_addr (address_t * addr, address_t * u_addr,
269 if (crypt_id_is_valid (key))
270 rv |= CRYPT_KV_VALID;
272 if (crypt_id_is_strong (key))
273 rv |= CRYPT_KV_STRONGID;
275 if (addr->mailbox && u_addr->mailbox
276 && m_strcasecmp(addr->mailbox, u_addr->mailbox) == 0)
279 if (addr->personal && u_addr->personal
280 && m_strcasecmp(addr->personal, u_addr->personal) == 0)
281 rv |= CRYPT_KV_STRING;
288 * GPGME convenient functions.
291 /* Create a new gpgme context and return it. With FOR_SMIME set to
292 true, the protocol of the context is set to CMS. */
293 static gpgme_ctx_t create_gpgme_context (int for_smime)
298 err = gpgme_new (&ctx);
300 mutt_error (_("error creating gpgme context: %s\n"), gpgme_strerror (err));
306 err = gpgme_set_protocol (ctx, GPGME_PROTOCOL_CMS);
308 mutt_error (_("error enabling CMS protocol: %s\n"), gpgme_strerror (err));
317 /* Create a new gpgme data object. This is a wrapper to die on
319 static gpgme_data_t create_gpgme_data (void)
324 err = gpgme_data_new (&data);
326 mutt_error (_("error creating gpgme data object: %s\n"),
327 gpgme_strerror (err));
334 /* Create a new GPGME Data object from the mail body A. With CONVERT
335 passed as true, the lines are converted to CR,LF if required.
336 Return NULL on error or the gpgme_data_t object on success. */
337 static gpgme_data_t body_to_data_object (BODY * a, int convert)
339 char tempfile[_POSIX_PATH_MAX];
344 fptmp = m_tempfile(tempfile, sizeof(tempfile), NONULL(MCore.tmpdir), NULL);
346 mutt_perror (_("Can't create temporary file"));
350 mutt_write_mime_header (a, fptmp);
352 mutt_write_mime_body (a, fptmp);
356 unsigned char buf[1];
358 data = create_gpgme_data ();
360 while ((c = fgetc (fptmp)) != EOF) {
364 if (c == '\n' && !hadcr) {
366 gpgme_data_write (data, buf, 1);
371 /* FIXME: This is quite suboptimal */
373 gpgme_data_write (data, buf, 1);
375 gpgme_data_seek (data, 0, SEEK_SET);
377 err = gpgme_data_new_from_file (&data, tempfile, 1);
382 mutt_error (_("error allocating data object: %s\n"), gpgme_strerror (err));
389 /* Create a GPGME data object from the stream FP but limit the object
390 to LENGTH bytes starting at OFFSET bytes from the beginning of the
392 static gpgme_data_t file_to_data_object (FILE * fp, long offset, long length)
397 err = gpgme_data_new_from_filepart (&data, NULL, fp, offset, length);
399 mutt_error (_("error allocating data object: %s\n"), gpgme_strerror (err));
406 /* Write a GPGME data object to the stream FP. */
407 static int data_object_to_stream (gpgme_data_t data, FILE * fp)
413 err = ((gpgme_data_seek (data, 0, SEEK_SET) == -1)
414 ? gpgme_error_from_errno (errno) : 0);
416 mutt_error (_("error rewinding data object: %s\n"), gpgme_strerror (err));
420 while ((nread = gpgme_data_read (data, buf, sizeof (buf)))) {
421 /* fixme: we are not really converting CRLF to LF but just
422 skipping CR. Doing it correctly needs a more complex logic */
423 for (p = buf; nread; p++, nread--) {
429 mutt_perror ("[tempfile]");
434 mutt_error (_("error reading data object: %s\n"), strerror (errno));
440 /* Copy a data object to a newly created temporay file and return that
441 filename. Caller must free. With RET_FP not NULL, don't close the
442 stream but return it there. */
443 static char *data_object_to_tempfile (gpgme_data_t data, FILE ** ret_fp)
446 char tempfile[_POSIX_PATH_MAX];
450 fp = m_tempfile(tempfile, sizeof(tempfile), NONULL(MCore.tmpdir), NULL);
452 mutt_perror (_("Can't create temporary file"));
456 err = ((gpgme_data_seek (data, 0, SEEK_SET) == -1)
457 ? gpgme_error_from_errno (errno) : 0);
461 while ((nread = gpgme_data_read (data, buf, sizeof (buf)))) {
462 if (fwrite (buf, nread, 1, fp) != 1) {
463 mutt_perror (_("Can't create temporary file"));
475 mutt_error (_("error reading data object: %s\n"), gpgme_strerror (err));
482 return m_strdup(tempfile);
486 /* FIXME: stolen from gpgme to avoid "ambiguous identity" errors */
488 gpgme_get_key2 (gpgme_ctx_t ctx, const char *fpr, gpgme_key_t *r_key,
494 if (!ctx || !r_key || !fpr)
495 return gpg_error (GPG_ERR_INV_VALUE);
497 if (strlen (fpr) < 8) /* We have at least a key ID. */
498 return gpg_error (GPG_ERR_INV_VALUE);
500 /* FIXME: We use our own context because we have to avoid the user's
501 I/O callback handlers. */
502 err = gpgme_new (&listctx);
505 gpgme_set_protocol (listctx, gpgme_get_protocol (ctx));
506 err = gpgme_op_keylist_start (listctx, fpr, secret);
508 err = gpgme_op_keylist_next (listctx, r_key);
509 gpgme_release (listctx);
513 /* Create a GpgmeRecipientSet from the keys in the string KEYLIST.
514 The keys must be space delimited. */
515 static gpgme_key_t *create_recipient_set (const char *keylist,
516 gpgme_protocol_t protocol)
522 gpgme_key_t *rset = NULL;
523 unsigned int rset_n = 0;
524 gpgme_key_t key = NULL;
525 gpgme_ctx_t context = NULL;
527 err = gpgme_new (&context);
529 err = gpgme_set_protocol (context, protocol);
536 for (i = 0; *s && *s != ' ' && i < ssizeof(buf) - 1;)
540 if (i > 1 && buf[i - 1] == '!') {
541 /* The user selected to override the valididy of that
545 err = gpgme_get_key2 (context, buf, &key, 0);
547 key->uids->validity = GPGME_VALIDITY_FULL;
551 err = gpgme_get_key2 (context, buf, &key, 0);
554 p_realloc(&rset, rset_n + 1);
555 rset[rset_n++] = key;
558 mutt_error (_("error adding recipient `%s': %s\n"),
559 buf, gpgme_strerror (err));
567 /* NULL terminate. */
568 p_realloc(&rset, rset_n + 1);
569 rset[rset_n++] = NULL;
572 gpgme_release (context);
578 /* Make sure that the correct signer is set. Returns 0 on success. */
579 static int set_signer (gpgme_ctx_t ctx, int for_smime)
581 char *signid = for_smime ? SmimeDefaultKey : PgpSignAs;
584 gpgme_key_t key, key2;
586 if (!signid || !*signid)
589 listctx = create_gpgme_context (for_smime);
590 err = gpgme_op_keylist_start (listctx, signid, 1);
592 err = gpgme_op_keylist_next (listctx, &key);
594 gpgme_release (listctx);
595 mutt_error (_("secret key `%s' not found: %s\n"),
596 signid, gpgme_strerror (err));
599 err = gpgme_op_keylist_next (listctx, &key2);
601 gpgme_key_release (key);
602 gpgme_key_release (key2);
603 gpgme_release (listctx);
604 mutt_error (_("ambiguous specification of secret key `%s'\n"), signid);
607 gpgme_op_keylist_end (listctx);
608 gpgme_release (listctx);
610 gpgme_signers_clear (ctx);
611 err = gpgme_signers_add (ctx, key);
612 gpgme_key_release (key);
614 mutt_error (_("error setting secret key `%s': %s\n"),
615 signid, gpgme_strerror (err));
622 /* Encrypt the gpgme data object PLAINTEXT to the recipients in RSET
623 and return an allocated filename to a temporary file containing the
624 enciphered text. With USE_SMIME set to true, the smime backend is
625 used. With COMBINED_SIGNED a PGP message is signed and
626 encrypted. Returns NULL in case of error */
627 static char *encrypt_gpgme_object (gpgme_data_t plaintext, gpgme_key_t * rset,
628 int use_smime, int combined_signed)
632 gpgme_data_t ciphertext;
635 ctx = create_gpgme_context (use_smime);
637 gpgme_set_armor (ctx, 1);
639 ciphertext = create_gpgme_data ();
641 if (combined_signed) {
642 if (set_signer (ctx, use_smime)) {
643 gpgme_data_release (ciphertext);
647 err = gpgme_op_encrypt_sign (ctx, rset, GPGME_ENCRYPT_ALWAYS_TRUST,
648 plaintext, ciphertext);
651 err = gpgme_op_encrypt (ctx, rset, GPGME_ENCRYPT_ALWAYS_TRUST,
652 plaintext, ciphertext);
653 mutt_need_hard_redraw ();
655 mutt_error (_("error encrypting data: %s\n"), gpgme_strerror (err));
656 gpgme_data_release (ciphertext);
663 outfile = data_object_to_tempfile (ciphertext, NULL);
664 gpgme_data_release (ciphertext);
668 /* Find the "micalg" parameter from the last Gpgme operation on
669 context CTX. It is expected that this operation was a sign
670 operation. Return the algorithm name as a C string in buffer BUF
671 which must have been allocated by the caller with size BUFLEN.
672 Returns 0 on success or -1 in case of an error. The return string
673 is truncted to BUFLEN - 1. */
674 static int get_micalg (gpgme_ctx_t ctx, char *buf, ssize_t buflen)
676 gpgme_sign_result_t result = NULL;
677 const char *algorithm_name = NULL;
683 result = gpgme_op_sign_result (ctx);
685 algorithm_name = gpgme_hash_algo_name (result->signatures->hash_algo);
686 if (algorithm_name) {
687 m_strcpy(buf, buflen, algorithm_name);
691 return *buf ? 0 : -1;
694 static void print_time (time_t t, STATE * s)
698 setlocale (LC_TIME, "");
699 #ifdef HAVE_LANGINFO_D_T_FMT
700 strftime (p, sizeof (p), nl_langinfo (D_T_FMT), localtime (&t));
702 strftime (p, sizeof (p), "%c", localtime (&t));
704 setlocale (LC_TIME, "C");
705 state_attach_puts (p, s);
708 /* Implementation of `sign_message'. */
710 /* Sign the MESSAGE in body A either using OpenPGP or S/MIME when
711 USE_SMIME is passed as true. Returns the new body or NULL on
713 static BODY *sign_message (BODY * a, int use_smime)
720 gpgme_data_t message, signature;
722 convert_to_7bit (a); /* Signed data _must_ be in 7-bit format. */
724 message = body_to_data_object (a, 1);
727 signature = create_gpgme_data ();
729 ctx = create_gpgme_context (use_smime);
731 gpgme_set_armor (ctx, 1);
733 if (set_signer (ctx, use_smime)) {
734 gpgme_data_release (signature);
739 err = gpgme_op_sign (ctx, message, signature, GPGME_SIG_MODE_DETACH);
740 mutt_need_hard_redraw ();
741 gpgme_data_release (message);
743 gpgme_data_release (signature);
745 mutt_error (_("error signing data: %s\n"), gpgme_strerror (err));
749 sigfile = data_object_to_tempfile (signature, NULL);
750 gpgme_data_release (signature);
757 t->type = TYPEMULTIPART;
758 t->subtype = m_strdup("signed");
759 t->encoding = ENC7BIT;
761 t->disposition = DISPINLINE;
763 parameter_set_boundary(&t->parameter);
764 parameter_setval(&t->parameter, "protocol",
765 use_smime ? "application/pkcs7-signature"
766 : "application/pgp-signature");
767 /* Get the micalg from gpgme. Old gpgme versions don't support this
768 for S/MIME so we assume sha-1 in this case. */
769 if (!get_micalg (ctx, buf, sizeof buf))
770 parameter_setval(&t->parameter, "micalg", buf);
772 parameter_setval(&t->parameter, "micalg", "sha1");
778 t->parts->next = body_new();
780 t->type = TYPEAPPLICATION;
782 t->subtype = m_strdup("pkcs7-signature");
783 parameter_setval(&t->parameter, "name", "smime.p7s");
784 t->encoding = ENCBASE64;
786 t->disposition = DISPATTACH;
787 t->d_filename = m_strdup("smime.p7s");
790 t->subtype = m_strdup("pgp-signature");
792 t->disposition = DISPINLINE;
793 t->encoding = ENC7BIT;
795 t->filename = sigfile;
796 t->unlink = 1; /* ok to remove this file after sending. */
802 * Implementation of `encrypt_message'.
805 /* Encrypt the mail body A to all keys given as space separated keyids
806 or fingerprints in KEYLIST and return the encrypted body. */
807 static BODY *crypt_pgp_encrypt_message (BODY * a, char *keylist, int sign)
809 char *outfile = NULL;
811 gpgme_key_t *rset = NULL;
812 gpgme_data_t plaintext;
814 rset = create_recipient_set (keylist, GPGME_PROTOCOL_OpenPGP);
820 plaintext = body_to_data_object (a, 0);
826 outfile = encrypt_gpgme_object (plaintext, rset, 0, sign);
827 gpgme_data_release (plaintext);
833 t->type = TYPEMULTIPART;
834 t->subtype = m_strdup("encrypted");
835 t->encoding = ENC7BIT;
837 t->disposition = DISPINLINE;
839 parameter_set_boundary(&t->parameter);
840 parameter_setval(&t->parameter, "protocol", "application/pgp-encrypted");
842 t->parts = body_new();
843 t->parts->type = TYPEAPPLICATION;
844 t->parts->subtype = m_strdup("pgp-encrypted");
845 t->parts->encoding = ENC7BIT;
847 t->parts->next = body_new();
848 t->parts->next->type = TYPEAPPLICATION;
849 t->parts->next->subtype = m_strdup("octet-stream");
850 t->parts->next->encoding = ENC7BIT;
851 t->parts->next->filename = outfile;
852 t->parts->next->use_disp = 1;
853 t->parts->next->disposition = DISPINLINE;
854 t->parts->next->unlink = 1; /* delete after sending the message */
855 t->parts->next->d_filename = m_strdup("msg.asc"); /* non pgp/mime
862 * Implementation of `smime_build_smime_entity'.
865 /* Encrypt the mail body A to all keys given as space separated
866 fingerprints in KEYLIST and return the S/MIME encrypted body. */
867 static BODY *crypt_smime_build_smime_entity (BODY * a, char *keylist)
869 char *outfile = NULL;
871 gpgme_key_t *rset = NULL;
872 gpgme_data_t plaintext;
874 rset = create_recipient_set (keylist, GPGME_PROTOCOL_CMS);
878 plaintext = body_to_data_object (a, 0);
884 outfile = encrypt_gpgme_object (plaintext, rset, 1, 0);
885 gpgme_data_release (plaintext);
891 t->type = TYPEAPPLICATION;
892 t->subtype = m_strdup("pkcs7-mime");
893 parameter_setval(&t->parameter, "name", "smime.p7m");
894 parameter_setval(&t->parameter, "smime-type", "enveloped-data");
895 t->encoding = ENCBASE64; /* The output of OpenSSL SHOULD be binary */
897 t->disposition = DISPATTACH;
898 t->d_filename = m_strdup("smime.p7m");
899 t->filename = outfile;
900 t->unlink = 1; /*delete after sending the message */
908 /* Implementation of `verify_one'. */
910 /* Display the common attributes of the signature summary SUM.
911 Return 1 if there is is a severe warning.
913 static int show_sig_summary (unsigned long sum,
914 gpgme_ctx_t ctx, gpgme_key_t key, int idx,
919 if ((sum & GPGME_SIGSUM_KEY_REVOKED)) {
920 state_attach_puts (_("Warning: One of the keys has been revoked\n"), s);
924 if ((sum & GPGME_SIGSUM_KEY_EXPIRED)) {
925 time_t at = key->subkeys->expires ? key->subkeys->expires : 0;
928 state_attach_puts (_("Warning: The key used to create the "
929 "signature expired at: "), s);
931 state_attach_puts ("\n", s);
934 state_attach_puts (_("Warning: At least one certification key "
935 "has expired\n"), s);
938 if ((sum & GPGME_SIGSUM_SIG_EXPIRED)) {
939 gpgme_verify_result_t result;
940 gpgme_signature_t sig;
943 result = gpgme_op_verify_result (ctx);
945 for (sig = result->signatures, i = 0; sig && (i < idx);
946 sig = sig->next, i++);
948 state_attach_puts (_("Warning: The signature expired at: "), s);
949 print_time (sig ? sig->exp_timestamp : 0, s);
950 state_attach_puts ("\n", s);
953 if ((sum & GPGME_SIGSUM_KEY_MISSING))
954 state_attach_puts (_("Can't verify due to a missing "
955 "key or certificate\n"), s);
957 if ((sum & GPGME_SIGSUM_CRL_MISSING)) {
958 state_attach_puts (_("The CRL is not available\n"), s);
962 if ((sum & GPGME_SIGSUM_CRL_TOO_OLD)) {
963 state_attach_puts (_("Available CRL is too old\n"), s);
967 if ((sum & GPGME_SIGSUM_BAD_POLICY))
968 state_attach_puts (_("A policy requirement was not met\n"), s);
970 if ((sum & GPGME_SIGSUM_SYS_ERROR)) {
971 const char *t0 = NULL, *t1 = NULL;
972 gpgme_verify_result_t result;
973 gpgme_signature_t sig;
976 state_attach_puts (_("A system error occurred"), s);
978 /* Try to figure out some more detailed system error information. */
979 result = gpgme_op_verify_result (ctx);
980 for (sig = result->signatures, i = 0; sig && (i < idx);
981 sig = sig->next, i++);
984 t1 = sig->wrong_key_usage ? "Wrong_Key_Usage" : "";
988 state_attach_puts (": ", s);
990 state_attach_puts (t0, s);
991 if (t1 && !(t0 && !m_strcmp(t0, t1))) {
993 state_attach_puts (",", s);
994 state_attach_puts (t1, s);
997 state_attach_puts ("\n", s);
1004 static void show_fingerprint (gpgme_key_t key, STATE * state)
1009 const char *prefix = _("Fingerprint: ");
1014 s = key->subkeys ? key->subkeys->fpr : NULL;
1017 is_pgp = (key->protocol == GPGME_PROTOCOL_OpenPGP);
1019 bufsize = m_strlen(prefix) + m_strlen(s) * 4 + 2;
1020 buf = p_new(char, bufsize);
1021 m_strcpy(buf, bufsize, prefix);
1022 p = buf + m_strlen(buf);
1023 if (is_pgp && m_strlen(s) == 40) { /* PGP v4 style formatted. */
1024 for (i = 0; *s && s[1] && s[2] && s[3] && s[4]; s += 4, i++) {
1035 for (i = 0; *s && s[1] && s[2]; s += 2, i++) {
1038 *p++ = is_pgp ? ' ' : ':';
1039 if (is_pgp && i == 7)
1044 /* just in case print remaining odd digits */
1049 state_attach_puts (buf, state);
1053 /* Show the valididy of a key used for one signature. */
1054 static void show_one_sig_validity (gpgme_ctx_t ctx, int idx, STATE * s)
1056 gpgme_verify_result_t result = NULL;
1057 gpgme_signature_t sig = NULL;
1058 const char *txt = NULL;
1060 result = gpgme_op_verify_result (ctx);
1062 for (sig = result->signatures; sig && (idx > 0); sig = sig->next, idx--);
1064 switch (sig ? sig->validity : 0) {
1065 case GPGME_VALIDITY_UNKNOWN:
1066 txt = _("WARNING: We have NO indication whether "
1067 "the key belongs to the person named " "as shown above\n");
1069 case GPGME_VALIDITY_UNDEFINED:
1071 case GPGME_VALIDITY_NEVER:
1072 txt = _("WARNING: The key does NOT BELONG to "
1073 "the person named as shown above\n");
1075 case GPGME_VALIDITY_MARGINAL:
1076 txt = _("WARNING: It is NOT certain that the key "
1077 "belongs to the person named as shown above\n");
1079 case GPGME_VALIDITY_FULL:
1080 case GPGME_VALIDITY_ULTIMATE:
1085 state_attach_puts (txt, s);
1088 /* Show information about one signature. This fucntion is called with
1089 the context CTX of a sucessful verification operation and the
1090 enumerator IDX which should start at 0 and incremete for each
1093 Return values are: 0 for normal procession, 1 for a bad signature,
1094 2 for a signature with a warning or -1 for no more signature. */
1095 static int show_one_sig_status (gpgme_ctx_t ctx, int idx, STATE * s)
1098 const char *fpr, *uid;
1099 gpgme_key_t key = NULL;
1100 int i, anybad = 0, anywarn = 0;
1102 gpgme_user_id_t uids = NULL;
1103 gpgme_verify_result_t result;
1104 gpgme_signature_t sig;
1105 gpgme_error_t err = GPG_ERR_NO_ERROR;
1107 result = gpgme_op_verify_result (ctx);
1109 /* FIXME: this code should use a static variable and remember
1110 the current position in the list of signatures, IMHO.
1113 for (i = 0, sig = result->signatures; sig && (i < idx);
1114 i++, sig = sig->next);
1116 return -1; /* Signature not found. */
1118 if (signature_key) {
1119 gpgme_key_release (signature_key);
1120 signature_key = NULL;
1123 created = sig->timestamp;
1127 if (gpg_err_code (sig->status) != GPG_ERR_NO_ERROR)
1130 err = gpgme_get_key2 (ctx, fpr, &key, 0); /* secret key? */
1132 uid = (key->uids && key->uids->uid) ? key->uids->uid : "[?]";
1134 signature_key = key;
1137 key = NULL; /* Old gpgme versions did not set KEY to NULL on
1138 error. Do it here to avoid a double free. */
1142 if (!s || !s->fpout || !(s->flags & M_DISPLAY)); /* No state information so no way to print anything. */
1144 state_attach_puts (_("Error getting key information: "), s);
1145 state_attach_puts (gpg_strerror (err), s);
1146 state_attach_puts ("\n", s);
1149 else if ((sum & GPGME_SIGSUM_GREEN)) {
1150 state_attach_puts (_("Good signature from: "), s);
1151 state_attach_puts (uid, s);
1152 state_attach_puts ("\n", s);
1153 for (i = 1, uids = key->uids; uids; i++, uids = uids->next) {
1155 /* Skip primary UID. */
1159 state_attach_puts (_(" aka: "), s);
1160 state_attach_puts (uids->uid, s);
1161 state_attach_puts ("\n", s);
1163 state_attach_puts (_(" created: "), s);
1164 print_time (created, s);
1165 state_attach_puts ("\n", s);
1166 if (show_sig_summary (sum, ctx, key, idx, s))
1168 show_one_sig_validity (ctx, idx, s);
1170 else if ((sum & GPGME_SIGSUM_RED)) {
1171 state_attach_puts (_("*BAD* signature claimed to be from: "), s);
1172 state_attach_puts (uid, s);
1173 state_attach_puts ("\n", s);
1174 show_sig_summary (sum, ctx, key, idx, s);
1176 else if (!anybad && key && (key->protocol == GPGME_PROTOCOL_OpenPGP)) { /* We can't decide (yellow) but this is a PGP key with a good
1177 signature, so we display what a PGP user expects: The name,
1178 fingerprint and the key validity (which is neither fully or
1180 state_attach_puts (_("Good signature from: "), s);
1181 state_attach_puts (uid, s);
1182 state_attach_puts ("\n", s);
1183 state_attach_puts (_(" created: "), s);
1184 print_time (created, s);
1185 state_attach_puts ("\n", s);
1186 show_one_sig_validity (ctx, idx, s);
1187 show_fingerprint (key, s);
1188 if (show_sig_summary (sum, ctx, key, idx, s))
1191 else { /* can't decide (yellow) */
1193 state_attach_puts (_("Error checking signature"), s);
1194 state_attach_puts ("\n", s);
1195 show_sig_summary (sum, ctx, key, idx, s);
1198 if (key != signature_key)
1199 gpgme_key_release (key);
1202 return anybad ? 1 : anywarn ? 2 : 0;
1205 /* Do the actual verification step. With IS_SMIME set to true we
1206 assume S/MIME (surprise!) */
1207 static int crypt_verify_one(BODY *sigbdy, STATE *s, FILE *fp, int is_smime)
1213 gpgme_data_t signature, message;
1215 signature = file_to_data_object (s->fpin, sigbdy->offset, sigbdy->length);
1219 /* We need to tell gpgme about the encoding because the backend can't
1220 auto-detect plain base-64 encoding which is used by S/MIME. */
1222 gpgme_data_set_encoding (signature, GPGME_DATA_ENCODING_BASE64);
1224 err = gpgme_data_new_from_stream(&message, fp);
1226 gpgme_data_release (signature);
1227 mutt_error (_("error allocating data object: %s\n"), gpgme_strerror (err));
1230 ctx = create_gpgme_context (is_smime);
1232 /* Note: We don't need a current time output because GPGME avoids
1233 such an attack by separating the meta information from the
1235 state_attach_puts (_("[-- Begin signature information --]\n"), s);
1237 err = gpgme_op_verify (ctx, signature, message, NULL);
1238 mutt_need_hard_redraw ();
1242 snprintf (buf, sizeof (buf) - 1,
1243 _("Error: verification failed: %s\n"), gpgme_strerror (err));
1244 state_attach_puts (buf, s);
1246 else { /* Verification succeeded, see what the result is. */
1250 if (signature_key) {
1251 gpgme_key_release (signature_key);
1252 signature_key = NULL;
1255 for (idx = 0; (res = show_one_sig_status (ctx, idx, s)) != -1; idx++) {
1266 gpgme_verify_result_t result;
1267 gpgme_sig_notation_t notation;
1268 gpgme_signature_t sig;
1270 result = gpgme_op_verify_result (ctx);
1272 for (sig = result->signatures; sig; sig = sig->next) {
1273 if (sig->notations) {
1274 state_attach_puts ("*** Begin Notation (signature by: ", s);
1275 state_attach_puts (sig->fpr, s);
1276 state_attach_puts (") ***\n", s);
1277 for (notation = sig->notations; notation; notation = notation->next)
1279 if (notation->name) {
1280 state_attach_puts (notation->name, s);
1281 state_attach_puts ("=", s);
1283 if (notation->value) {
1284 state_attach_puts (notation->value, s);
1285 if (!(*notation->value
1286 && (notation->value[m_strlen(notation->value) - 1] ==
1288 state_attach_puts ("\n", s);
1291 state_attach_puts ("*** End Notation ***\n", s);
1297 gpgme_release (ctx);
1299 state_attach_puts (_("[-- End signature information --]\n\n"), s);
1301 return badsig ? 1 : anywarn ? 2 : 0;
1305 * Implementation of `decrypt_part'.
1308 /* Decrypt a PGP or SMIME message (depending on the boolean flag
1309 IS_SMIME) with body A described further by state S. Write
1310 plaintext out to file FPOUT and return a new body. For PGP returns
1311 a flag in R_IS_SIGNED to indicate whether this is a combined
1312 encrypted and signed message, for S/MIME it returns true when it is
1313 not a encrypted but a signed message. */
1314 static BODY *decrypt_part (BODY * a, STATE * s, FILE * fpout, int is_smime,
1321 gpgme_data_t ciphertext, plaintext;
1322 int maybe_signed = 0;
1329 ctx = create_gpgme_context (is_smime);
1332 /* Make a data object from the body, create context etc. */
1333 ciphertext = file_to_data_object (s->fpin, a->offset, a->length);
1336 plaintext = create_gpgme_data ();
1338 /* Do the decryption or the verification in case of the S/MIME hack. */
1339 if ((!is_smime) || maybe_signed) {
1341 err = gpgme_op_decrypt_verify (ctx, ciphertext, plaintext);
1342 else if (maybe_signed)
1343 err = gpgme_op_verify (ctx, ciphertext, NULL, plaintext);
1346 /* Check wether signatures have been verified. */
1347 gpgme_verify_result_t verify_result = gpgme_op_verify_result (ctx);
1349 if (verify_result->signatures)
1354 err = gpgme_op_decrypt (ctx, ciphertext, plaintext);
1355 gpgme_data_release (ciphertext);
1357 if (is_smime && !maybe_signed && gpg_err_code (err) == GPG_ERR_NO_DATA) {
1358 /* Check whether this might be a signed message despite what
1359 the mime header told us. Retry then. gpgsm returns the
1360 error information "unsupported Algorithm '?'" but gpgme
1361 will not store this unknown algorithm, thus we test that
1362 it has not been set. */
1363 gpgme_decrypt_result_t result;
1365 result = gpgme_op_decrypt_result (ctx);
1366 if (!result->unsupported_algorithm) {
1368 gpgme_data_release (plaintext);
1372 mutt_need_hard_redraw ();
1373 if ((s->flags & M_DISPLAY)) {
1376 snprintf (buf, sizeof (buf) - 1,
1377 _("[-- Error: decryption failed: %s --]\n\n"),
1378 gpgme_strerror (err));
1379 state_attach_puts (buf, s);
1381 gpgme_data_release (plaintext);
1382 gpgme_release (ctx);
1385 mutt_need_hard_redraw ();
1387 /* Read the output from GPGME, and make sure to change CRLF to LF,
1388 otherwise read_mime_header has a hard time parsing the message. */
1389 if (data_object_to_stream (plaintext, fpout)) {
1390 gpgme_data_release (plaintext);
1391 gpgme_release (ctx);
1394 gpgme_data_release (plaintext);
1396 a->is_signed_data = 0;
1402 a->is_signed_data = 1;
1404 *r_is_signed = -1; /* A signature exists. */
1406 if ((s->flags & M_DISPLAY))
1407 state_attach_puts (_("[-- Begin signature " "information --]\n"), s);
1408 for (idx = 0; (res = show_one_sig_status (ctx, idx, s)) != -1; idx++) {
1414 if (!anybad && idx && r_is_signed && *r_is_signed)
1415 *r_is_signed = anywarn ? 2 : 1; /* Good signature. */
1417 if ((s->flags & M_DISPLAY))
1418 state_attach_puts (_("[-- End signature " "information --]\n\n"), s);
1420 gpgme_release (ctx);
1425 tattach = mutt_read_mime_header (fpout, 0);
1428 * Need to set the length of this body part.
1430 fstat (fileno (fpout), &info);
1431 tattach->length = info.st_size - tattach->offset;
1433 tattach->warnsig = anywarn;
1435 /* See if we need to recurse on this MIME part. */
1436 mutt_parse_part (fpout, tattach);
1442 /* Decrypt a PGP/MIME message in FPIN and B and return a new body and
1443 the stream in CUR and FPOUT. Returns 0 on success. */
1444 int crypt_pgp_decrypt_mime (FILE * fpin, FILE ** fpout, BODY * b, BODY ** cur)
1446 char tempfile[_POSIX_PATH_MAX];
1448 BODY *first_part = b;
1451 first_part->goodsig = 0;
1452 first_part->warnsig = 0;
1454 if (!mutt_is_multipart_encrypted (b))
1457 if (!b->parts || !b->parts->next)
1464 *fpout = m_tempfile(tempfile, sizeof(tempfile), NONULL(MCore.tmpdir), NULL);
1466 mutt_perror (_("Can't create temporary file"));
1471 *cur = decrypt_part (b, &s, *fpout, 0, &is_signed);
1474 first_part->goodsig = 1;
1476 return *cur ? 0 : -1;
1480 /* Decrypt a S/MIME message in FPIN and B and return a new body and
1481 the stream in CUR and FPOUT. Returns 0 on success. */
1482 int crypt_smime_decrypt_mime (FILE * fpin, FILE ** fpout, BODY * b,
1485 char tempfile[_POSIX_PATH_MAX];
1489 long saved_b_offset;
1490 ssize_t saved_b_length;
1493 if (!mutt_is_application_smime (b))
1499 /* Decode the body - we need to pass binary CMS to the
1500 backend. The backend allows for Base64 encoded data but it does
1501 not allow for QP which I have seen in some messages. So better
1503 saved_b_type = b->type;
1504 saved_b_offset = b->offset;
1505 saved_b_length = b->length;
1508 fseeko (s.fpin, b->offset, 0);
1509 tmpfp = m_tempfile (tempfile, sizeof(tempfile), NONULL(MCore.tmpdir), NULL);
1511 mutt_perror (_("Can't create temporary file"));
1514 mutt_unlink (tempfile);
1517 mutt_decode_attachment (b, &s);
1519 b->length = ftello (s.fpout);
1526 *fpout = m_tempfile(tempfile, sizeof(tempfile), NONULL(MCore.tmpdir), NULL);
1528 mutt_perror (_("Can't create temporary file"));
1531 mutt_unlink (tempfile);
1533 *cur = decrypt_part (b, &s, *fpout, 1, &is_signed);
1535 (*cur)->goodsig = is_signed > 0;
1536 b->type = saved_b_type;
1537 b->length = saved_b_length;
1538 b->offset = saved_b_offset;
1541 if (*cur && !is_signed && !(*cur)->parts
1542 && mutt_is_application_smime (*cur)) {
1543 /* Assume that this is a opaque signed s/mime message. This is
1544 an ugly way of doing it but we have anyway a problem with
1545 arbitrary encoded S/MIME messages: Only the outer part may be
1546 encrypted. The entire mime parsing should be revamped,
1547 probably by keeping the temportary files so that we don't
1548 need to decrypt them all the time. Inner parts of an
1549 encrypted part can then pint into this file and tehre won't
1550 never be a need to decrypt again. This needs a partial
1551 rewrite of the MIME engine. */
1555 saved_b_type = bb->type;
1556 saved_b_offset = bb->offset;
1557 saved_b_length = bb->length;
1560 fseeko (s.fpin, bb->offset, 0);
1561 tmpfp = m_tempfile (tempfile, sizeof(tempfile), NONULL(MCore.tmpdir), NULL);
1563 mutt_perror (_("Can't create temporary file"));
1566 mutt_unlink (tempfile);
1569 mutt_decode_attachment (bb, &s);
1571 bb->length = ftello (s.fpout);
1579 *fpout = m_tempfile(tempfile, sizeof(tempfile), NONULL(MCore.tmpdir), NULL);
1581 mutt_perror (_("Can't create temporary file"));
1584 mutt_unlink (tempfile);
1586 tmp_b = decrypt_part (bb, &s, *fpout, 1, &is_signed);
1588 tmp_b->goodsig = is_signed > 0;
1589 bb->type = saved_b_type;
1590 bb->length = saved_b_length;
1591 bb->offset = saved_b_offset;
1594 body_list_wipe(cur);
1597 return *cur ? 0 : -1;
1602 * Implementation of `pgp_check_traditional'.
1605 static int pgp_check_traditional_one_body (FILE * fp, BODY * b,
1608 char tempfile[_POSIX_PATH_MAX];
1609 char buf[HUGE_STRING];
1616 if (b->type != TYPETEXT)
1619 if (tagged_only && !b->tagged)
1622 tempfd = m_tempfd(tempfile, sizeof(tempfile), NONULL(MCore.tmpdir), NULL);
1623 if (mutt_decode_save_attachment (fp, b, tempfd, 0) != 0) {
1628 if ((tfp = fopen(tempfile, "r")) == NULL) {
1633 while (fgets (buf, sizeof (buf), tfp)) {
1634 if (!m_strncmp("-----BEGIN PGP ", buf, 15)) {
1635 if (!m_strcmp("MESSAGE-----\n", buf + 15))
1637 else if (!m_strcmp("SIGNED MESSAGE-----\n", buf + 15))
1647 /* fix the content type */
1649 parameter_setval(&b->parameter, "format", "fixed");
1650 parameter_setval(&b->parameter, "x-action",
1651 enc ? "pgp-encrypted" : "pgp-signed");
1655 int crypt_pgp_check_traditional (FILE * fp, BODY * b, int tagged_only)
1660 for (; b; b = b->next) {
1661 if (is_multipart (b))
1662 rv = (crypt_pgp_check_traditional (fp, b->parts, tagged_only) || rv);
1663 else if (b->type == TYPETEXT) {
1664 if ((r = mutt_is_application_pgp (b)))
1667 rv = (pgp_check_traditional_one_body (fp, b, tagged_only) || rv);
1674 /* Implementation of `application_handler'. */
1677 Copy a clearsigned message, and strip the signature and PGP's
1680 XXX - charset handling: We assume that it is safe to do
1681 character set decoding first, dash decoding second here, while
1682 we do it the other way around in the main handler.
1684 (Note that we aren't worse than Outlook & Cie in this, and also
1685 note that we can successfully handle anything produced by any
1686 existing versions of mutt.) */
1688 static void copy_clearsigned (gpgme_data_t data, STATE * s, char *charset)
1690 char buf[HUGE_STRING];
1691 short complete, armor_header;
1696 fname = data_object_to_tempfile (data, &fp);
1702 fc = fgetconv_open (fp, charset, MCharset.charset, M_ICONV_HOOK_FROM);
1704 for (complete = 1, armor_header = 1;
1705 fgetconvs (buf, sizeof (buf), fc) != NULL;
1706 complete = strchr (buf, '\n') != NULL) {
1709 state_puts (buf, s);
1713 if (!m_strcmp(buf, "-----BEGIN PGP SIGNATURE-----\n"))
1723 state_puts (s->prefix, s);
1725 if (buf[0] == '-' && buf[1] == ' ')
1726 state_puts (buf + 2, s);
1728 state_puts (buf, s);
1731 fgetconv_close (&fc);
1736 /* Support for classic_application/pgp */
1737 int crypt_pgp_application_pgp_handler (BODY * m, STATE * s)
1739 int needpass = -1, pgp_keyblock = 0;
1743 off_t last_pos, offset;
1744 char buf[HUGE_STRING];
1745 FILE *pgpout = NULL;
1747 gpgme_error_t err = 0;
1748 gpgme_data_t armored_data = NULL;
1750 short maybe_goodsig = 1;
1751 short have_any_sigs = 0;
1753 char body_charset[STRING]; /* Only used for clearsigned messages. */
1755 /* For clearsigned messages we won't be able to get a character set
1756 but we know that this may only be text thus we assume Latin-1
1758 if (!mutt_get_body_charset (body_charset, sizeof (body_charset), m))
1759 m_strcpy(body_charset, sizeof(body_charset), "iso-8859-1");
1761 fseeko (s->fpin, m->offset, 0);
1762 last_pos = m->offset;
1764 for (bytes = m->length; bytes > 0;) {
1765 if (fgets (buf, sizeof (buf), s->fpin) == NULL)
1768 offset = ftello (s->fpin);
1769 bytes -= (offset - last_pos); /* don't rely on m_strlen(buf) */
1772 if (!m_strncmp("-----BEGIN PGP ", buf, 15)) {
1774 start_pos = last_pos;
1776 if (!m_strcmp("MESSAGE-----\n", buf + 15))
1778 else if (!m_strcmp("SIGNED MESSAGE-----\n", buf + 15)) {
1782 else if (!option (OPTDONTHANDLEPGPKEYS) &&
1783 !m_strcmp("PUBLIC KEY BLOCK-----\n", buf + 15)) {
1788 /* XXX - we may wish to recode here */
1790 state_puts (s->prefix, s);
1791 state_puts (buf, s);
1795 have_any_sigs = (have_any_sigs || (clearsign && (s->flags & M_VERIFY)));
1797 /* Copy PGP material to an data container */
1798 armored_data = create_gpgme_data ();
1799 gpgme_data_write (armored_data, buf, m_strlen(buf));
1800 while (bytes > 0 && fgets (buf, sizeof (buf) - 1, s->fpin) != NULL) {
1801 offset = ftello (s->fpin);
1802 bytes -= (offset - last_pos); /* don't rely on m_strlen(buf) */
1805 gpgme_data_write (armored_data, buf, m_strlen(buf));
1807 if ((needpass && !m_strcmp("-----END PGP MESSAGE-----\n", buf))
1809 && (!m_strcmp("-----END PGP SIGNATURE-----\n", buf)
1810 || !m_strcmp("-----END PGP PUBLIC KEY BLOCK-----\n",
1815 /* Invoke PGP if needed */
1816 if (!clearsign || (s->flags & M_VERIFY)) {
1817 unsigned int sig_stat = 0;
1818 gpgme_data_t plaintext;
1821 plaintext = create_gpgme_data ();
1822 ctx = create_gpgme_context (0);
1825 err = gpgme_op_verify (ctx, armored_data, NULL, plaintext);
1827 err = gpgme_op_decrypt_verify (ctx, armored_data, plaintext);
1828 if (gpg_err_code (err) == GPG_ERR_NO_DATA) {
1829 /* Decrypt verify can't handle signed only messages. */
1830 err = (gpgme_data_seek (armored_data, 0, SEEK_SET) == -1)
1831 ? gpgme_error_from_errno (errno) : 0;
1832 /* Must release plaintext so that we supply an
1833 uninitialized object. */
1834 gpgme_data_release (plaintext);
1835 plaintext = create_gpgme_data ();
1836 err = gpgme_op_verify (ctx, armored_data, NULL, plaintext);
1843 snprintf (errbuf, sizeof (errbuf) - 1,
1844 _("Error: decryption/verification failed: %s\n"),
1845 gpgme_strerror (err));
1846 state_attach_puts (errbuf, s);
1848 else { /* Decryption/Verification succeeded */
1852 /* Check wether signatures have been verified. */
1853 gpgme_verify_result_t verify_result;
1855 verify_result = gpgme_op_verify_result (ctx);
1856 if (verify_result->signatures)
1862 if ((s->flags & M_DISPLAY) && sig_stat) {
1867 state_attach_puts (_("[-- Begin signature "
1868 "information --]\n"), s);
1871 (res = show_one_sig_status (ctx, idx, s)) != -1; idx++) {
1880 state_attach_puts (_("[-- End signature "
1881 "information --]\n\n"), s);
1884 tmpfname = data_object_to_tempfile (plaintext, &pgpout);
1887 state_attach_puts (_("Error: copy data failed\n"), s);
1891 p_delete(&tmpfname);
1894 gpgme_release (ctx);
1898 * Now, copy cleartext to the screen. NOTE - we expect that PGP
1899 * outputs utf-8 cleartext. This may not always be true, but it
1900 * seems to be a reasonable guess.
1903 if (s->flags & M_DISPLAY) {
1905 state_attach_puts (_("[-- BEGIN PGP MESSAGE --]\n\n"), s);
1906 else if (pgp_keyblock)
1907 state_attach_puts (_("[-- BEGIN PGP PUBLIC KEY BLOCK --]\n"), s);
1909 state_attach_puts (_("[-- BEGIN PGP SIGNED MESSAGE --]\n\n"), s);
1913 copy_clearsigned (armored_data, s, body_charset);
1920 fc = fgetconv_open (pgpout, "utf-8", MCharset.charset, 0);
1921 while ((c = fgetconv (fc)) != EOF) {
1923 if (c == '\n' && s->prefix)
1924 state_puts (s->prefix, s);
1926 fgetconv_close (&fc);
1929 if (s->flags & M_DISPLAY) {
1930 state_putc ('\n', s);
1932 state_attach_puts (_("[-- END PGP MESSAGE --]\n"), s);
1933 else if (pgp_keyblock)
1934 state_attach_puts (_("[-- END PGP PUBLIC KEY BLOCK --]\n"), s);
1936 state_attach_puts (_("[-- END PGP SIGNED MESSAGE --]\n"), s);
1944 /* XXX - we may wish to recode here */
1946 state_puts (s->prefix, s);
1947 state_puts (buf, s);
1951 m->goodsig = (maybe_goodsig && have_any_sigs);
1953 if (needpass == -1) {
1954 state_attach_puts (_("[-- Error: could not find beginning"
1955 " of PGP message! --]\n\n"), s);
1961 /* Implementation of `encrypted_handler'. */
1963 /* MIME handler for pgp/mime encrypted messages. */
1964 int crypt_pgp_encrypted_handler (BODY * a, STATE * s)
1966 char tempfile[_POSIX_PATH_MAX];
1969 BODY *orig_body = a;
1974 if (!a || a->type != TYPEAPPLICATION || !a->subtype
1975 || ascii_strcasecmp ("pgp-encrypted", a->subtype)
1976 || !a->next || a->next->type != TYPEAPPLICATION || !a->next->subtype
1977 || ascii_strcasecmp ("octet-stream", a->next->subtype)) {
1978 if (s->flags & M_DISPLAY)
1979 state_attach_puts (_("[-- Error: malformed PGP/MIME message! --]\n\n"),
1984 /* Move forward to the application/pgp-encrypted body. */
1987 fpout = m_tempfile(tempfile, sizeof(tempfile), NONULL(MCore.tmpdir), NULL);
1989 if (s->flags & M_DISPLAY)
1990 state_attach_puts (_("[-- Error: could not create temporary file! "
1995 tattach = decrypt_part (a, s, fpout, 0, &is_signed);
1997 tattach->goodsig = is_signed > 0;
1999 if (s->flags & M_DISPLAY)
2000 state_attach_puts (is_signed ?
2002 ("[-- The following data is PGP/MIME signed and encrypted --]\n\n") :
2003 _("[-- The following data is PGP/MIME encrypted --]\n\n"), s);
2006 FILE *savefp = s->fpin;
2009 rc = mutt_body_handler (tattach, s);
2014 * if a multipart/signed is the _only_ sub-part of a
2015 * multipart/encrypted, cache signature verification
2018 if (mutt_is_multipart_signed (tattach) && !tattach->next)
2019 orig_body->goodsig |= tattach->goodsig;
2021 if (s->flags & M_DISPLAY) {
2022 state_puts ("\n", s);
2023 state_attach_puts (is_signed ?
2025 ("[-- End of PGP/MIME signed and encrypted data --]\n")
2026 : _("[-- End of PGP/MIME encrypted data --]\n"), s);
2029 body_list_wipe(&tattach);
2033 mutt_unlink (tempfile);
2037 /* Support for application/smime */
2038 int crypt_smime_application_smime_handler (BODY * a, STATE * s)
2040 char tempfile[_POSIX_PATH_MAX];
2047 fpout = m_tempfile(tempfile, sizeof(tempfile), NONULL(MCore.tmpdir), NULL);
2049 if (s->flags & M_DISPLAY)
2050 state_attach_puts (_("[-- Error: could not create temporary file! "
2055 tattach = decrypt_part (a, s, fpout, 1, &is_signed);
2057 tattach->goodsig = is_signed > 0;
2059 if (s->flags & M_DISPLAY)
2060 state_attach_puts (is_signed ?
2061 _("[-- The following data is S/MIME signed --]\n\n") :
2062 _("[-- The following data is S/MIME encrypted --]\n\n"), s);
2065 FILE *savefp = s->fpin;
2068 rc = mutt_body_handler (tattach, s);
2073 * if a multipart/signed is the _only_ sub-part of a
2074 * multipart/encrypted, cache signature verification
2077 if (mutt_is_multipart_signed (tattach) && !tattach->next) {
2078 if (!(a->goodsig = tattach->goodsig))
2079 a->warnsig = tattach->warnsig;
2081 else if (tattach->goodsig) {
2083 a->warnsig = tattach->warnsig;
2086 if (s->flags & M_DISPLAY) {
2087 state_puts ("\n", s);
2088 state_attach_puts (is_signed ?
2089 _("[-- End of S/MIME signed data --]\n") :
2090 _("[-- End of S/MIME encrypted data --]\n"), s);
2093 body_list_wipe(&tattach);
2097 mutt_unlink (tempfile);
2103 * Format an entry on the CRYPT key selection menu.
2106 * %k key id %K key id of the principal key
2108 * %a algorithm %A algorithm of the princ. key
2109 * %l length %L length of the princ. key
2110 * %f flags %F flags of the princ. key
2111 * %c capabilities %C capabilities of the princ. key
2112 * %t trust/validity of the key-uid association
2114 * %[...] date of key using strftime(3)
2118 crypt_entry_fmt (char *dest, ssize_t destlen, char op,
2119 const char *src, const char *prefix,
2120 const char *ifstr, const char *elstr,
2121 anytype data, format_flag flags)
2124 crypt_entry_t *entry;
2127 int optional = (flags & M_FORMAT_OPTIONAL);
2128 const char *s = NULL;
2134 /* if (isupper ((unsigned char) op)) */
2137 kflags = (key->flags /*| (pkey->flags & KEYFLAG_RESTRICTIONS)
2140 switch (ascii_tolower (op)) {
2144 char buf2[STRING], *p;
2160 while (len > 0 && *cp != ']') {
2169 break; /* not enough space */
2179 if (do_locales && Locale)
2180 setlocale (LC_TIME, Locale);
2185 if (key->kobj->subkeys && (key->kobj->subkeys->timestamp > 0))
2186 tt = key->kobj->subkeys->timestamp;
2188 tm = localtime (&tt);
2190 strftime (buf2, sizeof (buf2), dest, tm);
2193 setlocale (LC_TIME, "C");
2195 snprintf (fmt, sizeof (fmt), "%%%ss", prefix);
2196 snprintf (dest, destlen, fmt, buf2);
2203 snprintf (fmt, sizeof (fmt), "%%%sd", prefix);
2204 snprintf (dest, destlen, fmt, entry->num);
2209 /* fixme: we need a way to distinguish between main and subkeys.
2210 Store the idx in entry? */
2211 snprintf (fmt, sizeof (fmt), "%%%ss", prefix);
2212 snprintf (dest, destlen, fmt, crypt_keyid (key));
2217 snprintf (fmt, sizeof (fmt), "%%%ss", prefix);
2218 snprintf (dest, destlen, fmt, key->uid);
2223 snprintf (fmt, sizeof (fmt), "%%%s.3s", prefix);
2224 if (key->kobj->subkeys)
2225 s = gpgme_pubkey_algo_name (key->kobj->subkeys->pubkey_algo);
2228 snprintf (dest, destlen, fmt, s);
2233 snprintf (fmt, sizeof (fmt), "%%%slu", prefix);
2234 if (key->kobj->subkeys)
2235 val = key->kobj->subkeys->length;
2238 snprintf (dest, destlen, fmt, val);
2243 snprintf (fmt, sizeof (fmt), "%%%sc", prefix);
2244 snprintf (dest, destlen, fmt, crypt_flags (kflags));
2246 else if (!(kflags & (KEYFLAG_RESTRICTIONS)))
2251 snprintf (fmt, sizeof (fmt), "%%%ss", prefix);
2252 snprintf (dest, destlen, fmt, crypt_key_abilities (kflags));
2254 else if (!(kflags & (KEYFLAG_ABILITIES)))
2258 if ((kflags & KEYFLAG_ISX509))
2261 gpgme_user_id_t uid = NULL;
2264 for (i = 0, uid = key->kobj->uids; uid && (i < key->idx);
2265 i++, uid = uid->next);
2267 switch (uid->validity) {
2268 case GPGME_VALIDITY_UNDEFINED:
2271 case GPGME_VALIDITY_NEVER:
2274 case GPGME_VALIDITY_MARGINAL:
2277 case GPGME_VALIDITY_FULL:
2280 case GPGME_VALIDITY_ULTIMATE:
2283 case GPGME_VALIDITY_UNKNOWN:
2289 snprintf (fmt, sizeof (fmt), "%%%sc", prefix);
2290 snprintf (dest, destlen, fmt, s ? *s : 'B');
2293 snprintf (fmt, sizeof (fmt), "%%%ss", prefix);
2294 snprintf (dest, destlen, fmt,
2295 gpgme_get_protocol_name (key->kobj->protocol));
2302 if (flags & M_FORMAT_OPTIONAL)
2303 m_strformat(dest, destlen, 0, optional ? ifstr: elstr,
2304 mutt_attach_fmt, data, 0);
2308 /* Used by the display fucntion to format a line. */
2309 static void crypt_entry (char *s, ssize_t l, MUTTMENU * menu, int num)
2311 crypt_key_t **key_table = (crypt_key_t **) menu->data;
2312 crypt_entry_t entry;
2314 entry.key = key_table[num];
2315 entry.num = num + 1;
2317 m_strformat(s, l, COLS - SW, PgpEntryFormat, crypt_entry_fmt, &entry,
2318 option(OPTARROWCURSOR) ? M_FORMAT_ARROWCURSOR : 0);
2321 /* Compare two addresses and the keyid to be used for sorting. */
2322 static int _crypt_compare_address (const void *a, const void *b)
2324 crypt_key_t **s = (crypt_key_t **) a;
2325 crypt_key_t **t = (crypt_key_t **) b;
2328 if ((r = m_strcasecmp((*s)->uid, (*t)->uid)))
2331 return m_strcasecmp(crypt_keyid (*s), crypt_keyid (*t)) > 0;
2334 static int crypt_compare_address (const void *a, const void *b)
2336 return ((PgpSortKeys & SORT_REVERSE) ? !_crypt_compare_address (a, b)
2337 : _crypt_compare_address (a, b));
2341 /* Compare two key IDs and the addresses to be used for sorting. */
2342 static int _crypt_compare_keyid (const void *a, const void *b)
2344 crypt_key_t **s = (crypt_key_t **) a;
2345 crypt_key_t **t = (crypt_key_t **) b;
2348 if ((r = m_strcasecmp(crypt_keyid (*s), crypt_keyid (*t))))
2351 return m_strcasecmp((*s)->uid, (*t)->uid) > 0;
2354 static int crypt_compare_keyid (const void *a, const void *b)
2356 return ((PgpSortKeys & SORT_REVERSE) ? !_crypt_compare_keyid (a, b)
2357 : _crypt_compare_keyid (a, b));
2360 /* Compare 2 creation dates and the addresses. For sorting. */
2361 static int _crypt_compare_date (const void *a, const void *b)
2363 crypt_key_t **s = (crypt_key_t **) a;
2364 crypt_key_t **t = (crypt_key_t **) b;
2365 unsigned long ts = 0, tt = 0;
2367 if ((*s)->kobj->subkeys && ((*s)->kobj->subkeys->timestamp > 0))
2368 ts = (*s)->kobj->subkeys->timestamp;
2369 if ((*t)->kobj->subkeys && ((*t)->kobj->subkeys->timestamp > 0))
2370 tt = (*t)->kobj->subkeys->timestamp;
2377 return m_strcasecmp((*s)->uid, (*t)->uid) > 0;
2380 static int crypt_compare_date (const void *a, const void *b)
2382 return ((PgpSortKeys & SORT_REVERSE) ? !_crypt_compare_date (a, b)
2383 : _crypt_compare_date (a, b));
2386 /* Compare two trust values, the key length, the creation dates. the
2387 addresses and the key IDs. For sorting. */
2388 static int _crypt_compare_trust (const void *a, const void *b)
2390 crypt_key_t **s = (crypt_key_t **) a;
2391 crypt_key_t **t = (crypt_key_t **) b;
2392 unsigned long ts = 0, tt = 0;
2395 if ((r = (((*s)->flags & (KEYFLAG_RESTRICTIONS))
2396 - ((*t)->flags & (KEYFLAG_RESTRICTIONS)))))
2399 if ((*s)->kobj->uids)
2400 ts = (*s)->kobj->uids->validity;
2401 if ((*t)->kobj->uids)
2402 tt = (*t)->kobj->uids->validity;
2403 if ((r = (tt - ts)))
2406 if ((*s)->kobj->subkeys)
2407 ts = (*s)->kobj->subkeys->length;
2408 if ((*t)->kobj->subkeys)
2409 tt = (*t)->kobj->subkeys->length;
2413 if ((*s)->kobj->subkeys && ((*s)->kobj->subkeys->timestamp > 0))
2414 ts = (*s)->kobj->subkeys->timestamp;
2415 if ((*t)->kobj->subkeys && ((*t)->kobj->subkeys->timestamp > 0))
2416 tt = (*t)->kobj->subkeys->timestamp;
2422 if ((r = m_strcasecmp((*s)->uid, (*t)->uid)))
2424 return (m_strcasecmp(crypt_keyid ((*s)), crypt_keyid ((*t)))) > 0;
2427 static int crypt_compare_trust (const void *a, const void *b)
2429 return ((PgpSortKeys & SORT_REVERSE) ? !_crypt_compare_trust (a, b)
2430 : _crypt_compare_trust (a, b));
2433 /* Print the X.500 Distinguished Name part KEY from the array of parts
2435 static int print_dn_part (FILE * fp, struct dn_array_s *dn, const char *key)
2439 for (; dn->key; dn++) {
2440 if (!m_strcmp(dn->key, key)) {
2443 print_utf8 (fp, dn->value, m_strlen(dn->value));
2450 /* Print all parts of a DN in a standard sequence. */
2451 static void print_dn_parts (FILE * fp, struct dn_array_s *dn)
2453 const char *stdpart[] = {
2454 "CN", "OU", "O", "STREET", "L", "ST", "C", NULL
2456 int any = 0, any2 = 0, i;
2458 for (i = 0; stdpart[i]; i++) {
2461 any = print_dn_part (fp, dn, stdpart[i]);
2463 /* now print the rest without any specific ordering */
2464 for (; dn->key; dn++) {
2465 for (i = 0; stdpart[i]; i++) {
2466 if (!m_strcmp(dn->key, stdpart[i]))
2474 any = print_dn_part (fp, dn, dn->key);
2483 /* Parse an RDN; this is a helper to parse_dn(). */
2484 static const unsigned char *parse_dn_part (struct dn_array_s *array,
2485 const unsigned char *string)
2487 const unsigned char *s, *s1;
2491 /* parse attributeType */
2492 for (s = string + 1; *s && *s != '='; s++);
2494 return NULL; /* error */
2497 return NULL; /* empty key */
2498 array->key = p_dupstr(string, n );
2499 p = (unsigned char *) array->key;
2502 if (*string == '#') { /* hexstring */
2504 for (s = string; hexval(*s) >= 0; s++)
2508 return NULL; /* empty or odd number of digits */
2510 p = p_new(unsigned char, n + 1);
2511 array->value = (char *) p;
2512 for (s1 = string; n; s1 += 2, n--)
2513 *p++ = (hexval(*s1) << 8) | hexval(*s1);
2516 else { /* regular v3 quoted string */
2517 for (n = 0, s = string; *s; s++) {
2518 if (*s == '\\') { /* pair */
2520 if (*s == ',' || *s == '=' || *s == '+'
2521 || *s == '<' || *s == '>' || *s == '#' || *s == ';'
2522 || *s == '\\' || *s == '\"' || *s == ' ')
2524 else if (hexval(*s) >= 0 && hexval(*s + 1) >= 0) {
2529 return NULL; /* invalid escape sequence */
2531 else if (*s == '\"')
2532 return NULL; /* invalid encoding */
2533 else if (*s == ',' || *s == '=' || *s == '+'
2534 || *s == '<' || *s == '>' || *s == '#' || *s == ';')
2540 p = p_new(unsigned char, n + 1);
2541 array->value = (char *) p;
2542 for (s = string; n; s++, n--) {
2545 if (hexval(*s) >= 0) {
2546 *p++ = (hexval(*s) << 8) | hexval(*s + 1);
2561 /* Parse a DN and return an array-ized one. This is not a validating
2562 parser and it does not support any old-stylish syntax; gpgme is
2563 expected to return only rfc2253 compatible strings. */
2564 static struct dn_array_s *parse_dn (const unsigned char *string)
2566 struct dn_array_s *array;
2567 ssize_t arrayidx, arraysize;
2570 arraysize = 7; /* C,ST,L,O,OU,CN,email */
2571 array = p_new(struct dn_array_s, arraysize + 1);
2574 while (*string == ' ')
2578 if (arrayidx >= arraysize) { /* mutt lacks a real safe_realoc - so we need to copy */
2579 struct dn_array_s *a2;
2582 a2 = p_new(struct dn_array_s, arraysize + 1);
2583 for (i = 0; i < arrayidx; i++) {
2584 a2[i].key = array[i].key;
2585 a2[i].value = array[i].value;
2590 array[arrayidx].key = NULL;
2591 array[arrayidx].value = NULL;
2592 string = parse_dn_part (array + arrayidx, string);
2596 while (*string == ' ')
2598 if (*string && *string != ',' && *string != ';' && *string != '+')
2599 goto failure; /* invalid delimiter */
2603 array[arrayidx].key = NULL;
2604 array[arrayidx].value = NULL;
2608 for (i = 0; i < arrayidx; i++) {
2609 p_delete(&array[i].key);
2610 p_delete(&array[i].value);
2617 /* Print a nice representation of the USERID and make sure it is
2618 displayed in a proper way, which does mean to reorder some parts
2619 for S/MIME's DNs. USERID is a string as returned by the gpgme key
2620 functions. It is utf-8 encoded. */
2621 static void parse_and_print_user_id(FILE * fp, const char *userid)
2626 if (*userid == '<') {
2627 s = strchr (userid + 1, '>');
2629 print_utf8 (fp, userid + 1, s - userid - 1);
2631 else if (*userid == '(')
2632 fputs (_("[Can't display this user ID (unknown encoding)]"), fp);
2633 else if (*userid & ~127 || __m_strdigits[(int)*userid] == 255)
2634 fputs (_("[Can't display this user ID (invalid encoding)]"), fp);
2636 struct dn_array_s *dn = parse_dn ((const unsigned char *) userid);
2639 fputs (_("[Can't display this user ID (invalid DN)]"), fp);
2641 print_dn_parts (fp, dn);
2642 for (i = 0; dn[i].key; i++) {
2643 p_delete(&dn[i].key);
2644 p_delete(&dn[i].value);
2652 KEY_CAP_CAN_ENCRYPT,
2657 static unsigned int key_check_cap (gpgme_key_t key, key_cap_t cap)
2659 gpgme_subkey_t subkey = NULL;
2660 unsigned int ret = 0;
2663 case KEY_CAP_CAN_ENCRYPT:
2664 if (!(ret = key->can_encrypt))
2665 for (subkey = key->subkeys; subkey; subkey = subkey->next)
2666 if ((ret = subkey->can_encrypt))
2669 case KEY_CAP_CAN_SIGN:
2670 if (!(ret = key->can_sign))
2671 for (subkey = key->subkeys; subkey; subkey = subkey->next)
2672 if ((ret = subkey->can_sign))
2675 case KEY_CAP_CAN_CERTIFY:
2676 if (!(ret = key->can_certify))
2677 for (subkey = key->subkeys; subkey; subkey = subkey->next)
2678 if ((ret = subkey->can_certify))
2687 /* Print verbose information about a key or certificate to FP. */
2688 static void print_key_info (gpgme_key_t key, FILE * fp)
2691 const char *s = NULL, *s2 = NULL;
2694 char shortbuf[STRING];
2695 unsigned long aval = 0;
2699 gpgme_user_id_t uid = NULL;
2702 setlocale (LC_TIME, Locale);
2704 is_pgp = key->protocol == GPGME_PROTOCOL_OpenPGP;
2706 for (idx = 0, uid = key->uids; uid; idx++, uid = uid->next) {
2711 fputs (idx ? _(" aka ......: ") :_("Name ......: "), fp);
2714 fputs (_("[Invalid]"), fp);
2718 print_utf8 (fp, s, m_strlen(s));
2720 parse_and_print_user_id (fp, s);
2724 if (key->subkeys && (key->subkeys->timestamp > 0)) {
2725 tt = key->subkeys->timestamp;
2727 tm = localtime (&tt);
2728 #ifdef HAVE_LANGINFO_D_T_FMT
2729 strftime (shortbuf, sizeof shortbuf, nl_langinfo (D_T_FMT), tm);
2731 strftime (shortbuf, sizeof shortbuf, "%c", tm);
2733 fprintf (fp, _("Valid From : %s\n"), shortbuf);
2736 if (key->subkeys && (key->subkeys->expires > 0)) {
2737 tt = key->subkeys->expires;
2739 tm = localtime (&tt);
2740 #ifdef HAVE_LANGINFO_D_T_FMT
2741 strftime (shortbuf, sizeof shortbuf, nl_langinfo (D_T_FMT), tm);
2743 strftime (shortbuf, sizeof shortbuf, "%c", tm);
2745 fprintf (fp, _("Valid To ..: %s\n"), shortbuf);
2749 s = gpgme_pubkey_algo_name (key->subkeys->pubkey_algo);
2753 s2 = is_pgp ? "PGP" : "X.509";
2756 aval = key->subkeys->length;
2758 fprintf (fp, _("Key Type ..: %s, %lu bit %s\n"), s2, aval, s);
2760 fprintf (fp, _("Key Usage .: "));
2763 if (key_check_cap (key, KEY_CAP_CAN_ENCRYPT)) {
2764 fprintf (fp, "%s%s", delim, _("encryption"));
2767 if (key_check_cap (key, KEY_CAP_CAN_SIGN)) {
2768 fprintf (fp, "%s%s", delim, _("signing"));
2771 if (key_check_cap (key, KEY_CAP_CAN_CERTIFY)) {
2772 fprintf (fp, "%s%s", delim, _("certification"));
2778 s = key->subkeys->fpr;
2779 fputs (_("Fingerprint: "), fp);
2780 if (is_pgp && m_strlen(s) == 40) {
2781 for (i = 0; *s && s[1] && s[2] && s[3] && s[4]; s += 4, i++) {
2786 putc (is_pgp ? ' ' : ':', fp);
2787 if (is_pgp && i == 4)
2792 for (i = 0; *s && s[1] && s[2]; s += 2, i++) {
2795 putc (is_pgp ? ' ' : ':', fp);
2796 if (is_pgp && i == 7)
2800 fprintf (fp, "%s\n", s);
2803 if (key->issuer_serial) {
2804 s = key->issuer_serial;
2806 fprintf (fp, _("Serial-No .: 0x%s\n"), s);
2809 if (key->issuer_name) {
2810 s = key->issuer_name;
2812 fprintf (fp, _("Issued By .: "));
2813 parse_and_print_user_id (fp, s);
2818 /* For PGP we list all subkeys. */
2820 gpgme_subkey_t subkey = NULL;
2822 for (idx = 1, subkey = key->subkeys; subkey; idx++, subkey = subkey->next) {
2826 if (m_strlen(s) == 16)
2827 s += 8; /* display only the short keyID */
2828 fprintf (fp, _("Subkey ....: 0x%s"), s);
2829 if (subkey->revoked) {
2831 fputs (_("[Revoked]"), fp);
2833 if (subkey->invalid) {
2835 fputs (_("[Invalid]"), fp);
2837 if (subkey->expired) {
2839 fputs (_("[Expired]"), fp);
2841 if (subkey->disabled) {
2843 fputs (_("[Disabled]"), fp);
2847 if (subkey->timestamp > 0) {
2848 tt = subkey->timestamp;
2850 tm = localtime (&tt);
2851 #ifdef HAVE_LANGINFO_D_T_FMT
2852 strftime (shortbuf, sizeof shortbuf, nl_langinfo (D_T_FMT), tm);
2854 strftime (shortbuf, sizeof shortbuf, "%c", tm);
2856 fprintf (fp, _("Valid From : %s\n"), shortbuf);
2859 if (subkey->expires > 0) {
2860 tt = subkey->expires;
2862 tm = localtime (&tt);
2863 #ifdef HAVE_LANGINFO_D_T_FMT
2864 strftime (shortbuf, sizeof shortbuf, nl_langinfo (D_T_FMT), tm);
2866 strftime (shortbuf, sizeof shortbuf, "%c", tm);
2868 fprintf (fp, _("Valid To ..: %s\n"), shortbuf);
2872 s = gpgme_pubkey_algo_name (subkey->pubkey_algo);
2877 aval = subkey->length;
2881 fprintf (fp, _("Key Type ..: %s, %lu bit %s\n"), "PGP", aval, s);
2883 fprintf (fp, _("Key Usage .: "));
2886 if (subkey->can_encrypt) {
2887 fprintf (fp, "%s%s", delim, _("encryption"));
2890 if (subkey->can_sign) {
2891 fprintf (fp, "%s%s", delim, _("signing"));
2894 if (subkey->can_certify) {
2895 fprintf (fp, "%s%s", delim, _("certification"));
2903 setlocale (LC_TIME, "C");
2907 /* Show detailed information about the selected key */
2908 static void verify_key (crypt_key_t * key)
2911 char cmd[LONG_STRING], tempfile[_POSIX_PATH_MAX];
2913 gpgme_ctx_t listctx = NULL;
2915 gpgme_key_t k = NULL;
2918 fp = m_tempfile (tempfile, sizeof(tempfile), NONULL(MCore.tmpdir), NULL);
2920 mutt_perror (_("Can't create temporary file"));
2923 mutt_message _("Collecting data...");
2925 print_key_info (key->kobj, fp);
2927 err = gpgme_new (&listctx);
2929 fprintf (fp, "Internal error: can't create gpgme context: %s\n",
2930 gpgme_strerror (err));
2933 if ((key->flags & KEYFLAG_ISX509))
2934 gpgme_set_protocol (listctx, GPGME_PROTOCOL_CMS);
2938 while ((s = k->chain_id) && k->subkeys && m_strcmp(s, k->subkeys->fpr)) {
2940 err = gpgme_op_keylist_start (listctx, s, 0);
2941 gpgme_key_release (k);
2944 err = gpgme_op_keylist_next (listctx, &k);
2946 fprintf (fp, _("Error finding issuer key: %s\n"), gpgme_strerror (err));
2949 gpgme_op_keylist_end (listctx);
2951 print_key_info (k, fp);
2954 fputs (_("Error: certification chain to long - stopping here\n"), fp);
2960 gpgme_key_release (k);
2961 gpgme_release (listctx);
2963 mutt_clear_error ();
2964 snprintf (cmd, sizeof (cmd), _("Key ID: 0x%s"), crypt_keyid (key));
2965 mutt_do_pager (cmd, tempfile, 0, NULL);
2968 /* Implementation of `findkeys'. */
2970 /* Convert string_list_t into a pattern string suitable to be passed to GPGME.
2971 We need to convert spaces in an item into a '+' and '%' into
2973 static char *list_to_pattern (string_list_t * list)
2981 for (l = list; l; l = l->next) {
2982 for (s = l->data; *s; s++) {
2987 n++; /* delimiter or end of string */
2989 n++; /* make sure to allocate at least one byte */
2990 pattern = p = p_new(char, n);
2991 for (l = list; l; l = l->next) {
2996 for (s = l->data; *s; s++) {
3002 else if (*s == '+') {
3018 /* Return a list of keys which are candidates for the selection.
3019 Select by looking at the HINTS list. */
3020 static crypt_key_t *get_candidates (string_list_t * hints, unsigned int app,
3023 crypt_key_t *db, *k, **kend;
3029 gpgme_user_id_t uid = NULL;
3031 pattern = list_to_pattern (hints);
3035 err = gpgme_new (&ctx);
3037 mutt_error (_("gpgme_new failed: %s"), gpgme_strerror (err));
3045 if ((app & APPLICATION_PGP)) {
3046 /* Its all a mess. That old GPGME expects different things
3047 depending on the protocol. For gpg we don' t need percent
3048 escaped pappert but simple strings passed in an array to the
3049 keylist_ext_start function. */
3054 for (l = hints, n = 0; l; l = l->next) {
3055 if (l->data && *l->data)
3061 patarr = p_new(char *, n + 1);
3062 for (l = hints, n = 0; l; l = l->next) {
3063 if (l->data && *l->data)
3064 patarr[n++] = m_strdup(l->data);
3067 err = gpgme_op_keylist_ext_start (ctx, (const char **) patarr, secret, 0);
3068 for (n = 0; patarr[n]; n++)
3069 p_delete(&patarr[n]);
3072 mutt_error (_("gpgme_op_keylist_start failed: %s"), gpgme_strerror (err));
3073 gpgme_release (ctx);
3078 while (!(err = gpgme_op_keylist_next (ctx, &key))) {
3079 unsigned int flags = 0;
3081 if (key_check_cap (key, KEY_CAP_CAN_ENCRYPT))
3082 flags |= KEYFLAG_CANENCRYPT;
3083 if (key_check_cap (key, KEY_CAP_CAN_SIGN))
3084 flags |= KEYFLAG_CANSIGN;
3086 for (idx = 0, uid = key->uids; uid; idx++, uid = uid->next) {
3087 k = p_new(crypt_key_t, 1);
3096 if (gpg_err_code (err) != GPG_ERR_EOF)
3097 mutt_error (_("gpgme_op_keylist_next failed: %s"), gpgme_strerror (err));
3098 gpgme_op_keylist_end (ctx);
3103 if ((app & APPLICATION_SMIME)) {
3104 /* and now look for x509 certificates */
3105 gpgme_set_protocol (ctx, GPGME_PROTOCOL_CMS);
3106 err = gpgme_op_keylist_start (ctx, pattern, 0);
3108 mutt_error (_("gpgme_op_keylist_start failed: %s"), gpgme_strerror (err));
3109 gpgme_release (ctx);
3114 while (!(err = gpgme_op_keylist_next (ctx, &key))) {
3115 unsigned int flags = KEYFLAG_ISX509;
3117 if (key_check_cap (key, KEY_CAP_CAN_ENCRYPT))
3118 flags |= KEYFLAG_CANENCRYPT;
3119 if (key_check_cap (key, KEY_CAP_CAN_SIGN))
3120 flags |= KEYFLAG_CANSIGN;
3122 for (idx = 0, uid = key->uids; uid; idx++, uid = uid->next) {
3123 k = p_new(crypt_key_t, 1);
3132 if (gpg_err_code (err) != GPG_ERR_EOF)
3133 mutt_error (_("gpgme_op_keylist_next failed: %s"), gpgme_strerror (err));
3134 gpgme_op_keylist_end (ctx);
3137 gpgme_release (ctx);
3142 /* Add the string STR to the list HINTS. This list is later used to
3144 static string_list_t *crypt_add_string_to_hints (string_list_t * hints, const char *str)
3149 if ((scratch = m_strdup(str)) == NULL)
3152 for (t = strtok (scratch, " ,.:\"()<>\n"); t;
3153 t = strtok (NULL, " ,.:\"()<>\n")) {
3154 if (m_strlen(t) > 3)
3155 hints = mutt_add_list(hints, t);
3162 /* Display a menu to select a key from the array KEYS. FORCED_VALID
3163 will be set to true on return if the user did override the the
3165 static crypt_key_t *crypt_select_key (crypt_key_t * keys,
3166 address_t * p, const char *s,
3167 unsigned int app, int *forced_valid)
3170 crypt_key_t **key_table;
3173 char helpstr[STRING], buf[LONG_STRING];
3175 int (*f) (const void *, const void *);
3176 int menu_to_use = 0;
3181 /* build the key table */
3184 for (k = keys; k; k = k->next) {
3185 if (!option (OPTPGPSHOWUNUSABLE) && (k->flags & KEYFLAG_CANTUSE)) {
3192 p_realloc(&key_table, keymax);
3198 if (!i && unusable) {
3199 mutt_error _("All matching keys are marked expired/revoked.");
3205 switch (PgpSortKeys & SORT_MASK) {
3207 f = crypt_compare_date;
3210 f = crypt_compare_keyid;
3213 f = crypt_compare_address;
3217 f = crypt_compare_trust;
3220 qsort (key_table, i, sizeof (crypt_key_t *), f);
3222 if (app & APPLICATION_PGP)
3223 menu_to_use = MENU_KEY_SELECT_PGP;
3224 else if (app & APPLICATION_SMIME)
3225 menu_to_use = MENU_KEY_SELECT_SMIME;
3228 mutt_make_help (buf, sizeof (buf), _("Exit "), menu_to_use, OP_EXIT);
3229 m_strcat(helpstr, sizeof(helpstr), buf);
3230 mutt_make_help (buf, sizeof (buf), _("Select "), menu_to_use,
3231 OP_GENERIC_SELECT_ENTRY);
3232 m_strcat(helpstr, sizeof(helpstr), buf);
3233 mutt_make_help (buf, sizeof (buf), _("Check key "),
3234 menu_to_use, OP_VERIFY_KEY);
3235 m_strcat(helpstr, sizeof(helpstr), buf);
3236 mutt_make_help (buf, sizeof (buf), _("Help"), menu_to_use, OP_HELP);
3237 m_strcat(helpstr, sizeof(helpstr), buf);
3239 menu = mutt_new_menu ();
3241 menu->make_entry = crypt_entry;
3242 menu->menu = menu_to_use;
3243 menu->help = helpstr;
3244 menu->data = key_table;
3249 if ((app & APPLICATION_PGP) && (app & APPLICATION_SMIME))
3250 ts = _("PGP and S/MIME keys matching");
3251 else if ((app & APPLICATION_PGP))
3252 ts = _("PGP keys matching");
3253 else if ((app & APPLICATION_SMIME))
3254 ts = _("S/MIME keys matching");
3256 ts = _("keys matching");
3259 snprintf (buf, sizeof (buf), _("%s <%s>."), ts, p->mailbox);
3261 snprintf (buf, sizeof (buf), _("%s \"%s\"."), ts, s);
3265 mutt_clear_error ();
3269 switch (mutt_menuLoop (menu)) {
3271 verify_key (key_table[menu->current]);
3272 menu->redraw = REDRAW_FULL;
3276 mutt_message ("%s", key_table[menu->current]->uid);
3279 case OP_GENERIC_SELECT_ENTRY:
3280 /* FIXME make error reporting more verbose - this should be
3281 easy because gpgme provides more information */
3282 if (option (OPTPGPCHECKTRUST)) {
3283 if (!crypt_key_is_valid (key_table[menu->current])) {
3284 mutt_error _("This key can't be used: "
3285 "expired/disabled/revoked.");
3290 if (option (OPTPGPCHECKTRUST) &&
3291 (!crypt_id_is_valid (key_table[menu->current])
3292 || !crypt_id_is_strong (key_table[menu->current]))) {
3294 char buff[LONG_STRING];
3296 if (key_table[menu->current]->flags & KEYFLAG_CANTUSE)
3297 s = N_("ID is expired/disabled/revoked.");
3299 gpgme_validity_t val = GPGME_VALIDITY_UNKNOWN;
3300 gpgme_user_id_t uid = NULL;
3305 uid = key_table[menu->current]->kobj->uids;
3306 for (j = 0; (j < key_table[menu->current]->idx) && uid;
3307 j++, uid = uid->next);
3309 val = uid->validity;
3312 case GPGME_VALIDITY_UNKNOWN:
3313 case GPGME_VALIDITY_UNDEFINED:
3314 warn_s = N_("ID has undefined validity.");
3316 case GPGME_VALIDITY_NEVER:
3317 warn_s = N_("ID is not valid.");
3319 case GPGME_VALIDITY_MARGINAL:
3320 warn_s = N_("ID is only marginally valid.");
3322 case GPGME_VALIDITY_FULL:
3323 case GPGME_VALIDITY_ULTIMATE:
3327 snprintf (buff, sizeof (buff),
3328 _("%s Do you really want to use the key?"), _(warn_s));
3330 if (mutt_yesorno (buff, 0) != 1) {
3331 mutt_clear_error ();
3338 k = crypt_copy_key (key_table[menu->current]);
3349 mutt_menuDestroy (&menu);
3350 p_delete(&key_table);
3352 set_option (OPTNEEDREDRAW);
3357 static crypt_key_t *crypt_getkeybyaddr (address_t * a, short abilities,
3358 unsigned int app, int *forced_valid)
3361 string_list_t *hints = NULL;
3366 int this_key_has_strong;
3367 int this_key_has_weak;
3368 int this_key_has_invalid;
3371 crypt_key_t *keys, *k;
3372 crypt_key_t *the_valid_key = NULL;
3373 crypt_key_t *matches = NULL;
3374 crypt_key_t **matches_endp = &matches;
3378 if (a && a->mailbox)
3379 hints = crypt_add_string_to_hints (hints, a->mailbox);
3380 if (a && a->personal)
3381 hints = crypt_add_string_to_hints (hints, a->personal);
3383 mutt_message (_("Looking for keys matching \"%s\"..."), a->mailbox);
3384 keys = get_candidates (hints, app, (abilities & KEYFLAG_CANSIGN));
3386 string_list_wipe(&hints);
3391 for (k = keys; k; k = k->next) {
3392 if (abilities && !(k->flags & abilities)) {
3396 this_key_has_weak = 0; /* weak but valid match */
3397 this_key_has_invalid = 0; /* invalid match */
3398 this_key_has_strong = 0; /* strong and valid match */
3399 match = 0; /* any match */
3401 r = rfc822_parse_adrlist (NULL, k->uid);
3402 for (p = r; p; p = p->next) {
3403 int validity = crypt_id_matches_addr (a, p, k);
3405 if (validity & CRYPT_KV_MATCH) /* something matches */
3408 /* is this key a strong candidate? */
3409 if ((validity & CRYPT_KV_VALID)
3410 && (validity & CRYPT_KV_STRONGID)
3411 && (validity & CRYPT_KV_ADDR)) {
3412 if (the_valid_key && the_valid_key != k)
3415 this_key_has_strong = 1;
3417 else if ((validity & CRYPT_KV_MATCH)
3418 && !(validity & CRYPT_KV_VALID))
3419 this_key_has_invalid = 1;
3420 else if ((validity & CRYPT_KV_MATCH)
3421 && (!(validity & CRYPT_KV_STRONGID)
3422 || !(validity & CRYPT_KV_ADDR)))
3423 this_key_has_weak = 1;
3425 address_list_wipe(&r);
3430 if (!this_key_has_strong && this_key_has_invalid)
3432 if (!this_key_has_strong && this_key_has_weak)
3435 *matches_endp = tmp = crypt_copy_key (k);
3436 matches_endp = &tmp->next;
3437 the_valid_key = tmp;
3441 crypt_free_key (&keys);
3444 if (the_valid_key && !multi && !weak
3445 && !(invalid && option (OPTPGPSHOWUNUSABLE))) {
3447 * There was precisely one strong match on a valid ID, there
3448 * were no valid keys with weak matches, and we aren't
3449 * interested in seeing invalid keys.
3451 * Proceed without asking the user.
3453 k = crypt_copy_key (the_valid_key);
3457 * Else: Ask the user.
3459 k = crypt_select_key (matches, a, NULL, app, forced_valid);
3461 crypt_free_key (&matches);
3470 static crypt_key_t *crypt_getkeybystr (const char *p, short abilities,
3471 unsigned int app, int *forced_valid)
3473 string_list_t *hints = NULL;
3475 crypt_key_t *matches = NULL;
3476 crypt_key_t **matches_endp = &matches;
3480 mutt_message (_("Looking for keys matching \"%s\"..."), p);
3484 hints = crypt_add_string_to_hints (hints, p);
3485 keys = get_candidates (hints, app, (abilities & KEYFLAG_CANSIGN));
3486 string_list_wipe(&hints);
3491 for (k = keys; k; k = k->next) {
3492 if (abilities && !(k->flags & abilities))
3497 if (!*p || !m_strcasecmp(p, crypt_keyid (k))
3498 || (!m_strncasecmp(p, "0x", 2)
3499 && !m_strcasecmp(p + 2, crypt_keyid (k)))
3500 || (option (OPTPGPLONGIDS)
3501 && !m_strncasecmp(p, "0x", 2)
3502 && !m_strcasecmp(p + 2, crypt_keyid (k) + 8))
3503 || m_stristr(k->uid, p)) {
3506 *matches_endp = tmp = crypt_copy_key (k);
3507 matches_endp = &tmp->next;
3511 crypt_free_key (&keys);
3514 k = crypt_select_key (matches, NULL, p, app, forced_valid);
3515 crypt_free_key (&matches);
3522 /* Display TAG as a prompt to ask for a key. If WHATFOR is not null
3523 use it as default and store it under that label as the next
3524 default. ABILITIES describe the required key abilities (sign,
3525 encrypt) and APP the type of the requested key; ether S/MIME or
3526 PGP. Return a copy of the key or NULL if not found. */
3527 static crypt_key_t *
3528 crypt_ask_for_key(char *tag, char *whatfor, short abilities,
3529 unsigned int app, int *forced_valid)
3533 struct crypt_cache *l = NULL;
3537 forced_valid = &dummy;
3539 mutt_clear_error ();
3544 for (l = id_defaults; l; l = l->next)
3545 if (!m_strcasecmp(whatfor, l->what)) {
3546 m_strcpy(resp, sizeof(resp), NONULL(l->dflt));
3553 if (mutt_get_field (tag, resp, sizeof (resp), M_CLEAR) != 0)
3558 m_strreplace(&l->dflt, resp);
3560 l = p_new(struct crypt_cache, 1);
3561 l->next = id_defaults;
3563 l->what = m_strdup(whatfor);
3564 l->dflt = m_strdup(resp);
3568 if ((key = crypt_getkeybystr (resp, abilities, app, forced_valid)))
3576 /* This routine attempts to find the keyids of the recipients of a
3577 message. It returns NULL if any of the keys can not be found. */
3578 static char *find_keys (address_t * to, address_t * cc, address_t * bcc,
3581 char *keylist = NULL, *t;
3583 ssize_t keylist_size = 0;
3584 ssize_t keylist_used = 0;
3585 address_t *tmp = NULL, *addr = NULL;
3586 address_t **last = &tmp;
3589 crypt_key_t *k_info, *key;
3590 const char *fqdn = mutt_fqdn (1);
3593 *r_application = APPLICATION_PGP | APPLICATION_SMIME;
3596 for (i = 0; i < 3; i++) {
3611 *last = address_list_dup (p);
3613 last = &((*last)->next);
3616 rfc822_qualify(tmp, fqdn);
3617 address_list_uniq(tmp);
3619 for (p = tmp; p; p = p->next) {
3620 char buf[LONG_STRING];
3621 int forced_valid = 0;
3626 if ((keyID = mutt_crypt_hook (p)) != NULL) {
3629 snprintf (buf, sizeof (buf), _("Use keyID = \"%s\" for %s?"),
3631 if ((r = mutt_yesorno (buf, M_YES)) == M_YES) {
3632 /* check for e-mail address */
3633 if ((t = strchr (keyID, '@')) &&
3634 (addr = rfc822_parse_adrlist (NULL, keyID))) {
3635 rfc822_qualify(addr, fqdn);
3639 k_info = crypt_getkeybystr (keyID, KEYFLAG_CANENCRYPT,
3640 app, &forced_valid);
3645 address_list_wipe(&tmp);
3646 address_list_wipe(&addr);
3652 && (k_info = crypt_getkeybyaddr (q, KEYFLAG_CANENCRYPT,
3653 app, &forced_valid)) == NULL) {
3654 snprintf (buf, sizeof (buf), _("Enter keyID for %s: "), q->mailbox);
3656 if ((key = crypt_ask_for_key (buf, q->mailbox, KEYFLAG_CANENCRYPT, app,
3657 &forced_valid)) == NULL)
3660 address_list_wipe(&tmp);
3661 address_list_wipe(&addr);
3669 const char *s = crypt_fpr (key);
3671 keylist_size += m_strlen(s) + 4 + 1;
3672 p_realloc(&keylist, keylist_size);
3673 sprintf (keylist + keylist_used, "%s0x%s%s",
3674 keylist_used ? " " : "", s, forced_valid ? "!" : "");
3676 keylist_used = m_strlen(keylist);
3678 crypt_free_key (&key);
3679 address_list_wipe(&addr);
3681 address_list_wipe(&tmp);
3685 int crypt_get_keys (HEADER * msg, char **keylist)
3687 /* Do a quick check to make sure that we can find all of the encryption
3688 * keys if the user has requested this service.
3693 if (msg->security & ENCRYPT) {
3694 if (msg->security & APPLICATION_PGP) {
3695 set_option(OPTPGPCHECKTRUST);
3696 *keylist = find_keys(msg->env->to, msg->env->cc, msg->env->bcc,
3698 unset_option(OPTPGPCHECKTRUST);
3703 if (msg->security & APPLICATION_SMIME) {
3704 *keylist = find_keys(msg->env->to, msg->env->cc, msg->env->bcc,
3715 int crypt_send_menu (HEADER * msg, int *redraw, int is_smime)
3718 char input_signas[STRING];
3721 if (msg->security & APPLICATION_PGP)
3723 else if (msg->security & APPLICATION_SMIME)
3728 mutt_multi_choice (_
3729 ("S/MIME (e)ncrypt, (s)ign, sign (a)s, (b)oth, (p)gp or (c)lear?"),
3733 mutt_multi_choice (_
3734 ("PGP (e)ncrypt, (s)ign, sign (a)s, (b)oth, s/(m)ime or (c)lear?"),
3738 case 1: /* (e)ncrypt */
3739 msg->security |= (is_smime ? SMIMEENCRYPT : PGPENCRYPT);
3740 msg->security &= ~(is_smime ? SMIMESIGN : PGPSIGN);
3743 case 2: /* (s)ign */
3744 msg->security |= (is_smime ? SMIMESIGN : PGPSIGN);
3745 msg->security &= ~(is_smime ? SMIMEENCRYPT : PGPENCRYPT);
3748 case 3: /* sign (a)s */
3749 if ((p = crypt_ask_for_key (_("Sign as: "), NULL, KEYFLAG_CANSIGN,
3750 is_smime ? APPLICATION_SMIME :
3751 APPLICATION_PGP, NULL)))
3753 snprintf (input_signas, sizeof (input_signas), "0x%s", crypt_keyid (p));
3754 m_strreplace(is_smime ? &SmimeDefaultKey : &PgpSignAs,
3756 crypt_free_key (&p);
3758 msg->security |= (is_smime ? SMIMESIGN : PGPSIGN);
3760 *redraw = REDRAW_FULL;
3763 case 4: /* (b)oth */
3765 (is_smime ? (SMIMEENCRYPT | SMIMESIGN) : (PGPENCRYPT | PGPSIGN));
3768 case 5: /* (p)gp or s/(m)ime */
3769 is_smime = !is_smime;
3772 case 6: /* (c)lear */
3773 return msg->security = 0;
3777 msg->security &= ~APPLICATION_PGP;
3778 msg->security |= APPLICATION_SMIME;
3780 msg->security &= ~APPLICATION_SMIME;
3781 msg->security |= APPLICATION_PGP;
3784 return msg->security;
3787 int crypt_smime_verify_sender (HEADER * h)
3789 address_t *sender = NULL;
3790 unsigned int ret = 1;
3793 h->env->from = mutt_expand_aliases (h->env->from);
3794 sender = h->env->from;
3796 else if (h->env->sender) {
3797 h->env->sender = mutt_expand_aliases (h->env->sender);
3798 sender = h->env->sender;
3802 if (signature_key) {
3803 gpgme_key_t key = signature_key;
3804 gpgme_user_id_t uid = NULL;
3805 int sender_length = 0;
3808 sender_length = m_strlen(sender->mailbox);
3809 for (uid = key->uids; uid && ret; uid = uid->next) {
3810 uid_length = m_strlen(uid->email);
3811 if (1 && (uid->email[0] == '<')
3812 && (uid->email[uid_length - 1] == '>')
3813 && (uid_length == sender_length + 2)
3814 && (!m_strncmp (uid->email + 1, sender->mailbox, sender_length)))
3819 mutt_any_key_to_continue ("Failed to verify sender");
3822 mutt_any_key_to_continue ("Failed to figure out sender");
3824 if (signature_key) {
3825 gpgme_key_release (signature_key);
3826 signature_key = NULL;
3832 static void crypt_invoke_import(FILE *stream, int smime)
3834 gpgme_ctx_t ctx = create_gpgme_context(smime);
3838 err = gpgme_data_new_from_stream(&data, stream);
3840 mutt_error (_("error allocating data object: %s\n"), gpgme_strerror (err));
3845 err = gpgme_op_import(ctx, data);
3847 mutt_error(_("error importing gpg data: %s\n"), gpgme_strerror(err));
3848 gpgme_data_release(data);
3853 gpgme_data_release(data);
3858 static void pgp_extract_keys_from_attachment(FILE * fp, BODY * top)
3861 FILE *tmpfp = tmpfile();
3863 if (tmpfp == NULL) {
3864 mutt_perror (_("Can't create temporary file"));
3871 mutt_body_handler(top, &s);
3874 crypt_invoke_import(tmpfp, 0);
3878 void crypt_pgp_extract_keys_from_attachment_list(FILE * fp, int tag, BODY * top)
3881 set_option (OPTDONTHANDLEPGPKEYS);
3883 for (; top; top = top->next) {
3884 if (!tag || top->tagged)
3885 pgp_extract_keys_from_attachment (fp, top);
3891 unset_option (OPTDONTHANDLEPGPKEYS);
3894 void crypt_invoke_message (int type)
3896 if (type & APPLICATION_PGP) {
3897 mutt_message _("Invoking PGP...");
3899 else if (type & APPLICATION_SMIME) {
3900 mutt_message _("Invoking S/MIME...");
3904 int mutt_protect (HEADER * msg, char *keylist)
3906 BODY *pbody = NULL, *tmp_pbody = NULL;
3907 BODY *tmp_smime_pbody = NULL;
3908 BODY *tmp_pgp_pbody = NULL;
3909 int flags = msg->security;
3914 tmp_smime_pbody = msg->content;
3915 tmp_pgp_pbody = msg->content;
3917 if (msg->security & SIGN) {
3918 if (msg->security & APPLICATION_SMIME) {
3919 if (!(tmp_pbody = sign_message(msg->content, 1)))
3921 pbody = tmp_smime_pbody = tmp_pbody;
3924 if ((msg->security & APPLICATION_PGP)
3925 && (!(flags & ENCRYPT) || option (OPTPGPRETAINABLESIG))) {
3926 if (!(tmp_pbody = sign_message(msg->content, 0)))
3930 pbody = tmp_pgp_pbody = tmp_pbody;
3933 if ((msg->security & APPLICATION_SMIME)
3934 && (msg->security & APPLICATION_PGP)) {
3935 /* here comes the draft ;-) */
3940 if (msg->security & ENCRYPT) {
3941 if ((msg->security & APPLICATION_SMIME)) {
3942 if (!(tmp_pbody = crypt_smime_build_smime_entity (tmp_smime_pbody,
3944 /* signed ? free it! */
3947 /* free tmp_body if messages was signed AND encrypted ... */
3948 if (tmp_smime_pbody != msg->content && tmp_smime_pbody != tmp_pbody) {
3949 /* detatch and dont't delete msg->content,
3950 which tmp_smime_pbody->parts after signing. */
3951 tmp_smime_pbody->parts = tmp_smime_pbody->parts->next;
3952 msg->content->next = NULL;
3953 body_list_wipe(&tmp_smime_pbody);
3958 if ((msg->security & APPLICATION_PGP)) {
3959 if (!(pbody = crypt_pgp_encrypt_message (tmp_pgp_pbody, keylist,
3962 /* did we perform a retainable signature? */
3963 if (flags != msg->security) {
3964 /* remove the outer multipart layer */
3965 tmp_pgp_pbody = mutt_remove_multipart (tmp_pgp_pbody);
3966 /* get rid of the signature */
3967 body_list_wipe(&tmp_pgp_pbody->next);
3973 /* destroy temporary signature envelope when doing retainable
3977 if (flags != msg->security) {
3978 tmp_pgp_pbody = mutt_remove_multipart (tmp_pgp_pbody);
3979 body_list_wipe(&tmp_pgp_pbody->next);
3985 msg->content = pbody;
3991 int crypt_query (BODY * m)
3998 if (m->type == TYPEAPPLICATION) {
3999 t |= mutt_is_application_pgp (m);
4001 t |= mutt_is_application_smime (m);
4002 if (t && m->goodsig)
4007 else if (m->type == TYPETEXT) {
4008 t |= mutt_is_application_pgp (m);
4009 if (t && m->goodsig)
4013 if (m->type == TYPEMULTIPART) {
4014 t |= mutt_is_multipart_encrypted (m);
4015 t |= mutt_is_multipart_signed (m);
4017 if (t && m->goodsig)
4021 if (m->type == TYPEMULTIPART || m->type == TYPEMESSAGE) {
4025 u = m->parts ? ~0 : 0; /* Bits set in all parts */
4026 w = 0; /* Bits set in any part */
4028 for (p = m->parts; p; p = p->next) {
4029 v = crypt_query (p);
4033 t |= u | (w & ~GOODSIGN);
4035 if ((w & GOODSIGN) && !(u & GOODSIGN))
4043 static void crypt_write_signed(BODY * a, STATE * s, FILE *fp)
4049 fseeko (s->fpin, a->hdr_offset, 0);
4050 bytes = a->length + a->offset - a->hdr_offset;
4053 if ((c = fgetc (s->fpin)) == EOF)
4061 if (c == '\n' && !hadcr)
4070 static void extract_keys_aux(FILE *fpout, HEADER *h)
4072 mutt_parse_mime_message (Context, h);
4075 if (h->security & APPLICATION_PGP) {
4076 mutt_copy_message(fpout, Context, h, M_CM_DECODE | M_CM_CHARCONV, 0);
4079 mutt_endwin (_("Trying to extract PGP keys...\n"));
4082 if (h->security & APPLICATION_SMIME) {
4083 if (h->security & ENCRYPT)
4084 mutt_copy_message (fpout, Context, h, M_CM_NOHEADER
4085 | M_CM_DECODE_CRYPT | M_CM_DECODE_SMIME, 0);
4087 mutt_copy_message(fpout, Context, h, 0, 0);
4090 mutt_message (_("Trying to extract S/MIME certificates...\n"));
4094 crypt_invoke_import(fpout, h->security & APPLICATION_SMIME);
4097 void crypt_extract_keys_from_messages(HEADER * h)
4099 FILE *tmpfp = tmpfile();
4101 mutt_error(_("Could not create temporary file"));
4105 set_option(OPTDONTHANDLEPGPKEYS);
4108 for (i = 0; i < Context->vcount; i++) {
4109 if (!Context->hdrs[Context->v2r[i]]->tagged)
4111 extract_keys_aux(tmpfp, Context->hdrs[Context->v2r[i]]);
4114 extract_keys_aux(tmpfp, h);
4116 unset_option(OPTDONTHANDLEPGPKEYS);
4120 mutt_any_key_to_continue(NULL);
4125 static void crypt_fetch_signatures (BODY ***signatures, BODY * a, int *n)
4127 for (; a; a = a->next) {
4128 if (a->type == TYPEMULTIPART)
4129 crypt_fetch_signatures (signatures, a->parts, n);
4132 p_realloc(signatures, *n + 6);
4134 (*signatures)[(*n)++] = a;
4141 * This routine verifies a "multipart/signed" body.
4144 int mutt_signed_handler (BODY * a, STATE * s)
4146 unsigned major, minor;
4148 int rc, i, goodsig = 1, sigcnt = 0;
4151 protocol = parameter_getval(a->parameter, "protocol");
4154 switch (mime_which_token(protocol, -1)) {
4155 case MIME_APPLICATION_PGP_SIGNATURE:
4156 major = TYPEAPPLICATION;
4157 minor = MIME_PGP_SIGNATURE;
4159 case MIME_APPLICATION_X_PKCS7_SIGNATURE:
4160 major = TYPEAPPLICATION;
4161 minor = MIME_X_PKCS7_SIGNATURE;
4163 case MIME_APPLICATION_PKCS7_SIGNATURE:
4164 major = TYPEAPPLICATION;
4165 minor = MIME_PKCS7_SIGNATURE;
4167 case MIME_MULTIPART_MIXED:
4168 major = TYPEMULTIPART;
4173 state_printf(s, _("[-- Error: "
4174 "Unknown multipart/signed protocol %s! --]\n\n"),
4176 return mutt_body_handler (a, s);
4179 /* consistency check */
4180 if (!(a && a->next && a->next->type == major &&
4181 mime_which_token(a->next->subtype, -1) == minor))
4183 state_attach_puts(_("[-- Error: "
4184 "Inconsistent multipart/signed structure! --]\n\n"),
4186 return mutt_body_handler (a, s);
4189 if (s->flags & M_DISPLAY) {
4192 crypt_fetch_signatures (&sigs, a->next, &sigcnt);
4194 FILE *tmpfp = tmpfile();
4197 mutt_error(_("Could not create temporary file"));
4199 crypt_write_signed(a, s, tmpfp);
4201 for (i = 0; i < sigcnt; i++) {
4202 if (sigs[i]->type == TYPEAPPLICATION) {
4205 switch ((subtype = mime_which_token(sigs[i]->subtype, -1))) {
4206 case MIME_PGP_SIGNATURE:
4207 case MIME_X_PKCS7_SIGNATURE:
4208 case MIME_PKCS7_SIGNATURE:
4209 if (crypt_verify_one(sigs[i], s, tmpfp, subtype != MIME_PGP_SIGNATURE) != 0)
4220 state_printf(s, _("[-- Warning: "
4221 "We can't verify %s/%s signatures. --]\n\n"),
4222 TYPE (sigs[i]), sigs[i]->subtype);
4226 b->goodsig = goodsig;
4227 b->badsig = !goodsig;
4229 /* Now display the signed body */
4230 state_attach_puts(_("[-- The following data is signed --]\n\n"), s);
4234 state_attach_puts(_("[-- Warning: Can't find any signatures. --]\n\n"),
4239 rc = mutt_body_handler (a, s);
4241 if (s->flags & M_DISPLAY && sigcnt)
4242 state_attach_puts (_("\n[-- End of signed data --]\n"), s);