From: Evan Hunt Date: Tue, 27 Jun 2017 18:40:31 +0000 (-0700) Subject: [v9_10] address TSIG bypass/forgery vulnerabilities X-Git-Tag: v9.10.6b1~6 X-Git-Url: http://git.ipfire.org/gitweb/?a=commitdiff_plain;h=88dc9d367d37b6eacfbaaef26c0da6d5ee4c29d4;p=thirdparty%2Fbind9.git [v9_10] address TSIG bypass/forgery vulnerabilities 4643. [security] An error in TSIG handling could permit unauthorized zone transfers or zone updates. (CVE-2017-3142) (CVE-2017-3143) [RT #45383] (cherry picked from commit 581c1526ab0f74a177980da9ff0514f795ed8669) (cherry picked from commit a03f4b1ea4f1a4a70963fbeb606841c217f9e5f3) --- diff --git a/CHANGES b/CHANGES index 13cade8950b..96b29b95ad8 100644 --- a/CHANGES +++ b/CHANGES @@ -1,5 +1,9 @@ --- 9.10.6b1 released --- +4643. [security] An error in TSIG handling could permit unauthorized + zone transfers or zone updates. (CVE-2017-3142) + (CVE-2017-3143) [RT #45383] + 4642. [cleanup] Add more logging of RFC 5011 events affecting the status of managed keys: newly observed keys, deletion of revoked keys, etc. [RT #45354] diff --git a/README b/README index e0bec15bb8b..af0c5173030 100644 --- a/README +++ b/README @@ -263,8 +263,14 @@ CVE-2017-3137, and CVE-2017-3138. BIND 9.10.6 -BIND 9.10.6 is a maintenance release, and addresses the security flaws -disclosed in CVE-2017-3140 and CVE-2017-3141. +<<<<<<< HEAD BIND 9.10.6 is a maintenance release, and addresses the +security flaws disclosed in CVE-2017-3140 and CVE-2017-3141. ======= BIND +9.11.2 is a maintenance release, and addresses the security flaws +disclosed in CVE-2017-3140, CVE-2017-3141, CVE-2017-3142 and +CVE-2017-3143. It also addresses several bugs related to the use of an +LMDB database to store data related to zones added via rndc addzone or +catalog zones. >>>>>>> a03f4b1... [v9_11] address TSIG bypass/forgery +vulnerabilities Building BIND diff --git a/README.md b/README.md index c8b567c7750..c95302dd235 100644 --- a/README.md +++ b/README.md @@ -277,8 +277,15 @@ CVE-2017-3137, and CVE-2017-3138. #### BIND 9.10.6 +<<<<<<< HEAD BIND 9.10.6 is a maintenance release, and addresses the security flaws disclosed in CVE-2017-3140 and CVE-2017-3141. +======= +BIND 9.11.2 is a maintenance release, and addresses the security flaws +disclosed in CVE-2017-3140, CVE-2017-3141, CVE-2017-3142 and CVE-2017-3143. +It also addresses several bugs related to the use of an LMDB database to +store data related to zones added via `rndc addzone` or catalog zones. +>>>>>>> a03f4b1... [v9_11] address TSIG bypass/forgery vulnerabilities ### Building BIND diff --git a/doc/arm/notes.xml b/doc/arm/notes.xml index bd1f603341a..3dd2ea6312e 100644 --- a/doc/arm/notes.xml +++ b/doc/arm/notes.xml @@ -69,6 +69,13 @@
Security Fixes + + + An error in TSIG handling could permit unauthorized zone + transfers or zone updates. These flaws are disclosed in + CVE-2017-3142 and CVE-2017-3143. [RT #45383] + + The BIND installer on Windows used an unquoted service path, diff --git a/lib/dns/dnssec.c b/lib/dns/dnssec.c index dae1cd7c669..cf6b206af48 100644 --- a/lib/dns/dnssec.c +++ b/lib/dns/dnssec.c @@ -980,6 +980,8 @@ dns_dnssec_verifymessage(isc_buffer_t *source, dns_message_t *msg, mctx = msg->mctx; msg->verify_attempted = 1; + msg->verified_sig = 0; + msg->sig0status = dns_tsigerror_badsig; if (is_response(msg)) { if (msg->query.base == NULL) @@ -1075,6 +1077,7 @@ dns_dnssec_verifymessage(isc_buffer_t *source, dns_message_t *msg, } msg->verified_sig = 1; + msg->sig0status = dns_rcode_noerror; dst_context_destroy(&ctx); dns_rdata_freestruct(&sig); diff --git a/lib/dns/message.c b/lib/dns/message.c index 3945f67523c..0933889549b 100644 --- a/lib/dns/message.c +++ b/lib/dns/message.c @@ -3068,12 +3068,19 @@ dns_message_signer(dns_message_t *msg, dns_name_t *signer) { result = dns_rdata_tostruct(&rdata, &tsig, NULL); INSIST(result == ISC_R_SUCCESS); - if (msg->tsigstatus != dns_rcode_noerror) + if (msg->verified_sig && + msg->tsigstatus == dns_rcode_noerror && + tsig.error == dns_rcode_noerror) + { + result = ISC_R_SUCCESS; + } else if ((!msg->verified_sig) || + (msg->tsigstatus != dns_rcode_noerror)) + { result = DNS_R_TSIGVERIFYFAILURE; - else if (tsig.error != dns_rcode_noerror) + } else { + INSIST(tsig.error != dns_rcode_noerror); result = DNS_R_TSIGERRORSET; - else - result = ISC_R_SUCCESS; + } dns_rdata_freestruct(&tsig); if (msg->tsigkey == NULL) { diff --git a/lib/dns/tsig.c b/lib/dns/tsig.c index bbbfc112132..49967540fdb 100644 --- a/lib/dns/tsig.c +++ b/lib/dns/tsig.c @@ -979,9 +979,10 @@ dns_tsig_sign(dns_message_t *msg) { return (ret); /* - * If this is a response, digest the query signature. + * If this is a response and the query's signature + * validated, digest the query signature. */ - if (response) { + if (response && (tsig.error == dns_rcode_noerror)) { dns_rdata_t querytsigrdata = DNS_RDATA_INIT; ret = dns_rdataset_first(msg->querytsig); @@ -1218,6 +1219,8 @@ dns_tsig_verify(isc_buffer_t *source, dns_message_t *msg, REQUIRE(tsigkey == NULL || VALID_TSIG_KEY(tsigkey)); msg->verify_attempted = 1; + msg->verified_sig = 0; + msg->tsigstatus = dns_tsigerror_badsig; if (msg->tcp_continuation) { if (tsigkey == NULL || msg->querytsig == NULL) @@ -1341,27 +1344,31 @@ dns_tsig_verify(isc_buffer_t *source, dns_message_t *msg, #endif alg == DST_ALG_HMACSHA1 || alg == DST_ALG_HMACSHA224 || alg == DST_ALG_HMACSHA256 || - alg == DST_ALG_HMACSHA384 || alg == DST_ALG_HMACSHA512) { + alg == DST_ALG_HMACSHA384 || alg == DST_ALG_HMACSHA512) + { isc_uint16_t digestbits = dst_key_getbits(key); if (tsig.siglen > siglen) { tsig_log(msg->tsigkey, 2, "signature length too big"); return (DNS_R_FORMERR); } if (tsig.siglen > 0 && - (tsig.siglen < 10 || tsig.siglen < ((siglen + 1) / 2))) { + (tsig.siglen < 10 || tsig.siglen < ((siglen + 1) / 2))) + { tsig_log(msg->tsigkey, 2, "signature length below minimum"); return (DNS_R_FORMERR); } if (tsig.siglen > 0 && digestbits != 0 && - tsig.siglen < ((digestbits + 1) / 8)) { + tsig.siglen < ((digestbits + 1) / 8)) + { msg->tsigstatus = dns_tsigerror_badtrunc; tsig_log(msg->tsigkey, 2, "truncated signature length too small"); return (DNS_R_TSIGVERIFYFAILURE); } if (tsig.siglen > 0 && digestbits == 0 && - tsig.siglen < siglen) { + tsig.siglen < siglen) + { msg->tsigstatus = dns_tsigerror_badtrunc; tsig_log(msg->tsigkey, 2, "signature length too small"); return (DNS_R_TSIGVERIFYFAILURE); @@ -1380,7 +1387,7 @@ dns_tsig_verify(isc_buffer_t *source, dns_message_t *msg, if (ret != ISC_R_SUCCESS) return (ret); - if (response) { + if (response && (tsig.error == dns_rcode_noerror)) { isc_buffer_init(&databuf, data, sizeof(data)); isc_buffer_putuint16(&databuf, querytsig.siglen); isc_buffer_usedregion(&databuf, &r); @@ -1485,10 +1492,9 @@ dns_tsig_verify(isc_buffer_t *source, dns_message_t *msg, tsig_log(msg->tsigkey, 2, "signature failed to verify(1)"); goto cleanup_context; - } else if (ret != ISC_R_SUCCESS) + } else if (ret != ISC_R_SUCCESS) { goto cleanup_context; - - dst_context_destroy(&ctx); + } } else if (tsig.error != dns_tsigerror_badsig && tsig.error != dns_tsigerror_badkey) { msg->tsigstatus = dns_tsigerror_badsig; @@ -1496,18 +1502,18 @@ dns_tsig_verify(isc_buffer_t *source, dns_message_t *msg, return (DNS_R_TSIGVERIFYFAILURE); } - msg->tsigstatus = dns_rcode_noerror; - if (tsig.error != dns_rcode_noerror) { + msg->tsigstatus = tsig.error; if (tsig.error == dns_tsigerror_badtime) - return (DNS_R_CLOCKSKEW); + ret = DNS_R_CLOCKSKEW; else - return (DNS_R_TSIGERRORSET); + ret = DNS_R_TSIGERRORSET; + goto cleanup_context; } + msg->tsigstatus = dns_rcode_noerror; msg->verified_sig = 1; - - return (ISC_R_SUCCESS); + ret = ISC_R_SUCCESS; cleanup_context: if (ctx != NULL) @@ -1539,6 +1545,9 @@ tsig_verify_tcp(isc_buffer_t *source, dns_message_t *msg) { REQUIRE(msg->tcp_continuation == 1); REQUIRE(msg->querytsig != NULL); + msg->verified_sig = 0; + msg->tsigstatus = dns_tsigerror_badsig; + if (!is_response(msg)) return (DNS_R_EXPECTEDRESPONSE); @@ -1577,7 +1586,8 @@ tsig_verify_tcp(isc_buffer_t *source, dns_message_t *msg) { * Do the key name and algorithm match that of the query? */ if (!dns_name_equal(keyname, &tsigkey->name) || - !dns_name_equal(&tsig.algorithm, &querytsig.algorithm)) { + !dns_name_equal(&tsig.algorithm, &querytsig.algorithm)) + { msg->tsigstatus = dns_tsigerror_badkey; ret = DNS_R_TSIGVERIFYFAILURE; tsig_log(msg->tsigkey, 2, @@ -1596,7 +1606,8 @@ tsig_verify_tcp(isc_buffer_t *source, dns_message_t *msg) { ret = DNS_R_CLOCKSKEW; goto cleanup_querystruct; } else if (now + msg->timeadjust < - tsig.timesigned - tsig.fudge) { + tsig.timesigned - tsig.fudge) + { msg->tsigstatus = dns_tsigerror_badtime; tsig_log(msg->tsigkey, 2, "signature is in the future"); @@ -1702,10 +1713,12 @@ tsig_verify_tcp(isc_buffer_t *source, dns_message_t *msg) { sig_r.length = tsig.siglen; if (tsig.siglen == 0) { if (tsig.error != dns_rcode_noerror) { - if (tsig.error == dns_tsigerror_badtime) + msg->tsigstatus = tsig.error; + if (tsig.error == dns_tsigerror_badtime) { ret = DNS_R_CLOCKSKEW; - else + } else { ret = DNS_R_TSIGERRORSET; + } } else { tsig_log(msg->tsigkey, 2, "signature is empty"); @@ -1721,24 +1734,32 @@ tsig_verify_tcp(isc_buffer_t *source, dns_message_t *msg) { "signature failed to verify(2)"); ret = DNS_R_TSIGVERIFYFAILURE; goto cleanup_context; - } - else if (ret != ISC_R_SUCCESS) + } else if (ret != ISC_R_SUCCESS) { goto cleanup_context; + } - dst_context_destroy(&msg->tsigctx); + if (tsig.error != dns_rcode_noerror) { + msg->tsigstatus = tsig.error; + if (tsig.error == dns_tsigerror_badtime) + ret = DNS_R_CLOCKSKEW; + else + ret = DNS_R_TSIGERRORSET; + goto cleanup_context; + } } msg->tsigstatus = dns_rcode_noerror; - return (ISC_R_SUCCESS); + msg->verified_sig = 1; + ret = ISC_R_SUCCESS; cleanup_context: - dst_context_destroy(&msg->tsigctx); + if (msg->tsigctx != NULL) + dst_context_destroy(&msg->tsigctx); cleanup_querystruct: dns_rdata_freestruct(&querytsig); return (ret); - } isc_result_t