xref: /netbsd-src/external/mpl/bind/dist/bin/tests/system/smartsign/tests.sh (revision 8aaca124c0ad52af9550477f296b63debc7b4c98)
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