This loads a SLH_DSA public key from data.
A simple SLH_DSA keymanager imports this key.
Initially this only has a parameter set for
SLH-DSA-SHA2-128s
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)
siphash sm3 des aes rc2 rc4 rc5 idea aria bf cast camellia \
seed sm4 chacha modes bn ec rsa dsa dh sm2 dso engine \
err comp http ocsp cms ts srp cmac ct async ess crmf cmp encode_decode \
- ffc hpke thread ml_dsa
+ ffc hpke thread ml_dsa slh_dsa
LIBS=../libcrypto
--- /dev/null
+LIBS=../../libcrypto
+
+$COMMON=slh_dsa_key.c slh_params.c
+
+IF[{- !$disabled{'slh_dsa'} -}]
+ SOURCE[../../libcrypto]=$COMMON
+ENDIF
--- /dev/null
+/*
+ * Copyright 2024 The OpenSSL Project Authors. All Rights Reserved.
+ *
+ * Licensed under the Apache License 2.0 (the "License"). You may not use
+ * this file except in compliance with the License. You can obtain a copy
+ * in the file LICENSE in the source distribution or at
+ * https://www.openssl.org/source/license.html
+ */
+
+#include <assert.h>
+#include <string.h>
+#include <openssl/core_dispatch.h>
+#include <openssl/core_names.h>
+#include <openssl/params.h>
+#include <openssl/rand.h>
+#include "slh_dsa_local.h"
+#include "slh_dsa_key.h"
+
+/**
+ * @brief Create a new SLH_DSA_KEY object
+ *
+ * @param libctx A OSSL_LIB_CTX object used for fetching algorithms.
+ * @param alg The algrithm 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 *ret;
+ const SLH_DSA_PARAMS *params = ossl_slh_dsa_params_get(alg);
+
+ if (params == NULL)
+ return NULL;
+
+ 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;
+ }
+ return ret;
+}
+
+/**
+ * @brief Destroy a SLH_DSA_KEY object
+ */
+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);
+
+ 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?
+ *
+ * To be equal the keys must have the same key data.
+ *
+ * @param key1 A SLH_DSA_KEY object
+ * @param key2 A SLH_DSA_KEY object
+ * @param selection to select public and/or private component comparison.
+ * @returns 1 if the keys are equal otherwise it returns 0.
+ */
+int ossl_slh_dsa_key_equal(const SLH_DSA_KEY *key1, const SLH_DSA_KEY *key2,
+ int selection)
+{
+ int ok = 1;
+
+ if ((selection & OSSL_KEYMGMT_SELECT_KEYPAIR) != 0) {
+ if (key1->key_len != key2->key_len)
+ return 0;
+ ok = (memcmp(key1->pub, key2->pub, key1->key_len) == 0);
+ }
+ return ok;
+}
+
+int ossl_slh_dsa_key_has(const SLH_DSA_KEY *key, int selection)
+{
+ if ((selection & OSSL_KEYMGMT_SELECT_KEYPAIR) != 0) {
+ if (key->key_len == 0)
+ return 0;
+ return 1;
+ }
+ return 0;
+}
+
+int ossl_slh_dsa_key_fromdata(SLH_DSA_KEY *key, const OSSL_PARAM params[])
+{
+ size_t n, key_len, len = 0;
+ const OSSL_PARAM *param_pub;
+ void *p;
+
+ if (key == NULL)
+ return 0;
+ n = key->params->n;
+ assert(n != 0);
+ /* Both the public and private key are composed of 2 elements of size n */
+ key_len = 2 * n;
+
+ 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;
+ key->key_len = key_len; /* This indicates the public key is present */
+ return 1;
+ err:
+ key->key_len = 0;
+ return 0;
+}
--- /dev/null
+/*
+ * Copyright 2024 The OpenSSL Project Authors. All Rights Reserved.
+ *
+ * Licensed under the Apache License 2.0 (the "License"). You may not use
+ * this file except in compliance with the License. You can obtain a copy
+ * in the file LICENSE in the source distribution or at
+ * https://www.openssl.org/source/license.html
+ */
+
+#include <openssl/e_os2.h>
+#include "internal/refcount.h"
+
+#define SLH_DSA_MAX_KEYLEN 32 * 2 /* 2 * n */
+
+struct slh_dsa_key_st {
+ uint8_t pub[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;
+};
--- /dev/null
+/*
+ * Copyright 2024 The OpenSSL Project Authors. All Rights Reserved.
+ *
+ * Licensed under the Apache License 2.0 (the "License"). You may not use
+ * this file except in compliance with the License. You can obtain a copy
+ * in the file LICENSE in the source distribution or at
+ * https://www.openssl.org/source/license.html
+ */
+
+#include "crypto/slh_dsa.h"
+#include "slh_params.h"
--- /dev/null
+/*
+ * Copyright 2024 The OpenSSL Project Authors. All Rights Reserved.
+ *
+ * Licensed under the Apache License 2.0 (the "License"). You may not use
+ * this file except in compliance with the License. You can obtain a copy
+ * in the file LICENSE in the source distribution or at
+ * https://www.openssl.org/source/license.html
+ */
+#include <stddef.h>
+#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
+
+static const SLH_DSA_PARAMS slh_dsa_params[] = {
+ {"SLH-DSA-SHA2-128s", 0, OSSL_SLH_DSA_128S},
+ {NULL},
+};
+
+/**
+ * @brief A getter to convert an algorithm name into a SLH_DSA_PARAMS object
+ */
+const SLH_DSA_PARAMS *ossl_slh_dsa_params_get(const char *alg)
+{
+ const SLH_DSA_PARAMS *p;
+
+ for (p = slh_dsa_params; p->alg != NULL; ++p) {
+ if (strcmp(p->alg, alg) == 0)
+ return p;
+ }
+ return NULL;
+}
--- /dev/null
+/*
+ * Copyright 2024 The OpenSSL Project Authors. All Rights Reserved.
+ *
+ * Licensed under the Apache License 2.0 (the "License"). You may not use
+ * this file except in compliance with the License. You can obtain a copy
+ * in the file LICENSE in the source distribution or at
+ * https://www.openssl.org/source/license.html
+ */
+
+#include <openssl/e_os2.h>
+
+/*
+ * Refer to FIPS 205 Section 11 parameter sets.
+ * lgw has been omitted since it is 4 for all algorithms i.e log(16)
+ */
+typedef struct slh_dsa_params_st {
+ const char *alg;
+ int is_shake;
+ uint32_t n; /* Security parameter (Hash output size in bytes) (16, 24, 32) */
+ uint32_t h; /* The total height of the tree (63, 64, 66, 68). #keypairs = 2^h */
+ uint32_t d; /* The number of tree layers (7, 8, 17, 22) */
+ uint32_t hm; /* The height (h') of each merkle tree. (h = hm * d ) */
+ uint32_t a; /* Height of a FORS tree */
+ uint32_t k; /* The number of FORS trees */
+ uint32_t m; /* The size of H_MSG() output */
+ uint32_t security_category;
+ uint32_t pk_len;
+ uint32_t sig_len;
+} SLH_DSA_PARAMS;
+
+const SLH_DSA_PARAMS *ossl_slh_dsa_params_get(const char *alg);
--- /dev/null
+/*
+ * Copyright 2024 The OpenSSL Project Authors. All Rights Reserved.
+ *
+ * Licensed under the Apache License 2.0 (the "License"). You may not use
+ * this file except in compliance with the License. You can obtain a copy
+ * in the file LICENSE in the source distribution or at
+ * https://www.openssl.org/source/license.html
+ */
+
+/* Internal SLH_DSA functions for other submodules, not for application use */
+
+#ifndef OSSL_CRYPTO_SLH_DSA_H
+# define OSSL_CRYPTO_SLH_DSA_H
+
+# pragma once
+# include <openssl/e_os2.h>
+# include <openssl/types.h>
+# include "crypto/types.h"
+
+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 ossl_slh_dsa_key_up_ref(SLH_DSA_KEY *key);
+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);
+
+#endif /* OSSL_CRYPTO_SLH_DSA_H */
# ifndef OPENSSL_NO_EC
typedef struct ecx_key_st ECX_KEY;
# endif
+# ifndef OPENSSL_NO_SLH_DSA
+typedef struct slh_dsa_key_st SLH_DSA_KEY;
+# endif
typedef struct prov_skey_st PROV_SKEY;
PROV_DESCS_SecP384r1MLKEM1024 },
# endif
#endif
+#ifndef OPENSSL_NO_SLH_DSA
+ { PROV_NAMES_SLH_DSA_SHA2_128S, "provider=default", ossl_slh_dsa_sha2_128s_keymgmt_functions,
+ PROV_DESCS_SLH_DSA_SHA2_128S },
+#endif /* OPENSSL_NO_SLH_DSA */
{ NULL, NULL, NULL }
};
extern const OSSL_DISPATCH ossl_mlx_p384_kem_kmgmt_functions[];
# endif
#endif
+#ifndef OPENSSL_NO_SLH_DSA
+extern const OSSL_DISPATCH ossl_slh_dsa_sha2_128s_keymgmt_functions[];
+#endif /* OPENSSL_NO_SLH_DSA */
/* Key Exchange */
extern const OSSL_DISPATCH ossl_dh_keyexch_functions[];
#define PROV_DESCS_SecP256r1MLKEM768 "P-256+ML-KEM-768 TLS hybrid implementation"
#define PROV_NAMES_SecP384r1MLKEM1024 "SecP384r1MLKEM1024"
#define PROV_DESCS_SecP384r1MLKEM1024 "P-384+ML-KEM-1024 TLS hybrid implementation"
+#define PROV_NAMES_SLH_DSA_SHA2_128S "SLH-DSA-SHA2-128s:2.16.840.1.101.3.4.3.20"
+#define PROV_DESCS_SLH_DSA_SHA2_128S "OpenSSL SLH-DSA-SHA2-128s implementation"
$ML_DSA_GOAL=../../libdefault.a ../../libfips.a
$ML_KEM_GOAL=../../libdefault.a ../../libfips.a
$TLS_ML_KEM_HYBRID_GOAL=../../libdefault.a ../../libfips.a
+$SLH_DSA_GOAL=../../libdefault.a
IF[{- !$disabled{dh} -}]
SOURCE[$DH_GOAL]=dh_kmgmt.c
IF[{- !$disabled{'ml-dsa'} -}]
SOURCE[$ML_DSA_GOAL]=ml_dsa_kmgmt.c
ENDIF
+
+IF[{- !$disabled{'slh-dsa'} -}]
+ SOURCE[$SLH_DSA_GOAL]=slh_dsa_kmgmt.c
+ENDIF
--- /dev/null
+/*
+ * Copyright 2024 The OpenSSL Project Authors. All Rights Reserved.
+ *
+ * Licensed under the Apache License 2.0 (the "License"). You may not use
+ * this file except in compliance with the License. You can obtain a copy
+ * in the file LICENSE in the source distribution or at
+ * https://www.openssl.org/source/license.html
+ */
+
+#include <openssl/core_dispatch.h>
+#include <openssl/core_names.h>
+#include <openssl/param_build.h>
+#include "crypto/slh_dsa.h"
+#include "internal/param_build_set.h"
+#include "prov/implementations.h"
+#include "prov/providercommon.h"
+#include "prov/provider_ctx.h"
+
+static OSSL_FUNC_keymgmt_free_fn slh_dsa_free_key;
+static OSSL_FUNC_keymgmt_has_fn slh_dsa_has;
+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 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);
+}
+
+static void slh_dsa_free_key(void *keydata)
+{
+ ossl_slh_dsa_key_free((SLH_DSA_KEY *)keydata);
+}
+
+static int slh_dsa_has(const void *keydata, int selection)
+{
+ const SLH_DSA_KEY *key = keydata;
+
+ if (!ossl_prov_is_running() || key == NULL)
+ return 0;
+ if ((selection & SLH_DSA_POSSIBLE_SELECTIONS) == 0)
+ return 1; /* the selection is not missing */
+
+ return ossl_slh_dsa_key_has(key, selection);
+}
+
+static int slh_dsa_match(const void *keydata1, const void *keydata2, int selection)
+{
+ const SLH_DSA_KEY *key1 = keydata1;
+ const SLH_DSA_KEY *key2 = keydata2;
+
+ if (!ossl_prov_is_running())
+ return 0;
+ if (key1 == NULL || key2 == NULL)
+ return 0;
+ return ossl_slh_dsa_key_equal(key1, key2, selection);
+}
+
+static int slh_dsa_import(void *keydata, int selection, const OSSL_PARAM params[])
+{
+ SLH_DSA_KEY *key = keydata;
+
+ 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);
+}
+
+static const OSSL_PARAM slh_dsa_key_types[] = {
+ OSSL_PARAM_octet_string(OSSL_PKEY_PARAM_PUB_KEY, NULL, 0),
+ OSSL_PARAM_END
+};
+
+static const OSSL_PARAM *slh_dsa_imexport_types(int selection)
+{
+ if ((selection & SLH_DSA_POSSIBLE_SELECTIONS) == 0)
+ return NULL;
+ return slh_dsa_key_types;
+}
+
+#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); \
+} \
+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_HAS, (void (*)(void))slh_dsa_has }, \
+ { 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_DISPATCH_END \
+}
+
+MAKE_KEYMGMT_FUNCTIONS("SLH-DSA-SHA2-128s", sha2_128s);
INCLUDE[evp_pkey_dhkem_test]=../include ../apps/include
DEPEND[evp_pkey_dhkem_test]=../libcrypto.a libtestutil.a
+ IF[{- !$disabled{'slh-dsa'} -}]
+ PROGRAMS{noinst}=slh_dsa_test
+ SOURCE[slh_dsa_test]=slh_dsa_test.c
+ INCLUDE[slh_dsa_test]=../include ../apps/include
+ DEPEND[slh_dsa_test]=../libcrypto.a libtestutil.a
+ ENDIF
+
IF[{- !$disabled{'deprecated-3.0'} -}]
PROGRAMS{noinst}=igetest bftest casttest
--- /dev/null
+#! /usr/bin/env perl
+# 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
+
+use strict;
+use warnings;
+
+use OpenSSL::Test qw(:DEFAULT srctop_dir bldtop_dir);
+use OpenSSL::Test::Utils;
+
+BEGIN {
+ setup("test_slh_dsa");
+}
+
+use lib srctop_dir('Configurations');
+use lib bldtop_dir('.');
+
+plan skip_all => 'SLH-DSA is not supported in this build' if disabled('slh-dsa');
+plan tests => 1;
+
+ok(run(test(["slh_dsa_test"])), "running slh_dsa_test");
--- /dev/null
+/*
+ * Copyright 2024 The OpenSSL Project Authors. All Rights Reserved.
+ *
+ * Licensed under the Apache License 2.0 (the "License"). You may not use
+ * this file except in compliance with the License. You can obtain a copy
+ * in the file LICENSE in the source distribution or at
+ * https://www.openssl.org/source/license.html
+ */
+
+typedef struct SLH_DSA_ACVP_TEST_DATA_st {
+ const char *alg;
+ const unsigned char *pub;
+ size_t pub_len;
+ const unsigned char *priv;
+ size_t priv_len;
+ const unsigned char *msg;
+ size_t msg_len;
+ /* sha256 digest of the signature - this reduces the footprint this file */
+ const unsigned char *sig_digest;
+ size_t sig_digest_len;
+} SLH_DSA_ACVP_TEST_DATA;
+
+#define SLH_DSA_ACVP_ITEM(name, alg) { \
+ alg, \
+ name##_pub, sizeof(name##_pub), \
+ name##_priv, sizeof(name##_priv), \
+ name##_msg, sizeof(name##_msg), \
+ name##_sig_digest, sizeof(name##_sig_digest) }
+
+/*
+ * Test vectors from
+ * usnistgov/ACVP-Server/refs/heads/master/gen-val/json-files/SLH-DSA-sigGen-FIPS205/internalProjection.json
+ *
+ * Note that the test vectors store the private & public components in one field
+ * (e.g sk)
+ * The following data separates these fields.
+ */
+static const uint8_t slh_dsa_sha2_128s_0_priv[] = {
+ 0x62, 0xb1, 0x97, 0x3a, 0x4d, 0xe0, 0x96, 0x3d, 0x74, 0xc1, 0xcb, 0x30, 0xfc, 0x8f, 0x56, 0x75,
+ 0xcf, 0xc8, 0x48, 0x80, 0xe4, 0xf0, 0xe1, 0xb4, 0x46, 0xb4, 0xf5, 0xd1, 0x3b, 0x2d, 0x31, 0xcc,
+};
+static const uint8_t slh_dsa_sha2_128s_0_pub[] = {
+ 0xcb, 0x23, 0xeb, 0x45, 0x52, 0x9e, 0x00, 0xd5, 0xf5, 0xe9, 0x51, 0x50, 0x7a, 0x9b, 0x90, 0xe9,
+ 0x8b, 0x6e, 0x7a, 0x28, 0x4b, 0xa3, 0xf6, 0x3a, 0x69, 0xe6, 0x9a, 0x78, 0x90, 0x83, 0xbe, 0xf6,
+};
+static const uint8_t slh_dsa_sha2_128s_0_msg[] = {
+ 0x9D, 0xDF
+};
+static const uint8_t slh_dsa_sha2_128s_0_sig_digest[] = {
+ 0xc7, 0xdf, 0xf0, 0xed, 0x25, 0x38, 0x49, 0xef, 0x51, 0x1e, 0x90, 0xbe, 0x0e, 0x2e, 0xb7, 0x71,
+ 0x65, 0x98, 0x91, 0x23, 0x17, 0x52, 0x9a, 0x61, 0xda, 0xe4, 0x32, 0x9b, 0xf1, 0x49, 0xef, 0x8b,
+};
+
+/* We can only use the hss tests that have a single level here */
+static SLH_DSA_ACVP_TEST_DATA slh_dsa_testdata[] = {
+ SLH_DSA_ACVP_ITEM(slh_dsa_sha2_128s_0, "SLH-DSA-SHA2-128s"),
+};
--- /dev/null
+/*
+ * Copyright 2024 The OpenSSL Project Authors. All Rights Reserved.
+ *
+ * Licensed under the Apache License 2.0 (the "License"). You may not use
+ * this file except in compliance with the License. You can obtain a copy
+ * in the file LICENSE in the source distribution or at
+ * https://www.openssl.org/source/license.html
+ */
+
+#include <openssl/core_names.h>
+#include <openssl/evp.h>
+#include "crypto/slh_dsa.h"
+#include "internal/nelem.h"
+#include "testutil.h"
+#include "slh_dsa.inc"
+
+static OSSL_LIB_CTX *libctx = NULL;
+
+static EVP_PKEY *slh_dsa_pubkey_from_data(const char *alg,
+ const unsigned char *data, size_t datalen)
+{
+ int ret;
+ EVP_PKEY_CTX *ctx = NULL;
+ EVP_PKEY *key = NULL;
+ OSSL_PARAM params[2];
+
+ params[0] = OSSL_PARAM_construct_octet_string(OSSL_PKEY_PARAM_PUB_KEY,
+ (unsigned char *)data, datalen);
+ params[1] = OSSL_PARAM_construct_end();
+ ret = TEST_ptr(ctx = EVP_PKEY_CTX_new_from_name(libctx, alg, NULL))
+ && TEST_int_eq(EVP_PKEY_fromdata_init(ctx), 1)
+ && (EVP_PKEY_fromdata(ctx, &key, EVP_PKEY_PUBLIC_KEY, params) == 1);
+ if (ret == 0) {
+ EVP_PKEY_free(key);
+ key = NULL;
+ }
+ EVP_PKEY_CTX_free(ctx);
+ return key;
+}
+
+static int slh_dsa_bad_pub_len_test(void)
+{
+ int ret = 0;
+ SLH_DSA_ACVP_TEST_DATA *td = &slh_dsa_testdata[0];
+ EVP_PKEY *pkey = NULL;
+ size_t pub_len = 0;
+ unsigned char pubdata[64 + 1];
+
+ if (!TEST_size_t_le(td->pub_len, sizeof(pubdata)))
+ goto end;
+
+ OPENSSL_cleanse(pubdata, sizeof(pubdata));
+ memcpy(pubdata, td->pub, td->pub_len);
+
+ if (!TEST_ptr_null(pkey = slh_dsa_pubkey_from_data(td->alg, pubdata,
+ td->pub_len - 1))
+ || !TEST_ptr_null(pkey = slh_dsa_pubkey_from_data(td->alg, pubdata,
+ td->pub_len + 1)))
+ goto end;
+
+ ret = 1;
+end:
+ if (ret == 0)
+ TEST_note("Incorrectly accepted public key of length %u (expected %u)",
+ (unsigned)pub_len, (unsigned)td->pub_len);
+ EVP_PKEY_free(pkey);
+ return ret == 1;
+}
+
+static int slh_dsa_key_eq_test(void)
+{
+ int ret = 0;
+ EVP_PKEY *key[2] = { NULL, NULL };
+ SLH_DSA_ACVP_TEST_DATA *td1 = &slh_dsa_testdata[0];
+#ifndef OPENSSL_NO_EC
+ EVP_PKEY *eckey = NULL;
+#endif
+
+ if (!TEST_ptr(key[0] = slh_dsa_pubkey_from_data(td1->alg, td1->pub, td1->pub_len))
+ || !TEST_ptr(key[1] = slh_dsa_pubkey_from_data(td1->alg, td1->pub, td1->pub_len)))
+ goto end;
+
+ ret = TEST_int_eq(EVP_PKEY_eq(key[0], key[1]), 1);
+ if (ret == 0)
+ goto end;
+
+#ifndef OPENSSL_NO_EC
+ if (!TEST_ptr(eckey = EVP_PKEY_Q_keygen(libctx, NULL, "EC", "P-256")))
+ goto end;
+ ret = TEST_int_ne(EVP_PKEY_eq(key[0], eckey), 1);
+ EVP_PKEY_free(eckey);
+#endif
+end:
+ EVP_PKEY_free(key[1]);
+ EVP_PKEY_free(key[0]);
+ return ret;
+}
+
+static int slh_dsa_key_validate_test(void)
+{
+ int ret = 0;
+ SLH_DSA_ACVP_TEST_DATA *td = &slh_dsa_testdata[0];
+ EVP_PKEY_CTX *vctx = NULL;
+ EVP_PKEY *key = NULL;
+
+ if (!TEST_ptr(key = slh_dsa_pubkey_from_data(td->alg, td->pub, td->pub_len)))
+ return 0;
+ if (!TEST_ptr(vctx = EVP_PKEY_CTX_new_from_pkey(libctx, key, NULL)))
+ goto end;
+ ret = TEST_int_eq(EVP_PKEY_check(vctx), 1);
+ EVP_PKEY_CTX_free(vctx);
+end:
+ EVP_PKEY_free(key);
+ return ret;
+}
+
+int setup_tests(void)
+{
+ ADD_TEST(slh_dsa_bad_pub_len_test);
+ ADD_TEST(slh_dsa_key_validate_test);
+ ADD_TEST(slh_dsa_key_eq_test);
+ return 1;
+}