Fixup trust anchor algorithm check.

git-svn-id: https://unbound.nlnetlabs.nl/svn/trunk@1532 be551aaa-1e26-0410-a405-d3ace91eadb9
This commit is contained in:
wouter 2009-03-18 13:07:48 +00:00
parent db6002ee2a
commit 91b39120f4
6 changed files with 204 additions and 27 deletions

View File

@ -1,5 +1,9 @@
18 March 2009: Wouter
- Added tests, unknown algorithms become insecure. fallback works.
- Fix for and test for unknown algorithms in a trust anchor
definition. Trust anchors with no supported algos are ignored.
This means a (higher)DS or DLV entry for them could succeed, and
otherwise they are treated as insecure.
17 March 2009: Wouter
- unit test for unsupported algorithm in anchor warning.

150
testdata/val_unalgo_anchor.rpl vendored Normal file
View File

@ -0,0 +1,150 @@
; config options
; The island of trust is at example.com
server:
trust-anchor: "example.com. 3600 IN DS 2854 208 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 unsupported algorithm trust anchor
; 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 qtype qname
ADJUST copy_id
REPLY QR NOERROR
SECTION QUESTION
www.example.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 qtype qname
ADJUST copy_id
REPLY QR NOERROR
SECTION QUESTION
www.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 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 ANSWER
www.example.com. IN A 10.20.30.40
ns.example.com. 3600 IN RRSIG A 3 3 3600 20070926134150 20070829134150 2854 example.com. MC0CFQCQMyTjn7WWwpwAR1LlVeLpRgZGuQIUCcJDEkwAuzytTDRlYK7nIMwH1CM= ;{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
www.example.com. 3600 IN RRSIG A 3 3 3600 20070926134150 20070829134150 2854 example.com. MC0CFC99iE9K5y2WNgI0gFvBWaTi9wm6AhUAoUqOpDtG5Zct+Qr9F3mSdnbc6V4= ;{id = 2854}
ENTRY_END
RANGE_END
STEP 1 QUERY
ENTRY_BEGIN
REPLY RD DO
SECTION QUESTION
www.example.com. IN A
ENTRY_END
; recursion happens here.
STEP 10 CHECK_ANSWER
ENTRY_BEGIN
MATCH all
REPLY QR RD RA NOERROR
SECTION QUESTION
www.example.com. IN A
SECTION ANSWER
www.example.com. IN A 10.20.30.40
www.example.com. 3600 IN RRSIG A 3 3 3600 20070926134150 20070829134150 2854 example.com. MC0CFC99iE9K5y2WNgI0gFvBWaTi9wm6AhUAoUqOpDtG5Zct+Qr9F3mSdnbc6V4= ;{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 20070926134150 20070829134150 2854 example.com. MC0CFQCQMyTjn7WWwpwAR1LlVeLpRgZGuQIUCcJDEkwAuzytTDRlYK7nIMwH1CM= ;{id = 2854}
ENTRY_END
SCENARIO_END

View File

@ -823,35 +823,34 @@ anchors_assemble(struct val_anchors* anchors, struct trust_anchor* ta)
/**
* Check DS algos for support, warn if not.
* @param ta: trust anchor
* @return true if all anchors are supported.
* @return number of DS anchors with unsupported algorithms.
*/
static int
anchors_ds_is_supported(struct trust_anchor* ta)
static size_t
anchors_ds_unsupported(struct trust_anchor* ta)
{
size_t i;
size_t i, num = 0;
for(i=0; i<ta->numDS; i++) {
if(!ds_digest_algo_is_supported(ta->ds_rrset, i))
return 0;
if(!ds_key_algo_is_supported(ta->ds_rrset, i))
return 0;
if(!ds_digest_algo_is_supported(ta->ds_rrset, i) ||
!ds_key_algo_is_supported(ta->ds_rrset, i))
num++;
}
return 1;
return num;
}
/**
* Check DNSKEY algos for support, warn if not.
* @param ta: trust anchor
* @return true if all anchors are supported.
* @return number of DNSKEY anchors with unsupported algorithms.
*/
static int
anchors_dnskey_is_supported(struct trust_anchor* ta)
static size_t
anchors_dnskey_unsupported(struct trust_anchor* ta)
{
size_t i;
size_t i, num = 0;
for(i=0; i<ta->numDNSKEY; i++) {
if(!dnskey_algo_is_supported(ta->dnskey_rrset, i))
return 0;
num++;
}
return 1;
return num;
}
/**
@ -863,21 +862,35 @@ static int
anchors_assemble_rrsets(struct val_anchors* anchors)
{
struct trust_anchor* ta;
RBTREE_FOR(ta, struct trust_anchor*, anchors->tree) {
struct trust_anchor* next;
size_t nods, nokey;
ta=(struct trust_anchor*)rbtree_first(anchors->tree);
while((rbnode_t*)ta != RBTREE_NULL) {
next = (struct trust_anchor*)rbtree_next(&ta->node);
if(!anchors_assemble(anchors, ta)) {
log_err("out of memory");
return 0;
}
if(!anchors_ds_is_supported(ta)) {
nods = anchors_ds_unsupported(ta);
nokey = anchors_dnskey_unsupported(ta);
if(nods) {
log_nametypeclass(0, "warning: unsupported "
"algorithm for trust anchor",
ta->name, LDNS_RR_TYPE_DS, ta->dclass);
}
if(!anchors_dnskey_is_supported(ta)) {
if(nokey) {
log_nametypeclass(0, "warning: unsupported "
"algorithm for trust anchor",
ta->name, LDNS_RR_TYPE_DNSKEY, ta->dclass);
}
if(nods == ta->numDS && nokey == ta->numDNSKEY) {
char b[257];
dname_str(ta->name, b);
log_warn("trust anchor %s has no supported algorithms,"
" the anchor is ignored", b);
(void)rbtree_delete(anchors->tree, &ta->node);
}
ta = next;
}
return 1;
}
@ -946,8 +959,9 @@ anchors_apply_cfg(struct val_anchors* anchors, struct config_file* cfg)
return 0;
}
}
init_parents(anchors);
/* first assemble, since it may delete useless anchors */
anchors_assemble_rrsets(anchors);
init_parents(anchors);
ldns_buffer_free(parsebuf);
return 1;
}

View File

@ -718,16 +718,15 @@ val_mark_indeterminate(struct reply_info* rep, struct val_anchors* anchors,
}
void
val_mark_insecure(struct reply_info* rep, struct key_entry_key* kkey,
val_mark_insecure(struct reply_info* rep, uint8_t* kname,
struct rrset_cache* r, struct module_env* env)
{
size_t i;
struct packed_rrset_data* d;
log_assert(key_entry_isnull(kkey));
for(i=0; i<rep->rrset_count; i++) {
d = (struct packed_rrset_data*)rep->rrsets[i]->entry.data;
if(d->security == sec_status_unchecked &&
dname_subdomain_c(rep->rrsets[i]->rk.dname, kkey->name)) {
dname_subdomain_c(rep->rrsets[i]->rk.dname, kname)) {
/* mark as insecure */
d->security = sec_status_insecure;
rrset_update_sec_status(r, rep->rrsets[i], *env->now);

View File

@ -240,12 +240,11 @@ void val_mark_indeterminate(struct reply_info* rep,
* Mark all unchecked rrset entries below a NULL key entry as insecure.
* Only security==unchecked rrsets are updated.
* @param rep: the reply with rrsets.
* @param kkey: key entry, key_entry_isnull() for it. A key entry that marks
* the end of secure space into insecure space.
* @param kname: end of secure space name.
* @param r: rrset cache to store updated security status into.
* @param env: module environment
*/
void val_mark_insecure(struct reply_info* rep, struct key_entry_key* kkey,
void val_mark_insecure(struct reply_info* rep, uint8_t* kname,
struct rrset_cache* r, struct module_env* env);
/**

View File

@ -1209,6 +1209,17 @@ processInit(struct module_qstate* qstate, struct val_qstate* vq,
else if(vq->key_entry == NULL || (vq->trust_anchor &&
dname_strict_subdomain_c(vq->trust_anchor->name,
vq->key_entry->name))) {
/* trust anchor is an 'unsigned' trust anchor */
if(vq->trust_anchor && vq->trust_anchor->numDS == 0 &&
vq->trust_anchor->numDNSKEY == 0) {
vq->chase_reply->security = sec_status_insecure;
val_mark_insecure(vq->chase_reply,
vq->trust_anchor->name,
qstate->env->rrset_cache, qstate->env);
/* go to finished state to cache this result */
vq->state = VAL_FINISHED_STATE;
return 1;
}
/* fire off a trust anchor priming query. */
verbose(VERB_DETAIL, "prime trust anchor");
if(!prime_trust_anchor(qstate, vq, id, vq->trust_anchor))
@ -1222,7 +1233,7 @@ processInit(struct module_qstate* qstate, struct val_qstate* vq,
* However, we do set the status to INSECURE, since it is
* essentially proven insecure. */
vq->chase_reply->security = sec_status_insecure;
val_mark_insecure(vq->chase_reply, vq->key_entry,
val_mark_insecure(vq->chase_reply, vq->key_entry->name,
qstate->env->rrset_cache, qstate->env);
/* go to finished state to cache this result */
vq->state = VAL_FINISHED_STATE;
@ -1394,7 +1405,7 @@ processValidate(struct module_qstate* qstate, struct val_qstate* vq,
verbose(VERB_DETAIL, "Verified that %sresponse is INSECURE",
vq->signer_name?"":"unsigned ");
vq->chase_reply->security = sec_status_insecure;
val_mark_insecure(vq->chase_reply, vq->key_entry,
val_mark_insecure(vq->chase_reply, vq->key_entry->name,
qstate->env->rrset_cache, qstate->env);
return 1;
}