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
|
@ -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)
|
||||
{
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue