mirror of
https://github.com/isc-projects/bind9.git
synced 2026-06-11 13:39:59 -04:00
[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 commit581c1526ab) (cherry picked from commita03f4b1ea4)
This commit is contained in:
parent
a71114e8bd
commit
88dc9d367d
7 changed files with 88 additions and 33 deletions
4
CHANGES
4
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]
|
||||
|
|
|
|||
10
README
10
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
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
||||
### <a name="build"/> Building BIND
|
||||
|
||||
|
|
|
|||
|
|
@ -69,6 +69,13 @@
|
|||
|
||||
<section xml:id="relnotes_security"><info><title>Security Fixes</title></info>
|
||||
<itemizedlist>
|
||||
<listitem>
|
||||
<para>
|
||||
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]
|
||||
</para>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<para>
|
||||
The BIND installer on Windows used an unquoted service path,
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
result = DNS_R_TSIGVERIFYFAILURE;
|
||||
else if (tsig.error != dns_rcode_noerror)
|
||||
result = DNS_R_TSIGERRORSET;
|
||||
else
|
||||
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 {
|
||||
INSIST(tsig.error != dns_rcode_noerror);
|
||||
result = DNS_R_TSIGERRORSET;
|
||||
}
|
||||
dns_rdata_freestruct(&tsig);
|
||||
|
||||
if (msg->tsigkey == NULL) {
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
Loading…
Reference in a new issue