From: Wouter Wijngaards Date: Tue, 28 Aug 2007 13:54:55 +0000 (+0000) Subject: Faster verification. X-Git-Tag: release-0.5~84 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=459039cf0887567f745f2f4d0153aedf10f33df9;p=thirdparty%2Funbound.git Faster verification. git-svn-id: file:///svn/unbound/trunk@557 be551aaa-1e26-0410-a405-d3ace91eadb9 --- diff --git a/doc/Changelog b/doc/Changelog index c4955dc35..1e4ce025b 100644 --- a/doc/Changelog +++ b/doc/Changelog @@ -9,6 +9,11 @@ - adjust TTL downwards if rrset TTL bigger than signature allows. - permissive mode feature, sets AD bit for secure, but bogus does not give servfail (bogus is changed into indeterminate). + - optimization of rrset verification. rr canonical sorting is reused, + for the same rrset. canonical rrset image in buffer is reused for + the same signature. + - if the rrset is too big (64k exactly + large owner name) the + canonicalization routine will fail if it does not fit in buffer. 27 August 2007: Wouter - do not garble the edns if a cache answer fails. diff --git a/validator/val_sigcrypt.c b/validator/val_sigcrypt.c index 9b0a114d6..b28578b97 100644 --- a/validator/val_sigcrypt.c +++ b/validator/val_sigcrypt.c @@ -397,6 +397,7 @@ dnskeyset_verify_rrset(struct module_env* env, struct val_env* ve, { enum sec_status sec; size_t i, num; + rbtree_t* sortree = NULL; num = rrset_get_sigcount(rrset); if(num == 0) { verbose(VERB_ALGO, "rrset failed to verify due to a lack of " @@ -404,7 +405,8 @@ dnskeyset_verify_rrset(struct module_env* env, struct val_env* ve, return sec_status_bogus; } for(i=0; iscratch, + env->scratch_buffer, ve, rrset, dnskey, dnskey_idx, i, + &sortree, &buf_canon); if(sec == sec_status_secure) return sec; } @@ -438,7 +445,7 @@ dnskey_verify_rrset(struct module_env* env, struct val_env* ve, enum sec_status dnskeyset_verify_rrset_sig(struct module_env* env, struct val_env* ve, struct ub_packed_rrset_key* rrset, struct ub_packed_rrset_key* dnskey, - size_t sig_idx) + size_t sig_idx, struct rbtree_t** sortree) { /* find matching keys and check them */ enum sec_status sec = sec_status_bogus; @@ -446,6 +453,7 @@ dnskeyset_verify_rrset_sig(struct module_env* env, struct val_env* ve, int algo = rrset_get_sig_algo(rrset, sig_idx); size_t i, num = rrset_get_count(dnskey); size_t numchecked = 0; + int buf_canon = 0; verbose(VERB_ALGO, "verify sig %d %d", (int)tag, algo); for(i=0; iscratch, + env->scratch_buffer, ve, rrset, dnskey, i, sig_idx, + sortree, &buf_canon); if(sec == sec_status_secure) return sec; } @@ -972,29 +981,47 @@ canonicalize_rdata(ldns_buffer* buf, struct ub_packed_rrset_key* rrset, * @param sig: RRSIG rdata to include. * @param siglen: RRSIG rdata len excluding signature field, but inclusive * signer name length. + * @param sortree: if NULL is passed a new sorted rrset tree is built. + * Otherwise it is reused. * @return false on alloc error. */ static int rrset_canonical(struct region* region, ldns_buffer* buf, - struct ub_packed_rrset_key* k, uint8_t* sig, size_t siglen) + struct ub_packed_rrset_key* k, uint8_t* sig, size_t siglen, + struct rbtree_t** sortree) { struct packed_rrset_data* d = (struct packed_rrset_data*)k->entry.data; uint8_t* can_owner = NULL; size_t can_owner_len = 0; - rbtree_t sortree; struct canon_rr* walk; struct canon_rr* rrs; - rrs = region_alloc(region, sizeof(struct canon_rr)*d->count); - if(!rrs) - return 0; - rbtree_init(&sortree, &canonical_tree_compare); - canonical_sort(k, d, &sortree, rrs); + + if(!*sortree) { + *sortree = (struct rbtree_t*)region_alloc(region, + sizeof(rbtree_t)); + if(!*sortree) + return 0; + rrs = region_alloc(region, sizeof(struct canon_rr)*d->count); + if(!rrs) { + *sortree = NULL; + return 0; + } + rbtree_init(*sortree, &canonical_tree_compare); + canonical_sort(k, d, *sortree, rrs); + } ldns_buffer_clear(buf); ldns_buffer_write(buf, sig, siglen); /* canonicalize signer name */ query_dname_tolower(ldns_buffer_begin(buf)+18); - RBTREE_FOR(walk, struct canon_rr*, &sortree) { + RBTREE_FOR(walk, struct canon_rr*, (*sortree)) { + /* see if there is enough space left in the buffer */ + if(ldns_buffer_remaining(buf) < can_owner_len + 2 + 2 + 4 + + d->rr_len[walk->rr_idx]) { + log_err("verify: failed to canonicalize, " + "rrset too big"); + return 0; + } /* determine canonical owner name */ if(can_owner) ldns_buffer_write(buf, can_owner, can_owner_len); @@ -1092,7 +1119,6 @@ adjust_ttl(struct val_env* ve, struct ub_packed_rrset_key* rrset, /* get current date */ if(ve->date_override) { now = ve->date_override; - verbose(VERB_ALGO, "date override option %d used", (int)now); } else now = (int32_t)time(0); expittl = expi - now; @@ -1333,9 +1359,11 @@ verify_canonrrset(ldns_buffer* buf, int algo, unsigned char* sigblock, } enum sec_status -dnskey_verify_rrset_sig(struct module_env* env, struct val_env* ve, +dnskey_verify_rrset_sig(struct region* region, ldns_buffer* buf, + struct val_env* ve, struct ub_packed_rrset_key* rrset, struct ub_packed_rrset_key* dnskey, - size_t dnskey_idx, size_t sig_idx) + size_t dnskey_idx, size_t sig_idx, + struct rbtree_t** sortree, int* buf_canon) { enum sec_status sec; uint8_t* sig; /* RRSIG rdata */ @@ -1420,11 +1448,15 @@ dnskey_verify_rrset_sig(struct module_env* env, struct val_env* ve, return sec_status_bogus; } - /* create rrset canonical format in buffer, ready for signature */ - if(!rrset_canonical(env->scratch, env->scratch_buffer, rrset, sig+2, - 18 + signer_len)) { - log_err("verify: failed due to alloc error"); - return sec_status_unchecked; + if(!*buf_canon) { + /* create rrset canonical format in buffer, ready for + * signature */ + if(!rrset_canonical(region, buf, rrset, sig+2, + 18 + signer_len, sortree)) { + log_err("verify: failed due to alloc error"); + return sec_status_unchecked; + } + *buf_canon = 1; } /* check that dnskey is available */ @@ -1435,7 +1467,7 @@ dnskey_verify_rrset_sig(struct module_env* env, struct val_env* ve, } /* verify */ - sec = verify_canonrrset(env->scratch_buffer, (int)sig[2+2], + sec = verify_canonrrset(buf, (int)sig[2+2], sigblock, sigblock_len, key, keylen); /* check if TTL is too high - reduce if so */ diff --git a/validator/val_sigcrypt.h b/validator/val_sigcrypt.h index cbaff2604..6fe070544 100644 --- a/validator/val_sigcrypt.h +++ b/validator/val_sigcrypt.h @@ -47,6 +47,8 @@ struct val_env; struct module_env; struct ub_packed_rrset_key; enum sec_status; +struct rbtree_t; +struct region; /** * Check if dnskey matches a DS digest @@ -165,26 +167,38 @@ enum sec_status dnskey_verify_rrset(struct module_env* env, * @param rrset: to be validated. * @param dnskey: DNSKEY rrset, keyset to try. * @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. * @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, struct ub_packed_rrset_key* rrset, - struct ub_packed_rrset_key* dnskey, size_t sig_idx); + struct ub_packed_rrset_key* dnskey, size_t sig_idx, + struct rbtree_t** sortree); /** * verify rrset, with specific dnskey(from set), for a specific rrsig + * @param region: scratch region used for temporary allocation. + * @param buf: scratch buffer used for canonicalized rrset data. * @param env: module environment, scratch space is used. * @param ve: validator environment, date settings. * @param rrset: to be validated. * @param dnskey: DNSKEY rrset, keyset. * @param dnskey_idx: which key from the rrset to try. * @param sig_idx: which signature to try to validate. + * @param sortree: pass NULL at start, the sorted rrset order is returned. + * pass it again for the same rrset. + * @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. * @return secure if this key signs this signature. unchecked on error or * bogus if it did not validate. */ -enum sec_status dnskey_verify_rrset_sig(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 sig_idx); +enum sec_status dnskey_verify_rrset_sig(struct region* region, + ldns_buffer* buf, struct val_env* ve, + 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); #endif /* VALIDATOR_VAL_SIGCRYPT_H */ diff --git a/validator/val_utils.c b/validator/val_utils.c index 33b9c1328..239fc02bd 100644 --- a/validator/val_utils.c +++ b/validator/val_utils.c @@ -50,6 +50,7 @@ #include "util/data/dname.h" #include "util/net_help.h" #include "util/module.h" +#include "util/region-allocator.h" enum val_classification val_classify_response(uint16_t query_flags, struct query_info* qinf, @@ -298,6 +299,7 @@ val_verify_rrset(struct module_env* env, struct val_env* ve, ntohs(rrset->rk.type), ntohs(rrset->rk.rrset_class)); sec = dnskeyset_verify_rrset(env, ve, rrset, keys); verbose(VERB_ALGO, "verify result: %s", sec_status_to_string(sec)); + region_free_all(env->scratch); /* update rrset security status * only improves security status