diff options
-rw-r--r-- | doc/DETAILS | 37 | ||||
-rw-r--r-- | g10/build-packet.c | 102 | ||||
-rw-r--r-- | g10/export.c | 29 | ||||
-rw-r--r-- | g10/free-packet.c | 6 | ||||
-rw-r--r-- | g10/import.c | 20 | ||||
-rw-r--r-- | g10/keydb.c | 6 | ||||
-rw-r--r-- | g10/keydb.h | 13 | ||||
-rw-r--r-- | g10/keyring.c | 61 | ||||
-rw-r--r-- | g10/mainproc.c | 15 | ||||
-rw-r--r-- | g10/packet.h | 41 | ||||
-rw-r--r-- | g10/parse-packet.c | 184 |
11 files changed, 377 insertions, 137 deletions
diff --git a/doc/DETAILS b/doc/DETAILS index 83d9fea75..1624315ff 100644 --- a/doc/DETAILS +++ b/doc/DETAILS @@ -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* diff --git a/g10/build-packet.c b/g10/build-packet.c index 512e55c57..60e7d45e8 100644 --- a/g10/build-packet.c +++ b/g10/build-packet.c @@ -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. * diff --git a/g10/export.c b/g10/export.c index 5b0c81ded..e2adcc4ab 100644 --- a/g10/export.c +++ b/g10/export.c @@ -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++; diff --git a/g10/free-packet.c b/g10/free-packet.c index 535a17fb8..c14424660 100644 --- a/g10/free-packet.c +++ b/g10/free-packet.c @@ -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); } diff --git a/g10/import.c b/g10/import.c index 3321a7eb8..d43b2a8e3 100644 --- a/g10/import.c +++ b/g10/import.c @@ -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) { diff --git a/g10/keydb.c b/g10/keydb.c index 1bbda35c7..67957f83e 100644 --- a/g10/keydb.c +++ b/g10/keydb.c @@ -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); diff --git a/g10/keydb.h b/g10/keydb.h index 6f57583fd..2de52d504 100644 --- a/g10/keydb.h +++ b/g10/keydb.h @@ -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. */ diff --git a/g10/keyring.c b/g10/keyring.c index 2210df9c0..e7ebbb38b 100644 --- a/g10/keyring.c +++ b/g10/keyring.c @@ -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. diff --git a/g10/mainproc.c b/g10/mainproc.c index 8581104de..7b2c4567c 100644 --- a/g10/mainproc.c +++ b/g10/mainproc.c @@ -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) { diff --git a/g10/packet.h b/g10/packet.h index ad6f317e7..b23298aac 100644 --- a/g10/packet.h +++ b/g10/packet.h @@ -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 ); 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; } |