gpg: Revamp reading and writing of ring trust packets.

* g10/parse-packet.c (parse_trust): Rename to ...
(parse_ring_trust): this.  Change args and implement new ring trust
packet format.
(parse): Add special ring trust packet handling.
* g10/packet.h (PKT_user_id): New fields KEYUPDATE, UPDATEURL, and
KEYSRC.
(PKT_public_key): Ditto.
(RING_TRUST_SIG, RING_TRUST_KEY, RING_TRUST_UID): New consts.
(PKT_ring_trust): New.
(struct packet_struct): Remove member RING_TRUST.
(strcu parse_packet_ctx_s): Add field SKIP_META.
(init_parse_packet): Init SKIPT_META.
* g10/free-packet.c (release_public_key_parts): Free UDPATEURL.
(free_user_id): Ditto.
* g10/mainproc.c (list_node): Remove printing of non-documented "rtv"
lines.
* g10/build-packet.c (build_packet_and_meta): New.
(do_ring_trust): New.
* g10/export.c (write_keyblock_to_output): Use build_packet_and_meta
in backup mode.
(do_export_one_keyblock): Ditto.
* g10/import.c (read_block): Add arg WITH_META.  Skip ring trust
packets if that ism not set.
(import): Call read_block WITH_META in restore mode.
* g10/keydb.h (KEYSRC_UNKNOWN, KEYSRC_FILE, KEYSRC_KS, KEYSRC_PREF_KS)
(KEYSRC_WKD, KEYSRC_WKD_SD, KEYSRC_DANE): New constants.  They are not
yet used, though.
* g10/keydb.c (parse_keyblock_image): Allow ring trust packets.
(build_keyblock_image): Ditto.  Use build_packet_and_meta.
* g10/keyring.c (keyring_get_keyblock): Remove specila treatment of
ring trust packets.
(write_keyblock): Use build_packet_and_meta.  Remove special treatment
of ring trust packets and initialization of the signature caches.
--

This patch introduced the framework to store meta data for keys and
user ids in the keyrings/keyboxes.  Ring trust packets are
implementation defined and have always been used in gpg to cache the
signature verification status.

Ring trust packets are only exported with the export option "backup"
and only imported with the import option "restore".

The new code uses a cleaner way to handle the ring trust packets: When
the parser reads a ring trust packet and the previously read packet
matches the type of that ring trust packet, the information is stored
in that previously read packet (signature, user id, or primary key)
and the next packet is read immediately.  Thus only the parser sees
the ring trust packets.  Ring trust packets are written by using the
new function build_packet_and_meta instead of build_packet.  That
function writes a ring trust packet when the needed information is
available.

As a side-effect of this patch the signature status cache works again
and "gpg --check-sigs" is thus much faster.

Signed-off-by: Werner Koch <wk@gnupg.org>
This commit is contained in:
Werner Koch 2017-03-30 09:07:02 +02:00
parent afa8680908
commit a8895c99a7
No known key found for this signature in database
GPG Key ID: E3FDFF218E45B72B
11 changed files with 380 additions and 140 deletions

View File

