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 static void convert_to_7bit (BODY * a)
82 if (a->type == TYPEMULTIPART) {
83 if (a->encoding != ENC7BIT) {
84 a->encoding = ENC7BIT;
85 convert_to_7bit (a->parts);
87 convert_to_7bit (a->parts);
90 else if (a->type == TYPEMESSAGE &&
91 m_strcasecmp(a->subtype, "delivery-status")) {
92 if (a->encoding != ENC7BIT)
93 mutt_message_to_7bit (a, NULL);
95 else if (a->encoding == ENC8BIT)
96 a->encoding = ENCQUOTEDPRINTABLE;
97 else if (a->encoding == ENCBINARY)
98 a->encoding = ENCBASE64;
99 else if (a->content && a->encoding != ENCBASE64 &&
100 (a->content->from || a->content->space))
101 a->encoding = ENCQUOTEDPRINTABLE;
107 /* return true when S points to a didgit or letter. */
108 static int digit_or_letter (const unsigned char *s)
110 return ((*s >= '0' && *s <= '9')
111 || (*s >= 'A' && *s <= 'Z')
112 || (*s >= 'a' && *s <= 'z'));
116 /* Print the utf-8 encoded string BUF of length LEN bytes to stream
117 FP. Convert the character set. */
118 static void print_utf8 (FILE * fp, const char *buf, ssize_t len)
122 tstr = p_dupstr(buf, len);
123 mutt_convert_string (&tstr, "utf-8", MCharset.charset, M_ICONV_HOOK_FROM);
133 /* Return the keyID for the key K. Note that this string is valid as
134 long as K is valid */
135 static const char *crypt_keyid (crypt_key_t * k)
137 const char *s = "????????";
139 if (k->kobj && k->kobj->subkeys) {
140 s = k->kobj->subkeys->keyid;
141 if ((!option (OPTPGPLONGIDS)) && (m_strlen(s) == 16))
142 /* Return only the short keyID. */
149 /* Return the hexstring fingerprint from the key K. */
150 static const char *crypt_fpr (crypt_key_t * k)
154 if (k->kobj && k->kobj->subkeys)
155 s = k->kobj->subkeys->fpr;
160 /* Parse FLAGS and return a statically allocated(!) string with them. */
161 static char *crypt_key_abilities (int flags)
165 if (!(flags & KEYFLAG_CANENCRYPT))
167 else if (flags & KEYFLAG_PREFER_SIGNING)
172 if (!(flags & KEYFLAG_CANSIGN))
174 else if (flags & KEYFLAG_PREFER_ENCRYPTION)
184 /* Parse FLAGS and return a character describing the most important flag. */
185 static char crypt_flags (int flags)
187 if (flags & KEYFLAG_REVOKED)
189 else if (flags & KEYFLAG_EXPIRED)
191 else if (flags & KEYFLAG_DISABLED)
193 else if (flags & KEYFLAG_CRITICAL)
199 /* Return a copy of KEY. */
200 static crypt_key_t *crypt_copy_key (crypt_key_t *key)
204 k = p_new(crypt_key_t, 1);
206 gpgme_key_ref (key->kobj);
209 k->flags = key->flags;
214 /* Release all the keys at the address of KEYLIST and set the address
216 static void crypt_free_key (crypt_key_t ** keylist)
219 crypt_key_t *k = (*keylist)->next;
226 /* Return trute when key K is valid. */
227 static int crypt_key_is_valid (crypt_key_t * k)
229 if (k->flags & KEYFLAG_CANTUSE)
234 /* Return true whe validity of KEY is sufficient. */
235 static int crypt_id_is_strong (crypt_key_t * key)
237 gpgme_validity_t val = GPGME_VALIDITY_UNKNOWN;
238 gpgme_user_id_t uid = NULL;
242 if ((key->flags & KEYFLAG_ISX509))
245 for (i = 0, uid = key->kobj->uids; (i < key->idx) && uid;
246 i++, uid = uid->next);
251 case GPGME_VALIDITY_UNKNOWN:
252 case GPGME_VALIDITY_UNDEFINED:
253 case GPGME_VALIDITY_NEVER:
254 case GPGME_VALIDITY_MARGINAL:
258 case GPGME_VALIDITY_FULL:
259 case GPGME_VALIDITY_ULTIMATE:
267 /* Return true when the KEY is valid, i.e. not marked as unusable. */
268 static int crypt_id_is_valid (crypt_key_t * key)
270 return !(key->flags & KEYFLAG_CANTUSE);
273 /* Return a bit vector describing how well the addresses ADDR and
274 U_ADDR match and whether KEY is valid. */
275 static int crypt_id_matches_addr (address_t * addr, address_t * u_addr,
280 if (crypt_id_is_valid (key))
281 rv |= CRYPT_KV_VALID;
283 if (crypt_id_is_strong (key))
284 rv |= CRYPT_KV_STRONGID;
286 if (addr->mailbox && u_addr->mailbox
287 && m_strcasecmp(addr->mailbox, u_addr->mailbox) == 0)
290 if (addr->personal && u_addr->personal
291 && m_strcasecmp(addr->personal, u_addr->personal) == 0)
292 rv |= CRYPT_KV_STRING;
299 * GPGME convenient functions.
302 /* Create a new gpgme context and return it. With FOR_SMIME set to
303 true, the protocol of the context is set to CMS. */
304 static gpgme_ctx_t create_gpgme_context (int for_smime)
309 err = gpgme_new (&ctx);
311 mutt_error (_("error creating gpgme context: %s\n"), gpgme_strerror (err));
317 err = gpgme_set_protocol (ctx, GPGME_PROTOCOL_CMS);
319 mutt_error (_("error enabling CMS protocol: %s\n"), gpgme_strerror (err));
328 /* Create a new gpgme data object. This is a wrapper to die on
330 static gpgme_data_t create_gpgme_data (void)
335 err = gpgme_data_new (&data);
337 mutt_error (_("error creating gpgme data object: %s\n"),
338 gpgme_strerror (err));
345 /* Create a new GPGME Data object from the mail body A. With CONVERT
346 passed as true, the lines are converted to CR,LF if required.
347 Return NULL on error or the gpgme_data_t object on success. */
348 static gpgme_data_t body_to_data_object (BODY * a, int convert)
350 char tempfile[_POSIX_PATH_MAX];
355 fptmp = m_tempfile(tempfile, sizeof(tempfile), NONULL(MCore.tmpdir), NULL);
357 mutt_perror (_("Can't create temporary file"));
361 mutt_write_mime_header (a, fptmp);
363 mutt_write_mime_body (a, fptmp);
367 unsigned char buf[1];
369 data = create_gpgme_data ();
371 while ((c = fgetc (fptmp)) != EOF) {
375 if (c == '\n' && !hadcr) {
377 gpgme_data_write (data, buf, 1);
382 /* FIXME: This is quite suboptimal */
384 gpgme_data_write (data, buf, 1);
386 gpgme_data_seek (data, 0, SEEK_SET);
388 err = gpgme_data_new_from_file (&data, tempfile, 1);
393 mutt_error (_("error allocating data object: %s\n"), gpgme_strerror (err));
400 /* Create a GPGME data object from the stream FP but limit the object
401 to LENGTH bytes starting at OFFSET bytes from the beginning of the
403 static gpgme_data_t file_to_data_object (FILE * fp, long offset, long length)
408 err = gpgme_data_new_from_filepart (&data, NULL, fp, offset, length);
410 mutt_error (_("error allocating data object: %s\n"), gpgme_strerror (err));
417 /* Write a GPGME data object to the stream FP. */
418 static int data_object_to_stream (gpgme_data_t data, FILE * fp)
424 err = ((gpgme_data_seek (data, 0, SEEK_SET) == -1)
425 ? gpgme_error_from_errno (errno) : 0);
427 mutt_error (_("error rewinding data object: %s\n"), gpgme_strerror (err));
431 while ((nread = gpgme_data_read (data, buf, sizeof (buf)))) {
432 /* fixme: we are not really converting CRLF to LF but just
433 skipping CR. Doing it correctly needs a more complex logic */
434 for (p = buf; nread; p++, nread--) {
440 mutt_perror ("[tempfile]");
445 mutt_error (_("error reading data object: %s\n"), strerror (errno));
451 /* Copy a data object to a newly created temporay file and return that
452 filename. Caller must free. With RET_FP not NULL, don't close the
453 stream but return it there. */
454 static char *data_object_to_tempfile (gpgme_data_t data, FILE ** ret_fp)
457 char tempfile[_POSIX_PATH_MAX];
461 fp = m_tempfile(tempfile, sizeof(tempfile), NONULL(MCore.tmpdir), NULL);
463 mutt_perror (_("Can't create temporary file"));
467 err = ((gpgme_data_seek (data, 0, SEEK_SET) == -1)
468 ? gpgme_error_from_errno (errno) : 0);
472 while ((nread = gpgme_data_read (data, buf, sizeof (buf)))) {
473 if (fwrite (buf, nread, 1, fp) != 1) {
474 mutt_perror (_("Can't create temporary file"));
486 mutt_error (_("error reading data object: %s\n"), gpgme_strerror (err));
493 return m_strdup(tempfile);
497 /* FIXME: stolen from gpgme to avoid "ambiguous identity" errors */
499 gpgme_get_key2 (gpgme_ctx_t ctx, const char *fpr, gpgme_key_t *r_key,
505 if (!ctx || !r_key || !fpr)
506 return gpg_error (GPG_ERR_INV_VALUE);
508 if (strlen (fpr) < 8) /* We have at least a key ID. */
509 return gpg_error (GPG_ERR_INV_VALUE);
511 /* FIXME: We use our own context because we have to avoid the user's
512 I/O callback handlers. */
513 err = gpgme_new (&listctx);
516 gpgme_set_protocol (listctx, gpgme_get_protocol (ctx));
517 err = gpgme_op_keylist_start (listctx, fpr, secret);
519 err = gpgme_op_keylist_next (listctx, r_key);
520 gpgme_release (listctx);
524 /* Create a GpgmeRecipientSet from the keys in the string KEYLIST.
525 The keys must be space delimited. */
526 static gpgme_key_t *create_recipient_set (const char *keylist,
527 gpgme_protocol_t protocol)
533 gpgme_key_t *rset = NULL;
534 unsigned int rset_n = 0;
535 gpgme_key_t key = NULL;
536 gpgme_ctx_t context = NULL;
538 err = gpgme_new (&context);
540 err = gpgme_set_protocol (context, protocol);
547 for (i = 0; *s && *s != ' ' && i < ssizeof(buf) - 1;)
551 if (i > 1 && buf[i - 1] == '!') {
552 /* The user selected to override the valididy of that
556 err = gpgme_get_key2 (context, buf, &key, 0);
558 key->uids->validity = GPGME_VALIDITY_FULL;
562 err = gpgme_get_key2 (context, buf, &key, 0);
565 p_realloc(&rset, rset_n + 1);
566 rset[rset_n++] = key;
569 mutt_error (_("error adding recipient `%s': %s\n"),
570 buf, gpgme_strerror (err));
578 /* NULL terminate. */
579 p_realloc(&rset, rset_n + 1);
580 rset[rset_n++] = NULL;
583 gpgme_release (context);
589 /* Make sure that the correct signer is set. Returns 0 on success. */
590 static int set_signer (gpgme_ctx_t ctx, int for_smime)
592 char *signid = for_smime ? SmimeDefaultKey : PgpSignAs;
595 gpgme_key_t key, key2;
597 if (!signid || !*signid)
600 listctx = create_gpgme_context (for_smime);
601 err = gpgme_op_keylist_start (listctx, signid, 1);
603 err = gpgme_op_keylist_next (listctx, &key);
605 gpgme_release (listctx);
606 mutt_error (_("secret key `%s' not found: %s\n"),
607 signid, gpgme_strerror (err));
610 err = gpgme_op_keylist_next (listctx, &key2);
612 gpgme_key_release (key);
613 gpgme_key_release (key2);
614 gpgme_release (listctx);
615 mutt_error (_("ambiguous specification of secret key `%s'\n"), signid);
618 gpgme_op_keylist_end (listctx);
619 gpgme_release (listctx);
621 gpgme_signers_clear (ctx);
622 err = gpgme_signers_add (ctx, key);
623 gpgme_key_release (key);
625 mutt_error (_("error setting secret key `%s': %s\n"),
626 signid, gpgme_strerror (err));
633 /* Encrypt the gpgme data object PLAINTEXT to the recipients in RSET
634 and return an allocated filename to a temporary file containing the
635 enciphered text. With USE_SMIME set to true, the smime backend is
636 used. With COMBINED_SIGNED a PGP message is signed and
637 encrypted. Returns NULL in case of error */
638 static char *encrypt_gpgme_object (gpgme_data_t plaintext, gpgme_key_t * rset,
639 int use_smime, int combined_signed)
643 gpgme_data_t ciphertext;
646 ctx = create_gpgme_context (use_smime);
648 gpgme_set_armor (ctx, 1);
650 ciphertext = create_gpgme_data ();
652 if (combined_signed) {
653 if (set_signer (ctx, use_smime)) {
654 gpgme_data_release (ciphertext);
658 err = gpgme_op_encrypt_sign (ctx, rset, GPGME_ENCRYPT_ALWAYS_TRUST,
659 plaintext, ciphertext);
662 err = gpgme_op_encrypt (ctx, rset, GPGME_ENCRYPT_ALWAYS_TRUST,
663 plaintext, ciphertext);
664 mutt_need_hard_redraw ();
666 mutt_error (_("error encrypting data: %s\n"), gpgme_strerror (err));
667 gpgme_data_release (ciphertext);
674 outfile = data_object_to_tempfile (ciphertext, NULL);
675 gpgme_data_release (ciphertext);
679 /* Find the "micalg" parameter from the last Gpgme operation on
680 context CTX. It is expected that this operation was a sign
681 operation. Return the algorithm name as a C string in buffer BUF
682 which must have been allocated by the caller with size BUFLEN.
683 Returns 0 on success or -1 in case of an error. The return string
684 is truncted to BUFLEN - 1. */
685 static int get_micalg (gpgme_ctx_t ctx, char *buf, ssize_t buflen)
687 gpgme_sign_result_t result = NULL;
688 const char *algorithm_name = NULL;
694 result = gpgme_op_sign_result (ctx);
696 algorithm_name = gpgme_hash_algo_name (result->signatures->hash_algo);
697 if (algorithm_name) {
698 m_strcpy(buf, buflen, algorithm_name);
702 return *buf ? 0 : -1;
705 static void print_time (time_t t, STATE * s)
709 setlocale (LC_TIME, "");
710 #ifdef HAVE_LANGINFO_D_T_FMT
711 strftime (p, sizeof (p), nl_langinfo (D_T_FMT), localtime (&t));
713 strftime (p, sizeof (p), "%c", localtime (&t));
715 setlocale (LC_TIME, "C");
716 state_attach_puts (p, s);
719 /* Implementation of `sign_message'. */
721 /* Sign the MESSAGE in body A either using OpenPGP or S/MIME when
722 USE_SMIME is passed as true. Returns the new body or NULL on
724 static BODY *sign_message (BODY * a, int use_smime)
731 gpgme_data_t message, signature;
733 convert_to_7bit (a); /* Signed data _must_ be in 7-bit format. */
735 message = body_to_data_object (a, 1);
738 signature = create_gpgme_data ();
740 ctx = create_gpgme_context (use_smime);
742 gpgme_set_armor (ctx, 1);
744 if (set_signer (ctx, use_smime)) {
745 gpgme_data_release (signature);
750 err = gpgme_op_sign (ctx, message, signature, GPGME_SIG_MODE_DETACH);
751 mutt_need_hard_redraw ();
752 gpgme_data_release (message);
754 gpgme_data_release (signature);
756 mutt_error (_("error signing data: %s\n"), gpgme_strerror (err));
760 sigfile = data_object_to_tempfile (signature, NULL);
761 gpgme_data_release (signature);
768 t->type = TYPEMULTIPART;
769 t->subtype = m_strdup("signed");
770 t->encoding = ENC7BIT;
772 t->disposition = DISPINLINE;
774 parameter_set_boundary(&t->parameter);
775 parameter_setval(&t->parameter, "protocol",
776 use_smime ? "application/pkcs7-signature"
777 : "application/pgp-signature");
778 /* Get the micalg from gpgme. Old gpgme versions don't support this
779 for S/MIME so we assume sha-1 in this case. */
780 if (!get_micalg (ctx, buf, sizeof buf))
781 parameter_setval(&t->parameter, "micalg", buf);
783 parameter_setval(&t->parameter, "micalg", "sha1");
789 t->parts->next = body_new();
791 t->type = TYPEAPPLICATION;
793 t->subtype = m_strdup("pkcs7-signature");
794 parameter_setval(&t->parameter, "name", "smime.p7s");
795 t->encoding = ENCBASE64;
797 t->disposition = DISPATTACH;
798 t->d_filename = m_strdup("smime.p7s");
801 t->subtype = m_strdup("pgp-signature");
803 t->disposition = DISPINLINE;
804 t->encoding = ENC7BIT;
806 t->filename = sigfile;
807 t->unlink = 1; /* ok to remove this file after sending. */
813 * Implementation of `encrypt_message'.
816 /* Encrypt the mail body A to all keys given as space separated keyids
817 or fingerprints in KEYLIST and return the encrypted body. */
818 static BODY *crypt_pgp_encrypt_message (BODY * a, char *keylist, int sign)
820 char *outfile = NULL;
822 gpgme_key_t *rset = NULL;
823 gpgme_data_t plaintext;
825 rset = create_recipient_set (keylist, GPGME_PROTOCOL_OpenPGP);
831 plaintext = body_to_data_object (a, 0);
837 outfile = encrypt_gpgme_object (plaintext, rset, 0, sign);
838 gpgme_data_release (plaintext);
844 t->type = TYPEMULTIPART;
845 t->subtype = m_strdup("encrypted");
846 t->encoding = ENC7BIT;
848 t->disposition = DISPINLINE;
850 parameter_set_boundary(&t->parameter);
851 parameter_setval(&t->parameter, "protocol", "application/pgp-encrypted");
853 t->parts = body_new();
854 t->parts->type = TYPEAPPLICATION;
855 t->parts->subtype = m_strdup("pgp-encrypted");
856 t->parts->encoding = ENC7BIT;
858 t->parts->next = body_new();
859 t->parts->next->type = TYPEAPPLICATION;
860 t->parts->next->subtype = m_strdup("octet-stream");
861 t->parts->next->encoding = ENC7BIT;
862 t->parts->next->filename = outfile;
863 t->parts->next->use_disp = 1;
864 t->parts->next->disposition = DISPINLINE;
865 t->parts->next->unlink = 1; /* delete after sending the message */
866 t->parts->next->d_filename = m_strdup("msg.asc"); /* non pgp/mime
873 * Implementation of `smime_build_smime_entity'.
876 /* Encrypt the mail body A to all keys given as space separated
877 fingerprints in KEYLIST and return the S/MIME encrypted body. */
878 static BODY *crypt_smime_build_smime_entity (BODY * a, char *keylist)
880 char *outfile = NULL;
882 gpgme_key_t *rset = NULL;
883 gpgme_data_t plaintext;
885 rset = create_recipient_set (keylist, GPGME_PROTOCOL_CMS);
889 plaintext = body_to_data_object (a, 0);
895 outfile = encrypt_gpgme_object (plaintext, rset, 1, 0);
896 gpgme_data_release (plaintext);
902 t->type = TYPEAPPLICATION;
903 t->subtype = m_strdup("pkcs7-mime");
904 parameter_setval(&t->parameter, "name", "smime.p7m");
905 parameter_setval(&t->parameter, "smime-type", "enveloped-data");
906 t->encoding = ENCBASE64; /* The output of OpenSSL SHOULD be binary */
908 t->disposition = DISPATTACH;
909 t->d_filename = m_strdup("smime.p7m");
910 t->filename = outfile;
911 t->unlink = 1; /*delete after sending the message */
919 /* Implementation of `verify_one'. */
921 /* Display the common attributes of the signature summary SUM.
922 Return 1 if there is is a severe warning.
924 static int show_sig_summary (unsigned long sum,
925 gpgme_ctx_t ctx, gpgme_key_t key, int idx,
930 if ((sum & GPGME_SIGSUM_KEY_REVOKED)) {
931 state_attach_puts (_("Warning: One of the keys has been revoked\n"), s);
935 if ((sum & GPGME_SIGSUM_KEY_EXPIRED)) {
936 time_t at = key->subkeys->expires ? key->subkeys->expires : 0;
939 state_attach_puts (_("Warning: The key used to create the "
940 "signature expired at: "), s);
942 state_attach_puts ("\n", s);
945 state_attach_puts (_("Warning: At least one certification key "
946 "has expired\n"), s);
949 if ((sum & GPGME_SIGSUM_SIG_EXPIRED)) {
950 gpgme_verify_result_t result;
951 gpgme_signature_t sig;
954 result = gpgme_op_verify_result (ctx);
956 for (sig = result->signatures, i = 0; sig && (i < idx);
957 sig = sig->next, i++);
959 state_attach_puts (_("Warning: The signature expired at: "), s);
960 print_time (sig ? sig->exp_timestamp : 0, s);
961 state_attach_puts ("\n", s);
964 if ((sum & GPGME_SIGSUM_KEY_MISSING))
965 state_attach_puts (_("Can't verify due to a missing "
966 "key or certificate\n"), s);
968 if ((sum & GPGME_SIGSUM_CRL_MISSING)) {
969 state_attach_puts (_("The CRL is not available\n"), s);
973 if ((sum & GPGME_SIGSUM_CRL_TOO_OLD)) {
974 state_attach_puts (_("Available CRL is too old\n"), s);
978 if ((sum & GPGME_SIGSUM_BAD_POLICY))
979 state_attach_puts (_("A policy requirement was not met\n"), s);
981 if ((sum & GPGME_SIGSUM_SYS_ERROR)) {
982 const char *t0 = NULL, *t1 = NULL;
983 gpgme_verify_result_t result;
984 gpgme_signature_t sig;
987 state_attach_puts (_("A system error occurred"), s);
989 /* Try to figure out some more detailed system error information. */
990 result = gpgme_op_verify_result (ctx);
991 for (sig = result->signatures, i = 0; sig && (i < idx);
992 sig = sig->next, i++);
995 t1 = sig->wrong_key_usage ? "Wrong_Key_Usage" : "";
999 state_attach_puts (": ", s);
1001 state_attach_puts (t0, s);
1002 if (t1 && !(t0 && !m_strcmp(t0, t1))) {
1004 state_attach_puts (",", s);
1005 state_attach_puts (t1, s);
1008 state_attach_puts ("\n", s);
1015 static void show_fingerprint (gpgme_key_t key, STATE * state)
1020 const char *prefix = _("Fingerprint: ");
1025 s = key->subkeys ? key->subkeys->fpr : NULL;
1028 is_pgp = (key->protocol == GPGME_PROTOCOL_OpenPGP);
1030 bufsize = m_strlen(prefix) + m_strlen(s) * 4 + 2;
1031 buf = p_new(char, bufsize);
1032 m_strcpy(buf, bufsize, prefix);
1033 p = buf + m_strlen(buf);
1034 if (is_pgp && m_strlen(s) == 40) { /* PGP v4 style formatted. */
1035 for (i = 0; *s && s[1] && s[2] && s[3] && s[4]; s += 4, i++) {
1046 for (i = 0; *s && s[1] && s[2]; s += 2, i++) {
1049 *p++ = is_pgp ? ' ' : ':';
1050 if (is_pgp && i == 7)
1055 /* just in case print remaining odd digits */
1060 state_attach_puts (buf, state);
1064 /* Show the valididy of a key used for one signature. */
1065 static void show_one_sig_validity (gpgme_ctx_t ctx, int idx, STATE * s)
1067 gpgme_verify_result_t result = NULL;
1068 gpgme_signature_t sig = NULL;
1069 const char *txt = NULL;
1071 result = gpgme_op_verify_result (ctx);
1073 for (sig = result->signatures; sig && (idx > 0); sig = sig->next, idx--);
1075 switch (sig ? sig->validity : 0) {
1076 case GPGME_VALIDITY_UNKNOWN:
1077 txt = _("WARNING: We have NO indication whether "
1078 "the key belongs to the person named " "as shown above\n");
1080 case GPGME_VALIDITY_UNDEFINED:
1082 case GPGME_VALIDITY_NEVER:
1083 txt = _("WARNING: The key does NOT BELONG to "
1084 "the person named as shown above\n");
1086 case GPGME_VALIDITY_MARGINAL:
1087 txt = _("WARNING: It is NOT certain that the key "
1088 "belongs to the person named as shown above\n");
1090 case GPGME_VALIDITY_FULL:
1091 case GPGME_VALIDITY_ULTIMATE:
1096 state_attach_puts (txt, s);
1099 /* Show information about one signature. This fucntion is called with
1100 the context CTX of a sucessful verification operation and the
1101 enumerator IDX which should start at 0 and incremete for each
1104 Return values are: 0 for normal procession, 1 for a bad signature,
1105 2 for a signature with a warning or -1 for no more signature. */
1106 static int show_one_sig_status (gpgme_ctx_t ctx, int idx, STATE * s)
1109 const char *fpr, *uid;
1110 gpgme_key_t key = NULL;
1111 int i, anybad = 0, anywarn = 0;
1113 gpgme_user_id_t uids = NULL;
1114 gpgme_verify_result_t result;
1115 gpgme_signature_t sig;
1116 gpgme_error_t err = GPG_ERR_NO_ERROR;
1118 result = gpgme_op_verify_result (ctx);
1120 /* FIXME: this code should use a static variable and remember
1121 the current position in the list of signatures, IMHO.
1124 for (i = 0, sig = result->signatures; sig && (i < idx);
1125 i++, sig = sig->next);
1127 return -1; /* Signature not found. */
1129 if (signature_key) {
1130 gpgme_key_release (signature_key);
1131 signature_key = NULL;
1134 created = sig->timestamp;
1138 if (gpg_err_code (sig->status) != GPG_ERR_NO_ERROR)
1141 err = gpgme_get_key2 (ctx, fpr, &key, 0); /* secret key? */
1143 uid = (key->uids && key->uids->uid) ? key->uids->uid : "[?]";
1145 signature_key = key;
1148 key = NULL; /* Old gpgme versions did not set KEY to NULL on
1149 error. Do it here to avoid a double free. */
1153 if (!s || !s->fpout || !(s->flags & M_DISPLAY)); /* No state information so no way to print anything. */
1155 state_attach_puts (_("Error getting key information: "), s);
1156 state_attach_puts (gpg_strerror (err), s);
1157 state_attach_puts ("\n", s);
1160 else if ((sum & GPGME_SIGSUM_GREEN)) {
1161 state_attach_puts (_("Good signature from: "), s);
1162 state_attach_puts (uid, s);
1163 state_attach_puts ("\n", s);
1164 for (i = 1, uids = key->uids; uids; i++, uids = uids->next) {
1166 /* Skip primary UID. */
1170 state_attach_puts (_(" aka: "), s);
1171 state_attach_puts (uids->uid, s);
1172 state_attach_puts ("\n", s);
1174 state_attach_puts (_(" created: "), s);
1175 print_time (created, s);
1176 state_attach_puts ("\n", s);
1177 if (show_sig_summary (sum, ctx, key, idx, s))
1179 show_one_sig_validity (ctx, idx, s);
1181 else if ((sum & GPGME_SIGSUM_RED)) {
1182 state_attach_puts (_("*BAD* signature claimed to be from: "), s);
1183 state_attach_puts (uid, s);
1184 state_attach_puts ("\n", s);
1185 show_sig_summary (sum, ctx, key, idx, s);
1187 else if (!anybad && key && (key->protocol == GPGME_PROTOCOL_OpenPGP)) { /* We can't decide (yellow) but this is a PGP key with a good
1188 signature, so we display what a PGP user expects: The name,
1189 fingerprint and the key validity (which is neither fully or
1191 state_attach_puts (_("Good signature from: "), s);
1192 state_attach_puts (uid, s);
1193 state_attach_puts ("\n", s);
1194 state_attach_puts (_(" created: "), s);
1195 print_time (created, s);
1196 state_attach_puts ("\n", s);
1197 show_one_sig_validity (ctx, idx, s);
1198 show_fingerprint (key, s);
1199 if (show_sig_summary (sum, ctx, key, idx, s))
1202 else { /* can't decide (yellow) */
1204 state_attach_puts (_("Error checking signature"), s);
1205 state_attach_puts ("\n", s);
1206 show_sig_summary (sum, ctx, key, idx, s);
1209 if (key != signature_key)
1210 gpgme_key_release (key);
1213 return anybad ? 1 : anywarn ? 2 : 0;
1216 /* Do the actual verification step. With IS_SMIME set to true we
1217 assume S/MIME (surprise!) */
1218 static int crypt_verify_one(BODY *sigbdy, STATE *s, FILE *fp, int is_smime)
1224 gpgme_data_t signature, message;
1226 signature = file_to_data_object (s->fpin, sigbdy->offset, sigbdy->length);
1230 /* We need to tell gpgme about the encoding because the backend can't
1231 auto-detect plain base-64 encoding which is used by S/MIME. */
1233 gpgme_data_set_encoding (signature, GPGME_DATA_ENCODING_BASE64);
1235 err = gpgme_data_new_from_stream(&message, fp);
1237 gpgme_data_release (signature);
1238 mutt_error (_("error allocating data object: %s\n"), gpgme_strerror (err));
1241 ctx = create_gpgme_context (is_smime);
1243 /* Note: We don't need a current time output because GPGME avoids
1244 such an attack by separating the meta information from the
1246 state_attach_puts (_("[-- Begin signature information --]\n"), s);
1248 err = gpgme_op_verify (ctx, signature, message, NULL);
1249 mutt_need_hard_redraw ();
1253 snprintf (buf, sizeof (buf) - 1,
1254 _("Error: verification failed: %s\n"), gpgme_strerror (err));
1255 state_attach_puts (buf, s);
1257 else { /* Verification succeeded, see what the result is. */
1261 if (signature_key) {
1262 gpgme_key_release (signature_key);
1263 signature_key = NULL;
1266 for (idx = 0; (res = show_one_sig_status (ctx, idx, s)) != -1; idx++) {
1277 gpgme_verify_result_t result;
1278 gpgme_sig_notation_t notation;
1279 gpgme_signature_t sig;
1281 result = gpgme_op_verify_result (ctx);
1283 for (sig = result->signatures; sig; sig = sig->next) {
1284 if (sig->notations) {
1285 state_attach_puts ("*** Begin Notation (signature by: ", s);
1286 state_attach_puts (sig->fpr, s);
1287 state_attach_puts (") ***\n", s);
1288 for (notation = sig->notations; notation; notation = notation->next)
1290 if (notation->name) {
1291 state_attach_puts (notation->name, s);
1292 state_attach_puts ("=", s);
1294 if (notation->value) {
1295 state_attach_puts (notation->value, s);
1296 if (!(*notation->value
1297 && (notation->value[m_strlen(notation->value) - 1] ==
1299 state_attach_puts ("\n", s);
1302 state_attach_puts ("*** End Notation ***\n", s);
1308 gpgme_release (ctx);
1310 state_attach_puts (_("[-- End signature information --]\n\n"), s);
1312 return badsig ? 1 : anywarn ? 2 : 0;
1316 * Implementation of `decrypt_part'.
1319 /* Decrypt a PGP or SMIME message (depending on the boolean flag
1320 IS_SMIME) with body A described further by state S. Write
1321 plaintext out to file FPOUT and return a new body. For PGP returns
1322 a flag in R_IS_SIGNED to indicate whether this is a combined
1323 encrypted and signed message, for S/MIME it returns true when it is
1324 not a encrypted but a signed message. */
1325 static BODY *decrypt_part (BODY * a, STATE * s, FILE * fpout, int is_smime,
1332 gpgme_data_t ciphertext, plaintext;
1333 int maybe_signed = 0;
1340 ctx = create_gpgme_context (is_smime);
1343 /* Make a data object from the body, create context etc. */
1344 ciphertext = file_to_data_object (s->fpin, a->offset, a->length);
1347 plaintext = create_gpgme_data ();
1349 /* Do the decryption or the verification in case of the S/MIME hack. */
1350 if ((!is_smime) || maybe_signed) {
1352 err = gpgme_op_decrypt_verify (ctx, ciphertext, plaintext);
1353 else if (maybe_signed)
1354 err = gpgme_op_verify (ctx, ciphertext, NULL, plaintext);
1357 /* Check wether signatures have been verified. */
1358 gpgme_verify_result_t verify_result = gpgme_op_verify_result (ctx);
1360 if (verify_result->signatures)
1365 err = gpgme_op_decrypt (ctx, ciphertext, plaintext);
1366 gpgme_data_release (ciphertext);
1368 if (is_smime && !maybe_signed && gpg_err_code (err) == GPG_ERR_NO_DATA) {
1369 /* Check whether this might be a signed message despite what
1370 the mime header told us. Retry then. gpgsm returns the
1371 error information "unsupported Algorithm '?'" but gpgme
1372 will not store this unknown algorithm, thus we test that
1373 it has not been set. */
1374 gpgme_decrypt_result_t result;
1376 result = gpgme_op_decrypt_result (ctx);
1377 if (!result->unsupported_algorithm) {
1379 gpgme_data_release (plaintext);
1383 mutt_need_hard_redraw ();
1384 if ((s->flags & M_DISPLAY)) {
1387 snprintf (buf, sizeof (buf) - 1,
1388 _("[-- Error: decryption failed: %s --]\n\n"),
1389 gpgme_strerror (err));
1390 state_attach_puts (buf, s);
1392 gpgme_data_release (plaintext);
1393 gpgme_release (ctx);
1396 mutt_need_hard_redraw ();
1398 /* Read the output from GPGME, and make sure to change CRLF to LF,
1399 otherwise read_mime_header has a hard time parsing the message. */
1400 if (data_object_to_stream (plaintext, fpout)) {
1401 gpgme_data_release (plaintext);
1402 gpgme_release (ctx);
1405 gpgme_data_release (plaintext);
1407 a->is_signed_data = 0;
1413 a->is_signed_data = 1;
1415 *r_is_signed = -1; /* A signature exists. */
1417 if ((s->flags & M_DISPLAY))
1418 state_attach_puts (_("[-- Begin signature " "information --]\n"), s);
1419 for (idx = 0; (res = show_one_sig_status (ctx, idx, s)) != -1; idx++) {
1425 if (!anybad && idx && r_is_signed && *r_is_signed)
1426 *r_is_signed = anywarn ? 2 : 1; /* Good signature. */
1428 if ((s->flags & M_DISPLAY))
1429 state_attach_puts (_("[-- End signature " "information --]\n\n"), s);
1431 gpgme_release (ctx);
1436 tattach = mutt_read_mime_header (fpout, 0);
1439 * Need to set the length of this body part.
1441 fstat (fileno (fpout), &info);
1442 tattach->length = info.st_size - tattach->offset;
1444 tattach->warnsig = anywarn;
1446 /* See if we need to recurse on this MIME part. */
1447 mutt_parse_part (fpout, tattach);
1453 /* Decrypt a PGP/MIME message in FPIN and B and return a new body and
1454 the stream in CUR and FPOUT. Returns 0 on success. */
1455 int crypt_pgp_decrypt_mime (FILE * fpin, FILE ** fpout, BODY * b, BODY ** cur)
1457 char tempfile[_POSIX_PATH_MAX];
1459 BODY *first_part = b;
1462 first_part->goodsig = 0;
1463 first_part->warnsig = 0;
1465 if (!mutt_is_multipart_encrypted (b))
1468 if (!b->parts || !b->parts->next)
1475 *fpout = m_tempfile(tempfile, sizeof(tempfile), NONULL(MCore.tmpdir), NULL);
1477 mutt_perror (_("Can't create temporary file"));
1482 *cur = decrypt_part (b, &s, *fpout, 0, &is_signed);
1485 first_part->goodsig = 1;
1487 return *cur ? 0 : -1;
1491 /* Decrypt a S/MIME message in FPIN and B and return a new body and
1492 the stream in CUR and FPOUT. Returns 0 on success. */
1493 int crypt_smime_decrypt_mime (FILE * fpin, FILE ** fpout, BODY * b,
1496 char tempfile[_POSIX_PATH_MAX];
1500 long saved_b_offset;
1501 ssize_t saved_b_length;
1504 if (!mutt_is_application_smime (b))
1510 /* Decode the body - we need to pass binary CMS to the
1511 backend. The backend allows for Base64 encoded data but it does
1512 not allow for QP which I have seen in some messages. So better
1514 saved_b_type = b->type;
1515 saved_b_offset = b->offset;
1516 saved_b_length = b->length;
1519 fseeko (s.fpin, b->offset, 0);
1520 tmpfp = m_tempfile (tempfile, sizeof(tempfile), NONULL(MCore.tmpdir), NULL);
1522 mutt_perror (_("Can't create temporary file"));
1525 mutt_unlink (tempfile);
1528 mutt_decode_attachment (b, &s);
1530 b->length = ftello (s.fpout);
1537 *fpout = m_tempfile(tempfile, sizeof(tempfile), NONULL(MCore.tmpdir), NULL);
1539 mutt_perror (_("Can't create temporary file"));
1542 mutt_unlink (tempfile);
1544 *cur = decrypt_part (b, &s, *fpout, 1, &is_signed);
1546 (*cur)->goodsig = is_signed > 0;
1547 b->type = saved_b_type;
1548 b->length = saved_b_length;
1549 b->offset = saved_b_offset;
1552 if (*cur && !is_signed && !(*cur)->parts
1553 && mutt_is_application_smime (*cur)) {
1554 /* Assume that this is a opaque signed s/mime message. This is
1555 an ugly way of doing it but we have anyway a problem with
1556 arbitrary encoded S/MIME messages: Only the outer part may be
1557 encrypted. The entire mime parsing should be revamped,
1558 probably by keeping the temportary files so that we don't
1559 need to decrypt them all the time. Inner parts of an
1560 encrypted part can then pint into this file and tehre won't
1561 never be a need to decrypt again. This needs a partial
1562 rewrite of the MIME engine. */
1566 saved_b_type = bb->type;
1567 saved_b_offset = bb->offset;
1568 saved_b_length = bb->length;
1571 fseeko (s.fpin, bb->offset, 0);
1572 tmpfp = m_tempfile (tempfile, sizeof(tempfile), NONULL(MCore.tmpdir), NULL);
1574 mutt_perror (_("Can't create temporary file"));
1577 mutt_unlink (tempfile);
1580 mutt_decode_attachment (bb, &s);
1582 bb->length = ftello (s.fpout);
1590 *fpout = m_tempfile(tempfile, sizeof(tempfile), NONULL(MCore.tmpdir), NULL);
1592 mutt_perror (_("Can't create temporary file"));
1595 mutt_unlink (tempfile);
1597 tmp_b = decrypt_part (bb, &s, *fpout, 1, &is_signed);
1599 tmp_b->goodsig = is_signed > 0;
1600 bb->type = saved_b_type;
1601 bb->length = saved_b_length;
1602 bb->offset = saved_b_offset;
1605 body_list_wipe(cur);
1608 return *cur ? 0 : -1;
1613 * Implementation of `pgp_check_traditional'.
1616 static int pgp_check_traditional_one_body (FILE * fp, BODY * b,
1619 char tempfile[_POSIX_PATH_MAX];
1620 char buf[HUGE_STRING];
1627 if (b->type != TYPETEXT)
1630 if (tagged_only && !b->tagged)
1633 tempfd = m_tempfd(tempfile, sizeof(tempfile), NONULL(MCore.tmpdir), NULL);
1634 if (mutt_decode_save_attachment (fp, b, tempfd, 0) != 0) {
1639 if ((tfp = fopen(tempfile, "r")) == NULL) {
1644 while (fgets (buf, sizeof (buf), tfp)) {
1645 if (!m_strncmp("-----BEGIN PGP ", buf, 15)) {
1646 if (!m_strcmp("MESSAGE-----\n", buf + 15))
1648 else if (!m_strcmp("SIGNED MESSAGE-----\n", buf + 15))
1658 /* fix the content type */
1660 parameter_setval(&b->parameter, "format", "fixed");
1661 parameter_setval(&b->parameter, "x-action",
1662 enc ? "pgp-encrypted" : "pgp-signed");
1666 int crypt_pgp_check_traditional (FILE * fp, BODY * b, int tagged_only)
1671 for (; b; b = b->next) {
1672 if (is_multipart (b))
1673 rv = (crypt_pgp_check_traditional (fp, b->parts, tagged_only) || rv);
1674 else if (b->type == TYPETEXT) {
1675 if ((r = mutt_is_application_pgp (b)))
1678 rv = (pgp_check_traditional_one_body (fp, b, tagged_only) || rv);
1685 /* Implementation of `application_handler'. */
1688 Copy a clearsigned message, and strip the signature and PGP's
1691 XXX - charset handling: We assume that it is safe to do
1692 character set decoding first, dash decoding second here, while
1693 we do it the other way around in the main handler.
1695 (Note that we aren't worse than Outlook & Cie in this, and also
1696 note that we can successfully handle anything produced by any
1697 existing versions of mutt.) */
1699 static void copy_clearsigned (gpgme_data_t data, STATE * s, char *charset)
1701 char buf[HUGE_STRING];
1702 short complete, armor_header;
1707 fname = data_object_to_tempfile (data, &fp);
1713 fc = fgetconv_open (fp, charset, MCharset.charset, M_ICONV_HOOK_FROM);
1715 for (complete = 1, armor_header = 1;
1716 fgetconvs (buf, sizeof (buf), fc) != NULL;
1717 complete = strchr (buf, '\n') != NULL) {
1720 state_puts (buf, s);
1724 if (!m_strcmp(buf, "-----BEGIN PGP SIGNATURE-----\n"))
1734 state_puts (s->prefix, s);
1736 if (buf[0] == '-' && buf[1] == ' ')
1737 state_puts (buf + 2, s);
1739 state_puts (buf, s);
1742 fgetconv_close (&fc);
1747 /* Support for classic_application/pgp */
1748 int crypt_pgp_application_pgp_handler (BODY * m, STATE * s)
1750 int needpass = -1, pgp_keyblock = 0;
1754 off_t last_pos, offset;
1755 char buf[HUGE_STRING];
1756 FILE *pgpout = NULL;
1758 gpgme_error_t err = 0;
1759 gpgme_data_t armored_data = NULL;
1761 short maybe_goodsig = 1;
1762 short have_any_sigs = 0;
1764 char body_charset[STRING]; /* Only used for clearsigned messages. */
1766 /* For clearsigned messages we won't be able to get a character set
1767 but we know that this may only be text thus we assume Latin-1
1769 if (!mutt_get_body_charset (body_charset, sizeof (body_charset), m))
1770 m_strcpy(body_charset, sizeof(body_charset), "iso-8859-1");
1772 fseeko (s->fpin, m->offset, 0);
1773 last_pos = m->offset;
1775 for (bytes = m->length; bytes > 0;) {
1776 if (fgets (buf, sizeof (buf), s->fpin) == NULL)
1779 offset = ftello (s->fpin);
1780 bytes -= (offset - last_pos); /* don't rely on m_strlen(buf) */
1783 if (!m_strncmp("-----BEGIN PGP ", buf, 15)) {
1785 start_pos = last_pos;
1787 if (!m_strcmp("MESSAGE-----\n", buf + 15))
1789 else if (!m_strcmp("SIGNED MESSAGE-----\n", buf + 15)) {
1793 else if (!option (OPTDONTHANDLEPGPKEYS) &&
1794 !m_strcmp("PUBLIC KEY BLOCK-----\n", buf + 15)) {
1799 /* XXX - we may wish to recode here */
1801 state_puts (s->prefix, s);
1802 state_puts (buf, s);
1806 have_any_sigs = (have_any_sigs || (clearsign && (s->flags & M_VERIFY)));
1808 /* Copy PGP material to an data container */
1809 armored_data = create_gpgme_data ();
1810 gpgme_data_write (armored_data, buf, m_strlen(buf));
1811 while (bytes > 0 && fgets (buf, sizeof (buf) - 1, s->fpin) != NULL) {
1812 offset = ftello (s->fpin);
1813 bytes -= (offset - last_pos); /* don't rely on m_strlen(buf) */
1816 gpgme_data_write (armored_data, buf, m_strlen(buf));
1818 if ((needpass && !m_strcmp("-----END PGP MESSAGE-----\n", buf))
1820 && (!m_strcmp("-----END PGP SIGNATURE-----\n", buf)
1821 || !m_strcmp("-----END PGP PUBLIC KEY BLOCK-----\n",
1826 /* Invoke PGP if needed */
1827 if (!clearsign || (s->flags & M_VERIFY)) {
1828 unsigned int sig_stat = 0;
1829 gpgme_data_t plaintext;
1832 plaintext = create_gpgme_data ();
1833 ctx = create_gpgme_context (0);
1836 err = gpgme_op_verify (ctx, armored_data, NULL, plaintext);
1838 err = gpgme_op_decrypt_verify (ctx, armored_data, plaintext);
1839 if (gpg_err_code (err) == GPG_ERR_NO_DATA) {
1840 /* Decrypt verify can't handle signed only messages. */
1841 err = (gpgme_data_seek (armored_data, 0, SEEK_SET) == -1)
1842 ? gpgme_error_from_errno (errno) : 0;
1843 /* Must release plaintext so that we supply an
1844 uninitialized object. */
1845 gpgme_data_release (plaintext);
1846 plaintext = create_gpgme_data ();
1847 err = gpgme_op_verify (ctx, armored_data, NULL, plaintext);
1854 snprintf (errbuf, sizeof (errbuf) - 1,
1855 _("Error: decryption/verification failed: %s\n"),
1856 gpgme_strerror (err));
1857 state_attach_puts (errbuf, s);
1859 else { /* Decryption/Verification succeeded */
1863 /* Check wether signatures have been verified. */
1864 gpgme_verify_result_t verify_result;
1866 verify_result = gpgme_op_verify_result (ctx);
1867 if (verify_result->signatures)
1873 if ((s->flags & M_DISPLAY) && sig_stat) {
1878 state_attach_puts (_("[-- Begin signature "
1879 "information --]\n"), s);
1882 (res = show_one_sig_status (ctx, idx, s)) != -1; idx++) {
1891 state_attach_puts (_("[-- End signature "
1892 "information --]\n\n"), s);
1895 tmpfname = data_object_to_tempfile (plaintext, &pgpout);
1898 state_attach_puts (_("Error: copy data failed\n"), s);
1902 p_delete(&tmpfname);
1905 gpgme_release (ctx);
1909 * Now, copy cleartext to the screen. NOTE - we expect that PGP
1910 * outputs utf-8 cleartext. This may not always be true, but it
1911 * seems to be a reasonable guess.
1914 if (s->flags & M_DISPLAY) {
1916 state_attach_puts (_("[-- BEGIN PGP MESSAGE --]\n\n"), s);
1917 else if (pgp_keyblock)
1918 state_attach_puts (_("[-- BEGIN PGP PUBLIC KEY BLOCK --]\n"), s);
1920 state_attach_puts (_("[-- BEGIN PGP SIGNED MESSAGE --]\n\n"), s);
1924 copy_clearsigned (armored_data, s, body_charset);
1931 fc = fgetconv_open (pgpout, "utf-8", MCharset.charset, 0);
1932 while ((c = fgetconv (fc)) != EOF) {
1934 if (c == '\n' && s->prefix)
1935 state_puts (s->prefix, s);
1937 fgetconv_close (&fc);
1940 if (s->flags & M_DISPLAY) {
1941 state_putc ('\n', s);
1943 state_attach_puts (_("[-- END PGP MESSAGE --]\n"), s);
1944 else if (pgp_keyblock)
1945 state_attach_puts (_("[-- END PGP PUBLIC KEY BLOCK --]\n"), s);
1947 state_attach_puts (_("[-- END PGP SIGNED MESSAGE --]\n"), s);
1955 /* XXX - we may wish to recode here */
1957 state_puts (s->prefix, s);
1958 state_puts (buf, s);
1962 m->goodsig = (maybe_goodsig && have_any_sigs);
1964 if (needpass == -1) {
1965 state_attach_puts (_("[-- Error: could not find beginning"
1966 " of PGP message! --]\n\n"), s);
1972 /* Implementation of `encrypted_handler'. */
1974 /* MIME handler for pgp/mime encrypted messages. */
1975 int crypt_pgp_encrypted_handler (BODY * a, STATE * s)
1977 char tempfile[_POSIX_PATH_MAX];
1980 BODY *orig_body = a;
1985 if (!a || a->type != TYPEAPPLICATION || !a->subtype
1986 || ascii_strcasecmp ("pgp-encrypted", a->subtype)
1987 || !a->next || a->next->type != TYPEAPPLICATION || !a->next->subtype
1988 || ascii_strcasecmp ("octet-stream", a->next->subtype)) {
1989 if (s->flags & M_DISPLAY)
1990 state_attach_puts (_("[-- Error: malformed PGP/MIME message! --]\n\n"),
1995 /* Move forward to the application/pgp-encrypted body. */
1998 fpout = m_tempfile(tempfile, sizeof(tempfile), NONULL(MCore.tmpdir), NULL);
2000 if (s->flags & M_DISPLAY)
2001 state_attach_puts (_("[-- Error: could not create temporary file! "
2006 tattach = decrypt_part (a, s, fpout, 0, &is_signed);
2008 tattach->goodsig = is_signed > 0;
2010 if (s->flags & M_DISPLAY)
2011 state_attach_puts (is_signed ?
2013 ("[-- The following data is PGP/MIME signed and encrypted --]\n\n") :
2014 _("[-- The following data is PGP/MIME encrypted --]\n\n"), s);
2017 FILE *savefp = s->fpin;
2020 rc = mutt_body_handler (tattach, s);
2025 * if a multipart/signed is the _only_ sub-part of a
2026 * multipart/encrypted, cache signature verification
2029 if (mutt_is_multipart_signed (tattach) && !tattach->next)
2030 orig_body->goodsig |= tattach->goodsig;
2032 if (s->flags & M_DISPLAY) {
2033 state_puts ("\n", s);
2034 state_attach_puts (is_signed ?
2036 ("[-- End of PGP/MIME signed and encrypted data --]\n")
2037 : _("[-- End of PGP/MIME encrypted data --]\n"), s);
2040 body_list_wipe(&tattach);
2044 mutt_unlink (tempfile);
2048 /* Support for application/smime */
2049 int crypt_smime_application_smime_handler (BODY * a, STATE * s)
2051 char tempfile[_POSIX_PATH_MAX];
2058 fpout = m_tempfile(tempfile, sizeof(tempfile), NONULL(MCore.tmpdir), NULL);
2060 if (s->flags & M_DISPLAY)
2061 state_attach_puts (_("[-- Error: could not create temporary file! "
2066 tattach = decrypt_part (a, s, fpout, 1, &is_signed);
2068 tattach->goodsig = is_signed > 0;
2070 if (s->flags & M_DISPLAY)
2071 state_attach_puts (is_signed ?
2072 _("[-- The following data is S/MIME signed --]\n\n") :
2073 _("[-- The following data is S/MIME encrypted --]\n\n"), s);
2076 FILE *savefp = s->fpin;
2079 rc = mutt_body_handler (tattach, s);
2084 * if a multipart/signed is the _only_ sub-part of a
2085 * multipart/encrypted, cache signature verification
2088 if (mutt_is_multipart_signed (tattach) && !tattach->next) {
2089 if (!(a->goodsig = tattach->goodsig))
2090 a->warnsig = tattach->warnsig;
2092 else if (tattach->goodsig) {
2094 a->warnsig = tattach->warnsig;
2097 if (s->flags & M_DISPLAY) {
2098 state_puts ("\n", s);
2099 state_attach_puts (is_signed ?
2100 _("[-- End of S/MIME signed data --]\n") :
2101 _("[-- End of S/MIME encrypted data --]\n"), s);
2104 body_list_wipe(&tattach);
2108 mutt_unlink (tempfile);
2114 * Format an entry on the CRYPT key selection menu.
2117 * %k key id %K key id of the principal key
2119 * %a algorithm %A algorithm of the princ. key
2120 * %l length %L length of the princ. key
2121 * %f flags %F flags of the princ. key
2122 * %c capabilities %C capabilities of the princ. key
2123 * %t trust/validity of the key-uid association
2125 * %[...] date of key using strftime(3)
2129 crypt_entry_fmt (char *dest, ssize_t destlen, char op,
2130 const char *src, const char *prefix,
2131 const char *ifstr, const char *elstr,
2132 anytype data, format_flag flags)
2135 crypt_entry_t *entry;
2138 int optional = (flags & M_FORMAT_OPTIONAL);
2139 const char *s = NULL;
2145 /* if (isupper ((unsigned char) op)) */
2148 kflags = (key->flags /*| (pkey->flags & KEYFLAG_RESTRICTIONS)
2151 switch (ascii_tolower (op)) {
2155 char buf2[STRING], *p;
2171 while (len > 0 && *cp != ']') {
2180 break; /* not enough space */
2190 if (do_locales && Locale)
2191 setlocale (LC_TIME, Locale);
2196 if (key->kobj->subkeys && (key->kobj->subkeys->timestamp > 0))
2197 tt = key->kobj->subkeys->timestamp;
2199 tm = localtime (&tt);
2201 strftime (buf2, sizeof (buf2), dest, tm);
2204 setlocale (LC_TIME, "C");
2206 snprintf (fmt, sizeof (fmt), "%%%ss", prefix);
2207 snprintf (dest, destlen, fmt, buf2);
2214 snprintf (fmt, sizeof (fmt), "%%%sd", prefix);
2215 snprintf (dest, destlen, fmt, entry->num);
2220 /* fixme: we need a way to distinguish between main and subkeys.
2221 Store the idx in entry? */
2222 snprintf (fmt, sizeof (fmt), "%%%ss", prefix);
2223 snprintf (dest, destlen, fmt, crypt_keyid (key));
2228 snprintf (fmt, sizeof (fmt), "%%%ss", prefix);
2229 snprintf (dest, destlen, fmt, key->uid);
2234 snprintf (fmt, sizeof (fmt), "%%%s.3s", prefix);
2235 if (key->kobj->subkeys)
2236 s = gpgme_pubkey_algo_name (key->kobj->subkeys->pubkey_algo);
2239 snprintf (dest, destlen, fmt, s);
2244 snprintf (fmt, sizeof (fmt), "%%%slu", prefix);
2245 if (key->kobj->subkeys)
2246 val = key->kobj->subkeys->length;
2249 snprintf (dest, destlen, fmt, val);
2254 snprintf (fmt, sizeof (fmt), "%%%sc", prefix);
2255 snprintf (dest, destlen, fmt, crypt_flags (kflags));
2257 else if (!(kflags & (KEYFLAG_RESTRICTIONS)))
2262 snprintf (fmt, sizeof (fmt), "%%%ss", prefix);
2263 snprintf (dest, destlen, fmt, crypt_key_abilities (kflags));
2265 else if (!(kflags & (KEYFLAG_ABILITIES)))
2269 if ((kflags & KEYFLAG_ISX509))
2272 gpgme_user_id_t uid = NULL;
2275 for (i = 0, uid = key->kobj->uids; uid && (i < key->idx);
2276 i++, uid = uid->next);
2278 switch (uid->validity) {
2279 case GPGME_VALIDITY_UNDEFINED:
2282 case GPGME_VALIDITY_NEVER:
2285 case GPGME_VALIDITY_MARGINAL:
2288 case GPGME_VALIDITY_FULL:
2291 case GPGME_VALIDITY_ULTIMATE:
2294 case GPGME_VALIDITY_UNKNOWN:
2300 snprintf (fmt, sizeof (fmt), "%%%sc", prefix);
2301 snprintf (dest, destlen, fmt, s ? *s : 'B');
2304 snprintf (fmt, sizeof (fmt), "%%%ss", prefix);
2305 snprintf (dest, destlen, fmt,
2306 gpgme_get_protocol_name (key->kobj->protocol));
2313 if (flags & M_FORMAT_OPTIONAL)
2314 m_strformat(dest, destlen, 0, optional ? ifstr: elstr,
2315 mutt_attach_fmt, data, 0);
2319 /* Used by the display fucntion to format a line. */
2320 static void crypt_entry (char *s, ssize_t l, MUTTMENU * menu, int num)
2322 crypt_key_t **key_table = (crypt_key_t **) menu->data;
2323 crypt_entry_t entry;
2325 entry.key = key_table[num];
2326 entry.num = num + 1;
2328 m_strformat(s, l, COLS - SW, PgpEntryFormat, crypt_entry_fmt, &entry,
2329 option(OPTARROWCURSOR) ? M_FORMAT_ARROWCURSOR : 0);
2332 /* Compare two addresses and the keyid to be used for sorting. */
2333 static int _crypt_compare_address (const void *a, const void *b)
2335 crypt_key_t **s = (crypt_key_t **) a;
2336 crypt_key_t **t = (crypt_key_t **) b;
2339 if ((r = m_strcasecmp((*s)->uid, (*t)->uid)))
2342 return m_strcasecmp(crypt_keyid (*s), crypt_keyid (*t)) > 0;
2345 static int crypt_compare_address (const void *a, const void *b)
2347 return ((PgpSortKeys & SORT_REVERSE) ? !_crypt_compare_address (a, b)
2348 : _crypt_compare_address (a, b));
2352 /* Compare two key IDs and the addresses to be used for sorting. */
2353 static int _crypt_compare_keyid (const void *a, const void *b)
2355 crypt_key_t **s = (crypt_key_t **) a;
2356 crypt_key_t **t = (crypt_key_t **) b;
2359 if ((r = m_strcasecmp(crypt_keyid (*s), crypt_keyid (*t))))
2362 return m_strcasecmp((*s)->uid, (*t)->uid) > 0;
2365 static int crypt_compare_keyid (const void *a, const void *b)
2367 return ((PgpSortKeys & SORT_REVERSE) ? !_crypt_compare_keyid (a, b)
2368 : _crypt_compare_keyid (a, b));
2371 /* Compare 2 creation dates and the addresses. For sorting. */
2372 static int _crypt_compare_date (const void *a, const void *b)
2374 crypt_key_t **s = (crypt_key_t **) a;
2375 crypt_key_t **t = (crypt_key_t **) b;
2376 unsigned long ts = 0, tt = 0;
2378 if ((*s)->kobj->subkeys && ((*s)->kobj->subkeys->timestamp > 0))
2379 ts = (*s)->kobj->subkeys->timestamp;
2380 if ((*t)->kobj->subkeys && ((*t)->kobj->subkeys->timestamp > 0))
2381 tt = (*t)->kobj->subkeys->timestamp;
2388 return m_strcasecmp((*s)->uid, (*t)->uid) > 0;
2391 static int crypt_compare_date (const void *a, const void *b)
2393 return ((PgpSortKeys & SORT_REVERSE) ? !_crypt_compare_date (a, b)
2394 : _crypt_compare_date (a, b));
2397 /* Compare two trust values, the key length, the creation dates. the
2398 addresses and the key IDs. For sorting. */
2399 static int _crypt_compare_trust (const void *a, const void *b)
2401 crypt_key_t **s = (crypt_key_t **) a;
2402 crypt_key_t **t = (crypt_key_t **) b;
2403 unsigned long ts = 0, tt = 0;
2406 if ((r = (((*s)->flags & (KEYFLAG_RESTRICTIONS))
2407 - ((*t)->flags & (KEYFLAG_RESTRICTIONS)))))
2410 if ((*s)->kobj->uids)
2411 ts = (*s)->kobj->uids->validity;
2412 if ((*t)->kobj->uids)
2413 tt = (*t)->kobj->uids->validity;
2414 if ((r = (tt - ts)))
2417 if ((*s)->kobj->subkeys)
2418 ts = (*s)->kobj->subkeys->length;
2419 if ((*t)->kobj->subkeys)
2420 tt = (*t)->kobj->subkeys->length;
2424 if ((*s)->kobj->subkeys && ((*s)->kobj->subkeys->timestamp > 0))
2425 ts = (*s)->kobj->subkeys->timestamp;
2426 if ((*t)->kobj->subkeys && ((*t)->kobj->subkeys->timestamp > 0))
2427 tt = (*t)->kobj->subkeys->timestamp;
2433 if ((r = m_strcasecmp((*s)->uid, (*t)->uid)))
2435 return (m_strcasecmp(crypt_keyid ((*s)), crypt_keyid ((*t)))) > 0;
2438 static int crypt_compare_trust (const void *a, const void *b)
2440 return ((PgpSortKeys & SORT_REVERSE) ? !_crypt_compare_trust (a, b)
2441 : _crypt_compare_trust (a, b));
2444 /* Print the X.500 Distinguished Name part KEY from the array of parts
2446 static int print_dn_part (FILE * fp, struct dn_array_s *dn, const char *key)
2450 for (; dn->key; dn++) {
2451 if (!m_strcmp(dn->key, key)) {
2454 print_utf8 (fp, dn->value, m_strlen(dn->value));
2461 /* Print all parts of a DN in a standard sequence. */
2462 static void print_dn_parts (FILE * fp, struct dn_array_s *dn)
2464 const char *stdpart[] = {
2465 "CN", "OU", "O", "STREET", "L", "ST", "C", NULL
2467 int any = 0, any2 = 0, i;
2469 for (i = 0; stdpart[i]; i++) {
2472 any = print_dn_part (fp, dn, stdpart[i]);
2474 /* now print the rest without any specific ordering */
2475 for (; dn->key; dn++) {
2476 for (i = 0; stdpart[i]; i++) {
2477 if (!m_strcmp(dn->key, stdpart[i]))
2485 any = print_dn_part (fp, dn, dn->key);
2494 /* Parse an RDN; this is a helper to parse_dn(). */
2495 static const unsigned char *parse_dn_part (struct dn_array_s *array,
2496 const unsigned char *string)
2498 const unsigned char *s, *s1;
2502 /* parse attributeType */
2503 for (s = string + 1; *s && *s != '='; s++);
2505 return NULL; /* error */
2508 return NULL; /* empty key */
2509 array->key = p_dupstr(string, n );
2510 p = (unsigned char *) array->key;
2513 if (*string == '#') { /* hexstring */
2515 for (s = string; hexval(*s) >= 0; s++)
2519 return NULL; /* empty or odd number of digits */
2521 p = p_new(unsigned char, n + 1);
2522 array->value = (char *) p;
2523 for (s1 = string; n; s1 += 2, n--)
2524 *p++ = (hexval(*s1) << 8) | hexval(*s1);
2527 else { /* regular v3 quoted string */
2528 for (n = 0, s = string; *s; s++) {
2529 if (*s == '\\') { /* pair */
2531 if (*s == ',' || *s == '=' || *s == '+'
2532 || *s == '<' || *s == '>' || *s == '#' || *s == ';'
2533 || *s == '\\' || *s == '\"' || *s == ' ')
2535 else if (hexval(*s) >= 0 && hexval(*s + 1) >= 0) {
2540 return NULL; /* invalid escape sequence */
2542 else if (*s == '\"')
2543 return NULL; /* invalid encoding */
2544 else if (*s == ',' || *s == '=' || *s == '+'
2545 || *s == '<' || *s == '>' || *s == '#' || *s == ';')
2551 p = p_new(unsigned char, n + 1);
2552 array->value = (char *) p;
2553 for (s = string; n; s++, n--) {
2556 if (hexval(*s) >= 0) {
2557 *p++ = (hexval(*s) << 8) | hexval(*s + 1);
2572 /* Parse a DN and return an array-ized one. This is not a validating
2573 parser and it does not support any old-stylish syntax; gpgme is
2574 expected to return only rfc2253 compatible strings. */
2575 static struct dn_array_s *parse_dn (const unsigned char *string)
2577 struct dn_array_s *array;
2578 ssize_t arrayidx, arraysize;
2581 arraysize = 7; /* C,ST,L,O,OU,CN,email */
2582 array = p_new(struct dn_array_s, arraysize + 1);
2585 while (*string == ' ')
2589 if (arrayidx >= arraysize) { /* mutt lacks a real safe_realoc - so we need to copy */
2590 struct dn_array_s *a2;
2593 a2 = p_new(struct dn_array_s, arraysize + 1);
2594 for (i = 0; i < arrayidx; i++) {
2595 a2[i].key = array[i].key;
2596 a2[i].value = array[i].value;
2601 array[arrayidx].key = NULL;
2602 array[arrayidx].value = NULL;
2603 string = parse_dn_part (array + arrayidx, string);
2607 while (*string == ' ')
2609 if (*string && *string != ',' && *string != ';' && *string != '+')
2610 goto failure; /* invalid delimiter */
2614 array[arrayidx].key = NULL;
2615 array[arrayidx].value = NULL;
2619 for (i = 0; i < arrayidx; i++) {
2620 p_delete(&array[i].key);
2621 p_delete(&array[i].value);
2628 /* Print a nice representation of the USERID and make sure it is
2629 displayed in a proper way, which does mean to reorder some parts
2630 for S/MIME's DNs. USERID is a string as returned by the gpgme key
2631 functions. It is utf-8 encoded. */
2632 static void parse_and_print_user_id (FILE * fp, const char *userid)
2637 if (*userid == '<') {
2638 s = strchr (userid + 1, '>');
2640 print_utf8 (fp, userid + 1, s - userid - 1);
2642 else if (*userid == '(')
2643 fputs (_("[Can't display this user ID (unknown encoding)]"), fp);
2644 else if (!digit_or_letter ((const unsigned char *) userid))
2645 fputs (_("[Can't display this user ID (invalid encoding)]"), fp);
2647 struct dn_array_s *dn = parse_dn ((const unsigned char *) userid);
2650 fputs (_("[Can't display this user ID (invalid DN)]"), fp);
2652 print_dn_parts (fp, dn);
2653 for (i = 0; dn[i].key; i++) {
2654 p_delete(&dn[i].key);
2655 p_delete(&dn[i].value);
2663 KEY_CAP_CAN_ENCRYPT,
2668 static unsigned int key_check_cap (gpgme_key_t key, key_cap_t cap)
2670 gpgme_subkey_t subkey = NULL;
2671 unsigned int ret = 0;
2674 case KEY_CAP_CAN_ENCRYPT:
2675 if (!(ret = key->can_encrypt))
2676 for (subkey = key->subkeys; subkey; subkey = subkey->next)
2677 if ((ret = subkey->can_encrypt))
2680 case KEY_CAP_CAN_SIGN:
2681 if (!(ret = key->can_sign))
2682 for (subkey = key->subkeys; subkey; subkey = subkey->next)
2683 if ((ret = subkey->can_sign))
2686 case KEY_CAP_CAN_CERTIFY:
2687 if (!(ret = key->can_certify))
2688 for (subkey = key->subkeys; subkey; subkey = subkey->next)
2689 if ((ret = subkey->can_certify))
2698 /* Print verbose information about a key or certificate to FP. */
2699 static void print_key_info (gpgme_key_t key, FILE * fp)
2702 const char *s = NULL, *s2 = NULL;
2705 char shortbuf[STRING];
2706 unsigned long aval = 0;
2710 gpgme_user_id_t uid = NULL;
2713 setlocale (LC_TIME, Locale);
2715 is_pgp = key->protocol == GPGME_PROTOCOL_OpenPGP;
2717 for (idx = 0, uid = key->uids; uid; idx++, uid = uid->next) {
2722 fputs (idx ? _(" aka ......: ") :_("Name ......: "), fp);
2725 fputs (_("[Invalid]"), fp);
2729 print_utf8 (fp, s, m_strlen(s));
2731 parse_and_print_user_id (fp, s);
2735 if (key->subkeys && (key->subkeys->timestamp > 0)) {
2736 tt = key->subkeys->timestamp;
2738 tm = localtime (&tt);
2739 #ifdef HAVE_LANGINFO_D_T_FMT
2740 strftime (shortbuf, sizeof shortbuf, nl_langinfo (D_T_FMT), tm);
2742 strftime (shortbuf, sizeof shortbuf, "%c", tm);
2744 fprintf (fp, _("Valid From : %s\n"), shortbuf);
2747 if (key->subkeys && (key->subkeys->expires > 0)) {
2748 tt = key->subkeys->expires;
2750 tm = localtime (&tt);
2751 #ifdef HAVE_LANGINFO_D_T_FMT
2752 strftime (shortbuf, sizeof shortbuf, nl_langinfo (D_T_FMT), tm);
2754 strftime (shortbuf, sizeof shortbuf, "%c", tm);
2756 fprintf (fp, _("Valid To ..: %s\n"), shortbuf);
2760 s = gpgme_pubkey_algo_name (key->subkeys->pubkey_algo);
2764 s2 = is_pgp ? "PGP" : "X.509";
2767 aval = key->subkeys->length;
2769 fprintf (fp, _("Key Type ..: %s, %lu bit %s\n"), s2, aval, s);
2771 fprintf (fp, _("Key Usage .: "));
2774 if (key_check_cap (key, KEY_CAP_CAN_ENCRYPT)) {
2775 fprintf (fp, "%s%s", delim, _("encryption"));
2778 if (key_check_cap (key, KEY_CAP_CAN_SIGN)) {
2779 fprintf (fp, "%s%s", delim, _("signing"));
2782 if (key_check_cap (key, KEY_CAP_CAN_CERTIFY)) {
2783 fprintf (fp, "%s%s", delim, _("certification"));
2789 s = key->subkeys->fpr;
2790 fputs (_("Fingerprint: "), fp);
2791 if (is_pgp && m_strlen(s) == 40) {
2792 for (i = 0; *s && s[1] && s[2] && s[3] && s[4]; s += 4, i++) {
2797 putc (is_pgp ? ' ' : ':', fp);
2798 if (is_pgp && i == 4)
2803 for (i = 0; *s && s[1] && s[2]; s += 2, i++) {
2806 putc (is_pgp ? ' ' : ':', fp);
2807 if (is_pgp && i == 7)
2811 fprintf (fp, "%s\n", s);
2814 if (key->issuer_serial) {
2815 s = key->issuer_serial;
2817 fprintf (fp, _("Serial-No .: 0x%s\n"), s);
2820 if (key->issuer_name) {
2821 s = key->issuer_name;
2823 fprintf (fp, _("Issued By .: "));
2824 parse_and_print_user_id (fp, s);
2829 /* For PGP we list all subkeys. */
2831 gpgme_subkey_t subkey = NULL;
2833 for (idx = 1, subkey = key->subkeys; subkey; idx++, subkey = subkey->next) {
2837 if (m_strlen(s) == 16)
2838 s += 8; /* display only the short keyID */
2839 fprintf (fp, _("Subkey ....: 0x%s"), s);
2840 if (subkey->revoked) {
2842 fputs (_("[Revoked]"), fp);
2844 if (subkey->invalid) {
2846 fputs (_("[Invalid]"), fp);
2848 if (subkey->expired) {
2850 fputs (_("[Expired]"), fp);
2852 if (subkey->disabled) {
2854 fputs (_("[Disabled]"), fp);
2858 if (subkey->timestamp > 0) {
2859 tt = subkey->timestamp;
2861 tm = localtime (&tt);
2862 #ifdef HAVE_LANGINFO_D_T_FMT
2863 strftime (shortbuf, sizeof shortbuf, nl_langinfo (D_T_FMT), tm);
2865 strftime (shortbuf, sizeof shortbuf, "%c", tm);
2867 fprintf (fp, _("Valid From : %s\n"), shortbuf);
2870 if (subkey->expires > 0) {
2871 tt = subkey->expires;
2873 tm = localtime (&tt);
2874 #ifdef HAVE_LANGINFO_D_T_FMT
2875 strftime (shortbuf, sizeof shortbuf, nl_langinfo (D_T_FMT), tm);
2877 strftime (shortbuf, sizeof shortbuf, "%c", tm);
2879 fprintf (fp, _("Valid To ..: %s\n"), shortbuf);
2883 s = gpgme_pubkey_algo_name (subkey->pubkey_algo);
2888 aval = subkey->length;
2892 fprintf (fp, _("Key Type ..: %s, %lu bit %s\n"), "PGP", aval, s);
2894 fprintf (fp, _("Key Usage .: "));
2897 if (subkey->can_encrypt) {
2898 fprintf (fp, "%s%s", delim, _("encryption"));
2901 if (subkey->can_sign) {
2902 fprintf (fp, "%s%s", delim, _("signing"));
2905 if (subkey->can_certify) {
2906 fprintf (fp, "%s%s", delim, _("certification"));
2914 setlocale (LC_TIME, "C");
2918 /* Show detailed information about the selected key */
2919 static void verify_key (crypt_key_t * key)
2922 char cmd[LONG_STRING], tempfile[_POSIX_PATH_MAX];
2924 gpgme_ctx_t listctx = NULL;
2926 gpgme_key_t k = NULL;
2929 fp = m_tempfile (tempfile, sizeof(tempfile), NONULL(MCore.tmpdir), NULL);
2931 mutt_perror (_("Can't create temporary file"));
2934 mutt_message _("Collecting data...");
2936 print_key_info (key->kobj, fp);
2938 err = gpgme_new (&listctx);
2940 fprintf (fp, "Internal error: can't create gpgme context: %s\n",
2941 gpgme_strerror (err));
2944 if ((key->flags & KEYFLAG_ISX509))
2945 gpgme_set_protocol (listctx, GPGME_PROTOCOL_CMS);
2949 while ((s = k->chain_id) && k->subkeys && m_strcmp(s, k->subkeys->fpr)) {
2951 err = gpgme_op_keylist_start (listctx, s, 0);
2952 gpgme_key_release (k);
2955 err = gpgme_op_keylist_next (listctx, &k);
2957 fprintf (fp, _("Error finding issuer key: %s\n"), gpgme_strerror (err));
2960 gpgme_op_keylist_end (listctx);
2962 print_key_info (k, fp);
2965 fputs (_("Error: certification chain to long - stopping here\n"), fp);
2971 gpgme_key_release (k);
2972 gpgme_release (listctx);
2974 mutt_clear_error ();
2975 snprintf (cmd, sizeof (cmd), _("Key ID: 0x%s"), crypt_keyid (key));
2976 mutt_do_pager (cmd, tempfile, 0, NULL);
2979 /* Implementation of `findkeys'. */
2981 /* Convert string_list_t into a pattern string suitable to be passed to GPGME.
2982 We need to convert spaces in an item into a '+' and '%' into
2984 static char *list_to_pattern (string_list_t * list)
2992 for (l = list; l; l = l->next) {
2993 for (s = l->data; *s; s++) {
2998 n++; /* delimiter or end of string */
3000 n++; /* make sure to allocate at least one byte */
3001 pattern = p = p_new(char, n);
3002 for (l = list; l; l = l->next) {
3007 for (s = l->data; *s; s++) {
3013 else if (*s == '+') {
3029 /* Return a list of keys which are candidates for the selection.
3030 Select by looking at the HINTS list. */
3031 static crypt_key_t *get_candidates (string_list_t * hints, unsigned int app,
3034 crypt_key_t *db, *k, **kend;
3040 gpgme_user_id_t uid = NULL;
3042 pattern = list_to_pattern (hints);
3046 err = gpgme_new (&ctx);
3048 mutt_error (_("gpgme_new failed: %s"), gpgme_strerror (err));
3056 if ((app & APPLICATION_PGP)) {
3057 /* Its all a mess. That old GPGME expects different things
3058 depending on the protocol. For gpg we don' t need percent
3059 escaped pappert but simple strings passed in an array to the
3060 keylist_ext_start function. */
3065 for (l = hints, n = 0; l; l = l->next) {
3066 if (l->data && *l->data)
3072 patarr = p_new(char *, n + 1);
3073 for (l = hints, n = 0; l; l = l->next) {
3074 if (l->data && *l->data)
3075 patarr[n++] = m_strdup(l->data);
3078 err = gpgme_op_keylist_ext_start (ctx, (const char **) patarr, secret, 0);
3079 for (n = 0; patarr[n]; n++)
3080 p_delete(&patarr[n]);
3083 mutt_error (_("gpgme_op_keylist_start failed: %s"), gpgme_strerror (err));
3084 gpgme_release (ctx);
3089 while (!(err = gpgme_op_keylist_next (ctx, &key))) {
3090 unsigned int flags = 0;
3092 if (key_check_cap (key, KEY_CAP_CAN_ENCRYPT))
3093 flags |= KEYFLAG_CANENCRYPT;
3094 if (key_check_cap (key, KEY_CAP_CAN_SIGN))
3095 flags |= KEYFLAG_CANSIGN;
3097 for (idx = 0, uid = key->uids; uid; idx++, uid = uid->next) {
3098 k = p_new(crypt_key_t, 1);
3107 if (gpg_err_code (err) != GPG_ERR_EOF)
3108 mutt_error (_("gpgme_op_keylist_next failed: %s"), gpgme_strerror (err));
3109 gpgme_op_keylist_end (ctx);
3114 if ((app & APPLICATION_SMIME)) {
3115 /* and now look for x509 certificates */
3116 gpgme_set_protocol (ctx, GPGME_PROTOCOL_CMS);
3117 err = gpgme_op_keylist_start (ctx, pattern, 0);
3119 mutt_error (_("gpgme_op_keylist_start failed: %s"), gpgme_strerror (err));
3120 gpgme_release (ctx);
3125 while (!(err = gpgme_op_keylist_next (ctx, &key))) {
3126 unsigned int flags = KEYFLAG_ISX509;
3128 if (key_check_cap (key, KEY_CAP_CAN_ENCRYPT))
3129 flags |= KEYFLAG_CANENCRYPT;
3130 if (key_check_cap (key, KEY_CAP_CAN_SIGN))
3131 flags |= KEYFLAG_CANSIGN;
3133 for (idx = 0, uid = key->uids; uid; idx++, uid = uid->next) {
3134 k = p_new(crypt_key_t, 1);
3143 if (gpg_err_code (err) != GPG_ERR_EOF)
3144 mutt_error (_("gpgme_op_keylist_next failed: %s"), gpgme_strerror (err));
3145 gpgme_op_keylist_end (ctx);
3148 gpgme_release (ctx);
3153 /* Add the string STR to the list HINTS. This list is later used to
3155 static string_list_t *crypt_add_string_to_hints (string_list_t * hints, const char *str)
3160 if ((scratch = m_strdup(str)) == NULL)
3163 for (t = strtok (scratch, " ,.:\"()<>\n"); t;
3164 t = strtok (NULL, " ,.:\"()<>\n")) {
3165 if (m_strlen(t) > 3)
3166 hints = mutt_add_list(hints, t);
3173 /* Display a menu to select a key from the array KEYS. FORCED_VALID
3174 will be set to true on return if the user did override the the
3176 static crypt_key_t *crypt_select_key (crypt_key_t * keys,
3177 address_t * p, const char *s,
3178 unsigned int app, int *forced_valid)
3181 crypt_key_t **key_table;
3184 char helpstr[STRING], buf[LONG_STRING];
3186 int (*f) (const void *, const void *);
3187 int menu_to_use = 0;
3192 /* build the key table */
3195 for (k = keys; k; k = k->next) {
3196 if (!option (OPTPGPSHOWUNUSABLE) && (k->flags & KEYFLAG_CANTUSE)) {
3203 p_realloc(&key_table, keymax);
3209 if (!i && unusable) {
3210 mutt_error _("All matching keys are marked expired/revoked.");
3216 switch (PgpSortKeys & SORT_MASK) {
3218 f = crypt_compare_date;
3221 f = crypt_compare_keyid;
3224 f = crypt_compare_address;
3228 f = crypt_compare_trust;
3231 qsort (key_table, i, sizeof (crypt_key_t *), f);
3233 if (app & APPLICATION_PGP)
3234 menu_to_use = MENU_KEY_SELECT_PGP;
3235 else if (app & APPLICATION_SMIME)
3236 menu_to_use = MENU_KEY_SELECT_SMIME;
3239 mutt_make_help (buf, sizeof (buf), _("Exit "), menu_to_use, OP_EXIT);
3240 m_strcat(helpstr, sizeof(helpstr), buf);
3241 mutt_make_help (buf, sizeof (buf), _("Select "), menu_to_use,
3242 OP_GENERIC_SELECT_ENTRY);
3243 m_strcat(helpstr, sizeof(helpstr), buf);
3244 mutt_make_help (buf, sizeof (buf), _("Check key "),
3245 menu_to_use, OP_VERIFY_KEY);
3246 m_strcat(helpstr, sizeof(helpstr), buf);
3247 mutt_make_help (buf, sizeof (buf), _("Help"), menu_to_use, OP_HELP);
3248 m_strcat(helpstr, sizeof(helpstr), buf);
3250 menu = mutt_new_menu ();
3252 menu->make_entry = crypt_entry;
3253 menu->menu = menu_to_use;
3254 menu->help = helpstr;
3255 menu->data = key_table;
3260 if ((app & APPLICATION_PGP) && (app & APPLICATION_SMIME))
3261 ts = _("PGP and S/MIME keys matching");
3262 else if ((app & APPLICATION_PGP))
3263 ts = _("PGP keys matching");
3264 else if ((app & APPLICATION_SMIME))
3265 ts = _("S/MIME keys matching");
3267 ts = _("keys matching");
3270 snprintf (buf, sizeof (buf), _("%s <%s>."), ts, p->mailbox);
3272 snprintf (buf, sizeof (buf), _("%s \"%s\"."), ts, s);
3276 mutt_clear_error ();
3280 switch (mutt_menuLoop (menu)) {
3282 verify_key (key_table[menu->current]);
3283 menu->redraw = REDRAW_FULL;
3287 mutt_message ("%s", key_table[menu->current]->uid);
3290 case OP_GENERIC_SELECT_ENTRY:
3291 /* FIXME make error reporting more verbose - this should be
3292 easy because gpgme provides more information */
3293 if (option (OPTPGPCHECKTRUST)) {
3294 if (!crypt_key_is_valid (key_table[menu->current])) {
3295 mutt_error _("This key can't be used: "
3296 "expired/disabled/revoked.");
3301 if (option (OPTPGPCHECKTRUST) &&
3302 (!crypt_id_is_valid (key_table[menu->current])
3303 || !crypt_id_is_strong (key_table[menu->current]))) {
3305 char buff[LONG_STRING];
3307 if (key_table[menu->current]->flags & KEYFLAG_CANTUSE)
3308 s = N_("ID is expired/disabled/revoked.");
3310 gpgme_validity_t val = GPGME_VALIDITY_UNKNOWN;
3311 gpgme_user_id_t uid = NULL;
3316 uid = key_table[menu->current]->kobj->uids;
3317 for (j = 0; (j < key_table[menu->current]->idx) && uid;
3318 j++, uid = uid->next);
3320 val = uid->validity;
3323 case GPGME_VALIDITY_UNKNOWN:
3324 case GPGME_VALIDITY_UNDEFINED:
3325 warn_s = N_("ID has undefined validity.");
3327 case GPGME_VALIDITY_NEVER:
3328 warn_s = N_("ID is not valid.");
3330 case GPGME_VALIDITY_MARGINAL:
3331 warn_s = N_("ID is only marginally valid.");
3333 case GPGME_VALIDITY_FULL:
3334 case GPGME_VALIDITY_ULTIMATE:
3338 snprintf (buff, sizeof (buff),
3339 _("%s Do you really want to use the key?"), _(warn_s));
3341 if (mutt_yesorno (buff, 0) != 1) {
3342 mutt_clear_error ();
3349 k = crypt_copy_key (key_table[menu->current]);
3360 mutt_menuDestroy (&menu);
3361 p_delete(&key_table);
3363 set_option (OPTNEEDREDRAW);
3368 static crypt_key_t *crypt_getkeybyaddr (address_t * a, short abilities,
3369 unsigned int app, int *forced_valid)
3372 string_list_t *hints = NULL;
3377 int this_key_has_strong;
3378 int this_key_has_weak;
3379 int this_key_has_invalid;
3382 crypt_key_t *keys, *k;
3383 crypt_key_t *the_valid_key = NULL;
3384 crypt_key_t *matches = NULL;
3385 crypt_key_t **matches_endp = &matches;
3389 if (a && a->mailbox)
3390 hints = crypt_add_string_to_hints (hints, a->mailbox);
3391 if (a && a->personal)
3392 hints = crypt_add_string_to_hints (hints, a->personal);
3394 mutt_message (_("Looking for keys matching \"%s\"..."), a->mailbox);
3395 keys = get_candidates (hints, app, (abilities & KEYFLAG_CANSIGN));
3397 string_list_wipe(&hints);
3402 for (k = keys; k; k = k->next) {
3403 if (abilities && !(k->flags & abilities)) {
3407 this_key_has_weak = 0; /* weak but valid match */
3408 this_key_has_invalid = 0; /* invalid match */
3409 this_key_has_strong = 0; /* strong and valid match */
3410 match = 0; /* any match */
3412 r = rfc822_parse_adrlist (NULL, k->uid);
3413 for (p = r; p; p = p->next) {
3414 int validity = crypt_id_matches_addr (a, p, k);
3416 if (validity & CRYPT_KV_MATCH) /* something matches */
3419 /* is this key a strong candidate? */
3420 if ((validity & CRYPT_KV_VALID)
3421 && (validity & CRYPT_KV_STRONGID)
3422 && (validity & CRYPT_KV_ADDR)) {
3423 if (the_valid_key && the_valid_key != k)
3426 this_key_has_strong = 1;
3428 else if ((validity & CRYPT_KV_MATCH)
3429 && !(validity & CRYPT_KV_VALID))
3430 this_key_has_invalid = 1;
3431 else if ((validity & CRYPT_KV_MATCH)
3432 && (!(validity & CRYPT_KV_STRONGID)
3433 || !(validity & CRYPT_KV_ADDR)))
3434 this_key_has_weak = 1;
3436 address_list_wipe(&r);
3441 if (!this_key_has_strong && this_key_has_invalid)
3443 if (!this_key_has_strong && this_key_has_weak)
3446 *matches_endp = tmp = crypt_copy_key (k);
3447 matches_endp = &tmp->next;
3448 the_valid_key = tmp;
3452 crypt_free_key (&keys);
3455 if (the_valid_key && !multi && !weak
3456 && !(invalid && option (OPTPGPSHOWUNUSABLE))) {
3458 * There was precisely one strong match on a valid ID, there
3459 * were no valid keys with weak matches, and we aren't
3460 * interested in seeing invalid keys.
3462 * Proceed without asking the user.
3464 k = crypt_copy_key (the_valid_key);
3468 * Else: Ask the user.
3470 k = crypt_select_key (matches, a, NULL, app, forced_valid);
3472 crypt_free_key (&matches);
3481 static crypt_key_t *crypt_getkeybystr (const char *p, short abilities,
3482 unsigned int app, int *forced_valid)
3484 string_list_t *hints = NULL;
3486 crypt_key_t *matches = NULL;
3487 crypt_key_t **matches_endp = &matches;
3491 mutt_message (_("Looking for keys matching \"%s\"..."), p);
3495 hints = crypt_add_string_to_hints (hints, p);
3496 keys = get_candidates (hints, app, (abilities & KEYFLAG_CANSIGN));
3497 string_list_wipe(&hints);
3502 for (k = keys; k; k = k->next) {
3503 if (abilities && !(k->flags & abilities))
3508 if (!*p || !m_strcasecmp(p, crypt_keyid (k))
3509 || (!m_strncasecmp(p, "0x", 2)
3510 && !m_strcasecmp(p + 2, crypt_keyid (k)))
3511 || (option (OPTPGPLONGIDS)
3512 && !m_strncasecmp(p, "0x", 2)
3513 && !m_strcasecmp(p + 2, crypt_keyid (k) + 8))
3514 || m_stristr(k->uid, p)) {
3517 *matches_endp = tmp = crypt_copy_key (k);
3518 matches_endp = &tmp->next;
3522 crypt_free_key (&keys);
3525 k = crypt_select_key (matches, NULL, p, app, forced_valid);
3526 crypt_free_key (&matches);
3533 /* Display TAG as a prompt to ask for a key. If WHATFOR is not null
3534 use it as default and store it under that label as the next
3535 default. ABILITIES describe the required key abilities (sign,
3536 encrypt) and APP the type of the requested key; ether S/MIME or
3537 PGP. Return a copy of the key or NULL if not found. */
3538 static crypt_key_t *crypt_ask_for_key (char *tag,
3541 unsigned int app, int *forced_valid)
3545 struct crypt_cache *l = NULL;
3549 forced_valid = &dummy;
3551 mutt_clear_error ();
3557 for (l = id_defaults; l; l = l->next)
3558 if (!m_strcasecmp(whatfor, l->what)) {
3559 m_strcpy(resp, sizeof(resp), NONULL(l->dflt));
3567 if (mutt_get_field (tag, resp, sizeof (resp), M_CLEAR) != 0)
3572 m_strreplace(&l->dflt, resp);
3574 l = p_new(struct crypt_cache, 1);
3575 l->next = id_defaults;
3577 l->what = m_strdup(whatfor);
3578 l->dflt = m_strdup(resp);
3582 if ((key = crypt_getkeybystr (resp, abilities, app, forced_valid)))
3590 /* This routine attempts to find the keyids of the recipients of a
3591 message. It returns NULL if any of the keys can not be found. */
3592 static char *find_keys (address_t * to, address_t * cc, address_t * bcc,
3595 char *keylist = NULL, *t;
3597 ssize_t keylist_size = 0;
3598 ssize_t keylist_used = 0;
3599 address_t *tmp = NULL, *addr = NULL;
3600 address_t **last = &tmp;
3603 crypt_key_t *k_info, *key;
3604 const char *fqdn = mutt_fqdn (1);
3607 *r_application = APPLICATION_PGP | APPLICATION_SMIME;
3610 for (i = 0; i < 3; i++) {
3625 *last = address_list_dup (p);
3627 last = &((*last)->next);
3630 rfc822_qualify(tmp, fqdn);
3631 address_list_uniq(tmp);
3633 for (p = tmp; p; p = p->next) {
3634 char buf[LONG_STRING];
3635 int forced_valid = 0;
3640 if ((keyID = mutt_crypt_hook (p)) != NULL) {
3643 snprintf (buf, sizeof (buf), _("Use keyID = \"%s\" for %s?"),
3645 if ((r = mutt_yesorno (buf, M_YES)) == M_YES) {
3646 /* check for e-mail address */
3647 if ((t = strchr (keyID, '@')) &&
3648 (addr = rfc822_parse_adrlist (NULL, keyID))) {
3649 rfc822_qualify(addr, fqdn);
3653 k_info = crypt_getkeybystr (keyID, KEYFLAG_CANENCRYPT,
3654 app, &forced_valid);
3659 address_list_wipe(&tmp);
3660 address_list_wipe(&addr);
3666 && (k_info = crypt_getkeybyaddr (q, KEYFLAG_CANENCRYPT,
3667 app, &forced_valid)) == NULL) {
3668 snprintf (buf, sizeof (buf), _("Enter keyID for %s: "), q->mailbox);
3670 if ((key = crypt_ask_for_key (buf, q->mailbox, KEYFLAG_CANENCRYPT,
3672 &forced_valid)) == NULL) {
3674 address_list_wipe(&tmp);
3675 address_list_wipe(&addr);
3683 const char *s = crypt_fpr (key);
3685 keylist_size += m_strlen(s) + 4 + 1;
3686 p_realloc(&keylist, keylist_size);
3687 sprintf (keylist + keylist_used, "%s0x%s%s",
3688 keylist_used ? " " : "", s, forced_valid ? "!" : "");
3690 keylist_used = m_strlen(keylist);
3692 crypt_free_key (&key);
3693 address_list_wipe(&addr);
3695 address_list_wipe(&tmp);
3699 int crypt_get_keys (HEADER * msg, char **keylist)
3701 /* Do a quick check to make sure that we can find all of the encryption
3702 * keys if the user has requested this service.
3707 if (msg->security & ENCRYPT) {
3708 if (msg->security & APPLICATION_PGP) {
3709 set_option(OPTPGPCHECKTRUST);
3710 *keylist = find_keys(msg->env->to, msg->env->cc, msg->env->bcc,
3712 unset_option(OPTPGPCHECKTRUST);
3717 if (msg->security & APPLICATION_SMIME) {
3718 *keylist = find_keys(msg->env->to, msg->env->cc, msg->env->bcc,
3729 int crypt_send_menu (HEADER * msg, int *redraw, int is_smime)
3732 char input_signas[STRING];
3735 if (msg->security & APPLICATION_PGP)
3737 else if (msg->security & APPLICATION_SMIME)
3742 mutt_multi_choice (_
3743 ("S/MIME (e)ncrypt, (s)ign, sign (a)s, (b)oth, (p)gp or (c)lear?"),
3747 mutt_multi_choice (_
3748 ("PGP (e)ncrypt, (s)ign, sign (a)s, (b)oth, s/(m)ime or (c)lear?"),
3752 case 1: /* (e)ncrypt */
3753 msg->security |= (is_smime ? SMIMEENCRYPT : PGPENCRYPT);
3754 msg->security &= ~(is_smime ? SMIMESIGN : PGPSIGN);
3757 case 2: /* (s)ign */
3758 msg->security |= (is_smime ? SMIMESIGN : PGPSIGN);
3759 msg->security &= ~(is_smime ? SMIMEENCRYPT : PGPENCRYPT);
3762 case 3: /* sign (a)s */
3763 if ((p = crypt_ask_for_key (_("Sign as: "), NULL, KEYFLAG_CANSIGN,
3764 is_smime ? APPLICATION_SMIME :
3765 APPLICATION_PGP, NULL))) {
3766 snprintf (input_signas, sizeof (input_signas), "0x%s", crypt_keyid (p));
3767 m_strreplace(is_smime ? &SmimeDefaultKey : &PgpSignAs,
3769 crypt_free_key (&p);
3771 msg->security |= (is_smime ? SMIMESIGN : PGPSIGN);
3773 *redraw = REDRAW_FULL;
3776 case 4: /* (b)oth */
3778 (is_smime ? (SMIMEENCRYPT | SMIMESIGN) : (PGPENCRYPT | PGPSIGN));
3781 case 5: /* (p)gp or s/(m)ime */
3782 is_smime = !is_smime;
3785 case 6: /* (c)lear */
3786 return msg->security = 0;
3790 msg->security &= ~APPLICATION_PGP;
3791 msg->security |= APPLICATION_SMIME;
3793 msg->security &= ~APPLICATION_SMIME;
3794 msg->security |= APPLICATION_PGP;
3797 return msg->security;
3800 int crypt_smime_verify_sender (HEADER * h)
3802 address_t *sender = NULL;
3803 unsigned int ret = 1;
3806 h->env->from = mutt_expand_aliases (h->env->from);
3807 sender = h->env->from;
3809 else if (h->env->sender) {
3810 h->env->sender = mutt_expand_aliases (h->env->sender);
3811 sender = h->env->sender;
3815 if (signature_key) {
3816 gpgme_key_t key = signature_key;
3817 gpgme_user_id_t uid = NULL;
3818 int sender_length = 0;
3821 sender_length = m_strlen(sender->mailbox);
3822 for (uid = key->uids; uid && ret; uid = uid->next) {
3823 uid_length = m_strlen(uid->email);
3824 if (1 && (uid->email[0] == '<')
3825 && (uid->email[uid_length - 1] == '>')
3826 && (uid_length == sender_length + 2)
3827 && (!m_strncmp (uid->email + 1, sender->mailbox, sender_length)))
3832 mutt_any_key_to_continue ("Failed to verify sender");
3835 mutt_any_key_to_continue ("Failed to figure out sender");
3837 if (signature_key) {
3838 gpgme_key_release (signature_key);
3839 signature_key = NULL;
3845 static void crypt_invoke_import(FILE *stream, int smime)
3847 gpgme_ctx_t ctx = create_gpgme_context(smime);
3851 err = gpgme_data_new_from_stream(&data, stream);
3853 mutt_error (_("error allocating data object: %s\n"), gpgme_strerror (err));
3858 err = gpgme_op_import(ctx, data);
3860 mutt_error(_("error importing gpg data: %s\n"), gpgme_strerror(err));
3861 gpgme_data_release(data);
3866 gpgme_data_release(data);
3871 static void pgp_extract_keys_from_attachment(FILE * fp, BODY * top)
3874 FILE *tmpfp = tmpfile();
3876 if (tmpfp == NULL) {
3877 mutt_perror (_("Can't create temporary file"));
3884 mutt_body_handler(top, &s);
3887 crypt_invoke_import(tmpfp, 0);
3891 void crypt_pgp_extract_keys_from_attachment_list(FILE * fp, int tag, BODY * top)
3894 set_option (OPTDONTHANDLEPGPKEYS);
3896 for (; top; top = top->next) {
3897 if (!tag || top->tagged)
3898 pgp_extract_keys_from_attachment (fp, top);
3904 unset_option (OPTDONTHANDLEPGPKEYS);
3910 /* fixme: needs documentation. */
3911 void crypt_pgp_invoke_getkeys (address_t * addr)
3915 /* Generate a PGP public key attachment. */
3916 BODY *crypt_pgp_make_key_attachment (char *tempf)
3923 /* fixme: Needs documentation. */
3924 void crypt_smime_getkeys (ENVELOPE * env)
3928 /***************************************************************************/
3930 void crypt_invoke_message (int type)
3932 if (type & APPLICATION_PGP) {
3933 mutt_message _("Invoking PGP...");
3935 else if (type & APPLICATION_SMIME) {
3936 mutt_message _("Invoking S/MIME...");
3940 int mutt_protect (HEADER * msg, char *keylist)
3942 BODY *pbody = NULL, *tmp_pbody = NULL;
3943 BODY *tmp_smime_pbody = NULL;
3944 BODY *tmp_pgp_pbody = NULL;
3945 int flags = msg->security;
3950 tmp_smime_pbody = msg->content;
3951 tmp_pgp_pbody = msg->content;
3953 if (msg->security & SIGN) {
3954 if (msg->security & APPLICATION_SMIME) {
3955 if (!(tmp_pbody = sign_message(msg->content, 1)))
3957 pbody = tmp_smime_pbody = tmp_pbody;
3960 if ((msg->security & APPLICATION_PGP)
3961 && (!(flags & ENCRYPT) || option (OPTPGPRETAINABLESIG))) {
3962 if (!(tmp_pbody = sign_message(msg->content, 0)))
3966 pbody = tmp_pgp_pbody = tmp_pbody;
3969 if ((msg->security & APPLICATION_SMIME)
3970 && (msg->security & APPLICATION_PGP)) {
3971 /* here comes the draft ;-) */
3976 if (msg->security & ENCRYPT) {
3977 if ((msg->security & APPLICATION_SMIME)) {
3978 if (!(tmp_pbody = crypt_smime_build_smime_entity (tmp_smime_pbody,
3980 /* signed ? free it! */
3983 /* free tmp_body if messages was signed AND encrypted ... */
3984 if (tmp_smime_pbody != msg->content && tmp_smime_pbody != tmp_pbody) {
3985 /* detatch and dont't delete msg->content,
3986 which tmp_smime_pbody->parts after signing. */
3987 tmp_smime_pbody->parts = tmp_smime_pbody->parts->next;
3988 msg->content->next = NULL;
3989 body_list_wipe(&tmp_smime_pbody);
3994 if ((msg->security & APPLICATION_PGP)) {
3995 if (!(pbody = crypt_pgp_encrypt_message (tmp_pgp_pbody, keylist,
3998 /* did we perform a retainable signature? */
3999 if (flags != msg->security) {
4000 /* remove the outer multipart layer */
4001 tmp_pgp_pbody = mutt_remove_multipart (tmp_pgp_pbody);
4002 /* get rid of the signature */
4003 body_list_wipe(&tmp_pgp_pbody->next);
4009 /* destroy temporary signature envelope when doing retainable
4013 if (flags != msg->security) {
4014 tmp_pgp_pbody = mutt_remove_multipart (tmp_pgp_pbody);
4015 body_list_wipe(&tmp_pgp_pbody->next);
4021 msg->content = pbody;
4027 int crypt_query (BODY * m)
4034 if (m->type == TYPEAPPLICATION) {
4035 t |= mutt_is_application_pgp (m);
4037 t |= mutt_is_application_smime (m);
4038 if (t && m->goodsig)
4043 else if (m->type == TYPETEXT) {
4044 t |= mutt_is_application_pgp (m);
4045 if (t && m->goodsig)
4049 if (m->type == TYPEMULTIPART) {
4050 t |= mutt_is_multipart_encrypted (m);
4051 t |= mutt_is_multipart_signed (m);
4053 if (t && m->goodsig)
4057 if (m->type == TYPEMULTIPART || m->type == TYPEMESSAGE) {
4061 u = m->parts ? ~0 : 0; /* Bits set in all parts */
4062 w = 0; /* Bits set in any part */
4064 for (p = m->parts; p; p = p->next) {
4065 v = crypt_query (p);
4069 t |= u | (w & ~GOODSIGN);
4071 if ((w & GOODSIGN) && !(u & GOODSIGN))
4079 static void crypt_write_signed(BODY * a, STATE * s, FILE *fp)
4085 fseeko (s->fpin, a->hdr_offset, 0);
4086 bytes = a->length + a->offset - a->hdr_offset;
4089 if ((c = fgetc (s->fpin)) == EOF)
4097 if (c == '\n' && !hadcr)
4106 static void extract_keys_aux(FILE *fpout, HEADER *h)
4108 mutt_parse_mime_message (Context, h);
4111 if (h->security & APPLICATION_PGP) {
4112 mutt_copy_message(fpout, Context, h, M_CM_DECODE | M_CM_CHARCONV, 0);
4115 mutt_endwin (_("Trying to extract PGP keys...\n"));
4118 if (h->security & APPLICATION_SMIME) {
4119 if (h->security & ENCRYPT)
4120 mutt_copy_message (fpout, Context, h, M_CM_NOHEADER
4121 | M_CM_DECODE_CRYPT | M_CM_DECODE_SMIME, 0);
4123 mutt_copy_message(fpout, Context, h, 0, 0);
4126 mutt_message (_("Trying to extract S/MIME certificates...\n"));
4130 crypt_invoke_import(fpout, h->security & APPLICATION_SMIME);
4133 void crypt_extract_keys_from_messages(HEADER * h)
4135 FILE *tmpfp = tmpfile();
4137 mutt_error(_("Could not create temporary file"));
4141 set_option(OPTDONTHANDLEPGPKEYS);
4144 for (i = 0; i < Context->vcount; i++) {
4145 if (!Context->hdrs[Context->v2r[i]]->tagged)
4147 extract_keys_aux(tmpfp, Context->hdrs[Context->v2r[i]]);
4150 extract_keys_aux(tmpfp, h);
4152 unset_option(OPTDONTHANDLEPGPKEYS);
4156 mutt_any_key_to_continue(NULL);
4161 static void crypt_fetch_signatures (BODY ***signatures, BODY * a, int *n)
4163 for (; a; a = a->next) {
4164 if (a->type == TYPEMULTIPART)
4165 crypt_fetch_signatures (signatures, a->parts, n);
4168 p_realloc(signatures, *n + 6);
4170 (*signatures)[(*n)++] = a;
4177 * This routine verifies a "multipart/signed" body.
4180 int mutt_signed_handler (BODY * a, STATE * s)
4182 unsigned major, minor;
4184 int rc, i, goodsig = 1, sigcnt = 0;
4187 protocol = parameter_getval(a->parameter, "protocol");
4190 switch (mime_which_token(protocol, -1)) {
4191 case MIME_APPLICATION_PGP_SIGNATURE:
4192 major = TYPEAPPLICATION;
4193 minor = MIME_PGP_SIGNATURE;
4195 case MIME_APPLICATION_X_PKCS7_SIGNATURE:
4196 major = TYPEAPPLICATION;
4197 minor = MIME_X_PKCS7_SIGNATURE;
4199 case MIME_APPLICATION_PKCS7_SIGNATURE:
4200 major = TYPEAPPLICATION;
4201 minor = MIME_PKCS7_SIGNATURE;
4203 case MIME_MULTIPART_MIXED:
4204 major = TYPEMULTIPART;
4209 state_printf(s, _("[-- Error: "
4210 "Unknown multipart/signed protocol %s! --]\n\n"),
4212 return mutt_body_handler (a, s);
4215 /* consistency check */
4216 if (!(a && a->next && a->next->type == major &&
4217 mime_which_token(a->next->subtype, -1) == minor))
4219 state_attach_puts(_("[-- Error: "
4220 "Inconsistent multipart/signed structure! --]\n\n"),
4222 return mutt_body_handler (a, s);
4225 if (s->flags & M_DISPLAY) {
4228 crypt_fetch_signatures (&sigs, a->next, &sigcnt);
4230 FILE *tmpfp = tmpfile();
4233 mutt_error(_("Could not create temporary file"));
4235 crypt_write_signed(a, s, tmpfp);
4237 for (i = 0; i < sigcnt; i++) {
4238 if (sigs[i]->type == TYPEAPPLICATION) {
4241 switch ((subtype = mime_which_token(sigs[i]->subtype, -1))) {
4242 case MIME_PGP_SIGNATURE:
4243 case MIME_X_PKCS7_SIGNATURE:
4244 case MIME_PKCS7_SIGNATURE:
4245 if (crypt_verify_one(sigs[i], s, tmpfp, subtype != MIME_PGP_SIGNATURE) != 0)
4256 state_printf(s, _("[-- Warning: "
4257 "We can't verify %s/%s signatures. --]\n\n"),
4258 TYPE (sigs[i]), sigs[i]->subtype);
4262 b->goodsig = goodsig;
4263 b->badsig = !goodsig;
4265 /* Now display the signed body */
4266 state_attach_puts(_("[-- The following data is signed --]\n\n"), s);
4270 state_attach_puts(_("[-- Warning: Can't find any signatures. --]\n\n"),
4275 rc = mutt_body_handler (a, s);
4277 if (s->flags & M_DISPLAY && sigcnt)
4278 state_attach_puts (_("\n[-- End of signed data --]\n"), s);