diff options
author | Werner Koch <[email protected]> | 2024-04-03 16:00:44 +0000 |
---|---|---|
committer | Werner Koch <[email protected]> | 2024-04-03 16:01:11 +0000 |
commit | 97f5159495146ce29d2011a07d493adc7c1b4086 (patch) | |
tree | 0a287f72cac848e9ddafa1870c68d4bdf1560fba /g10/parse-packet.c | |
parent | common: Extend openpgp_oid_to_curve to return an abbreviated name. (diff) | |
download | gnupg-97f5159495146ce29d2011a07d493adc7c1b4086.tar.gz gnupg-97f5159495146ce29d2011a07d493adc7c1b4086.zip |
gpg: Initial support for generating Kyber subkeys.
* common/openpgpdefs.h (PUBKEY_ALGO_KY768_25519): Remove.
(PUBKEY_ALGO_KY1024_448): Remove.
(PUBKEY_ALGO_KYBER): New. Use them everywhere instead of the removed.
* g10/build-packet.c (gpg_mpi_write_nohdr): Rename to
(gpg_mpi_write_opaque_nohdr): this. Change callers.
(gpg_mpi_write_opaque_32): New.
(do_key): Support Kyber keys using the revised format.
* g10/gpg.h (MAX_EXTERN_KEYPARM_BITS): New.
* g10/parse-packet.c (read_octet_string): Add arg nbytes so support
reading with a length prefix. Adjust callers.
(parse_key): Parse Kyber public keys.
* g10/misc.c (pubkey_get_npkey): Support Kyber.
(pubkey_get_nskey): Ditto.
* g10/keyid.c (pubkey_string): Support dual algorithms.
(do_hash_public_key): Support Kyber.
(nbits_from_pk): Ditto.
(keygrip_from_pk): Return the Kyber part for the ECC+Kyber dual algo.
* g10/keygen.c (struct common_gen_cb_parm_s): Add genkey_result2.
Note that this callback is not yet used.
(ecckey_from_sexp): Add optional arg sexp2 and use it for Kyber.
Change callers.
(ecckey_from_sexp): Do not leak LIST in case of an error.
(common_gen): Add arg keyparms2, change callers, and support Kyber.
(gen_kyber): New.
(get_keysize_range): Support Kyber.
(fixup_keysize): Simplify and support Kyber.
(do_create): Handle Kyber.
(parse_key_parameter_part): Remove algo strings "ky768" and "ky1024"
and add a generic "kyber" with default parameters.
--
This uses a revised format which is more aligned with the usual
OpenPGP structure. A lot of things are still missing. For example
support for handling two keygrips and checking both of them in a -K
listing. There is also only ky768_bp384 as fixed algorithm for now.
No passphrase for the Kyber part of the dual algorithm is on purpose.
A test was done using
gpg --quick-gen-key pqc1 nistp256
and then running
gpg -v --quick-add-key <fingerprint> kyber
which creates a v5 subkey on a v4 primary key. A second test using
gpg --quick-gen-key pqc2 Ed448
followed by a --quick-add-key created a v5 key with a v5 subkey.
GnuPG-bug-id: 6815
Diffstat (limited to 'g10/parse-packet.c')
-rw-r--r-- | g10/parse-packet.c | 113 |
1 files changed, 86 insertions, 27 deletions
diff --git a/g10/parse-packet.c b/g10/parse-packet.c index 34760a2d1..2163787cb 100644 --- a/g10/parse-packet.c +++ b/g10/parse-packet.c @@ -188,13 +188,21 @@ mpi_read (iobuf_t inp, unsigned int *ret_nread, int secure) } -/* Read an octet string of length NBYTES from INP and return it at - * R_DATA. On error return an error code and store NULL at R_DATA. - * PKTLEN shall give the current lenhgth of the packt and is updated - * with each read. If SECURE is true, the integer is stored in secure - * memory (allocated using gcry_xmalloc_secure). */ +/* If NLENGTH is zero read an octet string of length NBYTES from INP + * and return it at R_DATA. + * + * If NLENGTH is either 1, 2, or 4 and NLENGTH is zero read an + * NLENGTH-octet count and use this count number octets from INP and + * return it at R_DATA. + * + * On error return an error code and store NULL at R_DATA. PKTLEN + * shall give the current length of the packet and is updated with + * each read. If SECURE is true, the integer is stored in secure + * memory (allocated using gcry_xmalloc_secure). + */ static gpg_error_t -read_octet_string (iobuf_t inp, unsigned long *pktlen, unsigned int nbytes, +read_octet_string (iobuf_t inp, unsigned long *pktlen, + unsigned int nlength, unsigned int nbytes, int secure, gcry_mpi_t *r_data) { gpg_error_t err; @@ -204,12 +212,48 @@ read_octet_string (iobuf_t inp, unsigned long *pktlen, unsigned int nbytes, *r_data = NULL; - if (nbytes*8 > MAX_EXTERN_MPI_BITS) + if ((nbytes && nlength) + || (!nbytes && !(nlength == 1 || nlength == 2 || nlength == 4))) + { + err = gpg_error (GPG_ERR_INV_ARG); + goto leave; + } + + if (nlength) + { + for (i = 0; i < nlength; i++) + { + if (!*pktlen) + { + err = gpg_error (GPG_ERR_INV_PACKET); + goto leave; + } + c = iobuf_readbyte (inp); + if (c < 0) + { + err = gpg_error (GPG_ERR_INV_PACKET); + goto leave; + } + --*pktlen; + nbytes <<= 8; + nbytes |= c; + } + + if (!nbytes) + { + err = gpg_error (GPG_ERR_INV_PACKET); + goto leave; + } + } + + if (nbytes*8 > (nbytes==4? MAX_EXTERN_KEYPARM_BITS:MAX_EXTERN_MPI_BITS) + || (nbytes*8 < nbytes)) { log_error ("octet string too large (%u octets)\n", nbytes); err = gpg_error (GPG_ERR_TOO_LARGE); goto leave; } + if (nbytes > *pktlen) { log_error ("octet string larger than packet (%u octets)\n", nbytes); @@ -1408,7 +1452,6 @@ parse_pubkeyenc (IOBUF inp, int pkttype, unsigned long pktlen, int i, ndata; unsigned int n; PKT_pubkey_enc *k; - int is_ky1024 = 0; k = packet->pkt.pubkey_enc = xmalloc_clear (sizeof *packet->pkt.pubkey_enc); if (pktlen < 12) @@ -1467,23 +1510,19 @@ parse_pubkeyenc (IOBUF inp, int pkttype, unsigned long pktlen, if (rc) goto leave; } - else if (k->pubkey_algo == PUBKEY_ALGO_KY768_25519 - || (is_ky1024 = (k->pubkey_algo == PUBKEY_ALGO_KY1024_448))) + else if (k->pubkey_algo == PUBKEY_ALGO_KYBER) { log_assert (ndata == 4); /* Get the ephemeral public key. */ - n = is_ky1024? 56 : 32; - rc = read_octet_string (inp, &pktlen, n, 0, k->data + 0); + rc = read_octet_string (inp, &pktlen, 4, 0, 0, k->data + 0); if (rc) goto leave; /* Get the Kyber ciphertext. */ - n = is_ky1024? 1568 : 1088; - rc = read_octet_string (inp, &pktlen, n, 0, k->data + 1); + rc = read_octet_string (inp, &pktlen, 4, 0, 0, k->data + 1); if (rc) goto leave; /* Get the algorithm id. */ - n = 1; - rc = read_octet_string (inp, &pktlen, n, 0, k->data + 2); + rc = read_octet_string (inp, &pktlen, 0, 1, 0, k->data + 2); if (rc) goto leave; /* Get the wrapped symmetric key. */ @@ -2681,17 +2720,25 @@ parse_key (IOBUF inp, int pkttype, unsigned long pktlen, { if ( (algorithm == PUBKEY_ALGO_ECDSA && (i == 0)) || (algorithm == PUBKEY_ALGO_EDDSA && (i == 0)) - || (algorithm == PUBKEY_ALGO_ECDH && (i == 0 || i == 2))) + || (algorithm == PUBKEY_ALGO_ECDH && (i == 0 || i == 2)) + || (algorithm == PUBKEY_ALGO_KYBER && (i == 0))) { /* Read the OID (i==0) or the KDF params (i==2). */ err = read_sized_octet_string (inp, &pktlen, pk->pkey+i); } + else if (algorithm == PUBKEY_ALGO_KYBER && i == 2) + { + /* Read the four-octet count prefixed Kyber public key. */ + err = read_octet_string (inp, &pktlen, 4, 0, 0, pk->pkey+i); + } else { + /* Read MPI or SOS. */ unsigned int n = pktlen; if (algorithm == PUBKEY_ALGO_ECDSA || algorithm == PUBKEY_ALGO_EDDSA - || algorithm == PUBKEY_ALGO_ECDH) + || algorithm == PUBKEY_ALGO_ECDH + || algorithm == PUBKEY_ALGO_KYBER) pk->pkey[i] = sos_read (inp, &n, 0); else pk->pkey[i] = mpi_read (inp, &n, 0); @@ -2707,7 +2754,8 @@ parse_key (IOBUF inp, int pkttype, unsigned long pktlen, mpi_print (listfp, pk->pkey[i], mpi_print_mode); if ((algorithm == PUBKEY_ALGO_ECDSA || algorithm == PUBKEY_ALGO_EDDSA - || algorithm == PUBKEY_ALGO_ECDH) && i==0) + || algorithm == PUBKEY_ALGO_ECDH + || algorithm == PUBKEY_ALGO_KYBER) && i==0) { char *curve = openpgp_oid_to_str (pk->pkey[0]); const char *name = openpgp_oid_to_curve (curve, 0); @@ -3044,21 +3092,32 @@ parse_key (IOBUF inp, int pkttype, unsigned long pktlen, /* Not encrypted. */ for (i = npkey; i < nskey; i++) { - unsigned int n; if (pktlen < 2) /* At least two bytes for the length. */ { err = gpg_error (GPG_ERR_INV_PACKET); goto leave; } - n = pktlen; - if (algorithm == PUBKEY_ALGO_ECDSA - || algorithm == PUBKEY_ALGO_EDDSA - || algorithm == PUBKEY_ALGO_ECDH) - pk->pkey[i] = sos_read (inp, &n, 0); + if (algorithm == PUBKEY_ALGO_KYBER && i == npkey+1) + { + err = read_octet_string (inp, &pktlen, 4, 0, 1, pk->pkey+i); + if (err) + goto leave; + } else - pk->pkey[i] = mpi_read (inp, &n, 0); - pktlen -= n; + { + unsigned int n = pktlen; + + if (algorithm == PUBKEY_ALGO_ECDSA + || algorithm == PUBKEY_ALGO_EDDSA + || algorithm == PUBKEY_ALGO_ECDH + || algorithm == PUBKEY_ALGO_KYBER) + pk->pkey[i] = sos_read (inp, &n, 0); + else + pk->pkey[i] = mpi_read (inp, &n, 0); + pktlen -= n; + } + if (list_mode) { es_fprintf (listfp, "\tskey[%d]: ", i); |