From d8b1e148f785392e7119654e24c381602dce263d Mon Sep 17 00:00:00 2001
From: Libor Peltan <libor.peltan@nic.cz>
Date: Tue, 14 Dec 2021 19:56:05 +0100
Subject: [PATCH] dnssec: enforce safe rrsig-refresh

---
 src/knot/dnssec/zone-events.c                    |  4 +++-
 .../dnssec/keytag_conflict/data/example.com.zone | 16 ++++++++++++++++
 tests-extra/tests/dnssec/keytag_conflict/test.py | 13 ++++++++-----
 tests-extra/tests/dnssec/offline_ksk/test.py     |  2 +-
 .../dnssec/prerefresh/data/example.com.zone      | 16 ++++++++++++++++
 tests-extra/tests/dnssec/prerefresh/test.py      |  6 ++++--
 6 files changed, 48 insertions(+), 9 deletions(-)
 create mode 100644 tests-extra/tests/dnssec/keytag_conflict/data/example.com.zone
 create mode 100644 tests-extra/tests/dnssec/prerefresh/data/example.com.zone

diff --git a/src/knot/dnssec/zone-events.c b/src/knot/dnssec/zone-events.c
index 8811099c95..0dcb06516b 100644
--- a/src/knot/dnssec/zone-events.c
+++ b/src/knot/dnssec/zone-events.c
@@ -138,7 +138,9 @@ int knot_dnssec_zone_sign(zone_update_t *update,
 	update_policy_from_zone(ctx.policy, update->new_cont);
 
 	if (ctx.policy->rrsig_refresh_before < ctx.policy->zone_maximal_ttl + ctx.policy->propagation_delay) {
-		log_zone_warning(zone_name, "DNSSEC, rrsig-refresh too low to prevent expired RRSIGs in resolver caches");
+		log_zone_error(zone_name, "DNSSEC, rrsig-refresh too low to prevent expired RRSIGs in resolver caches");
+		result = KNOT_EINVAL;
+		goto done;
 	}
 
 	// perform key rollover if needed
diff --git a/tests-extra/tests/dnssec/keytag_conflict/data/example.com.zone b/tests-extra/tests/dnssec/keytag_conflict/data/example.com.zone
new file mode 100644
index 0000000000..7759558098
--- /dev/null
+++ b/tests-extra/tests/dnssec/keytag_conflict/data/example.com.zone
@@ -0,0 +1,16 @@
+$ORIGIN example.com.
+$TTL 1
+
+@	SOA	dns1 hostmaster 2010111201 10800 3600 1209600 1
+	NS	dns1
+	NS	dns2
+	MX	10 mail
+
+dns1	A	192.0.2.1
+	AAAA	2001:DB8::1
+
+dns2	A	192.0.2.2
+	AAAA	2001:DB8::2
+
+mail	A	192.0.2.3
+	AAAA	2001:DB8::3
diff --git a/tests-extra/tests/dnssec/keytag_conflict/test.py b/tests-extra/tests/dnssec/keytag_conflict/test.py
index c4f0501315..52e12abe43 100644
--- a/tests-extra/tests/dnssec/keytag_conflict/test.py
+++ b/tests-extra/tests/dnssec/keytag_conflict/test.py
@@ -17,12 +17,14 @@ from dnstest.test import Test
 
 t = Test()
 
+ZONE = "example.com."
+
 # check zone if keys are present and used for signing
 def check_zone4(server, min_dnskeys, min_rrsigs, msg):
-    dnskeys = server.dig("example.com", "DNSKEY")
+    dnskeys = server.dig(ZONE, "DNSKEY")
     found_dnskeys = dnskeys.count("DNSKEY")
 
-    soa = server.dig("mail.example.com", "A", dnssec=True)
+    soa = server.dig("mail." + ZONE, "A", dnssec=True)
     found_rrsigs = soa.count("RRSIG")
 
     check_log("RRSIGs: %d (expected min %d)" % (found_rrsigs, min_rrsigs));
@@ -37,18 +39,20 @@ def check_zone4(server, min_dnskeys, min_rrsigs, msg):
         detail_log("!DNSKEYs not published and activated as expected: " + msg)
 
     server.flush(wait=True)
-    server.zone_verify(server.zones["example.com."])
+    server.zone_verify(server.zones[ZONE])
 
     detail_log(SEP)
 
 knot = t.server("knot")
-zone = t.zone("example.com.")
+zone = t.zone(ZONE, storage=".")
 t.link(zone, knot)
 knot.dnssec(zone).enable = True
 knot.dnssec(zone).manual = True
 knot.dnssec(zone).rrsig_lifetime = 50
 knot.dnssec(zone).rrsig_refresh = 2
 knot.dnssec(zone).rrsig_prerefresh = 1
+knot.dnssec(zone).dnskey_ttl = 1
+knot.dnssec(zone).propagation_delay = 1
 knot.zonefile_sync = "0"
 
 # install KASP db (one always enabled, one for testing)
@@ -60,7 +64,6 @@ shutil.copytree(os.path.join(t.data_dir, "keys"), keydir)
 knot.gen_confile()
 
 # parameters
-ZONE = "example.com."
 KSK = "7a3500c7feac3fd99f09a208a83b97f7455fa3e0"
 ZSK1 = "712d0d0d57fa0aa006b5e20cd84e23941e5f3ab2"
 ZSK2 = "301d3fc5392e83ea02312dc5bdc1a9f0b7937ddf"
diff --git a/tests-extra/tests/dnssec/offline_ksk/test.py b/tests-extra/tests/dnssec/offline_ksk/test.py
index ef42af40ec..6a45112783 100644
--- a/tests-extra/tests/dnssec/offline_ksk/test.py
+++ b/tests-extra/tests/dnssec/offline_ksk/test.py
@@ -137,7 +137,7 @@ knot.dnssec(zone).ksk_lifetime = NONSENSE
 knot.dnssec(zone).propagation_delay = TICK - 2
 knot.dnssec(zone).cds_publish = "rollover"
 knot.dnssec(zone).rrsig_lifetime = 15
-knot.dnssec(zone).rrsig_refresh = 5
+knot.dnssec(zone).rrsig_refresh = 6
 knot.dnssec(zone).rrsig_prerefresh = 1
 
 # needed for keymgr
diff --git a/tests-extra/tests/dnssec/prerefresh/data/example.com.zone b/tests-extra/tests/dnssec/prerefresh/data/example.com.zone
new file mode 100644
index 0000000000..7759558098
--- /dev/null
+++ b/tests-extra/tests/dnssec/prerefresh/data/example.com.zone
@@ -0,0 +1,16 @@
+$ORIGIN example.com.
+$TTL 1
+
+@	SOA	dns1 hostmaster 2010111201 10800 3600 1209600 1
+	NS	dns1
+	NS	dns2
+	MX	10 mail
+
+dns1	A	192.0.2.1
+	AAAA	2001:DB8::1
+
+dns2	A	192.0.2.2
+	AAAA	2001:DB8::2
+
+mail	A	192.0.2.3
+	AAAA	2001:DB8::3
diff --git a/tests-extra/tests/dnssec/prerefresh/test.py b/tests-extra/tests/dnssec/prerefresh/test.py
index 865705592a..03b61bf282 100644
--- a/tests-extra/tests/dnssec/prerefresh/test.py
+++ b/tests-extra/tests/dnssec/prerefresh/test.py
@@ -8,13 +8,15 @@ from dnstest.test import Test
 t = Test()
 
 master = t.server("knot")
-zone = t.zone("example.com.")
+zone = t.zone("example.com.", storage=".")
 t.link(zone, master)
 
 master.dnssec(zone).enable = True
 master.dnssec(zone).rrsig_lifetime = 20
 master.dnssec(zone).rrsig_refresh = 2
 master.dnssec(zone).rrsig_prerefresh = 4
+master.dnssec(zone).propagation_delay = 1
+master.dnssec(zone).dnskey_ttl = 1
 
 t.start()
 
@@ -25,7 +27,7 @@ master.ctl("zone-sign", wait=True)
 t.sleep(2)
 
 up = master.update(zone)
-up.add("record1.example.com.", 3600, "A", "1.2.3.4")
+up.add("record1.example.com.", 1, "A", "1.2.3.4")
 up.send("NOERROR")
 
 serial_updates = master.zone_wait(zone)
-- 
GitLab