diff --git a/bin/tests/system/checkconf/kasp-bad-keylen.conf b/bin/tests/system/checkconf/kasp-bad-keylen.conf new file mode 100644 index 0000000000..ec52436fe8 --- /dev/null +++ b/bin/tests/system/checkconf/kasp-bad-keylen.conf @@ -0,0 +1,22 @@ +/* + * Copyright (C) Internet Systems Consortium, Inc. ("ISC") + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * See the COPYRIGHT file distributed with this work for additional + * information regarding copyright ownership. + */ + +dnssec-policy "bad-keylen" { + keys { + csk lifetime P10Y algorithm rsasha1 511; + }; +}; + +zone "example.net" { + type master; + file "example.db"; + dnssec-policy "badkeylen"; +}; diff --git a/bin/tests/system/checkconf/kasp-bad-nsec3-iter.conf b/bin/tests/system/checkconf/kasp-bad-nsec3-iter.conf new file mode 100644 index 0000000000..f537f50e92 --- /dev/null +++ b/bin/tests/system/checkconf/kasp-bad-nsec3-iter.conf @@ -0,0 +1,58 @@ +/* + * Copyright (C) Internet Systems Consortium, Inc. ("ISC") + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * See the COPYRIGHT file distributed with this work for additional + * information regarding copyright ownership. + */ + +dnssec-policy "rsasha1" { + keys { + csk lifetime P10Y algorithm rsasha1 1024; + }; + nsec3param iterations 150; +}; + +dnssec-policy "rsasha1-bad" { + keys { + csk lifetime P10Y algorithm rsasha1 1024; + }; + nsec3param iterations 151; +}; + +dnssec-policy "rsasha256" { + keys { + csk lifetime P10Y algorithm rsasha256 2048; + }; + nsec3param iterations 500; +}; + +dnssec-policy "rsasha256-bad" { + keys { + csk lifetime P10Y algorithm rsasha256 2048; + }; + nsec3param iterations 501; +}; + +dnssec-policy "rsasha512" { + keys { + csk lifetime P10Y algorithm rsasha512 4096; + }; + nsec3param iterations 2500; +}; + +dnssec-policy "rsasha512-bad" { + keys { + csk lifetime P10Y algorithm rsasha512 4096; + }; + nsec3param iterations 2501; +}; + +zone "example.net" { + type master; + file "example.db"; + dnssec-policy "default"; +}; diff --git a/bin/tests/system/checkconf/kasp-bad-nsec3-salt.conf b/bin/tests/system/checkconf/kasp-bad-nsec3-salt.conf new file mode 100644 index 0000000000..7701d3b4dd --- /dev/null +++ b/bin/tests/system/checkconf/kasp-bad-nsec3-salt.conf @@ -0,0 +1,21 @@ +/* + * Copyright (C) Internet Systems Consortium, Inc. ("ISC") + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * See the COPYRIGHT file distributed with this work for additional + * information regarding copyright ownership. + */ + +dnssec-policy "bad-salt" { + nsec3param salt "pepper"; +}; + +zone "example.net" { + type master; + file "example.db"; + dnssec-policy "bad-salt"; +}; + diff --git a/bin/tests/system/checkconf/tests.sh b/bin/tests/system/checkconf/tests.sh index 244c226469..eb39d59b56 100644 --- a/bin/tests/system/checkconf/tests.sh +++ b/bin/tests/system/checkconf/tests.sh @@ -509,7 +509,35 @@ if [ $ret != 0 ]; then echo_i "failed"; fi status=`expr $status + $ret` n=`expr $n + 1` -echo_i "checking named-checkconf kasp predefined key lengths ($n)" +echo_i "checking named-checkconf kasp nsec3 salt errors ($n)" +ret=0 +$CHECKCONF kasp-bad-nsec3-salt.conf > checkconf.out$n 2>&1 && ret=1 +grep "dnssec-policy: bad nsec3 salt pepper" < checkconf.out$n > /dev/null || ret=1 +if [ $ret != 0 ]; then echo_i "failed"; fi +status=`expr $status + $ret` + +n=`expr $n + 1` +echo_i "checking named-checkconf kasp nsec3 iterations errors ($n)" +ret=0 +$CHECKCONF kasp-bad-nsec3-iter.conf > checkconf.out$n 2>&1 && ret=1 +grep "dnssec-policy: nsec3 iterations value 151 out of range" < checkconf.out$n > /dev/null || ret=1 +grep "dnssec-policy: nsec3 iterations value 501 out of range" < checkconf.out$n > /dev/null || ret=1 +grep "dnssec-policy: nsec3 iterations value 2501 out of range" < checkconf.out$n > /dev/null || ret=1 +lines=$(wc -l < "checkconf.out$n") +if [ $lines != 3 ]; then ret=1; fi +if [ $ret != 0 ]; then echo_i "failed"; fi +status=`expr $status + $ret` + +n=`expr $n + 1` +echo_i "checking named-checkconf kasp key errors ($n)" +ret=0 +$CHECKCONF kasp-bad-keylen.conf > checkconf.out$n 2>&1 && ret=1 +grep "dnssec-policy: key with algorithm rsasha1 has invalid key length 511" < checkconf.out$n > /dev/null || ret=1 +if [ $ret != 0 ]; then echo_i "failed"; fi +status=`expr $status + $ret` + +n=`expr $n + 1` +echo_i "checking named-checkconf kasp predefined key length ($n)" ret=0 $CHECKCONF kasp-ignore-keylen.conf > checkconf.out$n 2>&1 || ret=1 grep "dnssec-policy: key algorithm ecdsa256 has predefined length; ignoring length value 2048" < checkconf.out$n > /dev/null || ret=1 diff --git a/lib/dns/include/dns/result.h b/lib/dns/include/dns/result.h index b7f178c7af..f6ec856308 100644 --- a/lib/dns/include/dns/result.h +++ b/lib/dns/include/dns/result.h @@ -158,8 +158,10 @@ #define DNS_R_NOKEYMATCH (ISC_RESULTCLASS_DNS + 120) #define DNS_R_TOOMANYKEYS (ISC_RESULTCLASS_DNS + 121) #define DNS_R_KEYNOTACTIVE (ISC_RESULTCLASS_DNS + 122) +#define DNS_R_NSEC3ITERRANGE (ISC_RESULTCLASS_DNS + 123) +#define DNS_R_NSEC3BADSALT (ISC_RESULTCLASS_DNS + 124) -#define DNS_R_NRESULTS 123 /*%< Number of results */ +#define DNS_R_NRESULTS 125 /*%< Number of results */ /* * DNS wire format rcodes. diff --git a/lib/dns/result.c b/lib/dns/result.c index 465f72f783..7df73f78e5 100644 --- a/lib/dns/result.c +++ b/lib/dns/result.c @@ -169,6 +169,9 @@ static const char *text[DNS_R_NRESULTS] = { "no matching key found", /*%< 120 DNS_R_NOKEYMATCH */ "too many keys matching", /*%< 121 DNS_R_TOOMANYKEYS */ "key is not actively signing", /*%< 122 DNS_R_KEYNOTACTIVE */ + + "NSEC3 iterations out of range", /*%< 123 DNS_R_NSEC3ITERRANGE */ + "bad NSEC3 salt", /*%< 124 DNS_R_NSEC3BADSALT */ }; static const char *ids[DNS_R_NRESULTS] = { @@ -299,6 +302,8 @@ static const char *ids[DNS_R_NRESULTS] = { "DNS_R_NOKEYMATCH", "DNS_R_TOOMANYKEYS", "DNS_R_KEYNOTACTIVE", + "DNS_R_NSEC3ITERRANGE", + "DNS_R_NSEC3BADSALT", }; static const char *rcode_text[DNS_R_NRCODERESULTS] = { diff --git a/lib/isccfg/kaspconf.c b/lib/isccfg/kaspconf.c index 6629bf52b3..af52c9c64f 100644 --- a/lib/isccfg/kaspconf.c +++ b/lib/isccfg/kaspconf.c @@ -166,17 +166,47 @@ cleanup: } static isc_result_t -cfg_nsec3param_fromconfig(const cfg_obj_t *config, dns_kasp_t *kasp) { +cfg_nsec3param_fromconfig(const cfg_obj_t *config, dns_kasp_t *kasp, + isc_log_t *logctx) { + dns_kasp_key_t *kkey; + unsigned int min_keysize = 4096; const cfg_obj_t *obj = NULL; const char *salt = NULL; - uint8_t iter = DEFAULT_NSEC3PARAM_ITER; + uint32_t iter = DEFAULT_NSEC3PARAM_ITER; bool optout = false; + isc_result_t ret = ISC_R_SUCCESS; /* How many iterations. */ obj = cfg_tuple_get(config, "iterations"); if (cfg_obj_isuint32(obj)) { iter = cfg_obj_asuint32(obj); } + dns_kasp_freeze(kasp); + for (kkey = ISC_LIST_HEAD(dns_kasp_keys(kasp)); kkey != NULL; + kkey = ISC_LIST_NEXT(kkey, link)) + { + unsigned int keysize = dns_kasp_key_size(kkey); + if (keysize < min_keysize) { + min_keysize = keysize; + } + } + dns_kasp_thaw(kasp); + /* See RFC 5155 Section 10.3 for iteration limits. */ + if (min_keysize <= 1024 && iter > 150) { + ret = DNS_R_NSEC3ITERRANGE; + } else if (min_keysize <= 2048 && iter > 500) { + ret = DNS_R_NSEC3ITERRANGE; + } else if (min_keysize <= 4096 && iter > 2500) { + ret = DNS_R_NSEC3ITERRANGE; + } + + if (ret == DNS_R_NSEC3ITERRANGE) { + cfg_obj_log(obj, logctx, ISC_LOG_ERROR, + "dnssec-policy: nsec3 iterations value %u " + "out of range", + iter); + return (ret); + } /* Opt-out? */ obj = cfg_tuple_get(config, "optout"); @@ -190,7 +220,12 @@ cfg_nsec3param_fromconfig(const cfg_obj_t *config, dns_kasp_t *kasp) { salt = cfg_obj_asstring(obj); } - return dns_kasp_setnsec3param(kasp, iter, optout, salt); + ret = dns_kasp_setnsec3param(kasp, iter, optout, salt); + if (ret != ISC_R_SUCCESS) { + cfg_obj_log(obj, logctx, ISC_LOG_ERROR, + "dnssec-policy: bad nsec3 salt %s", salt); + } + return (ret); } isc_result_t @@ -282,7 +317,7 @@ cfg_kasp_fromconfig(const cfg_obj_t *config, isc_mem_t *mctx, isc_log_t *logctx, dns_kasp_setnsec3(kasp, false); } else { dns_kasp_setnsec3(kasp, true); - result = cfg_nsec3param_fromconfig(nsec3, kasp); + result = cfg_nsec3param_fromconfig(nsec3, kasp, logctx); if (result != ISC_R_SUCCESS) { goto cleanup; }