@ -1311,6 +1311,43 @@ CREATE TABLE signatures (
S2K Specifier with an offset of 1000.
* Format of the OpenPGP TRUST packet
According to RFC4880 (5.10), the trust packet (aka ring trust) is
only used within keyrings and contains data that records the user's
specifications of which key holds trusted introducers. The RFC also
states that the format of this packet is implementation defined and
SHOULD NOT be emitted to output streams or should be ignored on
import. GnuPG uses this packet in several additional ways:
- 1 octet :: Trust-Value (only used by Subtype SIG)
- 1 octet :: Signature-Cache (only used by Subtype SIG; value must
be less than 128)
- 3 octets :: Fixed value: "gpg"
- 1 octet :: Subtype
- 0 :: Signature cache (SIG)
- 1 :: Key source on the primary key (KEY)
- 2 :: Key source on a user id (UID)
- 1 octet :: Key Source; i.e. the origin of the key:
- 0 :: Unknown source.
- 1 :: Direct import from a file.
- 2 :: Public keyserver.
- 3 :: Preferred keysrver.
- 4 :: Web Key Directory.
- 5 :: Web Key Directory via sub-domain.
- 6 :: OpenPGP DANE.
- 4 octets :: Time of last update. This is a a four-octet scalar
with the seconds since Epoch.
- 1 octet :: Scalar with the length of the following field.
- N octets :: String with the URL of the source. This may be a
zero-length string.
If the packets contains only two octets a Subtype of 0 is assumed;
this is the only format recognized by GnuPG versions < 2.1.18.
Trust-Value and Signature-Cache must be zero for all subtypes other
than SIG.
* Keyserver helper message format
*This information is obsolete*

View File

@ -33,6 +33,7 @@
#include "options.h"
#include "../common/host2net.h"
static gpg_error_t do_ring_trust (iobuf_t out, PKT_ring_trust *rt);
static int do_user_id( IOBUF out, int ctb, PKT_user_id *uid );
static int do_key (iobuf_t out, int ctb, PKT_public_key *pk);
static int do_symkey_enc( IOBUF out, int ctb, PKT_symkey_enc *enc );
@ -76,14 +77,11 @@ ctb_pkttype (int ctb)
return (ctb & ((1 << 6) - 1)) >> 2;
}
/****************
* Build a packet and write it to INP
* Returns: 0 := okay
* >0 := error
* Note: Caller must free the packet
*/
/* Build a packet and write it to the stream OUT.
* Returns: 0 on success or on an error code. */
int
build_packet( IOBUF out, PACKET *pkt )
build_packet (IOBUF out, PACKET *pkt)
{
int rc = 0;
int new_ctb = 0;
@ -170,7 +168,7 @@ build_packet( IOBUF out, PACKET *pkt )
rc = do_onepass_sig (out, ctb, pkt->pkt.onepass_sig);
break;
case PKT_RING_TRUST:
/* Ignore it (keyring.c does write it directly) */
/* Ignore it (only written by build_packet_and_meta) */
break;
case PKT_MDC:
/* We write it directly, so we should never see it here. */
@ -183,6 +181,62 @@ build_packet( IOBUF out, PACKET *pkt )
}
/* Build a packet and write it to the stream OUT. This variant also
* writes the meta data using ring tyrust packets. Returns: 0 on
* success or on aerror code. */
gpg_error_t
build_packet_and_meta (iobuf_t out, PACKET *pkt)
{
gpg_error_t err;
PKT_ring_trust rt = {0};
err = build_packet (out, pkt);
if (err)
;
else if (pkt->pkttype == PKT_SIGNATURE)
{
PKT_signature *sig = pkt->pkt.signature;
rt.subtype = RING_TRUST_SIG;
/* Note: trustval is not yet used. */
if (sig->flags.checked)
{
rt.sigcache = 1;
if (sig->flags.valid)
rt.sigcache |= 2;
}
err = do_ring_trust (out, &rt);
}
else if (pkt->pkttype == PKT_USER_ID
|| pkt->pkttype == PKT_ATTRIBUTE)
{
PKT_user_id *uid = pkt->pkt.user_id;
rt.subtype = RING_TRUST_UID;
rt.keysrc = uid->keysrc;
rt.keyupdate = uid->keyupdate;
rt.url = uid->updateurl;
err = do_ring_trust (out, &rt);
rt.url = NULL;
}
else if (pkt->pkttype == PKT_PUBLIC_KEY
|| pkt->pkttype == PKT_SECRET_KEY)
{
PKT_public_key *pk = pkt->pkt.public_key;
rt.subtype = RING_TRUST_KEY;
rt.keysrc = pk->keysrc;
rt.keyupdate = pk->keyupdate;
rt.url = pk->updateurl;
err = do_ring_trust (out, &rt);
rt.url = NULL;
}
return err;
}
/*
* Write the mpi A to OUT.
*/
@ -320,6 +374,38 @@ write_fake_data (IOBUF out, gcry_mpi_t a)
}
/* Write a ring trust meta packet. */
static gpg_error_t
do_ring_trust (iobuf_t out, PKT_ring_trust *rt)
{
unsigned int namelen = 0;
unsigned int pktlen = 6;
if (rt->subtype == RING_TRUST_KEY || rt->subtype == RING_TRUST_UID)
{
if (rt->url)
namelen = strlen (rt->url);
pktlen += 1 + 4 + 1 + namelen;
}
write_header (out, (0x80 | ((PKT_RING_TRUST & 15)<<2)), pktlen);
iobuf_put (out, rt->trustval);
iobuf_put (out, rt->sigcache);
iobuf_write (out, "gpg", 3);
iobuf_put (out, rt->subtype);
if (rt->subtype == RING_TRUST_KEY || rt->subtype == RING_TRUST_UID)
{
iobuf_put (out, rt->keysrc);
write_32 (out, rt->keyupdate);
iobuf_put (out, namelen);
if (namelen)
iobuf_write (out, rt->url, namelen);
}
return 0;
}
/* Serialize the user id (RFC 4880, Section 5.11) or the user
* attribute UID (Section 5.12) and write it to OUT.
*

View File

@ -1284,14 +1284,17 @@ write_keyblock_to_output (kbnode_t keyblock, int with_armor,
{
if (is_deleted_kbnode (node))
continue;
if (node->pkt->pkttype == PKT_RING_TRUST && !(options & EXPORT_BACKUP))
continue;
if (node->pkt->pkttype == PKT_RING_TRUST)
continue; /* Skip - they should not be here anyway. */
if (!pk && (node->pkt->pkttype == PKT_PUBLIC_KEY
|| node->pkt->pkttype == PKT_SECRET_KEY))
pk = node->pkt->pkt.public_key;
err = build_packet (out_help? out_help : out, node->pkt);
if ((options & EXPORT_BACKUP))
err = build_packet_and_meta (out_help? out_help : out, node->pkt);
else
err = build_packet (out_help? out_help : out, node->pkt);
if (err)
{
log_error ("build_packet(%d) failed: %s\n",
@ -1555,9 +1558,8 @@ do_export_one_keyblock (ctrl_t ctrl, kbnode_t keyblock, u32 *keyid,
if (node->pkt->pkttype == PKT_COMMENT)
continue;
/* Make sure that ring_trust packets are only exported in backup
* mode. */
if (node->pkt->pkttype == PKT_RING_TRUST && !(options & EXPORT_BACKUP))
/* Skip ring trust packets - they should not ne here anyway. */
if (node->pkt->pkttype == PKT_RING_TRUST)
continue;
/* If exact is set, then we only export what was requested
@ -1723,7 +1725,10 @@ do_export_one_keyblock (ctrl_t ctrl, kbnode_t keyblock, u32 *keyid,
ski->iv[ski->ivlen] = xtoi_2 (s);
}
err = build_packet (out, node->pkt);
if ((options & EXPORT_BACKUP))
err = build_packet_and_meta (out, node->pkt);
else
err = build_packet (out, node->pkt);
if (!err && node->pkt->pkttype == PKT_PUBLIC_KEY)
{
stats->exported++;
@ -1744,7 +1749,10 @@ do_export_one_keyblock (ctrl_t ctrl, kbnode_t keyblock, u32 *keyid,
}
else
{
err = build_packet (out, node->pkt);
if ((options & EXPORT_BACKUP))
err = build_packet_and_meta (out, node->pkt);
else
err = build_packet (out, node->pkt);
if (node->pkt->pkttype == PKT_PUBLIC_KEY)
{
stats->exported++;
@ -1775,7 +1783,10 @@ do_export_one_keyblock (ctrl_t ctrl, kbnode_t keyblock, u32 *keyid,
}
else /* Not secret or common packets. */
{
err = build_packet (out, node->pkt);
if ((options & EXPORT_BACKUP))
err = build_packet_and_meta (out, node->pkt);
else
err = build_packet (out, node->pkt);
if (!err && node->pkt->pkttype == PKT_PUBLIC_KEY)
{
stats->exported++;

View File

@ -127,6 +127,11 @@ release_public_key_parts (PKT_public_key *pk)
xfree (pk->serialno);
pk->serialno = NULL;
}
if (pk->updateurl)
{
xfree (pk->updateurl);
pk->updateurl = NULL;
}
}
@ -314,6 +319,7 @@ free_user_id (PKT_user_id *uid)
free_attributes(uid);
xfree (uid->prefs);
xfree (uid->namehash);
xfree (uid->updateurl);
xfree (uid->mbox);
xfree (uid);
}

View File

@ -97,8 +97,8 @@ static int import (ctrl_t ctrl,
IOBUF inp, const char* fname, struct import_stats_s *stats,
unsigned char **fpr, size_t *fpr_len, unsigned int options,
import_screener_t screener, void *screener_arg);
static int read_block (IOBUF a, PACKET **pending_pkt, kbnode_t *ret_root,
int *r_v3keys);
static int read_block (IOBUF a, int with_meta,
PACKET **pending_pkt, kbnode_t *ret_root, int *r_v3keys);
static void revocation_present (ctrl_t ctrl, kbnode_t keyblock);
static int import_one (ctrl_t ctrl,
kbnode_t keyblock,
@ -333,7 +333,7 @@ read_key_from_file (ctrl_t ctrl, const char *fname, kbnode_t *r_keyblock)
}
/* Read the first non-v3 keyblock. */
while (!(err = read_block (inp, &pending_pkt, &keyblock, &v3keys)))
while (!(err = read_block (inp, 0, &pending_pkt, &keyblock, &v3keys)))
{
if (keyblock->pkt->pkttype == PKT_PUBLIC_KEY)
break;
@ -563,7 +563,8 @@ import (ctrl_t ctrl, IOBUF inp, const char* fname,struct import_stats_s *stats,
release_armor_context (afx);
}
while (!(rc = read_block (inp, &pending_pkt, &keyblock, &v3keys)))
while (!(rc = read_block (inp, !!(options & IMPORT_RESTORE),
&pending_pkt, &keyblock, &v3keys)))
{
stats->v3keys += v3keys;
if (keyblock->pkt->pkttype == PKT_PUBLIC_KEY)
@ -637,7 +638,7 @@ import_old_secring (ctrl_t ctrl, const char *fname)
getkey_disable_caches();
stats = import_new_stats_handle ();
while (!(err = read_block (inp, &pending_pkt, &keyblock, &v3keys)))
while (!(err = read_block (inp, 0, &pending_pkt, &keyblock, &v3keys)))
{
if (keyblock->pkt->pkttype == PKT_SECRET_KEY)
err = import_secret_one (ctrl, keyblock, stats, 1, 0, 1,
@ -752,14 +753,15 @@ valid_keyblock_packet (int pkttype)
/****************
* Read the next keyblock from stream A.
* PENDING_PKT should be initialzed to NULL
* and not changed by the caller.
* Meta data (ring trust packets) are only considered of WITH_META is set.
* PENDING_PKT should be initialzed to NULL and not changed by the caller.
* Return: 0 = okay, -1 no more blocks or another errorcode.
* The int at at R_V3KEY counts the number of unsupported v3
* keyblocks.
*/
static int
read_block( IOBUF a, PACKET **pending_pkt, kbnode_t *ret_root, int *r_v3keys)
read_block( IOBUF a, int with_meta,
PACKET **pending_pkt, kbnode_t *ret_root, int *r_v3keys)
{
int rc;
struct parse_packet_ctx_s parsectx;
@ -781,6 +783,8 @@ read_block( IOBUF a, PACKET **pending_pkt, kbnode_t *ret_root, int *r_v3keys)
pkt = xmalloc (sizeof *pkt);
init_packet (pkt);
init_parse_packet (&parsectx, a);
if (!with_meta)
parsectx.skip_meta = 1;
in_v3key = 0;
while ((rc=parse_packet (&parsectx, pkt)) != -1)
{

View File

@ -1202,6 +1202,7 @@ parse_keyblock_image (iobuf_t iobuf, int pk_no, int uid_no,
case PKT_USER_ID:
case PKT_ATTRIBUTE:
case PKT_SIGNATURE:
case PKT_RING_TRUST:
break; /* Allowed per RFC. */
default:
@ -1458,14 +1459,13 @@ build_keyblock_image (kbnode_t keyblock, iobuf_t *r_iobuf, u32 **r_sigstatus)
case PKT_SIGNATURE:
case PKT_USER_ID:
case PKT_ATTRIBUTE:
/* Note that we don't want the ring trust packets. They are
not useful. */
case PKT_RING_TRUST:
break;
default:
continue;
}
err = build_packet (iobuf, node->pkt);
err = build_packet_and_meta (iobuf, node->pkt);
if (err)
{
iobuf_close (iobuf);

View File

@ -119,6 +119,19 @@ union pref_hint
};
/* Constants to describe from where a key was fetched or updated. */
enum
{
KEYSRC_UNKNOWN = 0,
KEYSRC_FILE = 1, /* Direct import from a file. */
KEYSRC_KS = 2, /* Public keyserver. */
KEYSRC_PREF_KS = 3, /* Preferred keysrver. */
KEYSRC_WKD = 4, /* Web Key Directory. */
KEYSRC_WKD_SD = 5, /* Web Key Directory but from a sub domain. */
KEYSRC_DANE = 6 /* OpenPGP DANE. */
};
/*-- keydb.c --*/
#define KEYDB_RESOURCE_FLAG_PRIMARY 2 /* The primary resource. */

View File

@ -473,29 +473,6 @@ keyring_get_keyblock (KEYRING_HANDLE hd, KBNODE *ret_kb)
}
in_cert = 1;
if (pkt->pkttype == PKT_RING_TRUST)
{
/*(this code is duplicated after the loop)*/
if ( lastnode
&& lastnode->pkt->pkttype == PKT_SIGNATURE
&& (pkt->pkt.ring_trust->sigcache & 1) ) {
/* This is a ring trust packet with a checked signature
* status cache following directly a signature paket.
* Set the cache status into that signature packet. */
PKT_signature *sig = lastnode->pkt->pkt.signature;
sig->flags.checked = 1;
sig->flags.valid = !!(pkt->pkt.ring_trust->sigcache & 2);
}
/* Reset LASTNODE, so that we set the cache status only from
* the ring trust packet immediately following a signature. */
lastnode = NULL;
free_packet(pkt, &parsectx);
init_packet(pkt);
continue;
}
node = lastnode = new_kbnode (pkt);
if (!keyblock)
keyblock = node;
@ -531,16 +508,7 @@ keyring_get_keyblock (KEYRING_HANDLE hd, KBNODE *ret_kb)
if (rc || !ret_kb)
release_kbnode (keyblock);
else {
/*(duplicated from the loop body)*/
if ( pkt && pkt->pkttype == PKT_RING_TRUST
&& lastnode
&& lastnode->pkt->pkttype == PKT_SIGNATURE
&& (pkt->pkt.ring_trust->sigcache & 1) ) {
PKT_signature *sig = lastnode->pkt->pkt.signature;
sig->flags.checked = 1;
sig->flags.valid = !!(pkt->pkt.ring_trust->sigcache & 2);
}
*ret_kb = keyblock;
*ret_kb = keyblock;
}
free_packet (pkt, &parsectx);
deinit_parse_packet (&parsectx);
@ -1420,36 +1388,12 @@ write_keyblock (IOBUF fp, KBNODE keyblock)
while ( (node = walk_kbnode (keyblock, &kbctx, 0)) )
{
if (node->pkt->pkttype == PKT_RING_TRUST)
continue; /* we write it later on our own */
if ( (rc = build_packet (fp, node->pkt) ))
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;
}
if (node->pkt->pkttype == PKT_SIGNATURE)
{ /* always write a signature cache packet */
PKT_signature *sig = node->pkt->pkt.signature;
unsigned int cacheval = 0;
if (sig->flags.checked)
{
cacheval |= 1;
if (sig->flags.valid)
cacheval |= 2;
}
iobuf_put (fp, 0xb0); /* old style packet 12, 1 byte len*/
iobuf_put (fp, 2); /* 2 bytes */
iobuf_put (fp, 0); /* unused */
if (iobuf_put (fp, cacheval))
{
rc = gpg_error_from_syserror ();
log_error ("writing sigcache packet failed\n");
return rc;
}
}
}
return 0;
}
@ -1640,6 +1584,7 @@ keyring_rebuild_cache (void *token,int noisy)
return rc;
}
/****************
* Perform insert/delete/update operation.

View File

@ -1046,13 +1046,6 @@ list_node (CTX c, kbnode_t node)
else if ((pk->flags.primary && opt.fingerprint) || opt.fingerprint > 1)
print_fingerprint (NULL, pk, 0);
if (opt.with_colons)
{
if (node->next && node->next->pkt->pkttype == PKT_RING_TRUST)
es_printf ("rtv:1:%u:\n",
node->next->pkt->pkt.ring_trust->trustval);
}
if (pk->flags.primary)
{
int kl = opt.keyid_format == KF_NONE? 0 : keystrlen ();
@ -1077,14 +1070,6 @@ list_node (CTX c, kbnode_t node)
if (opt.with_colons)
es_putc (':', es_stdout);
es_putc ('\n', es_stdout);
if (opt.with_colons
&& node->next
&& node->next->pkt->pkttype == PKT_RING_TRUST)
{
es_printf ("rtv:2:%u:\n",
node->next->pkt->pkt.ring_trust?
node->next->pkt->pkt.ring_trust->trustval : 0);
}
}
else if (node->pkt->pkttype == PKT_PUBLIC_SUBKEY)
{

View File

@ -283,20 +283,25 @@ typedef struct
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 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. */
* 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;
@ -402,6 +407,9 @@ typedef struct
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
@ -474,11 +482,28 @@ 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 becuase we use it only local in the packet
* parser and builder. */
typedef struct {
unsigned int trustval;
unsigned int sigcache;
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. */
@ -519,7 +544,6 @@ struct packet_struct {
PKT_compressed *compressed; /* PKT_COMPRESSED */
PKT_encrypted *encrypted; /* PKT_ENCRYPTED[_MDC] */
PKT_mdc *mdc; /* PKT_MDC */
PKT_ring_trust *ring_trust; /* PKT_RING_TRUST */
PKT_plaintext *plaintext; /* PKT_PLAINTEXT */
PKT_gpg_control *gpg_control; /* PKT_GPG_CONTROL */
} pkt;
@ -599,6 +623,7 @@ struct parse_packet_ctx_s
iobuf_t inp; /* The input stream with the packets. */
PACKET *last_pkt; /* The last parsed packet. */
int free_last_pkt; /* Indicates that LAST_PKT must be freed. */
int skip_meta; /* Skip right trust packets. */
};
typedef struct parse_packet_ctx_s *parse_packet_ctx_t;
@ -606,6 +631,7 @@ typedef struct parse_packet_ctx_s *parse_packet_ctx_t;
(a)->inp = (i); \
(a)->last_pkt = NULL; \
(a)->free_last_pkt = 0; \
(a)->skip_meta = 0; \
} while (0)
#define deinit_parse_packet(a) do { \
@ -786,7 +812,8 @@ PACKET *create_gpg_control ( ctrlpkttype_t type,
size_t datalen );
/*-- build-packet.c --*/
int build_packet( iobuf_t inp, PACKET *pkt );
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 );

View File

@ -74,8 +74,8 @@ static int parse_attribute (IOBUF inp, int pkttype, unsigned long pktlen,
PACKET * packet);
static int parse_comment (IOBUF inp, int pkttype, unsigned long pktlen,
PACKET * packet);
static void parse_trust (IOBUF inp, int pkttype, unsigned long pktlen,
PACKET * packet);
static 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,
@ -542,6 +542,7 @@ parse (parse_packet_ctx_t ctx, PACKET *pkt, int onlykeypkts, off_t * retpos,
*skip = 0;
inp = ctx->inp;
again:
log_assert (!pkt->pkt.generic);
if (retpos || list_mode)
{
@ -800,8 +801,11 @@ parse (parse_packet_ctx_t ctx, PACKET *pkt, int onlykeypkts, off_t * retpos,
rc = parse_comment (inp, pkttype, pktlen, pkt);
break;
case PKT_RING_TRUST:
parse_trust (inp, pkttype, pktlen, pkt);
rc = 0;
{
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);
@ -2873,42 +2877,164 @@ parse_comment (IOBUF inp, int pkttype, unsigned long pktlen, PACKET * packet)
}
static void
parse_trust (IOBUF inp, int pkttype, unsigned long pktlen, PACKET * pkt)
/* 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;
(void) pkttype;
pkt->pkt.ring_trust = xmalloc (sizeof *pkt->pkt.ring_trust);
if (pktlen)
if (!pktlen)
{
c = iobuf_get_noeof (inp);
pktlen--;
pkt->pkt.ring_trust->trustval = c;
pkt->pkt.ring_trust->sigcache = 0;
if (!c && pktlen == 1)
{
c = iobuf_get_noeof (inp);
pktlen--;
/* We require that bit 7 of the sigcache is 0 (easier eof
handling). */
if (!(c & 0x80))
pkt->pkt.ring_trust->sigcache = c;
}
if (list_mode)
es_fprintf (listfp, ":trust packet: flag=%02x sigcache=%02x\n",
pkt->pkt.ring_trust->trustval,
pkt->pkt.ring_trust->sigcache);
}
else
{
pkt->pkt.ring_trust->trustval = 0;
pkt->pkt.ring_trust->sigcache = 0;
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 || 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;
}