mirror of
https://gitlab.isc.org/isc-projects/bind9
synced 2025-08-21 17:48:07 +00:00
Similar to previous commit. Parametrize each test case and in case of manual-mode, execute additional checks. First a keymgr run should not change the existing key state (with exceptions of timing events such as moving from RUMOURED to OMNIPRESENT, and from UNRETENTIVE to HIDDEN). Appropriate messages must be logged. After enforcing the next step with 'rndc dnssec -step', the key state should be the same as if the step were to be taken automatically.
340 lines
13 KiB
Python
340 lines
13 KiB
Python
# 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.
|
|
|
|
# pylint: disable=redefined-outer-name,unused-import
|
|
|
|
from datetime import timedelta
|
|
|
|
import pytest
|
|
|
|
import isctest
|
|
from isctest.util import param
|
|
from rollover.common import (
|
|
pytestmark,
|
|
alg,
|
|
size,
|
|
KSK_CONFIG,
|
|
KSK_LIFETIME,
|
|
KSK_LIFETIME_POLICY,
|
|
KSK_IPUB,
|
|
KSK_IPUBC,
|
|
KSK_IRET,
|
|
KSK_KEYTTLPROP,
|
|
TIMEDELTA,
|
|
)
|
|
|
|
|
|
CDSS = ["CDS (SHA-256)"]
|
|
POLICY = "ksk-doubleksk"
|
|
OFFSETS = {}
|
|
OFFSETS["step1-p"] = -int(TIMEDELTA["P7D"].total_seconds())
|
|
OFFSETS["step2-p"] = -int(KSK_LIFETIME.total_seconds() - KSK_IPUBC.total_seconds())
|
|
OFFSETS["step2-s"] = 0
|
|
OFFSETS["step3-p"] = -int(KSK_LIFETIME.total_seconds())
|
|
OFFSETS["step3-s"] = -int(KSK_IPUBC.total_seconds())
|
|
OFFSETS["step4-p"] = OFFSETS["step3-p"] - int(KSK_IRET.total_seconds())
|
|
OFFSETS["step4-s"] = OFFSETS["step3-s"] - int(KSK_IRET.total_seconds())
|
|
OFFSETS["step5-p"] = OFFSETS["step4-p"] - int(KSK_KEYTTLPROP.total_seconds())
|
|
OFFSETS["step5-s"] = OFFSETS["step4-s"] - int(KSK_KEYTTLPROP.total_seconds())
|
|
OFFSETS["step6-p"] = OFFSETS["step5-p"] - int(KSK_CONFIG["purge-keys"].total_seconds())
|
|
OFFSETS["step6-s"] = OFFSETS["step5-s"] - int(KSK_CONFIG["purge-keys"].total_seconds())
|
|
|
|
|
|
@pytest.mark.parametrize(
|
|
"tld",
|
|
[
|
|
param("autosign"),
|
|
param("manual"),
|
|
],
|
|
)
|
|
def test_ksk_doubleksk_step1(tld, alg, size, ns3):
|
|
zone = f"step1.ksk-doubleksk.{tld}"
|
|
policy = f"{POLICY}-{tld}"
|
|
|
|
isctest.kasp.wait_keymgr_done(ns3, zone)
|
|
|
|
# manual-mode: Nothing changing in the zone, no 'dnssec -step' required.
|
|
# Note that the key was already generated during setup.
|
|
|
|
step = {
|
|
# Introduce the first key. This will immediately be active.
|
|
"zone": zone,
|
|
"cdss": CDSS,
|
|
"keyprops": [
|
|
f"zsk unlimited {alg} {size} goal:omnipresent dnskey:omnipresent zrrsig:omnipresent offset:{OFFSETS['step1-p']}",
|
|
f"ksk {KSK_LIFETIME_POLICY} {alg} {size} goal:omnipresent dnskey:omnipresent krrsig:omnipresent ds:omnipresent offset:{OFFSETS['step1-p']}",
|
|
],
|
|
# Next key event is when the successor KSK needs to be published.
|
|
# That is the KSK lifetime - prepublication time (minus time
|
|
# already passed).
|
|
"nextev": KSK_LIFETIME - KSK_IPUB - timedelta(days=7),
|
|
}
|
|
isctest.kasp.check_rollover_step(ns3, KSK_CONFIG, policy, step)
|
|
|
|
|
|
@pytest.mark.parametrize(
|
|
"tld",
|
|
[
|
|
param("autosign"),
|
|
param("manual"),
|
|
],
|
|
)
|
|
def test_ksk_doubleksk_step2(tld, alg, size, ns3):
|
|
zone = f"step2.ksk-doubleksk.{tld}"
|
|
policy = f"{POLICY}-{tld}"
|
|
|
|
isctest.kasp.wait_keymgr_done(ns3, zone)
|
|
|
|
if tld == "manual":
|
|
# Same as step 1.
|
|
step = {
|
|
"zone": zone,
|
|
"cdss": CDSS,
|
|
"keyprops": [
|
|
f"zsk unlimited {alg} {size} goal:omnipresent dnskey:omnipresent zrrsig:omnipresent offset:{OFFSETS['step2-p']}",
|
|
f"ksk {KSK_LIFETIME_POLICY} {alg} {size} goal:omnipresent dnskey:omnipresent krrsig:omnipresent ds:omnipresent offset:{OFFSETS['step2-p']}",
|
|
],
|
|
"manual-mode": True,
|
|
"nextev": None,
|
|
}
|
|
keys = isctest.kasp.check_rollover_step(ns3, KSK_CONFIG, policy, step)
|
|
|
|
# Check logs.
|
|
tag = keys[1].key.tag
|
|
msg = f"keymgr-manual-mode: block KSK rollover for key {zone}/ECDSAP256SHA256/{tag} (policy {policy})"
|
|
ns3.log.expect(msg)
|
|
|
|
# Force step.
|
|
with ns3.watch_log_from_here() as watcher:
|
|
ns3.rndc(f"dnssec -step {zone}")
|
|
watcher.wait_for_line(f"keymgr: {zone} done")
|
|
|
|
step = {
|
|
# Successor KSK is prepublished (and signs DNSKEY RRset).
|
|
# KSK1 goal: omnipresent -> hidden
|
|
# KSK2 goal: hidden -> omnipresent
|
|
# KSK2 dnskey: hidden -> rumoured
|
|
# KSK2 krrsig: hidden -> rumoured
|
|
"zone": zone,
|
|
"cdss": CDSS,
|
|
"keyprops": [
|
|
f"zsk unlimited {alg} {size} goal:omnipresent dnskey:omnipresent zrrsig:omnipresent offset:{OFFSETS['step2-p']}",
|
|
f"ksk {KSK_LIFETIME_POLICY} {alg} {size} goal:hidden dnskey:omnipresent krrsig:omnipresent ds:omnipresent offset:{OFFSETS['step2-p']}",
|
|
f"ksk {KSK_LIFETIME_POLICY} {alg} {size} goal:omnipresent dnskey:rumoured krrsig:rumoured ds:hidden offset:{OFFSETS['step2-s']}",
|
|
],
|
|
"keyrelationships": [1, 2],
|
|
# Next key event is when the successor KSK becomes OMNIPRESENT.
|
|
"nextev": KSK_IPUB,
|
|
}
|
|
isctest.kasp.check_rollover_step(ns3, KSK_CONFIG, policy, step)
|
|
|
|
|
|
@pytest.mark.parametrize(
|
|
"tld",
|
|
[
|
|
param("autosign"),
|
|
param("manual"),
|
|
],
|
|
)
|
|
def test_ksk_doubleksk_step3(tld, alg, size, ns3):
|
|
zone = f"step3.ksk-doubleksk.{tld}"
|
|
policy = f"{POLICY}-{tld}"
|
|
|
|
isctest.kasp.wait_keymgr_done(ns3, zone)
|
|
|
|
if tld == "manual":
|
|
# Same as step 2, but DNSKEY has become OMNIPRESENT.
|
|
step = {
|
|
"zone": zone,
|
|
"cdss": CDSS,
|
|
"keyprops": [
|
|
f"zsk unlimited {alg} {size} goal:omnipresent dnskey:omnipresent zrrsig:omnipresent offset:{OFFSETS['step3-p']}",
|
|
f"ksk {KSK_LIFETIME_POLICY} {alg} {size} goal:hidden dnskey:omnipresent krrsig:omnipresent ds:omnipresent offset:{OFFSETS['step3-p']}",
|
|
f"ksk {KSK_LIFETIME_POLICY} {alg} {size} goal:omnipresent dnskey:omnipresent krrsig:omnipresent ds:hidden offset:{OFFSETS['step3-s']}",
|
|
],
|
|
"keyrelationships": [1, 2],
|
|
"manual-mode": True,
|
|
"nextev": None,
|
|
}
|
|
keys = isctest.kasp.check_rollover_step(ns3, KSK_CONFIG, policy, step)
|
|
|
|
# Check logs.
|
|
tag = keys[2].key.tag
|
|
msg = f"keymgr-manual-mode: block transition KSK {zone}/ECDSAP256SHA256/{tag} type DS state HIDDEN to state RUMOURED"
|
|
ns3.log.expect(msg)
|
|
|
|
# Force step.
|
|
with ns3.watch_log_from_here() as watcher:
|
|
ns3.rndc(f"dnssec -step {zone}")
|
|
watcher.wait_for_line(f"keymgr: {zone} done")
|
|
|
|
# Check logs.
|
|
tag = keys[1].key.tag
|
|
msg = f"keymgr-manual-mode: block transition KSK {zone}/ECDSAP256SHA256/{tag} type DS state OMNIPRESENT to state UNRETENTIVE"
|
|
if msg in ns3.log:
|
|
# Force step.
|
|
isctest.log.debug(
|
|
f"keymgr-manual-mode blocking transition KSK {zone}/ECDSAP256SHA256/{tag} type DS state OMNIPRESENT to state UNRETENTIVE, step again"
|
|
)
|
|
with ns3.watch_log_from_here() as watcher:
|
|
ns3.rndc(f"dnssec -step {zone}")
|
|
watcher.wait_for_line(f"keymgr: {zone} done")
|
|
|
|
step = {
|
|
# The successor DNSKEY RRset has become omnipresent. The
|
|
# predecessor DS can be withdrawn and the successor DS can be
|
|
# introduced.
|
|
# KSK1 ds: omnipresent -> unretentive
|
|
# KSK2 dnskey: rumoured -> omnipresent
|
|
# KSK2 krrsig: rumoured -> omnipresent
|
|
# KSK2 ds: hidden -> rumoured
|
|
"zone": zone,
|
|
"cdss": CDSS,
|
|
"keyprops": [
|
|
f"zsk unlimited {alg} {size} goal:omnipresent dnskey:omnipresent zrrsig:omnipresent offset:{OFFSETS['step3-p']}",
|
|
f"ksk {KSK_LIFETIME_POLICY} {alg} {size} goal:hidden dnskey:omnipresent krrsig:omnipresent ds:unretentive offset:{OFFSETS['step3-p']}",
|
|
f"ksk {KSK_LIFETIME_POLICY} {alg} {size} goal:omnipresent dnskey:omnipresent krrsig:omnipresent ds:rumoured offset:{OFFSETS['step3-s']}",
|
|
],
|
|
"keyrelationships": [1, 2],
|
|
# Next key event is when the predecessor DS has been replaced with
|
|
# the successor DS and enough time has passed such that the all
|
|
# validators that have this DS RRset cached only know about the
|
|
# successor DS. This is the the retire interval.
|
|
"nextev": KSK_IRET,
|
|
}
|
|
isctest.kasp.check_rollover_step(ns3, KSK_CONFIG, policy, step)
|
|
|
|
|
|
@pytest.mark.parametrize(
|
|
"tld",
|
|
[
|
|
param("autosign"),
|
|
param("manual"),
|
|
],
|
|
)
|
|
def test_ksk_doubleksk_step4(tld, alg, size, ns3):
|
|
zone = f"step4.ksk-doubleksk.{tld}"
|
|
policy = f"{POLICY}-{tld}"
|
|
|
|
isctest.kasp.wait_keymgr_done(ns3, zone)
|
|
|
|
if tld == "manual":
|
|
# Same as step 3, but DS has become HIDDEN/OMNIPRESENT.
|
|
step = {
|
|
"zone": zone,
|
|
"cdss": CDSS,
|
|
"keyprops": [
|
|
f"zsk unlimited {alg} {size} goal:omnipresent dnskey:omnipresent zrrsig:omnipresent offset:{OFFSETS['step4-p']}",
|
|
f"ksk {KSK_LIFETIME_POLICY} {alg} {size} goal:hidden dnskey:omnipresent krrsig:omnipresent ds:hidden offset:{OFFSETS['step4-p']}",
|
|
f"ksk {KSK_LIFETIME_POLICY} {alg} {size} goal:omnipresent dnskey:omnipresent krrsig:omnipresent ds:omnipresent offset:{OFFSETS['step4-s']}",
|
|
],
|
|
"keyrelationships": [1, 2],
|
|
"manual-mode": True,
|
|
"nextev": None,
|
|
}
|
|
keys = isctest.kasp.check_rollover_step(ns3, KSK_CONFIG, policy, step)
|
|
|
|
# Check logs.
|
|
tag = keys[1].key.tag
|
|
msg1 = f"keymgr-manual-mode: block transition KSK {zone}/ECDSAP256SHA256/{tag} type DNSKEY state OMNIPRESENT to state UNRETENTIVE"
|
|
msg2 = f"keymgr-manual-mode: block transition KSK {zone}/ECDSAP256SHA256/{tag} type KRRSIG state OMNIPRESENT to state UNRETENTIVE"
|
|
ns3.log.expect(msg1)
|
|
ns3.log.expect(msg2)
|
|
|
|
# Force step.
|
|
with ns3.watch_log_from_here() as watcher:
|
|
ns3.rndc(f"dnssec -step {zone}")
|
|
watcher.wait_for_line(f"keymgr: {zone} done")
|
|
|
|
step = {
|
|
# The predecessor DNSKEY may be removed, the successor DS is
|
|
# omnipresent.
|
|
# KSK1 dnskey: omnipresent -> unretentive
|
|
# KSK1 krrsig: omnipresent -> unretentive
|
|
# KSK1 ds: unretentive -> hidden
|
|
# KSK2 ds: rumoured -> omnipresent
|
|
"zone": zone,
|
|
"cdss": CDSS,
|
|
"keyprops": [
|
|
f"zsk unlimited {alg} {size} goal:omnipresent dnskey:omnipresent zrrsig:omnipresent offset:{OFFSETS['step4-p']}",
|
|
f"ksk {KSK_LIFETIME_POLICY} {alg} {size} goal:hidden dnskey:unretentive krrsig:unretentive ds:hidden offset:{OFFSETS['step4-p']}",
|
|
f"ksk {KSK_LIFETIME_POLICY} {alg} {size} goal:omnipresent dnskey:omnipresent krrsig:omnipresent ds:omnipresent offset:{OFFSETS['step4-s']}",
|
|
],
|
|
"keyrelationships": [1, 2],
|
|
# Next key event is when the DNSKEY enters the HIDDEN state.
|
|
# This is the DNSKEY TTL plus zone propagation delay.
|
|
"nextev": KSK_KEYTTLPROP,
|
|
}
|
|
isctest.kasp.check_rollover_step(ns3, KSK_CONFIG, policy, step)
|
|
|
|
|
|
@pytest.mark.parametrize(
|
|
"tld",
|
|
[
|
|
param("autosign"),
|
|
param("manual"),
|
|
],
|
|
)
|
|
def test_ksk_doubleksk_step5(tld, alg, size, ns3):
|
|
zone = f"step5.ksk-doubleksk.{tld}"
|
|
policy = f"{POLICY}-{tld}"
|
|
|
|
isctest.kasp.wait_keymgr_done(ns3, zone)
|
|
|
|
# manual-mode: Nothing changing in the zone, no 'dnssec -step' required.
|
|
|
|
step = {
|
|
# The predecessor DNSKEY is long enough removed from the zone it
|
|
# has become hidden.
|
|
# KSK1 dnskey: unretentive -> hidden
|
|
# KSK1 krrsig: unretentive -> hidden
|
|
"zone": zone,
|
|
"cdss": CDSS,
|
|
"keyprops": [
|
|
f"zsk unlimited {alg} {size} goal:omnipresent dnskey:omnipresent zrrsig:omnipresent offset:{OFFSETS['step5-p']}",
|
|
f"ksk {KSK_LIFETIME_POLICY} {alg} {size} goal:hidden dnskey:hidden krrsig:hidden ds:hidden offset:{OFFSETS['step5-p']}",
|
|
f"ksk {KSK_LIFETIME_POLICY} {alg} {size} goal:omnipresent dnskey:omnipresent krrsig:omnipresent ds:omnipresent offset:{OFFSETS['step5-s']}",
|
|
],
|
|
"keyrelationships": [1, 2],
|
|
# Next key event is when the new successor needs to be published.
|
|
# This is the KSK lifetime minus Ipub minus Iret minus time elapsed.
|
|
"nextev": KSK_LIFETIME - KSK_IPUB - KSK_IRET - KSK_KEYTTLPROP,
|
|
}
|
|
isctest.kasp.check_rollover_step(ns3, KSK_CONFIG, policy, step)
|
|
|
|
|
|
@pytest.mark.parametrize(
|
|
"tld",
|
|
[
|
|
param("autosign"),
|
|
param("manual"),
|
|
],
|
|
)
|
|
def test_ksk_doubleksk_step6(tld, alg, size, ns3):
|
|
zone = f"step6.ksk-doubleksk.{tld}"
|
|
policy = f"{POLICY}-{tld}"
|
|
|
|
isctest.kasp.wait_keymgr_done(ns3, zone)
|
|
|
|
# manual-mode: Nothing changing in the zone, no 'dnssec -step' required.
|
|
|
|
step = {
|
|
# Predecessor KSK is now purged.
|
|
"zone": zone,
|
|
"cdss": CDSS,
|
|
"keyprops": [
|
|
f"zsk unlimited {alg} {size} goal:omnipresent dnskey:omnipresent zrrsig:omnipresent offset:{OFFSETS['step6-p']}",
|
|
f"ksk {KSK_LIFETIME_POLICY} {alg} {size} goal:omnipresent dnskey:omnipresent krrsig:omnipresent ds:omnipresent offset:{OFFSETS['step6-s']}",
|
|
],
|
|
"nextev": None,
|
|
}
|
|
isctest.kasp.check_rollover_step(ns3, KSK_CONFIG, policy, step)
|