From c5f4d66e734d189b57ae865223951012615524e9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nicki=20K=C5=99=C3=AD=C5=BEek?= Date: Tue, 16 Jun 2026 15:57:48 +0200 Subject: [PATCH 1/7] Read DNSKEY TTL from kasp.Key.dnskey Remove the redundant ttl() method. The DNSKEY RR already provides the TTL. (cherry picked from commit 9dc039f735788d81f695dccac6ffad65e8547476) --- bin/tests/system/isctest/kasp.py | 10 +--------- 1 file changed, 1 insertion(+), 9 deletions(-) diff --git a/bin/tests/system/isctest/kasp.py b/bin/tests/system/isctest/kasp.py index e6f95c1e05..eed25bddf9 100644 --- a/bin/tests/system/isctest/kasp.py +++ b/bin/tests/system/isctest/kasp.py @@ -438,14 +438,6 @@ class Key: return ksigning, zsigning - def ttl(self) -> int: - with open(self.keyfile, "r", encoding="utf-8") as file: - for line in file: - if line.startswith(";"): - continue - return int(line.split()[1]) - return 0 - @property def dnskey(self) -> dns.rrset.RRset: with open(self.keyfile, "r", encoding="utf-8") as file: @@ -513,7 +505,7 @@ class Key: dsfromkey_command = [ os.environ.get("DSFROMKEY"), "-T", - str(self.ttl()), + str(self.dnskey.ttl), "-a", alg, "-C", From df7e8cf6bbe926a4be97d9eebde80a1ccf0c89b4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nicki=20K=C5=99=C3=AD=C5=BEek?= Date: Tue, 16 Jun 2026 12:34:48 +0000 Subject: [PATCH 2/7] Merge kasp.Key functionality into zone.FileZoneKey Make zone.FileZoneKey the single representation of a file-backed key (typically generated by dnssec-keygen). Move the common key-related functionality into zone.FileZoneKey, and extend that functionality in kasp.Key to also add state and timing related operations on top. Remove duplicate into_ta() function. Note that is_ksk() is implemented differently for kasp.Key: with the metadata file available, the KSK status is loaded from that file, as it indicates the authoritative policy decision which makes the key a KSK. In zone.FileZoneKey which doesn't work with the metadata file, the KSK status if inferred from the DNSKEY SEP flag - the best information available for that class. Assisted-by: Claude:claude-opus-4-8 (cherry picked from commit 35fc5ce8b4ddc71d032b634cd7a827b606742495) --- bin/tests/system/isctest/kasp.py | 40 +++++++------------------------- bin/tests/system/isctest/zone.py | 29 ++++++++++++++++------- 2 files changed, 29 insertions(+), 40 deletions(-) diff --git a/bin/tests/system/isctest/kasp.py b/bin/tests/system/isctest/kasp.py index eed25bddf9..3f4c76b1c2 100644 --- a/bin/tests/system/isctest/kasp.py +++ b/bin/tests/system/isctest/kasp.py @@ -19,21 +19,18 @@ import os import re import time -import dns.dnssec import dns.exception import dns.message import dns.name import dns.rcode import dns.rdataclass import dns.rdatatype -import dns.rrset import dns.tsig import dns.zone -import dns.zonefile from isctest.instance import NamedInstance -from isctest.template import TrustAnchor from isctest.vars.algorithms import ALL_ALGORITHMS_BY_NUM, Algorithm +from isctest.zone import FileZoneKey import isctest.log import isctest.query @@ -320,26 +317,18 @@ class KeyProperties: @total_ordering -class Key: +class Key(FileZoneKey): """ - Represent a key from a keyfile. + A FileZoneKey specialized with KASP timing and state-file operations. - This object keeps track of its origin (keydir + name), can be used to - retrieve metadata from the underlying files and supports convenience - operations for KASP tests. + Inherits the key-material accessors (dnskey, into_ta, ...) from FileZoneKey + and adds the metadata reads, signing-state derivation, and timing + convenience operations used by the KASP/rollover tests. """ def __init__(self, name: str, keydir: str | Path | None = None): - self.name = name - if keydir is None: - self.keydir = Path() - else: - self.keydir = Path(keydir) - self.path = str(self.keydir / name) - self.privatefile = f"{self.path}.private" - self.keyfile = f"{self.path}.key" + super().__init__(name, keydir) self.statefile = f"{self.path}.state" - self.tag = int(self.name[-5:]) self.external = False def get_timing( @@ -454,20 +443,9 @@ class Key: ), f"DNSKEY not found in {self.keyfile}" return dnskey_rr - def into_ta(self, ta_type: str, dsdigest=dns.dnssec.DSDigest.SHA256) -> TrustAnchor: - dnskey = self.dnskey - if ta_type in ["static-ds", "initial-ds"]: - ds = dns.dnssec.make_ds(dnskey.name, dnskey[0], dsdigest) - parts = str(ds).split() - contents = " ".join(parts[:3]) + f' "{parts[3]}"' - elif ta_type in ["static-key", "initial-key"]: - parts = str(dnskey).split() - contents = " ".join(parts[4:7]) + f' "{"".join(parts[7:])}"' - else: - raise ValueError(f"invalid trust anchor type: {ta_type}") - return TrustAnchor(str(dnskey.name), ta_type, contents) - def is_ksk(self) -> bool: + # KASP role follows the .state KSK metadata, not the DNSKEY SEP flag: + # a CSK may be configured without SEP (see the csk-nosep test). return self.get_metadata("KSK") == "yes" def is_zsk(self) -> bool: diff --git a/bin/tests/system/isctest/zone.py b/bin/tests/system/isctest/zone.py index df65932541..02b93c8b8d 100644 --- a/bin/tests/system/isctest/zone.py +++ b/bin/tests/system/isctest/zone.py @@ -27,8 +27,8 @@ import dns.name import dns.rdataclass import dns.rdatatype import dns.rrset +import dns.zonefile -from .kasp import Key from .log import debug from .run import EnvCmd from .template import NS1, Nameserver, TemplateEngine, TrustAnchor @@ -50,7 +50,7 @@ class ZoneKey(ABC): Abstract base for a DNSSEC key attached to a Zone. Two concrete implementations exist: - FileZoneKey — wraps a dnssec-keygen-managed key file pair (kasp.Key). + FileZoneKey — reads a dnssec-keygen-managed key file pair. PythonZoneKey — holds a Python-native (private_key, dnskey_rdata) pair required for dnspython-based operations and signing. @@ -107,18 +107,28 @@ class FileZoneKey(ZoneKey): """ A ZoneKey backed by dnssec-keygen-managed key files. - Constructed by FileZoneKey.generate(); callers normally do not - instantiate this directly. The underlying kasp.Key is accessible via - .key for working with timing metadata, state files, etc. + Reads key material directly from the .key/.private file pair. Normally + constructed via FileZoneKey.generate() (or Zone.add_keys()); + isctest.kasp.Key subclasses it to add KASP timing/state operations. """ - def __init__(self, key: Key, zone: Zone) -> None: - self.key = key + def __init__( + self, + name: str, + keydir: str | Path | None = None, + zone: Zone | None = None, + ) -> None: + self.name = name + self.keydir = Path() if keydir is None else Path(keydir) + self.path = str(self.keydir / name) + self.privatefile = f"{self.path}.private" + self.keyfile = f"{self.path}.key" + self.tag = int(self.name[-5:]) self.zone = zone @property def dnskey(self) -> dns.rrset.RRset: - return self.key.dnskey + raise NotImplementedError # TODO will be re-implemented in the followup commit def write_dsset( self, @@ -134,6 +144,7 @@ class FileZoneKey(ZoneKey): PythonZoneKey KSKs (PythonZoneKey appends to the same file); Zone.copy_dssets enforces this. """ + assert self.zone is not None, "write_dsset requires a zone-attached key" src = Path(self.zone.ns.name) / f"dsset-{self.zone.name}." shutil.copy(src, Path(target_dir)) debug(f"{self.zone.name}: dsset copied to {target_dir}") @@ -160,7 +171,7 @@ class FileZoneKey(ZoneKey): "KEYGEN", f"-q -a {alg.number} -b {alg.bits} -K {KEYDIR} -L {DNSKEY_TTL}" ) key_name = keygen(f"{params} {zone.name}", cwd=zone.ns.name).out.strip() - return FileZoneKey(Key(key_name, keydir=keydir), zone=zone) + return FileZoneKey(key_name, keydir=keydir, zone=zone) class PythonZoneKey(ZoneKey): From cad093960271b4fc2108194179b6a332c66d7d0c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nicki=20K=C5=99=C3=AD=C5=BEek?= Date: Tue, 16 Jun 2026 12:32:28 +0000 Subject: [PATCH 3/7] Move dnskey method from kasp.Key to zone.FileZoneKey Code move with one change - switch dnskey TTL from 300s (DEFAULT_TTL) to 3600s (DNSKEY_TTL). Assisted-by: Claude:claude-opus-4-8 (cherry picked from commit 55cd4a1e11af1bd83f3dcb24e38d24182bc1adf4) --- bin/tests/system/isctest/kasp.py | 16 ---------------- bin/tests/system/isctest/zone.py | 14 +++++++++++++- 2 files changed, 13 insertions(+), 17 deletions(-) diff --git a/bin/tests/system/isctest/kasp.py b/bin/tests/system/isctest/kasp.py index 3f4c76b1c2..687cc1e485 100644 --- a/bin/tests/system/isctest/kasp.py +++ b/bin/tests/system/isctest/kasp.py @@ -427,22 +427,6 @@ class Key(FileZoneKey): return ksigning, zsigning - @property - def dnskey(self) -> dns.rrset.RRset: - with open(self.keyfile, "r", encoding="utf-8") as file: - rrsets = dns.zonefile.read_rrsets( - file.read(), - rdclass=None, # read rdclass from the file - default_ttl=DEFAULT_TTL, # use this TTL if not present - ) - assert len(rrsets) == 1, f"{self.keyfile} has multiple RRsets" - dnskey_rr = rrsets[0] - assert len(dnskey_rr) == 1, f"{self.keyfile} has multiple RRs" - assert ( - dnskey_rr.rdtype == dns.rdatatype.DNSKEY - ), f"DNSKEY not found in {self.keyfile}" - return dnskey_rr - def is_ksk(self) -> bool: # KASP role follows the .state KSK metadata, not the DNSKEY SEP flag: # a CSK may be configured without SEP (see the csk-nosep test). diff --git a/bin/tests/system/isctest/zone.py b/bin/tests/system/isctest/zone.py index 02b93c8b8d..a7ba22db90 100644 --- a/bin/tests/system/isctest/zone.py +++ b/bin/tests/system/isctest/zone.py @@ -128,7 +128,19 @@ class FileZoneKey(ZoneKey): @property def dnskey(self) -> dns.rrset.RRset: - raise NotImplementedError # TODO will be re-implemented in the followup commit + with open(self.keyfile, "r", encoding="utf-8") as file: + rrsets = dns.zonefile.read_rrsets( + file.read(), + rdclass=None, # read rdclass from the file + default_ttl=DNSKEY_TTL, # use this TTL if not present + ) + assert len(rrsets) == 1, f"{self.keyfile} has multiple RRsets" + dnskey_rr = rrsets[0] + assert len(dnskey_rr) == 1, f"{self.keyfile} has multiple RRs" + assert ( + dnskey_rr.rdtype == dns.rdatatype.DNSKEY + ), f"DNSKEY not found in {self.keyfile}" + return dnskey_rr def write_dsset( self, From 9d5b97db809f0436f9b31498fa83f5f2ead28d30 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nicki=20K=C5=99=C3=AD=C5=BEek?= Date: Tue, 16 Jun 2026 17:54:56 +0200 Subject: [PATCH 4/7] Add NSEC3RSASHA1 to list of algorithms This algorithm is deprecated and not currently used in our system tests, but it should be in the list of all algorithms. (cherry picked from commit 596e41553c95a8cb0d256521098959fe03a15a3c) --- bin/tests/system/isctest/vars/algorithms.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/bin/tests/system/isctest/vars/algorithms.py b/bin/tests/system/isctest/vars/algorithms.py index ac8605896a..63b574965f 100644 --- a/bin/tests/system/isctest/vars/algorithms.py +++ b/bin/tests/system/isctest/vars/algorithms.py @@ -82,6 +82,7 @@ class AlgorithmSet(NamedTuple): RSASHA1 = Algorithm("RSASHA1", 5, 2048) +NSEC3RSASHA1 = Algorithm("NSEC3RSASHA1", 7, 2048) RSASHA256 = Algorithm("RSASHA256", 8, 2048) RSASHA512 = Algorithm("RSASHA512", 10, 2048) ECDSAP256SHA256 = Algorithm("ECDSAP256SHA256", 13, 256) @@ -91,6 +92,7 @@ ED448 = Algorithm("ED448", 16, 456) ALL_ALGORITHMS = [ RSASHA1, + NSEC3RSASHA1, RSASHA256, RSASHA512, ECDSAP256SHA256, From a7c9dfe16987380363d1d575b84f67104947524c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nicki=20K=C5=99=C3=AD=C5=BEek?= Date: Thu, 2 Jul 2026 15:42:13 +0200 Subject: [PATCH 5/7] Use the algorithm.number interface --- bin/tests/system/isctest/kasp.py | 10 +++++----- bin/tests/system/ksr/tests_ksr.py | 2 +- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/bin/tests/system/isctest/kasp.py b/bin/tests/system/isctest/kasp.py index 687cc1e485..a566b39615 100644 --- a/bin/tests/system/isctest/kasp.py +++ b/bin/tests/system/isctest/kasp.py @@ -29,7 +29,7 @@ import dns.tsig import dns.zone from isctest.instance import NamedInstance -from isctest.vars.algorithms import ALL_ALGORITHMS_BY_NUM, Algorithm +from isctest.vars.algorithms import ALL_ALGORITHMS_BY_NUM, ECDSAP256SHA256, Algorithm from isctest.zone import FileZoneKey import isctest.log @@ -213,7 +213,7 @@ class KeyProperties: @staticmethod def default(with_state=True) -> "KeyProperties": metadata = { - "Algorithm": isctest.vars.algorithms.ECDSAP256SHA256.number, + "Algorithm": ECDSAP256SHA256.number, "Length": 256, "Lifetime": 0, "KSK": "yes", @@ -860,7 +860,7 @@ def _check_signatures( offline_ksk=offline_ksk, zsk_missing=zsk_missing, smooth=smooth ) - alg = key.get_metadata("Algorithm") + alg = key.algorithm.number rtype = dns.rdatatype.to_text(covers) expect = rf"IN RRSIG {rtype} {alg} (\d) (\d+) (\d+) (\d+) {key.tag} {fqdn}" @@ -1622,5 +1622,5 @@ def private_type_record(zone: str, key: Key, rrtype: int = 65534) -> str: indicating that the signing process for this key is completed. """ keyid = key.tag - secalg = int(key.get_metadata("Algorithm")) - return f"{zone}. 0 IN TYPE{rrtype} \\# 5 {secalg:02x}{keyid:04x}0000" + wire_alg = key.algorithm.number + return f"{zone}. 0 IN TYPE{rrtype} \\# 5 {wire_alg:02x}{keyid:04x}0000" diff --git a/bin/tests/system/ksr/tests_ksr.py b/bin/tests/system/ksr/tests_ksr.py index b7b221c5a4..e05172e103 100644 --- a/bin/tests/system/ksr/tests_ksr.py +++ b/bin/tests/system/ksr/tests_ksr.py @@ -318,7 +318,7 @@ def check_rrsig_bundle(bundle_keys, bundle_lines, zone, rrtype, sigend, sigstart count = 0 for key in bundle_keys: found = False - alg = key.get_metadata("Algorithm") + alg = key.algorithm.number expect = f"{zone}. {ttl} IN RRSIG {rrtype} {alg} 2 {ttl} {sigend} {sigstart} {key.tag} {zone}." # there must be a signature of this ksk for line in bundle_lines: From 9a420bde2f6e9088dda08993eea6eee596cb173b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nicki=20K=C5=99=C3=AD=C5=BEek?= Date: Tue, 16 Jun 2026 16:38:53 +0200 Subject: [PATCH 6/7] Add private_key support to all ZoneKey implementations Extend the ZoneKeyFile to read the file-backed private key and return it in a format suitable for use with dnspython. Add ZoneKey.private_key property to unify the interface. (cherry picked from commit ee73ba3bbaef6352dfeca8ebee53c78657e793e9) --- bin/tests/system/isctest/zone.py | 74 ++++++++++++++++++++++++++++++-- 1 file changed, 71 insertions(+), 3 deletions(-) diff --git a/bin/tests/system/isctest/zone.py b/bin/tests/system/isctest/zone.py index a7ba22db90..8f5a886627 100644 --- a/bin/tests/system/isctest/zone.py +++ b/bin/tests/system/isctest/zone.py @@ -16,6 +16,7 @@ from collections.abc import Callable from pathlib import Path from typing import TypeAlias +import base64 import shutil from cryptography.hazmat.primitives import serialization @@ -32,7 +33,14 @@ import dns.zonefile from .log import debug from .run import EnvCmd from .template import NS1, Nameserver, TemplateEngine, TrustAnchor -from .vars.algorithms import Algorithm +from .vars.algorithms import ( + ALL_ALGORITHMS_BY_NUM, + ECDSAP256SHA256, + ECDSAP384SHA384, + ED448, + ED25519, + Algorithm, +) KEYDIR = "keys" DNSKEY_TTL = 3600 @@ -61,7 +69,16 @@ class ZoneKey(ABC): @property @abstractmethod def dnskey(self) -> dns.rrset.RRset: - """The DNSKEY RRset for this key (single-record, with TTL).""" + """ + The DNSKEY RRset for this key (single-record, with TTL). + """ + + @property + @abstractmethod + def private_key(self) -> PrivateKey: + """ + The dnspython private-key object, for use with dns.dnssec signing. + """ def is_ksk(self) -> bool: return bool(self.dnskey[0].flags & int(Flag.SEP)) @@ -142,6 +159,53 @@ class FileZoneKey(ZoneKey): ), f"DNSKEY not found in {self.keyfile}" return dnskey_rr + @property + def private_key(self) -> PrivateKey: + """ + Read the .private file and build the corresponding cryptography + private-key object, dispatching on the DNSKEY algorithm. + + Supports the RSA, ECDSA and EdDSA families; other algorithms raise + NotImplementedError. + """ + alg = ALL_ALGORITHMS_BY_NUM[self.dnskey[0].algorithm] + + fields = {} + with open(self.privatefile, "r", encoding="utf-8") as file: + for line in file: + name, sep, value = line.partition(":") + if sep: + fields[name.strip()] = value.strip() + + def field(name: str) -> bytes: + return base64.b64decode(fields[name]) + + if "Modulus" in fields: # RSA family, including the private-OID variants + public = rsa.RSAPublicNumbers( + int.from_bytes(field("PublicExponent"), "big"), + int.from_bytes(field("Modulus"), "big"), + ) + return rsa.RSAPrivateNumbers( + p=int.from_bytes(field("Prime1"), "big"), + q=int.from_bytes(field("Prime2"), "big"), + d=int.from_bytes(field("PrivateExponent"), "big"), + dmp1=int.from_bytes(field("Exponent1"), "big"), + dmq1=int.from_bytes(field("Exponent2"), "big"), + iqmp=int.from_bytes(field("Coefficient"), "big"), + public_numbers=public, + ).private_key() + + secret = field("PrivateKey") + if alg == ECDSAP256SHA256: + return ec.derive_private_key(int.from_bytes(secret, "big"), ec.SECP256R1()) + if alg == ECDSAP384SHA384: + return ec.derive_private_key(int.from_bytes(secret, "big"), ec.SECP384R1()) + if alg == ED25519: + return ed25519.Ed25519PrivateKey.from_private_bytes(secret) + if alg == ED448: + return ed448.Ed448PrivateKey.from_private_bytes(secret) + raise NotImplementedError(f"dnskey algorithm {alg.name} not implemented") + def write_dsset( self, target_dir: Path | str, @@ -215,10 +279,14 @@ class PythonZoneKey(ZoneKey): ttl: int = DNSKEY_TTL, ) -> None: self.zone = zone - self.private_key = private_key + self._private_key = private_key self._dnskey_rdata = dnskey_rdata self.ttl = ttl + @property + def private_key(self) -> PrivateKey: + return self._private_key + @property def dnskey(self) -> dns.rrset.RRset: rrset = dns.rrset.RRset( From 4a93ba83a9652e91e2b71c20c4f4db4fe28f0754 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nicki=20K=C5=99=C3=AD=C5=BEek?= Date: Tue, 16 Jun 2026 16:23:23 +0000 Subject: [PATCH 7/7] Move algorithm definitions into a top-level isctest.algorithms module The Algorithm type, the per-algorithm constants, and the ALL_ALGORITHMS* lookup tables are general DNSSEC key definitions used across isctest package and the tests. Move them into a dedicated module to separate these from the environment-specific setup that remains in isctest.vars.algorithms. Assisted-by: Claude:claude-opus-4-8 (cherry picked from commit 4d76b7bd9eb6c5b96f43b6f14919b1c762e15e31) --- bin/tests/system/conftest.py | 2 +- bin/tests/system/dnssec_py/tests_mixed_ds.py | 2 +- bin/tests/system/isctest/__init__.py | 2 + bin/tests/system/isctest/algorithms.py | 51 +++++++++++++++++++ bin/tests/system/isctest/kasp.py | 2 +- bin/tests/system/isctest/vars/algorithms.py | 46 ++++------------- bin/tests/system/isctest/zone.py | 8 +-- bin/tests/system/kasp/tests_kasp.py | 2 +- bin/tests/system/ksr/tests_ksr.py | 2 +- .../system/migrate2kasp/tests_migrate2kasp.py | 2 +- bin/tests/system/nsec3/tests_nsec3_change.py | 2 +- bin/tests/system/nsec3/tests_nsec3_initial.py | 2 +- .../system/nsec3/tests_nsec3_reconfig.py | 2 +- bin/tests/system/nsec3/tests_nsec3_restart.py | 2 +- .../system/nsec3/tests_nsec3_retransfer.py | 2 +- bin/tests/system/rollover/setup.py | 2 +- .../system/rollover/tests_rollover_manual.py | 2 +- 17 files changed, 80 insertions(+), 53 deletions(-) create mode 100644 bin/tests/system/isctest/algorithms.py diff --git a/bin/tests/system/conftest.py b/bin/tests/system/conftest.py index b2102edbd3..4dd279e7bd 100644 --- a/bin/tests/system/conftest.py +++ b/bin/tests/system/conftest.py @@ -274,7 +274,7 @@ def control_port(): @pytest.fixture(scope="module") def default_algorithm(): - return isctest.vars.algorithms.Algorithm.default() + return isctest.algorithms.Algorithm.default() @pytest.fixture(scope="module") diff --git a/bin/tests/system/dnssec_py/tests_mixed_ds.py b/bin/tests/system/dnssec_py/tests_mixed_ds.py index a3c9d43845..57ca84457f 100644 --- a/bin/tests/system/dnssec_py/tests_mixed_ds.py +++ b/bin/tests/system/dnssec_py/tests_mixed_ds.py @@ -12,8 +12,8 @@ from re import compile as Re from dnssec_py.common import DNSSEC_PY_MARK +from isctest.algorithms import Algorithm from isctest.template import NS2, NS3, zones -from isctest.vars.algorithms import Algorithm from isctest.zone import Zone, configure_root import isctest diff --git a/bin/tests/system/isctest/__init__.py b/bin/tests/system/isctest/__init__.py index 30256087b3..326b77f0d4 100644 --- a/bin/tests/system/isctest/__init__.py +++ b/bin/tests/system/isctest/__init__.py @@ -10,6 +10,7 @@ # information regarding copyright ownership. from . import ( # pylint: disable=redefined-builtin + algorithms, check, hypothesis, instance, @@ -29,6 +30,7 @@ from . import ( # pylint: disable=redefined-builtin # instead. __all__ = [ + "algorithms", "check", "hypothesis", "instance", diff --git a/bin/tests/system/isctest/algorithms.py b/bin/tests/system/isctest/algorithms.py new file mode 100644 index 0000000000..0950f16c63 --- /dev/null +++ b/bin/tests/system/isctest/algorithms.py @@ -0,0 +1,51 @@ +# Copyright (C) Internet Systems Consortium, Inc. ("ISC") +# +# SPDX-License-Identifier: MPL-2.0 +# +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, you can obtain one at https://mozilla.org/MPL/2.0/. +# +# See the COPYRIGHT file distributed with this work for additional +# information regarding copyright ownership. + +from typing import NamedTuple + +import os + + +class Algorithm(NamedTuple): + name: str + number: int + bits: int + + @classmethod + def default(cls): + return cls( + os.environ["DEFAULT_ALGORITHM"], + int(os.environ["DEFAULT_ALGORITHM_NUMBER"]), + int(os.environ["DEFAULT_BITS"]), + ) + + +RSASHA1 = Algorithm("RSASHA1", 5, 2048) +NSEC3RSASHA1 = Algorithm("NSEC3RSASHA1", 7, 2048) +RSASHA256 = Algorithm("RSASHA256", 8, 2048) +RSASHA512 = Algorithm("RSASHA512", 10, 2048) +ECDSAP256SHA256 = Algorithm("ECDSAP256SHA256", 13, 256) +ECDSAP384SHA384 = Algorithm("ECDSAP384SHA384", 14, 384) +ED25519 = Algorithm("ED25519", 15, 256) +ED448 = Algorithm("ED448", 16, 456) + +ALL_ALGORITHMS = [ + RSASHA1, + NSEC3RSASHA1, + RSASHA256, + RSASHA512, + ECDSAP256SHA256, + ECDSAP384SHA384, + ED25519, + ED448, +] + +ALL_ALGORITHMS_BY_NUM = {alg.number: alg for alg in ALL_ALGORITHMS} diff --git a/bin/tests/system/isctest/kasp.py b/bin/tests/system/isctest/kasp.py index a566b39615..ba7975c811 100644 --- a/bin/tests/system/isctest/kasp.py +++ b/bin/tests/system/isctest/kasp.py @@ -28,8 +28,8 @@ import dns.rdatatype import dns.tsig import dns.zone +from isctest.algorithms import ALL_ALGORITHMS_BY_NUM, ECDSAP256SHA256, Algorithm from isctest.instance import NamedInstance -from isctest.vars.algorithms import ALL_ALGORITHMS_BY_NUM, ECDSAP256SHA256, Algorithm from isctest.zone import FileZoneKey import isctest.log diff --git a/bin/tests/system/isctest/vars/algorithms.py b/bin/tests/system/isctest/vars/algorithms.py index 63b574965f..6a37546bfd 100644 --- a/bin/tests/system/isctest/vars/algorithms.py +++ b/bin/tests/system/isctest/vars/algorithms.py @@ -19,6 +19,16 @@ import tempfile import time from .. import log +from ..algorithms import ( + ALL_ALGORITHMS, + ECDSAP256SHA256, + ECDSAP384SHA384, + ED448, + ED25519, + RSASHA256, + RSASHA512, + Algorithm, +) from .basic import BASIC_VARS # Algorithms are selected randomly at runtime from a list of supported @@ -52,20 +62,6 @@ STABLE_PERIOD = 3600 * 3 """number of secs during which algorithm selection remains stable""" -class Algorithm(NamedTuple): - name: str - number: int - bits: int - - @classmethod - def default(cls): - return cls( - os.environ["DEFAULT_ALGORITHM"], - int(os.environ["DEFAULT_ALGORITHM_NUMBER"]), - int(os.environ["DEFAULT_BITS"]), - ) - - class AlgorithmSet(NamedTuple): """Collection of DEFAULT, ALTERNATIVE and DISABLED algorithms""" @@ -81,28 +77,6 @@ class AlgorithmSet(NamedTuple): "disable-algorithms" configuration option.""" -RSASHA1 = Algorithm("RSASHA1", 5, 2048) -NSEC3RSASHA1 = Algorithm("NSEC3RSASHA1", 7, 2048) -RSASHA256 = Algorithm("RSASHA256", 8, 2048) -RSASHA512 = Algorithm("RSASHA512", 10, 2048) -ECDSAP256SHA256 = Algorithm("ECDSAP256SHA256", 13, 256) -ECDSAP384SHA384 = Algorithm("ECDSAP384SHA384", 14, 384) -ED25519 = Algorithm("ED25519", 15, 256) -ED448 = Algorithm("ED448", 16, 456) - -ALL_ALGORITHMS = [ - RSASHA1, - NSEC3RSASHA1, - RSASHA256, - RSASHA512, - ECDSAP256SHA256, - ECDSAP384SHA384, - ED25519, - ED448, -] - -ALL_ALGORITHMS_BY_NUM = {alg.number: alg for alg in ALL_ALGORITHMS} - ALGORITHM_SETS = { "stable": AlgorithmSet( default=ECDSAP256SHA256, alternative=RSASHA256, disabled=ECDSAP384SHA384 diff --git a/bin/tests/system/isctest/zone.py b/bin/tests/system/isctest/zone.py index 8f5a886627..359d0f2707 100644 --- a/bin/tests/system/isctest/zone.py +++ b/bin/tests/system/isctest/zone.py @@ -30,10 +30,7 @@ import dns.rdatatype import dns.rrset import dns.zonefile -from .log import debug -from .run import EnvCmd -from .template import NS1, Nameserver, TemplateEngine, TrustAnchor -from .vars.algorithms import ( +from .algorithms import ( ALL_ALGORITHMS_BY_NUM, ECDSAP256SHA256, ECDSAP384SHA384, @@ -41,6 +38,9 @@ from .vars.algorithms import ( ED25519, Algorithm, ) +from .log import debug +from .run import EnvCmd +from .template import NS1, Nameserver, TemplateEngine, TrustAnchor KEYDIR = "keys" DNSKEY_TTL = 3600 diff --git a/bin/tests/system/kasp/tests_kasp.py b/bin/tests/system/kasp/tests_kasp.py index c4ce8f738c..63d8477692 100644 --- a/bin/tests/system/kasp/tests_kasp.py +++ b/bin/tests/system/kasp/tests_kasp.py @@ -25,9 +25,9 @@ import dns.tsig import dns.update import pytest +from isctest.algorithms import ECDSAP256SHA256, ECDSAP384SHA384, Algorithm from isctest.kasp import KeyProperties, KeyTimingMetadata from isctest.util import param -from isctest.vars.algorithms import ECDSAP256SHA256, ECDSAP384SHA384, Algorithm import isctest import isctest.mark diff --git a/bin/tests/system/ksr/tests_ksr.py b/bin/tests/system/ksr/tests_ksr.py index e05172e103..19e7e94321 100644 --- a/bin/tests/system/ksr/tests_ksr.py +++ b/bin/tests/system/ksr/tests_ksr.py @@ -18,8 +18,8 @@ import time import pytest +from isctest.algorithms import Algorithm from isctest.kasp import KeyTimingMetadata -from isctest.vars.algorithms import Algorithm from rollover.common import TIMEDELTA import isctest diff --git a/bin/tests/system/migrate2kasp/tests_migrate2kasp.py b/bin/tests/system/migrate2kasp/tests_migrate2kasp.py index 3e4150ee7f..750eee509b 100644 --- a/bin/tests/system/migrate2kasp/tests_migrate2kasp.py +++ b/bin/tests/system/migrate2kasp/tests_migrate2kasp.py @@ -15,7 +15,7 @@ import os import pytest -from isctest.vars.algorithms import Algorithm +from isctest.algorithms import Algorithm import isctest diff --git a/bin/tests/system/nsec3/tests_nsec3_change.py b/bin/tests/system/nsec3/tests_nsec3_change.py index b8a8b066e3..564a670d63 100644 --- a/bin/tests/system/nsec3/tests_nsec3_change.py +++ b/bin/tests/system/nsec3/tests_nsec3_change.py @@ -17,7 +17,7 @@ import dns.rdataclass import dns.rdatatype import pytest -from isctest.vars.algorithms import Algorithm +from isctest.algorithms import Algorithm from nsec3.common import NSEC3_MARK, check_nsec3_case import isctest diff --git a/bin/tests/system/nsec3/tests_nsec3_initial.py b/bin/tests/system/nsec3/tests_nsec3_initial.py index 0cc53c81aa..7038dc6ab0 100644 --- a/bin/tests/system/nsec3/tests_nsec3_initial.py +++ b/bin/tests/system/nsec3/tests_nsec3_initial.py @@ -15,7 +15,7 @@ import dns.rcode import dns.update import pytest -from isctest.vars.algorithms import RSASHA1, Algorithm +from isctest.algorithms import RSASHA1, Algorithm from nsec3.common import NSEC3_MARK, check_nsec3_case import isctest diff --git a/bin/tests/system/nsec3/tests_nsec3_reconfig.py b/bin/tests/system/nsec3/tests_nsec3_reconfig.py index 9efc486791..5dbb294d41 100644 --- a/bin/tests/system/nsec3/tests_nsec3_reconfig.py +++ b/bin/tests/system/nsec3/tests_nsec3_reconfig.py @@ -18,7 +18,7 @@ import dns.rdataclass import dns.rdatatype import pytest -from isctest.vars.algorithms import RSASHA1, Algorithm +from isctest.algorithms import RSASHA1, Algorithm from nsec3.common import NSEC3_MARK, check_nsec3_case import isctest diff --git a/bin/tests/system/nsec3/tests_nsec3_restart.py b/bin/tests/system/nsec3/tests_nsec3_restart.py index ca6ebef811..aed7c41781 100644 --- a/bin/tests/system/nsec3/tests_nsec3_restart.py +++ b/bin/tests/system/nsec3/tests_nsec3_restart.py @@ -14,7 +14,7 @@ import os import dns.rdatatype import pytest -from isctest.vars.algorithms import Algorithm +from isctest.algorithms import Algorithm from nsec3.common import NSEC3_MARK, check_nsec3_case, check_nsec3param import isctest diff --git a/bin/tests/system/nsec3/tests_nsec3_retransfer.py b/bin/tests/system/nsec3/tests_nsec3_retransfer.py index 6fd2e86080..fcd36c5e8d 100644 --- a/bin/tests/system/nsec3/tests_nsec3_retransfer.py +++ b/bin/tests/system/nsec3/tests_nsec3_retransfer.py @@ -16,7 +16,7 @@ import os import dns.rcode import dns.rdatatype -from isctest.vars.algorithms import RSASHA256 +from isctest.algorithms import RSASHA256 from nsec3.common import NSEC3_MARK, check_auth_nsec3, check_nsec3param import isctest diff --git a/bin/tests/system/rollover/setup.py b/bin/tests/system/rollover/setup.py index c71b871562..4aa11025ed 100644 --- a/bin/tests/system/rollover/setup.py +++ b/bin/tests/system/rollover/setup.py @@ -13,10 +13,10 @@ from pathlib import Path import shutil +from isctest.algorithms import Algorithm from isctest.kasp import private_type_record from isctest.run import EnvCmd from isctest.template import NS2, NS3, TrustAnchor, Zone -from isctest.vars.algorithms import Algorithm import isctest diff --git a/bin/tests/system/rollover/tests_rollover_manual.py b/bin/tests/system/rollover/tests_rollover_manual.py index 17d446fcc9..240de4fd8a 100644 --- a/bin/tests/system/rollover/tests_rollover_manual.py +++ b/bin/tests/system/rollover/tests_rollover_manual.py @@ -11,10 +11,10 @@ from datetime import timedelta +from isctest.algorithms import Algorithm from isctest.kasp import Ipub, Iret, KeyTimingMetadata, private_type_record from isctest.run import EnvCmd from isctest.template import NS3, Zone -from isctest.vars.algorithms import Algorithm from rollover.setup import configure_root, configure_tld import isctest