Commit 24cf5ffbef for bind
commit 24cf5ffbef82b604fc99682afa47efa154d931a6
Author: Nicki Křížek <nicki@isc.org>
Date: Fri Oct 2 10:03:42 2026 +0000
Replace HSM keys that dnssec-keyfromlabel refuses
dnssec-keyfromlabel refuses to import a key from the HSM if a key file
with the same key tag already exists for the zone, whatever its role.
Unlike dnssec-keygen, pkcs11-tool does not avoid that, so the KSK of a
zone may share the key tag of its ZSK (or in enginepkcs11, of any other
key of the zone), and the import fails. Generate another key in that
case, as dnssec-keygen would.
Assisted-by: Claude:claude-opus-5-5
diff --git a/bin/tests/system/enginepkcs11/setup.sh b/bin/tests/system/enginepkcs11/setup.sh
index 459a6ea623..f10df0c118 100644
--- a/bin/tests/system/enginepkcs11/setup.sh
+++ b/bin/tests/system/enginepkcs11/setup.sh
@@ -44,6 +44,27 @@ keyfromlabel() {
cat keyfromlabel.out.$zone.$id
}
+# Unlike dnssec-keygen, pkcs11-tool does not avoid key tag collisions, so
+# dnssec-keyfromlabel may refuse a key. Replace it then.
+hsmkey() {
+ # keygen() and keyfromlabel() overwrite their (global) variables, so
+ # keep ours apart.
+ hsm_type="$1"
+ hsm_bits="$2"
+ hsm_alg="$3"
+ hsm_zone="$4"
+ hsm_id="$5"
+ hsm_dir="$6"
+ shift 6
+
+ for hsm_try in 0 1 2; do
+ keygen $hsm_type $hsm_bits $hsm_zone $hsm_id-$hsm_try || return 1
+ keyfromlabel $hsm_alg $hsm_zone $hsm_id-$hsm_try $hsm_dir "$@" && return 0
+ grep "already exists" keyfromlabel.err.$hsm_zone.$hsm_id-$hsm_try >/dev/null || return 1
+ done
+ return 1
+}
+
mkdir ns1/keys
dir="ns1"
@@ -64,16 +85,13 @@ for algtypebits in rsasha256:rsa:2048 rsasha512:rsa:2048 \
ret=0
echo_i "Generate keys $alg $type:$bits for zone $zone"
- keygen $type $bits $zone enginepkcs11-zsk || ret=1
- keygen $type $bits $zone enginepkcs11-ksk || ret=1
- test "$ret" -eq 0 || exit 1
echo_i "Get ZSK $alg $zone $type:$bits"
- zsk1=$(keyfromlabel $alg $zone enginepkcs11-zsk $dir)
+ zsk1=$(hsmkey $type $bits $alg $zone enginepkcs11-zsk $dir)
test -z "$zsk1" && exit 1
echo_i "Get KSK $alg $zone $type:$bits"
- ksk1=$(keyfromlabel $alg $zone enginepkcs11-ksk $dir -f KSK)
+ ksk1=$(hsmkey $type $bits $alg $zone enginepkcs11-ksk $dir -f KSK)
test -z "$ksk1" && exit 1
(
@@ -90,16 +108,13 @@ for algtypebits in rsasha256:rsa:2048 rsasha512:rsa:2048 \
test "$ret" -eq 0 || exit 1
echo_i "Generate successor keys $alg $type:$bits for zone $zone"
- keygen $type $bits $zone enginepkcs11-zsk2 || ret=1
- keygen $type $bits $zone enginepkcs11-ksk2 || ret=1
- test "$ret" -eq 0 || exit 1
- echo_i "Get ZSK $alg $id-$zone $type:$bits"
- zsk2=$(keyfromlabel $alg $zone enginepkcs11-zsk2 $dir)
+ echo_i "Get successor ZSK $alg $zone $type:$bits"
+ zsk2=$(hsmkey $type $bits $alg $zone enginepkcs11-zsk2 $dir)
test -z "$zsk2" && exit 1
- echo_i "Get KSK $alg $id-$zone $type:$bits"
- ksk2=$(keyfromlabel $alg $zone enginepkcs11-ksk2 $dir -f KSK)
+ echo_i "Get successor KSK $alg $zone $type:$bits"
+ ksk2=$(hsmkey $type $bits $alg $zone enginepkcs11-ksk2 $dir -f KSK)
test -z "$ksk2" && exit 1
(
@@ -195,16 +210,13 @@ if [ "${supported}" = 1 ]; then
ret=0
echo_i "Generate keys $alg $type:$bits for zone $zone"
- keygen $type $bits $zone enginepkcs11-zsk || ret=1
- keygen $type $bits $zone enginepkcs11-ksk || ret=1
- test "$ret" -eq 0 || exit 1
echo_i "Get ZSK $alg $zone $type:$bits"
- zsk1=$(keyfromlabel $alg $zone enginepkcs11-zsk $dir)
+ zsk1=$(hsmkey $type $bits $alg $zone enginepkcs11-zsk $dir)
test -z "$zsk1" && exit 1
echo_i "Get KSK $alg $zone $type:$bits"
- ksk1=$(keyfromlabel $alg $zone enginepkcs11-ksk $dir -f KSK)
+ ksk1=$(hsmkey $type $bits $alg $zone enginepkcs11-ksk $dir -f KSK)
test -z "$ksk1" && exit 1
(
@@ -225,16 +237,13 @@ if [ "${supported}" = 1 ]; then
test "$ret" -eq 0 || exit 1
echo_i "Generate successor keys $alg $type:$bits for zone $zone"
- keygen $type $bits $zone enginepkcs11-zsk2 || ret=1
- keygen $type $bits $zone enginepkcs11-ksk2 || ret=1
- test "$ret" -eq 0 || exit 1
- echo_i "Get ZSK $alg $id-$zone $type:$bits"
- zsk2=$(keyfromlabel $alg $zone enginepkcs11-zsk2 $dir)
+ echo_i "Get successor ZSK $alg $zone $type:$bits"
+ zsk2=$(hsmkey $type $bits $alg $zone enginepkcs11-zsk2 $dir)
test -z "$zsk2" && exit 1
- echo_i "Get KSK $alg $id-$zone $type:$bits"
- ksk2=$(keyfromlabel $alg $zone enginepkcs11-ksk2 $dir -f KSK)
+ echo_i "Get successor KSK $alg $zone $type:$bits"
+ ksk2=$(hsmkey $type $bits $alg $zone enginepkcs11-ksk2 $dir -f KSK)
test -z "$ksk2" && exit 1
(
diff --git a/bin/tests/system/keyfromlabel/tests_keyfromlabel.py b/bin/tests/system/keyfromlabel/tests_keyfromlabel.py
index efd152d3c5..3e2ee37dfd 100644
--- a/bin/tests/system/keyfromlabel/tests_keyfromlabel.py
+++ b/bin/tests/system/keyfromlabel/tests_keyfromlabel.py
@@ -117,8 +117,7 @@ def token_init_and_cleanup():
)
def test_keyfromlabel(alg_name, alg_type, alg_bits):
- def keygen(alg_type, alg_bits, zone, key_id):
- label = f"{key_id}-{zone}"
+ def keygen(alg_type, alg_bits, label):
p11_id = hashlib.sha1(label.encode("utf-8")).hexdigest()
pkcs11_command = [
@@ -143,7 +142,7 @@ def test_keyfromlabel(alg_name, alg_type, alg_bits):
assert "Key pair generated" in cmd.out
- def keyfromlabel(alg_name, zone, key_id, key_flag):
+ def keyfromlabel(alg_name, zone, label, key_flag):
key_flag = key_flag.split() if key_flag else []
keyfrlab_command = [
@@ -152,32 +151,45 @@ def test_keyfromlabel(alg_name, alg_type, alg_bits):
alg_name,
"-y",
"-l",
- f"pkcs11:token=softhsm2-keyfromlabel;object={key_id}-{zone};pin-source=pin",
+ f"pkcs11:token=softhsm2-keyfromlabel;object={label};pin-source=pin",
*key_flag,
zone,
]
- cmd = isctest.run.cmd(keyfrlab_command)
+ cmd = isctest.run.cmd(keyfrlab_command, raise_on_exception=False)
+ if cmd.rc != 0 and "already exists" in cmd.err:
+ return None
+ assert cmd.rc == 0
keyfile = cmd.out.rstrip() + ".key"
assert os.path.exists(keyfile)
return keyfile
+ def hsm_key(alg_type, alg_bits, alg_name, zone, key_id, key_flag):
+ # Unlike dnssec-keygen, pkcs11-tool does not avoid key tag collisions,
+ # so dnssec-keyfromlabel may refuse a key. Replace it then.
+ keyfile = None
+ for attempt in range(3):
+ label = f"{key_id}-{attempt}-{zone}"
+ keygen(alg_type, alg_bits, label)
+ keyfile = keyfromlabel(alg_name, zone, label, key_flag)
+ if keyfile is not None:
+ break
+ assert keyfile is not None, f"{key_id}: key tags keep colliding"
+ return keyfile
+
if f"{alg_name.upper()}_SUPPORTED" not in os.environ:
pytest.skip(f"{alg_name} is not supported")
# Generate keys for the $zone zone
zone = f"{alg_name}.example"
- keygen(alg_type, alg_bits, zone, "keyfromlabel-zsk")
- keygen(alg_type, alg_bits, zone, "keyfromlabel-ksk")
-
# Get ZSK
- zsk_file = keyfromlabel(alg_name, zone, "keyfromlabel-zsk", "")
+ zsk_file = hsm_key(alg_type, alg_bits, alg_name, zone, "keyfromlabel-zsk", "")
# Get KSK
- ksk_file = keyfromlabel(alg_name, zone, "keyfromlabel-ksk", "-f KSK")
+ ksk_file = hsm_key(alg_type, alg_bits, alg_name, zone, "keyfromlabel-ksk", "-f KSK")
# Sign zone with KSK and ZSK
zone_file = f"zone.{alg_name}.example.db"