]> git.ipfire.org Git - thirdparty/openssl.git/commitdiff
More polish and renamed codec tests
authorViktor Dukhovni <openssl-users@dukhovni.org>
Mon, 3 Feb 2025 19:02:20 +0000 (06:02 +1100)
committerTomas Mraz <tomas@openssl.org>
Fri, 14 Feb 2025 09:50:58 +0000 (10:50 +0100)
Reviewed-by: Shane Lontis <shane.lontis@oracle.com>
Reviewed-by: Paul Dale <ppzgs1@gmail.com>
(Merged from https://github.com/openssl/openssl/pull/26569)

43 files changed:
.gitattributes
doc/man7/EVP_PKEY-ML-KEM.pod
providers/implementations/encode_decode/ml_kem_codecs.c
providers/implementations/encode_decode/ml_kem_codecs.h
test/endecode_test.c
test/recipes/15-test_ml_kem_codecs.t [moved from test/recipes/15-test_ml_kem.t with 99% similarity]
test/recipes/15-test_ml_kem_codecs_data/ct-1024.dat [moved from test/recipes/15-test_ml_kem_data/ct-1024.dat with 100% similarity]
test/recipes/15-test_ml_kem_codecs_data/ct-512.dat [moved from test/recipes/15-test_ml_kem_data/ct-512.dat with 100% similarity]
test/recipes/15-test_ml_kem_codecs_data/ct-768.dat [moved from test/recipes/15-test_ml_kem_data/ct-768.dat with 100% similarity]
test/recipes/15-test_ml_kem_codecs_data/ml-kem.cnf [moved from test/recipes/15-test_ml_kem_data/ml-kem.cnf with 100% similarity]
test/recipes/15-test_ml_kem_codecs_data/prv-1024-bare-priv.pem [new file with mode: 0644]
test/recipes/15-test_ml_kem_codecs_data/prv-1024-bare-seed.pem [new file with mode: 0644]
test/recipes/15-test_ml_kem_codecs_data/prv-1024-pair-oqs.pem [moved from test/recipes/15-test_ml_kem_data/prv-1024-pair-oqs.pem with 100% similarity]
test/recipes/15-test_ml_kem_codecs_data/prv-1024-priv-only.pem [moved from test/recipes/15-test_ml_kem_data/prv-1024-priv-only.pem with 100% similarity]
test/recipes/15-test_ml_kem_codecs_data/prv-1024-priv-oqs.pem [moved from test/recipes/15-test_ml_kem_data/prv-1024-priv-oqs.pem with 100% similarity]
test/recipes/15-test_ml_kem_codecs_data/prv-1024-priv.txt [moved from test/recipes/15-test_ml_kem_data/prv-1024-priv.txt with 100% similarity]
test/recipes/15-test_ml_kem_codecs_data/prv-1024-seed-only.pem [moved from test/recipes/15-test_ml_kem_data/prv-1024-seed-only.pem with 100% similarity]
test/recipes/15-test_ml_kem_codecs_data/prv-1024-seed-priv.pem [moved from test/recipes/15-test_ml_kem_data/prv-1024-seed-priv.pem with 100% similarity]
test/recipes/15-test_ml_kem_codecs_data/prv-1024-seed.txt [moved from test/recipes/15-test_ml_kem_data/prv-1024-seed.txt with 100% similarity]
test/recipes/15-test_ml_kem_codecs_data/prv-512-bare-priv.pem [new file with mode: 0644]
test/recipes/15-test_ml_kem_codecs_data/prv-512-bare-seed.pem [new file with mode: 0644]
test/recipes/15-test_ml_kem_codecs_data/prv-512-pair-oqs.pem [moved from test/recipes/15-test_ml_kem_data/prv-512-pair-oqs.pem with 100% similarity]
test/recipes/15-test_ml_kem_codecs_data/prv-512-priv-only.pem [moved from test/recipes/15-test_ml_kem_data/prv-512-priv-only.pem with 100% similarity]
test/recipes/15-test_ml_kem_codecs_data/prv-512-priv-oqs.pem [moved from test/recipes/15-test_ml_kem_data/prv-512-priv-oqs.pem with 100% similarity]
test/recipes/15-test_ml_kem_codecs_data/prv-512-priv.txt [moved from test/recipes/15-test_ml_kem_data/prv-512-priv.txt with 100% similarity]
test/recipes/15-test_ml_kem_codecs_data/prv-512-seed-only.pem [moved from test/recipes/15-test_ml_kem_data/prv-512-seed-only.pem with 100% similarity]
test/recipes/15-test_ml_kem_codecs_data/prv-512-seed-priv.pem [moved from test/recipes/15-test_ml_kem_data/prv-512-seed-priv.pem with 100% similarity]
test/recipes/15-test_ml_kem_codecs_data/prv-512-seed.txt [moved from test/recipes/15-test_ml_kem_data/prv-512-seed.txt with 100% similarity]
test/recipes/15-test_ml_kem_codecs_data/prv-768-bare-priv.pem [new file with mode: 0644]
test/recipes/15-test_ml_kem_codecs_data/prv-768-bare-seed.pem [new file with mode: 0644]
test/recipes/15-test_ml_kem_codecs_data/prv-768-pair-oqs.pem [moved from test/recipes/15-test_ml_kem_data/prv-768-pair-oqs.pem with 100% similarity]
test/recipes/15-test_ml_kem_codecs_data/prv-768-priv-only.pem [moved from test/recipes/15-test_ml_kem_data/prv-768-priv-only.pem with 100% similarity]
test/recipes/15-test_ml_kem_codecs_data/prv-768-priv-oqs.pem [moved from test/recipes/15-test_ml_kem_data/prv-768-priv-oqs.pem with 100% similarity]
test/recipes/15-test_ml_kem_codecs_data/prv-768-priv.txt [moved from test/recipes/15-test_ml_kem_data/prv-768-priv.txt with 100% similarity]
test/recipes/15-test_ml_kem_codecs_data/prv-768-seed-only.pem [moved from test/recipes/15-test_ml_kem_data/prv-768-seed-only.pem with 100% similarity]
test/recipes/15-test_ml_kem_codecs_data/prv-768-seed-priv.pem [moved from test/recipes/15-test_ml_kem_data/prv-768-seed-priv.pem with 100% similarity]
test/recipes/15-test_ml_kem_codecs_data/prv-768-seed.txt [moved from test/recipes/15-test_ml_kem_data/prv-768-seed.txt with 100% similarity]
test/recipes/15-test_ml_kem_codecs_data/pub-1024.pem [moved from test/recipes/15-test_ml_kem_data/pub-1024.pem with 100% similarity]
test/recipes/15-test_ml_kem_codecs_data/pub-512.pem [moved from test/recipes/15-test_ml_kem_data/pub-512.pem with 100% similarity]
test/recipes/15-test_ml_kem_codecs_data/pub-768.pem [moved from test/recipes/15-test_ml_kem_data/pub-768.pem with 100% similarity]
test/recipes/15-test_ml_kem_codecs_data/ss-1024.dat [moved from test/recipes/15-test_ml_kem_data/ss-1024.dat with 100% similarity]
test/recipes/15-test_ml_kem_codecs_data/ss-512.dat [moved from test/recipes/15-test_ml_kem_data/ss-512.dat with 100% similarity]
test/recipes/15-test_ml_kem_codecs_data/ss-768.dat [moved from test/recipes/15-test_ml_kem_data/ss-768.dat with 100% similarity]

index ababed04a3ccc9aad84e6a9658e81763677ae134..a292d2b25de962aae4b44f2dfad23a21d00f5465 100644 (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
index 70576cfe8090d047e2ba8b23c94fc697ece4b2f6..ca690a53ca57d410c0cac3db08ab13a51e5da27a 100644 (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 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
 
index 4626618f683ca8fe3e42aaa7c1303a6fc26dd48f..9f46fed549539887eb35ce37b55f948e0121543b 100644 (file)
  * - 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)) {
index 53f258850d6542a1c341ad973fc5275459efb8c1..510dcdcd59b8ba47361b4b5ed812ec10bb8aed02 100644 (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;
index 0ec10f5ae6eac260aac93e7d3682a77c81513e2f..32072b2f8925af48a16e7bfbaf68a8e5809d02b4 100644 (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);
similarity index 99%
rename from test/recipes/15-test_ml_kem.t
rename to test/recipes/15-test_ml_kem_codecs.t
index 30e4b168871ba00e314655e82532611a34aaf315..096da4577210e0237dab3c3c75b8125c2e0dc1f5 100644 (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");
diff --git a/test/recipes/15-test_ml_kem_codecs_data/prv-1024-bare-priv.pem b/test/recipes/15-test_ml_kem_codecs_data/prv-1024-bare-priv.pem
new file mode 100644 (file)
index 0000000..dcc2256
--- /dev/null
@@ -0,0 +1,69 @@
+-----BEGIN PRIVATE KEY-----
+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
+KCkqKywtLi8wMTIzNDU2Nzg5Ojs8PT4/
+-----END PRIVATE KEY-----
diff --git a/test/recipes/15-test_ml_kem_codecs_data/prv-1024-bare-seed.pem b/test/recipes/15-test_ml_kem_codecs_data/prv-1024-bare-seed.pem
new file mode 100644 (file)
index 0000000..f1f9879
--- /dev/null
@@ -0,0 +1,4 @@
+-----BEGIN PRIVATE KEY-----
+MFICAQAwCwYJYIZIAWUDBAQDBEAAAQIDBAUGBwgJCgsMDQ4PEBESExQVFhcYGRob
+HB0eHyAhIiMkJSYnKCkqKywtLi8wMTIzNDU2Nzg5Ojs8PT4/
+-----END PRIVATE KEY-----
diff --git a/test/recipes/15-test_ml_kem_codecs_data/prv-512-bare-priv.pem b/test/recipes/15-test_ml_kem_codecs_data/prv-512-bare-priv.pem
new file mode 100644 (file)
index 0000000..124b97c
--- /dev/null
@@ -0,0 +1,37 @@
+-----BEGIN PRIVATE KEY-----
+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
+KCkqKywtLi8wMTIzNDU2Nzg5Ojs8PT4/
+-----END PRIVATE KEY-----
diff --git a/test/recipes/15-test_ml_kem_codecs_data/prv-512-bare-seed.pem b/test/recipes/15-test_ml_kem_codecs_data/prv-512-bare-seed.pem
new file mode 100644 (file)
index 0000000..4eaac3d
--- /dev/null
@@ -0,0 +1,4 @@
+-----BEGIN PRIVATE KEY-----
+MFICAQAwCwYJYIZIAWUDBAQBBEAAAQIDBAUGBwgJCgsMDQ4PEBESExQVFhcYGRob
+HB0eHyAhIiMkJSYnKCkqKywtLi8wMTIzNDU2Nzg5Ojs8PT4/
+-----END PRIVATE KEY-----
diff --git a/test/recipes/15-test_ml_kem_codecs_data/prv-768-bare-priv.pem b/test/recipes/15-test_ml_kem_codecs_data/prv-768-bare-priv.pem
new file mode 100644 (file)
index 0000000..b1a1c13
--- /dev/null
@@ -0,0 +1,53 @@
+-----BEGIN PRIVATE KEY-----
+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
+KCkqKywtLi8wMTIzNDU2Nzg5Ojs8PT4/
+-----END PRIVATE KEY-----
diff --git a/test/recipes/15-test_ml_kem_codecs_data/prv-768-bare-seed.pem b/test/recipes/15-test_ml_kem_codecs_data/prv-768-bare-seed.pem
new file mode 100644 (file)
index 0000000..84523bf
--- /dev/null
@@ -0,0 +1,4 @@
+-----BEGIN PRIVATE KEY-----
+MFICAQAwCwYJYIZIAWUDBAQCBEAAAQIDBAUGBwgJCgsMDQ4PEBESExQVFhcYGRob
+HB0eHyAhIiMkJSYnKCkqKywtLi8wMTIzNDU2Nzg5Ojs8PT4/
+-----END PRIVATE KEY-----