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 14 set -e 15 16 # shellcheck source=conf.sh 17 . ../conf.sh 18 19 PWD=$(pwd) 20 21 status=0 22 ret=0 23 n=0 24 25 dig_with_opts() { 26 $DIG +tcp +noadd +nosea +nostat +nocmd +dnssec -p "$PORT" "$@" 27 } 28 29 check_keys() { 30 _zone=$1 31 _expect=$2 32 _ret=0 33 _status=0 34 _count=$(ls K*.key | grep "K${_zone}" | wc -l) 35 36 test "$_count" -eq "$_expect" || _ret=1 37 test "$_ret" -eq 0 || echo_i "failed (expected $_expect keys, got $_count)" 38 _status=$((_status + _ret)) 39 40 _ret=0 41 _count=$(cat K${_zone}*.private | grep Label | wc -l) 42 test "$_count" -eq "$_expect" || _ret=1 43 test "$_ret" -eq 0 || echo_i "failed (expected Label metadata in key files)" 44 _status=$((_status + _ret)) 45 46 return $_status 47 } 48 49 # Perform tests inside ns1 dir 50 cd ns1 51 52 for algtypebits in rsasha256:rsa:2048 rsasha512:rsa:2048 \ 53 ecdsap256sha256:EC:prime256v1 ecdsap384sha384:EC:prime384v1; do # Edwards curves are not yet supported by OpenSC 54 # ed25519:EC:edwards25519 ed448:EC:edwards448 55 alg=$(echo "$algtypebits" | cut -f 1 -d :) 56 type=$(echo "$algtypebits" | cut -f 2 -d :) 57 bits=$(echo "$algtypebits" | cut -f 3 -d :) 58 zone="${alg}.example" 59 zonefile="zone.${zone}.db.signed" 60 61 if [ ! -f $zonefile ]; then 62 echo_i "skipping test for ${alg}:${type}:${bits}, no signed zone file ${zonefile}" 63 continue 64 fi 65 66 # Basic checks if setup was successful. 67 n=$((n + 1)) 68 ret=0 69 echo_i "Test key generation was successful for $zone ($n)" 70 check_keys $zone 4 || ret=1 71 status=$((status + ret)) 72 73 n=$((n + 1)) 74 ret=0 75 echo_i "Test zone signing was successful for $zone ($n)" 76 $VERIFY -z -o $zone "${zonefile}" >verify.out.$zone.$n 2>&1 || ret=1 77 test "$ret" -eq 0 || echo_i "failed (dnssec-verify failed)" 78 status=$((status + ret)) 79 80 # Test inline signing with keys stored in engine. 81 zskid1=$(cat "${zone}.zskid1") 82 zskid2=$(cat "${zone}.zskid2") 83 84 n=$((n + 1)) 85 ret=0 86 echo_i "Test inline signing for $zone ($n)" 87 dig_with_opts "$zone" @10.53.0.1 SOA >dig.out.soa.$zone.$n || ret=1 88 awk '$4 == "RRSIG" { print $11 }' dig.out.soa.$zone.$n >dig.out.keyids.$zone.$n || ret=1 89 numsigs=$(cat dig.out.keyids.$zone.$n | wc -l) 90 test $numsigs -eq 1 || ret=1 91 grep -w "$zskid1" dig.out.keyids.$zone.$n >/dev/null || ret=1 92 test "$ret" -eq 0 || echo_i "failed (SOA RRset not signed with key $zskid1)" 93 status=$((status + ret)) 94 95 n=$((n + 1)) 96 ret=0 97 echo_i "Dynamically update $zone, add new zsk ($n)" 98 zsk2=$(grep -v ';' K${zone}.*.zsk2) 99 cat >"update.cmd.zsk.$zone.$n" <<EOF 100 server 10.53.0.1 $PORT 101 ttl 300 102 zone $zone 103 update add $zsk2 104 send 105 EOF 106 107 $NSUPDATE -v >"update.log.zsk.$zone.$n" <"update.cmd.zsk.$zone.$n" || ret=1 108 test "$ret" -eq 0 || echo_i "failed (update failed)" 109 status=$((status + ret)) 110 111 n=$((n + 1)) 112 ret=0 113 echo_i "Test DNSKEY response for $zone after inline signing ($n)" 114 _dig_dnskey() { 115 dig_with_opts "$zone" @10.53.0.1 DNSKEY >dig.out.dnskey.$zone.$n || return 1 116 count=$(awk 'BEGIN { count = 0 } $4 == "DNSKEY" { count++ } END {print count}' dig.out.dnskey.$zone.$n) 117 test $count -eq 3 118 } 119 retry_quiet 10 _dig_dnskey || ret=1 120 test "$ret" -eq 0 || echo_i "failed (expected 3 DNSKEY records)" 121 status=$((status + ret)) 122 123 n=$((n + 1)) 124 ret=0 125 echo_i "Test SOA response for $zone after inline signing ($n)" 126 _dig_soa() { 127 dig_with_opts "$zone" @10.53.0.1 SOA >dig.out.soa.$zone.$n || return 1 128 awk '$4 == "RRSIG" { print $11 }' dig.out.soa.$zone.$n >dig.out.keyids.$zone.$n || return 1 129 numsigs=$(cat dig.out.keyids.$zone.$n | wc -l) 130 test $numsigs -eq 2 || return 1 131 grep -w "$zskid1" dig.out.keyids.$zone.$n >/dev/null || return 1 132 grep -w "$zskid2" dig.out.keyids.$zone.$n >/dev/null || return 1 133 return 0 134 } 135 retry_quiet 10 _dig_soa || ret=1 136 test "$ret" -eq 0 || echo_i "failed (expected 2 SOA RRSIG records)" 137 status=$((status + ret)) 138 139 # Test inline signing with keys stored in engine (key signing). 140 kskid1=$(cat "${zone}.kskid1") 141 kskid2=$(cat "${zone}.kskid2") 142 143 n=$((n + 1)) 144 ret=0 145 echo_i "Dynamically update $zone, add new ksk ($n)" 146 ksk2=$(grep -v ';' K${zone}.*.ksk2) 147 cat >"update.cmd.ksk.$zone.$n" <<EOF 148 server 10.53.0.1 $PORT 149 ttl 300 150 zone $zone 151 update add $ksk2 152 send 153 EOF 154 155 $NSUPDATE -v >"update.log.ksk.$zone.$n" <"update.cmd.ksk.$zone.$n" || ret=1 156 test "$ret" -eq 0 || echo_i "failed (update failed)" 157 status=$((status + ret)) 158 159 n=$((n + 1)) 160 ret=0 161 echo_i "Test DNSKEY response for $zone after inline signing (key signing) ($n)" 162 _dig_dnskey_ksk() { 163 dig_with_opts "$zone" @10.53.0.1 DNSKEY >dig.out.dnskey.$zone.$n || return 1 164 count=$(awk 'BEGIN { count = 0 } $4 == "DNSKEY" { count++ } END {print count}' dig.out.dnskey.$zone.$n) 165 test $count -eq 4 || return 1 166 awk '$4 == "RRSIG" { print $11 }' dig.out.dnskey.$zone.$n >dig.out.keyids.$zone.$n || return 1 167 numsigs=$(cat dig.out.keyids.$zone.$n | wc -l) 168 test $numsigs -eq 2 || return 1 169 grep -w "$kskid1" dig.out.keyids.$zone.$n >/dev/null || return 1 170 grep -w "$kskid2" dig.out.keyids.$zone.$n >/dev/null || return 1 171 return 0 172 } 173 retry_quiet 10 _dig_dnskey_ksk || ret=1 174 test "$ret" -eq 0 || echo_i "failed (expected 4 DNSKEY records, 2 KSK signatures)" 175 status=$((status + ret)) 176 177 # Check dnssec-policy interaction. 178 179 # Basic checks if setup was successful (dnssec-policy). 180 zone="${alg}.kasp" 181 n=$((n + 1)) 182 ret=0 183 ret=0 184 echo_i "Test key generation was successful for $zone ($n)" 185 check_keys $zone 2 || ret=1 186 status=$((status + ret)) 187 188 n=$((n + 1)) 189 ret=0 190 echo_i "Test DNSKEY response for $zone ($n)" 191 _dig_policy_dnskey() { 192 dig_with_opts "$zone" @10.53.0.1 DNSKEY >dig.out.dnskey.$zone.$n || return 1 193 count=$(awk 'BEGIN { count = 0 } $4 == "DNSKEY" { count++ } END {print count}' dig.out.dnskey.$zone.$n) 194 test $count -eq 2 195 } 196 retry_quiet 2 _dig_policy_dnskey || ret=1 197 test "$ret" -eq 0 || echo_i "failed (expected 2 DNSKEY records)" 198 status=$((status + ret)) 199 200 n=$((n + 1)) 201 ret=0 202 echo_i "Test SOA response for $zone ($n)" 203 _dig_policy_soa() { 204 dig_with_opts "$zone" @10.53.0.1 SOA >dig.out.soa.$zone.$n || return 1 205 awk '$4 == "RRSIG" && $5 == "SOA" { print $11 }' dig.out.soa.$zone.$n >dig.out.keyids.$zone.$n || return 1 206 numsigs=$(cat dig.out.keyids.$zone.$n | wc -l) 207 test $numsigs -eq 1 || return 1 208 return 0 209 } 210 retry_quiet 2 _dig_policy_soa || ret=1 211 test "$ret" -eq 0 || echo_i "failed (expected a SOA RRSIG record)" 212 213 zone="$alg.\"\:\;\?\&\[\]\@\!\$\*\+\,\|\=\.\(\)foo.weird" 214 keyfile="${alg}.%22%3A%3B%3F%26%5B%5D%40%21%24%2A%2B%2C%7C%3D%2E%28%29foo.weird" 215 n=$((n + 1)) 216 ret=0 217 echo_i "Test key generation was successful for $zone ($n)" 218 check_keys $keyfile 2 || ret=1 219 status=$((status + ret)) 220 221 n=$((n + 1)) 222 ret=0 223 echo_i "Test DNSKEY response for $zone ($n)" 224 retry_quiet 2 _dig_policy_dnskey || ret=1 225 test "$ret" -eq 0 || echo_i "failed (expected 2 DNSKEY records)" 226 status=$((status + ret)) 227 228 n=$((n + 1)) 229 ret=0 230 echo_i "Test SOA response for $zone ($n)" 231 retry_quiet 2 _dig_policy_soa || ret=1 232 test "$ret" -eq 0 || echo_i "failed (expected a SOA RRSIG record)" 233 status=$((status + ret)) 234 235 # Check a dnssec-policy that uses multiple key-stores. 236 zone="${alg}.split" 237 echo_i "Test key generation was successful for $zone ($n)" 238 # Check KSK. 239 check_keys $zone 1 || ret=1 240 # Check ZSK. 241 count=$(ls keys/K*.key | grep "K${_zone}" | wc -l) 242 test "$count" -eq 1 || ret=1 243 test "$ret" -eq 0 || echo_i "failed (expected 1 key, got $count)" 244 status=$((status + ret)) 245 ret=0 246 count=$(cat keys/K${zone}*.private | grep Engine | wc -l) 247 test "$count" -eq 0 || ret=1 248 count=$(cat keys/K${zone}*.private | grep Label | wc -l) 249 test "$count" -eq 0 || ret=1 250 test "$ret" -eq 0 || echo_i "failed (unexpected Engine and Label in key files)" 251 status=$((status + ret)) 252 253 # Check dnssec-keygen with dnssec-policy and key-store. 254 zone="${alg}.keygen" 255 n=$((n + 1)) 256 ret=0 257 echo_i "Test dnssec-keygen for $zone ($n)" 258 $KEYGEN $ENGINE_ARG -k $alg -l named.conf $zone >keygen.out.$zone.$n 2>/dev/null || ret=1 259 check_keys $zone 2 || ret=1 260 status=$((status + ret)) 261 262 done 263 264 # Go back to main test dir. 265 cd .. 266 267 # Perform tests inside ns2 dir 268 cd ns2 269 270 algtypebits="ecdsap256sha256:EC:prime256v1" 271 alg=$(echo "$algtypebits" | cut -f 1 -d :) 272 type=$(echo "$algtypebits" | cut -f 2 -d :) 273 bits=$(echo "$algtypebits" | cut -f 3 -d :) 274 zone="${alg}.views" 275 zonefile1="zone.$alg.views.view1.db.signed" 276 zonefile2="zone.$alg.views.view2.db.signed" 277 278 skip=0 279 if [ ! -f $zonefile1 ]; then 280 echo_i "skipping test for ${alg}:${type}:${bits}, no signed zone file ${zonefile1}" 281 skip=1 282 fi 283 284 if [ ! -f $zonefile2 ]; then 285 echo_i "skipping test for ${alg}:${type}:${bits}, no signed zone file ${zonefile2}" 286 skip=1 287 fi 288 289 if [ $skip -eq 0 ]; then 290 # Basic checks if setup was successful. 291 n=$((n + 1)) 292 ret=0 293 echo_i "Test key generation was successful for $zone ($n)" 294 check_keys $zone 4 || ret=1 295 status=$((status + ret)) 296 297 n=$((n + 1)) 298 ret=0 299 echo_i "Test zone signing was successful for $zone in view1 ($n)" 300 $VERIFY -z -o $zone "${zonefile1}" >verify.out.$zone.view1.$n 2>&1 || ret=1 301 test "$ret" -eq 0 || echo_i "failed (dnssec-verify failed)" 302 status=$((status + ret)) 303 304 n=$((n + 1)) 305 ret=0 306 echo_i "Test zone signing was successful for $zone in view2 ($n)" 307 $VERIFY -z -o $zone "${zonefile2}" >verify.out.$zone.view2.$n 2>&1 || ret=1 308 test "$ret" -eq 0 || echo_i "failed (dnssec-verify failed)" 309 status=$((status + ret)) 310 311 # Test dnssec-policy signing with keys stored in engine. 312 zone="${alg}.same-policy.views" 313 314 n=$((n + 1)) 315 ret=0 316 echo_i "Test key generation was successful for $zone ($n)" 317 check_keys $zone 1 || ret=1 318 status=$((status + ret)) 319 320 _dig_inview() { 321 _qtype="$1" 322 _alg="$2" 323 _tsig="$DEFAULT_HMAC:$3:$4" 324 dig_with_opts "$zone" @10.53.0.2 $_qtype -y "$_tsig" >dig.out.$zone.$n || return 1 325 awk -v cov="$_qtype" '$4 == "RRSIG" && $5 == cov { print $6 }' dig.out.$zone.$n >dig.out.alg.$zone.$n || return 1 326 numsigs=$(cat dig.out.alg.$zone.$n | wc -l) 327 test $numsigs -eq 1 || return 1 328 grep -w "$_alg" dig.out.alg.$zone.$n >/dev/null || return 1 329 } 330 331 n=$((n + 1)) 332 ret=0 333 echo_i "Test SOA is signed for $zone in view1 ($n)" 334 VIEW1="YPfMoAk6h+3iN8MDRQC004iSNHY=" 335 retry_quiet 4 _dig_inview SOA 13 keyforview1 $VIEW1 || ret=1 336 test "$ret" -eq 0 || echo_i "failed (SOA RRset not signed)" 337 status=$((status + ret)) 338 339 n=$((n + 1)) 340 ret=0 341 echo_i "Test DNSKEY is signed for $zone in view1 ($n)" 342 retry_quiet 4 _dig_inview DNSKEY 13 keyforview1 $VIEW1 || ret=1 343 test "$ret" -eq 0 || echo_i "failed (DNSKEY RRset not signed)" 344 status=$((status + ret)) 345 346 n=$((n + 1)) 347 ret=0 348 echo_i "Test SOA is signed for $zone in view2 ($n)" 349 VIEW2="4xILSZQnuO1UKubXHkYUsvBRPu8=" 350 retry_quiet 4 _dig_inview SOA 13 keyforview2 $VIEW2 || ret=1 351 test "$ret" -eq 0 || echo_i "failed (SOA RRset not signed)" 352 status=$((status + ret)) 353 354 n=$((n + 1)) 355 ret=0 356 echo_i "Test DNSKEY is signed for $zone in view2 ($n)" 357 retry_quiet 4 _dig_inview DNSKEY 13 keyforview2 $VIEW2 || ret=1 358 test "$ret" -eq 0 || echo_i "failed (DNSKEY RRset not signed)" 359 status=$((status + ret)) 360 361 # Now test zone in different views using a different dnssec-policy. 362 zone="zone-with.different-policy.views" 363 364 n=$((n + 1)) 365 ret=0 366 echo_i "Test key generation was successful for $zone in view1 ($n)" 367 # view1 368 check_keys $zone 1 || ret=1 369 status=$((status + ret)) 370 # view2 371 echo_i "Test key generation was successful for $zone in view2 ($n)" 372 count=$(ls keys/K*.key | grep "K${zone}" | wc -l) 373 test "$count" -eq 1 || ret=1 374 test "$ret" -eq 0 || echo_i "failed (expected 1 key, got $count)" 375 status=$((status + ret)) 376 377 n=$((n + 1)) 378 ret=0 379 echo_i "Test SOA is signed for $zone in view1 ($n)" 380 VIEW1="YPfMoAk6h+3iN8MDRQC004iSNHY=" 381 retry_quiet 4 _dig_inview SOA 13 keyforview1 $VIEW1 || ret=1 382 test "$ret" -eq 0 || echo_i "failed (SOA RRset not signed)" 383 status=$((status + ret)) 384 385 n=$((n + 1)) 386 ret=0 387 echo_i "Test DNSKEY is signed for $zone in view1 ($n)" 388 retry_quiet 4 _dig_inview DNSKEY 13 keyforview1 $VIEW1 || ret=1 389 test "$ret" -eq 0 || echo_i "failed (DNSKEY RRset not signed)" 390 status=$((status + ret)) 391 392 n=$((n + 1)) 393 ret=0 394 echo_i "Test SOA is signed for $zone in view2 ($n)" 395 VIEW2="4xILSZQnuO1UKubXHkYUsvBRPu8=" 396 retry_quiet 4 _dig_inview SOA 8 keyforview2 $VIEW2 || ret=1 397 test "$ret" -eq 0 || echo_i "failed (SOA RRset not signed)" 398 status=$((status + ret)) 399 400 n=$((n + 1)) 401 ret=0 402 echo_i "Test DNSKEY is signed for $zone in view2 ($n)" 403 retry_quiet 4 _dig_inview DNSKEY 8 keyforview2 $VIEW2 || ret=1 404 test "$ret" -eq 0 || echo_i "failed (DNSKEY RRset not signed)" 405 status=$((status + ret)) 406 fi 407 408 # Go back to main test dir. 409 cd .. 410 411 n=$((n + 1)) 412 ret=0 413 echo_i "Checking for assertion failure in pk11_numbits()" 414 $PERL ../packet.pl -a "10.53.0.1" -p "$PORT" -t udp 2037-pk11_numbits-crash-test.pkt 415 dig_with_opts @10.53.0.1 version.bind. CH TXT >dig.out.pk11_numbits || ret=1 416 test "$ret" -eq 0 || echo_i "failed" 417 status=$((status + ret)) 418 419 echo_i "exit status: $status" 420 [ $status -eq 0 ] || exit 1 421