From 945838e62136f3dfc24ec2ce46c8305e292d9e67 Mon Sep 17 00:00:00 2001 From: Michal Nowak Date: Thu, 14 May 2026 14:50:18 +0000 Subject: [PATCH] Tolerate non-extractable Ed25519/Ed448 private keys in tofile openssleddsa_tofile() called EVP_PKEY_get_raw_private_key() unconditionally whenever the dst_key_t had a private EVP_PKEY attached and aborted with ISC_R_FAILURE on any error. That is wrong for keys whose private material lives in a hardware token (PKCS#11): the provider deliberately refuses to export the raw bytes, but the keypair is still valid and the .private file should be written containing only the PKCS#11 label, with no raw key material. Without this, "dnssec-keyfromlabel -a ed25519 -l pkcs11:..." fails with "failed to write key ...: failure" even though pkcs11-tool has generated a valid Ed25519 key in SoftHSM. Mirror the behaviour already implemented in opensslecdsa_tofile(): if the raw private key cannot be retrieved AND the key has a PKCS#11 label to fall back on, clear the OpenSSL error queue and fall through to writing just the Label element. If extraction fails and there is no label to fall back on, return the OpenSSL failure rather than silently producing a .private file with neither raw key material nor a label, which would be unusable on the next load. Consolidate buffer cleanup into a single cleanup: path, freeing with the original allocation size (alginfo->key_size) rather than the potentially-modified len output parameter. Assisted-by: Claude:claude-opus-4-7 --- lib/dns/openssleddsa_link.c | 22 +++++++++++++++------- 1 file changed, 15 insertions(+), 7 deletions(-) diff --git a/lib/dns/openssleddsa_link.c b/lib/dns/openssleddsa_link.c index f9f1a0bdf0..26cc360727 100644 --- a/lib/dns/openssleddsa_link.c +++ b/lib/dns/openssleddsa_link.c @@ -371,14 +371,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 +401,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; }