diff --git a/CHANGES b/CHANGES index adda5fcfe3..3df60d23e0 100644 --- a/CHANGES +++ b/CHANGES @@ -1,3 +1,6 @@ +2145. [bug] Check DS/DLV digest lengths for known digests. + [RT #16622] + 2144. [cleanup] Suppress logging of SERVFAIL from forwarders. [RT #16619] diff --git a/lib/dns/rdata/generic/dlv_32769.c b/lib/dns/rdata/generic/dlv_32769.c index 0be365a80f..7a534ff528 100644 --- a/lib/dns/rdata/generic/dlv_32769.c +++ b/lib/dns/rdata/generic/dlv_32769.c @@ -14,7 +14,7 @@ * PERFORMANCE OF THIS SOFTWARE. */ -/* $Id: dlv_32769.c,v 1.3 2006/02/19 06:50:48 marka Exp $ */ +/* $Id: dlv_32769.c,v 1.4 2007/02/26 01:20:44 marka Exp $ */ /* draft-ietf-dnsext-delegation-signer-05.txt */ @@ -23,9 +23,17 @@ #define RRTYPE_DLV_ATTRIBUTES 0 +#include +#include + +#include + + static inline isc_result_t fromtext_dlv(ARGS_FROMTEXT) { isc_token_t token; + unsigned char c; + int length; REQUIRE(type == 32769); @@ -61,11 +69,17 @@ fromtext_dlv(ARGS_FROMTEXT) { if (token.value.as_ulong > 0xffU) RETTOK(ISC_R_RANGE); RETERR(uint8_tobuffer(token.value.as_ulong, target)); - type = (isc_uint16_t) token.value.as_ulong; + c = (unsigned char) token.value.as_ulong; /* * Digest. */ + if (c == DNS_DSDIGEST_SHA1) + length = ISC_SHA1_DIGESTLENGTH; + else if (c == DNS_DSDIGEST_SHA256) + length = ISC_SHA256_DIGESTLENGTH; + else + length = -1; return (isc_hex_tobuffer(lexer, target, -1)); } @@ -130,9 +144,27 @@ fromwire_dlv(ARGS_FROMWIRE) { UNUSED(options); isc_buffer_activeregion(source, &sr); - if (sr.length < 4) + + /* + * Check digest lengths if we know them. + */ + if (sr.length < 4 || + (sr.base[3] == DNS_DSDIGEST_SHA1 && + sr.length < 4 + ISC_SHA1_DIGESTLENGTH) || + (sr.base[3] == DNS_DSDIGEST_SHA256 && + sr.length < 4 + ISC_SHA256_DIGESTLENGTH)) return (ISC_R_UNEXPECTEDEND); + /* + * Only copy digest lengths if we know them. + * If there is extra data dns_rdata_fromwire() will + * detect that. + */ + if (sr.base[3] == DNS_DSDIGEST_SHA1) + sr.length = 4 + ISC_SHA1_DIGESTLENGTH; + else if (sr.base[3] == DNS_DSDIGEST_SHA256) + sr.length = 4 + ISC_SHA256_DIGESTLENGTH; + isc_buffer_forward(source, sr.length); return (mem_tobuffer(target, sr.base, sr.length)); } @@ -174,6 +206,14 @@ fromstruct_dlv(ARGS_FROMSTRUCT) { REQUIRE(source != NULL); REQUIRE(dlv->common.rdtype == type); REQUIRE(dlv->common.rdclass == rdclass); + switch (dlv->digest_type) { + case DNS_DSDIGEST_SHA1: + REQUIRE(dlv->length == ISC_SHA1_DIGESTLENGTH); + break; + case DNS_DSDIGEST_SHA256: + REQUIRE(dlv->length == ISC_SHA256_DIGESTLENGTH); + break; + } UNUSED(type); UNUSED(rdclass); diff --git a/lib/dns/rdata/generic/ds_43.c b/lib/dns/rdata/generic/ds_43.c index df8e3bafbc..b9bb763c75 100644 --- a/lib/dns/rdata/generic/ds_43.c +++ b/lib/dns/rdata/generic/ds_43.c @@ -15,7 +15,7 @@ * PERFORMANCE OF THIS SOFTWARE. */ -/* $Id: ds_43.c,v 1.9 2005/09/06 07:29:31 marka Exp $ */ +/* $Id: ds_43.c,v 1.10 2007/02/26 01:20:44 marka Exp $ */ /* draft-ietf-dnsext-delegation-signer-05.txt */ @@ -25,10 +25,16 @@ #define RRTYPE_DS_ATTRIBUTES \ (DNS_RDATATYPEATTR_DNSSEC|DNS_RDATATYPEATTR_ATPARENT) +#include +#include + +#include + static inline isc_result_t fromtext_ds(ARGS_FROMTEXT) { isc_token_t token; unsigned char c; + int length; REQUIRE(type == 43); @@ -63,12 +69,18 @@ fromtext_ds(ARGS_FROMTEXT) { if (token.value.as_ulong > 0xffU) RETTOK(ISC_R_RANGE); RETERR(uint8_tobuffer(token.value.as_ulong, target)); - type = (isc_uint16_t) token.value.as_ulong; + c = (unsigned char) token.value.as_ulong; /* * Digest. */ - return (isc_hex_tobuffer(lexer, target, -1)); + if (c == DNS_DSDIGEST_SHA1) + length = ISC_SHA1_DIGESTLENGTH; + else if (c == DNS_DSDIGEST_SHA256) + length = ISC_SHA256_DIGESTLENGTH; + else + length = -1; + return (isc_hex_tobuffer(lexer, target, length)); } static inline isc_result_t @@ -132,9 +144,27 @@ fromwire_ds(ARGS_FROMWIRE) { UNUSED(options); isc_buffer_activeregion(source, &sr); - if (sr.length < 4) + + /* + * Check digest lengths if we know them. + */ + if (sr.length < 4 || + (sr.base[3] == DNS_DSDIGEST_SHA1 && + sr.length < 4 + ISC_SHA1_DIGESTLENGTH) || + (sr.base[3] == DNS_DSDIGEST_SHA256 && + sr.length < 4 + ISC_SHA256_DIGESTLENGTH)) return (ISC_R_UNEXPECTEDEND); + /* + * Only copy digest lengths if we know them. + * If there is extra data dns_rdata_fromwire() will + * detect that. + */ + if (sr.base[3] == DNS_DSDIGEST_SHA1) + sr.length = 4 + ISC_SHA1_DIGESTLENGTH; + else if (sr.base[3] == DNS_DSDIGEST_SHA256) + sr.length = 4 + ISC_SHA256_DIGESTLENGTH; + isc_buffer_forward(source, sr.length); return (mem_tobuffer(target, sr.base, sr.length)); } @@ -176,6 +206,14 @@ fromstruct_ds(ARGS_FROMSTRUCT) { REQUIRE(source != NULL); REQUIRE(ds->common.rdtype == type); REQUIRE(ds->common.rdclass == rdclass); + switch (ds->digest_type) { + case DNS_DSDIGEST_SHA1: + REQUIRE(ds->length == ISC_SHA1_DIGESTLENGTH); + break; + case DNS_DSDIGEST_SHA256: + REQUIRE(ds->length == ISC_SHA256_DIGESTLENGTH); + break; + } UNUSED(type); UNUSED(rdclass); diff --git a/lib/dns/validator.c b/lib/dns/validator.c index e3c2f2b59a..ac2a6f0b94 100644 --- a/lib/dns/validator.c +++ b/lib/dns/validator.c @@ -15,7 +15,7 @@ * PERFORMANCE OF THIS SOFTWARE. */ -/* $Id: validator.c,v 1.149 2007/01/08 02:45:04 marka Exp $ */ +/* $Id: validator.c,v 1.150 2007/02/26 01:20:43 marka Exp $ */ #include @@ -24,6 +24,7 @@ #include #include #include +#include #include #include @@ -1502,7 +1503,8 @@ dlv_validatezonekey(dns_validator_t *val) { dlv.algorithm)) continue; - if (dlv.digest_type == DNS_DSDIGEST_SHA256) { + if (dlv.digest_type == DNS_DSDIGEST_SHA256 && + dlv.length == ISC_SHA256_DIGESTLENGTH) { digest_type = DNS_DSDIGEST_SHA256; break; } @@ -1835,7 +1837,8 @@ validatezonekey(dns_validator_t *val) { ds.algorithm)) continue; - if (ds.digest_type == DNS_DSDIGEST_SHA256) { + if (ds.digest_type == DNS_DSDIGEST_SHA256 && + ds.length == ISC_SHA256_DIGESTLENGTH) { digest_type = DNS_DSDIGEST_SHA256; break; }