diff --git a/.gitignore b/.gitignore index a9eb838e..4ff7122e 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 @@ -90,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/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 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/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) { \ 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: */ 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/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 diff --git a/src/libp11-int.h b/src/libp11-int.h index f9cee6e1..b9b1a8c7 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 *); @@ -394,15 +455,45 @@ 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 */ + +#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, - 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.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..bc6d54ef 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,10 +564,15 @@ 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, - 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_eddsa.c b/src/p11_eddsa.c index d0f90862..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; @@ -563,7 +569,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 +606,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) 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..a0f6c67c 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,23 +821,84 @@ 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, + unsigned char *oaep_label, size_t oaep_labellen, unsigned char *out, size_t *outlen, const unsigned char *in, size_t inlen) { @@ -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 29d5f216..501676e9 100644 --- a/src/p11_key.c +++ b/src/p11_key.c @@ -122,6 +122,27 @@ 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 */ + #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); @@ -214,6 +235,92 @@ PKCS11_OBJECT_private *pkcs11_object_from_handle(PKCS11_SLOT_private *slot, OPENSSL_free(data); 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, @@ -304,13 +411,44 @@ 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) { 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 +518,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 +567,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 +610,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 +637,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 +657,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 +700,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 +719,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); @@ -577,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 */ @@ -630,7 +1023,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); @@ -726,8 +1119,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) @@ -744,8 +1137,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) @@ -767,15 +1160,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 @@ -872,10 +1265,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); @@ -1106,6 +1503,131 @@ 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) + +{ + 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) */ @@ -1234,6 +1756,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 +1831,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_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 c31c6800..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 */ @@ -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; @@ -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 */ @@ -279,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; @@ -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. @@ -697,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; @@ -753,6 +826,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 +849,110 @@ int pkcs11_evp_pkey_eddsa_sign(PKCS11_OBJECT_private *key, return 1; } +#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. @@ -783,7 +961,7 @@ int pkcs11_evp_pkey_eddsa_sign(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) { @@ -870,6 +1048,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 +1069,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 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 c42257bb..7d4e7979 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 (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) @@ -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. */ 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); /******************************************************************************/ 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 00000000..86cb98f0 Binary files /dev/null and b/tests/mldsa87-cert.der differ 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 00000000..6f8e480f Binary files /dev/null and b/tests/mldsa87-privkey.der differ diff --git a/tests/mldsa87-pubkey.der b/tests/mldsa87-pubkey.der new file mode 100644 index 00000000..6216ef1b Binary files /dev/null and b/tests/mldsa87-pubkey.der differ diff --git a/tests/eddsa_common.c b/tests/oneshot_common.c similarity index 75% rename from tests/eddsa_common.c rename to tests/oneshot_common.c index fa7979b6..a5daf7ce 100644 --- a/tests/eddsa_common.c +++ b/tests/oneshot_common.c @@ -27,9 +27,24 @@ * SUCH DAMAGE. */ -/* Ed25519/ED448 common functions */ +/* + * One-shot signature algorithms common functions + * + * Ed25519, Ed448, ML-DSA, SLH-DSA and FALCON operate on the input message + * directly, without an external digest. EVP_DigestSignInit() and + * EVP_DigestVerifyInit() must therefore be called with the digest name set to NULL. + * + * The streaming EVP_DigestSignUpdate() / EVP_DigestSignFinal() and + * EVP_DigestVerifyUpdate() / EVP_DigestVerifyFinal() APIs are not used + * here. These tests use the one-shot EVP_DigestSign() and + * EVP_DigestVerify() interfaces instead. + * + * See also: + * EVP_SIGNATURE-ED25519, EVP_SIGNATURE-ED448, + * EVP_SIGNATURE-ML-DSA, EVP_SIGNATURE-SLH-DSA + */ -#include "eddsa_common.h" +#include "oneshot_common.h" #if OPENSSL_VERSION_NUMBER >= 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 ####