diff --git a/bin/tests/system/kasp/README b/bin/tests/system/kasp/README new file mode 100644 index 0000000000000000000000000000000000000000..d543c1a7791c79be6884fb094e970db160167f6d --- /dev/null +++ b/bin/tests/system/kasp/README @@ -0,0 +1,11 @@ +Copyright (C) Internet Systems Consortium, Inc. ("ISC") + +See COPYRIGHT in the source root or http://isc.org/copyright.html for terms. + +The test setup for the KASP tests. + +ns1 is reserved for the root server. + +ns2 is running primary service for ns3. + +ns3 is an authoritative server for the various test domains. diff --git a/bin/tests/system/kasp/clean.sh b/bin/tests/system/kasp/clean.sh index 6c3f01d9ecc8af09043201d9ccde907f8b277288..c9ef776eb68ee7be1030d586f64c25dcc61887b5 100644 --- a/bin/tests/system/kasp/clean.sh +++ b/bin/tests/system/kasp/clean.sh @@ -14,3 +14,12 @@ set -e rm -f ./keygen.* rm -f ./K*.private ./K*.key ./K*.state ./K*.cmp rm -rf ./keys/ +rm -f dig.out* rrsig.out.* keyevent.out.* +rm -f ns*/named.conf ns*/named.memstats ns*/named.run* +rm -f ns*/*.jnl ns*/*.jbk +rm -f ns*/K*.private ns*/K*.key ns*/K*.state +rm -f ns*/dsset-* ns*/*.db ns*/*.db.signed +rm -f ns*/keygen.out.* ns*/settime.out.* ns*/signer.out.* +rm -f ns*/managed-keys.bind +# NS3 specific +rm -f ns3/zones ns3/*.db.infile diff --git a/bin/tests/system/kasp/ns2/named.conf.in b/bin/tests/system/kasp/ns2/named.conf.in new file mode 100644 index 0000000000000000000000000000000000000000..640def73b3bddd9eb5375a98a0e8e45ecf6a3fb4 --- /dev/null +++ b/bin/tests/system/kasp/ns2/named.conf.in @@ -0,0 +1,42 @@ +/* + * Copyright (C) Internet Systems Consortium, Inc. ("ISC") + * + * 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 http://mozilla.org/MPL/2.0/. + * + * See the COPYRIGHT file distributed with this work for additional + * information regarding copyright ownership. + */ + +// NS2 + +options { + query-source address 10.53.0.2; + notify-source 10.53.0.2; + transfer-source 10.53.0.2; + port @PORT@; + pid-file "named.pid"; + listen-on { 10.53.0.2; }; + listen-on-v6 { none; }; + allow-transfer { any; }; + recursion no; +}; + +key rndc_key { + secret "1234abcd8765"; + algorithm hmac-sha256; +}; + +controls { + inet 10.53.0.2 port @CONTROLPORT@ allow { any; } keys { rndc_key; }; +}; + +/* Primary service for ns3 */ + +zone "secondary.kasp" { + type master; + file "secondary.kasp.db"; + allow-transfer { 10.53.0.3; }; + notify yes; +}; diff --git a/bin/tests/system/kasp/ns2/secondary.kasp.db.in b/bin/tests/system/kasp/ns2/secondary.kasp.db.in new file mode 100644 index 0000000000000000000000000000000000000000..12c678e8b3fc4ac1938841d419d0911b246f5017 --- /dev/null +++ b/bin/tests/system/kasp/ns2/secondary.kasp.db.in @@ -0,0 +1,27 @@ +; Copyright (C) Internet Systems Consortium, Inc. ("ISC") +; +; 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 http://mozilla.org/MPL/2.0/. +; +; See the COPYRIGHT file distributed with this work for additional +; information regarding copyright ownership. + +$TTL 300 +@ IN SOA secondary.kasp. hostmaster.kasp. ( + 1 ; serial + 20 ; refresh (20 seconds) + 20 ; retry (20 seconds) + 1814400 ; expire (3 weeks) + 3600 ; minimum (1 hour) + ) + + NS ns2 + NS ns3 +ns2 A 10.53.0.2 +ns3 A 10.53.0.3 + +a A 10.0.0.1 +b A 10.0.0.2 +c A 10.0.0.3 + diff --git a/bin/tests/system/kasp/ns2/secondary.kasp.db.in2 b/bin/tests/system/kasp/ns2/secondary.kasp.db.in2 new file mode 100644 index 0000000000000000000000000000000000000000..6fb00a9c30ec318c537384c6231dea0adbd2ee24 --- /dev/null +++ b/bin/tests/system/kasp/ns2/secondary.kasp.db.in2 @@ -0,0 +1,28 @@ +; Copyright (C) Internet Systems Consortium, Inc. ("ISC") +; +; 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 http://mozilla.org/MPL/2.0/. +; +; See the COPYRIGHT file distributed with this work for additional +; information regarding copyright ownership. + +$TTL 300 +@ IN SOA secondary.kasp. hostmaster.kasp. ( + 2 ; serial + 20 ; refresh (20 seconds) + 20 ; retry (20 seconds) + 1814400 ; expire (3 weeks) + 3600 ; minimum (1 hour) + ) + + NS ns2 + NS ns3 +ns2 A 10.53.0.2 +ns3 A 10.53.0.3 + +a A 10.0.0.11 +b A 10.0.0.2 +c A 10.0.0.3 +d A 10.0.0.4 + diff --git a/bin/tests/system/kasp/ns2/setup.sh b/bin/tests/system/kasp/ns2/setup.sh new file mode 100644 index 0000000000000000000000000000000000000000..d495e05f52dd684d8b5f997894ff14a5e777d4af --- /dev/null +++ b/bin/tests/system/kasp/ns2/setup.sh @@ -0,0 +1,21 @@ +#!/bin/sh -e +# +# Copyright (C) Internet Systems Consortium, Inc. ("ISC") +# +# 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 http://mozilla.org/MPL/2.0/. +# +# See the COPYRIGHT file distributed with this work for additional +# information regarding copyright ownership. + +# shellcheck source=conf.sh +. "$SYSTEMTESTTOP/conf.sh" + +echo_i "ns2/setup.sh" + +echo_i "setting up zone: $zone" +zone="secondary.kasp" +zonefile="${zone}.db" +infile="${zonefile}.in" +cp $infile $zonefile diff --git a/bin/tests/system/kasp/ns3/named.conf.in b/bin/tests/system/kasp/ns3/named.conf.in new file mode 100644 index 0000000000000000000000000000000000000000..880f3fd50c7388a9263df7ca928f792b5cf18d2a --- /dev/null +++ b/bin/tests/system/kasp/ns3/named.conf.in @@ -0,0 +1,122 @@ +/* + * Copyright (C) Internet Systems Consortium, Inc. ("ISC") + * + * 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 http://mozilla.org/MPL/2.0/. + * + * See the COPYRIGHT file distributed with this work for additional + * information regarding copyright ownership. + */ + +// NS3 + +options { + query-source address 10.53.0.3; + notify-source 10.53.0.3; + transfer-source 10.53.0.3; + port @PORT@; + pid-file "named.pid"; + listen-on { 10.53.0.3; }; + listen-on-v6 { none; }; + allow-transfer { any; }; + recursion no; +}; + +key rndc_key { + secret "1234abcd8765"; + algorithm hmac-sha256; +}; + +controls { + inet 10.53.0.3 port @CONTROLPORT@ allow { any; } keys { rndc_key; }; +}; + +include "policies/kasp.conf"; + +/* Zones that are getting initially signed */ + +/* The default case: No keys created, using default policy. */ +zone "default.kasp" { + type master; + file "default.kasp.db"; + dnssec-policy "default"; +}; + +/* A master zone with dnssec-policy, no keys created. */ +zone "rsasha1.kasp" { + type master; + file "rsasha1.kasp.db"; + dnssec-policy "rsasha1"; +}; + +/* A master zone with dnssec-policy but keys already created. */ +zone "dnssec-keygen.kasp" { + type master; + file "dnssec-keygen.kasp.db"; + dnssec-policy "rsasha1"; +}; + +/* A secondary zone with dnssec-policy. */ +zone "secondary.kasp" { + type secondary; + masters { 10.53.0.2; }; + file "secondary.kasp.db"; + dnssec-policy "rsasha1"; +}; + +/* + * A configured dnssec-policy but some keys already created. + */ +zone "some-keys.kasp" { + type master; + file "some-keys.kasp.db"; + dnssec-policy "rsasha1"; +}; + +/* + * A configured dnssec-policy but some keys already in use. + */ +zone "legacy-keys.kasp" { + type master; + file "legacy-keys.kasp.db"; + dnssec-policy "rsasha1"; +}; + +/* + * A configured dnssec-policy with (too) many keys pregenerated. + */ +zone "pregenerated.kasp" { + type master; + file "pregenerated.kasp.db"; + dnssec-policy "rsasha1"; +}; + +/* + * Different algorithms. + */ +zone "rsasha1-nsec3.kasp" { + type master; + file "rsasha1-nsec3.kasp.db"; + dnssec-policy "rsasha1-nsec3"; +}; +zone "rsasha256.kasp" { + type master; + file "rsasha256.kasp.db"; + dnssec-policy "rsasha256"; +}; +zone "rsasha512.kasp" { + type master; + file "rsasha512.kasp.db"; + dnssec-policy "rsasha512"; +}; +zone "ecdsa256.kasp" { + type master; + file "ecdsa256.kasp.db"; + dnssec-policy "ecdsa256"; +}; +zone "ecdsa384.kasp" { + type master; + file "ecdsa384.kasp.db"; + dnssec-policy "ecdsa384"; +}; diff --git a/bin/tests/system/kasp/ns3/policies/kasp.conf b/bin/tests/system/kasp/ns3/policies/kasp.conf new file mode 100644 index 0000000000000000000000000000000000000000..547c5c04296504d2a602d5be00fd70b881cf4d23 --- /dev/null +++ b/bin/tests/system/kasp/ns3/policies/kasp.conf @@ -0,0 +1,70 @@ +/* + * Copyright (C) Internet Systems Consortium, Inc. ("ISC") + * + * 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 http://mozilla.org/MPL/2.0/. + * + * See the COPYRIGHT file distributed with this work for additional + * information regarding copyright ownership. + */ + +dnssec-policy "rsasha1" { + dnskey-ttl 1234; + + keys { + ksk key-directory P10Y 5; + zsk key-directory P5Y 5; + zsk key-directory P1Y 5 2000; + }; +}; + +dnssec-policy "rsasha1-nsec3" { + dnskey-ttl 1234; + + keys { + ksk key-directory P10Y 7; + zsk key-directory P5Y 7; + zsk key-directory P1Y 7 2000; + }; +}; + +dnssec-policy "rsasha256" { + dnskey-ttl 1234; + + keys { + ksk key-directory P10Y 8; + zsk key-directory P5Y 8; + zsk key-directory P1Y 8 2000; + }; +}; + +dnssec-policy "rsasha512" { + dnskey-ttl 1234; + + keys { + ksk key-directory P10Y 10; + zsk key-directory P5Y 10; + zsk key-directory P1Y 10 2000; + }; +}; + +dnssec-policy "ecdsa256" { + dnskey-ttl 1234; + + keys { + ksk key-directory P10Y 13; + zsk key-directory P5Y 13; + zsk key-directory P1Y 13 256; + }; +}; + +dnssec-policy "ecdsa384" { + dnskey-ttl 1234; + + keys { + ksk key-directory P10Y 14; + zsk key-directory P5Y 14; + zsk key-directory P1Y 14 384; + }; +}; diff --git a/bin/tests/system/kasp/ns3/setup.sh b/bin/tests/system/kasp/ns3/setup.sh new file mode 100644 index 0000000000000000000000000000000000000000..b2fcaa7edbc475b2d6e4253cf0de647ed40c39c4 --- /dev/null +++ b/bin/tests/system/kasp/ns3/setup.sh @@ -0,0 +1,50 @@ +#!/bin/sh -e +# +# Copyright (C) Internet Systems Consortium, Inc. ("ISC") +# +# 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 http://mozilla.org/MPL/2.0/. +# +# See the COPYRIGHT file distributed with this work for additional +# information regarding copyright ownership. + +# shellcheck source=conf.sh +. "$SYSTEMTESTTOP/conf.sh" + +echo_i "ns3/setup.sh" + +setup() { + zone="$1" + echo_i "setting up zone: $zone" + zonefile="${zone}.db" + infile="${zone}.db.infile" + echo $zone >> zones +} + +# +# Set up zones that will be initially signed. +# +for zn in default rsasha1 dnssec-keygen some-keys legacy-keys pregenerated \ + rsasha1-nsec3 rsasha256 rsasha512 ecdsa256 ecdsa384 +do + setup "${zn}.kasp" + cp template.db.in $zonefile +done + +# Some of these zones already have keys. +zone="dnssec-keygen.kasp" +$KEYGEN -k rsasha1 -l policies/kasp.conf $zone > keygen.out.$zone.1 2>&1 + +zone="some-keys.kasp" +$KEYGEN -P none -A none -a RSASHA1 -b 2000 -L 1234 $zone > keygen.out.$zone.1 2>&1 +$KEYGEN -P none -A none -a RSASHA1 -f KSK -L 1234 $zone > keygen.out.$zone.2 2>&1 + +zone="legacy.kasp" +$KEYGEN -a RSASHA1 -b 2000 -L 1234 $zone > keygen.out.$zone.1 2>&1 +$KEYGEN -a RSASHA1 -f KSK -L 1234 $zone > keygen.out.$zone.2 2>&1 + +zone="pregenerated.kasp" +$KEYGEN -k rsasha1 -l policies/kasp.conf $zone > keygen.out.$zone.1 2>&1 +$KEYGEN -k rsasha1 -l policies/kasp.conf $zone > keygen.out.$zone.2 2>&1 + diff --git a/bin/tests/system/kasp/ns3/template.db.in b/bin/tests/system/kasp/ns3/template.db.in new file mode 100644 index 0000000000000000000000000000000000000000..051a312891a5ea526225a67639e207e4ee1a9af5 --- /dev/null +++ b/bin/tests/system/kasp/ns3/template.db.in @@ -0,0 +1,25 @@ +; Copyright (C) Internet Systems Consortium, Inc. ("ISC") +; +; 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 http://mozilla.org/MPL/2.0/. +; +; See the COPYRIGHT file distributed with this work for additional +; information regarding copyright ownership. + +$TTL 300 +@ IN SOA mname1. . ( + 1 ; serial + 20 ; refresh (20 seconds) + 20 ; retry (20 seconds) + 1814400 ; expire (3 weeks) + 3600 ; minimum (1 hour) + ) + + NS ns3 +ns3 A 10.53.0.3 + +a A 10.0.0.1 +b A 10.0.0.2 +c A 10.0.0.3 + diff --git a/bin/tests/system/kasp/ns3/template2.db.in b/bin/tests/system/kasp/ns3/template2.db.in new file mode 100644 index 0000000000000000000000000000000000000000..3fe69f34c38b8123e50d81b35d5159a2762877b4 --- /dev/null +++ b/bin/tests/system/kasp/ns3/template2.db.in @@ -0,0 +1,25 @@ +; Copyright (C) Internet Systems Consortium, Inc. ("ISC") +; +; 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 http://mozilla.org/MPL/2.0/. +; +; See the COPYRIGHT file distributed with this work for additional +; information regarding copyright ownership. + +$TTL 300 +@ IN SOA mname1. . ( + 2 ; serial + 20 ; refresh (20 seconds) + 20 ; retry (20 seconds) + 1814400 ; expire (3 weeks) + 3600 ; minimum (1 hour) + ) + + NS ns3 +ns3 A 10.53.0.3 + +a A 10.0.0.11 +b A 10.0.0.2 +c A 10.0.0.3 +d A 10.0.0.4 diff --git a/bin/tests/system/kasp/setup.sh b/bin/tests/system/kasp/setup.sh index 05b71ac269142a42d0dd1c2dce3a76021db5478c..6bdf0035a8bd69d563a0a5539d9029dcee0ecab9 100644 --- a/bin/tests/system/kasp/setup.sh +++ b/bin/tests/system/kasp/setup.sh @@ -17,3 +17,17 @@ set -e $SHELL clean.sh mkdir keys + +copy_setports ns2/named.conf.in ns2/named.conf +copy_setports ns3/named.conf.in ns3/named.conf + +# ns2: Setup zones +( + cd ns2 + $SHELL setup.sh +) +# ns3: Setup zones +( + cd ns3 + $SHELL setup.sh +) diff --git a/bin/tests/system/kasp/tests.sh b/bin/tests/system/kasp/tests.sh index b6e0e2ca47059cc2e96b8cb9b43cc2c153944f9c..f4b06b91ef78a06a0418d7879035b7325545ed74 100644 --- a/bin/tests/system/kasp/tests.sh +++ b/bin/tests/system/kasp/tests.sh @@ -436,6 +436,62 @@ check_key() { grep "Generated: " $STATE_FILE > /dev/null || log_error "mismatch generated in $STATE_FILE" } +# Check the key with key id $1 and see if it is unused. +# This requires environment variables to be set with 'zone_properties', +# and 'key_properties'. +# +# This will set the following environment variables for testing: +# BASE_FILE="${_dir}/K${_zone}.+${_alg_numpad}+${_key_idpad}" +# KEY_FILE="${BASE_FILE}.key" +# PRIVATE_FILE="${BASE_FILE}.private" +# STATE_FILE="${BASE_FILE}.state" +# KEY_ID=$(echo $1 | sed 's/^0*//') +key_unused() { + _dir=$DIR + _zone=$ZONE + _key_idpad=$1 + _key_id=$(echo $_key_idpad | sed 's/^0*//') + _alg_num="${KEY1[$ALG_NUM]}" + _alg_numpad=$(printf "%03d" $_alg_num) + + BASE_FILE="${_dir}/K${_zone}.+${_alg_numpad}+${_key_idpad}" + KEY_FILE="${BASE_FILE}.key" + PRIVATE_FILE="${BASE_FILE}.private" + STATE_FILE="${BASE_FILE}.state" + KEY_ID="${_key_id}" + + test $_log -eq 1 && echo_i "key unused $KEY_ID?" + + # Check timing metadata. + grep "; Publish:" $KEY_FILE > /dev/null && log_error "unexpected publish comment in $KEY_FILE" + grep "Publish:" $PRIVATE_FILE > /dev/null && log_error "unexpected publish in $PRIVATE_FILE" + grep "Published: " $STATE_FILE > /dev/null && log_error "unexpected publish in $STATE_FILE" + grep "; Activate:" $KEY_FILE > /dev/null && log_error "unexpected active comment in $KEY_FILE" + grep "Activate:" $PRIVATE_FILE > /dev/null && log_error "unexpected active in $PRIVATE_FILE" + grep "Active: " $STATE_FILE > /dev/null && log_error "unexpected active in $STATE_FILE" + grep "; Inactive:" $KEY_FILE > /dev/null && log_error "unexpected retired comment in $KEY_FILE" + grep "Inactive:" $PRIVATE_FILE > /dev/null && log_error "unexpected retired in $PRIVATE_FILE" + grep "Retired: " $STATE_FILE > /dev/null && log_error "unexpected retired in $STATE_FILE" + grep "; Revoke:" $KEY_FILE > /dev/null && log_error "unexpected revoked comment in $KEY_FILE" + grep "Revoke:" $PRIVATE_FILE > /dev/null && log_error "unexpected revoked in $PRIVATE_FILE" + grep "Revoked: " $STATE_FILE > /dev/null && log_error "unexpected revoked in $STATE_FILE" + grep "; Delete:" $KEY_FILE > /dev/null && log_error "unexpected removed comment in $KEY_FILE" + grep "Delete:" $PRIVATE_FILE > /dev/null && log_error "unexpected removed in $PRIVATE_FILE" + grep "Removed: " $STATE_FILE > /dev/null && log_error "unexpected removed in $STATE_FILE" +} + +# Test: dnssec-verify zone $1. +dnssec_verify() +{ + n=$((n+1)) + echo_i "dnssec-verify zone ${ZONE} ($n)" + ret=0 + dig_with_opts $ZONE @10.53.0.3 AXFR > dig.out.axfr.test$n || log_error "dig ${ZONE} AXFR failed" + $VERIFY -z -o $ZONE dig.out.axfr.test$n > /dev/null || log_error "dnssec verify zone $ZONE failed" + test "$ret" -eq 0 || echo_i "failed" + status=$((status+ret)) +} + ############################################################################### # Tests # ############################################################################### @@ -579,7 +635,450 @@ status=$((status+ret)) # # named # +# +# The NSEC record at the apex of the zone and its RRSIG records are +# added as part of the last step in signing a zone. We wait for the +# NSEC records to appear before proceeding with a counter to prevent +# infinite loops if there is a error. +# +n=$((n+1)) +echo_i "waiting for kasp signing changes to take effect ($n)" +i=0 +while [ $i -lt 30 ] +do + ret=0 + for z in `cat ns3/zones` + do + dig_with_opts $z @10.53.0.3 nsec > dig.out.ns3.test$n.$z || ret=1 + grep "NS SOA" dig.out.ns3.test$n.$z > /dev/null || ret=1 + grep "$z\..*IN.*RRSIG" dig.out.ns3.test$n.$z > /dev/null || ret=1 + done + i=`expr $i + 1` + if [ $ret = 0 ]; then break; fi + echo_i "waiting ... ($i)" + sleep 1 +done +test "$ret" -eq 0 || echo_i "failed" +status=$((status+ret)) + +# +# Zone: default.kasp. +# + +# Check the zone with default kasp policy has loaded and is signed. +zone_properties "ns3" "default.kasp" "_default" "3600" +key_properties "KEY1" "csk" "0" "13" "ECDSAP256SHA256" "256" "yes" +# The first key is immediately published and activated. +key_timings "KEY1" "published" "active" "none" "none" "none" "none" +# DNSKEY, RRSIG (ksk), RRSIG (zsk) are published. DS needs to wait. +key_states "KEY1" "omnipresent" "rumoured" "rumoured" "rumoured" "hidden" + +n=$((n+1)) +echo_i "check key is created for zone ${ZONE} ($n)" +ret=0 +id=$(get_keyids $DIR $ZONE "${KEY1[$ALG_NUM]}") +check_key "KEY1" $id +test "$ret" -eq 0 || echo_i "failed" +status=$((status+ret)) + +# Verify signed zone. +dnssec_verify $ZONE + +# Test DNSKEY query. +qtype="DNSKEY" +n=$((n+1)) +echo_i "check ${qtype} rrset is signed correctly for zone ${ZONE} ($n)" +ret=0 +dig_with_opts $ZONE @10.53.0.3 $qtype > dig.out.$DIR.test$n || log_error "dig ${ZONE} ${qtype} failed" +grep "status: NOERROR" dig.out.$DIR.test$n > /dev/null || log_error "mismatch status in DNS response" +grep "${ZONE}\..*${DNSKEY_TTL}.*IN.*${qtype}.*257.*.3.*${KEY1[$ALG_NUM]}" dig.out.$DIR.test$n > /dev/null || log_error "missing ${qtype} record in response" +lines=$(get_keys_which_signed $qtype dig.out.$DIR.test$n | wc -l) +test "$lines" -eq 1 || log_error "bad number ($lines) of RRSIG records in DNS response" +get_keys_which_signed $qtype dig.out.$DIR.test$n | grep "^${KEY_ID}$" > /dev/null || log_error "${qtype} RRset not signed with ${KEY_ID}" +test "$ret" -eq 0 || echo_i "failed" +status=$((status+ret)) + +# Test SOA query. +qtype="SOA" +n=$((n+1)) +echo_i "check ${qtype} rrset is signed correctly for zone ${ZONE} ($n)" +ret=0 +dig_with_opts $ZONE @10.53.0.3 $qtype > dig.out.$DIR.test$n || log_error "dig ${ZONE} ${qtype} failed" +grep "status: NOERROR" dig.out.$DIR.test$n > /dev/null || log_error "mismatch status in DNS response" +grep "${ZONE}\..*${DEFAULT_TTL}.*IN.*${qtype}.*mname1\..*\." dig.out.$DIR.test$n > /dev/null || log_error "missing ${qtype} record in response" +lines=$(get_keys_which_signed $qtype dig.out.$DIR.test$n | wc -l) +test "$lines" -eq 1 || log_error "bad number ($lines) of RRSIG records in DNS response" +get_keys_which_signed $qtype dig.out.$DIR.test$n | grep "^${KEY_ID}$" > /dev/null || log_error "${qtype} RRset not signed with ${KEY_ID}" +test "$ret" -eq 0 || echo_i "failed" +status=$((status+ret)) + +# Update zone. +n=$((n+1)) +echo_i "check that we can update unsigned zone file and new record gets signed for zone ${ZONE} ($n)" +ret=0 +cp "${DIR}/template2.db.in" "${DIR}/${ZONE}.db" +rndccmd 10.53.0.3 reload $ZONE > /dev/null || log_error "rndc reload zone ${ZONE} failed" +_log=0 +i=0 +while [ $i -lt 5 ] +do + ret=0 + + dig_with_opts "a.${ZONE}" @10.53.0.3 A > dig.out.$DIR.test$n.a || log_error "dig a.${ZONE} A failed" + grep "status: NOERROR" dig.out.$DIR.test$n.a > /dev/null || log_error "mismatch status in DNS response" + grep "a.${ZONE}\..*${DEFAULT_TTL}.*IN.*A.*10\.0\.0\.11" dig.out.$DIR.test$n.a > /dev/null || log_error "missing a.${ZONE} A record in response" + lines=$(get_keys_which_signed A dig.out.$DIR.test$n.a | wc -l) + test "$lines" -eq 1 || log_error "bad number ($lines) of RRSIG records in DNS response" + get_keys_which_signed A dig.out.$DIR.test$n.a | grep "^${KEY_ID}$" > /dev/null || log_error "A RRset not signed with ${KEY_ID}" + + dig_with_opts "d.${ZONE}" @10.53.0.3 A > dig.out.$DIR.test$n.d || log_error "dig d.${ZONE} A failed" + grep "status: NOERROR" dig.out.$DIR.test$n.d > /dev/null || log_error "mismatch status in DNS response" + grep "d.${ZONE}\..*${DEFAULT_TTL}.*IN.*A.*10\.0\.0\.4" dig.out.$DIR.test$n.d > /dev/null || log_error "missing d.${ZONE} A record in response" + lines=$(get_keys_which_signed A dig.out.$DIR.test$n.d | wc -l) + test "$lines" -eq 1 || log_error "bad number ($lines) of RRSIG records in DNS response" + get_keys_which_signed A dig.out.$DIR.test$n.d | grep "^${KEY_ID}$" > /dev/null || log_error "A RRset not signed with ${KEY_ID}" + + i=`expr $i + 1` + if [ $ret = 0 ]; then break; fi + echo_i "waiting ... ($i)" + sleep 1 +done +_log=1 +test "$ret" -eq 0 || echo_i "failed" +status=$((status+ret)) + +# +# Zone: rsasha1.kasp. +# +zone_properties "ns3" "rsasha1.kasp" "rsasha1" "1234" "3" +key_properties "KEY1" "ksk" "315360000" "5" "RSASHA1" "2048" "yes" +key_properties "KEY2" "zsk" "157680000" "5" "RSASHA1" "1024" "yes" +key_properties "KEY3" "zsk" "31536000" "5" "RSASHA1" "2000" "yes" +# The first keys are immediately published and activated. +# Because lifetime > 0, retired timing is also set. +key_timings "KEY1" "published" "active" "retired" "none" "none" +key_timings "KEY2" "published" "active" "retired" "none" "none" +key_timings "KEY3" "published" "active" "retired" "none" "none" +# KSK: DNSKEY, RRSIG (ksk) published. DS needs to wait. +# ZSK: DNSKEY, RRSIG (zsk) published. +key_states "KEY1" "omnipresent" "rumoured" "none" "rumoured" "hidden" +key_states "KEY2" "omnipresent" "rumoured" "rumoured" "none" "none" +key_states "KEY3" "omnipresent" "rumoured" "rumoured" "none" "none" + +# Check keys for a configured zone. This verifies: +# 1. The right number of keys exist in the key pool ($1). +# 2. The right number of keys is active (always expect three keys). +# The algorithm expected is set with $2 (string) and $3 (number), and the +# expected sizes for the keys are set with $4 (ksk), $5 and $6 (zsk). +# A size set to 0 means the corresponding key (KEY1, KEY2 or KEY3) is not +# expected. +# +# It is expected that KEY1, KEY2 and KEY3 arrays are set correctly. Found key +# identifiers are stored in the right key array. +check_keys() +{ + n=$((n+1)) + echo_i "check keys are created for zone ${ZONE} ($n)" + ret=0 + + _key_algnum="${KEY1[$ALG_NUM]}" + + n=$((n+1)) + echo_i "check number of keys with algorithm ${_key_algnum} for zone ${ZONE} in dir ${DIR} ($n)" + ret=0 + _numkeys=$(get_keyids $DIR $ZONE $_key_algnum | wc -l) + test "$_numkeys" -eq $NUM_KEYS || log_error "bad number ($_numkeys) of key files for zone $ZONE (expected $NUM_KEYS)" + test "$ret" -eq 0 || echo_i "failed" + status=$((status+ret)) + + # Temporarily don't log errors because we are searching multiple files. + _log=0 + + # Clear key ids. + KEY1[$ID]="0" + KEY2[$ID]="0" + KEY3[$ID]="0" + + # Check key files. + _ids=$(get_keyids $DIR $ZONE "$_key_algnum") + for _id in $_ids; do + # There are three key files with the same algorithm. + # Check them until a match is found. + echo_i "check key $_id" + + if [ "0" == "${KEY1[$ID]}" ] && [ "${KEY1[$EXPECT]}" == "yes" ]; then + ret=0 + check_key "KEY1" $_id + test "$ret" -eq 0 && KEY1[$ID]=$KEY_ID && continue + fi + if [ "0" == "${KEY2[$ID]}" ] && [ "${KEY2[$EXPECT]}" == "yes" ]; then + ret=0 + check_key "KEY2" $_id + test "$ret" -eq 0 && KEY2[$ID]=$KEY_ID && continue + fi + if [ "0" == "${KEY3[$ID]}" ] && [ "${KEY3[$EXPECT]}" == "yes" ]; then + ret=0 + check_key "KEY3" $_id + test "$ret" -eq 0 && KEY3[$ID]=$KEY_ID && continue + fi + + # This may be an unused key. + ret=0 && key_unused $_id + test "$ret" -eq 0 && continue + + # If ret is still non-zero, non of the files matched. + test "$ret" -eq 0 || echo_i "failed" + status=$((status+ret)) + done + + # Turn error logs on again. + _log=1 + + ret=0 + if [ "${KEY1[$EXPECT]}" == "yes" ]; then + test "0" == "${KEY1[$ID]}" && log_error "No KEY1 found for zone ${ZONE}" + fi + if [ "${KEY2[$EXPECT]}" == "yes" ]; then + test "0" == "${KEY2[$ID]}" && log_error "No KEY2 found for zone ${ZONE}" + fi + if [ "${KEY3[$EXPECT]}" == "yes" ]; then + test "0" == "${KEY3[$ID]}" && log_error "No KEY3 found for zone ${ZONE}" + fi + test "$ret" -eq 0 || echo_i "failed" + status=$((status+ret)) +} + +# Check if RRset of type $1 in file $2 is signed with the right keys. +# The right keys are the ones that expect a signature and matches the role $3. +check_signatures() { + _qtype=$1 + _file=$2 + _role=$3 + + if [ "${KEY1[$EXPECT_RRSIG]}" == "yes" ] && [ "${KEY1[$_role]}" == "yes" ]; then + get_keys_which_signed $_qtype $_file | grep "^${KEY1[$ID]}$" > /dev/null || log_error "${_qtype} RRset not signed with key ${KEY1[$ID]}" + elif [ "${KEY1[$EXPECT]}" == "yes" ]; then + get_keys_which_signed $_qtype $_file | grep "^${KEY1[$ID]}$" > /dev/null && log_error "${_qtype} RRset signed unexpectedly with ${KEY1[$ID]}" + fi + + if [ "${KEY2[$EXPECT_RRSIG]}" == "yes" ] && [ "${KEY2[$_role]}" == "yes" ]; then + get_keys_which_signed $_qtype $_file | grep "^${KEY2[$ID]}$" > /dev/null || log_error "${_qtype} RRset not signed with ${KEY2[$ID]}" + elif [ "${KEY2[$EXPECT]}" == "yes" ]; then + get_keys_which_signed $_qtype $_file | grep "^${KEY2[$ID]}$" > /dev/null && log_error "${_qtype} RRset signed unexpectedly with ${KEY2[$ID]}" + fi + + if [ "${KEY3[$EXPECT_RRSIG]}" == "yes" ] && [ "${KEY3[$_role]}" == "yes" ]; then + get_keys_which_signed $_qtype $_file | grep "^${KEY3[$ID]}$" > /dev/null || log_error "${_qtype} RRset not signed with ${KEY3[$ID]}" + elif [ "${KEY3[$EXPECT]}" == "yes" ]; then + get_keys_which_signed $_qtype $_file | grep "^${KEY3[$ID]}$" > /dev/null && log_error "${_qtype} RRset signed unexpectedly with ${KEY3[$ID]}" + fi +} + +# Test the apex of a configured zone. This checks that the SOA and DNSKEY +# RRsets are signed correctly and with the appropriate keys. +check_apex() { + + # Test DNSKEY query. + _qtype="DNSKEY" + n=$((n+1)) + echo_i "check ${_qtype} rrset is signed correctly for zone ${ZONE} ($n)" + ret=0 + dig_with_opts $ZONE @10.53.0.3 $_qtype > dig.out.$DIR.test$n || log_error "dig ${ZONE} ${_qtype} failed" + grep "status: NOERROR" dig.out.$DIR.test$n > /dev/null || log_error "mismatch status in DNS response" + grep "${ZONE}\..*${DNSKEY_TTL}.*IN.*${_qtype}.*257.*.3.*${_key_algnum}" dig.out.$DIR.test$n > /dev/null || log_error "missing ${_qtype} record in response" + lines=$(get_keys_which_signed $_qtype dig.out.$DIR.test$n | wc -l) + check_signatures $_qtype dig.out.$DIR.test$n $KSK + test "$ret" -eq 0 || echo_i "failed" + status=$((status+ret)) + + # Test SOA query. + _qtype="SOA" + n=$((n+1)) + echo_i "check ${_qtype} rrset is signed correctly for zone ${ZONE} ($n)" + ret=0 + dig_with_opts $ZONE @10.53.0.3 $_qtype > dig.out.$DIR.test$n || log_error "dig ${ZONE} ${_qtype} failed" + grep "status: NOERROR" dig.out.$DIR.test$n > /dev/null || log_error "mismatch status in DNS response" + grep "${ZONE}\..*${DEFAULT_TTL}.*IN.*${_qtype}.*" dig.out.$DIR.test$n > /dev/null || log_error "missing ${_qtype} record in response" + lines=$(get_keys_which_signed $_qtype dig.out.$DIR.test$n | wc -l) + check_signatures $_qtype dig.out.$DIR.test$n $ZSK + test "$ret" -eq 0 || echo_i "failed" + status=$((status+ret)) +} + +# Test an RRset below the apex and verify it is signed correctly. +check_subdomain() { + _qtype="A" + n=$((n+1)) + echo_i "check ${_qtype} a.${ZONE} rrset is signed correctly for zone ${ZONE} ($n)" + ret=0 + dig_with_opts a.$ZONE @10.53.0.3 $_qtype > dig.out.$DIR.test$n || log_error "dig a.${ZONE} ${_qtype} failed" + grep "status: NOERROR" dig.out.$DIR.test$n > /dev/null || log_error "mismatch status in DNS response" + grep "a.${ZONE}\..*${DEFAULT_TTL}.*IN.*${_qtype}.*10\.0\.0\.1" dig.out.$DIR.test$n > /dev/null || log_error "missing a.${ZONE} ${_qtype} record in response" + lines=$(get_keys_which_signed $_qtype dig.out.$DIR.test$n | wc -l) + check_signatures $_qtype dig.out.$DIR.test$n $ZSK + test "$ret" -eq 0 || echo_i "failed" + status=$((status+ret)) +} + +check_keys +check_apex +check_subdomain +dnssec_verify + +# +# Zone: dnssec-keygen.kasp. +# +zone_properties "ns3" "dnssec-keygen.kasp" "rsasha1" "1234" "3" +# key_properties, key_timings and key_states same as above. +check_keys +check_apex +check_subdomain +dnssec_verify + +# +# Zone: some-keys.kasp. +# +zone_properties "ns3" "some-keys.kasp" "rsasha1" "1234" "3" +# key_properties, key_timings and key_states same as above. +check_keys +check_apex +check_subdomain +dnssec_verify + +# +# Zone: legacy-keys.kasp. +# +zone_properties "ns3" "legacy-keys.kasp" "rsasha1" "1234" "3" +# key_properties, key_timings and key_states same as above. +check_keys +check_apex +check_subdomain +dnssec_verify + +# +# Zone: pregenerated.kasp. +# +# There are more pregenerated keys than needed, hence the number of keys is +# six, not three. +zone_properties "ns3" "pregenerated.kasp" "rsasha1" "1234" "6" +# key_properties, key_timings and key_states same as above. +check_keys +check_apex +check_subdomain +dnssec_verify + +# +# Zone: secondary.kasp. +# +zone_properties "ns3" "secondary.kasp" "rsasha1" "1234" "3" +# KSK properties, timings and states same as above. +check_keys +check_apex +check_subdomain +dnssec_verify + +# Update zone. +n=$((n+1)) +echo_i "check that we correctly sign the zone after IXFR for zone ${ZONE} ($n)" +ret=0 +cp ns2/secondary.kasp.db.in2 ns2/secondary.kasp.db +rndccmd 10.53.0.2 reload $ZONE > /dev/null || log_error "rndc reload zone ${ZONE} failed" +_log=0 +i=0 +while [ $i -lt 5 ] +do + ret=0 + + dig_with_opts "a.${ZONE}" @10.53.0.3 A > dig.out.$DIR.test$n.a || log_error "dig a.${ZONE} A failed" + grep "status: NOERROR" dig.out.$DIR.test$n.a > /dev/null || log_error "mismatch status in DNS response" + grep "a.${ZONE}\..*${DEFAULT_TTL}.*IN.*A.*10\.0\.0\.11" dig.out.$DIR.test$n.a > /dev/null || log_error "missing a.${ZONE} A record in response" + check_signatures $_qtype dig.out.$DIR.test$n.a $ZSK + + dig_with_opts "d.${ZONE}" @10.53.0.3 A > dig.out.$DIR.test$n.d || log_error "dig d.${ZONE} A failed" + grep "status: NOERROR" dig.out.$DIR.test$n.d > /dev/null || log_error "mismatch status in DNS response" + grep "d.${ZONE}\..*${DEFAULT_TTL}.*IN.*A.*10\.0\.0\.4" dig.out.$DIR.test$n.d > /dev/null || log_error "missing d.${ZONE} A record in response" + lines=$(get_keys_which_signed A dig.out.$DIR.test$n.d | wc -l) + check_signatures $_qtype dig.out.$DIR.test$n.d $ZSK + + i=`expr $i + 1` + if [ $ret = 0 ]; then break; fi + echo_i "waiting ... ($i)" + sleep 1 +done +_log=1 +test "$ret" -eq 0 || echo_i "failed" +status=$((status+ret)) + +# TODO: we might want to test: +# - configuring a zone with too many active keys (should trigger retire). +# - configuring a zone with keys not matching the policy. + +# +# Zone: rsasha1-nsec3.kasp. +# +zone_properties "ns3" "rsasha1-nsec3.kasp" "rsasha1-nsec3" "1234" "3" +key_properties "KEY1" "ksk" "315360000" "7" "NSEC3RSASHA1" "2048" "yes" +key_properties "KEY2" "zsk" "157680000" "7" "NSEC3RSASHA1" "1024" "yes" +key_properties "KEY3" "zsk" "31536000" "7" "NSEC3RSASHA1" "2000" "yes" +# key_timings and key_states same as above. +check_keys +check_apex +check_subdomain +dnssec_verify + +# +# Zone: rsasha256.kasp. +# +zone_properties "ns3" "rsasha256.kasp" "rsasha256" "1234" "3" +key_properties "KEY1" "ksk" "315360000" "8" "RSASHA256" "2048" "yes" +key_properties "KEY2" "zsk" "157680000" "8" "RSASHA256" "1024" "yes" +key_properties "KEY3" "zsk" "31536000" "8" "RSASHA256" "2000" "yes" +# key_timings and key_states same as above. +check_keys +check_apex +check_subdomain +dnssec_verify + +# +# Zone: rsasha512.kasp. +# +zone_properties "ns3" "rsasha512.kasp" "rsasha512" "1234" "3" +key_properties "KEY1" "ksk" "315360000" "10" "RSASHA512" "2048" "yes" +key_properties "KEY2" "zsk" "157680000" "10" "RSASHA512" "1024" "yes" +key_properties "KEY3" "zsk" "31536000" "10" "RSASHA512" "2000" "yes" +# key_timings and key_states same as above. +check_keys +check_apex +check_subdomain +dnssec_verify + +# +# Zone: ecdsa256.kasp. +# +zone_properties "ns3" "ecdsa256.kasp" "ecdsa256" "1234" "3" +key_properties "KEY1" "ksk" "315360000" "13" "ECDSAP256SHA256" "256" "yes" +key_properties "KEY2" "zsk" "157680000" "13" "ECDSAP256SHA256" "256" "yes" +key_properties "KEY3" "zsk" "31536000" "13" "ECDSAP256SHA256" "256" "yes" +# key_timings and key_states same as above. +check_keys +check_apex +check_subdomain +dnssec_verify + +# +# Zone: ecdsa512.kasp. +# +zone_properties "ns3" "ecdsa384.kasp" "ecdsa384" "1234" "3" +key_properties "KEY1" "ksk" "315360000" "14" "ECDSAP384SHA384" "384" "yes" +key_properties "KEY2" "zsk" "157680000" "14" "ECDSAP384SHA384" "384" "yes" +key_properties "KEY3" "zsk" "31536000" "14" "ECDSAP384SHA384" "384" "yes" +# key_timings and key_states same as above. +check_keys +check_apex +check_subdomain +dnssec_verify +# TODO: ED25519 and ED448. echo_i "exit status: $status" [ $status -eq 0 ] || exit 1 diff --git a/util/copyrights b/util/copyrights index 733bedd2b15ab0b27fb4b9211956f043a0a17351..3608a3a60ecce113860f9095f899fd9e74d35762 100644 --- a/util/copyrights +++ b/util/copyrights @@ -694,7 +694,10 @@ ./bin/tests/system/ixfr/prereq.sh SH 2001,2004,2007,2012,2014,2016,2018,2019 ./bin/tests/system/ixfr/setup.sh SH 2001,2004,2007,2011,2012,2013,2014,2016,2018,2019 ./bin/tests/system/ixfr/tests.sh SH 2001,2004,2007,2011,2012,2014,2016,2018,2019 +./bin/tests/system/kasp/README TXT.BRIEF 2019 ./bin/tests/system/kasp/clean.sh SH 2019 +./bin/tests/system/kasp/ns2/setup.sh SH 2019 +./bin/tests/system/kasp/ns3/setup.sh SH 2019 ./bin/tests/system/kasp/setup.sh SH 2019 ./bin/tests/system/kasp/tests.sh SH 2019 ./bin/tests/system/keepalive/clean.sh SH 2017,2018,2019