From a8895c99a7d0750132477d80cd66caaf3a709113 Mon Sep 17 00:00:00 2001 From: Werner Koch Date: Thu, 30 Mar 2017 09:07:02 +0200 Subject: 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 --- g10/parse-packet.c | 184 ++++++++++++++++++++++++++++++++++++++++++++--------- 1 file changed, 155 insertions(+), 29 deletions(-) (limited to 'g10/parse-packet.c') diff --git a/g10/parse-packet.c b/g10/parse-packet.c index ab273a5fa..df04fbc8b 100644 --- a/g10/parse-packet.c +++ b/g10/parse-packet.c @@ -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; + if (!pktlen) + { + if (list_mode) + es_fprintf (listfp, ":trust packet: empty\n"); + err = 0; + goto leave; + } - pkt->pkt.ring_trust = xmalloc (sizeof *pkt->pkt.ring_trust); + c = iobuf_get_noeof (inp); + pktlen--; + rt.trustval = c; if (pktlen) { - c = iobuf_get_noeof (inp); + 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--; - 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 + + /* Next is the optional subtype. */ + if (pktlen > 3) { - pkt->pkt.ring_trust->trustval = 0; - pkt->pkt.ring_trust->sigcache = 0; - if (list_mode) - es_fprintf (listfp, ":trust packet: empty\n"); + 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; } -- cgit v1.2.3