1
0
Fork 0
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:
Werner Koch 2019-03-14 11:20:07 +01:00
parent f40e9d6a52
commit 01c87d4ce2
No known key found for this signature in database
GPG key ID: E3FDFF218E45B72B
8 changed files with 565 additions and 197 deletions

View file

@ -243,12 +243,15 @@ build_packet_and_meta (iobuf_t out, PACKET *pkt)
/*
* Write the mpi A to OUT.
* Write the mpi A to OUT. If R_NWRITTEN is not NULL the number of
* bytes written is stored there. To only get the number of bytes
* which would be written NULL may be passed for OUT.
*/
gpg_error_t
gpg_mpi_write (iobuf_t out, gcry_mpi_t a)
gpg_mpi_write (iobuf_t out, gcry_mpi_t a, unsigned int *r_nwritten)
{
int rc;
gpg_error_t err;
unsigned int nwritten = 0;
if (gcry_mpi_get_flag (a, GCRYMPI_FLAG_OPAQUE))
{
@ -277,9 +280,17 @@ gpg_mpi_write (iobuf_t out, gcry_mpi_t a)
/* gcry_log_debughex (" ", p, (nbits+7)/8); */
lenhdr[0] = nbits >> 8;
lenhdr[1] = nbits;
rc = iobuf_write (out, lenhdr, 2);
if (!rc && p)
rc = iobuf_write (out, p, (nbits+7)/8);
err = out? iobuf_write (out, lenhdr, 2) : 0;
if (!err)
{
nwritten += 2;
if (p)
{
err = out? iobuf_write (out, p, (nbits+7)/8) : 0;
if (!err)
nwritten += (nbits+7)/8;
}
}
}
else
{
@ -287,18 +298,25 @@ gpg_mpi_write (iobuf_t out, gcry_mpi_t a)
size_t nbytes;
nbytes = DIM(buffer);
rc = gcry_mpi_print (GCRYMPI_FMT_PGP, buffer, nbytes, &nbytes, a );
if( !rc )
rc = iobuf_write( out, buffer, nbytes );
else if (gpg_err_code(rc) == GPG_ERR_TOO_SHORT )
err = gcry_mpi_print (GCRYMPI_FMT_PGP, buffer, nbytes, &nbytes, a );
if (!err)
{
err = out? iobuf_write (out, buffer, nbytes) : 0;
if (!err)
nwritten += nbytes;
}
else if (gpg_err_code (err) == GPG_ERR_TOO_SHORT )
{
log_info ("mpi too large (%u bits)\n", gcry_mpi_get_nbits (a));
/* The buffer was too small. We better tell the user about the MPI. */
rc = gpg_error (GPG_ERR_TOO_LARGE);
/* The buffer was too small. We better tell the user about
* the MPI. */
err = gpg_error (GPG_ERR_TOO_LARGE);
}
}
return rc;
if (r_nwritten)
*r_nwritten = nwritten;
return err;
}
@ -463,29 +481,29 @@ static int
do_key (iobuf_t out, int ctb, PKT_public_key *pk)
{
gpg_error_t err = 0;
/* The length of the body is stored in the packet's header, which
occurs before the body. Unfortunately, we don't know the length
of the packet's body until we've written all of the data! To
work around this, we first write the data into this temporary
buffer, then generate the header, and finally copy the contents
of this buffer to OUT. */
iobuf_t a = iobuf_temp();
iobuf_t a;
int i, nskey, npkey;
u32 pkbytes = 0;
int is_v5;
log_assert (pk->version == 0 || pk->version == 4);
log_assert (pk->version == 0 || pk->version == 4 || pk->version == 5);
log_assert (ctb_pkttype (ctb) == PKT_PUBLIC_KEY
|| ctb_pkttype (ctb) == PKT_PUBLIC_SUBKEY
|| ctb_pkttype (ctb) == PKT_SECRET_KEY
|| ctb_pkttype (ctb) == PKT_SECRET_SUBKEY);
/* Write the version number - if none is specified, use 4 */
if ( !pk->version )
iobuf_put ( a, 4 );
else
iobuf_put ( a, pk->version );
write_32 (a, pk->timestamp );
/* The length of the body is stored in the packet's header, which
* occurs before the body. Unfortunately, we don't know the length
* of the packet's body until we've written all of the data! To
* work around this, we first write the data into this temporary
* buffer, then generate the header, and finally copy the content
* of this buffer to OUT. */
a = iobuf_temp();
iobuf_put (a, pk->pubkey_algo );
/* Note that the Version number, Timestamp, Algo, and the v5 Key
* material count are written at the end of the function. */
is_v5 = (pk->version == 5);
/* Get number of secret and public parameters. They are held in one
array: the public ones followed by the secret ones. */
@ -509,11 +527,13 @@ do_key (iobuf_t out, int ctb, PKT_public_key *pk)
|| (pk->pubkey_algo == PUBKEY_ALGO_ECDH && (i == 0 || i == 2)))
err = gpg_mpi_write_nohdr (a, pk->pkey[i]);
else
err = gpg_mpi_write (a, pk->pkey[i]);
err = gpg_mpi_write (a, pk->pkey[i], NULL);
if (err)
goto leave;
}
/* Record the length of the public key part. */
pkbytes = iobuf_get_temp_length (a);
if (pk->seckey_info)
{
@ -523,9 +543,26 @@ do_key (iobuf_t out, int ctb, PKT_public_key *pk)
/* Build the header for protected (encrypted) secret parameters. */
if (ski->is_protected)
{
/* OpenPGP protection according to rfc2440. */
iobuf_put (a, ski->sha1chk? 0xfe : 0xff);
iobuf_put (a, ski->algo);
iobuf_put (a, ski->sha1chk? 0xfe : 0xff); /* S2k usage. */
if (is_v5)
{
/* For a v5 key determine the count of the following
* key-protection material and write it. */
int count = 1; /* Pubkey algo octet. */
if (ski->s2k.mode >= 1000)
count += 6; /* GNU specific mode descriptor. */
else
count += 2; /* Mode and hash algo. */
if (ski->s2k.mode == 1 || ski->s2k.mode == 3)
count += 8; /* Salt. */
if (ski->s2k.mode == 3)
count++; /* S2K.COUNT */
if (ski->s2k.mode != 1001 && ski->s2k.mode != 1002)
count += ski->ivlen;
iobuf_put (a, count);
}
iobuf_put (a, ski->algo); /* Pubkey algo octet. */
if (ski->s2k.mode >= 1000)
{
/* These modes are not possible in OpenPGP, we use them
@ -556,13 +593,24 @@ do_key (iobuf_t out, int ctb, PKT_public_key *pk)
}
else /* Not protected. */
iobuf_put (a, 0 );
{
iobuf_put (a, 0 ); /* S2K usage = not protected. */
if (is_v5)
iobuf_put (a, 0); /* Zero octets of key-protection
* material follows. */
}
if (ski->s2k.mode == 1001)
; /* GnuPG extension - don't write a secret key at all. */
{
/* GnuPG extension - don't write a secret key at all. */
if (is_v5)
write_32 (a, 0); /* Zero octets of key material. */
}
else if (ski->s2k.mode == 1002)
{
/* GnuPG extension - divert to OpenPGP smartcard. */
if (is_v5)
write_32 (a, 1 + ski->ivlen);
/* Length of the serial number or 0 for no serial number. */
iobuf_put (a, ski->ivlen );
/* The serial number gets stored in the IV field. */
@ -576,15 +624,36 @@ do_key (iobuf_t out, int ctb, PKT_public_key *pk)
log_assert (gcry_mpi_get_flag (pk->pkey[npkey], GCRYMPI_FLAG_OPAQUE));
p = gcry_mpi_get_opaque (pk->pkey[npkey], &ndatabits);
/* For v5 keys we first write the number of octets of the
* following encrypted key material. */
if (is_v5)
write_32 (a, p? (ndatabits+7)/8 : 0);
if (p)
iobuf_write (a, p, (ndatabits+7)/8 );
}
else
{
/* Non-protected key. */
if (is_v5)
{
unsigned int skbytes = 0;
unsigned int n;
int j;
for (j=i; j < nskey; j++ )
{
if ((err = gpg_mpi_write (NULL, pk->pkey[j], &n)))
goto leave;
skbytes += n;
}
write_32 (a, skbytes);
}
for ( ; i < nskey; i++ )
if ( (err = gpg_mpi_write (a, pk->pkey[i])))
if ( (err = gpg_mpi_write (a, pk->pkey[i], NULL)))
goto leave;
write_16 (a, ski->csum );
}
}
@ -593,11 +662,23 @@ do_key (iobuf_t out, int ctb, PKT_public_key *pk)
if (!err)
{
/* Build the header of the packet - which we must do after
writing all the other stuff, so that we know the length of
the packet */
write_header2 (out, ctb, iobuf_get_temp_length(a), 0);
* writing all the other stuff, so that we know the length of
* the packet */
u32 len = iobuf_get_temp_length (a);
len += 1; /* version number */
len += 4; /* timestamp */
len += 1; /* algo */
if (is_v5)
len += 4; /* public key material count */
write_header2 (out, ctb, len, 0);
/* And finally write it out to the real stream. */
err = iobuf_write_temp (out, a);
iobuf_put (out, pk->version? pk->version : 4); /* version number */
write_32 (out, pk->timestamp );
iobuf_put (out, pk->pubkey_algo); /* algo */
if (is_v5)
write_32 (out, pkbytes); /* public key material count */
err = iobuf_write_temp (out, a); /* pub and sec key material */
}
iobuf_close (a); /* Close the temporary buffer */
@ -688,7 +769,7 @@ do_pubkey_enc( IOBUF out, int ctb, PKT_pubkey_enc *enc )
if (enc->pubkey_algo == PUBKEY_ALGO_ECDH && i == 1)
rc = gpg_mpi_write_nohdr (a, enc->data[i]);
else
rc = gpg_mpi_write (a, enc->data[i]);
rc = gpg_mpi_write (a, enc->data[i], NULL);
}
if (!rc)
@ -1135,10 +1216,10 @@ build_sig_subpkt_from_sig (PKT_signature *sig, PKT_public_key *pksk)
/* Write the new ISSUER_FPR subpacket. */
fingerprint_from_pk (pksk, buf+1, &fprlen);
if (fprlen == 20)
if (fprlen == 20 || fprlen == 32)
{
buf[0] = pksk->version;
build_sig_subpkt (sig, SIGSUBPKT_ISSUER_FPR, buf, 21);
build_sig_subpkt (sig, SIGSUBPKT_ISSUER_FPR, buf, fprlen + 1);
}
/* Write the timestamp. */
@ -1567,7 +1648,7 @@ do_signature( IOBUF out, int ctb, PKT_signature *sig )
if ( !n )
write_fake_data( a, sig->data[0] );
for (i=0; i < n && !rc ; i++ )
rc = gpg_mpi_write (a, sig->data[i] );
rc = gpg_mpi_write (a, sig->data[i], NULL);
if (!rc)
{