diff options
author | Werner Koch <[email protected]> | 2019-03-14 10:20:07 +0000 |
---|---|---|
committer | Werner Koch <[email protected]> | 2019-03-14 10:26:54 +0000 |
commit | 01c87d4ce23bc9fc44ec5301c2c6bf2ce615c375 (patch) | |
tree | f19dff47ab919197f923a526e850c6954030b238 /g10/parse-packet.c | |
parent | kbx: Add support for 32 byte fingerprints. (diff) | |
download | gnupg-01c87d4ce23bc9fc44ec5301c2c6bf2ce615c375.tar.gz gnupg-01c87d4ce23bc9fc44ec5301c2c6bf2ce615c375.zip |
gpg: Implement v5 keys and v5 signatures.
* g10/build-packet.c (gpg_mpi_write): New optional arg
R_NWRITTEN. Allow NULL for OUT. Change all callers.
(do_key): Support v5 keys.
(build_sig_subpkt_from_sig): Support 32 byte fingerprints.
* g10/parse-packet.c (parse_signature): First try to set the keyid
from the issuer fingerprint.
(parse_key): Support v5 keys.
(create_gpg_control): Better make sure to always allocate the static
size of the struct in case future compilers print warnings.
* g10/keyid.c (hash_public_key): Add v5 support.
(keyid_from_pk): Ditto.
(keyid_from_fingerprint): Ditto.
(fingerprint_from_pk): Ditto.
* g10/keygen.c (KEYGEN_FLAG_CREATE_V5_KEY): New.
(pVERSION, pSUBVERSION): New.
(add_feature_v5): New.
(keygen_upd_std_prefs): Call it.
(do_create_from_keygrip): Add arg keygen_flags and support the v5
flag.
(common_gen): Support the v5 flag.
(parse_key_parameter_part): New flags v4 and v5.
(parse_key_parameter_string): Add args for version and subversion.
(read_parameter_file): New keywords "Key-Version" and
"Subkey-Version".
(quickgen_set_para): Add arg 'version'.
(quick_generate_keypair, generate_keypair): Support version parms.
(do_generate_keypair): Support v5 key flag.
(generate_subkeypair): Ditto.
(generate_card_subkeypair): Preparse for keyflags.
(gen_card_key): Ditto.
* g10/sig-check.c (check_signature2): Add args extrahash and
extrahashlen.
(check_signature_end): Ditto.
(check_signature_end_simple): Ditto. Use them.
* g10/mainproc.c (proc_plaintext): Put extra hash infor into the
control packet.
(do_check_sig): Add args extrahas and extrahashlen and pass them on.
(issuer_fpr_raw): Support 32 byte fingerprint.
(check_sig_and_print): get extra hash data and pass it on.
--
Note that this is only basic support and requires more fine
tuning/fixing.
Signed-off-by: Werner Koch <[email protected]>
Diffstat (limited to 'g10/parse-packet.c')
-rw-r--r-- | g10/parse-packet.c | 129 |
1 files changed, 98 insertions, 31 deletions
diff --git a/g10/parse-packet.c b/g10/parse-packet.c index 21a26c786..5b4b1c900 100644 --- a/g10/parse-packet.c +++ b/g10/parse-packet.c @@ -1644,7 +1644,7 @@ parse_one_sig_subpkt (const byte * buffer, size_t n, int type) if (n < 8) break; return 0; - case SIGSUBPKT_ISSUER_FPR: /* issuer key ID */ + case SIGSUBPKT_ISSUER_FPR: /* issuer key fingerprint */ if (n < 21) break; return 0; @@ -2078,10 +2078,23 @@ parse_signature (IOBUF inp, int pkttype, unsigned long pktlen, && 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); + /* Set the key id. We first try the issuer fingerprint and if + * it is a v4 signature the fallback to the issuer. Note that + * only the issuer packet is also searched in the unhashed area. */ + p = parse_sig_subpkt (sig->hashed, SIGSUBPKT_ISSUER_FPR, &len); + if (p && len == 21 && p[0] == 4) + { + sig->keyid[0] = buf32_to_u32 (p + 1 + 12); + sig->keyid[1] = buf32_to_u32 (p + 1 + 16); + } + else if (p && len == 33 && p[0] == 5) + { + sig->keyid[0] = buf32_to_u32 (p + 1 ); + sig->keyid[1] = buf32_to_u32 (p + 1 + 4); + } + else if ((p = parse_sig_subpkt2 (sig, SIGSUBPKT_ISSUER))) + { + 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) @@ -2287,6 +2300,9 @@ parse_key (IOBUF inp, int pkttype, unsigned long pktlen, int npkey, nskey; u32 keyid[2]; PKT_public_key *pk; + int is_v5; + unsigned int pkbytes; /* For v5 keys: Number of bytes in the public + * key material. For v4 keys: 0. */ (void) hdr; @@ -2318,12 +2334,13 @@ parse_key (IOBUF inp, int pkttype, unsigned long pktlen, return 0; } else if (version == 4) - { - /* The only supported version. Use an older gpg - version (i.e. gpg 1.4) to parse v3 packets. */ - } + is_v5 = 0; + else if (version == 5) + is_v5 = 1; else if (version == 2 || version == 3) { + /* Not anymore supported since 2.1. Use an older gpg version + * (i.e. gpg 1.4) to parse v3 packets. */ if (opt.verbose > 1) log_info ("packet(%d) with obsolete version %d\n", pkttype, version); if (list_mode) @@ -2341,7 +2358,7 @@ parse_key (IOBUF inp, int pkttype, unsigned long pktlen, goto leave; } - if (pktlen < 11) + if (pktlen < (is_v5? 15:11)) { log_error ("packet(%d) too short\n", pkttype); if (list_mode) @@ -2364,14 +2381,28 @@ parse_key (IOBUF inp, int pkttype, unsigned long pktlen, max_expiredate = 0; algorithm = iobuf_get_noeof (inp); pktlen--; + if (is_v5) + { + pkbytes = read_32 (inp); + pktlen -= 4; + } + else + pkbytes = 0; + 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); + { + es_fprintf (listfp, ":%s key packet:\n" + "\tversion %d, algo %d, created %lu, expires %lu", + 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); + if (is_v5) + es_fprintf (listfp, ", pkbytes %u\n", pkbytes); + else + es_fprintf (listfp, "\n"); + } pk->timestamp = timestamp; pk->expiredate = expiredate; @@ -2446,6 +2477,7 @@ parse_key (IOBUF inp, int pkttype, unsigned long pktlen, struct seckey_info *ski; byte temp[16]; size_t snlen = 0; + unsigned int skbytes; if (pktlen < 1) { @@ -2462,23 +2494,42 @@ parse_key (IOBUF inp, int pkttype, unsigned long pktlen, ski->algo = iobuf_get_noeof (inp); pktlen--; + + if (is_v5) + { + unsigned int protcount = 0; + + /* Read the one octet count of the following key-protection + * material. Only required in case of unknown values. */ + if (!pktlen) + { + err = gpg_error (GPG_ERR_INV_PACKET); + goto leave; + } + protcount = iobuf_get_noeof (inp); + pktlen--; + if (list_mode) + es_fprintf (listfp, "\tprotbytes: %u\n", protcount); + } + if (ski->algo) { ski->is_protected = 1; ski->s2k.count = 0; if (ski->algo == 254 || ski->algo == 255) { - if (pktlen < 3) + if (pktlen < 3) { err = gpg_error (GPG_ERR_INV_PACKET); goto leave; } - ski->sha1chk = (ski->algo == 254); + + 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. */ + * erroring out 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); @@ -2504,10 +2555,8 @@ parse_key (IOBUF inp, int pkttype, unsigned long pktlen, } /* Read the salt. */ - switch (ski->s2k.mode) + if (ski->s2k.mode == 3 || ski->s2k.mode == 1) { - case 1: - case 3: for (i = 0; i < 8 && pktlen; i++, pktlen--) temp[i] = iobuf_get_noeof (inp); if (i < 8) @@ -2516,7 +2565,6 @@ parse_key (IOBUF inp, int pkttype, unsigned long pktlen, goto leave; } memcpy (ski->s2k.salt, temp, 8); - break; } /* Check the mode. */ @@ -2616,7 +2664,9 @@ parse_key (IOBUF inp, int pkttype, unsigned long pktlen, * 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. */ + * enlarge temp. + * FIXME: For v5 keys we can deduce this info! + */ ski->ivlen = openpgp_cipher_blocklen (ski->algo); log_assert (ski->ivlen <= sizeof (temp)); @@ -2644,6 +2694,20 @@ parse_key (IOBUF inp, int pkttype, unsigned long pktlen, memcpy (ski->iv, temp, ski->ivlen); } + /* Skip count of secret key material. */ + if (is_v5) + { + if (pktlen < 4) + { + err = gpg_error (GPG_ERR_INV_PACKET); + goto leave; + } + skbytes = read_32 (inp); + pktlen -= 4; + if (list_mode) + es_fprintf (listfp, "\tskbytes: %u\n", skbytes); + } + /* 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 :=(. @@ -2666,13 +2730,14 @@ parse_key (IOBUF inp, int pkttype, unsigned long pktlen, /* Ugly: The length is encrypted too, so we read all stuff * up to the end of the packet into the first SKEY - * element. */ + * element. + * FIXME: We can do better for v5 keys. */ 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. */ + * 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; @@ -3509,11 +3574,13 @@ create_gpg_control (ctrlpkttype_t type, const byte * data, size_t datalen) PACKET *packet; byte *p; + if (!data) + datalen = 0; + 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 = xmalloc (sizeof *packet->pkt.gpg_control + datalen); packet->pkt.gpg_control->control = type; packet->pkt.gpg_control->datalen = datalen; p = packet->pkt.gpg_control->data; |