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>
17 #ifdef CRYPT_BACKEND_GPGME
22 #ifdef HAVE_LANGINFO_D_T_FMT
23 # include <langinfo.h>
25 #ifdef HAVE_SYS_RESOURCE_H
26 # include <sys/resource.h>
31 #include <lib-mime/mime.h>
33 #include <lib-ui/curses.h>
34 #include <lib-ui/enter.h>
35 #include <lib-ui/menu.h>
39 #include <lib-crypt/crypt.h>
43 #include "recvattach.h"
49 #define digitp(p) (*(p) >= '0' && *(p) <= '9')
50 #define hexdigitp(a) (digitp (a) \
51 || (*(a) >= 'A' && *(a) <= 'F') \
52 || (*(a) >= 'a' && *(a) <= 'f'))
53 #define xtoi_1(p) (*(p) <= '9'? (*(p)- '0'): \
54 *(p) <= 'F'? (*(p)-'A'+10):(*(p)-'a'+10))
55 #define xtoi_2(p) ((xtoi_1(p) * 16) + xtoi_1((p)+1))
57 /* Values used for comparing addresses. */
58 #define CRYPT_KV_VALID 1
59 #define CRYPT_KV_ADDR 2
60 #define CRYPT_KV_STRING 4
61 #define CRYPT_KV_STRONGID 8
62 #define CRYPT_KV_MATCH (CRYPT_KV_ADDR|CRYPT_KV_STRING)
71 struct crypt_cache *next;
79 /* We work based on user IDs, getting from a user ID to the key is
80 check and does not need any memory (gpgme uses reference counting). */
81 typedef struct crypt_keyinfo {
82 struct crypt_keyinfo *next;
84 int idx; /* and the user ID at this index */
85 const char *uid; /* and for convenience point to this user ID */
86 unsigned int flags; /* global and per uid flags (for convenience) */
89 typedef struct crypt_entry {
95 static struct crypt_cache *id_defaults = NULL;
96 static gpgme_key_t signature_key = NULL;
99 * General helper functions.
102 /* return true when S points to a didgit or letter. */
103 static int digit_or_letter (const unsigned char *s)
105 return ((*s >= '0' && *s <= '9')
106 || (*s >= 'A' && *s <= 'Z')
107 || (*s >= 'a' && *s <= 'z'));
111 /* Print the utf-8 encoded string BUF of length LEN bytes to stream
112 FP. Convert the character set. */
113 static void print_utf8 (FILE * fp, const char *buf, ssize_t len)
117 tstr = p_dupstr(buf, len);
118 mutt_convert_string (&tstr, "utf-8", Charset, M_ICONV_HOOK_FROM);
128 /* Return the keyID for the key K. Note that this string is valid as
129 long as K is valid */
130 static const char *crypt_keyid (crypt_key_t * k)
132 const char *s = "????????";
134 if (k->kobj && k->kobj->subkeys) {
135 s = k->kobj->subkeys->keyid;
136 if ((!option (OPTPGPLONGIDS)) && (m_strlen(s) == 16))
137 /* Return only the short keyID. */
144 /* Return the hexstring fingerprint from the key K. */
145 static const char *crypt_fpr (crypt_key_t * k)
149 if (k->kobj && k->kobj->subkeys)
150 s = k->kobj->subkeys->fpr;
155 /* Parse FLAGS and return a statically allocated(!) string with them. */
156 static char *crypt_key_abilities (int flags)
160 if (!(flags & KEYFLAG_CANENCRYPT))
162 else if (flags & KEYFLAG_PREFER_SIGNING)
167 if (!(flags & KEYFLAG_CANSIGN))
169 else if (flags & KEYFLAG_PREFER_ENCRYPTION)
179 /* Parse FLAGS and return a character describing the most important flag. */
180 static char crypt_flags (int flags)
182 if (flags & KEYFLAG_REVOKED)
184 else if (flags & KEYFLAG_EXPIRED)
186 else if (flags & KEYFLAG_DISABLED)
188 else if (flags & KEYFLAG_CRITICAL)
194 /* Return a copy of KEY. */
195 static crypt_key_t *crypt_copy_key (crypt_key_t *key)
199 k = p_new(crypt_key_t, 1);
201 gpgme_key_ref (key->kobj);
204 k->flags = key->flags;
209 /* Release all the keys at the address of KEYLIST and set the address
211 static void crypt_free_key (crypt_key_t ** keylist)
214 crypt_key_t *k = (*keylist)->next;
221 /* Return trute when key K is valid. */
222 static int crypt_key_is_valid (crypt_key_t * k)
224 if (k->flags & KEYFLAG_CANTUSE)
229 /* Return true whe validity of KEY is sufficient. */
230 static int crypt_id_is_strong (crypt_key_t * key)
232 gpgme_validity_t val = GPGME_VALIDITY_UNKNOWN;
233 gpgme_user_id_t uid = NULL;
237 if ((key->flags & KEYFLAG_ISX509))
240 for (i = 0, uid = key->kobj->uids; (i < key->idx) && uid;
241 i++, uid = uid->next);
246 case GPGME_VALIDITY_UNKNOWN:
247 case GPGME_VALIDITY_UNDEFINED:
248 case GPGME_VALIDITY_NEVER:
249 case GPGME_VALIDITY_MARGINAL:
253 case GPGME_VALIDITY_FULL:
254 case GPGME_VALIDITY_ULTIMATE:
262 /* Return true when the KEY is valid, i.e. not marked as unusable. */
263 static int crypt_id_is_valid (crypt_key_t * key)
265 return !(key->flags & KEYFLAG_CANTUSE);
268 /* Return a bit vector describing how well the addresses ADDR and
269 U_ADDR match and whether KEY is valid. */
270 static int crypt_id_matches_addr (address_t * addr, address_t * u_addr,
275 if (crypt_id_is_valid (key))
276 rv |= CRYPT_KV_VALID;
278 if (crypt_id_is_strong (key))
279 rv |= CRYPT_KV_STRONGID;
281 if (addr->mailbox && u_addr->mailbox
282 && m_strcasecmp(addr->mailbox, u_addr->mailbox) == 0)
285 if (addr->personal && u_addr->personal
286 && m_strcasecmp(addr->personal, u_addr->personal) == 0)
287 rv |= CRYPT_KV_STRING;
294 * GPGME convenient functions.
297 /* Create a new gpgme context and return it. With FOR_SMIME set to
298 true, the protocol of the context is set to CMS. */
299 static gpgme_ctx_t create_gpgme_context (int for_smime)
304 err = gpgme_new (&ctx);
306 mutt_error (_("error creating gpgme context: %s\n"), gpgme_strerror (err));
312 err = gpgme_set_protocol (ctx, GPGME_PROTOCOL_CMS);
314 mutt_error (_("error enabling CMS protocol: %s\n"), gpgme_strerror (err));
323 /* Create a new gpgme data object. This is a wrapper to die on
325 static gpgme_data_t create_gpgme_data (void)
330 err = gpgme_data_new (&data);
332 mutt_error (_("error creating gpgme data object: %s\n"),
333 gpgme_strerror (err));
340 /* Create a new GPGME Data object from the mail body A. With CONVERT
341 passed as true, the lines are converted to CR,LF if required.
342 Return NULL on error or the gpgme_data_t object on success. */
343 static gpgme_data_t body_to_data_object (BODY * a, int convert)
345 char tempfile[_POSIX_PATH_MAX];
350 mutt_mktemp (tempfile);
351 fptmp = safe_fopen (tempfile, "w+");
353 mutt_perror (tempfile);
357 mutt_write_mime_header (a, fptmp);
359 mutt_write_mime_body (a, fptmp);
363 unsigned char buf[1];
365 data = create_gpgme_data ();
367 while ((c = fgetc (fptmp)) != EOF) {
371 if (c == '\n' && !hadcr) {
373 gpgme_data_write (data, buf, 1);
378 /* FIXME: This is quite suboptimal */
380 gpgme_data_write (data, buf, 1);
383 gpgme_data_seek (data, 0, SEEK_SET);
387 err = gpgme_data_new_from_file (&data, tempfile, 1);
391 mutt_error (_("error allocating data object: %s\n"), gpgme_strerror (err));
398 /* Create a GPGME data object from the stream FP but limit the object
399 to LENGTH bytes starting at OFFSET bytes from the beginning of the
401 static gpgme_data_t file_to_data_object (FILE * fp, long offset, long length)
406 err = gpgme_data_new_from_filepart (&data, NULL, fp, offset, length);
408 mutt_error (_("error allocating data object: %s\n"), gpgme_strerror (err));
415 /* Write a GPGME data object to the stream FP. */
416 static int data_object_to_stream (gpgme_data_t data, FILE * fp)
422 err = ((gpgme_data_seek (data, 0, SEEK_SET) == -1)
423 ? gpgme_error_from_errno (errno) : 0);
425 mutt_error (_("error rewinding data object: %s\n"), gpgme_strerror (err));
429 while ((nread = gpgme_data_read (data, buf, sizeof (buf)))) {
430 /* fixme: we are not really converting CRLF to LF but just
431 skipping CR. Doing it correctly needs a more complex logic */
432 for (p = buf; nread; p++, nread--) {
438 mutt_perror ("[tempfile]");
443 mutt_error (_("error reading data object: %s\n"), strerror (errno));
449 /* Copy a data object to a newly created temporay file and return that
450 filename. Caller must free. With RET_FP not NULL, don't close the
451 stream but return it there. */
452 static char *data_object_to_tempfile (gpgme_data_t data, FILE ** ret_fp)
455 char tempfile[_POSIX_PATH_MAX];
459 mutt_mktemp (tempfile);
460 fp = safe_fopen (tempfile, "w+");
462 mutt_perror (tempfile);
466 err = ((gpgme_data_seek (data, 0, SEEK_SET) == -1)
467 ? gpgme_error_from_errno (errno) : 0);
471 while ((nread = gpgme_data_read (data, buf, sizeof (buf)))) {
472 if (fwrite (buf, nread, 1, fp) != 1) {
473 mutt_perror (tempfile);
485 mutt_error (_("error reading data object: %s\n"), gpgme_strerror (err));
492 return m_strdup(tempfile);
496 /* Create a GpgmeRecipientSet from the keys in the string KEYLIST.
497 The keys must be space delimited. */
498 static gpgme_key_t *create_recipient_set (const char *keylist,
499 gpgme_protocol_t protocol)
505 gpgme_key_t *rset = NULL;
506 unsigned int rset_n = 0;
507 gpgme_key_t key = NULL;
508 gpgme_ctx_t context = NULL;
510 err = gpgme_new (&context);
512 err = gpgme_set_protocol (context, protocol);
519 for (i = 0; *s && *s != ' ' && i < ssizeof(buf) - 1;)
523 if (i > 1 && buf[i - 1] == '!') {
524 /* The user selected to override the valididy of that
528 err = gpgme_get_key (context, buf, &key, 0);
530 key->uids->validity = GPGME_VALIDITY_FULL;
534 err = gpgme_get_key (context, buf, &key, 0);
537 p_realloc(&rset, rset_n + 1);
538 rset[rset_n++] = key;
541 mutt_error (_("error adding recipient `%s': %s\n"),
542 buf, gpgme_strerror (err));
550 /* NULL terminate. */
551 p_realloc(&rset, rset_n + 1);
552 rset[rset_n++] = NULL;
555 gpgme_release (context);
561 /* Make sure that the correct signer is set. Returns 0 on success. */
562 static int set_signer (gpgme_ctx_t ctx, int for_smime)
564 char *signid = for_smime ? SmimeDefaultKey : PgpSignAs;
567 gpgme_key_t key, key2;
569 if (!signid || !*signid)
572 listctx = create_gpgme_context (for_smime);
573 err = gpgme_op_keylist_start (listctx, signid, 1);
575 err = gpgme_op_keylist_next (listctx, &key);
577 gpgme_release (listctx);
578 mutt_error (_("secret key `%s' not found: %s\n"),
579 signid, gpgme_strerror (err));
582 err = gpgme_op_keylist_next (listctx, &key2);
584 gpgme_key_release (key);
585 gpgme_key_release (key2);
586 gpgme_release (listctx);
587 mutt_error (_("ambiguous specification of secret key `%s'\n"), signid);
590 gpgme_op_keylist_end (listctx);
591 gpgme_release (listctx);
593 gpgme_signers_clear (ctx);
594 err = gpgme_signers_add (ctx, key);
595 gpgme_key_release (key);
597 mutt_error (_("error setting secret key `%s': %s\n"),
598 signid, gpgme_strerror (err));
605 /* Encrypt the gpgme data object PLAINTEXT to the recipients in RSET
606 and return an allocated filename to a temporary file containing the
607 enciphered text. With USE_SMIME set to true, the smime backend is
608 used. With COMBINED_SIGNED a PGP message is signed and
609 encrypted. Returns NULL in case of error */
610 static char *encrypt_gpgme_object (gpgme_data_t plaintext, gpgme_key_t * rset,
611 int use_smime, int combined_signed)
615 gpgme_data_t ciphertext;
618 ctx = create_gpgme_context (use_smime);
620 gpgme_set_armor (ctx, 1);
622 ciphertext = create_gpgme_data ();
624 if (combined_signed) {
625 if (set_signer (ctx, use_smime)) {
626 gpgme_data_release (ciphertext);
630 err = gpgme_op_encrypt_sign (ctx, rset, GPGME_ENCRYPT_ALWAYS_TRUST,
631 plaintext, ciphertext);
634 err = gpgme_op_encrypt (ctx, rset, GPGME_ENCRYPT_ALWAYS_TRUST,
635 plaintext, ciphertext);
636 mutt_need_hard_redraw ();
638 mutt_error (_("error encrypting data: %s\n"), gpgme_strerror (err));
639 gpgme_data_release (ciphertext);
646 outfile = data_object_to_tempfile (ciphertext, NULL);
647 gpgme_data_release (ciphertext);
651 /* Find the "micalg" parameter from the last Gpgme operation on
652 context CTX. It is expected that this operation was a sign
653 operation. Return the algorithm name as a C string in buffer BUF
654 which must have been allocated by the caller with size BUFLEN.
655 Returns 0 on success or -1 in case of an error. The return string
656 is truncted to BUFLEN - 1. */
657 static int get_micalg (gpgme_ctx_t ctx, char *buf, ssize_t buflen)
659 gpgme_sign_result_t result = NULL;
660 const char *algorithm_name = NULL;
666 result = gpgme_op_sign_result (ctx);
668 algorithm_name = gpgme_hash_algo_name (result->signatures->hash_algo);
669 if (algorithm_name) {
670 m_strcpy(buf, buflen, algorithm_name);
674 return *buf ? 0 : -1;
677 static void print_time (time_t t, STATE * s)
681 setlocale (LC_TIME, "");
682 #ifdef HAVE_LANGINFO_D_T_FMT
683 strftime (p, sizeof (p), nl_langinfo (D_T_FMT), localtime (&t));
685 strftime (p, sizeof (p), "%c", localtime (&t));
687 setlocale (LC_TIME, "C");
688 state_attach_puts (p, s);
692 * Implementation of `sign_message'.
695 /* Sign the MESSAGE in body A either using OpenPGP or S/MIME when
696 USE_SMIME is passed as true. Returns the new body or NULL on
698 static BODY *sign_message (BODY * a, int use_smime)
705 gpgme_data_t message, signature;
707 convert_to_7bit (a); /* Signed data _must_ be in 7-bit format. */
709 message = body_to_data_object (a, 1);
712 signature = create_gpgme_data ();
714 ctx = create_gpgme_context (use_smime);
716 gpgme_set_armor (ctx, 1);
718 if (set_signer (ctx, use_smime)) {
719 gpgme_data_release (signature);
724 err = gpgme_op_sign (ctx, message, signature, GPGME_SIG_MODE_DETACH);
725 mutt_need_hard_redraw ();
726 gpgme_data_release (message);
728 gpgme_data_release (signature);
730 mutt_error (_("error signing data: %s\n"), gpgme_strerror (err));
734 sigfile = data_object_to_tempfile (signature, NULL);
735 gpgme_data_release (signature);
742 t->type = TYPEMULTIPART;
743 t->subtype = m_strdup("signed");
744 t->encoding = ENC7BIT;
746 t->disposition = DISPINLINE;
748 parameter_set_boundary(&t->parameter);
749 parameter_setval(&t->parameter, "protocol",
750 use_smime ? "application/pkcs7-signature"
751 : "application/pgp-signature");
752 /* Get the micalg from gpgme. Old gpgme versions don't support this
753 for S/MIME so we assume sha-1 in this case. */
754 if (!get_micalg (ctx, buf, sizeof buf))
755 parameter_setval(&t->parameter, "micalg", buf);
757 parameter_setval(&t->parameter, "micalg", "sha1");
763 t->parts->next = body_new();
765 t->type = TYPEAPPLICATION;
767 t->subtype = m_strdup("pkcs7-signature");
768 parameter_setval(&t->parameter, "name", "smime.p7s");
769 t->encoding = ENCBASE64;
771 t->disposition = DISPATTACH;
772 t->d_filename = m_strdup("smime.p7s");
775 t->subtype = m_strdup("pgp-signature");
777 t->disposition = DISPINLINE;
778 t->encoding = ENC7BIT;
780 t->filename = sigfile;
781 t->unlink = 1; /* ok to remove this file after sending. */
787 BODY *pgp_gpgme_sign_message (BODY * a)
789 return sign_message (a, 0);
792 BODY *smime_gpgme_sign_message (BODY * a)
794 return sign_message (a, 1);
798 * Implementation of `encrypt_message'.
801 /* Encrypt the mail body A to all keys given as space separated keyids
802 or fingerprints in KEYLIST and return the encrypted body. */
803 BODY *pgp_gpgme_encrypt_message (BODY * a, char *keylist, int sign)
805 char *outfile = NULL;
807 gpgme_key_t *rset = NULL;
808 gpgme_data_t plaintext;
810 rset = create_recipient_set (keylist, GPGME_PROTOCOL_OpenPGP);
816 plaintext = body_to_data_object (a, 0);
822 outfile = encrypt_gpgme_object (plaintext, rset, 0, sign);
823 gpgme_data_release (plaintext);
829 t->type = TYPEMULTIPART;
830 t->subtype = m_strdup("encrypted");
831 t->encoding = ENC7BIT;
833 t->disposition = DISPINLINE;
835 parameter_set_boundary(&t->parameter);
836 parameter_setval(&t->parameter, "protocol", "application/pgp-encrypted");
838 t->parts = body_new();
839 t->parts->type = TYPEAPPLICATION;
840 t->parts->subtype = m_strdup("pgp-encrypted");
841 t->parts->encoding = ENC7BIT;
843 t->parts->next = body_new();
844 t->parts->next->type = TYPEAPPLICATION;
845 t->parts->next->subtype = m_strdup("octet-stream");
846 t->parts->next->encoding = ENC7BIT;
847 t->parts->next->filename = outfile;
848 t->parts->next->use_disp = 1;
849 t->parts->next->disposition = DISPINLINE;
850 t->parts->next->unlink = 1; /* delete after sending the message */
851 t->parts->next->d_filename = m_strdup("msg.asc"); /* non pgp/mime
858 * Implementation of `smime_build_smime_entity'.
861 /* Encrypt the mail body A to all keys given as space separated
862 fingerprints in KEYLIST and return the S/MIME encrypted body. */
863 BODY *smime_gpgme_build_smime_entity (BODY * a, char *keylist)
865 char *outfile = NULL;
867 gpgme_key_t *rset = NULL;
868 gpgme_data_t plaintext;
870 rset = create_recipient_set (keylist, GPGME_PROTOCOL_CMS);
874 plaintext = body_to_data_object (a, 0);
880 outfile = encrypt_gpgme_object (plaintext, rset, 1, 0);
881 gpgme_data_release (plaintext);
887 t->type = TYPEAPPLICATION;
888 t->subtype = m_strdup("pkcs7-mime");
889 parameter_setval(&t->parameter, "name", "smime.p7m");
890 parameter_setval(&t->parameter, "smime-type", "enveloped-data");
891 t->encoding = ENCBASE64; /* The output of OpenSSL SHOULD be binary */
893 t->disposition = DISPATTACH;
894 t->d_filename = m_strdup("smime.p7m");
895 t->filename = outfile;
896 t->unlink = 1; /*delete after sending the message */
905 * Implementation of `verify_one'.
908 /* Display the common attributes of the signature summary SUM.
909 Return 1 if there is is a severe warning.
911 static int show_sig_summary (unsigned long sum,
912 gpgme_ctx_t ctx, gpgme_key_t key, int idx,
917 if ((sum & GPGME_SIGSUM_KEY_REVOKED)) {
918 state_attach_puts (_("Warning: One of the keys has been revoked\n"), s);
922 if ((sum & GPGME_SIGSUM_KEY_EXPIRED)) {
923 time_t at = key->subkeys->expires ? key->subkeys->expires : 0;
926 state_attach_puts (_("Warning: The key used to create the "
927 "signature expired at: "), s);
929 state_attach_puts ("\n", s);
932 state_attach_puts (_("Warning: At least one certification key "
933 "has expired\n"), s);
936 if ((sum & GPGME_SIGSUM_SIG_EXPIRED)) {
937 gpgme_verify_result_t result;
938 gpgme_signature_t sig;
941 result = gpgme_op_verify_result (ctx);
943 for (sig = result->signatures, i = 0; sig && (i < idx);
944 sig = sig->next, i++);
946 state_attach_puts (_("Warning: The signature expired at: "), s);
947 print_time (sig ? sig->exp_timestamp : 0, s);
948 state_attach_puts ("\n", s);
951 if ((sum & GPGME_SIGSUM_KEY_MISSING))
952 state_attach_puts (_("Can't verify due to a missing "
953 "key or certificate\n"), s);
955 if ((sum & GPGME_SIGSUM_CRL_MISSING)) {
956 state_attach_puts (_("The CRL is not available\n"), s);
960 if ((sum & GPGME_SIGSUM_CRL_TOO_OLD)) {
961 state_attach_puts (_("Available CRL is too old\n"), s);
965 if ((sum & GPGME_SIGSUM_BAD_POLICY))
966 state_attach_puts (_("A policy requirement was not met\n"), s);
968 if ((sum & GPGME_SIGSUM_SYS_ERROR)) {
969 const char *t0 = NULL, *t1 = NULL;
970 gpgme_verify_result_t result;
971 gpgme_signature_t sig;
974 state_attach_puts (_("A system error occurred"), s);
976 /* Try to figure out some more detailed system error information. */
977 result = gpgme_op_verify_result (ctx);
978 for (sig = result->signatures, i = 0; sig && (i < idx);
979 sig = sig->next, i++);
982 t1 = sig->wrong_key_usage ? "Wrong_Key_Usage" : "";
986 state_attach_puts (": ", s);
988 state_attach_puts (t0, s);
989 if (t1 && !(t0 && !m_strcmp(t0, t1))) {
991 state_attach_puts (",", s);
992 state_attach_puts (t1, s);
995 state_attach_puts ("\n", s);
1002 static void show_fingerprint (gpgme_key_t key, STATE * state)
1007 const char *prefix = _("Fingerprint: ");
1011 s = key->subkeys ? key->subkeys->fpr : NULL;
1014 is_pgp = (key->protocol == GPGME_PROTOCOL_OpenPGP);
1016 buf = xmalloc(m_strlen(prefix) + m_strlen(s) * 4 + 2);
1017 strcpy (buf, prefix); /* __STRCPY_CHECKED__ */
1018 p = buf + m_strlen(buf);
1019 if (is_pgp && m_strlen(s) == 40) { /* PGP v4 style formatted. */
1020 for (i = 0; *s && s[1] && s[2] && s[3] && s[4]; s += 4, i++) {
1031 for (i = 0; *s && s[1] && s[2]; s += 2, i++) {
1034 *p++ = is_pgp ? ' ' : ':';
1035 if (is_pgp && i == 7)
1040 /* just in case print remaining odd digits */
1045 state_attach_puts (buf, state);
1049 /* Show the valididy of a key used for one signature. */
1050 static void show_one_sig_validity (gpgme_ctx_t ctx, int idx, STATE * s)
1052 gpgme_verify_result_t result = NULL;
1053 gpgme_signature_t sig = NULL;
1054 const char *txt = NULL;
1056 result = gpgme_op_verify_result (ctx);
1058 for (sig = result->signatures; sig && (idx > 0); sig = sig->next, idx--);
1060 switch (sig ? sig->validity : 0) {
1061 case GPGME_VALIDITY_UNKNOWN:
1062 txt = _("WARNING: We have NO indication whether "
1063 "the key belongs to the person named " "as shown above\n");
1065 case GPGME_VALIDITY_UNDEFINED:
1067 case GPGME_VALIDITY_NEVER:
1068 txt = _("WARNING: The key does NOT BELONG to "
1069 "the person named as shown above\n");
1071 case GPGME_VALIDITY_MARGINAL:
1072 txt = _("WARNING: It is NOT certain that the key "
1073 "belongs to the person named as shown above\n");
1075 case GPGME_VALIDITY_FULL:
1076 case GPGME_VALIDITY_ULTIMATE:
1081 state_attach_puts (txt, s);
1084 /* Show information about one signature. This fucntion is called with
1085 the context CTX of a sucessful verification operation and the
1086 enumerator IDX which should start at 0 and incremete for each
1089 Return values are: 0 for normal procession, 1 for a bad signature,
1090 2 for a signature with a warning or -1 for no more signature. */
1091 static int show_one_sig_status (gpgme_ctx_t ctx, int idx, STATE * s)
1094 const char *fpr, *uid;
1095 gpgme_key_t key = NULL;
1096 int i, anybad = 0, anywarn = 0;
1098 gpgme_user_id_t uids = NULL;
1099 gpgme_verify_result_t result;
1100 gpgme_signature_t sig;
1101 gpgme_error_t err = GPG_ERR_NO_ERROR;
1103 result = gpgme_op_verify_result (ctx);
1105 /* FIXME: this code should use a static variable and remember
1106 the current position in the list of signatures, IMHO.
1109 for (i = 0, sig = result->signatures; sig && (i < idx);
1110 i++, sig = sig->next);
1112 return -1; /* Signature not found. */
1114 if (signature_key) {
1115 gpgme_key_release (signature_key);
1116 signature_key = NULL;
1119 created = sig->timestamp;
1123 if (gpg_err_code (sig->status) != GPG_ERR_NO_ERROR)
1126 err = gpgme_get_key (ctx, fpr, &key, 0); /* secret key? */
1128 uid = (key->uids && key->uids->uid) ? key->uids->uid : "[?]";
1130 signature_key = key;
1133 key = NULL; /* Old gpgme versions did not set KEY to NULL on
1134 error. Do it here to avoid a double free. */
1138 if (!s || !s->fpout || !(s->flags & M_DISPLAY)); /* No state information so no way to print anything. */
1140 state_attach_puts (_("Error getting key information: "), s);
1141 state_attach_puts (gpg_strerror (err), s);
1142 state_attach_puts ("\n", s);
1145 else if ((sum & GPGME_SIGSUM_GREEN)) {
1146 state_attach_puts (_("Good signature from: "), s);
1147 state_attach_puts (uid, s);
1148 state_attach_puts ("\n", s);
1149 for (i = 1, uids = key->uids; uids; i++, uids = uids->next) {
1151 /* Skip primary UID. */
1155 state_attach_puts (_(" aka: "), s);
1156 state_attach_puts (uids->uid, s);
1157 state_attach_puts ("\n", s);
1159 state_attach_puts (_(" created: "), s);
1160 print_time (created, s);
1161 state_attach_puts ("\n", s);
1162 if (show_sig_summary (sum, ctx, key, idx, s))
1164 show_one_sig_validity (ctx, idx, s);
1166 else if ((sum & GPGME_SIGSUM_RED)) {
1167 state_attach_puts (_("*BAD* signature claimed to be from: "), s);
1168 state_attach_puts (uid, s);
1169 state_attach_puts ("\n", s);
1170 show_sig_summary (sum, ctx, key, idx, s);
1172 else if (!anybad && key && (key->protocol == GPGME_PROTOCOL_OpenPGP)) { /* We can't decide (yellow) but this is a PGP key with a good
1173 signature, so we display what a PGP user expects: The name,
1174 fingerprint and the key validity (which is neither fully or
1176 state_attach_puts (_("Good signature from: "), s);
1177 state_attach_puts (uid, s);
1178 state_attach_puts ("\n", s);
1179 state_attach_puts (_(" created: "), s);
1180 print_time (created, s);
1181 state_attach_puts ("\n", s);
1182 show_one_sig_validity (ctx, idx, s);
1183 show_fingerprint (key, s);
1184 if (show_sig_summary (sum, ctx, key, idx, s))
1187 else { /* can't decide (yellow) */
1189 state_attach_puts (_("Error checking signature"), s);
1190 state_attach_puts ("\n", s);
1191 show_sig_summary (sum, ctx, key, idx, s);
1194 if (key != signature_key)
1195 gpgme_key_release (key);
1198 return anybad ? 1 : anywarn ? 2 : 0;
1201 /* Do the actual verification step. With IS_SMIME set to true we
1202 assume S/MIME (surprise!) */
1203 static int verify_one (BODY * sigbdy, STATE * s,
1204 const char *tempfile, int is_smime)
1210 gpgme_data_t signature, message;
1212 signature = file_to_data_object (s->fpin, sigbdy->offset, sigbdy->length);
1216 /* We need to tell gpgme about the encoding because the backend can't
1217 auto-detect plain base-64 encoding which is used by S/MIME. */
1219 gpgme_data_set_encoding (signature, GPGME_DATA_ENCODING_BASE64);
1221 err = gpgme_data_new_from_file (&message, tempfile, 1);
1223 gpgme_data_release (signature);
1224 mutt_error (_("error allocating data object: %s\n"), gpgme_strerror (err));
1227 ctx = create_gpgme_context (is_smime);
1229 /* Note: We don't need a current time output because GPGME avoids
1230 such an attack by separating the meta information from the
1232 state_attach_puts (_("[-- Begin signature information --]\n"), s);
1234 err = gpgme_op_verify (ctx, signature, message, NULL);
1235 mutt_need_hard_redraw ();
1239 snprintf (buf, sizeof (buf) - 1,
1240 _("Error: verification failed: %s\n"), gpgme_strerror (err));
1241 state_attach_puts (buf, s);
1243 else { /* Verification succeeded, see what the result is. */
1247 if (signature_key) {
1248 gpgme_key_release (signature_key);
1249 signature_key = NULL;
1252 for (idx = 0; (res = show_one_sig_status (ctx, idx, s)) != -1; idx++) {
1263 gpgme_verify_result_t result;
1264 gpgme_sig_notation_t notation;
1265 gpgme_signature_t sig;
1267 result = gpgme_op_verify_result (ctx);
1269 for (sig = result->signatures; sig; sig = sig->next) {
1270 if (sig->notations) {
1271 state_attach_puts ("*** Begin Notation (signature by: ", s);
1272 state_attach_puts (sig->fpr, s);
1273 state_attach_puts (") ***\n", s);
1274 for (notation = sig->notations; notation; notation = notation->next)
1276 if (notation->name) {
1277 state_attach_puts (notation->name, s);
1278 state_attach_puts ("=", s);
1280 if (notation->value) {
1281 state_attach_puts (notation->value, s);
1282 if (!(*notation->value
1283 && (notation->value[m_strlen(notation->value) - 1] ==
1285 state_attach_puts ("\n", s);
1288 state_attach_puts ("*** End Notation ***\n", s);
1294 gpgme_release (ctx);
1296 state_attach_puts (_("[-- End signature information --]\n\n"), s);
1298 return badsig ? 1 : anywarn ? 2 : 0;
1301 int pgp_gpgme_verify_one (BODY * sigbdy, STATE * s, const char *tempfile)
1303 return verify_one (sigbdy, s, tempfile, 0);
1306 int smime_gpgme_verify_one (BODY * sigbdy, STATE * s, const char *tempfile)
1308 return verify_one (sigbdy, s, tempfile, 1);
1312 * Implementation of `decrypt_part'.
1315 /* Decrypt a PGP or SMIME message (depending on the boolean flag
1316 IS_SMIME) with body A described further by state S. Write
1317 plaintext out to file FPOUT and return a new body. For PGP returns
1318 a flag in R_IS_SIGNED to indicate whether this is a combined
1319 encrypted and signed message, for S/MIME it returns true when it is
1320 not a encrypted but a signed message. */
1321 static BODY *decrypt_part (BODY * a, STATE * s, FILE * fpout, int is_smime,
1328 gpgme_data_t ciphertext, plaintext;
1329 int maybe_signed = 0;
1336 ctx = create_gpgme_context (is_smime);
1339 /* Make a data object from the body, create context etc. */
1340 ciphertext = file_to_data_object (s->fpin, a->offset, a->length);
1343 plaintext = create_gpgme_data ();
1345 /* Do the decryption or the verification in case of the S/MIME hack. */
1346 if ((!is_smime) || maybe_signed) {
1348 err = gpgme_op_decrypt_verify (ctx, ciphertext, plaintext);
1349 else if (maybe_signed)
1350 err = gpgme_op_verify (ctx, ciphertext, NULL, plaintext);
1353 /* Check wether signatures have been verified. */
1354 gpgme_verify_result_t verify_result = gpgme_op_verify_result (ctx);
1356 if (verify_result->signatures)
1361 err = gpgme_op_decrypt (ctx, ciphertext, plaintext);
1362 gpgme_data_release (ciphertext);
1364 if (is_smime && !maybe_signed && gpg_err_code (err) == GPG_ERR_NO_DATA) {
1365 /* Check whether this might be a signed message despite what
1366 the mime header told us. Retry then. gpgsm returns the
1367 error information "unsupported Algorithm '?'" but gpgme
1368 will not store this unknown algorithm, thus we test that
1369 it has not been set. */
1370 gpgme_decrypt_result_t result;
1372 result = gpgme_op_decrypt_result (ctx);
1373 if (!result->unsupported_algorithm) {
1375 gpgme_data_release (plaintext);
1379 mutt_need_hard_redraw ();
1380 if ((s->flags & M_DISPLAY)) {
1383 snprintf (buf, sizeof (buf) - 1,
1384 _("[-- Error: decryption failed: %s --]\n\n"),
1385 gpgme_strerror (err));
1386 state_attach_puts (buf, s);
1388 gpgme_data_release (plaintext);
1389 gpgme_release (ctx);
1392 mutt_need_hard_redraw ();
1394 /* Read the output from GPGME, and make sure to change CRLF to LF,
1395 otherwise read_mime_header has a hard time parsing the message. */
1396 if (data_object_to_stream (plaintext, fpout)) {
1397 gpgme_data_release (plaintext);
1398 gpgme_release (ctx);
1401 gpgme_data_release (plaintext);
1403 a->is_signed_data = 0;
1409 a->is_signed_data = 1;
1411 *r_is_signed = -1; /* A signature exists. */
1413 if ((s->flags & M_DISPLAY))
1414 state_attach_puts (_("[-- Begin signature " "information --]\n"), s);
1415 for (idx = 0; (res = show_one_sig_status (ctx, idx, s)) != -1; idx++) {
1421 if (!anybad && idx && r_is_signed && *r_is_signed)
1422 *r_is_signed = anywarn ? 2 : 1; /* Good signature. */
1424 if ((s->flags & M_DISPLAY))
1425 state_attach_puts (_("[-- End signature " "information --]\n\n"), s);
1427 gpgme_release (ctx);
1432 tattach = mutt_read_mime_header (fpout, 0);
1435 * Need to set the length of this body part.
1437 fstat (fileno (fpout), &info);
1438 tattach->length = info.st_size - tattach->offset;
1440 tattach->warnsig = anywarn;
1442 /* See if we need to recurse on this MIME part. */
1443 mutt_parse_part (fpout, tattach);
1449 /* Decrypt a PGP/MIME message in FPIN and B and return a new body and
1450 the stream in CUR and FPOUT. Returns 0 on success. */
1451 int pgp_gpgme_decrypt_mime (FILE * fpin, FILE ** fpout, BODY * b, BODY ** cur)
1453 char tempfile[_POSIX_PATH_MAX];
1455 BODY *first_part = b;
1458 first_part->goodsig = 0;
1459 first_part->warnsig = 0;
1461 if (!mutt_is_multipart_encrypted (b))
1464 if (!b->parts || !b->parts->next)
1471 mutt_mktemp (tempfile);
1472 if (!(*fpout = safe_fopen (tempfile, "w+"))) {
1473 mutt_perror (tempfile);
1478 *cur = decrypt_part (b, &s, *fpout, 0, &is_signed);
1481 first_part->goodsig = 1;
1483 return *cur ? 0 : -1;
1487 /* Decrypt a S/MIME message in FPIN and B and return a new body and
1488 the stream in CUR and FPOUT. Returns 0 on success. */
1489 int smime_gpgme_decrypt_mime (FILE * fpin, FILE ** fpout, BODY * b,
1492 char tempfile[_POSIX_PATH_MAX];
1496 long saved_b_offset;
1497 ssize_t saved_b_length;
1500 if (!mutt_is_application_smime (b))
1506 /* Decode the body - we need to pass binary CMS to the
1507 backend. The backend allows for Base64 encoded data but it does
1508 not allow for QP which I have seen in some messages. So better
1510 saved_b_type = b->type;
1511 saved_b_offset = b->offset;
1512 saved_b_length = b->length;
1515 fseeko (s.fpin, b->offset, 0);
1516 mutt_mktemp (tempfile);
1517 if (!(tmpfp = safe_fopen (tempfile, "w+"))) {
1518 mutt_perror (tempfile);
1521 mutt_unlink (tempfile);
1524 mutt_decode_attachment (b, &s);
1526 b->length = ftello (s.fpout);
1533 mutt_mktemp (tempfile);
1534 if (!(*fpout = safe_fopen (tempfile, "w+"))) {
1535 mutt_perror (tempfile);
1538 mutt_unlink (tempfile);
1540 *cur = decrypt_part (b, &s, *fpout, 1, &is_signed);
1542 (*cur)->goodsig = is_signed > 0;
1543 b->type = saved_b_type;
1544 b->length = saved_b_length;
1545 b->offset = saved_b_offset;
1548 if (*cur && !is_signed && !(*cur)->parts
1549 && mutt_is_application_smime (*cur)) {
1550 /* Assume that this is a opaque signed s/mime message. This is
1551 an ugly way of doing it but we have anyway a problem with
1552 arbitrary encoded S/MIME messages: Only the outer part may be
1553 encrypted. The entire mime parsing should be revamped,
1554 probably by keeping the temportary files so that we don't
1555 need to decrypt them all the time. Inner parts of an
1556 encrypted part can then pint into this file and tehre won't
1557 never be a need to decrypt again. This needs a partial
1558 rewrite of the MIME engine. */
1562 saved_b_type = bb->type;
1563 saved_b_offset = bb->offset;
1564 saved_b_length = bb->length;
1567 fseeko (s.fpin, bb->offset, 0);
1568 mutt_mktemp (tempfile);
1569 if (!(tmpfp = safe_fopen (tempfile, "w+"))) {
1570 mutt_perror (tempfile);
1573 mutt_unlink (tempfile);
1576 mutt_decode_attachment (bb, &s);
1578 bb->length = ftello (s.fpout);
1586 mutt_mktemp (tempfile);
1587 if (!(*fpout = safe_fopen (tempfile, "w+"))) {
1588 mutt_perror (tempfile);
1591 mutt_unlink (tempfile);
1593 tmp_b = decrypt_part (bb, &s, *fpout, 1, &is_signed);
1595 tmp_b->goodsig = is_signed > 0;
1596 bb->type = saved_b_type;
1597 bb->length = saved_b_length;
1598 bb->offset = saved_b_offset;
1601 body_list_wipe(cur);
1604 return *cur ? 0 : -1;
1609 * Implementation of `pgp_check_traditional'.
1612 static int pgp_check_traditional_one_body (FILE * fp, BODY * b,
1615 char tempfile[_POSIX_PATH_MAX];
1616 char buf[HUGE_STRING];
1622 if (b->type != TYPETEXT)
1625 if (tagged_only && !b->tagged)
1628 mutt_mktemp (tempfile);
1629 if (mutt_decode_save_attachment (fp, b, tempfile, 0, 0) != 0) {
1634 if ((tfp = fopen (tempfile, "r")) == NULL) {
1639 while (fgets (buf, sizeof (buf), tfp)) {
1640 if (!m_strncmp("-----BEGIN PGP ", buf, 15)) {
1641 if (!m_strcmp("MESSAGE-----\n", buf + 15))
1643 else if (!m_strcmp("SIGNED MESSAGE-----\n", buf + 15))
1653 /* fix the content type */
1655 parameter_setval(&b->parameter, "format", "fixed");
1656 parameter_setval(&b->parameter, "x-action",
1657 enc ? "pgp-encrypted" : "pgp-signed");
1661 int pgp_gpgme_check_traditional (FILE * fp, BODY * b, int tagged_only)
1666 for (; b; b = b->next) {
1667 if (is_multipart (b))
1668 rv = (pgp_gpgme_check_traditional (fp, b->parts, tagged_only) || rv);
1669 else if (b->type == TYPETEXT) {
1670 if ((r = mutt_is_application_pgp (b)))
1673 rv = (pgp_check_traditional_one_body (fp, b, tagged_only) || rv);
1681 * Implementation of `application_handler'.
1685 Copy a clearsigned message, and strip the signature and PGP's
1688 XXX - charset handling: We assume that it is safe to do
1689 character set decoding first, dash decoding second here, while
1690 we do it the other way around in the main handler.
1692 (Note that we aren't worse than Outlook & Cie in this, and also
1693 note that we can successfully handle anything produced by any
1694 existing versions of mutt.) */
1696 static void copy_clearsigned (gpgme_data_t data, STATE * s, char *charset)
1698 char buf[HUGE_STRING];
1699 short complete, armor_header;
1704 fname = data_object_to_tempfile (data, &fp);
1710 fc = fgetconv_open (fp, charset, Charset, M_ICONV_HOOK_FROM);
1712 for (complete = 1, armor_header = 1;
1713 fgetconvs (buf, sizeof (buf), fc) != NULL;
1714 complete = strchr (buf, '\n') != NULL) {
1717 state_puts (buf, s);
1721 if (!m_strcmp(buf, "-----BEGIN PGP SIGNATURE-----\n"))
1731 state_puts (s->prefix, s);
1733 if (buf[0] == '-' && buf[1] == ' ')
1734 state_puts (buf + 2, s);
1736 state_puts (buf, s);
1739 fgetconv_close (&fc);
1744 /* Support for classic_application/pgp */
1745 int pgp_gpgme_application_handler (BODY * m, STATE * s)
1747 int needpass = -1, pgp_keyblock = 0;
1751 off_t last_pos, offset;
1752 char buf[HUGE_STRING];
1753 FILE *pgpout = NULL;
1755 gpgme_error_t err = 0;
1756 gpgme_data_t armored_data = NULL;
1758 short maybe_goodsig = 1;
1759 short have_any_sigs = 0;
1761 char body_charset[STRING]; /* Only used for clearsigned messages. */
1763 /* For clearsigned messages we won't be able to get a character set
1764 but we know that this may only be text thus we assume Latin-1
1766 if (!mutt_get_body_charset (body_charset, sizeof (body_charset), m))
1767 m_strcpy(body_charset, sizeof(body_charset), "iso-8859-1");
1769 fseeko (s->fpin, m->offset, 0);
1770 last_pos = m->offset;
1772 for (bytes = m->length; bytes > 0;) {
1773 if (fgets (buf, sizeof (buf), s->fpin) == NULL)
1776 offset = ftello (s->fpin);
1777 bytes -= (offset - last_pos); /* don't rely on m_strlen(buf) */
1780 if (!m_strncmp("-----BEGIN PGP ", buf, 15)) {
1782 start_pos = last_pos;
1784 if (!m_strcmp("MESSAGE-----\n", buf + 15))
1786 else if (!m_strcmp("SIGNED MESSAGE-----\n", buf + 15)) {
1790 else if (!option (OPTDONTHANDLEPGPKEYS) &&
1791 !m_strcmp("PUBLIC KEY BLOCK-----\n", buf + 15)) {
1796 /* XXX - we may wish to recode here */
1798 state_puts (s->prefix, s);
1799 state_puts (buf, s);
1803 have_any_sigs = (have_any_sigs || (clearsign && (s->flags & M_VERIFY)));
1805 /* Copy PGP material to an data container */
1806 armored_data = create_gpgme_data ();
1807 gpgme_data_write (armored_data, buf, m_strlen(buf));
1808 while (bytes > 0 && fgets (buf, sizeof (buf) - 1, s->fpin) != NULL) {
1809 offset = ftello (s->fpin);
1810 bytes -= (offset - last_pos); /* don't rely on m_strlen(buf) */
1813 gpgme_data_write (armored_data, buf, m_strlen(buf));
1815 if ((needpass && !m_strcmp("-----END PGP MESSAGE-----\n", buf))
1817 && (!m_strcmp("-----END PGP SIGNATURE-----\n", buf)
1818 || !m_strcmp("-----END PGP PUBLIC KEY BLOCK-----\n",
1823 /* Invoke PGP if needed */
1824 if (!clearsign || (s->flags & M_VERIFY)) {
1825 unsigned int sig_stat = 0;
1826 gpgme_data_t plaintext;
1829 plaintext = create_gpgme_data ();
1830 ctx = create_gpgme_context (0);
1833 err = gpgme_op_verify (ctx, armored_data, NULL, plaintext);
1835 err = gpgme_op_decrypt_verify (ctx, armored_data, plaintext);
1836 if (gpg_err_code (err) == GPG_ERR_NO_DATA) {
1837 /* Decrypt verify can't handle signed only messages. */
1838 err = (gpgme_data_seek (armored_data, 0, SEEK_SET) == -1)
1839 ? gpgme_error_from_errno (errno) : 0;
1840 /* Must release plaintext so that we supply an
1841 uninitialized object. */
1842 gpgme_data_release (plaintext);
1843 plaintext = create_gpgme_data ();
1844 err = gpgme_op_verify (ctx, armored_data, NULL, plaintext);
1851 snprintf (errbuf, sizeof (errbuf) - 1,
1852 _("Error: decryption/verification failed: %s\n"),
1853 gpgme_strerror (err));
1854 state_attach_puts (errbuf, s);
1856 else { /* Decryption/Verification succeeded */
1860 /* Check wether signatures have been verified. */
1861 gpgme_verify_result_t verify_result;
1863 verify_result = gpgme_op_verify_result (ctx);
1864 if (verify_result->signatures)
1870 if ((s->flags & M_DISPLAY) && sig_stat) {
1875 state_attach_puts (_("[-- Begin signature "
1876 "information --]\n"), s);
1879 (res = show_one_sig_status (ctx, idx, s)) != -1; idx++) {
1888 state_attach_puts (_("[-- End signature "
1889 "information --]\n\n"), s);
1892 tmpfname = data_object_to_tempfile (plaintext, &pgpout);
1895 state_attach_puts (_("Error: copy data failed\n"), s);
1899 p_delete(&tmpfname);
1902 gpgme_release (ctx);
1906 * Now, copy cleartext to the screen. NOTE - we expect that PGP
1907 * outputs utf-8 cleartext. This may not always be true, but it
1908 * seems to be a reasonable guess.
1911 if (s->flags & M_DISPLAY) {
1913 state_attach_puts (_("[-- BEGIN PGP MESSAGE --]\n\n"), s);
1914 else if (pgp_keyblock)
1915 state_attach_puts (_("[-- BEGIN PGP PUBLIC KEY BLOCK --]\n"), s);
1917 state_attach_puts (_("[-- BEGIN PGP SIGNED MESSAGE --]\n\n"), s);
1921 copy_clearsigned (armored_data, s, body_charset);
1928 fc = fgetconv_open (pgpout, "utf-8", Charset, 0);
1929 while ((c = fgetconv (fc)) != EOF) {
1931 if (c == '\n' && s->prefix)
1932 state_puts (s->prefix, s);
1934 fgetconv_close (&fc);
1937 if (s->flags & M_DISPLAY) {
1938 state_putc ('\n', s);
1940 state_attach_puts (_("[-- END PGP MESSAGE --]\n"), s);
1941 else if (pgp_keyblock)
1942 state_attach_puts (_("[-- END PGP PUBLIC KEY BLOCK --]\n"), s);
1944 state_attach_puts (_("[-- END PGP SIGNED MESSAGE --]\n"), s);
1948 safe_fclose (&pgpout);
1952 /* XXX - we may wish to recode here */
1954 state_puts (s->prefix, s);
1955 state_puts (buf, s);
1959 m->goodsig = (maybe_goodsig && have_any_sigs);
1961 if (needpass == -1) {
1962 state_attach_puts (_("[-- Error: could not find beginning"
1963 " of PGP message! --]\n\n"), s);
1970 * Implementation of `encrypted_handler'.
1973 /* MIME handler for pgp/mime encrypted messages. */
1974 int pgp_gpgme_encrypted_handler (BODY * a, STATE * s)
1976 char tempfile[_POSIX_PATH_MAX];
1979 BODY *orig_body = a;
1984 if (!a || a->type != TYPEAPPLICATION || !a->subtype
1985 || ascii_strcasecmp ("pgp-encrypted", a->subtype)
1986 || !a->next || a->next->type != TYPEAPPLICATION || !a->next->subtype
1987 || ascii_strcasecmp ("octet-stream", a->next->subtype)) {
1988 if (s->flags & M_DISPLAY)
1989 state_attach_puts (_("[-- Error: malformed PGP/MIME message! --]\n\n"),
1994 /* Move forward to the application/pgp-encrypted body. */
1997 mutt_mktemp (tempfile);
1998 if (!(fpout = safe_fopen (tempfile, "w+"))) {
1999 if (s->flags & M_DISPLAY)
2000 state_attach_puts (_("[-- Error: could not create temporary file! "
2005 tattach = decrypt_part (a, s, fpout, 0, &is_signed);
2007 tattach->goodsig = is_signed > 0;
2009 if (s->flags & M_DISPLAY)
2010 state_attach_puts (is_signed ?
2012 ("[-- The following data is PGP/MIME signed and encrypted --]\n\n") :
2013 _("[-- The following data is PGP/MIME encrypted --]\n\n"), s);
2016 FILE *savefp = s->fpin;
2019 rc = mutt_body_handler (tattach, s);
2024 * if a multipart/signed is the _only_ sub-part of a
2025 * multipart/encrypted, cache signature verification
2028 if (mutt_is_multipart_signed (tattach) && !tattach->next)
2029 orig_body->goodsig |= tattach->goodsig;
2031 if (s->flags & M_DISPLAY) {
2032 state_puts ("\n", s);
2033 state_attach_puts (is_signed ?
2035 ("[-- End of PGP/MIME signed and encrypted data --]\n")
2036 : _("[-- End of PGP/MIME encrypted data --]\n"), s);
2039 body_list_wipe(&tattach);
2043 mutt_unlink (tempfile);
2047 /* Support for application/smime */
2048 int smime_gpgme_application_handler (BODY * a, STATE * s)
2050 char tempfile[_POSIX_PATH_MAX];
2057 mutt_mktemp (tempfile);
2058 if (!(fpout = safe_fopen (tempfile, "w+"))) {
2059 if (s->flags & M_DISPLAY)
2060 state_attach_puts (_("[-- Error: could not create temporary file! "
2065 tattach = decrypt_part (a, s, fpout, 1, &is_signed);
2067 tattach->goodsig = is_signed > 0;
2069 if (s->flags & M_DISPLAY)
2070 state_attach_puts (is_signed ?
2071 _("[-- The following data is S/MIME signed --]\n\n") :
2072 _("[-- The following data is S/MIME encrypted --]\n\n"), s);
2075 FILE *savefp = s->fpin;
2078 rc = mutt_body_handler (tattach, s);
2083 * if a multipart/signed is the _only_ sub-part of a
2084 * multipart/encrypted, cache signature verification
2087 if (mutt_is_multipart_signed (tattach) && !tattach->next) {
2088 if (!(a->goodsig = tattach->goodsig))
2089 a->warnsig = tattach->warnsig;
2091 else if (tattach->goodsig) {
2093 a->warnsig = tattach->warnsig;
2096 if (s->flags & M_DISPLAY) {
2097 state_puts ("\n", s);
2098 state_attach_puts (is_signed ?
2099 _("[-- End of S/MIME signed data --]\n") :
2100 _("[-- End of S/MIME encrypted data --]\n"), s);
2103 body_list_wipe(&tattach);
2107 mutt_unlink (tempfile);
2113 * Format an entry on the CRYPT key selection menu.
2116 * %k key id %K key id of the principal key
2118 * %a algorithm %A algorithm of the princ. key
2119 * %l length %L length of the princ. key
2120 * %f flags %F flags of the princ. key
2121 * %c capabilities %C capabilities of the princ. key
2122 * %t trust/validity of the key-uid association
2124 * %[...] date of key using strftime(3)
2128 crypt_entry_fmt (char *dest, ssize_t destlen, char op,
2129 const char *src, const char *prefix,
2130 const char *ifstring, const char *elsestring,
2131 unsigned long data, format_flag flags)
2134 crypt_entry_t *entry;
2137 int optional = (flags & M_FORMAT_OPTIONAL);
2138 const char *s = NULL;
2141 entry = (crypt_entry_t *) data;
2144 /* if (isupper ((unsigned char) op)) */
2147 kflags = (key->flags /*| (pkey->flags & KEYFLAG_RESTRICTIONS)
2150 switch (ascii_tolower (op)) {
2154 char buf2[SHORT_STRING], *p;
2170 while (len > 0 && *cp != ']') {
2179 break; /* not enough space */
2189 if (do_locales && Locale)
2190 setlocale (LC_TIME, Locale);
2195 if (key->kobj->subkeys && (key->kobj->subkeys->timestamp > 0))
2196 tt = key->kobj->subkeys->timestamp;
2198 tm = localtime (&tt);
2200 strftime (buf2, sizeof (buf2), dest, tm);
2203 setlocale (LC_TIME, "C");
2205 snprintf (fmt, sizeof (fmt), "%%%ss", prefix);
2206 snprintf (dest, destlen, fmt, buf2);
2213 snprintf (fmt, sizeof (fmt), "%%%sd", prefix);
2214 snprintf (dest, destlen, fmt, entry->num);
2219 /* fixme: we need a way to distinguish between main and subkeys.
2220 Store the idx in entry? */
2221 snprintf (fmt, sizeof (fmt), "%%%ss", prefix);
2222 snprintf (dest, destlen, fmt, crypt_keyid (key));
2227 snprintf (fmt, sizeof (fmt), "%%%ss", prefix);
2228 snprintf (dest, destlen, fmt, key->uid);
2233 snprintf (fmt, sizeof (fmt), "%%%s.3s", prefix);
2234 if (key->kobj->subkeys)
2235 s = gpgme_pubkey_algo_name (key->kobj->subkeys->pubkey_algo);
2238 snprintf (dest, destlen, fmt, s);
2243 snprintf (fmt, sizeof (fmt), "%%%slu", prefix);
2244 if (key->kobj->subkeys)
2245 val = key->kobj->subkeys->length;
2248 snprintf (dest, destlen, fmt, val);
2253 snprintf (fmt, sizeof (fmt), "%%%sc", prefix);
2254 snprintf (dest, destlen, fmt, crypt_flags (kflags));
2256 else if (!(kflags & (KEYFLAG_RESTRICTIONS)))
2261 snprintf (fmt, sizeof (fmt), "%%%ss", prefix);
2262 snprintf (dest, destlen, fmt, crypt_key_abilities (kflags));
2264 else if (!(kflags & (KEYFLAG_ABILITIES)))
2268 if ((kflags & KEYFLAG_ISX509))
2271 gpgme_user_id_t uid = NULL;
2274 for (i = 0, uid = key->kobj->uids; uid && (i < key->idx);
2275 i++, uid = uid->next);
2277 switch (uid->validity) {
2278 case GPGME_VALIDITY_UNDEFINED:
2281 case GPGME_VALIDITY_NEVER:
2284 case GPGME_VALIDITY_MARGINAL:
2287 case GPGME_VALIDITY_FULL:
2290 case GPGME_VALIDITY_ULTIMATE:
2293 case GPGME_VALIDITY_UNKNOWN:
2299 snprintf (fmt, sizeof (fmt), "%%%sc", prefix);
2300 snprintf (dest, destlen, fmt, s ? *s : 'B');
2303 snprintf (fmt, sizeof (fmt), "%%%ss", prefix);
2304 snprintf (dest, destlen, fmt,
2305 gpgme_get_protocol_name (key->kobj->protocol));
2313 mutt_FormatString (dest, destlen, ifstring, mutt_attach_fmt, data, 0);
2314 else if (flags & M_FORMAT_OPTIONAL)
2315 mutt_FormatString (dest, destlen, elsestring, 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 mutt_FormatString (s, l, NONULL (PgpEntryFormat), crypt_entry_fmt,
2329 (unsigned long) &entry, M_FORMAT_ARROWCURSOR);
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; hexdigitp (s); s++)
2519 return NULL; /* empty or odd number of digits */
2522 array->value = (char *) p;
2523 for (s1 = string; n; s1 += 2, n--)
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 (hexdigitp (s) && hexdigitp (s + 1)) {
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 == ';')
2552 array->value = (char *) p;
2553 for (s = string; n; s++, n--) {
2556 if (hexdigitp (s)) {
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[SHORT_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 mutt_mktemp (tempfile);
2930 if (!(fp = safe_fopen (tempfile, "w"))) {
2931 mutt_perror (_("Can't create temporary file"));
2935 mutt_message _("Collecting data...");
2937 print_key_info (key->kobj, fp);
2939 err = gpgme_new (&listctx);
2941 fprintf (fp, "Internal error: can't create gpgme context: %s\n",
2942 gpgme_strerror (err));
2945 if ((key->flags & KEYFLAG_ISX509))
2946 gpgme_set_protocol (listctx, GPGME_PROTOCOL_CMS);
2950 while ((s = k->chain_id) && k->subkeys && m_strcmp(s, k->subkeys->fpr)) {
2952 err = gpgme_op_keylist_start (listctx, s, 0);
2953 gpgme_key_release (k);
2956 err = gpgme_op_keylist_next (listctx, &k);
2958 fprintf (fp, _("Error finding issuer key: %s\n"), gpgme_strerror (err));
2961 gpgme_op_keylist_end (listctx);
2963 print_key_info (k, fp);
2966 fputs (_("Error: certification chain to long - stopping here\n"), fp);
2972 gpgme_key_release (k);
2973 gpgme_release (listctx);
2975 mutt_clear_error ();
2976 snprintf (cmd, sizeof (cmd), _("Key ID: 0x%s"), crypt_keyid (key));
2977 mutt_do_pager (cmd, tempfile, 0, NULL);
2981 * Implementation of `findkeys'.
2985 /* Convert string_list_t into a pattern string suitable to be passed to GPGME.
2986 We need to convert spaces in an item into a '+' and '%' into
2988 static char *list_to_pattern (string_list_t * list)
2996 for (l = list; l; l = l->next) {
2997 for (s = l->data; *s; s++) {
3002 n++; /* delimiter or end of string */
3004 n++; /* make sure to allocate at least one byte */
3005 pattern = p = p_new(char, n);
3006 for (l = list; l; l = l->next) {
3011 for (s = l->data; *s; s++) {
3017 else if (*s == '+') {
3033 /* Return a list of keys which are candidates for the selection.
3034 Select by looking at the HINTS list. */
3035 static crypt_key_t *get_candidates (string_list_t * hints, unsigned int app,
3038 crypt_key_t *db, *k, **kend;
3044 gpgme_user_id_t uid = NULL;
3046 pattern = list_to_pattern (hints);
3050 err = gpgme_new (&ctx);
3052 mutt_error (_("gpgme_new failed: %s"), gpgme_strerror (err));
3060 if ((app & APPLICATION_PGP)) {
3061 /* Its all a mess. That old GPGME expects different things
3062 depending on the protocol. For gpg we don' t need percent
3063 escaped pappert but simple strings passed in an array to the
3064 keylist_ext_start function. */
3069 for (l = hints, n = 0; l; l = l->next) {
3070 if (l->data && *l->data)
3076 patarr = p_new(char *, n + 1);
3077 for (l = hints, n = 0; l; l = l->next) {
3078 if (l->data && *l->data)
3079 patarr[n++] = m_strdup(l->data);
3082 err = gpgme_op_keylist_ext_start (ctx, (const char **) patarr, secret, 0);
3083 for (n = 0; patarr[n]; n++)
3084 p_delete(&patarr[n]);
3087 mutt_error (_("gpgme_op_keylist_start failed: %s"), gpgme_strerror (err));
3088 gpgme_release (ctx);
3093 while (!(err = gpgme_op_keylist_next (ctx, &key))) {
3094 unsigned int flags = 0;
3096 if (key_check_cap (key, KEY_CAP_CAN_ENCRYPT))
3097 flags |= KEYFLAG_CANENCRYPT;
3098 if (key_check_cap (key, KEY_CAP_CAN_SIGN))
3099 flags |= KEYFLAG_CANSIGN;
3101 #if 0 /* DISABLED code */
3103 /* Bug in gpg. Capabilities are not listed for secret
3104 keys. Try to deduce them from the algorithm. */
3106 switch (key->subkeys[0].pubkey_algo) {
3108 flags |= KEYFLAG_CANENCRYPT;
3109 flags |= KEYFLAG_CANSIGN;
3111 case GPGME_PK_ELG_E:
3112 flags |= KEYFLAG_CANENCRYPT;
3115 flags |= KEYFLAG_CANSIGN;
3119 #endif /* DISABLED code */
3121 for (idx = 0, uid = key->uids; uid; idx++, uid = uid->next) {
3122 k = p_new(crypt_key_t, 1);
3131 if (gpg_err_code (err) != GPG_ERR_EOF)
3132 mutt_error (_("gpgme_op_keylist_next failed: %s"), gpgme_strerror (err));
3133 gpgme_op_keylist_end (ctx);
3138 if ((app & APPLICATION_SMIME)) {
3139 /* and now look for x509 certificates */
3140 gpgme_set_protocol (ctx, GPGME_PROTOCOL_CMS);
3141 err = gpgme_op_keylist_start (ctx, pattern, 0);
3143 mutt_error (_("gpgme_op_keylist_start failed: %s"), gpgme_strerror (err));
3144 gpgme_release (ctx);
3149 while (!(err = gpgme_op_keylist_next (ctx, &key))) {
3150 unsigned int flags = KEYFLAG_ISX509;
3152 if (key_check_cap (key, KEY_CAP_CAN_ENCRYPT))
3153 flags |= KEYFLAG_CANENCRYPT;
3154 if (key_check_cap (key, KEY_CAP_CAN_SIGN))
3155 flags |= KEYFLAG_CANSIGN;
3157 for (idx = 0, uid = key->uids; uid; idx++, uid = uid->next) {
3158 k = p_new(crypt_key_t, 1);
3167 if (gpg_err_code (err) != GPG_ERR_EOF)
3168 mutt_error (_("gpgme_op_keylist_next failed: %s"), gpgme_strerror (err));
3169 gpgme_op_keylist_end (ctx);
3172 gpgme_release (ctx);
3177 /* Add the string STR to the list HINTS. This list is later used to
3179 static string_list_t *crypt_add_string_to_hints (string_list_t * hints, const char *str)
3184 if ((scratch = m_strdup(str)) == NULL)
3187 for (t = strtok (scratch, " ,.:\"()<>\n"); t;
3188 t = strtok (NULL, " ,.:\"()<>\n")) {
3189 if (m_strlen(t) > 3)
3190 hints = mutt_add_list(hints, t);
3197 /* Display a menu to select a key from the array KEYS. FORCED_VALID
3198 will be set to true on return if the user did override the the
3200 static crypt_key_t *crypt_select_key (crypt_key_t * keys,
3201 address_t * p, const char *s,
3202 unsigned int app, int *forced_valid)
3205 crypt_key_t **key_table;
3208 char helpstr[SHORT_STRING], buf[LONG_STRING];
3210 int (*f) (const void *, const void *);
3211 int menu_to_use = 0;
3216 /* build the key table */
3219 for (k = keys; k; k = k->next) {
3220 if (!option (OPTPGPSHOWUNUSABLE) && (k->flags & KEYFLAG_CANTUSE)) {
3227 p_realloc(&key_table, keymax);
3233 if (!i && unusable) {
3234 mutt_error _("All matching keys are marked expired/revoked.");
3240 switch (PgpSortKeys & SORT_MASK) {
3242 f = crypt_compare_date;
3245 f = crypt_compare_keyid;
3248 f = crypt_compare_address;
3252 f = crypt_compare_trust;
3255 qsort (key_table, i, sizeof (crypt_key_t *), f);
3257 if (app & APPLICATION_PGP)
3258 menu_to_use = MENU_KEY_SELECT_PGP;
3259 else if (app & APPLICATION_SMIME)
3260 menu_to_use = MENU_KEY_SELECT_SMIME;
3263 mutt_make_help (buf, sizeof (buf), _("Exit "), menu_to_use, OP_EXIT);
3264 strcat (helpstr, buf); /* __STRCAT_CHECKED__ */
3265 mutt_make_help (buf, sizeof (buf), _("Select "), menu_to_use,
3266 OP_GENERIC_SELECT_ENTRY);
3267 strcat (helpstr, buf); /* __STRCAT_CHECKED__ */
3268 mutt_make_help (buf, sizeof (buf), _("Check key "),
3269 menu_to_use, OP_VERIFY_KEY);
3270 strcat (helpstr, buf); /* __STRCAT_CHECKED__ */
3271 mutt_make_help (buf, sizeof (buf), _("Help"), menu_to_use, OP_HELP);
3272 strcat (helpstr, buf); /* __STRCAT_CHECKED__ */
3274 menu = mutt_new_menu ();
3276 menu->make_entry = crypt_entry;
3277 menu->menu = menu_to_use;
3278 menu->help = helpstr;
3279 menu->data = key_table;
3284 if ((app & APPLICATION_PGP) && (app & APPLICATION_SMIME))
3285 ts = _("PGP and S/MIME keys matching");
3286 else if ((app & APPLICATION_PGP))
3287 ts = _("PGP keys matching");
3288 else if ((app & APPLICATION_SMIME))
3289 ts = _("S/MIME keys matching");
3291 ts = _("keys matching");
3294 snprintf (buf, sizeof (buf), _("%s <%s>."), ts, p->mailbox);
3296 snprintf (buf, sizeof (buf), _("%s \"%s\"."), ts, s);
3300 mutt_clear_error ();
3304 switch (mutt_menuLoop (menu)) {
3306 verify_key (key_table[menu->current]);
3307 menu->redraw = REDRAW_FULL;
3311 mutt_message ("%s", key_table[menu->current]->uid);
3314 case OP_GENERIC_SELECT_ENTRY:
3315 /* FIXME make error reporting more verbose - this should be
3316 easy because gpgme provides more information */
3317 if (option (OPTPGPCHECKTRUST)) {
3318 if (!crypt_key_is_valid (key_table[menu->current])) {
3319 mutt_error _("This key can't be used: "
3320 "expired/disabled/revoked.");
3325 if (option (OPTPGPCHECKTRUST) &&
3326 (!crypt_id_is_valid (key_table[menu->current])
3327 || !crypt_id_is_strong (key_table[menu->current]))) {
3329 char buff[LONG_STRING];
3331 if (key_table[menu->current]->flags & KEYFLAG_CANTUSE)
3332 s = N_("ID is expired/disabled/revoked.");
3334 gpgme_validity_t val = GPGME_VALIDITY_UNKNOWN;
3335 gpgme_user_id_t uid = NULL;
3340 uid = key_table[menu->current]->kobj->uids;
3341 for (j = 0; (j < key_table[menu->current]->idx) && uid;
3342 j++, uid = uid->next);
3344 val = uid->validity;
3347 case GPGME_VALIDITY_UNKNOWN:
3348 case GPGME_VALIDITY_UNDEFINED:
3349 warn_s = N_("ID has undefined validity.");
3351 case GPGME_VALIDITY_NEVER:
3352 warn_s = N_("ID is not valid.");
3354 case GPGME_VALIDITY_MARGINAL:
3355 warn_s = N_("ID is only marginally valid.");
3357 case GPGME_VALIDITY_FULL:
3358 case GPGME_VALIDITY_ULTIMATE:
3362 snprintf (buff, sizeof (buff),
3363 _("%s Do you really want to use the key?"), _(warn_s));
3365 if (mutt_yesorno (buff, 0) != 1) {
3366 mutt_clear_error ();
3373 k = crypt_copy_key (key_table[menu->current]);
3384 mutt_menuDestroy (&menu);
3385 p_delete(&key_table);
3387 set_option (OPTNEEDREDRAW);
3392 static crypt_key_t *crypt_getkeybyaddr (address_t * a, short abilities,
3393 unsigned int app, int *forced_valid)
3396 string_list_t *hints = NULL;
3401 int this_key_has_strong;
3402 int this_key_has_weak;
3403 int this_key_has_invalid;
3406 crypt_key_t *keys, *k;
3407 crypt_key_t *the_valid_key = NULL;
3408 crypt_key_t *matches = NULL;
3409 crypt_key_t **matches_endp = &matches;
3413 if (a && a->mailbox)
3414 hints = crypt_add_string_to_hints (hints, a->mailbox);
3415 if (a && a->personal)
3416 hints = crypt_add_string_to_hints (hints, a->personal);
3418 mutt_message (_("Looking for keys matching \"%s\"..."), a->mailbox);
3419 keys = get_candidates (hints, app, (abilities & KEYFLAG_CANSIGN));
3421 string_list_wipe(&hints);
3426 for (k = keys; k; k = k->next) {
3427 if (abilities && !(k->flags & abilities)) {
3431 this_key_has_weak = 0; /* weak but valid match */
3432 this_key_has_invalid = 0; /* invalid match */
3433 this_key_has_strong = 0; /* strong and valid match */
3434 match = 0; /* any match */
3436 r = rfc822_parse_adrlist (NULL, k->uid);
3437 for (p = r; p; p = p->next) {
3438 int validity = crypt_id_matches_addr (a, p, k);
3440 if (validity & CRYPT_KV_MATCH) /* something matches */
3443 /* is this key a strong candidate? */
3444 if ((validity & CRYPT_KV_VALID)
3445 && (validity & CRYPT_KV_STRONGID)
3446 && (validity & CRYPT_KV_ADDR)) {
3447 if (the_valid_key && the_valid_key != k)
3450 this_key_has_strong = 1;
3452 else if ((validity & CRYPT_KV_MATCH)
3453 && !(validity & CRYPT_KV_VALID))
3454 this_key_has_invalid = 1;
3455 else if ((validity & CRYPT_KV_MATCH)
3456 && (!(validity & CRYPT_KV_STRONGID)
3457 || !(validity & CRYPT_KV_ADDR)))
3458 this_key_has_weak = 1;
3460 address_list_wipe(&r);
3465 if (!this_key_has_strong && this_key_has_invalid)
3467 if (!this_key_has_strong && this_key_has_weak)
3470 *matches_endp = tmp = crypt_copy_key (k);
3471 matches_endp = &tmp->next;
3472 the_valid_key = tmp;
3476 crypt_free_key (&keys);
3479 if (the_valid_key && !multi && !weak
3480 && !(invalid && option (OPTPGPSHOWUNUSABLE))) {
3482 * There was precisely one strong match on a valid ID, there
3483 * were no valid keys with weak matches, and we aren't
3484 * interested in seeing invalid keys.
3486 * Proceed without asking the user.
3488 k = crypt_copy_key (the_valid_key);
3492 * Else: Ask the user.
3494 k = crypt_select_key (matches, a, NULL, app, forced_valid);
3496 crypt_free_key (&matches);
3505 static crypt_key_t *crypt_getkeybystr (char *p, short abilities,
3506 unsigned int app, int *forced_valid)
3508 string_list_t *hints = NULL;
3510 crypt_key_t *matches = NULL;
3511 crypt_key_t **matches_endp = &matches;
3515 mutt_message (_("Looking for keys matching \"%s\"..."), p);
3519 hints = crypt_add_string_to_hints (hints, p);
3520 keys = get_candidates (hints, app, (abilities & KEYFLAG_CANSIGN));
3521 string_list_wipe(&hints);
3526 for (k = keys; k; k = k->next) {
3527 if (abilities && !(k->flags & abilities))
3532 if (!*p || !m_strcasecmp(p, crypt_keyid (k))
3533 || (!m_strncasecmp(p, "0x", 2)
3534 && !m_strcasecmp(p + 2, crypt_keyid (k)))
3535 || (option (OPTPGPLONGIDS)
3536 && !m_strncasecmp(p, "0x", 2)
3537 && !m_strcasecmp(p + 2, crypt_keyid (k) + 8))
3538 || m_stristr(k->uid, p)) {
3541 *matches_endp = tmp = crypt_copy_key (k);
3542 matches_endp = &tmp->next;
3546 crypt_free_key (&keys);
3549 k = crypt_select_key (matches, NULL, p, app, forced_valid);
3550 crypt_free_key (&matches);
3557 /* Display TAG as a prompt to ask for a key. If WHATFOR is not null
3558 use it as default and store it under that label as the next
3559 default. ABILITIES describe the required key abilities (sign,
3560 encrypt) and APP the type of the requested key; ether S/MIME or
3561 PGP. Return a copy of the key or NULL if not found. */
3562 static crypt_key_t *crypt_ask_for_key (char *tag,
3565 unsigned int app, int *forced_valid)
3568 char resp[SHORT_STRING];
3569 struct crypt_cache *l = NULL;
3573 forced_valid = &dummy;
3575 mutt_clear_error ();
3581 for (l = id_defaults; l; l = l->next)
3582 if (!m_strcasecmp(whatfor, l->what)) {
3583 m_strcpy(resp, sizeof(resp), NONULL(l->dflt));
3591 if (mutt_get_field (tag, resp, sizeof (resp), M_CLEAR) != 0)
3596 m_strreplace(&l->dflt, resp);
3598 l = p_new(struct crypt_cache, 1);
3599 l->next = id_defaults;
3601 l->what = m_strdup(whatfor);
3602 l->dflt = m_strdup(resp);
3606 if ((key = crypt_getkeybystr (resp, abilities, app, forced_valid)))
3614 /* This routine attempts to find the keyids of the recipients of a
3615 message. It returns NULL if any of the keys can not be found. */
3616 static char *find_keys (address_t * to, address_t * cc, address_t * bcc,
3619 char *keyID, *keylist = NULL, *t;
3620 ssize_t keylist_size = 0;
3621 ssize_t keylist_used = 0;
3622 address_t *tmp = NULL, *addr = NULL;
3623 address_t **last = &tmp;
3626 crypt_key_t *k_info, *key;
3627 const char *fqdn = mutt_fqdn (1);
3630 *r_application = APPLICATION_PGP | APPLICATION_SMIME;
3633 for (i = 0; i < 3; i++) {
3648 *last = address_list_dup (p);
3650 last = &((*last)->next);
3654 rfc822_qualify (tmp, fqdn);
3656 address_list_uniq(tmp);
3658 for (p = tmp; p; p = p->next) {
3659 char buf[LONG_STRING];
3660 int forced_valid = 0;
3665 if ((keyID = mutt_crypt_hook (p)) != NULL) {
3668 snprintf (buf, sizeof (buf), _("Use keyID = \"%s\" for %s?"),
3670 if ((r = mutt_yesorno (buf, M_YES)) == M_YES) {
3671 /* check for e-mail address */
3672 if ((t = strchr (keyID, '@')) &&
3673 (addr = rfc822_parse_adrlist (NULL, keyID))) {
3675 rfc822_qualify (addr, fqdn);
3680 k_info = crypt_getkeybystr (keyID, KEYFLAG_CANENCRYPT,
3681 *r_application, &forced_valid);
3683 k_info = crypt_getkeybystr (keyID, KEYFLAG_CANENCRYPT,
3684 app, &forced_valid);
3690 address_list_wipe(&tmp);
3691 address_list_wipe(&addr);
3697 && (k_info = crypt_getkeybyaddr (q, KEYFLAG_CANENCRYPT,
3698 app, &forced_valid)) == NULL) {
3699 snprintf (buf, sizeof (buf), _("Enter keyID for %s: "), q->mailbox);
3701 if ((key = crypt_ask_for_key (buf, q->mailbox, KEYFLAG_CANENCRYPT,
3707 &forced_valid)) == NULL) {
3709 address_list_wipe(&tmp);
3710 address_list_wipe(&addr);
3718 const char *s = crypt_fpr (key);
3721 if (key->flags & KEYFLAG_ISX509)
3722 *r_application &= ~APPLICATION_PGP;
3723 if (!(key->flags & KEYFLAG_ISX509))
3724 *r_application &= ~APPLICATION_SMIME;
3727 keylist_size += m_strlen(s) + 4 + 1;
3728 p_realloc(&keylist, keylist_size);
3729 sprintf (keylist + keylist_used, "%s0x%s%s", /* __SPRINTF_CHECKED__ */
3730 keylist_used ? " " : "", s, forced_valid ? "!" : "");
3732 keylist_used = m_strlen(keylist);
3734 crypt_free_key (&key);
3735 address_list_wipe(&addr);
3737 address_list_wipe(&tmp);
3741 char *pgp_gpgme_findkeys (address_t * to, address_t * cc, address_t * bcc)
3743 return find_keys (to, cc, bcc, APPLICATION_PGP);
3746 char *smime_gpgme_findkeys (address_t * to, address_t * cc, address_t * bcc)
3748 return find_keys (to, cc, bcc, APPLICATION_SMIME);
3752 * Implementation of `init'.
3755 /* Initialization. */
3756 static void init_gpgme (void)
3758 /* Make sure that gpg-agent is running. */
3759 if (!getenv ("GPG_AGENT_INFO")) {
3760 mutt_error ("\nUsing GPGME backend, although no gpg-agent is running");
3761 if (mutt_any_key_to_continue (NULL) == -1)
3766 void pgp_gpgme_init (void)
3771 void smime_gpgme_init (void)
3775 static int gpgme_send_menu (HEADER * msg, int *redraw, int is_smime)
3778 char input_signas[SHORT_STRING];
3781 if (msg->security & APPLICATION_PGP)
3783 else if (msg->security & APPLICATION_SMIME)
3788 mutt_multi_choice (_
3789 ("S/MIME (e)ncrypt, (s)ign, sign (a)s, (b)oth, (p)gp or (c)lear?"),
3793 mutt_multi_choice (_
3794 ("PGP (e)ncrypt, (s)ign, sign (a)s, (b)oth, s/(m)ime or (c)lear?"),
3798 case 1: /* (e)ncrypt */
3799 msg->security |= (is_smime ? SMIMEENCRYPT : PGPENCRYPT);
3800 msg->security &= ~(is_smime ? SMIMESIGN : PGPSIGN);
3803 case 2: /* (s)ign */
3804 msg->security |= (is_smime ? SMIMESIGN : PGPSIGN);
3805 msg->security &= ~(is_smime ? SMIMEENCRYPT : PGPENCRYPT);
3808 case 3: /* sign (a)s */
3809 /* unset_option(OPTCRYPTCHECKTRUST); */
3810 if ((p = crypt_ask_for_key (_("Sign as: "), NULL, KEYFLAG_CANSIGN,
3811 is_smime ? APPLICATION_SMIME :
3812 APPLICATION_PGP, NULL))) {
3813 snprintf (input_signas, sizeof (input_signas), "0x%s", crypt_keyid (p));
3814 m_strreplace(is_smime ? &SmimeDefaultKey : &PgpSignAs,
3816 crypt_free_key (&p);
3818 msg->security |= (is_smime ? SMIMESIGN : PGPSIGN);
3822 msg->security &= (is_smime ? ~SMIMESIGN : ~PGPSIGN);
3825 *redraw = REDRAW_FULL;
3828 case 4: /* (b)oth */
3830 (is_smime ? (SMIMEENCRYPT | SMIMESIGN) : (PGPENCRYPT | PGPSIGN));
3833 case 5: /* (p)gp or s/(m)ime */
3834 is_smime = !is_smime;
3837 case 6: /* (c)lear */
3842 if (choice == 6 || choice == 7);
3843 else if (is_smime) {
3844 msg->security &= ~APPLICATION_PGP;
3845 msg->security |= APPLICATION_SMIME;
3848 msg->security &= ~APPLICATION_SMIME;
3849 msg->security |= APPLICATION_PGP;
3852 return (msg->security);
3855 int pgp_gpgme_send_menu (HEADER * msg, int *redraw)
3857 return gpgme_send_menu (msg, redraw, 0);
3860 int smime_gpgme_send_menu (HEADER * msg, int *redraw)
3862 return gpgme_send_menu (msg, redraw, 1);
3865 static int verify_sender (HEADER * h, gpgme_protocol_t protocol __attribute__((unused)))
3867 address_t *sender = NULL;
3868 unsigned int ret = 1;
3871 h->env->from = mutt_expand_aliases (h->env->from);
3872 sender = h->env->from;
3874 else if (h->env->sender) {
3875 h->env->sender = mutt_expand_aliases (h->env->sender);
3876 sender = h->env->sender;
3880 if (signature_key) {
3881 gpgme_key_t key = signature_key;
3882 gpgme_user_id_t uid = NULL;
3883 int sender_length = 0;
3886 sender_length = m_strlen(sender->mailbox);
3887 for (uid = key->uids; uid && ret; uid = uid->next) {
3888 uid_length = m_strlen(uid->email);
3889 if (1 && (uid->email[0] == '<')
3890 && (uid->email[uid_length - 1] == '>')
3891 && (uid_length == sender_length + 2)
3892 && (!strncmp (uid->email + 1, sender->mailbox, sender_length)))
3897 mutt_any_key_to_continue ("Failed to verify sender");
3900 mutt_any_key_to_continue ("Failed to figure out sender");
3902 if (signature_key) {
3903 gpgme_key_release (signature_key);
3904 signature_key = NULL;
3910 int smime_gpgme_verify_sender (HEADER * h)
3912 return verify_sender (h, GPGME_PROTOCOL_CMS);