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>
31 #include "recvattach.h"
34 /* Values used for comparing addresses. */
35 #define CRYPT_KV_VALID 1
36 #define CRYPT_KV_ADDR 2
37 #define CRYPT_KV_STRING 4
38 #define CRYPT_KV_STRONGID 8
39 #define CRYPT_KV_MATCH (CRYPT_KV_ADDR|CRYPT_KV_STRING)
48 struct crypt_cache *next;
56 /* We work based on user IDs, getting from a user ID to the key is
57 check and does not need any memory (gpgme uses reference counting). */
58 typedef struct crypt_keyinfo {
59 struct crypt_keyinfo *next;
61 int idx; /* and the user ID at this index */
62 const char *uid; /* and for convenience point to this user ID */
63 unsigned int flags; /* global and per uid flags (for convenience) */
66 typedef struct crypt_entry {
72 static struct crypt_cache *id_defaults = NULL;
73 static gpgme_key_t signature_key = NULL;
76 * General helper functions.
79 /* return true when S points to a didgit or letter. */
80 static int digit_or_letter (const unsigned char *s)
82 return ((*s >= '0' && *s <= '9')
83 || (*s >= 'A' && *s <= 'Z')
84 || (*s >= 'a' && *s <= 'z'));
88 /* Print the utf-8 encoded string BUF of length LEN bytes to stream
89 FP. Convert the character set. */
90 static void print_utf8 (FILE * fp, const char *buf, ssize_t len)
94 tstr = p_dupstr(buf, len);
95 mutt_convert_string (&tstr, "utf-8", MCharset.charset, M_ICONV_HOOK_FROM);
105 /* Return the keyID for the key K. Note that this string is valid as
106 long as K is valid */
107 static const char *crypt_keyid (crypt_key_t * k)
109 const char *s = "????????";
111 if (k->kobj && k->kobj->subkeys) {
112 s = k->kobj->subkeys->keyid;
113 if ((!option (OPTPGPLONGIDS)) && (m_strlen(s) == 16))
114 /* Return only the short keyID. */
121 /* Return the hexstring fingerprint from the key K. */
122 static const char *crypt_fpr (crypt_key_t * k)
126 if (k->kobj && k->kobj->subkeys)
127 s = k->kobj->subkeys->fpr;
132 /* Parse FLAGS and return a statically allocated(!) string with them. */
133 static char *crypt_key_abilities (int flags)
137 if (!(flags & KEYFLAG_CANENCRYPT))
139 else if (flags & KEYFLAG_PREFER_SIGNING)
144 if (!(flags & KEYFLAG_CANSIGN))
146 else if (flags & KEYFLAG_PREFER_ENCRYPTION)
156 /* Parse FLAGS and return a character describing the most important flag. */
157 static char crypt_flags (int flags)
159 if (flags & KEYFLAG_REVOKED)
161 else if (flags & KEYFLAG_EXPIRED)
163 else if (flags & KEYFLAG_DISABLED)
165 else if (flags & KEYFLAG_CRITICAL)
171 /* Return a copy of KEY. */
172 static crypt_key_t *crypt_copy_key (crypt_key_t *key)
176 k = p_new(crypt_key_t, 1);
178 gpgme_key_ref (key->kobj);
181 k->flags = key->flags;
186 /* Release all the keys at the address of KEYLIST and set the address
188 static void crypt_free_key (crypt_key_t ** keylist)
191 crypt_key_t *k = (*keylist)->next;
198 /* Return trute when key K is valid. */
199 static int crypt_key_is_valid (crypt_key_t * k)
201 if (k->flags & KEYFLAG_CANTUSE)
206 /* Return true whe validity of KEY is sufficient. */
207 static int crypt_id_is_strong (crypt_key_t * key)
209 gpgme_validity_t val = GPGME_VALIDITY_UNKNOWN;
210 gpgme_user_id_t uid = NULL;
214 if ((key->flags & KEYFLAG_ISX509))
217 for (i = 0, uid = key->kobj->uids; (i < key->idx) && uid;
218 i++, uid = uid->next);
223 case GPGME_VALIDITY_UNKNOWN:
224 case GPGME_VALIDITY_UNDEFINED:
225 case GPGME_VALIDITY_NEVER:
226 case GPGME_VALIDITY_MARGINAL:
230 case GPGME_VALIDITY_FULL:
231 case GPGME_VALIDITY_ULTIMATE:
239 /* Return true when the KEY is valid, i.e. not marked as unusable. */
240 static int crypt_id_is_valid (crypt_key_t * key)
242 return !(key->flags & KEYFLAG_CANTUSE);
245 /* Return a bit vector describing how well the addresses ADDR and
246 U_ADDR match and whether KEY is valid. */
247 static int crypt_id_matches_addr (address_t * addr, address_t * u_addr,
252 if (crypt_id_is_valid (key))
253 rv |= CRYPT_KV_VALID;
255 if (crypt_id_is_strong (key))
256 rv |= CRYPT_KV_STRONGID;
258 if (addr->mailbox && u_addr->mailbox
259 && m_strcasecmp(addr->mailbox, u_addr->mailbox) == 0)
262 if (addr->personal && u_addr->personal
263 && m_strcasecmp(addr->personal, u_addr->personal) == 0)
264 rv |= CRYPT_KV_STRING;
271 * GPGME convenient functions.
274 /* Create a new gpgme context and return it. With FOR_SMIME set to
275 true, the protocol of the context is set to CMS. */
276 static gpgme_ctx_t create_gpgme_context (int for_smime)
281 err = gpgme_new (&ctx);
283 mutt_error (_("error creating gpgme context: %s\n"), gpgme_strerror (err));
289 err = gpgme_set_protocol (ctx, GPGME_PROTOCOL_CMS);
291 mutt_error (_("error enabling CMS protocol: %s\n"), gpgme_strerror (err));
300 /* Create a new gpgme data object. This is a wrapper to die on
302 static gpgme_data_t create_gpgme_data (void)
307 err = gpgme_data_new (&data);
309 mutt_error (_("error creating gpgme data object: %s\n"),
310 gpgme_strerror (err));
317 /* Create a new GPGME Data object from the mail body A. With CONVERT
318 passed as true, the lines are converted to CR,LF if required.
319 Return NULL on error or the gpgme_data_t object on success. */
320 static gpgme_data_t body_to_data_object (BODY * a, int convert)
322 char tempfile[_POSIX_PATH_MAX];
327 fptmp = m_tempfile(tempfile, sizeof(tempfile), NONULL(MCore.tmpdir), NULL);
329 mutt_perror (_("Can't create temporary file"));
333 mutt_write_mime_header (a, fptmp);
335 mutt_write_mime_body (a, fptmp);
339 unsigned char buf[1];
341 data = create_gpgme_data ();
343 while ((c = fgetc (fptmp)) != EOF) {
347 if (c == '\n' && !hadcr) {
349 gpgme_data_write (data, buf, 1);
354 /* FIXME: This is quite suboptimal */
356 gpgme_data_write (data, buf, 1);
358 gpgme_data_seek (data, 0, SEEK_SET);
360 err = gpgme_data_new_from_file (&data, tempfile, 1);
365 mutt_error (_("error allocating data object: %s\n"), gpgme_strerror (err));
372 /* Create a GPGME data object from the stream FP but limit the object
373 to LENGTH bytes starting at OFFSET bytes from the beginning of the
375 static gpgme_data_t file_to_data_object (FILE * fp, long offset, long length)
380 err = gpgme_data_new_from_filepart (&data, NULL, fp, offset, length);
382 mutt_error (_("error allocating data object: %s\n"), gpgme_strerror (err));
389 /* Write a GPGME data object to the stream FP. */
390 static int data_object_to_stream (gpgme_data_t data, FILE * fp)
396 err = ((gpgme_data_seek (data, 0, SEEK_SET) == -1)
397 ? gpgme_error_from_errno (errno) : 0);
399 mutt_error (_("error rewinding data object: %s\n"), gpgme_strerror (err));
403 while ((nread = gpgme_data_read (data, buf, sizeof (buf)))) {
404 /* fixme: we are not really converting CRLF to LF but just
405 skipping CR. Doing it correctly needs a more complex logic */
406 for (p = buf; nread; p++, nread--) {
412 mutt_perror ("[tempfile]");
417 mutt_error (_("error reading data object: %s\n"), strerror (errno));
423 /* Copy a data object to a newly created temporay file and return that
424 filename. Caller must free. With RET_FP not NULL, don't close the
425 stream but return it there. */
426 static char *data_object_to_tempfile (gpgme_data_t data, FILE ** ret_fp)
429 char tempfile[_POSIX_PATH_MAX];
433 fp = m_tempfile(tempfile, sizeof(tempfile), NONULL(MCore.tmpdir), NULL);
435 mutt_perror (_("Can't create temporary file"));
439 err = ((gpgme_data_seek (data, 0, SEEK_SET) == -1)
440 ? gpgme_error_from_errno (errno) : 0);
444 while ((nread = gpgme_data_read (data, buf, sizeof (buf)))) {
445 if (fwrite (buf, nread, 1, fp) != 1) {
446 mutt_perror (_("Can't create temporary file"));
458 mutt_error (_("error reading data object: %s\n"), gpgme_strerror (err));
465 return m_strdup(tempfile);
469 /* FIXME: stolen from gpgme to avoid "ambiguous identity" errors */
471 gpgme_get_key2 (gpgme_ctx_t ctx, const char *fpr, gpgme_key_t *r_key,
477 if (!ctx || !r_key || !fpr)
478 return gpg_error (GPG_ERR_INV_VALUE);
480 if (strlen (fpr) < 8) /* We have at least a key ID. */
481 return gpg_error (GPG_ERR_INV_VALUE);
483 /* FIXME: We use our own context because we have to avoid the user's
484 I/O callback handlers. */
485 err = gpgme_new (&listctx);
488 gpgme_set_protocol (listctx, gpgme_get_protocol (ctx));
489 err = gpgme_op_keylist_start (listctx, fpr, secret);
491 err = gpgme_op_keylist_next (listctx, r_key);
492 gpgme_release (listctx);
496 /* Create a GpgmeRecipientSet from the keys in the string KEYLIST.
497 The keys must be space delimited. */
498 static gpgme_key_t *create_recipient_set (const char *keylist,
499 gpgme_protocol_t protocol)
505 gpgme_key_t *rset = NULL;
506 unsigned int rset_n = 0;
507 gpgme_key_t key = NULL;
508 gpgme_ctx_t context = NULL;
510 err = gpgme_new (&context);
512 err = gpgme_set_protocol (context, protocol);
519 for (i = 0; *s && *s != ' ' && i < ssizeof(buf) - 1;)
523 if (i > 1 && buf[i - 1] == '!') {
524 /* The user selected to override the valididy of that
528 err = gpgme_get_key2 (context, buf, &key, 0);
530 key->uids->validity = GPGME_VALIDITY_FULL;
534 err = gpgme_get_key2 (context, buf, &key, 0);
537 p_realloc(&rset, rset_n + 1);
538 rset[rset_n++] = key;
541 mutt_error (_("error adding recipient `%s': %s\n"),
542 buf, gpgme_strerror (err));
550 /* NULL terminate. */
551 p_realloc(&rset, rset_n + 1);
552 rset[rset_n++] = NULL;
555 gpgme_release (context);
561 /* Make sure that the correct signer is set. Returns 0 on success. */
562 static int set_signer (gpgme_ctx_t ctx, int for_smime)
564 char *signid = for_smime ? SmimeDefaultKey : PgpSignAs;
567 gpgme_key_t key, key2;
569 if (!signid || !*signid)
572 listctx = create_gpgme_context (for_smime);
573 err = gpgme_op_keylist_start (listctx, signid, 1);
575 err = gpgme_op_keylist_next (listctx, &key);
577 gpgme_release (listctx);
578 mutt_error (_("secret key `%s' not found: %s\n"),
579 signid, gpgme_strerror (err));
582 err = gpgme_op_keylist_next (listctx, &key2);
584 gpgme_key_release (key);
585 gpgme_key_release (key2);
586 gpgme_release (listctx);
587 mutt_error (_("ambiguous specification of secret key `%s'\n"), signid);
590 gpgme_op_keylist_end (listctx);
591 gpgme_release (listctx);
593 gpgme_signers_clear (ctx);
594 err = gpgme_signers_add (ctx, key);
595 gpgme_key_release (key);
597 mutt_error (_("error setting secret key `%s': %s\n"),
598 signid, gpgme_strerror (err));
605 /* Encrypt the gpgme data object PLAINTEXT to the recipients in RSET
606 and return an allocated filename to a temporary file containing the
607 enciphered text. With USE_SMIME set to true, the smime backend is
608 used. With COMBINED_SIGNED a PGP message is signed and
609 encrypted. Returns NULL in case of error */
610 static char *encrypt_gpgme_object (gpgme_data_t plaintext, gpgme_key_t * rset,
611 int use_smime, int combined_signed)
615 gpgme_data_t ciphertext;
618 ctx = create_gpgme_context (use_smime);
620 gpgme_set_armor (ctx, 1);
622 ciphertext = create_gpgme_data ();
624 if (combined_signed) {
625 if (set_signer (ctx, use_smime)) {
626 gpgme_data_release (ciphertext);
630 err = gpgme_op_encrypt_sign (ctx, rset, GPGME_ENCRYPT_ALWAYS_TRUST,
631 plaintext, ciphertext);
634 err = gpgme_op_encrypt (ctx, rset, GPGME_ENCRYPT_ALWAYS_TRUST,
635 plaintext, ciphertext);
636 mutt_need_hard_redraw ();
638 mutt_error (_("error encrypting data: %s\n"), gpgme_strerror (err));
639 gpgme_data_release (ciphertext);
646 outfile = data_object_to_tempfile (ciphertext, NULL);
647 gpgme_data_release (ciphertext);
651 /* Find the "micalg" parameter from the last Gpgme operation on
652 context CTX. It is expected that this operation was a sign
653 operation. Return the algorithm name as a C string in buffer BUF
654 which must have been allocated by the caller with size BUFLEN.
655 Returns 0 on success or -1 in case of an error. The return string
656 is truncted to BUFLEN - 1. */
657 static int get_micalg (gpgme_ctx_t ctx, char *buf, ssize_t buflen)
659 gpgme_sign_result_t result = NULL;
660 const char *algorithm_name = NULL;
666 result = gpgme_op_sign_result (ctx);
668 algorithm_name = gpgme_hash_algo_name (result->signatures->hash_algo);
669 if (algorithm_name) {
670 m_strcpy(buf, buflen, algorithm_name);
674 return *buf ? 0 : -1;
677 static void print_time (time_t t, STATE * s)
681 setlocale (LC_TIME, "");
682 #ifdef HAVE_LANGINFO_D_T_FMT
683 strftime (p, sizeof (p), nl_langinfo (D_T_FMT), localtime (&t));
685 strftime (p, sizeof (p), "%c", localtime (&t));
687 setlocale (LC_TIME, "C");
688 state_attach_puts (p, s);
691 /* Implementation of `sign_message'. */
693 /* Sign the MESSAGE in body A either using OpenPGP or S/MIME when
694 USE_SMIME is passed as true. Returns the new body or NULL on
696 static BODY *sign_message (BODY * a, int use_smime)
703 gpgme_data_t message, signature;
705 convert_to_7bit (a); /* Signed data _must_ be in 7-bit format. */
707 message = body_to_data_object (a, 1);
710 signature = create_gpgme_data ();
712 ctx = create_gpgme_context (use_smime);
714 gpgme_set_armor (ctx, 1);
716 if (set_signer (ctx, use_smime)) {
717 gpgme_data_release (signature);
722 err = gpgme_op_sign (ctx, message, signature, GPGME_SIG_MODE_DETACH);
723 mutt_need_hard_redraw ();
724 gpgme_data_release (message);
726 gpgme_data_release (signature);
728 mutt_error (_("error signing data: %s\n"), gpgme_strerror (err));
732 sigfile = data_object_to_tempfile (signature, NULL);
733 gpgme_data_release (signature);
740 t->type = TYPEMULTIPART;
741 t->subtype = m_strdup("signed");
742 t->encoding = ENC7BIT;
744 t->disposition = DISPINLINE;
746 parameter_set_boundary(&t->parameter);
747 parameter_setval(&t->parameter, "protocol",
748 use_smime ? "application/pkcs7-signature"
749 : "application/pgp-signature");
750 /* Get the micalg from gpgme. Old gpgme versions don't support this
751 for S/MIME so we assume sha-1 in this case. */
752 if (!get_micalg (ctx, buf, sizeof buf))
753 parameter_setval(&t->parameter, "micalg", buf);
755 parameter_setval(&t->parameter, "micalg", "sha1");
761 t->parts->next = body_new();
763 t->type = TYPEAPPLICATION;
765 t->subtype = m_strdup("pkcs7-signature");
766 parameter_setval(&t->parameter, "name", "smime.p7s");
767 t->encoding = ENCBASE64;
769 t->disposition = DISPATTACH;
770 t->d_filename = m_strdup("smime.p7s");
773 t->subtype = m_strdup("pgp-signature");
775 t->disposition = DISPINLINE;
776 t->encoding = ENC7BIT;
778 t->filename = sigfile;
779 t->unlink = 1; /* ok to remove this file after sending. */
785 BODY *crypt_pgp_sign_message (BODY * a)
787 return sign_message (a, 0);
790 BODY *crypt_smime_sign_message (BODY * a)
792 return sign_message (a, 1);
796 * Implementation of `encrypt_message'.
799 /* Encrypt the mail body A to all keys given as space separated keyids
800 or fingerprints in KEYLIST and return the encrypted body. */
801 BODY *crypt_pgp_encrypt_message (BODY * a, char *keylist, int sign)
803 char *outfile = NULL;
805 gpgme_key_t *rset = NULL;
806 gpgme_data_t plaintext;
808 rset = create_recipient_set (keylist, GPGME_PROTOCOL_OpenPGP);
814 plaintext = body_to_data_object (a, 0);
820 outfile = encrypt_gpgme_object (plaintext, rset, 0, sign);
821 gpgme_data_release (plaintext);
827 t->type = TYPEMULTIPART;
828 t->subtype = m_strdup("encrypted");
829 t->encoding = ENC7BIT;
831 t->disposition = DISPINLINE;
833 parameter_set_boundary(&t->parameter);
834 parameter_setval(&t->parameter, "protocol", "application/pgp-encrypted");
836 t->parts = body_new();
837 t->parts->type = TYPEAPPLICATION;
838 t->parts->subtype = m_strdup("pgp-encrypted");
839 t->parts->encoding = ENC7BIT;
841 t->parts->next = body_new();
842 t->parts->next->type = TYPEAPPLICATION;
843 t->parts->next->subtype = m_strdup("octet-stream");
844 t->parts->next->encoding = ENC7BIT;
845 t->parts->next->filename = outfile;
846 t->parts->next->use_disp = 1;
847 t->parts->next->disposition = DISPINLINE;
848 t->parts->next->unlink = 1; /* delete after sending the message */
849 t->parts->next->d_filename = m_strdup("msg.asc"); /* non pgp/mime
856 * Implementation of `smime_build_smime_entity'.
859 /* Encrypt the mail body A to all keys given as space separated
860 fingerprints in KEYLIST and return the S/MIME encrypted body. */
861 BODY *crypt_smime_build_smime_entity (BODY * a, char *keylist)
863 char *outfile = NULL;
865 gpgme_key_t *rset = NULL;
866 gpgme_data_t plaintext;
868 rset = create_recipient_set (keylist, GPGME_PROTOCOL_CMS);
872 plaintext = body_to_data_object (a, 0);
878 outfile = encrypt_gpgme_object (plaintext, rset, 1, 0);
879 gpgme_data_release (plaintext);
885 t->type = TYPEAPPLICATION;
886 t->subtype = m_strdup("pkcs7-mime");
887 parameter_setval(&t->parameter, "name", "smime.p7m");
888 parameter_setval(&t->parameter, "smime-type", "enveloped-data");
889 t->encoding = ENCBASE64; /* The output of OpenSSL SHOULD be binary */
891 t->disposition = DISPATTACH;
892 t->d_filename = m_strdup("smime.p7m");
893 t->filename = outfile;
894 t->unlink = 1; /*delete after sending the message */
902 /* Implementation of `verify_one'. */
904 /* Display the common attributes of the signature summary SUM.
905 Return 1 if there is is a severe warning.
907 static int show_sig_summary (unsigned long sum,
908 gpgme_ctx_t ctx, gpgme_key_t key, int idx,
913 if ((sum & GPGME_SIGSUM_KEY_REVOKED)) {
914 state_attach_puts (_("Warning: One of the keys has been revoked\n"), s);
918 if ((sum & GPGME_SIGSUM_KEY_EXPIRED)) {
919 time_t at = key->subkeys->expires ? key->subkeys->expires : 0;
922 state_attach_puts (_("Warning: The key used to create the "
923 "signature expired at: "), s);
925 state_attach_puts ("\n", s);
928 state_attach_puts (_("Warning: At least one certification key "
929 "has expired\n"), s);
932 if ((sum & GPGME_SIGSUM_SIG_EXPIRED)) {
933 gpgme_verify_result_t result;
934 gpgme_signature_t sig;
937 result = gpgme_op_verify_result (ctx);
939 for (sig = result->signatures, i = 0; sig && (i < idx);
940 sig = sig->next, i++);
942 state_attach_puts (_("Warning: The signature expired at: "), s);
943 print_time (sig ? sig->exp_timestamp : 0, s);
944 state_attach_puts ("\n", s);
947 if ((sum & GPGME_SIGSUM_KEY_MISSING))
948 state_attach_puts (_("Can't verify due to a missing "
949 "key or certificate\n"), s);
951 if ((sum & GPGME_SIGSUM_CRL_MISSING)) {
952 state_attach_puts (_("The CRL is not available\n"), s);
956 if ((sum & GPGME_SIGSUM_CRL_TOO_OLD)) {
957 state_attach_puts (_("Available CRL is too old\n"), s);
961 if ((sum & GPGME_SIGSUM_BAD_POLICY))
962 state_attach_puts (_("A policy requirement was not met\n"), s);
964 if ((sum & GPGME_SIGSUM_SYS_ERROR)) {
965 const char *t0 = NULL, *t1 = NULL;
966 gpgme_verify_result_t result;
967 gpgme_signature_t sig;
970 state_attach_puts (_("A system error occurred"), s);
972 /* Try to figure out some more detailed system error information. */
973 result = gpgme_op_verify_result (ctx);
974 for (sig = result->signatures, i = 0; sig && (i < idx);
975 sig = sig->next, i++);
978 t1 = sig->wrong_key_usage ? "Wrong_Key_Usage" : "";
982 state_attach_puts (": ", s);
984 state_attach_puts (t0, s);
985 if (t1 && !(t0 && !m_strcmp(t0, t1))) {
987 state_attach_puts (",", s);
988 state_attach_puts (t1, s);
991 state_attach_puts ("\n", s);
998 static void show_fingerprint (gpgme_key_t key, STATE * state)
1003 const char *prefix = _("Fingerprint: ");
1008 s = key->subkeys ? key->subkeys->fpr : NULL;
1011 is_pgp = (key->protocol == GPGME_PROTOCOL_OpenPGP);
1013 bufsize = m_strlen(prefix) + m_strlen(s) * 4 + 2;
1014 buf = p_new(char, bufsize);
1015 m_strcpy(buf, bufsize, prefix);
1016 p = buf + m_strlen(buf);
1017 if (is_pgp && m_strlen(s) == 40) { /* PGP v4 style formatted. */
1018 for (i = 0; *s && s[1] && s[2] && s[3] && s[4]; s += 4, i++) {
1029 for (i = 0; *s && s[1] && s[2]; s += 2, i++) {
1032 *p++ = is_pgp ? ' ' : ':';
1033 if (is_pgp && i == 7)
1038 /* just in case print remaining odd digits */
1043 state_attach_puts (buf, state);
1047 /* Show the valididy of a key used for one signature. */
1048 static void show_one_sig_validity (gpgme_ctx_t ctx, int idx, STATE * s)
1050 gpgme_verify_result_t result = NULL;
1051 gpgme_signature_t sig = NULL;
1052 const char *txt = NULL;
1054 result = gpgme_op_verify_result (ctx);
1056 for (sig = result->signatures; sig && (idx > 0); sig = sig->next, idx--);
1058 switch (sig ? sig->validity : 0) {
1059 case GPGME_VALIDITY_UNKNOWN:
1060 txt = _("WARNING: We have NO indication whether "
1061 "the key belongs to the person named " "as shown above\n");
1063 case GPGME_VALIDITY_UNDEFINED:
1065 case GPGME_VALIDITY_NEVER:
1066 txt = _("WARNING: The key does NOT BELONG to "
1067 "the person named as shown above\n");
1069 case GPGME_VALIDITY_MARGINAL:
1070 txt = _("WARNING: It is NOT certain that the key "
1071 "belongs to the person named as shown above\n");
1073 case GPGME_VALIDITY_FULL:
1074 case GPGME_VALIDITY_ULTIMATE:
1079 state_attach_puts (txt, s);
1082 /* Show information about one signature. This fucntion is called with
1083 the context CTX of a sucessful verification operation and the
1084 enumerator IDX which should start at 0 and incremete for each
1087 Return values are: 0 for normal procession, 1 for a bad signature,
1088 2 for a signature with a warning or -1 for no more signature. */
1089 static int show_one_sig_status (gpgme_ctx_t ctx, int idx, STATE * s)
1092 const char *fpr, *uid;
1093 gpgme_key_t key = NULL;
1094 int i, anybad = 0, anywarn = 0;
1096 gpgme_user_id_t uids = NULL;
1097 gpgme_verify_result_t result;
1098 gpgme_signature_t sig;
1099 gpgme_error_t err = GPG_ERR_NO_ERROR;
1101 result = gpgme_op_verify_result (ctx);
1103 /* FIXME: this code should use a static variable and remember
1104 the current position in the list of signatures, IMHO.
1107 for (i = 0, sig = result->signatures; sig && (i < idx);
1108 i++, sig = sig->next);
1110 return -1; /* Signature not found. */
1112 if (signature_key) {
1113 gpgme_key_release (signature_key);
1114 signature_key = NULL;
1117 created = sig->timestamp;
1121 if (gpg_err_code (sig->status) != GPG_ERR_NO_ERROR)
1124 err = gpgme_get_key2 (ctx, fpr, &key, 0); /* secret key? */
1126 uid = (key->uids && key->uids->uid) ? key->uids->uid : "[?]";
1128 signature_key = key;
1131 key = NULL; /* Old gpgme versions did not set KEY to NULL on
1132 error. Do it here to avoid a double free. */
1136 if (!s || !s->fpout || !(s->flags & M_DISPLAY)); /* No state information so no way to print anything. */
1138 state_attach_puts (_("Error getting key information: "), s);
1139 state_attach_puts (gpg_strerror (err), s);
1140 state_attach_puts ("\n", s);
1143 else if ((sum & GPGME_SIGSUM_GREEN)) {
1144 state_attach_puts (_("Good signature from: "), s);
1145 state_attach_puts (uid, s);
1146 state_attach_puts ("\n", s);
1147 for (i = 1, uids = key->uids; uids; i++, uids = uids->next) {
1149 /* Skip primary UID. */
1153 state_attach_puts (_(" aka: "), s);
1154 state_attach_puts (uids->uid, s);
1155 state_attach_puts ("\n", s);
1157 state_attach_puts (_(" created: "), s);
1158 print_time (created, s);
1159 state_attach_puts ("\n", s);
1160 if (show_sig_summary (sum, ctx, key, idx, s))
1162 show_one_sig_validity (ctx, idx, s);
1164 else if ((sum & GPGME_SIGSUM_RED)) {
1165 state_attach_puts (_("*BAD* signature claimed to be from: "), s);
1166 state_attach_puts (uid, s);
1167 state_attach_puts ("\n", s);
1168 show_sig_summary (sum, ctx, key, idx, s);
1170 else if (!anybad && key && (key->protocol == GPGME_PROTOCOL_OpenPGP)) { /* We can't decide (yellow) but this is a PGP key with a good
1171 signature, so we display what a PGP user expects: The name,
1172 fingerprint and the key validity (which is neither fully or
1174 state_attach_puts (_("Good signature from: "), s);
1175 state_attach_puts (uid, s);
1176 state_attach_puts ("\n", s);
1177 state_attach_puts (_(" created: "), s);
1178 print_time (created, s);
1179 state_attach_puts ("\n", s);
1180 show_one_sig_validity (ctx, idx, s);
1181 show_fingerprint (key, s);
1182 if (show_sig_summary (sum, ctx, key, idx, s))
1185 else { /* can't decide (yellow) */
1187 state_attach_puts (_("Error checking signature"), s);
1188 state_attach_puts ("\n", s);
1189 show_sig_summary (sum, ctx, key, idx, s);
1192 if (key != signature_key)
1193 gpgme_key_release (key);
1196 return anybad ? 1 : anywarn ? 2 : 0;
1199 /* Do the actual verification step. With IS_SMIME set to true we
1200 assume S/MIME (surprise!) */
1201 int crypt_verify_one(BODY *sigbdy, STATE *s, FILE *fp, int is_smime)
1207 gpgme_data_t signature, message;
1209 signature = file_to_data_object (s->fpin, sigbdy->offset, sigbdy->length);
1213 /* We need to tell gpgme about the encoding because the backend can't
1214 auto-detect plain base-64 encoding which is used by S/MIME. */
1216 gpgme_data_set_encoding (signature, GPGME_DATA_ENCODING_BASE64);
1218 err = gpgme_data_new_from_stream(&message, fp);
1220 gpgme_data_release (signature);
1221 mutt_error (_("error allocating data object: %s\n"), gpgme_strerror (err));
1224 ctx = create_gpgme_context (is_smime);
1226 /* Note: We don't need a current time output because GPGME avoids
1227 such an attack by separating the meta information from the
1229 state_attach_puts (_("[-- Begin signature information --]\n"), s);
1231 err = gpgme_op_verify (ctx, signature, message, NULL);
1232 mutt_need_hard_redraw ();
1236 snprintf (buf, sizeof (buf) - 1,
1237 _("Error: verification failed: %s\n"), gpgme_strerror (err));
1238 state_attach_puts (buf, s);
1240 else { /* Verification succeeded, see what the result is. */
1244 if (signature_key) {
1245 gpgme_key_release (signature_key);
1246 signature_key = NULL;
1249 for (idx = 0; (res = show_one_sig_status (ctx, idx, s)) != -1; idx++) {
1260 gpgme_verify_result_t result;
1261 gpgme_sig_notation_t notation;
1262 gpgme_signature_t sig;
1264 result = gpgme_op_verify_result (ctx);
1266 for (sig = result->signatures; sig; sig = sig->next) {
1267 if (sig->notations) {
1268 state_attach_puts ("*** Begin Notation (signature by: ", s);
1269 state_attach_puts (sig->fpr, s);
1270 state_attach_puts (") ***\n", s);
1271 for (notation = sig->notations; notation; notation = notation->next)
1273 if (notation->name) {
1274 state_attach_puts (notation->name, s);
1275 state_attach_puts ("=", s);
1277 if (notation->value) {
1278 state_attach_puts (notation->value, s);
1279 if (!(*notation->value
1280 && (notation->value[m_strlen(notation->value) - 1] ==
1282 state_attach_puts ("\n", s);
1285 state_attach_puts ("*** End Notation ***\n", s);
1291 gpgme_release (ctx);
1293 state_attach_puts (_("[-- End signature information --]\n\n"), s);
1295 return badsig ? 1 : anywarn ? 2 : 0;
1299 * Implementation of `decrypt_part'.
1302 /* Decrypt a PGP or SMIME message (depending on the boolean flag
1303 IS_SMIME) with body A described further by state S. Write
1304 plaintext out to file FPOUT and return a new body. For PGP returns
1305 a flag in R_IS_SIGNED to indicate whether this is a combined
1306 encrypted and signed message, for S/MIME it returns true when it is
1307 not a encrypted but a signed message. */
1308 static BODY *decrypt_part (BODY * a, STATE * s, FILE * fpout, int is_smime,
1315 gpgme_data_t ciphertext, plaintext;
1316 int maybe_signed = 0;
1323 ctx = create_gpgme_context (is_smime);
1326 /* Make a data object from the body, create context etc. */
1327 ciphertext = file_to_data_object (s->fpin, a->offset, a->length);
1330 plaintext = create_gpgme_data ();
1332 /* Do the decryption or the verification in case of the S/MIME hack. */
1333 if ((!is_smime) || maybe_signed) {
1335 err = gpgme_op_decrypt_verify (ctx, ciphertext, plaintext);
1336 else if (maybe_signed)
1337 err = gpgme_op_verify (ctx, ciphertext, NULL, plaintext);
1340 /* Check wether signatures have been verified. */
1341 gpgme_verify_result_t verify_result = gpgme_op_verify_result (ctx);
1343 if (verify_result->signatures)
1348 err = gpgme_op_decrypt (ctx, ciphertext, plaintext);
1349 gpgme_data_release (ciphertext);
1351 if (is_smime && !maybe_signed && gpg_err_code (err) == GPG_ERR_NO_DATA) {
1352 /* Check whether this might be a signed message despite what
1353 the mime header told us. Retry then. gpgsm returns the
1354 error information "unsupported Algorithm '?'" but gpgme
1355 will not store this unknown algorithm, thus we test that
1356 it has not been set. */
1357 gpgme_decrypt_result_t result;
1359 result = gpgme_op_decrypt_result (ctx);
1360 if (!result->unsupported_algorithm) {
1362 gpgme_data_release (plaintext);
1366 mutt_need_hard_redraw ();
1367 if ((s->flags & M_DISPLAY)) {
1370 snprintf (buf, sizeof (buf) - 1,
1371 _("[-- Error: decryption failed: %s --]\n\n"),
1372 gpgme_strerror (err));
1373 state_attach_puts (buf, s);
1375 gpgme_data_release (plaintext);
1376 gpgme_release (ctx);
1379 mutt_need_hard_redraw ();
1381 /* Read the output from GPGME, and make sure to change CRLF to LF,
1382 otherwise read_mime_header has a hard time parsing the message. */
1383 if (data_object_to_stream (plaintext, fpout)) {
1384 gpgme_data_release (plaintext);
1385 gpgme_release (ctx);
1388 gpgme_data_release (plaintext);
1390 a->is_signed_data = 0;
1396 a->is_signed_data = 1;
1398 *r_is_signed = -1; /* A signature exists. */
1400 if ((s->flags & M_DISPLAY))
1401 state_attach_puts (_("[-- Begin signature " "information --]\n"), s);
1402 for (idx = 0; (res = show_one_sig_status (ctx, idx, s)) != -1; idx++) {
1408 if (!anybad && idx && r_is_signed && *r_is_signed)
1409 *r_is_signed = anywarn ? 2 : 1; /* Good signature. */
1411 if ((s->flags & M_DISPLAY))
1412 state_attach_puts (_("[-- End signature " "information --]\n\n"), s);
1414 gpgme_release (ctx);
1419 tattach = mutt_read_mime_header (fpout, 0);
1422 * Need to set the length of this body part.
1424 fstat (fileno (fpout), &info);
1425 tattach->length = info.st_size - tattach->offset;
1427 tattach->warnsig = anywarn;
1429 /* See if we need to recurse on this MIME part. */
1430 mutt_parse_part (fpout, tattach);
1436 /* Decrypt a PGP/MIME message in FPIN and B and return a new body and
1437 the stream in CUR and FPOUT. Returns 0 on success. */
1438 int crypt_pgp_decrypt_mime (FILE * fpin, FILE ** fpout, BODY * b, BODY ** cur)
1440 char tempfile[_POSIX_PATH_MAX];
1442 BODY *first_part = b;
1445 first_part->goodsig = 0;
1446 first_part->warnsig = 0;
1448 if (!mutt_is_multipart_encrypted (b))
1451 if (!b->parts || !b->parts->next)
1458 *fpout = m_tempfile(tempfile, sizeof(tempfile), NONULL(MCore.tmpdir), NULL);
1460 mutt_perror (_("Can't create temporary file"));
1465 *cur = decrypt_part (b, &s, *fpout, 0, &is_signed);
1468 first_part->goodsig = 1;
1470 return *cur ? 0 : -1;
1474 /* Decrypt a S/MIME message in FPIN and B and return a new body and
1475 the stream in CUR and FPOUT. Returns 0 on success. */
1476 int crypt_smime_decrypt_mime (FILE * fpin, FILE ** fpout, BODY * b,
1479 char tempfile[_POSIX_PATH_MAX];
1483 long saved_b_offset;
1484 ssize_t saved_b_length;
1487 if (!mutt_is_application_smime (b))
1493 /* Decode the body - we need to pass binary CMS to the
1494 backend. The backend allows for Base64 encoded data but it does
1495 not allow for QP which I have seen in some messages. So better
1497 saved_b_type = b->type;
1498 saved_b_offset = b->offset;
1499 saved_b_length = b->length;
1502 fseeko (s.fpin, b->offset, 0);
1503 tmpfp = m_tempfile (tempfile, sizeof(tempfile), NONULL(MCore.tmpdir), NULL);
1505 mutt_perror (_("Can't create temporary file"));
1508 mutt_unlink (tempfile);
1511 mutt_decode_attachment (b, &s);
1513 b->length = ftello (s.fpout);
1520 *fpout = m_tempfile(tempfile, sizeof(tempfile), NONULL(MCore.tmpdir), NULL);
1522 mutt_perror (_("Can't create temporary file"));
1525 mutt_unlink (tempfile);
1527 *cur = decrypt_part (b, &s, *fpout, 1, &is_signed);
1529 (*cur)->goodsig = is_signed > 0;
1530 b->type = saved_b_type;
1531 b->length = saved_b_length;
1532 b->offset = saved_b_offset;
1535 if (*cur && !is_signed && !(*cur)->parts
1536 && mutt_is_application_smime (*cur)) {
1537 /* Assume that this is a opaque signed s/mime message. This is
1538 an ugly way of doing it but we have anyway a problem with
1539 arbitrary encoded S/MIME messages: Only the outer part may be
1540 encrypted. The entire mime parsing should be revamped,
1541 probably by keeping the temportary files so that we don't
1542 need to decrypt them all the time. Inner parts of an
1543 encrypted part can then pint into this file and tehre won't
1544 never be a need to decrypt again. This needs a partial
1545 rewrite of the MIME engine. */
1549 saved_b_type = bb->type;
1550 saved_b_offset = bb->offset;
1551 saved_b_length = bb->length;
1554 fseeko (s.fpin, bb->offset, 0);
1555 tmpfp = m_tempfile (tempfile, sizeof(tempfile), NONULL(MCore.tmpdir), NULL);
1557 mutt_perror (_("Can't create temporary file"));
1560 mutt_unlink (tempfile);
1563 mutt_decode_attachment (bb, &s);
1565 bb->length = ftello (s.fpout);
1573 *fpout = m_tempfile(tempfile, sizeof(tempfile), NONULL(MCore.tmpdir), NULL);
1575 mutt_perror (_("Can't create temporary file"));
1578 mutt_unlink (tempfile);
1580 tmp_b = decrypt_part (bb, &s, *fpout, 1, &is_signed);
1582 tmp_b->goodsig = is_signed > 0;
1583 bb->type = saved_b_type;
1584 bb->length = saved_b_length;
1585 bb->offset = saved_b_offset;
1588 body_list_wipe(cur);
1591 return *cur ? 0 : -1;
1596 * Implementation of `pgp_check_traditional'.
1599 static int pgp_check_traditional_one_body (FILE * fp, BODY * b,
1602 char tempfile[_POSIX_PATH_MAX];
1603 char buf[HUGE_STRING];
1610 if (b->type != TYPETEXT)
1613 if (tagged_only && !b->tagged)
1616 tempfd = m_tempfd(tempfile, sizeof(tempfile), NONULL(MCore.tmpdir), NULL);
1617 if (mutt_decode_save_attachment (fp, b, tempfd, 0) != 0) {
1622 if ((tfp = fopen(tempfile, "r")) == NULL) {
1627 while (fgets (buf, sizeof (buf), tfp)) {
1628 if (!m_strncmp("-----BEGIN PGP ", buf, 15)) {
1629 if (!m_strcmp("MESSAGE-----\n", buf + 15))
1631 else if (!m_strcmp("SIGNED MESSAGE-----\n", buf + 15))
1641 /* fix the content type */
1643 parameter_setval(&b->parameter, "format", "fixed");
1644 parameter_setval(&b->parameter, "x-action",
1645 enc ? "pgp-encrypted" : "pgp-signed");
1649 int crypt_pgp_check_traditional (FILE * fp, BODY * b, int tagged_only)
1654 for (; b; b = b->next) {
1655 if (is_multipart (b))
1656 rv = (crypt_pgp_check_traditional (fp, b->parts, tagged_only) || rv);
1657 else if (b->type == TYPETEXT) {
1658 if ((r = mutt_is_application_pgp (b)))
1661 rv = (pgp_check_traditional_one_body (fp, b, tagged_only) || rv);
1668 /* Implementation of `application_handler'. */
1671 Copy a clearsigned message, and strip the signature and PGP's
1674 XXX - charset handling: We assume that it is safe to do
1675 character set decoding first, dash decoding second here, while
1676 we do it the other way around in the main handler.
1678 (Note that we aren't worse than Outlook & Cie in this, and also
1679 note that we can successfully handle anything produced by any
1680 existing versions of mutt.) */
1682 static void copy_clearsigned (gpgme_data_t data, STATE * s, char *charset)
1684 char buf[HUGE_STRING];
1685 short complete, armor_header;
1690 fname = data_object_to_tempfile (data, &fp);
1696 fc = fgetconv_open (fp, charset, MCharset.charset, M_ICONV_HOOK_FROM);
1698 for (complete = 1, armor_header = 1;
1699 fgetconvs (buf, sizeof (buf), fc) != NULL;
1700 complete = strchr (buf, '\n') != NULL) {
1703 state_puts (buf, s);
1707 if (!m_strcmp(buf, "-----BEGIN PGP SIGNATURE-----\n"))
1717 state_puts (s->prefix, s);
1719 if (buf[0] == '-' && buf[1] == ' ')
1720 state_puts (buf + 2, s);
1722 state_puts (buf, s);
1725 fgetconv_close (&fc);
1730 /* Support for classic_application/pgp */
1731 int crypt_pgp_application_pgp_handler (BODY * m, STATE * s)
1733 int needpass = -1, pgp_keyblock = 0;
1737 off_t last_pos, offset;
1738 char buf[HUGE_STRING];
1739 FILE *pgpout = NULL;
1741 gpgme_error_t err = 0;
1742 gpgme_data_t armored_data = NULL;
1744 short maybe_goodsig = 1;
1745 short have_any_sigs = 0;
1747 char body_charset[STRING]; /* Only used for clearsigned messages. */
1749 /* For clearsigned messages we won't be able to get a character set
1750 but we know that this may only be text thus we assume Latin-1
1752 if (!mutt_get_body_charset (body_charset, sizeof (body_charset), m))
1753 m_strcpy(body_charset, sizeof(body_charset), "iso-8859-1");
1755 fseeko (s->fpin, m->offset, 0);
1756 last_pos = m->offset;
1758 for (bytes = m->length; bytes > 0;) {
1759 if (fgets (buf, sizeof (buf), s->fpin) == NULL)
1762 offset = ftello (s->fpin);
1763 bytes -= (offset - last_pos); /* don't rely on m_strlen(buf) */
1766 if (!m_strncmp("-----BEGIN PGP ", buf, 15)) {
1768 start_pos = last_pos;
1770 if (!m_strcmp("MESSAGE-----\n", buf + 15))
1772 else if (!m_strcmp("SIGNED MESSAGE-----\n", buf + 15)) {
1776 else if (!option (OPTDONTHANDLEPGPKEYS) &&
1777 !m_strcmp("PUBLIC KEY BLOCK-----\n", buf + 15)) {
1782 /* XXX - we may wish to recode here */
1784 state_puts (s->prefix, s);
1785 state_puts (buf, s);
1789 have_any_sigs = (have_any_sigs || (clearsign && (s->flags & M_VERIFY)));
1791 /* Copy PGP material to an data container */
1792 armored_data = create_gpgme_data ();
1793 gpgme_data_write (armored_data, buf, m_strlen(buf));
1794 while (bytes > 0 && fgets (buf, sizeof (buf) - 1, s->fpin) != NULL) {
1795 offset = ftello (s->fpin);
1796 bytes -= (offset - last_pos); /* don't rely on m_strlen(buf) */
1799 gpgme_data_write (armored_data, buf, m_strlen(buf));
1801 if ((needpass && !m_strcmp("-----END PGP MESSAGE-----\n", buf))
1803 && (!m_strcmp("-----END PGP SIGNATURE-----\n", buf)
1804 || !m_strcmp("-----END PGP PUBLIC KEY BLOCK-----\n",
1809 /* Invoke PGP if needed */
1810 if (!clearsign || (s->flags & M_VERIFY)) {
1811 unsigned int sig_stat = 0;
1812 gpgme_data_t plaintext;
1815 plaintext = create_gpgme_data ();
1816 ctx = create_gpgme_context (0);
1819 err = gpgme_op_verify (ctx, armored_data, NULL, plaintext);
1821 err = gpgme_op_decrypt_verify (ctx, armored_data, plaintext);
1822 if (gpg_err_code (err) == GPG_ERR_NO_DATA) {
1823 /* Decrypt verify can't handle signed only messages. */
1824 err = (gpgme_data_seek (armored_data, 0, SEEK_SET) == -1)
1825 ? gpgme_error_from_errno (errno) : 0;
1826 /* Must release plaintext so that we supply an
1827 uninitialized object. */
1828 gpgme_data_release (plaintext);
1829 plaintext = create_gpgme_data ();
1830 err = gpgme_op_verify (ctx, armored_data, NULL, plaintext);
1837 snprintf (errbuf, sizeof (errbuf) - 1,
1838 _("Error: decryption/verification failed: %s\n"),
1839 gpgme_strerror (err));
1840 state_attach_puts (errbuf, s);
1842 else { /* Decryption/Verification succeeded */
1846 /* Check wether signatures have been verified. */
1847 gpgme_verify_result_t verify_result;
1849 verify_result = gpgme_op_verify_result (ctx);
1850 if (verify_result->signatures)
1856 if ((s->flags & M_DISPLAY) && sig_stat) {
1861 state_attach_puts (_("[-- Begin signature "
1862 "information --]\n"), s);
1865 (res = show_one_sig_status (ctx, idx, s)) != -1; idx++) {
1874 state_attach_puts (_("[-- End signature "
1875 "information --]\n\n"), s);
1878 tmpfname = data_object_to_tempfile (plaintext, &pgpout);
1881 state_attach_puts (_("Error: copy data failed\n"), s);
1885 p_delete(&tmpfname);
1888 gpgme_release (ctx);
1892 * Now, copy cleartext to the screen. NOTE - we expect that PGP
1893 * outputs utf-8 cleartext. This may not always be true, but it
1894 * seems to be a reasonable guess.
1897 if (s->flags & M_DISPLAY) {
1899 state_attach_puts (_("[-- BEGIN PGP MESSAGE --]\n\n"), s);
1900 else if (pgp_keyblock)
1901 state_attach_puts (_("[-- BEGIN PGP PUBLIC KEY BLOCK --]\n"), s);
1903 state_attach_puts (_("[-- BEGIN PGP SIGNED MESSAGE --]\n\n"), s);
1907 copy_clearsigned (armored_data, s, body_charset);
1914 fc = fgetconv_open (pgpout, "utf-8", MCharset.charset, 0);
1915 while ((c = fgetconv (fc)) != EOF) {
1917 if (c == '\n' && s->prefix)
1918 state_puts (s->prefix, s);
1920 fgetconv_close (&fc);
1923 if (s->flags & M_DISPLAY) {
1924 state_putc ('\n', s);
1926 state_attach_puts (_("[-- END PGP MESSAGE --]\n"), s);
1927 else if (pgp_keyblock)
1928 state_attach_puts (_("[-- END PGP PUBLIC KEY BLOCK --]\n"), s);
1930 state_attach_puts (_("[-- END PGP SIGNED MESSAGE --]\n"), s);
1938 /* XXX - we may wish to recode here */
1940 state_puts (s->prefix, s);
1941 state_puts (buf, s);
1945 m->goodsig = (maybe_goodsig && have_any_sigs);
1947 if (needpass == -1) {
1948 state_attach_puts (_("[-- Error: could not find beginning"
1949 " of PGP message! --]\n\n"), s);
1955 /* Implementation of `encrypted_handler'. */
1957 /* MIME handler for pgp/mime encrypted messages. */
1958 int crypt_pgp_encrypted_handler (BODY * a, STATE * s)
1960 char tempfile[_POSIX_PATH_MAX];
1963 BODY *orig_body = a;
1968 if (!a || a->type != TYPEAPPLICATION || !a->subtype
1969 || ascii_strcasecmp ("pgp-encrypted", a->subtype)
1970 || !a->next || a->next->type != TYPEAPPLICATION || !a->next->subtype
1971 || ascii_strcasecmp ("octet-stream", a->next->subtype)) {
1972 if (s->flags & M_DISPLAY)
1973 state_attach_puts (_("[-- Error: malformed PGP/MIME message! --]\n\n"),
1978 /* Move forward to the application/pgp-encrypted body. */
1981 fpout = m_tempfile(tempfile, sizeof(tempfile), NONULL(MCore.tmpdir), NULL);
1983 if (s->flags & M_DISPLAY)
1984 state_attach_puts (_("[-- Error: could not create temporary file! "
1989 tattach = decrypt_part (a, s, fpout, 0, &is_signed);
1991 tattach->goodsig = is_signed > 0;
1993 if (s->flags & M_DISPLAY)
1994 state_attach_puts (is_signed ?
1996 ("[-- The following data is PGP/MIME signed and encrypted --]\n\n") :
1997 _("[-- The following data is PGP/MIME encrypted --]\n\n"), s);
2000 FILE *savefp = s->fpin;
2003 rc = mutt_body_handler (tattach, s);
2008 * if a multipart/signed is the _only_ sub-part of a
2009 * multipart/encrypted, cache signature verification
2012 if (mutt_is_multipart_signed (tattach) && !tattach->next)
2013 orig_body->goodsig |= tattach->goodsig;
2015 if (s->flags & M_DISPLAY) {
2016 state_puts ("\n", s);
2017 state_attach_puts (is_signed ?
2019 ("[-- End of PGP/MIME signed and encrypted data --]\n")
2020 : _("[-- End of PGP/MIME encrypted data --]\n"), s);
2023 body_list_wipe(&tattach);
2027 mutt_unlink (tempfile);
2031 /* Support for application/smime */
2032 int crypt_smime_application_smime_handler (BODY * a, STATE * s)
2034 char tempfile[_POSIX_PATH_MAX];
2041 fpout = m_tempfile(tempfile, sizeof(tempfile), NONULL(MCore.tmpdir), NULL);
2043 if (s->flags & M_DISPLAY)
2044 state_attach_puts (_("[-- Error: could not create temporary file! "
2049 tattach = decrypt_part (a, s, fpout, 1, &is_signed);
2051 tattach->goodsig = is_signed > 0;
2053 if (s->flags & M_DISPLAY)
2054 state_attach_puts (is_signed ?
2055 _("[-- The following data is S/MIME signed --]\n\n") :
2056 _("[-- The following data is S/MIME encrypted --]\n\n"), s);
2059 FILE *savefp = s->fpin;
2062 rc = mutt_body_handler (tattach, s);
2067 * if a multipart/signed is the _only_ sub-part of a
2068 * multipart/encrypted, cache signature verification
2071 if (mutt_is_multipart_signed (tattach) && !tattach->next) {
2072 if (!(a->goodsig = tattach->goodsig))
2073 a->warnsig = tattach->warnsig;
2075 else if (tattach->goodsig) {
2077 a->warnsig = tattach->warnsig;
2080 if (s->flags & M_DISPLAY) {
2081 state_puts ("\n", s);
2082 state_attach_puts (is_signed ?
2083 _("[-- End of S/MIME signed data --]\n") :
2084 _("[-- End of S/MIME encrypted data --]\n"), s);
2087 body_list_wipe(&tattach);
2091 mutt_unlink (tempfile);
2097 * Format an entry on the CRYPT key selection menu.
2100 * %k key id %K key id of the principal key
2102 * %a algorithm %A algorithm of the princ. key
2103 * %l length %L length of the princ. key
2104 * %f flags %F flags of the princ. key
2105 * %c capabilities %C capabilities of the princ. key
2106 * %t trust/validity of the key-uid association
2108 * %[...] date of key using strftime(3)
2112 crypt_entry_fmt (char *dest, ssize_t destlen, char op,
2113 const char *src, const char *prefix,
2114 const char *ifstr, const char *elstr,
2115 anytype data, format_flag flags)
2118 crypt_entry_t *entry;
2121 int optional = (flags & M_FORMAT_OPTIONAL);
2122 const char *s = NULL;
2128 /* if (isupper ((unsigned char) op)) */
2131 kflags = (key->flags /*| (pkey->flags & KEYFLAG_RESTRICTIONS)
2134 switch (ascii_tolower (op)) {
2138 char buf2[STRING], *p;
2154 while (len > 0 && *cp != ']') {
2163 break; /* not enough space */
2173 if (do_locales && Locale)
2174 setlocale (LC_TIME, Locale);
2179 if (key->kobj->subkeys && (key->kobj->subkeys->timestamp > 0))
2180 tt = key->kobj->subkeys->timestamp;
2182 tm = localtime (&tt);
2184 strftime (buf2, sizeof (buf2), dest, tm);
2187 setlocale (LC_TIME, "C");
2189 snprintf (fmt, sizeof (fmt), "%%%ss", prefix);
2190 snprintf (dest, destlen, fmt, buf2);
2197 snprintf (fmt, sizeof (fmt), "%%%sd", prefix);
2198 snprintf (dest, destlen, fmt, entry->num);
2203 /* fixme: we need a way to distinguish between main and subkeys.
2204 Store the idx in entry? */
2205 snprintf (fmt, sizeof (fmt), "%%%ss", prefix);
2206 snprintf (dest, destlen, fmt, crypt_keyid (key));
2211 snprintf (fmt, sizeof (fmt), "%%%ss", prefix);
2212 snprintf (dest, destlen, fmt, key->uid);
2217 snprintf (fmt, sizeof (fmt), "%%%s.3s", prefix);
2218 if (key->kobj->subkeys)
2219 s = gpgme_pubkey_algo_name (key->kobj->subkeys->pubkey_algo);
2222 snprintf (dest, destlen, fmt, s);
2227 snprintf (fmt, sizeof (fmt), "%%%slu", prefix);
2228 if (key->kobj->subkeys)
2229 val = key->kobj->subkeys->length;
2232 snprintf (dest, destlen, fmt, val);
2237 snprintf (fmt, sizeof (fmt), "%%%sc", prefix);
2238 snprintf (dest, destlen, fmt, crypt_flags (kflags));
2240 else if (!(kflags & (KEYFLAG_RESTRICTIONS)))
2245 snprintf (fmt, sizeof (fmt), "%%%ss", prefix);
2246 snprintf (dest, destlen, fmt, crypt_key_abilities (kflags));
2248 else if (!(kflags & (KEYFLAG_ABILITIES)))
2252 if ((kflags & KEYFLAG_ISX509))
2255 gpgme_user_id_t uid = NULL;
2258 for (i = 0, uid = key->kobj->uids; uid && (i < key->idx);
2259 i++, uid = uid->next);
2261 switch (uid->validity) {
2262 case GPGME_VALIDITY_UNDEFINED:
2265 case GPGME_VALIDITY_NEVER:
2268 case GPGME_VALIDITY_MARGINAL:
2271 case GPGME_VALIDITY_FULL:
2274 case GPGME_VALIDITY_ULTIMATE:
2277 case GPGME_VALIDITY_UNKNOWN:
2283 snprintf (fmt, sizeof (fmt), "%%%sc", prefix);
2284 snprintf (dest, destlen, fmt, s ? *s : 'B');
2287 snprintf (fmt, sizeof (fmt), "%%%ss", prefix);
2288 snprintf (dest, destlen, fmt,
2289 gpgme_get_protocol_name (key->kobj->protocol));
2296 if (flags & M_FORMAT_OPTIONAL)
2297 m_strformat(dest, destlen, 0, optional ? ifstr: elstr,
2298 mutt_attach_fmt, data, 0);
2302 /* Used by the display fucntion to format a line. */
2303 static void crypt_entry (char *s, ssize_t l, MUTTMENU * menu, int num)
2305 crypt_key_t **key_table = (crypt_key_t **) menu->data;
2306 crypt_entry_t entry;
2308 entry.key = key_table[num];
2309 entry.num = num + 1;
2311 m_strformat(s, l, COLS - SW, PgpEntryFormat, crypt_entry_fmt, &entry,
2312 option(OPTARROWCURSOR) ? M_FORMAT_ARROWCURSOR : 0);
2315 /* Compare two addresses and the keyid to be used for sorting. */
2316 static int _crypt_compare_address (const void *a, const void *b)
2318 crypt_key_t **s = (crypt_key_t **) a;
2319 crypt_key_t **t = (crypt_key_t **) b;
2322 if ((r = m_strcasecmp((*s)->uid, (*t)->uid)))
2325 return m_strcasecmp(crypt_keyid (*s), crypt_keyid (*t)) > 0;
2328 static int crypt_compare_address (const void *a, const void *b)
2330 return ((PgpSortKeys & SORT_REVERSE) ? !_crypt_compare_address (a, b)
2331 : _crypt_compare_address (a, b));
2335 /* Compare two key IDs and the addresses to be used for sorting. */
2336 static int _crypt_compare_keyid (const void *a, const void *b)
2338 crypt_key_t **s = (crypt_key_t **) a;
2339 crypt_key_t **t = (crypt_key_t **) b;
2342 if ((r = m_strcasecmp(crypt_keyid (*s), crypt_keyid (*t))))
2345 return m_strcasecmp((*s)->uid, (*t)->uid) > 0;
2348 static int crypt_compare_keyid (const void *a, const void *b)
2350 return ((PgpSortKeys & SORT_REVERSE) ? !_crypt_compare_keyid (a, b)
2351 : _crypt_compare_keyid (a, b));
2354 /* Compare 2 creation dates and the addresses. For sorting. */
2355 static int _crypt_compare_date (const void *a, const void *b)
2357 crypt_key_t **s = (crypt_key_t **) a;
2358 crypt_key_t **t = (crypt_key_t **) b;
2359 unsigned long ts = 0, tt = 0;
2361 if ((*s)->kobj->subkeys && ((*s)->kobj->subkeys->timestamp > 0))
2362 ts = (*s)->kobj->subkeys->timestamp;
2363 if ((*t)->kobj->subkeys && ((*t)->kobj->subkeys->timestamp > 0))
2364 tt = (*t)->kobj->subkeys->timestamp;
2371 return m_strcasecmp((*s)->uid, (*t)->uid) > 0;
2374 static int crypt_compare_date (const void *a, const void *b)
2376 return ((PgpSortKeys & SORT_REVERSE) ? !_crypt_compare_date (a, b)
2377 : _crypt_compare_date (a, b));
2380 /* Compare two trust values, the key length, the creation dates. the
2381 addresses and the key IDs. For sorting. */
2382 static int _crypt_compare_trust (const void *a, const void *b)
2384 crypt_key_t **s = (crypt_key_t **) a;
2385 crypt_key_t **t = (crypt_key_t **) b;
2386 unsigned long ts = 0, tt = 0;
2389 if ((r = (((*s)->flags & (KEYFLAG_RESTRICTIONS))
2390 - ((*t)->flags & (KEYFLAG_RESTRICTIONS)))))
2393 if ((*s)->kobj->uids)
2394 ts = (*s)->kobj->uids->validity;
2395 if ((*t)->kobj->uids)
2396 tt = (*t)->kobj->uids->validity;
2397 if ((r = (tt - ts)))
2400 if ((*s)->kobj->subkeys)
2401 ts = (*s)->kobj->subkeys->length;
2402 if ((*t)->kobj->subkeys)
2403 tt = (*t)->kobj->subkeys->length;
2407 if ((*s)->kobj->subkeys && ((*s)->kobj->subkeys->timestamp > 0))
2408 ts = (*s)->kobj->subkeys->timestamp;
2409 if ((*t)->kobj->subkeys && ((*t)->kobj->subkeys->timestamp > 0))
2410 tt = (*t)->kobj->subkeys->timestamp;
2416 if ((r = m_strcasecmp((*s)->uid, (*t)->uid)))
2418 return (m_strcasecmp(crypt_keyid ((*s)), crypt_keyid ((*t)))) > 0;
2421 static int crypt_compare_trust (const void *a, const void *b)
2423 return ((PgpSortKeys & SORT_REVERSE) ? !_crypt_compare_trust (a, b)
2424 : _crypt_compare_trust (a, b));
2427 /* Print the X.500 Distinguished Name part KEY from the array of parts
2429 static int print_dn_part (FILE * fp, struct dn_array_s *dn, const char *key)
2433 for (; dn->key; dn++) {
2434 if (!m_strcmp(dn->key, key)) {
2437 print_utf8 (fp, dn->value, m_strlen(dn->value));
2444 /* Print all parts of a DN in a standard sequence. */
2445 static void print_dn_parts (FILE * fp, struct dn_array_s *dn)
2447 const char *stdpart[] = {
2448 "CN", "OU", "O", "STREET", "L", "ST", "C", NULL
2450 int any = 0, any2 = 0, i;
2452 for (i = 0; stdpart[i]; i++) {
2455 any = print_dn_part (fp, dn, stdpart[i]);
2457 /* now print the rest without any specific ordering */
2458 for (; dn->key; dn++) {
2459 for (i = 0; stdpart[i]; i++) {
2460 if (!m_strcmp(dn->key, stdpart[i]))
2468 any = print_dn_part (fp, dn, dn->key);
2477 /* Parse an RDN; this is a helper to parse_dn(). */
2478 static const unsigned char *parse_dn_part (struct dn_array_s *array,
2479 const unsigned char *string)
2481 const unsigned char *s, *s1;
2485 /* parse attributeType */
2486 for (s = string + 1; *s && *s != '='; s++);
2488 return NULL; /* error */
2491 return NULL; /* empty key */
2492 array->key = p_dupstr(string, n );
2493 p = (unsigned char *) array->key;
2496 if (*string == '#') { /* hexstring */
2498 for (s = string; hexval(*s) >= 0; s++)
2502 return NULL; /* empty or odd number of digits */
2504 p = p_new(unsigned char, n + 1);
2505 array->value = (char *) p;
2506 for (s1 = string; n; s1 += 2, n--)
2507 *p++ = (hexval(*s1) << 8) | hexval(*s1);
2510 else { /* regular v3 quoted string */
2511 for (n = 0, s = string; *s; s++) {
2512 if (*s == '\\') { /* pair */
2514 if (*s == ',' || *s == '=' || *s == '+'
2515 || *s == '<' || *s == '>' || *s == '#' || *s == ';'
2516 || *s == '\\' || *s == '\"' || *s == ' ')
2518 else if (hexval(*s) >= 0 && hexval(*s + 1) >= 0) {
2523 return NULL; /* invalid escape sequence */
2525 else if (*s == '\"')
2526 return NULL; /* invalid encoding */
2527 else if (*s == ',' || *s == '=' || *s == '+'
2528 || *s == '<' || *s == '>' || *s == '#' || *s == ';')
2534 p = p_new(unsigned char, n + 1);
2535 array->value = (char *) p;
2536 for (s = string; n; s++, n--) {
2539 if (hexval(*s) >= 0) {
2540 *p++ = (hexval(*s) << 8) | hexval(*s + 1);
2555 /* Parse a DN and return an array-ized one. This is not a validating
2556 parser and it does not support any old-stylish syntax; gpgme is
2557 expected to return only rfc2253 compatible strings. */
2558 static struct dn_array_s *parse_dn (const unsigned char *string)
2560 struct dn_array_s *array;
2561 ssize_t arrayidx, arraysize;
2564 arraysize = 7; /* C,ST,L,O,OU,CN,email */
2565 array = p_new(struct dn_array_s, arraysize + 1);
2568 while (*string == ' ')
2572 if (arrayidx >= arraysize) { /* mutt lacks a real safe_realoc - so we need to copy */
2573 struct dn_array_s *a2;
2576 a2 = p_new(struct dn_array_s, arraysize + 1);
2577 for (i = 0; i < arrayidx; i++) {
2578 a2[i].key = array[i].key;
2579 a2[i].value = array[i].value;
2584 array[arrayidx].key = NULL;
2585 array[arrayidx].value = NULL;
2586 string = parse_dn_part (array + arrayidx, string);
2590 while (*string == ' ')
2592 if (*string && *string != ',' && *string != ';' && *string != '+')
2593 goto failure; /* invalid delimiter */
2597 array[arrayidx].key = NULL;
2598 array[arrayidx].value = NULL;
2602 for (i = 0; i < arrayidx; i++) {
2603 p_delete(&array[i].key);
2604 p_delete(&array[i].value);
2611 /* Print a nice representation of the USERID and make sure it is
2612 displayed in a proper way, which does mean to reorder some parts
2613 for S/MIME's DNs. USERID is a string as returned by the gpgme key
2614 functions. It is utf-8 encoded. */
2615 static void parse_and_print_user_id (FILE * fp, const char *userid)
2620 if (*userid == '<') {
2621 s = strchr (userid + 1, '>');
2623 print_utf8 (fp, userid + 1, s - userid - 1);
2625 else if (*userid == '(')
2626 fputs (_("[Can't display this user ID (unknown encoding)]"), fp);
2627 else if (!digit_or_letter ((const unsigned char *) userid))
2628 fputs (_("[Can't display this user ID (invalid encoding)]"), fp);
2630 struct dn_array_s *dn = parse_dn ((const unsigned char *) userid);
2633 fputs (_("[Can't display this user ID (invalid DN)]"), fp);
2635 print_dn_parts (fp, dn);
2636 for (i = 0; dn[i].key; i++) {
2637 p_delete(&dn[i].key);
2638 p_delete(&dn[i].value);
2646 KEY_CAP_CAN_ENCRYPT,
2651 static unsigned int key_check_cap (gpgme_key_t key, key_cap_t cap)
2653 gpgme_subkey_t subkey = NULL;
2654 unsigned int ret = 0;
2657 case KEY_CAP_CAN_ENCRYPT:
2658 if (!(ret = key->can_encrypt))
2659 for (subkey = key->subkeys; subkey; subkey = subkey->next)
2660 if ((ret = subkey->can_encrypt))
2663 case KEY_CAP_CAN_SIGN:
2664 if (!(ret = key->can_sign))
2665 for (subkey = key->subkeys; subkey; subkey = subkey->next)
2666 if ((ret = subkey->can_sign))
2669 case KEY_CAP_CAN_CERTIFY:
2670 if (!(ret = key->can_certify))
2671 for (subkey = key->subkeys; subkey; subkey = subkey->next)
2672 if ((ret = subkey->can_certify))
2681 /* Print verbose information about a key or certificate to FP. */
2682 static void print_key_info (gpgme_key_t key, FILE * fp)
2685 const char *s = NULL, *s2 = NULL;
2688 char shortbuf[STRING];
2689 unsigned long aval = 0;
2693 gpgme_user_id_t uid = NULL;
2696 setlocale (LC_TIME, Locale);
2698 is_pgp = key->protocol == GPGME_PROTOCOL_OpenPGP;
2700 for (idx = 0, uid = key->uids; uid; idx++, uid = uid->next) {
2705 fputs (idx ? _(" aka ......: ") :_("Name ......: "), fp);
2708 fputs (_("[Invalid]"), fp);
2712 print_utf8 (fp, s, m_strlen(s));
2714 parse_and_print_user_id (fp, s);
2718 if (key->subkeys && (key->subkeys->timestamp > 0)) {
2719 tt = key->subkeys->timestamp;
2721 tm = localtime (&tt);
2722 #ifdef HAVE_LANGINFO_D_T_FMT
2723 strftime (shortbuf, sizeof shortbuf, nl_langinfo (D_T_FMT), tm);
2725 strftime (shortbuf, sizeof shortbuf, "%c", tm);
2727 fprintf (fp, _("Valid From : %s\n"), shortbuf);
2730 if (key->subkeys && (key->subkeys->expires > 0)) {
2731 tt = key->subkeys->expires;
2733 tm = localtime (&tt);
2734 #ifdef HAVE_LANGINFO_D_T_FMT
2735 strftime (shortbuf, sizeof shortbuf, nl_langinfo (D_T_FMT), tm);
2737 strftime (shortbuf, sizeof shortbuf, "%c", tm);
2739 fprintf (fp, _("Valid To ..: %s\n"), shortbuf);
2743 s = gpgme_pubkey_algo_name (key->subkeys->pubkey_algo);
2747 s2 = is_pgp ? "PGP" : "X.509";
2750 aval = key->subkeys->length;
2752 fprintf (fp, _("Key Type ..: %s, %lu bit %s\n"), s2, aval, s);
2754 fprintf (fp, _("Key Usage .: "));
2757 if (key_check_cap (key, KEY_CAP_CAN_ENCRYPT)) {
2758 fprintf (fp, "%s%s", delim, _("encryption"));
2761 if (key_check_cap (key, KEY_CAP_CAN_SIGN)) {
2762 fprintf (fp, "%s%s", delim, _("signing"));
2765 if (key_check_cap (key, KEY_CAP_CAN_CERTIFY)) {
2766 fprintf (fp, "%s%s", delim, _("certification"));
2772 s = key->subkeys->fpr;
2773 fputs (_("Fingerprint: "), fp);
2774 if (is_pgp && m_strlen(s) == 40) {
2775 for (i = 0; *s && s[1] && s[2] && s[3] && s[4]; s += 4, i++) {
2780 putc (is_pgp ? ' ' : ':', fp);
2781 if (is_pgp && i == 4)
2786 for (i = 0; *s && s[1] && s[2]; s += 2, i++) {
2789 putc (is_pgp ? ' ' : ':', fp);
2790 if (is_pgp && i == 7)
2794 fprintf (fp, "%s\n", s);
2797 if (key->issuer_serial) {
2798 s = key->issuer_serial;
2800 fprintf (fp, _("Serial-No .: 0x%s\n"), s);
2803 if (key->issuer_name) {
2804 s = key->issuer_name;
2806 fprintf (fp, _("Issued By .: "));
2807 parse_and_print_user_id (fp, s);
2812 /* For PGP we list all subkeys. */
2814 gpgme_subkey_t subkey = NULL;
2816 for (idx = 1, subkey = key->subkeys; subkey; idx++, subkey = subkey->next) {
2820 if (m_strlen(s) == 16)
2821 s += 8; /* display only the short keyID */
2822 fprintf (fp, _("Subkey ....: 0x%s"), s);
2823 if (subkey->revoked) {
2825 fputs (_("[Revoked]"), fp);
2827 if (subkey->invalid) {
2829 fputs (_("[Invalid]"), fp);
2831 if (subkey->expired) {
2833 fputs (_("[Expired]"), fp);
2835 if (subkey->disabled) {
2837 fputs (_("[Disabled]"), fp);
2841 if (subkey->timestamp > 0) {
2842 tt = subkey->timestamp;
2844 tm = localtime (&tt);
2845 #ifdef HAVE_LANGINFO_D_T_FMT
2846 strftime (shortbuf, sizeof shortbuf, nl_langinfo (D_T_FMT), tm);
2848 strftime (shortbuf, sizeof shortbuf, "%c", tm);
2850 fprintf (fp, _("Valid From : %s\n"), shortbuf);
2853 if (subkey->expires > 0) {
2854 tt = subkey->expires;
2856 tm = localtime (&tt);
2857 #ifdef HAVE_LANGINFO_D_T_FMT
2858 strftime (shortbuf, sizeof shortbuf, nl_langinfo (D_T_FMT), tm);
2860 strftime (shortbuf, sizeof shortbuf, "%c", tm);
2862 fprintf (fp, _("Valid To ..: %s\n"), shortbuf);
2866 s = gpgme_pubkey_algo_name (subkey->pubkey_algo);
2871 aval = subkey->length;
2875 fprintf (fp, _("Key Type ..: %s, %lu bit %s\n"), "PGP", aval, s);
2877 fprintf (fp, _("Key Usage .: "));
2880 if (subkey->can_encrypt) {
2881 fprintf (fp, "%s%s", delim, _("encryption"));
2884 if (subkey->can_sign) {
2885 fprintf (fp, "%s%s", delim, _("signing"));
2888 if (subkey->can_certify) {
2889 fprintf (fp, "%s%s", delim, _("certification"));
2897 setlocale (LC_TIME, "C");
2901 /* Show detailed information about the selected key */
2902 static void verify_key (crypt_key_t * key)
2905 char cmd[LONG_STRING], tempfile[_POSIX_PATH_MAX];
2907 gpgme_ctx_t listctx = NULL;
2909 gpgme_key_t k = NULL;
2912 fp = m_tempfile (tempfile, sizeof(tempfile), NONULL(MCore.tmpdir), NULL);
2914 mutt_perror (_("Can't create temporary file"));
2917 mutt_message _("Collecting data...");
2919 print_key_info (key->kobj, fp);
2921 err = gpgme_new (&listctx);
2923 fprintf (fp, "Internal error: can't create gpgme context: %s\n",
2924 gpgme_strerror (err));
2927 if ((key->flags & KEYFLAG_ISX509))
2928 gpgme_set_protocol (listctx, GPGME_PROTOCOL_CMS);
2932 while ((s = k->chain_id) && k->subkeys && m_strcmp(s, k->subkeys->fpr)) {
2934 err = gpgme_op_keylist_start (listctx, s, 0);
2935 gpgme_key_release (k);
2938 err = gpgme_op_keylist_next (listctx, &k);
2940 fprintf (fp, _("Error finding issuer key: %s\n"), gpgme_strerror (err));
2943 gpgme_op_keylist_end (listctx);
2945 print_key_info (k, fp);
2948 fputs (_("Error: certification chain to long - stopping here\n"), fp);
2954 gpgme_key_release (k);
2955 gpgme_release (listctx);
2957 mutt_clear_error ();
2958 snprintf (cmd, sizeof (cmd), _("Key ID: 0x%s"), crypt_keyid (key));
2959 mutt_do_pager (cmd, tempfile, 0, NULL);
2962 /* Implementation of `findkeys'. */
2964 /* Convert string_list_t into a pattern string suitable to be passed to GPGME.
2965 We need to convert spaces in an item into a '+' and '%' into
2967 static char *list_to_pattern (string_list_t * list)
2975 for (l = list; l; l = l->next) {
2976 for (s = l->data; *s; s++) {
2981 n++; /* delimiter or end of string */
2983 n++; /* make sure to allocate at least one byte */
2984 pattern = p = p_new(char, n);
2985 for (l = list; l; l = l->next) {
2990 for (s = l->data; *s; s++) {
2996 else if (*s == '+') {
3012 /* Return a list of keys which are candidates for the selection.
3013 Select by looking at the HINTS list. */
3014 static crypt_key_t *get_candidates (string_list_t * hints, unsigned int app,
3017 crypt_key_t *db, *k, **kend;
3023 gpgme_user_id_t uid = NULL;
3025 pattern = list_to_pattern (hints);
3029 err = gpgme_new (&ctx);
3031 mutt_error (_("gpgme_new failed: %s"), gpgme_strerror (err));
3039 if ((app & APPLICATION_PGP)) {
3040 /* Its all a mess. That old GPGME expects different things
3041 depending on the protocol. For gpg we don' t need percent
3042 escaped pappert but simple strings passed in an array to the
3043 keylist_ext_start function. */
3048 for (l = hints, n = 0; l; l = l->next) {
3049 if (l->data && *l->data)
3055 patarr = p_new(char *, n + 1);
3056 for (l = hints, n = 0; l; l = l->next) {
3057 if (l->data && *l->data)
3058 patarr[n++] = m_strdup(l->data);
3061 err = gpgme_op_keylist_ext_start (ctx, (const char **) patarr, secret, 0);
3062 for (n = 0; patarr[n]; n++)
3063 p_delete(&patarr[n]);
3066 mutt_error (_("gpgme_op_keylist_start failed: %s"), gpgme_strerror (err));
3067 gpgme_release (ctx);
3072 while (!(err = gpgme_op_keylist_next (ctx, &key))) {
3073 unsigned int flags = 0;
3075 if (key_check_cap (key, KEY_CAP_CAN_ENCRYPT))
3076 flags |= KEYFLAG_CANENCRYPT;
3077 if (key_check_cap (key, KEY_CAP_CAN_SIGN))
3078 flags |= KEYFLAG_CANSIGN;
3080 for (idx = 0, uid = key->uids; uid; idx++, uid = uid->next) {
3081 k = p_new(crypt_key_t, 1);
3090 if (gpg_err_code (err) != GPG_ERR_EOF)
3091 mutt_error (_("gpgme_op_keylist_next failed: %s"), gpgme_strerror (err));
3092 gpgme_op_keylist_end (ctx);
3097 if ((app & APPLICATION_SMIME)) {
3098 /* and now look for x509 certificates */
3099 gpgme_set_protocol (ctx, GPGME_PROTOCOL_CMS);
3100 err = gpgme_op_keylist_start (ctx, pattern, 0);
3102 mutt_error (_("gpgme_op_keylist_start failed: %s"), gpgme_strerror (err));
3103 gpgme_release (ctx);
3108 while (!(err = gpgme_op_keylist_next (ctx, &key))) {
3109 unsigned int flags = KEYFLAG_ISX509;
3111 if (key_check_cap (key, KEY_CAP_CAN_ENCRYPT))
3112 flags |= KEYFLAG_CANENCRYPT;
3113 if (key_check_cap (key, KEY_CAP_CAN_SIGN))
3114 flags |= KEYFLAG_CANSIGN;
3116 for (idx = 0, uid = key->uids; uid; idx++, uid = uid->next) {
3117 k = p_new(crypt_key_t, 1);
3126 if (gpg_err_code (err) != GPG_ERR_EOF)
3127 mutt_error (_("gpgme_op_keylist_next failed: %s"), gpgme_strerror (err));
3128 gpgme_op_keylist_end (ctx);
3131 gpgme_release (ctx);
3136 /* Add the string STR to the list HINTS. This list is later used to
3138 static string_list_t *crypt_add_string_to_hints (string_list_t * hints, const char *str)
3143 if ((scratch = m_strdup(str)) == NULL)
3146 for (t = strtok (scratch, " ,.:\"()<>\n"); t;
3147 t = strtok (NULL, " ,.:\"()<>\n")) {
3148 if (m_strlen(t) > 3)
3149 hints = mutt_add_list(hints, t);
3156 /* Display a menu to select a key from the array KEYS. FORCED_VALID
3157 will be set to true on return if the user did override the the
3159 static crypt_key_t *crypt_select_key (crypt_key_t * keys,
3160 address_t * p, const char *s,
3161 unsigned int app, int *forced_valid)
3164 crypt_key_t **key_table;
3167 char helpstr[STRING], buf[LONG_STRING];
3169 int (*f) (const void *, const void *);
3170 int menu_to_use = 0;
3175 /* build the key table */
3178 for (k = keys; k; k = k->next) {
3179 if (!option (OPTPGPSHOWUNUSABLE) && (k->flags & KEYFLAG_CANTUSE)) {
3186 p_realloc(&key_table, keymax);
3192 if (!i && unusable) {
3193 mutt_error _("All matching keys are marked expired/revoked.");
3199 switch (PgpSortKeys & SORT_MASK) {
3201 f = crypt_compare_date;
3204 f = crypt_compare_keyid;
3207 f = crypt_compare_address;
3211 f = crypt_compare_trust;
3214 qsort (key_table, i, sizeof (crypt_key_t *), f);
3216 if (app & APPLICATION_PGP)
3217 menu_to_use = MENU_KEY_SELECT_PGP;
3218 else if (app & APPLICATION_SMIME)
3219 menu_to_use = MENU_KEY_SELECT_SMIME;
3222 mutt_make_help (buf, sizeof (buf), _("Exit "), menu_to_use, OP_EXIT);
3223 m_strcat(helpstr, sizeof(helpstr), buf);
3224 mutt_make_help (buf, sizeof (buf), _("Select "), menu_to_use,
3225 OP_GENERIC_SELECT_ENTRY);
3226 m_strcat(helpstr, sizeof(helpstr), buf);
3227 mutt_make_help (buf, sizeof (buf), _("Check key "),
3228 menu_to_use, OP_VERIFY_KEY);
3229 m_strcat(helpstr, sizeof(helpstr), buf);
3230 mutt_make_help (buf, sizeof (buf), _("Help"), menu_to_use, OP_HELP);
3231 m_strcat(helpstr, sizeof(helpstr), buf);
3233 menu = mutt_new_menu ();
3235 menu->make_entry = crypt_entry;
3236 menu->menu = menu_to_use;
3237 menu->help = helpstr;
3238 menu->data = key_table;
3243 if ((app & APPLICATION_PGP) && (app & APPLICATION_SMIME))
3244 ts = _("PGP and S/MIME keys matching");
3245 else if ((app & APPLICATION_PGP))
3246 ts = _("PGP keys matching");
3247 else if ((app & APPLICATION_SMIME))
3248 ts = _("S/MIME keys matching");
3250 ts = _("keys matching");
3253 snprintf (buf, sizeof (buf), _("%s <%s>."), ts, p->mailbox);
3255 snprintf (buf, sizeof (buf), _("%s \"%s\"."), ts, s);
3259 mutt_clear_error ();
3263 switch (mutt_menuLoop (menu)) {
3265 verify_key (key_table[menu->current]);
3266 menu->redraw = REDRAW_FULL;
3270 mutt_message ("%s", key_table[menu->current]->uid);
3273 case OP_GENERIC_SELECT_ENTRY:
3274 /* FIXME make error reporting more verbose - this should be
3275 easy because gpgme provides more information */
3276 if (option (OPTPGPCHECKTRUST)) {
3277 if (!crypt_key_is_valid (key_table[menu->current])) {
3278 mutt_error _("This key can't be used: "
3279 "expired/disabled/revoked.");
3284 if (option (OPTPGPCHECKTRUST) &&
3285 (!crypt_id_is_valid (key_table[menu->current])
3286 || !crypt_id_is_strong (key_table[menu->current]))) {
3288 char buff[LONG_STRING];
3290 if (key_table[menu->current]->flags & KEYFLAG_CANTUSE)
3291 s = N_("ID is expired/disabled/revoked.");
3293 gpgme_validity_t val = GPGME_VALIDITY_UNKNOWN;
3294 gpgme_user_id_t uid = NULL;
3299 uid = key_table[menu->current]->kobj->uids;
3300 for (j = 0; (j < key_table[menu->current]->idx) && uid;
3301 j++, uid = uid->next);
3303 val = uid->validity;
3306 case GPGME_VALIDITY_UNKNOWN:
3307 case GPGME_VALIDITY_UNDEFINED:
3308 warn_s = N_("ID has undefined validity.");
3310 case GPGME_VALIDITY_NEVER:
3311 warn_s = N_("ID is not valid.");
3313 case GPGME_VALIDITY_MARGINAL:
3314 warn_s = N_("ID is only marginally valid.");
3316 case GPGME_VALIDITY_FULL:
3317 case GPGME_VALIDITY_ULTIMATE:
3321 snprintf (buff, sizeof (buff),
3322 _("%s Do you really want to use the key?"), _(warn_s));
3324 if (mutt_yesorno (buff, 0) != 1) {
3325 mutt_clear_error ();
3332 k = crypt_copy_key (key_table[menu->current]);
3343 mutt_menuDestroy (&menu);
3344 p_delete(&key_table);
3346 set_option (OPTNEEDREDRAW);
3351 static crypt_key_t *crypt_getkeybyaddr (address_t * a, short abilities,
3352 unsigned int app, int *forced_valid)
3355 string_list_t *hints = NULL;
3360 int this_key_has_strong;
3361 int this_key_has_weak;
3362 int this_key_has_invalid;
3365 crypt_key_t *keys, *k;
3366 crypt_key_t *the_valid_key = NULL;
3367 crypt_key_t *matches = NULL;
3368 crypt_key_t **matches_endp = &matches;
3372 if (a && a->mailbox)
3373 hints = crypt_add_string_to_hints (hints, a->mailbox);
3374 if (a && a->personal)
3375 hints = crypt_add_string_to_hints (hints, a->personal);
3377 mutt_message (_("Looking for keys matching \"%s\"..."), a->mailbox);
3378 keys = get_candidates (hints, app, (abilities & KEYFLAG_CANSIGN));
3380 string_list_wipe(&hints);
3385 for (k = keys; k; k = k->next) {
3386 if (abilities && !(k->flags & abilities)) {
3390 this_key_has_weak = 0; /* weak but valid match */
3391 this_key_has_invalid = 0; /* invalid match */
3392 this_key_has_strong = 0; /* strong and valid match */
3393 match = 0; /* any match */
3395 r = rfc822_parse_adrlist (NULL, k->uid);
3396 for (p = r; p; p = p->next) {
3397 int validity = crypt_id_matches_addr (a, p, k);
3399 if (validity & CRYPT_KV_MATCH) /* something matches */
3402 /* is this key a strong candidate? */
3403 if ((validity & CRYPT_KV_VALID)
3404 && (validity & CRYPT_KV_STRONGID)
3405 && (validity & CRYPT_KV_ADDR)) {
3406 if (the_valid_key && the_valid_key != k)
3409 this_key_has_strong = 1;
3411 else if ((validity & CRYPT_KV_MATCH)
3412 && !(validity & CRYPT_KV_VALID))
3413 this_key_has_invalid = 1;
3414 else if ((validity & CRYPT_KV_MATCH)
3415 && (!(validity & CRYPT_KV_STRONGID)
3416 || !(validity & CRYPT_KV_ADDR)))
3417 this_key_has_weak = 1;
3419 address_list_wipe(&r);
3424 if (!this_key_has_strong && this_key_has_invalid)
3426 if (!this_key_has_strong && this_key_has_weak)
3429 *matches_endp = tmp = crypt_copy_key (k);
3430 matches_endp = &tmp->next;
3431 the_valid_key = tmp;
3435 crypt_free_key (&keys);
3438 if (the_valid_key && !multi && !weak
3439 && !(invalid && option (OPTPGPSHOWUNUSABLE))) {
3441 * There was precisely one strong match on a valid ID, there
3442 * were no valid keys with weak matches, and we aren't
3443 * interested in seeing invalid keys.
3445 * Proceed without asking the user.
3447 k = crypt_copy_key (the_valid_key);
3451 * Else: Ask the user.
3453 k = crypt_select_key (matches, a, NULL, app, forced_valid);
3455 crypt_free_key (&matches);
3464 static crypt_key_t *crypt_getkeybystr (const char *p, short abilities,
3465 unsigned int app, int *forced_valid)
3467 string_list_t *hints = NULL;
3469 crypt_key_t *matches = NULL;
3470 crypt_key_t **matches_endp = &matches;
3474 mutt_message (_("Looking for keys matching \"%s\"..."), p);
3478 hints = crypt_add_string_to_hints (hints, p);
3479 keys = get_candidates (hints, app, (abilities & KEYFLAG_CANSIGN));
3480 string_list_wipe(&hints);
3485 for (k = keys; k; k = k->next) {
3486 if (abilities && !(k->flags & abilities))
3491 if (!*p || !m_strcasecmp(p, crypt_keyid (k))
3492 || (!m_strncasecmp(p, "0x", 2)
3493 && !m_strcasecmp(p + 2, crypt_keyid (k)))
3494 || (option (OPTPGPLONGIDS)
3495 && !m_strncasecmp(p, "0x", 2)
3496 && !m_strcasecmp(p + 2, crypt_keyid (k) + 8))
3497 || m_stristr(k->uid, p)) {
3500 *matches_endp = tmp = crypt_copy_key (k);
3501 matches_endp = &tmp->next;
3505 crypt_free_key (&keys);
3508 k = crypt_select_key (matches, NULL, p, app, forced_valid);
3509 crypt_free_key (&matches);
3516 /* Display TAG as a prompt to ask for a key. If WHATFOR is not null
3517 use it as default and store it under that label as the next
3518 default. ABILITIES describe the required key abilities (sign,
3519 encrypt) and APP the type of the requested key; ether S/MIME or
3520 PGP. Return a copy of the key or NULL if not found. */
3521 static crypt_key_t *crypt_ask_for_key (char *tag,
3524 unsigned int app, int *forced_valid)
3528 struct crypt_cache *l = NULL;
3532 forced_valid = &dummy;
3534 mutt_clear_error ();
3540 for (l = id_defaults; l; l = l->next)
3541 if (!m_strcasecmp(whatfor, l->what)) {
3542 m_strcpy(resp, sizeof(resp), NONULL(l->dflt));
3550 if (mutt_get_field (tag, resp, sizeof (resp), M_CLEAR) != 0)
3555 m_strreplace(&l->dflt, resp);
3557 l = p_new(struct crypt_cache, 1);
3558 l->next = id_defaults;
3560 l->what = m_strdup(whatfor);
3561 l->dflt = m_strdup(resp);
3565 if ((key = crypt_getkeybystr (resp, abilities, app, forced_valid)))
3573 /* This routine attempts to find the keyids of the recipients of a
3574 message. It returns NULL if any of the keys can not be found. */
3575 static char *find_keys (address_t * to, address_t * cc, address_t * bcc,
3578 char *keylist = NULL, *t;
3580 ssize_t keylist_size = 0;
3581 ssize_t keylist_used = 0;
3582 address_t *tmp = NULL, *addr = NULL;
3583 address_t **last = &tmp;
3586 crypt_key_t *k_info, *key;
3587 const char *fqdn = mutt_fqdn (1);
3590 *r_application = APPLICATION_PGP | APPLICATION_SMIME;
3593 for (i = 0; i < 3; i++) {
3608 *last = address_list_dup (p);
3610 last = &((*last)->next);
3613 rfc822_qualify(tmp, fqdn);
3614 address_list_uniq(tmp);
3616 for (p = tmp; p; p = p->next) {
3617 char buf[LONG_STRING];
3618 int forced_valid = 0;
3623 if ((keyID = mutt_crypt_hook (p)) != NULL) {
3626 snprintf (buf, sizeof (buf), _("Use keyID = \"%s\" for %s?"),
3628 if ((r = mutt_yesorno (buf, M_YES)) == M_YES) {
3629 /* check for e-mail address */
3630 if ((t = strchr (keyID, '@')) &&
3631 (addr = rfc822_parse_adrlist (NULL, keyID))) {
3632 rfc822_qualify(addr, fqdn);
3636 k_info = crypt_getkeybystr (keyID, KEYFLAG_CANENCRYPT,
3637 app, &forced_valid);
3642 address_list_wipe(&tmp);
3643 address_list_wipe(&addr);
3649 && (k_info = crypt_getkeybyaddr (q, KEYFLAG_CANENCRYPT,
3650 app, &forced_valid)) == NULL) {
3651 snprintf (buf, sizeof (buf), _("Enter keyID for %s: "), q->mailbox);
3653 if ((key = crypt_ask_for_key (buf, q->mailbox, KEYFLAG_CANENCRYPT,
3655 &forced_valid)) == NULL) {
3657 address_list_wipe(&tmp);
3658 address_list_wipe(&addr);
3666 const char *s = crypt_fpr (key);
3668 keylist_size += m_strlen(s) + 4 + 1;
3669 p_realloc(&keylist, keylist_size);
3670 sprintf (keylist + keylist_used, "%s0x%s%s",
3671 keylist_used ? " " : "", s, forced_valid ? "!" : "");
3673 keylist_used = m_strlen(keylist);
3675 crypt_free_key (&key);
3676 address_list_wipe(&addr);
3678 address_list_wipe(&tmp);
3682 int crypt_get_keys (HEADER * msg, char **keylist)
3684 /* Do a quick check to make sure that we can find all of the encryption
3685 * keys if the user has requested this service.
3690 if (msg->security & ENCRYPT) {
3691 if (msg->security & APPLICATION_PGP) {
3692 set_option(OPTPGPCHECKTRUST);
3693 *keylist = find_keys(msg->env->to, msg->env->cc, msg->env->bcc,
3695 unset_option(OPTPGPCHECKTRUST);
3700 if (msg->security & APPLICATION_SMIME) {
3701 *keylist = find_keys(msg->env->to, msg->env->cc, msg->env->bcc,
3712 int crypt_send_menu (HEADER * msg, int *redraw, int is_smime)
3715 char input_signas[STRING];
3718 if (msg->security & APPLICATION_PGP)
3720 else if (msg->security & APPLICATION_SMIME)
3725 mutt_multi_choice (_
3726 ("S/MIME (e)ncrypt, (s)ign, sign (a)s, (b)oth, (p)gp or (c)lear?"),
3730 mutt_multi_choice (_
3731 ("PGP (e)ncrypt, (s)ign, sign (a)s, (b)oth, s/(m)ime or (c)lear?"),
3735 case 1: /* (e)ncrypt */
3736 msg->security |= (is_smime ? SMIMEENCRYPT : PGPENCRYPT);
3737 msg->security &= ~(is_smime ? SMIMESIGN : PGPSIGN);
3740 case 2: /* (s)ign */
3741 msg->security |= (is_smime ? SMIMESIGN : PGPSIGN);
3742 msg->security &= ~(is_smime ? SMIMEENCRYPT : PGPENCRYPT);
3745 case 3: /* sign (a)s */
3746 if ((p = crypt_ask_for_key (_("Sign as: "), NULL, KEYFLAG_CANSIGN,
3747 is_smime ? APPLICATION_SMIME :
3748 APPLICATION_PGP, NULL))) {
3749 snprintf (input_signas, sizeof (input_signas), "0x%s", crypt_keyid (p));
3750 m_strreplace(is_smime ? &SmimeDefaultKey : &PgpSignAs,
3752 crypt_free_key (&p);
3754 msg->security |= (is_smime ? SMIMESIGN : PGPSIGN);
3756 *redraw = REDRAW_FULL;
3759 case 4: /* (b)oth */
3761 (is_smime ? (SMIMEENCRYPT | SMIMESIGN) : (PGPENCRYPT | PGPSIGN));
3764 case 5: /* (p)gp or s/(m)ime */
3765 is_smime = !is_smime;
3768 case 6: /* (c)lear */
3769 return msg->security = 0;
3773 msg->security &= ~APPLICATION_PGP;
3774 msg->security |= APPLICATION_SMIME;
3776 msg->security &= ~APPLICATION_SMIME;
3777 msg->security |= APPLICATION_PGP;
3780 return msg->security;
3783 int crypt_smime_verify_sender (HEADER * h)
3785 address_t *sender = NULL;
3786 unsigned int ret = 1;
3789 h->env->from = mutt_expand_aliases (h->env->from);
3790 sender = h->env->from;
3792 else if (h->env->sender) {
3793 h->env->sender = mutt_expand_aliases (h->env->sender);
3794 sender = h->env->sender;
3798 if (signature_key) {
3799 gpgme_key_t key = signature_key;
3800 gpgme_user_id_t uid = NULL;
3801 int sender_length = 0;
3804 sender_length = m_strlen(sender->mailbox);
3805 for (uid = key->uids; uid && ret; uid = uid->next) {
3806 uid_length = m_strlen(uid->email);
3807 if (1 && (uid->email[0] == '<')
3808 && (uid->email[uid_length - 1] == '>')
3809 && (uid_length == sender_length + 2)
3810 && (!m_strncmp (uid->email + 1, sender->mailbox, sender_length)))
3815 mutt_any_key_to_continue ("Failed to verify sender");
3818 mutt_any_key_to_continue ("Failed to figure out sender");
3820 if (signature_key) {
3821 gpgme_key_release (signature_key);
3822 signature_key = NULL;
3828 void crypt_invoke_import(FILE *stream, int smime)
3830 gpgme_ctx_t ctx = create_gpgme_context(smime);
3834 err = gpgme_data_new_from_stream(&data, stream);
3836 mutt_error (_("error allocating data object: %s\n"), gpgme_strerror (err));
3841 err = gpgme_op_import(ctx, data);
3843 mutt_error(_("error importing gpg data: %s\n"), gpgme_strerror(err));
3844 gpgme_data_release(data);
3849 gpgme_data_release(data);
3854 static void pgp_extract_keys_from_attachment(FILE * fp, BODY * top)
3857 FILE *tmpfp = tmpfile();
3859 if (tmpfp == NULL) {
3860 mutt_perror (_("Can't create temporary file"));
3867 mutt_body_handler(top, &s);
3870 crypt_invoke_import(tmpfp, 0);
3874 void crypt_pgp_extract_keys_from_attachment_list(FILE * fp, int tag, BODY * top)
3877 set_option (OPTDONTHANDLEPGPKEYS);
3879 for (; top; top = top->next) {
3880 if (!tag || top->tagged)
3881 pgp_extract_keys_from_attachment (fp, top);
3887 unset_option (OPTDONTHANDLEPGPKEYS);
3893 /* fixme: needs documentation. */
3894 void crypt_pgp_invoke_getkeys (address_t * addr)
3898 /* Generate a PGP public key attachment. */
3899 BODY *crypt_pgp_make_key_attachment (char *tempf)
3906 /* fixme: Needs documentation. */
3907 void crypt_smime_getkeys (ENVELOPE * env)
3911 /***************************************************************************/
3913 void crypt_invoke_message (int type)
3915 if (type & APPLICATION_PGP) {
3916 mutt_message _("Invoking PGP...");
3918 else if (type & APPLICATION_SMIME) {
3919 mutt_message _("Invoking S/MIME...");
3923 int mutt_protect (HEADER * msg, char *keylist)
3925 BODY *pbody = NULL, *tmp_pbody = NULL;
3926 BODY *tmp_smime_pbody = NULL;
3927 BODY *tmp_pgp_pbody = NULL;
3928 int flags = msg->security;
3933 tmp_smime_pbody = msg->content;
3934 tmp_pgp_pbody = msg->content;
3936 if (msg->security & SIGN) {
3937 if (msg->security & APPLICATION_SMIME) {
3938 if (!(tmp_pbody = crypt_smime_sign_message (msg->content)))
3940 pbody = tmp_smime_pbody = tmp_pbody;
3943 if ((msg->security & APPLICATION_PGP)
3944 && (!(flags & ENCRYPT) || option (OPTPGPRETAINABLESIG))) {
3945 if (!(tmp_pbody = crypt_pgp_sign_message (msg->content)))
3949 pbody = tmp_pgp_pbody = tmp_pbody;
3952 if ((msg->security & APPLICATION_SMIME)
3953 && (msg->security & APPLICATION_PGP)) {
3954 /* here comes the draft ;-) */
3959 if (msg->security & ENCRYPT) {
3960 if ((msg->security & APPLICATION_SMIME)) {
3961 if (!(tmp_pbody = crypt_smime_build_smime_entity (tmp_smime_pbody,
3963 /* signed ? free it! */
3966 /* free tmp_body if messages was signed AND encrypted ... */
3967 if (tmp_smime_pbody != msg->content && tmp_smime_pbody != tmp_pbody) {
3968 /* detatch and dont't delete msg->content,
3969 which tmp_smime_pbody->parts after signing. */
3970 tmp_smime_pbody->parts = tmp_smime_pbody->parts->next;
3971 msg->content->next = NULL;
3972 body_list_wipe(&tmp_smime_pbody);
3977 if ((msg->security & APPLICATION_PGP)) {
3978 if (!(pbody = crypt_pgp_encrypt_message (tmp_pgp_pbody, keylist,
3981 /* did we perform a retainable signature? */
3982 if (flags != msg->security) {
3983 /* remove the outer multipart layer */
3984 tmp_pgp_pbody = mutt_remove_multipart (tmp_pgp_pbody);
3985 /* get rid of the signature */
3986 body_list_wipe(&tmp_pgp_pbody->next);
3992 /* destroy temporary signature envelope when doing retainable
3996 if (flags != msg->security) {
3997 tmp_pgp_pbody = mutt_remove_multipart (tmp_pgp_pbody);
3998 body_list_wipe(&tmp_pgp_pbody->next);
4004 msg->content = pbody;
4010 int crypt_query (BODY * m)
4017 if (m->type == TYPEAPPLICATION) {
4018 t |= mutt_is_application_pgp (m);
4020 t |= mutt_is_application_smime (m);
4021 if (t && m->goodsig)
4026 else if (m->type == TYPETEXT) {
4027 t |= mutt_is_application_pgp (m);
4028 if (t && m->goodsig)
4032 if (m->type == TYPEMULTIPART) {
4033 t |= mutt_is_multipart_encrypted (m);
4034 t |= mutt_is_multipart_signed (m);
4036 if (t && m->goodsig)
4040 if (m->type == TYPEMULTIPART || m->type == TYPEMESSAGE) {
4044 u = m->parts ? ~0 : 0; /* Bits set in all parts */
4045 w = 0; /* Bits set in any part */
4047 for (p = m->parts; p; p = p->next) {
4048 v = crypt_query (p);
4052 t |= u | (w & ~GOODSIGN);
4054 if ((w & GOODSIGN) && !(u & GOODSIGN))
4062 static void crypt_write_signed(BODY * a, STATE * s, FILE *fp)
4068 fseeko (s->fpin, a->hdr_offset, 0);
4069 bytes = a->length + a->offset - a->hdr_offset;
4072 if ((c = fgetc (s->fpin)) == EOF)
4080 if (c == '\n' && !hadcr)
4091 void convert_to_7bit (BODY * a)
4094 if (a->type == TYPEMULTIPART) {
4095 if (a->encoding != ENC7BIT) {
4096 a->encoding = ENC7BIT;
4097 convert_to_7bit (a->parts);
4099 convert_to_7bit (a->parts);
4102 else if (a->type == TYPEMESSAGE &&
4103 m_strcasecmp(a->subtype, "delivery-status")) {
4104 if (a->encoding != ENC7BIT)
4105 mutt_message_to_7bit (a, NULL);
4107 else if (a->encoding == ENC8BIT)
4108 a->encoding = ENCQUOTEDPRINTABLE;
4109 else if (a->encoding == ENCBINARY)
4110 a->encoding = ENCBASE64;
4111 else if (a->content && a->encoding != ENCBASE64 &&
4112 (a->content->from || a->content->space))
4113 a->encoding = ENCQUOTEDPRINTABLE;
4119 static void extract_keys_aux(FILE *fpout, HEADER *h)
4121 mutt_parse_mime_message (Context, h);
4124 if (h->security & APPLICATION_PGP) {
4125 mutt_copy_message(fpout, Context, h, M_CM_DECODE | M_CM_CHARCONV, 0);
4128 mutt_endwin (_("Trying to extract PGP keys...\n"));
4131 if (h->security & APPLICATION_SMIME) {
4132 if (h->security & ENCRYPT)
4133 mutt_copy_message (fpout, Context, h, M_CM_NOHEADER
4134 | M_CM_DECODE_CRYPT | M_CM_DECODE_SMIME, 0);
4136 mutt_copy_message(fpout, Context, h, 0, 0);
4139 mutt_message (_("Trying to extract S/MIME certificates...\n"));
4143 crypt_invoke_import(fpout, h->security & APPLICATION_SMIME);
4146 void crypt_extract_keys_from_messages(HEADER * h)
4148 FILE *tmpfp = tmpfile();
4150 mutt_error(_("Could not create temporary file"));
4154 set_option(OPTDONTHANDLEPGPKEYS);
4157 for (i = 0; i < Context->vcount; i++) {
4158 if (!Context->hdrs[Context->v2r[i]]->tagged)
4160 extract_keys_aux(tmpfp, Context->hdrs[Context->v2r[i]]);
4163 extract_keys_aux(tmpfp, h);
4165 unset_option(OPTDONTHANDLEPGPKEYS);
4169 mutt_any_key_to_continue(NULL);
4174 static void crypt_fetch_signatures (BODY ***signatures, BODY * a, int *n)
4176 for (; a; a = a->next) {
4177 if (a->type == TYPEMULTIPART)
4178 crypt_fetch_signatures (signatures, a->parts, n);
4181 p_realloc(signatures, *n + 6);
4183 (*signatures)[(*n)++] = a;
4190 * This routine verifies a "multipart/signed" body.
4193 int mutt_signed_handler (BODY * a, STATE * s)
4195 unsigned major, minor;
4197 int rc, i, goodsig = 1, sigcnt = 0;
4200 protocol = parameter_getval(a->parameter, "protocol");
4203 switch (mime_which_token(protocol, -1)) {
4204 case MIME_APPLICATION_PGP_SIGNATURE:
4205 major = TYPEAPPLICATION;
4206 minor = MIME_PGP_SIGNATURE;
4208 case MIME_APPLICATION_X_PKCS7_SIGNATURE:
4209 major = TYPEAPPLICATION;
4210 minor = MIME_X_PKCS7_SIGNATURE;
4212 case MIME_APPLICATION_PKCS7_SIGNATURE:
4213 major = TYPEAPPLICATION;
4214 minor = MIME_PKCS7_SIGNATURE;
4216 case MIME_MULTIPART_MIXED:
4217 major = TYPEMULTIPART;
4222 state_printf(s, _("[-- Error: "
4223 "Unknown multipart/signed protocol %s! --]\n\n"),
4225 return mutt_body_handler (a, s);
4228 /* consistency check */
4229 if (!(a && a->next && a->next->type == major &&
4230 mime_which_token(a->next->subtype, -1) == minor))
4232 state_attach_puts(_("[-- Error: "
4233 "Inconsistent multipart/signed structure! --]\n\n"),
4235 return mutt_body_handler (a, s);
4238 if (s->flags & M_DISPLAY) {
4241 crypt_fetch_signatures (&sigs, a->next, &sigcnt);
4243 FILE *tmpfp = tmpfile();
4246 mutt_error(_("Could not create temporary file"));
4248 crypt_write_signed(a, s, tmpfp);
4250 for (i = 0; i < sigcnt; i++) {
4251 if (sigs[i]->type == TYPEAPPLICATION) {
4254 switch ((subtype = mime_which_token(sigs[i]->subtype, -1))) {
4255 case MIME_PGP_SIGNATURE:
4256 case MIME_X_PKCS7_SIGNATURE:
4257 case MIME_PKCS7_SIGNATURE:
4258 if (crypt_verify_one(sigs[i], s, tmpfp, subtype != MIME_PGP_SIGNATURE) != 0)
4269 state_printf(s, _("[-- Warning: "
4270 "We can't verify %s/%s signatures. --]\n\n"),
4271 TYPE (sigs[i]), sigs[i]->subtype);
4275 b->goodsig = goodsig;
4276 b->badsig = !goodsig;
4278 /* Now display the signed body */
4279 state_attach_puts(_("[-- The following data is signed --]\n\n"), s);
4283 state_attach_puts(_("[-- Warning: Can't find any signatures. --]\n\n"),
4288 rc = mutt_body_handler (a, s);
4290 if (s->flags & M_DISPLAY && sigcnt)
4291 state_attach_puts (_("\n[-- End of signed data --]\n"), s);