summaryrefslogtreecommitdiffstats
path: root/g10/build-packet.c
diff options
context:
space:
mode:
authorWerner Koch <wk@gnupg.org>2019-03-14 11:20:07 +0100
committerWerner Koch <wk@gnupg.org>2019-03-14 11:26:54 +0100
commit01c87d4ce23bc9fc44ec5301c2c6bf2ce615c375 (patch)
treef19dff47ab919197f923a526e850c6954030b238 /g10/build-packet.c
parentkbx: Add support for 32 byte fingerprints. (diff)
downloadgnupg2-01c87d4ce23bc9fc44ec5301c2c6bf2ce615c375.tar.xz
gnupg2-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 <wk@gnupg.org>
Diffstat (limited to 'g10/build-packet.c')
-rw-r--r--g10/build-packet.c167
1 files changed, 124 insertions, 43 deletions
diff --git a/g10/build-packet.c b/g10/build-packet.c
index dd4ad54bf..07fccb099 100644
--- a/g10/build-packet.c
+++ b/g10/build-packet.c
@@ -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();
+
+ /* Note that the Version number, Timestamp, Algo, and the v5 Key
+ * material count are written at the end of the function. */
- iobuf_put (a, pk->pubkey_algo );
+ 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)
{