From 5ebf17741f1f7ed46b4af49a024ea321d42335c2 Mon Sep 17 00:00:00 2001 From: Michal Nowak Date: Thu, 14 May 2026 14:50:58 +0000 Subject: [PATCH] Generate Ed25519/Ed448 keys via PKCS#11 when a label is set When a dst_key_t carries a PKCS#11 URI in key->label (as named does for dnssec-policy zones backed by a key-store "hsm"), key generation must happen inside the HSM, not in software. opensslecdsa_generate already branches on key->label and calls the matching pkcs11 wrapper; the EDDSA generator silently ignored the label and produced a software key, which named then wrote to the .private file with both a Label: line and the raw PrivateKey: bytes -- a corrupt hybrid record that prevented zone signing. Add the missing wrapper: - lib/isc/ossl_wrap/ossl3.c gains generate_pkcs11_eddsa_key() and the public isc_ossl_wrap_generate_pkcs11_ed25519_key() / isc_ossl_wrap_generate_pkcs11_ed448_key() entry points. They use EVP_PKEY_CTX_new_from_name(NULL, "ED25519" or "ED448", "provider=pkcs11") with the pkcs11_uri and pkcs11_key_usage parameters, mirroring the existing EC wrapper. - lib/isc/ossl_wrap/ossl1_1.c provides stubs returning ISC_R_NOTIMPLEMENTED for the new EDDSA wrappers; the pkcs11-provider stack requires OpenSSL 3. The pre-existing isc_ossl_wrap_generate_pkcs11_rsa_key() stub used to silently delegate to software keygen -- that hid the same "HSM label on a software key" hazard for RSA on OpenSSL 1.1 builds, so align it with the EDDSA stubs and return ISC_R_NOTIMPLEMENTED too. - lib/isc/include/isc/ossl_wrap.h declares the new wrappers. - lib/dns/openssleddsa_link.c routes openssleddsa_generate() through the new wrappers when key->label is non-NULL, leaving the existing EVP_PKEY_keygen() path untouched for software keys. The Ed448 case is guarded by HAVE_OPENSSL_ED448 to match the surrounding code. Assisted-by: Claude:claude-opus-4-7 --- lib/dns/openssleddsa_link.c | 22 +++++++++++++ lib/isc/include/isc/ossl_wrap.h | 22 +++++++++++++ lib/isc/ossl_wrap/ossl1_1.c | 28 ++++++++++++++-- lib/isc/ossl_wrap/ossl3.c | 57 +++++++++++++++++++++++++++++++++ 4 files changed, 127 insertions(+), 2 deletions(-) diff --git a/lib/dns/openssleddsa_link.c b/lib/dns/openssleddsa_link.c index 26cc360727..0d30defcc4 100644 --- a/lib/dns/openssleddsa_link.c +++ b/lib/dns/openssleddsa_link.c @@ -22,6 +22,7 @@ #include #include +#include #include #include #include @@ -270,6 +271,27 @@ openssleddsa_generate(dst_key_t *key, int unused, void (*callback)(int)) { UNUSED(unused); UNUSED(callback); + if (key->label != NULL) { + switch (key->key_alg) { + case DST_ALG_ED25519: + RETERR(isc_ossl_wrap_generate_pkcs11_ed25519_key( + key->label, &pkey)); + break; +#if HAVE_OPENSSL_ED448 + case DST_ALG_ED448: + RETERR(isc_ossl_wrap_generate_pkcs11_ed448_key( + key->label, &pkey)); + break; +#endif /* HAVE_OPENSSL_ED448 */ + default: + UNREACHABLE(); + } + key->key_size = alginfo->key_size * 8; + key->keydata.pkeypair.priv = pkey; + key->keydata.pkeypair.pub = pkey; + return ISC_R_SUCCESS; + } + ctx = EVP_PKEY_CTX_new_id(alginfo->nid, NULL); if (ctx == NULL) { return dst__openssl_toresult2("EVP_PKEY_CTX_new_id", diff --git a/lib/isc/include/isc/ossl_wrap.h b/lib/isc/include/isc/ossl_wrap.h index 4831fab405..cfb1cf2faf 100644 --- a/lib/isc/include/isc/ossl_wrap.h +++ b/lib/isc/include/isc/ossl_wrap.h @@ -131,6 +131,28 @@ isc_ossl_wrap_generate_pkcs11_p384_key(char *uri, EVP_PKEY **pkeyp); * \li `uri != NULL` and is a NUL-terminated string */ +isc_result_t +isc_ossl_wrap_generate_pkcs11_ed25519_key(char *uri, EVP_PKEY **pkeyp); +/*% + * Generates an Ed25519 key using the PKCS#11 label specified at `uri`. + * + * Requires: + * \li pkeyp != NULL + * \li *pkeyp == NULL + * \li `uri != NULL` and is a NUL-terminated string + */ + +isc_result_t +isc_ossl_wrap_generate_pkcs11_ed448_key(char *uri, EVP_PKEY **pkeyp); +/*% + * Generates an Ed448 key using the PKCS#11 label specified at `uri`. + * + * Requires: + * \li pkeyp != NULL + * \li *pkeyp == NULL + * \li `uri != NULL` and is a NUL-terminated string + */ + isc_result_t isc_ossl_wrap_load_p384_public_from_region(isc_region_t region, EVP_PKEY **pkeyp); diff --git a/lib/isc/ossl_wrap/ossl1_1.c b/lib/isc/ossl_wrap/ossl1_1.c index de325c47c4..6a5740a3b8 100644 --- a/lib/isc/ossl_wrap/ossl1_1.c +++ b/lib/isc/ossl_wrap/ossl1_1.c @@ -410,9 +410,33 @@ cleanup: isc_result_t isc_ossl_wrap_generate_pkcs11_rsa_key(char *uri, size_t bit_size, EVP_PKEY **pkeyp) { - UNUSED(uri); + REQUIRE(uri != NULL); + REQUIRE(pkeyp != NULL && *pkeyp == NULL); - return isc_ossl_wrap_generate_rsa_key(NULL, bit_size, pkeyp); + UNUSED(uri); + UNUSED(bit_size); + UNUSED(pkeyp); + return ISC_R_NOTIMPLEMENTED; +} + +isc_result_t +isc_ossl_wrap_generate_pkcs11_ed25519_key(char *uri, EVP_PKEY **pkeyp) { + REQUIRE(uri != NULL); + REQUIRE(pkeyp != NULL && *pkeyp == NULL); + + UNUSED(uri); + UNUSED(pkeyp); + return ISC_R_NOTIMPLEMENTED; +} + +isc_result_t +isc_ossl_wrap_generate_pkcs11_ed448_key(char *uri, EVP_PKEY **pkeyp) { + REQUIRE(uri != NULL); + REQUIRE(pkeyp != NULL && *pkeyp == NULL); + + UNUSED(uri); + UNUSED(pkeyp); + return ISC_R_NOTIMPLEMENTED; } bool diff --git a/lib/isc/ossl_wrap/ossl3.c b/lib/isc/ossl_wrap/ossl3.c index 92334b2d1c..7021ff5f5d 100644 --- a/lib/isc/ossl_wrap/ossl3.c +++ b/lib/isc/ossl_wrap/ossl3.c @@ -239,6 +239,60 @@ cleanup: return result; } +static isc_result_t +generate_pkcs11_eddsa_key(char *uri, EVP_PKEY **pkeyp, const char *keytype) { + isc_result_t result; + EVP_PKEY_CTX *pctx = NULL; + size_t len; + + INSIST(uri != NULL); + len = strlen(uri); + + const OSSL_PARAM params[] = { + OSSL_PARAM_utf8_string("pkcs11_uri", uri, len), + OSSL_PARAM_utf8_string("pkcs11_key_usage", pkcs11_key_usage, + sizeof(pkcs11_key_usage) - 1), + OSSL_PARAM_END, + }; + + pctx = EVP_PKEY_CTX_new_from_name(NULL, keytype, "provider=pkcs11"); + if (pctx == NULL) { + CLEANUP(OSSL_WRAP_ERROR("EVP_PKEY_CTX_new_from_name")); + } + + if (EVP_PKEY_keygen_init(pctx) != 1) { + CLEANUP(OSSL_WRAP_ERROR("EVP_PKEY_keygen_init")); + } + + if (EVP_PKEY_CTX_set_params(pctx, params) != 1) { + CLEANUP(OSSL_WRAP_ERROR("EVP_PKEY_CTX_set_params")); + } + + if (EVP_PKEY_generate(pctx, pkeyp) != 1) { + CLEANUP(OSSL_WRAP_ERROR("EVP_PKEY_generate")); + } + + result = ISC_R_SUCCESS; + +cleanup: + EVP_PKEY_CTX_free(pctx); + return result; +} + +isc_result_t +isc_ossl_wrap_generate_pkcs11_ed25519_key(char *uri, EVP_PKEY **pkeyp) { + REQUIRE(pkeyp != NULL && *pkeyp == NULL); + REQUIRE(uri != NULL); + return generate_pkcs11_eddsa_key(uri, pkeyp, "ED25519"); +} + +isc_result_t +isc_ossl_wrap_generate_pkcs11_ed448_key(char *uri, EVP_PKEY **pkeyp) { + REQUIRE(pkeyp != NULL && *pkeyp == NULL); + REQUIRE(uri != NULL); + return generate_pkcs11_eddsa_key(uri, pkeyp, "ED448"); +} + static isc_result_t validate_ec_pkey(EVP_PKEY *pkey, const OSSL_PARAM *const curve_params) { isc_result_t result; @@ -523,6 +577,9 @@ isc_ossl_wrap_generate_pkcs11_rsa_key(char *uri, size_t bit_size, int status; size_t len; + REQUIRE(uri != NULL); + REQUIRE(pkeyp != NULL && *pkeyp == NULL); + len = strlen(uri); INSIST(len != 0);