diff --git a/CHANGES b/CHANGES
index 13cade8950..96b29b95ad 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 e0bec15bb8..af0c517303 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 c8b567c775..c95302dd23 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 bd1f603341..3dd2ea6312 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 dae1cd7c66..cf6b206af4 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 3945f67523..0933889549 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)
- 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) {
diff --git a/lib/dns/tsig.c b/lib/dns/tsig.c
index bbbfc11213..49967540fd 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