diff --git a/g10/keyring.c b/g10/keyring.c
index e223f0f98..50f1b824c 100644
--- a/g10/keyring.c
+++ b/g10/keyring.c
@@ -1,1741 +1,1741 @@
/* keyring.c - keyring file handling
* Copyright (C) 1998-2010 Free Software Foundation, Inc.
* Copyright (C) 1997-2015 Werner Koch
*
* 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
* the Free Software Foundation; either version 3 of the License, or
* (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
* along with this program; if not, see .
*/
#include
#include
#include
#include
#include
#include
#include
#include
#include "gpg.h"
#include "../common/util.h"
#include "keyring.h"
#include "packet.h"
#include "keydb.h"
#include "options.h"
#include "main.h" /*for check_key_signature()*/
#include "../common/i18n.h"
#include "../kbx/keybox.h"
typedef struct keyring_resource *KR_RESOURCE;
struct keyring_resource
{
struct keyring_resource *next;
int read_only;
dotlock_t lockhd;
int is_locked;
int did_full_scan;
char fname[1];
};
typedef struct keyring_resource const * CONST_KR_RESOURCE;
static KR_RESOURCE kr_resources;
struct keyring_handle
{
CONST_KR_RESOURCE resource;
struct {
CONST_KR_RESOURCE kr;
IOBUF iobuf;
int eof;
int error;
} current;
struct {
CONST_KR_RESOURCE kr;
off_t offset;
size_t pk_no;
size_t uid_no;
unsigned int n_packets; /*used for delete and update*/
} found, saved_found;
struct {
char *name;
char *pattern;
} word_match;
};
/* The number of extant handles. */
static int active_handles;
static int do_copy (int mode, const char *fname, KBNODE root,
off_t start_offset, unsigned int n_packets );
/* We keep a cache of entries that we have entered in the DB. This
includes not only public keys, but also subkeys.
Note: we'd like to keep the offset of the items that are present,
however, this doesn't work, because another concurrent GnuPG
process could modify the keyring. */
struct key_present {
struct key_present *next;
u32 kid[2];
};
/* For the hash table, we use separate chaining with linked lists.
This means that we have an array of N linked lists (buckets), which
is indexed by KEYID[1] mod N. Elements present in the keyring will
be on the list; elements not present in the keyring will not be on
the list.
Note: since the hash table stores both present and not present
information, it cannot be used until we complete a full scan of the
keyring. This is indicated by key_present_hash_ready. */
typedef struct key_present **key_present_hash_t;
static key_present_hash_t key_present_hash;
static int key_present_hash_ready;
#define KEY_PRESENT_HASH_BUCKETS 2048
/* Allocate a new value for a key present hash table. */
static struct key_present *
key_present_value_new (void)
{
struct key_present *k;
k = xmalloc_clear (sizeof *k);
return k;
}
/* Allocate a new key present hash table. */
static key_present_hash_t
key_present_hash_new (void)
{
struct key_present **tbl;
tbl = xmalloc_clear (KEY_PRESENT_HASH_BUCKETS * sizeof *tbl);
return tbl;
}
/* Return whether the value described by KID if it is in the hash
table. Otherwise, return NULL. */
static struct key_present *
key_present_hash_lookup (key_present_hash_t tbl, u32 *kid)
{
struct key_present *k;
for (k = tbl[(kid[1] % (KEY_PRESENT_HASH_BUCKETS - 1))]; k; k = k->next)
if (k->kid[0] == kid[0] && k->kid[1] == kid[1])
return k;
return NULL;
}
/* Add the key to the hash table TBL if it is not already present. */
static void
key_present_hash_update (key_present_hash_t tbl, u32 *kid)
{
struct key_present *k;
for (k = tbl[(kid[1] % (KEY_PRESENT_HASH_BUCKETS - 1))]; k; k = k->next)
{
if (k->kid[0] == kid[0] && k->kid[1] == kid[1])
return;
}
k = key_present_value_new ();
k->kid[0] = kid[0];
k->kid[1] = kid[1];
k->next = tbl[(kid[1] % (KEY_PRESENT_HASH_BUCKETS - 1))];
tbl[(kid[1] % (KEY_PRESENT_HASH_BUCKETS - 1))] = k;
}
/* Add all the keys (public and subkeys) present in the keyblock to
the hash TBL. */
static void
key_present_hash_update_from_kb (key_present_hash_t tbl, KBNODE node)
{
for (; node; node = node->next)
{
if (node->pkt->pkttype == PKT_PUBLIC_KEY
|| node->pkt->pkttype == PKT_PUBLIC_SUBKEY)
{
u32 aki[2];
keyid_from_pk (node->pkt->pkt.public_key, aki);
key_present_hash_update (tbl, aki);
}
}
}
/*
* Register a filename for plain keyring files. ptr is set to a
* pointer to be used to create a handles etc, or the already-issued
* pointer if it has already been registered. The function returns 1
* if a new keyring was registered.
*/
int
keyring_register_filename (const char *fname, int read_only, void **ptr)
{
KR_RESOURCE kr;
if (active_handles)
/* There are open handles. */
BUG ();
for (kr=kr_resources; kr; kr = kr->next)
{
if (same_file_p (kr->fname, fname))
{
/* Already registered. */
if (read_only)
kr->read_only = 1;
*ptr=kr;
return 0;
}
}
kr = xmalloc (sizeof *kr + strlen (fname));
strcpy (kr->fname, fname);
kr->read_only = read_only;
kr->lockhd = NULL;
kr->is_locked = 0;
kr->did_full_scan = 0;
/* keep a list of all issued pointers */
kr->next = kr_resources;
kr_resources = kr;
/* create the offset table the first time a function here is used */
if (!key_present_hash)
key_present_hash = key_present_hash_new ();
*ptr=kr;
return 1;
}
int
keyring_is_writable (void *token)
{
KR_RESOURCE r = token;
return r? (r->read_only || !access (r->fname, W_OK)) : 0;
}
/* Create a new handle for the resource associated with TOKEN.
On error NULL is returned and ERRNO is set.
The returned handle must be released using keyring_release (). */
KEYRING_HANDLE
keyring_new (void *token)
{
KEYRING_HANDLE hd;
KR_RESOURCE resource = token;
log_assert (resource);
hd = xtrycalloc (1, sizeof *hd);
if (!hd)
return hd;
hd->resource = resource;
active_handles++;
return hd;
}
void
keyring_release (KEYRING_HANDLE hd)
{
if (!hd)
return;
log_assert (active_handles > 0);
active_handles--;
xfree (hd->word_match.name);
xfree (hd->word_match.pattern);
iobuf_close (hd->current.iobuf);
xfree (hd);
}
/* Save the current found state in HD for later retrieval by
keybox_pop_found_state. Only one state may be saved. */
void
keyring_push_found_state (KEYRING_HANDLE hd)
{
hd->saved_found = hd->found;
hd->found.kr = NULL;
}
/* Restore the saved found state in HD. */
void
keyring_pop_found_state (KEYRING_HANDLE hd)
{
hd->found = hd->saved_found;
hd->saved_found.kr = NULL;
}
const char *
keyring_get_resource_name (KEYRING_HANDLE hd)
{
if (!hd || !hd->resource)
return NULL;
return hd->resource->fname;
}
/*
* Lock the keyring with the given handle, or unlock if YES is false.
* We ignore the handle and lock all registered files.
*/
int
keyring_lock (KEYRING_HANDLE hd, int yes)
{
KR_RESOURCE kr;
int rc = 0;
(void)hd;
if (yes) {
/* first make sure the lock handles are created */
for (kr=kr_resources; kr; kr = kr->next) {
if (!keyring_is_writable(kr))
continue;
if (!kr->lockhd) {
kr->lockhd = dotlock_create (kr->fname, 0);
if (!kr->lockhd) {
log_info ("can't allocate lock for '%s'\n", kr->fname );
rc = GPG_ERR_GENERAL;
}
}
}
if (rc)
return rc;
/* and now set the locks */
for (kr=kr_resources; kr; kr = kr->next) {
if (!keyring_is_writable(kr))
continue;
if (kr->is_locked)
continue;
#ifdef HAVE_W32_SYSTEM
/* Under Windows we need to CloseHandle the file before we
* try to lock it. This is because another process might
* have taken the lock and is using keybox_file_rename to
* rename the base file. How if our dotlock_take below is
* waiting for the lock but we have the base file still
* open, keybox_file_rename will never succeed as we are
* in a deadlock. */
iobuf_ioctl (NULL, IOBUF_IOCTL_INVALIDATE_CACHE, 0,
(char*)kr->fname);
#endif /*HAVE_W32_SYSTEM*/
if (dotlock_take (kr->lockhd, -1) ) {
log_info ("can't lock '%s'\n", kr->fname );
rc = GPG_ERR_GENERAL;
}
else
kr->is_locked = 1;
}
}
if (rc || !yes) {
for (kr=kr_resources; kr; kr = kr->next) {
if (!keyring_is_writable(kr))
continue;
if (!kr->is_locked)
continue;
if (dotlock_release (kr->lockhd))
log_info ("can't unlock '%s'\n", kr->fname );
else
kr->is_locked = 0;
}
}
return rc;
}
/*
* Return the last found keyblock. Caller must free it.
* The returned keyblock has the kbode flag bit 0 set for the node with
* the public key used to locate the keyblock or flag bit 1 set for
* the user ID node.
*/
int
keyring_get_keyblock (KEYRING_HANDLE hd, KBNODE *ret_kb)
{
PACKET *pkt;
struct parse_packet_ctx_s parsectx;
int rc;
KBNODE keyblock = NULL, node, lastnode;
IOBUF a;
int in_cert = 0;
int pk_no = 0;
int uid_no = 0;
int save_mode;
if (ret_kb)
*ret_kb = NULL;
if (!hd->found.kr)
return -1; /* no successful search */
a = iobuf_open (hd->found.kr->fname);
if (!a)
{
log_error(_("can't open '%s'\n"), hd->found.kr->fname);
return GPG_ERR_KEYRING_OPEN;
}
if (iobuf_seek (a, hd->found.offset) ) {
log_error ("can't seek '%s'\n", hd->found.kr->fname);
iobuf_close(a);
return GPG_ERR_KEYRING_OPEN;
}
pkt = xmalloc (sizeof *pkt);
init_packet (pkt);
init_parse_packet (&parsectx, a);
- hd->found.n_packets = 0;;
+ hd->found.n_packets = 0;
lastnode = NULL;
save_mode = set_packet_list_mode(0);
while ((rc=parse_packet (&parsectx, pkt)) != -1) {
- hd->found.n_packets++;
+ hd->found.n_packets = parsectx.n_parsed_packets;
if (gpg_err_code (rc) == GPG_ERR_UNKNOWN_PACKET) {
free_packet (pkt, &parsectx);
init_packet (pkt);
continue;
}
if (gpg_err_code (rc) == GPG_ERR_LEGACY_KEY)
{
if (in_cert)
/* It is not this key that is problematic, but the
following key. */
{
rc = 0;
hd->found.n_packets --;
}
else
/* Upper layer needs to handle this. */
{
}
break;
}
if (rc) {
log_error ("keyring_get_keyblock: read error: %s\n",
gpg_strerror (rc) );
rc = GPG_ERR_INV_KEYRING;
break;
}
/* Filter allowed packets. */
switch (pkt->pkttype)
{
case PKT_PUBLIC_KEY:
case PKT_PUBLIC_SUBKEY:
case PKT_SECRET_KEY:
case PKT_SECRET_SUBKEY:
case PKT_USER_ID:
case PKT_ATTRIBUTE:
case PKT_SIGNATURE:
break; /* Allowed per RFC. */
case PKT_RING_TRUST:
case PKT_OLD_COMMENT:
case PKT_COMMENT:
case PKT_GPG_CONTROL:
break; /* Allowed by us. */
default:
log_error ("skipped packet of type %d in keyring\n",
(int)pkt->pkttype);
free_packet(pkt, &parsectx);
init_packet(pkt);
continue;
}
if (in_cert && (pkt->pkttype == PKT_PUBLIC_KEY
|| pkt->pkttype == PKT_SECRET_KEY)) {
hd->found.n_packets--; /* fix counter */
break; /* ready */
}
in_cert = 1;
node = lastnode = new_kbnode (pkt);
if (!keyblock)
keyblock = node;
else
add_kbnode (keyblock, node);
switch (pkt->pkttype)
{
case PKT_PUBLIC_KEY:
case PKT_PUBLIC_SUBKEY:
case PKT_SECRET_KEY:
case PKT_SECRET_SUBKEY:
if (++pk_no == hd->found.pk_no)
node->flag |= 1;
break;
case PKT_USER_ID:
if (++uid_no == hd->found.uid_no)
node->flag |= 2;
break;
default:
break;
}
pkt = xmalloc (sizeof *pkt);
init_packet(pkt);
}
set_packet_list_mode(save_mode);
if (rc == -1 && keyblock)
rc = 0; /* got the entire keyblock */
if (rc || !ret_kb)
release_kbnode (keyblock);
else {
*ret_kb = keyblock;
}
free_packet (pkt, &parsectx);
deinit_parse_packet (&parsectx);
xfree (pkt);
iobuf_close(a);
/* Make sure that future search operations fail immediately when
* we know that we are working on a invalid keyring
*/
if (gpg_err_code (rc) == GPG_ERR_INV_KEYRING)
hd->current.error = rc;
return rc;
}
int
keyring_update_keyblock (KEYRING_HANDLE hd, KBNODE kb)
{
int rc;
if (!hd->found.kr)
return -1; /* no successful prior search */
if (hd->found.kr->read_only)
return gpg_error (GPG_ERR_EACCES);
if (!hd->found.n_packets) {
/* need to know the number of packets - do a dummy get_keyblock*/
rc = keyring_get_keyblock (hd, NULL);
if (rc) {
log_error ("re-reading keyblock failed: %s\n", gpg_strerror (rc));
return rc;
}
if (!hd->found.n_packets)
BUG ();
}
/* The open iobuf isn't needed anymore and in fact is a problem when
it comes to renaming the keyring files on some operating systems,
so close it here */
iobuf_close(hd->current.iobuf);
hd->current.iobuf = NULL;
/* do the update */
rc = do_copy (3, hd->found.kr->fname, kb,
hd->found.offset, hd->found.n_packets );
if (!rc) {
if (key_present_hash)
{
key_present_hash_update_from_kb (key_present_hash, kb);
}
/* better reset the found info */
hd->found.kr = NULL;
hd->found.offset = 0;
}
return rc;
}
int
keyring_insert_keyblock (KEYRING_HANDLE hd, KBNODE kb)
{
int rc;
const char *fname;
if (!hd)
fname = NULL;
else if (hd->found.kr)
{
fname = hd->found.kr->fname;
if (hd->found.kr->read_only)
return gpg_error (GPG_ERR_EACCES);
}
else if (hd->current.kr)
{
fname = hd->current.kr->fname;
if (hd->current.kr->read_only)
return gpg_error (GPG_ERR_EACCES);
}
else
fname = hd->resource? hd->resource->fname:NULL;
if (!fname)
return GPG_ERR_GENERAL;
/* Close this one otherwise we will lose the position for
* a next search. Fixme: it would be better to adjust the position
* after the write opertions.
*/
iobuf_close (hd->current.iobuf);
hd->current.iobuf = NULL;
/* do the insert */
rc = do_copy (1, fname, kb, 0, 0 );
if (!rc && key_present_hash)
{
key_present_hash_update_from_kb (key_present_hash, kb);
}
return rc;
}
int
keyring_delete_keyblock (KEYRING_HANDLE hd)
{
int rc;
if (!hd->found.kr)
return -1; /* no successful prior search */
if (hd->found.kr->read_only)
return gpg_error (GPG_ERR_EACCES);
if (!hd->found.n_packets) {
/* need to know the number of packets - do a dummy get_keyblock*/
rc = keyring_get_keyblock (hd, NULL);
if (rc) {
log_error ("re-reading keyblock failed: %s\n", gpg_strerror (rc));
return rc;
}
if (!hd->found.n_packets)
BUG ();
}
/* close this one otherwise we will lose the position for
* a next search. Fixme: it would be better to adjust the position
* after the write opertions.
*/
iobuf_close (hd->current.iobuf);
hd->current.iobuf = NULL;
/* do the delete */
rc = do_copy (2, hd->found.kr->fname, NULL,
hd->found.offset, hd->found.n_packets );
if (!rc) {
/* better reset the found info */
hd->found.kr = NULL;
hd->found.offset = 0;
/* Delete is a rare operations, so we don't remove the keys
* from the offset table */
}
return rc;
}
/*
* Start the next search on this handle right at the beginning
*/
int
keyring_search_reset (KEYRING_HANDLE hd)
{
log_assert (hd);
iobuf_close (hd->current.iobuf);
hd->current.iobuf = NULL;
hd->current.eof = 0;
hd->current.error = 0;
hd->found.kr = NULL;
hd->found.offset = 0;
if (hd->current.kr)
iobuf_ioctl (NULL, IOBUF_IOCTL_INVALIDATE_CACHE, 0,
(char*)hd->current.kr->fname);
hd->current.kr = NULL;
return 0;
}
static int
prepare_search (KEYRING_HANDLE hd)
{
if (hd->current.error) {
/* If the last key was a legacy key, we simply ignore the error so that
we can easily use search_next. */
if (gpg_err_code (hd->current.error) == GPG_ERR_LEGACY_KEY)
{
if (DBG_LOOKUP)
log_debug ("%s: last error was GPG_ERR_LEGACY_KEY, clearing\n",
__func__);
hd->current.error = 0;
}
else
{
if (DBG_LOOKUP)
log_debug ("%s: returning last error: %s\n",
__func__, gpg_strerror (hd->current.error));
return hd->current.error; /* still in error state */
}
}
if (hd->current.kr && !hd->current.eof) {
if ( !hd->current.iobuf )
{
if (DBG_LOOKUP)
log_debug ("%s: missing iobuf!\n", __func__);
return GPG_ERR_GENERAL; /* Position invalid after a modify. */
}
return 0; /* okay */
}
if (!hd->current.kr && hd->current.eof)
{
if (DBG_LOOKUP)
log_debug ("%s: EOF!\n", __func__);
return -1; /* still EOF */
}
if (!hd->current.kr) { /* start search with first keyring */
hd->current.kr = hd->resource;
if (!hd->current.kr) {
if (DBG_LOOKUP)
log_debug ("%s: keyring not available!\n", __func__);
hd->current.eof = 1;
return -1; /* keyring not available */
}
log_assert (!hd->current.iobuf);
}
else { /* EOF */
if (DBG_LOOKUP)
log_debug ("%s: EOF\n", __func__);
iobuf_close (hd->current.iobuf);
hd->current.iobuf = NULL;
hd->current.kr = NULL;
hd->current.eof = 1;
return -1;
}
hd->current.eof = 0;
hd->current.iobuf = iobuf_open (hd->current.kr->fname);
if (!hd->current.iobuf)
{
hd->current.error = gpg_error_from_syserror ();
log_error(_("can't open '%s'\n"), hd->current.kr->fname );
return hd->current.error;
}
return 0;
}
/* A map of the all characters valid used for word_match()
* Valid characters are in this table converted to uppercase.
* because the upper 128 bytes have special meaning, we assume
* that they are all valid.
* Note: We must use numerical values here in case that this program
* will be converted to those little blue HAL9000s with their strange
* EBCDIC character set (user ids are UTF-8).
* wk 2000-04-13: Hmmm, does this really make sense, given the fact that
* we can run gpg now on a S/390 running GNU/Linux, where the code
* translation is done by the device drivers?
*/
static const byte word_match_chars[256] = {
/* 00 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
/* 08 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
/* 10 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
/* 18 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
/* 20 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
/* 28 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
/* 30 */ 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37,
/* 38 */ 0x38, 0x39, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
/* 40 */ 0x00, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47,
/* 48 */ 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f,
/* 50 */ 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57,
/* 58 */ 0x58, 0x59, 0x5a, 0x00, 0x00, 0x00, 0x00, 0x00,
/* 60 */ 0x00, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47,
/* 68 */ 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f,
/* 70 */ 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57,
/* 78 */ 0x58, 0x59, 0x5a, 0x00, 0x00, 0x00, 0x00, 0x00,
/* 80 */ 0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87,
/* 88 */ 0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f,
/* 90 */ 0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97,
/* 98 */ 0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f,
/* a0 */ 0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7,
/* a8 */ 0xa8, 0xa9, 0xaa, 0xab, 0xac, 0xad, 0xae, 0xaf,
/* b0 */ 0xb0, 0xb1, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7,
/* b8 */ 0xb8, 0xb9, 0xba, 0xbb, 0xbc, 0xbd, 0xbe, 0xbf,
/* c0 */ 0xc0, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7,
/* c8 */ 0xc8, 0xc9, 0xca, 0xcb, 0xcc, 0xcd, 0xce, 0xcf,
/* d0 */ 0xd0, 0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7,
/* d8 */ 0xd8, 0xd9, 0xda, 0xdb, 0xdc, 0xdd, 0xde, 0xdf,
/* e0 */ 0xe0, 0xe1, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7,
/* e8 */ 0xe8, 0xe9, 0xea, 0xeb, 0xec, 0xed, 0xee, 0xef,
/* f0 */ 0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7,
/* f8 */ 0xf8, 0xf9, 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xff
};
/****************
* Do a word match (original user id starts with a '+').
* The pattern is already tokenized to a more suitable format:
* There are only the real words in it delimited by one space
* and all converted to uppercase.
*
* Returns: 0 if all words match.
*
* Note: This algorithm is a straightforward one and not very
* fast. It works for UTF-8 strings. The uidlen should
* be removed but due to the fact that old versions of
* pgp don't use UTF-8 we still use the length; this should
* be fixed in parse-packet (and replace \0 by some special
* UTF-8 encoding)
*/
static int
word_match( const byte *uid, size_t uidlen, const byte *pattern )
{
size_t wlen, n;
const byte *p;
const byte *s;
for( s=pattern; *s; ) {
do {
/* skip leading delimiters */
while( uidlen && !word_match_chars[*uid] )
uid++, uidlen--;
/* get length of the word */
n = uidlen; p = uid;
while( n && word_match_chars[*p] )
p++, n--;
wlen = p - uid;
/* and compare against the current word from pattern */
for(n=0, p=uid; n < wlen && s[n] != ' ' && s[n] ; n++, p++ ) {
if( word_match_chars[*p] != s[n] )
break;
}
if( n == wlen && (s[n] == ' ' || !s[n]) )
break; /* found */
uid += wlen;
uidlen -= wlen;
} while( uidlen );
if( !uidlen )
return -1; /* not found */
/* advance to next word in pattern */
for(; *s != ' ' && *s ; s++ )
;
if( *s )
s++ ;
}
return 0; /* found */
}
/****************
* prepare word word_match; that is parse the name and
* build the pattern.
* caller has to free the returned pattern
*/
static char*
prepare_word_match (const byte *name)
{
byte *pattern, *p;
int c;
/* the original length is always enough for the pattern */
p = pattern = xmalloc(strlen(name)+1);
do {
/* skip leading delimiters */
while( *name && !word_match_chars[*name] )
name++;
/* copy as long as we don't have a delimiter and convert
* to uppercase.
* fixme: how can we handle utf8 uppercasing */
for( ; *name && (c=word_match_chars[*name]); name++ )
*p++ = c;
*p++ = ' '; /* append pattern delimiter */
} while( *name );
p[-1] = 0; /* replace last pattern delimiter by EOS */
return pattern;
}
static int
compare_name (int mode, const char *name, const char *uid, size_t uidlen)
{
int i;
const char *s, *se;
if (mode == KEYDB_SEARCH_MODE_EXACT) {
for (i=0; name[i] && uidlen; i++, uidlen--)
if (uid[i] != name[i])
break;
if (!uidlen && !name[i])
return 0; /* found */
}
else if (mode == KEYDB_SEARCH_MODE_SUBSTR) {
if (ascii_memistr( uid, uidlen, name ))
return 0;
}
else if ( mode == KEYDB_SEARCH_MODE_MAIL
|| mode == KEYDB_SEARCH_MODE_MAILSUB
|| mode == KEYDB_SEARCH_MODE_MAILEND) {
int have_angles = 1;
for (i=0, s= uid; i < uidlen && *s != '<'; s++, i++)
;
if (i == uidlen)
{
/* The UID is a plain addr-spec (cf. RFC2822 section 4.3). */
have_angles = 0;
s = uid;
i = 0;
}
if (i < uidlen) {
if (have_angles)
{
/* skip opening delim and one char and look for the closing one*/
s++; i++;
for (se=s+1, i++; i < uidlen && *se != '>'; se++, i++)
;
}
else
se = s + uidlen;
if (i < uidlen) {
i = se - s;
if (mode == KEYDB_SEARCH_MODE_MAIL) {
if( strlen(name)-2 == i
&& !ascii_memcasecmp( s, name+1, i) )
return 0;
}
else if (mode == KEYDB_SEARCH_MODE_MAILSUB) {
if( ascii_memistr( s, i, name ) )
return 0;
}
else { /* email from end */
/* nyi */
}
}
}
}
else if (mode == KEYDB_SEARCH_MODE_WORDS)
return word_match (uid, uidlen, name);
else
BUG();
return -1; /* not found */
}
/*
* Search through the keyring(s), starting at the current position,
* for a keyblock which contains one of the keys described in the DESC array.
*/
int
keyring_search (KEYRING_HANDLE hd, KEYDB_SEARCH_DESC *desc,
size_t ndesc, size_t *descindex, int ignore_legacy)
{
int rc;
PACKET pkt;
struct parse_packet_ctx_s parsectx;
int save_mode;
off_t offset, main_offset;
size_t n;
int need_uid, need_words, need_keyid, need_fpr, any_skip;
int pk_no, uid_no;
int initial_skip;
int scanned_from_start;
int use_key_present_hash;
PKT_user_id *uid = NULL;
PKT_public_key *pk = NULL;
u32 aki[2];
/* figure out what information we need */
need_uid = need_words = need_keyid = need_fpr = any_skip = 0;
for (n=0; n < ndesc; n++)
{
switch (desc[n].mode)
{
case KEYDB_SEARCH_MODE_EXACT:
case KEYDB_SEARCH_MODE_SUBSTR:
case KEYDB_SEARCH_MODE_MAIL:
case KEYDB_SEARCH_MODE_MAILSUB:
case KEYDB_SEARCH_MODE_MAILEND:
need_uid = 1;
break;
case KEYDB_SEARCH_MODE_WORDS:
need_uid = 1;
need_words = 1;
break;
case KEYDB_SEARCH_MODE_SHORT_KID:
case KEYDB_SEARCH_MODE_LONG_KID:
need_keyid = 1;
break;
case KEYDB_SEARCH_MODE_FPR16:
case KEYDB_SEARCH_MODE_FPR20:
case KEYDB_SEARCH_MODE_FPR:
need_fpr = 1;
break;
case KEYDB_SEARCH_MODE_FIRST:
/* always restart the search in this mode */
keyring_search_reset (hd);
break;
default: break;
}
if (desc[n].skipfnc)
{
any_skip = 1;
need_keyid = 1;
}
}
if (DBG_LOOKUP)
log_debug ("%s: need_uid = %d; need_words = %d; need_keyid = %d; need_fpr = %d; any_skip = %d\n",
__func__, need_uid, need_words, need_keyid, need_fpr, any_skip);
rc = prepare_search (hd);
if (rc)
{
if (DBG_LOOKUP)
log_debug ("%s: prepare_search failed: %s (%d)\n",
__func__, gpg_strerror (rc), gpg_err_code (rc));
return rc;
}
use_key_present_hash = !!key_present_hash;
if (!use_key_present_hash)
{
if (DBG_LOOKUP)
log_debug ("%s: no offset table.\n", __func__);
}
else if (!key_present_hash_ready)
{
if (DBG_LOOKUP)
log_debug ("%s: initializing offset table. (need_keyid: %d => 1)\n",
__func__, need_keyid);
need_keyid = 1;
}
else if (ndesc == 1 && desc[0].mode == KEYDB_SEARCH_MODE_LONG_KID)
{
struct key_present *oi;
if (DBG_LOOKUP)
log_debug ("%s: look up by long key id, checking cache\n", __func__);
oi = key_present_hash_lookup (key_present_hash, desc[0].u.kid);
if (!oi)
{ /* We know that we don't have this key */
if (DBG_LOOKUP)
log_debug ("%s: cache says not present\n", __func__);
hd->found.kr = NULL;
hd->current.eof = 1;
return -1;
}
/* We could now create a positive search status and return.
* However the problem is that another instance of gpg may
* have changed the keyring so that the offsets are not valid
* anymore - therefore we don't do it
*/
}
if (need_words)
{
const char *name = NULL;
log_debug ("word search mode does not yet work\n");
/* FIXME: here is a long standing bug in our function and in addition we
just use the first search description */
for (n=0; n < ndesc && !name; n++)
{
if (desc[n].mode == KEYDB_SEARCH_MODE_WORDS)
name = desc[n].u.name;
}
log_assert (name);
if ( !hd->word_match.name || strcmp (hd->word_match.name, name) )
{
/* name changed */
xfree (hd->word_match.name);
xfree (hd->word_match.pattern);
hd->word_match.name = xstrdup (name);
hd->word_match.pattern = prepare_word_match (name);
}
/* name = hd->word_match.pattern; */
}
init_packet(&pkt);
save_mode = set_packet_list_mode(0);
hd->found.kr = NULL;
main_offset = 0;
pk_no = uid_no = 0;
initial_skip = 1; /* skip until we see the start of a keyblock */
scanned_from_start = iobuf_tell (hd->current.iobuf) == 0;
if (DBG_LOOKUP)
log_debug ("%s: %ssearching from start of resource.\n",
__func__, scanned_from_start ? "" : "not ");
init_parse_packet (&parsectx, hd->current.iobuf);
while (1)
{
byte afp[MAX_FINGERPRINT_LEN];
size_t an;
rc = search_packet (&parsectx, &pkt, &offset, need_uid);
if (ignore_legacy && gpg_err_code (rc) == GPG_ERR_LEGACY_KEY)
{
free_packet (&pkt, &parsectx);
continue;
}
if (rc)
break;
if (pkt.pkttype == PKT_PUBLIC_KEY || pkt.pkttype == PKT_SECRET_KEY)
{
main_offset = offset;
pk_no = uid_no = 0;
initial_skip = 0;
}
if (initial_skip)
{
free_packet (&pkt, &parsectx);
continue;
}
pk = NULL;
uid = NULL;
if ( pkt.pkttype == PKT_PUBLIC_KEY
|| pkt.pkttype == PKT_PUBLIC_SUBKEY
|| pkt.pkttype == PKT_SECRET_KEY
|| pkt.pkttype == PKT_SECRET_SUBKEY)
{
pk = pkt.pkt.public_key;
++pk_no;
if (need_fpr) {
fingerprint_from_pk (pk, afp, &an);
while (an < 20) /* fill up to 20 bytes */
afp[an++] = 0;
}
if (need_keyid)
keyid_from_pk (pk, aki);
if (use_key_present_hash
&& !key_present_hash_ready
&& scanned_from_start)
key_present_hash_update (key_present_hash, aki);
}
else if (pkt.pkttype == PKT_USER_ID)
{
uid = pkt.pkt.user_id;
++uid_no;
}
for (n=0; n < ndesc; n++)
{
switch (desc[n].mode) {
case KEYDB_SEARCH_MODE_NONE:
BUG ();
break;
case KEYDB_SEARCH_MODE_EXACT:
case KEYDB_SEARCH_MODE_SUBSTR:
case KEYDB_SEARCH_MODE_MAIL:
case KEYDB_SEARCH_MODE_MAILSUB:
case KEYDB_SEARCH_MODE_MAILEND:
case KEYDB_SEARCH_MODE_WORDS:
if ( uid && !compare_name (desc[n].mode,
desc[n].u.name,
uid->name, uid->len))
goto found;
break;
case KEYDB_SEARCH_MODE_SHORT_KID:
if (pk && desc[n].u.kid[1] == aki[1])
goto found;
break;
case KEYDB_SEARCH_MODE_LONG_KID:
if (pk && desc[n].u.kid[0] == aki[0]
&& desc[n].u.kid[1] == aki[1])
goto found;
break;
case KEYDB_SEARCH_MODE_FPR16:
if (pk && !memcmp (desc[n].u.fpr, afp, 16))
goto found;
break;
case KEYDB_SEARCH_MODE_FPR20:
case KEYDB_SEARCH_MODE_FPR:
if (pk && !memcmp (desc[n].u.fpr, afp, 20))
goto found;
break;
case KEYDB_SEARCH_MODE_FIRST:
if (pk)
goto found;
break;
case KEYDB_SEARCH_MODE_NEXT:
if (pk)
goto found;
break;
default:
rc = GPG_ERR_INV_ARG;
goto found;
}
}
free_packet (&pkt, &parsectx);
continue;
found:
if (rc)
goto real_found;
if (DBG_LOOKUP)
log_debug ("%s: packet starting at offset %lld matched descriptor %zu\n"
, __func__, (long long)offset, n);
/* Record which desc we matched on. Note this value is only
meaningful if this function returns with no errors. */
if(descindex)
*descindex=n;
for (n=any_skip?0:ndesc; n < ndesc; n++)
{
if (desc[n].skipfnc
&& desc[n].skipfnc (desc[n].skipfncvalue, aki, uid_no))
{
if (DBG_LOOKUP)
log_debug ("%s: skipping match: desc %zd's skip function returned TRUE\n",
__func__, n);
break;
}
}
if (n == ndesc)
goto real_found;
free_packet (&pkt, &parsectx);
}
real_found:
if (!rc)
{
if (DBG_LOOKUP)
log_debug ("%s: returning success\n", __func__);
hd->found.offset = main_offset;
hd->found.kr = hd->current.kr;
hd->found.pk_no = pk? pk_no : 0;
hd->found.uid_no = uid? uid_no : 0;
}
else if (rc == -1)
{
if (DBG_LOOKUP)
log_debug ("%s: no matches (EOF)\n", __func__);
hd->current.eof = 1;
/* if we scanned all keyrings, we are sure that
* all known key IDs are in our offtbl, mark that. */
if (use_key_present_hash
&& !key_present_hash_ready
&& scanned_from_start)
{
KR_RESOURCE kr;
/* First set the did_full_scan flag for this keyring. */
for (kr=kr_resources; kr; kr = kr->next)
{
if (hd->resource == kr)
{
kr->did_full_scan = 1;
break;
}
}
/* Then check whether all flags are set and if so, mark the
offtbl ready */
for (kr=kr_resources; kr; kr = kr->next)
{
if (!kr->did_full_scan)
break;
}
if (!kr)
key_present_hash_ready = 1;
}
}
else
{
if (DBG_LOOKUP)
log_debug ("%s: error encountered during search: %s (%d)\n",
__func__, gpg_strerror (rc), rc);
hd->current.error = rc;
}
free_packet (&pkt, &parsectx);
deinit_parse_packet (&parsectx);
set_packet_list_mode(save_mode);
return rc;
}
static int
create_tmp_file (const char *template,
char **r_bakfname, char **r_tmpfname, IOBUF *r_fp)
{
gpg_error_t err;
mode_t oldmask;
err = keybox_tmp_names (template, 1, r_bakfname, r_tmpfname);
if (err)
return err;
/* Create the temp file with limited access. Note that the umask
call is not anymore needed because iobuf_create now takes care of
it. However, it does not harm and thus we keep it. */
oldmask = umask (077);
if (is_secured_filename (*r_tmpfname))
{
*r_fp = NULL;
gpg_err_set_errno (EPERM);
}
else
*r_fp = iobuf_create (*r_tmpfname, 1);
umask (oldmask);
if (!*r_fp)
{
err = gpg_error_from_syserror ();
log_error (_("can't create '%s': %s\n"), *r_tmpfname, gpg_strerror (err));
xfree (*r_tmpfname);
*r_tmpfname = NULL;
xfree (*r_bakfname);
*r_bakfname = NULL;
}
return err;
}
static int
rename_tmp_file (const char *bakfname, const char *tmpfname, const char *fname)
{
int rc = 0;
int block = 0;
/* Invalidate close caches. */
if (iobuf_ioctl (NULL, IOBUF_IOCTL_INVALIDATE_CACHE, 0, (char*)tmpfname ))
{
rc = gpg_error_from_syserror ();
goto fail;
}
iobuf_ioctl (NULL, IOBUF_IOCTL_INVALIDATE_CACHE, 0, (char*)bakfname );
iobuf_ioctl (NULL, IOBUF_IOCTL_INVALIDATE_CACHE, 0, (char*)fname );
/* First make a backup file. */
block = 1;
rc = gnupg_rename_file (fname, bakfname, &block);
if (rc)
goto fail;
/* then rename the file */
rc = gnupg_rename_file (tmpfname, fname, NULL);
if (block)
{
gnupg_unblock_all_signals ();
block = 0;
}
if (rc)
{
register_secured_file (fname);
goto fail;
}
/* Now make sure the file has the same permissions as the original */
#ifndef HAVE_DOSISH_SYSTEM
{
struct stat statbuf;
statbuf.st_mode=S_IRUSR | S_IWUSR;
if (!stat (bakfname, &statbuf) && !chmod (fname, statbuf.st_mode))
;
else
log_error ("WARNING: unable to restore permissions to '%s': %s",
fname, strerror(errno));
}
#endif
return 0;
fail:
if (block)
gnupg_unblock_all_signals ();
return rc;
}
static int
write_keyblock (IOBUF fp, KBNODE keyblock)
{
KBNODE kbctx = NULL, node;
int rc;
while ( (node = walk_kbnode (keyblock, &kbctx, 0)) )
{
if ( (rc = build_packet_and_meta (fp, node->pkt) ))
{
log_error ("build_packet(%d) failed: %s\n",
node->pkt->pkttype, gpg_strerror (rc) );
return rc;
}
}
return 0;
}
/*
* Walk over all public keyrings, check the signatures and replace the
* keyring with a new one where the signature cache is then updated.
* This is only done for the public keyrings.
*/
int
keyring_rebuild_cache (ctrl_t ctrl, void *token, int noisy)
{
KEYRING_HANDLE hd;
KEYDB_SEARCH_DESC desc;
KBNODE keyblock = NULL, node;
const char *lastresname = NULL, *resname;
IOBUF tmpfp = NULL;
char *tmpfilename = NULL;
char *bakfilename = NULL;
int rc;
ulong count = 0, sigcount = 0;
hd = keyring_new (token);
if (!hd)
return gpg_error_from_syserror ();
memset (&desc, 0, sizeof desc);
desc.mode = KEYDB_SEARCH_MODE_FIRST;
rc=keyring_lock (hd, 1);
if(rc)
goto leave;
for (;;)
{
rc = keyring_search (hd, &desc, 1, NULL, 1 /* ignore_legacy */);
if (rc)
break; /* ready. */
desc.mode = KEYDB_SEARCH_MODE_NEXT;
resname = keyring_get_resource_name (hd);
if (lastresname != resname )
{ /* we have switched to a new keyring - commit changes */
if (tmpfp)
{
if (iobuf_close (tmpfp))
{
rc = gpg_error_from_syserror ();
log_error ("error closing '%s': %s\n",
tmpfilename, strerror (errno));
goto leave;
}
/* because we have switched resources, we can be sure that
* the original file is closed */
tmpfp = NULL;
}
/* Static analyzer note: BAKFILENAME is never NULL here
because it is controlled by LASTRESNAME. */
rc = lastresname? rename_tmp_file (bakfilename, tmpfilename,
lastresname) : 0;
xfree (tmpfilename); tmpfilename = NULL;
xfree (bakfilename); bakfilename = NULL;
if (rc)
goto leave;
lastresname = resname;
if (noisy && !opt.quiet)
log_info (_("caching keyring '%s'\n"), resname);
rc = create_tmp_file (resname, &bakfilename, &tmpfilename, &tmpfp);
if (rc)
goto leave;
}
release_kbnode (keyblock);
rc = keyring_get_keyblock (hd, &keyblock);
if (rc)
{
if (gpg_err_code (rc) == GPG_ERR_LEGACY_KEY)
continue; /* Skip legacy keys. */
log_error ("keyring_get_keyblock failed: %s\n", gpg_strerror (rc));
goto leave;
}
if ( keyblock->pkt->pkttype != PKT_PUBLIC_KEY)
{
/* We had a few reports about corrupted keyrings; if we have
been called directly from the command line we delete such
a keyblock instead of bailing out. */
log_error ("unexpected keyblock found (pkttype=%d)%s\n",
keyblock->pkt->pkttype, noisy? " - deleted":"");
if (noisy)
continue;
log_info ("Hint: backup your keys and try running '%s'\n",
"gpg --rebuild-keydb-caches");
rc = gpg_error (GPG_ERR_INV_KEYRING);
goto leave;
}
if (keyblock->pkt->pkt.public_key->version < 4)
{
/* We do not copy/cache v3 keys or any other unknown
packets. It is better to remove them from the keyring.
The code required to keep them in the keyring would be
too complicated. Given that we do not touch the old
secring.gpg a suitable backup for decryption of v3 stuff
using an older gpg version will always be available.
Note: This test is actually superfluous because we
already acted upon GPG_ERR_LEGACY_KEY. */
}
else
{
/* Check all signature to set the signature's cache flags. */
for (node=keyblock; node; node=node->next)
{
/* Note that this doesn't cache the result of a
revocation issued by a designated revoker. This is
because the pk in question does not carry the revkeys
as we haven't merged the key and selfsigs. It is
questionable whether this matters very much since
there are very very few designated revoker revocation
packets out there. */
if (node->pkt->pkttype == PKT_SIGNATURE)
{
PKT_signature *sig=node->pkt->pkt.signature;
if(!opt.no_sig_cache && sig->flags.checked && sig->flags.valid
&& (openpgp_md_test_algo(sig->digest_algo)
|| openpgp_pk_test_algo(sig->pubkey_algo)))
sig->flags.checked=sig->flags.valid=0;
else
check_key_signature (ctrl, keyblock, node, NULL);
sigcount++;
}
}
/* Write the keyblock to the temporary file. */
rc = write_keyblock (tmpfp, keyblock);
if (rc)
goto leave;
if ( !(++count % 50) && noisy && !opt.quiet)
log_info (ngettext("%lu keys cached so far (%lu signature)\n",
"%lu keys cached so far (%lu signatures)\n",
sigcount),
count, sigcount);
}
} /* end main loop */
if (rc == -1)
rc = 0;
if (rc)
{
log_error ("keyring_search failed: %s\n", gpg_strerror (rc));
goto leave;
}
if (noisy || opt.verbose)
{
log_info (ngettext("%lu key cached",
"%lu keys cached", count), count);
log_printf (ngettext(" (%lu signature)\n",
" (%lu signatures)\n", sigcount), sigcount);
}
if (tmpfp)
{
if (iobuf_close (tmpfp))
{
rc = gpg_error_from_syserror ();
log_error ("error closing '%s': %s\n",
tmpfilename, strerror (errno));
goto leave;
}
/* because we have switched resources, we can be sure that
* the original file is closed */
tmpfp = NULL;
}
rc = lastresname? rename_tmp_file (bakfilename, tmpfilename,
lastresname) : 0;
xfree (tmpfilename); tmpfilename = NULL;
xfree (bakfilename); bakfilename = NULL;
leave:
if (tmpfp)
iobuf_cancel (tmpfp);
xfree (tmpfilename);
xfree (bakfilename);
release_kbnode (keyblock);
keyring_lock (hd, 0);
keyring_release (hd);
return rc;
}
/****************
* Perform insert/delete/update operation.
* mode 1 = insert
* 2 = delete
* 3 = update
*/
static int
do_copy (int mode, const char *fname, KBNODE root,
off_t start_offset, unsigned int n_packets )
{
IOBUF fp, newfp;
int rc=0;
char *bakfname = NULL;
char *tmpfname = NULL;
/* Open the source file. Because we do a rename, we have to check the
permissions of the file */
if (access (fname, W_OK))
return gpg_error_from_syserror ();
fp = iobuf_open (fname);
if (mode == 1 && !fp && errno == ENOENT) {
/* insert mode but file does not exist: create a new file */
KBNODE kbctx, node;
mode_t oldmask;
oldmask=umask(077);
if (is_secured_filename (fname)) {
newfp = NULL;
gpg_err_set_errno (EPERM);
}
else
newfp = iobuf_create (fname, 1);
umask(oldmask);
if( !newfp )
{
rc = gpg_error_from_syserror ();
log_error (_("can't create '%s': %s\n"), fname, strerror(errno));
return rc;
}
if( !opt.quiet )
log_info(_("%s: keyring created\n"), fname );
kbctx=NULL;
while ( (node = walk_kbnode( root, &kbctx, 0 )) ) {
if( (rc = build_packet( newfp, node->pkt )) ) {
log_error("build_packet(%d) failed: %s\n",
node->pkt->pkttype, gpg_strerror (rc) );
iobuf_cancel(newfp);
return rc;
}
}
if( iobuf_close(newfp) ) {
rc = gpg_error_from_syserror ();
log_error ("%s: close failed: %s\n", fname, strerror(errno));
return rc;
}
return 0; /* ready */
}
if( !fp )
{
rc = gpg_error_from_syserror ();
log_error(_("can't open '%s': %s\n"), fname, strerror(errno) );
goto leave;
}
/* Create the new file. */
rc = create_tmp_file (fname, &bakfname, &tmpfname, &newfp);
if (rc) {
iobuf_close(fp);
goto leave;
}
if( mode == 1 ) { /* insert */
/* copy everything to the new file */
rc = copy_all_packets (fp, newfp);
if( rc != -1 ) {
log_error("%s: copy to '%s' failed: %s\n",
fname, tmpfname, gpg_strerror (rc) );
iobuf_close(fp);
iobuf_cancel(newfp);
goto leave;
}
}
if( mode == 2 || mode == 3 ) { /* delete or update */
/* copy first part to the new file */
rc = copy_some_packets( fp, newfp, start_offset );
if( rc ) { /* should never get EOF here */
log_error ("%s: copy to '%s' failed: %s\n",
fname, tmpfname, gpg_strerror (rc) );
iobuf_close(fp);
iobuf_cancel(newfp);
goto leave;
}
/* skip this keyblock */
log_assert( n_packets );
rc = skip_some_packets( fp, n_packets );
if( rc ) {
log_error("%s: skipping %u packets failed: %s\n",
fname, n_packets, gpg_strerror (rc));
iobuf_close(fp);
iobuf_cancel(newfp);
goto leave;
}
}
if( mode == 1 || mode == 3 ) { /* insert or update */
rc = write_keyblock (newfp, root);
if (rc) {
iobuf_close(fp);
iobuf_cancel(newfp);
goto leave;
}
}
if( mode == 2 || mode == 3 ) { /* delete or update */
/* copy the rest */
rc = copy_all_packets( fp, newfp );
if( rc != -1 ) {
log_error("%s: copy to '%s' failed: %s\n",
fname, tmpfname, gpg_strerror (rc) );
iobuf_close(fp);
iobuf_cancel(newfp);
goto leave;
}
}
/* close both files */
if( iobuf_close(fp) ) {
rc = gpg_error_from_syserror ();
log_error("%s: close failed: %s\n", fname, strerror(errno) );
goto leave;
}
if( iobuf_close(newfp) ) {
rc = gpg_error_from_syserror ();
log_error("%s: close failed: %s\n", tmpfname, strerror(errno) );
goto leave;
}
rc = rename_tmp_file (bakfname, tmpfname, fname);
leave:
xfree(bakfname);
xfree(tmpfname);
return rc;
}
diff --git a/g10/packet.h b/g10/packet.h
index d42510dfc..cf2121c6c 100644
--- a/g10/packet.h
+++ b/g10/packet.h
@@ -1,910 +1,912 @@
/* packet.h - OpenPGP packet definitions
* Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006,
* 2007 Free Software Foundation, Inc.
* Copyright (C) 2015 g10 Code GmbH
*
* 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
* the Free Software Foundation; either version 3 of the License, or
* (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
* along with this program; if not, see .
*/
#ifndef G10_PACKET_H
#define G10_PACKET_H
#include "../common/types.h"
#include "../common/iobuf.h"
#include "../common/strlist.h"
#include "dek.h"
#include "filter.h"
#include "../common/openpgpdefs.h"
#include "../common/userids.h"
#include "../common/util.h"
#define DEBUG_PARSE_PACKET 1
/* Constants to allocate static MPI arrays. */
#define PUBKEY_MAX_NPKEY 5
#define PUBKEY_MAX_NSKEY 7
#define PUBKEY_MAX_NSIG 2
#define PUBKEY_MAX_NENC 2
/* Usage flags */
#define PUBKEY_USAGE_SIG GCRY_PK_USAGE_SIGN /* Good for signatures. */
#define PUBKEY_USAGE_ENC GCRY_PK_USAGE_ENCR /* Good for encryption. */
#define PUBKEY_USAGE_CERT GCRY_PK_USAGE_CERT /* Also good to certify keys.*/
#define PUBKEY_USAGE_AUTH GCRY_PK_USAGE_AUTH /* Good for authentication. */
#define PUBKEY_USAGE_UNKNOWN GCRY_PK_USAGE_UNKN /* Unknown usage flag. */
#define PUBKEY_USAGE_NONE 256 /* No usage given. */
#if (GCRY_PK_USAGE_SIGN | GCRY_PK_USAGE_ENCR | GCRY_PK_USAGE_CERT \
| GCRY_PK_USAGE_AUTH | GCRY_PK_USAGE_UNKN) >= 256
# error Please choose another value for PUBKEY_USAGE_NONE
#endif
/* Helper macros. */
#define is_RSA(a) ((a)==PUBKEY_ALGO_RSA || (a)==PUBKEY_ALGO_RSA_E \
|| (a)==PUBKEY_ALGO_RSA_S )
#define is_ELGAMAL(a) ((a)==PUBKEY_ALGO_ELGAMAL_E)
#define is_DSA(a) ((a)==PUBKEY_ALGO_DSA)
/* A pointer to the packet object. */
typedef struct packet_struct PACKET;
/* PKT_GPG_CONTROL types */
typedef enum {
CTRLPKT_CLEARSIGN_START = 1,
CTRLPKT_PIPEMODE = 2,
CTRLPKT_PLAINTEXT_MARK =3
} ctrlpkttype_t;
typedef enum {
PREFTYPE_NONE = 0,
PREFTYPE_SYM = 1,
PREFTYPE_HASH = 2,
PREFTYPE_ZIP = 3
} preftype_t;
typedef struct {
byte type;
byte value;
} prefitem_t;
/* A string-to-key specifier as defined in RFC 4880, Section 3.7. */
typedef struct
{
int mode; /* Must be an integer due to the GNU modes 1001 et al. */
byte hash_algo;
byte salt[8];
/* The *coded* (i.e., the serialized version) iteration count. */
u32 count;
} STRING2KEY;
/* A symmetric-key encrypted session key packet as defined in RFC
4880, Section 5.3. All fields are serialized. */
typedef struct {
/* RFC 4880: this must be 4. */
byte version;
/* The cipher algorithm used to encrypt the session key. (This may
be different from the algorithm that is used to encrypt the SED
packet.) */
byte cipher_algo;
/* The string-to-key specifier. */
STRING2KEY s2k;
/* The length of SESKEY in bytes or 0 if this packet does not
encrypt a session key. (In the latter case, the results of the
S2K function on the password is the session key. See RFC 4880,
Section 5.3.) */
byte seskeylen;
/* The session key as encrypted by the S2K specifier. */
byte seskey[1];
} PKT_symkey_enc;
/* A public-key encrypted session key packet as defined in RFC 4880,
Section 5.1. All fields are serialized. */
typedef struct {
/* The 64-bit keyid. */
u32 keyid[2];
/* The packet's version. Currently, only version 3 is defined. */
byte version;
/* The algorithm used for the public key encryption scheme. */
byte pubkey_algo;
/* Whether to hide the key id. This value is not directly
serialized. */
byte throw_keyid;
/* The session key. */
gcry_mpi_t data[PUBKEY_MAX_NENC];
} PKT_pubkey_enc;
/* A one-pass signature packet as defined in RFC 4880, Section
5.4. All fields are serialized. */
typedef struct {
u32 keyid[2]; /* The 64-bit keyid */
/* The signature's classification (RFC 4880, Section 5.2.1). */
byte sig_class;
byte digest_algo; /* algorithm used for digest */
byte pubkey_algo; /* algorithm used for public key scheme */
/* A message can be signed by multiple keys. In this case, there
are n one-pass signature packets before the message to sign and
n signatures packets after the message. It is conceivable that
someone wants to not only sign the message, but all of the
signatures. Now we need to distinguish between signing the
message and signing the message plus the surrounding
signatures. This is the point of this flag. If set, it means:
I sign all of the data starting at the next packet. */
byte last;
} PKT_onepass_sig;
/* A v4 OpenPGP signature has a hashed and unhashed area containing
co-called signature subpackets (RFC 4880, Section 5.2.3). These
areas are described by this data structure. Use enum_sig_subpkt to
parse this area. */
typedef struct {
size_t size; /* allocated */
size_t len; /* used (serialized) */
byte data[1]; /* the serialized subpackes (serialized) */
} subpktarea_t;
/* The in-memory representation of a designated revoker signature
subpacket (RFC 4880, Section 5.2.3.15). */
struct revocation_key {
/* A bit field. 0x80 must be set. 0x40 means this information is
sensitive (and should not be uploaded to a keyserver by
default). */
byte class;
/* The public-key algorithm ID. */
byte algid;
/* The fingerprint of the authorized key. */
byte fpr[MAX_FINGERPRINT_LEN];
};
/* Object to keep information about a PKA DNS record. */
typedef struct
{
int valid; /* An actual PKA record exists for EMAIL. */
int checked; /* Set to true if the FPR has been checked against the
actual key. */
char *uri; /* Malloced string with the URI. NULL if the URI is
not available.*/
unsigned char fpr[20]; /* The fingerprint as stored in the PKA RR. */
char email[1];/* The email address from the notation data. */
} pka_info_t;
/* A signature packet (RFC 4880, Section 5.2). Only a subset of these
fields are directly serialized (these are marked as such); the rest
are read from the subpackets, which are not synthesized when
serializing this data structure (i.e., when using build_packet()).
Instead, the subpackets must be created by hand. */
typedef struct
{
struct
{
unsigned checked:1; /* Signature has been checked. */
unsigned valid:1; /* Signature is good (if checked is set). */
unsigned chosen_selfsig:1; /* A selfsig that is the chosen one. */
unsigned unknown_critical:1;
unsigned exportable:1;
unsigned revocable:1;
unsigned policy_url:1; /* At least one policy URL is present */
unsigned notation:1; /* At least one notation is present */
unsigned pref_ks:1; /* At least one preferred keyserver is present */
unsigned expired:1;
unsigned pka_tried:1; /* Set if we tried to retrieve the PKA record. */
} flags;
/* The key that allegedly generated this signature. (Directly
serialized in v3 sigs; for v4 sigs, this must be explicitly added
as an issuer subpacket (5.2.3.5.) */
u32 keyid[2];
/* When the signature was made (seconds since the Epoch). (Directly
serialized in v3 sigs; for v4 sigs, this must be explicitly added
as a signature creation time subpacket (5.2.3.4).) */
u32 timestamp;
u32 expiredate; /* Expires at this date or 0 if not at all. */
/* The serialization format used / to use. If 0, then defaults to
version 3. (Serialized.) */
byte version;
/* The signature type. (See RFC 4880, Section 5.2.1.) */
byte sig_class;
/* Algorithm used for public key scheme (e.g., PUBKEY_ALGO_RSA).
(Serialized.) */
byte pubkey_algo;
/* Algorithm used for digest (e.g., DIGEST_ALGO_SHA1).
(Serialized.) */
byte digest_algo;
byte trust_depth;
byte trust_value;
const byte *trust_regexp;
struct revocation_key *revkey;
int numrevkeys;
pka_info_t *pka_info; /* Malloced PKA data or NULL if not
available. See also flags.pka_tried. */
char *signers_uid; /* Malloced value of the SIGNERS_UID
* subpacket or NULL. This string has
* already been sanitized. */
subpktarea_t *hashed; /* All subpackets with hashed data (v4 only). */
subpktarea_t *unhashed; /* Ditto for unhashed data. */
/* First 2 bytes of the digest. (Serialized. Note: this is not
automatically filled in when serializing a signature!) */
byte digest_start[2];
/* The signature. (Serialized.) */
gcry_mpi_t data[PUBKEY_MAX_NSIG];
/* The message digest and its length (in bytes). Note the maximum
digest length is 512 bits (64 bytes). If DIGEST_LEN is 0, then
the digest's value has not been saved here. */
byte digest[512 / 8];
int digest_len;
} PKT_signature;
#define ATTRIB_IMAGE 1
/* This is the cooked form of attributes. */
struct user_attribute {
byte type;
const byte *data;
u32 len;
};
/* A user id (RFC 4880, Section 5.11) or a user attribute packet (RFC
4880, Section 5.12). Only a subset of these fields are directly
serialized (these are marked as such); the rest are read from the
self-signatures in merge_keys_and_selfsig()). */
typedef struct
{
int ref; /* reference counter */
/* The length of NAME. */
int len;
struct user_attribute *attribs;
int numattribs;
/* If this is not NULL, the packet is a user attribute rather than a
user id (See RFC 4880 5.12). (Serialized.) */
byte *attrib_data;
/* The length of ATTRIB_DATA. */
unsigned long attrib_len;
byte *namehash;
int help_key_usage;
u32 help_key_expire;
int help_full_count;
int help_marginal_count;
u32 expiredate; /* expires at this date or 0 if not at all */
prefitem_t *prefs; /* list of preferences (may be NULL)*/
u32 created; /* according to the self-signature */
u32 keyupdate; /* From the ring trust packet. */
char *updateurl; /* NULL or the URL of the last update origin. */
byte keysrc; /* From the ring trust packet. */
byte selfsigversion;
struct
{
unsigned int mdc:1;
unsigned int ks_modify:1;
unsigned int compacted:1;
unsigned int primary:2; /* 2 if set via the primary flag, 1 if calculated */
unsigned int revoked:1;
unsigned int expired:1;
} flags;
char *mbox; /* NULL or the result of mailbox_from_userid. */
/* The text contained in the user id packet, which is normally the
* name and email address of the key holder (See RFC 4880 5.11).
* (Serialized.). For convenience an extra Nul is always appended. */
char name[1];
} PKT_user_id;
struct revoke_info
{
/* revoked at this date */
u32 date;
/* the keyid of the revoking key (selfsig or designated revoker) */
u32 keyid[2];
/* the algo of the revoking key */
byte algo;
};
/* Information pertaining to secret keys. */
struct seckey_info
{
int is_protected:1; /* The secret info is protected and must */
/* be decrypted before use, the protected */
/* MPIs are simply (void*) pointers to memory */
/* and should never be passed to a mpi_xxx() */
int sha1chk:1; /* SHA1 is used instead of a 16 bit checksum */
u16 csum; /* Checksum for old protection modes. */
byte algo; /* Cipher used to protect the secret information. */
STRING2KEY s2k; /* S2K parameter. */
byte ivlen; /* Used length of the IV. */
byte iv[16]; /* Initialization vector for CFB mode. */
};
/****************
* The in-memory representation of a public key (RFC 4880, Section
* 5.5). Note: this structure contains significantly more information
* than is contained in an OpenPGP public key packet. This
* information is derived from the self-signed signatures (by
* merge_keys_and_selfsig()) and is ignored when serializing the
* packet. The fields that are actually written out when serializing
* this packet are marked as accordingly.
*
* We assume that secret keys have the same number of parameters as
* the public key and that the public parameters are the first items
* in the PKEY array. Thus NPKEY is always less than NSKEY and it is
* possible to compare the secret and public keys by comparing the
* first NPKEY elements of the PKEY array. Note that since GnuPG 2.1
* we don't use secret keys anymore directly because they are managed
* by gpg-agent. However for parsing OpenPGP key files we need a way
* to temporary store those secret keys. We do this by putting them
* into the public key structure and extending the PKEY field to NSKEY
* elements; the extra secret key information are stored in the
* SECKEY_INFO field.
*/
typedef struct
{
/* When the key was created. (Serialized.) */
u32 timestamp;
u32 expiredate; /* expires at this date or 0 if not at all */
u32 max_expiredate; /* must not expire past this date */
struct revoke_info revoked;
/* An OpenPGP packet consists of a header and a body. This is the
size of the header. If this is 0, an appropriate size is
automatically chosen based on the size of the body.
(Serialized.) */
byte hdrbytes;
/* The serialization format. If 0, the default version (4) is used
when serializing. (Serialized.) */
byte version;
byte selfsigversion; /* highest version of all of the self-sigs */
/* The public key algorithm. (Serialized.) */
byte pubkey_algo;
byte pubkey_usage; /* for now only used to pass it to getkey() */
byte req_usage; /* hack to pass a request to getkey() */
u32 has_expired; /* set to the expiration date if expired */
/* keyid of the primary key. Never access this value directly.
Instead, use pk_main_keyid(). */
u32 main_keyid[2];
/* keyid of this key. Never access this value directly! Instead,
use pk_keyid(). */
u32 keyid[2];
prefitem_t *prefs; /* list of preferences (may be NULL) */
struct
{
unsigned int mdc:1; /* MDC feature set. */
unsigned int disabled_valid:1;/* The next flag is valid. */
unsigned int disabled:1; /* The key has been disabled. */
unsigned int primary:1; /* This is a primary key. */
unsigned int revoked:2; /* Key has been revoked.
1 = revoked by the owner
2 = revoked by designated revoker. */
unsigned int maybe_revoked:1; /* A designated revocation is
present, but without the key to
check it. */
unsigned int valid:1; /* Key (especially subkey) is valid. */
unsigned int dont_cache:1; /* Do not cache this key. */
unsigned int backsig:2; /* 0=none, 1=bad, 2=good. */
unsigned int serialno_valid:1;/* SERIALNO below is valid. */
unsigned int exact:1; /* Found via exact (!) search. */
} flags;
PKT_user_id *user_id; /* If != NULL: found by that uid. */
struct revocation_key *revkey;
int numrevkeys;
u32 trust_timestamp;
byte trust_depth;
byte trust_value;
byte keysrc; /* From the ring trust packet. */
u32 keyupdate; /* From the ring trust packet. */
char *updateurl; /* NULL or the URL of the last update origin. */
const byte *trust_regexp;
char *serialno; /* Malloced hex string or NULL if it is
likely not on a card. See also
flags.serialno_valid. */
/* If not NULL this malloced structure describes a secret key.
(Serialized.) */
struct seckey_info *seckey_info;
/* The public key. Contains pubkey_get_npkey (pubkey_algo) +
pubkey_get_nskey (pubkey_algo) MPIs. (If pubkey_get_npkey
returns 0, then the algorithm is not understood and the PKEY
contains a single opaque MPI.) (Serialized.) */
gcry_mpi_t pkey[PUBKEY_MAX_NSKEY]; /* Right, NSKEY elements. */
} PKT_public_key;
/* Evaluates as true if the pk is disabled, and false if it isn't. If
there is no disable value cached, fill one in. */
#define pk_is_disabled(a) \
(((a)->flags.disabled_valid)? \
((a)->flags.disabled):(cache_disabled_value(ctrl,(a))))
typedef struct {
int len; /* length of data */
char data[1];
} PKT_comment;
/* A compression packet (RFC 4880, Section 5.6). */
typedef struct {
/* Not used. */
u32 len;
/* Whether the serialized version of the packet used / should use
the new format. */
byte new_ctb;
/* The compression algorithm. */
byte algorithm;
/* An iobuf holding the data to be decompressed. (This is not used
for compression!) */
iobuf_t buf;
} PKT_compressed;
/* A symmetrically encrypted data packet (RFC 4880, Section 5.7) or a
symmetrically encrypted integrity protected data packet (Section
5.13) */
typedef struct {
/* Remaining length of encrypted data. */
u32 len;
/* When encrypting, the first block size bytes of data are random
data and the following 2 bytes are copies of the last two bytes
of the random data (RFC 4880, Section 5.7). This provides a
simple check that the key is correct. extralen is the size of
this extra data. This is used by build_packet when writing out
the packet's header. */
int extralen;
/* Whether the serialized version of the packet used / should use
the new format. */
byte new_ctb;
/* Whether the packet has an indeterminate length (old format) or
was encoded using partial body length headers (new format).
Note: this is ignored when encrypting. */
byte is_partial;
/* If 0, MDC is disabled. Otherwise, the MDC method that was used
(currently, only DIGEST_ALGO_SHA1 is supported). */
byte mdc_method;
/* An iobuf holding the data to be decrypted. (This is not used for
encryption!) */
iobuf_t buf;
} PKT_encrypted;
typedef struct {
byte hash[20];
} PKT_mdc;
/* Subtypes for the ring trust packet. */
#define RING_TRUST_SIG 0 /* The classical signature cache. */
#define RING_TRUST_KEY 1 /* A KEYSRC on a primary key. */
#define RING_TRUST_UID 2 /* A KEYSRC on a user id. */
/* The local only ring trust packet which OpenPGP declares as
* implementation defined. GnuPG uses this to cache signature
* verification status and since 2.1.18 also to convey information
* about the origin of a key. Note that this packet is not part
* struct packet_struct because we use it only local in the packet
* parser and builder. */
typedef struct {
unsigned int trustval;
unsigned int sigcache;
unsigned char subtype; /* The subtype of this ring trust packet. */
unsigned char keysrc; /* The origin of the key (KEYSRC_*). */
u32 keyupdate; /* The wall time the key was last updated. */
char *url; /* NULL or the URL of the source. */
} PKT_ring_trust;
/* A plaintext packet (see RFC 4880, 5.9). */
typedef struct {
/* The length of data in BUF or 0 if unknown. */
u32 len;
/* A buffer containing the data stored in the packet's body. */
iobuf_t buf;
byte new_ctb;
byte is_partial; /* partial length encoded */
/* The data's formatting. This is either 'b', 't', 'u', 'l' or '1'
(however, the last two are deprecated). */
int mode;
u32 timestamp;
/* The name of the file. This can be at most 255 characters long,
since namelen is just a byte in the serialized format. */
int namelen;
char name[1];
} PKT_plaintext;
typedef struct {
int control;
size_t datalen;
char data[1];
} PKT_gpg_control;
/* combine all packets into a union */
struct packet_struct {
pkttype_t pkttype;
union {
void *generic;
PKT_symkey_enc *symkey_enc; /* PKT_SYMKEY_ENC */
PKT_pubkey_enc *pubkey_enc; /* PKT_PUBKEY_ENC */
PKT_onepass_sig *onepass_sig; /* PKT_ONEPASS_SIG */
PKT_signature *signature; /* PKT_SIGNATURE */
PKT_public_key *public_key; /* PKT_PUBLIC_[SUB]KEY */
PKT_public_key *secret_key; /* PKT_SECRET_[SUB]KEY */
PKT_comment *comment; /* PKT_COMMENT */
PKT_user_id *user_id; /* PKT_USER_ID */
PKT_compressed *compressed; /* PKT_COMPRESSED */
PKT_encrypted *encrypted; /* PKT_ENCRYPTED[_MDC] */
PKT_mdc *mdc; /* PKT_MDC */
PKT_plaintext *plaintext; /* PKT_PLAINTEXT */
PKT_gpg_control *gpg_control; /* PKT_GPG_CONTROL */
} pkt;
};
#define init_packet(a) do { (a)->pkttype = 0; \
(a)->pkt.generic = NULL; \
} while(0)
/* A notation. See RFC 4880, Section 5.2.3.16. */
struct notation
{
/* The notation's name. */
char *name;
/* If the notation is human readable, then the value is stored here
as a NUL-terminated string. If it is not human readable a human
readable approximation of the binary value _may_ be stored
here. */
char *value;
/* Sometimes we want to %-expand the value. In these cases, we save
that transformed value here. */
char *altvalue;
/* If the notation is not human readable, then the value is stored
here. */
unsigned char *bdat;
/* The amount of data stored in BDAT.
Note: if this is 0 and BDAT is NULL, this does not necessarily
mean that the value is human readable. It could be that we have
a 0-length value. To determine whether the notation is human
readable, always check if VALUE is not NULL. This works, because
if a human-readable value has a length of 0, we will still
allocate space for the NUL byte. */
size_t blen;
struct
{
/* The notation is critical. */
unsigned int critical:1;
/* The notation is human readable. */
unsigned int human:1;
/* The notation should be deleted. */
unsigned int ignore:1;
} flags;
/* A field to facilitate creating a list of notations. */
struct notation *next;
};
typedef struct notation *notation_t;
/*-- mainproc.c --*/
void reset_literals_seen(void);
int proc_packets (ctrl_t ctrl, void *ctx, iobuf_t a );
int proc_signature_packets (ctrl_t ctrl, void *ctx, iobuf_t a,
strlist_t signedfiles, const char *sigfile );
int proc_signature_packets_by_fd (ctrl_t ctrl,
void *anchor, IOBUF a, int signed_data_fd );
int proc_encryption_packets (ctrl_t ctrl, void *ctx, iobuf_t a);
int list_packets( iobuf_t a );
/*-- parse-packet.c --*/
/* Sets the packet list mode to MODE (i.e., whether we are dumping a
packet or not). Returns the current mode. This allows for
temporarily suspending dumping by doing the following:
int saved_mode = set_packet_list_mode (0);
...
set_packet_list_mode (saved_mode);
*/
int set_packet_list_mode( int mode );
/* A context used with parse_packet. */
struct parse_packet_ctx_s
{
iobuf_t inp; /* The input stream with the packets. */
struct packet_struct last_pkt; /* The last parsed packet. */
int free_last_pkt; /* Indicates that LAST_PKT must be freed. */
int skip_meta; /* Skip ring trust packets. */
+ unsigned int n_parsed_packets; /* Number of parsed packets. */
};
typedef struct parse_packet_ctx_s *parse_packet_ctx_t;
#define init_parse_packet(a,i) do { \
(a)->inp = (i); \
(a)->last_pkt.pkttype = 0; \
(a)->last_pkt.pkt.generic= NULL;\
(a)->free_last_pkt = 0; \
(a)->skip_meta = 0; \
+ (a)->n_parsed_packets = 0; \
} while (0)
#define deinit_parse_packet(a) do { \
if ((a)->free_last_pkt) \
free_packet (NULL, (a)); \
} while (0)
#if DEBUG_PARSE_PACKET
/* There are debug functions and should not be used directly. */
int dbg_search_packet (parse_packet_ctx_t ctx, PACKET *pkt,
off_t *retpos, int with_uid,
const char* file, int lineno );
int dbg_parse_packet (parse_packet_ctx_t ctx, PACKET *ret_pkt,
const char *file, int lineno);
int dbg_copy_all_packets( iobuf_t inp, iobuf_t out,
const char* file, int lineno );
int dbg_copy_some_packets( iobuf_t inp, iobuf_t out, off_t stopoff,
const char* file, int lineno );
int dbg_skip_some_packets( iobuf_t inp, unsigned n,
const char* file, int lineno );
#define search_packet( a,b,c,d ) \
dbg_search_packet( (a), (b), (c), (d), __FILE__, __LINE__ )
#define parse_packet( a, b ) \
dbg_parse_packet( (a), (b), __FILE__, __LINE__ )
#define copy_all_packets( a,b ) \
dbg_copy_all_packets((a),(b), __FILE__, __LINE__ )
#define copy_some_packets( a,b,c ) \
dbg_copy_some_packets((a),(b),(c), __FILE__, __LINE__ )
#define skip_some_packets( a,b ) \
dbg_skip_some_packets((a),(b), __FILE__, __LINE__ )
#else
/* Return the next valid OpenPGP packet in *PKT. (This function will
* skip any packets whose type is 0.) CTX must have been setup prior to
* calling this function.
*
* Returns 0 on success, -1 if EOF is reached, and an error code
* otherwise. In the case of an error, the packet in *PKT may be
* partially constructed. As such, even if there is an error, it is
* necessary to free *PKT to avoid a resource leak. To detect what
* has been allocated, clear *PKT before calling this function. */
int parse_packet (parse_packet_ctx_t ctx, PACKET *pkt);
/* Return the first OpenPGP packet in *PKT that contains a key (either
* a public subkey, a public key, a secret subkey or a secret key) or,
* if WITH_UID is set, a user id.
*
* Saves the position in the pipeline of the start of the returned
* packet (according to iobuf_tell) in RETPOS, if it is not NULL.
*
* The return semantics are the same as parse_packet. */
int search_packet (parse_packet_ctx_t ctx, PACKET *pkt,
off_t *retpos, int with_uid);
/* Copy all packets (except invalid packets, i.e., those with a type
* of 0) from INP to OUT until either an error occurs or EOF is
* reached.
*
* Returns -1 when end of file is reached or an error code, if an
* error occurred. (Note: this function never returns 0, because it
* effectively keeps going until it gets an EOF.) */
int copy_all_packets (iobuf_t inp, iobuf_t out );
/* Like copy_all_packets, but stops at the first packet that starts at
* or after STOPOFF (as indicated by iobuf_tell).
*
* Example: if STOPOFF is 100, the first packet in INP goes from
* 0 to 110 and the next packet starts at offset 111, then the packet
* starting at offset 0 will be completely processed (even though it
* extends beyond STOPOFF) and the packet starting at offset 111 will
* not be processed at all. */
int copy_some_packets (iobuf_t inp, iobuf_t out, off_t stopoff);
/* Skips the next N packets from INP.
*
* If parsing a packet returns an error code, then the function stops
* immediately and returns the error code. Note: in the case of an
* error, this function does not indicate how many packets were
* successfully processed. */
int skip_some_packets (iobuf_t inp, unsigned int n);
#endif
/* Parse a signature packet and store it in *SIG.
The signature packet is read from INP. The OpenPGP header (the tag
and the packet's length) have already been read; the next byte read
from INP should be the first byte of the packet's contents. The
packet's type (as extract from the tag) must be passed as PKTTYPE
and the packet's length must be passed as PKTLEN. This is used as
the upper bound on the amount of data read from INP. If the packet
is shorter than PKTLEN, the data at the end will be silently
skipped. If an error occurs, an error code will be returned. -1
means the EOF was encountered. 0 means parsing was successful. */
int parse_signature( iobuf_t inp, int pkttype, unsigned long pktlen,
PKT_signature *sig );
/* Given a subpacket area (typically either PKT_signature.hashed or
PKT_signature.unhashed), either:
- test whether there are any subpackets with the critical bit set
that we don't understand,
- list the subpackets, or,
- find a subpacket with a specific type.
REQTYPE indicates the type of operation.
If REQTYPE is SIGSUBPKT_TEST_CRITICAL, then this function checks
whether there are any subpackets that have the critical bit and
which GnuPG cannot handle. If GnuPG understands all subpackets
whose critical bit is set, then this function returns simply
returns SUBPKTS. If there is a subpacket whose critical bit is set
and which GnuPG does not understand, then this function returns
NULL and, if START is not NULL, sets *START to the 1-based index of
the subpacket that violates the constraint.
If REQTYPE is SIGSUBPKT_LIST_HASHED or SIGSUBPKT_LIST_UNHASHED, the
packets are dumped. Note: if REQTYPE is SIGSUBPKT_LIST_HASHED,
this function does not check whether the hash is correct; this is
merely an indication of the section that the subpackets came from.
If REQTYPE is anything else, then this function interprets the
values as a subpacket type and looks for the first subpacket with
that type. If such a packet is found, *CRITICAL (if not NULL) is
set if the critical bit was set, *RET_N is set to the offset of the
subpacket's content within the SUBPKTS buffer, *START is set to the
1-based index of the subpacket within the buffer, and returns
&SUBPKTS[*RET_N].
*START is the number of initial subpackets to not consider. Thus,
if *START is 2, then the first 2 subpackets are ignored. */
const byte *enum_sig_subpkt ( const subpktarea_t *subpkts,
sigsubpkttype_t reqtype,
size_t *ret_n, int *start, int *critical );
/* Shorthand for:
enum_sig_subpkt (buffer, reqtype, ret_n, NULL, NULL); */
const byte *parse_sig_subpkt ( const subpktarea_t *buffer,
sigsubpkttype_t reqtype,
size_t *ret_n );
/* This calls parse_sig_subpkt first on the hashed signature area in
SIG and then, if that returns NULL, calls parse_sig_subpkt on the
unhashed subpacket area in SIG. */
const byte *parse_sig_subpkt2 ( PKT_signature *sig,
sigsubpkttype_t reqtype);
/* Returns whether the N byte large buffer BUFFER is sufficient to
hold a subpacket of type TYPE. Note: the buffer refers to the
contents of the subpacket (not the header) and it must already be
initialized: for some subpackets, it checks some internal
constraints.
Returns 0 if the size is acceptable. Returns -2 if the buffer is
definitely too short. To check for an error, check whether the
return value is less than 0. */
int parse_one_sig_subpkt( const byte *buffer, size_t n, int type );
/* Looks for revocation key subpackets (see RFC 4880 5.2.3.15) in the
hashed area of the signature packet. Any that are found are added
to SIG->REVKEY and SIG->NUMREVKEYS is updated appropriately. */
void parse_revkeys(PKT_signature *sig);
/* Extract the attributes from the buffer at UID->ATTRIB_DATA and
update UID->ATTRIBS and UID->NUMATTRIBS accordingly. */
int parse_attribute_subpkts(PKT_user_id *uid);
/* Set the UID->NAME field according to the attributes. MAX_NAMELEN
must be at least 71. */
void make_attribute_uidname(PKT_user_id *uid, size_t max_namelen);
/* Allocate and initialize a new GPG control packet. DATA is the data
to save in the packet. */
PACKET *create_gpg_control ( ctrlpkttype_t type,
const byte *data,
size_t datalen );
/*-- build-packet.c --*/
int build_packet (iobuf_t out, PACKET *pkt);
gpg_error_t build_packet_and_meta (iobuf_t out, PACKET *pkt);
gpg_error_t gpg_mpi_write (iobuf_t out, gcry_mpi_t a);
gpg_error_t gpg_mpi_write_nohdr (iobuf_t out, gcry_mpi_t a);
u32 calc_packet_length( PACKET *pkt );
void build_sig_subpkt( PKT_signature *sig, sigsubpkttype_t type,
const byte *buffer, size_t buflen );
void build_sig_subpkt_from_sig (PKT_signature *sig, PKT_public_key *pksk);
int delete_sig_subpkt(subpktarea_t *buffer, sigsubpkttype_t type );
void build_attribute_subpkt(PKT_user_id *uid,byte type,
const void *buf,u32 buflen,
const void *header,u32 headerlen);
struct notation *string_to_notation(const char *string,int is_utf8);
struct notation *blob_to_notation(const char *name,
const char *data, size_t len);
struct notation *sig_to_notation(PKT_signature *sig);
void free_notation(struct notation *notation);
/*-- free-packet.c --*/
void free_symkey_enc( PKT_symkey_enc *enc );
void free_pubkey_enc( PKT_pubkey_enc *enc );
void free_seckey_enc( PKT_signature *enc );
void release_public_key_parts( PKT_public_key *pk );
void free_public_key( PKT_public_key *key );
void free_attributes(PKT_user_id *uid);
void free_user_id( PKT_user_id *uid );
void free_comment( PKT_comment *rem );
void free_packet (PACKET *pkt, parse_packet_ctx_t parsectx);
prefitem_t *copy_prefs (const prefitem_t *prefs);
PKT_public_key *copy_public_key( PKT_public_key *d, PKT_public_key *s );
PKT_signature *copy_signature( PKT_signature *d, PKT_signature *s );
PKT_user_id *scopy_user_id (PKT_user_id *sd );
int cmp_public_keys( PKT_public_key *a, PKT_public_key *b );
int cmp_signatures( PKT_signature *a, PKT_signature *b );
int cmp_user_ids( PKT_user_id *a, PKT_user_id *b );
/*-- sig-check.c --*/
/* Check a signature. This is shorthand for check_signature2 with
the unnamed arguments passed as NULL. */
int check_signature (ctrl_t ctrl, PKT_signature *sig, gcry_md_hd_t digest);
/* Check a signature. Looks up the public key from the key db. (If
* R_PK is not NULL, it is stored at RET_PK.) DIGEST contains a
* valid hash context that already includes the signed data. This
* function adds the relevant meta-data to the hash before finalizing
* it and verifying the signature. */
gpg_error_t check_signature2 (ctrl_t ctrl,
PKT_signature *sig, gcry_md_hd_t digest,
u32 *r_expiredate, int *r_expired, int *r_revoked,
PKT_public_key **r_pk);
/*-- pubkey-enc.c --*/
gpg_error_t get_session_key (ctrl_t ctrl, PKT_pubkey_enc *k, DEK *dek);
gpg_error_t get_override_session_key (DEK *dek, const char *string);
/*-- compress.c --*/
int handle_compressed (ctrl_t ctrl, void *ctx, PKT_compressed *cd,
int (*callback)(iobuf_t, void *), void *passthru );
/*-- encr-data.c --*/
int decrypt_data (ctrl_t ctrl, void *ctx, PKT_encrypted *ed, DEK *dek );
/*-- plaintext.c --*/
gpg_error_t get_output_file (const byte *embedded_name, int embedded_namelen,
iobuf_t data, char **fnamep, estream_t *fpp);
int handle_plaintext( PKT_plaintext *pt, md_filter_context_t *mfx,
int nooutput, int clearsig );
int ask_for_detached_datafile( gcry_md_hd_t md, gcry_md_hd_t md2,
const char *inname, int textmode );
/*-- sign.c --*/
int make_keysig_packet (ctrl_t ctrl,
PKT_signature **ret_sig, PKT_public_key *pk,
PKT_user_id *uid, PKT_public_key *subpk,
PKT_public_key *pksk, int sigclass, int digest_algo,
u32 timestamp, u32 duration,
int (*mksubpkt)(PKT_signature *, void *),
void *opaque,
const char *cache_nonce);
gpg_error_t update_keysig_packet (ctrl_t ctrl,
PKT_signature **ret_sig,
PKT_signature *orig_sig,
PKT_public_key *pk,
PKT_user_id *uid,
PKT_public_key *subpk,
PKT_public_key *pksk,
int (*mksubpkt)(PKT_signature *, void *),
void *opaque );
/*-- keygen.c --*/
PKT_user_id *generate_user_id (kbnode_t keyblock, const char *uidstr);
#endif /*G10_PACKET_H*/
diff --git a/g10/parse-packet.c b/g10/parse-packet.c
index fa44f8389..dbb7af84d 100644
--- a/g10/parse-packet.c
+++ b/g10/parse-packet.c
@@ -1,3343 +1,3346 @@
/* parse-packet.c - read packets
* Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006,
* 2007, 2009, 2010 Free Software Foundation, Inc.
* Copyright (C) 2014 Werner Koch
* Copyright (C) 2015 g10 Code GmbH
*
* 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
* the Free Software Foundation; either version 3 of the License, or
* (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
* along with this program; if not, see .
*/
#include
#include
#include
#include
#include "gpg.h"
#include "../common/util.h"
#include "packet.h"
#include "../common/iobuf.h"
#include "filter.h"
#include "photoid.h"
#include "options.h"
#include "main.h"
#include "../common/i18n.h"
#include "../common/host2net.h"
/* Maximum length of packets to avoid excessive memory allocation. */
#define MAX_KEY_PACKET_LENGTH (256 * 1024)
#define MAX_UID_PACKET_LENGTH ( 2 * 1024)
#define MAX_COMMENT_PACKET_LENGTH ( 64 * 1024)
#define MAX_ATTR_PACKET_LENGTH ( 16 * 1024*1024)
static int mpi_print_mode;
static int list_mode;
static estream_t listfp;
static int parse (parse_packet_ctx_t ctx, PACKET *pkt, int onlykeypkts,
off_t * retpos, int *skip, IOBUF out, int do_skip
#if DEBUG_PARSE_PACKET
, const char *dbg_w, const char *dbg_f, int dbg_l
#endif
);
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);
static void *read_rest (IOBUF inp, size_t pktlen);
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 gpg_error_t parse_ring_trust (parse_packet_ctx_t ctx,
unsigned long pktlen);
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);
/* Read a 16-bit value in MSB order (big endian) from an iobuf. */
static unsigned short
read_16 (IOBUF inp)
{
unsigned short a;
a = (unsigned short)iobuf_get_noeof (inp) << 8;
a |= iobuf_get_noeof (inp);
return a;
}
/* Read a 32-bit value in MSB order (big endian) from an iobuf. */
static unsigned long
read_32 (IOBUF inp)
{
unsigned long a;
a = (unsigned long)iobuf_get_noeof (inp) << 24;
a |= iobuf_get_noeof (inp) << 16;
a |= iobuf_get_noeof (inp) << 8;
a |= iobuf_get_noeof (inp);
return a;
}
/* 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 MSB first and is left padded with zero bits to
align on a byte boundary.
The caller must set *RET_NREAD to the maximum number of bytes to
read from the pipeline INP. This function sets *RET_NREAD to be
the number of bytes actually read from the pipeline.
If SECURE is true, the integer is stored in secure memory
(allocated using gcry_xmalloc_secure). */
static gcry_mpi_t
mpi_read (iobuf_t inp, unsigned int *ret_nread, int secure)
{
int c, c1, c2, i;
unsigned int nmax = *ret_nread;
unsigned int nbits, nbytes;
size_t nread = 0;
gcry_mpi_t a = NULL;
byte *buf = NULL;
byte *p;
if (!nmax)
goto overflow;
if ((c = c1 = iobuf_get (inp)) == -1)
goto leave;
if (++nread == nmax)
goto overflow;
nbits = c << 8;
if ((c = c2 = iobuf_get (inp)) == -1)
goto leave;
++nread;
nbits |= c;
if (nbits > MAX_EXTERN_MPI_BITS)
{
log_error ("mpi too large (%u bits)\n", nbits);
goto leave;
}
nbytes = (nbits + 7) / 8;
buf = secure ? gcry_xmalloc_secure (nbytes + 2) : gcry_xmalloc (nbytes + 2);
p = buf;
p[0] = c1;
p[1] = c2;
for (i = 0; i < nbytes; i++)
{
if (nread == nmax)
goto overflow;
c = iobuf_get (inp);
if (c == -1)
goto leave;
p[i + 2] = c;
nread ++;
}
if (gcry_mpi_scan (&a, GCRYMPI_FMT_PGP, buf, nread, &nread))
a = NULL;
*ret_nread = nread;
gcry_free(buf);
return a;
overflow:
log_error ("mpi larger than indicated length (%u bits)\n", 8*nmax);
leave:
*ret_nread = nread;
gcry_free(buf);
return a;
}
int
set_packet_list_mode (int mode)
{
int old = list_mode;
list_mode = mode;
/* We use stdout only if invoked by the --list-packets command
but switch to stderr in all other cases. This breaks the
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 there is code which switches
opt.list_mode back to 1 and we want to have all output to the
same stream. The MPI_PRINT_MODE will be enabled if the
corresponding debug flag is set or if we are in --list-packets
and --verbose is given.
Using stderr is not actually very clean because it bypasses the
logging code but it is a special thing anyway. I am not sure
whether using log_stream() would be better. Perhaps we should
enable the list mode only with a special option. */
if (!listfp)
{
if (opt.list_packets)
{
listfp = es_stdout;
if (opt.verbose)
mpi_print_mode = 1;
}
else
listfp = es_stderr;
if (DBG_MPI)
mpi_print_mode = 1;
}
return old;
}
/* If OPT.VERBOSE is set, print a warning that the algorithm ALGO is
not suitable for signing and encryption. */
static void
unknown_pubkey_warning (int algo)
{
static byte unknown_pubkey_algos[256];
/* First check whether the algorithm is usable but not suitable for
encryption/signing. */
if (pubkey_get_npkey (algo))
{
if (opt.verbose)
{
if (!pubkey_get_nsig (algo))
log_info ("public key algorithm %s not suitable for %s\n",
openpgp_pk_algo_name (algo), "signing");
if (!pubkey_get_nenc (algo))
log_info ("public key algorithm %s not suitable for %s\n",
openpgp_pk_algo_name (algo), "encryption");
}
}
else
{
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;
}
}
}
#if DEBUG_PARSE_PACKET
int
dbg_parse_packet (parse_packet_ctx_t ctx, PACKET *pkt,
const char *dbg_f, int dbg_l)
{
int skip, rc;
do
{
rc = parse (ctx, pkt, 0, NULL, &skip, NULL, 0, "parse", dbg_f, dbg_l);
}
while (skip && ! rc);
return rc;
}
#else /*!DEBUG_PARSE_PACKET*/
int
parse_packet (parse_packet_ctx_t ctx, PACKET *pkt)
{
int skip, rc;
do
{
rc = parse (ctx, pkt, 0, NULL, &skip, NULL, 0);
}
while (skip && ! rc);
return rc;
}
#endif /*!DEBUG_PARSE_PACKET*/
/*
* Like parse packet, but only return secret or public (sub)key
* packets.
*/
#if DEBUG_PARSE_PACKET
int
dbg_search_packet (parse_packet_ctx_t ctx, PACKET *pkt,
off_t * retpos, int with_uid,
const char *dbg_f, int dbg_l)
{
int skip, rc;
do
{
rc = parse (ctx, pkt, with_uid ? 2 : 1, retpos, &skip, NULL, 0, "search",
dbg_f, dbg_l);
}
while (skip && ! rc);
return rc;
}
#else /*!DEBUG_PARSE_PACKET*/
int
search_packet (parse_packet_ctx_t ctx, PACKET *pkt,
off_t * retpos, int with_uid)
{
int skip, rc;
do
{
rc = parse (ctx, pkt, with_uid ? 2 : 1, retpos, &skip, NULL, 0);
}
while (skip && ! rc);
return rc;
}
#endif /*!DEBUG_PARSE_PACKET*/
/*
* Copy all packets from INP to OUT, thereby removing unused spaces.
*/
#if DEBUG_PARSE_PACKET
int
dbg_copy_all_packets (iobuf_t inp, iobuf_t out, const char *dbg_f, int dbg_l)
{
PACKET pkt;
struct parse_packet_ctx_s parsectx;
int skip, rc = 0;
if (! out)
log_bug ("copy_all_packets: OUT may not be NULL.\n");
init_parse_packet (&parsectx, inp);
do
{
init_packet (&pkt);
}
while (!
(rc =
parse (&parsectx, &pkt, 0, NULL, &skip, out, 0, "copy",
dbg_f, dbg_l)));
deinit_parse_packet (&parsectx);
return rc;
}
#else /*!DEBUG_PARSE_PACKET*/
int
copy_all_packets (iobuf_t inp, iobuf_t out)
{
PACKET pkt;
struct parse_packet_ctx_s parsectx;
int skip, rc = 0;
if (! out)
log_bug ("copy_all_packets: OUT may not be NULL.\n");
init_parse_packet (&parsectx, inp);
do
{
init_packet (&pkt);
}
while (!(rc = parse (&parsectx, &pkt, 0, NULL, &skip, out, 0)));
deinit_parse_packet (&parsectx);
return rc;
}
#endif /*!DEBUG_PARSE_PACKET*/
/*
* Copy some packets from INP to OUT, thereby removing unused spaces.
* Stop at offset STOPoff (i.e. don't copy packets at this or later
* offsets)
*/
#if DEBUG_PARSE_PACKET
int
dbg_copy_some_packets (iobuf_t inp, iobuf_t out, off_t stopoff,
const char *dbg_f, int dbg_l)
{
int rc = 0;
PACKET pkt;
int skip;
struct parse_packet_ctx_s parsectx;
init_parse_packet (&parsectx, inp);
do
{
if (iobuf_tell (inp) >= stopoff)
{
deinit_parse_packet (&parsectx);
return 0;
}
init_packet (&pkt);
}
while (!(rc = parse (&parsectx, &pkt, 0, NULL, &skip, out, 0,
"some", dbg_f, dbg_l)));
deinit_parse_packet (&parsectx);
return rc;
}
#else /*!DEBUG_PARSE_PACKET*/
int
copy_some_packets (iobuf_t inp, iobuf_t out, off_t stopoff)
{
int rc = 0;
PACKET pkt;
struct parse_packet_ctx_s parsectx;
int skip;
init_parse_packet (&parsectx, inp);
do
{
if (iobuf_tell (inp) >= stopoff)
{
deinit_parse_packet (&parsectx);
return 0;
}
init_packet (&pkt);
}
while (!(rc = parse (&parsectx, &pkt, 0, NULL, &skip, out, 0)));
deinit_parse_packet (&parsectx);
return rc;
}
#endif /*!DEBUG_PARSE_PACKET*/
/*
* Skip over N packets
*/
#if DEBUG_PARSE_PACKET
int
dbg_skip_some_packets (iobuf_t inp, unsigned n, const char *dbg_f, int dbg_l)
{
int rc = 0;
int skip;
PACKET pkt;
struct parse_packet_ctx_s parsectx;
init_parse_packet (&parsectx, inp);
for (; n && !rc; n--)
{
init_packet (&pkt);
rc = parse (&parsectx, &pkt, 0, NULL, &skip, NULL, 1, "skip",
dbg_f, dbg_l);
}
deinit_parse_packet (&parsectx);
return rc;
}
#else /*!DEBUG_PARSE_PACKET*/
int
skip_some_packets (iobuf_t inp, unsigned int n)
{
int rc = 0;
int skip;
PACKET pkt;
struct parse_packet_ctx_s parsectx;
init_parse_packet (&parsectx, inp);
for (; n && !rc; n--)
{
init_packet (&pkt);
rc = parse (&parsectx, &pkt, 0, NULL, &skip, NULL, 1);
}
deinit_parse_packet (&parsectx);
return rc;
}
#endif /*!DEBUG_PARSE_PACKET*/
/* Parse a packet and save it in *PKT.
If OUT is not NULL and the packet is valid (its type is not 0),
then the header, the initial length field and the packet's contents
are written to OUT. In this case, the packet is not saved in *PKT.
ONLYKEYPKTS is a simple packet filter. If ONLYKEYPKTS is set to 1,
then only public subkey packets, public key packets, private subkey
packets and private key packets are parsed. The rest are skipped
(i.e., the header and the contents are read from the pipeline and
discarded). If ONLYKEYPKTS is set to 2, then in addition to the
above 4 types of packets, user id packets are also accepted.
DO_SKIP is a more coarse grained filter. Unless ONLYKEYPKTS is set
to 2 and the packet is a user id packet, all packets are skipped.
Finally, if a packet is invalid (it's type is 0), it is skipped.
If a packet is skipped and SKIP is not NULL, then *SKIP is set to
1.
Note: ONLYKEYPKTS and DO_SKIP are only respected if OUT is NULL,
i.e., the packets are not simply being copied.
If RETPOS is not NULL, then the position of CTX->INP (as returned by
iobuf_tell) is saved there before any data is read from CTX->INP.
*/
static int
parse (parse_packet_ctx_t ctx, PACKET *pkt, int onlykeypkts, off_t * retpos,
int *skip, IOBUF out, int do_skip
#if DEBUG_PARSE_PACKET
, const char *dbg_w, const char *dbg_f, int dbg_l
#endif
)
{
int rc = 0;
iobuf_t inp;
int c, ctb, pkttype, lenbytes;
unsigned long pktlen;
byte hdr[8];
int hdrlen;
int new_ctb = 0, partial = 0;
int with_uid = (onlykeypkts == 2);
off_t pos;
*skip = 0;
inp = ctx->inp;
again:
log_assert (!pkt->pkt.generic);
if (retpos || list_mode)
{
pos = iobuf_tell (inp);
if (retpos)
*retpos = pos;
}
else
pos = 0; /* (silence compiler warning) */
/* The first byte of a packet is the so-called tag. The highest bit
must be set. */
if ((ctb = iobuf_get (inp)) == -1)
{
rc = -1;
goto leave;
}
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;
}
/* Immediately following the header is the length. There are two
formats: the old format and the new format. If bit 6 (where the
least significant bit is bit 0) is set in the tag, then we are
dealing with a new format packet. Otherwise, it is an old format
packet. */
pktlen = 0;
new_ctb = !!(ctb & 0x40);
if (new_ctb)
{
/* Get the packet's type. This is encoded in the 6 least
significant bits of the tag. */
pkttype = ctb & 0x3f;
/* Extract the packet's length. New format packets have 4 ways
to encode the packet length. The value of the first byte
determines the encoding and partially determines the length.
See section 4.2.2 of RFC 4880 for details. */
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;
}
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)
{
int i;
char value[4];
for (i = 0; i < 4; i ++)
{
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;
}
value[i] = hdr[hdrlen++] = c;
}
pktlen = buf32_to_ulong (value);
}
else /* Partial body length. */
{
switch (pkttype)
{
case PKT_PLAINTEXT:
case PKT_ENCRYPTED:
case PKT_ENCRYPTED_MDC:
case PKT_COMPRESSED:
iobuf_set_partial_body_length_mode (inp, c & 0xff);
pktlen = 0; /* To indicate partial length. */
partial = 1;
break;
default:
log_error ("%s: partial length invalid for"
" packet type %d\n", iobuf_where (inp), pkttype);
rc = gpg_error (GPG_ERR_INV_PACKET);
goto leave;
}
}
}
else
/* This is an old format packet. */
{
/* Extract the packet's type. This is encoded in bits 2-5. */
pkttype = (ctb >> 2) & 0xf;
/* The type of length encoding is encoded in bits 0-1 of the
tag. */
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;
c = iobuf_get (inp);
if (c == -1)
{
log_error ("%s: length invalid\n", iobuf_where (inp));
rc = gpg_error (GPG_ERR_INV_PACKET);
goto leave;
}
pktlen |= hdr[hdrlen++] = c;
}
}
}
/* Sometimes the decompressing layer enters an error state in which
it simply outputs 0xff for every byte read. If we have a stream
of 0xff bytes, then it will be detected as a new format packet
with type 63 and a 4-byte encoded length that is 4G-1. Since
packets with type 63 are private and we use them as a control
packet, which won't be 4 GB, we reject such packets as
invalid. */
if (pkttype == 63 && pktlen == 0xFFFFFFFF)
{
/* 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);
}
if (out && pkttype)
{
/* This type of copying won't work if the packet uses a partial
body length. (In other words, this only works if HDR is
actually the length.) Currently, no callers require this
functionality so we just log this as an error. */
if (partial)
{
log_error ("parse: Can't copy partial packet. Aborting.\n");
rc = gpg_error (GPG_ERR_INV_PACKET);
goto leave;
}
rc = iobuf_write (out, hdr, hdrlen);
if (!rc)
rc = copy_packet (inp, out, pkttype, pktlen, partial);
goto leave;
}
if (with_uid && pkttype == PKT_USER_ID)
/* If ONLYKEYPKTS is set to 2, then we never skip user id packets,
even if DO_SKIP is set. */
;
else if (do_skip
/* type==0 is not allowed. This is an invalid packet. */
|| !pkttype
/* When ONLYKEYPKTS is set, we don't skip keys. */
|| (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;
}
if (DBG_PACKET)
{
#if DEBUG_PARSE_PACKET
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);
#else
log_debug ("parse_packet(iob=%d): type=%d length=%lu%s\n",
iobuf_id (inp), pkttype, pktlen,
new_ctb ? " (new_ctb)" : "");
#endif
}
if (list_mode)
es_fprintf (listfp, "# off=%lu ctb=%02x tag=%d hlen=%d plen=%lu%s%s\n",
(unsigned long)pos, ctb, pkttype, hdrlen, pktlen,
partial? (new_ctb ? " partial" : " indeterminate") :"",
new_ctb? " new-ctb":"");
+ /* Count it. */
+ ctx->n_parsed_packets++;
+
pkt->pkttype = pkttype;
rc = GPG_ERR_UNKNOWN_PACKET; /* default error */
switch (pkttype)
{
case PKT_PUBLIC_KEY:
case PKT_PUBLIC_SUBKEY:
case PKT_SECRET_KEY:
case PKT_SECRET_SUBKEY:
pkt->pkt.public_key = xmalloc_clear (sizeof *pkt->pkt.public_key);
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:
{
rc = parse_ring_trust (ctx, pktlen);
if (!rc)
goto again; /* Directly read the next packet. */
}
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;
case PKT_MARKER:
rc = parse_marker (inp, pkttype, pktlen);
break;
default:
/* Unknown packet. Skip it. */
skip_packet (inp, pkttype, pktlen, partial);
break;
}
/* Store a shallow copy of certain packets in the context. */
free_packet (NULL, ctx);
if (!rc && (pkttype == PKT_PUBLIC_KEY
|| pkttype == PKT_SECRET_KEY
|| pkttype == PKT_USER_ID
|| pkttype == PKT_ATTRIBUTE
|| pkttype == PKT_SIGNATURE))
{
ctx->last_pkt = *pkt;
}
leave:
/* FIXME: We leak in case of an error (see the xmalloc's above). */
if (!rc && iobuf_error (inp))
rc = GPG_ERR_INV_KEYRING;
/* FIXME: We use only the error code for now to avoid problems with
callers which have not been checked to always use gpg_err_code()
when comparing error codes. */
return rc == -1? -1 : gpg_err_code (rc);
}
static void
dump_hex_line (int c, int *i)
{
if (*i && !(*i % 8))
{
if (*i && !(*i % 24))
es_fprintf (listfp, "\n%4d:", *i);
else
es_putc (' ', listfp);
}
if (c == -1)
es_fprintf (listfp, " EOF");
else
es_fprintf (listfp, " %02x", c);
++*i;
}
/* Copy the contents of a packet from the pipeline IN to the pipeline
OUT.
The header and length have already been read from INP and the
decoded values are given as PKGTYPE and PKTLEN.
If the packet is a partial body length packet (RFC 4880, Section
4.2.2.4), then iobuf_set_partial_block_modeiobuf_set_partial_block_mode
should already have been called on INP and PARTIAL should be set.
If PARTIAL is set or PKTLEN is 0 and PKTTYPE is PKT_COMPRESSED,
copy until the first EOF is encountered on INP.
Returns 0 on success and an error code if an error occurs. */
static int
copy_packet (IOBUF inp, IOBUF out, int pkttype,
unsigned long pktlen, int partial)
{
int rc;
int n;
char buf[100];
if (partial)
{
while ((n = iobuf_read (inp, buf, sizeof (buf))) != -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, sizeof (buf))) != -1)
if ((rc = iobuf_write (out, buf, n)))
return rc; /* write error */
}
else
{
for (; pktlen; pktlen -= n)
{
n = pktlen > sizeof (buf) ? sizeof (buf) : 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 */
}
}
return 0;
}
/* Skip an unknown packet. PKTTYPE is the packet's type, PKTLEN is
the length of the packet's content and PARTIAL is whether partial
body length encoding in used (in this case PKTLEN is ignored). */
static void
skip_packet (IOBUF inp, int pkttype, unsigned long pktlen, int partial)
{
if (list_mode)
{
es_fprintf (listfp, ":unknown packet: type %2d, length %lu\n",
pkttype, pktlen);
if (pkttype)
{
int c, i = 0;
es_fputs ("dump:", listfp);
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;
}
}
es_putc ('\n', listfp);
return;
}
}
iobuf_skip_rest (inp, pktlen, partial);
}
/* Read PKTLEN bytes form INP and return them in a newly allocated
buffer. In case of an error (including reading fewer than PKTLEN
bytes from INP before EOF is returned), NULL is returned and an
error message is logged. */
static void *
read_rest (IOBUF inp, size_t pktlen)
{
int c;
byte *buf, *p;
buf = xtrymalloc (pktlen);
if (!buf)
{
gpg_error_t err = gpg_error_from_syserror ();
log_error ("error reading rest of packet: %s\n", gpg_strerror (err));
return NULL;
}
for (p = buf; pktlen; pktlen--)
{
c = iobuf_get (inp);
if (c == -1)
{
log_error ("premature eof while reading rest of packet\n");
xfree (buf);
return NULL;
}
*p++ = c;
}
return buf;
}
/* 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)
{
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);
buffer[0] = nbytes;
for (i = 0; i < nbytes; i++)
{
c = iobuf_get (inp);
if (c < 0)
return gpg_error (GPG_ERR_INV_PACKET);
++*r_nread;
buffer[1+i] = c;
}
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)
{
xfree (tmpbuf);
return gpg_error_from_syserror ();
}
return 0;
}
/* Parse a marker packet. */
static int
parse_marker (IOBUF inp, int pkttype, unsigned long pktlen)
{
(void) pkttype;
if (pktlen != 3)
goto fail;
if (iobuf_get (inp) != 'P')
{
pktlen--;
goto fail;
}
if (iobuf_get (inp) != 'G')
{
pktlen--;
goto fail;
}
if (iobuf_get (inp) != 'P')
{
pktlen--;
goto fail;
}
if (list_mode)
es_fputs (":marker packet: PGP\n", listfp);
return 0;
fail:
log_error ("invalid marker packet\n");
if (list_mode)
es_fputs (":marker packet: [invalid]\n", listfp);
iobuf_skip_rest (inp, pktlen, 0);
return GPG_ERR_INV_PACKET;
}
static int
parse_symkeyenc (IOBUF inp, int pkttype, unsigned long pktlen,
PACKET * packet)
{
PKT_symkey_enc *k;
int rc = 0;
int i, version, s2kmode, cipher_algo, hash_algo, seskeylen, minlen;
if (pktlen < 4)
{
log_error ("packet(%d) too short\n", pkttype);
if (list_mode)
es_fprintf (listfp, ":symkey enc packet: [too short]\n");
rc = gpg_error (GPG_ERR_INV_PACKET);
goto leave;
}
version = iobuf_get_noeof (inp);
pktlen--;
if (version != 4)
{
log_error ("packet(%d) with unknown version %d\n", pkttype, version);
if (list_mode)
es_fprintf (listfp, ":symkey enc packet: [unknown version]\n");
rc = gpg_error (GPG_ERR_INV_PACKET);
goto leave;
}
if (pktlen > 200)
{ /* (we encode the seskeylen in a byte) */
log_error ("packet(%d) too large\n", pkttype);
if (list_mode)
es_fprintf (listfp, ":symkey enc packet: [too large]\n");
rc = gpg_error (GPG_ERR_INV_PACKET);
goto leave;
}
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);
if (list_mode)
es_fprintf (listfp, ":symkey enc packet: [unknown S2K mode]\n");
goto leave;
}
if (minlen > pktlen)
{
log_error ("packet with S2K %d too short\n", s2kmode);
if (list_mode)
es_fprintf (listfp, ":symkey enc packet: [too short]\n");
rc = gpg_error (GPG_ERR_INV_PACKET);
goto leave;
}
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"));
}
log_assert (!pktlen);
if (list_mode)
{
es_fprintf (listfp,
":symkey enc packet: version %d, cipher %d, s2k %d, hash %d",
version, cipher_algo, s2kmode, hash_algo);
if (seskeylen)
es_fprintf (listfp, ", seskey %d bits", (seskeylen - 1) * 8);
es_fprintf (listfp, "\n");
if (s2kmode == 1 || s2kmode == 3)
{
es_fprintf (listfp, "\tsalt ");
es_write_hexstring (listfp, k->s2k.salt, 8, 0, NULL);
if (s2kmode == 3)
es_fprintf (listfp, ", count %lu (%lu)",
S2K_DECODE_COUNT ((ulong) k->s2k.count),
(ulong) k->s2k.count);
es_fprintf (listfp, "\n");
}
}
leave:
iobuf_skip_rest (inp, pktlen, 0);
return rc;
}
static int
parse_pubkeyenc (IOBUF inp, int pkttype, unsigned long pktlen,
PACKET * packet)
{
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);
if (list_mode)
es_fputs (":pubkey enc packet: [too short]\n", listfp);
rc = gpg_error (GPG_ERR_INV_PACKET);
goto leave;
}
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);
if (list_mode)
es_fputs (":pubkey enc packet: [unknown version]\n", listfp);
rc = gpg_error (GPG_ERR_INV_PACKET);
goto leave;
}
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)
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]);
ndata = pubkey_get_nenc (k->pubkey_algo);
if (!ndata)
{
if (list_mode)
es_fprintf (listfp, "\tunsupported algorithm %d\n", k->pubkey_algo);
unknown_pubkey_warning (k->pubkey_algo);
k->data[0] = NULL; /* No need to store the encrypted data. */
}
else
{
for (i = 0; i < ndata; i++)
{
if (k->pubkey_algo == PUBKEY_ALGO_ECDH && i == 1)
{
size_t n;
rc = read_size_body (inp, pktlen, &n, k->data+i);
pktlen -= n;
}
else
{
int n = pktlen;
k->data[i] = mpi_read (inp, &n, 0);
pktlen -= n;
if (!k->data[i])
rc = gpg_error (GPG_ERR_INV_PACKET);
}
if (rc)
goto leave;
if (list_mode)
{
es_fprintf (listfp, "\tdata: ");
mpi_print (listfp, k->data[i], mpi_print_mode);
es_putc ('\n', listfp);
}
}
}
leave:
iobuf_skip_rest (inp, pktlen, 0);
return rc;
}
/* Dump a subpacket to LISTFP. BUFFER contains the subpacket in
question and points to the type field in the subpacket header (not
the start of the header). TYPE is the subpacket's type with the
critical bit cleared. CRITICAL is the value of the CRITICAL bit.
BUFLEN is the length of the buffer and LENGTH is the length of the
subpacket according to the subpacket's header. */
static void
dump_sig_subpkt (int hashed, int type, int critical,
const byte * buffer, size_t buflen, size_t length)
{
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)
{
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);
}
buffer++;
length--;
es_fprintf (listfp, "\t%s%ssubpkt %d len %u (", /*) */
critical ? "critical " : "",
hashed ? "hashed " : "", type, (unsigned) length);
if (length > buflen)
{
es_fprintf (listfp, "too short: buffer is only %u)\n", (unsigned) buflen);
return;
}
switch (type)
{
case SIGSUBPKT_SIG_CREATED:
if (length >= 4)
es_fprintf (listfp, "sig created %s",
strtimestamp (buf32_to_u32 (buffer)));
break;
case SIGSUBPKT_SIG_EXPIRE:
if (length >= 4)
{
if (buf32_to_u32 (buffer))
es_fprintf (listfp, "sig expires after %s",
strtimevalue (buf32_to_u32 (buffer)));
else
es_fprintf (listfp, "sig does not expire");
}
break;
case SIGSUBPKT_EXPORTABLE:
if (length)
es_fprintf (listfp, "%sexportable", *buffer ? "" : "not ");
break;
case SIGSUBPKT_TRUST:
if (length != 2)
p = "[invalid trust subpacket]";
else
es_fprintf (listfp, "trust signature of depth %d, value %d", buffer[0],
buffer[1]);
break;
case SIGSUBPKT_REGEXP:
if (!length)
p = "[invalid regexp subpacket]";
else
{
es_fprintf (listfp, "regular expression: \"");
es_write_sanitized (listfp, buffer, length, "\"", NULL);
p = "\"";
}
break;
case SIGSUBPKT_REVOCABLE:
if (length)
es_fprintf (listfp, "%srevocable", *buffer ? "" : "not ");
break;
case SIGSUBPKT_KEY_EXPIRE:
if (length >= 4)
{
if (buf32_to_u32 (buffer))
es_fprintf (listfp, "key expires after %s",
strtimevalue (buf32_to_u32 (buffer)));
else
es_fprintf (listfp, "key does not expire");
}
break;
case SIGSUBPKT_PREF_SYM:
es_fputs ("pref-sym-algos:", listfp);
for (i = 0; i < length; i++)
es_fprintf (listfp, " %d", buffer[i]);
break;
case SIGSUBPKT_REV_KEY:
es_fputs ("revocation key: ", listfp);
if (length < 22)
p = "[too short]";
else
{
es_fprintf (listfp, "c=%02x a=%d f=", buffer[0], buffer[1]);
for (i = 2; i < length; i++)
es_fprintf (listfp, "%02X", buffer[i]);
}
break;
case SIGSUBPKT_ISSUER:
if (length >= 8)
es_fprintf (listfp, "issuer key ID %08lX%08lX",
(ulong) buf32_to_u32 (buffer),
(ulong) buf32_to_u32 (buffer + 4));
break;
case SIGSUBPKT_ISSUER_FPR:
if (length >= 21)
{
char *tmp;
es_fprintf (listfp, "issuer fpr v%d ", buffer[0]);
tmp = bin2hex (buffer+1, length-1, NULL);
if (tmp)
{
es_fputs (tmp, listfp);
xfree (tmp);
}
}
break;
case SIGSUBPKT_NOTATION:
{
es_fputs ("notation: ", listfp);
if (length < 8)
p = "[too short]";
else
{
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]";
else
{
es_write_sanitized (listfp, s, n1, ")", NULL);
es_putc ('=', listfp);
if (*buffer & 0x80)
es_write_sanitized (listfp, s + n1, n2, ")", NULL);
else
p = "[not human readable]";
}
}
}
break;
case SIGSUBPKT_PREF_HASH:
es_fputs ("pref-hash-algos:", listfp);
for (i = 0; i < length; i++)
es_fprintf (listfp, " %d", buffer[i]);
break;
case SIGSUBPKT_PREF_COMPR:
es_fputs ("pref-zip-algos:", listfp);
for (i = 0; i < length; i++)
es_fprintf (listfp, " %d", buffer[i]);
break;
case SIGSUBPKT_KS_FLAGS:
es_fputs ("keyserver preferences:", listfp);
for (i = 0; i < length; i++)
es_fprintf (listfp, " %02X", buffer[i]);
break;
case SIGSUBPKT_PREF_KS:
es_fputs ("preferred keyserver: ", listfp);
es_write_sanitized (listfp, buffer, length, ")", NULL);
break;
case SIGSUBPKT_PRIMARY_UID:
p = "primary user ID";
break;
case SIGSUBPKT_POLICY:
es_fputs ("policy: ", listfp);
es_write_sanitized (listfp, buffer, length, ")", NULL);
break;
case SIGSUBPKT_KEY_FLAGS:
es_fputs ("key flags:", listfp);
for (i = 0; i < length; i++)
es_fprintf (listfp, " %02X", buffer[i]);
break;
case SIGSUBPKT_SIGNERS_UID:
p = "signer's user ID";
break;
case SIGSUBPKT_REVOC_REASON:
if (length)
{
es_fprintf (listfp, "revocation reason 0x%02x (", *buffer);
es_write_sanitized (listfp, buffer + 1, length - 1, ")", NULL);
p = ")";
}
break;
case SIGSUBPKT_ARR:
es_fputs ("Big Brother's key (ignored): ", listfp);
if (length < 22)
p = "[too short]";
else
{
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);
}
break;
case SIGSUBPKT_FEATURES:
es_fputs ("features:", listfp);
for (i = 0; i < length; i++)
es_fprintf (listfp, " %02x", buffer[i]);
break;
case SIGSUBPKT_SIGNATURE:
es_fputs ("signature: ", listfp);
if (length < 17)
p = "[too short]";
else
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]);
break;
default:
if (type >= 100 && type <= 110)
p = "experimental / private subpacket";
else
p = "?";
break;
}
es_fprintf (listfp, "%s)\n", p ? p : "");
}
/*
* Returns: >= 0 use this offset into buffer
* -1 explicitly reject returning this type
* -2 subpacket too short
*/
int
parse_one_sig_subpkt (const byte * buffer, size_t n, int type)
{
switch (type)
{
case SIGSUBPKT_REV_KEY:
if (n < 22)
break;
return 0;
case SIGSUBPKT_SIG_CREATED:
case SIGSUBPKT_SIG_EXPIRE:
case SIGSUBPKT_KEY_EXPIRE:
if (n < 4)
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:
if (!n)
break;
return 0;
case SIGSUBPKT_ISSUER: /* issuer key ID */
if (n < 8)
break;
return 0;
case SIGSUBPKT_ISSUER_FPR: /* issuer key ID */
if (n < 21)
break;
return 0;
case SIGSUBPKT_NOTATION:
/* minimum length needed, and the subpacket must be well-formed
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)
break;
return 0;
case SIGSUBPKT_PRIMARY_UID:
if (n != 1)
break;
return 0;
case SIGSUBPKT_TRUST:
if (n != 2)
break;
return 0;
default:
return 0;
}
return -2;
}
/* Return true if we understand the critical notation. */
static int
can_handle_critical_notation (const byte * name, size_t len)
{
if (len == 32 && memcmp (name, "preferred-email-encoding@pgp.com", 32) == 0)
return 1;
if (len == 21 && memcmp (name, "pka-address@gnupg.org", 21) == 0)
return 1;
return 0;
}
static int
can_handle_critical (const byte * buffer, size_t n, int type)
{
switch (type)
{
case SIGSUBPKT_NOTATION:
if (n >= 8)
{
size_t notation_len = ((buffer[4] << 8) | buffer[5]);
if (n - 8 >= notation_len)
return can_handle_critical_notation (buffer + 8, notation_len);
}
return 0;
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:
case SIGSUBPKT_ISSUER: /* issuer key ID */
case SIGSUBPKT_ISSUER_FPR: /* issuer fingerprint */
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:
case SIGSUBPKT_REVOC_REASON: /* At least we know about it. */
return 1;
default:
return 0;
}
}
const byte *
enum_sig_subpkt (const subpktarea_t * pktbuf, sigsubpkttype_t reqtype,
size_t * ret_n, int *start, int *critical)
{
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)
{
static char dummy[] = "x";
/* Return a value different from NULL to indicate that
* there is no critical bit we do not understand. */
return reqtype == SIGSUBPKT_TEST_CRITICAL ? dummy : NULL;
}
buffer = pktbuf->data;
buflen = pktbuf->len;
while (buflen)
{
n = *buffer++;
buflen--;
if (n == 255) /* 4 byte length header. */
{
if (buflen < 4)
goto too_short;
n = buf32_to_size_t (buffer);
buffer += 4;
buflen -= 4;
}
else if (n >= 192) /* 4 byte special encoded length header. */
{
if (buflen < 2)
goto too_short;
n = ((n - 192) << 8) + *buffer + 192;
buffer++;
buflen--;
}
if (buflen < n)
goto too_short;
type = *buffer;
if (type & 0x80)
{
type &= 0x7f;
*critical = 1;
}
else
*critical = 0;
if (!(++seq > reqseq))
;
else if (reqtype == SIGSUBPKT_TEST_CRITICAL)
{
if (*critical)
{
if (n - 1 > buflen + 1)
goto too_short;
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. */
}
}
}
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)
/* Returning NULL means we found a subpacket with the critical bit
set that we don't grok. We've iterated over all the subpackets
and haven't found such a packet so we need to return a non-NULL
value. */
return buffer;
/* 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;
}
const byte *
parse_sig_subpkt (const subpktarea_t * buffer, sigsubpkttype_t reqtype,
size_t * ret_n)
{
return enum_sig_subpkt (buffer, reqtype, ret_n, NULL, NULL);
}
const byte *
parse_sig_subpkt2 (PKT_signature * sig, sigsubpkttype_t reqtype)
{
const byte *p;
p = parse_sig_subpkt (sig->hashed, reqtype, NULL);
if (!p)
p = parse_sig_subpkt (sig->unhashed, reqtype, NULL);
return p;
}
/* Find all revocation keys. Look in hashed area only. */
void
parse_revkeys (PKT_signature * sig)
{
const byte *revkey;
int seq = 0;
size_t len;
if (sig->sig_class != 0x1F)
return;
while ((revkey = enum_sig_subpkt (sig->hashed, SIGSUBPKT_REV_KEY,
&len, &seq, NULL)))
{
if (/* The only valid length is 22 bytes. See RFC 4880
5.2.3.15. */
len == 22
/* 0x80 bit must be set on the class. */
&& (revkey[0] & 0x80))
{
sig->revkey = xrealloc (sig->revkey,
sizeof (struct revocation_key) *
(sig->numrevkeys + 1));
/* Copy the individual fields. */
sig->revkey[sig->numrevkeys].class = revkey[0];
sig->revkey[sig->numrevkeys].algid = revkey[1];
memcpy (sig->revkey[sig->numrevkeys].fpr, &revkey[2], 20);
sig->numrevkeys++;
}
}
}
int
parse_signature (IOBUF inp, int pkttype, unsigned long pktlen,
PKT_signature * sig)
{
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);
if (list_mode)
es_fputs (":signature packet: [too short]\n", listfp);
goto leave;
}
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);
if (list_mode)
es_fputs (":signature packet: [unknown version]\n", listfp);
rc = gpg_error (GPG_ERR_INV_PACKET);
goto leave;
}
if (!is_v4)
{
if (pktlen == 0)
goto underflow;
md5_len = iobuf_get_noeof (inp);
pktlen--;
}
if (pktlen == 0)
goto underflow;
sig->sig_class = iobuf_get_noeof (inp);
pktlen--;
if (!is_v4)
{
if (pktlen < 12)
goto underflow;
sig->timestamp = read_32 (inp);
pktlen -= 4;
sig->keyid[0] = read_32 (inp);
pktlen -= 4;
sig->keyid[1] = read_32 (inp);
pktlen -= 4;
}
if (pktlen < 2)
goto underflow;
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. */
{
if (pktlen < 2)
goto underflow;
n = read_16 (inp);
pktlen -= 2; /* Length of hashed data. */
if (pktlen < n)
goto underflow;
if (n > 10000)
{
log_error ("signature packet: hashed data too long\n");
if (list_mode)
es_fputs (":signature packet: [hashed data too long]\n", listfp);
rc = GPG_ERR_INV_PACKET;
goto leave;
}
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");
if (list_mode)
es_fputs (":signature packet: [premature eof]\n", listfp);
rc = -1;
goto leave;
}
pktlen -= n;
}
if (pktlen < 2)
goto underflow;
n = read_16 (inp);
pktlen -= 2; /* Length of unhashed data. */
if (pktlen < n)
goto underflow;
if (n > 10000)
{
log_error ("signature packet: unhashed data too long\n");
if (list_mode)
es_fputs (":signature packet: [unhashed data too long]\n", listfp);
rc = GPG_ERR_INV_PACKET;
goto leave;
}
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");
if (list_mode)
es_fputs (":signature packet: [premature eof]\n", listfp);
rc = -1;
goto leave;
}
pktlen -= n;
}
}
if (pktlen < 2)
goto underflow;
sig->digest_start[0] = iobuf_get_noeof (inp);
pktlen--;
sig->digest_start[1] = iobuf_get_noeof (inp);
pktlen--;
if (is_v4 && sig->pubkey_algo) /* Extract required information. */
{
const byte *p;
size_t len;
/* 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;
p = parse_sig_subpkt (sig->hashed, SIGSUBPKT_SIG_CREATED, NULL);
if (p)
sig->timestamp = buf32_to_u32 (p);
else if (!(sig->pubkey_algo >= 100 && sig->pubkey_algo <= 110)
&& opt.verbose)
log_info ("signature packet without timestamp\n");
p = parse_sig_subpkt2 (sig, SIGSUBPKT_ISSUER);
if (p)
{
sig->keyid[0] = buf32_to_u32 (p);
sig->keyid[1] = buf32_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 && buf32_to_u32 (p))
sig->expiredate = sig->timestamp + buf32_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_SIGNERS_UID, &len);
if (p && len)
{
sig->signers_uid = try_make_printable_string (p, len, 0);
if (!sig->signers_uid)
{
rc = gpg_error_from_syserror ();
goto leave;
}
}
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;
}
/* 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. */
p = parse_sig_subpkt2 (sig, SIGSUBPKT_EXPORTABLE);
if (p && *p == 0)
sig->flags.exportable = 0;
/* Find all revocation keys. */
if (sig->sig_class == 0x1F)
parse_revkeys (sig);
}
if (list_mode)
{
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]);
if (is_v4)
{
parse_sig_subpkt (sig->hashed, SIGSUBPKT_LIST_HASHED, NULL);
parse_sig_subpkt (sig->unhashed, SIGSUBPKT_LIST_UNHASHED, NULL);
}
}
ndata = pubkey_get_nsig (sig->pubkey_algo);
if (!ndata)
{
if (list_mode)
es_fprintf (listfp, "\tunknown algorithm %d\n", sig->pubkey_algo);
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 = GPG_ERR_INV_PACKET;
}
else
{
sig->data[0] =
gcry_mpi_set_opaque (NULL, read_rest (inp, pktlen), pktlen * 8);
pktlen = 0;
}
}
else
{
for (i = 0; i < ndata; i++)
{
n = pktlen;
sig->data[i] = mpi_read (inp, &n, 0);
pktlen -= n;
if (list_mode)
{
es_fprintf (listfp, "\tdata: ");
mpi_print (listfp, sig->data[i], mpi_print_mode);
es_putc ('\n', listfp);
}
if (!sig->data[i])
rc = GPG_ERR_INV_PACKET;
}
}
leave:
iobuf_skip_rest (inp, pktlen, 0);
return rc;
underflow:
log_error ("packet(%d) too short\n", pkttype);
if (list_mode)
es_fputs (":signature packet: [too short]\n", listfp);
iobuf_skip_rest (inp, pktlen, 0);
return GPG_ERR_INV_PACKET;
}
static int
parse_onepass_sig (IOBUF inp, int pkttype, unsigned long pktlen,
PKT_onepass_sig * ops)
{
int version;
int rc = 0;
if (pktlen < 13)
{
log_error ("packet(%d) too short\n", pkttype);
if (list_mode)
es_fputs (":onepass_sig packet: [too short]\n", listfp);
rc = gpg_error (GPG_ERR_INV_PACKET);
goto leave;
}
version = iobuf_get_noeof (inp);
pktlen--;
if (version != 3)
{
log_error ("onepass_sig with unknown version %d\n", version);
if (list_mode)
es_fputs (":onepass_sig packet: [unknown version]\n", listfp);
rc = gpg_error (GPG_ERR_INV_PACKET);
goto leave;
}
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)
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);
leave:
iobuf_skip_rest (inp, pktlen, 0);
return rc;
}
static int
parse_key (IOBUF inp, int pkttype, unsigned long pktlen,
byte * hdr, int hdrlen, PACKET * pkt)
{
gpg_error_t err = 0;
int i, version, algorithm;
unsigned long timestamp, expiredate, max_expiredate;
int npkey, nskey;
u32 keyid[2];
PKT_public_key *pk;
(void) hdr;
pk = pkt->pkt.public_key; /* PK has been cleared. */
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)
{
es_fprintf (listfp, ":rfc1991 comment packet: \"");
for (; pktlen; pktlen--)
{
int c;
c = iobuf_get (inp);
if (c == -1)
break; /* Ooops: shorter than indicated. */
if (c >= ' ' && c <= 'z')
es_putc (c, listfp);
else
es_fprintf (listfp, "\\x%02x", c);
}
es_fprintf (listfp, "\"\n");
}
iobuf_skip_rest (inp, pktlen, 0);
return 0;
}
else if (version == 4)
{
/* The only supported version. Use an older gpg
version (i.e. gpg 1.4) to parse v3 packets. */
}
else if (version == 2 || version == 3)
{
if (opt.verbose > 1)
log_info ("packet(%d) with obsolete version %d\n", pkttype, version);
if (list_mode)
es_fprintf (listfp, ":key packet: [obsolete version %d]\n", version);
pk->version = version;
err = gpg_error (GPG_ERR_LEGACY_KEY);
goto leave;
}
else
{
log_error ("packet(%d) with unknown version %d\n", pkttype, version);
if (list_mode)
es_fputs (":key packet: [unknown version]\n", listfp);
err = gpg_error (GPG_ERR_INV_PACKET);
goto leave;
}
if (pktlen < 11)
{
log_error ("packet(%d) too short\n", pkttype);
if (list_mode)
es_fputs (":key packet: [too short]\n", listfp);
err = gpg_error (GPG_ERR_INV_PACKET);
goto leave;
}
else if (pktlen > MAX_KEY_PACKET_LENGTH)
{
log_error ("packet(%d) too large\n", pkttype);
if (list_mode)
es_fputs (":key packet: [too larget]\n", listfp);
err = gpg_error (GPG_ERR_INV_PACKET);
goto leave;
}
timestamp = read_32 (inp);
pktlen -= 4;
expiredate = 0; /* have to get it from the selfsignature */
max_expiredate = 0;
algorithm = iobuf_get_noeof (inp);
pktlen--;
if (list_mode)
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);
pk->timestamp = timestamp;
pk->expiredate = expiredate;
pk->max_expiredate = max_expiredate;
pk->hdrbytes = hdrlen;
pk->version = version;
pk->flags.primary = (pkttype == PKT_PUBLIC_KEY || pkttype == PKT_SECRET_KEY);
pk->pubkey_algo = algorithm;
nskey = pubkey_get_nskey (algorithm);
npkey = pubkey_get_npkey (algorithm);
if (!npkey)
{
if (list_mode)
es_fprintf (listfp, "\tunknown algorithm %d\n", algorithm);
unknown_pubkey_warning (algorithm);
}
if (!npkey)
{
/* Unknown algorithm - put data into an opaque MPI. */
pk->pkey[0] = gcry_mpi_set_opaque (NULL,
read_rest (inp, pktlen), pktlen * 8);
pktlen = 0;
goto leave;
}
else
{
for (i = 0; i < npkey; i++)
{
if ( (algorithm == PUBKEY_ALGO_ECDSA && (i == 0))
|| (algorithm == PUBKEY_ALGO_EDDSA && (i == 0))
|| (algorithm == PUBKEY_ALGO_ECDH && (i == 0 || i == 2)))
{
/* Read the OID (i==1) or the KDF params (i==2). */
size_t n;
err = read_size_body (inp, pktlen, &n, pk->pkey+i);
pktlen -= n;
}
else
{
unsigned int n = pktlen;
pk->pkey[i] = mpi_read (inp, &n, 0);
pktlen -= n;
if (!pk->pkey[i])
err = gpg_error (GPG_ERR_INV_PACKET);
}
if (err)
goto leave;
if (list_mode)
{
es_fprintf (listfp, "\tpkey[%d]: ", i);
mpi_print (listfp, pk->pkey[i], mpi_print_mode);
if ((algorithm == PUBKEY_ALGO_ECDSA
|| algorithm == PUBKEY_ALGO_EDDSA
|| algorithm == PUBKEY_ALGO_ECDH) && i==0)
{
char *curve = openpgp_oid_to_str (pk->pkey[0]);
const char *name = openpgp_oid_to_curve (curve, 0);
es_fprintf (listfp, " %s (%s)", name?name:"", curve);
xfree (curve);
}
es_putc ('\n', listfp);
}
}
}
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;
if (pktlen < 1)
{
err = gpg_error (GPG_ERR_INV_PACKET);
goto leave;
}
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);
pktlen--;
if (ski->algo)
{
ski->is_protected = 1;
ski->s2k.count = 0;
if (ski->algo == 254 || ski->algo == 255)
{
if (pktlen < 3)
{
err = gpg_error (GPG_ERR_INV_PACKET);
goto leave;
}
ski->sha1chk = (ski->algo == 254);
ski->algo = iobuf_get_noeof (inp);
pktlen--;
/* 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);
pktlen--;
ski->s2k.hash_algo = iobuf_get_noeof (inp);
pktlen--;
/* Check for the special GNU extension. */
if (ski->s2k.mode == 101)
{
for (i = 0; i < 4 && pktlen; i++, pktlen--)
temp[i] = iobuf_get_noeof (inp);
if (i < 4 || memcmp (temp, "GNU", 3))
{
if (list_mode)
es_fprintf (listfp, "\tunknown S2K %d\n",
ski->s2k.mode);
err = gpg_error (GPG_ERR_INV_PACKET);
goto leave;
}
/* 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. */
ski->s2k.mode = 1000 + temp[3];
}
/* Read the salt. */
switch (ski->s2k.mode)
{
case 1:
case 3:
for (i = 0; i < 8 && pktlen; i++, pktlen--)
temp[i] = iobuf_get_noeof (inp);
if (i < 8)
{
err = gpg_error (GPG_ERR_INV_PACKET);
goto leave;
}
memcpy (ski->s2k.salt, temp, 8);
break;
}
/* Check the mode. */
switch (ski->s2k.mode)
{
case 0:
if (list_mode)
es_fprintf (listfp, "\tsimple S2K");
break;
case 1:
if (list_mode)
es_fprintf (listfp, "\tsalted S2K");
break;
case 3:
if (list_mode)
es_fprintf (listfp, "\titer+salt S2K");
break;
case 1001:
if (list_mode)
es_fprintf (listfp, "\tgnu-dummy S2K");
break;
case 1002:
if (list_mode)
es_fprintf (listfp, "\tgnu-divert-to-card S2K");
break;
default:
if (list_mode)
es_fprintf (listfp, "\tunknown %sS2K %d\n",
ski->s2k.mode < 1000 ? "" : "GNU ",
ski->s2k.mode);
err = gpg_error (GPG_ERR_INV_PACKET);
goto leave;
}
/* Print some info. */
if (list_mode)
{
es_fprintf (listfp, ", algo: %d,%s hash: %d",
ski->algo,
ski->sha1chk ? " SHA1 protection,"
: " simple checksum,", ski->s2k.hash_algo);
if (ski->s2k.mode == 1 || ski->s2k.mode == 3)
{
es_fprintf (listfp, ", salt: ");
es_write_hexstring (listfp, ski->s2k.salt, 8, 0, NULL);
}
es_putc ('\n', listfp);
}
/* Read remaining protection parameters. */
if (ski->s2k.mode == 3)
{
if (pktlen < 1)
{
err = gpg_error (GPG_ERR_INV_PACKET);
goto leave;
}
ski->s2k.count = iobuf_get (inp);
pktlen--;
if (list_mode)
es_fprintf (listfp, "\tprotect count: %lu (%lu)\n",
(ulong)S2K_DECODE_COUNT ((ulong)ski->s2k.count),
(ulong) ski->s2k.count);
}
else if (ski->s2k.mode == 1002)
{
/* Read the serial number. */
if (pktlen < 1)
{
err = gpg_error (GPG_ERR_INV_PACKET);
goto leave;
}
snlen = iobuf_get (inp);
pktlen--;
if (pktlen < snlen || snlen == (size_t)(-1))
{
err = gpg_error (GPG_ERR_INV_PACKET);
goto leave;
}
}
}
else /* Old version; no S2K, so we set mode to 0, hash MD5. */
{
/* 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;
if (list_mode)
es_fprintf (listfp, "\tprotect algo: %d (hash algo: %d)\n",
ski->algo, ski->s2k.hash_algo);
}
/* 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
* ski->ivlen = cipher_get_blocksize (ski->algo);
* 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. */
ski->ivlen = openpgp_cipher_blocklen (ski->algo);
log_assert (ski->ivlen <= sizeof (temp));
if (ski->s2k.mode == 1001)
ski->ivlen = 0;
else if (ski->s2k.mode == 1002)
ski->ivlen = snlen < 16 ? snlen : 16;
if (pktlen < ski->ivlen)
{
err = gpg_error (GPG_ERR_INV_PACKET);
goto leave;
}
for (i = 0; i < ski->ivlen; i++, pktlen--)
temp[i] = iobuf_get_noeof (inp);
if (list_mode)
{
es_fprintf (listfp,
ski->s2k.mode == 1002 ? "\tserial-number: "
: "\tprotect IV: ");
for (i = 0; i < ski->ivlen; i++)
es_fprintf (listfp, " %02x", temp[i]);
es_putc ('\n', listfp);
}
memcpy (ski->iv, temp, ski->ivlen);
}
/* 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. */
if (ski->s2k.mode == 1001 || ski->s2k.mode == 1002)
{
/* Better set some dummy stuff here. */
pk->pkey[npkey] = gcry_mpi_set_opaque (NULL,
xstrdup ("dummydata"),
10 * 8);
pktlen = 0;
}
else if (ski->is_protected)
{
if (pktlen < 2) /* At least two bytes for the length. */
{
err = gpg_error (GPG_ERR_INV_PACKET);
goto leave;
}
/* Ugly: The length is encrypted too, so we read all stuff
* up to the end of the packet into the first SKEY
* element. */
pk->pkey[npkey] = gcry_mpi_set_opaque (NULL,
read_rest (inp, pktlen),
pktlen * 8);
/* Mark that MPI as protected - we need this information for
importing a key. The OPAQUE flag can't be used because
we also store public EdDSA values in opaque MPIs. */
if (pk->pkey[npkey])
gcry_mpi_set_flag (pk->pkey[npkey], GCRYMPI_FLAG_USER1);
pktlen = 0;
if (list_mode)
es_fprintf (listfp, "\tskey[%d]: [v4 protected]\n", npkey);
}
else
{
/* Not encrypted. */
for (i = npkey; i < nskey; i++)
{
unsigned int n;
if (pktlen < 2) /* At least two bytes for the length. */
{
err = gpg_error (GPG_ERR_INV_PACKET);
goto leave;
}
n = pktlen;
pk->pkey[i] = mpi_read (inp, &n, 0);
pktlen -= n;
if (list_mode)
{
es_fprintf (listfp, "\tskey[%d]: ", i);
mpi_print (listfp, pk->pkey[i], mpi_print_mode);
es_putc ('\n', listfp);
}
if (!pk->pkey[i])
err = gpg_error (GPG_ERR_INV_PACKET);
}
if (err)
goto leave;
if (pktlen < 2)
{
err = gpg_error (GPG_ERR_INV_PACKET);
goto leave;
}
ski->csum = read_16 (inp);
pktlen -= 2;
if (list_mode)
es_fprintf (listfp, "\tchecksum: %04hx\n", ski->csum);
}
}
/* Note that KEYID below has been initialized above in list_mode. */
if (list_mode)
es_fprintf (listfp, "\tkeyid: %08lX%08lX\n",
(ulong) keyid[0], (ulong) keyid[1]);
leave:
iobuf_skip_rest (inp, pktlen, 0);
return err;
}
/* Attribute subpackets have the same format as v4 signature
subpackets. This is not part of OpenPGP, but is done in several
versions of PGP nevertheless. */
int
parse_attribute_subpkts (PKT_user_id * uid)
{
size_t n;
int count = 0;
struct user_attribute *attribs = NULL;
const byte *buffer = uid->attrib_data;
int buflen = uid->attrib_len;
byte type;
xfree (uid->attribs);
while (buflen)
{
n = *buffer++;
buflen--;
if (n == 255) /* 4 byte length header. */
{
if (buflen < 4)
goto too_short;
n = buf32_to_size_t (buffer);
buffer += 4;
buflen -= 4;
}
else if (n >= 192) /* 2 byte special encoded length header. */
{
if (buflen < 2)
goto too_short;
n = ((n - 192) << 8) + *buffer + 192;
buffer++;
buflen--;
}
if (buflen < n)
goto too_short;
if (!n)
{
/* Too short to encode the subpacket type. */
if (opt.verbose)
log_info ("attribute subpacket too short\n");
break;
}
attribs = xrealloc (attribs,
(count + 1) * sizeof (struct user_attribute));
memset (&attribs[count], 0, sizeof (struct user_attribute));
type = *buffer;
buffer++;
buflen--;
n--;
attribs[count].type = type;
attribs[count].data = buffer;
attribs[count].len = n;
buffer += n;
buflen -= n;
count++;
}
uid->attribs = attribs;
uid->numattribs = count;
return count;
too_short:
if (opt.verbose)
log_info ("buffer shorter than attribute subpacket\n");
uid->attribs = attribs;
uid->numattribs = count;
return count;
}
static int
parse_user_id (IOBUF inp, int pkttype, unsigned long pktlen, PACKET * packet)
{
byte *p;
/* 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. */
if (pktlen > MAX_UID_PACKET_LENGTH)
{
log_error ("packet(%d) too large\n", pkttype);
if (list_mode)
es_fprintf (listfp, ":user ID packet: [too large]\n");
iobuf_skip_rest (inp, pktlen, 0);
return GPG_ERR_INV_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;
es_fprintf (listfp, ":user ID packet: \"");
/* fixme: Hey why don't we replace this with es_write_sanitized?? */
for (p = packet->pkt.user_id->name; n; p++, n--)
{
if (*p >= ' ' && *p <= 'z')
es_putc (*p, listfp);
else
es_fprintf (listfp, "\\x%02x", *p);
}
es_fprintf (listfp, "\"\n");
}
return 0;
}
void
make_attribute_uidname (PKT_user_id * uid, size_t max_namelen)
{
log_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);
else
{
/* Only one attribute, so list it as the "user id" */
if (uid->attribs->type == ATTRIB_IMAGE)
{
u32 len;
byte type;
if (parse_image_header (uid->attribs, &type, &len))
sprintf (uid->name, "[%.20s image of size %lu]",
image_type_to_string (type, 1), (ulong) len);
else
sprintf (uid->name, "[invalid image]");
}
else
sprintf (uid->name, "[unknown attribute of size %lu]",
(ulong) uid->attribs->len);
}
uid->len = strlen (uid->name);
}
static int
parse_attribute (IOBUF inp, int pkttype, unsigned long pktlen,
PACKET * packet)
{
byte *p;
(void) pkttype;
/* We better cap the size of an attribute packet to make DoS not too
easy. 16MB should be more then enough for one attribute packet
(ie. a photo). */
if (pktlen > MAX_ATTR_PACKET_LENGTH)
{
log_error ("packet(%d) too large\n", pkttype);
if (list_mode)
es_fprintf (listfp, ":attribute packet: [too large]\n");
iobuf_skip_rest (inp, pktlen, 0);
return GPG_ERR_INV_PACKET;
}
#define EXTRA_UID_NAME_SPACE 71
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? pktlen:1);
packet->pkt.user_id->attrib_len = pktlen;
p = packet->pkt.user_id->attrib_data;
for (; pktlen; pktlen--, p++)
*p = iobuf_get_noeof (inp);
/* 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);
make_attribute_uidname (packet->pkt.user_id, EXTRA_UID_NAME_SPACE);
if (list_mode)
{
es_fprintf (listfp, ":attribute packet: %s\n", packet->pkt.user_id->name);
}
return 0;
}
static int
parse_comment (IOBUF inp, int pkttype, unsigned long pktlen, PACKET * packet)
{
byte *p;
/* 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 > MAX_COMMENT_PACKET_LENGTH)
{
log_error ("packet(%d) too large\n", pkttype);
if (list_mode)
es_fprintf (listfp, ":%scomment packet: [too large]\n",
pkttype == PKT_OLD_COMMENT ? "OpenPGP draft " : "");
iobuf_skip_rest (inp, pktlen, 0);
return GPG_ERR_INV_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;
es_fprintf (listfp, ":%scomment packet: \"", pkttype == PKT_OLD_COMMENT ?
"OpenPGP draft " : "");
for (p = packet->pkt.comment->data; n; p++, n--)
{
if (*p >= ' ' && *p <= 'z')
es_putc (*p, listfp);
else
es_fprintf (listfp, "\\x%02x", *p);
}
es_fprintf (listfp, "\"\n");
}
return 0;
}
/* Parse a ring trust packet RFC4880 (5.10).
*
* This parser is special in that the packet is not stored as a packet
* but its content is merged into the previous packet. */
static gpg_error_t
parse_ring_trust (parse_packet_ctx_t ctx, unsigned long pktlen)
{
gpg_error_t err;
iobuf_t inp = ctx->inp;
PKT_ring_trust rt = {0};
int c;
int not_gpg = 0;
if (!pktlen)
{
if (list_mode)
es_fprintf (listfp, ":trust packet: empty\n");
err = 0;
goto leave;
}
c = iobuf_get_noeof (inp);
pktlen--;
rt.trustval = c;
if (pktlen)
{
if (!c)
{
c = iobuf_get_noeof (inp);
/* We require that bit 7 of the sigcache is 0 (easier
* eof handling). */
if (!(c & 0x80))
rt.sigcache = c;
}
else
iobuf_get_noeof (inp); /* Dummy read. */
pktlen--;
}
/* Next is the optional subtype. */
if (pktlen > 3)
{
char tmp[4];
tmp[0] = iobuf_get_noeof (inp);
tmp[1] = iobuf_get_noeof (inp);
tmp[2] = iobuf_get_noeof (inp);
tmp[3] = iobuf_get_noeof (inp);
pktlen -= 4;
if (!memcmp (tmp, "gpg", 3))
rt.subtype = tmp[3];
else
not_gpg = 1;
}
/* If it is a key or uid subtype read the remaining data. */
if ((rt.subtype == RING_TRUST_KEY || rt.subtype == RING_TRUST_UID)
&& pktlen >= 6 )
{
int i;
unsigned int namelen;
rt.keysrc = iobuf_get_noeof (inp);
pktlen--;
rt.keyupdate = read_32 (inp);
pktlen -= 4;
namelen = iobuf_get_noeof (inp);
pktlen--;
if (namelen && pktlen)
{
rt.url = xtrymalloc (namelen + 1);
if (!rt.url)
{
err = gpg_error_from_syserror ();
goto leave;
}
for (i = 0; pktlen && i < namelen; pktlen--, i++)
rt.url[i] = iobuf_get_noeof (inp);
rt.url[i] = 0;
}
}
if (list_mode)
{
if (rt.subtype == RING_TRUST_SIG)
es_fprintf (listfp, ":trust packet: sig flag=%02x sigcache=%02x\n",
rt.trustval, rt.sigcache);
else if (rt.subtype == RING_TRUST_UID || rt.subtype == RING_TRUST_KEY)
{
unsigned char *p;
es_fprintf (listfp, ":trust packet: %s upd=%lu src=%d%s",
(rt.subtype == RING_TRUST_UID? "uid" : "key"),
(unsigned long)rt.keyupdate,
rt.keysrc,
(rt.url? " url=":""));
if (rt.url)
{
for (p = rt.url; *p; p++)
{
if (*p >= ' ' && *p <= 'z')
es_putc (*p, listfp);
else
es_fprintf (listfp, "\\x%02x", *p);
}
}
es_putc ('\n', listfp);
}
else if (not_gpg)
es_fprintf (listfp, ":trust packet: not created by gpg\n");
else
es_fprintf (listfp, ":trust packet: subtype=%02x\n",
rt.subtype);
}
/* Now transfer the data to the respective packet. Do not do this
* if SKIP_META is set. */
if (!ctx->last_pkt.pkt.generic || ctx->skip_meta)
;
else if (rt.subtype == RING_TRUST_SIG
&& ctx->last_pkt.pkttype == PKT_SIGNATURE)
{
PKT_signature *sig = ctx->last_pkt.pkt.signature;
if ((rt.sigcache & 1))
{
sig->flags.checked = 1;
sig->flags.valid = !!(rt.sigcache & 2);
}
}
else if (rt.subtype == RING_TRUST_UID
&& (ctx->last_pkt.pkttype == PKT_USER_ID
|| ctx->last_pkt.pkttype == PKT_ATTRIBUTE))
{
PKT_user_id *uid = ctx->last_pkt.pkt.user_id;
uid->keysrc = rt.keysrc;
uid->keyupdate = rt.keyupdate;
uid->updateurl = rt.url;
rt.url = NULL;
}
else if (rt.subtype == RING_TRUST_KEY
&& (ctx->last_pkt.pkttype == PKT_PUBLIC_KEY
|| ctx->last_pkt.pkttype == PKT_SECRET_KEY))
{
PKT_public_key *pk = ctx->last_pkt.pkt.public_key;
pk->keysrc = rt.keysrc;
pk->keyupdate = rt.keyupdate;
pk->updateurl = rt.url;
rt.url = NULL;
}
err = 0;
leave:
xfree (rt.url);
free_packet (NULL, ctx); /* This sets ctx->last_pkt to NULL. */
iobuf_skip_rest (inp, pktlen, 0);
return err;
}
static int
parse_plaintext (IOBUF inp, int pkttype, unsigned long pktlen,
PACKET * pkt, int new_ctb, int partial)
{
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);
if (list_mode)
es_fputs (":literal data packet: [too short]\n", listfp);
rc = gpg_error (GPG_ERR_INV_PACKET);
goto leave;
}
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;
}
pt->timestamp = read_32 (inp);
if (pktlen)
pktlen -= 4;
pt->len = pktlen;
pt->buf = inp;
if (list_mode)
{
es_fprintf (listfp, ":literal data packet:\n"
"\tmode %c (%X), created %lu, name=\"",
mode >= ' ' && mode < 'z' ? mode : '?', mode,
(ulong) pt->timestamp);
for (p = pt->name, i = 0; i < namelen; p++, i++)
{
if (*p >= ' ' && *p <= 'z')
es_putc (*p, listfp);
else
es_fprintf (listfp, "\\x%02x", *p);
}
es_fprintf (listfp, "\",\n\traw data: ");
if (partial)
es_fprintf (listfp, "unknown length\n");
else
es_fprintf (listfp, "%lu bytes\n", (ulong) pt->len);
}
leave:
return rc;
}
static int
parse_compressed (IOBUF inp, int pkttype, unsigned long pktlen,
PACKET * pkt, int new_ctb)
{
PKT_compressed *zd;
/* PKTLEN is here 0, but data follows (this should be the last
object in a file or the compress algorithm should know the
length). */
(void) pkttype;
(void) pktlen;
zd = pkt->pkt.compressed = xmalloc (sizeof *pkt->pkt.compressed);
zd->algorithm = iobuf_get_noeof (inp);
zd->len = 0; /* not used */
zd->new_ctb = new_ctb;
zd->buf = inp;
if (list_mode)
es_fprintf (listfp, ":compressed packet: algo=%d\n", zd->algorithm);
return 0;
}
static int
parse_encrypted (IOBUF inp, int pkttype, unsigned long pktlen,
PACKET * pkt, int new_ctb, int partial)
{
int rc = 0;
PKT_encrypted *ed;
unsigned long orig_pktlen = pktlen;
ed = pkt->pkt.encrypted = xmalloc (sizeof *pkt->pkt.encrypted);
/* ed->len is set below. */
ed->extralen = 0; /* Unknown here; only used in build_packet. */
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);
if (list_mode)
es_fputs (":encrypted data packet: [unknown version]\n", listfp);
/*skip_rest(inp, pktlen); should we really do this? */
rc = gpg_error (GPG_ERR_INV_PACKET);
goto leave;
}
ed->mdc_method = DIGEST_ALGO_SHA1;
}
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. */
if (orig_pktlen && pktlen < 10)
{
/* Actually this is blocksize+2. */
log_error ("packet(%d) too short\n", pkttype);
if (list_mode)
es_fputs (":encrypted data packet: [too short]\n", listfp);
rc = GPG_ERR_INV_PACKET;
iobuf_skip_rest (inp, pktlen, partial);
goto leave;
}
/* 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;
if (list_mode)
{
if (orig_pktlen)
es_fprintf (listfp, ":encrypted data packet:\n\tlength: %lu\n",
orig_pktlen);
else
es_fprintf (listfp, ":encrypted data packet:\n\tlength: unknown\n");
if (ed->mdc_method)
es_fprintf (listfp, "\tmdc_method: %d\n", ed->mdc_method);
}
ed->buf = inp;
leave:
return rc;
}
/* 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. */
static int
parse_mdc (IOBUF inp, int pkttype, unsigned long pktlen,
PACKET * pkt, int new_ctb)
{
int rc = 0;
PKT_mdc *mdc;
byte *p;
(void) pkttype;
mdc = pkt->pkt.mdc = xmalloc (sizeof *pkt->pkt.mdc);
if (list_mode)
es_fprintf (listfp, ":mdc packet: length=%lu\n", pktlen);
if (!new_ctb || pktlen != 20)
{
log_error ("mdc_packet with invalid encoding\n");
rc = gpg_error (GPG_ERR_INV_PACKET);
goto leave;
}
p = mdc->hash;
for (; pktlen; pktlen--, p++)
*p = iobuf_get_noeof (inp);
leave:
return rc;
}
/*
* This packet is internally generated by us (in 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 coming from outside, we
* first check that there is a unique tag in it.
*
* The format of such a control packet is:
* n byte session marker
* 1 byte control type CTRLPKT_xxxxx
* m byte control data
*/
static int
parse_gpg_control (IOBUF inp, int pkttype, unsigned long pktlen,
PACKET * packet, int partial)
{
byte *p;
const byte *sesmark;
size_t sesmarklen;
int i;
(void) pkttype;
if (list_mode)
es_fprintf (listfp, ":packet 63: length %lu ", pktlen);
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)
es_fputs ("- gpg control packet", listfp);
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;
skipit:
if (list_mode)
{
int c;
i = 0;
es_fprintf (listfp, "- private (rest length %lu)\n", pktlen);
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;
}
}
es_putc ('\n', listfp);
}
iobuf_skip_rest (inp, pktlen, 0);
return gpg_error (GPG_ERR_INV_PACKET);
}
/* Create a GPG control packet to be used internally as a placeholder. */
PACKET *
create_gpg_control (ctrlpkttype_t type, const byte * data, size_t datalen)
{
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;
}