And related cleanup.
Reviewed-by: Shane Lontis <shane.lontis@oracle.com>
Reviewed-by: Tim Hudson <tjh@openssl.org>
(Merged from https://github.com/openssl/openssl/pull/26789)
return key->seed;
}
-int ossl_ml_dsa_key_prefer_seed(const ML_DSA_KEY *key)
+int ossl_ml_dsa_key_get_prov_flags(const ML_DSA_KEY *key)
{
- return key->prefer_seed;
+ return key->prov_flags;
}
-int ossl_ml_dsa_key_retain_seed(const ML_DSA_KEY *key)
-{
- return key->retain_seed;
-}
-
-int ossl_ml_dsa_set_prekey(ML_DSA_KEY *key, int prefer_seed, int retain_seed,
+int ossl_ml_dsa_set_prekey(ML_DSA_KEY *key, int flags_set, int flags_clr,
const uint8_t *seed, size_t seed_len,
const uint8_t *sk, size_t sk_len)
{
if (seed != NULL
&& (key->seed = OPENSSL_memdup(seed, seed_len)) == NULL)
goto end;
- if (prefer_seed >= 0)
- key->prefer_seed = prefer_seed;
- if (retain_seed >= 0)
- key->retain_seed = retain_seed;
+ key->prov_flags |= flags_set;
+ key->prov_flags &= ~flags_clr;
ret = 1;
end:
if (ret != NULL) {
ret->libctx = libctx;
ret->params = params;
- ret->prefer_seed = 1;
- ret->retain_seed = 1;
+ ret->prov_flags = ML_DSA_KEY_PROV_FLAGS_DEFAULT;
ret->shake128_md = EVP_MD_fetch(libctx, "SHAKE-128", propq);
ret->shake256_md = EVP_MD_fetch(libctx, "SHAKE-256", propq);
if (ret->shake128_md == NULL || ret->shake256_md == NULL)
if (ret != NULL) {
ret->libctx = src->libctx;
ret->params = src->params;
- ret->retain_seed = src->retain_seed;
- ret->prefer_seed = src->prefer_seed;
+ ret->prov_flags = src->prov_flags;
if ((selection & OSSL_KEYMGMT_SELECT_KEYPAIR) != 0) {
if (src->pub_encoding != NULL) {
/* The public components are present if the private key is present */
&& ossl_ml_dsa_sk_encode(out);
err:
- if (out->seed != NULL && !out->retain_seed) {
+ if (out->seed != NULL && (out->prov_flags & ML_DSA_KEY_RETAIN_SEED) == 0) {
OPENSSL_clear_free(out->seed, ML_DSA_SEED_BYTES);
out->seed = NULL;
}
uint8_t *pub_encoding;
uint8_t *priv_encoding;
uint8_t *seed;
- int retain_seed;
- int prefer_seed;
+ int prov_flags;
/*
* t1 is the Polynomial encoding of the 10 MSB of each coefficient of the
/* Optionally save the |d| portion of the seed */
key->d = key->z + ML_KEM_RANDOM_BYTES;
- if (key->retain_seed) {
+ if (key->prov_flags & ML_KEM_KEY_RETAIN_SEED) {
memcpy(key->d, seed, ML_KEM_RANDOM_BYTES);
} else {
OPENSSL_cleanse(key->d, ML_KEM_RANDOM_BYTES);
return NULL;
}
-/*
- * The |retain_seed| parameter indicates whether the seed should be retained
- * once the key is generated.
- */
ML_KEM_KEY *ossl_ml_kem_key_new(OSSL_LIB_CTX *libctx, const char *properties,
int evp_type)
{
key->vinfo = vinfo;
key->libctx = libctx;
- key->prefer_seed = 1;
- key->retain_seed = 1;
+ key->prov_flags = ML_KEM_KEY_PROV_FLAGS_DEFAULT;
key->shake128_md = EVP_MD_fetch(libctx, "SHAKE128", properties);
key->shake256_md = EVP_MD_fetch(libctx, "SHAKE256", properties);
key->sha3_256_md = EVP_MD_fetch(libctx, "SHA3-256", properties);
=over 4
+=item C<ml-kem.import_pct_type> (B<OSSL_PKEY_PARAM_ML_KEM_IMPORT_PCT_TYPE>) <UTF8 string>
+
+When an B<ML-KEM> key is imported as an explict FIPS 203 B<dk> decapsulation
+key, rather than a seed, a pairwise consistency test (PCT) is optionally
+performed.
+By default, or when this parameter is set explicitly to C<random>, the PCT
+is performed with a random entropy value for the encapsulation step.
+Setting the parameter to C<fixed>, still runs the test, but the encapsulation
+entropy is a fixed 32 byte value.
+Specifying any other value of the parameter, e.g. C<none>, skips the test.
+
=item C<ml-kem.retain_seed> (B<OSSL_PKEY_PARAM_ML_KEM_RETAIN_SEED>) <UTF8 string>
When set to a string representing a false boolean value (see
# define MAX_ML_DSA_PUB_LEN ML_DSA_87_PUB_LEN
# define MAX_ML_DSA_SIG_LEN ML_DSA_87_SIG_LEN
+# define ML_DSA_KEY_PREFER_SEED (1 << 0)
+# define ML_DSA_KEY_RETAIN_SEED (1 << 1)
+/* Default provider flags */
+# define ML_DSA_KEY_PROV_FLAGS_DEFAULT \
+ (ML_DSA_KEY_PREFER_SEED | ML_DSA_KEY_RETAIN_SEED)
+
/*
* Refer to FIPS 204 Section 4 Parameter sets.
* Fields that are shared between all algorithms (such as q & d) have been omitted.
__owur const uint8_t *ossl_ml_dsa_key_get_priv(const ML_DSA_KEY *key);
__owur size_t ossl_ml_dsa_key_get_priv_len(const ML_DSA_KEY *key);
__owur const uint8_t *ossl_ml_dsa_key_get_seed(const ML_DSA_KEY *key);
-__owur int ossl_ml_dsa_key_prefer_seed(const ML_DSA_KEY *key);
-__owur int ossl_ml_dsa_key_retain_seed(const ML_DSA_KEY *key);
-int ossl_ml_dsa_set_prekey(ML_DSA_KEY *key, int prefer_seed, int retain_seed,
+__owur int ossl_ml_dsa_key_get_prov_flags(const ML_DSA_KEY *key);
+int ossl_ml_dsa_set_prekey(ML_DSA_KEY *key, int flags_set, int flags_clr,
const uint8_t *seed, size_t seed_len,
const uint8_t *sk, size_t sk_len);
__owur size_t ossl_ml_dsa_key_get_collision_strength_bits(const ML_DSA_KEY *key);
# define ML_KEM_1024_DV 5
# define ML_KEM_1024_SECBITS 256
+# define ML_KEM_KEY_RANDOM_PCT (1 << 0)
+# define ML_KEM_KEY_FIXED_PCT (1 << 1)
+# define ML_KEM_KEY_PREFER_SEED (1 << 2)
+# define ML_KEM_KEY_RETAIN_SEED (1 << 3)
+/* Mask to check whether PCT on import is enabled */
+# define ML_KEM_KEY_PCT_TYPE \
+ (ML_KEM_KEY_RANDOM_PCT | ML_KEM_KEY_FIXED_PCT)
+/* Default provider flags */
+# define ML_KEM_KEY_PROV_FLAGS_DEFAULT \
+ (ML_KEM_KEY_RANDOM_PCT | ML_KEM_KEY_PREFER_SEED | ML_KEM_KEY_RETAIN_SEED)
+
/*
* External variant-specific API
* -----------------------------
struct ossl_ml_kem_scalar_st *s; /* Private key secret vector */
uint8_t *z; /* Private key FO failure secret */
uint8_t *d; /* Private key seed */
- int prefer_seed; /* Given seed and key use seed? */
- int retain_seed; /* Retain the seed after keygen? */
+ int prov_flags; /* prefer/retain seed and PCT flags */
/*
* Fixed-size built-in buffer, which holds the |rho| and the public key
#include <openssl/x509.h>
#include <openssl/core_names.h>
#include "internal/encoder.h"
+#include "prov/ml_dsa.h"
#include "ml_dsa_codecs.h"
/*-
int evp_type, PROV_CTX *provctx,
const char *propq)
{
- OSSL_LIB_CTX *libctx = PROV_LIBCTX_OF(provctx);
const ML_DSA_PARAMS *v;
const ML_COMMON_CODEC *codec;
ML_COMMON_PKCS8_FMT_PREF *fmt_slots = NULL, *slot;
const uint8_t *buf, *pos;
const X509_ALGOR *alg = NULL;
const char *formats;
- int len, ptype, retain, prefer;
+ int len, ptype;
uint32_t magic;
uint16_t seed_magic;
const uint8_t *seed = NULL;
* Collect the seed and/or key into a "decoded" private key object,
* to be turned into a real key on provider "load" or "import".
*/
- if ((key = ossl_ml_dsa_key_new(libctx, propq, evp_type)) == NULL)
+ if ((key = ossl_prov_ml_dsa_new(provctx, propq, evp_type)) == NULL)
goto end;
if (p8fmt->seed_length > 0)
seed = buf + p8fmt->seed_offset;
priv = buf + p8fmt->priv_offset;
/* Any OQS public key content is ignored */
- /*
- * If the key ends up "loaded" into the same provider, these are the
- * correct config settings, otherwise, new values will be assigned on
- * import into a different provider. The "load" API does not pass along
- * the provider context.
- */
- retain =
- ossl_prov_ctx_get_bool_param(
- provctx, OSSL_PKEY_PARAM_ML_DSA_RETAIN_SEED, 1);
- prefer =
- ossl_prov_ctx_get_bool_param(
- provctx, OSSL_PKEY_PARAM_ML_DSA_PREFER_SEED, 1);
- if (ossl_ml_dsa_set_prekey(key, prefer, retain,
+ if (ossl_ml_dsa_set_prekey(key, 0, 0,
seed, ML_DSA_SEED_BYTES, priv, v->sk_len))
ret = key;
#include <openssl/x509.h>
#include <openssl/core_names.h>
#include "internal/encoder.h"
+#include "prov/ml_kem.h"
#include "ml_kem_codecs.h"
/* Tables describing supported ASN.1 input/output formats. */
int evp_type, PROV_CTX *provctx,
const char *propq)
{
- OSSL_LIB_CTX *libctx = PROV_LIBCTX_OF(provctx);
const ML_KEM_VINFO *v;
const ML_COMMON_CODEC *codec;
ML_COMMON_PKCS8_FMT_PREF *fmt_slots = NULL, *slot;
* Collect the seed and/or key into a "decoded" private key object,
* to be turned into a real key on provider "load" or "import".
*/
- if ((key = ossl_ml_kem_key_new(libctx, propq, evp_type)) == NULL)
+ if ((key = ossl_prov_ml_kem_new(provctx, propq, evp_type)) == NULL)
goto end;
- key->retain_seed = ossl_prov_ctx_get_bool_param(
- 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 (p8fmt->seed_length > 0) {
if (!ossl_ml_kem_set_seed(buf + p8fmt->seed_offset,
ML_KEM_SEED_BYTES, key)) {
--- /dev/null
+/*
+ * Copyright 2024 The OpenSSL Project Authors. All Rights Reserved.
+ *
+ * Licensed under the Apache License 2.0 (the "License"). You may not use
+ * this file except in compliance with the License. You can obtain a copy
+ * in the file LICENSE in the source distribution or at
+ * https://www.openssl.org/source/license.html
+ */
+
+#include "crypto/ml_dsa.h"
+#include "prov/provider_ctx.h"
+
+ML_DSA_KEY *
+ossl_prov_ml_dsa_new(PROV_CTX *provctx, const char *propq, int evp_type);
--- /dev/null
+/*
+ * Copyright 2024 The OpenSSL Project Authors. All Rights Reserved.
+ *
+ * Licensed under the Apache License 2.0 (the "License"). You may not use
+ * this file except in compliance with the License. You can obtain a copy
+ * in the file LICENSE in the source distribution or at
+ * https://www.openssl.org/source/license.html
+ */
+
+#include "crypto/ml_kem.h"
+#include "prov/provider_ctx.h"
+
+ML_KEM_KEY *
+ossl_prov_ml_kem_new(PROV_CTX *provctx, const char *propq, int evp_type);
#include "prov/implementations.h"
#include "prov/providercommon.h"
#include "prov/provider_ctx.h"
+#include "prov/ml_dsa.h"
static OSSL_FUNC_keymgmt_free_fn ml_dsa_free_key;
static OSSL_FUNC_keymgmt_has_fn ml_dsa_has;
}
#endif
-static void *ml_dsa_new_key(void *provctx, const char *propq,
- int evp_type)
+ML_DSA_KEY *ossl_prov_ml_dsa_new(PROV_CTX *ctx, const char *propq, int evp_type)
{
ML_DSA_KEY *key;
- int prefer, retain;
if (!ossl_prov_is_running())
return 0;
- key = ossl_ml_dsa_key_new(PROV_LIBCTX_OF(provctx), propq, evp_type);
+ key = ossl_ml_dsa_key_new(PROV_LIBCTX_OF(ctx), propq, evp_type);
+ /*
+ * When decoding, if the key ends up "loaded" into the same provider, these
+ * are the correct config settings, otherwise, new values will be assigned
+ * on import into a different provider. The "load" API does not pass along
+ * the provider context.
+ */
if (key != NULL) {
- prefer = ossl_prov_ctx_get_bool_param(
- provctx, OSSL_PKEY_PARAM_ML_DSA_PREFER_SEED, 1);
- retain = ossl_prov_ctx_get_bool_param(
- provctx, OSSL_PKEY_PARAM_ML_DSA_RETAIN_SEED, 1);
- ossl_ml_dsa_set_prekey(key, prefer, retain, NULL, 0, NULL, 0);
+ int flags_set = 0, flags_clr = 0;
+
+ if (ossl_prov_ctx_get_bool_param(
+ ctx, OSSL_PKEY_PARAM_ML_DSA_RETAIN_SEED, 1))
+ flags_set |= ML_DSA_KEY_RETAIN_SEED;
+ else
+ flags_clr = ML_DSA_KEY_RETAIN_SEED;
+
+ if (ossl_prov_ctx_get_bool_param(
+ ctx, OSSL_PKEY_PARAM_ML_DSA_PREFER_SEED, 1))
+ flags_set |= ML_DSA_KEY_PREFER_SEED;
+ else
+ flags_clr |= ML_DSA_KEY_PREFER_SEED;
+
+ ossl_ml_dsa_set_prekey(key, flags_set, flags_clr, NULL, 0, NULL, 0);
}
return key;
}
}
if (seed_len != 0
- && (sk_len == 0 || ossl_ml_dsa_key_prefer_seed(key))) {
- if (!ossl_ml_dsa_set_prekey(key, -1, -1, seed, seed_len, NULL, 0))
+ && (sk_len == 0
+ || (ossl_ml_dsa_key_get_prov_flags(key) & ML_DSA_KEY_PREFER_SEED))) {
+ if (!ossl_ml_dsa_set_prekey(key, 0, 0, seed, seed_len, NULL, 0))
return 0;
if (!ossl_ml_dsa_generate_key(key)) {
ERR_raise(ERR_LIB_PROV, PROV_R_FAILED_TO_GENERATE_KEY);
#ifndef FIPS_MODULE
static void *ml_dsa_load(const void *reference, size_t reference_sz)
{
- ML_DSA_KEY *ret = NULL, *key = NULL;
+ ML_DSA_KEY *key = NULL;
+ const ML_DSA_PARAMS *key_params;
const uint8_t *sk, *seed;
if (ossl_prov_is_running() && reference_sz == sizeof(key)) {
sk = ossl_ml_dsa_key_get_priv(key);
seed = ossl_ml_dsa_key_get_seed(key);
if (seed != NULL
- && (sk == NULL || ossl_ml_dsa_key_prefer_seed(key))) {
+ && (sk == NULL || (ossl_ml_dsa_key_get_prov_flags(key)
+ & ML_DSA_KEY_PREFER_SEED))) {
if (ossl_ml_dsa_generate_key(key))
- ret = key;
+ return key;
} else if (sk != NULL) {
if (ossl_ml_dsa_sk_decode(key, sk,
ossl_ml_dsa_key_get_priv_len(key)))
- ret = key;
+ return key;
+ key_params = ossl_ml_dsa_key_params(key);
+ ERR_raise_data(ERR_LIB_PROV, PROV_R_INVALID_KEY,
+ "error parsing %s private key",
+ key_params->alg);
+ } else {
+ return key;
}
}
- if (ret == NULL)
- ossl_ml_dsa_key_free(key);
- return ret;
+
+ ossl_ml_dsa_key_free(key);
+ return NULL;
}
#endif
if (!ossl_prov_is_running())
return NULL;
- key = ml_dsa_new_key(gctx->provctx, gctx->propq, evp_type);
+ key = ossl_prov_ml_dsa_new(gctx->provctx, gctx->propq, evp_type);
if (key == NULL)
return NULL;
if (gctx->entropy_len != 0
- && !ossl_ml_dsa_set_prekey(key, -1, -1,
+ && !ossl_ml_dsa_set_prekey(key, 0, 0,
gctx->entropy, gctx->entropy_len, NULL, 0))
goto err;
if (!ossl_ml_dsa_generate_key(key)) {
static OSSL_FUNC_keymgmt_gen_fn ml_dsa_##alg##_gen; \
static void *ml_dsa_##alg##_new_key(void *provctx) \
{ \
- return ml_dsa_new_key(provctx, NULL, EVP_PKEY_ML_DSA_##alg); \
+ return ossl_prov_ml_dsa_new(provctx, NULL, EVP_PKEY_ML_DSA_##alg); \
} \
static void *ml_dsa_##alg##_gen(void *genctx, OSSL_CALLBACK *osslcb, void *cbarg)\
{ \
#include <openssl/self_test.h>
#include <openssl/param_build.h>
#include "crypto/ml_kem.h"
+#include "internal/param_build_set.h"
#include "prov/implementations.h"
#include "prov/providercommon.h"
#include "prov/provider_ctx.h"
#include "prov/securitycheck.h"
-#include "internal/param_build_set.h"
+#include "prov/ml_kem.h"
static OSSL_FUNC_keymgmt_new_fn ml_kem_512_new;
static OSSL_FUNC_keymgmt_new_fn ml_kem_768_new;
uint8_t *seed;
} PROV_ML_KEM_GEN_CTX;
-static int ml_kem_pairwise_test(const ML_KEM_KEY *key)
+static int ml_kem_pairwise_test(const ML_KEM_KEY *key, int key_flags)
{
#ifdef FIPS_MODULE
OSSL_SELF_TEST *st = NULL;
OSSL_CALLBACK *cb = NULL;
void *cbarg = NULL;
- unsigned char entropy[ML_KEM_RANDOM_BYTES];
#endif
+ unsigned char entropy[ML_KEM_RANDOM_BYTES];
unsigned char secret[ML_KEM_SHARED_SECRET_BYTES];
unsigned char out[ML_KEM_SHARED_SECRET_BYTES];
unsigned char *ctext = NULL;
int ret = 0;
/* Unless we have both a public and private key, we can't do the test */
- if (!ossl_ml_kem_have_prvkey(key) || !ossl_ml_kem_have_pubkey(key))
+ if (!ossl_ml_kem_have_prvkey(key)
+ || !ossl_ml_kem_have_pubkey(key)
+ || (key_flags & ML_KEM_KEY_PCT_TYPE) == 0)
return 1;
-
#ifdef FIPS_MODULE
/*
* The functions `OSSL_SELF_TEST_*` will return directly if parameter `st`
goto err;
memset(out, 0, sizeof(out));
-#ifdef FIPS_MODULE
+
/*
- * The FIPS module does a PCT on power-on, and would leak the RNG
- * handle if use random entropy here. So we use fixed entropy in
- * the FIPS case. Ideally, the leak will be fixed, and the test
- * will also use random entropy in FIPS mode.
+ * The pairwise test is skipped unless either RANDOM or FIXED entropy PCTs
+ * are enabled.
*/
- memset(entropy, 0125, sizeof(entropy));
- operation_result = ossl_ml_kem_encap_seed(ctext, v->ctext_bytes,
- secret, sizeof(secret),
- entropy, sizeof(entropy),
- key);
-#else
- operation_result = ossl_ml_kem_encap_rand(ctext, v->ctext_bytes,
- secret, sizeof(secret), key);
-#endif
+ if (key_flags & ML_KEM_KEY_RANDOM_PCT) {
+ operation_result = ossl_ml_kem_encap_rand(ctext, v->ctext_bytes,
+ secret, sizeof(secret), key);
+ } else {
+ memset(entropy, 0125, sizeof(entropy));
+ operation_result = ossl_ml_kem_encap_seed(ctext, v->ctext_bytes,
+ secret, sizeof(secret),
+ entropy, sizeof(entropy),
+ key);
+ }
if (operation_result != 1)
goto err;
return ret;
}
-static void *ml_kem_new(PROV_CTX *ctx, const char *propq, int evp_type)
+ML_KEM_KEY *ossl_prov_ml_kem_new(PROV_CTX *ctx, const char *propq, int evp_type)
{
ML_KEM_KEY *key;
if (!ossl_prov_is_running())
return NULL;
+ /*
+ * When decoding, if the key ends up "loaded" into the same provider, these
+ * are the correct config settings, otherwise, new values will be assigned
+ * on import into a different provider. The "load" API does not pass along
+ * the provider context.
+ */
if ((key = ossl_ml_kem_key_new(PROV_LIBCTX_OF(ctx), propq, evp_type)) != NULL) {
- key->retain_seed = ossl_prov_ctx_get_bool_param(
- ctx, OSSL_PKEY_PARAM_ML_KEM_RETAIN_SEED, 1);
- key->prefer_seed = ossl_prov_ctx_get_bool_param(
- ctx, OSSL_PKEY_PARAM_ML_KEM_PREFER_SEED, 1);
+ const char *pct_type = ossl_prov_ctx_get_param(
+ ctx, OSSL_PKEY_PARAM_ML_KEM_IMPORT_PCT_TYPE, "random");
+
+ if (ossl_prov_ctx_get_bool_param(
+ ctx, OSSL_PKEY_PARAM_ML_KEM_RETAIN_SEED, 1))
+ key->prov_flags |= ML_KEM_KEY_RETAIN_SEED;
+ else
+ key->prov_flags &= ~ML_KEM_KEY_RETAIN_SEED;
+ if (ossl_prov_ctx_get_bool_param(
+ ctx, OSSL_PKEY_PARAM_ML_KEM_PREFER_SEED, 1))
+ key->prov_flags |= ML_KEM_KEY_PREFER_SEED;
+ else
+ key->prov_flags &= ~ML_KEM_KEY_PREFER_SEED;
+ if (OPENSSL_strcasecmp(pct_type, "random") == 0)
+ key->prov_flags |= ML_KEM_KEY_RANDOM_PCT;
+ else if (OPENSSL_strcasecmp(pct_type, "fixed") == 0)
+ key->prov_flags |= ML_KEM_KEY_FIXED_PCT;
+ else
+ key->prov_flags &= ~ML_KEM_KEY_PCT_TYPE;
}
return key;
}
return 0;
if ((selection & OSSL_KEYMGMT_SELECT_KEYPAIR) == OSSL_KEYMGMT_SELECT_KEYPAIR)
- return ml_kem_pairwise_test(key);
+ return ml_kem_pairwise_test(key, ML_KEM_KEY_RANDOM_PCT);
return 1;
}
}
}
- if (seedlen != 0 && (prvlen == 0 || key->prefer_seed)) {
+ if (seedlen != 0
+ && (prvlen == 0 || (key->prov_flags & ML_KEM_KEY_PREFER_SEED))) {
if (prvlen != 0 && !check_seed(seedenc, prvenc, key))
return 0;
if (!ossl_ml_kem_set_seed(seedenc, seedlen, key)
include_private = selection & OSSL_KEYMGMT_SELECT_PRIVATE_KEY ? 1 : 0;
res = ml_kem_key_fromdata(key, params, include_private);
- if (res > 0 && include_private && !ml_kem_pairwise_test(key)) {
+ if (res > 0 && include_private
+ && !ml_kem_pairwise_test(key, key->prov_flags)) {
#ifdef FIPS_MODULE
ossl_set_error_state(OSSL_SELF_TEST_TYPE_PCT);
#endif
&& !check_seed(seed, encoded_dk, key))
goto err;
/* Generate the key now, if it holds only a stashed seed. */
- if (ossl_ml_kem_have_seed(key) &&
- (encoded_dk == NULL || key->prefer_seed)) {
+ if (ossl_ml_kem_have_seed(key)
+ && (encoded_dk == NULL
+ || (key->prov_flags & ML_KEM_KEY_PREFER_SEED))) {
if (!ossl_ml_kem_genkey(NULL, 0, key)
|| (encoded_dk != NULL && !check_pkhash(encoded_dk, key)))
goto err;
key->vinfo->algorithm_name);
goto err;
}
- if (!ml_kem_pairwise_test(key))
+ if (!ml_kem_pairwise_test(key, key->prov_flags))
goto err;
}
OPENSSL_free(encoded_dk);
OSSL_KEYMGMT_SELECT_PUBLIC_KEY)
return NULL;
seed = gctx->seed;
- key = ml_kem_new(gctx->provctx, gctx->propq, gctx->evp_type);
+ key = ossl_prov_ml_kem_new(gctx->provctx, gctx->propq, gctx->evp_type);
if (key == NULL)
return NULL;
if (genok) {
#ifdef FIPS_MODULE
- if (!ml_kem_pairwise_test(key)) {
+ if (!ml_kem_pairwise_test(key, ML_KEM_KEY_FIXED_PCT)) {
ossl_set_error_state(OSSL_SELF_TEST_TYPE_PCT);
ossl_ml_kem_key_free(key);
return NULL;
#define DECLARE_VARIANT(bits) \
static void *ml_kem_##bits##_new(void *provctx) \
{ \
- return ml_kem_new(provctx, NULL, EVP_PKEY_ML_KEM_##bits); \
+ return ossl_prov_ml_kem_new(provctx, NULL, EVP_PKEY_ML_KEM_##bits); \
} \
static void *ml_kem_##bits##_gen_init(void *provctx, int selection, \
const OSSL_PARAM params[]) \
plan skip_all => "ML-KEM isn't supported in this build"
if disabled("ml-kem");
-plan tests => @algs * (24 + 10 * @formats);
+plan tests => @algs * (25 + 10 * @formats);
my $seed = join ("", map {sprintf "%02x", $_} (0..63));
my $weed = join ("", map {sprintf "%02x", $_} (1..64));
my $ikme = join ("", map {sprintf "%02x", $_} (0..31));
sprintf("text form private key: %s with %s", $alg, $f));
}
- # (5 tests): Test import/load PCT failure
+ # (6 tests): Test import/load PCT failure
my $real = sprintf('real-%s.der', $alg);
my $fake = sprintf('fake-%s.der', $alg);
my $mixt = sprintf('mixt-%s.der', $alg);
ok(run(app([qw(openssl genpkey -algorithm), "ml-kem-$alg",
qw(-provparam ml-kem.output_formats=seed-priv -pkeyopt),
"hexseed:$seed", qw(-outform DER -out), $real])),
- sprintf("create real private key: %s", $alg));
+ sprintf("create real private key: %s", $alg));
ok(run(app([qw(openssl genpkey -algorithm), "ml-kem-$alg",
qw(-provparam ml-kem.output_formats=seed-priv -pkeyopt),
"hexseed:$weed", qw(-outform DER -out), $fake])),
- sprintf("create fake private key: %s", $alg));
+ sprintf("create fake private key: %s", $alg));
my $realfh = IO::File->new($real, "r");
my $fakefh = IO::File->new($fake, "r");
local $/ = undef;
my $realder = <$realfh>;
my $fakeder = <$fakefh>;
- ok (length($realder) == 28 + (2 + 64) + (4 + $slen + $plen + $zlen)
+ #
+ # - 20 bytes PKCS8 fixed overhead,
+ # - 4 byte private key octet string tag + length
+ # - 4 byte seed + key sequence tag + length
+ # - 2 byte seed tag + length
+ # - 64 byte seed
+ # - 4 byte key tag + length
+ # - |dk| 's' vector
+ # - |ek| public key ('t' vector || 'rho')
+ # - implicit rejection 'z' seed component
+ #
+ ok(length($realder) == 28 + (2 + 64) + (4 + $slen + $plen + $zlen)
&& length($fakeder) == 28 + (2 + 64) + (4 + $slen + $plen + $zlen));
my $mixtder = substr($realder, 0, 28 + 66 + 4 + $slen)
. substr($fakeder, 28 + 66 + 4 + $slen, $plen)
. substr($realder, 28 + 66 + 4 + $slen + $plen, $zlen);
- my $mixtfh = IO::File->new($mixt, "w");
+ my $mixtfh = IO::File->new($mixt, ">:raw");
print $mixtfh $mixtder;
$mixtfh->close();
- ok(run(app([qw(openssl pkey -inform DER -noout -in), $real],
- sprintf("accept valid keypair: %s", $alg))));
+ ok(run(app([qw(openssl pkey -inform DER -noout -in), $real])),
+ sprintf("accept valid keypair: %s", $alg));
ok(!run(app([qw(openssl pkey -provparam ml-kem.prefer_seed=no),
qw(-inform DER -noout -in), $mixt])),
- sprintf("reject real private and fake public: %s", $alg));
+ sprintf("reject real private and fake public: %s", $alg));
+ ok(run(app([qw(openssl pkey -provparam ml-kem.prefer_seed=no),
+ qw(-provparam ml-kem.import_pct_type=none),
+ qw(-inform DER -noout -in), $mixt])),
+ sprintf("Absent PCT accept fake public: %s", $alg));
# Mutate the public key hash
my $mashder = $realder;
substr($mashder, -64, 1) =~ s{(.)}{chr(ord($1)^1)}es;
- my $mashfh = IO::File->new($mash, "w");
+ my $mashfh = IO::File->new($mash, ">:raw");
print $mashfh $mashder;
$mashfh->close();
ok(!run(app([qw(openssl pkey -inform DER -noout -in), $mash])),
- sprintf("reject real private and mutated public: %s", $alg));
+ sprintf("reject real private and mutated public: %s", $alg));
}
'PKEY_PARAM_ML_KEM_RETAIN_SEED' => "ml-kem.retain_seed",
'PKEY_PARAM_ML_KEM_INPUT_FORMATS' => "ml-kem.input_formats",
'PKEY_PARAM_ML_KEM_OUTPUT_FORMATS' => "ml-kem.output_formats",
+ 'PKEY_PARAM_ML_KEM_IMPORT_PCT_TYPE' => "ml-kem.import_pct_type",
# Key generation parameters
'PKEY_PARAM_FFC_TYPE' => "type",