summaryrefslogtreecommitdiffstats
path: root/modules/ta_update/ta_update.test.integr/rfc5011
diff options
context:
space:
mode:
Diffstat (limited to 'modules/ta_update/ta_update.test.integr/rfc5011')
-rw-r--r--modules/ta_update/ta_update.test.integr/rfc5011/README13
-rwxr-xr-xmodules/ta_update/ta_update.test.integr/rfc5011/dns2rpl.py222
-rw-r--r--modules/ta_update/ta_update.test.integr/rfc5011/empty.rpl20
-rwxr-xr-xmodules/ta_update/ta_update.test.integr/rfc5011/genkeyszones.sh174
-rw-r--r--modules/ta_update/ta_update.test.integr/rfc5011/knot.root.conf26
l---------modules/ta_update/ta_update.test.integr/rfc5011/pydnstest1
-rw-r--r--modules/ta_update/ta_update.test.integr/rfc5011/unsigned_check.db8
-rw-r--r--modules/ta_update/ta_update.test.integr/rfc5011/unsigned_ok.db8
8 files changed, 472 insertions, 0 deletions
diff --git a/modules/ta_update/ta_update.test.integr/rfc5011/README b/modules/ta_update/ta_update.test.integr/rfc5011/README
new file mode 100644
index 0000000..9b71987
--- /dev/null
+++ b/modules/ta_update/ta_update.test.integr/rfc5011/README
@@ -0,0 +1,13 @@
+Start with `genkeyszones.sh` and generate DNSSEC keys + signed versions of `unsigned_*.db`.
+Then use `dns2rpl.py` to run Knot DNS server with signed zone
+and to generate RPL file from server's answers.
+
+Generate RFC5011 test:
+`dns2rpl.py`.
+`./genkeyszones.sh`
+
+Generate unmanaged keys tests:
+`./genkeyszones.sh <--unmanaged_key-presens|--unmanagedkey-missing|--unmanagedkey-revoke>`
+`VARIANT="unmanaged_key" ./dns2rpl.py`
+
+See comments in script headers to further details.
diff --git a/modules/ta_update/ta_update.test.integr/rfc5011/dns2rpl.py b/modules/ta_update/ta_update.test.integr/rfc5011/dns2rpl.py
new file mode 100755
index 0000000..317d671
--- /dev/null
+++ b/modules/ta_update/ta_update.test.integr/rfc5011/dns2rpl.py
@@ -0,0 +1,222 @@
+#!/usr/bin/python3
+"""
+Generate RFC 5011 test simulating successful KSK roll-over in 2017.
+
+Dependencies: Knot DNS server + Deckard library.
+Environment: Set PYTHONPATH variable so "import pydnstest" will use module from Deckard.
+Input: Root zone files, presumably created by genkeyszones.sh.
+Output: RPL file for Deckard on standard output.
+"""
+
+import copy
+import datetime
+import os.path
+import subprocess
+import time
+
+import dns.resolver
+
+import pydnstest.scenario
+
+try:
+ VARIANT = os.environ["VARIANT"]
+except KeyError:
+ VARIANT = ""
+
+def store_answer(qname, qtype, template):
+ answ = dns.resolver.query(qname, qtype, raise_on_no_answer=False)
+ entr = copy.copy(template)
+ entr.message = answ.response
+ return entr
+
+
+def resolver_init():
+ """
+ Configure dns.resolver to ask ::1@5353 with EDNS0 DO set.
+ """
+ dns.resolver.reset_default_resolver()
+ dns.resolver.default_resolver.use_edns(0, dns.flags.DO, 4096)
+ dns.resolver.default_resolver.nameservers = ['::1']
+ dns.resolver.default_resolver.nameserver_ports = {'::1': 5353}
+ dns.resolver.default_resolver.flags = 0
+
+
+def get_templates():
+ """
+ Return empty objects for RANGE and ENTRY suitable as object templates.
+ """
+ empty_case, _ = pydnstest.scenario.parse_file(os.path.realpath('empty.rpl'))
+
+ rng = copy.copy(empty_case.ranges[0])
+
+ entry = copy.copy(rng.stored[0])
+ entry.adjust_fields = ['copy_id']
+ entry.match_fields = ['opcode', 'question']
+
+ rng.addresses = {'198.41.0.4', '2001:503:ba3e::2:30'}
+ rng.stored = []
+
+ return rng, entry
+
+
+def generate_range(filename, rng_templ, entry_templ):
+ """
+ Run Knot DNS server with specified zone file and generate RANGE object.
+ """
+ assert filename.startswith('20')
+ assert filename.endswith('.db')
+ try:
+ os.unlink('root.db')
+ except FileNotFoundError:
+ pass
+ os.link(filename, 'root.db')
+
+ # run server
+ knotd = subprocess.Popen(['knotd', '-c', 'knot.root.conf', '-s', '/tmp/knot-dns2rpl.sock'])
+ time.sleep(0.1) # give kresd time to start so we do not wait for first timeout
+
+ # query data
+ rng = copy.copy(rng_templ)
+ rng.stored = []
+ rng.stored.append(store_answer('.', 'SOA', entry_templ))
+ rng.stored.append(store_answer('.', 'DNSKEY', entry_templ))
+ rng.stored.append(store_answer('.', 'NS', entry_templ))
+ rng.stored.append(store_answer('rootns.', 'NS', entry_templ))
+ rng.stored.append(store_answer('rootns.', 'A', entry_templ))
+ rng.stored.append(store_answer('rootns.', 'AAAA', entry_templ))
+ rng.stored.append(store_answer('test.', 'TXT', entry_templ))
+ rng.a = int(filename[:-len('.db')])
+
+ # kill server
+ knotd.kill()
+
+ return rng
+
+
+def generate_step_query(tcurr, id_prefix):
+ out = '; {0}'.format(tcurr.isoformat())
+ out += '''
+STEP {0}000000 QUERY
+ENTRY_BEGIN
+REPLY RD AD
+SECTION QUESTION
+test. IN TXT
+ENTRY_END
+'''.format(id_prefix)
+ return out
+
+
+def generate_step_check(id_prefix):
+ return '''STEP {0}000001 CHECK_ANSWER
+ENTRY_BEGIN
+REPLY QR RD RA AD
+MATCH opcode rcode flags question answer
+SECTION QUESTION
+test. IN TXT
+SECTION ANSWER
+test. IN TXT "it works"
+ENTRY_END
+'''.format(id_prefix)
+
+def generate_step_nocheck(id_prefix):
+ return '''STEP {0}000001 CHECK_ANSWER
+ENTRY_BEGIN
+REPLY QR RD RA AD
+MATCH opcode qname question
+SECTION QUESTION
+test. IN TXT
+SECTION ANSWER
+test. IN TXT "it works"
+ENTRY_END
+'''.format(id_prefix)
+
+def generate_step_finish_msg(id_prefix):
+ return '''STEP {0}000001 CHECK_ANSWER
+ENTRY_BEGIN
+REPLY QR RD RA AA NXDOMAIN
+MATCH opcode rcode flags question answer
+SECTION QUESTION
+test. IN TXT
+SECTION AUTHORITY
+test. 10800 IN SOA test. nobody.invalid. 1 3600 1200 604800 10800
+SECTION ADDITIONAL
+explanation.invalid. 10800 IN TXT "check last answer"
+ENTRY_END
+'''.format(id_prefix)
+
+def generate_step_elapse(tstep, id_prefix):
+ out = '; move time by {0}\n'.format(tstep)
+ out += '''STEP {0}000099 TIME_PASSES ELAPSE {1}\n\n'''.format(
+ id_prefix, int(tstep.total_seconds()))
+ return out
+
+
+def main():
+ resolver_init()
+ rng_templ, entry_templ = get_templates()
+ ranges = []
+ check_last_msg = False
+
+ # transform data in zones files into RANGEs
+ files = os.listdir()
+ files.sort()
+ for fn in files:
+ if not fn.endswith('.db') or not fn.startswith('20'):
+ continue
+ ranges.append(generate_range(fn, rng_templ, entry_templ))
+
+ # connect ranges
+ for i in range(1, len(ranges)):
+ ranges[i - 1].b = ranges[i].a - 1
+ ranges[-1].b = 99999999999999
+
+ # steps
+ steps = []
+ tstart = datetime.datetime(year=2017, month=7, day=1)
+ if VARIANT == "unmanaged_key":
+ tend = datetime.datetime(year=2017, month=7, day=21, hour=23, minute=59, second=59)
+ check_last_msg = True
+ else:
+ tend = datetime.datetime(year=2017, month=12, day=31, hour=23, minute=59, second=59)
+ tstep = datetime.timedelta(days=1)
+ tcurr = tstart
+ while tcurr < tend:
+ id_prefix = tcurr.strftime('%Y%m%d')
+ steps.append(generate_step_query(tcurr, id_prefix))
+ if (check_last_msg is True and tcurr + tstep > tend):
+ steps.append(generate_step_finish_msg(id_prefix))
+ elif VARIANT == "unmanaged_key":
+ steps.append(generate_step_nocheck(id_prefix))
+ else:
+ steps.append(generate_step_check(id_prefix))
+ steps.append(generate_step_elapse(tstep, id_prefix))
+ tcurr += tstep
+
+ # generate output
+ with open('keys/ds') as dsfile:
+ tas = dsfile.read().strip()
+
+ # constant RPL file header
+ print("stub-addr: 2001:503:ba3e::2:30")
+ for ta in tas.split('\n'):
+ print ("trust-anchor: " + ta)
+ print("""val-override-date: 20170701000000
+query-minimization: off
+CONFIG_END
+
+SCENARIO_BEGIN Simulation of successful RFC 5011 KSK roll-over during 2017
+ """.format(ta=ta))
+ for rng in ranges:
+ print(rng)
+
+ for step in steps:
+ print(step)
+
+ # constant RPL file footer
+ print('''
+SCENARIO_END
+ ''')
+
+
+if __name__ == '__main__':
+ main()
diff --git a/modules/ta_update/ta_update.test.integr/rfc5011/empty.rpl b/modules/ta_update/ta_update.test.integr/rfc5011/empty.rpl
new file mode 100644
index 0000000..295d5a5
--- /dev/null
+++ b/modules/ta_update/ta_update.test.integr/rfc5011/empty.rpl
@@ -0,0 +1,20 @@
+stub-addr: 127.0.0.10
+CONFIG_END
+
+SCENARIO_BEGIN empty replies
+
+RANGE_BEGIN 0 100
+ ADDRESS 127.0.0.10
+ENTRY_BEGIN
+MATCH subdomain
+ADJUST copy_id copy_query
+SECTION QUESTION
+. IN A
+ENTRY_END
+RANGE_END
+
+STEP 1 QUERY
+ENTRY_BEGIN
+ENTRY_END
+
+SCENARIO_END
diff --git a/modules/ta_update/ta_update.test.integr/rfc5011/genkeyszones.sh b/modules/ta_update/ta_update.test.integr/rfc5011/genkeyszones.sh
new file mode 100755
index 0000000..4a65469
--- /dev/null
+++ b/modules/ta_update/ta_update.test.integr/rfc5011/genkeyszones.sh
@@ -0,0 +1,174 @@
+#!/usr/bin/bash
+
+# First, generate DNSSEC keys with timers set to simulate 2017 KSK roll-over.
+# Second, fake system time to pretend that we are at the beginning on time slots
+# used during 2017 and sign our fake root zone.
+
+# Depends on libfaketime + dnssec-keygen and dnssec-signzone from BIND 9.11.
+
+# Output: Bunch of DNSSEC keys + several versions of signed root zone.
+
+set -o nounset -o errexit -o xtrace
+
+GEN="dnssec-keygen -K keys/ -a RSASHA256 -b 2048 -L 21d"
+
+function usage {
+ echo -e "Usage: $0 <option>\n\n\
+Option:\n\
+\t--help\t\t\tShow this help.
+\t--rollover\t\tGenerate files for rollover test.\n\
+\t--unmanagedkey-present\tGenerate files for present new unmanaged key.\n\
+\t--unmanagedkey-missing\tGenerate files for missing unmanaged key.\n\
+\t--unmanagedkey-revoke\tGenerate files for revoked unmanaged key."
+}
+
+function sign () {
+ OUTFILE="$(echo "$1" | sed 's/[- :]//g').db"
+ TZ=UTC \
+ LD_PRELOAD="/usr/lib64/faketime/libfaketimeMT.so.1" \
+ FAKETIME="$1" \
+ dnssec-signzone \
+ -K keys/ \
+ -o . \
+ -S \
+ -T 21d \
+ -s now \
+ -e +14d \
+ -X +21d \
+ -O full \
+ -f "${OUTFILE}" \
+ "$2"
+
+ # DS for the very first KSK
+ test ! -f keys/ds && dnssec-dsfromkey -2 -f "${OUTFILE}" . > keys/ds || : initial DS RR already exists
+}
+
+function test_rollover {
+ # old KSK
+ ${GEN} -f KSK -P 20100715000000 -A 20100715000000 -I 20171011000000 -R 20180111000000 -D 20180322000000 .
+ # new KSK
+ ${GEN} -f KSK -P 20170711000000 -A 20171011000000 .
+
+ # ZSK before roll-over: 2017-Q2
+ ${GEN} -P 20170320000000 -A 20170401000000 -I 20170701000000 -D 20170711000000 .
+ # ZSK-q1: 2017-Q3
+ ${GEN} -P 20170621000000 -A 20170701000000 -I 20171001000000 -D 20171011000000 .
+ # ZSK-q2: 2017-Q4
+ ${GEN} -P 20170919000000 -A 20171001000000 -I 20180101000000 -D 20180111000000 .
+ # ZSK-q3: 2018-Q1
+ ${GEN} -P 20171220000000 -A 20180101000000 -I 20180401000000 -D 20180411000000 .
+ # ZSK: 2018-Q2
+ ${GEN} -P 20180322000000 -A 20180401000000 .
+
+
+ # hopefully slots according to
+ # https://www.icann.org/en/system/files/files/ksk-rollover-operational-implementation-plan-22jul16-en.pdf
+ # https://data.iana.org/ksk-ceremony/29/KC29_Script_Annotated.pdf
+ sign "2017-07-01 00:00:00" # 2017 Q3 slot 1
+ sign "2017-07-11 00:00:00" # 2017 Q3 slot 2
+ sign "2017-07-21 00:00:00" # 2017 Q3 slot 3
+ sign "2017-07-31 00:00:00" # 2017 Q3 slot 4
+ sign "2017-08-10 00:00:00" # 2017 Q3 slot 5
+ sign "2017-08-20 00:00:00" # 2017 Q3 slot 6
+ sign "2017-08-30 00:00:00" # 2017 Q3 slot 7
+ sign "2017-09-09 00:00:00" # 2017 Q3 slot 8
+ sign "2017-09-19 00:00:00" # 2017 Q3 slot 9
+
+ sign "2017-10-01 00:00:00" # 2017 Q4 slot 1
+ sign "2017-10-11 00:00:00" # 2017 Q4 slot 2
+ sign "2017-10-21 00:00:00" # 2017 Q4 slot 3
+ sign "2017-10-31 00:00:00" # 2017 Q4 slot 4
+ sign "2017-11-10 00:00:00" # 2017 Q4 slot 5
+ sign "2017-11-20 00:00:00" # 2017 Q4 slot 6
+ sign "2017-11-30 00:00:00" # 2017 Q4 slot 7
+ sign "2017-12-10 00:00:00" # 2017 Q4 slot 8
+ sign "2017-12-20 00:00:00" # 2017 Q4 slot 9
+
+ # 2018-01-01 00:00:00 # 2018 Q1 slot 1
+ # 2018-01-11 00:00:00 # 2018 Q1 slot 2
+ # 2018-01-21 00:00:00 # 2018 Q1 slot 3
+ # 2018-01-31 00:00:00 # 2018 Q1 slot 4
+ # 2018-02-10 00:00:00 # 2018 Q1 slot 5
+ # 2018-02-20 00:00:00 # 2018 Q1 slot 6
+ # 2018-03-02 00:00:00 # 2018 Q1 slot 7
+ # 2018-03-12 00:00:00 # 2018 Q1 slot 8
+ # 2018-03-22 00:00:00 # 2018 Q1 slot 9
+}
+
+function test_unmanagedkey_present {
+ # old KSK
+ ${GEN} -f KSK -P 20100715000000 -A 20100715000000 -I 20171011000000 -R 20180111000000 -D 20180322000000 .
+ # new KSK
+ ${GEN} -f KSK -P 20170711000000 -A 20171011000000 .
+
+ # ZSKs
+ ${GEN} -P 20170621000000 -A 20170701000000 -I 20171001000000 -D 20171011000000 .
+ ${GEN} -P 20170919000000 -A 20171001000000 -I 20180101000000 -D 20180111000000 .
+
+ sign "2017-07-01 00:00:00" unsigned_ok.db
+ sign "2017-07-11 00:00:00" unsigned_ok.db # present key is seen 10 days
+ sign "2017-07-21 00:00:00" unsigned_check.db # last edited message for check result from deckard
+}
+
+function test_unmanagedkey_revoke {
+ # old KSK
+ ${GEN} -f KSK -P 20100715000000 -A 20100715000000 -I 20171011000000 -R 20180111000000 -D 20180322000000 .
+ # revoked KSK
+ ${GEN} -f KSK -P 20100715000000 -A 20100715000000 -I 20171011000000 -R 20170710000000 -D 20180322000000 .
+
+ # ZSKs
+ ${GEN} -P 20170621000000 -A 20170701000000 -I 20171001000000 -D 20171011000000 .
+ ${GEN} -P 20170919000000 -A 20171001000000 -I 20180101000000 -D 20180111000000 .
+
+ sign "2017-07-01 00:00:00" unsigned_ok.db
+ sign "2017-07-11 00:00:00" unsigned_ok.db # revoke key is seen 10 days
+ sign "2017-07-21 00:00:00" unsigned_check.db # last edited message for check result from deckard
+}
+
+function test_unmanagedkey_missing {
+ # old KSK
+ ${GEN} -f KSK -P 20100715000000 -A 20100715000000 -I 20171011000000 -R 20180111000000 -D 20180322000000 .
+ # missing KSK
+ ${GEN} -f KSK -P 20100715000000 -A 20100715000000 -I 20171011000000 -R 20180111000000 -D 20170710000000 .
+
+ # ZSKs
+ ${GEN} -P 20170621000000 -A 20170701000000 -I 20171001000000 -D 20171011000000 .
+ ${GEN} -P 20170919000000 -A 20171001000000 -I 20180101000000 -D 20180111000000 .
+
+ sign "2017-07-01 00:00:00" unsigned_ok.db
+ sign "2017-07-11 00:00:00" unsigned_ok.db # missing key is seen 10 days
+ sign "2017-07-21 00:00:00" unsigned_check.db # last edited message for check result from deckard
+}
+
+if [ $# -ne 1 ]; then
+ usage
+ exit 0
+fi
+
+rm -f 20*.db
+rm -f keys/K*
+rm -f keys/ds
+mkdir -p keys/
+
+case $1 in
+ --rollover)
+ test_rollover
+ ;;
+ --unmanagedkey-present)
+ test_unmanagedkey_present
+ #test_rollover
+ ;;
+ --unmanagedkey-revoke)
+ test_unmanagedkey_revoke
+ ;;
+ --unmanagedkey-missing)
+ test_unmanagedkey_missing
+ ;;
+ --help|-h)
+ usage
+ ;;
+ *)
+ echo -e "Unknown option !\n\n"
+ usage
+ ;;
+esac
diff --git a/modules/ta_update/ta_update.test.integr/rfc5011/knot.root.conf b/modules/ta_update/ta_update.test.integr/rfc5011/knot.root.conf
new file mode 100644
index 0000000..5e20747
--- /dev/null
+++ b/modules/ta_update/ta_update.test.integr/rfc5011/knot.root.conf
@@ -0,0 +1,26 @@
+#
+# Minimal configuration file for Knot DNS server used by dns2rpl.py.
+#
+
+server:
+ # Listen on all configured IPv4 interfaces.
+ listen: 0.0.0.0@5353
+ # Listen on all configured IPv6 interfaces.
+ listen: ::@5353
+ # User for running the server.
+ # user: knot:knot
+# Log info and more serious events to syslog.
+log:
+ - target: stderr
+ any: debug
+
+template:
+# - id: default
+# storage: "/usr/local/var/lib/knot"
+
+zone:
+# Master zone.
+ - domain: .
+ storage: "."
+ file: "root.db"
+
diff --git a/modules/ta_update/ta_update.test.integr/rfc5011/pydnstest b/modules/ta_update/ta_update.test.integr/rfc5011/pydnstest
new file mode 120000
index 0000000..331fa73
--- /dev/null
+++ b/modules/ta_update/ta_update.test.integr/rfc5011/pydnstest
@@ -0,0 +1 @@
+../../../../tests/integration/deckard/pydnstest \ No newline at end of file
diff --git a/modules/ta_update/ta_update.test.integr/rfc5011/unsigned_check.db b/modules/ta_update/ta_update.test.integr/rfc5011/unsigned_check.db
new file mode 100644
index 0000000..cf03621
--- /dev/null
+++ b/modules/ta_update/ta_update.test.integr/rfc5011/unsigned_check.db
@@ -0,0 +1,8 @@
+. 86400 IN SOA rootns. you.test. 2017071100 1800 900 604800 86400
+
+. 518400 IN NS rootns.
+
+rootns. 518400 IN A 198.41.0.4
+rootns. 518400 IN AAAA 2001:503:ba3e::2:30
+
+test. 1 IN TXT "check and change answer"
diff --git a/modules/ta_update/ta_update.test.integr/rfc5011/unsigned_ok.db b/modules/ta_update/ta_update.test.integr/rfc5011/unsigned_ok.db
new file mode 100644
index 0000000..b837acd
--- /dev/null
+++ b/modules/ta_update/ta_update.test.integr/rfc5011/unsigned_ok.db
@@ -0,0 +1,8 @@
+. 86400 IN SOA rootns. you.test. 2017071100 1800 900 604800 86400
+
+. 518400 IN NS rootns.
+
+rootns. 518400 IN A 198.41.0.4
+rootns. 518400 IN AAAA 2001:503:ba3e::2:30
+
+test. 1 IN TXT "it works"