diff --git a/bin/tests/system/enginepkcs11/setup.sh b/bin/tests/system/enginepkcs11/setup.sh index 0f6cbc6932..459a6ea623 100644 --- a/bin/tests/system/enginepkcs11/setup.sh +++ b/bin/tests/system/enginepkcs11/setup.sh @@ -49,8 +49,8 @@ mkdir ns1/keys dir="ns1" infile="${dir}/template.db.in" for algtypebits in rsasha256:rsa:2048 rsasha512:rsa:2048 \ - ecdsap256sha256:EC:prime256v1 ecdsap384sha384:EC:prime384v1; do # Edwards curves are not yet supported by OpenSC - # ed25519:EC:edwards25519 ed448:EC:edwards448 + ecdsap256sha256:EC:prime256v1 ecdsap384sha384:EC:prime384v1 \ + ed25519:EC:Ed25519 ed448:EC:Ed448; do alg=$(echo "$algtypebits" | cut -f 1 -d :) type=$(echo "$algtypebits" | cut -f 2 -d :) bits=$(echo "$algtypebits" | cut -f 3 -d :) diff --git a/bin/tests/system/enginepkcs11/tests.sh b/bin/tests/system/enginepkcs11/tests.sh index 138b0483a8..0546a7c62a 100644 --- a/bin/tests/system/enginepkcs11/tests.sh +++ b/bin/tests/system/enginepkcs11/tests.sh @@ -50,11 +50,17 @@ check_keys() { cd ns1 for algtypebits in rsasha256:rsa:2048 rsasha512:rsa:2048 \ - ecdsap256sha256:EC:prime256v1 ecdsap384sha384:EC:prime384v1; do # Edwards curves are not yet supported by OpenSC - # ed25519:EC:edwards25519 ed448:EC:edwards448 + ecdsap256sha256:EC:prime256v1 ecdsap384sha384:EC:prime384v1 \ + ed25519:EC:Ed25519 ed448:EC:Ed448; do alg=$(echo "$algtypebits" | cut -f 1 -d :) type=$(echo "$algtypebits" | cut -f 2 -d :) bits=$(echo "$algtypebits" | cut -f 3 -d :) + alg_upper=$(echo "$alg" | tr '[:lower:]' '[:upper:]') + supported=$(eval "echo \$${alg_upper}_SUPPORTED") + if [ "${supported}" != 1 ]; then + echo_i "skipping test for ${alg}:${type}:${bits}, not supported by this build" + continue + fi zone="${alg}.example" zonefile="zone.${zone}.db.signed" diff --git a/bin/tests/system/keyfromlabel/tests_keyfromlabel.py b/bin/tests/system/keyfromlabel/tests_keyfromlabel.py index ad3ad01603..948d308ef9 100644 --- a/bin/tests/system/keyfromlabel/tests_keyfromlabel.py +++ b/bin/tests/system/keyfromlabel/tests_keyfromlabel.py @@ -17,6 +17,8 @@ import shutil import pytest +from isctest.util import param + import isctest.mark pytestmark = [ @@ -93,9 +95,24 @@ def token_init_and_cleanup(): ("rsasha512", "rsa", "2048"), ("ecdsap256sha256", "EC", "prime256v1"), ("ecdsap384sha384", "EC", "prime384v1"), - # Edwards curves are not yet supported by OpenSC - # ("ed25519","EC","edwards25519"), - # ("ed448","EC","edwards448") + param( + "ed25519", + "EC", + "Ed25519", + marks=pytest.mark.skipif( + os.environ.get("ED25519_SUPPORTED") != "1", + reason="Ed25519 not supported by this build", + ), + ), + param( + "ed448", + "EC", + "Ed448", + marks=pytest.mark.skipif( + os.environ.get("ED448_SUPPORTED") != "1", + reason="Ed448 not supported by this build", + ), + ), ], ) def test_keyfromlabel(alg_name, alg_type, alg_bits): diff --git a/lib/dns/openssleddsa_link.c b/lib/dns/openssleddsa_link.c index f9f1a0bdf0..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", @@ -371,14 +393,22 @@ openssleddsa_tofile(const dst_key_t *key, const char *directory) { len = alginfo->key_size; buf = isc_mem_get(key->mctx, len); if (EVP_PKEY_get_raw_private_key(key->keydata.pkeypair.priv, - buf, &len) != 1) + buf, &len) == 1) { - CLEANUP(dst__openssl_toresult(ISC_R_FAILURE)); + priv.elements[i].tag = TAG_EDDSA_PRIVATEKEY; + priv.elements[i].length = len; + priv.elements[i].data = buf; + i++; + } else if (key->label != NULL) { + /* + * The raw private key is not extractable + * (e.g. HSM-backed via PKCS#11); fall through to + * writing only the label. + */ + ERR_clear_error(); + } else { + CLEANUP(dst__openssl_toresult(DST_R_OPENSSLFAILURE)); } - priv.elements[i].tag = TAG_EDDSA_PRIVATEKEY; - priv.elements[i].length = len; - priv.elements[i].data = buf; - i++; } if (key->label != NULL) { priv.elements[i].tag = TAG_EDDSA_LABEL; @@ -393,7 +423,7 @@ openssleddsa_tofile(const dst_key_t *key, const char *directory) { cleanup: if (buf != NULL) { - isc_mem_put(key->mctx, buf, len); + isc_mem_put(key->mctx, buf, alginfo->key_size); } return result; } 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);