SLH-DSA cleanups

Addressed some review comments.
- Ref counting has been removed from SLH_DSA_KEY (EVP_PKEY is responsible
for the keys ref counting).
- Moved constants and prefetched objects into SLH_DSA_KEY.
- The SLH_DSA_HASH_CTX is still required since there are multiple
  contexts that need to propagate to a lot of functions, but it no
  longer contains the constants. Note that it also holds a pointer to
  the SLH_DSA_KEY.

Reviewed-by: Paul Dale <ppzgs1@gmail.com>
Reviewed-by: Viktor Dukhovni <viktor@openssl.org>
Reviewed-by: Tim Hudson <tjh@openssl.org>
(Merged from https://github.com/openssl/openssl/pull/25882)
This commit is contained in:
slontis 2025-01-23 08:20:58 +11:00 committed by Tomas Mraz
parent eba0e11c39
commit 79e7c83711
25 changed files with 554 additions and 507 deletions

View File

@ -987,7 +987,7 @@ See [Notes on shared libraries](#notes-on-shared-libraries) below.
### no-slh-dsa
Disable Stateless Hash Based Digital Signature Standard support.
(SLH-DSA is based on SPHINCS+. See NIST.FIPS.205)
(SLH-DSA is based on SPHINCS+. See [FIPS 205])
### no-sm2-precomp
@ -2061,5 +2061,5 @@ is used, as it is the version of the GNU assembler that will be checked.
[SP 800-90B]:
<https://csrc.nist.gov/pubs/sp/800/90/b/final>
[jitterentropy-library]:
<https://github.com/smuellerDD/jitterentropy-library>
[FIPS 205]:
<https://csrc.nist.gov/pubs/fips/205/final>

View File

@ -949,7 +949,7 @@ SLH_DSA_KEY *ossl_evp_pkey_get1_SLH_DSA_KEY(EVP_PKEY *pkey)
{
SLH_DSA_KEY *ret = (SLH_DSA_KEY *)evp_pkey_get_legacy(pkey);
if (ret != NULL && !ossl_slh_dsa_key_up_ref(ret))
if (ret != NULL)
ret = NULL;
return ret;
}

View File

@ -1,6 +1,6 @@
LIBS=../../libcrypto
$COMMON=slh_adrs.c slh_dsa.c slh_dsa_ctx.c slh_dsa_key.c slh_fors.c slh_hash.c \
$COMMON=slh_adrs.c slh_dsa.c slh_dsa_hash_ctx.c slh_dsa_key.c slh_fors.c slh_hash.c \
slh_hypertree.c slh_params.c slh_wots.c slh_xmss.c
IF[{- !$disabled{'slh_dsa'} -}]

View File

@ -28,8 +28,8 @@ static int get_tree_ids(PACKET *pkt, const SLH_DSA_PARAMS *params,
* [k]*[1+a][n] FORS signature bytes
* [h + d*len][n] Hyper tree signature bytes
*
* @param ctx Contains SLH_DSA algorithm functions and constants.
* @param priv The private SLH_DSA key to use for signing.
* @param ctx Contains SLH_DSA algorithm functions and constants, and the
* private SLH_DSA key to use for signing.
* @param msg The message to sign. This may be encoded beforehand.
* @param msg_len The size of |msg|
* @param sig The returned signature
@ -38,13 +38,14 @@ static int get_tree_ids(PACKET *pkt, const SLH_DSA_PARAMS *params,
* @param opt_rand An optional random value to use of size |n|. It can be NULL.
* @returns 1 if the signature generation succeeded or 0 otherwise.
*/
static int slh_sign_internal(SLH_DSA_CTX *ctx, const SLH_DSA_KEY *priv,
static int slh_sign_internal(SLH_DSA_HASH_CTX *hctx,
const uint8_t *msg, size_t msg_len,
uint8_t *sig, size_t *sig_len, size_t sig_size,
const uint8_t *opt_rand)
{
int ret = 0;
const SLH_DSA_PARAMS *params = ctx->params;
const SLH_DSA_KEY *priv = hctx->key;
const SLH_DSA_PARAMS *params = priv->params;
size_t sig_len_expected = params->sig_len;
uint8_t m_digest[SLH_MAX_M];
const uint8_t *md; /* The first md_len bytes of m_digest */
@ -59,8 +60,8 @@ static int slh_sign_internal(SLH_DSA_CTX *ctx, const SLH_DSA_KEY *priv,
uint32_t leaf_id;
SLH_ADRS_DECLARE(adrs);
SLH_HASH_FUNC_DECLARE(ctx, hashf, hctx);
SLH_ADRS_FUNC_DECLARE(ctx, adrsf);
SLH_HASH_FUNC_DECLARE(priv, hashf);
SLH_ADRS_FUNC_DECLARE(priv, adrsf);
if (sig_len != NULL)
*sig_len = sig_len_expected;
@ -104,14 +105,14 @@ static int slh_sign_internal(SLH_DSA_CTX *ctx, const SLH_DSA_KEY *priv,
sig_fors = WPACKET_get_curr(wpkt);
/* generate the FORS signature and append it to the SLH-DSA signature */
ret = ossl_slh_fors_sign(ctx, md, sk_seed, pk_seed, adrs, wpkt)
ret = ossl_slh_fors_sign(hctx, md, sk_seed, pk_seed, adrs, wpkt)
/* Reuse rpkt to point to the FORS signature that was just generated */
&& PACKET_buf_init(rpkt, sig_fors, WPACKET_get_curr(wpkt) - sig_fors)
/* Calculate the FORS public key using the generated FORS signature */
&& ossl_slh_fors_pk_from_sig(ctx, rpkt, md, pk_seed, adrs,
&& ossl_slh_fors_pk_from_sig(hctx, rpkt, md, pk_seed, adrs,
pk_fors, sizeof(pk_fors))
/* Generate ht signature and append to the SLH-DSA signature */
&& ossl_slh_ht_sign(ctx, pk_fors, sk_seed, pk_seed, tree_id, leaf_id,
&& ossl_slh_ht_sign(hctx, pk_fors, sk_seed, pk_seed, tree_id, leaf_id,
wpkt);
ret = 1;
err:
@ -129,22 +130,23 @@ static int slh_sign_internal(SLH_DSA_CTX *ctx, const SLH_DSA_KEY *priv,
* [k]*[1+a][n] FORS signature bytes
* [h + d*len][n] Hyper tree signature bytes
*
* @param ctx Contains SLH_DSA algorithm functions and constants.
* @param pub The public SLH_DSA key to use for verification.
* @param hctx Contains SLH_DSA algorithm functions and constants and the
* public SLH_DSA key to use for verification.
* @param msg The message to verify. This may be encoded beforehand.
* @param msg_len The size of |msg|
* @param sig A signature to verify
* @param sig_len The size of |sig|
* @returns 1 if the signature verification succeeded or 0 otherwise.
*/
static int slh_verify_internal(SLH_DSA_CTX *ctx, const SLH_DSA_KEY *pub,
static int slh_verify_internal(SLH_DSA_HASH_CTX *hctx,
const uint8_t *msg, size_t msg_len,
const uint8_t *sig, size_t sig_len)
{
SLH_HASH_FUNC_DECLARE(ctx, hashf, hctx);
SLH_ADRS_FUNC_DECLARE(ctx, adrsf);
const SLH_DSA_KEY *pub = hctx->key;
SLH_HASH_FUNC_DECLARE(pub, hashf);
SLH_ADRS_FUNC_DECLARE(pub, adrsf);
SLH_ADRS_DECLARE(adrs);
const SLH_DSA_PARAMS *params = ctx->params;
const SLH_DSA_PARAMS *params = pub->params;
uint32_t n = params->n;
const uint8_t *pk_seed, *pk_root; /* Pointers to elements in |pub| */
PACKET pkt, *sig_rpkt = &pkt; /* Points to the |sig| buffer */
@ -162,7 +164,7 @@ static int slh_verify_internal(SLH_DSA_CTX *ctx, const SLH_DSA_KEY *pub,
return 0;
/* Exit if signature is invalid size */
if (sig_len != ctx->params->sig_len
if (sig_len != params->sig_len
|| !PACKET_buf_init(sig_rpkt, sig, sig_len))
return 0;
if (!PACKET_get_bytes(sig_rpkt, &r, n))
@ -190,9 +192,9 @@ static int slh_verify_internal(SLH_DSA_CTX *ctx, const SLH_DSA_KEY *pub,
adrsf->set_tree_address(adrs, tree_id);
adrsf->set_type_and_clear(adrs, SLH_ADRS_TYPE_FORS_TREE);
adrsf->set_keypair_address(adrs, leaf_id);
return ossl_slh_fors_pk_from_sig(ctx, sig_rpkt, md, pk_seed, adrs,
return ossl_slh_fors_pk_from_sig(hctx, sig_rpkt, md, pk_seed, adrs,
pk_fors, sizeof(pk_fors))
&& ossl_slh_ht_verify(ctx, pk_fors, sig_rpkt, pk_seed,
&& ossl_slh_ht_verify(hctx, pk_fors, sig_rpkt, pk_seed,
tree_id, leaf_id, pk_root)
&& PACKET_remaining(sig_rpkt) == 0;
}
@ -254,7 +256,7 @@ static uint8_t *msg_encode(const uint8_t *msg, size_t msg_len,
* See FIPS 205 Section 10.2.1 Algorithm 22
* @returns 1 on success, or 0 on error.
*/
int ossl_slh_dsa_sign(SLH_DSA_CTX *slh_ctx, const SLH_DSA_KEY *priv,
int ossl_slh_dsa_sign(SLH_DSA_HASH_CTX *slh_ctx,
const uint8_t *msg, size_t msg_len,
const uint8_t *ctx, size_t ctx_len,
const uint8_t *add_rand, int encode,
@ -270,7 +272,7 @@ int ossl_slh_dsa_sign(SLH_DSA_CTX *slh_ctx, const SLH_DSA_KEY *priv,
if (m == NULL)
return 0;
}
ret = slh_sign_internal(slh_ctx, priv, m, m_len, sig, siglen, sigsize, add_rand);
ret = slh_sign_internal(slh_ctx, m, m_len, sig, siglen, sigsize, add_rand);
if (m != msg && m != m_tmp)
OPENSSL_free(m);
return ret;
@ -280,7 +282,7 @@ int ossl_slh_dsa_sign(SLH_DSA_CTX *slh_ctx, const SLH_DSA_KEY *priv,
* See FIPS 205 Section 10.3 Algorithm 24
* @returns 1 on success, or 0 on error.
*/
int ossl_slh_dsa_verify(SLH_DSA_CTX *slh_ctx, const SLH_DSA_KEY *pub,
int ossl_slh_dsa_verify(SLH_DSA_HASH_CTX *slh_ctx,
const uint8_t *msg, size_t msg_len,
const uint8_t *ctx, size_t ctx_len, int encode,
const uint8_t *sig, size_t sig_len)
@ -295,7 +297,7 @@ int ossl_slh_dsa_verify(SLH_DSA_CTX *slh_ctx, const SLH_DSA_KEY *pub,
if (m == NULL)
return 0;
ret = slh_verify_internal(slh_ctx, pub, m, m_len, sig, sig_len);
ret = slh_verify_internal(slh_ctx, m, m_len, sig, sig_len);
if (m != msg && m != m_tmp)
OPENSSL_free(m);
return ret;

View File

@ -49,7 +49,7 @@ SLH_DSA_KEY *ossl_slh_dsa_key_from_pkcs8(const PKCS8_PRIV_KEY_INFO *p8_info,
if (alg_name == NULL)
goto err;
key = ossl_slh_dsa_key_new(lib_ctx, alg_name);
key = ossl_slh_dsa_key_new(lib_ctx, propq, alg_name);
if (key == NULL
|| !ossl_slh_dsa_set_priv(key, p, p_len))
goto err;

View File

@ -1,59 +0,0 @@
/*
* 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 <stddef.h>
#include <openssl/crypto.h>
#include "slh_dsa_local.h"
/**
* @brief Create a SLH_DSA_CTX that contains parameters, functions, and
* pre-fetched HASH related objects for a SLH_DSA algorithm.This context is passed
* to most SLH-DSA functions.
*
* @param alg An SLH-DSA algorithm name such as "SLH-DSA-SHA2-128s"
* @param lib_ctx A library context used for fetching. Can be NULL
* @param propq A propqery query to use for algorithm fetching. Can be NULL.
*
* @returns The created SLH_DSA_CTX object or NULL on failure.
*/
SLH_DSA_CTX *ossl_slh_dsa_ctx_new(const char *alg,
OSSL_LIB_CTX *lib_ctx, const char *propq)
{
SLH_DSA_CTX *ret = OPENSSL_zalloc(sizeof(*ret));
if (ret != NULL) {
const SLH_DSA_PARAMS *params = ossl_slh_dsa_params_get(alg);
if (params == NULL)
goto err;
ret->params = params;
ret->hash_func = ossl_slh_get_hash_fn(params->is_shake);
ret->adrs_func = ossl_slh_get_adrs_fn(params->is_shake == 0);
if (!ossl_slh_hash_ctx_init(&ret->hash_ctx, lib_ctx, propq,
params->is_shake,
params->security_category,
params->n, params->m))
goto err;
}
return ret;
err:
OPENSSL_free(ret);
return NULL;
}
/**
* @brief Destroy a SLH_DSA_CTX
*
* @param ctx The SLH_DSA_CTX object to destroy.
*/
void ossl_slh_dsa_ctx_free(SLH_DSA_CTX *ctx)
{
ossl_slh_hash_ctx_cleanup(&ctx->hash_ctx);
OPENSSL_free(ctx);
}

View File

@ -0,0 +1,77 @@
/*
* 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 <stddef.h>
#include <openssl/crypto.h>
#include "slh_dsa_local.h"
#include "slh_dsa_key.h"
#include <openssl/evp.h>
/**
* @brief Create a SLH_DSA_HASH_CTX that contains parameters, functions, and
* pre-fetched HASH related objects for a SLH_DSA algorithm.This context is passed
* to most SLH-DSA functions.
*
* @param alg An SLH-DSA algorithm name such as "SLH-DSA-SHA2-128s"
* @param lib_ctx A library context used for fetching. Can be NULL
* @param propq A propqery query to use for algorithm fetching. Can be NULL.
*
* @returns The created SLH_DSA_HASH_CTX object or NULL on failure.
*/
SLH_DSA_HASH_CTX *ossl_slh_dsa_hash_ctx_new(const SLH_DSA_KEY *key)
{
SLH_DSA_HASH_CTX *ret = OPENSSL_zalloc(sizeof(*ret));
if (ret == NULL)
return NULL;
ret->key = key;
ret->md_ctx = EVP_MD_CTX_new();
if (ret->md_ctx == NULL)
goto err;
if (EVP_DigestInit_ex2(ret->md_ctx, key->md, NULL) != 1)
goto err;
if (key->md_big != NULL) {
/* Gets here for SHA2 algorithms */
if (key->md_big == key->md) {
ret->md_big_ctx = ret->md_ctx;
} else {
/* Only gets here for SHA2 */
ret->md_big_ctx = EVP_MD_CTX_new();
if (ret->md_big_ctx == NULL)
goto err;
if (EVP_DigestInit_ex2(ret->md_big_ctx, key->md_big, NULL) != 1)
goto err;
}
if (key->hmac != NULL) {
ret->hmac_ctx = EVP_MAC_CTX_new(key->hmac);
if (ret->hmac_ctx == NULL)
goto err;
}
}
return ret;
err:
ossl_slh_dsa_hash_ctx_free(ret);
return NULL;
}
/**
* @brief Destroy a SLH_DSA_HASH_CTX
*
* @param ctx The SLH_DSA_HASH_CTX object to destroy.
*/
void ossl_slh_dsa_hash_ctx_free(SLH_DSA_HASH_CTX *ctx)
{
if (ctx == NULL)
return;
EVP_MD_CTX_free(ctx->md_ctx);
if (ctx->md_big_ctx != ctx->md_ctx)
EVP_MD_CTX_free(ctx->md_big_ctx);
EVP_MAC_CTX_free(ctx->hmac_ctx);
OPENSSL_free(ctx);
}

View File

@ -17,17 +17,64 @@
#include "slh_dsa_key.h"
#include "internal/encoder.h"
static int slh_dsa_compute_pk_root(SLH_DSA_CTX *ctx, SLH_DSA_KEY *out,
int verify);
static int slh_dsa_compute_pk_root(SLH_DSA_HASH_CTX *ctx, SLH_DSA_KEY *out, int verify);
static void slh_dsa_key_hash_cleanup(SLH_DSA_KEY *key)
{
OPENSSL_free(key->propq);
if (key->md_big != key->md)
EVP_MD_free(key->md_big);
key->md_big = NULL;
EVP_MD_free(key->md);
EVP_MAC_free(key->hmac);
key->md = NULL;
}
static int slh_dsa_key_hash_init(SLH_DSA_KEY *key)
{
int is_shake = key->params->is_shake;
int security_category = key->params->security_category;
const char *digest_alg = is_shake ? "SHAKE-256" : "SHA2-256";
key->md = EVP_MD_fetch(key->libctx, digest_alg, key->propq);
if (key->md == NULL)
return 0;
/*
* SHA2 algorithm(s) require SHA256 + HMAC_SHA(X) & MGF1(SHAX)
* SHAKE algorithm(s) use SHAKE for all functions.
*/
if (is_shake == 0) {
if (security_category == 1) {
/* For category 1 SHA2-256 is used for all hash operations */
key->md_big = key->md;
} else {
/* Security categories 3 & 5 also need SHA-512 */
key->md_big = EVP_MD_fetch(key->libctx, "SHA2-512", key->propq);
if (key->md_big == NULL)
goto err;
}
key->hmac = EVP_MAC_fetch(key->libctx, "HMAC", key->propq);
if (key->hmac == NULL)
goto err;
}
key->adrs_func = ossl_slh_get_adrs_fn(is_shake == 0);
key->hash_func = ossl_slh_get_hash_fn(is_shake);
return 1;
err:
slh_dsa_key_hash_cleanup(key);
return 0;
}
/**
* @brief Create a new SLH_DSA_KEY object
*
* @param libctx A OSSL_LIB_CTX object used for fetching algorithms.
* @param propq The property query used for fetching algorithms
* @param alg The algorithm name associated with the key type
* @returns The new SLH_DSA_KEY object on success, or NULL on malloc failure
*/
SLH_DSA_KEY *ossl_slh_dsa_key_new(OSSL_LIB_CTX *libctx, const char *alg)
SLH_DSA_KEY *ossl_slh_dsa_key_new(OSSL_LIB_CTX *libctx, const char *propq,
const char *alg)
{
SLH_DSA_KEY *ret;
const SLH_DSA_PARAMS *params = ossl_slh_dsa_params_get(alg);
@ -37,14 +84,20 @@ SLH_DSA_KEY *ossl_slh_dsa_key_new(OSSL_LIB_CTX *libctx, const char *alg)
ret = OPENSSL_zalloc(sizeof(*ret));
if (ret != NULL) {
if (!CRYPTO_NEW_REF(&ret->references, 1)) {
OPENSSL_free(ret);
return NULL;
}
ret->libctx = libctx;
ret->params = params;
if (propq != NULL) {
ret->propq = OPENSSL_strdup(propq);
if (ret->propq == NULL)
goto err;
}
if (!slh_dsa_key_hash_init(ret))
goto err;
}
return ret;
err:
ossl_slh_dsa_key_free(ret);
return NULL;
}
/**
@ -52,39 +105,14 @@ SLH_DSA_KEY *ossl_slh_dsa_key_new(OSSL_LIB_CTX *libctx, const char *alg)
*/
void ossl_slh_dsa_key_free(SLH_DSA_KEY *key)
{
int i;
if (key == NULL)
return;
CRYPTO_DOWN_REF(&key->references, &i);
REF_PRINT_COUNT("SLH_DSA_KEY", key);
if (i > 0)
return;
REF_ASSERT_ISNT(i < 0);
slh_dsa_key_hash_cleanup(key);
OPENSSL_cleanse(&key->priv, sizeof(key->priv) >> 1);
OPENSSL_free(key->propq);
CRYPTO_FREE_REF(&key->references);
OPENSSL_free(key);
}
/*
* @brief Increase the reference count for a SLH_DSA_KEY object.
* @returns 1 on success or 0 otherwise.
*/
int ossl_slh_dsa_key_up_ref(SLH_DSA_KEY *key)
{
int i;
if (CRYPTO_UP_REF(&key->references, &i) <= 0)
return 0;
REF_PRINT_COUNT("SLH_DSA_KEY", key);
REF_ASSERT_ISNT(i < 2);
return ((i > 1) ? 1 : 0);
}
/**
* @brief Are 2 keys equal?
*
@ -147,16 +175,16 @@ int ossl_slh_dsa_key_has(const SLH_DSA_KEY *key, int selection)
int ossl_slh_dsa_key_pairwise_check(const SLH_DSA_KEY *key)
{
int ret;
SLH_DSA_CTX *ctx = NULL;
SLH_DSA_HASH_CTX *ctx = NULL;
if (key->pub == NULL || key->has_priv == 0)
return 0;
ctx = ossl_slh_dsa_ctx_new(key->params->alg, key->libctx, key->propq);
ctx = ossl_slh_dsa_hash_ctx_new(key);
if (ctx == NULL)
return 0;
ret = slh_dsa_compute_pk_root(ctx, (SLH_DSA_KEY *)key, 1);
ossl_slh_dsa_ctx_free(ctx);
ossl_slh_dsa_hash_ctx_free(ctx);
return ret;
}
@ -229,18 +257,19 @@ int ossl_slh_dsa_key_fromdata(SLH_DSA_KEY *key, const OSSL_PARAM params[],
* See FIPS 205 Section 9.1 Algorithm 18
*
* @param ctx Contains SLH_DSA algorithm functions and constants.
* @param out A SLH_DSA key containing the private key (seed and prf) and public key seed.
* @param out An SLH_DSA key containing the private key (seed and prf) and public key seed.
* The public root key is written to this key.
* @param validate If set to 1 the computed public key is not written to the key,
* but will be compared to the existing value.
* @returns 1 if the root key is generated or compared successfully, or 0 on error.
*/
static int slh_dsa_compute_pk_root(SLH_DSA_CTX *ctx, SLH_DSA_KEY *out,
static int slh_dsa_compute_pk_root(SLH_DSA_HASH_CTX *ctx, SLH_DSA_KEY *out,
int validate)
{
SLH_ADRS_FUNC_DECLARE(ctx, adrsf);
const SLH_DSA_KEY *key = ctx->key;
SLH_ADRS_FUNC_DECLARE(key, adrsf);
SLH_ADRS_DECLARE(adrs);
const SLH_DSA_PARAMS *params = out->params;
const SLH_DSA_PARAMS *params = key->params;
size_t n = params->n;
uint8_t pk_root[SLH_DSA_MAX_N], *dst;
@ -250,8 +279,8 @@ static int slh_dsa_compute_pk_root(SLH_DSA_CTX *ctx, SLH_DSA_KEY *out,
dst = validate ? pk_root : SLH_DSA_PK_ROOT(out);
/* Generate the ROOT public key */
return ossl_slh_xmss_node(ctx, SLH_DSA_SK_SEED(out), 0, params->hm,
SLH_DSA_PK_SEED(out), adrs, dst, n)
return ossl_slh_xmss_node(ctx, SLH_DSA_SK_SEED(key), 0, params->hm,
SLH_DSA_PK_SEED(key), adrs, dst, n)
&& (validate == 0 || memcmp(dst, SLH_DSA_PK_ROOT(out), n) == 0);
}
@ -261,27 +290,25 @@ static int slh_dsa_compute_pk_root(SLH_DSA_CTX *ctx, SLH_DSA_KEY *out,
* calculated using these generated values.
* See FIPS 205 Section 10.1 Algorithm 21
*
* @param ctx Contains SLH_DSA algorithm functions and constants.
* @param ctx Contains SLH_DSA algorithm functions and constants
* @param out An SLH_DSA key to write key pair data to.
* @param lib_ctx A library context for fetching RAND algorithms
* @param entropy Optional entropy to use instead of using a DRBG.
* Required for ACVP testing. It may be NULL.
* @param entropy_len the size of |entropy|. If set it must be at least 3 * |n|.
* @param out An SLH_DSA key to write keypair data to.
* @returns 1 if the key is generated or 0 otherwise.
*/
int ossl_slh_dsa_generate_key(SLH_DSA_CTX *ctx, OSSL_LIB_CTX *lib_ctx,
const uint8_t *entropy, size_t entropy_len,
SLH_DSA_KEY *out)
int ossl_slh_dsa_generate_key(SLH_DSA_HASH_CTX *ctx, SLH_DSA_KEY *out,
OSSL_LIB_CTX *lib_ctx,
const uint8_t *entropy, size_t entropy_len)
{
size_t n = ctx->params->n;
size_t n = out->params->n;
size_t secret_key_len = 2 * n; /* The length of SK_SEED + SK_PRF */
size_t pk_seed_len = n; /* The length of PK_SEED */
size_t entropy_len_expected = secret_key_len + pk_seed_len;
uint8_t *priv = SLH_DSA_PRIV(out);
uint8_t *pub = SLH_DSA_PUB(out);
assert(ctx->params == out->params);
if (entropy != NULL && entropy_len != 0) {
if (entropy_len < entropy_len_expected)
goto err;
@ -313,9 +340,9 @@ err:
*
* @returns 1 if the algorithm matches, or 0 otherwise.
*/
int ossl_slh_dsa_key_type_matches(SLH_DSA_CTX *ctx, const SLH_DSA_KEY *key)
int ossl_slh_dsa_key_type_matches(const SLH_DSA_KEY *key, const char *alg)
{
return (key->params == ctx->params);
return (OPENSSL_strcasecmp(key->params->alg, alg) == 0);
}
/* Returns the public key data or NULL if there is no public key */

View File

@ -8,7 +8,6 @@
*/
#include <openssl/e_os2.h>
#include "internal/refcount.h"
#define SLH_DSA_MAX_N 32
#define SLH_DSA_SK_SEED(key) ((key)->priv)
@ -33,10 +32,16 @@ struct slh_dsa_key_st {
* to &priv[n * 2]
*/
uint8_t *pub;
CRYPTO_REF_COUNT references;
OSSL_LIB_CTX *libctx;
char *propq;
/* contains the algorithm name and constants such as |n| */
const SLH_DSA_PARAMS *params;
int has_priv; /* Set to 1 if there is a private key component */
const SLH_DSA_PARAMS *params;
const SLH_ADRS_FUNC *adrs_func;
const SLH_HASH_FUNC *hash_func;
/* See FIPS 205 Section 11.1 */
EVP_MD *md; /* Used for SHAKE and SHA-256 */
EVP_MD *md_big; /* Used for SHA-256 or SHA-512 */
EVP_MAC *hmac;
};

View File

@ -26,63 +26,67 @@
#define SLH_WOTS_LEN(n) (2 * (n) + 3)
/*
* FIPS 205 SLH_DSA algorithms have many different parameters which includes:
* FIPS 205 SLH_DSA algorithms have many different parameters which includes
* the following constants that are stored into a |key|:
* - A set of constants (Section 11. contains 12 parameter sets)
* such as tree heights and security parameters associated with a algorithm
* name such as SLH-DSA-SHA2-128s.
* - ADRS functions (such as set_layer_address() in Section 4.3 & 11.2)
* - Hash Functions (such as H_MSG() & PRF()) See Sections 11.1, 11.2.1 & 11.2.2.
* - prefetched EVP_MD objects used for hashing.
*
* - OpenSSL also uses an SLH_HASH_CTX to pass pre-fetched EVP related objects
* to the Hash functions.
* When performing operations multiple Hash related objects are also needed
* such as EVP_MD_CTX and EVP_MAC_CTX (these are independent of the |key|)
*
* SLH_DSA_CTX is a container to hold all of these objects. This object is
* resolved early and is then passed to most SLH_DSA related functions.
* SLH_DSA_HASH_CTX is a container to hold all of these objects. This object is
* resolved early and is then passed to most SLH_DSA related functions, since
* there are many nested layers of calls that require these values.
*/
struct slh_dsa_ctx_st {
const SLH_DSA_PARAMS *params;
const SLH_ADRS_FUNC *adrs_func;
const SLH_HASH_FUNC *hash_func;
SLH_HASH_CTX hash_ctx;
struct slh_dsa_hash_ctx_st {
const SLH_DSA_KEY *key; /* This key is not owned by this object */
EVP_MD_CTX *md_ctx; /* Either SHAKE OR SHA-256 */
EVP_MD_CTX *md_big_ctx; /* Either SHA-512 or points to |md_ctx| for SHA-256*/
EVP_MAC_CTX *hmac_ctx; /* required by SHA algorithms for PRFmsg() */
int hmac_digest_used; /* Used for lazy init of hmac_ctx digest */
};
__owur int ossl_slh_wots_pk_gen(SLH_DSA_CTX *ctx, const uint8_t *sk_seed,
__owur int ossl_slh_wots_pk_gen(SLH_DSA_HASH_CTX *ctx, const uint8_t *sk_seed,
const uint8_t *pk_seed, SLH_ADRS adrs,
uint8_t *pk_out, size_t pk_out_len);
__owur int ossl_slh_wots_sign(SLH_DSA_CTX *ctx, const uint8_t *msg,
__owur int ossl_slh_wots_sign(SLH_DSA_HASH_CTX *ctx, const uint8_t *msg,
const uint8_t *sk_seed, const uint8_t *pk_seed,
SLH_ADRS adrs, WPACKET *sig_wpkt);
__owur int ossl_slh_wots_pk_from_sig(SLH_DSA_CTX *ctx,
__owur int ossl_slh_wots_pk_from_sig(SLH_DSA_HASH_CTX *ctx,
PACKET *sig_rpkt, const uint8_t *msg,
const uint8_t *pk_seed, SLH_ADRS adrs,
uint8_t *pk_out, size_t pk_out_len);
__owur int ossl_slh_xmss_node(SLH_DSA_CTX *ctx, const uint8_t *sk_seed,
__owur int ossl_slh_xmss_node(SLH_DSA_HASH_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, size_t pk_out_len);
__owur int ossl_slh_xmss_sign(SLH_DSA_CTX *ctx, const uint8_t *msg,
__owur int ossl_slh_xmss_sign(SLH_DSA_HASH_CTX *ctx, const uint8_t *msg,
const uint8_t *sk_seed, uint32_t node_id,
const uint8_t *pk_seed, SLH_ADRS adrs,
WPACKET *sig_wpkt);
__owur int ossl_slh_xmss_pk_from_sig(SLH_DSA_CTX *ctx, uint32_t node_id,
__owur int ossl_slh_xmss_pk_from_sig(SLH_DSA_HASH_CTX *ctx, uint32_t node_id,
PACKET *sig_rpkt, const uint8_t *msg,
const uint8_t *pk_seed, SLH_ADRS adrs,
uint8_t *pk_out, size_t pk_out_len);
__owur int ossl_slh_ht_sign(SLH_DSA_CTX *ctx, const uint8_t *msg,
__owur int ossl_slh_ht_sign(SLH_DSA_HASH_CTX *ctx, const uint8_t *msg,
const uint8_t *sk_seed, const uint8_t *pk_seed,
uint64_t tree_id, uint32_t leaf_id,
WPACKET *sig_wpkt);
__owur int ossl_slh_ht_verify(SLH_DSA_CTX *ctx, const uint8_t *msg,
__owur int ossl_slh_ht_verify(SLH_DSA_HASH_CTX *ctx, const uint8_t *msg,
PACKET *sig_rpkt, const uint8_t *pk_seed,
uint64_t tree_id, uint32_t leaf_id,
const uint8_t *pk_root);
__owur int ossl_slh_fors_sign(SLH_DSA_CTX *ctx, const uint8_t *md,
__owur int ossl_slh_fors_sign(SLH_DSA_HASH_CTX *ctx, const uint8_t *md,
const uint8_t *sk_seed, const uint8_t *pk_seed,
SLH_ADRS adrs, WPACKET *sig_wpkt);
__owur int ossl_slh_fors_pk_from_sig(SLH_DSA_CTX *ctx, PACKET *sig_rpkt,
__owur int ossl_slh_fors_pk_from_sig(SLH_DSA_HASH_CTX *ctx, PACKET *sig_rpkt,
const uint8_t *md, const uint8_t *pk_seed,
SLH_ADRS adrs,
uint8_t *pk_out, size_t pk_out_len);

View File

@ -57,7 +57,7 @@ static SLH_DSA_KEY *ossl_slh_dsa_key_create(const X509_ALGOR *palg,
if (id == EVP_PKEY_NONE)
return 0;
key = ossl_slh_dsa_key_new(libctx, OBJ_nid2ln(id));
key = ossl_slh_dsa_key_new(libctx, propq, OBJ_nid2ln(id));
if (key == NULL)
return 0;
if (public)

View File

@ -11,6 +11,7 @@
#include <string.h>
#include <openssl/crypto.h>
#include "slh_dsa_local.h"
#include "slh_dsa_key.h"
/* k = 14, 17, 22, 33, 35 (number of trees) */
#define SLH_MAX_K 35
@ -38,19 +39,19 @@ static void slh_base_2b(const uint8_t *in, uint32_t b, uint32_t *out, size_t out
* @param pk_out_len The maximum size of |pk_out|
* @returns 1 on success, or 0 on error.
*/
static int slh_fors_sk_gen(SLH_DSA_CTX *ctx, const uint8_t *sk_seed,
static int slh_fors_sk_gen(SLH_DSA_HASH_CTX *ctx, const uint8_t *sk_seed,
const uint8_t *pk_seed, SLH_ADRS adrs, uint32_t id,
uint8_t *pk_out, size_t pk_out_len)
{
const SLH_DSA_KEY *key = ctx->key;
SLH_ADRS_DECLARE(sk_adrs);
SLH_ADRS_FUNC_DECLARE(ctx, adrsf);
SLH_ADRS_FUNC_DECLARE(key, adrsf);
adrsf->copy(sk_adrs, adrs);
adrsf->set_type_and_clear(sk_adrs, SLH_ADRS_TYPE_FORS_PRF);
adrsf->copy_keypair_address(sk_adrs, adrs);
adrsf->set_tree_index(sk_adrs, id);
return ctx->hash_func->PRF(&ctx->hash_ctx, pk_seed, sk_seed, sk_adrs,
pk_out, pk_out_len);
return key->hash_func->PRF(ctx, pk_seed, sk_seed, sk_adrs, pk_out, pk_out_len);
}
/**
@ -74,25 +75,24 @@ static int slh_fors_sk_gen(SLH_DSA_CTX *ctx, const uint8_t *sk_seed,
* @param node_len The maximum size of |node|
* @returns 1 on success, or 0 on error.
*/
static int slh_fors_node(SLH_DSA_CTX *ctx, const uint8_t *sk_seed,
static int slh_fors_node(SLH_DSA_HASH_CTX *ctx, const uint8_t *sk_seed,
const uint8_t *pk_seed, SLH_ADRS adrs, uint32_t node_id,
uint32_t height, uint8_t *node, size_t node_len)
{
int ret = 0;
const SLH_DSA_KEY *key = ctx->key;
uint8_t sk[SLH_MAX_N], lnode[SLH_MAX_N], rnode[SLH_MAX_N];
uint32_t n = ctx->params->n;
uint32_t n = key->params->n;
SLH_ADRS_FUNC_DECLARE(ctx, adrsf);
SLH_ADRS_FUNC_DECLARE(key, adrsf);
if (height == 0) {
/* Gets here for leaf nodes */
if (!slh_fors_sk_gen(ctx, sk_seed, pk_seed, adrs, node_id,
sk, sizeof(sk)))
if (!slh_fors_sk_gen(ctx, sk_seed, pk_seed, adrs, node_id, sk, sizeof(sk)))
return 0;
adrsf->set_tree_height(adrs, 0);
adrsf->set_tree_index(adrs, node_id);
ret = ctx->hash_func->F(&ctx->hash_ctx, pk_seed, adrs, sk, n,
node, node_len);
ret = key->hash_func->F(ctx, pk_seed, adrs, sk, n, node, node_len);
OPENSSL_cleanse(sk, n);
return ret;
} else {
@ -103,8 +103,7 @@ static int slh_fors_node(SLH_DSA_CTX *ctx, const uint8_t *sk_seed,
return 0;
adrsf->set_tree_height(adrs, height);
adrsf->set_tree_index(adrs, node_id);
if (!ctx->hash_func->H(&ctx->hash_ctx, pk_seed, adrs, lnode, rnode,
node, node_len))
if (!key->hash_func->H(ctx, pk_seed, adrs, lnode, rnode, node, node_len))
return 0;
}
return 1;
@ -130,13 +129,14 @@ static int slh_fors_node(SLH_DSA_CTX *ctx, const uint8_t *sk_seed,
* @param sig_len The size of |sig| which is (2 * n + 3) * n + tree_height * n.
* @returns 1 on success, or 0 on error.
*/
int ossl_slh_fors_sign(SLH_DSA_CTX *ctx, const uint8_t *md,
int ossl_slh_fors_sign(SLH_DSA_HASH_CTX *ctx, const uint8_t *md,
const uint8_t *sk_seed, const uint8_t *pk_seed,
SLH_ADRS adrs, WPACKET *sig_wpkt)
{
const SLH_DSA_KEY *key = ctx->key;
uint32_t tree_id, layer, s, tree_offset;
uint32_t ids[SLH_MAX_K];
const SLH_DSA_PARAMS *params = ctx->params;
const SLH_DSA_PARAMS *params = key->params;
uint32_t n = params->n;
uint32_t k = params->k; /* number of trees */
uint32_t a = params->a;
@ -207,14 +207,15 @@ int ossl_slh_fors_sign(SLH_DSA_CTX *ctx, const uint8_t *md,
* @param pk_out_len The maximum size of |pk_out|
* @returns 1 on success, or 0 on error.
*/
int ossl_slh_fors_pk_from_sig(SLH_DSA_CTX *ctx, PACKET *fors_sig_rpkt,
int ossl_slh_fors_pk_from_sig(SLH_DSA_HASH_CTX *ctx, PACKET *fors_sig_rpkt,
const uint8_t *md, const uint8_t *pk_seed,
SLH_ADRS adrs, uint8_t *pk_out, size_t pk_out_len)
{
const SLH_DSA_KEY *key = ctx->key;
int ret = 0;
uint32_t i, j, aoff = 0;
uint32_t ids[SLH_MAX_K];
const SLH_DSA_PARAMS *params = ctx->params;
const SLH_DSA_PARAMS *params = key->params;
uint32_t a = params->a;
uint32_t k = params->k;
uint32_t n = params->n;
@ -226,10 +227,10 @@ int ossl_slh_fors_pk_from_sig(SLH_DSA_CTX *ctx, PACKET *fors_sig_rpkt,
WPACKET root_pkt, *wroot_pkt = &root_pkt; /* Points to |roots| buffer */
SLH_ADRS_DECLARE(pk_adrs);
SLH_ADRS_FUNC_DECLARE(ctx, adrsf);
SLH_ADRS_FUNC_DECLARE(key, adrsf);
SLH_ADRS_FN_DECLARE(adrsf, set_tree_index);
SLH_ADRS_FN_DECLARE(adrsf, set_tree_height);
SLH_HASH_FUNC_DECLARE(ctx, hashf, hctx);
SLH_HASH_FUNC_DECLARE(key, hashf);
SLH_HASH_FN_DECLARE(hashf, F);
SLH_HASH_FN_DECLARE(hashf, H);
@ -250,7 +251,7 @@ int ossl_slh_fors_pk_from_sig(SLH_DSA_CTX *ctx, PACKET *fors_sig_rpkt,
/* Regenerate the public key of the leaf */
if (!PACKET_get_bytes(fors_sig_rpkt, &sk, n)
|| !WPACKET_allocate_bytes(wroot_pkt, n, &node0)
|| !F(hctx, pk_seed, adrs, sk, n, node0, n))
|| !F(ctx, pk_seed, adrs, sk, n, node0, n))
goto err;
/* This omits the copying of the nodes that the FIPS 205 code does */
@ -264,12 +265,12 @@ int ossl_slh_fors_pk_from_sig(SLH_DSA_CTX *ctx, PACKET *fors_sig_rpkt,
if ((id & 1) == 0) {
node_id >>= 1;
set_tree_index(adrs, node_id);
if (!H(hctx, pk_seed, adrs, node0, authj, node1, n))
if (!H(ctx, pk_seed, adrs, node0, authj, node1, n))
goto err;
} else {
node_id = (node_id - 1) >> 1;
set_tree_index(adrs, node_id);
if (!H(hctx, pk_seed, adrs, authj, node0, node1, n))
if (!H(ctx, pk_seed, adrs, authj, node0, node1, n))
goto err;
}
id >>= 1;
@ -283,8 +284,7 @@ int ossl_slh_fors_pk_from_sig(SLH_DSA_CTX *ctx, PACKET *fors_sig_rpkt,
adrsf->copy(pk_adrs, adrs);
adrsf->set_type_and_clear(pk_adrs, SLH_ADRS_TYPE_FORS_ROOTS);
adrsf->copy_keypair_address(pk_adrs, adrs);
ret = hashf->T(hctx, pk_seed, pk_adrs, roots, roots_len,
pk_out, pk_out_len);
ret = hashf->T(ctx, pk_seed, pk_adrs, roots, roots_len, pk_out, pk_out_len);
err:
if (!WPACKET_finish(wroot_pkt))
ret = 0;

View File

@ -15,15 +15,9 @@
#include <openssl/core_names.h>
#include <openssl/rsa.h> /* PKCS1_MGF1() */
#include "slh_dsa_local.h"
#include "slh_dsa_key.h"
#define MAX_DIGEST_SIZE 64 /* SHA-512 is used for security category 3 & 5 */
/*
* PRF(), F() use this value to calculate the number of zeros
* H(), T() also use this for security cat 1
*/
#define SHA2_NUM_ZEROS_BOUND1 64
/* H(), T() use this to calculate the number of zeros for security cat 3 & 5 */
#define SHA2_NUM_ZEROS_BOUND2 128
static OSSL_SLH_HASHFUNC_H_MSG slh_hmsg_sha2;
static OSSL_SLH_HASHFUNC_PRF slh_prf_sha2;
@ -39,95 +33,6 @@ static OSSL_SLH_HASHFUNC_F slh_f_shake;
static OSSL_SLH_HASHFUNC_H slh_h_shake;
static OSSL_SLH_HASHFUNC_T slh_t_shake;
static EVP_MAC_CTX *hmac_ctx_new(OSSL_LIB_CTX *lib_ctx, const char *propq)
{
EVP_MAC_CTX *mctx = NULL;
EVP_MAC *mac = EVP_MAC_fetch(lib_ctx, "HMAC", propq);
if (mac == NULL)
return NULL;
mctx = EVP_MAC_CTX_new(mac);
EVP_MAC_free(mac);
return mctx;
}
static EVP_MD_CTX *md_ctx_new(EVP_MD *md)
{
EVP_MD_CTX *ctx = EVP_MD_CTX_new();
if (ctx == NULL)
return NULL;
if (EVP_DigestInit_ex2(ctx, md, NULL) != 1) {
EVP_MD_CTX_free(ctx);
ctx = NULL;
}
return ctx;
}
int ossl_slh_hash_ctx_init(SLH_HASH_CTX *ctx, OSSL_LIB_CTX *lib_ctx,
const char *propq, int is_shake,
int security_category, size_t n, size_t m)
{
const char *digest_alg = is_shake ? "SHAKE-256" : "SHA2-256";
ctx->md = EVP_MD_fetch(lib_ctx, digest_alg, propq);
if (ctx->md == NULL)
return 0;
/* For SHA2 all categories require a SHA2-256 digest */
ctx->md_ctx = md_ctx_new(ctx->md);
if (ctx->md_ctx == NULL)
goto err;
/*
* SHA2 algorithm(s) require SHA256 + HMAC_SHA(X) & MGF1(SHAX)
* SHAKE algorithm(s) use SHAKE for all functions.
*/
if (is_shake == 0) {
if (security_category == 1) {
ctx->sha2_h_and_t_bound = SHA2_NUM_ZEROS_BOUND1;
/* For category 1 SHA2-256 is used for all hash operations */
ctx->md_big_ctx = ctx->md_ctx;
ctx->hmac_digest = "SHA2-256";
} else {
/* Security categories 3 & 5 also need SHA-512 */
EVP_MD_free(ctx->md);
ctx->md = EVP_MD_fetch(lib_ctx, "SHA2-512", propq);
if (ctx->md == NULL)
goto err;
ctx->sha2_h_and_t_bound = SHA2_NUM_ZEROS_BOUND2;
/* Use HMAC-SHA2-512 for PRF_MSG */
ctx->hmac_digest = "SHA2-512";
/* use SHA2-512 in H_MSG, H and T */
ctx->md_big_ctx = md_ctx_new(ctx->md);
if (ctx->md_big_ctx == NULL)
goto err;
/* PRF & F use SHA2-256 via ctx->md_ctx */
}
/* This assumes that propq exists for the duration of the operation */
ctx->hmac_propq = propq;
ctx->hmac_ctx = hmac_ctx_new(lib_ctx, propq);
if (ctx->hmac_ctx == NULL)
goto err;
}
ctx->n = n;
ctx->m = m;
return 1;
err:
ossl_slh_hash_ctx_cleanup(ctx);
return 0;
}
void ossl_slh_hash_ctx_cleanup(SLH_HASH_CTX *ctx)
{
EVP_MD_free(ctx->md);
EVP_MAC_CTX_free(ctx->hmac_ctx);
if (ctx->md_big_ctx != ctx->md_ctx)
EVP_MD_CTX_free(ctx->md_big_ctx);
EVP_MD_CTX_free(ctx->md_ctx);
}
static ossl_inline int xof_digest_3(EVP_MD_CTX *ctx,
const uint8_t *in1, size_t in1_len,
const uint8_t *in2, size_t in2_len,
@ -158,80 +63,72 @@ static ossl_inline int xof_digest_4(EVP_MD_CTX *ctx,
/* See FIPS 205 Section 11.1 */
static int
slh_hmsg_shake(SLH_HASH_CTX *hctx, const uint8_t *r, const uint8_t *pk_seed,
const uint8_t *pk_root, const uint8_t *msg, size_t msg_len,
slh_hmsg_shake(SLH_DSA_HASH_CTX *ctx, const uint8_t *r,
const uint8_t *pk_seed, const uint8_t *pk_root,
const uint8_t *msg, size_t msg_len,
uint8_t *out, size_t out_len)
{
size_t m = hctx->m;
size_t n = hctx->n;
const SLH_DSA_PARAMS *params = ctx->key->params;
size_t m = params->m;
size_t n = params->n;
assert(m <= out_len);
return xof_digest_4(hctx->md_ctx, r, n, pk_seed, n, pk_root, n,
return xof_digest_4(ctx->md_ctx, r, n, pk_seed, n, pk_root, n,
msg, msg_len, out, m);
}
static int
slh_prf_shake(SLH_HASH_CTX *hctx, const uint8_t *pk_seed, const uint8_t *sk_seed,
slh_prf_shake(SLH_DSA_HASH_CTX *ctx,
const uint8_t *pk_seed, const uint8_t *sk_seed,
const SLH_ADRS adrs, uint8_t *out, size_t out_len)
{
size_t n = hctx->n;
const SLH_DSA_PARAMS *params = ctx->key->params;
size_t n = params->n;
assert(n <= out_len);
return xof_digest_3(hctx->md_ctx, pk_seed, n, adrs, SLH_ADRS_SIZE,
return xof_digest_3(ctx->md_ctx, pk_seed, n, adrs, SLH_ADRS_SIZE,
sk_seed, n, out, n);
}
static int
slh_prf_msg_shake(SLH_HASH_CTX *hctx, const uint8_t *sk_prf,
slh_prf_msg_shake(SLH_DSA_HASH_CTX *ctx, const uint8_t *sk_prf,
const uint8_t *opt_rand, const uint8_t *msg, size_t msg_len,
WPACKET *pkt)
{
unsigned char out[SLH_MAX_N];
size_t n = hctx->n;
const SLH_DSA_PARAMS *params = ctx->key->params;
size_t n = params->n;
assert(n <= sizeof(out));
return xof_digest_3(hctx->md_ctx, sk_prf, n, opt_rand, n,
msg, msg_len, out, n)
return xof_digest_3(ctx->md_ctx, sk_prf, n, opt_rand, n, msg, msg_len, out, n)
&& WPACKET_memcpy(pkt, out, n);
}
static int
slh_f_shake(SLH_HASH_CTX *hctx, const uint8_t *pk_seed, const SLH_ADRS adrs,
slh_f_shake(SLH_DSA_HASH_CTX *ctx, const uint8_t *pk_seed, const SLH_ADRS adrs,
const uint8_t *m1, size_t m1_len, uint8_t *out, size_t out_len)
{
size_t n = hctx->n;
const SLH_DSA_PARAMS *params = ctx->key->params;
size_t n = params->n;
assert(n <= out_len);
return xof_digest_3(hctx->md_ctx, pk_seed, n, adrs, SLH_ADRS_SIZE,
m1, m1_len, out, n);
return xof_digest_3(ctx->md_ctx, pk_seed, n, adrs, SLH_ADRS_SIZE, m1, m1_len, out, n);
}
static int
slh_h_shake(SLH_HASH_CTX *hctx, const uint8_t *pk_seed, const SLH_ADRS adrs,
slh_h_shake(SLH_DSA_HASH_CTX *ctx, const uint8_t *pk_seed, const SLH_ADRS adrs,
const uint8_t *m1, const uint8_t *m2, uint8_t *out, size_t out_len)
{
size_t n = hctx->n;
const SLH_DSA_PARAMS *params = ctx->key->params;
size_t n = params->n;
assert(n <= out_len);
return xof_digest_4(hctx->md_ctx, pk_seed, n, adrs, SLH_ADRS_SIZE,
m1, n, m2, n, out, n);
return xof_digest_4(ctx->md_ctx, pk_seed, n, adrs, SLH_ADRS_SIZE, m1, n, m2, n, out, n);
}
static int
slh_t_shake(SLH_HASH_CTX *hctx, const uint8_t *pk_seed, const SLH_ADRS adrs,
slh_t_shake(SLH_DSA_HASH_CTX *ctx, const uint8_t *pk_seed, const SLH_ADRS adrs,
const uint8_t *ml, size_t ml_len, uint8_t *out, size_t out_len)
{
size_t n = hctx->n;
const SLH_DSA_PARAMS *params = ctx->key->params;
size_t n = params->n;
assert(n <= out_len);
return xof_digest_3(hctx->md_ctx, pk_seed, n, adrs, SLH_ADRS_SIZE,
ml, ml_len, out, n);
return xof_digest_3(ctx->md_ctx, pk_seed, n, adrs, SLH_ADRS_SIZE, ml, ml_len, out, n);
}
static ossl_inline int
@ -251,14 +148,15 @@ digest_4(EVP_MD_CTX *ctx,
/* FIPS 205 Section 11.2.1 and 11.2.2 */
static int
slh_hmsg_sha2(SLH_HASH_CTX *hctx, const uint8_t *r, const uint8_t *pk_seed,
slh_hmsg_sha2(SLH_DSA_HASH_CTX *hctx, const uint8_t *r, const uint8_t *pk_seed,
const uint8_t *pk_root, const uint8_t *msg, size_t msg_len,
uint8_t *out, size_t out_len)
{
size_t m = hctx->m;
size_t n = hctx->n;
const SLH_DSA_PARAMS *params = hctx->key->params;
size_t m = params->m;
size_t n = params->n;
uint8_t seed[2 * SLH_MAX_N + MAX_DIGEST_SIZE];
int sz = EVP_MD_get_size(hctx->md);
int sz = EVP_MD_get_size(hctx->key->md_big);
size_t seed_len = (size_t)sz + 2 * n;
assert(m <= out_len);
@ -269,17 +167,19 @@ slh_hmsg_sha2(SLH_HASH_CTX *hctx, const uint8_t *r, const uint8_t *pk_seed,
memcpy(seed + n, pk_seed, n);
return digest_4(hctx->md_big_ctx, r, n, pk_seed, n, pk_root, n, msg, msg_len,
seed + 2 * n)
&& (PKCS1_MGF1(out, m, seed, seed_len, hctx->md) == 0);
&& (PKCS1_MGF1(out, m, seed, seed_len, hctx->key->md_big) == 0);
}
static int
slh_prf_msg_sha2(SLH_HASH_CTX *hctx,
slh_prf_msg_sha2(SLH_DSA_HASH_CTX *hctx,
const uint8_t *sk_prf, const uint8_t *opt_rand,
const uint8_t *msg, size_t msg_len, WPACKET *pkt)
{
int ret;
const SLH_DSA_KEY *key = hctx->key;
EVP_MAC_CTX *mctx = hctx->hmac_ctx;
size_t n = hctx->n;
const SLH_DSA_PARAMS *prms = key->params;
size_t n = prms->n;
uint8_t mac[MAX_DIGEST_SIZE] = {0};
OSSL_PARAM *p = NULL;
OSSL_PARAM params[3];
@ -287,18 +187,19 @@ slh_prf_msg_sha2(SLH_HASH_CTX *hctx,
/*
* Due to the way HMAC works, it is not possible to do this code early
* in hmac_ctx_new() since it requires a key in order to set the digest.
* So we do a lazy update here on the first call.
*/
if (hctx->hmac_digest != NULL) {
if (hctx->hmac_digest_used == 0) {
p = params;
/* The underlying digest to be used */
*p++ = OSSL_PARAM_construct_utf8_string(OSSL_MAC_PARAM_DIGEST,
(char *)hctx->hmac_digest, 0);
if (hctx->hmac_propq != NULL)
(char *)EVP_MD_get0_name(key->md_big), 0);
if (key->propq != NULL)
*p++ = OSSL_PARAM_construct_utf8_string(OSSL_MAC_PARAM_PROPERTIES,
(char *)hctx->hmac_propq, 0);
(char *)key->propq, 0);
*p = OSSL_PARAM_construct_end();
p = params;
hctx->hmac_digest = NULL;
hctx->hmac_digest_used = 1;
}
ret = EVP_MAC_init(mctx, sk_prf, n, p) == 1
@ -328,43 +229,46 @@ do_hash(EVP_MD_CTX *ctx, size_t n, const uint8_t *pk_seed, const SLH_ADRS adrs,
}
static int
slh_prf_sha2(SLH_HASH_CTX *hctx, const uint8_t *pk_seed,
slh_prf_sha2(SLH_DSA_HASH_CTX *hctx, const uint8_t *pk_seed,
const uint8_t *sk_seed, const SLH_ADRS adrs,
uint8_t *out, size_t out_len)
{
size_t n = hctx->n;
size_t n = hctx->key->params->n;
return do_hash(hctx->md_ctx, n, pk_seed, adrs, sk_seed, n,
SHA2_NUM_ZEROS_BOUND1, out, out_len);
OSSL_SLH_DSA_SHA2_NUM_ZEROS_H_AND_T_BOUND1, out, out_len);
}
static int
slh_f_sha2(SLH_HASH_CTX *hctx, const uint8_t *pk_seed, const SLH_ADRS adrs,
slh_f_sha2(SLH_DSA_HASH_CTX *hctx, const uint8_t *pk_seed, const SLH_ADRS adrs,
const uint8_t *m1, size_t m1_len, uint8_t *out, size_t out_len)
{
return do_hash(hctx->md_ctx, hctx->n, pk_seed, adrs, m1, m1_len,
SHA2_NUM_ZEROS_BOUND1, out, out_len);
return do_hash(hctx->md_ctx, hctx->key->params->n, pk_seed, adrs, m1, m1_len,
OSSL_SLH_DSA_SHA2_NUM_ZEROS_H_AND_T_BOUND1, out, out_len);
}
static int
slh_h_sha2(SLH_HASH_CTX *hctx, const uint8_t *pk_seed, const SLH_ADRS adrs,
slh_h_sha2(SLH_DSA_HASH_CTX *hctx, const uint8_t *pk_seed, const SLH_ADRS adrs,
const uint8_t *m1, const uint8_t *m2, uint8_t *out, size_t out_len)
{
uint8_t m[SLH_MAX_N * 2];
size_t n = hctx->n;
const SLH_DSA_PARAMS *prms = hctx->key->params;
size_t n = prms->n;
memcpy(m, m1, n);
memcpy(m + n, m2, n);
return do_hash(hctx->md_big_ctx, n, pk_seed, adrs, m, 2 * n,
hctx->sha2_h_and_t_bound, out, out_len);
prms->sha2_h_and_t_bound, out, out_len);
}
static int
slh_t_sha2(SLH_HASH_CTX *hctx, const uint8_t *pk_seed, const SLH_ADRS adrs,
slh_t_sha2(SLH_DSA_HASH_CTX *hctx, const uint8_t *pk_seed, const SLH_ADRS adrs,
const uint8_t *ml, size_t ml_len, uint8_t *out, size_t out_len)
{
return do_hash(hctx->md_big_ctx, hctx->n, pk_seed, adrs, ml, ml_len,
hctx->sha2_h_and_t_bound, out, out_len);
const SLH_DSA_PARAMS *prms = hctx->key->params;
return do_hash(hctx->md_big_ctx, prms->n, pk_seed, adrs, ml, ml_len,
prms->sha2_h_and_t_bound, out, out_len);
}
const SLH_HASH_FUNC *ossl_slh_get_hash_fn(int is_shake)

View File

@ -15,55 +15,39 @@
# include "slh_adrs.h"
# include "internal/packet.h"
# define SLH_HASH_FUNC_DECLARE(ctx, hashf, hashctx) \
# define SLH_HASH_FUNC_DECLARE(ctx, hashf) \
const SLH_HASH_FUNC *hashf = ctx->hash_func; \
SLH_HASH_CTX *hashctx = &ctx->hash_ctx
# define SLH_HASH_FN_DECLARE(hashf, t) OSSL_SLH_HASHFUNC_##t * t = hashf->t
/* See FIPS 205 Section 11.1 */
typedef struct slh_hash_ctx_st {
EVP_MD_CTX *md_ctx; /* Used for SHAKE and SHA-256 */
EVP_MD_CTX *md_big_ctx; /* Used for SHA-256 or SHA-512 */
EVP_MAC_CTX *hmac_ctx;
/* Stupid HMAC can't be set up early since the key is required */
const char *hmac_digest;
const char *hmac_propq;
EVP_MD *md; /* Used by the MGF1 */
size_t n; /* The output size of a HASH - this truncates in some cases */
size_t m; /* The output size of the HMSG */
size_t sha2_h_and_t_bound;
} SLH_HASH_CTX;
/*
* @params out is |m| bytes which ranges from (30..49) bytes
*/
typedef int (OSSL_SLH_HASHFUNC_H_MSG)(SLH_HASH_CTX *ctx, const uint8_t *r,
typedef int (OSSL_SLH_HASHFUNC_H_MSG)(SLH_DSA_HASH_CTX *ctx, const uint8_t *r,
const uint8_t *pk_seed, const uint8_t *pk_root,
const uint8_t *msg, size_t msg_len,
uint8_t *out, size_t out_len);
typedef int (OSSL_SLH_HASHFUNC_PRF)(SLH_HASH_CTX *ctx, const uint8_t *pk_seed,
typedef int (OSSL_SLH_HASHFUNC_PRF)(SLH_DSA_HASH_CTX *ctx, const uint8_t *pk_seed,
const uint8_t *sk_seed, const SLH_ADRS adrs,
uint8_t *out, size_t out_len);
typedef int (OSSL_SLH_HASHFUNC_PRF_MSG)(SLH_HASH_CTX *ctx, const uint8_t *sk_prf,
typedef int (OSSL_SLH_HASHFUNC_PRF_MSG)(SLH_DSA_HASH_CTX *ctx, const uint8_t *sk_prf,
const uint8_t *opt_rand,
const uint8_t *msg, size_t msg_len,
WPACKET *pkt);
typedef int (OSSL_SLH_HASHFUNC_F)(SLH_HASH_CTX *ctx, const uint8_t *pk_seed,
typedef int (OSSL_SLH_HASHFUNC_F)(SLH_DSA_HASH_CTX *ctx, const uint8_t *pk_seed,
const SLH_ADRS adrs,
const uint8_t *m1, size_t m1_len,
uint8_t *out, size_t out_len);
typedef int (OSSL_SLH_HASHFUNC_H)(SLH_HASH_CTX *ctx, const uint8_t *pk_seed,
typedef int (OSSL_SLH_HASHFUNC_H)(SLH_DSA_HASH_CTX *ctx, const uint8_t *pk_seed,
const SLH_ADRS adrs,
const uint8_t *m1, const uint8_t *m2,
uint8_t *out, size_t out_len);
typedef int (OSSL_SLH_HASHFUNC_T)(SLH_HASH_CTX *ctx, const uint8_t *pk_seed,
typedef int (OSSL_SLH_HASHFUNC_T)(SLH_DSA_HASH_CTX *ctx, const uint8_t *pk_seed,
const SLH_ADRS adrs,
const uint8_t *m1, size_t m1_len,
uint8_t *out, size_t out_len);
@ -79,9 +63,4 @@ typedef struct slh_hash_func_st {
const SLH_HASH_FUNC *ossl_slh_get_hash_fn(int is_shake);
__owur int ossl_slh_hash_ctx_init(SLH_HASH_CTX *ctx, OSSL_LIB_CTX *libctx,
const char *propq, int is_shake,
int security_category, size_t n, size_t m);
void ossl_slh_hash_ctx_cleanup(SLH_HASH_CTX *ctx);
#endif

View File

@ -10,12 +10,15 @@
#include <assert.h>
#include <string.h>
#include "slh_dsa_local.h"
#include "slh_dsa_key.h"
/**
* @brief Generate a Hypertree Signature
* See FIPS 205 Section 7.1 Algorithm 12
*
* This writes |d| XMSS signatures i.e. ((|h| + |d| * |len|) * |n|)
* where the first signature uses the XMSS key at the lowest layer, and the last
* signature uses the XMSS key at the top layer.
*
* @param ctx Contains SLH_DSA algorithm functions and constants.
* @param msg A message of size |n|.
@ -26,24 +29,39 @@
* @param sig_wpkt A WPACKET object to write the Hypertree Signature to.
* @returns 1 on success, or 0 on error.
*/
int ossl_slh_ht_sign(SLH_DSA_CTX *ctx,
int ossl_slh_ht_sign(SLH_DSA_HASH_CTX *ctx,
const uint8_t *msg, const uint8_t *sk_seed,
const uint8_t *pk_seed,
uint64_t tree_id, uint32_t leaf_id, WPACKET *sig_wpkt)
{
SLH_ADRS_FUNC_DECLARE(ctx, adrsf);
const SLH_DSA_KEY *key = ctx->key;
SLH_ADRS_FUNC_DECLARE(key, adrsf);
SLH_ADRS_DECLARE(adrs);
uint8_t root[SLH_MAX_N];
uint32_t layer, mask;
uint32_t n = ctx->params->n;
uint32_t d = ctx->params->d;
uint32_t hm = ctx->params->hm;
const SLH_DSA_PARAMS *params = key->params;
uint32_t n = params->n;
uint32_t d = params->d;
uint32_t hm = params->hm;
uint8_t *psig;
PACKET rpkt, *xmss_sig_rpkt = &rpkt;
mask = (1 << hm) - 1; /* A mod 2^h = A & ((2^h - 1))) */
adrsf->zero(adrs);
/*
* For each XMSS tree there is a current leaf node that is used for signing.
* The first iteration of the loop signs the input message using the bottom
* tree. Subsequent passes use the parent trees leaf node to sign the current
* trees public key.
* Each node in an XMSS tree has a sibling (except for the root node),
* so starting at the leaf node it traverses up the tree calculating
* hashes for all the siblings in the path to the root node,
* which are then stored in the XMSS signature. The verify then just needs
* the hash of the leaf node which is can then combine with the signature
* path hashes to work all the way up to the root node to calculate the
* public key.
*/
memcpy(root, msg, n);
for (layer = 0; layer < d; ++layer) {
@ -54,15 +72,21 @@ int ossl_slh_ht_sign(SLH_DSA_CTX *ctx,
if (!ossl_slh_xmss_sign(ctx, root, sk_seed, leaf_id, pk_seed, adrs,
sig_wpkt))
return 0;
if (!PACKET_buf_init(xmss_sig_rpkt, psig, WPACKET_get_curr(sig_wpkt) - psig))
return 0;
/*
* On the last loop it skips getting the public key since it is not needed
* to calculate another signature. If this was called it should equal
* the PK_ROOT (i.e. the public key of the top level tree).
*/
if (layer < d - 1) {
if (!PACKET_buf_init(xmss_sig_rpkt, psig,
WPACKET_get_curr(sig_wpkt) - psig))
return 0;
if (!ossl_slh_xmss_pk_from_sig(ctx, leaf_id, xmss_sig_rpkt, root,
pk_seed, adrs, root, sizeof(root)))
return 0;
leaf_id = tree_id & mask;
tree_id >>= hm;
}
leaf_id = tree_id & mask;
tree_id >>= hm;
}
return 1;
}
@ -81,14 +105,15 @@ int ossl_slh_ht_sign(SLH_DSA_CTX *ctx,
*
* @returns 1 if the computed XMSS public key matches pk_root, or 0 otherwise.
*/
int ossl_slh_ht_verify(SLH_DSA_CTX *ctx, const uint8_t *msg, PACKET *sig_pkt,
int ossl_slh_ht_verify(SLH_DSA_HASH_CTX *ctx, const uint8_t *msg, PACKET *sig_pkt,
const uint8_t *pk_seed, uint64_t tree_id, uint32_t leaf_id,
const uint8_t *pk_root)
{
SLH_ADRS_FUNC_DECLARE(ctx, adrsf);
const SLH_DSA_KEY *key = ctx->key;
SLH_ADRS_FUNC_DECLARE(key, adrsf);
SLH_ADRS_DECLARE(adrs);
uint8_t node[SLH_MAX_N];
const SLH_DSA_PARAMS *params = ctx->params;
const SLH_DSA_PARAMS *params = key->params;
uint32_t tree_height = params->hm;
uint32_t n = params->n;
uint32_t d = params->d;

View File

@ -10,30 +10,102 @@
#include <string.h>
#include "slh_params.h"
/*
* See FIPS 205 Section 11 Table 2
* n h d hm a k m sc pk sig
*/
#define OSSL_SLH_DSA_128S 16, 63, 7, 9, 12, 14, 30, 1, 32, 7856
#define OSSL_SLH_DSA_128F 16, 66, 22, 3, 6, 33, 34, 1, 32, 17088
#define OSSL_SLH_DSA_192S 24, 63, 7, 9, 14, 17, 39, 3, 48, 16224
#define OSSL_SLH_DSA_192F 24, 66, 22, 3, 8, 33, 42, 3, 48, 35664
#define OSSL_SLH_DSA_256S 32, 64, 8, 8, 14, 22, 47, 5, 64, 29792
#define OSSL_SLH_DSA_256F 32, 68, 17, 4, 9, 35, 49, 5, 64, 49856
/* H(), T() use this to calculate the number of zeros for security cat 3 & 5 */
#define OSSL_SLH_DSA_SHA2_NUM_ZEROS_H_AND_T_BOUND2 128
/* See FIPS 205 Section 11 Table 2 (n h d h` a k m sc pk sig*/
#define OSSL_SLH_DSA_128S_N 16
#define OSSL_SLH_DSA_128S_D 7
#define OSSL_SLH_DSA_128S_H_DASH 9
#define OSSL_SLH_DSA_128S_H (OSSL_SLH_DSA_128S_D * OSSL_SLH_DSA_128S_H_DASH)
#define OSSL_SLH_DSA_128S_A 12
#define OSSL_SLH_DSA_128S_K 14
#define OSSL_SLH_DSA_128S_M 30
#define OSSL_SLH_DSA_128S_SECURITY_CATEGORY 1
#define OSSL_SLH_DSA_128S_PUB_BYTES 32
#define OSSL_SLH_DSA_128S_SIG_BYTES 7856
#define OSSL_SLH_DSA_128F_N 16
#define OSSL_SLH_DSA_128F_D 22
#define OSSL_SLH_DSA_128F_H_DASH 3
#define OSSL_SLH_DSA_128F_H (OSSL_SLH_DSA_128F_D * OSSL_SLH_DSA_128F_H_DASH)
#define OSSL_SLH_DSA_128F_A 6
#define OSSL_SLH_DSA_128F_K 33
#define OSSL_SLH_DSA_128F_M 34
#define OSSL_SLH_DSA_128F_SECURITY_CATEGORY 1
#define OSSL_SLH_DSA_128F_PUB_BYTES 32
#define OSSL_SLH_DSA_128F_SIG_BYTES 17088
#define OSSL_SLH_DSA_192S_N 24
#define OSSL_SLH_DSA_192S_D 7
#define OSSL_SLH_DSA_192S_H_DASH 9
#define OSSL_SLH_DSA_192S_H (OSSL_SLH_DSA_192S_D * OSSL_SLH_DSA_192S_H_DASH)
#define OSSL_SLH_DSA_192S_A 14
#define OSSL_SLH_DSA_192S_K 17
#define OSSL_SLH_DSA_192S_M 39
#define OSSL_SLH_DSA_192S_SECURITY_CATEGORY 3
#define OSSL_SLH_DSA_192S_PUB_BYTES 48
#define OSSL_SLH_DSA_192S_SIG_BYTES 16224
#define OSSL_SLH_DSA_192F_N 24
#define OSSL_SLH_DSA_192F_D 22
#define OSSL_SLH_DSA_192F_H_DASH 3
#define OSSL_SLH_DSA_192F_H (OSSL_SLH_DSA_192F_D * OSSL_SLH_DSA_192F_H_DASH)
#define OSSL_SLH_DSA_192F_A 8
#define OSSL_SLH_DSA_192F_K 33
#define OSSL_SLH_DSA_192F_M 42
#define OSSL_SLH_DSA_192F_SECURITY_CATEGORY 3
#define OSSL_SLH_DSA_192F_PUB_BYTES 48
#define OSSL_SLH_DSA_192F_SIG_BYTES 35664
#define OSSL_SLH_DSA_256S_N 32
#define OSSL_SLH_DSA_256S_D 8
#define OSSL_SLH_DSA_256S_H_DASH 8
#define OSSL_SLH_DSA_256S_H (OSSL_SLH_DSA_256S_D * OSSL_SLH_DSA_256S_H_DASH)
#define OSSL_SLH_DSA_256S_A 14
#define OSSL_SLH_DSA_256S_K 22
#define OSSL_SLH_DSA_256S_M 47
#define OSSL_SLH_DSA_256S_SECURITY_CATEGORY 5
#define OSSL_SLH_DSA_256S_PUB_BYTES 64
#define OSSL_SLH_DSA_256S_SIG_BYTES 29792
#define OSSL_SLH_DSA_256F_N 32
#define OSSL_SLH_DSA_256F_D 17
#define OSSL_SLH_DSA_256F_H_DASH 4
#define OSSL_SLH_DSA_256F_H (OSSL_SLH_DSA_256F_D * OSSL_SLH_DSA_256F_H_DASH)
#define OSSL_SLH_DSA_256F_A 9
#define OSSL_SLH_DSA_256F_K 35
#define OSSL_SLH_DSA_256F_M 49
#define OSSL_SLH_DSA_256F_SECURITY_CATEGORY 5
#define OSSL_SLH_DSA_256F_PUB_BYTES 64
#define OSSL_SLH_DSA_256F_SIG_BYTES 49856
#define OSSL_SLH_PARAMS(name) \
OSSL_SLH_DSA_##name##_N, \
OSSL_SLH_DSA_##name##_H, \
OSSL_SLH_DSA_##name##_D, \
OSSL_SLH_DSA_##name##_H_DASH, \
OSSL_SLH_DSA_##name##_A, \
OSSL_SLH_DSA_##name##_K, \
OSSL_SLH_DSA_##name##_M, \
OSSL_SLH_DSA_##name##_SECURITY_CATEGORY, \
OSSL_SLH_DSA_##name##_PUB_BYTES, \
OSSL_SLH_DSA_##name##_SIG_BYTES \
static const SLH_DSA_PARAMS slh_dsa_params[] = {
{"SLH-DSA-SHA2-128s", 0, OSSL_SLH_DSA_128S},
{"SLH-DSA-SHAKE-128s", 1, OSSL_SLH_DSA_128S},
{"SLH-DSA-SHA2-128f", 0, OSSL_SLH_DSA_128F},
{"SLH-DSA-SHAKE-128f", 1, OSSL_SLH_DSA_128F},
{"SLH-DSA-SHA2-192s", 0, OSSL_SLH_DSA_192S},
{"SLH-DSA-SHAKE-192s", 1, OSSL_SLH_DSA_192S},
{"SLH-DSA-SHA2-192f", 0, OSSL_SLH_DSA_192F},
{"SLH-DSA-SHAKE-192f", 1, OSSL_SLH_DSA_192F},
{"SLH-DSA-SHA2-256s", 0, OSSL_SLH_DSA_256S},
{"SLH-DSA-SHAKE-256s", 1, OSSL_SLH_DSA_256S},
{"SLH-DSA-SHA2-256f", 0, OSSL_SLH_DSA_256F},
{"SLH-DSA-SHAKE-256f", 1, OSSL_SLH_DSA_256F},
{"SLH-DSA-SHA2-128s", 0, OSSL_SLH_PARAMS(128S), OSSL_SLH_DSA_SHA2_NUM_ZEROS_H_AND_T_BOUND1},
{"SLH-DSA-SHAKE-128s", 1, OSSL_SLH_PARAMS(128S)},
{"SLH-DSA-SHA2-128f", 0, OSSL_SLH_PARAMS(128F), OSSL_SLH_DSA_SHA2_NUM_ZEROS_H_AND_T_BOUND1},
{"SLH-DSA-SHAKE-128f", 1, OSSL_SLH_PARAMS(128F)},
{"SLH-DSA-SHA2-192s", 0, OSSL_SLH_PARAMS(192S), OSSL_SLH_DSA_SHA2_NUM_ZEROS_H_AND_T_BOUND2},
{"SLH-DSA-SHAKE-192s", 1, OSSL_SLH_PARAMS(192S)},
{"SLH-DSA-SHA2-192f", 0, OSSL_SLH_PARAMS(192F), OSSL_SLH_DSA_SHA2_NUM_ZEROS_H_AND_T_BOUND2},
{"SLH-DSA-SHAKE-192f", 1, OSSL_SLH_PARAMS(192F)},
{"SLH-DSA-SHA2-256s", 0, OSSL_SLH_PARAMS(256S), OSSL_SLH_DSA_SHA2_NUM_ZEROS_H_AND_T_BOUND2},
{"SLH-DSA-SHAKE-256s", 1, OSSL_SLH_PARAMS(256S)},
{"SLH-DSA-SHA2-256f", 0, OSSL_SLH_PARAMS(256F), OSSL_SLH_DSA_SHA2_NUM_ZEROS_H_AND_T_BOUND2},
{"SLH-DSA-SHAKE-256f", 1, OSSL_SLH_PARAMS(256F)},
{NULL},
};

View File

@ -9,6 +9,12 @@
#include <openssl/e_os2.h>
/*
* PRF(), F() use this value to calculate the number of zeros
* H(), T() use this to calculate the number of zeros for security cat 1
*/
#define OSSL_SLH_DSA_SHA2_NUM_ZEROS_H_AND_T_BOUND1 64
/*
* Refer to FIPS 205 Section 11 parameter sets.
* lgw has been omitted since it is 4 for all algorithms i.e. log(16)
@ -26,6 +32,7 @@ typedef struct slh_dsa_params_st {
uint32_t security_category;
uint32_t pk_len;
uint32_t sig_len;
size_t sha2_h_and_t_bound;
} SLH_DSA_PARAMS;
const SLH_DSA_PARAMS *ossl_slh_dsa_params_get(const char *alg);

View File

@ -11,6 +11,7 @@
#include <string.h>
#include <openssl/crypto.h>
#include "slh_dsa_local.h"
#include "slh_dsa_key.h"
/* For the parameter sets defined there is only one w value */
#define SLH_WOTS_LOGW 4
@ -92,16 +93,17 @@ static ossl_inline void compute_checksum_nibbles(const uint8_t *in, size_t in_le
* @params wpkt A WPACKET object to write the hash chain to (n bytes are written)
* @returns 1 on success, or 0 on error.
*/
static int slh_wots_chain(SLH_DSA_CTX *ctx, const uint8_t *in,
static int slh_wots_chain(SLH_DSA_HASH_CTX *ctx, const uint8_t *in,
uint8_t start_index, uint8_t steps,
const uint8_t *pk_seed, uint8_t *adrs, WPACKET *wpkt)
{
SLH_HASH_FUNC_DECLARE(ctx, hashf, hctx);
SLH_ADRS_FUNC_DECLARE(ctx, adrsf);
const SLH_DSA_KEY *key = ctx->key;
SLH_HASH_FUNC_DECLARE(key, hashf);
SLH_ADRS_FUNC_DECLARE(key, adrsf);
SLH_HASH_FN_DECLARE(hashf, F);
SLH_ADRS_FN_DECLARE(adrsf, set_hash_address);
size_t j = start_index, end_index;
size_t n = ctx->params->n;
size_t n = key->params->n;
uint8_t *tmp; /* Pointer into the |wpkt| buffer */
size_t tmp_len = n;
@ -112,13 +114,13 @@ static int slh_wots_chain(SLH_DSA_CTX *ctx, const uint8_t *in,
return 0;
set_hash_address(adrs, j++);
if (!F(hctx, pk_seed, adrs, in, n, tmp, tmp_len))
if (!F(ctx, pk_seed, adrs, in, n, tmp, tmp_len))
return 0;
end_index = start_index + steps;
for (; j < end_index; ++j) {
set_hash_address(adrs, j);
if (!F(hctx, pk_seed, adrs, tmp, n, tmp, tmp_len))
if (!F(ctx, pk_seed, adrs, tmp, n, tmp, tmp_len))
return 0;
}
return 1;
@ -137,20 +139,21 @@ static int slh_wots_chain(SLH_DSA_CTX *ctx, const uint8_t *in,
* @param pk_out_len The maximum size of |pk_out|
* @returns 1 on success, or 0 on error.
*/
int ossl_slh_wots_pk_gen(SLH_DSA_CTX *ctx,
int ossl_slh_wots_pk_gen(SLH_DSA_HASH_CTX *ctx,
const uint8_t *sk_seed, const uint8_t *pk_seed,
SLH_ADRS adrs, uint8_t *pk_out, size_t pk_out_len)
{
int ret = 0;
size_t n = ctx->params->n;
const SLH_DSA_KEY *key = ctx->key;
size_t n = key->params->n;
size_t i, len = SLH_WOTS_LEN(n); /* 2 * n + 3 */
uint8_t sk[SLH_MAX_N];
uint8_t tmp[SLH_WOTS_LEN_MAX * SLH_MAX_N];
WPACKET pkt, *tmp_wpkt = &pkt; /* Points to the |tmp| buffer */
size_t tmp_len = 0;
SLH_HASH_FUNC_DECLARE(ctx, hashf, hctx);
SLH_ADRS_FUNC_DECLARE(ctx, adrsf);
SLH_HASH_FUNC_DECLARE(key, hashf);
SLH_ADRS_FUNC_DECLARE(key, adrsf);
SLH_HASH_FN_DECLARE(hashf, PRF);
SLH_ADRS_FN_DECLARE(adrsf, set_chain_address);
SLH_ADRS_DECLARE(sk_adrs);
@ -164,7 +167,7 @@ int ossl_slh_wots_pk_gen(SLH_DSA_CTX *ctx,
for (i = 0; i < len; ++i) { /* len = 2n + 3 */
set_chain_address(sk_adrs, i);
if (!PRF(hctx, pk_seed, sk_seed, sk_adrs, sk, sizeof(sk)))
if (!PRF(ctx, pk_seed, sk_seed, sk_adrs, sk, sizeof(sk)))
goto end;
set_chain_address(adrs, i);
@ -177,8 +180,7 @@ int ossl_slh_wots_pk_gen(SLH_DSA_CTX *ctx,
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);
ret = hashf->T(hctx, pk_seed, wots_pk_adrs, tmp, tmp_len,
pk_out, pk_out_len);
ret = hashf->T(ctx, pk_seed, wots_pk_adrs, tmp, tmp_len, pk_out, pk_out_len);
end:
WPACKET_finish(tmp_wpkt);
OPENSSL_cleanse(tmp, sizeof(tmp));
@ -202,21 +204,22 @@ end:
* @param sig_wpkt A WPACKET object to write the signature to.
* @returns 1 on success, or 0 on error.
*/
int ossl_slh_wots_sign(SLH_DSA_CTX *ctx, const uint8_t *msg,
int ossl_slh_wots_sign(SLH_DSA_HASH_CTX *ctx, const uint8_t *msg,
const uint8_t *sk_seed, const uint8_t *pk_seed,
SLH_ADRS adrs, WPACKET *sig_wpkt)
{
int ret = 0;
const SLH_DSA_KEY *key = ctx->key;
uint8_t msg_and_csum_nibbles[SLH_WOTS_LEN_MAX]; /* size is >= 2 * n + 3 */
uint8_t sk[SLH_MAX_N];
size_t i;
size_t n = ctx->params->n;
size_t n = key->params->n;
size_t len1 = SLH_WOTS_LEN1(n); /* 2 * n = the msg length in nibbles */
size_t len = len1 + SLH_WOTS_LEN2; /* 2 * n + 3 (3 checksum nibbles) */
SLH_ADRS_DECLARE(sk_adrs);
SLH_HASH_FUNC_DECLARE(ctx, hashf, hctx);
SLH_ADRS_FUNC_DECLARE(ctx, adrsf);
SLH_HASH_FUNC_DECLARE(key, hashf);
SLH_ADRS_FUNC_DECLARE(key, adrsf);
SLH_HASH_FN_DECLARE(hashf, PRF);
SLH_ADRS_FN_DECLARE(adrsf, set_chain_address);
@ -235,7 +238,7 @@ int ossl_slh_wots_sign(SLH_DSA_CTX *ctx, const uint8_t *msg,
for (i = 0; i < len; ++i) {
set_chain_address(sk_adrs, i);
/* compute chain i secret */
if (!PRF(hctx, pk_seed, sk_seed, sk_adrs, sk, sizeof(sk)))
if (!PRF(ctx, pk_seed, sk_seed, sk_adrs, sk, sizeof(sk)))
goto err;
set_chain_address(adrs, i);
/* compute chain i signature */
@ -264,15 +267,16 @@ err:
* @param pk_out_len The maximum size of |pk_out|
* @returns 1 on success, or 0 on error.
*/
int ossl_slh_wots_pk_from_sig(SLH_DSA_CTX *ctx,
int ossl_slh_wots_pk_from_sig(SLH_DSA_HASH_CTX *ctx,
PACKET *sig_rpkt, const uint8_t *msg,
const uint8_t *pk_seed, uint8_t *adrs,
uint8_t *pk_out, size_t pk_out_len)
{
int ret = 0;
const SLH_DSA_KEY *key = ctx->key;
uint8_t msg_and_csum_nibbles[SLH_WOTS_LEN_MAX];
size_t i;
size_t n = ctx->params->n;
size_t n = key->params->n;
size_t len1 = SLH_WOTS_LEN1(n);
size_t len = len1 + SLH_WOTS_LEN2; /* 2n + 3 */
const uint8_t *sig_i; /* Pointer into |sig_rpkt| buffer */
@ -280,8 +284,8 @@ int ossl_slh_wots_pk_from_sig(SLH_DSA_CTX *ctx,
WPACKET pkt, *tmp_pkt = &pkt;
size_t tmp_len = 0;
SLH_HASH_FUNC_DECLARE(ctx, hashf, hctx);
SLH_ADRS_FUNC_DECLARE(ctx, adrsf);
SLH_HASH_FUNC_DECLARE(key, hashf);
SLH_ADRS_FUNC_DECLARE(key, adrsf);
SLH_ADRS_FN_DECLARE(adrsf, set_chain_address);
SLH_ADRS_DECLARE(wots_pk_adrs);
@ -306,7 +310,7 @@ int ossl_slh_wots_pk_from_sig(SLH_DSA_CTX *ctx,
adrsf->copy_keypair_address(wots_pk_adrs, adrs);
if (!WPACKET_get_total_written(tmp_pkt, &tmp_len))
goto err;
ret = hashf->T(hctx, pk_seed, wots_pk_adrs, tmp, tmp_len,
ret = hashf->T(ctx, pk_seed, wots_pk_adrs, tmp, tmp_len,
pk_out, pk_out_len);
err:
if (!WPACKET_finish(tmp_pkt))

View File

@ -10,6 +10,7 @@
#include <assert.h>
#include <string.h>
#include "slh_dsa_local.h"
#include "slh_dsa_key.h"
/**
* @brief Compute the root Public key of a XMSS tree.
@ -32,12 +33,13 @@
* @param pk_out_len The maximum size of |pk_out|
* @returns 1 on success, or 0 on error.
*/
int ossl_slh_xmss_node(SLH_DSA_CTX *ctx, const uint8_t *sk_seed,
int ossl_slh_xmss_node(SLH_DSA_HASH_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, size_t pk_out_len)
{
SLH_ADRS_FUNC_DECLARE(ctx, adrsf);
const SLH_DSA_KEY *key = ctx->key;
SLH_ADRS_FUNC_DECLARE(key, adrsf);
if (h == 0) {
/* For leaf nodes generate the public key */
@ -57,8 +59,7 @@ int ossl_slh_xmss_node(SLH_DSA_CTX *ctx, const uint8_t *sk_seed,
adrsf->set_type_and_clear(adrs, SLH_ADRS_TYPE_TREE);
adrsf->set_tree_height(adrs, h);
adrsf->set_tree_index(adrs, node_id);
if (!ctx->hash_func->H(&ctx->hash_ctx, pk_seed, adrs, lnode, rnode,
pk_out, pk_out_len))
if (!key->hash_func->H(ctx, pk_seed, adrs, lnode, rnode, pk_out, pk_out_len))
return 0;
}
return 1;
@ -82,14 +83,15 @@ int ossl_slh_xmss_node(SLH_DSA_CTX *ctx, const uint8_t *sk_seed,
* @param sig_wpkt A WPACKET object to write the generated XMSS signature to.
* @returns 1 on success, or 0 on error.
*/
int ossl_slh_xmss_sign(SLH_DSA_CTX *ctx, const uint8_t *msg,
int ossl_slh_xmss_sign(SLH_DSA_HASH_CTX *ctx, const uint8_t *msg,
const uint8_t *sk_seed, uint32_t node_id,
const uint8_t *pk_seed, SLH_ADRS adrs, WPACKET *sig_wpkt)
{
SLH_ADRS_FUNC_DECLARE(ctx, adrsf);
const SLH_DSA_KEY *key = ctx->key;
SLH_ADRS_FUNC_DECLARE(key, adrsf);
SLH_ADRS_DECLARE(tmp_adrs);
size_t n = ctx->params->n;
uint32_t h, hm = ctx->params->hm;
size_t n = key->params->n;
uint32_t h, hm = key->params->hm;
uint32_t id = node_id;
uint8_t *auth_path; /* Pointer to a buffer offset inside |sig_wpkt| */
size_t auth_path_len = n;
@ -135,19 +137,20 @@ int ossl_slh_xmss_sign(SLH_DSA_CTX *ctx, const uint8_t *msg,
* @param pk_out_len The maximum size of |pk_out|.
* @returns 1 on success, or 0 on error.
*/
int ossl_slh_xmss_pk_from_sig(SLH_DSA_CTX *ctx, uint32_t node_id,
int ossl_slh_xmss_pk_from_sig(SLH_DSA_HASH_CTX *ctx, uint32_t node_id,
PACKET *sig_rpkt, const uint8_t *msg,
const uint8_t *pk_seed, SLH_ADRS adrs,
uint8_t *pk_out, size_t pk_out_len)
{
SLH_HASH_FUNC_DECLARE(ctx, hashf, hctx);
const SLH_DSA_KEY *key = ctx->key;
SLH_HASH_FUNC_DECLARE(key, hashf);
SLH_ADRS_FUNC_DECLARE(key, adrsf);
SLH_HASH_FN_DECLARE(hashf, H);
SLH_ADRS_FUNC_DECLARE(ctx, adrsf);
SLH_ADRS_FN_DECLARE(adrsf, set_tree_index);
SLH_ADRS_FN_DECLARE(adrsf, set_tree_height);
uint32_t k;
size_t n = ctx->params->n;
uint32_t hm = ctx->params->hm;
size_t n = key->params->n;
uint32_t hm = key->params->hm;
uint8_t *node = pk_out;
const uint8_t *auth_path; /* Pointer to buffer offset in |pkt_sig| */
@ -166,12 +169,12 @@ int ossl_slh_xmss_pk_from_sig(SLH_DSA_CTX *ctx, uint32_t node_id,
if ((node_id & 1) == 0) { /* even */
node_id >>= 1;
set_tree_index(adrs, node_id);
if (!H(hctx, pk_seed, adrs, node, auth_path, node, pk_out_len))
if (!H(ctx, pk_seed, adrs, node, auth_path, node, pk_out_len))
return 0;
} else { /* odd */
node_id = (node_id - 1) >> 1;
set_tree_index(adrs, node_id);
if (!H(hctx, pk_seed, adrs, auth_path, node, node, pk_out_len))
if (!H(ctx, pk_seed, adrs, auth_path, node, node, pk_out_len))
return 0;
}
}

View File

@ -30,12 +30,12 @@ There are many functions required to implement the sign and verify paths, which
Merkle trees and WOTS+. The different functions normally call one of 2 of the
7 hash functions, as well as calling ADRS functions to pass to the HASH functions.
Rather that duplicating this code 12 times for every function, instead a
SLH_DSA_CTX object is created.
This contains the HASH functions, the ADRS functions, and the parameter constants.
It also contains pre fetched algorithms.
This SLH_DSA_CTX is then passed to all functions. This context is allocated in the
Rather that duplicating this code 12 times for every function, the constants are
stored within the SLH_DSA_KEY. This contains the HASH functions,
the ADRS functions, and the parameter constants. It also contains pre fetched algorithms.
A SLH_DSA_HASH_CTX object is also created, that references the key, as well as
containing per operation hash context objects.
This SLH_DSA_HASH_CTX is then passed to all functions. This context is allocated in the
providers SLH_DSA signature context.
SLH-DSA keys
@ -54,6 +54,7 @@ struct slh_dsa_key_st {
/* contains the algorithm name and constants such as |n| */
const SLH_DSA_PARAMS *params;
int has_priv; /* Set to 1 if there is a private key component */
...
};
The fields 'key_len' and 'has_priv' are used to determine if a key has loaded

View File

@ -66,21 +66,20 @@ The default value of 1 uses 'Pure SLH-DSA Signature Generation' as described
above. Setting it to 0 does not encode the message, which is used for testing,
but can also be used for 'Pre Hash SLH-DSA Signature Generation'.
=item "additional-random" (B<OSSL_SIGNATURE_PARAM_ADD_RANDOM <octet string>
=item "test-entropy" (B<OSSL_SIGNATURE_PARAM_TEST_ENTROPY <octet string>
Used for testing to pass a optional random value.
=item "deterministic" (B<OSSL_SIGNATURE_PARAM_DETERMINISTIC>) <integer>
The default value of 0 causes an randomly generated additional random value
to be used when processing the message. Setting this to 1 causes the private key
seed to be used instead. This value is ignored if "additional-random" is set.
The default value of 0 generates a random value (using a DRBG) this is used when
processing the message. Setting this to 1 causes the private key seed to be used
instead. This value is ignored if "test-entropy" is set.
=back
See L<EVP_PKEY-SLH-DSA(7)> for information related to B<SLH-DSA> keys.
=head1 EXAMPLES
To sign a message using an SLH-DSA EVP_PKEY structure:
@ -120,7 +119,7 @@ This functionality was added in OpenSSL 3.5.
=head1 COPYRIGHT
Copyright 2024 The OpenSSL Project Authors. All Rights Reserved.
Copyright 2024-2025 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

View File

@ -19,20 +19,20 @@
# define SLH_DSA_MAX_CONTEXT_STRING_LEN 255
typedef struct slh_dsa_ctx_st SLH_DSA_CTX;
typedef struct slh_dsa_hash_ctx_st SLH_DSA_HASH_CTX;
__owur SLH_DSA_KEY *ossl_slh_dsa_key_new(OSSL_LIB_CTX *libctx, const char *alg);
__owur SLH_DSA_KEY *ossl_slh_dsa_key_new(OSSL_LIB_CTX *libctx, const char *propq,
const char *alg);
void ossl_slh_dsa_key_free(SLH_DSA_KEY *key);
__owur int ossl_slh_dsa_key_up_ref(SLH_DSA_KEY *key);
__owur int ossl_slh_dsa_key_equal(const SLH_DSA_KEY *key1, const SLH_DSA_KEY *key2,
int selection);
__owur int ossl_slh_dsa_key_has(const SLH_DSA_KEY *key, int selection);
__owur int ossl_slh_dsa_key_pairwise_check(const SLH_DSA_KEY *key);
__owur int ossl_slh_dsa_key_fromdata(SLH_DSA_KEY *key, const OSSL_PARAM *params,
int include_private);
__owur int ossl_slh_dsa_generate_key(SLH_DSA_CTX *ctx, OSSL_LIB_CTX *libctx,
const uint8_t *entropy, size_t entropy_len,
SLH_DSA_KEY *out);
__owur int ossl_slh_dsa_generate_key(SLH_DSA_HASH_CTX *ctx, SLH_DSA_KEY *out,
OSSL_LIB_CTX *libctx,
const uint8_t *entropy, size_t entropy_len);
__owur int ossl_slh_dsa_key_to_text(BIO *out, const SLH_DSA_KEY *key, int selection);
__owur const uint8_t *ossl_slh_dsa_key_get_pub(const SLH_DSA_KEY *key);
__owur const uint8_t *ossl_slh_dsa_key_get_priv(const SLH_DSA_KEY *key);
@ -45,23 +45,22 @@ __owur size_t ossl_slh_dsa_key_get_priv_len(const SLH_DSA_KEY *key);
__owur size_t ossl_slh_dsa_key_get_n(const SLH_DSA_KEY *key);
__owur size_t ossl_slh_dsa_key_get_sig_len(const SLH_DSA_KEY *key);
__owur const char *ossl_slh_dsa_key_get_name(const SLH_DSA_KEY *key);
__owur int ossl_slh_dsa_key_type_matches(SLH_DSA_CTX *ctx, const SLH_DSA_KEY *key);
__owur int ossl_slh_dsa_key_type_matches(const SLH_DSA_KEY *key, const char *alg);
__owur int ossl_slh_dsa_key_to_text(BIO *out, const SLH_DSA_KEY *key, int selection);
void ossl_slh_dsa_key_set0_libctx(SLH_DSA_KEY *key, OSSL_LIB_CTX *lib_ctx);
SLH_DSA_KEY *ossl_slh_dsa_key_from_pkcs8(const PKCS8_PRIV_KEY_INFO *p8inf,
OSSL_LIB_CTX *libctx, const char *propq);
SLH_DSA_KEY *ossl_evp_pkey_get1_SLH_DSA_KEY(EVP_PKEY *pkey);
__owur SLH_DSA_CTX *ossl_slh_dsa_ctx_new(const char *alg,
OSSL_LIB_CTX *lib_ctx, const char *propq);
void ossl_slh_dsa_ctx_free(SLH_DSA_CTX *ctx);
__owur SLH_DSA_HASH_CTX *ossl_slh_dsa_hash_ctx_new(const SLH_DSA_KEY *key);
void ossl_slh_dsa_hash_ctx_free(SLH_DSA_HASH_CTX *ctx);
__owur int ossl_slh_dsa_sign(SLH_DSA_CTX *slh_ctx, const SLH_DSA_KEY *priv,
__owur int ossl_slh_dsa_sign(SLH_DSA_HASH_CTX *slh_ctx,
const uint8_t *msg, size_t msg_len,
const uint8_t *ctx, size_t ctx_len,
const uint8_t *add_rand, int encode,
unsigned char *sig, size_t *siglen, size_t sigsize);
__owur int ossl_slh_dsa_verify(SLH_DSA_CTX *slh_ctx, const SLH_DSA_KEY *pub,
__owur int ossl_slh_dsa_verify(SLH_DSA_HASH_CTX *slh_ctx,
const uint8_t *msg, size_t msg_len,
const uint8_t *ctx, size_t ctx_len, int encode,
const uint8_t *sig, size_t sig_len);

View File

@ -36,7 +36,7 @@ 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 {
SLH_DSA_CTX *ctx;
SLH_DSA_HASH_CTX *ctx;
OSSL_LIB_CTX *libctx;
char *propq;
uint8_t entropy[32 * 3];
@ -48,7 +48,7 @@ static void *slh_dsa_new_key(void *provctx, const char *alg)
if (!ossl_prov_is_running())
return 0;
return ossl_slh_dsa_key_new(PROV_LIBCTX_OF(provctx), alg);
return ossl_slh_dsa_key_new(PROV_LIBCTX_OF(provctx), NULL, alg);
}
static void slh_dsa_free_key(void *keydata)
@ -267,7 +267,8 @@ static void *slh_dsa_gen_init(void *provctx, int selection,
* Refer to FIPS 140-3 IG 10.3.A Additional Comment 1
* Perform a pairwise test for SLH_DSA by signing and verifying a signature.
*/
static int slh_dsa_fips140_pairwise_test(SLH_DSA_CTX *ctx, const SLH_DSA_KEY *key,
static int slh_dsa_fips140_pairwise_test(SLH_DSA_HASH_CTX *ctx,
const SLH_DSA_KEY *key,
OSSL_LIB_CTX *lib_ctx)
{
int ret = 0;
@ -292,13 +293,13 @@ static int slh_dsa_fips140_pairwise_test(SLH_DSA_CTX *ctx, const SLH_DSA_KEY *ke
if (sig == NULL)
goto err;
if (ossl_slh_dsa_sign(ctx, key, msg, msg_len, NULL, 0, NULL, 0,
if (ossl_slh_dsa_sign(ctx, msg, msg_len, NULL, 0, NULL, 0,
sig, &sig_len, sig_len) != 1)
goto err;
OSSL_SELF_TEST_oncorrupt_byte(st, sig);
if (ossl_slh_dsa_verify(ctx, key, msg, msg_len, NULL, 0, 0, sig, sig_len) != 1)
if (ossl_slh_dsa_verify(ctx, msg, msg_len, NULL, 0, 0, sig, sig_len) != 1)
goto err;
ret = 1;
@ -314,27 +315,27 @@ 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;
SLH_DSA_HASH_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);
key = ossl_slh_dsa_key_new(gctx->libctx, gctx->propq, alg);
if (key == NULL)
return NULL;
if (!ossl_slh_dsa_generate_key(ctx, gctx->libctx,
gctx->entropy, gctx->entropy_len, key))
ctx = ossl_slh_dsa_hash_ctx_new(key);
if (ctx == NULL)
return NULL;
if (!ossl_slh_dsa_generate_key(ctx, key, gctx->libctx,
gctx->entropy, gctx->entropy_len))
goto err;
#ifdef FIPS_MODULE
if (!slh_dsa_fips140_pairwise_test(ctx, key, gctx->libctx))
goto err;
#endif /* FIPS_MODULE */
ossl_slh_dsa_ctx_free(ctx);
ossl_slh_dsa_hash_ctx_free(ctx);
return key;
err:
ossl_slh_dsa_ctx_free(ctx);
ossl_slh_dsa_hash_ctx_free(ctx);
ossl_slh_dsa_key_free(key);
return NULL;
}

View File

@ -33,8 +33,8 @@ static OSSL_FUNC_signature_set_ctx_params_fn slh_set_ctx_params;
static OSSL_FUNC_signature_settable_ctx_params_fn slh_settable_ctx_params;
typedef struct {
SLH_DSA_KEY *key;
SLH_DSA_CTX *ctx;
SLH_DSA_KEY *key; /* Note that the key is not owned by this object */
SLH_DSA_HASH_CTX *hash_ctx;
uint8_t context_string[SLH_DSA_MAX_CONTEXT_STRING_LEN];
size_t context_string_len;
uint8_t add_random[SLH_DSA_MAX_ADD_RANDOM_LEN];
@ -43,38 +43,35 @@ typedef struct {
int deterministic;
OSSL_LIB_CTX *libctx;
char *propq;
} PROV_SLH_DSA_CTX;
const char *alg;
} PROV_SLH_DSA_HASH_CTX;
static void slh_freectx(void *vctx)
{
PROV_SLH_DSA_CTX *ctx = (PROV_SLH_DSA_CTX *)vctx;
PROV_SLH_DSA_HASH_CTX *ctx = (PROV_SLH_DSA_HASH_CTX *)vctx;
ossl_slh_dsa_hash_ctx_free(ctx->hash_ctx);
OPENSSL_free(ctx->propq);
ossl_slh_dsa_ctx_free(ctx->ctx);
ossl_slh_dsa_key_free(ctx->key);
OPENSSL_cleanse(ctx->add_random, ctx->add_random_len);
OPENSSL_free(ctx);
}
static void *slh_newctx(void *provctx, const char *alg, const char *propq)
{
PROV_SLH_DSA_CTX *ctx;
PROV_SLH_DSA_HASH_CTX *ctx;
if (!ossl_prov_is_running())
return NULL;
ctx = OPENSSL_zalloc(sizeof(PROV_SLH_DSA_CTX));
ctx = OPENSSL_zalloc(sizeof(PROV_SLH_DSA_HASH_CTX));
if (ctx == NULL)
return NULL;
ctx->libctx = PROV_LIBCTX_OF(provctx);
if (propq != NULL && (ctx->propq = OPENSSL_strdup(propq)) == NULL)
goto err;
ctx->ctx = ossl_slh_dsa_ctx_new(alg, ctx->libctx, ctx->propq);
if (ctx->ctx == NULL)
goto err;
ctx->alg = alg;
ctx->msg_encode = SLH_DSA_MESSAGE_ENCODE_PURE;
return ctx;
err:
slh_freectx(ctx);
@ -85,7 +82,7 @@ static int slh_signverify_msg_init(void *vctx, void *vkey,
const OSSL_PARAM params[], int operation,
const char *desc)
{
PROV_SLH_DSA_CTX *ctx = (PROV_SLH_DSA_CTX *)vctx;
PROV_SLH_DSA_HASH_CTX *ctx = (PROV_SLH_DSA_HASH_CTX *)vctx;
SLH_DSA_KEY *key = vkey;
if (!ossl_prov_is_running()
@ -98,11 +95,11 @@ static int slh_signverify_msg_init(void *vctx, void *vkey,
}
if (key != NULL) {
if (!ossl_slh_dsa_key_type_matches(ctx->ctx, key))
if (!ossl_slh_dsa_key_type_matches(key, ctx->alg))
return 0;
if (!ossl_slh_dsa_key_up_ref(vkey))
ctx->hash_ctx = ossl_slh_dsa_hash_ctx_new(key);
if (ctx->hash_ctx == NULL)
return 0;
ossl_slh_dsa_key_free(ctx->key);
ctx->key = vkey;
}
@ -121,7 +118,7 @@ static int slh_sign(void *vctx, unsigned char *sig, size_t *siglen,
size_t sigsize, const unsigned char *msg, size_t msg_len)
{
int ret = 0;
PROV_SLH_DSA_CTX *ctx = (PROV_SLH_DSA_CTX *)vctx;
PROV_SLH_DSA_HASH_CTX *ctx = (PROV_SLH_DSA_HASH_CTX *)vctx;
uint8_t add_rand[SLH_DSA_MAX_ADD_RANDOM_LEN], *opt_rand = NULL;
size_t n = 0;
@ -138,7 +135,7 @@ static int slh_sign(void *vctx, unsigned char *sig, size_t *siglen,
opt_rand = add_rand;
}
}
ret = ossl_slh_dsa_sign(ctx->ctx, ctx->key, msg, msg_len,
ret = ossl_slh_dsa_sign(ctx->hash_ctx, msg, msg_len,
ctx->context_string, ctx->context_string_len,
opt_rand, ctx->msg_encode,
sig, siglen, sigsize);
@ -156,11 +153,11 @@ static int slh_verify_msg_init(void *vctx, void *vkey, const OSSL_PARAM params[]
static int slh_verify(void *vctx, const unsigned char *sig, size_t siglen,
const unsigned char *msg, size_t msg_len)
{
PROV_SLH_DSA_CTX *ctx = (PROV_SLH_DSA_CTX *)vctx;
PROV_SLH_DSA_HASH_CTX *ctx = (PROV_SLH_DSA_HASH_CTX *)vctx;
if (!ossl_prov_is_running())
return 0;
return ossl_slh_dsa_verify(ctx->ctx, ctx->key, msg, msg_len,
return ossl_slh_dsa_verify(ctx->hash_ctx, msg, msg_len,
ctx->context_string, ctx->context_string_len,
ctx->msg_encode, sig, siglen);
@ -169,7 +166,7 @@ static int slh_verify(void *vctx, const unsigned char *sig, size_t siglen,
static int slh_set_ctx_params(void *vctx, const OSSL_PARAM params[])
{
PROV_SLH_DSA_CTX *pctx = (PROV_SLH_DSA_CTX *)vctx;
PROV_SLH_DSA_HASH_CTX *pctx = (PROV_SLH_DSA_HASH_CTX *)vctx;
const OSSL_PARAM *p;
if (pctx == NULL)
@ -187,7 +184,7 @@ static int slh_set_ctx_params(void *vctx, const OSSL_PARAM params[])
return 0;
}
}
p = OSSL_PARAM_locate_const(params, OSSL_SIGNATURE_PARAM_ADD_RANDOM);
p = OSSL_PARAM_locate_const(params, OSSL_SIGNATURE_PARAM_TEST_ENTROPY);
if (p != NULL) {
void *vp = pctx->add_random;
size_t n = ossl_slh_dsa_key_get_n(pctx->key);
@ -214,7 +211,7 @@ static const OSSL_PARAM *slh_settable_ctx_params(void *vctx,
{
static const OSSL_PARAM settable_ctx_params[] = {
OSSL_PARAM_octet_string(OSSL_SIGNATURE_PARAM_CONTEXT_STRING, NULL, 0),
OSSL_PARAM_octet_string(OSSL_SIGNATURE_PARAM_ADD_RANDOM, NULL, 0),
OSSL_PARAM_octet_string(OSSL_SIGNATURE_PARAM_TEST_ENTROPY, NULL, 0),
OSSL_PARAM_int(OSSL_SIGNATURE_PARAM_DETERMINISTIC, 0),
OSSL_PARAM_int(OSSL_SIGNATURE_PARAM_MESSAGE_ENCODING, 0),
OSSL_PARAM_END

View File

@ -1,5 +1,5 @@
/*
* Copyright 2024 The OpenSSL Project Authors. All Rights Reserved.
* Copyright 2024-2025 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
@ -250,7 +250,7 @@ static int slh_dsa_sign_verify_test(int tst_id)
*p++ = OSSL_PARAM_construct_int(OSSL_SIGNATURE_PARAM_DETERMINISTIC, &deterministic);
*p++ = OSSL_PARAM_construct_int(OSSL_SIGNATURE_PARAM_MESSAGE_ENCODING, &encode);
if (td->add_random != NULL)
*p++ = OSSL_PARAM_construct_octet_string(OSSL_SIGNATURE_PARAM_ADD_RANDOM,
*p++ = OSSL_PARAM_construct_octet_string(OSSL_SIGNATURE_PARAM_TEST_ENTROPY,
(char *)td->add_random,
td->add_random_len);
*p = OSSL_PARAM_construct_end();