More polish and renamed codec tests

Reviewed-by: Shane Lontis <shane.lontis@oracle.com>
Reviewed-by: Paul Dale <ppzgs1@gmail.com>
(Merged from https://github.com/openssl/openssl/pull/26569)
This commit is contained in:
Viktor Dukhovni 2025-02-04 06:02:20 +11:00 committed by Tomas Mraz
parent 5b2d996f91
commit 0fb5a78acd
43 changed files with 351 additions and 115 deletions

2
.gitattributes vendored
View File

@ -3,7 +3,7 @@
/fuzz/corpora/** binary
*.pfx binary
test/recipes/15-test_ml_dsa_codecs_data/*.dat binary
test/recipes/15-test_ml_kem_data/*.dat binary
test/recipes/15-test_ml_kem_codecs_data/*.dat binary
# For git archive
fuzz/corpora/** export-ignore

View File

@ -2,13 +2,14 @@
=head1 NAME
EVP_PKEY-ML-KEM,
EVP_KEYMGMT-ML-KEM,
EVP_PKEY-ML-KEM-512,
EVP_PKEY-ML-KEM-768,
EVP_PKEY-ML-KEM-1024,
EVP_KEYMGMT-ML-KEM-512,
EVP_KEYMGMT-ML-KEM-768,
EVP_KEYMGMT-ML-KEM-1024,
EVP_PKEY-ML-KEM
EVP_KEYMGMT-ML-KEM-1024
- ML-KEM keytype and algorithm support
=head1 DESCRIPTION
@ -39,10 +40,16 @@ with keys (by default) regenerated from the seed even when also provided on impo
See L</Provider configuration parameters> below for related controls.
When the seed is retained, it is also available as a B<gettable> parameter,
and private key output to B<PKCS#8> files will default to seed format.
When the seed is not available, because not included in the B<PKCS#8> file, not
available on import, or not retained, B<PKCS#8> private key files will have the
private key in FIPS 203 C<dk> format.
and private key output to B<PKCS#8> files will by default include the seed.
When the seed was not initially known, or was not retained, B<PKCS#8> private
key files will contain only the private key in FIPS 203 C<dk> format.
=item "properties" (B<OSSL_PKEY_PARAM_PROPERTIES>) <UTF8 string>
Sets properties to be used when fetching algorithm implementations used for
ML-KEM hashing operations.
Use L<EVP_PKEY_CTX_set_params(3)> after calling L<EVP_PKEY_keygen_init(3)>.
=back
@ -50,7 +57,13 @@ private key in FIPS 203 C<dk> format.
In addition to the common parameters that all keytypes should support (see
L<provider-keymgmt(7)/Common Information Parameters>), B<ML-KEM> keys
keys support the following.
keys support the parameters listed below.
These are gettable using
L<EVP_PKEY_get_octet_string_param(3)> or L<EVP_PKEY_get_params(3)>.
They can be initialised via L<EVP_PKEY_fromdata(3)>, and are returned by
L<EVP_PKEY_todata(3)> given a suitable I<selection>.
Once a public or private key is configured, it can no longer be modified,
nor can another key component be added.
=over 4
@ -129,8 +142,8 @@ The supported formats are:
=item C<seed-priv>:
This format represents keys in which both the 64-byte B<(d, z)> seed and the
FIPS 203 decapsulation private key B<dk> are present in the PKCS#8 private key
This format represents B<PKCS#8> objects in which both the FIPS 203 64-byte
B<(d, z)> seed and the decapsulation key B<dk> are present in the private key
as part of the DER encoding of the ASN.1 sequence:
PrivateKey ::= SEQUENCE {
@ -144,49 +157,55 @@ recognised on input.
=item C<seed-only>:
This format represents keys in which only the 64-byte B<(d, z)> seed is present
in the above sequence.
This format represents B<PKCS#8> objects in which only the 64-byte B<(d, z)>
seed is present in the above sequence.
If the C<seed-only> format is not included in the list, this format will not be
recognised on input.
=item C<priv-only>:
This format represents keys in which only the FIPS 203 decapsulation key B<dk>
is present in the above sequence.
This format represents B<PKCS#8> objects in which only the FIPS 203
decapsulation key B<dk> is present in the above sequence.
If the C<priv-only> format is not included in the list, this format will not be
recognised on input.
=item C<priv-oqs>:
This format represents keys in which the private key value is a DER encoding of an
octet string containing the FIPS 203 decapsulation key B<dk>.
This format is used in some builds of the C<oqsprovider>, with a non-NIST value of
the algorithm OID by default.
For interoperability with OpenSSL, environment variable settings, such as
C<OQS_OID_MLKEM768=2.16.840.1.101.3.4.4.2>, need to be used to configure
C<oqsprovider> to use the expected NIST OIDs for B<ML-kEM>.
This format represents B<PKCS#8> objects in which the private key is a DER
encoding of an octet string containing the FIPS 203 decapsulation key B<dk>.
This format is used in some builds of the C<oqsprovider>.
If the C<priv-oqs> format is not included in the list, this format will not be
recognised on input.
=item C<pair-oqs>:
This format represents keys in which the private keys a DER encoding of an
octet string containing the concatenaton of the FIPS 203 decapsulation key B<dk> and
the encapsulation key B<ek>.
This encoding is used in some builds of the C<oqsprovider>, with a non-NIST
value of the OID by default.
For interoperability with OpenSSL, environment variable settings, such as
C<OQS_OID_MLKEM512=2.16.840.1.101.3.4.4.1>, need to be used to configure
C<oqsprovider> to use the expected NIST OIDs for B<ML-kEM>.
This format represents B<PKCS#8> objects in which the private key is a DER
encoding of an octet string containing the concatenaton of the FIPS 203
decapsulation key B<dk> and the encapsulation key B<ek>.
This encoding is used in some builds of the C<oqsprovider>.
If the C<pair-oqs> format is not included in the list, this format will not be
recognised on input.
=item C<bare-seed>:
This format represents B<PKCS#8> objects in which the private key contains
the 64-byte FIPS 204 seed B<(d, z)> without any ASN.1 encapsulation.
If the C<bare-seed> format is not included in the list, this format will not be
recognised on input.
=item C<bare-priv>:
This format represents B<PKCS#8> objects in which the private key contains
the FIPS 204 decapsulation key B<dk> without any ASN.1 encapsulation.
If the C<bare-priv> format is not included in the list, this format will not be
recognised on input.
=back
=item C<ml-kem.output_formats> (B<OSSL_PKEY_PARAM_ML_KEM_OUTPUT_FORMATS>) <UTF8 string>
Ordered list of enabled private key output formats when writing PKCS#8 files.
List elements are separated by commas and/or spaces or tabs.
Ordered list of enabled private key output formats when writing B<PKCS#8> files.
List elements are separated by commas, spaces or tabs.
The list of enabled formats can be specified in the configuration file, as seen
in the L</EXAMPLES> section below, or the via the B<-provparam> command-line
option.
@ -197,14 +216,15 @@ The order in which elements are listed is important, the selected format will be
the first one that is possible to output.
If the key seed is known, the first listed format will be selected.
If the key seed is not known, the first format that omits the seed will be selected.
The default order is equivalent to C<seed-priv> and C<priv-only> second, with
both seed and key output when the seed is available, and otherwise just the
key is output.
The default order is equivalent to C<seed-priv> first and C<priv-only> second, with
both seed and key output when the seed is available, and just the
key otherwise.
If C<seed-only> is listed first, then the seed will be output without the key
when available, otherwise the output will have just the key.
If C<priv-only> is listed first, then just the key is output regardless of
whether the seed is present.
The legacy C<oqs> formats can also be output, by listing either of those first.
The legacy C<oqs> and C<bare> formats can also be output, by listing those
first.
=back
@ -227,8 +247,6 @@ An B<ML-KEM-768> key can be generated like this:
pkey = EVP_PKEY_Q_keygen(NULL, NULL, "ML-KEM-768");
Equivalent calls are available for B<ML-KEM-512> and B<ML-KEM-1024>.
An B<ML-KEM> private key in seed format can be converted to a key in the FIPS
203 B<dk> format by running:
@ -238,9 +256,9 @@ An B<ML-KEM> private key in seed format can be converted to a key in the FIPS
To generate an, e.g., B<ML-KEM-768> key, in FIPS 203 B<dk> format, you can run:
$ openssl genpkey -provparam ml-kem.retain_seed=no \
-algorithm ml-kem-768 -out long.pem
-algorithm ml-kem-768 -out priv-only.pem
If you have B<PKCS#8> file with both a seed and a key, and prefer to import the
If you have a B<PKCS#8> file with both a seed and a key, and prefer to import the
companion key rather than the seed, you can run:
$ openssl pkey -provparam ml-kem.prefer_seed=no \
@ -283,9 +301,9 @@ L<EVP_PKEY(3)>,
L<EVP_PKEY_get_raw_private_key(3)>,
L<EVP_PKEY_get_raw_public_key(3)>,
L<EVP_PKEY_get1_encoded_public_key(3)>,
LOSSL_PROVIDER_add_conf_parameter(3)>,
L<provider-keymgmt(7)>,
L<EVP_KEM-ML-KEM(7)>,
LOSSL_PROVIDER_add_conf_parameter(3)>
L<EVP_KEM-ML-KEM(7)>
=head1 HISTORY

View File

@ -32,6 +32,11 @@
* - OQS private + public key: OCTET STRING
* (The public key is ignored, just as with PKCS#8 v2.)
*
* and two more that are "inspired" by the IETF non-ASN.1 seed encoding.
*
* - Bare seed (just the 64 bytes)
* - Bare priv (just the key bytes)
*
* An offset of zero means that particular field is absent.
*
* On output the PKCS8 info table order is important:
@ -47,7 +52,7 @@
* into the tables. Had they been zeroed, one table could cover all three
* ML-KEM parameter sets.
*/
#define NUM_PKCS8_FORMATS 5
#define NUM_PKCS8_FORMATS 7
/*-
* ML-KEM-512:
@ -58,12 +63,14 @@ static const ML_KEM_SPKI_INFO ml_kem_512_spki_info = {
{ 0x30, 0x82, 0x03, 0x32, 0x30, 0x0b, 0x06, 0x09, 0x60, 0x86, 0x48,
0x01, 0x65, 0x03, 0x04, 0x04, 0x01, 0x03, 0x82, 0x03, 0x21, 0x00, }
};
static const ML_KEM_PKCS8_INFO ml_kem_512_pkcs8_info[NUM_PKCS8_FORMATS] = {
{ "seed-priv", 1706, 0x308206a6, 0x0440, 6, 0x81820660, 74, 0, },
{ "priv-only", 1640, 0x30820664, 0, 0, 0x81820660, 8, 0, },
{ "seed-only", 68, 0x30420440, 0x0440, 4, 0, 0, 0, },
{ "priv-oqs", 1636, 0x04820660, 0, 0, 0x04820660, 4, 0, },
{ "pair-oqs", 2436, 0x04820980, 0, 0, 0x04820980, 4, 1636, },
static const ML_KEM_PKCS8_INFO ml_kem_512_pkcs8_info[] = {
{ "seed-priv", 0x06aa, 0x308206a6, 0x0440, 6, 0x40, 0x81820660, 0x4a, 0x0660, 0x0000, 0x0000 },
{ "priv-only", 0x0668, 0x30820664, 0, 0, 0x00, 0x81820660, 0x08, 0x0660, 0x0000, 0x0000 },
{ "seed-only", 0x0044, 0x30420440, 0, 4, 0x40, 0, 0x00, 0x0000, 0x0000, 0x0000 },
{ "priv-oqs", 0x0664, 0x04820660, 0, 0, 0x00, 0x04820660, 0x04, 0x0660, 0x0000, 0x0000 },
{ "pair-oqs", 0x0984, 0x04820980, 0, 0, 0x00, 0x04820980, 0x04, 0x0660, 0x0664, 0x0320 },
{ "bare-seed", 0x0040, 0, 0, 0, 0x40, 0, 0x00, 0x0000, 0x0000, 0x0000 },
{ "bare-priv", 0x0660, 0, 0, 0, 0x00, 0, 0x00, 0x0660, 0x0000, 0x0000 },
};
/*-
@ -75,12 +82,14 @@ static const ML_KEM_SPKI_INFO ml_kem_768_spki_info = {
{ 0x30, 0x82, 0x04, 0xb2, 0x30, 0x0b, 0x06, 0x09, 0x60, 0x86, 0x48,
0x01, 0x65, 0x03, 0x04, 0x04, 0x02, 0x03, 0x82, 0x04, 0xa1, 0x00, }
};
static const ML_KEM_PKCS8_INFO ml_kem_768_pkcs8_info[NUM_PKCS8_FORMATS] = {
{ "seed-priv", 2474, 0x308209a6, 0x0440, 6, 0x81820960, 74, 0, },
{ "priv-only", 2408, 0x30820964, 0, 0, 0x81820960, 8, 0, },
{ "seed-only", 68, 0x30420440, 0x0440, 4, 0, 0, 0, },
{ "priv-oqs", 2404, 0x04820960, 0, 0, 0x04820960, 4, 0, },
{ "pair-oqs", 3588, 0x04820e00, 0, 0, 0x04820e00, 4, 2404, },
static const ML_KEM_PKCS8_INFO ml_kem_768_pkcs8_info[] = {
{ "seed-priv", 0x09aa, 0x308209a6, 0x0440, 6, 0x40, 0x81820960, 0x4a, 0x0960, 0x0000, 0x0000 },
{ "priv-only", 0x0968, 0x30820964, 0, 0, 0x00, 0x81820960, 0x08, 0x0960, 0x0000, 0x0000 },
{ "seed-only", 0x0044, 0x30420440, 0, 4, 0x40, 0, 0x00, 0x0000, 0x0000, 0x0000 },
{ "priv-oqs", 0x0964, 0x04820960, 0, 0, 0x00, 0x04820960, 0x04, 0x0960, 0x0000, 0x0000 },
{ "pair-oqs", 0x0e04, 0x04820e00, 0, 0, 0x00, 0x04820e00, 0x04, 0x0960, 0x0964, 0x04a0 },
{ "bare-seed", 0x0040, 0, 0, 0, 0x40, 0, 0x00, 0x0000, 0x0000, 0x0000 },
{ "bare-priv", 0x0960, 0, 0, 0, 0x00, 0, 0x00, 0x0960, 0x0000, 0x0000 },
};
/*-
@ -92,38 +101,40 @@ static const ML_KEM_SPKI_INFO ml_kem_1024_spki_info = {
{ 0x30, 0x82, 0x06, 0x32, 0x30, 0x0b, 0x06, 0x09, 0x60, 0x86, 0x48,
0x01, 0x65, 0x03, 0x04, 0x04, 0x03, 0x03, 0x82, 0x06, 0x21, 0x00, }
};
static const ML_KEM_PKCS8_INFO ml_kem_1024_pkcs8_info[NUM_PKCS8_FORMATS] = {
{ "seed-priv", 3242, 0x30820ca6, 0x0440, 6, 0x81820c60, 74, 0, },
{ "priv-only", 3176, 0x30820c64, 0, 0, 0x81820c60, 8, 0, },
{ "seed-only", 68, 0x30420440, 0x0440, 4, 0, 0, 0, },
{ "priv-oqs", 3172, 0x04820c60, 0, 0, 0x04820c60, 4, 0, },
{ "pair-oqs", 4740, 0x04821280, 0, 0, 0x04821280, 4, 3172, },
static const ML_KEM_PKCS8_INFO ml_kem_1024_pkcs8_info[] = {
{ "seed-priv", 0x0caa, 0x30820ca6, 0x0440, 6, 0x40, 0x81820c60, 0x4a, 0x0c60, 0x0000, 0x0000 },
{ "priv-only", 0x0c68, 0x30820c64, 0, 0, 0x00, 0x81820c60, 0x08, 0x0c60, 0x0000, 0x0000 },
{ "seed-only", 0x0044, 0x30420440, 0, 4, 0x40, 0, 0x00, 0x0000, 0x0000, 0x0000 },
{ "priv-oqs", 0x0c64, 0x04820c60, 0, 0, 0x00, 0x04820c60, 0x04, 0x0c60, 0x0000, 0x0000 },
{ "pair-oqs", 0x1284, 0x04821280, 0, 0, 0x00, 0x04821280, 0x04, 0x0c60, 0x0c64, 0x0620 },
{ "bare-seed", 0x0040, 0, 0, 0, 0x40, 0, 0x00, 0x0000, 0x0000, 0x0000 },
{ "bare-priv", 0x0c60, 0, 0, 0, 0x00, 0, 0x00, 0x0c60, 0x0000, 0x0000 },
};
/* Indices of slots in the `cinfo_map` table below */
#define ML_KEM_512_CINFO 0
#define ML_KEM_768_CINFO 1
#define ML_KEM_1024_CINFO 2
/* Indices of slots in the `codecs` table below */
#define ML_KEM_512_CODEC 0
#define ML_KEM_768_CODEC 1
#define ML_KEM_1024_CODEC 2
/*
* Per-variant fixed parameters
*/
static const ML_KEM_CINFO cinfo_map[3] = {
static const ML_KEM_CODEC codecs[3] = {
{ &ml_kem_512_spki_info, ml_kem_512_pkcs8_info },
{ &ml_kem_768_spki_info, ml_kem_768_pkcs8_info },
{ &ml_kem_1024_spki_info, ml_kem_1024_pkcs8_info }
};
/* Retrieve the parameters of one of the ML-KEM variants */
static const ML_KEM_CINFO *ml_kem_get_cinfo(int evp_type)
static const ML_KEM_CODEC *ml_kem_get_codec(int evp_type)
{
switch (evp_type) {
case EVP_PKEY_ML_KEM_512:
return &cinfo_map[ML_KEM_512_CINFO];
return &codecs[ML_KEM_512_CODEC];
case EVP_PKEY_ML_KEM_768:
return &cinfo_map[ML_KEM_768_CINFO];
return &codecs[ML_KEM_768_CODEC];
case EVP_PKEY_ML_KEM_1024:
return &cinfo_map[ML_KEM_1024_CINFO];
return &codecs[ML_KEM_1024_CODEC];
}
return NULL;
}
@ -136,15 +147,14 @@ static int vp8_pref_cmp(const void *va, const void *vb)
/*
* Zeros sort last, otherwise the sort is in increasing order.
*
* The preferences are small enough to ensure the comparison is monotone as
* required. Some versions of qsort(3) have been known to crash when the
* comparison is not monotone.
* The preferences are small enough to ensure the comparison is transitive
* as required by qsort(3). When overflow or underflow is possible, the
* correct transitive comparison would be: (b < a) - (a < b).
*/
if (a->vp8_pref > 0 && b->vp8_pref > 0)
return a->vp8_pref - b->vp8_pref;
if (a->vp8_pref == 0)
return b->vp8_pref;
return -a->vp8_pref;
/* A preference of 0 is "larger" than (sorts after) any nonzero value. */
return b->vp8_pref - a->vp8_pref;
}
static ML_KEM_PKCS8_PREF *vp8_order(const char *algorithm_name,
@ -156,33 +166,42 @@ static ML_KEM_PKCS8_PREF *vp8_order(const char *algorithm_name,
const char *fmt = formats, *end;
const char *sep = "\t ,";
/* Reserve an extra terminal slot with vp8_entry == NULL */
if ((ret = OPENSSL_zalloc((NUM_PKCS8_FORMATS + 1) * sizeof(*ret))) == NULL)
return NULL;
/* Entries that match a format will get a non-zero preference. */
for (i = 0; i < NUM_PKCS8_FORMATS; ++i) {
ret[i].vp8_entry = &pkcs8_info[i];
ret[i].vp8_pref = 0;
}
/* Default to compile-time table order. */
/* Default to compile-time table order when none specified. */
if (formats == NULL)
return ret;
/* Formats are case-insensitive, separated by spaces, tabs and/or commas */
/*
* Formats are case-insensitive, separated by spaces, tabs or commas.
* Duplicate formats are allowed, the first occurence determines the order.
*/
do {
if (*(fmt += strspn(fmt, sep)) == '\0')
break;
end = fmt + strcspn(fmt, sep);
for (i = 0; i < NUM_PKCS8_FORMATS; ++i) {
/* Skip slots already selected or with a different name. */
if (ret[i].vp8_pref > 0
|| OPENSSL_strncasecmp(ret[i].vp8_entry->p8_name,
fmt, (end - fmt)) != 0)
continue;
/* First time match */
ret[i].vp8_pref = ++count;
break;
}
fmt = end;
} while (count < NUM_PKCS8_FORMATS);
/* No formats matched, raise an error */
if (count == 0) {
OPENSSL_free(ret);
ERR_raise_data(ERR_LIB_PROV, PROV_R_ML_KEM_NO_FORMAT,
@ -190,7 +209,9 @@ static ML_KEM_PKCS8_PREF *vp8_order(const char *algorithm_name,
algorithm_name, direction);
return NULL;
}
/* Sort by preference, with 0's last */
qsort(ret, NUM_PKCS8_FORMATS, sizeof(*ret), vp8_pref_cmp);
/* Terminate the list at first unselected entry, perhaps reserved slot. */
ret[count].vp8_entry = NULL;
return ret;
}
@ -201,14 +222,14 @@ ossl_ml_kem_d2i_PUBKEY(const uint8_t *pubenc, int publen, int evp_type,
{
OSSL_LIB_CTX *libctx = PROV_LIBCTX_OF(provctx);
const ML_KEM_VINFO *v;
const ML_KEM_CINFO *c;
const ML_KEM_CODEC *codec;
const ML_KEM_SPKI_INFO *vspki;
ML_KEM_KEY *ret;
if ((v = ossl_ml_kem_get_vinfo(evp_type)) == NULL
|| (c = ml_kem_get_cinfo(evp_type)) == NULL)
|| (codec = ml_kem_get_codec(evp_type)) == NULL)
return NULL;
vspki = c->spki_info;
vspki = codec->spki_info;
if (publen != ML_KEM_SPKI_OVERHEAD + (ossl_ssize_t) v->pubkey_bytes
|| memcmp(pubenc, vspki->asn1_prefix, ML_KEM_SPKI_OVERHEAD) != 0)
return NULL;
@ -236,7 +257,7 @@ ossl_ml_kem_d2i_PKCS8(const uint8_t *prvenc, int prvlen,
{
OSSL_LIB_CTX *libctx = PROV_LIBCTX_OF(provctx);
const ML_KEM_VINFO *v;
const ML_KEM_CINFO *c;
const ML_KEM_CODEC *codec;
ML_KEM_PKCS8_PREF *vp8_alloc = NULL, *vp8_slot;
const ML_KEM_PKCS8_INFO *vp8;
ML_KEM_KEY *key = NULL, *ret = NULL;
@ -245,12 +266,12 @@ ossl_ml_kem_d2i_PKCS8(const uint8_t *prvenc, int prvlen,
const X509_ALGOR *alg = NULL;
const char *formats;
int len, ptype;
uint32_t magic;
uint32_t magic, p8_magic;
uint16_t seed_magic;
/* Which ML-KEM variant? */
if ((v = ossl_ml_kem_get_vinfo(evp_type)) == NULL
|| (c = ml_kem_get_cinfo(evp_type)) == NULL)
|| (codec = ml_kem_get_codec(evp_type)) == NULL)
return 0;
/* Extract the key OID and any parameters. */
@ -266,7 +287,7 @@ ossl_ml_kem_d2i_PKCS8(const uint8_t *prvenc, int prvlen,
/* Get the list of enabled decoders. Their order is not important here. */
formats = ossl_prov_ctx_get_param(
provctx, OSSL_PKEY_PARAM_ML_KEM_INPUT_FORMATS, NULL);
vp8_slot = vp8_alloc = vp8_order(v->algorithm_name, c->pkcs8_info,
vp8_slot = vp8_alloc = vp8_order(v->algorithm_name, codec->pkcs8_info,
"input", formats);
if (vp8_alloc == NULL)
goto end;
@ -285,14 +306,27 @@ ossl_ml_kem_d2i_PKCS8(const uint8_t *prvenc, int prvlen,
/* Find the matching p8 info slot, that also has the expected length. */
pos = OPENSSL_load_u32_be(&magic, buf);
for (vp8_slot = vp8_alloc; vp8_slot->vp8_entry != NULL; ++vp8_slot) {
if (magic == vp8_slot->vp8_entry->p8_magic
&& len == (ossl_ssize_t)vp8_slot->vp8_entry->p8_bytes)
if (len != (ossl_ssize_t)vp8_slot->vp8_entry->p8_bytes)
continue;
/* p8_magic == 0, signals a non-ASN.1 length-based encoding */
if ((p8_magic = vp8_slot->vp8_entry->p8_magic) == 0) {
pos = buf;
break;
}
if (magic == p8_magic)
break;
}
if ((vp8 = vp8_slot->vp8_entry) == NULL)
if ((vp8 = vp8_slot->vp8_entry) == NULL
|| (vp8->seed_length > 0 && vp8->seed_length != ML_KEM_SEED_BYTES)
|| (vp8->priv_length > 0 && vp8->priv_length != v->prvkey_bytes)
|| (vp8->pub_length > 0 && vp8->pub_length != v->pubkey_bytes)) {
ERR_raise_data(ERR_LIB_PROV, PROV_R_ML_KEM_NO_FORMAT,
"no matching enabled %s private key input formats",
v->algorithm_name);
goto end;
}
if (vp8->seed_offset > 0) {
if (vp8->seed_length > 0) {
/* Check |seed| tag/len, if not subsumed by |magic|. */
if (pos + sizeof(uint16_t) == buf + vp8->seed_offset) {
pos = OPENSSL_load_u16_be(&seed_magic, pos);
@ -303,7 +337,7 @@ ossl_ml_kem_d2i_PKCS8(const uint8_t *prvenc, int prvlen,
}
pos += ML_KEM_SEED_BYTES;
}
if (vp8->priv_offset > 0) {
if (vp8->priv_length > 0) {
/* Check |priv| tag/len */
if (pos + sizeof(uint32_t) == buf + vp8->priv_offset) {
pos = OPENSSL_load_u32_be(&magic, pos);
@ -314,7 +348,7 @@ ossl_ml_kem_d2i_PKCS8(const uint8_t *prvenc, int prvlen,
}
pos += v->prvkey_bytes;
}
if (vp8->pub_offset > 0) {
if (vp8->pub_length > 0) {
if (pos != buf + vp8->pub_offset)
goto end;
pos += v->pubkey_bytes;
@ -332,7 +366,7 @@ ossl_ml_kem_d2i_PKCS8(const uint8_t *prvenc, int prvlen,
provctx, OSSL_PKEY_PARAM_ML_KEM_RETAIN_SEED, 1);
key->prefer_seed = ossl_prov_ctx_get_bool_param(
provctx, OSSL_PKEY_PARAM_ML_KEM_PREFER_SEED, 1);
if (vp8->seed_offset > 0) {
if (vp8->seed_length > 0) {
if (!ossl_ml_kem_set_seed(buf + vp8->seed_offset,
ML_KEM_SEED_BYTES, key)) {
ERR_raise_data(ERR_LIB_OSSL_DECODER, ERR_R_INTERNAL_ERROR,
@ -341,14 +375,14 @@ ossl_ml_kem_d2i_PKCS8(const uint8_t *prvenc, int prvlen,
goto end;
}
}
if (vp8->priv_offset > 0) {
if ((key->encoded_dk = OPENSSL_malloc(v->prvkey_bytes)) == NULL) {
if (vp8->priv_length > 0) {
if ((key->encoded_dk = OPENSSL_malloc(vp8->priv_length)) == NULL) {
ERR_raise_data(ERR_LIB_PROV, PROV_R_INVALID_KEY,
"error parsing %s private key",
v->algorithm_name);
goto end;
}
memcpy(key->encoded_dk, buf + vp8->priv_offset, v->prvkey_bytes);
memcpy(key->encoded_dk, buf + vp8->priv_offset, vp8->priv_length);
}
/* Any OQS public key content is ignored */
ret = key;
@ -393,7 +427,7 @@ int ossl_ml_kem_i2d_prvkey(const ML_KEM_KEY *key, uint8_t **out,
PROV_CTX *provctx)
{
const ML_KEM_VINFO *v = key->vinfo;
const ML_KEM_CINFO *c;
const ML_KEM_CODEC *codec;
ML_KEM_PKCS8_PREF *vp8_alloc, *vp8_slot;
const ML_KEM_PKCS8_INFO *vp8;
uint8_t *buf = NULL, *pos;
@ -402,7 +436,7 @@ int ossl_ml_kem_i2d_prvkey(const ML_KEM_KEY *key, uint8_t **out,
int ret = 0;
/* Not ours to handle */
if ((c = ml_kem_get_cinfo(v->evp_type)) == NULL)
if ((codec = ml_kem_get_codec(v->evp_type)) == NULL)
return 0;
if (!ossl_ml_kem_have_prvkey(key)) {
@ -414,7 +448,7 @@ int ossl_ml_kem_i2d_prvkey(const ML_KEM_KEY *key, uint8_t **out,
formats = ossl_prov_ctx_get_param(
provctx, OSSL_PKEY_PARAM_ML_KEM_OUTPUT_FORMATS, NULL);
vp8_slot = vp8_alloc = vp8_order(v->algorithm_name, c->pkcs8_info,
vp8_slot = vp8_alloc = vp8_order(v->algorithm_name, codec->pkcs8_info,
"output", formats);
if (vp8_alloc == NULL)
return 0;
@ -422,10 +456,13 @@ int ossl_ml_kem_i2d_prvkey(const ML_KEM_KEY *key, uint8_t **out,
/* If we don't have a seed, skip seedful entries */
if (!ossl_ml_kem_have_seed(key))
while (vp8_slot->vp8_entry != NULL
&& vp8_slot->vp8_entry->seed_offset != 0)
&& vp8_slot->vp8_entry->seed_length != 0)
++vp8_slot;
/* No matching table entries, give up */
if ((vp8 = vp8_slot->vp8_entry) == NULL) {
if ((vp8 = vp8_slot->vp8_entry) == NULL
|| (vp8->seed_length > 0 && vp8->seed_length != ML_KEM_SEED_BYTES)
|| (vp8->priv_length > 0 && vp8->priv_length != v->prvkey_bytes)
|| (vp8->pub_length > 0 && vp8->pub_length != v->pubkey_bytes)) {
ERR_raise_data(ERR_LIB_PROV, PROV_R_ML_KEM_NO_FORMAT,
"no matching enabled %s private key output formats",
v->algorithm_name);
@ -441,8 +478,9 @@ int ossl_ml_kem_i2d_prvkey(const ML_KEM_KEY *key, uint8_t **out,
if ((pos = buf = OPENSSL_malloc((size_t) len)) == NULL)
goto end;
pos = OPENSSL_store_u32_be(pos, vp8->p8_magic);
if (vp8->seed_offset != 0) {
if (vp8->p8_magic != 0)
pos = OPENSSL_store_u32_be(pos, vp8->p8_magic);
if (vp8->seed_length != 0) {
/*
* Either the tag/len were already included in |magic| or they require
* us to write two bytes now.
@ -458,7 +496,7 @@ int ossl_ml_kem_i2d_prvkey(const ML_KEM_KEY *key, uint8_t **out,
}
pos += ML_KEM_SEED_BYTES;
}
if (vp8->priv_offset != 0) {
if (vp8->priv_length != 0) {
if (pos + sizeof(uint32_t) == buf + vp8->priv_offset)
pos = OPENSSL_store_u32_be(pos, vp8->priv_magic);
if (pos != buf + vp8->priv_offset
@ -471,7 +509,7 @@ int ossl_ml_kem_i2d_prvkey(const ML_KEM_KEY *key, uint8_t **out,
pos += v->prvkey_bytes;
}
/* OQS form output with tacked-on public key */
if (vp8->pub_offset != 0) {
if (vp8->pub_length != 0) {
/* The OQS pubkey is never separately DER-wrapped */
if (pos != buf + vp8->pub_offset
|| !ossl_ml_kem_encode_public_key(pos, v->pubkey_bytes, key)) {

View File

@ -55,15 +55,18 @@ typedef struct {
uint32_t p8_magic;
uint16_t seed_magic;
size_t seed_offset;
size_t seed_length;
uint32_t priv_magic;
size_t priv_offset;
size_t priv_length;
size_t pub_offset;
size_t pub_length;
} ML_KEM_PKCS8_INFO;
typedef struct {
const ML_KEM_SPKI_INFO *spki_info;
const ML_KEM_PKCS8_INFO *pkcs8_info;
} ML_KEM_CINFO;
} ML_KEM_CODEC;
typedef struct {
const ML_KEM_PKCS8_INFO *vp8_entry;

View File

@ -1448,9 +1448,11 @@ int setup_tests(void)
}
#endif /* OPENSSL_NO_ML_DSA */
#ifndef OPENSSL_NO_ML_KEM
MAKE_KEYS(ML_KEM_512, "ML-KEM-512", NULL);
MAKE_KEYS(ML_KEM_768, "ML-KEM-768", NULL);
MAKE_KEYS(ML_KEM_1024, "ML-KEM-1024", NULL);
if (!is_fips_lt_3_5) {
MAKE_KEYS(ML_KEM_512, "ML-KEM-512", NULL);
MAKE_KEYS(ML_KEM_768, "ML-KEM-768", NULL);
MAKE_KEYS(ML_KEM_1024, "ML-KEM-1024", NULL);
}
#endif
TEST_info("Loading RSA key...");
@ -1508,9 +1510,11 @@ int setup_tests(void)
ADD_TEST_SUITE(X448);
#endif
#ifndef OPENSSL_NO_ML_KEM
ADD_TEST_SUITE(ML_KEM_512);
ADD_TEST_SUITE(ML_KEM_768);
ADD_TEST_SUITE(ML_KEM_1024);
if (!is_fips_lt_3_5) {
ADD_TEST_SUITE(ML_KEM_512);
ADD_TEST_SUITE(ML_KEM_768);
ADD_TEST_SUITE(ML_KEM_1024);
}
#endif
/*
* ED25519, ED448, X25519 and X448 have no support for
@ -1583,9 +1587,11 @@ void cleanup_tests(void)
FREE_KEYS(X448);
#endif
#ifndef OPENSSL_NO_ML_KEM
FREE_KEYS(ML_KEM_512);
FREE_KEYS(ML_KEM_768);
FREE_KEYS(ML_KEM_1024);
if (!is_fips_lt_3_5) {
FREE_KEYS(ML_KEM_512);
FREE_KEYS(ML_KEM_768);
FREE_KEYS(ML_KEM_1024);
}
#endif
FREE_KEYS(RSA);
FREE_KEYS(RSA_PSS);

View File

@ -17,10 +17,10 @@ use OpenSSL::Glob;
use OpenSSL::Test qw/:DEFAULT data_file srctop_file bldtop_dir/;
use OpenSSL::Test::Utils;
setup("test_ml_kem");
setup("test_ml_kem_codecs");
my @algs = qw(512 768 1024);
my @formats = qw(seed-priv priv-only seed-only priv-oqs pair-oqs);
my @formats = qw(seed-priv priv-only seed-only priv-oqs pair-oqs bare-seed bare-priv);
plan skip_all => "ML-KEM isn't supported in this build"
if disabled("ml-kem");

View File

@ -0,0 +1,69 @@
-----BEGIN PRIVATE KEY-----
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
KCkqKywtLi8wMTIzNDU2Nzg5Ojs8PT4/
-----END PRIVATE KEY-----

View File

@ -0,0 +1,4 @@
-----BEGIN PRIVATE KEY-----
MFICAQAwCwYJYIZIAWUDBAQDBEAAAQIDBAUGBwgJCgsMDQ4PEBESExQVFhcYGRob
HB0eHyAhIiMkJSYnKCkqKywtLi8wMTIzNDU2Nzg5Ojs8PT4/
-----END PRIVATE KEY-----

View File

@ -0,0 +1,37 @@
-----BEGIN PRIVATE KEY-----
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
KCkqKywtLi8wMTIzNDU2Nzg5Ojs8PT4/
-----END PRIVATE KEY-----

View File

@ -0,0 +1,4 @@
-----BEGIN PRIVATE KEY-----
MFICAQAwCwYJYIZIAWUDBAQBBEAAAQIDBAUGBwgJCgsMDQ4PEBESExQVFhcYGRob
HB0eHyAhIiMkJSYnKCkqKywtLi8wMTIzNDU2Nzg5Ojs8PT4/
-----END PRIVATE KEY-----

View File

@ -0,0 +1,53 @@
-----BEGIN PRIVATE KEY-----
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
KCkqKywtLi8wMTIzNDU2Nzg5Ojs8PT4/
-----END PRIVATE KEY-----

View File

@ -0,0 +1,4 @@
-----BEGIN PRIVATE KEY-----
MFICAQAwCwYJYIZIAWUDBAQCBEAAAQIDBAUGBwgJCgsMDQ4PEBESExQVFhcYGRob
HB0eHyAhIiMkJSYnKCkqKywtLi8wMTIzNDU2Nzg5Ojs8PT4/
-----END PRIVATE KEY-----