{
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 "
return sec_status_bogus;
}
for(i=0; i<num; i++) {
- sec = dnskeyset_verify_rrset_sig(env, ve, rrset, dnskey, i);
+ sec = dnskeyset_verify_rrset_sig(env, ve, rrset, dnskey, i,
+ &sortree);
if(sec == sec_status_secure)
return sec;
}
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)
{
enum sec_status sec;
size_t i, num;
+ rbtree_t* sortree = NULL;
+ int buf_canon = 0;
+
num = rrset_get_sigcount(rrset);
if(num == 0) {
verbose(VERB_ALGO, "rrset failed to verify due to a lack of "
return sec_status_bogus;
}
for(i=0; i<num; i++) {
- sec = dnskey_verify_rrset_sig(env, ve, rrset, dnskey,
- dnskey_idx, i);
+ buf_canon = 0;
+ sec = dnskey_verify_rrset_sig(env->scratch,
+ env->scratch_buffer, ve, rrset, dnskey, dnskey_idx, i,
+ &sortree, &buf_canon);
if(sec == sec_status_secure)
return sec;
}
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;
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; i<num; i++) {
numchecked ++;
/* see if key verifies */
- sec = dnskey_verify_rrset_sig(env, ve, rrset, dnskey,
- i, sig_idx);
+ sec = dnskey_verify_rrset_sig(env->scratch,
+ env->scratch_buffer, ve, rrset, dnskey, i, sig_idx,
+ sortree, &buf_canon);
if(sec == sec_status_secure)
return sec;
}
* @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);
/* 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;
}
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 */
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 */
}
/* 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 */
struct module_env;
struct ub_packed_rrset_key;
enum sec_status;
+struct rbtree_t;
+struct region;
/**
* Check if dnskey matches a DS digest
* @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 */