diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-27 07:24:22 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-27 07:24:22 +0000 |
commit | 45d6379135504814ab723b57f0eb8be23393a51d (patch) | |
tree | d4f2ec4acca824a8446387a758b0ce4238a4dffa /bin/tests/system/kasp | |
parent | Initial commit. (diff) | |
download | bind9-upstream/1%9.16.44.tar.xz bind9-upstream/1%9.16.44.zip |
Adding upstream version 1:9.16.44.upstream/1%9.16.44upstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to '')
41 files changed, 10330 insertions, 0 deletions
diff --git a/bin/tests/system/kasp.sh b/bin/tests/system/kasp.sh new file mode 100644 index 0000000..d49baa3 --- /dev/null +++ b/bin/tests/system/kasp.sh @@ -0,0 +1,1238 @@ +#!/bin/sh + +# 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. + +# +# Common configuration data for kasp system tests, to be sourced into +# other shell scripts. +# + +# shellcheck source=conf.sh +. ../conf.sh + +############################################################################### +# Constants # +############################################################################### +DEFAULT_TTL=300 + +############################################################################### +# Query properties # +############################################################################### +TSIG="" +SHA1="FrSt77yPTFx6hTs4i2tKLB9LmE0=" +SHA224="hXfwwwiag2QGqblopofai9NuW28q/1rH4CaTnA==" +SHA256="R16NojROxtxH/xbDl//ehDsHm5DjWTQ2YXV+hGC2iBY=" +VIEW1="YPfMoAk6h+3iN8MDRQC004iSNHY=" +VIEW2="4xILSZQnuO1UKubXHkYUsvBRPu8=" +VIEW3="C1Azf+gGPMmxrUg/WQINP6eV9Y0=" + +############################################################################### +# Key properties # +############################################################################### +# ID +# BASEFILE +# EXPECT +# ROLE +# KSK +# ZSK +# FLAGS +# LIFETIME +# ALG_NUM +# ALG_STR +# ALG_LEN +# CREATED +# PUBLISHED +# ACTIVE +# RETIRED +# REVOKED +# REMOVED +# GOAL +# STATE_DNSKEY +# STATE_ZRRSIG +# STATE_KRRSIG +# STATE_DS +# EXPECT_ZRRSIG +# EXPECT_KRRSIG +# LEGACY +# PRIVATE +# PRIVKEY_STAT +# PUBKEY_STAT +# STATE_STAT + +key_key() { + echo "${1}__${2}" +} + +key_get() { + eval "echo \${$(key_key "$1" "$2")}" +} + +key_set() { + eval "$(key_key "$1" "$2")='$3'" +} + +key_stat() { + $PERL -e 'print((stat @ARGV[0])[9] . "\n");' "$1" +} + +# Save certain values in the KEY array. +key_save() +{ + # Save key id. + key_set "$1" ID "$KEY_ID" + # Save base filename. + key_set "$1" BASEFILE "$BASE_FILE" + # Save creation date. + key_set "$1" CREATED "${KEY_CREATED}" + # Save key change time. + key_set "$1" PRIVKEY_STAT $(key_stat "${BASE_FILE}.private") + key_set "$1" PUBKEY_STAT $(key_stat "${BASE_FILE}.key") + key_set "$1" STATE_STAT $(key_stat "${BASE_FILE}.state") +} + +# Clear key state. +# +# This will update either the KEY1, KEY2, or KEY3 array. +key_clear() { + key_set "$1" "ID" 'no' + key_set "$1" "IDPAD" 'no' + key_set "$1" "EXPECT" 'no' + key_set "$1" "ROLE" 'none' + key_set "$1" "KSK" 'no' + key_set "$1" "ZSK" 'no' + key_set "$1" "FLAGS" '0' + key_set "$1" "LIFETIME" 'none' + key_set "$1" "ALG_NUM" '0' + key_set "$1" "ALG_STR" 'none' + key_set "$1" "ALG_LEN" '0' + key_set "$1" "CREATED" '0' + key_set "$1" "PUBLISHED" 'none' + key_set "$1" "SYNCPUBLISH" 'none' + key_set "$1" "ACTIVE" 'none' + key_set "$1" "RETIRED" 'none' + key_set "$1" "REVOKED" 'none' + key_set "$1" "REMOVED" 'none' + key_set "$1" "GOAL" 'none' + key_set "$1" "STATE_DNSKEY" 'none' + key_set "$1" "STATE_KRRSIG" 'none' + key_set "$1" "STATE_ZRRSIG" 'none' + key_set "$1" "STATE_DS" 'none' + key_set "$1" "EXPECT_ZRRSIG" 'no' + key_set "$1" "EXPECT_KRRSIG" 'no' + key_set "$1" "LEGACY" 'no' + key_set "$1" "PRIVATE" 'yes' + key_set "$1" "PRIVKEY_STAT" '0' + key_set "$1" "PUBKEY_STAT" '0' + key_set "$1" "STATE_STAT" '0' +} + +# Start clear. +# There can be at most 4 keys at the same time during a rollover: +# 2x KSK, 2x ZSK +key_clear "KEY1" +key_clear "KEY2" +key_clear "KEY3" +key_clear "KEY4" + +############################################################################### +# Utilities # +############################################################################### + +# Call dig with default options. +_dig_with_opts() { + + if [ -n "$TSIG" ]; then + "$DIG" +tcp +noadd +nosea +nostat +nocmd +dnssec -p "$PORT" -y "$TSIG" "$@" + else + "$DIG" +tcp +noadd +nosea +nostat +nocmd +dnssec -p "$PORT" "$@" + fi +} + +# RNDC. +_rndccmd() { + "$RNDC" -c ../common/rndc.conf -p "$CONTROLPORT" -s "$@" +} + +# Print IDs of keys used for generating RRSIG records for RRsets of type $1 +# found in dig output file $2. +get_keys_which_signed() { + _qtype=$1 + _output=$2 + # The key ID is the 11th column of the RRSIG record line. + awk -v qt="$_qtype" '$4 == "RRSIG" && $5 == qt {print $11}' < "$_output" +} + +# Get the key ids from key files for zone $2 in directory $1. +get_keyids() { + _dir=$1 + _zone=$2 + _regex="K${_zone}.+*+*.key" + + find "${_dir}" -mindepth 1 -maxdepth 1 -name "${_regex}" | sed "s,$_dir/K${_zone}.+\([0-9]\{3\}\)+\([0-9]\{5\}\).key,\2," +} + +# By default log errors and don't quit immediately. +_log=1 +_log_error() { + test $_log -eq 1 && echo_i "error: $1" + ret=$((ret+1)) +} +disable_logerror() { + _log=0 +} +enable_logerror() { + _log=1 +} + +# Set server key-directory ($1) and address ($2) for testing keys. +set_server() { + DIR=$1 + SERVER=$2 +} +# Set zone name for testing keys. +set_zone() { + ZONE=$1 + DYNAMIC="no" +} +# By default zones are considered static. +# When testing dynamic zones, call 'set_dynamic' after 'set_zone'. +set_dynamic() { + DYNAMIC="yes" +} + +# Set policy settings (name $1, number of keys $2, dnskey ttl $3) for testing keys. +set_policy() { + POLICY=$1 + NUM_KEYS=$2 + DNSKEY_TTL=$3 + CDS_DELETE="no" +} +# By default policies are considered to be secure. +# If a zone sets its policy to "insecure", call 'set_cdsdelete' to tell the +# system test to expect a CDS and CDNSKEY Delete record. +set_cdsdelete() { + CDS_DELETE="yes" +} + +# Set key properties for testing keys. +# $1: Key to update (KEY1, KEY2, ...) +# $2: Value +set_keyrole() { + key_set "$1" "EXPECT" "yes" + key_set "$1" "ROLE" "$2" + key_set "$1" "KSK" "no" + key_set "$1" "ZSK" "no" + key_set "$1" "FLAGS" "0" + + test "$2" = "ksk" && key_set "$1" "KSK" "yes" + test "$2" = "ksk" && key_set "$1" "FLAGS" "257" + + test "$2" = "zsk" && key_set "$1" "ZSK" "yes" + test "$2" = "zsk" && key_set "$1" "FLAGS" "256" + + test "$2" = "csk" && key_set "$1" "KSK" "yes" + test "$2" = "csk" && key_set "$1" "ZSK" "yes" + test "$2" = "csk" && key_set "$1" "FLAGS" "257" +} +set_keylifetime() { + key_set "$1" "EXPECT" "yes" + key_set "$1" "LIFETIME" "$2" +} +# The algorithm value consists of three parts: +# $2: Algorithm (number) +# $3: Algorithm (string-format) +# $4: Algorithm length +set_keyalgorithm() { + key_set "$1" "EXPECT" "yes" + key_set "$1" "ALG_NUM" "$2" + key_set "$1" "ALG_STR" "$3" + key_set "$1" "ALG_LEN" "$4" +} +set_keysigning() { + key_set "$1" "EXPECT" "yes" + key_set "$1" "EXPECT_KRRSIG" "$2" +} +set_zonesigning() { + key_set "$1" "EXPECT" "yes" + key_set "$1" "EXPECT_ZRRSIG" "$2" +} + +# Set key timing metadata. Set to "none" to unset. +# $1: Key to update (KEY1, KEY2, ...) +# $2: Time to update (PUBLISHED, SYNCPUBLISH, ACTIVE, RETIRED, REVOKED, or REMOVED). +# $3: Value +set_keytime() { + key_set "$1" "EXPECT" "yes" + key_set "$1" "$2" "$3" +} + +# Set key timing metadata to a value plus additional time. +# $1: Key to update (KEY1, KEY2, ...) +# $2: Time to update (PUBLISHED, SYNCPUBLISH, ACTIVE, RETIRED, REVOKED, or REMOVED). +# $3: Value +# $4: Additional time. +set_addkeytime() { + if [ -x "$PYTHON" ]; then + # Convert "%Y%m%d%H%M%S" format to epoch seconds. + # Then, add the additional time (can be negative). + _value=$3 + _plus=$4 + $PYTHON > python.out.$ZONE.$1.$2 <<EOF +from datetime import datetime +from datetime import timedelta +_now = datetime.strptime("$_value", "%Y%m%d%H%M%S") +_delta = timedelta(seconds=$_plus) +_then = _now + _delta +print(_then.strftime("%Y%m%d%H%M%S")); +EOF + # Set the expected timing metadata. + key_set "$1" "$2" $(cat python.out.$ZONE.$1.$2) + fi +} + +# Set key state metadata. Set to "none" to unset. +# $1: Key to update (KEY1, KEY2, ...) +# $2: Key state to update (GOAL, STATE_DNSKEY, STATE_ZRRSIG, STATE_KRRSIG, or STATE_DS) +# $3: Value +set_keystate() { + key_set "$1" "EXPECT" "yes" + key_set "$1" "$2" "$3" +} + +# Check the key $1 with id $2. +# This requires environment variables to be set. +# +# 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\{0,4\}//') +# KEY_CREATED (from the KEY_FILE) +check_key() { + _dir="$DIR" + _zone="$ZONE" + _role=$(key_get "$1" ROLE) + _key_idpad="$2" + _key_id=$(echo "$_key_idpad" | sed 's/^0\{0,4\}//') + _alg_num=$(key_get "$1" ALG_NUM) + _alg_numpad=$(printf "%03d" "$_alg_num") + _alg_string=$(key_get "$1" ALG_STR) + _length=$(key_get "$1" "ALG_LEN") + _dnskey_ttl="$DNSKEY_TTL" + _lifetime=$(key_get "$1" LIFETIME) + _legacy=$(key_get "$1" LEGACY) + _private=$(key_get "$1" PRIVATE) + _flags=$(key_get "$1" FLAGS) + + _published=$(key_get "$1" PUBLISHED) + _active=$(key_get "$1" ACTIVE) + _retired=$(key_get "$1" RETIRED) + _revoked=$(key_get "$1" REVOKED) + _removed=$(key_get "$1" REMOVED) + + _goal=$(key_get "$1" GOAL) + _state_dnskey=$(key_get "$1" STATE_DNSKEY) + _state_zrrsig=$(key_get "$1" STATE_ZRRSIG) + _state_krrsig=$(key_get "$1" STATE_KRRSIG) + _state_ds=$(key_get "$1" STATE_DS) + + _ksk="no" + _zsk="no" + if [ "$_role" = "ksk" ]; then + _ksk="yes" + elif [ "$_role" = "zsk" ]; then + _zsk="yes" + elif [ "$_role" = "csk" ]; then + _zsk="yes" + _ksk="yes" + fi + + _role2="none" + if [ "$_flags" = "257" ]; then + _role2="key-signing" + elif [ "$_flags" = "256" ]; then + _role2="zone-signing" + fi + + 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}" + + # Check file existence. + [ -s "$KEY_FILE" ] || ret=1 + if [ "$_private" = "yes" ]; then + [ -s "$PRIVATE_FILE" ] || ret=1 + fi + if [ "$_legacy" = "no" ]; then + [ -s "$STATE_FILE" ] || ret=1 + fi + [ "$ret" -eq 0 ] || _log_error "${BASE_FILE} files missing" + [ "$ret" -eq 0 ] || return + + # Retrieve creation date. + grep "; Created:" "$KEY_FILE" > "${ZONE}.${KEY_ID}.${_alg_num}.created" || _log_error "mismatch created comment in $KEY_FILE" + KEY_CREATED=$(awk '{print $3}' < "${ZONE}.${KEY_ID}.${_alg_num}.created") + + if [ "$_private" = "yes" ]; then + grep "Created: ${KEY_CREATED}" "$PRIVATE_FILE" > /dev/null || _log_error "mismatch created in $PRIVATE_FILE" + fi + if [ "$_legacy" = "no" ]; then + grep "Generated: ${KEY_CREATED}" "$STATE_FILE" > /dev/null || _log_error "mismatch generated in $STATE_FILE" + fi + + test $_log -eq 1 && echo_i "check key file $BASE_FILE" + + # Check the public key file. + grep "This is a ${_role2} key, keyid ${_key_id}, for ${_zone}." "$KEY_FILE" > /dev/null || _log_error "mismatch top comment in $KEY_FILE" + grep "${_zone}\. ${_dnskey_ttl} IN DNSKEY ${_flags} 3 ${_alg_num}" "$KEY_FILE" > /dev/null || _log_error "mismatch DNSKEY record in $KEY_FILE" + # Now check the private key file. + if [ "$_private" = "yes" ]; then + grep "Private-key-format: v1.3" "$PRIVATE_FILE" > /dev/null || _log_error "mismatch private key format in $PRIVATE_FILE" + grep "Algorithm: ${_alg_num} (${_alg_string})" "$PRIVATE_FILE" > /dev/null || _log_error "mismatch algorithm in $PRIVATE_FILE" + fi + # Now check the key state file. + if [ "$_legacy" = "no" ]; then + grep "This is the state of key ${_key_id}, for ${_zone}." "$STATE_FILE" > /dev/null || _log_error "mismatch top comment in $STATE_FILE" + if [ "$_lifetime" = "none" ]; then + grep "Lifetime: " "$STATE_FILE" > /dev/null && _log_error "unexpected lifetime in $STATE_FILE" + else + grep "Lifetime: ${_lifetime}" "$STATE_FILE" > /dev/null || _log_error "mismatch lifetime in $STATE_FILE" + fi + grep "Algorithm: ${_alg_num}" "$STATE_FILE" > /dev/null || _log_error "mismatch algorithm in $STATE_FILE" + grep "Length: ${_length}" "$STATE_FILE" > /dev/null || _log_error "mismatch length in $STATE_FILE" + grep "KSK: ${_ksk}" "$STATE_FILE" > /dev/null || _log_error "mismatch ksk in $STATE_FILE" + grep "ZSK: ${_zsk}" "$STATE_FILE" > /dev/null || _log_error "mismatch zsk in $STATE_FILE" + + # Check key states. + if [ "$_goal" = "none" ]; then + grep "GoalState: " "$STATE_FILE" > /dev/null && _log_error "unexpected goal state in $STATE_FILE" + else + grep "GoalState: ${_goal}" "$STATE_FILE" > /dev/null || _log_error "mismatch goal state in $STATE_FILE" + fi + + if [ "$_state_dnskey" = "none" ]; then + grep "DNSKEYState: " "$STATE_FILE" > /dev/null && _log_error "unexpected dnskey state in $STATE_FILE" + grep "DNSKEYChange: " "$STATE_FILE" > /dev/null && _log_error "unexpected dnskey change in $STATE_FILE" + else + grep "DNSKEYState: ${_state_dnskey}" "$STATE_FILE" > /dev/null || _log_error "mismatch dnskey state in $STATE_FILE" + grep "DNSKEYChange: " "$STATE_FILE" > /dev/null || _log_error "mismatch dnskey change in $STATE_FILE" + fi + + if [ "$_state_zrrsig" = "none" ]; then + grep "ZRRSIGState: " "$STATE_FILE" > /dev/null && _log_error "unexpected zrrsig state in $STATE_FILE" + grep "ZRRSIGChange: " "$STATE_FILE" > /dev/null && _log_error "unexpected zrrsig change in $STATE_FILE" + else + grep "ZRRSIGState: ${_state_zrrsig}" "$STATE_FILE" > /dev/null || _log_error "mismatch zrrsig state in $STATE_FILE" + grep "ZRRSIGChange: " "$STATE_FILE" > /dev/null || _log_error "mismatch zrrsig change in $STATE_FILE" + fi + + if [ "$_state_krrsig" = "none" ]; then + grep "KRRSIGState: " "$STATE_FILE" > /dev/null && _log_error "unexpected krrsig state in $STATE_FILE" + grep "KRRSIGChange: " "$STATE_FILE" > /dev/null && _log_error "unexpected krrsig change in $STATE_FILE" + else + grep "KRRSIGState: ${_state_krrsig}" "$STATE_FILE" > /dev/null || _log_error "mismatch krrsig state in $STATE_FILE" + grep "KRRSIGChange: " "$STATE_FILE" > /dev/null || _log_error "mismatch krrsig change in $STATE_FILE" + fi + + if [ "$_state_ds" = "none" ]; then + grep "DSState: " "$STATE_FILE" > /dev/null && _log_error "unexpected ds state in $STATE_FILE" + grep "DSChange: " "$STATE_FILE" > /dev/null && _log_error "unexpected ds change in $STATE_FILE" + else + grep "DSState: ${_state_ds}" "$STATE_FILE" > /dev/null || _log_error "mismatch ds state in $STATE_FILE" + grep "DSChange: " "$STATE_FILE" > /dev/null || _log_error "mismatch ds change in $STATE_FILE" + fi + fi +} + +# Check the key timing metadata for key $1. +check_timingmetadata() { + _dir="$DIR" + _zone="$ZONE" + _key_idpad=$(key_get "$1" ID) + _key_id=$(echo "$_key_idpad" | sed 's/^0\{0,4\}//') + _alg_num=$(key_get "$1" ALG_NUM) + _alg_numpad=$(printf "%03d" "$_alg_num") + + _published=$(key_get "$1" PUBLISHED) + _active=$(key_get "$1" ACTIVE) + _retired=$(key_get "$1" RETIRED) + _revoked=$(key_get "$1" REVOKED) + _removed=$(key_get "$1" REMOVED) + + _goal=$(key_get "$1" GOAL) + _state_dnskey=$(key_get "$1" STATE_DNSKEY) + _state_zrrsig=$(key_get "$1" STATE_ZRRSIG) + _state_krrsig=$(key_get "$1" STATE_KRRSIG) + _state_ds=$(key_get "$1" STATE_DS) + + _base_file=$(key_get "$1" BASEFILE) + _key_file="${_base_file}.key" + _private_file="${_base_file}.private" + _state_file="${_base_file}.state" + _legacy=$(key_get "$1" LEGACY) + _private=$(key_get "$1" PRIVATE) + + _published=$(key_get "$1" PUBLISHED) + _syncpublish=$(key_get "$1" SYNCPUBLISH) + _active=$(key_get "$1" ACTIVE) + _retired=$(key_get "$1" RETIRED) + _revoked=$(key_get "$1" REVOKED) + _removed=$(key_get "$1" REMOVED) + + # Check timing metadata. + n=$((n+1)) + echo_i "check key timing metadata for key $1 id ${_key_id} zone ${ZONE} ($n)" + ret=0 + + if [ "$_published" = "none" ]; then + grep "; Publish:" "${_key_file}" > /dev/null && _log_error "unexpected publish comment in ${_key_file}" + if [ "$_private" = "yes" ]; then + grep "Publish:" "${_private_file}" > /dev/null && _log_error "unexpected publish in ${_private_file}" + fi + if [ "$_legacy" = "no" ]; then + grep "Published: " "${_state_file}" > /dev/null && _log_error "unexpected publish in ${_state_file}" + fi + else + grep "; Publish: $_published" "${_key_file}" > /dev/null || _log_error "mismatch publish comment in ${_key_file} (expected ${_published})" + if [ "$_private" = "yes" ]; then + grep "Publish: $_published" "${_private_file}" > /dev/null || _log_error "mismatch publish in ${_private_file} (expected ${_published})" + fi + if [ "$_legacy" = "no" ]; then + grep "Published: $_published" "${_state_file}" > /dev/null || _log_error "mismatch publish in ${_state_file} (expected ${_published})" + fi + fi + + if [ "$_syncpublish" = "none" ]; then + grep "; SyncPublish:" "${_key_file}" > /dev/null && _log_error "unexpected syncpublish comment in ${_key_file}" + if [ "$_private" = "yes" ]; then + grep "SyncPublish:" "${_private_file}" > /dev/null && _log_error "unexpected syncpublish in ${_private_file}" + fi + if [ "$_legacy" = "no" ]; then + grep "PublishCDS: " "${_state_file}" > /dev/null && _log_error "unexpected syncpublish in ${_state_file}" + fi + else + grep "; SyncPublish: $_syncpublish" "${_key_file}" > /dev/null || _log_error "mismatch syncpublish comment in ${_key_file} (expected ${_syncpublish})" + if [ "$_private" = "yes" ]; then + grep "SyncPublish: $_syncpublish" "${_private_file}" > /dev/null || _log_error "mismatch syncpublish in ${_private_file} (expected ${_syncpublish})" + fi + if [ "$_legacy" = "no" ]; then + grep "PublishCDS: $_syncpublish" "${_state_file}" > /dev/null || _log_error "mismatch syncpublish in ${_state_file} (expected ${_syncpublish})" + fi + fi + + if [ "$_active" = "none" ]; then + grep "; Activate:" "${_key_file}" > /dev/null && _log_error "unexpected active comment in ${_key_file}" + if [ "$_private" = "yes" ]; then + grep "Activate:" "${_private_file}" > /dev/null && _log_error "unexpected active in ${_private_file}" + fi + if [ "$_legacy" = "no" ]; then + grep "Active: " "${_state_file}" > /dev/null && _log_error "unexpected active in ${_state_file}" + fi + else + grep "; Activate: $_active" "${_key_file}" > /dev/null || _log_error "mismatch active comment in ${_key_file} (expected ${_active})" + if [ "$_private" = "yes" ]; then + grep "Activate: $_active" "${_private_file}" > /dev/null || _log_error "mismatch active in ${_private_file} (expected ${_active})" + fi + if [ "$_legacy" = "no" ]; then + grep "Active: $_active" "${_state_file}" > /dev/null || _log_error "mismatch active in ${_state_file} (expected ${_active})" + fi + fi + + if [ "$_retired" = "none" ]; then + grep "; Inactive:" "${_key_file}" > /dev/null && _log_error "unexpected retired comment in ${_key_file}" + if [ "$_private" = "yes" ]; then + grep "Inactive:" "${_private_file}" > /dev/null && _log_error "unexpected retired in ${_private_file}" + fi + if [ "$_legacy" = "no" ]; then + grep "Retired: " "${_state_file}" > /dev/null && _log_error "unexpected retired in ${_state_file}" + fi + else + grep "; Inactive: $_retired" "${_key_file}" > /dev/null || _log_error "mismatch retired comment in ${_key_file} (expected ${_retired})" + if [ "$_private" = "yes" ]; then + grep "Inactive: $_retired" "${_private_file}" > /dev/null || _log_error "mismatch retired in ${_private_file} (expected ${_retired})" + fi + if [ "$_legacy" = "no" ]; then + grep "Retired: $_retired" "${_state_file}" > /dev/null || _log_error "mismatch retired in ${_state_file} (expected ${_retired})" + fi + fi + + if [ "$_revoked" = "none" ]; then + grep "; Revoke:" "${_key_file}" > /dev/null && _log_error "unexpected revoked comment in ${_key_file}" + if [ "$_private" = "yes" ]; then + grep "Revoke:" "${_private_file}" > /dev/null && _log_error "unexpected revoked in ${_private_file}" + fi + if [ "$_legacy" = "no" ]; then + grep "Revoked: " "${_state_file}" > /dev/null && _log_error "unexpected revoked in ${_state_file}" + fi + else + grep "; Revoke: $_revoked" "${_key_file}" > /dev/null || _log_error "mismatch revoked comment in ${_key_file} (expected ${_revoked})" + if [ "$_private" = "yes" ]; then + grep "Revoke: $_revoked" "${_private_file}" > /dev/null || _log_error "mismatch revoked in ${_private_file} (expected ${_revoked})" + fi + if [ "$_legacy" = "no" ]; then + grep "Revoked: $_revoked" "${_state_file}" > /dev/null || _log_error "mismatch revoked in ${_state_file} (expected ${_revoked})" + fi + fi + + if [ "$_removed" = "none" ]; then + grep "; Delete:" "${_key_file}" > /dev/null && _log_error "unexpected removed comment in ${_key_file}" + if [ "$_private" = "yes" ]; then + grep "Delete:" "${_private_file}" > /dev/null && _log_error "unexpected removed in ${_private_file}" + fi + if [ "$_legacy" = "no" ]; then + grep "Removed: " "${_state_file}" > /dev/null && _log_error "unexpected removed in ${_state_file}" + fi + else + grep "; Delete: $_removed" "${_key_file}" > /dev/null || _log_error "mismatch removed comment in ${_key_file} (expected ${_removed})" + if [ "$_private" = "yes" ]; then + grep "Delete: $_removed" "${_private_file}" > /dev/null || _log_error "mismatch removed in ${_private_file} (expected ${_removed})" + fi + if [ "$_legacy" = "no" ]; then + grep "Removed: $_removed" "${_state_file}" > /dev/null || _log_error "mismatch removed in ${_state_file} (expected ${_removed})" + fi + fi + + test "$ret" -eq 0 || echo_i "failed" + status=$((status+ret)) +} + +check_keytimes() { + # The script relies on Python to set keytimes. + if [ -x "$PYTHON" ]; then + + if [ "$(key_get KEY1 EXPECT)" = "yes" ]; then + check_timingmetadata "KEY1" + fi + if [ "$(key_get KEY2 EXPECT)" = "yes" ]; then + check_timingmetadata "KEY2" + fi + if [ "$(key_get KEY3 EXPECT)" = "yes" ]; then + check_timingmetadata "KEY3" + fi + if [ "$(key_get KEY4 EXPECT)" = "yes" ]; then + check_timingmetadata "KEY4" + fi + fi +} + +# Check the key with key id $1 and see if it is unused. +# This requires environment variables to be set. +# +# 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\{0,4\}//') +key_unused() { + _dir=$DIR + _zone=$ZONE + _key_idpad=$1 + _key_id=$(echo "$_key_idpad" | sed 's/^0\{0,4\}//') + _alg_num=$2 + _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 file existence. + [ -s "$KEY_FILE" ] || ret=1 + [ -s "$PRIVATE_FILE" ] || ret=1 + [ -s "$STATE_FILE" ] || ret=1 + [ "$ret" -eq 0 ] || return + + # Treat keys that have been removed from the zone as unused. + _check_removed=1 + grep "; Created:" "$KEY_FILE" > created.key-${KEY_ID}.test${n} || _check_removed=0 + grep "; Delete:" "$KEY_FILE" > unused.key-${KEY_ID}.test${n} || _check_removed=0 + if [ "$_check_removed" -eq 1 ]; then + _created=$(awk '{print $3}' < created.key-${KEY_ID}.test${n}) + _removed=$(awk '{print $3}' < unused.key-${KEY_ID}.test${n}) + [ "$_removed" -le "$_created" ] && return + fi + + # If no timing metadata is set, this key is unused. + grep "; Publish:" "$KEY_FILE" > /dev/null && _log_error "unexpected publish comment in $KEY_FILE" + grep "; Activate:" "$KEY_FILE" > /dev/null && _log_error "unexpected active comment in $KEY_FILE" + grep "; Inactive:" "$KEY_FILE" > /dev/null && _log_error "unexpected retired comment in $KEY_FILE" + grep "; Revoke:" "$KEY_FILE" > /dev/null && _log_error "unexpected revoked comment in $KEY_FILE" + grep "; Delete:" "$KEY_FILE" > /dev/null && _log_error "unexpected removed comment in $KEY_FILE" + + grep "Publish:" "$PRIVATE_FILE" > /dev/null && _log_error "unexpected publish in $PRIVATE_FILE" + grep "Activate:" "$PRIVATE_FILE" > /dev/null && _log_error "unexpected active in $PRIVATE_FILE" + grep "Inactive:" "$PRIVATE_FILE" > /dev/null && _log_error "unexpected retired in $PRIVATE_FILE" + grep "Revoke:" "$PRIVATE_FILE" > /dev/null && _log_error "unexpected revoked in $PRIVATE_FILE" + grep "Delete:" "$PRIVATE_FILE" > /dev/null && _log_error "unexpected removed in $PRIVATE_FILE" + + grep "Published: " "$STATE_FILE" > /dev/null && _log_error "unexpected publish in $STATE_FILE" + grep "Active: " "$STATE_FILE" > /dev/null && _log_error "unexpected active in $STATE_FILE" + grep "Retired: " "$STATE_FILE" > /dev/null && _log_error "unexpected retired in $STATE_FILE" + grep "Revoked: " "$STATE_FILE" > /dev/null && _log_error "unexpected revoked in $STATE_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" "@${SERVER}" AXFR > dig.out.axfr.test$n || _log_error "dig ${ZONE} AXFR failed" + $VERIFY -z -o "$ZONE" dig.out.axfr.test$n > verify.out.$ZONE.test$n || _log_error "dnssec verify zone $ZONE failed" + test "$ret" -eq 0 || echo_i "failed" + status=$((status+ret)) +} + +# Wait for the zone to be signed. +# The apex NSEC record indicates that it is signed. +_wait_for_nsec() { + _dig_with_opts "@${SERVER}" "$ZONE" NSEC > "dig.out.nsec.test$n" || return 1 + grep "NS SOA" "dig.out.nsec.test$n" > /dev/null || return 1 + grep "${ZONE}\..*IN.*RRSIG" "dig.out.nsec.test$n" > /dev/null || return 1 + return 0 +} +wait_for_nsec() { + n=$((n+1)) + ret=0 + echo_i "wait for ${ZONE} to be signed ($n)" + retry_quiet 10 _wait_for_nsec || _log_error "wait for ${ZONE} to be signed failed" + test "$ret" -eq 0 || echo_i "failed" + status=$((status+ret)) +} + +check_numkeys() { + _numkeys=$(get_keyids "$DIR" "$ZONE" | wc -l) + test "$_numkeys" -eq "$NUM_KEYS" || return 1 + return 0 +} + +_check_keys() { + ret=0 + _ret=0 + + # Clear key ids. + key_set KEY1 ID "no" + key_set KEY2 ID "no" + key_set KEY3 ID "no" + key_set KEY4 ID "no" + + # Check key files. + _ids=$(get_keyids "$DIR" "$ZONE") + for _id in $_ids; do + # There are multiple key files with the same algorithm. + # Check them until a match is found. + ret=0 + echo_i "check key id $_id" + + if [ "no" = "$(key_get KEY1 ID)" ] && [ "$(key_get KEY1 EXPECT)" = "yes" ]; then + ret=0 + check_key "KEY1" "$_id" + test "$ret" -eq 0 && key_save KEY1 && continue + fi + if [ "no" = "$(key_get KEY2 ID)" ] && [ "$(key_get KEY2 EXPECT)" = "yes" ]; then + ret=0 + check_key "KEY2" "$_id" + test "$ret" -eq 0 && key_save KEY2 && continue + fi + if [ "no" = "$(key_get KEY3 ID)" ] && [ "$(key_get KEY3 EXPECT)" = "yes" ]; then + ret=0 + check_key "KEY3" "$_id" + test "$ret" -eq 0 && key_save KEY3 && continue + fi + if [ "no" = "$(key_get KEY4 ID)" ] && [ "$(key_get KEY4 EXPECT)" = "yes" ]; then + ret=0 + check_key "KEY4" "$_id" + test "$ret" -eq 0 && key_save KEY4 && continue + fi + + # This may be an unused key. Assume algorithm of KEY1. + ret=0 && key_unused "$_id" "$(key_get KEY1 ALG_NUM)" + test "$ret" -eq 0 && continue + + # If ret is still non-zero, none of the files matched. + echo_i "failed" + _ret=1 + done + + return $_ret +} + +# 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. Checks KEY1, KEY2, KEY3, and KEY4. +# +# It is expected that KEY1, KEY2, KEY3, and KEY4 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 + + echo_i "check number of keys for zone ${ZONE} in dir ${DIR} ($n)" + retry_quiet 10 check_numkeys || ret=1 + if [ $ret -ne 0 ]; then + _numkeys=$(get_keyids "$DIR" "$ZONE" | wc -l) + _log_error "bad number of key files ($_numkeys) for zone $ZONE (expected $NUM_KEYS)" + status=$((status+ret)) + fi + + # Temporarily don't log errors because we are searching multiple files. + disable_logerror + + retry_quiet 3 _check_keys || ret=1 + test "$ret" -eq 0 || echo_i "failed" + status=$((status+ret)) + + # Turn error logs on again. + enable_logerror + + ret=0 + if [ "$(key_get KEY1 EXPECT)" = "yes" ]; then + echo_i "KEY1 ID $(key_get KEY1 ID)" + test "no" = "$(key_get KEY1 ID)" && _log_error "No KEY1 found for zone ${ZONE}" + fi + if [ "$(key_get KEY2 EXPECT)" = "yes" ]; then + echo_i "KEY2 ID $(key_get KEY2 ID)" + test "no" = "$(key_get KEY2 ID)" && _log_error "No KEY2 found for zone ${ZONE}" + fi + if [ "$(key_get KEY3 EXPECT)" = "yes" ]; then + echo_i "KEY3 ID $(key_get KEY3 ID)" + test "no" = "$(key_get KEY3 ID)" && _log_error "No KEY3 found for zone ${ZONE}" + fi + if [ "$(key_get KEY4 EXPECT)" = "yes" ]; then + echo_i "KEY4 ID $(key_get KEY4 ID)" + test "no" = "$(key_get KEY4 ID)" && _log_error "No KEY4 found for zone ${ZONE}" + fi + test "$ret" -eq 0 || echo_i "failed" + status=$((status+ret)) +} + +# Call rndc dnssec -status on server $1 for zone $3 in view $4 with policy $2 +# and check output. This is a loose verification, it just tests if the right +# policy name is returned, and if all expected keys are listed. The rndc +# dnssec -status output also lists whether a key is published, +# used for signing, is retired, or is removed, and if not when +# it is scheduled to do so, and it shows the states for the various +# DNSSEC records. +check_dnssecstatus() { + _server=$1 + _policy=$2 + _zone=$3 + _view=$4 + + n=$((n+1)) + echo_i "check rndc dnssec -status output for ${_zone} (policy: $_policy) ($n)" + ret=0 + + _rndccmd $_server dnssec -status $_zone in $_view > rndc.dnssec.status.out.$_zone.$n || _log_error "rndc dnssec -status zone ${_zone} failed" + + if [ "$_policy" = "none" ]; then + grep "Zone does not have dnssec-policy" rndc.dnssec.status.out.$_zone.$n > /dev/null || log_error "bad dnssec status for unsigned zone ${_zone}" + else + grep "dnssec-policy: ${_policy}" rndc.dnssec.status.out.$_zone.$n > /dev/null || _log_error "bad dnssec status for signed zone ${_zone}" + if [ "$(key_get KEY1 EXPECT)" = "yes" ]; then + grep "key: $(key_get KEY1 ID)" rndc.dnssec.status.out.$_zone.$n > /dev/null || _log_error "missing key $(key_get KEY1 ID) from dnssec status" + fi + if [ "$(key_get KEY2 EXPECT)" = "yes" ]; then + grep "key: $(key_get KEY2 ID)" rndc.dnssec.status.out.$_zone.$n > /dev/null || _log_error "missing key $(key_get KEY2 ID) from dnssec status" + fi + if [ "$(key_get KEY3 EXPECT)" = "yes" ]; then + grep "key: $(key_get KEY3 ID)" rndc.dnssec.status.out.$_zone.$n > /dev/null || _log_error "missing key $(key_get KEY3 ID) from dnssec status" + fi + if [ "$(key_get KEY4 EXPECT)" = "yes" ]; then + grep "key: $(key_get KEY4 ID)" rndc.dnssec.status.out.$_zone.$n > /dev/null || _log_error "missing key $(key_get KEY4 ID) from dnssec status" + fi + fi + + test "$ret" -eq 0 || echo_i "failed" + status=$((status+ret)) +} + +# Call rndc zonestatus on server $1 for zone $2 in view $3 and check output if +# inline-signing is enabled. +check_inlinesigning() { + _server=$1 + _zone=$2 + _view=$3 + + _rndccmd $_server zonestatus $_zone in $_view > rndc.zonestatus.out.$_zone.$n || return 1 + grep "inline signing: yes" rndc.zonestatus.out.$_zone.$n > /dev/null || return 1 +} + +# Call rndc zonestatus on server $1 for zone $2 in view $3 and check output if +# the zone is dynamic. +check_isdynamic() { + _server=$1 + _zone=$2 + _view=$3 + + _rndccmd $_server zonestatus $_zone in $_view > rndc.zonestatus.out.$_zone.$n || return 1 + grep "dynamic: yes" rndc.zonestatus.out.$_zone.$n > /dev/null || return 1 +} + +# 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 + + numsigs=0 + + if [ "$_role" = "KSK" ]; then + _expect_type=EXPECT_KRRSIG + elif [ "$_role" = "ZSK" ]; then + _expect_type=EXPECT_ZRRSIG + fi + + if [ "$(key_get KEY1 "$_expect_type")" = "yes" ] && [ "$(key_get KEY1 "$_role")" = "yes" ]; then + get_keys_which_signed "$_qtype" "$_file" | grep "^$(key_get KEY1 ID)$" > /dev/null || return 1 + numsigs=$((numsigs+1)) + elif [ "$(key_get KEY1 EXPECT)" = "yes" ]; then + get_keys_which_signed "$_qtype" "$_file" | grep "^$(key_get KEY1 ID)$" > /dev/null && return 1 + fi + + if [ "$(key_get KEY2 "$_expect_type")" = "yes" ] && [ "$(key_get KEY2 "$_role")" = "yes" ]; then + get_keys_which_signed "$_qtype" "$_file" | grep "^$(key_get KEY2 ID)$" > /dev/null || return 1 + numsigs=$((numsigs+1)) + elif [ "$(key_get KEY2 EXPECT)" = "yes" ]; then + get_keys_which_signed "$_qtype" "$_file" | grep "^$(key_get KEY2 ID)$" > /dev/null && return 1 + fi + + if [ "$(key_get KEY3 "$_expect_type")" = "yes" ] && [ "$(key_get KEY3 "$_role")" = "yes" ]; then + get_keys_which_signed "$_qtype" "$_file" | grep "^$(key_get KEY3 ID)$" > /dev/null || return 1 + numsigs=$((numsigs+1)) + elif [ "$(key_get KEY3 EXPECT)" = "yes" ]; then + get_keys_which_signed "$_qtype" "$_file" | grep "^$(key_get KEY3 ID)$" > /dev/null && return 1 + fi + + if [ "$(key_get KEY4 "$_expect_type")" = "yes" ] && [ "$(key_get KEY4 "$_role")" = "yes" ]; then + get_keys_which_signed "$_qtype" "$_file" | grep "^$(key_get KEY4 ID)$" > /dev/null || return 1 + numsigs=$((numsigs+1)) + elif [ "$(key_get KEY4 EXPECT)" = "yes" ]; then + get_keys_which_signed "$_qtype" "$_file" | grep "^$(key_get KEY4 ID)$" > /dev/null && return 1 + fi + + lines=$(get_keys_which_signed "${_qtype}" "${_file}" | wc -l) + test "$lines" -eq "$numsigs" || echo_i "bad number of signatures for $_qtype (got $lines, expected $numsigs)" + test "$lines" -eq "$numsigs" || return 1 + + return 0 +} +check_signatures() { + retry_quiet 3 _check_signatures $1 $2 $3 || _log_error "RRset $1 in zone $ZONE incorrectly signed" +} + +response_has_cds_for_key() ( + awk -v zone="${ZONE%%.}." \ + -v ttl="${DNSKEY_TTL}" \ + -v qtype="CDS" \ + -v keyid="$(key_get "${1}" ID)" \ + -v keyalg="$(key_get "${1}" ALG_NUM)" \ + -v hashalg="2" \ + 'BEGIN { ret=1; } + $1 == zone && $2 == ttl && $4 == qtype && $5 == keyid && $6 == keyalg && $7 == hashalg { ret=0; exit; } + END { exit ret; }' \ + "$2" +) + +response_has_cdnskey_for_key() ( + + awk -v zone="${ZONE%%.}." \ + -v ttl="${DNSKEY_TTL}" \ + -v qtype="CDNSKEY" \ + -v flags="$(key_get "${1}" FLAGS)" \ + -v keyalg="$(key_get "${1}" ALG_NUM)" \ + 'BEGIN { ret=1; } + $1 == zone && $2 == ttl && $4 == qtype && $5 == flags && $7 == keyalg { ret=0; exit; } + END { exit ret; }' \ + "$2" +) + +# Test CDS and CDNSKEY publication. +check_cds() { + + n=$((n+1)) + echo_i "check CDS and CDNSKEY rrset are signed correctly for zone ${ZONE} ($n)" + ret=0 + + _checksig=0 + + _dig_with_opts "$ZONE" "@${SERVER}" "CDS" > "dig.out.$DIR.test$n.cds" || _log_error "dig ${ZONE} CDS failed" + grep "status: NOERROR" "dig.out.$DIR.test$n.cds" > /dev/null || _log_error "mismatch status in DNS response" + + _dig_with_opts "$ZONE" "@${SERVER}" "CDNSKEY" > "dig.out.$DIR.test$n.cdnskey" || _log_error "dig ${ZONE} CDNSKEY failed" + grep "status: NOERROR" "dig.out.$DIR.test$n.cdnskey" > /dev/null || _log_error "mismatch status in DNS response" + + if [ "$CDS_DELETE" = "no" ]; then + grep "CDS.*0 0 0 00" "dig.out.$DIR.test$n.cds" > /dev/null && _log_error "unexpected CDS DELETE record in DNS response" + grep "CDNSKEY.*0 3 0 AA==" "dig.out.$DIR.test$n.cdnskey" > /dev/null && _log_error "unexpected CDNSKEY DELETE record in DNS response" + else + grep "CDS.*0 0 0 00" "dig.out.$DIR.test$n.cds" > /dev/null || _log_error "missing CDS DELETE record in DNS response" + grep "CDNSKEY.*0 3 0 AA==" "dig.out.$DIR.test$n.cdnskey" > /dev/null || _log_error "missing CDNSKEY DELETE record in DNS response" + _checksig=1 + fi + + if [ "$(key_get KEY1 STATE_DS)" = "rumoured" ] || [ "$(key_get KEY1 STATE_DS)" = "omnipresent" ]; then + response_has_cds_for_key KEY1 "dig.out.$DIR.test$n.cds" || _log_error "missing CDS record in response for key $(key_get KEY1 ID)" + response_has_cdnskey_for_key KEY1 "dig.out.$DIR.test$n.cdnskey" || _log_error "missing CDNSKEY record in response for key $(key_get KEY1 ID)" + _checksig=1 + elif [ "$(key_get KEY1 EXPECT)" = "yes" ]; then + response_has_cds_for_key KEY1 "dig.out.$DIR.test$n.cds" && _log_error "unexpected CDS record in response for key $(key_get KEY1 ID)" + # KEY1 should not have an associated CDNSKEY, but there may be + # one for another key. Since the CDNSKEY has no field for key + # id, it is hard to check what key the CDNSKEY may belong to + # so let's skip this check for now. + fi + + if [ "$(key_get KEY2 STATE_DS)" = "rumoured" ] || [ "$(key_get KEY2 STATE_DS)" = "omnipresent" ]; then + response_has_cds_for_key KEY2 "dig.out.$DIR.test$n.cds" || _log_error "missing CDS record in response for key $(key_get KEY2 ID)" + response_has_cdnskey_for_key KEY2 "dig.out.$DIR.test$n.cdnskey" || _log_error "missing CDNSKEY record in response for key $(key_get KEY2 ID)" + _checksig=1 + elif [ "$(key_get KEY2 EXPECT)" = "yes" ]; then + response_has_cds_for_key KEY2 "dig.out.$DIR.test$n.cds" && _log_error "unexpected CDS record in response for key $(key_get KEY2 ID)" + # KEY2 should not have an associated CDNSKEY, but there may be + # one for another key. Since the CDNSKEY has no field for key + # id, it is hard to check what key the CDNSKEY may belong to + # so let's skip this check for now. + fi + + if [ "$(key_get KEY3 STATE_DS)" = "rumoured" ] || [ "$(key_get KEY3 STATE_DS)" = "omnipresent" ]; then + response_has_cds_for_key KEY3 "dig.out.$DIR.test$n.cds" || _log_error "missing CDS record in response for key $(key_get KEY3 ID)" + response_has_cdnskey_for_key KEY3 "dig.out.$DIR.test$n.cdnskey" || _log_error "missing CDNSKEY record in response for key $(key_get KEY3 ID)" + _checksig=1 + elif [ "$(key_get KEY3 EXPECT)" = "yes" ]; then + response_has_cds_for_key KEY3 "dig.out.$DIR.test$n.cds" && _log_error "unexpected CDS record in response for key $(key_get KEY3 ID)" + # KEY3 should not have an associated CDNSKEY, but there may be + # one for another key. Since the CDNSKEY has no field for key + # id, it is hard to check what key the CDNSKEY may belong to + # so let's skip this check for now. + fi + + if [ "$(key_get KEY4 STATE_DS)" = "rumoured" ] || [ "$(key_get KEY4 STATE_DS)" = "omnipresent" ]; then + response_has_cds_for_key KEY4 "dig.out.$DIR.test$n.cds" || _log_error "missing CDS record in response for key $(key_get KEY4 ID)" + response_has_cdnskey_for_key KEY4 "dig.out.$DIR.test$n.cdnskey" || _log_error "missing CDNSKEY record in response for key $(key_get KEY4 ID)" + _checksig=1 + elif [ "$(key_get KEY4 EXPECT)" = "yes" ]; then + response_has_cds_for_key KEY4 "dig.out.$DIR.test$n.cds" && _log_error "unexpected CDS record in response for key $(key_get KEY4 ID)" + # KEY4 should not have an associated CDNSKEY, but there may be + # one for another key. Since the CDNSKEY has no field for key + # id, it is hard to check what key the CDNSKEY may belong to + # so let's skip this check for now. + fi + + test "$_checksig" -eq 0 || check_signatures "CDS" "dig.out.$DIR.test$n.cds" "KSK" + test "$_checksig" -eq 0 || check_signatures "CDNSKEY" "dig.out.$DIR.test$n.cdnskey" "KSK" + + test "$ret" -eq 0 || echo_i "failed" + status=$((status+ret)) +} + +_find_dnskey() { + _owner="${ZONE}." + _alg="$(key_get $1 ALG_NUM)" + _flags="$(key_get $1 FLAGS)" + _key_file="$(key_get $1 BASEFILE).key" + + awk '$1 == "'"$_owner"'" && $2 == "'"$DNSKEY_TTL"'" && $3 == "IN" && $4 == "DNSKEY" && $5 == "'"$_flags"'" && $6 == "3" && $7 == "'"$_alg"'" { print $8 }' < "$_key_file" +} + + +# Test DNSKEY query. +_check_apex_dnskey() { + _dig_with_opts "$ZONE" "@${SERVER}" "DNSKEY" > "dig.out.$DIR.test$n" || return 1 + grep "status: NOERROR" "dig.out.$DIR.test$n" > /dev/null || return 1 + + _checksig=0 + + if [ "$(key_get KEY1 STATE_DNSKEY)" = "rumoured" ] || [ "$(key_get KEY1 STATE_DNSKEY)" = "omnipresent" ]; then + _pubkey=$(_find_dnskey KEY1) + test -z "$_pubkey" && return 1 + grep -F "$_pubkey" "dig.out.$DIR.test$n" > /dev/null || return 1 + _checksig=1 + elif [ "$(key_get KEY1 EXPECT)" = "yes" ]; then + _pubkey=$(_find_dnskey KEY1) + test -z "$_pubkey" && return 1 + grep -F "$_pubkey" "dig.out.$DIR.test$n" > /dev/null && return 1 + fi + + if [ "$(key_get KEY2 STATE_DNSKEY)" = "rumoured" ] || [ "$(key_get KEY2 STATE_DNSKEY)" = "omnipresent" ]; then + _pubkey=$(_find_dnskey KEY2) + test -z "$_pubkey" && return 1 + grep -F "$_pubkey" "dig.out.$DIR.test$n" > /dev/null || return 1 + _checksig=1 + elif [ "$(key_get KEY2 EXPECT)" = "yes" ]; then + _pubkey=$(_find_dnskey KEY2) + test -z "$_pubkey" && return 1 + grep -F "$_pubkey" "dig.out.$DIR.test$n" > /dev/null && return 1 + fi + + if [ "$(key_get KEY3 STATE_DNSKEY)" = "rumoured" ] || [ "$(key_get KEY3 STATE_DNSKEY)" = "omnipresent" ]; then + _pubkey=$(_find_dnskey KEY3) + test -z "$_pubkey" && return 1 + grep -F "$_pubkey" "dig.out.$DIR.test$n" > /dev/null || return 1 + _checksig=1 + elif [ "$(key_get KEY3 EXPECT)" = "yes" ]; then + _pubkey=$(_find_dnskey KEY3) + test -z "$_pubkey" && return 1 + grep -F "$_pubkey" "dig.out.$DIR.test$n" > /dev/null && return 1 + fi + + if [ "$(key_get KEY4 STATE_DNSKEY)" = "rumoured" ] || [ "$(key_get KEY4 STATE_DNSKEY)" = "omnipresent" ]; then + _pubkey=$(_find_dnskey KEY4) + test -z "$_pubkey" && return 1 + grep -F "$_pubkey" "dig.out.$DIR.test$n" > /dev/null || return 1 + _checksig=1 + elif [ "$(key_get KEY4 EXPECT)" = "yes" ]; then + _pubkey=$(_find_dnskey KEY4) + test -z "$_pubkey" && return 1 + grep -F "$_pubkey" "dig.out.$DIR.test$n" > /dev/null && return 1 + fi + + test "$_checksig" -eq 0 && return 0 + + _check_signatures "DNSKEY" "dig.out.$DIR.test$n" "KSK" || return 1 + + return 0 +} + +# 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. + n=$((n+1)) + echo_i "check DNSKEY rrset is signed correctly for zone ${ZONE} ($n)" + ret=0 + retry_quiet 10 _check_apex_dnskey || ret=1 + test "$ret" -eq 0 || echo_i "failed" + status=$((status+ret)) + + # We retry the DNSKEY query for at most ten seconds to avoid test + # failures due to timing issues. If the DNSKEY query check passes this + # means the zone is resigned and further apex checks (SOA, CDS, CDNSKEY) + # don't need to be retried quietly. + + # Test SOA query. + n=$((n+1)) + echo_i "check SOA rrset is signed correctly for zone ${ZONE} ($n)" + ret=0 + _dig_with_opts "$ZONE" "@${SERVER}" "SOA" > "dig.out.$DIR.test$n" || _log_error "dig ${ZONE} SOA failed" + grep "status: NOERROR" "dig.out.$DIR.test$n" > /dev/null || _log_error "mismatch status in DNS response" + grep "${ZONE}\..*${DEFAULT_TTL}.*IN.*SOA.*" "dig.out.$DIR.test$n" > /dev/null || _log_error "missing SOA record in response" + check_signatures "SOA" "dig.out.$DIR.test$n" "ZSK" + test "$ret" -eq 0 || echo_i "failed" + status=$((status+ret)) + + # Test CDS and CDNSKEY publication. + check_cds +} + +# 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" "@${SERVER}" $_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 if "CDS/CDNSKEY Published" is logged. +check_cdslog() { + _dir=$1 + _zone=$2 + _key=$3 + + _alg=$(key_get $_key ALG_STR) + _id=$(key_get $_key ID) + + n=$((n+1)) + echo_i "check CDS/CDNSKEY publication is logged in ${_dir}/named.run for key ${_zone}/${_alg}/${_id} ($n)" + ret=0 + + grep "CDS for key ${_zone}/${_alg}/${_id} is now published" "${_dir}/named.run" > /dev/null || ret=1 + grep "CDNSKEY for key ${_zone}/${_alg}/${_id} is now published" "${_dir}/named.run" > /dev/null || ret=1 + + test "$ret" -eq 0 || echo_i "failed" + status=$((status+ret)) +} + +# Tell named that the DS for the key in given zone has been seen in the +# parent (this does not actually has to be true, we just issue the command +# to make named believe it can continue with the rollover). +rndc_checkds() { + _server=$1 + _dir=$2 + _key=$3 + _when=$4 + _what=$5 + _zone=$6 + _view=$7 + + _keycmd="" + if [ "${_key}" != "-" ]; then + _keyid=$(key_get $_key ID) + _keycmd=" -key ${_keyid}" + fi + + _whencmd="" + if [ "${_when}" != "now" ]; then + _whencmd=" -when ${_when}" + fi + + n=$((n+1)) + echo_i "calling rndc dnssec -checkds${_keycmd}${_whencmd} ${_what} zone ${_zone} in ${_view} ($n)" + ret=0 + + _rndccmd $_server dnssec -checkds $_keycmd $_whencmd $_what $_zone in $_view > rndc.dnssec.checkds.out.$_zone.$n || _log_error "rndc dnssec -checkds${_keycmd}${_whencmd} ${_what} zone ${_zone} failed" + + test "$ret" -eq 0 || echo_i "failed" + status=$((status+ret)) +} + +# Tell named to schedule a key rollover. +rndc_rollover() { + _server=$1 + _dir=$2 + _keyid=$3 + _when=$4 + _zone=$5 + _view=$6 + + _whencmd="" + if [ "${_when}" != "now" ]; then + _whencmd="-when ${_when}" + fi + + n=$((n+1)) + echo_i "calling rndc dnssec -rollover key ${_keyid} ${_whencmd} zone ${_zone} ($n)" + ret=0 + + _rndccmd $_server dnssec -rollover -key $_keyid $_whencmd $_zone in $_view > rndc.dnssec.rollover.out.$_zone.$n || _log_error "rndc dnssec -rollover (key ${_keyid} when ${_when}) zone ${_zone} failed" + + test "$ret" -eq 0 || echo_i "failed" + status=$((status+ret)) +} diff --git a/bin/tests/system/kasp/README b/bin/tests/system/kasp/README new file mode 100644 index 0000000..96b0ef7 --- /dev/null +++ b/bin/tests/system/kasp/README @@ -0,0 +1,23 @@ +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. + +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. + +ns4 and ns5 are authoritative servers for various test domains related to views. + +ns6 is an authoritative server that tests changes in dnssec-policy (algorithm +rollover). diff --git a/bin/tests/system/kasp/clean.sh b/bin/tests/system/kasp/clean.sh new file mode 100644 index 0000000..db264c2 --- /dev/null +++ b/bin/tests/system/kasp/clean.sh @@ -0,0 +1,36 @@ +#!/bin/sh + +# 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. + +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.* verify.out.* zone.out.* +rm -f ns*/named.conf ns*/named.memstats ns*/named.run* +rm -f ns*/named-fips.conf +rm -f ns*/policies/*.conf +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 +rm -f ns*/*.mkeys +rm -f ns*/zones ns*/*.db.infile +rm -f ns*/*.zsk1 ns*/*.zsk2 +rm -f ns3/legacy-keys.* +rm -f *.created published.test* retired.test* +rm -f rndc.dnssec.*.out.* rndc.zonestatus.out.* +rm -f python.out.* +rm -f *-supported.file +rm -f created.key-* unused.key-* diff --git a/bin/tests/system/kasp/kasp.conf b/bin/tests/system/kasp/kasp.conf new file mode 100644 index 0000000..e7a2eab --- /dev/null +++ b/bin/tests/system/kasp/kasp.conf @@ -0,0 +1,27 @@ +/* + * 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. + */ + +/* + * This is just a random selection of configuration options. + */ + +dnssec-policy "kasp" { + dnskey-ttl 200; + + keys { + csk key-directory lifetime P1Y algorithm 13; + ksk key-directory lifetime P1Y algorithm 8; + zsk key-directory lifetime P30D algorithm 8 2048; + zsk key-directory lifetime P6M algorithm 8 3072; + }; +}; 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 0000000..4b673c4 --- /dev/null +++ b/bin/tests/system/kasp/ns2/named.conf.in @@ -0,0 +1,61 @@ +/* + * 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. + */ + +// 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; + dnssec-policy "none"; +}; + +key rndc_key { + secret "1234abcd8765"; + algorithm hmac-sha256; +}; + +controls { + inet 10.53.0.2 port @CONTROLPORT@ allow { any; } keys { rndc_key; }; +}; + +/* Inherit dnssec-policy (which is none) */ + +zone "unsigned.tld" { + type primary; + file "unsigned.tld.db"; +}; + +/* Override dnssec-policy */ + +zone "signed.tld" { + type primary; + file "signed.tld.db"; + dnssec-policy "default"; + inline-signing yes; +}; + +/* Primary service for ns3 */ + +zone "secondary.kasp" { + type primary; + 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 0000000..3c8d124 --- /dev/null +++ b/bin/tests/system/kasp/ns2/secondary.kasp.db.in @@ -0,0 +1,29 @@ +; 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. + +$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 0000000..9289831 --- /dev/null +++ b/bin/tests/system/kasp/ns2/secondary.kasp.db.in2 @@ -0,0 +1,30 @@ +; 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. + +$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 0000000..3890d52 --- /dev/null +++ b/bin/tests/system/kasp/ns2/setup.sh @@ -0,0 +1,35 @@ +#!/bin/sh -e + +# 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. + +# shellcheck source=conf.sh +. "$SYSTEMTESTTOP/conf.sh" + +echo_i "ns2/setup.sh" + +zone="secondary.kasp" +echo_i "setting up zone: $zone" +zonefile="${zone}.db" +infile="${zonefile}.in" +cp $infile $zonefile + +zone="signed.tld" +echo_i "setting up zone: $zone" +zonefile="${zone}.db" +infile="template.tld.db.in" +cp $infile $zonefile + +zone="unsigned.tld" +echo_i "setting up zone: $zone" +zonefile="${zone}.db" +infile="template.tld.db.in" +cp $infile $zonefile diff --git a/bin/tests/system/kasp/ns2/template.tld.db.in b/bin/tests/system/kasp/ns2/template.tld.db.in new file mode 100644 index 0000000..400dc34 --- /dev/null +++ b/bin/tests/system/kasp/ns2/template.tld.db.in @@ -0,0 +1,27 @@ +; 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. + +$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 +ns2 A 10.53.0.2 + +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/ed25519.conf b/bin/tests/system/kasp/ns3/ed25519.conf new file mode 100644 index 0000000..999fa2f --- /dev/null +++ b/bin/tests/system/kasp/ns3/ed25519.conf @@ -0,0 +1,29 @@ +/* + * 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. + */ + +dnssec-policy "ed25519" { + dnskey-ttl 1234; + + keys { + ksk key-directory lifetime P10Y algorithm 15; + zsk key-directory lifetime P5Y algorithm 15; + zsk key-directory lifetime P1Y algorithm 15 256; + }; +}; + +zone "ed25519.kasp" { + type primary; + file "ed25519.kasp.db"; + inline-signing yes; + dnssec-policy "ed25519"; +}; diff --git a/bin/tests/system/kasp/ns3/ed448.conf b/bin/tests/system/kasp/ns3/ed448.conf new file mode 100644 index 0000000..e9c8312 --- /dev/null +++ b/bin/tests/system/kasp/ns3/ed448.conf @@ -0,0 +1,29 @@ +/* + * 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. + */ + +dnssec-policy "ed448" { + dnskey-ttl 1234; + + keys { + ksk key-directory lifetime P10Y algorithm 16; + zsk key-directory lifetime P5Y algorithm 16; + zsk key-directory lifetime P1Y algorithm 16 456; + }; +}; + +zone "ed448.kasp" { + type primary; + file "ed448.kasp.db"; + inline-signing yes; + dnssec-policy "ed448"; +}; diff --git a/bin/tests/system/kasp/ns3/named-fips.conf.in b/bin/tests/system/kasp/ns3/named-fips.conf.in new file mode 100644 index 0000000..b14b142 --- /dev/null +++ b/bin/tests/system/kasp/ns3/named-fips.conf.in @@ -0,0 +1,519 @@ +/* + * 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. + */ + +// NS3 + +include "policies/kasp.conf"; +include "policies/autosign.conf"; + +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; + dnssec-policy "rsasha256"; +}; + +key rndc_key { + secret "1234abcd8765"; + algorithm @DEFAULT_HMAC@; +}; + +controls { + inet 10.53.0.3 port @CONTROLPORT@ allow { any; } keys { rndc_key; }; +}; + +/* Zones that are getting initially signed */ + +/* The default case: No keys created, using default policy. */ +zone "default.kasp" { + type primary; + file "default.kasp.db"; + inline-signing yes; + dnssec-policy "default"; +}; + +/* checkds: Zone with one KSK. */ +zone "checkds-ksk.kasp" { + type primary; + file "checkds-ksk.kasp.db"; + inline-signing yes; + dnssec-policy "checkds-ksk"; +}; + +/* checkds: Zone with two KSKs. */ +zone "checkds-doubleksk.kasp" { + type primary; + file "checkds-doubleksk.kasp.db"; + inline-signing yes; + dnssec-policy "checkds-doubleksk"; +}; + +/* checkds: Zone with one CSK. */ +zone "checkds-csk.kasp" { + type primary; + file "checkds-csk.kasp.db"; + inline-signing yes; + dnssec-policy "checkds-csk"; +}; + +/* Key lifetime unlimited. */ +zone "unlimited.kasp" { + type primary; + file "unlimited.kasp.db"; + inline-signing yes; + dnssec-policy "unlimited"; +}; + +/* Manual rollover. */ +zone "manual-rollover.kasp" { + type primary; + file "manual-rollover.kasp.db"; + inline-signing yes; + dnssec-policy "manual-rollover"; +}; + +/* A zone that inherits dnssec-policy. */ +zone "inherit.kasp" { + type primary; + inline-signing yes; + file "inherit.kasp.db"; +}; + +/* A zone that overrides dnssec-policy. */ +zone "unsigned.kasp" { + type primary; + file "unsigned.kasp.db"; + inline-signing yes; + dnssec-policy "none"; +}; + +/* A zone that is initially set to insecure. */ +zone "insecure.kasp" { + type primary; + file "insecure.kasp.db"; + inline-signing yes; + dnssec-policy "insecure"; +}; + +/* A primary zone with dnssec-policy but keys already created. */ +zone "dnssec-keygen.kasp" { + type primary; + file "dnssec-keygen.kasp.db"; + inline-signing yes; + dnssec-policy "rsasha256"; +}; + +/* A secondary zone with dnssec-policy. */ +zone "secondary.kasp" { + type secondary; + primaries { 10.53.0.2; }; + file "secondary.kasp.db"; + inline-signing yes; + dnssec-policy "rsasha256"; +}; + +/* A dynamic zone with dnssec-policy. */ +zone "dynamic.kasp" { + type primary; + file "dynamic.kasp.db"; + dnssec-policy "default"; + allow-update { any; }; +}; + +/* A dynamic inline-signed zone with dnssec-policy. */ +zone "dynamic-inline-signing.kasp" { + type primary; + file "dynamic-inline-signing.kasp.db"; + dnssec-policy "default"; + allow-update { any; }; + inline-signing yes; +}; + +/* An inline-signed zone with dnssec-policy. */ +zone "inline-signing.kasp" { + type primary; + file "inline-signing.kasp.db"; + dnssec-policy "default"; + inline-signing yes; +}; + +/* + * A configured dnssec-policy but some keys already created. + */ +zone "some-keys.kasp" { + type primary; + file "some-keys.kasp.db"; + inline-signing yes; + dnssec-policy "rsasha256"; +}; + +/* + * A configured dnssec-policy but some keys already in use. + */ +zone "legacy-keys.kasp" { + type primary; + file "legacy-keys.kasp.db"; + inline-signing yes; + dnssec-policy "migrate-to-dnssec-policy"; +}; + +/* + * A configured dnssec-policy with (too) many keys pregenerated. + */ +zone "pregenerated.kasp" { + type primary; + file "pregenerated.kasp.db"; + inline-signing yes; + dnssec-policy "rsasha256"; +}; + +/* + * A configured dnssec-policy with one rumoured key. + * Bugfix case for GL #1593. + */ +zone "rumoured.kasp" { + type primary; + file "rumoured.kasp.db"; + inline-signing yes; + dnssec-policy "rsasha256"; +}; + +/* RFC 8901 Multi-signer Model 2. */ +zone "multisigner-model2.kasp" { + type primary; + file "multisigner-model2.kasp.db"; + dnssec-policy "multisigner-model2"; + allow-update { any; }; +}; + +/* + * Different algorithms. + */ +zone "rsasha256.kasp" { + type primary; + file "rsasha256.kasp.db"; + inline-signing yes; + dnssec-policy "rsasha256"; +}; +zone "rsasha512.kasp" { + type primary; + file "rsasha512.kasp.db"; + inline-signing yes; + dnssec-policy "rsasha512"; +}; +zone "ecdsa256.kasp" { + type primary; + file "ecdsa256.kasp.db"; + inline-signing yes; + dnssec-policy "ecdsa256"; +}; +zone "ecdsa384.kasp" { + type primary; + file "ecdsa384.kasp.db"; + inline-signing yes; + dnssec-policy "ecdsa384"; +}; + +/* + * Zone with too high TTL. + */ +zone "max-zone-ttl.kasp" { + type primary; + file "max-zone-ttl.kasp.db"; + inline-signing yes; + dnssec-policy "ttl"; +}; + +/* + * Zone for testing GL #2375: Three is a crowd. + */ +zone "three-is-a-crowd.kasp" { + type primary; + file "three-is-a-crowd.kasp.db"; + inline-signing yes; + /* Use same policy as KSK rollover test zones. */ + dnssec-policy "ksk-doubleksk"; +}; + +/* + * Zones in different signing states. + */ + +/* + * Zone that has expired signatures. + */ +zone "expired-sigs.autosign" { + type primary; + file "expired-sigs.autosign.db"; + inline-signing yes; + dnssec-policy "autosign"; +}; + +/* + * Zone that has valid, fresh signatures. + */ +zone "fresh-sigs.autosign" { + type primary; + file "fresh-sigs.autosign.db"; + inline-signing yes; + dnssec-policy "autosign"; +}; + +/* + * Zone that has unfresh signatures. + */ +zone "unfresh-sigs.autosign" { + type primary; + file "unfresh-sigs.autosign.db"; + inline-signing yes; + dnssec-policy "autosign"; +}; + +/* + * Zone that has missing private KSK. + */ +zone "ksk-missing.autosign" { + type primary; + file "ksk-missing.autosign.db"; + inline-signing yes; + dnssec-policy "autosign"; +}; + +/* + * Zone that has missing private ZSK. + */ +zone "zsk-missing.autosign" { + type primary; + file "zsk-missing.autosign.db"; + inline-signing yes; + dnssec-policy "autosign"; +}; + +/* + * Zone that has inactive ZSK. + */ +zone "zsk-retired.autosign" { + type primary; + file "zsk-retired.autosign.db"; + inline-signing yes; + dnssec-policy "autosign"; +}; + +/* + * Zones for testing enabling DNSSEC. + */ +zone "step1.enable-dnssec.autosign" { + type primary; + file "step1.enable-dnssec.autosign.db"; + inline-signing yes; + dnssec-policy "enable-dnssec"; +}; +zone "step2.enable-dnssec.autosign" { + type primary; + file "step2.enable-dnssec.autosign.db"; + inline-signing yes; + dnssec-policy "enable-dnssec"; +}; +zone "step3.enable-dnssec.autosign" { + type primary; + file "step3.enable-dnssec.autosign.db"; + inline-signing yes; + dnssec-policy "enable-dnssec"; +}; +zone "step4.enable-dnssec.autosign" { + type primary; + file "step4.enable-dnssec.autosign.db"; + inline-signing yes; + dnssec-policy "enable-dnssec"; +}; + +/* + * Zones for testing ZSK Pre-Publication steps. + */ +zone "step1.zsk-prepub.autosign" { + type primary; + file "step1.zsk-prepub.autosign.db"; + inline-signing yes; + dnssec-policy "zsk-prepub"; +}; +zone "step2.zsk-prepub.autosign" { + type primary; + file "step2.zsk-prepub.autosign.db"; + inline-signing yes; + dnssec-policy "zsk-prepub"; +}; +zone "step3.zsk-prepub.autosign" { + type primary; + file "step3.zsk-prepub.autosign.db"; + inline-signing yes; + dnssec-policy "zsk-prepub"; +}; +zone "step4.zsk-prepub.autosign" { + type primary; + file "step4.zsk-prepub.autosign.db"; + inline-signing yes; + dnssec-policy "zsk-prepub"; +}; +zone "step5.zsk-prepub.autosign" { + type primary; + file "step5.zsk-prepub.autosign.db"; + inline-signing yes; + dnssec-policy "zsk-prepub"; +}; +zone "step6.zsk-prepub.autosign" { + type primary; + file "step6.zsk-prepub.autosign.db"; + inline-signing yes; + dnssec-policy "zsk-prepub"; +}; + +/* + * Zones for testing KSK Double-KSK steps. + */ +zone "step1.ksk-doubleksk.autosign" { + type primary; + file "step1.ksk-doubleksk.autosign.db"; + inline-signing yes; + dnssec-policy "ksk-doubleksk"; +}; +zone "step2.ksk-doubleksk.autosign" { + type primary; + file "step2.ksk-doubleksk.autosign.db"; + inline-signing yes; + dnssec-policy "ksk-doubleksk"; +}; +zone "step3.ksk-doubleksk.autosign" { + type primary; + file "step3.ksk-doubleksk.autosign.db"; + inline-signing yes; + dnssec-policy "ksk-doubleksk"; +}; +zone "step4.ksk-doubleksk.autosign" { + type primary; + file "step4.ksk-doubleksk.autosign.db"; + inline-signing yes; + dnssec-policy "ksk-doubleksk"; +}; +zone "step5.ksk-doubleksk.autosign" { + type primary; + file "step5.ksk-doubleksk.autosign.db"; + inline-signing yes; + dnssec-policy "ksk-doubleksk"; +}; +zone "step6.ksk-doubleksk.autosign" { + type primary; + file "step6.ksk-doubleksk.autosign.db"; + inline-signing yes; + dnssec-policy "ksk-doubleksk"; +}; + +/* + * Zones for testing CSK rollover steps. + */ +zone "step1.csk-roll.autosign" { + type primary; + file "step1.csk-roll.autosign.db"; + inline-signing yes; + dnssec-policy "csk-roll"; +}; +zone "step2.csk-roll.autosign" { + type primary; + file "step2.csk-roll.autosign.db"; + inline-signing yes; + dnssec-policy "csk-roll"; +}; +zone "step3.csk-roll.autosign" { + type primary; + file "step3.csk-roll.autosign.db"; + inline-signing yes; + dnssec-policy "csk-roll"; +}; +zone "step4.csk-roll.autosign" { + type primary; + file "step4.csk-roll.autosign.db"; + inline-signing yes; + dnssec-policy "csk-roll"; +}; +zone "step5.csk-roll.autosign" { + type primary; + file "step5.csk-roll.autosign.db"; + inline-signing yes; + dnssec-policy "csk-roll"; +}; +zone "step6.csk-roll.autosign" { + type primary; + file "step6.csk-roll.autosign.db"; + inline-signing yes; + dnssec-policy "csk-roll"; +}; +zone "step7.csk-roll.autosign" { + type primary; + file "step7.csk-roll.autosign.db"; + inline-signing yes; + dnssec-policy "csk-roll"; +}; +zone "step8.csk-roll.autosign" { + type primary; + file "step8.csk-roll.autosign.db"; + inline-signing yes; + dnssec-policy "csk-roll"; +}; + +zone "step1.csk-roll2.autosign" { + type primary; + file "step1.csk-roll2.autosign.db"; + inline-signing yes; + dnssec-policy "csk-roll2"; +}; +zone "step2.csk-roll2.autosign" { + type primary; + file "step2.csk-roll2.autosign.db"; + inline-signing yes; + dnssec-policy "csk-roll2"; +}; +zone "step3.csk-roll2.autosign" { + type primary; + file "step3.csk-roll2.autosign.db"; + inline-signing yes; + dnssec-policy "csk-roll2"; +}; +zone "step4.csk-roll2.autosign" { + type primary; + file "step4.csk-roll2.autosign.db"; + inline-signing yes; + dnssec-policy "csk-roll2"; +}; +zone "step5.csk-roll2.autosign" { + type primary; + file "step5.csk-roll2.autosign.db"; + inline-signing yes; + dnssec-policy "csk-roll2"; +}; +zone "step6.csk-roll2.autosign" { + type primary; + file "step6.csk-roll2.autosign.db"; + inline-signing yes; + dnssec-policy "csk-roll2"; +}; +zone "step7.csk-roll2.autosign" { + type primary; + file "step7.csk-roll2.autosign.db"; + inline-signing yes; + dnssec-policy "csk-roll2"; +}; 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 0000000..92e007d --- /dev/null +++ b/bin/tests/system/kasp/ns3/named.conf.in @@ -0,0 +1,30 @@ +/* + * 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. + */ + +// NS3 + +include "named-fips.conf"; + +zone "rsasha1.kasp" { + type primary; + file "rsasha1.kasp.db"; + inline-signing yes; + dnssec-policy "rsasha1"; +}; + +zone "rsasha1-nsec3.kasp" { + type primary; + file "rsasha1-nsec3.kasp.db"; + inline-signing yes; + dnssec-policy "rsasha1-nsec3"; +}; diff --git a/bin/tests/system/kasp/ns3/policies/autosign.conf.in b/bin/tests/system/kasp/ns3/policies/autosign.conf.in new file mode 100644 index 0000000..5564ec5 --- /dev/null +++ b/bin/tests/system/kasp/ns3/policies/autosign.conf.in @@ -0,0 +1,133 @@ +/* + * 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. + */ + +dnssec-policy "autosign" { + + signatures-refresh P1W; + signatures-validity P2W; + signatures-validity-dnskey P2W; + + dnskey-ttl 300; + + keys { + ksk key-directory lifetime P2Y algorithm @DEFAULT_ALGORITHM@; + zsk key-directory lifetime P1Y algorithm @DEFAULT_ALGORITHM@; + }; +}; + +dnssec-policy "enable-dnssec" { + + signatures-refresh P1W; + signatures-validity P2W; + signatures-validity-dnskey P2W; + + dnskey-ttl 300; + max-zone-ttl PT12H; + zone-propagation-delay PT5M; + retire-safety PT20M; + publish-safety PT5M; + + parent-propagation-delay 1h; + parent-ds-ttl 2h; + + keys { + csk lifetime unlimited algorithm @DEFAULT_ALGORITHM_NUMBER@; + }; +}; + +dnssec-policy "zsk-prepub" { + + signatures-refresh P1W; + signatures-validity P2W; + signatures-validity-dnskey P2W; + + dnskey-ttl 3600; + publish-safety P1D; + retire-safety P2D; + purge-keys PT1H; + + keys { + ksk key-directory lifetime P2Y algorithm @DEFAULT_ALGORITHM@; + zsk key-directory lifetime P30D algorithm @DEFAULT_ALGORITHM@; + }; + + zone-propagation-delay PT1H; + max-zone-ttl 1d; +}; + +dnssec-policy "ksk-doubleksk" { + + signatures-refresh P1W; + signatures-validity P2W; + signatures-validity-dnskey P2W; + + dnskey-ttl 2h; + publish-safety P1D; + retire-safety P2D; + purge-keys PT1H; + + keys { + ksk key-directory lifetime P60D algorithm @DEFAULT_ALGORITHM@; + zsk key-directory lifetime P1Y algorithm @DEFAULT_ALGORITHM@; + }; + + zone-propagation-delay PT1H; + max-zone-ttl 1d; + + parent-ds-ttl 3600; + parent-propagation-delay PT1H; +}; + +dnssec-policy "csk-roll" { + + signatures-refresh P5D; + signatures-validity 30d; + signatures-validity-dnskey 30d; + + dnskey-ttl 1h; + publish-safety PT1H; + retire-safety 2h; + purge-keys PT1H; + + keys { + csk key-directory lifetime P6M algorithm @DEFAULT_ALGORITHM@; + }; + + zone-propagation-delay 1h; + max-zone-ttl P1D; + + parent-ds-ttl 1h; + parent-propagation-delay 1h; +}; + +dnssec-policy "csk-roll2" { + + signatures-refresh 12h; + signatures-validity P1D; + signatures-validity-dnskey P1D; + + dnskey-ttl 1h; + publish-safety PT1H; + retire-safety 1h; + purge-keys 0; + + keys { + csk key-directory lifetime P6M algorithm @DEFAULT_ALGORITHM@; + }; + + zone-propagation-delay PT1H; + max-zone-ttl 1d; + + parent-ds-ttl PT1H; + parent-propagation-delay P1W; +}; diff --git a/bin/tests/system/kasp/ns3/policies/kasp-fips.conf.in b/bin/tests/system/kasp/ns3/policies/kasp-fips.conf.in new file mode 100644 index 0000000..90a92a2 --- /dev/null +++ b/bin/tests/system/kasp/ns3/policies/kasp-fips.conf.in @@ -0,0 +1,118 @@ +/* + * 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. + */ + +dnssec-policy "unlimited" { + dnskey-ttl 1234; + + keys { + csk key-directory lifetime unlimited algorithm @DEFAULT_ALGORITHM@; + }; +}; + +dnssec-policy "manual-rollover" { + dnskey-ttl 3600; + + keys { + ksk key-directory lifetime unlimited algorithm @DEFAULT_ALGORITHM@; + zsk key-directory lifetime unlimited algorithm @DEFAULT_ALGORITHM@; + }; +}; + +dnssec-policy "multisigner-model2" { + dnskey-ttl 3600; + + keys { + ksk key-directory lifetime unlimited algorithm @DEFAULT_ALGORITHM@; + zsk key-directory lifetime unlimited algorithm @DEFAULT_ALGORITHM@; + }; +}; + +dnssec-policy "migrate-to-dnssec-policy" { + dnskey-ttl 1234; + + keys { + ksk key-directory lifetime P6M algorithm 8; + zsk key-directory lifetime P6M algorithm 8; + }; +}; + +dnssec-policy "rsasha256" { + dnskey-ttl 1234; + + keys { + ksk key-directory lifetime P10Y algorithm 8; + zsk key-directory lifetime P5Y algorithm 8; + zsk key-directory lifetime P1Y algorithm 8 3072; + }; +}; + +dnssec-policy "rsasha512" { + dnskey-ttl 1234; + + keys { + ksk key-directory lifetime P10Y algorithm 10; + zsk key-directory lifetime P5Y algorithm 10; + zsk key-directory lifetime P1Y algorithm 10 3072; + }; +}; + +dnssec-policy "ecdsa256" { + dnskey-ttl 1234; + + keys { + ksk key-directory lifetime P10Y algorithm 13; + zsk key-directory lifetime P5Y algorithm 13; + zsk key-directory lifetime P1Y algorithm 13 256; + }; +}; + +dnssec-policy "ecdsa384" { + dnskey-ttl 1234; + + keys { + ksk key-directory lifetime P10Y algorithm 14; + zsk key-directory lifetime P5Y algorithm 14; + zsk key-directory lifetime P1Y algorithm 14 384; + }; +}; + +dnssec-policy "checkds-ksk" { + dnskey-ttl 303; + + keys { + ksk key-directory lifetime unlimited algorithm @DEFAULT_ALGORITHM@; + zsk key-directory lifetime unlimited algorithm @DEFAULT_ALGORITHM@; + }; +}; + +dnssec-policy "checkds-doubleksk" { + dnskey-ttl 303; + + keys { + ksk key-directory lifetime unlimited algorithm @DEFAULT_ALGORITHM@; + ksk key-directory lifetime unlimited algorithm @DEFAULT_ALGORITHM@; + zsk key-directory lifetime unlimited algorithm @DEFAULT_ALGORITHM@; + }; +}; + +dnssec-policy "checkds-csk" { + dnskey-ttl 303; + + keys { + csk key-directory lifetime unlimited algorithm @DEFAULT_ALGORITHM@; + }; +}; + +dnssec-policy "ttl" { + max-zone-ttl 299; +}; diff --git a/bin/tests/system/kasp/ns3/policies/kasp.conf.in b/bin/tests/system/kasp/ns3/policies/kasp.conf.in new file mode 100644 index 0000000..cb045bc --- /dev/null +++ b/bin/tests/system/kasp/ns3/policies/kasp.conf.in @@ -0,0 +1,34 @@ +/* + * 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. + */ + +include "policies/kasp-fips.conf"; + +dnssec-policy "rsasha1" { + dnskey-ttl 1234; + + keys { + ksk key-directory lifetime P10Y algorithm 5; + zsk key-directory lifetime P5Y algorithm 5; + zsk key-directory lifetime P1Y algorithm 5 2000; + }; +}; + +dnssec-policy "rsasha1-nsec3" { + dnskey-ttl 1234; + + keys { + ksk key-directory lifetime P10Y algorithm 7; + zsk key-directory lifetime P5Y algorithm 7; + zsk key-directory lifetime P1Y algorithm 7 2000; + }; +}; diff --git a/bin/tests/system/kasp/ns3/setup.sh b/bin/tests/system/kasp/ns3/setup.sh new file mode 100644 index 0000000..8682f54 --- /dev/null +++ b/bin/tests/system/kasp/ns3/setup.sh @@ -0,0 +1,1470 @@ +#!/bin/sh -e + +# 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. + +# 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 in the key state files the Predecessor/Successor fields. +# Key $1 is the predecessor of key $2. +key_successor() { + id1=$(keyfile_to_key_id "$1") + id2=$(keyfile_to_key_id "$2") + echo "Predecessor: ${id1}" >> "${2}.state" + echo "Successor: ${id2}" >> "${1}.state" +} + +# Make lines shorter by storing key states in environment variables. +H="HIDDEN" +R="RUMOURED" +O="OMNIPRESENT" +U="UNRETENTIVE" + +# +# Set up zones that will be initially signed. +# +for zn in default dnssec-keygen some-keys legacy-keys pregenerated \ + rumoured rsasha256 rsasha512 ecdsa256 ecdsa384 \ + dynamic dynamic-inline-signing inline-signing \ + checkds-ksk checkds-doubleksk checkds-csk inherit unlimited \ + manual-rollover multisigner-model2 +do + setup "${zn}.kasp" + cp template.db.in "$zonefile" +done + +# +# Set up RSASHA1 based zones +# +for zn in rsasha1 rsasha1-nsec3 +do + if (cd ..; $SHELL ../testcrypto.sh -q RSASHA1) + then + setup "${zn}.kasp" + cp template.db.in "$zonefile" + else + # don't add to zones. + echo_i "setting up zone: ${zn}.kasp" + cp template.db.in "${zn}.kasp.db" + fi +done + +if [ -f ../ed25519-supported.file ]; then + setup "ed25519.kasp" + cp template.db.in "$zonefile" + cat ed25519.conf >> named.conf +fi + +if [ -f ../ed448-supported.file ]; then + setup "ed448.kasp" + cp template.db.in "$zonefile" + cat ed448.conf >> named.conf +fi + +# Set up zones that stay unsigned. +for zn in unsigned insecure max-zone-ttl +do + zone="${zn}.kasp" + echo_i "setting up zone: $zone" + zonefile="${zone}.db" + infile="${zone}.db.infile" + cp template.db.in $infile + cp template.db.in $zonefile +done + +# Some of these zones already have keys. +zone="dnssec-keygen.kasp" +echo_i "setting up zone: $zone" +$KEYGEN -k rsasha256 -l policies/kasp.conf $zone > keygen.out.$zone.1 2>&1 + +zone="some-keys.kasp" +echo_i "setting up zone: $zone" +$KEYGEN -G -a RSASHA256 -b 2048 -L 1234 $zone > keygen.out.$zone.1 2>&1 +$KEYGEN -G -a RSASHA256 -f KSK -L 1234 $zone > keygen.out.$zone.2 2>&1 + +zone="legacy-keys.kasp" +echo_i "setting up zone: $zone" +ZSK=$($KEYGEN -a RSASHA256 -b 2048 -L 1234 $zone 2> keygen.out.$zone.1) +KSK=$($KEYGEN -a RSASHA256 -f KSK -L 1234 $zone 2> keygen.out.$zone.2) +echo $ZSK > legacy-keys.kasp.zsk +echo $KSK > legacy-keys.kasp.ksk +# Predecessor keys: +Tact="now-9mo" +Tret="now-3mo" +ZSK=$($KEYGEN -a RSASHA256 -b 2048 -L 1234 $zone 2> keygen.out.$zone.3) +KSK=$($KEYGEN -a RSASHA256 -f KSK -L 1234 $zone 2> keygen.out.$zone.4) +$SETTIME -P $Tact -A $Tact -I $Tret -D $Tret "$ZSK" > settime.out.$zone.1 2>&1 +$SETTIME -P $Tact -A $Tact -I $Tret -D $Tret "$KSK" > settime.out.$zone.2 2>&1 + +zone="pregenerated.kasp" +echo_i "setting up zone: $zone" +$KEYGEN -G -k rsasha256 -l policies/kasp.conf $zone > keygen.out.$zone.1 2>&1 +$KEYGEN -G -k rsasha256 -l policies/kasp.conf $zone > keygen.out.$zone.2 2>&1 + +zone="multisigner-model2.kasp" +echo_i "setting up zone: $zone" +# Import the ZSK sets of the other providers into their DNSKEY RRset. +ZSK1=$($KEYGEN -K ../ -a $DEFAULT_ALGORITHM -L 3600 $zone 2> keygen.out.$zone.1) +ZSK2=$($KEYGEN -K ../ -a $DEFAULT_ALGORITHM -L 3600 $zone 2> keygen.out.$zone.2) +# ZSK1 will be added to the unsigned zonefile. +cat "../${ZSK1}.key" | grep -v ";.*" >> "${zone}.db" +cat "../${ZSK1}.key" | grep -v ";.*" > "${zone}.zsk1" +rm -f "../${ZSK1}.*" +# ZSK2 will be used with a Dynamic Update. +cat "../${ZSK2}.key" | grep -v ";.*" > "${zone}.zsk2" +rm -f "../${ZSK2}.*" + +zone="rumoured.kasp" +echo_i "setting up zone: $zone" +Tpub="now" +Tact="now+1d" +keytimes="-P ${Tpub} -A ${Tact}" +KSK=$($KEYGEN -a RSASHA256 -f KSK -L 1234 $keytimes $zone 2> keygen.out.$zone.1) +ZSK1=$($KEYGEN -a RSASHA256 -b 3072 -L 1234 $keytimes $zone 2> keygen.out.$zone.2) +ZSK2=$($KEYGEN -a RSASHA256 -L 1234 $keytimes $zone 2> keygen.out.$zone.3) +$SETTIME -s -g $O -k $R $Tpub -r $R $Tpub -d $H $Tpub "$KSK" > settime.out.$zone.1 2>&1 +$SETTIME -s -g $O -k $R $Tpub -z $R $Tpub "$ZSK1" > settime.out.$zone.2 2>&1 +$SETTIME -s -g $O -k $R $Tpub -z $R $Tpub "$ZSK2" > settime.out.$zone.2 2>&1 + +# +# Set up zones that are already signed. +# + +# Zone to test manual rollover. +setup manual-rollover.kasp +T="now-1d" +ksktimes="-P $T -A $T -P sync $T" +zsktimes="-P $T -A $T" +KSK=$($KEYGEN -a $DEFAULT_ALGORITHM -L 3600 -f KSK $ksktimes $zone 2> keygen.out.$zone.1) +ZSK=$($KEYGEN -a $DEFAULT_ALGORITHM -L 3600 $zsktimes $zone 2> keygen.out.$zone.2) +$SETTIME -s -g $O -d $O $T -k $O $T -r $O $T "$KSK" > settime.out.$zone.1 2>&1 +$SETTIME -s -g $O -k $O $T -z $O $T "$ZSK" > settime.out.$zone.2 2>&1 +cat template.db.in "${KSK}.key" "${ZSK}.key" > "$infile" +private_type_record $zone $DEFAULT_ALGORITHM_NUMBER "$KSK" >> "$infile" +private_type_record $zone $DEFAULT_ALGORITHM_NUMBER "$ZSK" >> "$infile" +cp $infile $zonefile +$SIGNER -PS -x -o $zone -O raw -f "${zonefile}.signed" $infile > signer.out.$zone.1 2>&1 + +# These signatures are set to expire long in the past, update immediately. +setup expired-sigs.autosign +T="now-6mo" +ksktimes="-P $T -A $T -P sync $T" +zsktimes="-P $T -A $T" +KSK=$($KEYGEN -a $DEFAULT_ALGORITHM -L 300 -f KSK $ksktimes $zone 2> keygen.out.$zone.1) +ZSK=$($KEYGEN -a $DEFAULT_ALGORITHM -L 300 $zsktimes $zone 2> keygen.out.$zone.2) +$SETTIME -s -g $O -d $O $T -k $O $T -r $O $T "$KSK" > settime.out.$zone.1 2>&1 +$SETTIME -s -g $O -k $O $T -z $O $T "$ZSK" > settime.out.$zone.2 2>&1 +cat template.db.in "${KSK}.key" "${ZSK}.key" > "$infile" +private_type_record $zone $DEFAULT_ALGORITHM_NUMBER "$KSK" >> "$infile" +private_type_record $zone $DEFAULT_ALGORITHM_NUMBER "$ZSK" >> "$infile" +cp $infile $zonefile +$SIGNER -PS -x -s now-2mo -e now-1mo -o $zone -O raw -f "${zonefile}.signed" $infile > signer.out.$zone.1 2>&1 + +# These signatures are still good, and can be reused. +setup fresh-sigs.autosign +T="now-6mo" +ksktimes="-P $T -A $T -P sync $T" +zsktimes="-P $T -A $T" +KSK=$($KEYGEN -a $DEFAULT_ALGORITHM -L 300 -f KSK $ksktimes $zone 2> keygen.out.$zone.1) +ZSK=$($KEYGEN -a $DEFAULT_ALGORITHM -L 300 $zsktimes $zone 2> keygen.out.$zone.2) +$SETTIME -s -g $O -d $O $T -k $O $T -r $O $T "$KSK" > settime.out.$zone.1 2>&1 +$SETTIME -s -g $O -k $O $T -z $O $T "$ZSK" > settime.out.$zone.2 2>&1 +cat template.db.in "${KSK}.key" "${ZSK}.key" > "$infile" +private_type_record $zone $DEFAULT_ALGORITHM_NUMBER "$KSK" >> "$infile" +private_type_record $zone $DEFAULT_ALGORITHM_NUMBER "$ZSK" >> "$infile" +cp $infile $zonefile +$SIGNER -S -x -s now-1h -e now+2w -o $zone -O raw -f "${zonefile}.signed" $infile > signer.out.$zone.1 2>&1 + +# These signatures are still good, but not fresh enough, update immediately. +setup unfresh-sigs.autosign +T="now-6mo" +ksktimes="-P $T -A $T -P sync $T" +zsktimes="-P $T -A $T" +KSK=$($KEYGEN -a $DEFAULT_ALGORITHM -L 300 -f KSK $ksktimes $zone 2> keygen.out.$zone.1) +ZSK=$($KEYGEN -a $DEFAULT_ALGORITHM -L 300 $zsktimes $zone 2> keygen.out.$zone.2) +$SETTIME -s -g $O -d $O $T -k $O $T -r $O $T "$KSK" > settime.out.$zone.1 2>&1 +$SETTIME -s -g $O -k $O $T -z $O $T "$ZSK" > settime.out.$zone.2 2>&1 +cat template.db.in "${KSK}.key" "${ZSK}.key" > "$infile" +private_type_record $zone $DEFAULT_ALGORITHM_NUMBER "$KSK" >> "$infile" +private_type_record $zone $DEFAULT_ALGORITHM_NUMBER "$ZSK" >> "$infile" +cp $infile $zonefile +$SIGNER -S -x -s now-1w -e now+1w -o $zone -O raw -f "${zonefile}.signed" $infile > signer.out.$zone.1 2>&1 + +# These signatures are still good, but the private KSK is missing. +setup ksk-missing.autosign +T="now-6mo" +ksktimes="-P $T -A $T -P sync $T" +zsktimes="-P $T -A $T" +KSK=$($KEYGEN -a $DEFAULT_ALGORITHM -L 300 -f KSK $ksktimes $zone 2> keygen.out.$zone.1) +ZSK=$($KEYGEN -a $DEFAULT_ALGORITHM -L 300 $zsktimes $zone 2> keygen.out.$zone.2) +$SETTIME -s -g $O -d $O $T -k $O $T -r $O $T "$KSK" > settime.out.$zone.1 2>&1 +$SETTIME -s -g $O -k $O $T -z $O $T "$ZSK" > settime.out.$zone.2 2>&1 +cat template.db.in "${KSK}.key" "${ZSK}.key" > "$infile" +private_type_record $zone $DEFAULT_ALGORITHM_NUMBER "$KSK" >> "$infile" +private_type_record $zone $DEFAULT_ALGORITHM_NUMBER "$ZSK" >> "$infile" +cp $infile $zonefile +$SIGNER -S -x -s now-1w -e now+1w -o $zone -O raw -f "${zonefile}.signed" $infile > signer.out.$zone.1 2>&1 +echo "KSK: yes" >> "${KSK}".state +echo "ZSK: no" >> "${KSK}".state +echo "Lifetime: 63072000" >> "${KSK}".state # PT2Y +rm -f "${KSK}".private + +# These signatures are still good, but the private ZSK is missing. +setup zsk-missing.autosign +T="now-6mo" +ksktimes="-P $T -A $T -P sync $T" +zsktimes="-P $T -A $T" +KSK=$($KEYGEN -a $DEFAULT_ALGORITHM -L 300 -f KSK $ksktimes $zone 2> keygen.out.$zone.1) +ZSK=$($KEYGEN -a $DEFAULT_ALGORITHM -L 300 $zsktimes $zone 2> keygen.out.$zone.2) +$SETTIME -s -g $O -d $O $T -k $O $T -r $O $T "$KSK" > settime.out.$zone.1 2>&1 +$SETTIME -s -g $O -k $O $T -z $O $T "$ZSK" > settime.out.$zone.2 2>&1 +cat template.db.in "${KSK}.key" "${ZSK}.key" > "$infile" +private_type_record $zone $DEFAULT_ALGORITHM_NUMBER "$KSK" >> "$infile" +private_type_record $zone $DEFAULT_ALGORITHM_NUMBER "$ZSK" >> "$infile" +cp $infile $zonefile +$SIGNER -S -x -s now-1w -e now+1w -o $zone -O raw -f "${zonefile}.signed" $infile > signer.out.$zone.1 2>&1 +echo "KSK: no" >> "${ZSK}".state +echo "ZSK: yes" >> "${ZSK}".state +echo "Lifetime: 31536000" >> "${ZSK}".state # PT1Y +rm -f "${ZSK}".private + +# These signatures are already expired, and the private ZSK is retired. +setup zsk-retired.autosign +T="now-6mo" +ksktimes="-P $T -A $T -P sync $T" +zsktimes="-P $T -A $T -I now" +KSK=$($KEYGEN -a $DEFAULT_ALGORITHM -L 300 -f KSK $ksktimes $zone 2> keygen.out.$zone.1) +ZSK=$($KEYGEN -a $DEFAULT_ALGORITHM -L 300 $zsktimes $zone 2> keygen.out.$zone.2) +$SETTIME -s -g $O -d $O $T -k $O $T -r $O $T "$KSK" > settime.out.$zone.1 2>&1 +$SETTIME -s -g $O -k $O $T -z $O $T "$ZSK" > settime.out.$zone.2 2>&1 +cat template.db.in "${KSK}.key" "${ZSK}.key" > "$infile" +private_type_record $zone $DEFAULT_ALGORITHM_NUMBER "$KSK" >> "$infile" +private_type_record $zone $DEFAULT_ALGORITHM_NUMBER "$ZSK" >> "$infile" +cp $infile $zonefile +$SIGNER -PS -x -s now-2w -e now-1mi -o $zone -O raw -f "${zonefile}.signed" $infile > signer.out.$zone.1 2>&1 +$SETTIME -s -g HIDDEN "$ZSK" > settime.out.$zone.3 2>&1 + +# +# The zones at enable-dnssec.autosign represent the various steps of the +# initial signing of a zone. +# + +# Step 1: +# This is an unsigned zone and named should perform the initial steps of +# introducing the DNSSEC records in the right order. +setup step1.enable-dnssec.autosign +cp template.db.in $zonefile + +# Step 2: +# The DNSKEY has been published long enough to become OMNIPRESENT. +setup step2.enable-dnssec.autosign +# DNSKEY TTL: 300 seconds +# zone-propagation-delay: 5 minutes (300 seconds) +# publish-safety: 5 minutes (300 seconds) +# Total: 900 seconds +TpubN="now-900s" +# RRSIG TTL: 12 hour (43200 seconds) +# zone-propagation-delay: 5 minutes (300 seconds) +# retire-safety: 20 minutes (1200 seconds) +# Already passed time: -900 seconds +# Total: 43800 seconds +TsbmN="now+43800s" +keytimes="-P ${TpubN} -P sync ${TsbmN} -A ${TpubN}" +CSK=$($KEYGEN -k enable-dnssec -l policies/autosign.conf $keytimes $zone 2> keygen.out.$zone.1) +$SETTIME -s -g $O -k $R $TpubN -r $R $TpubN -d $H $TpubN -z $R $TpubN "$CSK" > settime.out.$zone.1 2>&1 +cat template.db.in "${CSK}.key" > "$infile" +private_type_record $zone $DEFAULT_ALGORITHM_NUMBER "$CSK" >> "$infile" +cp $infile $zonefile +$SIGNER -S -z -x -s now-1h -e now+30d -o $zone -O raw -f "${zonefile}.signed" $infile > signer.out.$zone.1 2>&1 + +# Step 3: +# The zone signatures have been published long enough to become OMNIPRESENT. +setup step3.enable-dnssec.autosign +# Passed time since publications: 43800 + 900 = 44700 seconds. +TpubN="now-44700s" +# The key is secure for using in chain of trust when the DNSKEY is OMNIPRESENT. +TcotN="now-43800s" +# We can submit the DS now. +TsbmN="now" +keytimes="-P ${TpubN} -P sync ${TsbmN} -A ${TpubN}" +CSK=$($KEYGEN -k enable-dnssec -l policies/autosign.conf $keytimes $zone 2> keygen.out.$zone.1) +$SETTIME -s -g $O -k $O $TcotN -r $O $TcotN -d $H $TpubN -z $R $TpubN "$CSK" > settime.out.$zone.1 2>&1 +cat template.db.in "${CSK}.key" > "$infile" +private_type_record $zone $DEFAULT_ALGORITHM_NUMBER "$CSK" >> "$infile" +cp $infile $zonefile +$SIGNER -S -z -x -s now-1h -e now+30d -o $zone -O raw -f "${zonefile}.signed" $infile > signer.out.$zone.1 2>&1 + +# Step 4: +# The DS has been submitted long enough ago to become OMNIPRESENT. +setup step4.enable-dnssec.autosign +# DS TTL: 2 hour (7200 seconds) +# parent-propagation-delay: 1 hour (3600 seconds) +# retire-safety: 20 minutes (1200 seconds) +# Total aditional time: 12000 seconds +# 44700 + 12000 = 56700 +TpubN="now-56700s" +# 43800 + 12000 = 55800 +TcotN="now-55800s" +TsbmN="now-12000s" +keytimes="-P ${TpubN} -P sync ${TsbmN} -A ${TpubN}" +CSK=$($KEYGEN -k enable-dnssec -l policies/autosign.conf $keytimes $zone 2> keygen.out.$zone.1) +$SETTIME -s -g $O -P ds $TsbmN -k $O $TcotN -r $O $TcotN -d $R $TsbmN -z $O $TsbmN "$CSK" > settime.out.$zone.1 2>&1 +cat template.db.in "${CSK}.key" > "$infile" +private_type_record $zone $DEFAULT_ALGORITHM_NUMBER "$CSK" >> "$infile" +cp $infile $zonefile +$SIGNER -S -z -x -s now-1h -e now+30d -o $zone -O raw -f "${zonefile}.signed" $infile > signer.out.$zone.1 2>&1 +setup step4.enable-dnssec.autosign + +# +# The zones at zsk-prepub.autosign represent the various steps of a ZSK +# Pre-Publication rollover. +# + +# Step 1: +# Introduce the first key. This will immediately be active. +setup step1.zsk-prepub.autosign +TactN="now" +ksktimes="-P ${TactN} -A ${TactN} -P sync ${TactN}" +zsktimes="-P ${TactN} -A ${TactN}" +KSK=$($KEYGEN -a $DEFAULT_ALGORITHM -L 3600 -f KSK $ksktimes $zone 2> keygen.out.$zone.1) +ZSK=$($KEYGEN -a $DEFAULT_ALGORITHM -L 3600 $zsktimes $zone 2> keygen.out.$zone.2) +$SETTIME -s -g $O -k $O $TactN -r $O $TactN -d $O $TactN "$KSK" > settime.out.$zone.1 2>&1 +$SETTIME -s -g $O -k $O $TactN -z $O $TactN "$ZSK" > settime.out.$zone.2 2>&1 +cat template.db.in "${KSK}.key" "${ZSK}.key" > "$infile" +private_type_record $zone $DEFAULT_ALGORITHM_NUMBER "$KSK" >> "$infile" +private_type_record $zone $DEFAULT_ALGORITHM_NUMBER "$ZSK" >> "$infile" +cp $infile $zonefile +$SIGNER -S -x -s now-1h -e now+2w -o $zone -O raw -f "${zonefile}.signed" $infile > signer.out.$zone.1 2>&1 + +# Step 2: +# It is time to pre-publish the successor ZSK. +setup step2.zsk-prepub.autosign +# According to RFC 7583: +# +# Tpub(N+1) <= Tact(N) + Lzsk - Ipub +# Ipub = Dprp + TTLkey (+publish-safety) +# +# |3| |4| |5| |6| +# | | | | +# Key N |<-------Lzsk------>| +# | | | | +# Key N+1 | |<-Ipub->|<-->| +# | | | | +# Key N Tact +# Key N+1 Tpub Trdy Tact +# +# Tnow +# +# Lzsk: 30d +# Dprp: 1h +# TTLkey: 1h +# publish-safety: 1d +# Ipub: 26h +# +# Tact(N) = Tnow + Ipub - Lzsk = now + 26h - 30d +# = now + 26h - 30d = now − 694h +TactN="now-694h" +ksktimes="-P ${TactN} -A ${TactN} -P sync ${TactN}" +zsktimes="-P ${TactN} -A ${TactN}" +KSK=$($KEYGEN -a $DEFAULT_ALGORITHM -L 3600 -f KSK $ksktimes $zone 2> keygen.out.$zone.1) +ZSK=$($KEYGEN -a $DEFAULT_ALGORITHM -L 3600 $zsktimes $zone 2> keygen.out.$zone.2) +$SETTIME -s -g $O -k $O $TactN -r $O $TactN -d $O $TactN "$KSK" > settime.out.$zone.1 2>&1 +$SETTIME -s -g $O -k $O $TactN -z $O $TactN "$ZSK" > settime.out.$zone.2 2>&1 +cat template.db.in "${KSK}.key" "${ZSK}.key" > "$infile" +private_type_record $zone $DEFAULT_ALGORITHM_NUMBER "$KSK" >> "$infile" +private_type_record $zone $DEFAULT_ALGORITHM_NUMBER "$ZSK" >> "$infile" +cp $infile $zonefile +$SIGNER -S -x -s now-1h -e now+2w -o $zone -O raw -f "${zonefile}.signed" $infile > signer.out.$zone.1 2>&1 + +# Step 3: +# After the publication interval has passed the DNSKEY of the successor ZSK +# is OMNIPRESENT and the zone can thus be signed with the successor ZSK. +setup step3.zsk-prepub.autosign +# According to RFC 7583: +# +# Tpub(N+1) <= Tact(N) + Lzsk - Ipub +# Tret(N) = Tact(N+1) = Tact(N) + Lzsk +# Trem(N) = Tret(N) + Iret +# Iret = Dsgn + Dprp + TTLsig (+retire-safety) +# +# |3| |4| |5| |6| |7| |8| +# | | | | | | +# Key N |<-------Lzsk------>|<-Iret->|<--->| +# | | | | | | +# Key N+1 | |<-Ipub->|<-->|<---Lzsk---- - - +# | | | | | | +# Key N Tact Tret Tdea Trem +# Key N+1 Tpub Trdy Tact +# +# Tnow +# +# Lzsk: 30d +# Ipub: 26h +# Dsgn: 1w +# Dprp: 1h +# TTLsig: 1d +# retire-safety: 2d +# Iret: 10d1h = 241h +# +# Tact(N) = Tnow - Lzsk = now - 30d +# Tret(N) = now +# Trem(N) = Tnow + Iret = now + 241h +# Tpub(N+1) = Tnow - Ipub = now - 26h +# Tret(N+1) = Tnow + Lzsk = now + 30d +# Trem(N+1) = Tnow + Lzsk + Iret = now + 30d + 241h +# = now + 961h +TactN="now-30d" +TretN="now" +TremN="now+241h" +TpubN1="now-26h" +TactN1="now" +TretN1="now+30d" +TremN1="now+961h" +ksktimes="-P ${TactN} -A ${TactN} -P sync ${TactN}" +zsktimes="-P ${TactN} -A ${TactN} -I ${TretN} -D ${TremN}" +newtimes="-P ${TpubN1} -A ${TactN1} -I ${TretN1} -D ${TremN1}" +KSK=$($KEYGEN -a $DEFAULT_ALGORITHM -L 3600 -f KSK $ksktimes $zone 2> keygen.out.$zone.1) +ZSK1=$($KEYGEN -a $DEFAULT_ALGORITHM -L 3600 $zsktimes $zone 2> keygen.out.$zone.2) +ZSK2=$($KEYGEN -a $DEFAULT_ALGORITHM -L 3600 $newtimes $zone 2> keygen.out.$zone.3) +$SETTIME -s -g $O -k $O $TactN -r $O $TactN -d $O $TactN "$KSK" > settime.out.$zone.1 2>&1 +$SETTIME -s -g $H -k $O $TactN -z $O $TactN "$ZSK1" > settime.out.$zone.2 2>&1 +$SETTIME -s -g $O -k $R $TpubN1 -z $H $TpubN1 "$ZSK2" > settime.out.$zone.3 2>&1 +# Set key rollover relationship. +key_successor $ZSK1 $ZSK2 +# Sign zone. +cat template.db.in "${KSK}.key" "${ZSK1}.key" "${ZSK2}.key" > "$infile" +private_type_record $zone $DEFAULT_ALGORITHM_NUMBER "$KSK" >> "$infile" +private_type_record $zone $DEFAULT_ALGORITHM_NUMBER "$ZSK1" >> "$infile" +private_type_record $zone $DEFAULT_ALGORITHM_NUMBER "$ZSK2" >> "$infile" +cp $infile $zonefile +$SIGNER -S -x -s now-1h -e now+2w -o $zone -O raw -f "${zonefile}.signed" $infile > signer.out.$zone.1 2>&1 + +# Step 4: +# After the retire interval has passed the predecessor DNSKEY can be +# removed from the zone. +setup step4.zsk-prepub.autosign +# According to RFC 7583: +# +# Tret(N) = Tact(N) + Lzsk +# Tdea(N) = Tret(N) + Iret +# +# |3| |4| |5| |6| |7| |8| +# | | | | | | +# Key N |<-------Lzsk------>|<-Iret->|<--->| +# | | | | | | +# Key N+1 | |<-Ipub->|<-->|<---Lzsk---- - - +# | | | | | | +# Key N Tact Tret Tdea Trem +# Key N+1 Tpub Trdy Tact +# +# Tnow +# +# Lzsk: 30d +# Ipub: 26h +# Iret: 241h +# +# Tact(N) = Tnow - Iret - Lzsk +# = now - 241h - 30d = now - 241h - 720h +# = now - 961h +# Tret(N) = Tnow - Iret = now - 241h +# Trem(N) = Tnow +# Tpub(N+1) = Tnow - Iret - Ipub +# = now - 241h - 26h +# = now - 267h +# Tact(N+1) = Tnow - Iret = Tret(N) +# Tret(N+1) = Tnow - Iret + Lzsk +# = now - 241h + 30d = now - 241h + 720h +# = now + 479h +# Trem(N+1) = Tnow + Lzsk = now + 30d +TactN="now-961h" +TretN="now-241h" +TremN="now" +TpubN1="now-267h" +TactN1="${TretN}" +TretN1="now+479h" +TremN1="now+30d" +ksktimes="-P ${TactN} -A ${TactN} -P sync ${TactN}" +zsktimes="-P ${TactN} -A ${TactN} -I ${TretN} -D ${TremN}" +newtimes="-P ${TpubN1} -A ${TactN1} -I ${TretN1} -D ${TremN1}" +KSK=$($KEYGEN -a $DEFAULT_ALGORITHM -L 3600 -f KSK $ksktimes $zone 2> keygen.out.$zone.1) +ZSK1=$($KEYGEN -a $DEFAULT_ALGORITHM -L 3600 $zsktimes $zone 2> keygen.out.$zone.2) +ZSK2=$($KEYGEN -a $DEFAULT_ALGORITHM -L 3600 $newtimes $zone 2> keygen.out.$zone.3) +$SETTIME -s -g $O -k $O $TactN -r $O $TactN -d $O $TactN "$KSK" > settime.out.$zone.1 2>&1 +$SETTIME -s -g $H -k $O $TactN -z $U $TretN "$ZSK1" > settime.out.$zone.2 2>&1 +$SETTIME -s -g $O -k $O $TactN1 -z $R $TactN1 "$ZSK2" > settime.out.$zone.3 2>&1 +# Set key rollover relationship. +key_successor $ZSK1 $ZSK2 +# Sign zone. +cat template.db.in "${KSK}.key" "${ZSK1}.key" "${ZSK2}.key" > "$infile" +cp $infile $zonefile +$SIGNER -PS -x -s now-2w -e now-1mi -o $zone -O raw -f "${zonefile}.signed" $infile > signer.out.$zone.1 2>&1 + +# Step 5: +# The predecessor DNSKEY is removed long enough that is has become HIDDEN. +setup step5.zsk-prepub.autosign +# Subtract DNSKEY TTL from all the times (1h). +# Tact(N) = now - 961h - 1h = now - 962h +# Tret(N) = now - 241h - 1h = now - 242h +# Tdea(N) = now - 2d - 1h = now - 49h +# Trem(N) = now - 1h +# Tpub(N+1) = now - 267h - 1h = now - 268h +# Tact(N+1) = Tret(N) +# Tret(N+1) = now + 479h - 1h = now + 478h +# Trem(N+1) = now + 30d - 1h = now + 719h +TactN="now-962h" +TretN="now-242h" +TremN="now-1h" +TdeaN="now-49h" +TpubN1="now-268h" +TactN1="${TretN}" +TretN1="now+478h" +TremN1="now+719h" +ksktimes="-P ${TactN} -A ${TactN} -P sync ${TactN}" +zsktimes="-P ${TactN} -A ${TactN} -I ${TretN} -D ${TremN}" +newtimes="-P ${TpubN1} -A ${TactN1} -I ${TretN1} -D ${TremN1}" +KSK=$($KEYGEN -a $DEFAULT_ALGORITHM -L 3600 -f KSK $ksktimes $zone 2> keygen.out.$zone.1) +ZSK1=$($KEYGEN -a $DEFAULT_ALGORITHM -L 3600 $zsktimes $zone 2> keygen.out.$zone.2) +ZSK2=$($KEYGEN -a $DEFAULT_ALGORITHM -L 3600 $newtimes $zone 2> keygen.out.$zone.3) +$SETTIME -s -g $O -k $O $TactN -r $O $TactN -d $O $TactN "$KSK" > settime.out.$zone.1 2>&1 +$SETTIME -s -g $H -k $U $TdeaN -z $H $TdeaN "$ZSK1" > settime.out.$zone.2 2>&1 +$SETTIME -s -g $O -k $O $TactN1 -z $O $TdeaN "$ZSK2" > settime.out.$zone.3 2>&1 +# Set key rollover relationship. +key_successor $ZSK1 $ZSK2 +# Sign zone. +cat template.db.in "${KSK}.key" "${ZSK1}.key" "${ZSK2}.key" > "$infile" +private_type_record $zone $DEFAULT_ALGORITHM_NUMBER "$KSK" >> "$infile" +private_type_record $zone $DEFAULT_ALGORITHM_NUMBER "$ZSK1" >> "$infile" +private_type_record $zone $DEFAULT_ALGORITHM_NUMBER "$ZSK2" >> "$infile" +cp $infile $zonefile +$SIGNER -S -x -s now-1h -e now+2w -o $zone -O raw -f "${zonefile}.signed" $infile > signer.out.$zone.1 2>&1 + +# Step 6: +# The predecessor DNSKEY can be purged. +setup step6.zsk-prepub.autosign +# Subtract purge-keys interval from all the times (1h). +# Tact(N) = now - 962h - 1h = now - 963h +# Tret(N) = now - 242h - 1h = now - 243h +# Tdea(N) = now - 49h - 1h = now - 50h +# Trem(N) = now - 1h - 1h = now - 2h +# Tpub(N+1) = now - 268h - 1h = now - 269h +# Tact(N+1) = Tret(N) +# Tret(N+1) = now + 478h - 1h = now + 477h +# Trem(N+1) = now + 719h - 1h = now + 718h +TactN="now-963h" +TretN="now-243h" +TremN="now-2h" +TdeaN="now-50h" +TpubN1="now-269h" +TactN1="${TretN}" +TretN1="now+477h" +TremN1="now+718h" +ksktimes="-P ${TactN} -A ${TactN} -P sync ${TactN}" +zsktimes="-P ${TactN} -A ${TactN} -I ${TretN} -D ${TremN}" +newtimes="-P ${TpubN1} -A ${TactN1} -I ${TretN1} -D ${TremN1}" +KSK=$($KEYGEN -a $DEFAULT_ALGORITHM -L 3600 -f KSK $ksktimes $zone 2> keygen.out.$zone.1) +ZSK1=$($KEYGEN -a $DEFAULT_ALGORITHM -L 3600 $zsktimes $zone 2> keygen.out.$zone.2) +ZSK2=$($KEYGEN -a $DEFAULT_ALGORITHM -L 3600 $newtimes $zone 2> keygen.out.$zone.3) +$SETTIME -s -g $O -k $O $TactN -r $O $TactN -d $O $TactN "$KSK" > settime.out.$zone.1 2>&1 +$SETTIME -s -g $H -k $H $TdeaN -z $H $TdeaN "$ZSK1" > settime.out.$zone.2 2>&1 +$SETTIME -s -g $O -k $O $TactN1 -z $O $TdeaN "$ZSK2" > settime.out.$zone.3 2>&1 +# Set key rollover relationship. +key_successor $ZSK1 $ZSK2 +# Sign zone. +cat template.db.in "${KSK}.key" "${ZSK1}.key" "${ZSK2}.key" > "$infile" +private_type_record $zone $DEFAULT_ALGORITHM_NUMBER "$KSK" >> "$infile" +private_type_record $zone $DEFAULT_ALGORITHM_NUMBER "$ZSK1" >> "$infile" +private_type_record $zone $DEFAULT_ALGORITHM_NUMBER "$ZSK2" >> "$infile" +cp $infile $zonefile +$SIGNER -S -x -s now-1h -e now+2w -o $zone -O raw -f "${zonefile}.signed" $infile > signer.out.$zone.1 2>&1 + +# +# The zones at ksk-doubleksk.autosign represent the various steps of a KSK +# Double-KSK rollover. +# + +# Step 1: +# Introduce the first key. This will immediately be active. +setup step1.ksk-doubleksk.autosign +TactN="now" +ksktimes="-P ${TactN} -A ${TactN} -P sync ${TactN}" +zsktimes="-P ${TactN} -A ${TactN}" +KSK=$($KEYGEN -a $DEFAULT_ALGORITHM -L 7200 -f KSK $ksktimes $zone 2> keygen.out.$zone.1) +ZSK=$($KEYGEN -a $DEFAULT_ALGORITHM -L 7200 $zsktimes $zone 2> keygen.out.$zone.2) +$SETTIME -s -g $O -k $O $TactN -r $O $TactN -d $O $TactN "$KSK" > settime.out.$zone.1 2>&1 +$SETTIME -s -g $O -k $O $TactN -z $O $TactN "$ZSK" > settime.out.$zone.2 2>&1 +cat template.db.in "${KSK}.key" "${ZSK}.key" > "$infile" +cp $infile $zonefile +$SIGNER -S -x -s now-1h -e now+2w -o $zone -O raw -f "${zonefile}.signed" $infile > signer.out.$zone.1 2>&1 + +# Step 2: +# It is time to submit the introduce the new KSK. +setup step2.ksk-doubleksk.autosign +# According to RFC 7583: +# +# Tpub(N+1) <= Tact(N) + Lksk - Dreg - IpubC +# IpubC = DprpC + TTLkey (+publish-safety) +# +# |1| |2| |3| |4| +# | | | | +# Key N |<-IpubC->|<--->|<-Dreg->|<-----Lksk--- - - +# | | | | +# Key N+1 | | | | +# | | | | +# Key N Tpub Trdy Tsbm Tact +# Key N+1 +# +# (continued ...) +# +# |5| |6| |7| |8| |9| |10| +# | | | | | | +# Key N - - --------------Lksk------->|<-Iret->|<----->| +# | | | | | | +# Key N+1 |<-IpubC->|<--->|<-Dreg->|<--------Lksk----- - - +# | | | | | | +# Key N Tret Tdea Trem +# Key N+1 Tpub Trdy Tsbm Tact +# +# Tnow +# +# Lksk: 60d +# Dreg: 1d +# DprpC: 1h +# TTLkey: 2h +# publish-safety: 1d +# IpubC: 27h +# +# Tact(N) = Tnow - Lksk + Dreg + IpubC = now - 60d + 27h +# = now - 1440h + 27h = now - 1413h +TactN="now-1413h" +ksktimes="-P ${TactN} -A ${TactN} -P sync ${TactN}" +zsktimes="-P ${TactN} -A ${TactN}" +KSK=$($KEYGEN -a $DEFAULT_ALGORITHM -L 7200 -f KSK $ksktimes $zone 2> keygen.out.$zone.1) +ZSK=$($KEYGEN -a $DEFAULT_ALGORITHM -L 7200 $zsktimes $zone 2> keygen.out.$zone.2) +$SETTIME -s -g $O -k $O $TactN -r $O $TactN -d $O $TactN "$KSK" > settime.out.$zone.1 2>&1 +$SETTIME -s -g $O -k $O $TactN -z $O $TactN "$ZSK" > settime.out.$zone.2 2>&1 +cat template.db.in "${KSK}.key" "${ZSK}.key" > "$infile" +private_type_record $zone $DEFAULT_ALGORITHM_NUMBER "$KSK" >> "$infile" +private_type_record $zone $DEFAULT_ALGORITHM_NUMBER "$ZSK" >> "$infile" +cp $infile $zonefile +$SIGNER -S -x -s now-1h -e now+2w -o $zone -O raw -f "${zonefile}.signed" $infile > signer.out.$zone.1 2>&1 + +# Step 3: +# It is time to submit the DS. +setup step3.ksk-doubleksk.autosign +# According to RFC 7583: +# +# Tsbm(N+1) >= Trdy(N+1) +# Tact(N+1) = Tsbm(N+1) + Dreg +# Iret = DprpP + TTLds (+retire-safety) +# +# |5| |6| |7| |8| |9| |10| +# | | | | | | +# Key N - - --------------Lksk------->|<-Iret->|<----->| +# | | | | | | +# Key N+1 |<-IpubC->|<--->|<-Dreg->|<--------Lksk----- - - +# | | | | | | +# Key N Tret Tdea Trem +# Key N+1 Tpub Trdy Tsbm Tact +# +# Tnow +# +# Lksk: 60d +# Dreg: N/A +# DprpP: 1h +# TTLds: 1h +# retire-safety: 2d +# Iret: 50h +# DprpC: 1h +# TTLkey: 2h +# publish-safety: 1d +# IpubC: 27h +# +# Tact(N) = Tnow + Lksk = now - 60d = now - 60d +# Tret(N) = now +# Trem(N) = Tnow + Iret = now + 50h +# Tpub(N+1) = Tnow - IpubC = now - 27h +# Tsbm(N+1) = now +# Tact(N+1) = Tret(N) +# Tret(N+1) = Tnow + Lksk = now + 60d +# Trem(N+1) = Tnow + Lksk + Iret = now + 60d + 50h +# = now + 1440h + 50h = 1490h +TactN="now-60d" +TretN="now" +TremN="now+50h" +TpubN1="now-27h" +TsbmN1="now" +TactN1="${TretN}" +TretN1="now+60d" +TremN1="now+1490h" +ksktimes="-P ${TactN} -A ${TactN} -P sync ${TactN} -I ${TretN} -D ${TremN}" +newtimes="-P ${TpubN1} -A ${TactN1} -P sync ${TsbmN1} -I ${TretN1} -D ${TremN1}" +zsktimes="-P ${TactN} -A ${TactN}" +KSK1=$($KEYGEN -a $DEFAULT_ALGORITHM -L 7200 -f KSK $ksktimes $zone 2> keygen.out.$zone.1) +KSK2=$($KEYGEN -a $DEFAULT_ALGORITHM -L 7200 -f KSK $newtimes $zone 2> keygen.out.$zone.2) +ZSK=$($KEYGEN -a $DEFAULT_ALGORITHM -L 7200 $zsktimes $zone 2> keygen.out.$zone.3) +$SETTIME -s -g $H -k $O $TactN -r $O $TactN -d $O $TactN "$KSK1" > settime.out.$zone.1 2>&1 +$SETTIME -s -g $O -k $R $TpubN1 -r $R $TpubN1 -d $H $TpubN1 "$KSK2" > settime.out.$zone.2 2>&1 +$SETTIME -s -g $O -k $O $TactN -z $O $TactN "$ZSK" > settime.out.$zone.3 2>&1 +# Set key rollover relationship. +key_successor $KSK1 $KSK2 +# Sign zone. +cat template.db.in "${KSK1}.key" "${KSK2}.key" "${ZSK}.key" > "$infile" +private_type_record $zone $DEFAULT_ALGORITHM_NUMBER "$KSK1" >> "$infile" +private_type_record $zone $DEFAULT_ALGORITHM_NUMBER "$KSK2" >> "$infile" +private_type_record $zone $DEFAULT_ALGORITHM_NUMBER "$ZSK" >> "$infile" +cp $infile $zonefile +$SIGNER -S -x -s now-1h -e now+2w -o $zone -O raw -f "${zonefile}.signed" $infile > signer.out.$zone.1 2>&1 + +# Step 4: +# The DS should be swapped now. +setup step4.ksk-doubleksk.autosign +# According to RFC 7583: +# +# Tret(N) = Tsbm(N+1) +# Tdea(N) = Tret(N) + Iret +# Tact(N+1) = Tret(N) +# +# |5| |6| |7| |8| |9| |10| +# | | | | | | +# Key N - - --------------Lksk------->|<-Iret->|<----->| +# | | | | | | +# Key N+1 |<-IpubC->|<--->|<-Dreg->|<--------Lksk----- - - +# | | | | | | +# Key N Tret Tdea Trem +# Key N+1 Tpub Trdy Tsbm Tact +# +# Tnow +# +# Lksk: 60d +# Dreg: N/A +# Iret: 50h +# +# Tact(N) = Tnow - Lksk - Iret = now - 60d - 50h +# = now - 1440h - 50h = now - 1490h +# Tret(N) = Tnow - Iret = now - 50h +# Trem(N) = Tnow +# Tpub(N+1) = Tnow - Iret - IpubC = now - 50h - 27h +# = now - 77h +# Tsbm(N+1) = Tnow - Iret = now - 50h +# Tact(N+1) = Tret(N) +# Tret(N+1) = Tnow + Lksk - Iret = now + 60d - 50h = now + 1390h +# Trem(N+1) = Tnow + Lksk = now + 60d +TactN="now-1490h" +TretN="now-50h" +TremN="now" +TpubN1="now-77h" +TsbmN1="now-50h" +TactN1="${TretN}" +TretN1="now+1390h" +TremN1="now+60d" +ksktimes="-P ${TactN} -A ${TactN} -P sync ${TactN} -I ${TretN} -D ${TremN}" +newtimes="-P ${TpubN1} -A ${TretN} -P sync ${TsbmN1} -I ${TretN1} -D ${TremN1}" +zsktimes="-P ${TactN} -A ${TactN}" +KSK1=$($KEYGEN -a $DEFAULT_ALGORITHM -L 7200 -f KSK $ksktimes $zone 2> keygen.out.$zone.1) +KSK2=$($KEYGEN -a $DEFAULT_ALGORITHM -L 7200 -f KSK $newtimes $zone 2> keygen.out.$zone.2) +ZSK=$($KEYGEN -a $DEFAULT_ALGORITHM -L 7200 $zsktimes $zone 2> keygen.out.$zone.3) +$SETTIME -s -g $H -k $O $TactN -r $O $TactN -d $U $TsbmN1 -D ds $TsbmN1 "$KSK1" > settime.out.$zone.1 2>&1 +$SETTIME -s -g $O -k $O $TsbmN1 -r $O $TsbmN1 -d $R $TsbmN1 -P ds $TsbmN1 "$KSK2" > settime.out.$zone.2 2>&1 +$SETTIME -s -g $O -k $O $TactN -z $O $TactN "$ZSK" > settime.out.$zone.3 2>&1 +# Set key rollover relationship. +key_successor $KSK1 $KSK2 +# Sign zone. +cat template.db.in "${KSK1}.key" "${KSK2}.key" "${ZSK}.key" > "$infile" +private_type_record $zone $DEFAULT_ALGORITHM_NUMBER "$KSK1" >> "$infile" +private_type_record $zone $DEFAULT_ALGORITHM_NUMBER "$KSK2" >> "$infile" +private_type_record $zone $DEFAULT_ALGORITHM_NUMBER "$ZSK" >> "$infile" +cp $infile $zonefile +$SIGNER -S -x -s now-1h -e now+2w -o $zone -O raw -f "${zonefile}.signed" $infile > signer.out.$zone.1 2>&1 + +# Step 5: +# The predecessor DNSKEY is removed long enough that is has become HIDDEN. +setup step5.ksk-doubleksk.autosign +# Subtract DNSKEY TTL from all the times (2h). +# Tact(N) = now - 1490h - 2h = now - 1492h +# Tret(N) = now - 50h - 2h = now - 52h +# Trem(N) = now - 2h +# Tpub(N+1) = now - 77h - 2h = now - 79h +# Tsbm(N+1) = now - 50h - 2h = now - 52h +# Tact(N+1) = Tret(N) +# Tret(N+1) = now + 1390h - 2h = now + 1388h +# Trem(N+1) = now + 60d - 2h = now + 1442h +TactN="now-1492h" +TretN="now-52h" +TremN="now-2h" +TpubN1="now-79h" +TsbmN1="now-52h" +TactN1="${TretN}" +TretN1="now+1388h" +TremN1="now+1442h" +ksktimes="-P ${TactN} -A ${TactN} -P sync ${TactN} -I ${TretN} -D ${TremN}" +newtimes="-P ${TpubN1} -A ${TretN} -P sync ${TsbmN1} -I ${TretN1} -D ${TremN1}" +zsktimes="-P ${TactN} -A ${TactN}" +KSK1=$($KEYGEN -a $DEFAULT_ALGORITHM -L 7200 -f KSK $ksktimes $zone 2> keygen.out.$zone.1) +KSK2=$($KEYGEN -a $DEFAULT_ALGORITHM -L 7200 -f KSK $newtimes $zone 2> keygen.out.$zone.2) +ZSK=$($KEYGEN -a $DEFAULT_ALGORITHM -L 7200 $zsktimes $zone 2> keygen.out.$zone.3) +$SETTIME -s -g $H -k $U $TretN -r $U $TretN -d $H $TretN "$KSK1" > settime.out.$zone.1 2>&1 +$SETTIME -s -g $O -k $O $TactN1 -r $O $TactN1 -d $O $TactN1 "$KSK2" > settime.out.$zone.2 2>&1 +$SETTIME -s -g $O -k $O $TactN -z $O $TactN "$ZSK" > settime.out.$zone.3 2>&1 +# Set key rollover relationship. +key_successor $KSK1 $KSK2 +# Sign zone. +cat template.db.in "${KSK1}.key" "${KSK2}.key" "${ZSK}.key" > "$infile" +private_type_record $zone $DEFAULT_ALGORITHM_NUMBER "$KSK1" >> "$infile" +private_type_record $zone $DEFAULT_ALGORITHM_NUMBER "$KSK2" >> "$infile" +private_type_record $zone $DEFAULT_ALGORITHM_NUMBER "$ZSK" >> "$infile" +cp $infile $zonefile +$SIGNER -S -x -s now-1h -e now+2w -o $zone -O raw -f "${zonefile}.signed" $infile > signer.out.$zone.1 2>&1 + +# Step 6: +# The predecessor DNSKEY can be purged. +setup step6.ksk-doubleksk.autosign +# Subtract purge-keys interval from all the times (1h). +# Tact(N) = now - 1492h - 1h = now - 1493h +# Tret(N) = now - 52h - 1h = now - 53h +# Trem(N) = now - 2h - 1h = now - 3h +# Tpub(N+1) = now - 79h - 1h = now - 80h +# Tsbm(N+1) = now - 52h - 1h = now - 53h +# Tact(N+1) = Tret(N) +# Tret(N+1) = now + 1388h - 1h = now + 1387h +# Trem(N+1) = now + 1442h - 1h = now + 1441h +TactN="now-1493h" +TretN="now-53h" +TremN="now-3h" +TpubN1="now-80h" +TsbmN1="now-53h" +TactN1="${TretN}" +TretN1="now+1387h" +TremN1="now+1441h" +ksktimes="-P ${TactN} -A ${TactN} -P sync ${TactN} -I ${TretN} -D ${TremN}" +newtimes="-P ${TpubN1} -A ${TretN} -P sync ${TsbmN1} -I ${TretN1} -D ${TremN1}" +zsktimes="-P ${TactN} -A ${TactN}" +KSK1=$($KEYGEN -a $DEFAULT_ALGORITHM -L 7200 -f KSK $ksktimes $zone 2> keygen.out.$zone.1) +KSK2=$($KEYGEN -a $DEFAULT_ALGORITHM -L 7200 -f KSK $newtimes $zone 2> keygen.out.$zone.2) +ZSK=$($KEYGEN -a $DEFAULT_ALGORITHM -L 7200 $zsktimes $zone 2> keygen.out.$zone.3) +$SETTIME -s -g $H -k $H $TretN -r $H $TretN -d $H $TretN "$KSK1" > settime.out.$zone.1 2>&1 +$SETTIME -s -g $O -k $O $TactN1 -r $O $TactN1 -d $O $TactN1 "$KSK2" > settime.out.$zone.2 2>&1 +$SETTIME -s -g $O -k $O $TactN -z $O $TactN "$ZSK" > settime.out.$zone.3 2>&1 +# Set key rollover relationship. +key_successor $KSK1 $KSK2 +# Sign zone. +cat template.db.in "${KSK1}.key" "${KSK2}.key" "${ZSK}.key" > "$infile" +private_type_record $zone $DEFAULT_ALGORITHM_NUMBER "$KSK1" >> "$infile" +private_type_record $zone $DEFAULT_ALGORITHM_NUMBER "$KSK2" >> "$infile" +private_type_record $zone $DEFAULT_ALGORITHM_NUMBER "$ZSK" >> "$infile" +cp $infile $zonefile +$SIGNER -S -x -s now-1h -e now+2w -o $zone -O raw -f "${zonefile}.signed" $infile > signer.out.$zone.1 2>&1 + +# +# The zones at csk-roll.autosign represent the various steps of a CSK rollover +# (which is essentially a ZSK Pre-Publication / KSK Double-KSK rollover). +# + +# Step 1: +# Introduce the first key. This will immediately be active. +setup step1.csk-roll.autosign +TactN="now" +csktimes="-P ${TactN} -P sync ${TactN} -A ${TactN}" +CSK=$($KEYGEN -k csk-roll -l policies/autosign.conf $csktimes $zone 2> keygen.out.$zone.1) +$SETTIME -s -g $O -k $O $TactN -r $O $TactN -d $O $TactN -z $O $TactN "$CSK" > settime.out.$zone.1 2>&1 +cat template.db.in "${CSK}.key" > "$infile" +private_type_record $zone $DEFAULT_ALGORITHM_NUMBER "$CSK" >> "$infile" +cp $infile $zonefile +$SIGNER -S -z -x -s now-1h -e now+30d -o $zone -O raw -f "${zonefile}.signed" $infile > signer.out.$zone.1 2>&1 + +# Step 2: +# It is time to introduce the new CSK. +setup step2.csk-roll.autosign +# According to RFC 7583: +# KSK: Tpub(N+1) <= Tact(N) + Lksk - IpubC +# ZSK: Tpub(N+1) <= Tact(N) + Lzsk - Ipub +# IpubC = DprpC + TTLkey (+publish-safety) +# Ipub = IpubC +# Lcsk = Lksk = Lzsk +# +# Lcsk: 6mo (186d, 4464h) +# Dreg: N/A +# DprpC: 1h +# TTLkey: 1h +# publish-safety: 1h +# Ipub: 3h +# +# Tact(N) = Tnow - Lcsk + Ipub = now - 186d + 3h +# = now - 4464h + 3h = now - 4461h +TactN="now-4461h" +csktimes="-P ${TactN} -P sync ${TactN} -A ${TactN}" +CSK=$($KEYGEN -k csk-roll -l policies/autosign.conf $csktimes $zone 2> keygen.out.$zone.1) +$SETTIME -s -g $O -k $O $TactN -r $O $TactN -d $O $TactN -z $O $TactN "$CSK" > settime.out.$zone.1 2>&1 +cat template.db.in "${CSK}.key" > "$infile" +private_type_record $zone $DEFAULT_ALGORITHM_NUMBER "$CSK" >> "$infile" +cp $infile $zonefile +$SIGNER -S -z -x -s now-1h -e now+30d -o $zone -O raw -f "${zonefile}.signed" $infile > signer.out.$zone.1 2>&1 + +# Step 3: +# It is time to submit the DS and to roll signatures. +setup step3.csk-roll.autosign +# According to RFC 7583: +# +# Tsbm(N+1) >= Trdy(N+1) +# KSK: Tact(N+1) = Tsbm(N+1) +# ZSK: Tact(N+1) = Tpub(N+1) + Ipub = Tsbm(N+1) +# KSK: Iret = DprpP + TTLds (+retire-safety) +# ZSK: IretZ = Dsgn + Dprp + TTLsig (+retire-safety) +# +# Lcsk: 186d +# Dprp: 1h +# DprpP: 1h +# Dreg: N/A +# Dsgn: 25d +# TTLds: 1h +# TTLsig: 1d +# retire-safety: 2h +# Iret: 4h +# IretZ: 26d3h +# Ipub: 3h +# +# Tact(N) = Tnow - Lcsk = now - 186d +# Tret(N) = now +# Trem(N) = Tnow + IretZ = now + 26d3h = now + 627h +# Tpub(N+1) = Tnow - Ipub = now - 3h +# Tsbm(N+1) = Tret(N) +# Tact(N+1) = Tret(N) +# Tret(N+1) = Tnow + Lcsk = now + 186d = now + 186d +# Trem(N+1) = Tnow + Lcsk + IretZ = now + 186d + 26d3h = +# = now + 5091h +TactN="now-186d" +TretN="now" +TremN="now+627h" +TpubN1="now-3h" +TsbmN1="now" +TactN1="${TretN}" +TretN1="now+186d" +TremN1="now+5091h" +csktimes="-P ${TactN} -P sync ${TactN} -A ${TactN} -I ${TretN} -D ${TremN}" +newtimes="-P ${TpubN1} -P sync ${TsbmN1} -A ${TactN1} -I ${TretN1} -D ${TremN1}" +CSK1=$($KEYGEN -k csk-roll -l policies/autosign.conf $csktimes $zone 2> keygen.out.$zone.1) +CSK2=$($KEYGEN -k csk-roll -l policies/autosign.conf $newtimes $zone 2> keygen.out.$zone.2) +$SETTIME -s -g $H -k $O $TactN -r $O $TactN -d $O $TactN -z $O $TactN "$CSK1" > settime.out.$zone.1 2>&1 +$SETTIME -s -g $O -k $R $TpubN1 -r $R $TpubN1 -d $H $TpubN1 -z $H $TpubN1 "$CSK2" > settime.out.$zone.2 2>&1 +# Set key rollover relationship. +key_successor $CSK1 $CSK2 +# Sign zone. +cat template.db.in "${CSK1}.key" "${CSK2}.key" > "$infile" +private_type_record $zone $DEFAULT_ALGORITHM_NUMBER "$CSK1" >> "$infile" +private_type_record $zone $DEFAULT_ALGORITHM_NUMBER "$CSK2" >> "$infile" +cp $infile $zonefile +$SIGNER -S -z -x -s now-1h -e now+30d -o $zone -O raw -f "${zonefile}.signed" $infile > signer.out.$zone.1 2>&1 + +# Step 4: +# Some time later all the ZRRSIG records should be from the new CSK, and the +# DS should be swapped. The ZRRSIG records are all replaced after IretZ +# (which is 26d3h). The DS is swapped after Iret (which is 4h). +# In other words, the DS is swapped before all zone signatures are replaced. +setup step4.csk-roll.autosign +# According to RFC 7583: +# Trem(N) = Tret(N) - Iret + IretZ +# Tnow = Tsbm(N+1) + Iret +# +# Lcsk: 186d +# Iret: 4h +# IretZ: 26d3h +# +# Tact(N) = Tnow - Iret - Lcsk = now - 4h - 186d = now - 4468h +# Tret(N) = Tnow - Iret = now - 4h = now - 4h +# Trem(N) = Tnow - Iret + IretZ = now - 4h + 26d3h +# = now + 623h +# Tpub(N+1) = Tnow - Iret - IpubC = now - 4h - 3h = now - 7h +# Tsbm(N+1) = Tret(N) +# Tact(N+1) = Tret(N) +# Tret(N+1) = Tnow - Iret + Lcsk = now - 4h + 186d = now + 4460h +# Trem(N+1) = Tnow - Iret + Lcsk + IretZ = now - 4h + 186d + 26d3h +# = now + 5087h +TactN="now-4468h" +TretN="now-4h" +TremN="now+623h" +TpubN1="now-7h" +TsbmN1="${TretN}" +TactN1="${TretN}" +TretN1="now+4460h" +TremN1="now+5087h" +csktimes="-P ${TactN} -P sync ${TactN} -A ${TactN} -I ${TretN} -D ${TremN}" +newtimes="-P ${TpubN1} -P sync ${TsbmN1} -A ${TactN1} -I ${TretN1} -D ${TremN1}" +CSK1=$($KEYGEN -k csk-roll -l policies/autosign.conf $csktimes $zone 2> keygen.out.$zone.1) +CSK2=$($KEYGEN -k csk-roll -l policies/autosign.conf $newtimes $zone 2> keygen.out.$zone.2) +$SETTIME -s -g $H -k $O $TactN -r $O $TactN -d $U $TsbmN1 -z $U $TsbmN1 -D ds $TsbmN1 "$CSK1" > settime.out.$zone.1 2>&1 +$SETTIME -s -g $O -k $O $TsbmN1 -r $O $TsbmN1 -d $R $TsbmN1 -z $R $TsbmN1 -P ds $TsbmN1 "$CSK2" > settime.out.$zone.2 2>&1 +# Set key rollover relationship. +key_successor $CSK1 $CSK2 +# Sign zone. +cat template.db.in "${CSK1}.key" "${CSK2}.key" > "$infile" +private_type_record $zone $DEFAULT_ALGORITHM_NUMBER "$CSK1" >> "$infile" +private_type_record $zone $DEFAULT_ALGORITHM_NUMBER "$CSK2" >> "$infile" +cp $infile $zonefile +$SIGNER -S -z -x -s now-1h -e now+30d -o $zone -O raw -f "${zonefile}.signed" $infile > signer.out.$zone.1 2>&1 + +# Step 5: +# After the DS is swapped in step 4, also the KRRSIG records can be removed. +# At this time these have all become hidden. +setup step5.csk-roll.autosign +# Subtract DNSKEY TTL plus zone propagation delay from all the times (2h). +# Tact(N) = now - 4468h - 2h = now - 4470h +# Tret(N) = now - 4h - 2h = now - 6h +# Trem(N) = now + 623h - 2h = now + 621h +# Tpub(N+1) = now - 7h - 2h = now - 9h +# Tsbm(N+1) = Tret(N) +# Tact(N+1) = Tret(N) +# Tret(N+1) = now + 4460h - 2h = now + 4458h +# Trem(N+1) = now + 5087h - 2h = now + 5085h +TactN="now-4470h" +TretN="now-6h" +TremN="now+621h" +TpubN1="now-9h" +TsbmN1="${TretN}" +TactN1="${TretN}" +TretN1="now+4458h" +TremN1="now+5085h" +csktimes="-P ${TactN} -P sync ${TactN} -A ${TactN} -I ${TretN} -D ${TremN}" +newtimes="-P ${TpubN1} -P sync ${TsbmN1} -A ${TactN1} -I ${TretN1} -D ${TremN1}" +CSK1=$($KEYGEN -k csk-roll -l policies/autosign.conf $csktimes $zone 2> keygen.out.$zone.1) +CSK2=$($KEYGEN -k csk-roll -l policies/autosign.conf $newtimes $zone 2> keygen.out.$zone.2) +$SETTIME -s -g $H -k $O $TactN -r $U now-2h -d $H now-2h -z $U $TactN1 "$CSK1" > settime.out.$zone.1 2>&1 +$SETTIME -s -g $O -k $O $TsbmN1 -r $O $TsbmN1 -d $O now-2h -z $R $TactN1 "$CSK2" > settime.out.$zone.2 2>&1 +# Set key rollover relationship. +key_successor $CSK1 $CSK2 +# Sign zone. +cat template.db.in "${CSK1}.key" "${CSK2}.key" > "$infile" +private_type_record $zone $DEFAULT_ALGORITHM_NUMBER "$CSK1" >> "$infile" +private_type_record $zone $DEFAULT_ALGORITHM_NUMBER "$CSK2" >> "$infile" +cp $infile $zonefile +$SIGNER -S -z -x -s now-1h -e now+30d -o $zone -O raw -f "${zonefile}.signed" $infile > signer.out.$zone.1 2>&1 + +# Step 6: +# After the retire interval has passed the predecessor DNSKEY can be +# removed from the zone. +setup step6.csk-roll.autosign +# According to RFC 7583: +# Trem(N) = Tret(N) + IretZ +# Tret(N) = Tact(N) + Lcsk +# +# Lcsk: 186d +# Iret: 4h +# IretZ: 26d3h +# +# Tact(N) = Tnow - IretZ - Lcsk = now - 627h - 186d +# = now - 627h - 4464h = now - 5091h +# Tret(N) = Tnow - IretZ = now - 627h +# Trem(N) = Tnow +# Tpub(N+1) = Tnow - IretZ - Ipub = now - 627h - 3h = now - 630h +# Tsbm(N+1) = Tret(N) +# Tact(N+1) = Tret(N) +# Tret(N+1) = Tnow - IretZ + Lcsk = now - 627h + 186d = now + 3837h +# Trem(N+1) = Tnow + Lcsk = now + 186d +TactN="now-5091h" +TretN="now-627h" +TremN="now" +TpubN1="now-630h" +TsbmN1="${TretN}" +TactN1="${TretN}" +TretN1="now+3837h" +TremN1="now+186d" +csktimes="-P ${TactN} -P sync ${TactN} -A ${TactN} -I ${TretN} -D ${TremN}" +newtimes="-P ${TpubN1} -P sync ${TsbmN1} -A ${TactN1} -I ${TretN1} -D ${TremN1}" +CSK1=$($KEYGEN -k csk-roll -l policies/autosign.conf $csktimes $zone 2> keygen.out.$zone.1) +CSK2=$($KEYGEN -k csk-roll -l policies/autosign.conf $newtimes $zone 2> keygen.out.$zone.2) +$SETTIME -s -g $H -k $O $TactN -r $H $TremN -d $H $TremN -z $U $TsbmN1 "$CSK1" > settime.out.$zone.1 2>&1 +$SETTIME -s -g $O -k $O $TsbmN1 -r $O $TsbmN1 -d $O $TremN -z $R $TsbmN1 "$CSK2" > settime.out.$zone.2 2>&1 +# Set key rollover relationship. +key_successor $CSK1 $CSK2 +# Sign zone. +cat template.db.in "${CSK1}.key" "${CSK2}.key" > "$infile" +private_type_record $zone $DEFAULT_ALGORITHM_NUMBER "$CSK1" >> "$infile" +private_type_record $zone $DEFAULT_ALGORITHM_NUMBER "$CSK2" >> "$infile" +cp $infile $zonefile +$SIGNER -S -z -x -s now-1h -e now+30d -o $zone -O raw -f "${zonefile}.signed" $infile > signer.out.$zone.1 2>&1 + +# Step 7: +# Some time later the predecessor DNSKEY enters the HIDDEN state. +setup step7.csk-roll.autosign +# Subtract DNSKEY TTL plus zone propagation delay from all the times (2h). +# Tact(N) = now - 5091h - 2h = now - 5093h +# Tret(N) = now - 627h - 2h = now - 629h +# Trem(N) = now - 2h +# Tpub(N+1) = now - 630h - 2h = now - 632h +# Tsbm(N+1) = Tret(N) +# Tact(N+1) = Tret(N) +# Tret(N+1) = now + 3837h - 2h = now + 3835h +# Trem(N+1) = now + 186d - 2h = now + 4462h +TactN="now-5093h" +TretN="now-629h" +TremN="now-2h" +TpubN1="now-632h" +TsbmN1="${TretN}" +TactN1="${TretN}" +TretN1="now+3835h" +TremN1="now+4462h" +csktimes="-P ${TactN} -P sync ${TactN} -A ${TactN} -I ${TretN} -D ${TremN}" +newtimes="-P ${TpubN1} -P sync ${TsbmN1} -A ${TactN1} -I ${TretN1} -D ${TremN1}" +CSK1=$($KEYGEN -k csk-roll -l policies/autosign.conf $csktimes $zone 2> keygen.out.$zone.1) +CSK2=$($KEYGEN -k csk-roll -l policies/autosign.conf $newtimes $zone 2> keygen.out.$zone.2) +$SETTIME -s -g $H -k $U $TremN -r $H $TremN -d $H $TremN -z $H $TactN1 "$CSK1" > settime.out.$zone.1 2>&1 +$SETTIME -s -g $O -k $O $TsbmN1 -r $O $TsbmN1 -d $O $TactN1 -z $O $TactN1 "$CSK2" > settime.out.$zone.2 2>&1 +# Set key rollover relationship. +key_successor $CSK1 $CSK2 +# Sign zone. +cat template.db.in "${CSK1}.key" "${CSK2}.key" > "$infile" +private_type_record $zone $DEFAULT_ALGORITHM_NUMBER "$CSK1" >> "$infile" +private_type_record $zone $DEFAULT_ALGORITHM_NUMBER "$CSK2" >> "$infile" +cp $infile $zonefile +$SIGNER -S -z -x -s now-1h -e now+30d -o $zone -O raw -f "${zonefile}.signed" $infile > signer.out.$zone.1 2>&1 + +# Step 8: +# The predecessor DNSKEY can be purged. +setup step8.csk-roll.autosign +# Subtract purge-keys interval from all the times (1h). +# Tact(N) = now - 5093h - 1h = now - 5094h +# Tret(N) = now - 629h - 1h = now - 630h +# Trem(N) = now - 2h - 1h = now - 3h +# Tpub(N+1) = now - 632h - 1h = now - 633h +# Tsbm(N+1) = Tret(N) +# Tact(N+1) = Tret(N) +# Tret(N+1) = now + 3835h - 1h = now + 3834h +# Trem(N+1) = now + 4462h - 1h = now + 4461h +TactN="now-5094h" +TretN="now-630h" +TremN="now-3h" +TpubN1="now-633h" +TsbmN1="${TretN}" +TactN1="${TretN}" +TretN1="now+3834h" +TremN1="now+4461h" +csktimes="-P ${TactN} -P sync ${TactN} -A ${TactN} -I ${TretN} -D ${TremN}" +newtimes="-P ${TpubN1} -P sync ${TsbmN1} -A ${TactN1} -I ${TretN1} -D ${TremN1}" +CSK1=$($KEYGEN -k csk-roll -l policies/autosign.conf $csktimes $zone 2> keygen.out.$zone.1) +CSK2=$($KEYGEN -k csk-roll -l policies/autosign.conf $newtimes $zone 2> keygen.out.$zone.2) +$SETTIME -s -g $H -k $H $TremN -r $H $TremN -d $H $TremN -z $H $TactN1 "$CSK1" > settime.out.$zone.1 2>&1 +$SETTIME -s -g $O -k $O $TsbmN1 -r $O $TsbmN1 -d $O $TactN1 -z $O $TactN1 "$CSK2" > settime.out.$zone.2 2>&1 +# Set key rollover relationship. +key_successor $CSK1 $CSK2 +# Sign zone. +cat template.db.in "${CSK1}.key" "${CSK2}.key" > "$infile" +private_type_record $zone $DEFAULT_ALGORITHM_NUMBER "$CSK1" >> "$infile" +private_type_record $zone $DEFAULT_ALGORITHM_NUMBER "$CSK2" >> "$infile" +cp $infile $zonefile +$SIGNER -S -z -x -s now-1h -e now+30d -o $zone -O raw -f "${zonefile}.signed" $infile > signer.out.$zone.1 2>&1 + +# +# The zones at csk-roll2.autosign represent the various steps of a CSK rollover +# (which is essentially a ZSK Pre-Publication / KSK Double-KSK rollover). +# This scenario differs from the above one because the zone signatures (ZRRSIG) +# are replaced with the new key sooner than the DS is swapped. +# + +# Step 1: +# Introduce the first key. This will immediately be active. +setup step1.csk-roll2.autosign +TactN="now" +csktimes="-P ${TactN} -P sync ${TactN} -A ${TactN}" +CSK=$($KEYGEN -k csk-roll2 -l policies/autosign.conf $csktimes $zone 2> keygen.out.$zone.1) +$SETTIME -s -g $O -k $O $TactN -r $O $TactN -d $O $TactN -z $O $TactN "$CSK" > settime.out.$zone.1 2>&1 +cat template.db.in "${CSK}.key" > "$infile" +private_type_record $zone $DEFAULT_ALGORITHM_NUMBER "$CSK" >> "$infile" +cp $infile $zonefile +$SIGNER -S -z -x -s now-1h -e now+30d -o $zone -O raw -f "${zonefile}.signed" $infile > signer.out.$zone.1 2>&1 + +# Step 2: +# It is time to introduce the new CSK. +setup step2.csk-roll2.autosign +# According to RFC 7583: +# KSK: Tpub(N+1) <= Tact(N) + Lksk - IpubC +# ZSK: Tpub(N+1) <= Tact(N) + Lzsk - Ipub +# IpubC = DprpC + TTLkey (+publish-safety) +# Ipub = IpubC +# Lcsk = Lksk = Lzsk +# +# Lcsk: 6mo (186d, 4464h) +# Dreg: N/A +# DprpC: 1h +# TTLkey: 1h +# publish-safety: 1h +# Ipub: 3h +# +# Tact(N) = Tnow - Lcsk + Ipub = now - 186d + 3h +# = now - 4464h + 3h = now - 4461h +TactN="now-4461h" +csktimes="-P ${TactN} -P sync ${TactN} -A ${TactN}" +CSK=$($KEYGEN -k csk-roll2 -l policies/autosign.conf $csktimes $zone 2> keygen.out.$zone.1) +$SETTIME -s -g $O -k $O $TactN -r $O $TactN -d $O $TactN -z $O $TactN "$CSK" > settime.out.$zone.1 2>&1 +cat template.db.in "${CSK}.key" > "$infile" +private_type_record $zone $DEFAULT_ALGORITHM_NUMBER "$CSK" >> "$infile" +cp $infile $zonefile +$SIGNER -S -z -x -s now-1h -e now+30d -o $zone -O raw -f "${zonefile}.signed" $infile > signer.out.$zone.1 2>&1 + +# Step 3: +# It is time to submit the DS and to roll signatures. +setup step3.csk-roll2.autosign +# According to RFC 7583: +# +# Tsbm(N+1) >= Trdy(N+1) +# KSK: Tact(N+1) = Tsbm(N+1) +# ZSK: Tact(N+1) = Tpub(N+1) + Ipub = Tsbm(N+1) +# KSK: Iret = DprpP + TTLds (+retire-safety) +# ZSK: IretZ = Dsgn + Dprp + TTLsig (+retire-safety) +# +# Lcsk: 186d +# Dprp: 1h +# DprpP: 1w +# Dreg: N/A +# Dsgn: 12h +# TTLds: 1h +# TTLsig: 1d +# retire-safety: 1h +# Iret: 170h +# IretZ: 38h +# Ipub: 3h +# +# Tact(N) = Tnow - Lcsk = now - 186d +# Tret(N) = now +# Trem(N) = Tnow + Iret = now + 170h +# Tpub(N+1) = Tnow - Ipub = now - 3h +# Tsbm(N+1) = Tret(N) +# Tact(N+1) = Tret(N) +# Tret(N+1) = Tnow + Lcsk = now + 186d +# Trem(N+1) = Tnow + Lcsk + Iret = now + 186d + 170h = +# = now + 4464h + 170h = now + 4634h +TactN="now-186d" +TretN="now" +TremN="now+170h" +TpubN1="now-3h" +TsbmN1="${TretN}" +TactN1="${TretN}" +TretN1="now+186d" +TremN1="now+4634h" +csktimes="-P ${TactN} -P sync ${TactN} -A ${TactN} -I ${TretN} -D ${TremN}" +newtimes="-P ${TpubN1} -P sync ${TsbmN1} -A ${TactN1} -I ${TretN1} -D ${TremN1}" +CSK1=$($KEYGEN -k csk-roll2 -l policies/autosign.conf $csktimes $zone 2> keygen.out.$zone.1) +CSK2=$($KEYGEN -k csk-roll2 -l policies/autosign.conf $newtimes $zone 2> keygen.out.$zone.2) +$SETTIME -s -g $H -k $O $TactN -r $O $TactN -d $O $TactN -z $O $TactN "$CSK1" > settime.out.$zone.1 2>&1 +$SETTIME -s -g $O -k $R $TpubN1 -r $R $TpubN1 -d $H $TpubN1 -z $H $TpubN1 "$CSK2" > settime.out.$zone.2 2>&1 +# Set key rollover relationship. +key_successor $CSK1 $CSK2 +# Sign zone. +cat template.db.in "${CSK1}.key" "${CSK2}.key" > "$infile" +private_type_record $zone $DEFAULT_ALGORITHM_NUMBER "$CSK1" >> "$infile" +private_type_record $zone $DEFAULT_ALGORITHM_NUMBER "$CSK2" >> "$infile" +cp $infile $zonefile +$SIGNER -S -z -x -s now-1h -e now+30d -o $zone -O raw -f "${zonefile}.signed" $infile > signer.out.$zone.1 2>&1 + +# Step 4: +# Some time later all the ZRRSIG records should be from the new CSK, and the +# DS should be swapped. The ZRRSIG records are all replaced after IretZ (38h). +# The DS is swapped after Dreg + Iret (1w3h). In other words, the zone +# signatures are replaced before the DS is swapped. +setup step4.csk-roll2.autosign +# According to RFC 7583: +# Trem(N) = Tret(N) + IretZ +# +# Lcsk: 186d +# Dreg: N/A +# Iret: 170h +# IretZ: 38h +# +# Tact(N) = Tnow - IretZ = Lcsk = now - 38h - 186d +# = now - 38h - 4464h = now - 4502h +# Tret(N) = Tnow - IretZ = now - 38h +# Trem(N) = Tnow - IretZ + Iret = now - 38h + 170h = now + 132h +# Tpub(N+1) = Tnow - IretZ - IpubC = now - 38h - 3h = now - 41h +# Tsbm(N+1) = Tret(N) +# Tact(N+1) = Tret(N) +# Tret(N+1) = Tnow - IretZ + Lcsk = now - 38h + 186d +# = now + 4426h +# Trem(N+1) = Tnow - IretZ + Lcsk + Iret +# = now + 4426h + 3h = now + 4429h +TactN="now-4502h" +TretN="now-38h" +TremN="now+132h" +TpubN1="now-41h" +TsbmN1="${TretN}" +TactN1="${TretN}" +TretN1="now+4426h" +TremN1="now+4429h" +csktimes="-P ${TactN} -P sync ${TactN} -A ${TactN} -I ${TretN} -D ${TremN}" +newtimes="-P ${TpubN1} -P sync ${TsbmN1} -A ${TactN1} -I ${TretN1} -D ${TremN1}" +CSK1=$($KEYGEN -k csk-roll2 -l policies/autosign.conf $csktimes $zone 2> keygen.out.$zone.1) +CSK2=$($KEYGEN -k csk-roll2 -l policies/autosign.conf $newtimes $zone 2> keygen.out.$zone.2) +$SETTIME -s -g $H -k $O $TactN -r $O $TactN -z $U $TretN -d $U $TsbmN1 -D ds $TsbmN1 "$CSK1" > settime.out.$zone.1 2>&1 +$SETTIME -s -g $O -k $O $TsbmN1 -r $O $TsbmN1 -z $R $TactN1 -d $R $TsbmN1 -P ds $TsbmN1 "$CSK2" > settime.out.$zone.2 2>&1 +# Set key rollover relationship. +key_successor $CSK1 $CSK2 +# Sign zone. +cat template.db.in "${CSK1}.key" "${CSK2}.key" > "$infile" +private_type_record $zone $DEFAULT_ALGORITHM_NUMBER "$CSK1" >> "$infile" +private_type_record $zone $DEFAULT_ALGORITHM_NUMBER "$CSK2" >> "$infile" +cp $infile $zonefile +$SIGNER -S -z -x -s now-1h -e now+30d -o $zone -O raw -f "${zonefile}.signed" $infile > signer.out.$zone.1 2>&1 + +# Step 5: +# Some time later the DS can be swapped and the old DNSKEY can be removed from +# the zone. +setup step5.csk-roll2.autosign +# Subtract Iret (170h) - IretZ (38h) = 132h. +# +# Tact(N) = now - 4502h - 132h = now - 4634h +# Tret(N) = now - 38h - 132h = now - 170h +# Trem(N) = now + 132h - 132h = now +# Tpub(N+1) = now - 41h - 132h = now - 173h +# Tsbm(N+1) = Tret(N) +# Tact(N+1) = Tret(N) +# Tret(N+1) = now + 4426h - 132h = now + 4294h +# Trem(N+1) = now + 4492h - 132h = now + 4360h +TactN="now-4634h" +TretN="now-170h" +TremN="now" +TpubN1="now-173h" +TsbmN1="${TretN}" +TactN1="${TretN}" +TretN1="now+4294h" +TremN1="now+4360h" +csktimes="-P ${TactN} -P sync ${TactN} -A ${TactN} -I ${TretN} -D ${TremN}" +newtimes="-P ${TpubN1} -P sync ${TsbmN1} -A ${TactN1} -I ${TretN1} -D ${TremN1}" +CSK1=$($KEYGEN -k csk-roll2 -l policies/autosign.conf $csktimes $zone 2> keygen.out.$zone.1) +CSK2=$($KEYGEN -k csk-roll2 -l policies/autosign.conf $newtimes $zone 2> keygen.out.$zone.2) +$SETTIME -s -g $H -k $O $TactN -r $O $TactN -z $H now-133h -d $U $TsbmN1 -D ds $TsbmN1 "$CSK1" > settime.out.$zone.1 2>&1 +$SETTIME -s -g $O -k $O $TsbmN1 -r $O $TsbmN1 -z $O now-133h -d $R $TsbmN1 -P ds $TsbmN1 "$CSK2" > settime.out.$zone.2 2>&1 +# Set key rollover relationship. +key_successor $CSK1 $CSK2 +# Sign zone. +cat template.db.in "${CSK1}.key" "${CSK2}.key" > "$infile" +private_type_record $zone $DEFAULT_ALGORITHM_NUMBER "$CSK1" >> "$infile" +private_type_record $zone $DEFAULT_ALGORITHM_NUMBER "$CSK2" >> "$infile" +cp $infile $zonefile +$SIGNER -S -z -x -s now-1h -e now+30d -o $zone -O raw -f "${zonefile}.signed" $infile > signer.out.$zone.1 2>&1 + +# Step 6: +# Some time later the predecessor DNSKEY enters the HIDDEN state. +setup step6.csk-roll2.autosign +# Subtract DNSKEY TTL plus zone propagation delay (2h). +# +# Tact(N) = now - 4634h - 2h = now - 4636h +# Tret(N) = now - 170h - 2h = now - 172h +# Trem(N) = now - 2h +# Tpub(N+1) = now - 173h - 2h = now - 175h +# Tsbm(N+1) = Tret(N) +# Tact(N+1) = Tret(N) +# Tret(N+1) = now + 4294h - 2h = now + 4292h +# Trem(N+1) = now + 4360h - 2h = now + 4358h +TactN="now-4636h" +TretN="now-172h" +TremN="now-2h" +TpubN1="now-175h" +TsbmN1="${TretN}" +TactN1="${TretN}" +TretN1="now+4292h" +TremN1="now+4358h" +csktimes="-P ${TactN} -P sync ${TactN} -A ${TactN} -I ${TretN} -D ${TremN}" +newtimes="-P ${TpubN1} -P sync ${TsbmN1} -A ${TactN1} -I ${TretN1} -D ${TremN1}" +CSK1=$($KEYGEN -k csk-roll2 -l policies/autosign.conf $csktimes $zone 2> keygen.out.$zone.1) +CSK2=$($KEYGEN -k csk-roll2 -l policies/autosign.conf $newtimes $zone 2> keygen.out.$zone.2) +$SETTIME -s -g $H -k $U $TremN -r $U $TremN -d $H $TremN -z $H now-135h "$CSK1" > settime.out.$zone.1 2>&1 +$SETTIME -s -g $O -k $O $TsbmN1 -r $O $TsbmN1 -d $O $TremN -z $O now-135h "$CSK2" > settime.out.$zone.2 2>&1 +# Set key rollover relationship. +key_successor $CSK1 $CSK2 +# Sign zone. +cat template.db.in "${CSK1}.key" "${CSK2}.key" > "$infile" +private_type_record $zone $DEFAULT_ALGORITHM_NUMBER "$CSK1" >> "$infile" +private_type_record $zone $DEFAULT_ALGORITHM_NUMBER "$CSK2" >> "$infile" +cp $infile $zonefile +$SIGNER -S -z -x -s now-1h -e now+30d -o $zone -O raw -f "${zonefile}.signed" $infile > signer.out.$zone.1 2>&1 + +# Step 7: +# The predecessor DNSKEY can be purged, but purge-keys is disabled. +setup step7.csk-roll2.autosign +# Subtract 90 days (default, 2160h) from all the times. +# Tact(N) = now - 4636h - 2160h = now - 6796h +# Tret(N) = now - 172h - 2160h = now - 2332h +# Trem(N) = now - 2h - 2160h = now - 2162h +# Tpub(N+1) = now - 175h - 2160h = now - 2335h +# Tsbm(N+1) = Tret(N) +# Tact(N+1) = Tret(N) +# Tret(N+1) = now + 4294h - 2160h = now + 2134h +# Trem(N+1) = now + 4360h - 2160h = now + 2200h +TactN="now-6796h" +TretN="now-2332h" +TremN="now-2162h" +TpubN1="now-2335h" +TsbmN1="${TretN}" +TactN1="${TretN}" +TretN1="now+2134h" +TremN1="now+2200h" +csktimes="-P ${TactN} -P sync ${TactN} -A ${TactN} -I ${TretN} -D ${TremN}" +newtimes="-P ${TpubN1} -P sync ${TsbmN1} -A ${TactN1} -I ${TretN1} -D ${TremN1}" +CSK1=$($KEYGEN -k csk-roll2 -l policies/autosign.conf $csktimes $zone 2> keygen.out.$zone.1) +CSK2=$($KEYGEN -k csk-roll2 -l policies/autosign.conf $newtimes $zone 2> keygen.out.$zone.2) +$SETTIME -s -g $H -k $U $TremN -r $U $TremN -d $H $TremN -z $H now-135h "$CSK1" > settime.out.$zone.1 2>&1 +$SETTIME -s -g $O -k $O $TsbmN1 -r $O $TsbmN1 -d $O $TremN -z $O now-135h "$CSK2" > settime.out.$zone.2 2>&1 +# Set key rollover relationship. +key_successor $CSK1 $CSK2 +# Sign zone. +cat template.db.in "${CSK1}.key" "${CSK2}.key" > "$infile" +private_type_record $zone $DEFAULT_ALGORITHM_NUMBER "$CSK1" >> "$infile" +private_type_record $zone $DEFAULT_ALGORITHM_NUMBER "$CSK2" >> "$infile" +cp $infile $zonefile +$SIGNER -S -z -x -s now-1h -e now+30d -o $zone -O raw -f "${zonefile}.signed" $infile > signer.out.$zone.1 2>&1 + +# Test #2375, the "three is a crowd" bug, where a new key is introduced but the +# previous rollover has not finished yet. In other words, we have a key KEY2 +# that is the successor of key KEY1, and we introduce a new key KEY3 that is +# the successor of key KEY2: +# +# KEY1 < KEY2 < KEY3. +# +# The expected behavior is that all three keys remain in the zone, and not +# the bug behavior where KEY2 is removed and immediately replaced with KEY3. +# +# Set up a zone that has a KSK (KEY1) and have the successor key (KEY2) +# published as well. +setup three-is-a-crowd.kasp +# These times are the same as step3.ksk-doubleksk.autosign. +TactN="now-60d" +TretN="now" +TremN="now+50h" +TpubN1="now-27h" +TsbmN1="now" +TactN1="${TretN}" +TretN1="now+60d" +TremN1="now+1490h" +ksktimes="-P ${TactN} -A ${TactN} -P sync ${TactN} -I ${TretN} -D ${TremN}" +newtimes="-P ${TpubN1} -A ${TactN1} -P sync ${TsbmN1} -I ${TretN1} -D ${TremN1}" +zsktimes="-P ${TactN} -A ${TactN}" +KSK1=$($KEYGEN -a $DEFAULT_ALGORITHM -L 7200 -f KSK $ksktimes $zone 2> keygen.out.$zone.1) +KSK2=$($KEYGEN -a $DEFAULT_ALGORITHM -L 7200 -f KSK $newtimes $zone 2> keygen.out.$zone.2) +ZSK=$($KEYGEN -a $DEFAULT_ALGORITHM -L 7200 $zsktimes $zone 2> keygen.out.$zone.3) +$SETTIME -s -g $H -k $O $TactN -r $O $TactN -d $O $TactN "$KSK1" > settime.out.$zone.1 2>&1 +$SETTIME -s -g $O -k $R $TpubN1 -r $R $TpubN1 -d $H $TpubN1 "$KSK2" > settime.out.$zone.2 2>&1 +$SETTIME -s -g $O -k $O $TactN -z $O $TactN "$ZSK" > settime.out.$zone.3 2>&1 +# Set key rollover relationship. +key_successor $KSK1 $KSK2 +# Sign zone. +cat template.db.in "${KSK1}.key" "${KSK2}.key" "${ZSK}.key" > "$infile" +private_type_record $zone $DEFAULT_ALGORITHM_NUMBER "$KSK1" >> "$infile" +private_type_record $zone $DEFAULT_ALGORITHM_NUMBER "$KSK2" >> "$infile" +private_type_record $zone $DEFAULT_ALGORITHM_NUMBER "$ZSK" >> "$infile" +cp $infile $zonefile +$SIGNER -S -x -s now-1h -e now+2w -o $zone -O raw -f "${zonefile}.signed" $infile > signer.out.$zone.1 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 0000000..010b05b --- /dev/null +++ b/bin/tests/system/kasp/ns3/template.db.in @@ -0,0 +1,27 @@ +; 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. + +$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 0000000..7b94ace --- /dev/null +++ b/bin/tests/system/kasp/ns3/template2.db.in @@ -0,0 +1,27 @@ +; 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. + +$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.22 +c A 10.0.0.33 +d A 10.0.0.44 diff --git a/bin/tests/system/kasp/ns4/example1.db.in b/bin/tests/system/kasp/ns4/example1.db.in new file mode 100644 index 0000000..c9e537f --- /dev/null +++ b/bin/tests/system/kasp/ns4/example1.db.in @@ -0,0 +1,24 @@ +; 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. + +$TTL 300 +@ IN SOA mname1. . ( + 1 ; serial + 20 ; refresh (20 seconds) + 20 ; retry (20 seconds) + 1814400 ; expire (3 weeks) + 3600 ; minimum (1 hour) + ) + + NS ns4 +ns4 A 10.53.0.4 + +view TXT "view1" diff --git a/bin/tests/system/kasp/ns4/example2.db.in b/bin/tests/system/kasp/ns4/example2.db.in new file mode 100644 index 0000000..c1f16a2 --- /dev/null +++ b/bin/tests/system/kasp/ns4/example2.db.in @@ -0,0 +1,24 @@ +; 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. + +$TTL 300 +@ IN SOA mname1. . ( + 1 ; serial + 20 ; refresh (20 seconds) + 20 ; retry (20 seconds) + 1814400 ; expire (3 weeks) + 3600 ; minimum (1 hour) + ) + + NS ns4 +ns4 A 10.53.0.4 + +view TXT "view2" diff --git a/bin/tests/system/kasp/ns4/named.conf.in b/bin/tests/system/kasp/ns4/named.conf.in new file mode 100644 index 0000000..fff45ab --- /dev/null +++ b/bin/tests/system/kasp/ns4/named.conf.in @@ -0,0 +1,176 @@ +/* + * 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. + */ + +// NS4 + +key rndc_key { + secret "1234abcd8765"; + algorithm hmac-sha256; +}; + +controls { + inet 10.53.0.4 port @CONTROLPORT@ allow { any; } keys { rndc_key; }; +}; + +key "sha1" { + algorithm "hmac-sha1"; + secret "FrSt77yPTFx6hTs4i2tKLB9LmE0="; +}; + +key "sha224" { + algorithm "hmac-sha224"; + secret "hXfwwwiag2QGqblopofai9NuW28q/1rH4CaTnA=="; +}; + +key "sha256" { + algorithm "hmac-sha256"; + secret "R16NojROxtxH/xbDl//ehDsHm5DjWTQ2YXV+hGC2iBY="; +}; + +key "keyforview1" { + algorithm @DEFAULT_HMAC@; + secret "YPfMoAk6h+3iN8MDRQC004iSNHY="; +}; + +key "keyforview2" { + algorithm @DEFAULT_HMAC@; + secret "4xILSZQnuO1UKubXHkYUsvBRPu8="; +}; + +key "keyforview3" { + algorithm @DEFAULT_HMAC@; + secret "C1Azf+gGPMmxrUg/WQINP6eV9Y0="; +}; + +dnssec-policy "test" { + keys { + csk key-directory lifetime 0 algorithm 14; + }; +}; + +options { + query-source address 10.53.0.4; + port @PORT@; + pid-file "named.pid"; + listen-on { 10.53.0.4; }; + listen-on-v6 { none; }; + recursion no; + dnssec-policy "test"; +}; + +view "inherit" { + match-clients { key "sha1"; }; + + /* Inherit dnssec-policy 'test' */ + zone "inherit.inherit.signed" { + type primary; + file "inherit.inherit.signed.db"; + inline-signing yes; + }; + + /* Override dnssec-policy */ + zone "override.inherit.signed" { + type primary; + file "override.inherit.signed.db"; + inline-signing yes; + dnssec-policy "default"; + }; + + /* Unset dnssec-policy */ + zone "none.inherit.signed" { + type primary; + file "none.inherit.signed.db"; + dnssec-policy "none"; + }; +}; + +view "override" { + match-clients { key "sha224"; }; + dnssec-policy "default"; + + /* Inherit dnssec-policy 'test' */ + zone "inherit.override.signed" { + type primary; + file "inherit.override.signed.db"; + inline-signing yes; + }; + + /* Override dnssec-policy */ + zone "override.override.signed" { + type primary; + file "override.override.signed.db"; + inline-signing yes; + dnssec-policy "test"; + }; + + /* Unset dnssec-policy */ + zone "none.override.signed" { + type primary; + file "none.override.signed.db"; + dnssec-policy "none"; + }; +}; + +view "none" { + match-clients { key "sha256"; }; + dnssec-policy "none"; + + /* Inherit dnssec-policy 'none' */ + zone "inherit.none.signed" { + type primary; + file "inherit.none.signed.db"; + }; + + /* Override dnssec-policy */ + zone "override.none.signed" { + type primary; + file "override.none.signed.db"; + inline-signing yes; + dnssec-policy "test"; + }; + + /* Unset dnssec-policy */ + zone "none.none.signed" { + type primary; + file "none.none.signed.db"; + dnssec-policy "none"; + }; +}; + +view "example1" { + match-clients { key "keyforview1"; }; + + allow-update { any; }; + + zone "example.net" { + type primary; + file "example1.db"; + }; +}; + +view "example2" { + match-clients { key "keyforview2"; }; + + zone "example.net" { + type primary; + file "example2.db"; + inline-signing yes; + }; +}; + +view "example3" { + match-clients { key "keyforview3"; }; + zone "example.net" { + in-view example2; + }; +}; diff --git a/bin/tests/system/kasp/ns4/setup.sh b/bin/tests/system/kasp/ns4/setup.sh new file mode 100644 index 0000000..45cb5b3 --- /dev/null +++ b/bin/tests/system/kasp/ns4/setup.sh @@ -0,0 +1,33 @@ +#!/bin/sh -e + +# 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. + +# shellcheck source=conf.sh +. "$SYSTEMTESTTOP/conf.sh" + +echo_i "ns4/setup.sh" + +# +# Set up zones that potentially will be initially signed. +# +for zn in inherit.inherit override.inherit none.inherit \ + inherit.override override.override none.override \ + inherit.none override.none none.none +do + zone="$zn.signed" + echo_i "setting up zone: $zone" + zonefile="${zone}.db" + cp template.db.in $zonefile +done + +cp example1.db.in example1.db +cp example2.db.in example2.db diff --git a/bin/tests/system/kasp/ns4/template.db.in b/bin/tests/system/kasp/ns4/template.db.in new file mode 100644 index 0000000..0f72e9c --- /dev/null +++ b/bin/tests/system/kasp/ns4/template.db.in @@ -0,0 +1,27 @@ +; 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. + +$TTL 300 +@ IN SOA mname1. . ( + 1 ; serial + 20 ; refresh (20 seconds) + 20 ; retry (20 seconds) + 1814400 ; expire (3 weeks) + 3600 ; minimum (1 hour) + ) + + NS ns4 +ns4 A 10.53.0.4 + +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/ns5/named.conf.in b/bin/tests/system/kasp/ns5/named.conf.in new file mode 100644 index 0000000..dae2405 --- /dev/null +++ b/bin/tests/system/kasp/ns5/named.conf.in @@ -0,0 +1,132 @@ +/* + * 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. + */ + +// NS5 + +key rndc_key { + secret "1234abcd8765"; + algorithm hmac-sha256; +}; + +controls { + inet 10.53.0.5 port @CONTROLPORT@ allow { any; } keys { rndc_key; }; +}; + +key "sha1" { + algorithm "hmac-sha1"; + secret "FrSt77yPTFx6hTs4i2tKLB9LmE0="; +}; + +key "sha224" { + algorithm "hmac-sha224"; + secret "hXfwwwiag2QGqblopofai9NuW28q/1rH4CaTnA=="; +}; + +key "sha256" { + algorithm "hmac-sha256"; + secret "R16NojROxtxH/xbDl//ehDsHm5DjWTQ2YXV+hGC2iBY="; +}; + +dnssec-policy "test" { + keys { + csk key-directory lifetime 0 algorithm 14; + }; +}; + +options { + query-source address 10.53.0.5; + port @PORT@; + pid-file "named.pid"; + listen-on { 10.53.0.5; }; + listen-on-v6 { none; }; + recursion no; + dnssec-policy "none"; +}; + +view "inherit" { + match-clients { key "sha1"; }; + + /* Inherit dnssec-policy 'none' */ + zone "inherit.inherit.unsigned" { + type primary; + file "inherit.inherit.unsigned.db"; + }; + + /* Override dnssec-policy */ + zone "override.inherit.unsigned" { + type primary; + file "override.inherit.unsigned.db"; + inline-signing yes; + dnssec-policy "default"; + }; + + /* Unset dnssec-policy */ + zone "none.inherit.unsigned" { + type primary; + file "none.inherit.unsigned.db"; + dnssec-policy "none"; + }; +}; + +view "override" { + match-clients { key "sha224"; }; + dnssec-policy "default"; + + /* Inherit dnssec-policy 'default' */ + zone "inherit.override.unsigned" { + type primary; + file "inherit.override.unsigned.db"; + inline-signing yes; + }; + + /* Override dnssec-policy */ + zone "override.override.unsigned" { + type primary; + file "override.override.unsigned.db"; + inline-signing yes; + dnssec-policy "test"; + }; + + /* Unset dnssec-policy */ + zone "none.override.unsigned" { + type primary; + file "none.override.unsigned.db"; + dnssec-policy "none"; + }; +}; + +view "none" { + match-clients { key "sha256"; }; + dnssec-policy "none"; + + /* Inherit dnssec-policy 'none' */ + zone "inherit.none.unsigned" { + type primary; + file "inherit.none.unsigned.db"; + }; + + /* Override dnssec-policy */ + zone "override.none.unsigned" { + type primary; + file "override.none.unsigned.db"; + inline-signing yes; + dnssec-policy "test"; + }; + + /* Unset dnssec-policy */ + zone "none.none.unsigned" { + type primary; + file "none.none.unsigned.db"; + dnssec-policy "none"; + }; +}; diff --git a/bin/tests/system/kasp/ns5/setup.sh b/bin/tests/system/kasp/ns5/setup.sh new file mode 100644 index 0000000..e51af06 --- /dev/null +++ b/bin/tests/system/kasp/ns5/setup.sh @@ -0,0 +1,30 @@ +#!/bin/sh -e + +# 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. + +# shellcheck source=conf.sh +. "$SYSTEMTESTTOP/conf.sh" + +echo_i "ns5/setup.sh" + +# +# Set up zones that potentially will be initially signed. +# +for zn in inherit.inherit override.inherit none.inherit \ + inherit.override override.override none.override \ + inherit.none override.none none.none +do + zone="$zn.unsigned" + echo_i "setting up zone: $zone" + zonefile="${zone}.db" + cp template.db.in $zonefile +done diff --git a/bin/tests/system/kasp/ns5/template.db.in b/bin/tests/system/kasp/ns5/template.db.in new file mode 100644 index 0000000..6cb07a4 --- /dev/null +++ b/bin/tests/system/kasp/ns5/template.db.in @@ -0,0 +1,27 @@ +; 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. + +$TTL 300 +@ IN SOA mname1. . ( + 1 ; serial + 20 ; refresh (20 seconds) + 20 ; retry (20 seconds) + 1814400 ; expire (3 weeks) + 3600 ; minimum (1 hour) + ) + + NS ns5 +ns5 A 10.53.0.5 + +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/ns6/example.db.in b/bin/tests/system/kasp/ns6/example.db.in new file mode 100644 index 0000000..d6b912c --- /dev/null +++ b/bin/tests/system/kasp/ns6/example.db.in @@ -0,0 +1,26 @@ +; 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. + +$TTL 300 +@ IN SOA mname1. . ( + 1 ; serial + 20 ; refresh (20 seconds) + 20 ; retry (20 seconds) + 1814400 ; expire (3 weeks) + 3600 ; minimum (1 hour) + ) + + NS ns6 +ns6 A 10.53.0.6 + +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/ns6/example2.db.in b/bin/tests/system/kasp/ns6/example2.db.in new file mode 100644 index 0000000..46aed9b --- /dev/null +++ b/bin/tests/system/kasp/ns6/example2.db.in @@ -0,0 +1,26 @@ +; 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. + +$TTL 300 +@ IN SOA mname1. . ( + 2 ; serial + 20 ; refresh (20 seconds) + 20 ; retry (20 seconds) + 1814400 ; expire (3 weeks) + 3600 ; minimum (1 hour) + ) + + NS ns6 +ns6 A 10.53.0.6 + +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/ns6/example3.db.in b/bin/tests/system/kasp/ns6/example3.db.in new file mode 100644 index 0000000..ccbd96a --- /dev/null +++ b/bin/tests/system/kasp/ns6/example3.db.in @@ -0,0 +1,26 @@ +; 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. + +$TTL 400 +@ IN SOA mname1. . ( + 3 ; serial + 20 ; refresh (20 seconds) + 20 ; retry (20 seconds) + 1814400 ; expire (3 weeks) + 3600 ; minimum (1 hour) + ) + + NS ns6 +ns6 A 10.53.0.6 + +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/ns6/named.conf.in b/bin/tests/system/kasp/ns6/named.conf.in new file mode 100644 index 0000000..cb9bd27 --- /dev/null +++ b/bin/tests/system/kasp/ns6/named.conf.in @@ -0,0 +1,97 @@ +/* + * 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. + */ + +// NS6 + +include "policies/kasp.conf"; +include "policies/csk1.conf"; + +options { + query-source address 10.53.0.6; + notify-source 10.53.0.6; + transfer-source 10.53.0.6; + port @PORT@; + pid-file "named.pid"; + listen-on { 10.53.0.6; }; + listen-on-v6 { none; }; + allow-transfer { any; }; + recursion no; + key-directory "."; +}; + +key rndc_key { + secret "1234abcd8765"; + algorithm hmac-sha256; +}; + +controls { + inet 10.53.0.6 port @CONTROLPORT@ allow { any; } keys { rndc_key; }; +}; + +/* This zone switch from dynamic to inline-signing. */ +zone "dynamic2inline.kasp" { + type primary; + file "dynamic2inline.kasp.db"; + allow-update { any; }; + dnssec-policy "default"; +}; + +/* These zones are going insecure. */ +zone "step1.going-insecure.kasp" { + type master; + file "step1.going-insecure.kasp.db"; + inline-signing yes; + dnssec-policy "unsigning"; +}; + +zone "step1.going-insecure-dynamic.kasp" { + type master; + file "step1.going-insecure-dynamic.kasp.db"; + dnssec-policy "unsigning"; + allow-update { any; }; +}; + +zone "step1.going-straight-to-none.kasp" { + type master; + file "step1.going-straight-to-none.kasp.db"; + inline-signing yes; + dnssec-policy "default"; +}; + +/* These are alorithm rollover test zones. */ +zone "step1.algorithm-roll.kasp" { + type primary; + file "step1.algorithm-roll.kasp.db"; + inline-signing yes; + dnssec-policy "rsasha256"; +}; + +zone "step1.csk-algorithm-roll.kasp" { + type primary; + file "step1.csk-algorithm-roll.kasp.db"; + inline-signing yes; + dnssec-policy "csk-algoroll"; +}; + +dnssec-policy "modified" { + keys { + csk lifetime unlimited algorithm rsasha256 2048; + }; +}; + +zone example { + type primary; + file "example.db"; + inline-signing yes; + dnssec-policy modified; +}; diff --git a/bin/tests/system/kasp/ns6/named2.conf.in b/bin/tests/system/kasp/ns6/named2.conf.in new file mode 100644 index 0000000..5f4097e --- /dev/null +++ b/bin/tests/system/kasp/ns6/named2.conf.in @@ -0,0 +1,185 @@ +/* + * 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. + */ + +// NS6 + +include "policies/kasp.conf"; +include "policies/csk2.conf"; + +options { + query-source address 10.53.0.6; + notify-source 10.53.0.6; + transfer-source 10.53.0.6; + port @PORT@; + pid-file "named.pid"; + listen-on { 10.53.0.6; }; + listen-on-v6 { none; }; + allow-transfer { any; }; + recursion no; +}; + +key rndc_key { + secret "1234abcd8765"; + algorithm hmac-sha256; +}; + +controls { + inet 10.53.0.6 port @CONTROLPORT@ allow { any; } keys { rndc_key; }; +}; + +/* This zone switch from dynamic to inline-signing. */ +zone "dynamic2inline.kasp" { + type primary; + file "dynamic2inline.kasp.db"; + allow-update { any; }; + inline-signing yes; + dnssec-policy "default"; +}; + +/* Zones for testing going insecure. */ +zone "step1.going-insecure.kasp" { + type master; + file "step1.going-insecure.kasp.db"; + inline-signing yes; + dnssec-policy "insecure"; +}; + +zone "step2.going-insecure.kasp" { + type master; + file "step2.going-insecure.kasp.db"; + inline-signing yes; + dnssec-policy "insecure"; +}; + +zone "step1.going-insecure-dynamic.kasp" { + type master; + file "step1.going-insecure-dynamic.kasp.db"; + dnssec-policy "insecure"; + allow-update { any; }; +}; + +zone "step2.going-insecure-dynamic.kasp" { + type master; + file "step2.going-insecure-dynamic.kasp.db"; + dnssec-policy "insecure"; + allow-update { any; }; +}; + +zone "step1.going-straight-to-none.kasp" { + type master; + file "step1.going-straight-to-none.kasp.db"; + dnssec-policy "none"; +}; + +/* + * Zones for testing KSK/ZSK algorithm roll. + */ +zone "step1.algorithm-roll.kasp" { + type primary; + file "step1.algorithm-roll.kasp.db"; + inline-signing yes; + dnssec-policy "ecdsa256"; +}; + +zone "step2.algorithm-roll.kasp" { + type primary; + file "step2.algorithm-roll.kasp.db"; + inline-signing yes; + dnssec-policy "ecdsa256"; +}; + +zone "step3.algorithm-roll.kasp" { + type primary; + file "step3.algorithm-roll.kasp.db"; + inline-signing yes; + dnssec-policy "ecdsa256"; +}; + +zone "step4.algorithm-roll.kasp" { + type primary; + file "step4.algorithm-roll.kasp.db"; + inline-signing yes; + dnssec-policy "ecdsa256"; +}; + +zone "step5.algorithm-roll.kasp" { + type primary; + file "step5.algorithm-roll.kasp.db"; + inline-signing yes; + dnssec-policy "ecdsa256"; +}; + +zone "step6.algorithm-roll.kasp" { + type primary; + file "step6.algorithm-roll.kasp.db"; + inline-signing yes; + dnssec-policy "ecdsa256"; +}; + +/* + * Zones for testing CSK algorithm roll. + */ +zone "step1.csk-algorithm-roll.kasp" { + type primary; + file "step1.csk-algorithm-roll.kasp.db"; + inline-signing yes; + dnssec-policy "csk-algoroll"; +}; + +zone "step2.csk-algorithm-roll.kasp" { + type primary; + file "step2.csk-algorithm-roll.kasp.db"; + inline-signing yes; + dnssec-policy "csk-algoroll"; +}; + +zone "step3.csk-algorithm-roll.kasp" { + type primary; + file "step3.csk-algorithm-roll.kasp.db"; + inline-signing yes; + dnssec-policy "csk-algoroll"; +}; + +zone "step4.csk-algorithm-roll.kasp" { + type primary; + file "step4.csk-algorithm-roll.kasp.db"; + inline-signing yes; + dnssec-policy "csk-algoroll"; +}; + +zone "step5.csk-algorithm-roll.kasp" { + type primary; + file "step5.csk-algorithm-roll.kasp.db"; + inline-signing yes; + dnssec-policy "csk-algoroll"; +}; + +zone "step6.csk-algorithm-roll.kasp" { + type primary; + file "step6.csk-algorithm-roll.kasp.db"; + inline-signing yes; + dnssec-policy "csk-algoroll"; +}; + +dnssec-policy "modified" { + keys { + csk lifetime unlimited algorithm rsasha256 2048; + }; +}; + +zone example { + type primary; + file "example.db"; + inline-signing yes; + dnssec-policy modified; +}; diff --git a/bin/tests/system/kasp/ns6/policies/csk1.conf.in b/bin/tests/system/kasp/ns6/policies/csk1.conf.in new file mode 100644 index 0000000..a5ff042 --- /dev/null +++ b/bin/tests/system/kasp/ns6/policies/csk1.conf.in @@ -0,0 +1,30 @@ +/* + * 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. + */ + +dnssec-policy "csk-algoroll" { + signatures-refresh P5D; + signatures-validity 30d; + signatures-validity-dnskey 30d; + + keys { + csk lifetime unlimited algorithm rsasha256; + }; + + dnskey-ttl 1h; + publish-safety PT1H; + retire-safety 2h; + zone-propagation-delay 3600; + max-zone-ttl 6h; + parent-propagation-delay pt1h; + parent-ds-ttl 7200; +}; diff --git a/bin/tests/system/kasp/ns6/policies/csk2.conf.in b/bin/tests/system/kasp/ns6/policies/csk2.conf.in new file mode 100644 index 0000000..6d290c3 --- /dev/null +++ b/bin/tests/system/kasp/ns6/policies/csk2.conf.in @@ -0,0 +1,30 @@ +/* + * 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. + */ + +dnssec-policy "csk-algoroll" { + signatures-refresh P5D; + signatures-validity 30d; + signatures-validity-dnskey 30d; + + keys { + csk lifetime unlimited algorithm @DEFAULT_ALGORITHM@; + }; + + dnskey-ttl 1h; + publish-safety PT1H; + retire-safety 2h; + zone-propagation-delay 3600; + max-zone-ttl 6h; + parent-propagation-delay pt1h; + parent-ds-ttl 7200; +}; diff --git a/bin/tests/system/kasp/ns6/policies/kasp-fips.conf.in b/bin/tests/system/kasp/ns6/policies/kasp-fips.conf.in new file mode 100644 index 0000000..810b91d --- /dev/null +++ b/bin/tests/system/kasp/ns6/policies/kasp-fips.conf.in @@ -0,0 +1,63 @@ +/* + * 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. + */ + +dnssec-policy "unsigning" { + dnskey-ttl 7200; + + keys { + ksk key-directory lifetime unlimited algorithm @DEFAULT_ALGORITHM@; + zsk key-directory lifetime P60D algorithm @DEFAULT_ALGORITHM@; + }; +}; + +dnssec-policy "nsec3" { + nsec3param iterations 0 optout no salt-length 0; +}; + +dnssec-policy "rsasha256" { + signatures-refresh P5D; + signatures-validity 30d; + signatures-validity-dnskey 30d; + + keys { + ksk lifetime unlimited algorithm rsasha256; + zsk lifetime unlimited algorithm rsasha256; + }; + + dnskey-ttl 1h; + publish-safety PT1H; + retire-safety 2h; + zone-propagation-delay 3600; + max-zone-ttl 6h; + parent-propagation-delay pt1h; + parent-ds-ttl 7200; +}; + +dnssec-policy "ecdsa256" { + signatures-refresh P5D; + signatures-validity 30d; + signatures-validity-dnskey 30d; + + keys { + ksk lifetime unlimited algorithm ecdsa256; + zsk lifetime unlimited algorithm ecdsa256; + }; + + dnskey-ttl 1h; + publish-safety PT1H; + retire-safety 2h; + zone-propagation-delay 3600; + max-zone-ttl 6h; + parent-propagation-delay pt1h; + parent-ds-ttl 7200; +}; diff --git a/bin/tests/system/kasp/ns6/policies/kasp.conf.in b/bin/tests/system/kasp/ns6/policies/kasp.conf.in new file mode 100644 index 0000000..d634b76 --- /dev/null +++ b/bin/tests/system/kasp/ns6/policies/kasp.conf.in @@ -0,0 +1,33 @@ +/* + * 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. + */ + +include "policies/kasp-fips.conf"; + +dnssec-policy "rsasha1" { + signatures-refresh P5D; + signatures-validity 30d; + signatures-validity-dnskey 30d; + + keys { + ksk lifetime unlimited algorithm rsasha1; + zsk lifetime unlimited algorithm rsasha1; + }; + + dnskey-ttl 1h; + publish-safety PT1H; + retire-safety 2h; + zone-propagation-delay 3600; + max-zone-ttl 6h; + parent-propagation-delay pt1h; + parent-ds-ttl 7200; +}; diff --git a/bin/tests/system/kasp/ns6/setup.sh b/bin/tests/system/kasp/ns6/setup.sh new file mode 100644 index 0000000..3a18750 --- /dev/null +++ b/bin/tests/system/kasp/ns6/setup.sh @@ -0,0 +1,409 @@ +#!/bin/sh -e + +# 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. + +# shellcheck source=conf.sh +. "$SYSTEMTESTTOP/conf.sh" + +echo_i "ns6/setup.sh" + +setup() { + zone="$1" + echo_i "setting up zone: $zone" + zonefile="${zone}.db" + infile="${zone}.db.infile" +} + +# Make lines shorter by storing key states in environment variables. +H="HIDDEN" +R="RUMOURED" +O="OMNIPRESENT" +U="UNRETENTIVE" + +# The child zones (step1, step2) beneath these zones represent the various +# steps of unsigning a zone. +for zn in going-insecure.kasp going-insecure-dynamic.kasp +do + # Step 1: + # Set up a zone with dnssec-policy that is going insecure. + setup step1.$zn + echo "$zone" >> zones + T="now-10d" + ksktimes="-P $T -A $T -P sync $T" + zsktimes="-P $T -A $T" + KSK=$($KEYGEN -a $DEFAULT_ALGORITHM -L 7200 -f KSK $ksktimes $zone 2> keygen.out.$zone.1) + ZSK=$($KEYGEN -a $DEFAULT_ALGORITHM -L 7200 $zsktimes $zone 2> keygen.out.$zone.2) + cat template.db.in "${KSK}.key" "${ZSK}.key" > "$infile" + private_type_record $zone $DEFAULT_ALGORITHM_NUMBER "$KSK" >> "$infile" + private_type_record $zone $DEFAULT_ALGORITHM_NUMBER "$ZSK" >> "$infile" + cp $infile $zonefile + $SIGNER -S -x -s now-1h -e now+2w -o $zone -O raw -f "${zonefile}.signed" $infile > signer.out.$zone.1 2>&1 + + # Step 2: + # Set up a zone with dnssec-policy that is going insecure. Don't add + # this zone to the zones file, because this zone is no longer expected + # to be fully signed. + setup step2.$zn + # The DS was withdrawn from the parent zone 26 hours ago. + Trem="now-26h" + ksktimes="-P $T -A $T -P sync $T" + zsktimes="-P $T -A $T" + KSK=$($KEYGEN -a $DEFAULT_ALGORITHM -L 7200 -f KSK $ksktimes $zone 2> keygen.out.$zone.1) + ZSK=$($KEYGEN -a $DEFAULT_ALGORITHM -L 7200 $zsktimes $zone 2> keygen.out.$zone.2) + $SETTIME -s -g $H -k $O $T -r $O $T -d $U $Trem -D ds $Trem "$KSK" > settime.out.$zone.1 2>&1 + $SETTIME -s -g $H -k $O $T -z $O $T "$ZSK" > settime.out.$zone.2 2>&1 + # Fake lifetime of old algorithm keys. + echo "Lifetime: 0" >> "${KSK}.state" + echo "Lifetime: 5184000" >> "${ZSK}.state" + cat template.db.in "${KSK}.key" "${ZSK}.key" > "$infile" + private_type_record $zone $DEFAULT_ALGORITHM_NUMBER "$KSK" >> "$infile" + private_type_record $zone $DEFAULT_ALGORITHM_NUMBER "$ZSK" >> "$infile" + cp $infile $zonefile + $SIGNER -S -x -s now-1h -e now+2w -o $zone -O raw -f "${zonefile}.signed" $infile > signer.out.$zone.1 2>&1 +done + +# This zone is going straight to "none" policy. This is undefined behavior. +setup step1.going-straight-to-none.kasp +echo "$zone" >> zones +TactN="now" +csktimes="-P ${TactN} -A ${TactN} -P sync ${TactN}" +CSK=$($KEYGEN -k default $csktimes $zone 2> keygen.out.$zone.1) +$SETTIME -s -g $O -k $O $TactN -z $O $TactN -r $O $TactN -d $O $TactN "$CSK" > settime.out.$zone.1 2>&1 +cat template.db.in "${CSK}.key" > "$infile" +private_type_record $zone $DEFAULT_ALGORITHM_NUMBER "$CSK" >> "$infile" +cp $infile $zonefile +$SIGNER -S -z -x -s now-1h -e now+2w -o $zone -O raw -f "${zonefile}.signed" $infile > signer.out.$zone.1 2>&1 + +# +# The zones at algorithm-roll.kasp represent the various steps of a ZSK/KSK +# algorithm rollover. +# + +# Step 1: +# Introduce the first key. This will immediately be active. +setup step1.algorithm-roll.kasp +echo "$zone" >> zones +TactN="now" +ksktimes="-P ${TactN} -A ${TactN} -P sync ${TactN}" +zsktimes="-P ${TactN} -A ${TactN}" +KSK=$($KEYGEN -a RSASHA256 -L 3600 -f KSK $ksktimes $zone 2> keygen.out.$zone.1) +ZSK=$($KEYGEN -a RSASHA256 -L 3600 $zsktimes $zone 2> keygen.out.$zone.2) +$SETTIME -s -g $O -k $O $TactN -r $O $TactN -d $O $TactN "$KSK" > settime.out.$zone.1 2>&1 +$SETTIME -s -g $O -k $O $TactN -z $O $TactN "$ZSK" > settime.out.$zone.2 2>&1 +cat template.db.in "${KSK}.key" "${ZSK}.key" > "$infile" +private_type_record $zone 8 "$KSK" >> "$infile" +private_type_record $zone 8 "$ZSK" >> "$infile" +cp $infile $zonefile +$SIGNER -S -x -s now-1h -e now+2w -o $zone -O raw -f "${zonefile}.signed" $infile > signer.out.$zone.1 2>&1 + +# Step 2: +# After the publication interval has passed the DNSKEY is OMNIPRESENT. +setup step2.algorithm-roll.kasp +# The time passed since the new algorithm keys have been introduced is 3 hours. +TactN="now-3h" +TpubN1="now-3h" +# Tsbm(N+1) = TpubN1 + Ipub = now + TTLsig + Dprp + publish-safety = +# now - 3h + 6h + 1h + 1h = now + 5h +TsbmN1="now+5h" +ksk1times="-P ${TactN} -A ${TactN} -P sync ${TactN} -I now" +zsk1times="-P ${TactN} -A ${TactN} -I now" +ksk2times="-P ${TpubN1} -A ${TpubN1} -P sync ${TsbmN1}" +zsk2times="-P ${TpubN1} -A ${TpubN1}" +KSK1=$($KEYGEN -a RSASHA256 -L 3600 -f KSK $ksk1times $zone 2> keygen.out.$zone.1) +ZSK1=$($KEYGEN -a RSASHA256 -L 3600 $zsk1times $zone 2> keygen.out.$zone.2) +KSK2=$($KEYGEN -a $DEFAULT_ALGORITHM -L 3600 -f KSK $ksk2times $zone 2> keygen.out.$zone.3) +ZSK2=$($KEYGEN -a $DEFAULT_ALGORITHM -L 3600 $zsk2times $zone 2> keygen.out.$zone.4) +$SETTIME -s -g $H -k $O $TactN -r $O $TactN -d $O $TactN "$KSK1" > settime.out.$zone.1 2>&1 +$SETTIME -s -g $H -k $O $TactN -z $O $TactN "$ZSK1" > settime.out.$zone.2 2>&1 +$SETTIME -s -g $O -k $R $TpubN1 -r $R $TpubN1 -d $H $TpubN1 "$KSK2" > settime.out.$zone.3 2>&1 +$SETTIME -s -g $O -k $R $TpubN1 -z $R $TpubN1 "$ZSK2" > settime.out.$zone.4 2>&1 +# Fake lifetime of old algorithm keys. +echo "Lifetime: 0" >> "${KSK1}.state" +echo "Lifetime: 0" >> "${ZSK1}.state" +cat template.db.in "${KSK1}.key" "${ZSK1}.key" "${KSK2}.key" "${ZSK2}.key" > "$infile" +private_type_record $zone 8 "$KSK1" >> "$infile" +private_type_record $zone 8 "$ZSK1" >> "$infile" +private_type_record $zone $DEFAULT_ALGORITHM_NUMBER "$KSK2" >> "$infile" +private_type_record $zone $DEFAULT_ALGORITHM_NUMBER "$ZSK2" >> "$infile" +cp $infile $zonefile +$SIGNER -S -x -s now-1h -e now+2w -o $zone -O raw -f "${zonefile}.signed" $infile > signer.out.$zone.1 2>&1 + +# Step 3: +# The zone signatures are also OMNIPRESENT. +setup step3.algorithm-roll.kasp +# The time passed since the new algorithm keys have been introduced is 9 hours. +TactN="now-9h" +TretN="now-6h" +TpubN1="now-9h" +TsbmN1="now-1h" +ksk1times="-P ${TactN} -A ${TactN} -P sync ${TactN} -I ${TretN}" +zsk1times="-P ${TactN} -A ${TactN} -I ${TretN}" +ksk2times="-P ${TpubN1} -A ${TpubN1} -P sync ${TsbmN1}" +zsk2times="-P ${TpubN1} -A ${TpubN1}" +KSK1=$($KEYGEN -a RSASHA256 -L 3600 -f KSK $ksk1times $zone 2> keygen.out.$zone.1) +ZSK1=$($KEYGEN -a RSASHA256 -L 3600 $zsk1times $zone 2> keygen.out.$zone.2) +KSK2=$($KEYGEN -a $DEFAULT_ALGORITHM -L 3600 -f KSK $ksk2times $zone 2> keygen.out.$zone.3) +ZSK2=$($KEYGEN -a $DEFAULT_ALGORITHM -L 3600 $zsk2times $zone 2> keygen.out.$zone.4) +$SETTIME -s -g $H -k $O $TactN -r $O $TactN -d $O $TactN "$KSK1" > settime.out.$zone.1 2>&1 +$SETTIME -s -g $H -k $O $TactN -z $O $TactN "$ZSK1" > settime.out.$zone.2 2>&1 +$SETTIME -s -g $O -k $O $TpubN1 -r $O $TpubN1 -d $H $TpubN1 "$KSK2" > settime.out.$zone.3 2>&1 +$SETTIME -s -g $O -k $O $TpubN1 -z $R $TpubN1 "$ZSK2" > settime.out.$zone.4 2>&1 +# Fake lifetime of old algorithm keys. +echo "Lifetime: 0" >> "${KSK1}.state" +echo "Lifetime: 0" >> "${ZSK1}.state" +cat template.db.in "${KSK1}.key" "${ZSK1}.key" "${KSK2}.key" "${ZSK2}.key" > "$infile" +private_type_record $zone 8 "$KSK1" >> "$infile" +private_type_record $zone 8 "$ZSK1" >> "$infile" +private_type_record $zone $DEFAULT_ALGORITHM_NUMBER "$KSK2" >> "$infile" +private_type_record $zone $DEFAULT_ALGORITHM_NUMBER "$ZSK2" >> "$infile" +cp $infile $zonefile +$SIGNER -S -x -s now-1h -e now+2w -o $zone -O raw -f "${zonefile}.signed" $infile > signer.out.$zone.1 2>&1 + +# Step 4: +# The DS is swapped and can become OMNIPRESENT. +setup step4.algorithm-roll.kasp +# The time passed since the DS has been swapped is 29 hours. +TactN="now-38h" +TretN="now-35h" +TpubN1="now-38h" +TsbmN1="now-30h" +TactN1="now-29h" +ksk1times="-P ${TactN} -A ${TactN} -P sync ${TactN} -I ${TretN}" +zsk1times="-P ${TactN} -A ${TactN} -I ${TretN}" +ksk2times="-P ${TpubN1} -A ${TpubN1} -P sync ${TsbmN1}" +zsk2times="-P ${TpubN1} -A ${TpubN1}" +KSK1=$($KEYGEN -a RSASHA256 -L 3600 -f KSK $ksk1times $zone 2> keygen.out.$zone.1) +ZSK1=$($KEYGEN -a RSASHA256 -L 3600 $zsk1times $zone 2> keygen.out.$zone.2) +KSK2=$($KEYGEN -a $DEFAULT_ALGORITHM -L 3600 -f KSK $ksk2times $zone 2> keygen.out.$zone.3) +ZSK2=$($KEYGEN -a $DEFAULT_ALGORITHM -L 3600 $zsk2times $zone 2> keygen.out.$zone.4) +$SETTIME -s -g $H -k $O $TactN -r $O $TactN -d $U $TactN1 -D ds $TactN1 "$KSK1" > settime.out.$zone.1 2>&1 +$SETTIME -s -g $H -k $O $TactN -z $O $TactN "$ZSK1" > settime.out.$zone.2 2>&1 +$SETTIME -s -g $O -k $O $TpubN1 -r $O $TpubN1 -d $R $TactN1 -P ds $TactN1 "$KSK2" > settime.out.$zone.3 2>&1 +$SETTIME -s -g $O -k $O $TpubN1 -z $R $TpubN1 "$ZSK2" > settime.out.$zone.4 2>&1 +# Fake lifetime of old algorithm keys. +echo "Lifetime: 0" >> "${KSK1}.state" +echo "Lifetime: 0" >> "${ZSK1}.state" +cat template.db.in "${KSK1}.key" "${ZSK1}.key" "${KSK2}.key" "${ZSK2}.key" > "$infile" +private_type_record $zone 8 "$KSK1" >> "$infile" +private_type_record $zone 8 "$ZSK1" >> "$infile" +private_type_record $zone $DEFAULT_ALGORITHM_NUMBER "$KSK2" >> "$infile" +private_type_record $zone $DEFAULT_ALGORITHM_NUMBER "$ZSK2" >> "$infile" +cp $infile $zonefile +$SIGNER -S -x -s now-1h -e now+2w -o $zone -O raw -f "${zonefile}.signed" $infile > signer.out.$zone.1 2>&1 + +# Step 5: +# The DNSKEY is removed long enough to be HIDDEN. +setup step5.algorithm-roll.kasp +# The time passed since the DNSKEY has been removed is 2 hours. +TactN="now-40h" +TretN="now-37h" +TremN="now-2h" +TpubN1="now-40h" +TsbmN1="now-32h" +TactN1="now-31h" +ksk1times="-P ${TactN} -A ${TactN} -P sync ${TactN} -I ${TretN}" +zsk1times="-P ${TactN} -A ${TactN} -I ${TretN}" +ksk2times="-P ${TpubN1} -A ${TpubN1} -P sync ${TsbmN1}" +zsk2times="-P ${TpubN1} -A ${TpubN1}" +KSK1=$($KEYGEN -a RSASHA256 -L 3600 -f KSK $ksk1times $zone 2> keygen.out.$zone.1) +ZSK1=$($KEYGEN -a RSASHA256 -L 3600 $zsk1times $zone 2> keygen.out.$zone.2) +KSK2=$($KEYGEN -a $DEFAULT_ALGORITHM -L 3600 -f KSK $ksk2times $zone 2> keygen.out.$zone.3) +ZSK2=$($KEYGEN -a $DEFAULT_ALGORITHM -L 3600 $zsk2times $zone 2> keygen.out.$zone.4) +$SETTIME -s -g $H -k $U $TremN -r $U $TremN -d $H $TactN1 "$KSK1" > settime.out.$zone.1 2>&1 +$SETTIME -s -g $H -k $U $TremN -z $U $TremN "$ZSK1" > settime.out.$zone.2 2>&1 +$SETTIME -s -g $O -k $O $TpubN1 -r $O $TpubN1 -d $O $TactN1 "$KSK2" > settime.out.$zone.3 2>&1 +$SETTIME -s -g $O -k $O $TpubN1 -z $R $TpubN1 "$ZSK2" > settime.out.$zone.4 2>&1 +# Fake lifetime of old algorithm keys. +echo "Lifetime: 0" >> "${KSK1}.state" +echo "Lifetime: 0" >> "${ZSK1}.state" +cat template.db.in "${KSK1}.key" "${ZSK1}.key" "${KSK2}.key" "${ZSK2}.key" > "$infile" +private_type_record $zone 8 "$KSK1" >> "$infile" +private_type_record $zone 8 "$ZSK1" >> "$infile" +private_type_record $zone $DEFAULT_ALGORITHM_NUMBER "$KSK2" >> "$infile" +private_type_record $zone $DEFAULT_ALGORITHM_NUMBER "$ZSK2" >> "$infile" +cp $infile $zonefile +$SIGNER -S -x -s now-1h -e now+2w -o $zone -O raw -f "${zonefile}.signed" $infile > signer.out.$zone.1 2>&1 + +# Step 6: +# The RRSIGs have been removed long enough to be HIDDEN. +setup step6.algorithm-roll.kasp +# Additional time passed: 7h. +TactN="now-47h" +TretN="now-44h" +TremN="now-7h" +TpubN1="now-47h" +TsbmN1="now-39h" +TactN1="now-38h" +TdeaN="now-9h" +ksk1times="-P ${TactN} -A ${TactN} -P sync ${TactN} -I ${TretN}" +zsk1times="-P ${TactN} -A ${TactN} -I ${TretN}" +ksk2times="-P ${TpubN1} -A ${TpubN1} -P sync ${TsbmN1}" +zsk2times="-P ${TpubN1} -A ${TpubN1}" +KSK1=$($KEYGEN -a RSASHA256 -L 3600 -f KSK $ksk1times $zone 2> keygen.out.$zone.1) +ZSK1=$($KEYGEN -a RSASHA256 -L 3600 $zsk1times $zone 2> keygen.out.$zone.2) +KSK2=$($KEYGEN -a $DEFAULT_ALGORITHM -L 3600 -f KSK $ksk2times $zone 2> keygen.out.$zone.3) +ZSK2=$($KEYGEN -a $DEFAULT_ALGORITHM -L 3600 $zsk2times $zone 2> keygen.out.$zone.4) +$SETTIME -s -g $H -k $H $TremN -r $U $TdeaN -d $H $TactN1 "$KSK1" > settime.out.$zone.1 2>&1 +$SETTIME -s -g $H -k $H $TremN -z $U $TdeaN "$ZSK1" > settime.out.$zone.2 2>&1 +$SETTIME -s -g $O -k $O $TpubN1 -r $O $TpubN1 -d $O $TactN1 "$KSK2" > settime.out.$zone.3 2>&1 +$SETTIME -s -g $O -k $O $TpubN1 -z $R $TpubN1 "$ZSK2" > settime.out.$zone.4 2>&1 +# Fake lifetime of old algorithm keys. +echo "Lifetime: 0" >> "${KSK1}.state" +echo "Lifetime: 0" >> "${ZSK1}.state" +cat template.db.in "${KSK1}.key" "${ZSK1}.key" "${KSK2}.key" "${ZSK2}.key" > "$infile" +private_type_record $zone 8 "$KSK1" >> "$infile" +private_type_record $zone 8 "$ZSK1" >> "$infile" +private_type_record $zone $DEFAULT_ALGORITHM_NUMBER "$KSK2" >> "$infile" +private_type_record $zone $DEFAULT_ALGORITHM_NUMBER "$ZSK2" >> "$infile" +cp $infile $zonefile +$SIGNER -S -x -s now-1h -e now+2w -o $zone -O raw -f "${zonefile}.signed" $infile > signer.out.$zone.1 2>&1 + +# +# The zones at csk-algorithm-roll.kasp represent the various steps of a CSK +# algorithm rollover. +# + +# Step 1: +# Introduce the first key. This will immediately be active. +setup step1.csk-algorithm-roll.kasp +echo "$zone" >> zones +TactN="now" +csktimes="-P ${TactN} -P sync ${TactN} -A ${TactN}" +CSK=$($KEYGEN -k csk-algoroll -l policies/csk1.conf $csktimes $zone 2> keygen.out.$zone.1) +$SETTIME -s -g $O -k $O $TactN -r $O $TactN -z $O $TactN -d $O $TactN "$CSK" > settime.out.$zone.1 2>&1 +cat template.db.in "${CSK}.key" > "$infile" +private_type_record $zone 5 "$CSK" >> "$infile" +cp $infile $zonefile +$SIGNER -S -x -z -s now-1h -e now+2w -o $zone -O raw -f "${zonefile}.signed" $infile > signer.out.$zone.1 2>&1 + +# Step 2: +# After the publication interval has passed the DNSKEY is OMNIPRESENT. +setup step2.csk-algorithm-roll.kasp +# The time passed since the new algorithm keys have been introduced is 3 hours. +TactN="now-3h" +TpubN1="now-3h" +csktimes="-P ${TactN} -A ${TactN} -P sync ${TactN} -I now" +newtimes="-P ${TpubN1} -A ${TpubN1}" +CSK1=$($KEYGEN -k csk-algoroll -l policies/csk1.conf $csktimes $zone 2> keygen.out.$zone.1) +CSK2=$($KEYGEN -k csk-algoroll -l policies/csk2.conf $newtimes $zone 2> keygen.out.$zone.2) +$SETTIME -s -g $H -k $O $TactN -r $O $TactN -z $O $TactN -d $O $TactN "$CSK1" > settime.out.$zone.1 2>&1 +$SETTIME -s -g $O -k $R $TpubN1 -r $R $TpubN1 -z $R $TpubN1 -d $H $TpubN1 "$CSK2" > settime.out.$zone.2 2>&1 +# Fake lifetime of old algorithm keys. +echo "Lifetime: 0" >> "${CSK1}.state" +cat template.db.in "${CSK1}.key" "${CSK2}.key" > "$infile" +private_type_record $zone 5 "$CSK1" >> "$infile" +private_type_record $zone $DEFAULT_ALGORITHM_NUMBER "$CSK2" >> "$infile" +cp $infile $zonefile +$SIGNER -S -x -z -s now-1h -e now+2w -o $zone -O raw -f "${zonefile}.signed" $infile > signer.out.$zone.1 2>&1 + +# Step 3: +# The zone signatures are also OMNIPRESENT. +setup step3.csk-algorithm-roll.kasp +# The time passed since the new algorithm keys have been introduced is 9 hours. +TactN="now-9h" +TretN="now-6h" +TpubN1="now-9h" +TactN1="now-6h" +csktimes="-P ${TactN} -A ${TactN} -P sync ${TactN} -I ${TretN}" +newtimes="-P ${TpubN1} -A ${TpubN1}" +CSK1=$($KEYGEN -k csk-algoroll -l policies/csk1.conf $csktimes $zone 2> keygen.out.$zone.1) +CSK2=$($KEYGEN -k csk-algoroll -l policies/csk2.conf $newtimes $zone 2> keygen.out.$zone.2) +$SETTIME -s -g $H -k $O $TactN -r $O $TactN -z $O $TactN -d $O $TactN "$CSK1" > settime.out.$zone.1 2>&1 +$SETTIME -s -g $O -k $O $TactN1 -r $O $TactN1 -z $R $TpubN1 -d $H $TpubN1 "$CSK2" > settime.out.$zone.2 2>&1 +# Fake lifetime of old algorithm keys. +echo "Lifetime: 0" >> "${CSK1}.state" +cat template.db.in "${CSK1}.key" "${CSK2}.key" > "$infile" +private_type_record $zone 5 "$CSK1" >> "$infile" +private_type_record $zone $DEFAULT_ALGORITHM_NUMBER "$CSK2" >> "$infile" +cp $infile $zonefile +$SIGNER -S -x -z -s now-1h -e now+2w -o $zone -O raw -f "${zonefile}.signed" $infile > signer.out.$zone.1 2>&1 + +# Step 4: +# The DS is swapped and can become OMNIPRESENT. +setup step4.csk-algorithm-roll.kasp +# The time passed since the DS has been swapped is 29 hours. +TactN="now-38h" +TretN="now-35h" +TpubN1="now-38h" +TactN1="now-35h" +TsubN1="now-29h" +csktimes="-P ${TactN} -A ${TactN} -P sync ${TactN} -I ${TretN}" +newtimes="-P ${TpubN1} -A ${TpubN1}" +CSK1=$($KEYGEN -k csk-algoroll -l policies/csk1.conf $csktimes $zone 2> keygen.out.$zone.1) +CSK2=$($KEYGEN -k csk-algoroll -l policies/csk2.conf $newtimes $zone 2> keygen.out.$zone.2) +$SETTIME -s -g $H -k $O $TactN -r $O $TactN -z $O $TactN -d $U $TactN1 -D ds $TactN1 "$CSK1" > settime.out.$zone.1 2>&1 +$SETTIME -s -g $O -k $O $TactN1 -r $O $TactN1 -z $O $TsubN1 -d $R $TsubN1 -P ds $TsubN1 "$CSK2" > settime.out.$zone.2 2>&1 +# Fake lifetime of old algorithm keys. +echo "Lifetime: 0" >> "${CSK1}.state" +cat template.db.in "${CSK1}.key" "${CSK2}.key" > "$infile" +private_type_record $zone 5 "$CSK1" >> "$infile" +private_type_record $zone $DEFAULT_ALGORITHM_NUMBER "$CSK2" >> "$infile" +cp $infile $zonefile +$SIGNER -S -x -z -s now-1h -e now+2w -o $zone -O raw -f "${zonefile}.signed" $infile > signer.out.$zone.1 2>&1 + +# Step 5: +# The DNSKEY is removed long enough to be HIDDEN. +setup step5.csk-algorithm-roll.kasp +# The time passed since the DNSKEY has been removed is 2 hours. +TactN="now-40h" +TretN="now-37h" +TremN="now-2h" +TpubN1="now-40h" +TactN1="now-37h" +TsubN1="now-31h" +csktimes="-P ${TactN} -A ${TactN} -P sync ${TactN} -I ${TretN}" +newtimes="-P ${TpubN1} -A ${TpubN1}" +CSK1=$($KEYGEN -k csk-algoroll -l policies/csk1.conf $csktimes $zone 2> keygen.out.$zone.1) +CSK2=$($KEYGEN -k csk-algoroll -l policies/csk2.conf $newtimes $zone 2> keygen.out.$zone.2) +$SETTIME -s -g $H -k $U $TremN -r $U $TremN -z $U $TremN -d $H $TremN "$CSK1" > settime.out.$zone.1 2>&1 +$SETTIME -s -g $O -k $O $TactN1 -r $O $TactN1 -z $O $TsubN1 -d $O $TremN "$CSK2" > settime.out.$zone.2 2>&1 +# Fake lifetime of old algorithm keys. +echo "Lifetime: 0" >> "${CSK1}.state" +cat template.db.in "${CSK1}.key" "${CSK2}.key" > "$infile" +private_type_record $zone 5 "$CSK1" >> "$infile" +private_type_record $zone $DEFAULT_ALGORITHM_NUMBER "$CSK2" >> "$infile" +cp $infile $zonefile +$SIGNER -S -x -z -s now-1h -e now+2w -o $zone -O raw -f "${zonefile}.signed" $infile > signer.out.$zone.1 2>&1 + +# Step 6: +# The RRSIGs have been removed long enough to be HIDDEN. +setup step6.csk-algorithm-roll.kasp +# Additional time passed: 7h. +TactN="now-47h" +TretN="now-44h" +TdeaN="now-9h" +TremN="now-7h" +TpubN1="now-47h" +TactN1="now-44h" +TsubN1="now-38h" +csktimes="-P ${TactN} -A ${TactN} -P sync ${TactN} -I ${TretN}" +newtimes="-P ${TpubN1} -A ${TpubN1}" +CSK1=$($KEYGEN -k csk-algoroll -l policies/csk1.conf $csktimes $zone 2> keygen.out.$zone.1) +CSK2=$($KEYGEN -k csk-algoroll -l policies/csk2.conf $newtimes $zone 2> keygen.out.$zone.2) +$SETTIME -s -g $H -k $H $TremN -r $U $TdeaN -z $U $TdeaN -d $H $TactN1 "$CSK1" > settime.out.$zone.1 2>&1 +$SETTIME -s -g $O -k $O $TactN1 -r $O $TactN1 -z $O $TsubN1 -d $O $TactN1 "$CSK2" > settime.out.$zone.2 2>&1 +# Fake lifetime of old algorithm keys. +echo "Lifetime: 0" >> "${CSK1}.state" +cat template.db.in "${CSK1}.key" "${CSK2}.key" > "$infile" +private_type_record $zone 5 "$CSK1" >> "$infile" +private_type_record $zone $DEFAULT_ALGORITHM_NUMBER "$CSK2" >> "$infile" +cp $infile $zonefile +$SIGNER -S -x -z -s now-1h -e now+2w -o $zone -O raw -f "${zonefile}.signed" $infile > signer.out.$zone.1 2>&1 + +# +# Reload testing +# +echo "example" >> zones +cp example.db.in example.db + +setup "dynamic2inline.kasp" +cp template.db.in $zonefile diff --git a/bin/tests/system/kasp/ns6/template.db.in b/bin/tests/system/kasp/ns6/template.db.in new file mode 100644 index 0000000..f1d8b94 --- /dev/null +++ b/bin/tests/system/kasp/ns6/template.db.in @@ -0,0 +1,27 @@ +; 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. + +$TTL 300 +@ IN SOA mname1. . ( + 1 ; serial + 20 ; refresh (20 seconds) + 20 ; retry (20 seconds) + 1814400 ; expire (3 weeks) + 3600 ; minimum (1 hour) + ) + + NS ns6 +ns6 A 10.53.0.6 + +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/prereq.sh b/bin/tests/system/kasp/prereq.sh new file mode 100644 index 0000000..9c5d879 --- /dev/null +++ b/bin/tests/system/kasp/prereq.sh @@ -0,0 +1,21 @@ +#!/bin/sh + +# 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. + +SYSTEMTESTTOP=.. +. $SYSTEMTESTTOP/conf.sh + +if ! test -n "$PYTHON"; then + echo_i "This test requires Python." + exit 1 +fi +exit 0 diff --git a/bin/tests/system/kasp/setup.sh b/bin/tests/system/kasp/setup.sh new file mode 100644 index 0000000..d3f4329 --- /dev/null +++ b/bin/tests/system/kasp/setup.sh @@ -0,0 +1,80 @@ +#!/bin/sh -e + +# 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. + +# shellcheck source=conf.sh +. "$SYSTEMTESTTOP/conf.sh" + +set -e + +$SHELL clean.sh + +mkdir keys + +copy_setports ns2/named.conf.in ns2/named.conf +if ! $SHELL ../testcrypto.sh -q RSASHA1 +then + copy_setports ns3/named-fips.conf.in ns3/named.conf +else + copy_setports ns3/named-fips.conf.in ns3/named-fips.conf + copy_setports ns3/named.conf.in ns3/named.conf +fi +copy_setports ns4/named.conf.in ns4/named.conf +copy_setports ns5/named.conf.in ns5/named.conf +copy_setports ns6/named.conf.in ns6/named.conf + +if $SHELL ../testcrypto.sh ed25519; then + echo "yes" > ed25519-supported.file +fi + +if $SHELL ../testcrypto.sh ed448; then + echo "yes" > ed448-supported.file +fi + +copy_setports ns3/policies/autosign.conf.in ns3/policies/autosign.conf +copy_setports ns3/policies/kasp-fips.conf.in ns3/policies/kasp-fips.conf +copy_setports ns3/policies/kasp.conf.in ns3/policies/kasp.conf +if ! $SHELL ../testcrypto.sh -q RSASHA1 +then + cp ns3/policies/kasp-fips.conf ns3/policies/kasp.conf +fi + +copy_setports ns6/policies/csk1.conf.in ns6/policies/csk1.conf +copy_setports ns6/policies/csk2.conf.in ns6/policies/csk2.conf +copy_setports ns6/policies/kasp-fips.conf.in ns6/policies/kasp-fips.conf +copy_setports ns6/policies/kasp.conf.in ns6/policies/kasp.conf +if ! $SHELL ../testcrypto.sh -q RSASHA1 +then + cp ns6/policies/kasp-fips.conf ns6/policies/kasp.conf +fi + +# Setup zones +( + cd ns2 + $SHELL setup.sh +) +( + cd ns3 + $SHELL setup.sh +) +( + cd ns4 + $SHELL setup.sh +) +( + cd ns5 + $SHELL setup.sh +) +( + cd ns6 + $SHELL setup.sh +) diff --git a/bin/tests/system/kasp/tests.sh b/bin/tests/system/kasp/tests.sh new file mode 100644 index 0000000..4d3bda7 --- /dev/null +++ b/bin/tests/system/kasp/tests.sh @@ -0,0 +1,4882 @@ +#!/bin/sh + +# 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. + +# shellcheck source=conf.sh +# shellcheck source=kasp.sh +SYSTEMTESTTOP=.. +. "$SYSTEMTESTTOP/conf.sh" +. "$SYSTEMTESTTOP/kasp.sh" + +start_time="$(TZ=UTC date +%s)" +status=0 +n=0 + +############################################################################### +# Utilities # +############################################################################### + +# Call dig with default options. +dig_with_opts() { + + if [ -n "$TSIG" ]; then + "$DIG" +tcp +noadd +nosea +nostat +nocmd +dnssec -p "$PORT" -y "$TSIG" "$@" + else + "$DIG" +tcp +noadd +nosea +nostat +nocmd +dnssec -p "$PORT" "$@" + fi +} + +# RNDC. +rndccmd() { + "$RNDC" -c "$SYSTEMTESTTOP/common/rndc.conf" -p "$CONTROLPORT" -s "$@" +} + +# Log error and increment failure rate. +log_error() { + echo_i "error: $1" + ret=$((ret+1)) +} + +# Default next key event threshold. May be extended by wait periods. +next_key_event_threshold=100 + +############################################################################### +# Tests # +############################################################################### + +# +# dnssec-keygen +# +set_zone "kasp" +set_policy "kasp" "4" "200" +set_server "keys" "10.53.0.1" + +n=$((n+1)) +echo_i "check that 'dnssec-keygen -k' (configured policy) creates valid files ($n)" +ret=0 +$KEYGEN -K keys -k "$POLICY" -l kasp.conf "$ZONE" > "keygen.out.$POLICY.test$n" 2>/dev/null || ret=1 +lines=$(wc -l < "keygen.out.$POLICY.test$n") +test "$lines" -eq $NUM_KEYS || log_error "wrong number of keys created for policy kasp: $lines" +# Temporarily don't log errors because we are searching multiple files. +disable_logerror + +# Key properties. +set_keyrole "KEY1" "csk" +set_keylifetime "KEY1" "31536000" +set_keyalgorithm "KEY1" "13" "ECDSAP256SHA256" "256" +set_keysigning "KEY1" "yes" +set_zonesigning "KEY1" "yes" + +set_keyrole "KEY2" "ksk" +set_keylifetime "KEY2" "31536000" +set_keyalgorithm "KEY2" "8" "RSASHA256" "2048" +set_keysigning "KEY2" "yes" +set_zonesigning "KEY2" "no" + +set_keyrole "KEY3" "zsk" +set_keylifetime "KEY3" "2592000" +set_keyalgorithm "KEY3" "8" "RSASHA256" "2048" +set_keysigning "KEY3" "no" +set_zonesigning "KEY3" "yes" + +set_keyrole "KEY4" "zsk" +set_keylifetime "KEY4" "16070400" +set_keyalgorithm "KEY4" "8" "RSASHA256" "3072" +set_keysigning "KEY4" "no" +set_zonesigning "KEY4" "yes" + +lines=$(get_keyids "$DIR" "$ZONE" | wc -l) +test "$lines" -eq $NUM_KEYS || log_error "bad number of key ids" + +ids=$(get_keyids "$DIR" "$ZONE") +for id in $ids; do + # There are four key files with the same algorithm. + # Check them until a match is found. + ret=0 && check_key "KEY1" "$id" + test "$ret" -eq 0 && continue + + ret=0 && check_key "KEY2" "$id" + test "$ret" -eq 0 && continue + + ret=0 && check_key "KEY3" "$id" + test "$ret" -eq 0 && continue + + ret=0 && check_key "KEY4" "$id" + + # 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. +enable_logerror + +n=$((n+1)) +echo_i "check that 'dnssec-keygen -k' (default policy) creates valid files ($n)" +ret=0 +set_zone "kasp" +set_policy "default" "1" "3600" +set_server "." "10.53.0.1" +# Key properties. +set_keyrole "KEY1" "csk" +set_keylifetime "KEY1" "0" +set_keyalgorithm "KEY1" "13" "ECDSAP256SHA256" "256" +set_keysigning "KEY1" "yes" +set_zonesigning "KEY1" "yes" + +key_clear "KEY2" +key_clear "KEY3" +key_clear "KEY4" + +$KEYGEN -G -k "$POLICY" "$ZONE" > "keygen.out.$POLICY.test$n" 2>/dev/null || ret=1 +lines=$(wc -l < "keygen.out.$POLICY.test$n") +test "$lines" -eq $NUM_KEYS || log_error "wrong number of keys created for policy default: $lines" +ids=$(get_keyids "$DIR" "$ZONE") +for id in $ids; do + check_key "KEY1" "$id" + test "$ret" -eq 0 && key_save KEY1 + check_keytimes +done +test "$ret" -eq 0 || echo_i "failed" +status=$((status+ret)) + +# +# dnssec-settime +# + +# These test builds upon the latest created key with dnssec-keygen and uses the +# environment variables BASE_FILE, KEY_FILE, PRIVATE_FILE and STATE_FILE. +CMP_FILE="${BASE_FILE}.cmp" +n=$((n+1)) +echo_i "check that 'dnssec-settime' by default does not edit key state file ($n)" +ret=0 +cp "$STATE_FILE" "$CMP_FILE" +$SETTIME -P +3600 "$BASE_FILE" > /dev/null || log_error "settime failed" +grep "; Publish: " "$KEY_FILE" > /dev/null || log_error "mismatch published in $KEY_FILE" +grep "Publish: " "$PRIVATE_FILE" > /dev/null || log_error "mismatch published in $PRIVATE_FILE" +$DIFF "$CMP_FILE" "$STATE_FILE" || log_error "unexpected file change in $STATE_FILE" +test "$ret" -eq 0 || echo_i "failed" +status=$((status+ret)) + +n=$((n+1)) +echo_i "check that 'dnssec-settime -s' also sets publish time metadata and states in key state file ($n)" +ret=0 +cp "$STATE_FILE" "$CMP_FILE" +now=$(date +%Y%m%d%H%M%S) +$SETTIME -s -P "$now" -g "omnipresent" -k "rumoured" "$now" -z "omnipresent" "$now" -r "rumoured" "$now" -d "hidden" "$now" "$BASE_FILE" > /dev/null || log_error "settime failed" +set_keystate "KEY1" "GOAL" "omnipresent" +set_keystate "KEY1" "STATE_DNSKEY" "rumoured" +set_keystate "KEY1" "STATE_KRRSIG" "rumoured" +set_keystate "KEY1" "STATE_ZRRSIG" "omnipresent" +set_keystate "KEY1" "STATE_DS" "hidden" +check_key "KEY1" "$id" +test "$ret" -eq 0 && key_save KEY1 +set_keytime "KEY1" "PUBLISHED" "${now}" +check_keytimes +test "$ret" -eq 0 || echo_i "failed" +status=$((status+ret)) + +n=$((n+1)) +echo_i "check that 'dnssec-settime -s' also unsets publish time metadata and states in key state file ($n)" +ret=0 +cp "$STATE_FILE" "$CMP_FILE" +$SETTIME -s -P "none" -g "none" -k "none" "$now" -z "none" "$now" -r "none" "$now" -d "none" "$now" "$BASE_FILE" > /dev/null || log_error "settime failed" +set_keystate "KEY1" "GOAL" "none" +set_keystate "KEY1" "STATE_DNSKEY" "none" +set_keystate "KEY1" "STATE_KRRSIG" "none" +set_keystate "KEY1" "STATE_ZRRSIG" "none" +set_keystate "KEY1" "STATE_DS" "none" +check_key "KEY1" "$id" +test "$ret" -eq 0 && key_save KEY1 +set_keytime "KEY1" "PUBLISHED" "none" +check_keytimes +test "$ret" -eq 0 || echo_i "failed" +status=$((status+ret)) + +n=$((n+1)) +echo_i "check that 'dnssec-settime -s' also sets active time metadata and states in key state file (uppercase) ($n)" +ret=0 +cp "$STATE_FILE" "$CMP_FILE" +now=$(date +%Y%m%d%H%M%S) +$SETTIME -s -A "$now" -g "HIDDEN" -k "UNRETENTIVE" "$now" -z "UNRETENTIVE" "$now" -r "OMNIPRESENT" "$now" -d "OMNIPRESENT" "$now" "$BASE_FILE" > /dev/null || log_error "settime failed" +set_keystate "KEY1" "GOAL" "hidden" +set_keystate "KEY1" "STATE_DNSKEY" "unretentive" +set_keystate "KEY1" "STATE_KRRSIG" "omnipresent" +set_keystate "KEY1" "STATE_ZRRSIG" "unretentive" +set_keystate "KEY1" "STATE_DS" "omnipresent" +check_key "KEY1" "$id" +test "$ret" -eq 0 && key_save KEY1 +set_keytime "KEY1" "ACTIVE" "${now}" +check_keytimes +test "$ret" -eq 0 || echo_i "failed" +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 an error. +n=$((n+1)) +echo_i "waiting for kasp signing changes to take effect ($n)" + +_wait_for_done_apexnsec() { + while read -r zone + do + dig_with_opts "$zone" @10.53.0.3 nsec > "dig.out.ns3.test$n.$zone" || return 1 + grep "NS SOA" "dig.out.ns3.test$n.$zone" > /dev/null || return 1 + grep "$zone\..*IN.*RRSIG" "dig.out.ns3.test$n.$zone" > /dev/null || return 1 + done < ns3/zones + + while read -r zone + do + dig_with_opts "$zone" @10.53.0.6 nsec > "dig.out.ns6.test$n.$zone" || return 1 + grep "NS SOA" "dig.out.ns6.test$n.$zone" > /dev/null || return 1 + grep "$zone\..*IN.*RRSIG" "dig.out.ns6.test$n.$zone" > /dev/null || return 1 + done < ns6/zones + + return 0 +} +retry_quiet 30 _wait_for_done_apexnsec || ret=1 +test "$ret" -eq 0 || echo_i "failed" +status=$((status+ret)) + +# Test max-zone-ttl rejects zones with too high TTL. +n=$((n+1)) +echo_i "check that max-zone-ttl rejects zones with too high TTL ($n)" +ret=0 +set_zone "max-zone-ttl.kasp" +grep "loading from master file ${ZONE}.db failed: out of range" "ns3/named.run" > /dev/null || ret=1 +test "$ret" -eq 0 || echo_i "failed" +status=$((status+ret)) + +# +# Zone: default.kasp. +# +set_keytimes_csk_policy() { + # The first key is immediately published and activated. + created=$(key_get KEY1 CREATED) + set_keytime "KEY1" "PUBLISHED" "${created}" + set_keytime "KEY1" "ACTIVE" "${created}" + # The DS can be published if the DNSKEY and RRSIG records are + # OMNIPRESENT. This happens after max-zone-ttl (1d) plus + # publish-safety (1h) plus zone-propagation-delay (300s) = + # 86400 + 3600 + 300 = 90300. + set_addkeytime "KEY1" "SYNCPUBLISH" "${created}" 90300 + # Key lifetime is unlimited, so not setting RETIRED and REMOVED. +} + +# Check the zone with default kasp policy has loaded and is signed. +set_zone "default.kasp" +set_policy "default" "1" "3600" +set_server "ns3" "10.53.0.3" +# Key properties. +set_keyrole "KEY1" "csk" +set_keylifetime "KEY1" "0" +set_keyalgorithm "KEY1" "13" "ECDSAP256SHA256" "256" +set_keysigning "KEY1" "yes" +set_zonesigning "KEY1" "yes" +# DNSKEY, RRSIG (ksk), RRSIG (zsk) are published. DS needs to wait. +set_keystate "KEY1" "GOAL" "omnipresent" +set_keystate "KEY1" "STATE_DNSKEY" "rumoured" +set_keystate "KEY1" "STATE_KRRSIG" "rumoured" +set_keystate "KEY1" "STATE_ZRRSIG" "rumoured" +set_keystate "KEY1" "STATE_DS" "hidden" + +check_keys +check_dnssecstatus "$SERVER" "$POLICY" "$ZONE" +set_keytimes_csk_policy +check_keytimes +check_apex +check_subdomain +dnssec_verify + +# Trigger a keymgr run. Make sure the key files are not touched if there are +# no modifications to the key metadata. +n=$((n+1)) +echo_i "make sure key files are untouched if metadata does not change ($n)" +ret=0 +basefile=$(key_get KEY1 BASEFILE) +privkey_stat=$(key_get KEY1 PRIVKEY_STAT) +pubkey_stat=$(key_get KEY1 PUBKEY_STAT) +state_stat=$(key_get KEY1 STATE_STAT) + +nextpart $DIR/named.run > /dev/null +rndccmd 10.53.0.3 loadkeys "$ZONE" > /dev/null || log_error "rndc loadkeys zone ${ZONE} failed" +wait_for_log 3 "keymgr: $ZONE done" $DIR/named.run +privkey_stat2=$(key_stat "${basefile}.private") +pubkey_stat2=$(key_stat "${basefile}.key") +state_stat2=$(key_stat "${basefile}.state") +test "$privkey_stat" = "$privkey_stat2" || log_error "wrong private key file stat (expected $privkey_stat got $privkey_stat2)" +test "$pubkey_stat" = "$pubkey_stat2" || log_error "wrong public key file stat (expected $pubkey_stat got $pubkey_stat2)" +test "$state_stat" = "$state_stat2" || log_error "wrong state file stat (expected $state_stat got $state_stat2)" +test "$ret" -eq 0 || echo_i "failed" +status=$((status+ret)) + +n=$((n+1)) +echo_i "again ($n)" +ret=0 + +nextpart $DIR/named.run > /dev/null +rndccmd 10.53.0.3 loadkeys "$ZONE" > /dev/null || log_error "rndc loadkeys zone ${ZONE} failed" +wait_for_log 3 "keymgr: $ZONE done" $DIR/named.run +privkey_stat2=$(key_stat "${basefile}.private") +pubkey_stat2=$(key_stat "${basefile}.key") +state_stat2=$(key_stat "${basefile}.state") +test "$privkey_stat" = "$privkey_stat2" || log_error "wrong private key file stat (expected $privkey_stat got $privkey_stat2)" +test "$pubkey_stat" = "$pubkey_stat2" || log_error "wrong public key file stat (expected $pubkey_stat got $pubkey_stat2)" +test "$state_stat" = "$state_stat2" || log_error "wrong state file stat (expected $state_stat got $state_stat2)" +test "$ret" -eq 0 || echo_i "failed" +status=$((status+ret)) + +# Update zone. +n=$((n+1)) +echo_i "modify unsigned zone file and check that new record is 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" + +update_is_signed() { + ip_a=$1 + ip_d=$2 + + if [ "$ip_a" != "-" ]; then + dig_with_opts "a.${ZONE}" "@${SERVER}" A > "dig.out.$DIR.test$n.a" || return 1 + grep "status: NOERROR" "dig.out.$DIR.test$n.a" > /dev/null || return 1 + grep "a.${ZONE}\..*${DEFAULT_TTL}.*IN.*A.*${ip_a}" "dig.out.$DIR.test$n.a" > /dev/null || return 1 + lines=$(get_keys_which_signed A "dig.out.$DIR.test$n.a" | wc -l) + test "$lines" -eq 1 || return 1 + get_keys_which_signed A "dig.out.$DIR.test$n.a" | grep "^${KEY_ID}$" > /dev/null || return 1 + fi + + if [ "$ip_d" != "-" ]; then + dig_with_opts "d.${ZONE}" "@${SERVER}" A > "dig.out.$DIR.test$n".d || return 1 + grep "status: NOERROR" "dig.out.$DIR.test$n".d > /dev/null || return 1 + grep "d.${ZONE}\..*${DEFAULT_TTL}.*IN.*A.*${ip_d}" "dig.out.$DIR.test$n".d > /dev/null || return 1 + lines=$(get_keys_which_signed A "dig.out.$DIR.test$n".d | wc -l) + test "$lines" -eq 1 || return 1 + get_keys_which_signed A "dig.out.$DIR.test$n".d | grep "^${KEY_ID}$" > /dev/null || return 1 + fi +} + +retry_quiet 10 update_is_signed "10.0.0.11" "10.0.0.44" || ret=1 +test "$ret" -eq 0 || echo_i "failed" +status=$((status+ret)) + +# Move the private key file, a rekey event should not introduce replacement +# keys. +ret=0 +echo_i "test that if private key files are inaccessible this doesn't trigger a rollover ($n)" +basefile=$(key_get KEY1 BASEFILE) +mv "${basefile}.private" "${basefile}.offline" +rndccmd 10.53.0.3 loadkeys "$ZONE" > /dev/null || log_error "rndc loadkeys zone ${ZONE} failed" +wait_for_log 3 "offline, policy default" $DIR/named.run || ret=1 +mv "${basefile}.offline" "${basefile}.private" +test "$ret" -eq 0 || echo_i "failed" +status=$((status+ret)) + +# Nothing has changed. +check_keys +check_dnssecstatus "$SERVER" "$POLICY" "$ZONE" +set_keytimes_csk_policy +check_keytimes +check_apex +check_subdomain +dnssec_verify + +# +# Zone: dynamic.kasp +# +set_zone "dynamic.kasp" +set_dynamic +set_policy "default" "1" "3600" +set_server "ns3" "10.53.0.3" +# Key properties, timings and states same as above. +check_keys +check_dnssecstatus "$SERVER" "$POLICY" "$ZONE" +set_keytimes_csk_policy +check_keytimes +check_apex +check_subdomain +dnssec_verify + +# Update zone with nsupdate. +n=$((n+1)) +echo_i "nsupdate zone and check that new record is signed for zone ${ZONE} ($n)" +ret=0 +( +echo zone ${ZONE} +echo server 10.53.0.3 "$PORT" +echo update del "a.${ZONE}" 300 A 10.0.0.1 +echo update add "a.${ZONE}" 300 A 10.0.0.101 +echo update add "d.${ZONE}" 300 A 10.0.0.4 +echo send +) | $NSUPDATE + +retry_quiet 10 update_is_signed "10.0.0.101" "10.0.0.4" || ret=1 +test "$ret" -eq 0 || echo_i "failed" +status=$((status+ret)) + +# Update zone with nsupdate (reverting the above change). +n=$((n+1)) +echo_i "nsupdate zone and check that new record is signed for zone ${ZONE} ($n)" +ret=0 +( +echo zone ${ZONE} +echo server 10.53.0.3 "$PORT" +echo update add "a.${ZONE}" 300 A 10.0.0.1 +echo update del "a.${ZONE}" 300 A 10.0.0.101 +echo update del "d.${ZONE}" 300 A 10.0.0.4 +echo send +) | $NSUPDATE + +retry_quiet 10 update_is_signed "10.0.0.1" "-" || ret=1 +test "$ret" -eq 0 || echo_i "failed" +status=$((status+ret)) + +# Update zone with freeze/thaw. +n=$((n+1)) +echo_i "modify zone file and check that new record is signed for zone ${ZONE} ($n)" +ret=0 +rndccmd 10.53.0.3 freeze "$ZONE" > /dev/null || log_error "rndc freeze zone ${ZONE} failed" +sleep 1 +echo "d.${ZONE}. 300 A 10.0.0.44" >> "${DIR}/${ZONE}.db" +rndccmd 10.53.0.3 thaw "$ZONE" > /dev/null || log_error "rndc thaw zone ${ZONE} failed" + +retry_quiet 10 update_is_signed "10.0.0.1" "10.0.0.44" || ret=1 +test "$ret" -eq 0 || echo_i "failed" +status=$((status+ret)) + +# +# Zone: dynamic-inline-signing.kasp +# +set_zone "dynamic-inline-signing.kasp" +set_dynamic +set_policy "default" "1" "3600" +set_server "ns3" "10.53.0.3" +# Key properties, timings and states same as above. +check_keys +check_dnssecstatus "$SERVER" "$POLICY" "$ZONE" +set_keytimes_csk_policy +check_keytimes +check_apex +check_subdomain +dnssec_verify + +# Update zone with freeze/thaw. +n=$((n+1)) +echo_i "modify unsigned zone file and check that new record is signed for zone ${ZONE} ($n)" +ret=0 +rndccmd 10.53.0.3 freeze "$ZONE" > /dev/null || log_error "rndc freeze zone ${ZONE} failed" +sleep 1 +cp "${DIR}/template2.db.in" "${DIR}/${ZONE}.db" +rndccmd 10.53.0.3 thaw "$ZONE" > /dev/null || log_error "rndc thaw zone ${ZONE} failed" + +retry_quiet 10 update_is_signed || ret=1 +test "$ret" -eq 0 || echo_i "failed" +status=$((status+ret)) + +# +# Zone: inline-signing.kasp +# +set_zone "inline-signing.kasp" +set_policy "default" "1" "3600" +set_server "ns3" "10.53.0.3" +# Key properties, timings and states same as above. +check_keys +check_dnssecstatus "$SERVER" "$POLICY" "$ZONE" +set_keytimes_csk_policy +check_keytimes +check_apex +check_subdomain +dnssec_verify + +# +# Zone: checkds-ksk.kasp. +# +key_clear "KEY1" +key_clear "KEY2" +key_clear "KEY3" +key_clear "KEY4" + +set_zone "checkds-ksk.kasp" +set_policy "checkds-ksk" "2" "303" +set_server "ns3" "10.53.0.3" +# Key properties. +set_keyrole "KEY1" "ksk" +set_keylifetime "KEY1" "0" +set_keyalgorithm "KEY1" "13" "ECDSAP256SHA256" "256" +set_keysigning "KEY1" "yes" +set_zonesigning "KEY1" "no" + +set_keyrole "KEY2" "zsk" +set_keylifetime "KEY2" "0" +set_keyalgorithm "KEY2" "13" "ECDSAP256SHA256" "256" +set_keysigning "KEY2" "no" +set_zonesigning "KEY2" "yes" +# DNSKEY, RRSIG (ksk), RRSIG (zsk) are published. DS needs to wait. +set_keystate "KEY1" "GOAL" "omnipresent" +set_keystate "KEY1" "STATE_DNSKEY" "rumoured" +set_keystate "KEY1" "STATE_KRRSIG" "rumoured" +set_keystate "KEY1" "STATE_DS" "hidden" + +set_keystate "KEY2" "GOAL" "omnipresent" +set_keystate "KEY2" "STATE_DNSKEY" "rumoured" +set_keystate "KEY2" "STATE_ZRRSIG" "rumoured" + +check_keys +check_dnssecstatus "$SERVER" "$POLICY" "$ZONE" +check_apex +check_subdomain +dnssec_verify + +basefile=$(key_get KEY1 BASEFILE) + +_wait_for_metadata() { + _expr=$1 + _file=$2 + grep "$_expr" $_file > /dev/null || return 1 + return 0 +} + +n=$((n+1)) +echo_i "checkds publish correctly sets DSPublish for zone $ZONE ($n)" +now=$(date +%Y%m%d%H%M%S) +rndc_checkds "$SERVER" "$DIR" "-" "$now" "published" "$ZONE" +retry_quiet 3 _wait_for_metadata "DSPublish: $now" "${basefile}.state" || log_error "bad DSPublish in ${basefile}.state" +# DS State should be forced into RUMOURED. +set_keystate "KEY1" "STATE_DS" "rumoured" +check_keys +test "$ret" -eq 0 || echo_i "failed" +status=$((status+ret)) + +n=$((n+1)) +echo_i "checkds withdraw correctly sets DSRemoved for zone $ZONE ($n)" +now=$(date +%Y%m%d%H%M%S) +rndc_checkds "$SERVER" "$DIR" "-" "$now" "withdrawn" "$ZONE" +retry_quiet 3 _wait_for_metadata "DSRemoved: $now" "${basefile}.state" || log_error "bad DSRemoved in ${basefile}.state" +# DS State should be forced into UNRETENTIVE. +set_keystate "KEY1" "STATE_DS" "unretentive" +check_keys +test "$ret" -eq 0 || echo_i "failed" +status=$((status+ret)) + +# +# Zone: checkds-doubleksk.kasp. +# +key_clear "KEY1" +key_clear "KEY2" +key_clear "KEY3" +key_clear "KEY4" + +set_zone "checkds-doubleksk.kasp" +set_policy "checkds-doubleksk" "3" "303" +set_server "ns3" "10.53.0.3" +# Key properties. +set_keyrole "KEY1" "ksk" +set_keylifetime "KEY1" "0" +set_keyalgorithm "KEY1" "13" "ECDSAP256SHA256" "256" +set_keysigning "KEY1" "yes" +set_zonesigning "KEY1" "no" + +set_keyrole "KEY2" "ksk" +set_keylifetime "KEY2" "0" +set_keyalgorithm "KEY2" "13" "ECDSAP256SHA256" "256" +set_keysigning "KEY2" "yes" +set_zonesigning "KEY2" "no" + +set_keyrole "KEY3" "zsk" +set_keylifetime "KEY3" "0" +set_keyalgorithm "KEY3" "13" "ECDSAP256SHA256" "256" +set_keysigning "KEY3" "no" +set_zonesigning "KEY3" "yes" +# DNSKEY, RRSIG (ksk), RRSIG (zsk) are published. DS needs to wait. +set_keystate "KEY1" "GOAL" "omnipresent" +set_keystate "KEY1" "STATE_DNSKEY" "rumoured" +set_keystate "KEY1" "STATE_KRRSIG" "rumoured" +set_keystate "KEY1" "STATE_DS" "hidden" + +set_keystate "KEY2" "GOAL" "omnipresent" +set_keystate "KEY2" "STATE_DNSKEY" "rumoured" +set_keystate "KEY2" "STATE_KRRSIG" "rumoured" +set_keystate "KEY2" "STATE_DS" "hidden" + +set_keystate "KEY3" "GOAL" "omnipresent" +set_keystate "KEY3" "STATE_DNSKEY" "rumoured" +set_keystate "KEY3" "STATE_ZRRSIG" "rumoured" + +check_keys +check_dnssecstatus "$SERVER" "$POLICY" "$ZONE" +check_apex +check_subdomain +dnssec_verify + +basefile1=$(key_get KEY1 BASEFILE) +basefile2=$(key_get KEY2 BASEFILE) + +n=$((n+1)) +echo_i "checkds published does not set DSPublish for zone $ZONE (multiple KSK) ($n)" +rndc_checkds "$SERVER" "$DIR" "-" "20200102121314" "published" "$ZONE" +grep "DSPublish:" "${basefile1}.state" > /dev/null && log_error "DSPublish incorrectly set in ${basefile1}" +grep "DSPublish:" "${basefile2}.state" > /dev/null && log_error "DSPublish incorrectly set in ${basefile2}" +test "$ret" -eq 0 || echo_i "failed" +status=$((status+ret)) + +n=$((n+1)) +echo_i "checkds withdrawn does not set DSRemoved for zone $ZONE (multiple KSK) ($n)" +rndc_checkds "$SERVER" "$DIR" "-" "20190102121314" "withdrawn" "$ZONE" +grep "DSRemoved:" "${basefile1}.state" > /dev/null && log_error "DSRemoved incorrectly set in ${basefile1}" +grep "DSRemoved:" "${basefile2}.state" > /dev/null && log_error "DSRemoved incorrectly set in ${basefile2}" +test "$ret" -eq 0 || echo_i "failed" +status=$((status+ret)) + +n=$((n+1)) +echo_i "checkds published does not set DSPublish for zone $ZONE (wrong algorithm) ($n)" +rndccmd "$SERVER" dnssec -checkds -key $(key_get KEY1 ID) -alg 8 "published" "$ZONE" > rndc.dnssec.checkds.out.$ZONE.$n +grep "DSPublish:" "${basefile1}.state" > /dev/null && log_error "DSPublish incorrectly set in ${basefile1}" +grep "DSPublish:" "${basefile2}.state" > /dev/null && log_error "DSPublish incorrectly set in ${basefile2}" +test "$ret" -eq 0 || echo_i "failed" +status=$((status+ret)) + +n=$((n+1)) +echo_i "checkds withdrawn does not set DSRemoved for zone $ZONE (wrong algorithm) ($n)" +rndccmd "$SERVER" dnssec -checkds -key $(key_get KEY1 ID) -alg RSASHA256 "withdrawn" "$ZONE" > rndc.dnssec.checkds.out.$ZONE.$n +grep "DSRemoved:" "${basefile1}.state" > /dev/null && log_error "DSRemoved incorrectly set in ${basefile1}" +grep "DSRemoved:" "${basefile2}.state" > /dev/null && log_error "DSRemoved incorrectly set in ${basefile2}" +test "$ret" -eq 0 || echo_i "failed" +status=$((status+ret)) + +n=$((n+1)) +echo_i "checkds published -key correctly sets DSPublish for key $(key_get KEY1 ID) zone $ZONE (multiple KSK) ($n)" +rndc_checkds "$SERVER" "$DIR" KEY1 "20190102121314" "published" "$ZONE" +retry_quiet 3 _wait_for_metadata "DSPublish: 20190102121314" "${basefile1}.state" || log_error "bad DSPublish in ${basefile1}.state" +grep "DSPublish:" "${basefile2}.state" > /dev/null && log_error "DSPublish incorrectly set in ${basefile2}" +test "$ret" -eq 0 || echo_i "failed" +status=$((status+ret)) + +n=$((n+1)) +echo_i "checkds withdrawn -key correctly sets DSRemoved for key $(key_get KEY2 ID) zone $ZONE (multiple KSK) ($n)" +rndc_checkds "$SERVER" "$DIR" KEY2 "20200102121314" "withdrawn" "$ZONE" +grep "DSRemoved:" "${basefile1}.state" > /dev/null && log_error "DSPublish incorrectly set in ${basefile1}" +retry_quiet 3 _wait_for_metadata "DSRemoved: 20200102121314" "${basefile2}.state" || log_error "bad DSRemoved in ${basefile2}.state" +test "$ret" -eq 0 || echo_i "failed" +status=$((status+ret)) + +# +# Zone: checkds-csk.kasp. +# +key_clear "KEY1" +key_clear "KEY2" +key_clear "KEY3" +key_clear "KEY4" + +set_zone "checkds-csk.kasp" +set_policy "checkds-csk" "1" "303" +set_server "ns3" "10.53.0.3" +# Key properties. +set_keyrole "KEY1" "csk" +set_keylifetime "KEY1" "0" +set_keyalgorithm "KEY1" "13" "ECDSAP256SHA256" "256" +set_keysigning "KEY1" "yes" +set_zonesigning "KEY1" "yes" +# DNSKEY, RRSIG (ksk), RRSIG (zsk) are published. DS needs to wait. +set_keystate "KEY1" "GOAL" "omnipresent" +set_keystate "KEY1" "STATE_DNSKEY" "rumoured" +set_keystate "KEY1" "STATE_KRRSIG" "rumoured" +set_keystate "KEY1" "STATE_ZRRSIG" "rumoured" +set_keystate "KEY1" "STATE_DS" "hidden" + +check_keys +check_dnssecstatus "$SERVER" "$POLICY" "$ZONE" +check_apex +check_subdomain +dnssec_verify + +basefile=$(key_get KEY1 BASEFILE) + +n=$((n+1)) +echo_i "checkds publish correctly sets DSPublish for zone $ZONE ($n)" +rndc_checkds "$SERVER" "$DIR" "-" "20190102121314" "published" "$ZONE" +retry_quiet 3 _wait_for_metadata "DSPublish: 20190102121314" "${basefile}.state" || log_error "bad DSPublish in ${basefile}.state" +test "$ret" -eq 0 || echo_i "failed" +status=$((status+ret)) + +n=$((n+1)) +echo_i "checkds withdraw correctly sets DSRemoved for zone $ZONE ($n)" +rndc_checkds "$SERVER" "$DIR" "-" "20200102121314" "withdrawn" "$ZONE" +retry_quiet 3 _wait_for_metadata "DSRemoved: 20200102121314" "${basefile}.state" || log_error "bad DSRemoved in ${basefile}.state" +test "$ret" -eq 0 || echo_i "failed" +status=$((status+ret)) + +# Set keytimes for dnssec-policy with various algorithms. +# These all use the same time values. +set_keytimes_algorithm_policy() { + # The first KSK is immediately published and activated. + created=$(key_get KEY1 CREATED) + set_keytime "KEY1" "PUBLISHED" "${created}" + set_keytime "KEY1" "ACTIVE" "${created}" + # Key was pregenerated. + if [ "$1" = "pregenerated" ]; then + keyfile=$(key_get KEY1 BASEFILE) + grep "; Publish:" "${keyfile}.key" > published.test${n}.key1 + published=$(awk '{print $3}' < published.test${n}.key1) + set_keytime "KEY1" "PUBLISHED" "${published}" + set_keytime "KEY1" "ACTIVE" "${published}" + fi + published=$(key_get KEY1 PUBLISHED) + + # The DS can be published if the DNSKEY and RRSIG records are + # OMNIPRESENT. This happens after max-zone-ttl (1d) plus + # publish-safety (1h) plus zone-propagation-delay (300s) = + # 86400 + 3600 + 300 = 90300. + set_addkeytime "KEY1" "SYNCPUBLISH" "${published}" 90300 + # Key lifetime is 10 years, 315360000 seconds. + set_addkeytime "KEY1" "RETIRED" "${published}" 315360000 + # The key is removed after the retire time plus DS TTL (1d), + # parent propagation delay (1h), and retire safety (1h) = + # 86400 + 3600 + 3600 = 93600. + retired=$(key_get KEY1 RETIRED) + set_addkeytime "KEY1" "REMOVED" "${retired}" 93600 + + # The first ZSKs are immediately published and activated. + created=$(key_get KEY2 CREATED) + set_keytime "KEY2" "PUBLISHED" "${created}" + set_keytime "KEY2" "ACTIVE" "${created}" + # Key was pregenerated. + if [ "$1" = "pregenerated" ]; then + keyfile=$(key_get KEY2 BASEFILE) + grep "; Publish:" "${keyfile}.key" > published.test${n}.key2 + published=$(awk '{print $3}' < published.test${n}.key2) + set_keytime "KEY2" "PUBLISHED" "${published}" + set_keytime "KEY2" "ACTIVE" "${published}" + fi + published=$(key_get KEY2 PUBLISHED) + + # Key lifetime for KSK2 is 5 years, 157680000 seconds. + set_addkeytime "KEY2" "RETIRED" "${published}" 157680000 + # The key is removed after the retire time plus max zone ttl (1d), zone + # propagation delay (300s), retire safety (1h), and sign delay + # (signature validity minus refresh, 9d) = + # 86400 + 300 + 3600 + 777600 = 867900. + retired=$(key_get KEY2 RETIRED) + set_addkeytime "KEY2" "REMOVED" "${retired}" 867900 + + # Second ZSK (KEY3). + created=$(key_get KEY3 CREATED) + set_keytime "KEY3" "PUBLISHED" "${created}" + set_keytime "KEY3" "ACTIVE" "${created}" + # Key was pregenerated. + if [ "$1" = "pregenerated" ]; then + keyfile=$(key_get KEY3 BASEFILE) + grep "; Publish:" "${keyfile}.key" > published.test${n}.key3 + published=$(awk '{print $3}' < published.test${n}.key3) + set_keytime "KEY3" "PUBLISHED" "${published}" + set_keytime "KEY3" "ACTIVE" "${published}" + fi + published=$(key_get KEY3 PUBLISHED) + + # Key lifetime for KSK3 is 1 year, 31536000 seconds. + set_addkeytime "KEY3" "RETIRED" "${published}" 31536000 + retired=$(key_get KEY3 RETIRED) + set_addkeytime "KEY3" "REMOVED" "${retired}" 867900 +} + +# +# Zone: rsasha1.kasp. +# +if $SHELL ../testcrypto.sh -q RSASHA1 +then + set_zone "rsasha1.kasp" + set_policy "rsasha1" "3" "1234" + set_server "ns3" "10.53.0.3" + # Key properties. + key_clear "KEY1" + set_keyrole "KEY1" "ksk" + set_keylifetime "KEY1" "315360000" + set_keyalgorithm "KEY1" "5" "RSASHA1" "2048" + set_keysigning "KEY1" "yes" + set_zonesigning "KEY1" "no" + + key_clear "KEY2" + set_keyrole "KEY2" "zsk" + set_keylifetime "KEY2" "157680000" + set_keyalgorithm "KEY2" "5" "RSASHA1" "2048" + set_keysigning "KEY2" "no" + set_zonesigning "KEY2" "yes" + + key_clear "KEY3" + set_keyrole "KEY3" "zsk" + set_keylifetime "KEY3" "31536000" + set_keyalgorithm "KEY3" "5" "RSASHA1" "2000" + set_keysigning "KEY3" "no" + set_zonesigning "KEY3" "yes" + + # KSK: DNSKEY, RRSIG (ksk) published. DS needs to wait. + # ZSK: DNSKEY, RRSIG (zsk) published. + set_keystate "KEY1" "GOAL" "omnipresent" + set_keystate "KEY1" "STATE_DNSKEY" "rumoured" + set_keystate "KEY1" "STATE_KRRSIG" "rumoured" + set_keystate "KEY1" "STATE_DS" "hidden" + + set_keystate "KEY2" "GOAL" "omnipresent" + set_keystate "KEY2" "STATE_DNSKEY" "rumoured" + set_keystate "KEY2" "STATE_ZRRSIG" "rumoured" + + set_keystate "KEY3" "GOAL" "omnipresent" + set_keystate "KEY3" "STATE_DNSKEY" "rumoured" + set_keystate "KEY3" "STATE_ZRRSIG" "rumoured" + # Three keys only. + key_clear "KEY4" + + check_keys + check_dnssecstatus "$SERVER" "$POLICY" "$ZONE" + set_keytimes_algorithm_policy + check_keytimes + check_apex + check_subdomain + dnssec_verify +fi + +# +# Zone: unsigned.kasp. +# +set_zone "unsigned.kasp" +set_policy "none" "0" "0" +set_server "ns3" "10.53.0.3" + +key_clear "KEY1" +key_clear "KEY2" +key_clear "KEY3" +key_clear "KEY4" + +check_keys +check_dnssecstatus "$SERVER" "$POLICY" "$ZONE" +check_apex +check_subdomain +# Make sure the zone file is untouched. +n=$((n+1)) +echo_i "Make sure the zonefile for zone ${ZONE} is not edited ($n)" +ret=0 +diff "${DIR}/${ZONE}.db.infile" "${DIR}/${ZONE}.db" || ret=1 +test "$ret" -eq 0 || echo_i "failed" +status=$((status+ret)) + +# +# Zone: insecure.kasp. +# +set_zone "insecure.kasp" +set_policy "insecure" "0" "0" +set_server "ns3" "10.53.0.3" + +key_clear "KEY1" +key_clear "KEY2" +key_clear "KEY3" +key_clear "KEY4" + +check_keys +check_dnssecstatus "$SERVER" "$POLICY" "$ZONE" +check_apex +check_subdomain + +# +# Zone: unlimited.kasp. +# +set_zone "unlimited.kasp" +set_policy "unlimited" "1" "1234" +set_server "ns3" "10.53.0.3" +# Key properties. +set_keyrole "KEY1" "csk" +set_keylifetime "KEY1" "0" +set_keyalgorithm "KEY1" "13" "ECDSAP256SHA256" "256" +set_keysigning "KEY1" "yes" +set_zonesigning "KEY1" "yes" +# DNSKEY, RRSIG (ksk), RRSIG (zsk) are published. DS needs to wait. +set_keystate "KEY1" "GOAL" "omnipresent" +set_keystate "KEY1" "STATE_DNSKEY" "rumoured" +set_keystate "KEY1" "STATE_KRRSIG" "rumoured" +set_keystate "KEY1" "STATE_ZRRSIG" "rumoured" +set_keystate "KEY1" "STATE_DS" "hidden" + +check_keys +check_dnssecstatus "$SERVER" "$POLICY" "$ZONE" +set_keytimes_csk_policy +check_keytimes +check_apex +check_subdomain +dnssec_verify + +# +# Zone: inherit.kasp. +# +set_zone "inherit.kasp" +set_policy "rsasha256" "3" "1234" +set_server "ns3" "10.53.0.3" + +# Key properties. +key_clear "KEY1" +set_keyrole "KEY1" "ksk" +set_keylifetime "KEY1" "315360000" +set_keyalgorithm "KEY1" "8" "RSASHA256" "2048" +set_keysigning "KEY1" "yes" +set_zonesigning "KEY1" "no" + +key_clear "KEY2" +set_keyrole "KEY2" "zsk" +set_keylifetime "KEY2" "157680000" +set_keyalgorithm "KEY2" "8" "RSASHA256" "2048" +set_keysigning "KEY2" "no" +set_zonesigning "KEY2" "yes" + +key_clear "KEY3" +set_keyrole "KEY3" "zsk" +set_keylifetime "KEY3" "31536000" +set_keyalgorithm "KEY3" "8" "RSASHA256" "3072" +set_keysigning "KEY3" "no" +set_zonesigning "KEY3" "yes" +# KSK: DNSKEY, RRSIG (ksk) published. DS needs to wait. +# ZSK: DNSKEY, RRSIG (zsk) published. +set_keystate "KEY1" "GOAL" "omnipresent" +set_keystate "KEY1" "STATE_DNSKEY" "rumoured" +set_keystate "KEY1" "STATE_KRRSIG" "rumoured" +set_keystate "KEY1" "STATE_DS" "hidden" + +set_keystate "KEY2" "GOAL" "omnipresent" +set_keystate "KEY2" "STATE_DNSKEY" "rumoured" +set_keystate "KEY2" "STATE_ZRRSIG" "rumoured" + +set_keystate "KEY3" "GOAL" "omnipresent" +set_keystate "KEY3" "STATE_DNSKEY" "rumoured" +set_keystate "KEY3" "STATE_ZRRSIG" "rumoured" +# Three keys only. +key_clear "KEY4" + +check_keys +check_dnssecstatus "$SERVER" "$POLICY" "$ZONE" +set_keytimes_algorithm_policy +check_keytimes +check_apex +check_subdomain +dnssec_verify + +# +# Zone: dnssec-keygen.kasp. +# +set_zone "dnssec-keygen.kasp" +set_policy "rsasha256" "3" "1234" +set_server "ns3" "10.53.0.3" +# Key properties, timings and states same as above. + +check_keys +check_dnssecstatus "$SERVER" "$POLICY" "$ZONE" +set_keytimes_algorithm_policy +check_keytimes +check_apex +check_subdomain +dnssec_verify + +# +# Zone: some-keys.kasp. +# +set_zone "some-keys.kasp" +set_policy "rsasha256" "3" "1234" +set_server "ns3" "10.53.0.3" +# Key properties, timings and states same as above. + +check_keys +check_dnssecstatus "$SERVER" "$POLICY" "$ZONE" +set_keytimes_algorithm_policy "pregenerated" +check_keytimes +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. +set_zone "pregenerated.kasp" +set_policy "rsasha256" "6" "1234" +set_server "ns3" "10.53.0.3" +# Key properties, timings and states same as above. + +check_keys +check_dnssecstatus "$SERVER" "$POLICY" "$ZONE" +set_keytimes_algorithm_policy "pregenerated" +check_keytimes +check_apex +check_subdomain +dnssec_verify + +# +# Zone: rumoured.kasp. +# +# There are three keys in rumoured state. +set_zone "rumoured.kasp" +set_policy "rsasha256" "3" "1234" +set_server "ns3" "10.53.0.3" +# Key properties, timings and states same as above. + +check_keys +check_dnssecstatus "$SERVER" "$POLICY" "$ZONE" +set_keytimes_algorithm_policy +# Activation date is a day later. +set_addkeytime "KEY1" "ACTIVE" $(key_get KEY1 ACTIVE) 86400 +set_addkeytime "KEY1" "RETIRED" $(key_get KEY1 RETIRED) 86400 +set_addkeytime "KEY1" "REMOVED" $(key_get KEY1 REMOVED) 86400 +set_addkeytime "KEY2" "ACTIVE" $(key_get KEY2 ACTIVE) 86400 +set_addkeytime "KEY2" "RETIRED" $(key_get KEY2 RETIRED) 86400 +set_addkeytime "KEY2" "REMOVED" $(key_get KEY2 REMOVED) 86400 +set_addkeytime "KEY3" "ACTIVE" $(key_get KEY3 ACTIVE) 86400 +set_addkeytime "KEY3" "RETIRED" $(key_get KEY3 RETIRED) 86400 +set_addkeytime "KEY3" "REMOVED" $(key_get KEY3 REMOVED) 86400 +check_keytimes +check_apex +check_subdomain +dnssec_verify + +# +# Zone: secondary.kasp. +# +set_zone "secondary.kasp" +set_policy "rsasha256" "3" "1234" +set_server "ns3" "10.53.0.3" +# Key properties, timings and states same as above. + +check_keys +check_dnssecstatus "$SERVER" "$POLICY" "$ZONE" +set_keytimes_algorithm_policy +check_keytimes +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" + +_wait_for_done_subdomains() { + ret=0 + dig_with_opts "a.${ZONE}" "@${SERVER}" A > "dig.out.$DIR.test$n.a" || return 1 + grep "status: NOERROR" "dig.out.$DIR.test$n.a" > /dev/null || return 1 + grep "a.${ZONE}\..*${DEFAULT_TTL}.*IN.*A.*10\.0\.0\.11" "dig.out.$DIR.test$n.a" > /dev/null || return 1 + check_signatures $_qtype "dig.out.$DIR.test$n.a" "ZSK" + if [ $ret -gt 0 ]; then return $ret; fi + + dig_with_opts "d.${ZONE}" "@${SERVER}" A > "dig.out.$DIR.test$n.d" || return 1 + grep "status: NOERROR" "dig.out.$DIR.test$n.d" > /dev/null || return 1 + grep "d.${ZONE}\..*${DEFAULT_TTL}.*IN.*A.*10\.0\.0\.4" "dig.out.$DIR.test$n.d" > /dev/null || return 1 + check_signatures $_qtype "dig.out.$DIR.test$n.d" "ZSK" + return $ret +} +retry_quiet 5 _wait_for_done_subdomains || ret=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. +# +if $SHELL ../testcrypto.sh -q RSASHA1 +then + set_zone "rsasha1-nsec3.kasp" + set_policy "rsasha1-nsec3" "3" "1234" + set_server "ns3" "10.53.0.3" + # Key properties. + set_keyalgorithm "KEY1" "7" "NSEC3RSASHA1" "2048" + set_keyalgorithm "KEY2" "7" "NSEC3RSASHA1" "2048" + set_keyalgorithm "KEY3" "7" "NSEC3RSASHA1" "2000" + # Key timings and states same as above. + + check_keys + check_dnssecstatus "$SERVER" "$POLICY" "$ZONE" + set_keytimes_algorithm_policy + check_keytimes + check_apex + check_subdomain + dnssec_verify +fi + +# +# Zone: rsasha256.kasp. +# +set_zone "rsasha256.kasp" +set_policy "rsasha256" "3" "1234" +set_server "ns3" "10.53.0.3" +# Key properties. +set_keyalgorithm "KEY1" "8" "RSASHA256" "2048" +set_keyalgorithm "KEY2" "8" "RSASHA256" "2048" +set_keyalgorithm "KEY3" "8" "RSASHA256" "3072" +# Key timings and states same as above. + +check_keys +check_dnssecstatus "$SERVER" "$POLICY" "$ZONE" +set_keytimes_algorithm_policy +check_keytimes +check_apex +check_subdomain +dnssec_verify + +# +# Zone: rsasha512.kasp. +# +set_zone "rsasha512.kasp" +set_policy "rsasha512" "3" "1234" +set_server "ns3" "10.53.0.3" +# Key properties. +set_keyalgorithm "KEY1" "10" "RSASHA512" "2048" +set_keyalgorithm "KEY2" "10" "RSASHA512" "2048" +set_keyalgorithm "KEY3" "10" "RSASHA512" "3072" +# Key timings and states same as above. + +check_keys +check_dnssecstatus "$SERVER" "$POLICY" "$ZONE" +set_keytimes_algorithm_policy +check_keytimes +check_apex +check_subdomain +dnssec_verify + +# +# Zone: ecdsa256.kasp. +# +set_zone "ecdsa256.kasp" +set_policy "ecdsa256" "3" "1234" +set_server "ns3" "10.53.0.3" +# Key properties. +set_keyalgorithm "KEY1" "13" "ECDSAP256SHA256" "256" +set_keyalgorithm "KEY2" "13" "ECDSAP256SHA256" "256" +set_keyalgorithm "KEY3" "13" "ECDSAP256SHA256" "256" +# Key timings and states same as above. + +check_keys +check_dnssecstatus "$SERVER" "$POLICY" "$ZONE" +set_keytimes_algorithm_policy +check_keytimes +check_apex +check_subdomain +dnssec_verify + +# +# Zone: ecdsa512.kasp. +# +set_zone "ecdsa384.kasp" +set_policy "ecdsa384" "3" "1234" +set_server "ns3" "10.53.0.3" +# Key properties. +set_keyalgorithm "KEY1" "14" "ECDSAP384SHA384" "384" +set_keyalgorithm "KEY2" "14" "ECDSAP384SHA384" "384" +set_keyalgorithm "KEY3" "14" "ECDSAP384SHA384" "384" +# Key timings and states same as above. + +check_keys +check_dnssecstatus "$SERVER" "$POLICY" "$ZONE" +set_keytimes_algorithm_policy +check_keytimes +check_apex +check_subdomain +dnssec_verify + +# +# Zone: ed25519.kasp. +# +if [ -f ed25519-supported.file ]; then + set_zone "ed25519.kasp" + set_policy "ed25519" "3" "1234" + set_server "ns3" "10.53.0.3" + # Key properties. + set_keyalgorithm "KEY1" "15" "ED25519" "256" + set_keyalgorithm "KEY2" "15" "ED25519" "256" + set_keyalgorithm "KEY3" "15" "ED25519" "256" + # Key timings and states same as above. + + check_keys + check_dnssecstatus "$SERVER" "$POLICY" "$ZONE" + set_keytimes_algorithm_policy + check_keytimes + check_apex + check_subdomain + dnssec_verify +fi + +# +# Zone: ed448.kasp. +# +if [ -f ed448-supported.file ]; then + set_zone "ed448.kasp" + set_policy "ed448" "3" "1234" + set_server "ns3" "10.53.0.3" + # Key properties. + set_keyalgorithm "KEY1" "16" "ED448" "456" + set_keyalgorithm "KEY2" "16" "ED448" "456" + set_keyalgorithm "KEY3" "16" "ED448" "456" + # Key timings and states same as above. + + check_keys + check_dnssecstatus "$SERVER" "$POLICY" "$ZONE" + set_keytimes_algorithm_policy + check_keytimes + check_apex + check_subdomain + dnssec_verify +fi + +# Set key times for 'autosign' policy. +set_keytimes_autosign_policy() { + # The KSK was published six months ago (with settime). + created=$(key_get KEY1 CREATED) + set_addkeytime "KEY1" "PUBLISHED" "${created}" -15552000 + set_addkeytime "KEY1" "ACTIVE" "${created}" -15552000 + set_addkeytime "KEY1" "SYNCPUBLISH" "${created}" -15552000 + # Key lifetime is 2 years, 63072000 seconds. + active=$(key_get KEY1 ACTIVE) + set_addkeytime "KEY1" "RETIRED" "${active}" 63072000 + # The key is removed after the retire time plus DS TTL (1d), + # parent propagation delay (1h), retire safety (1h) = + # 86400 + 3600 + 3600 = 93600 + retired=$(key_get KEY1 RETIRED) + set_addkeytime "KEY1" "REMOVED" "${retired}" 93600 + + # The ZSK was published six months ago (with settime). + created=$(key_get KEY2 CREATED) + set_addkeytime "KEY2" "PUBLISHED" "${created}" -15552000 + set_addkeytime "KEY2" "ACTIVE" "${created}" -15552000 + # Key lifetime for KSK2 is 1 year, 31536000 seconds. + active=$(key_get KEY2 ACTIVE) + set_addkeytime "KEY2" "RETIRED" "${active}" 31536000 + # The key is removed after the retire time plus: + # TTLsig (RRSIG TTL): 1 day (86400 seconds) + # Dprp (propagation delay): 5 minutes (300 seconds) + # retire-safety: 1 hour (3600 seconds) + # Dsgn (sign delay): 7 days (604800 seconds) + # Iret: 695100 seconds. + retired=$(key_get KEY2 RETIRED) + set_addkeytime "KEY2" "REMOVED" "${retired}" 695100 +} + +# +# Zone: expired-sigs.autosign. +# +set_zone "expired-sigs.autosign" +set_policy "autosign" "2" "300" +set_server "ns3" "10.53.0.3" +# Key properties. +key_clear "KEY1" +set_keyrole "KEY1" "ksk" +set_keylifetime "KEY1" "63072000" +set_keyalgorithm "KEY1" "$DEFAULT_ALGORITHM_NUMBER" "$DEFAULT_ALGORITHM" "$DEFAULT_BITS" +set_keysigning "KEY1" "yes" +set_zonesigning "KEY1" "no" + +key_clear "KEY2" +set_keyrole "KEY2" "zsk" +set_keylifetime "KEY2" "31536000" +set_keyalgorithm "KEY2" "$DEFAULT_ALGORITHM_NUMBER" "$DEFAULT_ALGORITHM" "$DEFAULT_BITS" +set_keysigning "KEY2" "no" +set_zonesigning "KEY2" "yes" + +# Both KSK and ZSK stay OMNIPRESENT. +set_keystate "KEY1" "GOAL" "omnipresent" +set_keystate "KEY1" "STATE_DNSKEY" "omnipresent" +set_keystate "KEY1" "STATE_KRRSIG" "omnipresent" +set_keystate "KEY1" "STATE_DS" "omnipresent" + +set_keystate "KEY2" "GOAL" "omnipresent" +set_keystate "KEY2" "STATE_DNSKEY" "omnipresent" +set_keystate "KEY2" "STATE_ZRRSIG" "omnipresent" +# Expect only two keys. +key_clear "KEY3" +key_clear "KEY4" + +check_keys +check_dnssecstatus "$SERVER" "$POLICY" "$ZONE" +set_keytimes_autosign_policy +check_keytimes +check_apex +check_subdomain +dnssec_verify + +# Verify all signatures have been refreshed. +check_rrsig_refresh() { + # Apex. + _qtypes="DNSKEY SOA NS NSEC" + for _qtype in $_qtypes + do + n=$((n+1)) + echo_i "check ${_qtype} rrsig is refreshed correctly for zone ${ZONE} ($n)" + ret=0 + dig_with_opts "$ZONE" "@${SERVER}" "$_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}\..*IN.*RRSIG.*${_qtype}.*${ZONE}" "dig.out.$DIR.test$n" > "rrsig.out.$ZONE.$_qtype" || log_error "missing RRSIG (${_qtype}) record in response" + # If this exact RRSIG is also in the zone file it is not refreshed. + _rrsig=$(cat "rrsig.out.$ZONE.$_qtype") + grep "${_rrsig}" "${DIR}/${ZONE}.db" > /dev/null && log_error "RRSIG (${_qtype}) not refreshed in zone ${ZONE}" + test "$ret" -eq 0 || echo_i "failed" + status=$((status+ret)) + done + + # Below apex. + _labels="a b c ns3" + for _label in $_labels; + do + _qtypes="A NSEC" + for _qtype in $_qtypes + do + n=$((n+1)) + echo_i "check ${_label} ${_qtype} rrsig is refreshed correctly for zone ${ZONE} ($n)" + ret=0 + dig_with_opts "${_label}.${ZONE}" "@${SERVER}" "$_qtype" > "dig.out.$DIR.test$n" || log_error "dig ${_label}.${ZONE} ${_qtype} failed" + grep "status: NOERROR" "dig.out.$DIR.test$n" > /dev/null || log_error "mismatch status in DNS response" + grep "${ZONE}\..*IN.*RRSIG.*${_qtype}.*${ZONE}" "dig.out.$DIR.test$n" > "rrsig.out.$ZONE.$_qtype" || log_error "missing RRSIG (${_qtype}) record in response" + _rrsig=$(cat "rrsig.out.$ZONE.$_qtype") + grep "${_rrsig}" "${DIR}/${ZONE}.db" > /dev/null && log_error "RRSIG (${_qtype}) not refreshed in zone ${ZONE}" + test "$ret" -eq 0 || echo_i "failed" + status=$((status+ret)) + done + done +} + +check_rrsig_refresh + +# +# Zone: fresh-sigs.autosign. +# +set_zone "fresh-sigs.autosign" +set_policy "autosign" "2" "300" +set_server "ns3" "10.53.0.3" +# Key properties, timings and states same as above. + +check_keys +check_dnssecstatus "$SERVER" "$POLICY" "$ZONE" +set_keytimes_autosign_policy +check_keytimes +check_apex +check_subdomain +dnssec_verify + +# Verify signature reuse. +check_rrsig_reuse() { + # Apex. + _qtypes="NS NSEC" + for _qtype in $_qtypes + do + n=$((n+1)) + echo_i "check ${_qtype} rrsig is reused correctly for zone ${ZONE} ($n)" + ret=0 + dig_with_opts "$ZONE" "@${SERVER}" "$_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}\..*IN.*RRSIG.*${_qtype}.*${ZONE}" "dig.out.$DIR.test$n" > "rrsig.out.$ZONE.$_qtype" || log_error "missing RRSIG (${_qtype}) record in response" + # If this exact RRSIG is also in the signed zone file it is not refreshed. + _rrsig=$(awk '{print $5, $6, $7, $8, $9, $10, $11, $12, $13, $14;}' < "rrsig.out.$ZONE.$_qtype") + $CHECKZONE -f raw -F text -s full -o zone.out.${ZONE}.test$n "${ZONE}" "${DIR}/${ZONE}.db.signed" > /dev/null + grep "${_rrsig}" zone.out.${ZONE}.test$n > /dev/null || log_error "RRSIG (${_qtype}) not reused in zone ${ZONE}" + test "$ret" -eq 0 || echo_i "failed" + status=$((status+ret)) + done + + # Below apex. + _labels="a b c ns3" + for _label in $_labels; + do + _qtypes="A NSEC" + for _qtype in $_qtypes + do + n=$((n+1)) + echo_i "check ${_label} ${_qtype} rrsig is reused correctly for zone ${ZONE} ($n)" + ret=0 + dig_with_opts "${_label}.${ZONE}" "@${SERVER}" "$_qtype" > "dig.out.$DIR.test$n" || log_error "dig ${_label}.${ZONE} ${_qtype} failed" + grep "status: NOERROR" "dig.out.$DIR.test$n" > /dev/null || log_error "mismatch status in DNS response" + grep "${ZONE}\..*IN.*RRSIG.*${_qtype}.*${ZONE}" "dig.out.$DIR.test$n" > "rrsig.out.$ZONE.$_qtype" || log_error "missing RRSIG (${_qtype}) record in response" + # If this exact RRSIG is also in the signed zone file it is not refreshed. + _rrsig=$(awk '{print $5, $6, $7, $8, $9, $10, $11, $12, $13, $14;}' < "rrsig.out.$ZONE.$_qtype") + $CHECKZONE -f raw -F text -s full -o zone.out.${ZONE}.test$n "${ZONE}" "${DIR}/${ZONE}.db.signed" > /dev/null + grep "${_rrsig}" zone.out.${ZONE}.test$n > /dev/null || log_error "RRSIG (${_qtype}) not reused in zone ${ZONE}" + test "$ret" -eq 0 || echo_i "failed" + status=$((status+ret)) + done + done +} + +check_rrsig_reuse + +# +# Zone: unfresh-sigs.autosign. +# +set_zone "unfresh-sigs.autosign" +set_policy "autosign" "2" "300" +set_server "ns3" "10.53.0.3" +# Key properties, timings and states same as above. + +check_keys +check_dnssecstatus "$SERVER" "$POLICY" "$ZONE" +set_keytimes_autosign_policy +check_keytimes +check_apex +check_subdomain +dnssec_verify +check_rrsig_refresh + +# +# Zone: ksk-missing.autosign. +# +set_zone "ksk-missing.autosign" +set_policy "autosign" "2" "300" +set_server "ns3" "10.53.0.3" +# Key properties, timings and states same as above. +# Skip checking the private file, because it is missing. +key_set "KEY1" "PRIVATE" "no" + +check_keys +check_dnssecstatus "$SERVER" "$POLICY" "$ZONE" +check_apex +check_subdomain +dnssec_verify + +# Restore the PRIVATE variable. +key_set "KEY1" "PRIVATE" "yes" + +# +# Zone: zsk-missing.autosign. +# +set_zone "zsk-missing.autosign" +set_policy "autosign" "2" "300" +set_server "ns3" "10.53.0.3" +# Key properties, timings and states same as above. +# Skip checking the private file, because it is missing. +key_set "KEY2" "PRIVATE" "no" + +check_keys +check_dnssecstatus "$SERVER" "$POLICY" "$ZONE" +# For the apex, we expect the SOA to be signed with the KSK because the ZSK is +# offline. Temporary treat KEY1 as a zone signing key too. +set_keyrole "KEY1" "csk" +set_zonesigning "KEY1" "yes" +set_zonesigning "KEY2" "no" +check_apex +set_keyrole "KEY1" "ksk" +set_zonesigning "KEY1" "no" +set_zonesigning "KEY2" "yes" +check_subdomain +dnssec_verify + +# Restore the PRIVATE variable. +key_set "KEY2" "PRIVATE" "yes" + +# +# Zone: zsk-retired.autosign. +# +set_zone "zsk-retired.autosign" +set_policy "autosign" "3" "300" +set_server "ns3" "10.53.0.3" +# The third key is not yet expected to be signing. +set_keyrole "KEY3" "zsk" +set_keylifetime "KEY3" "31536000" +set_keyalgorithm "KEY3" "$DEFAULT_ALGORITHM_NUMBER" "$DEFAULT_ALGORITHM" "$DEFAULT_BITS" +set_keysigning "KEY3" "no" +set_zonesigning "KEY3" "no" +# The ZSK goal is set to HIDDEN but records stay OMNIPRESENT until the new ZSK +# is active. +set_keystate "KEY2" "GOAL" "hidden" +set_keystate "KEY2" "STATE_DNSKEY" "omnipresent" +set_keystate "KEY2" "STATE_ZRRSIG" "omnipresent" +# A new ZSK should be introduced, so expect a key with goal OMNIPRESENT, +# the DNSKEY introduced (RUMOURED) and the signatures HIDDEN. +set_keystate "KEY3" "GOAL" "omnipresent" +set_keystate "KEY3" "STATE_DNSKEY" "rumoured" +set_keystate "KEY3" "STATE_ZRRSIG" "hidden" + +check_keys +check_dnssecstatus "$SERVER" "$POLICY" "$ZONE" +set_keytimes_autosign_policy + +# The old ZSK is retired. +created=$(key_get KEY2 CREATED) +set_keytime "KEY2" "RETIRED" "${created}" +set_addkeytime "KEY2" "REMOVED" "${created}" 695100 +# The new ZSK is immediately published. +created=$(key_get KEY3 CREATED) +set_keytime "KEY3" "PUBLISHED" "${created}" +# And becomes active after Ipub: +# DNSKEY TTL: 300 seconds +# zone-propagation-delay 5 minutes (300 seconds) +# publish-safety: 1 hour (3600 seconds) +# Ipub: 4200 seconds +published=$(key_get KEY3 PUBLISHED) +set_addkeytime "KEY3" "ACTIVE" "${published}" 4200 +# Lzsk: 1 year (31536000 seconds) +active=$(key_get KEY3 ACTIVE) +set_addkeytime "KEY3" "RETIRED" "${active}" 31536000 +# Iret: 695100 seconds. +retired=$(key_get KEY3 RETIRED) +set_addkeytime "KEY3" "REMOVED" "${retired}" 695100 + +check_keytimes +check_apex +check_subdomain +dnssec_verify +check_rrsig_refresh + +# +# Zone: legacy-keys.kasp. +# +set_zone "legacy-keys.kasp" +# This zone has two active keys and two old keys left in key directory, so +# expect 4 key files. +set_policy "migrate-to-dnssec-policy" "4" "1234" +set_server "ns3" "10.53.0.3" + +# Key properties. +key_clear "KEY1" +set_keyrole "KEY1" "ksk" +set_keylifetime "KEY1" "16070400" +set_keyalgorithm "KEY1" "8" "RSASHA256" "2048" +set_keysigning "KEY1" "yes" +set_zonesigning "KEY1" "no" + +key_clear "KEY2" +set_keyrole "KEY2" "zsk" +set_keylifetime "KEY2" "16070400" +set_keyalgorithm "KEY2" "8" "RSASHA256" "2048" +set_keysigning "KEY2" "no" +set_zonesigning "KEY2" "yes" +# KSK: DNSKEY, RRSIG (ksk) published. DS needs to wait. +# ZSK: DNSKEY, RRSIG (zsk) published. +set_keystate "KEY1" "GOAL" "omnipresent" +set_keystate "KEY1" "STATE_DNSKEY" "rumoured" +set_keystate "KEY1" "STATE_KRRSIG" "rumoured" +set_keystate "KEY1" "STATE_DS" "hidden" + +set_keystate "KEY2" "GOAL" "omnipresent" +set_keystate "KEY2" "STATE_DNSKEY" "rumoured" +set_keystate "KEY2" "STATE_ZRRSIG" "rumoured" +# Two keys only. +key_clear "KEY3" +key_clear "KEY4" + +check_keys +check_dnssecstatus "$SERVER" "$POLICY" "$ZONE" + +# Make sure the correct legacy keys were used (and not the removed predecessor +# keys). +n=$((n+1)) +echo_i "check correct keys were used when migrating zone ${ZONE} to dnssec-policy ($n)" +ret=0 +kskfile=$(cat ns3/legacy-keys.kasp.ksk) +basefile=$(key_get KEY1 BASEFILE) +echo_i "filename: $basefile (expect $kskfile)" +test "$DIR/$kskfile" = "$basefile" || ret=1 +zskfile=$(cat ns3/legacy-keys.kasp.zsk) +basefile=$(key_get KEY2 BASEFILE) +echo_i "filename: $basefile (expect $zskfile)" +test "$DIR/$zskfile" = "$basefile" || ret=1 +test "$ret" -eq 0 || echo_i "failed" +status=$((status+ret)) + +# KSK times. +created=$(key_get KEY1 CREATED) +keyfile=$(key_get KEY1 BASEFILE) +grep "; Publish:" "${keyfile}.key" > published.test${n}.key1 +published=$(awk '{print $3}' < published.test${n}.key1) +set_keytime "KEY1" "PUBLISHED" "${published}" +set_keytime "KEY1" "ACTIVE" "${published}" +published=$(key_get KEY1 PUBLISHED) +# The DS can be published if the DNSKEY and RRSIG records are OMNIPRESENT. +# This happens after max-zone-ttl (1d) plus publish-safety (1h) plus +# zone-propagation-delay (300s) = 86400 + 3600 + 300 = 90300. +set_addkeytime "KEY1" "SYNCPUBLISH" "${published}" 90300 +# Key lifetime is 6 months, 315360000 seconds. +set_addkeytime "KEY1" "RETIRED" "${published}" 16070400 +# The key is removed after the retire time plus DS TTL (1d), parent +# propagation delay (1h), and retire safety (1h) = 86400 + 3600 + 3600 = 93600. +retired=$(key_get KEY1 RETIRED) +set_addkeytime "KEY1" "REMOVED" "${retired}" 93600 + +# ZSK times. +created=$(key_get KEY2 CREATED) +keyfile=$(key_get KEY2 BASEFILE) +grep "; Publish:" "${keyfile}.key" > published.test${n}.key2 +published=$(awk '{print $3}' < published.test${n}.key2) +set_keytime "KEY2" "PUBLISHED" "${published}" +set_keytime "KEY2" "ACTIVE" "${published}" +published=$(key_get KEY2 PUBLISHED) +# Key lifetime is 6 months, 315360000 seconds. +set_addkeytime "KEY2" "RETIRED" "${published}" 16070400 +# The key is removed after the retire time plus max zone ttl (1d), zone +# propagation delay (300s), retire safety (1h), and sign delay (signature +# validity minus refresh, 9d) = 86400 + 300 + 3600 + 777600 = 867900. +retired=$(key_get KEY2 RETIRED) +set_addkeytime "KEY2" "REMOVED" "${retired}" 867900 + +check_keytimes +check_apex +check_subdomain +dnssec_verify + +# +# Test dnssec-policy inheritance. +# + +# These zones should be unsigned: +# ns2/unsigned.tld +# ns4/none.inherit.signed +# ns4/none.override.signed +# ns4/inherit.none.signed +# ns4/none.none.signed +# ns5/inherit.inherit.unsigned +# ns5/none.inherit.unsigned +# ns5/none.override.unsigned +# ns5/inherit.none.unsigned +# ns5/none.none.unsigned +key_clear "KEY1" +key_clear "KEY2" +key_clear "KEY3" +key_clear "KEY4" + +set_zone "unsigned.tld" +set_policy "none" "0" "0" +set_server "ns2" "10.53.0.2" +TSIG="" +check_keys +check_dnssecstatus "$SERVER" "$POLICY" "$ZONE" +check_apex +check_subdomain + +set_zone "none.inherit.signed" +set_policy "none" "0" "0" +set_server "ns4" "10.53.0.4" +TSIG="hmac-sha1:sha1:$SHA1" +check_keys +check_dnssecstatus "$SERVER" "$POLICY" "$ZONE" +check_apex +check_subdomain + +set_zone "none.override.signed" +set_policy "none" "0" "0" +set_server "ns4" "10.53.0.4" +TSIG="hmac-sha224:sha224:$SHA224" +check_keys +check_dnssecstatus "$SERVER" "$POLICY" "$ZONE" +check_apex +check_subdomain + +set_zone "inherit.none.signed" +set_policy "none" "0" "0" +set_server "ns4" "10.53.0.4" +TSIG="hmac-sha256:sha256:$SHA256" +check_keys +check_dnssecstatus "$SERVER" "$POLICY" "$ZONE" +check_apex +check_subdomain + +set_zone "none.none.signed" +set_policy "none" "0" "0" +set_server "ns4" "10.53.0.4" +TSIG="hmac-sha256:sha256:$SHA256" +check_keys +check_dnssecstatus "$SERVER" "$POLICY" "$ZONE" +check_apex +check_subdomain + +set_zone "inherit.inherit.unsigned" +set_policy "none" "0" "0" +set_server "ns5" "10.53.0.5" +TSIG="hmac-sha1:sha1:$SHA1" +check_keys +check_dnssecstatus "$SERVER" "$POLICY" "$ZONE" +check_apex +check_subdomain + +set_zone "none.inherit.unsigned" +set_policy "none" "0" "0" +set_server "ns5" "10.53.0.5" +TSIG="hmac-sha1:sha1:$SHA1" +check_keys +check_dnssecstatus "$SERVER" "$POLICY" "$ZONE" +check_apex +check_subdomain + +set_zone "none.override.unsigned" +set_policy "none" "0" "0" +set_server "ns5" "10.53.0.5" +TSIG="hmac-sha224:sha224:$SHA224" +check_keys +check_dnssecstatus "$SERVER" "$POLICY" "$ZONE" +check_apex +check_subdomain + +set_zone "inherit.none.unsigned" +set_policy "none" "0" "0" +set_server "ns5" "10.53.0.5" +TSIG="hmac-sha256:sha256:$SHA256" +check_keys +check_dnssecstatus "$SERVER" "$POLICY" "$ZONE" +check_apex +check_subdomain + +set_zone "none.none.unsigned" +set_policy "none" "0" "0" +set_server "ns5" "10.53.0.5" +TSIG="hmac-sha256:sha256:$SHA256" +check_keys +check_dnssecstatus "$SERVER" "$POLICY" "$ZONE" +check_apex +check_subdomain + +# These zones should be signed with the default policy: +# ns2/signed.tld +# ns4/override.inherit.signed +# ns4/inherit.override.signed +# ns5/override.inherit.signed +# ns5/inherit.override.signed +set_keyrole "KEY1" "csk" +set_keylifetime "KEY1" "0" +set_keyalgorithm "KEY1" "13" "ECDSAP256SHA256" "256" +set_keysigning "KEY1" "yes" +set_zonesigning "KEY1" "yes" + +set_keystate "KEY1" "GOAL" "omnipresent" +set_keystate "KEY1" "STATE_DNSKEY" "rumoured" +set_keystate "KEY1" "STATE_KRRSIG" "rumoured" +set_keystate "KEY1" "STATE_ZRRSIG" "rumoured" +set_keystate "KEY1" "STATE_DS" "hidden" + +set_zone "signed.tld" +set_policy "default" "1" "3600" +set_server "ns2" "10.53.0.2" +TSIG="" +check_keys +check_dnssecstatus "$SERVER" "$POLICY" "$ZONE" +set_keytimes_csk_policy +check_keytimes +check_apex +check_subdomain +dnssec_verify + +set_zone "override.inherit.signed" +set_policy "default" "1" "3600" +set_server "ns4" "10.53.0.4" +TSIG="hmac-sha1:sha1:$SHA1" +check_keys +check_dnssecstatus "$SERVER" "$POLICY" "$ZONE" +set_keytimes_csk_policy +check_keytimes +check_apex +check_subdomain +dnssec_verify + +set_zone "inherit.override.signed" +set_policy "default" "1" "3600" +set_server "ns4" "10.53.0.4" +TSIG="hmac-sha224:sha224:$SHA224" +check_keys +check_dnssecstatus "$SERVER" "$POLICY" "$ZONE" +set_keytimes_csk_policy +check_keytimes +check_apex +check_subdomain +dnssec_verify + +set_zone "override.inherit.unsigned" +set_policy "default" "1" "3600" +set_server "ns5" "10.53.0.5" +TSIG="hmac-sha1:sha1:$SHA1" +check_keys +check_dnssecstatus "$SERVER" "$POLICY" "$ZONE" +set_keytimes_csk_policy +check_keytimes +check_apex +check_subdomain +dnssec_verify + +set_zone "inherit.override.unsigned" +set_policy "default" "1" "3600" +set_server "ns5" "10.53.0.5" +TSIG="hmac-sha224:sha224:$SHA224" +check_keys +check_dnssecstatus "$SERVER" "$POLICY" "$ZONE" +set_keytimes_csk_policy +check_keytimes +check_apex +check_subdomain +dnssec_verify + +# These zones should be signed with the test policy: +# ns4/inherit.inherit.signed +# ns4/override.override.signed +# ns4/override.none.signed +# ns5/override.override.unsigned +# ns5/override.none.unsigned +# ns4/example.net (both views) +set_keyrole "KEY1" "csk" +set_keylifetime "KEY1" "0" +set_keyalgorithm "KEY1" "14" "ECDSAP384SHA384" "384" +set_keysigning "KEY1" "yes" +set_zonesigning "KEY1" "yes" + +set_zone "inherit.inherit.signed" +set_policy "test" "1" "3600" +set_server "ns4" "10.53.0.4" +TSIG="hmac-sha1:sha1:$SHA1" +wait_for_nsec +check_keys +check_dnssecstatus "$SERVER" "$POLICY" "$ZONE" +set_keytimes_csk_policy +check_keytimes +check_apex +check_subdomain +dnssec_verify + +set_zone "override.override.signed" +set_policy "test" "1" "3600" +set_server "ns4" "10.53.0.4" +TSIG="hmac-sha224:sha224:$SHA224" +wait_for_nsec +check_keys +check_dnssecstatus "$SERVER" "$POLICY" "$ZONE" +set_keytimes_csk_policy +check_keytimes +check_apex +check_subdomain +dnssec_verify + +set_zone "override.none.signed" +set_policy "test" "1" "3600" +set_server "ns4" "10.53.0.4" +TSIG="hmac-sha256:sha256:$SHA256" +wait_for_nsec +check_keys +check_dnssecstatus "$SERVER" "$POLICY" "$ZONE" +set_keytimes_csk_policy +check_keytimes +check_apex +check_subdomain +dnssec_verify + +set_zone "override.override.unsigned" +set_policy "test" "1" "3600" +set_server "ns5" "10.53.0.5" +TSIG="hmac-sha224:sha224:$SHA224" +wait_for_nsec +check_keys +check_dnssecstatus "$SERVER" "$POLICY" "$ZONE" +set_keytimes_csk_policy +check_keytimes +check_apex +check_subdomain +dnssec_verify + +set_zone "override.none.unsigned" +set_policy "test" "1" "3600" +set_server "ns5" "10.53.0.5" +TSIG="hmac-sha256:sha256:$SHA256" +wait_for_nsec +check_keys +check_dnssecstatus "$SERVER" "$POLICY" "$ZONE" +set_keytimes_csk_policy +check_keytimes +check_apex +check_subdomain +dnssec_verify + +# Test with views. +set_zone "example.net" +set_server "ns4" "10.53.0.4" +TSIG="$DEFAULT_HMAC:keyforview1:$VIEW1" +wait_for_nsec +check_keys +check_dnssecstatus "$SERVER" "$POLICY" "$ZONE" "example1" +set_keytimes_csk_policy +check_keytimes +check_apex +dnssec_verify +# check zonestatus +n=$((n+1)) +echo_i "check $ZONE (view example1) zonestatus ($n)" +ret=0 +check_isdynamic "$SERVER" "$ZONE" "example1" || log_error "zone not dynamic" +check_inlinesigning "$SERVER" "$ZONE" "example1" && log_error "inline-signing enabled, expected disabled" +test "$ret" -eq 0 || echo_i "failed" +status=$((status+ret)) +# check subdomain +n=$((n+1)) +echo_i "check TXT example.net (view example1) rrset is signed correctly ($n)" +ret=0 +dig_with_opts "view.${ZONE}" "@${SERVER}" TXT > "dig.out.$DIR.test$n.txt" || log_error "dig view.${ZONE} TXT failed" +grep "status: NOERROR" "dig.out.$DIR.test$n.txt" > /dev/null || log_error "mismatch status in DNS response" +grep "view.${ZONE}\..*${DEFAULT_TTL}.*IN.*TXT.*view1" "dig.out.$DIR.test$n.txt" > /dev/null || log_error "missing view.${ZONE} TXT record in response" +check_signatures TXT "dig.out.$DIR.test$n.txt" "ZSK" +test "$ret" -eq 0 || echo_i "failed" +status=$((status+ret)) + +TSIG="$DEFAULT_HMAC:keyforview2:$VIEW2" +wait_for_nsec +check_keys +check_dnssecstatus "$SERVER" "$POLICY" "$ZONE" "example2" +check_apex +dnssec_verify +# check zonestatus +n=$((n+1)) +echo_i "check $ZONE (view example2) zonestatus ($n)" +ret=0 +check_isdynamic "$SERVER" "$ZONE" "example2" && log_error "zone dynamic, but not expected" +check_inlinesigning "$SERVER" "$ZONE" "example2" || log_error "inline-signing disabled, expected enabled" +test "$ret" -eq 0 || echo_i "failed" +status=$((status+ret)) +# check subdomain +n=$((n+1)) +echo_i "check TXT example.net (view example2) rrset is signed correctly ($n)" +ret=0 +dig_with_opts "view.${ZONE}" "@${SERVER}" TXT > "dig.out.$DIR.test$n.txt" || log_error "dig view.${ZONE} TXT failed" +grep "status: NOERROR" "dig.out.$DIR.test$n.txt" > /dev/null || log_error "mismatch status in DNS response" +grep "view.${ZONE}\..*${DEFAULT_TTL}.*IN.*TXT.*view2" "dig.out.$DIR.test$n.txt" > /dev/null || log_error "missing view.${ZONE} TXT record in response" +check_signatures TXT "dig.out.$DIR.test$n.txt" "ZSK" +test "$ret" -eq 0 || echo_i "failed" +status=$((status+ret)) + +TSIG="$DEFAULT_HMAC:keyforview3:$VIEW3" +wait_for_nsec +check_keys +check_dnssecstatus "$SERVER" "$POLICY" "$ZONE" "example3" +check_apex +dnssec_verify +# check zonestatus +n=$((n+1)) +echo_i "check $ZONE (view example3) zonestatus ($n)" +ret=0 +check_isdynamic "$SERVER" "$ZONE" "example3" && log_error "zone dynamic, but not expected" +check_inlinesigning "$SERVER" "$ZONE" "example3" || log_error "inline-signing disabled, expected enabled" +test "$ret" -eq 0 || echo_i "failed" +status=$((status+ret)) +# check subdomain +n=$((n+1)) +echo_i "check TXT example.net (view example3) rrset is signed correctly ($n)" +ret=0 +dig_with_opts "view.${ZONE}" "@${SERVER}" TXT > "dig.out.$DIR.test$n.txt" || log_error "dig view.${ZONE} TXT failed" +grep "status: NOERROR" "dig.out.$DIR.test$n.txt" > /dev/null || log_error "mismatch status in DNS response" +grep "view.${ZONE}\..*${DEFAULT_TTL}.*IN.*TXT.*view2" "dig.out.$DIR.test$n.txt" > /dev/null || log_error "missing view.${ZONE} TXT record in response" +check_signatures TXT "dig.out.$DIR.test$n.txt" "ZSK" +test "$ret" -eq 0 || echo_i "failed" +status=$((status+ret)) + +# Clear TSIG. +TSIG="" + +# +# Testing RFC 8901 Multi-Signer Model 2. +# +set_zone "multisigner-model2.kasp" +set_policy "multisigner-model2" "2" "3600" +set_server "ns3" "10.53.0.3" +key_clear "KEY1" +key_clear "KEY2" +key_clear "KEY3" +key_clear "KEY4" + +# Key properties. +set_keyrole "KEY1" "ksk" +set_keylifetime "KEY1" "0" +set_keyalgorithm "KEY1" "$DEFAULT_ALGORITHM_NUMBER" "$DEFAULT_ALGORITHM" "$DEFAULT_BITS" +set_keysigning "KEY1" "yes" +set_zonesigning "KEY1" "no" + +set_keyrole "KEY2" "zsk" +set_keylifetime "KEY2" "0" +set_keyalgorithm "KEY2" "$DEFAULT_ALGORITHM_NUMBER" "$DEFAULT_ALGORITHM" "$DEFAULT_BITS" +set_keysigning "KEY2" "no" +set_zonesigning "KEY2" "yes" + +set_keystate "KEY1" "GOAL" "omnipresent" +set_keystate "KEY1" "STATE_DNSKEY" "rumoured" +set_keystate "KEY1" "STATE_KRRSIG" "rumoured" +set_keystate "KEY1" "STATE_DS" "hidden" +set_keystate "KEY2" "GOAL" "omnipresent" +set_keystate "KEY2" "STATE_DNSKEY" "rumoured" +set_keystate "KEY2" "STATE_ZRRSIG" "rumoured" + +check_keys +check_dnssecstatus "$SERVER" "$POLICY" "$ZONE" +check_apex +check_subdomain +dnssec_verify + +# Check that the ZSKs from the other provider are published. +zsks_are_published() { + dig_with_opts +short "$ZONE" "@${SERVER}" DNSKEY > "dig.out.$DIR.test$n" || return 1 + # We should have three ZSKs. + lines=$(grep "256 3 13" dig.out.$DIR.test$n | wc -l) + test "$lines" -eq 3 || return 1 + # And one KSK. + lines=$(grep "257 3 13" dig.out.$DIR.test$n | wc -l) + test "$lines" -eq 1 || return 1 +} + +n=$((n+1)) +echo_i "update zone with ZSK from another provider for zone ${ZONE} ($n)" +ret=0 +( +echo zone ${ZONE} +echo server 10.53.0.3 "$PORT" +echo update add $(cat "${DIR}/${ZONE}.zsk2") +echo send +) | $NSUPDATE +retry_quiet 10 zsks_are_published || ret=1 +test "$ret" -eq 0 || echo_i "failed" +status=$((status+ret)) + +# +# Testing manual rollover. +# +set_zone "manual-rollover.kasp" +set_policy "manual-rollover" "2" "3600" +set_server "ns3" "10.53.0.3" +key_clear "KEY1" +key_clear "KEY2" +key_clear "KEY3" +key_clear "KEY4" +# Key properties. +set_keyrole "KEY1" "ksk" +set_keylifetime "KEY1" "0" +set_keyalgorithm "KEY1" "$DEFAULT_ALGORITHM_NUMBER" "$DEFAULT_ALGORITHM" "$DEFAULT_BITS" +set_keysigning "KEY1" "yes" +set_zonesigning "KEY1" "no" + +set_keyrole "KEY2" "zsk" +set_keylifetime "KEY2" "0" +set_keyalgorithm "KEY2" "$DEFAULT_ALGORITHM_NUMBER" "$DEFAULT_ALGORITHM" "$DEFAULT_BITS" +set_keysigning "KEY2" "no" +set_zonesigning "KEY2" "yes" +# During set up everything was set to OMNIPRESENT. +set_keystate "KEY1" "GOAL" "omnipresent" +set_keystate "KEY1" "STATE_DNSKEY" "omnipresent" +set_keystate "KEY1" "STATE_KRRSIG" "omnipresent" +set_keystate "KEY1" "STATE_DS" "omnipresent" + +set_keystate "KEY2" "GOAL" "omnipresent" +set_keystate "KEY2" "STATE_DNSKEY" "omnipresent" +set_keystate "KEY2" "STATE_ZRRSIG" "omnipresent" + +check_keys +check_dnssecstatus "$SERVER" "$POLICY" "$ZONE" + +# The first keys were published and activated a day ago. +created=$(key_get KEY1 CREATED) +set_addkeytime "KEY1" "PUBLISHED" "${created}" -86400 +set_addkeytime "KEY1" "SYNCPUBLISH" "${created}" -86400 +set_addkeytime "KEY1" "ACTIVE" "${created}" -86400 +created=$(key_get KEY2 CREATED) +set_addkeytime "KEY2" "PUBLISHED" "${created}" -86400 +set_addkeytime "KEY2" "ACTIVE" "${created}" -86400 +# Key lifetimes are unlimited, so not setting RETIRED and REMOVED. +check_keytimes +check_apex +check_subdomain +dnssec_verify + +# Schedule KSK rollover in six months (15552000 seconds). +active=$(key_get KEY1 ACTIVE) +set_addkeytime "KEY1" "RETIRED" "${active}" 15552000 +retired=$(key_get KEY1 RETIRED) +rndc_rollover "$SERVER" "$DIR" $(key_get KEY1 ID) "${retired}" "$ZONE" +# Rollover starts in six months, but lifetime is set to six months plus +# prepublication duration = 15552000 + 7500 = 15559500 seconds. +set_keylifetime "KEY1" "15559500" +set_addkeytime "KEY1" "RETIRED" "${active}" 15559500 +retired=$(key_get KEY1 RETIRED) +# Retire interval of this policy is 26h (93600 seconds). +set_addkeytime "KEY1" "REMOVED" "${retired}" 93600 + +check_keys +check_dnssecstatus "$SERVER" "$POLICY" "$ZONE" +check_keytimes +check_apex +check_subdomain +dnssec_verify + +# Schedule KSK rollover now. +set_policy "manual-rollover" "3" "3600" +set_keystate "KEY1" "GOAL" "hidden" +# This key was activated one day ago, so lifetime is set to 1d plus +# prepublication duration (7500 seconds) = 93900 seconds. +set_keylifetime "KEY1" "93900" +created=$(key_get KEY1 CREATED) +set_keytime "KEY1" "RETIRED" "${created}" +rndc_rollover "$SERVER" "$DIR" $(key_get KEY1 ID) "${created}" "$ZONE" +# New key is introduced. +set_keyrole "KEY3" "ksk" +set_keylifetime "KEY3" "0" +set_keyalgorithm "KEY3" "13" "ECDSAP256SHA256" "256" +set_keysigning "KEY3" "yes" +set_zonesigning "KEY3" "no" + +set_keystate "KEY3" "GOAL" "omnipresent" +set_keystate "KEY3" "STATE_DNSKEY" "rumoured" +set_keystate "KEY3" "STATE_KRRSIG" "rumoured" +set_keystate "KEY3" "STATE_DS" "hidden" + +check_keys +check_dnssecstatus "$SERVER" "$POLICY" "$ZONE" +check_apex +check_subdomain +dnssec_verify + +# Schedule ZSK rollover now. +set_policy "manual-rollover" "4" "3600" +set_keystate "KEY2" "GOAL" "hidden" +# This key was activated one day ago, so lifetime is set to 1d plus +# prepublication duration (7500 seconds) = 93900 seconds. +set_keylifetime "KEY2" "93900" +created=$(key_get KEY2 CREATED) +set_keytime "KEY2" "RETIRED" "${created}" +rndc_rollover "$SERVER" "$DIR" $(key_get KEY2 ID) "${created}" "$ZONE" +# New key is introduced. +set_keyrole "KEY4" "zsk" +set_keylifetime "KEY4" "0" +set_keyalgorithm "KEY4" "13" "ECDSAP256SHA256" "256" +set_keysigning "KEY4" "no" +set_zonesigning "KEY4" "no" # not yet, first prepublish DNSKEY. + +set_keystate "KEY4" "GOAL" "omnipresent" +set_keystate "KEY4" "STATE_DNSKEY" "rumoured" +set_keystate "KEY4" "STATE_ZRRSIG" "hidden" + +check_keys +check_dnssecstatus "$SERVER" "$POLICY" "$ZONE" +check_apex +check_subdomain +dnssec_verify + +# Try to schedule a ZSK rollover for an inactive key (should fail). +n=$((n+1)) +echo_i "check that rndc dnssec -rollover fails if key is inactive ($n)" +ret=0 +rndccmd "$SERVER" dnssec -rollover -key $(key_get KEY4 ID) "$ZONE" > rndc.dnssec.rollover.out.$ZONE.$n +grep "key is not actively signing" rndc.dnssec.rollover.out.$ZONE.$n > /dev/null || log_error "bad error message" +test "$ret" -eq 0 || echo_i "failed" +status=$((status+ret)) + +# +# Testing DNSSEC introduction. +# + +# +# Zone: step1.enable-dnssec.autosign. +# +set_zone "step1.enable-dnssec.autosign" +set_policy "enable-dnssec" "1" "300" +set_server "ns3" "10.53.0.3" +# Key properties. +key_clear "KEY1" +set_keyrole "KEY1" "csk" +set_keylifetime "KEY1" "0" +set_keyalgorithm "KEY1" "$DEFAULT_ALGORITHM_NUMBER" "$DEFAULT_ALGORITHM" "$DEFAULT_BITS" +set_keysigning "KEY1" "yes" +set_zonesigning "KEY1" "yes" +# The DNSKEY and signatures are introduced first, the DS remains hidden. +set_keystate "KEY1" "GOAL" "omnipresent" +set_keystate "KEY1" "STATE_DNSKEY" "rumoured" +set_keystate "KEY1" "STATE_KRRSIG" "rumoured" +set_keystate "KEY1" "STATE_ZRRSIG" "rumoured" +set_keystate "KEY1" "STATE_DS" "hidden" +# This policy lists only one key (CSK). +key_clear "KEY2" +key_clear "KEY3" +key_clear "KEY4" + +check_keys +check_dnssecstatus "$SERVER" "$POLICY" "$ZONE" + +# Set expected key times: +# - The first key is immediately published and activated. +created=$(key_get KEY1 CREATED) +set_keytime "KEY1" "PUBLISHED" "${created}" +set_keytime "KEY1" "ACTIVE" "${created}" +# - The DS can be published if the DNSKEY and RRSIG records are +# OMNIPRESENT. This happens after max-zone-ttl (12h) plus +# publish-safety (5m) plus zone-propagation-delay (5m) = +# 43200 + 300 + 300 = 43800. +set_addkeytime "KEY1" "SYNCPUBLISH" "${created}" 43800 +# - Key lifetime is unlimited, so not setting RETIRED and REMOVED. + +# Various signing policy checks. +check_keytimes +check_apex +check_subdomain +dnssec_verify + +_check_next_key_event() { + _expect=$1 + + grep "zone ${ZONE}.*: next key event in .* seconds" "${DIR}/named.run" > "keyevent.out.$ZONE.test$n" || return 1 + + # Get the latest next key event. + if [ "${DYNAMIC}" = "yes" ]; then + _time=$(awk '{print $9}' < "keyevent.out.$ZONE.test$n" | tail -1) + else + # inline-signing zone adds "(signed)" + _time=$(awk '{print $10}' < "keyevent.out.$ZONE.test$n" | tail -1) + fi + + # The next key event time must within threshold of the + # expected time. + _expectmin=$((_expect-next_key_event_threshold)) + _expectmax=$((_expect+next_key_event_threshold)) + + test $_expectmin -le "$_time" || return 1 + test $_expectmax -ge "$_time" || return 1 + + return 0 +} + +check_next_key_event() { + n=$((n+1)) + echo_i "check next key event for zone ${ZONE} ($n)" + ret=0 + + retry_quiet 3 _check_next_key_event $1 || log_error "bad next key event time for zone ${ZONE} (expect ${_expect})" + test "$ret" -eq 0 || echo_i "failed" + status=$((status+ret)) + +} + +# Next key event is when the DNSKEY RRset becomes OMNIPRESENT: DNSKEY TTL plus +# publish safety plus the zone propagation delay: 900 seconds. +check_next_key_event 900 + +# +# Zone: step2.enable-dnssec.autosign. +# +set_zone "step2.enable-dnssec.autosign" +set_policy "enable-dnssec" "1" "300" +set_server "ns3" "10.53.0.3" +# The DNSKEY is omnipresent, but the zone signatures not yet. +# Thus, the DS remains hidden. +set_keystate "KEY1" "STATE_DNSKEY" "omnipresent" +set_keystate "KEY1" "STATE_KRRSIG" "omnipresent" + +# Various signing policy checks. +check_keys +check_dnssecstatus "$SERVER" "$POLICY" "$ZONE" + +# Set expected key times: +# - The key was published and activated 900 seconds ago (with settime). +created=$(key_get KEY1 CREATED) +set_addkeytime "KEY1" "PUBLISHED" "${created}" -900 +set_addkeytime "KEY1" "ACTIVE" "${created}" -900 +set_addkeytime "KEY1" "SYNCPUBLISH" "${created}" 43800 + +# Continue signing policy checks. +check_keytimes +check_apex +check_subdomain +dnssec_verify + +# Next key event is when the zone signatures become OMNIPRESENT: max-zone-ttl +# plus zone propagation delay plus retire safety minus the already elapsed +# 900 seconds: 12h + 300s + 20m - 900 = 44700 - 900 = 43800 seconds +check_next_key_event 43800 + +# +# Zone: step3.enable-dnssec.autosign. +# +set_zone "step3.enable-dnssec.autosign" +set_policy "enable-dnssec" "1" "300" +set_server "ns3" "10.53.0.3" +# All signatures should be omnipresent, so the DS can be submitted. +set_keystate "KEY1" "STATE_ZRRSIG" "omnipresent" +set_keystate "KEY1" "STATE_DS" "rumoured" + +# Various signing policy checks. +check_keys +check_dnssecstatus "$SERVER" "$POLICY" "$ZONE" + +# Set expected key times: +# - The key was published and activated 44700 seconds ago (with settime). +created=$(key_get KEY1 CREATED) +set_addkeytime "KEY1" "PUBLISHED" "${created}" -44700 +set_addkeytime "KEY1" "ACTIVE" "${created}" -44700 +set_keytime "KEY1" "SYNCPUBLISH" "${created}" + +# Continue signing policy checks. +check_keytimes +check_apex +check_subdomain +dnssec_verify +# Check that CDS publication is logged. +check_cdslog "$DIR" "$ZONE" KEY1 + +# The DS can be introduced. We ignore any parent registration delay, so set +# the DS publish time to now. +rndc_checkds "$SERVER" "$DIR" KEY1 "now" "published" "$ZONE" +# Next key event is when the DS can move to the OMNIPRESENT state. This occurs +# when the parent propagation delay have passed, plus the DS TTL and retire +# safety delay: 1h + 2h + 20m = 3h20m = 12000 seconds +check_next_key_event 12000 + +# +# Zone: step4.enable-dnssec.autosign. +# +set_zone "step4.enable-dnssec.autosign" +set_policy "enable-dnssec" "1" "300" +set_server "ns3" "10.53.0.3" +# The DS is omnipresent. +set_keystate "KEY1" "STATE_DS" "omnipresent" + +# Various signing policy checks. +check_keys +check_dnssecstatus "$SERVER" "$POLICY" "$ZONE" + +# Set expected key times: +# - The key was published and activated 56700 seconds ago (with settime). +created=$(key_get KEY1 CREATED) +set_addkeytime "KEY1" "PUBLISHED" "${created}" -56700 +set_addkeytime "KEY1" "ACTIVE" "${created}" -56700 +set_addkeytime "KEY1" "SYNCPUBLISH" "${created}" -12000 + +# Continue signing policy checks. +check_keytimes +check_apex +check_subdomain +dnssec_verify + +# Next key event is never, the zone dnssec-policy has been established. So we +# fall back to the default loadkeys interval. +check_next_key_event 3600 + +# +# Testing ZSK Pre-Publication rollover. +# + +# Policy parameters. +# Lksk: 2 years (63072000 seconds) +# Lzsk: 30 days (2592000 seconds) +# Iret(KSK): DS TTL (1d) + DprpP (1h) + retire-safety (2d) +# Iret(KSK): 3d1h (262800 seconds) +# Iret(ZSK): RRSIG TTL (1d) + Dprp (1h) + Dsgn (1w) + retire-safety (2d) +# Iret(ZSK): 10d1h (867600 seconds) +Lksk=63072000 +Lzsk=2592000 +IretKSK=262800 +IretZSK=867600 + +# +# Zone: step1.zsk-prepub.autosign. +# +set_zone "step1.zsk-prepub.autosign" +set_policy "zsk-prepub" "2" "3600" +set_server "ns3" "10.53.0.3" + +set_retired_removed() { + _Lkey=$2 + _Iret=$3 + + _active=$(key_get $1 ACTIVE) + set_addkeytime "${1}" "RETIRED" "${_active}" "${_Lkey}" + _retired=$(key_get $1 RETIRED) + set_addkeytime "${1}" "REMOVED" "${_retired}" "${_Iret}" +} + +rollover_predecessor_keytimes() { + _addtime=$1 + + _created=$(key_get KEY1 CREATED) + set_addkeytime "KEY1" "PUBLISHED" "${_created}" "${_addtime}" + set_addkeytime "KEY1" "SYNCPUBLISH" "${_created}" "${_addtime}" + set_addkeytime "KEY1" "ACTIVE" "${_created}" "${_addtime}" + [ "$Lksk" = 0 ] || set_retired_removed "KEY1" "${Lksk}" "${IretKSK}" + + _created=$(key_get KEY2 CREATED) + set_addkeytime "KEY2" "PUBLISHED" "${_created}" "${_addtime}" + set_addkeytime "KEY2" "ACTIVE" "${_created}" "${_addtime}" + [ "$Lzsk" = 0 ] || set_retired_removed "KEY2" "${Lzsk}" "${IretZSK}" +} + +# Key properties. +key_clear "KEY1" +set_keyrole "KEY1" "ksk" +set_keylifetime "KEY1" "${Lksk}" +set_keyalgorithm "KEY1" "$DEFAULT_ALGORITHM_NUMBER" "$DEFAULT_ALGORITHM" "$DEFAULT_BITS" +set_keysigning "KEY1" "yes" +set_zonesigning "KEY1" "no" + +key_clear "KEY2" +set_keyrole "KEY2" "zsk" +set_keylifetime "KEY2" "${Lzsk}" +set_keyalgorithm "KEY2" "$DEFAULT_ALGORITHM_NUMBER" "$DEFAULT_ALGORITHM" "$DEFAULT_BITS" +set_keysigning "KEY2" "no" +set_zonesigning "KEY2" "yes" +# Both KSK (KEY1) and ZSK (KEY2) start in OMNIPRESENT. +set_keystate "KEY1" "GOAL" "omnipresent" +set_keystate "KEY1" "STATE_DNSKEY" "omnipresent" +set_keystate "KEY1" "STATE_KRRSIG" "omnipresent" +set_keystate "KEY1" "STATE_DS" "omnipresent" + +set_keystate "KEY2" "GOAL" "omnipresent" +set_keystate "KEY2" "STATE_DNSKEY" "omnipresent" +set_keystate "KEY2" "STATE_ZRRSIG" "omnipresent" +# Initially only two keys. +key_clear "KEY3" +key_clear "KEY4" + +# Various signing policy checks. +check_keys +check_dnssecstatus "$SERVER" "$POLICY" "$ZONE" +# These keys are immediately published and activated. +rollover_predecessor_keytimes 0 +check_keytimes +check_apex +check_subdomain +dnssec_verify + +# Next key event is when the successor ZSK needs to be published. That is +# the ZSK lifetime - prepublication time. The prepublication time is DNSKEY +# TTL plus publish safety plus the zone propagation delay. For the +# zsk-prepub policy that means: 30d - 3600s + 1d + 1h = 2498400 seconds. +check_next_key_event 2498400 + +# +# Zone: step2.zsk-prepub.autosign. +# +set_zone "step2.zsk-prepub.autosign" +set_policy "zsk-prepub" "3" "3600" +set_server "ns3" "10.53.0.3" +# New ZSK (KEY3) is prepublished, but not yet signing. +key_clear "KEY3" +set_keyrole "KEY3" "zsk" +set_keylifetime "KEY3" "${Lzsk}" +set_keyalgorithm "KEY3" "$DEFAULT_ALGORITHM_NUMBER" "$DEFAULT_ALGORITHM" "$DEFAULT_BITS" +set_keysigning "KEY3" "no" +set_zonesigning "KEY3" "no" +# Key states. +set_keystate "KEY2" "GOAL" "hidden" +set_keystate "KEY3" "GOAL" "omnipresent" +set_keystate "KEY3" "STATE_DNSKEY" "rumoured" +set_keystate "KEY3" "STATE_ZRRSIG" "hidden" + +# Various signing policy checks. +check_keys +check_dnssecstatus "$SERVER" "$POLICY" "$ZONE" + +# Set expected key times: +# - The old keys were activated 694 hours ago (2498400 seconds). +rollover_predecessor_keytimes -2498400 +# - The new ZSK is published now. +created=$(key_get KEY3 CREATED) +set_keytime "KEY3" "PUBLISHED" "${created}" +# - The new ZSK becomes active when the DNSKEY is OMNIPRESENT. +# Ipub: TTLkey (1h) + Dprp (1h) + publish-safety (1d) +# Ipub: 26 hour (93600 seconds). +IpubZSK=93600 +set_addkeytime "KEY3" "ACTIVE" "${created}" "${IpubZSK}" +set_retired_removed "KEY3" "${Lzsk}" "${IretZSK}" + +# Continue signing policy checks. +check_keytimes +check_apex +check_subdomain +dnssec_verify + +# Next key event is when the successor ZSK becomes OMNIPRESENT. That is the +# DNSKEY TTL plus the zone propagation delay, plus the publish-safety. For +# the zsk-prepub policy, this means: 3600s + 1h + 1d = 93600 seconds. +check_next_key_event 93600 + +# +# Zone: step3.zsk-prepub.autosign. +# +set_zone "step3.zsk-prepub.autosign" +set_policy "zsk-prepub" "3" "3600" +set_server "ns3" "10.53.0.3" +# ZSK (KEY2) no longer is actively signing, RRSIG state in UNRETENTIVE. +# New ZSK (KEY3) is now actively signing, RRSIG state in RUMOURED. +set_zonesigning "KEY2" "no" +set_keystate "KEY2" "STATE_ZRRSIG" "unretentive" +set_zonesigning "KEY3" "yes" +set_keystate "KEY3" "STATE_DNSKEY" "omnipresent" +set_keystate "KEY3" "STATE_ZRRSIG" "rumoured" + +# Various signing policy checks. +check_keys +check_dnssecstatus "$SERVER" "$POLICY" "$ZONE" + +# Set expected key times: +# - The old keys are activated 30 days ago (2592000 seconds). +rollover_predecessor_keytimes -2592000 +# - The new ZSK is published 26 hours ago (93600 seconds). +created=$(key_get KEY3 CREATED) +set_addkeytime "KEY3" "PUBLISHED" "${created}" -93600 +set_keytime "KEY3" "ACTIVE" "${created}" +set_retired_removed "KEY3" "${Lzsk}" "${IretZSK}" + +# Continue signing policy checks. +check_keytimes +check_apex +# Subdomain still has good signatures of ZSK (KEY2). +# Set expected zone signing on for KEY2 and off for KEY3, +# testing whether signatures which are still valid are being reused. +set_zonesigning "KEY2" "yes" +set_zonesigning "KEY3" "no" +check_subdomain +# Restore the expected zone signing properties. +set_zonesigning "KEY2" "no" +set_zonesigning "KEY3" "yes" +dnssec_verify + +# Next key event is when all the RRSIG records have been replaced with +# signatures of the new ZSK, in other words when ZRRSIG becomes OMNIPRESENT. +# That is Dsgn plus the maximum zone TTL plus the zone propagation delay plus +# retire-safety. For the zsk-prepub policy that means: 1w (because 2w validity +# and refresh within a week) + 1d + 1h + 2d = 10d1h = 867600 seconds. +check_next_key_event 867600 + +# +# Zone: step4.zsk-prepub.autosign. +# +set_zone "step4.zsk-prepub.autosign" +set_policy "zsk-prepub" "3" "3600" +set_server "ns3" "10.53.0.3" +# ZSK (KEY2) DNSKEY is no longer needed. +# ZSK (KEY3) is now actively signing, RRSIG state in RUMOURED. +set_keystate "KEY2" "STATE_DNSKEY" "unretentive" +set_keystate "KEY2" "STATE_ZRRSIG" "hidden" +set_keystate "KEY3" "STATE_ZRRSIG" "omnipresent" + +# Various signing policy checks. +check_keys +check_dnssecstatus "$SERVER" "$POLICY" "$ZONE" + +# Set expected key times: +# - The old keys are activated 961 hours ago (3459600 seconds). +rollover_predecessor_keytimes -3459600 +# - The new ZSK is published 267 hours ago (961200 seconds). +created=$(key_get KEY3 CREATED) +set_addkeytime "KEY3" "PUBLISHED" "${created}" -961200 +published=$(key_get KEY3 PUBLISHED) +set_addkeytime "KEY3" "ACTIVE" "${published}" "${IpubZSK}" +set_retired_removed "KEY3" "${Lzsk}" "${IretZSK}" + +# Continue signing policy checks. +check_keytimes +check_apex +check_subdomain +dnssec_verify + +# Next key event is when the DNSKEY enters the HIDDEN state. This is the +# DNSKEY TTL plus zone propagation delay. For the zsk-prepub policy this is: +# 3600s + 1h = 7200s +check_next_key_event 7200 + +# +# Zone: step5.zsk-prepub.autosign. +# +set_zone "step5.zsk-prepub.autosign" +set_policy "zsk-prepub" "3" "3600" +set_server "ns3" "10.53.0.3" +# ZSK (KEY2) DNSKEY is now completely HIDDEN and removed. +set_keystate "KEY2" "STATE_DNSKEY" "hidden" + +# Various signing policy checks. +check_keys +check_dnssecstatus "$SERVER" "$POLICY" "$ZONE" + +# Set expected key times: +# - The old keys are activated 962 hours ago (3463200 seconds). +rollover_predecessor_keytimes -3463200 +# - The new ZSK is published 268 hours ago (964800 seconds). +created=$(key_get KEY3 CREATED) +set_addkeytime "KEY3" "PUBLISHED" "${created}" -964800 +published=$(key_get KEY3 PUBLISHED) +set_addkeytime "KEY3" "ACTIVE" "${published}" "${IpubZSK}" +set_retired_removed "KEY3" "${Lzsk}" "${IretZSK}" + +# Continue signing policy checks. +check_keytimes +check_apex +check_subdomain +dnssec_verify + +# Next key event is when the new successor needs to be published. This is the +# ZSK lifetime minus Iret minus Ipub minus DNSKEY TTL. For the zsk-prepub +# policy this is: 30d - 867600s - 93600s - 3600s = 1627200 seconds. +check_next_key_event 1627200 + +# +# Zone: step6.zsk-prepub.autosign. +# +set_zone "step6.zsk-prepub.autosign" +set_policy "zsk-prepub" "2" "3600" +set_server "ns3" "10.53.0.3" +# ZSK (KEY2) DNSKEY is purged. +key_clear "KEY2" + +# Various signing policy checks. +check_keys +check_dnssecstatus "$SERVER" "$POLICY" "$ZONE" +check_apex +check_subdomain +dnssec_verify + +# +# Testing KSK Double-KSK rollover. +# + +# Policy parameters. +# Lksk: 60 days (16070400 seconds) +# Lzsk: 1 year (31536000 seconds) +# Iret(KSK): DS TTL (1h) + DprpP (1h) + retire-safety (2d) +# Iret(KSK): 50h (180000 seconds) +# Iret(ZSK): RRSIG TTL (1d) + Dprp (1h) + Dsgn (1w) + retire-safety (2d) +# Iret(ZSK): 10d1h (867600 seconds) +Lksk=5184000 +Lzsk=31536000 +IretKSK=180000 +IretZSK=867600 + +# +# Zone: step1.ksk-doubleksk.autosign. +# +set_zone "step1.ksk-doubleksk.autosign" +set_policy "ksk-doubleksk" "2" "7200" +set_server "ns3" "10.53.0.3" +# Key properties. +key_clear "KEY1" +set_keyrole "KEY1" "ksk" +set_keylifetime "KEY1" "${Lksk}" +set_keyalgorithm "KEY1" "$DEFAULT_ALGORITHM_NUMBER" "$DEFAULT_ALGORITHM" "$DEFAULT_BITS" +set_keysigning "KEY1" "yes" +set_zonesigning "KEY1" "no" + +key_clear "KEY2" +set_keyrole "KEY2" "zsk" +set_keylifetime "KEY2" "${Lzsk}" +set_keyalgorithm "KEY2" "$DEFAULT_ALGORITHM_NUMBER" "$DEFAULT_ALGORITHM" "$DEFAULT_BITS" +set_keysigning "KEY2" "no" +set_zonesigning "KEY2" "yes" +# Both KSK (KEY1) and ZSK (KEY2) start in OMNIPRESENT. +set_keystate "KEY1" "GOAL" "omnipresent" +set_keystate "KEY1" "STATE_DNSKEY" "omnipresent" +set_keystate "KEY1" "STATE_KRRSIG" "omnipresent" +set_keystate "KEY1" "STATE_DS" "omnipresent" + +set_keystate "KEY2" "GOAL" "omnipresent" +set_keystate "KEY2" "STATE_DNSKEY" "omnipresent" +set_keystate "KEY2" "STATE_ZRRSIG" "omnipresent" +# Initially only two keys. +key_clear "KEY3" +key_clear "KEY4" + +# Various signing policy checks. +check_keys +check_dnssecstatus "$SERVER" "$POLICY" "$ZONE" +# These keys are immediately published and activated. +rollover_predecessor_keytimes 0 +check_keytimes +check_apex +check_subdomain +dnssec_verify + +# Next key event is when the successor KSK needs to be published. That is +# the KSK lifetime - prepublication time. The prepublication time is +# DNSKEY TTL plus publish safety plus the zone propagation delay. +# For the ksk-doubleksk policy that means: 60d - (1d3h) = 5086800 seconds. +check_next_key_event 5086800 + +# +# Zone: step2.ksk-doubleksk.autosign. +# +set_zone "step2.ksk-doubleksk.autosign" +set_policy "ksk-doubleksk" "3" "7200" +set_server "ns3" "10.53.0.3" +# New KSK (KEY3) is prepublished (and signs DNSKEY RRset). +key_clear "KEY3" +set_keyrole "KEY3" "ksk" +set_keylifetime "KEY3" "${Lksk}" +set_keyalgorithm "KEY3" "$DEFAULT_ALGORITHM_NUMBER" "$DEFAULT_ALGORITHM" "$DEFAULT_BITS" +set_keysigning "KEY3" "yes" +set_zonesigning "KEY3" "no" +# Key states. +set_keystate "KEY1" "GOAL" "hidden" +set_keystate "KEY3" "GOAL" "omnipresent" +set_keystate "KEY3" "STATE_DNSKEY" "rumoured" +set_keystate "KEY3" "STATE_KRRSIG" "rumoured" +set_keystate "KEY3" "STATE_DS" "hidden" + +# Various signing policy checks. +check_keys +check_dnssecstatus "$SERVER" "$POLICY" "$ZONE" + +# Set expected key times: +# - The old keys were activated 1413 hours ago (5086800 seconds). +rollover_predecessor_keytimes -5086800 +# - The new KSK is published now. +created=$(key_get KEY3 CREATED) +set_keytime "KEY3" "PUBLISHED" "${created}" +# The new KSK should publish the CDS after the prepublication time. +# TTLkey: 2h +# DprpC: 1h +# publish-safety: 1d +# IpubC: 27h (97200 seconds) +IpubC=97200 +set_addkeytime "KEY3" "SYNCPUBLISH" "${created}" "${IpubC}" +set_addkeytime "KEY3" "ACTIVE" "${created}" "${IpubC}" +set_retired_removed "KEY3" "${Lksk}" "${IretKSK}" + +# Continue signing policy checks. +check_keytimes +check_apex +check_subdomain +dnssec_verify + +# Next key event is when the successor KSK becomes OMNIPRESENT. That is the +# DNSKEY TTL plus the zone propagation delay, plus the publish-safety. For +# the ksk-doubleksk policy, this means: 7200s + 1h + 1d = 97200 seconds. +check_next_key_event 97200 + +# +# Zone: step3.ksk-doubleksk.autosign. +# +set_zone "step3.ksk-doubleksk.autosign" +set_policy "ksk-doubleksk" "3" "7200" +set_server "ns3" "10.53.0.3" + +# The DNSKEY RRset has become omnipresent. +# Check keys before we tell named that we saw the DS has been replaced. +set_keystate "KEY3" "STATE_DNSKEY" "omnipresent" +set_keystate "KEY3" "STATE_KRRSIG" "omnipresent" +# The old DS (KEY1) can be withdrawn and the new DS (KEY3) can be introduced. +set_keystate "KEY1" "STATE_DS" "unretentive" +set_keystate "KEY3" "STATE_DS" "rumoured" + +# Various signing policy checks. +check_keys +check_dnssecstatus "$SERVER" "$POLICY" "$ZONE" +# Check that CDS publication is logged. +check_cdslog "$DIR" "$ZONE" KEY3 + +# Set expected key times: +# - The old keys were activated 60 days ago (5184000 seconds). +rollover_predecessor_keytimes -5184000 +# - The new KSK is published 27 hours ago (97200 seconds). +created=$(key_get KEY3 CREATED) +set_addkeytime "KEY3" "PUBLISHED" "${created}" -97200 +# - The new KSK CDS is published now. +set_keytime "KEY3" "SYNCPUBLISH" "${created}" +syncpub=$(key_get KEY3 SYNCPUBLISH) +set_keytime "KEY3" "ACTIVE" "${syncpub}" +set_retired_removed "KEY3" "${Lksk}" "${IretKSK}" + +# Continue signing policy checks. +check_keytimes +check_apex +check_subdomain +dnssec_verify + +# We ignore any parent registration delay, so set the DS publish time to now. +rndc_checkds "$SERVER" "$DIR" KEY1 "now" "withdrawn" "$ZONE" +rndc_checkds "$SERVER" "$DIR" KEY3 "now" "published" "$ZONE" +# 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, which is the parent propagation delay plus the DS TTL +# plus the retire-safety. For the ksk-double-ksk policy this means: +# 1h + 3600s + 2d = 2d2h = 180000 seconds. +check_next_key_event 180000 + +# +# Zone: step4.ksk-doubleksk.autosign. +# +set_zone "step4.ksk-doubleksk.autosign" +set_policy "ksk-doubleksk" "3" "7200" +set_server "ns3" "10.53.0.3" +# KSK (KEY1) DNSKEY can be removed. +set_keysigning "KEY1" "no" +set_keystate "KEY1" "STATE_DNSKEY" "unretentive" +set_keystate "KEY1" "STATE_KRRSIG" "unretentive" +set_keystate "KEY1" "STATE_DS" "hidden" +# New KSK (KEY3) DS is now OMNIPRESENT. +set_keystate "KEY3" "STATE_DS" "omnipresent" + +# Various signing policy checks. +check_keys +check_dnssecstatus "$SERVER" "$POLICY" "$ZONE" + +# Set expected key times: +# - The old keys were activated 1490 hours ago (5364000 seconds). +rollover_predecessor_keytimes -5364000 +# - The new KSK is published 77 hours ago (277200 seconds). +created=$(key_get KEY3 CREATED) +set_addkeytime "KEY3" "PUBLISHED" "${created}" -277200 +published=$(key_get KEY3 PUBLISHED) +set_addkeytime "KEY3" "SYNCPUBLISH" "${published}" "${IpubC}" +syncpub=$(key_get KEY3 SYNCPUBLISH) +set_keytime "KEY3" "ACTIVE" "${syncpub}" +set_retired_removed "KEY3" "${Lksk}" "${IretKSK}" + +# Continue signing policy checks. +check_keytimes +check_apex +check_subdomain +dnssec_verify + +# Next key event is when the DNSKEY enters the HIDDEN state. This is the +# DNSKEY TTL plus zone propagation delay. For the ksk-doubleksk policy this is: +# 7200s + 1h = 10800s +check_next_key_event 10800 + +# +# Zone: step5.ksk-doubleksk.autosign. +# +set_zone "step5.ksk-doubleksk.autosign" +set_policy "ksk-doubleksk" "3" "7200" +set_server "ns3" "10.53.0.3" +# KSK (KEY1) DNSKEY is now HIDDEN. +set_keystate "KEY1" "STATE_DNSKEY" "hidden" +set_keystate "KEY1" "STATE_KRRSIG" "hidden" + +# Various signing policy checks. +check_keys +check_dnssecstatus "$SERVER" "$POLICY" "$ZONE" + +# Set expected key times: +# - The old KSK is activated 1492 hours ago (5371200 seconds). +rollover_predecessor_keytimes -5371200 +# - The new KSK is published 79 hours ago (284400 seconds). +created=$(key_get KEY3 CREATED) +set_addkeytime "KEY3" "PUBLISHED" "${created}" -284400 +published=$(key_get KEY3 PUBLISHED) +set_addkeytime "KEY3" "SYNCPUBLISH" "${published}" "${IpubC}" +syncpub=$(key_get KEY3 SYNCPUBLISH) +set_keytime "KEY3" "ACTIVE" "${syncpub}" +set_retired_removed "KEY3" "${Lksk}" "${IretKSK}" + +# Various signing policy checks. +check_keytimes +check_apex +check_subdomain +dnssec_verify + +# Next key event is when the new successor needs to be published. This is the +# KSK lifetime minus Ipub minus Iret minus DNSKEY TTL. For the +# ksk-doubleksk this is: 60d - 1d3h - 1d - 2d2h - 2h = +# 5184000 - 97200 - 180000 - 7200 = 4813200 seconds. +check_next_key_event 4899600 + +# +# Zone: step6.ksk-doubleksk.autosign. +# +set_zone "step6.ksk-doubleksk.autosign" +set_policy "ksk-doubleksk" "2" "7200" +set_server "ns3" "10.53.0.3" +# KSK (KEY1) DNSKEY is purged. +key_clear "KEY1" + +# Various signing policy checks. +check_keys +check_dnssecstatus "$SERVER" "$POLICY" "$ZONE" +check_apex +check_subdomain +dnssec_verify + +# +# Testing CSK key rollover (1). +# + +# Policy parameters. +# Lcsk: 186 days (5184000 seconds) +# Iret(KSK): DS TTL (1h) + DprpP (1h) + retire-safety (2h) +# Iret(KSK): 4h (14400 seconds) +# Iret(ZSK): RRSIG TTL (1d) + Dprp (1h) + Dsgn (25d) + retire-safety (2h) +# Iret(ZSK): 26d3h (2257200 seconds) +Lcsk=16070400 +IretKSK=14400 +IretZSK=2257200 +IretCSK=$IretZSK + +csk_rollover_predecessor_keytimes() { + _addtime=$1 + + _created=$(key_get KEY1 CREATED) + set_addkeytime "KEY1" "PUBLISHED" "${_created}" "${_addtime}" + set_addkeytime "KEY1" "SYNCPUBLISH" "${_created}" "${_addtime}" + set_addkeytime "KEY1" "ACTIVE" "${_created}" "${_addtime}" + [ "$Lcsk" = 0 ] || set_retired_removed "KEY1" "${Lcsk}" "${IretCSK}" +} + +# +# Zone: step1.csk-roll.autosign. +# +set_zone "step1.csk-roll.autosign" +set_policy "csk-roll" "1" "3600" +set_server "ns3" "10.53.0.3" +# Key properties. +key_clear "KEY1" +set_keyrole "KEY1" "csk" +set_keylifetime "KEY1" "${Lcsk}" +set_keyalgorithm "KEY1" "$DEFAULT_ALGORITHM_NUMBER" "$DEFAULT_ALGORITHM" "$DEFAULT_BITS" +set_keysigning "KEY1" "yes" +set_zonesigning "KEY1" "yes" +# The CSK (KEY1) starts in OMNIPRESENT. +set_keystate "KEY1" "GOAL" "omnipresent" +set_keystate "KEY1" "STATE_DNSKEY" "omnipresent" +set_keystate "KEY1" "STATE_KRRSIG" "omnipresent" +set_keystate "KEY1" "STATE_ZRRSIG" "omnipresent" +set_keystate "KEY1" "STATE_DS" "omnipresent" +# Initially only one key. +key_clear "KEY2" +key_clear "KEY3" +key_clear "KEY4" + +# Various signing policy checks. +check_keys +check_dnssecstatus "$SERVER" "$POLICY" "$ZONE" +# This key is immediately published and activated. +csk_rollover_predecessor_keytimes 0 +check_keytimes +check_apex +check_subdomain +dnssec_verify + +# Next key event is when the successor CSK needs to be published. +# This is Lcsk - Ipub - Dreg. +# Lcsk: 186d (16070400 seconds) +# Ipub: 3h (10800 seconds) +check_next_key_event 16059600 + +# +# Zone: step2.csk-roll.autosign. +# +set_zone "step2.csk-roll.autosign" +set_policy "csk-roll" "2" "3600" +set_server "ns3" "10.53.0.3" +# New CSK (KEY2) is prepublished (signs DNSKEY RRset, but not yet other RRsets). +key_clear "KEY2" +set_keyrole "KEY2" "csk" +set_keylifetime "KEY2" "16070400" +set_keyalgorithm "KEY2" "$DEFAULT_ALGORITHM_NUMBER" "$DEFAULT_ALGORITHM" "$DEFAULT_BITS" +set_keysigning "KEY2" "yes" +set_zonesigning "KEY2" "no" +# Key states. +set_keystate "KEY1" "GOAL" "hidden" +set_keystate "KEY2" "GOAL" "omnipresent" +set_keystate "KEY2" "STATE_DNSKEY" "rumoured" +set_keystate "KEY2" "STATE_KRRSIG" "rumoured" +set_keystate "KEY2" "STATE_ZRRSIG" "hidden" +set_keystate "KEY2" "STATE_DS" "hidden" + +# Various signing policy checks. +check_keys +check_dnssecstatus "$SERVER" "$POLICY" "$ZONE" + +# Set expected key times: +# - This key was activated 4461 hours ago (16059600 seconds). +csk_rollover_predecessor_keytimes -16059600 +# - The new CSK is published now. +created=$(key_get KEY2 CREATED) +set_keytime "KEY2" "PUBLISHED" "${created}" +# - The new CSK should publish the CDS after the prepublication time. +# Ipub: 3 hour (10800 seconds) +Ipub="10800" +set_addkeytime "KEY2" "SYNCPUBLISH" "${created}" "${Ipub}" +set_addkeytime "KEY2" "ACTIVE" "${created}" "${Ipub}" +set_retired_removed "KEY2" "${Lcsk}" "${IretCSK}" + +# Continue signing policy checks. +check_keytimes +check_apex +check_subdomain +dnssec_verify + +# Next key event is when the successor CSK becomes OMNIPRESENT. That is the +# DNSKEY TTL plus the zone propagation delay, plus the publish-safety. For +# the csk-roll policy, this means 3 hours = 10800 seconds. +check_next_key_event 10800 + +# +# Zone: step3.csk-roll.autosign. +# +set_zone "step3.csk-roll.autosign" +set_policy "csk-roll" "2" "3600" +set_server "ns3" "10.53.0.3" +# Swap zone signing role. +set_zonesigning "KEY1" "no" +set_zonesigning "KEY2" "yes" +# CSK (KEY1) will be removed, so moving to UNRETENTIVE. +set_keystate "KEY1" "STATE_ZRRSIG" "unretentive" +# New CSK (KEY2) DNSKEY is OMNIPRESENT, so moving ZRRSIG to RUMOURED. +set_keystate "KEY2" "STATE_DNSKEY" "omnipresent" +set_keystate "KEY2" "STATE_KRRSIG" "omnipresent" +set_keystate "KEY2" "STATE_ZRRSIG" "rumoured" +# The old DS (KEY1) can be withdrawn and the new DS (KEY2) can be introduced. +set_keystate "KEY1" "STATE_DS" "unretentive" +set_keystate "KEY2" "STATE_DS" "rumoured" + +# Various signing policy checks. +check_keys +check_dnssecstatus "$SERVER" "$POLICY" "$ZONE" +# Check that CDS publication is logged. +check_cdslog "$DIR" "$ZONE" KEY2 + +# Set expected key times: +# - This key was activated 186 days ago (16070400 seconds). +csk_rollover_predecessor_keytimes -16070400 +# - The new CSK is published three hours ago, CDS must be published now. +created=$(key_get KEY2 CREATED) +set_addkeytime "KEY2" "PUBLISHED" "${created}" "-${Ipub}" +set_keytime "KEY2" "SYNCPUBLISH" "${created}" +# - Also signatures are being introduced now. +set_keytime "KEY2" "ACTIVE" "${created}" +set_retired_removed "KEY2" "${Lcsk}" "${IretCSK}" + +# Continue signing policy checks. +check_keytimes +check_apex +# Subdomain still has good signatures of old CSK (KEY1). +# Set expected zone signing on for KEY1 and off for KEY2, +# testing whether signatures which are still valid are being reused. +set_zonesigning "KEY1" "yes" +set_zonesigning "KEY2" "no" +check_subdomain +# Restore the expected zone signing properties. +set_zonesigning "KEY1" "no" +set_zonesigning "KEY2" "yes" +dnssec_verify + +# We ignore any parent registration delay, so set the DS publish time to now. +rndc_checkds "$SERVER" "$DIR" KEY1 "now" "withdrawn" "$ZONE" +rndc_checkds "$SERVER" "$DIR" KEY2 "now" "published" "$ZONE" +# 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, which is the parent propagation delay plus the DS TTL +# plus the retire-safety. For the csk-roll policy this means: +# 1h + 1h + 2h = 4h = 14400 seconds. +check_next_key_event 14400 + +# +# Zone: step4.csk-roll.autosign. +# +set_zone "step4.csk-roll.autosign" +set_policy "csk-roll" "2" "3600" +set_server "ns3" "10.53.0.3" +# The old CSK (KEY1) is no longer signing the DNSKEY RRset. +set_keysigning "KEY1" "no" +# The old CSK (KEY1) DS is hidden. We still need to keep the DNSKEY public +# but can remove the KRRSIG records. +set_keystate "KEY1" "STATE_KRRSIG" "unretentive" +set_keystate "KEY1" "STATE_DS" "hidden" +# The new CSK (KEY2) DS is now OMNIPRESENT. +set_keystate "KEY2" "STATE_DS" "omnipresent" + +# Various signing policy checks. +check_keys +check_dnssecstatus "$SERVER" "$POLICY" "$ZONE" + +# Set expected key times: +# - This key was activated 4468 hours ago (16084800 seconds). +csk_rollover_predecessor_keytimes -16084800 +# - The new CSK started signing 4h ago (14400 seconds). +created=$(key_get KEY2 CREATED) +set_addkeytime "KEY2" "ACTIVE" "${created}" -14400 +set_addkeytime "KEY2" "SYNCPUBLISH" "${created}" -14400 +syncpub=$(key_get KEY2 SYNCPUBLISH) +set_addkeytime "KEY2" "PUBLISHED" "${syncpub}" "-${Ipub}" +set_retired_removed "KEY2" "${Lcsk}" "${IretCSK}" + +# Continue signing policy checks. +check_keytimes +check_apex +check_subdomain +dnssec_verify + +# Next key event is when the KRRSIG enters the HIDDEN state. This is the +# DNSKEY TTL plus zone propagation delay. For the csk-roll policy this is: +# 1h + 1h = 7200 seconds. +check_next_key_event 7200 + +# +# Zone: step5.csk-roll.autosign. +# +set_zone "step5.csk-roll.autosign" +set_policy "csk-roll" "2" "3600" +set_server "ns3" "10.53.0.3" +# The old CSK (KEY1) KRRSIG records are now all hidden. +set_keystate "KEY1" "STATE_KRRSIG" "hidden" + +# Various signing policy checks. +check_keys +check_dnssecstatus "$SERVER" "$POLICY" "$ZONE" + +# Set expected key times: +# - This key was activated 4470 hours ago (16092000 seconds). +csk_rollover_predecessor_keytimes -16092000 +# - The new CSK started signing 6h ago (21600 seconds). +created=$(key_get KEY2 CREATED) +set_addkeytime "KEY2" "ACTIVE" "${created}" -21600 +set_addkeytime "KEY2" "SYNCPUBLISH" "${created}" -21600 +syncpub=$(key_get KEY2 SYNCPUBLISH) +set_addkeytime "KEY2" "PUBLISHED" "${syncpub}" "-${Ipub}" +set_retired_removed "KEY2" "${Lcsk}" "${IretCSK}" + +# Continue signing policy checks. +check_keytimes +check_apex +check_subdomain +dnssec_verify + +# Next key event is when the DNSKEY can be removed. This is when all ZRRSIG +# records have been replaced with signatures of the new CSK. We have +# calculated the interval to be 26d3h of which 4h (Iret(KSK)) plus +# 2h (DNSKEY TTL + Dprp) have already passed. So next key event is in +# 26d3h - 4h - 2h = 621h = 2235600 seconds. +check_next_key_event 2235600 + +# +# Zone: step6.csk-roll.autosign. +# +set_zone "step6.csk-roll.autosign" +set_policy "csk-roll" "2" "3600" +set_server "ns3" "10.53.0.3" +# The old CSK (KEY1) ZRRSIG records are now all hidden (so the DNSKEY can +# be removed). +set_keystate "KEY1" "STATE_DNSKEY" "unretentive" +set_keystate "KEY1" "STATE_ZRRSIG" "hidden" +# The new CSK (KEY2) is now fully OMNIPRESENT. +set_keystate "KEY2" "STATE_ZRRSIG" "omnipresent" + +# Various signing policy checks. +check_keys +check_dnssecstatus "$SERVER" "$POLICY" "$ZONE" + +# Set expected key times +# - This key was activated 5091 hours ago (18327600 seconds). +csk_rollover_predecessor_keytimes -18327600 +# - The new CSK is activated 627 hours ago (2257200 seconds). +created=$(key_get KEY2 CREATED) +set_addkeytime "KEY2" "ACTIVE" "${created}" -2257200 +set_addkeytime "KEY2" "SYNCPUBLISH" "${created}" -2257200 +syncpub=$(key_get KEY2 SYNCPUBLISH) +set_addkeytime "KEY2" "PUBLISHED" "${syncpub}" "-${Ipub}" +set_retired_removed "KEY2" "${Lcsk}" "${IretCSK}" + +# Continue signing policy checks. +check_keytimes +check_apex +check_subdomain +dnssec_verify + +# Next key event is when the DNSKEY enters the HIDDEN state. This is the +# DNSKEY TTL plus zone propagation delay. For the csk-roll policy this is: +# 1h + 1h = 7200 seconds. +check_next_key_event 7200 + +# +# Zone: step7.csk-roll.autosign. +# +set_zone "step7.csk-roll.autosign" +set_policy "csk-roll" "2" "3600" +set_server "ns3" "10.53.0.3" +# The old CSK (KEY1) is now completely HIDDEN. +set_keystate "KEY1" "STATE_DNSKEY" "hidden" + +# Various signing policy checks. +check_keys +check_dnssecstatus "$SERVER" "$POLICY" "$ZONE" + +# Set expected key times: +# - This key was activated 5093 hours ago (18334800 seconds). +csk_rollover_predecessor_keytimes -18334800 +# - The new CSK is activated 629 hours ago (2264400 seconds). +created=$(key_get KEY2 CREATED) +set_addkeytime "KEY2" "ACTIVE" "${created}" -2264400 +set_addkeytime "KEY2" "SYNCPUBLISH" "${created}" -2264400 +syncpub=$(key_get KEY2 SYNCPUBLISH) +set_addkeytime "KEY2" "PUBLISHED" "${syncpub}" "-${Ipub}" +set_retired_removed "KEY2" "${Lcsk}" "${IretCSK}" + +# Continue signing policy checks. +check_keytimes +check_apex +check_subdomain +dnssec_verify + +# Next key event is when the new successor needs to be published. +# This is the Lcsk, minus time passed since the key started signing, +# minus the prepublication time. +# Lcsk: 186d (16070400 seconds) +# Time passed: 629h (2264400 seconds) +# Ipub: 3h (10800 seconds) +check_next_key_event 13795200 + +# +# Zone: step8.csk-roll.autosign. +# +set_zone "step8.csk-roll.autosign" +set_policy "csk-roll" "1" "3600" +set_server "ns3" "10.53.0.3" +# The old CSK (KEY1) is purged. +key_clear "KEY1" + +# Various signing policy checks. +check_keys +check_dnssecstatus "$SERVER" "$POLICY" "$ZONE" +check_apex +check_subdomain +dnssec_verify + +# +# Testing CSK key rollover (2). +# + +# Policy parameters. +# Lcsk: 186 days (16070400 seconds) +# Dreg: N/A +# Iret(KSK): DS TTL (1h) + DprpP (1w) + retire-safety (1h) +# Iret(KSK): 170h (61200 seconds) +# Iret(ZSK): RRSIG TTL (1d) + Dprp (1h) + Dsgn (12h) + retire-safety (1h) +# Iret(ZSK): 38h (136800 seconds) +Lcsk=16070400 +IretKSK=612000 +IretZSK=136800 +IretCSK=$IretKSK + +# +# Zone: step1.csk-roll2.autosign. +# +set_zone "step1.csk-roll2.autosign" +set_policy "csk-roll2" "1" "3600" +set_server "ns3" "10.53.0.3" +# Key properties. +key_clear "KEY1" +set_keyrole "KEY1" "csk" +set_keylifetime "KEY1" "16070400" +set_keyalgorithm "KEY1" "$DEFAULT_ALGORITHM_NUMBER" "$DEFAULT_ALGORITHM" "$DEFAULT_BITS" +set_keysigning "KEY1" "yes" +set_zonesigning "KEY1" "yes" +# The CSK (KEY1) starts in OMNIPRESENT. +set_keystate "KEY1" "GOAL" "omnipresent" +set_keystate "KEY1" "STATE_DNSKEY" "omnipresent" +set_keystate "KEY1" "STATE_KRRSIG" "omnipresent" +set_keystate "KEY1" "STATE_ZRRSIG" "omnipresent" +set_keystate "KEY1" "STATE_DS" "omnipresent" +# Initially only one key. +key_clear "KEY2" +key_clear "KEY3" +key_clear "KEY4" + +# Various signing policy checks. +check_keys +check_dnssecstatus "$SERVER" "$POLICY" "$ZONE" +# This key is immediately published and activated. +csk_rollover_predecessor_keytimes 0 +check_keytimes +check_apex +check_subdomain +dnssec_verify + +# Next key event is when the successor CSK needs to be published. +# This is Lcsk - Ipub. +# Lcsk: 186d (16070400 seconds) +# Ipub: 3h (10800 seconds) +# Total: 186d3h (16059600 seconds) +check_next_key_event 16059600 + +# +# Zone: step2.csk-roll2.autosign. +# +set_zone "step2.csk-roll2.autosign" +set_policy "csk-roll2" "2" "3600" +set_server "ns3" "10.53.0.3" +# New CSK (KEY2) is prepublished (signs DNSKEY RRset, but not yet other RRsets). +key_clear "KEY2" +set_keyrole "KEY2" "csk" +set_keylifetime "KEY2" "16070400" +set_keyalgorithm "KEY2" "$DEFAULT_ALGORITHM_NUMBER" "$DEFAULT_ALGORITHM" "$DEFAULT_BITS" +set_keysigning "KEY2" "yes" +set_zonesigning "KEY2" "no" +# Key states. +set_keystate "KEY1" "GOAL" "hidden" +set_keystate "KEY2" "GOAL" "omnipresent" +set_keystate "KEY2" "STATE_DNSKEY" "rumoured" +set_keystate "KEY2" "STATE_KRRSIG" "rumoured" +set_keystate "KEY2" "STATE_ZRRSIG" "hidden" +set_keystate "KEY2" "STATE_DS" "hidden" + +# Various signing policy checks. +check_keys +check_dnssecstatus "$SERVER" "$POLICY" "$ZONE" + +# Set expected key times: +# - This key was activated 4461 hours ago (16059600 seconds). +csk_rollover_predecessor_keytimes -16059600 +# - The new CSK is published now. +created=$(key_get KEY2 CREATED) +set_keytime "KEY2" "PUBLISHED" "${created}" +# - The new CSK should publish the CDS after the prepublication time. +# - Ipub: 3 hour (10800 seconds) +Ipub="10800" +set_addkeytime "KEY2" "SYNCPUBLISH" "${created}" "${Ipub}" +set_addkeytime "KEY2" "ACTIVE" "${created}" "${Ipub}" +set_retired_removed "KEY2" "${Lcsk}" "${IretCSK}" + +# Continue signing policy checks. +check_apex +check_subdomain +dnssec_verify + +# Next key event is when the successor CSK becomes OMNIPRESENT. That is the +# DNSKEY TTL plus the zone propagation delay, plus the publish-safety. For +# the csk-roll2 policy, this means 3h hours = 10800 seconds. +check_next_key_event 10800 + +# +# Zone: step3.csk-roll2.autosign. +# +set_zone "step3.csk-roll2.autosign" +set_policy "csk-roll2" "2" "3600" +set_server "ns3" "10.53.0.3" +# CSK (KEY1) can be removed, so move to UNRETENTIVE. +set_zonesigning "KEY1" "no" +set_keystate "KEY1" "STATE_ZRRSIG" "unretentive" +# New CSK (KEY2) DNSKEY is OMNIPRESENT, so move ZRRSIG to RUMOURED state. +set_zonesigning "KEY2" "yes" +set_keystate "KEY2" "STATE_DNSKEY" "omnipresent" +set_keystate "KEY2" "STATE_KRRSIG" "omnipresent" +set_keystate "KEY2" "STATE_ZRRSIG" "rumoured" +# The old DS (KEY1) can be withdrawn and the new DS (KEY2) can be introduced. +set_keystate "KEY1" "STATE_DS" "unretentive" +set_keystate "KEY2" "STATE_DS" "rumoured" + +# Various signing policy checks. +check_keys +check_dnssecstatus "$SERVER" "$POLICY" "$ZONE" +# Check that CDS publication is logged. +check_cdslog "$DIR" "$ZONE" KEY2 + +# Set expected key times: +# - This key was activated 186 days ago (16070400 seconds). +csk_rollover_predecessor_keytimes -16070400 +# - The new CSK is published three hours ago, CDS must be published now. +created=$(key_get KEY2 CREATED) +set_addkeytime "KEY2" "PUBLISHED" "${created}" "-${Ipub}" +set_keytime "KEY2" "SYNCPUBLISH" "${created}" +# - Also signatures are being introduced now. +set_keytime "KEY2" "ACTIVE" "${created}" +set_retired_removed "KEY2" "${Lcsk}" "${IretCSK}" + +# Continue signing policy checks. +check_keytimes +check_apex +# Subdomain still has good signatures of old CSK (KEY1). +# Set expected zone signing on for KEY1 and off for KEY2, +# testing whether signatures which are still valid are being reused. +set_zonesigning "KEY1" "yes" +set_zonesigning "KEY2" "no" +check_subdomain +# Restore the expected zone signing properties. +set_zonesigning "KEY1" "no" +set_zonesigning "KEY2" "yes" +dnssec_verify + +# We ignore any parent registration delay, so set the DS publish time to now. +rndc_checkds "$SERVER" "$DIR" KEY1 "now" "withdrawn" "$ZONE" +rndc_checkds "$SERVER" "$DIR" KEY2 "now" "published" "$ZONE" +# Next key event is when the predecessor ZRRSIG records have been replaced +# with that of the successor and enough time has passed such that the all +# validators that have such signed RRsets in cache only know about the +# successor signatures. This is the retire interval: Dsgn plus the +# maximum zone TTL plus the zone propagation delay plus retire-safety. For the +# csk-roll2 policy that means: 12h (because 1d validity and refresh within +# 12 hours) + 1d + 1h + 1h = 38h = 136800 seconds. Prevent intermittent false +# positives on slow platforms by subtracting the number of seconds which +# passed between key creation and invoking 'rndc dnssec -checkds'. +now="$(TZ=UTC date +%s)" +time_passed=$((now-start_time)) +next_time=$((136800-time_passed)) +check_next_key_event $next_time + +# +# Zone: step4.csk-roll2.autosign. +# +set_zone "step4.csk-roll2.autosign" +set_policy "csk-roll2" "2" "3600" +set_server "ns3" "10.53.0.3" +# The old CSK (KEY1) ZRRSIG is now HIDDEN. +set_keystate "KEY1" "STATE_ZRRSIG" "hidden" +# The new CSK (KEY2) ZRRSIG is now OMNIPRESENT. +set_keystate "KEY2" "STATE_ZRRSIG" "omnipresent" + +# Various signing policy checks. +check_keys +check_dnssecstatus "$SERVER" "$POLICY" "$ZONE" + +# Set expected key times: +# - This key was activated 4502 hours ago (16207200 seconds). +csk_rollover_predecessor_keytimes -16207200 +# - The new CSK was published 41 hours (147600 seconds) ago. +created=$(key_get KEY2 CREATED) +set_addkeytime "KEY2" "PUBLISHED" "${created}" -147600 +published=$(key_get KEY2 PUBLISHED) +set_addkeytime "KEY2" "SYNCPUBLISH" "${published}" "${Ipub}" +set_addkeytime "KEY2" "ACTIVE" "${published}" "${Ipub}" +set_retired_removed "KEY2" "${Lcsk}" "${IretCSK}" + +# Continue signing policy checks. +check_keytimes +check_apex +check_subdomain +dnssec_verify + +# 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 +# registration delay plus the retire interval, which is the parent +# propagation delay plus the DS TTL plus the retire-safety. For the +# csk-roll2 policy this means: 1w + 1h + 1h = 170h = 612000 seconds. +# However, 136800 seconds have passed already, so 478800 seconds left. +check_next_key_event 475200 + +# +# Zone: step5.csk-roll2.autosign. +# +set_zone "step5.csk-roll2.autosign" +set_policy "csk-roll2" "2" "3600" +set_server "ns3" "10.53.0.3" +# The old CSK (KEY1) DNSKEY can be removed. +set_keysigning "KEY1" "no" +set_keystate "KEY1" "STATE_DNSKEY" "unretentive" +set_keystate "KEY1" "STATE_KRRSIG" "unretentive" +set_keystate "KEY1" "STATE_DS" "hidden" +# The new CSK (KEY2) is now fully OMNIPRESENT. +set_keystate "KEY2" "STATE_DS" "omnipresent" + +# Various signing policy checks. +check_keys +check_dnssecstatus "$SERVER" "$POLICY" "$ZONE" + +# Set expected key times: +# - This key was activated 4634 hours ago (16682400 seconds). +csk_rollover_predecessor_keytimes -16682400 +# - The new CSK was published 173 hours (622800 seconds) ago. +created=$(key_get KEY2 CREATED) +set_addkeytime "KEY2" "PUBLISHED" "${created}" -622800 +published=$(key_get KEY2 PUBLISHED) +set_addkeytime "KEY2" "SYNCPUBLISH" "${published}" "${Ipub}" +set_addkeytime "KEY2" "ACTIVE" "${published}" "${Ipub}" +set_retired_removed "KEY2" "${Lcsk}" "${IretCSK}" + +# Continue signing policy checks. +check_keytimes +check_apex +check_subdomain +dnssec_verify + +# Next key event is when the DNSKEY enters the HIDDEN state. This is the +# DNSKEY TTL plus zone propagation delay. For the csk-roll policy this is: +# 1h + 1h = 7200 seconds. +check_next_key_event 7200 + +# +# Zone: step6.csk-roll2.autosign. +# +set_zone "step6.csk-roll2.autosign" +set_policy "csk-roll2" "2" "3600" +set_server "ns3" "10.53.0.3" +# The old CSK (KEY1) is now completely HIDDEN. +set_keystate "KEY1" "STATE_DNSKEY" "hidden" +set_keystate "KEY1" "STATE_KRRSIG" "hidden" + +# Various signing policy checks. +check_keys +check_dnssecstatus "$SERVER" "$POLICY" "$ZONE" + +# Set expected key times: +# - This key was activated 4636 hours ago (16689600 seconds). +csk_rollover_predecessor_keytimes -16689600 +# - The new CSK was published 175 hours (630000 seconds) ago. +created=$(key_get KEY2 CREATED) +set_addkeytime "KEY2" "PUBLISHED" "${created}" -630000 +published=$(key_get KEY2 PUBLISHED) +set_addkeytime "KEY2" "SYNCPUBLISH" "${published}" "${Ipub}" +set_addkeytime "KEY2" "ACTIVE" "${published}" "${Ipub}" +set_retired_removed "KEY2" "${Lcsk}" "${IretCSK}" + +# Continue signing policy checks. +check_keytimes +check_apex +check_subdomain +dnssec_verify + +# Next key event is when the new successor needs to be published. +# This is the Lcsk, minus time passed since the key was published. +# Lcsk: 186d (16070400 seconds) +# Time passed: 175h (630000 seconds) +check_next_key_event 15440400 + +# +# Zone: step7.csk-roll2.autosign. +# +set_zone "step7.csk-roll2.autosign" +set_policy "csk-roll2" "2" "3600" +set_server "ns3" "10.53.0.3" +# The old CSK (KEY1) could have been purged, but purge-keys is disabled. + +# Various signing policy checks. +check_keys +check_dnssecstatus "$SERVER" "$POLICY" "$ZONE" +check_apex +check_subdomain +dnssec_verify + +# +# Test #2375: Scheduled rollovers are happening faster than they can finish +# +set_zone "three-is-a-crowd.kasp" +set_policy "ksk-doubleksk" "3" "7200" +set_server "ns3" "10.53.0.3" +CDNSKEY="no" +# These are the same time values as calculated for ksk-doubleksk. +Lksk=5184000 +Lzsk=31536000 +IretKSK=180000 +IretZSK=867600 +# KSK (KEY1) is outgoing. +key_clear "KEY1" +set_keyrole "KEY1" "ksk" +set_keylifetime "KEY1" "${Lksk}" +set_keyalgorithm "KEY1" "$DEFAULT_ALGORITHM_NUMBER" "$DEFAULT_ALGORITHM" "$DEFAULT_BITS" +set_keysigning "KEY1" "yes" +set_zonesigning "KEY1" "yes" +set_keystate "KEY1" "GOAL" "hidden" +set_keystate "KEY1" "STATE_DNSKEY" "omnipresent" +set_keystate "KEY1" "STATE_KRRSIG" "omnipresent" +set_keystate "KEY1" "STATE_DS" "unretentive" +# KSK (KEY2) is incoming. +key_clear "KEY2" +set_keyrole "KEY2" "ksk" +set_keylifetime "KEY2" "${Lksk}" +set_keyalgorithm "KEY2" "$DEFAULT_ALGORITHM_NUMBER" "$DEFAULT_ALGORITHM" "$DEFAULT_BITS" +set_keysigning "KEY2" "yes" +set_zonesigning "KEY2" "no" +set_keystate "KEY2" "GOAL" "omnipresent" +set_keystate "KEY2" "STATE_DNSKEY" "omnipresent" +set_keystate "KEY2" "STATE_KRRSIG" "omnipresent" +set_keystate "KEY2" "STATE_DS" "rumoured" +# We will introduce the third KSK shortly. +key_clear "KEY3" +# ZSK (KEY4). +key_clear "KEY4" +set_keyrole "KEY4" "zsk" +set_keylifetime "KEY4" "${Lzsk}" +set_keyalgorithm "KEY4" "$DEFAULT_ALGORITHM_NUMBER" "$DEFAULT_ALGORITHM" "$DEFAULT_BITS" +set_keysigning "KEY4" "no" +set_zonesigning "KEY4" "yes" +set_keystate "KEY4" "GOAL" "omnipresent" +set_keystate "KEY4" "STATE_DNSKEY" "omnipresent" +set_keystate "KEY4" "STATE_ZRRSIG" "omnipresent" +# Run preliminary tests. +check_keys +check_dnssecstatus "$SERVER" "$POLICY" "$ZONE" +check_apex +check_subdomain +dnssec_verify +# Roll over KEY2. +# Set expected key lifetime, which is DNSKEY TTL plus the zone propagation delay, +# plus the publish-safety: 7200s + 1h + 1d = 97200 seconds. +set_keylifetime "KEY2" "97200" +created=$(key_get KEY2 CREATED) +rndc_rollover "$SERVER" "$DIR" $(key_get KEY2 ID) "${created}" "$ZONE" +# Update expected number of keys and key states. +set_keystate "KEY2" "GOAL" "hidden" +set_policy "ksk-doubleksk" "4" "7200" +CDNSKEY="no" +# New KSK (KEY3) is introduced. +set_keyrole "KEY3" "ksk" +set_keylifetime "KEY3" "${Lksk}" +set_keyalgorithm "KEY3" "$DEFAULT_ALGORITHM_NUMBER" "$DEFAULT_ALGORITHM" "$DEFAULT_BITS" +set_keysigning "KEY3" "yes" +set_zonesigning "KEY3" "no" +set_keystate "KEY3" "GOAL" "omnipresent" +set_keystate "KEY3" "STATE_DNSKEY" "rumoured" +set_keystate "KEY3" "STATE_KRRSIG" "rumoured" +set_keystate "KEY3" "STATE_DS" "hidden" +# Run tests again. We now expect four keys (3x KSK, 1x ZSK). +check_keys +check_dnssecstatus "$SERVER" "$POLICY" "$ZONE" +check_apex +check_subdomain +dnssec_verify + +# Test dynamic zones that switch to inline-signing. +set_zone "dynamic2inline.kasp" +set_policy "default" "1" "3600" +set_server "ns6" "10.53.0.6" +# Key properties. +key_clear "KEY1" +set_keyrole "KEY1" "csk" +set_keylifetime "KEY1" "0" +set_keyalgorithm "KEY1" "13" "ECDSAP256SHA256" "256" +set_keysigning "KEY1" "yes" +set_zonesigning "KEY1" "yes" +key_clear "KEY2" +key_clear "KEY3" +key_clear "KEY4" + +# The CSK is rumoured. +set_keystate "KEY1" "GOAL" "omnipresent" +set_keystate "KEY1" "STATE_DNSKEY" "rumoured" +set_keystate "KEY1" "STATE_KRRSIG" "rumoured" +set_keystate "KEY1" "STATE_ZRRSIG" "rumoured" +set_keystate "KEY1" "STATE_DS" "hidden" +# Various signing policy checks. +check_keys +check_dnssecstatus "$SERVER" "$POLICY" "$ZONE" +check_apex +check_subdomain +dnssec_verify + +# +# Testing algorithm rollover. +# +Lksk=0 +Lzsk=0 +IretKSK=0 +IretZSK=0 + +# +# Zone: step1.algorithm-roll.kasp +# +set_zone "step1.algorithm-roll.kasp" +set_policy "rsasha256" "2" "3600" +set_server "ns6" "10.53.0.6" +# Key properties. +key_clear "KEY1" +set_keyrole "KEY1" "ksk" +set_keylifetime "KEY1" "0" +set_keyalgorithm "KEY1" "8" "RSASHA256" "2048" +set_keysigning "KEY1" "yes" +set_zonesigning "KEY1" "no" + +key_clear "KEY2" +set_keyrole "KEY2" "zsk" +set_keylifetime "KEY2" "0" +set_keyalgorithm "KEY2" "8" "RSASHA256" "2048" +set_keysigning "KEY2" "no" +set_zonesigning "KEY2" "yes" +key_clear "KEY3" +key_clear "KEY4" + +# The KSK (KEY1) and ZSK (KEY2) start in OMNIPRESENT. +set_keystate "KEY1" "GOAL" "omnipresent" +set_keystate "KEY1" "STATE_DNSKEY" "omnipresent" +set_keystate "KEY1" "STATE_KRRSIG" "omnipresent" +set_keystate "KEY1" "STATE_DS" "omnipresent" + +set_keystate "KEY2" "GOAL" "omnipresent" +set_keystate "KEY2" "STATE_DNSKEY" "omnipresent" +set_keystate "KEY2" "STATE_ZRRSIG" "omnipresent" + +# Various signing policy checks. +check_keys +check_dnssecstatus "$SERVER" "$POLICY" "$ZONE" +# These keys are immediately published and activated. +rollover_predecessor_keytimes 0 +check_keytimes +check_apex +check_subdomain +dnssec_verify + +# Next key event is when the successor keys need to be published. +# Since the lifetime of the keys are unlimited, so default to loadkeys +# interval. +check_next_key_event 3600 + +# +# Zone: step1.csk-algorithm-roll.kasp +# +set_zone "step1.csk-algorithm-roll.kasp" +set_policy "csk-algoroll" "1" "3600" +set_server "ns6" "10.53.0.6" +# Key properties. +key_clear "KEY1" +set_keyrole "KEY1" "csk" +set_keylifetime "KEY1" "0" +set_keyalgorithm "KEY1" "8" "RSASHA256" "2048" +set_keysigning "KEY1" "yes" +set_zonesigning "KEY1" "yes" +key_clear "KEY2" +key_clear "KEY3" +key_clear "KEY4" +# The CSK (KEY1) starts in OMNIPRESENT. +set_keystate "KEY1" "GOAL" "omnipresent" +set_keystate "KEY1" "STATE_DNSKEY" "omnipresent" +set_keystate "KEY1" "STATE_KRRSIG" "omnipresent" +set_keystate "KEY1" "STATE_ZRRSIG" "omnipresent" +set_keystate "KEY1" "STATE_DS" "omnipresent" + +# Various signing policy checks. +check_keys +check_dnssecstatus "$SERVER" "$POLICY" "$ZONE" +# This key is immediately published and activated. +Lcsk=0 +IretCSK=0 +csk_rollover_predecessor_keytimes 0 +check_keytimes +check_apex +check_subdomain +dnssec_verify + +# Next key event is when the successor keys need to be published. +# Since the lifetime of the keys are unlimited, so default to loadkeys +# interval. +check_next_key_event 3600 + +# +# Testing going insecure. +# + +# +# Zone step1.going-insecure.kasp +# +set_zone "step1.going-insecure.kasp" +set_policy "unsigning" "2" "7200" +set_server "ns6" "10.53.0.6" + +# Policy parameters. +# Lksk: 0 +# Lzsk: 60 days (5184000 seconds) +# Iret(KSK): DS TTL (1d) + DprpP (1h) + retire-safety (1h) +# Iret(KSK): 1d2h (93600 seconds) +# Iret(ZSK): RRSIG TTL (1d) + Dprp (5m) + Dsgn (9d) + retire-safety (1h) +# Iret(ZSK): 10d1h5m (867900 seconds) +Lksk=0 +Lzsk=5184000 +IretKSK=93600 +IretZSK=867900 + +init_migration_insecure() { + key_clear "KEY1" + set_keyrole "KEY1" "ksk" + set_keylifetime "KEY1" "${Lksk}" + set_keyalgorithm "KEY1" "$DEFAULT_ALGORITHM_NUMBER" "$DEFAULT_ALGORITHM" "$DEFAULT_BITS" + set_keysigning "KEY1" "yes" + set_zonesigning "KEY1" "no" + + set_keystate "KEY1" "GOAL" "omnipresent" + set_keystate "KEY1" "STATE_DNSKEY" "omnipresent" + set_keystate "KEY1" "STATE_KRRSIG" "omnipresent" + set_keystate "KEY1" "STATE_DS" "omnipresent" + + key_clear "KEY2" + set_keyrole "KEY2" "zsk" + set_keylifetime "KEY2" "${Lzsk}" + set_keyalgorithm "KEY2" "$DEFAULT_ALGORITHM_NUMBER" "$DEFAULT_ALGORITHM" "$DEFAULT_BITS" + set_keysigning "KEY2" "no" + set_zonesigning "KEY2" "yes" + + set_keystate "KEY2" "GOAL" "omnipresent" + set_keystate "KEY2" "STATE_DNSKEY" "omnipresent" + set_keystate "KEY2" "STATE_ZRRSIG" "omnipresent" + + key_clear "KEY3" + key_clear "KEY4" +} +init_migration_insecure + +# Various signing policy checks. +check_keys +check_dnssecstatus "$SERVER" "$POLICY" "$ZONE" + +# We have set the timing metadata to now - 10 days (864000 seconds). +rollover_predecessor_keytimes -864000 +check_keytimes +check_apex +check_subdomain +dnssec_verify + +# +# Zone step1.going-insecure-dynamic.kasp +# + +set_zone "step1.going-insecure-dynamic.kasp" +set_dynamic +set_policy "unsigning" "2" "7200" +set_server "ns6" "10.53.0.6" +init_migration_insecure + +# Various signing policy checks. +check_keys +check_dnssecstatus "$SERVER" "$POLICY" "$ZONE" + +# We have set the timing metadata to now - 10 days (864000 seconds). +rollover_predecessor_keytimes -864000 +check_keytimes +check_apex +check_subdomain +dnssec_verify + +# +# Zone step1.going-straight-to-none.kasp +# +set_zone "step1.going-straight-to-none.kasp" +set_policy "default" "1" "3600" +set_server "ns6" "10.53.0.6" +# Key properties. +set_keyrole "KEY1" "csk" +set_keylifetime "KEY1" "0" +set_keyalgorithm "KEY1" "13" "ECDSAP256SHA256" "256" +set_keysigning "KEY1" "yes" +set_zonesigning "KEY1" "yes" +# DNSKEY, RRSIG (ksk), RRSIG (zsk) are published. DS needs to wait. +set_keystate "KEY1" "GOAL" "omnipresent" +set_keystate "KEY1" "STATE_DNSKEY" "omnipresent" +set_keystate "KEY1" "STATE_KRRSIG" "omnipresent" +set_keystate "KEY1" "STATE_ZRRSIG" "omnipresent" +set_keystate "KEY1" "STATE_DS" "omnipresent" +# This policy only has one key. +key_clear "KEY2" +key_clear "KEY3" +key_clear "KEY4" + +check_keys +check_dnssecstatus "$SERVER" "$POLICY" "$ZONE" + +# The first key is immediately published and activated. +created=$(key_get KEY1 CREATED) +set_keytime "KEY1" "PUBLISHED" "${created}" +set_keytime "KEY1" "ACTIVE" "${created}" +set_keytime "KEY1" "SYNCPUBLISH" "${created}" +# Key lifetime is unlimited, so not setting RETIRED and REMOVED. +check_keytimes + +check_apex +check_subdomain +dnssec_verify + +# Reconfig dnssec-policy (triggering algorithm roll and other dnssec-policy +# changes). +echo_i "reconfig dnssec-policy to trigger algorithm rollover" +copy_setports ns6/named2.conf.in ns6/named.conf +rndc_reconfig ns6 10.53.0.6 + +# Calculate time passed to correctly check for next key events. +now="$(TZ=UTC date +%s)" +time_passed=$((now-start_time)) +echo_i "${time_passed} seconds passed between start of tests and reconfig" + +# Wait until we have seen "zone_rekey done:" message for this key. +_wait_for_done_signing() { + _zone=$1 + + _ksk=$(key_get $2 KSK) + _zsk=$(key_get $2 ZSK) + if [ "$_ksk" = "yes" ]; then + _role="KSK" + _expect_type=EXPECT_KRRSIG + elif [ "$_zsk" = "yes" ]; then + _role="ZSK" + _expect_type=EXPECT_ZRRSIG + fi + + if [ "$(key_get ${2} $_expect_type)" = "yes" ] && [ "$(key_get $2 $_role)" = "yes" ]; then + _keyid=$(key_get $2 ID) + _keyalg=$(key_get $2 ALG_STR) + echo_i "wait for zone ${_zone} is done signing with $2 ${_zone}/${_keyalg}/${_keyid}" + grep "zone_rekey done: key ${_keyid}/${_keyalg}" "${DIR}/named.run" > /dev/null || return 1 + fi + + return 0 +} + +wait_for_done_signing() { + n=$((n+1)) + echo_i "wait for zone ${ZONE} is done signing ($n)" + ret=0 + + retry_quiet 30 _wait_for_done_signing ${ZONE} KEY1 || ret=1 + retry_quiet 30 _wait_for_done_signing ${ZONE} KEY2 || ret=1 + retry_quiet 30 _wait_for_done_signing ${ZONE} KEY3 || ret=1 + retry_quiet 30 _wait_for_done_signing ${ZONE} KEY4 || ret=1 + + test "$ret" -eq 0 || echo_i "failed" + status=$((status+ret)) +} + +# Test dynamic zones that switch to inline-signing. +set_zone "dynamic2inline.kasp" +set_policy "default" "1" "3600" +set_server "ns6" "10.53.0.6" +# Key properties. +key_clear "KEY1" +set_keyrole "KEY1" "csk" +set_keylifetime "KEY1" "0" +set_keyalgorithm "KEY1" "13" "ECDSAP256SHA256" "256" +set_keysigning "KEY1" "yes" +set_zonesigning "KEY1" "yes" +key_clear "KEY2" +key_clear "KEY3" +key_clear "KEY4" + +# The CSK is rumoured. +set_keystate "KEY1" "GOAL" "omnipresent" +set_keystate "KEY1" "STATE_DNSKEY" "rumoured" +set_keystate "KEY1" "STATE_KRRSIG" "rumoured" +set_keystate "KEY1" "STATE_ZRRSIG" "rumoured" +set_keystate "KEY1" "STATE_DS" "hidden" +# Various signing policy checks. +check_keys +check_dnssecstatus "$SERVER" "$POLICY" "$ZONE" +check_apex +check_subdomain +dnssec_verify + +# +# Testing going insecure. +# + +# +# Zone: step1.going-insecure.kasp +# +set_zone "step1.going-insecure.kasp" +set_policy "insecure" "2" "7200" +set_server "ns6" "10.53.0.6" +# Expect a CDS/CDNSKEY Delete Record. +set_cdsdelete + +# Key goal states should be HIDDEN. +init_migration_insecure +set_keystate "KEY1" "GOAL" "hidden" +set_keystate "KEY2" "GOAL" "hidden" +# The DS may be removed if we are going insecure. +set_keystate "KEY1" "STATE_DS" "unretentive" + +# Various signing policy checks. +check_keys +wait_for_done_signing +check_dnssecstatus "$SERVER" "$POLICY" "$ZONE" +check_apex +check_subdomain +dnssec_verify + +# Tell named that the DS has been removed. +rndc_checkds "$SERVER" "$DIR" "KEY1" "now" "withdrawn" "$ZONE" +wait_for_done_signing +check_dnssecstatus "$SERVER" "$POLICY" "$ZONE" +check_apex +check_subdomain +dnssec_verify + +# Next key event is when the DS becomes HIDDEN. This happens after the +# parent propagation delay, retire safety delay, and DS TTL: +# 1h + 1h + 1d = 26h = 93600 seconds. +check_next_key_event 93600 + +# +# Zone: step2.going-insecure.kasp +# +set_zone "step2.going-insecure.kasp" +set_policy "insecure" "2" "7200" +set_server "ns6" "10.53.0.6" + +# The DS is long enough removed from the zone to be considered HIDDEN. +# This means the DNSKEY and the KSK signatures can be removed. +set_keystate "KEY1" "STATE_DS" "hidden" +set_keystate "KEY1" "STATE_DNSKEY" "unretentive" +set_keystate "KEY1" "STATE_KRRSIG" "unretentive" +set_keysigning "KEY1" "no" + +set_keystate "KEY2" "STATE_DNSKEY" "unretentive" +set_keystate "KEY2" "STATE_ZRRSIG" "unretentive" +set_zonesigning "KEY2" "no" + +# Various signing policy checks. +check_keys +check_dnssecstatus "$SERVER" "$POLICY" "$ZONE" +check_apex +check_subdomain + +# Next key event is when the DNSKEY becomes HIDDEN. This happens after the +# propagation delay, plus DNSKEY TTL: +# 5m + 2h = 125m = 7500 seconds. +check_next_key_event 7500 + +# +# Zone: step1.going-insecure-dynamic.kasp +# +set_zone "step1.going-insecure-dynamic.kasp" +set_dynamic +set_policy "insecure" "2" "7200" +set_server "ns6" "10.53.0.6" +# Expect a CDS/CDNSKEY Delete Record. +set_cdsdelete + +# Key goal states should be HIDDEN. +init_migration_insecure +set_keystate "KEY1" "GOAL" "hidden" +set_keystate "KEY2" "GOAL" "hidden" +# The DS may be removed if we are going insecure. +set_keystate "KEY1" "STATE_DS" "unretentive" + +# Various signing policy checks. +check_keys +wait_for_done_signing +check_dnssecstatus "$SERVER" "$POLICY" "$ZONE" +check_apex +check_subdomain +dnssec_verify + +# Tell named that the DS has been removed. +rndc_checkds "$SERVER" "$DIR" "KEY1" "now" "withdrawn" "$ZONE" +wait_for_done_signing +check_dnssecstatus "$SERVER" "$POLICY" "$ZONE" +check_apex +check_subdomain +dnssec_verify + +# Next key event is when the DS becomes HIDDEN. This happens after the +# parent propagation delay, retire safety delay, and DS TTL: +# 1h + 1h + 1d = 26h = 93600 seconds. +check_next_key_event 93600 + +# +# Zone: step2.going-insecure-dynamic.kasp +# +set_zone "step2.going-insecure-dynamic.kasp" +set_dynamic +set_policy "insecure" "2" "7200" +set_server "ns6" "10.53.0.6" + +# The DS is long enough removed from the zone to be considered HIDDEN. +# This means the DNSKEY and the KSK signatures can be removed. +set_keystate "KEY1" "STATE_DS" "hidden" +set_keystate "KEY1" "STATE_DNSKEY" "unretentive" +set_keystate "KEY1" "STATE_KRRSIG" "unretentive" +set_keysigning "KEY1" "no" + +set_keystate "KEY2" "STATE_DNSKEY" "unretentive" +set_keystate "KEY2" "STATE_ZRRSIG" "unretentive" +set_zonesigning "KEY2" "no" + +# Various signing policy checks. +check_keys +check_dnssecstatus "$SERVER" "$POLICY" "$ZONE" +check_apex +check_subdomain + +# Next key event is when the DNSKEY becomes HIDDEN. This happens after the +# propagation delay, plus DNSKEY TTL: +# 5m + 2h = 125m = 7500 seconds. +check_next_key_event 7500 + +# +# Zone: step1.going-straight-to-none.kasp +# +set_zone "step1.going-straight-to-none.kasp" +set_policy "none" "1" "3600" +set_server "ns6" "10.53.0.6" + +# The zone will go bogus after signatures expire, but remains validly signed for now. + +# Key properties. +set_keyrole "KEY1" "csk" +set_keylifetime "KEY1" "0" +set_keyalgorithm "KEY1" "13" "ECDSAP256SHA256" "256" +set_keysigning "KEY1" "yes" +set_zonesigning "KEY1" "yes" +# DNSKEY, RRSIG (ksk), RRSIG (zsk) are published. DS needs to wait. +set_keystate "KEY1" "GOAL" "omnipresent" +set_keystate "KEY1" "STATE_DNSKEY" "omnipresent" +set_keystate "KEY1" "STATE_KRRSIG" "omnipresent" +set_keystate "KEY1" "STATE_ZRRSIG" "omnipresent" +set_keystate "KEY1" "STATE_DS" "omnipresent" +# This policy only has one key. +key_clear "KEY2" +key_clear "KEY3" +key_clear "KEY4" + +# Various signing policy checks. +check_keys +check_dnssecstatus "$SERVER" "$POLICY" "$ZONE" +dnssec_verify + +# +# Testing KSK/ZSK algorithm rollover. +# + +# Policy parameters. +# Lksk: unlimited +# Lzsk: unlimited +Lksk=0 +Lzsk=0 + +# +# Zone: step1.algorithm-roll.kasp +# +set_zone "step1.algorithm-roll.kasp" +set_policy "ecdsa256" "4" "3600" +set_server "ns6" "10.53.0.6" +# Old RSASHA1 keys. +key_clear "KEY1" +set_keyrole "KEY1" "ksk" +set_keylifetime "KEY1" "0" +set_keyalgorithm "KEY1" "8" "RSASHA256" "2048" +set_keysigning "KEY1" "yes" +set_zonesigning "KEY1" "no" + +key_clear "KEY2" +set_keyrole "KEY2" "zsk" +set_keylifetime "KEY2" "0" +set_keyalgorithm "KEY2" "8" "RSASHA256" "2048" +set_keysigning "KEY2" "no" +set_zonesigning "KEY2" "yes" +# New ECDSAP256SHA256 keys. +key_clear "KEY3" +set_keyrole "KEY3" "ksk" +set_keylifetime "KEY3" "0" +set_keyalgorithm "KEY3" "13" "ECDSAP256SHA256" "256" +set_keysigning "KEY3" "yes" +set_zonesigning "KEY3" "no" + +key_clear "KEY4" +set_keyrole "KEY4" "zsk" +set_keylifetime "KEY4" "0" +set_keyalgorithm "KEY4" "13" "ECDSAP256SHA256" "256" +set_keysigning "KEY4" "no" +set_zonesigning "KEY4" "yes" +# The RSAHSHA1 keys are outroducing. +set_keystate "KEY1" "GOAL" "hidden" +set_keystate "KEY1" "STATE_DNSKEY" "omnipresent" +set_keystate "KEY1" "STATE_KRRSIG" "omnipresent" +set_keystate "KEY1" "STATE_DS" "omnipresent" +set_keystate "KEY2" "GOAL" "hidden" +set_keystate "KEY2" "STATE_DNSKEY" "omnipresent" +set_keystate "KEY2" "STATE_ZRRSIG" "omnipresent" +# The ECDSAP256SHA256 keys are introducing. +set_keystate "KEY3" "GOAL" "omnipresent" +set_keystate "KEY3" "STATE_DNSKEY" "rumoured" +set_keystate "KEY3" "STATE_KRRSIG" "rumoured" +set_keystate "KEY3" "STATE_DS" "hidden" +set_keystate "KEY4" "GOAL" "omnipresent" +set_keystate "KEY4" "STATE_DNSKEY" "rumoured" +set_keystate "KEY4" "STATE_ZRRSIG" "rumoured" + +# Various signing policy checks. +check_keys +wait_for_done_signing +check_dnssecstatus "$SERVER" "$POLICY" "$ZONE" + +# Set expected key times: +# - The old keys are published and activated. +rollover_predecessor_keytimes 0 +# - KSK must be retired since it no longer matches the policy. +keyfile=$(key_get KEY1 BASEFILE) +grep "; Inactive:" "${keyfile}.key" > retired.test${n}.ksk +retired=$(awk '{print $3}' < retired.test${n}.ksk) +set_keytime "KEY1" "RETIRED" "${retired}" +# - The key is removed after the retire interval: +# IretKSK = TTLds + DprpP + retire-safety +# TTLds: 2h (7200 seconds) +# DprpP: 1h (3600 seconds) +# retire-safety: 2h (7200 seconds) +# IretKSK: 5h (18000 seconds) +IretKSK=18000 +set_addkeytime "KEY1" "REMOVED" "${retired}" "${IretKSK}" +# - ZSK must be retired since it no longer matches the policy. +keyfile=$(key_get KEY2 BASEFILE) +grep "; Inactive:" "${keyfile}.key" > retired.test${n}.zsk +retired=$(awk '{print $3}' < retired.test${n}.zsk) +set_keytime "KEY2" "RETIRED" "${retired}" +# - The key is removed after the retire interval: +# IretZSK = TTLsig + Dprp + Dsgn + retire-safety +# TTLsig: 6h (21600 seconds) +# Dprp: 1h (3600 seconds) +# Dsgn: 25d (2160000 seconds) +# retire-safety: 2h (7200 seconds) +# IretZSK: 25d9h (2192400 seconds) +IretZSK=2192400 +set_addkeytime "KEY2" "REMOVED" "${retired}" "${IretZSK}" +# - The new KSK is published and activated. +created=$(key_get KEY3 CREATED) +set_keytime "KEY3" "PUBLISHED" "${created}" +set_keytime "KEY3" "ACTIVE" "${created}" +# - It takes TTLsig + Dprp + publish-safety hours to propagate the zone. +# TTLsig: 6h (39600 seconds) +# Dprp: 1h (3600 seconds) +# publish-safety: 1h (3600 seconds) +# Ipub: 8h (28800 seconds) +Ipub=28800 +set_addkeytime "KEY3" "SYNCPUBLISH" "${created}" "${Ipub}" +# - The new ZSK is published and activated. +created=$(key_get KEY4 CREATED) +set_keytime "KEY4" "PUBLISHED" "${created}" +set_keytime "KEY4" "ACTIVE" "${created}" + +# Continue signing policy checks. +check_keytimes +check_apex +check_subdomain +dnssec_verify + +# Next key event is when the ecdsa256 keys have been propagated. +# This is the DNSKEY TTL plus publish safety plus zone propagation delay: +# 3 times an hour: 10800 seconds. +check_next_key_event 10800 + +# +# Zone: step2.algorithm-roll.kasp +# +set_zone "step2.algorithm-roll.kasp" +set_policy "ecdsa256" "4" "3600" +set_server "ns6" "10.53.0.6" +# The RSAHSHA1 keys are outroducing, but need to stay present until the new +# algorithm chain of trust has been established. Thus the properties, timings +# and states of the KEY1 and KEY2 are the same as above. + +# The ECDSAP256SHA256 keys are introducing. The DNSKEY RRset is omnipresent, +# but the zone signatures are not. +set_keystate "KEY3" "STATE_DNSKEY" "omnipresent" +set_keystate "KEY3" "STATE_KRRSIG" "omnipresent" +set_keystate "KEY4" "STATE_DNSKEY" "omnipresent" + +# Various signing policy checks. +check_keys +wait_for_done_signing +check_dnssecstatus "$SERVER" "$POLICY" "$ZONE" + +# Set expected key times: +# - The old keys were activated three hours ago (10800 seconds). +rollover_predecessor_keytimes -10800 +# - KSK must be retired since it no longer matches the policy. +created=$(key_get KEY1 CREATED) +set_keytime "KEY1" "RETIRED" "${created}" +set_addkeytime "KEY1" "REMOVED" "${created}" "${IretKSK}" +# - ZSK must be retired since it no longer matches the policy. +created=$(key_get KEY2 CREATED) +set_keytime "KEY2" "RETIRED" "${created}" +set_addkeytime "KEY2" "REMOVED" "${created}" "${IretZSK}" +# - The new keys are published 3 hours ago. +created=$(key_get KEY3 CREATED) +set_addkeytime "KEY3" "PUBLISHED" "${created}" -10800 +set_addkeytime "KEY3" "ACTIVE" "${created}" -10800 +published=$(key_get KEY3 PUBLISHED) +set_addkeytime "KEY3" "SYNCPUBLISH" "${published}" "${Ipub}" + +created=$(key_get KEY4 CREATED) +set_addkeytime "KEY4" "PUBLISHED" "${created}" -10800 +set_addkeytime "KEY4" "ACTIVE" "${created}" -10800 + +# Continue signing policy checks. +check_keytimes +check_apex +check_subdomain +dnssec_verify + +# Next key event is when all zone signatures are signed with the new +# algorithm. This is the max-zone-ttl plus zone propagation delay +# plus retire safety: 6h + 1h + 2h. But three hours have already passed +# (the time it took to make the DNSKEY omnipresent), so the next event +# should be scheduled in 6 hour: 21600 seconds. Prevent intermittent +# false positives on slow platforms by subtracting the number of seconds +# which passed between key creation and invoking 'rndc reconfig'. +next_time=$((21600-time_passed)) +check_next_key_event $next_time + +# +# Zone: step3.algorithm-roll.kasp +# +set_zone "step3.algorithm-roll.kasp" +set_policy "ecdsa256" "4" "3600" +set_server "ns6" "10.53.0.6" +# The ECDSAP256SHA256 keys are introducing. +set_keystate "KEY4" "STATE_ZRRSIG" "omnipresent" +# The DS can be swapped. +set_keystate "KEY1" "STATE_DS" "unretentive" +set_keystate "KEY3" "STATE_DS" "rumoured" + +# Various signing policy checks. +check_keys +wait_for_done_signing +check_dnssecstatus "$SERVER" "$POLICY" "$ZONE" +# Check that CDS publication is logged. +check_cdslog "$DIR" "$ZONE" KEY3 + +# Set expected key times: +# - The old keys were activated 9 hours ago (32400 seconds). +rollover_predecessor_keytimes -32400 +# - And retired 6 hours ago (21600 seconds). +created=$(key_get KEY1 CREATED) +set_addkeytime "KEY1" "RETIRED" "${created}" -21600 +retired=$(key_get KEY1 RETIRED) +set_addkeytime "KEY1" "REMOVED" "${retired}" "${IretKSK}" + +created=$(key_get KEY2 CREATED) +set_addkeytime "KEY2" "RETIRED" "${created}" -21600 +retired=$(key_get KEY2 RETIRED) +set_addkeytime "KEY2" "REMOVED" "${retired}" "${IretZSK}" +# - The new keys are published 9 hours ago. +created=$(key_get KEY3 CREATED) +set_addkeytime "KEY3" "PUBLISHED" "${created}" -32400 +set_addkeytime "KEY3" "ACTIVE" "${created}" -32400 +published=$(key_get KEY3 PUBLISHED) +set_addkeytime "KEY3" "SYNCPUBLISH" "${published}" ${Ipub} + +created=$(key_get KEY4 CREATED) +set_addkeytime "KEY4" "PUBLISHED" "${created}" -32400 +set_addkeytime "KEY4" "ACTIVE" "${created}" -32400 + +# Continue signing policy checks. +check_keytimes +check_apex +check_subdomain +dnssec_verify + +# Tell named we "saw" the parent swap the DS and see if the next key event is +# scheduled at the correct time. +rndc_checkds "$SERVER" "$DIR" KEY1 "now" "withdrawn" "$ZONE" +rndc_checkds "$SERVER" "$DIR" KEY3 "now" "published" "$ZONE" +# Next key event is when the DS becomes OMNIPRESENT. This happens after the +# parent propagation delay, retire safety delay, and DS TTL: +# 1h + 2h + 2h = 5h = 18000 seconds. +check_next_key_event 18000 + +# +# Zone: step4.algorithm-roll.kasp +# +set_zone "step4.algorithm-roll.kasp" +set_policy "ecdsa256" "4" "3600" +set_server "ns6" "10.53.0.6" +# The old DS is HIDDEN, we can remove the old algorithm DNSKEY/RRSIG records. +set_keysigning "KEY1" "no" +set_keystate "KEY1" "STATE_DNSKEY" "unretentive" +set_keystate "KEY1" "STATE_KRRSIG" "unretentive" +set_keystate "KEY1" "STATE_DS" "hidden" + +set_zonesigning "KEY2" "no" +set_keystate "KEY2" "GOAL" "hidden" +set_keystate "KEY2" "STATE_DNSKEY" "unretentive" +set_keystate "KEY2" "STATE_ZRRSIG" "unretentive" +# The ECDSAP256SHA256 DS is now OMNIPRESENT. +set_keystate "KEY3" "STATE_DS" "omnipresent" + +# Various signing policy checks. +check_keys +wait_for_done_signing +check_dnssecstatus "$SERVER" "$POLICY" "$ZONE" + +# Set expected key times: +# - The old keys were activated 38 hours ago (136800 seconds). +rollover_predecessor_keytimes -136800 +# - And retired 35 hours ago (126000 seconds). +created=$(key_get KEY1 CREATED) +set_addkeytime "KEY1" "RETIRED" "${created}" -126000 +retired=$(key_get KEY1 RETIRED) +set_addkeytime "KEY1" "REMOVED" "${retired}" "${IretKSK}" + +created=$(key_get KEY2 CREATED) +set_addkeytime "KEY2" "RETIRED" "${created}" -126000 +retired=$(key_get KEY2 RETIRED) +set_addkeytime "KEY2" "REMOVED" "${retired}" "${IretZSK}" + +# - The new keys are published 38 hours ago. +created=$(key_get KEY3 CREATED) +set_addkeytime "KEY3" "PUBLISHED" "${created}" -136800 +set_addkeytime "KEY3" "ACTIVE" "${created}" -136800 +published=$(key_get KEY3 PUBLISHED) +set_addkeytime "KEY3" "SYNCPUBLISH" "${published}" ${Ipub} + +created=$(key_get KEY4 CREATED) +set_addkeytime "KEY4" "PUBLISHED" "${created}" -136800 +set_addkeytime "KEY4" "ACTIVE" "${created}" -136800 + +# Continue signing policy checks. +check_keytimes +check_apex +check_subdomain +dnssec_verify + +# Next key event is when the old DNSKEY becomes HIDDEN. This happens after the +# DNSKEY TTL plus zone propagation delay (2h). +check_next_key_event 7200 + +# +# Zone: step5.algorithm-roll.kasp +# +set_zone "step5.algorithm-roll.kasp" +set_policy "ecdsa256" "4" "3600" +set_server "ns6" "10.53.0.6" +# The DNSKEY becomes HIDDEN. +set_keystate "KEY1" "STATE_DNSKEY" "hidden" +set_keystate "KEY1" "STATE_KRRSIG" "hidden" +set_keystate "KEY2" "STATE_DNSKEY" "hidden" + +# Various signing policy checks. +check_keys +wait_for_done_signing +check_dnssecstatus "$SERVER" "$POLICY" "$ZONE" + +# Set expected key times: +# - The old keys were activated 40 hours ago (144000 seconds) +rollover_predecessor_keytimes -144000 +# - And retired 37 hours ago (133200 seconds). +created=$(key_get KEY1 CREATED) +set_addkeytime "KEY1" "RETIRED" "${created}" -133200 +retired=$(key_get KEY1 RETIRED) +set_addkeytime "KEY1" "REMOVED" "${retired}" "${IretKSK}" + +created=$(key_get KEY2 CREATED) +set_addkeytime "KEY2" "RETIRED" "${created}" -133200 +retired=$(key_get KEY2 RETIRED) +set_addkeytime "KEY2" "REMOVED" "${retired}" "${IretZSK}" + +# The new keys are published 40 hours ago. +created=$(key_get KEY3 CREATED) +set_addkeytime "KEY3" "PUBLISHED" "${created}" -144000 +set_addkeytime "KEY3" "ACTIVE" "${created}" -144000 +published=$(key_get KEY3 PUBLISHED) +set_addkeytime "KEY3" "SYNCPUBLISH" "${published}" ${Ipub} + +created=$(key_get KEY4 CREATED) +set_addkeytime "KEY4" "PUBLISHED" "${created}" -144000 +set_addkeytime "KEY4" "ACTIVE" "${created}" -144000 + +# Continue signing policy checks. +check_keytimes +check_apex +check_subdomain +dnssec_verify + +# Next key event is when the RSASHA1 signatures become HIDDEN. This happens +# after the max-zone-ttl plus zone propagation delay plus retire safety +# (6h + 1h + 2h) minus the time already passed since the UNRETENTIVE state has +# been reached (2h): 9h - 2h = 7h = 25200 seconds. Prevent intermittent +# false positives on slow platforms by subtracting the number of seconds +# which passed between key creation and invoking 'rndc reconfig'. +next_time=$((25200-time_passed)) +check_next_key_event $next_time + +# +# Zone: step6.algorithm-roll.kasp +# +set_zone "step6.algorithm-roll.kasp" +set_policy "ecdsa256" "4" "3600" +set_server "ns6" "10.53.0.6" +# The old zone signatures (KEY2) should now also be HIDDEN. +set_keystate "KEY2" "STATE_ZRRSIG" "hidden" + +# Various signing policy checks. +check_keys +wait_for_done_signing +check_dnssecstatus "$SERVER" "$POLICY" "$ZONE" + +# Set expected key times: +# - The old keys were activated 47 hours ago (169200 seconds) +rollover_predecessor_keytimes -169200 +# - And retired 44 hours ago (158400 seconds). +created=$(key_get KEY1 CREATED) +set_addkeytime "KEY1" "RETIRED" "${created}" -158400 +retired=$(key_get KEY1 RETIRED) +set_addkeytime "KEY1" "REMOVED" "${retired}" "${IretKSK}" + +created=$(key_get KEY2 CREATED) +set_addkeytime "KEY2" "RETIRED" "${created}" -158400 +retired=$(key_get KEY2 RETIRED) +set_addkeytime "KEY2" "REMOVED" "${retired}" "${IretZSK}" + +# The new keys are published 47 hours ago. +created=$(key_get KEY3 CREATED) +set_addkeytime "KEY3" "PUBLISHED" "${created}" -169200 +set_addkeytime "KEY3" "ACTIVE" "${created}" -169200 +published=$(key_get KEY3 PUBLISHED) +set_addkeytime "KEY3" "SYNCPUBLISH" "${published}" ${Ipub} + +created=$(key_get KEY4 CREATED) +set_addkeytime "KEY4" "PUBLISHED" "${created}" -169200 +set_addkeytime "KEY4" "ACTIVE" "${created}" -169200 + +# Continue signing policy checks. +check_keytimes +check_apex +check_subdomain +dnssec_verify + +# Next key event is never since we established the policy and the keys have +# an unlimited lifetime. Fallback to the default loadkeys interval. +check_next_key_event 3600 + +# +# Testing CSK algorithm rollover. +# + +# Policy parameters. +# Lcsk: unlimited +Lcksk=0 + +# +# Zone: step1.csk-algorithm-roll.kasp +# +set_zone "step1.csk-algorithm-roll.kasp" +set_policy "csk-algoroll" "2" "3600" +set_server "ns6" "10.53.0.6" +# Old RSASHA1 key. +key_clear "KEY1" +set_keyrole "KEY1" "csk" +set_keylifetime "KEY1" "0" +set_keyalgorithm "KEY1" "8" "RSASHA256" "2048" +set_keysigning "KEY1" "yes" +set_zonesigning "KEY1" "yes" +# New ECDSAP256SHA256 key. +key_clear "KEY2" +set_keyrole "KEY2" "csk" +set_keylifetime "KEY2" "0" +set_keyalgorithm "KEY2" "$DEFAULT_ALGORITHM_NUMBER" "$DEFAULT_ALGORITHM" "$DEFAULT_BITS" +set_keysigning "KEY2" "yes" +set_zonesigning "KEY2" "yes" +key_clear "KEY3" +key_clear "KEY4" +# The RSAHSHA1 key is outroducing. +set_keystate "KEY1" "GOAL" "hidden" +set_keystate "KEY1" "STATE_DNSKEY" "omnipresent" +set_keystate "KEY1" "STATE_KRRSIG" "omnipresent" +set_keystate "KEY1" "STATE_ZRRSIG" "omnipresent" +set_keystate "KEY1" "STATE_DS" "omnipresent" +# The ECDSAP256SHA256 key is introducing. +set_keystate "KEY2" "GOAL" "omnipresent" +set_keystate "KEY2" "STATE_DNSKEY" "rumoured" +set_keystate "KEY2" "STATE_KRRSIG" "rumoured" +set_keystate "KEY2" "STATE_ZRRSIG" "rumoured" +set_keystate "KEY2" "STATE_DS" "hidden" + +# Various signing policy checks. +check_keys +wait_for_done_signing +check_dnssecstatus "$SERVER" "$POLICY" "$ZONE" + +# Set expected key times: +# - CSK must be retired since it no longer matches the policy. +csk_rollover_predecessor_keytimes 0 +keyfile=$(key_get KEY1 BASEFILE) +grep "; Inactive:" "${keyfile}.key" > retired.test${n}.ksk +retired=$(awk '{print $3}' < retired.test${n}.ksk) +set_keytime "KEY1" "RETIRED" "${retired}" +# - The key is removed after the retire interval: +# IretZSK = TTLsig + Dprp + Dsgn + retire-safety +# TTLsig: 6h (21600 seconds) +# Dprp: 1h (3600 seconds) +# Dsgn: 25d (2160000 seconds) +# retire-safety: 2h (7200 seconds) +# IretZSK: 25d9h (2192400 seconds) +IretCSK=2192400 +set_addkeytime "KEY1" "REMOVED" "${retired}" "${IretCSK}" +# - The new CSK is published and activated. +created=$(key_get KEY2 CREATED) +set_keytime "KEY2" "PUBLISHED" "${created}" +set_keytime "KEY2" "ACTIVE" "${created}" +# - It takes TTLsig + Dprp + publish-safety hours to propagate the zone. +# TTLsig: 6h (39600 seconds) +# Dprp: 1h (3600 seconds) +# publish-safety: 1h (3600 seconds) +# Ipub: 8h (28800 seconds) +Ipub=28800 +set_addkeytime "KEY2" "SYNCPUBLISH" "${created}" "${Ipub}" + +# Continue signing policy checks. +check_keytimes +check_apex +check_subdomain +dnssec_verify + +# Next key event is when the new key has been propagated. +# This is the DNSKEY TTL plus publish safety plus zone propagation delay: +# 3 times an hour: 10800 seconds. +check_next_key_event 10800 + +# +# Zone: step2.csk-algorithm-roll.kasp +# +set_zone "step2.csk-algorithm-roll.kasp" +set_policy "csk-algoroll" "2" "3600" +set_server "ns6" "10.53.0.6" +# The RSAHSHA1 key is outroducing, but need to stay present until the new +# algorithm chain of trust has been established. Thus the properties, timings +# and states of KEY1 is the same as above. +# +# The ECDSAP256SHA256 keys are introducing. The DNSKEY RRset is omnipresent, +# but the zone signatures are not. +set_keystate "KEY2" "STATE_DNSKEY" "omnipresent" +set_keystate "KEY2" "STATE_KRRSIG" "omnipresent" + +# Various signing policy checks. +check_keys +wait_for_done_signing +check_dnssecstatus "$SERVER" "$POLICY" "$ZONE" + +# Set expected key times: +# - The old key was activated three hours ago (10800 seconds). +csk_rollover_predecessor_keytimes -10800 +# - CSK must be retired since it no longer matches the policy. +created=$(key_get KEY1 CREATED) +set_keytime "KEY1" "RETIRED" "${created}" +set_addkeytime "KEY1" "REMOVED" "${created}" "${IretCSK}" +# - The new key was published 3 hours ago. +created=$(key_get KEY2 CREATED) +set_addkeytime "KEY2" "PUBLISHED" "${created}" -10800 +set_addkeytime "KEY2" "ACTIVE" "${created}" -10800 +published=$(key_get KEY2 PUBLISHED) +set_addkeytime "KEY2" "SYNCPUBLISH" "${published}" "${Ipub}" + +# Continue signing policy checks. +check_keytimes +check_apex +check_subdomain +dnssec_verify + +# Next key event is when all zone signatures are signed with the new +# algorithm. This is the max-zone-ttl plus zone propagation delay +# plus retire safety: 6h + 1h + 2h. But three hours have already passed +# (the time it took to make the DNSKEY omnipresent), so the next event +# should be scheduled in 6 hour: 21600 seconds. Prevent intermittent +# false positives on slow platforms by subtracting the number of seconds +# which passed between key creation and invoking 'rndc reconfig'. +next_time=$((21600-time_passed)) +check_next_key_event $next_time + +# +# Zone: step3.csk-algorithm-roll.kasp +# +set_zone "step3.csk-algorithm-roll.kasp" +set_policy "csk-algoroll" "2" "3600" +set_server "ns6" "10.53.0.6" +# The RSAHSHA1 key is outroducing, and it is time to swap the DS. +# The ECDSAP256SHA256 key is introducing. The DNSKEY RRset and all signatures +# are now omnipresent, so the DS can be introduced. +set_keystate "KEY2" "STATE_ZRRSIG" "omnipresent" +# The old DS (KEY1) can be withdrawn and the new DS (KEY2) can be introduced. +set_keystate "KEY1" "STATE_DS" "unretentive" +set_keystate "KEY2" "STATE_DS" "rumoured" + +# Various signing policy checks. +check_keys +wait_for_done_signing +check_dnssecstatus "$SERVER" "$POLICY" "$ZONE" +# Check that CDS publication is logged. +check_cdslog "$DIR" "$ZONE" KEY2 + +# Set expected key times: +# - The old key was activated 9 hours ago (32400 seconds). +csk_rollover_predecessor_keytimes -32400 +# - And was retired 6 hours ago (21600 seconds). +created=$(key_get KEY1 CREATED) +set_addkeytime "KEY1" "RETIRED" "${created}" -21600 +retired=$(key_get KEY1 RETIRED) +set_addkeytime "KEY1" "REMOVED" "${retired}" "${IretCSK}" +# - The new key was published 9 hours ago. +created=$(key_get KEY2 CREATED) +set_addkeytime "KEY2" "PUBLISHED" "${created}" -32400 +set_addkeytime "KEY2" "ACTIVE" "${created}" -32400 +published=$(key_get KEY2 PUBLISHED) +set_addkeytime "KEY2" "SYNCPUBLISH" "${published}" "${Ipub}" + +# Continue signing policy checks. +check_keytimes +check_apex +check_subdomain +dnssec_verify + +# We ignore any parent registration delay, so set the DS publish time to now. +rndc_checkds "$SERVER" "$DIR" KEY1 "now" "withdrawn" "$ZONE" +rndc_checkds "$SERVER" "$DIR" KEY2 "now" "published" "$ZONE" +# Next key event is when the DS becomes OMNIPRESENT. This happens after the +# parent propagation delay, retire safety delay, and DS TTL: +# 1h + 2h + 2h = 5h = 18000 seconds. +check_next_key_event 18000 + +# +# Zone: step4.csk-algorithm-roll.kasp +# +set_zone "step4.csk-algorithm-roll.kasp" +set_policy "csk-algoroll" "2" "3600" +set_server "ns6" "10.53.0.6" +# The old DS is HIDDEN, we can remove the old algorithm DNSKEY/RRSIG records. +set_keysigning "KEY1" "no" +set_zonesigning "KEY1" "no" +set_keystate "KEY1" "STATE_DNSKEY" "unretentive" +set_keystate "KEY1" "STATE_KRRSIG" "unretentive" +set_keystate "KEY1" "STATE_ZRRSIG" "unretentive" +set_keystate "KEY1" "STATE_DS" "hidden" +# The ECDSAP256SHA256 DS is now OMNIPRESENT. +set_keystate "KEY2" "STATE_DS" "omnipresent" + +# Various signing policy checks. +check_keys +wait_for_done_signing +check_dnssecstatus "$SERVER" "$POLICY" "$ZONE" + +# Set expected key times: +# - The old key was activated 38 hours ago (136800 seconds) +csk_rollover_predecessor_keytimes -136800 +# - And retired 35 hours ago (126000 seconds). +created=$(key_get KEY1 CREATED) +set_addkeytime "KEY1" "RETIRED" "${created}" -126000 +retired=$(key_get KEY1 RETIRED) +set_addkeytime "KEY1" "REMOVED" "${retired}" "${IretCSK}" +# - The new key was published 38 hours ago. +created=$(key_get KEY2 CREATED) +set_addkeytime "KEY2" "PUBLISHED" "${created}" -136800 +set_addkeytime "KEY2" "ACTIVE" "${created}" -136800 +published=$(key_get KEY2 PUBLISHED) +set_addkeytime "KEY2" "SYNCPUBLISH" "${published}" ${Ipub} + +# Continue signing policy checks. +check_keytimes +check_apex +check_subdomain +dnssec_verify + +# Next key event is when the old DNSKEY becomes HIDDEN. This happens after the +# DNSKEY TTL plus zone propagation delay (2h). +check_next_key_event 7200 + +# +# Zone: step5.csk-algorithm-roll.kasp +# +set_zone "step5.csk-algorithm-roll.kasp" +set_policy "csk-algoroll" "2" "3600" +set_server "ns6" "10.53.0.6" +# The DNSKEY becomes HIDDEN. +set_keystate "KEY1" "STATE_DNSKEY" "hidden" +set_keystate "KEY1" "STATE_KRRSIG" "hidden" + +# Various signing policy checks. +check_keys +wait_for_done_signing +check_dnssecstatus "$SERVER" "$POLICY" "$ZONE" + +# Set expected key times: +# - The old key was activated 40 hours ago (144000 seconds) +csk_rollover_predecessor_keytimes -144000 +# - And retired 37 hours ago (133200 seconds). +created=$(key_get KEY1 CREATED) +set_addkeytime "KEY1" "RETIRED" "${created}" -133200 +retired=$(key_get KEY1 RETIRED) +set_addkeytime "KEY1" "REMOVED" "${retired}" "${IretCSK}" +# - The new key was published 40 hours ago. +created=$(key_get KEY2 CREATED) +set_addkeytime "KEY2" "PUBLISHED" "${created}" -144000 +set_addkeytime "KEY2" "ACTIVE" "${created}" -144000 +published=$(key_get KEY2 PUBLISHED) +set_addkeytime "KEY2" "SYNCPUBLISH" "${published}" ${Ipub} + +# Continue signing policy checks. +check_keytimes +check_apex +check_subdomain +dnssec_verify + +# Next key event is when the RSASHA1 signatures become HIDDEN. This happens +# after the max-zone-ttl plus zone propagation delay plus retire safety +# (6h + 1h + 2h) minus the time already passed since the UNRETENTIVE state has +# been reached (2h): 9h - 2h = 7h = 25200 seconds. Prevent intermittent +# false positives on slow platforms by subtracting the number of seconds +# which passed between key creation and invoking 'rndc reconfig'. +next_time=$((25200-time_passed)) +check_next_key_event $next_time + +# +# Zone: step6.csk-algorithm-roll.kasp +# +set_zone "step6.csk-algorithm-roll.kasp" +set_policy "csk-algoroll" "2" "3600" +set_server "ns6" "10.53.0.6" +# The zone signatures should now also be HIDDEN. +set_keystate "KEY1" "STATE_ZRRSIG" "hidden" + +# Various signing policy checks. +check_keys +wait_for_done_signing +check_dnssecstatus "$SERVER" "$POLICY" "$ZONE" + +# Set expected key times: +# - The old keys were activated 47 hours ago (169200 seconds) +csk_rollover_predecessor_keytimes -169200 +# - And retired 44 hours ago (158400 seconds). +created=$(key_get KEY1 CREATED) +set_addkeytime "KEY1" "RETIRED" "${created}" -158400 +retired=$(key_get KEY1 RETIRED) +set_addkeytime "KEY1" "REMOVED" "${retired}" "${IretCSK}" +# - The new key was published 47 hours ago. +created=$(key_get KEY2 CREATED) +set_addkeytime "KEY2" "PUBLISHED" "${created}" -169200 +set_addkeytime "KEY2" "ACTIVE" "${created}" -169200 +published=$(key_get KEY2 PUBLISHED) +set_addkeytime "KEY2" "SYNCPUBLISH" "${published}" ${Ipub} + +# Continue signing policy checks. +check_keytimes +check_apex +check_subdomain +dnssec_verify + +# Next key event is never since we established the policy and the keys have +# an unlimited lifetime. Fallback to the default loadkeys interval. +check_next_key_event 3600 + +_check_soa_ttl() { + dig_with_opts @10.53.0.6 example SOA > dig.out.ns6.test$n.soa2 || return 1 + soa1=$(awk '$4 == "SOA" { print $7 }' dig.out.ns6.test$n.soa1) + soa2=$(awk '$4 == "SOA" { print $7 }' dig.out.ns6.test$n.soa2) + ttl1=$(awk '$4 == "SOA" { print $2 }' dig.out.ns6.test$n.soa1) + ttl2=$(awk '$4 == "SOA" { print $2 }' dig.out.ns6.test$n.soa2) + test ${soa1:-1000} -lt ${soa2:-0} || return 1 + test ${ttl1:-0} -eq $1 || return 1 + test ${ttl2:-0} -eq $2 || return 1 +} + +n=$((n+1)) +echo_i "Check that 'rndc reload' of just the serial updates the signed instance ($n)" +TSIG= +ret=0 +dig_with_opts @10.53.0.6 example SOA > dig.out.ns6.test$n.soa1 || ret=1 +cp ns6/example2.db.in ns6/example.db || ret=1 +nextpart ns6/named.run > /dev/null +rndccmd 10.53.0.6 reload || ret=1 +wait_for_log 3 "all zones loaded" ns6/named.run +# Check that the SOA SERIAL increases and check the TTLs (should be 300 as +# defined in ns6/example2.db.in). +retry_quiet 10 _check_soa_ttl 300 300 || ret=1 +test "$ret" -eq 0 || echo_i "failed" +status=$((status+ret)) + +n=$((n+1)) +echo_i "Check that restart with zone changes and deleted journal works ($n)" +TSIG= +ret=0 +dig_with_opts @10.53.0.6 example SOA > dig.out.ns6.test$n.soa1 || ret=1 +stop_server --use-rndc --port ${CONTROLPORT} ns6 +# TTL of all records change from 300 to 400 +cp ns6/example3.db.in ns6/example.db || ret=1 +rm ns6/example.db.jnl +nextpart ns6/named.run > /dev/null +start_server --noclean --restart --port ${PORT} ns6 +wait_for_log 3 "all zones loaded" ns6/named.run +# Check that the SOA SERIAL increases and check the TTLs (should be changed +# from 300 to 400 as defined in ns6/example3.db.in). +retry_quiet 10 _check_soa_ttl 300 400 || ret=1 +test "$ret" -eq 0 || echo_i "failed" +status=$((status+ret)) + +echo_i "exit status: $status" +[ $status -eq 0 ] || exit 1 |