Commit 90bea32a authored by Thomas Roessler's avatar Thomas Roessler

GPG support, first take.

parent 6f8d5623
......@@ -52,7 +52,7 @@ DISTCLEANFILES=$(VERYCLEANFILES) tags keymap_defs.h *.rej *.orig *~ Makefile.bak
# kill these files when making new export distributions
NONEXPORT=pgp.c pgp.h pgpinvoke.c pgpkey.c pgppubring.c sha.h sha1dgst.c \
sha_locl.h OPS.PGP doc/pgp-Notes.txt doc/language.txt \
gnupgparse.c sha_locl.h OPS.PGP doc/pgp-Notes.txt doc/language.txt \
doc/language50.txt
all: mutt
......
......@@ -66,12 +66,18 @@
/* Where is PGP 5 located on your system? */
#undef _PGPV3PATH
/* Where is GNU Privacy Guard located on your system? */
#undef _PGPGPGPATH
/* Do we have PGP 2.*? */
#undef HAVE_PGP2
/* Do we have PGP 5.0 or up? */
#undef HAVE_PGP5
/* Do we have GPG? */
#undef HAVE_GPG
/* Where to find ispell on your system? */
#undef ISPELL
......
......@@ -120,6 +120,9 @@ static int pgp_send_menu (int bits)
char *micalg = NULL;
char input_signas[SHORT_STRING];
char input_micalg[SHORT_STRING];
KEYINFO *secring;
struct pgp_vinfo *pgp = pgp_get_vinfo(PGP_SIGN);
mvaddstr (LINES-1, 0, "(e)ncrypt, (s)ign, sign (a)s, (b)oth, select (m)ic algorithm, or (f)orget it? ");
clrtoeol ();
......@@ -131,17 +134,36 @@ static int pgp_send_menu (int bits)
if (c == 'a')
{
unset_option(OPTPGPCHECKTRUST);
if ((p = pgp_ask_for_key (pgp_secring(PGP_SIGN),
NULL, "Sign as: ", NULL, KEYFLAG_CANSIGN, &micalg)))
if(pgp)
{
snprintf (input_signas, sizeof (input_signas), "0x%s", p);
safe_free((void **) &PgpSignAs);
PgpSignAs = safe_strdup(input_signas);
safe_free((void **) &PgpSignMicalg);
PgpSignMicalg = micalg; /* micalg is malloc()ed by pgp_ask_for_key */
pgp_void_passphrase (); /* probably need a different passphrase */
safe_free ((void **) &p);
bits |= PGPSIGN;
if(!(secring = pgp->read_secring(pgp)))
{
mutt_error("Can't open your secret key ring!");
bits &= ~PGPSIGN;
}
else
{
if ((p = pgp_ask_for_key (pgp, secring, "Sign as: ",
NULL, KEYFLAG_CANSIGN, &micalg)))
{
snprintf (input_signas, sizeof (input_signas), "0x%s", p);
safe_free((void **) &PgpSignAs);
PgpSignAs = safe_strdup(input_signas);
safe_free((void **) &PgpSignMicalg);
PgpSignMicalg = micalg; /* micalg is malloc()ed by pgp_ask_for_key */
pgp_void_passphrase (); /* probably need a different passphrase */
safe_free ((void **) &p);
bits |= PGPSIGN;
}
pgp_close_keydb(&secring);
}
}
else
{
bits &= ~PGPSIGN;
mutt_error("An unkown PGP version was defined for signing.");
}
}
else if (c == 'm')
......@@ -160,7 +182,8 @@ static int pgp_send_menu (int bits)
{
mutt_error("Unknown MIC algorithm, valid ones are: pgp-md5, pgp-sha1, pgp-rmd160");
}
else {
else
{
safe_free((void **) &PgpSignMicalg);
PgpSignMicalg = safe_strdup(input_micalg);
}
......@@ -190,10 +213,6 @@ static int pgp_send_menu (int bits)
static void draw_envelope (HEADER *msg, char *fcc)
{
char buf[STRING];
......
......@@ -75,12 +75,18 @@
/* Where is PGP 5 located on your system? */
#undef _PGPV3PATH
/* Where is GNU Privacy Guard located on your system? */
#undef _PGPGPGPATH
/* Do we have PGP 2.*? */
#undef HAVE_PGP2
/* Do we have PGP 5.0 or up? */
#undef HAVE_PGP5
/* Do we have GPG? */
#undef HAVE_GPG
/* Where to find ispell on your system? */
#undef ISPELL
......
This diff is collapsed.
......@@ -23,6 +23,14 @@ OPS='$(srcdir)/OPS'
if test -f $srcdir/pgp.c; then
SUBVERSION=i
PGPPATH=no
AC_PATH_PROG(GPG, gpg, no)
if test $GPG != no ; then
AC_DEFINE_UNQUOTED(_PGPGPGPATH, "$GPG")
PGPPATH="$GPG"
AC_DEFINE(HAVE_GPG)
fi
AC_PATH_PROG(PGPK, pgpk, no)
if test $PGPK != no ; then
PGPK=`echo $PGPK | sed 's,.$,,'`
......@@ -43,7 +51,7 @@ if test -f $srcdir/pgp.c; then
fi
if test $PGP != no || test $PGPK != no ; then
LIBOBJS="$LIBOBJS pgp.o pgpinvoke.o pgpkey.o pgppubring.o sha1dgst.o"
LIBOBJS="$LIBOBJS pgp.o pgpinvoke.o pgpkey.o pgppubring.o sha1dgst.o gnupgparse.o"
OPS="$OPS \$(srcdir)/OPS.PGP"
fi
fi
......
/*
* Copyright (C) 1998 Werner Koch <werner.koch@guug.de>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <time.h>
#include "mutt.h"
#include "pgp.h"
static const char *
pkalgbytype(unsigned char type)
{
switch(type)
{
case 1:
case 2:
case 3: return "RSA";
case 16: /* encrypt only */
case 20: return "ElG";
case 17: return "DSA";
default: return "unk";
}
}
static short canencrypt(unsigned char type)
{
switch(type)
{
case 1:
case 2:
case 16:
case 20:
return 1;
default:
return 0;
}
}
static short cansign(unsigned char type)
{
switch(type)
{
case 1:
case 3:
case 16: /* hmmm: this one can only sign if used in a v3 packet */
case 17:
case 20:
return 1;
default:
return 0;
}
}
/* return values:
*
* 1 = sign only
* 2 = encrypt only
* 3 = both
*/
static short get_abilities(unsigned char type)
{
return (canencrypt(type) << 1) | cansign(type);
}
/****************
* Read the GNUPG keys. For now we read the complete keyring by
* calling gnupg in a special mode.
*
* The output format of gpgm is colon delimited with these fields:
* - record type ("pub","uid","sig","rev" etc.)
* - trust info
* - key length
* - pubkey algo
* - 16 hex digits with the long keyid.
* - timestamp (1998-02-28)
* - Local id
* - ownertrust
* - name
* - signature class
*/
static KEYINFO *
parse_pub_line( char *buf )
{
KEYINFO *k=NULL;
PGPUID *uid = NULL;
int field = 0;
char *pend, *p;
if( !*buf )
return NULL;
for( p = buf; p; p = pend ) {
if( (pend = strchr(p, ':')) )
*pend++ = 0;
field++;
if( field > 1 && !*p )
continue;
switch( field ) {
case 1: /* record type */
if( strcmp(p,"pub") )
return NULL;
k = safe_malloc( sizeof(KEYINFO) );
k->keyid = NULL;
k->address = NULL;
k->flags = 0;
k->next = NULL;
k->keylen = 0;
break;
case 2: /* trust info */
/* k_>flags |= KEYFLAG_EXPIRED */
break;
case 3: /* key length */
k->keylen = atoi(p); /* fixme: add validation checks */
break;
case 4: /* pubkey algo */
k->algorithm = pkalgbytype(atoi(p));
k->flags |= get_abilities(atoi(p));
break;
case 5: /* 16 hex digits with the long keyid. */
/* We really should do a check here */
k->keyid = safe_strdup(p);
break;
case 6: /* timestamp (1998-02-28) */
break;
case 7: /* Local id */
break;
case 8: /* ownertrust */
break;
case 9: /* name */
k->address = mutt_new_list();
k->address->data = safe_malloc( sizeof(PGPUID) );
uid = (PGPUID *)k->address->data;
uid->addr = safe_strdup(p);
uid->trust = 0;
break;
case 10: /* signature class */
break;
default:
break;
}
}
return k;
}
static pid_t gpg_invoke_list_keys(struct pgp_vinfo *pgp,
FILE **pgpin, FILE **pgpout, FILE **pgperr,
int pgpinfd, int pgpoutfd, int pgperrfd,
const char *uids)
{
char cmd[HUGE_STRING];
char tmpcmd[HUGE_STRING];
char *cp;
char *keylist;
/* we use gpgm here */
snprintf(cmd, sizeof(cmd),
"%sm --no-verbose --batch --with-colons --list-keys ",
NONULL(*pgp->binary));
keylist = safe_strdup(uids);
for(cp = strtok(keylist, " "); cp ; cp = strtok(NULL, " "))
{
snprintf(tmpcmd, sizeof(tmpcmd), "%s %s",
cmd, cp);
strcpy(cmd, tmpcmd);
}
safe_free((void **) &keylist);
return mutt_create_filter_fd(cmd, pgpin, pgpout, pgperr,
pgpinfd, pgpoutfd, pgperrfd);
}
KEYINFO *gpg_read_pubring(struct pgp_vinfo *pgp)
{
FILE *fp;
pid_t thepid;
char buf[LONG_STRING];
KEYINFO *db = NULL, **kend, *k = NULL;
thepid = gpg_invoke_list_keys(pgp, NULL, &fp, NULL, -1, -1, -1, NULL);
if( thepid == -1 )
return NULL;
kend = &db;
k = NULL;
while( fgets( buf, sizeof(buf)-1, fp ) ) {
if( k )
kend = &k->next;
*kend = k = parse_pub_line(buf);
}
fclose( fp );
mutt_wait_filter( thepid );
return db;
}
KEYINFO *gpg_read_secring(struct pgp_vinfo *pgp)
{
mutt_error("gpg_read_secring() has not yet been implemented.");
sleep(1);
return NULL;
}
......@@ -1400,6 +1400,10 @@ void mutt_init (int skip_sys_rc, LIST *commands)
PgpV3Secring = safe_strdup (buffer);
}
#endif
#ifdef _PGPGPGPATH
PgpGpg = safe_strdup (_PGPGPGPATH);
#endif
#endif /* _PGPPATH */
......
......@@ -177,21 +177,27 @@ struct option_t MuttVars[] = {
{ "pgp_v5_pubring", DT_PATH, R_NONE, UL &PgpV3Pubring, 0 },
{ "pgp_v5_secring", DT_PATH, R_NONE, UL &PgpV3Secring, 0 },
{ "pgp_gpg", DT_PATH, R_NONE, UL &PgpGpg, 0 },
# ifdef HAVE_PGP2
{ "pgp_default_version", DT_STR, R_NONE, UL &PgpDefaultVersion, UL "pgp2" },
# else
# ifdef HAVE_PGP5
{ "pgp_default_version", DT_STR, R_NONE, UL &PgpDefaultVersion, UL "pgp5" },
# else
# ifdef HAVE_GPG
{ "pgp_default_version", DT_STR, R_NONE, UL &PgpDefaultVersion, UL "gpg" },
# endif
# endif
# endif
{ "pgp_receive_version", DT_STR, R_NONE, UL &PgpReceiveVersion, UL "default" },
{ "pgp_send_version", DT_STR, R_NONE, UL &PgpSendVersion, UL "default" },
{ "pgp_key_version", DT_STR, R_NONE, UL &PgpKeyVersion, UL "default" },
#endif /* _PGPPATH */
{ "pipe_split", DT_BOOL, R_NONE, OPTPIPESPLIT, 0 },
{ "pipe_decode", DT_BOOL, R_NONE, OPTPIPEDECODE, 0 },
{ "pipe_sep", DT_STR, R_NONE, UL &PipeSep, UL "\n" },
......
......@@ -202,6 +202,9 @@ static void show_version (void)
#ifdef HAVE_PGP2
"+HAVE_PGP2 "
#endif
#ifdef HAVE_GPG
"+HAVE_GPG "
#endif
#endif
......@@ -241,6 +244,9 @@ static void show_version (void)
# ifdef _PGPV3PATH
printf ("_PGPV3PATH=\"%s\"\n", _PGPV3PATH);
# endif
# ifdef _PGPGPPATH
pritnf ("_PGPGPGPATH=\"%s\"\n", _PGPGPGPATH);
# endif
#endif
......
This diff is collapsed.
......@@ -53,7 +53,8 @@ typedef struct pgp_uid
enum pgp_version
{
PGP_V2,
PGP_V3,
PGP_V3,
PGP_GPG,
PGP_UNKNOWN
};
......@@ -64,20 +65,59 @@ enum pgp_ops
PGP_DECRYPT, /* PGP/MIME, encrypted */
PGP_SIGN, /* sign data */
PGP_ENCRYPT, /* encrypt data */
PGP_EXTRACT, /* extract keys from messages */
PGP_IMPORT, /* extract keys from messages */
PGP_VERIFY_KEY, /* verify key when selecting */
PGP_EXTRACT_KEY, /* extract keys from key ring */
PGP_EXPORT, /* extract keys from key ring */
PGP_LAST_OP
};
struct pgp_vinfo
{
/* data */
enum pgp_version v;
char *name;
char **binary;
char **pubring;
char **secring;
char **language;
/* functions */
KEYINFO * (*read_pubring)(struct pgp_vinfo *);
KEYINFO * (*read_secring)(struct pgp_vinfo *);
pid_t (*invoke_decode)(struct pgp_vinfo *, FILE **, FILE **, FILE **,
int, int, int,
const char *, int);
pid_t (*invoke_verify)(struct pgp_vinfo *, FILE **, FILE **, FILE **,
int, int, int,
const char *, const char *);
pid_t (*invoke_decrypt)(struct pgp_vinfo *, FILE **, FILE **, FILE **,
int, int, int,
const char *);
pid_t (*invoke_sign)(struct pgp_vinfo *, FILE **, FILE **, FILE **,
int, int, int,
const char *);
pid_t (*invoke_encrypt)(struct pgp_vinfo *, FILE **, FILE **, FILE **,
int, int, int,
const char *, const char *, int);
void (*invoke_import)(struct pgp_vinfo *, const char *);
pid_t (*invoke_export)(struct pgp_vinfo *, FILE **, FILE **, FILE **,
int, int, int,
const char *);
pid_t (*invoke_verify_key)(struct pgp_vinfo *, FILE **, FILE **, FILE **,
int, int, int,
const char *);
};
......@@ -91,6 +131,15 @@ WHERE char *PgpV3Language;
WHERE char *PgpV3Pubring;
WHERE char *PgpV3Secring;
WHERE char *PgpGpg;
#if 0
WHERE char *PgpGpgLanguage;
WHERE char *PgpGpgPubring;
WHERE char *PgpGpgSecring;
#else
WHERE char *PgpGpgDummy;
#endif
WHERE char *PgpSendVersion;
WHERE char *PgpReceiveVersion;
WHERE char *PgpKeyVersion;
......@@ -108,14 +157,11 @@ BODY *pgp_make_key_attachment (char *);
const char *pgp_pkalg_to_mic(const char *);
char *pgp_ask_for_key (const char *, KEYINFO *, char *, char *, short, char **);
char *pgp_ask_for_key (struct pgp_vinfo *, KEYINFO *, char *, char *, short, char **);
char *pgp_binary(enum pgp_ops);
char *pgp_getring (enum pgp_ops, int);
char *pgp_keyid(KEYINFO *);
char *_pgp_keyid(KEYINFO *);
enum pgp_version pgp_version(enum pgp_ops);
struct pgp_vinfo *pgp_get_vinfo(enum pgp_ops);
int mutt_check_pgp (HEADER *h);
......@@ -125,13 +171,16 @@ int pgp_protect (HEADER *);
int pgp_query (BODY *);
int pgp_valid_passphrase (void);
KEYINFO *ki_getkeybyaddr (ADDRESS *, KEYINFO *, short);
KEYINFO *ki_getkeybystr (char *, KEYINFO *, short);
KEYINFO *pgp_read_keyring(const char *);
KEYINFO *ki_getkeybyaddr (struct pgp_vinfo *pgp, ADDRESS *, KEYINFO *, short);
KEYINFO *ki_getkeybystr (struct pgp_vinfo *pgp, char *, KEYINFO *, short);
KEYINFO *pgp_read_pubring(struct pgp_vinfo *pgp);
KEYINFO *pgp_read_secring(struct pgp_vinfo *pgp);
KEYINFO *gpg_read_pubring(struct pgp_vinfo *pgp);
KEYINFO *gpg_read_secring(struct pgp_vinfo *pgp);
void application_pgp_handler (BODY *, STATE *);
void mutt_forget_passphrase (void);
void pgp_closedb (KEYINFO *);
void pgp_close_keydb (KEYINFO **);
void pgp_encrypted_handler (BODY *, STATE *);
void pgp_extract_keys_from_attachment_list (FILE *fp, int tag, BODY *top);
void pgp_extract_keys_from_messages(HEADER *hdr);
......@@ -141,15 +190,173 @@ void pgp_void_passphrase (void);
#define pgp_secring(a) pgp_getring(a, 0)
#define pgp_pubring(a) pgp_getring(a, 1)
/* PGP V2 prototypes */
pid_t pgp_v2_invoke_decode(struct pgp_vinfo *,
FILE **, FILE **, FILE **,
int, int, int,
const char *, int);
pid_t pgp_v2_invoke_verify(struct pgp_vinfo *,
FILE **, FILE **, FILE **,
int, int, int,
const char *, const char *);
pid_t pgp_v2_invoke_decrypt(struct pgp_vinfo *,
FILE **, FILE **, FILE **,
int, int, int,
const char *);
pid_t pgp_v2_invoke_sign(struct pgp_vinfo *,
FILE **, FILE **, FILE **,
int, int, int,
const char *);
pid_t pgp_v2_invoke_encrypt(struct pgp_vinfo *,
FILE **, FILE **, FILE **,
int, int, int,
const char *, const char *, int);
void pgp_v2_invoke_import(struct pgp_vinfo *, const char *);
pid_t pgp_v2_invoke_export(struct pgp_vinfo*,
FILE **, FILE **, FILE **,
int, int, int,
const char *);
pid_t pgp_v2_invoke_verify_key(struct pgp_vinfo *,
FILE **, FILE **, FILE **,
int, int, int,
const char *);
/* PGP V3 prototypes */
pid_t pgp_v3_invoke_decode(struct pgp_vinfo *,
FILE **, FILE **, FILE **,
int, int, int,
const char *, int);
pid_t pgp_v3_invoke_verify(struct pgp_vinfo *,
FILE **, FILE **, FILE **,
int, int, int,
const char *, const char *);
pid_t pgp_v3_invoke_decrypt(struct pgp_vinfo *,
FILE **, FILE **, FILE **,
int, int, int,
const char *);
pid_t pgp_v3_invoke_sign(struct pgp_vinfo *,
FILE **, FILE **, FILE **,
int, int, int,
const char *);
pid_t pgp_v3_invoke_encrypt(struct pgp_vinfo *,
FILE **, FILE **, FILE **,
int, int, int,
const char *, const char *, int);
void pgp_v3_invoke_import(struct pgp_vinfo *, const char *);
pid_t pgp_v3_invoke_export(struct pgp_vinfo*,
FILE **, FILE **, FILE **,
int, int, int,
const char *);
pid_t pgp_v3_invoke_verify_key(struct pgp_vinfo *,
FILE **, FILE **, FILE **,
int, int, int,
const char *);
/* GNU Privacy Guard Prototypes */
pid_t pgp_gpg_invoke_decode(struct pgp_vinfo *,
FILE **, FILE **, FILE **,
int, int, int,
const char *, int);
pid_t pgp_gpg_invoke_verify(struct pgp_vinfo *,
FILE **, FILE **, FILE **,
int, int, int,
const char *, const char *);
pid_t pgp_gpg_invoke_decrypt(struct pgp_vinfo *,
FILE **, FILE **, FILE **,
int, int, int,
const char *);
pid_t pgp_gpg_invoke_sign(struct pgp_vinfo *,
FILE **, FILE **, FILE **,
int, int, int,
const char *);
pid_t pgp_gpg_invoke_encrypt(struct pgp_vinfo *,
FILE **, FILE **, FILE **,
int, int, int,
const char *, const char *, int);
void pgp_gpg_invoke_import(struct pgp_vinfo *, const char *);
pid_t pgp_gpg_invoke_export(struct pgp_vinfo*,
FILE **, FILE **, FILE **,
int, int, int,
const char *);
pid_t pgp_gpg_invoke_verify_key(struct pgp_vinfo *,
FILE **, FILE **, FILE **,
int, int, int,
const char *);
#if 0
/* use these as templates for your own prototypes */
pid_t pgp_VERSION_invoke_decode(struct pgp_vinfo *,
FILE **, FILE **, FILE **,
int, int, int,
const char *, int);
pid_t pgp_VERSION_invoke_verify(struct pgp_vinfo *,
FILE **, FILE **, FILE **,
int, int, int,
const char *, const char *);
pid_t pgp_VERSION_invoke_decrypt(struct pgp_vinfo *,
FILE **, FILE **, FILE **,
int, int, int,
const char *);
pid_t pgp_VERSION_invoke_sign(struct pgp_vinfo *,
FILE **, FILE **, FILE **,
int, int, int,
const char *);
pid_t pgp_VERSION_invoke_encrypt(struct pgp_vinfo *,
FILE **, FILE **, FILE **,
int, int, int,
const char *, const char *, int);
void pgp_VERSION_invoke_import(struct pgp_vinfo *, const char *);
pid_t pgp_VERSION_invoke_export(struct pgp_vinfo*,
FILE **, FILE **, FILE **,
int, int, int,
const char *);
pid_t pgp_invoke_decode(FILE **, FILE **, FILE **, int, int, int, const char *, int);
pid_t pgp_invoke_verify(FILE **, FILE **, FILE **, int, int, int, const char *, const char *);
pid_t pgp_invoke_decrypt(FILE **, FILE **, FILE **, int, int, int, const char *);
pid_t pgp_invoke_sign(FILE **, FILE **, FILE **, int, int, int, const char *);
pid_t pgp_invoke_encrypt(FILE **, FILE **, FILE **, int, int, int, const char *, const char *, int);
void pgp_invoke_extract(const char *);
pid_t pgp_invoke_verify_key(FILE **, FILE **, FILE **, int, int, int, const char *);
pid_t pgp_invoke_extract_key(FILE **, FILE **, FILE **, int, int, int, const char *);
pid_t pgp_VERSION_invoke_verify_key(struct pgp_vinfo *,
FILE **, FILE **, FILE **,
int, int, int,
const char *);
#endif
#endif /* _PGPPATH */
This diff is collapsed.
/*
* Copyright (C) 1996,1997 Michael R. Elkins <me@cs.hmc.edu>
* Copyright (c) 1998 Thomas Roessler <roessler@guug.de>
*
* This program is free software; you can redistribute it and/or modify
*