+16 August 2007: Wouter
+ - DS sig unit test.
+ - latest release libevent 1.3c and 1.3d have threading fixed.
+ - key entry fixup data pointer and ttl absolute.
+ - This makes a key-prime succeed in validator, with DS or DNSKEY as
+ trust-anchor.
+
15 August 2007: Wouter
- crypto calls to verify signatures.
- unit test for rrsig verification.
Known issues
------------
-o If libevent is older (1.3 and before), unbound will exit instead of reload
+o If libevent is older (before 1.3c), unbound will exit instead of reload
on sighup. On a restart 'did not exit gracefully last time' warning is
printed. Perform ./configure --with-libevent=no or update libevent, rerun
configure and recompile unbound to make sighup work correctly.
query_info_clear(&qinfo);
}
+/** find RRset in reply by type */
+static struct ub_packed_rrset_key*
+find_rrset_type(struct reply_info* rep, uint16_t type)
+{
+ size_t i;
+ for(i=0; i<rep->rrset_count; i++) {
+ if(ntohs(rep->rrsets[i]->rk.type) == type)
+ return rep->rrsets[i];
+ }
+ return NULL;
+}
+
+/** DS sig test an entry - get DNSKEY and DS in entry and verify */
+static void
+dstest_entry(struct entry* e, struct alloc_cache* alloc, struct region*
+ region, ldns_buffer* pkt, struct module_env* env)
+{
+ struct query_info qinfo;
+ struct reply_info* rep = NULL;
+ struct ub_packed_rrset_key* ds, *dnskey;
+ int ret;
+
+ region_free_all(region);
+ if(vsig) {
+ printf("verifying DS-DNSKEY match:\n");
+ ldns_pkt_print(stdout, e->reply_list->reply);
+ printf("\n");
+ }
+ entry_to_repinfo(e, alloc, region, pkt, &qinfo, &rep);
+ ds = find_rrset_type(rep, LDNS_RR_TYPE_DS);
+ dnskey = find_rrset_type(rep, LDNS_RR_TYPE_DNSKEY);
+ /* check test is OK */
+ unit_assert(ds && dnskey);
+
+ ret = ds_digest_match_dnskey(env, dnskey, 0, ds, 0);
+ if(strncmp((char*)qinfo.qname, "\003yes", 4) == 0) {
+ if(vsig) {
+ printf("result(yes)= %s\n", ret?"yes":"no");
+ }
+ unit_assert(ret);
+ } else if (strncmp((char*)qinfo.qname, "\002no", 3) == 0) {
+ if(vsig) {
+ printf("result(no)= %s\n", ret?"yes":"no");
+ }
+ unit_assert(!ret);
+ } else {
+ fatal_exit("Bad qname in DS unit test, yes or no");
+ }
+
+ reply_info_parsedelete(rep, alloc);
+ query_info_clear(&qinfo);
+}
+
/** verify from a file */
static void
verifytest_file(const char* fname, const char* at_date)
ldns_buffer_free(buf);
}
+/** verify DS matches DNSKEY from a file */
+static void
+dstest_file(const char* fname)
+{
+ /*
+ * The file contains a list of ldns-testpkts entries.
+ * The first entry must be a query for DNSKEY.
+ * The answer rrset is the keyset that will be used for verification
+ */
+ struct region* region = region_create(malloc, free);
+ struct alloc_cache alloc;
+ ldns_buffer* buf = ldns_buffer_new(65535);
+ struct entry* e;
+ struct entry* list = read_datafile(fname);
+ struct module_env env;
+
+ if(!list)
+ fatal_exit("could not read %s: %s", fname, strerror(errno));
+ alloc_init(&alloc, NULL, 1);
+ memset(&env, 0, sizeof(env));
+ env.scratch = region;
+ env.scratch_buffer = buf;
+ unit_assert(region && buf);
+
+ /* ready to go! */
+ for(e = list; e; e = e->next) {
+ dstest_entry(e, &alloc, region, buf, &env);
+ }
+
+ delete_entry(list);
+ region_destroy(region);
+ alloc_clear(&alloc);
+ ldns_buffer_free(buf);
+}
+
void
verify_test()
{
printf("verify test\n");
verifytest_file("testdata/test_signatures.1", "20070818005004");
+ dstest_file("testdata/test_ds_sig.1");
}
--- /dev/null
+;
+; DS match test file.
+; test matching of DS hash against DNSKEYs.
+;
+; enter ENTRYs with a DS and a DNSKEY.
+; These are matched against another.
+; If the query name starts with 'yes' then it must match.
+; If the query name starts with 'no' then it must not match.
+
+ENTRY_BEGIN
+SECTION QUESTION
+yes. IN A
+SECTION ANSWER
+nlnetlabs.nl. 3600 IN DS 43791 RSASHA1 1 81ee88356df3c3077549445ed2fb1c92adc80641
+nlnetlabs.nl. DNSKEY 257 3 5 AQPzzTWMz8qSWIQlfRnPckx2BiVmkVN6LPupO3mbz7FhLSnm26n6iG9N Lby97Ji453aWZY3M5/xJBSOS2vWtco2t8C0+xeO1bc/d6ZTy32DHchpW 6rDH1vp86Ll+ha0tmwyy9QP7y2bVw5zSbFCrefk8qCUBgfHm9bHzMG1U BYtEIQ==
+ENTRY_END
+
+ENTRY_BEGIN
+SECTION QUESTION
+yes. IN A
+SECTION ANSWER
+jelte.nlnetlabs.nl. DS 42860 5 1 14D739EB566D2B1A5E216A0BA4D17FA9B038BE4A
+jelte.nlnetlabs.nl. 3600 IN DNSKEY 256 3 5 AQOraLfzarHAlFskVGwAGnX0LRjlcOiO6y5WM4Kz+QvZ9vX28h4lOvnf d5tkxnZm7ERLTAJoFq+1w/wl7VXs2Isz75BSZ7LQh3OT2xXnS6VT5ZxX ko/UCOdoGiKZZ63jHZ0jNSTCYy8+5rfvwRD8s3gGuErp5KcHg3V8VLUK SDNNEQ==
+ENTRY_END
+
+ENTRY_BEGIN
+SECTION QUESTION
+no. IN A
+SECTION ANSWER
+nlnetlabs.nl. 3600 IN DS 43791 RSASHA1 1 14D739EB566D2B1A5E216A0BA4D17FA9B038BE4A
+nlnetlabs.nl. DNSKEY 257 3 5 AQPzzTWMz8qSWIQlfRnPckx2BiVmkVN6LPupO3mbz7FhLSnm26n6iG9N Lby97Ji453aWZY3M5/xJBSOS2vWtco2t8C0+xeO1bc/d6ZTy32DHchpW 6rDH1vp86Ll+ha0tmwyy9QP7y2bVw5zSbFCrefk8qCUBgfHm9bHzMG1U BYtEIQ==
+ENTRY_END
+
else {
for(i=0; i<length*2; i+=blocksize) {
log_info("%s[%u:%u] %.*s", msg, (unsigned)length,
- (unsigned)i, blocksize, buf+i);
+ (unsigned)i/2, blocksize, buf+i);
}
}
free(buf);
*d = region_alloc(region, sizeof(**d));
if(!*d)
return 0;
- (*k)->entry.data = d;
+ (*k)->entry.data = *d;
return 1;
}
rrset->entry.data;
if(!key_entry_setup(region, name, namelen, dclass, &k, &d))
return NULL;
- d->ttl = rd->ttl;
- log_info("New key entry TTL is %d", (int)d->ttl);
+ log_info("New key entry TTL is now+%d", (int)rd->ttl);
+ d->ttl = rd->ttl + time(NULL);
d->isbad = 0;
d->rrset_type = ntohs(rrset->rk.type);
d->rrset_data = (struct packed_rrset_data*)region_alloc_init(region,
if(len < 2+2)
return 0;
memmove(&t, rdata+2, 2);
- return t;
+ return ntohs(t);
}
/**
int algo = rrset_get_sig_algo(rrset, sig_idx);
size_t i, num = rrset_get_count(dnskey);
size_t numchecked = 0;
+ verbose(VERB_ALGO, "verify sig %d %d", (int)tag, algo);
for(i=0; i<num; i++) {
/* see if key matches keytag and algo */
!= ds_get_keytag(ds_rrset, ds_idx)) {
continue;
}
+ 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));
/* Convert the candidate DNSKEY into a hash using the
* same DS hash algorithm. */
/* If the CD bit is on in the original request, then we don't bother to
* validate anything.*/
- if(qstate->query_flags | BIT_CD) {
+ if(qstate->query_flags & BIT_CD) {
verbose(VERB_ALGO, "not validating response due to CD bit");
return 0;
}
log_query_info(VERB_DETAIL, "validator operate: chased to",
&vq->qchase);
(void)outbound;
- if(event == module_event_new || event == module_event_pass) {
+ if(event == module_event_new ||
+ (event == module_event_pass && vq == NULL)) {
/* pass request to next module, to get it */
verbose(VERB_ALGO, "validator: pass to next module");
qstate->ext_state[id] = module_wait_module;
val_handle(qstate, vq, ve, id);
return;
}
+ if(event == module_event_pass) {
+ qstate->ext_state[id] = module_error; /* override this */
+ /* continue processing, since val_env exists */
+ val_handle(qstate, vq, ve, id);
+ return;
+ }
log_err("validator: bad event %s", strmodulevent(event));
qstate->ext_state[id] = module_error;
return;
sec = sec_status_secure;
else
sec = sec_status_bogus;
+ log_info("priming DS result %s", sec_status_to_string(sec));
}
if(sec != sec_status_secure && ta->dnskey_rrset) {
sec = val_verify_rrset(qstate->env, ve, dnskey_rrset,