From c10ab62335b6f4909bfeb58657a5adb3eed01bfb Mon Sep 17 00:00:00 2001 From: olszomal Date: Tue, 16 Jun 2026 08:41:50 +0200 Subject: [PATCH 01/14] Add PKCS#11 PQC mechanism constants --- src/pkcs11.h | 33 +++++++++++++++++++++++++++++++++ 1 file changed, 33 insertions(+) diff --git a/src/pkcs11.h b/src/pkcs11.h index c42257bb..7878d5f1 100644 --- a/src/pkcs11.h +++ b/src/pkcs11.h @@ -360,6 +360,8 @@ typedef unsigned long ck_key_type_t; #define CKK_GOSTR3411 (0x31UL) #define CKK_GOST28147 (0x32UL) #define CKK_EC_EDWARDS (0x40UL) +#define CKK_ML_DSA (0x4AUL) +#define CKK_SLH_DSA (0x4BUL) #define CKK_VENDOR_DEFINED (1UL << 31) /* @@ -482,6 +484,7 @@ typedef unsigned long ck_attribute_type_t; #define CKA_OTP_SERVICE_LOGO_TYPE (0x22DUL) #define CKA_OTP_COUNTER (0x22EUL) #define CKA_OTP_TIME (0x22FUL) +#define CKA_PARAMETER_SET (0x61DUL) #define CKA_ALLOWED_MECHANISMS (CKF_ARRAY_ATTRIBUTE | 0x600UL) #define CKA_VENDOR_DEFINED (1UL << 31) @@ -526,8 +529,13 @@ typedef unsigned long ck_mechanism_type_t; #define CKM_DSA_SHA256 (0x14UL) #define CKM_DSA_SHA384 (0x15UL) #define CKM_DSA_SHA512 (0x16UL) +#define CKM_ML_DSA_KEY_PAIR_GEN (0x1CUL) +#define CKM_ML_DSA (0x1DUL) #define CKM_DH_PKCS_KEY_PAIR_GEN (0x20UL) #define CKM_DH_PKCS_DERIVE (0x21UL) +/* PKCS#11 v3.2: SLH-DSA */ +#define CKM_SLH_DSA_KEY_PAIR_GEN (0x2EUL) +#define CKM_SLH_DSA (0x2FUL) #define CKM_X9_42_DH_KEY_PAIR_GEN (0x30UL) #define CKM_X9_42_DH_DERIVE (0x31UL) #define CKM_X9_42_DH_HYBRID_DERIVE (0x32UL) @@ -772,8 +780,31 @@ typedef unsigned long ck_mechanism_type_t; #define CKM_DH_PKCS_PARAMETER_GEN (0x2001UL) #define CKM_X9_42_DH_PARAMETER_GEN (0x2002UL) #define CKM_AES_KEY_WRAP (0x2109UL) +#define CKM_PQC_FALCON (CKM_VENDOR_DEFINED + 0x10025UL) #define CKM_VENDOR_DEFINED (1UL << 31) +/* CKP (ML-DSA) */ +#define CKP_ML_DSA_44 (0x0001UL) +#define CKP_ML_DSA_65 (0x0002UL) +#define CKP_ML_DSA_87 (0x0003UL) + +/* CKP (SLH-DSA) */ +#define CKP_SLH_DSA_SHA2_128S (0x0001UL) +#define CKP_SLH_DSA_SHAKE_128S (0x0002UL) +#define CKP_SLH_DSA_SHA2_128F (0x0003UL) +#define CKP_SLH_DSA_SHAKE_128F (0x0004UL) +#define CKP_SLH_DSA_SHA2_192S (0x0005UL) +#define CKP_SLH_DSA_SHAKE_192S (0x0006UL) +#define CKP_SLH_DSA_SHA2_192F (0x0007UL) +#define CKP_SLH_DSA_SHAKE_192F (0x0008UL) +#define CKP_SLH_DSA_SHA2_256S (0x0009UL) +#define CKP_SLH_DSA_SHAKE_256S (0x000AUL) +#define CKP_SLH_DSA_SHA2_256F (0x000BUL) +#define CKP_SLH_DSA_SHAKE_256F (0x000CUL) + +/* CKP (FALCON) */ +#define CKP_FALCON_512 (0x0001UL) +#define CKP_FALCON_1024 (0x0002UL) struct ck_mechanism { @@ -1442,6 +1473,8 @@ typedef struct ck_function_list **CK_FUNCTION_LIST_PTR_PTR; typedef struct ck_c_initialize_args CK_C_INITIALIZE_ARGS; typedef struct ck_c_initialize_args *CK_C_INITIALIZE_ARGS_PTR; +typedef CK_ULONG CK_SIGN_PARAMETER_SET_TYPE; + #define NULL_PTR NULL /* Delete the helper macros defined at the top of the file. */ From c4a47b6a24e9471106d033867a3914ac415d0721 Mon Sep 17 00:00:00 2001 From: olszomal Date: Tue, 16 Jun 2026 08:44:57 +0200 Subject: [PATCH 02/14] Fix EdDSA example includes outside OpenSSL guards --- examples/ed25519keygen.c | 6 +++--- examples/ed448keygen.c | 6 +++--- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/examples/ed25519keygen.c b/examples/ed25519keygen.c index 67160de2..9cb9c2e8 100644 --- a/examples/ed25519keygen.c +++ b/examples/ed25519keygen.c @@ -27,13 +27,13 @@ * SUCH DAMAGE. */ +#include +#include + #if !defined(OPENSSL_NO_EC) && \ (OPENSSL_VERSION_NUMBER >= 0x30000000L) && \ (OPENSSL_VERSION_NUMBER < 0x40000000L) -#include -#include - #define CHECK_ERR(cond, txt, code) \ do { \ if (cond) { \ diff --git a/examples/ed448keygen.c b/examples/ed448keygen.c index 5a87bfbd..04153973 100644 --- a/examples/ed448keygen.c +++ b/examples/ed448keygen.c @@ -27,13 +27,13 @@ * SUCH DAMAGE. */ +#include +#include + #if !defined(OPENSSL_NO_EC) && \ (OPENSSL_VERSION_NUMBER >= 0x30000000L) && \ (OPENSSL_VERSION_NUMBER < 0x40000000L) -#include -#include - #define CHECK_ERR(cond, txt, code) \ do { \ if (cond) { \ From 2644de75b0fda9213cd368447950c3659d9e486d Mon Sep 17 00:00:00 2001 From: olszomal Date: Tue, 16 Jun 2026 09:05:22 +0200 Subject: [PATCH 03/14] Fix EdDSA raw public key creation to use default provider --- src/p11_eddsa.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/p11_eddsa.c b/src/p11_eddsa.c index d0f90862..8e510862 100644 --- a/src/p11_eddsa.c +++ b/src/p11_eddsa.c @@ -563,7 +563,9 @@ static EVP_PKEY *pkcs11_get_evp_key_ed25519(PKCS11_OBJECT_private *key) if (pkcs11_get_raw_public_key(key, &raw, &rawlen) < 0) return NULL; - pkey = EVP_PKEY_new_raw_public_key(EVP_PKEY_ED25519, NULL, raw, rawlen); + /* Build a software EVP_PKEY from the raw public key using the default provider. + * Without the property query OpenSSL may fetch our pkcs11prov keymgmt. */ + pkey = EVP_PKEY_new_raw_public_key_ex(NULL, "ED25519", "provider=default", raw, rawlen); OPENSSL_free(raw); if (!pkey) @@ -598,7 +600,7 @@ static EVP_PKEY *pkcs11_get_evp_key_ed448(PKCS11_OBJECT_private *key) if (pkcs11_get_raw_public_key(key, &raw, &rawlen) < 0) return NULL; - pkey = EVP_PKEY_new_raw_public_key(EVP_PKEY_ED448, NULL, raw, rawlen); + pkey = EVP_PKEY_new_raw_public_key_ex(NULL, "ED448", "provider=default", raw, rawlen); OPENSSL_free(raw); if (!pkey) From 9918df028502305ac032d94de24b661a74f1253d Mon Sep 17 00:00:00 2001 From: olszomal Date: Tue, 16 Jun 2026 09:35:38 +0200 Subject: [PATCH 04/14] Fix PKCS#11 session and attribute cleanup leaks --- src/p11_eddsa.c | 6 ++++++ src/p11_key.c | 44 ++++++++++++++++++++++++++++++++++++-------- src/p11_pkey.c | 4 ++++ src/p11_rsa.c | 6 +++++- 4 files changed, 51 insertions(+), 9 deletions(-) diff --git a/src/p11_eddsa.c b/src/p11_eddsa.c index 8e510862..2a081051 100644 --- a/src/p11_eddsa.c +++ b/src/p11_eddsa.c @@ -81,6 +81,8 @@ static int pkcs11_eddsa_pmeth_sign(EVP_PKEY_CTX *ctx, unsigned char *sig, if (pkcs11_get_session(slot, 0, &session)) return 0; + pkcs11_put_session(slot, session); + if (!pkcs11_evp_pkey_eddsa_sign(key, sig, siglen, tbs, tbslen)) return 0; @@ -123,6 +125,8 @@ static int pkcs11_eddsa_pmeth_digestsign(EVP_MD_CTX *ctx, unsigned char *sig, if (pkcs11_get_session(slot, 0, &session)) return -1; + pkcs11_put_session(slot, session); + /* Step 1: caller asks for signature length only */ if (sig == NULL) { if (EVP_PKEY_id(pkey) == EVP_PKEY_ED25519) @@ -542,6 +546,8 @@ static int pkcs11_get_raw_public_key(PKCS11_OBJECT_private *key, } end: + pkcs11_put_session(slot, session); + if (!ok) { OPENSSL_free(*raw); *raw = NULL; diff --git a/src/p11_key.c b/src/p11_key.c index 29d5f216..3047a60a 100644 --- a/src/p11_key.c +++ b/src/p11_key.c @@ -214,6 +214,7 @@ PKCS11_OBJECT_private *pkcs11_object_from_handle(PKCS11_SLOT_private *slot, OPENSSL_free(data); break; #endif /* !defined(OPENSSL_NO_ECX) && OPENSSL_VERSION_NUMBER >= 0x30000000L */ + default: /* Ignore any keys we don't understand */ pkcs11_log(ctx, LOG_DEBUG, @@ -308,9 +309,13 @@ PKCS11_OBJECT_private *pkcs11_object_from_object(PKCS11_OBJECT_private *obj, CK_SESSION_HANDLE session, CK_OBJECT_CLASS object_class) { PKCS11_TEMPLATE tmpl = {0}; + PKCS11_OBJECT_private *ret; + pkcs11_addattr_var(&tmpl, CKA_CLASS, object_class); pkcs11_addattr(&tmpl, CKA_ID, obj->id, obj->id_len); - return pkcs11_object_from_template(obj->slot, session, &tmpl); + ret = pkcs11_object_from_template(obj->slot, session, &tmpl); + pkcs11_zap_attrs(&tmpl); + return ret; } void pkcs11_object_free(PKCS11_OBJECT_private *obj) @@ -380,6 +385,8 @@ int pkcs11_reload_object(PKCS11_OBJECT_private *obj) pkcs11_addattr_s(&tmpl, CKA_LABEL, obj->label); obj->object = pkcs11_handle_from_template(slot, session, &tmpl); + + pkcs11_zap_attrs(&tmpl); pkcs11_put_session(slot, session); if (obj->object == CK_INVALID_HANDLE) @@ -427,6 +434,7 @@ int pkcs11_rsa_keygen(PKCS11_SLOT_private *slot, unsigned int bits, pubtmpl.attrs, pubtmpl.nattr, privtmpl.attrs, privtmpl.nattr, &pub_key_obj, &priv_key_obj)); + pkcs11_put_session(slot, session); /* zap all memory allocated when building the template */ @@ -469,18 +477,26 @@ int pkcs11_ec_keygen(PKCS11_SLOT_private *slot, const char *curve, curve_nid = OBJ_sn2nid(curve); if (curve_nid == NID_undef) curve_nid = OBJ_ln2nid(curve); - if (curve_nid == NID_undef) + if (curve_nid == NID_undef) { + pkcs11_put_session(slot, session); return -1; + } curve_obj = OBJ_nid2obj(curve_nid); - if (!curve_obj) + if (!curve_obj) { + pkcs11_put_session(slot, session); return -1; + } /* convert to DER format and take just the length */ ec_params_len = i2d_ASN1_OBJECT(curve_obj, NULL); - if (ec_params_len < 0) + if (ec_params_len < 0) { + pkcs11_put_session(slot, session); return -1; + } ec_params = OPENSSL_malloc(ec_params_len); - if (!ec_params) + if (!ec_params) { + pkcs11_put_session(slot, session); return -1; + } /** * ec_params points to beginning of DER encoded object. Since we need this * location later and OpenSSL changes it in i2d_ASN1_OBJECT to point to 1 byte @@ -488,8 +504,10 @@ int pkcs11_ec_keygen(PKCS11_SLOT_private *slot, const char *curve, * pointer tmp */ tmp = ec_params; - if (i2d_ASN1_OBJECT(curve_obj, &tmp) < 0) + if (i2d_ASN1_OBJECT(curve_obj, &tmp) < 0) { + pkcs11_put_session(slot, session); return -1; + } /* The following attributes are necessary for ECDSA and ECDH mechanisms */ /* pubkey attributes */ @@ -506,6 +524,7 @@ int pkcs11_ec_keygen(PKCS11_SLOT_private *slot, const char *curve, pubtmpl.attrs, pubtmpl.nattr, privtmpl.attrs, privtmpl.nattr, &pub_key_obj, &priv_key_obj)); + pkcs11_put_session(slot, session); /* zap all memory allocated when building the template */ @@ -548,6 +567,7 @@ int pkcs11_eddsa_keygen(PKCS11_SLOT_private *slot, eddsa_params = (unsigned char *)OID_ED448; eddsa_params_len = sizeof(OID_ED448); } else { + pkcs11_put_session(slot, session); return -1; /* unsupported */ } @@ -566,9 +586,9 @@ int pkcs11_eddsa_keygen(PKCS11_SLOT_private *slot, pubtmpl.attrs, pubtmpl.nattr, privtmpl.attrs, privtmpl.nattr, &pub_key_obj, &priv_key_obj)); - pkcs11_put_session(slot, session); /* cleanup */ + pkcs11_put_session(slot, session); pkcs11_zap_attrs(&privtmpl); pkcs11_zap_attrs(&pubtmpl); @@ -872,10 +892,14 @@ int pkcs11_enumerate_keys(PKCS11_SLOT_private *slot, unsigned int type, const PK if (key_template->label) pkcs11_addattr_s(&tmpl, CKA_LABEL, key_template->label); } - if (pkcs11_get_session(slot, 0, &session)) + if (pkcs11_get_session(slot, 0, &session)) { + pkcs11_zap_attrs(&tmpl); return -1; + } rv = pkcs11_find_keys(slot, session, type, &tmpl); + + pkcs11_zap_attrs(&tmpl); pkcs11_put_session(slot, session); if (rv < 0) { pkcs11_destroy_keys(slot, type); @@ -1234,6 +1258,8 @@ static int pkcs11_try_pkey_rsa_sign(EVP_PKEY_CTX *evp_pkey_ctx, if (pkcs11_get_session(slot, 0, &session)) return -1; + pkcs11_put_session(slot, session); + /* retrieve PSS parameters */ if (EVP_PKEY_CTX_get_rsa_padding(evp_pkey_ctx, &padding) <= 0) return -1; @@ -1307,6 +1333,8 @@ static int pkcs11_try_pkey_rsa_decrypt(EVP_PKEY_CTX *evp_pkey_ctx, if (pkcs11_get_session(slot, 0, &session)) return -1; + pkcs11_put_session(slot, session); + switch (padding) { case RSA_PKCS1_PADDING: break; diff --git a/src/p11_pkey.c b/src/p11_pkey.c index c31c6800..0fe53ec6 100644 --- a/src/p11_pkey.c +++ b/src/p11_pkey.c @@ -870,6 +870,8 @@ static int pkcs11_try_pkey_ec_sign(EVP_PKEY_CTX *evp_pkey_ctx, if (pkcs11_get_session(slot, 0, &session)) return -1; + pkcs11_put_session(slot, session); + return pkcs11_evp_pkey_ec_sign(key, sig, siglen, tbs, tbslen); } #endif /* OPENSSL_NO_EC */ @@ -889,6 +891,8 @@ static int pkcs11_eddsa_sign(unsigned char *sig, size_t *siglen, if (pkcs11_get_session(slot, 0, &session)) return -1; + pkcs11_put_session(slot, session); + return pkcs11_evp_pkey_eddsa_sign(key, sig, siglen, tbs, tbslen); } diff --git a/src/p11_rsa.c b/src/p11_rsa.c index 8d764864..b049bb6d 100644 --- a/src/p11_rsa.c +++ b/src/p11_rsa.c @@ -85,6 +85,8 @@ int pkcs11_private_encrypt(int flen, if (pkcs11_get_session(slot, 0, &session)) return -1; + pkcs11_put_session(slot, session); + siglen = pkcs11_get_key_size(key); if (pkcs11_evp_pkey_rsa_sign(key, NULL, /* EVP_PKEY unused: RSA-PSS unsupported in ENGINE path */ @@ -119,6 +121,8 @@ int pkcs11_private_decrypt(int flen, if (pkcs11_get_session(slot, 0, &session)) return -1; + pkcs11_put_session(slot, session); + /* Openssl API for RSA_private_decrypt() allows to use * RSA_PKCS1_OAEP_PADDING only with SHA_1 hash and and MGF1_SHA1 mask * gen function. It is not possible to use RFC8017 "Label" or @@ -205,10 +209,10 @@ static RSA *pkcs11_get_rsa(PKCS11_OBJECT_private *key) return NULL; success: - pkcs11_put_session(slot, session); rsa = RSA_new(); if (!rsa) goto failure; + pkcs11_put_session(slot, session); #if OPENSSL_VERSION_NUMBER >= 0x10100005L || ( defined(LIBRESSL_VERSION_NUMBER) && LIBRESSL_VERSION_NUMBER >= 0x3050000fL ) RSA_set0_key(rsa, rsa_n, rsa_e, NULL); #else From 147c02d2f560fdb5424188063e4bd93af3102709 Mon Sep 17 00:00:00 2001 From: olszomal Date: Tue, 16 Jun 2026 09:37:29 +0200 Subject: [PATCH 05/14] Fix build without OpenSSL ECX support --- src/libp11-int.h | 2 ++ src/p11_pkey.c | 2 ++ 2 files changed, 4 insertions(+) diff --git a/src/libp11-int.h b/src/libp11-int.h index f9cee6e1..b5626863 100644 --- a/src/libp11-int.h +++ b/src/libp11-int.h @@ -394,10 +394,12 @@ extern int pkcs11_evp_pkey_ec_sign(PKCS11_OBJECT_private *key, const unsigned char *tbs, size_t tbslen); #endif /* OPENSSL_NO_EC */ +#ifndef OPENSSL_NO_ECX /* Sign message input with EdDSA private key via PKCS#11 mechanism */ extern int pkcs11_evp_pkey_eddsa_sign(PKCS11_OBJECT_private *key, unsigned char *sig, size_t *siglen, const unsigned char *tbs, size_t tbslen); +#endif /* OPENSSL_NO_ECX */ /* Decrypt RSA input via PKCS#11 using configured padding and OAEP parameters */ extern int pkcs11_evp_pkey_rsa_decrypt(PKCS11_OBJECT_private *key, diff --git a/src/p11_pkey.c b/src/p11_pkey.c index 0fe53ec6..bacb306c 100644 --- a/src/p11_pkey.c +++ b/src/p11_pkey.c @@ -753,6 +753,7 @@ int pkcs11_evp_pkey_ec_sign(PKCS11_OBJECT_private *key, } #endif /* OPENSSL_NO_EC */ +#ifndef OPENSSL_NO_ECX /* * Sign message input with EdDSA private key via PKCS#11 mechanism. * Returns 1 on success or -1 on failure. @@ -775,6 +776,7 @@ int pkcs11_evp_pkey_eddsa_sign(PKCS11_OBJECT_private *key, return 1; } +#endif /* OPENSSL_NO_ECX */ /* * Decrypt RSA input via PKCS#11 using configured padding and OAEP parameters. From 4507bc855d310257bfae622be3bd493d2e292bd2 Mon Sep 17 00:00:00 2001 From: olszomal Date: Tue, 16 Jun 2026 09:43:37 +0200 Subject: [PATCH 06/14] Use EVP_PKEY_is_a instead of deprecated EVP_PKEY_base_id --- src/p11_key.c | 56 ++++++++++++++++++++++++++++++++++++++++++--------- 1 file changed, 46 insertions(+), 10 deletions(-) diff --git a/src/p11_key.c b/src/p11_key.c index 3047a60a..eeaaddc7 100644 --- a/src/p11_key.c +++ b/src/p11_key.c @@ -122,6 +122,10 @@ static void pkcs11_common_pubkey_attr(PKCS11_TEMPLATE *, const char *, static void pkcs11_common_privkey_attr(PKCS11_TEMPLATE *, const char *, const unsigned char *, size_t, const PKCS11_params *); +#if OPENSSL_VERSION_NUMBER < 0x30000000L +static int EVP_PKEY_is_a(const EVP_PKEY *pkey, const char *name); +#endif /* OPENSSL_VERSION_NUMBER < 0x30000000L */ + #if OPENSSL_VERSION_NUMBER >= 0x30000000L static void pkcs11_set_ex_data_evp_pkey(EVP_PKEY *pkey, PKCS11_KEY *key); static PKCS11_KEY *pkcs11_get_ex_data_evp_pkey(const EVP_PKEY *pkey); @@ -650,7 +654,7 @@ static int pkcs11_store_key(PKCS11_SLOT_private *slot, EVP_PKEY *pk, pkcs11_addattr_bool(&tmpl, CKA_WRAP, TRUE); } #if OPENSSL_VERSION_NUMBER >= 0x10100003L || ( defined(LIBRESSL_VERSION_NUMBER) && LIBRESSL_VERSION_NUMBER >= 0x3050000fL ) - if (EVP_PKEY_base_id(pk) == EVP_PKEY_RSA) { + if (EVP_PKEY_is_a(pk, "RSA") || EVP_PKEY_is_a(pk, "RSA-PSS")) { RSA *rsa = EVP_PKEY_get1_RSA(pk); RSA_get0_key(rsa, &rsa_n, &rsa_e, &rsa_d); RSA_get0_factors(rsa, &rsa_p, &rsa_q); @@ -746,8 +750,8 @@ EVP_PKEY *pkcs11_get_key(PKCS11_OBJECT_private *key0, CK_OBJECT_CLASS object_cla * Using a reference would mean changes to the duplicated EVP_PKEY could * affect the original one. */ - switch (EVP_PKEY_base_id(key->evp_key)) { - case EVP_PKEY_RSA: + if (EVP_PKEY_is_a(key->evp_key, "RSA") || + EVP_PKEY_is_a(key->evp_key, "RSA-PSS")) { /* Do not try to duplicate foreign RSA keys */ rsa = EVP_PKEY_get1_RSA(key->evp_key); if (!rsa) @@ -764,8 +768,8 @@ EVP_PKEY *pkcs11_get_key(PKCS11_OBJECT_private *key0, CK_OBJECT_CLASS object_cla } if (key->object_class != CKO_PRIVATE_KEY) pkcs11_set_ex_data_rsa(rsa, NULL); - break; - case EVP_PKEY_EC: + + } else if (EVP_PKEY_is_a(key->evp_key, "EC")) { #if OPENSSL_VERSION_NUMBER < 0x30000000L || defined(LIBRESSL_VERSION_NUMBER) ec_key = EVP_PKEY_get1_EC_KEY(key->evp_key); if (!ec_key) @@ -787,15 +791,15 @@ EVP_PKEY *pkcs11_get_key(PKCS11_OBJECT_private *key0, CK_OBJECT_CLASS object_cla * so public keys do not have a PKCS11_OBJECT reference */ ret = EVP_PKEY_dup(key->evp_key); #endif - break; #if OPENSSL_VERSION_NUMBER >= 0x30000000L - case EVP_PKEY_ED25519: - case EVP_PKEY_ED448: + } else { ret = EVP_PKEY_dup(key->evp_key); - break; #endif /* OPENSSL_VERSION_NUMBER >= 0x30000000L */ - default: + } + + if (!ret) { pkcs11_log(key0->slot->ctx, LOG_DEBUG, "Unsupported key type\n"); + goto err; } #if OPENSSL_VERSION_NUMBER >= 0x30000000L @@ -1130,6 +1134,38 @@ static void pkcs11_common_privkey_attr(PKCS11_TEMPLATE *privtmpl, pkcs11_addattr_bool(privtmpl, CKA_UNWRAP, TRUE); } +#if OPENSSL_VERSION_NUMBER < 0x30000000L +static int EVP_PKEY_is_a(const EVP_PKEY *pkey, const char *name) + +{ + if (pkey == NULL || name == NULL) + return 0; + + switch (EVP_PKEY_base_id(pkey)) { + case EVP_PKEY_RSA: + return strcmp(name, "RSA") == 0; +#ifdef EVP_PKEY_RSA_PSS + case EVP_PKEY_RSA_PSS: + return strcmp(name, "RSA-PSS") == 0; +#endif /* EVP_PKEY_RSA_PSS */ + case EVP_PKEY_EC: + return strcmp(name, "EC") == 0; +#ifndef OPENSSL_NO_ECX +#ifdef EVP_PKEY_ED25519 + case EVP_PKEY_ED25519: + return strcmp(name, "ED25519") == 0; +#endif /* EVP_PKEY_ED25519 */ +#ifdef EVP_PKEY_ED448 + case EVP_PKEY_ED448: + return strcmp(name, "ED448") == 0; +#endif /* EVP_PKEY_ED448 */ +#endif /* OPENSSL_NO_ECX */ + default: + return 0; + } +} +#endif /* OPENSSL_VERSION_NUMBER < 0x30000000L */ + /* * Destroy all keys of a given type (public or private) */ From 22bc63c13066142ca72dfa55b0fb4216fb47fc42 Mon Sep 17 00:00:00 2001 From: olszomal Date: Tue, 16 Jun 2026 11:55:17 +0200 Subject: [PATCH 07/14] Add PKCS#11 provider support for PQC key generation and signatures Add support for ML-DSA, SLH-DSA, and FALCON keys in the PKCS#11 provider path. This includes key generation, key type detection from CKA_PARAMETER_SET, raw public key export, one-shot signing support, and FALCON verification through PKCS#11. --- src/Makefile.am | 1 + src/libp11-int.h | 89 ++++ src/libp11.exports | 1 + src/libp11.h | 18 +- src/p11_falcon.c | 300 ++++++++++++ src/p11_front.c | 332 ++++++++++++- src/p11_key.c | 462 ++++++++++++++++++ src/p11_load.c | 41 +- src/p11_mldsa.c | 312 +++++++++++++ src/p11_pkey.c | 182 +++++++- src/p11_slhdsa.c | 415 +++++++++++++++++ src/pkcs11.h | 4 +- src/provider.c | 332 ++++++++++++- src/provider_helpers.c | 1006 +++++++++++++++++++++++++++++----------- src/provider_helpers.h | 4 +- 15 files changed, 3176 insertions(+), 323 deletions(-) create mode 100644 src/p11_falcon.c create mode 100644 src/p11_mldsa.c create mode 100644 src/p11_slhdsa.c diff --git a/src/Makefile.am b/src/Makefile.am index 1978e356..92d3fdbe 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -63,6 +63,7 @@ libeng_err_la_CFLAGS = $(AM_CFLAGS) $(OPENSSL_EXTRA_CFLAGS) $(OPENSSL_CFLAGS) \ # ---------------------------------------------------------- libp11_la_SOURCES = libpkcs11.c p11_attr.c p11_cert.c p11_ckr.c \ p11_key.c p11_load.c p11_misc.c p11_rsa.c p11_ec.c p11_eddsa.c \ + p11_mldsa.c p11_slhdsa.c p11_falcon.c \ p11_pkey.c p11_slot.c p11_front.c p11_atfork.c libp11.exports # Compiler flags for libp11 diff --git a/src/libp11-int.h b/src/libp11-int.h index b5626863..4c531e22 100644 --- a/src/libp11-int.h +++ b/src/libp11-int.h @@ -44,6 +44,14 @@ #include "p11_pthread.h" +#if OPENSSL_VERSION_NUMBER >= 0x30000000L +#define EVP_PKEY_FALCON512 0x10001 +#define EVP_PKEY_FALCON1024 0x10002 + +extern int NID_FALCON_512; +extern int NID_FALCON_1024; +#endif /* OPENSSL_VERSION_NUMBER >= 0x30000000L */ + /* forward type declarations */ typedef struct pkcs11_keys PKCS11_keys; typedef struct pkcs11_object_ops PKCS11_OBJECT_ops; @@ -127,6 +135,34 @@ extern PKCS11_OBJECT_ops pkcs11_ed448_ops; # endif /* OPENSSL_VERSION_NUMBER >= 0x30000000L */ #endif /* OPENSSL_NO_EC */ +#if OPENSSL_VERSION_NUMBER >= 0x30500000L +#ifndef OPENSSL_NO_ML_DSA +extern PKCS11_OBJECT_ops pkcs11_mldsa44_ops; +extern PKCS11_OBJECT_ops pkcs11_mldsa65_ops; +extern PKCS11_OBJECT_ops pkcs11_mldsa87_ops; +#endif /* OPENSSL_NO_ML_DSA */ +#ifndef OPENSSL_NO_SLH_DSA +extern PKCS11_OBJECT_ops pkcs11_slhdsa_sha2_128s_ops; +extern PKCS11_OBJECT_ops pkcs11_slhdsa_sha2_128f_ops; +extern PKCS11_OBJECT_ops pkcs11_slhdsa_sha2_192s_ops; +extern PKCS11_OBJECT_ops pkcs11_slhdsa_sha2_192f_ops; +extern PKCS11_OBJECT_ops pkcs11_slhdsa_sha2_256s_ops; +extern PKCS11_OBJECT_ops pkcs11_slhdsa_sha2_256f_ops; +extern PKCS11_OBJECT_ops pkcs11_slhdsa_shake_128s_ops; +extern PKCS11_OBJECT_ops pkcs11_slhdsa_shake_128f_ops; +extern PKCS11_OBJECT_ops pkcs11_slhdsa_shake_192s_ops; +extern PKCS11_OBJECT_ops pkcs11_slhdsa_shake_192f_ops; +extern PKCS11_OBJECT_ops pkcs11_slhdsa_shake_256s_ops; +extern PKCS11_OBJECT_ops pkcs11_slhdsa_shake_256f_ops; +#endif /* OPENSSL_NO_SLH_DSA */ +#endif /* OPENSSL_VERSION_NUMBER >= 0x30500000L */ + +#if OPENSSL_VERSION_NUMBER >= 0x30000000L +extern PKCS11_OBJECT_ops pkcs11_falcon512_ops; +extern PKCS11_OBJECT_ops pkcs11_falcon1024_ops; +#endif /* OPENSSL_VERSION_NUMBER >= 0x30000000L */ + + /* * Internal functions */ @@ -277,6 +313,11 @@ extern PKCS11_OBJECT_private *pkcs11_object_from_handle(PKCS11_SLOT_private *slo extern PKCS11_OBJECT_private *pkcs11_object_from_template(PKCS11_SLOT_private *slot, CK_SESSION_HANDLE session, PKCS11_TEMPLATE *tmpl); +#if OPENSSL_VERSION_NUMBER >= 0x30000000L +/* Get the public key object matching the given PKCS11_KEY */ +extern PKCS11_OBJECT_private *pkcs11_public_object_from_key(PKCS11_KEY *pkey); +#endif /* OPENSSL_VERSION_NUMBER >= 0x30000000L */ + /* Get the corresponding object (same ID, given different object type) */ extern PKCS11_OBJECT_private *pkcs11_object_from_object(PKCS11_OBJECT_private *obj, CK_SESSION_HANDLE session, CK_OBJECT_CLASS object_class); @@ -362,6 +403,26 @@ extern int pkcs11_eddsa_keygen(PKCS11_SLOT_private *tpriv, size_t id_len, const PKCS11_params *params); #endif /* !defined(OPENSSL_NO_ECX) && OPENSSL_VERSION_NUMBER >= 0x30000000L */ +#if OPENSSL_VERSION_NUMBER >= 0x30500000L +#ifndef OPENSSL_NO_ML_DSA +extern int pkcs11_mldsa_keygen(PKCS11_SLOT_private *tpriv, + int nid, const char *label, const unsigned char *id, + size_t id_len, const PKCS11_params *params); +#endif /* OPENSSL_NO_ML_DSA */ + +#ifndef OPENSSL_NO_SLH_DSA +extern int pkcs11_slhdsa_keygen(PKCS11_SLOT_private *tpriv, + int nid, const char *label, const unsigned char *id, + size_t id_len, const PKCS11_params *params); +#endif /* OPENSSL_NO_SLH_DSA */ +#endif /* OPENSSL_VERSION_NUMBER >= 0x30500000L */ + +#if OPENSSL_VERSION_NUMBER >= 0x30000000L +extern int pkcs11_falcon_keygen(PKCS11_SLOT_private *tpriv, + int nid, const char *label, const unsigned char *id, + size_t id_len, const PKCS11_params *params); +#endif /* OPENSSL_VERSION_NUMBER >= 0x30000000L */ + /* Get the RSA key modulus size (in bytes) */ extern int pkcs11_get_key_size(PKCS11_OBJECT_private *); @@ -401,6 +462,34 @@ extern int pkcs11_evp_pkey_eddsa_sign(PKCS11_OBJECT_private *key, const unsigned char *tbs, size_t tbslen); #endif /* OPENSSL_NO_ECX */ +#if OPENSSL_VERSION_NUMBER >= 0x30500000L +#ifndef OPENSSL_NO_ML_DSA +/* Sign message input with ML-DSA private key via PKCS#11 mechanism */ +extern int pkcs11_evp_pkey_mldsa_sign(PKCS11_OBJECT_private *key, + unsigned char *sig, size_t *siglen, + const unsigned char *tbs, size_t tbslen); +#endif /* OPENSSL_NO_ML_DSA */ + +#ifndef OPENSSL_NO_SLH_DSA +/* Sign message input with SLH-DSA private key via PKCS#11 mechanism */ +extern int pkcs11_evp_pkey_slhdsa_sign(PKCS11_OBJECT_private *key, + unsigned char *sig, size_t *siglen, + const unsigned char *tbs, size_t tbslen); +#endif /* OPENSSL_NO_SLH_DSA */ +#endif /* OPENSSL_VERSION_NUMBER >= 0x30500000L */ + +#if OPENSSL_VERSION_NUMBER >= 0x30000000L +/* Sign message input with PQC FALCON private key via PKCS#11 mechanism */ +extern int pkcs11_evp_pkey_falcon_sign(PKCS11_OBJECT_private *key, + unsigned char *sig, size_t *siglen, + const unsigned char *tbs, size_t tbslen); + +/* Verify message input with PQC FALCON public key via PKCS#11 mechanism */ +extern int pkcs11_evp_pkey_falcon_verify(PKCS11_OBJECT_private *key, + const unsigned char *sig, size_t siglen, + const unsigned char *tbs, size_t tbslen); +#endif /* OPENSSL_VERSION_NUMBER >= 0x30000000L */ + /* Decrypt RSA input via PKCS#11 using configured padding and OAEP parameters */ extern int pkcs11_evp_pkey_rsa_decrypt(PKCS11_OBJECT_private *key, const char *mdname, const int pad_mode, diff --git a/src/libp11.exports b/src/libp11.exports index 75ef61ca..f59d61d7 100644 --- a/src/libp11.exports +++ b/src/libp11.exports @@ -39,6 +39,7 @@ PKCS11_store_public_key PKCS11_store_certificate PKCS11_sign PKCS11_evp_pkey_sign +PKCS11_evp_pkey_verify PKCS11_evp_pkey_decrypt PKCS11_private_encrypt PKCS11_private_decrypt diff --git a/src/libp11.h b/src/libp11.h index e9c9df01..2c62007e 100644 --- a/src/libp11.h +++ b/src/libp11.h @@ -64,11 +64,15 @@ typedef struct PKCS11_token_st PKCS11_TOKEN; typedef struct PKCS11_slot_st PKCS11_SLOT; typedef struct PKCS11_ctx_st PKCS11_CTX; typedef struct PKCS11_ec_kgen_st PKCS11_EC_KGEN; -typedef struct PKCS11_eddsa_kgen_st PKCS11_EDDSA_KGEN; +typedef struct PKCS11_nid_kgen_st PKCS11_NID_KGEN; typedef struct PKCS11_rsa_kgen_st PKCS11_RSA_KGEN; typedef struct PKCS11_params PKCS11_params; typedef struct PKCS11_kgen_attrs_st PKCS11_KGEN_ATTRS; +/* Legacy EC-specific name retained for compatibility. + * Use PKCS11_NID_KGEN for new code. */ +#define PKCS11_EDDSA_KGEN PKCS11_NID_KGEN + /** PKCS11 key object (public or private) */ struct PKCS11_key_st { char *label; @@ -131,8 +135,8 @@ struct PKCS11_ec_kgen_st { const char *curve; }; -struct PKCS11_eddsa_kgen_st { - int nid; /* NID_ED25519 or NID_ED448 */ +struct PKCS11_nid_kgen_st { + int nid; }; struct PKCS11_rsa_kgen_st { @@ -147,11 +151,14 @@ struct PKCS11_params { struct PKCS11_kgen_attrs_st { /* Key generation type from OpenSSL. Given the union below this should * be either EVP_PKEY_EC or EVP_PKEY_RSA or EVP_PKEY_ED25519 or EVP_PKEY_ED448 + * EVP_PKEY_ML_DSA_* or EVP_PKEY_SLH_DSA_*. or + * EVP_PKEY_FALCON512 or EVP_PKEY_FALCON1024 */ int type; union { PKCS11_EC_KGEN *ec; PKCS11_EDDSA_KGEN *eddsa; + PKCS11_NID_KGEN *nid; PKCS11_RSA_KGEN *rsa; } kgen; const char *token_label; @@ -557,6 +564,11 @@ extern int PKCS11_evp_pkey_sign(EVP_PKEY *pkey, int type, const char *mdname, unsigned char *sig, size_t *siglen, const unsigned char *tbs, size_t tbslen); +/* Perform a public-key operation using a PKCS#11-backed EVP_PKEY */ +int PKCS11_evp_pkey_verify(EVP_PKEY *pkey, int type, + const unsigned char *sig, size_t siglen, + const unsigned char *tbs, size_t tbslen); + /* Perform a private-key decryption operation using a PKCS#11-backed EVP_PKEY */ extern int PKCS11_evp_pkey_decrypt(EVP_PKEY *pk, int type, const char *mdname, const int pad_mode, const char *mgf1_mdname, diff --git a/src/p11_falcon.c b/src/p11_falcon.c new file mode 100644 index 00000000..a5131921 --- /dev/null +++ b/src/p11_falcon.c @@ -0,0 +1,300 @@ +/* + * Copyright © 2026 Mobi - Com Polska Sp. z o.o. + * Author: Małgorzata Olszówka + * All rights reserved. + * + * This file implements the handling of ML-DSA keys stored on a PKCS11 token. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include "libp11-int.h" +#include + +#if OPENSSL_VERSION_NUMBER >= 0x30000000L + +#define FALCON_512_PUB_LEN 897 +#define FALCON_1024_PUB_LEN 2305 + +/* + * Extract raw PQC FALCON public key bytes from a CKO_PUBLIC_KEY object using CKA_VALUE. + * Returns 1 on success, 0 on failure. + */ +static int extract_pub_from_public_key_obj(PKCS11_CTX_private *ctx, + CK_SESSION_HANDLE session, CK_OBJECT_HANDLE obj, + size_t expected_len, unsigned char **raw, size_t *rawlen) +{ + unsigned char *value = NULL; + size_t value_len = 0; + + if (ctx == NULL || raw == NULL || rawlen == NULL || + obj == CK_INVALID_HANDLE || expected_len == 0) + return 0; + + *raw = NULL; + *rawlen = 0; + + if (pkcs11_getattr_alloc(ctx, session, obj, CKA_VALUE, &value, &value_len)) { + pkcs11_log(ctx, LOG_DEBUG, + "Missing CKA_VALUE attribute on PQC FALCON public key\n"); + return 0; + } + + if (value_len != expected_len) { + pkcs11_log(ctx, LOG_DEBUG, + "Unexpected PQC FALCON public key size: got %lu, expected %lu\n", + (unsigned long)value_len, (unsigned long)expected_len); + OPENSSL_free(value); + return 0; + } + + *raw = value; + *rawlen = value_len; + return 1; +} + +/* + * Extract raw PQC FALCON public key bytes from a CKO_CERTIFICATE object. + * The certificate is read from CKA_VALUE (DER-encoded X.509) and + * the public key is obtained via X.509 parsing. + * Returns 1 on success, 0 on failure. + */ +static int extract_pub_from_cert_obj(PKCS11_CTX_private *ctx, + CK_SESSION_HANDLE session, CK_OBJECT_HANDLE obj, + size_t expected_len, const char *algname, + unsigned char **raw, size_t *rawlen) +{ + const unsigned char *p; + unsigned char *der = NULL; + unsigned char *buf = NULL; + size_t derlen = 0; + size_t len = 0; + X509 *cert = NULL; + EVP_PKEY *pkey = NULL; + int ok = 0; + + if (ctx == NULL || raw == NULL || rawlen == NULL || + obj == CK_INVALID_HANDLE || expected_len == 0 || algname == NULL) + return 0; + + *raw = NULL; + *rawlen = 0; + + if (pkcs11_getattr_alloc(ctx, session, obj, CKA_VALUE, &der, &derlen)) + return 0; + + if (derlen == 0 || derlen > LONG_MAX) + goto end; + + p = der; + cert = d2i_X509(NULL, &p, (long)derlen); + if (cert == NULL || p != der + derlen) + goto end; + + pkey = X509_get_pubkey(cert); + if (pkey == NULL) + goto end; + + if (!EVP_PKEY_is_a(pkey, algname)) + goto end; + + if (EVP_PKEY_get_raw_public_key(pkey, NULL, &len) != 1) + goto end; + + if (len != expected_len) + goto end; + + buf = OPENSSL_malloc(len); + if (buf == NULL) + goto end; + + if (EVP_PKEY_get_raw_public_key(pkey, buf, &len) != 1) + goto end; + + if (len != expected_len) + goto end; + + *raw = buf; + *rawlen = len; + buf = NULL; + ok = 1; + +end: + OPENSSL_free(buf); + OPENSSL_free(der); + EVP_PKEY_free(pkey); + X509_free(cert); + return ok; +} + +/* + * Select an object that can provide public key material. + * + * For a private key object, try to locate a matching CKO_PUBLIC_KEY + * (same CKA_ID). If not found, fall back to CKO_CERTIFICATE. + * + * On success, returns a PKCS11_OBJECT_private pointer. + * If a new object is returned, *needs_free is set to 1 and the caller + * must free it with pkcs11_object_free(). + * + * Returns NULL on failure. + */ +static PKCS11_OBJECT_private *pkcs11_choose_public_source(PKCS11_OBJECT_private *key, + CK_SESSION_HANDLE session, int *needs_free) +{ + PKCS11_OBJECT_private *obj; + + *needs_free = 0; + + if (key->object_class != CKO_PRIVATE_KEY) + return key; + + obj = pkcs11_object_from_object(key, session, CKO_PUBLIC_KEY); + if (obj != NULL && obj->object != CK_INVALID_HANDLE) { + *needs_free = 1; + return obj; + } + if (obj != NULL) + pkcs11_object_free(obj); + + obj = pkcs11_object_from_object(key, session, CKO_CERTIFICATE); + if (obj != NULL && obj->object != CK_INVALID_HANDLE) { + *needs_free = 1; + return obj; + } + if (obj != NULL) + pkcs11_object_free(obj); + + return NULL; +} + +/* + * Retrieve raw PQC FALCON public key bytes. + * + * Preference order: + * 1. CKO_PUBLIC_KEY -> CKA_VALUE + * 2. CKO_CERTIFICATE -> CKA_VALUE (DER) + X.509 parsing + * + * The returned buffer is allocated with OPENSSL_malloc() + * and must be freed by the caller. + * + * Returns 0 on success, -1 on failure. + */ +static int pkcs11_get_raw_public_key(PKCS11_OBJECT_private *key, + size_t expected_len, const char *algname, + unsigned char **raw, size_t *rawlen) +{ + PKCS11_SLOT_private *slot; + PKCS11_CTX_private *ctx; + CK_SESSION_HANDLE session = CK_INVALID_HANDLE; + PKCS11_OBJECT_private *obj = NULL; + int obj_needs_free = 0, ok = 0; + + if (key == NULL || key->slot == NULL || raw == NULL || rawlen == NULL) + return -1; + + *raw = NULL; + *rawlen = 0; + slot = key->slot; + ctx = slot->ctx; + + if (pkcs11_get_session(slot, 0, &session)) + return -1; + + obj = pkcs11_choose_public_source(key, session, &obj_needs_free); + if (obj == NULL || obj->object == CK_INVALID_HANDLE) + goto end; + + switch (obj->object_class) { + case CKO_PUBLIC_KEY: + ok = extract_pub_from_public_key_obj(ctx, session, obj->object, + expected_len, raw, rawlen); + break; + case CKO_CERTIFICATE: + ok = extract_pub_from_cert_obj(ctx, session, obj->object, + expected_len, algname, raw, rawlen); + break; + default: + ok = 0; + break; + } + +end: + if (!ok) { + OPENSSL_free(*raw); + *raw = NULL; + *rawlen = 0; + } + if (obj_needs_free && obj != NULL) + pkcs11_object_free(obj); + + return ok ? 0 : -1; +} + +static EVP_PKEY *pkcs11_get_evp_key_falcon(PKCS11_OBJECT_private *key, + size_t publen, const char *algname) +{ + EVP_PKEY *pkey = NULL; + unsigned char *raw = NULL; + size_t rawlen = 0; + + /* Retrieve the public key in raw format from PKCS#11 */ + if (pkcs11_get_raw_public_key(key, publen, algname, &raw, &rawlen) < 0) + return NULL; + + /* Public key from CKA_VALUE, used only as software public key */ + pkey = EVP_PKEY_new_raw_public_key_ex(NULL, algname, "provider=default", raw, rawlen); + OPENSSL_free(raw); + return pkey; +} + +static EVP_PKEY *pkcs11_get_evp_key_falcon512(PKCS11_OBJECT_private *key) +{ + return pkcs11_get_evp_key_falcon(key, FALCON_512_PUB_LEN, "FALCON-512"); +} + +static EVP_PKEY *pkcs11_get_evp_key_falcon1024(PKCS11_OBJECT_private *key) +{ + return pkcs11_get_evp_key_falcon(key, FALCON_1024_PUB_LEN, "FALCON-1024"); +} + + +PKCS11_OBJECT_ops pkcs11_falcon512_ops = { + EVP_PKEY_FALCON512, + pkcs11_get_evp_key_falcon512, +}; + +PKCS11_OBJECT_ops pkcs11_falcon1024_ops = { + EVP_PKEY_FALCON1024, + pkcs11_get_evp_key_falcon1024, +}; + +#else /* OPENSSL_VERSION_NUMBER >= 0x30000000L */ +/* + * PQC FALCON support is not available: + * - OpenSSL version is older than 3.0. + */ +#warning "PQC FALCON support not built with libp11" + +#endif /* OPENSSL_VERSION_NUMBER >= 0x30000000L */ + +/* vim: set noexpandtab: */ diff --git a/src/p11_front.c b/src/p11_front.c index e8f19f5d..856c30c8 100644 --- a/src/p11_front.c +++ b/src/p11_front.c @@ -434,9 +434,44 @@ int PKCS11_keygen(PKCS11_TOKEN *token, PKCS11_KGEN_ATTRS *kg) #if !defined(OPENSSL_NO_ECX) && OPENSSL_VERSION_NUMBER >= 0x30000000L case EVP_PKEY_ED25519: case EVP_PKEY_ED448: - return pkcs11_eddsa_keygen(slot, kg->kgen.eddsa->nid, + return pkcs11_eddsa_keygen(slot, kg->kgen.nid->nid, kg->key_label, kg->key_id, kg->id_len, kg->key_params); #endif /* !defined(OPENSSL_NO_ECX) && OPENSSL_VERSION_NUMBER >= 0x30000000L */ + +#if OPENSSL_VERSION_NUMBER >= 0x30500000L +#ifndef OPENSSL_NO_ML_DSA + case EVP_PKEY_ML_DSA_44: + case EVP_PKEY_ML_DSA_65: + case EVP_PKEY_ML_DSA_87: + return pkcs11_mldsa_keygen(slot, kg->kgen.nid->nid, + kg->key_label, kg->key_id, kg->id_len, kg->key_params); +#endif /* OPENSSL_NO_ML_DSA */ + +#ifndef OPENSSL_NO_SLH_DSA + case EVP_PKEY_SLH_DSA_SHA2_128S: + case EVP_PKEY_SLH_DSA_SHA2_128F: + case EVP_PKEY_SLH_DSA_SHA2_192S: + case EVP_PKEY_SLH_DSA_SHA2_192F: + case EVP_PKEY_SLH_DSA_SHA2_256S: + case EVP_PKEY_SLH_DSA_SHA2_256F: + case EVP_PKEY_SLH_DSA_SHAKE_128S: + case EVP_PKEY_SLH_DSA_SHAKE_128F: + case EVP_PKEY_SLH_DSA_SHAKE_192S: + case EVP_PKEY_SLH_DSA_SHAKE_192F: + case EVP_PKEY_SLH_DSA_SHAKE_256S: + case EVP_PKEY_SLH_DSA_SHAKE_256F: + return pkcs11_slhdsa_keygen(slot, kg->kgen.nid->nid, + kg->key_label, kg->key_id, kg->id_len, kg->key_params); +#endif /* OPENSSL_NO_SLH_DSA */ +#endif /* OPENSSL_VERSION_NUMBER >= 0x30500000L */ + +#if OPENSSL_VERSION_NUMBER >= 0x30000000L + case EVP_PKEY_FALCON512: + case EVP_PKEY_FALCON1024: + return pkcs11_falcon_keygen(slot, kg->kgen.nid->nid, + kg->key_label, kg->key_id, kg->id_len, kg->key_params); +#endif /* OPENSSL_VERSION_NUMBER >= 0x30000000L */ + default: return -1; } @@ -450,10 +485,9 @@ int PKCS11_generate_key(PKCS11_TOKEN *token, int algorithm, #ifndef OPENSSL_NO_EC PKCS11_EC_KGEN ec_kgen; #endif /* OPENSSL_NO_EC */ -#if !defined(OPENSSL_NO_ECX) && OPENSSL_VERSION_NUMBER >= 0x30000000L - PKCS11_EDDSA_KGEN eddsa_kgen; -#endif /* !defined(OPENSSL_NO_ECX) && OPENSSL_VERSION_NUMBER >= 0x30000000L */ - +#if OPENSSL_VERSION_NUMBER >= 0x30000000L + PKCS11_NID_KGEN nid_kgen; +#endif /* OPENSSL_VERSION_NUMBER >= 0x30000000L */ PKCS11_RSA_KGEN rsa_kgen; PKCS11_KGEN_ATTRS kgen_attrs = { 0 }; @@ -474,10 +508,10 @@ int PKCS11_generate_key(PKCS11_TOKEN *token, int algorithm, #endif /* OPENSSL_NO_EC */ #if !defined(OPENSSL_NO_ECX) && OPENSSL_VERSION_NUMBER >= 0x30000000L case EVP_PKEY_ED25519: - eddsa_kgen.nid = NID_ED25519; + nid_kgen.nid = NID_ED25519; kgen_attrs = (PKCS11_KGEN_ATTRS){ .type = EVP_PKEY_ED25519, - .kgen.eddsa = &eddsa_kgen, + .kgen.nid = &nid_kgen, .token_label = (const char *)token->label, .key_label = label, .key_id = (const unsigned char *)id, @@ -487,10 +521,10 @@ int PKCS11_generate_key(PKCS11_TOKEN *token, int algorithm, break; case EVP_PKEY_ED448: - eddsa_kgen.nid = NID_ED448; + nid_kgen.nid = NID_ED448; kgen_attrs = (PKCS11_KGEN_ATTRS){ .type = EVP_PKEY_ED448, - .kgen.eddsa = &eddsa_kgen, + .kgen.nid = &nid_kgen, .token_label = (const char *)token->label, .key_label = label, .key_id = (const unsigned char *)id, @@ -499,6 +533,224 @@ int PKCS11_generate_key(PKCS11_TOKEN *token, int algorithm, }; break; #endif /* !defined(OPENSSL_NO_ECX) && OPENSSL_VERSION_NUMBER >= 0x30000000L */ + +#if OPENSSL_VERSION_NUMBER >= 0x30500000L +#ifndef OPENSSL_NO_ML_DSA + case EVP_PKEY_ML_DSA_44: + nid_kgen.nid = NID_ML_DSA_44; + kgen_attrs = (PKCS11_KGEN_ATTRS){ + .type = EVP_PKEY_ML_DSA_44, + .kgen.nid = &nid_kgen, + .token_label = (const char *)token->label, + .key_label = label, + .key_id = (const unsigned char *)id, + .id_len = id_len, + .key_params = &key_params + }; + break; + + case EVP_PKEY_ML_DSA_65: + nid_kgen.nid = NID_ML_DSA_65; + kgen_attrs = (PKCS11_KGEN_ATTRS){ + .type = EVP_PKEY_ML_DSA_65, + .kgen.nid = &nid_kgen, + .token_label = (const char *)token->label, + .key_label = label, + .key_id = (const unsigned char *)id, + .id_len = id_len, + .key_params = &key_params + }; + break; + + case EVP_PKEY_ML_DSA_87: + nid_kgen.nid = NID_ML_DSA_87; + kgen_attrs = (PKCS11_KGEN_ATTRS){ + .type = EVP_PKEY_ML_DSA_87, + .kgen.nid = &nid_kgen, + .token_label = (const char *)token->label, + .key_label = label, + .key_id = (const unsigned char *)id, + .id_len = id_len, + .key_params = &key_params + }; + break; +#endif /* OPENSSL_NO_ML_DSA */ + +#ifndef OPENSSL_NO_SLH_DSA + case EVP_PKEY_SLH_DSA_SHA2_128S: + nid_kgen.nid = NID_SLH_DSA_SHA2_128s; + kgen_attrs = (PKCS11_KGEN_ATTRS){ + .type = EVP_PKEY_SLH_DSA_SHA2_128S, + .kgen.nid = &nid_kgen, + .token_label = (const char *)token->label, + .key_label = label, + .key_id = (const unsigned char *)id, + .id_len = id_len, + .key_params = &key_params + }; + break; + case EVP_PKEY_SLH_DSA_SHA2_128F: + nid_kgen.nid = NID_SLH_DSA_SHA2_128f; + kgen_attrs = (PKCS11_KGEN_ATTRS){ + .type = EVP_PKEY_SLH_DSA_SHA2_128F, + .kgen.nid = &nid_kgen, + .token_label = (const char *)token->label, + .key_label = label, + .key_id = (const unsigned char *)id, + .id_len = id_len, + .key_params = &key_params + }; + break; + case EVP_PKEY_SLH_DSA_SHA2_192S: + nid_kgen.nid = NID_SLH_DSA_SHA2_192s; + kgen_attrs = (PKCS11_KGEN_ATTRS){ + .type = EVP_PKEY_SLH_DSA_SHA2_192S, + .kgen.nid = &nid_kgen, + .token_label = (const char *)token->label, + .key_label = label, + .key_id = (const unsigned char *)id, + .id_len = id_len, + .key_params = &key_params + }; + break; + case EVP_PKEY_SLH_DSA_SHA2_192F: + nid_kgen.nid = NID_SLH_DSA_SHA2_192f; + kgen_attrs = (PKCS11_KGEN_ATTRS){ + .type = EVP_PKEY_SLH_DSA_SHA2_192F, + .kgen.nid = &nid_kgen, + .token_label = (const char *)token->label, + .key_label = label, + .key_id = (const unsigned char *)id, + .id_len = id_len, + .key_params = &key_params + }; + break; + case EVP_PKEY_SLH_DSA_SHA2_256S: + nid_kgen.nid = NID_SLH_DSA_SHA2_256s; + kgen_attrs = (PKCS11_KGEN_ATTRS){ + .type = EVP_PKEY_SLH_DSA_SHA2_256S, + .kgen.nid = &nid_kgen, + .token_label = (const char *)token->label, + .key_label = label, + .key_id = (const unsigned char *)id, + .id_len = id_len, + .key_params = &key_params + }; + break; + case EVP_PKEY_SLH_DSA_SHA2_256F: + nid_kgen.nid = NID_SLH_DSA_SHA2_256f; + kgen_attrs = (PKCS11_KGEN_ATTRS){ + .type = EVP_PKEY_SLH_DSA_SHA2_256F, + .kgen.nid = &nid_kgen, + .token_label = (const char *)token->label, + .key_label = label, + .key_id = (const unsigned char *)id, + .id_len = id_len, + .key_params = &key_params + }; + break; + case EVP_PKEY_SLH_DSA_SHAKE_128S: + nid_kgen.nid = NID_SLH_DSA_SHAKE_128s; + kgen_attrs = (PKCS11_KGEN_ATTRS){ + .type = EVP_PKEY_SLH_DSA_SHAKE_128S, + .kgen.nid = &nid_kgen, + .token_label = (const char *)token->label, + .key_label = label, + .key_id = (const unsigned char *)id, + .id_len = id_len, + .key_params = &key_params + }; + break; + case EVP_PKEY_SLH_DSA_SHAKE_128F: + nid_kgen.nid = NID_SLH_DSA_SHAKE_128f; + kgen_attrs = (PKCS11_KGEN_ATTRS){ + .type = EVP_PKEY_SLH_DSA_SHAKE_128F, + .kgen.nid = &nid_kgen, + .token_label = (const char *)token->label, + .key_label = label, + .key_id = (const unsigned char *)id, + .id_len = id_len, + .key_params = &key_params + }; + break; + case EVP_PKEY_SLH_DSA_SHAKE_192S: + nid_kgen.nid = NID_SLH_DSA_SHAKE_192s; + kgen_attrs = (PKCS11_KGEN_ATTRS){ + .type = EVP_PKEY_SLH_DSA_SHAKE_192S, + .kgen.nid = &nid_kgen, + .token_label = (const char *)token->label, + .key_label = label, + .key_id = (const unsigned char *)id, + .id_len = id_len, + .key_params = &key_params + }; + break; + case EVP_PKEY_SLH_DSA_SHAKE_192F: + nid_kgen.nid = NID_SLH_DSA_SHAKE_192f; + kgen_attrs = (PKCS11_KGEN_ATTRS){ + .type = EVP_PKEY_SLH_DSA_SHAKE_192F, + .kgen.nid = &nid_kgen, + .token_label = (const char *)token->label, + .key_label = label, + .key_id = (const unsigned char *)id, + .id_len = id_len, + .key_params = &key_params + }; + break; + case EVP_PKEY_SLH_DSA_SHAKE_256S: + nid_kgen.nid = NID_SLH_DSA_SHAKE_256s; + kgen_attrs = (PKCS11_KGEN_ATTRS){ + .type = EVP_PKEY_SLH_DSA_SHAKE_256S, + .kgen.nid = &nid_kgen, + .token_label = (const char *)token->label, + .key_label = label, + .key_id = (const unsigned char *)id, + .id_len = id_len, + .key_params = &key_params + }; + break; + case EVP_PKEY_SLH_DSA_SHAKE_256F: + nid_kgen.nid = NID_SLH_DSA_SHAKE_256f; + kgen_attrs = (PKCS11_KGEN_ATTRS){ + .type = EVP_PKEY_SLH_DSA_SHAKE_256F, + .kgen.nid = &nid_kgen, + .token_label = (const char *)token->label, + .key_label = label, + .key_id = (const unsigned char *)id, + .id_len = id_len, + .key_params = &key_params + }; + break; +#endif /* OPENSSL_NO_SLH_DSA */ +#endif /* OPENSSL_VERSION_NUMBER >= 0x30500000L */ + +#if OPENSSL_VERSION_NUMBER >= 0x30000000L + case EVP_PKEY_FALCON512: + nid_kgen.nid = NID_FALCON_512; + kgen_attrs = (PKCS11_KGEN_ATTRS){ + .type = EVP_PKEY_FALCON512, + .kgen.nid = &nid_kgen, + .token_label = (const char *)token->label, + .key_label = label, + .key_id = (const unsigned char *)id, + .id_len = id_len, + .key_params = &key_params + }; + break; + case EVP_PKEY_FALCON1024: + nid_kgen.nid = NID_FALCON_1024; + kgen_attrs = (PKCS11_KGEN_ATTRS){ + .type = EVP_PKEY_FALCON1024, + .kgen.nid = &nid_kgen, + .token_label = (const char *)token->label, + .key_label = label, + .key_id = (const unsigned char *)id, + .id_len = id_len, + .key_params = &key_params + }; + break; +#endif /* OPENSSL_VERSION_NUMBER >= 0x30000000L */ + default: rsa_kgen.bits = param; kgen_attrs = (PKCS11_KGEN_ATTRS){ @@ -569,20 +821,81 @@ int PKCS11_evp_pkey_sign(EVP_PKEY *pk, int type, const char *mdname, return pkcs11_evp_pkey_rsa_sign(key, pk, mdname, pad_mode, pss_saltlen, mgf1_mdname, sig, siglen, tbs, tbslen); + #ifndef OPENSSL_NO_EC case EVP_PKEY_EC: return pkcs11_evp_pkey_ec_sign(key, sig, siglen, tbs, tbslen); #endif /* OPENSSL_NO_EC */ + #if !defined(OPENSSL_NO_ECX) && OPENSSL_VERSION_NUMBER >= 0x30000000L case EVP_PKEY_ED25519: case EVP_PKEY_ED448: return pkcs11_evp_pkey_eddsa_sign(key, sig, siglen, tbs, tbslen); #endif /* !defined(OPENSSL_NO_ECX) && OPENSSL_VERSION_NUMBER >= 0x30000000L */ + +#if OPENSSL_VERSION_NUMBER >= 0x30500000L +#ifndef OPENSSL_NO_ML_DSA + case EVP_PKEY_ML_DSA_44: + case EVP_PKEY_ML_DSA_65: + case EVP_PKEY_ML_DSA_87: + return pkcs11_evp_pkey_mldsa_sign(key, sig, siglen, tbs, tbslen); +#endif /* OPENSSL_NO_ML_DSA */ + +#ifndef OPENSSL_NO_SLH_DSA + case EVP_PKEY_SLH_DSA_SHA2_128S: + case EVP_PKEY_SLH_DSA_SHA2_128F: + case EVP_PKEY_SLH_DSA_SHA2_192S: + case EVP_PKEY_SLH_DSA_SHA2_192F: + case EVP_PKEY_SLH_DSA_SHA2_256S: + case EVP_PKEY_SLH_DSA_SHA2_256F: + case EVP_PKEY_SLH_DSA_SHAKE_128S: + case EVP_PKEY_SLH_DSA_SHAKE_128F: + case EVP_PKEY_SLH_DSA_SHAKE_192S: + case EVP_PKEY_SLH_DSA_SHAKE_192F: + case EVP_PKEY_SLH_DSA_SHAKE_256S: + case EVP_PKEY_SLH_DSA_SHAKE_256F: + return pkcs11_evp_pkey_slhdsa_sign(key, sig, siglen, tbs, tbslen); +#endif /* OPENSSL_NO_SLH_DSA */ +#endif /* OPENSSL_VERSION_NUMBER >= 0x30500000L */ + + case EVP_PKEY_FALCON512: + case EVP_PKEY_FALCON1024: + return pkcs11_evp_pkey_falcon_sign(key, sig, siglen, tbs, tbslen); + default: return -2; /* type not supported */ } } +int PKCS11_evp_pkey_verify(EVP_PKEY *pk, int type, + const unsigned char *sig, size_t siglen, + const unsigned char *tbs, size_t tbslen) +{ + PKCS11_OBJECT_private *key; + PKCS11_KEY *pkey = pkcs11_get_pkcs11_key(pk); + int ret = -1; + + if (pkey == NULL) + return -1; + + key = pkcs11_public_object_from_key(pkey); + if (key == NULL) + return -1; + + switch (type) { + case EVP_PKEY_FALCON512: + case EVP_PKEY_FALCON1024: + ret = pkcs11_evp_pkey_falcon_verify(key, sig, siglen, tbs, tbslen); + break; + default: + ret = -2; /* type not supported */ + break; + } + + pkcs11_object_free(key); + return ret; +} + int PKCS11_evp_pkey_decrypt(EVP_PKEY *pk, int type, const char *mdname, const int pad_mode, const char *mgf1_mdname, unsigned char *oaep_label, const int oaep_labellen, @@ -609,6 +922,7 @@ int PKCS11_evp_pkey_decrypt(EVP_PKEY *pk, int type, const char *mdname, return -2; /* type not supported */ } } + #endif /* OPENSSL_VERSION_NUMBER >= 0x30000000L */ int PKCS11_private_encrypt(int flen, const unsigned char *from, unsigned char *to, diff --git a/src/p11_key.c b/src/p11_key.c index eeaaddc7..501676e9 100644 --- a/src/p11_key.c +++ b/src/p11_key.c @@ -122,6 +122,23 @@ static void pkcs11_common_pubkey_attr(PKCS11_TEMPLATE *, const char *, static void pkcs11_common_privkey_attr(PKCS11_TEMPLATE *, const char *, const unsigned char *, size_t, const PKCS11_params *); +#if OPENSSL_VERSION_NUMBER >= 0x30500000L +#ifndef OPENSSL_NO_ML_DSA +static void pkcs11_luna_pubkey_attr(PKCS11_TEMPLATE *, const char *, + const unsigned char *, size_t); +static void pkcs11_luna_privkey_attr(PKCS11_TEMPLATE *, const char *, + const unsigned char *, size_t, const PKCS11_params *); +static PKCS11_OBJECT_ops *pkcs11_mldsa_ops_from_param(CK_ULONG param_set); +#endif /* OPENSSL_NO_ML_DSA */ +#ifndef OPENSSL_NO_SLH_DSA +static PKCS11_OBJECT_ops *pkcs11_slhdsa_ops_from_param(CK_ULONG param_set); +#endif /* OPENSSL_NO_SLH_DSA */ +#endif /* OPENSSL_VERSION_NUMBER >= 0x30500000L */ + +#if OPENSSL_VERSION_NUMBER >= 0x30000000L +static PKCS11_OBJECT_ops *pkcs11_falcon_ops_from_param(CK_ULONG param_set); +#endif /* OPENSSL_VERSION_NUMBER >= 0x30000000L */ + #if OPENSSL_VERSION_NUMBER < 0x30000000L static int EVP_PKEY_is_a(const EVP_PKEY *pkey, const char *name); #endif /* OPENSSL_VERSION_NUMBER < 0x30000000L */ @@ -219,6 +236,91 @@ PKCS11_OBJECT_private *pkcs11_object_from_handle(PKCS11_SLOT_private *slot, break; #endif /* !defined(OPENSSL_NO_ECX) && OPENSSL_VERSION_NUMBER >= 0x30000000L */ +#if OPENSSL_VERSION_NUMBER >= 0x30500000L +#ifndef OPENSSL_NO_ML_DSA + case CKK_ML_DSA: { + CK_ULONG param_set; + + /* Read ML-DSA parameters to distinguish + * ML-DSA-44 vs ML-DSA-65 vs ML-DSA-87 */ + if (pkcs11_getattr_alloc(ctx, session, object, + CKA_PARAMETER_SET, &data, &size)) { + pkcs11_log(ctx, LOG_DEBUG, "Missing CKA_PARAMETER_SET attribute\n"); + return NULL; + } + if (size != sizeof(CK_ULONG)) { + pkcs11_log(ctx, LOG_DEBUG, "Invalid CKA_PARAMETER_SET size for ML-DSA\n"); + OPENSSL_free(data); + return NULL; + } + memcpy(¶m_set, data, sizeof(param_set)); + OPENSSL_free(data); + + ops = pkcs11_mldsa_ops_from_param(param_set); + if (ops == NULL) { + pkcs11_log(ctx, LOG_DEBUG, "Unsupported ML-DSA parameter set\n"); + return NULL; + } + break; + } +#endif /* OPENSSL_NO_ML_DSA */ +#ifndef OPENSSL_NO_SLH_DSA + case CKK_SLH_DSA: { + CK_ULONG param_set; + + /* Read SLH-DSA parameters to distinguish + * SHA2/SHAKE and 128/192/256 variants */ + if (pkcs11_getattr_alloc(ctx, session, object, + CKA_PARAMETER_SET, &data, &size)) { + pkcs11_log(ctx, LOG_DEBUG, "Missing CKA_PARAMETER_SET attribute\n"); + return NULL; + } + if (size != sizeof(CK_ULONG)) { + pkcs11_log(ctx, LOG_DEBUG, "Invalid CKA_PARAMETER_SET size for SLH-DSA\n"); + OPENSSL_free(data); + return NULL; + } + memcpy(¶m_set, data, sizeof(param_set)); + OPENSSL_free(data); + + ops = pkcs11_slhdsa_ops_from_param(param_set); + if (ops == NULL) { + pkcs11_log(ctx, LOG_DEBUG, "Unsupported SLH-DSA parameter set\n"); + return NULL; + } + break; + } +#endif /* OPENSSL_NO_SLH_DSA */ +#endif /* OPENSSL_VERSION_NUMBER >= 0x30500000L */ + +#if OPENSSL_VERSION_NUMBER >= 0x30000000L + case CKM_PQC_FALCON: { + CK_ULONG param_set; + + /* Read PQC FALCON parameters to distinguish + * Falcon-512 vs Falcon-1024 */ + if (pkcs11_getattr_alloc(ctx, session, object, + CKA_PARAMETER_SET, &data, &size)) { + pkcs11_log(ctx, LOG_DEBUG, "Missing CKA_PARAMETER_SET attribute\n"); + return NULL; + } + if (size != sizeof(CK_ULONG)) { + pkcs11_log(ctx, LOG_DEBUG, "Invalid CKA_PARAMETER_SET size for PQC FALCON\n"); + OPENSSL_free(data); + return NULL; + } + memcpy(¶m_set, data, sizeof(param_set)); + OPENSSL_free(data); + + ops = pkcs11_falcon_ops_from_param(param_set); + if (ops == NULL) { + pkcs11_log(ctx, LOG_DEBUG, "Unsupported PQC FALCON parameter set\n"); + return NULL; + } + break; + } +#endif /* OPENSSL_VERSION_NUMBER >= 0x30000000L */ + default: /* Ignore any keys we don't understand */ pkcs11_log(ctx, LOG_DEBUG, @@ -309,6 +411,33 @@ PKCS11_OBJECT_private *pkcs11_object_from_template(PKCS11_SLOT_private *slot, return obj; } +#if OPENSSL_VERSION_NUMBER >= 0x30000000L +/* Find the public key object matching the given PKCS11_KEY */ +PKCS11_OBJECT_private *pkcs11_public_object_from_key(PKCS11_KEY *pkey) +{ + PKCS11_OBJECT_private *key, *pubkey; + CK_SESSION_HANDLE session; + + if (pkey == NULL) + return NULL; + + key = pkey->_private; + + if (check_object_fork(key) < 0) + return NULL; + + if (key->id_len == 0) + return NULL; + + if (pkcs11_get_session(key->slot, 0, &session)) + return NULL; + + pubkey = pkcs11_object_from_object(key, session, CKO_PUBLIC_KEY); + pkcs11_put_session(key->slot, session); + return pubkey; +} +#endif /* OPENSSL_VERSION_NUMBER >= 0x30000000L */ + PKCS11_OBJECT_private *pkcs11_object_from_object(PKCS11_OBJECT_private *obj, CK_SESSION_HANDLE session, CK_OBJECT_CLASS object_class) { @@ -601,6 +730,246 @@ int pkcs11_eddsa_keygen(PKCS11_SLOT_private *slot, } #endif /* !defined(OPENSSL_NO_ECX) && OPENSSL_VERSION_NUMBER >= 0x30000000L */ +#if OPENSSL_VERSION_NUMBER >= 0x30500000L +#ifndef OPENSSL_NO_ML_DSA +/** + * Generate ML-DSA (ML-DSA-44 / ML-DSA-65 / ML-DSA-87) key pair directly on token + */ +int pkcs11_mldsa_keygen(PKCS11_SLOT_private *slot, + int nid, const char *label, const unsigned char *id, + size_t id_len, const PKCS11_params *params) +{ + PKCS11_CTX_private *ctx = slot->ctx; + CK_SESSION_HANDLE session; + PKCS11_TEMPLATE pubtmpl = {0}, privtmpl = {0}; + CK_MECHANISM mechanism = { + CKM_ML_DSA_KEY_PAIR_GEN, NULL_PTR, 0 + }; + CK_SIGN_PARAMETER_SET_TYPE signParamSet = 0; + CK_OBJECT_HANDLE pub_key_obj, priv_key_obj; + CK_RV rv; + + if (pkcs11_init_keygen(slot, &session)) + return -1; + + switch (nid) { + case NID_ML_DSA_44: + signParamSet = CKP_ML_DSA_44; + break; + case NID_ML_DSA_65: + signParamSet = CKP_ML_DSA_65; + break; + case NID_ML_DSA_87: + signParamSet = CKP_ML_DSA_87; + break; + default: + pkcs11_put_session(slot, session); + return -1; /* unsupported */ + } + + /* public key attributes */ + pkcs11_common_pubkey_attr(&pubtmpl, label, id, id_len); + pkcs11_addattr(&pubtmpl, CKA_PARAMETER_SET, + &signParamSet, sizeof(signParamSet)); + pkcs11_addattr_bool(&pubtmpl, CKA_VERIFY, TRUE); + + /* private key attributes */ + pkcs11_common_privkey_attr(&privtmpl, label, id, id_len, params); + pkcs11_addattr_bool(&privtmpl, CKA_SIGN, TRUE); + + /* generate key pair */ + rv = CRYPTOKI_call(ctx, C_GenerateKeyPair( + session, (CK_MECHANISM_PTR)&mechanism, + pubtmpl.attrs, pubtmpl.nattr, + privtmpl.attrs, privtmpl.nattr, + &pub_key_obj, &priv_key_obj)); + + if (rv != CKR_OK) { + /* Thales Luna HSM firmware does not support the wrapping + * or unwrapping of CK_ML_DSA private key objects. + * Retry with these attributes explicitly disabled. */ + pkcs11_zap_attrs(&privtmpl); + pkcs11_zap_attrs(&pubtmpl); + memset(&privtmpl, 0, sizeof(privtmpl)); + memset(&pubtmpl, 0, sizeof(pubtmpl)); + + pkcs11_luna_pubkey_attr(&pubtmpl, label, id, id_len); + pkcs11_addattr(&pubtmpl, CKA_PARAMETER_SET, + &signParamSet, sizeof(signParamSet)); + + pkcs11_luna_privkey_attr(&privtmpl, label, id, id_len, params); + pkcs11_addattr(&privtmpl, CKA_PARAMETER_SET, + &signParamSet, sizeof(signParamSet)); + + pub_key_obj = CK_INVALID_HANDLE; + priv_key_obj = CK_INVALID_HANDLE; + + rv = CRYPTOKI_call(ctx, C_GenerateKeyPair( + session, (CK_MECHANISM_PTR)&mechanism, + pubtmpl.attrs, pubtmpl.nattr, + privtmpl.attrs, privtmpl.nattr, + &pub_key_obj, &priv_key_obj)); + } + + /* cleanup */ + pkcs11_put_session(slot, session); + pkcs11_zap_attrs(&privtmpl); + pkcs11_zap_attrs(&pubtmpl); + + CRYPTOKI_checkerr(CKR_F_PKCS11_GENERATE_KEY, rv); + return 0; +} +#endif /* OPENSSL_NO_ML_DSA */ +#ifndef OPENSSL_NO_SLH_DSA +/** + * Generate SLH-DSA key pair directly on token + */ +int pkcs11_slhdsa_keygen(PKCS11_SLOT_private *slot, + int nid, const char *label, const unsigned char *id, + size_t id_len, const PKCS11_params *params) +{ + PKCS11_CTX_private *ctx = slot->ctx; + CK_SESSION_HANDLE session; + PKCS11_TEMPLATE pubtmpl = {0}, privtmpl = {0}; + CK_MECHANISM mechanism = { + CKM_SLH_DSA_KEY_PAIR_GEN, NULL_PTR, 0 + }; + CK_SIGN_PARAMETER_SET_TYPE signParamSet = 0; + CK_OBJECT_HANDLE pub_key_obj, priv_key_obj; + CK_RV rv; + + if (pkcs11_init_keygen(slot, &session)) + return -1; + + switch (nid) { + case NID_SLH_DSA_SHA2_128s: + signParamSet = CKP_SLH_DSA_SHA2_128S; + break; + case NID_SLH_DSA_SHAKE_128s: + signParamSet = CKP_SLH_DSA_SHAKE_128S; + break; + case NID_SLH_DSA_SHA2_128f: + signParamSet = CKP_SLH_DSA_SHA2_128F; + break; + case NID_SLH_DSA_SHAKE_128f: + signParamSet = CKP_SLH_DSA_SHAKE_128F; + break; + case NID_SLH_DSA_SHA2_192s: + signParamSet = CKP_SLH_DSA_SHA2_192S; + break; + case NID_SLH_DSA_SHAKE_192s: + signParamSet = CKP_SLH_DSA_SHAKE_192S; + break; + case NID_SLH_DSA_SHA2_192f: + signParamSet = CKP_SLH_DSA_SHA2_192F; + break; + case NID_SLH_DSA_SHAKE_192f: + signParamSet = CKP_SLH_DSA_SHAKE_192F; + break; + case NID_SLH_DSA_SHA2_256s: + signParamSet = CKP_SLH_DSA_SHA2_256S; + break; + case NID_SLH_DSA_SHAKE_256s: + signParamSet = CKP_SLH_DSA_SHAKE_256S; + break; + case NID_SLH_DSA_SHA2_256f: + signParamSet = CKP_SLH_DSA_SHA2_256F; + break; + case NID_SLH_DSA_SHAKE_256f: + signParamSet = CKP_SLH_DSA_SHAKE_256F; + break; + default: + pkcs11_put_session(slot, session); + return -1; /* unsupported */ + } + + /* public key attributes */ + pkcs11_common_pubkey_attr(&pubtmpl, label, id, id_len); + pkcs11_addattr(&pubtmpl, CKA_PARAMETER_SET, + &signParamSet, sizeof(signParamSet)); + pkcs11_addattr_bool(&pubtmpl, CKA_VERIFY, TRUE); + + /* private key attributes */ + pkcs11_common_privkey_attr(&privtmpl, label, id, id_len, params); + pkcs11_addattr(&privtmpl, CKA_PARAMETER_SET, + &signParamSet, sizeof(signParamSet)); + pkcs11_addattr_bool(&privtmpl, CKA_SIGN, TRUE); + + /* generate key pair */ + rv = CRYPTOKI_call(ctx, C_GenerateKeyPair( + session, (CK_MECHANISM_PTR)&mechanism, + pubtmpl.attrs, pubtmpl.nattr, + privtmpl.attrs, privtmpl.nattr, + &pub_key_obj, &priv_key_obj)); + + /* cleanup */ + pkcs11_put_session(slot, session); + pkcs11_zap_attrs(&privtmpl); + pkcs11_zap_attrs(&pubtmpl); + + CRYPTOKI_checkerr(CKR_F_PKCS11_GENERATE_KEY, rv); + return 0; +} +#endif /* OPENSSL_NO_SLH_DSA */ +#endif /* OPENSSL_VERSION_NUMBER >= 0x30500000L */ + +#if OPENSSL_VERSION_NUMBER >= 0x30000000L +/** + * Generate PQC FALCON (FALCON-512 / FALCON-1024) key pair directly on token + */ +int pkcs11_falcon_keygen(PKCS11_SLOT_private *slot, + int nid, const char *label, const unsigned char *id, + size_t id_len, const PKCS11_params *params) +{ + PKCS11_CTX_private *ctx = slot->ctx; + CK_SESSION_HANDLE session; + PKCS11_TEMPLATE pubtmpl = {0}, privtmpl = {0}; + CK_MECHANISM mechanism = { + CKM_PQC_FALCON, NULL_PTR, 0 + }; + CK_SIGN_PARAMETER_SET_TYPE signParamSet = 0; + CK_OBJECT_HANDLE pub_key_obj, priv_key_obj; + CK_RV rv; + + if (pkcs11_init_keygen(slot, &session)) + return -1; + + if (nid == NID_FALCON_512) { + signParamSet = CKP_FALCON_512; + } else if (nid == NID_FALCON_1024) { + signParamSet = CKP_FALCON_1024; + } else { + pkcs11_put_session(slot, session); + return -1; /* unsupported */ + } + + /* public key attributes */ + pkcs11_common_pubkey_attr(&pubtmpl, label, id, id_len); + pkcs11_addattr(&pubtmpl, CKA_PARAMETER_SET, + &signParamSet, sizeof(signParamSet)); + pkcs11_addattr_bool(&pubtmpl, CKA_VERIFY, TRUE); + + /* private key attributes */ + pkcs11_common_privkey_attr(&privtmpl, label, id, id_len, params); + pkcs11_addattr_bool(&privtmpl, CKA_SIGN, TRUE); + + /* generate key pair */ + rv = CRYPTOKI_call(ctx, C_GenerateKeyPair( + session, (CK_MECHANISM_PTR)&mechanism, + pubtmpl.attrs, pubtmpl.nattr, + privtmpl.attrs, privtmpl.nattr, + &pub_key_obj, &priv_key_obj)); + + /* cleanup */ + pkcs11_put_session(slot, session); + pkcs11_zap_attrs(&privtmpl); + pkcs11_zap_attrs(&pubtmpl); + + CRYPTOKI_checkerr(CKR_F_PKCS11_GENERATE_KEY, rv); + return 0; +} +#endif /* OPENSSL_VERSION_NUMBER >= 0x30000000L */ + /* * Store a private key on the token */ @@ -1134,6 +1503,99 @@ static void pkcs11_common_privkey_attr(PKCS11_TEMPLATE *privtmpl, pkcs11_addattr_bool(privtmpl, CKA_UNWRAP, TRUE); } +#if OPENSSL_VERSION_NUMBER >= 0x30500000L +#ifndef OPENSSL_NO_ML_DSA + +static void pkcs11_luna_pubkey_attr(PKCS11_TEMPLATE *pubtmpl, + const char *label, const unsigned char *id, size_t id_len) +{ + /* Thales Luna HSM pubkey attributes */ + pkcs11_addattr(pubtmpl, CKA_ID, (void *)id, id_len); + if (label) + pkcs11_addattr_s(pubtmpl, CKA_LABEL, label); + pkcs11_addattr_bool(pubtmpl, CKA_TOKEN, TRUE); + pkcs11_addattr_bool(pubtmpl, CKA_VERIFY, TRUE); +} + +static void pkcs11_luna_privkey_attr(PKCS11_TEMPLATE *privtmpl, + const char *label, const unsigned char *id, size_t id_len, + const PKCS11_params *params) +{ + /* Thales Luna HSM privkey attributes */ + pkcs11_addattr(privtmpl, CKA_ID, (void *)id, id_len); + if (label) + pkcs11_addattr_s(privtmpl, CKA_LABEL, label); + pkcs11_addattr_bool(privtmpl, CKA_PRIVATE, TRUE); + pkcs11_addattr_bool(privtmpl, CKA_TOKEN, TRUE); + pkcs11_addattr_bool(privtmpl, CKA_SENSITIVE, params->sensitive); + pkcs11_addattr_bool(privtmpl, CKA_EXTRACTABLE, params->extractable); + pkcs11_addattr_bool(privtmpl, CKA_SIGN, TRUE); +} + +static PKCS11_OBJECT_ops *pkcs11_mldsa_ops_from_param(CK_ULONG param_set) +{ + switch (param_set) { + case CKP_ML_DSA_44: + return &pkcs11_mldsa44_ops; + case CKP_ML_DSA_65: + return &pkcs11_mldsa65_ops; + case CKP_ML_DSA_87: + return &pkcs11_mldsa87_ops; + default: + return NULL; + } +} +#endif /* OPENSSL_NO_ML_DSA */ + +#ifndef OPENSSL_NO_SLH_DSA +static PKCS11_OBJECT_ops *pkcs11_slhdsa_ops_from_param(CK_ULONG param_set) +{ + switch (param_set) { + case CKP_SLH_DSA_SHA2_128S: + return &pkcs11_slhdsa_sha2_128s_ops; + case CKP_SLH_DSA_SHAKE_128S: + return &pkcs11_slhdsa_shake_128s_ops; + case CKP_SLH_DSA_SHA2_128F: + return &pkcs11_slhdsa_sha2_128f_ops; + case CKP_SLH_DSA_SHAKE_128F: + return &pkcs11_slhdsa_shake_128f_ops; + case CKP_SLH_DSA_SHA2_192S: + return &pkcs11_slhdsa_sha2_192s_ops; + case CKP_SLH_DSA_SHAKE_192S: + return &pkcs11_slhdsa_shake_192s_ops; + case CKP_SLH_DSA_SHA2_192F: + return &pkcs11_slhdsa_sha2_192f_ops; + case CKP_SLH_DSA_SHAKE_192F: + return &pkcs11_slhdsa_shake_192f_ops; + case CKP_SLH_DSA_SHA2_256S: + return &pkcs11_slhdsa_sha2_256s_ops; + case CKP_SLH_DSA_SHAKE_256S: + return &pkcs11_slhdsa_shake_256s_ops; + case CKP_SLH_DSA_SHA2_256F: + return &pkcs11_slhdsa_sha2_256f_ops; + case CKP_SLH_DSA_SHAKE_256F: + return &pkcs11_slhdsa_shake_256f_ops; + default: + return NULL; + } +} +#endif /* OPENSSL_NO_SLH_DSA */ +#endif /* OPENSSL_VERSION_NUMBER >= 0x30500000L */ + +#if OPENSSL_VERSION_NUMBER >= 0x30000000L +static PKCS11_OBJECT_ops *pkcs11_falcon_ops_from_param(CK_ULONG param_set) +{ + switch (param_set) { + case CKP_FALCON_512: + return &pkcs11_falcon512_ops; + case CKP_FALCON_1024: + return &pkcs11_falcon1024_ops; + default: + return NULL; + } +} +#endif /* OPENSSL_VERSION_NUMBER >= 0x30000000L */ + #if OPENSSL_VERSION_NUMBER < 0x30000000L static int EVP_PKEY_is_a(const EVP_PKEY *pkey, const char *name) diff --git a/src/p11_load.c b/src/p11_load.c index e2bf279d..80b09514 100644 --- a/src/p11_load.c +++ b/src/p11_load.c @@ -23,6 +23,11 @@ /* Global number of active PKCS11_CTX objects */ static int pkcs11_global_data_refs = 0; +#if OPENSSL_VERSION_NUMBER >= 0x30000000L +int NID_FALCON_512 = NID_undef; +int NID_FALCON_1024 = NID_undef; +#endif /* OPENSSL_VERSION_NUMBER >= 0x30000000L */ + /* * Free global ex_data indexes and custom key methods */ @@ -127,6 +132,38 @@ static int pkcs11_initialize(PKCS11_CTX_private *cpriv) return 0; } +#if OPENSSL_VERSION_NUMBER >= 0x30000000L +static int register_falcon_oid(const char *oid, const char *sn, const char *ln) +{ + int nid; + + nid = OBJ_txt2nid(oid); + if (nid != NID_undef) + return nid; + + return OBJ_create(oid, sn, ln); +} + +static int register_falcon_oids(void) +{ + static int initialized = 0; + + if (initialized) + return 1; + + NID_FALCON_512 = register_falcon_oid( + "1.3.9999.3.11", "FALCON512", "Falcon-512"); + NID_FALCON_1024 = register_falcon_oid( + "1.3.9999.3.14", "FALCON1024", "Falcon-1024"); + + if (NID_FALCON_512 == NID_undef || NID_FALCON_1024 == NID_undef) + return 0; + + initialized = 1; + return 1; +} +#endif /* OPENSSL_VERSION_NUMBER >= 0x30000000L */ + /* * Load the shared library, and initialize it. */ @@ -159,7 +196,9 @@ int pkcs11_CTX_load(PKCS11_CTX *ctx, const char *name) ctx->description = PKCS11_DUP(ck_info.libraryDescription); cpriv->cryptoki_version.major = ck_info.cryptokiVersion.major; cpriv->cryptoki_version.minor = ck_info.cryptokiVersion.minor; - +#if OPENSSL_VERSION_NUMBER >= 0x30000000L + register_falcon_oids(); +#endif /* OPENSSL_VERSION_NUMBER >= 0x30000000L */ return 0; } diff --git a/src/p11_mldsa.c b/src/p11_mldsa.c new file mode 100644 index 00000000..d9db2068 --- /dev/null +++ b/src/p11_mldsa.c @@ -0,0 +1,312 @@ +/* + * Copyright © 2026 Mobi - Com Polska Sp. z o.o. + * Author: Małgorzata Olszówka + * All rights reserved. + * + * This file implements the handling of ML-DSA keys stored on a PKCS11 token. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include "libp11-int.h" +#include + +#if !defined(OPENSSL_NO_ML_DSA) && OPENSSL_VERSION_NUMBER >= 0x30500000L + +#define ML_DSA_44_PUB_LEN 1312 +#define ML_DSA_65_PUB_LEN 1952 +#define ML_DSA_87_PUB_LEN 2592 + +/* + * Extract raw ML-DSA public key bytes from a CKO_PUBLIC_KEY object using CKA_VALUE. + * Returns 1 on success, 0 on failure. + */ +static int extract_pub_from_public_key_obj(PKCS11_CTX_private *ctx, + CK_SESSION_HANDLE session, CK_OBJECT_HANDLE obj, + size_t expected_len, unsigned char **raw, size_t *rawlen) +{ + unsigned char *value = NULL; + size_t value_len = 0; + + if (ctx == NULL || raw == NULL || rawlen == NULL || + obj == CK_INVALID_HANDLE || expected_len == 0) + return 0; + + *raw = NULL; + *rawlen = 0; + + if (pkcs11_getattr_alloc(ctx, session, obj, CKA_VALUE, &value, &value_len)) { + pkcs11_log(ctx, LOG_DEBUG, + "Missing CKA_VALUE attribute on ML-DSA public key\n"); + return 0; + } + + if (value_len != expected_len) { + pkcs11_log(ctx, LOG_DEBUG, + "Unexpected ML-DSA public key size: got %lu, expected %lu\n", + (unsigned long)value_len, (unsigned long)expected_len); + OPENSSL_free(value); + return 0; + } + + *raw = value; + *rawlen = value_len; + return 1; +} + +/* + * Extract raw ML-DSA public key bytes from a CKO_CERTIFICATE object. + * The certificate is read from CKA_VALUE (DER-encoded X.509) and + * the public key is obtained via X.509 parsing. + * Returns 1 on success, 0 on failure. + */ +static int extract_pub_from_cert_obj(PKCS11_CTX_private *ctx, + CK_SESSION_HANDLE session, CK_OBJECT_HANDLE obj, + size_t expected_len, const char *algname, + unsigned char **raw, size_t *rawlen) +{ + const unsigned char *p; + unsigned char *der = NULL; + unsigned char *buf = NULL; + size_t derlen = 0; + size_t len = 0; + X509 *cert = NULL; + EVP_PKEY *pkey = NULL; + int ok = 0; + + if (ctx == NULL || raw == NULL || rawlen == NULL || + obj == CK_INVALID_HANDLE || expected_len == 0 || algname == NULL) + return 0; + + *raw = NULL; + *rawlen = 0; + + if (pkcs11_getattr_alloc(ctx, session, obj, CKA_VALUE, &der, &derlen)) + return 0; + + if (derlen == 0 || derlen > LONG_MAX) + goto end; + + p = der; + cert = d2i_X509(NULL, &p, (long)derlen); + if (cert == NULL || p != der + derlen) + goto end; + + pkey = X509_get_pubkey(cert); + if (pkey == NULL) + goto end; + + if (!EVP_PKEY_is_a(pkey, algname)) + goto end; + + if (EVP_PKEY_get_raw_public_key(pkey, NULL, &len) != 1) + goto end; + + if (len != expected_len) + goto end; + + buf = OPENSSL_malloc(len); + if (buf == NULL) + goto end; + + if (EVP_PKEY_get_raw_public_key(pkey, buf, &len) != 1) + goto end; + + if (len != expected_len) + goto end; + + *raw = buf; + *rawlen = len; + buf = NULL; + ok = 1; + +end: + OPENSSL_free(buf); + OPENSSL_free(der); + EVP_PKEY_free(pkey); + X509_free(cert); + return ok; +} + +/* + * Select an object that can provide public key material. + * + * For a private key object, try to locate a matching CKO_PUBLIC_KEY + * (same CKA_ID). If not found, fall back to CKO_CERTIFICATE. + * + * On success, returns a PKCS11_OBJECT_private pointer. + * If a new object is returned, *needs_free is set to 1 and the caller + * must free it with pkcs11_object_free(). + * + * Returns NULL on failure. + */ +static PKCS11_OBJECT_private *pkcs11_choose_public_source(PKCS11_OBJECT_private *key, + CK_SESSION_HANDLE session, int *needs_free) +{ + PKCS11_OBJECT_private *obj; + + *needs_free = 0; + + if (key->object_class != CKO_PRIVATE_KEY) + return key; + + obj = pkcs11_object_from_object(key, session, CKO_PUBLIC_KEY); + if (obj != NULL && obj->object != CK_INVALID_HANDLE) { + *needs_free = 1; + return obj; + } + if (obj != NULL) + pkcs11_object_free(obj); + + obj = pkcs11_object_from_object(key, session, CKO_CERTIFICATE); + if (obj != NULL && obj->object != CK_INVALID_HANDLE) { + *needs_free = 1; + return obj; + } + if (obj != NULL) + pkcs11_object_free(obj); + + return NULL; +} + +/* + * Retrieve raw ML-DSA public key bytes. + * + * Preference order: + * 1. CKO_PUBLIC_KEY -> CKA_VALUE + * 2. CKO_CERTIFICATE -> CKA_VALUE (DER) + X.509 parsing + * + * The returned buffer is allocated with OPENSSL_malloc() + * and must be freed by the caller. + * + * Returns 0 on success, -1 on failure. + */ +static int pkcs11_get_raw_public_key(PKCS11_OBJECT_private *key, + size_t expected_len, const char *algname, + unsigned char **raw, size_t *rawlen) +{ + PKCS11_SLOT_private *slot; + PKCS11_CTX_private *ctx; + CK_SESSION_HANDLE session = CK_INVALID_HANDLE; + PKCS11_OBJECT_private *obj = NULL; + int obj_needs_free = 0, ok = 0; + + if (key == NULL || key->slot == NULL || raw == NULL || rawlen == NULL) + return -1; + + *raw = NULL; + *rawlen = 0; + slot = key->slot; + ctx = slot->ctx; + + if (pkcs11_get_session(slot, 0, &session)) + return -1; + + obj = pkcs11_choose_public_source(key, session, &obj_needs_free); + if (obj == NULL || obj->object == CK_INVALID_HANDLE) + goto end; + + switch (obj->object_class) { + case CKO_PUBLIC_KEY: + ok = extract_pub_from_public_key_obj(ctx, session, obj->object, + expected_len, raw, rawlen); + break; + case CKO_CERTIFICATE: + ok = extract_pub_from_cert_obj(ctx, session, obj->object, + expected_len, algname, raw, rawlen); + break; + default: + ok = 0; + break; + } + +end: + if (!ok) { + OPENSSL_free(*raw); + *raw = NULL; + *rawlen = 0; + } + if (obj_needs_free && obj != NULL) + pkcs11_object_free(obj); + + return ok ? 0 : -1; +} + +static EVP_PKEY *pkcs11_get_evp_key_mldsa(PKCS11_OBJECT_private *key, + size_t publen, const char *algname) +{ + EVP_PKEY *pkey = NULL; + unsigned char *raw = NULL; + size_t rawlen = 0; + + /* Retrieve the public key in raw format from PKCS#11 */ + if (pkcs11_get_raw_public_key(key, publen, algname, &raw, &rawlen) < 0) + return NULL; + + /* Public key from CKA_VALUE, used only as software public key */ + pkey = EVP_PKEY_new_raw_public_key_ex(NULL, algname, "provider=default", raw, rawlen); + OPENSSL_free(raw); + return pkey; +} + +static EVP_PKEY *pkcs11_get_evp_key_mldsa44(PKCS11_OBJECT_private *key) +{ + return pkcs11_get_evp_key_mldsa(key, ML_DSA_44_PUB_LEN, "ML-DSA-44"); +} + +static EVP_PKEY *pkcs11_get_evp_key_mldsa65(PKCS11_OBJECT_private *key) +{ + return pkcs11_get_evp_key_mldsa(key, ML_DSA_65_PUB_LEN, "ML-DSA-65"); +} + +static EVP_PKEY *pkcs11_get_evp_key_mldsa87(PKCS11_OBJECT_private *key) +{ + return pkcs11_get_evp_key_mldsa(key, ML_DSA_87_PUB_LEN, "ML-DSA-87"); +} + + +PKCS11_OBJECT_ops pkcs11_mldsa44_ops = { + EVP_PKEY_ML_DSA_44, + pkcs11_get_evp_key_mldsa44, +}; + +PKCS11_OBJECT_ops pkcs11_mldsa65_ops = { + EVP_PKEY_ML_DSA_65, + pkcs11_get_evp_key_mldsa65, +}; + +PKCS11_OBJECT_ops pkcs11_mldsa87_ops = { + EVP_PKEY_ML_DSA_87, + pkcs11_get_evp_key_mldsa87, +}; + +#else /* !defined(OPENSSL_NO_ML_DSA) && OPENSSL_VERSION_NUMBER >= 0x30500000L */ +/* + * ML-DSA support is not available: + * - either OpenSSL was built without ML-DSA support, or + * - OpenSSL version is older than 3.5. + */ +#warning "ML-DSA support not built with libp11" + +#endif /* !defined(OPENSSL_NO_ML_DSA) && OPENSSL_VERSION_NUMBER >= 0x30500000L */ + +/* vim: set noexpandtab: */ diff --git a/src/p11_pkey.c b/src/p11_pkey.c index bacb306c..11f7f182 100644 --- a/src/p11_pkey.c +++ b/src/p11_pkey.c @@ -216,7 +216,10 @@ static int pkcs11_oaep_param(CK_RSA_PKCS_OAEP_PARAMS *oaep_params, if (mgf1_md == NULL) return -1; - pkcs11_log(pctx, LOG_DEBUG, "oaep_md=%s mdf1_md=%s oaep_labellen=%d\n", + if (oaep_labellen > (size_t)((CK_ULONG)-1)) + return -1; + + pkcs11_log(pctx, LOG_DEBUG, "oaep_md=%s mgf1_md=%s oaep_labellen=%lu\n", EVP_MD_name(oaep_md), EVP_MD_name(mgf1_md), oaep_labellen); /* fill the CK_RSA_PKCS_OAEP_PARAMS structure */ @@ -325,10 +328,14 @@ const char *pkcs11_mechanism_name(CK_MECHANISM *mechanism) return "CKM_RSA_X9_31"; case CKM_ECDSA: return "CKM_ECDSA"; -#ifdef CKM_EDDSA case CKM_EDDSA: return "CKM_EDDSA"; -#endif + case CKM_ML_DSA: + return "CKM_ML_DSA"; + case CKM_SLH_DSA: + return "CKM_SLH_DSA"; + case CKM_PQC_FALCON: + return "CKM_PQC_FALCON"; default: return "UNKNOWN_MECHANISM"; } @@ -416,6 +423,72 @@ static int pkcs11_sign_with_mechanism(PKCS11_OBJECT_private *key, return rv; } +#if OPENSSL_VERSION_NUMBER >= 0x30000000L +/* + * Execute a PKCS#11 verify operation using the specified mechanism. + * + * Returns: CKR_OK on success or PKCS#11 error code on failure + */ +static int pkcs11_verify_with_mechanism(PKCS11_OBJECT_private *key, + CK_MECHANISM *mechanism, + const unsigned char *sig, size_t siglen, + const unsigned char *tbs, size_t tbslen) +{ + int rv = CKR_GENERAL_ERROR; + PKCS11_SLOT_private *slot; + PKCS11_CTX_private *ctx; + CK_SESSION_HANDLE session; + CK_ULONG ck_siglen; + CK_ULONG ck_tbslen; + + if (key == NULL || mechanism == NULL || sig == NULL || tbs == NULL) + return CKR_ARGUMENTS_BAD; + + slot = key->slot; + if (slot == NULL) + return CKR_GENERAL_ERROR; + + ctx = slot->ctx; + if (ctx == NULL) + return CKR_GENERAL_ERROR; + +#ifdef DEBUG + pkcs11_log(ctx, LOG_DEBUG, "%s:%d pkcs11_verify_with_mechanism() " + "%s sig=%p siglen=%lu tbs=%p tbslen=%lu\n", + __FILE__, __LINE__, + pkcs11_mechanism_name(mechanism), sig, siglen, tbs, tbslen); +#endif + + ck_siglen = (CK_ULONG)siglen; + ck_tbslen = (CK_ULONG)tbslen; + + if (pkcs11_get_session(slot, 0, &session)) + return CKR_GENERAL_ERROR; + + rv = CRYPTOKI_call(ctx, + C_VerifyInit(session, mechanism, key->object)); + if (rv != CKR_OK) { + pkcs11_log(ctx, LOG_DEBUG, "%s:%d C_VerifyInit rv=%d\n", + __FILE__, __LINE__, rv); + goto end; + } + + rv = CRYPTOKI_call(ctx, + C_Verify(session, + (CK_BYTE_PTR)tbs, ck_tbslen, + (CK_BYTE_PTR)sig, ck_siglen)); + if (rv != CKR_OK) { + pkcs11_log(ctx, LOG_DEBUG, "%s:%d C_Verify rv=%d\n", + __FILE__, __LINE__, rv); + goto end; + } + +end: + pkcs11_put_session(slot, session); + return rv; +} +#endif /* OPENSSL_VERSION_NUMBER >= 0x30000000L */ + /* * Execute a PKCS#11 decryption operation using the specified mechanism. * Returns: CKR_OK on success or PKCS#11 error code on failure. @@ -778,6 +851,109 @@ int pkcs11_evp_pkey_eddsa_sign(PKCS11_OBJECT_private *key, } #endif /* OPENSSL_NO_ECX */ +#if OPENSSL_VERSION_NUMBER >= 0x30500000L +#ifndef OPENSSL_NO_ML_DSA +/* + * Sign message input with ML-DSA private key via PKCS#11 mechanism. + * Returns 1 on success or -1 on failure. + */ +int pkcs11_evp_pkey_mldsa_sign(PKCS11_OBJECT_private *key, + unsigned char *sig, size_t *siglen, + const unsigned char *tbs, size_t tbslen) +{ + CK_MECHANISM mechanism; + + if (key == NULL || sig == NULL || siglen == NULL || tbs == NULL) + return -1; + + memset(&mechanism, 0, sizeof(mechanism)); + mechanism.mechanism = CKM_ML_DSA; + + if (pkcs11_sign_with_mechanism(key, &mechanism, sig, siglen, + tbs, tbslen) != CKR_OK) + return -1; + + return 1; +} +#endif /* OPENSSL_NO_ML_DSA */ + +#ifndef OPENSSL_NO_SLH_DSA +/* + * Sign message input with SLH-DSA private key via PKCS#11 mechanism. + * Returns 1 on success or -1 on failure. + */ +int pkcs11_evp_pkey_slhdsa_sign(PKCS11_OBJECT_private *key, + unsigned char *sig, size_t *siglen, + const unsigned char *tbs, size_t tbslen) +{ + CK_MECHANISM mechanism; + + if (key == NULL || sig == NULL || siglen == NULL || tbs == NULL) + return -1; + + memset(&mechanism, 0, sizeof(mechanism)); + mechanism.mechanism = CKM_SLH_DSA; + + if (pkcs11_sign_with_mechanism(key, &mechanism, sig, siglen, + tbs, tbslen) != CKR_OK) + return -1; + + return 1; +} +#endif /* OPENSSL_NO_SLH_DSA */ +#endif /* OPENSSL_VERSION_NUMBER >= 0x30500000L */ + +#if OPENSSL_VERSION_NUMBER >= 0x30000000L +/* + * Sign message input with PQC FALCON private key via PKCS#11 mechanism. + * Returns 1 on success or -1 on failure. + */ +int pkcs11_evp_pkey_falcon_sign(PKCS11_OBJECT_private *key, + unsigned char *sig, size_t *siglen, + const unsigned char *tbs, size_t tbslen) +{ + CK_MECHANISM mechanism; + + if (key == NULL || sig == NULL || siglen == NULL || tbs == NULL) + return -1; + + memset(&mechanism, 0, sizeof(mechanism)); + mechanism.mechanism = CKM_PQC_FALCON; + + if (pkcs11_sign_with_mechanism(key, &mechanism, sig, siglen, + tbs, tbslen) != CKR_OK) + return -1; + + return 1; +} + +/* + * Verify message input with PQC FALCON public key via PKCS#11 mechanism. + * Returns 1 on success or -1 on failure. + */ +int pkcs11_evp_pkey_falcon_verify(PKCS11_OBJECT_private *key, + const unsigned char *sig, size_t siglen, + const unsigned char *tbs, size_t tbslen) +{ + CK_MECHANISM mechanism; + + if (key == NULL || sig == NULL || tbs == NULL) + return -1; + + if (siglen == 0 || tbslen == 0) + return -1; + + memset(&mechanism, 0, sizeof(mechanism)); + mechanism.mechanism = CKM_PQC_FALCON; + + if (pkcs11_verify_with_mechanism(key, &mechanism, sig, siglen, + tbs, tbslen) != CKR_OK) + return -1; + + return 1; +} +#endif /* OPENSSL_VERSION_NUMBER >= 0x30000000L */ + /* * Decrypt RSA input via PKCS#11 using configured padding and OAEP parameters. * EME-OAEP as defined in PKCS #1 v2.0 with SHA-1, MGF1 and an encoding parameter diff --git a/src/p11_slhdsa.c b/src/p11_slhdsa.c new file mode 100644 index 00000000..dea98c9b --- /dev/null +++ b/src/p11_slhdsa.c @@ -0,0 +1,415 @@ +/* + * Copyright © 2026 Mobi - Com Polska Sp. z o.o. + * Author: Małgorzata Olszówka + * All rights reserved. + * + * This file implements the handling of SLH-DSA keys stored on a PKCS11 token. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include "libp11-int.h" +#include + +#if !defined(OPENSSL_NO_SLH_DSA) && OPENSSL_VERSION_NUMBER >= 0x30500000L + +#define SLH_DSA_128_PUB_BYTES 32 +#define SLH_DSA_192_PUB_BYTES 48 +#define SLH_DSA_256_PUB_BYTES 64 + +/* + * Extract raw SLH-DSA public key bytes from a CKO_PUBLIC_KEY object using CKA_VALUE. + * Returns 1 on success, 0 on failure. + */ +static int extract_pub_from_public_key_obj(PKCS11_CTX_private *ctx, + CK_SESSION_HANDLE session, CK_OBJECT_HANDLE obj, + size_t expected_len, unsigned char **raw, size_t *rawlen) +{ + unsigned char *value = NULL; + size_t value_len = 0; + + if (ctx == NULL || raw == NULL || rawlen == NULL || + obj == CK_INVALID_HANDLE || expected_len == 0) + return 0; + + *raw = NULL; + *rawlen = 0; + + if (pkcs11_getattr_alloc(ctx, session, obj, CKA_VALUE, &value, &value_len)) { + pkcs11_log(ctx, LOG_DEBUG, + "Missing CKA_VALUE attribute on SLH-DSA public key\n"); + return 0; + } + + if (value_len != expected_len) { + pkcs11_log(ctx, LOG_DEBUG, + "Unexpected SLH-DSA public key size: got %lu, expected %lu\n", + (unsigned long)value_len, (unsigned long)expected_len); + OPENSSL_free(value); + return 0; + } + + *raw = value; + *rawlen = value_len; + return 1; +} + +/* + * Extract raw SLH-DSA public key bytes from a CKO_CERTIFICATE object. + * The certificate is read from CKA_VALUE (DER-encoded X.509) and + * the public key is obtained via X.509 parsing. + * Returns 1 on success, 0 on failure. + */ +static int extract_pub_from_cert_obj(PKCS11_CTX_private *ctx, + CK_SESSION_HANDLE session, CK_OBJECT_HANDLE obj, + size_t expected_len, const char *algname, + unsigned char **raw, size_t *rawlen) +{ + const unsigned char *p; + unsigned char *der = NULL; + unsigned char *buf = NULL; + size_t derlen = 0; + size_t len = 0; + X509 *cert = NULL; + EVP_PKEY *pkey = NULL; + int ok = 0; + + if (ctx == NULL || raw == NULL || rawlen == NULL || + obj == CK_INVALID_HANDLE || expected_len == 0 || algname == NULL) + return 0; + + *raw = NULL; + *rawlen = 0; + + if (pkcs11_getattr_alloc(ctx, session, obj, CKA_VALUE, &der, &derlen)) + return 0; + + if (derlen == 0 || derlen > LONG_MAX) + goto end; + + p = der; + cert = d2i_X509(NULL, &p, (long)derlen); + if (cert == NULL || p != der + derlen) + goto end; + + pkey = X509_get_pubkey(cert); + if (pkey == NULL) + goto end; + + if (!EVP_PKEY_is_a(pkey, algname)) + goto end; + + if (EVP_PKEY_get_raw_public_key(pkey, NULL, &len) != 1) + goto end; + + if (len != expected_len) + goto end; + + buf = OPENSSL_malloc(len); + if (buf == NULL) + goto end; + + if (EVP_PKEY_get_raw_public_key(pkey, buf, &len) != 1) + goto end; + + if (len != expected_len) + goto end; + + *raw = buf; + *rawlen = len; + buf = NULL; + ok = 1; + +end: + OPENSSL_free(buf); + OPENSSL_free(der); + EVP_PKEY_free(pkey); + X509_free(cert); + return ok; +} + +/* + * Select an object that can provide public key material. + * + * For a private key object, try to locate a matching CKO_PUBLIC_KEY + * (same CKA_ID). If not found, fall back to CKO_CERTIFICATE. + * + * On success, returns a PKCS11_OBJECT_private pointer. + * If a new object is returned, *needs_free is set to 1 and the caller + * must free it with pkcs11_object_free(). + * + * Returns NULL on failure. + */ +static PKCS11_OBJECT_private *pkcs11_choose_public_source(PKCS11_OBJECT_private *key, + CK_SESSION_HANDLE session, int *needs_free) +{ + PKCS11_OBJECT_private *obj; + + *needs_free = 0; + + if (key->object_class != CKO_PRIVATE_KEY) + return key; + + obj = pkcs11_object_from_object(key, session, CKO_PUBLIC_KEY); + if (obj != NULL && obj->object != CK_INVALID_HANDLE) { + *needs_free = 1; + return obj; + } + if (obj != NULL) + pkcs11_object_free(obj); + + obj = pkcs11_object_from_object(key, session, CKO_CERTIFICATE); + if (obj != NULL && obj->object != CK_INVALID_HANDLE) { + *needs_free = 1; + return obj; + } + if (obj != NULL) + pkcs11_object_free(obj); + + return NULL; +} + +/* + * Retrieve raw SLH-DSA public key bytes. + * + * Preference order: + * 1. CKO_PUBLIC_KEY -> CKA_VALUE + * 2. CKO_CERTIFICATE -> CKA_VALUE (DER) + X.509 parsing + * + * The returned buffer is allocated with OPENSSL_malloc() + * and must be freed by the caller. + * + * Returns 0 on success, -1 on failure. + */ +static int pkcs11_get_raw_public_key(PKCS11_OBJECT_private *key, + size_t expected_len, const char *algname, + unsigned char **raw, size_t *rawlen) +{ + PKCS11_SLOT_private *slot; + PKCS11_CTX_private *ctx; + CK_SESSION_HANDLE session = CK_INVALID_HANDLE; + PKCS11_OBJECT_private *obj = NULL; + int obj_needs_free = 0, ok = 0; + + if (key == NULL || key->slot == NULL || raw == NULL || rawlen == NULL) + return -1; + + *raw = NULL; + *rawlen = 0; + slot = key->slot; + ctx = slot->ctx; + + if (pkcs11_get_session(slot, 0, &session)) + return -1; + + obj = pkcs11_choose_public_source(key, session, &obj_needs_free); + if (obj == NULL || obj->object == CK_INVALID_HANDLE) + goto end; + + switch (obj->object_class) { + case CKO_PUBLIC_KEY: + ok = extract_pub_from_public_key_obj(ctx, session, obj->object, + expected_len, raw, rawlen); + break; + case CKO_CERTIFICATE: + ok = extract_pub_from_cert_obj(ctx, session, obj->object, + expected_len, algname, raw, rawlen); + break; + default: + ok = 0; + break; + } + +end: + if (!ok) { + OPENSSL_free(*raw); + *raw = NULL; + *rawlen = 0; + } + if (obj_needs_free && obj != NULL) + pkcs11_object_free(obj); + + return ok ? 0 : -1; +} + +static EVP_PKEY *pkcs11_get_evp_key_slhdsa(PKCS11_OBJECT_private *key, + size_t publen, const char *algname) +{ + EVP_PKEY *pkey = NULL; + unsigned char *raw = NULL; + size_t rawlen = 0; + + /* Retrieve the public key in raw format from PKCS#11 */ + if (pkcs11_get_raw_public_key(key, publen, algname, &raw, &rawlen) < 0) + return NULL; + + /* Public key from CKA_VALUE, used only as software public key */ + pkey = EVP_PKEY_new_raw_public_key_ex(NULL, algname, "provider=default", raw, rawlen); + OPENSSL_free(raw); + return pkey; +} + +static EVP_PKEY *pkcs11_get_evp_key_slhdsa_sha2_128s(PKCS11_OBJECT_private *key) +{ + return pkcs11_get_evp_key_slhdsa(key, SLH_DSA_128_PUB_BYTES, + "SLH-DSA-SHA2-128s"); +} + +static EVP_PKEY *pkcs11_get_evp_key_slhdsa_sha2_128f(PKCS11_OBJECT_private *key) +{ + return pkcs11_get_evp_key_slhdsa(key, SLH_DSA_128_PUB_BYTES, + "SLH-DSA-SHA2-128f"); +} + +static EVP_PKEY *pkcs11_get_evp_key_slhdsa_sha2_192s(PKCS11_OBJECT_private *key) +{ + return pkcs11_get_evp_key_slhdsa(key, SLH_DSA_192_PUB_BYTES, + "SLH-DSA-SHA2-192s"); +} + +static EVP_PKEY *pkcs11_get_evp_key_slhdsa_sha2_192f(PKCS11_OBJECT_private *key) +{ + return pkcs11_get_evp_key_slhdsa(key, SLH_DSA_192_PUB_BYTES, + "SLH-DSA-SHA2-192f"); +} + +static EVP_PKEY *pkcs11_get_evp_key_slhdsa_sha2_256s(PKCS11_OBJECT_private *key) +{ + return pkcs11_get_evp_key_slhdsa(key, SLH_DSA_256_PUB_BYTES, + "SLH-DSA-SHA2-256s"); +} + +static EVP_PKEY *pkcs11_get_evp_key_slhdsa_sha2_256f(PKCS11_OBJECT_private *key) +{ + return pkcs11_get_evp_key_slhdsa(key, SLH_DSA_256_PUB_BYTES, + "SLH-DSA-SHA2-256f"); +} + +static EVP_PKEY *pkcs11_get_evp_key_slhdsa_shake_128s(PKCS11_OBJECT_private *key) +{ + return pkcs11_get_evp_key_slhdsa(key, SLH_DSA_128_PUB_BYTES, + "SLH-DSA-SHAKE-128s"); +} + +static EVP_PKEY *pkcs11_get_evp_key_slhdsa_shake_128f(PKCS11_OBJECT_private *key) +{ + return pkcs11_get_evp_key_slhdsa(key, SLH_DSA_128_PUB_BYTES, + "SLH-DSA-SHAKE-128f"); +} + +static EVP_PKEY *pkcs11_get_evp_key_slhdsa_shake_192s(PKCS11_OBJECT_private *key) +{ + return pkcs11_get_evp_key_slhdsa(key, SLH_DSA_192_PUB_BYTES, + "SLH-DSA-SHAKE-192s"); +} + +static EVP_PKEY *pkcs11_get_evp_key_slhdsa_shake_192f(PKCS11_OBJECT_private *key) +{ + return pkcs11_get_evp_key_slhdsa(key, SLH_DSA_192_PUB_BYTES, + "SLH-DSA-SHAKE-192f"); +} + +static EVP_PKEY *pkcs11_get_evp_key_slhdsa_shake_256s(PKCS11_OBJECT_private *key) +{ + return pkcs11_get_evp_key_slhdsa(key, SLH_DSA_256_PUB_BYTES, + "SLH-DSA-SHAKE-256s"); +} + +static EVP_PKEY *pkcs11_get_evp_key_slhdsa_shake_256f(PKCS11_OBJECT_private *key) +{ + return pkcs11_get_evp_key_slhdsa(key, SLH_DSA_256_PUB_BYTES, + "SLH-DSA-SHAKE-256f"); +} + + +PKCS11_OBJECT_ops pkcs11_slhdsa_sha2_128s_ops = { + EVP_PKEY_SLH_DSA_SHA2_128S, + pkcs11_get_evp_key_slhdsa_sha2_128s, +}; + +PKCS11_OBJECT_ops pkcs11_slhdsa_sha2_128f_ops = { + EVP_PKEY_SLH_DSA_SHA2_128F, + pkcs11_get_evp_key_slhdsa_sha2_128f, +}; + +PKCS11_OBJECT_ops pkcs11_slhdsa_sha2_192s_ops = { + EVP_PKEY_SLH_DSA_SHA2_192S, + pkcs11_get_evp_key_slhdsa_sha2_192s, +}; + +PKCS11_OBJECT_ops pkcs11_slhdsa_sha2_192f_ops = { + EVP_PKEY_SLH_DSA_SHA2_192F, + pkcs11_get_evp_key_slhdsa_sha2_192f, +}; + +PKCS11_OBJECT_ops pkcs11_slhdsa_sha2_256s_ops = { + EVP_PKEY_SLH_DSA_SHA2_256S, + pkcs11_get_evp_key_slhdsa_sha2_256s, +}; + +PKCS11_OBJECT_ops pkcs11_slhdsa_sha2_256f_ops = { + EVP_PKEY_SLH_DSA_SHA2_256F, + pkcs11_get_evp_key_slhdsa_sha2_256f, +}; + +PKCS11_OBJECT_ops pkcs11_slhdsa_shake_128s_ops = { + EVP_PKEY_SLH_DSA_SHAKE_128S, + pkcs11_get_evp_key_slhdsa_shake_128s, +}; + +PKCS11_OBJECT_ops pkcs11_slhdsa_shake_128f_ops = { + EVP_PKEY_SLH_DSA_SHAKE_128F, + pkcs11_get_evp_key_slhdsa_shake_128f, +}; + +PKCS11_OBJECT_ops pkcs11_slhdsa_shake_192s_ops = { + EVP_PKEY_SLH_DSA_SHAKE_192S, + pkcs11_get_evp_key_slhdsa_shake_192s, +}; + +PKCS11_OBJECT_ops pkcs11_slhdsa_shake_192f_ops = { + EVP_PKEY_SLH_DSA_SHAKE_192F, + pkcs11_get_evp_key_slhdsa_shake_192f, +}; + +PKCS11_OBJECT_ops pkcs11_slhdsa_shake_256s_ops = { + EVP_PKEY_SLH_DSA_SHAKE_256S, + pkcs11_get_evp_key_slhdsa_shake_256s, +}; + +PKCS11_OBJECT_ops pkcs11_slhdsa_shake_256f_ops = { + EVP_PKEY_SLH_DSA_SHAKE_256F, + pkcs11_get_evp_key_slhdsa_shake_256f, +}; + + +#else /* !defined(OPENSSL_NO_SLH_DSA) && OPENSSL_VERSION_NUMBER >= 0x30500000L */ +/* + * SLH-DSA support is not available: + * - either OpenSSL was built without SLH-DSA support, or + * - OpenSSL version is older than 3.5. + */ +#warning "SLH-DSA support not built with libp11" + +#endif /* !defined(OPENSSL_NO_SLH_DSA) && OPENSSL_VERSION_NUMBER >= 0x30500000L */ + +/* vim: set noexpandtab: */ diff --git a/src/pkcs11.h b/src/pkcs11.h index 7878d5f1..7d4e7979 100644 --- a/src/pkcs11.h +++ b/src/pkcs11.h @@ -534,8 +534,8 @@ typedef unsigned long ck_mechanism_type_t; #define CKM_DH_PKCS_KEY_PAIR_GEN (0x20UL) #define CKM_DH_PKCS_DERIVE (0x21UL) /* PKCS#11 v3.2: SLH-DSA */ -#define CKM_SLH_DSA_KEY_PAIR_GEN (0x2EUL) -#define CKM_SLH_DSA (0x2FUL) +#define CKM_SLH_DSA_KEY_PAIR_GEN (0x2DUL) +#define CKM_SLH_DSA (0x2EUL) #define CKM_X9_42_DH_KEY_PAIR_GEN (0x30UL) #define CKM_X9_42_DH_DERIVE (0x31UL) #define CKM_X9_42_DH_HYBRID_DERIVE (0x32UL) diff --git a/src/provider.c b/src/provider.c index 4aa136dc..2dc63707 100644 --- a/src/provider.c +++ b/src/provider.c @@ -202,6 +202,41 @@ static const OSSL_ALGORITHM p11_keymgmts[] = { {"EC:id-ecPublicKey", FIPS_PROPQ, keymgmt_functions, "PKCS#11 EC keymgm functions"}, {"ED25519", FIPS_PROPQ, keymgmt_functions, "PKCS#11 Ed25519 keymgm functions"}, {"ED448", FIPS_PROPQ, keymgmt_functions, "PKCS#11 Ed448 keymgm functions"}, +#if OPENSSL_VERSION_NUMBER >= 0x30500000L +#ifndef OPENSSL_NO_ML_DSA + {"ML-DSA-44", FIPS_PROPQ, keymgmt_functions, "PKCS#11 ML-DSA-44 keymgmt functions"}, + {"ML-DSA-65", FIPS_PROPQ, keymgmt_functions, "PKCS#11 ML-DSA-65 keymgmt functions"}, + {"ML-DSA-87", FIPS_PROPQ, keymgmt_functions, "PKCS#11 ML-DSA-87 keymgmt functions"}, +#endif /* OPENSSL_NO_ML_DSA */ +#ifndef OPENSSL_NO_SLH_DSA + {"SLH-DSA-SHA2-128s", FIPS_PROPQ, keymgmt_functions, + "PKCS#11 SLH-DSA-SHA2-128s keymgmt functions"}, + {"SLH-DSA-SHA2-128f", FIPS_PROPQ, keymgmt_functions, + "PKCS#11 SLH-DSA-SHA2-128f keymgmt functions"}, + {"SLH-DSA-SHA2-192s", FIPS_PROPQ, keymgmt_functions, + "PKCS#11 SLH-DSA-SHA2-192s keymgmt functions"}, + {"SLH-DSA-SHA2-192f", FIPS_PROPQ, keymgmt_functions, + "PKCS#11 SLH-DSA-SHA2-192f keymgmt functions"}, + {"SLH-DSA-SHA2-256s", FIPS_PROPQ, keymgmt_functions, + "PKCS#11 SLH-DSA-SHA2-256s keymgmt functions"}, + {"SLH-DSA-SHA2-256f", FIPS_PROPQ, keymgmt_functions, + "PKCS#11 SLH-DSA-SHA2-256f keymgmt functions"}, + {"SLH-DSA-SHAKE-128s", FIPS_PROPQ, keymgmt_functions, + "PKCS#11 SLH-DSA-SHAKE-128s keymgmt functions"}, + {"SLH-DSA-SHAKE-128f", FIPS_PROPQ, keymgmt_functions, + "PKCS#11 SLH-DSA-SHAKE-128f keymgmt functions"}, + {"SLH-DSA-SHAKE-192s", FIPS_PROPQ, keymgmt_functions, + "PKCS#11 SLH-DSA-SHAKE-192s keymgmt functions"}, + {"SLH-DSA-SHAKE-192f", FIPS_PROPQ, keymgmt_functions, + "PKCS#11 SLH-DSA-SHAKE-192f keymgmt functions"}, + {"SLH-DSA-SHAKE-256s", FIPS_PROPQ, keymgmt_functions, + "PKCS#11 SLH-DSA-SHAKE-256s keymgmt functions"}, + {"SLH-DSA-SHAKE-256f", FIPS_PROPQ, keymgmt_functions, + "PKCS#11 SLH-DSA-SHAKE-256f keymgmt functions"}, +#endif /* OPENSSL_NO_SLH_DSA */ +#endif /* OPENSSL_VERSION_NUMBER >= 0x30500000L */ + {"FALCON-512", FIPS_PROPQ, keymgmt_functions, "PKCS#11 Falcon-512 keymgmt"}, + {"FALCON-1024", FIPS_PROPQ, keymgmt_functions, "PKCS#11 Falcon-512 keymgmt"}, {NULL, NULL, NULL, NULL} }; @@ -547,7 +582,30 @@ static int keymgmt_export(void *provkey, int selection, OSSL_CALLBACK *param_cb, return export_ec_pub(keydata, param_cb, cbarg); case EVP_PKEY_ED25519: case EVP_PKEY_ED448: - return export_eddsa_pub(keydata, param_cb, cbarg); +#if OPENSSL_VERSION_NUMBER >= 0x30500000L +#ifndef OPENSSL_NO_ML_DSA + case EVP_PKEY_ML_DSA_44: + case EVP_PKEY_ML_DSA_65: + case EVP_PKEY_ML_DSA_87: +#endif /* OPENSSL_NO_ML_DSA */ +#ifndef OPENSSL_NO_SLH_DSA + case EVP_PKEY_SLH_DSA_SHA2_128S: + case EVP_PKEY_SLH_DSA_SHA2_128F: + case EVP_PKEY_SLH_DSA_SHA2_192S: + case EVP_PKEY_SLH_DSA_SHA2_192F: + case EVP_PKEY_SLH_DSA_SHA2_256S: + case EVP_PKEY_SLH_DSA_SHA2_256F: + case EVP_PKEY_SLH_DSA_SHAKE_128S: + case EVP_PKEY_SLH_DSA_SHAKE_128F: + case EVP_PKEY_SLH_DSA_SHAKE_192S: + case EVP_PKEY_SLH_DSA_SHAKE_192F: + case EVP_PKEY_SLH_DSA_SHAKE_256S: + case EVP_PKEY_SLH_DSA_SHAKE_256F: +#endif /* OPENSSL_NO_SLH_DSA */ +#endif /* OPENSSL_VERSION_NUMBER >= 0x30500000L */ + case EVP_PKEY_FALCON512: + case EVP_PKEY_FALCON1024: + return export_raw_pub(keydata, param_cb, cbarg); default: return 0; } @@ -581,7 +639,7 @@ static int keymgmt_get_params(void *provkey, OSSL_PARAM params[]) P11_KEYDATA *keydata = (P11_KEYDATA *)provkey; const OSSL_PARAM *pub; OSSL_PARAM *p; - int bits, secbits; + int type, bits, secbits; #if OPENSSL_VERSION_NUMBER >= 0x30600000L int category; #endif /* OPENSSL_VERSION_NUMBER >= 0x30600000L */ @@ -589,6 +647,7 @@ static int keymgmt_get_params(void *provkey, OSSL_PARAM params[]) if (keydata == NULL || params == NULL) return 0; + type = p11_keydata_get_type(keydata); bits = p11_keydata_get_bits(keydata); secbits = p11_keydata_get_security_bits(keydata); #if OPENSSL_VERSION_NUMBER >= 0x30600000L @@ -619,24 +678,49 @@ static int keymgmt_get_params(void *provkey, OSSL_PARAM params[]) /* EVP_PKEY_get1_encoded_public_key(), not covered by tests */ p = OSSL_PARAM_locate(params, OSSL_PKEY_PARAM_ENCODED_PUBLIC_KEY); - if (p != NULL && p11_keydata_get_type(keydata) == EVP_PKEY_EC) { + if (p != NULL && type == EVP_PKEY_EC) { const OSSL_PARAM *key_params = p11_keydata_get_params(keydata); if (key_params == NULL) return 0; pub = OSSL_PARAM_locate_const(key_params, OSSL_PKEY_PARAM_PUB_KEY); - if (pub != NULL && pub->data != NULL && - !OSSL_PARAM_set_octet_string(p, pub->data, pub->data_size)) + if (pub == NULL || pub->data_type != OSSL_PARAM_OCTET_STRING || + pub->data == NULL || pub->data_size == 0) + return 0; + if (!OSSL_PARAM_set_octet_string(p, pub->data, pub->data_size)) return 0; } - /* EVP_PKEY_get_default_digest_nid(), "pkeyutl -sign -rawin" - * For signature algorithms like RSA, DSA and ECDSA, the default - * digest algorithm is SHA256. */ - p = OSSL_PARAM_locate(params, OSSL_PKEY_PARAM_DEFAULT_DIGEST); - if (p != NULL && !OSSL_PARAM_set_utf8_string(p, "SHA256")) - return 0; + p = OSSL_PARAM_locate(params, OSSL_PKEY_PARAM_PUB_KEY); + if (p != NULL && is_oneshot_sig_type(type)) { + const OSSL_PARAM *key_params = p11_keydata_get_params(keydata); + + if (key_params == NULL) + return 0; + + pub = OSSL_PARAM_locate_const(key_params, OSSL_PKEY_PARAM_PUB_KEY); + if (pub == NULL || pub->data_type != OSSL_PARAM_OCTET_STRING || + pub->data == NULL || pub->data_size == 0) + return 0; + if (!OSSL_PARAM_set_octet_string(p, pub->data, pub->data_size)) + return 0; + } + + /* EVP_PKEY_get_default_digest_name(), "pkeyutl -sign -rawin" + * Hash-and-sign algorithms such as RSA and ECDSA use SHA256 as the + * default digest. One-shot signature algorithms (EdDSA, ML-DSA, + * SLH-DSA) do not accept an external digest and therefore report + * OSSL_PKEY_PARAM_MANDATORY_DIGEST = "UNDEF". */ + if (is_oneshot_sig_type(type)) { + p = OSSL_PARAM_locate(params, OSSL_PKEY_PARAM_MANDATORY_DIGEST); + if (p != NULL && !OSSL_PARAM_set_utf8_string(p, "UNDEF")) + return 0; + } else { + p = OSSL_PARAM_locate(params, OSSL_PKEY_PARAM_DEFAULT_DIGEST); + if (p != NULL && !OSSL_PARAM_set_utf8_string(p, "SHA256")) + return 0; + } return 1; } @@ -652,7 +736,9 @@ static const OSSL_PARAM *keymgmt_gettable_params(void *provctx) OSSL_PARAM_int(OSSL_PKEY_PARAM_SECURITY_CATEGORY, NULL), #endif /* OPENSSL_VERSION_NUMBER >= 0x30600000L */ OSSL_PARAM_octet_string(OSSL_PKEY_PARAM_ENCODED_PUBLIC_KEY, NULL, 0), + OSSL_PARAM_octet_string(OSSL_PKEY_PARAM_PUB_KEY, NULL, 0), OSSL_PARAM_utf8_string(OSSL_PKEY_PARAM_DEFAULT_DIGEST, NULL, 0), + OSSL_PARAM_utf8_string(OSSL_PKEY_PARAM_MANDATORY_DIGEST, NULL, 0), OSSL_PARAM_END }; (void)provctx; @@ -812,9 +898,37 @@ static int signature_digest_sign_init(void *ctx, const char *mdname, void *provk if (!p11_signature_ctx_init(sig_ctx, keydata, params)) return 0; - if (p11_keydata_get_type(keydata) == EVP_PKEY_ED25519 || - p11_keydata_get_type(keydata) == EVP_PKEY_ED448) - return 1; /* Ed25519 / Ed448 do not use an external digest */ + switch (p11_keydata_get_type(keydata)) { + case EVP_PKEY_ED25519: + case EVP_PKEY_ED448: +#if OPENSSL_VERSION_NUMBER >= 0x30500000L +#ifndef OPENSSL_NO_ML_DSA + case EVP_PKEY_ML_DSA_44: + case EVP_PKEY_ML_DSA_65: + case EVP_PKEY_ML_DSA_87: +#endif /* OPENSSL_NO_ML_DSA */ +#ifndef OPENSSL_NO_SLH_DSA + case EVP_PKEY_SLH_DSA_SHA2_128S: + case EVP_PKEY_SLH_DSA_SHA2_128F: + case EVP_PKEY_SLH_DSA_SHA2_192S: + case EVP_PKEY_SLH_DSA_SHA2_192F: + case EVP_PKEY_SLH_DSA_SHA2_256S: + case EVP_PKEY_SLH_DSA_SHA2_256F: + case EVP_PKEY_SLH_DSA_SHAKE_128S: + case EVP_PKEY_SLH_DSA_SHAKE_128F: + case EVP_PKEY_SLH_DSA_SHAKE_192S: + case EVP_PKEY_SLH_DSA_SHAKE_192F: + case EVP_PKEY_SLH_DSA_SHAKE_256S: + case EVP_PKEY_SLH_DSA_SHAKE_256F: +#endif /* OPENSSL_NO_SLH_DSA */ +#endif /* OPENSSL_VERSION_NUMBER >= 0x30500000L */ + case EVP_PKEY_FALCON512: + case EVP_PKEY_FALCON1024: + /* EdDSA, ML-DSA, SLH-DSA, FALCON are one-shot signature algorithms */ + return 1; + default: + break; + } /* For signature algorithms the default digest algorithm is SHA256 */ if (mdname == NULL) @@ -855,7 +969,30 @@ static int signature_digest_sign_update(void *ctx, const unsigned char *data, switch (p11_signature_ctx_get_type(sig_ctx)) { case EVP_PKEY_ED25519: case EVP_PKEY_ED448: - /* EdDSA does not support streaming DigestSignUpdate/Final */ +#if OPENSSL_VERSION_NUMBER >= 0x30500000L +#ifndef OPENSSL_NO_ML_DSA + case EVP_PKEY_ML_DSA_44: + case EVP_PKEY_ML_DSA_65: + case EVP_PKEY_ML_DSA_87: +#endif /* OPENSSL_NO_ML_DSA */ +#ifndef OPENSSL_NO_SLH_DSA + case EVP_PKEY_SLH_DSA_SHA2_128S: + case EVP_PKEY_SLH_DSA_SHA2_128F: + case EVP_PKEY_SLH_DSA_SHA2_192S: + case EVP_PKEY_SLH_DSA_SHA2_192F: + case EVP_PKEY_SLH_DSA_SHA2_256S: + case EVP_PKEY_SLH_DSA_SHA2_256F: + case EVP_PKEY_SLH_DSA_SHAKE_128S: + case EVP_PKEY_SLH_DSA_SHAKE_128F: + case EVP_PKEY_SLH_DSA_SHAKE_192S: + case EVP_PKEY_SLH_DSA_SHAKE_192F: + case EVP_PKEY_SLH_DSA_SHAKE_256S: + case EVP_PKEY_SLH_DSA_SHAKE_256F: +#endif /* OPENSSL_NO_SLH_DSA */ +#endif /* OPENSSL_VERSION_NUMBER >= 0x30500000L */ + case EVP_PKEY_FALCON512: + case EVP_PKEY_FALCON1024: + /* EdDSA, ML-DSA, SLH-DSA, FALCON are one-shot signature algorithms */ return 0; case EVP_PKEY_RSA: @@ -891,7 +1028,30 @@ static int signature_digest_sign_final(void *ctx, unsigned char *sig, switch (p11_signature_ctx_get_type(sig_ctx)) { case EVP_PKEY_ED25519: case EVP_PKEY_ED448: - /* EdDSA should use one-shot signature_digest_sign() */ +#if OPENSSL_VERSION_NUMBER >= 0x30500000L +#ifndef OPENSSL_NO_ML_DSA + case EVP_PKEY_ML_DSA_44: + case EVP_PKEY_ML_DSA_65: + case EVP_PKEY_ML_DSA_87: +#endif /* OPENSSL_NO_ML_DSA */ +#ifndef OPENSSL_NO_SLH_DSA + case EVP_PKEY_SLH_DSA_SHA2_128S: + case EVP_PKEY_SLH_DSA_SHA2_128F: + case EVP_PKEY_SLH_DSA_SHA2_192S: + case EVP_PKEY_SLH_DSA_SHA2_192F: + case EVP_PKEY_SLH_DSA_SHA2_256S: + case EVP_PKEY_SLH_DSA_SHA2_256F: + case EVP_PKEY_SLH_DSA_SHAKE_128S: + case EVP_PKEY_SLH_DSA_SHAKE_128F: + case EVP_PKEY_SLH_DSA_SHAKE_192S: + case EVP_PKEY_SLH_DSA_SHAKE_192F: + case EVP_PKEY_SLH_DSA_SHAKE_256S: + case EVP_PKEY_SLH_DSA_SHAKE_256F: +#endif /* OPENSSL_NO_SLH_DSA */ +#endif /* OPENSSL_VERSION_NUMBER >= 0x30500000L */ + case EVP_PKEY_FALCON512: + case EVP_PKEY_FALCON1024: + /* EdDSA, ML-DSA, SLH-DSA, FALCON are one-shot signature algorithms */ return 0; case EVP_PKEY_RSA: @@ -968,7 +1128,30 @@ static int signature_digest_sign(void *ctx, unsigned char *sig, size_t *siglen, switch (p11_signature_ctx_get_type(sig_ctx)) { case EVP_PKEY_ED25519: case EVP_PKEY_ED448: - /* EdDSA signs the message directly */ +#if OPENSSL_VERSION_NUMBER >= 0x30500000L +#ifndef OPENSSL_NO_ML_DSA + case EVP_PKEY_ML_DSA_44: + case EVP_PKEY_ML_DSA_65: + case EVP_PKEY_ML_DSA_87: +#endif /* OPENSSL_NO_ML_DSA */ +#ifndef OPENSSL_NO_SLH_DSA + case EVP_PKEY_SLH_DSA_SHA2_128S: + case EVP_PKEY_SLH_DSA_SHA2_128F: + case EVP_PKEY_SLH_DSA_SHA2_192S: + case EVP_PKEY_SLH_DSA_SHA2_192F: + case EVP_PKEY_SLH_DSA_SHA2_256S: + case EVP_PKEY_SLH_DSA_SHA2_256F: + case EVP_PKEY_SLH_DSA_SHAKE_128S: + case EVP_PKEY_SLH_DSA_SHAKE_128F: + case EVP_PKEY_SLH_DSA_SHAKE_192S: + case EVP_PKEY_SLH_DSA_SHAKE_192F: + case EVP_PKEY_SLH_DSA_SHAKE_256S: + case EVP_PKEY_SLH_DSA_SHAKE_256F: +#endif /* OPENSSL_NO_SLH_DSA */ +#endif /* OPENSSL_VERSION_NUMBER >= 0x30500000L */ + case EVP_PKEY_FALCON512: + case EVP_PKEY_FALCON1024: + /* EdDSA, ML-DSA, SLH-DSA, FALCON are one-shot signature algorithms */ return PKCS11_evp_pkey_sign( p11_signature_ctx_get_evp_pkey(sig_ctx), p11_signature_ctx_get_type(sig_ctx), @@ -1024,9 +1207,37 @@ static int signature_digest_verify_init(void *ctx, const char *mdname, if (!p11_signature_ctx_init(sig_ctx, keydata, params)) return 0; - if (p11_keydata_get_type(keydata) == EVP_PKEY_ED25519 || - p11_keydata_get_type(keydata) == EVP_PKEY_ED448) - return 1; /* Ed25519 / Ed448 do not use an external digest */ + switch (p11_keydata_get_type(keydata)) { + case EVP_PKEY_ED25519: + case EVP_PKEY_ED448: +#if OPENSSL_VERSION_NUMBER >= 0x30500000L +#ifndef OPENSSL_NO_ML_DSA + case EVP_PKEY_ML_DSA_44: + case EVP_PKEY_ML_DSA_65: + case EVP_PKEY_ML_DSA_87: +#endif /* OPENSSL_NO_ML_DSA */ +#ifndef OPENSSL_NO_SLH_DSA + case EVP_PKEY_SLH_DSA_SHA2_128S: + case EVP_PKEY_SLH_DSA_SHA2_128F: + case EVP_PKEY_SLH_DSA_SHA2_192S: + case EVP_PKEY_SLH_DSA_SHA2_192F: + case EVP_PKEY_SLH_DSA_SHA2_256S: + case EVP_PKEY_SLH_DSA_SHA2_256F: + case EVP_PKEY_SLH_DSA_SHAKE_128S: + case EVP_PKEY_SLH_DSA_SHAKE_128F: + case EVP_PKEY_SLH_DSA_SHAKE_192S: + case EVP_PKEY_SLH_DSA_SHAKE_192F: + case EVP_PKEY_SLH_DSA_SHAKE_256S: + case EVP_PKEY_SLH_DSA_SHAKE_256F: +#endif /* OPENSSL_NO_SLH_DSA */ +#endif /* OPENSSL_VERSION_NUMBER >= 0x30500000L */ + case EVP_PKEY_FALCON512: + case EVP_PKEY_FALCON1024: + /* EdDSA, ML-DSA, SLH-DSA, FALCON are one-shot signature algorithms */ + return 1; + default: + break; + } /* For signature algorithms the default digest algorithm is SHA256 */ if (mdname == NULL) @@ -1068,7 +1279,30 @@ static int signature_digest_verify_update(void *ctx, const unsigned char *data, switch (p11_signature_ctx_get_type(sig_ctx)) { case EVP_PKEY_ED25519: case EVP_PKEY_ED448: - /* EdDSA does not support streaming DigestVerifyUpdate/Final */ +#if OPENSSL_VERSION_NUMBER >= 0x30500000L +#ifndef OPENSSL_NO_ML_DSA + case EVP_PKEY_ML_DSA_44: + case EVP_PKEY_ML_DSA_65: + case EVP_PKEY_ML_DSA_87: +#endif /* OPENSSL_NO_ML_DSA */ +#ifndef OPENSSL_NO_SLH_DSA + case EVP_PKEY_SLH_DSA_SHA2_128S: + case EVP_PKEY_SLH_DSA_SHA2_128F: + case EVP_PKEY_SLH_DSA_SHA2_192S: + case EVP_PKEY_SLH_DSA_SHA2_192F: + case EVP_PKEY_SLH_DSA_SHA2_256S: + case EVP_PKEY_SLH_DSA_SHA2_256F: + case EVP_PKEY_SLH_DSA_SHAKE_128S: + case EVP_PKEY_SLH_DSA_SHAKE_128F: + case EVP_PKEY_SLH_DSA_SHAKE_192S: + case EVP_PKEY_SLH_DSA_SHAKE_192F: + case EVP_PKEY_SLH_DSA_SHAKE_256S: + case EVP_PKEY_SLH_DSA_SHAKE_256F: +#endif /* OPENSSL_NO_SLH_DSA */ +#endif /* OPENSSL_VERSION_NUMBER >= 0x30500000L */ + case EVP_PKEY_FALCON512: + case EVP_PKEY_FALCON1024: + /* EdDSA, ML-DSA, SLH-DSA, FALCON are one-shot signature algorithms */ return 0; case EVP_PKEY_RSA: @@ -1103,7 +1337,30 @@ static int signature_digest_verify_final(void *ctx, const unsigned char *sig, switch (p11_signature_ctx_get_type(sig_ctx)) { case EVP_PKEY_ED25519: case EVP_PKEY_ED448: - /* EdDSA should use one-shot EVP_DigestVerify() */ +#if OPENSSL_VERSION_NUMBER >= 0x30500000L +#ifndef OPENSSL_NO_ML_DSA + case EVP_PKEY_ML_DSA_44: + case EVP_PKEY_ML_DSA_65: + case EVP_PKEY_ML_DSA_87: +#endif /* OPENSSL_NO_ML_DSA */ +#ifndef OPENSSL_NO_SLH_DSA + case EVP_PKEY_SLH_DSA_SHA2_128S: + case EVP_PKEY_SLH_DSA_SHA2_128F: + case EVP_PKEY_SLH_DSA_SHA2_192S: + case EVP_PKEY_SLH_DSA_SHA2_192F: + case EVP_PKEY_SLH_DSA_SHA2_256S: + case EVP_PKEY_SLH_DSA_SHA2_256F: + case EVP_PKEY_SLH_DSA_SHAKE_128S: + case EVP_PKEY_SLH_DSA_SHAKE_128F: + case EVP_PKEY_SLH_DSA_SHAKE_192S: + case EVP_PKEY_SLH_DSA_SHAKE_192F: + case EVP_PKEY_SLH_DSA_SHAKE_256S: + case EVP_PKEY_SLH_DSA_SHAKE_256F: +#endif /* OPENSSL_NO_SLH_DSA */ +#endif /* OPENSSL_VERSION_NUMBER >= 0x30500000L */ + case EVP_PKEY_FALCON512: + case EVP_PKEY_FALCON1024: + /* EdDSA, ML-DSA, SLH-DSA, FALCON are one-shot signature algorithms */ return 0; case EVP_PKEY_RSA: @@ -1145,9 +1402,38 @@ static int signature_digest_verify(void *ctx, switch (p11_signature_ctx_get_type(sig_ctx)) { case EVP_PKEY_ED25519: case EVP_PKEY_ED448: - /* EdDSA verifies the message directly */ +#if OPENSSL_VERSION_NUMBER >= 0x30500000L +#ifndef OPENSSL_NO_ML_DSA + case EVP_PKEY_ML_DSA_44: + case EVP_PKEY_ML_DSA_65: + case EVP_PKEY_ML_DSA_87: +#endif /* OPENSSL_NO_ML_DSA */ +#ifndef OPENSSL_NO_SLH_DSA + case EVP_PKEY_SLH_DSA_SHA2_128S: + case EVP_PKEY_SLH_DSA_SHA2_128F: + case EVP_PKEY_SLH_DSA_SHA2_192S: + case EVP_PKEY_SLH_DSA_SHA2_192F: + case EVP_PKEY_SLH_DSA_SHA2_256S: + case EVP_PKEY_SLH_DSA_SHA2_256F: + case EVP_PKEY_SLH_DSA_SHAKE_128S: + case EVP_PKEY_SLH_DSA_SHAKE_128F: + case EVP_PKEY_SLH_DSA_SHAKE_192S: + case EVP_PKEY_SLH_DSA_SHAKE_192F: + case EVP_PKEY_SLH_DSA_SHAKE_256S: + case EVP_PKEY_SLH_DSA_SHAKE_256F: +#endif /* OPENSSL_NO_SLH_DSA */ +#endif /* OPENSSL_VERSION_NUMBER >= 0x30500000L */ + /* EdDSA, ML-DSA, SLH-DSA are one-shot signature algorithms */ return p11_signature_ctx_verify(sig_ctx, sig, siglen, tbs, tbslen); + case EVP_PKEY_FALCON512: + case EVP_PKEY_FALCON1024: + /* FALCON is not supported by OpenSSL verify path */ + return PKCS11_evp_pkey_verify( + p11_signature_ctx_get_evp_pkey(sig_ctx), + p11_signature_ctx_get_type(sig_ctx), + sig, siglen, tbs, tbslen); + case EVP_PKEY_RSA: case EVP_PKEY_RSA_PSS: case EVP_PKEY_EC: diff --git a/src/provider_helpers.c b/src/provider_helpers.c index e7e764e9..42609a5b 100644 --- a/src/provider_helpers.c +++ b/src/provider_helpers.c @@ -40,6 +40,43 @@ #define PKCS11_PROVIDER_NAME "libp11 PKCS#11 provider" +#ifndef OPENSSL_NO_ECX +#define ED25519_KEYLEN 32 +#define ED448_KEYLEN 57 +#define ED25519_SIGSIZE 64 +#define ED448_SIGSIZE 114 +#endif /* OPENSSL_NO_ECX */ + +#if OPENSSL_VERSION_NUMBER >= 0x30500000L +#ifndef OPENSSL_NO_ML_DSA +#define ML_DSA_44_PUB_LEN 1312 +#define ML_DSA_65_PUB_LEN 1952 +#define ML_DSA_87_PUB_LEN 2592 +#define ML_DSA_44_SIG_LEN 2420 +#define ML_DSA_65_SIG_LEN 3309 +#define ML_DSA_87_SIG_LEN 4627 +#endif /* OPENSSL_NO_ML_DSA */ +#ifndef OPENSSL_NO_SLH_DSA +#define SLH_DSA_128S_PUB_BYTES 32 +#define SLH_DSA_128F_PUB_BYTES 32 +#define SLH_DSA_192S_PUB_BYTES 48 +#define SLH_DSA_192F_PUB_BYTES 48 +#define SLH_DSA_256S_PUB_BYTES 64 +#define SLH_DSA_256F_PUB_BYTES 64 +#define SLH_DSA_128S_SIG_BYTES 7856 +#define SLH_DSA_128F_SIG_BYTES 17088 +#define SLH_DSA_192S_SIG_BYTES 16224 +#define SLH_DSA_192F_SIG_BYTES 35664 +#define SLH_DSA_256S_SIG_BYTES 29792 +#define SLH_DSA_256F_SIG_BYTES 49856 +#endif /* OPENSSL_NO_SLH_DSA */ +#endif /* OPENSSL_VERSION_NUMBER >= 0x30500000L */ + +#define FALCON_512_PUB_LEN 897 +#define FALCON_1024_PUB_LEN 2305 +#define FALCON_512_SIG_LEN 666 +#define FALCON_1024_SIG_LEN 1280 + typedef struct { char *pkcs11_module; char *pin; @@ -93,30 +130,42 @@ typedef struct p11_ec_pub_st { size_t pub_len; } P11_EC_PUB; -typedef struct p11_eddsa_pub_st { - unsigned char *pub; /* optional raw 32/57-byte public key */ +typedef struct p11_raw_pub_st { + unsigned char *pub; /* optional raw public key */ size_t pub_len; -} P11_EDDSA_PUB; +} P11_RAW_PUB; typedef union p11_pubdata_u { P11_RSA_PUB rsa; P11_EC_PUB ec; - P11_EDDSA_PUB eddsa; + P11_RAW_PUB raw; } P11_PUBDATA; struct p11_keydata_st { PROVIDER_CTX *prov_ctx; int refcnt; CRYPTO_RWLOCK *lock; - int type; /* EVP_PKEY_RSA, EVP_PKEY_EC, EVP_PKEY_ED25519, EVP_PKEY_ED448 */ - const char *name; /* "RSA", "EC", "ED25519", "ED448" */ + /* EVP_PKEY_* type identifier: RSA, EC, EdDSA, ML-DSA, SLH-DSA, etc. */ + int type; + /* Algorithm name: "RSA", "EC", "ED25519", "ML-DSA-44", etc. */ + const char *name; int is_private; - EVP_PKEY *pkey; /* optional cache */ - size_t keysize; /* bytes: RSA modulus, EC field/order bytes, EdDSA key bytes */ - size_t sigsize; /* bytes if fixed-size signature (RSA/EdDSA), else 0 */ - OSSL_PARAM *params; /* owned by this struct; free with OSSL_PARAM_free() */ - P11_PUB_KEY *pubkey; /* optional raw public key */ - P11_PUBDATA pubdata; /* data for keymgmt_export() */ + /* optional cached EVP_PKEY */ + EVP_PKEY *pkey; + /* Public key size in bytes: + * - RSA: modulus size + * - EC: group order size + * - EdDSA / ML-DSA / SLH-DSA: raw public key size */ + size_t keysize; + /* Signature size in bytes if fixed-size, + * otherwise 0 for variable-size signatures */ + size_t sigsize; + /* owned by this struct; free with OSSL_PARAM_free() */ + OSSL_PARAM *params; + /* optional provider-side public key cache */ + P11_PUB_KEY *pubkey; + /* public-key material used by keymgmt_export() */ + P11_PUBDATA pubdata; }; struct p11_store_ctx_st { @@ -130,7 +179,7 @@ struct p11_signature_ctx { PROVIDER_CTX *prov_ctx; char *propq; P11_KEYDATA *keydata; - char *mdname; /* digest name (RSA/ECDSA); NULL for EdDSA */ + char *mdname; /* digest name (RSA/ECDSA); NULL for EdDSA, ML-DSA, SLH-DSA */ EVP_MD_CTX *mdctx; /* digest state for DigestSignUpdate/Final */ int pad_mode; /* RSA_NO_PADDING, RSA_PKCS1_PADDING, RSA_PKCS1_PSS_PADDING */ int pss_saltlen; /* RSA_PSS_SALTLEN_* or >=0 explicit */ @@ -155,28 +204,37 @@ static EVP_PKEY *pubkey_from_params_default(P11_KEYDATA *keydata); static EVP_PKEY *p11_keydata_get_evp_pkey(P11_KEYDATA *keydata); static int p11_keydata_set_pub(P11_KEYDATA *keydata, const void *buf, size_t len); static OSSL_PARAM *public_params_from_evp_pkey(EVP_PKEY *pkey); -static int p11_keydata_init_from_params(P11_KEYDATA *keydata); -static int p11_keydata_replace_params(P11_KEYDATA *keydata, OSSL_PARAM *params); -static int algorithm_from_ossl_param(const OSSL_PARAM *params); +static int p11_keydata_init_from_params(EVP_PKEY *pkey, P11_KEYDATA *keydata); +static int p11_keydata_init_rsa_from_params(P11_KEYDATA *keydata); +#ifndef OPENSSL_NO_EC +static int p11_keydata_init_ec_from_params(P11_KEYDATA *keydata); +#endif /* OPENSSL_NO_EC */ +#ifndef OPENSSL_NO_ECX +static int p11_keydata_init_eddsa_from_params(P11_KEYDATA *keydata, int type); +#endif /* OPENSSL_NO_ECX */ +#if OPENSSL_VERSION_NUMBER >= 0x30500000L +#ifndef OPENSSL_NO_ML_DSA +static int p11_keydata_init_mldsa_from_params(P11_KEYDATA *keydata, int type); +#endif /* OPENSSL_NO_ML_DSA */ +#ifndef OPENSSL_NO_SLH_DSA +static int p11_keydata_init_slhdsa_from_params(P11_KEYDATA *keydata, int type); +#endif /* OPENSSL_NO_SLH_DSA */ +#endif /* OPENSSL_VERSION_NUMBER >= 0x30500000L */ +static int p11_keydata_init_falcon_from_params(P11_KEYDATA *keydata, int type); static int params_contains_private_key(const OSSL_PARAM *params); static int param_blob_equal(const OSSL_PARAM *a, const OSSL_PARAM *b); -static int rsa_public_match_params(const OSSL_PARAM *p1, const OSSL_PARAM *p2); #ifndef OPENSSL_NO_EC static int p11_dup_param_utf8(const OSSL_PARAM *p, char **out); -static int ec_public_match_params(const OSSL_PARAM *p1, const OSSL_PARAM *p2); static int ec_point_equal_by_value(const char *group_name, const unsigned char *a, size_t alen, const unsigned char *b, size_t blen); #endif /* OPENSSL_NO_EC */ -#ifndef OPENSSL_NO_ECX -static int eddsa_public_match_params(const OSSL_PARAM *p1, const OSSL_PARAM *p2); static int octet_equal(const OSSL_PARAM *a, const OSSL_PARAM *b); -#endif /* OPENSSL_NO_ECX */ static void p11_keydata_clear_pubdata(P11_KEYDATA *keydata); static int p11_dup_param_blob(const OSSL_PARAM *p, unsigned char **out, size_t *out_len); static int p11_keydata_get_pub(const P11_KEYDATA *keydata, unsigned char **buf, size_t *len); static int p11_signature_ctx_setup_rsa_verify(P11_SIGNATURE_CTX *sig_ctx, EVP_PKEY_CTX *pctx); - +static int evp_pkey_get_type_id(const EVP_PKEY *pkey); /******************************************************************************/ /* Provider helper API */ @@ -482,25 +540,20 @@ void p11_keydata_free(P11_KEYDATA *keydata) OSSL_PARAM_free(keydata->params); EVP_PKEY_free(keydata->pkey); - switch (keydata->type) { - case EVP_PKEY_RSA: - OPENSSL_free(keydata->pubdata.rsa.n); - OPENSSL_free(keydata->pubdata.rsa.e); - break; + if (keydata->name != NULL) { + if (strcmp(keydata->name, "RSA") == 0 || + strcmp(keydata->name, "RSA-PSS") == 0) { + OPENSSL_free(keydata->pubdata.rsa.n); + OPENSSL_free(keydata->pubdata.rsa.e); #ifndef OPENSSL_NO_EC - case EVP_PKEY_EC: - OPENSSL_free(keydata->pubdata.ec.group_name); - OPENSSL_free(keydata->pubdata.ec.pub); - break; -#endif /* OPENSSL_NO_EC */ -#ifndef OPENSSL_NO_ECX - case EVP_PKEY_ED25519: - case EVP_PKEY_ED448: - OPENSSL_free(keydata->pubdata.eddsa.pub); - break; -#endif /* OPENSSL_NO_ECX */ - default: - break; + } else if (strcmp(keydata->name, "EC") == 0) { + OPENSSL_free(keydata->pubdata.ec.group_name); + OPENSSL_free(keydata->pubdata.ec.pub); +#endif + } else { + /* EdDSA / ML-DSA / SLH-DSA / FALCON */ + OPENSSL_free(keydata->pubdata.raw.pub); + } } if (keydata->pubkey != NULL) { @@ -524,12 +577,12 @@ P11_KEYDATA *p11_keydata_from_evp_pkey(PROVIDER_CTX *ctx, EVP_PKEY *pkey, int is if (keydata == NULL) goto err; - keydata->type = EVP_PKEY_base_id(pkey); + keydata->type = evp_pkey_get_type_id(pkey); keydata->is_private = is_private; /* optional, params may be unavailable for some private keys */ keydata->params = public_params_from_evp_pkey(pkey); - if (keydata->params != NULL && p11_keydata_init_from_params(keydata) != 1) + if (keydata->params != NULL && p11_keydata_init_from_params(pkey, keydata) != 1) goto err; /* take our own reference before storing the pointer */ @@ -625,6 +678,43 @@ int p11_keydata_get_security_bits(const P11_KEYDATA *keydata) case EVP_PKEY_ED448: return 224; #endif /* OPENSSL_NO_ECX */ + +#if OPENSSL_VERSION_NUMBER >= 0x30500000L +#ifndef OPENSSL_NO_ML_DSA + case EVP_PKEY_ML_DSA_44: + return 128; + case EVP_PKEY_ML_DSA_65: + return 192; + case EVP_PKEY_ML_DSA_87: + return 256; +#endif /* OPENSSL_NO_ML_DSA */ + +#ifndef OPENSSL_NO_SLH_DSA + case EVP_PKEY_SLH_DSA_SHA2_128S: + case EVP_PKEY_SLH_DSA_SHA2_128F: + case EVP_PKEY_SLH_DSA_SHAKE_128S: + case EVP_PKEY_SLH_DSA_SHAKE_128F: + return 128; + + case EVP_PKEY_SLH_DSA_SHA2_192S: + case EVP_PKEY_SLH_DSA_SHA2_192F: + case EVP_PKEY_SLH_DSA_SHAKE_192S: + case EVP_PKEY_SLH_DSA_SHAKE_192F: + return 192; + + case EVP_PKEY_SLH_DSA_SHA2_256S: + case EVP_PKEY_SLH_DSA_SHA2_256F: + case EVP_PKEY_SLH_DSA_SHAKE_256S: + case EVP_PKEY_SLH_DSA_SHAKE_256F: + return 256; +#endif /* OPENSSL_NO_SLH_DSA */ +#endif /* OPENSSL_VERSION_NUMBER >= 0x30500000L */ + + case EVP_PKEY_FALCON512: + return 128; + case EVP_PKEY_FALCON1024: + return 256; + default: return 0; } @@ -651,6 +741,7 @@ size_t p11_keydata_get_sigsize(const P11_KEYDATA *keydata) /* * Return key type identifier: * EVP_PKEY_RSA, EVP_PKEY_EC, EVP_PKEY_ED25519, EVP_PKEY_ED448 + * EVP_PKEY_ML_DSA*, EVP_PKEY_SLH_DSA_* */ int p11_keydata_get_type(const P11_KEYDATA *keydata) { @@ -686,7 +777,6 @@ int p11_keydata_set_params(P11_KEYDATA *key, const OSSL_PARAM *params) p = OSSL_PARAM_locate_const(params, OSSL_PKEY_PARAM_PUB_KEY); if (p != NULL) { - if (!OSSL_PARAM_get_octet_string_ptr(p, &pub, &publen) || pub == NULL || publen == 0 || !p11_keydata_set_pub(key, pub, publen)) { @@ -694,34 +784,88 @@ int p11_keydata_set_params(P11_KEYDATA *key, const OSSL_PARAM *params) return 0; } } - return p11_keydata_replace_params(key, dup); + /* replace existing parameter set in key object with new OSSL_PARAM array */ + OSSL_PARAM_free(key->params); + key->params = dup; + key->is_private = params_contains_private_key(dup); + return 1; } -/* Compare two keys by public parameters, based on the key type. */ +/* + * Compare two public keys represented as OSSL_PARAM arrays. + * + * The key type is inferred from the available parameters: + * - RSA keys are identified by the presence of RSA modulus and exponent. + * - Classical EC keys are identified by GROUP_NAME and compared using + * curve-aware point comparison. + * - EdDSA, ML-DSA, SLH-DSA, Falcon and other raw public-key algorithms + * are compared as raw public-key octet strings. + * + * Returns 1 if the public keys are equal, 0 otherwise. + */ int p11_public_equal(const P11_KEYDATA *k1, const P11_KEYDATA *k2) { - if (k1 == NULL || k2 == NULL || k1->params == NULL || k2->params == NULL) + const OSSL_PARAM *n1, *e1, *n2, *e2; + const OSSL_PARAM *g1, *g2; + const OSSL_PARAM *pub1, *pub2; + const char *group1 = NULL, *group2 = NULL; + + if (k1 == NULL || k2 == NULL || + k1->params == NULL || k2->params == NULL) return 0; - if (k1->type != k2->type) + /* RSA: compare modulus (n) and public exponent (e). */ + n1 = OSSL_PARAM_locate_const(k1->params, OSSL_PKEY_PARAM_RSA_N); + e1 = OSSL_PARAM_locate_const(k1->params, OSSL_PKEY_PARAM_RSA_E); + n2 = OSSL_PARAM_locate_const(k2->params, OSSL_PKEY_PARAM_RSA_N); + e2 = OSSL_PARAM_locate_const(k2->params, OSSL_PKEY_PARAM_RSA_E); + + if (n1 != NULL || e1 != NULL || n2 != NULL || e2 != NULL) + return (n1 && e1 && n2 && e2 && + param_blob_equal(n1, n2) && param_blob_equal(e1, e2)); + + pub1 = OSSL_PARAM_locate_const(k1->params, OSSL_PKEY_PARAM_PUB_KEY); + pub2 = OSSL_PARAM_locate_const(k2->params, OSSL_PKEY_PARAM_PUB_KEY); + + if (pub1 == NULL || pub2 == NULL) return 0; - switch (k1->type) { - case EVP_PKEY_RSA: - case EVP_PKEY_RSA_PSS: - return rsa_public_match_params(k1->params, k2->params); #ifndef OPENSSL_NO_EC - case EVP_PKEY_EC: - return ec_public_match_params(k1->params, k2->params); -#endif /* OPENSSL_NO_EC */ -#ifndef OPENSSL_NO_ECX - case EVP_PKEY_ED25519: - case EVP_PKEY_ED448: - return eddsa_public_match_params(k1->params, k2->params); -#endif /* OPENSSL_NO_ECX */ - default: - return 0; + /* Classical EC keys include GROUP_NAME and must be compared using + * curve-aware point comparison. Ed25519 and Ed448 also may expose + * GROUP_NAME, but their public keys are raw octet strings. */ + g1 = OSSL_PARAM_locate_const(k1->params, OSSL_PKEY_PARAM_GROUP_NAME); + g2 = OSSL_PARAM_locate_const(k2->params, OSSL_PKEY_PARAM_GROUP_NAME); + + if (g1 != NULL && g2 != NULL) { + if (g1->data_type != OSSL_PARAM_UTF8_STRING || + g2->data_type != OSSL_PARAM_UTF8_STRING) + return 0; + + if (!OSSL_PARAM_get_utf8_string_ptr(g1, &group1) || + !OSSL_PARAM_get_utf8_string_ptr(g2, &group2) || + group1 == NULL || group2 == NULL) + return 0; + + if (OPENSSL_strcasecmp(group1, group2) != 0) + return 0; + + if (g1->data_type != OSSL_PARAM_UTF8_STRING || + g2->data_type != OSSL_PARAM_UTF8_STRING) + return 0; + + if (OPENSSL_strcasecmp(group1, "ed25519") == 0 || + OPENSSL_strcasecmp(group1, "ed448") == 0) + return octet_equal(pub1, pub2); /* EdDSA */ + + return ec_point_equal_by_value(group1, + (const unsigned char *)pub1->data, pub1->data_size, + (const unsigned char *)pub2->data, pub2->data_size); } +#endif /* OPENSSL_NO_EC */ + + /* EdDSA, ML-DSA, SLH-DSA, Falcon and other raw public-key algorithms. */ + return octet_equal(pub1, pub2); } /* Parse RSA padding mode from OSSL_PARAM (integer or string). */ @@ -793,15 +937,15 @@ int export_ec_pub(P11_KEYDATA *keydata, OSSL_CALLBACK *param_cb, void *cbarg) return param_cb(params, cbarg); } -int export_eddsa_pub(P11_KEYDATA *keydata, OSSL_CALLBACK *param_cb, void *cbarg) +int export_raw_pub(P11_KEYDATA *keydata, OSSL_CALLBACK *param_cb, void *cbarg) { OSSL_PARAM params[2]; unsigned char *pub = NULL; size_t pub_len = 0; - if (keydata->pubdata.eddsa.pub != NULL && keydata->pubdata.eddsa.pub_len != 0) + if (keydata->pubdata.raw.pub != NULL && keydata->pubdata.raw.pub_len != 0) params[0] = OSSL_PARAM_construct_octet_string(OSSL_PKEY_PARAM_PUB_KEY, - keydata->pubdata.eddsa.pub, keydata->pubdata.eddsa.pub_len); + keydata->pubdata.raw.pub, keydata->pubdata.raw.pub_len); else if (p11_keydata_get_pub(keydata, &pub, &pub_len) && pub != NULL && pub_len != 0) params[0] = OSSL_PARAM_construct_octet_string(OSSL_PKEY_PARAM_PUB_KEY, pub, pub_len); @@ -987,10 +1131,7 @@ int p11_signature_ctx_verify(P11_SIGNATURE_CTX *sig_ctx, if (pub == NULL) return 0; - switch (sig_ctx->keydata->type) { -#ifndef OPENSSL_NO_ECX - case EVP_PKEY_ED25519: - case EVP_PKEY_ED448: + if (is_oneshot_sig_type(sig_ctx->keydata->type)) { mdctx = EVP_MD_CTX_new(); if (mdctx == NULL) goto end; @@ -998,13 +1139,15 @@ int p11_signature_ctx_verify(P11_SIGNATURE_CTX *sig_ctx, if (EVP_DigestVerifyInit(mdctx, NULL, NULL, NULL, pub) <= 0) goto end; - if (EVP_DigestVerify(mdctx, sig, siglen, tbs, tbslen) <= 0) + if (EVP_DigestVerify(mdctx, sig, siglen, + tbs, tbslen) <= 0) goto end; ok = 1; - break; -#endif /* OPENSSL_NO_ECX */ + goto end; + } + switch (sig_ctx->keydata->type) { case EVP_PKEY_RSA: case EVP_PKEY_RSA_PSS: pctx = EVP_PKEY_CTX_new(pub, NULL); @@ -1046,6 +1189,7 @@ int p11_signature_ctx_verify(P11_SIGNATURE_CTX *sig_ctx, EVP_MD_CTX_free(mdctx); EVP_PKEY_CTX_free(pctx); EVP_PKEY_free(pub); + return ok; } @@ -1274,6 +1418,51 @@ const char *p11_pad_mode_to_string(int pad_mode) } } +/** + * Return whether the key type uses one-shot signing without an external digest. + * + * These algorithms internally process the input message as specified by + * their standards and therefore do not accept a separately supplied digest. + * Such key types report OSSL_PKEY_PARAM_MANDATORY_DIGEST = "UNDEF" via + * keymgmt_get_params(). + */ +int is_oneshot_sig_type(int type) +{ + switch (type) { +#ifndef OPENSSL_NO_ECX + case EVP_PKEY_ED25519: + case EVP_PKEY_ED448: +#endif +#if OPENSSL_VERSION_NUMBER >= 0x30500000L +#ifndef OPENSSL_NO_ML_DSA + case EVP_PKEY_ML_DSA_44: + case EVP_PKEY_ML_DSA_65: + case EVP_PKEY_ML_DSA_87: +#endif /* OPENSSL_NO_ML_DSA */ +#ifndef OPENSSL_NO_SLH_DSA + case EVP_PKEY_SLH_DSA_SHA2_128S: + case EVP_PKEY_SLH_DSA_SHA2_128F: + case EVP_PKEY_SLH_DSA_SHA2_192S: + case EVP_PKEY_SLH_DSA_SHA2_192F: + case EVP_PKEY_SLH_DSA_SHA2_256S: + case EVP_PKEY_SLH_DSA_SHA2_256F: + case EVP_PKEY_SLH_DSA_SHAKE_128S: + case EVP_PKEY_SLH_DSA_SHAKE_128F: + case EVP_PKEY_SLH_DSA_SHAKE_192S: + case EVP_PKEY_SLH_DSA_SHAKE_192F: + case EVP_PKEY_SLH_DSA_SHAKE_256S: + case EVP_PKEY_SLH_DSA_SHAKE_256F: +#endif /* OPENSSL_NO_SLH_DSA */ +#endif /* OPENSSL_VERSION_NUMBER >= 0x30500000L */ + case EVP_PKEY_FALCON512: + case EVP_PKEY_FALCON1024: + return 1; + + default: + return 0; + } +} + /******************************************************************************/ /* ASYM CIPHER helper functions */ @@ -1747,6 +1936,7 @@ static EVP_PKEY *pubkey_from_params_default(P11_KEYDATA *keydata) err: EVP_PKEY_CTX_free(pctx); EVP_PKEY_free(pkey); + return NULL; } @@ -1804,7 +1994,7 @@ static OSSL_PARAM *public_params_from_evp_pkey(EVP_PKEY *pkey) if (bld == NULL) return NULL; - nid = EVP_PKEY_base_id(pkey); + nid = evp_pkey_get_type_id(pkey); switch (nid) { case EVP_PKEY_RSA: @@ -1903,10 +2093,49 @@ static OSSL_PARAM *public_params_from_evp_pkey(EVP_PKEY *pkey) break; } #endif /* OPENSSL_NO_ECX */ +#if OPENSSL_VERSION_NUMBER >= 0x30500000L +#ifndef OPENSSL_NO_ML_DSA + case EVP_PKEY_ML_DSA_44: + case EVP_PKEY_ML_DSA_65: + case EVP_PKEY_ML_DSA_87: +#endif +#ifndef OPENSSL_NO_SLH_DSA + case EVP_PKEY_SLH_DSA_SHA2_128S: + case EVP_PKEY_SLH_DSA_SHA2_128F: + case EVP_PKEY_SLH_DSA_SHA2_192S: + case EVP_PKEY_SLH_DSA_SHA2_192F: + case EVP_PKEY_SLH_DSA_SHA2_256S: + case EVP_PKEY_SLH_DSA_SHA2_256F: + case EVP_PKEY_SLH_DSA_SHAKE_128S: + case EVP_PKEY_SLH_DSA_SHAKE_128F: + case EVP_PKEY_SLH_DSA_SHAKE_192S: + case EVP_PKEY_SLH_DSA_SHAKE_192F: + case EVP_PKEY_SLH_DSA_SHAKE_256S: + case EVP_PKEY_SLH_DSA_SHAKE_256F: +#endif + case EVP_PKEY_FALCON512: + case EVP_PKEY_FALCON1024: + { + size_t publen = 0; + + if (EVP_PKEY_get_raw_public_key(pkey, NULL, &publen)) { + pub = OPENSSL_malloc(publen); + if (pub == NULL) + goto err; + + if (!EVP_PKEY_get_raw_public_key(pkey, pub, &publen)) + goto err; + + if (!OSSL_PARAM_BLD_push_octet_string(bld, + OSSL_PKEY_PARAM_PUB_KEY, pub, publen)) + goto err; + } + break; + } +#endif /* OPENSSL_VERSION_NUMBER >= 0x30500000L */ default: goto err; /* unsupported key type */ } - params = OSSL_PARAM_BLD_to_param(bld); err: @@ -1918,11 +2147,11 @@ static OSSL_PARAM *public_params_from_evp_pkey(EVP_PKEY *pkey) } /* Initialize key type and size metadata from stored key parameters. */ -static int p11_keydata_init_from_params(P11_KEYDATA *keydata) +static int p11_keydata_init_from_params(EVP_PKEY *pkey, P11_KEYDATA *keydata) { - const OSSL_PARAM *p; + int type; - if (keydata == NULL || keydata->params == NULL) + if (pkey == NULL || keydata == NULL || keydata->params == NULL) return 0; p11_keydata_clear_pubdata(keydata); @@ -1932,195 +2161,386 @@ static int p11_keydata_init_from_params(P11_KEYDATA *keydata) keydata->keysize = 0; keydata->sigsize = 0; - /* RSA */ - p = OSSL_PARAM_locate_const(keydata->params, OSSL_PKEY_PARAM_RSA_N); - if (p != NULL && p->data_type == OSSL_PARAM_UNSIGNED_INTEGER && - p->data != NULL && p->data_size > 0) { - const OSSL_PARAM *pe; + type = evp_pkey_get_type_id(pkey); - pe = OSSL_PARAM_locate_const(keydata->params, OSSL_PKEY_PARAM_RSA_E); - if (pe == NULL || pe->data_type != OSSL_PARAM_UNSIGNED_INTEGER || - pe->data == NULL || pe->data_size == 0) - return 0; + switch (type) { + case EVP_PKEY_RSA: + case EVP_PKEY_RSA_PSS: + return p11_keydata_init_rsa_from_params(keydata); - if (!p11_dup_param_blob(p, &keydata->pubdata.rsa.n, - &keydata->pubdata.rsa.n_len)) - goto err; +#ifndef OPENSSL_NO_EC + case EVP_PKEY_EC: + return p11_keydata_init_ec_from_params(keydata); +#endif /* OPENSSL_NO_EC */ - if (!p11_dup_param_blob(pe, &keydata->pubdata.rsa.e, - &keydata->pubdata.rsa.e_len)) - goto err; +#ifndef OPENSSL_NO_ECX + case EVP_PKEY_ED25519: + case EVP_PKEY_ED448: + return p11_keydata_init_eddsa_from_params(keydata, type); +#endif /* OPENSSL_NO_ECX */ - keydata->type = EVP_PKEY_RSA; - keydata->name = "RSA"; - keydata->keysize = p->data_size; - keydata->sigsize = p->data_size; /* RSA signature == modulus size */ - return 1; +#if OPENSSL_VERSION_NUMBER >= 0x30500000L +#ifndef OPENSSL_NO_ML_DSA + case EVP_PKEY_ML_DSA_44: + case EVP_PKEY_ML_DSA_65: + case EVP_PKEY_ML_DSA_87: + return p11_keydata_init_mldsa_from_params(keydata, type); +#endif /* OPENSSL_NO_ML_DSA */ + +#ifndef OPENSSL_NO_SLH_DSA + case EVP_PKEY_SLH_DSA_SHA2_128S: + case EVP_PKEY_SLH_DSA_SHA2_128F: + case EVP_PKEY_SLH_DSA_SHAKE_128S: + case EVP_PKEY_SLH_DSA_SHAKE_128F: + case EVP_PKEY_SLH_DSA_SHA2_192S: + case EVP_PKEY_SLH_DSA_SHA2_192F: + case EVP_PKEY_SLH_DSA_SHAKE_192S: + case EVP_PKEY_SLH_DSA_SHAKE_192F: + case EVP_PKEY_SLH_DSA_SHA2_256S: + case EVP_PKEY_SLH_DSA_SHA2_256F: + case EVP_PKEY_SLH_DSA_SHAKE_256S: + case EVP_PKEY_SLH_DSA_SHAKE_256F: + return p11_keydata_init_slhdsa_from_params(keydata, type); +#endif /* OPENSSL_NO_SLH_DSA */ +#endif /* OPENSSL_VERSION_NUMBER >= 0x30500000 */ + case EVP_PKEY_FALCON512: + case EVP_PKEY_FALCON1024: + return p11_keydata_init_falcon_from_params(keydata, type); + + default: + return 0; } +} - p = OSSL_PARAM_locate_const(keydata->params, OSSL_PKEY_PARAM_GROUP_NAME); +static int p11_keydata_init_rsa_from_params(P11_KEYDATA *keydata) +{ + const OSSL_PARAM *p; + const OSSL_PARAM *pe; - /* Ed25519 / Ed448 and classic EC can be identified from GROUP_NAME alone */ - if (p != NULL && p->data_type == OSSL_PARAM_UTF8_STRING) { - const char *group_name = NULL; + p = OSSL_PARAM_locate_const(keydata->params, OSSL_PKEY_PARAM_RSA_N); + if (p == NULL || p->data_type != OSSL_PARAM_UNSIGNED_INTEGER || + p->data == NULL || p->data_size == 0) + return 0; - if (!OSSL_PARAM_get_utf8_string_ptr(p, &group_name) || group_name == NULL) - return 0; + pe = OSSL_PARAM_locate_const(keydata->params, OSSL_PKEY_PARAM_RSA_E); + if (pe == NULL || pe->data_type != OSSL_PARAM_UNSIGNED_INTEGER || + pe->data == NULL || pe->data_size == 0) + return 0; -#ifndef OPENSSL_NO_ECX - if (OPENSSL_strcasecmp(group_name, "ED25519") == 0) { - const OSSL_PARAM *ppub; - - ppub = OSSL_PARAM_locate_const(keydata->params, OSSL_PKEY_PARAM_PUB_KEY); - if (ppub != NULL && ppub->data_type == OSSL_PARAM_OCTET_STRING && - ppub->data != NULL && ppub->data_size == 32) { - if (!p11_dup_param_blob(ppub, &keydata->pubdata.eddsa.pub, - &keydata->pubdata.eddsa.pub_len)) - goto err; - } - keydata->type = EVP_PKEY_ED25519; - keydata->name = "ED25519"; - keydata->keysize = 32; - keydata->sigsize = 64; - return 1; - } + if (!p11_dup_param_blob(p, &keydata->pubdata.rsa.n, + &keydata->pubdata.rsa.n_len)) + return 0; - if (OPENSSL_strcasecmp(group_name, "ED448") == 0) { - const OSSL_PARAM *ppub; + if (!p11_dup_param_blob(pe, &keydata->pubdata.rsa.e, + &keydata->pubdata.rsa.e_len)) + return 0; - ppub = OSSL_PARAM_locate_const(keydata->params, OSSL_PKEY_PARAM_PUB_KEY); - if (ppub != NULL && ppub->data_type == OSSL_PARAM_OCTET_STRING && - ppub->data != NULL && ppub->data_size == 57) { - if (!p11_dup_param_blob(ppub, &keydata->pubdata.eddsa.pub, - &keydata->pubdata.eddsa.pub_len)) - goto err; - } - keydata->type = EVP_PKEY_ED448; - keydata->name = "ED448"; - keydata->keysize = 57; - keydata->sigsize = 114; - return 1; - } -#endif /* OPENSSL_NO_ECX */ + keydata->type = EVP_PKEY_RSA; + keydata->name = "RSA"; + keydata->keysize = p->data_size; + keydata->sigsize = p->data_size; /* RSA signature == modulus size */ + return 1; +} #ifndef OPENSSL_NO_EC - /* classic EC */ - { - const OSSL_PARAM *ppub; - int nid = NID_undef; - EC_GROUP *grp = NULL; - BN_CTX *bnctx = NULL; - BIGNUM *order = NULL; - size_t order_bytes = 0; - - nid = OBJ_sn2nid(group_name); - if (nid == NID_undef) - nid = OBJ_ln2nid(group_name); - if (nid == NID_undef) - return 0; - - grp = EC_GROUP_new_by_curve_name(nid); - bnctx = BN_CTX_new(); - order = BN_new(); - if (grp == NULL || bnctx == NULL || order == NULL) - goto ec_err; +static int p11_keydata_init_ec_from_params(P11_KEYDATA *keydata) +{ + const OSSL_PARAM *p, *ppub; + const char *group_name = NULL; + int nid = NID_undef; + EC_GROUP *grp = NULL; + BN_CTX *bnctx = NULL; + BIGNUM *order = NULL; + size_t order_bytes = 0; - if (EC_GROUP_get_order(grp, order, bnctx) != 1) - goto ec_err; + p = OSSL_PARAM_locate_const(keydata->params, OSSL_PKEY_PARAM_GROUP_NAME); + if (p == NULL || p->data_type != OSSL_PARAM_UTF8_STRING) + return 0; - order_bytes = (size_t)BN_num_bytes(order); - if (order_bytes == 0) - goto ec_err; + if (!OSSL_PARAM_get_utf8_string_ptr(p, &group_name) || + group_name == NULL) + return 0; - if (!p11_dup_param_utf8(p, &keydata->pubdata.ec.group_name)) - goto ec_err; + nid = OBJ_sn2nid(group_name); + if (nid == NID_undef) + nid = OBJ_ln2nid(group_name); + if (nid == NID_undef) + return 0; - ppub = OSSL_PARAM_locate_const(keydata->params, OSSL_PKEY_PARAM_PUB_KEY); - if (ppub != NULL && ppub->data_type == OSSL_PARAM_OCTET_STRING && - ppub->data != NULL && ppub->data_size > 0) { - if (!p11_dup_param_blob(ppub, &keydata->pubdata.ec.pub, - &keydata->pubdata.ec.pub_len)) - goto ec_err; - } - keydata->type = EVP_PKEY_EC; - keydata->name = "EC"; + grp = EC_GROUP_new_by_curve_name(nid); + bnctx = BN_CTX_new(); + order = BN_new(); + if (grp == NULL || bnctx == NULL || order == NULL) + goto err; - /* good approximation for "key size" */ - keydata->keysize = order_bytes; + if (EC_GROUP_get_order(grp, order, bnctx) != 1) + goto err; - /* safe upper bound for DER-encoded ECDSA signatures */ - keydata->sigsize = (2 * (order_bytes + 3)) + - ((2 * (order_bytes + 3) < 128) ? 2 : 3); + order_bytes = (size_t)BN_num_bytes(order); + if (order_bytes == 0) + goto err; - BN_free(order); - BN_CTX_free(bnctx); - EC_GROUP_free(grp); - return 1; + if (!p11_dup_param_utf8(p, &keydata->pubdata.ec.group_name)) + goto err; -ec_err: - BN_free(order); - BN_CTX_free(bnctx); - EC_GROUP_free(grp); + ppub = OSSL_PARAM_locate_const(keydata->params, OSSL_PKEY_PARAM_PUB_KEY); + if (ppub != NULL && + ppub->data_type == OSSL_PARAM_OCTET_STRING && + ppub->data != NULL && + ppub->data_size > 0) { + if (!p11_dup_param_blob(ppub, + &keydata->pubdata.ec.pub, + &keydata->pubdata.ec.pub_len)) goto err; - } -#endif /* OPENSSL_NO_EC */ } - return 0; + + keydata->type = EVP_PKEY_EC; + keydata->name = "EC"; + + /* good approximation for "key size" */ + keydata->keysize = order_bytes; + + /* safe upper bound for DER-encoded ECDSA signatures */ + keydata->sigsize = (2 * (order_bytes + 3)) + + ((2 * (order_bytes + 3) < 128) ? 2 : 3); + + BN_free(order); + BN_CTX_free(bnctx); + EC_GROUP_free(grp); + return 1; err: - p11_keydata_clear_pubdata(keydata); - keydata->type = 0; - keydata->name = NULL; - keydata->keysize = 0; - keydata->sigsize = 0; + BN_free(order); + BN_CTX_free(bnctx); + EC_GROUP_free(grp); return 0; } +#endif /* OPENSSL_NO_EC */ -/* Replace existing parameter set in key object with new OSSL_PARAM array. */ -static int p11_keydata_replace_params(P11_KEYDATA *keydata, OSSL_PARAM *params) +#ifndef OPENSSL_NO_ECX +static int p11_keydata_init_eddsa_from_params(P11_KEYDATA *keydata, int type) { - if (keydata == NULL || params == NULL) + const OSSL_PARAM *p; + size_t keysize = 0; + size_t sigsize = 0; + const char *name = NULL; + + switch (type) { + case EVP_PKEY_ED25519: + name = "ED25519"; + keysize = ED25519_KEYLEN; + sigsize = ED25519_SIGSIZE; + break; + case EVP_PKEY_ED448: + name = "ED448"; + keysize = ED448_KEYLEN; + sigsize = ED448_SIGSIZE; + break; + default: return 0; + } - OSSL_PARAM_free(keydata->params); - keydata->params = params; - keydata->type = algorithm_from_ossl_param(params); - keydata->is_private = params_contains_private_key(params); + p = OSSL_PARAM_locate_const(keydata->params, OSSL_PKEY_PARAM_PUB_KEY); + if (p != NULL && p->data_type == OSSL_PARAM_OCTET_STRING && + p->data != NULL && p->data_size == keysize) { + if (!p11_dup_param_blob(p, &keydata->pubdata.raw.pub, + &keydata->pubdata.raw.pub_len)) + return 0; + } + keydata->type = type; + keydata->name = name; + keydata->keysize = keysize; + keydata->sigsize = sigsize; return 1; } +#endif /* OPENSSL_NO_ECX */ -/* Detect key algorithm type from OSSL_PARAM key attributes. */ -static int algorithm_from_ossl_param(const OSSL_PARAM *params) +#if OPENSSL_VERSION_NUMBER >= 0x30500000L +#ifndef OPENSSL_NO_ML_DSA +static int p11_keydata_init_mldsa_from_params(P11_KEYDATA *keydata, int type) { -#ifndef OPENSSL_NO_ECX const OSSL_PARAM *p; + const char *name = NULL; + size_t keysize = 0; + size_t sigsize = 0; + + switch (type) { + case EVP_PKEY_ML_DSA_44: + name = "ML-DSA-44"; + keysize = ML_DSA_44_PUB_LEN; + sigsize = ML_DSA_44_SIG_LEN; + break; + case EVP_PKEY_ML_DSA_65: + name = "ML-DSA-65"; + keysize = ML_DSA_65_PUB_LEN; + sigsize = ML_DSA_65_SIG_LEN; + break; + case EVP_PKEY_ML_DSA_87: + name = "ML-DSA-87"; + keysize = ML_DSA_87_PUB_LEN; + sigsize = ML_DSA_87_SIG_LEN; + break; + default: + return 0; + } - /* Ed25519 / Ed448 (EdDSA): most reliable is raw key size */ - p = OSSL_PARAM_locate_const(params, OSSL_PKEY_PARAM_PUB_KEY); - if (p != NULL && p->data_type == OSSL_PARAM_OCTET_STRING) { - if (p->data_size == 32) - return EVP_PKEY_ED25519; - if (p->data_size == 57) - return EVP_PKEY_ED448; + p = OSSL_PARAM_locate_const(keydata->params, OSSL_PKEY_PARAM_PUB_KEY); + if (p != NULL && p->data_type == OSSL_PARAM_OCTET_STRING && + p->data != NULL && p->data_size == keysize) { + if (!p11_dup_param_blob(p, &keydata->pubdata.raw.pub, + &keydata->pubdata.raw.pub_len)) + return 0; } -#endif /* OPENSSL_NO_ECX */ - /* RSA */ - if (OSSL_PARAM_locate_const(params, OSSL_PKEY_PARAM_RSA_N) || - OSSL_PARAM_locate_const(params, OSSL_PKEY_PARAM_RSA_E)) { - return EVP_PKEY_RSA; + keydata->type = type; + keydata->name = name; + keydata->keysize = keysize; + keydata->sigsize = sigsize; + return 1; +} +#endif /* OPENSSL_NO_ML_DSA */ + +#ifndef OPENSSL_NO_SLH_DSA +static int p11_keydata_init_slhdsa_from_params(P11_KEYDATA *keydata, int type) +{ + const OSSL_PARAM *p; + const char *name; + size_t keysize = 0; + size_t sigsize = 0; + + switch (type) { + case EVP_PKEY_SLH_DSA_SHA2_128S: + name = "SLH-DSA-SHA2-128S"; + keysize = SLH_DSA_128S_PUB_BYTES; + sigsize = SLH_DSA_128S_SIG_BYTES; + break; + + case EVP_PKEY_SLH_DSA_SHAKE_128S: + name = "SLH-DSA-SHAKE-128S"; + keysize = SLH_DSA_128S_PUB_BYTES; + sigsize = SLH_DSA_128S_SIG_BYTES; + break; + + case EVP_PKEY_SLH_DSA_SHA2_128F: + name = "SLH-DSA-SHA2-128F"; + keysize = SLH_DSA_128F_PUB_BYTES; + sigsize = SLH_DSA_128F_SIG_BYTES; + break; + + case EVP_PKEY_SLH_DSA_SHAKE_128F: + name = "SLH-DSA-SHAKE-128F"; + keysize = SLH_DSA_128F_PUB_BYTES; + sigsize = SLH_DSA_128F_SIG_BYTES; + break; + + case EVP_PKEY_SLH_DSA_SHA2_192S: + name = "SLH-DSA-SHA2-192S"; + keysize = SLH_DSA_192S_PUB_BYTES; + sigsize = SLH_DSA_192S_SIG_BYTES; + break; + + case EVP_PKEY_SLH_DSA_SHAKE_192S: + name = "SLH-DSA-SHAKE-192S"; + keysize = SLH_DSA_192S_PUB_BYTES; + sigsize = SLH_DSA_192S_SIG_BYTES; + break; + + case EVP_PKEY_SLH_DSA_SHA2_192F: + name = "SLH-DSA-SHA2-192F"; + keysize = SLH_DSA_192F_PUB_BYTES; + sigsize = SLH_DSA_192F_SIG_BYTES; + break; + + case EVP_PKEY_SLH_DSA_SHAKE_192F: + name = "SLH-DSA-SHAKE-192F"; + keysize = SLH_DSA_192F_PUB_BYTES; + sigsize = SLH_DSA_192F_SIG_BYTES; + break; + + case EVP_PKEY_SLH_DSA_SHA2_256S: + name = "SLH-DSA-SHA2-256S"; + keysize = SLH_DSA_256S_PUB_BYTES; + sigsize = SLH_DSA_256S_SIG_BYTES; + break; + + case EVP_PKEY_SLH_DSA_SHAKE_256S: + name = "SLH-DSA-SHAKE-256S"; + keysize = SLH_DSA_256S_PUB_BYTES; + sigsize = SLH_DSA_256S_SIG_BYTES; + break; + + case EVP_PKEY_SLH_DSA_SHA2_256F: + name = "SLH-DSA-SHA2-256F"; + keysize = SLH_DSA_256F_PUB_BYTES; + sigsize = SLH_DSA_256F_SIG_BYTES; + break; + + case EVP_PKEY_SLH_DSA_SHAKE_256F: + name = "SLH-DSA-SHAKE-256F"; + keysize = SLH_DSA_256F_PUB_BYTES; + sigsize = SLH_DSA_256F_SIG_BYTES; + break; + + default: + return 0; } -#ifndef OPENSSL_NO_EC - /* EC (classic ECDSA/ECDH) */ - if (OSSL_PARAM_locate_const(params, OSSL_PKEY_PARAM_EC_ENCODING) || - OSSL_PARAM_locate_const(params, OSSL_PKEY_PARAM_EC_POINT_CONVERSION_FORMAT)) { - return EVP_PKEY_EC; + p = OSSL_PARAM_locate_const(keydata->params, OSSL_PKEY_PARAM_PUB_KEY); + if (p != NULL && p->data_type == OSSL_PARAM_OCTET_STRING && + p->data != NULL && p->data_size == keysize) { + if (!p11_dup_param_blob(p, &keydata->pubdata.raw.pub, + &keydata->pubdata.raw.pub_len)) + return 0; } -#endif /* OPENSSL_NO_EC */ - return 0; + keydata->type = type; + keydata->name = name; + keydata->keysize = keysize; + keydata->sigsize = sigsize; + return 1; +} +#endif /* OPENSSL_NO_SLH_DSA */ +#endif /* OPENSSL_VERSION_NUMBER >= 0x30500000L */ + +static int p11_keydata_init_falcon_from_params(P11_KEYDATA *keydata, int type) +{ + const OSSL_PARAM *p; + const char *name = NULL; + size_t keysize = 0; + size_t sigsize = 0; + + switch (type) { + case EVP_PKEY_FALCON512: + name = "FALCON-512"; + keysize = FALCON_512_PUB_LEN; + sigsize = FALCON_512_SIG_LEN; + break; + + case EVP_PKEY_FALCON1024: + name = "FALCON-1024"; + keysize = FALCON_1024_PUB_LEN; + sigsize = FALCON_1024_SIG_LEN; + break; + + default: + return 0; + } + + p = OSSL_PARAM_locate_const(keydata->params, OSSL_PKEY_PARAM_PUB_KEY); + if (p != NULL && p->data_type == OSSL_PARAM_OCTET_STRING && + p->data != NULL && p->data_size == keysize) { + if (!p11_dup_param_blob(p, &keydata->pubdata.raw.pub, + &keydata->pubdata.raw.pub_len)) + return 0; + } + + keydata->type = type; + keydata->name = name; + keydata->keysize = keysize; + keydata->sigsize = sigsize; + + return 1; } /* @@ -2163,17 +2583,6 @@ static int param_blob_equal(const OSSL_PARAM *a, const OSSL_PARAM *b) return CRYPTO_memcmp(a->data, b->data, a->data_size) == 0; } -/* Compare two RSA public keys by matching modulus (n) and public exponent (e). */ -static int rsa_public_match_params(const OSSL_PARAM *p1, const OSSL_PARAM *p2) -{ - const OSSL_PARAM *n1 = OSSL_PARAM_locate_const(p1, OSSL_PKEY_PARAM_RSA_N); - const OSSL_PARAM *e1 = OSSL_PARAM_locate_const(p1, OSSL_PKEY_PARAM_RSA_E); - const OSSL_PARAM *n2 = OSSL_PARAM_locate_const(p2, OSSL_PKEY_PARAM_RSA_N); - const OSSL_PARAM *e2 = OSSL_PARAM_locate_const(p2, OSSL_PKEY_PARAM_RSA_E); - - return (n1 && e1 && n2 && e2 && param_blob_equal(n1, n2) && param_blob_equal(e1, e2)); -} - #ifndef OPENSSL_NO_EC static int p11_dup_param_utf8(const OSSL_PARAM *p, char **out) { @@ -2189,42 +2598,6 @@ static int p11_dup_param_utf8(const OSSL_PARAM *p, char **out) return (*out != NULL); } -/* Match EC public keys by curve name and public point value. */ -static int ec_public_match_params(const OSSL_PARAM *p1, const OSSL_PARAM *p2) -{ - const char *group1 = NULL, *group2 = NULL; - const OSSL_PARAM *g1 = OSSL_PARAM_locate_const(p1, OSSL_PKEY_PARAM_GROUP_NAME); - const OSSL_PARAM *g2 = OSSL_PARAM_locate_const(p2, OSSL_PKEY_PARAM_GROUP_NAME); - const OSSL_PARAM *k1 = OSSL_PARAM_locate_const(p1, OSSL_PKEY_PARAM_PUB_KEY); - const OSSL_PARAM *k2 = OSSL_PARAM_locate_const(p2, OSSL_PKEY_PARAM_PUB_KEY); - - if (g1 == NULL || g2 == NULL || k1 == NULL || k2 == NULL) - return 0; - - /* GROUP_NAME */ - if (g1->data_type != OSSL_PARAM_UTF8_STRING || - g2->data_type != OSSL_PARAM_UTF8_STRING) - return 0; - - if (!OSSL_PARAM_get_utf8_string_ptr(g1, &group1) || - !OSSL_PARAM_get_utf8_string_ptr(g2, &group2) || - group1 == NULL || group2 == NULL) - return 0; - - if (OPENSSL_strcasecmp(group1, group2) != 0) - return 0; - - /* PUB_KEY */ - if (k1->data_type != OSSL_PARAM_OCTET_STRING || - k2->data_type != OSSL_PARAM_OCTET_STRING || - k1->data == NULL || k2->data == NULL) - return 0; - - return ec_point_equal_by_value(group1, - (const unsigned char *)k1->data, k1->data_size, - (const unsigned char *)k2->data, k2->data_size); -} - /* Compare two EC public points by value on the given curve. */ static int ec_point_equal_by_value(const char *group_name, const unsigned char *a, size_t alen, const unsigned char *b, size_t blen) @@ -2266,20 +2639,11 @@ static int ec_point_equal_by_value(const char *group_name, EC_POINT_free(pa); EC_POINT_free(pb); EC_GROUP_free(grp); + return ok; } #endif /* OPENSSL_NO_EC */ -#ifndef OPENSSL_NO_ECX -/* Compare EdDSA public keys by raw public key bytes. */ -static int eddsa_public_match_params(const OSSL_PARAM *p1, const OSSL_PARAM *p2) -{ - const OSSL_PARAM *k1 = OSSL_PARAM_locate_const(p1, OSSL_PKEY_PARAM_PUB_KEY); - const OSSL_PARAM *k2 = OSSL_PARAM_locate_const(p2, OSSL_PKEY_PARAM_PUB_KEY); - - return (k1 && k2 && octet_equal(k1, k2)); -} - /* Compare two OSSL_PARAM octet strings for equality. */ static int octet_equal(const OSSL_PARAM *a, const OSSL_PARAM *b) { @@ -2292,9 +2656,8 @@ static int octet_equal(const OSSL_PARAM *a, const OSSL_PARAM *b) return 0; if (a->data_size != b->data_size) return 0; - return CRYPTO_memcmp(a->data, b->data, a->data_size) == 0; + return CRYPTO_memcmp(a->data, b->data, a->data_size) == 0; } -#endif /* OPENSSL_NO_ECX */ static void p11_keydata_clear_pubdata(P11_KEYDATA *keydata) { @@ -2305,7 +2668,7 @@ static void p11_keydata_clear_pubdata(P11_KEYDATA *keydata) OPENSSL_free(keydata->pubdata.rsa.e); OPENSSL_free(keydata->pubdata.ec.group_name); OPENSSL_free(keydata->pubdata.ec.pub); - OPENSSL_free(keydata->pubdata.eddsa.pub); + OPENSSL_free(keydata->pubdata.raw.pub); memset(&keydata->pubdata, 0, sizeof(keydata->pubdata)); } @@ -2410,4 +2773,85 @@ static int p11_signature_ctx_setup_rsa_verify(P11_SIGNATURE_CTX *sig_ctx, return 1; } +/* + * Return a legacy EVP_PKEY_* type identifier for the given EVP_PKEY. + * + * OpenSSL 3.x deprecates the use of EVP_PKEY_base_id() in favor of + * provider-aware type checks via EVP_PKEY_is_a(). This helper maps an + * EVP_PKEY object to the corresponding EVP_PKEY_* identifier used by + * the existing PKCS#11 code paths and switch statements. + * + * Returns: + * EVP_PKEY_* identifier on success + * EVP_PKEY_NONE if the key type is unknown or unsupported + */ +static int evp_pkey_get_type_id(const EVP_PKEY *pkey) +{ + if (pkey == NULL) + return EVP_PKEY_NONE; + + if (EVP_PKEY_is_a(pkey, "RSA")) + return EVP_PKEY_RSA; + if (EVP_PKEY_is_a(pkey, "RSA-PSS")) + return EVP_PKEY_RSA_PSS; + +#ifndef OPENSSL_NO_EC + if (EVP_PKEY_is_a(pkey, "EC")) + return EVP_PKEY_EC; +#endif /* OPENSSL_NO_EC */ + +#ifndef OPENSSL_NO_ECX + if (EVP_PKEY_is_a(pkey, "ED25519")) + return EVP_PKEY_ED25519; + if (EVP_PKEY_is_a(pkey, "ED448")) + return EVP_PKEY_ED448; +#endif /* OPENSSL_NO_ECX */ + +#if OPENSSL_VERSION_NUMBER >= 0x30500000L +#ifndef OPENSSL_NO_ML_DSA + if (EVP_PKEY_is_a(pkey, "ML-DSA-44")) + return EVP_PKEY_ML_DSA_44; + if (EVP_PKEY_is_a(pkey, "ML-DSA-65")) + return EVP_PKEY_ML_DSA_65; + if (EVP_PKEY_is_a(pkey, "ML-DSA-87")) + return EVP_PKEY_ML_DSA_87; +#endif /* OPENSSL_NO_ML_DSA */ + +#ifndef OPENSSL_NO_SLH_DSA + if (EVP_PKEY_is_a(pkey, "SLH-DSA-SHA2-128s")) + return EVP_PKEY_SLH_DSA_SHA2_128S; + if (EVP_PKEY_is_a(pkey, "SLH-DSA-SHA2-128f")) + return EVP_PKEY_SLH_DSA_SHA2_128F; + if (EVP_PKEY_is_a(pkey, "SLH-DSA-SHA2-192s")) + return EVP_PKEY_SLH_DSA_SHA2_192S; + if (EVP_PKEY_is_a(pkey, "SLH-DSA-SHA2-192f")) + return EVP_PKEY_SLH_DSA_SHA2_192F; + if (EVP_PKEY_is_a(pkey, "SLH-DSA-SHA2-256s")) + return EVP_PKEY_SLH_DSA_SHA2_256S; + if (EVP_PKEY_is_a(pkey, "SLH-DSA-SHA2-256f")) + return EVP_PKEY_SLH_DSA_SHA2_256F; + if (EVP_PKEY_is_a(pkey, "SLH-DSA-SHAKE-128s")) + return EVP_PKEY_SLH_DSA_SHAKE_128S; + if (EVP_PKEY_is_a(pkey, "SLH-DSA-SHAKE-128f")) + return EVP_PKEY_SLH_DSA_SHAKE_128F; + if (EVP_PKEY_is_a(pkey, "SLH-DSA-SHAKE-192s")) + return EVP_PKEY_SLH_DSA_SHAKE_192S; + if (EVP_PKEY_is_a(pkey, "SLH-DSA-SHAKE-192f")) + return EVP_PKEY_SLH_DSA_SHAKE_192F; + if (EVP_PKEY_is_a(pkey, "SLH-DSA-SHAKE-256s")) + return EVP_PKEY_SLH_DSA_SHAKE_256S; + if (EVP_PKEY_is_a(pkey, "SLH-DSA-SHAKE-256f")) + return EVP_PKEY_SLH_DSA_SHAKE_256F; +#endif /* OPENSSL_NO_SLH_DSA */ + + if (EVP_PKEY_is_a(pkey, "FALCON512")) + return EVP_PKEY_FALCON512; + + if (EVP_PKEY_is_a(pkey, "FALCON1024")) + return EVP_PKEY_FALCON1024; +#endif /* OPENSSL_VERSION_NUMBER >= 0x30500000L */ + + return EVP_PKEY_NONE; +} + /* vim: set noexpandtab: */ diff --git a/src/provider_helpers.h b/src/provider_helpers.h index 1857cee6..378d2ede 100644 --- a/src/provider_helpers.h +++ b/src/provider_helpers.h @@ -27,6 +27,7 @@ #define _PROVIDER_HELPERS_H #include "util.h" +#include "libp11-int.h" #include #include #include @@ -95,7 +96,7 @@ int p11_public_equal(const P11_KEYDATA *k1, const P11_KEYDATA *k2); int pad_mode_from_param(const OSSL_PARAM *p, int *pad_mode); int export_rsa_pub(P11_KEYDATA *keydata, OSSL_CALLBACK *param_cb, void *cbarg); int export_ec_pub(P11_KEYDATA *keydata, OSSL_CALLBACK *param_cb, void *cbarg); -int export_eddsa_pub(P11_KEYDATA *keydata, OSSL_CALLBACK *param_cb, void *cbarg); +int export_raw_pub(P11_KEYDATA *keydata, OSSL_CALLBACK *param_cb, void *cbarg); /******************************************************************************/ /* SIGNATURE helper functions */ @@ -134,6 +135,7 @@ const char *p11_signature_ctx_get_mgf1_mdname(const P11_SIGNATURE_CTX *sig_ctx); EVP_MD_CTX *p11_signature_ctx_get_mdctx(P11_SIGNATURE_CTX *sig_ctx); const char *p11_signature_pss_saltlen_to_string(int saltlen); const char *p11_pad_mode_to_string(int pad_mode); +int is_oneshot_sig_type(int type); /******************************************************************************/ From ca800fb35df43f9ef1f4e25727fec5565f36e204 Mon Sep 17 00:00:00 2001 From: olszomal Date: Tue, 16 Jun 2026 12:03:18 +0200 Subject: [PATCH 08/14] Add PQC key generation examples Add example programs for generating ML-DSA-87, SLH-DSA-256s, and FALCON-512 key pairs on PKCS#11 tokens. --- .gitignore | 3 + examples/Makefile.am | 5 +- examples/falcon512keygen.c | 205 ++++++++++++++++++++++++++++++++++++ examples/mldsa87keygen.c | 191 +++++++++++++++++++++++++++++++++ examples/slhdsa256skeygen.c | 191 +++++++++++++++++++++++++++++++++ 5 files changed, 594 insertions(+), 1 deletion(-) create mode 100644 examples/falcon512keygen.c create mode 100644 examples/mldsa87keygen.c create mode 100644 examples/slhdsa256skeygen.c diff --git a/.gitignore b/.gitignore index a9eb838e..b2355ae7 100644 --- a/.gitignore +++ b/.gitignore @@ -66,6 +66,9 @@ examples/eckeygen examples/rsakeygen examples/ed25519keygen examples/ed448keygen +examples/falcon512keygen +examples/mldsa87keygen +examples/slhdsa256skeygen examples/storecert test-driver diff --git a/examples/Makefile.am b/examples/Makefile.am index a3a15365..35d227bd 100644 --- a/examples/Makefile.am +++ b/examples/Makefile.am @@ -4,7 +4,10 @@ AM_CPPFLAGS = -I$(srcdir) -I$(top_srcdir)/src \ EXTRA_DIST = README -noinst_PROGRAMS = auth decrypt getrandom listkeys listkeys_ext ed25519keygen ed448keygen eckeygen rsakeygen storecert +noinst_PROGRAMS = auth decrypt getrandom listkeys listkeys_ext \ + ed25519keygen ed448keygen eckeygen rsakeygen \ + mldsa87keygen slhdsa256skeygen falcon512keygen \ + storecert LDADD = ../src/libp11.la $(OPENSSL_LIBS) diff --git a/examples/falcon512keygen.c b/examples/falcon512keygen.c new file mode 100644 index 00000000..85e500b8 --- /dev/null +++ b/examples/falcon512keygen.c @@ -0,0 +1,205 @@ +/* + * Copyright © 2026 Mobi - Com Polska Sp. z o.o. + * Author: Małgorzata Olszówka + * All rights reserved. + * + * PQC FALCON 512 key generation + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include +#include + +#if OPENSSL_VERSION_NUMBER >= 0x30500000L + +#define EVP_PKEY_FALCON512 0x10001 + +#define CHECK_ERR(cond, txt, code) \ + do { \ + if (cond) { \ + fprintf(stderr, "%s\n", (txt)); \ + rc=(code); \ + goto end; \ + } \ + } while (0) + +static void error_queue(const char *name) +{ + if (ERR_peek_last_error()) { + fprintf(stderr, "%s generated errors:\n", name); + ERR_print_errors_fp(stderr); + } +} + +static int hex_to_bytes(const char *hex, unsigned char *out, size_t out_len) +{ + size_t i; + + for (i = 0; i < out_len; i++) { + if (sscanf(hex + (i * 2), "%2hhx", &out[i]) != 1) { + return -1; + } + } + return 0; +} + +static void list_keys(const char *title, const PKCS11_KEY *keys, + const unsigned int nkeys) { + unsigned int i; + + printf("\n%s:\n", title); + for (i = 0; i < nkeys; i++) { + printf(" #%d id=", i); + for (size_t j = 0; j < keys[i].id_len; j++) { + printf("%02x", keys[i].id[j]); + } + printf(";object=%s\n", keys[i].label); + } +} + +static int register_falcon512_oid(void) +{ + int nid; + + nid = OBJ_txt2nid("1.3.9999.3.11"); + if (nid != NID_undef) + return nid; + + return OBJ_create("1.3.9999.3.11", "FALCON512", "Falcon-512"); +} + +int main(int argc, char *argv[]) +{ + PKCS11_CTX *ctx = NULL; + PKCS11_SLOT *slots = NULL, *slot; + PKCS11_KEY *keys; + unsigned int nslots, nkeys; + unsigned char *key_id = NULL; + size_t len, key_id_len; + const char *key_id_str; + int rc = 0; + int falcon512_nid = register_falcon512_oid(); + PKCS11_NID_KGEN falcon = { .nid = falcon512_nid }; + PKCS11_params params = {.sensitive = 1, .extractable = 0}; + PKCS11_KGEN_ATTRS mlkg = {0}; + + if (argc < 5) { + fprintf(stderr, "usage: %s [module] [TOKEN] [KEY-LABEL] [KEY-ID] [PIN]\n", argv[0]); + return 1; + } + key_id_str = argv[4]; + len = strlen(key_id_str); + CHECK_ERR(len % 2 != 0, "Invalid key ID format: odd length", 1); + + /* key_id_str is a null-terminated string, but key_id is not */ + key_id_len = len / 2; + key_id = OPENSSL_malloc(key_id_len); + CHECK_ERR(!key_id, "Memory allocation failed for key ID", 2); + + rc = hex_to_bytes(key_id_str, key_id, key_id_len); + CHECK_ERR(rc != 0, "Invalid hex digit in key ID", 3); + + ctx = PKCS11_CTX_new(); + error_queue("PKCS11_CTX_new"); + + /* load PKCS#11 module */ + rc = PKCS11_CTX_load(ctx, argv[1]); + error_queue("PKCS11_CTX_load"); + CHECK_ERR(rc < 0, "loading PKCS#11 module failed", 4); + + /* get information on all slots */ + rc = PKCS11_enumerate_slots(ctx, &slots, &nslots); + error_queue("PKCS11_enumerate_slots"); + CHECK_ERR(rc < 0, "no slots available", 5); + + slot = PKCS11_find_token(ctx, slots, nslots); + error_queue("PKCS11_find_token"); + while (slot) { + if (slot->token && slot->token->initialized && slot->token->label + && strcmp(argv[2], slot->token->label) == 0) + break; + slot = PKCS11_find_next_token(ctx, slots, nslots, slot); + }; + CHECK_ERR(!slot || !slot->token, "no token available", 6); + + printf("Found token:\n"); + printf("Slot manufacturer......: %s\n", slot->manufacturer); + printf("Slot description.......: %s\n", slot->description); + printf("Slot token label.......: %s\n", slot->token->label); + printf("Slot token serialnr....: %s\n", slot->token->serialnr); + + rc = PKCS11_login(slot, 0, argv[5]); + error_queue("PKCS11_login"); + CHECK_ERR(rc < 0, "PKCS11_login failed", 7); + + mlkg.type = EVP_PKEY_FALCON512; + mlkg.kgen.nid = &falcon; + mlkg.token_label = argv[2]; + mlkg.key_label = argv[3]; + /* key_id is a raw binary buffer of length key_id_len */ + mlkg.key_id = (const unsigned char *)key_id; + mlkg.id_len = key_id_len; + mlkg.key_params = ¶ms; + + rc = PKCS11_keygen(slot->token, &mlkg); + error_queue("PKCS11_keygen"); + CHECK_ERR(rc < 0, "Failed to generate a key pair on the token", 8); + + printf("\nFalcon-512 keys generated\n"); + + /* get private keys */ + rc = PKCS11_enumerate_keys(slot->token, &keys, &nkeys); + error_queue("PKCS11_enumerate_keys"); + CHECK_ERR(rc < 0, "PKCS11_enumerate_keys failed", 9); + CHECK_ERR(nkeys == 0, "No private keys found", 10); + list_keys("Private keys", keys, nkeys); + +end: + if (slots) + PKCS11_release_all_slots(ctx, slots, nslots); + if (ctx) { + PKCS11_CTX_unload(ctx); + PKCS11_CTX_free(ctx); + } + OPENSSL_free(key_id); + + if (rc) + printf("Failed (error code %d).\n", rc); + else + printf("Success.\n"); + return rc; +} + +#else /* OPENSSL_VERSION_NUMBER >= 0x30500000L */ + +#include + +int main(void) +{ + fprintf(stderr, "Skipped: requires OpenSSL 3.5 built\n"); + return 77; +} + +#endif /* OPENSSL_VERSION_NUMBER >= 0x30500000L */ + +/* vim: set noexpandtab: */ diff --git a/examples/mldsa87keygen.c b/examples/mldsa87keygen.c new file mode 100644 index 00000000..f49a851b --- /dev/null +++ b/examples/mldsa87keygen.c @@ -0,0 +1,191 @@ +/* + * Copyright © 2026 Mobi - Com Polska Sp. z o.o. + * Author: Małgorzata Olszówka + * All rights reserved. + * + * ML-DSA-87 key generation + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include +#include + +#if !defined(OPENSSL_NO_ML_DSA) && OPENSSL_VERSION_NUMBER >= 0x30500000L + +#define CHECK_ERR(cond, txt, code) \ + do { \ + if (cond) { \ + fprintf(stderr, "%s\n", (txt)); \ + rc=(code); \ + goto end; \ + } \ + } while (0) + +static void error_queue(const char *name) +{ + if (ERR_peek_last_error()) { + fprintf(stderr, "%s generated errors:\n", name); + ERR_print_errors_fp(stderr); + } +} + +static int hex_to_bytes(const char *hex, unsigned char *out, size_t out_len) +{ + size_t i; + + for (i = 0; i < out_len; i++) { + if (sscanf(hex + (i * 2), "%2hhx", &out[i]) != 1) { + return -1; + } + } + return 0; +} + +static void list_keys(const char *title, const PKCS11_KEY *keys, + const unsigned int nkeys) { + unsigned int i; + + printf("\n%s:\n", title); + for (i = 0; i < nkeys; i++) { + printf(" #%d id=", i); + for (size_t j = 0; j < keys[i].id_len; j++) { + printf("%02x", keys[i].id[j]); + } + printf(";object=%s\n", keys[i].label); + } +} + +int main(int argc, char *argv[]) +{ + PKCS11_CTX *ctx = NULL; + PKCS11_SLOT *slots = NULL, *slot; + PKCS11_KEY *keys; + unsigned int nslots, nkeys; + unsigned char *key_id = NULL; + size_t len, key_id_len; + const char *key_id_str; + int rc = 0; + PKCS11_params params = {.sensitive = 1, .extractable = 0}; + PKCS11_NID_KGEN mldsa = {.nid = NID_ML_DSA_87}; + PKCS11_KGEN_ATTRS mlkg = {0}; + + if (argc < 5) { + fprintf(stderr, "usage: %s [module] [TOKEN] [KEY-LABEL] [KEY-ID] [PIN]\n", argv[0]); + return 1; + } + key_id_str = argv[4]; + len = strlen(key_id_str); + CHECK_ERR(len % 2 != 0, "Invalid key ID format: odd length", 1); + + /* key_id_str is a null-terminated string, but key_id is not */ + key_id_len = len / 2; + key_id = OPENSSL_malloc(key_id_len); + CHECK_ERR(!key_id, "Memory allocation failed for key ID", 2); + + rc = hex_to_bytes(key_id_str, key_id, key_id_len); + CHECK_ERR(rc != 0, "Invalid hex digit in key ID", 3); + + ctx = PKCS11_CTX_new(); + error_queue("PKCS11_CTX_new"); + + /* load PKCS#11 module */ + rc = PKCS11_CTX_load(ctx, argv[1]); + error_queue("PKCS11_CTX_load"); + CHECK_ERR(rc < 0, "loading PKCS#11 module failed", 4); + + /* get information on all slots */ + rc = PKCS11_enumerate_slots(ctx, &slots, &nslots); + error_queue("PKCS11_enumerate_slots"); + CHECK_ERR(rc < 0, "no slots available", 5); + + slot = PKCS11_find_token(ctx, slots, nslots); + error_queue("PKCS11_find_token"); + while (slot) { + if (slot->token && slot->token->initialized && slot->token->label + && strcmp(argv[2], slot->token->label) == 0) + break; + slot = PKCS11_find_next_token(ctx, slots, nslots, slot); + }; + CHECK_ERR(!slot || !slot->token, "no token available", 6); + + printf("Found token:\n"); + printf("Slot manufacturer......: %s\n", slot->manufacturer); + printf("Slot description.......: %s\n", slot->description); + printf("Slot token label.......: %s\n", slot->token->label); + printf("Slot token serialnr....: %s\n", slot->token->serialnr); + + rc = PKCS11_login(slot, 0, argv[5]); + error_queue("PKCS11_login"); + CHECK_ERR(rc < 0, "PKCS11_login failed", 7); + + mlkg.type = EVP_PKEY_ML_DSA_87; + mlkg.kgen.nid = &mldsa; + mlkg.token_label = argv[2]; + mlkg.key_label = argv[3]; + /* key_id is a raw binary buffer of length key_id_len */ + mlkg.key_id = (const unsigned char *)key_id; + mlkg.id_len = key_id_len; + mlkg.key_params = ¶ms; + + rc = PKCS11_keygen(slot->token, &mlkg); + error_queue("PKCS11_keygen"); + CHECK_ERR(rc < 0, "Failed to generate a key pair on the token", 8); + + printf("\nML-DSA-87 keys generated\n"); + + /* get private keys */ + rc = PKCS11_enumerate_keys(slot->token, &keys, &nkeys); + error_queue("PKCS11_enumerate_keys"); + CHECK_ERR(rc < 0, "PKCS11_enumerate_keys failed", 9); + CHECK_ERR(nkeys == 0, "No private keys found", 10); + list_keys("Private keys", keys, nkeys); + +end: + if (slots) + PKCS11_release_all_slots(ctx, slots, nslots); + if (ctx) { + PKCS11_CTX_unload(ctx); + PKCS11_CTX_free(ctx); + } + OPENSSL_free(key_id); + + if (rc) + printf("Failed (error code %d).\n", rc); + else + printf("Success.\n"); + return rc; +} + +#else /* !defined(OPENSSL_NO_ML_DSA) && OPENSSL_VERSION_NUMBER >= 0x30500000L */ + +#include + +int main(void) +{ + fprintf(stderr, "Skipped: requires OpenSSL 3.5 built with ML-DSA support\n"); + return 77; +} + +#endif /* !defined(OPENSSL_NO_ML_DSA) && OPENSSL_VERSION_NUMBER >= 0x30500000L */ + +/* vim: set noexpandtab: */ diff --git a/examples/slhdsa256skeygen.c b/examples/slhdsa256skeygen.c new file mode 100644 index 00000000..7355f0f4 --- /dev/null +++ b/examples/slhdsa256skeygen.c @@ -0,0 +1,191 @@ +/* + * Copyright © 2026 Mobi - Com Polska Sp. z o.o. + * Author: Małgorzata Olszówka + * All rights reserved. + * + * SLH-DSA-128s key generation + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include +#include + +#if !defined(OPENSSL_NO_SLH_DSA) && OPENSSL_VERSION_NUMBER >= 0x30500000L + +#define CHECK_ERR(cond, txt, code) \ + do { \ + if (cond) { \ + fprintf(stderr, "%s\n", (txt)); \ + rc=(code); \ + goto end; \ + } \ + } while (0) + +static void error_queue(const char *name) +{ + if (ERR_peek_last_error()) { + fprintf(stderr, "%s generated errors:\n", name); + ERR_print_errors_fp(stderr); + } +} + +static int hex_to_bytes(const char *hex, unsigned char *out, size_t out_len) +{ + size_t i; + + for (i = 0; i < out_len; i++) { + if (sscanf(hex + (i * 2), "%2hhx", &out[i]) != 1) { + return -1; + } + } + return 0; +} + +static void list_keys(const char *title, const PKCS11_KEY *keys, + const unsigned int nkeys) { + unsigned int i; + + printf("\n%s:\n", title); + for (i = 0; i < nkeys; i++) { + printf(" #%d id=", i); + for (size_t j = 0; j < keys[i].id_len; j++) { + printf("%02x", keys[i].id[j]); + } + printf(";object=%s\n", keys[i].label); + } +} + +int main(int argc, char *argv[]) +{ + PKCS11_CTX *ctx = NULL; + PKCS11_SLOT *slots = NULL, *slot; + PKCS11_KEY *keys; + unsigned int nslots, nkeys; + unsigned char *key_id = NULL; + size_t len, key_id_len; + const char *key_id_str; + int rc = 0; + PKCS11_params params = {.sensitive = 1, .extractable = 0}; + PKCS11_NID_KGEN slhdsa = {.nid = NID_SLH_DSA_SHA2_256s}; + PKCS11_KGEN_ATTRS mlkg = {0}; + + if (argc < 5) { + fprintf(stderr, "usage: %s [module] [TOKEN] [KEY-LABEL] [KEY-ID] [PIN]\n", argv[0]); + return 1; + } + key_id_str = argv[4]; + len = strlen(key_id_str); + CHECK_ERR(len % 2 != 0, "Invalid key ID format: odd length", 1); + + /* key_id_str is a null-terminated string, but key_id is not */ + key_id_len = len / 2; + key_id = OPENSSL_malloc(key_id_len); + CHECK_ERR(!key_id, "Memory allocation failed for key ID", 2); + + rc = hex_to_bytes(key_id_str, key_id, key_id_len); + CHECK_ERR(rc != 0, "Invalid hex digit in key ID", 3); + + ctx = PKCS11_CTX_new(); + error_queue("PKCS11_CTX_new"); + + /* load PKCS#11 module */ + rc = PKCS11_CTX_load(ctx, argv[1]); + error_queue("PKCS11_CTX_load"); + CHECK_ERR(rc < 0, "loading PKCS#11 module failed", 4); + + /* get information on all slots */ + rc = PKCS11_enumerate_slots(ctx, &slots, &nslots); + error_queue("PKCS11_enumerate_slots"); + CHECK_ERR(rc < 0, "no slots available", 5); + + slot = PKCS11_find_token(ctx, slots, nslots); + error_queue("PKCS11_find_token"); + while (slot) { + if (slot->token && slot->token->initialized && slot->token->label + && strcmp(argv[2], slot->token->label) == 0) + break; + slot = PKCS11_find_next_token(ctx, slots, nslots, slot); + }; + CHECK_ERR(!slot || !slot->token, "no token available", 6); + + printf("Found token:\n"); + printf("Slot manufacturer......: %s\n", slot->manufacturer); + printf("Slot description.......: %s\n", slot->description); + printf("Slot token label.......: %s\n", slot->token->label); + printf("Slot token serialnr....: %s\n", slot->token->serialnr); + + rc = PKCS11_login(slot, 0, argv[5]); + error_queue("PKCS11_login"); + CHECK_ERR(rc < 0, "PKCS11_login failed", 7); + + mlkg.type = EVP_PKEY_SLH_DSA_SHA2_256S; + mlkg.kgen.nid = &slhdsa; + mlkg.token_label = argv[2]; + mlkg.key_label = argv[3]; + /* key_id is a raw binary buffer of length key_id_len */ + mlkg.key_id = (const unsigned char *)key_id; + mlkg.id_len = key_id_len; + mlkg.key_params = ¶ms; + + rc = PKCS11_keygen(slot->token, &mlkg); + error_queue("PKCS11_keygen"); + CHECK_ERR(rc < 0, "Failed to generate a key pair on the token", 8); + + printf("\nSLH-DSA-256s keys generated\n"); + + /* get private keys */ + rc = PKCS11_enumerate_keys(slot->token, &keys, &nkeys); + error_queue("PKCS11_enumerate_keys"); + CHECK_ERR(rc < 0, "PKCS11_enumerate_keys failed", 9); + CHECK_ERR(nkeys == 0, "No private keys found", 10); + list_keys("Private keys", keys, nkeys); + +end: + if (slots) + PKCS11_release_all_slots(ctx, slots, nslots); + if (ctx) { + PKCS11_CTX_unload(ctx); + PKCS11_CTX_free(ctx); + } + OPENSSL_free(key_id); + + if (rc) + printf("Failed (error code %d).\n", rc); + else + printf("Success.\n"); + return rc; +} + +#else /* !defined(OPENSSL_NO_SLH_DSA) && OPENSSL_VERSION_NUMBER >= 0x30500000L */ + +#include + +int main(void) +{ + fprintf(stderr, "Skipped: requires OpenSSL 3.5 built with SLH-DSA support\n"); + return 77; +} + +#endif /* !defined(OPENSSL_NO_SLH_DSA) && OPENSSL_VERSION_NUMBER >= 0x30500000L */ + +/* vim: set noexpandtab: */ From 292ce125cbc73c1bb5bd3c85bc8c076755d00713 Mon Sep 17 00:00:00 2001 From: olszomal Date: Tue, 16 Jun 2026 14:14:03 +0200 Subject: [PATCH 09/14] tests: Add ML-DSA provider tests and one-shot helpers --- .gitignore | 1 + tests/Makefile.am | 21 ++- tests/dup-key-prov.c | 1 + tests/ed25519-keygen-prov.c | 2 +- tests/ed25519-keygen.c | 2 +- tests/ed448-keygen-prov.c | 2 +- tests/ed448-keygen.c | 2 +- tests/mldsa87-cert.der | Bin 0 -> 7502 bytes tests/mldsa87-keygen-prov.c | 176 ++++++++++++++++++ tests/mldsa87-privkey.der | Bin 0 -> 4962 bytes tests/mldsa87-pubkey.der | Bin 0 -> 2614 bytes tests/{eddsa_common.c => oneshot_common.c} | 43 +++-- tests/{eddsa_common.h => oneshot_common.h} | 2 +- tests/provider-ec-copy.softhsm | 3 + tests/provider-ed25519-copy.softhsm | 59 ++++++ tests/provider-mldsa87-check-privkey.softhsm | 81 ++++++++ tests/provider-mldsa87-copy.softhsm | 64 +++++++ tests/provider-mldsa87-keygen.softhsm | 68 +++++++ .../provider-pkcs11-uri-without-token.softhsm | 24 +-- 19 files changed, 513 insertions(+), 38 deletions(-) create mode 100644 tests/mldsa87-cert.der create mode 100644 tests/mldsa87-keygen-prov.c create mode 100644 tests/mldsa87-privkey.der create mode 100644 tests/mldsa87-pubkey.der rename tests/{eddsa_common.c => oneshot_common.c} (75%) rename tests/{eddsa_common.h => oneshot_common.h} (97%) create mode 100755 tests/provider-ed25519-copy.softhsm create mode 100755 tests/provider-mldsa87-check-privkey.softhsm create mode 100755 tests/provider-mldsa87-copy.softhsm create mode 100755 tests/provider-mldsa87-keygen.softhsm diff --git a/.gitignore b/.gitignore index b2355ae7..4ff7122e 100644 --- a/.gitignore +++ b/.gitignore @@ -93,6 +93,7 @@ tests/ed25519-keygen tests/ed448-keygen tests/ed25519-keygen-prov tests/ed448-keygen-prov +tests/mldsa87-keygen-prov tests/check-all-prov tests/*.log diff --git a/tests/Makefile.am b/tests/Makefile.am index 208309c4..7ec87474 100644 --- a/tests/Makefile.am +++ b/tests/Makefile.am @@ -1,4 +1,4 @@ -EXTRA_DIST = engines.cnf.in common.sh openssl-settings.sh helpers_prov.h eddsa_common.h +EXTRA_DIST = engines.cnf.in common.sh openssl-settings.sh helpers_prov.h oneshot_common.h AM_CFLAGS = $(OPENSSL_CFLAGS) AM_CPPFLAGS = \ @@ -31,7 +31,8 @@ check_PROGRAMS = \ ed25519-keygen \ ed448-keygen \ ed25519-keygen-prov \ - ed448-keygen-prov + ed448-keygen-prov \ + mldsa87-keygen-prov dist_check_SCRIPTS = \ rsa-testpkcs11.softhsm \ rsa-testfork.softhsm \ @@ -69,6 +70,10 @@ dist_check_SCRIPTS = \ provider-ed448-check-privkey.softhsm \ provider-ed25519-keygen.softhsm \ provider-ed448-keygen.softhsm \ + provider-ed25519-copy.softhsm \ + provider-mldsa87-check-privkey.softhsm \ + provider-mldsa87-keygen.softhsm \ + provider-mldsa87-copy.softhsm \ provider-fork-change-slot.softhsm \ provider-case-insensitive.softhsm \ provider-pkcs11-uri-without-token.softhsm \ @@ -77,12 +82,14 @@ dist_check_DATA = \ rsa-cert.der rsa-privkey.der rsa-pubkey.der \ ec-cert.der ec-privkey.der ec-pubkey.der \ ed25519-cert.der ed25519-privkey.der ed25519-pubkey.der \ - ed448-cert.der ed448-privkey.der ed448-pubkey.der + ed448-cert.der ed448-privkey.der ed448-pubkey.der \ + mldsa87-cert.der mldsa87-privkey.der mldsa87-pubkey.der -ed25519_keygen_SOURCES = ed25519-keygen.c eddsa_common.c -ed448_keygen_SOURCES = ed448-keygen.c eddsa_common.c -ed25519_keygen_prov_SOURCES = ed25519-keygen-prov.c helpers_prov.c eddsa_common.c -ed448_keygen_prov_SOURCES = ed448-keygen-prov.c helpers_prov.c eddsa_common.c +ed25519_keygen_SOURCES = ed25519-keygen.c oneshot_common.c +ed448_keygen_SOURCES = ed448-keygen.c oneshot_common.c +ed25519_keygen_prov_SOURCES = ed25519-keygen-prov.c helpers_prov.c oneshot_common.c +ed448_keygen_prov_SOURCES = ed448-keygen-prov.c helpers_prov.c oneshot_common.c +mldsa87_keygen_prov_SOURCES = mldsa87-keygen-prov.c helpers_prov.c oneshot_common.c evp_sign_prov_SOURCES = evp-sign-prov.c helpers_prov.c fork_change_slot_prov_SOURCES = fork-change-slot-prov.c helpers_prov.c dup_key_prov_SOURCES = dup-key-prov.c helpers_prov.c diff --git a/tests/dup-key-prov.c b/tests/dup-key-prov.c index 3055a9cf..7e8cc715 100644 --- a/tests/dup-key-prov.c +++ b/tests/dup-key-prov.c @@ -53,6 +53,7 @@ int main(int argc, char *argv[]) if (!private_key) { fprintf(stderr, "Cannot load private key: %s\n", argv[1]); display_openssl_errors(); + ret = 77; /* skipped */ goto cleanup; } printf("Private key found.\n"); diff --git a/tests/ed25519-keygen-prov.c b/tests/ed25519-keygen-prov.c index 20d12ace..4ca0da60 100644 --- a/tests/ed25519-keygen-prov.c +++ b/tests/ed25519-keygen-prov.c @@ -18,7 +18,7 @@ */ #include "helpers_prov.h" -#include "eddsa_common.h" +#include "oneshot_common.h" #if !defined(OPENSSL_NO_ECX) && (OPENSSL_VERSION_NUMBER >= 0x30000000L) diff --git a/tests/ed25519-keygen.c b/tests/ed25519-keygen.c index 76cddbb3..3819e021 100644 --- a/tests/ed25519-keygen.c +++ b/tests/ed25519-keygen.c @@ -20,7 +20,7 @@ #define OPENSSL_SUPPRESS_DEPRECATED #include -#include "eddsa_common.h" +#include "oneshot_common.h" #if !defined(OPENSSL_NO_ENGINE) && \ !defined(OPENSSL_NO_ECX) && \ diff --git a/tests/ed448-keygen-prov.c b/tests/ed448-keygen-prov.c index bd26d3f4..5940239a 100644 --- a/tests/ed448-keygen-prov.c +++ b/tests/ed448-keygen-prov.c @@ -18,7 +18,7 @@ */ #include "helpers_prov.h" -#include "eddsa_common.h" +#include "oneshot_common.h" #if !defined(OPENSSL_NO_ECX) && (OPENSSL_VERSION_NUMBER >= 0x30000000L) diff --git a/tests/ed448-keygen.c b/tests/ed448-keygen.c index 44ea94ce..30ab3f98 100644 --- a/tests/ed448-keygen.c +++ b/tests/ed448-keygen.c @@ -20,7 +20,7 @@ #define OPENSSL_SUPPRESS_DEPRECATED #include -#include "eddsa_common.h" +#include "oneshot_common.h" #if !defined(OPENSSL_NO_ENGINE) && \ !defined(OPENSSL_NO_ECX) && \ diff --git a/tests/mldsa87-cert.der b/tests/mldsa87-cert.der new file mode 100644 index 0000000000000000000000000000000000000000..86cb98f0136dbba8df3d5bb58867b9532e84d6f4 GIT binary patch literal 7502 zcma);RZtuNx1^E5-C+ps?h@QXaEHMqxWnM?POt%j1=nG4cMTrgf(0kILxSvo_hGAc zYj4%2LyF0jHwVVVGAW zP$M5;9;)Jrflss^iek*Dm0%R(uv4P|NChf;Q^8+}9MT&VwrRyDSc@_3FqjOeJvvXA zD?m_KKGIkTZN>uUzak#?6cJBujaec?OJhNajgqvZsu1U@ zYZ)4AXP#8--nU>49zA9mC6-(Zo5q5=qe**~9OOFDFMpR!(3FNs0FPj7{{7=Rry?RM3nRC;jbxj1M_t2H6iK*>Ryl z(}rVfk`av)*_$+Nw1XNG2HS3=6o4eOBBUL$pf3;!65^|VFZGE2bHXODpY^7OlcA4*)Hwsn6whzaadq>}3Dfb3WJ z@Sa!4imhS`#9~>yYy<;sL;i^sb?TddIj<_n89#H1_By+e>fQVtV&+kN^PH#Q_P+~6 zeZV_B`8~O+Cz5TR!ZcxDUAF-{@kLCwdsYOH2JuP;3>>IXD>iYYPzb_NAq$xrOk_Ie zc7GZSgykEmPAe*^@r4i5T5w#U#0#)CVeUoPBecZ>^O`6Kbfe0g-s6Q|fFVq>#h*y# z8cr}~txC7_v$RmsB}|1x*wveoA!0w0YDYwr})?9?Ggt!u0qIkD-tm=NQfu*&aHX6o%6>1li zr9ev;D^w%>b1kRYM`sptMiklw0$5*aSHy>xnT!63jqxdj%u?N6K-v>PnMm~JLlcUI zp1dU>^v^d1vo_66Z2^Cwh?D*ul1`oJFCpQ)S|JASmaV)L#!>RF_#Qo(x4+L@!=iAY zieFC5up#MM$hl{Mdom>EjuTNOCbGqcAa2=RFh1u;oCO&qPGoQ8H&CO5LxMX1O$<+%-H^bj znhZ9p7UL&3zad zQQdxUmU!h$0<*9xRC})jZrT0M3J_<`N;O3UE2Y0{-^NvN%Hbxk8q(Z5jf(){Ds=ck z`iLG!Vuk)vfWIK*3T+Y9=%F#iQm7Ww$&l&vCsfq5-xl%(#3;2_HbsMN;flR%=Ub@qkeu` zZWJLO`G@jFLyXp-MOgNODN5#f;RvfvOF}aKmtml_ z)>2ophjoOQkq~7vNbhi9{Hmz&qwkr|YM_Tkpi%8%Xu)?scV=EV*CvHRgsN^jo!CIed2C>dllJf)VLgxuZR9Q z_~C@QZ_8SZY@$t@1jn`So6jc98lee5N#Ylf4a1@-h}ppgo81Am(Bj(j%h0|jslrBy z%O{uwYX5q2+?2CdsvWbfnGln#S7DbayN)o}Oon8H%^Yc`M{m00< zDZ)NRr!S^0hJhZi+s}UTk53{M$4bXEWL?fdRut)1NM6aVCozZ21!F8|8YVTY0ejrr)C`rZ(kwC<5W3L6Ik5H*fsFcu;!}l@P%as-!9!^Iqc= zzZGs1u}x~)5c!whPdhEl)QE1}kZ$~17_kAFzkp|_g8f>KHZ#=nLVe|qo2fXGsBMtW z2Wj_ybmhZZAhmZ)ef&>yEcHT3hi`$CGH*9vMfGpVpimM>+P2%x=;j~CH;nk0v?Z5R z+O1u4xzf!DE;+<+&TP+nO3?2!{ss^F*HK)3?4>Z&tK-A_b&uI9_jd|%7cApbk57rb zvWNvU7qdKqOe3ZTGB&^>Yuwjt&P5XO7jf3QEaHvaIofW$!|iXrbQCDwpWTe}qQYA1 z3DT?2FG6HsiWFRyq>`uiHUMkH<`;j#b9x8wOfSgH;nidu`n$e-RTm1QV}zf&R=&(0 zua@<{#IEJv&itp4e|n9C+p>j$n8>yj^R1_zi5NREHdPp@$UdO{SkiR%(CFZzGUgQ8 zC{HAc#M&Vt6JZsR&_5@3g=H$w_Ocs*wAkM@4{W!CZ^TdySrw#y1^Ep*qZtq@&%aB= zq-tIDuh&)n{M1JT9zhgLnkvY$M*_PKr_q1Nit2BKTW-u@Mq`O<<>~^Vi{a0__uP|k z^!OQNbVErL@-P`gpY8S|IJxR)D6rZ{0U`{abiU(aL;G`~$hXL71CEa`9^bdRu#g9t zav!ho-LpGuqD_Whd*}*zSj2zJCHgE2%~PFrJ;S>m6wCmBo`j#>oyNSZo8L-KvVB^J zc2|{X-qJOa)tqeQIV`-wuydOe5;TUGFyH&;dlH1aZEBnwAI&D?eW0NE+(N0zV2(z2 zF_*7tK9IAM6y~G+oxC|BgF!vuUx_xiCO5@@7?lDWKnx(%2~JKpGJpWDw{}0|b)3rm zrFJyrruwg#4nWFH9Qyw+;QUvC03QAwfW(dXpY#7JMUFRh$u2l)3k-Y!_f*5nOhpBxtO(Od>JJj_UTT(4?dU*g`oi~1=tq{UAvwnPT z8{=uMiU_R+d8x0wp9*J(V3>e?UV9J?q7oBDf7&gnMiY$}xjmN*sCr^D`f4ug*`sW^ z=G$W4kF;twwvtA4VoKv*i{aJHOFor>Hoc$8)O98`Pp0o4ziy(q3(c=?wfcRN-OPNV zW;#k%*KnxYaJ5nWz%9qYuN@k_OXQ_nw9d5kqYu3P$MrU(L7co8606A{3t*pc4s21b*Ow*{=6y8@mYI(djyHmdz^ z{fIS$QV0K#uhN)-gmPINemeT~_{8FQ}`NwW@z%%=GwQJ@$S+b-HV z8vZ#~^je|snvUOn)q_i2UrnMJguf~^N`LCaC?F*fHlD4?LRff^}g@e-#La zS$lSO@-p{}OS!4(WlpLRDv;NK0+fH7;VO4m&7NKmYGtNCHQe_VX_E@sga%r5g)cZi zgd$?5FK3u=t=+%sbVU*z7$guhFA%MvH~JAF!kH#!bManC+VY2IypAoa2Zt}M258Vo z%$9BiJ3f72ujZikxywpj^yLVF$Lwn{Hm}pNJhhz@*FvQ=^TG{8y6dNtwKx7W zI~k}qVcRtpiR1BT#35?=JhkxcFFDU9PGqU=V;p)2-;O;^QO%k9SEIbruqx`7!aThs zD*n7{1xauFp&2bQnlT)LI-T^Vs&vMms74S3SQ2RQ9f-Oe&DpNCm%u7?qDw9$R{GFtm^1!i%>&jBj(WH#d`{s2tPYBG_rC zc#0R~Cc0b(`i-^XAN~WL6d~=&_v+P16<;(88Jd?;^yB z{mdX-NWvc9>U(@{Q#2_mx805QZJHd((b(&dIZM!=0FVcYFPE_RC@AHX#)J{~^L-I}9E6*zL@NhKg)pRR>|k-p*t zyc{$~$62xIj3T+z_!WZYXv=+OY$JfyJN}aMQNd>t@2T$SvfaR2O5sZ8s*}jNtXJm@am5u+HhdQNPi(gL5xSka3GbbCi1EQ;P5~DW@D3W(h@Pt)8|Xm z6p`EjJ`LW*wdNrj2)8S^;%_Se2U+vm;-QFdlika=%WnkVst~wW2iYN#9F{SjiV_kJ zT7Pee8Wcae{rNp^hLxhYn0$VpsR)xtyG%J79sW;poZLGDK)^ELOIQ740ryKSo<-cU z4g0&Lo`U_)7*%wJgR|d*f_;{JDW!hHECqDaZW!8M44Vpib@i!zb&{0H9|#vsNiW); zh22xmlr#|T$R@>sX zoM&jSRU|gi@~?Jk-dlwob}msDRy^TDo|#vh%EQW$KBlTNR8hX7??A^5Cr$ny;ItKR zkW|6!{Xw6PZHyI?PP?1Jt0!)T7mO4gho&Rf$@3}#Jpls%FyF{SQjmj!nQ7~1^1R{X zE!WhH!4PT|RpK{V3UrGZ@1W1s z=l3j*ET(N<6#Tl>=`fVWVB$g*>vhtq>({g;@_~f2RpluO;88?iK`rtjEfTw=T+){- z+M;@GRYsyxdAi1WyY%r!VjgKg46s`XO?^9)U@p%p1us73j!*1)*W=36IxlAAwRR<= zYzi$EF4*F;_+{#>T2AePkgOY(wP+_Cn3+#e;pVkRkHu)dCOpo52`SJ}8XCQvl?LE1 zq0u}m&y+)n^QFroX!FuGRfXog;(qv)m)WwBFyiIcg;&eqeKQh>ux(#<%yZzQ^iq~X zy%?Twg>8-})c-S#p{#DI2bI#O*lpgn^gg7nzeG{o%mzH%^AID*EAMJ;#nz;)i>Azm zGdcTp@K>0s$8P=y6&8W@Q$vho4eHzVx->DD-o8CtzU4S$lKP7w;&)-3PkFXj9nqRUFYOh%!&B^NNYcYOS3HUr+=X1s6z zQj6n_?D#d|%lS^ax^;%zXX}W%deMjIiVM-tSWAvG9n#Q^d6Td$Q>@XV+_jX+=kfPq zsOdVA1OuuLx+~nj2>biDec7q#wp!e|TdH$}C}ooflzSZrv#UY+r1fCXBGQ)HqW!I{ zc=#vn!0&qd^hzY73Vp{(_qt+f!=Y^Jz2PzsuFjt^tUqndrTMG{l#^gtrBL63_}luA zr_CnD4_WW!eqv*>Wea6F7R=S%Y?#PBbtuXwnK&3G1L<0Tc&x6!(v7wsv@YL*ObA#R zakCE`ClJ2^C2&?(CQxDT2za;vRd1S*yb9T(?L(**Ixp@&FJEE?uEsO>?gYtl|Brc^ z{is;*y?bdUq(lTu->}Q`pKgak9p(HM*?d~>XZA(xy84Pza_RDX zaydj`GHl-Uy#Fo3iP-((zFY|mSS{$n>oX#oV14=i@9d`<-rsHu%lG% z*Q=nG&KQhn`MfSXjAvJH>v9<5Us=e6ya2bQ-CTfL$I3GVNg|K+Pdq%BCHO?+uH9A_ zF=8}NZ%*2bdD>s zk|{#njga56wfY}60UX-5_z=C2+x_D{W`&LUX9j#WVi-1#OCwcHC#V5vznww(7+xH$ z=uu4wAc4tLG1@Xc{H{eZS&mi15m#;9O=CMZYqH}mN?{N8F$ftb```=iJ8{YK5fn-E zbl)6>IEQ~mTJf-4Zq>=*v>+1s@N9~-z4>=iNB>g%#NSIBBrVXPCRR{Mj5JjhW%M~F z(ag@3Sdi^z>--XKB7;Qs_Y+VLL68dkN@!B@t}<|NxyQiA-T1`d1vh5LTWwb&H`$+k zUM~sjm+#fdHxFo&I(6~QMY1^xWLTWmA-h%j0Ub~tQZ>O)UxY%!<;f3f@pw(?SO$^& zuP;TqD9>sli`;P5jRvYvu+l29`=%g4lMT$uVm|DLzDV)TM$1hOsX{pu)AwdWz0QT) zgJv(c=*ZRSZs8v@{TQUF%AniNc~P(ppcjz51+z^y3io#lNCmw6XAHjnJJ==yd;xuw zbR^pUroQle2YmYK9-FlsQ@Z$&-&Ny?KA)z<8Yub0yI$_ihV-(at0Y5@BU>#~=Du!{qzF%=;^$AEo-eQCzG< zcd>cGn)V+c?NmrJW-wvgT+Zr;Ue~Y}=RLgZINbbhyh8T^mtf$}y@jZM&Mq+MG0C?69`$N--@X z+*{q62I3MXpqaITZA$;s!58D(_yDE{+VyBux$dtOv%V~PS!UPA7J9#OB0A85^|4+* z(jD(z*_?G_*Gt8e8*|Li)lzmLNM-Xrx7O5fZEM)vAL~y3T+NObs)zYNcg>FAss0vf zmr?S>a9CAd>X0LcmHPOU*zjjvs{IO10eaeU!I8RQ9d{w_8YCIJ9IoA*mBp$|b$`8* zxaPbi@GIZn_un$pkS_}97lMn}kKJPMyZN0yJdZBI2Xedei?ZwXQt)3&ps|jS4LfRs zw0epbtYC!X;1bxJ|AKv6dP+vh48z@SaCfE7vk*<+M$Qa&U`TFsR$>xiE&tGCy*=J; z6j6pU_RF4gZe_c;9a%l1;Wl@lfJ4V7QF9N?ZkLmH_c(k8(DR8IIaf@qJ&-br RG{gOOLdL))qNL~K{a;~1M796` literal 0 HcmV?d00001 diff --git a/tests/mldsa87-keygen-prov.c b/tests/mldsa87-keygen-prov.c new file mode 100644 index 00000000..b46e800a --- /dev/null +++ b/tests/mldsa87-keygen-prov.c @@ -0,0 +1,176 @@ +/* + * Copyright © 2026 Mobi - Com Polska Sp. z o.o. + * Author: Małgorzata Olszówka + * All rights reserved. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include "helpers_prov.h" +#include "oneshot_common.h" + +#if !defined(OPENSSL_NO_ML_DSA) && OPENSSL_VERSION_NUMBER >= 0x30500000L + +static void error_queue(const char *name) +{ + if (ERR_peek_last_error()) { + fprintf(stderr, "%s generated errors:\n", name); + ERR_print_errors_fp(stderr); + } +} + +int main(int argc, char *argv[]) +{ + int ret = EXIT_FAILURE; + int rc = 0; + PKCS11_CTX *ctx = NULL; + PKCS11_SLOT *slots = NULL, *slot; + unsigned int nslots; + EVP_PKEY *private_key = NULL, *public_key = NULL; + PKCS11_NID_KGEN mldsa = { + .nid = NID_ML_DSA_87 + }; + PKCS11_params params = { + .sensitive = 1, + .extractable = 0, + }; + PKCS11_KGEN_ATTRS mldsa_kg = { + .type = EVP_PKEY_ML_DSA_87, + .kgen.nid = &mldsa, + .token_label = NULL, + .key_label = NULL, + .key_id = (const unsigned char *)"\x22\x33", + .id_len = 2, + .key_params = ¶ms, + }; + const char *private_uri = "pkcs11:token=token1;object=libp11-keylabel;type=private;pin-value=1234"; + const char *public_uri = "pkcs11:token=token1;object=libp11-keylabel;type=public"; + + if (argc < 4) { + printf("Too few arguments\n"); + printf("%s /usr/lib/opensc-pkcs11.so [MODULE] [TOKEN1] [KEY-LABEL] [PIN]\n", argv[0]); + goto cleanup; + } + mldsa_kg.token_label = argv[2]; + mldsa_kg.key_label = argv[3]; + + ctx = PKCS11_CTX_new(); + error_queue("PKCS11_CTX_new"); + + /* load PKCS#11 module */ + rc = PKCS11_CTX_load(ctx, argv[1]); + error_queue("PKCS11_CTX_load"); + CHECK_ERR(rc < 0, "loading PKCS#11 module failed", 4); + + /* get information on all slots */ + rc = PKCS11_enumerate_slots(ctx, &slots, &nslots); + error_queue("PKCS11_enumerate_slots"); + CHECK_ERR(rc < 0, "no slots available", 5); + + slot = PKCS11_find_token(ctx, slots, nslots); + error_queue("PKCS11_find_token"); + while (slot) { + if (slot->token && slot->token->initialized && slot->token->label + && strcmp(argv[2], slot->token->label) == 0) + break; + slot = PKCS11_find_next_token(ctx, slots, nslots, slot); + }; + CHECK_ERR(!slot || !slot->token, "no token available", 6); + + printf("Found token:\n"); + printf("Slot manufacturer......: %s\n", slot->manufacturer); + printf("Slot description.......: %s\n", slot->description); + printf("Slot token label.......: %s\n", slot->token->label); + printf("Slot token serialnr....: %s\n", slot->token->serialnr); + + rc = PKCS11_login(slot, 0, argv[4]); + error_queue("PKCS11_login"); + CHECK_ERR(rc < 0, "PKCS11_login failed", 7); + /* + * ML-DSA key generation test + */ + rc = PKCS11_keygen(slot->token, &mldsa_kg); + error_queue("PKCS11_keygen"); + CHECK_ERR(rc < 0, "Failed to generate a key pair on the token", 8); + printf("ML-DSA keys generated\n"); + + /* Free the list of slots allocated by PKCS11_enumerate_slots() */ + PKCS11_release_all_slots(ctx, slots, nslots); + slots = NULL; + PKCS11_CTX_unload(ctx); + PKCS11_CTX_free(ctx); + ctx = NULL; + + /* Load pkcs11prov and default providers */ + if (!providers_load()) { + display_openssl_errors(); + goto cleanup; + } + + /* Load keys */ + private_key = load_pkey(private_uri, "provider=pkcs11prov", NULL); + if (!private_key) { + printf("Cannot load private key: %s\n", argv[3]); + display_openssl_errors(); + goto cleanup; + } + printf("Private key found.\n"); + + public_key = load_pubkey(public_uri, "provider=pkcs11prov"); + if (!public_key) { + printf("Cannot load public key: %s\n", argv[3]); + display_openssl_errors(); + goto cleanup; + } + printf("Public key found.\n"); + + if ((ret = EVP_Digest_sign_verify_test(private_key, public_key)) < 0) { + printf("EVP_Digest_sign_verify_test() failed with err code: %d\n", ret); + display_openssl_errors(); + goto cleanup; + } + if ((ret = EVP_PKEY_sign_verify_test(private_key, public_key)) < 0) { + printf("EVP_PKEY_sign_verify_test() failed with err code: %d\n", ret); + display_openssl_errors(); + goto cleanup; + } + printf("ML-DSA Sign-verify success\n"); + + ret = 0; +cleanup: + EVP_PKEY_free(private_key); + EVP_PKEY_free(public_key); + if (slots) + PKCS11_release_all_slots(ctx, slots, nslots); + if (ctx) { + PKCS11_CTX_unload(ctx); + PKCS11_CTX_free(ctx); + } + providers_cleanup(); + printf("\n"); + return ret; +} + +#else /* !defined(OPENSSL_NO_ML_DSA) && OPENSSL_VERSION_NUMBER >= 0x30500000L */ + +#include + +int main() { + fprintf(stderr, "Skipped: requires OpenSSL >= 3.5 built with ML-DSA support\n"); + return 77; +} + +#endif /* !defined(OPENSSL_NO_ML_DSA) && OPENSSL_VERSION_NUMBER >= 0x30500000L */ + +/* vim: set noexpandtab: */ diff --git a/tests/mldsa87-privkey.der b/tests/mldsa87-privkey.der new file mode 100644 index 0000000000000000000000000000000000000000..6f8e480f420728a6037bc71672409ae109a3edea GIT binary patch literal 4962 zcmV-o6P@fZf)ic>0RS)y1_@w>NC9O71OpQUf)h$Gf)hprARA4i8!?oZV=@*)AYy##_2ATPCI#(j;07*?*c=E@3252w0n#4 z5*A0%GTe_o^sQh-{wBCeYYZc707;KdDC~%cM%{KY6@x|nGllp$F6Kv`cSuM8>9p#%7_R_ zh(r>lWFawa0)=tdln@h{fto;3NQ6WL!X*H(Pz!^B%rXj)fM^6a5tt+*$qLUMqXE!0M09D{_^7)cWaNRuWI3zcA#563NSJnA}j$RGJysK9G3+c5D^dsDIkRj0{|@wIDkSXh69lhnIMHAuw`7pMacq) z2qTJ!NNtj+2|@q?gcvFaHEv)i1<^8547m`@Mq zX(R~%5rt9Gq=_3PQUiz~+<=jqw2jcfP>Zk-7y&3um|%h^WFjIiSi*q{f^3X1E(^7R zgP0{zwlNu*faDgEf+%tlG=@}wWz;|r6qO~QGHQ{qWnz{f3%4xLLUF+e2#BIY9GGmH zByLw2TBKiHn#B+XRseqLIol zY8<01L9`?jwvZ7gWEqtaBQk9gvPIwqhQqjQp#(*XKnMUuMB9Q437}C>uo0mEjU2)- z;KV>6hGp7_1PB#|6QfKSBa+lWEEI)k0W>hfm<><@Vp$R@peAjLL{3uzXp9yln-r2t z$ZX^?aYM!soE9zN1}Rvwh#G)xn-B(w0#P6|f)s>}0+cP=mXV7F5)?F23@~8eBuShi zgpvYi2_cDN2o4y+jm#nnVHOD>lW~lcEm9(3loAdBf?#CAiGs8wp)hWYkVK=RiJBmZ z45@@$G>F_7MFPn{3NkPug($$nWdI~G;vz~J5<#K_Qp%Kwj1p!NkzvU=X$Tf-9F=5* zz=as4APO=<(S&gzhe?uzK)^T>Q6y%WHYCIbOqnJOq!3196mEpVi~+N85~+#7q$n7L zj6y^VfD&O6K?Gxxg~XI32oP|=z%UvFfntDQ0SPDor!gRzNf{FWiWZO=fl=DDgj1$b z7^aO}MvPNHNyH*f6S;-SBqAdRQNaX-!V+-GzyZS~4U0%bm=Hx`AS6mM4uh0Y+!87i z!i?m=EaS3Z6SPEul7SmIYzjC@q!uC=#fibhK^a2;;>ZXCm|(ybQVFGr#0G3iNP(fC zFq*&nN5eSNiupmM*B@4De8yImU#7Ptgf(j`K2}vQM0*2DK001&7 z!L(pmCJ|W>Ou~qTix7$&wU88`F%pwa6h z5*xUT(>4KNAT1d}DI5ug$|923Gzr7NK>`RN!iYs!v_%Rz0TMw1889%AB!LN-MAC$S z*ceeF1dGZV+3GaKrJA~Ox!RDN&r#Js3;S)Wy%&X5vWk3 z7KkIIOk}1cOe6(BHUboa5JX5w+Y~AoLMp(taVq?@1oXlqPQi+PCXKcYj?Bvw4uq-K z*>-6+GkI!8W`?(B8*g*2N1H6`zQiBWaO*g|9Ivfy|))r5n0V> zGp!1RJISsD$KDvG-%S{_tM~#!#94Nr*BG!53f{PxqB=1?B$$yg-wy?y$4wgiO{GaV zn}M}@9!!jnHO#vEH0UYdO7 z5nDUaQtZnJ!y(o#>L*F~^yC*DozN3l7APu-mA>31`LT!IO}!ARs)XIVt*ylI2ze+p zJpV^8A-Od_Ym$F}XuoY$_eH2i6WJIQJlJx;{ZMW@XCoYE&4BuPDQ)L5ZFVoqVnB9MsGsAs z$TWQ4osFGJFUNl#Sc*Pnwfv00r%T3)z74r9`V2M?cOKW0u2l^IVf4Eq-vO~%kZ=J; zY^8DLR>yiCF3>|Yvu5VEIX>|w;8kQnSIr5pb(h+i#Z4Kel|^OV91pSaOEPCoJ7qM7 zZOoyzh(rAxF9}m8<}pY5{iI4mc5zPOsXcWJ$nKqnmOVoBtl_$8`LGT!pr5Z@qfT_w^gAyf+Wf_g^eq*Uaqp2dhmIN! z6-Dk&ho^_OPa)x6Zvt1*)qQLZh)13%HJ66Ig7Rih7}`-+S2NO9qJC0fO>`6uYQpKA z2fe}K%$?Zymo%2ETe{eZ(N7u={TS~Qk6&CArmmw8Wx4xMI^-^;u|OG6#8Uzi#fI_D zoa)nhYQ}F~01}NL$qcSna68+=CcN9>dB+g>n@!(fWv@F9HKXoD?TC9vpN3~M9IDL! zsbvUcdM!5UOQz`z(zxa)a$;v#Yv04G673uS6#cKj zsJ#q&&2FBbZ}Ix!zzAc=!sG`fce>&KyhcS?F4{HLrF@yndshND%3?9ig>uRsI2)_} zn1~2qBN>IjqYIoeH<8KwA5yQ>d|kJ-anRij;$f4>L%O&6#$+D!lX$Z`yD9GyGjtdC z2~ERMB+;2Q4*v@OF@UQK-uOvu$%(SdH026BY;T?#`V;HjlMqKaC}tb55@?`xaUckN zW~NFUe}ZVo!M(=me$d+(^WH<^aT;GoBEY|C{^_&I09vt%^6nB>XCEfhZX6&Qp63atq06Mt>QuWQF< zEJmV?jR0s=shWN?CX~uQh)RuxY!q6&q_H+R=!nZRvr)Uikx&|WIz}R=N%fQl@O=3x za&2SJ)#jQht5cr^Q$OXKnT=-br*uh%?Jy+@_YFviLX;5&h&Za(Y^pR95;nNJ8&12= z8xyecYxKXu8fH(X=r_f!^nU6ov1=Yf4o9)?+p=}AB{2Pp!X+ivte@Eu?_ns7FA|2c ztstT#G(BK@Wv4_jVrI<`Oz@kN7-3cWz~=(tjLK*K78y(*)wUvF_FR8Au2`A(Eb1+= zkT{bC2)xDfKk#yZP zO!5Sl>YWFK>vQ5R4cB2e3%}tcD3Z;uSMSKYQ3vRoXk}z@lXfBX$c9iBc~G7e`=f#7g(;QFh{9FbcFttrqr`uYSXx+9*W%_NkQ_N|(PViwy@s}E8AjeZM zIKJ$lMBjS3+<9`@FmT(D*qfl`CXTQrhoIaYRWW1GB_M=HqeGK55(Hp5iMVsL3FgaO zMMlnq*u*DSAA!g^s*)OO3w^J81(UU6>1I8iM|F&W+q$O{-}{|r1fR27K7FbpQQHZ$ z>=e1|>^AT>&6C?bvq0{_?MrZcwUs$Z9tdp6rg0*f$1TBWYxfxvO@*6v!0aQ;9892r2Ax(hrbagIQ0(XID-VIbn5tFgzQcBO z-{&O;A$~sL0JIP+kOSMRidiH%QW2f9b0z2M_>q`bDN0YBB3KoSh`>2Vk??Tp{9fnb zo)I;JBG6mhjt+>3+9?c0BFGJ>!908__u&3Q+e$?`wwMW+;wHa1YdZJ|4Mh?N7oicJO^1ShREZQX)yrW$R3#aj!l-LFihTI(#pY3E!rw1_J!4H63=>0H?-#eRl=5BBKLRm$@mQWd8Sb@8jD_F5_ zkJ{N3E&jDaLDP66)U!$8YwEr+Z6D6qXbI({p(#UVYoVp3JL-eUtCW5pj~J=>0~WUT zpb;->+sVW{?#K3F?_>2d3#^9!+m)j6fFYuV?GbzQN2Q=F$gwz;Qzf+e98^op>5VEO z`<~3ZWk$T{-mUDRIh0!^DZRBoJ!-L2!&+A|rHz*thHt?(SE;ctkI*T^)HpPN@x6WL zeuL3rfFJ=WU=pZ_ZU1k5PjEKfsKz7}JP~{ktKMJjv;ByWp#SX7>6b&dRoc#S6A&aN z<$LBL1L8yPR{?p?{MBgG*)-Zjk>|TkZM#CvY|x3=0_*2rVt9@bLcQQs{yl)$dy+^D zAu$E}tNRC+9O4?|zIKtY8v{tvK@oIRkVI@gg=Vta;)2M@FP^~-f2TT#UTO@BWUX7_ z`$DwJM^?D!*~eK9HGTH8|27wqqq2BHL_`$`k#jr3m<41V_S65@rf}o4CPC4=xvDEpC#zr7$nmgYTFQM!EQ3DlXt5gKvCR2hYyJ(w zM!=MIXJ#aG$;C?@_hIFjg?%3xgO?H*k?M$O)BWGQrv*2t1#&GVQ)d0|D?Yxuj}&U? zNPmtvS#tOFlXRt}J=KI6`ZZNwQmY@Ls?A$KbN1N~0|D5rRrc$h1%SkXnfa6prgOwa zg(h))s_T2I7k~Pt=Me(S;2i_lM5qr-29ero)D=aVe$o?{&vL75D#&4B5-#-``$gE> z+tav=UR93GF1l()K~fX#JM)wmz_|}cbWem7aZsh;sGOP-fl%`PqX2#ORWrhNww+P9 g>NQ%hzo|Wb6v_pSNh_!ytxWyPyrR(5g=Tx!pN+?`6951J literal 0 HcmV?d00001 diff --git a/tests/mldsa87-pubkey.der b/tests/mldsa87-pubkey.der new file mode 100644 index 0000000000000000000000000000000000000000..6216ef1b0738391c16187366190bfa230be83161 GIT binary patch literal 2614 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 0x30000000L @@ -52,7 +67,7 @@ int EVP_Digest_sign_verify_test(EVP_PKEY *priv, EVP_PKEY *pub) retval = -2; goto err; } - /* initialize the sign context using an Ed25519/Ed448 private key, + /* initialize the sign context using a one-shot signature private key, * notice that the digest name must NOT be used */ if (EVP_DigestSignInit(mdctx, NULL, NULL, NULL, priv) != 1) { retval = -3; @@ -81,13 +96,15 @@ int EVP_Digest_sign_verify_test(EVP_PKEY *priv, EVP_PKEY *pub) retval = -7; goto err; } - /* initialize the verify context with a Ed25519/Ed448 public key */ + /* initialize the verify context using a one-shot signature public key, + * notice that the digest name must NOT be used */ if (EVP_DigestVerifyInit(mdctx, NULL, NULL, NULL, pub) != 1) { retval = -8; goto err; } - /* Ed25519/Ed448 only supports the one shot interface using EVP_DigestVerify(), - * the streaming EVP_DigestVerifyUpdate() API is not supported */ + /* one-shot signature algorithms only support the one-shot + * EVP_DigestVerify() interface; the streaming EVP_DigestVerifyUpdate() + * API is not supported */ if (EVP_DigestVerify(mdctx, sig, siglen, msg, msglen) == 1) { retval = 0; goto err; @@ -138,23 +155,21 @@ int EVP_PKEY_sign_verify_test(EVP_PKEY *priv, EVP_PKEY *pub) goto err; } - /* --- Verify --- - * Ed25519 and Ed448 do not implement verify_init/verify in EVP_PKEY_METHOD. - * These algorithms support only one-shot signing and verification operations. - * See also: EVP_SIGNATURE-ED25519 and EVP_SIGNATURE-ED448. - */ + /* --- Verify --- */ mdctx = EVP_MD_CTX_new(); if (!mdctx) { retval = -6; goto err; } - /* initialize the verify context with a Ed25519/Ed448 public key */ + /* initialize the verify context using a one-shot signature public key, + * notice that the digest name must NOT be used */ if (EVP_DigestVerifyInit(mdctx, NULL, NULL, NULL, pub) != 1) { retval = -7; goto err; } - /* Ed25519/Ed448 only supports the one shot interface using EVP_DigestVerify(), - * the streaming EVP_DigestVerifyUpdate() API is not supported */ + /* one-shot signature algorithms only support the one-shot + * EVP_DigestVerify() interface; the streaming EVP_DigestVerifyUpdate() + * API is not supported */ if (EVP_DigestVerify(mdctx, sig, siglen, msg, msglen) == 1) { retval = 0; goto err; diff --git a/tests/eddsa_common.h b/tests/oneshot_common.h similarity index 97% rename from tests/eddsa_common.h rename to tests/oneshot_common.h index c61e445c..7f1cf779 100644 --- a/tests/eddsa_common.h +++ b/tests/oneshot_common.h @@ -27,7 +27,7 @@ * SUCH DAMAGE. */ -/* Ed25519/ED448 common functions */ +/* One-shot signature algorithms common functions */ #include diff --git a/tests/provider-ec-copy.softhsm b/tests/provider-ec-copy.softhsm index 0eaa601f..2f28529d 100755 --- a/tests/provider-ec-copy.softhsm +++ b/tests/provider-ec-copy.softhsm @@ -23,6 +23,9 @@ outdir="output.$$" PRIVATE_KEY="pkcs11:token=libp11-0;id=%01%02%03%04;object=server-key-0;type=private;pin-value=${PIN}" +# EC tests only require the private key object, as the public key can be +# reconstructed from the EC point and curve parameters. + # Do the token initialization init_token "ec" "1" "libp11" ${ID} "server-key" "privkey" "" "" diff --git a/tests/provider-ed25519-copy.softhsm b/tests/provider-ed25519-copy.softhsm new file mode 100755 index 00000000..162ca245 --- /dev/null +++ b/tests/provider-ed25519-copy.softhsm @@ -0,0 +1,59 @@ +#!/bin/bash + +# Copyright © 2026 Mobi - Com Polska Sp. z o.o. +# Author: Małgorzata Olszówka +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see + +outdir="output.$$" + +# Load common test functions +. ${srcdir}/common.sh + +PRIVATE_KEY="pkcs11:token=libp11-0;id=%01%02%03%04;object=server-key-0;type=private;pin-value=${PIN}" + +# EdDSA tests require both private and public key objects, as the public +# key cannot be reliably reconstructed from a PKCS#11 private key object. + +# Do the token initialization +init_token "ed25519" "1" "libp11" ${ID} "server-key" "privkey" "pubkey" "" + +# Ensure the use of the locally built provider; applies after running 'pkcs11-tool' +unset OPENSSL_ENGINES +export OPENSSL_MODULES="../src/.libs/" +export PKCS11_MODULE_PATH=${MODULE} +echo "OPENSSL_MODULES=${OPENSSL_MODULES}" +echo "PKCS11_MODULE_PATH=${PKCS11_MODULE_PATH}" + +# Load openssl settings +. ${srcdir}/openssl-settings.sh + +# Restore openssl settings +trap cleanup EXIT + +# Run the test +${WRAPPER} ./dup-key-prov ${PRIVATE_KEY} +rc=$? +if [[ $rc -eq 77 ]]; then + echo "Duplicate private key test skipped." + rm -rf "$outdir" + exit 77 +elif [[ $rc -ne 0 ]]; then + echo "Duplicate private key test failed." + exit 1 +fi + +rm -rf "$outdir" + +exit 0 diff --git a/tests/provider-mldsa87-check-privkey.softhsm b/tests/provider-mldsa87-check-privkey.softhsm new file mode 100755 index 00000000..ceac3f39 --- /dev/null +++ b/tests/provider-mldsa87-check-privkey.softhsm @@ -0,0 +1,81 @@ +#!/bin/bash + +# Copyright © 2026 Mobi - Com Polska Sp. z o.o. +# Author: Małgorzata Olszówka +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see +# +# EdDSA public key resolution tests +# +# The provider resolves the public key for a private key as follows: +# 1. CKO_PUBLIC_KEY (CKA_EC_POINT) +# 2. CKO_CERTIFICATE (CKA_VALUE + X.509 parsing) +# +# ML-DSA-87: +# Import privkey + cert only (no pubkey) to exercise the CKO_CERTIFICATE fallback path. + +outdir="output.$$" + +# Load common test functions +. ${srcdir}/common.sh + +PRIVATE_KEY="pkcs11:token=libp11-0;id=%01%02%03%04;object=server-key-0;type=private;pin-value=${PIN}" +CERTIFICATE_URL="pkcs11:token=libp11-0;id=%01%02%03%04;object=server-key-0;type=cert" + +# Do the token initialization +init_token "mldsa87" "1" "libp11" ${ID} "server-key" "privkey" "" "cert" +if [[ $? -eq 77 ]]; then + echo "ML-DSA-87 key test skipped." + rm -rf "$outdir" + exit 77 +fi + +# Ensure the use of the locally built provider; applies after running 'pkcs11-tool' +unset OPENSSL_ENGINES +export OPENSSL_MODULES="../src/.libs/" +export PKCS11_MODULE_PATH=${MODULE} +echo "OPENSSL_MODULES=${OPENSSL_MODULES}" +echo "PKCS11_MODULE_PATH=${PKCS11_MODULE_PATH}" + +# Load openssl settings +. ${srcdir}/openssl-settings.sh + +# Restore openssl settings +trap cleanup EXIT + +${OPENSSL} x509 -in ${srcdir}/mldsa87-cert.der -inform DER -outform PEM \ + -out ${outdir}/mldsa87-cert.pem +CERTIFICATE="${outdir}/mldsa87-cert.pem" + +# Run the test +${WRAPPER} ./check-privkey-prov ${CERTIFICATE} ${PRIVATE_KEY} +rc=$? +if [[ $rc -eq 77 ]]; then + echo "ML-DSA-87 key test skipped." + rm -rf "$outdir" + exit 77 +elif [[ $rc -ne 0 ]]; then + echo "The private key loading couldn't get the public key from the certificate." + exit 1 +fi + +./check-privkey-prov ${CERTIFICATE_URL} ${PRIVATE_KEY} +if [[ $? -ne 0 ]]; then + echo "The private key loading couldn't get the public key from the certificate URL." + exit 1 +fi + +rm -rf "$outdir" + +exit 0 diff --git a/tests/provider-mldsa87-copy.softhsm b/tests/provider-mldsa87-copy.softhsm new file mode 100755 index 00000000..f2b60873 --- /dev/null +++ b/tests/provider-mldsa87-copy.softhsm @@ -0,0 +1,64 @@ +#!/bin/bash + +# Copyright © 2026 Mobi - Com Polska Sp. z o.o. +# Author: Małgorzata Olszówka +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see + +outdir="output.$$" + +# Load common test functions +. ${srcdir}/common.sh + +PRIVATE_KEY="pkcs11:token=libp11-0;id=%01%02%03%04;object=server-key-0;type=private;pin-value=${PIN}" + +# ML-DSA tests require both private and public key objects, as the public +# key cannot be reliably reconstructed from a PKCS#11 private key object. + +# Do the token initialization +init_token "mldsa87" "1" "libp11" ${ID} "server-key" "privkey" "pubkey" "" +if [[ $? -eq 77 ]]; then + echo "ML-DSA-87 key test skipped." + rm -rf "$outdir" + exit 77 +fi + +# Ensure the use of the locally built provider; applies after running 'pkcs11-tool' +unset OPENSSL_ENGINES +export OPENSSL_MODULES="../src/.libs/" +export PKCS11_MODULE_PATH=${MODULE} +echo "OPENSSL_MODULES=${OPENSSL_MODULES}" +echo "PKCS11_MODULE_PATH=${PKCS11_MODULE_PATH}" + +# Load openssl settings +. ${srcdir}/openssl-settings.sh + +# Restore openssl settings +trap cleanup EXIT + +# Run the test +${WRAPPER} ./dup-key-prov ${PRIVATE_KEY} +rc=$? +if [[ $rc -eq 77 ]]; then + echo "Duplicate private key test skipped." + rm -rf "$outdir" + exit 77 +elif [[ $rc -ne 0 ]]; then + echo "Duplicate private key test failed." + exit 1 +fi + +rm -rf "$outdir" + +exit 0 diff --git a/tests/provider-mldsa87-keygen.softhsm b/tests/provider-mldsa87-keygen.softhsm new file mode 100755 index 00000000..84130bb9 --- /dev/null +++ b/tests/provider-mldsa87-keygen.softhsm @@ -0,0 +1,68 @@ +#!/bin/bash + +# Copyright © 2026 Mobi - Com Polska Sp. z o.o. +# Author: Małgorzata Olszówka + +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . + +outdir="output.$$" + +# Load common test functions +. ${srcdir}/common.sh + +# Initialize SoftHSM DB +init_db + +# Create token +init_card "token1" + +unset OPENSSL_ENGINES +export OPENSSL_MODULES="../src/.libs/" +export PKCS11_MODULE_PATH=${MODULE} +echo "OPENSSL_MODULES=${OPENSSL_MODULES}" +echo "PKCS11_MODULE_PATH=${PKCS11_MODULE_PATH}" + +# Load openssl settings +. ${srcdir}/openssl-settings.sh + +# Restore openssl settings +trap cleanup EXIT + +if ! has_mechanism ML-DSA; then + echo "ML-DSA key generation test skipped." + rm -rf "$outdir" + exit 77 +fi + +${WRAPPER} ./mldsa87-keygen-prov ${MODULE} token1 libp11-keylabel ${PIN} +rc=$? +if [[ $rc -eq 77 ]]; then + echo "ML-DSA key generation test skipped." + rm -rf "$outdir" + exit 77 +elif [[ $rc -ne 0 ]]; then + echo "ML-DSA key generation test failed." + exit 1 +fi + +echo "Checking pkcs11-tool result..." +list_objects | grep -q libp11-keylabel +if [[ $? != 0 ]]; then + echo "ML-DSA key was not properly generated." + exit 1 +fi + +rm -rf "$outdir" + +exit 0 diff --git a/tests/provider-pkcs11-uri-without-token.softhsm b/tests/provider-pkcs11-uri-without-token.softhsm index 2680d16d..12b50ad0 100755 --- a/tests/provider-pkcs11-uri-without-token.softhsm +++ b/tests/provider-pkcs11-uri-without-token.softhsm @@ -234,24 +234,24 @@ if has_mechanism RSA-PKCS; then echo "Failed to verify signature using PKCS#11 URI ${CERTIFICATE}" exit 1 fi + echo + + # Verify the signature using a certificate via rsa_verify_directly() + ${OPENSSL} pkeyutl -provider pkcs11prov -provider default \ + -propquery "?provider=pkcs11prov" \ + -inkey ${CERTIFICATE} \ + -verify -certin \ + -sigfile "${outdir}/signature.bin" -in "${outdir}/hash.bin" + if [[ $? -ne 0 ]]; then + echo "Failed to verify signature using PKCS#11 URI ${CERTIFICATE}" + exit 1 + fi else echo "Skipping CKM_RSA_PKCS tests" fi echo -# Verify the signature using a certificate via rsa_verify_directly() -${OPENSSL} pkeyutl -provider pkcs11prov -provider default \ - -propquery "?provider=pkcs11prov" \ - -inkey ${CERTIFICATE} \ - -verify -certin \ - -sigfile "${outdir}/signature.bin" -in "${outdir}/hash.bin" -if [[ $? -ne 0 ]]; then - echo "Failed to verify signature using PKCS#11 URI ${CERTIFICATE}" - exit 1 -fi -echo - #### Sign/verify RSA_PKCS1_PADDING (CKM_RSA_PKCS) with implicit SHA256 digest #### From 15b11b23ed36cc51aa36430e306a1a63ee21d2d7 Mon Sep 17 00:00:00 2001 From: olszomal Date: Tue, 16 Jun 2026 14:33:07 +0200 Subject: [PATCH 10/14] Update NEWS for PQC support --- NEWS | 3 +++ 1 file changed, 3 insertions(+) diff --git a/NEWS b/NEWS index ecae25fb..1cb131bf 100644 --- a/NEWS +++ b/NEWS @@ -3,6 +3,9 @@ NEWS for Libp11 -- History of user visible changes New in 0.4.19; unreleased * Define LIBP11_VERSION_NUMBER (Michał Trojnara) * Added PKCS#11 provider support for OpenSSL 4.x. (Małgorzata Olszówka) +* Added support for ML-DSA, SLH-DSA and FALCON key generation, signing and + verification (Małgorzata Olszówka) +* Added PQC key generation examples and provider tests (Małgorzata Olszówka) New in 0.4.18; 2026-02-16; Michał Trojnara * Support for RSA-PSS and RSA-OAEP using keys retrieved using the From 8df4f8e2c80c7c46a0beedb1bf238c45ad2bdf1e Mon Sep 17 00:00:00 2001 From: olszomal Date: Tue, 16 Jun 2026 14:42:22 +0200 Subject: [PATCH 11/14] build: Add PQC sources to Windows makefile --- src/Makefile.mak | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Makefile.mak b/src/Makefile.mak index 63fb805f..3cb7d481 100644 --- a/src/Makefile.mak +++ b/src/Makefile.mak @@ -5,7 +5,7 @@ TOPDIR = .. LIBP11_OBJECTS = libpkcs11.obj p11_attr.obj p11_cert.obj \ p11_err.obj p11_ckr.obj p11_key.obj p11_load.obj p11_misc.obj \ p11_rsa.obj p11_ec.obj p11_pkey.obj p11_slot.obj p11_front.obj \ - p11_atfork.obj p11_eddsa.obj + p11_atfork.obj p11_eddsa.obj p11_mldsa.obj p11_slhdsa.obj p11_falcon.obj LIBP11_LIB = libp11.lib LIBP11_TARGET = libp11.dll From 7cbac849fc19f2e7d9a7681101e6a13df17f1314 Mon Sep 17 00:00:00 2001 From: olszomal Date: Tue, 16 Jun 2026 15:03:37 +0200 Subject: [PATCH 12/14] Fix MSVC size_t conversion warning in EC signing --- src/p11_pkey.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/p11_pkey.c b/src/p11_pkey.c index 11f7f182..a868f62b 100644 --- a/src/p11_pkey.c +++ b/src/p11_pkey.c @@ -770,11 +770,11 @@ ECDSA_SIG *pkcs11_ec_sign_raw(PKCS11_OBJECT_private *key, return NULL; tmp_len = *siglen; - if (tmp_len == 0 || tmp_len % 2 != 0) + if (tmp_len == 0 || tmp_len % 2 != 0 || tmp_len / 2 > INT_MAX) return NULL; - r = BN_bin2bn(sig, tmp_len / 2, NULL); - s = BN_bin2bn(sig + tmp_len / 2, tmp_len / 2, NULL); + r = BN_bin2bn(sig, (int)(tmp_len / 2), NULL); + s = BN_bin2bn(sig + tmp_len / 2, (int)(tmp_len / 2), NULL); if (r == NULL || s == NULL) goto error; From d35cfdd36743f06f9bb16ff41c79b22c597f8c63 Mon Sep 17 00:00:00 2001 From: olszomal Date: Tue, 16 Jun 2026 15:10:38 +0200 Subject: [PATCH 13/14] Fix MSVC warning for OAEP label length --- src/libp11-int.h | 2 +- src/libp11.h | 2 +- src/p11_front.c | 2 +- src/p11_pkey.c | 6 +++--- 4 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/libp11-int.h b/src/libp11-int.h index 4c531e22..b9b1a8c7 100644 --- a/src/libp11-int.h +++ b/src/libp11-int.h @@ -493,7 +493,7 @@ extern int pkcs11_evp_pkey_falcon_verify(PKCS11_OBJECT_private *key, /* Decrypt RSA input via PKCS#11 using configured padding and OAEP parameters */ extern int pkcs11_evp_pkey_rsa_decrypt(PKCS11_OBJECT_private *key, const char *mdname, const int pad_mode, - const char *mgf1_mdname, unsigned char *oaep_label, const int oaep_labellen, + const char *mgf1_mdname, unsigned char *oaep_label, size_t oaep_labellen, unsigned char *out, size_t *outlen, const unsigned char *in, size_t inlen); diff --git a/src/libp11.h b/src/libp11.h index 2c62007e..bc6d54ef 100644 --- a/src/libp11.h +++ b/src/libp11.h @@ -572,7 +572,7 @@ int PKCS11_evp_pkey_verify(EVP_PKEY *pkey, int type, /* Perform a private-key decryption operation using a PKCS#11-backed EVP_PKEY */ extern int PKCS11_evp_pkey_decrypt(EVP_PKEY *pk, int type, const char *mdname, const int pad_mode, const char *mgf1_mdname, - unsigned char *oaep_label, const int oaep_labellen, + unsigned char *oaep_label, size_t oaep_labellen, unsigned char *sig, size_t *siglen, const unsigned char *in, size_t inlen); #endif /* OPENSSL_VERSION_NUMBER >= 0x30000000L */ diff --git a/src/p11_front.c b/src/p11_front.c index 856c30c8..a0f6c67c 100644 --- a/src/p11_front.c +++ b/src/p11_front.c @@ -898,7 +898,7 @@ int PKCS11_evp_pkey_verify(EVP_PKEY *pk, int type, int PKCS11_evp_pkey_decrypt(EVP_PKEY *pk, int type, const char *mdname, const int pad_mode, const char *mgf1_mdname, - unsigned char *oaep_label, const int oaep_labellen, + unsigned char *oaep_label, size_t oaep_labellen, unsigned char *out, size_t *outlen, const unsigned char *in, size_t inlen) { diff --git a/src/p11_pkey.c b/src/p11_pkey.c index a868f62b..c7cd9991 100644 --- a/src/p11_pkey.c +++ b/src/p11_pkey.c @@ -195,7 +195,7 @@ static int pkcs11_params_pss(CK_RSA_PKCS_PSS_PARAMS *pss_params, EVP_PKEY *pkey, static int pkcs11_oaep_param(CK_RSA_PKCS_OAEP_PARAMS *oaep_params, const char *oaep_mdname, const char *mgf1_mdname, - unsigned char *oaep_label, const int oaep_labellen, + unsigned char *oaep_label, size_t oaep_labellen, PKCS11_CTX_private *pctx) { const EVP_MD *oaep_md = NULL; @@ -282,7 +282,7 @@ static int pkcs11_set_rsa_decrypt_mechanism(CK_MECHANISM *mechanism, CK_RSA_PKCS_OAEP_PARAMS *oaep_params, PKCS11_CTX_private *pctx, const int padding, const char *mdname, const char *mgf1_mdname, - unsigned char *oaep_label, const int oaep_labellen) + unsigned char *oaep_label, size_t oaep_labellen) { if (mechanism == NULL) return -1; @@ -961,7 +961,7 @@ int pkcs11_evp_pkey_falcon_verify(PKCS11_OBJECT_private *key, */ int pkcs11_evp_pkey_rsa_decrypt(PKCS11_OBJECT_private *key, const char *mdname, const int pad_mode, - const char *mgf1_mdname, unsigned char *oaep_label, const int oaep_labellen, + const char *mgf1_mdname, unsigned char *oaep_label, size_t oaep_labellen, unsigned char *out, size_t *outlen, const unsigned char *in, size_t inlen) { From 7d1bda5b398c1a75b82fa88fec9af09ed90bfd34 Mon Sep 17 00:00:00 2001 From: olszomal Date: Wed, 17 Jun 2026 14:12:59 +0200 Subject: [PATCH 14/14] Fix MGF1 name typo in debug logs --- src/p11_pkey.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/p11_pkey.c b/src/p11_pkey.c index c7cd9991..eea9d597 100644 --- a/src/p11_pkey.c +++ b/src/p11_pkey.c @@ -179,7 +179,7 @@ static int pkcs11_params_pss(CK_RSA_PKCS_PSS_PARAMS *pss_params, EVP_PKEY *pkey, break; } - pkcs11_log(pctx, LOG_DEBUG, "salt_len=%d sig_md=%s mdf1_md=%s\n", + pkcs11_log(pctx, LOG_DEBUG, "salt_len=%d sig_md=%s mgf1_md=%s\n", salt_len, EVP_MD_name(sig_md), EVP_MD_name(mgf1_md)); /* fill the CK_RSA_PKCS_PSS_PARAMS structure */