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.
--- /dev/null
+; 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
/**
* 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;
}
/**
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;
}
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;
}
}
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);
* 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);
/**
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))
* 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;
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;
}