mirror of
git://git.gnupg.org/gnupg.git
synced 2025-07-03 22:56:33 +02:00
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 <wk@gnupg.org>
This commit is contained in:
parent
f40e9d6a52
commit
01c87d4ce2
8 changed files with 565 additions and 197 deletions
|
@ -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;
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue