1#!/bin/sh 2 3# Copyright (C) Internet Systems Consortium, Inc. ("ISC") 4# 5# SPDX-License-Identifier: MPL-2.0 6# 7# This Source Code Form is subject to the terms of the Mozilla Public 8# License, v. 2.0. If a copy of the MPL was not distributed with this 9# file, you can obtain one at https://mozilla.org/MPL/2.0/. 10# 11# See the COPYRIGHT file distributed with this work for additional 12# information regarding copyright ownership. 13 14set -e 15 16. ../conf.sh 17 18status=0 19 20pzone=parent.nil 21pfile=parent.db 22 23czone=child.parent.nil 24cfile=child.db 25 26echo_i "generating child's keys" 27# active zsk 28czsk1=$($KEYGEN -q -a ${DEFAULT_ALGORITHM} -L 30 $czone) 29 30# not yet published or active 31czsk2=$($KEYGEN -q -a ${DEFAULT_ALGORITHM} -P none -A none $czone) 32 33# published but not active 34czsk3=$($KEYGEN -q -a ${DEFAULT_ALGORITHM} -A none $czone) 35 36# inactive 37czsk4=$($KEYGEN -q -a ${DEFAULT_ALGORITHM} -P now-24h -A now-24h -I now $czone) 38 39# active in 12 hours, inactive 12 hours after that... 40czsk5=$($KEYGEN -q -a ${DEFAULT_ALGORITHM} -P now+12h -A now+12h -I now+24h $czone) 41 42# explicit successor to czk5 43# (suppressing warning about lack of removal date) 44czsk6=$($KEYGEN -q -S $czsk5 -i 6h 2>/dev/null) 45 46# active ksk 47cksk1=$($KEYGEN -q -a ${DEFAULT_ALGORITHM} -fk -L 30 $czone) 48 49# published but not YET active; will be active in 20 seconds 50cksk2=$($KEYGEN -q -a ${DEFAULT_ALGORITHM} -fk $czone) 51# $SETTIME moved after other $KEYGENs 52 53echo_i "revoking key" 54# revoking key changes its ID 55cksk3=$($KEYGEN -q -a ${DEFAULT_ALGORITHM} -fk $czone) 56cksk4=$($REVOKE $cksk3) 57 58echo_i "setting up sync key" 59cksk5=$($KEYGEN -q -a ${DEFAULT_ALGORITHM} -fk -P now+1mo -A now+1mo -Psync now $czone) 60 61echo_i "and future sync key" 62cksk6=$($KEYGEN -q -a ${DEFAULT_ALGORITHM} -fk -P now+1mo -A now+1mo -Psync now+1mo $czone) 63 64echo_i "generating parent keys" 65pzsk=$($KEYGEN -q -a ${DEFAULT_ALGORITHM} $pzone) 66pksk=$($KEYGEN -q -a ${DEFAULT_ALGORITHM} -fk $pzone) 67 68echo_i "setting child's activation time" 69# using now+30s to fix RT 24561 70$SETTIME -A now+30s $cksk2 >/dev/null 71 72echo_i "signing child zone" 73czoneout=$($SIGNER -Sg -e now+1d -X now+2d -o $czone $cfile) 74 75echo_i "signing parent zone" 76pzoneout=$($SIGNER -Sg -o $pzone $pfile) 77 78czactive=$(keyfile_to_key_id $czsk1) 79czgenerated=$(keyfile_to_key_id $czsk2) 80czpublished=$(keyfile_to_key_id $czsk3) 81czinactive=$(keyfile_to_key_id $czsk4) 82czpredecessor=$(keyfile_to_key_id $czsk5) 83czsuccessor=$(keyfile_to_key_id $czsk6) 84ckactive=$(keyfile_to_key_id $cksk1) 85ckpublished=$(keyfile_to_key_id $cksk2) 86ckprerevoke=$(keyfile_to_key_id $cksk3) 87ckrevoked=$(keyfile_to_key_id $cksk4) 88 89pzid=$(keyfile_to_key_id $pzsk) 90pkid=$(keyfile_to_key_id $pksk) 91 92echo_i "checking dnssec-signzone output matches expectations" 93ret=0 94echo "$pzoneout" | grep 'KSKs: 1 active, 0 stand-by, 0 revoked' >/dev/null || ret=1 95echo "$pzoneout" | grep 'ZSKs: 1 active, 0 stand-by, 0 revoked' >/dev/null || ret=1 96echo "$czoneout" | grep 'KSKs: 1 active, 1 stand-by, 1 revoked' >/dev/null || ret=1 97echo "$czoneout" | grep 'ZSKs: 1 active, 2 stand-by, 0 revoked' >/dev/null || ret=1 98if [ $ret != 0 ]; then 99 echo_i "parent $pzoneout" 100 echo_i "child $czoneout" 101 echo_i "failed" 102fi 103status=$((status + ret)) 104 105echo_i "rechecking dnssec-signzone output with -x" 106ret=0 107# use an alternate output file so -x doesn't interfere with later checks 108pzoneout=$($SIGNER -Sxg -o $pzone -f ${pfile}2.signed $pfile) 109czoneout=$($SIGNER -Sxg -e now+1d -X now+2d -o $czone -f ${cfile}2.signed $cfile) 110echo "$pzoneout" | grep 'KSKs: 1 active, 0 stand-by, 0 revoked' >/dev/null || ret=1 111echo "$pzoneout" | grep 'ZSKs: 1 active, 0 present, 0 revoked' >/dev/null || ret=1 112echo "$czoneout" | grep 'KSKs: 1 active, 1 stand-by, 1 revoked' >/dev/null || ret=1 113echo "$czoneout" | grep 'ZSKs: 1 active, 2 present, 0 revoked' >/dev/null || ret=1 114if [ $ret != 0 ]; then 115 echo_i "parent $pzoneout" 116 echo_i "child $czoneout" 117 echo_i "failed" 118fi 119status=$((status + ret)) 120 121echo_i "checking parent zone DNSKEY set" 122ret=0 123grep "key id = $pzid" $pfile.signed >/dev/null || { 124 ret=1 125 echo_i "missing expected parent ZSK id = $pzid" 126} 127grep "key id = $pkid" $pfile.signed >/dev/null || { 128 ret=1 129 echo_i "missing expected parent KSK id = $pkid" 130} 131if [ $ret != 0 ]; then echo_i "failed"; fi 132status=$((status + ret)) 133 134echo_i "checking parent zone DS records" 135ret=0 136awk '$2 == "DS" {print $3}' $pfile.signed >dsset.out 137grep -w "$ckactive" dsset.out >/dev/null || ret=1 138grep -w "$ckpublished" dsset.out >/dev/null || ret=1 139# revoked key should not be there, hence the && 140grep -w "$ckprerevoke" dsset.out >/dev/null && ret=1 141grep -w "$ckrevoked" dsset.out >/dev/null && ret=1 142if [ $ret != 0 ]; then echo_i "failed"; fi 143status=$((status + ret)) 144 145echo_i "checking child zone DNSKEY set" 146ret=0 147grep "key id = $ckactive\$" $cfile.signed >/dev/null || { 148 ret=1 149 echo_i "missing expected child KSK id = $ckactive" 150} 151grep "key id = $ckpublished\$" $cfile.signed >/dev/null || { 152 ret=1 153 echo_i "missing expected child prepublished KSK id = $ckpublished" 154} 155grep "key id = $ckrevoked\$" $cfile.signed >/dev/null || { 156 ret=1 157 echo_i "missing expected child revoked KSK id = $ckrevoked" 158} 159grep "key id = $czactive\$" $cfile.signed >/dev/null || { 160 ret=1 161 echo_i "missing expected child ZSK id = $czactive" 162} 163grep "key id = $czpublished\$" $cfile.signed >/dev/null || { 164 ret=1 165 echo_i "missing expected child prepublished ZSK id = $czpublished" 166} 167grep "key id = $czinactive\$" $cfile.signed >/dev/null || { 168 ret=1 169 echo_i "missing expected child inactive ZSK id = $czinactive" 170} 171# should not be there, hence the && 172grep "key id = $ckprerevoke\$" $cfile.signed >/dev/null && { 173 ret=1 174 echo_i "found unexpected child pre-revoke ZSK id = $ckprerevoke" 175} 176grep "key id = $czgenerated\$" $cfile.signed >/dev/null && { 177 ret=1 178 echo_i "found unexpected child generated ZSK id = $czgenerated" 179} 180grep "key id = $czpredecessor\$" $cfile.signed >/dev/null && { 181 echo_i "found unexpected ZSK predecessor id = $czpredecessor (ignored)" 182} 183grep "key id = $czsuccessor\$" $cfile.signed >/dev/null && { 184 echo_i "found unexpected ZSK successor id = $czsuccessor (ignored)" 185} 186#grep "key id = $czpredecessor\$" $cfile.signed > /dev/null && ret=1 187#grep "key id = $czsuccessor\$" $cfile.signed > /dev/null && ret=1 188if [ $ret != 0 ]; then echo_i "failed"; fi 189status=$((status + ret)) 190 191echo_i "checking key TTLs are correct" 192ret=0 193grep "${czone}. 30 IN" ${czsk1}.key >/dev/null 2>&1 || ret=1 194grep "${czone}. 30 IN" ${cksk1}.key >/dev/null 2>&1 || ret=1 195grep "${czone}. IN" ${czsk2}.key >/dev/null 2>&1 || ret=1 196$SETTIME -L 45 ${czsk2} >/dev/null 197grep "${czone}. 45 IN" ${czsk2}.key >/dev/null 2>&1 || ret=1 198$SETTIME -L 0 ${czsk2} >/dev/null 199grep "${czone}. IN" ${czsk2}.key >/dev/null 2>&1 || ret=1 200if [ $ret != 0 ]; then echo_i "failed"; fi 201status=$((status + ret)) 202 203echo_i "checking key TTLs were imported correctly" 204ret=0 205awk 'BEGIN {r = 0} $2 == "DNSKEY" && $1 != 30 {r = 1} END {exit r}' \ 206 ${cfile}.signed || ret=1 207if [ $ret != 0 ]; then echo_i "failed"; fi 208status=$((status + ret)) 209 210echo_i "re-signing and checking imported TTLs again" 211ret=0 212$SETTIME -L 15 ${czsk2} >/dev/null 213czoneout=$($SIGNER -Sg -e now+1d -X now+2d -o $czone $cfile) 214awk 'BEGIN {r = 0} $2 == "DNSKEY" && $1 != 15 {r = 1} END {exit r}' \ 215 ${cfile}.signed || ret=1 216if [ $ret != 0 ]; then echo_i "failed"; fi 217status=$((status + ret)) 218 219# There is some weirdness in Solaris 10 (Generic_120011-14), which 220# is why the next section has all those echo $ret > /dev/null;sync 221# commands 222echo_i "checking child zone signatures" 223ret=0 224# check DNSKEY signatures first 225awk '$2 == "RRSIG" && $3 == "DNSKEY" { getline; print $3 }' $cfile.signed >dnskey.sigs 226sub=0 227grep -w "$ckactive" dnskey.sigs >/dev/null || sub=1 228if [ $sub != 0 ]; then 229 echo_i "missing ckactive $ckactive (dnskey)" 230 ret=1 231fi 232echo $ret >/dev/null 233sync 234sub=0 235grep -w "$ckrevoked" dnskey.sigs >/dev/null || sub=1 236if [ $sub != 0 ]; then 237 echo_i "missing ckrevoke $ckrevoke (dnskey)" 238 ret=1 239fi 240echo $ret >/dev/null 241sync 242sub=0 243grep -w "$czactive" dnskey.sigs >/dev/null || sub=1 244if [ $sub != 0 ]; then 245 echo_i "missing czactive $czactive (dnskey)" 246 ret=1 247fi 248# should not be there: 249echo $ret >/dev/null 250sync 251sub=0 252grep -w "$ckprerevoke" dnskey.sigs >/dev/null && sub=1 253if [ $sub != 0 ]; then 254 echo_i "found ckprerevoke $ckprerevoke (dnskey)" 255 ret=1 256fi 257echo $ret >/dev/null 258sync 259sub=0 260grep -w "$ckpublished" dnskey.sigs >/dev/null && sub=1 261if [ $sub != 0 ]; then 262 echo_i "found ckpublished $ckpublished (dnskey)" 263 ret=1 264fi 265echo $ret >/dev/null 266sync 267sub=0 268grep -w "$czpublished" dnskey.sigs >/dev/null && sub=1 269if [ $sub != 0 ]; then 270 echo_i "found czpublished $czpublished (dnskey)" 271 ret=1 272fi 273echo $ret >/dev/null 274sync 275sub=0 276grep -w "$czinactive" dnskey.sigs >/dev/null && sub=1 277if [ $sub != 0 ]; then 278 echo_i "found czinactive $czinactive (dnskey)" 279 ret=1 280fi 281echo $ret >/dev/null 282sync 283sub=0 284grep -w "$czgenerated" dnskey.sigs >/dev/null && sub=1 285if [ $sub != 0 ]; then 286 echo_i "found czgenerated $czgenerated (dnskey)" 287 ret=1 288fi 289# now check other signatures first 290awk '$2 == "RRSIG" && $3 != "DNSKEY" && $3 != "CDNSKEY" && $3 != "CDS" { getline; print $3 }' $cfile.signed | sort -un >other.sigs 291# should not be there: 292echo $ret >/dev/null 293sync 294sub=0 295grep -w "$ckactive" other.sigs >/dev/null && sub=1 296if [ $sub != 0 ]; then 297 echo_i "found ckactive $ckactive (other)" 298 ret=1 299fi 300echo $ret >/dev/null 301sync 302sub=0 303grep -w "$ckpublished" other.sigs >/dev/null && sub=1 304if [ $sub != 0 ]; then 305 echo_i "found ckpublished $ckpublished (other)" 306 ret=1 307fi 308echo $ret >/dev/null 309sync 310sub=0 311grep -w "$ckprerevoke" other.sigs >/dev/null && sub=1 312if [ $sub != 0 ]; then 313 echo_i "found ckprerevoke $ckprerevoke (other)" 314 ret=1 315fi 316echo $ret >/dev/null 317sync 318sub=0 319grep -w "$ckrevoked" other.sigs >/dev/null && sub=1 320if [ $sub != 0 ]; then 321 echo_i "found ckrevoked $ckrevoked (other)" 322 ret=1 323fi 324echo $ret >/dev/null 325sync 326sub=0 327grep -w "$czpublished" other.sigs >/dev/null && sub=1 328if [ $sub != 0 ]; then 329 echo_i "found czpublished $czpublished (other)" 330 ret=1 331fi 332echo $ret >/dev/null 333sync 334sub=0 335grep -w "$czinactive" other.sigs >/dev/null && sub=1 336if [ $sub != 0 ]; then 337 echo_i "found czinactive $czinactive (other)" 338 ret=1 339fi 340echo $ret >/dev/null 341sync 342sub=0 343grep -w "$czgenerated" other.sigs >/dev/null && sub=1 344if [ $sub != 0 ]; then 345 echo_i "found czgenerated $czgenerated (other)" 346 ret=1 347fi 348echo $ret >/dev/null 349sync 350sub=0 351grep -w "$czpredecessor" other.sigs >/dev/null && sub=1 352if [ $sub != 0 ]; then 353 echo_i "found czpredecessor $czpredecessor (other)" 354 ret=1 355fi 356echo $ret >/dev/null 357sync 358sub=0 359grep -w "$czsuccessor" other.sigs >/dev/null && sub=1 360if [ $sub != 0 ]; then 361 echo_i "found czsuccessor $czsuccessor (other)" 362 ret=1 363fi 364if [ $ret != 0 ]; then 365 sed 's/^/I:dnskey sigs: /' <dnskey.sigs 366 sed 's/^/I:other sigs: /' <other.sigs 367 echo_i "failed" 368fi 369status=$((status + ret)) 370 371echo_i "checking RRSIG expiry date correctness" 372dnskey_expiry=$($CHECKZONE -o - $czone $cfile.signed 2>/dev/null \ 373 | awk '$4 == "RRSIG" && $5 == "DNSKEY" {print $9; exit}' \ 374 | cut -c1-10) 375soa_expiry=$($CHECKZONE -o - $czone $cfile.signed 2>/dev/null \ 376 | awk '$4 == "RRSIG" && $5 == "SOA" {print $9; exit}' \ 377 | cut -c1-10) 378[ $dnskey_expiry -gt $soa_expiry ] || ret=1 379if [ $ret != 0 ]; then echo_i "failed"; fi 380status=$((status + ret)) 381 382echo_i "waiting 30 seconds for key activation" 383sleep 30 384echo_i "re-signing child zone" 385czoneout2=$($SIGNER -Sg -o $czone -f $cfile.new $cfile.signed) 386mv $cfile.new $cfile.signed 387 388echo_i "checking dnssec-signzone output matches expectations" 389ret=0 390echo "$czoneout2" | grep 'KSKs: 2 active, 0 stand-by, 1 revoked' >/dev/null || ret=1 391if [ $ret != 0 ]; then echo_i "failed"; fi 392status=$((status + ret)) 393 394echo_i "checking child zone signatures again" 395ret=0 396awk '$2 == "RRSIG" && $3 == "DNSKEY" { getline; print $3 }' $cfile.signed >dnskey.sigs 397grep -w "$ckpublished" dnskey.sigs >/dev/null || ret=1 398if [ $ret != 0 ]; then echo_i "failed"; fi 399status=$((status + ret)) 400 401echo_i "checking sync record publication" 402ret=0 403awk 'BEGIN { r=1 } $2 == "CDNSKEY" { r=0 } END { exit r }' $cfile.signed || ret=1 404awk 'BEGIN { r=1 } $2 == "CDS" { r=0 } END { exit r }' $cfile.signed || ret=1 405if [ $ret != 0 ]; then echo_i "failed"; fi 406status=$((status + ret)) 407 408# this also checks that the future sync record is not yet published 409echo_i "checking sync record deletion" 410ret=0 411$SETTIME -P now -A now -Dsync now ${cksk5} >/dev/null 412$SIGNER -Sg -o $czone -f $cfile.new $cfile.signed >/dev/null 413mv $cfile.new $cfile.signed 414awk 'BEGIN { r=1 } $2 == "CDNSKEY" { r=0 } END { exit r }' $cfile.signed && ret=1 415awk 'BEGIN { r=1 } $2 == "CDS" { r=0 } END { exit r }' $cfile.signed && ret=1 416if [ $ret != 0 ]; then echo_i "failed"; fi 417status=$((status + ret)) 418 419echo_i "exit status: $status" 420[ $status -eq 0 ] || exit 1 421