- moved version number to 1.4.0 because of 1.3.4 release with only

the NSEC3 patch.
	- val-log-level: 2 shows extended error information for validation
	  failures, but still one (longish) line per failure.  For example:
	  validation failure <example.com. DNSKEY IN>: signature expired from
	  192.0.2.4 for trust anchor example.com. while building chain of trust
	  validation failure <www.example.com. A IN>: no signatures from
	  192.0.2.6 for key example.com. while building chain of trust



git-svn-id: file:///svn/unbound/trunk@1868 be551aaa-1e26-0410-a405-d3ace91eadb9
This commit is contained in:
Wouter Wijngaards 2009-10-07 16:45:47 +00:00
parent 6f37df3b92
commit ce45cbda6d
16 changed files with 822 additions and 95 deletions

49
configure vendored
View file

@ -1,6 +1,6 @@
#! /bin/sh
# Guess values for system-dependent variables and create Makefiles.
# Generated by GNU Autoconf 2.63 for unbound 1.3.4.
# Generated by GNU Autoconf 2.63 for unbound 1.4.0.
#
# Report bugs to <unbound-bugs@nlnetlabs.nl>.
#
@ -745,8 +745,8 @@ SHELL=${CONFIG_SHELL-/bin/sh}
# Identity of this package.
PACKAGE_NAME='unbound'
PACKAGE_TARNAME='unbound'
PACKAGE_VERSION='1.3.4'
PACKAGE_STRING='unbound 1.3.4'
PACKAGE_VERSION='1.4.0'
PACKAGE_STRING='unbound 1.4.0'
PACKAGE_BUGREPORT='unbound-bugs@nlnetlabs.nl'
# Factoring default headers for most tests.
@ -1499,7 +1499,7 @@ if test "$ac_init_help" = "long"; then
# Omit some internal or obsolete options to make the list less imposing.
# This message is too long to be a string in the A/UX 3.1 sh.
cat <<_ACEOF
\`configure' configures unbound 1.3.4 to adapt to many kinds of systems.
\`configure' configures unbound 1.4.0 to adapt to many kinds of systems.
Usage: $0 [OPTION]... [VAR=VALUE]...
@ -1564,7 +1564,7 @@ fi
if test -n "$ac_init_help"; then
case $ac_init_help in
short | recursive ) echo "Configuration of unbound 1.3.4:";;
short | recursive ) echo "Configuration of unbound 1.4.0:";;
esac
cat <<\_ACEOF
@ -1710,7 +1710,7 @@ fi
test -n "$ac_init_help" && exit $ac_status
if $ac_init_version; then
cat <<\_ACEOF
unbound configure 1.3.4
unbound configure 1.4.0
generated by GNU Autoconf 2.63
Copyright (C) 1992, 1993, 1994, 1995, 1996, 1998, 1999, 2000, 2001,
@ -1724,7 +1724,7 @@ cat >config.log <<_ACEOF
This file contains any messages produced by compilers while
running configure, to aid debugging if configure makes a mistake.
It was created by unbound $as_me 1.3.4, which was
It was created by unbound $as_me 1.4.0, which was
generated by GNU Autoconf 2.63. Invocation command line was
$ $0 $@
@ -2094,7 +2094,7 @@ ac_compiler_gnu=$ac_cv_c_compiler_gnu
LIBUNBOUND_CURRENT=1
LIBUNBOUND_REVISION=4
LIBUNBOUND_REVISION=5
LIBUNBOUND_AGE=0
# 1.0.0 had 0:12:0
# 1.0.1 had 0:13:0
@ -2108,6 +2108,7 @@ LIBUNBOUND_AGE=0
# 1.3.2 had 1:2:0
# 1.3.3 had 1:3:0
# 1.3.4 had 1:4:0
# 1.4.0 had 1:5:0
# Current -- the number of the binary API that we're implementing
# Revision -- which iteration of the implementation of the binary
@ -7278,13 +7279,13 @@ if test "${lt_cv_nm_interface+set}" = set; then
else
lt_cv_nm_interface="BSD nm"
echo "int some_variable = 0;" > conftest.$ac_ext
(eval echo "\"\$as_me:7281: $ac_compile\"" >&5)
(eval echo "\"\$as_me:7282: $ac_compile\"" >&5)
(eval "$ac_compile" 2>conftest.err)
cat conftest.err >&5
(eval echo "\"\$as_me:7284: $NM \\\"conftest.$ac_objext\\\"\"" >&5)
(eval echo "\"\$as_me:7285: $NM \\\"conftest.$ac_objext\\\"\"" >&5)
(eval "$NM \"conftest.$ac_objext\"" 2>conftest.err > conftest.out)
cat conftest.err >&5
(eval echo "\"\$as_me:7287: output\"" >&5)
(eval echo "\"\$as_me:7288: output\"" >&5)
cat conftest.out >&5
if $GREP 'External.*some_variable' conftest.out > /dev/null; then
lt_cv_nm_interface="MS dumpbin"
@ -8489,7 +8490,7 @@ ia64-*-hpux*)
;;
*-*-irix6*)
# Find out which ABI we are using.
echo '#line 8492 "configure"' > conftest.$ac_ext
echo '#line 8493 "configure"' > conftest.$ac_ext
if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
(eval $ac_compile) 2>&5
ac_status=$?
@ -9856,11 +9857,11 @@ else
-e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \
-e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \
-e 's:$: $lt_compiler_flag:'`
(eval echo "\"\$as_me:9859: $lt_compile\"" >&5)
(eval echo "\"\$as_me:9860: $lt_compile\"" >&5)
(eval "$lt_compile" 2>conftest.err)
ac_status=$?
cat conftest.err >&5
echo "$as_me:9863: \$? = $ac_status" >&5
echo "$as_me:9864: \$? = $ac_status" >&5
if (exit $ac_status) && test -s "$ac_outfile"; then
# The compiler can only warn and ignore the option if not recognized
# So say no if there are warnings other than the usual output.
@ -10195,11 +10196,11 @@ else
-e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \
-e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \
-e 's:$: $lt_compiler_flag:'`
(eval echo "\"\$as_me:10198: $lt_compile\"" >&5)
(eval echo "\"\$as_me:10199: $lt_compile\"" >&5)
(eval "$lt_compile" 2>conftest.err)
ac_status=$?
cat conftest.err >&5
echo "$as_me:10202: \$? = $ac_status" >&5
echo "$as_me:10203: \$? = $ac_status" >&5
if (exit $ac_status) && test -s "$ac_outfile"; then
# The compiler can only warn and ignore the option if not recognized
# So say no if there are warnings other than the usual output.
@ -10300,11 +10301,11 @@ else
-e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \
-e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \
-e 's:$: $lt_compiler_flag:'`
(eval echo "\"\$as_me:10303: $lt_compile\"" >&5)
(eval echo "\"\$as_me:10304: $lt_compile\"" >&5)
(eval "$lt_compile" 2>out/conftest.err)
ac_status=$?
cat out/conftest.err >&5
echo "$as_me:10307: \$? = $ac_status" >&5
echo "$as_me:10308: \$? = $ac_status" >&5
if (exit $ac_status) && test -s out/conftest2.$ac_objext
then
# The compiler can only warn and ignore the option if not recognized
@ -10355,11 +10356,11 @@ else
-e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \
-e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \
-e 's:$: $lt_compiler_flag:'`
(eval echo "\"\$as_me:10358: $lt_compile\"" >&5)
(eval echo "\"\$as_me:10359: $lt_compile\"" >&5)
(eval "$lt_compile" 2>out/conftest.err)
ac_status=$?
cat out/conftest.err >&5
echo "$as_me:10362: \$? = $ac_status" >&5
echo "$as_me:10363: \$? = $ac_status" >&5
if (exit $ac_status) && test -s out/conftest2.$ac_objext
then
# The compiler can only warn and ignore the option if not recognized
@ -13158,7 +13159,7 @@ else
lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2
lt_status=$lt_dlunknown
cat > conftest.$ac_ext <<_LT_EOF
#line 13161 "configure"
#line 13162 "configure"
#include "confdefs.h"
#if HAVE_DLFCN_H
@ -13254,7 +13255,7 @@ else
lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2
lt_status=$lt_dlunknown
cat > conftest.$ac_ext <<_LT_EOF
#line 13257 "configure"
#line 13258 "configure"
#include "confdefs.h"
#if HAVE_DLFCN_H
@ -23301,7 +23302,7 @@ exec 6>&1
# report actual input values of CONFIG_FILES etc. instead of their
# values after options handling.
ac_log="
This file was extended by unbound $as_me 1.3.4, which was
This file was extended by unbound $as_me 1.4.0, which was
generated by GNU Autoconf 2.63. Invocation command line was
CONFIG_FILES = $CONFIG_FILES
@ -23364,7 +23365,7 @@ Report bugs to <bug-autoconf@gnu.org>."
_ACEOF
cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
ac_cs_version="\\
unbound config.status 1.3.4
unbound config.status 1.4.0
configured by $0, generated by GNU Autoconf 2.63,
with options \\"`$as_echo "$ac_configure_args" | sed 's/^ //; s/[\\""\`\$]/\\\\&/g'`\\"

View file

@ -6,10 +6,10 @@ sinclude(acx_pthread.m4)
sinclude(acx_python.m4)
sinclude(ac_pkg_swig.m4)
AC_INIT(unbound, 1.3.4, unbound-bugs@nlnetlabs.nl, unbound)
AC_INIT(unbound, 1.4.0, unbound-bugs@nlnetlabs.nl, unbound)
LIBUNBOUND_CURRENT=1
LIBUNBOUND_REVISION=4
LIBUNBOUND_REVISION=5
LIBUNBOUND_AGE=0
# 1.0.0 had 0:12:0
# 1.0.1 had 0:13:0
@ -23,6 +23,7 @@ LIBUNBOUND_AGE=0
# 1.3.2 had 1:2:0
# 1.3.3 had 1:3:0
# 1.3.4 had 1:4:0
# 1.4.0 had 1:5:0
# Current -- the number of the binary API that we're implementing
# Revision -- which iteration of the implementation of the binary

View file

@ -7,6 +7,14 @@
- Fixed security bug where the signatures for NSEC3 records were not
checked when checking for absence of DS records. This could have
enabled the substitution of an insecure delegation.
- moved version number to 1.4.0 because of 1.3.4 release with only
the NSEC3 patch from the entry above.
- val-log-level: 2 shows extended error information for validation
failures, but still one (longish) line per failure. For example:
validation failure <example.com. DNSKEY IN>: signature expired from
192.0.2.4 for trust anchor example.com. while building chain of trust
validation failure <www.example.com. A IN>: no signatures from
192.0.2.6 for key example.com. while building chain of trust
6 October 2009: Wouter
- Test set updated to provide additional ns lookup result.

View file

@ -186,6 +186,7 @@ setup_config(FILE* in, int* lineno, int* pass_argc, char* pass_argv[])
fprintf(cfg, " chroot: \"\"\n");
fprintf(cfg, " username: \"\"\n");
fprintf(cfg, " pidfile: \"\"\n");
fprintf(cfg, " val-log-level: 2\n");
while(fgets(line, MAX_LINE_LEN-1, in)) {
parse = line;
(*lineno)++;

View file

@ -155,14 +155,16 @@ verifytest_rrset(struct module_env* env, struct val_env* ve,
struct query_info* qinfo)
{
enum sec_status sec;
char* reason = NULL;
if(vsig) {
log_nametypeclass(VERB_QUERY, "verify of rrset",
rrset->rk.dname, ntohs(rrset->rk.type),
ntohs(rrset->rk.rrset_class));
}
sec = dnskeyset_verify_rrset(env, ve, rrset, dnskey);
sec = dnskeyset_verify_rrset(env, ve, rrset, dnskey, &reason);
if(vsig) {
printf("verify outcome is: %s\n", sec_status_to_string(sec));
printf("verify outcome is: %s %s\n", sec_status_to_string(sec),
reason?reason:"");
}
if(should_be_bogus(rrset, qinfo)) {
unit_assert(sec == sec_status_bogus);

227
testdata/val_nsec3_nods_badsig.rpl vendored Normal file
View file

@ -0,0 +1,227 @@
; config options
; The island of trust is at example.com
server:
trust-anchor: "example.com. 3600 IN DS 2854 3 1 46e4ffc6e9a4793b488954bd3f0cc6af0dfb201b"
val-override-date: "20070916134226"
target-fetch-policy: "0 0 0 0 0"
stub-zone:
name: "."
stub-addr: 193.0.14.129 # K.ROOT-SERVERS.NET.
CONFIG_END
SCENARIO_BEGIN Test validator with NSEC3 with no DS referral with bad signature.
; K.ROOT-SERVERS.NET.
RANGE_BEGIN 0 100
ADDRESS 193.0.14.129
ENTRY_BEGIN
MATCH opcode qtype qname
ADJUST copy_id
REPLY QR NOERROR
SECTION QUESTION
. IN NS
SECTION ANSWER
. IN NS K.ROOT-SERVERS.NET.
SECTION ADDITIONAL
K.ROOT-SERVERS.NET. IN A 193.0.14.129
ENTRY_END
ENTRY_BEGIN
MATCH opcode subdomain
ADJUST copy_id copy_query
REPLY QR NOERROR
SECTION QUESTION
com. IN A
SECTION AUTHORITY
com. IN NS a.gtld-servers.net.
SECTION ADDITIONAL
a.gtld-servers.net. IN A 192.5.6.30
ENTRY_END
RANGE_END
; a.gtld-servers.net.
RANGE_BEGIN 0 100
ADDRESS 192.5.6.30
ENTRY_BEGIN
MATCH opcode qtype qname
ADJUST copy_id
REPLY QR NOERROR
SECTION QUESTION
com. IN NS
SECTION ANSWER
com. IN NS a.gtld-servers.net.
SECTION ADDITIONAL
a.gtld-servers.net. IN A 192.5.6.30
ENTRY_END
ENTRY_BEGIN
MATCH opcode subdomain
ADJUST copy_id copy_query
REPLY QR NOERROR
SECTION QUESTION
example.com. IN A
SECTION AUTHORITY
example.com. IN NS ns.example.com.
SECTION ADDITIONAL
ns.example.com. IN A 1.2.3.4
ENTRY_END
RANGE_END
; ns.example.com.
RANGE_BEGIN 0 100
ADDRESS 1.2.3.4
ENTRY_BEGIN
MATCH opcode qtype qname
ADJUST copy_id
REPLY QR AA REFUSED
SECTION QUESTION
ns.example.com. IN AAAA
ENTRY_END
ENTRY_BEGIN
MATCH opcode qtype qname
ADJUST copy_id
REPLY QR NOERROR
SECTION QUESTION
example.com. IN NS
SECTION ANSWER
example.com. IN NS ns.example.com.
example.com. 3600 IN RRSIG NS 3 2 3600 20070926134150 20070829134150 2854 example.com. MC0CFQCN+qHdJxoI/2tNKwsb08pra/G7aAIUAWA5sDdJTbrXA1/3OaesGBAO3sI= ;{id = 2854}
SECTION ADDITIONAL
ns.example.com. IN A 1.2.3.4
ns.example.com. 3600 IN RRSIG A 3 3 3600 20070926135752 20070829135752 2854 example.com. MC0CFQCMSWxVehgOQLoYclB9PIAbNP229AIUeH0vNNGJhjnZiqgIOKvs1EhzqAo= ;{id = 2854}
ENTRY_END
; response to DNSKEY priming query
ENTRY_BEGIN
MATCH opcode qtype qname
ADJUST copy_id
REPLY QR NOERROR
SECTION QUESTION
example.com. IN DNSKEY
SECTION ANSWER
example.com. 3600 IN DNSKEY 256 3 3 ALXLUsWqUrY3JYER3T4TBJII s70j+sDS/UT2QRp61SE7S3E EXopNXoFE73JLRmvpi/UrOO/Vz4Se 6wXv/CYCKjGw06U4WRgR YXcpEhJROyNapmdIKSx hOzfLVE1gqA0PweZR8d tY3aNQSRn3sPpwJr6Mi /PqQKAMMrZ9ckJpf1+b QMOOvxgzz2U1GS18b3y ZKcgTMEaJzd/GZYzi/B N2DzQ0MsrSwYXfsNLFO Bbs8PJMW4LYIxeeOe6rUgkWOF 7CC9Dh/dduQ1QrsJhmZAEFfd6ByYV+ ;{id = 2854 (zsk), size = 1688b}
example.com. 3600 IN RRSIG DNSKEY 3 2 3600 20070926134802 20070829134802 2854 example.com. MCwCFG1yhRNtTEa3Eno2zhVVuy2EJX3wAhQeLyUp6+UXcpC5qGNu9tkrTEgPUg== ;{id = 2854}
SECTION AUTHORITY
example.com. IN NS ns.example.com.
example.com. 3600 IN RRSIG NS 3 2 3600 20070926134150 20070829134150 2854 example.com. MC0CFQCN+qHdJxoI/2tNKwsb08pra/G7aAIUAWA5sDdJTbrXA1/3OaesGBAO3sI= ;{id = 2854}
SECTION ADDITIONAL
ns.example.com. IN A 1.2.3.4
ns.example.com. 3600 IN RRSIG A 3 3 3600 20070926135752 20070829135752 2854 example.com. MC0CFQCMSWxVehgOQLoYclB9PIAbNP229AIUeH0vNNGJhjnZiqgIOKvs1EhzqAo= ;{id = 2854}
ENTRY_END
; response to query of interest
ENTRY_BEGIN
MATCH opcode qtype qname
ADJUST copy_id
REPLY QR NOERROR
SECTION QUESTION
www.example.com. IN A
SECTION AUTHORITY
example.com. IN SOA ns.example.com. hostmaster.example.com. 2007090400 28800 7200 604800 18000
example.com. 3600 IN RRSIG SOA 3 2 3600 20070926135752 20070829135752 2854 example.com. MC0CFQCM6lsu9byZIQ1yYjJmyYfFWM2RWAIUcR5t84r2La824oWCkLjmHXRQlco= ;{id = 2854}
; NODATA response. H(www.example.com.) = s1unhcti19bkdr98fegs0v46mbu3t4m3
s1unhcti19bkdr98fegs0v46mbu3t4m3.example.com. IN NSEC3 1 1 123 aabb00123456bbccdd s1unhcti19bkdr98fegs0v46mbu3t4m4 MX RRSIG
s1unhcti19bkdr98fegs0v46mbu3t4m3.example.com. 3600 IN RRSIG NSEC3 3 3 3600 20070926135752 20070829135752 2854 example.com. MCwCFE/a24nsY2luhQmZjY/ObAIgNSMkAhQWd4MUOUVK55bD6AbMHWrDA0yvEA== ;{id = 2854}
ENTRY_END
; refer to server one down
ENTRY_BEGIN
MATCH opcode qtype qname
ADJUST copy_id
REPLY QR NOERROR
SECTION QUESTION
www.sub.example.com. IN A
SECTION AUTHORITY
sub.example.com. IN NS ns.sub.example.com.
; proof that there is no DS here.
;sub.example.com. 3600 IN DS 2854 DSA 1 be4d46cd7489cce25a31af0dff2968ce0425dd31
;sub.example.com. 3600 IN RRSIG DS 3 3 3600 20070926135752 20070829135752 2854 example.com. MC0CFQC1WMTfb25sTgeUEXCFR4+YiJqecwIUc2R/jrO4amyQxovSnld2reg8eyo= ;{id = 2854}
; sub.example.com. -> 8r1f0ieoutlnjc03meng9e3bn2n0o9pd.
8r1f0ieoutlnjc03meng9e3bn2n0o9pd.example.com. IN NSEC3 1 1 123 aabb00123456bbccdd 8r1f0ieoutlnjc03meng9e3bn3n0o9pd NS RRSIG
; bad signature:
8r1f0ieoutlnjc03meng9e3bn2n0o9pd.example.com. 3600 IN RRSIG NSEC3 3 3 3600 20010926135752 20010829135752 2854 example.com. MC0CFEC78oZJjqlV6kVyQb4X0o6tsUpUAhUAk+bgth7eeN+aO8ts2+yLSyzSX9g= ;{id = 2854}
;8r1f0ieoutlnjc03meng9e3bn2n0o9pd.example.com. 3600 IN RRSIG NSEC3 3 3 3600 20070926135752 20070829135752 2854 example.com. MC0CFEC78oZJjqlV6kVyQb4X0o6tsUpUAhUAk+bgth7eeN+aO8ts2+yLSyzSX9g= ;{id = 2854}
SECTION ADDITIONAL
ns.sub.example.com. IN A 1.2.3.10
ENTRY_END
ENTRY_BEGIN
MATCH opcode qtype qname
ADJUST copy_id
REPLY QR NOERROR
SECTION QUESTION
sub.example.com. IN DS
SECTION AUTHORITY
; proof that there is no DS here.
;sub.example.com. 3600 IN DS 2854 DSA 1 be4d46cd7489cce25a31af0dff2968ce0425dd31
;sub.example.com. 3600 IN RRSIG DS 3 3 3600 20070926135752 20070829135752 2854 example.com. MC0CFQC1WMTfb25sTgeUEXCFR4+YiJqecwIUc2R/jrO4amyQxovSnld2reg8eyo= ;{id = 2854}
; sub.example.com. -> 8r1f0ieoutlnjc03meng9e3bn2n0o9pd.
8r1f0ieoutlnjc03meng9e3bn2n0o9pd.example.com. IN NSEC3 1 1 123 aabb00123456bbccdd 8r1f0ieoutlnjc03meng9e3bn3n0o9pd NS RRSIG
; bad signature
8r1f0ieoutlnjc03meng9e3bn2n0o9pd.example.com. 3600 IN RRSIG NSEC3 3 3 3600 20010926135752 20010829135752 2854 example.com. MC0CFEC78oZJjqlV6kVyQb4X0o6tsUpUAhUAk+bgth7eeN+aO8ts2+yLSyzSX9g= ;{id = 2854}
;8r1f0ieoutlnjc03meng9e3bn2n0o9pd.example.com. 3600 IN RRSIG NSEC3 3 3 3600 20070926135752 20070829135752 2854 example.com. MC0CFEC78oZJjqlV6kVyQb4X0o6tsUpUAhUAk+bgth7eeN+aO8ts2+yLSyzSX9g= ;{id = 2854}
ENTRY_END
RANGE_END
; ns.sub.example.com.
RANGE_BEGIN 0 100
ADDRESS 1.2.3.10
ENTRY_BEGIN
MATCH opcode qtype qname
ADJUST copy_id
REPLY QR REFUSED
SECTION QUESTION
sub.example.com. IN NS
SECTION ANSWER
ENTRY_END
; response to DNSKEY priming query
ENTRY_BEGIN
MATCH opcode qtype qname
ADJUST copy_id
REPLY QR NOERROR
SECTION QUESTION
sub.example.com. IN DNSKEY
SECTION ANSWER
sub.example.com. 3600 IN DNSKEY 256 3 3 ALXLUsWqUrY3JYER3T4TBJII s70j+sDS/UT2QRp61SE7S3E EXopNXoFE73JLRmvpi/UrOO/Vz4Se 6wXv/CYCKjGw06U4WRgR YXcpEhJROyNapmdIKSx hOzfLVE1gqA0PweZR8d tY3aNQSRn3sPpwJr6Mi /PqQKAMMrZ9ckJpf1+b QMOOvxgzz2U1GS18b3y ZKcgTMEaJzd/GZYzi/B N2DzQ0MsrSwYXfsNLFO Bbs8PJMW4LYIxeeOe6rUgkWOF 7CC9Dh/dduQ1QrsJhmZAEFfd6ByYV+ ;{id = 2854 (zsk), size = 1688b}
sub.example.com. 3600 IN RRSIG DNSKEY 3 3 3600 20070926135752 20070829135752 2854 sub.example.com. MCwCFBznBTYM/SrdUnjQdBnLtRO79KAaAhQReG5nRuL7Xsdf6D0KKwPa1GpWyQ== ;{id = 2854}
ENTRY_END
ENTRY_BEGIN
MATCH opcode qtype qname
ADJUST copy_id
REPLY QR NOERROR
SECTION QUESTION
www.sub.example.com. IN A
SECTION ANSWER
www.sub.example.com. IN A 1.2.3.123
www.sub.example.com. 3600 IN RRSIG A 3 4 3600 20070926135752 20070829135752 2854 sub.example.com. MC0CFEExteiCsLkRi/md6o5K8BhRJAKFAhUAgg2tkvwaDn8Xbm9q+5xnjvgIB8k= ;{id = 2854}
ENTRY_END
RANGE_END
STEP 1 QUERY
ENTRY_BEGIN
REPLY RD DO
SECTION QUESTION
www.sub.example.com. IN A
ENTRY_END
; recursion happens here.
STEP 10 CHECK_ANSWER
ENTRY_BEGIN
MATCH all
REPLY QR RD RA SERVFAIL
SECTION QUESTION
www.sub.example.com. IN A
SECTION ANSWER
SECTION AUTHORITY
SECTION ADDITIONAL
ENTRY_END
SCENARIO_END

191
testdata/val_secds_nosig.rpl vendored Normal file
View file

@ -0,0 +1,191 @@
; config options
; The island of trust is at example.com
server:
trust-anchor: "example.com. 3600 IN DS 2854 3 1 46e4ffc6e9a4793b488954bd3f0cc6af0dfb201b"
val-override-date: "20070916134226"
target-fetch-policy: "0 0 0 0 0"
stub-zone:
name: "."
stub-addr: 193.0.14.129 # K.ROOT-SERVERS.NET.
CONFIG_END
SCENARIO_BEGIN Test validator with no signatures after secure delegation
; K.ROOT-SERVERS.NET.
RANGE_BEGIN 0 100
ADDRESS 193.0.14.129
ENTRY_BEGIN
MATCH opcode qtype qname
ADJUST copy_id
REPLY QR NOERROR
SECTION QUESTION
. IN NS
SECTION ANSWER
. IN NS K.ROOT-SERVERS.NET.
SECTION ADDITIONAL
K.ROOT-SERVERS.NET. IN A 193.0.14.129
ENTRY_END
ENTRY_BEGIN
MATCH opcode subdomain
ADJUST copy_id copy_query
REPLY QR NOERROR
SECTION QUESTION
com. IN A
SECTION AUTHORITY
com. IN NS a.gtld-servers.net.
SECTION ADDITIONAL
a.gtld-servers.net. IN A 192.5.6.30
ENTRY_END
RANGE_END
; a.gtld-servers.net.
RANGE_BEGIN 0 100
ADDRESS 192.5.6.30
ENTRY_BEGIN
MATCH opcode qtype qname
ADJUST copy_id
REPLY QR NOERROR
SECTION QUESTION
com. IN NS
SECTION ANSWER
com. IN NS a.gtld-servers.net.
SECTION ADDITIONAL
a.gtld-servers.net. IN A 192.5.6.30
ENTRY_END
ENTRY_BEGIN
MATCH opcode subdomain
ADJUST copy_id copy_query
REPLY QR NOERROR
SECTION QUESTION
example.com. IN A
SECTION AUTHORITY
example.com. IN NS ns.example.com.
SECTION ADDITIONAL
ns.example.com. IN A 1.2.3.4
ENTRY_END
RANGE_END
; ns.example.com.
RANGE_BEGIN 0 100
ADDRESS 1.2.3.4
ENTRY_BEGIN
MATCH opcode qtype qname
ADJUST copy_id
REPLY QR NOERROR
SECTION QUESTION
example.com. IN NS
SECTION ANSWER
example.com. IN NS ns.example.com.
example.com. 3600 IN RRSIG NS 3 2 3600 20070926134150 20070829134150 2854 example.com. MC0CFQCN+qHdJxoI/2tNKwsb08pra/G7aAIUAWA5sDdJTbrXA1/3OaesGBAO3sI= ;{id = 2854}
SECTION ADDITIONAL
ns.example.com. IN A 1.2.3.4
ns.example.com. 3600 IN RRSIG A 3 3 3600 20070926135752 20070829135752 2854 example.com. MC0CFQCMSWxVehgOQLoYclB9PIAbNP229AIUeH0vNNGJhjnZiqgIOKvs1EhzqAo= ;{id = 2854}
ENTRY_END
; response to DNSKEY priming query
ENTRY_BEGIN
MATCH opcode qtype qname
ADJUST copy_id
REPLY QR NOERROR
SECTION QUESTION
example.com. IN DNSKEY
SECTION ANSWER
example.com. 3600 IN DNSKEY 256 3 3 ALXLUsWqUrY3JYER3T4TBJII s70j+sDS/UT2QRp61SE7S3E EXopNXoFE73JLRmvpi/UrOO/Vz4Se 6wXv/CYCKjGw06U4WRgR YXcpEhJROyNapmdIKSx hOzfLVE1gqA0PweZR8d tY3aNQSRn3sPpwJr6Mi /PqQKAMMrZ9ckJpf1+b QMOOvxgzz2U1GS18b3y ZKcgTMEaJzd/GZYzi/B N2DzQ0MsrSwYXfsNLFO Bbs8PJMW4LYIxeeOe6rUgkWOF 7CC9Dh/dduQ1QrsJhmZAEFfd6ByYV+ ;{id = 2854 (zsk), size = 1688b}
example.com. 3600 IN RRSIG DNSKEY DSA 2 3600 20070926134150 20070829134150 2854 example.com. MCwCFBQRtlR4BEv9ohi+PGFjp+AHsJuHAhRCvz0shggvnvI88DFnBDCczHUcVA== ;{id = 2854}
SECTION AUTHORITY
example.com. IN NS ns.example.com.
example.com. 3600 IN RRSIG NS 3 2 3600 20070926134150 20070829134150 2854 example.com. MC0CFQCN+qHdJxoI/2tNKwsb08pra/G7aAIUAWA5sDdJTbrXA1/3OaesGBAO3sI= ;{id = 2854}
SECTION ADDITIONAL
ns.example.com. IN A 1.2.3.4
ns.example.com. 3600 IN RRSIG A 3 3 3600 20070926135752 20070829135752 2854 example.com. MC0CFQCMSWxVehgOQLoYclB9PIAbNP229AIUeH0vNNGJhjnZiqgIOKvs1EhzqAo= ;{id = 2854}
ENTRY_END
; response for delegation to sub.example.com.
ENTRY_BEGIN
MATCH opcode subdomain
ADJUST copy_id copy_query
REPLY QR NOERROR
SECTION QUESTION
sub.example.com. IN A
SECTION ANSWER
SECTION AUTHORITY
sub.example.com. IN NS ns.sub.example.com.
sub.example.com. 3600 IN DS 30899 RSASHA1 1 f7ed618f24d5e5202927e1d27bc2e84a141cb4b3
sub.example.com. 3600 IN RRSIG DS 3 3 3600 20070926134150 20070829134150 2854 example.com. MCwCFCW3ix0GD4BSvNLWIbROCJt5DAW9AhRt/kg9kBKJ20UBUdumrBUHqnskdA== ;{id = 2854}
SECTION ADDITIONAL
ns.sub.example.com. IN A 1.2.3.6
ENTRY_END
RANGE_END
; ns.sub.example.com.
RANGE_BEGIN 0 100
ADDRESS 1.2.3.6
ENTRY_BEGIN
MATCH opcode qtype qname
ADJUST copy_id
REPLY QR NOERROR
SECTION QUESTION
sub.example.com. IN NS
SECTION ANSWER
sub.example.com. IN NS ns.sub.example.com.
;sub.example.com. 3600 IN RRSIG NS 5 3 3600 20070926134150 20070829134150 30899 sub.example.com. wcpHeBILHfo8C9uxMhcW03gcURZeUffiKdSTb50ZjzTHgMNhRyMfpcvSpXEd9548A9UTmWKeLZChfr5Z/glONw== ;{id = 30899}
SECTION ADDITIONAL
ns.sub.example.com. IN A 1.2.3.6
;ns.sub.example.com. 3600 IN RRSIG A 5 4 3600 20070926134150 20070829134150 30899 sub.example.com. UF7shD/gt1FOp2UHgLTNbPzVykklSXFMEtJ1xD+Hholwf/PIzd7zoaIttIYibNa4fUXCqMg22H9P7MRhfmFe6g== ;{id = 30899}
ENTRY_END
; response to DNSKEY priming query
; sub.example.com. 3600 IN DS 30899 RSASHA1 1 f7ed618f24d5e5202927e1d27bc2e84a141cb4b3
ENTRY_BEGIN
MATCH opcode qtype qname
ADJUST copy_id
REPLY QR NOERROR
SECTION QUESTION
sub.example.com. IN DNSKEY
SECTION ANSWER
sub.example.com. 3600 IN DNSKEY 256 3 5 AQPQ41chR9DEHt/aIzIFAqanbDlRflJoRs5yz1jFsoRIT7dWf0r+PeDuewdxkszNH6wnU4QL8pfKFRh5PIYVBLK3 ;{id = 30899 (zsk), size = 512b}
;sub.example.com. 3600 IN RRSIG DNSKEY 5 3 3600 20070926134150 20070829134150 30899 sub.example.com. uNGp99iznjD7oOX02XnQbDnbg75UwBHRvZSKYUorTKvPUnCWMHKdRsQ+mf+Fx3GZ+Fz9BVjoCmQqpnfgXLEYqw== ;{id = 30899}
SECTION AUTHORITY
sub.example.com. IN NS ns.sub.example.com.
;sub.example.com. 3600 IN RRSIG NS 5 3 3600 20070926134150 20070829134150 30899 sub.example.com. wcpHeBILHfo8C9uxMhcW03gcURZeUffiKdSTb50ZjzTHgMNhRyMfpcvSpXEd9548A9UTmWKeLZChfr5Z/glONw== ;{id = 30899}
SECTION ADDITIONAL
ns.sub.example.com. IN A 1.2.3.6
;ns.sub.example.com. 3600 IN RRSIG A 5 4 3600 20070926134150 20070829134150 30899 sub.example.com. UF7shD/gt1FOp2UHgLTNbPzVykklSXFMEtJ1xD+Hholwf/PIzd7zoaIttIYibNa4fUXCqMg22H9P7MRhfmFe6g== ;{id = 30899}
ENTRY_END
; response to query of interest
ENTRY_BEGIN
MATCH opcode qtype qname
ADJUST copy_id
REPLY QR NOERROR
SECTION QUESTION
www.sub.example.com. IN A
SECTION ANSWER
www.sub.example.com. IN A 11.11.11.11
;www.sub.example.com. 3600 IN RRSIG A 5 4 3600 20070926134150 20070829134150 30899 sub.example.com. 0DqqRfRtm7VSEQ4mmBbzrKRqQAay3JAE8DPDGmjtokrrjN9F1G/HxozDV7bjdIh2EChlQea8FPwf/GepJMUVxg== ;{id = 30899}
SECTION AUTHORITY
SECTION ADDITIONAL
ENTRY_END
RANGE_END
STEP 1 QUERY
ENTRY_BEGIN
REPLY RD DO
SECTION QUESTION
www.sub.example.com. IN A
ENTRY_END
; recursion happens here.
STEP 10 CHECK_ANSWER
ENTRY_BEGIN
MATCH all
REPLY QR RD RA SERVFAIL
SECTION QUESTION
www.sub.example.com. IN A
ENTRY_END
SCENARIO_END

View file

@ -946,10 +946,11 @@ static int
verify_dnskey(struct module_env* env, struct val_env* ve,
struct trust_anchor* tp, struct ub_packed_rrset_key* rrset)
{
char* reason = NULL;
if(tp->ds_rrset) {
/* verify with ds, any will do to prime autotrust */
enum sec_status sec = val_verify_DNSKEY_with_DS(
env, ve, rrset, tp->ds_rrset);
env, ve, rrset, tp->ds_rrset, &reason);
verbose(VERB_ALGO, "autotrust: validate DNSKEY with DS: %s",
sec_status_to_string(sec));
if(sec == sec_status_secure) {
@ -959,7 +960,7 @@ verify_dnskey(struct module_env* env, struct val_env* ve,
if(tp->dnskey_rrset) {
/* verify with keys */
enum sec_status sec = val_verify_rrset(env, ve, rrset,
tp->dnskey_rrset);
tp->dnskey_rrset, &reason);
verbose(VERB_ALGO, "autotrust: validate DNSKEY with keys: %s",
sec_status_to_string(sec));
if(sec == sec_status_secure) {
@ -995,9 +996,11 @@ rr_is_selfsigned_revoked(struct module_env* env, struct val_env* ve,
struct ub_packed_rrset_key* dnskey_rrset, size_t i)
{
enum sec_status sec;
char* reason = NULL;
verbose(VERB_ALGO, "seen REVOKE flag, check self-signed, rr %d",
(int)i);
sec = dnskey_verify_rrset(env, ve, dnskey_rrset, dnskey_rrset, i);
sec = dnskey_verify_rrset(env, ve, dnskey_rrset, dnskey_rrset, i,
&reason);
return (sec == sec_status_secure);
}

View file

@ -183,6 +183,7 @@ val_nsec_prove_nodata_dsreply(struct module_env* env, struct val_env* ve,
uint8_t* wc = NULL, *ce = NULL;
int valid_nsec = 0;
struct ub_packed_rrset_key* wc_nsec = NULL;
char* reason = NULL;
/* If we have a NSEC at the same name, it must prove one
* of two things
@ -190,7 +191,7 @@ val_nsec_prove_nodata_dsreply(struct module_env* env, struct val_env* ve,
* 1) this is a delegation point and there is no DS
* 2) this is not a delegation point */
if(nsec) {
sec = val_verify_rrset_entry(env, ve, nsec, kkey);
sec = val_verify_rrset_entry(env, ve, nsec, kkey, &reason);
if(sec != sec_status_secure) {
verbose(VERB_ALGO, "NSEC RRset for the "
"referral did not verify.");
@ -219,7 +220,8 @@ val_nsec_prove_nodata_dsreply(struct module_env* env, struct val_env* ve,
i++) {
if(rep->rrsets[i]->rk.type != htons(LDNS_RR_TYPE_NSEC))
continue;
sec = val_verify_rrset_entry(env, ve, rep->rrsets[i], kkey);
sec = val_verify_rrset_entry(env, ve, rep->rrsets[i], kkey,
&reason);
if(sec != sec_status_secure) {
verbose(VERB_ALGO, "NSEC for empty non-terminal "
"did not verify.");

View file

@ -1245,10 +1245,11 @@ list_is_secure(struct module_env* env, struct val_env* ve,
{
size_t i;
enum sec_status sec;
char* reason = NULL;
for(i=0; i<num; i++) {
if(list[i]->rk.type != htons(LDNS_RR_TYPE_NSEC3))
continue;
sec = val_verify_rrset_entry(env, ve, list[i], kkey);
sec = val_verify_rrset_entry(env, ve, list[i], kkey, &reason);
if(sec != sec_status_secure) {
verbose(VERB_ALGO, "NSEC3 did not verify");
return 0;

View file

@ -461,25 +461,28 @@ dnskeyset_needs(struct ub_packed_rrset_key* dnskey, uint8_t needs[])
enum sec_status
dnskeyset_verify_rrset(struct module_env* env, struct val_env* ve,
struct ub_packed_rrset_key* rrset, struct ub_packed_rrset_key* dnskey)
struct ub_packed_rrset_key* rrset, struct ub_packed_rrset_key* dnskey,
char** reason)
{
enum sec_status sec;
size_t i, num, numneeds;
rbtree_t* sortree = NULL;
/* make sure that for all DNSKEY algorithms there are valid sigs */
uint8_t needs[256]; /* 1 if need sig for that algorithm */
int sawbogus = 0;
num = rrset_get_sigcount(rrset);
if(num == 0) {
verbose(VERB_QUERY, "rrset failed to verify due to a lack of "
"signatures");
*reason = "no signatures";
return sec_status_bogus;
}
numneeds = dnskeyset_needs(dnskey, needs);
for(i=0; i<num; i++) {
sec = dnskeyset_verify_rrset_sig(env, ve, *env->now, rrset,
dnskey, i, &sortree);
dnskey, i, &sortree, reason);
/* see which algorithm has been fixed up */
if(sec == sec_status_secure) {
uint8_t a = (uint8_t)rrset_get_sig_algo(rrset, i);
@ -490,19 +493,23 @@ dnskeyset_verify_rrset(struct module_env* env, struct val_env* ve,
return sec;
}
}
else if(sec == sec_status_bogus)
sawbogus = 1;
}
verbose(VERB_ALGO, "rrset failed to verify: no valid signatures for "
"%d algorithms", (int)numneeds);
if(!sawbogus)
*reason = "no signatures for all algorithms";
return sec_status_bogus;
}
enum sec_status
dnskey_verify_rrset(struct module_env* env, struct val_env* ve,
struct ub_packed_rrset_key* rrset, struct ub_packed_rrset_key* dnskey,
size_t dnskey_idx)
size_t dnskey_idx, char** reason)
{
enum sec_status sec;
size_t i, num;
size_t i, num, numchecked = 0;
rbtree_t* sortree = NULL;
int buf_canon = 0;
uint16_t tag = dnskey_calc_keytag(dnskey, dnskey_idx);
@ -512,6 +519,7 @@ dnskey_verify_rrset(struct module_env* env, struct val_env* ve,
if(num == 0) {
verbose(VERB_QUERY, "rrset failed to verify due to a lack of "
"signatures");
*reason = "no signatures";
return sec_status_bogus;
}
for(i=0; i<num; i++) {
@ -522,11 +530,13 @@ dnskey_verify_rrset(struct module_env* env, struct val_env* ve,
buf_canon = 0;
sec = dnskey_verify_rrset_sig(env->scratch,
env->scratch_buffer, ve, *env->now, rrset,
dnskey, dnskey_idx, i, &sortree, &buf_canon);
dnskey, dnskey_idx, i, &sortree, &buf_canon, reason);
if(sec == sec_status_secure)
return sec;
numchecked ++;
}
verbose(VERB_ALGO, "rrset failed to verify: all signatures are bogus");
if(!numchecked) *reason = "signatures from unknown keys";
return sec_status_bogus;
}
@ -534,7 +544,7 @@ enum sec_status
dnskeyset_verify_rrset_sig(struct module_env* env, struct val_env* ve,
uint32_t now, struct ub_packed_rrset_key* rrset,
struct ub_packed_rrset_key* dnskey, size_t sig_idx,
struct rbtree_t** sortree)
struct rbtree_t** sortree, char** reason)
{
/* find matching keys and check them */
enum sec_status sec = sec_status_bogus;
@ -555,11 +565,12 @@ dnskeyset_verify_rrset_sig(struct module_env* env, struct val_env* ve,
/* see if key verifies */
sec = dnskey_verify_rrset_sig(env->scratch,
env->scratch_buffer, ve, now, rrset, dnskey, i,
sig_idx, sortree, &buf_canon);
sig_idx, sortree, &buf_canon, reason);
if(sec == sec_status_secure)
return sec;
}
if(numchecked == 0) {
*reason = "signatures from unknown keys";
verbose(VERB_QUERY, "verify: could not find appropriate key");
return sec_status_bogus;
}
@ -1075,7 +1086,7 @@ sigdate_error(const char* str, int32_t expi, int32_t incep, int32_t now)
/** check rrsig dates */
static int
check_dates(struct val_env* ve, uint32_t unow,
uint8_t* expi_p, uint8_t* incep_p)
uint8_t* expi_p, uint8_t* incep_p, char** reason)
{
/* read out the dates */
int32_t expi, incep, now;
@ -1094,6 +1105,7 @@ check_dates(struct val_env* ve, uint32_t unow,
if(incep - expi > 0) {
sigdate_error("verify: inception after expiration, "
"signature bad", expi, incep, now);
*reason = "signature inception after expiration";
return 0;
}
if(incep - now > 0) {
@ -1104,6 +1116,7 @@ check_dates(struct val_env* ve, uint32_t unow,
if(incep - now > skew) {
sigdate_error("verify: signature bad, current time is"
" before inception date", expi, incep, now);
*reason = "signature before inception date";
return 0;
}
sigdate_error("verify warning suspicious signature inception "
@ -1116,6 +1129,7 @@ check_dates(struct val_env* ve, uint32_t unow,
if(now - expi > skew) {
sigdate_error("verify: signature expired", expi,
incep, now);
*reason = "signature expired";
return 0;
}
sigdate_error("verify warning suspicious signature expiration "
@ -1430,7 +1444,7 @@ dnskey_verify_rrset_sig(struct regional* region, ldns_buffer* buf,
struct val_env* ve, uint32_t now,
struct ub_packed_rrset_key* rrset, struct ub_packed_rrset_key* dnskey,
size_t dnskey_idx, size_t sig_idx,
struct rbtree_t** sortree, int* buf_canon)
struct rbtree_t** sortree, int* buf_canon, char** reason)
{
enum sec_status sec;
uint8_t* sig; /* RRSIG rdata */
@ -1447,17 +1461,20 @@ dnskey_verify_rrset_sig(struct regional* region, ldns_buffer* buf,
/* min length of rdatalen, fixed rrsig, root signer, 1 byte sig */
if(siglen < 2+20) {
verbose(VERB_QUERY, "verify: signature too short");
*reason = "signature too short";
return sec_status_bogus;
}
if(!(dnskey_get_flags(dnskey, dnskey_idx) & DNSKEY_BIT_ZSK)) {
verbose(VERB_QUERY, "verify: dnskey without ZSK flag");
*reason = "dnskey without ZSK flag";
return sec_status_bogus;
}
if(dnskey_get_protocol(dnskey, dnskey_idx) != LDNS_DNSSEC_KEYPROTO) {
/* RFC 4034 says DNSKEY PROTOCOL MUST be 3 */
verbose(VERB_QUERY, "verify: dnskey has wrong key protocol");
*reason = "dnskey has wrong protocolnumber";
return sec_status_bogus;
}
@ -1466,15 +1483,18 @@ dnskey_verify_rrset_sig(struct regional* region, ldns_buffer* buf,
signer_len = dname_valid(signer, siglen-2-18);
if(!signer_len) {
verbose(VERB_QUERY, "verify: malformed signer name");
*reason = "signer name malformed";
return sec_status_bogus; /* signer name invalid */
}
if(!dname_subdomain_c(rrset->rk.dname, signer)) {
verbose(VERB_QUERY, "verify: signer name is off-tree");
*reason = "signer name off-tree";
return sec_status_bogus; /* signer name offtree */
}
sigblock = (unsigned char*)signer+signer_len;
if(siglen < 2+18+signer_len+1) {
verbose(VERB_QUERY, "verify: too short, no signature data");
*reason = "signature too short, no signature data";
return sec_status_bogus; /* sig rdf is < 1 byte */
}
sigblock_len = (unsigned int)(siglen - 2 - 18 - signer_len);
@ -1486,6 +1506,7 @@ dnskey_verify_rrset_sig(struct regional* region, ldns_buffer* buf,
signer, 0, 0);
log_nametypeclass(VERB_QUERY, "the key name is",
dnskey->rk.dname, 0, 0);
*reason = "signer name mismatches key name";
return sec_status_bogus;
}
@ -1493,29 +1514,33 @@ dnskey_verify_rrset_sig(struct regional* region, ldns_buffer* buf,
/* memcmp works because type is in network format for rrset */
if(memcmp(sig+2, &rrset->rk.type, 2) != 0) {
verbose(VERB_QUERY, "verify: wrong type covered");
*reason = "signature covers wrong type";
return sec_status_bogus;
}
/* verify keytag and sig algo (possibly again) */
if((int)sig[2+2] != dnskey_get_algo(dnskey, dnskey_idx)) {
verbose(VERB_QUERY, "verify: wrong algorithm");
*reason = "signature has wrong algorithm";
return sec_status_bogus;
}
ktag = htons(dnskey_calc_keytag(dnskey, dnskey_idx));
if(memcmp(sig+2+16, &ktag, 2) != 0) {
verbose(VERB_QUERY, "verify: wrong keytag");
*reason = "signature has wrong keytag";
return sec_status_bogus;
}
/* verify labels is in a valid range */
if((int)sig[2+3] > dname_signame_label_count(rrset->rk.dname)) {
verbose(VERB_QUERY, "verify: labelcount out of range");
*reason = "signature labelcount out of range";
return sec_status_bogus;
}
/* original ttl, always ok */
/* verify inception, expiration dates */
if(!check_dates(ve, now, sig+2+8, sig+2+12)) {
if(!check_dates(ve, now, sig+2+8, sig+2+12, reason)) {
return sec_status_bogus;
}
@ -1544,7 +1569,8 @@ dnskey_verify_rrset_sig(struct regional* region, ldns_buffer* buf,
/* check if TTL is too high - reduce if so */
if(sec == sec_status_secure) {
adjust_ttl(ve, now, rrset, sig+2+4, sig+2+8, sig+2+12);
}
} else if(sec == sec_status_bogus)
*reason = "signature crypto failed";
return sec;
}

View file

@ -146,13 +146,14 @@ uint16_t dnskey_get_flags(struct ub_packed_rrset_key* k, size_t idx);
* @param ve: validator environment, date settings.
* @param rrset: to be validated.
* @param dnskey: DNSKEY rrset, keyset to try.
* @param reason: if bogus, a string returned, fixed or alloced in scratch.
* @return SECURE if one key in the set verifies one rrsig.
* UNCHECKED on allocation errors, unsupported algorithms, malformed data,
* and BOGUS on verification failures (no keys match any signatures).
*/
enum sec_status dnskeyset_verify_rrset(struct module_env* env,
struct val_env* ve, struct ub_packed_rrset_key* rrset,
struct ub_packed_rrset_key* dnskey);
struct ub_packed_rrset_key* dnskey, char** reason);
/**
* verify rrset against one specific dnskey (from rrset)
@ -161,12 +162,13 @@ enum sec_status dnskeyset_verify_rrset(struct module_env* env,
* @param rrset: to be validated.
* @param dnskey: DNSKEY rrset, keyset.
* @param dnskey_idx: which key from the rrset to try.
* @param reason: if bogus, a string returned, fixed or alloced in scratch.
* @return secure if *this* key signs any of the signatures on rrset.
* unchecked on error or and bogus on bad signature.
*/
enum sec_status dnskey_verify_rrset(struct module_env* env,
struct val_env* ve, struct ub_packed_rrset_key* rrset,
struct ub_packed_rrset_key* dnskey, size_t dnskey_idx);
struct ub_packed_rrset_key* dnskey, size_t dnskey_idx, char** reason);
/**
* verify rrset, with dnskey rrset, for a specific rrsig in rrset
@ -178,13 +180,14 @@ enum sec_status dnskey_verify_rrset(struct module_env* env,
* @param sig_idx: which signature to try to validate.
* @param sortree: reused sorted order. Stored in region. Pass NULL at start,
* and for a new rrset.
* @param reason: if bogus, a string returned, fixed or alloced in scratch.
* @return secure if any key signs *this* signature. bogus if no key signs it,
* or unchecked on error.
*/
enum sec_status dnskeyset_verify_rrset_sig(struct module_env* env,
struct val_env* ve, uint32_t now, struct ub_packed_rrset_key* rrset,
struct ub_packed_rrset_key* dnskey, size_t sig_idx,
struct rbtree_t** sortree);
struct rbtree_t** sortree, char** reason);
/**
* verify rrset, with specific dnskey(from set), for a specific rrsig
@ -201,6 +204,7 @@ enum sec_status dnskeyset_verify_rrset_sig(struct module_env* env,
* @param buf_canon: if true, the buffer is already canonical.
* pass false at start. pass old value only for same rrset and same
* signature (but perhaps different key) for reuse.
* @param reason: if bogus, a string returned, fixed or alloced in scratch.
* @return secure if this key signs this signature. unchecked on error or
* bogus if it did not validate.
*/
@ -208,7 +212,7 @@ enum sec_status dnskey_verify_rrset_sig(struct regional* region,
ldns_buffer* buf, struct val_env* ve, uint32_t now,
struct ub_packed_rrset_key* rrset, struct ub_packed_rrset_key* dnskey,
size_t dnskey_idx, size_t sig_idx,
struct rbtree_t** sortree, int* buf_canon);
struct rbtree_t** sortree, int* buf_canon, char** reason);
/**
* canonical compare for two tree entries

View file

@ -51,6 +51,7 @@
#include "util/net_help.h"
#include "util/module.h"
#include "util/regional.h"
#include "util/config_file.h"
enum val_classification
val_classify_response(uint16_t query_flags, struct query_info* origqinf,
@ -303,7 +304,8 @@ rrset_get_ttl(struct ub_packed_rrset_key* rrset)
enum sec_status
val_verify_rrset(struct module_env* env, struct val_env* ve,
struct ub_packed_rrset_key* rrset, struct ub_packed_rrset_key* keys)
struct ub_packed_rrset_key* rrset, struct ub_packed_rrset_key* keys,
char** reason)
{
enum sec_status sec;
struct packed_rrset_data* d = (struct packed_rrset_data*)rrset->
@ -325,7 +327,7 @@ val_verify_rrset(struct module_env* env, struct val_env* ve,
}
log_nametypeclass(VERB_ALGO, "verify rrset", rrset->rk.dname,
ntohs(rrset->rk.type), ntohs(rrset->rk.rrset_class));
sec = dnskeyset_verify_rrset(env, ve, rrset, keys);
sec = dnskeyset_verify_rrset(env, ve, rrset, keys, reason);
verbose(VERB_ALGO, "verify result: %s", sec_status_to_string(sec));
regional_free_all(env->scratch);
@ -357,7 +359,8 @@ val_verify_rrset(struct module_env* env, struct val_env* ve,
enum sec_status
val_verify_rrset_entry(struct module_env* env, struct val_env* ve,
struct ub_packed_rrset_key* rrset, struct key_entry_key* kkey)
struct ub_packed_rrset_key* rrset, struct key_entry_key* kkey,
char** reason)
{
/* temporary dnskey rrset-key */
struct ub_packed_rrset_key dnskey;
@ -370,7 +373,7 @@ val_verify_rrset_entry(struct module_env* env, struct val_env* ve,
dnskey.rk.dname_len = kkey->namelen;
dnskey.entry.key = &dnskey;
dnskey.entry.data = kd->rrset_data;
sec = val_verify_rrset(env, ve, rrset, &dnskey);
sec = val_verify_rrset(env, ve, rrset, &dnskey, reason);
return sec;
}
@ -378,10 +381,10 @@ val_verify_rrset_entry(struct module_env* env, struct val_env* ve,
static enum sec_status
verify_dnskeys_with_ds_rr(struct module_env* env, struct val_env* ve,
struct ub_packed_rrset_key* dnskey_rrset,
struct ub_packed_rrset_key* ds_rrset, size_t ds_idx)
struct ub_packed_rrset_key* ds_rrset, size_t ds_idx, char** reason)
{
enum sec_status sec = sec_status_bogus;
size_t i, num;
size_t i, num, numchecked = 0, numhashok = 0;
num = rrset_get_count(dnskey_rrset);
for(i=0; i<num; i++) {
/* Skip DNSKEYs that don't match the basic criteria. */
@ -391,6 +394,7 @@ verify_dnskeys_with_ds_rr(struct module_env* env, struct val_env* ve,
!= ds_get_keytag(ds_rrset, ds_idx)) {
continue;
}
numchecked++;
verbose(VERB_ALGO, "attempt DS match algo %d keytag %d",
ds_get_key_algo(ds_rrset, ds_idx),
ds_get_keytag(ds_rrset, ds_idx));
@ -402,24 +406,31 @@ verify_dnskeys_with_ds_rr(struct module_env* env, struct val_env* ve,
verbose(VERB_ALGO, "DS match attempt failed");
continue;
}
numhashok++;
verbose(VERB_ALGO, "DS match digest ok, trying signature");
/* Otherwise, we have a match! Make sure that the DNSKEY
* verifies *with this key* */
sec = dnskey_verify_rrset(env, ve, dnskey_rrset,
dnskey_rrset, i);
dnskey_rrset, i, reason);
if(sec == sec_status_secure) {
return sec;
}
/* If it didn't validate with the DNSKEY, try the next one! */
}
if(numchecked == 0)
*reason = "no keys have a DS";
else if(numhashok == 0)
*reason = "DS hash mismatches key";
else if(!*reason)
*reason = "keyset not secured by DNSKEY that matches DS";
return sec_status_bogus;
}
enum sec_status
val_verify_DNSKEY_with_DS(struct module_env* env, struct val_env* ve,
struct ub_packed_rrset_key* dnskey_rrset,
struct ub_packed_rrset_key* ds_rrset)
struct ub_packed_rrset_key* ds_rrset, char** reason)
{
/* as long as this is false, we can consider this DS rrset to be
* equivalent to no DS rrset. */
@ -433,6 +444,7 @@ val_verify_DNSKEY_with_DS(struct module_env* env, struct val_env* ve,
!= 0) {
verbose(VERB_QUERY, "DNSKEY RRset did not match DS RRset "
"by name");
*reason = "DNSKEY RRset did not match DS RRset by name";
return sec_status_bogus;
}
@ -462,7 +474,7 @@ val_verify_DNSKEY_with_DS(struct module_env* env, struct val_env* ve,
has_useful_ds = true;
sec = verify_dnskeys_with_ds_rr(env, ve, dnskey_rrset,
ds_rrset, i);
ds_rrset, i, reason);
if(sec == sec_status_secure) {
verbose(VERB_ALGO, "DS matched DNSKEY.");
return sec_status_secure;
@ -485,10 +497,10 @@ val_verify_DNSKEY_with_DS(struct module_env* env, struct val_env* ve,
struct key_entry_key*
val_verify_new_DNSKEYs(struct regional* region, struct module_env* env,
struct val_env* ve, struct ub_packed_rrset_key* dnskey_rrset,
struct ub_packed_rrset_key* ds_rrset)
struct ub_packed_rrset_key* ds_rrset, char** reason)
{
enum sec_status sec = val_verify_DNSKEY_with_DS(env, ve,
dnskey_rrset, ds_rrset);
dnskey_rrset, ds_rrset, reason);
if(sec == sec_status_secure) {
return key_entry_create_rrset(region,
@ -837,3 +849,117 @@ void val_blacklist(struct sock_list** blacklist, struct regional* region,
sock_list_prepend(blacklist, origin);
else sock_list_merge(blacklist, region, origin);
}
void val_errinf(struct module_qstate* qstate, struct val_qstate* vq,
const char* str)
{
struct config_strlist* p;
if(qstate->env->cfg->val_log_level < 2 || !str)
return;
p = (struct config_strlist*)regional_alloc(qstate->region, sizeof(*p));
if(!p) {
log_err("malloc failure in validator-error-info string");
return;
}
p->next = NULL;
p->str = regional_strdup(qstate->region, str);
if(!p->str) {
log_err("malloc failure in validator-error-info string");
return;
}
/* add at end */
if(vq->errinf) {
struct config_strlist* q = vq->errinf;
while(q->next)
q = q->next;
q->next = p;
} else vq->errinf = p;
}
void val_errinf_origin(struct module_qstate* qstate, struct val_qstate* vq,
struct sock_list *origin)
{
struct sock_list* p;
if(qstate->env->cfg->val_log_level < 2)
return;
for(p=origin; p; p=p->next) {
char buf[256];
if(p == origin)
snprintf(buf, sizeof(buf), "from ");
else snprintf(buf, sizeof(buf), "and from ");
if(p->len == 0)
snprintf(buf+strlen(buf), sizeof(buf)-strlen(buf),
"cache");
else
addr_to_str(&p->addr, p->len, buf+strlen(buf),
sizeof(buf)-strlen(buf));
val_errinf(qstate, vq, buf);
}
}
char* val_errinf_to_str(struct module_qstate* qstate, struct val_qstate* vq)
{
char buf[20480];
char* p = buf;
size_t left = sizeof(buf);
struct config_strlist* s;
char dname[LDNS_MAX_DOMAINLEN+1];
char* t = ldns_rr_type2str(qstate->qinfo.qtype);
char* c = ldns_rr_class2str(qstate->qinfo.qclass);
if(!t || !c) {
free(t);
free(c);
log_err("malloc failure in errinf_to_str");
return NULL;
}
dname_str(qstate->qinfo.qname, dname);
snprintf(p, left, "validation failure <%s %s %s>:", dname, t, c);
free(t);
free(c);
left -= strlen(p); p += strlen(p);
if(!vq->errinf)
snprintf(p, left, " misc failure");
else for(s=vq->errinf; s; s=s->next) {
snprintf(p, left, " %s", s->str);
left -= strlen(p); p += strlen(p);
}
p = strdup(buf);
if(!p)
log_err("malloc failure in errinf_to_str");
return p;
}
void val_errinf_rrset(struct module_qstate* qstate, struct val_qstate* vq,
struct ub_packed_rrset_key *rr)
{
char buf[1024];
char dname[LDNS_MAX_DOMAINLEN+1];
char *t, *c;
if(qstate->env->cfg->val_log_level < 2 || !rr)
return;
t = ldns_rr_type2str(ntohs(rr->rk.type));
c = ldns_rr_class2str(ntohs(rr->rk.rrset_class));
if(!t || !c) {
free(t);
free(c);
log_err("malloc failure in errinf_rrset");
return;
}
dname_str(qstate->qinfo.qname, dname);
snprintf(buf, sizeof(buf), "for <%s %s %s>", dname, t, c);
free(t);
free(c);
val_errinf(qstate, vq, buf);
}
void val_errinf_dname(struct module_qstate* qstate, struct val_qstate* vq,
const char* str, uint8_t* dname)
{
char b[1024];
char buf[LDNS_MAX_DOMAINLEN+1];
if(qstate->env->cfg->val_log_level < 2 || !str || !dname)
return;
dname_str(dname, buf);
snprintf(b, sizeof(b), "%s %s", str, buf);
val_errinf(qstate, vq, b);
}

View file

@ -52,6 +52,8 @@ struct regional;
struct val_anchors;
struct rrset_cache;
struct sock_list;
struct module_qstate;
struct val_qstate;
/**
* Response classifications for the validator. The different types of proofs.
@ -117,10 +119,12 @@ void val_find_signer(enum val_classification subtype,
* @param ve: validator environment (verification settings)
* @param rrset: what to verify
* @param keys: dnskey rrset to verify with.
* @param reason: reason of failure. Fixed string or alloced in scratch.
* @return security status of verification.
*/
enum sec_status val_verify_rrset(struct module_env* env, struct val_env* ve,
struct ub_packed_rrset_key* rrset, struct ub_packed_rrset_key* keys);
struct ub_packed_rrset_key* rrset, struct ub_packed_rrset_key* keys,
char** reason);
/**
* Verify RRset with keys from a keyset.
@ -128,11 +132,12 @@ enum sec_status val_verify_rrset(struct module_env* env, struct val_env* ve,
* @param ve: validator environment (verification settings)
* @param rrset: what to verify
* @param kkey: key_entry to verify with.
* @param reason: reason of failure. Fixed string or alloced in scratch.
* @return security status of verification.
*/
enum sec_status val_verify_rrset_entry(struct module_env* env,
struct val_env* ve, struct ub_packed_rrset_key* rrset,
struct key_entry_key* kkey);
struct key_entry_key* kkey, char** reason);
/**
* Verify DNSKEYs with DS rrset. Like val_verify_new_DNSKEYs but
@ -141,13 +146,14 @@ enum sec_status val_verify_rrset_entry(struct module_env* env,
* @param ve: validator environment (verification settings)
* @param dnskey_rrset: DNSKEY rrset to verify
* @param ds_rrset: DS rrset to verify with.
* @param reason: reason of failure. Fixed string or alloced in scratch.
* @return: sec_status_secure if a DS matches.
* sec_status_insecure if end of trust (i.e., unknown algorithms).
* sec_status_bogus if it fails.
*/
enum sec_status val_verify_DNSKEY_with_DS(struct module_env* env,
struct val_env* ve, struct ub_packed_rrset_key* dnskey_rrset,
struct ub_packed_rrset_key* ds_rrset);
struct ub_packed_rrset_key* ds_rrset, char** reason);
/**
* Verify new DNSKEYs with DS rrset. The DS contains hash values that should
@ -159,6 +165,7 @@ enum sec_status val_verify_DNSKEY_with_DS(struct module_env* env,
* @param ve: validator environment (verification settings)
* @param dnskey_rrset: DNSKEY rrset to verify
* @param ds_rrset: DS rrset to verify with.
* @param reason: reason of failure. Fixed string or alloced in scratch.
* @return a KeyEntry. This will either contain the now trusted
* dnskey_rrset, a "null" key entry indicating that this DS
* rrset/DNSKEY pair indicate an secure end to the island of trust
@ -171,7 +178,7 @@ enum sec_status val_verify_DNSKEY_with_DS(struct module_env* env,
struct key_entry_key* val_verify_new_DNSKEYs(struct regional* region,
struct module_env* env, struct val_env* ve,
struct ub_packed_rrset_key* dnskey_rrset,
struct ub_packed_rrset_key* ds_rrset);
struct ub_packed_rrset_key* ds_rrset, char** reason);
/**
* Determine if DS rrset is usable for validator or not.
@ -301,4 +308,55 @@ const char* val_classification_to_string(enum val_classification subtype);
void val_blacklist(struct sock_list** blacklist, struct regional* region,
struct sock_list* origin, int cross);
/**
* Append text to the error info for validation.
* @param qstate: query state.
* @param vq: validator state.
* @param str: copied into query region and appended.
* Failures to allocate are logged.
*/
void val_errinf(struct module_qstate* qstate, struct val_qstate* vq,
const char* str);
/**
* Append text to error info: from 1.2.3.4
* @param qstate: query state.
* @param vq: validator state.
* @param list: sock list with origin of trouble.
* Every element added.
* If NULL: nothing is added.
* if 0len element: 'from cache' is added.
*/
void val_errinf_origin(struct module_qstate* qstate, struct val_qstate* vq,
struct sock_list *origin);
/**
* Append text to error info: for RRset name type class
* @param qstate: query state.
* @param vq: validator state.
* @param rr: rrset_key.
*/
void val_errinf_rrset(struct module_qstate* qstate, struct val_qstate* vq,
struct ub_packed_rrset_key *rr);
/**
* Append text to error info: str dname
* @param qstate: query state.
* @param vq: validator state.
* @param str: explanation string
* @param dname: the dname.
* @param rr: rrset_key.
*/
void val_errinf_dname(struct module_qstate* qstate, struct val_qstate* vq,
const char* str, uint8_t* dname);
/**
* Create error info in string
* @param qstate: query state. (for query name)
* @param vq: validator state.
* @return string or NULL on malloc failure (already logged).
* This string is malloced and has to be freed by caller.
*/
char* val_errinf_to_str(struct module_qstate* qstate, struct val_qstate* vq);
#endif /* VALIDATOR_VAL_UTILS_H */

View file

@ -409,6 +409,8 @@ prime_trust_anchor(struct module_qstate* qstate, struct val_qstate* vq,
* trusted DNSKEY rrset that signs this response must already have been
* completed.
*
* @param qstate: query state.
* @param vq: validator query state.
* @param env: module env for verify.
* @param ve: validator env for verify.
* @param qchase: query that was made.
@ -419,15 +421,16 @@ prime_trust_anchor(struct module_qstate* qstate, struct val_qstate* vq,
* fail to verify. The message is then set to bogus.
*/
static int
validate_msg_signatures(struct module_env* env, struct val_env* ve,
struct query_info* qchase, struct reply_info* chase_reply,
struct key_entry_key* key_entry)
validate_msg_signatures(struct module_qstate* qstate, struct val_qstate* vq,
struct module_env* env, struct val_env* ve, struct query_info* qchase,
struct reply_info* chase_reply, struct key_entry_key* key_entry)
{
uint8_t* sname;
size_t i, slen;
struct ub_packed_rrset_key* s;
enum sec_status sec;
int dname_seen = 0;
char* reason = NULL;
/* validate the ANSWER section */
for(i=0; i<chase_reply->an_numrrsets; i++) {
@ -448,13 +451,19 @@ validate_msg_signatures(struct module_env* env, struct val_env* ve,
}
/* Verify the answer rrset */
sec = val_verify_rrset_entry(env, ve, s, key_entry);
sec = val_verify_rrset_entry(env, ve, s, key_entry, &reason);
/* If the (answer) rrset failed to validate, then this
* message is BAD. */
if(sec != sec_status_secure) {
log_nametypeclass(VERB_QUERY, "validator: response "
"has failed ANSWER rrset:", s->rk.dname,
ntohs(s->rk.type), ntohs(s->rk.rrset_class));
val_errinf(qstate, vq, reason);
if(ntohs(s->rk.type) == LDNS_RR_TYPE_CNAME)
val_errinf(qstate, vq, "for CNAME");
else if(ntohs(s->rk.type) == LDNS_RR_TYPE_DNAME)
val_errinf(qstate, vq, "for DNAME");
val_errinf_origin(qstate, vq, qstate->reply_origin);
chase_reply->security = sec_status_bogus;
return 0;
}
@ -471,13 +480,16 @@ validate_msg_signatures(struct module_env* env, struct val_env* ve,
for(i=chase_reply->an_numrrsets; i<chase_reply->an_numrrsets+
chase_reply->ns_numrrsets; i++) {
s = chase_reply->rrsets[i];
sec = val_verify_rrset_entry(env, ve, s, key_entry);
sec = val_verify_rrset_entry(env, ve, s, key_entry, &reason);
/* If anything in the authority section fails to be secure,
* we have a bad message. */
if(sec != sec_status_secure) {
log_nametypeclass(VERB_QUERY, "validator: response "
"has failed AUTHORITY rrset:", s->rk.dname,
ntohs(s->rk.type), ntohs(s->rk.rrset_class));
val_errinf(qstate, vq, reason);
val_errinf_rrset(qstate, vq, s);
val_errinf_origin(qstate, vq, qstate->reply_origin);
chase_reply->security = sec_status_bogus;
return 0;
}
@ -493,7 +505,8 @@ validate_msg_signatures(struct module_env* env, struct val_env* ve,
/* leave others unchecked, those get removed later on too */
val_find_rrset_signer(s, &sname, &slen);
if(sname && query_dname_compare(sname, key_entry->name)==0)
(void)val_verify_rrset_entry(env, ve, s, key_entry);
(void)val_verify_rrset_entry(env, ve, s, key_entry,
&reason);
/* the additional section can fail to be secure,
* it is optional, check signature in case we need
* to clean the additional section later. */
@ -1493,6 +1506,15 @@ processValidate(struct module_qstate* qstate, struct val_qstate* vq,
return 1;
}
if(key_entry_isbad(vq->key_entry)) {
log_nametypeclass(VERB_DETAIL, "Could not establish a chain "
"of trust to keys for", vq->key_entry->name,
LDNS_RR_TYPE_DNSKEY, vq->key_entry->key_class);
vq->chase_reply->security = sec_status_bogus;
val_errinf(qstate, vq, "while building chain of trust");
return 1;
}
/* signerName being null is the indicator that this response was
* unsigned */
if(vq->signer_name == NULL) {
@ -1500,14 +1522,8 @@ processValidate(struct module_qstate* qstate, struct val_qstate* vq,
"signer name", &vq->qchase);
verbose(VERB_DETAIL, "Could not establish validation of "
"INSECURE status of unsigned response.");
vq->chase_reply->security = sec_status_bogus;
return 1;
}
if(key_entry_isbad(vq->key_entry)) {
log_nametypeclass(VERB_DETAIL, "Could not establish a chain "
"of trust to keys for", vq->key_entry->name,
LDNS_RR_TYPE_DNSKEY, vq->key_entry->key_class);
val_errinf(qstate, vq, "no signatures");
val_errinf_origin(qstate, vq, qstate->reply_origin);
vq->chase_reply->security = sec_status_bogus;
return 1;
}
@ -1516,7 +1532,7 @@ processValidate(struct module_qstate* qstate, struct val_qstate* vq,
/* check signatures in the message;
* answer and authority must be valid, additional is only checked. */
if(!validate_msg_signatures(qstate->env, ve, &vq->qchase,
if(!validate_msg_signatures(qstate, vq, qstate->env, ve, &vq->qchase,
vq->chase_reply, vq->key_entry)) {
/* workaround bad recursor out there that truncates (even
* with EDNS4k) to 512 by removing RRSIG from auth section
@ -1533,6 +1549,7 @@ processValidate(struct module_qstate* qstate, struct val_qstate* vq,
vq->chase_reply->ar_numrrsets = 0;
vq->chase_reply->rrset_count =
vq->chase_reply->an_numrrsets;
vq->errinf = NULL;
}
else {
verbose(VERB_DETAIL, "Validate: message contains "
@ -1610,6 +1627,14 @@ processValidate(struct module_qstate* qstate, struct val_qstate* vq,
log_err("validate: unhandled response subtype: %d",
subtype);
}
if(vq->chase_reply->security == sec_status_bogus) {
if(subtype == VAL_CLASS_POSITIVE)
val_errinf(qstate, vq, "wildcard");
else val_errinf(qstate, vq,
val_classification_to_string(subtype));
val_errinf(qstate, vq, "proof failed");
val_errinf_origin(qstate, vq, qstate->reply_origin);
}
return 1;
}
@ -1860,7 +1885,14 @@ processFinished(struct module_qstate* qstate, struct val_qstate* vq,
vq->orig_msg->rep->ttl = ve->bogus_ttl;
if(qstate->env->cfg->val_log_level >= 1) {
log_query_info(0, "validation failure", &qstate->qinfo);
if(qstate->env->cfg->val_log_level < 2)
log_query_info(0, "validation failure",
&qstate->qinfo);
else {
char* err = val_errinf_to_str(qstate, vq);
if(err) log_info(err);
free(err);
}
}
/* If we are in permissive mode, bogus gets indeterminate */
if(ve->permissive_mode)
@ -2118,15 +2150,19 @@ primeResponseToKE(struct ub_packed_rrset_key* dnskey_rrset,
struct val_env* ve = (struct val_env*)qstate->env->modinfo[id];
struct key_entry_key* kkey = NULL;
enum sec_status sec = sec_status_unchecked;
char* reason = NULL;
if(!dnskey_rrset) {
log_nametypeclass(VERB_OPS, "failed to prime trust anchor -- "
"could not fetch DNSKEY rrset",
ta->name, LDNS_RR_TYPE_DNSKEY, ta->dclass);
if(qstate->env->cfg->harden_dnssec_stripped)
if(qstate->env->cfg->harden_dnssec_stripped) {
struct val_qstate* vq = (struct val_qstate*)
qstate->minfo[id];
val_errinf(qstate, vq, "no DNSKEY rrset");
kkey = key_entry_create_bad(qstate->region, ta->name,
ta->namelen, ta->dclass);
else kkey = key_entry_create_null(qstate->region, ta->name,
} else kkey = key_entry_create_null(qstate->region, ta->name,
ta->namelen, ta->dclass, NULL_KEY_TTL,
*qstate->env->now);
if(!kkey) {
@ -2138,7 +2174,7 @@ primeResponseToKE(struct ub_packed_rrset_key* dnskey_rrset,
/* attempt to verify with trust anchor DS and DNSKEY */
if(ta->ds_rrset) {
kkey = val_verify_new_DNSKEYs(qstate->region, qstate->env, ve,
dnskey_rrset, ta->ds_rrset);
dnskey_rrset, ta->ds_rrset, &reason);
if(!kkey) {
log_err("out of memory: verifying prime DS");
return NULL;
@ -2152,7 +2188,7 @@ primeResponseToKE(struct ub_packed_rrset_key* dnskey_rrset,
}
if(sec != sec_status_secure && ta->dnskey_rrset) {
sec = val_verify_rrset(qstate->env, ve, dnskey_rrset,
ta->dnskey_rrset);
ta->dnskey_rrset, &reason);
verbose(VERB_DETAIL, "validate keys with anchor(DNSKEY): %s",
sec_status_to_string(sec));
if(sec == sec_status_secure) {
@ -2172,10 +2208,13 @@ primeResponseToKE(struct ub_packed_rrset_key* dnskey_rrset,
ta->name, LDNS_RR_TYPE_DNSKEY, ta->dclass);
/* NOTE: in this case, we should probably reject the trust
* anchor for longer, perhaps forever. */
if(qstate->env->cfg->harden_dnssec_stripped)
if(qstate->env->cfg->harden_dnssec_stripped) {
struct val_qstate* vq = (struct val_qstate*)
qstate->minfo[id];
val_errinf(qstate, vq, reason);
kkey = key_entry_create_bad(qstate->region, ta->name,
ta->namelen, ta->dclass);
else kkey = key_entry_create_null(qstate->region, ta->name,
} else kkey = key_entry_create_null(qstate->region, ta->name,
ta->namelen, ta->dclass, NULL_KEY_TTL,
*qstate->env->now);
if(!kkey) {
@ -2213,10 +2252,15 @@ ds_response_to_ke(struct module_qstate* qstate, struct val_qstate* vq,
struct key_entry_key** ke)
{
struct val_env* ve = (struct val_env*)qstate->env->modinfo[id];
char* reason = NULL;
enum val_classification subtype;
if(rcode != LDNS_RCODE_NOERROR) {
char* rc = ldns_pkt_rcode2str(rcode);
/* errors here pretty much break validation */
verbose(VERB_DETAIL, "DS response was error, thus bogus");
val_errinf(qstate, vq, rc);
val_errinf(qstate, vq, "no DS");
free(rc);
goto return_bogus;
}
@ -2230,15 +2274,17 @@ ds_response_to_ke(struct module_qstate* qstate, struct val_qstate* vq,
if(!ds) {
log_warn("internal error: POSITIVE DS response was "
"missing DS.");
val_errinf(qstate, vq, "no DS record");
goto return_bogus;
}
/* Verify only returns BOGUS or SECURE. If the rrset is
* bogus, then we are done. */
sec = val_verify_rrset_entry(qstate->env, ve, ds,
vq->key_entry);
vq->key_entry, &reason);
if(sec != sec_status_secure) {
verbose(VERB_DETAIL, "DS rrset in DS response did "
"not verify");
val_errinf(qstate, vq, reason);
goto return_bogus;
}
@ -2291,6 +2337,8 @@ ds_response_to_ke(struct module_qstate* qstate, struct val_qstate* vq,
case sec_status_bogus:
verbose(VERB_DETAIL, "NSEC RRset for the "
"referral did not prove no DS.");
val_errinf(qstate, vq, "NSEC DS absent proof "
"failed");
goto return_bogus;
case sec_status_unchecked:
default:
@ -2318,6 +2366,8 @@ ds_response_to_ke(struct module_qstate* qstate, struct val_qstate* vq,
case sec_status_bogus:
verbose(VERB_DETAIL, "NSEC3s for the "
"referral did not prove no DS.");
val_errinf(qstate, vq, "NSEC3 DS absent proof "
"failed");
goto return_bogus;
case sec_status_insecure:
case sec_status_unchecked:
@ -2330,10 +2380,20 @@ ds_response_to_ke(struct module_qstate* qstate, struct val_qstate* vq,
* this is BOGUS. */
verbose(VERB_DETAIL, "DS %s ran out of options, so return "
"bogus", val_classification_to_string(subtype));
val_errinf(qstate, vq, "no DS but also no proof of that");
goto return_bogus;
} else {
verbose(VERB_QUERY, "Encountered an unhandled type of "
"DS response, thus bogus.");
val_errinf(qstate, vq, "no DS and ");
if(FLAGS_GET_RCODE(msg->rep->flags) != LDNS_RCODE_NOERROR) {
char* rc = ldns_pkt_rcode2str(
FLAGS_GET_RCODE(msg->rep->flags));
val_errinf(qstate, vq, rc);
free(rc);
} else val_errinf(qstate, vq,
val_classification_to_string(subtype));
val_errinf(qstate, vq, "message fails to prove that");
goto return_bogus;
}
return_bogus:
@ -2398,8 +2458,13 @@ process_ds_response(struct module_qstate* qstate, struct val_qstate* vq,
&& vq->restart_count < VAL_MAX_RESTART_COUNT) {
vq->empty_DS_name = olds;
val_blacklist(&vq->chain_blacklist, qstate->region, origin, 1);
vq->errinf = NULL;
vq->restart_count++;
} else {
if(key_entry_isbad(dske)) {
val_errinf_origin(qstate, vq, origin);
val_errinf_dname(qstate, vq, "for DS", qinfo->qname);
}
/* NOTE: the reason for the DS to be not good (that is,
* either bad or null) should have been logged by
* dsResponseToKE. */
@ -2433,6 +2498,7 @@ process_dnskey_response(struct module_qstate* qstate, struct val_qstate* vq,
struct val_env* ve = (struct val_env*)qstate->env->modinfo[id];
struct key_entry_key* old = vq->key_entry;
struct ub_packed_rrset_key* dnskey = NULL;
char* reason = NULL;
if(rcode == LDNS_RCODE_NOERROR)
dnskey = reply_find_answer_rrset(qinfo, msg->rep);
@ -2442,9 +2508,10 @@ process_dnskey_response(struct module_qstate* qstate, struct val_qstate* vq,
verbose(VERB_DETAIL, "Missing DNSKEY RRset in response to "
"DNSKEY query.");
if(vq->restart_count < VAL_MAX_RESTART_COUNT) {
vq->restart_count++;
val_blacklist(&vq->chain_blacklist, qstate->region,
origin, 1);
vq->errinf = NULL;
vq->restart_count++;
return;
}
vq->key_entry = key_entry_create_bad(qstate->region,
@ -2463,7 +2530,7 @@ process_dnskey_response(struct module_qstate* qstate, struct val_qstate* vq,
return;
}
vq->key_entry = val_verify_new_DNSKEYs(qstate->region, qstate->env,
ve, dnskey, vq->ds_rrset);
ve, dnskey, vq->ds_rrset, &reason);
if(!vq->key_entry) {
log_err("out of memory in verify new DNSKEYs");
@ -2477,18 +2544,23 @@ process_dnskey_response(struct module_qstate* qstate, struct val_qstate* vq,
if(vq->restart_count < VAL_MAX_RESTART_COUNT) {
val_blacklist(&vq->chain_blacklist,
qstate->region, origin, 1);
vq->errinf = NULL;
vq->restart_count++;
vq->key_entry = old;
return;
}
verbose(VERB_DETAIL, "Did not match a DS to a DNSKEY, "
"thus bogus.");
val_errinf(qstate, vq, reason);
val_errinf_origin(qstate, vq, origin);
val_errinf_dname(qstate, vq, "for key", qinfo->qname);
}
vq->chain_blacklist = NULL;
vq->state = VAL_VALIDATE_STATE;
return;
}
vq->chain_blacklist = NULL;
vq->errinf = NULL;
/* The DNSKEY validated, so cache it as a trusted key rrset. */
key_cache_insert(ve->kcache, vq->key_entry);
@ -2547,12 +2619,15 @@ process_prime_response(struct module_qstate* qstate, struct val_qstate* vq,
&& vq->restart_count < VAL_MAX_RESTART_COUNT) {
val_blacklist(&vq->chain_blacklist, qstate->region,
origin, 1);
vq->key_entry = NULL;
vq->errinf = NULL;
vq->restart_count++;
vq->key_entry = NULL;
vq->state = VAL_INIT_STATE;
return;
}
vq->chain_blacklist = NULL;
val_errinf_origin(qstate, vq, origin);
val_errinf_dname(qstate, vq, "for trust anchor", ta->name);
/* store the freshly primed entry in the cache */
key_cache_insert(ve->kcache, vq->key_entry);
}
@ -2578,12 +2653,10 @@ process_prime_response(struct module_qstate* qstate, struct val_qstate* vq,
* @param rcode: rcode result value.
* @param msg: result message (if rcode is OK).
* @param qinfo: from the sub query state, query info.
* @param origin: the origin of msg.
*/
static void
process_dlv_response(struct module_qstate* qstate, struct val_qstate* vq,
int id, int rcode, struct dns_msg* msg, struct query_info* qinfo,
struct sock_list* origin)
int id, int rcode, struct dns_msg* msg, struct query_info* qinfo)
{
struct val_env* ve = (struct val_env*)qstate->env->modinfo[id];
@ -2697,8 +2770,7 @@ val_inform_super(struct module_qstate* qstate, int id,
return;
} else if(qstate->qinfo.qtype == LDNS_RR_TYPE_DLV) {
process_dlv_response(super, vq, id, qstate->return_rcode,
qstate->return_msg, &qstate->qinfo,
qstate->reply_origin);
qstate->return_msg, &qstate->qinfo);
return;
}
log_err("internal error in validator: no inform_supers possible");

View file

@ -49,6 +49,7 @@ struct val_anchors;
struct key_cache;
struct key_entry_key;
struct val_neg_cache;
struct config_strlist;
/**
* This is the TTL to use when a trust anchor fails to prime. A trust anchor
@ -236,6 +237,9 @@ struct val_qstate {
dlv_ask_higher, /* ask again */
dlv_there_is_no_dlv /* got no DLV, sure of it */
} dlv_status;
/** failure reason information if val-log-level is high */
struct config_strlist* errinf;
};
/**