From 3323929ce7804dbd24e7ff18d7a51a7ccf7cb876 Mon Sep 17 00:00:00 2001 From: Moritz Schulte Date: Sat, 24 Feb 2007 06:12:19 +0000 Subject: [PATCH] PKA signature verification via GPGME, controlled by $crypt_use_pka. --- Makefile.am | 4 +- UPDATING | 6 ++- configure.in | 40 +++++++-------- crypt-gpgme.c | 100 +++++++++++++++++++++++++++++++++++--- crypt-gpgme.h | 3 ++ crypt-mod-pgp-classic.c | 1 + crypt-mod-pgp-gpgme.c | 6 +++ crypt-mod-smime-classic.c | 1 + crypt-mod-smime-gpgme.c | 1 + crypt-mod.h | 2 + crypt.c | 12 +++++ cryptglue.c | 13 +++++ init.h | 16 ++++-- mutt.h | 1 + mutt_crypt.h | 4 +- 15 files changed, 173 insertions(+), 37 deletions(-) diff --git a/Makefile.am b/Makefile.am index e194705ea..46ada466b 100644 --- a/Makefile.am +++ b/Makefile.am @@ -32,7 +32,7 @@ mutt_SOURCES = $(BUILT_SOURCES) \ url.c ascii.c mutt_idna.c crypt-mod.c crypt-mod.h mutt_LDADD = @MUTT_LIB_OBJECTS@ @LIBOBJS@ $(LIBIMAP) $(MUTTLIBS) \ - $(INTLLIBS) $(LIBICONV) $(LIBGPGME_LIBS) + $(INTLLIBS) $(LIBICONV) $(GPGME_LIBS) mutt_DEPENDENCIES = @MUTT_LIB_OBJECTS@ @LIBOBJS@ $(LIBIMAPDEPS) \ $(INTLDEPS) @@ -52,7 +52,7 @@ DEFS=-DPKGDATADIR=\"$(pkgdatadir)\" -DSYSCONFDIR=\"$(sysconfdir)\" \ -DBINDIR=\"$(bindir)\" -DMUTTLOCALEDIR=\"$(datadir)/locale\" \ -DHAVE_CONFIG_H=1 -AM_CPPFLAGS=-I. -I$(top_srcdir) $(IMAP_INCLUDES) $(LIBGPGME_CFLAGS) -Iintl +AM_CPPFLAGS=-I. -I$(top_srcdir) $(IMAP_INCLUDES) $(GPGME_CFLAGS) -Iintl CPPFLAGS=@CPPFLAGS@ -I$(includedir) diff --git a/UPDATING b/UPDATING index 2eff36419..c53fc44a2 100644 --- a/UPDATING +++ b/UPDATING @@ -4,10 +4,12 @@ mutt. Please read this file carefully when upgrading your installation. The keys used are: !: modified feature, -: deleted feature, +: new feature + + $crypt_use_pka (use GPGME PKA signature verification) + 1.5.13 (2006-08-14): - + thread patterns. Use ~(...) to match all threads that - contain a message that matches ... + + thread patterns. Use ~(...) to match all threads that + contain a message that matches ... 1.5.12 (2006-07-14): diff --git a/configure.in b/configure.in index 60e72da91..8fa03858c 100644 --- a/configure.in +++ b/configure.in @@ -107,31 +107,31 @@ AC_DEFINE_UNQUOTED(SENDMAIL,"$ac_cv_path_SENDMAIL", [Where to find sendmail on y OPS='$(srcdir)/OPS' +AC_MSG_CHECKING([whether to build with GPGME support]) AC_ARG_ENABLE(gpgme, AC_HELP_STRING([--enable-gpgme], [Enable GPGME support]), [ if test x$enableval = xyes; then - have_gpgme=yes + enable_gpgme=yes fi ]) -AC_ARG_WITH(gpgme-prefix, AC_HELP_STRING([--with-gpgme-prefix=PFX], [prefix where GPGME is installed (optional)]), -gpgme_config_prefix="$withval", gpgme_config_prefix="") - -if test x$have_gpgme = xyes; then - if test x$gpgme_config_prefix != x; then - GPGME_CONFIG="$gpgme_config_prefix/bin/gpgme-config" - else - AC_PATH_PROG(GPGME_CONFIG, gpgme-config, no) - fi - if test "x$GPGME_CONFIG" = "xno"; then - AC_MSG_ERROR([GPGME not found]) - else - LIBGPGME_CFLAGS=`$GPGME_CONFIG --cflags` - LIBGPGME_LIBS=`$GPGME_CONFIG --libs` - MUTT_LIB_OBJECTS="$MUTT_LIB_OBJECTS crypt-gpgme.o crypt-mod-pgp-gpgme.o crypt-mod-smime-gpgme.o" - AC_DEFINE(CRYPT_BACKEND_GPGME, 1, [Defined, if GPGME support is enabled]) - fi + +if test x"$enable_gpgme" = xyes; then + AC_MSG_RESULT(yes) + AM_PATH_GPGME(1.0.0, AC_DEFINE(CRYPT_BACKEND_GPGME, 1, + [Defined, if GPGME support is enabled]), + [gpgme_found=no]) + if test x"$gpgme_found" = xno; then + AC_MSG_ERROR([*** GPGME not found ***]) + else + AM_PATH_GPGME(1.1.1, AC_DEFINE(HAVE_GPGME_PKA_TRUST, 1, + [Define if GPGME supports PKA])) + #needed to get GPGME_LIBS and al correctly + AM_PATH_GPGME(1.0.0, AC_DEFINE(CRYPT_BACKEND_GPGME, 1, + [Define if you use GPGME to support OpenPGP])) + MUTT_LIB_OBJECTS="$MUTT_LIB_OBJECTS crypt-gpgme.o crypt-mod-pgp-gpgme.o crypt-mod-smime-gpgme.o" + fi +else + AC_MSG_RESULT([no]) fi -AC_SUBST(LIBGPGME_CFLAGS) -AC_SUBST(LIBGPGME_LIBS) AC_ARG_ENABLE(pgp, AC_HELP_STRING([--disable-pgp], [Disable PGP support]), [ if test x$enableval = xno ; then diff --git a/crypt-gpgme.c b/crypt-gpgme.c index 07d0039a9..bf1bd3821 100644 --- a/crypt-gpgme.c +++ b/crypt-gpgme.c @@ -71,6 +71,10 @@ *(p) <= 'F'? (*(p)-'A'+10):(*(p)-'a'+10)) #define xtoi_2(p) ((xtoi_1(p) * 16) + xtoi_1((p)+1)) +#define PKA_NOTATION_NAME "pka-address@gnupg.org" +#define is_pka_notation(notation) (! strcmp ((notation)->name, \ + PKA_NOTATION_NAME)) + /* Values used for comparing addresses. */ #define CRYPT_KV_VALID 1 #define CRYPT_KV_ADDR 2 @@ -115,6 +119,8 @@ typedef struct crypt_entry static struct crypt_cache *id_defaults = NULL; static gpgme_key_t signature_key = NULL; +static char *current_sender = NULL; + /* * General helper functions. @@ -661,6 +667,23 @@ static int set_signer (gpgme_ctx_t ctx, int for_smime) return 0; } +static gpgme_error_t +set_pka_sig_notation (gpgme_ctx_t ctx) +{ + gpgme_error_t err; + + err = gpgme_sig_notation_add (ctx, + PKA_NOTATION_NAME, current_sender, 0); + + if (err) + { + mutt_error (_("error setting PKA signature notation: %s\n"), + gpgme_strerror (err)); + mutt_sleep (2); + } + + return err; +} /* Encrypt the gpgme data object PLAINTEXT to the recipients in RSET and return an allocated filename to a temporary file containing the @@ -670,7 +693,7 @@ static int set_signer (gpgme_ctx_t ctx, int for_smime) static char *encrypt_gpgme_object (gpgme_data_t plaintext, gpgme_key_t *rset, int use_smime, int combined_signed) { - int err; + gpgme_error_t err; gpgme_ctx_t ctx; gpgme_data_t ciphertext; char *outfile; @@ -689,6 +712,18 @@ static char *encrypt_gpgme_object (gpgme_data_t plaintext, gpgme_key_t *rset, gpgme_release (ctx); return NULL; } + + if (option (OPTCRYPTUSEPKA)) + { + err = set_pka_sig_notation (ctx); + if (err) + { + gpgme_data_release (ciphertext); + gpgme_release (ctx); + return NULL; + } + } + err = gpgme_op_encrypt_sign (ctx, rset, GPGME_ENCRYPT_ALWAYS_TRUST, plaintext, ciphertext); } @@ -788,6 +823,18 @@ static BODY *sign_message (BODY *a, int use_smime) return NULL; } + if (option (OPTCRYPTUSEPKA)) + { + err = set_pka_sig_notation (ctx); + if (err) + { + gpgme_data_release (signature); + gpgme_data_release (message); + gpgme_release (ctx); + return NULL; + } + } + err = gpgme_op_sign (ctx, message, signature, GPGME_SIG_MODE_DETACH ); mutt_need_hard_redraw (); gpgme_data_release (message); @@ -984,7 +1031,7 @@ BODY *smime_gpgme_build_smime_entity (BODY *a, char *keylist) */ static int show_sig_summary (unsigned long sum, gpgme_ctx_t ctx, gpgme_key_t key, int idx, - STATE *s) + STATE *s, gpgme_signature_t sig) { int severe = 0; @@ -1080,6 +1127,27 @@ static int show_sig_summary (unsigned long sum, state_attach_puts ("\n", s); } +#ifdef HAVE_GPGME_PKA_TRUST + + if (option (OPTCRYPTUSEPKA)) + { + if (sig->pka_trust == 1 && sig->pka_address) + { + state_attach_puts (_("WARNING: PKA entry does not match " + "signer's address: "), s); + state_attach_puts (sig->pka_address, s); + state_attach_puts ("\n", s); + } + else if (sig->pka_trust == 2 && sig->pka_address) + { + state_attach_puts (_("PKA verified signer's address is: "), s); + state_attach_puts (sig->pka_address, s); + state_attach_puts ("\n", s); + } + } + +#endif + return severe; } @@ -1259,7 +1327,7 @@ static int show_one_sig_status (gpgme_ctx_t ctx, int idx, STATE *s) state_attach_puts (_(" created: "), s); print_time (created, s); state_attach_puts ("\n", s); - if (show_sig_summary (sum, ctx, key, idx, s)) + if (show_sig_summary (sum, ctx, key, idx, s, sig)) anywarn = 1; show_one_sig_validity (ctx, idx, s); } @@ -1268,7 +1336,7 @@ static int show_one_sig_status (gpgme_ctx_t ctx, int idx, STATE *s) state_attach_puts (_("*BAD* signature claimed to be from: "), s); state_attach_puts (uid, s); state_attach_puts ("\n", s); - show_sig_summary (sum, ctx, key, idx, s); + show_sig_summary (sum, ctx, key, idx, s, sig); } else if (!anybad && key && (key->protocol == GPGME_PROTOCOL_OpenPGP)) { /* We can't decide (yellow) but this is a PGP key with a good @@ -1283,14 +1351,14 @@ static int show_one_sig_status (gpgme_ctx_t ctx, int idx, STATE *s) state_attach_puts ("\n", s); show_one_sig_validity (ctx, idx, s); show_fingerprint (key,s); - if (show_sig_summary (sum, ctx, key, idx, s)) + if (show_sig_summary (sum, ctx, key, idx, s, sig)) anywarn = 1; } else /* can't decide (yellow) */ { state_attach_puts (_("Error checking signature"), s); state_attach_puts ("\n", s); - show_sig_summary (sum, ctx, key, idx, s); + show_sig_summary (sum, ctx, key, idx, s, sig); } if (key != signature_key) @@ -1372,6 +1440,7 @@ static int verify_one (BODY *sigbdy, STATE *s, gpgme_verify_result_t result; gpgme_sig_notation_t notation; gpgme_signature_t signature; + int non_pka_notations; result = gpgme_op_verify_result (ctx); if (result) @@ -1379,7 +1448,13 @@ static int verify_one (BODY *sigbdy, STATE *s, for (signature = result->signatures; signature; signature = signature->next) { - if (signature->notations) + non_pka_notations = 0; + for (notation = signature->notations; notation; + notation = notation->next) + if (! is_pka_notation (notation)) + non_pka_notations++; + + if (non_pka_notations) { char buf[SHORT_STRING]; snprintf (buf, sizeof (buf), @@ -1389,6 +1464,9 @@ static int verify_one (BODY *sigbdy, STATE *s, for (notation = signature->notations; notation; notation = notation->next) { + if (is_pka_notation (notation)) + continue; + if (notation->name) { state_attach_puts (notation->name, s); @@ -4266,4 +4344,12 @@ int smime_gpgme_verify_sender (HEADER *h) return verify_sender (h, GPGME_PROTOCOL_CMS); } +void gpgme_set_sender (const char *sender) +{ + mutt_error ("[setting sender] mailbox: %s\n", sender); + FREE (¤t_sender); + current_sender = safe_strdup (sender); +} + + #endif diff --git a/crypt-gpgme.h b/crypt-gpgme.h index c8aa08ed7..d0da2bb56 100644 --- a/crypt-gpgme.h +++ b/crypt-gpgme.h @@ -51,4 +51,7 @@ int pgp_gpgme_send_menu (HEADER *msg, int *redraw); int smime_gpgme_send_menu (HEADER *msg, int *redraw); int smime_gpgme_verify_sender (HEADER *h); + +void gpgme_set_sender (const char *sender); + #endif diff --git a/crypt-mod-pgp-classic.c b/crypt-mod-pgp-classic.c index b471e4c90..e414a147e 100644 --- a/crypt-mod-pgp-classic.c +++ b/crypt-mod-pgp-classic.c @@ -119,6 +119,7 @@ struct crypt_module_specs crypt_mod_pgp_classic = crypt_mod_pgp_sign_message, crypt_mod_pgp_verify_one, crypt_mod_pgp_send_menu, + NULL, crypt_mod_pgp_encrypt_message, crypt_mod_pgp_make_key_attachment, diff --git a/crypt-mod-pgp-gpgme.c b/crypt-mod-pgp-gpgme.c index 55257cb06..290adf710 100644 --- a/crypt-mod-pgp-gpgme.c +++ b/crypt-mod-pgp-gpgme.c @@ -90,6 +90,11 @@ static BODY *crypt_mod_pgp_encrypt_message (BODY *a, char *keylist, int sign) return pgp_gpgme_encrypt_message (a, keylist, sign); } +static void crypt_mod_pgp_set_sender (const char *sender) +{ + gpgme_set_sender (sender); +} + struct crypt_module_specs crypt_mod_pgp_gpgme = { APPLICATION_PGP, { @@ -104,6 +109,7 @@ struct crypt_module_specs crypt_mod_pgp_gpgme = crypt_mod_pgp_sign_message, crypt_mod_pgp_verify_one, crypt_mod_pgp_send_menu, + crypt_mod_pgp_set_sender, /* PGP specific. */ crypt_mod_pgp_encrypt_message, diff --git a/crypt-mod-smime-classic.c b/crypt-mod-smime-classic.c index a5e7d92a9..bc0bb75ef 100644 --- a/crypt-mod-smime-classic.c +++ b/crypt-mod-smime-classic.c @@ -100,6 +100,7 @@ struct crypt_module_specs crypt_mod_smime_classic = crypt_mod_smime_sign_message, crypt_mod_smime_verify_one, crypt_mod_smime_send_menu, + NULL, NULL, /* pgp_encrypt_message */ NULL, /* pgp_make_key_attachment */ diff --git a/crypt-mod-smime-gpgme.c b/crypt-mod-smime-gpgme.c index 577309634..6e85b9803 100644 --- a/crypt-mod-smime-gpgme.c +++ b/crypt-mod-smime-gpgme.c @@ -98,6 +98,7 @@ struct crypt_module_specs crypt_mod_smime_gpgme = crypt_mod_smime_sign_message, crypt_mod_smime_verify_one, crypt_mod_smime_send_menu, + NULL, NULL, /* pgp_encrypt_message */ NULL, /* pgp_make_key_attachment */ diff --git a/crypt-mod.h b/crypt-mod.h index 3bd74260b..08dfa43c4 100644 --- a/crypt-mod.h +++ b/crypt-mod.h @@ -67,6 +67,7 @@ typedef void (*crypt_func_smime_invoke_import_t) (char *infile, char *mailbox); typedef void (*crypt_func_init_t) (void); +typedef void (*crypt_func_set_sender_t) (const char *sender); /* A structure to keep all crypto module fucntions together. @@ -84,6 +85,7 @@ typedef struct crypt_module_functions crypt_func_sign_message_t sign_message; crypt_func_verify_one_t verify_one; crypt_func_send_menu_t send_menu; + crypt_func_set_sender_t set_sender; /* PGP specific functions. */ crypt_func_pgp_encrypt_message_t pgp_encrypt_message; diff --git a/crypt.c b/crypt.c index 473e099ae..67d7276bf 100644 --- a/crypt.c +++ b/crypt.c @@ -169,6 +169,18 @@ int mutt_protect (HEADER *msg, char *keylist) if ((WithCrypto & APPLICATION_PGP)) tmp_pgp_pbody = msg->content; + if (option (OPTCRYPTUSEPKA) && (msg->security & SIGN)) + { + /* Set sender (necessary for e.g. PKA). */ + + if ((WithCrypto & APPLICATION_SMIME) + && (msg->security & APPLICATION_SMIME)) + crypt_smime_set_sender (msg->env->from->mailbox); + else if ((WithCrypto & APPLICATION_PGP) + && (msg->security & APPLICATION_PGP)) + crypt_pgp_set_sender (msg->env->from->mailbox); + } + if (msg->security & SIGN) { if ((WithCrypto & APPLICATION_SMIME) diff --git a/cryptglue.c b/cryptglue.c index 8f840c57b..e6f0aab61 100644 --- a/cryptglue.c +++ b/cryptglue.c @@ -260,8 +260,15 @@ void crypt_pgp_extract_keys_from_attachment_list (FILE *fp, int tag, BODY *top) (CRYPT_MOD_CALL (PGP, pgp_extract_keys_from_attachment_list)) (fp, tag, top); } +void crypt_pgp_set_sender (const char *sender) +{ + if (CRYPT_MOD_CALL_CHECK (PGP, set_sender)) + (CRYPT_MOD_CALL (PGP, set_sender)) (sender); +} + + /* S/MIME @@ -376,3 +383,9 @@ int crypt_smime_send_menu (HEADER *msg, int *redraw) return 0; } + +void crypt_smime_set_sender (const char *sender) +{ + if (CRYPT_MOD_CALL_CHECK (SMIME, set_sender)) + (CRYPT_MOD_CALL (SMIME, set_sender)) (sender); +} diff --git a/init.h b/init.h index fd9c78c50..0bba9d226 100644 --- a/init.h +++ b/init.h @@ -406,13 +406,19 @@ struct option_t MuttVars[] = { { "crypt_use_gpgme", DT_BOOL, R_NONE, OPTCRYPTUSEGPGME, 0 }, /* ** .pp - ** This variable controls the use the GPGME enabled crypto backends. - ** If it is set and Mutt was build with gpgme support, the gpgme code for - ** S/MIME and PGP will be used instead of the classic code. Note, that - ** you need to use this option in .muttrc as it won't have any effect when + ** This variable controls the use of the GPGME-enabled crypto backends. + ** If it is set and Mutt was built with gpgme support, the gpgme code for + ** S/MIME and PGP will be used instead of the classic code. Note that + ** you need to set this option in .muttrc; it won't have any effect when ** used interactively. */ - + { "crypt_use_pka", DT_BOOL, R_NONE, OPTCRYPTUSEPKA, 0 }, + /* + ** .pp Controls whether mutt uses PKA + ** (http://www.g10code.de/docs/pka-intro.de.pdf) during signature + ** verification (only supported by the GPGME backend). + */ + { "crypt_autopgp", DT_BOOL, R_NONE, OPTCRYPTAUTOPGP, 1 }, /* ** .pp diff --git a/mutt.h b/mutt.h index 8cb74f8b2..e23771cba 100644 --- a/mutt.h +++ b/mutt.h @@ -453,6 +453,7 @@ enum OPTXMAILER, OPTCRYPTUSEGPGME, + OPTCRYPTUSEPKA, /* PGP options */ diff --git a/mutt_crypt.h b/mutt_crypt.h index b432cd6eb..db152b027 100644 --- a/mutt_crypt.h +++ b/mutt_crypt.h @@ -220,7 +220,7 @@ char *crypt_pgp_keyid (pgp_key_t k); /* fixme: needs documentation */ void crypt_pgp_extract_keys_from_attachment_list (FILE *fp, int tag,BODY *top); - +void crypt_pgp_set_sender (const char *sender); @@ -259,6 +259,8 @@ void crypt_smime_invoke_import (char *infile, char *mailbox); int crypt_smime_send_menu (HEADER *msg, int *redraw); +void crypt_smime_set_sender (const char *sender); + /* fixme: needs documentation */ int crypt_smime_verify_one (BODY *sigbdy, STATE *s, const char *tempf); -- 2.50.1