diff --git a/CHANGES b/CHANGES index 00c888c6db..e6ab1262d0 100644 --- a/CHANGES +++ b/CHANGES @@ -1,3 +1,6 @@ +3387. [func] Support for a DS digest can be disabled at + runtime with disable-ds-digests. [RT #21581] + 3386. [bug] Address locking violation when generating new NSEC / NSEC3 chains. [RT #31224] diff --git a/bin/named/named.conf.docbook b/bin/named/named.conf.docbook index 338d805993..1063ddf2d5 100644 --- a/bin/named/named.conf.docbook +++ b/bin/named/named.conf.docbook @@ -284,6 +284,7 @@ options { max-udp-size integer; root-delegation-only exclude { quoted_string; ... } ; disable-algorithms string { string; ... }; + disable-ds-digests string { string; ... }; dnssec-enable boolean; dnssec-validation boolean; dnssec-lookaside ( auto | no | domain trust-anchor domain ); @@ -472,6 +473,7 @@ view string optional_class max-udp-size integer; root-delegation-only exclude { quoted_string; ... } ; disable-algorithms string { string; ... }; + disable-ds-digests string { string; ... }; dnssec-enable boolean; dnssec-validation boolean; dnssec-lookaside ( auto | no | domain trust-anchor domain ); diff --git a/bin/named/server.c b/bin/named/server.c index 27e676489e..5264042a4c 100644 --- a/bin/named/server.c +++ b/bin/named/server.c @@ -1216,6 +1216,48 @@ disable_algorithms(const cfg_obj_t *disabled, dns_resolver_t *resolver) { return (result); } +static isc_result_t +disable_ds_digests(const cfg_obj_t *disabled, dns_resolver_t *resolver) { + isc_result_t result; + const cfg_obj_t *digests; + const cfg_listelt_t *element; + const char *str; + dns_fixedname_t fixed; + dns_name_t *name; + isc_buffer_t b; + + dns_fixedname_init(&fixed); + name = dns_fixedname_name(&fixed); + str = cfg_obj_asstring(cfg_tuple_get(disabled, "name")); + isc_buffer_init(&b, str, strlen(str)); + isc_buffer_add(&b, strlen(str)); + CHECK(dns_name_fromtext(name, &b, dns_rootname, 0, NULL)); + + digests = cfg_tuple_get(disabled, "digests"); + for (element = cfg_list_first(digests); + element != NULL; + element = cfg_list_next(element)) + { + isc_textregion_t r; + dns_dsdigest_t digest; + + DE_CONST(cfg_obj_asstring(cfg_listelt_value(element)), r.base); + r.length = strlen(r.base); + + /* disable_ds_digests handles numeric values. */ + result = dns_dsdigest_fromtext(&digest, &r); + if (result != ISC_R_SUCCESS) { + cfg_obj_log(cfg_listelt_value(element), + ns_g_lctx, ISC_LOG_ERROR, + "invalid algorithm"); + CHECK(result); + } + CHECK(dns_resolver_disable_ds_digest(resolver, name, digest)); + } + cleanup: + return (result); +} + static isc_boolean_t on_disable_list(const cfg_obj_t *disablelist, dns_name_t *zonename) { const cfg_listelt_t *element; @@ -2275,6 +2317,20 @@ configure_view(dns_view_t *view, cfg_obj_t *config, cfg_obj_t *vconfig, view->resolver)); } + /* + * Set supported DS/DLV digest types. + */ + dns_resolver_reset_ds_digests(view->resolver); + disabled = NULL; + (void)ns_config_get(maps, "disable-ds-digests", &disabled); + if (disabled != NULL) { + for (element = cfg_list_first(disabled); + element != NULL; + element = cfg_list_next(element)) + CHECK(disable_ds_digests(cfg_listelt_value(element), + view->resolver)); + } + /* * A global or view "forwarders" option, if present, * creates an entry for "." in the forwarding table. diff --git a/bin/tests/system/conf.sh.in b/bin/tests/system/conf.sh.in index d67470800a..c9a2fb2606 100644 --- a/bin/tests/system/conf.sh.in +++ b/bin/tests/system/conf.sh.in @@ -56,8 +56,8 @@ VERIFY=$TOP/bin/dnssec/dnssec-verify # v6synth SUBDIRS="acl allow_query addzone autosign builtin cacheclean checkconf @CHECKDS@ checknames checkzone database dlv dlvauto dlz dlzexternal - dname dns64 dnssec ecdsa forward glue gost ixfr inline limits - logfileconfig lwresd masterfile masterformat metadata notify + dname dns64 dnssec dsdigest ecdsa forward glue gost ixfr inline + limits logfileconfig lwresd masterfile masterformat metadata notify nsupdate pending pkcs11 redirect resolver rndc rpz rrsetorder rsabigexponent sortlist smartsign staticstub statistics stub tkey tsig tsiggss unknown upforwd verify views xfer xferquota diff --git a/configure.in b/configure.in index 2b857bd4dc..69a84f14d0 100644 --- a/configure.in +++ b/configure.in @@ -3595,6 +3595,7 @@ AC_CONFIG_FILES([ bin/tests/system/dlz/prereq.sh bin/tests/system/dlzexternal/Makefile bin/tests/system/dlzexternal/ns1/named.conf + bin/tests/system/dsdigest/prereq.sh bin/tests/system/ecdsa/prereq.sh bin/tests/system/filter-aaaa/Makefile bin/tests/system/gost/prereq.sh diff --git a/doc/arm/Bv9ARM-book.xml b/doc/arm/Bv9ARM-book.xml index c3eb51aea8..eae919fed5 100644 --- a/doc/arm/Bv9ARM-book.xml +++ b/doc/arm/Bv9ARM-book.xml @@ -5340,6 +5340,8 @@ badresp:1,adberr:0,findfail:0,valfail:0] querylog yes_or_no ; disable-algorithms domain { algorithm; algorithm; }; + disable-ds-digests domain { digest_type; + digest_type; }; acache-enable yes_or_no ; acache-cleaning-interval number; max-acache-size size_spec ; @@ -5871,8 +5873,33 @@ options { specified name. Multiple disable-algorithms statements are allowed. - Only the most specific will be applied. + Only the best match disable-algorithms + clause will be used to determine which algorithms are used. + + If all supported algorithms are disabled, the zones covered + by the disable-algorithms will be treated + as insecure. + + + + + + disable-ds-digests + + + Disable the specified DS/DLV digest types at and below the + specified name. + Multiple disable-ds-digests + statements are allowed. + Only the best match disable-ds-digests + clause will be used to determine which digest types are used. + + + If all supported digest types are disabled, the zones covered + by the disable-ds-digests will be treated + as insecure. + diff --git a/doc/misc/options b/doc/misc/options index 57641e7c11..e38357319a 100644 --- a/doc/misc/options +++ b/doc/misc/options @@ -101,6 +101,7 @@ options { dialup ; directory ; disable-algorithms { ; ... }; + disable-ds-digests { ; ... }; disable-empty-zone ; dns64 { break-dnssec ; diff --git a/lib/bind9/check.c b/lib/bind9/check.c index 9a14bfe86d..6c0407a6aa 100644 --- a/lib/bind9/check.c +++ b/lib/bind9/check.c @@ -286,12 +286,61 @@ disabled_algorithms(const cfg_obj_t *disabled, isc_log_t *logctx) { r.length = strlen(r.base); tresult = dns_secalg_fromtext(&alg, &r); - if (tresult != ISC_R_SUCCESS) { + if (tresult != ISC_R_SUCCESS) { cfg_obj_log(cfg_listelt_value(element), logctx, ISC_LOG_ERROR, "invalid algorithm '%s'", r.base); result = tresult; - } + } + } + return (result); +} + +static isc_result_t +disabled_ds_digests(const cfg_obj_t *disabled, isc_log_t *logctx) { + isc_result_t result = ISC_R_SUCCESS; + isc_result_t tresult; + const cfg_listelt_t *element; + const char *str; + isc_buffer_t b; + dns_fixedname_t fixed; + dns_name_t *name; + const cfg_obj_t *obj; + + dns_fixedname_init(&fixed); + name = dns_fixedname_name(&fixed); + obj = cfg_tuple_get(disabled, "name"); + str = cfg_obj_asstring(obj); + isc_buffer_init(&b, str, strlen(str)); + isc_buffer_add(&b, strlen(str)); + tresult = dns_name_fromtext(name, &b, dns_rootname, 0, NULL); + if (tresult != ISC_R_SUCCESS) { + cfg_obj_log(obj, logctx, ISC_LOG_ERROR, + "bad domain name '%s'", str); + result = tresult; + } + + obj = cfg_tuple_get(disabled, "digests"); + + for (element = cfg_list_first(obj); + element != NULL; + element = cfg_list_next(element)) + { + isc_textregion_t r; + dns_dsdigest_t digest; + isc_result_t tresult; + + DE_CONST(cfg_obj_asstring(cfg_listelt_value(element)), r.base); + r.length = strlen(r.base); + + /* works with a numeric argument too */ + tresult = dns_dsdigest_fromtext(&digest, &r); + if (tresult != ISC_R_SUCCESS) { + cfg_obj_log(cfg_listelt_value(element), logctx, + ISC_LOG_ERROR, "invalid digest type '%s'", + r.base); + result = tresult; + } } return (result); } @@ -869,6 +918,23 @@ check_options(const cfg_obj_t *options, isc_log_t *logctx, isc_mem_t *mctx, } } + /* + * Set supported DS/DLV digest types. + */ + obj = NULL; + (void)cfg_map_get(options, "disable-ds-digests", &obj); + if (obj != NULL) { + for (element = cfg_list_first(obj); + element != NULL; + element = cfg_list_next(element)) + { + obj = cfg_listelt_value(element); + tresult = disabled_ds_digests(obj, logctx); + if (tresult != ISC_R_SUCCESS) + result = tresult; + } + } + dns_fixedname_init(&fixed); name = dns_fixedname_name(&fixed); diff --git a/lib/dns/ds.c b/lib/dns/ds.c index e72ecbb6cc..8eb31d3073 100644 --- a/lib/dns/ds.c +++ b/lib/dns/ds.c @@ -67,7 +67,7 @@ dns_ds_buildrdata(dns_name_t *owner, dns_rdata_t *key, REQUIRE(key != NULL); REQUIRE(key->type == dns_rdatatype_dnskey); - if (!dns_ds_digest_supported(digest_type)) + if (!dst_ds_digest_supported(digest_type)) return (ISC_R_NOTIMPLEMENTED); dns_fixedname_init(&fname); @@ -167,17 +167,3 @@ dns_ds_buildrdata(dns_name_t *owner, dns_rdata_t *key, return (dns_rdata_fromstruct(rdata, key->rdclass, dns_rdatatype_ds, &ds, &b)); } - -isc_boolean_t -dns_ds_digest_supported(unsigned int digest_type) { -#ifdef HAVE_OPENSSL_GOST - return (ISC_TF(digest_type == DNS_DSDIGEST_SHA1 || - digest_type == DNS_DSDIGEST_SHA256 || - digest_type == DNS_DSDIGEST_GOST || - digest_type == DNS_DSDIGEST_SHA384)); -#else - return (ISC_TF(digest_type == DNS_DSDIGEST_SHA1 || - digest_type == DNS_DSDIGEST_SHA256 || - digest_type == DNS_DSDIGEST_SHA384)); -#endif -} diff --git a/lib/dns/dst_api.c b/lib/dns/dst_api.c index 12822bedf2..481601c6e2 100644 --- a/lib/dns/dst_api.c +++ b/lib/dns/dst_api.c @@ -277,6 +277,20 @@ dst_algorithm_supported(unsigned int alg) { return (ISC_TRUE); } +isc_boolean_t +dst_ds_digest_supported(unsigned int digest_type) { +#ifdef HAVE_OPENSSL_GOST + return (ISC_TF(digest_type == DNS_DSDIGEST_SHA1 || + digest_type == DNS_DSDIGEST_SHA256 || + digest_type == DNS_DSDIGEST_GOST || + digest_type == DNS_DSDIGEST_SHA384)); +#else + return (ISC_TF(digest_type == DNS_DSDIGEST_SHA1 || + digest_type == DNS_DSDIGEST_SHA256 || + digest_type == DNS_DSDIGEST_SHA384)); +#endif +} + isc_result_t dst_context_create(dst_key_t *key, isc_mem_t *mctx, dst_context_t **dctxp) { dst_context_t *dctx; diff --git a/lib/dns/include/dns/ds.h b/lib/dns/include/dns/ds.h index 03ab0ed09d..41cd2235bf 100644 --- a/lib/dns/include/dns/ds.h +++ b/lib/dns/include/dns/ds.h @@ -58,12 +58,6 @@ dns_ds_buildrdata(dns_name_t *owner, dns_rdata_t *key, * to 'buffer'. */ -isc_boolean_t -dns_ds_digest_supported(unsigned int digest_type); -/*%< - * Is this digest algorithm supported by dns_ds_buildrdata()? - */ - ISC_LANG_ENDDECLS #endif /* DNS_DS_H */ diff --git a/lib/dns/include/dns/resolver.h b/lib/dns/include/dns/resolver.h index 095269ea2d..b96724fb75 100644 --- a/lib/dns/include/dns/resolver.h +++ b/lib/dns/include/dns/resolver.h @@ -456,11 +456,17 @@ dns_resolver_reset_algorithms(dns_resolver_t *resolver); * Clear the disabled DNSSEC algorithms. */ +void +dns_resolver_reset_ds_digests(dns_resolver_t *resolver); +/*%< + * Clear the disabled DS/DLV digest types. + */ + isc_result_t dns_resolver_disable_algorithm(dns_resolver_t *resolver, dns_name_t *name, unsigned int alg); /*%< - * Mark the give DNSSEC algorithm as disabled and below 'name'. + * Mark the given DNSSEC algorithm as disabled and below 'name'. * Valid algorithms are less than 256. * * Returns: @@ -469,20 +475,37 @@ dns_resolver_disable_algorithm(dns_resolver_t *resolver, dns_name_t *name, *\li #ISC_R_NOMEMORY */ +isc_result_t +dns_resolver_disable_ds_digest(dns_resolver_t *resolver, dns_name_t *name, + unsigned int digest_type); +/*%< + * Mark the given DS/DLV digest type as disabled and below 'name'. + * Valid types are less than 256. + * + * Returns: + *\li #ISC_R_SUCCESS + *\li #ISC_R_RANGE + *\li #ISC_R_NOMEMORY + */ + isc_boolean_t dns_resolver_algorithm_supported(dns_resolver_t *resolver, dns_name_t *name, unsigned int alg); /*%< * Check if the given algorithm is supported by this resolver. - * This checks if the algorithm has been disabled via - * dns_resolver_disable_algorithm() then the underlying - * crypto libraries if not specifically disabled. + * This checks whether the algorithm has been disabled via + * dns_resolver_disable_algorithm(), then checks the underlying + * crypto libraries if it was not specifically disabled. */ isc_boolean_t -dns_resolver_digest_supported(dns_resolver_t *resolver, unsigned int digest_type); +dns_resolver_ds_digest_supported(dns_resolver_t *resolver, dns_name_t *name, + unsigned int digest_type); /*%< - * Is this digest type supported. + * Check if the given digest type is supported by this resolver. + * This checks whether the digest type has been disabled via + * dns_resolver_disable_ds_digest(), then checks the underlying + * crypto libraries if it was not specifically disabled. */ void diff --git a/lib/dns/include/dns/types.h b/lib/dns/include/dns/types.h index 62e79998f7..a163e3fa23 100644 --- a/lib/dns/include/dns/types.h +++ b/lib/dns/include/dns/types.h @@ -74,6 +74,7 @@ typedef struct dns_dns64 dns_dns64_t; typedef ISC_LIST(dns_dns64_t) dns_dns64list_t; typedef struct dns_dnsseckey dns_dnsseckey_t; typedef ISC_LIST(dns_dnsseckey_t) dns_dnsseckeylist_t; +typedef isc_uint8_t dns_dsdigest_t; typedef struct dns_dumpctx dns_dumpctx_t; typedef struct dns_fetch dns_fetch_t; typedef struct dns_fixedname dns_fixedname_t; diff --git a/lib/dns/include/dst/dst.h b/lib/dns/include/dst/dst.h index 66501df4fc..d59ff7c32a 100644 --- a/lib/dns/include/dst/dst.h +++ b/lib/dns/include/dst/dst.h @@ -28,6 +28,8 @@ #include #include #include +#include +#include #include @@ -167,6 +169,16 @@ dst_algorithm_supported(unsigned int alg); * \li ISC_FALSE */ +isc_boolean_t +dst_ds_digest_supported(unsigned int digest_type); +/*%< + * Checks that a given digest algorithm is supported by DST. + * + * Returns: + * \li ISC_TRUE + * \li ISC_FALSE + */ + isc_result_t dst_context_create(dst_key_t *key, isc_mem_t *mctx, dst_context_t **dctxp); /*%< diff --git a/lib/dns/rcode.c b/lib/dns/rcode.c index 0b7fe8c280..b05100615c 100644 --- a/lib/dns/rcode.c +++ b/lib/dns/rcode.c @@ -32,6 +32,8 @@ #include #include +#include +#include #include #include #include @@ -130,6 +132,15 @@ { 1, "SHA-1", 0 }, \ { 0, NULL, 0 } +/* RFC3658, RFC4509, RFC5933, RFC6605 */ + +#define DSDIGESTNAMES \ + { DNS_DSDIGEST_SHA1, "SHA-1", 0 }, \ + { DNS_DSDIGEST_SHA256, "SHA-256", 0 }, \ + { DNS_DSDIGEST_GOST, "GOST", 0 }, \ + { DNS_DSDIGEST_SHA384, "SHA-384", 0 }, \ + { 0, NULL, 0} + struct tbl { unsigned int value; const char *name; @@ -142,6 +153,7 @@ static struct tbl certs[] = { CERTNAMES }; static struct tbl secalgs[] = { SECALGNAMES }; static struct tbl secprotos[] = { SECPROTONAMES }; static struct tbl hashalgs[] = { HASHALGNAMES }; +static struct tbl dsdigests[] = { DSDIGESTNAMES }; static struct keyflag { const char *name; @@ -404,6 +416,34 @@ dns_keyflags_fromtext(dns_keyflags_t *flagsp, isc_textregion_t *source) return (ISC_R_SUCCESS); } +isc_result_t +dns_dsdigest_fromtext(dns_dsdigest_t *dsdigestp, isc_textregion_t *source) { + unsigned int value; + RETERR(dns_mnemonic_fromtext(&value, source, dsdigests, 0xff)); + *dsdigestp = value; + return (ISC_R_SUCCESS); +} + +isc_result_t +dns_dsdigest_totext(dns_dsdigest_t dsdigest, isc_buffer_t *target) { + return (dns_mnemonic_totext(dsdigest, target, dsdigests)); +} + +void +dns_dsdigest_format(dns_dsdigest_t typ, char *cp, unsigned int size) { + isc_buffer_t b; + isc_region_t r; + isc_result_t result; + + REQUIRE(cp != NULL && size > 0); + isc_buffer_init(&b, cp, size - 1); + result = dns_dsdigest_totext(typ, &b); + isc_buffer_usedregion(&b, &r); + r.base[r.length] = 0; + if (result != ISC_R_SUCCESS) + r.base[0] = 0; +} + /* * This uses lots of hard coded values, but how often do we actually * add classes? diff --git a/lib/dns/rdata.c b/lib/dns/rdata.c index b6e715eff0..6e7c8a229e 100644 --- a/lib/dns/rdata.c +++ b/lib/dns/rdata.c @@ -35,6 +35,7 @@ #include #include #include +#include #include #include #include diff --git a/lib/dns/rdata/generic/dlv_32769.c b/lib/dns/rdata/generic/dlv_32769.c index 474e9cb3bb..5797012591 100644 --- a/lib/dns/rdata/generic/dlv_32769.c +++ b/lib/dns/rdata/generic/dlv_32769.c @@ -16,7 +16,7 @@ /* $Id$ */ -/* draft-ietf-dnsext-delegation-signer-05.txt */ +/* RFC3658 */ #ifndef RDATA_GENERIC_DLV_32769_C #define RDATA_GENERIC_DLV_32769_C @@ -28,7 +28,6 @@ #include - static inline isc_result_t fromtext_dlv(ARGS_FROMTEXT) { isc_token_t token; diff --git a/lib/dns/rdata/generic/ds_43.c b/lib/dns/rdata/generic/ds_43.c index dd47c8d5e8..bbcadc43f4 100644 --- a/lib/dns/rdata/generic/ds_43.c +++ b/lib/dns/rdata/generic/ds_43.c @@ -17,7 +17,7 @@ /* $Id$ */ -/* draft-ietf-dnsext-delegation-signer-05.txt */ +/* RFC3658 */ #ifndef RDATA_GENERIC_DS_43_C #define RDATA_GENERIC_DS_43_C @@ -64,12 +64,10 @@ fromtext_ds(ARGS_FROMTEXT) { /* * Digest type. */ - RETERR(isc_lex_getmastertoken(lexer, &token, isc_tokentype_number, + RETERR(isc_lex_getmastertoken(lexer, &token, isc_tokentype_string, ISC_FALSE)); - if (token.value.as_ulong > 0xffU) - RETTOK(ISC_R_RANGE); - RETERR(uint8_tobuffer(token.value.as_ulong, target)); - c = (unsigned char) token.value.as_ulong; + RETTOK(dns_dsdigest_fromtext(&c, &token.value.as_textregion)); + RETERR(mem_tobuffer(target, &c, 1)); /* * Digest. diff --git a/lib/dns/resolver.c b/lib/dns/resolver.c index 46af973a84..0659c6ca62 100644 --- a/lib/dns/resolver.c +++ b/lib/dns/resolver.c @@ -404,6 +404,7 @@ struct dns_resolver { isc_rwlock_t alglock; #endif dns_rbt_t * algorithms; + dns_rbt_t * digests; #if USE_MBSLOCK isc_rwlock_t mbslock; #endif @@ -7352,6 +7353,7 @@ destroy(dns_resolver_t *res) { isc_mem_put(res->mctx, a, sizeof(*a)); } dns_resolver_reset_algorithms(res); + dns_resolver_reset_ds_digests(res); destroy_badcache(res); dns_resolver_resetmustbesecure(res); #if USE_ALGLOCK @@ -7478,6 +7480,7 @@ dns_resolver_create(dns_view_t *view, ISC_LIST_INIT(res->alternates); res->udpsize = RECV_BUFFER_SIZE; res->algorithms = NULL; + res->digests = NULL; res->badcache = NULL; res->badcount = 0; res->badhash = 0; @@ -8667,11 +8670,118 @@ dns_resolver_algorithm_supported(dns_resolver_t *resolver, dns_name_t *name, return (dst_algorithm_supported(alg)); } -isc_boolean_t -dns_resolver_digest_supported(dns_resolver_t *resolver, unsigned int digest) { +static void +free_digest(void *node, void *arg) { + unsigned char *digests = node; + isc_mem_t *mctx = arg; - UNUSED(resolver); - return (dns_ds_digest_supported(digest)); + isc_mem_put(mctx, digests, *digests); +} + +void +dns_resolver_reset_ds_digests(dns_resolver_t *resolver) { + + REQUIRE(VALID_RESOLVER(resolver)); + +#if USE_ALGLOCK + RWLOCK(&resolver->alglock, isc_rwlocktype_write); +#endif + if (resolver->digests != NULL) + dns_rbt_destroy(&resolver->digests); +#if USE_ALGLOCK + RWUNLOCK(&resolver->alglock, isc_rwlocktype_write); +#endif +} + +isc_result_t +dns_resolver_disable_ds_digest(dns_resolver_t *resolver, dns_name_t *name, + unsigned int digest_type) +{ + unsigned int len, mask; + unsigned char *new; + unsigned char *digests; + isc_result_t result; + dns_rbtnode_t *node = NULL; + + REQUIRE(VALID_RESOLVER(resolver)); + if (digest_type > 255) + return (ISC_R_RANGE); + +#if USE_ALGLOCK + RWLOCK(&resolver->alglock, isc_rwlocktype_write); +#endif + if (resolver->digests == NULL) { + result = dns_rbt_create(resolver->mctx, free_digest, + resolver->mctx, &resolver->digests); + if (result != ISC_R_SUCCESS) + goto cleanup; + } + + len = digest_type/8 + 2; + mask = 1 << (digest_type%8); + + result = dns_rbt_addnode(resolver->digests, name, &node); + + if (result == ISC_R_SUCCESS || result == ISC_R_EXISTS) { + digests = node->data; + if (digests == NULL || len > *digests) { + new = isc_mem_get(resolver->mctx, len); + if (new == NULL) { + result = ISC_R_NOMEMORY; + goto cleanup; + } + memset(new, 0, len); + if (digests != NULL) + memcpy(new, digests, *digests); + new[len-1] |= mask; + *new = len; + node->data = new; + if (digests != NULL) + isc_mem_put(resolver->mctx, digests, + *digests); + } else + digests[len-1] |= mask; + } + result = ISC_R_SUCCESS; + cleanup: +#if USE_ALGLOCK + RWUNLOCK(&resolver->alglock, isc_rwlocktype_write); +#endif + return (result); +} + +isc_boolean_t +dns_resolver_ds_digest_supported(dns_resolver_t *resolver, dns_name_t *name, + unsigned int digest_type) +{ + unsigned int len, mask; + unsigned char *digests; + void *data = NULL; + isc_result_t result; + isc_boolean_t found = ISC_FALSE; + + REQUIRE(VALID_RESOLVER(resolver)); + +#if USE_ALGLOCK + RWLOCK(&resolver->alglock, isc_rwlocktype_read); +#endif + if (resolver->digests == NULL) + goto unlock; + result = dns_rbt_findname(resolver->digests, name, 0, NULL, &data); + if (result == ISC_R_SUCCESS || result == DNS_R_PARTIALMATCH) { + len = digest_type/8 + 2; + mask = 1 << (digest_type%8); + digests = data; + if (len <= *digests && (digests[len-1] & mask) != 0) + found = ISC_TRUE; + } + unlock: +#if USE_ALGLOCK + RWUNLOCK(&resolver->alglock, isc_rwlocktype_read); +#endif + if (found) + return (ISC_FALSE); + return (dst_ds_digest_supported(digest_type)); } void diff --git a/lib/dns/validator.c b/lib/dns/validator.c index 56639241b7..ebbda29517 100644 --- a/lib/dns/validator.c +++ b/lib/dns/validator.c @@ -255,17 +255,10 @@ dlv_algorithm_supported(dns_validator_t *val) { dlv.algorithm)) continue; -#ifdef HAVE_OPENSSL_GOST - if (dlv.digest_type != DNS_DSDIGEST_SHA256 && - dlv.digest_type != DNS_DSDIGEST_SHA1 && - dlv.digest_type != DNS_DSDIGEST_GOST) + if (!dns_resolver_ds_digest_supported(val->view->resolver, + val->event->name, + dlv.digest_type)) continue; -#else - if (dlv.digest_type != DNS_DSDIGEST_SHA256 && - dlv.digest_type != DNS_DSDIGEST_SHA1) - continue; -#endif - return (ISC_TRUE); } @@ -2275,11 +2268,12 @@ dlv_validatezonekey(dns_validator_t *val) { result = dns_rdata_tostruct(&dlvrdata, &dlv, NULL); RUNTIME_CHECK(result == ISC_R_SUCCESS); - if (!dns_resolver_digest_supported(val->view->resolver, - dlv.digest_type)) + if (digest_types[dlv.digest_type] == 0) continue; - if (digest_types[dlv.digest_type] == 0) + if (!dns_resolver_ds_digest_supported(val->view->resolver, + val->event->name, + dlv.digest_type)) continue; if (!dns_resolver_algorithm_supported(val->view->resolver, @@ -2629,11 +2623,12 @@ validatezonekey(dns_validator_t *val) { result = dns_rdata_tostruct(&dsrdata, &ds, NULL); RUNTIME_CHECK(result == ISC_R_SUCCESS); - if (!dns_resolver_digest_supported(val->view->resolver, - ds.digest_type)) + if (digest_types[ds.digest_type] == 0) continue; - if (digest_types[ds.digest_type] == 0) + if (!dns_resolver_ds_digest_supported(val->view->resolver, + val->event->name, + ds.digest_type)) continue; if (!dns_resolver_algorithm_supported(val->view->resolver, @@ -3299,8 +3294,8 @@ check_ds(dns_validator_t *val, dns_name_t *name, dns_rdataset_t *rdataset) { result = dns_rdata_tostruct(&dsrdata, &ds, NULL); RUNTIME_CHECK(result == ISC_R_SUCCESS); - if (dns_resolver_digest_supported(val->view->resolver, - ds.digest_type) && + if (dns_resolver_ds_digest_supported(val->view->resolver, + name, ds.digest_type) && dns_resolver_algorithm_supported(val->view->resolver, name, ds.algorithm)) { dns_rdata_reset(&dsrdata); diff --git a/lib/dns/win32/libdns.def b/lib/dns/win32/libdns.def index 2a70292e96..4895e01202 100644 --- a/lib/dns/win32/libdns.def +++ b/lib/dns/win32/libdns.def @@ -231,7 +231,6 @@ dns_dnssec_verifymessage dns_dnsseckey_create dns_dnsseckey_destroy dns_ds_buildrdata -dns_ds_digest_supported dns_dumpctx_detach dns_fwdtable_add dns_fwdtable_create @@ -616,9 +615,11 @@ dns_resolver_createfetch2 dns_resolver_destroyfetch dns_resolver_detach dns_resolver_disable_algorithm +dns_resolver_disable_ds_digest dns_resolver_dispatchmgr dns_resolver_dispatchv4 dns_resolver_dispatchv6 +dns_resolver_ds_digest_supported dns_resolver_flushbadcache dns_resolver_freeze dns_resolver_getbadcache @@ -631,6 +632,7 @@ dns_resolver_nrunning dns_resolver_prime dns_resolver_printbadcache dns_resolver_reset_algorithms +dns_resolver_reset_ds_digests dns_resolver_resetmustbesecure dns_resolver_setclientsperquery dns_resolver_setlamettl @@ -980,6 +982,7 @@ dst_context_create dst_context_destroy dst_context_sign dst_context_verify +dst_ds_digest_supported dst_gssapi_acceptctx dst_gssapi_acquirecred dst_gssapi_initctx diff --git a/lib/isccfg/namedconf.c b/lib/isccfg/namedconf.c index 9bd1ab4c28..264d1aa347 100644 --- a/lib/isccfg/namedconf.c +++ b/lib/isccfg/namedconf.c @@ -1007,6 +1007,21 @@ static cfg_type_t cfg_type_disablealgorithm = { &cfg_rep_tuple, disablealgorithm_fields }; +static cfg_type_t cfg_type_dsdigestlist = { + "dsdigestlist", cfg_parse_bracketed_list, cfg_print_bracketed_list, + cfg_doc_bracketed_list, &cfg_rep_list, &cfg_type_astring }; + +static cfg_tuplefielddef_t disabledsdigest_fields[] = { + { "name", &cfg_type_astring, 0 }, + { "digests", &cfg_type_dsdigestlist, 0 }, + { NULL, NULL, 0 } +}; + +static cfg_type_t cfg_type_disabledsdigest = { + "disabledsdigest", cfg_parse_tuple, cfg_print_tuple, cfg_doc_tuple, + &cfg_rep_tuple, disabledsdigest_fields +}; + static cfg_tuplefielddef_t mustbesecure_fields[] = { { "name", &cfg_type_astring, 0 }, { "value", &cfg_type_boolean, 0 }, @@ -1337,6 +1352,8 @@ view_clauses[] = { { "deny-answer-aliases", &cfg_type_denyaliases, 0 }, { "disable-algorithms", &cfg_type_disablealgorithm, CFG_CLAUSEFLAG_MULTI }, + { "disable-ds-digests", &cfg_type_disabledsdigest, + CFG_CLAUSEFLAG_MULTI }, { "disable-empty-zone", &cfg_type_astring, CFG_CLAUSEFLAG_MULTI }, { "dns64", &cfg_type_dns64, CFG_CLAUSEFLAG_MULTI }, { "dns64-server", &cfg_type_astring, 0 },