2
0
mirror of https://gitlab.isc.org/isc-projects/bind9 synced 2025-08-29 13:38:26 +00:00

2828. [security] Cached CNAME or DNAME RR could be returned to clients

without DNSSEC validation. [RT #20737]

9.4-ESV, 9.5.3, 9.6.2, 9.7.0, 9.8.0(?)
This commit is contained in:
Tatuya JINMEI 神明達哉 2009-12-30 08:02:23 +00:00
parent 0f348b269b
commit d8680445d6
15 changed files with 283 additions and 70 deletions

View File

@ -1,3 +1,6 @@
2828. [security] Cached CNAME or DNAME RR could be returned to clients
without DNSSEC validation. [RT #20737]
2827. [security] Bogus NXDOMAIN could be cached as if valid. [RT #20712]
2826. [bug] NSEC3->NSEC transitions could fail due to a lock not

View File

@ -15,7 +15,7 @@
* PERFORMANCE OF THIS SOFTWARE.
*/
/* $Id: query.c,v 1.335 2009/11/28 15:57:36 vjs Exp $ */
/* $Id: query.c,v 1.336 2009/12/30 08:02:22 jinmei Exp $ */
/*! \file */
@ -3737,8 +3737,6 @@ query_find(ns_client_t *client, dns_fetchevent_t *event, dns_rdatatype_t qtype)
dns_rdataset_t *noqname;
isc_boolean_t resuming;
int line = -1;
dns_rdataset_t tmprdataset;
unsigned int dboptions;
CTRACE("query_find");
@ -3956,49 +3954,9 @@ query_find(ns_client_t *client, dns_fetchevent_t *event, dns_rdatatype_t qtype)
/*
* Now look for an answer in the database.
*/
dboptions = client->query.dboptions;
if (sigrdataset == NULL && client->view->enablednssec) {
/*
* If the client doesn't want DNSSEC we still want to
* look for any data pending validation to save a remote
* lookup if possible.
*/
dns_rdataset_init(&tmprdataset);
sigrdataset = &tmprdataset;
dboptions |= DNS_DBFIND_PENDINGOK;
}
refind:
result = dns_db_find(db, client->query.qname, version, type,
dboptions, client->now, &node, fname,
rdataset, sigrdataset);
/*
* If we have found pending data try to validate it.
* If the data does not validate as secure and we can't
* use the unvalidated data requery the database with
* pending disabled to prevent infinite looping.
*/
if (result != ISC_R_SUCCESS || !DNS_TRUST_PENDING(rdataset->trust))
goto validation_done;
if (validate(client, db, fname, rdataset, sigrdataset))
goto validation_done;
if (rdataset->trust != dns_trust_pending_answer ||
!PENDINGOK(client->query.dboptions)) {
dns_rdataset_disassociate(rdataset);
if (sigrdataset != NULL &&
dns_rdataset_isassociated(sigrdataset))
dns_rdataset_disassociate(sigrdataset);
if (sigrdataset == &tmprdataset)
sigrdataset = NULL;
dns_db_detachnode(db, &node);
dboptions &= ~DNS_DBFIND_PENDINGOK;
goto refind;
}
validation_done:
if (sigrdataset == &tmprdataset) {
if (dns_rdataset_isassociated(sigrdataset))
dns_rdataset_disassociate(sigrdataset);
sigrdataset = NULL;
}
client->query.dboptions, client->now,
&node, fname, rdataset, sigrdataset);
resume:
CTRACE("query_find: resume");

View File

@ -13,7 +13,7 @@
# OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
# PERFORMANCE OF THIS SOFTWARE.
# $Id: Makefile.in,v 1.138 2009/12/05 23:31:40 each Exp $
# $Id: Makefile.in,v 1.139 2009/12/30 08:02:22 jinmei Exp $
srcdir = @srcdir@
VPATH = @srcdir@
@ -245,6 +245,10 @@ rwlock_test@EXEEXT@: rwlock_test.@O@ ${ISCDEPLIBS}
${LIBTOOL_MODE_LINK} ${PURIFY} ${CC} ${CFLAGS} ${LDFLAGS} -o $@ rwlock_test.@O@ \
${ISCLIBS} ${LIBS}
rwlock_upgradetest@EXEEXT@: rwlock_upgradetest.@O@ ${ISCDEPLIBS}
${LIBTOOL_MODE_LINK} ${PURIFY} ${CC} ${CFLAGS} ${LDFLAGSe} -o $@ rwlock_upgradetest.@O@ \
${ISCLIBS} ${LIBS}
wire_test@EXEEXT@: wire_test.@O@ printmsg.@O@ ${ISCDEPLIBS} ${DNSDEPLIBS}
${LIBTOOL_MODE_LINK} ${PURIFY} ${CC} ${CFLAGS} ${LDFLAGS} -o $@ wire_test.@O@ printmsg.@O@ \
${DNSLIBS} ${ISCLIBS} ${LIBS}

View File

@ -13,7 +13,7 @@
; OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
; PERFORMANCE OF THIS SOFTWARE.
; $Id: example.db.in,v 1.21 2009/10/27 23:47:44 tbox Exp $
; $Id: example.db.in,v 1.22 2009/12/30 08:02:22 jinmei Exp $
$TTL 300 ; 5 minutes
@ IN SOA mname1. . (
@ -36,6 +36,9 @@ d A 10.0.0.4
foo TXT "testing"
foo A 10.0.1.0
bad-cname CNAME a
bad-dname DNAME @
; Used for testing CNAME queries
cname1 CNAME cname1-target
cname1-target TXT "testing cname"

View File

@ -15,7 +15,7 @@
# OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
# PERFORMANCE OF THIS SOFTWARE.
# $Id: sign.sh,v 1.35 2009/10/28 00:27:10 marka Exp $
# $Id: sign.sh,v 1.36 2009/12/30 08:02:22 jinmei Exp $
SYSTEMTESTTOP=../..
. $SYSTEMTESTTOP/conf.sh
@ -43,6 +43,53 @@ cat $infile $keyname1.key $keyname2.key >$zonefile
$SIGNER -P -g -r $RANDFILE -o $zone -k $keyname1 $zonefile $keyname2 > /dev/null
#
# lower/uppercase the signature bits with the exception of the last characters
# changing the last 4 characters will lead to a bad base64 encoding.
#
$CHECKZONE -D -q -i local $zone $zonefile.signed |
awk '
tolower($1) == "bad-cname.example." && $4 == "RRSIG" && $5 == "CNAME" {
for (i = 1; i <= NF; i++ ) {
if (i <= 12) {
printf("%s ", $i);
continue;
}
prefix = substr($i, 1, length($i) - 4);
suffix = substr($i, length($i) - 4, 4);
if (i > 12 && tolower(prefix) != prefix)
printf("%s%s", tolower(prefix), suffix);
else if (i > 12 && toupper(prefix) != prefix)
printf("%s%s", toupper(prefix), suffix);
else
printf("%s%s ", prefix, suffix);
}
printf("\n");
next;
}
tolower($1) == "bad-dname.example." && $4 == "RRSIG" && $5 == "DNAME" {
for (i = 1; i <= NF; i++ ) {
if (i <= 12) {
printf("%s ", $i);
continue;
}
prefix = substr($i, 1, length($i) - 4);
suffix = substr($i, length($i) - 4, 4);
if (i > 12 && tolower(prefix) != prefix)
printf("%s%s", tolower(prefix), suffix);
else if (i > 12 && toupper(prefix) != prefix)
printf("%s%s", toupper(prefix), suffix);
else
printf("%s%s ", prefix, suffix);
}
printf("\n");
next;
}
{ print; }' > $zonefile.signed++ && mv $zonefile.signed++ $zonefile.signed
# Sign the privately secure file
privzone=private.secure.example.

View File

@ -15,7 +15,7 @@
# OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
# PERFORMANCE OF THIS SOFTWARE.
# $Id: tests.sh,v 1.55 2009/10/27 23:47:44 tbox Exp $
# $Id: tests.sh,v 1.56 2009/12/30 08:02:22 jinmei Exp $
SYSTEMTESTTOP=..
. $SYSTEMTESTTOP/conf.sh
@ -522,6 +522,41 @@ n=`expr $n + 1`
if [ $ret != 0 ]; then echo "I:failed"; fi
status=`expr $status + $ret`
echo "I:Checking that a bad CNAME signature is caught after a +CD query ($n)"
ret=0
#prime
$DIG $DIGOPTS +cd bad-cname.example. @10.53.0.4 > dig.out.ns4.prime$n || ret=1
#check: requery with +CD. pending data should be returned even if it's bogus
expect="a.example.
10.0.0.1"
ans=`$DIG $DIGOPTS +cd +nodnssec +short bad-cname.example. @10.53.0.4` || ret=1
test "$ans" = "$expect" || ret=1
test $ret = 0 || echo I:failed, got "'""$ans""'", expected "'""$expect""'"
#check: requery without +CD. bogus cached data should be rejected.
$DIG $DIGOPTS +nodnssec bad-cname.example. @10.53.0.4 > dig.out.ns4.test$n || ret=1
grep "SERVFAIL" dig.out.ns4.test$n > /dev/null || ret=1
n=`expr $n + 1`
if [ $ret != 0 ]; then echo "I:failed"; fi
status=`expr $status + $ret`
echo "I:Checking that a bad DNAME signature is caught after a +CD query ($n)"
ret=0
#prime
$DIG $DIGOPTS +cd a.bad-dname.example. @10.53.0.4 > dig.out.ns4.prime$n || ret=1
#check: requery with +CD. pending data should be returned even if it's bogus
expect="example.
a.example.
10.0.0.1"
ans=`$DIG $DIGOPTS +cd +nodnssec +short a.bad-dname.example. @10.53.0.4` || ret=1
test "$ans" = "$expect" || ret=1
test $ret = 0 || echo I:failed, got "'""$ans""'", expected "'""$expect""'"
#check: requery without +CD. bogus cached data should be rejected.
$DIG $DIGOPTS +nodnssec a.bad-dname.example. @10.53.0.4 > dig.out.ns4.test$n || ret=1
grep "SERVFAIL" dig.out.ns4.test$n > /dev/null || ret=1
n=`expr $n + 1`
if [ $ret != 0 ]; then echo "I:failed"; fi
status=`expr $status + $ret`
# Check the insecure.secure.example domain (insecurity proof)
echo "I:checking 2-server insecurity proof ($n)"

View File

@ -14,9 +14,10 @@
# OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
# PERFORMANCE OF THIS SOFTWARE.
# $Id: clean.sh,v 1.3 2009/12/03 04:51:41 marka Exp $
# $Id: clean.sh,v 1.4 2009/12/30 08:02:22 jinmei Exp $
rm -rf */*.signed
rm -rf */*.jnl
rm -rf */K*
rm -rf */dsset-*
rm -rf */named.memstats
@ -24,4 +25,6 @@ rm -rf */named.run
rm -rf */trusted.conf
rm -rf ns1/root.db
rm -rf ns2/example.db
rm -rf ns2/example.com.db
rm -rf random.data
rm -rf nsupdate.out.test

View File

@ -12,7 +12,7 @@
; OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
; PERFORMANCE OF THIS SOFTWARE.
; $Id: root.db.in,v 1.3 2009/11/18 23:48:06 tbox Exp $
; $Id: root.db.in,v 1.4 2009/12/30 08:02:22 jinmei Exp $
$TTL 30
. IN SOA marka.isc.org. a.root.servers.nil. (
@ -27,5 +27,7 @@ a.root-servers.nil. A 10.53.0.1
example. NS ns2.example.
ns2.example. A 10.53.0.2
example.com. NS ns2.example.com.
ns2.example.com. A 10.53.0.2
hostile. NS ns3.hostile.
ns3.hostile. A 10.53.0.3

View File

@ -14,7 +14,7 @@
# OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
# PERFORMANCE OF THIS SOFTWARE.
# $Id: sign.sh,v 1.2 2009/11/17 23:55:18 marka Exp $
# $Id: sign.sh,v 1.3 2009/12/30 08:02:22 jinmei Exp $
SYSTEMTESTTOP=../..
. $SYSTEMTESTTOP/conf.sh
@ -28,6 +28,7 @@ zonefile=root.db
(cd ../ns2 && sh -e sign.sh )
cp ../ns2/dsset-example. .
cp ../ns2/dsset-example.com. .
keyname1=`$KEYGEN -q -r $RANDFILE -a RSASHA256 -b 1024 -n zone $zone`
keyname2=`$KEYGEN -q -r $RANDFILE -a RSASHA256 -b 2048 -f KSK -n zone $zone`

View File

@ -0,0 +1,31 @@
; Copyright (C) 2009 Internet Systems Consortium, Inc. ("ISC")
;
; Permission to use, copy, modify, and/or distribute this software for any
; purpose with or without fee is hereby granted, provided that the above
; copyright notice and this permission notice appear in all copies.
;
; THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
; REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
; AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
; INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
; LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
; OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
; PERFORMANCE OF THIS SOFTWARE.
; $Id: example.com.db.in,v 1.2 2009/12/30 08:02:22 jinmei Exp $
$TTL 30
@ IN SOA mname1. . (
2009110300 ; serial
20 ; refresh (20 seconds)
20 ; retry (20 seconds)
1814400 ; expire (3 weeks)
3600 ; minimum (1 hour)
)
NS ns2
MX 10 mail
ns2 A 10.53.0.2
mail A 192.0.2.2
AAAA 2001:db8::2
pending-ok A 192.0.2.2
pending-ng A 192.0.2.102

View File

@ -14,7 +14,7 @@
* PERFORMANCE OF THIS SOFTWARE.
*/
/* $Id: named.conf,v 1.3 2009/11/18 23:48:06 tbox Exp $ */
/* $Id: named.conf,v 1.4 2009/12/30 08:02:22 jinmei Exp $ */
// NS2
@ -45,3 +45,9 @@ zone "example" {
type master;
file "example.db.signed";
};
zone "example.com" {
type master;
file "example.com.db.signed";
allow-update { 10.53.0.0/8; };
};

View File

@ -14,20 +14,22 @@
# OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
# PERFORMANCE OF THIS SOFTWARE.
# $Id: sign.sh,v 1.3 2009/11/18 23:48:07 tbox Exp $
# $Id: sign.sh,v 1.4 2009/12/30 08:02:22 jinmei Exp $
SYSTEMTESTTOP=../..
. $SYSTEMTESTTOP/conf.sh
RANDFILE=../random.data
zone=example.
infile=example.db.in
zonefile=example.db
for domain in example example.com; do
zone=${domain}.
infile=${domain}.db.in
zonefile=${domain}.db
keyname1=`$KEYGEN -q -r $RANDFILE -a RSASHA1 -b 768 -n zone $zone`
keyname2=`$KEYGEN -q -r $RANDFILE -a RSASHA1 -b 1024 -f KSK -n zone $zone`
keyname1=`$KEYGEN -q -r $RANDFILE -a RSASHA1 -b 768 -n zone $zone`
keyname2=`$KEYGEN -q -r $RANDFILE -a RSASHA1 -b 1024 -f KSK -n zone $zone`
cat $infile $keyname1.key $keyname2.key >$zonefile
cat $infile $keyname1.key $keyname2.key >$zonefile
$SIGNER -r $RANDFILE -o $zone $zonefile > /dev/null
$SIGNER -r $RANDFILE -o $zone $zonefile > /dev/null
done

View File

@ -14,22 +14,50 @@
# OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
# PERFORMANCE OF THIS SOFTWARE.
# $Id: tests.sh,v 1.3 2009/11/18 23:48:06 tbox Exp $
# $Id: tests.sh,v 1.4 2009/12/30 08:02:22 jinmei Exp $
SYSTEMTESTTOP=..
. $SYSTEMTESTTOP/conf.sh
# replace_data dname RR old_data new_data
replace_data()
{
if [ $# -ne 4 ]; then
echo I:unexpected input for replace_data
return 1
fi
_dname=$1
_rr=$2
_olddata=$3
_newdata=$4
_ret=0
$NSUPDATE -d <<END>> nsupdate.out.test 2>&1 || _ret=1
server 10.53.0.2 5300
update delete ${_dname} 30 ${_rr} ${_olddata}
update add ${_dname} 30 ${_rr} ${_newdata}
send
END
if [ $_ret != 0 ]; then
echo I:failed to update the test data
return 1
fi
return 0
}
status=0
n=0
rm -f dig.out.*
DIGOPTS="+short +tcp +cd -p 5300"
DIGOPTS="+short +tcp -p 5300"
DIGOPTS_CD="$DIGOPTS +cd"
echo I:Priming cache.
ret=0
expect="10 mail.example."
ans=`$DIG $DIGOPTS @10.53.0.4 hostile MX` || ret=1
ans=`$DIG $DIGOPTS_CD @10.53.0.4 hostile MX` || ret=1
test "$ans" = "$expect" || ret=1
test $ret = 0 || echo I:failed, got "'""$ans""'", expected "'""$expect""'"
status=`expr $status + $ret`
@ -37,7 +65,95 @@ status=`expr $status + $ret`
echo I:Checking that bogus additional is not returned with +CD.
ret=0
expect="10.0.0.2"
ans=`$DIG $DIGOPTS @10.53.0.4 mail.example A` || ret=1
ans=`$DIG $DIGOPTS_CD @10.53.0.4 mail.example A` || ret=1
test "$ans" = "$expect" || ret=1
test $ret = 0 || echo I:failed, got "'""$ans""'", expected "'""$expect""'"
status=`expr $status + $ret`
#
# Prime cache with pending additional records. These should not be promoted
# to answer.
#
echo "I:Priming cache (pending additional A and AAAA)"
ret=0
expect="10 mail.example.com."
ans=`$DIG $DIGOPTS @10.53.0.4 example.com MX` || ret=1
test "$ans" = "$expect" || ret=1
test $ret = 0 || echo I:failed, got "'""$ans""'", expected "'""$expect""'"
status=`expr $status + $ret`
echo "I:Replacing pending A"
ret=0
replace_data mail.example.com. A 192.0.2.2 192.0.2.3 || ret=1
status=`expr $status + $ret`
echo "I:Replacing pending AAAA"
ret=0
replace_data mail.example.com. AAAA 2001:db8::2 2001:db8::3 || ret=1
status=`expr $status + $ret`
echo "I:Checking updated data to be returned (without CD)"
ret=0
expect="192.0.2.3"
ans=`$DIG $DIGOPTS @10.53.0.4 mail.example.com A` || ret=1
test "$ans" = "$expect" || ret=1
test $ret = 0 || echo I:failed, got "'""$ans""'", expected "'""$expect""'"
status=`expr $status + $ret`
echo "I:Checking updated data to be returned (with CD)"
ret=0
expect="2001:db8::3"
ans=`$DIG $DIGOPTS_CD @10.53.0.4 mail.example.com AAAA` || ret=1
test "$ans" = "$expect" || ret=1
test $ret = 0 || echo I:failed, got "'""$ans""'", expected "'""$expect""'"
status=`expr $status + $ret`
#
# Prime cache with a pending answer record. It can be returned (without
# validation) with +CD.
#
echo "I:Priming cache (pending answer)"
ret=0
expect="192.0.2.2"
ans=`$DIG $DIGOPTS_CD @10.53.0.4 pending-ok.example.com A` || ret=1
test "$ans" = "$expect" || ret=1
test $ret = 0 || echo I:failed, got "'""$ans""'", expected "'""$expect""'"
status=`expr $status + $ret`
echo I:Replacing pending data
ret=0
replace_data pending-ok.example.com. A 192.0.2.2 192.0.2.3 || ret=1
status=`expr $status + $ret`
echo I:Confirming cached pending data to be returned with CD
ret=0
expect="192.0.2.2"
ans=`$DIG $DIGOPTS_CD @10.53.0.4 pending-ok.example.com A` || ret=1
test "$ans" = "$expect" || ret=1
test $ret = 0 || echo I:failed, got "'""$ans""'", expected "'""$expect""'"
status=`expr $status + $ret`
#
# Prime cache with a pending answer record. It should not be returned
# to no-DNSSEC clients.
#
echo "I:Priming cache (pending answer)"
ret=0
expect="192.0.2.102"
ans=`$DIG $DIGOPTS_CD @10.53.0.4 pending-ng.example.com A` || ret=1
test "$ans" = "$expect" || ret=1
test $ret = 0 || echo I:failed, got "'""$ans""'", expected "'""$expect""'"
status=`expr $status + $ret`
echo I:Replacing pending data
ret=0
replace_data pending-ng.example.com. A 192.0.2.102 192.0.2.103 || ret=1
status=`expr $status + $ret`
echo I:Confirming updated data returned, not the cached one, without CD
ret=0
expect="192.0.2.103"
ans=`$DIG $DIGOPTS @10.53.0.4 pending-ng.example.com A` || ret=1
test "$ans" = "$expect" || ret=1
test $ret = 0 || echo I:failed, got "'""$ans""'", expected "'""$expect""'"
status=`expr $status + $ret`

View File

@ -15,7 +15,7 @@
* PERFORMANCE OF THIS SOFTWARE.
*/
/* $Id: types.h,v 1.138 2009/11/17 23:55:18 marka Exp $ */
/* $Id: types.h,v 1.139 2009/12/30 08:02:23 jinmei Exp $ */
#ifndef DNS_TYPES_H
#define DNS_TYPES_H 1
@ -318,6 +318,8 @@ enum {
#define DNS_TRUST_PENDING(x) ((x) == dns_trust_pending_answer || \
(x) == dns_trust_pending_additional)
#define DNS_TRUST_ADDITIONAL(x) ((x) == dns_trust_additional || \
(x) == dns_trust_pending_additional)
#define DNS_TRUST_GLUE(x) ((x) == dns_trust_glue)

View File

@ -15,7 +15,7 @@
* PERFORMANCE OF THIS SOFTWARE.
*/
/* $Id: rbtdb.c,v 1.295 2009/12/29 22:04:16 marka Exp $ */
/* $Id: rbtdb.c,v 1.296 2009/12/30 08:02:23 jinmei Exp $ */
/*! \file */
@ -4678,7 +4678,7 @@ cache_find(dns_db_t *db, dns_name_t *name, dns_dbversion_t *version,
* If we didn't find what we were looking for...
*/
if (found == NULL ||
(found->trust == dns_trust_additional &&
(DNS_TRUST_ADDITIONAL(found->trust) &&
((options & DNS_DBFIND_ADDITIONALOK) == 0)) ||
(found->trust == dns_trust_glue &&
((options & DNS_DBFIND_GLUEOK) == 0)) ||