2003-06-05 09:14:21 +02:00
|
|
|
/* parse-packet.c - read packets
|
2007-04-06 05:46:03 +02:00
|
|
|
* Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006,
|
2010-03-15 12:15:45 +01:00
|
|
|
* 2007, 2009, 2010 Free Software Foundation, Inc.
|
2003-06-05 09:14:21 +02:00
|
|
|
*
|
|
|
|
* This file is part of GnuPG.
|
|
|
|
*
|
|
|
|
* GnuPG is free software; you can redistribute it and/or modify
|
|
|
|
* it under the terms of the GNU General Public License as published by
|
2007-07-04 21:49:40 +02:00
|
|
|
* the Free Software Foundation; either version 3 of the License, or
|
2003-06-05 09:14:21 +02:00
|
|
|
* (at your option) any later version.
|
|
|
|
*
|
|
|
|
* GnuPG 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
|
2011-02-04 12:57:53 +01:00
|
|
|
* along with this program; if not, see <http://www.gnu.org/licenses/>.
|
2003-06-05 09:14:21 +02:00
|
|
|
*/
|
|
|
|
|
|
|
|
#include <config.h>
|
|
|
|
#include <stdio.h>
|
|
|
|
#include <stdlib.h>
|
|
|
|
#include <string.h>
|
|
|
|
#include <assert.h>
|
|
|
|
|
2006-04-19 13:26:11 +02:00
|
|
|
#include "gpg.h"
|
2010-10-01 22:33:53 +02:00
|
|
|
#include "util.h"
|
2003-06-05 09:14:21 +02:00
|
|
|
#include "packet.h"
|
|
|
|
#include "iobuf.h"
|
|
|
|
#include "filter.h"
|
|
|
|
#include "photoid.h"
|
|
|
|
#include "options.h"
|
|
|
|
#include "main.h"
|
|
|
|
#include "i18n.h"
|
|
|
|
|
2006-04-19 13:26:11 +02:00
|
|
|
static int mpi_print_mode;
|
|
|
|
static int list_mode;
|
2010-03-15 12:15:45 +01:00
|
|
|
static estream_t listfp;
|
2003-06-05 09:14:21 +02:00
|
|
|
|
2009-10-02 11:15:10 +02:00
|
|
|
static int parse (IOBUF inp, PACKET * pkt, int onlykeypkts,
|
|
|
|
off_t * retpos, int *skip, IOBUF out, int do_skip
|
2003-06-05 09:14:21 +02:00
|
|
|
#ifdef DEBUG_PARSE_PACKET
|
2009-10-02 11:15:10 +02:00
|
|
|
, const char *dbg_w, const char *dbg_f, int dbg_l
|
2003-06-05 09:14:21 +02:00
|
|
|
#endif
|
2009-10-02 11:15:10 +02:00
|
|
|
);
|
|
|
|
static int copy_packet (IOBUF inp, IOBUF out, int pkttype,
|
|
|
|
unsigned long pktlen, int partial);
|
|
|
|
static void skip_packet (IOBUF inp, int pkttype,
|
|
|
|
unsigned long pktlen, int partial);
|
2011-03-23 10:07:59 +01:00
|
|
|
static void *read_rest (IOBUF inp, size_t pktlen);
|
2009-10-02 11:15:10 +02:00
|
|
|
static int parse_marker (IOBUF inp, int pkttype, unsigned long pktlen);
|
|
|
|
static int parse_symkeyenc (IOBUF inp, int pkttype, unsigned long pktlen,
|
|
|
|
PACKET * packet);
|
|
|
|
static int parse_pubkeyenc (IOBUF inp, int pkttype, unsigned long pktlen,
|
|
|
|
PACKET * packet);
|
|
|
|
static int parse_onepass_sig (IOBUF inp, int pkttype, unsigned long pktlen,
|
|
|
|
PKT_onepass_sig * ops);
|
|
|
|
static int parse_key (IOBUF inp, int pkttype, unsigned long pktlen,
|
|
|
|
byte * hdr, int hdrlen, PACKET * packet);
|
|
|
|
static int parse_user_id (IOBUF inp, int pkttype, unsigned long pktlen,
|
|
|
|
PACKET * packet);
|
|
|
|
static int parse_attribute (IOBUF inp, int pkttype, unsigned long pktlen,
|
|
|
|
PACKET * packet);
|
|
|
|
static int parse_comment (IOBUF inp, int pkttype, unsigned long pktlen,
|
|
|
|
PACKET * packet);
|
|
|
|
static void parse_trust (IOBUF inp, int pkttype, unsigned long pktlen,
|
|
|
|
PACKET * packet);
|
|
|
|
static int parse_plaintext (IOBUF inp, int pkttype, unsigned long pktlen,
|
|
|
|
PACKET * packet, int new_ctb, int partial);
|
|
|
|
static int parse_compressed (IOBUF inp, int pkttype, unsigned long pktlen,
|
|
|
|
PACKET * packet, int new_ctb);
|
|
|
|
static int parse_encrypted (IOBUF inp, int pkttype, unsigned long pktlen,
|
|
|
|
PACKET * packet, int new_ctb, int partial);
|
|
|
|
static int parse_mdc (IOBUF inp, int pkttype, unsigned long pktlen,
|
|
|
|
PACKET * packet, int new_ctb);
|
|
|
|
static int parse_gpg_control (IOBUF inp, int pkttype, unsigned long pktlen,
|
|
|
|
PACKET * packet, int partial);
|
2003-06-05 09:14:21 +02:00
|
|
|
|
|
|
|
static unsigned short
|
2009-10-02 11:15:10 +02:00
|
|
|
read_16 (IOBUF inp)
|
2003-06-05 09:14:21 +02:00
|
|
|
{
|
2009-10-02 11:15:10 +02:00
|
|
|
unsigned short a;
|
|
|
|
a = iobuf_get_noeof (inp) << 8;
|
|
|
|
a |= iobuf_get_noeof (inp);
|
|
|
|
return a;
|
2003-06-05 09:14:21 +02:00
|
|
|
}
|
|
|
|
|
2009-10-02 11:15:10 +02:00
|
|
|
|
2003-06-05 09:14:21 +02:00
|
|
|
static unsigned long
|
2009-10-02 11:15:10 +02:00
|
|
|
read_32 (IOBUF inp)
|
2003-06-05 09:14:21 +02:00
|
|
|
{
|
2009-10-02 11:15:10 +02:00
|
|
|
unsigned long a;
|
|
|
|
a = iobuf_get_noeof (inp) << 24;
|
|
|
|
a |= iobuf_get_noeof (inp) << 16;
|
|
|
|
a |= iobuf_get_noeof (inp) << 8;
|
|
|
|
a |= iobuf_get_noeof (inp);
|
|
|
|
return a;
|
2003-06-05 09:14:21 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2006-04-19 13:26:11 +02:00
|
|
|
/* Read an external representation of an mpi and return the MPI. The
|
|
|
|
* external format is a 16 bit unsigned value stored in network byte
|
|
|
|
* order, giving the number of bits for the following integer. The
|
|
|
|
* integer is stored with MSB first (left padded with zeroes to align
|
2009-10-02 11:15:10 +02:00
|
|
|
* on a byte boundary). */
|
2006-04-19 13:26:11 +02:00
|
|
|
static gcry_mpi_t
|
|
|
|
mpi_read (iobuf_t inp, unsigned int *ret_nread, int secure)
|
|
|
|
{
|
2009-10-02 11:15:10 +02:00
|
|
|
/*FIXME: Needs to be synced with gnupg14/mpi/mpicoder.c */
|
2006-04-19 13:26:11 +02:00
|
|
|
|
|
|
|
int c, c1, c2, i;
|
2006-11-10 12:32:00 +01:00
|
|
|
unsigned int nbits, nbytes;
|
2009-06-24 16:03:09 +02:00
|
|
|
size_t nread = 0;
|
2006-04-19 13:26:11 +02:00
|
|
|
gcry_mpi_t a = NULL;
|
|
|
|
byte *buf = NULL;
|
|
|
|
byte *p;
|
2009-10-02 11:15:10 +02:00
|
|
|
|
|
|
|
if ((c = c1 = iobuf_get (inp)) == -1)
|
2006-04-19 13:26:11 +02:00
|
|
|
goto leave;
|
|
|
|
nbits = c << 8;
|
2009-10-02 11:15:10 +02:00
|
|
|
if ((c = c2 = iobuf_get (inp)) == -1)
|
2006-04-19 13:26:11 +02:00
|
|
|
goto leave;
|
|
|
|
nbits |= c;
|
2009-10-02 11:15:10 +02:00
|
|
|
if (nbits > MAX_EXTERN_MPI_BITS)
|
2006-04-19 13:26:11 +02:00
|
|
|
{
|
2009-10-02 11:15:10 +02:00
|
|
|
log_error ("mpi too large (%u bits)\n", nbits);
|
2006-04-19 13:26:11 +02:00
|
|
|
goto leave;
|
|
|
|
}
|
|
|
|
nread = 2;
|
2009-10-02 11:15:10 +02:00
|
|
|
nbytes = (nbits + 7) / 8;
|
2006-11-10 12:32:00 +01:00
|
|
|
buf = secure ? gcry_xmalloc_secure (nbytes + 2) : gcry_xmalloc (nbytes + 2);
|
2006-04-19 13:26:11 +02:00
|
|
|
p = buf;
|
|
|
|
p[0] = c1;
|
|
|
|
p[1] = c2;
|
2009-10-02 11:15:10 +02:00
|
|
|
for (i = 0; i < nbytes; i++)
|
2006-04-19 13:26:11 +02:00
|
|
|
{
|
2009-10-02 11:15:10 +02:00
|
|
|
p[i + 2] = iobuf_get (inp) & 0xff;
|
2006-04-19 13:26:11 +02:00
|
|
|
nread++;
|
|
|
|
}
|
2009-05-26 11:29:02 +02:00
|
|
|
|
2013-11-15 08:59:45 +01:00
|
|
|
if (gcry_mpi_scan (&a, GCRYMPI_FMT_PGP, buf, nread, &nread))
|
|
|
|
a = NULL;
|
2009-05-26 11:29:02 +02:00
|
|
|
|
2006-04-19 13:26:11 +02:00
|
|
|
leave:
|
2009-10-02 11:15:10 +02:00
|
|
|
gcry_free (buf);
|
|
|
|
if (nread > *ret_nread)
|
2013-11-15 08:59:45 +01:00
|
|
|
log_bug ("mpi larger than packet (%zu/%u)", nread, *ret_nread);
|
2006-04-19 13:26:11 +02:00
|
|
|
else
|
|
|
|
*ret_nread = nread;
|
|
|
|
return a;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2003-06-05 09:14:21 +02:00
|
|
|
int
|
2009-10-02 11:15:10 +02:00
|
|
|
set_packet_list_mode (int mode)
|
2003-06-05 09:14:21 +02:00
|
|
|
{
|
2009-10-02 11:15:10 +02:00
|
|
|
int old = list_mode;
|
|
|
|
list_mode = mode;
|
|
|
|
/* FIXME(gcrypt) mpi_print_mode = DBG_MPI; */
|
|
|
|
/* We use stdout print only if invoked by the --list-packets command
|
2010-03-15 12:15:45 +01:00
|
|
|
but switch to stderr in all other cases. This breaks the
|
2009-10-02 11:15:10 +02:00
|
|
|
previous behaviour but that seems to be more of a bug than
|
|
|
|
intentional. I don't believe that any application makes use of
|
|
|
|
this long standing annoying way of printing to stdout except when
|
|
|
|
doing a --list-packets. If this assumption fails, it will be easy
|
|
|
|
to add an option for the listing stream. Note that we initialize
|
|
|
|
it only once; mainly because some code may switch the option
|
|
|
|
value later back to 1 and we want to have all output to the same
|
|
|
|
stream.
|
|
|
|
|
|
|
|
Using stderr is not actually very clean because it bypasses the
|
2010-03-15 12:15:45 +01:00
|
|
|
logging code but it is a special thing anyway. I am not sure
|
2009-10-02 11:15:10 +02:00
|
|
|
whether using log_stream() would be better. Perhaps we should
|
|
|
|
enable the list mdoe only with a special option. */
|
|
|
|
if (!listfp)
|
2010-03-15 12:15:45 +01:00
|
|
|
listfp = opt.list_packets == 2 ? es_stdout : es_stderr;
|
2009-10-02 11:15:10 +02:00
|
|
|
return old;
|
2003-06-05 09:14:21 +02:00
|
|
|
}
|
|
|
|
|
2009-10-02 11:15:10 +02:00
|
|
|
|
2003-06-05 09:14:21 +02:00
|
|
|
static void
|
2009-10-02 11:15:10 +02:00
|
|
|
unknown_pubkey_warning (int algo)
|
2003-06-05 09:14:21 +02:00
|
|
|
{
|
2009-10-02 11:15:10 +02:00
|
|
|
static byte unknown_pubkey_algos[256];
|
2003-06-05 09:14:21 +02:00
|
|
|
|
2009-10-02 11:15:10 +02:00
|
|
|
algo &= 0xff;
|
|
|
|
if (!unknown_pubkey_algos[algo])
|
|
|
|
{
|
|
|
|
if (opt.verbose)
|
|
|
|
log_info (_("can't handle public key algorithm %d\n"), algo);
|
|
|
|
unknown_pubkey_algos[algo] = 1;
|
2003-06-05 09:14:21 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2009-10-02 11:15:10 +02:00
|
|
|
|
|
|
|
/* Parse a packet and return it in packet structure.
|
2003-06-05 09:14:21 +02:00
|
|
|
* Returns: 0 := valid packet in pkt
|
|
|
|
* -1 := no more packets
|
|
|
|
* >0 := error
|
|
|
|
* Note: The function may return an error and a partly valid packet;
|
2009-10-02 11:15:10 +02:00
|
|
|
* caller must free this packet. */
|
2003-06-05 09:14:21 +02:00
|
|
|
#ifdef DEBUG_PARSE_PACKET
|
|
|
|
int
|
2009-10-02 11:15:10 +02:00
|
|
|
dbg_parse_packet (IOBUF inp, PACKET *pkt, const char *dbg_f, int dbg_l)
|
2003-06-05 09:14:21 +02:00
|
|
|
{
|
2009-10-02 11:15:10 +02:00
|
|
|
int skip, rc;
|
2003-06-05 09:14:21 +02:00
|
|
|
|
2009-10-02 11:15:10 +02:00
|
|
|
do
|
|
|
|
{
|
|
|
|
rc = parse (inp, pkt, 0, NULL, &skip, NULL, 0, "parse", dbg_f, dbg_l);
|
|
|
|
}
|
|
|
|
while (skip);
|
|
|
|
return rc;
|
2003-06-05 09:14:21 +02:00
|
|
|
}
|
2009-10-02 11:15:10 +02:00
|
|
|
#else /*!DEBUG_PARSE_PACKET*/
|
2003-06-05 09:14:21 +02:00
|
|
|
int
|
2009-10-02 11:15:10 +02:00
|
|
|
parse_packet (IOBUF inp, PACKET * pkt)
|
2003-06-05 09:14:21 +02:00
|
|
|
{
|
2009-10-02 11:15:10 +02:00
|
|
|
int skip, rc;
|
2003-06-05 09:14:21 +02:00
|
|
|
|
2009-10-02 11:15:10 +02:00
|
|
|
do
|
|
|
|
{
|
|
|
|
rc = parse (inp, pkt, 0, NULL, &skip, NULL, 0);
|
|
|
|
}
|
|
|
|
while (skip);
|
|
|
|
return rc;
|
2003-06-05 09:14:21 +02:00
|
|
|
}
|
2009-10-02 11:15:10 +02:00
|
|
|
#endif /*!DEBUG_PARSE_PACKET*/
|
2003-06-05 09:14:21 +02:00
|
|
|
|
2009-10-02 11:15:10 +02:00
|
|
|
|
|
|
|
/*
|
|
|
|
* Like parse packet, but only return secret or public (sub)key
|
|
|
|
* packets.
|
2003-06-05 09:14:21 +02:00
|
|
|
*/
|
|
|
|
#ifdef DEBUG_PARSE_PACKET
|
|
|
|
int
|
2009-10-02 11:15:10 +02:00
|
|
|
dbg_search_packet (IOBUF inp, PACKET * pkt, off_t * retpos, int with_uid,
|
|
|
|
const char *dbg_f, int dbg_l)
|
2003-06-05 09:14:21 +02:00
|
|
|
{
|
2009-10-02 11:15:10 +02:00
|
|
|
int skip, rc;
|
2003-06-05 09:14:21 +02:00
|
|
|
|
2009-10-02 11:15:10 +02:00
|
|
|
do
|
|
|
|
{
|
|
|
|
rc =
|
|
|
|
parse (inp, pkt, with_uid ? 2 : 1, retpos, &skip, NULL, 0, "search",
|
|
|
|
dbg_f, dbg_l);
|
|
|
|
}
|
|
|
|
while (skip);
|
|
|
|
return rc;
|
2003-06-05 09:14:21 +02:00
|
|
|
}
|
2009-10-02 11:15:10 +02:00
|
|
|
#else /*!DEBUG_PARSE_PACKET*/
|
2003-06-05 09:14:21 +02:00
|
|
|
int
|
2009-10-02 11:15:10 +02:00
|
|
|
search_packet (IOBUF inp, PACKET * pkt, off_t * retpos, int with_uid)
|
2003-06-05 09:14:21 +02:00
|
|
|
{
|
2009-10-02 11:15:10 +02:00
|
|
|
int skip, rc;
|
2003-06-05 09:14:21 +02:00
|
|
|
|
2009-10-02 11:15:10 +02:00
|
|
|
do
|
|
|
|
{
|
|
|
|
rc = parse (inp, pkt, with_uid ? 2 : 1, retpos, &skip, NULL, 0);
|
|
|
|
}
|
|
|
|
while (skip);
|
|
|
|
return rc;
|
2003-06-05 09:14:21 +02:00
|
|
|
}
|
2009-10-02 11:15:10 +02:00
|
|
|
#endif /*!DEBUG_PARSE_PACKET*/
|
|
|
|
|
2003-06-05 09:14:21 +02:00
|
|
|
|
2009-10-02 11:15:10 +02:00
|
|
|
/*
|
2003-06-05 09:14:21 +02:00
|
|
|
* Copy all packets from INP to OUT, thereby removing unused spaces.
|
|
|
|
*/
|
|
|
|
#ifdef DEBUG_PARSE_PACKET
|
|
|
|
int
|
2009-10-02 11:15:10 +02:00
|
|
|
dbg_copy_all_packets (IOBUF inp, IOBUF out, const char *dbg_f, int dbg_l)
|
2003-06-05 09:14:21 +02:00
|
|
|
{
|
2009-10-02 11:15:10 +02:00
|
|
|
PACKET pkt;
|
|
|
|
int skip, rc = 0;
|
|
|
|
do
|
|
|
|
{
|
|
|
|
init_packet (&pkt);
|
|
|
|
}
|
|
|
|
while (!
|
|
|
|
(rc =
|
|
|
|
parse (inp, &pkt, 0, NULL, &skip, out, 0, "copy", dbg_f, dbg_l)));
|
|
|
|
return rc;
|
2003-06-05 09:14:21 +02:00
|
|
|
}
|
2009-10-02 11:15:10 +02:00
|
|
|
#else /*!DEBUG_PARSE_PACKET*/
|
2003-06-05 09:14:21 +02:00
|
|
|
int
|
2009-10-02 11:15:10 +02:00
|
|
|
copy_all_packets (IOBUF inp, IOBUF out)
|
2003-06-05 09:14:21 +02:00
|
|
|
{
|
2009-10-02 11:15:10 +02:00
|
|
|
PACKET pkt;
|
|
|
|
int skip, rc = 0;
|
|
|
|
do
|
|
|
|
{
|
|
|
|
init_packet (&pkt);
|
|
|
|
}
|
|
|
|
while (!(rc = parse (inp, &pkt, 0, NULL, &skip, out, 0)));
|
|
|
|
return rc;
|
2003-06-05 09:14:21 +02:00
|
|
|
}
|
2009-10-02 11:15:10 +02:00
|
|
|
#endif /*!DEBUG_PARSE_PACKET*/
|
|
|
|
|
2003-06-05 09:14:21 +02:00
|
|
|
|
2009-10-02 11:15:10 +02:00
|
|
|
/*
|
2003-06-05 09:14:21 +02:00
|
|
|
* Copy some packets from INP to OUT, thereby removing unused spaces.
|
2009-10-02 11:15:10 +02:00
|
|
|
* Stop at offset STOPoff (i.e. don't copy packets at this or later
|
|
|
|
* offsets)
|
2003-06-05 09:14:21 +02:00
|
|
|
*/
|
|
|
|
#ifdef DEBUG_PARSE_PACKET
|
|
|
|
int
|
2009-10-02 11:15:10 +02:00
|
|
|
dbg_copy_some_packets (IOBUF inp, IOBUF out, off_t stopoff,
|
|
|
|
const char *dbg_f, int dbg_l)
|
2003-06-05 09:14:21 +02:00
|
|
|
{
|
2009-10-02 11:15:10 +02:00
|
|
|
PACKET pkt;
|
|
|
|
int skip, rc = 0;
|
|
|
|
do
|
|
|
|
{
|
|
|
|
if (iobuf_tell (inp) >= stopoff)
|
|
|
|
return 0;
|
|
|
|
init_packet (&pkt);
|
|
|
|
}
|
|
|
|
while (!(rc = parse (inp, &pkt, 0, NULL, &skip, out, 0,
|
|
|
|
"some", dbg_f, dbg_l)));
|
|
|
|
return rc;
|
2003-06-05 09:14:21 +02:00
|
|
|
}
|
2009-10-02 11:15:10 +02:00
|
|
|
#else /*!DEBUG_PARSE_PACKET*/
|
2003-06-05 09:14:21 +02:00
|
|
|
int
|
2009-10-02 11:15:10 +02:00
|
|
|
copy_some_packets (IOBUF inp, IOBUF out, off_t stopoff)
|
2003-06-05 09:14:21 +02:00
|
|
|
{
|
2009-10-02 11:15:10 +02:00
|
|
|
PACKET pkt;
|
|
|
|
int skip, rc = 0;
|
|
|
|
do
|
|
|
|
{
|
|
|
|
if (iobuf_tell (inp) >= stopoff)
|
|
|
|
return 0;
|
|
|
|
init_packet (&pkt);
|
|
|
|
}
|
|
|
|
while (!(rc = parse (inp, &pkt, 0, NULL, &skip, out, 0)));
|
|
|
|
return rc;
|
2003-06-05 09:14:21 +02:00
|
|
|
}
|
2009-10-02 11:15:10 +02:00
|
|
|
#endif /*!DEBUG_PARSE_PACKET*/
|
|
|
|
|
2003-06-05 09:14:21 +02:00
|
|
|
|
2009-10-02 11:15:10 +02:00
|
|
|
/*
|
2003-06-05 09:14:21 +02:00
|
|
|
* Skip over N packets
|
|
|
|
*/
|
|
|
|
#ifdef DEBUG_PARSE_PACKET
|
|
|
|
int
|
2009-10-02 11:15:10 +02:00
|
|
|
dbg_skip_some_packets (IOBUF inp, unsigned n, const char *dbg_f, int dbg_l)
|
2003-06-05 09:14:21 +02:00
|
|
|
{
|
2009-10-02 11:15:10 +02:00
|
|
|
int skip, rc = 0;
|
|
|
|
PACKET pkt;
|
2003-06-05 09:14:21 +02:00
|
|
|
|
2009-10-02 11:15:10 +02:00
|
|
|
for (; n && !rc; n--)
|
|
|
|
{
|
|
|
|
init_packet (&pkt);
|
|
|
|
rc = parse (inp, &pkt, 0, NULL, &skip, NULL, 1, "skip", dbg_f, dbg_l);
|
2003-06-05 09:14:21 +02:00
|
|
|
}
|
2009-10-02 11:15:10 +02:00
|
|
|
return rc;
|
2003-06-05 09:14:21 +02:00
|
|
|
}
|
2009-10-02 11:15:10 +02:00
|
|
|
#else /*!DEBUG_PARSE_PACKET*/
|
2003-06-05 09:14:21 +02:00
|
|
|
int
|
2009-10-02 11:15:10 +02:00
|
|
|
skip_some_packets (IOBUF inp, unsigned n)
|
2003-06-05 09:14:21 +02:00
|
|
|
{
|
2009-10-02 11:15:10 +02:00
|
|
|
int skip, rc = 0;
|
|
|
|
PACKET pkt;
|
2003-06-05 09:14:21 +02:00
|
|
|
|
2009-10-02 11:15:10 +02:00
|
|
|
for (; n && !rc; n--)
|
|
|
|
{
|
|
|
|
init_packet (&pkt);
|
|
|
|
rc = parse (inp, &pkt, 0, NULL, &skip, NULL, 1);
|
2003-06-05 09:14:21 +02:00
|
|
|
}
|
2009-10-02 11:15:10 +02:00
|
|
|
return rc;
|
2003-06-05 09:14:21 +02:00
|
|
|
}
|
2009-10-02 11:15:10 +02:00
|
|
|
#endif /*!DEBUG_PARSE_PACKET*/
|
2003-06-05 09:14:21 +02:00
|
|
|
|
|
|
|
|
2009-10-02 11:15:10 +02:00
|
|
|
/*
|
|
|
|
* Parse packet. Stores 1 at SKIP 1 if the packet should be skipped;
|
|
|
|
* this is the case if either ONLYKEYPKTS is set and the parsed packet
|
|
|
|
* isn't a key packet or the packet-type is 0, indicating deleted
|
|
|
|
* stuff. If OUT is not NULL, a special copymode is used.
|
2003-06-05 09:14:21 +02:00
|
|
|
*/
|
|
|
|
static int
|
2009-10-02 11:15:10 +02:00
|
|
|
parse (IOBUF inp, PACKET * pkt, int onlykeypkts, off_t * retpos,
|
2006-04-19 13:26:11 +02:00
|
|
|
int *skip, IOBUF out, int do_skip
|
2003-06-05 09:14:21 +02:00
|
|
|
#ifdef DEBUG_PARSE_PACKET
|
2009-10-02 11:15:10 +02:00
|
|
|
, const char *dbg_w, const char *dbg_f, int dbg_l
|
2003-06-05 09:14:21 +02:00
|
|
|
#endif
|
2009-10-02 11:15:10 +02:00
|
|
|
)
|
2003-06-05 09:14:21 +02:00
|
|
|
{
|
2009-10-02 11:15:10 +02:00
|
|
|
int rc = 0, c, ctb, pkttype, lenbytes;
|
|
|
|
unsigned long pktlen;
|
|
|
|
byte hdr[8];
|
|
|
|
int hdrlen;
|
|
|
|
int new_ctb = 0, partial = 0;
|
|
|
|
int with_uid = (onlykeypkts == 2);
|
|
|
|
|
|
|
|
*skip = 0;
|
|
|
|
assert (!pkt->pkt.generic);
|
|
|
|
if (retpos)
|
|
|
|
*retpos = iobuf_tell (inp);
|
|
|
|
|
|
|
|
if ((ctb = iobuf_get (inp)) == -1)
|
|
|
|
{
|
|
|
|
rc = -1;
|
|
|
|
goto leave;
|
2003-06-05 09:14:21 +02:00
|
|
|
}
|
2009-10-02 11:15:10 +02:00
|
|
|
hdrlen = 0;
|
|
|
|
hdr[hdrlen++] = ctb;
|
|
|
|
if (!(ctb & 0x80))
|
|
|
|
{
|
|
|
|
log_error ("%s: invalid packet (ctb=%02x)\n", iobuf_where (inp), ctb);
|
|
|
|
rc = gpg_error (GPG_ERR_INV_PACKET);
|
|
|
|
goto leave;
|
2003-06-05 09:14:21 +02:00
|
|
|
}
|
2009-10-02 11:15:10 +02:00
|
|
|
pktlen = 0;
|
|
|
|
new_ctb = !!(ctb & 0x40);
|
|
|
|
if (new_ctb)
|
|
|
|
{
|
|
|
|
pkttype = ctb & 0x3f;
|
|
|
|
if ((c = iobuf_get (inp)) == -1)
|
|
|
|
{
|
|
|
|
log_error ("%s: 1st length byte missing\n", iobuf_where (inp));
|
|
|
|
rc = gpg_error (GPG_ERR_INV_PACKET);
|
|
|
|
goto leave;
|
2003-06-05 09:14:21 +02:00
|
|
|
}
|
2008-09-25 14:55:50 +02:00
|
|
|
|
2009-10-02 11:15:10 +02:00
|
|
|
|
|
|
|
hdr[hdrlen++] = c;
|
|
|
|
if (c < 192)
|
|
|
|
pktlen = c;
|
|
|
|
else if (c < 224)
|
|
|
|
{
|
|
|
|
pktlen = (c - 192) * 256;
|
|
|
|
if ((c = iobuf_get (inp)) == -1)
|
|
|
|
{
|
|
|
|
log_error ("%s: 2nd length byte missing\n",
|
|
|
|
iobuf_where (inp));
|
|
|
|
rc = gpg_error (GPG_ERR_INV_PACKET);
|
|
|
|
goto leave;
|
|
|
|
}
|
|
|
|
hdr[hdrlen++] = c;
|
|
|
|
pktlen += c + 192;
|
|
|
|
}
|
|
|
|
else if (c == 255)
|
|
|
|
{
|
|
|
|
pktlen = (hdr[hdrlen++] = iobuf_get_noeof (inp)) << 24;
|
|
|
|
pktlen |= (hdr[hdrlen++] = iobuf_get_noeof (inp)) << 16;
|
|
|
|
pktlen |= (hdr[hdrlen++] = iobuf_get_noeof (inp)) << 8;
|
|
|
|
if ((c = iobuf_get (inp)) == -1)
|
|
|
|
{
|
|
|
|
log_error ("%s: 4 byte length invalid\n", iobuf_where (inp));
|
|
|
|
rc = gpg_error (GPG_ERR_INV_PACKET);
|
|
|
|
goto leave;
|
|
|
|
}
|
|
|
|
pktlen |= (hdr[hdrlen++] = c);
|
|
|
|
}
|
|
|
|
else /* Partial body length. */
|
2008-09-25 14:55:50 +02:00
|
|
|
{
|
2009-10-02 11:15:10 +02:00
|
|
|
switch (pkttype)
|
|
|
|
{
|
|
|
|
case PKT_PLAINTEXT:
|
|
|
|
case PKT_ENCRYPTED:
|
|
|
|
case PKT_ENCRYPTED_MDC:
|
|
|
|
case PKT_COMPRESSED:
|
|
|
|
iobuf_set_partial_block_mode (inp, c & 0xff);
|
|
|
|
pktlen = 0; /* To indicate partial length. */
|
|
|
|
partial = 1;
|
|
|
|
break;
|
|
|
|
|
|
|
|
default:
|
|
|
|
log_error ("%s: partial length for invalid"
|
|
|
|
" packet type %d\n", iobuf_where (inp), pkttype);
|
|
|
|
rc = gpg_error (GPG_ERR_INV_PACKET);
|
|
|
|
goto leave;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
pkttype = (ctb >> 2) & 0xf;
|
|
|
|
lenbytes = ((ctb & 3) == 3) ? 0 : (1 << (ctb & 3));
|
|
|
|
if (!lenbytes)
|
|
|
|
{
|
|
|
|
pktlen = 0; /* Don't know the value. */
|
|
|
|
/* This isn't really partial, but we can treat it the same
|
|
|
|
in a "read until the end" sort of way. */
|
|
|
|
partial = 1;
|
|
|
|
if (pkttype != PKT_ENCRYPTED && pkttype != PKT_PLAINTEXT
|
|
|
|
&& pkttype != PKT_COMPRESSED)
|
|
|
|
{
|
|
|
|
log_error ("%s: indeterminate length for invalid"
|
|
|
|
" packet type %d\n", iobuf_where (inp), pkttype);
|
|
|
|
rc = gpg_error (GPG_ERR_INV_PACKET);
|
|
|
|
goto leave;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
for (; lenbytes; lenbytes--)
|
|
|
|
{
|
|
|
|
pktlen <<= 8;
|
|
|
|
pktlen |= hdr[hdrlen++] = iobuf_get_noeof (inp);
|
|
|
|
}
|
2003-06-05 09:14:21 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2009-10-02 11:15:10 +02:00
|
|
|
if (pktlen == (unsigned long) (-1))
|
|
|
|
{
|
|
|
|
/* With some probability this is caused by a problem in the
|
|
|
|
* the uncompressing layer - in some error cases it just loops
|
|
|
|
* and spits out 0xff bytes. */
|
|
|
|
log_error ("%s: garbled packet detected\n", iobuf_where (inp));
|
|
|
|
g10_exit (2);
|
2003-06-05 09:14:21 +02:00
|
|
|
}
|
|
|
|
|
2009-10-02 11:15:10 +02:00
|
|
|
if (out && pkttype)
|
|
|
|
{
|
2006-04-19 15:24:36 +02:00
|
|
|
rc = iobuf_write (out, hdr, hdrlen);
|
|
|
|
if (!rc)
|
2009-10-02 11:15:10 +02:00
|
|
|
rc = copy_packet (inp, out, pkttype, pktlen, partial);
|
2006-04-19 15:24:36 +02:00
|
|
|
goto leave;
|
2003-06-05 09:14:21 +02:00
|
|
|
}
|
|
|
|
|
2009-10-02 11:15:10 +02:00
|
|
|
if (with_uid && pkttype == PKT_USER_ID)
|
|
|
|
;
|
|
|
|
else if (do_skip
|
|
|
|
|| !pkttype
|
|
|
|
|| (onlykeypkts && pkttype != PKT_PUBLIC_SUBKEY
|
|
|
|
&& pkttype != PKT_PUBLIC_KEY
|
|
|
|
&& pkttype != PKT_SECRET_SUBKEY && pkttype != PKT_SECRET_KEY))
|
|
|
|
{
|
|
|
|
iobuf_skip_rest (inp, pktlen, partial);
|
|
|
|
*skip = 1;
|
|
|
|
rc = 0;
|
|
|
|
goto leave;
|
2003-06-05 09:14:21 +02:00
|
|
|
}
|
|
|
|
|
2009-10-02 11:15:10 +02:00
|
|
|
if (DBG_PACKET)
|
|
|
|
{
|
2003-06-05 09:14:21 +02:00
|
|
|
#ifdef DEBUG_PARSE_PACKET
|
2009-10-02 11:15:10 +02:00
|
|
|
log_debug ("parse_packet(iob=%d): type=%d length=%lu%s (%s.%s.%d)\n",
|
|
|
|
iobuf_id (inp), pkttype, pktlen, new_ctb ? " (new_ctb)" : "",
|
|
|
|
dbg_w, dbg_f, dbg_l);
|
2003-06-05 09:14:21 +02:00
|
|
|
#else
|
2009-10-02 11:15:10 +02:00
|
|
|
log_debug ("parse_packet(iob=%d): type=%d length=%lu%s\n",
|
|
|
|
iobuf_id (inp), pkttype, pktlen,
|
|
|
|
new_ctb ? " (new_ctb)" : "");
|
2003-06-05 09:14:21 +02:00
|
|
|
#endif
|
|
|
|
}
|
2009-10-02 11:15:10 +02:00
|
|
|
|
|
|
|
pkt->pkttype = pkttype;
|
|
|
|
rc = G10ERR_UNKNOWN_PACKET; /* default error */
|
|
|
|
switch (pkttype)
|
|
|
|
{
|
|
|
|
case PKT_PUBLIC_KEY:
|
|
|
|
case PKT_PUBLIC_SUBKEY:
|
|
|
|
case PKT_SECRET_KEY:
|
|
|
|
case PKT_SECRET_SUBKEY:
|
2010-09-06 21:57:42 +02:00
|
|
|
pkt->pkt.public_key = xmalloc_clear (sizeof *pkt->pkt.public_key);
|
2009-10-02 11:15:10 +02:00
|
|
|
rc = parse_key (inp, pkttype, pktlen, hdr, hdrlen, pkt);
|
|
|
|
break;
|
|
|
|
case PKT_SYMKEY_ENC:
|
|
|
|
rc = parse_symkeyenc (inp, pkttype, pktlen, pkt);
|
|
|
|
break;
|
|
|
|
case PKT_PUBKEY_ENC:
|
|
|
|
rc = parse_pubkeyenc (inp, pkttype, pktlen, pkt);
|
|
|
|
break;
|
|
|
|
case PKT_SIGNATURE:
|
|
|
|
pkt->pkt.signature = xmalloc_clear (sizeof *pkt->pkt.signature);
|
|
|
|
rc = parse_signature (inp, pkttype, pktlen, pkt->pkt.signature);
|
|
|
|
break;
|
|
|
|
case PKT_ONEPASS_SIG:
|
|
|
|
pkt->pkt.onepass_sig = xmalloc_clear (sizeof *pkt->pkt.onepass_sig);
|
|
|
|
rc = parse_onepass_sig (inp, pkttype, pktlen, pkt->pkt.onepass_sig);
|
|
|
|
break;
|
|
|
|
case PKT_USER_ID:
|
|
|
|
rc = parse_user_id (inp, pkttype, pktlen, pkt);
|
|
|
|
break;
|
|
|
|
case PKT_ATTRIBUTE:
|
|
|
|
pkt->pkttype = pkttype = PKT_USER_ID; /* we store it in the userID */
|
|
|
|
rc = parse_attribute (inp, pkttype, pktlen, pkt);
|
|
|
|
break;
|
|
|
|
case PKT_OLD_COMMENT:
|
|
|
|
case PKT_COMMENT:
|
|
|
|
rc = parse_comment (inp, pkttype, pktlen, pkt);
|
|
|
|
break;
|
|
|
|
case PKT_RING_TRUST:
|
|
|
|
parse_trust (inp, pkttype, pktlen, pkt);
|
|
|
|
rc = 0;
|
|
|
|
break;
|
|
|
|
case PKT_PLAINTEXT:
|
|
|
|
rc = parse_plaintext (inp, pkttype, pktlen, pkt, new_ctb, partial);
|
|
|
|
break;
|
|
|
|
case PKT_COMPRESSED:
|
|
|
|
rc = parse_compressed (inp, pkttype, pktlen, pkt, new_ctb);
|
|
|
|
break;
|
|
|
|
case PKT_ENCRYPTED:
|
|
|
|
case PKT_ENCRYPTED_MDC:
|
|
|
|
rc = parse_encrypted (inp, pkttype, pktlen, pkt, new_ctb, partial);
|
|
|
|
break;
|
|
|
|
case PKT_MDC:
|
|
|
|
rc = parse_mdc (inp, pkttype, pktlen, pkt, new_ctb);
|
|
|
|
break;
|
|
|
|
case PKT_GPG_CONTROL:
|
|
|
|
rc = parse_gpg_control (inp, pkttype, pktlen, pkt, partial);
|
|
|
|
break;
|
2007-04-06 05:46:03 +02:00
|
|
|
case PKT_MARKER:
|
2009-10-02 11:15:10 +02:00
|
|
|
rc = parse_marker (inp, pkttype, pktlen);
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
skip_packet (inp, pkttype, pktlen, partial);
|
|
|
|
break;
|
2003-06-05 09:14:21 +02:00
|
|
|
}
|
|
|
|
|
2009-10-02 11:15:10 +02:00
|
|
|
leave:
|
2010-09-06 21:57:42 +02:00
|
|
|
/* FIXME: Do we leak in case of an error? */
|
2009-10-02 11:15:10 +02:00
|
|
|
if (!rc && iobuf_error (inp))
|
|
|
|
rc = G10ERR_INV_KEYRING;
|
|
|
|
return rc;
|
2003-06-05 09:14:21 +02:00
|
|
|
}
|
|
|
|
|
2009-10-02 11:15:10 +02:00
|
|
|
|
2003-06-05 09:14:21 +02:00
|
|
|
static void
|
2009-10-02 11:15:10 +02:00
|
|
|
dump_hex_line (int c, int *i)
|
2003-06-05 09:14:21 +02:00
|
|
|
{
|
2009-10-02 11:15:10 +02:00
|
|
|
if (*i && !(*i % 8))
|
|
|
|
{
|
|
|
|
if (*i && !(*i % 24))
|
2010-03-15 12:15:45 +01:00
|
|
|
es_fprintf (listfp, "\n%4d:", *i);
|
2009-10-02 11:15:10 +02:00
|
|
|
else
|
2010-03-15 12:15:45 +01:00
|
|
|
es_putc (' ', listfp);
|
2003-06-05 09:14:21 +02:00
|
|
|
}
|
2009-10-02 11:15:10 +02:00
|
|
|
if (c == -1)
|
2010-03-15 12:15:45 +01:00
|
|
|
es_fprintf (listfp, " EOF");
|
2009-10-02 11:15:10 +02:00
|
|
|
else
|
2010-03-15 12:15:45 +01:00
|
|
|
es_fprintf (listfp, " %02x", c);
|
2009-10-02 11:15:10 +02:00
|
|
|
++*i;
|
2003-06-05 09:14:21 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static int
|
2009-10-02 11:15:10 +02:00
|
|
|
copy_packet (IOBUF inp, IOBUF out, int pkttype,
|
|
|
|
unsigned long pktlen, int partial)
|
2003-06-05 09:14:21 +02:00
|
|
|
{
|
2009-10-02 11:15:10 +02:00
|
|
|
int rc;
|
|
|
|
int n;
|
|
|
|
char buf[100];
|
|
|
|
|
|
|
|
if (partial)
|
|
|
|
{
|
|
|
|
while ((n = iobuf_read (inp, buf, 100)) != -1)
|
|
|
|
if ((rc = iobuf_write (out, buf, n)))
|
|
|
|
return rc; /* write error */
|
|
|
|
}
|
|
|
|
else if (!pktlen && pkttype == PKT_COMPRESSED)
|
|
|
|
{
|
|
|
|
log_debug ("copy_packet: compressed!\n");
|
|
|
|
/* compressed packet, copy till EOF */
|
|
|
|
while ((n = iobuf_read (inp, buf, 100)) != -1)
|
|
|
|
if ((rc = iobuf_write (out, buf, n)))
|
|
|
|
return rc; /* write error */
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
for (; pktlen; pktlen -= n)
|
|
|
|
{
|
|
|
|
n = pktlen > 100 ? 100 : pktlen;
|
|
|
|
n = iobuf_read (inp, buf, n);
|
|
|
|
if (n == -1)
|
|
|
|
return gpg_error (GPG_ERR_EOF);
|
|
|
|
if ((rc = iobuf_write (out, buf, n)))
|
|
|
|
return rc; /* write error */
|
2003-06-05 09:14:21 +02:00
|
|
|
}
|
|
|
|
}
|
2009-10-02 11:15:10 +02:00
|
|
|
return 0;
|
2003-06-05 09:14:21 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static void
|
2009-10-02 11:15:10 +02:00
|
|
|
skip_packet (IOBUF inp, int pkttype, unsigned long pktlen, int partial)
|
2003-06-05 09:14:21 +02:00
|
|
|
{
|
2009-10-02 11:15:10 +02:00
|
|
|
if (list_mode)
|
2007-04-06 05:46:03 +02:00
|
|
|
{
|
2010-03-15 12:15:45 +01:00
|
|
|
es_fprintf (listfp, ":unknown packet: type %2d, length %lu\n",
|
|
|
|
pkttype, pktlen);
|
2009-10-02 11:15:10 +02:00
|
|
|
if (pkttype)
|
2007-04-06 05:46:03 +02:00
|
|
|
{
|
2009-10-02 11:15:10 +02:00
|
|
|
int c, i = 0;
|
2010-03-15 12:15:45 +01:00
|
|
|
es_fputs ("dump:", listfp);
|
2009-10-02 11:15:10 +02:00
|
|
|
if (partial)
|
2007-04-06 05:46:03 +02:00
|
|
|
{
|
2009-10-02 11:15:10 +02:00
|
|
|
while ((c = iobuf_get (inp)) != -1)
|
|
|
|
dump_hex_line (c, &i);
|
2003-06-05 09:14:21 +02:00
|
|
|
}
|
2007-04-06 05:46:03 +02:00
|
|
|
else
|
|
|
|
{
|
2009-10-02 11:15:10 +02:00
|
|
|
for (; pktlen; pktlen--)
|
|
|
|
{
|
|
|
|
dump_hex_line ((c = iobuf_get (inp)), &i);
|
|
|
|
if (c == -1)
|
|
|
|
break;
|
|
|
|
}
|
2003-06-05 09:14:21 +02:00
|
|
|
}
|
2010-03-15 12:15:45 +01:00
|
|
|
es_putc ('\n', listfp);
|
2007-04-06 05:46:03 +02:00
|
|
|
return;
|
2003-06-05 09:14:21 +02:00
|
|
|
}
|
|
|
|
}
|
2009-10-02 11:15:10 +02:00
|
|
|
iobuf_skip_rest (inp, pktlen, partial);
|
2003-06-05 09:14:21 +02:00
|
|
|
}
|
|
|
|
|
2009-10-02 11:15:10 +02:00
|
|
|
|
2011-03-23 10:07:59 +01:00
|
|
|
/* Read PKTLEN bytes form INP and return them in a newly allocated
|
|
|
|
buffer. In case of an error NULL is returned and a error messages
|
|
|
|
printed. */
|
2003-06-05 09:14:21 +02:00
|
|
|
static void *
|
2011-03-23 10:07:59 +01:00
|
|
|
read_rest (IOBUF inp, size_t pktlen)
|
2003-06-05 09:14:21 +02:00
|
|
|
{
|
2011-03-23 10:07:59 +01:00
|
|
|
int c;
|
|
|
|
byte *buf, *p;
|
2003-06-05 09:14:21 +02:00
|
|
|
|
2011-03-23 10:07:59 +01:00
|
|
|
buf = xtrymalloc (pktlen);
|
|
|
|
if (!buf)
|
2009-10-02 11:15:10 +02:00
|
|
|
{
|
2011-03-23 10:07:59 +01:00
|
|
|
gpg_error_t err = gpg_error_from_syserror ();
|
|
|
|
log_error ("error reading rest of packet: %s\n", gpg_strerror (err));
|
|
|
|
return NULL;
|
2003-06-05 09:14:21 +02:00
|
|
|
}
|
2011-03-23 10:07:59 +01:00
|
|
|
for (p = buf; pktlen; pktlen--)
|
2009-10-02 11:15:10 +02:00
|
|
|
{
|
2011-03-23 10:07:59 +01:00
|
|
|
c = iobuf_get (inp);
|
|
|
|
if (c == -1)
|
|
|
|
{
|
|
|
|
log_error ("premature eof while reading rest of packet\n");
|
|
|
|
xfree (buf);
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
*p++ = c;
|
2003-06-05 09:14:21 +02:00
|
|
|
}
|
2011-03-23 10:07:59 +01:00
|
|
|
|
|
|
|
return buf;
|
2003-06-05 09:14:21 +02:00
|
|
|
}
|
|
|
|
|
2009-10-02 11:15:10 +02:00
|
|
|
|
2011-01-31 09:27:06 +01:00
|
|
|
/* Read a special size+body from INP. On success store an opaque MPI
|
|
|
|
with it at R_DATA. On error return an error code and store NULL at
|
|
|
|
R_DATA. Even in the error case store the number of read bytes at
|
|
|
|
R_NREAD. The caller shall pass the remaining size of the packet in
|
|
|
|
PKTLEN. */
|
|
|
|
static gpg_error_t
|
|
|
|
read_size_body (iobuf_t inp, int pktlen, size_t *r_nread,
|
|
|
|
gcry_mpi_t *r_data)
|
2011-01-26 17:17:43 +01:00
|
|
|
{
|
2011-01-31 09:27:06 +01:00
|
|
|
char buffer[256];
|
|
|
|
char *tmpbuf;
|
|
|
|
int i, c, nbytes;
|
|
|
|
|
|
|
|
*r_nread = 0;
|
|
|
|
*r_data = NULL;
|
|
|
|
|
|
|
|
if (!pktlen)
|
|
|
|
return gpg_error (GPG_ERR_INV_PACKET);
|
|
|
|
c = iobuf_readbyte (inp);
|
|
|
|
if (c < 0)
|
|
|
|
return gpg_error (GPG_ERR_INV_PACKET);
|
|
|
|
pktlen--;
|
|
|
|
++*r_nread;
|
|
|
|
nbytes = c;
|
|
|
|
if (nbytes < 2 || nbytes > 254)
|
|
|
|
return gpg_error (GPG_ERR_INV_PACKET);
|
|
|
|
if (nbytes > pktlen)
|
|
|
|
return gpg_error (GPG_ERR_INV_PACKET);
|
2011-01-26 17:17:43 +01:00
|
|
|
|
2011-01-31 09:27:06 +01:00
|
|
|
buffer[0] = nbytes;
|
2011-01-26 17:17:43 +01:00
|
|
|
|
2011-01-31 09:27:06 +01:00
|
|
|
for (i = 0; i < nbytes; i++)
|
2011-01-26 17:17:43 +01:00
|
|
|
{
|
2011-01-31 09:27:06 +01:00
|
|
|
c = iobuf_get (inp);
|
|
|
|
if (c < 0)
|
|
|
|
return gpg_error (GPG_ERR_INV_PACKET);
|
|
|
|
++*r_nread;
|
|
|
|
buffer[1+i] = c;
|
2011-01-26 17:17:43 +01:00
|
|
|
}
|
2011-01-31 09:27:06 +01:00
|
|
|
|
|
|
|
tmpbuf = xtrymalloc (1 + nbytes);
|
|
|
|
if (!tmpbuf)
|
|
|
|
return gpg_error_from_syserror ();
|
|
|
|
memcpy (tmpbuf, buffer, 1 + nbytes);
|
|
|
|
*r_data = gcry_mpi_set_opaque (NULL, tmpbuf, 8 * (1 + nbytes));
|
|
|
|
if (!*r_data)
|
2011-01-26 17:17:43 +01:00
|
|
|
{
|
2011-01-31 09:27:06 +01:00
|
|
|
xfree (tmpbuf);
|
|
|
|
return gpg_error_from_syserror ();
|
2011-01-26 17:17:43 +01:00
|
|
|
}
|
2011-01-31 09:27:06 +01:00
|
|
|
return 0;
|
2011-01-26 17:17:43 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/* Parse a marker packet. */
|
2007-04-06 05:46:03 +02:00
|
|
|
static int
|
2009-10-02 11:15:10 +02:00
|
|
|
parse_marker (IOBUF inp, int pkttype, unsigned long pktlen)
|
2007-04-06 05:46:03 +02:00
|
|
|
{
|
2009-10-02 11:15:10 +02:00
|
|
|
(void) pkttype;
|
2008-10-20 15:53:23 +02:00
|
|
|
|
2009-10-02 11:15:10 +02:00
|
|
|
if (pktlen != 3)
|
2007-04-06 05:46:03 +02:00
|
|
|
goto fail;
|
|
|
|
|
2009-10-02 11:15:10 +02:00
|
|
|
if (iobuf_get (inp) != 'P')
|
2007-04-06 05:46:03 +02:00
|
|
|
{
|
|
|
|
pktlen--;
|
|
|
|
goto fail;
|
|
|
|
}
|
|
|
|
|
2009-10-02 11:15:10 +02:00
|
|
|
if (iobuf_get (inp) != 'G')
|
2007-04-06 05:46:03 +02:00
|
|
|
{
|
|
|
|
pktlen--;
|
|
|
|
goto fail;
|
|
|
|
}
|
2003-06-05 09:14:21 +02:00
|
|
|
|
2009-10-02 11:15:10 +02:00
|
|
|
if (iobuf_get (inp) != 'P')
|
2007-04-06 05:46:03 +02:00
|
|
|
{
|
|
|
|
pktlen--;
|
|
|
|
goto fail;
|
|
|
|
}
|
|
|
|
|
2009-10-02 11:15:10 +02:00
|
|
|
if (list_mode)
|
2010-03-15 12:15:45 +01:00
|
|
|
es_fputs (":marker packet: PGP\n", listfp);
|
2007-04-06 05:46:03 +02:00
|
|
|
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
fail:
|
2009-10-02 11:15:10 +02:00
|
|
|
log_error ("invalid marker packet\n");
|
|
|
|
iobuf_skip_rest (inp, pktlen, 0);
|
2007-04-06 05:46:03 +02:00
|
|
|
return G10ERR_INVALID_PACKET;
|
|
|
|
}
|
2003-06-05 09:14:21 +02:00
|
|
|
|
2009-10-02 11:15:10 +02:00
|
|
|
|
2003-06-05 09:14:21 +02:00
|
|
|
static int
|
2009-10-02 11:15:10 +02:00
|
|
|
parse_symkeyenc (IOBUF inp, int pkttype, unsigned long pktlen,
|
|
|
|
PACKET * packet)
|
2003-06-05 09:14:21 +02:00
|
|
|
{
|
2009-10-02 11:15:10 +02:00
|
|
|
PKT_symkey_enc *k;
|
|
|
|
int rc = 0;
|
|
|
|
int i, version, s2kmode, cipher_algo, hash_algo, seskeylen, minlen;
|
2003-06-05 09:14:21 +02:00
|
|
|
|
2009-10-02 11:15:10 +02:00
|
|
|
if (pktlen < 4)
|
|
|
|
{
|
|
|
|
log_error ("packet(%d) too short\n", pkttype);
|
|
|
|
rc = gpg_error (GPG_ERR_INV_PACKET);
|
|
|
|
goto leave;
|
2003-06-05 09:14:21 +02:00
|
|
|
}
|
2009-10-02 11:15:10 +02:00
|
|
|
version = iobuf_get_noeof (inp);
|
|
|
|
pktlen--;
|
|
|
|
if (version != 4)
|
|
|
|
{
|
|
|
|
log_error ("packet(%d) with unknown version %d\n", pkttype, version);
|
|
|
|
rc = gpg_error (GPG_ERR_INV_PACKET);
|
|
|
|
goto leave;
|
2003-06-05 09:14:21 +02:00
|
|
|
}
|
2009-10-02 11:15:10 +02:00
|
|
|
if (pktlen > 200)
|
|
|
|
{ /* (we encode the seskeylen in a byte) */
|
|
|
|
log_error ("packet(%d) too large\n", pkttype);
|
|
|
|
rc = gpg_error (GPG_ERR_INV_PACKET);
|
|
|
|
goto leave;
|
2003-06-05 09:14:21 +02:00
|
|
|
}
|
2009-10-02 11:15:10 +02:00
|
|
|
cipher_algo = iobuf_get_noeof (inp);
|
|
|
|
pktlen--;
|
|
|
|
s2kmode = iobuf_get_noeof (inp);
|
|
|
|
pktlen--;
|
|
|
|
hash_algo = iobuf_get_noeof (inp);
|
|
|
|
pktlen--;
|
|
|
|
switch (s2kmode)
|
|
|
|
{
|
|
|
|
case 0: /* Simple S2K. */
|
|
|
|
minlen = 0;
|
|
|
|
break;
|
|
|
|
case 1: /* Salted S2K. */
|
|
|
|
minlen = 8;
|
|
|
|
break;
|
|
|
|
case 3: /* Iterated+salted S2K. */
|
|
|
|
minlen = 9;
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
log_error ("unknown S2K mode %d\n", s2kmode);
|
|
|
|
goto leave;
|
2003-06-05 09:14:21 +02:00
|
|
|
}
|
2009-10-02 11:15:10 +02:00
|
|
|
if (minlen > pktlen)
|
|
|
|
{
|
|
|
|
log_error ("packet with S2K %d too short\n", s2kmode);
|
|
|
|
rc = gpg_error (GPG_ERR_INV_PACKET);
|
|
|
|
goto leave;
|
2003-06-05 09:14:21 +02:00
|
|
|
}
|
2009-10-02 11:15:10 +02:00
|
|
|
seskeylen = pktlen - minlen;
|
|
|
|
k = packet->pkt.symkey_enc = xmalloc_clear (sizeof *packet->pkt.symkey_enc
|
|
|
|
+ seskeylen - 1);
|
|
|
|
k->version = version;
|
|
|
|
k->cipher_algo = cipher_algo;
|
|
|
|
k->s2k.mode = s2kmode;
|
|
|
|
k->s2k.hash_algo = hash_algo;
|
|
|
|
if (s2kmode == 1 || s2kmode == 3)
|
|
|
|
{
|
|
|
|
for (i = 0; i < 8 && pktlen; i++, pktlen--)
|
|
|
|
k->s2k.salt[i] = iobuf_get_noeof (inp);
|
|
|
|
}
|
|
|
|
if (s2kmode == 3)
|
|
|
|
{
|
|
|
|
k->s2k.count = iobuf_get (inp);
|
|
|
|
pktlen--;
|
|
|
|
}
|
|
|
|
k->seskeylen = seskeylen;
|
|
|
|
if (k->seskeylen)
|
|
|
|
{
|
|
|
|
for (i = 0; i < seskeylen && pktlen; i++, pktlen--)
|
|
|
|
k->seskey[i] = iobuf_get_noeof (inp);
|
|
|
|
|
|
|
|
/* What we're watching out for here is a session key decryptor
|
|
|
|
with no salt. The RFC says that using salt for this is a
|
|
|
|
MUST. */
|
|
|
|
if (s2kmode != 1 && s2kmode != 3)
|
|
|
|
log_info (_("WARNING: potentially insecure symmetrically"
|
|
|
|
" encrypted session key\n"));
|
|
|
|
}
|
|
|
|
assert (!pktlen);
|
2003-06-05 09:14:21 +02:00
|
|
|
|
2009-10-02 11:15:10 +02:00
|
|
|
if (list_mode)
|
|
|
|
{
|
2010-03-15 12:15:45 +01:00
|
|
|
es_fprintf (listfp,
|
|
|
|
":symkey enc packet: version %d, cipher %d, s2k %d, hash %d",
|
|
|
|
version, cipher_algo, s2kmode, hash_algo);
|
2009-10-02 11:15:10 +02:00
|
|
|
if (seskeylen)
|
2010-03-15 12:15:45 +01:00
|
|
|
es_fprintf (listfp, ", seskey %d bits", (seskeylen - 1) * 8);
|
|
|
|
es_fprintf (listfp, "\n");
|
2009-10-02 11:15:10 +02:00
|
|
|
if (s2kmode == 1 || s2kmode == 3)
|
|
|
|
{
|
2010-03-15 12:15:45 +01:00
|
|
|
es_fprintf (listfp, "\tsalt ");
|
|
|
|
es_write_hexstring (listfp, k->s2k.salt, 8, 0, NULL);
|
2009-10-02 11:15:10 +02:00
|
|
|
if (s2kmode == 3)
|
2010-03-15 12:15:45 +01:00
|
|
|
es_fprintf (listfp, ", count %lu (%lu)",
|
|
|
|
S2K_DECODE_COUNT ((ulong) k->s2k.count),
|
|
|
|
(ulong) k->s2k.count);
|
|
|
|
es_fprintf (listfp, "\n");
|
2003-06-05 09:14:21 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2009-10-02 11:15:10 +02:00
|
|
|
leave:
|
|
|
|
iobuf_skip_rest (inp, pktlen, 0);
|
|
|
|
return rc;
|
2003-06-05 09:14:21 +02:00
|
|
|
}
|
|
|
|
|
2009-10-02 11:15:10 +02:00
|
|
|
|
2003-06-05 09:14:21 +02:00
|
|
|
static int
|
2009-10-02 11:15:10 +02:00
|
|
|
parse_pubkeyenc (IOBUF inp, int pkttype, unsigned long pktlen,
|
|
|
|
PACKET * packet)
|
2003-06-05 09:14:21 +02:00
|
|
|
{
|
2009-10-02 11:15:10 +02:00
|
|
|
int rc = 0;
|
|
|
|
int i, ndata;
|
|
|
|
PKT_pubkey_enc *k;
|
|
|
|
|
|
|
|
k = packet->pkt.pubkey_enc = xmalloc_clear (sizeof *packet->pkt.pubkey_enc);
|
|
|
|
if (pktlen < 12)
|
|
|
|
{
|
|
|
|
log_error ("packet(%d) too short\n", pkttype);
|
|
|
|
rc = gpg_error (GPG_ERR_INV_PACKET);
|
|
|
|
goto leave;
|
2003-06-05 09:14:21 +02:00
|
|
|
}
|
2009-10-02 11:15:10 +02:00
|
|
|
k->version = iobuf_get_noeof (inp);
|
|
|
|
pktlen--;
|
|
|
|
if (k->version != 2 && k->version != 3)
|
|
|
|
{
|
|
|
|
log_error ("packet(%d) with unknown version %d\n", pkttype, k->version);
|
|
|
|
rc = gpg_error (GPG_ERR_INV_PACKET);
|
|
|
|
goto leave;
|
2003-06-05 09:14:21 +02:00
|
|
|
}
|
2009-10-02 11:15:10 +02:00
|
|
|
k->keyid[0] = read_32 (inp);
|
|
|
|
pktlen -= 4;
|
|
|
|
k->keyid[1] = read_32 (inp);
|
|
|
|
pktlen -= 4;
|
|
|
|
k->pubkey_algo = iobuf_get_noeof (inp);
|
|
|
|
pktlen--;
|
|
|
|
k->throw_keyid = 0; /* Only used as flag for build_packet. */
|
|
|
|
if (list_mode)
|
2010-03-15 12:15:45 +01:00
|
|
|
es_fprintf (listfp,
|
|
|
|
":pubkey enc packet: version %d, algo %d, keyid %08lX%08lX\n",
|
|
|
|
k->version, k->pubkey_algo, (ulong) k->keyid[0],
|
|
|
|
(ulong) k->keyid[1]);
|
2009-10-02 11:15:10 +02:00
|
|
|
|
|
|
|
ndata = pubkey_get_nenc (k->pubkey_algo);
|
|
|
|
if (!ndata)
|
|
|
|
{
|
|
|
|
if (list_mode)
|
2010-03-15 12:15:45 +01:00
|
|
|
es_fprintf (listfp, "\tunsupported algorithm %d\n", k->pubkey_algo);
|
2009-10-02 11:15:10 +02:00
|
|
|
unknown_pubkey_warning (k->pubkey_algo);
|
|
|
|
k->data[0] = NULL; /* No need to store the encrypted data. */
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2011-01-31 09:27:06 +01:00
|
|
|
for (i = 0; i < ndata; i++)
|
2011-01-06 02:33:17 +01:00
|
|
|
{
|
2011-01-31 09:27:06 +01:00
|
|
|
if (k->pubkey_algo == PUBKEY_ALGO_ECDH && i == 1)
|
2011-01-21 12:00:57 +01:00
|
|
|
{
|
2011-06-01 21:43:30 +02:00
|
|
|
size_t n;
|
|
|
|
rc = read_size_body (inp, pktlen, &n, k->data+i);
|
2011-01-31 09:27:06 +01:00
|
|
|
pktlen -= n;
|
2011-01-21 12:00:57 +01:00
|
|
|
}
|
2011-01-31 09:27:06 +01:00
|
|
|
else
|
2011-01-21 12:00:57 +01:00
|
|
|
{
|
2011-06-01 21:43:30 +02:00
|
|
|
int n = pktlen;
|
2011-01-21 12:00:57 +01:00
|
|
|
k->data[i] = mpi_read (inp, &n, 0);
|
|
|
|
pktlen -= n;
|
|
|
|
if (!k->data[i])
|
|
|
|
rc = gpg_error (GPG_ERR_INV_PACKET);
|
|
|
|
}
|
2011-01-31 09:27:06 +01:00
|
|
|
if (rc)
|
|
|
|
goto leave;
|
|
|
|
if (list_mode)
|
|
|
|
{
|
|
|
|
es_fprintf (listfp, "\tdata: ");
|
|
|
|
mpi_print (listfp, k->data[i], mpi_print_mode);
|
|
|
|
es_putc ('\n', listfp);
|
|
|
|
}
|
2011-01-21 12:00:57 +01:00
|
|
|
}
|
2003-06-05 09:14:21 +02:00
|
|
|
}
|
|
|
|
|
2009-10-02 11:15:10 +02:00
|
|
|
leave:
|
|
|
|
iobuf_skip_rest (inp, pktlen, 0);
|
|
|
|
return rc;
|
2003-06-05 09:14:21 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static void
|
2009-10-02 11:15:10 +02:00
|
|
|
dump_sig_subpkt (int hashed, int type, int critical,
|
|
|
|
const byte * buffer, size_t buflen, size_t length)
|
2003-06-05 09:14:21 +02:00
|
|
|
{
|
2009-10-02 11:15:10 +02:00
|
|
|
const char *p = NULL;
|
|
|
|
int i;
|
|
|
|
|
|
|
|
/* The CERT has warning out with explains how to use GNUPG to detect
|
|
|
|
* the ARRs - we print our old message here when it is a faked ARR
|
|
|
|
* and add an additional notice. */
|
|
|
|
if (type == SIGSUBPKT_ARR && !hashed)
|
|
|
|
{
|
2010-03-15 12:15:45 +01:00
|
|
|
es_fprintf (listfp,
|
|
|
|
"\tsubpkt %d len %u (additional recipient request)\n"
|
|
|
|
"WARNING: PGP versions > 5.0 and < 6.5.8 will automagically "
|
|
|
|
"encrypt to this key and thereby reveal the plaintext to "
|
|
|
|
"the owner of this ARR key. Detailed info follows:\n",
|
|
|
|
type, (unsigned) length);
|
2009-10-02 11:15:10 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
buffer++;
|
|
|
|
length--;
|
|
|
|
|
2010-03-15 12:15:45 +01:00
|
|
|
es_fprintf (listfp, "\t%s%ssubpkt %d len %u (", /*) */
|
|
|
|
critical ? "critical " : "",
|
|
|
|
hashed ? "hashed " : "", type, (unsigned) length);
|
2009-10-02 11:15:10 +02:00
|
|
|
if (length > buflen)
|
|
|
|
{
|
2010-03-15 12:15:45 +01:00
|
|
|
es_fprintf (listfp, "too short: buffer is only %u)\n", (unsigned) buflen);
|
2009-10-02 11:15:10 +02:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
switch (type)
|
|
|
|
{
|
|
|
|
case SIGSUBPKT_SIG_CREATED:
|
|
|
|
if (length >= 4)
|
2010-03-15 12:15:45 +01:00
|
|
|
es_fprintf (listfp, "sig created %s",
|
|
|
|
strtimestamp (buffer_to_u32 (buffer)));
|
2009-10-02 11:15:10 +02:00
|
|
|
break;
|
|
|
|
case SIGSUBPKT_SIG_EXPIRE:
|
|
|
|
if (length >= 4)
|
|
|
|
{
|
|
|
|
if (buffer_to_u32 (buffer))
|
2010-03-15 12:15:45 +01:00
|
|
|
es_fprintf (listfp, "sig expires after %s",
|
|
|
|
strtimevalue (buffer_to_u32 (buffer)));
|
2009-10-02 11:15:10 +02:00
|
|
|
else
|
2010-03-15 12:15:45 +01:00
|
|
|
es_fprintf (listfp, "sig does not expire");
|
2009-10-02 11:15:10 +02:00
|
|
|
}
|
|
|
|
break;
|
|
|
|
case SIGSUBPKT_EXPORTABLE:
|
|
|
|
if (length)
|
2010-03-15 12:15:45 +01:00
|
|
|
es_fprintf (listfp, "%sexportable", *buffer ? "" : "not ");
|
2009-10-02 11:15:10 +02:00
|
|
|
break;
|
|
|
|
case SIGSUBPKT_TRUST:
|
|
|
|
if (length != 2)
|
|
|
|
p = "[invalid trust subpacket]";
|
|
|
|
else
|
2010-03-15 12:15:45 +01:00
|
|
|
es_fprintf (listfp, "trust signature of depth %d, value %d", buffer[0],
|
|
|
|
buffer[1]);
|
2009-10-02 11:15:10 +02:00
|
|
|
break;
|
|
|
|
case SIGSUBPKT_REGEXP:
|
|
|
|
if (!length)
|
|
|
|
p = "[invalid regexp subpacket]";
|
|
|
|
else
|
2010-03-15 12:15:45 +01:00
|
|
|
es_fprintf (listfp, "regular expression: \"%s\"", buffer);
|
2009-10-02 11:15:10 +02:00
|
|
|
break;
|
|
|
|
case SIGSUBPKT_REVOCABLE:
|
|
|
|
if (length)
|
2010-03-15 12:15:45 +01:00
|
|
|
es_fprintf (listfp, "%srevocable", *buffer ? "" : "not ");
|
2009-10-02 11:15:10 +02:00
|
|
|
break;
|
|
|
|
case SIGSUBPKT_KEY_EXPIRE:
|
|
|
|
if (length >= 4)
|
|
|
|
{
|
|
|
|
if (buffer_to_u32 (buffer))
|
2010-03-15 12:15:45 +01:00
|
|
|
es_fprintf (listfp, "key expires after %s",
|
|
|
|
strtimevalue (buffer_to_u32 (buffer)));
|
2009-10-02 11:15:10 +02:00
|
|
|
else
|
2010-03-15 12:15:45 +01:00
|
|
|
es_fprintf (listfp, "key does not expire");
|
2009-10-02 11:15:10 +02:00
|
|
|
}
|
|
|
|
break;
|
|
|
|
case SIGSUBPKT_PREF_SYM:
|
2010-03-15 12:15:45 +01:00
|
|
|
es_fputs ("pref-sym-algos:", listfp);
|
2009-10-02 11:15:10 +02:00
|
|
|
for (i = 0; i < length; i++)
|
2010-03-15 12:15:45 +01:00
|
|
|
es_fprintf (listfp, " %d", buffer[i]);
|
2009-10-02 11:15:10 +02:00
|
|
|
break;
|
|
|
|
case SIGSUBPKT_REV_KEY:
|
2010-03-15 12:15:45 +01:00
|
|
|
es_fputs ("revocation key: ", listfp);
|
2009-10-02 11:15:10 +02:00
|
|
|
if (length < 22)
|
|
|
|
p = "[too short]";
|
|
|
|
else
|
|
|
|
{
|
2010-03-15 12:15:45 +01:00
|
|
|
es_fprintf (listfp, "c=%02x a=%d f=", buffer[0], buffer[1]);
|
2009-10-02 11:15:10 +02:00
|
|
|
for (i = 2; i < length; i++)
|
2010-03-15 12:15:45 +01:00
|
|
|
es_fprintf (listfp, "%02X", buffer[i]);
|
2009-10-02 11:15:10 +02:00
|
|
|
}
|
|
|
|
break;
|
|
|
|
case SIGSUBPKT_ISSUER:
|
|
|
|
if (length >= 8)
|
2010-03-15 12:15:45 +01:00
|
|
|
es_fprintf (listfp, "issuer key ID %08lX%08lX",
|
|
|
|
(ulong) buffer_to_u32 (buffer),
|
|
|
|
(ulong) buffer_to_u32 (buffer + 4));
|
2009-10-02 11:15:10 +02:00
|
|
|
break;
|
|
|
|
case SIGSUBPKT_NOTATION:
|
|
|
|
{
|
2010-03-15 12:15:45 +01:00
|
|
|
es_fputs ("notation: ", listfp);
|
2009-10-02 11:15:10 +02:00
|
|
|
if (length < 8)
|
|
|
|
p = "[too short]";
|
2003-06-05 09:14:21 +02:00
|
|
|
else
|
2006-06-27 16:30:59 +02:00
|
|
|
{
|
2009-10-02 11:15:10 +02:00
|
|
|
const byte *s = buffer;
|
|
|
|
size_t n1, n2;
|
|
|
|
|
|
|
|
n1 = (s[4] << 8) | s[5];
|
|
|
|
n2 = (s[6] << 8) | s[7];
|
|
|
|
s += 8;
|
|
|
|
if (8 + n1 + n2 != length)
|
|
|
|
p = "[error]";
|
2006-06-27 16:30:59 +02:00
|
|
|
else
|
2009-10-02 11:15:10 +02:00
|
|
|
{
|
2010-03-15 12:15:45 +01:00
|
|
|
es_write_sanitized (listfp, s, n1, ")", NULL);
|
|
|
|
es_putc ('=', listfp);
|
2009-10-02 11:15:10 +02:00
|
|
|
|
|
|
|
if (*buffer & 0x80)
|
2010-03-15 12:15:45 +01:00
|
|
|
es_write_sanitized (listfp, s + n1, n2, ")", NULL);
|
2009-10-02 11:15:10 +02:00
|
|
|
else
|
|
|
|
p = "[not human readable]";
|
|
|
|
}
|
2006-06-27 16:30:59 +02:00
|
|
|
}
|
2009-10-02 11:15:10 +02:00
|
|
|
}
|
|
|
|
break;
|
|
|
|
case SIGSUBPKT_PREF_HASH:
|
2010-03-15 12:15:45 +01:00
|
|
|
es_fputs ("pref-hash-algos:", listfp);
|
2009-10-02 11:15:10 +02:00
|
|
|
for (i = 0; i < length; i++)
|
2010-03-15 12:15:45 +01:00
|
|
|
es_fprintf (listfp, " %d", buffer[i]);
|
2009-10-02 11:15:10 +02:00
|
|
|
break;
|
|
|
|
case SIGSUBPKT_PREF_COMPR:
|
2010-03-15 12:15:45 +01:00
|
|
|
es_fputs ("pref-zip-algos:", listfp);
|
2009-10-02 11:15:10 +02:00
|
|
|
for (i = 0; i < length; i++)
|
2010-03-15 12:15:45 +01:00
|
|
|
es_fprintf (listfp, " %d", buffer[i]);
|
2009-10-02 11:15:10 +02:00
|
|
|
break;
|
|
|
|
case SIGSUBPKT_KS_FLAGS:
|
2010-03-15 12:15:45 +01:00
|
|
|
es_fputs ("key server preferences:", listfp);
|
2009-10-02 11:15:10 +02:00
|
|
|
for (i = 0; i < length; i++)
|
2010-03-15 12:15:45 +01:00
|
|
|
es_fprintf (listfp, " %02X", buffer[i]);
|
2009-10-02 11:15:10 +02:00
|
|
|
break;
|
|
|
|
case SIGSUBPKT_PREF_KS:
|
2010-03-15 12:15:45 +01:00
|
|
|
es_fputs ("preferred key server: ", listfp);
|
|
|
|
es_write_sanitized (listfp, buffer, length, ")", NULL);
|
2009-10-02 11:15:10 +02:00
|
|
|
break;
|
|
|
|
case SIGSUBPKT_PRIMARY_UID:
|
|
|
|
p = "primary user ID";
|
|
|
|
break;
|
|
|
|
case SIGSUBPKT_POLICY:
|
2010-03-15 12:15:45 +01:00
|
|
|
es_fputs ("policy: ", listfp);
|
|
|
|
es_write_sanitized (listfp, buffer, length, ")", NULL);
|
2009-10-02 11:15:10 +02:00
|
|
|
break;
|
|
|
|
case SIGSUBPKT_KEY_FLAGS:
|
2010-03-15 12:15:45 +01:00
|
|
|
es_fputs ("key flags:", listfp);
|
2009-10-02 11:15:10 +02:00
|
|
|
for (i = 0; i < length; i++)
|
2010-03-15 12:15:45 +01:00
|
|
|
es_fprintf (listfp, " %02X", buffer[i]);
|
2009-10-02 11:15:10 +02:00
|
|
|
break;
|
|
|
|
case SIGSUBPKT_SIGNERS_UID:
|
|
|
|
p = "signer's user ID";
|
|
|
|
break;
|
|
|
|
case SIGSUBPKT_REVOC_REASON:
|
|
|
|
if (length)
|
2003-06-05 09:14:21 +02:00
|
|
|
{
|
2010-03-15 12:15:45 +01:00
|
|
|
es_fprintf (listfp, "revocation reason 0x%02x (", *buffer);
|
|
|
|
es_write_sanitized (listfp, buffer + 1, length - 1, ")", NULL);
|
2009-10-02 11:15:10 +02:00
|
|
|
p = ")";
|
2003-06-05 09:14:21 +02:00
|
|
|
}
|
2009-10-02 11:15:10 +02:00
|
|
|
break;
|
|
|
|
case SIGSUBPKT_ARR:
|
2010-03-15 12:15:45 +01:00
|
|
|
es_fputs ("Big Brother's key (ignored): ", listfp);
|
2009-10-02 11:15:10 +02:00
|
|
|
if (length < 22)
|
|
|
|
p = "[too short]";
|
|
|
|
else
|
|
|
|
{
|
2010-03-15 12:15:45 +01:00
|
|
|
es_fprintf (listfp, "c=%02x a=%d f=", buffer[0], buffer[1]);
|
|
|
|
if (length > 2)
|
|
|
|
es_write_hexstring (listfp, buffer+2, length-2, 0, NULL);
|
2003-06-05 09:14:21 +02:00
|
|
|
}
|
2009-10-02 11:15:10 +02:00
|
|
|
break;
|
|
|
|
case SIGSUBPKT_FEATURES:
|
2010-03-15 12:15:45 +01:00
|
|
|
es_fputs ("features:", listfp);
|
2009-10-02 11:15:10 +02:00
|
|
|
for (i = 0; i < length; i++)
|
2010-03-15 12:15:45 +01:00
|
|
|
es_fprintf (listfp, " %02x", buffer[i]);
|
2009-10-02 11:15:10 +02:00
|
|
|
break;
|
|
|
|
case SIGSUBPKT_SIGNATURE:
|
2010-03-15 12:15:45 +01:00
|
|
|
es_fputs ("signature: ", listfp);
|
2009-10-02 11:15:10 +02:00
|
|
|
if (length < 17)
|
|
|
|
p = "[too short]";
|
|
|
|
else
|
2010-03-15 12:15:45 +01:00
|
|
|
es_fprintf (listfp, "v%d, class 0x%02X, algo %d, digest algo %d",
|
|
|
|
buffer[0],
|
|
|
|
buffer[0] == 3 ? buffer[2] : buffer[1],
|
|
|
|
buffer[0] == 3 ? buffer[15] : buffer[2],
|
|
|
|
buffer[0] == 3 ? buffer[16] : buffer[3]);
|
2009-10-02 11:15:10 +02:00
|
|
|
break;
|
|
|
|
default:
|
|
|
|
if (type >= 100 && type <= 110)
|
|
|
|
p = "experimental / private subpacket";
|
|
|
|
else
|
|
|
|
p = "?";
|
|
|
|
break;
|
2003-06-05 09:14:21 +02:00
|
|
|
}
|
|
|
|
|
2010-03-15 12:15:45 +01:00
|
|
|
es_fprintf (listfp, "%s)\n", p ? p : "");
|
2003-06-05 09:14:21 +02:00
|
|
|
}
|
|
|
|
|
2009-10-02 11:15:10 +02:00
|
|
|
|
|
|
|
/*
|
2006-04-19 13:26:11 +02:00
|
|
|
* Returns: >= 0 use this offset into buffer
|
|
|
|
* -1 explicitly reject returning this type
|
|
|
|
* -2 subpacket too short
|
2003-06-05 09:14:21 +02:00
|
|
|
*/
|
|
|
|
int
|
2009-10-02 11:15:10 +02:00
|
|
|
parse_one_sig_subpkt (const byte * buffer, size_t n, int type)
|
2003-06-05 09:14:21 +02:00
|
|
|
{
|
2009-10-02 11:15:10 +02:00
|
|
|
switch (type)
|
2006-04-19 13:26:11 +02:00
|
|
|
{
|
|
|
|
case SIGSUBPKT_REV_KEY:
|
2009-10-02 11:15:10 +02:00
|
|
|
if (n < 22)
|
2006-04-19 13:26:11 +02:00
|
|
|
break;
|
|
|
|
return 0;
|
|
|
|
case SIGSUBPKT_SIG_CREATED:
|
|
|
|
case SIGSUBPKT_SIG_EXPIRE:
|
|
|
|
case SIGSUBPKT_KEY_EXPIRE:
|
2009-10-02 11:15:10 +02:00
|
|
|
if (n < 4)
|
2006-04-19 13:26:11 +02:00
|
|
|
break;
|
|
|
|
return 0;
|
|
|
|
case SIGSUBPKT_KEY_FLAGS:
|
|
|
|
case SIGSUBPKT_KS_FLAGS:
|
|
|
|
case SIGSUBPKT_PREF_SYM:
|
|
|
|
case SIGSUBPKT_PREF_HASH:
|
|
|
|
case SIGSUBPKT_PREF_COMPR:
|
|
|
|
case SIGSUBPKT_POLICY:
|
|
|
|
case SIGSUBPKT_PREF_KS:
|
|
|
|
case SIGSUBPKT_FEATURES:
|
|
|
|
case SIGSUBPKT_REGEXP:
|
|
|
|
return 0;
|
|
|
|
case SIGSUBPKT_SIGNATURE:
|
|
|
|
case SIGSUBPKT_EXPORTABLE:
|
|
|
|
case SIGSUBPKT_REVOCABLE:
|
|
|
|
case SIGSUBPKT_REVOC_REASON:
|
2009-10-02 11:15:10 +02:00
|
|
|
if (!n)
|
2006-04-19 13:26:11 +02:00
|
|
|
break;
|
|
|
|
return 0;
|
2009-10-02 11:15:10 +02:00
|
|
|
case SIGSUBPKT_ISSUER: /* issuer key ID */
|
|
|
|
if (n < 8)
|
2006-04-19 13:26:11 +02:00
|
|
|
break;
|
|
|
|
return 0;
|
|
|
|
case SIGSUBPKT_NOTATION:
|
|
|
|
/* minimum length needed, and the subpacket must be well-formed
|
2009-10-02 11:15:10 +02:00
|
|
|
where the name length and value length all fit inside the
|
|
|
|
packet. */
|
|
|
|
if (n < 8
|
|
|
|
|| 8 + ((buffer[4] << 8) | buffer[5]) +
|
|
|
|
((buffer[6] << 8) | buffer[7]) != n)
|
2006-04-19 13:26:11 +02:00
|
|
|
break;
|
|
|
|
return 0;
|
|
|
|
case SIGSUBPKT_PRIMARY_UID:
|
2009-10-02 11:15:10 +02:00
|
|
|
if (n != 1)
|
2006-04-19 13:26:11 +02:00
|
|
|
break;
|
|
|
|
return 0;
|
|
|
|
case SIGSUBPKT_TRUST:
|
2009-10-02 11:15:10 +02:00
|
|
|
if (n != 2)
|
2006-04-19 13:26:11 +02:00
|
|
|
break;
|
|
|
|
return 0;
|
2009-10-02 11:15:10 +02:00
|
|
|
default:
|
|
|
|
return 0;
|
2003-06-05 09:14:21 +02:00
|
|
|
}
|
2006-04-19 13:26:11 +02:00
|
|
|
return -2;
|
2003-06-05 09:14:21 +02:00
|
|
|
}
|
|
|
|
|
2009-10-02 11:15:10 +02:00
|
|
|
|
|
|
|
/* Return true if we understand the critical notation. */
|
2003-06-05 09:14:21 +02:00
|
|
|
static int
|
2009-10-02 11:15:10 +02:00
|
|
|
can_handle_critical_notation (const byte * name, size_t len)
|
2003-06-05 09:14:21 +02:00
|
|
|
{
|
2009-10-02 11:15:10 +02:00
|
|
|
if (len == 32 && memcmp (name, "preferred-email-encoding@pgp.com", 32) == 0)
|
2006-04-19 13:26:11 +02:00
|
|
|
return 1;
|
2009-10-02 11:15:10 +02:00
|
|
|
if (len == 21 && memcmp (name, "pka-address@gnupg.org", 21) == 0)
|
2006-04-19 13:26:11 +02:00
|
|
|
return 1;
|
2003-06-05 09:14:21 +02:00
|
|
|
|
2006-04-19 13:26:11 +02:00
|
|
|
return 0;
|
|
|
|
}
|
2003-06-05 09:14:21 +02:00
|
|
|
|
2009-10-02 11:15:10 +02:00
|
|
|
|
2006-04-19 13:26:11 +02:00
|
|
|
static int
|
2009-10-02 11:15:10 +02:00
|
|
|
can_handle_critical (const byte * buffer, size_t n, int type)
|
2006-04-19 13:26:11 +02:00
|
|
|
{
|
2009-10-02 11:15:10 +02:00
|
|
|
switch (type)
|
2006-04-19 13:26:11 +02:00
|
|
|
{
|
|
|
|
case SIGSUBPKT_NOTATION:
|
2009-10-02 11:15:10 +02:00
|
|
|
if (n >= 8)
|
|
|
|
return can_handle_critical_notation (buffer + 8,
|
|
|
|
(buffer[4] << 8) | buffer[5]);
|
2006-04-19 13:26:11 +02:00
|
|
|
else
|
2003-06-05 09:14:21 +02:00
|
|
|
return 0;
|
2006-04-19 13:26:11 +02:00
|
|
|
case SIGSUBPKT_SIGNATURE:
|
|
|
|
case SIGSUBPKT_SIG_CREATED:
|
|
|
|
case SIGSUBPKT_SIG_EXPIRE:
|
|
|
|
case SIGSUBPKT_KEY_EXPIRE:
|
|
|
|
case SIGSUBPKT_EXPORTABLE:
|
|
|
|
case SIGSUBPKT_REVOCABLE:
|
|
|
|
case SIGSUBPKT_REV_KEY:
|
2009-10-02 11:15:10 +02:00
|
|
|
case SIGSUBPKT_ISSUER: /* issuer key ID */
|
2006-04-19 13:26:11 +02:00
|
|
|
case SIGSUBPKT_PREF_SYM:
|
|
|
|
case SIGSUBPKT_PREF_HASH:
|
|
|
|
case SIGSUBPKT_PREF_COMPR:
|
|
|
|
case SIGSUBPKT_KEY_FLAGS:
|
|
|
|
case SIGSUBPKT_PRIMARY_UID:
|
|
|
|
case SIGSUBPKT_FEATURES:
|
|
|
|
case SIGSUBPKT_TRUST:
|
|
|
|
case SIGSUBPKT_REGEXP:
|
|
|
|
/* Is it enough to show the policy or keyserver? */
|
|
|
|
case SIGSUBPKT_POLICY:
|
|
|
|
case SIGSUBPKT_PREF_KS:
|
|
|
|
return 1;
|
|
|
|
|
|
|
|
default:
|
|
|
|
return 0;
|
2003-06-05 09:14:21 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
const byte *
|
2009-10-02 11:15:10 +02:00
|
|
|
enum_sig_subpkt (const subpktarea_t * pktbuf, sigsubpkttype_t reqtype,
|
|
|
|
size_t * ret_n, int *start, int *critical)
|
2003-06-05 09:14:21 +02:00
|
|
|
{
|
2009-10-02 11:15:10 +02:00
|
|
|
const byte *buffer;
|
|
|
|
int buflen;
|
|
|
|
int type;
|
|
|
|
int critical_dummy;
|
|
|
|
int offset;
|
|
|
|
size_t n;
|
|
|
|
int seq = 0;
|
|
|
|
int reqseq = start ? *start : 0;
|
|
|
|
|
|
|
|
if (!critical)
|
|
|
|
critical = &critical_dummy;
|
|
|
|
|
|
|
|
if (!pktbuf || reqseq == -1)
|
|
|
|
{
|
|
|
|
/* return some value different from NULL to indicate that
|
|
|
|
* there is no critical bit we do not understand. The caller
|
|
|
|
* will never use the value. Yes I know, it is an ugly hack */
|
|
|
|
return reqtype ==
|
|
|
|
SIGSUBPKT_TEST_CRITICAL ? (const byte *) &pktbuf : NULL;
|
|
|
|
}
|
|
|
|
buffer = pktbuf->data;
|
|
|
|
buflen = pktbuf->len;
|
|
|
|
while (buflen)
|
|
|
|
{
|
|
|
|
n = *buffer++;
|
|
|
|
buflen--;
|
|
|
|
if (n == 255) /* 4 byte length header. */
|
2011-02-04 12:57:53 +01:00
|
|
|
{
|
2009-10-02 11:15:10 +02:00
|
|
|
if (buflen < 4)
|
|
|
|
goto too_short;
|
|
|
|
n = (buffer[0] << 24) | (buffer[1] << 16)
|
|
|
|
| (buffer[2] << 8) | buffer[3];
|
|
|
|
buffer += 4;
|
|
|
|
buflen -= 4;
|
2003-06-05 09:14:21 +02:00
|
|
|
}
|
2009-10-02 11:15:10 +02:00
|
|
|
else if (n >= 192) /* 4 byte special encoded length header. */
|
2011-02-04 12:57:53 +01:00
|
|
|
{
|
2009-10-02 11:15:10 +02:00
|
|
|
if (buflen < 2)
|
2003-06-05 09:14:21 +02:00
|
|
|
goto too_short;
|
2009-10-02 11:15:10 +02:00
|
|
|
n = ((n - 192) << 8) + *buffer + 192;
|
|
|
|
buffer++;
|
|
|
|
buflen--;
|
2003-06-05 09:14:21 +02:00
|
|
|
}
|
2009-10-02 11:15:10 +02:00
|
|
|
if (buflen < n)
|
|
|
|
goto too_short;
|
|
|
|
type = *buffer;
|
|
|
|
if (type & 0x80)
|
|
|
|
{
|
|
|
|
type &= 0x7f;
|
|
|
|
*critical = 1;
|
2003-06-05 09:14:21 +02:00
|
|
|
}
|
2009-10-02 11:15:10 +02:00
|
|
|
else
|
|
|
|
*critical = 0;
|
|
|
|
if (!(++seq > reqseq))
|
|
|
|
;
|
|
|
|
else if (reqtype == SIGSUBPKT_TEST_CRITICAL)
|
|
|
|
{
|
|
|
|
if (*critical)
|
|
|
|
{
|
|
|
|
if (n - 1 > buflen + 1)
|
2003-06-05 09:14:21 +02:00
|
|
|
goto too_short;
|
2009-10-02 11:15:10 +02:00
|
|
|
if (!can_handle_critical (buffer + 1, n - 1, type))
|
|
|
|
{
|
|
|
|
if (opt.verbose)
|
|
|
|
log_info (_("subpacket of type %d has "
|
|
|
|
"critical bit set\n"), type);
|
|
|
|
if (start)
|
|
|
|
*start = seq;
|
|
|
|
return NULL; /* This is an error. */
|
|
|
|
}
|
2003-06-05 09:14:21 +02:00
|
|
|
}
|
|
|
|
}
|
2009-10-02 11:15:10 +02:00
|
|
|
else if (reqtype < 0) /* List packets. */
|
|
|
|
dump_sig_subpkt (reqtype == SIGSUBPKT_LIST_HASHED,
|
|
|
|
type, *critical, buffer, buflen, n);
|
|
|
|
else if (type == reqtype) /* Found. */
|
|
|
|
{
|
|
|
|
buffer++;
|
|
|
|
n--;
|
|
|
|
if (n > buflen)
|
|
|
|
goto too_short;
|
|
|
|
if (ret_n)
|
|
|
|
*ret_n = n;
|
|
|
|
offset = parse_one_sig_subpkt (buffer, n, type);
|
|
|
|
switch (offset)
|
|
|
|
{
|
|
|
|
case -2:
|
|
|
|
log_error ("subpacket of type %d too short\n", type);
|
|
|
|
return NULL;
|
|
|
|
case -1:
|
|
|
|
return NULL;
|
|
|
|
default:
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
if (start)
|
|
|
|
*start = seq;
|
|
|
|
return buffer + offset;
|
|
|
|
}
|
|
|
|
buffer += n;
|
|
|
|
buflen -= n;
|
|
|
|
}
|
|
|
|
if (reqtype == SIGSUBPKT_TEST_CRITICAL)
|
|
|
|
return buffer; /* Used as True to indicate that there is no. */
|
|
|
|
|
|
|
|
/* Critical bit we don't understand. */
|
|
|
|
if (start)
|
|
|
|
*start = -1;
|
|
|
|
return NULL; /* End of packets; not found. */
|
|
|
|
|
|
|
|
too_short:
|
|
|
|
if (opt.verbose)
|
|
|
|
log_info ("buffer shorter than subpacket\n");
|
|
|
|
if (start)
|
|
|
|
*start = -1;
|
|
|
|
return NULL;
|
2003-06-05 09:14:21 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
const byte *
|
2009-10-02 11:15:10 +02:00
|
|
|
parse_sig_subpkt (const subpktarea_t * buffer, sigsubpkttype_t reqtype,
|
|
|
|
size_t * ret_n)
|
2003-06-05 09:14:21 +02:00
|
|
|
{
|
2009-10-02 11:15:10 +02:00
|
|
|
return enum_sig_subpkt (buffer, reqtype, ret_n, NULL, NULL);
|
2003-06-05 09:14:21 +02:00
|
|
|
}
|
|
|
|
|
2009-10-02 11:15:10 +02:00
|
|
|
|
2003-06-05 09:14:21 +02:00
|
|
|
const byte *
|
2009-10-02 11:15:10 +02:00
|
|
|
parse_sig_subpkt2 (PKT_signature * sig, sigsubpkttype_t reqtype,
|
|
|
|
size_t * ret_n)
|
2003-06-05 09:14:21 +02:00
|
|
|
{
|
2009-10-02 11:15:10 +02:00
|
|
|
const byte *p;
|
2003-06-05 09:14:21 +02:00
|
|
|
|
2009-10-02 11:15:10 +02:00
|
|
|
p = parse_sig_subpkt (sig->hashed, reqtype, ret_n);
|
|
|
|
if (!p)
|
|
|
|
p = parse_sig_subpkt (sig->unhashed, reqtype, ret_n);
|
|
|
|
return p;
|
2003-06-05 09:14:21 +02:00
|
|
|
}
|
|
|
|
|
2009-10-02 11:15:10 +02:00
|
|
|
|
|
|
|
/* Find all revocation keys. Look in hashed area only. */
|
|
|
|
void
|
|
|
|
parse_revkeys (PKT_signature * sig)
|
2003-06-05 09:14:21 +02:00
|
|
|
{
|
|
|
|
struct revocation_key *revkey;
|
2009-10-02 11:15:10 +02:00
|
|
|
int seq = 0;
|
2003-06-05 09:14:21 +02:00
|
|
|
size_t len;
|
|
|
|
|
2009-10-02 11:15:10 +02:00
|
|
|
if (sig->sig_class != 0x1F)
|
2003-06-05 09:14:21 +02:00
|
|
|
return;
|
|
|
|
|
2009-10-02 11:15:10 +02:00
|
|
|
while ((revkey =
|
|
|
|
(struct revocation_key *) enum_sig_subpkt (sig->hashed,
|
|
|
|
SIGSUBPKT_REV_KEY,
|
|
|
|
&len, &seq, NULL)))
|
2003-06-05 09:14:21 +02:00
|
|
|
{
|
2011-02-04 12:57:53 +01:00
|
|
|
if (len == sizeof (struct revocation_key)
|
2009-10-02 11:15:10 +02:00
|
|
|
&& (revkey->class & 0x80)) /* 0x80 bit must be set. */
|
2003-06-05 09:14:21 +02:00
|
|
|
{
|
2009-10-02 11:15:10 +02:00
|
|
|
sig->revkey = xrealloc (sig->revkey,
|
|
|
|
sizeof (struct revocation_key *) *
|
|
|
|
(sig->numrevkeys + 1));
|
|
|
|
sig->revkey[sig->numrevkeys] = revkey;
|
2003-06-05 09:14:21 +02:00
|
|
|
sig->numrevkeys++;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2009-10-02 11:15:10 +02:00
|
|
|
|
2006-04-19 13:26:11 +02:00
|
|
|
int
|
2009-10-02 11:15:10 +02:00
|
|
|
parse_signature (IOBUF inp, int pkttype, unsigned long pktlen,
|
|
|
|
PKT_signature * sig)
|
2003-06-05 09:14:21 +02:00
|
|
|
{
|
2009-10-02 11:15:10 +02:00
|
|
|
int md5_len = 0;
|
|
|
|
unsigned n;
|
|
|
|
int is_v4 = 0;
|
|
|
|
int rc = 0;
|
|
|
|
int i, ndata;
|
|
|
|
|
|
|
|
if (pktlen < 16)
|
|
|
|
{
|
|
|
|
log_error ("packet(%d) too short\n", pkttype);
|
|
|
|
goto leave;
|
2003-06-05 09:14:21 +02:00
|
|
|
}
|
2009-10-02 11:15:10 +02:00
|
|
|
sig->version = iobuf_get_noeof (inp);
|
|
|
|
pktlen--;
|
|
|
|
if (sig->version == 4)
|
|
|
|
is_v4 = 1;
|
|
|
|
else if (sig->version != 2 && sig->version != 3)
|
|
|
|
{
|
|
|
|
log_error ("packet(%d) with unknown version %d\n",
|
|
|
|
pkttype, sig->version);
|
|
|
|
rc = gpg_error (GPG_ERR_INV_PACKET);
|
|
|
|
goto leave;
|
2003-06-05 09:14:21 +02:00
|
|
|
}
|
|
|
|
|
2009-10-02 11:15:10 +02:00
|
|
|
if (!is_v4)
|
|
|
|
{
|
|
|
|
md5_len = iobuf_get_noeof (inp);
|
|
|
|
pktlen--;
|
2003-06-05 09:14:21 +02:00
|
|
|
}
|
2009-10-02 11:15:10 +02:00
|
|
|
sig->sig_class = iobuf_get_noeof (inp);
|
|
|
|
pktlen--;
|
|
|
|
if (!is_v4)
|
|
|
|
{
|
|
|
|
sig->timestamp = read_32 (inp);
|
|
|
|
pktlen -= 4;
|
|
|
|
sig->keyid[0] = read_32 (inp);
|
|
|
|
pktlen -= 4;
|
|
|
|
sig->keyid[1] = read_32 (inp);
|
|
|
|
pktlen -= 4;
|
|
|
|
}
|
|
|
|
sig->pubkey_algo = iobuf_get_noeof (inp);
|
|
|
|
pktlen--;
|
|
|
|
sig->digest_algo = iobuf_get_noeof (inp);
|
|
|
|
pktlen--;
|
|
|
|
sig->flags.exportable = 1;
|
|
|
|
sig->flags.revocable = 1;
|
|
|
|
if (is_v4) /* Read subpackets. */
|
2011-02-04 12:57:53 +01:00
|
|
|
{
|
2009-10-02 11:15:10 +02:00
|
|
|
n = read_16 (inp);
|
|
|
|
pktlen -= 2; /* Length of hashed data. */
|
|
|
|
if (n > 10000)
|
|
|
|
{
|
|
|
|
log_error ("signature packet: hashed data too long\n");
|
|
|
|
rc = G10ERR_INVALID_PACKET;
|
|
|
|
goto leave;
|
2003-06-05 09:14:21 +02:00
|
|
|
}
|
2009-10-02 11:15:10 +02:00
|
|
|
if (n)
|
|
|
|
{
|
|
|
|
sig->hashed = xmalloc (sizeof (*sig->hashed) + n - 1);
|
|
|
|
sig->hashed->size = n;
|
|
|
|
sig->hashed->len = n;
|
|
|
|
if (iobuf_read (inp, sig->hashed->data, n) != n)
|
|
|
|
{
|
|
|
|
log_error ("premature eof while reading "
|
|
|
|
"hashed signature data\n");
|
|
|
|
rc = -1;
|
|
|
|
goto leave;
|
2003-06-05 09:14:21 +02:00
|
|
|
}
|
2009-10-02 11:15:10 +02:00
|
|
|
pktlen -= n;
|
2003-06-05 09:14:21 +02:00
|
|
|
}
|
2009-10-02 11:15:10 +02:00
|
|
|
n = read_16 (inp);
|
|
|
|
pktlen -= 2; /* Length of unhashed data. */
|
|
|
|
if (n > 10000)
|
|
|
|
{
|
|
|
|
log_error ("signature packet: unhashed data too long\n");
|
|
|
|
rc = G10ERR_INVALID_PACKET;
|
|
|
|
goto leave;
|
2003-06-05 09:14:21 +02:00
|
|
|
}
|
2009-10-02 11:15:10 +02:00
|
|
|
if (n)
|
|
|
|
{
|
|
|
|
sig->unhashed = xmalloc (sizeof (*sig->unhashed) + n - 1);
|
|
|
|
sig->unhashed->size = n;
|
|
|
|
sig->unhashed->len = n;
|
|
|
|
if (iobuf_read (inp, sig->unhashed->data, n) != n)
|
|
|
|
{
|
|
|
|
log_error ("premature eof while reading "
|
|
|
|
"unhashed signature data\n");
|
|
|
|
rc = -1;
|
|
|
|
goto leave;
|
2003-06-05 09:14:21 +02:00
|
|
|
}
|
2009-10-02 11:15:10 +02:00
|
|
|
pktlen -= n;
|
2003-06-05 09:14:21 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2009-10-02 11:15:10 +02:00
|
|
|
if (pktlen < 5) /* Sanity check. */
|
2011-02-04 12:57:53 +01:00
|
|
|
{
|
2009-10-02 11:15:10 +02:00
|
|
|
log_error ("packet(%d) too short\n", pkttype);
|
|
|
|
rc = G10ERR_INVALID_PACKET;
|
|
|
|
goto leave;
|
2003-06-05 09:14:21 +02:00
|
|
|
}
|
|
|
|
|
2009-10-02 11:15:10 +02:00
|
|
|
sig->digest_start[0] = iobuf_get_noeof (inp);
|
|
|
|
pktlen--;
|
|
|
|
sig->digest_start[1] = iobuf_get_noeof (inp);
|
|
|
|
pktlen--;
|
2003-06-05 09:14:21 +02:00
|
|
|
|
2009-10-02 11:15:10 +02:00
|
|
|
if (is_v4 && sig->pubkey_algo) /* Extract required information. */
|
2011-02-04 12:57:53 +01:00
|
|
|
{
|
2009-10-02 11:15:10 +02:00
|
|
|
const byte *p;
|
|
|
|
size_t len;
|
2003-06-05 09:14:21 +02:00
|
|
|
|
2009-10-02 11:15:10 +02:00
|
|
|
/* Set sig->flags.unknown_critical if there is a critical bit
|
|
|
|
* set for packets which we do not understand. */
|
|
|
|
if (!parse_sig_subpkt (sig->hashed, SIGSUBPKT_TEST_CRITICAL, NULL)
|
|
|
|
|| !parse_sig_subpkt (sig->unhashed, SIGSUBPKT_TEST_CRITICAL, NULL))
|
|
|
|
sig->flags.unknown_critical = 1;
|
2003-06-05 09:14:21 +02:00
|
|
|
|
2009-10-02 11:15:10 +02:00
|
|
|
p = parse_sig_subpkt (sig->hashed, SIGSUBPKT_SIG_CREATED, NULL);
|
|
|
|
if (p)
|
|
|
|
sig->timestamp = buffer_to_u32 (p);
|
|
|
|
else if (!(sig->pubkey_algo >= 100 && sig->pubkey_algo <= 110)
|
|
|
|
&& opt.verbose)
|
|
|
|
log_info ("signature packet without timestamp\n");
|
2003-09-23 19:48:33 +02:00
|
|
|
|
2009-10-02 11:15:10 +02:00
|
|
|
p = parse_sig_subpkt2 (sig, SIGSUBPKT_ISSUER, NULL);
|
|
|
|
if (p)
|
|
|
|
{
|
|
|
|
sig->keyid[0] = buffer_to_u32 (p);
|
|
|
|
sig->keyid[1] = buffer_to_u32 (p + 4);
|
|
|
|
}
|
|
|
|
else if (!(sig->pubkey_algo >= 100 && sig->pubkey_algo <= 110)
|
|
|
|
&& opt.verbose)
|
|
|
|
log_info ("signature packet without keyid\n");
|
|
|
|
|
|
|
|
p = parse_sig_subpkt (sig->hashed, SIGSUBPKT_SIG_EXPIRE, NULL);
|
|
|
|
if (p && buffer_to_u32 (p))
|
|
|
|
sig->expiredate = sig->timestamp + buffer_to_u32 (p);
|
|
|
|
if (sig->expiredate && sig->expiredate <= make_timestamp ())
|
|
|
|
sig->flags.expired = 1;
|
|
|
|
|
|
|
|
p = parse_sig_subpkt (sig->hashed, SIGSUBPKT_POLICY, NULL);
|
|
|
|
if (p)
|
|
|
|
sig->flags.policy_url = 1;
|
|
|
|
|
|
|
|
p = parse_sig_subpkt (sig->hashed, SIGSUBPKT_PREF_KS, NULL);
|
|
|
|
if (p)
|
|
|
|
sig->flags.pref_ks = 1;
|
|
|
|
|
|
|
|
p = parse_sig_subpkt (sig->hashed, SIGSUBPKT_NOTATION, NULL);
|
|
|
|
if (p)
|
|
|
|
sig->flags.notation = 1;
|
|
|
|
|
|
|
|
p = parse_sig_subpkt (sig->hashed, SIGSUBPKT_REVOCABLE, NULL);
|
|
|
|
if (p && *p == 0)
|
|
|
|
sig->flags.revocable = 0;
|
|
|
|
|
|
|
|
p = parse_sig_subpkt (sig->hashed, SIGSUBPKT_TRUST, &len);
|
|
|
|
if (p && len == 2)
|
|
|
|
{
|
|
|
|
sig->trust_depth = p[0];
|
|
|
|
sig->trust_value = p[1];
|
|
|
|
|
|
|
|
/* Only look for a regexp if there is also a trust
|
|
|
|
subpacket. */
|
|
|
|
sig->trust_regexp =
|
|
|
|
parse_sig_subpkt (sig->hashed, SIGSUBPKT_REGEXP, &len);
|
|
|
|
|
|
|
|
/* If the regular expression is of 0 length, there is no
|
|
|
|
regular expression. */
|
|
|
|
if (len == 0)
|
|
|
|
sig->trust_regexp = NULL;
|
|
|
|
}
|
2003-06-05 09:14:21 +02:00
|
|
|
|
2009-10-02 11:15:10 +02:00
|
|
|
/* We accept the exportable subpacket from either the hashed or
|
|
|
|
unhashed areas as older versions of gpg put it in the
|
|
|
|
unhashed area. In theory, anyway, we should never see this
|
|
|
|
packet off of a local keyring. */
|
2003-06-05 09:14:21 +02:00
|
|
|
|
2009-10-02 11:15:10 +02:00
|
|
|
p = parse_sig_subpkt2 (sig, SIGSUBPKT_EXPORTABLE, NULL);
|
|
|
|
if (p && *p == 0)
|
|
|
|
sig->flags.exportable = 0;
|
2003-06-05 09:14:21 +02:00
|
|
|
|
2009-10-02 11:15:10 +02:00
|
|
|
/* Find all revocation keys. */
|
|
|
|
if (sig->sig_class == 0x1F)
|
|
|
|
parse_revkeys (sig);
|
|
|
|
}
|
2003-06-05 09:14:21 +02:00
|
|
|
|
2009-10-02 11:15:10 +02:00
|
|
|
if (list_mode)
|
|
|
|
{
|
2010-03-15 12:15:45 +01:00
|
|
|
es_fprintf (listfp, ":signature packet: algo %d, keyid %08lX%08lX\n"
|
|
|
|
"\tversion %d, created %lu, md5len %d, sigclass 0x%02x\n"
|
|
|
|
"\tdigest algo %d, begin of digest %02x %02x\n",
|
|
|
|
sig->pubkey_algo,
|
|
|
|
(ulong) sig->keyid[0], (ulong) sig->keyid[1],
|
|
|
|
sig->version, (ulong) sig->timestamp, md5_len, sig->sig_class,
|
|
|
|
sig->digest_algo, sig->digest_start[0], sig->digest_start[1]);
|
2009-10-02 11:15:10 +02:00
|
|
|
if (is_v4)
|
|
|
|
{
|
|
|
|
parse_sig_subpkt (sig->hashed, SIGSUBPKT_LIST_HASHED, NULL);
|
|
|
|
parse_sig_subpkt (sig->unhashed, SIGSUBPKT_LIST_UNHASHED, NULL);
|
2003-06-05 09:14:21 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2009-10-02 11:15:10 +02:00
|
|
|
ndata = pubkey_get_nsig (sig->pubkey_algo);
|
|
|
|
if (!ndata)
|
|
|
|
{
|
|
|
|
if (list_mode)
|
2010-03-15 12:15:45 +01:00
|
|
|
es_fprintf (listfp, "\tunknown algorithm %d\n", sig->pubkey_algo);
|
2009-10-02 11:15:10 +02:00
|
|
|
unknown_pubkey_warning (sig->pubkey_algo);
|
|
|
|
|
|
|
|
/* We store the plain material in data[0], so that we are able
|
|
|
|
* to write it back with build_packet(). */
|
|
|
|
if (pktlen > (5 * MAX_EXTERN_MPI_BITS / 8))
|
|
|
|
{
|
|
|
|
/* We include a limit to avoid too trivial DoS attacks by
|
|
|
|
having gpg allocate too much memory. */
|
|
|
|
log_error ("signature packet: too much data\n");
|
|
|
|
rc = G10ERR_INVALID_PACKET;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
sig->data[0] =
|
2011-03-23 10:07:59 +01:00
|
|
|
gcry_mpi_set_opaque (NULL, read_rest (inp, pktlen), pktlen * 8);
|
2009-10-02 11:15:10 +02:00
|
|
|
pktlen = 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
for (i = 0; i < ndata; i++)
|
|
|
|
{
|
|
|
|
n = pktlen;
|
|
|
|
sig->data[i] = mpi_read (inp, &n, 0);
|
|
|
|
pktlen -= n;
|
|
|
|
if (list_mode)
|
|
|
|
{
|
2010-03-15 12:15:45 +01:00
|
|
|
es_fprintf (listfp, "\tdata: ");
|
2009-10-02 11:15:10 +02:00
|
|
|
mpi_print (listfp, sig->data[i], mpi_print_mode);
|
2010-03-15 12:15:45 +01:00
|
|
|
es_putc ('\n', listfp);
|
2003-06-05 09:14:21 +02:00
|
|
|
}
|
2009-10-02 11:15:10 +02:00
|
|
|
if (!sig->data[i])
|
|
|
|
rc = G10ERR_INVALID_PACKET;
|
2003-06-05 09:14:21 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2009-10-02 11:15:10 +02:00
|
|
|
leave:
|
|
|
|
iobuf_skip_rest (inp, pktlen, 0);
|
|
|
|
return rc;
|
2003-06-05 09:14:21 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static int
|
2009-10-02 11:15:10 +02:00
|
|
|
parse_onepass_sig (IOBUF inp, int pkttype, unsigned long pktlen,
|
|
|
|
PKT_onepass_sig * ops)
|
2003-06-05 09:14:21 +02:00
|
|
|
{
|
2009-10-02 11:15:10 +02:00
|
|
|
int version;
|
|
|
|
int rc = 0;
|
2003-06-05 09:14:21 +02:00
|
|
|
|
2009-10-02 11:15:10 +02:00
|
|
|
if (pktlen < 13)
|
|
|
|
{
|
|
|
|
log_error ("packet(%d) too short\n", pkttype);
|
|
|
|
rc = gpg_error (GPG_ERR_INV_PACKET);
|
|
|
|
goto leave;
|
2003-06-05 09:14:21 +02:00
|
|
|
}
|
2009-10-02 11:15:10 +02:00
|
|
|
version = iobuf_get_noeof (inp);
|
|
|
|
pktlen--;
|
|
|
|
if (version != 3)
|
|
|
|
{
|
|
|
|
log_error ("onepass_sig with unknown version %d\n", version);
|
|
|
|
rc = gpg_error (GPG_ERR_INV_PACKET);
|
|
|
|
goto leave;
|
2003-06-05 09:14:21 +02:00
|
|
|
}
|
2009-10-02 11:15:10 +02:00
|
|
|
ops->sig_class = iobuf_get_noeof (inp);
|
|
|
|
pktlen--;
|
|
|
|
ops->digest_algo = iobuf_get_noeof (inp);
|
|
|
|
pktlen--;
|
|
|
|
ops->pubkey_algo = iobuf_get_noeof (inp);
|
|
|
|
pktlen--;
|
|
|
|
ops->keyid[0] = read_32 (inp);
|
|
|
|
pktlen -= 4;
|
|
|
|
ops->keyid[1] = read_32 (inp);
|
|
|
|
pktlen -= 4;
|
|
|
|
ops->last = iobuf_get_noeof (inp);
|
|
|
|
pktlen--;
|
|
|
|
if (list_mode)
|
2010-03-15 12:15:45 +01:00
|
|
|
es_fprintf (listfp,
|
|
|
|
":onepass_sig packet: keyid %08lX%08lX\n"
|
|
|
|
"\tversion %d, sigclass 0x%02x, digest %d, pubkey %d, "
|
|
|
|
"last=%d\n",
|
|
|
|
(ulong) ops->keyid[0], (ulong) ops->keyid[1],
|
|
|
|
version, ops->sig_class,
|
|
|
|
ops->digest_algo, ops->pubkey_algo, ops->last);
|
2009-10-02 11:15:10 +02:00
|
|
|
|
|
|
|
|
|
|
|
leave:
|
|
|
|
iobuf_skip_rest (inp, pktlen, 0);
|
|
|
|
return rc;
|
2003-06-05 09:14:21 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2003-06-18 21:56:13 +02:00
|
|
|
static gcry_mpi_t
|
2006-04-19 13:26:11 +02:00
|
|
|
read_protected_v3_mpi (IOBUF inp, unsigned long *length)
|
2003-06-05 09:14:21 +02:00
|
|
|
{
|
|
|
|
int c;
|
|
|
|
unsigned int nbits, nbytes;
|
|
|
|
unsigned char *buf, *p;
|
2003-06-18 21:56:13 +02:00
|
|
|
gcry_mpi_t val;
|
2003-06-05 09:14:21 +02:00
|
|
|
|
|
|
|
if (*length < 2)
|
|
|
|
{
|
|
|
|
log_error ("mpi too small\n");
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2009-10-02 11:15:10 +02:00
|
|
|
if ((c = iobuf_get (inp)) == -1)
|
2003-06-05 09:14:21 +02:00
|
|
|
return NULL;
|
|
|
|
--*length;
|
|
|
|
nbits = c << 8;
|
2009-10-02 11:15:10 +02:00
|
|
|
if ((c = iobuf_get (inp)) == -1)
|
2003-06-05 09:14:21 +02:00
|
|
|
return NULL;
|
|
|
|
--*length;
|
|
|
|
nbits |= c;
|
|
|
|
|
|
|
|
if (nbits > 16384)
|
|
|
|
{
|
|
|
|
log_error ("mpi too large (%u bits)\n", nbits);
|
|
|
|
return NULL;
|
|
|
|
}
|
2009-10-02 11:15:10 +02:00
|
|
|
nbytes = (nbits + 7) / 8;
|
2003-06-18 21:56:13 +02:00
|
|
|
buf = p = xmalloc (2 + nbytes);
|
2003-06-05 09:14:21 +02:00
|
|
|
*p++ = nbits >> 8;
|
|
|
|
*p++ = nbits;
|
2007-01-15 20:31:24 +01:00
|
|
|
for (; nbytes && *length; nbytes--, --*length)
|
2003-06-05 09:14:21 +02:00
|
|
|
*p++ = iobuf_get (inp);
|
|
|
|
if (nbytes)
|
|
|
|
{
|
2007-01-15 20:31:24 +01:00
|
|
|
log_error ("packet shorter than mpi\n");
|
2003-06-18 21:56:13 +02:00
|
|
|
xfree (buf);
|
2003-06-05 09:14:21 +02:00
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2009-10-02 11:15:10 +02:00
|
|
|
/* Convert buffer into an opaque MPI. */
|
|
|
|
val = gcry_mpi_set_opaque (NULL, buf, (p - buf) * 8);
|
2003-06-05 09:14:21 +02:00
|
|
|
return val;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static int
|
2008-10-20 15:53:23 +02:00
|
|
|
parse_key (IOBUF inp, int pkttype, unsigned long pktlen,
|
2009-10-02 11:15:10 +02:00
|
|
|
byte * hdr, int hdrlen, PACKET * pkt)
|
2003-06-05 09:14:21 +02:00
|
|
|
{
|
2010-09-06 21:57:42 +02:00
|
|
|
gpg_error_t err = 0;
|
2009-10-02 11:15:10 +02:00
|
|
|
int i, version, algorithm;
|
|
|
|
unsigned long timestamp, expiredate, max_expiredate;
|
|
|
|
int npkey, nskey;
|
|
|
|
int is_v4 = 0;
|
|
|
|
int rc = 0;
|
|
|
|
u32 keyid[2];
|
2010-09-06 21:57:42 +02:00
|
|
|
PKT_public_key *pk;
|
2009-10-02 11:15:10 +02:00
|
|
|
|
|
|
|
(void) hdr;
|
|
|
|
|
2010-09-06 21:57:42 +02:00
|
|
|
pk = pkt->pkt.public_key; /* PK has been cleared. */
|
|
|
|
|
2009-10-02 11:15:10 +02:00
|
|
|
version = iobuf_get_noeof (inp);
|
|
|
|
pktlen--;
|
|
|
|
if (pkttype == PKT_PUBLIC_SUBKEY && version == '#')
|
|
|
|
{
|
|
|
|
/* Early versions of G10 used the old PGP comments packets;
|
|
|
|
* luckily all those comments are started by a hash. */
|
|
|
|
if (list_mode)
|
|
|
|
{
|
2010-03-15 12:15:45 +01:00
|
|
|
es_fprintf (listfp, ":rfc1991 comment packet: \"");
|
2009-10-02 11:15:10 +02:00
|
|
|
for (; pktlen; pktlen--)
|
|
|
|
{
|
|
|
|
int c;
|
|
|
|
c = iobuf_get_noeof (inp);
|
|
|
|
if (c >= ' ' && c <= 'z')
|
2010-03-15 12:15:45 +01:00
|
|
|
es_putc (c, listfp);
|
2009-10-02 11:15:10 +02:00
|
|
|
else
|
2010-03-15 12:15:45 +01:00
|
|
|
es_fprintf (listfp, "\\x%02x", c);
|
2003-06-05 09:14:21 +02:00
|
|
|
}
|
2010-03-15 12:15:45 +01:00
|
|
|
es_fprintf (listfp, "\"\n");
|
2003-06-05 09:14:21 +02:00
|
|
|
}
|
2009-10-02 11:15:10 +02:00
|
|
|
iobuf_skip_rest (inp, pktlen, 0);
|
|
|
|
return 0;
|
2003-06-05 09:14:21 +02:00
|
|
|
}
|
2009-10-02 11:15:10 +02:00
|
|
|
else if (version == 4)
|
|
|
|
is_v4 = 1;
|
|
|
|
else if (version != 2 && version != 3)
|
|
|
|
{
|
|
|
|
log_error ("packet(%d) with unknown version %d\n", pkttype, version);
|
2010-09-06 21:57:42 +02:00
|
|
|
err = gpg_error (GPG_ERR_INV_PACKET);
|
2009-10-02 11:15:10 +02:00
|
|
|
goto leave;
|
2003-06-05 09:14:21 +02:00
|
|
|
}
|
|
|
|
|
2009-10-02 11:15:10 +02:00
|
|
|
if (pktlen < 11)
|
|
|
|
{
|
|
|
|
log_error ("packet(%d) too short\n", pkttype);
|
2010-09-06 21:57:42 +02:00
|
|
|
err = gpg_error (GPG_ERR_INV_PACKET);
|
2009-10-02 11:15:10 +02:00
|
|
|
goto leave;
|
2003-06-05 09:14:21 +02:00
|
|
|
}
|
|
|
|
|
2009-10-02 11:15:10 +02:00
|
|
|
timestamp = read_32 (inp);
|
|
|
|
pktlen -= 4;
|
|
|
|
if (is_v4)
|
|
|
|
{
|
|
|
|
expiredate = 0; /* have to get it from the selfsignature */
|
|
|
|
max_expiredate = 0;
|
2003-06-05 09:14:21 +02:00
|
|
|
}
|
2009-10-02 11:15:10 +02:00
|
|
|
else
|
|
|
|
{
|
|
|
|
unsigned short ndays;
|
|
|
|
ndays = read_16 (inp);
|
|
|
|
pktlen -= 2;
|
|
|
|
if (ndays)
|
|
|
|
expiredate = timestamp + ndays * 86400L;
|
|
|
|
else
|
|
|
|
expiredate = 0;
|
|
|
|
|
|
|
|
max_expiredate = expiredate;
|
|
|
|
}
|
|
|
|
algorithm = iobuf_get_noeof (inp);
|
|
|
|
pktlen--;
|
|
|
|
if (list_mode)
|
2010-03-15 12:15:45 +01:00
|
|
|
es_fprintf (listfp, ":%s key packet:\n"
|
|
|
|
"\tversion %d, algo %d, created %lu, expires %lu\n",
|
|
|
|
pkttype == PKT_PUBLIC_KEY ? "public" :
|
|
|
|
pkttype == PKT_SECRET_KEY ? "secret" :
|
|
|
|
pkttype == PKT_PUBLIC_SUBKEY ? "public sub" :
|
|
|
|
pkttype == PKT_SECRET_SUBKEY ? "secret sub" : "??",
|
|
|
|
version, algorithm, timestamp, expiredate);
|
2009-10-02 11:15:10 +02:00
|
|
|
|
2010-09-06 21:57:42 +02:00
|
|
|
pk->timestamp = timestamp;
|
|
|
|
pk->expiredate = expiredate;
|
|
|
|
pk->max_expiredate = max_expiredate;
|
|
|
|
pk->hdrbytes = hdrlen;
|
|
|
|
pk->version = version;
|
2010-10-20 13:33:50 +02:00
|
|
|
pk->flags.primary = (pkttype == PKT_PUBLIC_KEY || pkttype == PKT_SECRET_KEY);
|
2010-09-06 21:57:42 +02:00
|
|
|
pk->pubkey_algo = algorithm;
|
2009-10-02 11:15:10 +02:00
|
|
|
|
|
|
|
nskey = pubkey_get_nskey (algorithm);
|
|
|
|
npkey = pubkey_get_npkey (algorithm);
|
|
|
|
if (!npkey)
|
|
|
|
{
|
|
|
|
if (list_mode)
|
2010-03-15 12:15:45 +01:00
|
|
|
es_fprintf (listfp, "\tunknown algorithm %d\n", algorithm);
|
2009-10-02 11:15:10 +02:00
|
|
|
unknown_pubkey_warning (algorithm);
|
|
|
|
}
|
|
|
|
|
2010-09-06 21:57:42 +02:00
|
|
|
if (!npkey)
|
2009-10-02 11:15:10 +02:00
|
|
|
{
|
2010-09-06 21:57:42 +02:00
|
|
|
/* Unknown algorithm - put data into an opaque MPI. */
|
|
|
|
pk->pkey[0] = gcry_mpi_set_opaque (NULL,
|
2011-03-23 10:07:59 +01:00
|
|
|
read_rest (inp, pktlen), pktlen * 8);
|
2010-09-06 21:57:42 +02:00
|
|
|
pktlen = 0;
|
|
|
|
goto leave;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2011-01-31 09:27:06 +01:00
|
|
|
for (i = 0; i < npkey; i++)
|
2011-01-21 12:00:57 +01:00
|
|
|
{
|
gpg: Use only OpenPGP public key algo ids and add the EdDSA algo id.
* common/sexputil.c (get_pk_algo_from_canon_sexp): Change to return a
string.
* g10/keygen.c (check_keygrip): Adjust for change.
* sm/certreqgen-ui.c (check_keygrip): Likewise.
* agent/pksign.c (do_encode_dsa): Remove bogus map_pk_openpgp_to_gcry.
* g10/misc.c (map_pk_openpgp_to_gcry): Remove.
(openpgp_pk_test_algo): Change to a wrapper for openpgp_pk_test_algo2.
(openpgp_pk_test_algo2): Rewrite.
(openpgp_pk_algo_usage, pubkey_nbits): Add support for EdDSA.
(openpgp_pk_algo_name): Rewrite to remove need for gcry calls.
(pubkey_get_npkey, pubkey_get_nskey): Ditto.
(pubkey_get_nsig, pubkey_get_nenc): Ditto.
* g10/keygen.c(do_create_from_keygrip): Support EdDSA.
(common_gen, gen_ecc, ask_keysize, generate_keypair): Ditto.
* g10/build-packet.c (do_key): Ditto.
* g10/export.c (transfer_format_to_openpgp): Ditto.
* g10/getkey.c (cache_public_key): Ditto.
* g10/import.c (transfer_secret_keys): Ditto.
* g10/keylist.c (list_keyblock_print, list_keyblock_colon): Ditto.
* g10/mainproc.c (proc_pubkey_enc): Ditto.
* g10/parse-packet.c (parse_key): Ditto,
* g10/sign.c (hash_for, sign_file, make_keysig_packet): Ditto.
* g10/keyserver.c (print_keyrec): Use openpgp_pk_algo_name.
* g10/pkglue.c (pk_verify, pk_encrypt, pk_check_secret_key): Use only
OpenPGP algo ids and support EdDSA.
* g10/pubkey-enc.c (get_it): Use only OpenPGP algo ids.
* g10/seskey.c (encode_md_value): Ditto.
--
This patch separates Libgcrypt and OpenPGP public key algorithms ids
and in most cases completely removes the Libgcrypt ones. This is
useful because for Libgcrypt we specify the algorithm in the
S-expressions and the public key ids are not anymore needed.
This patch also adds some support for PUBKEY_ALGO_EDDSA which will
eventually be used instead of merging EdDSA with ECDSA. As of now an
experimental algorithm id is used but the plan is to write an I-D so
that we can get a new id from the IETF. Note that EdDSA (Ed25519)
does not yet work and that more changes are required.
The ECC support is still broken right now. Needs to be fixed.
Signed-off-by: Werner Koch <wk@gnupg.org>
2014-01-30 18:48:37 +01:00
|
|
|
if ( (algorithm == PUBKEY_ALGO_ECDSA && (i == 0))
|
|
|
|
|| (algorithm == PUBKEY_ALGO_EDDSA && (i == 0))
|
|
|
|
|| (algorithm == PUBKEY_ALGO_ECDH && (i == 0 || i == 2)))
|
2011-01-21 12:00:57 +01:00
|
|
|
{
|
gpg: Use only OpenPGP public key algo ids and add the EdDSA algo id.
* common/sexputil.c (get_pk_algo_from_canon_sexp): Change to return a
string.
* g10/keygen.c (check_keygrip): Adjust for change.
* sm/certreqgen-ui.c (check_keygrip): Likewise.
* agent/pksign.c (do_encode_dsa): Remove bogus map_pk_openpgp_to_gcry.
* g10/misc.c (map_pk_openpgp_to_gcry): Remove.
(openpgp_pk_test_algo): Change to a wrapper for openpgp_pk_test_algo2.
(openpgp_pk_test_algo2): Rewrite.
(openpgp_pk_algo_usage, pubkey_nbits): Add support for EdDSA.
(openpgp_pk_algo_name): Rewrite to remove need for gcry calls.
(pubkey_get_npkey, pubkey_get_nskey): Ditto.
(pubkey_get_nsig, pubkey_get_nenc): Ditto.
* g10/keygen.c(do_create_from_keygrip): Support EdDSA.
(common_gen, gen_ecc, ask_keysize, generate_keypair): Ditto.
* g10/build-packet.c (do_key): Ditto.
* g10/export.c (transfer_format_to_openpgp): Ditto.
* g10/getkey.c (cache_public_key): Ditto.
* g10/import.c (transfer_secret_keys): Ditto.
* g10/keylist.c (list_keyblock_print, list_keyblock_colon): Ditto.
* g10/mainproc.c (proc_pubkey_enc): Ditto.
* g10/parse-packet.c (parse_key): Ditto,
* g10/sign.c (hash_for, sign_file, make_keysig_packet): Ditto.
* g10/keyserver.c (print_keyrec): Use openpgp_pk_algo_name.
* g10/pkglue.c (pk_verify, pk_encrypt, pk_check_secret_key): Use only
OpenPGP algo ids and support EdDSA.
* g10/pubkey-enc.c (get_it): Use only OpenPGP algo ids.
* g10/seskey.c (encode_md_value): Ditto.
--
This patch separates Libgcrypt and OpenPGP public key algorithms ids
and in most cases completely removes the Libgcrypt ones. This is
useful because for Libgcrypt we specify the algorithm in the
S-expressions and the public key ids are not anymore needed.
This patch also adds some support for PUBKEY_ALGO_EDDSA which will
eventually be used instead of merging EdDSA with ECDSA. As of now an
experimental algorithm id is used but the plan is to write an I-D so
that we can get a new id from the IETF. Note that EdDSA (Ed25519)
does not yet work and that more changes are required.
The ECC support is still broken right now. Needs to be fixed.
Signed-off-by: Werner Koch <wk@gnupg.org>
2014-01-30 18:48:37 +01:00
|
|
|
/* Read the OID (i==1) or the KDF params (i==2). */
|
2011-06-01 21:43:30 +02:00
|
|
|
size_t n;
|
|
|
|
err = read_size_body (inp, pktlen, &n, pk->pkey+i);
|
2011-01-31 09:27:06 +01:00
|
|
|
pktlen -= n;
|
2011-01-21 12:00:57 +01:00
|
|
|
}
|
2011-01-31 09:27:06 +01:00
|
|
|
else
|
2011-01-21 12:00:57 +01:00
|
|
|
{
|
2011-06-01 21:43:30 +02:00
|
|
|
unsigned int n = pktlen;
|
2011-01-21 12:00:57 +01:00
|
|
|
pk->pkey[i] = mpi_read (inp, &n, 0);
|
|
|
|
pktlen -= n;
|
|
|
|
if (!pk->pkey[i])
|
|
|
|
err = gpg_error (GPG_ERR_INV_PACKET);
|
|
|
|
}
|
2011-01-31 09:27:06 +01:00
|
|
|
if (err)
|
|
|
|
goto leave;
|
|
|
|
if (list_mode)
|
|
|
|
{
|
|
|
|
es_fprintf (listfp, "\tpkey[%d]: ", i);
|
|
|
|
mpi_print (listfp, pk->pkey[i], mpi_print_mode);
|
2013-11-15 08:59:45 +01:00
|
|
|
if ((algorithm == PUBKEY_ALGO_ECDSA
|
gpg: Use only OpenPGP public key algo ids and add the EdDSA algo id.
* common/sexputil.c (get_pk_algo_from_canon_sexp): Change to return a
string.
* g10/keygen.c (check_keygrip): Adjust for change.
* sm/certreqgen-ui.c (check_keygrip): Likewise.
* agent/pksign.c (do_encode_dsa): Remove bogus map_pk_openpgp_to_gcry.
* g10/misc.c (map_pk_openpgp_to_gcry): Remove.
(openpgp_pk_test_algo): Change to a wrapper for openpgp_pk_test_algo2.
(openpgp_pk_test_algo2): Rewrite.
(openpgp_pk_algo_usage, pubkey_nbits): Add support for EdDSA.
(openpgp_pk_algo_name): Rewrite to remove need for gcry calls.
(pubkey_get_npkey, pubkey_get_nskey): Ditto.
(pubkey_get_nsig, pubkey_get_nenc): Ditto.
* g10/keygen.c(do_create_from_keygrip): Support EdDSA.
(common_gen, gen_ecc, ask_keysize, generate_keypair): Ditto.
* g10/build-packet.c (do_key): Ditto.
* g10/export.c (transfer_format_to_openpgp): Ditto.
* g10/getkey.c (cache_public_key): Ditto.
* g10/import.c (transfer_secret_keys): Ditto.
* g10/keylist.c (list_keyblock_print, list_keyblock_colon): Ditto.
* g10/mainproc.c (proc_pubkey_enc): Ditto.
* g10/parse-packet.c (parse_key): Ditto,
* g10/sign.c (hash_for, sign_file, make_keysig_packet): Ditto.
* g10/keyserver.c (print_keyrec): Use openpgp_pk_algo_name.
* g10/pkglue.c (pk_verify, pk_encrypt, pk_check_secret_key): Use only
OpenPGP algo ids and support EdDSA.
* g10/pubkey-enc.c (get_it): Use only OpenPGP algo ids.
* g10/seskey.c (encode_md_value): Ditto.
--
This patch separates Libgcrypt and OpenPGP public key algorithms ids
and in most cases completely removes the Libgcrypt ones. This is
useful because for Libgcrypt we specify the algorithm in the
S-expressions and the public key ids are not anymore needed.
This patch also adds some support for PUBKEY_ALGO_EDDSA which will
eventually be used instead of merging EdDSA with ECDSA. As of now an
experimental algorithm id is used but the plan is to write an I-D so
that we can get a new id from the IETF. Note that EdDSA (Ed25519)
does not yet work and that more changes are required.
The ECC support is still broken right now. Needs to be fixed.
Signed-off-by: Werner Koch <wk@gnupg.org>
2014-01-30 18:48:37 +01:00
|
|
|
|| algorithm == PUBKEY_ALGO_EDDSA
|
2013-11-15 08:59:45 +01:00
|
|
|
|| algorithm == PUBKEY_ALGO_ECDH) && i==0)
|
|
|
|
{
|
|
|
|
char *curve = openpgp_oid_to_str (pk->pkey[0]);
|
|
|
|
es_fprintf (listfp, " %s (%s)",
|
|
|
|
openpgp_oid_to_curve (curve), curve);
|
|
|
|
xfree (curve);
|
|
|
|
}
|
2011-01-31 09:27:06 +01:00
|
|
|
es_putc ('\n', listfp);
|
|
|
|
}
|
2011-01-21 12:00:57 +01:00
|
|
|
}
|
2010-09-06 21:57:42 +02:00
|
|
|
}
|
|
|
|
if (list_mode)
|
|
|
|
keyid_from_pk (pk, keyid);
|
|
|
|
|
|
|
|
if (pkttype == PKT_SECRET_KEY || pkttype == PKT_SECRET_SUBKEY)
|
|
|
|
{
|
|
|
|
struct seckey_info *ski;
|
|
|
|
byte temp[16];
|
|
|
|
size_t snlen = 0;
|
|
|
|
|
|
|
|
pk->seckey_info = ski = xtrycalloc (1, sizeof *ski);
|
|
|
|
if (!pk->seckey_info)
|
|
|
|
{
|
|
|
|
err = gpg_error_from_syserror ();
|
|
|
|
goto leave;
|
|
|
|
}
|
|
|
|
|
|
|
|
ski->algo = iobuf_get_noeof (inp);
|
2009-10-02 11:15:10 +02:00
|
|
|
pktlen--;
|
2010-09-06 21:57:42 +02:00
|
|
|
if (ski->algo)
|
2009-10-02 11:15:10 +02:00
|
|
|
{
|
2010-09-06 21:57:42 +02:00
|
|
|
ski->is_protected = 1;
|
|
|
|
ski->s2k.count = 0;
|
|
|
|
if (ski->algo == 254 || ski->algo == 255)
|
2009-10-02 11:15:10 +02:00
|
|
|
{
|
|
|
|
if (pktlen < 3)
|
|
|
|
{
|
2010-09-06 21:57:42 +02:00
|
|
|
err = gpg_error (GPG_ERR_INV_PACKET);
|
2009-10-02 11:15:10 +02:00
|
|
|
goto leave;
|
2003-06-05 09:14:21 +02:00
|
|
|
}
|
2010-09-06 21:57:42 +02:00
|
|
|
ski->sha1chk = (ski->algo == 254);
|
|
|
|
ski->algo = iobuf_get_noeof (inp);
|
2009-10-02 11:15:10 +02:00
|
|
|
pktlen--;
|
2010-09-06 21:57:42 +02:00
|
|
|
/* Note that a ski->algo > 110 is illegal, but I'm not
|
|
|
|
erroring on it here as otherwise there would be no
|
|
|
|
way to delete such a key. */
|
|
|
|
ski->s2k.mode = iobuf_get_noeof (inp);
|
2009-10-02 11:15:10 +02:00
|
|
|
pktlen--;
|
2010-09-06 21:57:42 +02:00
|
|
|
ski->s2k.hash_algo = iobuf_get_noeof (inp);
|
2009-10-02 11:15:10 +02:00
|
|
|
pktlen--;
|
2010-09-06 21:57:42 +02:00
|
|
|
/* Check for the special GNU extension. */
|
|
|
|
if (is_v4 && ski->s2k.mode == 101)
|
2009-10-02 11:15:10 +02:00
|
|
|
{
|
|
|
|
for (i = 0; i < 4 && pktlen; i++, pktlen--)
|
|
|
|
temp[i] = iobuf_get_noeof (inp);
|
|
|
|
if (i < 4 || memcmp (temp, "GNU", 3))
|
|
|
|
{
|
|
|
|
if (list_mode)
|
2010-03-15 12:15:45 +01:00
|
|
|
es_fprintf (listfp, "\tunknown S2K %d\n",
|
2010-09-06 21:57:42 +02:00
|
|
|
ski->s2k.mode);
|
|
|
|
err = gpg_error (GPG_ERR_INV_PACKET);
|
2009-10-02 11:15:10 +02:00
|
|
|
goto leave;
|
2003-06-05 09:14:21 +02:00
|
|
|
}
|
2009-10-02 11:15:10 +02:00
|
|
|
/* Here we know that it is a GNU extension. What
|
|
|
|
* follows is the GNU protection mode: All values
|
|
|
|
* have special meanings and they are mapped to MODE
|
|
|
|
* with a base of 1000. */
|
2010-09-06 21:57:42 +02:00
|
|
|
ski->s2k.mode = 1000 + temp[3];
|
2003-06-05 09:14:21 +02:00
|
|
|
}
|
2010-09-06 21:57:42 +02:00
|
|
|
|
|
|
|
/* Read the salt. */
|
|
|
|
switch (ski->s2k.mode)
|
2009-10-02 11:15:10 +02:00
|
|
|
{
|
|
|
|
case 1:
|
|
|
|
case 3:
|
|
|
|
for (i = 0; i < 8 && pktlen; i++, pktlen--)
|
|
|
|
temp[i] = iobuf_get_noeof (inp);
|
2010-09-06 21:57:42 +02:00
|
|
|
memcpy (ski->s2k.salt, temp, 8);
|
2009-10-02 11:15:10 +02:00
|
|
|
break;
|
2003-06-05 09:14:21 +02:00
|
|
|
}
|
2010-09-06 21:57:42 +02:00
|
|
|
|
|
|
|
/* Check the mode. */
|
|
|
|
switch (ski->s2k.mode)
|
2009-10-02 11:15:10 +02:00
|
|
|
{
|
|
|
|
case 0:
|
|
|
|
if (list_mode)
|
2010-03-15 12:15:45 +01:00
|
|
|
es_fprintf (listfp, "\tsimple S2K");
|
2009-10-02 11:15:10 +02:00
|
|
|
break;
|
|
|
|
case 1:
|
|
|
|
if (list_mode)
|
2010-03-15 12:15:45 +01:00
|
|
|
es_fprintf (listfp, "\tsalted S2K");
|
2009-10-02 11:15:10 +02:00
|
|
|
break;
|
|
|
|
case 3:
|
|
|
|
if (list_mode)
|
2010-03-15 12:15:45 +01:00
|
|
|
es_fprintf (listfp, "\titer+salt S2K");
|
2009-10-02 11:15:10 +02:00
|
|
|
break;
|
|
|
|
case 1001:
|
|
|
|
if (list_mode)
|
2010-03-15 12:15:45 +01:00
|
|
|
es_fprintf (listfp, "\tgnu-dummy S2K");
|
2009-10-02 11:15:10 +02:00
|
|
|
break;
|
|
|
|
case 1002:
|
|
|
|
if (list_mode)
|
2010-03-15 12:15:45 +01:00
|
|
|
es_fprintf (listfp, "\tgnu-divert-to-card S2K");
|
2009-10-02 11:15:10 +02:00
|
|
|
break;
|
|
|
|
default:
|
|
|
|
if (list_mode)
|
2010-03-15 12:15:45 +01:00
|
|
|
es_fprintf (listfp, "\tunknown %sS2K %d\n",
|
2010-09-06 21:57:42 +02:00
|
|
|
ski->s2k.mode < 1000 ? "" : "GNU ",
|
|
|
|
ski->s2k.mode);
|
|
|
|
err = gpg_error (GPG_ERR_INV_PACKET);
|
2009-10-02 11:15:10 +02:00
|
|
|
goto leave;
|
2003-06-05 09:14:21 +02:00
|
|
|
}
|
|
|
|
|
2010-09-06 21:57:42 +02:00
|
|
|
/* Print some info. */
|
2009-10-02 11:15:10 +02:00
|
|
|
if (list_mode)
|
|
|
|
{
|
2010-03-15 12:15:45 +01:00
|
|
|
es_fprintf (listfp, ", algo: %d,%s hash: %d",
|
2010-09-06 21:57:42 +02:00
|
|
|
ski->algo,
|
|
|
|
ski->sha1chk ? " SHA1 protection,"
|
|
|
|
: " simple checksum,", ski->s2k.hash_algo);
|
|
|
|
if (ski->s2k.mode == 1 || ski->s2k.mode == 3)
|
2009-10-02 11:15:10 +02:00
|
|
|
{
|
2010-03-15 12:15:45 +01:00
|
|
|
es_fprintf (listfp, ", salt: ");
|
2010-09-06 21:57:42 +02:00
|
|
|
es_write_hexstring (listfp, ski->s2k.salt, 8, 0, NULL);
|
2003-06-05 09:14:21 +02:00
|
|
|
}
|
2010-03-15 12:15:45 +01:00
|
|
|
es_putc ('\n', listfp);
|
2003-06-05 09:14:21 +02:00
|
|
|
}
|
|
|
|
|
2010-09-06 21:57:42 +02:00
|
|
|
/* Read remaining protection parameters. */
|
|
|
|
if (ski->s2k.mode == 3)
|
2009-10-02 11:15:10 +02:00
|
|
|
{
|
|
|
|
if (pktlen < 1)
|
|
|
|
{
|
2010-09-06 21:57:42 +02:00
|
|
|
err = gpg_error (GPG_ERR_INV_PACKET);
|
2009-10-02 11:15:10 +02:00
|
|
|
goto leave;
|
2003-06-05 09:14:21 +02:00
|
|
|
}
|
2010-09-06 21:57:42 +02:00
|
|
|
ski->s2k.count = iobuf_get (inp);
|
2009-10-02 11:15:10 +02:00
|
|
|
pktlen--;
|
|
|
|
if (list_mode)
|
2011-07-18 10:57:33 +02:00
|
|
|
es_fprintf (listfp, "\tprotect count: %lu (%lu)\n",
|
|
|
|
(ulong)S2K_DECODE_COUNT ((ulong)ski->s2k.count),
|
2010-09-06 21:57:42 +02:00
|
|
|
(ulong) ski->s2k.count);
|
2003-06-05 09:14:21 +02:00
|
|
|
}
|
2010-09-06 21:57:42 +02:00
|
|
|
else if (ski->s2k.mode == 1002)
|
2009-10-02 11:15:10 +02:00
|
|
|
{
|
|
|
|
/* Read the serial number. */
|
|
|
|
if (pktlen < 1)
|
|
|
|
{
|
2010-09-06 21:57:42 +02:00
|
|
|
err = gpg_error (GPG_ERR_INV_PACKET);
|
2009-10-02 11:15:10 +02:00
|
|
|
goto leave;
|
|
|
|
}
|
|
|
|
snlen = iobuf_get (inp);
|
|
|
|
pktlen--;
|
2010-10-20 13:33:50 +02:00
|
|
|
if (pktlen < snlen || snlen == (size_t)(-1))
|
2009-10-02 11:15:10 +02:00
|
|
|
{
|
2010-09-06 21:57:42 +02:00
|
|
|
err = gpg_error (GPG_ERR_INV_PACKET);
|
2009-10-02 11:15:10 +02:00
|
|
|
goto leave;
|
2003-06-27 22:53:09 +02:00
|
|
|
}
|
|
|
|
}
|
2003-06-05 09:14:21 +02:00
|
|
|
}
|
2009-10-02 11:15:10 +02:00
|
|
|
else /* Old version; no S2K, so we set mode to 0, hash MD5. */
|
2011-02-04 12:57:53 +01:00
|
|
|
{
|
2010-09-06 21:57:42 +02:00
|
|
|
/* Note that a ski->algo > 110 is illegal, but I'm not
|
|
|
|
erroring on it here as otherwise there would be no
|
|
|
|
way to delete such a key. */
|
|
|
|
ski->s2k.mode = 0;
|
|
|
|
ski->s2k.hash_algo = DIGEST_ALGO_MD5;
|
2009-10-02 11:15:10 +02:00
|
|
|
if (list_mode)
|
2010-03-15 12:15:45 +01:00
|
|
|
es_fprintf (listfp, "\tprotect algo: %d (hash algo: %d)\n",
|
2010-09-06 21:57:42 +02:00
|
|
|
ski->algo, ski->s2k.hash_algo);
|
2003-06-05 09:14:21 +02:00
|
|
|
}
|
2011-02-04 12:57:53 +01:00
|
|
|
|
2009-10-02 11:15:10 +02:00
|
|
|
/* It is really ugly that we don't know the size
|
|
|
|
* of the IV here in cases we are not aware of the algorithm.
|
|
|
|
* so a
|
2010-09-06 21:57:42 +02:00
|
|
|
* ski->ivlen = cipher_get_blocksize (ski->algo);
|
2009-10-02 11:15:10 +02:00
|
|
|
* won't work. The only solution I see is to hardwire it.
|
|
|
|
* NOTE: if you change the ivlen above 16, don't forget to
|
|
|
|
* enlarge temp. */
|
2010-09-06 21:57:42 +02:00
|
|
|
ski->ivlen = openpgp_cipher_blocklen (ski->algo);
|
|
|
|
assert (ski->ivlen <= sizeof (temp));
|
2009-10-02 11:15:10 +02:00
|
|
|
|
2010-09-06 21:57:42 +02:00
|
|
|
if (ski->s2k.mode == 1001)
|
|
|
|
ski->ivlen = 0;
|
|
|
|
else if (ski->s2k.mode == 1002)
|
|
|
|
ski->ivlen = snlen < 16 ? snlen : 16;
|
2009-10-02 11:15:10 +02:00
|
|
|
|
2010-09-06 21:57:42 +02:00
|
|
|
if (pktlen < ski->ivlen)
|
2009-10-02 11:15:10 +02:00
|
|
|
{
|
2010-09-06 21:57:42 +02:00
|
|
|
err = gpg_error (GPG_ERR_INV_PACKET);
|
2009-10-02 11:15:10 +02:00
|
|
|
goto leave;
|
2003-06-05 09:14:21 +02:00
|
|
|
}
|
2010-09-06 21:57:42 +02:00
|
|
|
for (i = 0; i < ski->ivlen && pktlen; i++, pktlen--)
|
2009-10-02 11:15:10 +02:00
|
|
|
temp[i] = iobuf_get_noeof (inp);
|
|
|
|
if (list_mode)
|
|
|
|
{
|
2010-03-15 12:15:45 +01:00
|
|
|
es_fprintf (listfp,
|
2010-09-06 21:57:42 +02:00
|
|
|
ski->s2k.mode == 1002 ? "\tserial-number: "
|
|
|
|
: "\tprotect IV: ");
|
|
|
|
for (i = 0; i < ski->ivlen; i++)
|
2010-03-15 12:15:45 +01:00
|
|
|
es_fprintf (listfp, " %02x", temp[i]);
|
|
|
|
es_putc ('\n', listfp);
|
2003-06-05 09:14:21 +02:00
|
|
|
}
|
2010-09-06 21:57:42 +02:00
|
|
|
memcpy (ski->iv, temp, ski->ivlen);
|
2003-06-05 09:14:21 +02:00
|
|
|
}
|
2009-10-02 11:15:10 +02:00
|
|
|
|
|
|
|
/* It does not make sense to read it into secure memory.
|
|
|
|
* If the user is so careless, not to protect his secret key,
|
|
|
|
* we can assume, that he operates an open system :=(.
|
|
|
|
* So we put the key into secure memory when we unprotect it. */
|
2010-09-06 21:57:42 +02:00
|
|
|
if (ski->s2k.mode == 1001 || ski->s2k.mode == 1002)
|
2009-10-02 11:15:10 +02:00
|
|
|
{
|
|
|
|
/* Better set some dummy stuff here. */
|
2010-09-06 21:57:42 +02:00
|
|
|
pk->pkey[npkey] = gcry_mpi_set_opaque (NULL,
|
2009-10-02 11:15:10 +02:00
|
|
|
xstrdup ("dummydata"),
|
|
|
|
10 * 8);
|
|
|
|
pktlen = 0;
|
2003-06-05 09:14:21 +02:00
|
|
|
}
|
2010-09-06 21:57:42 +02:00
|
|
|
else if (is_v4 && ski->is_protected)
|
2009-10-02 11:15:10 +02:00
|
|
|
{
|
|
|
|
/* Ugly: The length is encrypted too, so we read all stuff
|
|
|
|
* up to the end of the packet into the first SKEY
|
|
|
|
* element. */
|
2010-09-06 21:57:42 +02:00
|
|
|
pk->pkey[npkey] = gcry_mpi_set_opaque (NULL,
|
2011-03-23 10:07:59 +01:00
|
|
|
read_rest (inp, pktlen),
|
2009-10-02 11:15:10 +02:00
|
|
|
pktlen * 8);
|
|
|
|
pktlen = 0;
|
|
|
|
if (list_mode)
|
2010-09-06 21:57:42 +02:00
|
|
|
es_fprintf (listfp, "\tskey[%d]: [v4 protected]\n", npkey);
|
2003-06-05 09:14:21 +02:00
|
|
|
}
|
2011-02-04 12:57:53 +01:00
|
|
|
else
|
|
|
|
{
|
2010-09-06 21:57:42 +02:00
|
|
|
/* The v3 method: The mpi length is not encrypted. */
|
2009-10-02 11:15:10 +02:00
|
|
|
for (i = npkey; i < nskey; i++)
|
|
|
|
{
|
2010-09-06 21:57:42 +02:00
|
|
|
if (ski->is_protected)
|
2009-10-02 11:15:10 +02:00
|
|
|
{
|
2010-09-06 21:57:42 +02:00
|
|
|
pk->pkey[i] = read_protected_v3_mpi (inp, &pktlen);
|
2009-10-02 11:15:10 +02:00
|
|
|
if (list_mode)
|
2010-09-06 21:57:42 +02:00
|
|
|
es_fprintf (listfp, "\tskey[%d]: [v3 protected]\n", i);
|
2009-10-02 11:15:10 +02:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2011-06-01 21:43:30 +02:00
|
|
|
unsigned int n = pktlen;
|
2010-09-06 21:57:42 +02:00
|
|
|
pk->pkey[i] = mpi_read (inp, &n, 0);
|
2009-10-02 11:15:10 +02:00
|
|
|
pktlen -= n;
|
|
|
|
if (list_mode)
|
|
|
|
{
|
2010-03-15 12:15:45 +01:00
|
|
|
es_fprintf (listfp, "\tskey[%d]: ", i);
|
2010-09-06 21:57:42 +02:00
|
|
|
mpi_print (listfp, pk->pkey[i], mpi_print_mode);
|
2010-03-15 12:15:45 +01:00
|
|
|
es_putc ('\n', listfp);
|
2009-10-02 11:15:10 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2010-09-06 21:57:42 +02:00
|
|
|
if (!pk->pkey[i])
|
|
|
|
err = gpg_error (GPG_ERR_INV_PACKET);
|
2003-06-05 09:14:21 +02:00
|
|
|
}
|
2010-09-06 21:57:42 +02:00
|
|
|
if (err)
|
2009-10-02 11:15:10 +02:00
|
|
|
goto leave;
|
2003-06-05 09:14:21 +02:00
|
|
|
|
2010-09-06 21:57:42 +02:00
|
|
|
ski->csum = read_16 (inp);
|
2009-10-02 11:15:10 +02:00
|
|
|
pktlen -= 2;
|
|
|
|
if (list_mode)
|
2010-09-06 21:57:42 +02:00
|
|
|
es_fprintf (listfp, "\tchecksum: %04hx\n", ski->csum);
|
2003-06-05 09:14:21 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2009-10-02 11:15:10 +02:00
|
|
|
if (list_mode)
|
2010-03-15 12:15:45 +01:00
|
|
|
es_fprintf (listfp, "\tkeyid: %08lX%08lX\n",
|
|
|
|
(ulong) keyid[0], (ulong) keyid[1]);
|
2009-05-13 13:42:34 +02:00
|
|
|
|
2009-10-02 11:15:10 +02:00
|
|
|
leave:
|
|
|
|
iobuf_skip_rest (inp, pktlen, 0);
|
|
|
|
return rc;
|
2003-06-05 09:14:21 +02:00
|
|
|
}
|
|
|
|
|
2009-10-02 11:15:10 +02:00
|
|
|
|
2003-06-05 09:14:21 +02:00
|
|
|
/* Attribute subpackets have the same format as v4 signature
|
|
|
|
subpackets. This is not part of OpenPGP, but is done in several
|
2009-10-02 11:15:10 +02:00
|
|
|
versions of PGP nevertheless. */
|
2003-06-05 09:14:21 +02:00
|
|
|
int
|
2009-10-02 11:15:10 +02:00
|
|
|
parse_attribute_subpkts (PKT_user_id * uid)
|
2003-06-05 09:14:21 +02:00
|
|
|
{
|
|
|
|
size_t n;
|
2009-10-02 11:15:10 +02:00
|
|
|
int count = 0;
|
|
|
|
struct user_attribute *attribs = NULL;
|
|
|
|
const byte *buffer = uid->attrib_data;
|
|
|
|
int buflen = uid->attrib_len;
|
2003-06-05 09:14:21 +02:00
|
|
|
byte type;
|
|
|
|
|
2009-10-02 11:15:10 +02:00
|
|
|
xfree (uid->attribs);
|
2003-06-05 09:14:21 +02:00
|
|
|
|
2009-10-02 11:15:10 +02:00
|
|
|
while (buflen)
|
2003-06-05 09:14:21 +02:00
|
|
|
{
|
2009-10-02 11:15:10 +02:00
|
|
|
n = *buffer++;
|
|
|
|
buflen--;
|
|
|
|
if (n == 255) /* 4 byte length header. */
|
2011-02-04 12:57:53 +01:00
|
|
|
{
|
2009-10-02 11:15:10 +02:00
|
|
|
if (buflen < 4)
|
|
|
|
goto too_short;
|
|
|
|
n = (buffer[0] << 24) | (buffer[1] << 16)
|
|
|
|
| (buffer[2] << 8) | buffer[3];
|
|
|
|
buffer += 4;
|
|
|
|
buflen -= 4;
|
|
|
|
}
|
|
|
|
else if (n >= 192) /* 2 byte special encoded length header. */
|
2011-02-04 12:57:53 +01:00
|
|
|
{
|
2009-10-02 11:15:10 +02:00
|
|
|
if (buflen < 2)
|
|
|
|
goto too_short;
|
|
|
|
n = ((n - 192) << 8) + *buffer + 192;
|
|
|
|
buffer++;
|
|
|
|
buflen--;
|
|
|
|
}
|
|
|
|
if (buflen < n)
|
2003-06-05 09:14:21 +02:00
|
|
|
goto too_short;
|
|
|
|
|
2009-10-02 11:15:10 +02:00
|
|
|
attribs =
|
|
|
|
xrealloc (attribs, (count + 1) * sizeof (struct user_attribute));
|
|
|
|
memset (&attribs[count], 0, sizeof (struct user_attribute));
|
2003-06-05 09:14:21 +02:00
|
|
|
|
2009-10-02 11:15:10 +02:00
|
|
|
type = *buffer;
|
2003-06-05 09:14:21 +02:00
|
|
|
buffer++;
|
|
|
|
buflen--;
|
|
|
|
n--;
|
|
|
|
|
2009-10-02 11:15:10 +02:00
|
|
|
attribs[count].type = type;
|
|
|
|
attribs[count].data = buffer;
|
|
|
|
attribs[count].len = n;
|
|
|
|
buffer += n;
|
|
|
|
buflen -= n;
|
2003-06-05 09:14:21 +02:00
|
|
|
count++;
|
|
|
|
}
|
|
|
|
|
2009-10-02 11:15:10 +02:00
|
|
|
uid->attribs = attribs;
|
|
|
|
uid->numattribs = count;
|
2003-06-05 09:14:21 +02:00
|
|
|
return count;
|
|
|
|
|
|
|
|
too_short:
|
2009-10-02 11:15:10 +02:00
|
|
|
if (opt.verbose)
|
|
|
|
log_info ("buffer shorter than attribute subpacket\n");
|
|
|
|
uid->attribs = attribs;
|
|
|
|
uid->numattribs = count;
|
2003-06-05 09:14:21 +02:00
|
|
|
return count;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static int
|
2009-10-02 11:15:10 +02:00
|
|
|
parse_user_id (IOBUF inp, int pkttype, unsigned long pktlen, PACKET * packet)
|
2003-06-05 09:14:21 +02:00
|
|
|
{
|
2009-10-02 11:15:10 +02:00
|
|
|
byte *p;
|
2003-06-05 09:14:21 +02:00
|
|
|
|
2009-10-02 11:15:10 +02:00
|
|
|
/* Cap the size of a user ID at 2k: a value absurdly large enough
|
|
|
|
that there is no sane user ID string (which is printable text
|
|
|
|
as of RFC2440bis) that won't fit in it, but yet small enough to
|
|
|
|
avoid allocation problems. A large pktlen may not be
|
|
|
|
allocatable, and a very large pktlen could actually cause our
|
|
|
|
allocation to wrap around in xmalloc to a small number. */
|
2006-06-27 16:30:59 +02:00
|
|
|
|
2009-10-02 11:15:10 +02:00
|
|
|
if (pktlen > 2048)
|
|
|
|
{
|
|
|
|
log_error ("packet(%d) too large\n", pkttype);
|
|
|
|
iobuf_skip_rest (inp, pktlen, 0);
|
|
|
|
return G10ERR_INVALID_PACKET;
|
|
|
|
}
|
|
|
|
|
|
|
|
packet->pkt.user_id = xmalloc_clear (sizeof *packet->pkt.user_id + pktlen);
|
|
|
|
packet->pkt.user_id->len = pktlen;
|
|
|
|
packet->pkt.user_id->ref = 1;
|
|
|
|
|
|
|
|
p = packet->pkt.user_id->name;
|
|
|
|
for (; pktlen; pktlen--, p++)
|
|
|
|
*p = iobuf_get_noeof (inp);
|
|
|
|
*p = 0;
|
|
|
|
|
|
|
|
if (list_mode)
|
|
|
|
{
|
|
|
|
int n = packet->pkt.user_id->len;
|
2010-03-15 12:15:45 +01:00
|
|
|
es_fprintf (listfp, ":user ID packet: \"");
|
|
|
|
/* fixme: Hey why don't we replace this with es_write_sanitized?? */
|
2009-10-02 11:15:10 +02:00
|
|
|
for (p = packet->pkt.user_id->name; n; p++, n--)
|
|
|
|
{
|
|
|
|
if (*p >= ' ' && *p <= 'z')
|
2010-03-15 12:15:45 +01:00
|
|
|
es_putc (*p, listfp);
|
2009-10-02 11:15:10 +02:00
|
|
|
else
|
2010-03-15 12:15:45 +01:00
|
|
|
es_fprintf (listfp, "\\x%02x", *p);
|
2003-06-05 09:14:21 +02:00
|
|
|
}
|
2010-03-15 12:15:45 +01:00
|
|
|
es_fprintf (listfp, "\"\n");
|
2003-06-05 09:14:21 +02:00
|
|
|
}
|
2009-10-02 11:15:10 +02:00
|
|
|
return 0;
|
2003-06-05 09:14:21 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void
|
2009-10-02 11:15:10 +02:00
|
|
|
make_attribute_uidname (PKT_user_id * uid, size_t max_namelen)
|
2003-06-05 09:14:21 +02:00
|
|
|
{
|
2009-10-02 11:15:10 +02:00
|
|
|
assert (max_namelen > 70);
|
|
|
|
if (uid->numattribs <= 0)
|
|
|
|
sprintf (uid->name, "[bad attribute packet of size %lu]",
|
|
|
|
uid->attrib_len);
|
|
|
|
else if (uid->numattribs > 1)
|
|
|
|
sprintf (uid->name, "[%d attributes of size %lu]",
|
|
|
|
uid->numattribs, uid->attrib_len);
|
2003-06-05 09:14:21 +02:00
|
|
|
else
|
|
|
|
{
|
|
|
|
/* Only one attribute, so list it as the "user id" */
|
|
|
|
|
2009-10-02 11:15:10 +02:00
|
|
|
if (uid->attribs->type == ATTRIB_IMAGE)
|
2003-06-05 09:14:21 +02:00
|
|
|
{
|
|
|
|
u32 len;
|
|
|
|
byte type;
|
|
|
|
|
2009-10-02 11:15:10 +02:00
|
|
|
if (parse_image_header (uid->attribs, &type, &len))
|
|
|
|
sprintf (uid->name, "[%.20s image of size %lu]",
|
|
|
|
image_type_to_string (type, 1), (ulong) len);
|
2003-06-05 09:14:21 +02:00
|
|
|
else
|
2009-10-02 11:15:10 +02:00
|
|
|
sprintf (uid->name, "[invalid image]");
|
2003-06-05 09:14:21 +02:00
|
|
|
}
|
|
|
|
else
|
2009-10-02 11:15:10 +02:00
|
|
|
sprintf (uid->name, "[unknown attribute of size %lu]",
|
|
|
|
(ulong) uid->attribs->len);
|
2003-06-05 09:14:21 +02:00
|
|
|
}
|
|
|
|
|
2009-10-02 11:15:10 +02:00
|
|
|
uid->len = strlen (uid->name);
|
2003-06-05 09:14:21 +02:00
|
|
|
}
|
|
|
|
|
2009-10-02 11:15:10 +02:00
|
|
|
|
2003-06-05 09:14:21 +02:00
|
|
|
static int
|
2009-10-02 11:15:10 +02:00
|
|
|
parse_attribute (IOBUF inp, int pkttype, unsigned long pktlen,
|
|
|
|
PACKET * packet)
|
2003-06-05 09:14:21 +02:00
|
|
|
{
|
2009-10-02 11:15:10 +02:00
|
|
|
byte *p;
|
2003-06-05 09:14:21 +02:00
|
|
|
|
2009-10-02 11:15:10 +02:00
|
|
|
(void) pkttype;
|
2008-10-20 15:53:23 +02:00
|
|
|
|
2003-06-05 09:14:21 +02:00
|
|
|
#define EXTRA_UID_NAME_SPACE 71
|
2009-10-02 11:15:10 +02:00
|
|
|
packet->pkt.user_id = xmalloc_clear (sizeof *packet->pkt.user_id
|
|
|
|
+ EXTRA_UID_NAME_SPACE);
|
|
|
|
packet->pkt.user_id->ref = 1;
|
|
|
|
packet->pkt.user_id->attrib_data = xmalloc (pktlen);
|
|
|
|
packet->pkt.user_id->attrib_len = pktlen;
|
2006-04-19 13:26:11 +02:00
|
|
|
|
2009-10-02 11:15:10 +02:00
|
|
|
p = packet->pkt.user_id->attrib_data;
|
|
|
|
for (; pktlen; pktlen--, p++)
|
|
|
|
*p = iobuf_get_noeof (inp);
|
2003-06-05 09:14:21 +02:00
|
|
|
|
2009-10-02 11:15:10 +02:00
|
|
|
/* Now parse out the individual attribute subpackets. This is
|
|
|
|
somewhat pointless since there is only one currently defined
|
|
|
|
attribute type (jpeg), but it is correct by the spec. */
|
|
|
|
parse_attribute_subpkts (packet->pkt.user_id);
|
2003-06-05 09:14:21 +02:00
|
|
|
|
2009-10-02 11:15:10 +02:00
|
|
|
make_attribute_uidname (packet->pkt.user_id, EXTRA_UID_NAME_SPACE);
|
2003-06-05 09:14:21 +02:00
|
|
|
|
2009-10-02 11:15:10 +02:00
|
|
|
if (list_mode)
|
|
|
|
{
|
2010-03-15 12:15:45 +01:00
|
|
|
es_fprintf (listfp, ":attribute packet: %s\n", packet->pkt.user_id->name);
|
2003-06-05 09:14:21 +02:00
|
|
|
}
|
2009-10-02 11:15:10 +02:00
|
|
|
return 0;
|
2003-06-05 09:14:21 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static int
|
2009-10-02 11:15:10 +02:00
|
|
|
parse_comment (IOBUF inp, int pkttype, unsigned long pktlen, PACKET * packet)
|
2003-06-05 09:14:21 +02:00
|
|
|
{
|
2009-10-02 11:15:10 +02:00
|
|
|
byte *p;
|
2003-06-05 09:14:21 +02:00
|
|
|
|
2009-10-02 11:15:10 +02:00
|
|
|
/* Cap comment packet at a reasonable value to avoid an integer
|
|
|
|
overflow in the malloc below. Comment packets are actually not
|
|
|
|
anymore define my OpenPGP and we even stopped to use our
|
|
|
|
private comment packet. */
|
|
|
|
if (pktlen > 65536)
|
|
|
|
{
|
|
|
|
log_error ("packet(%d) too large\n", pkttype);
|
|
|
|
iobuf_skip_rest (inp, pktlen, 0);
|
|
|
|
return G10ERR_INVALID_PACKET;
|
|
|
|
}
|
|
|
|
packet->pkt.comment = xmalloc (sizeof *packet->pkt.comment + pktlen - 1);
|
|
|
|
packet->pkt.comment->len = pktlen;
|
|
|
|
p = packet->pkt.comment->data;
|
|
|
|
for (; pktlen; pktlen--, p++)
|
|
|
|
*p = iobuf_get_noeof (inp);
|
|
|
|
|
|
|
|
if (list_mode)
|
|
|
|
{
|
|
|
|
int n = packet->pkt.comment->len;
|
2010-03-15 12:15:45 +01:00
|
|
|
es_fprintf (listfp, ":%scomment packet: \"", pkttype == PKT_OLD_COMMENT ?
|
|
|
|
"OpenPGP draft " : "");
|
2009-10-02 11:15:10 +02:00
|
|
|
for (p = packet->pkt.comment->data; n; p++, n--)
|
|
|
|
{
|
|
|
|
if (*p >= ' ' && *p <= 'z')
|
2010-03-15 12:15:45 +01:00
|
|
|
es_putc (*p, listfp);
|
2009-10-02 11:15:10 +02:00
|
|
|
else
|
2010-03-15 12:15:45 +01:00
|
|
|
es_fprintf (listfp, "\\x%02x", *p);
|
2003-06-05 09:14:21 +02:00
|
|
|
}
|
2010-03-15 12:15:45 +01:00
|
|
|
es_fprintf (listfp, "\"\n");
|
2003-06-05 09:14:21 +02:00
|
|
|
}
|
2009-10-02 11:15:10 +02:00
|
|
|
return 0;
|
2003-06-05 09:14:21 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static void
|
2009-10-02 11:15:10 +02:00
|
|
|
parse_trust (IOBUF inp, int pkttype, unsigned long pktlen, PACKET * pkt)
|
2003-06-05 09:14:21 +02:00
|
|
|
{
|
|
|
|
int c;
|
|
|
|
|
2009-10-02 11:15:10 +02:00
|
|
|
(void) pkttype;
|
2008-10-20 15:53:23 +02:00
|
|
|
|
2003-06-05 09:14:21 +02:00
|
|
|
if (pktlen)
|
|
|
|
{
|
2009-10-02 11:15:10 +02:00
|
|
|
c = iobuf_get_noeof (inp);
|
2003-06-05 09:14:21 +02:00
|
|
|
pktlen--;
|
2009-10-02 11:15:10 +02:00
|
|
|
pkt->pkt.ring_trust = xmalloc (sizeof *pkt->pkt.ring_trust);
|
2003-06-05 09:14:21 +02:00
|
|
|
pkt->pkt.ring_trust->trustval = c;
|
|
|
|
pkt->pkt.ring_trust->sigcache = 0;
|
2009-10-02 11:15:10 +02:00
|
|
|
if (!c && pktlen == 1)
|
|
|
|
{
|
|
|
|
c = iobuf_get_noeof (inp);
|
|
|
|
pktlen--;
|
|
|
|
/* We require that bit 7 of the sigcache is 0 (easier eof
|
|
|
|
handling). */
|
|
|
|
if (!(c & 0x80))
|
|
|
|
pkt->pkt.ring_trust->sigcache = c;
|
|
|
|
}
|
|
|
|
if (list_mode)
|
2010-03-15 12:15:45 +01:00
|
|
|
es_fprintf (listfp, ":trust packet: flag=%02x sigcache=%02x\n",
|
|
|
|
pkt->pkt.ring_trust->trustval,
|
|
|
|
pkt->pkt.ring_trust->sigcache);
|
2003-06-05 09:14:21 +02:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2009-10-02 11:15:10 +02:00
|
|
|
if (list_mode)
|
2010-03-15 12:15:45 +01:00
|
|
|
es_fprintf (listfp, ":trust packet: empty\n");
|
2003-06-05 09:14:21 +02:00
|
|
|
}
|
2006-04-19 13:26:11 +02:00
|
|
|
iobuf_skip_rest (inp, pktlen, 0);
|
2003-06-05 09:14:21 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static int
|
2009-10-02 11:15:10 +02:00
|
|
|
parse_plaintext (IOBUF inp, int pkttype, unsigned long pktlen,
|
|
|
|
PACKET * pkt, int new_ctb, int partial)
|
2003-06-05 09:14:21 +02:00
|
|
|
{
|
2009-10-02 11:15:10 +02:00
|
|
|
int rc = 0;
|
|
|
|
int mode, namelen;
|
|
|
|
PKT_plaintext *pt;
|
|
|
|
byte *p;
|
|
|
|
int c, i;
|
|
|
|
|
|
|
|
if (!partial && pktlen < 6)
|
|
|
|
{
|
|
|
|
log_error ("packet(%d) too short (%lu)\n", pkttype, (ulong) pktlen);
|
|
|
|
rc = gpg_error (GPG_ERR_INV_PACKET);
|
|
|
|
goto leave;
|
2003-06-05 09:14:21 +02:00
|
|
|
}
|
2009-10-02 11:15:10 +02:00
|
|
|
mode = iobuf_get_noeof (inp);
|
|
|
|
if (pktlen)
|
|
|
|
pktlen--;
|
|
|
|
namelen = iobuf_get_noeof (inp);
|
|
|
|
if (pktlen)
|
|
|
|
pktlen--;
|
|
|
|
/* Note that namelen will never exceed 255 bytes. */
|
|
|
|
pt = pkt->pkt.plaintext =
|
|
|
|
xmalloc (sizeof *pkt->pkt.plaintext + namelen - 1);
|
|
|
|
pt->new_ctb = new_ctb;
|
|
|
|
pt->mode = mode;
|
|
|
|
pt->namelen = namelen;
|
|
|
|
pt->is_partial = partial;
|
|
|
|
if (pktlen)
|
|
|
|
{
|
|
|
|
for (i = 0; pktlen > 4 && i < namelen; pktlen--, i++)
|
|
|
|
pt->name[i] = iobuf_get_noeof (inp);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
for (i = 0; i < namelen; i++)
|
|
|
|
if ((c = iobuf_get (inp)) == -1)
|
|
|
|
break;
|
|
|
|
else
|
|
|
|
pt->name[i] = c;
|
2003-06-05 09:14:21 +02:00
|
|
|
}
|
2009-10-02 11:15:10 +02:00
|
|
|
pt->timestamp = read_32 (inp);
|
|
|
|
if (pktlen)
|
|
|
|
pktlen -= 4;
|
|
|
|
pt->len = pktlen;
|
|
|
|
pt->buf = inp;
|
|
|
|
pktlen = 0;
|
2003-06-05 09:14:21 +02:00
|
|
|
|
2009-10-02 11:15:10 +02:00
|
|
|
if (list_mode)
|
|
|
|
{
|
2010-03-15 12:15:45 +01:00
|
|
|
es_fprintf (listfp, ":literal data packet:\n"
|
|
|
|
"\tmode %c (%X), created %lu, name=\"",
|
|
|
|
mode >= ' ' && mode < 'z' ? mode : '?', mode,
|
|
|
|
(ulong) pt->timestamp);
|
2009-10-02 11:15:10 +02:00
|
|
|
for (p = pt->name, i = 0; i < namelen; p++, i++)
|
|
|
|
{
|
|
|
|
if (*p >= ' ' && *p <= 'z')
|
2010-03-15 12:15:45 +01:00
|
|
|
es_putc (*p, listfp);
|
2009-10-02 11:15:10 +02:00
|
|
|
else
|
2010-03-15 12:15:45 +01:00
|
|
|
es_fprintf (listfp, "\\x%02x", *p);
|
2003-06-05 09:14:21 +02:00
|
|
|
}
|
2010-03-15 12:15:45 +01:00
|
|
|
es_fprintf (listfp, "\",\n\traw data: ");
|
2009-10-02 11:15:10 +02:00
|
|
|
if (partial)
|
2010-03-15 12:15:45 +01:00
|
|
|
es_fprintf (listfp, "unknown length\n");
|
2009-10-02 11:15:10 +02:00
|
|
|
else
|
2010-03-15 12:15:45 +01:00
|
|
|
es_fprintf (listfp, "%lu bytes\n", (ulong) pt->len);
|
2003-06-05 09:14:21 +02:00
|
|
|
}
|
|
|
|
|
2009-10-02 11:15:10 +02:00
|
|
|
leave:
|
|
|
|
return rc;
|
2003-06-05 09:14:21 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static int
|
2009-10-02 11:15:10 +02:00
|
|
|
parse_compressed (IOBUF inp, int pkttype, unsigned long pktlen,
|
|
|
|
PACKET * pkt, int new_ctb)
|
2003-06-05 09:14:21 +02:00
|
|
|
{
|
2008-10-20 15:53:23 +02:00
|
|
|
PKT_compressed *zd;
|
2009-10-02 11:15:10 +02:00
|
|
|
|
2008-10-20 15:53:23 +02:00
|
|
|
/* PKTLEN is here 0, but data follows (this should be the last
|
|
|
|
object in a file or the compress algorithm should know the
|
|
|
|
length). */
|
2009-10-02 11:15:10 +02:00
|
|
|
(void) pkttype;
|
|
|
|
(void) pktlen;
|
2008-10-20 15:53:23 +02:00
|
|
|
|
|
|
|
zd = pkt->pkt.compressed = xmalloc (sizeof *pkt->pkt.compressed);
|
2009-10-02 11:15:10 +02:00
|
|
|
zd->algorithm = iobuf_get_noeof (inp);
|
|
|
|
zd->len = 0; /* not used */
|
2008-10-20 15:53:23 +02:00
|
|
|
zd->new_ctb = new_ctb;
|
|
|
|
zd->buf = inp;
|
|
|
|
if (list_mode)
|
2010-03-15 12:15:45 +01:00
|
|
|
es_fprintf (listfp, ":compressed packet: algo=%d\n", zd->algorithm);
|
2008-10-20 15:53:23 +02:00
|
|
|
return 0;
|
2003-06-05 09:14:21 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static int
|
2009-10-02 11:15:10 +02:00
|
|
|
parse_encrypted (IOBUF inp, int pkttype, unsigned long pktlen,
|
|
|
|
PACKET * pkt, int new_ctb, int partial)
|
2003-06-05 09:14:21 +02:00
|
|
|
{
|
2009-10-02 11:15:10 +02:00
|
|
|
int rc = 0;
|
|
|
|
PKT_encrypted *ed;
|
|
|
|
unsigned long orig_pktlen = pktlen;
|
|
|
|
|
|
|
|
ed = pkt->pkt.encrypted = xmalloc (sizeof *pkt->pkt.encrypted);
|
2009-10-02 14:31:14 +02:00
|
|
|
/* ed->len is set below. */
|
|
|
|
ed->extralen = 0; /* Unknown here; only used in build_packet. */
|
2009-10-02 11:15:10 +02:00
|
|
|
ed->buf = NULL;
|
|
|
|
ed->new_ctb = new_ctb;
|
|
|
|
ed->is_partial = partial;
|
|
|
|
if (pkttype == PKT_ENCRYPTED_MDC)
|
|
|
|
{
|
|
|
|
/* Fixme: add some pktlen sanity checks. */
|
|
|
|
int version;
|
|
|
|
|
|
|
|
version = iobuf_get_noeof (inp);
|
|
|
|
if (orig_pktlen)
|
|
|
|
pktlen--;
|
|
|
|
if (version != 1)
|
|
|
|
{
|
|
|
|
log_error ("encrypted_mdc packet with unknown version %d\n",
|
|
|
|
version);
|
|
|
|
/*skip_rest(inp, pktlen); should we really do this? */
|
|
|
|
rc = gpg_error (GPG_ERR_INV_PACKET);
|
|
|
|
goto leave;
|
2003-06-05 09:14:21 +02:00
|
|
|
}
|
2009-10-02 11:15:10 +02:00
|
|
|
ed->mdc_method = DIGEST_ALGO_SHA1;
|
2003-06-05 09:14:21 +02:00
|
|
|
}
|
2009-10-02 14:31:14 +02:00
|
|
|
else
|
|
|
|
ed->mdc_method = 0;
|
|
|
|
|
|
|
|
/* A basic sanity check. We need at least an 8 byte IV plus the 2
|
|
|
|
detection bytes. Note that we don't known the algorithm and thus
|
|
|
|
we may only check against the minimum blocksize. */
|
2009-10-02 11:15:10 +02:00
|
|
|
if (orig_pktlen && pktlen < 10)
|
|
|
|
{
|
|
|
|
/* Actually this is blocksize+2. */
|
|
|
|
log_error ("packet(%d) too short\n", pkttype);
|
|
|
|
rc = G10ERR_INVALID_PACKET;
|
|
|
|
iobuf_skip_rest (inp, pktlen, partial);
|
|
|
|
goto leave;
|
2003-06-05 09:14:21 +02:00
|
|
|
}
|
2009-10-02 14:31:14 +02:00
|
|
|
|
|
|
|
/* Store the remaining length of the encrypted data (i.e. without
|
|
|
|
the MDC version number but with the IV etc.). This value is
|
|
|
|
required during decryption. */
|
|
|
|
ed->len = pktlen;
|
|
|
|
|
2009-10-02 11:15:10 +02:00
|
|
|
if (list_mode)
|
|
|
|
{
|
|
|
|
if (orig_pktlen)
|
2010-03-15 12:15:45 +01:00
|
|
|
es_fprintf (listfp, ":encrypted data packet:\n\tlength: %lu\n",
|
|
|
|
orig_pktlen);
|
2009-10-02 11:15:10 +02:00
|
|
|
else
|
2010-03-15 12:15:45 +01:00
|
|
|
es_fprintf (listfp, ":encrypted data packet:\n\tlength: unknown\n");
|
2009-10-02 11:15:10 +02:00
|
|
|
if (ed->mdc_method)
|
2010-03-15 12:15:45 +01:00
|
|
|
es_fprintf (listfp, "\tmdc_method: %d\n", ed->mdc_method);
|
2003-06-05 09:14:21 +02:00
|
|
|
}
|
|
|
|
|
2009-10-02 11:15:10 +02:00
|
|
|
ed->buf = inp;
|
2003-06-05 09:14:21 +02:00
|
|
|
|
2009-10-02 11:15:10 +02:00
|
|
|
leave:
|
|
|
|
return rc;
|
2003-06-05 09:14:21 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2009-10-02 11:15:10 +02:00
|
|
|
/* Note, that this code is not anymore used in real life because the
|
|
|
|
MDC checking is now done right after the decryption in
|
|
|
|
decrypt_data. */
|
2003-06-05 09:14:21 +02:00
|
|
|
static int
|
2008-10-20 15:53:23 +02:00
|
|
|
parse_mdc (IOBUF inp, int pkttype, unsigned long pktlen,
|
2009-10-02 11:15:10 +02:00
|
|
|
PACKET * pkt, int new_ctb)
|
2003-06-05 09:14:21 +02:00
|
|
|
{
|
2008-10-20 15:53:23 +02:00
|
|
|
int rc = 0;
|
|
|
|
PKT_mdc *mdc;
|
|
|
|
byte *p;
|
2003-06-05 09:14:21 +02:00
|
|
|
|
2009-10-02 11:15:10 +02:00
|
|
|
(void) pkttype;
|
2003-06-05 09:14:21 +02:00
|
|
|
|
2009-10-02 11:15:10 +02:00
|
|
|
mdc = pkt->pkt.mdc = xmalloc (sizeof *pkt->pkt.mdc);
|
2008-10-20 15:53:23 +02:00
|
|
|
if (list_mode)
|
2010-03-15 12:15:45 +01:00
|
|
|
es_fprintf (listfp, ":mdc packet: length=%lu\n", pktlen);
|
2008-10-20 15:53:23 +02:00
|
|
|
if (!new_ctb || pktlen != 20)
|
|
|
|
{
|
2009-10-02 11:15:10 +02:00
|
|
|
log_error ("mdc_packet with invalid encoding\n");
|
2008-10-20 15:53:23 +02:00
|
|
|
rc = gpg_error (GPG_ERR_INV_PACKET);
|
|
|
|
goto leave;
|
|
|
|
}
|
|
|
|
p = mdc->hash;
|
|
|
|
for (; pktlen; pktlen--, p++)
|
2009-10-02 11:15:10 +02:00
|
|
|
*p = iobuf_get_noeof (inp);
|
|
|
|
|
2008-10-20 15:53:23 +02:00
|
|
|
leave:
|
|
|
|
return rc;
|
2003-06-05 09:14:21 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
2009-10-02 11:15:10 +02:00
|
|
|
* This packet is internally generated by us (ibn armor.c) to transfer
|
|
|
|
* some information to the lower layer. To make sure that this packet
|
|
|
|
* is really a GPG faked one and not one comming from outside, we
|
|
|
|
* first check that there is a unique tag in it.
|
|
|
|
*
|
2003-06-05 09:14:21 +02:00
|
|
|
* The format of such a control packet is:
|
|
|
|
* n byte session marker
|
|
|
|
* 1 byte control type CTRLPKT_xxxxx
|
|
|
|
* m byte control data
|
|
|
|
*/
|
|
|
|
static int
|
2008-10-20 15:53:23 +02:00
|
|
|
parse_gpg_control (IOBUF inp, int pkttype, unsigned long pktlen,
|
2009-10-02 11:15:10 +02:00
|
|
|
PACKET * packet, int partial)
|
2003-06-05 09:14:21 +02:00
|
|
|
{
|
2009-10-02 11:15:10 +02:00
|
|
|
byte *p;
|
|
|
|
const byte *sesmark;
|
|
|
|
size_t sesmarklen;
|
|
|
|
int i;
|
|
|
|
|
|
|
|
(void) pkttype;
|
|
|
|
|
|
|
|
if (list_mode)
|
2010-03-15 12:15:45 +01:00
|
|
|
es_fprintf (listfp, ":packet 63: length %lu ", pktlen);
|
2009-10-02 11:15:10 +02:00
|
|
|
|
|
|
|
sesmark = get_session_marker (&sesmarklen);
|
|
|
|
if (pktlen < sesmarklen + 1) /* 1 is for the control bytes */
|
|
|
|
goto skipit;
|
|
|
|
for (i = 0; i < sesmarklen; i++, pktlen--)
|
|
|
|
{
|
|
|
|
if (sesmark[i] != iobuf_get_noeof (inp))
|
|
|
|
goto skipit;
|
|
|
|
}
|
|
|
|
if (pktlen > 4096)
|
|
|
|
goto skipit; /* Definitely too large. We skip it to avoid an
|
|
|
|
overflow in the malloc. */
|
|
|
|
if (list_mode)
|
|
|
|
puts ("- gpg control packet");
|
|
|
|
|
|
|
|
packet->pkt.gpg_control = xmalloc (sizeof *packet->pkt.gpg_control
|
|
|
|
+ pktlen - 1);
|
|
|
|
packet->pkt.gpg_control->control = iobuf_get_noeof (inp);
|
|
|
|
pktlen--;
|
|
|
|
packet->pkt.gpg_control->datalen = pktlen;
|
|
|
|
p = packet->pkt.gpg_control->data;
|
|
|
|
for (; pktlen; pktlen--, p++)
|
|
|
|
*p = iobuf_get_noeof (inp);
|
|
|
|
|
|
|
|
return 0;
|
2003-06-05 09:14:21 +02:00
|
|
|
|
|
|
|
skipit:
|
2009-10-02 11:15:10 +02:00
|
|
|
if (list_mode)
|
|
|
|
{
|
|
|
|
int c;
|
|
|
|
|
|
|
|
i = 0;
|
2010-03-15 12:15:45 +01:00
|
|
|
es_fprintf (listfp, "- private (rest length %lu)\n", pktlen);
|
2009-10-02 11:15:10 +02:00
|
|
|
if (partial)
|
|
|
|
{
|
|
|
|
while ((c = iobuf_get (inp)) != -1)
|
|
|
|
dump_hex_line (c, &i);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
for (; pktlen; pktlen--)
|
|
|
|
{
|
|
|
|
dump_hex_line ((c = iobuf_get (inp)), &i);
|
|
|
|
if (c == -1)
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
2010-03-15 12:15:45 +01:00
|
|
|
es_putc ('\n', listfp);
|
2003-06-05 09:14:21 +02:00
|
|
|
}
|
2009-10-02 11:15:10 +02:00
|
|
|
iobuf_skip_rest (inp, pktlen, 0);
|
|
|
|
return gpg_error (GPG_ERR_INV_PACKET);
|
2003-06-05 09:14:21 +02:00
|
|
|
}
|
|
|
|
|
2009-10-02 11:15:10 +02:00
|
|
|
|
|
|
|
/* Create a GPG control packet to be used internally as a placeholder. */
|
2003-06-05 09:14:21 +02:00
|
|
|
PACKET *
|
2009-10-02 11:15:10 +02:00
|
|
|
create_gpg_control (ctrlpkttype_t type, const byte * data, size_t datalen)
|
2003-06-05 09:14:21 +02:00
|
|
|
{
|
2009-10-02 11:15:10 +02:00
|
|
|
PACKET *packet;
|
|
|
|
byte *p;
|
|
|
|
|
|
|
|
packet = xmalloc (sizeof *packet);
|
|
|
|
init_packet (packet);
|
|
|
|
packet->pkttype = PKT_GPG_CONTROL;
|
|
|
|
packet->pkt.gpg_control = xmalloc (sizeof *packet->pkt.gpg_control
|
|
|
|
+ datalen - 1);
|
|
|
|
packet->pkt.gpg_control->control = type;
|
|
|
|
packet->pkt.gpg_control->datalen = datalen;
|
|
|
|
p = packet->pkt.gpg_control->data;
|
|
|
|
for (; datalen; datalen--, p++)
|
|
|
|
*p = *data++;
|
|
|
|
|
|
|
|
return packet;
|
2003-06-05 09:14:21 +02:00
|
|
|
}
|