=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
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
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
=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 {
=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.
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
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:
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 \
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
* - 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:
* 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:
{ 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 },
};
/*-
{ 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 },
};
/*-
{ 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;
}
/*
* 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,
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,
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;
}
{
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;
{
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;
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. */
/* 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;
/* 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);
}
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);
}
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;
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,
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;
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;
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)) {
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;
/* 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);
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.
}
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
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)) {