1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
|
#!/usr/bin/env python3
"""
Test of offline signing using KSR and SKR with pre-planned KSK rollover and automatic ZSK rollover.
"""
import collections
import os
import shutil
import datetime
import subprocess
import time
from subprocess import check_call
from dnstest.utils import *
from dnstest.keys import Keymgr
from dnstest.test import Test
# check zone if keys are present and used for signing
def check_zone(server, zone, dnskeys, dnskey_rrsigs, soa_rrsigs, msg):
qdnskeys = server.dig("example.com", "DNSKEY", bufsize=4096)
found_dnskeys = qdnskeys.count("DNSKEY")
qdnskeyrrsig = server.dig("example.com", "DNSKEY", dnssec=True, bufsize=4096)
found_rrsigs = qdnskeyrrsig.count("RRSIG")
qsoa = server.dig("example.com", "SOA", dnssec=True, bufsize=4096)
found_soa_rrsigs = qsoa.count("RRSIG")
check_log("DNSKEYs: %d (expected %d)" % (found_dnskeys, dnskeys));
check_log("RRSIGs: %d (expected %d)" % (found_soa_rrsigs, soa_rrsigs));
check_log("DNSKEY-RRSIGs: %d (expected %d)" % (found_rrsigs, dnskey_rrsigs));
if found_dnskeys != dnskeys:
set_err("BAD DNSKEY COUNT: " + msg)
detail_log("!DNSKEYs not published and activated as expected: " + msg)
if found_soa_rrsigs != soa_rrsigs:
set_err("BAD RRSIG COUNT: " + msg)
detail_log("!RRSIGs not published and activated as expected: " + msg)
if found_rrsigs != dnskey_rrsigs:
set_err("BAD DNSKEY RRSIG COUNT: " + msg)
detail_log("!RRSIGs not published and activated as expected: " + msg)
detail_log(SEP)
# Valgrind delay breaks the timing!
if not server.valgrind:
server.zone_backup(zone, flush=True)
server.zone_verify(zone)
def wait_for_rrsig_count(t, server, rrtype, rrsig_count, timeout):
rtime = 0
while True:
qdnskeyrrsig = server.dig("example.com", rrtype, dnssec=True, bufsize=4096)
found_rrsigs = qdnskeyrrsig.count("RRSIG")
if found_rrsigs == rrsig_count:
break
rtime = rtime + 1
t.sleep(1)
if rtime > timeout:
break
def wait_for_dnskey_count(t, server, dnskey_count, timeout):
for rtime in range(1, timeout):
qdnskeyrrsig = server.dig("example.com", "DNSKEY", dnssec=True, bufsize=4096)
found_dnskeys = qdnskeyrrsig.count("DNSKEY")
if found_dnskeys == dnskey_count:
break
t.sleep(1)
def writef(filename, contents):
with open(filename, "w") as f:
f.write(contents)
t = Test()
knot = t.server("knot")
ZONE = "example.com."
FUTURE = 100
TICK = 5
STARTUP = 10
zone = t.zone(ZONE)
t.link(zone, knot)
knot.zonefile_sync = 24 * 60 * 60
knot.dnssec(zone).enable = True
knot.dnssec(zone).manual = True
knot.dnssec(zone).alg = "ECDSAP384SHA384"
knot.dnssec(zone).dnskey_ttl = 2
knot.dnssec(zone).zsk_lifetime = STARTUP + 6*TICK # see ksk1 lifetime
knot.dnssec(zone).ksk_lifetime = 300 # this can be possibly left also infinity
knot.dnssec(zone).propagation_delay = TICK-2
knot.dnssec(zone).offline_ksk = "on"
knot.dnssec(zone).cds_publish = "rollover"
knot.port = 1234 # dummy, will be overwritten
knot.gen_confile()
signer = t.server("knot")
t.link(zone, signer)
signer.zones[ZONE].dnssec = knot.zones[ZONE].dnssec
signer.port = 1235
signer.gen_confile()
def tickf(when):
return "+%d" % (STARTUP + when * TICK)
# generate keys, including manual KSK rollover on the beginning
key_ksk1 = signer.key_gen(ZONE, ksk="true", created="+0", publish="+0", ready="+0", active="+0", retire=tickf(4), remove=tickf(5))
key_ksk2 = signer.key_gen(ZONE, ksk="true", created="+0", publish=tickf(2), ready=tickf(3), active=tickf(4), retire="+2h", remove="+3h")
key_zsk1 = knot.key_gen(ZONE, ksk="false", created="+0", publish="+0", active="+0")
# pregenerate keys, exchange KSR, pre-sign it, exchange SKR
KSR = knot.keydir + "/ksr"
SKR = knot.keydir + "/skr"
Keymgr.run_check(knot.confile, ZONE, "pregenerate", "+" + str(FUTURE))
_, out, _ = Keymgr.run_check(knot.confile, ZONE, "generate-ksr", "+" + str(FUTURE))
writef(KSR, out)
_, out, _ = Keymgr.run_check(signer.confile, ZONE, "sign-ksr", KSR)
writef(SKR, out)
Keymgr.run_check(knot.confile, ZONE, "import-skr", SKR)
TICK_SAFE = TICK + TICK // 2;
# run it and see if the signing and rollovers work well
t.start()
knot.zone_wait(zone)
check_zone(knot, zone, 2, 1, 1, "init")
wait_for_dnskey_count(t, knot, 3, STARTUP + TICK_SAFE)
check_zone(knot, zone, 3, 1, 1, "KSK rollover: publish")
wait_for_rrsig_count(t, knot, "DNSKEY", 2, TICK_SAFE)
check_zone(knot, zone, 3, 2, 1, "KSK rollover: submission")
wait_for_rrsig_count(t, knot, "DNSKEY", 1, TICK_SAFE)
check_zone(knot, zone, 3, 1, 1, "KSK rollover: retired")
wait_for_dnskey_count(t, knot, 2, TICK_SAFE)
check_zone(knot, zone, 2, 1, 1, "KSK rollover: finished")
wait_for_dnskey_count(t, knot, 3, TICK_SAFE)
check_zone(knot, zone, 3, 1, 1, "ZSK rollover: running")
wait_for_dnskey_count(t, knot, 2, TICK_SAFE*2)
check_zone(knot, zone, 2, 1, 1, "ZSK rollover: done")
t.end()
|