Commit fe573eb9 authored by Thomas Roessler's avatar Thomas Roessler

Auto-detect the micalg used with PGP/MIME signatures.

parent 3afe7d22
......@@ -65,16 +65,17 @@ INCLUDES=-I$(top_srcdir) -I. $(IMAP_INCLUDES) \
-Iintl -I$(includedir)
non_us_sources = pgp.c pgpinvoke.c pgpkey.c pgplib.c sha1.c \
gnupgparse.c sha1.h \
pgpmicalg.c gnupgparse.c sha1.h \
doc/language.txt doc/language50.txt OPS.PGP doc/PGP-Notes.txt \
OPS.MIX remailer.c remailer.h pgpewrap \
contrib/pgp2.rc contrib/pgp5.rc contrib/gpg.rc \
mutt_ssl.c mutt_ssl.h README.SSL mutt_ssl_nss.c
mutt_ssl.c mutt_ssl.h README.SSL mutt_ssl_nss.c \
pgppacket.c pgppacket.h
EXTRA_mutt_SOURCES = account.c md5c.c mutt_sasl.c mutt_socket.c mutt_ssl.c \
pop.c pop_auth.c pop_lib.c pgp.c pgpinvoke.c pgpkey.c pgplib.c \
sha1.c gnupgparse.c resize.c dotlock.c remailer.c browser.h mbyte.h \
remailer.h url.h mutt_ssl_nss.c
sha1.c pgpmicalg.c gnupgparse.c resize.c dotlock.c remailer.c browser.h mbyte.h \
remailer.h url.h mutt_ssl_nss.c pgppacket.c
EXTRA_DIST = COPYRIGHT GPL OPS OPS.PGP TODO configure acconfig.h account.h \
attach.h buffy.h charset.h copy.h dotlock.h functions.h gen_defs \
......@@ -86,13 +87,13 @@ EXTRA_DIST = COPYRIGHT GPL OPS OPS.PGP TODO configure acconfig.h account.h \
_regex.h OPS.MIX README.SECURITY remailer.c remailer.h browser.h \
mbyte.h lib.h extlib.c pgpewrap pgplib.h Muttrc.head Muttrc \
makedoc.c stamp-doc-rc README.SSL README.UPGRADE checktypes.c \
muttbug
muttbug pgppacket.h
mutt_dotlock_SOURCES = mutt_dotlock.c
mutt_dotlock_LDADD = @LIBOBJS@
mutt_dotlock_DEPENDENCIES = @LIBOBJS@
pgpring_SOURCES = pgppubring.c pgplib.c lib.c extlib.c sha1.c
pgpring_SOURCES = pgppubring.c pgplib.c lib.c extlib.c sha1.c pgppacket.c
pgpring_LDADD = @LIBOBJS@ $(INTLLIBS)
pgpring_DEPENDENCIES = @LIBOBJS@ $(INTLDEPS)
......
......@@ -121,21 +121,16 @@ static void redraw_pgp_lines (int pgp)
move (HDR_PGPSIGINFO, 0);
clrtoeol ();
if (pgp & PGPSIGN)
{
printw ("%s%s", _(" sign as: "), PgpSignAs ? PgpSignAs : _("<default>"));
mvprintw (HDR_PGPSIGINFO, 40, "%s%s", _("MIC algorithm: "),
NONULL(PgpSignMicalg));
}
}
static int pgp_send_menu (int bits, int *redraw)
{
pgp_key_t *p;
char input_signas[SHORT_STRING];
char input_micalg[SHORT_STRING];
switch (mutt_multi_choice (_("(e)ncrypt, (s)ign, sign (a)s, (b)oth, select (m)ic algorithm, or (f)orget it? "),
_("esabmf")))
switch (mutt_multi_choice (_("(e)ncrypt, (s)ign, sign (a)s, (b)oth, or (f)orget it? "),
_("esabf")))
{
case 1: /* (e)ncrypt */
bits |= PGPENCRYPT;
......@@ -153,7 +148,6 @@ static int pgp_send_menu (int bits, int *redraw)
{
snprintf (input_signas, sizeof (input_signas), "0x%s", pgp_keyid (p));
mutt_str_replace (&PgpSignAs, input_signas);
mutt_str_replace (&PgpSignMicalg, pgp_pkalg_to_mic (p->algorithm));
pgp_free_key (&p);
bits |= PGPSIGN;
......@@ -172,28 +166,7 @@ static int pgp_send_menu (int bits, int *redraw)
bits = PGPENCRYPT | PGPSIGN;
break;
case 5: /* select (m)ic algorithm */
if (!(bits & PGPSIGN))
mutt_error _("This doesn't make sense if you don't want to sign the message.");
else
{
/* Copy the existing MIC algorithm into place */
strfcpy(input_micalg, NONULL (PgpSignMicalg), sizeof (input_micalg));
if (mutt_get_field (_("MIC algorithm: "), input_micalg, sizeof (input_micalg), 0) == 0)
{
if (mutt_strcasecmp (input_micalg, "pgp-md5") && mutt_strcasecmp (input_micalg, "pgp-sha1")
&& mutt_strcasecmp (input_micalg, "pgp-rmd160"))
{
mutt_error _("Unknown MIC algorithm, valid ones are: pgp-md5, pgp-sha1, pgp-rmd160");
}
else
mutt_str_replace (&PgpSignMicalg, input_micalg);
}
}
break;
case 6: /* (f)orget it */
case 5: /* (f)orget it */
bits = 0;
break;
}
......
......@@ -75,7 +75,7 @@ else
AC_DEFINE(HAVE_PGP)
PGPAUX_TARGET=pgpring
AM_CONDITIONAL(NEEDS_PGPEWRAP, true)
MUTT_LIB_OBJECTS="$MUTT_LIB_OBJECTS pgp.o pgpinvoke.o pgpkey.o pgplib.o gnupgparse.o"
MUTT_LIB_OBJECTS="$MUTT_LIB_OBJECTS pgp.o pgpinvoke.o pgpkey.o pgplib.o gnupgparse.o pgpmicalg.o pgppacket.o"
OPS="$OPS \$(srcdir)/OPS.PGP"
fi
......
......@@ -252,6 +252,10 @@ static pgp_key_t *parse_pub_line (char *buf, int *is_subkey, pgp_key_t *k)
{
if (!pend || !*p)
break; /* empty field or no trailing colon */
/* ignore user IDs on subkeys */
if (!is_uid && (*is_subkey && option (OPTPGPIGNORESUB)))
break;
dprint (2, (debugfile, "user ID: %s\n", p));
......@@ -318,7 +322,7 @@ pgp_key_t *pgp_get_candidates (pgp_ring_t keyring, LIST * hints)
if (is_sub)
{
pgp_uid_t **l;
k->flags |= KEYFLAG_SUBKEY;
k->parent = mainkey;
for (l = &k->address; *l; l = &(*l)->next)
......
......@@ -1176,20 +1176,6 @@ struct option_t MuttVars[] = {
** which of your private keys to use. It is recommended that you use the
** keyid form to specify your key (e.g., ``0x00112233'').
*/
{ "pgp_sign_micalg", DT_STR, R_NONE, UL &PgpSignMicalg, UL "pgp-md5" },
/*
** .pp
** This variable contains the default message integrity check algorithm.
** Valid values are ``pgp-md5'', ``pgp-sha1'', and ``pgp-rmd160''. If you
** select a signing key using the sign as option on the compose menu,
** mutt will automagically figure out the correct value to insert here,
** but it does not know about the user's default key.
** .pp
** So if you are using an RSA key for signing, set this variable to
** ``pgp-md5'', if you use a PGP 5 DSS key for signing, say ``pgp-sha1''
** here. The value of this variable will show up in the micalg parameter
** of MIME headers when creating RFC 2015 signatures.
*/
{ "pgp_strict_enc", DT_BOOL, R_NONE, OPTPGPSTRICTENC, 1 },
/*
** .pp
......
......@@ -48,6 +48,7 @@
#include "rfc822.h"
#include "hash.h"
#include "charset.h"
#ifdef SUBVERSION
# define MUTT_VERSION (VERSION SUBVERSION)
......
......@@ -1152,7 +1152,7 @@ static BODY *pgp_sign_message (BODY *a)
mutt_generate_boundary (&t->parameter);
mutt_set_parameter ("protocol", "application/pgp-signature", &t->parameter);
mutt_set_parameter ("micalg", PgpSignMicalg, &t->parameter);
mutt_set_parameter ("micalg", pgp_micalg (sigfile), &t->parameter);
t->parts = a;
a = t;
......
......@@ -24,7 +24,6 @@
WHERE REGEXP PgpGoodSign;
WHERE char *PgpSignAs;
WHERE char *PgpSignMicalg;
WHERE short PgpTimeout;
WHERE char *PgpEntryFormat;
......@@ -49,6 +48,7 @@ WHERE char *PgpGetkeysCommand;
BODY *pgp_decrypt_part (BODY *, STATE *, FILE *);
BODY *pgp_make_key_attachment (char *);
const char *pgp_micalg (const char *fname);
char *_pgp_keyid (pgp_key_t *);
char *pgp_keyid (pgp_key_t *);
......
......@@ -52,44 +52,6 @@ const char *pgp_pkalgbytype (unsigned char type)
}
static struct
{
char *pkalg;
char *micalg;
}
pktomic[] =
{
{
"RSA", "pgp-md5"
}
,
{
"ElG", "pgp-rmd160"
}
,
{
"DSA", "pgp-sha1"
}
,
{
NULL, "x-unknown"
}
};
const char *pgp_pkalg_to_mic (const char *alg)
{
int i;
for (i = 0; pktomic[i].pkalg; i++)
{
if (!mutt_strcasecmp (pktomic[i].pkalg, alg))
break;
}
return pktomic[i].micalg;
}
/* unused */
......
......@@ -81,7 +81,6 @@ typedef enum pgp_ring pgp_ring_t;
/* prototypes */
const char *pgp_pkalg_to_mic (const char *);
const char *pgp_pkalgbytype (unsigned char);
pgp_key_t *pgp_remove_key (pgp_key_t **, pgp_key_t *);
......
/*
* Copyright (C) 2001 Thomas Roessler <roessler@does-not-exist.org>
*
* 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., 59 Temple Place - Suite 330, Boston,
* MA 02111, USA.
*/
/* This module peeks at a PGP signature and figures out the hash
* algorithm.
*/
#include "mutt.h"
#include "pgp.h"
#include "pgppacket.h"
#include "mime.h"
#include "charset.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
static struct
{
short id;
const char *name;
}
HashAlgorithms[] =
{
{ 1, "pgp-md5" },
{ 2, "pgp-sha1" },
{ 3, "pgp-ripemd160" },
{ 5, "pgp-md2" },
{ 6, "pgp-tiger192" },
{ 7, "pgp-haval-5-160" },
{ -1, NULL }
};
static const char *pgp_hash_to_micalg (short id)
{
int i;
for (i = 0; HashAlgorithms[i].id >= 0; i++)
if (HashAlgorithms[i].id == id)
return HashAlgorithms[i].name;
return "x-unknown";
}
static void pgp_dearmor (FILE *in, FILE *out)
{
char line[HUGE_STRING];
long start;
long end;
char *r;
STATE state;
memset (&state, 0, sizeof (STATE));
state.fpin = in;
state.fpout = out;
/* find the beginning of ASCII armor */
while ((r = fgets (line, sizeof (line), in)) != NULL)
{
if (!strncmp (line, "-----BEGIN", 10))
break;
}
if (r == NULL)
{
dprint (1, (debugfile, "pgp_dearmor: Can't find begin of ASCII armor.\n"));
return;
}
/* skip the armor header */
while ((r = fgets (line, sizeof (line), in)) != NULL)
{
SKIPWS (r);
if (!*r) break;
}
if (r == NULL)
{
dprint (1, (debugfile, "pgp_dearmor: Armor header doesn't end.\n"));
return;
}
/* actual data starts here */
start = ftell (in);
/* find the checksum */
while ((r = fgets (line, sizeof (line), in)) != NULL)
{
if (*line == '=' || !strncmp (line, "-----END", 8))
break;
}
if (r == NULL)
{
dprint (1, (debugfile, "pgp_dearmor: Can't find end of ASCII armor.\n"));
return;
}
if ((end = ftell (in) - strlen (line)) < start)
{
dprint (1, (debugfile, "pgp_dearmor: end < start???\n"));
return;
}
if (fseek (in, start, SEEK_SET) == -1)
{
dprint (1, (debugfile, "pgp_dearmor: Can't seekto start.\n"));
return;
}
mutt_decode_base64 (&state, end - start, 0, (iconv_t) -1);
}
static short pgp_mic_from_packet (unsigned char *p, size_t len)
{
/* is signature? */
if ((p[0] & 0x3f) != PT_SIG)
{
dprint (1, (debugfile, "pgp_mic_from_packet: tag = %d, want %d.\n",
p[0]&0x3f, PT_SIG));
return -1;
}
if (len >= 18 && p[1] == 3)
/* version 3 signature */
return (short) p[17];
else if (len >= 5 && p[1] == 4)
/* version 4 signature */
return (short) p[4];
else
{
dprint (1, (debugfile, "pgp_mic_from_packet: Bad signature packet.\n"));
return -1;
}
}
static short pgp_find_hash (const char *fname)
{
FILE *in = NULL;
FILE *out = NULL;
char tempfile[_POSIX_PATH_MAX];
unsigned char *p;
size_t l;
short rv = -1;
mutt_mktemp (tempfile);
if ((out = safe_fopen (tempfile, "w+")) == NULL)
{
mutt_perror (tempfile);
goto bye;
}
unlink (tempfile);
if ((in = fopen (fname, "r")) == NULL)
{
mutt_perror (fname);
goto bye;
}
pgp_dearmor (in, out);
rewind (out);
if ((p = pgp_read_packet (out, &l)) != NULL)
{
rv = pgp_mic_from_packet (p, l);
}
else
{
dprint (1, (debugfile, "pgp_find_hash: No packet.\n"));
}
bye:
safe_fclose (&in);
safe_fclose (&out);
pgp_release_packet ();
return rv;
}
const char *pgp_micalg (const char *fname)
{
return pgp_hash_to_micalg (pgp_find_hash (fname));
}
/*
* Copyright (C) 2001 Thomas Roessler <roessler@does-not-exist.org>
*
* 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., 59 Temple Place - Suite 330, Boston,
* MA 02111, USA.
*/
#include "config.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <time.h>
#include "sha1.h"
#include "lib.h"
#include "pgplib.h"
#include "pgppacket.h"
#define CHUNKSIZE 1024
static unsigned char *pbuf = NULL;
static size_t plen = 0;
static int read_material (size_t material, size_t * used, FILE * fp)
{
if (*used + material >= plen)
{
unsigned char *p;
size_t nplen;
nplen = *used + material + CHUNKSIZE;
if (!(p = realloc (pbuf, nplen))) /* __MEM_CHECKED__ */
{
perror ("realloc");
return -1;
}
plen = nplen;
pbuf = p;
}
if (fread (pbuf + *used, 1, material, fp) < material)
{
perror ("fread");
return -1;
}
*used += material;
return 0;
}
unsigned char *pgp_read_packet (FILE * fp, size_t * len)
{
size_t used = 0;
long startpos;
unsigned char ctb;
unsigned char b;
size_t material;
startpos = ftell (fp);
if (!plen)
{
plen = CHUNKSIZE;
pbuf = safe_malloc (plen);
}
if (fread (&ctb, 1, 1, fp) < 1)
{
if (!feof (fp))
perror ("fread");
goto bail;
}
if (!(ctb & 0x80))
{
goto bail;
}
if (ctb & 0x40) /* handle PGP 5.0 packets. */
{
int partial = 0;
pbuf[0] = ctb;
used++;
do
{
if (fread (&b, 1, 1, fp) < 1)
{
perror ("fread");
goto bail;
}
if (b < 192)
{
material = b;
partial = 0;
material -= 1;
}
else if (192 <= b && b <= 223)
{
material = (b - 192) * 256;
if (fread (&b, 1, 1, fp) < 1)
{
perror ("fread");
goto bail;
}
material += b + 192;
partial = 0;
material -= 2;
}
else if (b < 255)
{
material = 1 << (b & 0x1f);
partial = 1;
material -= 1;
}
else
/* b == 255 */
{
unsigned char buf[4];
if (fread (buf, 4, 1, fp) < 1)
{
perror ("fread");
goto bail;
}
/*assert( sizeof(material) >= 4 ); */
material = buf[0] << 24;
material |= buf[1] << 16;
material |= buf[2] << 8;
material |= buf[3];
partial = 0;
material -= 5;
}
if (read_material (material, &used, fp) == -1)
goto bail;
}
while (partial);
}
else
/* Old-Style PGP */
{
int bytes = 0;
pbuf[0] = 0x80 | ((ctb >> 2) & 0x0f);
used++;
switch (ctb & 0x03)
{
case 0:
{
if (fread (&b, 1, 1, fp) < 1)
{
perror ("fread");
goto bail;
}
material = b;
break;
}
case 1:
bytes = 2;
case 2:
{
int i;
if (!bytes)
bytes = 4;
material = 0;
for (i = 0; i < bytes; i++)
{
if (fread (&b, 1, 1, fp) < 1)
{
perror ("fread");
goto bail;
}
material = (material << 8) + b;
}
break;
}
default:
goto bail;
}
if (read_material (material, &used, fp) == -1)
goto bail;
}
if (len)
*len = used;
return pbuf;
bail:
fseek (fp, startpos, SEEK_SET);
return NULL;
}
void pgp_release_packet (void)
{
plen = 0;
free (pbuf);
pbuf = NULL;
}
/*
* Copyright (C) 2001 Thomas Roessler <roessler@does-not-exist.org>
*
* 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., 59 Temple Place - Suite 330, Boston,
* MA 02111, USA.
*/
/*
* Definitions for a rudimentary PGP packet parser which is shared
* by mutt proper and the PGP public key ring lister.
*/
#ifndef _PGPPACKET_H
# define _PGPPACKET_H
enum packet_tags
{
PT_RES0 = 0, /* reserved */
PT_ESK, /* Encrypted Session Key */
PT_SIG, /* Signature Packet */
PT_CESK, /* Conventionally Encrypted Session Key Packet */
PT_OPS, /* One-Pass Signature Packet */
PT_SECKEY, /* Secret Key Packet */
PT_PUBKEY, /* Public Key Packet */
PT_SUBSECKEY, /* Secret Subkey Packet */
PT_COMPRESSED, /* Compressed Data Packet */
PT_SKE, /* Symmetrically Encrypted Data Packet */
PT_MARKER, /* Marker Packet */
PT_LITERAL, /* Literal Data Packet */
PT_TRUST, /* Trust Packet */
PT_NAME, /* Name Packet */
PT_SUBKEY, /* Subkey Packet */
PT_RES15, /* Reserved */
PT_COMMENT /* Comment Packet */
};
unsigned char *pgp_read_packet (FILE * fp, size_t * len);
void pgp_release_packet (void);
#endif
......@@ -52,6 +52,8 @@ extern int optind;
#include "sha1.h"
#include "lib.h"
#include "pgplib.h"
#include "pgppacket.h"
#ifdef HAVE_FGETPOS
#define FGETPOS(fp,pos) fgetpos((fp),&(pos))
......@@ -61,10 +63,7 @@ extern int optind;
#define FSETPOS(fp,pos) fseek((fp),(pos),SEEK_SET)
#endif
#define CHUNKSIZE 1024
static unsigned char *pbuf = NULL;
static size_t plen = 0;
static void pgpring_find_candidates (char *ringfile, const char *hints[], int nhints);
static void pgpring_dump_keyblock (pgp_key_t *p);
......@@ -141,243 +140,6 @@ int main (int argc, char * const argv[])
/* The actual key ring parser */
enum packet_tags
{
PT_RES0 = 0, /* reserved */
PT_ESK, /* Encrypted Session Key */
PT_SIG, /* Signature Packet */
PT_CESK, /* Conventionally Encrypted Session Key Packet */
PT_OPS, /* One-Pass Signature Packet */
PT_SECKEY, /* Secret Key Packet */
PT_PUBKEY, /* Public Key Packet */
PT_SUBSECKEY, /* Secret Subkey Packet */
PT_COMPRESSED, /* Compressed Data Packet */
PT_SKE, /* Symmetrically Encrypted Data Packet */
PT_MARKER, /* Marker Packet */
PT_LITERAL, /* Literal Data Packet */