2 * Copyright notice from original mutt:
3 * crypt-gpgme.c - GPGME based crypto operations
4 * Copyright (C) 1996,1997 Michael R. Elkins <me@cs.hmc.edu>
5 * Copyright (C) 1998,1999,2000 Thomas Roessler <roessler@guug.de>
6 * Copyright (C) 2001 Thomas Roessler <roessler@guug.de>
7 * Oliver Ehli <elmy@acm.org>
8 * Copyright (C) 2002, 2003, 2004 g10 Code GmbH
10 * This file is part of mutt-ng, see http://www.muttng.org/.
11 * It's licensed under the GNU General Public License,
12 * please see the file GPL in the top level source directory.
15 #include <lib-lib/lib-lib.h>
20 #ifdef HAVE_LANGINFO_D_T_FMT
21 # include <langinfo.h>
23 #ifdef HAVE_SYS_RESOURCE_H
24 # include <sys/resource.h>
29 #include <lib-mime/mime.h>
31 #include <lib-ui/curses.h>
32 #include <lib-ui/enter.h>
33 #include <lib-ui/menu.h>
37 #include <lib-crypt/crypt.h>
41 #include "recvattach.h"
43 #include "crypt-gpgme.h"
48 #define digitp(p) (*(p) >= '0' && *(p) <= '9')
49 #define hexdigitp(a) (digitp (a) \
50 || (*(a) >= 'A' && *(a) <= 'F') \
51 || (*(a) >= 'a' && *(a) <= 'f'))
52 #define xtoi_1(p) (*(p) <= '9'? (*(p)- '0'): \
53 *(p) <= 'F'? (*(p)-'A'+10):(*(p)-'a'+10))
54 #define xtoi_2(p) ((xtoi_1(p) * 16) + xtoi_1((p)+1))
56 /* Values used for comparing addresses. */
57 #define CRYPT_KV_VALID 1
58 #define CRYPT_KV_ADDR 2
59 #define CRYPT_KV_STRING 4
60 #define CRYPT_KV_STRONGID 8
61 #define CRYPT_KV_MATCH (CRYPT_KV_ADDR|CRYPT_KV_STRING)
70 struct crypt_cache *next;
78 /* We work based on user IDs, getting from a user ID to the key is
79 check and does not need any memory (gpgme uses reference counting). */
80 typedef struct crypt_keyinfo {
81 struct crypt_keyinfo *next;
83 int idx; /* and the user ID at this index */
84 const char *uid; /* and for convenience point to this user ID */
85 unsigned int flags; /* global and per uid flags (for convenience) */
88 typedef struct crypt_entry {
94 static struct crypt_cache *id_defaults = NULL;
95 static gpgme_key_t signature_key = NULL;
100 /* Make sure that gpg-agent is running. */
101 if (!getenv ("GPG_AGENT_INFO")) {
102 mutt_error ("\nUsing GPGME backend, although no gpg-agent is running");
103 if (mutt_any_key_to_continue (NULL) == -1)
108 /* Show a message that a backend will be invoked. */
109 void crypt_invoke_message (int type)
111 if (type & APPLICATION_PGP) {
112 mutt_message _("Invoking PGP...");
114 else if (type & APPLICATION_SMIME) {
115 mutt_message _("Invoking S/MIME...");
120 * General helper functions.
123 /* return true when S points to a didgit or letter. */
124 static int digit_or_letter (const unsigned char *s)
126 return ((*s >= '0' && *s <= '9')
127 || (*s >= 'A' && *s <= 'Z')
128 || (*s >= 'a' && *s <= 'z'));
132 /* Print the utf-8 encoded string BUF of length LEN bytes to stream
133 FP. Convert the character set. */
134 static void print_utf8 (FILE * fp, const char *buf, ssize_t len)
138 tstr = p_dupstr(buf, len);
139 mutt_convert_string (&tstr, "utf-8", MCharset.charset, M_ICONV_HOOK_FROM);
149 /* Return the keyID for the key K. Note that this string is valid as
150 long as K is valid */
151 static const char *crypt_keyid (crypt_key_t * k)
153 const char *s = "????????";
155 if (k->kobj && k->kobj->subkeys) {
156 s = k->kobj->subkeys->keyid;
157 if ((!option (OPTPGPLONGIDS)) && (m_strlen(s) == 16))
158 /* Return only the short keyID. */
165 /* Return the hexstring fingerprint from the key K. */
166 static const char *crypt_fpr (crypt_key_t * k)
170 if (k->kobj && k->kobj->subkeys)
171 s = k->kobj->subkeys->fpr;
176 /* Parse FLAGS and return a statically allocated(!) string with them. */
177 static char *crypt_key_abilities (int flags)
181 if (!(flags & KEYFLAG_CANENCRYPT))
183 else if (flags & KEYFLAG_PREFER_SIGNING)
188 if (!(flags & KEYFLAG_CANSIGN))
190 else if (flags & KEYFLAG_PREFER_ENCRYPTION)
200 /* Parse FLAGS and return a character describing the most important flag. */
201 static char crypt_flags (int flags)
203 if (flags & KEYFLAG_REVOKED)
205 else if (flags & KEYFLAG_EXPIRED)
207 else if (flags & KEYFLAG_DISABLED)
209 else if (flags & KEYFLAG_CRITICAL)
215 /* Return a copy of KEY. */
216 static crypt_key_t *crypt_copy_key (crypt_key_t *key)
220 k = p_new(crypt_key_t, 1);
222 gpgme_key_ref (key->kobj);
225 k->flags = key->flags;
230 /* Release all the keys at the address of KEYLIST and set the address
232 static void crypt_free_key (crypt_key_t ** keylist)
235 crypt_key_t *k = (*keylist)->next;
242 /* Return trute when key K is valid. */
243 static int crypt_key_is_valid (crypt_key_t * k)
245 if (k->flags & KEYFLAG_CANTUSE)
250 /* Return true whe validity of KEY is sufficient. */
251 static int crypt_id_is_strong (crypt_key_t * key)
253 gpgme_validity_t val = GPGME_VALIDITY_UNKNOWN;
254 gpgme_user_id_t uid = NULL;
258 if ((key->flags & KEYFLAG_ISX509))
261 for (i = 0, uid = key->kobj->uids; (i < key->idx) && uid;
262 i++, uid = uid->next);
267 case GPGME_VALIDITY_UNKNOWN:
268 case GPGME_VALIDITY_UNDEFINED:
269 case GPGME_VALIDITY_NEVER:
270 case GPGME_VALIDITY_MARGINAL:
274 case GPGME_VALIDITY_FULL:
275 case GPGME_VALIDITY_ULTIMATE:
283 /* Return true when the KEY is valid, i.e. not marked as unusable. */
284 static int crypt_id_is_valid (crypt_key_t * key)
286 return !(key->flags & KEYFLAG_CANTUSE);
289 /* Return a bit vector describing how well the addresses ADDR and
290 U_ADDR match and whether KEY is valid. */
291 static int crypt_id_matches_addr (address_t * addr, address_t * u_addr,
296 if (crypt_id_is_valid (key))
297 rv |= CRYPT_KV_VALID;
299 if (crypt_id_is_strong (key))
300 rv |= CRYPT_KV_STRONGID;
302 if (addr->mailbox && u_addr->mailbox
303 && m_strcasecmp(addr->mailbox, u_addr->mailbox) == 0)
306 if (addr->personal && u_addr->personal
307 && m_strcasecmp(addr->personal, u_addr->personal) == 0)
308 rv |= CRYPT_KV_STRING;
315 * GPGME convenient functions.
318 /* Create a new gpgme context and return it. With FOR_SMIME set to
319 true, the protocol of the context is set to CMS. */
320 static gpgme_ctx_t create_gpgme_context (int for_smime)
325 err = gpgme_new (&ctx);
327 mutt_error (_("error creating gpgme context: %s\n"), gpgme_strerror (err));
333 err = gpgme_set_protocol (ctx, GPGME_PROTOCOL_CMS);
335 mutt_error (_("error enabling CMS protocol: %s\n"), gpgme_strerror (err));
344 /* Create a new gpgme data object. This is a wrapper to die on
346 static gpgme_data_t create_gpgme_data (void)
351 err = gpgme_data_new (&data);
353 mutt_error (_("error creating gpgme data object: %s\n"),
354 gpgme_strerror (err));
361 /* Create a new GPGME Data object from the mail body A. With CONVERT
362 passed as true, the lines are converted to CR,LF if required.
363 Return NULL on error or the gpgme_data_t object on success. */
364 static gpgme_data_t body_to_data_object (BODY * a, int convert)
366 char tempfile[_POSIX_PATH_MAX];
371 fptmp = m_tempfile(tempfile, sizeof(tempfile), NONULL(MCore.tmpdir), NULL);
373 mutt_perror (_("Can't create temporary file"));
377 mutt_write_mime_header (a, fptmp);
379 mutt_write_mime_body (a, fptmp);
383 unsigned char buf[1];
385 data = create_gpgme_data ();
387 while ((c = fgetc (fptmp)) != EOF) {
391 if (c == '\n' && !hadcr) {
393 gpgme_data_write (data, buf, 1);
398 /* FIXME: This is quite suboptimal */
400 gpgme_data_write (data, buf, 1);
402 gpgme_data_seek (data, 0, SEEK_SET);
404 err = gpgme_data_new_from_file (&data, tempfile, 1);
409 mutt_error (_("error allocating data object: %s\n"), gpgme_strerror (err));
416 /* Create a GPGME data object from the stream FP but limit the object
417 to LENGTH bytes starting at OFFSET bytes from the beginning of the
419 static gpgme_data_t file_to_data_object (FILE * fp, long offset, long length)
424 err = gpgme_data_new_from_filepart (&data, NULL, fp, offset, length);
426 mutt_error (_("error allocating data object: %s\n"), gpgme_strerror (err));
433 /* Write a GPGME data object to the stream FP. */
434 static int data_object_to_stream (gpgme_data_t data, FILE * fp)
440 err = ((gpgme_data_seek (data, 0, SEEK_SET) == -1)
441 ? gpgme_error_from_errno (errno) : 0);
443 mutt_error (_("error rewinding data object: %s\n"), gpgme_strerror (err));
447 while ((nread = gpgme_data_read (data, buf, sizeof (buf)))) {
448 /* fixme: we are not really converting CRLF to LF but just
449 skipping CR. Doing it correctly needs a more complex logic */
450 for (p = buf; nread; p++, nread--) {
456 mutt_perror ("[tempfile]");
461 mutt_error (_("error reading data object: %s\n"), strerror (errno));
467 /* Copy a data object to a newly created temporay file and return that
468 filename. Caller must free. With RET_FP not NULL, don't close the
469 stream but return it there. */
470 static char *data_object_to_tempfile (gpgme_data_t data, FILE ** ret_fp)
473 char tempfile[_POSIX_PATH_MAX];
477 fp = m_tempfile(tempfile, sizeof(tempfile), NONULL(MCore.tmpdir), NULL);
479 mutt_perror (_("Can't create temporary file"));
483 err = ((gpgme_data_seek (data, 0, SEEK_SET) == -1)
484 ? gpgme_error_from_errno (errno) : 0);
488 while ((nread = gpgme_data_read (data, buf, sizeof (buf)))) {
489 if (fwrite (buf, nread, 1, fp) != 1) {
490 mutt_perror (_("Can't create temporary file"));
502 mutt_error (_("error reading data object: %s\n"), gpgme_strerror (err));
509 return m_strdup(tempfile);
513 /* Create a GpgmeRecipientSet from the keys in the string KEYLIST.
514 The keys must be space delimited. */
515 static gpgme_key_t *create_recipient_set (const char *keylist,
516 gpgme_protocol_t protocol)
522 gpgme_key_t *rset = NULL;
523 unsigned int rset_n = 0;
524 gpgme_key_t key = NULL;
525 gpgme_ctx_t context = NULL;
527 err = gpgme_new (&context);
529 err = gpgme_set_protocol (context, protocol);
536 for (i = 0; *s && *s != ' ' && i < ssizeof(buf) - 1;)
540 if (i > 1 && buf[i - 1] == '!') {
541 /* The user selected to override the valididy of that
545 err = gpgme_get_key (context, buf, &key, 0);
547 key->uids->validity = GPGME_VALIDITY_FULL;
551 err = gpgme_get_key (context, buf, &key, 0);
554 p_realloc(&rset, rset_n + 1);
555 rset[rset_n++] = key;
558 mutt_error (_("error adding recipient `%s': %s\n"),
559 buf, gpgme_strerror (err));
567 /* NULL terminate. */
568 p_realloc(&rset, rset_n + 1);
569 rset[rset_n++] = NULL;
572 gpgme_release (context);
578 /* Make sure that the correct signer is set. Returns 0 on success. */
579 static int set_signer (gpgme_ctx_t ctx, int for_smime)
581 char *signid = for_smime ? SmimeDefaultKey : PgpSignAs;
584 gpgme_key_t key, key2;
586 if (!signid || !*signid)
589 listctx = create_gpgme_context (for_smime);
590 err = gpgme_op_keylist_start (listctx, signid, 1);
592 err = gpgme_op_keylist_next (listctx, &key);
594 gpgme_release (listctx);
595 mutt_error (_("secret key `%s' not found: %s\n"),
596 signid, gpgme_strerror (err));
599 err = gpgme_op_keylist_next (listctx, &key2);
601 gpgme_key_release (key);
602 gpgme_key_release (key2);
603 gpgme_release (listctx);
604 mutt_error (_("ambiguous specification of secret key `%s'\n"), signid);
607 gpgme_op_keylist_end (listctx);
608 gpgme_release (listctx);
610 gpgme_signers_clear (ctx);
611 err = gpgme_signers_add (ctx, key);
612 gpgme_key_release (key);
614 mutt_error (_("error setting secret key `%s': %s\n"),
615 signid, gpgme_strerror (err));
622 /* Encrypt the gpgme data object PLAINTEXT to the recipients in RSET
623 and return an allocated filename to a temporary file containing the
624 enciphered text. With USE_SMIME set to true, the smime backend is
625 used. With COMBINED_SIGNED a PGP message is signed and
626 encrypted. Returns NULL in case of error */
627 static char *encrypt_gpgme_object (gpgme_data_t plaintext, gpgme_key_t * rset,
628 int use_smime, int combined_signed)
632 gpgme_data_t ciphertext;
635 ctx = create_gpgme_context (use_smime);
637 gpgme_set_armor (ctx, 1);
639 ciphertext = create_gpgme_data ();
641 if (combined_signed) {
642 if (set_signer (ctx, use_smime)) {
643 gpgme_data_release (ciphertext);
647 err = gpgme_op_encrypt_sign (ctx, rset, GPGME_ENCRYPT_ALWAYS_TRUST,
648 plaintext, ciphertext);
651 err = gpgme_op_encrypt (ctx, rset, GPGME_ENCRYPT_ALWAYS_TRUST,
652 plaintext, ciphertext);
653 mutt_need_hard_redraw ();
655 mutt_error (_("error encrypting data: %s\n"), gpgme_strerror (err));
656 gpgme_data_release (ciphertext);
663 outfile = data_object_to_tempfile (ciphertext, NULL);
664 gpgme_data_release (ciphertext);
668 /* Find the "micalg" parameter from the last Gpgme operation on
669 context CTX. It is expected that this operation was a sign
670 operation. Return the algorithm name as a C string in buffer BUF
671 which must have been allocated by the caller with size BUFLEN.
672 Returns 0 on success or -1 in case of an error. The return string
673 is truncted to BUFLEN - 1. */
674 static int get_micalg (gpgme_ctx_t ctx, char *buf, ssize_t buflen)
676 gpgme_sign_result_t result = NULL;
677 const char *algorithm_name = NULL;
683 result = gpgme_op_sign_result (ctx);
685 algorithm_name = gpgme_hash_algo_name (result->signatures->hash_algo);
686 if (algorithm_name) {
687 m_strcpy(buf, buflen, algorithm_name);
691 return *buf ? 0 : -1;
694 static void print_time (time_t t, STATE * s)
698 setlocale (LC_TIME, "");
699 #ifdef HAVE_LANGINFO_D_T_FMT
700 strftime (p, sizeof (p), nl_langinfo (D_T_FMT), localtime (&t));
702 strftime (p, sizeof (p), "%c", localtime (&t));
704 setlocale (LC_TIME, "C");
705 state_attach_puts (p, s);
708 /* Implementation of `sign_message'. */
710 /* Sign the MESSAGE in body A either using OpenPGP or S/MIME when
711 USE_SMIME is passed as true. Returns the new body or NULL on
713 static BODY *sign_message (BODY * a, int use_smime)
720 gpgme_data_t message, signature;
722 convert_to_7bit (a); /* Signed data _must_ be in 7-bit format. */
724 message = body_to_data_object (a, 1);
727 signature = create_gpgme_data ();
729 ctx = create_gpgme_context (use_smime);
731 gpgme_set_armor (ctx, 1);
733 if (set_signer (ctx, use_smime)) {
734 gpgme_data_release (signature);
739 err = gpgme_op_sign (ctx, message, signature, GPGME_SIG_MODE_DETACH);
740 mutt_need_hard_redraw ();
741 gpgme_data_release (message);
743 gpgme_data_release (signature);
745 mutt_error (_("error signing data: %s\n"), gpgme_strerror (err));
749 sigfile = data_object_to_tempfile (signature, NULL);
750 gpgme_data_release (signature);
757 t->type = TYPEMULTIPART;
758 t->subtype = m_strdup("signed");
759 t->encoding = ENC7BIT;
761 t->disposition = DISPINLINE;
763 parameter_set_boundary(&t->parameter);
764 parameter_setval(&t->parameter, "protocol",
765 use_smime ? "application/pkcs7-signature"
766 : "application/pgp-signature");
767 /* Get the micalg from gpgme. Old gpgme versions don't support this
768 for S/MIME so we assume sha-1 in this case. */
769 if (!get_micalg (ctx, buf, sizeof buf))
770 parameter_setval(&t->parameter, "micalg", buf);
772 parameter_setval(&t->parameter, "micalg", "sha1");
778 t->parts->next = body_new();
780 t->type = TYPEAPPLICATION;
782 t->subtype = m_strdup("pkcs7-signature");
783 parameter_setval(&t->parameter, "name", "smime.p7s");
784 t->encoding = ENCBASE64;
786 t->disposition = DISPATTACH;
787 t->d_filename = m_strdup("smime.p7s");
790 t->subtype = m_strdup("pgp-signature");
792 t->disposition = DISPINLINE;
793 t->encoding = ENC7BIT;
795 t->filename = sigfile;
796 t->unlink = 1; /* ok to remove this file after sending. */
802 BODY *crypt_pgp_sign_message (BODY * a)
804 return sign_message (a, 0);
807 BODY *crypt_smime_sign_message (BODY * a)
809 return sign_message (a, 1);
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 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 BODY *smime_gpgme_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_key (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 verify_one (BODY * sigbdy, STATE * s,
1219 const char *tempfile, int is_smime)
1225 gpgme_data_t signature, message;
1227 signature = file_to_data_object (s->fpin, sigbdy->offset, sigbdy->length);
1231 /* We need to tell gpgme about the encoding because the backend can't
1232 auto-detect plain base-64 encoding which is used by S/MIME. */
1234 gpgme_data_set_encoding (signature, GPGME_DATA_ENCODING_BASE64);
1236 err = gpgme_data_new_from_file (&message, tempfile, 1);
1238 gpgme_data_release (signature);
1239 mutt_error (_("error allocating data object: %s\n"), gpgme_strerror (err));
1242 ctx = create_gpgme_context (is_smime);
1244 /* Note: We don't need a current time output because GPGME avoids
1245 such an attack by separating the meta information from the
1247 state_attach_puts (_("[-- Begin signature information --]\n"), s);
1249 err = gpgme_op_verify (ctx, signature, message, NULL);
1250 mutt_need_hard_redraw ();
1254 snprintf (buf, sizeof (buf) - 1,
1255 _("Error: verification failed: %s\n"), gpgme_strerror (err));
1256 state_attach_puts (buf, s);
1258 else { /* Verification succeeded, see what the result is. */
1262 if (signature_key) {
1263 gpgme_key_release (signature_key);
1264 signature_key = NULL;
1267 for (idx = 0; (res = show_one_sig_status (ctx, idx, s)) != -1; idx++) {
1278 gpgme_verify_result_t result;
1279 gpgme_sig_notation_t notation;
1280 gpgme_signature_t sig;
1282 result = gpgme_op_verify_result (ctx);
1284 for (sig = result->signatures; sig; sig = sig->next) {
1285 if (sig->notations) {
1286 state_attach_puts ("*** Begin Notation (signature by: ", s);
1287 state_attach_puts (sig->fpr, s);
1288 state_attach_puts (") ***\n", s);
1289 for (notation = sig->notations; notation; notation = notation->next)
1291 if (notation->name) {
1292 state_attach_puts (notation->name, s);
1293 state_attach_puts ("=", s);
1295 if (notation->value) {
1296 state_attach_puts (notation->value, s);
1297 if (!(*notation->value
1298 && (notation->value[m_strlen(notation->value) - 1] ==
1300 state_attach_puts ("\n", s);
1303 state_attach_puts ("*** End Notation ***\n", s);
1309 gpgme_release (ctx);
1311 state_attach_puts (_("[-- End signature information --]\n\n"), s);
1313 return badsig ? 1 : anywarn ? 2 : 0;
1316 int crypt_pgp_verify_one (BODY * sigbdy, STATE * s, const char *tempfile)
1318 return verify_one (sigbdy, s, tempfile, 0);
1321 int crypt_smime_verify_one (BODY * sigbdy, STATE * s, const char *tempfile)
1323 return verify_one (sigbdy, s, tempfile, 1);
1327 * Implementation of `decrypt_part'.
1330 /* Decrypt a PGP or SMIME message (depending on the boolean flag
1331 IS_SMIME) with body A described further by state S. Write
1332 plaintext out to file FPOUT and return a new body. For PGP returns
1333 a flag in R_IS_SIGNED to indicate whether this is a combined
1334 encrypted and signed message, for S/MIME it returns true when it is
1335 not a encrypted but a signed message. */
1336 static BODY *decrypt_part (BODY * a, STATE * s, FILE * fpout, int is_smime,
1343 gpgme_data_t ciphertext, plaintext;
1344 int maybe_signed = 0;
1351 ctx = create_gpgme_context (is_smime);
1354 /* Make a data object from the body, create context etc. */
1355 ciphertext = file_to_data_object (s->fpin, a->offset, a->length);
1358 plaintext = create_gpgme_data ();
1360 /* Do the decryption or the verification in case of the S/MIME hack. */
1361 if ((!is_smime) || maybe_signed) {
1363 err = gpgme_op_decrypt_verify (ctx, ciphertext, plaintext);
1364 else if (maybe_signed)
1365 err = gpgme_op_verify (ctx, ciphertext, NULL, plaintext);
1368 /* Check wether signatures have been verified. */
1369 gpgme_verify_result_t verify_result = gpgme_op_verify_result (ctx);
1371 if (verify_result->signatures)
1376 err = gpgme_op_decrypt (ctx, ciphertext, plaintext);
1377 gpgme_data_release (ciphertext);
1379 if (is_smime && !maybe_signed && gpg_err_code (err) == GPG_ERR_NO_DATA) {
1380 /* Check whether this might be a signed message despite what
1381 the mime header told us. Retry then. gpgsm returns the
1382 error information "unsupported Algorithm '?'" but gpgme
1383 will not store this unknown algorithm, thus we test that
1384 it has not been set. */
1385 gpgme_decrypt_result_t result;
1387 result = gpgme_op_decrypt_result (ctx);
1388 if (!result->unsupported_algorithm) {
1390 gpgme_data_release (plaintext);
1394 mutt_need_hard_redraw ();
1395 if ((s->flags & M_DISPLAY)) {
1398 snprintf (buf, sizeof (buf) - 1,
1399 _("[-- Error: decryption failed: %s --]\n\n"),
1400 gpgme_strerror (err));
1401 state_attach_puts (buf, s);
1403 gpgme_data_release (plaintext);
1404 gpgme_release (ctx);
1407 mutt_need_hard_redraw ();
1409 /* Read the output from GPGME, and make sure to change CRLF to LF,
1410 otherwise read_mime_header has a hard time parsing the message. */
1411 if (data_object_to_stream (plaintext, fpout)) {
1412 gpgme_data_release (plaintext);
1413 gpgme_release (ctx);
1416 gpgme_data_release (plaintext);
1418 a->is_signed_data = 0;
1424 a->is_signed_data = 1;
1426 *r_is_signed = -1; /* A signature exists. */
1428 if ((s->flags & M_DISPLAY))
1429 state_attach_puts (_("[-- Begin signature " "information --]\n"), s);
1430 for (idx = 0; (res = show_one_sig_status (ctx, idx, s)) != -1; idx++) {
1436 if (!anybad && idx && r_is_signed && *r_is_signed)
1437 *r_is_signed = anywarn ? 2 : 1; /* Good signature. */
1439 if ((s->flags & M_DISPLAY))
1440 state_attach_puts (_("[-- End signature " "information --]\n\n"), s);
1442 gpgme_release (ctx);
1447 tattach = mutt_read_mime_header (fpout, 0);
1450 * Need to set the length of this body part.
1452 fstat (fileno (fpout), &info);
1453 tattach->length = info.st_size - tattach->offset;
1455 tattach->warnsig = anywarn;
1457 /* See if we need to recurse on this MIME part. */
1458 mutt_parse_part (fpout, tattach);
1464 /* Decrypt a PGP/MIME message in FPIN and B and return a new body and
1465 the stream in CUR and FPOUT. Returns 0 on success. */
1466 int crypt_pgp_decrypt_mime (FILE * fpin, FILE ** fpout, BODY * b, BODY ** cur)
1468 char tempfile[_POSIX_PATH_MAX];
1470 BODY *first_part = b;
1473 first_part->goodsig = 0;
1474 first_part->warnsig = 0;
1476 if (!mutt_is_multipart_encrypted (b))
1479 if (!b->parts || !b->parts->next)
1486 *fpout = m_tempfile(tempfile, sizeof(tempfile), NONULL(MCore.tmpdir), NULL);
1488 mutt_perror (_("Can't create temporary file"));
1493 *cur = decrypt_part (b, &s, *fpout, 0, &is_signed);
1496 first_part->goodsig = 1;
1498 return *cur ? 0 : -1;
1502 /* Decrypt a S/MIME message in FPIN and B and return a new body and
1503 the stream in CUR and FPOUT. Returns 0 on success. */
1504 int crypt_smime_decrypt_mime (FILE * fpin, FILE ** fpout, BODY * b,
1507 char tempfile[_POSIX_PATH_MAX];
1511 long saved_b_offset;
1512 ssize_t saved_b_length;
1515 if (!mutt_is_application_smime (b))
1521 /* Decode the body - we need to pass binary CMS to the
1522 backend. The backend allows for Base64 encoded data but it does
1523 not allow for QP which I have seen in some messages. So better
1525 saved_b_type = b->type;
1526 saved_b_offset = b->offset;
1527 saved_b_length = b->length;
1530 fseeko (s.fpin, b->offset, 0);
1531 tmpfp = m_tempfile (tempfile, sizeof(tempfile), NONULL(MCore.tmpdir), NULL);
1533 mutt_perror (_("Can't create temporary file"));
1536 mutt_unlink (tempfile);
1539 mutt_decode_attachment (b, &s);
1541 b->length = ftello (s.fpout);
1548 *fpout = m_tempfile(tempfile, sizeof(tempfile), NONULL(MCore.tmpdir), NULL);
1550 mutt_perror (_("Can't create temporary file"));
1553 mutt_unlink (tempfile);
1555 *cur = decrypt_part (b, &s, *fpout, 1, &is_signed);
1557 (*cur)->goodsig = is_signed > 0;
1558 b->type = saved_b_type;
1559 b->length = saved_b_length;
1560 b->offset = saved_b_offset;
1563 if (*cur && !is_signed && !(*cur)->parts
1564 && mutt_is_application_smime (*cur)) {
1565 /* Assume that this is a opaque signed s/mime message. This is
1566 an ugly way of doing it but we have anyway a problem with
1567 arbitrary encoded S/MIME messages: Only the outer part may be
1568 encrypted. The entire mime parsing should be revamped,
1569 probably by keeping the temportary files so that we don't
1570 need to decrypt them all the time. Inner parts of an
1571 encrypted part can then pint into this file and tehre won't
1572 never be a need to decrypt again. This needs a partial
1573 rewrite of the MIME engine. */
1577 saved_b_type = bb->type;
1578 saved_b_offset = bb->offset;
1579 saved_b_length = bb->length;
1582 fseeko (s.fpin, bb->offset, 0);
1583 tmpfp = m_tempfile (tempfile, sizeof(tempfile), NONULL(MCore.tmpdir), NULL);
1585 mutt_perror (_("Can't create temporary file"));
1588 mutt_unlink (tempfile);
1591 mutt_decode_attachment (bb, &s);
1593 bb->length = ftello (s.fpout);
1601 *fpout = m_tempfile(tempfile, sizeof(tempfile), NONULL(MCore.tmpdir), NULL);
1603 mutt_perror (_("Can't create temporary file"));
1606 mutt_unlink (tempfile);
1608 tmp_b = decrypt_part (bb, &s, *fpout, 1, &is_signed);
1610 tmp_b->goodsig = is_signed > 0;
1611 bb->type = saved_b_type;
1612 bb->length = saved_b_length;
1613 bb->offset = saved_b_offset;
1616 body_list_wipe(cur);
1619 return *cur ? 0 : -1;
1624 * Implementation of `pgp_check_traditional'.
1627 static int pgp_check_traditional_one_body (FILE * fp, BODY * b,
1630 char tempfile[_POSIX_PATH_MAX];
1631 char buf[HUGE_STRING];
1638 if (b->type != TYPETEXT)
1641 if (tagged_only && !b->tagged)
1644 tempfd = m_tempfd(tempfile, sizeof(tempfile), NONULL(MCore.tmpdir), NULL);
1645 if (mutt_decode_save_attachment (fp, b, tempfd, 0) != 0) {
1650 if ((tfp = fopen(tempfile, "r")) == NULL) {
1655 while (fgets (buf, sizeof (buf), tfp)) {
1656 if (!m_strncmp("-----BEGIN PGP ", buf, 15)) {
1657 if (!m_strcmp("MESSAGE-----\n", buf + 15))
1659 else if (!m_strcmp("SIGNED MESSAGE-----\n", buf + 15))
1669 /* fix the content type */
1671 parameter_setval(&b->parameter, "format", "fixed");
1672 parameter_setval(&b->parameter, "x-action",
1673 enc ? "pgp-encrypted" : "pgp-signed");
1677 int crypt_pgp_check_traditional (FILE * fp, BODY * b, int tagged_only)
1682 for (; b; b = b->next) {
1683 if (is_multipart (b))
1684 rv = (crypt_pgp_check_traditional (fp, b->parts, tagged_only) || rv);
1685 else if (b->type == TYPETEXT) {
1686 if ((r = mutt_is_application_pgp (b)))
1689 rv = (pgp_check_traditional_one_body (fp, b, tagged_only) || rv);
1696 /* Implementation of `application_handler'. */
1699 Copy a clearsigned message, and strip the signature and PGP's
1702 XXX - charset handling: We assume that it is safe to do
1703 character set decoding first, dash decoding second here, while
1704 we do it the other way around in the main handler.
1706 (Note that we aren't worse than Outlook & Cie in this, and also
1707 note that we can successfully handle anything produced by any
1708 existing versions of mutt.) */
1710 static void copy_clearsigned (gpgme_data_t data, STATE * s, char *charset)
1712 char buf[HUGE_STRING];
1713 short complete, armor_header;
1718 fname = data_object_to_tempfile (data, &fp);
1724 fc = fgetconv_open (fp, charset, MCharset.charset, M_ICONV_HOOK_FROM);
1726 for (complete = 1, armor_header = 1;
1727 fgetconvs (buf, sizeof (buf), fc) != NULL;
1728 complete = strchr (buf, '\n') != NULL) {
1731 state_puts (buf, s);
1735 if (!m_strcmp(buf, "-----BEGIN PGP SIGNATURE-----\n"))
1745 state_puts (s->prefix, s);
1747 if (buf[0] == '-' && buf[1] == ' ')
1748 state_puts (buf + 2, s);
1750 state_puts (buf, s);
1753 fgetconv_close (&fc);
1758 /* Support for classic_application/pgp */
1759 int crypt_pgp_application_pgp_handler (BODY * m, STATE * s)
1761 int needpass = -1, pgp_keyblock = 0;
1765 off_t last_pos, offset;
1766 char buf[HUGE_STRING];
1767 FILE *pgpout = NULL;
1769 gpgme_error_t err = 0;
1770 gpgme_data_t armored_data = NULL;
1772 short maybe_goodsig = 1;
1773 short have_any_sigs = 0;
1775 char body_charset[STRING]; /* Only used for clearsigned messages. */
1777 /* For clearsigned messages we won't be able to get a character set
1778 but we know that this may only be text thus we assume Latin-1
1780 if (!mutt_get_body_charset (body_charset, sizeof (body_charset), m))
1781 m_strcpy(body_charset, sizeof(body_charset), "iso-8859-1");
1783 fseeko (s->fpin, m->offset, 0);
1784 last_pos = m->offset;
1786 for (bytes = m->length; bytes > 0;) {
1787 if (fgets (buf, sizeof (buf), s->fpin) == NULL)
1790 offset = ftello (s->fpin);
1791 bytes -= (offset - last_pos); /* don't rely on m_strlen(buf) */
1794 if (!m_strncmp("-----BEGIN PGP ", buf, 15)) {
1796 start_pos = last_pos;
1798 if (!m_strcmp("MESSAGE-----\n", buf + 15))
1800 else if (!m_strcmp("SIGNED MESSAGE-----\n", buf + 15)) {
1804 else if (!option (OPTDONTHANDLEPGPKEYS) &&
1805 !m_strcmp("PUBLIC KEY BLOCK-----\n", buf + 15)) {
1810 /* XXX - we may wish to recode here */
1812 state_puts (s->prefix, s);
1813 state_puts (buf, s);
1817 have_any_sigs = (have_any_sigs || (clearsign && (s->flags & M_VERIFY)));
1819 /* Copy PGP material to an data container */
1820 armored_data = create_gpgme_data ();
1821 gpgme_data_write (armored_data, buf, m_strlen(buf));
1822 while (bytes > 0 && fgets (buf, sizeof (buf) - 1, s->fpin) != NULL) {
1823 offset = ftello (s->fpin);
1824 bytes -= (offset - last_pos); /* don't rely on m_strlen(buf) */
1827 gpgme_data_write (armored_data, buf, m_strlen(buf));
1829 if ((needpass && !m_strcmp("-----END PGP MESSAGE-----\n", buf))
1831 && (!m_strcmp("-----END PGP SIGNATURE-----\n", buf)
1832 || !m_strcmp("-----END PGP PUBLIC KEY BLOCK-----\n",
1837 /* Invoke PGP if needed */
1838 if (!clearsign || (s->flags & M_VERIFY)) {
1839 unsigned int sig_stat = 0;
1840 gpgme_data_t plaintext;
1843 plaintext = create_gpgme_data ();
1844 ctx = create_gpgme_context (0);
1847 err = gpgme_op_verify (ctx, armored_data, NULL, plaintext);
1849 err = gpgme_op_decrypt_verify (ctx, armored_data, plaintext);
1850 if (gpg_err_code (err) == GPG_ERR_NO_DATA) {
1851 /* Decrypt verify can't handle signed only messages. */
1852 err = (gpgme_data_seek (armored_data, 0, SEEK_SET) == -1)
1853 ? gpgme_error_from_errno (errno) : 0;
1854 /* Must release plaintext so that we supply an
1855 uninitialized object. */
1856 gpgme_data_release (plaintext);
1857 plaintext = create_gpgme_data ();
1858 err = gpgme_op_verify (ctx, armored_data, NULL, plaintext);
1865 snprintf (errbuf, sizeof (errbuf) - 1,
1866 _("Error: decryption/verification failed: %s\n"),
1867 gpgme_strerror (err));
1868 state_attach_puts (errbuf, s);
1870 else { /* Decryption/Verification succeeded */
1874 /* Check wether signatures have been verified. */
1875 gpgme_verify_result_t verify_result;
1877 verify_result = gpgme_op_verify_result (ctx);
1878 if (verify_result->signatures)
1884 if ((s->flags & M_DISPLAY) && sig_stat) {
1889 state_attach_puts (_("[-- Begin signature "
1890 "information --]\n"), s);
1893 (res = show_one_sig_status (ctx, idx, s)) != -1; idx++) {
1902 state_attach_puts (_("[-- End signature "
1903 "information --]\n\n"), s);
1906 tmpfname = data_object_to_tempfile (plaintext, &pgpout);
1909 state_attach_puts (_("Error: copy data failed\n"), s);
1913 p_delete(&tmpfname);
1916 gpgme_release (ctx);
1920 * Now, copy cleartext to the screen. NOTE - we expect that PGP
1921 * outputs utf-8 cleartext. This may not always be true, but it
1922 * seems to be a reasonable guess.
1925 if (s->flags & M_DISPLAY) {
1927 state_attach_puts (_("[-- BEGIN PGP MESSAGE --]\n\n"), s);
1928 else if (pgp_keyblock)
1929 state_attach_puts (_("[-- BEGIN PGP PUBLIC KEY BLOCK --]\n"), s);
1931 state_attach_puts (_("[-- BEGIN PGP SIGNED MESSAGE --]\n\n"), s);
1935 copy_clearsigned (armored_data, s, body_charset);
1942 fc = fgetconv_open (pgpout, "utf-8", MCharset.charset, 0);
1943 while ((c = fgetconv (fc)) != EOF) {
1945 if (c == '\n' && s->prefix)
1946 state_puts (s->prefix, s);
1948 fgetconv_close (&fc);
1951 if (s->flags & M_DISPLAY) {
1952 state_putc ('\n', s);
1954 state_attach_puts (_("[-- END PGP MESSAGE --]\n"), s);
1955 else if (pgp_keyblock)
1956 state_attach_puts (_("[-- END PGP PUBLIC KEY BLOCK --]\n"), s);
1958 state_attach_puts (_("[-- END PGP SIGNED MESSAGE --]\n"), s);
1966 /* XXX - we may wish to recode here */
1968 state_puts (s->prefix, s);
1969 state_puts (buf, s);
1973 m->goodsig = (maybe_goodsig && have_any_sigs);
1975 if (needpass == -1) {
1976 state_attach_puts (_("[-- Error: could not find beginning"
1977 " of PGP message! --]\n\n"), s);
1984 * Implementation of `encrypted_handler'.
1987 /* MIME handler for pgp/mime encrypted messages. */
1988 int pgp_gpgme_encrypted_handler (BODY * a, STATE * s)
1990 char tempfile[_POSIX_PATH_MAX];
1993 BODY *orig_body = a;
1998 if (!a || a->type != TYPEAPPLICATION || !a->subtype
1999 || ascii_strcasecmp ("pgp-encrypted", a->subtype)
2000 || !a->next || a->next->type != TYPEAPPLICATION || !a->next->subtype
2001 || ascii_strcasecmp ("octet-stream", a->next->subtype)) {
2002 if (s->flags & M_DISPLAY)
2003 state_attach_puts (_("[-- Error: malformed PGP/MIME message! --]\n\n"),
2008 /* Move forward to the application/pgp-encrypted body. */
2011 fpout = m_tempfile(tempfile, sizeof(tempfile), NONULL(MCore.tmpdir), NULL);
2013 if (s->flags & M_DISPLAY)
2014 state_attach_puts (_("[-- Error: could not create temporary file! "
2019 tattach = decrypt_part (a, s, fpout, 0, &is_signed);
2021 tattach->goodsig = is_signed > 0;
2023 if (s->flags & M_DISPLAY)
2024 state_attach_puts (is_signed ?
2026 ("[-- The following data is PGP/MIME signed and encrypted --]\n\n") :
2027 _("[-- The following data is PGP/MIME encrypted --]\n\n"), s);
2030 FILE *savefp = s->fpin;
2033 rc = mutt_body_handler (tattach, s);
2038 * if a multipart/signed is the _only_ sub-part of a
2039 * multipart/encrypted, cache signature verification
2042 if (mutt_is_multipart_signed (tattach) && !tattach->next)
2043 orig_body->goodsig |= tattach->goodsig;
2045 if (s->flags & M_DISPLAY) {
2046 state_puts ("\n", s);
2047 state_attach_puts (is_signed ?
2049 ("[-- End of PGP/MIME signed and encrypted data --]\n")
2050 : _("[-- End of PGP/MIME encrypted data --]\n"), s);
2053 body_list_wipe(&tattach);
2057 mutt_unlink (tempfile);
2061 /* Support for application/smime */
2062 int crypt_smime_application_smime_handler (BODY * a, STATE * s)
2064 char tempfile[_POSIX_PATH_MAX];
2071 fpout = m_tempfile(tempfile, sizeof(tempfile), NONULL(MCore.tmpdir), NULL);
2073 if (s->flags & M_DISPLAY)
2074 state_attach_puts (_("[-- Error: could not create temporary file! "
2079 tattach = decrypt_part (a, s, fpout, 1, &is_signed);
2081 tattach->goodsig = is_signed > 0;
2083 if (s->flags & M_DISPLAY)
2084 state_attach_puts (is_signed ?
2085 _("[-- The following data is S/MIME signed --]\n\n") :
2086 _("[-- The following data is S/MIME encrypted --]\n\n"), s);
2089 FILE *savefp = s->fpin;
2092 rc = mutt_body_handler (tattach, s);
2097 * if a multipart/signed is the _only_ sub-part of a
2098 * multipart/encrypted, cache signature verification
2101 if (mutt_is_multipart_signed (tattach) && !tattach->next) {
2102 if (!(a->goodsig = tattach->goodsig))
2103 a->warnsig = tattach->warnsig;
2105 else if (tattach->goodsig) {
2107 a->warnsig = tattach->warnsig;
2110 if (s->flags & M_DISPLAY) {
2111 state_puts ("\n", s);
2112 state_attach_puts (is_signed ?
2113 _("[-- End of S/MIME signed data --]\n") :
2114 _("[-- End of S/MIME encrypted data --]\n"), s);
2117 body_list_wipe(&tattach);
2121 mutt_unlink (tempfile);
2127 * Format an entry on the CRYPT key selection menu.
2130 * %k key id %K key id of the principal key
2132 * %a algorithm %A algorithm of the princ. key
2133 * %l length %L length of the princ. key
2134 * %f flags %F flags of the princ. key
2135 * %c capabilities %C capabilities of the princ. key
2136 * %t trust/validity of the key-uid association
2138 * %[...] date of key using strftime(3)
2142 crypt_entry_fmt (char *dest, ssize_t destlen, char op,
2143 const char *src, const char *prefix,
2144 const char *ifstr, const char *elstr,
2145 anytype data, format_flag flags)
2148 crypt_entry_t *entry;
2151 int optional = (flags & M_FORMAT_OPTIONAL);
2152 const char *s = NULL;
2158 /* if (isupper ((unsigned char) op)) */
2161 kflags = (key->flags /*| (pkey->flags & KEYFLAG_RESTRICTIONS)
2164 switch (ascii_tolower (op)) {
2168 char buf2[STRING], *p;
2184 while (len > 0 && *cp != ']') {
2193 break; /* not enough space */
2203 if (do_locales && Locale)
2204 setlocale (LC_TIME, Locale);
2209 if (key->kobj->subkeys && (key->kobj->subkeys->timestamp > 0))
2210 tt = key->kobj->subkeys->timestamp;
2212 tm = localtime (&tt);
2214 strftime (buf2, sizeof (buf2), dest, tm);
2217 setlocale (LC_TIME, "C");
2219 snprintf (fmt, sizeof (fmt), "%%%ss", prefix);
2220 snprintf (dest, destlen, fmt, buf2);
2227 snprintf (fmt, sizeof (fmt), "%%%sd", prefix);
2228 snprintf (dest, destlen, fmt, entry->num);
2233 /* fixme: we need a way to distinguish between main and subkeys.
2234 Store the idx in entry? */
2235 snprintf (fmt, sizeof (fmt), "%%%ss", prefix);
2236 snprintf (dest, destlen, fmt, crypt_keyid (key));
2241 snprintf (fmt, sizeof (fmt), "%%%ss", prefix);
2242 snprintf (dest, destlen, fmt, key->uid);
2247 snprintf (fmt, sizeof (fmt), "%%%s.3s", prefix);
2248 if (key->kobj->subkeys)
2249 s = gpgme_pubkey_algo_name (key->kobj->subkeys->pubkey_algo);
2252 snprintf (dest, destlen, fmt, s);
2257 snprintf (fmt, sizeof (fmt), "%%%slu", prefix);
2258 if (key->kobj->subkeys)
2259 val = key->kobj->subkeys->length;
2262 snprintf (dest, destlen, fmt, val);
2267 snprintf (fmt, sizeof (fmt), "%%%sc", prefix);
2268 snprintf (dest, destlen, fmt, crypt_flags (kflags));
2270 else if (!(kflags & (KEYFLAG_RESTRICTIONS)))
2275 snprintf (fmt, sizeof (fmt), "%%%ss", prefix);
2276 snprintf (dest, destlen, fmt, crypt_key_abilities (kflags));
2278 else if (!(kflags & (KEYFLAG_ABILITIES)))
2282 if ((kflags & KEYFLAG_ISX509))
2285 gpgme_user_id_t uid = NULL;
2288 for (i = 0, uid = key->kobj->uids; uid && (i < key->idx);
2289 i++, uid = uid->next);
2291 switch (uid->validity) {
2292 case GPGME_VALIDITY_UNDEFINED:
2295 case GPGME_VALIDITY_NEVER:
2298 case GPGME_VALIDITY_MARGINAL:
2301 case GPGME_VALIDITY_FULL:
2304 case GPGME_VALIDITY_ULTIMATE:
2307 case GPGME_VALIDITY_UNKNOWN:
2313 snprintf (fmt, sizeof (fmt), "%%%sc", prefix);
2314 snprintf (dest, destlen, fmt, s ? *s : 'B');
2317 snprintf (fmt, sizeof (fmt), "%%%ss", prefix);
2318 snprintf (dest, destlen, fmt,
2319 gpgme_get_protocol_name (key->kobj->protocol));
2326 if (flags & M_FORMAT_OPTIONAL)
2327 m_strformat(dest, destlen, 0, optional ? ifstr: elstr,
2328 mutt_attach_fmt, data, 0);
2332 /* Used by the display fucntion to format a line. */
2333 static void crypt_entry (char *s, ssize_t l, MUTTMENU * menu, int num)
2335 crypt_key_t **key_table = (crypt_key_t **) menu->data;
2336 crypt_entry_t entry;
2338 entry.key = key_table[num];
2339 entry.num = num + 1;
2341 m_strformat(s, l, COLS - SW, PgpEntryFormat, crypt_entry_fmt, &entry,
2342 option(OPTARROWCURSOR) ? M_FORMAT_ARROWCURSOR : 0);
2345 /* Compare two addresses and the keyid to be used for sorting. */
2346 static int _crypt_compare_address (const void *a, const void *b)
2348 crypt_key_t **s = (crypt_key_t **) a;
2349 crypt_key_t **t = (crypt_key_t **) b;
2352 if ((r = m_strcasecmp((*s)->uid, (*t)->uid)))
2355 return m_strcasecmp(crypt_keyid (*s), crypt_keyid (*t)) > 0;
2358 static int crypt_compare_address (const void *a, const void *b)
2360 return ((PgpSortKeys & SORT_REVERSE) ? !_crypt_compare_address (a, b)
2361 : _crypt_compare_address (a, b));
2365 /* Compare two key IDs and the addresses to be used for sorting. */
2366 static int _crypt_compare_keyid (const void *a, const void *b)
2368 crypt_key_t **s = (crypt_key_t **) a;
2369 crypt_key_t **t = (crypt_key_t **) b;
2372 if ((r = m_strcasecmp(crypt_keyid (*s), crypt_keyid (*t))))
2375 return m_strcasecmp((*s)->uid, (*t)->uid) > 0;
2378 static int crypt_compare_keyid (const void *a, const void *b)
2380 return ((PgpSortKeys & SORT_REVERSE) ? !_crypt_compare_keyid (a, b)
2381 : _crypt_compare_keyid (a, b));
2384 /* Compare 2 creation dates and the addresses. For sorting. */
2385 static int _crypt_compare_date (const void *a, const void *b)
2387 crypt_key_t **s = (crypt_key_t **) a;
2388 crypt_key_t **t = (crypt_key_t **) b;
2389 unsigned long ts = 0, tt = 0;
2391 if ((*s)->kobj->subkeys && ((*s)->kobj->subkeys->timestamp > 0))
2392 ts = (*s)->kobj->subkeys->timestamp;
2393 if ((*t)->kobj->subkeys && ((*t)->kobj->subkeys->timestamp > 0))
2394 tt = (*t)->kobj->subkeys->timestamp;
2401 return m_strcasecmp((*s)->uid, (*t)->uid) > 0;
2404 static int crypt_compare_date (const void *a, const void *b)
2406 return ((PgpSortKeys & SORT_REVERSE) ? !_crypt_compare_date (a, b)
2407 : _crypt_compare_date (a, b));
2410 /* Compare two trust values, the key length, the creation dates. the
2411 addresses and the key IDs. For sorting. */
2412 static int _crypt_compare_trust (const void *a, const void *b)
2414 crypt_key_t **s = (crypt_key_t **) a;
2415 crypt_key_t **t = (crypt_key_t **) b;
2416 unsigned long ts = 0, tt = 0;
2419 if ((r = (((*s)->flags & (KEYFLAG_RESTRICTIONS))
2420 - ((*t)->flags & (KEYFLAG_RESTRICTIONS)))))
2423 if ((*s)->kobj->uids)
2424 ts = (*s)->kobj->uids->validity;
2425 if ((*t)->kobj->uids)
2426 tt = (*t)->kobj->uids->validity;
2427 if ((r = (tt - ts)))
2430 if ((*s)->kobj->subkeys)
2431 ts = (*s)->kobj->subkeys->length;
2432 if ((*t)->kobj->subkeys)
2433 tt = (*t)->kobj->subkeys->length;
2437 if ((*s)->kobj->subkeys && ((*s)->kobj->subkeys->timestamp > 0))
2438 ts = (*s)->kobj->subkeys->timestamp;
2439 if ((*t)->kobj->subkeys && ((*t)->kobj->subkeys->timestamp > 0))
2440 tt = (*t)->kobj->subkeys->timestamp;
2446 if ((r = m_strcasecmp((*s)->uid, (*t)->uid)))
2448 return (m_strcasecmp(crypt_keyid ((*s)), crypt_keyid ((*t)))) > 0;
2451 static int crypt_compare_trust (const void *a, const void *b)
2453 return ((PgpSortKeys & SORT_REVERSE) ? !_crypt_compare_trust (a, b)
2454 : _crypt_compare_trust (a, b));
2457 /* Print the X.500 Distinguished Name part KEY from the array of parts
2459 static int print_dn_part (FILE * fp, struct dn_array_s *dn, const char *key)
2463 for (; dn->key; dn++) {
2464 if (!m_strcmp(dn->key, key)) {
2467 print_utf8 (fp, dn->value, m_strlen(dn->value));
2474 /* Print all parts of a DN in a standard sequence. */
2475 static void print_dn_parts (FILE * fp, struct dn_array_s *dn)
2477 const char *stdpart[] = {
2478 "CN", "OU", "O", "STREET", "L", "ST", "C", NULL
2480 int any = 0, any2 = 0, i;
2482 for (i = 0; stdpart[i]; i++) {
2485 any = print_dn_part (fp, dn, stdpart[i]);
2487 /* now print the rest without any specific ordering */
2488 for (; dn->key; dn++) {
2489 for (i = 0; stdpart[i]; i++) {
2490 if (!m_strcmp(dn->key, stdpart[i]))
2498 any = print_dn_part (fp, dn, dn->key);
2507 /* Parse an RDN; this is a helper to parse_dn(). */
2508 static const unsigned char *parse_dn_part (struct dn_array_s *array,
2509 const unsigned char *string)
2511 const unsigned char *s, *s1;
2515 /* parse attributeType */
2516 for (s = string + 1; *s && *s != '='; s++);
2518 return NULL; /* error */
2521 return NULL; /* empty key */
2522 array->key = p_dupstr(string, n );
2523 p = (unsigned char *) array->key;
2526 if (*string == '#') { /* hexstring */
2528 for (s = string; hexdigitp (s); s++)
2532 return NULL; /* empty or odd number of digits */
2534 p = p_new(unsigned char, n + 1);
2535 array->value = (char *) p;
2536 for (s1 = string; n; s1 += 2, n--)
2540 else { /* regular v3 quoted string */
2541 for (n = 0, s = string; *s; s++) {
2542 if (*s == '\\') { /* pair */
2544 if (*s == ',' || *s == '=' || *s == '+'
2545 || *s == '<' || *s == '>' || *s == '#' || *s == ';'
2546 || *s == '\\' || *s == '\"' || *s == ' ')
2548 else if (hexdigitp (s) && hexdigitp (s + 1)) {
2553 return NULL; /* invalid escape sequence */
2555 else if (*s == '\"')
2556 return NULL; /* invalid encoding */
2557 else if (*s == ',' || *s == '=' || *s == '+'
2558 || *s == '<' || *s == '>' || *s == '#' || *s == ';')
2564 p = p_new(unsigned char, n + 1);
2565 array->value = (char *) p;
2566 for (s = string; n; s++, n--) {
2569 if (hexdigitp (s)) {
2585 /* Parse a DN and return an array-ized one. This is not a validating
2586 parser and it does not support any old-stylish syntax; gpgme is
2587 expected to return only rfc2253 compatible strings. */
2588 static struct dn_array_s *parse_dn (const unsigned char *string)
2590 struct dn_array_s *array;
2591 ssize_t arrayidx, arraysize;
2594 arraysize = 7; /* C,ST,L,O,OU,CN,email */
2595 array = p_new(struct dn_array_s, arraysize + 1);
2598 while (*string == ' ')
2602 if (arrayidx >= arraysize) { /* mutt lacks a real safe_realoc - so we need to copy */
2603 struct dn_array_s *a2;
2606 a2 = p_new(struct dn_array_s, arraysize + 1);
2607 for (i = 0; i < arrayidx; i++) {
2608 a2[i].key = array[i].key;
2609 a2[i].value = array[i].value;
2614 array[arrayidx].key = NULL;
2615 array[arrayidx].value = NULL;
2616 string = parse_dn_part (array + arrayidx, string);
2620 while (*string == ' ')
2622 if (*string && *string != ',' && *string != ';' && *string != '+')
2623 goto failure; /* invalid delimiter */
2627 array[arrayidx].key = NULL;
2628 array[arrayidx].value = NULL;
2632 for (i = 0; i < arrayidx; i++) {
2633 p_delete(&array[i].key);
2634 p_delete(&array[i].value);
2641 /* Print a nice representation of the USERID and make sure it is
2642 displayed in a proper way, which does mean to reorder some parts
2643 for S/MIME's DNs. USERID is a string as returned by the gpgme key
2644 functions. It is utf-8 encoded. */
2645 static void parse_and_print_user_id (FILE * fp, const char *userid)
2650 if (*userid == '<') {
2651 s = strchr (userid + 1, '>');
2653 print_utf8 (fp, userid + 1, s - userid - 1);
2655 else if (*userid == '(')
2656 fputs (_("[Can't display this user ID (unknown encoding)]"), fp);
2657 else if (!digit_or_letter ((const unsigned char *) userid))
2658 fputs (_("[Can't display this user ID (invalid encoding)]"), fp);
2660 struct dn_array_s *dn = parse_dn ((const unsigned char *) userid);
2663 fputs (_("[Can't display this user ID (invalid DN)]"), fp);
2665 print_dn_parts (fp, dn);
2666 for (i = 0; dn[i].key; i++) {
2667 p_delete(&dn[i].key);
2668 p_delete(&dn[i].value);
2676 KEY_CAP_CAN_ENCRYPT,
2681 static unsigned int key_check_cap (gpgme_key_t key, key_cap_t cap)
2683 gpgme_subkey_t subkey = NULL;
2684 unsigned int ret = 0;
2687 case KEY_CAP_CAN_ENCRYPT:
2688 if (!(ret = key->can_encrypt))
2689 for (subkey = key->subkeys; subkey; subkey = subkey->next)
2690 if ((ret = subkey->can_encrypt))
2693 case KEY_CAP_CAN_SIGN:
2694 if (!(ret = key->can_sign))
2695 for (subkey = key->subkeys; subkey; subkey = subkey->next)
2696 if ((ret = subkey->can_sign))
2699 case KEY_CAP_CAN_CERTIFY:
2700 if (!(ret = key->can_certify))
2701 for (subkey = key->subkeys; subkey; subkey = subkey->next)
2702 if ((ret = subkey->can_certify))
2711 /* Print verbose information about a key or certificate to FP. */
2712 static void print_key_info (gpgme_key_t key, FILE * fp)
2715 const char *s = NULL, *s2 = NULL;
2718 char shortbuf[STRING];
2719 unsigned long aval = 0;
2723 gpgme_user_id_t uid = NULL;
2726 setlocale (LC_TIME, Locale);
2728 is_pgp = key->protocol == GPGME_PROTOCOL_OpenPGP;
2730 for (idx = 0, uid = key->uids; uid; idx++, uid = uid->next) {
2735 fputs (idx ? _(" aka ......: ") :_("Name ......: "), fp);
2738 fputs (_("[Invalid]"), fp);
2742 print_utf8 (fp, s, m_strlen(s));
2744 parse_and_print_user_id (fp, s);
2748 if (key->subkeys && (key->subkeys->timestamp > 0)) {
2749 tt = key->subkeys->timestamp;
2751 tm = localtime (&tt);
2752 #ifdef HAVE_LANGINFO_D_T_FMT
2753 strftime (shortbuf, sizeof shortbuf, nl_langinfo (D_T_FMT), tm);
2755 strftime (shortbuf, sizeof shortbuf, "%c", tm);
2757 fprintf (fp, _("Valid From : %s\n"), shortbuf);
2760 if (key->subkeys && (key->subkeys->expires > 0)) {
2761 tt = key->subkeys->expires;
2763 tm = localtime (&tt);
2764 #ifdef HAVE_LANGINFO_D_T_FMT
2765 strftime (shortbuf, sizeof shortbuf, nl_langinfo (D_T_FMT), tm);
2767 strftime (shortbuf, sizeof shortbuf, "%c", tm);
2769 fprintf (fp, _("Valid To ..: %s\n"), shortbuf);
2773 s = gpgme_pubkey_algo_name (key->subkeys->pubkey_algo);
2777 s2 = is_pgp ? "PGP" : "X.509";
2780 aval = key->subkeys->length;
2782 fprintf (fp, _("Key Type ..: %s, %lu bit %s\n"), s2, aval, s);
2784 fprintf (fp, _("Key Usage .: "));
2787 if (key_check_cap (key, KEY_CAP_CAN_ENCRYPT)) {
2788 fprintf (fp, "%s%s", delim, _("encryption"));
2791 if (key_check_cap (key, KEY_CAP_CAN_SIGN)) {
2792 fprintf (fp, "%s%s", delim, _("signing"));
2795 if (key_check_cap (key, KEY_CAP_CAN_CERTIFY)) {
2796 fprintf (fp, "%s%s", delim, _("certification"));
2802 s = key->subkeys->fpr;
2803 fputs (_("Fingerprint: "), fp);
2804 if (is_pgp && m_strlen(s) == 40) {
2805 for (i = 0; *s && s[1] && s[2] && s[3] && s[4]; s += 4, i++) {
2810 putc (is_pgp ? ' ' : ':', fp);
2811 if (is_pgp && i == 4)
2816 for (i = 0; *s && s[1] && s[2]; s += 2, i++) {
2819 putc (is_pgp ? ' ' : ':', fp);
2820 if (is_pgp && i == 7)
2824 fprintf (fp, "%s\n", s);
2827 if (key->issuer_serial) {
2828 s = key->issuer_serial;
2830 fprintf (fp, _("Serial-No .: 0x%s\n"), s);
2833 if (key->issuer_name) {
2834 s = key->issuer_name;
2836 fprintf (fp, _("Issued By .: "));
2837 parse_and_print_user_id (fp, s);
2842 /* For PGP we list all subkeys. */
2844 gpgme_subkey_t subkey = NULL;
2846 for (idx = 1, subkey = key->subkeys; subkey; idx++, subkey = subkey->next) {
2850 if (m_strlen(s) == 16)
2851 s += 8; /* display only the short keyID */
2852 fprintf (fp, _("Subkey ....: 0x%s"), s);
2853 if (subkey->revoked) {
2855 fputs (_("[Revoked]"), fp);
2857 if (subkey->invalid) {
2859 fputs (_("[Invalid]"), fp);
2861 if (subkey->expired) {
2863 fputs (_("[Expired]"), fp);
2865 if (subkey->disabled) {
2867 fputs (_("[Disabled]"), fp);
2871 if (subkey->timestamp > 0) {
2872 tt = subkey->timestamp;
2874 tm = localtime (&tt);
2875 #ifdef HAVE_LANGINFO_D_T_FMT
2876 strftime (shortbuf, sizeof shortbuf, nl_langinfo (D_T_FMT), tm);
2878 strftime (shortbuf, sizeof shortbuf, "%c", tm);
2880 fprintf (fp, _("Valid From : %s\n"), shortbuf);
2883 if (subkey->expires > 0) {
2884 tt = subkey->expires;
2886 tm = localtime (&tt);
2887 #ifdef HAVE_LANGINFO_D_T_FMT
2888 strftime (shortbuf, sizeof shortbuf, nl_langinfo (D_T_FMT), tm);
2890 strftime (shortbuf, sizeof shortbuf, "%c", tm);
2892 fprintf (fp, _("Valid To ..: %s\n"), shortbuf);
2896 s = gpgme_pubkey_algo_name (subkey->pubkey_algo);
2901 aval = subkey->length;
2905 fprintf (fp, _("Key Type ..: %s, %lu bit %s\n"), "PGP", aval, s);
2907 fprintf (fp, _("Key Usage .: "));
2910 if (subkey->can_encrypt) {
2911 fprintf (fp, "%s%s", delim, _("encryption"));
2914 if (subkey->can_sign) {
2915 fprintf (fp, "%s%s", delim, _("signing"));
2918 if (subkey->can_certify) {
2919 fprintf (fp, "%s%s", delim, _("certification"));
2927 setlocale (LC_TIME, "C");
2931 /* Show detailed information about the selected key */
2932 static void verify_key (crypt_key_t * key)
2935 char cmd[LONG_STRING], tempfile[_POSIX_PATH_MAX];
2937 gpgme_ctx_t listctx = NULL;
2939 gpgme_key_t k = NULL;
2942 fp = m_tempfile (tempfile, sizeof(tempfile), NONULL(MCore.tmpdir), NULL);
2944 mutt_perror (_("Can't create temporary file"));
2947 mutt_message _("Collecting data...");
2949 print_key_info (key->kobj, fp);
2951 err = gpgme_new (&listctx);
2953 fprintf (fp, "Internal error: can't create gpgme context: %s\n",
2954 gpgme_strerror (err));
2957 if ((key->flags & KEYFLAG_ISX509))
2958 gpgme_set_protocol (listctx, GPGME_PROTOCOL_CMS);
2962 while ((s = k->chain_id) && k->subkeys && m_strcmp(s, k->subkeys->fpr)) {
2964 err = gpgme_op_keylist_start (listctx, s, 0);
2965 gpgme_key_release (k);
2968 err = gpgme_op_keylist_next (listctx, &k);
2970 fprintf (fp, _("Error finding issuer key: %s\n"), gpgme_strerror (err));
2973 gpgme_op_keylist_end (listctx);
2975 print_key_info (k, fp);
2978 fputs (_("Error: certification chain to long - stopping here\n"), fp);
2984 gpgme_key_release (k);
2985 gpgme_release (listctx);
2987 mutt_clear_error ();
2988 snprintf (cmd, sizeof (cmd), _("Key ID: 0x%s"), crypt_keyid (key));
2989 mutt_do_pager (cmd, tempfile, 0, NULL);
2992 /* Implementation of `findkeys'. */
2994 /* Convert string_list_t into a pattern string suitable to be passed to GPGME.
2995 We need to convert spaces in an item into a '+' and '%' into
2997 static char *list_to_pattern (string_list_t * list)
3005 for (l = list; l; l = l->next) {
3006 for (s = l->data; *s; s++) {
3011 n++; /* delimiter or end of string */
3013 n++; /* make sure to allocate at least one byte */
3014 pattern = p = p_new(char, n);
3015 for (l = list; l; l = l->next) {
3020 for (s = l->data; *s; s++) {
3026 else if (*s == '+') {
3042 /* Return a list of keys which are candidates for the selection.
3043 Select by looking at the HINTS list. */
3044 static crypt_key_t *get_candidates (string_list_t * hints, unsigned int app,
3047 crypt_key_t *db, *k, **kend;
3053 gpgme_user_id_t uid = NULL;
3055 pattern = list_to_pattern (hints);
3059 err = gpgme_new (&ctx);
3061 mutt_error (_("gpgme_new failed: %s"), gpgme_strerror (err));
3069 if ((app & APPLICATION_PGP)) {
3070 /* Its all a mess. That old GPGME expects different things
3071 depending on the protocol. For gpg we don' t need percent
3072 escaped pappert but simple strings passed in an array to the
3073 keylist_ext_start function. */
3078 for (l = hints, n = 0; l; l = l->next) {
3079 if (l->data && *l->data)
3085 patarr = p_new(char *, n + 1);
3086 for (l = hints, n = 0; l; l = l->next) {
3087 if (l->data && *l->data)
3088 patarr[n++] = m_strdup(l->data);
3091 err = gpgme_op_keylist_ext_start (ctx, (const char **) patarr, secret, 0);
3092 for (n = 0; patarr[n]; n++)
3093 p_delete(&patarr[n]);
3096 mutt_error (_("gpgme_op_keylist_start failed: %s"), gpgme_strerror (err));
3097 gpgme_release (ctx);
3102 while (!(err = gpgme_op_keylist_next (ctx, &key))) {
3103 unsigned int flags = 0;
3105 if (key_check_cap (key, KEY_CAP_CAN_ENCRYPT))
3106 flags |= KEYFLAG_CANENCRYPT;
3107 if (key_check_cap (key, KEY_CAP_CAN_SIGN))
3108 flags |= KEYFLAG_CANSIGN;
3110 #if 0 /* DISABLED code */
3112 /* Bug in gpg. Capabilities are not listed for secret
3113 keys. Try to deduce them from the algorithm. */
3115 switch (key->subkeys[0].pubkey_algo) {
3117 flags |= KEYFLAG_CANENCRYPT;
3118 flags |= KEYFLAG_CANSIGN;
3120 case GPGME_PK_ELG_E:
3121 flags |= KEYFLAG_CANENCRYPT;
3124 flags |= KEYFLAG_CANSIGN;
3128 #endif /* DISABLED code */
3130 for (idx = 0, uid = key->uids; uid; idx++, uid = uid->next) {
3131 k = p_new(crypt_key_t, 1);
3140 if (gpg_err_code (err) != GPG_ERR_EOF)
3141 mutt_error (_("gpgme_op_keylist_next failed: %s"), gpgme_strerror (err));
3142 gpgme_op_keylist_end (ctx);
3147 if ((app & APPLICATION_SMIME)) {
3148 /* and now look for x509 certificates */
3149 gpgme_set_protocol (ctx, GPGME_PROTOCOL_CMS);
3150 err = gpgme_op_keylist_start (ctx, pattern, 0);
3152 mutt_error (_("gpgme_op_keylist_start failed: %s"), gpgme_strerror (err));
3153 gpgme_release (ctx);
3158 while (!(err = gpgme_op_keylist_next (ctx, &key))) {
3159 unsigned int flags = KEYFLAG_ISX509;
3161 if (key_check_cap (key, KEY_CAP_CAN_ENCRYPT))
3162 flags |= KEYFLAG_CANENCRYPT;
3163 if (key_check_cap (key, KEY_CAP_CAN_SIGN))
3164 flags |= KEYFLAG_CANSIGN;
3166 for (idx = 0, uid = key->uids; uid; idx++, uid = uid->next) {
3167 k = p_new(crypt_key_t, 1);
3176 if (gpg_err_code (err) != GPG_ERR_EOF)
3177 mutt_error (_("gpgme_op_keylist_next failed: %s"), gpgme_strerror (err));
3178 gpgme_op_keylist_end (ctx);
3181 gpgme_release (ctx);
3186 /* Add the string STR to the list HINTS. This list is later used to
3188 static string_list_t *crypt_add_string_to_hints (string_list_t * hints, const char *str)
3193 if ((scratch = m_strdup(str)) == NULL)
3196 for (t = strtok (scratch, " ,.:\"()<>\n"); t;
3197 t = strtok (NULL, " ,.:\"()<>\n")) {
3198 if (m_strlen(t) > 3)
3199 hints = mutt_add_list(hints, t);
3206 /* Display a menu to select a key from the array KEYS. FORCED_VALID
3207 will be set to true on return if the user did override the the
3209 static crypt_key_t *crypt_select_key (crypt_key_t * keys,
3210 address_t * p, const char *s,
3211 unsigned int app, int *forced_valid)
3214 crypt_key_t **key_table;
3217 char helpstr[STRING], buf[LONG_STRING];
3219 int (*f) (const void *, const void *);
3220 int menu_to_use = 0;
3225 /* build the key table */
3228 for (k = keys; k; k = k->next) {
3229 if (!option (OPTPGPSHOWUNUSABLE) && (k->flags & KEYFLAG_CANTUSE)) {
3236 p_realloc(&key_table, keymax);
3242 if (!i && unusable) {
3243 mutt_error _("All matching keys are marked expired/revoked.");
3249 switch (PgpSortKeys & SORT_MASK) {
3251 f = crypt_compare_date;
3254 f = crypt_compare_keyid;
3257 f = crypt_compare_address;
3261 f = crypt_compare_trust;
3264 qsort (key_table, i, sizeof (crypt_key_t *), f);
3266 if (app & APPLICATION_PGP)
3267 menu_to_use = MENU_KEY_SELECT_PGP;
3268 else if (app & APPLICATION_SMIME)
3269 menu_to_use = MENU_KEY_SELECT_SMIME;
3272 mutt_make_help (buf, sizeof (buf), _("Exit "), menu_to_use, OP_EXIT);
3273 m_strcat(helpstr, sizeof(helpstr), buf);
3274 mutt_make_help (buf, sizeof (buf), _("Select "), menu_to_use,
3275 OP_GENERIC_SELECT_ENTRY);
3276 m_strcat(helpstr, sizeof(helpstr), buf);
3277 mutt_make_help (buf, sizeof (buf), _("Check key "),
3278 menu_to_use, OP_VERIFY_KEY);
3279 m_strcat(helpstr, sizeof(helpstr), buf);
3280 mutt_make_help (buf, sizeof (buf), _("Help"), menu_to_use, OP_HELP);
3281 m_strcat(helpstr, sizeof(helpstr), buf);
3283 menu = mutt_new_menu ();
3285 menu->make_entry = crypt_entry;
3286 menu->menu = menu_to_use;
3287 menu->help = helpstr;
3288 menu->data = key_table;
3293 if ((app & APPLICATION_PGP) && (app & APPLICATION_SMIME))
3294 ts = _("PGP and S/MIME keys matching");
3295 else if ((app & APPLICATION_PGP))
3296 ts = _("PGP keys matching");
3297 else if ((app & APPLICATION_SMIME))
3298 ts = _("S/MIME keys matching");
3300 ts = _("keys matching");
3303 snprintf (buf, sizeof (buf), _("%s <%s>."), ts, p->mailbox);
3305 snprintf (buf, sizeof (buf), _("%s \"%s\"."), ts, s);
3309 mutt_clear_error ();
3313 switch (mutt_menuLoop (menu)) {
3315 verify_key (key_table[menu->current]);
3316 menu->redraw = REDRAW_FULL;
3320 mutt_message ("%s", key_table[menu->current]->uid);
3323 case OP_GENERIC_SELECT_ENTRY:
3324 /* FIXME make error reporting more verbose - this should be
3325 easy because gpgme provides more information */
3326 if (option (OPTPGPCHECKTRUST)) {
3327 if (!crypt_key_is_valid (key_table[menu->current])) {
3328 mutt_error _("This key can't be used: "
3329 "expired/disabled/revoked.");
3334 if (option (OPTPGPCHECKTRUST) &&
3335 (!crypt_id_is_valid (key_table[menu->current])
3336 || !crypt_id_is_strong (key_table[menu->current]))) {
3338 char buff[LONG_STRING];
3340 if (key_table[menu->current]->flags & KEYFLAG_CANTUSE)
3341 s = N_("ID is expired/disabled/revoked.");
3343 gpgme_validity_t val = GPGME_VALIDITY_UNKNOWN;
3344 gpgme_user_id_t uid = NULL;
3349 uid = key_table[menu->current]->kobj->uids;
3350 for (j = 0; (j < key_table[menu->current]->idx) && uid;
3351 j++, uid = uid->next);
3353 val = uid->validity;
3356 case GPGME_VALIDITY_UNKNOWN:
3357 case GPGME_VALIDITY_UNDEFINED:
3358 warn_s = N_("ID has undefined validity.");
3360 case GPGME_VALIDITY_NEVER:
3361 warn_s = N_("ID is not valid.");
3363 case GPGME_VALIDITY_MARGINAL:
3364 warn_s = N_("ID is only marginally valid.");
3366 case GPGME_VALIDITY_FULL:
3367 case GPGME_VALIDITY_ULTIMATE:
3371 snprintf (buff, sizeof (buff),
3372 _("%s Do you really want to use the key?"), _(warn_s));
3374 if (mutt_yesorno (buff, 0) != 1) {
3375 mutt_clear_error ();
3382 k = crypt_copy_key (key_table[menu->current]);
3393 mutt_menuDestroy (&menu);
3394 p_delete(&key_table);
3396 set_option (OPTNEEDREDRAW);
3401 static crypt_key_t *crypt_getkeybyaddr (address_t * a, short abilities,
3402 unsigned int app, int *forced_valid)
3405 string_list_t *hints = NULL;
3410 int this_key_has_strong;
3411 int this_key_has_weak;
3412 int this_key_has_invalid;
3415 crypt_key_t *keys, *k;
3416 crypt_key_t *the_valid_key = NULL;
3417 crypt_key_t *matches = NULL;
3418 crypt_key_t **matches_endp = &matches;
3422 if (a && a->mailbox)
3423 hints = crypt_add_string_to_hints (hints, a->mailbox);
3424 if (a && a->personal)
3425 hints = crypt_add_string_to_hints (hints, a->personal);
3427 mutt_message (_("Looking for keys matching \"%s\"..."), a->mailbox);
3428 keys = get_candidates (hints, app, (abilities & KEYFLAG_CANSIGN));
3430 string_list_wipe(&hints);
3435 for (k = keys; k; k = k->next) {
3436 if (abilities && !(k->flags & abilities)) {
3440 this_key_has_weak = 0; /* weak but valid match */
3441 this_key_has_invalid = 0; /* invalid match */
3442 this_key_has_strong = 0; /* strong and valid match */
3443 match = 0; /* any match */
3445 r = rfc822_parse_adrlist (NULL, k->uid);
3446 for (p = r; p; p = p->next) {
3447 int validity = crypt_id_matches_addr (a, p, k);
3449 if (validity & CRYPT_KV_MATCH) /* something matches */
3452 /* is this key a strong candidate? */
3453 if ((validity & CRYPT_KV_VALID)
3454 && (validity & CRYPT_KV_STRONGID)
3455 && (validity & CRYPT_KV_ADDR)) {
3456 if (the_valid_key && the_valid_key != k)
3459 this_key_has_strong = 1;
3461 else if ((validity & CRYPT_KV_MATCH)
3462 && !(validity & CRYPT_KV_VALID))
3463 this_key_has_invalid = 1;
3464 else if ((validity & CRYPT_KV_MATCH)
3465 && (!(validity & CRYPT_KV_STRONGID)
3466 || !(validity & CRYPT_KV_ADDR)))
3467 this_key_has_weak = 1;
3469 address_list_wipe(&r);
3474 if (!this_key_has_strong && this_key_has_invalid)
3476 if (!this_key_has_strong && this_key_has_weak)
3479 *matches_endp = tmp = crypt_copy_key (k);
3480 matches_endp = &tmp->next;
3481 the_valid_key = tmp;
3485 crypt_free_key (&keys);
3488 if (the_valid_key && !multi && !weak
3489 && !(invalid && option (OPTPGPSHOWUNUSABLE))) {
3491 * There was precisely one strong match on a valid ID, there
3492 * were no valid keys with weak matches, and we aren't
3493 * interested in seeing invalid keys.
3495 * Proceed without asking the user.
3497 k = crypt_copy_key (the_valid_key);
3501 * Else: Ask the user.
3503 k = crypt_select_key (matches, a, NULL, app, forced_valid);
3505 crypt_free_key (&matches);
3514 static crypt_key_t *crypt_getkeybystr (const char *p, short abilities,
3515 unsigned int app, int *forced_valid)
3517 string_list_t *hints = NULL;
3519 crypt_key_t *matches = NULL;
3520 crypt_key_t **matches_endp = &matches;
3524 mutt_message (_("Looking for keys matching \"%s\"..."), p);
3528 hints = crypt_add_string_to_hints (hints, p);
3529 keys = get_candidates (hints, app, (abilities & KEYFLAG_CANSIGN));
3530 string_list_wipe(&hints);
3535 for (k = keys; k; k = k->next) {
3536 if (abilities && !(k->flags & abilities))
3541 if (!*p || !m_strcasecmp(p, crypt_keyid (k))
3542 || (!m_strncasecmp(p, "0x", 2)
3543 && !m_strcasecmp(p + 2, crypt_keyid (k)))
3544 || (option (OPTPGPLONGIDS)
3545 && !m_strncasecmp(p, "0x", 2)
3546 && !m_strcasecmp(p + 2, crypt_keyid (k) + 8))
3547 || m_stristr(k->uid, p)) {
3550 *matches_endp = tmp = crypt_copy_key (k);
3551 matches_endp = &tmp->next;
3555 crypt_free_key (&keys);
3558 k = crypt_select_key (matches, NULL, p, app, forced_valid);
3559 crypt_free_key (&matches);
3566 /* Display TAG as a prompt to ask for a key. If WHATFOR is not null
3567 use it as default and store it under that label as the next
3568 default. ABILITIES describe the required key abilities (sign,
3569 encrypt) and APP the type of the requested key; ether S/MIME or
3570 PGP. Return a copy of the key or NULL if not found. */
3571 static crypt_key_t *crypt_ask_for_key (char *tag,
3574 unsigned int app, int *forced_valid)
3578 struct crypt_cache *l = NULL;
3582 forced_valid = &dummy;
3584 mutt_clear_error ();
3590 for (l = id_defaults; l; l = l->next)
3591 if (!m_strcasecmp(whatfor, l->what)) {
3592 m_strcpy(resp, sizeof(resp), NONULL(l->dflt));
3600 if (mutt_get_field (tag, resp, sizeof (resp), M_CLEAR) != 0)
3605 m_strreplace(&l->dflt, resp);
3607 l = p_new(struct crypt_cache, 1);
3608 l->next = id_defaults;
3610 l->what = m_strdup(whatfor);
3611 l->dflt = m_strdup(resp);
3615 if ((key = crypt_getkeybystr (resp, abilities, app, forced_valid)))
3623 /* This routine attempts to find the keyids of the recipients of a
3624 message. It returns NULL if any of the keys can not be found. */
3625 static char *find_keys (address_t * to, address_t * cc, address_t * bcc,
3628 char *keylist = NULL, *t;
3630 ssize_t keylist_size = 0;
3631 ssize_t keylist_used = 0;
3632 address_t *tmp = NULL, *addr = NULL;
3633 address_t **last = &tmp;
3636 crypt_key_t *k_info, *key;
3637 const char *fqdn = mutt_fqdn (1);
3640 *r_application = APPLICATION_PGP | APPLICATION_SMIME;
3643 for (i = 0; i < 3; i++) {
3658 *last = address_list_dup (p);
3660 last = &((*last)->next);
3663 rfc822_qualify(tmp, fqdn);
3664 address_list_uniq(tmp);
3666 for (p = tmp; p; p = p->next) {
3667 char buf[LONG_STRING];
3668 int forced_valid = 0;
3673 if ((keyID = mutt_crypt_hook (p)) != NULL) {
3676 snprintf (buf, sizeof (buf), _("Use keyID = \"%s\" for %s?"),
3678 if ((r = mutt_yesorno (buf, M_YES)) == M_YES) {
3679 /* check for e-mail address */
3680 if ((t = strchr (keyID, '@')) &&
3681 (addr = rfc822_parse_adrlist (NULL, keyID))) {
3682 rfc822_qualify(addr, fqdn);
3686 k_info = crypt_getkeybystr (keyID, KEYFLAG_CANENCRYPT,
3687 app, &forced_valid);
3692 address_list_wipe(&tmp);
3693 address_list_wipe(&addr);
3699 && (k_info = crypt_getkeybyaddr (q, KEYFLAG_CANENCRYPT,
3700 app, &forced_valid)) == NULL) {
3701 snprintf (buf, sizeof (buf), _("Enter keyID for %s: "), q->mailbox);
3703 if ((key = crypt_ask_for_key (buf, q->mailbox, KEYFLAG_CANENCRYPT,
3705 &forced_valid)) == NULL) {
3707 address_list_wipe(&tmp);
3708 address_list_wipe(&addr);
3716 const char *s = crypt_fpr (key);
3718 keylist_size += m_strlen(s) + 4 + 1;
3719 p_realloc(&keylist, keylist_size);
3720 sprintf (keylist + keylist_used, "%s0x%s%s",
3721 keylist_used ? " " : "", s, forced_valid ? "!" : "");
3723 keylist_used = m_strlen(keylist);
3725 crypt_free_key (&key);
3726 address_list_wipe(&addr);
3728 address_list_wipe(&tmp);
3732 char *crypt_pgp_findkeys (address_t * to, address_t * cc, address_t * bcc)
3734 return find_keys (to, cc, bcc, APPLICATION_PGP);
3737 char *crypt_smime_findkeys (address_t * to, address_t * cc, address_t * bcc)
3739 return find_keys (to, cc, bcc, APPLICATION_SMIME);
3742 static int gpgme_send_menu (HEADER * msg, int *redraw, int is_smime)
3745 char input_signas[STRING];
3748 if (msg->security & APPLICATION_PGP)
3750 else if (msg->security & APPLICATION_SMIME)
3755 mutt_multi_choice (_
3756 ("S/MIME (e)ncrypt, (s)ign, sign (a)s, (b)oth, (p)gp or (c)lear?"),
3760 mutt_multi_choice (_
3761 ("PGP (e)ncrypt, (s)ign, sign (a)s, (b)oth, s/(m)ime or (c)lear?"),
3765 case 1: /* (e)ncrypt */
3766 msg->security |= (is_smime ? SMIMEENCRYPT : PGPENCRYPT);
3767 msg->security &= ~(is_smime ? SMIMESIGN : PGPSIGN);
3770 case 2: /* (s)ign */
3771 msg->security |= (is_smime ? SMIMESIGN : PGPSIGN);
3772 msg->security &= ~(is_smime ? SMIMEENCRYPT : PGPENCRYPT);
3775 case 3: /* sign (a)s */
3776 /* unset_option(OPTCRYPTCHECKTRUST); */
3777 if ((p = crypt_ask_for_key (_("Sign as: "), NULL, KEYFLAG_CANSIGN,
3778 is_smime ? APPLICATION_SMIME :
3779 APPLICATION_PGP, NULL))) {
3780 snprintf (input_signas, sizeof (input_signas), "0x%s", crypt_keyid (p));
3781 m_strreplace(is_smime ? &SmimeDefaultKey : &PgpSignAs,
3783 crypt_free_key (&p);
3785 msg->security |= (is_smime ? SMIMESIGN : PGPSIGN);
3787 *redraw = REDRAW_FULL;
3790 case 4: /* (b)oth */
3792 (is_smime ? (SMIMEENCRYPT | SMIMESIGN) : (PGPENCRYPT | PGPSIGN));
3795 case 5: /* (p)gp or s/(m)ime */
3796 is_smime = !is_smime;
3799 case 6: /* (c)lear */
3804 if (choice == 6 || choice == 7);
3805 else if (is_smime) {
3806 msg->security &= ~APPLICATION_PGP;
3807 msg->security |= APPLICATION_SMIME;
3810 msg->security &= ~APPLICATION_SMIME;
3811 msg->security |= APPLICATION_PGP;
3814 return (msg->security);
3817 int crypt_pgp_send_menu(HEADER * msg, int *redraw)
3819 return gpgme_send_menu(msg, redraw, 0);
3822 int crypt_smime_send_menu(HEADER * msg, int *redraw)
3824 return gpgme_send_menu (msg, redraw, 1);
3827 int crypt_smime_verify_sender (HEADER * h)
3829 address_t *sender = NULL;
3830 unsigned int ret = 1;
3833 h->env->from = mutt_expand_aliases (h->env->from);
3834 sender = h->env->from;
3836 else if (h->env->sender) {
3837 h->env->sender = mutt_expand_aliases (h->env->sender);
3838 sender = h->env->sender;
3842 if (signature_key) {
3843 gpgme_key_t key = signature_key;
3844 gpgme_user_id_t uid = NULL;
3845 int sender_length = 0;
3848 sender_length = m_strlen(sender->mailbox);
3849 for (uid = key->uids; uid && ret; uid = uid->next) {
3850 uid_length = m_strlen(uid->email);
3851 if (1 && (uid->email[0] == '<')
3852 && (uid->email[uid_length - 1] == '>')
3853 && (uid_length == sender_length + 2)
3854 && (!m_strncmp (uid->email + 1, sender->mailbox, sender_length)))
3859 mutt_any_key_to_continue ("Failed to verify sender");
3862 mutt_any_key_to_continue ("Failed to figure out sender");
3864 if (signature_key) {
3865 gpgme_key_release (signature_key);
3866 signature_key = NULL;
3872 static void invoke_import(const char *fname, int smime)
3874 gpgme_ctx_t ctx = create_gpgme_context(smime);
3878 err = gpgme_data_new_from_file(&data, fname, 1);
3880 mutt_error (_("error allocating data object: %s\n"), gpgme_strerror (err));
3885 err = gpgme_op_import(ctx, data);
3887 mutt_error(_("error importing gpg data: %s\n"), gpgme_strerror(err));
3888 gpgme_data_release(data);
3893 gpgme_data_release(data);
3898 void crypt_pgp_invoke_import(const char *fname)
3900 invoke_import(fname, 0);
3903 void crypt_smime_invoke_import(const char *fname)
3905 invoke_import(fname, 1);
3908 static void pgp_extract_keys_from_attachment (FILE * fp, BODY * top)
3912 char tempfname[_POSIX_PATH_MAX];
3914 tempfp = m_tempfile(tempfname, sizeof(tempfname), NONULL(MCore.tmpdir), NULL);
3915 if (tempfp == NULL) {
3916 mutt_perror (_("Can't create temporary file"));
3925 mutt_body_handler (top, &s);
3928 crypt_pgp_invoke_import(tempfname);
3929 mutt_unlink (tempfname);
3932 void crypt_pgp_extract_keys_from_attachment_list(FILE * fp, int tag, BODY * top)
3935 set_option (OPTDONTHANDLEPGPKEYS);
3937 for (; top; top = top->next) {
3938 if (!tag || top->tagged)
3939 pgp_extract_keys_from_attachment (fp, top);
3945 unset_option (OPTDONTHANDLEPGPKEYS);