Home | History | Annotate | Line # | Download | only in rollover
      1 # Copyright (C) Internet Systems Consortium, Inc. ("ISC")
      2 #
      3 # SPDX-License-Identifier: MPL-2.0
      4 #
      5 # This Source Code Form is subject to the terms of the Mozilla Public
      6 # License, v. 2.0.  If a copy of the MPL was not distributed with this
      7 # file, you can obtain one at https://mozilla.org/MPL/2.0/.
      8 #
      9 # See the COPYRIGHT file distributed with this work for additional
     10 # information regarding copyright ownership.
     11 
     12 import shutil
     13 from typing import List
     14 
     15 import isctest
     16 from isctest.kasp import private_type_record
     17 from isctest.template import Nameserver, TrustAnchor, Zone
     18 from isctest.run import EnvCmd
     19 from rollover.common import default_algorithm
     20 
     21 
     22 def configure_tld(zonename: str, delegations: List[Zone]) -> Zone:
     23     templates = isctest.template.TemplateEngine(".")
     24     alg = default_algorithm()
     25     keygen = EnvCmd("KEYGEN", f"-q -a {alg.number} -b {alg.bits} -L 3600")
     26     signer = EnvCmd("SIGNER", "-S -g")
     27 
     28     isctest.log.info(f"create {zonename} zone with delegations and sign")
     29 
     30     for zone in delegations:
     31         try:
     32             shutil.copy(f"{zone.ns.name}/dsset-{zone.name}.", "ns2/")
     33         except FileNotFoundError:
     34             # Some delegations are unsigned.
     35             pass
     36 
     37     ksk_name = keygen(f"-f KSK {zonename}", cwd="ns2").out.strip()
     38     zsk_name = keygen(f"{zonename}", cwd="ns2").out.strip()
     39     ksk = isctest.kasp.Key(ksk_name, keydir="ns2")
     40     zsk = isctest.kasp.Key(zsk_name, keydir="ns2")
     41     dnskeys = [ksk.dnskey, zsk.dnskey]
     42 
     43     template = "template.db.j2.manual"
     44     outfile = f"{zonename}.db"
     45     tdata = {
     46         "fqdn": f"{zonename}.",
     47         "delegations": delegations,
     48         "dnskeys": dnskeys,
     49     }
     50     templates.render(f"ns2/{outfile}", tdata, template=f"ns2/{template}")
     51     signer(f"-P -x -O full -o {zonename} -f {outfile}.signed {outfile}", cwd="ns2")
     52 
     53     return Zone(zonename, f"{outfile}.signed", Nameserver("ns2", "10.53.0.2"))
     54 
     55 
     56 def configure_root(delegations: List[Zone]) -> TrustAnchor:
     57     templates = isctest.template.TemplateEngine(".")
     58     alg = default_algorithm()
     59     keygen = EnvCmd("KEYGEN", f"-q -a {alg.number} -b {alg.bits} -L 3600")
     60     signer = EnvCmd("SIGNER", "-S -g")
     61 
     62     zonename = "."
     63     isctest.log.info("create root zone with delegations and sign")
     64 
     65     for zone in delegations:
     66         shutil.copy(f"{zone.ns.name}/dsset-{zone.name}.", "ns1/")
     67 
     68     ksk_name = keygen(f"-f KSK {zonename}", cwd="ns1").out.strip()
     69     zsk_name = keygen(f"{zonename}", cwd="ns1").out.strip()
     70     ksk = isctest.kasp.Key(ksk_name, keydir="ns1")
     71     zsk = isctest.kasp.Key(zsk_name, keydir="ns1")
     72     dnskeys = [ksk.dnskey, zsk.dnskey]
     73 
     74     template = "root.db.j2.manual"
     75     infile = "root.db.in"
     76     outfile = "root.db.signed"
     77     tdata = {
     78         "fdqn": f"{zonename}.",
     79         "delegations": delegations,
     80         "dnskeys": dnskeys,
     81     }
     82     templates.render(f"ns1/{infile}", tdata, template=f"ns1/{template}")
     83     signer(f"-P -x -O full -o {zonename} -f {outfile} {infile}", cwd="ns1")
     84 
     85     return ksk.into_ta("static-ds")
     86 
     87 
     88 def fake_lifetime(key: str, lifetime: int):
     89     """
     90     Fake lifetime of key.
     91     """
     92     with open(f"ns3/{key}.state", "a", encoding="utf-8") as statefile:
     93         statefile.write(f"Lifetime: {lifetime}\n")
     94 
     95 
     96 def set_key_relationship(key1: str, key2: str):
     97     """
     98     Set in the key state files the Predecessor/Successor fields.
     99     """
    100     predecessor = isctest.kasp.Key(key1, keydir="ns3")
    101     successor = isctest.kasp.Key(key2, keydir="ns3")
    102 
    103     with open(f"ns3/{key1}.state", "a", encoding="utf-8") as statefile:
    104         statefile.write(f"Successor: {successor.tag}\n")
    105 
    106     with open(f"ns3/{key2}.state", "a", encoding="utf-8") as statefile:
    107         statefile.write(f"Predecessor: {predecessor.tag}\n")
    108 
    109 
    110 def render_and_sign_zone(
    111     zonename: str, keys: List[str], signing: bool = True, extra_options: str = ""
    112 ):
    113     dnskeys = []
    114     privaterrs = []
    115     for key_name in keys:
    116         key = isctest.kasp.Key(key_name, keydir="ns3")
    117         privaterr = private_type_record(zonename, key)
    118         dnskeys.append(key.dnskey)
    119         privaterrs.append(privaterr)
    120 
    121     outfile = f"{zonename}.db"
    122     templates = isctest.template.TemplateEngine(".")
    123     template = "template.db.j2.manual"
    124     tdata = {
    125         "fqdn": f"{zonename}.",
    126         "dnskeys": dnskeys,
    127         "privaterrs": privaterrs,
    128     }
    129     templates.render(f"ns3/{outfile}", tdata, template=f"ns3/{template}")
    130 
    131     if signing:
    132         signer = EnvCmd("SIGNER", "-S -g -x -s now-1h -e now+2w -O raw")
    133         signer(
    134             f"{extra_options} -o {zonename} -f {outfile}.signed {outfile}", cwd="ns3"
    135         )
    136 
    137 
    138 def configure_algo_csk(tld: str, policy: str, reconfig: bool = False) -> List[Zone]:
    139     # The zones at csk-algorithm-roll.$tld represent the various steps
    140     # of a CSK algorithm rollover.
    141     zones = []
    142     zone = f"csk-algorithm-roll.{tld}"
    143     keygen = EnvCmd("KEYGEN", f"-k {policy}")
    144     settime = EnvCmd("SETTIME", "-s")
    145 
    146     # Step 1:
    147     # Introduce the first key. This will immediately be active.
    148     zonename = f"step1.{zone}"
    149     zones.append(Zone(zonename, f"{zonename}.db", Nameserver("ns3", "10.53.0.3")))
    150     isctest.log.info(f"setup {zonename}")
    151     TactN = "now-7d"
    152     TsbmN = "now-161h"
    153     csktimes = f"-P {TactN} -A {TactN}"
    154     # Key generation.
    155     csk_name = keygen(f"-l csk1.conf {csktimes} {zonename}", cwd="ns3").out.strip()
    156     settime(
    157         f"-g OMNIPRESENT -k OMNIPRESENT {TactN} -r OMNIPRESENT {TactN} -z OMNIPRESENT {TactN} -d OMNIPRESENT {TactN} {csk_name}",
    158         cwd="ns3",
    159     )
    160     # Signing.
    161     render_and_sign_zone(zonename, [csk_name], extra_options="-z")
    162 
    163     if reconfig:
    164         # Step 2:
    165         # After the publication interval has passed the DNSKEY is OMNIPRESENT.
    166         zonename = f"step2.{zone}"
    167         zones.append(Zone(zonename, f"{zonename}.db", Nameserver("ns3", "10.53.0.3")))
    168         isctest.log.info(f"setup {zonename}")
    169         # The time passed since the new algorithm keys have been introduced is 3 hours.
    170         TpubN1 = "now-3h"
    171         csktimes = f"-P {TactN} -A {TactN} -P sync {TsbmN} -I now"
    172         newtimes = f"-P {TpubN1} -A {TpubN1}"
    173         # Key generation.
    174         csk1_name = keygen(f"-l csk1.conf {csktimes} {zonename}", cwd="ns3").out.strip()
    175         csk2_name = keygen(f"-l csk2.conf {newtimes} {zonename}", cwd="ns3").out.strip()
    176         settime(
    177             f"-g HIDDEN -k OMNIPRESENT {TactN} -r OMNIPRESENT {TactN} -z OMNIPRESENT {TactN} -d OMNIPRESENT {TactN} {csk1_name}",
    178             cwd="ns3",
    179         )
    180         settime(
    181             f"-g OMNIPRESENT -k RUMOURED {TpubN1} -r RUMOURED {TpubN1} -z RUMOURED {TpubN1} -d HIDDEN {TpubN1} {csk2_name}",
    182             cwd="ns3",
    183         )
    184         # Signing.
    185         render_and_sign_zone(zonename, [csk1_name, csk2_name], extra_options="-z")
    186 
    187         # Step 3:
    188         # The zone signatures are also OMNIPRESENT.
    189         zonename = f"step3.{zone}"
    190         zones.append(Zone(zonename, f"{zonename}.db", Nameserver("ns3", "10.53.0.3")))
    191         isctest.log.info(f"setup {zonename}")
    192         # The time passed since the new algorithm keys have been introduced is 7 hours.
    193         TpubN1 = "now-7h"
    194         TsbmN1 = "now"
    195         csktimes = f"-P {TactN} -A {TactN}  -P sync {TsbmN} -I {TsbmN1}"
    196         newtimes = f"-P {TpubN1} -A {TpubN1} -P sync {TsbmN1}"
    197         # Key generation.
    198         csk1_name = keygen(f"-l csk1.conf {csktimes} {zonename}", cwd="ns3").out.strip()
    199         csk2_name = keygen(f"-l csk2.conf {newtimes} {zonename}", cwd="ns3").out.strip()
    200         settime(
    201             f"-g HIDDEN -k OMNIPRESENT {TactN} -r OMNIPRESENT {TactN} -z OMNIPRESENT {TactN} -d OMNIPRESENT {TactN} {csk1_name}",
    202             cwd="ns3",
    203         )
    204         settime(
    205             f"-g OMNIPRESENT -k OMNIPRESENT {TpubN1} -r OMNIPRESENT {TpubN1} -z RUMOURED {TpubN1} -d HIDDEN {TpubN1} {csk2_name}",
    206             cwd="ns3",
    207         )
    208         # Signing.
    209         render_and_sign_zone(zonename, [csk1_name, csk2_name], extra_options="-z")
    210 
    211         # Step 4:
    212         # The DS is swapped and can become OMNIPRESENT.
    213         zonename = f"step4.{zone}"
    214         zones.append(Zone(zonename, f"{zonename}.db", Nameserver("ns3", "10.53.0.3")))
    215         isctest.log.info(f"setup {zonename}")
    216         # The time passed since the DS has been swapped is 3 hours.
    217         TpubN1 = "now-10h"
    218         TsbmN1 = "now-3h"
    219         csktimes = f"-P {TactN} -A {TactN}  -P sync {TsbmN} -I {TsbmN1}"
    220         newtimes = f"-P {TpubN1} -A {TpubN1} -P sync {TsbmN1}"
    221         # Key generation.
    222         csk1_name = keygen(f"-l csk1.conf {csktimes} {zonename}", cwd="ns3").out.strip()
    223         csk2_name = keygen(f"-l csk2.conf {newtimes} {zonename}", cwd="ns3").out.strip()
    224         settime(
    225             f"-g HIDDEN -k OMNIPRESENT {TactN} -r OMNIPRESENT {TactN} -z OMNIPRESENT {TsbmN1} -d UNRETENTIVE {TsbmN1} -D ds {TsbmN1} {csk1_name}",
    226             cwd="ns3",
    227         )
    228         settime(
    229             f"-g OMNIPRESENT -k OMNIPRESENT {TpubN1} -r OMNIPRESENT {TpubN1} -z OMNIPRESENT {TsbmN1} -d RUMOURED {TsbmN1} -P ds {TsbmN1} {csk2_name}",
    230             cwd="ns3",
    231         )
    232         # Signing.
    233         render_and_sign_zone(zonename, [csk1_name, csk2_name], extra_options="-z")
    234 
    235         # Step 5:
    236         # The DNSKEY is removed long enough to be HIDDEN.
    237         zonename = f"step5.{zone}"
    238         zones.append(Zone(zonename, f"{zonename}.db", Nameserver("ns3", "10.53.0.3")))
    239         isctest.log.info(f"setup {zonename}")
    240         # The time passed since the DNSKEY has been removed is 2 hours.
    241         TpubN1 = "now-12h"
    242         TsbmN1 = "now-5h"
    243         csktimes = f"-P {TactN} -A {TactN} -P sync {TsbmN} -I {TsbmN1}"
    244         newtimes = f"-P {TpubN1} -A {TpubN1} -P sync {TsbmN1}"
    245         # Key generation.
    246         csk1_name = keygen(f"-l csk1.conf {csktimes} {zonename}", cwd="ns3").out.strip()
    247         csk2_name = keygen(f"-l csk2.conf {newtimes} {zonename}", cwd="ns3").out.strip()
    248         settime(
    249             f"-g HIDDEN -k UNRETENTIVE {TactN} -r UNRETENTIVE {TactN} -z UNRETENTIVE {TsbmN1} -d HIDDEN {TsbmN1} {csk1_name}",
    250             cwd="ns3",
    251         )
    252         settime(
    253             f"-g OMNIPRESENT -k OMNIPRESENT {TpubN1} -r OMNIPRESENT {TpubN1} -z OMNIPRESENT {TsbmN1} -d OMNIPRESENT {TsbmN1} {csk2_name}",
    254             cwd="ns3",
    255         )
    256         # Signing.
    257         render_and_sign_zone(zonename, [csk1_name, csk2_name], extra_options="-z")
    258 
    259         # Step 6:
    260         # The RRSIGs have been removed long enough to be HIDDEN.
    261         zonename = f"step6.{zone}"
    262         zones.append(Zone(zonename, f"{zonename}.db", Nameserver("ns3", "10.53.0.3")))
    263         isctest.log.info(f"setup {zonename}")
    264         # Additional time passed: 7h.
    265         TpubN1 = "now-19h"
    266         TsbmN1 = "now-12h"
    267         csktimes = f"-P {TactN}  -A {TactN}  -P sync {TsbmN} -I {TsbmN1}"
    268         newtimes = f"-P {TpubN1} -A {TpubN1} -P sync {TsbmN1}"
    269         # Key generation.
    270         csk1_name = keygen(f"-l csk1.conf {csktimes} {zonename}", cwd="ns3").out.strip()
    271         csk2_name = keygen(f"-l csk2.conf {newtimes} {zonename}", cwd="ns3").out.strip()
    272         settime(
    273             f"-g HIDDEN -k HIDDEN {TactN} -r UNRETENTIVE {TactN} -z UNRETENTIVE {TactN} -d HIDDEN {TsbmN1} {csk1_name}",
    274             cwd="ns3",
    275         )
    276         settime(
    277             f"-g OMNIPRESENT -k OMNIPRESENT {TpubN1} -r OMNIPRESENT {TpubN1} -z OMNIPRESENT {TsbmN1} -d OMNIPRESENT {TsbmN1} {csk2_name}",
    278             cwd="ns3",
    279         )
    280         # Signing.
    281         render_and_sign_zone(zonename, [csk1_name, csk2_name], extra_options="-z")
    282 
    283     return zones
    284 
    285 
    286 def configure_algo_ksk_zsk(tld: str, reconfig: bool = False) -> List[Zone]:
    287     # The zones at algorithm-roll.$tld represent the various steps of a ZSK/KSK
    288     # algorithm rollover.
    289     zones = []
    290     zone = f"algorithm-roll.{tld}"
    291     keygen = EnvCmd("KEYGEN", "-L 3600")
    292     settime = EnvCmd("SETTIME", "-s")
    293 
    294     # Step 1:
    295     # Introduce the first key. This will immediately be active.
    296     zonename = f"step1.{zone}"
    297     zones.append(Zone(zonename, f"{zonename}.db", Nameserver("ns3", "10.53.0.3")))
    298     isctest.log.info(f"setup {zonename}")
    299     TactN = "now-7d"
    300     TsbmN = "now-161h"
    301     keytimes = f"-P {TactN} -A {TactN}"
    302     # Key generation.
    303     ksk_name = keygen(
    304         f"-a RSASHA256 -f KSK {keytimes} {zonename}", cwd="ns3"
    305     ).out.strip()
    306     zsk_name = keygen(f"-a RSASHA256 {keytimes} {zonename}", cwd="ns3").out.strip()
    307     settime(
    308         f"-g OMNIPRESENT -k OMNIPRESENT {TactN} -r OMNIPRESENT {TactN} -d OMNIPRESENT {TactN} {ksk_name}",
    309         cwd="ns3",
    310     )
    311     settime(
    312         f"-g OMNIPRESENT -k OMNIPRESENT {TactN} -z OMNIPRESENT {TactN} {zsk_name}",
    313         cwd="ns3",
    314     )
    315     # Signing.
    316     render_and_sign_zone(zonename, [ksk_name, zsk_name])
    317 
    318     if reconfig:
    319         # Step 2:
    320         # After the publication interval has passed the DNSKEY is OMNIPRESENT.
    321         zonename = f"step2.{zone}"
    322         zones.append(Zone(zonename, f"{zonename}.db", Nameserver("ns3", "10.53.0.3")))
    323         isctest.log.info(f"setup {zonename}")
    324         # The time passed since the new algorithm keys have been introduced is 3 hours.
    325         # Tsbm(N+1) = TpubN1 + Ipub = now + TTLsig + Dprp = now - 3h + 6h + 1h = now + 4h
    326         TpubN1 = "now-3h"
    327         TsbmN1 = "now+4h"
    328         ksk1times = f"-P {TactN}  -A {TactN}  -P sync {TsbmN} -I {TsbmN1}"
    329         zsk1times = f"-P {TactN}  -A {TactN}  -I {TsbmN1}"
    330         ksk2times = f"-P {TpubN1} -A {TpubN1} -P sync {TsbmN1}"
    331         zsk2times = f"-P {TpubN1} -A {TpubN1}"
    332         # Key generation.
    333         ksk1_name = keygen(
    334             f"-a RSASHA256 -f KSK {ksk1times} {zonename}", cwd="ns3"
    335         ).out.strip()
    336         zsk1_name = keygen(
    337             f"-a RSASHA256 {zsk1times} {zonename}", cwd="ns3"
    338         ).out.strip()
    339         ksk2_name = keygen(
    340             f"-a ECDSA256 -f KSK {ksk2times} {zonename}", cwd="ns3"
    341         ).out.strip()
    342         zsk2_name = keygen(f"-a ECDSA256 {zsk2times} {zonename}", cwd="ns3").out.strip()
    343         settime(
    344             f"-g HIDDEN -k OMNIPRESENT {TactN} -r OMNIPRESENT {TactN} -d OMNIPRESENT {TactN} {ksk1_name}",
    345             cwd="ns3",
    346         )
    347         settime(
    348             f"-g HIDDEN -k OMNIPRESENT {TactN} -z OMNIPRESENT {TactN} {zsk1_name}",
    349             cwd="ns3",
    350         )
    351         settime(
    352             f"-g OMNIPRESENT -k RUMOURED {TpubN1} -r RUMOURED {TpubN1} -d HIDDEN {TpubN1} {ksk2_name}",
    353             cwd="ns3",
    354         )
    355         settime(
    356             f"-g OMNIPRESENT -k RUMOURED {TpubN1} -z RUMOURED {TpubN1} {zsk2_name}",
    357             cwd="ns3",
    358         )
    359         # Signing.
    360         fake_lifetime(ksk1_name, 0)
    361         fake_lifetime(zsk1_name, 0)
    362         render_and_sign_zone(zonename, [ksk1_name, zsk1_name, ksk2_name, zsk2_name])
    363 
    364         # Step 3:
    365         # The zone signatures are also OMNIPRESENT.
    366         zonename = f"step3.{zone}"
    367         zones.append(Zone(zonename, f"{zonename}.db", Nameserver("ns3", "10.53.0.3")))
    368         isctest.log.info(f"setup {zonename}")
    369         # The time passed since the new algorithm keys have been introduced is 7 hours.
    370         TpubN1 = "now-7h"
    371         TsbmN1 = "now"
    372         ksk1times = f"-P {TactN} -A {TactN} -P sync {TsbmN} -I {TsbmN1}"
    373         zsk1times = f"-P {TactN} -A {TactN} -I {TsbmN1}"
    374         ksk2times = f"-P {TpubN1} -A {TpubN1} -P sync {TsbmN1}"
    375         zsk2times = f"-P {TpubN1} -A {TpubN1}"
    376         # Key generation.
    377         ksk1_name = keygen(
    378             f"-a RSASHA256 -f KSK {ksk1times} {zonename}", cwd="ns3"
    379         ).out.strip()
    380         zsk1_name = keygen(
    381             f"-a RSASHA256 {zsk1times} {zonename}", cwd="ns3"
    382         ).out.strip()
    383         ksk2_name = keygen(
    384             f"-a ECDSA256 -f KSK {ksk2times} {zonename}", cwd="ns3"
    385         ).out.strip()
    386         zsk2_name = keygen(f"-a ECDSA256 {zsk2times} {zonename}", cwd="ns3").out.strip()
    387         settime(
    388             f"-g HIDDEN -k OMNIPRESENT {TactN} -r OMNIPRESENT {TactN} -d OMNIPRESENT {TactN} {ksk1_name}",
    389             cwd="ns3",
    390         )
    391         settime(
    392             f"-g HIDDEN -k OMNIPRESENT {TactN} -z OMNIPRESENT {TactN} {zsk1_name}",
    393             cwd="ns3",
    394         )
    395         settime(
    396             f"-g OMNIPRESENT -k OMNIPRESENT {TpubN1} -r OMNIPRESENT {TpubN1} -d HIDDEN {TpubN1} {ksk2_name}",
    397             cwd="ns3",
    398         )
    399         settime(
    400             f"-g OMNIPRESENT -k OMNIPRESENT {TpubN1} -z RUMOURED {TpubN1} {zsk2_name}",
    401             cwd="ns3",
    402         )
    403         # Signing.
    404         fake_lifetime(ksk1_name, 0)
    405         fake_lifetime(zsk1_name, 0)
    406         render_and_sign_zone(zonename, [ksk1_name, zsk1_name, ksk2_name, zsk2_name])
    407 
    408         # Step 4:
    409         # The DS is swapped and can become OMNIPRESENT.
    410         zonename = f"step4.{zone}"
    411         zones.append(Zone(zonename, f"{zonename}.db", Nameserver("ns3", "10.53.0.3")))
    412         isctest.log.info(f"setup {zonename}")
    413         # The time passed since the DS has been swapped is 3 hours.
    414         TpubN1 = "now-10h"
    415         TsbmN1 = "now-3h"
    416         ksk1times = f"-P {TactN} -A {TactN} -P sync {TsbmN} -I {TsbmN1}"
    417         zsk1times = f"-P {TactN} -A {TactN} -I {TsbmN1}"
    418         ksk2times = f"-P {TpubN1} -A {TpubN1} -P sync {TsbmN1}"
    419         zsk2times = f"-P {TpubN1} -A {TpubN1}"
    420         # Key generation.
    421         ksk1_name = keygen(
    422             f"-a RSASHA256 -f KSK {ksk1times} {zonename}", cwd="ns3"
    423         ).out.strip()
    424         zsk1_name = keygen(
    425             f"-a RSASHA256 {zsk1times} {zonename}", cwd="ns3"
    426         ).out.strip()
    427         ksk2_name = keygen(
    428             f"-a ECDSA256 -f KSK {ksk2times} {zonename}", cwd="ns3"
    429         ).out.strip()
    430         zsk2_name = keygen(f"-a ECDSA256 {zsk2times} {zonename}", cwd="ns3").out.strip()
    431         settime(
    432             f"-g HIDDEN -k OMNIPRESENT {TactN} -r OMNIPRESENT {TactN} -d UNRETENTIVE {TsbmN1} -D ds {TsbmN1} {ksk1_name}",
    433             cwd="ns3",
    434         )
    435         settime(
    436             f"-g HIDDEN -k OMNIPRESENT {TactN} -z OMNIPRESENT {TactN} {zsk1_name}",
    437             cwd="ns3",
    438         )
    439         settime(
    440             f"-g OMNIPRESENT -k OMNIPRESENT {TpubN1} -r OMNIPRESENT {TpubN1} -d RUMOURED {TsbmN1} -P ds {TsbmN1} {ksk2_name}",
    441             cwd="ns3",
    442         )
    443         settime(
    444             f"-g OMNIPRESENT -k OMNIPRESENT {TpubN1} -z RUMOURED {TpubN1} {zsk2_name}",
    445             cwd="ns3",
    446         )
    447         # Signing.
    448         fake_lifetime(ksk1_name, 0)
    449         fake_lifetime(zsk1_name, 0)
    450         render_and_sign_zone(zonename, [ksk1_name, zsk1_name, ksk2_name, zsk2_name])
    451 
    452         # Step 5:
    453         # The DNSKEY is removed long enough to be HIDDEN.
    454         zonename = f"step5.{zone}"
    455         zones.append(Zone(zonename, f"{zonename}.db", Nameserver("ns3", "10.53.0.3")))
    456         isctest.log.info(f"setup {zonename}")
    457         # The time passed since the DNSKEY has been removed is 2 hours.
    458         TpubN1 = "now-12h"
    459         TsbmN1 = "now-5h"
    460         ksk1times = f"-P {TactN} -A {TactN} -P sync {TsbmN} -I {TsbmN1}"
    461         zsk1times = f"-P {TactN} -A {TactN} -I {TsbmN1}"
    462         ksk2times = f"-P {TpubN1} -A {TpubN1} -P sync {TsbmN1}"
    463         zsk2times = f"-P {TpubN1} -A {TpubN1}"
    464         # Key generation.
    465         ksk1_name = keygen(
    466             f"-a RSASHA256 -f KSK {ksk1times} {zonename}", cwd="ns3"
    467         ).out.strip()
    468         zsk1_name = keygen(
    469             f"-a RSASHA256 {zsk1times} {zonename}", cwd="ns3"
    470         ).out.strip()
    471         ksk2_name = keygen(
    472             f"-a ECDSA256 -f KSK {ksk2times} {zonename}", cwd="ns3"
    473         ).out.strip()
    474         zsk2_name = keygen(f"-a ECDSA256 {zsk2times} {zonename}", cwd="ns3").out.strip()
    475         settime(
    476             f"-g HIDDEN -k UNRETENTIVE {TsbmN1} -r UNRETENTIVE {TsbmN1} -d HIDDEN {TsbmN1} {ksk1_name}",
    477             cwd="ns3",
    478         )
    479         settime(
    480             f"-g HIDDEN -k UNRETENTIVE {TsbmN1} -z UNRETENTIVE {TsbmN1} {zsk1_name}",
    481             cwd="ns3",
    482         )
    483         settime(
    484             f"-g OMNIPRESENT -k OMNIPRESENT {TpubN1} -r OMNIPRESENT {TpubN1} -d OMNIPRESENT {TsbmN1} {ksk2_name}",
    485             cwd="ns3",
    486         )
    487         settime(
    488             f"-g OMNIPRESENT -k OMNIPRESENT {TpubN1} -z RUMOURED {TpubN1} {zsk2_name}",
    489             cwd="ns3",
    490         )
    491         # Signing.
    492         fake_lifetime(ksk1_name, 0)
    493         fake_lifetime(zsk1_name, 0)
    494         render_and_sign_zone(zonename, [ksk1_name, zsk1_name, ksk2_name, zsk2_name])
    495 
    496         # Step 6:
    497         # The RRSIGs have been removed long enough to be HIDDEN.
    498         zonename = f"step6.{zone}"
    499         zones.append(Zone(zonename, f"{zonename}.db", Nameserver("ns3", "10.53.0.3")))
    500         isctest.log.info(f"setup {zonename}")
    501         # Additional time passed: 7h.
    502         TpubN1 = "now-19h"
    503         TsbmN1 = "now-12h"
    504         ksk1times = f"-P {TactN} -A {TactN} -P sync {TsbmN} -I {TsbmN1}"
    505         zsk1times = f"-P {TactN} -A {TactN} -I {TsbmN1}"
    506         ksk2times = f"-P {TpubN1} -A {TpubN1} -P sync {TsbmN1}"
    507         zsk2times = f"-P {TpubN1} -A {TpubN1}"
    508         ksk1_name = keygen(
    509             f"-a RSASHA256 -f KSK {ksk1times} {zonename}", cwd="ns3"
    510         ).out.strip()
    511         zsk1_name = keygen(
    512             f"-a RSASHA256 {zsk1times} {zonename}", cwd="ns3"
    513         ).out.strip()
    514         ksk2_name = keygen(
    515             f"-a ECDSA256 -f KSK {ksk2times} {zonename}", cwd="ns3"
    516         ).out.strip()
    517         zsk2_name = keygen(f"-a ECDSA256 {zsk2times} {zonename}", cwd="ns3").out.strip()
    518         settime(
    519             f"-g HIDDEN -k HIDDEN {TsbmN1} -r UNRETENTIVE {TsbmN1} -d HIDDEN {TsbmN1} {ksk1_name}",
    520             cwd="ns3",
    521         )
    522         settime(
    523             f"-g HIDDEN -k HIDDEN {TsbmN1} -z UNRETENTIVE {TsbmN1} {zsk1_name}",
    524             cwd="ns3",
    525         )
    526         settime(
    527             f"-g OMNIPRESENT -k OMNIPRESENT {TpubN1} -r OMNIPRESENT {TpubN1} -d OMNIPRESENT {TsbmN1} {ksk2_name}",
    528             cwd="ns3",
    529         )
    530         settime(
    531             f"-g OMNIPRESENT -k OMNIPRESENT {TpubN1} -z RUMOURED {TpubN1} {zsk2_name}",
    532             cwd="ns3",
    533         )
    534         # Signing.
    535         fake_lifetime(ksk1_name, 0)
    536         fake_lifetime(zsk1_name, 0)
    537         render_and_sign_zone(zonename, [ksk1_name, zsk1_name, ksk2_name, zsk2_name])
    538 
    539     return zones
    540 
    541 
    542 def configure_cskroll1(tld: str, policy: str) -> List[Zone]:
    543     # The zones at csk-roll1.$tld represent the various steps of a CSK rollover
    544     # (which is essentially a ZSK Pre-Publication / KSK Double-KSK rollover).
    545     zones = []
    546     zone = f"csk-roll1.{tld}"
    547     cds = "cdnskey,cds:sha384"
    548     keygen = EnvCmd("KEYGEN", f"-k {policy} -l kasp.conf")
    549     settime = EnvCmd("SETTIME", "-s")
    550 
    551     # Step 1:
    552     # Introduce the first key. This will immediately be active.
    553     zonename = f"step1.{zone}"
    554     zones.append(Zone(zonename, f"{zonename}.db", Nameserver("ns3", "10.53.0.3")))
    555     isctest.log.info(f"setup {zonename}")
    556     TactN = "now-7d"
    557     keytimes = f"-P {TactN} -A {TactN}"
    558     # Key generation.
    559     csk_name = keygen(f"{keytimes} {zonename}", cwd="ns3").out.strip()
    560     settime(
    561         f"-g OMNIPRESENT -k OMNIPRESENT {TactN} -r OMNIPRESENT {TactN} -z OMNIPRESENT {TactN} -d OMNIPRESENT {TactN} {csk_name}",
    562         cwd="ns3",
    563     )
    564     # Signing.
    565     render_and_sign_zone(zonename, [csk_name], extra_options=f"-z -G {cds}")
    566 
    567     # Step 2:
    568     # It is time to introduce the new CSK.
    569     zonename = f"step2.{zone}"
    570     zones.append(Zone(zonename, f"{zonename}.db", Nameserver("ns3", "10.53.0.3")))
    571     isctest.log.info(f"setup {zonename}")
    572     # According to RFC 7583:
    573     # KSK: Tpub(N+1) <= Tact(N) + Lksk - IpubC
    574     # ZSK: Tpub(N+1) <= Tact(N) + Lzsk - Ipub
    575     # IpubC = DprpC + TTLkey (+publish-safety)
    576     # Ipub  = IpubC
    577     # Lcsk = Lksk = Lzsk
    578     #
    579     # Lcsk:           6mo (186d, 4464h)
    580     # Dreg:           N/A
    581     # DprpC:          1h
    582     # TTLkey:         1h
    583     # publish-safety: 1h
    584     # Ipub:           3h
    585     #
    586     # Tact(N) = now - Lcsk + Ipub = now - 186d + 3h
    587     #         = now - 4464h + 3h  = now - 4461h
    588     TactN = "now-4461h"
    589     keytimes = f"-P {TactN} -A {TactN}"
    590     # Key generation.
    591     csk_name = keygen(f"{keytimes} {zonename}", cwd="ns3").out.strip()
    592     settime(
    593         f"-g OMNIPRESENT -k OMNIPRESENT {TactN} -r OMNIPRESENT {TactN} -z OMNIPRESENT {TactN} -d OMNIPRESENT {TactN} {csk_name}",
    594         cwd="ns3",
    595     )
    596     # Signing.
    597     render_and_sign_zone(zonename, [csk_name], extra_options=f"-z -G {cds}")
    598 
    599     # Step 3:
    600     # It is time to submit the DS and to roll signatures.
    601     zonename = f"step3.{zone}"
    602     zones.append(Zone(zonename, f"{zonename}.db", Nameserver("ns3", "10.53.0.3")))
    603     isctest.log.info(f"setup {zonename}")
    604     # According to RFC 7583:
    605     #
    606     # Tsbm(N+1) >= Trdy(N+1)
    607     # KSK: Tact(N+1) = Tsbm(N+1)
    608     # ZSK: Tact(N+1) = Tpub(N+1) + Ipub = Tsbm(N+1)
    609     # KSK: Iret  = DprpP + TTLds (+retire-safety)
    610     # ZSK: IretZ = Dsgn + Dprp + TTLsig (+retire-safety)
    611     #
    612     # Lcsk:           186d
    613     # Dprp:           1h
    614     # DprpP:          1h
    615     # Dreg:           N/A
    616     # Dsgn:           25d
    617     # TTLds:          1h
    618     # TTLsig:         1d
    619     # retire-safety:  2h
    620     # Iret:           4h
    621     # IretZ:          26d3h
    622     # Ipub:           3h
    623     #
    624     # Tpub(N)   = now - Lcsk = now - 186d
    625     # Tact(N)   = now - Lcsk + Dprp + TTLsig = now - 4439h
    626     # Tret(N)   = now
    627     # Trem(N)   = now + IretZ = now + 26d3h = now + 627h
    628     # Tpub(N+1) = now - Ipub = now - 3h
    629     # Tact(N+1) = Tret(N)
    630     # Tret(N+1) = now + Lcsk = now + 186d = now + 186d
    631     # Trem(N+1) = now + Lcsk + IretZ = now + 186d + 26d3h =
    632     #           = now + 5091h
    633     TpubN = "now-186d"
    634     TactN = "now-4439h"
    635     TretN = "now"
    636     TremN = "now+627h"
    637     TpubN1 = "now-3h"
    638     TactN1 = TretN
    639     TretN1 = "now+186d"
    640     TremN1 = "now+5091h"
    641     keytimes = (
    642         f"-P {TpubN} -P sync {TactN} -A {TpubN} -I {TretN} -D {TremN} -D sync {TactN1}"
    643     )
    644     newtimes = f"-P {TpubN1} -P sync {TactN1} -A {TactN1} -I {TretN1} -D {TremN1}"
    645     # Key generation.
    646     csk1_name = keygen(f"{keytimes} {zonename}", cwd="ns3").out.strip()
    647     csk2_name = keygen(f"{newtimes} {zonename}", cwd="ns3").out.strip()
    648     settime(
    649         f"-g HIDDEN -k OMNIPRESENT {TactN} -r OMNIPRESENT {TactN} -z OMNIPRESENT {TactN} -d OMNIPRESENT {TactN} {csk1_name}",
    650         cwd="ns3",
    651     )
    652     settime(
    653         f"-g OMNIPRESENT -k RUMOURED {TpubN1} -r RUMOURED {TpubN1} -z HIDDEN {TpubN1} -d HIDDEN {TpubN1} {csk2_name}",
    654         cwd="ns3",
    655     )
    656     # Set key rollover relationship.
    657     set_key_relationship(csk1_name, csk2_name)
    658     # Signing.
    659     render_and_sign_zone(zonename, [csk1_name, csk2_name], extra_options=f"-z -G {cds}")
    660 
    661     # Step 4:
    662     # Some time later all the ZRRSIG records should be from the new CSK, and the
    663     # DS should be swapped.  The ZRRSIG records are all replaced after IretZ
    664     # (which is 26d3h).  The DS is swapped after Iret (which is 4h).
    665     # In other words, the DS is swapped before all zone signatures are replaced.
    666     zonename = f"step4.{zone}"
    667     zones.append(Zone(zonename, f"{zonename}.db", Nameserver("ns3", "10.53.0.3")))
    668     isctest.log.info(f"setup {zonename}")
    669     # According to RFC 7583:
    670     # Trem(N)    = Tret(N) - Iret + IretZ
    671     # now       = Tsbm(N+1) + Iret
    672     #
    673     # Lcsk:   186d
    674     # Iret:   4h
    675     # IretZ:  26d3h
    676     #
    677     # Tpub(N)   = now - Iret - Lcsk = now - 4h - 186d = now - 4468h
    678     # Tret(N)   = now - Iret = now - 4h = now - 4h
    679     # Trem(N)   = now - Iret + IretZ = now - 4h + 26d3h
    680     #           = now + 623h
    681     # Tpub(N+1) = now - Iret - IpubC = now - 4h - 3h = now - 7h
    682     # Tact(N+1) = Tret(N)
    683     # Tret(N+1) = now - Iret + Lcsk = now - 4h + 186d = now + 4460h
    684     # Trem(N+1) = now - Iret + Lcsk + IretZ = now - 4h + 186d + 26d3h
    685     #           = now + 5087h
    686     TpubN = "now-4468h"
    687     TactN = "now-4443h"
    688     TretN = "now-4h"
    689     TremN = "now+623h"
    690     TpubN1 = "now-7h"
    691     TactN1 = TretN
    692     TretN1 = "now+4460h"
    693     TremN1 = "now+5087h"
    694     keytimes = (
    695         f"-P {TpubN} -P sync {TactN} -A {TpubN} -I {TretN} -D {TremN} -D sync {TactN1}"
    696     )
    697     newtimes = f"-P {TpubN1} -P sync {TactN1} -A {TactN1} -I {TretN1} -D {TremN1}"
    698     # Key generation.
    699     csk1_name = keygen(f"{keytimes} {zonename}", cwd="ns3").out.strip()
    700     csk2_name = keygen(f"{newtimes} {zonename}", cwd="ns3").out.strip()
    701     settime(
    702         f"-g HIDDEN -k OMNIPRESENT {TactN} -r OMNIPRESENT {TactN} -z UNRETENTIVE {TactN1} -d UNRETENTIVE {TactN1} -D ds {TactN1} {csk1_name}",
    703         cwd="ns3",
    704     )
    705     settime(
    706         f"-g OMNIPRESENT -k OMNIPRESENT {TactN1} -r OMNIPRESENT {TactN1} -z RUMOURED {TactN1} -d RUMOURED {TactN1} -P ds {TactN1} {csk2_name}",
    707         cwd="ns3",
    708     )
    709     # Set key rollover relationship.
    710     set_key_relationship(csk1_name, csk2_name)
    711     # Signing.
    712     render_and_sign_zone(zonename, [csk1_name, csk2_name], extra_options=f"-z -G {cds}")
    713 
    714     # Step 5:
    715     # After the DS is swapped in step 4, also the KRRSIG records can be removed.
    716     # At this time these have all become hidden.
    717     zonename = f"step5.{zone}"
    718     zones.append(Zone(zonename, f"{zonename}.db", Nameserver("ns3", "10.53.0.3")))
    719     isctest.log.info(f"setup {zonename}")
    720     # Subtract DNSKEY TTL plus zone propagation delay from all the times (2h).
    721     TpubN = "now-4470h"
    722     TactN = "now-4445h"
    723     TretN = "now-6h"
    724     TremN = "now+621h"
    725     TpubN1 = "now-9h"
    726     TactN1 = TretN
    727     TretN1 = "now+4458h"
    728     TremN1 = "now+5085h"
    729     keytimes = (
    730         f"-P {TpubN} -P sync {TactN} -A {TpubN} -I {TretN} -D {TremN} -D sync {TactN1}"
    731     )
    732     newtimes = f"-P {TpubN1} -P sync {TactN1} -A {TactN1} -I {TretN1} -D {TremN1}"
    733     # Key generation.
    734     csk1_name = keygen(f"{keytimes} {zonename}", cwd="ns3").out.strip()
    735     csk2_name = keygen(f"{newtimes} {zonename}", cwd="ns3").out.strip()
    736     settime(
    737         f"-g HIDDEN -k OMNIPRESENT {TactN} -r UNRETENTIVE now-2h -z UNRETENTIVE {TactN1} -d HIDDEN now-2h {csk1_name}",
    738         cwd="ns3",
    739     )
    740     settime(
    741         f"-g OMNIPRESENT -k OMNIPRESENT {TactN1} -r OMNIPRESENT {TactN1} -z RUMOURED {TactN1} -d OMNIPRESENT now-2h {csk2_name}",
    742         cwd="ns3",
    743     )
    744     # Set key rollover relationship.
    745     set_key_relationship(csk1_name, csk2_name)
    746     # Signing.
    747     render_and_sign_zone(zonename, [csk1_name, csk2_name], extra_options=f"-z -G {cds}")
    748 
    749     # Step 6:
    750     # After the retire interval has passed the predecessor DNSKEY can be
    751     # removed from the zone.
    752     zonename = f"step6.{zone}"
    753     zones.append(Zone(zonename, f"{zonename}.db", Nameserver("ns3", "10.53.0.3")))
    754     isctest.log.info(f"setup {zonename}")
    755     # According to RFC 7583:
    756     # Trem(N) = Tret(N) + IretZ
    757     # Tret(N) = Tact(N) + Lcsk
    758     #
    759     # Lcsk:   186d
    760     # Iret:   4h
    761     # IretZ:  26d3h
    762     #
    763     # Tpub(N)   = now - IretZ - Lcsk = now - 627h - 186d
    764     #           = now - 627h - 4464h = now - 5091h
    765     # Tact(N)   = now - 627h - 186d
    766     # Tret(N)   = now - IretZ = now - 627h
    767     # Trem(N)   = now
    768     # Tpub(N+1) = now - IretZ - Ipub = now - 627h - 3h = now - 630h
    769     # Tact(N+1) = Tret(N)
    770     # Tret(N+1) = now - IretZ + Lcsk = now - 627h + 186d = now + 3837h
    771     # Trem(N+1) = now + Lcsk = now + 186d
    772     TpubN = "now-5091h"
    773     TactN = "now-5066h"
    774     TretN = "now-627h"
    775     TremN = "now"
    776     TpubN1 = "now-630h"
    777     TactN1 = TretN
    778     TretN1 = "now+3837h"
    779     TremN1 = "now+186d"
    780     keytimes = (
    781         f"-P {TpubN} -P sync {TactN} -A {TpubN} -I {TretN} -D {TremN} -D sync {TactN1}"
    782     )
    783     newtimes = f"-P {TpubN1} -P sync {TactN1} -A {TactN1} -I {TretN1} -D {TremN1}"
    784     # Key generation.
    785     csk1_name = keygen(f"{keytimes} {zonename}", cwd="ns3").out.strip()
    786     csk2_name = keygen(f"{newtimes} {zonename}", cwd="ns3").out.strip()
    787     settime(
    788         f"-g HIDDEN -k OMNIPRESENT {TactN} -r HIDDEN {TremN} -z UNRETENTIVE {TactN1} -d HIDDEN {TremN} {csk1_name}",
    789         cwd="ns3",
    790     )
    791     settime(
    792         f"-g OMNIPRESENT -k OMNIPRESENT {TactN1} -r OMNIPRESENT {TactN1} -z RUMOURED {TactN1} -d OMNIPRESENT {TremN} {csk2_name}",
    793         cwd="ns3",
    794     )
    795     # Set key rollover relationship.
    796     set_key_relationship(csk1_name, csk2_name)
    797     # Signing.
    798     render_and_sign_zone(zonename, [csk1_name, csk2_name], extra_options=f"-z -G {cds}")
    799 
    800     # Step 7:
    801     # Some time later the predecessor DNSKEY enters the HIDDEN state.
    802     zonename = f"step7.{zone}"
    803     zones.append(Zone(zonename, f"{zonename}.db", Nameserver("ns3", "10.53.0.3")))
    804     isctest.log.info(f"setup {zonename}")
    805     # Subtract DNSKEY TTL plus zone propagation delay from all the times (2h).
    806     TpubN = "now-5093h"
    807     TactN = "now-5068h"
    808     TretN = "now-629h"
    809     TremN = "now-2h"
    810     TpubN1 = "now-632h"
    811     TactN1 = TretN
    812     TretN1 = "now+3835h"
    813     TremN1 = "now+4462h"
    814     keytimes = (
    815         f"-P {TpubN} -P sync {TactN} -A {TpubN} -I {TretN} -D {TremN} -D sync {TactN1}"
    816     )
    817     newtimes = f"-P {TpubN1} -P sync {TactN1} -A {TactN1} -I {TretN1} -D {TremN1}"
    818     # Key generation.
    819     csk1_name = keygen(f"{keytimes} {zonename}", cwd="ns3").out.strip()
    820     csk2_name = keygen(f"{newtimes} {zonename}", cwd="ns3").out.strip()
    821     settime(
    822         f"-g HIDDEN -k UNRETENTIVE {TremN} -r HIDDEN {TremN} -z HIDDEN {TactN1} -d HIDDEN {TremN} {csk1_name}",
    823         cwd="ns3",
    824     )
    825     settime(
    826         f"-g OMNIPRESENT -k OMNIPRESENT {TactN1} -r OMNIPRESENT {TactN1} -z OMNIPRESENT {TactN1} -d OMNIPRESENT {TactN1} {csk2_name}",
    827         cwd="ns3",
    828     )
    829     # Set key rollover relationship.
    830     set_key_relationship(csk1_name, csk2_name)
    831     # Signing.
    832     render_and_sign_zone(zonename, [csk1_name, csk2_name], extra_options=f"-z -G {cds}")
    833 
    834     # Step 8:
    835     # The predecessor DNSKEY can be purged.
    836     zonename = f"step8.{zone}"
    837     zones.append(Zone(zonename, f"{zonename}.db", Nameserver("ns3", "10.53.0.3")))
    838     isctest.log.info(f"setup {zonename}")
    839     # Subtract purge-keys interval from all the times (1h).
    840     TpubN = "now-5094h"
    841     TactN = "now-5069h"
    842     TretN = "now-630h"
    843     TremN = "now-3h"
    844     TpubN1 = "now-633h"
    845     TactN1 = TretN
    846     TretN1 = "now+3834h"
    847     TremN1 = "now+4461h"
    848     keytimes = (
    849         f"-P {TpubN} -P sync {TactN} -A {TpubN} -I {TretN} -D {TremN} -D sync {TactN1}"
    850     )
    851     newtimes = f"-P {TpubN1} -P sync {TactN1} -A {TactN1} -I {TretN1} -D {TremN1}"
    852     # Key generation.
    853     csk1_name = keygen(f"{keytimes} {zonename}", cwd="ns3").out.strip()
    854     csk2_name = keygen(f"{newtimes} {zonename}", cwd="ns3").out.strip()
    855     settime(
    856         f"-g HIDDEN -k HIDDEN {TremN} -r HIDDEN {TremN} -z HIDDEN {TactN1} -d HIDDEN {TremN} {csk1_name}",
    857         cwd="ns3",
    858     )
    859     settime(
    860         f"-g OMNIPRESENT -k OMNIPRESENT {TactN1} -r OMNIPRESENT {TactN1} -z OMNIPRESENT {TactN1} -d OMNIPRESENT {TactN1} {csk2_name}",
    861         cwd="ns3",
    862     )
    863     # Set key rollover relationship.
    864     set_key_relationship(csk1_name, csk2_name)
    865     # Signing.
    866     render_and_sign_zone(zonename, [csk1_name, csk2_name], extra_options=f"-z -G {cds}")
    867 
    868     return zones
    869 
    870 
    871 def configure_cskroll2(tld: str, policy: str) -> List[Zone]:
    872     # The zones at csk-roll2.$tld represent the various steps of a CSK rollover
    873     # (which is essentially a ZSK Pre-Publication / KSK Double-KSK rollover).
    874     # This scenario differs from the csk-roll1 one because the zone signatures (ZRRSIG)
    875     # are replaced with the new key sooner than the DS is swapped.
    876     zones = []
    877     zone = f"csk-roll2.{tld}"
    878     cds = "cdnskey,cds:sha-256,cds:sha-384"
    879     keygen = EnvCmd("KEYGEN", f"-k {policy} -l kasp.conf")
    880     settime = EnvCmd("SETTIME", "-s")
    881 
    882     # Step 1:
    883     # Introduce the first key. This will immediately be active.
    884     zonename = f"step1.{zone}"
    885     zones.append(Zone(zonename, f"{zonename}.db", Nameserver("ns3", "10.53.0.3")))
    886     isctest.log.info(f"setup {zonename}")
    887     TactN = "now-7d"
    888     keytimes = f"-P {TactN} -A {TactN}"
    889     # Key generation.
    890     csk_name = keygen(f"{keytimes} {zonename}", cwd="ns3").out.strip()
    891     settime(
    892         f"-g OMNIPRESENT -k OMNIPRESENT {TactN} -r OMNIPRESENT {TactN} -z OMNIPRESENT {TactN} -d OMNIPRESENT {TactN} {csk_name}",
    893         cwd="ns3",
    894     )
    895     # Signing.
    896     render_and_sign_zone(zonename, [csk_name], extra_options=f"-z -G {cds}")
    897 
    898     # Step 2:
    899     # It is time to introduce the new CSK.
    900     zonename = f"step2.{zone}"
    901     zones.append(Zone(zonename, f"{zonename}.db", Nameserver("ns3", "10.53.0.3")))
    902     isctest.log.info(f"setup {zonename}")
    903     # According to RFC 7583:
    904     # KSK: Tpub(N+1) <= Tact(N) + Lksk - IpubC
    905     # ZSK: Tpub(N+1) <= Tact(N) + Lzsk - Ipub
    906     # IpubC = DprpC + TTLkey (+publish-safety)
    907     # Ipub  = IpubC
    908     # Lcsk = Lksk = Lzsk
    909     #
    910     # Lcsk:           6mo (186d, 4464h)
    911     # Dreg:           N/A
    912     # DprpC:          1h
    913     # TTLkey:         1h
    914     # publish-safety: 1h
    915     # Ipub:           3h
    916     #
    917     # Tact(N)  = now - Lcsk + Ipub = now - 186d + 3h
    918     #          = now - 4464h + 3h = now - 4461h
    919     TactN = "now-4461h"
    920     keytimes = f"-P {TactN} -A {TactN}"
    921     # Key generation.
    922     csk_name = keygen(f"{keytimes} {zonename}", cwd="ns3").out.strip()
    923     settime(
    924         f"-g OMNIPRESENT -k OMNIPRESENT {TactN} -r OMNIPRESENT {TactN} -z OMNIPRESENT {TactN} -d OMNIPRESENT {TactN} {csk_name}",
    925         cwd="ns3",
    926     )
    927     # Signing.
    928     render_and_sign_zone(zonename, [csk_name], extra_options=f"-z -G {cds}")
    929 
    930     # Step 3:
    931     # It is time to submit the DS and to roll signatures.
    932     zonename = f"step3.{zone}"
    933     zones.append(Zone(zonename, f"{zonename}.db", Nameserver("ns3", "10.53.0.3")))
    934     isctest.log.info(f"setup {zonename}")
    935     # According to RFC 7583:
    936     #
    937     # Tsbm(N+1) >= Trdy(N+1)
    938     # KSK: Tact(N+1) = Tsbm(N+1)
    939     # ZSK: Tact(N+1) = Tpub(N+1) + Ipub = Tsbm(N+1)
    940     # KSK: Iret  = DprpP + TTLds (+retire-safety)
    941     # ZSK: IretZ = Dsgn + Dprp + TTLsig (+retire-safety)
    942     #
    943     # Lcsk:           186d
    944     # Dprp:           1h
    945     # DprpP:          1w
    946     # Dreg:           N/A
    947     # Dsgn:           12h
    948     # TTLds:          1h
    949     # TTLsig:         1d
    950     # retire-safety:  1h
    951     # Iret:           170h
    952     # IretZ:          38h
    953     # Ipub:           3h
    954     #
    955     # Tpub(N)   = now - Lcsk = now - 186d
    956     # Tact(N)   = now - Lcsk + Dprp + TTLsig = now - 4439h
    957     # Tret(N)   = now
    958     # Trem(N)   = now + IretZ = now + 26d3h = now + 627h
    959     # Tpub(N+1) = now - Ipub = now - 3h
    960     # Tact(N+1) = Tret(N)
    961     # Tret(N+1) = now + Lcsk = now + 186d = now + 186d
    962     # Trem(N+1) = now + Lcsk + IretZ = now + 186d + 26d3h =
    963     #           = now + 5091h
    964     TpubN = "now-186d"
    965     TactN = "now-4439h"
    966     TretN = "now"
    967     TremN = "now+170h"
    968     TpubN1 = "now-3h"
    969     TactN1 = TretN
    970     TretN1 = "now+186d"
    971     TremN1 = "now+4634h"
    972     keytimes = (
    973         f"-P {TpubN} -P sync {TactN} -A {TpubN} -I {TretN} -D {TremN} -D sync {TactN1}"
    974     )
    975     newtimes = f"-P {TpubN1} -P sync {TactN1} -A {TactN1} -I {TretN1} -D {TremN1}"
    976     # Key generation.
    977     csk1_name = keygen(f"{keytimes} {zonename}", cwd="ns3").out.strip()
    978     csk2_name = keygen(f"{newtimes} {zonename}", cwd="ns3").out.strip()
    979     settime(
    980         f"-g HIDDEN -k OMNIPRESENT {TactN} -r OMNIPRESENT {TactN} -z OMNIPRESENT {TactN} -d OMNIPRESENT {TactN} {csk1_name}",
    981         cwd="ns3",
    982     )
    983     settime(
    984         f"-g OMNIPRESENT -k RUMOURED {TpubN1} -r RUMOURED {TpubN1} -z HIDDEN {TpubN1} -d HIDDEN {TpubN1} {csk2_name}",
    985         cwd="ns3",
    986     )
    987     # Set key rollover relationship.
    988     set_key_relationship(csk1_name, csk2_name)
    989     # Signing.
    990     render_and_sign_zone(zonename, [csk1_name, csk2_name], extra_options=f"-z -G {cds}")
    991 
    992     # Step 4:
    993     # Some time later all the ZRRSIG records should be from the new CSK, and the
    994     # DS should be swapped.  The ZRRSIG records are all replaced after IretZ (38h).
    995     # The DS is swapped after Dreg + Iret (1w3h). In other words, the zone
    996     # signatures are replaced before the DS is swapped.
    997     zonename = f"step4.{zone}"
    998     zones.append(Zone(zonename, f"{zonename}.db", Nameserver("ns3", "10.53.0.3")))
    999     isctest.log.info(f"setup {zonename}")
   1000     # According to RFC 7583:
   1001     # Trem(N)    = Tret(N) + IretZ
   1002     #
   1003     # Lcsk:   186d
   1004     # Dreg:   N/A
   1005     # Iret:   170h
   1006     # IretZ:  38h
   1007     #
   1008     # Tpub(N)    = now - IretZ - Lcsk = now - 38h - 186d
   1009     #            = now - 38h - 4464h = now - 4502h
   1010     # Tact(N)    = now - Iret - Lcsk + TTLsig = now - 4502h + 25h = now - 4477h
   1011     # Tret(N)    = now - IretZ = now - 38h
   1012     # Trem(N)    = now - IretZ + Iret = now - 38h + 170h = now + 132h
   1013     # Tpub(N+1)  = now - IretZ - IpubC = now - 38h - 3h = now - 41h
   1014     # Tact(N+1)  = Tret(N)
   1015     # Tret(N+1)  = now - IretZ + Lcsk = now - 38h + 186d
   1016     #            = now + 4426h
   1017     # Trem(N+1)  = now - IretZ + Lcsk + Iret
   1018     #            = now + 4426h + 3h = now + 4429h
   1019     TpubN = "now-4502h"
   1020     TactN = "now-4477h"
   1021     TretN = "now-38h"
   1022     TremN = "now+132h"
   1023     TpubN1 = "now-41h"
   1024     TactN1 = TretN
   1025     TretN1 = "now+4426h"
   1026     TremN1 = "now+4429h"
   1027     keytimes = (
   1028         f"-P {TpubN} -P sync {TactN} -A {TpubN} -I {TretN} -D {TremN} -D sync {TactN1}"
   1029     )
   1030     newtimes = f"-P {TpubN1} -P sync {TactN1} -A {TactN1} -I {TretN1} -D {TremN1}"
   1031     # Key generation.
   1032     csk1_name = keygen(f"{keytimes} {zonename}", cwd="ns3").out.strip()
   1033     csk2_name = keygen(f"{newtimes} {zonename}", cwd="ns3").out.strip()
   1034     settime(
   1035         f"-g HIDDEN -k OMNIPRESENT {TactN} -r OMNIPRESENT {TactN} -z UNRETENTIVE {TretN} -d UNRETENTIVE {TretN} -D ds {TretN} {csk1_name}",
   1036         cwd="ns3",
   1037     )
   1038     settime(
   1039         f"-g OMNIPRESENT -k OMNIPRESENT {TactN1} -r OMNIPRESENT {TactN1} -z RUMOURED {TactN1} -d RUMOURED {TactN1} -P ds {TactN1} {csk2_name}",
   1040         cwd="ns3",
   1041     )
   1042     # Set key rollover relationship.
   1043     set_key_relationship(csk1_name, csk2_name)
   1044     # Signing.
   1045     render_and_sign_zone(zonename, [csk1_name, csk2_name], extra_options=f"-z -G {cds}")
   1046 
   1047     # Step 5:
   1048     # Some time later the DS can be swapped and the old DNSKEY can be removed from
   1049     # the zone.
   1050     zonename = f"step5.{zone}"
   1051     zones.append(Zone(zonename, f"{zonename}.db", Nameserver("ns3", "10.53.0.3")))
   1052     isctest.log.info(f"setup {zonename}")
   1053     # Subtract Iret (170h) - IretZ (38h) = 132h.
   1054     #
   1055     # Tpub(N)   = now - 4502h - 132h = now - 4634h
   1056     # Tact(N)   = now - 4477h - 132h = now - 4609h
   1057     # Tret(N)   = now - 38h - 132h = now - 170h
   1058     # Trem(N)   = now + 132h - 132h = now
   1059     # Tpub(N+1) = now - 41h - 132h = now - 173h
   1060     # Tact(N+1) = Tret(N)
   1061     # Tret(N+1) = now + 4426h - 132h = now + 4294h
   1062     # Trem(N+1) = now + 4492h - 132h = now + 4360h
   1063     TpubN = "now-4634h"
   1064     TactN = "now-4609h"
   1065     TretN = "now-170h"
   1066     TremN = "now"
   1067     TpubN1 = "now-173h"
   1068     TactN1 = TretN
   1069     TretN1 = "now+4294h"
   1070     TremN1 = "now+4360h"
   1071     keytimes = (
   1072         f"-P {TpubN} -P sync {TactN} -A {TpubN} -I {TretN} -D {TremN} -D sync {TactN1}"
   1073     )
   1074     newtimes = f"-P {TpubN1} -P sync {TactN1} -A {TactN1} -I {TretN1} -D {TremN1}"
   1075     # Key generation.
   1076     csk1_name = keygen(f"{keytimes} {zonename}", cwd="ns3").out.strip()
   1077     csk2_name = keygen(f"{newtimes} {zonename}", cwd="ns3").out.strip()
   1078     settime(
   1079         f"-g HIDDEN -k OMNIPRESENT {TactN} -r OMNIPRESENT {TactN} -z HIDDEN now-133h -d UNRETENTIVE {TactN1} -D ds {TactN1} {csk1_name}",
   1080         cwd="ns3",
   1081     )
   1082     settime(
   1083         f"-g OMNIPRESENT -k OMNIPRESENT {TactN1} -r OMNIPRESENT {TactN1} -z OMNIPRESENT now-133h -d RUMOURED {TactN1} -P ds {TactN1} {csk2_name}",
   1084         cwd="ns3",
   1085     )
   1086     # Set key rollover relationship.
   1087     set_key_relationship(csk1_name, csk2_name)
   1088     # Signing.
   1089     render_and_sign_zone(zonename, [csk1_name, csk2_name], extra_options=f"-z -G {cds}")
   1090 
   1091     # Step 6:
   1092     # Some time later the predecessor DNSKEY enters the HIDDEN state.
   1093     zonename = f"step6.{zone}"
   1094     zones.append(Zone(zonename, f"{zonename}.db", Nameserver("ns3", "10.53.0.3")))
   1095     isctest.log.info(f"setup {zonename}")
   1096     # Subtract DNSKEY TTL plus zone propagation delay (2h).
   1097     #
   1098     # Tpub(N)   = now - 4634h - 2h = now - 4636h
   1099     # Tact(N)   = now - 4609h - 2h = now - 4611h
   1100     # Tret(N)   = now - 170h - 2h = now - 172h
   1101     # Trem(N)   = now - 2h
   1102     # Tpub(N+1) = now - 173h - 2h = now - 175h
   1103     # Tact(N+1) = Tret(N)
   1104     # Tret(N+1) = now + 4294h - 2h = now + 4292h
   1105     # Trem(N+1) = now + 4360h - 2h = now + 4358h
   1106     TpubN = "now-4636h"
   1107     TactN = "now-4611h"
   1108     TretN = "now-172h"
   1109     TremN = "now-2h"
   1110     TpubN1 = "now-175h"
   1111     TactN1 = TretN
   1112     TretN1 = "now+4292h"
   1113     TremN1 = "now+4358h"
   1114     keytimes = (
   1115         f"-P {TpubN} -P sync {TactN} -A {TpubN} -I {TretN} -D {TremN} -D sync {TactN1}"
   1116     )
   1117     newtimes = f"-P {TpubN1} -P sync {TactN1} -A {TactN1} -I {TretN1} -D {TremN1}"
   1118     # Key generation.
   1119     csk1_name = keygen(f"{keytimes} {zonename}", cwd="ns3").out.strip()
   1120     csk2_name = keygen(f"{newtimes} {zonename}", cwd="ns3").out.strip()
   1121     settime(
   1122         f"-g HIDDEN -k UNRETENTIVE {TremN} -r UNRETENTIVE {TremN} -z HIDDEN now-135h -d HIDDEN {TremN} {csk1_name}",
   1123         cwd="ns3",
   1124     )
   1125     settime(
   1126         f"-g OMNIPRESENT -k OMNIPRESENT {TactN1} -r OMNIPRESENT {TactN1} -z OMNIPRESENT now-135h -d OMNIPRESENT {TremN} {csk2_name}",
   1127         cwd="ns3",
   1128     )
   1129     # Set key rollover relationship.
   1130     set_key_relationship(csk1_name, csk2_name)
   1131     # Signing.
   1132     render_and_sign_zone(zonename, [csk1_name, csk2_name], extra_options=f"-z -G {cds}")
   1133 
   1134     # Step 7:
   1135     # The predecessor DNSKEY can be purged, but purge-keys is disabled.
   1136     zonename = f"step7.{zone}"
   1137     zones.append(Zone(zonename, f"{zonename}.db", Nameserver("ns3", "10.53.0.3")))
   1138     isctest.log.info(f"setup {zonename}")
   1139     # Subtract 90 days (default, 2160h) from all the times.
   1140     #
   1141     # Tpub(N)   = now - 4636h - 2160h = now - 6796h
   1142     # Tact(N)   = now - 4611h - 2160h = now - 6771h
   1143     # Tret(N)   = now - 172h - 2160h = now - 2332h
   1144     # Trem(N)   = now - 2h - 2160h = now - 2162h
   1145     # Tpub(N+1) = now - 175h - 2160h = now - 2335h
   1146     # Tact(N+1) = Tret(N)
   1147     # Tret(N+1) = now + 4292h - 2160h = now + 2132h
   1148     # Trem(N+1) = now + 4358h - 2160h = now + 2198h
   1149     TpubN = "now-6796h"
   1150     TactN = "now-6771h"
   1151     TretN = "now-2332h"
   1152     TremN = "now-2162h"
   1153     TpubN1 = "now-2335h"
   1154     TactN1 = TretN
   1155     TretN1 = "now+2132h"
   1156     TremN1 = "now+2198h"
   1157 
   1158     keytimes = (
   1159         f"-P {TpubN} -P sync {TactN} -A {TpubN} -I {TretN} -D {TremN} -D sync {TactN1}"
   1160     )
   1161     newtimes = f"-P {TpubN1} -P sync {TactN1} -A {TactN1} -I {TretN1} -D {TremN1}"
   1162     # Key generation.
   1163     csk1_name = keygen(f"{keytimes} {zonename}", cwd="ns3").out.strip()
   1164     csk2_name = keygen(f"{newtimes} {zonename}", cwd="ns3").out.strip()
   1165     settime(
   1166         f"-g HIDDEN -k UNRETENTIVE {TremN} -r HIDDEN {TremN} -z HIDDEN {TactN1} -d HIDDEN {TremN} {csk1_name}",
   1167         cwd="ns3",
   1168     )
   1169     settime(
   1170         f"-g OMNIPRESENT -k OMNIPRESENT {TactN1} -r OMNIPRESENT {TactN1} -z OMNIPRESENT {TactN1} -d OMNIPRESENT {TremN} {csk2_name}",
   1171         cwd="ns3",
   1172     )
   1173     # Set key rollover relationship.
   1174     set_key_relationship(csk1_name, csk2_name)
   1175     # Signing.
   1176     render_and_sign_zone(zonename, [csk1_name, csk2_name], extra_options=f"-z -G {cds}")
   1177 
   1178     # Step 8:
   1179     # The predecessor DNSKEY can be purged.
   1180     zonename = f"step8.{zone}"
   1181     zones.append(Zone(zonename, f"{zonename}.db", Nameserver("ns3", "10.53.0.3")))
   1182     isctest.log.info(f"setup {zonename}")
   1183     # Subtract purge-keys interval from all the times (1h).
   1184     TpubN = "now-5094h"
   1185     TactN = "now-5069h"
   1186     TretN = "now-630h"
   1187     TremN = "now-3h"
   1188     TpubN1 = "now-633h"
   1189     TactN1 = TretN
   1190     TretN1 = "now+3834h"
   1191     TremN1 = "now+4461h"
   1192     keytimes = (
   1193         f"-P {TpubN} -P sync {TactN} -A {TpubN} -I {TretN} -D {TremN} -D sync {TactN1}"
   1194     )
   1195     newtimes = f"-P {TpubN1} -P sync {TactN1} -A {TactN1} -I {TretN1} -D {TremN1}"
   1196     # Key generation.
   1197     csk1_name = keygen(f"{keytimes} {zonename}", cwd="ns3").out.strip()
   1198     csk2_name = keygen(f"{newtimes} {zonename}", cwd="ns3").out.strip()
   1199     settime(
   1200         f"-g HIDDEN -k UNRETENTIVE {TremN} -r UNRETENTIVE {TremN} -z HIDDEN now-2295h -d HIDDEN {TremN} {csk1_name}",
   1201         cwd="ns3",
   1202     )
   1203     settime(
   1204         f"-g OMNIPRESENT -k OMNIPRESENT {TactN1} -r OMNIPRESENT {TactN1} -z OMNIPRESENT now-2295h -d OMNIPRESENT {TremN} {csk2_name}",
   1205         cwd="ns3",
   1206     )
   1207     # Set key rollover relationship.
   1208     set_key_relationship(csk1_name, csk2_name)
   1209     # Signing.
   1210     render_and_sign_zone(zonename, [csk1_name, csk2_name], extra_options=f"-z -G {cds}")
   1211 
   1212     return zones
   1213 
   1214 
   1215 def configure_enable_dnssec(tld: str, policy: str) -> List[Zone]:
   1216     # The zones at enable-dnssec.$tld represent the various steps of the
   1217     # initial signing of a zone.
   1218     zones = []
   1219     zone = f"enable-dnssec.{tld}"
   1220     keygen = EnvCmd("KEYGEN", f"-k {policy} -l kasp.conf")
   1221     settime = EnvCmd("SETTIME", "-s")
   1222 
   1223     # Step 1:
   1224     # This is an unsigned zone and named should perform the initial steps of
   1225     # introducing the DNSSEC records in the right order.
   1226     zonename = f"step1.{zone}"
   1227     zones.append(Zone(zonename, f"{zonename}.db", Nameserver("ns3", "10.53.0.3")))
   1228     isctest.log.info(f"setup {zonename}")
   1229     render_and_sign_zone(zonename, [], signing=False)
   1230 
   1231     # Step 2:
   1232     # The DNSKEY has been published long enough to become OMNIPRESENT.
   1233     zonename = f"step2.{zone}"
   1234     zones.append(Zone(zonename, f"{zonename}.db", Nameserver("ns3", "10.53.0.3")))
   1235     isctest.log.info(f"setup {zonename}")
   1236     # DNSKEY TTL:             300 seconds
   1237     # zone-propagation-delay: 5 minutes (300 seconds)
   1238     # publish-safety:         5 minutes (300 seconds)
   1239     # Total:                  900 seconds
   1240     TpubN = "now-900s"
   1241     keytimes = f"-P {TpubN} -A {TpubN}"
   1242     # Key generation.
   1243     csk_name = keygen(f"{keytimes} {zonename}", cwd="ns3").out.strip()
   1244     settime(
   1245         f"-g OMNIPRESENT -k RUMOURED {TpubN} -r RUMOURED {TpubN} -z RUMOURED {TpubN} -d HIDDEN {TpubN} {csk_name}",
   1246         cwd="ns3",
   1247     )
   1248     # Signing.
   1249     render_and_sign_zone(zonename, [csk_name], extra_options="-z")
   1250 
   1251     # Step 3:
   1252     # The zone signatures have been published long enough to become OMNIPRESENT.
   1253     zonename = f"step3.{zone}"
   1254     zones.append(Zone(zonename, f"{zonename}.db", Nameserver("ns3", "10.53.0.3")))
   1255     isctest.log.info(f"setup {zonename}")
   1256     # Passed time since publication:
   1257     # max-zone-ttl:           12 hours (43200 seconds)
   1258     # zone-propagation-delay: 5 minutes (300 seconds)
   1259     # We can submit the DS now.
   1260     TpubN = "now-43500s"
   1261     keytimes = f"-P {TpubN} -A {TpubN}"
   1262     # Key generation.
   1263     csk_name = keygen(f"{keytimes} {zonename}", cwd="ns3").out.strip()
   1264     settime(
   1265         f"-g OMNIPRESENT -k OMNIPRESENT {TpubN} -r OMNIPRESENT {TpubN} -z RUMOURED {TpubN} -d HIDDEN {TpubN} {csk_name}",
   1266         cwd="ns3",
   1267     )
   1268     # Signing.
   1269     render_and_sign_zone(zonename, [csk_name], extra_options="-z")
   1270 
   1271     # Step 4:
   1272     # The DS has been submitted long enough ago to become OMNIPRESENT.
   1273     zonename = f"step4.{zone}"
   1274     zones.append(Zone(zonename, f"{zonename}.db", Nameserver("ns3", "10.53.0.3")))
   1275     isctest.log.info(f"setup {zonename}")
   1276     # DS TTL:                    2 hour (7200 seconds)
   1277     # parent-propagation-delay:  1 hour (3600 seconds)
   1278     # Total aditional time:      10800 seconds
   1279     # 43500 + 10800 = 54300
   1280     TpubN = "now-54300s"
   1281     TsbmN = "now-10800s"
   1282     keytimes = f"-P {TpubN} -A {TpubN} -P sync {TsbmN}"
   1283     # Key generation.
   1284     csk_name = keygen(f"{keytimes} {zonename}", cwd="ns3").out.strip()
   1285     settime(
   1286         f"-g OMNIPRESENT -k OMNIPRESENT {TpubN} -r OMNIPRESENT {TpubN} -z OMNIPRESENT {TsbmN} -d RUMOURED {TpubN} -P ds {TsbmN} {csk_name}",
   1287         cwd="ns3",
   1288     )
   1289     # Signing.
   1290     render_and_sign_zone(zonename, [csk_name], extra_options="-z")
   1291 
   1292     return zones
   1293 
   1294 
   1295 def configure_going_insecure(tld: str, reconfig: bool = False) -> List[Zone]:
   1296     zones = []
   1297     keygen = EnvCmd("KEYGEN", "-a ECDSA256 -L 7200")
   1298     settime = EnvCmd("SETTIME", "-s")
   1299 
   1300     # The child zones (step1, step2) beneath these zones represent the various
   1301     # steps of unsigning a zone.
   1302     for zone in [f"going-insecure.{tld}", f"going-insecure-dynamic.{tld}"]:
   1303         # Set up a zone with dnssec-policy that is going insecure.
   1304 
   1305         # Step 1:
   1306         zonename = f"step1.{zone}"
   1307         zones.append(Zone(zonename, f"{zonename}.db", Nameserver("ns3", "10.53.0.3")))
   1308         isctest.log.info(f"setup {zonename}")
   1309         # Timing metadata.
   1310         TpubN = "now-10d"
   1311         TsbmN = "now-12955mi"
   1312         keytimes = f"-P {TpubN} -A {TpubN}"
   1313         cdstimes = f"-P sync {TsbmN}"
   1314         # Key generation.
   1315         ksk_name = keygen(
   1316             f"-f KSK {keytimes} {cdstimes} {zonename}", cwd="ns3"
   1317         ).out.strip()
   1318         zsk_name = keygen(f"{keytimes} {zonename}", cwd="ns3").out.strip()
   1319         settime(
   1320             f"-g OMNIPRESENT -k OMNIPRESENT {TpubN} -r OMNIPRESENT {TpubN} -d OMNIPRESENT {TpubN} {ksk_name}",
   1321             cwd="ns3",
   1322         )
   1323         settime(
   1324             f"-g OMNIPRESENT -k OMNIPRESENT {TpubN} -z OMNIPRESENT {TpubN} {zsk_name}",
   1325             cwd="ns3",
   1326         )
   1327         # Signing.
   1328         render_and_sign_zone(zonename, [ksk_name, zsk_name])
   1329 
   1330         if reconfig:
   1331             # Step 2:
   1332             zonename = f"step2.{zone}"
   1333             zones.append(
   1334                 Zone(zonename, f"{zonename}.db", Nameserver("ns3", "10.53.0.3"))
   1335             )
   1336             isctest.log.info(f"setup {zonename}")
   1337             # The DS was withdrawn from the parent zone 26 hours ago.
   1338             TremN = "now-26h"
   1339             keytimes = f"-P {TpubN} -A {TpubN} -I {TremN} -D now"
   1340             cdstimes = f"-P sync {TsbmN} -D sync {TremN}"
   1341             # Key generation.
   1342             ksk_name = keygen(
   1343                 f"-f KSK {keytimes} {cdstimes} {zonename}", cwd="ns3"
   1344             ).out.strip()
   1345             zsk_name = keygen(f"{keytimes} {zonename}", cwd="ns3").out.strip()
   1346             settime(
   1347                 f"-g HIDDEN -k OMNIPRESENT {TpubN} -r OMNIPRESENT {TpubN} -d UNRETENTIVE {TremN} -D ds {TremN} {ksk_name}",
   1348                 cwd="ns3",
   1349             )
   1350             settime(
   1351                 f"-g HIDDEN -k OMNIPRESENT {TpubN} -z OMNIPRESENT {TpubN} {zsk_name}",
   1352                 cwd="ns3",
   1353             )
   1354             # Fake lifetime of old algorithm keys.
   1355             fake_lifetime(ksk_name, 0)
   1356             fake_lifetime(zsk_name, 5184000)
   1357             # Signing.
   1358             render_and_sign_zone(zonename, [ksk_name, zsk_name], extra_options="-P")
   1359 
   1360     return zones
   1361 
   1362 
   1363 def configure_straight2none(tld: str) -> List[Zone]:
   1364     # These zones are going straight to "none" policy. This is undefined behavior.
   1365     zones = []
   1366     keygen = EnvCmd("KEYGEN", "-k default")
   1367     settime = EnvCmd("SETTIME", "-s")
   1368 
   1369     TpubN = "now-10d"
   1370     TsbmN = "now-12955mi"
   1371     keytimes = f"-P {TpubN} -A {TpubN} -P sync {TsbmN}"
   1372 
   1373     zonename = f"going-straight-to-none.{tld}"
   1374     zones.append(Zone(zonename, f"{zonename}.db", Nameserver("ns3", "10.53.0.3")))
   1375     isctest.log.info(f"setup {zonename}")
   1376     # Key generation.
   1377     csk_name = keygen(f"-f KSK {keytimes} {zonename}", cwd="ns3").out.strip()
   1378     settime(
   1379         f"-g OMNIPRESENT -k OMNIPRESENT {TpubN} -r OMNIPRESENT {TpubN} -z OMNIPRESENT {TpubN} -d OMNIPRESENT {TpubN} {csk_name}",
   1380         cwd="ns3",
   1381     )
   1382     # Signing.
   1383     render_and_sign_zone(zonename, [csk_name], extra_options="-z")
   1384 
   1385     zonename = f"going-straight-to-none-dynamic.{tld}"
   1386     zones.append(
   1387         Zone(zonename, f"{zonename}.db.signed", Nameserver("ns3", "10.53.0.3"))
   1388     )
   1389     isctest.log.info(f"setup {zonename}")
   1390     # Key generation.
   1391     csk_name = keygen(f"-f KSK {keytimes} {zonename}", cwd="ns3").out.strip()
   1392     settime(
   1393         f"-g OMNIPRESENT -k OMNIPRESENT {TpubN} -r OMNIPRESENT {TpubN} -z OMNIPRESENT {TpubN} -d OMNIPRESENT {TpubN} {csk_name}",
   1394         cwd="ns3",
   1395     )
   1396     # Signing.
   1397     render_and_sign_zone(zonename, [csk_name], extra_options="-z -O full")
   1398 
   1399     return zones
   1400 
   1401 
   1402 def configure_ksk_doubleksk(tld: str) -> List[Zone]:
   1403     # The zones at ksk-doubleksk.$tld represent the various steps of a KSK
   1404     # Double-KSK rollover.
   1405     zones = []
   1406     zone = f"ksk-doubleksk.{tld}"
   1407     cds = "cds:sha-256"
   1408     keygen = EnvCmd("KEYGEN", "-a ECDSAP256SHA256 -L 7200")
   1409     settime = EnvCmd("SETTIME", "-s")
   1410 
   1411     # Step 1:
   1412     # Introduce the first key. This will immediately be active.
   1413     zonename = f"step1.{zone}"
   1414     zones.append(Zone(zonename, f"{zonename}.db", Nameserver("ns3", "10.53.0.3")))
   1415     isctest.log.info(f"setup {zonename}")
   1416     # Timing metadata.
   1417     TactN = "now-7d"
   1418     keytimes = f"-P {TactN} -A {TactN}"
   1419     # Key generation.
   1420     ksk_name = keygen(f"-f KSK {keytimes} {zonename}", cwd="ns3").out.strip()
   1421     zsk_name = keygen(f"{keytimes} {zonename}", cwd="ns3").out.strip()
   1422     settime(
   1423         f"-g OMNIPRESENT -k OMNIPRESENT {TactN} -r OMNIPRESENT {TactN} -d OMNIPRESENT {TactN} {ksk_name}",
   1424         cwd="ns3",
   1425     )
   1426     settime(
   1427         f"-g OMNIPRESENT -k OMNIPRESENT {TactN} -z OMNIPRESENT {TactN} {zsk_name}",
   1428         cwd="ns3",
   1429     )
   1430     # Signing.
   1431     render_and_sign_zone(zonename, [ksk_name, zsk_name], extra_options=f"-G {cds}")
   1432 
   1433     # Step 2:
   1434     # It is time to introduce the new KSK.
   1435     zonename = f"step2.{zone}"
   1436     zones.append(Zone(zonename, f"{zonename}.db", Nameserver("ns3", "10.53.0.3")))
   1437     isctest.log.info(f"setup {zonename}")
   1438     # Lksk:           60d
   1439     # Dreg:           n/a
   1440     # DprpC:          1h
   1441     # TTLds:          1d
   1442     # TTLkey:         2h
   1443     # publish-safety: 1d
   1444     # retire-safety:  2d
   1445     #
   1446     # According to RFC 7583:
   1447     # Tpub(N+1) <= Tact(N) + Lksk - Dreg - IpubC
   1448     # IpubC = DprpC + TTLkey (+publish-safety)
   1449     #
   1450     # IpubC   = 27h
   1451     # Tact(N) = now - Lksk + Dreg + IpubC = now - 60d + 27h
   1452     #         = now - 1440h + 27h = now - 1413h
   1453     TactN = "now-1413h"
   1454     keytimes = f"-P {TactN} -A {TactN}"
   1455     # Key generation.
   1456     ksk_name = keygen(f"-f KSK {keytimes} {zonename}", cwd="ns3").out.strip()
   1457     zsk_name = keygen(f"{keytimes} {zonename}", cwd="ns3").out.strip()
   1458     settime(
   1459         f"-g OMNIPRESENT -k OMNIPRESENT {TactN} -r OMNIPRESENT {TactN} -d OMNIPRESENT {TactN} {ksk_name}",
   1460         cwd="ns3",
   1461     )
   1462     settime(
   1463         f"-g OMNIPRESENT -k OMNIPRESENT {TactN} -z OMNIPRESENT {TactN} {zsk_name}",
   1464         cwd="ns3",
   1465     )
   1466     # Signing.
   1467     render_and_sign_zone(zonename, [ksk_name, zsk_name], extra_options=f"-G {cds}")
   1468 
   1469     # Step 3:
   1470     # It is time to submit the DS.
   1471     zonename = f"step3.{zone}"
   1472     zones.append(Zone(zonename, f"{zonename}.db", Nameserver("ns3", "10.53.0.3")))
   1473     isctest.log.info(f"setup {zonename}")
   1474     # According to RFC 7583:
   1475     # Iret = DprpP + TTLds (+retire-safety)
   1476     #
   1477     # Iret       = 50h
   1478     # Tpub(N)    = now - Lksk = now - 60d = now - 60d
   1479     # Tact(N)    = now - 1413h
   1480     # Tret(N)    = now
   1481     # Trem(N)    = now + Iret = now + 50h
   1482     # Tpub(N+1)  = now - IpubC = now - 27h
   1483     # Tact(N+1)  = now
   1484     # Tret(N+1)  = now + Lksk = now + 60d
   1485     # Trem(N+1)  = now + Lksk + Iret = now + 60d + 50h
   1486     #            = now + 1440h + 50h = 1490h
   1487     TpubN = "now-60d"
   1488     TactN = "now-1413h"
   1489     TretN = "now"
   1490     TremN = "now+50h"
   1491     TpubN1 = "now-27h"
   1492     TactN1 = "now"
   1493     TretN1 = "now+60d"
   1494     TremN1 = "now+1490h"
   1495     ksktimes = (
   1496         f"-P {TpubN} -A {TpubN} -P sync {TactN} -I {TretN} -D {TremN} -D sync {TactN1}"
   1497     )
   1498     newtimes = f"-P {TpubN1} -A {TactN1} -P sync {TactN1} -I {TretN1} -D {TremN1}"
   1499     zsktimes = f"-P {TpubN}  -A {TpubN}"
   1500     # Key generation.
   1501     ksk1_name = keygen(f"-f KSK {ksktimes} {zonename}", cwd="ns3").out.strip()
   1502     ksk2_name = keygen(f"-f KSK {newtimes} {zonename}", cwd="ns3").out.strip()
   1503     zsk_name = keygen(f"{zsktimes} {zonename}", cwd="ns3").out.strip()
   1504     settime(
   1505         f"-g HIDDEN -k OMNIPRESENT {TactN} -r OMNIPRESENT {TactN} -d OMNIPRESENT {TactN} {ksk1_name}",
   1506         cwd="ns3",
   1507     )
   1508     settime(
   1509         f"-g OMNIPRESENT -k RUMOURED {TpubN1} -r RUMOURED {TpubN1} -d HIDDEN {TpubN1} {ksk2_name}",
   1510         cwd="ns3",
   1511     )
   1512     settime(
   1513         f"-g OMNIPRESENT -k OMNIPRESENT {TpubN} -z OMNIPRESENT {TpubN} {zsk_name}",
   1514         cwd="ns3",
   1515     )
   1516     # Set key rollover relationship.
   1517     set_key_relationship(ksk1_name, ksk2_name)
   1518     # Signing.
   1519     render_and_sign_zone(
   1520         zonename, [ksk1_name, ksk2_name, zsk_name], extra_options=f"-G {cds}"
   1521     )
   1522 
   1523     # Step 4:
   1524     # The DS should be swapped now.
   1525     zonename = f"step4.{zone}"
   1526     zones.append(Zone(zonename, f"{zonename}.db", Nameserver("ns3", "10.53.0.3")))
   1527     isctest.log.info(f"setup {zonename}")
   1528     # Tpub(N)    = now - Lksk - Iret = now - 60d - 50h
   1529     #            = now - 1440h - 50h = now - 1490h
   1530     # Tact(N)    = now - 1490h + 27h = now - 1463h
   1531     # Tret(N)    = now - Iret = now - 50h
   1532     # Trem(N)    = now
   1533     # Tpub(N+1)  = now - Iret - IpubC = now - 50h - 27h
   1534     #            = now - 77h
   1535     # Tact(N+1)  = Tret(N)
   1536     # Tret(N+1)  = now + Lksk - Iret = now + 60d - 50h = now + 1390h
   1537     # Trem(N+1)  = now + Lksk = now + 60d
   1538     TpubN = "now-1490h"
   1539     TactN = "now-1463h"
   1540     TretN = "now-50h"
   1541     TremN = "now"
   1542     TpubN1 = "now-77h"
   1543     TactN1 = TretN
   1544     TretN1 = "now+1390h"
   1545     TremN1 = "now+60d"
   1546     ksktimes = (
   1547         f"-P {TpubN} -A {TpubN} -P sync {TactN} -I {TretN} -D {TremN} -D sync {TactN1}"
   1548     )
   1549     newtimes = f"-P {TpubN1} -A {TactN1} -P sync {TactN1} -I {TretN1} -D {TremN1}"
   1550     zsktimes = f"-P {TpubN} -A {TpubN}"
   1551     # Key generation.
   1552     ksk1_name = keygen(f"-f KSK {ksktimes} {zonename}", cwd="ns3").out.strip()
   1553     ksk2_name = keygen(f"-f KSK {newtimes} {zonename}", cwd="ns3").out.strip()
   1554     zsk_name = keygen(f"{zsktimes} {zonename}", cwd="ns3").out.strip()
   1555     settime(
   1556         f"-g HIDDEN -k OMNIPRESENT {TactN} -r OMNIPRESENT {TactN} -d UNRETENTIVE {TretN} -D ds {TretN} {ksk1_name}",
   1557         cwd="ns3",
   1558     )
   1559     settime(
   1560         f"-g OMNIPRESENT -k OMNIPRESENT {TactN1} -r OMNIPRESENT {TactN1} -d RUMOURED {TactN1} -P ds {TactN1} {ksk2_name}",
   1561         cwd="ns3",
   1562     )
   1563     settime(
   1564         f"-g OMNIPRESENT -k OMNIPRESENT {TactN} -z OMNIPRESENT {TactN} {zsk_name}",
   1565         cwd="ns3",
   1566     )
   1567     # Set key rollover relationship.
   1568     set_key_relationship(ksk1_name, ksk2_name)
   1569     # Signing.
   1570     render_and_sign_zone(
   1571         zonename, [ksk1_name, ksk2_name, zsk_name], extra_options=f"-G {cds}"
   1572     )
   1573 
   1574     # Step 5:
   1575     # The predecessor DNSKEY is removed long enough that is has become HIDDEN.
   1576     zonename = f"step5.{zone}"
   1577     zones.append(Zone(zonename, f"{zonename}.db", Nameserver("ns3", "10.53.0.3")))
   1578     isctest.log.info(f"setup {zonename}")
   1579     # Subtract DNSKEY TTL + zone-propagation-delay from all the times (3h).
   1580     # Tpub(N)    = now - 1490h - 3h = now - 1493h
   1581     # Tact(N)    = now - 1463h - 3h = now - 1466h
   1582     # Tret(N)    = now - 50h - 3h = now - 53h
   1583     # Trem(N)    = now - 3h
   1584     # Tpub(N+1)  = now - 77h - 3h = now - 80h
   1585     # Tact(N+1)  = Tret(N)
   1586     # Tret(N+1)  = now + 1390h - 3h = now + 1387h
   1587     # Trem(N+1)  = now + 60d - 3h = now + 1441h
   1588     TpubN = "now-1493h"
   1589     TactN = "now-1466h"
   1590     TretN = "now-53h"
   1591     TremN = "now-3h"
   1592     TpubN1 = "now-80h"
   1593     TactN1 = TretN
   1594     TretN1 = "now+1387h"
   1595     TremN1 = "now+1441h"
   1596     ksktimes = (
   1597         f"-P {TpubN} -A {TpubN} -P sync {TactN} -I {TretN} -D {TremN} -D sync {TactN1}"
   1598     )
   1599     newtimes = f"-P {TpubN1} -A {TactN1} -P sync {TactN1} -I {TretN1} -D {TremN1}"
   1600     zsktimes = f"-P {TpubN} -A {TpubN}"
   1601     # Key generation.
   1602     ksk1_name = keygen(f"-f KSK {ksktimes} {zonename}", cwd="ns3").out.strip()
   1603     ksk2_name = keygen(f"-f KSK {newtimes} {zonename}", cwd="ns3").out.strip()
   1604     zsk_name = keygen(f"{zsktimes} {zonename}", cwd="ns3").out.strip()
   1605     settime(
   1606         f"-g HIDDEN -k UNRETENTIVE {TretN} -r UNRETENTIVE {TretN} -d HIDDEN {TretN} {ksk1_name}",
   1607         cwd="ns3",
   1608     )
   1609     settime(
   1610         f"-g OMNIPRESENT -k OMNIPRESENT {TactN1} -r OMNIPRESENT {TactN1} -d OMNIPRESENT {TactN1} {ksk2_name}",
   1611         cwd="ns3",
   1612     )
   1613     settime(
   1614         f"-g OMNIPRESENT -k OMNIPRESENT {TactN} -z OMNIPRESENT {TactN} {zsk_name}",
   1615         cwd="ns3",
   1616     )
   1617     # Set key rollover relationship.
   1618     set_key_relationship(ksk1_name, ksk2_name)
   1619     # Signing.
   1620     render_and_sign_zone(
   1621         zonename, [ksk1_name, ksk2_name, zsk_name], extra_options=f"-G {cds}"
   1622     )
   1623 
   1624     # Step 6:
   1625     # The predecessor DNSKEY can be purged.
   1626     zonename = f"step6.{zone}"
   1627     zones.append(Zone(zonename, f"{zonename}.db", Nameserver("ns3", "10.53.0.3")))
   1628     isctest.log.info(f"setup {zonename}")
   1629     # Subtract purge-keys interval from all the times (1h).
   1630     TpubN = "now-1494h"
   1631     TactN = "now-1467h"
   1632     TretN = "now-54h"
   1633     TremN = "now-4h"
   1634     TpubN1 = "now-81h"
   1635     TactN1 = TretN
   1636     TretN1 = "now+1386h"
   1637     TremN1 = "now+1440h"
   1638     ksktimes = (
   1639         f"-P {TpubN} -A {TpubN} -P sync {TactN} -I {TretN} -D {TremN} -D sync {TactN1}"
   1640     )
   1641     newtimes = f"-P {TpubN1} -A {TactN1} -P sync {TactN1} -I {TretN1} -D {TremN1}"
   1642     zsktimes = f"-P {TpubN} -A {TpubN}"
   1643     # Key generation.
   1644     ksk1_name = keygen(f"-f KSK {ksktimes} {zonename}", cwd="ns3").out.strip()
   1645     ksk2_name = keygen(f"-f KSK {newtimes} {zonename}", cwd="ns3").out.strip()
   1646     zsk_name = keygen(f"{zsktimes} {zonename}", cwd="ns3").out.strip()
   1647     settime(
   1648         f"-g HIDDEN -k HIDDEN {TretN} -r HIDDEN {TretN} -d HIDDEN {TretN} {ksk1_name}",
   1649         cwd="ns3",
   1650     )
   1651     settime(
   1652         f"-g OMNIPRESENT -k OMNIPRESENT {TactN1} -r OMNIPRESENT {TactN1} -d OMNIPRESENT {TactN1} {ksk2_name}",
   1653         cwd="ns3",
   1654     )
   1655     settime(
   1656         f"-g OMNIPRESENT -k OMNIPRESENT {TactN} -z OMNIPRESENT {TactN} {zsk_name}",
   1657         cwd="ns3",
   1658     )
   1659     # Set key rollover relationship.
   1660     set_key_relationship(ksk1_name, ksk2_name)
   1661     # Signing.
   1662     render_and_sign_zone(
   1663         zonename, [ksk1_name, ksk2_name, zsk_name], extra_options=f"-G {cds}"
   1664     )
   1665 
   1666     return zones
   1667 
   1668 
   1669 def configure_ksk_3crowd(tld: str) -> List[Zone]:
   1670     # Test #2375, the "three is a crowd" bug, where a new key is introduced but the
   1671     # previous rollover has not finished yet. In other words, we have a key KEY2
   1672     # that is the successor of key KEY1, and we introduce a new key KEY3 that is
   1673     # the successor of key KEY2:
   1674     #
   1675     #     KEY1 < KEY2 < KEY3.
   1676     #
   1677     # The expected behavior is that all three keys remain in the zone, and not
   1678     # the bug behavior where KEY2 is removed and immediately replaced with KEY3.
   1679     #
   1680     zones = []
   1681     cds = "cds:sha-256"
   1682     keygen = EnvCmd("KEYGEN", "-a ECDSAP256SHA256 -L 7200")
   1683     settime = EnvCmd("SETTIME", "-s")
   1684 
   1685     # Set up a zone that has a KSK (KEY1) and have the successor key (KEY2)
   1686     # published as well.
   1687     zonename = f"three-is-a-crowd.{tld}"
   1688     zones.append(Zone(zonename, f"{zonename}.db", Nameserver("ns3", "10.53.0.3")))
   1689     isctest.log.info(f"setup {zonename}")
   1690     # These times are the same as step3.ksk-doubleksk.autosign.
   1691     TpubN = "now-60d"
   1692     TactN = "now-1413h"
   1693     TretN = "now"
   1694     TremN = "now+50h"
   1695     TpubN1 = "now-27h"
   1696     TactN1 = TretN
   1697     TretN1 = "now+60d"
   1698     TremN1 = "now+1490h"
   1699     ksktimes = (
   1700         f"-P {TpubN} -A {TpubN} -P sync {TactN} -I {TretN} -D {TremN} -D sync {TactN1}"
   1701     )
   1702     newtimes = f"-P {TpubN1} -A {TactN1} -P sync {TactN1} -I {TretN1} -D {TremN1}"
   1703     zsktimes = f"-P {TpubN}  -A {TpubN}"
   1704     # Key generation.
   1705     ksk1_name = keygen(f"-f KSK {ksktimes} {zonename}", cwd="ns3").out.strip()
   1706     ksk2_name = keygen(f"-f KSK {newtimes} {zonename}", cwd="ns3").out.strip()
   1707     zsk_name = keygen(f"{zsktimes} {zonename}", cwd="ns3").out.strip()
   1708     settime(
   1709         f"-g HIDDEN -k OMNIPRESENT {TactN} -r OMNIPRESENT {TactN} -d OMNIPRESENT {TactN} {ksk1_name}",
   1710         cwd="ns3",
   1711     )
   1712     settime(
   1713         f"-g OMNIPRESENT -k RUMOURED {TpubN1} -r RUMOURED {TpubN1} -d HIDDEN {TpubN1} {ksk2_name}",
   1714         cwd="ns3",
   1715     )
   1716     settime(
   1717         f"-g OMNIPRESENT -k OMNIPRESENT {TpubN} -z OMNIPRESENT {TpubN} {zsk_name}",
   1718         cwd="ns3",
   1719     )
   1720     # Set key rollover relationship.
   1721     set_key_relationship(ksk1_name, ksk2_name)
   1722     # Signing.
   1723     render_and_sign_zone(
   1724         zonename, [ksk1_name, ksk2_name, zsk_name], extra_options=f"-G {cds}"
   1725     )
   1726 
   1727     return zones
   1728 
   1729 
   1730 def configure_zsk_prepub(tld: str) -> List[Zone]:
   1731     # The zones at zsk-prepub.$tld represent the various steps of a ZSK
   1732     # Pre-Publication rollover.
   1733     zones = []
   1734     zone = f"zsk-prepub.{tld}"
   1735     keygen = EnvCmd("KEYGEN", "-a ECDSAP256SHA256 -L 3600")
   1736     settime = EnvCmd("SETTIME", "-s")
   1737 
   1738     # Step 1:
   1739     # Introduce the first key. This will immediately be active.
   1740     zonename = f"step1.{zone}"
   1741     zones.append(Zone(zonename, f"{zonename}.db", Nameserver("ns3", "10.53.0.3")))
   1742     isctest.log.info(f"setup {zonename}")
   1743     # Timing metadata.
   1744     TactN = "now-7d"
   1745     keytimes = f"-P {TactN} -A {TactN}"
   1746     # Key generation.
   1747     ksk_name = keygen(f"-f KSK {keytimes} {zonename}", cwd="ns3").out.strip()
   1748     zsk_name = keygen(f"{keytimes} {zonename}", cwd="ns3").out.strip()
   1749     settime(
   1750         f"-g OMNIPRESENT -k OMNIPRESENT {TactN} -r OMNIPRESENT {TactN} -d OMNIPRESENT {TactN} {ksk_name}",
   1751         cwd="ns3",
   1752     )
   1753     settime(
   1754         f"-g OMNIPRESENT -k OMNIPRESENT {TactN} -z OMNIPRESENT {TactN} {zsk_name}",
   1755         cwd="ns3",
   1756     )
   1757     # Signing.
   1758     render_and_sign_zone(zonename, [ksk_name, zsk_name])
   1759 
   1760     # Step 2:
   1761     # It is time to pre-publish the successor ZSK.
   1762     zonename = f"step2.{zone}"
   1763     zones.append(Zone(zonename, f"{zonename}.db", Nameserver("ns3", "10.53.0.3")))
   1764     isctest.log.info(f"setup {zonename}")
   1765     # According to RFC 7583:
   1766     # Tact(N) = now + Ipub - Lzsk = now + 26h - 30d
   1767     #         = now + 26h - 30d = now  694h
   1768     TactN = "now-694h"
   1769     keytimes = f"-P {TactN} -A {TactN}"
   1770     # Key generation.
   1771     ksk_name = keygen(f"-f KSK {keytimes} {zonename}", cwd="ns3").out.strip()
   1772     zsk_name = keygen(f"{keytimes} {zonename}", cwd="ns3").out.strip()
   1773     settime(
   1774         f"-g OMNIPRESENT -k OMNIPRESENT {TactN} -r OMNIPRESENT {TactN} -d OMNIPRESENT {TactN} {ksk_name}",
   1775         cwd="ns3",
   1776     )
   1777     settime(
   1778         f"-g OMNIPRESENT -k OMNIPRESENT {TactN} -z OMNIPRESENT {TactN} {zsk_name}",
   1779         cwd="ns3",
   1780     )
   1781     # Signing.
   1782     render_and_sign_zone(zonename, [ksk_name, zsk_name])
   1783 
   1784     # Step 3:
   1785     # After the publication interval has passed the DNSKEY of the successor ZSK
   1786     # is OMNIPRESENT and the zone can thus be signed with the successor ZSK.
   1787     zonename = f"step3.{zone}"
   1788     zones.append(Zone(zonename, f"{zonename}.db", Nameserver("ns3", "10.53.0.3")))
   1789     isctest.log.info(f"setup {zonename}")
   1790     # According to RFC 7583:
   1791     # Tpub(N+1) <= Tact(N) + Lzsk - Ipub
   1792     # Tact(N+1) = Tact(N) + Lzsk
   1793     #
   1794     # Tact(N)   = now - Lzsk = now - 30d
   1795     # Tpub(N+1) = now - Ipub = now - 26h
   1796     # Tact(N+1) = now
   1797     # Tret(N) = now
   1798     # Trem(N) = now + Iret = now + Dsign + Dprp + TTLsig + retire-safety = 8d1h = now + 241h
   1799     TactN = "now-30d"
   1800     TpubN1 = "now-26h"
   1801     TactN1 = "now"
   1802     TremN = "now+241h"
   1803     keytimes = f"-P {TactN} -A {TactN}"
   1804     oldtimes = f"-P {TactN} -A {TactN} -I {TactN1} -D {TremN}"
   1805     newtimes = f"-P {TpubN1} -A {TactN1}"
   1806     # Key generation.
   1807     ksk_name = keygen(f"-f KSK {keytimes} {zonename}", cwd="ns3").out.strip()
   1808     zsk1_name = keygen(f"{oldtimes} {zonename}", cwd="ns3").out.strip()
   1809     zsk2_name = keygen(f"{newtimes} {zonename}", cwd="ns3").out.strip()
   1810     settime(
   1811         f"-g OMNIPRESENT -k OMNIPRESENT {TactN} -r OMNIPRESENT {TactN} -d OMNIPRESENT {TactN} {ksk_name}",
   1812         cwd="ns3",
   1813     )
   1814     settime(
   1815         f"-g HIDDEN -k OMNIPRESENT {TactN} -z OMNIPRESENT {TactN} {zsk1_name}",
   1816         cwd="ns3",
   1817     )
   1818     settime(
   1819         f"-g OMNIPRESENT -k RUMOURED {TpubN1} -z HIDDEN {TpubN1} {zsk2_name}", cwd="ns3"
   1820     )
   1821     # Set key rollover relationship.
   1822     set_key_relationship(zsk1_name, zsk2_name)
   1823     # Signing.
   1824     render_and_sign_zone(zonename, [ksk_name, zsk1_name, zsk2_name])
   1825 
   1826     # Step 4:
   1827     # After the retire interval has passed the predecessor DNSKEY can be
   1828     # removed from the zone.
   1829     zonename = f"step4.{zone}"
   1830     zones.append(Zone(zonename, f"{zonename}.db", Nameserver("ns3", "10.53.0.3")))
   1831     isctest.log.info(f"setup {zonename}")
   1832     # Lzsk:          30d
   1833     # Ipub:          26h
   1834     # Dsgn:          1w
   1835     # Dprp:          1h
   1836     # TTLsig:        1d
   1837     # retire-safety: 2d
   1838     #
   1839     # According to RFC 7583:
   1840     # Iret      = Dsgn + Dprp + TTLsig (+retire-safety)
   1841     # Iret      = 1w + 1h + 1d + 2d = 10d1h = 241h
   1842     #
   1843     # Tact(N)   = now - Iret - Lzsk
   1844     #           = now - 241h - 30d = now - 241h - 720h
   1845     #           = now - 961h
   1846     # Tpub(N+1) = now - Iret - Ipub
   1847     #           = now - 241h - 26h
   1848     #           = now - 267h
   1849     # Tact(N+1) = now - Iret = now - 241h
   1850     TactN = "now-961h"
   1851     TpubN1 = "now-267h"
   1852     TactN1 = "now-241h"
   1853     TremN = "now"
   1854     keytimes = f"-P {TactN} -A {TactN}"
   1855     oldtimes = f"-P {TactN} -A {TactN} -I {TactN1} -D {TremN}"
   1856     newtimes = f"-P {TpubN1} -A {TactN1}"
   1857     # Key generation.
   1858     ksk_name = keygen(f"-f KSK {keytimes} {zonename}", cwd="ns3").out.strip()
   1859     zsk1_name = keygen(f"{oldtimes} {zonename}", cwd="ns3").out.strip()
   1860     zsk2_name = keygen(f"{newtimes} {zonename}", cwd="ns3").out.strip()
   1861     settime(
   1862         f"-g OMNIPRESENT -k OMNIPRESENT {TactN} -r OMNIPRESENT {TactN} -d OMNIPRESENT {TactN} {ksk_name}",
   1863         cwd="ns3",
   1864     )
   1865     settime(
   1866         f"-g HIDDEN -k OMNIPRESENT {TactN} -z UNRETENTIVE {TactN1} {zsk1_name}",
   1867         cwd="ns3",
   1868     )
   1869     settime(
   1870         f"-g OMNIPRESENT -k OMNIPRESENT {TactN1} -z RUMOURED {TactN1} {zsk2_name}",
   1871         cwd="ns3",
   1872     )
   1873     # Set key rollover relationship.
   1874     set_key_relationship(zsk1_name, zsk2_name)
   1875     # Signing.
   1876     render_and_sign_zone(zonename, [ksk_name, zsk1_name, zsk2_name])
   1877 
   1878     # Step 5:
   1879     # The predecessor DNSKEY is removed long enough that is has become HIDDEN.
   1880     zonename = f"step5.{zone}"
   1881     zones.append(Zone(zonename, f"{zonename}.db", Nameserver("ns3", "10.53.0.3")))
   1882     isctest.log.info(f"setup {zonename}")
   1883     # Subtract DNSKEY TTL + zone-propagation-delay from all the times (2h).
   1884     # Tact(N)   = now - 961h - 2h = now - 963h
   1885     # Tpub(N+1) = now - 267h - 2h = now - 269h
   1886     # Tact(N+1) = now - 241h - 2h = now - 243h
   1887     # Trem(N)   = Tact(N+1) + Iret = now -2h
   1888     TactN = "now-963h"
   1889     TremN = "now-2h"
   1890     TpubN1 = "now-269h"
   1891     TactN1 = "now-243h"
   1892     TremN = "now-2h"
   1893     keytimes = f"-P {TactN} -A {TactN}"
   1894     oldtimes = f"-P {TactN} -A {TactN} -I {TactN1} -D {TremN}"
   1895     newtimes = f"-P {TpubN1} -A {TactN1}"
   1896     # Key generation.
   1897     ksk_name = keygen(f"-f KSK {keytimes} {zonename}", cwd="ns3").out.strip()
   1898     zsk1_name = keygen(f"{oldtimes} {zonename}", cwd="ns3").out.strip()
   1899     zsk2_name = keygen(f"{newtimes} {zonename}", cwd="ns3").out.strip()
   1900     settime(
   1901         f"-g OMNIPRESENT -k OMNIPRESENT {TactN} -r OMNIPRESENT {TactN} -d OMNIPRESENT {TactN} {ksk_name}",
   1902         cwd="ns3",
   1903     )
   1904     settime(
   1905         f"-g HIDDEN -k UNRETENTIVE {TremN} -z HIDDEN {TremN} {zsk1_name}", cwd="ns3"
   1906     )
   1907     settime(
   1908         f"-g OMNIPRESENT -k OMNIPRESENT {TactN1} -z OMNIPRESENT {TremN} {zsk2_name}",
   1909         cwd="ns3",
   1910     )
   1911     # Set key rollover relationship.
   1912     set_key_relationship(zsk1_name, zsk2_name)
   1913     # Signing.
   1914     render_and_sign_zone(zonename, [ksk_name, zsk1_name, zsk2_name])
   1915 
   1916     # Step 6:
   1917     # The predecessor DNSKEY can be purged.
   1918     zonename = f"step6.{zone}"
   1919     zones.append(Zone(zonename, f"{zonename}.db", Nameserver("ns3", "10.53.0.3")))
   1920     isctest.log.info(f"setup {zonename}")
   1921     # Subtract purge-keys interval from all the times (1h).
   1922     TactN = "now-964h"
   1923     TremN = "now-3h"
   1924     TpubN1 = "now-270h"
   1925     TactN1 = "now-244h"
   1926     TremN = "now-3h"
   1927     keytimes = f"-P {TactN} -A {TactN}"
   1928     oldtimes = f"-P {TactN} -A {TactN} -I {TactN1} -D {TremN}"
   1929     newtimes = f"-P {TpubN1} -A {TactN1}"
   1930     # Key generation.
   1931     ksk_name = keygen(f"-f KSK {keytimes} {zonename}", cwd="ns3").out.strip()
   1932     zsk1_name = keygen(f"{oldtimes} {zonename}", cwd="ns3").out.strip()
   1933     zsk2_name = keygen(f"{newtimes} {zonename}", cwd="ns3").out.strip()
   1934     settime(
   1935         f"-g OMNIPRESENT -k OMNIPRESENT {TactN} -r OMNIPRESENT {TactN} -d OMNIPRESENT {TactN} {ksk_name}",
   1936         cwd="ns3",
   1937     )
   1938     settime(f"-g HIDDEN -k HIDDEN {TremN} -z HIDDEN {TremN} {zsk1_name}", cwd="ns3")
   1939     settime(
   1940         f"-g OMNIPRESENT -k OMNIPRESENT {TactN1} -z OMNIPRESENT {TremN} {zsk2_name}",
   1941         cwd="ns3",
   1942     )
   1943     # Set key rollover relationship.
   1944     set_key_relationship(zsk1_name, zsk2_name)
   1945     # Signing.
   1946     render_and_sign_zone(zonename, [ksk_name, zsk1_name, zsk2_name])
   1947 
   1948     return zones
   1949