#include "slh_dsa_local.h"
#include "slh_dsa_key.h"
+static int slh_dsa_compute_pk_root(SLH_DSA_CTX *ctx, SLH_DSA_KEY *out);
+
/**
* @brief Create a new SLH_DSA_KEY object
*
return;
REF_ASSERT_ISNT(i < 0);
+ OPENSSL_cleanse(&key->priv, sizeof(key->priv));
OPENSSL_free(key->propq);
CRYPTO_FREE_REF(&key->references);
OPENSSL_free(key);
return 0;
ok = (memcmp(key1->pub, key2->pub, key1->key_len) == 0);
}
+ if ((selection & OSSL_KEYMGMT_SELECT_PRIVATE_KEY) != 0) {
+ ok = ok && (key1->has_priv == key2->has_priv);
+ if (key1->has_priv)
+ ok = ok && (memcmp(key1->priv, key2->priv, key1->key_len) == 0);
+ }
return ok;
}
if ((selection & OSSL_KEYMGMT_SELECT_KEYPAIR) != 0) {
if (key->key_len == 0)
return 0;
+ if ((selection & OSSL_KEYMGMT_SELECT_PRIVATE_KEY) != 0
+ && key->has_priv == 0)
+ return 0;
return 1;
}
return 0;
}
-int ossl_slh_dsa_key_fromdata(SLH_DSA_KEY *key, const OSSL_PARAM params[])
+int ossl_slh_dsa_key_fromdata(SLH_DSA_KEY *key, const OSSL_PARAM params[],
+ int include_private)
{
size_t n, key_len, len = 0;
- const OSSL_PARAM *param_pub;
+ const OSSL_PARAM *param_priv = NULL, *param_pub, *param_pk_seed = NULL;
void *p;
+ SLH_DSA_CTX *dsa_ctx = NULL;
if (key == NULL)
return 0;
/* Both the public and private key are composed of 2 elements of size n */
key_len = 2 * n;
+ /* Private key is optional */
+ if (include_private) {
+ param_priv = OSSL_PARAM_locate_const(params, OSSL_PKEY_PARAM_PRIV_KEY);
+ if (param_priv == NULL)
+ return 0;
+ }
+
+ /*
+ * There must always be a public key, since the private key cannot exist
+ * without the public key elements.
+ * If there is only the public seed then the private key MUST be present in
+ * order to compute the pk_root element.
+ */
param_pub = OSSL_PARAM_locate_const(params, OSSL_PKEY_PARAM_PUB_KEY);
- if (param_pub == NULL)
- goto err;
- p = key->pub;
- if (!OSSL_PARAM_get_octet_string(param_pub, &p, key_len, &len))
- goto err;
- if (len != key_len)
- goto err;
+ if (param_pub == NULL) {
+ param_pk_seed = OSSL_PARAM_locate_const(params,
+ OSSL_PKEY_PARAM_SLH_DSA_PUB_SEED);
+ if (param_pk_seed == NULL || param_priv == NULL)
+ return 0;
+ }
+
+ if (param_pub != NULL) {
+ p = key->pub;
+ if (!OSSL_PARAM_get_octet_string(param_pub, &p, key_len, &len))
+ return 0;
+ if (len != key_len)
+ return 0;
+ }
+ if (param_priv != NULL) {
+ p = key->priv;
+ if (!OSSL_PARAM_get_octet_string(param_priv, &p, key_len, &len))
+ return 0;
+ /* This is assuming that the private component contains no public elements */
+ if (len != key_len)
+ goto err;
+ key->has_priv = 1;
+ }
+ if (param_pk_seed != NULL) {
+ /*
+ * In this case we need to generate the pk_root
+ * which requires both the private key element(s) and the public key seed.
+ */
+ p = SLH_DSA_PK_SEED(key);
+ if (!OSSL_PARAM_get_octet_string(param_pk_seed, &p, n, &len))
+ goto err;
+ if (len != n)
+ goto err;
+ /* Compute the pk_root element */
+ dsa_ctx = ossl_slh_dsa_ctx_new(key->params->alg, key->libctx, key->propq);
+ if (dsa_ctx == NULL
+ || !slh_dsa_compute_pk_root(dsa_ctx, key))
+ goto err;
+ ossl_slh_dsa_ctx_free(dsa_ctx);
+ }
key->key_len = key_len; /* This indicates the public key is present */
return 1;
err:
key->key_len = 0;
+ key->has_priv = 0;
+ return 0;
+}
+
+static int slh_dsa_compute_pk_root(SLH_DSA_CTX *ctx, SLH_DSA_KEY *out)
+{
+ SLH_ADRS_FUNC_DECLARE(ctx, adrsf);
+ SLH_ADRS_DECLARE(adrs);
+ const SLH_DSA_PARAMS *params = out->params;
+
+ assert(params != NULL);
+
+ adrsf->zero(adrs);
+ adrsf->set_layer_address(adrs, params->d - 1);
+ /* Generate the ROOT public key */
+ ossl_slh_xmss_node(ctx, SLH_DSA_SK_SEED(out), 0, params->hm,
+ SLH_DSA_PK_SEED(out), adrs, SLH_DSA_PK_ROOT(out));
+ return 1;
+}
+
+int ossl_slh_dsa_generate_key(SLH_DSA_CTX *ctx, OSSL_LIB_CTX *libctx,
+ SLH_DSA_KEY *out)
+{
+ size_t n = ctx->params->n;
+ size_t key_len = 2 * n;
+
+ assert(ctx->params == out->params);
+
+ if (RAND_priv_bytes_ex(libctx, out->priv, key_len, 0) <= 0
+ || RAND_bytes_ex(libctx, out->pub, n, 0) <= 0
+ || !slh_dsa_compute_pk_root(ctx, out))
+ goto err;
+ out->key_len = key_len;
+ out->has_priv = 1;
+ return 1;
+err:
+ out->has_priv = 0;
+ out->key_len = 0;
+ OPENSSL_cleanse(&out->priv, sizeof(out->priv));
return 0;
}
{
return (key->params == ctx->params);
}
+
+int ossl_slh_dsa_key_is_private(const SLH_DSA_KEY *key)
+{
+ return key->has_priv;
+}
+
+const uint8_t *ossl_slh_dsa_key_get_pub(const SLH_DSA_KEY *key)
+{
+ return key->pub;
+}
+
+const uint8_t *ossl_slh_dsa_key_get_priv(const SLH_DSA_KEY *key)
+{
+ return key->priv;
+}
+
+size_t ossl_slh_dsa_key_get_len(const SLH_DSA_KEY *key)
+{
+ return key->key_len;
+}
+
+size_t ossl_slh_dsa_key_get_n(const SLH_DSA_KEY *key)
+{
+ return key->params->n;
+}
#include "internal/refcount.h"
#define SLH_DSA_MAX_KEYLEN 32 * 2 /* 2 * n */
+#define SLH_DSA_SK_SEED(key) (key->priv)
+#define SLH_DSA_SK_PRF(key) (key->priv + key->params->n)
#define SLH_DSA_PK_SEED(key) (key->pub)
-#define SLH_DSA_PK_ROOT(key) (key->pub + key->params->n)
+#define SLH_DSA_PK_ROOT(key) (key->pub + key->params->n)
struct slh_dsa_key_st {
uint8_t pub[SLH_DSA_MAX_KEYLEN];
+ uint8_t priv[SLH_DSA_MAX_KEYLEN];
size_t key_len; /* This value is set to 2 * n if there is a public key */
CRYPTO_REF_COUNT references;
OSSL_LIB_CTX *libctx;
char *propq;
const SLH_DSA_PARAMS *params;
+ int has_priv;
};
SLH_HASH_CTX hash_ctx;
};
+void ossl_slh_wots_pk_gen(SLH_DSA_CTX *ctx,
+ const uint8_t *sk_seed, const uint8_t *pk_seed,
+ SLH_ADRS adrs, uint8_t *pk_out);
+
void ossl_slh_wots_pk_from_sig(SLH_DSA_CTX *ctx,
const uint8_t *sig, const uint8_t *msg,
const uint8_t *pk_seed, uint8_t *adrs,
uint8_t *pk_out);
+void ossl_slh_xmss_node(SLH_DSA_CTX *ctx, const uint8_t *sk_seed,
+ uint32_t node_id, uint32_t height,
+ const uint8_t *pk_seed, SLH_ADRS adrs, uint8_t *pk_out);
void ossl_slh_xmss_pk_from_sig(SLH_DSA_CTX *ctx, uint32_t node_id,
const uint8_t *sig, const uint8_t *msg,
const uint8_t *pk_seed, SLH_ADRS adrs,
}
}
+/**
+ * @brief WOTS+ Public key generation. See FIPS 205 Section 5.1
+ *
+ * @param ctx Contains SLH_DSA algorithm functions and constants.
+ * @param sk_seed A private key seed of size |n|
+ * @param pk_seed A public key seed of size |n|
+ * @param adrs An ADRS object containing the layer address, tree address and
+ * keypair address of the WOTS+ public key to generate.
+ * @param pk_out The generated public key of size |n|
+ */
+void ossl_slh_wots_pk_gen(SLH_DSA_CTX *ctx,
+ const uint8_t *sk_seed, const uint8_t *pk_seed,
+ SLH_ADRS adrs, uint8_t *pk_out)
+{
+ SLH_HASH_FUNC_DECLARE(ctx, hashf, hctx);
+ SLH_ADRS_FUNC_DECLARE(ctx, adrsf);
+ SLH_HASH_FN_DECLARE(hashf, PRF);
+ SLH_ADRS_FN_DECLARE(adrsf, set_chain_address);
+ SLH_ADRS_DECLARE(sk_adrs);
+ SLH_ADRS_DECLARE(wots_pk_adrs);
+ size_t i, len;
+ size_t n = ctx->params->n;
+ uint8_t tmp[SLH_WOTS_LEN_MAX * SLH_MAX_N], *ptmp = tmp;
+ uint8_t sk[32];
+
+ adrsf->copy(sk_adrs, adrs);
+ adrsf->set_type_and_clear(sk_adrs, SLH_ADRS_TYPE_WOTS_PRF);
+ adrsf->copy_keypair_address(sk_adrs, adrs);
+
+ len = SLH_WOTS_LEN(n); /* See Section 5 intro */
+ for (i = 0; i < len; ++i) {
+ set_chain_address(sk_adrs, i);
+ PRF(hctx, pk_seed, sk_seed, sk_adrs, sk);
+
+ set_chain_address(adrs, i);
+ slh_wots_chain(ctx, sk, 0, NIBBLE_MASK, pk_seed, adrs, ptmp);
+ ptmp += n;
+ }
+
+ len = ptmp - tmp; /* should be n * (2 * n + 3) */
+ adrsf->copy(wots_pk_adrs, adrs);
+ adrsf->set_type_and_clear(wots_pk_adrs, SLH_ADRS_TYPE_WOTS_PK);
+ adrsf->copy_keypair_address(wots_pk_adrs, adrs);
+ hashf->T(hctx, pk_seed, wots_pk_adrs, tmp, len, pk_out);
+}
+
/**
* @brief Compute a candidate WOTS+ public key from a message and signature
* See FIPS 205 Section 5.2 Algorithm 7
#include <string.h>
#include "slh_dsa_local.h"
+/**
+ * @brief Compute the root Public key of a XMSS tree.
+ * See FIPS 205 Section 6.1 Algorithm 9.
+ * This is a recursive function that starts at an leaf index, that calculates
+ * the hash of each parent using 2 child nodes.
+ *
+ * @param sk_seed A private key seed
+ * @param pk_seed A public key seed
+ * @param n The size of |sk_seed|, |pk_seed| and |pk_out|
+ * @param adrs An ADRS object containing the layer address and tree address set
+ * to the XMSS treewithing which the XMSS tree is being computed.
+ * @param nodeid The index of the target node being computed
+ * (which must be < 2^(hm - height)
+ * @param height The height within the tree of the node being computed.
+ * (which must be <= hm) (hm is one of 3, 4, 8 or 9)
+ * At height=0 There are 2^hm leaf nodes,
+ * and the root node is at height = hm)
+ * @param pk_out The generated public key of size |n|
+ */
+void ossl_slh_xmss_node(SLH_DSA_CTX *ctx,
+ const uint8_t *sk_seed,
+ uint32_t node_id,
+ uint32_t h,
+ const uint8_t *pk_seed,
+ SLH_ADRS adrs,
+ uint8_t *pk_out)
+{
+ SLH_ADRS_FUNC_DECLARE(ctx, adrsf);
+
+ if (h == 0) {
+ /* For leaf nodes generate the public key */
+ adrsf->set_type_and_clear(adrs, SLH_ADRS_TYPE_WOTS_HASH);
+ adrsf->set_keypair_address(adrs, node_id);
+ ossl_slh_wots_pk_gen(ctx, sk_seed, pk_seed, adrs, pk_out);
+ } else {
+ uint8_t lnode[SLH_MAX_N], rnode[SLH_MAX_N];
+
+ ossl_slh_xmss_node(ctx, sk_seed, 2 * node_id, h - 1, pk_seed, adrs,
+ lnode);
+ ossl_slh_xmss_node(ctx, sk_seed, 2 * node_id + 1, h - 1, pk_seed, adrs,
+ rnode);
+ adrsf->set_type_and_clear(adrs, SLH_ADRS_TYPE_TREE);
+ adrsf->set_tree_height(adrs, h);
+ adrsf->set_tree_index(adrs, node_id);
+ ctx->hash_func->H(&ctx->hash_ctx, pk_seed, adrs, lnode, rnode, pk_out);
+ }
+}
+
/**
* @brief Compute a candidate XMSS public key from a message and XMSS signature
*
int ossl_slh_dsa_key_equal(const SLH_DSA_KEY *key1, const SLH_DSA_KEY *key2,
int selection);
int ossl_slh_dsa_key_has(const SLH_DSA_KEY *key, int selection);
-int ossl_slh_dsa_key_fromdata(SLH_DSA_KEY *key, const OSSL_PARAM *params);
+int ossl_slh_dsa_key_fromdata(SLH_DSA_KEY *key, const OSSL_PARAM *params,
+ int include_private);
+int ossl_slh_dsa_generate_key(SLH_DSA_CTX *ctx, OSSL_LIB_CTX *libctx,
+ SLH_DSA_KEY *out);
+int ossl_slh_dsa_key_is_private(const SLH_DSA_KEY *key);
+const uint8_t *ossl_slh_dsa_key_get_pub(const SLH_DSA_KEY *key);
+const uint8_t *ossl_slh_dsa_key_get_priv(const SLH_DSA_KEY *key);
+size_t ossl_slh_dsa_key_get_len(const SLH_DSA_KEY *key);
+size_t ossl_slh_dsa_key_get_n(const SLH_DSA_KEY *key);
int ossl_slh_dsa_key_type_matches(SLH_DSA_CTX *ctx, const SLH_DSA_KEY *key);
static OSSL_FUNC_keymgmt_match_fn slh_dsa_match;
static OSSL_FUNC_keymgmt_import_fn slh_dsa_import;
static OSSL_FUNC_keymgmt_import_types_fn slh_dsa_imexport_types;
-
-#define SLH_DSA_POSSIBLE_SELECTIONS (OSSL_KEYMGMT_SELECT_PUBLIC_KEY)
+static OSSL_FUNC_keymgmt_get_params_fn slh_dsa_get_params;
+static OSSL_FUNC_keymgmt_gettable_params_fn slh_dsa_gettable_params;
+static OSSL_FUNC_keymgmt_gen_init_fn slh_dsa_gen_init;
+static OSSL_FUNC_keymgmt_gen_cleanup_fn slh_dsa_gen_cleanup;
+static OSSL_FUNC_keymgmt_gen_set_params_fn slh_dsa_gen_set_params;
+static OSSL_FUNC_keymgmt_gen_settable_params_fn slh_dsa_gen_settable_params;
+
+#define SLH_DSA_POSSIBLE_SELECTIONS (OSSL_KEYMGMT_SELECT_KEYPAIR)
+
+struct slh_dsa_gen_ctx {
+ OSSL_LIB_CTX *libctx;
+ char *propq;
+ SLH_DSA_CTX *ctx;
+};
static void *slh_dsa_new_key(void *provctx, const char *alg)
{
static int slh_dsa_import(void *keydata, int selection, const OSSL_PARAM params[])
{
SLH_DSA_KEY *key = keydata;
+ int include_priv;
if (!ossl_prov_is_running() || key == NULL)
return 0;
if ((selection & SLH_DSA_POSSIBLE_SELECTIONS) == 0)
return 0;
- return ossl_slh_dsa_key_fromdata(key, params);
+ include_priv = ((selection & OSSL_KEYMGMT_SELECT_PRIVATE_KEY) != 0);
+ return ossl_slh_dsa_key_fromdata(key, params, include_priv);
}
static const OSSL_PARAM slh_dsa_key_types[] = {
OSSL_PARAM_octet_string(OSSL_PKEY_PARAM_PUB_KEY, NULL, 0),
+ OSSL_PARAM_octet_string(OSSL_PKEY_PARAM_PRIV_KEY, NULL, 0),
OSSL_PARAM_END
};
return slh_dsa_key_types;
}
+static const OSSL_PARAM *slh_dsa_gettable_params(void *provctx)
+{
+ return slh_dsa_key_types;
+}
+
+static int key_to_params(SLH_DSA_KEY *key, OSSL_PARAM_BLD *tmpl,
+ OSSL_PARAM params[], int include_private)
+{
+ if (key == NULL)
+ return 0;
+
+ if (!ossl_param_build_set_octet_string(tmpl, params,
+ OSSL_PKEY_PARAM_PUB_KEY,
+ ossl_slh_dsa_key_get_pub(key),
+ ossl_slh_dsa_key_get_len(key)))
+ return 0;
+
+ if (include_private
+ && ossl_slh_dsa_key_is_private(key)
+ && !ossl_param_build_set_octet_string(tmpl, params,
+ OSSL_PKEY_PARAM_PRIV_KEY,
+ ossl_slh_dsa_key_get_priv(key),
+ ossl_slh_dsa_key_get_len(key)))
+ return 0;
+
+ return 1;
+}
+
+static int slh_dsa_get_params(void *keydata, OSSL_PARAM params[])
+{
+ SLH_DSA_KEY *key = keydata;
+
+ return key_to_params(key, NULL, params, 1);
+}
+
+static void *slh_dsa_gen_init(void *provctx, int selection,
+ const OSSL_PARAM params[])
+{
+ OSSL_LIB_CTX *libctx = PROV_LIBCTX_OF(provctx);
+ struct slh_dsa_gen_ctx *gctx = NULL;
+
+ if (!ossl_prov_is_running())
+ return NULL;
+
+ if ((gctx = OPENSSL_zalloc(sizeof(*gctx))) != NULL) {
+ gctx->libctx = libctx;
+ if (!slh_dsa_gen_set_params(gctx, params)) {
+ OPENSSL_free(gctx);
+ gctx = NULL;
+ }
+ }
+ return gctx;
+}
+
+static void *slh_dsa_gen(void *genctx, const char *alg)
+{
+ struct slh_dsa_gen_ctx *gctx = genctx;
+ SLH_DSA_KEY *key = NULL;
+ SLH_DSA_CTX *ctx = NULL;
+
+ if (!ossl_prov_is_running())
+ return NULL;
+ ctx = ossl_slh_dsa_ctx_new(alg, gctx->libctx, gctx->propq);
+ if (ctx == NULL)
+ return NULL;
+ key = ossl_slh_dsa_key_new(gctx->libctx, alg);
+ if (key == NULL)
+ return NULL;
+ if (!ossl_slh_dsa_generate_key(ctx, gctx->libctx, key))
+ goto err;
+ ossl_slh_dsa_ctx_free(ctx);
+ return key;
+ err:
+ ossl_slh_dsa_ctx_free(ctx);
+ ossl_slh_dsa_key_free(key);
+ return NULL;
+}
+
+static int slh_dsa_gen_set_params(void *genctx, const OSSL_PARAM params[])
+{
+ struct slh_dsa_gen_ctx *gctx = genctx;
+ const OSSL_PARAM *p;
+
+ if (gctx == NULL)
+ return 0;
+
+ p = OSSL_PARAM_locate_const(params, OSSL_SIGNATURE_PARAM_PROPERTIES);
+ if (p != NULL) {
+ if (p->data_type != OSSL_PARAM_UTF8_STRING)
+ return 0;
+ OPENSSL_free(gctx->propq);
+ gctx->propq = OPENSSL_strdup(p->data);
+ if (gctx->propq == NULL)
+ return 0;
+ }
+ return 1;
+}
+
+static const OSSL_PARAM *slh_dsa_gen_settable_params(ossl_unused void *genctx,
+ ossl_unused void *provctx)
+{
+ static OSSL_PARAM settable[] = {
+ OSSL_PARAM_utf8_string(OSSL_KDF_PARAM_PROPERTIES, NULL, 0),
+ OSSL_PARAM_END
+ };
+ return settable;
+}
+
+static void slh_dsa_gen_cleanup(void *genctx)
+{
+ struct slh_dsa_gen_ctx *gctx = genctx;
+
+ OPENSSL_free(gctx->propq);
+ OPENSSL_free(gctx);
+}
+
#define MAKE_KEYMGMT_FUNCTIONS(alg, fn) \
static OSSL_FUNC_keymgmt_new_fn slh_dsa_##fn##_new_key; \
static void *slh_dsa_##fn##_new_key(void *provctx) \
{ \
return slh_dsa_new_key(provctx, alg); \
} \
+static void *slh_dsa_##fn##_gen(void *genctx, OSSL_CALLBACK *osslcb, void *cbarg)\
+{ \
+ return slh_dsa_gen(genctx, alg); \
+} \
const OSSL_DISPATCH ossl_slh_dsa_##fn##_keymgmt_functions[] = { \
{ OSSL_FUNC_KEYMGMT_NEW, (void (*)(void))slh_dsa_##fn##_new_key }, \
{ OSSL_FUNC_KEYMGMT_FREE, (void (*)(void))slh_dsa_free_key }, \
{ OSSL_FUNC_KEYMGMT_MATCH, (void (*)(void))slh_dsa_match }, \
{ OSSL_FUNC_KEYMGMT_IMPORT, (void (*)(void))slh_dsa_import }, \
{ OSSL_FUNC_KEYMGMT_IMPORT_TYPES, (void (*)(void))slh_dsa_imexport_types },\
+ { OSSL_FUNC_KEYMGMT_GET_PARAMS, (void (*) (void))slh_dsa_get_params }, \
+ { OSSL_FUNC_KEYMGMT_GETTABLE_PARAMS, (void (*) (void))slh_dsa_gettable_params }, \
+ { OSSL_FUNC_KEYMGMT_GEN_INIT, (void (*)(void))slh_dsa_gen_init }, \
+ { OSSL_FUNC_KEYMGMT_GEN, (void (*)(void))slh_dsa_##fn##_gen }, \
+ { OSSL_FUNC_KEYMGMT_GEN_CLEANUP, (void (*)(void))slh_dsa_gen_cleanup }, \
+ { OSSL_FUNC_KEYMGMT_GEN_SET_PARAMS, \
+ (void (*)(void))slh_dsa_gen_set_params }, \
+ { OSSL_FUNC_KEYMGMT_GEN_SETTABLE_PARAMS, \
+ (void (*)(void))slh_dsa_gen_settable_params }, \
OSSL_DISPATCH_END \
}
* https://www.openssl.org/source/license.html
*/
-typedef struct SLH_DSA_ACVP_TEST_DATA_st {
+typedef struct slh_dsa_sig_test_data_st {
const char *alg;
const unsigned char *pub;
size_t pub_len;
size_t msg_len;
const unsigned char *sig;
size_t sig_len;
-} SLH_DSA_ACVP_TEST_DATA;
+} SLH_DSA_SIG_TEST_DATA;
-#define SLH_DSA_ACVP_ITEM(name, alg) { \
+typedef struct slh_dsa_keygen_test_data_st {
+ const char *name;
+ const uint8_t *priv;
+ size_t priv_len;
+ const uint8_t *pub_seed;
+ size_t pub_seed_len;
+ const uint8_t *pub_expected;
+ size_t pub_expected_len;
+} SLH_DSA_KEYGEN_TEST_DATA;
+
+#define SLH_DSA_SIG_TEST_ITEM(name, alg) { \
alg, \
name##_pub, sizeof(name##_pub), \
name##_priv, sizeof(name##_priv), \
name##_msg, sizeof(name##_msg), \
name##_sig, sizeof(name##_sig) }
+#define SLH_DSA_KEYGEN_TEST_ITEM(name, alg) { \
+ alg, \
+ name##_keygen_priv, sizeof(name##_keygen_priv), \
+ name##_keygen_pub_seed, sizeof(name##_keygen_pub_seed), \
+ name##_keygen_pub_expected, sizeof(name##_keygen_pub_expected) \
+}
+
/*
* Test vectors from
* usnistgov/ACVP-Server/refs/heads/master/gen-val/json-files/SLH-DSA-sigGen-FIPS205/internalProjection.json
0xe0,0xd7,0x42,0x24,0xb6,0xfe,0xd7,0x6e,0xa8,0x3a,0x09,0x52,0x8f,0xb2,0x88,0xab,0x2a,0x88,0x67,0xdd,0x0a,0x9e,0x80,0x10,0x27,0x4b,0x21,0x09,0xa5,0x31,0x23,0x8e,0x34,0x51,0x23,0xc8,0xe0,0xd8,0xfd,0x4d,0x46,0xbf,0xc8,0x88,0xe4,0xd9,0x50,0xac,
};
-static SLH_DSA_ACVP_TEST_DATA slh_dsa_testdata[] = {
- SLH_DSA_ACVP_ITEM(slh_dsa_sha2_128s_0, "SLH-DSA-SHA2-128s"),
+static SLH_DSA_SIG_TEST_DATA slh_dsa_sig_testdata[] = {
+ SLH_DSA_SIG_TEST_ITEM(slh_dsa_sha2_128s_0, "SLH-DSA-SHA2-128s"),
+};
+
+
+/* skSeed || skPrf */
+static const uint8_t slh_dsa_sha2_128s_0_keygen_priv[] = {
+ 0x2F, 0x89, 0x6D, 0x61, 0xD9, 0xCD, 0x90, 0x38,
+ 0xCA, 0x30, 0x33, 0x94, 0xFA, 0xDA, 0xA2, 0x2A,
+ 0x24, 0xAC, 0x5E, 0xC1, 0xD8, 0x6A, 0x98, 0x9C,
+ 0xA2, 0x19, 0x6C, 0x3C, 0x86, 0x32, 0x41, 0x9C,
+};
+/* pkSeed */
+static const uint8_t slh_dsa_sha2_128s_0_keygen_pub_seed[] = {
+ 0x1A, 0x05, 0xA4, 0x2F, 0xE3, 0x00, 0xE8, 0x7B,
+ 0x16, 0xAE, 0xE1, 0x16, 0xCB, 0x2E, 0x23, 0x63,
+};
+/* pkSeed || pkRoot */
+static const uint8_t slh_dsa_sha2_128s_0_keygen_pub_expected[] = {
+ 0x1A, 0x05, 0xA4, 0x2F, 0xE3, 0x00, 0xE8, 0x7B,
+ 0x16, 0xAE, 0xE1, 0x16, 0xCB, 0x2E, 0x23, 0x63,
+ 0x58, 0xE2, 0xC3, 0xE6, 0x26, 0x32, 0xC9, 0xDE,
+ 0x03, 0xD0, 0x8A, 0x53, 0x5A, 0x0E, 0xB7, 0xE7,
+};
+
+static const SLH_DSA_KEYGEN_TEST_DATA slh_dsa_keygen_testdata[] = {
+ SLH_DSA_KEYGEN_TEST_ITEM(slh_dsa_sha2_128s_0, "SLH-DSA-SHA2-128s"),
};
#include <openssl/core_names.h>
#include <openssl/evp.h>
+#include <openssl/param_build.h>
+#include <openssl/rand.h>
#include "crypto/slh_dsa.h"
#include "internal/nelem.h"
#include "testutil.h"
#include "slh_dsa.inc"
static OSSL_LIB_CTX *libctx = NULL;
+static OSSL_PROVIDER *fake_rand = NULL;
+
+static size_t entropy_pos = 0;
+static size_t entropy_sz = 0;
+static uint8_t entropy[128];
+
+static int set_entropy(const uint8_t *ent1, size_t ent1_len,
+ const uint8_t *ent2, size_t ent2_len)
+{
+ if ((ent1_len + ent2_len) > sizeof(entropy))
+ return 0;
+ entropy_pos = 0;
+ entropy_sz += (ent1_len + ent2_len);
+ memcpy(entropy, ent1, ent1_len);
+ if (ent2 != NULL)
+ memcpy(entropy + ent1_len, ent2, ent2_len);
+ return 1;
+}
+
+static int fake_rand_cb(unsigned char *buf, size_t num,
+ ossl_unused const char *name, EVP_RAND_CTX *ctx)
+{
+ if ((entropy_pos + num) > entropy_sz)
+ return 0;
+ memcpy(buf, entropy + entropy_pos, num);
+ entropy_pos += num;
+ return 1;
+}
static EVP_PKEY *slh_dsa_pubkey_from_data(const char *alg,
const unsigned char *data, size_t datalen)
return key;
}
+static int slh_dsa_create_keypair(EVP_PKEY **pkey, const char *name,
+ const uint8_t *priv, size_t priv_len,
+ const uint8_t *pub, size_t pub_len)
+{
+ int ret = 0;
+ EVP_PKEY_CTX *ctx = NULL;
+ OSSL_PARAM_BLD *bld = NULL;
+ OSSL_PARAM *params = NULL;
+ const char *pub_name = OSSL_PKEY_PARAM_PUB_KEY;
+
+ if (pub_len != priv_len)
+ pub_name = OSSL_PKEY_PARAM_SLH_DSA_PUB_SEED;
+
+ if (!TEST_ptr(bld = OSSL_PARAM_BLD_new())
+ || !TEST_true(OSSL_PARAM_BLD_push_octet_string(bld,
+ OSSL_PKEY_PARAM_PRIV_KEY,
+ priv, priv_len) > 0)
+ || !TEST_true(OSSL_PARAM_BLD_push_octet_string(bld,
+ pub_name,
+ pub, pub_len) > 0)
+ || !TEST_ptr(params = OSSL_PARAM_BLD_to_param(bld))
+ || !TEST_ptr(ctx = EVP_PKEY_CTX_new_from_name(libctx, name, NULL))
+ || !TEST_int_eq(EVP_PKEY_fromdata_init(ctx), 1)
+ || !TEST_int_eq(EVP_PKEY_fromdata(ctx, pkey, EVP_PKEY_KEYPAIR,
+ params), 1))
+ goto err;
+
+ ret = 1;
+err:
+ OSSL_PARAM_free(params);
+ OSSL_PARAM_BLD_free(bld);
+ EVP_PKEY_CTX_free(ctx);
+ return ret;
+}
+
static int slh_dsa_bad_pub_len_test(void)
{
int ret = 0;
- SLH_DSA_ACVP_TEST_DATA *td = &slh_dsa_testdata[0];
+ SLH_DSA_SIG_TEST_DATA *td = &slh_dsa_sig_testdata[0];
EVP_PKEY *pkey = NULL;
size_t pub_len = 0;
unsigned char pubdata[64 + 1];
{
int ret = 0;
EVP_PKEY *key[2] = { NULL, NULL };
- SLH_DSA_ACVP_TEST_DATA *td1 = &slh_dsa_testdata[0];
+ SLH_DSA_SIG_TEST_DATA *td1 = &slh_dsa_sig_testdata[0];
#ifndef OPENSSL_NO_EC
EVP_PKEY *eckey = NULL;
#endif
static int slh_dsa_key_validate_test(void)
{
int ret = 0;
- SLH_DSA_ACVP_TEST_DATA *td = &slh_dsa_testdata[0];
+ SLH_DSA_SIG_TEST_DATA *td = &slh_dsa_sig_testdata[0];
EVP_PKEY_CTX *vctx = NULL;
EVP_PKEY *key = NULL;
static int slh_dsa_sig_verify_test(void)
{
int ret = 0;
- SLH_DSA_ACVP_TEST_DATA *td = &slh_dsa_testdata[0];
+ SLH_DSA_SIG_TEST_DATA *td = &slh_dsa_sig_testdata[0];
EVP_PKEY_CTX *vctx = NULL;
EVP_PKEY *key = NULL;
EVP_SIGNATURE *sig_alg = NULL;
return ret;
}
+static int slh_dsa_keygen_test(void)
+{
+ int ret = 0;
+ const SLH_DSA_KEYGEN_TEST_DATA *tst = &slh_dsa_keygen_testdata[0];
+ EVP_PKEY *pkey = NULL;
+ uint8_t priv[32 * 2], pub[32 * 2];
+ size_t priv_len, pub_len;
+
+ if (!TEST_true(set_entropy(tst->priv, tst->priv_len,
+ tst->pub_seed, tst->pub_seed_len)))
+ goto err;
+
+ fake_rand_set_callback(RAND_get0_private(NULL), &fake_rand_cb);
+ fake_rand_set_callback(RAND_get0_public(NULL), &fake_rand_cb);
+
+ if (!TEST_ptr(pkey = EVP_PKEY_Q_keygen(libctx, NULL, tst->name)))
+ goto err;
+ if (!TEST_true(EVP_PKEY_get_octet_string_param(pkey, OSSL_PKEY_PARAM_PRIV_KEY,
+ priv, sizeof(priv), &priv_len)))
+ goto err;
+ if (!TEST_true(EVP_PKEY_get_octet_string_param(pkey, OSSL_PKEY_PARAM_PUB_KEY,
+ pub, sizeof(pub), &pub_len)))
+ goto err;
+ if (!TEST_size_t_eq(priv_len, tst->priv_len)
+ || !TEST_size_t_eq(pub_len, tst->priv_len))
+ goto err;
+ ret = 1;
+err:
+ fake_rand_set_callback(RAND_get0_public(NULL), NULL);
+ fake_rand_set_callback(RAND_get0_private(NULL), NULL);
+ EVP_PKEY_free(pkey);
+ return ret;
+}
+
+/*
+ * Given raw values for the private key + public key seed
+ * generate the public root also when using from data.
+ */
+static int slh_dsa_pub_root_from_data_test(void)
+{
+ int ret = 0;
+ uint8_t priv[64], pub[64];
+ size_t priv_len = 0, pub_len = 0;
+ EVP_PKEY *pkey = NULL;
+ const SLH_DSA_KEYGEN_TEST_DATA *tst = &slh_dsa_keygen_testdata[0];
+
+ if (!slh_dsa_create_keypair(&pkey, tst->name, tst->priv, tst->priv_len,
+ tst->pub_seed, tst->pub_seed_len))
+ goto err;
+
+ if (!TEST_true(EVP_PKEY_get_octet_string_param(pkey, OSSL_PKEY_PARAM_PRIV_KEY,
+ priv, sizeof(priv), &priv_len)))
+ goto err;
+ if (!TEST_true(EVP_PKEY_get_octet_string_param(pkey, OSSL_PKEY_PARAM_PUB_KEY,
+ pub, sizeof(pub), &pub_len)))
+ goto err;
+ if (!TEST_mem_eq(pub, pub_len, tst->pub_expected, tst->pub_expected_len))
+ goto err;
+ ret = 1;
+err:
+ OPENSSL_cleanse(priv, priv_len);
+ EVP_PKEY_free(pkey);
+ return ret;
+}
+
int setup_tests(void)
{
+ fake_rand = fake_rand_start(NULL);
+ if (fake_rand == NULL)
+ return 0;
+
ADD_TEST(slh_dsa_bad_pub_len_test);
ADD_TEST(slh_dsa_key_validate_test);
ADD_TEST(slh_dsa_key_eq_test);
ADD_TEST(slh_dsa_sig_verify_test);
+ ADD_TEST(slh_dsa_keygen_test);
+ ADD_TEST(slh_dsa_pub_root_from_data_test);
return 1;
}
+
+void cleanup_tests(void)
+{
+ fake_rand_finish(fake_rand);
+}
'PKEY_PARAM_ML_DSA_PREFER_SEED' => "ml-dsa.prefer_seed",
'PKEY_PARAM_ML_DSA_INPUT_FORMATS' => "ml-dsa.input_formats",
'PKEY_PARAM_ML_DSA_OUTPUT_FORMATS' => "ml-dsa.output_formats",
+# SLH_DSA parameters
+ 'PKEY_PARAM_SLH_DSA_PUB_SEED' => "pk-seed",
# Key Exchange parameters
'EXCHANGE_PARAM_PAD' => "pad",# uint