aboutsummaryrefslogtreecommitdiffstats
path: root/g10/parse-packet.c
diff options
context:
space:
mode:
authorWerner Koch <[email protected]>2019-03-14 10:20:07 +0000
committerWerner Koch <[email protected]>2019-03-14 10:26:54 +0000
commit01c87d4ce23bc9fc44ec5301c2c6bf2ce615c375 (patch)
treef19dff47ab919197f923a526e850c6954030b238 /g10/parse-packet.c
parentkbx: Add support for 32 byte fingerprints. (diff)
downloadgnupg-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.c129
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;