Introduce rollover/setup.py for all setup related test code.
Introduce rollover/ns1 and rollover/ns2 to create a chain of trust to
all rollover related test zones. The tld zones in rollover/ns2 contain
a DSYNC record that at a later time will be used for testing Generalized
DNS Notifications.
Write a python version of private_type_record so we can put such
records in the zone via jinja2 templating.
messages.append(f"keymgr: {zone} done")
with server.watch_log_from_start(timeout=60) as watcher:
watcher.wait_for_sequence(messages)
+
+
+def private_type_record(zone: str, key: Key, rrtype: int = 65534) -> str:
+ """
+ Write a private type record recording the state of the signing process for
+ a given zone and key, print the private type record with given RRtype,
+ indicating that the signing process for this key is completed.
+ """
+ keyid = key.tag
+ algorithm = key.get_dnsalg()
+ secalg = int(key.get_metadata("Algorithm"))
+
+ if algorithm < 256:
+ return f"{zone}. 0 IN TYPE{rrtype} \\# 5 {secalg:02x}{keyid:04x}0000"
+
+ return f"{zone}. 0 IN TYPE{rrtype} \\# 7 {secalg:02x}{keyid:04x}0000{algorithm:04x}"
self.render(template[:-3], data)
+@dataclass
+class Nameserver:
+ name: str
+ ip: str
+
+
+@dataclass
+class Zone:
+ name: str
+ filename: str
+ ns: Nameserver
+ type: str = "primary"
+
+
@dataclass
class TrustAnchor:
domain: str
import pytest
from isctest.kasp import Ipub, IpubC, Iret
+from isctest.vars.algorithms import Algorithm
pytestmark = pytest.mark.extra_artifacts(
[
"ns*/K*.private",
"ns*/K*.state",
"ns*/keygen.out.*",
+ "ns*/managed-keys.**",
"ns*/settime.out.*",
"ns*/signer.out.*",
"ns*/zones",
+ "ns1/root.db.in",
]
)
@pytest.fixture
def size():
return os.environ["DEFAULT_BITS"]
+
+
+def default_algorithm():
+ return Algorithm(
+ os.environ["DEFAULT_ALGORITHM"],
+ int(os.environ["DEFAULT_ALGORITHM_NUMBER"]),
+ int(os.environ["DEFAULT_ALGORITHM_DST_NUMBER"]),
+ int(os.environ["DEFAULT_BITS"]),
+ )
--- /dev/null
+/*
+ * 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.
+ */
+
+// NS1
+
+options {
+ query-source address 10.53.0.1;
+ notify-source 10.53.0.1;
+ transfer-source 10.53.0.1;
+ port @PORT@;
+ pid-file "named.pid";
+ listen-on { 10.53.0.1; };
+ listen-on-v6 { none; };
+ recursion no;
+ notify yes;
+};
+
+zone "." {
+ type primary;
+ file "root.db.signed";
+};
--- /dev/null
+; 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.
+
+$TTL 300
+. IN SOA . a.root.servers.nil. (
+ 2000042100 ; serial
+ 600 ; refresh
+ 600 ; retry
+ 1200 ; expire
+ 600 ; minimum
+ )
+. NS a.root-servers.nil.
+a.root-servers.nil. A 10.53.0.1
+
+{% for dnskey in dnskeys %}
+@dnskey@
+{% endfor %}
+
+{% for zone in delegations %}
+{% set ns_name = zone.ns.name + "." + zone.name %}
+@zone.name@ NS @ns_name@
+@ns_name@ A @zone.ns.ip@
+{% endfor %}
--- /dev/null
+/*
+ * 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.
+ */
+
+// NS2
+
+options {
+ query-source address 10.53.0.2;
+ notify-source 10.53.0.2;
+ transfer-source 10.53.0.2;
+ port @PORT@;
+ pid-file "named.pid";
+ listen-on { 10.53.0.2; };
+ listen-on-v6 { none; };
+ allow-transfer { any; };
+ allow-notify { 10.53.0.3; };
+ recursion no;
+ dnssec-validation no;
+};
+
+key rndc_key {
+ secret "1234abcd8765";
+ algorithm @DEFAULT_HMAC@;
+};
+
+controls {
+ inet 10.53.0.2 port @CONTROLPORT@ allow { any; } keys { rndc_key; };
+};
+
+zone "." {
+ type hint;
+ file "../../_common/root.hint";
+};
+
+{% for zone in tlds %}
+zone "@zone@" {
+ type primary;
+ file "@zone@.db.signed";
+};
+{% endfor %}
--- /dev/null
+; 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.
+
+$TTL 300
+$ORIGIN @fqdn@
+
+@fqdn@ IN SOA mname1. . (
+ 1 ; serial
+ 20 ; refresh (20 seconds)
+ 20 ; retry (20 seconds)
+ 1814400 ; expire (3 weeks)
+ 3600 ; minimum (1 hour)
+ )
+
+ NS ns2
+
+ns2 A 10.53.0.2
+ns3 A 10.53.0.3
+
+scanner A 10.53.0.2
+
+*._dsync DSYNC CDS NOTIFY @PORT@ scanner
+
+{% for dnskey in dnskeys %}
+@dnskey@
+{% endfor %}
+
+{% for zone in delegations %}
+{% set ns_name = zone.ns.name + "." + zone.name %}
+@zone.name@. NS @ns_name@.
+@ns_name@. A @zone.ns.ip@
+{% endfor %}
* information regarding copyright ownership.
*/
+{% if trust_anchors is defined %}
+include "trusted.conf";
+{% set dnssec_validation = "yes" %}
+{% else %}
+{% set dnssec_validation = "auto" %}
+{% endif %}
+
+
options {
query-source address 10.53.0.3;
notify-source 10.53.0.3;
listen-on { 10.53.0.3; };
listen-on-v6 { none; };
allow-transfer { any; };
- recursion no;
- dnssec-validation no;
+ recursion yes;
+ dnssec-validation @dnssec_validation@;
};
key rndc_key {
zone "." {
type hint;
- file "../../_common/root.hint.blackhole";
+ file "../../_common/root.hint";
};
; information regarding copyright ownership.
$TTL 300
-@ IN SOA mname1. . (
+@fqdn@ IN SOA mname1. . (
1 ; serial
20 ; refresh (20 seconds)
20 ; retry (20 seconds)
b A 10.0.0.2
c A 10.0.0.3
+{% for dnskey in dnskeys %}
+@dnskey@
+{% endfor %}
+
+{% for privaterr in privaterrs %}
+@privaterr@
+{% endfor %}
--- /dev/null
+../../_common/trusted.conf.j2
\ No newline at end of file
--- /dev/null
+# 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.
+
+import shutil
+from typing import List
+
+import isctest
+from isctest.kasp import private_type_record
+from isctest.template import Nameserver, TrustAnchor, Zone
+from rollover.common import default_algorithm
+
+
+class CmdHelper:
+ def __init__(self, env_name: str, base_params: str = ""):
+ self.bin_path = os.environ[env_name]
+ self.base_params = base_params
+
+ def __call__(self, params: str, **kwargs):
+ args = f"{self.base_params} {params}".split()
+ return isctest.run.cmd([self.bin_path] + args, **kwargs).stdout.decode("utf-8")
+
+
+def configure_tld(zonename: str, delegations: List[Zone]) -> Zone:
+ templates = isctest.template.TemplateEngine(".")
+ alg = default_algorithm()
+ keygen = CmdHelper("KEYGEN", f"-q -a {alg.number} -b {alg.bits} -L 3600")
+ signer = CmdHelper("SIGNER", "-S -g")
+
+ isctest.log.info(f"create {zonename} zone with delegations and sign")
+
+ for zone in delegations:
+ shutil.copy(f"{zone.ns.name}/dsset-{zone.name}.", "ns2/")
+
+ ksk_name = keygen(f"-f KSK {zonename}", cwd="ns2").strip()
+ zsk_name = keygen(f"{zonename}", cwd="ns2").strip()
+ ksk = isctest.kasp.Key(ksk_name, keydir="ns2")
+ zsk = isctest.kasp.Key(zsk_name, keydir="ns2")
+ dnskeys = [ksk.dnskey, zsk.dnskey]
+
+ template = "template.db.j2.manual"
+ outfile = f"{zonename}.db"
+ tdata = {
+ "fqdn": f"{zonename}.",
+ "delegations": delegations,
+ "dnskeys": dnskeys,
+ }
+ templates.render(f"ns2/{outfile}", tdata, template=f"ns2/{template}")
+ signer(f"-P -x -O full -o {zonename} -f {outfile}.signed {outfile}", cwd="ns2")
+
+ return Zone(zonename, f"{outfile}.signed", Nameserver("ns2", "10.53.0.2"))
+
+
+def configure_root(delegations: List[Zone]) -> TrustAnchor:
+ templates = isctest.template.TemplateEngine(".")
+ alg = default_algorithm()
+ keygen = CmdHelper("KEYGEN", f"-q -a {alg.number} -b {alg.bits} -L 3600")
+ signer = CmdHelper("SIGNER", "-S -g")
+
+ zonename = "."
+ isctest.log.info("create root zone with delegations and sign")
+
+ for zone in delegations:
+ shutil.copy(f"{zone.ns.name}/dsset-{zone.name}.", "ns1/")
+
+ ksk_name = keygen(f"-f KSK {zonename}", cwd="ns1").strip()
+ zsk_name = keygen(f"{zonename}", cwd="ns1").strip()
+ ksk = isctest.kasp.Key(ksk_name, keydir="ns1")
+ zsk = isctest.kasp.Key(zsk_name, keydir="ns1")
+ dnskeys = [ksk.dnskey, zsk.dnskey]
+
+ template = "root.db.j2.manual"
+ infile = "root.db.in"
+ outfile = "root.db.signed"
+ tdata = {
+ "fdqn": f"{zonename}.",
+ "delegations": delegations,
+ "dnskeys": dnskeys,
+ }
+ templates.render(f"ns1/{infile}", tdata, template=f"ns1/{template}")
+ signer(f"-P -x -O full -o {zonename} -f {outfile} {infile}", cwd="ns1")
+
+ return ksk.into_ta("static-ds")
+++ /dev/null
-#!/bin/sh -e
-
-# 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.
-
-# shellcheck source=conf.sh
-. ../conf.sh
-
-cd "ns3"
-
-setup() {
- zone="$1"
- echo_i "setting up zone: $zone"
- zonefile="${zone}.db"
- infile="${zone}.db.infile"
- echo "$zone" >>zones
-}
-
-# Make lines shorter by storing key states in environment variables.
-H="HIDDEN"
-R="RUMOURED"
-O="OMNIPRESENT"
-U="UNRETENTIVE"
-
-# Zone to test manual rollover.
-setup manual-rollover.kasp
-T="now-7d"
-keytimes="-P $T -A $T"
-KSK=$($KEYGEN -a $DEFAULT_ALGORITHM -L 3600 -f KSK $keytimes $zone 2>keygen.out.$zone.1)
-ZSK=$($KEYGEN -a $DEFAULT_ALGORITHM -L 3600 $keytimes $zone 2>keygen.out.$zone.2)
-$SETTIME -s -g $O -d $O $T -k $O $T -r $O $T "$KSK" >settime.out.$zone.1 2>&1
-$SETTIME -s -g $O -k $O $T -z $O $T "$ZSK" >settime.out.$zone.2 2>&1
-cat template.db.in "${KSK}.key" "${ZSK}.key" >"$infile"
-private_type_record $zone $DEFAULT_ALGORITHM_NUMBER "$KSK" >>"$infile"
-private_type_record $zone $DEFAULT_ALGORITHM_NUMBER "$ZSK" >>"$infile"
-cp $infile $zonefile
-$SIGNER -PS -x -o $zone -O raw -f "${zonefile}.signed" $infile >signer.out.$zone.1 2>&1
-
-# Zone to test manual rollover.
-setup manual-rollover-zrrsig-rumoured.kasp
-T2="now-2h"
-zsktimes="-P $T2 -A $T2"
-KSK=$($KEYGEN -a $DEFAULT_ALGORITHM -L 3600 -f KSK $keytimes $zone 2>keygen.out.$zone.1)
-ZSK=$($KEYGEN -a $DEFAULT_ALGORITHM -L 3600 $zsktimes $zone 2>keygen.out.$zone.2)
-$SETTIME -s -g $O -d $O $T -k $O $T -r $O $T "$KSK" >settime.out.$zone.1 2>&1
-$SETTIME -s -g $O -k $O $T2 -z $R $T2 "$ZSK" >settime.out.$zone.2 2>&1
-cat template.db.in "${KSK}.key" "${ZSK}.key" >"$infile"
-private_type_record $zone $DEFAULT_ALGORITHM_NUMBER "$KSK" >>"$infile"
-private_type_record $zone $DEFAULT_ALGORITHM_NUMBER "$ZSK" >>"$infile"
-cp $infile $zonefile
-$SIGNER -PS -x -o $zone -O raw -f "${zonefile}.signed" $infile >signer.out.$zone.1 2>&1
import os
import isctest
-from isctest.kasp import KeyTimingMetadata, Ipub, Iret
+from isctest.kasp import KeyTimingMetadata, Ipub, Iret, private_type_record
+from isctest.template import Nameserver, Zone
+
+from rollover.common import default_algorithm
+from rollover.setup import (
+ CmdHelper,
+ configure_root,
+ configure_tld,
+)
+
+
+def setup_zone(zone, ksk_time, ksk_settime, zsk_time, zsk_settime) -> Zone:
+ templates = isctest.template.TemplateEngine(".")
+ alg = default_algorithm()
+ keygen = CmdHelper("KEYGEN", f"-q -a {alg.number} -b {alg.bits} -L 3600")
+ signer = CmdHelper("SIGNER", "-S -g")
+ settime = CmdHelper("SETTIME", "-s")
+
+ isctest.log.info(f"setup {zone}")
+ template = "template.db.j2.manual"
+ outfile = f"{zone}.db"
+
+ # Configuration.
+ isctest.log.info(f"setup {zone}")
+ template = "template.db.j2.manual"
+ outfile = f"{zone}.db"
+ # Key generation.
+ ksk_name = keygen(f"-f KSK -P {ksk_time} -A {ksk_time} {zone}", cwd="ns3").strip()
+ zsk_name = keygen(f"-P {zsk_time} -A {zsk_time} {zone}", cwd="ns3").strip()
+ settime(f"{ksk_settime} {ksk_name}", cwd="ns3")
+ settime(f"{zsk_settime} {zsk_name}", cwd="ns3")
+ # Signing.
+ ksk = isctest.kasp.Key(ksk_name, keydir="ns3")
+ zsk = isctest.kasp.Key(zsk_name, keydir="ns3")
+ dnskeys = [ksk.dnskey, zsk.dnskey]
+ privaterrs = [
+ private_type_record(zone, ksk),
+ private_type_record(zone, zsk),
+ ]
+ tdata = {
+ "fqdn": f"{zone}.",
+ "dnskeys": dnskeys,
+ "privaterrs": privaterrs,
+ }
+ templates.render(f"ns3/{outfile}", tdata, template=f"ns3/{template}")
+ signer(f"-P -x -O raw -o {zone} -f {outfile}.signed {outfile}", cwd="ns3")
+
+ return Zone(zone, outfile, Nameserver("ns3", "10.53.0.3"))
+
+
+def bootstrap():
+ zones = []
+
+ zone = "manual-rollover.kasp"
+ when = "now-7d"
+ ksk_settime = f"-g OMNIPRESENT -k OMNIPRESENT {when} -r OMNIPRESENT {when} -d OMNIPRESENT {when}"
+ zsk_settime = f"-g OMNIPRESENT -k OMNIPRESENT {when} -z OMNIPRESENT {when}"
+ zones.append(setup_zone(zone, when, ksk_settime, when, zsk_settime))
+
+ zone = "manual-rollover-zrrsig-rumoured.kasp"
+ then = "now-2h"
+ ksk_settime = f"-g OMNIPRESENT -k OMNIPRESENT {when} -r OMNIPRESENT {when} -d OMNIPRESENT {when}"
+ zsk_settime = f"-g OMNIPRESENT -k OMNIPRESENT {then} -z RUMOURED {then}"
+ zones.append(setup_zone(zone, when, ksk_settime, then, zsk_settime))
+
+ # Chain of trust.
+ data = {
+ "tlds": [],
+ "trust_anchors": [],
+ }
+ tld = configure_tld("kasp", zones)
+ data["tlds"].append("kasp")
+
+ ta = configure_root([tld])
+ data["trust_anchors"].append(ta)
+
+ return data
-from rollover.common import pytestmark # pylint: disable=unused-import
CONFIG = {
"dnskey-ttl": timedelta(hours=1),