File 1901-crypto-Add-SLH-DSA-algorithms-for-sign-verify.patch of Package erlang
From a0602a1b92efa0fa857904d1825ff6a1a5084610 Mon Sep 17 00:00:00 2001
From: Sverker Eriksson <sverker@erlang.org>
Date: Wed, 20 Aug 2025 16:43:51 +0200
Subject: [PATCH 1/2] crypto: Add SLH-DSA algorithms for sign/verify
SLH-DSA-SHAKE-256s
SLH-DSA-SHAKE-256f
SLH-DSA-SHA2-256s
SLH-DSA-SHA2-256f
---
lib/crypto/c_src/algorithms.c | 16 +-
lib/crypto/c_src/atoms.c | 10 -
lib/crypto/c_src/atoms.h | 5 -
lib/crypto/c_src/crypto.c | 4 +-
lib/crypto/c_src/evp.c | 19 +-
lib/crypto/c_src/openssl_config.h | 7 +
lib/crypto/c_src/pkey.c | 431 +++++++++++++++++-------------
lib/crypto/c_src/pkey.h | 25 +-
lib/crypto/src/crypto.erl | 44 ++-
lib/crypto/test/crypto_SUITE.erl | 6 +-
10 files changed, 328 insertions(+), 239 deletions(-)
diff --git a/lib/crypto/c_src/algorithms.c b/lib/crypto/c_src/algorithms.c
index 2e1465e15e..5b718f2bd3 100644
--- a/lib/crypto/c_src/algorithms.c
+++ b/lib/crypto/c_src/algorithms.c
@@ -26,6 +26,7 @@
#include "mac.h"
#ifdef HAS_3_0_API
#include "digest.h"
+#include "pkey.h"
#endif
#ifdef HAS_3_0_API
@@ -160,10 +161,14 @@ void init_hash_types(ErlNifEnv* env) {
ERL_NIF_TERM pubkey_algorithms(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
{
- unsigned int cnt =
- FIPS_MODE() ? algo_pubkey_fips_cnt : algo_pubkey_cnt;
+ const bool fips = FIPS_MODE();
+ unsigned int cnt = fips ? algo_pubkey_fips_cnt : algo_pubkey_cnt;
+ ERL_NIF_TERM list = enif_make_list_from_array(env, algo_pubkey, cnt);
- return enif_make_list_from_array(env, algo_pubkey, cnt);
+#ifdef HAS_3_0_API
+ list = build_pkey_type_list(env, list, fips);
+#endif
+ return list;
}
void init_pubkey_types(ErlNifEnv* env) {
@@ -193,11 +198,6 @@ void init_pubkey_types(ErlNifEnv* env) {
algo_pubkey[algo_pubkey_cnt++] = enif_make_atom(env, "eddh");
#endif
algo_pubkey[algo_pubkey_cnt++] = enif_make_atom(env, "srp");
-#ifdef HAVE_ML_DSA
- algo_pubkey[algo_pubkey_cnt++] = atom_mldsa44;
- algo_pubkey[algo_pubkey_cnt++] = atom_mldsa65;
- algo_pubkey[algo_pubkey_cnt++] = atom_mldsa87;
-#endif
ASSERT(algo_pubkey_cnt <= sizeof(algo_pubkey)/sizeof(ERL_NIF_TERM));
}
diff --git a/lib/crypto/c_src/atoms.c b/lib/crypto/c_src/atoms.c
index 41e171afbc..b1741cab46 100644
--- a/lib/crypto/c_src/atoms.c
+++ b/lib/crypto/c_src/atoms.c
@@ -151,13 +151,8 @@ ERL_NIF_TERM atom_key_id;
ERL_NIF_TERM atom_password;
#endif
-#ifdef HAVE_ML_DSA
-ERL_NIF_TERM atom_mldsa44;
-ERL_NIF_TERM atom_mldsa65;
-ERL_NIF_TERM atom_mldsa87;
ERL_NIF_TERM atom_seed;
ERL_NIF_TERM atom_expandedkey;
-#endif
#ifdef HAVE_ML_KEM
ERL_NIF_TERM atom_mlkem512;
@@ -288,13 +283,8 @@ int init_atoms(ErlNifEnv *env) {
atom_password = enif_make_atom(env,"password");
#endif
-#ifdef HAVE_ML_DSA
- atom_mldsa44 = enif_make_atom(env,"mldsa44");
- atom_mldsa65 = enif_make_atom(env,"mldsa65");
- atom_mldsa87 = enif_make_atom(env,"mldsa87");
atom_seed = enif_make_atom(env,"seed");
atom_expandedkey = enif_make_atom(env,"expandedkey");
-#endif
#ifdef HAVE_ML_KEM
atom_mlkem512 = enif_make_atom(env,"mlkem512");
atom_mlkem768 = enif_make_atom(env,"mlkem768");
diff --git a/lib/crypto/c_src/atoms.h b/lib/crypto/c_src/atoms.h
index 4ee6a56057..928297a017 100644
--- a/lib/crypto/c_src/atoms.h
+++ b/lib/crypto/c_src/atoms.h
@@ -150,13 +150,8 @@ extern ERL_NIF_TERM atom_key_id;
extern ERL_NIF_TERM atom_password;
#endif
-#ifdef HAVE_ML_DSA
-extern ERL_NIF_TERM atom_mldsa44;
-extern ERL_NIF_TERM atom_mldsa65;
-extern ERL_NIF_TERM atom_mldsa87;
extern ERL_NIF_TERM atom_seed;
extern ERL_NIF_TERM atom_expandedkey;
-#endif
#ifdef HAVE_ML_KEM
extern ERL_NIF_TERM atom_mlkem512;
extern ERL_NIF_TERM atom_mlkem768;
diff --git a/lib/crypto/c_src/crypto.c b/lib/crypto/c_src/crypto.c
index aad48c45eb..7cb4068063 100644
--- a/lib/crypto/c_src/crypto.c
+++ b/lib/crypto/c_src/crypto.c
@@ -102,6 +102,7 @@ static ErlNifFunc nif_funcs[] = {
{"pbkdf2_hmac_nif", 5, pbkdf2_hmac_nif, 0},
{"pkey_sign_nif", 5, pkey_sign_nif, 0},
+ {"pkey_sign_heavy_nif", 5, pkey_sign_heavy_nif, ERL_NIF_DIRTY_JOB_CPU_BOUND},
{"pkey_verify_nif", 6, pkey_verify_nif, 0},
{"pkey_crypt_nif", 6, pkey_crypt_nif, 0},
{"encapsulate_key_nif", 2, encapsulate_key_nif, 0},
@@ -275,9 +276,8 @@ static int initialize(ErlNifEnv* env, ERL_NIF_TERM load_info)
/* Don't fail loading if the legacy provider is missing */
prov_cnt++;
}
- prefetched_sign_algo_init();
-
#endif
+ prefetched_sign_algo_init(env);
if (!init_atoms(env)) {
ret = __LINE__; goto done;
diff --git a/lib/crypto/c_src/evp.c b/lib/crypto/c_src/evp.c
index f09eedb00e..26177659d8 100644
--- a/lib/crypto/c_src/evp.c
+++ b/lib/crypto/c_src/evp.c
@@ -38,7 +38,7 @@ ERL_NIF_TERM encapsulate_key_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM ar
ERL_NIF_TERM ret;
if (!get_pkey_from_octet_string(env, argv[0], argv[1], PKEY_PUB,
- &peer_pkey, &ret)) {
+ NULL, &peer_pkey, &ret)) {
goto err;
}
@@ -92,7 +92,7 @@ ERL_NIF_TERM decapsulate_key_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM ar
assign_goto(ret, err, EXCP_ERROR_N(env, 2, "Invalid encapsulated secret"));
}
if (!get_pkey_from_octet_string(env, argv[0], argv[1], PKEY_PRIV,
- &my_pkey, &ret)) {
+ NULL, &my_pkey, &ret)) {
goto err;
}
@@ -229,8 +229,12 @@ ERL_NIF_TERM evp_generate_key_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM a
ErlNifBinary prv_key;
size_t key_len;
unsigned char *out_pub = NULL, *out_priv = NULL;
+ struct pkey_type_t *pkey_type = get_pkey_type(argv[0]);
- if (argv[0] == atom_x25519)
+ if (pkey_type) {
+ type = pkey_type->evp_pkey_id;
+ }
+ else if (argv[0] == atom_x25519)
type = EVP_PKEY_X25519;
#ifdef HAVE_X448
else if (argv[0] == atom_x448)
@@ -242,15 +246,6 @@ ERL_NIF_TERM evp_generate_key_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM a
else if (argv[0] == atom_ed448)
type = EVP_PKEY_ED448;
#endif
-#ifdef HAVE_ML_DSA
- else if (argv[0] == atom_mldsa44) {
- type = EVP_PKEY_ML_DSA_44;
- } else if (argv[0] == atom_mldsa65) {
- type = EVP_PKEY_ML_DSA_65;
- } else if (argv[0] == atom_mldsa87) {
- type = EVP_PKEY_ML_DSA_87;
- }
-#endif
#ifdef HAVE_ML_KEM
else if (argv[0] == atom_mlkem512) {
type = NID_ML_KEM_512;
diff --git a/lib/crypto/c_src/openssl_config.h b/lib/crypto/c_src/openssl_config.h
index 9957b58d98..f525aeccc1 100644
--- a/lib/crypto/c_src/openssl_config.h
+++ b/lib/crypto/c_src/openssl_config.h
@@ -389,6 +389,10 @@
#endif
#endif
+#if OPENSSL_VERSION_NUMBER >= PACKED_OPENSSL_VERSION_PLAIN(3,4,0)
+# define HAS_PREFETCH_SIGN_INIT
+#endif
+
#if OPENSSL_VERSION_NUMBER >= PACKED_OPENSSL_VERSION_PLAIN(3,5,0)
# ifndef OPENSSL_NO_ML_KEM
# define HAVE_ML_KEM
@@ -396,6 +400,9 @@
# ifndef OPENSSL_NO_ML_DSA
# define HAVE_ML_DSA
# endif
+# ifndef OPENSSL_NO_SLH_DSA
+# define HAVE_SLH_DSA
+# endif
#endif
#if defined(HAS_ENGINE_SUPPORT)
diff --git a/lib/crypto/c_src/pkey.c b/lib/crypto/c_src/pkey.c
index f10998baff..6646a69f3e 100644
--- a/lib/crypto/c_src/pkey.c
+++ b/lib/crypto/c_src/pkey.c
@@ -49,28 +49,33 @@ static int check_pkey_algorithm_type(ErlNifEnv *env,
int allow_unknown,
ERL_NIF_TERM *err_return);
static int get_pkey_digest_type(ErlNifEnv *env, ERL_NIF_TERM algorithm,
+ const struct pkey_type_t *pkey_type,
int type_arg_num, ERL_NIF_TERM type,
const EVP_MD **md,
ERL_NIF_TERM *err_return);
static int get_pkey_sign_digest(ErlNifEnv *env,
const ERL_NIF_TERM argv[],
int algorithm_arg_num, int type_arg_num, int data_arg_num,
+ const struct pkey_type_t *pkey_type,
unsigned char *md_value, const EVP_MD **mdp,
unsigned char **tbsp, size_t *tbslenp,
ERL_NIF_TERM *err_return);
static int get_pkey_sign_options(ErlNifEnv *env,
const ERL_NIF_TERM argv[],
int algorithm_arg_num, int options_arg_num,
+ const struct pkey_type_t *pkey_type,
const EVP_MD *md, PKeySignOptions *opt,
ERL_NIF_TERM *err_return);
static int get_pkey_private_key(ErlNifEnv *env,
const ERL_NIF_TERM argv[],
int algorithm_arg_num, int key_arg_num,
+ struct pkey_type_t *pkey_type,
EVP_PKEY **pkey,
ERL_NIF_TERM *err_return);
static int get_pkey_public_key(ErlNifEnv *env,
const ERL_NIF_TERM argv[],
int algorithm_arg_num, int key_arg_num,
+ struct pkey_type_t *pkey_type,
EVP_PKEY **pkey,
ERL_NIF_TERM *err_return);
static int get_pkey_crypt_options(ErlNifEnv *env,
@@ -82,38 +87,87 @@ static int get_pkey_crypt_options(ErlNifEnv *env,
static size_t size_of_RSA(EVP_PKEY *pkey);
#endif
+struct pkey_type_t pkey_types[] = {
#ifdef HAVE_ML_DSA
-static EVP_SIGNATURE* the_mldsa44_algo;
-static EVP_SIGNATURE* the_mldsa65_algo;
-static EVP_SIGNATURE* the_mldsa87_algo;
+ {
+ .name.atom_str = "mldsa44",
+ .evp_pkey_id = EVP_PKEY_ML_DSA_44,
+ .sign.alg_str = "mldsa44",
+ .allow_seed = true
+ },
+ {
+ .name.atom_str = "mldsa65",
+ .evp_pkey_id = EVP_PKEY_ML_DSA_65,
+ .sign.alg_str = "mldsa65",
+ .allow_seed = true
+ },
+ {
+ .name.atom_str = "mldsa87",
+ .evp_pkey_id = EVP_PKEY_ML_DSA_87,
+ .sign.alg_str = "mldsa87",
+ .allow_seed = true
+ },
+#endif
+#ifdef HAVE_SLH_DSA
+ {
+ .name.atom_str = "slh_dsa_shake_256s",
+ .evp_pkey_id = EVP_PKEY_SLH_DSA_SHAKE_256S,
+ .sign.alg_str = "SLH-DSA-SHAKE-256s"
+ },
+ {
+ .name.atom_str = "slh_dsa_shake_256f",
+ .evp_pkey_id = EVP_PKEY_SLH_DSA_SHAKE_256F,
+ .sign.alg_str = "SLH-DSA-SHAKE-256f"
+ },
+ {
+ .name.atom_str = "slh_dsa_sha2_256s",
+ .evp_pkey_id = EVP_PKEY_SLH_DSA_SHA2_256S,
+ .sign.alg_str = "SLH-DSA-SHA2-256s"
+ },
+ {
+ .name.atom_str = "slh_dsa_sha2_256f",
+ .evp_pkey_id = EVP_PKEY_SLH_DSA_SHA2_256F,
+ .sign.alg_str = "SLH-DSA-SHA2-256f"
+ },
#endif
-void prefetched_sign_algo_init(void)
+ {.name.atom_str = NULL}
+};
+struct pkey_type_t *pkey_types_end;
+
+
+void prefetched_sign_algo_init(ErlNifEnv* env)
{
-#ifdef HAVE_ML_DSA
- the_mldsa44_algo = EVP_SIGNATURE_fetch(NULL, "mldsa44", NULL);
- the_mldsa65_algo = EVP_SIGNATURE_fetch(NULL, "mldsa65", NULL);
- the_mldsa87_algo = EVP_SIGNATURE_fetch(NULL, "mldsa87", NULL);
+ struct pkey_type_t* p;
+ for (p = pkey_types; p->name.atom_str; p++) {
+ p->name.atom = enif_make_atom(env, p->name.atom_str);
+#ifdef HAS_PREFETCH_SIGN_INIT
+ p->sign.alg = EVP_SIGNATURE_fetch(NULL, p->sign.alg_str, NULL);
#endif
+ }
+ pkey_types_end = p;
}
-#ifdef HAS_3_0_API
-static EVP_SIGNATURE* get_prefetched_sign_algo(ERL_NIF_TERM alg_atom)
+struct pkey_type_t* get_pkey_type(ERL_NIF_TERM alg_atom)
{
-#ifdef HAVE_ML_DSA
- if (alg_atom == atom_mldsa44) {
- return the_mldsa44_algo;
- }
- else if (alg_atom == atom_mldsa65) {
- return the_mldsa65_algo;
- }
- else if (alg_atom == atom_mldsa87) {
- return the_mldsa87_algo;
+ for (struct pkey_type_t* p = pkey_types; p != pkey_types_end; p++) {
+ if (alg_atom == p->name.atom) {
+ return p;
+ }
}
-#endif
return NULL;
}
-#endif
+
+ERL_NIF_TERM build_pkey_type_list(ErlNifEnv* env, ERL_NIF_TERM tail, bool fips)
+{
+ ERL_NIF_TERM list = tail;
+ if (!fips) {
+ for (struct pkey_type_t* p = pkey_types; p != pkey_types_end; p++) {
+ list = enif_make_list_cell(env, p->name.atom, list);
+ }
+ }
+ return list;
+}
static int check_pkey_algorithm_type(ErlNifEnv *env,
int alg_arg_num, ERL_NIF_TERM algorithm,
@@ -156,7 +210,9 @@ static int check_pkey_algorithm_type(ErlNifEnv *env,
}
-static int get_pkey_digest_type(ErlNifEnv *env, ERL_NIF_TERM algorithm,
+static int get_pkey_digest_type(ErlNifEnv *env,
+ ERL_NIF_TERM algorithm,
+ const struct pkey_type_t *pkey_type,
int type_arg_num, ERL_NIF_TERM type,
const EVP_MD **md,
ERL_NIF_TERM *err_return)
@@ -168,13 +224,9 @@ static int get_pkey_digest_type(ErlNifEnv *env, ERL_NIF_TERM algorithm,
if (algorithm == atom_rsa) {
return 1;
}
-#ifdef HAVE_ML_DSA
- if (algorithm == atom_mldsa44 ||
- algorithm == atom_mldsa65 ||
- algorithm == atom_mldsa87) {
+ if (pkey_type && algorithm == pkey_type->name.atom) {
return 1;
}
-#endif
}
if (algorithm == atom_eddsa) /* Type was skipped for eddsa in < OTP-25
@@ -200,7 +252,9 @@ static int get_pkey_digest_type(ErlNifEnv *env, ERL_NIF_TERM algorithm,
static int get_pkey_sign_digest(ErlNifEnv *env,
const ERL_NIF_TERM argv[],
- int algorithm_arg_num, int type_arg_num, int data_arg_num,
+ int algorithm_arg_num,
+ int type_arg_num, int data_arg_num,
+ const struct pkey_type_t *pkey_type,
unsigned char *md_value, const EVP_MD **mdp,
unsigned char **tbsp, size_t *tbslenp,
ERL_NIF_TERM *err_return)
@@ -224,7 +278,8 @@ static int get_pkey_sign_digest(ErlNifEnv *env,
goto err; /* An exception is present in ret */
}
- if (!get_pkey_digest_type(env, argv[algorithm_arg_num],
+ if (!get_pkey_digest_type(env,
+ argv[algorithm_arg_num], pkey_type,
type_arg_num, argv[type_arg_num],
&md, err_return))
goto err; /* An exception is present in ret */
@@ -292,6 +347,7 @@ static int get_pkey_sign_digest(ErlNifEnv *env,
static int get_pkey_sign_options(ErlNifEnv *env,
const ERL_NIF_TERM argv[],
int algorithm_arg_num, int options_arg_num,
+ const struct pkey_type_t *pkey_type,
const EVP_MD *md, PKeySignOptions *opt,
ERL_NIF_TERM *err_return)
{
@@ -331,6 +387,7 @@ static int get_pkey_sign_options(ErlNifEnv *env,
assign_goto(*err_return, err, EXCP_BADARG_N(env, options_arg_num, "Atom expected as argument to option rsa_mgf1_md"));
if (!get_pkey_digest_type(env, argv[algorithm_arg_num],
+ pkey_type,
options_arg_num, tpl_terms[1],
&opt_md, err_return))
goto err; /* An exception is present in ret */
@@ -380,6 +437,7 @@ static int get_pkey_private_key(ErlNifEnv *env,
const ERL_NIF_TERM argv[],
int algorithm_arg_num,
int key_arg_num,
+ struct pkey_type_t *pkey_type,
EVP_PKEY **pkey,
ERL_NIF_TERM *err_return)
{
@@ -440,29 +498,29 @@ static int get_pkey_private_key(ErlNifEnv *env,
#else
enum pkey_format_t pkey_format = PKEY_PRIV;
ERL_NIF_TERM key_bin = argv[key_arg_num];
+ const ERL_NIF_TERM* tpl_array;
+ int tpl_arity;
-# ifdef HAVE_ML_DSA
- if (argv[algorithm_arg_num] == atom_mldsa44 ||
- argv[algorithm_arg_num] == atom_mldsa65 ||
- argv[algorithm_arg_num] == atom_mldsa87) {
- int tpl_arity;
- const ERL_NIF_TERM* tpl_array;
+ if (enif_get_tuple(env, argv[key_arg_num], &tpl_arity, &tpl_array)
+ && tpl_arity == 2) {
- if (!enif_get_tuple(env, argv[key_arg_num], &tpl_arity, &tpl_array)
- || tpl_arity != 2) {
- assign_goto(*err_return, err, EXCP_BADARG_N(env, key_arg_num, "MLDSA key not 2-tuple"));
- }
if (tpl_array[0] == atom_seed) {
- pkey_format = PKEY_PRIV_SEED;
+ if (pkey_type && pkey_type->allow_seed) {
+ pkey_format = PKEY_PRIV_SEED;
+ }
+ else {
+ assign_goto(*err_return, err, EXCP_BADARG_N(env, key_arg_num, "Seed key not allowed"));
+ }
}
else if (tpl_array[0] != atom_expandedkey) {
- assign_goto(*err_return, err, EXCP_BADARG_N(env, key_arg_num, "Invalid MLDSA key tuple"));
+ assign_goto(*err_return, err, EXCP_BADARG_N(env, key_arg_num, "Invalid key tuple format"));
}
key_bin = tpl_array[1];
}
-# endif
if (!get_pkey_from_octet_string(env, argv[algorithm_arg_num], key_bin,
- pkey_format, pkey, err_return)) {
+ pkey_format,
+ pkey_type,
+ pkey, err_return)) {
goto err;
}
#endif
@@ -490,10 +548,10 @@ int get_pkey_from_octet_string(ErlNifEnv *env,
ERL_NIF_TERM alg_atom,
ERL_NIF_TERM key_bin,
enum pkey_format_t pkey_format,
+ struct pkey_type_t *pkey_type,
EVP_PKEY **pkey_p,
ERL_NIF_TERM *ret_p)
{
- char type[40];
OSSL_PARAM params[2];
int i = 0;
EVP_PKEY *pkey = NULL;
@@ -502,9 +560,23 @@ int get_pkey_from_octet_string(ErlNifEnv *env,
const char* key_type;
int selection;
- if (!enif_get_atom(env, alg_atom, type, sizeof(type), ERL_NIF_UTF8)) {
- assign_goto(*ret_p, err, EXCP_ERROR_N(env, 0, "Invalid key type"));
+ if (pkey_type) {
+ ctx = EVP_PKEY_CTX_new_id(pkey_type->evp_pkey_id, NULL);
+ if (!ctx) {
+ assign_goto(*ret_p, err, EXCP_ERROR(env, "Can't create PKEY_CTX from id"));
+ }
}
+ else {
+ char type[40];
+ if (!enif_get_atom(env, alg_atom, type, sizeof(type), ERL_NIF_UTF8)) {
+ assign_goto(*ret_p, err, EXCP_ERROR_N(env, 0, "Invalid key type"));
+ }
+ ctx = EVP_PKEY_CTX_new_from_name(NULL, type, NULL);
+ if (!ctx) {
+ assign_goto(*ret_p, err, EXCP_ERROR(env, "Can't create PKEY_CTX from name"));
+ }
+ }
+
if (!enif_inspect_binary(env, key_bin, &keyb)) {
assign_goto(*ret_p, err, EXCP_ERROR_N(env, 1, "Invalid public key"));
}
@@ -529,11 +601,6 @@ int get_pkey_from_octet_string(ErlNifEnv *env,
params[i++] = OSSL_PARAM_construct_octet_string(key_type, keyb.data, keyb.size);
params[i++] = OSSL_PARAM_construct_end();
- ctx = EVP_PKEY_CTX_new_from_name(NULL, type, NULL);
- if (!ctx) {
- assign_goto(*ret_p, err, EXCP_ERROR(env, "Can't create PKEY_CTX from name"));
- }
-
if (EVP_PKEY_fromdata_init(ctx) <= 0) {
assign_goto(*ret_p, err, EXCP_ERROR(env, "Can't init fromdata"));
}
@@ -562,6 +629,7 @@ err:
static int get_pkey_public_key(ErlNifEnv *env,
const ERL_NIF_TERM argv[],
int algorithm_arg_num, int key_arg_num,
+ struct pkey_type_t *pkey_type,
EVP_PKEY **pkey,
ERL_NIF_TERM *err_return)
{
@@ -618,7 +686,7 @@ static int get_pkey_public_key(ErlNifEnv *env,
} else {
#ifdef HAS_3_0_API
if (!get_pkey_from_octet_string(env, argv[algorithm_arg_num], argv[key_arg_num],
- PKEY_PUB, pkey, err_return)) {
+ PKEY_PUB, pkey_type, pkey, err_return)) {
goto err;
}
#else
@@ -645,6 +713,12 @@ static int get_pkey_public_key(ErlNifEnv *env,
goto done;
}
+ERL_NIF_TERM pkey_sign_heavy_nif(ErlNifEnv *env, int argc, const ERL_NIF_TERM argv[])
+{
+ // We are running on a dirty CPU scheduler.
+ return pkey_sign_nif(env, argc, argv);
+}
+
ERL_NIF_TERM pkey_sign_nif(ErlNifEnv *env, int argc, const ERL_NIF_TERM argv[])
{/* (Algorithm, Type, Data|{digest,Digest}, Key|#{}, Options) */
int sig_bin_alloc = 0;
@@ -653,6 +727,7 @@ ERL_NIF_TERM pkey_sign_nif(ErlNifEnv *env, int argc, const ERL_NIF_TERM argv[])
unsigned char md_value[EVP_MAX_MD_SIZE];
EVP_PKEY *pkey = NULL;
#ifdef HAS_EVP_PKEY_CTX
+ struct pkey_type_t *pkey_type = get_pkey_type(argv[0]);
EVP_PKEY_CTX *ctx = NULL;
size_t siglen;
#else
@@ -675,46 +750,63 @@ ERL_NIF_TERM pkey_sign_nif(ErlNifEnv *env, int argc, const ERL_NIF_TERM argv[])
if (enif_is_map(env, argv[3]))
assign_goto(ret, err, EXCP_BADARG_N(env, 3, "No engine support"));
#endif
- if (!get_pkey_sign_digest(env, argv, 0, 1, 2, md_value, &md, &tbs, &tbslen, &ret))
+ if (!get_pkey_sign_digest(env, argv, 0, 1, 2, pkey_type, md_value, &md, &tbs, &tbslen, &ret))
goto err; /* An exception is present in ret */
- if (!get_pkey_sign_options(env, argv, 0, 4, md, &sig_opt, &ret))
+ if (!get_pkey_sign_options(env, argv, 0, 4, pkey_type, md, &sig_opt, &ret))
goto err; /* An exception is present in ret */
#ifdef HAS_EVP_PKEY_CTX
- { /* EVP_MD_CTX */
- if (!get_pkey_private_key(env, argv, 0, 3, &pkey, &ret))
- goto err; /* An exception is present in ret */
+ if (!get_pkey_private_key(env, argv, 0, 3, pkey_type, &pkey, &ret))
+ goto err; /* An exception is present in ret */
- if ((ctx = EVP_PKEY_CTX_new(pkey, NULL)) == NULL)
- assign_goto(ret, err, EXCP_ERROR(env, "Can't allocate new EVP_PKEY_CTX"));
+ if (argv[0] == atom_eddsa) {
+# ifdef HAVE_EDDSA
+ if (!FIPS_MODE()) {
+ EVP_MD_CTX *mdctx = NULL;
+ if ((mdctx = EVP_MD_CTX_new()) == NULL)
+ assign_goto(ret, err, EXCP_ERROR(env, "Can't EVP_MD_CTX_new"));
- if (argv[0] != atom_eddsa) {
-#ifdef HAS_3_0_API
- EVP_SIGNATURE *sig_alg = get_prefetched_sign_algo(argv[0]);
+ if (EVP_DigestSignInit(mdctx, NULL, NULL, NULL, pkey) != 1)
+ assign_goto(ret, err, EXCP_ERROR(env, "Can't EVP_DigestSignInit"));
+ if (EVP_DigestSign(mdctx, NULL, &siglen, tbs, tbslen) != 1)
+ assign_goto(ret, err, EXCP_ERROR(env, "Can't EVP_DigestSign"));
+ if (!enif_alloc_binary(siglen, &sig_bin))
+ assign_goto(ret, err, EXCP_ERROR(env, "Can't allocate binary"));
+ sig_bin_alloc = 1;
- if (!sig_alg) {
- if (EVP_PKEY_sign_init(ctx) != 1) {
- assign_goto(ret, err, EXCP_ERROR(env, "Can't EVP_PKEY_sign_init"));
- }
- }
- else {
-# ifdef HAVE_ML_DSA
- if (EVP_PKEY_sign_message_init(ctx, sig_alg, NULL) != 1)
- assign_goto(ret, err, EXCP_ERROR(env, "Can't EVP_PKEY_sign_message_init"));
-# else
- assign_goto(ret, err, EXCP_ERROR(env, "Unknown signature algorithm"));
-# endif
+ if (EVP_DigestSign(mdctx, sig_bin.data, &siglen, tbs, tbslen) != 1) {
+ if (mdctx)
+ EVP_MD_CTX_free(mdctx);
+ assign_goto(ret, err, EXCP_ERROR(env, "Can't EVP_DigestSign"));
}
-#else
+ if (mdctx)
+ EVP_MD_CTX_free(mdctx);
+ }
+ else
+# endif
+ assign_goto(ret, err, EXCP_NOTSUP_N(env, 0, "eddsa not supported"));
+ }
+ else {
+ if ((ctx = EVP_PKEY_CTX_new(pkey, NULL)) == NULL) {
+ assign_goto(ret, err, EXCP_ERROR(env, "Can't allocate new EVP_PKEY_CTX"));
+ }
+# ifdef HAS_PREFETCH_SIGN_INIT
+ if (pkey_type && pkey_type->sign.alg) {
+ if (EVP_PKEY_sign_message_init(ctx, pkey_type->sign.alg, NULL) != 1)
+ assign_goto(ret, err, EXCP_ERROR(env, "Can't EVP_PKEY_sign_message_init"));
+ }
+ else
+# endif
+ {
if (EVP_PKEY_sign_init(ctx) != 1) {
assign_goto(ret, err, EXCP_ERROR(env, "Can't EVP_PKEY_sign_init"));
}
-#endif
- if (md != NULL) {
- if (EVP_PKEY_CTX_set_signature_md(ctx, md) != 1)
- assign_goto(ret, err, EXCP_ERROR(env, "Can't EVP_PKEY_CTX_set_signature_md"));
- }
+ }
+
+ if (md != NULL) {
+ if (EVP_PKEY_CTX_set_signature_md(ctx, md) != 1)
+ assign_goto(ret, err, EXCP_ERROR(env, "Can't EVP_PKEY_CTX_set_signature_md"));
}
if (argv[0] == atom_rsa) {
@@ -738,46 +830,19 @@ ERL_NIF_TERM pkey_sign_nif(ErlNifEnv *env, int argc, const ERL_NIF_TERM argv[])
# endif
}
- if (argv[0] == atom_eddsa) {
-# ifdef HAVE_EDDSA
- if (!FIPS_MODE()) {
- EVP_MD_CTX *mdctx = NULL;
- if ((mdctx = EVP_MD_CTX_new()) == NULL)
- assign_goto(ret, err, EXCP_ERROR(env, "Can't EVP_MD_CTX_new"));
+ if (EVP_PKEY_sign(ctx, NULL, &siglen, tbs, tbslen) != 1)
+ assign_goto(ret, err, EXCP_ERROR(env, "Can't EVP_PKEY_sign"));
- if (EVP_DigestSignInit(mdctx, NULL, NULL, NULL, pkey) != 1)
- assign_goto(ret, err, EXCP_ERROR(env, "Can't EVP_DigestSignInit"));
- if (EVP_DigestSign(mdctx, NULL, &siglen, tbs, tbslen) != 1)
- assign_goto(ret, err, EXCP_ERROR(env, "Can't EVP_DigestSign"));
- if (!enif_alloc_binary(siglen, &sig_bin))
- assign_goto(ret, err, EXCP_ERROR(env, "Can't allocate binary"));
- sig_bin_alloc = 1;
-
- if (EVP_DigestSign(mdctx, sig_bin.data, &siglen, tbs, tbslen) != 1) {
- if (mdctx)
- EVP_MD_CTX_free(mdctx);
- assign_goto(ret, err, EXCP_ERROR(env, "Can't EVP_DigestSign"));
- }
- if (mdctx)
- EVP_MD_CTX_free(mdctx);
- }
- else
-# endif
- assign_goto(ret, err, EXCP_NOTSUP_N(env, 0, "eddsa not supported"));
- } else {
- if (EVP_PKEY_sign(ctx, NULL, &siglen, tbs, tbslen) != 1)
- assign_goto(ret, err, EXCP_ERROR(env, "Can't EVP_PKEY_sign"));
+ if (!enif_alloc_binary(siglen, &sig_bin))
+ assign_goto(ret, err, EXCP_ERROR(env, "Can't allocate binary"));
+ sig_bin_alloc = 1;
- if (!enif_alloc_binary(siglen, &sig_bin))
- assign_goto(ret, err, EXCP_ERROR(env, "Can't allocate binary"));
- sig_bin_alloc = 1;
-
- if (md != NULL) {
- ERL_VALGRIND_ASSERT_MEM_DEFINED(tbs, EVP_MD_size(md));
- }
- if (EVP_PKEY_sign(ctx, sig_bin.data, &siglen, tbs, tbslen) != 1)
- assign_goto(ret, err, EXCP_ERROR(env, "Can't EVP_PKEY_sign"));
+ if (md != NULL) {
+ ERL_VALGRIND_ASSERT_MEM_DEFINED(tbs, EVP_MD_size(md));
}
+ if (EVP_PKEY_sign(ctx, sig_bin.data, &siglen, tbs, tbslen) != 1)
+ assign_goto(ret, err, EXCP_ERROR(env, "Can't EVP_PKEY_sign"));
+ }
ERL_VALGRIND_MAKE_MEM_DEFINED(sig_bin.data, siglen);
if (siglen != sig_bin.size) {
@@ -797,7 +862,7 @@ ERL_NIF_TERM pkey_sign_nif(ErlNifEnv *env, int argc, const ERL_NIF_TERM argv[])
if (pkey)
EVP_PKEY_free(pkey);
return ret;
- }
+
/* End of HAS_EVP_PKEY_CTX */
#else
/* Old interface - before EVP_PKEY_CTX */
@@ -909,68 +974,74 @@ ERL_NIF_TERM pkey_verify_nif(ErlNifEnv *env, int argc, const ERL_NIF_TERM argv[]
ERL_NIF_TERM ret = atom_undefined;
#ifdef HAS_EVP_PKEY_CTX
+ struct pkey_type_t *pkey_type = get_pkey_type(argv[0]);
EVP_PKEY_CTX *ctx = NULL;
#else
RSA *rsa = NULL;
# ifdef HAVE_DSA
- DSA *dsa = NULL;
+ DSA *dsa = NULL;
# endif
# ifdef HAVE_EC
- EC_KEY *ec = NULL;
+ EC_KEY *ec = NULL;
# endif
#endif // HAS_EVP_PKEY_CTX
-
#ifndef HAS_ENGINE_SUPPORT
if (enif_is_map(env, argv[3]))
assign_goto(ret, err, EXCP_BADARG_N(env, 3, "No engine support"));
#endif
- if (!get_pkey_sign_digest(env, argv, 0, 1, 2, md_value, &md, &tbs, &tbslen, &ret))
+ if (!get_pkey_sign_digest(env, argv, 0, 1, 2, pkey_type, md_value, &md, &tbs, &tbslen, &ret))
goto err; /* An exception is present in ret */
- if (!get_pkey_sign_options(env, argv, 0, 5, md, &sig_opt, &ret))
+ if (!get_pkey_sign_options(env, argv, 0, 5, pkey_type, md, &sig_opt, &ret))
goto err; /* An exception is present in ret */
if (!enif_inspect_binary(env, argv[3], &sig_bin))
assign_goto(ret, err, EXCP_BADARG_N(env, 3, "Expected a binary"));
#ifdef HAS_EVP_PKEY_CTX
- /* EVP_PKEY_CTX */
- {
- if (!get_pkey_public_key(env, argv, 0, 4, &pkey, &ret))
- goto err; /* An exception is present in ret */
+ if (!get_pkey_public_key(env, argv, 0, 4, pkey_type, &pkey, &ret))
+ goto err; /* An exception is present in ret */
- if ((ctx = EVP_PKEY_CTX_new(pkey, NULL)) == NULL)
- assign_goto(ret, err, EXCP_ERROR(env, "Can't allocate new EVP_PKEY_CTX"));
+ if (argv[0] == atom_eddsa) {
+# ifdef HAVE_EDDSA
+ EVP_MD_CTX *mdctx = NULL;
+ if (!FIPS_MODE()) {
+ if ((mdctx = EVP_MD_CTX_new()) == NULL)
+ assign_goto(ret, err, EXCP_ERROR(env, "Can't EVP_MD_CTX_new"));
- if (argv[0] != atom_eddsa) {
-#ifdef HAS_3_0_API
- EVP_SIGNATURE *sig_alg = get_prefetched_sign_algo(argv[0]);
+ if (EVP_DigestVerifyInit(mdctx, NULL, NULL, NULL, pkey) != 1)
+ assign_goto(ret, err, EXCP_ERROR(env, "Can't EVP_DigestVerifyInit"));
- if (!sig_alg) {
- if (EVP_PKEY_verify_init(ctx) != 1) {
- assign_goto(ret, err, EXCP_ERROR(env, "Can't EVP_PKEY_verify_init"));
- }
- }
- else {
-# ifdef HAVE_ML_DSA
- if (EVP_PKEY_verify_message_init(ctx, sig_alg, NULL) != 1)
- assign_goto(ret, err, EXCP_ERROR(env, "Can't EVP_PKEY_verify_message_init"));
-# else
- assign_goto(ret, err, EXCP_ERROR(env, "Unknown signature algorithm"));
-# endif
- }
-#else
+ result = EVP_DigestVerify(mdctx, sig_bin.data, sig_bin.size, tbs, tbslen);
+ if (mdctx)
+ EVP_MD_CTX_free(mdctx);
+ }
+ else
+# endif /* HAVE_EDDSA */
+ assign_goto(ret, err, EXCP_NOTSUP_N(env, 0, "eddsa not supported"));
+ }
+ else {
+ if ((ctx = EVP_PKEY_CTX_new(pkey, NULL)) == NULL) {
+ assign_goto(ret, err, EXCP_ERROR(env, "Can't allocate new EVP_PKEY_CTX"));
+ }
+# ifdef HAS_PREFETCH_SIGN_INIT
+ if (pkey_type && pkey_type->sign.alg) {
+ if (EVP_PKEY_verify_message_init(ctx, pkey_type->sign.alg, NULL) != 1)
+ assign_goto(ret, err, EXCP_ERROR(env, "Can't EVP_PKEY_verify_message_init"));
+ }
+ else
+# endif
+ {
if (EVP_PKEY_verify_init(ctx) != 1) {
assign_goto(ret, err, EXCP_ERROR(env, "Can't EVP_PKEY_verify_init"));
- }
-#endif
- if (md != NULL) {
- if (EVP_PKEY_CTX_set_signature_md(ctx, md) != 1)
- assign_goto(ret, err, EXCP_ERROR(env, "Can't EVP_PKEY_CTX_set_signature_md"));
}
}
+ if (md != NULL) {
+ if (EVP_PKEY_CTX_set_signature_md(ctx, md) != 1)
+ assign_goto(ret, err, EXCP_ERROR(env, "Can't EVP_PKEY_CTX_set_signature_md"));
+ }
if (argv[0] == atom_rsa) {
if (EVP_PKEY_CTX_set_rsa_padding(ctx, sig_opt.rsa_padding) != 1)
@@ -993,46 +1064,28 @@ ERL_NIF_TERM pkey_verify_nif(ErlNifEnv *env, int argc, const ERL_NIF_TERM argv[]
# endif
}
- if (argv[0] == atom_eddsa) {
-# ifdef HAVE_EDDSA
- EVP_MD_CTX *mdctx = NULL;
- if (!FIPS_MODE()) {
- if ((mdctx = EVP_MD_CTX_new()) == NULL)
- assign_goto(ret, err, EXCP_ERROR(env, "Can't EVP_MD_CTX_new"));
-
- if (EVP_DigestVerifyInit(mdctx, NULL, NULL, NULL, pkey) != 1)
- assign_goto(ret, err, EXCP_ERROR(env, "Can't EVP_DigestVerifyInit"));
-
- result = EVP_DigestVerify(mdctx, sig_bin.data, sig_bin.size, tbs, tbslen);
- if (mdctx)
- EVP_MD_CTX_free(mdctx);
- }
- else
-# endif /* HAVE_EDDSA */
- assign_goto(ret, err, EXCP_NOTSUP_N(env, 0, "eddsa not supported"));
- } else {
- /* RSA or DSS */
- if (md != NULL) {
- ERL_VALGRIND_ASSERT_MEM_DEFINED(tbs, EVP_MD_size(md));
- }
- result = EVP_PKEY_verify(ctx, sig_bin.data, sig_bin.size, tbs, tbslen);
+ /* RSA or DSS */
+ if (md != NULL) {
+ ERL_VALGRIND_ASSERT_MEM_DEFINED(tbs, EVP_MD_size(md));
}
+ result = EVP_PKEY_verify(ctx, sig_bin.data, sig_bin.size, tbs, tbslen);
+ }
- ret = (result == 1 ? atom_true : atom_false);
+ ret = (result == 1 ? atom_true : atom_false);
- err:
- if (ctx)
- EVP_PKEY_CTX_free(ctx);
- if (pkey)
- EVP_PKEY_free(pkey);
+err:
+ if (ctx)
+ EVP_PKEY_CTX_free(ctx);
+ if (pkey)
+ EVP_PKEY_free(pkey);
+
+ return ret;
- return ret;
- }
/* End of HAS_EVP_PKEY_CTX */
#else
/* Old interface - before EVP_PKEY_CTX */
{
- if (!get_pkey_public_key(env, argv, 0, 4, &pkey, &ret))
+ if (!get_pkey_public_key(env, argv, 0, 4, NULL, &pkey, &ret))
goto err; /* An exception is present in ret */
if (argv[0] == atom_rsa) {
@@ -1149,7 +1202,7 @@ static int get_pkey_crypt_options(ErlNifEnv *env,
if (!enif_is_atom(env, tpl_terms[1]))
assign_goto(*err_return, err, EXCP_BADARG_N(env, options_arg_num, "Atom expected as argument to option signature_md"));
- if (!get_pkey_digest_type(env, argv[algorithm_arg_num],
+ if (!get_pkey_digest_type(env, argv[algorithm_arg_num], NULL,
options_arg_num, tpl_terms[1],
&opt_md, err_return))
goto err; /* An exception is present in ret */
@@ -1163,7 +1216,7 @@ static int get_pkey_crypt_options(ErlNifEnv *env,
if (tpl_terms[1] != atom_sha)
assign_goto(*err_return, err, EXCP_BADARG_N(env, options_arg_num, "Only 'sha' is supported in option rsa_mgf1_md"));
#endif
- if (!get_pkey_digest_type(env, argv[algorithm_arg_num],
+ if (!get_pkey_digest_type(env, argv[algorithm_arg_num], NULL,
options_arg_num, tpl_terms[1],
&opt_md, err_return))
goto err; /* An exception is present in ret */
@@ -1185,7 +1238,7 @@ static int get_pkey_crypt_options(ErlNifEnv *env,
if (tpl_terms[1] != atom_sha)
assign_goto(*err_return, err, EXCP_BADARG_N(env, options_arg_num, "Only 'sha' is supported in option rsa_oaep_md"));
#endif
- if (!get_pkey_digest_type(env, argv[algorithm_arg_num],
+ if (!get_pkey_digest_type(env, argv[algorithm_arg_num], NULL,
options_arg_num, tpl_terms[1],
&opt_md, err_return))
goto err; /* An exception is present in ret */
@@ -1254,10 +1307,10 @@ ERL_NIF_TERM pkey_crypt_nif(ErlNifEnv *env, int argc, const ERL_NIF_TERM argv[])
#endif
if (is_private) {
- if (!get_pkey_private_key(env, argv, 0, 2, &pkey, &ret))
+ if (!get_pkey_private_key(env, argv, 0, 2, NULL, &pkey, &ret))
goto err; /* An exception is present in ret */
} else {
- if (!get_pkey_public_key(env, argv, 0, 2, &pkey, &ret))
+ if (!get_pkey_public_key(env, argv, 0, 2, NULL, &pkey, &ret))
goto err; /* An exception is present in ret */
}
@@ -1497,7 +1550,7 @@ ERL_NIF_TERM privkey_to_pubkey_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM
if (!check_pkey_algorithm_type(env, 0, argv[0], 0, &ret))
goto err; /* An exception is present in ret */
- if (!get_pkey_private_key(env, argv, 0, 1, &pkey, &ret)) // handles engine
+ if (!get_pkey_private_key(env, argv, 0, 1, NULL, &pkey, &ret)) // handles engine
goto err; /* An exception is present in ret */
if (argv[0] == atom_rsa) {
diff --git a/lib/crypto/c_src/pkey.h b/lib/crypto/c_src/pkey.h
index 257a755aef..ba5f7c4423 100644
--- a/lib/crypto/c_src/pkey.h
+++ b/lib/crypto/c_src/pkey.h
@@ -25,23 +25,44 @@
#include "common.h"
-void prefetched_sign_algo_init(void);
+void prefetched_sign_algo_init(ErlNifEnv*);
-#ifdef HAS_3_0_API
enum pkey_format_t {
PKEY_PUB = 0,
PKEY_PRIV = 1,
PKEY_PRIV_SEED = 2
};
+
+struct pkey_type_t {
+ union {
+ const char* atom_str; // before init
+ ERL_NIF_TERM atom; // after init
+ }name;
+ const int evp_pkey_id;
+ union {
+ const char* alg_str; // before init
+#ifdef HAS_PREFETCH_SIGN_INIT
+ EVP_SIGNATURE* alg; // after init
+#endif
+ } sign;
+ const bool allow_seed;
+};
+
+struct pkey_type_t* get_pkey_type(ERL_NIF_TERM alg_atom);
+ERL_NIF_TERM build_pkey_type_list(ErlNifEnv* env, ERL_NIF_TERM tail, bool fips);
+
+#ifdef HAS_3_0_API
int get_pkey_from_octet_string(ErlNifEnv*,
ERL_NIF_TERM alg_atom,
ERL_NIF_TERM key_bin,
enum pkey_format_t,
+ struct pkey_type_t *pkey_type,
EVP_PKEY **pkey_p,
ERL_NIF_TERM *ret_p);
#endif
ERL_NIF_TERM pkey_sign_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]);
+ERL_NIF_TERM pkey_sign_heavy_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]);
ERL_NIF_TERM pkey_verify_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]);
ERL_NIF_TERM pkey_crypt_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]);
ERL_NIF_TERM privkey_to_pubkey_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]);
diff --git a/lib/crypto/src/crypto.erl b/lib/crypto/src/crypto.erl
index 27dc2e51dd..53e392b412 100644
--- a/lib/crypto/src/crypto.erl
+++ b/lib/crypto/src/crypto.erl
@@ -279,6 +279,7 @@ end
strong_rand_bytes_nif/1, strong_rand_range_nif/1, rand_uniform_nif/2,
mod_exp_nif/4, do_exor/2, hash_equals_nif/2, pbkdf2_hmac_nif/5,
pkey_sign_nif/5, pkey_verify_nif/6, pkey_crypt_nif/6,
+ pkey_sign_heavy_nif/5,
encapsulate_key_nif/2, decapsulate_key_nif/3,
rsa_generate_key_nif/2, dh_generate_key_nif/4, dh_compute_key_nif/3,
evp_compute_key_nif/3, evp_generate_key_nif/2, privkey_to_pubkey_nif/2,
@@ -823,7 +824,7 @@ stop() ->
Hashs :: [sha1() | sha2() | sha3() | sha3_xof() | blake2() | ripemd160 | sm3 | compatibility_only_hash()],
Ciphers :: [cipher()],
KEMs :: [kem()],
- PKs :: [rsa | dss | ecdsa | dh | ecdh | eddh | ec_gf2m | mldsa()],
+ PKs :: [rsa | dss | ecdsa | dh | ecdh | eddh | ec_gf2m | mldsa() | slh_dsa()],
Macs :: [hmac | cmac | poly1305],
Curves :: [ec_named_curve() | edwards_curve_dh() | edwards_curve_ed()],
RSAopts :: [rsa_sign_verify_opt() | rsa_opt()] .
@@ -2438,10 +2439,13 @@ rand_seed_nif(_Seed) -> ?nif_stub.
%%%================================================================
-doc "Algorithms for sign and verify.".
-doc(#{group => <<"Public Key Sign and Verify">>}).
--type pk_sign_verify_algs() :: rsa | dss | ecdsa | eddsa | mldsa().
+-type pk_sign_verify_algs() :: rsa | dss | ecdsa | eddsa | mldsa() | slh_dsa().
-type mldsa() :: mldsa44 | mldsa65 | mldsa87.
-type mldsa_private() :: {seed | expandedkey, binary()}.
-type mldsa_public() :: binary().
+-type slh_dsa() :: slh_dsa_shake_256s | slh_dsa_shake_256f | slh_dsa_sha2_256s | slh_dsa_sha2_256f.
+-type slh_dsa_private() :: binary().
+-type slh_dsa_public() :: binary().
-doc(#{group => <<"Public Key Sign and Verify">>,
equiv => rsa_sign_verify_padding()}).
@@ -2488,6 +2492,7 @@ Options for sign and verify.
| [ecdsa_private() | ecdsa_params()]
| [eddsa_private() | eddsa_params()]
| mldsa_private()
+ | slh_dsa_private()
| engine_key_ref(),
Signature :: binary() .
@@ -2522,18 +2527,36 @@ See also `public_key:sign/3`.
| [ecdsa_private() | ecdsa_params()]
| [eddsa_private() | eddsa_params()]
| mldsa_private()
+ | slh_dsa_private()
| engine_key_ref(),
Options :: pk_sign_verify_opts(),
Signature :: binary() .
-sign(Algorithm0, Type0, Data, Key, Options) ->
+sign(Algorithm0, Type0, Data, Key0, Options) ->
{Algorithm, Type} = sign_verify_compatibility(Algorithm0, Type0, Data),
- ?nif_call(pkey_sign_nif(Algorithm, Type, Data, format_pkey(Algorithm, Key), Options),
- {1, 2, 3, 4, 5},
- [Algorithm0, Type0, Data, Key, Options]).
+ Key = format_pkey(Algorithm, Key0),
+ case is_heavy(Algorithm) of
+ false ->
+ ?nif_call(pkey_sign_nif(Algorithm, Type, Data, Key, Options),
+ {1, 2, 3, 4, 5},
+ [Algorithm0, Type0, Data, Key0, Options]);
+ true ->
+ ?nif_call(pkey_sign_heavy_nif(Algorithm, Type, Data, Key, Options),
+ {1, 2, 3, 4, 5},
+ [Algorithm0, Type0, Data, Key0, Options])
+ end.
+
pkey_sign_nif(_Algorithm, _Type, _Digest, _Key, _Options) -> ?nif_stub.
+pkey_sign_heavy_nif(_Algorithm, _Type, _Digest, _Key, _Options) -> ?nif_stub.
+
+is_heavy(slh_dsa_shake_256s) -> true;
+is_heavy(slh_dsa_shake_256f) -> true;
+is_heavy(slh_dsa_sha2_256s) -> true;
+is_heavy(slh_dsa_sha2_256f) -> true;
+is_heavy(_) -> false.
+
%%%----------------------------------------------------------------
%%% Verify
@@ -2554,6 +2577,7 @@ pkey_sign_nif(_Algorithm, _Type, _Digest, _Key, _Options) -> ?nif_stub.
| [ecdsa_public() | ecdsa_params()]
| [eddsa_public() | eddsa_params()]
| mldsa_public()
+ | slh_dsa_public()
| engine_key_ref(),
Result :: boolean().
@@ -2588,6 +2612,7 @@ See also `public_key:verify/4`.
| [ecdsa_public() | ecdsa_params()]
| [eddsa_public() | eddsa_params()]
| mldsa_public()
+ | slh_dsa_public()
| engine_key_ref(),
Options :: pk_sign_verify_opts(),
Result :: boolean().
@@ -2793,11 +2818,10 @@ pkey_crypt_nif(_Algorithm, _In, _Key, _Options, _IsPrivate, _IsEncrypt) -> ?nif_
since => <<"OTP R16B01">>}).
-spec generate_key(Type, Params)
-> {PublicKey, PrivKeyOut}
- when Type :: dh | ecdh | eddh | eddsa | rsa | mldsa() | mlkem512 | mlkem768 | mlkem1024| srp,
+ when Type :: dh | ecdh | eddh | eddsa | rsa | mldsa() | mlkem512 | mlkem768 | mlkem1024 | slh_dsa() | srp,
PublicKey :: dh_public() | ecdh_public() | rsa_public() | srp_public(),
PrivKeyOut :: dh_private() | ecdh_private() | rsa_private() | {srp_public(),srp_private()},
- Params :: dh_params() | ecdh_params() | eddsa_params() | rsa_params() | srp_gen_params() | []
- .
+ Params :: dh_params() | ecdh_params() | eddsa_params() | rsa_params() | srp_gen_params() | [].
generate_key(Type, Params) ->
generate_key(Type, Params, undefined).
@@ -2825,7 +2849,7 @@ Uses the [3-tuple style](`m:crypto#error_3tup`) for error handling.
since => <<"OTP R16B01">>}).
-spec generate_key(Type, Params, PrivKeyIn)
-> {PublicKey, PrivKeyOut}
- when Type :: dh | ecdh | eddh | eddsa | rsa | mldsa() | mlkem512 | mlkem768 | mlkem1024 | srp,
+ when Type :: dh | ecdh | eddh | eddsa | rsa | mldsa() | mlkem512 | mlkem768 | mlkem1024 | srp | slh_dsa(),
PublicKey :: dh_public() | ecdh_public() | rsa_public() | srp_public(),
PrivKeyIn :: undefined | dh_private() | ecdh_private() | rsa_private() | {srp_public(),srp_private()},
PrivKeyOut :: dh_private() | ecdh_private() | rsa_private() | {srp_public(),srp_private()},
diff --git a/lib/crypto/test/crypto_SUITE.erl b/lib/crypto/test/crypto_SUITE.erl
index 6f780d467f..cd348278f9 100644
--- a/lib/crypto/test/crypto_SUITE.erl
+++ b/lib/crypto/test/crypto_SUITE.erl
@@ -1302,7 +1302,11 @@ sign_verify_oqs_do(Alg) ->
%% Supported by OpenSSL 3.5
mldsa_sign_ciphers() ->
- [mldsa44, mldsa65, mldsa87].
+ [mldsa44, mldsa65, mldsa87,
+ slh_dsa_shake_256s,
+ slh_dsa_shake_256f,
+ slh_dsa_sha2_256s,
+ slh_dsa_sha2_256f].
%%--------------------------------------------------------------------
use_all_ec_sign_verify(_Config) ->
--
2.51.0