aboutsummaryrefslogtreecommitdiff
path: root/external/unbound/validator
diff options
context:
space:
mode:
authoranonimal <anonimal@i2pmail.org>2017-06-28 21:07:24 +0000
committeranonimal <anonimal@i2pmail.org>2018-03-18 15:52:19 +0000
commit84c5a9ba481d7a33cc0fd0ca43867b61d127d907 (patch)
treef05d3d3f107da02005b4a61f0e5074c113a7165c /external/unbound/validator
parentMerge pull request #3416 (diff)
downloadmonero-84c5a9ba481d7a33cc0fd0ca43867b61d127d907.tar.xz
Unbound: remove unbound from in-tree source
We'll instead use a git submodule to pull from our unbound repo.
Diffstat (limited to 'external/unbound/validator')
-rw-r--r--external/unbound/validator/autotrust.c2416
-rw-r--r--external/unbound/validator/autotrust.h208
-rw-r--r--external/unbound/validator/val_anchor.c1311
-rw-r--r--external/unbound/validator/val_anchor.h230
-rw-r--r--external/unbound/validator/val_kcache.c172
-rw-r--r--external/unbound/validator/val_kcache.h118
-rw-r--r--external/unbound/validator/val_kentry.c413
-rw-r--r--external/unbound/validator/val_kentry.h220
-rw-r--r--external/unbound/validator/val_neg.c1470
-rw-r--r--external/unbound/validator/val_neg.h315
-rw-r--r--external/unbound/validator/val_nsec.c624
-rw-r--r--external/unbound/validator/val_nsec.h182
-rw-r--r--external/unbound/validator/val_nsec3.c1434
-rw-r--r--external/unbound/validator/val_nsec3.h380
-rw-r--r--external/unbound/validator/val_secalgo.c1753
-rw-r--r--external/unbound/validator/val_secalgo.h107
-rw-r--r--external/unbound/validator/val_sigcrypt.c1451
-rw-r--r--external/unbound/validator/val_sigcrypt.h323
-rw-r--r--external/unbound/validator/val_utils.c1151
-rw-r--r--external/unbound/validator/val_utils.h410
-rw-r--r--external/unbound/validator/validator.c3079
-rw-r--r--external/unbound/validator/validator.h294
22 files changed, 0 insertions, 18061 deletions
diff --git a/external/unbound/validator/autotrust.c b/external/unbound/validator/autotrust.c
deleted file mode 100644
index a533733c7..000000000
--- a/external/unbound/validator/autotrust.c
+++ /dev/null
@@ -1,2416 +0,0 @@
-/*
- * validator/autotrust.c - RFC5011 trust anchor management for unbound.
- *
- * Copyright (c) 2009, NLnet Labs. All rights reserved.
- *
- * This software is open source.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- *
- * Redistributions of source code must retain the above copyright notice,
- * this list of conditions and the following disclaimer.
- *
- * Redistributions in binary form must reproduce the above copyright notice,
- * this list of conditions and the following disclaimer in the documentation
- * and/or other materials provided with the distribution.
- *
- * Neither the name of the NLNET LABS nor the names of its contributors may
- * be used to endorse or promote products derived from this software without
- * specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
- * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
- * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
- * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
- * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
- * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-/**
- * \file
- *
- * Contains autotrust implementation. The implementation was taken from
- * the autotrust daemon (BSD licensed), written by Matthijs Mekking.
- * It was modified to fit into unbound. The state table process is the same.
- */
-#include "config.h"
-#include "validator/autotrust.h"
-#include "validator/val_anchor.h"
-#include "validator/val_utils.h"
-#include "validator/val_sigcrypt.h"
-#include "util/data/dname.h"
-#include "util/data/packed_rrset.h"
-#include "util/log.h"
-#include "util/module.h"
-#include "util/net_help.h"
-#include "util/config_file.h"
-#include "util/regional.h"
-#include "util/random.h"
-#include "util/data/msgparse.h"
-#include "services/mesh.h"
-#include "services/cache/rrset.h"
-#include "validator/val_kcache.h"
-#include "sldns/sbuffer.h"
-#include "sldns/wire2str.h"
-#include "sldns/str2wire.h"
-#include "sldns/keyraw.h"
-#include "sldns/rrdef.h"
-#include <stdarg.h>
-#include <ctype.h>
-
-/** number of times a key must be seen before it can become valid */
-#define MIN_PENDINGCOUNT 2
-
-/** Event: Revoked */
-static void do_revoked(struct module_env* env, struct autr_ta* anchor, int* c);
-
-struct autr_global_data* autr_global_create(void)
-{
- struct autr_global_data* global;
- global = (struct autr_global_data*)malloc(sizeof(*global));
- if(!global)
- return NULL;
- rbtree_init(&global->probe, &probetree_cmp);
- return global;
-}
-
-void autr_global_delete(struct autr_global_data* global)
-{
- if(!global)
- return;
- /* elements deleted by parent */
- memset(global, 0, sizeof(*global));
- free(global);
-}
-
-int probetree_cmp(const void* x, const void* y)
-{
- struct trust_anchor* a = (struct trust_anchor*)x;
- struct trust_anchor* b = (struct trust_anchor*)y;
- log_assert(a->autr && b->autr);
- if(a->autr->next_probe_time < b->autr->next_probe_time)
- return -1;
- if(a->autr->next_probe_time > b->autr->next_probe_time)
- return 1;
- /* time is equal, sort on trust point identity */
- return anchor_cmp(x, y);
-}
-
-size_t
-autr_get_num_anchors(struct val_anchors* anchors)
-{
- size_t res = 0;
- if(!anchors)
- return 0;
- lock_basic_lock(&anchors->lock);
- if(anchors->autr)
- res = anchors->autr->probe.count;
- lock_basic_unlock(&anchors->lock);
- return res;
-}
-
-/** Position in string */
-static int
-position_in_string(char *str, const char* sub)
-{
- char* pos = strstr(str, sub);
- if(pos)
- return (int)(pos-str)+(int)strlen(sub);
- return -1;
-}
-
-/** Debug routine to print pretty key information */
-static void
-verbose_key(struct autr_ta* ta, enum verbosity_value level,
- const char* format, ...) ATTR_FORMAT(printf, 3, 4);
-
-/**
- * Implementation of debug pretty key print
- * @param ta: trust anchor key with DNSKEY data.
- * @param level: verbosity level to print at.
- * @param format: printf style format string.
- */
-static void
-verbose_key(struct autr_ta* ta, enum verbosity_value level,
- const char* format, ...)
-{
- va_list args;
- va_start(args, format);
- if(verbosity >= level) {
- char* str = sldns_wire2str_dname(ta->rr, ta->dname_len);
- int keytag = (int)sldns_calc_keytag_raw(sldns_wirerr_get_rdata(
- ta->rr, ta->rr_len, ta->dname_len),
- sldns_wirerr_get_rdatalen(ta->rr, ta->rr_len,
- ta->dname_len));
- char msg[MAXSYSLOGMSGLEN];
- vsnprintf(msg, sizeof(msg), format, args);
- verbose(level, "%s key %d %s", str?str:"??", keytag, msg);
- free(str);
- }
- va_end(args);
-}
-
-/**
- * Parse comments
- * @param str: to parse
- * @param ta: trust key autotrust metadata
- * @return false on failure.
- */
-static int
-parse_comments(char* str, struct autr_ta* ta)
-{
- int len = (int)strlen(str), pos = 0, timestamp = 0;
- char* comment = (char*) malloc(sizeof(char)*len+1);
- char* comments = comment;
- if(!comment) {
- log_err("malloc failure in parse");
- return 0;
- }
- /* skip over whitespace and data at start of line */
- while (*str != '\0' && *str != ';')
- str++;
- if (*str == ';')
- str++;
- /* copy comments */
- while (*str != '\0')
- {
- *comments = *str;
- comments++;
- str++;
- }
- *comments = '\0';
-
- comments = comment;
-
- /* read state */
- pos = position_in_string(comments, "state=");
- if (pos >= (int) strlen(comments))
- {
- log_err("parse error");
- free(comment);
- return 0;
- }
- if (pos <= 0)
- ta->s = AUTR_STATE_VALID;
- else
- {
- int s = (int) comments[pos] - '0';
- switch(s)
- {
- case AUTR_STATE_START:
- case AUTR_STATE_ADDPEND:
- case AUTR_STATE_VALID:
- case AUTR_STATE_MISSING:
- case AUTR_STATE_REVOKED:
- case AUTR_STATE_REMOVED:
- ta->s = s;
- break;
- default:
- verbose_key(ta, VERB_OPS, "has undefined "
- "state, considered NewKey");
- ta->s = AUTR_STATE_START;
- break;
- }
- }
- /* read pending count */
- pos = position_in_string(comments, "count=");
- if (pos >= (int) strlen(comments))
- {
- log_err("parse error");
- free(comment);
- return 0;
- }
- if (pos <= 0)
- ta->pending_count = 0;
- else
- {
- comments += pos;
- ta->pending_count = (uint8_t)atoi(comments);
- }
-
- /* read last change */
- pos = position_in_string(comments, "lastchange=");
- if (pos >= (int) strlen(comments))
- {
- log_err("parse error");
- free(comment);
- return 0;
- }
- if (pos >= 0)
- {
- comments += pos;
- timestamp = atoi(comments);
- }
- if (pos < 0 || !timestamp)
- ta->last_change = 0;
- else
- ta->last_change = (time_t)timestamp;
-
- free(comment);
- return 1;
-}
-
-/** Check if a line contains data (besides comments) */
-static int
-str_contains_data(char* str, char comment)
-{
- while (*str != '\0') {
- if (*str == comment || *str == '\n')
- return 0;
- if (*str != ' ' && *str != '\t')
- return 1;
- str++;
- }
- return 0;
-}
-
-/** Get DNSKEY flags
- * rdata without rdatalen in front of it. */
-static int
-dnskey_flags(uint16_t t, uint8_t* rdata, size_t len)
-{
- uint16_t f;
- if(t != LDNS_RR_TYPE_DNSKEY)
- return 0;
- if(len < 2)
- return 0;
- memmove(&f, rdata, 2);
- f = ntohs(f);
- return (int)f;
-}
-
-/** Check if KSK DNSKEY.
- * pass rdata without rdatalen in front of it */
-static int
-rr_is_dnskey_sep(uint16_t t, uint8_t* rdata, size_t len)
-{
- return (dnskey_flags(t, rdata, len)&DNSKEY_BIT_SEP);
-}
-
-/** Check if TA is KSK DNSKEY */
-static int
-ta_is_dnskey_sep(struct autr_ta* ta)
-{
- return (dnskey_flags(
- sldns_wirerr_get_type(ta->rr, ta->rr_len, ta->dname_len),
- sldns_wirerr_get_rdata(ta->rr, ta->rr_len, ta->dname_len),
- sldns_wirerr_get_rdatalen(ta->rr, ta->rr_len, ta->dname_len)
- ) & DNSKEY_BIT_SEP);
-}
-
-/** Check if REVOKED DNSKEY
- * pass rdata without rdatalen in front of it */
-static int
-rr_is_dnskey_revoked(uint16_t t, uint8_t* rdata, size_t len)
-{
- return (dnskey_flags(t, rdata, len)&LDNS_KEY_REVOKE_KEY);
-}
-
-/** create ta */
-static struct autr_ta*
-autr_ta_create(uint8_t* rr, size_t rr_len, size_t dname_len)
-{
- struct autr_ta* ta = (struct autr_ta*)calloc(1, sizeof(*ta));
- if(!ta) {
- free(rr);
- return NULL;
- }
- ta->rr = rr;
- ta->rr_len = rr_len;
- ta->dname_len = dname_len;
- return ta;
-}
-
-/** create tp */
-static struct trust_anchor*
-autr_tp_create(struct val_anchors* anchors, uint8_t* own, size_t own_len,
- uint16_t dc)
-{
- struct trust_anchor* tp = (struct trust_anchor*)calloc(1, sizeof(*tp));
- if(!tp) return NULL;
- tp->name = memdup(own, own_len);
- if(!tp->name) {
- free(tp);
- return NULL;
- }
- tp->namelen = own_len;
- tp->namelabs = dname_count_labels(tp->name);
- tp->node.key = tp;
- tp->dclass = dc;
- tp->autr = (struct autr_point_data*)calloc(1, sizeof(*tp->autr));
- if(!tp->autr) {
- free(tp->name);
- free(tp);
- return NULL;
- }
- tp->autr->pnode.key = tp;
-
- lock_basic_lock(&anchors->lock);
- if(!rbtree_insert(anchors->tree, &tp->node)) {
- lock_basic_unlock(&anchors->lock);
- log_err("trust anchor presented twice");
- free(tp->name);
- free(tp->autr);
- free(tp);
- return NULL;
- }
- if(!rbtree_insert(&anchors->autr->probe, &tp->autr->pnode)) {
- (void)rbtree_delete(anchors->tree, tp);
- lock_basic_unlock(&anchors->lock);
- log_err("trust anchor in probetree twice");
- free(tp->name);
- free(tp->autr);
- free(tp);
- return NULL;
- }
- lock_basic_unlock(&anchors->lock);
- lock_basic_init(&tp->lock);
- lock_protect(&tp->lock, tp, sizeof(*tp));
- lock_protect(&tp->lock, tp->autr, sizeof(*tp->autr));
- return tp;
-}
-
-/** delete assembled rrsets */
-static void
-autr_rrset_delete(struct ub_packed_rrset_key* r)
-{
- if(r) {
- free(r->rk.dname);
- free(r->entry.data);
- free(r);
- }
-}
-
-void autr_point_delete(struct trust_anchor* tp)
-{
- if(!tp)
- return;
- lock_unprotect(&tp->lock, tp);
- lock_unprotect(&tp->lock, tp->autr);
- lock_basic_destroy(&tp->lock);
- autr_rrset_delete(tp->ds_rrset);
- autr_rrset_delete(tp->dnskey_rrset);
- if(tp->autr) {
- struct autr_ta* p = tp->autr->keys, *np;
- while(p) {
- np = p->next;
- free(p->rr);
- free(p);
- p = np;
- }
- free(tp->autr->file);
- free(tp->autr);
- }
- free(tp->name);
- free(tp);
-}
-
-/** find or add a new trust point for autotrust */
-static struct trust_anchor*
-find_add_tp(struct val_anchors* anchors, uint8_t* rr, size_t rr_len,
- size_t dname_len)
-{
- struct trust_anchor* tp;
- tp = anchor_find(anchors, rr, dname_count_labels(rr), dname_len,
- sldns_wirerr_get_class(rr, rr_len, dname_len));
- if(tp) {
- if(!tp->autr) {
- log_err("anchor cannot be with and without autotrust");
- lock_basic_unlock(&tp->lock);
- return NULL;
- }
- return tp;
- }
- tp = autr_tp_create(anchors, rr, dname_len, sldns_wirerr_get_class(rr,
- rr_len, dname_len));
- if(!tp)
- return NULL;
- lock_basic_lock(&tp->lock);
- return tp;
-}
-
-/** Add trust anchor from RR */
-static struct autr_ta*
-add_trustanchor_frm_rr(struct val_anchors* anchors, uint8_t* rr, size_t rr_len,
- size_t dname_len, struct trust_anchor** tp)
-{
- struct autr_ta* ta = autr_ta_create(rr, rr_len, dname_len);
- if(!ta)
- return NULL;
- *tp = find_add_tp(anchors, rr, rr_len, dname_len);
- if(!*tp) {
- free(ta->rr);
- free(ta);
- return NULL;
- }
- /* add ta to tp */
- ta->next = (*tp)->autr->keys;
- (*tp)->autr->keys = ta;
- lock_basic_unlock(&(*tp)->lock);
- return ta;
-}
-
-/**
- * Add new trust anchor from a string in file.
- * @param anchors: all anchors
- * @param str: string with anchor and comments, if any comments.
- * @param tp: trust point returned.
- * @param origin: what to use for @
- * @param origin_len: length of origin
- * @param prev: previous rr name
- * @param prev_len: length of prev
- * @param skip: if true, the result is NULL, but not an error, skip it.
- * @return new key in trust point.
- */
-static struct autr_ta*
-add_trustanchor_frm_str(struct val_anchors* anchors, char* str,
- struct trust_anchor** tp, uint8_t* origin, size_t origin_len,
- uint8_t** prev, size_t* prev_len, int* skip)
-{
- uint8_t rr[LDNS_RR_BUF_SIZE];
- size_t rr_len = sizeof(rr), dname_len;
- uint8_t* drr;
- int lstatus;
- if (!str_contains_data(str, ';')) {
- *skip = 1;
- return NULL; /* empty line */
- }
- if(0 != (lstatus = sldns_str2wire_rr_buf(str, rr, &rr_len, &dname_len,
- 0, origin, origin_len, *prev, *prev_len)))
- {
- log_err("ldns error while converting string to RR at%d: %s: %s",
- LDNS_WIREPARSE_OFFSET(lstatus),
- sldns_get_errorstr_parse(lstatus), str);
- return NULL;
- }
- free(*prev);
- *prev = memdup(rr, dname_len);
- *prev_len = dname_len;
- if(!*prev) {
- log_err("malloc failure in add_trustanchor");
- return NULL;
- }
- if(sldns_wirerr_get_type(rr, rr_len, dname_len)!=LDNS_RR_TYPE_DNSKEY &&
- sldns_wirerr_get_type(rr, rr_len, dname_len)!=LDNS_RR_TYPE_DS) {
- *skip = 1;
- return NULL; /* only DS and DNSKEY allowed */
- }
- drr = memdup(rr, rr_len);
- if(!drr) {
- log_err("malloc failure in add trustanchor");
- return NULL;
- }
- return add_trustanchor_frm_rr(anchors, drr, rr_len, dname_len, tp);
-}
-
-/**
- * Load single anchor
- * @param anchors: all points.
- * @param str: comments line
- * @param fname: filename
- * @param origin: the $ORIGIN.
- * @param origin_len: length of origin
- * @param prev: passed to ldns.
- * @param prev_len: length of prev
- * @param skip: if true, the result is NULL, but not an error, skip it.
- * @return false on failure, otherwise the tp read.
- */
-static struct trust_anchor*
-load_trustanchor(struct val_anchors* anchors, char* str, const char* fname,
- uint8_t* origin, size_t origin_len, uint8_t** prev, size_t* prev_len,
- int* skip)
-{
- struct autr_ta* ta = NULL;
- struct trust_anchor* tp = NULL;
-
- ta = add_trustanchor_frm_str(anchors, str, &tp, origin, origin_len,
- prev, prev_len, skip);
- if(!ta)
- return NULL;
- lock_basic_lock(&tp->lock);
- if(!parse_comments(str, ta)) {
- lock_basic_unlock(&tp->lock);
- return NULL;
- }
- if(!tp->autr->file) {
- tp->autr->file = strdup(fname);
- if(!tp->autr->file) {
- lock_basic_unlock(&tp->lock);
- log_err("malloc failure");
- return NULL;
- }
- }
- lock_basic_unlock(&tp->lock);
- return tp;
-}
-
-/** iterator for DSes from keylist. return true if a next element exists */
-static int
-assemble_iterate_ds(struct autr_ta** list, uint8_t** rr, size_t* rr_len,
- size_t* dname_len)
-{
- while(*list) {
- if(sldns_wirerr_get_type((*list)->rr, (*list)->rr_len,
- (*list)->dname_len) == LDNS_RR_TYPE_DS) {
- *rr = (*list)->rr;
- *rr_len = (*list)->rr_len;
- *dname_len = (*list)->dname_len;
- *list = (*list)->next;
- return 1;
- }
- *list = (*list)->next;
- }
- return 0;
-}
-
-/** iterator for DNSKEYs from keylist. return true if a next element exists */
-static int
-assemble_iterate_dnskey(struct autr_ta** list, uint8_t** rr, size_t* rr_len,
- size_t* dname_len)
-{
- while(*list) {
- if(sldns_wirerr_get_type((*list)->rr, (*list)->rr_len,
- (*list)->dname_len) != LDNS_RR_TYPE_DS &&
- ((*list)->s == AUTR_STATE_VALID ||
- (*list)->s == AUTR_STATE_MISSING)) {
- *rr = (*list)->rr;
- *rr_len = (*list)->rr_len;
- *dname_len = (*list)->dname_len;
- *list = (*list)->next;
- return 1;
- }
- *list = (*list)->next;
- }
- return 0;
-}
-
-/** see if iterator-list has any elements in it, or it is empty */
-static int
-assemble_iterate_hasfirst(int iter(struct autr_ta**, uint8_t**, size_t*,
- size_t*), struct autr_ta* list)
-{
- uint8_t* rr = NULL;
- size_t rr_len = 0, dname_len = 0;
- return iter(&list, &rr, &rr_len, &dname_len);
-}
-
-/** number of elements in iterator list */
-static size_t
-assemble_iterate_count(int iter(struct autr_ta**, uint8_t**, size_t*,
- size_t*), struct autr_ta* list)
-{
- uint8_t* rr = NULL;
- size_t i = 0, rr_len = 0, dname_len = 0;
- while(iter(&list, &rr, &rr_len, &dname_len)) {
- i++;
- }
- return i;
-}
-
-/**
- * Create a ub_packed_rrset_key allocated on the heap.
- * It therefore does not have the correct ID value, and cannot be used
- * inside the cache. It can be used in storage outside of the cache.
- * Keys for the cache have to be obtained from alloc.h .
- * @param iter: iterator over the elements in the list. It filters elements.
- * @param list: the list.
- * @return key allocated or NULL on failure.
- */
-static struct ub_packed_rrset_key*
-ub_packed_rrset_heap_key(int iter(struct autr_ta**, uint8_t**, size_t*,
- size_t*), struct autr_ta* list)
-{
- uint8_t* rr = NULL;
- size_t rr_len = 0, dname_len = 0;
- struct ub_packed_rrset_key* k;
- if(!iter(&list, &rr, &rr_len, &dname_len))
- return NULL;
- k = (struct ub_packed_rrset_key*)calloc(1, sizeof(*k));
- if(!k)
- return NULL;
- k->rk.type = htons(sldns_wirerr_get_type(rr, rr_len, dname_len));
- k->rk.rrset_class = htons(sldns_wirerr_get_class(rr, rr_len, dname_len));
- k->rk.dname_len = dname_len;
- k->rk.dname = memdup(rr, dname_len);
- if(!k->rk.dname) {
- free(k);
- return NULL;
- }
- return k;
-}
-
-/**
- * Create packed_rrset data on the heap.
- * @param iter: iterator over the elements in the list. It filters elements.
- * @param list: the list.
- * @return data allocated or NULL on failure.
- */
-static struct packed_rrset_data*
-packed_rrset_heap_data(int iter(struct autr_ta**, uint8_t**, size_t*,
- size_t*), struct autr_ta* list)
-{
- uint8_t* rr = NULL;
- size_t rr_len = 0, dname_len = 0;
- struct packed_rrset_data* data;
- size_t count=0, rrsig_count=0, len=0, i, total;
- uint8_t* nextrdata;
- struct autr_ta* list_i;
- time_t ttl = 0;
-
- list_i = list;
- while(iter(&list_i, &rr, &rr_len, &dname_len)) {
- if(sldns_wirerr_get_type(rr, rr_len, dname_len) ==
- LDNS_RR_TYPE_RRSIG)
- rrsig_count++;
- else count++;
- /* sizeof the rdlength + rdatalen */
- len += 2 + sldns_wirerr_get_rdatalen(rr, rr_len, dname_len);
- ttl = (time_t)sldns_wirerr_get_ttl(rr, rr_len, dname_len);
- }
- if(count == 0 && rrsig_count == 0)
- return NULL;
-
- /* allocate */
- total = count + rrsig_count;
- len += sizeof(*data) + total*(sizeof(size_t) + sizeof(time_t) +
- sizeof(uint8_t*));
- data = (struct packed_rrset_data*)calloc(1, len);
- if(!data)
- return NULL;
-
- /* fill it */
- data->ttl = ttl;
- data->count = count;
- data->rrsig_count = rrsig_count;
- data->rr_len = (size_t*)((uint8_t*)data +
- sizeof(struct packed_rrset_data));
- data->rr_data = (uint8_t**)&(data->rr_len[total]);
- data->rr_ttl = (time_t*)&(data->rr_data[total]);
- nextrdata = (uint8_t*)&(data->rr_ttl[total]);
-
- /* fill out len, ttl, fields */
- list_i = list;
- i = 0;
- while(iter(&list_i, &rr, &rr_len, &dname_len)) {
- data->rr_ttl[i] = (time_t)sldns_wirerr_get_ttl(rr, rr_len,
- dname_len);
- if(data->rr_ttl[i] < data->ttl)
- data->ttl = data->rr_ttl[i];
- data->rr_len[i] = 2 /* the rdlength */ +
- sldns_wirerr_get_rdatalen(rr, rr_len, dname_len);
- i++;
- }
-
- /* fixup rest of ptrs */
- for(i=0; i<total; i++) {
- data->rr_data[i] = nextrdata;
- nextrdata += data->rr_len[i];
- }
-
- /* copy data in there */
- list_i = list;
- i = 0;
- while(iter(&list_i, &rr, &rr_len, &dname_len)) {
- memmove(data->rr_data[i],
- sldns_wirerr_get_rdatawl(rr, rr_len, dname_len),
- data->rr_len[i]);
- i++;
- }
-
- if(data->rrsig_count && data->count == 0) {
- data->count = data->rrsig_count; /* rrset type is RRSIG */
- data->rrsig_count = 0;
- }
- return data;
-}
-
-/**
- * Assemble the trust anchors into DS and DNSKEY packed rrsets.
- * Uses only VALID and MISSING DNSKEYs.
- * Read the sldns_rrs and builds packed rrsets
- * @param tp: the trust point. Must be locked.
- * @return false on malloc failure.
- */
-static int
-autr_assemble(struct trust_anchor* tp)
-{
- struct ub_packed_rrset_key* ubds=NULL, *ubdnskey=NULL;
-
- /* make packed rrset keys - malloced with no ID number, they
- * are not in the cache */
- /* make packed rrset data (if there is a key) */
- if(assemble_iterate_hasfirst(assemble_iterate_ds, tp->autr->keys)) {
- ubds = ub_packed_rrset_heap_key(
- assemble_iterate_ds, tp->autr->keys);
- if(!ubds)
- goto error_cleanup;
- ubds->entry.data = packed_rrset_heap_data(
- assemble_iterate_ds, tp->autr->keys);
- if(!ubds->entry.data)
- goto error_cleanup;
- }
-
- /* make packed DNSKEY data */
- if(assemble_iterate_hasfirst(assemble_iterate_dnskey, tp->autr->keys)) {
- ubdnskey = ub_packed_rrset_heap_key(
- assemble_iterate_dnskey, tp->autr->keys);
- if(!ubdnskey)
- goto error_cleanup;
- ubdnskey->entry.data = packed_rrset_heap_data(
- assemble_iterate_dnskey, tp->autr->keys);
- if(!ubdnskey->entry.data) {
- error_cleanup:
- autr_rrset_delete(ubds);
- autr_rrset_delete(ubdnskey);
- return 0;
- }
- }
-
- /* we have prepared the new keys so nothing can go wrong any more.
- * And we are sure we cannot be left without trustanchor after
- * any errors. Put in the new keys and remove old ones. */
-
- /* free the old data */
- autr_rrset_delete(tp->ds_rrset);
- autr_rrset_delete(tp->dnskey_rrset);
-
- /* assign the data to replace the old */
- tp->ds_rrset = ubds;
- tp->dnskey_rrset = ubdnskey;
- tp->numDS = assemble_iterate_count(assemble_iterate_ds,
- tp->autr->keys);
- tp->numDNSKEY = assemble_iterate_count(assemble_iterate_dnskey,
- tp->autr->keys);
- return 1;
-}
-
-/** parse integer */
-static unsigned int
-parse_int(char* line, int* ret)
-{
- char *e;
- unsigned int x = (unsigned int)strtol(line, &e, 10);
- if(line == e) {
- *ret = -1; /* parse error */
- return 0;
- }
- *ret = 1; /* matched */
- return x;
-}
-
-/** parse id sequence for anchor */
-static struct trust_anchor*
-parse_id(struct val_anchors* anchors, char* line)
-{
- struct trust_anchor *tp;
- int r;
- uint16_t dclass;
- uint8_t* dname;
- size_t dname_len;
- /* read the owner name */
- char* next = strchr(line, ' ');
- if(!next)
- return NULL;
- next[0] = 0;
- dname = sldns_str2wire_dname(line, &dname_len);
- if(!dname)
- return NULL;
-
- /* read the class */
- dclass = parse_int(next+1, &r);
- if(r == -1) {
- free(dname);
- return NULL;
- }
-
- /* find the trust point */
- tp = autr_tp_create(anchors, dname, dname_len, dclass);
- free(dname);
- return tp;
-}
-
-/**
- * Parse variable from trustanchor header
- * @param line: to parse
- * @param anchors: the anchor is added to this, if "id:" is seen.
- * @param anchor: the anchor as result value or previously returned anchor
- * value to read the variable lines into.
- * @return: 0 no match, -1 failed syntax error, +1 success line read.
- * +2 revoked trust anchor file.
- */
-static int
-parse_var_line(char* line, struct val_anchors* anchors,
- struct trust_anchor** anchor)
-{
- struct trust_anchor* tp = *anchor;
- int r = 0;
- if(strncmp(line, ";;id: ", 6) == 0) {
- *anchor = parse_id(anchors, line+6);
- if(!*anchor) return -1;
- else return 1;
- } else if(strncmp(line, ";;REVOKED", 9) == 0) {
- if(tp) {
- log_err("REVOKED statement must be at start of file");
- return -1;
- }
- return 2;
- } else if(strncmp(line, ";;last_queried: ", 16) == 0) {
- if(!tp) return -1;
- lock_basic_lock(&tp->lock);
- tp->autr->last_queried = (time_t)parse_int(line+16, &r);
- lock_basic_unlock(&tp->lock);
- } else if(strncmp(line, ";;last_success: ", 16) == 0) {
- if(!tp) return -1;
- lock_basic_lock(&tp->lock);
- tp->autr->last_success = (time_t)parse_int(line+16, &r);
- lock_basic_unlock(&tp->lock);
- } else if(strncmp(line, ";;next_probe_time: ", 19) == 0) {
- if(!tp) return -1;
- lock_basic_lock(&anchors->lock);
- lock_basic_lock(&tp->lock);
- (void)rbtree_delete(&anchors->autr->probe, tp);
- tp->autr->next_probe_time = (time_t)parse_int(line+19, &r);
- (void)rbtree_insert(&anchors->autr->probe, &tp->autr->pnode);
- lock_basic_unlock(&tp->lock);
- lock_basic_unlock(&anchors->lock);
- } else if(strncmp(line, ";;query_failed: ", 16) == 0) {
- if(!tp) return -1;
- lock_basic_lock(&tp->lock);
- tp->autr->query_failed = (uint8_t)parse_int(line+16, &r);
- lock_basic_unlock(&tp->lock);
- } else if(strncmp(line, ";;query_interval: ", 18) == 0) {
- if(!tp) return -1;
- lock_basic_lock(&tp->lock);
- tp->autr->query_interval = (time_t)parse_int(line+18, &r);
- lock_basic_unlock(&tp->lock);
- } else if(strncmp(line, ";;retry_time: ", 14) == 0) {
- if(!tp) return -1;
- lock_basic_lock(&tp->lock);
- tp->autr->retry_time = (time_t)parse_int(line+14, &r);
- lock_basic_unlock(&tp->lock);
- }
- return r;
-}
-
-/** handle origin lines */
-static int
-handle_origin(char* line, uint8_t** origin, size_t* origin_len)
-{
- size_t len = 0;
- while(isspace((unsigned char)*line))
- line++;
- if(strncmp(line, "$ORIGIN", 7) != 0)
- return 0;
- free(*origin);
- line += 7;
- while(isspace((unsigned char)*line))
- line++;
- *origin = sldns_str2wire_dname(line, &len);
- *origin_len = len;
- if(!*origin)
- log_warn("malloc failure or parse error in $ORIGIN");
- return 1;
-}
-
-/** Read one line and put multiline RRs onto one line string */
-static int
-read_multiline(char* buf, size_t len, FILE* in, int* linenr)
-{
- char* pos = buf;
- size_t left = len;
- int depth = 0;
- buf[len-1] = 0;
- while(left > 0 && fgets(pos, (int)left, in) != NULL) {
- size_t i, poslen = strlen(pos);
- (*linenr)++;
-
- /* check what the new depth is after the line */
- /* this routine cannot handle braces inside quotes,
- say for TXT records, but this routine only has to read keys */
- for(i=0; i<poslen; i++) {
- if(pos[i] == '(') {
- depth++;
- } else if(pos[i] == ')') {
- if(depth == 0) {
- log_err("mismatch: too many ')'");
- return -1;
- }
- depth--;
- } else if(pos[i] == ';') {
- break;
- }
- }
-
- /* normal oneline or last line: keeps newline and comments */
- if(depth == 0) {
- return 1;
- }
-
- /* more lines expected, snip off comments and newline */
- if(poslen>0)
- pos[poslen-1] = 0; /* strip newline */
- if(strchr(pos, ';'))
- strchr(pos, ';')[0] = 0; /* strip comments */
-
- /* move to paste other lines behind this one */
- poslen = strlen(pos);
- pos += poslen;
- left -= poslen;
- /* the newline is changed into a space */
- if(left <= 2 /* space and eos */) {
- log_err("line too long");
- return -1;
- }
- pos[0] = ' ';
- pos[1] = 0;
- pos += 1;
- left -= 1;
- }
- if(depth != 0) {
- log_err("mismatch: too many '('");
- return -1;
- }
- if(pos != buf)
- return 1;
- return 0;
-}
-
-int autr_read_file(struct val_anchors* anchors, const char* nm)
-{
- /* the file descriptor */
- FILE* fd;
- /* keep track of line numbers */
- int line_nr = 0;
- /* single line */
- char line[10240];
- /* trust point being read */
- struct trust_anchor *tp = NULL, *tp2;
- int r;
- /* for $ORIGIN parsing */
- uint8_t *origin=NULL, *prev=NULL;
- size_t origin_len=0, prev_len=0;
-
- if (!(fd = fopen(nm, "r"))) {
- log_err("unable to open %s for reading: %s",
- nm, strerror(errno));
- return 0;
- }
- verbose(VERB_ALGO, "reading autotrust anchor file %s", nm);
- while ( (r=read_multiline(line, sizeof(line), fd, &line_nr)) != 0) {
- if(r == -1 || (r = parse_var_line(line, anchors, &tp)) == -1) {
- log_err("could not parse auto-trust-anchor-file "
- "%s line %d", nm, line_nr);
- fclose(fd);
- free(origin);
- free(prev);
- return 0;
- } else if(r == 1) {
- continue;
- } else if(r == 2) {
- log_warn("trust anchor %s has been revoked", nm);
- fclose(fd);
- free(origin);
- free(prev);
- return 1;
- }
- if (!str_contains_data(line, ';'))
- continue; /* empty lines allowed */
- if(handle_origin(line, &origin, &origin_len))
- continue;
- r = 0;
- if(!(tp2=load_trustanchor(anchors, line, nm, origin,
- origin_len, &prev, &prev_len, &r))) {
- if(!r) log_err("failed to load trust anchor from %s "
- "at line %i, skipping", nm, line_nr);
- /* try to do the rest */
- continue;
- }
- if(tp && tp != tp2) {
- log_err("file %s has mismatching data inside: "
- "the file may only contain keys for one name, "
- "remove keys for other domain names", nm);
- fclose(fd);
- free(origin);
- free(prev);
- return 0;
- }
- tp = tp2;
- }
- fclose(fd);
- free(origin);
- free(prev);
- if(!tp) {
- log_err("failed to read %s", nm);
- return 0;
- }
-
- /* now assemble the data into DNSKEY and DS packed rrsets */
- lock_basic_lock(&tp->lock);
- if(!autr_assemble(tp)) {
- lock_basic_unlock(&tp->lock);
- log_err("malloc failure assembling %s", nm);
- return 0;
- }
- lock_basic_unlock(&tp->lock);
- return 1;
-}
-
-/** string for a trustanchor state */
-static const char*
-trustanchor_state2str(autr_state_type s)
-{
- switch (s) {
- case AUTR_STATE_START: return " START ";
- case AUTR_STATE_ADDPEND: return " ADDPEND ";
- case AUTR_STATE_VALID: return " VALID ";
- case AUTR_STATE_MISSING: return " MISSING ";
- case AUTR_STATE_REVOKED: return " REVOKED ";
- case AUTR_STATE_REMOVED: return " REMOVED ";
- }
- return " UNKNOWN ";
-}
-
-/** print ID to file */
-static int
-print_id(FILE* out, char* fname, uint8_t* nm, size_t nmlen, uint16_t dclass)
-{
- char* s = sldns_wire2str_dname(nm, nmlen);
- if(!s) {
- log_err("malloc failure in write to %s", fname);
- return 0;
- }
- if(fprintf(out, ";;id: %s %d\n", s, (int)dclass) < 0) {
- log_err("could not write to %s: %s", fname, strerror(errno));
- free(s);
- return 0;
- }
- free(s);
- return 1;
-}
-
-static int
-autr_write_contents(FILE* out, char* fn, struct trust_anchor* tp)
-{
- char tmi[32];
- struct autr_ta* ta;
- char* str;
-
- /* write pretty header */
- if(fprintf(out, "; autotrust trust anchor file\n") < 0) {
- log_err("could not write to %s: %s", fn, strerror(errno));
- return 0;
- }
- if(tp->autr->revoked) {
- if(fprintf(out, ";;REVOKED\n") < 0 ||
- fprintf(out, "; The zone has all keys revoked, and is\n"
- "; considered as if it has no trust anchors.\n"
- "; the remainder of the file is the last probe.\n"
- "; to restart the trust anchor, overwrite this file.\n"
- "; with one containing valid DNSKEYs or DSes.\n") < 0) {
- log_err("could not write to %s: %s", fn, strerror(errno));
- return 0;
- }
- }
- if(!print_id(out, fn, tp->name, tp->namelen, tp->dclass)) {
- return 0;
- }
- if(fprintf(out, ";;last_queried: %u ;;%s",
- (unsigned int)tp->autr->last_queried,
- ctime_r(&(tp->autr->last_queried), tmi)) < 0 ||
- fprintf(out, ";;last_success: %u ;;%s",
- (unsigned int)tp->autr->last_success,
- ctime_r(&(tp->autr->last_success), tmi)) < 0 ||
- fprintf(out, ";;next_probe_time: %u ;;%s",
- (unsigned int)tp->autr->next_probe_time,
- ctime_r(&(tp->autr->next_probe_time), tmi)) < 0 ||
- fprintf(out, ";;query_failed: %d\n", (int)tp->autr->query_failed)<0
- || fprintf(out, ";;query_interval: %d\n",
- (int)tp->autr->query_interval) < 0 ||
- fprintf(out, ";;retry_time: %d\n", (int)tp->autr->retry_time) < 0) {
- log_err("could not write to %s: %s", fn, strerror(errno));
- return 0;
- }
-
- /* write anchors */
- for(ta=tp->autr->keys; ta; ta=ta->next) {
- /* by default do not store START and REMOVED keys */
- if(ta->s == AUTR_STATE_START)
- continue;
- if(ta->s == AUTR_STATE_REMOVED)
- continue;
- /* only store keys */
- if(sldns_wirerr_get_type(ta->rr, ta->rr_len, ta->dname_len)
- != LDNS_RR_TYPE_DNSKEY)
- continue;
- str = sldns_wire2str_rr(ta->rr, ta->rr_len);
- if(!str || !str[0]) {
- free(str);
- log_err("malloc failure writing %s", fn);
- return 0;
- }
- str[strlen(str)-1] = 0; /* remove newline */
- if(fprintf(out, "%s ;;state=%d [%s] ;;count=%d "
- ";;lastchange=%u ;;%s", str, (int)ta->s,
- trustanchor_state2str(ta->s), (int)ta->pending_count,
- (unsigned int)ta->last_change,
- ctime_r(&(ta->last_change), tmi)) < 0) {
- log_err("could not write to %s: %s", fn, strerror(errno));
- free(str);
- return 0;
- }
- free(str);
- }
- return 1;
-}
-
-void autr_write_file(struct module_env* env, struct trust_anchor* tp)
-{
- FILE* out;
- char* fname = tp->autr->file;
- char tempf[2048];
- log_assert(tp->autr);
- if(!env) {
- log_err("autr_write_file: Module environment is NULL.");
- return;
- }
- /* unique name with pid number and thread number */
- snprintf(tempf, sizeof(tempf), "%s.%d-%d", fname, (int)getpid(),
- env->worker?*(int*)env->worker:0);
- verbose(VERB_ALGO, "autotrust: write to disk: %s", tempf);
- out = fopen(tempf, "w");
- if(!out) {
- fatal_exit("could not open autotrust file for writing, %s: %s",
- tempf, strerror(errno));
- return;
- }
- if(!autr_write_contents(out, tempf, tp)) {
- /* failed to write contents (completely) */
- fclose(out);
- unlink(tempf);
- fatal_exit("could not completely write: %s", fname);
- return;
- }
- if(fflush(out) != 0)
- log_err("could not fflush(%s): %s", fname, strerror(errno));
-#ifdef HAVE_FSYNC
- if(fsync(fileno(out)) != 0)
- log_err("could not fsync(%s): %s", fname, strerror(errno));
-#else
- FlushFileBuffers((HANDLE)_get_osfhandle(_fileno(out)));
-#endif
- if(fclose(out) != 0) {
- fatal_exit("could not complete write: %s: %s",
- fname, strerror(errno));
- unlink(tempf);
- return;
- }
- /* success; overwrite actual file */
- verbose(VERB_ALGO, "autotrust: replaced %s", fname);
-#ifdef UB_ON_WINDOWS
- (void)unlink(fname); /* windows does not replace file with rename() */
-#endif
- if(rename(tempf, fname) < 0) {
- fatal_exit("rename(%s to %s): %s", tempf, fname, strerror(errno));
- }
-}
-
-/**
- * Verify if dnskey works for trust point
- * @param env: environment (with time) for verification
- * @param ve: validator environment (with options) for verification.
- * @param tp: trust point to verify with
- * @param rrset: DNSKEY rrset to verify.
- * @return false on failure, true if verification successful.
- */
-static int
-verify_dnskey(struct module_env* env, struct val_env* ve,
- struct trust_anchor* tp, struct ub_packed_rrset_key* rrset)
-{
- char* reason = NULL;
- uint8_t sigalg[ALGO_NEEDS_MAX+1];
- int downprot = env->cfg->harden_algo_downgrade;
- enum sec_status sec = val_verify_DNSKEY_with_TA(env, ve, rrset,
- tp->ds_rrset, tp->dnskey_rrset, downprot?sigalg:NULL, &reason);
- /* sigalg is ignored, it returns algorithms signalled to exist, but
- * in 5011 there are no other rrsets to check. if downprot is
- * enabled, then it checks that the DNSKEY is signed with all
- * algorithms available in the trust store. */
- verbose(VERB_ALGO, "autotrust: validate DNSKEY with anchor: %s",
- sec_status_to_string(sec));
- return sec == sec_status_secure;
-}
-
-static int32_t
-rrsig_get_expiry(uint8_t* d, size_t len)
-{
- /* rrsig: 2(rdlen), 2(type) 1(alg) 1(v) 4(origttl), then 4(expi), (4)incep) */
- if(len < 2+8+4)
- return 0;
- return sldns_read_uint32(d+2+8);
-}
-
-/** Find minimum expiration interval from signatures */
-static time_t
-min_expiry(struct module_env* env, struct packed_rrset_data* dd)
-{
- size_t i;
- int32_t t, r = 15 * 24 * 3600; /* 15 days max */
- for(i=dd->count; i<dd->count+dd->rrsig_count; i++) {
- t = rrsig_get_expiry(dd->rr_data[i], dd->rr_len[i]);
- if((int32_t)t - (int32_t)*env->now > 0) {
- t -= (int32_t)*env->now;
- if(t < r)
- r = t;
- }
- }
- return (time_t)r;
-}
-
-/** Is rr self-signed revoked key */
-static int
-rr_is_selfsigned_revoked(struct module_env* env, struct val_env* ve,
- struct ub_packed_rrset_key* dnskey_rrset, size_t i)
-{
- enum sec_status sec;
- char* reason = NULL;
- verbose(VERB_ALGO, "seen REVOKE flag, check self-signed, rr %d",
- (int)i);
- /* no algorithm downgrade protection necessary, if it is selfsigned
- * revoked it can be removed. */
- sec = dnskey_verify_rrset(env, ve, dnskey_rrset, dnskey_rrset, i,
- &reason);
- return (sec == sec_status_secure);
-}
-
-/** Set fetched value */
-static void
-seen_trustanchor(struct autr_ta* ta, uint8_t seen)
-{
- ta->fetched = seen;
- if(ta->pending_count < 250) /* no numerical overflow, please */
- ta->pending_count++;
-}
-
-/** set revoked value */
-static void
-seen_revoked_trustanchor(struct autr_ta* ta, uint8_t revoked)
-{
- ta->revoked = revoked;
-}
-
-/** revoke a trust anchor */
-static void
-revoke_dnskey(struct autr_ta* ta, int off)
-{
- uint16_t flags;
- uint8_t* data;
- if(sldns_wirerr_get_type(ta->rr, ta->rr_len, ta->dname_len) !=
- LDNS_RR_TYPE_DNSKEY)
- return;
- if(sldns_wirerr_get_rdatalen(ta->rr, ta->rr_len, ta->dname_len) < 2)
- return;
- data = sldns_wirerr_get_rdata(ta->rr, ta->rr_len, ta->dname_len);
- flags = sldns_read_uint16(data);
- if (off && (flags&LDNS_KEY_REVOKE_KEY))
- flags ^= LDNS_KEY_REVOKE_KEY; /* flip */
- else
- flags |= LDNS_KEY_REVOKE_KEY;
- sldns_write_uint16(data, flags);
-}
-
-/** Compare two RRs skipping the REVOKED bit. Pass rdata(no len) */
-static int
-dnskey_compare_skip_revbit(uint8_t* a, size_t a_len, uint8_t* b, size_t b_len)
-{
- size_t i;
- if(a_len != b_len)
- return -1;
- /* compare RRs RDATA byte for byte. */
- for(i = 0; i < a_len; i++)
- {
- uint8_t rdf1, rdf2;
- rdf1 = a[i];
- rdf2 = b[i];
- if(i==1) {
- /* this is the second part of the flags field */
- rdf1 |= LDNS_KEY_REVOKE_KEY;
- rdf2 |= LDNS_KEY_REVOKE_KEY;
- }
- if (rdf1 < rdf2) return -1;
- else if (rdf1 > rdf2) return 1;
- }
- return 0;
-}
-
-
-/** compare trust anchor with rdata, 0 if equal. Pass rdata(no len) */
-static int
-ta_compare(struct autr_ta* a, uint16_t t, uint8_t* b, size_t b_len)
-{
- if(!a) return -1;
- else if(!b) return -1;
- else if(sldns_wirerr_get_type(a->rr, a->rr_len, a->dname_len) != t)
- return (int)sldns_wirerr_get_type(a->rr, a->rr_len,
- a->dname_len) - (int)t;
- else if(t == LDNS_RR_TYPE_DNSKEY) {
- return dnskey_compare_skip_revbit(
- sldns_wirerr_get_rdata(a->rr, a->rr_len, a->dname_len),
- sldns_wirerr_get_rdatalen(a->rr, a->rr_len,
- a->dname_len), b, b_len);
- }
- else if(t == LDNS_RR_TYPE_DS) {
- if(sldns_wirerr_get_rdatalen(a->rr, a->rr_len, a->dname_len) !=
- b_len)
- return -1;
- return memcmp(sldns_wirerr_get_rdata(a->rr,
- a->rr_len, a->dname_len), b, b_len);
- }
- return -1;
-}
-
-/**
- * Find key
- * @param tp: to search in
- * @param t: rr type of the rdata.
- * @param rdata: to look for (no rdatalen in it)
- * @param rdata_len: length of rdata
- * @param result: returns NULL or the ta key looked for.
- * @return false on malloc failure during search. if true examine result.
- */
-static int
-find_key(struct trust_anchor* tp, uint16_t t, uint8_t* rdata, size_t rdata_len,
- struct autr_ta** result)
-{
- struct autr_ta* ta;
- if(!tp || !rdata) {
- *result = NULL;
- return 0;
- }
- for(ta=tp->autr->keys; ta; ta=ta->next) {
- if(ta_compare(ta, t, rdata, rdata_len) == 0) {
- *result = ta;
- return 1;
- }
- }
- *result = NULL;
- return 1;
-}
-
-/** add key and clone RR and tp already locked. rdata without rdlen. */
-static struct autr_ta*
-add_key(struct trust_anchor* tp, uint32_t ttl, uint8_t* rdata, size_t rdata_len)
-{
- struct autr_ta* ta;
- uint8_t* rr;
- size_t rr_len, dname_len;
- uint16_t rrtype = htons(LDNS_RR_TYPE_DNSKEY);
- uint16_t rrclass = htons(LDNS_RR_CLASS_IN);
- uint16_t rdlen = htons(rdata_len);
- dname_len = tp->namelen;
- ttl = htonl(ttl);
- rr_len = dname_len + 10 /* type,class,ttl,rdatalen */ + rdata_len;
- rr = (uint8_t*)malloc(rr_len);
- if(!rr) return NULL;
- memmove(rr, tp->name, tp->namelen);
- memmove(rr+dname_len, &rrtype, 2);
- memmove(rr+dname_len+2, &rrclass, 2);
- memmove(rr+dname_len+4, &ttl, 4);
- memmove(rr+dname_len+8, &rdlen, 2);
- memmove(rr+dname_len+10, rdata, rdata_len);
- ta = autr_ta_create(rr, rr_len, dname_len);
- if(!ta) {
- /* rr freed in autr_ta_create */
- return NULL;
- }
- /* link in, tp already locked */
- ta->next = tp->autr->keys;
- tp->autr->keys = ta;
- return ta;
-}
-
-/** get TTL from DNSKEY rrset */
-static time_t
-key_ttl(struct ub_packed_rrset_key* k)
-{
- struct packed_rrset_data* d = (struct packed_rrset_data*)k->entry.data;
- return d->ttl;
-}
-
-/** update the time values for the trustpoint */
-static void
-set_tp_times(struct trust_anchor* tp, time_t rrsig_exp_interval,
- time_t origttl, int* changed)
-{
- time_t x, qi = tp->autr->query_interval, rt = tp->autr->retry_time;
-
- /* x = MIN(15days, ttl/2, expire/2) */
- x = 15 * 24 * 3600;
- if(origttl/2 < x)
- x = origttl/2;
- if(rrsig_exp_interval/2 < x)
- x = rrsig_exp_interval/2;
- /* MAX(1hr, x) */
- if(!autr_permit_small_holddown) {
- if(x < 3600)
- tp->autr->query_interval = 3600;
- else tp->autr->query_interval = x;
- } else tp->autr->query_interval = x;
-
- /* x= MIN(1day, ttl/10, expire/10) */
- x = 24 * 3600;
- if(origttl/10 < x)
- x = origttl/10;
- if(rrsig_exp_interval/10 < x)
- x = rrsig_exp_interval/10;
- /* MAX(1hr, x) */
- if(!autr_permit_small_holddown) {
- if(x < 3600)
- tp->autr->retry_time = 3600;
- else tp->autr->retry_time = x;
- } else tp->autr->retry_time = x;
-
- if(qi != tp->autr->query_interval || rt != tp->autr->retry_time) {
- *changed = 1;
- verbose(VERB_ALGO, "orig_ttl is %d", (int)origttl);
- verbose(VERB_ALGO, "rrsig_exp_interval is %d",
- (int)rrsig_exp_interval);
- verbose(VERB_ALGO, "query_interval: %d, retry_time: %d",
- (int)tp->autr->query_interval,
- (int)tp->autr->retry_time);
- }
-}
-
-/** init events to zero */
-static void
-init_events(struct trust_anchor* tp)
-{
- struct autr_ta* ta;
- for(ta=tp->autr->keys; ta; ta=ta->next) {
- ta->fetched = 0;
- }
-}
-
-/** check for revoked keys without trusting any other information */
-static void
-check_contains_revoked(struct module_env* env, struct val_env* ve,
- struct trust_anchor* tp, struct ub_packed_rrset_key* dnskey_rrset,
- int* changed)
-{
- struct packed_rrset_data* dd = (struct packed_rrset_data*)
- dnskey_rrset->entry.data;
- size_t i;
- log_assert(ntohs(dnskey_rrset->rk.type) == LDNS_RR_TYPE_DNSKEY);
- for(i=0; i<dd->count; i++) {
- struct autr_ta* ta = NULL;
- if(!rr_is_dnskey_sep(ntohs(dnskey_rrset->rk.type),
- dd->rr_data[i]+2, dd->rr_len[i]-2) ||
- !rr_is_dnskey_revoked(ntohs(dnskey_rrset->rk.type),
- dd->rr_data[i]+2, dd->rr_len[i]-2))
- continue; /* not a revoked KSK */
- if(!find_key(tp, ntohs(dnskey_rrset->rk.type),
- dd->rr_data[i]+2, dd->rr_len[i]-2, &ta)) {
- log_err("malloc failure");
- continue; /* malloc fail in compare*/
- }
- if(!ta)
- continue; /* key not found */
- if(rr_is_selfsigned_revoked(env, ve, dnskey_rrset, i)) {
- /* checked if there is an rrsig signed by this key. */
- /* same keytag, but stored can be revoked already, so
- * compare keytags, with +0 or +128(REVOKE flag) */
- log_assert(dnskey_calc_keytag(dnskey_rrset, i)-128 ==
- sldns_calc_keytag_raw(sldns_wirerr_get_rdata(
- ta->rr, ta->rr_len, ta->dname_len),
- sldns_wirerr_get_rdatalen(ta->rr, ta->rr_len,
- ta->dname_len)) ||
- dnskey_calc_keytag(dnskey_rrset, i) ==
- sldns_calc_keytag_raw(sldns_wirerr_get_rdata(
- ta->rr, ta->rr_len, ta->dname_len),
- sldns_wirerr_get_rdatalen(ta->rr, ta->rr_len,
- ta->dname_len))); /* checks conversion*/
- verbose_key(ta, VERB_ALGO, "is self-signed revoked");
- if(!ta->revoked)
- *changed = 1;
- seen_revoked_trustanchor(ta, 1);
- do_revoked(env, ta, changed);
- }
- }
-}
-
-/** See if a DNSKEY is verified by one of the DSes */
-static int
-key_matches_a_ds(struct module_env* env, struct val_env* ve,
- struct ub_packed_rrset_key* dnskey_rrset, size_t key_idx,
- struct ub_packed_rrset_key* ds_rrset)
-{
- struct packed_rrset_data* dd = (struct packed_rrset_data*)
- ds_rrset->entry.data;
- size_t ds_idx, num = dd->count;
- int d = val_favorite_ds_algo(ds_rrset);
- char* reason = "";
- for(ds_idx=0; ds_idx<num; ds_idx++) {
- if(!ds_digest_algo_is_supported(ds_rrset, ds_idx) ||
- !ds_key_algo_is_supported(ds_rrset, ds_idx) ||
- ds_get_digest_algo(ds_rrset, ds_idx) != d)
- continue;
- if(ds_get_key_algo(ds_rrset, ds_idx)
- != dnskey_get_algo(dnskey_rrset, key_idx)
- || dnskey_calc_keytag(dnskey_rrset, key_idx)
- != ds_get_keytag(ds_rrset, ds_idx)) {
- continue;
- }
- if(!ds_digest_match_dnskey(env, dnskey_rrset, key_idx,
- ds_rrset, ds_idx)) {
- verbose(VERB_ALGO, "DS match attempt failed");
- continue;
- }
- if(dnskey_verify_rrset(env, ve, dnskey_rrset,
- dnskey_rrset, key_idx, &reason) == sec_status_secure) {
- return 1;
- } else {
- verbose(VERB_ALGO, "DS match failed because the key "
- "does not verify the keyset: %s", reason);
- }
- }
- return 0;
-}
-
-/** Set update events */
-static int
-update_events(struct module_env* env, struct val_env* ve,
- struct trust_anchor* tp, struct ub_packed_rrset_key* dnskey_rrset,
- int* changed)
-{
- struct packed_rrset_data* dd = (struct packed_rrset_data*)
- dnskey_rrset->entry.data;
- size_t i;
- log_assert(ntohs(dnskey_rrset->rk.type) == LDNS_RR_TYPE_DNSKEY);
- init_events(tp);
- for(i=0; i<dd->count; i++) {
- struct autr_ta* ta = NULL;
- if(!rr_is_dnskey_sep(ntohs(dnskey_rrset->rk.type),
- dd->rr_data[i]+2, dd->rr_len[i]-2))
- continue;
- if(rr_is_dnskey_revoked(ntohs(dnskey_rrset->rk.type),
- dd->rr_data[i]+2, dd->rr_len[i]-2)) {
- /* self-signed revoked keys already detected before,
- * other revoked keys are not 'added' again */
- continue;
- }
- /* is a key of this type supported?. Note rr_list and
- * packed_rrset are in the same order. */
- if(!dnskey_algo_is_supported(dnskey_rrset, i)) {
- /* skip unknown algorithm key, it is useless to us */
- log_nametypeclass(VERB_DETAIL, "trust point has "
- "unsupported algorithm at",
- tp->name, LDNS_RR_TYPE_DNSKEY, tp->dclass);
- continue;
- }
-
- /* is it new? if revocation bit set, find the unrevoked key */
- if(!find_key(tp, ntohs(dnskey_rrset->rk.type),
- dd->rr_data[i]+2, dd->rr_len[i]-2, &ta)) {
- return 0;
- }
- if(!ta) {
- ta = add_key(tp, (uint32_t)dd->rr_ttl[i],
- dd->rr_data[i]+2, dd->rr_len[i]-2);
- *changed = 1;
- /* first time seen, do we have DSes? if match: VALID */
- if(ta && tp->ds_rrset && key_matches_a_ds(env, ve,
- dnskey_rrset, i, tp->ds_rrset)) {
- verbose_key(ta, VERB_ALGO, "verified by DS");
- ta->s = AUTR_STATE_VALID;
- }
- }
- if(!ta) {
- return 0;
- }
- seen_trustanchor(ta, 1);
- verbose_key(ta, VERB_ALGO, "in DNS response");
- }
- set_tp_times(tp, min_expiry(env, dd), key_ttl(dnskey_rrset), changed);
- return 1;
-}
-
-/**
- * Check if the holddown time has already exceeded
- * setting: add-holddown: add holddown timer
- * setting: del-holddown: del holddown timer
- * @param env: environment with current time
- * @param ta: trust anchor to check for.
- * @param holddown: the timer value
- * @return number of seconds the holddown has passed.
- */
-static time_t
-check_holddown(struct module_env* env, struct autr_ta* ta,
- unsigned int holddown)
-{
- time_t elapsed;
- if(*env->now < ta->last_change) {
- log_warn("time goes backwards. delaying key holddown");
- return 0;
- }
- elapsed = *env->now - ta->last_change;
- if (elapsed > (time_t)holddown) {
- return elapsed-(time_t)holddown;
- }
- verbose_key(ta, VERB_ALGO, "holddown time " ARG_LL "d seconds to go",
- (long long) ((time_t)holddown-elapsed));
- return 0;
-}
-
-
-/** Set last_change to now */
-static void
-reset_holddown(struct module_env* env, struct autr_ta* ta, int* changed)
-{
- ta->last_change = *env->now;
- *changed = 1;
-}
-
-/** Set the state for this trust anchor */
-static void
-set_trustanchor_state(struct module_env* env, struct autr_ta* ta, int* changed,
- autr_state_type s)
-{
- verbose_key(ta, VERB_ALGO, "update: %s to %s",
- trustanchor_state2str(ta->s), trustanchor_state2str(s));
- ta->s = s;
- reset_holddown(env, ta, changed);
-}
-
-
-/** Event: NewKey */
-static void
-do_newkey(struct module_env* env, struct autr_ta* anchor, int* c)
-{
- if (anchor->s == AUTR_STATE_START)
- set_trustanchor_state(env, anchor, c, AUTR_STATE_ADDPEND);
-}
-
-/** Event: AddTime */
-static void
-do_addtime(struct module_env* env, struct autr_ta* anchor, int* c)
-{
- /* This not according to RFC, this is 30 days, but the RFC demands
- * MAX(30days, TTL expire time of first DNSKEY set with this key),
- * The value may be too small if a very large TTL was used. */
- time_t exceeded = check_holddown(env, anchor, env->cfg->add_holddown);
- if (exceeded && anchor->s == AUTR_STATE_ADDPEND) {
- verbose_key(anchor, VERB_ALGO, "add-holddown time exceeded "
- ARG_LL "d seconds ago, and pending-count %d",
- (long long)exceeded, anchor->pending_count);
- if(anchor->pending_count >= MIN_PENDINGCOUNT) {
- set_trustanchor_state(env, anchor, c, AUTR_STATE_VALID);
- anchor->pending_count = 0;
- return;
- }
- verbose_key(anchor, VERB_ALGO, "add-holddown time sanity check "
- "failed (pending count: %d)", anchor->pending_count);
- }
-}
-
-/** Event: RemTime */
-static void
-do_remtime(struct module_env* env, struct autr_ta* anchor, int* c)
-{
- time_t exceeded = check_holddown(env, anchor, env->cfg->del_holddown);
- if(exceeded && anchor->s == AUTR_STATE_REVOKED) {
- verbose_key(anchor, VERB_ALGO, "del-holddown time exceeded "
- ARG_LL "d seconds ago", (long long)exceeded);
- set_trustanchor_state(env, anchor, c, AUTR_STATE_REMOVED);
- }
-}
-
-/** Event: KeyRem */
-static void
-do_keyrem(struct module_env* env, struct autr_ta* anchor, int* c)
-{
- if(anchor->s == AUTR_STATE_ADDPEND) {
- set_trustanchor_state(env, anchor, c, AUTR_STATE_START);
- anchor->pending_count = 0;
- } else if(anchor->s == AUTR_STATE_VALID)
- set_trustanchor_state(env, anchor, c, AUTR_STATE_MISSING);
-}
-
-/** Event: KeyPres */
-static void
-do_keypres(struct module_env* env, struct autr_ta* anchor, int* c)
-{
- if(anchor->s == AUTR_STATE_MISSING)
- set_trustanchor_state(env, anchor, c, AUTR_STATE_VALID);
-}
-
-/* Event: Revoked */
-static void
-do_revoked(struct module_env* env, struct autr_ta* anchor, int* c)
-{
- if(anchor->s == AUTR_STATE_VALID || anchor->s == AUTR_STATE_MISSING) {
- set_trustanchor_state(env, anchor, c, AUTR_STATE_REVOKED);
- verbose_key(anchor, VERB_ALGO, "old id, prior to revocation");
- revoke_dnskey(anchor, 0);
- verbose_key(anchor, VERB_ALGO, "new id, after revocation");
- }
-}
-
-/** Do statestable transition matrix for anchor */
-static void
-anchor_state_update(struct module_env* env, struct autr_ta* anchor, int* c)
-{
- log_assert(anchor);
- switch(anchor->s) {
- /* START */
- case AUTR_STATE_START:
- /* NewKey: ADDPEND */
- if (anchor->fetched)
- do_newkey(env, anchor, c);
- break;
- /* ADDPEND */
- case AUTR_STATE_ADDPEND:
- /* KeyRem: START */
- if (!anchor->fetched)
- do_keyrem(env, anchor, c);
- /* AddTime: VALID */
- else do_addtime(env, anchor, c);
- break;
- /* VALID */
- case AUTR_STATE_VALID:
- /* RevBit: REVOKED */
- if (anchor->revoked)
- do_revoked(env, anchor, c);
- /* KeyRem: MISSING */
- else if (!anchor->fetched)
- do_keyrem(env, anchor, c);
- else if(!anchor->last_change) {
- verbose_key(anchor, VERB_ALGO, "first seen");
- reset_holddown(env, anchor, c);
- }
- break;
- /* MISSING */
- case AUTR_STATE_MISSING:
- /* RevBit: REVOKED */
- if (anchor->revoked)
- do_revoked(env, anchor, c);
- /* KeyPres */
- else if (anchor->fetched)
- do_keypres(env, anchor, c);
- break;
- /* REVOKED */
- case AUTR_STATE_REVOKED:
- if (anchor->fetched)
- reset_holddown(env, anchor, c);
- /* RemTime: REMOVED */
- else do_remtime(env, anchor, c);
- break;
- /* REMOVED */
- case AUTR_STATE_REMOVED:
- default:
- break;
- }
-}
-
-/** if ZSK init then trust KSKs */
-static int
-init_zsk_to_ksk(struct module_env* env, struct trust_anchor* tp, int* changed)
-{
- /* search for VALID ZSKs */
- struct autr_ta* anchor;
- int validzsk = 0;
- int validksk = 0;
- for(anchor = tp->autr->keys; anchor; anchor = anchor->next) {
- /* last_change test makes sure it was manually configured */
- if(sldns_wirerr_get_type(anchor->rr, anchor->rr_len,
- anchor->dname_len) == LDNS_RR_TYPE_DNSKEY &&
- anchor->last_change == 0 &&
- !ta_is_dnskey_sep(anchor) &&
- anchor->s == AUTR_STATE_VALID)
- validzsk++;
- }
- if(validzsk == 0)
- return 0;
- for(anchor = tp->autr->keys; anchor; anchor = anchor->next) {
- if (ta_is_dnskey_sep(anchor) &&
- anchor->s == AUTR_STATE_ADDPEND) {
- verbose_key(anchor, VERB_ALGO, "trust KSK from "
- "ZSK(config)");
- set_trustanchor_state(env, anchor, changed,
- AUTR_STATE_VALID);
- validksk++;
- }
- }
- return validksk;
-}
-
-/** Remove missing trustanchors so the list does not grow forever */
-static void
-remove_missing_trustanchors(struct module_env* env, struct trust_anchor* tp,
- int* changed)
-{
- struct autr_ta* anchor;
- time_t exceeded;
- int valid = 0;
- /* see if we have anchors that are valid */
- for(anchor = tp->autr->keys; anchor; anchor = anchor->next) {
- /* Only do KSKs */
- if (!ta_is_dnskey_sep(anchor))
- continue;
- if (anchor->s == AUTR_STATE_VALID)
- valid++;
- }
- /* if there are no SEP Valid anchors, see if we started out with
- * a ZSK (last-change=0) anchor, which is VALID and there are KSKs
- * now that can be made valid. Do this immediately because there
- * is no guarantee that the ZSKs get announced long enough. Usually
- * this is immediately after init with a ZSK trusted, unless the domain
- * was not advertising any KSKs at all. In which case we perfectly
- * track the zero number of KSKs. */
- if(valid == 0) {
- valid = init_zsk_to_ksk(env, tp, changed);
- if(valid == 0)
- return;
- }
-
- for(anchor = tp->autr->keys; anchor; anchor = anchor->next) {
- /* ignore ZSKs if newly added */
- if(anchor->s == AUTR_STATE_START)
- continue;
- /* remove ZSKs if a KSK is present */
- if (!ta_is_dnskey_sep(anchor)) {
- if(valid > 0) {
- verbose_key(anchor, VERB_ALGO, "remove ZSK "
- "[%d key(s) VALID]", valid);
- set_trustanchor_state(env, anchor, changed,
- AUTR_STATE_REMOVED);
- }
- continue;
- }
- /* Only do MISSING keys */
- if (anchor->s != AUTR_STATE_MISSING)
- continue;
- if(env->cfg->keep_missing == 0)
- continue; /* keep forever */
-
- exceeded = check_holddown(env, anchor, env->cfg->keep_missing);
- /* If keep_missing has exceeded and we still have more than
- * one valid KSK: remove missing trust anchor */
- if (exceeded && valid > 0) {
- verbose_key(anchor, VERB_ALGO, "keep-missing time "
- "exceeded " ARG_LL "d seconds ago, [%d key(s) VALID]",
- (long long)exceeded, valid);
- set_trustanchor_state(env, anchor, changed,
- AUTR_STATE_REMOVED);
- }
- }
-}
-
-/** Do the statetable from RFC5011 transition matrix */
-static int
-do_statetable(struct module_env* env, struct trust_anchor* tp, int* changed)
-{
- struct autr_ta* anchor;
- for(anchor = tp->autr->keys; anchor; anchor = anchor->next) {
- /* Only do KSKs */
- if(!ta_is_dnskey_sep(anchor))
- continue;
- anchor_state_update(env, anchor, changed);
- }
- remove_missing_trustanchors(env, tp, changed);
- return 1;
-}
-
-/** See if time alone makes ADDPEND to VALID transition */
-static void
-autr_holddown_exceed(struct module_env* env, struct trust_anchor* tp, int* c)
-{
- struct autr_ta* anchor;
- for(anchor = tp->autr->keys; anchor; anchor = anchor->next) {
- if(ta_is_dnskey_sep(anchor) &&
- anchor->s == AUTR_STATE_ADDPEND)
- do_addtime(env, anchor, c);
- }
-}
-
-/** cleanup key list */
-static void
-autr_cleanup_keys(struct trust_anchor* tp)
-{
- struct autr_ta* p, **prevp;
- prevp = &tp->autr->keys;
- p = tp->autr->keys;
- while(p) {
- /* do we want to remove this key? */
- if(p->s == AUTR_STATE_START || p->s == AUTR_STATE_REMOVED ||
- sldns_wirerr_get_type(p->rr, p->rr_len, p->dname_len)
- != LDNS_RR_TYPE_DNSKEY) {
- struct autr_ta* np = p->next;
- /* remove */
- free(p->rr);
- free(p);
- /* snip and go to next item */
- *prevp = np;
- p = np;
- continue;
- }
- /* remove pending counts if no longer pending */
- if(p->s != AUTR_STATE_ADDPEND)
- p->pending_count = 0;
- prevp = &p->next;
- p = p->next;
- }
-}
-
-/** calculate next probe time */
-static time_t
-calc_next_probe(struct module_env* env, time_t wait)
-{
- /* make it random, 90-100% */
- time_t rnd, rest;
- if(!autr_permit_small_holddown) {
- if(wait < 3600)
- wait = 3600;
- } else {
- if(wait == 0) wait = 1;
- }
- rnd = wait/10;
- rest = wait-rnd;
- rnd = (time_t)ub_random_max(env->rnd, (long int)rnd);
- return (time_t)(*env->now + rest + rnd);
-}
-
-/** what is first probe time (anchors must be locked) */
-static time_t
-wait_probe_time(struct val_anchors* anchors)
-{
- rbnode_type* t = rbtree_first(&anchors->autr->probe);
- if(t != RBTREE_NULL)
- return ((struct trust_anchor*)t->key)->autr->next_probe_time;
- return 0;
-}
-
-/** reset worker timer */
-static void
-reset_worker_timer(struct module_env* env)
-{
- struct timeval tv;
-#ifndef S_SPLINT_S
- time_t next = (time_t)wait_probe_time(env->anchors);
- /* in case this is libunbound, no timer */
- if(!env->probe_timer)
- return;
- if(next > *env->now)
- tv.tv_sec = (time_t)(next - *env->now);
- else tv.tv_sec = 0;
-#endif
- tv.tv_usec = 0;
- comm_timer_set(env->probe_timer, &tv);
- verbose(VERB_ALGO, "scheduled next probe in " ARG_LL "d sec", (long long)tv.tv_sec);
-}
-
-/** set next probe for trust anchor */
-static int
-set_next_probe(struct module_env* env, struct trust_anchor* tp,
- struct ub_packed_rrset_key* dnskey_rrset)
-{
- struct trust_anchor key, *tp2;
- time_t mold, mnew;
- /* use memory allocated in rrset for temporary name storage */
- key.node.key = &key;
- key.name = dnskey_rrset->rk.dname;
- key.namelen = dnskey_rrset->rk.dname_len;
- key.namelabs = dname_count_labels(key.name);
- key.dclass = tp->dclass;
- lock_basic_unlock(&tp->lock);
-
- /* fetch tp again and lock anchors, so that we can modify the trees */
- lock_basic_lock(&env->anchors->lock);
- tp2 = (struct trust_anchor*)rbtree_search(env->anchors->tree, &key);
- if(!tp2) {
- verbose(VERB_ALGO, "trustpoint was deleted in set_next_probe");
- lock_basic_unlock(&env->anchors->lock);
- return 0;
- }
- log_assert(tp == tp2);
- lock_basic_lock(&tp->lock);
-
- /* schedule */
- mold = wait_probe_time(env->anchors);
- (void)rbtree_delete(&env->anchors->autr->probe, tp);
- tp->autr->next_probe_time = calc_next_probe(env,
- tp->autr->query_interval);
- (void)rbtree_insert(&env->anchors->autr->probe, &tp->autr->pnode);
- mnew = wait_probe_time(env->anchors);
-
- lock_basic_unlock(&env->anchors->lock);
- verbose(VERB_ALGO, "next probe set in %d seconds",
- (int)tp->autr->next_probe_time - (int)*env->now);
- if(mold != mnew) {
- reset_worker_timer(env);
- }
- return 1;
-}
-
-/** Revoke and Delete a trust point */
-static void
-autr_tp_remove(struct module_env* env, struct trust_anchor* tp,
- struct ub_packed_rrset_key* dnskey_rrset)
-{
- struct trust_anchor* del_tp;
- struct trust_anchor key;
- struct autr_point_data pd;
- time_t mold, mnew;
-
- log_nametypeclass(VERB_OPS, "trust point was revoked",
- tp->name, LDNS_RR_TYPE_DNSKEY, tp->dclass);
- tp->autr->revoked = 1;
-
- /* use space allocated for dnskey_rrset to save name of anchor */
- memset(&key, 0, sizeof(key));
- memset(&pd, 0, sizeof(pd));
- key.autr = &pd;
- key.node.key = &key;
- pd.pnode.key = &key;
- pd.next_probe_time = tp->autr->next_probe_time;
- key.name = dnskey_rrset->rk.dname;
- key.namelen = tp->namelen;
- key.namelabs = tp->namelabs;
- key.dclass = tp->dclass;
-
- /* unlock */
- lock_basic_unlock(&tp->lock);
-
- /* take from tree. It could be deleted by someone else,hence (void). */
- lock_basic_lock(&env->anchors->lock);
- del_tp = (struct trust_anchor*)rbtree_delete(env->anchors->tree, &key);
- mold = wait_probe_time(env->anchors);
- (void)rbtree_delete(&env->anchors->autr->probe, &key);
- mnew = wait_probe_time(env->anchors);
- anchors_init_parents_locked(env->anchors);
- lock_basic_unlock(&env->anchors->lock);
-
- /* if !del_tp then the trust point is no longer present in the tree,
- * it was deleted by someone else, who will write the zonefile and
- * clean up the structure */
- if(del_tp) {
- /* save on disk */
- del_tp->autr->next_probe_time = 0; /* no more probing for it */
- autr_write_file(env, del_tp);
-
- /* delete */
- autr_point_delete(del_tp);
- }
- if(mold != mnew) {
- reset_worker_timer(env);
- }
-}
-
-int autr_process_prime(struct module_env* env, struct val_env* ve,
- struct trust_anchor* tp, struct ub_packed_rrset_key* dnskey_rrset)
-{
- int changed = 0;
- log_assert(tp && tp->autr);
- /* autotrust update trust anchors */
- /* the tp is locked, and stays locked unless it is deleted */
-
- /* we could just catch the anchor here while another thread
- * is busy deleting it. Just unlock and let the other do its job */
- if(tp->autr->revoked) {
- log_nametypeclass(VERB_ALGO, "autotrust not processed, "
- "trust point revoked", tp->name,
- LDNS_RR_TYPE_DNSKEY, tp->dclass);
- lock_basic_unlock(&tp->lock);
- return 0; /* it is revoked */
- }
-
- /* query_dnskeys(): */
- tp->autr->last_queried = *env->now;
-
- log_nametypeclass(VERB_ALGO, "autotrust process for",
- tp->name, LDNS_RR_TYPE_DNSKEY, tp->dclass);
- /* see if time alone makes some keys valid */
- autr_holddown_exceed(env, tp, &changed);
- if(changed) {
- verbose(VERB_ALGO, "autotrust: morekeys, reassemble");
- if(!autr_assemble(tp)) {
- log_err("malloc failure assembling autotrust keys");
- return 1; /* unchanged */
- }
- }
- /* did we get any data? */
- if(!dnskey_rrset) {
- verbose(VERB_ALGO, "autotrust: no dnskey rrset");
- /* no update of query_failed, because then we would have
- * to write to disk. But we cannot because we maybe are
- * still 'initialising' with DS records, that we cannot write
- * in the full format (which only contains KSKs). */
- return 1; /* trust point exists */
- }
- /* check for revoked keys to remove immediately */
- check_contains_revoked(env, ve, tp, dnskey_rrset, &changed);
- if(changed) {
- verbose(VERB_ALGO, "autotrust: revokedkeys, reassemble");
- if(!autr_assemble(tp)) {
- log_err("malloc failure assembling autotrust keys");
- return 1; /* unchanged */
- }
- if(!tp->ds_rrset && !tp->dnskey_rrset) {
- /* no more keys, all are revoked */
- /* this is a success for this probe attempt */
- tp->autr->last_success = *env->now;
- autr_tp_remove(env, tp, dnskey_rrset);
- return 0; /* trust point removed */
- }
- }
- /* verify the dnskey rrset and see if it is valid. */
- if(!verify_dnskey(env, ve, tp, dnskey_rrset)) {
- verbose(VERB_ALGO, "autotrust: dnskey did not verify.");
- /* only increase failure count if this is not the first prime,
- * this means there was a previous successful probe */
- if(tp->autr->last_success) {
- tp->autr->query_failed += 1;
- autr_write_file(env, tp);
- }
- return 1; /* trust point exists */
- }
-
- tp->autr->last_success = *env->now;
- tp->autr->query_failed = 0;
-
- /* Add new trust anchors to the data structure
- * - note which trust anchors are seen this probe.
- * Set trustpoint query_interval and retry_time.
- * - find minimum rrsig expiration interval
- */
- if(!update_events(env, ve, tp, dnskey_rrset, &changed)) {
- log_err("malloc failure in autotrust update_events. "
- "trust point unchanged.");
- return 1; /* trust point unchanged, so exists */
- }
-
- /* - for every SEP key do the 5011 statetable.
- * - remove missing trustanchors (if veryold and we have new anchors).
- */
- if(!do_statetable(env, tp, &changed)) {
- log_err("malloc failure in autotrust do_statetable. "
- "trust point unchanged.");
- return 1; /* trust point unchanged, so exists */
- }
-
- autr_cleanup_keys(tp);
- if(!set_next_probe(env, tp, dnskey_rrset))
- return 0; /* trust point does not exist */
- autr_write_file(env, tp);
- if(changed) {
- verbose(VERB_ALGO, "autotrust: changed, reassemble");
- if(!autr_assemble(tp)) {
- log_err("malloc failure assembling autotrust keys");
- return 1; /* unchanged */
- }
- if(!tp->ds_rrset && !tp->dnskey_rrset) {
- /* no more keys, all are revoked */
- autr_tp_remove(env, tp, dnskey_rrset);
- return 0; /* trust point removed */
- }
- } else verbose(VERB_ALGO, "autotrust: no changes");
-
- return 1; /* trust point exists */
-}
-
-/** debug print a trust anchor key */
-static void
-autr_debug_print_ta(struct autr_ta* ta)
-{
- char buf[32];
- char* str = sldns_wire2str_rr(ta->rr, ta->rr_len);
- if(!str) {
- log_info("out of memory in debug_print_ta");
- return;
- }
- if(str && str[0]) str[strlen(str)-1]=0; /* remove newline */
- ctime_r(&ta->last_change, buf);
- if(buf[0]) buf[strlen(buf)-1]=0; /* remove newline */
- log_info("[%s] %s ;;state:%d ;;pending_count:%d%s%s last:%s",
- trustanchor_state2str(ta->s), str, ta->s, ta->pending_count,
- ta->fetched?" fetched":"", ta->revoked?" revoked":"", buf);
- free(str);
-}
-
-/** debug print a trust point */
-static void
-autr_debug_print_tp(struct trust_anchor* tp)
-{
- struct autr_ta* ta;
- char buf[257];
- if(!tp->autr)
- return;
- dname_str(tp->name, buf);
- log_info("trust point %s : %d", buf, (int)tp->dclass);
- log_info("assembled %d DS and %d DNSKEYs",
- (int)tp->numDS, (int)tp->numDNSKEY);
- if(tp->ds_rrset) {
- log_packed_rrset(0, "DS:", tp->ds_rrset);
- }
- if(tp->dnskey_rrset) {
- log_packed_rrset(0, "DNSKEY:", tp->dnskey_rrset);
- }
- log_info("file %s", tp->autr->file);
- ctime_r(&tp->autr->last_queried, buf);
- if(buf[0]) buf[strlen(buf)-1]=0; /* remove newline */
- log_info("last_queried: %u %s", (unsigned)tp->autr->last_queried, buf);
- ctime_r(&tp->autr->last_success, buf);
- if(buf[0]) buf[strlen(buf)-1]=0; /* remove newline */
- log_info("last_success: %u %s", (unsigned)tp->autr->last_success, buf);
- ctime_r(&tp->autr->next_probe_time, buf);
- if(buf[0]) buf[strlen(buf)-1]=0; /* remove newline */
- log_info("next_probe_time: %u %s", (unsigned)tp->autr->next_probe_time,
- buf);
- log_info("query_interval: %u", (unsigned)tp->autr->query_interval);
- log_info("retry_time: %u", (unsigned)tp->autr->retry_time);
- log_info("query_failed: %u", (unsigned)tp->autr->query_failed);
-
- for(ta=tp->autr->keys; ta; ta=ta->next) {
- autr_debug_print_ta(ta);
- }
-}
-
-void
-autr_debug_print(struct val_anchors* anchors)
-{
- struct trust_anchor* tp;
- lock_basic_lock(&anchors->lock);
- RBTREE_FOR(tp, struct trust_anchor*, anchors->tree) {
- lock_basic_lock(&tp->lock);
- autr_debug_print_tp(tp);
- lock_basic_unlock(&tp->lock);
- }
- lock_basic_unlock(&anchors->lock);
-}
-
-void probe_answer_cb(void* arg, int ATTR_UNUSED(rcode),
- sldns_buffer* ATTR_UNUSED(buf), enum sec_status ATTR_UNUSED(sec),
- char* ATTR_UNUSED(why_bogus))
-{
- /* retry was set before the query was done,
- * re-querytime is set when query succeeded, but that may not
- * have reset this timer because the query could have been
- * handled by another thread. In that case, this callback would
- * get called after the original timeout is done.
- * By not resetting the timer, it may probe more often, but not
- * less often.
- * Unless the new lookup resulted in smaller TTLs and thus smaller
- * timeout values. In that case one old TTL could be mistakenly done.
- */
- struct module_env* env = (struct module_env*)arg;
- verbose(VERB_ALGO, "autotrust probe answer cb");
- reset_worker_timer(env);
-}
-
-/** probe a trust anchor DNSKEY and unlocks tp */
-static void
-probe_anchor(struct module_env* env, struct trust_anchor* tp)
-{
- struct query_info qinfo;
- uint16_t qflags = BIT_RD;
- struct edns_data edns;
- sldns_buffer* buf = env->scratch_buffer;
- qinfo.qname = regional_alloc_init(env->scratch, tp->name, tp->namelen);
- if(!qinfo.qname) {
- log_err("out of memory making 5011 probe");
- return;
- }
- qinfo.qname_len = tp->namelen;
- qinfo.qtype = LDNS_RR_TYPE_DNSKEY;
- qinfo.qclass = tp->dclass;
- qinfo.local_alias = NULL;
- log_query_info(VERB_ALGO, "autotrust probe", &qinfo);
- verbose(VERB_ALGO, "retry probe set in %d seconds",
- (int)tp->autr->next_probe_time - (int)*env->now);
- edns.edns_present = 1;
- edns.ext_rcode = 0;
- edns.edns_version = 0;
- edns.bits = EDNS_DO;
- edns.opt_list = NULL;
- if(sldns_buffer_capacity(buf) < 65535)
- edns.udp_size = (uint16_t)sldns_buffer_capacity(buf);
- else edns.udp_size = 65535;
-
- /* can't hold the lock while mesh_run is processing */
- lock_basic_unlock(&tp->lock);
-
- /* delete the DNSKEY from rrset and key cache so an active probe
- * is done. First the rrset so another thread does not use it
- * to recreate the key entry in a race condition. */
- rrset_cache_remove(env->rrset_cache, qinfo.qname, qinfo.qname_len,
- qinfo.qtype, qinfo.qclass, 0);
- key_cache_remove(env->key_cache, qinfo.qname, qinfo.qname_len,
- qinfo.qclass);
-
- if(!mesh_new_callback(env->mesh, &qinfo, qflags, &edns, buf, 0,
- &probe_answer_cb, env)) {
- log_err("out of memory making 5011 probe");
- }
-}
-
-/** fetch first to-probe trust-anchor and lock it and set retrytime */
-static struct trust_anchor*
-todo_probe(struct module_env* env, time_t* next)
-{
- struct trust_anchor* tp;
- rbnode_type* el;
- /* get first one */
- lock_basic_lock(&env->anchors->lock);
- if( (el=rbtree_first(&env->anchors->autr->probe)) == RBTREE_NULL) {
- /* in case of revoked anchors */
- lock_basic_unlock(&env->anchors->lock);
- /* signal that there are no anchors to probe */
- *next = 0;
- return NULL;
- }
- tp = (struct trust_anchor*)el->key;
- lock_basic_lock(&tp->lock);
-
- /* is it eligible? */
- if((time_t)tp->autr->next_probe_time > *env->now) {
- /* no more to probe */
- *next = (time_t)tp->autr->next_probe_time - *env->now;
- lock_basic_unlock(&tp->lock);
- lock_basic_unlock(&env->anchors->lock);
- return NULL;
- }
-
- /* reset its next probe time */
- (void)rbtree_delete(&env->anchors->autr->probe, tp);
- tp->autr->next_probe_time = calc_next_probe(env, tp->autr->retry_time);
- (void)rbtree_insert(&env->anchors->autr->probe, &tp->autr->pnode);
- lock_basic_unlock(&env->anchors->lock);
-
- return tp;
-}
-
-time_t
-autr_probe_timer(struct module_env* env)
-{
- struct trust_anchor* tp;
- time_t next_probe = 3600;
- int num = 0;
- if(autr_permit_small_holddown) next_probe = 1;
- verbose(VERB_ALGO, "autotrust probe timer callback");
- /* while there are still anchors to probe */
- while( (tp = todo_probe(env, &next_probe)) ) {
- /* make a probe for this anchor */
- probe_anchor(env, tp);
- num++;
- }
- regional_free_all(env->scratch);
- if(next_probe == 0)
- return 0; /* no trust points to probe */
- verbose(VERB_ALGO, "autotrust probe timer %d callbacks done", num);
- return next_probe;
-}
diff --git a/external/unbound/validator/autotrust.h b/external/unbound/validator/autotrust.h
deleted file mode 100644
index dbaf5126a..000000000
--- a/external/unbound/validator/autotrust.h
+++ /dev/null
@@ -1,208 +0,0 @@
-/*
- * validator/autotrust.h - RFC5011 trust anchor management for unbound.
- *
- * Copyright (c) 2009, NLnet Labs. All rights reserved.
- *
- * This software is open source.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- *
- * Redistributions of source code must retain the above copyright notice,
- * this list of conditions and the following disclaimer.
- *
- * Redistributions in binary form must reproduce the above copyright notice,
- * this list of conditions and the following disclaimer in the documentation
- * and/or other materials provided with the distribution.
- *
- * Neither the name of the NLNET LABS nor the names of its contributors may
- * be used to endorse or promote products derived from this software without
- * specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
- * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
- * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
- * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
- * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
- * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-/**
- * \file
- *
- * Contains autotrust definitions.
- */
-
-#ifndef VALIDATOR_AUTOTRUST_H
-#define VALIDATOR_AUTOTRUST_H
-#include "util/rbtree.h"
-#include "util/data/packed_rrset.h"
-struct val_anchors;
-struct trust_anchor;
-struct ub_packed_rrset_key;
-struct module_env;
-struct val_env;
-struct sldns_buffer;
-
-/** Autotrust anchor states */
-typedef enum {
- AUTR_STATE_START = 0,
- AUTR_STATE_ADDPEND = 1,
- AUTR_STATE_VALID = 2,
- AUTR_STATE_MISSING = 3,
- AUTR_STATE_REVOKED = 4,
- AUTR_STATE_REMOVED = 5
-} autr_state_type;
-
-/**
- * Autotrust metadata for one trust anchor key.
- */
-struct autr_ta {
- /** next key */
- struct autr_ta* next;
- /** the RR */
- uint8_t* rr;
- /** length of rr */
- size_t rr_len, dname_len;
- /** last update of key state (new pending count keeps date the same) */
- time_t last_change;
- /** 5011 state */
- autr_state_type s;
- /** pending count */
- uint8_t pending_count;
- /** fresh TA was seen */
- uint8_t fetched;
- /** revoked TA was seen */
- uint8_t revoked;
-};
-
-/**
- * Autotrust metadata for a trust point.
- * This is part of the struct trust_anchor data.
- */
-struct autr_point_data {
- /** file to store the trust point in. chrootdir already applied. */
- char* file;
- /** rbtree node for probe sort, key is struct trust_anchor */
- rbnode_type pnode;
-
- /** the keys */
- struct autr_ta* keys;
-
- /** last queried DNSKEY set
- * Not all failures are captured in this entry.
- * If the validator did not even start (e.g. timeout or localservfail),
- * then the last_queried and query_failed values are not updated.
- */
- time_t last_queried;
- /** last successful DNSKEY set */
- time_t last_success;
- /** next probe time */
- time_t next_probe_time;
-
- /** when to query if !failed */
- time_t query_interval;
- /** when to retry if failed */
- time_t retry_time;
-
- /**
- * How many times did it fail. diagnostic only (has no effect).
- * Only updated if there was a dnskey rrset that failed to verify.
- */
- uint8_t query_failed;
- /** true if the trust point has been revoked */
- uint8_t revoked;
-};
-
-/**
- * Autotrust global metadata.
- */
-struct autr_global_data {
- /** rbtree of autotrust anchors sorted by next probe time.
- * When time is equal, sorted by anchor class, name. */
- rbtree_type probe;
-};
-
-/**
- * Create new global 5011 data structure.
- * @return new structure or NULL on malloc failure.
- */
-struct autr_global_data* autr_global_create(void);
-
-/**
- * Delete global 5011 data structure.
- * @param global: global autotrust state to delete.
- */
-void autr_global_delete(struct autr_global_data* global);
-
-/**
- * See if autotrust anchors are configured and how many.
- * @param anchors: the trust anchors structure.
- * @return number of autotrust trust anchors
- */
-size_t autr_get_num_anchors(struct val_anchors* anchors);
-
-/**
- * Process probe timer. Add new probes if needed.
- * @param env: module environment with time, with anchors and with the mesh.
- * @return time of next probe (in seconds from now).
- * If 0, then there is no next probe anymore (trust points deleted).
- */
-time_t autr_probe_timer(struct module_env* env);
-
-/** probe tree compare function */
-int probetree_cmp(const void* x, const void* y);
-
-/**
- * Read autotrust file.
- * @param anchors: the anchors structure.
- * @param nm: name of the file (copied).
- * @return false on failure.
- */
-int autr_read_file(struct val_anchors* anchors, const char* nm);
-
-/**
- * Write autotrust file.
- * @param env: environment with scratch space.
- * @param tp: trust point to write.
- */
-void autr_write_file(struct module_env* env, struct trust_anchor* tp);
-
-/**
- * Delete autr anchor, deletes the autr data but does not do
- * unlinking from trees, caller does that.
- * @param tp: trust point to delete.
- */
-void autr_point_delete(struct trust_anchor* tp);
-
-/**
- * Perform autotrust processing.
- * @param env: qstate environment with the anchors structure.
- * @param ve: validator environment for verification of rrsigs.
- * @param tp: trust anchor to process.
- * @param dnskey_rrset: DNSKEY rrset probed (can be NULL if bad prime result).
- * allocated in a region. Has not been validated yet.
- * @return false if trust anchor was revoked completely.
- * Otherwise logs errors to log, does not change return value.
- * On errors, likely the trust point has been unchanged.
- */
-int autr_process_prime(struct module_env* env, struct val_env* ve,
- struct trust_anchor* tp, struct ub_packed_rrset_key* dnskey_rrset);
-
-/**
- * Debug printout of rfc5011 tracked anchors
- * @param anchors: all the anchors.
- */
-void autr_debug_print(struct val_anchors* anchors);
-
-/** callback for query answer to 5011 probe */
-void probe_answer_cb(void* arg, int rcode, struct sldns_buffer* buf,
- enum sec_status sec, char* errinf);
-
-#endif /* VALIDATOR_AUTOTRUST_H */
diff --git a/external/unbound/validator/val_anchor.c b/external/unbound/validator/val_anchor.c
deleted file mode 100644
index 6c6322447..000000000
--- a/external/unbound/validator/val_anchor.c
+++ /dev/null
@@ -1,1311 +0,0 @@
-/*
- * validator/val_anchor.c - validator trust anchor storage.
- *
- * Copyright (c) 2007, NLnet Labs. All rights reserved.
- *
- * This software is open source.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- *
- * Redistributions of source code must retain the above copyright notice,
- * this list of conditions and the following disclaimer.
- *
- * Redistributions in binary form must reproduce the above copyright notice,
- * this list of conditions and the following disclaimer in the documentation
- * and/or other materials provided with the distribution.
- *
- * Neither the name of the NLNET LABS nor the names of its contributors may
- * be used to endorse or promote products derived from this software without
- * specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
- * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
- * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
- * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
- * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
- * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-/**
- * \file
- *
- * This file contains storage for the trust anchors for the validator.
- */
-#include "config.h"
-#include <ctype.h>
-#include "validator/val_anchor.h"
-#include "validator/val_sigcrypt.h"
-#include "validator/autotrust.h"
-#include "util/data/packed_rrset.h"
-#include "util/data/dname.h"
-#include "util/log.h"
-#include "util/net_help.h"
-#include "util/config_file.h"
-#include "util/as112.h"
-#include "sldns/sbuffer.h"
-#include "sldns/rrdef.h"
-#include "sldns/str2wire.h"
-#ifdef HAVE_GLOB_H
-#include <glob.h>
-#endif
-
-int
-anchor_cmp(const void* k1, const void* k2)
-{
- int m;
- struct trust_anchor* n1 = (struct trust_anchor*)k1;
- struct trust_anchor* n2 = (struct trust_anchor*)k2;
- /* no need to ntohs(class) because sort order is irrelevant */
- if(n1->dclass != n2->dclass) {
- if(n1->dclass < n2->dclass)
- return -1;
- return 1;
- }
- return dname_lab_cmp(n1->name, n1->namelabs, n2->name, n2->namelabs,
- &m);
-}
-
-struct val_anchors*
-anchors_create(void)
-{
- struct val_anchors* a = (struct val_anchors*)calloc(1, sizeof(*a));
- if(!a)
- return NULL;
- a->tree = rbtree_create(anchor_cmp);
- if(!a->tree) {
- anchors_delete(a);
- return NULL;
- }
- a->autr = autr_global_create();
- if(!a->autr) {
- anchors_delete(a);
- return NULL;
- }
- lock_basic_init(&a->lock);
- lock_protect(&a->lock, a, sizeof(*a));
- lock_protect(&a->lock, a->autr, sizeof(*a->autr));
- return a;
-}
-
-/** delete assembled rrset */
-static void
-assembled_rrset_delete(struct ub_packed_rrset_key* pkey)
-{
- if(!pkey) return;
- if(pkey->entry.data) {
- struct packed_rrset_data* pd = (struct packed_rrset_data*)
- pkey->entry.data;
- free(pd->rr_data);
- free(pd->rr_ttl);
- free(pd->rr_len);
- free(pd);
- }
- free(pkey->rk.dname);
- free(pkey);
-}
-
-/** destroy locks in tree and delete autotrust anchors */
-static void
-anchors_delfunc(rbnode_type* elem, void* ATTR_UNUSED(arg))
-{
- struct trust_anchor* ta = (struct trust_anchor*)elem;
- if(!ta) return;
- if(ta->autr) {
- autr_point_delete(ta);
- } else {
- struct ta_key* p, *np;
- lock_basic_destroy(&ta->lock);
- free(ta->name);
- p = ta->keylist;
- while(p) {
- np = p->next;
- free(p->data);
- free(p);
- p = np;
- }
- assembled_rrset_delete(ta->ds_rrset);
- assembled_rrset_delete(ta->dnskey_rrset);
- free(ta);
- }
-}
-
-void
-anchors_delete(struct val_anchors* anchors)
-{
- if(!anchors)
- return;
- lock_unprotect(&anchors->lock, anchors->autr);
- lock_unprotect(&anchors->lock, anchors);
- lock_basic_destroy(&anchors->lock);
- if(anchors->tree)
- traverse_postorder(anchors->tree, anchors_delfunc, NULL);
- free(anchors->tree);
- autr_global_delete(anchors->autr);
- free(anchors);
-}
-
-void
-anchors_init_parents_locked(struct val_anchors* anchors)
-{
- struct trust_anchor* node, *prev = NULL, *p;
- int m;
- /* nobody else can grab locks because we hold the main lock.
- * Thus the previous items, after unlocked, are not deleted */
- RBTREE_FOR(node, struct trust_anchor*, anchors->tree) {
- lock_basic_lock(&node->lock);
- node->parent = NULL;
- if(!prev || prev->dclass != node->dclass) {
- prev = node;
- lock_basic_unlock(&node->lock);
- continue;
- }
- (void)dname_lab_cmp(prev->name, prev->namelabs, node->name,
- node->namelabs, &m); /* we know prev is smaller */
- /* sort order like: . com. bla.com. zwb.com. net. */
- /* find the previous, or parent-parent-parent */
- for(p = prev; p; p = p->parent)
- /* looking for name with few labels, a parent */
- if(p->namelabs <= m) {
- /* ==: since prev matched m, this is closest*/
- /* <: prev matches more, but is not a parent,
- * this one is a (grand)parent */
- node->parent = p;
- break;
- }
- lock_basic_unlock(&node->lock);
- prev = node;
- }
-}
-
-/** initialise parent pointers in the tree */
-static void
-init_parents(struct val_anchors* anchors)
-{
- lock_basic_lock(&anchors->lock);
- anchors_init_parents_locked(anchors);
- lock_basic_unlock(&anchors->lock);
-}
-
-struct trust_anchor*
-anchor_find(struct val_anchors* anchors, uint8_t* name, int namelabs,
- size_t namelen, uint16_t dclass)
-{
- struct trust_anchor key;
- rbnode_type* n;
- if(!name) return NULL;
- key.node.key = &key;
- key.name = name;
- key.namelabs = namelabs;
- key.namelen = namelen;
- key.dclass = dclass;
- lock_basic_lock(&anchors->lock);
- n = rbtree_search(anchors->tree, &key);
- if(n) {
- lock_basic_lock(&((struct trust_anchor*)n->key)->lock);
- }
- lock_basic_unlock(&anchors->lock);
- if(!n)
- return NULL;
- return (struct trust_anchor*)n->key;
-}
-
-/** create new trust anchor object */
-static struct trust_anchor*
-anchor_new_ta(struct val_anchors* anchors, uint8_t* name, int namelabs,
- size_t namelen, uint16_t dclass, int lockit)
-{
-#ifdef UNBOUND_DEBUG
- rbnode_type* r;
-#endif
- struct trust_anchor* ta = (struct trust_anchor*)malloc(
- sizeof(struct trust_anchor));
- if(!ta)
- return NULL;
- memset(ta, 0, sizeof(*ta));
- ta->node.key = ta;
- ta->name = memdup(name, namelen);
- if(!ta->name) {
- free(ta);
- return NULL;
- }
- ta->namelabs = namelabs;
- ta->namelen = namelen;
- ta->dclass = dclass;
- lock_basic_init(&ta->lock);
- if(lockit) {
- lock_basic_lock(&anchors->lock);
- }
-#ifdef UNBOUND_DEBUG
- r =
-#else
- (void)
-#endif
- rbtree_insert(anchors->tree, &ta->node);
- if(lockit) {
- lock_basic_unlock(&anchors->lock);
- }
- log_assert(r != NULL);
- return ta;
-}
-
-/** find trustanchor key by exact data match */
-static struct ta_key*
-anchor_find_key(struct trust_anchor* ta, uint8_t* rdata, size_t rdata_len,
- uint16_t type)
-{
- struct ta_key* k;
- for(k = ta->keylist; k; k = k->next) {
- if(k->type == type && k->len == rdata_len &&
- memcmp(k->data, rdata, rdata_len) == 0)
- return k;
- }
- return NULL;
-}
-
-/** create new trustanchor key */
-static struct ta_key*
-anchor_new_ta_key(uint8_t* rdata, size_t rdata_len, uint16_t type)
-{
- struct ta_key* k = (struct ta_key*)malloc(sizeof(*k));
- if(!k)
- return NULL;
- memset(k, 0, sizeof(*k));
- k->data = memdup(rdata, rdata_len);
- if(!k->data) {
- free(k);
- return NULL;
- }
- k->len = rdata_len;
- k->type = type;
- return k;
-}
-
-/**
- * This routine adds a new RR to a trust anchor. The trust anchor may not
- * exist yet, and is created if not. The RR can be DS or DNSKEY.
- * This routine will also remove duplicates; storing them only once.
- * @param anchors: anchor storage.
- * @param name: name of trust anchor (wireformat)
- * @param type: type or RR
- * @param dclass: class of RR
- * @param rdata: rdata wireformat, starting with rdlength.
- * If NULL, nothing is stored, but an entry is created.
- * @param rdata_len: length of rdata including rdlength.
- * @return: NULL on error, else the trust anchor.
- */
-static struct trust_anchor*
-anchor_store_new_key(struct val_anchors* anchors, uint8_t* name, uint16_t type,
- uint16_t dclass, uint8_t* rdata, size_t rdata_len)
-{
- struct ta_key* k;
- struct trust_anchor* ta;
- int namelabs;
- size_t namelen;
- namelabs = dname_count_size_labels(name, &namelen);
- if(type != LDNS_RR_TYPE_DS && type != LDNS_RR_TYPE_DNSKEY) {
- log_err("Bad type for trust anchor");
- return 0;
- }
- /* lookup or create trustanchor */
- ta = anchor_find(anchors, name, namelabs, namelen, dclass);
- if(!ta) {
- ta = anchor_new_ta(anchors, name, namelabs, namelen, dclass, 1);
- if(!ta)
- return NULL;
- lock_basic_lock(&ta->lock);
- }
- if(!rdata) {
- lock_basic_unlock(&ta->lock);
- return ta;
- }
- /* look for duplicates */
- if(anchor_find_key(ta, rdata, rdata_len, type)) {
- lock_basic_unlock(&ta->lock);
- return ta;
- }
- k = anchor_new_ta_key(rdata, rdata_len, type);
- if(!k) {
- lock_basic_unlock(&ta->lock);
- return NULL;
- }
- /* add new key */
- if(type == LDNS_RR_TYPE_DS)
- ta->numDS++;
- else ta->numDNSKEY++;
- k->next = ta->keylist;
- ta->keylist = k;
- lock_basic_unlock(&ta->lock);
- return ta;
-}
-
-/**
- * Add new RR. It converts ldns RR to wire format.
- * @param anchors: anchor storage.
- * @param rr: the wirerr.
- * @param rl: length of rr.
- * @param dl: length of dname.
- * @return NULL on error, else the trust anchor.
- */
-static struct trust_anchor*
-anchor_store_new_rr(struct val_anchors* anchors, uint8_t* rr, size_t rl,
- size_t dl)
-{
- struct trust_anchor* ta;
- if(!(ta=anchor_store_new_key(anchors, rr,
- sldns_wirerr_get_type(rr, rl, dl),
- sldns_wirerr_get_class(rr, rl, dl),
- sldns_wirerr_get_rdatawl(rr, rl, dl),
- sldns_wirerr_get_rdatalen(rr, rl, dl)+2))) {
- return NULL;
- }
- log_nametypeclass(VERB_QUERY, "adding trusted key",
- rr, sldns_wirerr_get_type(rr, rl, dl),
- sldns_wirerr_get_class(rr, rl, dl));
- return ta;
-}
-
-/**
- * Insert insecure anchor
- * @param anchors: anchor storage.
- * @param str: the domain name.
- * @return NULL on error, Else last trust anchor point
- */
-static struct trust_anchor*
-anchor_insert_insecure(struct val_anchors* anchors, const char* str)
-{
- struct trust_anchor* ta;
- size_t dname_len = 0;
- uint8_t* nm = sldns_str2wire_dname(str, &dname_len);
- if(!nm) {
- log_err("parse error in domain name '%s'", str);
- return NULL;
- }
- ta = anchor_store_new_key(anchors, nm, LDNS_RR_TYPE_DS,
- LDNS_RR_CLASS_IN, NULL, 0);
- free(nm);
- return ta;
-}
-
-struct trust_anchor*
-anchor_store_str(struct val_anchors* anchors, sldns_buffer* buffer,
- const char* str)
-{
- struct trust_anchor* ta;
- uint8_t* rr = sldns_buffer_begin(buffer);
- size_t len = sldns_buffer_capacity(buffer), dname_len = 0;
- int status = sldns_str2wire_rr_buf(str, rr, &len, &dname_len,
- 0, NULL, 0, NULL, 0);
- if(status != 0) {
- log_err("error parsing trust anchor %s: at %d: %s",
- str, LDNS_WIREPARSE_OFFSET(status),
- sldns_get_errorstr_parse(status));
- return NULL;
- }
- if(!(ta=anchor_store_new_rr(anchors, rr, len, dname_len))) {
- log_err("out of memory");
- return NULL;
- }
- return ta;
-}
-
-/**
- * Read a file with trust anchors
- * @param anchors: anchor storage.
- * @param buffer: parsing buffer.
- * @param fname: string.
- * @param onlyone: only one trust anchor allowed in file.
- * @return NULL on error. Else last trust-anchor point.
- */
-static struct trust_anchor*
-anchor_read_file(struct val_anchors* anchors, sldns_buffer* buffer,
- const char* fname, int onlyone)
-{
- struct trust_anchor* ta = NULL, *tanew;
- struct sldns_file_parse_state pst;
- int status;
- size_t len, dname_len;
- uint8_t* rr = sldns_buffer_begin(buffer);
- int ok = 1;
- FILE* in = fopen(fname, "r");
- if(!in) {
- log_err("error opening file %s: %s", fname, strerror(errno));
- return 0;
- }
- memset(&pst, 0, sizeof(pst));
- pst.default_ttl = 3600;
- pst.lineno = 1;
- while(!feof(in)) {
- len = sldns_buffer_capacity(buffer);
- dname_len = 0;
- status = sldns_fp2wire_rr_buf(in, rr, &len, &dname_len, &pst);
- if(len == 0) /* empty, $TTL, $ORIGIN */
- continue;
- if(status != 0) {
- log_err("parse error in %s:%d:%d : %s", fname,
- pst.lineno, LDNS_WIREPARSE_OFFSET(status),
- sldns_get_errorstr_parse(status));
- ok = 0;
- break;
- }
- if(sldns_wirerr_get_type(rr, len, dname_len) !=
- LDNS_RR_TYPE_DS && sldns_wirerr_get_type(rr, len,
- dname_len) != LDNS_RR_TYPE_DNSKEY) {
- continue;
- }
- if(!(tanew=anchor_store_new_rr(anchors, rr, len, dname_len))) {
- log_err("mem error at %s line %d", fname, pst.lineno);
- ok = 0;
- break;
- }
- if(onlyone && ta && ta != tanew) {
- log_err("error at %s line %d: no multiple anchor "
- "domains allowed (you can have multiple "
- "keys, but they must have the same name).",
- fname, pst.lineno);
- ok = 0;
- break;
- }
- ta = tanew;
- }
- fclose(in);
- if(!ok) return NULL;
- /* empty file is OK when multiple anchors are allowed */
- if(!onlyone && !ta) return (struct trust_anchor*)1;
- return ta;
-}
-
-/** skip file to end of line */
-static void
-skip_to_eol(FILE* in)
-{
- int c;
- while((c = getc(in)) != EOF ) {
- if(c == '\n')
- return;
- }
-}
-
-/** true for special characters in bind configs */
-static int
-is_bind_special(int c)
-{
- switch(c) {
- case '{':
- case '}':
- case '"':
- case ';':
- return 1;
- }
- return 0;
-}
-
-/**
- * Read a keyword skipping bind comments; spaces, specials, restkeywords.
- * The file is split into the following tokens:
- * * special characters, on their own, rdlen=1, { } doublequote ;
- * * whitespace becomes a single ' ' or tab. Newlines become spaces.
- * * other words ('keywords')
- * * comments are skipped if desired
- * / / C++ style comment to end of line
- * # to end of line
- * / * C style comment * /
- * @param in: file to read from.
- * @param buf: buffer, what is read is stored after current buffer position.
- * Space is left in the buffer to write a terminating 0.
- * @param line: line number is increased per line, for error reports.
- * @param comments: if 0, comments are not possible and become text.
- * if 1, comments are skipped entirely.
- * In BIND files, this is when reading quoted strings, for example
- * " base 64 text with / / in there "
- * @return the number of character written to the buffer.
- * 0 on end of file.
- */
-static int
-readkeyword_bindfile(FILE* in, sldns_buffer* buf, int* line, int comments)
-{
- int c;
- int numdone = 0;
- while((c = getc(in)) != EOF ) {
- if(comments && c == '#') { /* # blabla */
- skip_to_eol(in);
- (*line)++;
- continue;
- } else if(comments && c=='/' && numdone>0 && /* /_/ bla*/
- sldns_buffer_read_u8_at(buf,
- sldns_buffer_position(buf)-1) == '/') {
- sldns_buffer_skip(buf, -1);
- numdone--;
- skip_to_eol(in);
- (*line)++;
- continue;
- } else if(comments && c=='*' && numdone>0 && /* /_* bla *_/ */
- sldns_buffer_read_u8_at(buf,
- sldns_buffer_position(buf)-1) == '/') {
- sldns_buffer_skip(buf, -1);
- numdone--;
- /* skip to end of comment */
- while(c != EOF && (c=getc(in)) != EOF ) {
- if(c == '*') {
- if((c=getc(in)) == '/')
- break;
- }
- if(c == '\n')
- (*line)++;
- }
- continue;
- }
- /* not a comment, complete the keyword */
- if(numdone > 0) {
- /* check same type */
- if(isspace((unsigned char)c)) {
- ungetc(c, in);
- return numdone;
- }
- if(is_bind_special(c)) {
- ungetc(c, in);
- return numdone;
- }
- }
- if(c == '\n') {
- c = ' ';
- (*line)++;
- }
- /* space for 1 char + 0 string terminator */
- if(sldns_buffer_remaining(buf) < 2) {
- fatal_exit("trusted-keys, %d, string too long", *line);
- }
- sldns_buffer_write_u8(buf, (uint8_t)c);
- numdone++;
- if(isspace((unsigned char)c)) {
- /* collate whitespace into ' ' */
- while((c = getc(in)) != EOF ) {
- if(c == '\n')
- (*line)++;
- if(!isspace((unsigned char)c)) {
- ungetc(c, in);
- break;
- }
- }
- return numdone;
- }
- if(is_bind_special(c))
- return numdone;
- }
- return numdone;
-}
-
-/** skip through file to { or ; */
-static int
-skip_to_special(FILE* in, sldns_buffer* buf, int* line, int spec)
-{
- int rdlen;
- sldns_buffer_clear(buf);
- while((rdlen=readkeyword_bindfile(in, buf, line, 1))) {
- if(rdlen == 1 && isspace((unsigned char)*sldns_buffer_begin(buf))) {
- sldns_buffer_clear(buf);
- continue;
- }
- if(rdlen != 1 || *sldns_buffer_begin(buf) != (uint8_t)spec) {
- sldns_buffer_write_u8(buf, 0);
- log_err("trusted-keys, line %d, expected %c",
- *line, spec);
- return 0;
- }
- return 1;
- }
- log_err("trusted-keys, line %d, expected %c got EOF", *line, spec);
- return 0;
-}
-
-/**
- * read contents of trusted-keys{ ... ; clauses and insert keys into storage.
- * @param anchors: where to store keys
- * @param buf: buffer to use
- * @param line: line number in file
- * @param in: file to read from.
- * @return 0 on error.
- */
-static int
-process_bind_contents(struct val_anchors* anchors, sldns_buffer* buf,
- int* line, FILE* in)
-{
- /* loop over contents, collate strings before ; */
- /* contents is (numbered): 0 1 2 3 4 5 6 7 8 */
- /* name. 257 3 5 base64 base64 */
- /* quoted value: 0 "111" 0 0 0 0 0 0 0 */
- /* comments value: 1 "000" 1 1 1 "0 0 0 0" 1 */
- int contnum = 0;
- int quoted = 0;
- int comments = 1;
- int rdlen;
- char* str = 0;
- sldns_buffer_clear(buf);
- while((rdlen=readkeyword_bindfile(in, buf, line, comments))) {
- if(rdlen == 1 && sldns_buffer_position(buf) == 1
- && isspace((unsigned char)*sldns_buffer_begin(buf))) {
- /* starting whitespace is removed */
- sldns_buffer_clear(buf);
- continue;
- } else if(rdlen == 1 && sldns_buffer_current(buf)[-1] == '"') {
- /* remove " from the string */
- if(contnum == 0) {
- quoted = 1;
- comments = 0;
- }
- sldns_buffer_skip(buf, -1);
- if(contnum > 0 && quoted) {
- if(sldns_buffer_remaining(buf) < 8+1) {
- log_err("line %d, too long", *line);
- return 0;
- }
- sldns_buffer_write(buf, " DNSKEY ", 8);
- quoted = 0;
- comments = 1;
- } else if(contnum > 0)
- comments = !comments;
- continue;
- } else if(rdlen == 1 && sldns_buffer_current(buf)[-1] == ';') {
-
- if(contnum < 5) {
- sldns_buffer_write_u8(buf, 0);
- log_err("line %d, bad key", *line);
- return 0;
- }
- sldns_buffer_skip(buf, -1);
- sldns_buffer_write_u8(buf, 0);
- str = strdup((char*)sldns_buffer_begin(buf));
- if(!str) {
- log_err("line %d, allocation failure", *line);
- return 0;
- }
- if(!anchor_store_str(anchors, buf, str)) {
- log_err("line %d, bad key", *line);
- free(str);
- return 0;
- }
- free(str);
- sldns_buffer_clear(buf);
- contnum = 0;
- quoted = 0;
- comments = 1;
- continue;
- } else if(rdlen == 1 && sldns_buffer_current(buf)[-1] == '}') {
- if(contnum > 0) {
- sldns_buffer_write_u8(buf, 0);
- log_err("line %d, bad key before }", *line);
- return 0;
- }
- return 1;
- } else if(rdlen == 1 &&
- isspace((unsigned char)sldns_buffer_current(buf)[-1])) {
- /* leave whitespace here */
- } else {
- /* not space or whatnot, so actual content */
- contnum ++;
- if(contnum == 1 && !quoted) {
- if(sldns_buffer_remaining(buf) < 8+1) {
- log_err("line %d, too long", *line);
- return 0;
- }
- sldns_buffer_write(buf, " DNSKEY ", 8);
- }
- }
- }
-
- log_err("line %d, EOF before }", *line);
- return 0;
-}
-
-/**
- * Read a BIND9 like file with trust anchors in named.conf format.
- * @param anchors: anchor storage.
- * @param buffer: parsing buffer.
- * @param fname: string.
- * @return false on error.
- */
-static int
-anchor_read_bind_file(struct val_anchors* anchors, sldns_buffer* buffer,
- const char* fname)
-{
- int line_nr = 1;
- FILE* in = fopen(fname, "r");
- int rdlen = 0;
- if(!in) {
- log_err("error opening file %s: %s", fname, strerror(errno));
- return 0;
- }
- verbose(VERB_QUERY, "reading in bind-compat-mode: '%s'", fname);
- /* scan for trusted-keys keyword, ignore everything else */
- sldns_buffer_clear(buffer);
- while((rdlen=readkeyword_bindfile(in, buffer, &line_nr, 1)) != 0) {
- if(rdlen != 12 || strncmp((char*)sldns_buffer_begin(buffer),
- "trusted-keys", 12) != 0) {
- sldns_buffer_clear(buffer);
- /* ignore everything but trusted-keys */
- continue;
- }
- if(!skip_to_special(in, buffer, &line_nr, '{')) {
- log_err("error in trusted key: \"%s\"", fname);
- fclose(in);
- return 0;
- }
- /* process contents */
- if(!process_bind_contents(anchors, buffer, &line_nr, in)) {
- log_err("error in trusted key: \"%s\"", fname);
- fclose(in);
- return 0;
- }
- if(!skip_to_special(in, buffer, &line_nr, ';')) {
- log_err("error in trusted key: \"%s\"", fname);
- fclose(in);
- return 0;
- }
- sldns_buffer_clear(buffer);
- }
- fclose(in);
- return 1;
-}
-
-/**
- * Read a BIND9 like files with trust anchors in named.conf format.
- * Performs wildcard processing of name.
- * @param anchors: anchor storage.
- * @param buffer: parsing buffer.
- * @param pat: pattern string. (can be wildcarded)
- * @return false on error.
- */
-static int
-anchor_read_bind_file_wild(struct val_anchors* anchors, sldns_buffer* buffer,
- const char* pat)
-{
-#ifdef HAVE_GLOB
- glob_t g;
- size_t i;
- int r, flags;
- if(!strchr(pat, '*') && !strchr(pat, '?') && !strchr(pat, '[') &&
- !strchr(pat, '{') && !strchr(pat, '~')) {
- return anchor_read_bind_file(anchors, buffer, pat);
- }
- verbose(VERB_QUERY, "wildcard found, processing %s", pat);
- flags = 0
-#ifdef GLOB_ERR
- | GLOB_ERR
-#endif
-#ifdef GLOB_NOSORT
- | GLOB_NOSORT
-#endif
-#ifdef GLOB_BRACE
- | GLOB_BRACE
-#endif
-#ifdef GLOB_TILDE
- | GLOB_TILDE
-#endif
- ;
- memset(&g, 0, sizeof(g));
- r = glob(pat, flags, NULL, &g);
- if(r) {
- /* some error */
- if(r == GLOB_NOMATCH) {
- verbose(VERB_QUERY, "trusted-keys-file: "
- "no matches for %s", pat);
- return 1;
- } else if(r == GLOB_NOSPACE) {
- log_err("wildcard trusted-keys-file %s: "
- "pattern out of memory", pat);
- } else if(r == GLOB_ABORTED) {
- log_err("wildcard trusted-keys-file %s: expansion "
- "aborted (%s)", pat, strerror(errno));
- } else {
- log_err("wildcard trusted-keys-file %s: expansion "
- "failed (%s)", pat, strerror(errno));
- }
- /* ignore globs that yield no files */
- return 1;
- }
- /* process files found, if any */
- for(i=0; i<(size_t)g.gl_pathc; i++) {
- if(!anchor_read_bind_file(anchors, buffer, g.gl_pathv[i])) {
- log_err("error reading wildcard "
- "trusted-keys-file: %s", g.gl_pathv[i]);
- globfree(&g);
- return 0;
- }
- }
- globfree(&g);
- return 1;
-#else /* not HAVE_GLOB */
- return anchor_read_bind_file(anchors, buffer, pat);
-#endif /* HAVE_GLOB */
-}
-
-/**
- * Assemble an rrset structure for the type
- * @param ta: trust anchor.
- * @param num: number of items to fetch from list.
- * @param type: fetch only items of this type.
- * @return rrset or NULL on error.
- */
-static struct ub_packed_rrset_key*
-assemble_it(struct trust_anchor* ta, size_t num, uint16_t type)
-{
- struct ub_packed_rrset_key* pkey = (struct ub_packed_rrset_key*)
- malloc(sizeof(*pkey));
- struct packed_rrset_data* pd;
- struct ta_key* tk;
- size_t i;
- if(!pkey)
- return NULL;
- memset(pkey, 0, sizeof(*pkey));
- pkey->rk.dname = memdup(ta->name, ta->namelen);
- if(!pkey->rk.dname) {
- free(pkey);
- return NULL;
- }
-
- pkey->rk.dname_len = ta->namelen;
- pkey->rk.type = htons(type);
- pkey->rk.rrset_class = htons(ta->dclass);
- /* The rrset is build in an uncompressed way. This means it
- * cannot be copied in the normal way. */
- pd = (struct packed_rrset_data*)malloc(sizeof(*pd));
- if(!pd) {
- free(pkey->rk.dname);
- free(pkey);
- return NULL;
- }
- memset(pd, 0, sizeof(*pd));
- pd->count = num;
- pd->trust = rrset_trust_ultimate;
- pd->rr_len = (size_t*)reallocarray(NULL, num, sizeof(size_t));
- if(!pd->rr_len) {
- free(pd);
- free(pkey->rk.dname);
- free(pkey);
- return NULL;
- }
- pd->rr_ttl = (time_t*)reallocarray(NULL, num, sizeof(time_t));
- if(!pd->rr_ttl) {
- free(pd->rr_len);
- free(pd);
- free(pkey->rk.dname);
- free(pkey);
- return NULL;
- }
- pd->rr_data = (uint8_t**)reallocarray(NULL, num, sizeof(uint8_t*));
- if(!pd->rr_data) {
- free(pd->rr_ttl);
- free(pd->rr_len);
- free(pd);
- free(pkey->rk.dname);
- free(pkey);
- return NULL;
- }
- /* fill in rrs */
- i=0;
- for(tk = ta->keylist; tk; tk = tk->next) {
- if(tk->type != type)
- continue;
- pd->rr_len[i] = tk->len;
- /* reuse data ptr to allocation in talist */
- pd->rr_data[i] = tk->data;
- pd->rr_ttl[i] = 0;
- i++;
- }
- pkey->entry.data = (void*)pd;
- return pkey;
-}
-
-/**
- * Assemble structures for the trust DS and DNSKEY rrsets.
- * @param ta: trust anchor
- * @return: false on error.
- */
-static int
-anchors_assemble(struct trust_anchor* ta)
-{
- if(ta->numDS > 0) {
- ta->ds_rrset = assemble_it(ta, ta->numDS, LDNS_RR_TYPE_DS);
- if(!ta->ds_rrset)
- return 0;
- }
- if(ta->numDNSKEY > 0) {
- ta->dnskey_rrset = assemble_it(ta, ta->numDNSKEY,
- LDNS_RR_TYPE_DNSKEY);
- if(!ta->dnskey_rrset)
- return 0;
- }
- return 1;
-}
-
-/**
- * Check DS algos for support, warn if not.
- * @param ta: trust anchor
- * @return number of DS anchors with unsupported algorithms.
- */
-static size_t
-anchors_ds_unsupported(struct trust_anchor* ta)
-{
- size_t i, num = 0;
- for(i=0; i<ta->numDS; i++) {
- if(!ds_digest_algo_is_supported(ta->ds_rrset, i) ||
- !ds_key_algo_is_supported(ta->ds_rrset, i))
- num++;
- }
- return num;
-}
-
-/**
- * Check DNSKEY algos for support, warn if not.
- * @param ta: trust anchor
- * @return number of DNSKEY anchors with unsupported algorithms.
- */
-static size_t
-anchors_dnskey_unsupported(struct trust_anchor* ta)
-{
- size_t i, num = 0;
- for(i=0; i<ta->numDNSKEY; i++) {
- if(!dnskey_algo_is_supported(ta->dnskey_rrset, i))
- num++;
- }
- return num;
-}
-
-/**
- * Assemble the rrsets in the anchors, ready for use by validator.
- * @param anchors: trust anchor storage.
- * @return: false on error.
- */
-static int
-anchors_assemble_rrsets(struct val_anchors* anchors)
-{
- struct trust_anchor* ta;
- struct trust_anchor* next;
- size_t nods, nokey;
- lock_basic_lock(&anchors->lock);
- ta=(struct trust_anchor*)rbtree_first(anchors->tree);
- while((rbnode_type*)ta != RBTREE_NULL) {
- next = (struct trust_anchor*)rbtree_next(&ta->node);
- lock_basic_lock(&ta->lock);
- if(ta->autr || (ta->numDS == 0 && ta->numDNSKEY == 0)) {
- lock_basic_unlock(&ta->lock);
- ta = next; /* skip */
- continue;
- }
- if(!anchors_assemble(ta)) {
- log_err("out of memory");
- lock_basic_unlock(&ta->lock);
- lock_basic_unlock(&anchors->lock);
- return 0;
- }
- 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(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 (check if you need to"
- " upgrade unbound and "
-#ifdef HAVE_LIBRESSL
- "libressl"
-#else
- "openssl"
-#endif
- ")", b);
- (void)rbtree_delete(anchors->tree, &ta->node);
- lock_basic_unlock(&ta->lock);
- if(anchors->dlv_anchor == ta)
- anchors->dlv_anchor = NULL;
- anchors_delfunc(&ta->node, NULL);
- ta = next;
- continue;
- }
- lock_basic_unlock(&ta->lock);
- ta = next;
- }
- lock_basic_unlock(&anchors->lock);
- return 1;
-}
-
-int
-anchors_apply_cfg(struct val_anchors* anchors, struct config_file* cfg)
-{
- struct config_strlist* f;
- const char** zstr;
- char* nm;
- sldns_buffer* parsebuf = sldns_buffer_new(65535);
- if(cfg->insecure_lan_zones) {
- for(zstr = as112_zones; *zstr; zstr++) {
- if(!anchor_insert_insecure(anchors, *zstr)) {
- log_err("error in insecure-lan-zones: %s", *zstr);
- sldns_buffer_free(parsebuf);
- return 0;
- }
- }
- }
- for(f = cfg->domain_insecure; f; f = f->next) {
- if(!f->str || f->str[0] == 0) /* empty "" */
- continue;
- if(!anchor_insert_insecure(anchors, f->str)) {
- log_err("error in domain-insecure: %s", f->str);
- sldns_buffer_free(parsebuf);
- return 0;
- }
- }
- for(f = cfg->trust_anchor_file_list; f; f = f->next) {
- if(!f->str || f->str[0] == 0) /* empty "" */
- continue;
- nm = f->str;
- if(cfg->chrootdir && cfg->chrootdir[0] && strncmp(nm,
- cfg->chrootdir, strlen(cfg->chrootdir)) == 0)
- nm += strlen(cfg->chrootdir);
- if(!anchor_read_file(anchors, parsebuf, nm, 0)) {
- log_err("error reading trust-anchor-file: %s", f->str);
- sldns_buffer_free(parsebuf);
- return 0;
- }
- }
- for(f = cfg->trusted_keys_file_list; f; f = f->next) {
- if(!f->str || f->str[0] == 0) /* empty "" */
- continue;
- nm = f->str;
- if(cfg->chrootdir && cfg->chrootdir[0] && strncmp(nm,
- cfg->chrootdir, strlen(cfg->chrootdir)) == 0)
- nm += strlen(cfg->chrootdir);
- if(!anchor_read_bind_file_wild(anchors, parsebuf, nm)) {
- log_err("error reading trusted-keys-file: %s", f->str);
- sldns_buffer_free(parsebuf);
- return 0;
- }
- }
- for(f = cfg->trust_anchor_list; f; f = f->next) {
- if(!f->str || f->str[0] == 0) /* empty "" */
- continue;
- if(!anchor_store_str(anchors, parsebuf, f->str)) {
- log_err("error in trust-anchor: \"%s\"", f->str);
- sldns_buffer_free(parsebuf);
- return 0;
- }
- }
- if(cfg->dlv_anchor_file && cfg->dlv_anchor_file[0] != 0) {
- struct trust_anchor* dlva;
- nm = cfg->dlv_anchor_file;
- if(cfg->chrootdir && cfg->chrootdir[0] && strncmp(nm,
- cfg->chrootdir, strlen(cfg->chrootdir)) == 0)
- nm += strlen(cfg->chrootdir);
- if(!(dlva = anchor_read_file(anchors, parsebuf,
- nm, 1))) {
- log_err("error reading dlv-anchor-file: %s",
- cfg->dlv_anchor_file);
- sldns_buffer_free(parsebuf);
- return 0;
- }
- lock_basic_lock(&anchors->lock);
- anchors->dlv_anchor = dlva;
- lock_basic_unlock(&anchors->lock);
- }
- for(f = cfg->dlv_anchor_list; f; f = f->next) {
- struct trust_anchor* dlva;
- if(!f->str || f->str[0] == 0) /* empty "" */
- continue;
- if(!(dlva = anchor_store_str(
- anchors, parsebuf, f->str))) {
- log_err("error in dlv-anchor: \"%s\"", f->str);
- sldns_buffer_free(parsebuf);
- return 0;
- }
- lock_basic_lock(&anchors->lock);
- anchors->dlv_anchor = dlva;
- lock_basic_unlock(&anchors->lock);
- }
- /* do autr last, so that it sees what anchors are filled by other
- * means can can print errors about double config for the name */
- for(f = cfg->auto_trust_anchor_file_list; f; f = f->next) {
- if(!f->str || f->str[0] == 0) /* empty "" */
- continue;
- nm = f->str;
- if(cfg->chrootdir && cfg->chrootdir[0] && strncmp(nm,
- cfg->chrootdir, strlen(cfg->chrootdir)) == 0)
- nm += strlen(cfg->chrootdir);
- if(!autr_read_file(anchors, nm)) {
- log_err("error reading auto-trust-anchor-file: %s",
- f->str);
- sldns_buffer_free(parsebuf);
- return 0;
- }
- }
- /* first assemble, since it may delete useless anchors */
- anchors_assemble_rrsets(anchors);
- init_parents(anchors);
- sldns_buffer_free(parsebuf);
- if(verbosity >= VERB_ALGO) autr_debug_print(anchors);
- return 1;
-}
-
-struct trust_anchor*
-anchors_lookup(struct val_anchors* anchors,
- uint8_t* qname, size_t qname_len, uint16_t qclass)
-{
- struct trust_anchor key;
- struct trust_anchor* result;
- rbnode_type* res = NULL;
- key.node.key = &key;
- key.name = qname;
- key.namelabs = dname_count_labels(qname);
- key.namelen = qname_len;
- key.dclass = qclass;
- lock_basic_lock(&anchors->lock);
- if(rbtree_find_less_equal(anchors->tree, &key, &res)) {
- /* exact */
- result = (struct trust_anchor*)res;
- } else {
- /* smaller element (or no element) */
- int m;
- result = (struct trust_anchor*)res;
- if(!result || result->dclass != qclass) {
- lock_basic_unlock(&anchors->lock);
- return NULL;
- }
- /* count number of labels matched */
- (void)dname_lab_cmp(result->name, result->namelabs, key.name,
- key.namelabs, &m);
- while(result) { /* go up until qname is subdomain of stub */
- if(result->namelabs <= m)
- break;
- result = result->parent;
- }
- }
- if(result) {
- lock_basic_lock(&result->lock);
- }
- lock_basic_unlock(&anchors->lock);
- return result;
-}
-
-size_t
-anchors_get_mem(struct val_anchors* anchors)
-{
- struct trust_anchor *ta;
- size_t s = sizeof(*anchors);
- if(!anchors)
- return 0;
- RBTREE_FOR(ta, struct trust_anchor*, anchors->tree) {
- s += sizeof(*ta) + ta->namelen;
- /* keys and so on */
- }
- return s;
-}
-
-int
-anchors_add_insecure(struct val_anchors* anchors, uint16_t c, uint8_t* nm)
-{
- struct trust_anchor key;
- key.node.key = &key;
- key.name = nm;
- key.namelabs = dname_count_size_labels(nm, &key.namelen);
- key.dclass = c;
- lock_basic_lock(&anchors->lock);
- if(rbtree_search(anchors->tree, &key)) {
- lock_basic_unlock(&anchors->lock);
- /* nothing to do, already an anchor or insecure point */
- return 1;
- }
- if(!anchor_new_ta(anchors, nm, key.namelabs, key.namelen, c, 0)) {
- log_err("out of memory");
- lock_basic_unlock(&anchors->lock);
- return 0;
- }
- /* no other contents in new ta, because it is insecure point */
- anchors_init_parents_locked(anchors);
- lock_basic_unlock(&anchors->lock);
- return 1;
-}
-
-void
-anchors_delete_insecure(struct val_anchors* anchors, uint16_t c,
- uint8_t* nm)
-{
- struct trust_anchor key;
- struct trust_anchor* ta;
- key.node.key = &key;
- key.name = nm;
- key.namelabs = dname_count_size_labels(nm, &key.namelen);
- key.dclass = c;
- lock_basic_lock(&anchors->lock);
- if(!(ta=(struct trust_anchor*)rbtree_search(anchors->tree, &key))) {
- lock_basic_unlock(&anchors->lock);
- /* nothing there */
- return;
- }
- /* lock it to drive away other threads that use it */
- lock_basic_lock(&ta->lock);
- /* see if its really an insecure point */
- if(ta->keylist || ta->autr || ta->numDS || ta->numDNSKEY) {
- lock_basic_unlock(&anchors->lock);
- lock_basic_unlock(&ta->lock);
- /* its not an insecure point, do not remove it */
- return;
- }
-
- /* remove from tree */
- (void)rbtree_delete(anchors->tree, &ta->node);
- anchors_init_parents_locked(anchors);
- lock_basic_unlock(&anchors->lock);
-
- /* actual free of data */
- lock_basic_unlock(&ta->lock);
- anchors_delfunc(&ta->node, NULL);
-}
-
-/** compare two keytags, return -1, 0 or 1 */
-static int
-keytag_compare(const void* x, const void* y)
-{
- if(*(uint16_t*)x == *(uint16_t*)y)
- return 0;
- if(*(uint16_t*)x > *(uint16_t*)y)
- return 1;
- return -1;
-}
-
-size_t
-anchor_list_keytags(struct trust_anchor* ta, uint16_t* list, size_t num)
-{
- size_t i, ret = 0;
- if(ta->numDS == 0 && ta->numDNSKEY == 0)
- return 0; /* insecure point */
- if(ta->numDS != 0 && ta->ds_rrset) {
- struct packed_rrset_data* d=(struct packed_rrset_data*)
- ta->ds_rrset->entry.data;
- for(i=0; i<d->count; i++) {
- if(ret == num) continue;
- list[ret++] = ds_get_keytag(ta->ds_rrset, i);
- }
- }
- if(ta->numDNSKEY != 0 && ta->dnskey_rrset) {
- struct packed_rrset_data* d=(struct packed_rrset_data*)
- ta->dnskey_rrset->entry.data;
- for(i=0; i<d->count; i++) {
- if(ret == num) continue;
- list[ret++] = dnskey_calc_keytag(ta->dnskey_rrset, i);
- }
- }
- qsort(list, ret, sizeof(*list), keytag_compare);
- return ret;
-}
diff --git a/external/unbound/validator/val_anchor.h b/external/unbound/validator/val_anchor.h
deleted file mode 100644
index 318a2b227..000000000
--- a/external/unbound/validator/val_anchor.h
+++ /dev/null
@@ -1,230 +0,0 @@
-/*
- * validator/val_anchor.h - validator trust anchor storage.
- *
- * Copyright (c) 2007, NLnet Labs. All rights reserved.
- *
- * This software is open source.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- *
- * Redistributions of source code must retain the above copyright notice,
- * this list of conditions and the following disclaimer.
- *
- * Redistributions in binary form must reproduce the above copyright notice,
- * this list of conditions and the following disclaimer in the documentation
- * and/or other materials provided with the distribution.
- *
- * Neither the name of the NLNET LABS nor the names of its contributors may
- * be used to endorse or promote products derived from this software without
- * specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
- * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
- * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
- * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
- * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
- * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-/**
- * \file
- *
- * This file contains storage for the trust anchors for the validator.
- */
-
-#ifndef VALIDATOR_VAL_ANCHOR_H
-#define VALIDATOR_VAL_ANCHOR_H
-#include "util/rbtree.h"
-#include "util/locks.h"
-struct trust_anchor;
-struct config_file;
-struct ub_packed_rrset_key;
-struct autr_point_data;
-struct autr_global_data;
-struct sldns_buffer;
-
-/**
- * Trust anchor store.
- * The tree must be locked, while no other locks (from trustanchors) are held.
- * And then an anchor searched for. Which can be locked or deleted. Then
- * the tree can be unlocked again. This means you have to release the lock
- * on a trust anchor and look it up again to delete it.
- */
-struct val_anchors {
- /** lock on trees */
- lock_basic_type lock;
- /**
- * Anchors are store in this tree. Sort order is chosen, so that
- * dnames are in nsec-like order. A lookup on class, name will return
- * an exact match of the closest match, with the ancestor needed.
- * contents of type trust_anchor.
- */
- rbtree_type* tree;
- /** The DLV trust anchor (if one is configured, else NULL) */
- struct trust_anchor* dlv_anchor;
- /** Autotrust global data, anchors sorted by next probe time */
- struct autr_global_data* autr;
-};
-
-/**
- * Trust anchor key
- */
-struct ta_key {
- /** next in list */
- struct ta_key* next;
- /** rdata, in wireformat of the key RR. starts with rdlength. */
- uint8_t* data;
- /** length of the rdata (including rdlength). */
- size_t len;
- /** DNS type (host format) of the key, DS or DNSKEY */
- uint16_t type;
-};
-
-/**
- * A trust anchor in the trust anchor store.
- * Unique by name, class.
- */
-struct trust_anchor {
- /** rbtree node, key is this structure */
- rbnode_type node;
- /** lock on the entire anchor and its keys; for autotrust changes */
- lock_basic_type lock;
- /** name of this trust anchor */
- uint8_t* name;
- /** length of name */
- size_t namelen;
- /** number of labels in name of rrset */
- int namelabs;
- /** the ancestor in the trustanchor tree */
- struct trust_anchor* parent;
- /**
- * List of DS or DNSKEY rrs that form the trust anchor.
- */
- struct ta_key* keylist;
- /** Autotrust anchor point data, or NULL */
- struct autr_point_data* autr;
- /** number of DSs in the keylist */
- size_t numDS;
- /** number of DNSKEYs in the keylist */
- size_t numDNSKEY;
- /** the DS RRset */
- struct ub_packed_rrset_key* ds_rrset;
- /** The DNSKEY RRset */
- struct ub_packed_rrset_key* dnskey_rrset;
- /** class of the trust anchor */
- uint16_t dclass;
-};
-
-/**
- * Create trust anchor storage
- * @return new storage or NULL on error.
- */
-struct val_anchors* anchors_create(void);
-
-/**
- * Delete trust anchor storage.
- * @param anchors: to delete.
- */
-void anchors_delete(struct val_anchors* anchors);
-
-/**
- * Process trust anchor config.
- * @param anchors: struct anchor storage
- * @param cfg: config options.
- * @return 0 on error.
- */
-int anchors_apply_cfg(struct val_anchors* anchors, struct config_file* cfg);
-
-/**
- * Recalculate parent pointers. The caller must hold the lock on the
- * anchors structure (say after removing an item from the rbtree).
- * Caller must not hold any locks on trust anchors.
- * After the call is complete the parent pointers are updated and an item
- * just removed is no longer referenced in parent pointers.
- * @param anchors: the structure to update.
- */
-void anchors_init_parents_locked(struct val_anchors* anchors);
-
-/**
- * Given a qname/qclass combination, find the trust anchor closest above it.
- * Or return NULL if none exists.
- *
- * @param anchors: struct anchor storage
- * @param qname: query name, uncompressed wireformat.
- * @param qname_len: length of qname.
- * @param qclass: class to query for.
- * @return the trust anchor or NULL if none is found. The anchor is locked.
- */
-struct trust_anchor* anchors_lookup(struct val_anchors* anchors,
- uint8_t* qname, size_t qname_len, uint16_t qclass);
-
-/**
- * Find a trust anchor. Exact matching.
- * @param anchors: anchor storage.
- * @param name: name of trust anchor (wireformat)
- * @param namelabs: labels in name
- * @param namelen: length of name
- * @param dclass: class of trust anchor
- * @return NULL if not found. The anchor is locked.
- */
-struct trust_anchor* anchor_find(struct val_anchors* anchors,
- uint8_t* name, int namelabs, size_t namelen, uint16_t dclass);
-
-/**
- * Store one string as trust anchor RR.
- * @param anchors: anchor storage.
- * @param buffer: parsing buffer, to generate the RR wireformat in.
- * @param str: string.
- * @return NULL on error.
- */
-struct trust_anchor* anchor_store_str(struct val_anchors* anchors,
- struct sldns_buffer* buffer, const char* str);
-
-/**
- * Get memory in use by the trust anchor storage
- * @param anchors: anchor storage.
- * @return memory in use in bytes.
- */
-size_t anchors_get_mem(struct val_anchors* anchors);
-
-/** compare two trust anchors */
-int anchor_cmp(const void* k1, const void* k2);
-
-/**
- * Add insecure point trust anchor. For external use (locks and init_parents)
- * @param anchors: anchor storage.
- * @param c: class.
- * @param nm: name of insecure trust point.
- * @return false on alloc failure.
- */
-int anchors_add_insecure(struct val_anchors* anchors, uint16_t c, uint8_t* nm);
-
-/**
- * Delete insecure point trust anchor. Does not remove if no such point.
- * For external use (locks and init_parents)
- * @param anchors: anchor storage.
- * @param c: class.
- * @param nm: name of insecure trust point.
- */
-void anchors_delete_insecure(struct val_anchors* anchors, uint16_t c,
- uint8_t* nm);
-
-/**
- * Get a list of keytags for the trust anchor. Zero tags for insecure points.
- * @param ta: trust anchor (locked by caller).
- * @param list: array of uint16_t.
- * @param num: length of array.
- * @return number of keytags filled into array. If total number of keytags is
- * bigger than the array, it is truncated at num. On errors, less keytags
- * are filled in. The array is sorted.
- */
-size_t anchor_list_keytags(struct trust_anchor* ta, uint16_t* list, size_t num);
-
-#endif /* VALIDATOR_VAL_ANCHOR_H */
diff --git a/external/unbound/validator/val_kcache.c b/external/unbound/validator/val_kcache.c
deleted file mode 100644
index 22070cc6a..000000000
--- a/external/unbound/validator/val_kcache.c
+++ /dev/null
@@ -1,172 +0,0 @@
-/*
- * validator/val_kcache.c - validator key shared cache with validated keys
- *
- * Copyright (c) 2007, NLnet Labs. All rights reserved.
- *
- * This software is open source.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- *
- * Redistributions of source code must retain the above copyright notice,
- * this list of conditions and the following disclaimer.
- *
- * Redistributions in binary form must reproduce the above copyright notice,
- * this list of conditions and the following disclaimer in the documentation
- * and/or other materials provided with the distribution.
- *
- * Neither the name of the NLNET LABS nor the names of its contributors may
- * be used to endorse or promote products derived from this software without
- * specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
- * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
- * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
- * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
- * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
- * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-/**
- * \file
- *
- * This file contains functions for dealing with the validator key cache.
- */
-#include "config.h"
-#include "validator/val_kcache.h"
-#include "validator/val_kentry.h"
-#include "util/log.h"
-#include "util/config_file.h"
-#include "util/data/dname.h"
-#include "util/module.h"
-
-struct key_cache*
-key_cache_create(struct config_file* cfg)
-{
- struct key_cache* kcache = (struct key_cache*)calloc(1,
- sizeof(*kcache));
- size_t numtables, start_size, maxmem;
- if(!kcache) {
- log_err("malloc failure");
- return NULL;
- }
- numtables = cfg->key_cache_slabs;
- start_size = HASH_DEFAULT_STARTARRAY;
- maxmem = cfg->key_cache_size;
- kcache->slab = slabhash_create(numtables, start_size, maxmem,
- &key_entry_sizefunc, &key_entry_compfunc,
- &key_entry_delkeyfunc, &key_entry_deldatafunc, NULL);
- if(!kcache->slab) {
- log_err("malloc failure");
- free(kcache);
- return NULL;
- }
- return kcache;
-}
-
-void
-key_cache_delete(struct key_cache* kcache)
-{
- if(!kcache)
- return;
- slabhash_delete(kcache->slab);
- free(kcache);
-}
-
-void
-key_cache_insert(struct key_cache* kcache, struct key_entry_key* kkey,
- struct module_qstate* qstate)
-{
- struct key_entry_key* k = key_entry_copy(kkey);
- if(!k)
- return;
- if(key_entry_isbad(k) && qstate->errinf &&
- qstate->env->cfg->val_log_level >= 2) {
- /* on malloc failure there is simply no reason string */
- key_entry_set_reason(k, errinf_to_str(qstate));
- }
- key_entry_hash(k);
- slabhash_insert(kcache->slab, k->entry.hash, &k->entry,
- k->entry.data, NULL);
-}
-
-/**
- * Lookup exactly in the key cache. Returns pointer to locked entry.
- * Caller must unlock it after use.
- * @param kcache: the key cache.
- * @param name: for what name to look; uncompressed wireformat
- * @param namelen: length of the name.
- * @param key_class: class of the key.
- * @param wr: set true to get a writelock.
- * @return key entry, locked, or NULL if not found. No TTL checking is
- * performed.
- */
-static struct key_entry_key*
-key_cache_search(struct key_cache* kcache, uint8_t* name, size_t namelen,
- uint16_t key_class, int wr)
-{
- struct lruhash_entry* e;
- struct key_entry_key lookfor;
- lookfor.entry.key = &lookfor;
- lookfor.name = name;
- lookfor.namelen = namelen;
- lookfor.key_class = key_class;
- key_entry_hash(&lookfor);
- e = slabhash_lookup(kcache->slab, lookfor.entry.hash, &lookfor, wr);
- if(!e)
- return NULL;
- return (struct key_entry_key*)e->key;
-}
-
-struct key_entry_key*
-key_cache_obtain(struct key_cache* kcache, uint8_t* name, size_t namelen,
- uint16_t key_class, struct regional* region, time_t now)
-{
- /* keep looking until we find a nonexpired entry */
- while(1) {
- struct key_entry_key* k = key_cache_search(kcache, name,
- namelen, key_class, 0);
- if(k) {
- /* see if TTL is OK */
- struct key_entry_data* d = (struct key_entry_data*)
- k->entry.data;
- if(now <= d->ttl) {
- /* copy and return it */
- struct key_entry_key* retkey =
- key_entry_copy_toregion(k, region);
- lock_rw_unlock(&k->entry.lock);
- return retkey;
- }
- lock_rw_unlock(&k->entry.lock);
- }
- /* snip off first label to continue */
- if(dname_is_root(name))
- break;
- dname_remove_label(&name, &namelen);
- }
- return NULL;
-}
-
-size_t
-key_cache_get_mem(struct key_cache* kcache)
-{
- return sizeof(*kcache) + slabhash_get_mem(kcache->slab);
-}
-
-void key_cache_remove(struct key_cache* kcache,
- uint8_t* name, size_t namelen, uint16_t key_class)
-{
- struct key_entry_key lookfor;
- lookfor.entry.key = &lookfor;
- lookfor.name = name;
- lookfor.namelen = namelen;
- lookfor.key_class = key_class;
- key_entry_hash(&lookfor);
- slabhash_remove(kcache->slab, lookfor.entry.hash, &lookfor);
-}
diff --git a/external/unbound/validator/val_kcache.h b/external/unbound/validator/val_kcache.h
deleted file mode 100644
index 76c9dd094..000000000
--- a/external/unbound/validator/val_kcache.h
+++ /dev/null
@@ -1,118 +0,0 @@
-/*
- * validator/val_kcache.h - validator key shared cache with validated keys
- *
- * Copyright (c) 2007, NLnet Labs. All rights reserved.
- *
- * This software is open source.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- *
- * Redistributions of source code must retain the above copyright notice,
- * this list of conditions and the following disclaimer.
- *
- * Redistributions in binary form must reproduce the above copyright notice,
- * this list of conditions and the following disclaimer in the documentation
- * and/or other materials provided with the distribution.
- *
- * Neither the name of the NLNET LABS nor the names of its contributors may
- * be used to endorse or promote products derived from this software without
- * specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
- * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
- * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
- * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
- * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
- * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-/**
- * \file
- *
- * This file contains functions for caching validated key entries.
- */
-
-#ifndef VALIDATOR_VAL_KCACHE_H
-#define VALIDATOR_VAL_KCACHE_H
-#include "util/storage/slabhash.h"
-struct key_entry_key;
-struct key_entry_data;
-struct config_file;
-struct regional;
-struct module_qstate;
-
-/**
- * Key cache
- */
-struct key_cache {
- /** uses slabhash for storage, type key_entry_key, key_entry_data */
- struct slabhash* slab;
-};
-
-/**
- * Create the key cache
- * @param cfg: config settings for the key cache.
- * @return new key cache or NULL on malloc failure.
- */
-struct key_cache* key_cache_create(struct config_file* cfg);
-
-/**
- * Delete the key cache
- * @param kcache: to delete
- */
-void key_cache_delete(struct key_cache* kcache);
-
-/**
- * Insert or update a key cache entry. Note that the insert may silently
- * fail if there is not enough memory.
- *
- * @param kcache: the key cache.
- * @param kkey: key entry key, assumed malloced in a region, is copied
- * to perform update or insertion. Its data pointer is also copied.
- * @param qstate: store errinf reason in case its bad.
- */
-void key_cache_insert(struct key_cache* kcache, struct key_entry_key* kkey,
- struct module_qstate* qstate);
-
-/**
- * Remove an entry from the key cache.
- * @param kcache: the key cache.
- * @param name: for what name to look; uncompressed wireformat
- * @param namelen: length of the name.
- * @param key_class: class of the key.
- */
-void key_cache_remove(struct key_cache* kcache,
- uint8_t* name, size_t namelen, uint16_t key_class);
-
-/**
- * Lookup key entry in the cache. Looks up the closest key entry above the
- * given name.
- * @param kcache: the key cache.
- * @param name: for what name to look; uncompressed wireformat
- * @param namelen: length of the name.
- * @param key_class: class of the key.
- * @param region: a copy of the key_entry is allocated in this region.
- * @param now: current time.
- * @return pointer to a newly allocated key_entry copy in the region, if
- * a key entry could be found, and allocation succeeded and TTL was OK.
- * Otherwise, NULL is returned.
- */
-struct key_entry_key* key_cache_obtain(struct key_cache* kcache,
- uint8_t* name, size_t namelen, uint16_t key_class,
- struct regional* region, time_t now);
-
-/**
- * Get memory in use by the key cache.
- * @param kcache: the key cache.
- * @return memory in use in bytes.
- */
-size_t key_cache_get_mem(struct key_cache* kcache);
-
-#endif /* VALIDATOR_VAL_KCACHE_H */
diff --git a/external/unbound/validator/val_kentry.c b/external/unbound/validator/val_kentry.c
deleted file mode 100644
index 93fe2145e..000000000
--- a/external/unbound/validator/val_kentry.c
+++ /dev/null
@@ -1,413 +0,0 @@
-/*
- * validator/val_kentry.c - validator key entry definition.
- *
- * Copyright (c) 2007, NLnet Labs. All rights reserved.
- *
- * This software is open source.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- *
- * Redistributions of source code must retain the above copyright notice,
- * this list of conditions and the following disclaimer.
- *
- * Redistributions in binary form must reproduce the above copyright notice,
- * this list of conditions and the following disclaimer in the documentation
- * and/or other materials provided with the distribution.
- *
- * Neither the name of the NLNET LABS nor the names of its contributors may
- * be used to endorse or promote products derived from this software without
- * specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
- * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
- * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
- * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
- * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
- * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-/**
- * \file
- *
- * This file contains functions for dealing with validator key entries.
- */
-#include "config.h"
-#include "validator/val_kentry.h"
-#include "util/data/packed_rrset.h"
-#include "util/data/dname.h"
-#include "util/storage/lookup3.h"
-#include "util/regional.h"
-#include "util/net_help.h"
-#include "sldns/rrdef.h"
-#include "sldns/keyraw.h"
-
-size_t
-key_entry_sizefunc(void* key, void* data)
-{
- struct key_entry_key* kk = (struct key_entry_key*)key;
- struct key_entry_data* kd = (struct key_entry_data*)data;
- size_t s = sizeof(*kk) + kk->namelen;
- s += sizeof(*kd) + lock_get_mem(&kk->entry.lock);
- if(kd->rrset_data)
- s += packed_rrset_sizeof(kd->rrset_data);
- if(kd->reason)
- s += strlen(kd->reason)+1;
- if(kd->algo)
- s += strlen((char*)kd->algo)+1;
- return s;
-}
-
-int
-key_entry_compfunc(void* k1, void* k2)
-{
- struct key_entry_key* n1 = (struct key_entry_key*)k1;
- struct key_entry_key* n2 = (struct key_entry_key*)k2;
- if(n1->key_class != n2->key_class) {
- if(n1->key_class < n2->key_class)
- return -1;
- return 1;
- }
- return query_dname_compare(n1->name, n2->name);
-}
-
-void
-key_entry_delkeyfunc(void* key, void* ATTR_UNUSED(userarg))
-{
- struct key_entry_key* kk = (struct key_entry_key*)key;
- if(!key)
- return;
- lock_rw_destroy(&kk->entry.lock);
- free(kk->name);
- free(kk);
-}
-
-void
-key_entry_deldatafunc(void* data, void* ATTR_UNUSED(userarg))
-{
- struct key_entry_data* kd = (struct key_entry_data*)data;
- free(kd->reason);
- free(kd->rrset_data);
- free(kd->algo);
- free(kd);
-}
-
-void
-key_entry_hash(struct key_entry_key* kk)
-{
- kk->entry.hash = 0x654;
- kk->entry.hash = hashlittle(&kk->key_class, sizeof(kk->key_class),
- kk->entry.hash);
- kk->entry.hash = dname_query_hash(kk->name, kk->entry.hash);
-}
-
-struct key_entry_key*
-key_entry_copy_toregion(struct key_entry_key* kkey, struct regional* region)
-{
- struct key_entry_key* newk;
- newk = regional_alloc_init(region, kkey, sizeof(*kkey));
- if(!newk)
- return NULL;
- newk->name = regional_alloc_init(region, kkey->name, kkey->namelen);
- if(!newk->name)
- return NULL;
- newk->entry.key = newk;
- if(newk->entry.data) {
- /* copy data element */
- struct key_entry_data *d = (struct key_entry_data*)
- kkey->entry.data;
- struct key_entry_data *newd;
- newd = regional_alloc_init(region, d, sizeof(*d));
- if(!newd)
- return NULL;
- /* copy rrset */
- if(d->rrset_data) {
- newd->rrset_data = regional_alloc_init(region,
- d->rrset_data,
- packed_rrset_sizeof(d->rrset_data));
- if(!newd->rrset_data)
- return NULL;
- packed_rrset_ptr_fixup(newd->rrset_data);
- }
- if(d->reason) {
- newd->reason = regional_strdup(region, d->reason);
- if(!newd->reason)
- return NULL;
- }
- if(d->algo) {
- newd->algo = (uint8_t*)regional_strdup(region,
- (char*)d->algo);
- if(!newd->algo)
- return NULL;
- }
- newk->entry.data = newd;
- }
- return newk;
-}
-
-struct key_entry_key*
-key_entry_copy(struct key_entry_key* kkey)
-{
- struct key_entry_key* newk;
- if(!kkey)
- return NULL;
- newk = memdup(kkey, sizeof(*kkey));
- if(!newk)
- return NULL;
- newk->name = memdup(kkey->name, kkey->namelen);
- if(!newk->name) {
- free(newk);
- return NULL;
- }
- lock_rw_init(&newk->entry.lock);
- newk->entry.key = newk;
- if(newk->entry.data) {
- /* copy data element */
- struct key_entry_data *d = (struct key_entry_data*)
- kkey->entry.data;
- struct key_entry_data *newd;
- newd = memdup(d, sizeof(*d));
- if(!newd) {
- free(newk->name);
- free(newk);
- return NULL;
- }
- /* copy rrset */
- if(d->rrset_data) {
- newd->rrset_data = memdup(d->rrset_data,
- packed_rrset_sizeof(d->rrset_data));
- if(!newd->rrset_data) {
- free(newd);
- free(newk->name);
- free(newk);
- return NULL;
- }
- packed_rrset_ptr_fixup(newd->rrset_data);
- }
- if(d->reason) {
- newd->reason = strdup(d->reason);
- if(!newd->reason) {
- free(newd->rrset_data);
- free(newd);
- free(newk->name);
- free(newk);
- return NULL;
- }
- }
- if(d->algo) {
- newd->algo = (uint8_t*)strdup((char*)d->algo);
- if(!newd->algo) {
- free(newd->rrset_data);
- free(newd->reason);
- free(newd);
- free(newk->name);
- free(newk);
- return NULL;
- }
- }
- newk->entry.data = newd;
- }
- return newk;
-}
-
-int
-key_entry_isnull(struct key_entry_key* kkey)
-{
- struct key_entry_data* d = (struct key_entry_data*)kkey->entry.data;
- return (!d->isbad && d->rrset_data == NULL);
-}
-
-int
-key_entry_isgood(struct key_entry_key* kkey)
-{
- struct key_entry_data* d = (struct key_entry_data*)kkey->entry.data;
- return (!d->isbad && d->rrset_data != NULL);
-}
-
-int
-key_entry_isbad(struct key_entry_key* kkey)
-{
- struct key_entry_data* d = (struct key_entry_data*)kkey->entry.data;
- return (int)(d->isbad);
-}
-
-void
-key_entry_set_reason(struct key_entry_key* kkey, char* reason)
-{
- struct key_entry_data* d = (struct key_entry_data*)kkey->entry.data;
- d->reason = reason;
-}
-
-char*
-key_entry_get_reason(struct key_entry_key* kkey)
-{
- struct key_entry_data* d = (struct key_entry_data*)kkey->entry.data;
- return d->reason;
-}
-
-/** setup key entry in region */
-static int
-key_entry_setup(struct regional* region,
- uint8_t* name, size_t namelen, uint16_t dclass,
- struct key_entry_key** k, struct key_entry_data** d)
-{
- *k = regional_alloc(region, sizeof(**k));
- if(!*k)
- return 0;
- memset(*k, 0, sizeof(**k));
- (*k)->entry.key = *k;
- (*k)->name = regional_alloc_init(region, name, namelen);
- if(!(*k)->name)
- return 0;
- (*k)->namelen = namelen;
- (*k)->key_class = dclass;
- *d = regional_alloc(region, sizeof(**d));
- if(!*d)
- return 0;
- (*k)->entry.data = *d;
- return 1;
-}
-
-struct key_entry_key*
-key_entry_create_null(struct regional* region,
- uint8_t* name, size_t namelen, uint16_t dclass, time_t ttl,
- time_t now)
-{
- struct key_entry_key* k;
- struct key_entry_data* d;
- if(!key_entry_setup(region, name, namelen, dclass, &k, &d))
- return NULL;
- d->ttl = now + ttl;
- d->isbad = 0;
- d->reason = NULL;
- d->rrset_type = LDNS_RR_TYPE_DNSKEY;
- d->rrset_data = NULL;
- d->algo = NULL;
- return k;
-}
-
-struct key_entry_key*
-key_entry_create_rrset(struct regional* region,
- uint8_t* name, size_t namelen, uint16_t dclass,
- struct ub_packed_rrset_key* rrset, uint8_t* sigalg, time_t now)
-{
- struct key_entry_key* k;
- struct key_entry_data* d;
- struct packed_rrset_data* rd = (struct packed_rrset_data*)
- rrset->entry.data;
- if(!key_entry_setup(region, name, namelen, dclass, &k, &d))
- return NULL;
- d->ttl = rd->ttl + now;
- d->isbad = 0;
- d->reason = NULL;
- d->rrset_type = ntohs(rrset->rk.type);
- d->rrset_data = (struct packed_rrset_data*)regional_alloc_init(region,
- rd, packed_rrset_sizeof(rd));
- if(!d->rrset_data)
- return NULL;
- if(sigalg) {
- d->algo = (uint8_t*)regional_strdup(region, (char*)sigalg);
- if(!d->algo)
- return NULL;
- } else d->algo = NULL;
- packed_rrset_ptr_fixup(d->rrset_data);
- return k;
-}
-
-struct key_entry_key*
-key_entry_create_bad(struct regional* region,
- uint8_t* name, size_t namelen, uint16_t dclass, time_t ttl,
- time_t now)
-{
- struct key_entry_key* k;
- struct key_entry_data* d;
- if(!key_entry_setup(region, name, namelen, dclass, &k, &d))
- return NULL;
- d->ttl = now + ttl;
- d->isbad = 1;
- d->reason = NULL;
- d->rrset_type = LDNS_RR_TYPE_DNSKEY;
- d->rrset_data = NULL;
- d->algo = NULL;
- return k;
-}
-
-struct ub_packed_rrset_key*
-key_entry_get_rrset(struct key_entry_key* kkey, struct regional* region)
-{
- struct key_entry_data* d = (struct key_entry_data*)kkey->entry.data;
- struct ub_packed_rrset_key* rrk;
- struct packed_rrset_data* rrd;
- if(!d || !d->rrset_data)
- return NULL;
- rrk = regional_alloc(region, sizeof(*rrk));
- if(!rrk)
- return NULL;
- memset(rrk, 0, sizeof(*rrk));
- rrk->rk.dname = regional_alloc_init(region, kkey->name, kkey->namelen);
- if(!rrk->rk.dname)
- return NULL;
- rrk->rk.dname_len = kkey->namelen;
- rrk->rk.type = htons(d->rrset_type);
- rrk->rk.rrset_class = htons(kkey->key_class);
- rrk->entry.key = rrk;
- rrd = regional_alloc_init(region, d->rrset_data,
- packed_rrset_sizeof(d->rrset_data));
- if(!rrd)
- return NULL;
- rrk->entry.data = rrd;
- packed_rrset_ptr_fixup(rrd);
- return rrk;
-}
-
-/** Get size of key in keyset */
-static size_t
-dnskey_get_keysize(struct packed_rrset_data* data, size_t idx)
-{
- unsigned char* pk;
- unsigned int pklen = 0;
- int algo;
- if(data->rr_len[idx] < 2+5)
- return 0;
- algo = (int)data->rr_data[idx][2+3];
- pk = (unsigned char*)data->rr_data[idx]+2+4;
- pklen = (unsigned)data->rr_len[idx]-2-4;
- return sldns_rr_dnskey_key_size_raw(pk, pklen, algo);
-}
-
-/** get dnskey flags from data */
-static uint16_t
-kd_get_flags(struct packed_rrset_data* data, size_t idx)
-{
- uint16_t f;
- if(data->rr_len[idx] < 2+2)
- return 0;
- memmove(&f, data->rr_data[idx]+2, 2);
- f = ntohs(f);
- return f;
-}
-
-size_t
-key_entry_keysize(struct key_entry_key* kkey)
-{
- struct packed_rrset_data* d;
- /* compute size of smallest ZSK key in the rrset */
- size_t i;
- size_t bits = 0;
- if(!key_entry_isgood(kkey))
- return 0;
- d = ((struct key_entry_data*)kkey->entry.data)->rrset_data;
- for(i=0; i<d->count; i++) {
- if(!(kd_get_flags(d, i) & DNSKEY_BIT_ZSK))
- continue;
- if(i==0 || dnskey_get_keysize(d, i) < bits)
- bits = dnskey_get_keysize(d, i);
- }
- return bits;
-}
diff --git a/external/unbound/validator/val_kentry.h b/external/unbound/validator/val_kentry.h
deleted file mode 100644
index ade65571a..000000000
--- a/external/unbound/validator/val_kentry.h
+++ /dev/null
@@ -1,220 +0,0 @@
-/*
- * validator/val_kentry.h - validator key entry definition.
- *
- * Copyright (c) 2007, NLnet Labs. All rights reserved.
- *
- * This software is open source.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- *
- * Redistributions of source code must retain the above copyright notice,
- * this list of conditions and the following disclaimer.
- *
- * Redistributions in binary form must reproduce the above copyright notice,
- * this list of conditions and the following disclaimer in the documentation
- * and/or other materials provided with the distribution.
- *
- * Neither the name of the NLNET LABS nor the names of its contributors may
- * be used to endorse or promote products derived from this software without
- * specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
- * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
- * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
- * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
- * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
- * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-/**
- * \file
- *
- * This file contains functions for dealing with validator key entries.
- */
-
-#ifndef VALIDATOR_VAL_KENTRY_H
-#define VALIDATOR_VAL_KENTRY_H
-struct packed_rrset_data;
-struct regional;
-struct ub_packed_rrset_key;
-#include "util/storage/lruhash.h"
-
-/**
- * A key entry for the validator.
- * This may or may not be a trusted key.
- * This is what is stored in the key cache.
- * This is the key part for the cache; the key entry key.
- */
-struct key_entry_key {
- /** lru hash entry */
- struct lruhash_entry entry;
- /** name of the key */
- uint8_t* name;
- /** length of name */
- size_t namelen;
- /** class of the key, host byteorder */
- uint16_t key_class;
-};
-
-/**
- * Key entry for the validator.
- * Contains key status.
- * This is the data part for the cache, the key entry data.
- *
- * Can be in three basic states:
- * isbad=0: good key
- * isbad=1: bad key
- * isbad=0 && rrset=0: insecure space.
- */
-struct key_entry_data {
- /** the TTL of this entry (absolute time) */
- time_t ttl;
- /** the key rrdata. can be NULL to signal keyless name. */
- struct packed_rrset_data* rrset_data;
- /** not NULL sometimes to give reason why bogus */
- char* reason;
- /** list of algorithms signalled, ends with 0, or NULL */
- uint8_t* algo;
- /** DNS RR type of the rrset data (host order) */
- uint16_t rrset_type;
- /** if the key is bad: Bogus or malformed */
- uint8_t isbad;
-};
-
-/** function for lruhash operation */
-size_t key_entry_sizefunc(void* key, void* data);
-
-/** function for lruhash operation */
-int key_entry_compfunc(void* k1, void* k2);
-
-/** function for lruhash operation */
-void key_entry_delkeyfunc(void* key, void* userarg);
-
-/** function for lruhash operation */
-void key_entry_deldatafunc(void* data, void* userarg);
-
-/** calculate hash for key entry
- * @param kk: key entry. The lruhash entry.hash value is filled in.
- */
-void key_entry_hash(struct key_entry_key* kk);
-
-/**
- * Copy a key entry, to be region-allocated.
- * @param kkey: the key entry key (and data pointer) to copy.
- * @param region: where to allocate it
- * @return newly region-allocated entry or NULL on a failure to allocate.
- */
-struct key_entry_key* key_entry_copy_toregion(struct key_entry_key* kkey,
- struct regional* region);
-
-/**
- * Copy a key entry, malloced.
- * @param kkey: the key entry key (and data pointer) to copy.
- * @return newly allocated entry or NULL on a failure to allocate memory.
- */
-struct key_entry_key* key_entry_copy(struct key_entry_key* kkey);
-
-/**
- * See if this is a null entry. Does not do locking.
- * @param kkey: must have data pointer set correctly
- * @return true if it is a NULL rrset entry.
- */
-int key_entry_isnull(struct key_entry_key* kkey);
-
-/**
- * See if this entry is good. Does not do locking.
- * @param kkey: must have data pointer set correctly
- * @return true if it is good.
- */
-int key_entry_isgood(struct key_entry_key* kkey);
-
-/**
- * See if this entry is bad. Does not do locking.
- * @param kkey: must have data pointer set correctly
- * @return true if it is bad.
- */
-int key_entry_isbad(struct key_entry_key* kkey);
-
-/**
- * Set reason why a key is bad.
- * @param kkey: bad key.
- * @param reason: string to attach, you must allocate it.
- * Not safe to call twice unless you deallocate it yourself.
- */
-void key_entry_set_reason(struct key_entry_key* kkey, char* reason);
-
-/**
- * Get reason why a key is bad.
- * @param kkey: bad key
- * @return pointer to string.
- * String is part of key entry and is deleted with it.
- */
-char* key_entry_get_reason(struct key_entry_key* kkey);
-
-/**
- * Create a null entry, in the given region.
- * @param region: where to allocate
- * @param name: the key name
- * @param namelen: length of name
- * @param dclass: class of key entry. (host order);
- * @param ttl: what ttl should the key have. relative.
- * @param now: current time (added to ttl).
- * @return new key entry or NULL on alloc failure
- */
-struct key_entry_key* key_entry_create_null(struct regional* region,
- uint8_t* name, size_t namelen, uint16_t dclass, time_t ttl,
- time_t now);
-
-/**
- * Create a key entry from an rrset, in the given region.
- * @param region: where to allocate.
- * @param name: the key name
- * @param namelen: length of name
- * @param dclass: class of key entry. (host order);
- * @param rrset: data for key entry. This is copied to the region.
- * @param sigalg: signalled algorithm list (or NULL).
- * @param now: current time (added to ttl of rrset)
- * @return new key entry or NULL on alloc failure
- */
-struct key_entry_key* key_entry_create_rrset(struct regional* region,
- uint8_t* name, size_t namelen, uint16_t dclass,
- struct ub_packed_rrset_key* rrset, uint8_t* sigalg, time_t now);
-
-/**
- * Create a bad entry, in the given region.
- * @param region: where to allocate
- * @param name: the key name
- * @param namelen: length of name
- * @param dclass: class of key entry. (host order);
- * @param ttl: what ttl should the key have. relative.
- * @param now: current time (added to ttl).
- * @return new key entry or NULL on alloc failure
- */
-struct key_entry_key* key_entry_create_bad(struct regional* region,
- uint8_t* name, size_t namelen, uint16_t dclass, time_t ttl,
- time_t now);
-
-/**
- * Obtain rrset from a key entry, allocated in region.
- * @param kkey: key entry to convert to a rrset.
- * @param region: where to allocate rrset
- * @return rrset copy; if no rrset or alloc error returns NULL.
- */
-struct ub_packed_rrset_key* key_entry_get_rrset(struct key_entry_key* kkey,
- struct regional* region);
-
-/**
- * Get keysize of the keyentry.
- * @param kkey: key, must be a good key, with contents.
- * @return size in bits of the key.
- */
-size_t key_entry_keysize(struct key_entry_key* kkey);
-
-#endif /* VALIDATOR_VAL_KENTRY_H */
diff --git a/external/unbound/validator/val_neg.c b/external/unbound/validator/val_neg.c
deleted file mode 100644
index fe57ac2c4..000000000
--- a/external/unbound/validator/val_neg.c
+++ /dev/null
@@ -1,1470 +0,0 @@
-/*
- * validator/val_neg.c - validator aggressive negative caching functions.
- *
- * Copyright (c) 2008, NLnet Labs. All rights reserved.
- *
- * This software is open source.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- *
- * Redistributions of source code must retain the above copyright notice,
- * this list of conditions and the following disclaimer.
- *
- * Redistributions in binary form must reproduce the above copyright notice,
- * this list of conditions and the following disclaimer in the documentation
- * and/or other materials provided with the distribution.
- *
- * Neither the name of the NLNET LABS nor the names of its contributors may
- * be used to endorse or promote products derived from this software without
- * specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
- * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
- * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
- * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
- * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
- * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-/**
- * \file
- *
- * This file contains helper functions for the validator module.
- * The functions help with aggressive negative caching.
- * This creates new denials of existence, and proofs for absence of types
- * from cached NSEC records.
- */
-#include "config.h"
-#ifdef HAVE_OPENSSL_SSL_H
-#include "openssl/ssl.h"
-#define NSEC3_SHA_LEN SHA_DIGEST_LENGTH
-#else
-#define NSEC3_SHA_LEN 20
-#endif
-#include "validator/val_neg.h"
-#include "validator/val_nsec.h"
-#include "validator/val_nsec3.h"
-#include "validator/val_utils.h"
-#include "util/data/dname.h"
-#include "util/data/msgreply.h"
-#include "util/log.h"
-#include "util/net_help.h"
-#include "util/config_file.h"
-#include "services/cache/rrset.h"
-#include "services/cache/dns.h"
-#include "sldns/rrdef.h"
-#include "sldns/sbuffer.h"
-
-int val_neg_data_compare(const void* a, const void* b)
-{
- struct val_neg_data* x = (struct val_neg_data*)a;
- struct val_neg_data* y = (struct val_neg_data*)b;
- int m;
- return dname_canon_lab_cmp(x->name, x->labs, y->name, y->labs, &m);
-}
-
-int val_neg_zone_compare(const void* a, const void* b)
-{
- struct val_neg_zone* x = (struct val_neg_zone*)a;
- struct val_neg_zone* y = (struct val_neg_zone*)b;
- int m;
- if(x->dclass != y->dclass) {
- if(x->dclass < y->dclass)
- return -1;
- return 1;
- }
- return dname_canon_lab_cmp(x->name, x->labs, y->name, y->labs, &m);
-}
-
-struct val_neg_cache* val_neg_create(struct config_file* cfg, size_t maxiter)
-{
- struct val_neg_cache* neg = (struct val_neg_cache*)calloc(1,
- sizeof(*neg));
- if(!neg) {
- log_err("Could not create neg cache: out of memory");
- return NULL;
- }
- neg->nsec3_max_iter = maxiter;
- neg->max = 1024*1024; /* 1 M is thousands of entries */
- if(cfg) neg->max = cfg->neg_cache_size;
- rbtree_init(&neg->tree, &val_neg_zone_compare);
- lock_basic_init(&neg->lock);
- lock_protect(&neg->lock, neg, sizeof(*neg));
- return neg;
-}
-
-size_t val_neg_get_mem(struct val_neg_cache* neg)
-{
- size_t result;
- lock_basic_lock(&neg->lock);
- result = sizeof(*neg) + neg->use;
- lock_basic_unlock(&neg->lock);
- return result;
-}
-
-/** clear datas on cache deletion */
-static void
-neg_clear_datas(rbnode_type* n, void* ATTR_UNUSED(arg))
-{
- struct val_neg_data* d = (struct val_neg_data*)n;
- free(d->name);
- free(d);
-}
-
-/** clear zones on cache deletion */
-static void
-neg_clear_zones(rbnode_type* n, void* ATTR_UNUSED(arg))
-{
- struct val_neg_zone* z = (struct val_neg_zone*)n;
- /* delete all the rrset entries in the tree */
- traverse_postorder(&z->tree, &neg_clear_datas, NULL);
- free(z->nsec3_salt);
- free(z->name);
- free(z);
-}
-
-void neg_cache_delete(struct val_neg_cache* neg)
-{
- if(!neg) return;
- lock_basic_destroy(&neg->lock);
- /* delete all the zones in the tree */
- traverse_postorder(&neg->tree, &neg_clear_zones, NULL);
- free(neg);
-}
-
-/**
- * Put data element at the front of the LRU list.
- * @param neg: negative cache with LRU start and end.
- * @param data: this data is fronted.
- */
-static void neg_lru_front(struct val_neg_cache* neg,
- struct val_neg_data* data)
-{
- data->prev = NULL;
- data->next = neg->first;
- if(!neg->first)
- neg->last = data;
- else neg->first->prev = data;
- neg->first = data;
-}
-
-/**
- * Remove data element from LRU list.
- * @param neg: negative cache with LRU start and end.
- * @param data: this data is removed from the list.
- */
-static void neg_lru_remove(struct val_neg_cache* neg,
- struct val_neg_data* data)
-{
- if(data->prev)
- data->prev->next = data->next;
- else neg->first = data->next;
- if(data->next)
- data->next->prev = data->prev;
- else neg->last = data->prev;
-}
-
-/**
- * Touch LRU for data element, put it at the start of the LRU list.
- * @param neg: negative cache with LRU start and end.
- * @param data: this data is used.
- */
-static void neg_lru_touch(struct val_neg_cache* neg,
- struct val_neg_data* data)
-{
- if(data == neg->first)
- return; /* nothing to do */
- /* remove from current lru position */
- neg_lru_remove(neg, data);
- /* add at front */
- neg_lru_front(neg, data);
-}
-
-/**
- * Delete a zone element from the negative cache.
- * May delete other zone elements to keep tree coherent, or
- * only mark the element as 'not in use'.
- * @param neg: negative cache.
- * @param z: zone element to delete.
- */
-static void neg_delete_zone(struct val_neg_cache* neg, struct val_neg_zone* z)
-{
- struct val_neg_zone* p, *np;
- if(!z) return;
- log_assert(z->in_use);
- log_assert(z->count > 0);
- z->in_use = 0;
-
- /* go up the tree and reduce counts */
- p = z;
- while(p) {
- log_assert(p->count > 0);
- p->count --;
- p = p->parent;
- }
-
- /* remove zones with zero count */
- p = z;
- while(p && p->count == 0) {
- np = p->parent;
- (void)rbtree_delete(&neg->tree, &p->node);
- neg->use -= p->len + sizeof(*p);
- free(p->nsec3_salt);
- free(p->name);
- free(p);
- p = np;
- }
-}
-
-void neg_delete_data(struct val_neg_cache* neg, struct val_neg_data* el)
-{
- struct val_neg_zone* z;
- struct val_neg_data* p, *np;
- if(!el) return;
- z = el->zone;
- log_assert(el->in_use);
- log_assert(el->count > 0);
- el->in_use = 0;
-
- /* remove it from the lru list */
- neg_lru_remove(neg, el);
-
- /* go up the tree and reduce counts */
- p = el;
- while(p) {
- log_assert(p->count > 0);
- p->count --;
- p = p->parent;
- }
-
- /* delete 0 count items from tree */
- p = el;
- while(p && p->count == 0) {
- np = p->parent;
- (void)rbtree_delete(&z->tree, &p->node);
- neg->use -= p->len + sizeof(*p);
- free(p->name);
- free(p);
- p = np;
- }
-
- /* check if the zone is now unused */
- if(z->tree.count == 0) {
- neg_delete_zone(neg, z);
- }
-}
-
-/**
- * Create more space in negative cache
- * The oldest elements are deleted until enough space is present.
- * Empty zones are deleted.
- * @param neg: negative cache.
- * @param need: how many bytes are needed.
- */
-static void neg_make_space(struct val_neg_cache* neg, size_t need)
-{
- /* delete elements until enough space or its empty */
- while(neg->last && neg->max < neg->use + need) {
- neg_delete_data(neg, neg->last);
- }
-}
-
-struct val_neg_zone* neg_find_zone(struct val_neg_cache* neg,
- uint8_t* nm, size_t len, uint16_t dclass)
-{
- struct val_neg_zone lookfor;
- struct val_neg_zone* result;
- lookfor.node.key = &lookfor;
- lookfor.name = nm;
- lookfor.len = len;
- lookfor.labs = dname_count_labels(lookfor.name);
- lookfor.dclass = dclass;
-
- result = (struct val_neg_zone*)
- rbtree_search(&neg->tree, lookfor.node.key);
- return result;
-}
-
-/**
- * Find the given data
- * @param zone: negative zone
- * @param nm: what to look for.
- * @param len: length of nm
- * @param labs: labels in nm
- * @return data or NULL if not found.
- */
-static struct val_neg_data* neg_find_data(struct val_neg_zone* zone,
- uint8_t* nm, size_t len, int labs)
-{
- struct val_neg_data lookfor;
- struct val_neg_data* result;
- lookfor.node.key = &lookfor;
- lookfor.name = nm;
- lookfor.len = len;
- lookfor.labs = labs;
-
- result = (struct val_neg_data*)
- rbtree_search(&zone->tree, lookfor.node.key);
- return result;
-}
-
-/**
- * Calculate space needed for the data and all its parents
- * @param rep: NSEC entries.
- * @return size.
- */
-static size_t calc_data_need(struct reply_info* rep)
-{
- uint8_t* d;
- size_t i, len, res = 0;
-
- for(i=rep->an_numrrsets; i<rep->an_numrrsets+rep->ns_numrrsets; i++) {
- if(ntohs(rep->rrsets[i]->rk.type) == LDNS_RR_TYPE_NSEC) {
- d = rep->rrsets[i]->rk.dname;
- len = rep->rrsets[i]->rk.dname_len;
- res = sizeof(struct val_neg_data) + len;
- while(!dname_is_root(d)) {
- log_assert(len > 1); /* not root label */
- dname_remove_label(&d, &len);
- res += sizeof(struct val_neg_data) + len;
- }
- }
- }
- return res;
-}
-
-/**
- * Calculate space needed for zone and all its parents
- * @param d: name of zone
- * @param len: length of name
- * @return size.
- */
-static size_t calc_zone_need(uint8_t* d, size_t len)
-{
- size_t res = sizeof(struct val_neg_zone) + len;
- while(!dname_is_root(d)) {
- log_assert(len > 1); /* not root label */
- dname_remove_label(&d, &len);
- res += sizeof(struct val_neg_zone) + len;
- }
- return res;
-}
-
-/**
- * Find closest existing parent zone of the given name.
- * @param neg: negative cache.
- * @param nm: name to look for
- * @param nm_len: length of nm
- * @param labs: labelcount of nm.
- * @param qclass: class.
- * @return the zone or NULL if none found.
- */
-static struct val_neg_zone* neg_closest_zone_parent(struct val_neg_cache* neg,
- uint8_t* nm, size_t nm_len, int labs, uint16_t qclass)
-{
- struct val_neg_zone key;
- struct val_neg_zone* result;
- rbnode_type* res = NULL;
- key.node.key = &key;
- key.name = nm;
- key.len = nm_len;
- key.labs = labs;
- key.dclass = qclass;
- if(rbtree_find_less_equal(&neg->tree, &key, &res)) {
- /* exact match */
- result = (struct val_neg_zone*)res;
- } else {
- /* smaller element (or no element) */
- int m;
- result = (struct val_neg_zone*)res;
- if(!result || result->dclass != qclass)
- return NULL;
- /* count number of labels matched */
- (void)dname_lab_cmp(result->name, result->labs, key.name,
- key.labs, &m);
- while(result) { /* go up until qname is subdomain of stub */
- if(result->labs <= m)
- break;
- result = result->parent;
- }
- }
- return result;
-}
-
-/**
- * Find closest existing parent data for the given name.
- * @param zone: to look in.
- * @param nm: name to look for
- * @param nm_len: length of nm
- * @param labs: labelcount of nm.
- * @return the data or NULL if none found.
- */
-static struct val_neg_data* neg_closest_data_parent(
- struct val_neg_zone* zone, uint8_t* nm, size_t nm_len, int labs)
-{
- struct val_neg_data key;
- struct val_neg_data* result;
- rbnode_type* res = NULL;
- key.node.key = &key;
- key.name = nm;
- key.len = nm_len;
- key.labs = labs;
- if(rbtree_find_less_equal(&zone->tree, &key, &res)) {
- /* exact match */
- result = (struct val_neg_data*)res;
- } else {
- /* smaller element (or no element) */
- int m;
- result = (struct val_neg_data*)res;
- if(!result)
- return NULL;
- /* count number of labels matched */
- (void)dname_lab_cmp(result->name, result->labs, key.name,
- key.labs, &m);
- while(result) { /* go up until qname is subdomain of stub */
- if(result->labs <= m)
- break;
- result = result->parent;
- }
- }
- return result;
-}
-
-/**
- * Create a single zone node
- * @param nm: name for zone (copied)
- * @param nm_len: length of name
- * @param labs: labels in name.
- * @param dclass: class of zone, host order.
- * @return new zone or NULL on failure
- */
-static struct val_neg_zone* neg_setup_zone_node(
- uint8_t* nm, size_t nm_len, int labs, uint16_t dclass)
-{
- struct val_neg_zone* zone =
- (struct val_neg_zone*)calloc(1, sizeof(*zone));
- if(!zone) {
- return NULL;
- }
- zone->node.key = zone;
- zone->name = memdup(nm, nm_len);
- if(!zone->name) {
- free(zone);
- return NULL;
- }
- zone->len = nm_len;
- zone->labs = labs;
- zone->dclass = dclass;
-
- rbtree_init(&zone->tree, &val_neg_data_compare);
- return zone;
-}
-
-/**
- * Create a linked list of parent zones, starting at longname ending on
- * the parent (can be NULL, creates to the root).
- * @param nm: name for lowest in chain
- * @param nm_len: length of name
- * @param labs: labels in name.
- * @param dclass: class of zone.
- * @param parent: NULL for to root, else so it fits under here.
- * @return zone; a chain of zones and their parents up to the parent.
- * or NULL on malloc failure
- */
-static struct val_neg_zone* neg_zone_chain(
- uint8_t* nm, size_t nm_len, int labs, uint16_t dclass,
- struct val_neg_zone* parent)
-{
- int i;
- int tolabs = parent?parent->labs:0;
- struct val_neg_zone* zone, *prev = NULL, *first = NULL;
-
- /* create the new subtree, i is labelcount of current creation */
- /* this creates a 'first' to z->parent=NULL list of zones */
- for(i=labs; i!=tolabs; i--) {
- /* create new item */
- zone = neg_setup_zone_node(nm, nm_len, i, dclass);
- if(!zone) {
- /* need to delete other allocations in this routine!*/
- struct val_neg_zone* p=first, *np;
- while(p) {
- np = p->parent;
- free(p->name);
- free(p);
- p = np;
- }
- return NULL;
- }
- if(i == labs) {
- first = zone;
- } else {
- prev->parent = zone;
- }
- /* prepare for next name */
- prev = zone;
- dname_remove_label(&nm, &nm_len);
- }
- return first;
-}
-
-void val_neg_zone_take_inuse(struct val_neg_zone* zone)
-{
- if(!zone->in_use) {
- struct val_neg_zone* p;
- zone->in_use = 1;
- /* increase usage count of all parents */
- for(p=zone; p; p = p->parent) {
- p->count++;
- }
- }
-}
-
-struct val_neg_zone* neg_create_zone(struct val_neg_cache* neg,
- uint8_t* nm, size_t nm_len, uint16_t dclass)
-{
- struct val_neg_zone* zone;
- struct val_neg_zone* parent;
- struct val_neg_zone* p, *np;
- int labs = dname_count_labels(nm);
-
- /* find closest enclosing parent zone that (still) exists */
- parent = neg_closest_zone_parent(neg, nm, nm_len, labs, dclass);
- if(parent && query_dname_compare(parent->name, nm) == 0)
- return parent; /* already exists, weird */
- /* if parent exists, it is in use */
- log_assert(!parent || parent->count > 0);
- zone = neg_zone_chain(nm, nm_len, labs, dclass, parent);
- if(!zone) {
- return NULL;
- }
-
- /* insert the list of zones into the tree */
- p = zone;
- while(p) {
- np = p->parent;
- /* mem use */
- neg->use += sizeof(struct val_neg_zone) + p->len;
- /* insert in tree */
- (void)rbtree_insert(&neg->tree, &p->node);
- /* last one needs proper parent pointer */
- if(np == NULL)
- p->parent = parent;
- p = np;
- }
- return zone;
-}
-
-/** find zone name of message, returns the SOA record */
-static struct ub_packed_rrset_key* reply_find_soa(struct reply_info* rep)
-{
- size_t i;
- for(i=rep->an_numrrsets; i< rep->an_numrrsets+rep->ns_numrrsets; i++){
- if(ntohs(rep->rrsets[i]->rk.type) == LDNS_RR_TYPE_SOA)
- return rep->rrsets[i];
- }
- return NULL;
-}
-
-/** see if the reply has NSEC records worthy of caching */
-static int reply_has_nsec(struct reply_info* rep)
-{
- size_t i;
- struct packed_rrset_data* d;
- if(rep->security != sec_status_secure)
- return 0;
- for(i=rep->an_numrrsets; i< rep->an_numrrsets+rep->ns_numrrsets; i++){
- if(ntohs(rep->rrsets[i]->rk.type) == LDNS_RR_TYPE_NSEC) {
- d = (struct packed_rrset_data*)rep->rrsets[i]->
- entry.data;
- if(d->security == sec_status_secure)
- return 1;
- }
- }
- return 0;
-}
-
-
-/**
- * Create single node of data element.
- * @param nm: name (copied)
- * @param nm_len: length of name
- * @param labs: labels in name.
- * @return element with name nm, or NULL malloc failure.
- */
-static struct val_neg_data* neg_setup_data_node(
- uint8_t* nm, size_t nm_len, int labs)
-{
- struct val_neg_data* el;
- el = (struct val_neg_data*)calloc(1, sizeof(*el));
- if(!el) {
- return NULL;
- }
- el->node.key = el;
- el->name = memdup(nm, nm_len);
- if(!el->name) {
- free(el);
- return NULL;
- }
- el->len = nm_len;
- el->labs = labs;
- return el;
-}
-
-/**
- * Create chain of data element and parents
- * @param nm: name
- * @param nm_len: length of name
- * @param labs: labels in name.
- * @param parent: up to where to make, if NULL up to root label.
- * @return lowest element with name nm, or NULL malloc failure.
- */
-static struct val_neg_data* neg_data_chain(
- uint8_t* nm, size_t nm_len, int labs, struct val_neg_data* parent)
-{
- int i;
- int tolabs = parent?parent->labs:0;
- struct val_neg_data* el, *first = NULL, *prev = NULL;
-
- /* create the new subtree, i is labelcount of current creation */
- /* this creates a 'first' to z->parent=NULL list of zones */
- for(i=labs; i!=tolabs; i--) {
- /* create new item */
- el = neg_setup_data_node(nm, nm_len, i);
- if(!el) {
- /* need to delete other allocations in this routine!*/
- struct val_neg_data* p = first, *np;
- while(p) {
- np = p->parent;
- free(p->name);
- free(p);
- p = np;
- }
- return NULL;
- }
- if(i == labs) {
- first = el;
- } else {
- prev->parent = el;
- }
-
- /* prepare for next name */
- prev = el;
- dname_remove_label(&nm, &nm_len);
- }
- return first;
-}
-
-/**
- * Remove NSEC records between start and end points.
- * By walking the tree, the tree is sorted canonically.
- * @param neg: negative cache.
- * @param zone: the zone
- * @param el: element to start walking at.
- * @param nsec: the nsec record with the end point
- */
-static void wipeout(struct val_neg_cache* neg, struct val_neg_zone* zone,
- struct val_neg_data* el, struct ub_packed_rrset_key* nsec)
-{
- struct packed_rrset_data* d = (struct packed_rrset_data*)nsec->
- entry.data;
- uint8_t* end;
- size_t end_len;
- int end_labs, m;
- rbnode_type* walk, *next;
- struct val_neg_data* cur;
- uint8_t buf[257];
- /* get endpoint */
- if(!d || d->count == 0 || d->rr_len[0] < 2+1)
- return;
- if(ntohs(nsec->rk.type) == LDNS_RR_TYPE_NSEC) {
- end = d->rr_data[0]+2;
- end_len = dname_valid(end, d->rr_len[0]-2);
- end_labs = dname_count_labels(end);
- } else {
- /* NSEC3 */
- if(!nsec3_get_nextowner_b32(nsec, 0, buf, sizeof(buf)))
- return;
- end = buf;
- end_labs = dname_count_size_labels(end, &end_len);
- }
-
- /* sanity check, both owner and end must be below the zone apex */
- if(!dname_subdomain_c(el->name, zone->name) ||
- !dname_subdomain_c(end, zone->name))
- return;
-
- /* detect end of zone NSEC ; wipe until the end of zone */
- if(query_dname_compare(end, zone->name) == 0) {
- end = NULL;
- }
-
- walk = rbtree_next(&el->node);
- while(walk && walk != RBTREE_NULL) {
- cur = (struct val_neg_data*)walk;
- /* sanity check: must be larger than start */
- if(dname_canon_lab_cmp(cur->name, cur->labs,
- el->name, el->labs, &m) <= 0) {
- /* r == 0 skip original record. */
- /* r < 0 too small! */
- walk = rbtree_next(walk);
- continue;
- }
- /* stop at endpoint, also data at empty nonterminals must be
- * removed (no NSECs there) so everything between
- * start and end */
- if(end && dname_canon_lab_cmp(cur->name, cur->labs,
- end, end_labs, &m) >= 0) {
- break;
- }
- /* this element has to be deleted, but we cannot do it
- * now, because we are walking the tree still ... */
- /* get the next element: */
- next = rbtree_next(walk);
- /* now delete the original element, this may trigger
- * rbtree rebalances, but really, the next element is
- * the one we need.
- * But it may trigger delete of other data and the
- * entire zone. However, if that happens, this is done
- * by deleting the *parents* of the element for deletion,
- * and maybe also the entire zone if it is empty.
- * But parents are smaller in canonical compare, thus,
- * if a larger element exists, then it is not a parent,
- * it cannot get deleted, the zone cannot get empty.
- * If the next==NULL, then zone can be empty. */
- if(cur->in_use)
- neg_delete_data(neg, cur);
- walk = next;
- }
-}
-
-void neg_insert_data(struct val_neg_cache* neg,
- struct val_neg_zone* zone, struct ub_packed_rrset_key* nsec)
-{
- struct packed_rrset_data* d;
- struct val_neg_data* parent;
- struct val_neg_data* el;
- uint8_t* nm = nsec->rk.dname;
- size_t nm_len = nsec->rk.dname_len;
- int labs = dname_count_labels(nsec->rk.dname);
-
- d = (struct packed_rrset_data*)nsec->entry.data;
- if( !(d->security == sec_status_secure ||
- (d->security == sec_status_unchecked && d->rrsig_count > 0)))
- return;
- log_nametypeclass(VERB_ALGO, "negcache rr",
- nsec->rk.dname, ntohs(nsec->rk.type),
- ntohs(nsec->rk.rrset_class));
-
- /* find closest enclosing parent data that (still) exists */
- parent = neg_closest_data_parent(zone, nm, nm_len, labs);
- if(parent && query_dname_compare(parent->name, nm) == 0) {
- /* perfect match already exists */
- log_assert(parent->count > 0);
- el = parent;
- } else {
- struct val_neg_data* p, *np;
-
- /* create subtree for perfect match */
- /* if parent exists, it is in use */
- log_assert(!parent || parent->count > 0);
-
- el = neg_data_chain(nm, nm_len, labs, parent);
- if(!el) {
- log_err("out of memory inserting NSEC negative cache");
- return;
- }
- el->in_use = 0; /* set on below */
-
- /* insert the list of zones into the tree */
- p = el;
- while(p) {
- np = p->parent;
- /* mem use */
- neg->use += sizeof(struct val_neg_data) + p->len;
- /* insert in tree */
- p->zone = zone;
- (void)rbtree_insert(&zone->tree, &p->node);
- /* last one needs proper parent pointer */
- if(np == NULL)
- p->parent = parent;
- p = np;
- }
- }
-
- if(!el->in_use) {
- struct val_neg_data* p;
-
- el->in_use = 1;
- /* increase usage count of all parents */
- for(p=el; p; p = p->parent) {
- p->count++;
- }
-
- neg_lru_front(neg, el);
- } else {
- /* in use, bring to front, lru */
- neg_lru_touch(neg, el);
- }
-
- /* if nsec3 store last used parameters */
- if(ntohs(nsec->rk.type) == LDNS_RR_TYPE_NSEC3) {
- int h;
- uint8_t* s;
- size_t slen, it;
- if(nsec3_get_params(nsec, 0, &h, &it, &s, &slen) &&
- it <= neg->nsec3_max_iter &&
- (h != zone->nsec3_hash || it != zone->nsec3_iter ||
- slen != zone->nsec3_saltlen ||
- memcmp(zone->nsec3_salt, s, slen) != 0)) {
-
- if(slen > 0) {
- uint8_t* sa = memdup(s, slen);
- if(sa) {
- free(zone->nsec3_salt);
- zone->nsec3_salt = sa;
- zone->nsec3_saltlen = slen;
- zone->nsec3_iter = it;
- zone->nsec3_hash = h;
- }
- } else {
- free(zone->nsec3_salt);
- zone->nsec3_salt = NULL;
- zone->nsec3_saltlen = 0;
- zone->nsec3_iter = it;
- zone->nsec3_hash = h;
- }
- }
- }
-
- /* wipe out the cache items between NSEC start and end */
- wipeout(neg, zone, el, nsec);
-}
-
-void val_neg_addreply(struct val_neg_cache* neg, struct reply_info* rep)
-{
- size_t i, need;
- struct ub_packed_rrset_key* soa;
- struct val_neg_zone* zone;
- /* see if secure nsecs inside */
- if(!reply_has_nsec(rep))
- return;
- /* find the zone name in message */
- soa = reply_find_soa(rep);
- if(!soa)
- return;
-
- log_nametypeclass(VERB_ALGO, "negcache insert for zone",
- soa->rk.dname, LDNS_RR_TYPE_SOA, ntohs(soa->rk.rrset_class));
-
- /* ask for enough space to store all of it */
- need = calc_data_need(rep) +
- calc_zone_need(soa->rk.dname, soa->rk.dname_len);
- lock_basic_lock(&neg->lock);
- neg_make_space(neg, need);
-
- /* find or create the zone entry */
- zone = neg_find_zone(neg, soa->rk.dname, soa->rk.dname_len,
- ntohs(soa->rk.rrset_class));
- if(!zone) {
- if(!(zone = neg_create_zone(neg, soa->rk.dname,
- soa->rk.dname_len, ntohs(soa->rk.rrset_class)))) {
- lock_basic_unlock(&neg->lock);
- log_err("out of memory adding negative zone");
- return;
- }
- }
- val_neg_zone_take_inuse(zone);
-
- /* insert the NSECs */
- for(i=rep->an_numrrsets; i< rep->an_numrrsets+rep->ns_numrrsets; i++){
- if(ntohs(rep->rrsets[i]->rk.type) != LDNS_RR_TYPE_NSEC)
- continue;
- if(!dname_subdomain_c(rep->rrsets[i]->rk.dname,
- zone->name)) continue;
- /* insert NSEC into this zone's tree */
- neg_insert_data(neg, zone, rep->rrsets[i]);
- }
- if(zone->tree.count == 0) {
- /* remove empty zone if inserts failed */
- neg_delete_zone(neg, zone);
- }
- lock_basic_unlock(&neg->lock);
-}
-
-/**
- * Lookup closest data record. For NSEC denial.
- * @param zone: zone to look in
- * @param qname: name to look for.
- * @param len: length of name
- * @param labs: labels in name
- * @param data: data element, exact or smaller or NULL
- * @return true if exact match.
- */
-static int neg_closest_data(struct val_neg_zone* zone,
- uint8_t* qname, size_t len, int labs, struct val_neg_data** data)
-{
- struct val_neg_data key;
- rbnode_type* r;
- key.node.key = &key;
- key.name = qname;
- key.len = len;
- key.labs = labs;
- if(rbtree_find_less_equal(&zone->tree, &key, &r)) {
- /* exact match */
- *data = (struct val_neg_data*)r;
- return 1;
- } else {
- /* smaller match */
- *data = (struct val_neg_data*)r;
- return 0;
- }
-}
-
-int val_neg_dlvlookup(struct val_neg_cache* neg, uint8_t* qname, size_t len,
- uint16_t qclass, struct rrset_cache* rrset_cache, time_t now)
-{
- /* lookup closest zone */
- struct val_neg_zone* zone;
- struct val_neg_data* data;
- int labs;
- struct ub_packed_rrset_key* nsec;
- struct packed_rrset_data* d;
- uint32_t flags;
- uint8_t* wc;
- struct query_info qinfo;
- if(!neg) return 0;
-
- log_nametypeclass(VERB_ALGO, "negcache dlvlookup", qname,
- LDNS_RR_TYPE_DLV, qclass);
-
- labs = dname_count_labels(qname);
- lock_basic_lock(&neg->lock);
- zone = neg_closest_zone_parent(neg, qname, len, labs, qclass);
- while(zone && !zone->in_use)
- zone = zone->parent;
- if(!zone) {
- lock_basic_unlock(&neg->lock);
- return 0;
- }
- log_nametypeclass(VERB_ALGO, "negcache zone", zone->name, 0,
- zone->dclass);
-
- /* DLV is defined to use NSEC only */
- if(zone->nsec3_hash) {
- lock_basic_unlock(&neg->lock);
- return 0;
- }
-
- /* lookup closest data record */
- (void)neg_closest_data(zone, qname, len, labs, &data);
- while(data && !data->in_use)
- data = data->parent;
- if(!data) {
- lock_basic_unlock(&neg->lock);
- return 0;
- }
- log_nametypeclass(VERB_ALGO, "negcache rr", data->name,
- LDNS_RR_TYPE_NSEC, zone->dclass);
-
- /* lookup rrset in rrset cache */
- flags = 0;
- if(query_dname_compare(data->name, zone->name) == 0)
- flags = PACKED_RRSET_NSEC_AT_APEX;
- nsec = rrset_cache_lookup(rrset_cache, data->name, data->len,
- LDNS_RR_TYPE_NSEC, zone->dclass, flags, now, 0);
-
- /* check if secure and TTL ok */
- if(!nsec) {
- lock_basic_unlock(&neg->lock);
- return 0;
- }
- d = (struct packed_rrset_data*)nsec->entry.data;
- if(!d || now > d->ttl) {
- lock_rw_unlock(&nsec->entry.lock);
- /* delete data record if expired */
- neg_delete_data(neg, data);
- lock_basic_unlock(&neg->lock);
- return 0;
- }
- if(d->security != sec_status_secure) {
- lock_rw_unlock(&nsec->entry.lock);
- neg_delete_data(neg, data);
- lock_basic_unlock(&neg->lock);
- return 0;
- }
- verbose(VERB_ALGO, "negcache got secure rrset");
-
- /* check NSEC security */
- /* check if NSEC proves no DLV type exists */
- /* check if NSEC proves NXDOMAIN for qname */
- qinfo.qname = qname;
- qinfo.qtype = LDNS_RR_TYPE_DLV;
- qinfo.qclass = qclass;
- qinfo.local_alias = NULL;
- if(!nsec_proves_nodata(nsec, &qinfo, &wc) &&
- !val_nsec_proves_name_error(nsec, qname)) {
- /* the NSEC is not a denial for the DLV */
- lock_rw_unlock(&nsec->entry.lock);
- lock_basic_unlock(&neg->lock);
- verbose(VERB_ALGO, "negcache not proven");
- return 0;
- }
- /* so the NSEC was a NODATA proof, or NXDOMAIN proof. */
-
- /* no need to check for wildcard NSEC; no wildcards in DLV repos */
- /* no need to lookup SOA record for client; no response message */
-
- lock_rw_unlock(&nsec->entry.lock);
- /* if OK touch the LRU for neg_data element */
- neg_lru_touch(neg, data);
- lock_basic_unlock(&neg->lock);
- verbose(VERB_ALGO, "negcache DLV denial proven");
- return 1;
-}
-
-/** see if the reply has signed NSEC records and return the signer */
-static uint8_t* reply_nsec_signer(struct reply_info* rep, size_t* signer_len,
- uint16_t* dclass)
-{
- size_t i;
- struct packed_rrset_data* d;
- uint8_t* s;
- for(i=rep->an_numrrsets; i< rep->an_numrrsets+rep->ns_numrrsets; i++){
- if(ntohs(rep->rrsets[i]->rk.type) == LDNS_RR_TYPE_NSEC ||
- ntohs(rep->rrsets[i]->rk.type) == LDNS_RR_TYPE_NSEC3) {
- d = (struct packed_rrset_data*)rep->rrsets[i]->
- entry.data;
- /* return first signer name of first NSEC */
- if(d->rrsig_count != 0) {
- val_find_rrset_signer(rep->rrsets[i],
- &s, signer_len);
- if(s && *signer_len) {
- *dclass = ntohs(rep->rrsets[i]->
- rk.rrset_class);
- return s;
- }
- }
- }
- }
- return 0;
-}
-
-void val_neg_addreferral(struct val_neg_cache* neg, struct reply_info* rep,
- uint8_t* zone_name)
-{
- size_t i, need;
- uint8_t* signer;
- size_t signer_len;
- uint16_t dclass;
- struct val_neg_zone* zone;
- /* no SOA in this message, find RRSIG over NSEC's signer name.
- * note the NSEC records are maybe not validated yet */
- signer = reply_nsec_signer(rep, &signer_len, &dclass);
- if(!signer)
- return;
- if(!dname_subdomain_c(signer, zone_name)) {
- /* the signer is not in the bailiwick, throw it out */
- return;
- }
-
- log_nametypeclass(VERB_ALGO, "negcache insert referral ",
- signer, LDNS_RR_TYPE_NS, dclass);
-
- /* ask for enough space to store all of it */
- need = calc_data_need(rep) + calc_zone_need(signer, signer_len);
- lock_basic_lock(&neg->lock);
- neg_make_space(neg, need);
-
- /* find or create the zone entry */
- zone = neg_find_zone(neg, signer, signer_len, dclass);
- if(!zone) {
- if(!(zone = neg_create_zone(neg, signer, signer_len,
- dclass))) {
- lock_basic_unlock(&neg->lock);
- log_err("out of memory adding negative zone");
- return;
- }
- }
- val_neg_zone_take_inuse(zone);
-
- /* insert the NSECs */
- for(i=rep->an_numrrsets; i< rep->an_numrrsets+rep->ns_numrrsets; i++){
- if(ntohs(rep->rrsets[i]->rk.type) != LDNS_RR_TYPE_NSEC &&
- ntohs(rep->rrsets[i]->rk.type) != LDNS_RR_TYPE_NSEC3)
- continue;
- if(!dname_subdomain_c(rep->rrsets[i]->rk.dname,
- zone->name)) continue;
- /* insert NSEC into this zone's tree */
- neg_insert_data(neg, zone, rep->rrsets[i]);
- }
- if(zone->tree.count == 0) {
- /* remove empty zone if inserts failed */
- neg_delete_zone(neg, zone);
- }
- lock_basic_unlock(&neg->lock);
-}
-
-/**
- * Check that an NSEC3 rrset does not have a type set.
- * None of the nsec3s in a hash-collision are allowed to have the type.
- * (since we do not know which one is the nsec3 looked at, flags, ..., we
- * ignore the cached item and let it bypass negative caching).
- * @param k: the nsec3 rrset to check.
- * @param t: type to check
- * @return true if no RRs have the type.
- */
-static int nsec3_no_type(struct ub_packed_rrset_key* k, uint16_t t)
-{
- int count = (int)((struct packed_rrset_data*)k->entry.data)->count;
- int i;
- for(i=0; i<count; i++)
- if(nsec3_has_type(k, i, t))
- return 0;
- return 1;
-}
-
-/**
- * See if rrset exists in rrset cache.
- * If it does, the bit is checked, and if not expired, it is returned
- * allocated in region.
- * @param rrset_cache: rrset cache
- * @param qname: to lookup rrset name
- * @param qname_len: length of qname.
- * @param qtype: type of rrset to lookup, host order
- * @param qclass: class of rrset to lookup, host order
- * @param flags: flags for rrset to lookup
- * @param region: where to alloc result
- * @param checkbit: if true, a bit in the nsec typemap is checked for absence.
- * @param checktype: which bit to check
- * @param now: to check ttl against
- * @return rrset or NULL
- */
-static struct ub_packed_rrset_key*
-grab_nsec(struct rrset_cache* rrset_cache, uint8_t* qname, size_t qname_len,
- uint16_t qtype, uint16_t qclass, uint32_t flags,
- struct regional* region, int checkbit, uint16_t checktype,
- time_t now)
-{
- struct ub_packed_rrset_key* r, *k = rrset_cache_lookup(rrset_cache,
- qname, qname_len, qtype, qclass, flags, now, 0);
- struct packed_rrset_data* d;
- if(!k) return NULL;
- d = (struct packed_rrset_data*)k->entry.data;
- if(d->ttl < now) {
- lock_rw_unlock(&k->entry.lock);
- return NULL;
- }
- /* only secure or unchecked records that have signatures. */
- if( ! ( d->security == sec_status_secure ||
- (d->security == sec_status_unchecked &&
- d->rrsig_count > 0) ) ) {
- lock_rw_unlock(&k->entry.lock);
- return NULL;
- }
- /* check if checktype is absent */
- if(checkbit && (
- (qtype == LDNS_RR_TYPE_NSEC && nsec_has_type(k, checktype)) ||
- (qtype == LDNS_RR_TYPE_NSEC3 && !nsec3_no_type(k, checktype))
- )) {
- lock_rw_unlock(&k->entry.lock);
- return NULL;
- }
- /* looks OK! copy to region and return it */
- r = packed_rrset_copy_region(k, region, now);
- /* if it failed, we return the NULL */
- lock_rw_unlock(&k->entry.lock);
- return r;
-}
-
-/** find nsec3 closest encloser in neg cache */
-static struct val_neg_data*
-neg_find_nsec3_ce(struct val_neg_zone* zone, uint8_t* qname, size_t qname_len,
- int qlabs, sldns_buffer* buf, uint8_t* hashnc, size_t* nclen)
-{
- struct val_neg_data* data;
- uint8_t hashce[NSEC3_SHA_LEN];
- uint8_t b32[257];
- size_t celen, b32len;
-
- *nclen = 0;
- while(qlabs > 0) {
- /* hash */
- if(!(celen=nsec3_get_hashed(buf, qname, qname_len,
- zone->nsec3_hash, zone->nsec3_iter, zone->nsec3_salt,
- zone->nsec3_saltlen, hashce, sizeof(hashce))))
- return NULL;
- if(!(b32len=nsec3_hash_to_b32(hashce, celen, zone->name,
- zone->len, b32, sizeof(b32))))
- return NULL;
-
- /* lookup (exact match only) */
- data = neg_find_data(zone, b32, b32len, zone->labs+1);
- if(data && data->in_use) {
- /* found ce match! */
- return data;
- }
-
- *nclen = celen;
- memmove(hashnc, hashce, celen);
- dname_remove_label(&qname, &qname_len);
- qlabs --;
- }
- return NULL;
-}
-
-/** check nsec3 parameters on nsec3 rrset with current zone values */
-static int
-neg_params_ok(struct val_neg_zone* zone, struct ub_packed_rrset_key* rrset)
-{
- int h;
- uint8_t* s;
- size_t slen, it;
- if(!nsec3_get_params(rrset, 0, &h, &it, &s, &slen))
- return 0;
- return (h == zone->nsec3_hash && it == zone->nsec3_iter &&
- slen == zone->nsec3_saltlen &&
- memcmp(zone->nsec3_salt, s, slen) == 0);
-}
-
-/** get next closer for nsec3 proof */
-static struct ub_packed_rrset_key*
-neg_nsec3_getnc(struct val_neg_zone* zone, uint8_t* hashnc, size_t nclen,
- struct rrset_cache* rrset_cache, struct regional* region,
- time_t now, uint8_t* b32, size_t maxb32)
-{
- struct ub_packed_rrset_key* nc_rrset;
- struct val_neg_data* data;
- size_t b32len;
-
- if(!(b32len=nsec3_hash_to_b32(hashnc, nclen, zone->name,
- zone->len, b32, maxb32)))
- return NULL;
- (void)neg_closest_data(zone, b32, b32len, zone->labs+1, &data);
- if(!data && zone->tree.count != 0) {
- /* could be before the first entry ; return the last
- * entry (possibly the rollover nsec3 at end) */
- data = (struct val_neg_data*)rbtree_last(&zone->tree);
- }
- while(data && !data->in_use)
- data = data->parent;
- if(!data)
- return NULL;
- /* got a data element in tree, grab it */
- nc_rrset = grab_nsec(rrset_cache, data->name, data->len,
- LDNS_RR_TYPE_NSEC3, zone->dclass, 0, region, 0, 0, now);
- if(!nc_rrset)
- return NULL;
- if(!neg_params_ok(zone, nc_rrset))
- return NULL;
- return nc_rrset;
-}
-
-/** neg cache nsec3 proof procedure*/
-static struct dns_msg*
-neg_nsec3_proof_ds(struct val_neg_zone* zone, uint8_t* qname, size_t qname_len,
- int qlabs, sldns_buffer* buf, struct rrset_cache* rrset_cache,
- struct regional* region, time_t now, uint8_t* topname)
-{
- struct dns_msg* msg;
- struct val_neg_data* data;
- uint8_t hashnc[NSEC3_SHA_LEN];
- size_t nclen;
- struct ub_packed_rrset_key* ce_rrset, *nc_rrset;
- struct nsec3_cached_hash c;
- uint8_t nc_b32[257];
-
- /* for NSEC3 ; determine the closest encloser for which we
- * can find an exact match. Remember the hashed lower name,
- * since that is the one we need a closest match for.
- * If we find a match straight away, then it becomes NODATA.
- * Otherwise, NXDOMAIN or if OPTOUT, an insecure delegation.
- * Also check that parameters are the same on closest encloser
- * and on closest match.
- */
- if(!zone->nsec3_hash)
- return NULL; /* not nsec3 zone */
-
- if(!(data=neg_find_nsec3_ce(zone, qname, qname_len, qlabs, buf,
- hashnc, &nclen))) {
- return NULL;
- }
-
- /* grab the ce rrset */
- ce_rrset = grab_nsec(rrset_cache, data->name, data->len,
- LDNS_RR_TYPE_NSEC3, zone->dclass, 0, region, 1,
- LDNS_RR_TYPE_DS, now);
- if(!ce_rrset)
- return NULL;
- if(!neg_params_ok(zone, ce_rrset))
- return NULL;
-
- if(nclen == 0) {
- /* exact match, just check the type bits */
- /* need: -SOA, -DS, +NS */
- if(nsec3_has_type(ce_rrset, 0, LDNS_RR_TYPE_SOA) ||
- nsec3_has_type(ce_rrset, 0, LDNS_RR_TYPE_DS) ||
- !nsec3_has_type(ce_rrset, 0, LDNS_RR_TYPE_NS))
- return NULL;
- if(!(msg = dns_msg_create(qname, qname_len,
- LDNS_RR_TYPE_DS, zone->dclass, region, 1)))
- return NULL;
- /* TTL reduced in grab_nsec */
- if(!dns_msg_authadd(msg, region, ce_rrset, 0))
- return NULL;
- return msg;
- }
-
- /* optout is not allowed without knowing the trust-anchor in use,
- * otherwise the optout could spoof away that anchor */
- if(!topname)
- return NULL;
-
- /* if there is no exact match, it must be in an optout span
- * (an existing DS implies an NSEC3 must exist) */
- nc_rrset = neg_nsec3_getnc(zone, hashnc, nclen, rrset_cache,
- region, now, nc_b32, sizeof(nc_b32));
- if(!nc_rrset)
- return NULL;
- if(!neg_params_ok(zone, nc_rrset))
- return NULL;
- if(!nsec3_has_optout(nc_rrset, 0))
- return NULL;
- c.hash = hashnc;
- c.hash_len = nclen;
- c.b32 = nc_b32+1;
- c.b32_len = (size_t)nc_b32[0];
- if(nsec3_covers(zone->name, &c, nc_rrset, 0, buf)) {
- /* nc_rrset covers the next closer name.
- * ce_rrset equals a closer encloser.
- * nc_rrset is optout.
- * No need to check wildcard for type DS */
- /* capacity=3: ce + nc + soa(if needed) */
- if(!(msg = dns_msg_create(qname, qname_len,
- LDNS_RR_TYPE_DS, zone->dclass, region, 3)))
- return NULL;
- /* now=0 because TTL was reduced in grab_nsec */
- if(!dns_msg_authadd(msg, region, ce_rrset, 0))
- return NULL;
- if(!dns_msg_authadd(msg, region, nc_rrset, 0))
- return NULL;
- return msg;
- }
- return NULL;
-}
-
-/**
- * Add SOA record for external responses.
- * @param rrset_cache: to look into.
- * @param now: current time.
- * @param region: where to perform the allocation
- * @param msg: current msg with NSEC.
- * @param zone: val_neg_zone if we have one.
- * @return false on lookup or alloc failure.
- */
-static int add_soa(struct rrset_cache* rrset_cache, time_t now,
- struct regional* region, struct dns_msg* msg, struct val_neg_zone* zone)
-{
- struct ub_packed_rrset_key* soa;
- uint8_t* nm;
- size_t nmlen;
- uint16_t dclass;
- if(zone) {
- nm = zone->name;
- nmlen = zone->len;
- dclass = zone->dclass;
- } else {
- /* Assumes the signer is the zone SOA to add */
- nm = reply_nsec_signer(msg->rep, &nmlen, &dclass);
- if(!nm)
- return 0;
- }
- soa = rrset_cache_lookup(rrset_cache, nm, nmlen, LDNS_RR_TYPE_SOA,
- dclass, PACKED_RRSET_SOA_NEG, now, 0);
- if(!soa)
- return 0;
- if(!dns_msg_authadd(msg, region, soa, now)) {
- lock_rw_unlock(&soa->entry.lock);
- return 0;
- }
- lock_rw_unlock(&soa->entry.lock);
- return 1;
-}
-
-struct dns_msg*
-val_neg_getmsg(struct val_neg_cache* neg, struct query_info* qinfo,
- struct regional* region, struct rrset_cache* rrset_cache,
- sldns_buffer* buf, time_t now, int addsoa, uint8_t* topname)
-{
- struct dns_msg* msg;
- struct ub_packed_rrset_key* rrset;
- uint8_t* zname;
- size_t zname_len;
- int zname_labs;
- struct val_neg_zone* zone;
-
- /* only for DS queries */
- if(qinfo->qtype != LDNS_RR_TYPE_DS)
- return NULL;
- log_assert(!topname || dname_subdomain_c(qinfo->qname, topname));
-
- /* see if info from neg cache is available
- * For NSECs, because there is no optout; a DS next to a delegation
- * always has exactly an NSEC for it itself; check its DS bit.
- * flags=0 (not the zone apex).
- */
- rrset = grab_nsec(rrset_cache, qinfo->qname, qinfo->qname_len,
- LDNS_RR_TYPE_NSEC, qinfo->qclass, 0, region, 1,
- qinfo->qtype, now);
- if(rrset) {
- /* return msg with that rrset */
- if(!(msg = dns_msg_create(qinfo->qname, qinfo->qname_len,
- qinfo->qtype, qinfo->qclass, region, 2)))
- return NULL;
- /* TTL already subtracted in grab_nsec */
- if(!dns_msg_authadd(msg, region, rrset, 0))
- return NULL;
- if(addsoa && !add_soa(rrset_cache, now, region, msg, NULL))
- return NULL;
- return msg;
- }
-
- /* check NSEC3 neg cache for type DS */
- /* need to look one zone higher for DS type */
- zname = qinfo->qname;
- zname_len = qinfo->qname_len;
- dname_remove_label(&zname, &zname_len);
- zname_labs = dname_count_labels(zname);
-
- /* lookup closest zone */
- lock_basic_lock(&neg->lock);
- zone = neg_closest_zone_parent(neg, zname, zname_len, zname_labs,
- qinfo->qclass);
- while(zone && !zone->in_use)
- zone = zone->parent;
- /* check that the zone is not too high up so that we do not pick data
- * out of a zone that is above the last-seen key (or trust-anchor). */
- if(zone && topname) {
- if(!dname_subdomain_c(zone->name, topname))
- zone = NULL;
- }
- if(!zone) {
- lock_basic_unlock(&neg->lock);
- return NULL;
- }
-
- msg = neg_nsec3_proof_ds(zone, qinfo->qname, qinfo->qname_len,
- zname_labs+1, buf, rrset_cache, region, now, topname);
- if(msg && addsoa && !add_soa(rrset_cache, now, region, msg, zone)) {
- lock_basic_unlock(&neg->lock);
- return NULL;
- }
- lock_basic_unlock(&neg->lock);
- return msg;
-}
diff --git a/external/unbound/validator/val_neg.h b/external/unbound/validator/val_neg.h
deleted file mode 100644
index 6ae71306c..000000000
--- a/external/unbound/validator/val_neg.h
+++ /dev/null
@@ -1,315 +0,0 @@
-/*
- * validator/val_neg.h - validator aggressive negative caching functions.
- *
- * Copyright (c) 2008, NLnet Labs. All rights reserved.
- *
- * This software is open source.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- *
- * Redistributions of source code must retain the above copyright notice,
- * this list of conditions and the following disclaimer.
- *
- * Redistributions in binary form must reproduce the above copyright notice,
- * this list of conditions and the following disclaimer in the documentation
- * and/or other materials provided with the distribution.
- *
- * Neither the name of the NLNET LABS nor the names of its contributors may
- * be used to endorse or promote products derived from this software without
- * specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
- * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
- * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
- * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
- * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
- * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-/**
- * \file
- *
- * This file contains helper functions for the validator module.
- * The functions help with aggressive negative caching.
- * This creates new denials of existence, and proofs for absence of types
- * from cached NSEC records.
- */
-
-#ifndef VALIDATOR_VAL_NEG_H
-#define VALIDATOR_VAL_NEG_H
-#include "util/locks.h"
-#include "util/rbtree.h"
-struct sldns_buffer;
-struct val_neg_data;
-struct config_file;
-struct reply_info;
-struct rrset_cache;
-struct regional;
-struct query_info;
-struct dns_msg;
-struct ub_packed_rrset_key;
-
-/**
- * The negative cache. It is shared between the threads, so locked.
- * Kept as validator-environ-state. It refers back to the rrset cache for
- * data elements. It can be out of date and contain conflicting data
- * from zone content changes.
- * It contains a tree of zones, every zone has a tree of data elements.
- * The data elements are part of one big LRU list, with one memory counter.
- */
-struct val_neg_cache {
- /** the big lock on the negative cache. Because we use a rbtree
- * for the data (quick lookup), we need a big lock */
- lock_basic_type lock;
- /** The zone rbtree. contents sorted canonical, type val_neg_zone */
- rbtree_type tree;
- /** the first in linked list of LRU of val_neg_data */
- struct val_neg_data* first;
- /** last in lru (least recently used element) */
- struct val_neg_data* last;
- /** current memory in use (bytes) */
- size_t use;
- /** max memory to use (bytes) */
- size_t max;
- /** max nsec3 iterations allowed */
- size_t nsec3_max_iter;
-};
-
-/**
- * Per Zone aggressive negative caching data.
- */
-struct val_neg_zone {
- /** rbtree node element, key is this struct: the name, class */
- rbnode_type node;
- /** name; the key */
- uint8_t* name;
- /** length of name */
- size_t len;
- /** labels in name */
- int labs;
-
- /** pointer to parent zone in the negative cache */
- struct val_neg_zone* parent;
-
- /** the number of elements, including this one and the ones whose
- * parents (-parents) include this one, that are in_use
- * No elements have a count of zero, those are removed. */
- int count;
-
- /** if 0: NSEC zone, else NSEC3 hash algorithm in use */
- int nsec3_hash;
- /** nsec3 iteration count in use */
- size_t nsec3_iter;
- /** nsec3 salt in use */
- uint8_t* nsec3_salt;
- /** length of salt in bytes */
- size_t nsec3_saltlen;
-
- /** tree of NSEC data for this zone, sorted canonical
- * by NSEC owner name */
- rbtree_type tree;
-
- /** class of node; host order */
- uint16_t dclass;
- /** if this element is in use, boolean */
- uint8_t in_use;
-};
-
-/**
- * Data element for aggressive negative caching.
- * The tree of these elements acts as an index onto the rrset cache.
- * It shows the NSEC records that (may) exist and are (possibly) secure.
- * The rbtree allows for logN search for a covering NSEC record.
- * To make tree insertion and deletion logN too, all the parent (one label
- * less than the name) data elements are also in the rbtree, with a usage
- * count for every data element.
- * There is no actual data stored in this data element, if it is in_use,
- * then the data can (possibly) be found in the rrset cache.
- */
-struct val_neg_data {
- /** rbtree node element, key is this struct: the name */
- rbnode_type node;
- /** name; the key */
- uint8_t* name;
- /** length of name */
- size_t len;
- /** labels in name */
- int labs;
-
- /** pointer to parent node in the negative cache */
- struct val_neg_data* parent;
-
- /** the number of elements, including this one and the ones whose
- * parents (-parents) include this one, that are in use
- * No elements have a count of zero, those are removed. */
- int count;
-
- /** the zone that this denial is part of */
- struct val_neg_zone* zone;
-
- /** previous in LRU */
- struct val_neg_data* prev;
- /** next in LRU (next element was less recently used) */
- struct val_neg_data* next;
-
- /** if this element is in use, boolean */
- uint8_t in_use;
-};
-
-/**
- * Create negative cache
- * @param cfg: config options.
- * @param maxiter: max nsec3 iterations allowed.
- * @return neg cache, empty or NULL on failure.
- */
-struct val_neg_cache* val_neg_create(struct config_file* cfg, size_t maxiter);
-
-/**
- * see how much memory is in use by the negative cache.
- * @param neg: negative cache
- * @return number of bytes in use.
- */
-size_t val_neg_get_mem(struct val_neg_cache* neg);
-
-/**
- * Destroy negative cache. There must no longer be any other threads.
- * @param neg: negative cache.
- */
-void neg_cache_delete(struct val_neg_cache* neg);
-
-/**
- * Comparison function for rbtree val neg data elements
- */
-int val_neg_data_compare(const void* a, const void* b);
-
-/**
- * Comparison function for rbtree val neg zone elements
- */
-int val_neg_zone_compare(const void* a, const void* b);
-
-/**
- * Insert NSECs from this message into the negative cache for reference.
- * @param neg: negative cache
- * @param rep: reply with NSECs.
- * Errors are ignored, means that storage is omitted.
- */
-void val_neg_addreply(struct val_neg_cache* neg, struct reply_info* rep);
-
-/**
- * Insert NSECs from this referral into the negative cache for reference.
- * @param neg: negative cache
- * @param rep: referral reply with NS, NSECs.
- * @param zone: bailiwick for the referral.
- * Errors are ignored, means that storage is omitted.
- */
-void val_neg_addreferral(struct val_neg_cache* neg, struct reply_info* rep,
- uint8_t* zone);
-
-/**
- * Perform a DLV style lookup
- * During the lookup, we could find out that data has expired. In that
- * case the neg_cache entries are removed, and lookup fails.
- *
- * @param neg: negative cache.
- * @param qname: name to look for
- * @param len: length of qname.
- * @param qclass: class to look in.
- * @param rrset_cache: the rrset cache, for NSEC lookups.
- * @param now: current time for ttl checks.
- * @return
- * 0 on error
- * 0 if no proof of negative
- * 1 if indeed negative was proven
- * thus, qname DLV qclass does not exist.
- */
-int val_neg_dlvlookup(struct val_neg_cache* neg, uint8_t* qname, size_t len,
- uint16_t qclass, struct rrset_cache* rrset_cache, time_t now);
-
-/**
- * For the given query, try to get a reply out of the negative cache.
- * The reply still needs to be validated.
- * @param neg: negative cache.
- * @param qinfo: query
- * @param region: where to allocate reply.
- * @param rrset_cache: rrset cache.
- * @param buf: temporary buffer.
- * @param now: to check TTLs against.
- * @param addsoa: if true, produce result for external consumption.
- * if false, do not add SOA - for unbound-internal consumption.
- * @param topname: do not look higher than this name,
- * so that the result cannot be taken from a zone above the current
- * trust anchor. Which could happen with multiple islands of trust.
- * if NULL, then no trust anchor is used, but also the algorithm becomes
- * more conservative, especially for opt-out zones, since the receiver
- * may have a trust-anchor below the optout and thus the optout cannot
- * be used to create a proof from the negative cache.
- * @return a reply message if something was found.
- * This reply may still need validation.
- * NULL if nothing found (or out of memory).
- */
-struct dns_msg* val_neg_getmsg(struct val_neg_cache* neg,
- struct query_info* qinfo, struct regional* region,
- struct rrset_cache* rrset_cache, struct sldns_buffer* buf, time_t now,
- int addsoa, uint8_t* topname);
-
-
-/**** functions exposed for unit test ****/
-/**
- * Insert data into the data tree of a zone
- * Does not do locking.
- * @param neg: negative cache
- * @param zone: zone to insert into
- * @param nsec: record to insert.
- */
-void neg_insert_data(struct val_neg_cache* neg,
- struct val_neg_zone* zone, struct ub_packed_rrset_key* nsec);
-
-/**
- * Delete a data element from the negative cache.
- * May delete other data elements to keep tree coherent, or
- * only mark the element as 'not in use'.
- * Does not do locking.
- * @param neg: negative cache.
- * @param el: data element to delete.
- */
-void neg_delete_data(struct val_neg_cache* neg, struct val_neg_data* el);
-
-/**
- * Find the given zone, from the SOA owner name and class
- * Does not do locking.
- * @param neg: negative cache
- * @param nm: what to look for.
- * @param len: length of nm
- * @param dclass: class to look for.
- * @return zone or NULL if not found.
- */
-struct val_neg_zone* neg_find_zone(struct val_neg_cache* neg,
- uint8_t* nm, size_t len, uint16_t dclass);
-
-/**
- * Create a new zone.
- * Does not do locking.
- * @param neg: negative cache
- * @param nm: what to look for.
- * @param nm_len: length of name.
- * @param dclass: class of zone, host order.
- * @return zone or NULL if out of memory.
- */
-struct val_neg_zone* neg_create_zone(struct val_neg_cache* neg,
- uint8_t* nm, size_t nm_len, uint16_t dclass);
-
-/**
- * take a zone into use. increases counts of parents.
- * Does not do locking.
- * @param zone: zone to take into use.
- */
-void val_neg_zone_take_inuse(struct val_neg_zone* zone);
-
-#endif /* VALIDATOR_VAL_NEG_H */
diff --git a/external/unbound/validator/val_nsec.c b/external/unbound/validator/val_nsec.c
deleted file mode 100644
index 1e4f440ff..000000000
--- a/external/unbound/validator/val_nsec.c
+++ /dev/null
@@ -1,624 +0,0 @@
-/*
- * validator/val_nsec.c - validator NSEC denial of existence functions.
- *
- * Copyright (c) 2007, NLnet Labs. All rights reserved.
- *
- * This software is open source.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- *
- * Redistributions of source code must retain the above copyright notice,
- * this list of conditions and the following disclaimer.
- *
- * Redistributions in binary form must reproduce the above copyright notice,
- * this list of conditions and the following disclaimer in the documentation
- * and/or other materials provided with the distribution.
- *
- * Neither the name of the NLNET LABS nor the names of its contributors may
- * be used to endorse or promote products derived from this software without
- * specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
- * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
- * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
- * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
- * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
- * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-/**
- * \file
- *
- * This file contains helper functions for the validator module.
- * The functions help with NSEC checking, the different NSEC proofs
- * for denial of existence, and proofs for presence of types.
- */
-#include "config.h"
-#include "validator/val_nsec.h"
-#include "validator/val_utils.h"
-#include "util/data/msgreply.h"
-#include "util/data/dname.h"
-#include "util/net_help.h"
-#include "util/module.h"
-#include "services/cache/rrset.h"
-
-/** get ttl of rrset */
-static uint32_t
-rrset_get_ttl(struct ub_packed_rrset_key* k)
-{
- struct packed_rrset_data* d = (struct packed_rrset_data*)k->entry.data;
- return d->ttl;
-}
-
-int
-nsecbitmap_has_type_rdata(uint8_t* bitmap, size_t len, uint16_t type)
-{
- /* Check type present in NSEC typemap with bitmap arg */
- /* bitmasks for determining type-lowerbits presence */
- uint8_t masks[8] = {0x80, 0x40, 0x20, 0x10, 0x08, 0x04, 0x02, 0x01};
- uint8_t type_window = type>>8;
- uint8_t type_low = type&0xff;
- uint8_t win, winlen;
- /* read each of the type bitmap windows and see if the searched
- * type is amongst it */
- while(len > 0) {
- if(len < 3) /* bad window, at least window# winlen bitmap */
- return 0;
- win = *bitmap++;
- winlen = *bitmap++;
- len -= 2;
- if(len < winlen || winlen < 1 || winlen > 32)
- return 0; /* bad window length */
- if(win == type_window) {
- /* search window bitmap for the correct byte */
- /* mybyte is 0 if we need the first byte */
- size_t mybyte = type_low>>3;
- if(winlen <= mybyte)
- return 0; /* window too short */
- return (int)(bitmap[mybyte] & masks[type_low&0x7]);
- } else {
- /* not the window we are looking for */
- bitmap += winlen;
- len -= winlen;
- }
- }
- /* end of bitmap reached, no type found */
- return 0;
-}
-
-int
-nsec_has_type(struct ub_packed_rrset_key* nsec, uint16_t type)
-{
- struct packed_rrset_data* d = (struct packed_rrset_data*)nsec->
- entry.data;
- size_t len;
- if(!d || d->count == 0 || d->rr_len[0] < 2+1)
- return 0;
- len = dname_valid(d->rr_data[0]+2, d->rr_len[0]-2);
- if(!len)
- return 0;
- return nsecbitmap_has_type_rdata(d->rr_data[0]+2+len,
- d->rr_len[0]-2-len, type);
-}
-
-/**
- * Get next owner name from nsec record
- * @param nsec: the nsec RRset.
- * If there are multiple RRs, then this will only return one of them.
- * @param nm: the next name is returned.
- * @param ln: length of nm is returned.
- * @return false on a bad NSEC RR (too short, malformed dname).
- */
-static int
-nsec_get_next(struct ub_packed_rrset_key* nsec, uint8_t** nm, size_t* ln)
-{
- struct packed_rrset_data* d = (struct packed_rrset_data*)nsec->
- entry.data;
- if(!d || d->count == 0 || d->rr_len[0] < 2+1) {
- *nm = 0;
- *ln = 0;
- return 0;
- }
- *nm = d->rr_data[0]+2;
- *ln = dname_valid(*nm, d->rr_len[0]-2);
- if(!*ln) {
- *nm = 0;
- *ln = 0;
- return 0;
- }
- return 1;
-}
-
-/**
- * For an NSEC that matches the DS queried for, check absence of DS type.
- *
- * @param nsec: NSEC for proof, must be trusted.
- * @param qinfo: what is queried for.
- * @return if secure the nsec proves that no DS is present, or
- * insecure if it proves it is not a delegation point.
- * or bogus if something was wrong.
- */
-static enum sec_status
-val_nsec_proves_no_ds(struct ub_packed_rrset_key* nsec,
- struct query_info* qinfo)
-{
- log_assert(qinfo->qtype == LDNS_RR_TYPE_DS);
- log_assert(ntohs(nsec->rk.type) == LDNS_RR_TYPE_NSEC);
-
- if(nsec_has_type(nsec, LDNS_RR_TYPE_SOA) && qinfo->qname_len != 1) {
- /* SOA present means that this is the NSEC from the child,
- * not the parent (so it is the wrong one). */
- return sec_status_bogus;
- }
- if(nsec_has_type(nsec, LDNS_RR_TYPE_DS)) {
- /* DS present means that there should have been a positive
- * response to the DS query, so there is something wrong. */
- return sec_status_bogus;
- }
-
- if(!nsec_has_type(nsec, LDNS_RR_TYPE_NS)) {
- /* If there is no NS at this point at all, then this
- * doesn't prove anything one way or the other. */
- return sec_status_insecure;
- }
- /* Otherwise, this proves no DS. */
- return sec_status_secure;
-}
-
-/** check security status from cache or verify rrset, returns true if secure */
-static int
-nsec_verify_rrset(struct module_env* env, struct val_env* ve,
- struct ub_packed_rrset_key* nsec, struct key_entry_key* kkey,
- char** reason)
-{
- struct packed_rrset_data* d = (struct packed_rrset_data*)
- nsec->entry.data;
- if(d->security == sec_status_secure)
- return 1;
- rrset_check_sec_status(env->rrset_cache, nsec, *env->now);
- if(d->security == sec_status_secure)
- return 1;
- d->security = val_verify_rrset_entry(env, ve, nsec, kkey, reason);
- if(d->security == sec_status_secure) {
- rrset_update_sec_status(env->rrset_cache, nsec, *env->now);
- return 1;
- }
- return 0;
-}
-
-enum sec_status
-val_nsec_prove_nodata_dsreply(struct module_env* env, struct val_env* ve,
- struct query_info* qinfo, struct reply_info* rep,
- struct key_entry_key* kkey, time_t* proof_ttl, char** reason)
-{
- struct ub_packed_rrset_key* nsec = reply_find_rrset_section_ns(
- rep, qinfo->qname, qinfo->qname_len, LDNS_RR_TYPE_NSEC,
- qinfo->qclass);
- enum sec_status sec;
- size_t i;
- uint8_t* wc = NULL, *ce = NULL;
- int valid_nsec = 0;
- struct ub_packed_rrset_key* wc_nsec = NULL;
-
- /* If we have a NSEC at the same name, it must prove one
- * of two things
- * --
- * 1) this is a delegation point and there is no DS
- * 2) this is not a delegation point */
- if(nsec) {
- if(!nsec_verify_rrset(env, ve, nsec, kkey, reason)) {
- verbose(VERB_ALGO, "NSEC RRset for the "
- "referral did not verify.");
- return sec_status_bogus;
- }
- sec = val_nsec_proves_no_ds(nsec, qinfo);
- if(sec == sec_status_bogus) {
- /* something was wrong. */
- *reason = "NSEC does not prove absence of DS";
- return sec;
- } else if(sec == sec_status_insecure) {
- /* this wasn't a delegation point. */
- return sec;
- } else if(sec == sec_status_secure) {
- /* this proved no DS. */
- *proof_ttl = ub_packed_rrset_ttl(nsec);
- return sec;
- }
- /* if unchecked, fall through to next proof */
- }
-
- /* Otherwise, there is no NSEC at qname. This could be an ENT.
- * (ENT=empty non terminal). If not, this is broken. */
-
- /* verify NSEC rrsets in auth section */
- for(i=rep->an_numrrsets; i < rep->an_numrrsets+rep->ns_numrrsets;
- i++) {
- if(rep->rrsets[i]->rk.type != htons(LDNS_RR_TYPE_NSEC))
- continue;
- if(!nsec_verify_rrset(env, ve, rep->rrsets[i], kkey, reason)) {
- verbose(VERB_ALGO, "NSEC for empty non-terminal "
- "did not verify.");
- return sec_status_bogus;
- }
- if(nsec_proves_nodata(rep->rrsets[i], qinfo, &wc)) {
- verbose(VERB_ALGO, "NSEC for empty non-terminal "
- "proved no DS.");
- *proof_ttl = rrset_get_ttl(rep->rrsets[i]);
- if(wc && dname_is_wild(rep->rrsets[i]->rk.dname))
- wc_nsec = rep->rrsets[i];
- valid_nsec = 1;
- }
- if(val_nsec_proves_name_error(rep->rrsets[i], qinfo->qname)) {
- ce = nsec_closest_encloser(qinfo->qname,
- rep->rrsets[i]);
- }
- }
- if(wc && !ce)
- valid_nsec = 0;
- else if(wc && ce) {
- /* ce and wc must match */
- if(query_dname_compare(wc, ce) != 0)
- valid_nsec = 0;
- else if(!wc_nsec)
- valid_nsec = 0;
- }
- if(valid_nsec) {
- if(wc) {
- /* check if this is a delegation */
- *reason = "NSEC for wildcard does not prove absence of DS";
- return val_nsec_proves_no_ds(wc_nsec, qinfo);
- }
- /* valid nsec proves empty nonterminal */
- return sec_status_insecure;
- }
-
- /* NSEC proof did not conclusively point to DS or no DS */
- return sec_status_unchecked;
-}
-
-int nsec_proves_nodata(struct ub_packed_rrset_key* nsec,
- struct query_info* qinfo, uint8_t** wc)
-{
- log_assert(wc);
- if(query_dname_compare(nsec->rk.dname, qinfo->qname) != 0) {
- uint8_t* nm;
- size_t ln;
-
- /* empty-non-terminal checking.
- * Done before wildcard, because this is an exact match,
- * and would prevent a wildcard from matching. */
-
- /* If the nsec is proving that qname is an ENT, the nsec owner
- * will be less than qname, and the next name will be a child
- * domain of the qname. */
- if(!nsec_get_next(nsec, &nm, &ln))
- return 0; /* bad nsec */
- if(dname_strict_subdomain_c(nm, qinfo->qname) &&
- dname_canonical_compare(nsec->rk.dname,
- qinfo->qname) < 0) {
- return 1; /* proves ENT */
- }
-
- /* wildcard checking. */
-
- /* If this is a wildcard NSEC, make sure that a) it was
- * possible to have generated qname from the wildcard and
- * b) the type map does not contain qtype. Note that this
- * does NOT prove that this wildcard was the applicable
- * wildcard. */
- if(dname_is_wild(nsec->rk.dname)) {
- /* the purported closest encloser. */
- uint8_t* ce = nsec->rk.dname;
- size_t ce_len = nsec->rk.dname_len;
- dname_remove_label(&ce, &ce_len);
-
- /* The qname must be a strict subdomain of the
- * closest encloser, for the wildcard to apply
- */
- if(dname_strict_subdomain_c(qinfo->qname, ce)) {
- /* here we have a matching NSEC for the qname,
- * perform matching NSEC checks */
- if(nsec_has_type(nsec, LDNS_RR_TYPE_CNAME)) {
- /* should have gotten the wildcard CNAME */
- return 0;
- }
- if(nsec_has_type(nsec, LDNS_RR_TYPE_NS) &&
- !nsec_has_type(nsec, LDNS_RR_TYPE_SOA)) {
- /* wrong parentside (wildcard) NSEC used */
- return 0;
- }
- if(nsec_has_type(nsec, qinfo->qtype)) {
- return 0;
- }
- *wc = ce;
- return 1;
- }
- } else {
- /* See if the next owner name covers a wildcard
- * empty non-terminal. */
- while (dname_canonical_compare(nsec->rk.dname, nm) < 0) {
- /* wildcard does not apply if qname below
- * the name that exists under the '*' */
- if (dname_subdomain_c(qinfo->qname, nm))
- break;
- /* but if it is a wildcard and qname is below
- * it, then the wildcard applies. The wildcard
- * is an empty nonterminal. nodata proven. */
- if (dname_is_wild(nm)) {
- size_t ce_len = ln;
- uint8_t* ce = nm;
- dname_remove_label(&ce, &ce_len);
- if(dname_strict_subdomain_c(qinfo->qname, ce)) {
- *wc = ce;
- return 1;
- }
- }
- dname_remove_label(&nm, &ln);
- }
- }
-
- /* Otherwise, this NSEC does not prove ENT and is not a
- * wildcard, so it does not prove NODATA. */
- return 0;
- }
-
- /* If the qtype exists, then we should have gotten it. */
- if(nsec_has_type(nsec, qinfo->qtype)) {
- return 0;
- }
-
- /* if the name is a CNAME node, then we should have gotten the CNAME*/
- if(nsec_has_type(nsec, LDNS_RR_TYPE_CNAME)) {
- return 0;
- }
-
- /* If an NS set exists at this name, and NOT a SOA (so this is a
- * zone cut, not a zone apex), then we should have gotten a
- * referral (or we just got the wrong NSEC).
- * The reverse of this check is used when qtype is DS, since that
- * must use the NSEC from above the zone cut. */
- if(qinfo->qtype != LDNS_RR_TYPE_DS &&
- nsec_has_type(nsec, LDNS_RR_TYPE_NS) &&
- !nsec_has_type(nsec, LDNS_RR_TYPE_SOA)) {
- return 0;
- } else if(qinfo->qtype == LDNS_RR_TYPE_DS &&
- nsec_has_type(nsec, LDNS_RR_TYPE_SOA) &&
- !dname_is_root(qinfo->qname)) {
- return 0;
- }
-
- return 1;
-}
-
-int
-val_nsec_proves_name_error(struct ub_packed_rrset_key* nsec, uint8_t* qname)
-{
- uint8_t* owner = nsec->rk.dname;
- uint8_t* next;
- size_t nlen;
- if(!nsec_get_next(nsec, &next, &nlen))
- return 0;
-
- /* If NSEC owner == qname, then this NSEC proves that qname exists. */
- if(query_dname_compare(qname, owner) == 0) {
- return 0;
- }
-
- /* If NSEC is a parent of qname, we need to check the type map
- * If the parent name has a DNAME or is a delegation point, then
- * this NSEC is being misused. */
- if(dname_subdomain_c(qname, owner) &&
- (nsec_has_type(nsec, LDNS_RR_TYPE_DNAME) ||
- (nsec_has_type(nsec, LDNS_RR_TYPE_NS)
- && !nsec_has_type(nsec, LDNS_RR_TYPE_SOA))
- )) {
- return 0;
- }
-
- if(query_dname_compare(owner, next) == 0) {
- /* this nsec is the only nsec */
- /* zone.name NSEC zone.name, disproves everything else */
- /* but only for subdomains of that zone */
- if(dname_strict_subdomain_c(qname, next))
- return 1;
- }
- else if(dname_canonical_compare(owner, next) > 0) {
- /* this is the last nsec, ....(bigger) NSEC zonename(smaller) */
- /* the names after the last (owner) name do not exist
- * there are no names before the zone name in the zone
- * but the qname must be a subdomain of the zone name(next). */
- if(dname_canonical_compare(owner, qname) < 0 &&
- dname_strict_subdomain_c(qname, next))
- return 1;
- } else {
- /* regular NSEC, (smaller) NSEC (larger) */
- if(dname_canonical_compare(owner, qname) < 0 &&
- dname_canonical_compare(qname, next) < 0) {
- return 1;
- }
- }
- return 0;
-}
-
-int val_nsec_proves_insecuredelegation(struct ub_packed_rrset_key* nsec,
- struct query_info* qinfo)
-{
- if(nsec_has_type(nsec, LDNS_RR_TYPE_NS) &&
- !nsec_has_type(nsec, LDNS_RR_TYPE_DS) &&
- !nsec_has_type(nsec, LDNS_RR_TYPE_SOA)) {
- /* see if nsec signals an insecure delegation */
- if(qinfo->qtype == LDNS_RR_TYPE_DS) {
- /* if type is DS and qname is equal to nsec, then it
- * is an exact match nsec, result not insecure */
- if(dname_strict_subdomain_c(qinfo->qname,
- nsec->rk.dname))
- return 1;
- } else {
- if(dname_subdomain_c(qinfo->qname, nsec->rk.dname))
- return 1;
- }
- }
- return 0;
-}
-
-uint8_t*
-nsec_closest_encloser(uint8_t* qname, struct ub_packed_rrset_key* nsec)
-{
- uint8_t* next;
- size_t nlen;
- uint8_t* common1, *common2;
- if(!nsec_get_next(nsec, &next, &nlen))
- return NULL;
- /* longest common with owner or next name */
- common1 = dname_get_shared_topdomain(nsec->rk.dname, qname);
- common2 = dname_get_shared_topdomain(next, qname);
- if(dname_count_labels(common1) > dname_count_labels(common2))
- return common1;
- return common2;
-}
-
-int val_nsec_proves_positive_wildcard(struct ub_packed_rrset_key* nsec,
- struct query_info* qinf, uint8_t* wc)
-{
- uint8_t* ce;
- /* 1) prove that qname doesn't exist and
- * 2) that the correct wildcard was used
- * nsec has been verified already. */
- if(!val_nsec_proves_name_error(nsec, qinf->qname))
- return 0;
- /* check wildcard name */
- ce = nsec_closest_encloser(qinf->qname, nsec);
- if(!ce)
- return 0;
- if(query_dname_compare(wc, ce) != 0) {
- return 0;
- }
- return 1;
-}
-
-int
-val_nsec_proves_no_wc(struct ub_packed_rrset_key* nsec, uint8_t* qname,
- size_t qnamelen)
-{
- /* Determine if a NSEC record proves the non-existence of a
- * wildcard that could have produced qname. */
- int labs;
- int i;
- uint8_t* ce = nsec_closest_encloser(qname, nsec);
- uint8_t* strip;
- size_t striplen;
- uint8_t buf[LDNS_MAX_DOMAINLEN+3];
- if(!ce)
- return 0;
- /* we can subtract the closest encloser count - since that is the
- * largest shared topdomain with owner and next NSEC name,
- * because the NSEC is no proof for names shorter than the owner
- * and next names. */
- labs = dname_count_labels(qname) - dname_count_labels(ce);
-
- for(i=labs; i>0; i--) {
- /* i is number of labels to strip off qname, prepend * wild */
- strip = qname;
- striplen = qnamelen;
- dname_remove_labels(&strip, &striplen, i);
- if(striplen > LDNS_MAX_DOMAINLEN-2)
- continue; /* too long to prepend wildcard */
- buf[0] = 1;
- buf[1] = (uint8_t)'*';
- memmove(buf+2, strip, striplen);
- if(val_nsec_proves_name_error(nsec, buf)) {
- return 1;
- }
- }
- return 0;
-}
-
-/**
- * Find shared topdomain that exists
- */
-static void
-dlv_topdomain(struct ub_packed_rrset_key* nsec, uint8_t* qname,
- uint8_t** nm, size_t* nm_len)
-{
- /* make sure reply is part of nm */
- /* take shared topdomain with left of NSEC. */
-
- /* because, if empty nonterminal, then right is subdomain of qname.
- * and any shared topdomain would be empty nonterminals.
- *
- * If nxdomain, then the right is bigger, and could have an
- * interesting shared topdomain, but if it does have one, it is
- * an empty nonterminal. An empty nonterminal shared with the left
- * one. */
- int n;
- uint8_t* common = dname_get_shared_topdomain(qname, nsec->rk.dname);
- n = dname_count_labels(*nm) - dname_count_labels(common);
- dname_remove_labels(nm, nm_len, n);
-}
-
-int val_nsec_check_dlv(struct query_info* qinfo,
- struct reply_info* rep, uint8_t** nm, size_t* nm_len)
-{
- uint8_t* next;
- size_t i, nlen;
- int c;
- /* we should now have a NOERROR/NODATA or NXDOMAIN message */
- if(rep->an_numrrsets != 0) {
- return 0;
- }
- /* is this NOERROR ? */
- if(FLAGS_GET_RCODE(rep->flags) == LDNS_RCODE_NOERROR) {
- /* it can be a plain NSEC match - go up one more level. */
- /* or its an empty nonterminal - go up to nonempty level */
- for(i=0; i<rep->ns_numrrsets; i++) {
- if(htons(rep->rrsets[i]->rk.type)!=LDNS_RR_TYPE_NSEC ||
- !nsec_get_next(rep->rrsets[i], &next, &nlen))
- continue;
- c = dname_canonical_compare(
- rep->rrsets[i]->rk.dname, qinfo->qname);
- if(c == 0) {
- /* plain match */
- if(nsec_has_type(rep->rrsets[i],
- LDNS_RR_TYPE_DLV))
- return 0;
- dname_remove_label(nm, nm_len);
- return 1;
- } else if(c < 0 &&
- dname_strict_subdomain_c(next, qinfo->qname)) {
- /* ENT */
- dlv_topdomain(rep->rrsets[i], qinfo->qname,
- nm, nm_len);
- return 1;
- }
- }
- return 0;
- }
-
- /* is this NXDOMAIN ? */
- if(FLAGS_GET_RCODE(rep->flags) == LDNS_RCODE_NXDOMAIN) {
- /* find the qname denial NSEC record. It can tell us
- * a closest encloser name; or that we not need bother */
- for(i=0; i<rep->ns_numrrsets; i++) {
- if(htons(rep->rrsets[i]->rk.type) != LDNS_RR_TYPE_NSEC)
- continue;
- if(val_nsec_proves_name_error(rep->rrsets[i],
- qinfo->qname)) {
- log_nametypeclass(VERB_ALGO, "topdomain on",
- rep->rrsets[i]->rk.dname,
- ntohs(rep->rrsets[i]->rk.type), 0);
- dlv_topdomain(rep->rrsets[i], qinfo->qname,
- nm, nm_len);
- return 1;
- }
- }
- return 0;
- }
- return 0;
-}
diff --git a/external/unbound/validator/val_nsec.h b/external/unbound/validator/val_nsec.h
deleted file mode 100644
index c031c9a3b..000000000
--- a/external/unbound/validator/val_nsec.h
+++ /dev/null
@@ -1,182 +0,0 @@
-/*
- * validator/val_nsec.h - validator NSEC denial of existence functions.
- *
- * Copyright (c) 2007, NLnet Labs. All rights reserved.
- *
- * This software is open source.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- *
- * Redistributions of source code must retain the above copyright notice,
- * this list of conditions and the following disclaimer.
- *
- * Redistributions in binary form must reproduce the above copyright notice,
- * this list of conditions and the following disclaimer in the documentation
- * and/or other materials provided with the distribution.
- *
- * Neither the name of the NLNET LABS nor the names of its contributors may
- * be used to endorse or promote products derived from this software without
- * specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
- * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
- * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
- * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
- * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
- * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-/**
- * \file
- *
- * This file contains helper functions for the validator module.
- * The functions help with NSEC checking, the different NSEC proofs
- * for denial of existence, and proofs for presence of types.
- */
-
-#ifndef VALIDATOR_VAL_NSEC_H
-#define VALIDATOR_VAL_NSEC_H
-#include "util/data/packed_rrset.h"
-struct val_env;
-struct module_env;
-struct ub_packed_rrset_key;
-struct reply_info;
-struct query_info;
-struct key_entry_key;
-
-/**
- * Check DS absence.
- * There is a NODATA reply to a DS that needs checking.
- * NSECs can prove this is not a delegation point, or successfully prove
- * that there is no DS. Or this fails.
- *
- * @param env: module env for rrsig verification routines.
- * @param ve: validator env for rrsig verification routines.
- * @param qinfo: the DS queried for.
- * @param rep: reply received.
- * @param kkey: key entry to use for verification of signatures.
- * @param proof_ttl: if secure, the TTL of how long this proof lasts.
- * @param reason: string explaining why bogus.
- * @return security status.
- * SECURE: proved absence of DS.
- * INSECURE: proved that this was not a delegation point.
- * BOGUS: crypto bad, or no absence of DS proven.
- * UNCHECKED: there was no way to prove anything (no NSECs, unknown algo).
- */
-enum sec_status val_nsec_prove_nodata_dsreply(struct module_env* env,
- struct val_env* ve, struct query_info* qinfo,
- struct reply_info* rep, struct key_entry_key* kkey,
- time_t* proof_ttl, char** reason);
-
-/**
- * nsec typemap check, takes an NSEC-type bitmap as argument, checks for type.
- * @param bitmap: pointer to the bitmap part of wireformat rdata.
- * @param len: length of the bitmap, in bytes.
- * @param type: the type (in host order) to check for.
- * @return true if the type bit was set in the bitmap. false if not, or
- * if the bitmap was malformed in some way.
- */
-int nsecbitmap_has_type_rdata(uint8_t* bitmap, size_t len, uint16_t type);
-
-/**
- * Check if type is present in the NSEC typemap
- * @param nsec: the nsec RRset.
- * If there are multiple RRs, then each must have the same typemap,
- * since the typemap represents the types at this domain node.
- * @param type: type to check for, host order.
- * @return true if present
- */
-int nsec_has_type(struct ub_packed_rrset_key* nsec, uint16_t type);
-
-/**
- * Determine if a NSEC proves the NOERROR/NODATA conditions. This will also
- * handle the empty non-terminal (ENT) case and partially handle the
- * wildcard case. If the ownername of 'nsec' is a wildcard, the validator
- * must still be provided proof that qname did not directly exist and that
- * the wildcard is, in fact, *.closest_encloser.
- *
- * @param nsec: the nsec record to check against.
- * @param qinfo: the query info.
- * @param wc: if the nodata is proven for a wildcard match, the wildcard
- * closest encloser is returned, else NULL (wc is unchanged).
- * This closest encloser must then match the nameerror given for the
- * nextcloser of qname.
- * @return true if NSEC proves this.
- */
-int nsec_proves_nodata(struct ub_packed_rrset_key* nsec,
- struct query_info* qinfo, uint8_t** wc);
-
-/**
- * Determine if the given NSEC proves a NameError (NXDOMAIN) for a given
- * qname.
- *
- * @param nsec: the nsec to check
- * @param qname: what was queried.
- * @return true if proven.
- */
-int val_nsec_proves_name_error(struct ub_packed_rrset_key* nsec,
- uint8_t* qname);
-
-/**
- * Determine if the given NSEC proves a positive wildcard response.
- * @param nsec: the nsec to check
- * @param qinf: what was queried.
- * @param wc: wildcard (without *. label)
- * @return true if proven.
- */
-int val_nsec_proves_positive_wildcard(struct ub_packed_rrset_key* nsec,
- struct query_info* qinf, uint8_t* wc);
-
-/**
- * Determine closest encloser of a query name and the NSEC that covers it
- * (and thus disproved it).
- * A name error must have been proven already, otherwise this will be invalid.
- * @param qname: the name queried for.
- * @param nsec: the nsec RRset.
- * @return closest encloser dname or NULL on error (bad nsec RRset).
- */
-uint8_t* nsec_closest_encloser(uint8_t* qname,
- struct ub_packed_rrset_key* nsec);
-
-/**
- * Determine if the given NSEC proves that a wildcard match does not exist.
- *
- * @param nsec: the nsec RRset.
- * @param qname: the name queried for.
- * @param qnamelen: length of qname.
- * @return true if proven.
- */
-int val_nsec_proves_no_wc(struct ub_packed_rrset_key* nsec, uint8_t* qname,
- size_t qnamelen);
-
-/**
- * Determine the DLV result, what to do with NSEC DLV reply.
- * @param qinfo: what was queried for.
- * @param rep: the nonpositive reply.
- * @param nm: dlv lookup name, to adjust for new lookup name (if needed).
- * @param nm_len: length of lookup name.
- * @return 0 on error, 1 if a higher point is found.
- * If the higher point is above the dlv repo anchor, the qname does
- * not exist.
- */
-int val_nsec_check_dlv(struct query_info* qinfo,
- struct reply_info* rep, uint8_t** nm, size_t* nm_len);
-
-/**
- * Determine if an nsec proves an insecure delegation towards the qname.
- * @param nsec: nsec rrset.
- * @param qinfo: what was queries for.
- * @return 0 if not, 1 if an NSEC that signals an insecure delegation to
- * the qname.
- */
-int val_nsec_proves_insecuredelegation(struct ub_packed_rrset_key* nsec,
- struct query_info* qinfo);
-
-#endif /* VALIDATOR_VAL_NSEC_H */
diff --git a/external/unbound/validator/val_nsec3.c b/external/unbound/validator/val_nsec3.c
deleted file mode 100644
index 4d978372a..000000000
--- a/external/unbound/validator/val_nsec3.c
+++ /dev/null
@@ -1,1434 +0,0 @@
-/*
- * validator/val_nsec3.c - validator NSEC3 denial of existence functions.
- *
- * Copyright (c) 2007, NLnet Labs. All rights reserved.
- *
- * This software is open source.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- *
- * Redistributions of source code must retain the above copyright notice,
- * this list of conditions and the following disclaimer.
- *
- * Redistributions in binary form must reproduce the above copyright notice,
- * this list of conditions and the following disclaimer in the documentation
- * and/or other materials provided with the distribution.
- *
- * Neither the name of the NLNET LABS nor the names of its contributors may
- * be used to endorse or promote products derived from this software without
- * specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
- * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
- * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
- * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
- * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
- * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-/**
- * \file
- *
- * This file contains helper functions for the validator module.
- * The functions help with NSEC3 checking, the different NSEC3 proofs
- * for denial of existence, and proofs for presence of types.
- */
-#include "config.h"
-#include <ctype.h>
-#include "validator/val_nsec3.h"
-#include "validator/val_secalgo.h"
-#include "validator/validator.h"
-#include "validator/val_kentry.h"
-#include "services/cache/rrset.h"
-#include "util/regional.h"
-#include "util/rbtree.h"
-#include "util/module.h"
-#include "util/net_help.h"
-#include "util/data/packed_rrset.h"
-#include "util/data/dname.h"
-#include "util/data/msgreply.h"
-/* we include nsec.h for the bitmap_has_type function */
-#include "validator/val_nsec.h"
-#include "sldns/sbuffer.h"
-
-/**
- * This function we get from ldns-compat or from base system
- * it returns the number of data bytes stored at the target, or <0 on error.
- */
-int sldns_b32_ntop_extended_hex(uint8_t const *src, size_t srclength,
- char *target, size_t targsize);
-/**
- * This function we get from ldns-compat or from base system
- * it returns the number of data bytes stored at the target, or <0 on error.
- */
-int sldns_b32_pton_extended_hex(char const *src, size_t hashed_owner_str_len,
- uint8_t *target, size_t targsize);
-
-/**
- * Closest encloser (ce) proof results
- * Contains the ce and the next-closer (nc) proof.
- */
-struct ce_response {
- /** the closest encloser name */
- uint8_t* ce;
- /** length of ce */
- size_t ce_len;
- /** NSEC3 record that proved ce. rrset */
- struct ub_packed_rrset_key* ce_rrset;
- /** NSEC3 record that proved ce. rr number */
- int ce_rr;
- /** NSEC3 record that proved nc. rrset */
- struct ub_packed_rrset_key* nc_rrset;
- /** NSEC3 record that proved nc. rr*/
- int nc_rr;
-};
-
-/**
- * Filter conditions for NSEC3 proof
- * Used to iterate over the applicable NSEC3 RRs.
- */
-struct nsec3_filter {
- /** Zone name, only NSEC3 records for this zone are considered */
- uint8_t* zone;
- /** length of the zonename */
- size_t zone_len;
- /** the list of NSEC3s to filter; array */
- struct ub_packed_rrset_key** list;
- /** number of rrsets in list */
- size_t num;
- /** class of records for the NSEC3, only this class applies */
- uint16_t fclass;
-};
-
-/** return number of rrs in an rrset */
-static size_t
-rrset_get_count(struct ub_packed_rrset_key* rrset)
-{
- struct packed_rrset_data* d = (struct packed_rrset_data*)
- rrset->entry.data;
- if(!d) return 0;
- return d->count;
-}
-
-/** return if nsec3 RR has unknown flags */
-static int
-nsec3_unknown_flags(struct ub_packed_rrset_key* rrset, int r)
-{
- struct packed_rrset_data* d = (struct packed_rrset_data*)
- rrset->entry.data;
- log_assert(d && r < (int)d->count);
- if(d->rr_len[r] < 2+2)
- return 0; /* malformed */
- return (int)(d->rr_data[r][2+1] & NSEC3_UNKNOWN_FLAGS);
-}
-
-int
-nsec3_has_optout(struct ub_packed_rrset_key* rrset, int r)
-{
- struct packed_rrset_data* d = (struct packed_rrset_data*)
- rrset->entry.data;
- log_assert(d && r < (int)d->count);
- if(d->rr_len[r] < 2+2)
- return 0; /* malformed */
- return (int)(d->rr_data[r][2+1] & NSEC3_OPTOUT);
-}
-
-/** return nsec3 RR algorithm */
-static int
-nsec3_get_algo(struct ub_packed_rrset_key* rrset, int r)
-{
- struct packed_rrset_data* d = (struct packed_rrset_data*)
- rrset->entry.data;
- log_assert(d && r < (int)d->count);
- if(d->rr_len[r] < 2+1)
- return 0; /* malformed */
- return (int)(d->rr_data[r][2+0]);
-}
-
-/** return if nsec3 RR has known algorithm */
-static int
-nsec3_known_algo(struct ub_packed_rrset_key* rrset, int r)
-{
- struct packed_rrset_data* d = (struct packed_rrset_data*)
- rrset->entry.data;
- log_assert(d && r < (int)d->count);
- if(d->rr_len[r] < 2+1)
- return 0; /* malformed */
- switch(d->rr_data[r][2+0]) {
- case NSEC3_HASH_SHA1:
- return 1;
- }
- return 0;
-}
-
-/** return nsec3 RR iteration count */
-static size_t
-nsec3_get_iter(struct ub_packed_rrset_key* rrset, int r)
-{
- uint16_t i;
- struct packed_rrset_data* d = (struct packed_rrset_data*)
- rrset->entry.data;
- log_assert(d && r < (int)d->count);
- if(d->rr_len[r] < 2+4)
- return 0; /* malformed */
- memmove(&i, d->rr_data[r]+2+2, sizeof(i));
- i = ntohs(i);
- return (size_t)i;
-}
-
-/** return nsec3 RR salt */
-static int
-nsec3_get_salt(struct ub_packed_rrset_key* rrset, int r,
- uint8_t** salt, size_t* saltlen)
-{
- struct packed_rrset_data* d = (struct packed_rrset_data*)
- rrset->entry.data;
- log_assert(d && r < (int)d->count);
- if(d->rr_len[r] < 2+5) {
- *salt = 0;
- *saltlen = 0;
- return 0; /* malformed */
- }
- *saltlen = (size_t)d->rr_data[r][2+4];
- if(d->rr_len[r] < 2+5+(size_t)*saltlen) {
- *salt = 0;
- *saltlen = 0;
- return 0; /* malformed */
- }
- *salt = d->rr_data[r]+2+5;
- return 1;
-}
-
-int nsec3_get_params(struct ub_packed_rrset_key* rrset, int r,
- int* algo, size_t* iter, uint8_t** salt, size_t* saltlen)
-{
- if(!nsec3_known_algo(rrset, r) || nsec3_unknown_flags(rrset, r))
- return 0;
- if(!nsec3_get_salt(rrset, r, salt, saltlen))
- return 0;
- *algo = nsec3_get_algo(rrset, r);
- *iter = nsec3_get_iter(rrset, r);
- return 1;
-}
-
-int
-nsec3_get_nextowner(struct ub_packed_rrset_key* rrset, int r,
- uint8_t** next, size_t* nextlen)
-{
- size_t saltlen;
- struct packed_rrset_data* d = (struct packed_rrset_data*)
- rrset->entry.data;
- log_assert(d && r < (int)d->count);
- if(d->rr_len[r] < 2+5) {
- *next = 0;
- *nextlen = 0;
- return 0; /* malformed */
- }
- saltlen = (size_t)d->rr_data[r][2+4];
- if(d->rr_len[r] < 2+5+saltlen+1) {
- *next = 0;
- *nextlen = 0;
- return 0; /* malformed */
- }
- *nextlen = (size_t)d->rr_data[r][2+5+saltlen];
- if(d->rr_len[r] < 2+5+saltlen+1+*nextlen) {
- *next = 0;
- *nextlen = 0;
- return 0; /* malformed */
- }
- *next = d->rr_data[r]+2+5+saltlen+1;
- return 1;
-}
-
-size_t nsec3_hash_to_b32(uint8_t* hash, size_t hashlen, uint8_t* zone,
- size_t zonelen, uint8_t* buf, size_t max)
-{
- /* write b32 of name, leave one for length */
- int ret;
- if(max < hashlen*2+1) /* quick approx of b32, as if hexb16 */
- return 0;
- ret = sldns_b32_ntop_extended_hex(hash, hashlen, (char*)buf+1, max-1);
- if(ret < 1)
- return 0;
- buf[0] = (uint8_t)ret; /* length of b32 label */
- ret++;
- if(max - ret < zonelen)
- return 0;
- memmove(buf+ret, zone, zonelen);
- return zonelen+(size_t)ret;
-}
-
-size_t nsec3_get_nextowner_b32(struct ub_packed_rrset_key* rrset, int r,
- uint8_t* buf, size_t max)
-{
- uint8_t* nm, *zone;
- size_t nmlen, zonelen;
- if(!nsec3_get_nextowner(rrset, r, &nm, &nmlen))
- return 0;
- /* append zone name; the owner name must be <b32>.zone */
- zone = rrset->rk.dname;
- zonelen = rrset->rk.dname_len;
- dname_remove_label(&zone, &zonelen);
- return nsec3_hash_to_b32(nm, nmlen, zone, zonelen, buf, max);
-}
-
-int
-nsec3_has_type(struct ub_packed_rrset_key* rrset, int r, uint16_t type)
-{
- uint8_t* bitmap;
- size_t bitlen, skiplen;
- struct packed_rrset_data* d = (struct packed_rrset_data*)
- rrset->entry.data;
- log_assert(d && r < (int)d->count);
- skiplen = 2+4;
- /* skip salt */
- if(d->rr_len[r] < skiplen+1)
- return 0; /* malformed, too short */
- skiplen += 1+(size_t)d->rr_data[r][skiplen];
- /* skip next hashed owner */
- if(d->rr_len[r] < skiplen+1)
- return 0; /* malformed, too short */
- skiplen += 1+(size_t)d->rr_data[r][skiplen];
- if(d->rr_len[r] < skiplen)
- return 0; /* malformed, too short */
- bitlen = d->rr_len[r] - skiplen;
- bitmap = d->rr_data[r]+skiplen;
- return nsecbitmap_has_type_rdata(bitmap, bitlen, type);
-}
-
-/**
- * Iterate through NSEC3 list, per RR
- * This routine gives the next RR in the list (or sets rrset null).
- * Usage:
- *
- * size_t rrsetnum;
- * int rrnum;
- * struct ub_packed_rrset_key* rrset;
- * for(rrset=filter_first(filter, &rrsetnum, &rrnum); rrset;
- * rrset=filter_next(filter, &rrsetnum, &rrnum))
- * do_stuff;
- *
- * Also filters out
- * o unknown flag NSEC3s
- * o unknown algorithm NSEC3s.
- * @param filter: nsec3 filter structure.
- * @param rrsetnum: in/out rrset number to look at.
- * @param rrnum: in/out rr number in rrset to look at.
- * @returns ptr to the next rrset (or NULL at end).
- */
-static struct ub_packed_rrset_key*
-filter_next(struct nsec3_filter* filter, size_t* rrsetnum, int* rrnum)
-{
- size_t i;
- int r;
- uint8_t* nm;
- size_t nmlen;
- if(!filter->zone) /* empty list */
- return NULL;
- for(i=*rrsetnum; i<filter->num; i++) {
- /* see if RRset qualifies */
- if(ntohs(filter->list[i]->rk.type) != LDNS_RR_TYPE_NSEC3 ||
- ntohs(filter->list[i]->rk.rrset_class) !=
- filter->fclass)
- continue;
- /* check RRset zone */
- nm = filter->list[i]->rk.dname;
- nmlen = filter->list[i]->rk.dname_len;
- dname_remove_label(&nm, &nmlen);
- if(query_dname_compare(nm, filter->zone) != 0)
- continue;
- if(i == *rrsetnum)
- r = (*rrnum) + 1; /* continue at next RR */
- else r = 0; /* new RRset start at first RR */
- for(; r < (int)rrset_get_count(filter->list[i]); r++) {
- /* skip unknown flags, algo */
- if(nsec3_unknown_flags(filter->list[i], r) ||
- !nsec3_known_algo(filter->list[i], r))
- continue;
- /* this one is a good target */
- *rrsetnum = i;
- *rrnum = r;
- return filter->list[i];
- }
- }
- return NULL;
-}
-
-/**
- * Start iterating over NSEC3 records.
- * @param filter: the filter structure, must have been filter_init-ed.
- * @param rrsetnum: can be undefined on call, initialised.
- * @param rrnum: can be undefined on call, initialised.
- * @return first rrset of an NSEC3, together with rrnum this points to
- * the first RR to examine. Is NULL on empty list.
- */
-static struct ub_packed_rrset_key*
-filter_first(struct nsec3_filter* filter, size_t* rrsetnum, int* rrnum)
-{
- *rrsetnum = 0;
- *rrnum = -1;
- return filter_next(filter, rrsetnum, rrnum);
-}
-
-/** see if at least one RR is known (flags, algo) */
-static int
-nsec3_rrset_has_known(struct ub_packed_rrset_key* s)
-{
- int r;
- for(r=0; r < (int)rrset_get_count(s); r++) {
- if(!nsec3_unknown_flags(s, r) && nsec3_known_algo(s, r))
- return 1;
- }
- return 0;
-}
-
-/**
- * Initialize the filter structure.
- * Finds the zone by looking at available NSEC3 records and best match.
- * (skips the unknown flag and unknown algo NSEC3s).
- *
- * @param filter: nsec3 filter structure.
- * @param list: list of rrsets, an array of them.
- * @param num: number of rrsets in list.
- * @param qinfo:
- * query name to match a zone for.
- * query type (if DS a higher zone must be chosen)
- * qclass, to filter NSEC3s with.
- */
-static void
-filter_init(struct nsec3_filter* filter, struct ub_packed_rrset_key** list,
- size_t num, struct query_info* qinfo)
-{
- size_t i;
- uint8_t* nm;
- size_t nmlen;
- filter->zone = NULL;
- filter->zone_len = 0;
- filter->list = list;
- filter->num = num;
- filter->fclass = qinfo->qclass;
- for(i=0; i<num; i++) {
- /* ignore other stuff in the list */
- if(ntohs(list[i]->rk.type) != LDNS_RR_TYPE_NSEC3 ||
- ntohs(list[i]->rk.rrset_class) != qinfo->qclass)
- continue;
- /* skip unknown flags, algo */
- if(!nsec3_rrset_has_known(list[i]))
- continue;
-
- /* since NSEC3s are base32.zonename, we can find the zone
- * name by stripping off the first label of the record */
- nm = list[i]->rk.dname;
- nmlen = list[i]->rk.dname_len;
- dname_remove_label(&nm, &nmlen);
- /* if we find a domain that can prove about the qname,
- * and if this domain is closer to the qname */
- if(dname_subdomain_c(qinfo->qname, nm) && (!filter->zone ||
- dname_subdomain_c(nm, filter->zone))) {
- /* for a type DS do not accept a zone equal to qname*/
- if(qinfo->qtype == LDNS_RR_TYPE_DS &&
- query_dname_compare(qinfo->qname, nm) == 0 &&
- !dname_is_root(qinfo->qname))
- continue;
- filter->zone = nm;
- filter->zone_len = nmlen;
- }
- }
-}
-
-/**
- * Find max iteration count using config settings and key size
- * @param ve: validator environment with iteration count config settings.
- * @param bits: key size
- * @return max iteration count
- */
-static size_t
-get_max_iter(struct val_env* ve, size_t bits)
-{
- int i;
- log_assert(ve->nsec3_keyiter_count > 0);
- /* round up to nearest config keysize, linear search, keep it small */
- for(i=0; i<ve->nsec3_keyiter_count; i++) {
- if(bits <= ve->nsec3_keysize[i])
- return ve->nsec3_maxiter[i];
- }
- /* else, use value for biggest key */
- return ve->nsec3_maxiter[ve->nsec3_keyiter_count-1];
-}
-
-/**
- * Determine if any of the NSEC3 rrs iteration count is too high, from key.
- * @param ve: validator environment with iteration count config settings.
- * @param filter: what NSEC3s to loop over.
- * @param kkey: key entry used for verification; used for iteration counts.
- * @return 1 if some nsec3s are above the max iteration count.
- */
-static int
-nsec3_iteration_count_high(struct val_env* ve, struct nsec3_filter* filter,
- struct key_entry_key* kkey)
-{
- size_t rrsetnum;
- int rrnum;
- struct ub_packed_rrset_key* rrset;
- /* first determine the max number of iterations */
- size_t bits = key_entry_keysize(kkey);
- size_t max_iter = get_max_iter(ve, bits);
- verbose(VERB_ALGO, "nsec3: keysize %d bits, max iterations %d",
- (int)bits, (int)max_iter);
-
- for(rrset=filter_first(filter, &rrsetnum, &rrnum); rrset;
- rrset=filter_next(filter, &rrsetnum, &rrnum)) {
- if(nsec3_get_iter(rrset, rrnum) > max_iter)
- return 1;
- }
- return 0;
-}
-
-/* nsec3_cache_compare for rbtree */
-int
-nsec3_hash_cmp(const void* c1, const void* c2)
-{
- struct nsec3_cached_hash* h1 = (struct nsec3_cached_hash*)c1;
- struct nsec3_cached_hash* h2 = (struct nsec3_cached_hash*)c2;
- uint8_t* s1, *s2;
- size_t s1len, s2len;
- int c = query_dname_compare(h1->dname, h2->dname);
- if(c != 0)
- return c;
- /* compare parameters */
- /* if both malformed, its equal, robustness */
- if(nsec3_get_algo(h1->nsec3, h1->rr) !=
- nsec3_get_algo(h2->nsec3, h2->rr)) {
- if(nsec3_get_algo(h1->nsec3, h1->rr) <
- nsec3_get_algo(h2->nsec3, h2->rr))
- return -1;
- return 1;
- }
- if(nsec3_get_iter(h1->nsec3, h1->rr) !=
- nsec3_get_iter(h2->nsec3, h2->rr)) {
- if(nsec3_get_iter(h1->nsec3, h1->rr) <
- nsec3_get_iter(h2->nsec3, h2->rr))
- return -1;
- return 1;
- }
- (void)nsec3_get_salt(h1->nsec3, h1->rr, &s1, &s1len);
- (void)nsec3_get_salt(h2->nsec3, h2->rr, &s2, &s2len);
- if(s1len != s2len) {
- if(s1len < s2len)
- return -1;
- return 1;
- }
- return memcmp(s1, s2, s1len);
-}
-
-size_t
-nsec3_get_hashed(sldns_buffer* buf, uint8_t* nm, size_t nmlen, int algo,
- size_t iter, uint8_t* salt, size_t saltlen, uint8_t* res, size_t max)
-{
- size_t i, hash_len;
- /* prepare buffer for first iteration */
- sldns_buffer_clear(buf);
- sldns_buffer_write(buf, nm, nmlen);
- query_dname_tolower(sldns_buffer_begin(buf));
- sldns_buffer_write(buf, salt, saltlen);
- sldns_buffer_flip(buf);
- hash_len = nsec3_hash_algo_size_supported(algo);
- if(hash_len == 0) {
- log_err("nsec3 hash of unknown algo %d", algo);
- return 0;
- }
- if(hash_len > max)
- return 0;
- if(!secalgo_nsec3_hash(algo, (unsigned char*)sldns_buffer_begin(buf),
- sldns_buffer_limit(buf), (unsigned char*)res))
- return 0;
- for(i=0; i<iter; i++) {
- sldns_buffer_clear(buf);
- sldns_buffer_write(buf, res, hash_len);
- sldns_buffer_write(buf, salt, saltlen);
- sldns_buffer_flip(buf);
- if(!secalgo_nsec3_hash(algo,
- (unsigned char*)sldns_buffer_begin(buf),
- sldns_buffer_limit(buf), (unsigned char*)res))
- return 0;
- }
- return hash_len;
-}
-
-/** perform hash of name */
-static int
-nsec3_calc_hash(struct regional* region, sldns_buffer* buf,
- struct nsec3_cached_hash* c)
-{
- int algo = nsec3_get_algo(c->nsec3, c->rr);
- size_t iter = nsec3_get_iter(c->nsec3, c->rr);
- uint8_t* salt;
- size_t saltlen, i;
- if(!nsec3_get_salt(c->nsec3, c->rr, &salt, &saltlen))
- return -1;
- /* prepare buffer for first iteration */
- sldns_buffer_clear(buf);
- sldns_buffer_write(buf, c->dname, c->dname_len);
- query_dname_tolower(sldns_buffer_begin(buf));
- sldns_buffer_write(buf, salt, saltlen);
- sldns_buffer_flip(buf);
- c->hash_len = nsec3_hash_algo_size_supported(algo);
- if(c->hash_len == 0) {
- log_err("nsec3 hash of unknown algo %d", algo);
- return -1;
- }
- c->hash = (uint8_t*)regional_alloc(region, c->hash_len);
- if(!c->hash)
- return 0;
- (void)secalgo_nsec3_hash(algo, (unsigned char*)sldns_buffer_begin(buf),
- sldns_buffer_limit(buf), (unsigned char*)c->hash);
- for(i=0; i<iter; i++) {
- sldns_buffer_clear(buf);
- sldns_buffer_write(buf, c->hash, c->hash_len);
- sldns_buffer_write(buf, salt, saltlen);
- sldns_buffer_flip(buf);
- (void)secalgo_nsec3_hash(algo,
- (unsigned char*)sldns_buffer_begin(buf),
- sldns_buffer_limit(buf), (unsigned char*)c->hash);
- }
- return 1;
-}
-
-/** perform b32 encoding of hash */
-static int
-nsec3_calc_b32(struct regional* region, sldns_buffer* buf,
- struct nsec3_cached_hash* c)
-{
- int r;
- sldns_buffer_clear(buf);
- r = sldns_b32_ntop_extended_hex(c->hash, c->hash_len,
- (char*)sldns_buffer_begin(buf), sldns_buffer_limit(buf));
- if(r < 1) {
- log_err("b32_ntop_extended_hex: error in encoding: %d", r);
- return 0;
- }
- c->b32_len = (size_t)r;
- c->b32 = regional_alloc_init(region, sldns_buffer_begin(buf),
- c->b32_len);
- if(!c->b32)
- return 0;
- return 1;
-}
-
-int
-nsec3_hash_name(rbtree_type* table, struct regional* region, sldns_buffer* buf,
- struct ub_packed_rrset_key* nsec3, int rr, uint8_t* dname,
- size_t dname_len, struct nsec3_cached_hash** hash)
-{
- struct nsec3_cached_hash* c;
- struct nsec3_cached_hash looki;
-#ifdef UNBOUND_DEBUG
- rbnode_type* n;
-#endif
- int r;
- looki.node.key = &looki;
- looki.nsec3 = nsec3;
- looki.rr = rr;
- looki.dname = dname;
- looki.dname_len = dname_len;
- /* lookup first in cache */
- c = (struct nsec3_cached_hash*)rbtree_search(table, &looki);
- if(c) {
- *hash = c;
- return 1;
- }
- /* create a new entry */
- c = (struct nsec3_cached_hash*)regional_alloc(region, sizeof(*c));
- if(!c) return 0;
- c->node.key = c;
- c->nsec3 = nsec3;
- c->rr = rr;
- c->dname = dname;
- c->dname_len = dname_len;
- r = nsec3_calc_hash(region, buf, c);
- if(r != 1)
- return r;
- r = nsec3_calc_b32(region, buf, c);
- if(r != 1)
- return r;
-#ifdef UNBOUND_DEBUG
- n =
-#else
- (void)
-#endif
- rbtree_insert(table, &c->node);
- log_assert(n); /* cannot be duplicate, just did lookup */
- *hash = c;
- return 1;
-}
-
-/**
- * compare a label lowercased
- */
-static int
-label_compare_lower(uint8_t* lab1, uint8_t* lab2, size_t lablen)
-{
- size_t i;
- for(i=0; i<lablen; i++) {
- if(tolower((unsigned char)*lab1) != tolower((unsigned char)*lab2)) {
- if(tolower((unsigned char)*lab1) < tolower((unsigned char)*lab2))
- return -1;
- return 1;
- }
- lab1++;
- lab2++;
- }
- return 0;
-}
-
-/**
- * Compare a hashed name with the owner name of an NSEC3 RRset.
- * @param flt: filter with zone name.
- * @param hash: the hashed name.
- * @param s: rrset with owner name.
- * @return true if matches exactly, false if not.
- */
-static int
-nsec3_hash_matches_owner(struct nsec3_filter* flt,
- struct nsec3_cached_hash* hash, struct ub_packed_rrset_key* s)
-{
- uint8_t* nm = s->rk.dname;
- /* compare, does hash of name based on params in this NSEC3
- * match the owner name of this NSEC3?
- * name must be: <hashlength>base32 . zone name
- * so; first label must not be root label (not zero length),
- * and match the b32 encoded hash length,
- * and the label content match the b32 encoded hash
- * and the rest must be the zone name.
- */
- if(hash->b32_len != 0 && (size_t)nm[0] == hash->b32_len &&
- label_compare_lower(nm+1, hash->b32, hash->b32_len) == 0 &&
- query_dname_compare(nm+(size_t)nm[0]+1, flt->zone) == 0) {
- return 1;
- }
- return 0;
-}
-
-/**
- * Find matching NSEC3
- * Find the NSEC3Record that matches a hash of a name.
- * @param env: module environment with temporary region and buffer.
- * @param flt: the NSEC3 RR filter, contains zone name and RRs.
- * @param ct: cached hashes table.
- * @param nm: name to look for.
- * @param nmlen: length of name.
- * @param rrset: nsec3 that matches is returned here.
- * @param rr: rr number in nsec3 rrset that matches.
- * @return true if a matching NSEC3 is found, false if not.
- */
-static int
-find_matching_nsec3(struct module_env* env, struct nsec3_filter* flt,
- rbtree_type* ct, uint8_t* nm, size_t nmlen,
- struct ub_packed_rrset_key** rrset, int* rr)
-{
- size_t i_rs;
- int i_rr;
- struct ub_packed_rrset_key* s;
- struct nsec3_cached_hash* hash;
- int r;
-
- /* this loop skips other-zone and unknown NSEC3s, also non-NSEC3 RRs */
- for(s=filter_first(flt, &i_rs, &i_rr); s;
- s=filter_next(flt, &i_rs, &i_rr)) {
- /* get name hashed for this NSEC3 RR */
- r = nsec3_hash_name(ct, env->scratch, env->scratch_buffer,
- s, i_rr, nm, nmlen, &hash);
- if(r == 0) {
- log_err("nsec3: malloc failure");
- break; /* alloc failure */
- } else if(r < 0)
- continue; /* malformed NSEC3 */
- else if(nsec3_hash_matches_owner(flt, hash, s)) {
- *rrset = s; /* rrset with this name */
- *rr = i_rr; /* matches hash with these parameters */
- return 1;
- }
- }
- *rrset = NULL;
- *rr = 0;
- return 0;
-}
-
-int
-nsec3_covers(uint8_t* zone, struct nsec3_cached_hash* hash,
- struct ub_packed_rrset_key* rrset, int rr, sldns_buffer* buf)
-{
- uint8_t* next, *owner;
- size_t nextlen;
- int len;
- if(!nsec3_get_nextowner(rrset, rr, &next, &nextlen))
- return 0; /* malformed RR proves nothing */
-
- /* check the owner name is a hashed value . apex
- * base32 encoded values must have equal length.
- * hash_value and next hash value must have equal length. */
- if(nextlen != hash->hash_len || hash->hash_len==0||hash->b32_len==0||
- (size_t)*rrset->rk.dname != hash->b32_len ||
- query_dname_compare(rrset->rk.dname+1+
- (size_t)*rrset->rk.dname, zone) != 0)
- return 0; /* bad lengths or owner name */
-
- /* This is the "normal case: owner < next and owner < hash < next */
- if(label_compare_lower(rrset->rk.dname+1, hash->b32,
- hash->b32_len) < 0 &&
- memcmp(hash->hash, next, nextlen) < 0)
- return 1;
-
- /* convert owner name from text to binary */
- sldns_buffer_clear(buf);
- owner = sldns_buffer_begin(buf);
- len = sldns_b32_pton_extended_hex((char*)rrset->rk.dname+1,
- hash->b32_len, owner, sldns_buffer_limit(buf));
- if(len<1)
- return 0; /* bad owner name in some way */
- if((size_t)len != hash->hash_len || (size_t)len != nextlen)
- return 0; /* wrong length */
-
- /* this is the end of zone case: next <= owner &&
- * (hash > owner || hash < next)
- * this also covers the only-apex case of next==owner.
- */
- if(memcmp(next, owner, nextlen) <= 0 &&
- ( memcmp(hash->hash, owner, nextlen) > 0 ||
- memcmp(hash->hash, next, nextlen) < 0)) {
- return 1;
- }
- return 0;
-}
-
-/**
- * findCoveringNSEC3
- * Given a name, find a covering NSEC3 from among a list of NSEC3s.
- *
- * @param env: module environment with temporary region and buffer.
- * @param flt: the NSEC3 RR filter, contains zone name and RRs.
- * @param ct: cached hashes table.
- * @param nm: name to check if covered.
- * @param nmlen: length of name.
- * @param rrset: covering NSEC3 rrset is returned here.
- * @param rr: rr of cover is returned here.
- * @return true if a covering NSEC3 is found, false if not.
- */
-static int
-find_covering_nsec3(struct module_env* env, struct nsec3_filter* flt,
- rbtree_type* ct, uint8_t* nm, size_t nmlen,
- struct ub_packed_rrset_key** rrset, int* rr)
-{
- size_t i_rs;
- int i_rr;
- struct ub_packed_rrset_key* s;
- struct nsec3_cached_hash* hash;
- int r;
-
- /* this loop skips other-zone and unknown NSEC3s, also non-NSEC3 RRs */
- for(s=filter_first(flt, &i_rs, &i_rr); s;
- s=filter_next(flt, &i_rs, &i_rr)) {
- /* get name hashed for this NSEC3 RR */
- r = nsec3_hash_name(ct, env->scratch, env->scratch_buffer,
- s, i_rr, nm, nmlen, &hash);
- if(r == 0) {
- log_err("nsec3: malloc failure");
- break; /* alloc failure */
- } else if(r < 0)
- continue; /* malformed NSEC3 */
- else if(nsec3_covers(flt->zone, hash, s, i_rr,
- env->scratch_buffer)) {
- *rrset = s; /* rrset with this name */
- *rr = i_rr; /* covers hash with these parameters */
- return 1;
- }
- }
- *rrset = NULL;
- *rr = 0;
- return 0;
-}
-
-/**
- * findClosestEncloser
- * Given a name and a list of NSEC3s, find the candidate closest encloser.
- * This will be the first ancestor of 'name' (including itself) to have a
- * matching NSEC3 RR.
- * @param env: module environment with temporary region and buffer.
- * @param flt: the NSEC3 RR filter, contains zone name and RRs.
- * @param ct: cached hashes table.
- * @param qinfo: query that is verified for.
- * @param ce: closest encloser information is returned in here.
- * @return true if a closest encloser candidate is found, false if not.
- */
-static int
-nsec3_find_closest_encloser(struct module_env* env, struct nsec3_filter* flt,
- rbtree_type* ct, struct query_info* qinfo, struct ce_response* ce)
-{
- uint8_t* nm = qinfo->qname;
- size_t nmlen = qinfo->qname_len;
-
- /* This scans from longest name to shortest, so the first match
- * we find is the only viable candidate. */
-
- /* (David:) FIXME: modify so that the NSEC3 matching the zone apex need
- * not be present. (Mark Andrews idea).
- * (Wouter:) But make sure you check for DNAME bit in zone apex,
- * if the NSEC3 you find is the only NSEC3 in the zone, then this
- * may be the case. */
-
- while(dname_subdomain_c(nm, flt->zone)) {
- if(find_matching_nsec3(env, flt, ct, nm, nmlen,
- &ce->ce_rrset, &ce->ce_rr)) {
- ce->ce = nm;
- ce->ce_len = nmlen;
- return 1;
- }
- dname_remove_label(&nm, &nmlen);
- }
- return 0;
-}
-
-/**
- * Given a qname and its proven closest encloser, calculate the "next
- * closest" name. Basically, this is the name that is one label longer than
- * the closest encloser that is still a subdomain of qname.
- *
- * @param qname: query name.
- * @param qnamelen: length of qname.
- * @param ce: closest encloser
- * @param nm: result name.
- * @param nmlen: length of nm.
- */
-static void
-next_closer(uint8_t* qname, size_t qnamelen, uint8_t* ce,
- uint8_t** nm, size_t* nmlen)
-{
- int strip = dname_count_labels(qname) - dname_count_labels(ce) -1;
- *nm = qname;
- *nmlen = qnamelen;
- if(strip>0)
- dname_remove_labels(nm, nmlen, strip);
-}
-
-/**
- * proveClosestEncloser
- * Given a List of nsec3 RRs, find and prove the closest encloser to qname.
- * @param env: module environment with temporary region and buffer.
- * @param flt: the NSEC3 RR filter, contains zone name and RRs.
- * @param ct: cached hashes table.
- * @param qinfo: query that is verified for.
- * @param prove_does_not_exist: If true, then if the closest encloser
- * turns out to be qname, then null is returned.
- * If set true, and the return value is true, then you can be
- * certain that the ce.nc_rrset and ce.nc_rr are set properly.
- * @param ce: closest encloser information is returned in here.
- * @return bogus if no closest encloser could be proven.
- * secure if a closest encloser could be proven, ce is set.
- * insecure if the closest-encloser candidate turns out to prove
- * that an insecure delegation exists above the qname.
- */
-static enum sec_status
-nsec3_prove_closest_encloser(struct module_env* env, struct nsec3_filter* flt,
- rbtree_type* ct, struct query_info* qinfo, int prove_does_not_exist,
- struct ce_response* ce)
-{
- uint8_t* nc;
- size_t nc_len;
- /* robust: clean out ce, in case it gets abused later */
- memset(ce, 0, sizeof(*ce));
-
- if(!nsec3_find_closest_encloser(env, flt, ct, qinfo, ce)) {
- verbose(VERB_ALGO, "nsec3 proveClosestEncloser: could "
- "not find a candidate for the closest encloser.");
- return sec_status_bogus;
- }
- log_nametypeclass(VERB_ALGO, "ce candidate", ce->ce, 0, 0);
-
- if(query_dname_compare(ce->ce, qinfo->qname) == 0) {
- if(prove_does_not_exist) {
- verbose(VERB_ALGO, "nsec3 proveClosestEncloser: "
- "proved that qname existed, bad");
- return sec_status_bogus;
- }
- /* otherwise, we need to nothing else to prove that qname
- * is its own closest encloser. */
- return sec_status_secure;
- }
-
- /* If the closest encloser is actually a delegation, then the
- * response should have been a referral. If it is a DNAME, then
- * it should have been a DNAME response. */
- if(nsec3_has_type(ce->ce_rrset, ce->ce_rr, LDNS_RR_TYPE_NS) &&
- !nsec3_has_type(ce->ce_rrset, ce->ce_rr, LDNS_RR_TYPE_SOA)) {
- if(!nsec3_has_type(ce->ce_rrset, ce->ce_rr, LDNS_RR_TYPE_DS)) {
- verbose(VERB_ALGO, "nsec3 proveClosestEncloser: "
- "closest encloser is insecure delegation");
- return sec_status_insecure;
- }
- verbose(VERB_ALGO, "nsec3 proveClosestEncloser: closest "
- "encloser was a delegation, bad");
- return sec_status_bogus;
- }
- if(nsec3_has_type(ce->ce_rrset, ce->ce_rr, LDNS_RR_TYPE_DNAME)) {
- verbose(VERB_ALGO, "nsec3 proveClosestEncloser: closest "
- "encloser was a DNAME, bad");
- return sec_status_bogus;
- }
-
- /* Otherwise, we need to show that the next closer name is covered. */
- next_closer(qinfo->qname, qinfo->qname_len, ce->ce, &nc, &nc_len);
- if(!find_covering_nsec3(env, flt, ct, nc, nc_len,
- &ce->nc_rrset, &ce->nc_rr)) {
- verbose(VERB_ALGO, "nsec3: Could not find proof that the "
- "candidate encloser was the closest encloser");
- return sec_status_bogus;
- }
- return sec_status_secure;
-}
-
-/** allocate a wildcard for the closest encloser */
-static uint8_t*
-nsec3_ce_wildcard(struct regional* region, uint8_t* ce, size_t celen,
- size_t* len)
-{
- uint8_t* nm;
- if(celen > LDNS_MAX_DOMAINLEN - 2)
- return 0; /* too long */
- nm = (uint8_t*)regional_alloc(region, celen+2);
- if(!nm) {
- log_err("nsec3 wildcard: out of memory");
- return 0; /* alloc failure */
- }
- nm[0] = 1;
- nm[1] = (uint8_t)'*'; /* wildcard label */
- memmove(nm+2, ce, celen);
- *len = celen+2;
- return nm;
-}
-
-/** Do the name error proof */
-static enum sec_status
-nsec3_do_prove_nameerror(struct module_env* env, struct nsec3_filter* flt,
- rbtree_type* ct, struct query_info* qinfo)
-{
- struct ce_response ce;
- uint8_t* wc;
- size_t wclen;
- struct ub_packed_rrset_key* wc_rrset;
- int wc_rr;
- enum sec_status sec;
-
- /* First locate and prove the closest encloser to qname. We will
- * use the variant that fails if the closest encloser turns out
- * to be qname. */
- sec = nsec3_prove_closest_encloser(env, flt, ct, qinfo, 1, &ce);
- if(sec != sec_status_secure) {
- if(sec == sec_status_bogus)
- verbose(VERB_ALGO, "nsec3 nameerror proof: failed "
- "to prove a closest encloser");
- else verbose(VERB_ALGO, "nsec3 nameerror proof: closest "
- "nsec3 is an insecure delegation");
- return sec;
- }
- log_nametypeclass(VERB_ALGO, "nsec3 namerror: proven ce=", ce.ce,0,0);
-
- /* At this point, we know that qname does not exist. Now we need
- * to prove that the wildcard does not exist. */
- log_assert(ce.ce);
- wc = nsec3_ce_wildcard(env->scratch, ce.ce, ce.ce_len, &wclen);
- if(!wc || !find_covering_nsec3(env, flt, ct, wc, wclen,
- &wc_rrset, &wc_rr)) {
- verbose(VERB_ALGO, "nsec3 nameerror proof: could not prove "
- "that the applicable wildcard did not exist.");
- return sec_status_bogus;
- }
-
- if(ce.nc_rrset && nsec3_has_optout(ce.nc_rrset, ce.nc_rr)) {
- verbose(VERB_ALGO, "nsec3 nameerror proof: nc has optout");
- return sec_status_insecure;
- }
- return sec_status_secure;
-}
-
-enum sec_status
-nsec3_prove_nameerror(struct module_env* env, struct val_env* ve,
- struct ub_packed_rrset_key** list, size_t num,
- struct query_info* qinfo, struct key_entry_key* kkey)
-{
- rbtree_type ct;
- struct nsec3_filter flt;
-
- if(!list || num == 0 || !kkey || !key_entry_isgood(kkey))
- return sec_status_bogus; /* no valid NSEC3s, bogus */
- rbtree_init(&ct, &nsec3_hash_cmp); /* init names-to-hash cache */
- filter_init(&flt, list, num, qinfo); /* init RR iterator */
- if(!flt.zone)
- return sec_status_bogus; /* no RRs */
- if(nsec3_iteration_count_high(ve, &flt, kkey))
- return sec_status_insecure; /* iteration count too high */
- log_nametypeclass(VERB_ALGO, "start nsec3 nameerror proof, zone",
- flt.zone, 0, 0);
- return nsec3_do_prove_nameerror(env, &flt, &ct, qinfo);
-}
-
-/*
- * No code to handle qtype=NSEC3 specially.
- * This existed in early drafts, but was later (-05) removed.
- */
-
-/** Do the nodata proof */
-static enum sec_status
-nsec3_do_prove_nodata(struct module_env* env, struct nsec3_filter* flt,
- rbtree_type* ct, struct query_info* qinfo)
-{
- struct ce_response ce;
- uint8_t* wc;
- size_t wclen;
- struct ub_packed_rrset_key* rrset;
- int rr;
- enum sec_status sec;
-
- if(find_matching_nsec3(env, flt, ct, qinfo->qname, qinfo->qname_len,
- &rrset, &rr)) {
- /* cases 1 and 2 */
- if(nsec3_has_type(rrset, rr, qinfo->qtype)) {
- verbose(VERB_ALGO, "proveNodata: Matching NSEC3 "
- "proved that type existed, bogus");
- return sec_status_bogus;
- } else if(nsec3_has_type(rrset, rr, LDNS_RR_TYPE_CNAME)) {
- verbose(VERB_ALGO, "proveNodata: Matching NSEC3 "
- "proved that a CNAME existed, bogus");
- return sec_status_bogus;
- }
-
- /*
- * If type DS: filter_init zone find already found a parent
- * zone, so this nsec3 is from a parent zone.
- * o can be not a delegation (unusual query for normal name,
- * no DS anyway, but we can verify that).
- * o can be a delegation (which is the usual DS check).
- * o may not have the SOA bit set (only the top of the
- * zone, which must have been above the name, has that).
- * Except for the root; which is checked by itself.
- *
- * If not type DS: matching nsec3 must not be a delegation.
- */
- if(qinfo->qtype == LDNS_RR_TYPE_DS && qinfo->qname_len != 1
- && nsec3_has_type(rrset, rr, LDNS_RR_TYPE_SOA) &&
- !dname_is_root(qinfo->qname)) {
- verbose(VERB_ALGO, "proveNodata: apex NSEC3 "
- "abused for no DS proof, bogus");
- return sec_status_bogus;
- } else if(qinfo->qtype != LDNS_RR_TYPE_DS &&
- nsec3_has_type(rrset, rr, LDNS_RR_TYPE_NS) &&
- !nsec3_has_type(rrset, rr, LDNS_RR_TYPE_SOA)) {
- if(!nsec3_has_type(rrset, rr, LDNS_RR_TYPE_DS)) {
- verbose(VERB_ALGO, "proveNodata: matching "
- "NSEC3 is insecure delegation");
- return sec_status_insecure;
- }
- verbose(VERB_ALGO, "proveNodata: matching "
- "NSEC3 is a delegation, bogus");
- return sec_status_bogus;
- }
- return sec_status_secure;
- }
-
- /* For cases 3 - 5, we need the proven closest encloser, and it
- * can't match qname. Although, at this point, we know that it
- * won't since we just checked that. */
- sec = nsec3_prove_closest_encloser(env, flt, ct, qinfo, 1, &ce);
- if(sec == sec_status_bogus) {
- verbose(VERB_ALGO, "proveNodata: did not match qname, "
- "nor found a proven closest encloser.");
- return sec_status_bogus;
- } else if(sec==sec_status_insecure && qinfo->qtype!=LDNS_RR_TYPE_DS){
- verbose(VERB_ALGO, "proveNodata: closest nsec3 is insecure "
- "delegation.");
- return sec_status_insecure;
- }
-
- /* Case 3: removed */
-
- /* Case 4: */
- log_assert(ce.ce);
- wc = nsec3_ce_wildcard(env->scratch, ce.ce, ce.ce_len, &wclen);
- if(wc && find_matching_nsec3(env, flt, ct, wc, wclen, &rrset, &rr)) {
- /* found wildcard */
- if(nsec3_has_type(rrset, rr, qinfo->qtype)) {
- verbose(VERB_ALGO, "nsec3 nodata proof: matching "
- "wildcard had qtype, bogus");
- return sec_status_bogus;
- } else if(nsec3_has_type(rrset, rr, LDNS_RR_TYPE_CNAME)) {
- verbose(VERB_ALGO, "nsec3 nodata proof: matching "
- "wildcard had a CNAME, bogus");
- return sec_status_bogus;
- }
- if(qinfo->qtype == LDNS_RR_TYPE_DS && qinfo->qname_len != 1
- && nsec3_has_type(rrset, rr, LDNS_RR_TYPE_SOA)) {
- verbose(VERB_ALGO, "nsec3 nodata proof: matching "
- "wildcard for no DS proof has a SOA, bogus");
- return sec_status_bogus;
- } else if(qinfo->qtype != LDNS_RR_TYPE_DS &&
- nsec3_has_type(rrset, rr, LDNS_RR_TYPE_NS) &&
- !nsec3_has_type(rrset, rr, LDNS_RR_TYPE_SOA)) {
- verbose(VERB_ALGO, "nsec3 nodata proof: matching "
- "wildcard is a delegation, bogus");
- return sec_status_bogus;
- }
- /* everything is peachy keen, except for optout spans */
- if(ce.nc_rrset && nsec3_has_optout(ce.nc_rrset, ce.nc_rr)) {
- verbose(VERB_ALGO, "nsec3 nodata proof: matching "
- "wildcard is in optout range, insecure");
- return sec_status_insecure;
- }
- return sec_status_secure;
- }
-
- /* Case 5: */
- /* Due to forwarders, cnames, and other collating effects, we
- * can see the ordinary unsigned data from a zone beneath an
- * insecure delegation under an optout here */
- if(!ce.nc_rrset) {
- verbose(VERB_ALGO, "nsec3 nodata proof: no next closer nsec3");
- return sec_status_bogus;
- }
-
- /* We need to make sure that the covering NSEC3 is opt-out. */
- log_assert(ce.nc_rrset);
- if(!nsec3_has_optout(ce.nc_rrset, ce.nc_rr)) {
- if(qinfo->qtype == LDNS_RR_TYPE_DS)
- verbose(VERB_ALGO, "proveNodata: covering NSEC3 was not "
- "opt-out in an opt-out DS NOERROR/NODATA case.");
- else verbose(VERB_ALGO, "proveNodata: could not find matching "
- "NSEC3, nor matching wildcard, nor optout NSEC3 "
- "-- no more options, bogus.");
- return sec_status_bogus;
- }
- /* RFC5155 section 9.2: if nc has optout then no AD flag set */
- return sec_status_insecure;
-}
-
-enum sec_status
-nsec3_prove_nodata(struct module_env* env, struct val_env* ve,
- struct ub_packed_rrset_key** list, size_t num,
- struct query_info* qinfo, struct key_entry_key* kkey)
-{
- rbtree_type ct;
- struct nsec3_filter flt;
-
- if(!list || num == 0 || !kkey || !key_entry_isgood(kkey))
- return sec_status_bogus; /* no valid NSEC3s, bogus */
- rbtree_init(&ct, &nsec3_hash_cmp); /* init names-to-hash cache */
- filter_init(&flt, list, num, qinfo); /* init RR iterator */
- if(!flt.zone)
- return sec_status_bogus; /* no RRs */
- if(nsec3_iteration_count_high(ve, &flt, kkey))
- return sec_status_insecure; /* iteration count too high */
- return nsec3_do_prove_nodata(env, &flt, &ct, qinfo);
-}
-
-enum sec_status
-nsec3_prove_wildcard(struct module_env* env, struct val_env* ve,
- struct ub_packed_rrset_key** list, size_t num,
- struct query_info* qinfo, struct key_entry_key* kkey, uint8_t* wc)
-{
- rbtree_type ct;
- struct nsec3_filter flt;
- struct ce_response ce;
- uint8_t* nc;
- size_t nc_len;
- size_t wclen;
- (void)dname_count_size_labels(wc, &wclen);
-
- if(!list || num == 0 || !kkey || !key_entry_isgood(kkey))
- return sec_status_bogus; /* no valid NSEC3s, bogus */
- rbtree_init(&ct, &nsec3_hash_cmp); /* init names-to-hash cache */
- filter_init(&flt, list, num, qinfo); /* init RR iterator */
- if(!flt.zone)
- return sec_status_bogus; /* no RRs */
- if(nsec3_iteration_count_high(ve, &flt, kkey))
- return sec_status_insecure; /* iteration count too high */
-
- /* We know what the (purported) closest encloser is by just
- * looking at the supposed generating wildcard.
- * The *. has already been removed from the wc name.
- */
- memset(&ce, 0, sizeof(ce));
- ce.ce = wc;
- ce.ce_len = wclen;
-
- /* Now we still need to prove that the original data did not exist.
- * Otherwise, we need to show that the next closer name is covered. */
- next_closer(qinfo->qname, qinfo->qname_len, ce.ce, &nc, &nc_len);
- if(!find_covering_nsec3(env, &flt, &ct, nc, nc_len,
- &ce.nc_rrset, &ce.nc_rr)) {
- verbose(VERB_ALGO, "proveWildcard: did not find a covering "
- "NSEC3 that covered the next closer name.");
- return sec_status_bogus;
- }
- if(ce.nc_rrset && nsec3_has_optout(ce.nc_rrset, ce.nc_rr)) {
- verbose(VERB_ALGO, "proveWildcard: NSEC3 optout");
- return sec_status_insecure;
- }
- return sec_status_secure;
-}
-
-/** test if list is all secure */
-static int
-list_is_secure(struct module_env* env, struct val_env* ve,
- struct ub_packed_rrset_key** list, size_t num,
- struct key_entry_key* kkey, char** reason)
-{
- struct packed_rrset_data* d;
- size_t i;
- for(i=0; i<num; i++) {
- d = (struct packed_rrset_data*)list[i]->entry.data;
- if(list[i]->rk.type != htons(LDNS_RR_TYPE_NSEC3))
- continue;
- if(d->security == sec_status_secure)
- continue;
- rrset_check_sec_status(env->rrset_cache, list[i], *env->now);
- if(d->security == sec_status_secure)
- continue;
- d->security = val_verify_rrset_entry(env, ve, list[i], kkey,
- reason);
- if(d->security != sec_status_secure) {
- verbose(VERB_ALGO, "NSEC3 did not verify");
- return 0;
- }
- rrset_update_sec_status(env->rrset_cache, list[i], *env->now);
- }
- return 1;
-}
-
-enum sec_status
-nsec3_prove_nods(struct module_env* env, struct val_env* ve,
- struct ub_packed_rrset_key** list, size_t num,
- struct query_info* qinfo, struct key_entry_key* kkey, char** reason)
-{
- rbtree_type ct;
- struct nsec3_filter flt;
- struct ce_response ce;
- struct ub_packed_rrset_key* rrset;
- int rr;
- log_assert(qinfo->qtype == LDNS_RR_TYPE_DS);
-
- if(!list || num == 0 || !kkey || !key_entry_isgood(kkey)) {
- *reason = "no valid NSEC3s";
- return sec_status_bogus; /* no valid NSEC3s, bogus */
- }
- if(!list_is_secure(env, ve, list, num, kkey, reason))
- return sec_status_bogus; /* not all NSEC3 records secure */
- rbtree_init(&ct, &nsec3_hash_cmp); /* init names-to-hash cache */
- filter_init(&flt, list, num, qinfo); /* init RR iterator */
- if(!flt.zone) {
- *reason = "no NSEC3 records";
- return sec_status_bogus; /* no RRs */
- }
- if(nsec3_iteration_count_high(ve, &flt, kkey))
- return sec_status_insecure; /* iteration count too high */
-
- /* Look for a matching NSEC3 to qname -- this is the normal
- * NODATA case. */
- if(find_matching_nsec3(env, &flt, &ct, qinfo->qname, qinfo->qname_len,
- &rrset, &rr)) {
- /* If the matching NSEC3 has the SOA bit set, it is from
- * the wrong zone (the child instead of the parent). If
- * it has the DS bit set, then we were lied to. */
- if(nsec3_has_type(rrset, rr, LDNS_RR_TYPE_SOA) &&
- qinfo->qname_len != 1) {
- verbose(VERB_ALGO, "nsec3 provenods: NSEC3 is from"
- " child zone, bogus");
- *reason = "NSEC3 from child zone";
- return sec_status_bogus;
- } else if(nsec3_has_type(rrset, rr, LDNS_RR_TYPE_DS)) {
- verbose(VERB_ALGO, "nsec3 provenods: NSEC3 has qtype"
- " DS, bogus");
- *reason = "NSEC3 has DS in bitmap";
- return sec_status_bogus;
- }
- /* If the NSEC3 RR doesn't have the NS bit set, then
- * this wasn't a delegation point. */
- if(!nsec3_has_type(rrset, rr, LDNS_RR_TYPE_NS))
- return sec_status_indeterminate;
- /* Otherwise, this proves no DS. */
- return sec_status_secure;
- }
-
- /* Otherwise, we are probably in the opt-out case. */
- if(nsec3_prove_closest_encloser(env, &flt, &ct, qinfo, 1, &ce)
- != sec_status_secure) {
- /* an insecure delegation *above* the qname does not prove
- * anything about this qname exactly, and bogus is bogus */
- verbose(VERB_ALGO, "nsec3 provenods: did not match qname, "
- "nor found a proven closest encloser.");
- *reason = "no NSEC3 closest encloser";
- return sec_status_bogus;
- }
-
- /* robust extra check */
- if(!ce.nc_rrset) {
- verbose(VERB_ALGO, "nsec3 nods proof: no next closer nsec3");
- *reason = "no NSEC3 next closer";
- return sec_status_bogus;
- }
-
- /* we had the closest encloser proof, then we need to check that the
- * covering NSEC3 was opt-out -- the proveClosestEncloser step already
- * checked to see if the closest encloser was a delegation or DNAME.
- */
- log_assert(ce.nc_rrset);
- if(!nsec3_has_optout(ce.nc_rrset, ce.nc_rr)) {
- verbose(VERB_ALGO, "nsec3 provenods: covering NSEC3 was not "
- "opt-out in an opt-out DS NOERROR/NODATA case.");
- *reason = "covering NSEC3 was not opt-out in an opt-out "
- "DS NOERROR/NODATA case";
- return sec_status_bogus;
- }
- /* RFC5155 section 9.2: if nc has optout then no AD flag set */
- return sec_status_insecure;
-}
-
-enum sec_status
-nsec3_prove_nxornodata(struct module_env* env, struct val_env* ve,
- struct ub_packed_rrset_key** list, size_t num,
- struct query_info* qinfo, struct key_entry_key* kkey, int* nodata)
-{
- enum sec_status sec, secnx;
- rbtree_type ct;
- struct nsec3_filter flt;
- *nodata = 0;
-
- if(!list || num == 0 || !kkey || !key_entry_isgood(kkey))
- return sec_status_bogus; /* no valid NSEC3s, bogus */
- rbtree_init(&ct, &nsec3_hash_cmp); /* init names-to-hash cache */
- filter_init(&flt, list, num, qinfo); /* init RR iterator */
- if(!flt.zone)
- return sec_status_bogus; /* no RRs */
- if(nsec3_iteration_count_high(ve, &flt, kkey))
- return sec_status_insecure; /* iteration count too high */
-
- /* try nxdomain and nodata after another, while keeping the
- * hash cache intact */
-
- secnx = nsec3_do_prove_nameerror(env, &flt, &ct, qinfo);
- if(secnx==sec_status_secure)
- return sec_status_secure;
- sec = nsec3_do_prove_nodata(env, &flt, &ct, qinfo);
- if(sec==sec_status_secure) {
- *nodata = 1;
- } else if(sec == sec_status_insecure) {
- *nodata = 1;
- } else if(secnx == sec_status_insecure) {
- sec = sec_status_insecure;
- }
- return sec;
-}
diff --git a/external/unbound/validator/val_nsec3.h b/external/unbound/validator/val_nsec3.h
deleted file mode 100644
index 27e9f9eac..000000000
--- a/external/unbound/validator/val_nsec3.h
+++ /dev/null
@@ -1,380 +0,0 @@
-/*
- * validator/val_nsec3.h - validator NSEC3 denial of existence functions.
- *
- * Copyright (c) 2007, NLnet Labs. All rights reserved.
- *
- * This software is open source.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- *
- * Redistributions of source code must retain the above copyright notice,
- * this list of conditions and the following disclaimer.
- *
- * Redistributions in binary form must reproduce the above copyright notice,
- * this list of conditions and the following disclaimer in the documentation
- * and/or other materials provided with the distribution.
- *
- * Neither the name of the NLNET LABS nor the names of its contributors may
- * be used to endorse or promote products derived from this software without
- * specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
- * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
- * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
- * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
- * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
- * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-/**
- * \file
- *
- * This file contains helper functions for the validator module.
- * The functions help with NSEC3 checking, the different NSEC3 proofs
- * for denial of existence, and proofs for presence of types.
- *
- * NSEC3
- * 1 1 1 1 1 1 1 1 1 1 2 2 2 2 2 2 2 2 2 2 3 3
- * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
- * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
- * | Hash Alg. | Flags | Iterations |
- * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
- * | Salt Length | Salt /
- * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
- * | Hash Length | Next Hashed Owner Name /
- * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
- * / Type Bit Maps /
- * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
- *
- * NSEC3PARAM
- * 1 1 1 1 1 1 1 1 1 1 2 2 2 2 2 2 2 2 2 2 3 3
- * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
- * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
- * | Hash Alg. | Flags | Iterations |
- * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
- * | Salt Length | Salt /
- * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
- *
- */
-
-#ifndef VALIDATOR_VAL_NSEC3_H
-#define VALIDATOR_VAL_NSEC3_H
-#include "util/rbtree.h"
-#include "util/data/packed_rrset.h"
-struct val_env;
-struct regional;
-struct module_env;
-struct ub_packed_rrset_key;
-struct reply_info;
-struct query_info;
-struct key_entry_key;
-struct sldns_buffer;
-
-/**
- * 0 1 2 3 4 5 6 7
- * +-+-+-+-+-+-+-+-+
- * | |O|
- * +-+-+-+-+-+-+-+-+
- * The OPT-OUT bit in the NSEC3 flags field.
- * If enabled, there can be zero or more unsigned delegations in the span.
- * If disabled, there are zero unsigned delegations in the span.
- */
-#define NSEC3_OPTOUT 0x01
-/**
- * The unknown flags in the NSEC3 flags field.
- * They must be zero, or the NSEC3 is ignored.
- */
-#define NSEC3_UNKNOWN_FLAGS 0xFE
-
-/** The SHA1 hash algorithm for NSEC3 */
-#define NSEC3_HASH_SHA1 0x01
-
-/**
- * Determine if the set of NSEC3 records provided with a response prove NAME
- * ERROR. This means that the NSEC3s prove a) the closest encloser exists,
- * b) the direct child of the closest encloser towards qname doesn't exist,
- * and c) *.closest encloser does not exist.
- *
- * @param env: module environment with temporary region and buffer.
- * @param ve: validator environment, with iteration count settings.
- * @param list: array of RRsets, some of which are NSEC3s.
- * @param num: number of RRsets in the array to examine.
- * @param qinfo: query that is verified for.
- * @param kkey: key entry that signed the NSEC3s.
- * @return:
- * sec_status SECURE of the Name Error is proven by the NSEC3 RRs,
- * BOGUS if not, INSECURE if all of the NSEC3s could be validly ignored.
- */
-enum sec_status
-nsec3_prove_nameerror(struct module_env* env, struct val_env* ve,
- struct ub_packed_rrset_key** list, size_t num,
- struct query_info* qinfo, struct key_entry_key* kkey);
-
-/**
- * Determine if the NSEC3s provided in a response prove the NOERROR/NODATA
- * status. There are a number of different variants to this:
- *
- * 1) Normal NODATA -- qname is matched to an NSEC3 record, type is not
- * present.
- *
- * 2) ENT NODATA -- because there must be NSEC3 record for
- * empty-non-terminals, this is the same as #1.
- *
- * 3) NSEC3 ownername NODATA -- qname matched an existing, lone NSEC3
- * ownername, but qtype was not NSEC3. NOTE: as of nsec-05, this case no
- * longer exists.
- *
- * 4) Wildcard NODATA -- A wildcard matched the name, but not the type.
- *
- * 5) Opt-In DS NODATA -- the qname is covered by an opt-in span and qtype ==
- * DS. (or maybe some future record with the same parent-side-only property)
- *
- * @param env: module environment with temporary region and buffer.
- * @param ve: validator environment, with iteration count settings.
- * @param list: array of RRsets, some of which are NSEC3s.
- * @param num: number of RRsets in the array to examine.
- * @param qinfo: query that is verified for.
- * @param kkey: key entry that signed the NSEC3s.
- * @return:
- * sec_status SECURE of the proposition is proven by the NSEC3 RRs,
- * BOGUS if not, INSECURE if all of the NSEC3s could be validly ignored.
- */
-enum sec_status
-nsec3_prove_nodata(struct module_env* env, struct val_env* ve,
- struct ub_packed_rrset_key** list, size_t num,
- struct query_info* qinfo, struct key_entry_key* kkey);
-
-
-/**
- * Prove that a positive wildcard match was appropriate (no direct match
- * RRset).
- *
- * @param env: module environment with temporary region and buffer.
- * @param ve: validator environment, with iteration count settings.
- * @param list: array of RRsets, some of which are NSEC3s.
- * @param num: number of RRsets in the array to examine.
- * @param qinfo: query that is verified for.
- * @param kkey: key entry that signed the NSEC3s.
- * @param wc: The purported wildcard that matched. This is the wildcard name
- * as *.wildcard.name., with the *. label already removed.
- * @return:
- * sec_status SECURE of the proposition is proven by the NSEC3 RRs,
- * BOGUS if not, INSECURE if all of the NSEC3s could be validly ignored.
- */
-enum sec_status
-nsec3_prove_wildcard(struct module_env* env, struct val_env* ve,
- struct ub_packed_rrset_key** list, size_t num,
- struct query_info* qinfo, struct key_entry_key* kkey, uint8_t* wc);
-
-/**
- * Prove that a DS response either had no DS, or wasn't a delegation point.
- *
- * Fundamentally there are two cases here: normal NODATA and Opt-In NODATA.
- *
- * @param env: module environment with temporary region and buffer.
- * @param ve: validator environment, with iteration count settings.
- * @param list: array of RRsets, some of which are NSEC3s.
- * @param num: number of RRsets in the array to examine.
- * @param qinfo: query that is verified for.
- * @param kkey: key entry that signed the NSEC3s.
- * @param reason: string for bogus result.
- * @return:
- * sec_status SECURE of the proposition is proven by the NSEC3 RRs,
- * BOGUS if not, INSECURE if all of the NSEC3s could be validly ignored.
- * or if there was no DS in an insecure (i.e., opt-in) way,
- * INDETERMINATE if it was clear that this wasn't a delegation point.
- */
-enum sec_status
-nsec3_prove_nods(struct module_env* env, struct val_env* ve,
- struct ub_packed_rrset_key** list, size_t num,
- struct query_info* qinfo, struct key_entry_key* kkey, char** reason);
-
-/**
- * Prove NXDOMAIN or NODATA.
- *
- * @param env: module environment with temporary region and buffer.
- * @param ve: validator environment, with iteration count settings.
- * @param list: array of RRsets, some of which are NSEC3s.
- * @param num: number of RRsets in the array to examine.
- * @param qinfo: query that is verified for.
- * @param kkey: key entry that signed the NSEC3s.
- * @param nodata: if return value is secure, this indicates if nodata or
- * nxdomain was proven.
- * @return:
- * sec_status SECURE of the proposition is proven by the NSEC3 RRs,
- * BOGUS if not, INSECURE if all of the NSEC3s could be validly ignored.
- */
-enum sec_status
-nsec3_prove_nxornodata(struct module_env* env, struct val_env* ve,
- struct ub_packed_rrset_key** list, size_t num,
- struct query_info* qinfo, struct key_entry_key* kkey, int* nodata);
-
-/**
- * The NSEC3 hash result storage.
- * Consists of an rbtree, with these nodes in it.
- * The nodes detail how a set of parameters (from nsec3 rr) plus
- * a dname result in a hash.
- */
-struct nsec3_cached_hash {
- /** rbtree node, key is this structure */
- rbnode_type node;
- /** where are the parameters for conversion, in this rrset data */
- struct ub_packed_rrset_key* nsec3;
- /** where are the parameters for conversion, this RR number in data */
- int rr;
- /** the name to convert */
- uint8_t* dname;
- /** length of the dname */
- size_t dname_len;
- /** the hash result (not base32 encoded) */
- uint8_t* hash;
- /** length of hash in bytes */
- size_t hash_len;
- /** the hash result in base32 encoding */
- uint8_t* b32;
- /** length of base32 encoding (as a label) */
- size_t b32_len;
-};
-
-/**
- * Rbtree for hash cache comparison function.
- * @param c1: key 1.
- * @param c2: key 2.
- * @return: comparison code, -1, 0, 1, of the keys.
- */
-int nsec3_hash_cmp(const void* c1, const void* c2);
-
-/**
- * Obtain the hash of an owner name.
- * Used internally by the nsec3 proof functions in this file.
- * published to enable unit testing of hash algorithms and cache.
- *
- * @param table: the cache table. Must be initialised at start.
- * @param region: scratch region to use for allocation.
- * This region holds the tree, if you wipe the region, reinit the tree.
- * @param buf: temporary buffer.
- * @param nsec3: the rrset with parameters
- * @param rr: rr number from d that has the NSEC3 parameters to hash to.
- * @param dname: name to hash
- * This pointer is used inside the tree, assumed region-alloced.
- * @param dname_len: the length of the name.
- * @param hash: the hash node is returned on success.
- * @return:
- * 1 on success, either from cache or newly hashed hash is returned.
- * 0 on a malloc failure.
- * -1 if the NSEC3 rr was badly formatted (i.e. formerr).
- */
-int nsec3_hash_name(rbtree_type* table, struct regional* region,
- struct sldns_buffer* buf, struct ub_packed_rrset_key* nsec3, int rr,
- uint8_t* dname, size_t dname_len, struct nsec3_cached_hash** hash);
-
-/**
- * Get next owner name, converted to base32 encoding and with the
- * zone name (taken from the nsec3 owner name) appended.
- * @param rrset: the NSEC3 rrset.
- * @param r: the rr num of the nsec3 in the rrset.
- * @param buf: buffer to store name in
- * @param max: size of buffer.
- * @return length of name on success. 0 on failure (buffer too short or
- * bad format nsec3 record).
- */
-size_t nsec3_get_nextowner_b32(struct ub_packed_rrset_key* rrset, int r,
- uint8_t* buf, size_t max);
-
-/**
- * Convert hash into base32 encoding and with the
- * zone name appended.
- * @param hash: hashed buffer
- * @param hashlen: length of hash
- * @param zone: name of zone
- * @param zonelen: length of zonename.
- * @param buf: buffer to store name in
- * @param max: size of buffer.
- * @return length of name on success. 0 on failure (buffer too short or
- * bad format nsec3 record).
- */
-size_t nsec3_hash_to_b32(uint8_t* hash, size_t hashlen, uint8_t* zone,
- size_t zonelen, uint8_t* buf, size_t max);
-
-/**
- * Get NSEC3 parameters out of rr.
- * @param rrset: the NSEC3 rrset.
- * @param r: the rr num of the nsec3 in the rrset.
- * @param algo: nsec3 hash algo.
- * @param iter: iteration count.
- * @param salt: ptr to salt inside rdata.
- * @param saltlen: length of salt.
- * @return 0 if bad formatted, unknown nsec3 hash algo, or unknown flags set.
- */
-int nsec3_get_params(struct ub_packed_rrset_key* rrset, int r,
- int* algo, size_t* iter, uint8_t** salt, size_t* saltlen);
-
-/**
- * Get NSEC3 hashed in a buffer
- * @param buf: buffer for temp use.
- * @param nm: name to hash
- * @param nmlen: length of nm.
- * @param algo: algo to use, must be known.
- * @param iter: iterations
- * @param salt: salt for nsec3
- * @param saltlen: length of salt.
- * @param res: result of hash stored here.
- * @param max: maximum space for result.
- * @return 0 on failure, otherwise bytelength stored.
- */
-size_t nsec3_get_hashed(struct sldns_buffer* buf, uint8_t* nm, size_t nmlen,
- int algo, size_t iter, uint8_t* salt, size_t saltlen, uint8_t* res,
- size_t max);
-
-/**
- * see if NSEC3 RR contains given type
- * @param rrset: NSEC3 rrset
- * @param r: RR in rrset
- * @param type: in host order to check bit for.
- * @return true if bit set, false if not or error.
- */
-int nsec3_has_type(struct ub_packed_rrset_key* rrset, int r, uint16_t type);
-
-/**
- * return if nsec3 RR has the optout flag
- * @param rrset: NSEC3 rrset
- * @param r: RR in rrset
- * @return true if optout, false on error or not optout
- */
-int nsec3_has_optout(struct ub_packed_rrset_key* rrset, int r);
-
-/**
- * Return nsec3 RR next hashed owner name
- * @param rrset: NSEC3 rrset
- * @param r: RR in rrset
- * @param next: ptr into rdata to next owner hash
- * @param nextlen: length of hash.
- * @return false on malformed
- */
-int nsec3_get_nextowner(struct ub_packed_rrset_key* rrset, int r,
- uint8_t** next, size_t* nextlen);
-
-/**
- * nsec3Covers
- * Given a hash and a candidate NSEC3Record, determine if that NSEC3Record
- * covers the hash. Covers specifically means that the hash is in between
- * the owner and next hashes and does not equal either.
- *
- * @param zone: the zone name.
- * @param hash: the hash of the name
- * @param rrset: the rrset of the NSEC3.
- * @param rr: which rr in the rrset.
- * @param buf: temporary buffer.
- * @return true if covers, false if not.
- */
-int nsec3_covers(uint8_t* zone, struct nsec3_cached_hash* hash,
- struct ub_packed_rrset_key* rrset, int rr, struct sldns_buffer* buf);
-
-#endif /* VALIDATOR_VAL_NSEC3_H */
diff --git a/external/unbound/validator/val_secalgo.c b/external/unbound/validator/val_secalgo.c
deleted file mode 100644
index be88ff438..000000000
--- a/external/unbound/validator/val_secalgo.c
+++ /dev/null
@@ -1,1753 +0,0 @@
-/*
- * validator/val_secalgo.c - validator security algorithm functions.
- *
- * Copyright (c) 2012, NLnet Labs. All rights reserved.
- *
- * This software is open source.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- *
- * Redistributions of source code must retain the above copyright notice,
- * this list of conditions and the following disclaimer.
- *
- * Redistributions in binary form must reproduce the above copyright notice,
- * this list of conditions and the following disclaimer in the documentation
- * and/or other materials provided with the distribution.
- *
- * Neither the name of the NLNET LABS nor the names of its contributors may
- * be used to endorse or promote products derived from this software without
- * specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
- * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
- * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
- * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
- * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
- * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-/**
- * \file
- *
- * This file contains helper functions for the validator module.
- * These functions take raw data buffers, formatted for crypto verification,
- * and do the library calls (for the crypto library in use).
- */
-#include "config.h"
-/* packed_rrset on top to define enum types (forced by c99 standard) */
-#include "util/data/packed_rrset.h"
-#include "validator/val_secalgo.h"
-#include "validator/val_nsec3.h"
-#include "util/log.h"
-#include "sldns/rrdef.h"
-#include "sldns/keyraw.h"
-#include "sldns/sbuffer.h"
-
-#if !defined(HAVE_SSL) && !defined(HAVE_NSS) && !defined(HAVE_NETTLE)
-#error "Need crypto library to do digital signature cryptography"
-#endif
-
-/* OpenSSL implementation */
-#ifdef HAVE_SSL
-#ifdef HAVE_OPENSSL_ERR_H
-#include <openssl/err.h>
-#endif
-
-#ifdef HAVE_OPENSSL_RAND_H
-#include <openssl/rand.h>
-#endif
-
-#ifdef HAVE_OPENSSL_CONF_H
-#include <openssl/conf.h>
-#endif
-
-#ifdef HAVE_OPENSSL_ENGINE_H
-#include <openssl/engine.h>
-#endif
-
-/** fake DSA support for unit tests */
-int fake_dsa = 0;
-/** fake SHA1 support for unit tests */
-int fake_sha1 = 0;
-
-/* return size of digest if supported, or 0 otherwise */
-size_t
-nsec3_hash_algo_size_supported(int id)
-{
- switch(id) {
- case NSEC3_HASH_SHA1:
- return SHA_DIGEST_LENGTH;
- default:
- return 0;
- }
-}
-
-/* perform nsec3 hash. return false on failure */
-int
-secalgo_nsec3_hash(int algo, unsigned char* buf, size_t len,
- unsigned char* res)
-{
- switch(algo) {
- case NSEC3_HASH_SHA1:
- (void)SHA1(buf, len, res);
- return 1;
- default:
- return 0;
- }
-}
-
-void
-secalgo_hash_sha256(unsigned char* buf, size_t len, unsigned char* res)
-{
- (void)SHA256(buf, len, res);
-}
-
-/**
- * Return size of DS digest according to its hash algorithm.
- * @param algo: DS digest algo.
- * @return size in bytes of digest, or 0 if not supported.
- */
-size_t
-ds_digest_size_supported(int algo)
-{
- switch(algo) {
- case LDNS_SHA1:
-#if defined(HAVE_EVP_SHA1) && defined(USE_SHA1)
- return SHA_DIGEST_LENGTH;
-#else
- if(fake_sha1) return 20;
- return 0;
-#endif
-#ifdef HAVE_EVP_SHA256
- case LDNS_SHA256:
- return SHA256_DIGEST_LENGTH;
-#endif
-#ifdef USE_GOST
- case LDNS_HASH_GOST:
- /* we support GOST if it can be loaded */
- (void)sldns_key_EVP_load_gost_id();
- if(EVP_get_digestbyname("md_gost94"))
- return 32;
- else return 0;
-#endif
-#ifdef USE_ECDSA
- case LDNS_SHA384:
- return SHA384_DIGEST_LENGTH;
-#endif
- default: break;
- }
- return 0;
-}
-
-#ifdef USE_GOST
-/** Perform GOST hash */
-static int
-do_gost94(unsigned char* data, size_t len, unsigned char* dest)
-{
- const EVP_MD* md = EVP_get_digestbyname("md_gost94");
- if(!md)
- return 0;
- return sldns_digest_evp(data, (unsigned int)len, dest, md);
-}
-#endif
-
-int
-secalgo_ds_digest(int algo, unsigned char* buf, size_t len,
- unsigned char* res)
-{
- switch(algo) {
-#if defined(HAVE_EVP_SHA1) && defined(USE_SHA1)
- case LDNS_SHA1:
- (void)SHA1(buf, len, res);
- return 1;
-#endif
-#ifdef HAVE_EVP_SHA256
- case LDNS_SHA256:
- (void)SHA256(buf, len, res);
- return 1;
-#endif
-#ifdef USE_GOST
- case LDNS_HASH_GOST:
- if(do_gost94(buf, len, res))
- return 1;
- break;
-#endif
-#ifdef USE_ECDSA
- case LDNS_SHA384:
- (void)SHA384(buf, len, res);
- return 1;
-#endif
- default:
- verbose(VERB_QUERY, "unknown DS digest algorithm %d",
- algo);
- break;
- }
- return 0;
-}
-
-/** return true if DNSKEY algorithm id is supported */
-int
-dnskey_algo_id_is_supported(int id)
-{
- switch(id) {
- case LDNS_RSAMD5:
- /* RFC 6725 deprecates RSAMD5 */
- return 0;
- case LDNS_DSA:
- case LDNS_DSA_NSEC3:
-#if defined(USE_DSA) && defined(USE_SHA1)
- return 1;
-#else
- if(fake_dsa || fake_sha1) return 1;
- return 0;
-#endif
-
- case LDNS_RSASHA1:
- case LDNS_RSASHA1_NSEC3:
-#ifdef USE_SHA1
- return 1;
-#else
- if(fake_sha1) return 1;
- return 0;
-#endif
-
-#if defined(HAVE_EVP_SHA256) && defined(USE_SHA2)
- case LDNS_RSASHA256:
-#endif
-#if defined(HAVE_EVP_SHA512) && defined(USE_SHA2)
- case LDNS_RSASHA512:
-#endif
-#ifdef USE_ECDSA
- case LDNS_ECDSAP256SHA256:
- case LDNS_ECDSAP384SHA384:
-#endif
-#if (defined(HAVE_EVP_SHA256) && defined(USE_SHA2)) || (defined(HAVE_EVP_SHA512) && defined(USE_SHA2)) || defined(USE_ECDSA)
- return 1;
-#endif
-
-#ifdef USE_GOST
- case LDNS_ECC_GOST:
- /* we support GOST if it can be loaded */
- return sldns_key_EVP_load_gost_id();
-#endif
- default:
- return 0;
- }
-}
-
-/**
- * Output a libcrypto openssl error to the logfile.
- * @param str: string to add to it.
- * @param e: the error to output, error number from ERR_get_error().
- */
-static void
-log_crypto_error(const char* str, unsigned long e)
-{
- char buf[128];
- /* or use ERR_error_string if ERR_error_string_n is not avail TODO */
- ERR_error_string_n(e, buf, sizeof(buf));
- /* buf now contains */
- /* error:[error code]:[library name]:[function name]:[reason string] */
- log_err("%s crypto %s", str, buf);
-}
-
-#ifdef USE_DSA
-/**
- * Setup DSA key digest in DER encoding ...
- * @param sig: input is signature output alloced ptr (unless failure).
- * caller must free alloced ptr if this routine returns true.
- * @param len: input is initial siglen, output is output len.
- * @return false on failure.
- */
-static int
-setup_dsa_sig(unsigned char** sig, unsigned int* len)
-{
- unsigned char* orig = *sig;
- unsigned int origlen = *len;
- int newlen;
- BIGNUM *R, *S;
- DSA_SIG *dsasig;
-
- /* extract the R and S field from the sig buffer */
- if(origlen < 1 + 2*SHA_DIGEST_LENGTH)
- return 0;
- R = BN_new();
- if(!R) return 0;
- (void) BN_bin2bn(orig + 1, SHA_DIGEST_LENGTH, R);
- S = BN_new();
- if(!S) return 0;
- (void) BN_bin2bn(orig + 21, SHA_DIGEST_LENGTH, S);
- dsasig = DSA_SIG_new();
- if(!dsasig) return 0;
-
-#ifdef HAVE_DSA_SIG_SET0
- if(!DSA_SIG_set0(dsasig, R, S)) return 0;
-#else
- dsasig->r = R;
- dsasig->s = S;
-#endif
- *sig = NULL;
- newlen = i2d_DSA_SIG(dsasig, sig);
- if(newlen < 0) {
- DSA_SIG_free(dsasig);
- free(*sig);
- return 0;
- }
- *len = (unsigned int)newlen;
- DSA_SIG_free(dsasig);
- return 1;
-}
-#endif /* USE_DSA */
-
-#ifdef USE_ECDSA
-/**
- * Setup the ECDSA signature in its encoding that the library wants.
- * Converts from plain numbers to ASN formatted.
- * @param sig: input is signature, output alloced ptr (unless failure).
- * caller must free alloced ptr if this routine returns true.
- * @param len: input is initial siglen, output is output len.
- * @return false on failure.
- */
-static int
-setup_ecdsa_sig(unsigned char** sig, unsigned int* len)
-{
- /* convert from two BIGNUMs in the rdata buffer, to ASN notation.
- * ASN preable: 30440220 <R 32bytefor256> 0220 <S 32bytefor256>
- * the '20' is the length of that field (=bnsize).
-i * the '44' is the total remaining length.
- * if negative, start with leading zero.
- * if starts with 00s, remove them from the number.
- */
- uint8_t pre[] = {0x30, 0x44, 0x02, 0x20};
- int pre_len = 4;
- uint8_t mid[] = {0x02, 0x20};
- int mid_len = 2;
- int raw_sig_len, r_high, s_high, r_rem=0, s_rem=0;
- int bnsize = (int)((*len)/2);
- unsigned char* d = *sig;
- uint8_t* p;
- /* if too short or not even length, fails */
- if(*len < 16 || bnsize*2 != (int)*len)
- return 0;
-
- /* strip leading zeroes from r (but not last one) */
- while(r_rem < bnsize-1 && d[r_rem] == 0)
- r_rem++;
- /* strip leading zeroes from s (but not last one) */
- while(s_rem < bnsize-1 && d[bnsize+s_rem] == 0)
- s_rem++;
-
- r_high = ((d[0+r_rem]&0x80)?1:0);
- s_high = ((d[bnsize+s_rem]&0x80)?1:0);
- raw_sig_len = pre_len + r_high + bnsize - r_rem + mid_len +
- s_high + bnsize - s_rem;
- *sig = (unsigned char*)malloc((size_t)raw_sig_len);
- if(!*sig)
- return 0;
- p = (uint8_t*)*sig;
- p[0] = pre[0];
- p[1] = (uint8_t)(raw_sig_len-2);
- p[2] = pre[2];
- p[3] = (uint8_t)(bnsize + r_high - r_rem);
- p += 4;
- if(r_high) {
- *p = 0;
- p += 1;
- }
- memmove(p, d+r_rem, (size_t)bnsize-r_rem);
- p += bnsize-r_rem;
- memmove(p, mid, (size_t)mid_len-1);
- p += mid_len-1;
- *p = (uint8_t)(bnsize + s_high - s_rem);
- p += 1;
- if(s_high) {
- *p = 0;
- p += 1;
- }
- memmove(p, d+bnsize+s_rem, (size_t)bnsize-s_rem);
- *len = (unsigned int)raw_sig_len;
- return 1;
-}
-#endif /* USE_ECDSA */
-
-#ifdef USE_ECDSA_EVP_WORKAROUND
-static EVP_MD ecdsa_evp_256_md;
-static EVP_MD ecdsa_evp_384_md;
-void ecdsa_evp_workaround_init(void)
-{
- /* openssl before 1.0.0 fixes RSA with the SHA256
- * hash in EVP. We create one for ecdsa_sha256 */
- ecdsa_evp_256_md = *EVP_sha256();
- ecdsa_evp_256_md.required_pkey_type[0] = EVP_PKEY_EC;
- ecdsa_evp_256_md.verify = (void*)ECDSA_verify;
-
- ecdsa_evp_384_md = *EVP_sha384();
- ecdsa_evp_384_md.required_pkey_type[0] = EVP_PKEY_EC;
- ecdsa_evp_384_md.verify = (void*)ECDSA_verify;
-}
-#endif /* USE_ECDSA_EVP_WORKAROUND */
-
-/**
- * Setup key and digest for verification. Adjust sig if necessary.
- *
- * @param algo: key algorithm
- * @param evp_key: EVP PKEY public key to create.
- * @param digest_type: digest type to use
- * @param key: key to setup for.
- * @param keylen: length of key.
- * @return false on failure.
- */
-static int
-setup_key_digest(int algo, EVP_PKEY** evp_key, const EVP_MD** digest_type,
- unsigned char* key, size_t keylen)
-{
-#if defined(USE_DSA) && defined(USE_SHA1)
- DSA* dsa;
-#endif
- RSA* rsa;
-
- switch(algo) {
-#if defined(USE_DSA) && defined(USE_SHA1)
- case LDNS_DSA:
- case LDNS_DSA_NSEC3:
- *evp_key = EVP_PKEY_new();
- if(!*evp_key) {
- log_err("verify: malloc failure in crypto");
- return 0;
- }
- dsa = sldns_key_buf2dsa_raw(key, keylen);
- if(!dsa) {
- verbose(VERB_QUERY, "verify: "
- "sldns_key_buf2dsa_raw failed");
- return 0;
- }
- if(EVP_PKEY_assign_DSA(*evp_key, dsa) == 0) {
- verbose(VERB_QUERY, "verify: "
- "EVP_PKEY_assign_DSA failed");
- return 0;
- }
-#ifdef HAVE_EVP_DSS1
- *digest_type = EVP_dss1();
-#else
- *digest_type = EVP_sha1();
-#endif
-
- break;
-#endif /* USE_DSA && USE_SHA1 */
-
-#if defined(USE_SHA1) || (defined(HAVE_EVP_SHA256) && defined(USE_SHA2)) || (defined(HAVE_EVP_SHA512) && defined(USE_SHA2))
-#ifdef USE_SHA1
- case LDNS_RSASHA1:
- case LDNS_RSASHA1_NSEC3:
-#endif
-#if defined(HAVE_EVP_SHA256) && defined(USE_SHA2)
- case LDNS_RSASHA256:
-#endif
-#if defined(HAVE_EVP_SHA512) && defined(USE_SHA2)
- case LDNS_RSASHA512:
-#endif
- *evp_key = EVP_PKEY_new();
- if(!*evp_key) {
- log_err("verify: malloc failure in crypto");
- return 0;
- }
- rsa = sldns_key_buf2rsa_raw(key, keylen);
- if(!rsa) {
- verbose(VERB_QUERY, "verify: "
- "sldns_key_buf2rsa_raw SHA failed");
- return 0;
- }
- if(EVP_PKEY_assign_RSA(*evp_key, rsa) == 0) {
- verbose(VERB_QUERY, "verify: "
- "EVP_PKEY_assign_RSA SHA failed");
- return 0;
- }
-
- /* select SHA version */
-#if defined(HAVE_EVP_SHA256) && defined(USE_SHA2)
- if(algo == LDNS_RSASHA256)
- *digest_type = EVP_sha256();
- else
-#endif
-#if defined(HAVE_EVP_SHA512) && defined(USE_SHA2)
- if(algo == LDNS_RSASHA512)
- *digest_type = EVP_sha512();
- else
-#endif
-#ifdef USE_SHA1
- *digest_type = EVP_sha1();
-#else
- { verbose(VERB_QUERY, "no digest available"); return 0; }
-#endif
- break;
-#endif /* defined(USE_SHA1) || (defined(HAVE_EVP_SHA256) && defined(USE_SHA2)) || (defined(HAVE_EVP_SHA512) && defined(USE_SHA2)) */
-
- case LDNS_RSAMD5:
- *evp_key = EVP_PKEY_new();
- if(!*evp_key) {
- log_err("verify: malloc failure in crypto");
- return 0;
- }
- rsa = sldns_key_buf2rsa_raw(key, keylen);
- if(!rsa) {
- verbose(VERB_QUERY, "verify: "
- "sldns_key_buf2rsa_raw MD5 failed");
- return 0;
- }
- if(EVP_PKEY_assign_RSA(*evp_key, rsa) == 0) {
- verbose(VERB_QUERY, "verify: "
- "EVP_PKEY_assign_RSA MD5 failed");
- return 0;
- }
- *digest_type = EVP_md5();
-
- break;
-#ifdef USE_GOST
- case LDNS_ECC_GOST:
- *evp_key = sldns_gost2pkey_raw(key, keylen);
- if(!*evp_key) {
- verbose(VERB_QUERY, "verify: "
- "sldns_gost2pkey_raw failed");
- return 0;
- }
- *digest_type = EVP_get_digestbyname("md_gost94");
- if(!*digest_type) {
- verbose(VERB_QUERY, "verify: "
- "EVP_getdigest md_gost94 failed");
- return 0;
- }
- break;
-#endif
-#ifdef USE_ECDSA
- case LDNS_ECDSAP256SHA256:
- *evp_key = sldns_ecdsa2pkey_raw(key, keylen,
- LDNS_ECDSAP256SHA256);
- if(!*evp_key) {
- verbose(VERB_QUERY, "verify: "
- "sldns_ecdsa2pkey_raw failed");
- return 0;
- }
-#ifdef USE_ECDSA_EVP_WORKAROUND
- *digest_type = &ecdsa_evp_256_md;
-#else
- *digest_type = EVP_sha256();
-#endif
- break;
- case LDNS_ECDSAP384SHA384:
- *evp_key = sldns_ecdsa2pkey_raw(key, keylen,
- LDNS_ECDSAP384SHA384);
- if(!*evp_key) {
- verbose(VERB_QUERY, "verify: "
- "sldns_ecdsa2pkey_raw failed");
- return 0;
- }
-#ifdef USE_ECDSA_EVP_WORKAROUND
- *digest_type = &ecdsa_evp_384_md;
-#else
- *digest_type = EVP_sha384();
-#endif
- break;
-#endif /* USE_ECDSA */
- default:
- verbose(VERB_QUERY, "verify: unknown algorithm %d",
- algo);
- return 0;
- }
- return 1;
-}
-
-/**
- * Check a canonical sig+rrset and signature against a dnskey
- * @param buf: buffer with data to verify, the first rrsig part and the
- * canonicalized rrset.
- * @param algo: DNSKEY algorithm.
- * @param sigblock: signature rdata field from RRSIG
- * @param sigblock_len: length of sigblock data.
- * @param key: public key data from DNSKEY RR.
- * @param keylen: length of keydata.
- * @param reason: bogus reason in more detail.
- * @return secure if verification succeeded, bogus on crypto failure,
- * unchecked on format errors and alloc failures.
- */
-enum sec_status
-verify_canonrrset(sldns_buffer* buf, int algo, unsigned char* sigblock,
- unsigned int sigblock_len, unsigned char* key, unsigned int keylen,
- char** reason)
-{
- const EVP_MD *digest_type;
- EVP_MD_CTX* ctx;
- int res, dofree = 0, docrypto_free = 0;
- EVP_PKEY *evp_key = NULL;
-
-#ifndef USE_DSA
- if((algo == LDNS_DSA || algo == LDNS_DSA_NSEC3) &&(fake_dsa||fake_sha1))
- return sec_status_secure;
-#endif
-#ifndef USE_SHA1
- if(fake_sha1 && (algo == LDNS_DSA || algo == LDNS_DSA_NSEC3 || algo == LDNS_RSASHA1 || algo == LDNS_RSASHA1_NSEC3))
- return sec_status_secure;
-#endif
-
- if(!setup_key_digest(algo, &evp_key, &digest_type, key, keylen)) {
- verbose(VERB_QUERY, "verify: failed to setup key");
- *reason = "use of key for crypto failed";
- EVP_PKEY_free(evp_key);
- return sec_status_bogus;
- }
-#ifdef USE_DSA
- /* if it is a DSA signature in bind format, convert to DER format */
- if((algo == LDNS_DSA || algo == LDNS_DSA_NSEC3) &&
- sigblock_len == 1+2*SHA_DIGEST_LENGTH) {
- if(!setup_dsa_sig(&sigblock, &sigblock_len)) {
- verbose(VERB_QUERY, "verify: failed to setup DSA sig");
- *reason = "use of key for DSA crypto failed";
- EVP_PKEY_free(evp_key);
- return sec_status_bogus;
- }
- docrypto_free = 1;
- }
-#endif
-#if defined(USE_ECDSA) && defined(USE_DSA)
- else
-#endif
-#ifdef USE_ECDSA
- if(algo == LDNS_ECDSAP256SHA256 || algo == LDNS_ECDSAP384SHA384) {
- /* EVP uses ASN prefix on sig, which is not in the wire data */
- if(!setup_ecdsa_sig(&sigblock, &sigblock_len)) {
- verbose(VERB_QUERY, "verify: failed to setup ECDSA sig");
- *reason = "use of signature for ECDSA crypto failed";
- EVP_PKEY_free(evp_key);
- return sec_status_bogus;
- }
- dofree = 1;
- }
-#endif /* USE_ECDSA */
-
- /* do the signature cryptography work */
-#ifdef HAVE_EVP_MD_CTX_NEW
- ctx = EVP_MD_CTX_new();
-#else
- ctx = (EVP_MD_CTX*)malloc(sizeof(*ctx));
- if(ctx) EVP_MD_CTX_init(ctx);
-#endif
- if(!ctx) {
- log_err("EVP_MD_CTX_new: malloc failure");
- EVP_PKEY_free(evp_key);
- if(dofree) free(sigblock);
- else if(docrypto_free) OPENSSL_free(sigblock);
- return sec_status_unchecked;
- }
- if(EVP_VerifyInit(ctx, digest_type) == 0) {
- verbose(VERB_QUERY, "verify: EVP_VerifyInit failed");
- EVP_MD_CTX_destroy(ctx);
- EVP_PKEY_free(evp_key);
- if(dofree) free(sigblock);
- else if(docrypto_free) OPENSSL_free(sigblock);
- return sec_status_unchecked;
- }
- if(EVP_VerifyUpdate(ctx, (unsigned char*)sldns_buffer_begin(buf),
- (unsigned int)sldns_buffer_limit(buf)) == 0) {
- verbose(VERB_QUERY, "verify: EVP_VerifyUpdate failed");
- EVP_MD_CTX_destroy(ctx);
- EVP_PKEY_free(evp_key);
- if(dofree) free(sigblock);
- else if(docrypto_free) OPENSSL_free(sigblock);
- return sec_status_unchecked;
- }
-
- res = EVP_VerifyFinal(ctx, sigblock, sigblock_len, evp_key);
-#ifdef HAVE_EVP_MD_CTX_NEW
- EVP_MD_CTX_destroy(ctx);
-#else
- EVP_MD_CTX_cleanup(ctx);
- free(ctx);
-#endif
- EVP_PKEY_free(evp_key);
-
- if(dofree) free(sigblock);
- else if(docrypto_free) OPENSSL_free(sigblock);
-
- if(res == 1) {
- return sec_status_secure;
- } else if(res == 0) {
- verbose(VERB_QUERY, "verify: signature mismatch");
- *reason = "signature crypto failed";
- return sec_status_bogus;
- }
-
- log_crypto_error("verify:", ERR_get_error());
- return sec_status_unchecked;
-}
-
-/**************************************************/
-#elif defined(HAVE_NSS)
-/* libnss implementation */
-/* nss3 */
-#include "sechash.h"
-#include "pk11pub.h"
-#include "keyhi.h"
-#include "secerr.h"
-#include "cryptohi.h"
-/* nspr4 */
-#include "prerror.h"
-
-/* return size of digest if supported, or 0 otherwise */
-size_t
-nsec3_hash_algo_size_supported(int id)
-{
- switch(id) {
- case NSEC3_HASH_SHA1:
- return SHA1_LENGTH;
- default:
- return 0;
- }
-}
-
-/* perform nsec3 hash. return false on failure */
-int
-secalgo_nsec3_hash(int algo, unsigned char* buf, size_t len,
- unsigned char* res)
-{
- switch(algo) {
- case NSEC3_HASH_SHA1:
- (void)HASH_HashBuf(HASH_AlgSHA1, res, buf, (unsigned long)len);
- return 1;
- default:
- return 0;
- }
-}
-
-void
-secalgo_hash_sha256(unsigned char* buf, size_t len, unsigned char* res)
-{
- (void)HASH_HashBuf(HASH_AlgSHA256, res, buf, (unsigned long)len);
-}
-
-size_t
-ds_digest_size_supported(int algo)
-{
- /* uses libNSS */
- switch(algo) {
-#ifdef USE_SHA1
- case LDNS_SHA1:
- return SHA1_LENGTH;
-#endif
-#ifdef USE_SHA2
- case LDNS_SHA256:
- return SHA256_LENGTH;
-#endif
-#ifdef USE_ECDSA
- case LDNS_SHA384:
- return SHA384_LENGTH;
-#endif
- /* GOST not supported in NSS */
- case LDNS_HASH_GOST:
- default: break;
- }
- return 0;
-}
-
-int
-secalgo_ds_digest(int algo, unsigned char* buf, size_t len,
- unsigned char* res)
-{
- /* uses libNSS */
- switch(algo) {
-#ifdef USE_SHA1
- case LDNS_SHA1:
- return HASH_HashBuf(HASH_AlgSHA1, res, buf, len)
- == SECSuccess;
-#endif
-#if defined(USE_SHA2)
- case LDNS_SHA256:
- return HASH_HashBuf(HASH_AlgSHA256, res, buf, len)
- == SECSuccess;
-#endif
-#ifdef USE_ECDSA
- case LDNS_SHA384:
- return HASH_HashBuf(HASH_AlgSHA384, res, buf, len)
- == SECSuccess;
-#endif
- case LDNS_HASH_GOST:
- default:
- verbose(VERB_QUERY, "unknown DS digest algorithm %d",
- algo);
- break;
- }
- return 0;
-}
-
-int
-dnskey_algo_id_is_supported(int id)
-{
- /* uses libNSS */
- switch(id) {
- case LDNS_RSAMD5:
- /* RFC 6725 deprecates RSAMD5 */
- return 0;
-#if defined(USE_SHA1) || defined(USE_SHA2)
-#if defined(USE_DSA) && defined(USE_SHA1)
- case LDNS_DSA:
- case LDNS_DSA_NSEC3:
-#endif
-#ifdef USE_SHA1
- case LDNS_RSASHA1:
- case LDNS_RSASHA1_NSEC3:
-#endif
-#ifdef USE_SHA2
- case LDNS_RSASHA256:
-#endif
-#ifdef USE_SHA2
- case LDNS_RSASHA512:
-#endif
- return 1;
-#endif /* SHA1 or SHA2 */
-
-#ifdef USE_ECDSA
- case LDNS_ECDSAP256SHA256:
- case LDNS_ECDSAP384SHA384:
- return PK11_TokenExists(CKM_ECDSA);
-#endif
- case LDNS_ECC_GOST:
- default:
- return 0;
- }
-}
-
-/* return a new public key for NSS */
-static SECKEYPublicKey* nss_key_create(KeyType ktype)
-{
- SECKEYPublicKey* key;
- PLArenaPool* arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
- if(!arena) {
- log_err("out of memory, PORT_NewArena failed");
- return NULL;
- }
- key = PORT_ArenaZNew(arena, SECKEYPublicKey);
- if(!key) {
- log_err("out of memory, PORT_ArenaZNew failed");
- PORT_FreeArena(arena, PR_FALSE);
- return NULL;
- }
- key->arena = arena;
- key->keyType = ktype;
- key->pkcs11Slot = NULL;
- key->pkcs11ID = CK_INVALID_HANDLE;
- return key;
-}
-
-static SECKEYPublicKey* nss_buf2ecdsa(unsigned char* key, size_t len, int algo)
-{
- SECKEYPublicKey* pk;
- SECItem pub = {siBuffer, NULL, 0};
- SECItem params = {siBuffer, NULL, 0};
- static unsigned char param256[] = {
- /* OBJECTIDENTIFIER 1.2.840.10045.3.1.7 (P-256)
- * {iso(1) member-body(2) us(840) ansi-x962(10045) curves(3) prime(1) prime256v1(7)} */
- 0x06, 0x08, 0x2a, 0x86, 0x48, 0xce, 0x3d, 0x03, 0x01, 0x07
- };
- static unsigned char param384[] = {
- /* OBJECTIDENTIFIER 1.3.132.0.34 (P-384)
- * {iso(1) identified-organization(3) certicom(132) curve(0) ansip384r1(34)} */
- 0x06, 0x05, 0x2b, 0x81, 0x04, 0x00, 0x22
- };
- unsigned char buf[256+2]; /* sufficient for 2*384/8+1 */
-
- /* check length, which uncompressed must be 2 bignums */
- if(algo == LDNS_ECDSAP256SHA256) {
- if(len != 2*256/8) return NULL;
- /* ECCurve_X9_62_PRIME_256V1 */
- } else if(algo == LDNS_ECDSAP384SHA384) {
- if(len != 2*384/8) return NULL;
- /* ECCurve_X9_62_PRIME_384R1 */
- } else return NULL;
-
- buf[0] = 0x04; /* POINT_FORM_UNCOMPRESSED */
- memmove(buf+1, key, len);
- pub.data = buf;
- pub.len = len+1;
- if(algo == LDNS_ECDSAP256SHA256) {
- params.data = param256;
- params.len = sizeof(param256);
- } else {
- params.data = param384;
- params.len = sizeof(param384);
- }
-
- pk = nss_key_create(ecKey);
- if(!pk)
- return NULL;
- pk->u.ec.size = (len/2)*8;
- if(SECITEM_CopyItem(pk->arena, &pk->u.ec.publicValue, &pub)) {
- SECKEY_DestroyPublicKey(pk);
- return NULL;
- }
- if(SECITEM_CopyItem(pk->arena, &pk->u.ec.DEREncodedParams, &params)) {
- SECKEY_DestroyPublicKey(pk);
- return NULL;
- }
-
- return pk;
-}
-
-static SECKEYPublicKey* nss_buf2dsa(unsigned char* key, size_t len)
-{
- SECKEYPublicKey* pk;
- uint8_t T;
- uint16_t length;
- uint16_t offset;
- SECItem Q = {siBuffer, NULL, 0};
- SECItem P = {siBuffer, NULL, 0};
- SECItem G = {siBuffer, NULL, 0};
- SECItem Y = {siBuffer, NULL, 0};
-
- if(len == 0)
- return NULL;
- T = (uint8_t)key[0];
- length = (64 + T * 8);
- offset = 1;
-
- if (T > 8) {
- return NULL;
- }
- if(len < (size_t)1 + SHA1_LENGTH + 3*length)
- return NULL;
-
- Q.data = key+offset;
- Q.len = SHA1_LENGTH;
- offset += SHA1_LENGTH;
-
- P.data = key+offset;
- P.len = length;
- offset += length;
-
- G.data = key+offset;
- G.len = length;
- offset += length;
-
- Y.data = key+offset;
- Y.len = length;
- offset += length;
-
- pk = nss_key_create(dsaKey);
- if(!pk)
- return NULL;
- if(SECITEM_CopyItem(pk->arena, &pk->u.dsa.params.prime, &P)) {
- SECKEY_DestroyPublicKey(pk);
- return NULL;
- }
- if(SECITEM_CopyItem(pk->arena, &pk->u.dsa.params.subPrime, &Q)) {
- SECKEY_DestroyPublicKey(pk);
- return NULL;
- }
- if(SECITEM_CopyItem(pk->arena, &pk->u.dsa.params.base, &G)) {
- SECKEY_DestroyPublicKey(pk);
- return NULL;
- }
- if(SECITEM_CopyItem(pk->arena, &pk->u.dsa.publicValue, &Y)) {
- SECKEY_DestroyPublicKey(pk);
- return NULL;
- }
- return pk;
-}
-
-static SECKEYPublicKey* nss_buf2rsa(unsigned char* key, size_t len)
-{
- SECKEYPublicKey* pk;
- uint16_t exp;
- uint16_t offset;
- uint16_t int16;
- SECItem modulus = {siBuffer, NULL, 0};
- SECItem exponent = {siBuffer, NULL, 0};
- if(len == 0)
- return NULL;
- if(key[0] == 0) {
- if(len < 3)
- return NULL;
- /* the exponent is too large so it's places further */
- memmove(&int16, key+1, 2);
- exp = ntohs(int16);
- offset = 3;
- } else {
- exp = key[0];
- offset = 1;
- }
-
- /* key length at least one */
- if(len < (size_t)offset + exp + 1)
- return NULL;
-
- exponent.data = key+offset;
- exponent.len = exp;
- offset += exp;
- modulus.data = key+offset;
- modulus.len = (len - offset);
-
- pk = nss_key_create(rsaKey);
- if(!pk)
- return NULL;
- if(SECITEM_CopyItem(pk->arena, &pk->u.rsa.modulus, &modulus)) {
- SECKEY_DestroyPublicKey(pk);
- return NULL;
- }
- if(SECITEM_CopyItem(pk->arena, &pk->u.rsa.publicExponent, &exponent)) {
- SECKEY_DestroyPublicKey(pk);
- return NULL;
- }
- return pk;
-}
-
-/**
- * Setup key and digest for verification. Adjust sig if necessary.
- *
- * @param algo: key algorithm
- * @param evp_key: EVP PKEY public key to create.
- * @param digest_type: digest type to use
- * @param key: key to setup for.
- * @param keylen: length of key.
- * @param prefix: if returned, the ASN prefix for the hashblob.
- * @param prefixlen: length of the prefix.
- * @return false on failure.
- */
-static int
-nss_setup_key_digest(int algo, SECKEYPublicKey** pubkey, HASH_HashType* htype,
- unsigned char* key, size_t keylen, unsigned char** prefix,
- size_t* prefixlen)
-{
- /* uses libNSS */
-
- /* hash prefix for md5, RFC2537 */
- static unsigned char p_md5[] = {0x30, 0x20, 0x30, 0x0c, 0x06, 0x08, 0x2a,
- 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x02, 0x05, 0x05, 0x00, 0x04, 0x10};
- /* hash prefix to prepend to hash output, from RFC3110 */
- static unsigned char p_sha1[] = {0x30, 0x21, 0x30, 0x09, 0x06, 0x05, 0x2B,
- 0x0E, 0x03, 0x02, 0x1A, 0x05, 0x00, 0x04, 0x14};
- /* from RFC5702 */
- static unsigned char p_sha256[] = {0x30, 0x31, 0x30, 0x0d, 0x06, 0x09, 0x60,
- 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x01, 0x05, 0x00, 0x04, 0x20};
- static unsigned char p_sha512[] = {0x30, 0x51, 0x30, 0x0d, 0x06, 0x09, 0x60,
- 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x03, 0x05, 0x00, 0x04, 0x40};
- /* from RFC6234 */
- /* for future RSASHA384 ..
- static unsigned char p_sha384[] = {0x30, 0x51, 0x30, 0x0d, 0x06, 0x09, 0x60,
- 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x02, 0x05, 0x00, 0x04, 0x30};
- */
-
- switch(algo) {
-
-#if defined(USE_SHA1) || defined(USE_SHA2)
-#if defined(USE_DSA) && defined(USE_SHA1)
- case LDNS_DSA:
- case LDNS_DSA_NSEC3:
- *pubkey = nss_buf2dsa(key, keylen);
- if(!*pubkey) {
- log_err("verify: malloc failure in crypto");
- return 0;
- }
- *htype = HASH_AlgSHA1;
- /* no prefix for DSA verification */
- break;
-#endif
-#ifdef USE_SHA1
- case LDNS_RSASHA1:
- case LDNS_RSASHA1_NSEC3:
-#endif
-#ifdef USE_SHA2
- case LDNS_RSASHA256:
-#endif
-#ifdef USE_SHA2
- case LDNS_RSASHA512:
-#endif
- *pubkey = nss_buf2rsa(key, keylen);
- if(!*pubkey) {
- log_err("verify: malloc failure in crypto");
- return 0;
- }
- /* select SHA version */
-#ifdef USE_SHA2
- if(algo == LDNS_RSASHA256) {
- *htype = HASH_AlgSHA256;
- *prefix = p_sha256;
- *prefixlen = sizeof(p_sha256);
- } else
-#endif
-#ifdef USE_SHA2
- if(algo == LDNS_RSASHA512) {
- *htype = HASH_AlgSHA512;
- *prefix = p_sha512;
- *prefixlen = sizeof(p_sha512);
- } else
-#endif
-#ifdef USE_SHA1
- {
- *htype = HASH_AlgSHA1;
- *prefix = p_sha1;
- *prefixlen = sizeof(p_sha1);
- }
-#else
- {
- verbose(VERB_QUERY, "verify: no digest algo");
- return 0;
- }
-#endif
-
- break;
-#endif /* SHA1 or SHA2 */
-
- case LDNS_RSAMD5:
- *pubkey = nss_buf2rsa(key, keylen);
- if(!*pubkey) {
- log_err("verify: malloc failure in crypto");
- return 0;
- }
- *htype = HASH_AlgMD5;
- *prefix = p_md5;
- *prefixlen = sizeof(p_md5);
-
- break;
-#ifdef USE_ECDSA
- case LDNS_ECDSAP256SHA256:
- *pubkey = nss_buf2ecdsa(key, keylen,
- LDNS_ECDSAP256SHA256);
- if(!*pubkey) {
- log_err("verify: malloc failure in crypto");
- return 0;
- }
- *htype = HASH_AlgSHA256;
- /* no prefix for DSA verification */
- break;
- case LDNS_ECDSAP384SHA384:
- *pubkey = nss_buf2ecdsa(key, keylen,
- LDNS_ECDSAP384SHA384);
- if(!*pubkey) {
- log_err("verify: malloc failure in crypto");
- return 0;
- }
- *htype = HASH_AlgSHA384;
- /* no prefix for DSA verification */
- break;
-#endif /* USE_ECDSA */
- case LDNS_ECC_GOST:
- default:
- verbose(VERB_QUERY, "verify: unknown algorithm %d",
- algo);
- return 0;
- }
- return 1;
-}
-
-/**
- * Check a canonical sig+rrset and signature against a dnskey
- * @param buf: buffer with data to verify, the first rrsig part and the
- * canonicalized rrset.
- * @param algo: DNSKEY algorithm.
- * @param sigblock: signature rdata field from RRSIG
- * @param sigblock_len: length of sigblock data.
- * @param key: public key data from DNSKEY RR.
- * @param keylen: length of keydata.
- * @param reason: bogus reason in more detail.
- * @return secure if verification succeeded, bogus on crypto failure,
- * unchecked on format errors and alloc failures.
- */
-enum sec_status
-verify_canonrrset(sldns_buffer* buf, int algo, unsigned char* sigblock,
- unsigned int sigblock_len, unsigned char* key, unsigned int keylen,
- char** reason)
-{
- /* uses libNSS */
- /* large enough for the different hashes */
- unsigned char hash[HASH_LENGTH_MAX];
- unsigned char hash2[HASH_LENGTH_MAX*2];
- HASH_HashType htype = 0;
- SECKEYPublicKey* pubkey = NULL;
- SECItem secsig = {siBuffer, sigblock, sigblock_len};
- SECItem sechash = {siBuffer, hash, 0};
- SECStatus res;
- unsigned char* prefix = NULL; /* prefix for hash, RFC3110, RFC5702 */
- size_t prefixlen = 0;
- int err;
-
- if(!nss_setup_key_digest(algo, &pubkey, &htype, key, keylen,
- &prefix, &prefixlen)) {
- verbose(VERB_QUERY, "verify: failed to setup key");
- *reason = "use of key for crypto failed";
- SECKEY_DestroyPublicKey(pubkey);
- return sec_status_bogus;
- }
-
-#if defined(USE_DSA) && defined(USE_SHA1)
- /* need to convert DSA, ECDSA signatures? */
- if((algo == LDNS_DSA || algo == LDNS_DSA_NSEC3)) {
- if(sigblock_len == 1+2*SHA1_LENGTH) {
- secsig.data ++;
- secsig.len --;
- } else {
- SECItem* p = DSAU_DecodeDerSig(&secsig);
- if(!p) {
- verbose(VERB_QUERY, "verify: failed DER decode");
- *reason = "signature DER decode failed";
- SECKEY_DestroyPublicKey(pubkey);
- return sec_status_bogus;
- }
- if(SECITEM_CopyItem(pubkey->arena, &secsig, p)) {
- log_err("alloc failure in DER decode");
- SECKEY_DestroyPublicKey(pubkey);
- SECITEM_FreeItem(p, PR_TRUE);
- return sec_status_unchecked;
- }
- SECITEM_FreeItem(p, PR_TRUE);
- }
- }
-#endif /* USE_DSA */
-
- /* do the signature cryptography work */
- /* hash the data */
- sechash.len = HASH_ResultLen(htype);
- if(sechash.len > sizeof(hash)) {
- verbose(VERB_QUERY, "verify: hash too large for buffer");
- SECKEY_DestroyPublicKey(pubkey);
- return sec_status_unchecked;
- }
- if(HASH_HashBuf(htype, hash, (unsigned char*)sldns_buffer_begin(buf),
- (unsigned int)sldns_buffer_limit(buf)) != SECSuccess) {
- verbose(VERB_QUERY, "verify: HASH_HashBuf failed");
- SECKEY_DestroyPublicKey(pubkey);
- return sec_status_unchecked;
- }
- if(prefix) {
- int hashlen = sechash.len;
- if(prefixlen+hashlen > sizeof(hash2)) {
- verbose(VERB_QUERY, "verify: hashprefix too large");
- SECKEY_DestroyPublicKey(pubkey);
- return sec_status_unchecked;
- }
- sechash.data = hash2;
- sechash.len = prefixlen+hashlen;
- memcpy(sechash.data, prefix, prefixlen);
- memmove(sechash.data+prefixlen, hash, hashlen);
- }
-
- /* verify the signature */
- res = PK11_Verify(pubkey, &secsig, &sechash, NULL /*wincx*/);
- SECKEY_DestroyPublicKey(pubkey);
-
- if(res == SECSuccess) {
- return sec_status_secure;
- }
- err = PORT_GetError();
- if(err != SEC_ERROR_BAD_SIGNATURE) {
- /* failed to verify */
- verbose(VERB_QUERY, "verify: PK11_Verify failed: %s",
- PORT_ErrorToString(err));
- /* if it is not supported, like ECC is removed, we get,
- * SEC_ERROR_NO_MODULE */
- if(err == SEC_ERROR_NO_MODULE)
- return sec_status_unchecked;
- /* but other errors are commonly returned
- * for a bad signature from NSS. Thus we return bogus,
- * not unchecked */
- *reason = "signature crypto failed";
- return sec_status_bogus;
- }
- verbose(VERB_QUERY, "verify: signature mismatch: %s",
- PORT_ErrorToString(err));
- *reason = "signature crypto failed";
- return sec_status_bogus;
-}
-
-#elif defined(HAVE_NETTLE)
-
-#include "sha.h"
-#include "bignum.h"
-#include "macros.h"
-#include "rsa.h"
-#include "dsa.h"
-#ifdef HAVE_NETTLE_DSA_COMPAT_H
-#include "dsa-compat.h"
-#endif
-#include "asn1.h"
-#ifdef USE_ECDSA
-#include "ecdsa.h"
-#include "ecc-curve.h"
-#endif
-
-static int
-_digest_nettle(int algo, uint8_t* buf, size_t len,
- unsigned char* res)
-{
- switch(algo) {
- case SHA1_DIGEST_SIZE:
- {
- struct sha1_ctx ctx;
- sha1_init(&ctx);
- sha1_update(&ctx, len, buf);
- sha1_digest(&ctx, SHA1_DIGEST_SIZE, res);
- return 1;
- }
- case SHA256_DIGEST_SIZE:
- {
- struct sha256_ctx ctx;
- sha256_init(&ctx);
- sha256_update(&ctx, len, buf);
- sha256_digest(&ctx, SHA256_DIGEST_SIZE, res);
- return 1;
- }
- case SHA384_DIGEST_SIZE:
- {
- struct sha384_ctx ctx;
- sha384_init(&ctx);
- sha384_update(&ctx, len, buf);
- sha384_digest(&ctx, SHA384_DIGEST_SIZE, res);
- return 1;
- }
- case SHA512_DIGEST_SIZE:
- {
- struct sha512_ctx ctx;
- sha512_init(&ctx);
- sha512_update(&ctx, len, buf);
- sha512_digest(&ctx, SHA512_DIGEST_SIZE, res);
- return 1;
- }
- default:
- break;
- }
- return 0;
-}
-
-/* return size of digest if supported, or 0 otherwise */
-size_t
-nsec3_hash_algo_size_supported(int id)
-{
- switch(id) {
- case NSEC3_HASH_SHA1:
- return SHA1_DIGEST_SIZE;
- default:
- return 0;
- }
-}
-
-/* perform nsec3 hash. return false on failure */
-int
-secalgo_nsec3_hash(int algo, unsigned char* buf, size_t len,
- unsigned char* res)
-{
- switch(algo) {
- case NSEC3_HASH_SHA1:
- return _digest_nettle(SHA1_DIGEST_SIZE, (uint8_t*)buf, len,
- res);
- default:
- return 0;
- }
-}
-
-void
-secalgo_hash_sha256(unsigned char* buf, size_t len, unsigned char* res)
-{
- _digest_nettle(SHA256_DIGEST_SIZE, (uint8_t*)buf, len, res);
-}
-
-/**
- * Return size of DS digest according to its hash algorithm.
- * @param algo: DS digest algo.
- * @return size in bytes of digest, or 0 if not supported.
- */
-size_t
-ds_digest_size_supported(int algo)
-{
- switch(algo) {
- case LDNS_SHA1:
-#ifdef USE_SHA1
- return SHA1_DIGEST_SIZE;
-#else
- if(fake_sha1) return 20;
- return 0;
-#endif
-#ifdef USE_SHA2
- case LDNS_SHA256:
- return SHA256_DIGEST_SIZE;
-#endif
-#ifdef USE_ECDSA
- case LDNS_SHA384:
- return SHA384_DIGEST_SIZE;
-#endif
- /* GOST not supported */
- case LDNS_HASH_GOST:
- default:
- break;
- }
- return 0;
-}
-
-int
-secalgo_ds_digest(int algo, unsigned char* buf, size_t len,
- unsigned char* res)
-{
- switch(algo) {
-#ifdef USE_SHA1
- case LDNS_SHA1:
- return _digest_nettle(SHA1_DIGEST_SIZE, buf, len, res);
-#endif
-#if defined(USE_SHA2)
- case LDNS_SHA256:
- return _digest_nettle(SHA256_DIGEST_SIZE, buf, len, res);
-#endif
-#ifdef USE_ECDSA
- case LDNS_SHA384:
- return _digest_nettle(SHA384_DIGEST_SIZE, buf, len, res);
-
-#endif
- case LDNS_HASH_GOST:
- default:
- verbose(VERB_QUERY, "unknown DS digest algorithm %d",
- algo);
- break;
- }
- return 0;
-}
-
-int
-dnskey_algo_id_is_supported(int id)
-{
- /* uses libnettle */
- switch(id) {
-#if defined(USE_DSA) && defined(USE_SHA1)
- case LDNS_DSA:
- case LDNS_DSA_NSEC3:
-#endif
-#ifdef USE_SHA1
- case LDNS_RSASHA1:
- case LDNS_RSASHA1_NSEC3:
-#endif
-#ifdef USE_SHA2
- case LDNS_RSASHA256:
- case LDNS_RSASHA512:
-#endif
-#ifdef USE_ECDSA
- case LDNS_ECDSAP256SHA256:
- case LDNS_ECDSAP384SHA384:
-#endif
- return 1;
- case LDNS_RSAMD5: /* RFC 6725 deprecates RSAMD5 */
- case LDNS_ECC_GOST:
- default:
- return 0;
- }
-}
-
-#if defined(USE_DSA) && defined(USE_SHA1)
-static char *
-_verify_nettle_dsa(sldns_buffer* buf, unsigned char* sigblock,
- unsigned int sigblock_len, unsigned char* key, unsigned int keylen)
-{
- uint8_t digest[SHA1_DIGEST_SIZE];
- uint8_t key_t_value;
- int res = 0;
- size_t offset;
- struct dsa_public_key pubkey;
- struct dsa_signature signature;
- unsigned int expected_len;
-
- /* Extract DSA signature from the record */
- nettle_dsa_signature_init(&signature);
- /* Signature length: 41 bytes - RFC 2536 sec. 3 */
- if(sigblock_len == 41) {
- if(key[0] != sigblock[0])
- return "invalid T value in DSA signature or pubkey";
- nettle_mpz_set_str_256_u(signature.r, 20, sigblock+1);
- nettle_mpz_set_str_256_u(signature.s, 20, sigblock+1+20);
- } else {
- /* DER encoded, decode the ASN1 notated R and S bignums */
- /* SEQUENCE { r INTEGER, s INTEGER } */
- struct asn1_der_iterator i, seq;
- if(asn1_der_iterator_first(&i, sigblock_len,
- (uint8_t*)sigblock) != ASN1_ITERATOR_CONSTRUCTED
- || i.type != ASN1_SEQUENCE)
- return "malformed DER encoded DSA signature";
- /* decode this element of i using the seq iterator */
- if(asn1_der_decode_constructed(&i, &seq) !=
- ASN1_ITERATOR_PRIMITIVE || seq.type != ASN1_INTEGER)
- return "malformed DER encoded DSA signature";
- if(!asn1_der_get_bignum(&seq, signature.r, 20*8))
- return "malformed DER encoded DSA signature";
- if(asn1_der_iterator_next(&seq) != ASN1_ITERATOR_PRIMITIVE
- || seq.type != ASN1_INTEGER)
- return "malformed DER encoded DSA signature";
- if(!asn1_der_get_bignum(&seq, signature.s, 20*8))
- return "malformed DER encoded DSA signature";
- if(asn1_der_iterator_next(&i) != ASN1_ITERATOR_END)
- return "malformed DER encoded DSA signature";
- }
-
- /* Validate T values constraints - RFC 2536 sec. 2 & sec. 3 */
- key_t_value = key[0];
- if (key_t_value > 8) {
- return "invalid T value in DSA pubkey";
- }
-
- /* Pubkey minimum length: 21 bytes - RFC 2536 sec. 2 */
- if (keylen < 21) {
- return "DSA pubkey too short";
- }
-
- expected_len = 1 + /* T */
- 20 + /* Q */
- (64 + key_t_value*8) + /* P */
- (64 + key_t_value*8) + /* G */
- (64 + key_t_value*8); /* Y */
- if (keylen != expected_len ) {
- return "invalid DSA pubkey length";
- }
-
- /* Extract DSA pubkey from the record */
- nettle_dsa_public_key_init(&pubkey);
- offset = 1;
- nettle_mpz_set_str_256_u(pubkey.q, 20, key+offset);
- offset += 20;
- nettle_mpz_set_str_256_u(pubkey.p, (64 + key_t_value*8), key+offset);
- offset += (64 + key_t_value*8);
- nettle_mpz_set_str_256_u(pubkey.g, (64 + key_t_value*8), key+offset);
- offset += (64 + key_t_value*8);
- nettle_mpz_set_str_256_u(pubkey.y, (64 + key_t_value*8), key+offset);
-
- /* Digest content of "buf" and verify its DSA signature in "sigblock"*/
- res = _digest_nettle(SHA1_DIGEST_SIZE, (unsigned char*)sldns_buffer_begin(buf),
- (unsigned int)sldns_buffer_limit(buf), (unsigned char*)digest);
- res &= dsa_sha1_verify_digest(&pubkey, digest, &signature);
-
- /* Clear and return */
- nettle_dsa_signature_clear(&signature);
- nettle_dsa_public_key_clear(&pubkey);
- if (!res)
- return "DSA signature verification failed";
- else
- return NULL;
-}
-#endif /* USE_DSA */
-
-static char *
-_verify_nettle_rsa(sldns_buffer* buf, unsigned int digest_size, char* sigblock,
- unsigned int sigblock_len, uint8_t* key, unsigned int keylen)
-{
- uint16_t exp_len = 0;
- size_t exp_offset = 0, mod_offset = 0;
- struct rsa_public_key pubkey;
- mpz_t signature;
- int res = 0;
-
- /* RSA pubkey parsing as per RFC 3110 sec. 2 */
- if( keylen <= 1) {
- return "null RSA key";
- }
- if (key[0] != 0) {
- /* 1-byte length */
- exp_len = key[0];
- exp_offset = 1;
- } else {
- /* 1-byte NUL + 2-bytes exponent length */
- if (keylen < 3) {
- return "incorrect RSA key length";
- }
- exp_len = READ_UINT16(key+1);
- if (exp_len == 0)
- return "null RSA exponent length";
- exp_offset = 3;
- }
- /* Check that we are not over-running input length */
- if (keylen < exp_offset + exp_len + 1) {
- return "RSA key content shorter than expected";
- }
- mod_offset = exp_offset + exp_len;
- nettle_rsa_public_key_init(&pubkey);
- pubkey.size = keylen - mod_offset;
- nettle_mpz_set_str_256_u(pubkey.e, exp_len, &key[exp_offset]);
- nettle_mpz_set_str_256_u(pubkey.n, pubkey.size, &key[mod_offset]);
-
- /* Digest content of "buf" and verify its RSA signature in "sigblock"*/
- nettle_mpz_init_set_str_256_u(signature, sigblock_len, (uint8_t*)sigblock);
- switch (digest_size) {
- case SHA1_DIGEST_SIZE:
- {
- uint8_t digest[SHA1_DIGEST_SIZE];
- res = _digest_nettle(SHA1_DIGEST_SIZE, (unsigned char*)sldns_buffer_begin(buf),
- (unsigned int)sldns_buffer_limit(buf), (unsigned char*)digest);
- res &= rsa_sha1_verify_digest(&pubkey, digest, signature);
- break;
- }
- case SHA256_DIGEST_SIZE:
- {
- uint8_t digest[SHA256_DIGEST_SIZE];
- res = _digest_nettle(SHA256_DIGEST_SIZE, (unsigned char*)sldns_buffer_begin(buf),
- (unsigned int)sldns_buffer_limit(buf), (unsigned char*)digest);
- res &= rsa_sha256_verify_digest(&pubkey, digest, signature);
- break;
- }
- case SHA512_DIGEST_SIZE:
- {
- uint8_t digest[SHA512_DIGEST_SIZE];
- res = _digest_nettle(SHA512_DIGEST_SIZE, (unsigned char*)sldns_buffer_begin(buf),
- (unsigned int)sldns_buffer_limit(buf), (unsigned char*)digest);
- res &= rsa_sha512_verify_digest(&pubkey, digest, signature);
- break;
- }
- default:
- break;
- }
-
- /* Clear and return */
- nettle_rsa_public_key_clear(&pubkey);
- mpz_clear(signature);
- if (!res) {
- return "RSA signature verification failed";
- } else {
- return NULL;
- }
-}
-
-#ifdef USE_ECDSA
-static char *
-_verify_nettle_ecdsa(sldns_buffer* buf, unsigned int digest_size, unsigned char* sigblock,
- unsigned int sigblock_len, unsigned char* key, unsigned int keylen)
-{
- int res = 0;
- struct ecc_point pubkey;
- struct dsa_signature signature;
-
- /* Always matched strength, as per RFC 6605 sec. 1 */
- if (sigblock_len != 2*digest_size || keylen != 2*digest_size) {
- return "wrong ECDSA signature length";
- }
-
- /* Parse ECDSA signature as per RFC 6605 sec. 4 */
- nettle_dsa_signature_init(&signature);
- switch (digest_size) {
- case SHA256_DIGEST_SIZE:
- {
- uint8_t digest[SHA256_DIGEST_SIZE];
- mpz_t x, y;
- nettle_ecc_point_init(&pubkey, &nettle_secp_256r1);
- nettle_mpz_init_set_str_256_u(x, SHA256_DIGEST_SIZE, key);
- nettle_mpz_init_set_str_256_u(y, SHA256_DIGEST_SIZE, key+SHA256_DIGEST_SIZE);
- nettle_mpz_set_str_256_u(signature.r, SHA256_DIGEST_SIZE, sigblock);
- nettle_mpz_set_str_256_u(signature.s, SHA256_DIGEST_SIZE, sigblock+SHA256_DIGEST_SIZE);
- res = _digest_nettle(SHA256_DIGEST_SIZE, (unsigned char*)sldns_buffer_begin(buf),
- (unsigned int)sldns_buffer_limit(buf), (unsigned char*)digest);
- res &= nettle_ecc_point_set(&pubkey, x, y);
- res &= nettle_ecdsa_verify (&pubkey, SHA256_DIGEST_SIZE, digest, &signature);
- mpz_clear(x);
- mpz_clear(y);
- break;
- }
- case SHA384_DIGEST_SIZE:
- {
- uint8_t digest[SHA384_DIGEST_SIZE];
- mpz_t x, y;
- nettle_ecc_point_init(&pubkey, &nettle_secp_384r1);
- nettle_mpz_init_set_str_256_u(x, SHA384_DIGEST_SIZE, key);
- nettle_mpz_init_set_str_256_u(y, SHA384_DIGEST_SIZE, key+SHA384_DIGEST_SIZE);
- nettle_mpz_set_str_256_u(signature.r, SHA384_DIGEST_SIZE, sigblock);
- nettle_mpz_set_str_256_u(signature.s, SHA384_DIGEST_SIZE, sigblock+SHA384_DIGEST_SIZE);
- res = _digest_nettle(SHA384_DIGEST_SIZE, (unsigned char*)sldns_buffer_begin(buf),
- (unsigned int)sldns_buffer_limit(buf), (unsigned char*)digest);
- res &= nettle_ecc_point_set(&pubkey, x, y);
- res &= nettle_ecdsa_verify (&pubkey, SHA384_DIGEST_SIZE, digest, &signature);
- mpz_clear(x);
- mpz_clear(y);
- nettle_ecc_point_clear(&pubkey);
- break;
- }
- default:
- return "unknown ECDSA algorithm";
- }
-
- /* Clear and return */
- nettle_dsa_signature_clear(&signature);
- if (!res)
- return "ECDSA signature verification failed";
- else
- return NULL;
-}
-#endif
-
-/**
- * Check a canonical sig+rrset and signature against a dnskey
- * @param buf: buffer with data to verify, the first rrsig part and the
- * canonicalized rrset.
- * @param algo: DNSKEY algorithm.
- * @param sigblock: signature rdata field from RRSIG
- * @param sigblock_len: length of sigblock data.
- * @param key: public key data from DNSKEY RR.
- * @param keylen: length of keydata.
- * @param reason: bogus reason in more detail.
- * @return secure if verification succeeded, bogus on crypto failure,
- * unchecked on format errors and alloc failures.
- */
-enum sec_status
-verify_canonrrset(sldns_buffer* buf, int algo, unsigned char* sigblock,
- unsigned int sigblock_len, unsigned char* key, unsigned int keylen,
- char** reason)
-{
- unsigned int digest_size = 0;
-
- if (sigblock_len == 0 || keylen == 0) {
- *reason = "null signature";
- return sec_status_bogus;
- }
-
- switch(algo) {
-#if defined(USE_DSA) && defined(USE_SHA1)
- case LDNS_DSA:
- case LDNS_DSA_NSEC3:
- *reason = _verify_nettle_dsa(buf, sigblock, sigblock_len, key, keylen);
- if (*reason != NULL)
- return sec_status_bogus;
- else
- return sec_status_secure;
-#endif /* USE_DSA */
-
-#ifdef USE_SHA1
- case LDNS_RSASHA1:
- case LDNS_RSASHA1_NSEC3:
- digest_size = (digest_size ? digest_size : SHA1_DIGEST_SIZE);
-#endif
-#ifdef USE_SHA2
- case LDNS_RSASHA256:
- digest_size = (digest_size ? digest_size : SHA256_DIGEST_SIZE);
- case LDNS_RSASHA512:
- digest_size = (digest_size ? digest_size : SHA512_DIGEST_SIZE);
-
-#endif
- *reason = _verify_nettle_rsa(buf, digest_size, (char*)sigblock,
- sigblock_len, key, keylen);
- if (*reason != NULL)
- return sec_status_bogus;
- else
- return sec_status_secure;
-
-#ifdef USE_ECDSA
- case LDNS_ECDSAP256SHA256:
- digest_size = (digest_size ? digest_size : SHA256_DIGEST_SIZE);
- case LDNS_ECDSAP384SHA384:
- digest_size = (digest_size ? digest_size : SHA384_DIGEST_SIZE);
- *reason = _verify_nettle_ecdsa(buf, digest_size, sigblock,
- sigblock_len, key, keylen);
- if (*reason != NULL)
- return sec_status_bogus;
- else
- return sec_status_secure;
-#endif
- case LDNS_RSAMD5:
- case LDNS_ECC_GOST:
- default:
- *reason = "unable to verify signature, unknown algorithm";
- return sec_status_bogus;
- }
-}
-
-#endif /* HAVE_SSL or HAVE_NSS or HAVE_NETTLE */
diff --git a/external/unbound/validator/val_secalgo.h b/external/unbound/validator/val_secalgo.h
deleted file mode 100644
index 52aaeb9f6..000000000
--- a/external/unbound/validator/val_secalgo.h
+++ /dev/null
@@ -1,107 +0,0 @@
-/*
- * validator/val_secalgo.h - validator security algorithm functions.
- *
- * Copyright (c) 2012, NLnet Labs. All rights reserved.
- *
- * This software is open source.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- *
- * Redistributions of source code must retain the above copyright notice,
- * this list of conditions and the following disclaimer.
- *
- * Redistributions in binary form must reproduce the above copyright notice,
- * this list of conditions and the following disclaimer in the documentation
- * and/or other materials provided with the distribution.
- *
- * Neither the name of the NLNET LABS nor the names of its contributors may
- * be used to endorse or promote products derived from this software without
- * specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
- * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
- * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
- * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
- * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
- * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-/**
- * \file
- *
- * This file contains helper functions for the validator module.
- * The functions take buffers with raw data and convert to library calls.
- */
-
-#ifndef VALIDATOR_VAL_SECALGO_H
-#define VALIDATOR_VAL_SECALGO_H
-struct sldns_buffer;
-
-/** Return size of nsec3 hash algorithm, 0 if not supported */
-size_t nsec3_hash_algo_size_supported(int id);
-
-/**
- * Hash a single hash call of an NSEC3 hash algorithm.
- * Iterations and salt are done by the caller.
- * @param algo: nsec3 hash algorithm.
- * @param buf: the buffer to digest
- * @param len: length of buffer to digest.
- * @param res: result stored here (must have sufficient space).
- * @return false on failure.
-*/
-int secalgo_nsec3_hash(int algo, unsigned char* buf, size_t len,
- unsigned char* res);
-
-/**
- * Calculate the sha256 hash for the data buffer into the result.
- * @param buf: buffer to digest.
- * @param len: length of the buffer to digest.
- * @param res: result is stored here (space 256/8 bytes).
- */
-void secalgo_hash_sha256(unsigned char* buf, size_t len, unsigned char* res);
-
-/**
- * Return size of DS digest according to its hash algorithm.
- * @param algo: DS digest algo.
- * @return size in bytes of digest, or 0 if not supported.
- */
-size_t ds_digest_size_supported(int algo);
-
-/**
- * @param algo: the DS digest algo
- * @param buf: the buffer to digest
- * @param len: length of buffer to digest.
- * @param res: result stored here (must have sufficient space).
- * @return false on failure.
- */
-int secalgo_ds_digest(int algo, unsigned char* buf, size_t len,
- unsigned char* res);
-
-/** return true if DNSKEY algorithm id is supported */
-int dnskey_algo_id_is_supported(int id);
-
-/**
- * Check a canonical sig+rrset and signature against a dnskey
- * @param buf: buffer with data to verify, the first rrsig part and the
- * canonicalized rrset.
- * @param algo: DNSKEY algorithm.
- * @param sigblock: signature rdata field from RRSIG
- * @param sigblock_len: length of sigblock data.
- * @param key: public key data from DNSKEY RR.
- * @param keylen: length of keydata.
- * @param reason: bogus reason in more detail.
- * @return secure if verification succeeded, bogus on crypto failure,
- * unchecked on format errors and alloc failures.
- */
-enum sec_status verify_canonrrset(struct sldns_buffer* buf, int algo,
- unsigned char* sigblock, unsigned int sigblock_len,
- unsigned char* key, unsigned int keylen, char** reason);
-
-#endif /* VALIDATOR_VAL_SECALGO_H */
diff --git a/external/unbound/validator/val_sigcrypt.c b/external/unbound/validator/val_sigcrypt.c
deleted file mode 100644
index 25278a8f3..000000000
--- a/external/unbound/validator/val_sigcrypt.c
+++ /dev/null
@@ -1,1451 +0,0 @@
-/*
- * validator/val_sigcrypt.c - validator signature crypto functions.
- *
- * Copyright (c) 2007, NLnet Labs. All rights reserved.
- *
- * This software is open source.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- *
- * Redistributions of source code must retain the above copyright notice,
- * this list of conditions and the following disclaimer.
- *
- * Redistributions in binary form must reproduce the above copyright notice,
- * this list of conditions and the following disclaimer in the documentation
- * and/or other materials provided with the distribution.
- *
- * Neither the name of the NLNET LABS nor the names of its contributors may
- * be used to endorse or promote products derived from this software without
- * specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
- * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
- * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
- * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
- * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
- * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-/**
- * \file
- *
- * This file contains helper functions for the validator module.
- * The functions help with signature verification and checking, the
- * bridging between RR wireformat data and crypto calls.
- */
-#include "config.h"
-#include "validator/val_sigcrypt.h"
-#include "validator/val_secalgo.h"
-#include "validator/validator.h"
-#include "util/data/msgreply.h"
-#include "util/data/msgparse.h"
-#include "util/data/dname.h"
-#include "util/rbtree.h"
-#include "util/module.h"
-#include "util/net_help.h"
-#include "util/regional.h"
-#include "util/config_file.h"
-#include "sldns/keyraw.h"
-#include "sldns/sbuffer.h"
-#include "sldns/parseutil.h"
-#include "sldns/wire2str.h"
-
-#include <ctype.h>
-#if !defined(HAVE_SSL) && !defined(HAVE_NSS) && !defined(HAVE_NETTLE)
-#error "Need crypto library to do digital signature cryptography"
-#endif
-
-#ifdef HAVE_OPENSSL_ERR_H
-#include <openssl/err.h>
-#endif
-
-#ifdef HAVE_OPENSSL_RAND_H
-#include <openssl/rand.h>
-#endif
-
-#ifdef HAVE_OPENSSL_CONF_H
-#include <openssl/conf.h>
-#endif
-
-#ifdef HAVE_OPENSSL_ENGINE_H
-#include <openssl/engine.h>
-#endif
-
-/** return number of rrs in an rrset */
-static size_t
-rrset_get_count(struct ub_packed_rrset_key* rrset)
-{
- struct packed_rrset_data* d = (struct packed_rrset_data*)
- rrset->entry.data;
- if(!d) return 0;
- return d->count;
-}
-
-/**
- * Get RR signature count
- */
-static size_t
-rrset_get_sigcount(struct ub_packed_rrset_key* k)
-{
- struct packed_rrset_data* d = (struct packed_rrset_data*)k->entry.data;
- return d->rrsig_count;
-}
-
-/**
- * Get signature keytag value
- * @param k: rrset (with signatures)
- * @param sig_idx: signature index.
- * @return keytag or 0 if malformed rrsig.
- */
-static uint16_t
-rrset_get_sig_keytag(struct ub_packed_rrset_key* k, size_t sig_idx)
-{
- uint16_t t;
- struct packed_rrset_data* d = (struct packed_rrset_data*)k->entry.data;
- log_assert(sig_idx < d->rrsig_count);
- if(d->rr_len[d->count + sig_idx] < 2+18)
- return 0;
- memmove(&t, d->rr_data[d->count + sig_idx]+2+16, 2);
- return ntohs(t);
-}
-
-/**
- * Get signature signing algorithm value
- * @param k: rrset (with signatures)
- * @param sig_idx: signature index.
- * @return algo or 0 if malformed rrsig.
- */
-static int
-rrset_get_sig_algo(struct ub_packed_rrset_key* k, size_t sig_idx)
-{
- struct packed_rrset_data* d = (struct packed_rrset_data*)k->entry.data;
- log_assert(sig_idx < d->rrsig_count);
- if(d->rr_len[d->count + sig_idx] < 2+3)
- return 0;
- return (int)d->rr_data[d->count + sig_idx][2+2];
-}
-
-/** get rdata pointer and size */
-static void
-rrset_get_rdata(struct ub_packed_rrset_key* k, size_t idx, uint8_t** rdata,
- size_t* len)
-{
- struct packed_rrset_data* d = (struct packed_rrset_data*)k->entry.data;
- log_assert(d && idx < (d->count + d->rrsig_count));
- *rdata = d->rr_data[idx];
- *len = d->rr_len[idx];
-}
-
-uint16_t
-dnskey_get_flags(struct ub_packed_rrset_key* k, size_t idx)
-{
- uint8_t* rdata;
- size_t len;
- uint16_t f;
- rrset_get_rdata(k, idx, &rdata, &len);
- if(len < 2+2)
- return 0;
- memmove(&f, rdata+2, 2);
- f = ntohs(f);
- return f;
-}
-
-/**
- * Get DNSKEY protocol value from rdata
- * @param k: DNSKEY rrset.
- * @param idx: which key.
- * @return protocol octet value
- */
-static int
-dnskey_get_protocol(struct ub_packed_rrset_key* k, size_t idx)
-{
- uint8_t* rdata;
- size_t len;
- rrset_get_rdata(k, idx, &rdata, &len);
- if(len < 2+4)
- return 0;
- return (int)rdata[2+2];
-}
-
-int
-dnskey_get_algo(struct ub_packed_rrset_key* k, size_t idx)
-{
- uint8_t* rdata;
- size_t len;
- rrset_get_rdata(k, idx, &rdata, &len);
- if(len < 2+4)
- return 0;
- return (int)rdata[2+3];
-}
-
-/** get public key rdata field from a dnskey RR and do some checks */
-static void
-dnskey_get_pubkey(struct ub_packed_rrset_key* k, size_t idx,
- unsigned char** pk, unsigned int* pklen)
-{
- uint8_t* rdata;
- size_t len;
- rrset_get_rdata(k, idx, &rdata, &len);
- if(len < 2+5) {
- *pk = NULL;
- *pklen = 0;
- return;
- }
- *pk = (unsigned char*)rdata+2+4;
- *pklen = (unsigned)len-2-4;
-}
-
-int
-ds_get_key_algo(struct ub_packed_rrset_key* k, size_t idx)
-{
- uint8_t* rdata;
- size_t len;
- rrset_get_rdata(k, idx, &rdata, &len);
- if(len < 2+3)
- return 0;
- return (int)rdata[2+2];
-}
-
-int
-ds_get_digest_algo(struct ub_packed_rrset_key* k, size_t idx)
-{
- uint8_t* rdata;
- size_t len;
- rrset_get_rdata(k, idx, &rdata, &len);
- if(len < 2+4)
- return 0;
- return (int)rdata[2+3];
-}
-
-uint16_t
-ds_get_keytag(struct ub_packed_rrset_key* ds_rrset, size_t ds_idx)
-{
- uint16_t t;
- uint8_t* rdata;
- size_t len;
- rrset_get_rdata(ds_rrset, ds_idx, &rdata, &len);
- if(len < 2+2)
- return 0;
- memmove(&t, rdata+2, 2);
- return ntohs(t);
-}
-
-/**
- * Return pointer to the digest in a DS RR.
- * @param k: DS rrset.
- * @param idx: which DS.
- * @param digest: digest data is returned.
- * on error, this is NULL.
- * @param len: length of digest is returned.
- * on error, the length is 0.
- */
-static void
-ds_get_sigdata(struct ub_packed_rrset_key* k, size_t idx, uint8_t** digest,
- size_t* len)
-{
- uint8_t* rdata;
- size_t rdlen;
- rrset_get_rdata(k, idx, &rdata, &rdlen);
- if(rdlen < 2+5) {
- *digest = NULL;
- *len = 0;
- return;
- }
- *digest = rdata + 2 + 4;
- *len = rdlen - 2 - 4;
-}
-
-/**
- * Return size of DS digest according to its hash algorithm.
- * @param k: DS rrset.
- * @param idx: which DS.
- * @return size in bytes of digest, or 0 if not supported.
- */
-static size_t
-ds_digest_size_algo(struct ub_packed_rrset_key* k, size_t idx)
-{
- return ds_digest_size_supported(ds_get_digest_algo(k, idx));
-}
-
-/**
- * Create a DS digest for a DNSKEY entry.
- *
- * @param env: module environment. Uses scratch space.
- * @param dnskey_rrset: DNSKEY rrset.
- * @param dnskey_idx: index of RR in rrset.
- * @param ds_rrset: DS rrset
- * @param ds_idx: index of RR in DS rrset.
- * @param digest: digest is returned in here (must be correctly sized).
- * @return false on error.
- */
-static int
-ds_create_dnskey_digest(struct module_env* env,
- struct ub_packed_rrset_key* dnskey_rrset, size_t dnskey_idx,
- struct ub_packed_rrset_key* ds_rrset, size_t ds_idx,
- uint8_t* digest)
-{
- sldns_buffer* b = env->scratch_buffer;
- uint8_t* dnskey_rdata;
- size_t dnskey_len;
- rrset_get_rdata(dnskey_rrset, dnskey_idx, &dnskey_rdata, &dnskey_len);
-
- /* create digest source material in buffer
- * digest = digest_algorithm( DNSKEY owner name | DNSKEY RDATA);
- * DNSKEY RDATA = Flags | Protocol | Algorithm | Public Key. */
- sldns_buffer_clear(b);
- sldns_buffer_write(b, dnskey_rrset->rk.dname,
- dnskey_rrset->rk.dname_len);
- query_dname_tolower(sldns_buffer_begin(b));
- sldns_buffer_write(b, dnskey_rdata+2, dnskey_len-2); /* skip rdatalen*/
- sldns_buffer_flip(b);
-
- return secalgo_ds_digest(ds_get_digest_algo(ds_rrset, ds_idx),
- (unsigned char*)sldns_buffer_begin(b), sldns_buffer_limit(b),
- (unsigned char*)digest);
-}
-
-int ds_digest_match_dnskey(struct module_env* env,
- struct ub_packed_rrset_key* dnskey_rrset, size_t dnskey_idx,
- struct ub_packed_rrset_key* ds_rrset, size_t ds_idx)
-{
- uint8_t* ds; /* DS digest */
- size_t dslen;
- uint8_t* digest; /* generated digest */
- size_t digestlen = ds_digest_size_algo(ds_rrset, ds_idx);
-
- if(digestlen == 0) {
- verbose(VERB_QUERY, "DS fail: not supported, or DS RR "
- "format error");
- return 0; /* not supported, or DS RR format error */
- }
-#ifndef USE_SHA1
- if(fake_sha1 && ds_get_digest_algo(ds_rrset, ds_idx)==LDNS_SHA1)
- return 1;
-#endif
-
- /* check digest length in DS with length from hash function */
- ds_get_sigdata(ds_rrset, ds_idx, &ds, &dslen);
- if(!ds || dslen != digestlen) {
- verbose(VERB_QUERY, "DS fail: DS RR algo and digest do not "
- "match each other");
- return 0; /* DS algorithm and digest do not match */
- }
-
- digest = regional_alloc(env->scratch, digestlen);
- if(!digest) {
- verbose(VERB_QUERY, "DS fail: out of memory");
- return 0; /* mem error */
- }
- if(!ds_create_dnskey_digest(env, dnskey_rrset, dnskey_idx, ds_rrset,
- ds_idx, digest)) {
- verbose(VERB_QUERY, "DS fail: could not calc key digest");
- return 0; /* digest algo failed */
- }
- if(memcmp(digest, ds, dslen) != 0) {
- verbose(VERB_QUERY, "DS fail: digest is different");
- return 0; /* digest different */
- }
- return 1;
-}
-
-int
-ds_digest_algo_is_supported(struct ub_packed_rrset_key* ds_rrset,
- size_t ds_idx)
-{
- return (ds_digest_size_algo(ds_rrset, ds_idx) != 0);
-}
-
-int
-ds_key_algo_is_supported(struct ub_packed_rrset_key* ds_rrset,
- size_t ds_idx)
-{
- return dnskey_algo_id_is_supported(ds_get_key_algo(ds_rrset, ds_idx));
-}
-
-uint16_t
-dnskey_calc_keytag(struct ub_packed_rrset_key* dnskey_rrset, size_t dnskey_idx)
-{
- uint8_t* data;
- size_t len;
- rrset_get_rdata(dnskey_rrset, dnskey_idx, &data, &len);
- /* do not pass rdatalen to ldns */
- return sldns_calc_keytag_raw(data+2, len-2);
-}
-
-int dnskey_algo_is_supported(struct ub_packed_rrset_key* dnskey_rrset,
- size_t dnskey_idx)
-{
- return dnskey_algo_id_is_supported(dnskey_get_algo(dnskey_rrset,
- dnskey_idx));
-}
-
-void algo_needs_init_dnskey_add(struct algo_needs* n,
- struct ub_packed_rrset_key* dnskey, uint8_t* sigalg)
-{
- uint8_t algo;
- size_t i, total = n->num;
- size_t num = rrset_get_count(dnskey);
-
- for(i=0; i<num; i++) {
- algo = (uint8_t)dnskey_get_algo(dnskey, i);
- if(!dnskey_algo_id_is_supported((int)algo))
- continue;
- if(n->needs[algo] == 0) {
- n->needs[algo] = 1;
- sigalg[total] = algo;
- total++;
- }
- }
- sigalg[total] = 0;
- n->num = total;
-}
-
-void algo_needs_init_list(struct algo_needs* n, uint8_t* sigalg)
-{
- uint8_t algo;
- size_t total = 0;
-
- memset(n->needs, 0, sizeof(uint8_t)*ALGO_NEEDS_MAX);
- while( (algo=*sigalg++) != 0) {
- log_assert(dnskey_algo_id_is_supported((int)algo));
- log_assert(n->needs[algo] == 0);
- n->needs[algo] = 1;
- total++;
- }
- n->num = total;
-}
-
-void algo_needs_init_ds(struct algo_needs* n, struct ub_packed_rrset_key* ds,
- int fav_ds_algo, uint8_t* sigalg)
-{
- uint8_t algo;
- size_t i, total = 0;
- size_t num = rrset_get_count(ds);
-
- memset(n->needs, 0, sizeof(uint8_t)*ALGO_NEEDS_MAX);
- for(i=0; i<num; i++) {
- if(ds_get_digest_algo(ds, i) != fav_ds_algo)
- continue;
- algo = (uint8_t)ds_get_key_algo(ds, i);
- if(!dnskey_algo_id_is_supported((int)algo))
- continue;
- log_assert(algo != 0); /* we do not support 0 and is EOS */
- if(n->needs[algo] == 0) {
- n->needs[algo] = 1;
- sigalg[total] = algo;
- total++;
- }
- }
- sigalg[total] = 0;
- n->num = total;
-}
-
-int algo_needs_set_secure(struct algo_needs* n, uint8_t algo)
-{
- if(n->needs[algo]) {
- n->needs[algo] = 0;
- n->num --;
- if(n->num == 0) /* done! */
- return 1;
- }
- return 0;
-}
-
-void algo_needs_set_bogus(struct algo_needs* n, uint8_t algo)
-{
- if(n->needs[algo]) n->needs[algo] = 2; /* need it, but bogus */
-}
-
-size_t algo_needs_num_missing(struct algo_needs* n)
-{
- return n->num;
-}
-
-int algo_needs_missing(struct algo_needs* n)
-{
- int i;
- /* first check if a needed algo was bogus - report that */
- for(i=0; i<ALGO_NEEDS_MAX; i++)
- if(n->needs[i] == 2)
- return 0;
- /* now check which algo is missing */
- for(i=0; i<ALGO_NEEDS_MAX; i++)
- if(n->needs[i] == 1)
- return i;
- return 0;
-}
-
-enum sec_status
-dnskeyset_verify_rrset(struct module_env* env, struct val_env* ve,
- struct ub_packed_rrset_key* rrset, struct ub_packed_rrset_key* dnskey,
- uint8_t* sigalg, char** reason)
-{
- enum sec_status sec;
- size_t i, num;
- rbtree_type* sortree = NULL;
- /* make sure that for all DNSKEY algorithms there are valid sigs */
- struct algo_needs needs;
- int alg;
-
- num = rrset_get_sigcount(rrset);
- if(num == 0) {
- verbose(VERB_QUERY, "rrset failed to verify due to a lack of "
- "signatures");
- *reason = "no signatures";
- return sec_status_bogus;
- }
-
- if(sigalg) {
- algo_needs_init_list(&needs, sigalg);
- if(algo_needs_num_missing(&needs) == 0) {
- verbose(VERB_QUERY, "zone has no known algorithms");
- *reason = "zone has no known algorithms";
- return sec_status_insecure;
- }
- }
- for(i=0; i<num; i++) {
- sec = dnskeyset_verify_rrset_sig(env, ve, *env->now, rrset,
- dnskey, i, &sortree, reason);
- /* see which algorithm has been fixed up */
- if(sec == sec_status_secure) {
- if(!sigalg)
- return sec; /* done! */
- else if(algo_needs_set_secure(&needs,
- (uint8_t)rrset_get_sig_algo(rrset, i)))
- return sec; /* done! */
- } else if(sigalg && sec == sec_status_bogus) {
- algo_needs_set_bogus(&needs,
- (uint8_t)rrset_get_sig_algo(rrset, i));
- }
- }
- if(sigalg && (alg=algo_needs_missing(&needs)) != 0) {
- verbose(VERB_ALGO, "rrset failed to verify: "
- "no valid signatures for %d algorithms",
- (int)algo_needs_num_missing(&needs));
- algo_needs_reason(env, alg, reason, "no signatures");
- } else {
- verbose(VERB_ALGO, "rrset failed to verify: "
- "no valid signatures");
- }
- return sec_status_bogus;
-}
-
-void algo_needs_reason(struct module_env* env, int alg, char** reason, char* s)
-{
- char buf[256];
- sldns_lookup_table *t = sldns_lookup_by_id(sldns_algorithms, alg);
- if(t&&t->name)
- snprintf(buf, sizeof(buf), "%s with algorithm %s", s, t->name);
- else snprintf(buf, sizeof(buf), "%s with algorithm ALG%u", s,
- (unsigned)alg);
- *reason = regional_strdup(env->scratch, buf);
- if(!*reason)
- *reason = s;
-}
-
-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, char** reason)
-{
- enum sec_status sec;
- size_t i, num, numchecked = 0;
- rbtree_type* sortree = NULL;
- int buf_canon = 0;
- uint16_t tag = dnskey_calc_keytag(dnskey, dnskey_idx);
- int algo = dnskey_get_algo(dnskey, dnskey_idx);
-
- num = rrset_get_sigcount(rrset);
- if(num == 0) {
- verbose(VERB_QUERY, "rrset failed to verify due to a lack of "
- "signatures");
- *reason = "no signatures";
- return sec_status_bogus;
- }
- for(i=0; i<num; i++) {
- /* see if sig matches keytag and algo */
- if(algo != rrset_get_sig_algo(rrset, i) ||
- tag != rrset_get_sig_keytag(rrset, i))
- continue;
- buf_canon = 0;
- sec = dnskey_verify_rrset_sig(env->scratch,
- env->scratch_buffer, ve, *env->now, rrset,
- dnskey, dnskey_idx, i, &sortree, &buf_canon, reason);
- if(sec == sec_status_secure)
- return sec;
- numchecked ++;
- }
- verbose(VERB_ALGO, "rrset failed to verify: all signatures are bogus");
- if(!numchecked) *reason = "signature missing";
- return sec_status_bogus;
-}
-
-enum sec_status
-dnskeyset_verify_rrset_sig(struct module_env* env, struct val_env* ve,
- time_t now, struct ub_packed_rrset_key* rrset,
- struct ub_packed_rrset_key* dnskey, size_t sig_idx,
- struct rbtree_type** sortree, char** reason)
-{
- /* find matching keys and check them */
- enum sec_status sec = sec_status_bogus;
- uint16_t tag = rrset_get_sig_keytag(rrset, sig_idx);
- 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);
- if(!dnskey_algo_id_is_supported(algo)) {
- verbose(VERB_QUERY, "verify sig: unknown algorithm");
- return sec_status_insecure;
- }
-
- for(i=0; i<num; i++) {
- /* see if key matches keytag and algo */
- if(algo != dnskey_get_algo(dnskey, i) ||
- tag != dnskey_calc_keytag(dnskey, i))
- continue;
- numchecked ++;
-
- /* see if key verifies */
- sec = dnskey_verify_rrset_sig(env->scratch,
- env->scratch_buffer, ve, now, rrset, dnskey, i,
- sig_idx, sortree, &buf_canon, reason);
- if(sec == sec_status_secure)
- return sec;
- }
- if(numchecked == 0) {
- *reason = "signatures from unknown keys";
- verbose(VERB_QUERY, "verify: could not find appropriate key");
- return sec_status_bogus;
- }
- return sec_status_bogus;
-}
-
-/**
- * RR entries in a canonical sorted tree of RRs
- */
-struct canon_rr {
- /** rbtree node, key is this structure */
- rbnode_type node;
- /** rrset the RR is in */
- struct ub_packed_rrset_key* rrset;
- /** which RR in the rrset */
- size_t rr_idx;
-};
-
-/**
- * Compare two RR for canonical order, in a field-style sweep.
- * @param d: rrset data
- * @param desc: ldns wireformat descriptor.
- * @param i: first RR to compare
- * @param j: first RR to compare
- * @return comparison code.
- */
-static int
-canonical_compare_byfield(struct packed_rrset_data* d,
- const sldns_rr_descriptor* desc, size_t i, size_t j)
-{
- /* sweep across rdata, keep track of some state:
- * which rr field, and bytes left in field.
- * current position in rdata, length left.
- * are we in a dname, length left in a label.
- */
- int wfi = -1; /* current wireformat rdata field (rdf) */
- int wfj = -1;
- uint8_t* di = d->rr_data[i]+2; /* ptr to current rdata byte */
- uint8_t* dj = d->rr_data[j]+2;
- size_t ilen = d->rr_len[i]-2; /* length left in rdata */
- size_t jlen = d->rr_len[j]-2;
- int dname_i = 0; /* true if these bytes are part of a name */
- int dname_j = 0;
- size_t lablen_i = 0; /* 0 for label length byte,for first byte of rdf*/
- size_t lablen_j = 0; /* otherwise remaining length of rdf or label */
- int dname_num_i = (int)desc->_dname_count; /* decreased at root label */
- int dname_num_j = (int)desc->_dname_count;
-
- /* loop while there are rdata bytes available for both rrs,
- * and still some lowercasing needs to be done; either the dnames
- * have not been reached yet, or they are currently being processed */
- while(ilen > 0 && jlen > 0 && (dname_num_i > 0 || dname_num_j > 0)) {
- /* compare these two bytes */
- /* lowercase if in a dname and not a label length byte */
- if( ((dname_i && lablen_i)?(uint8_t)tolower((int)*di):*di)
- != ((dname_j && lablen_j)?(uint8_t)tolower((int)*dj):*dj)
- ) {
- if(((dname_i && lablen_i)?(uint8_t)tolower((int)*di):*di)
- < ((dname_j && lablen_j)?(uint8_t)tolower((int)*dj):*dj))
- return -1;
- return 1;
- }
- ilen--;
- jlen--;
- /* bytes are equal */
-
- /* advance field i */
- /* lablen 0 means that this byte is the first byte of the
- * next rdata field; inspect this rdata field and setup
- * to process the rest of this rdata field.
- * The reason to first read the byte, then setup the rdf,
- * is that we are then sure the byte is available and short
- * rdata is handled gracefully (even if it is a formerr). */
- if(lablen_i == 0) {
- if(dname_i) {
- /* scan this dname label */
- /* capture length to lowercase */
- lablen_i = (size_t)*di;
- if(lablen_i == 0) {
- /* end root label */
- dname_i = 0;
- dname_num_i--;
- /* if dname num is 0, then the
- * remainder is binary only */
- if(dname_num_i == 0)
- lablen_i = ilen;
- }
- } else {
- /* scan this rdata field */
- wfi++;
- if(desc->_wireformat[wfi]
- == LDNS_RDF_TYPE_DNAME) {
- dname_i = 1;
- lablen_i = (size_t)*di;
- if(lablen_i == 0) {
- dname_i = 0;
- dname_num_i--;
- if(dname_num_i == 0)
- lablen_i = ilen;
- }
- } else if(desc->_wireformat[wfi]
- == LDNS_RDF_TYPE_STR)
- lablen_i = (size_t)*di;
- else lablen_i = get_rdf_size(
- desc->_wireformat[wfi]) - 1;
- }
- } else lablen_i--;
-
- /* advance field j; same as for i */
- if(lablen_j == 0) {
- if(dname_j) {
- lablen_j = (size_t)*dj;
- if(lablen_j == 0) {
- dname_j = 0;
- dname_num_j--;
- if(dname_num_j == 0)
- lablen_j = jlen;
- }
- } else {
- wfj++;
- if(desc->_wireformat[wfj]
- == LDNS_RDF_TYPE_DNAME) {
- dname_j = 1;
- lablen_j = (size_t)*dj;
- if(lablen_j == 0) {
- dname_j = 0;
- dname_num_j--;
- if(dname_num_j == 0)
- lablen_j = jlen;
- }
- } else if(desc->_wireformat[wfj]
- == LDNS_RDF_TYPE_STR)
- lablen_j = (size_t)*dj;
- else lablen_j = get_rdf_size(
- desc->_wireformat[wfj]) - 1;
- }
- } else lablen_j--;
- di++;
- dj++;
- }
- /* end of the loop; because we advanced byte by byte; now we have
- * that the rdata has ended, or that there is a binary remainder */
- /* shortest first */
- if(ilen == 0 && jlen == 0)
- return 0;
- if(ilen == 0)
- return -1;
- if(jlen == 0)
- return 1;
- /* binary remainder, capture comparison in wfi variable */
- if((wfi = memcmp(di, dj, (ilen<jlen)?ilen:jlen)) != 0)
- return wfi;
- if(ilen < jlen)
- return -1;
- if(jlen < ilen)
- return 1;
- return 0;
-}
-
-/**
- * Compare two RRs in the same RRset and determine their relative
- * canonical order.
- * @param rrset: the rrset in which to perform compares.
- * @param i: first RR to compare
- * @param j: first RR to compare
- * @return 0 if RR i== RR j, -1 if <, +1 if >.
- */
-static int
-canonical_compare(struct ub_packed_rrset_key* rrset, size_t i, size_t j)
-{
- struct packed_rrset_data* d = (struct packed_rrset_data*)
- rrset->entry.data;
- const sldns_rr_descriptor* desc;
- uint16_t type = ntohs(rrset->rk.type);
- size_t minlen;
- int c;
-
- if(i==j)
- return 0;
-
- switch(type) {
- /* These RR types have only a name as RDATA.
- * This name has to be canonicalized.*/
- case LDNS_RR_TYPE_NS:
- case LDNS_RR_TYPE_MD:
- case LDNS_RR_TYPE_MF:
- case LDNS_RR_TYPE_CNAME:
- case LDNS_RR_TYPE_MB:
- case LDNS_RR_TYPE_MG:
- case LDNS_RR_TYPE_MR:
- case LDNS_RR_TYPE_PTR:
- case LDNS_RR_TYPE_DNAME:
- /* the wireread function has already checked these
- * dname's for correctness, and this double checks */
- if(!dname_valid(d->rr_data[i]+2, d->rr_len[i]-2) ||
- !dname_valid(d->rr_data[j]+2, d->rr_len[j]-2))
- return 0;
- return query_dname_compare(d->rr_data[i]+2,
- d->rr_data[j]+2);
-
- /* These RR types have STR and fixed size rdata fields
- * before one or more name fields that need canonicalizing,
- * and after that a byte-for byte remainder can be compared.
- */
- /* type starts with the name; remainder is binary compared */
- case LDNS_RR_TYPE_NXT:
- /* use rdata field formats */
- case LDNS_RR_TYPE_MINFO:
- case LDNS_RR_TYPE_RP:
- case LDNS_RR_TYPE_SOA:
- case LDNS_RR_TYPE_RT:
- case LDNS_RR_TYPE_AFSDB:
- case LDNS_RR_TYPE_KX:
- case LDNS_RR_TYPE_MX:
- case LDNS_RR_TYPE_SIG:
- /* RRSIG signer name has to be downcased */
- case LDNS_RR_TYPE_RRSIG:
- case LDNS_RR_TYPE_PX:
- case LDNS_RR_TYPE_NAPTR:
- case LDNS_RR_TYPE_SRV:
- desc = sldns_rr_descript(type);
- log_assert(desc);
- /* this holds for the types that need canonicalizing */
- log_assert(desc->_minimum == desc->_maximum);
- return canonical_compare_byfield(d, desc, i, j);
-
- case LDNS_RR_TYPE_HINFO: /* no longer downcased */
- case LDNS_RR_TYPE_NSEC:
- default:
- /* For unknown RR types, or types not listed above,
- * no canonicalization is needed, do binary compare */
- /* byte for byte compare, equal means shortest first*/
- minlen = d->rr_len[i]-2;
- if(minlen > d->rr_len[j]-2)
- minlen = d->rr_len[j]-2;
- c = memcmp(d->rr_data[i]+2, d->rr_data[j]+2, minlen);
- if(c!=0)
- return c;
- /* rdata equal, shortest is first */
- if(d->rr_len[i] < d->rr_len[j])
- return -1;
- if(d->rr_len[i] > d->rr_len[j])
- return 1;
- /* rdata equal, length equal */
- break;
- }
- return 0;
-}
-
-int
-canonical_tree_compare(const void* k1, const void* k2)
-{
- struct canon_rr* r1 = (struct canon_rr*)k1;
- struct canon_rr* r2 = (struct canon_rr*)k2;
- log_assert(r1->rrset == r2->rrset);
- return canonical_compare(r1->rrset, r1->rr_idx, r2->rr_idx);
-}
-
-/**
- * Sort RRs for rrset in canonical order.
- * Does not actually canonicalize the RR rdatas.
- * Does not touch rrsigs.
- * @param rrset: to sort.
- * @param d: rrset data.
- * @param sortree: tree to sort into.
- * @param rrs: rr storage.
- */
-static void
-canonical_sort(struct ub_packed_rrset_key* rrset, struct packed_rrset_data* d,
- rbtree_type* sortree, struct canon_rr* rrs)
-{
- size_t i;
- /* insert into rbtree to sort and detect duplicates */
- for(i=0; i<d->count; i++) {
- rrs[i].node.key = &rrs[i];
- rrs[i].rrset = rrset;
- rrs[i].rr_idx = i;
- if(!rbtree_insert(sortree, &rrs[i].node)) {
- /* this was a duplicate */
- }
- }
-}
-
-/**
- * Inser canonical owner name into buffer.
- * @param buf: buffer to insert into at current position.
- * @param k: rrset with its owner name.
- * @param sig: signature with signer name and label count.
- * must be length checked, at least 18 bytes long.
- * @param can_owner: position in buffer returned for future use.
- * @param can_owner_len: length of canonical owner name.
- */
-static void
-insert_can_owner(sldns_buffer* buf, struct ub_packed_rrset_key* k,
- uint8_t* sig, uint8_t** can_owner, size_t* can_owner_len)
-{
- int rrsig_labels = (int)sig[3];
- int fqdn_labels = dname_signame_label_count(k->rk.dname);
- *can_owner = sldns_buffer_current(buf);
- if(rrsig_labels == fqdn_labels) {
- /* no change */
- sldns_buffer_write(buf, k->rk.dname, k->rk.dname_len);
- query_dname_tolower(*can_owner);
- *can_owner_len = k->rk.dname_len;
- return;
- }
- log_assert(rrsig_labels < fqdn_labels);
- /* *. | fqdn(rightmost rrsig_labels) */
- if(rrsig_labels < fqdn_labels) {
- int i;
- uint8_t* nm = k->rk.dname;
- size_t len = k->rk.dname_len;
- /* so skip fqdn_labels-rrsig_labels */
- for(i=0; i<fqdn_labels-rrsig_labels; i++) {
- dname_remove_label(&nm, &len);
- }
- *can_owner_len = len+2;
- sldns_buffer_write(buf, (uint8_t*)"\001*", 2);
- sldns_buffer_write(buf, nm, len);
- query_dname_tolower(*can_owner);
- }
-}
-
-/**
- * Canonicalize Rdata in buffer.
- * @param buf: buffer at position just after the rdata.
- * @param rrset: rrset with type.
- * @param len: length of the rdata (including rdatalen uint16).
- */
-static void
-canonicalize_rdata(sldns_buffer* buf, struct ub_packed_rrset_key* rrset,
- size_t len)
-{
- uint8_t* datstart = sldns_buffer_current(buf)-len+2;
- switch(ntohs(rrset->rk.type)) {
- case LDNS_RR_TYPE_NXT:
- case LDNS_RR_TYPE_NS:
- case LDNS_RR_TYPE_MD:
- case LDNS_RR_TYPE_MF:
- case LDNS_RR_TYPE_CNAME:
- case LDNS_RR_TYPE_MB:
- case LDNS_RR_TYPE_MG:
- case LDNS_RR_TYPE_MR:
- case LDNS_RR_TYPE_PTR:
- case LDNS_RR_TYPE_DNAME:
- /* type only has a single argument, the name */
- query_dname_tolower(datstart);
- return;
- case LDNS_RR_TYPE_MINFO:
- case LDNS_RR_TYPE_RP:
- case LDNS_RR_TYPE_SOA:
- /* two names after another */
- query_dname_tolower(datstart);
- query_dname_tolower(datstart +
- dname_valid(datstart, len-2));
- return;
- case LDNS_RR_TYPE_RT:
- case LDNS_RR_TYPE_AFSDB:
- case LDNS_RR_TYPE_KX:
- case LDNS_RR_TYPE_MX:
- /* skip fixed part */
- if(len < 2+2+1) /* rdlen, skiplen, 1byteroot */
- return;
- datstart += 2;
- query_dname_tolower(datstart);
- return;
- case LDNS_RR_TYPE_SIG:
- /* downcase the RRSIG, compat with BIND (kept it from SIG) */
- case LDNS_RR_TYPE_RRSIG:
- /* skip fixed part */
- if(len < 2+18+1)
- return;
- datstart += 18;
- query_dname_tolower(datstart);
- return;
- case LDNS_RR_TYPE_PX:
- /* skip, then two names after another */
- if(len < 2+2+1)
- return;
- datstart += 2;
- query_dname_tolower(datstart);
- query_dname_tolower(datstart +
- dname_valid(datstart, len-2-2));
- return;
- case LDNS_RR_TYPE_NAPTR:
- if(len < 2+4)
- return;
- len -= 2+4;
- datstart += 4;
- if(len < (size_t)datstart[0]+1) /* skip text field */
- return;
- len -= (size_t)datstart[0]+1;
- datstart += (size_t)datstart[0]+1;
- if(len < (size_t)datstart[0]+1) /* skip text field */
- return;
- len -= (size_t)datstart[0]+1;
- datstart += (size_t)datstart[0]+1;
- if(len < (size_t)datstart[0]+1) /* skip text field */
- return;
- len -= (size_t)datstart[0]+1;
- datstart += (size_t)datstart[0]+1;
- if(len < 1) /* check name is at least 1 byte*/
- return;
- query_dname_tolower(datstart);
- return;
- case LDNS_RR_TYPE_SRV:
- /* skip fixed part */
- if(len < 2+6+1)
- return;
- datstart += 6;
- query_dname_tolower(datstart);
- return;
-
- /* do not canonicalize NSEC rdata name, compat with
- * from bind 9.4 signer, where it does not do so */
- case LDNS_RR_TYPE_NSEC: /* type starts with the name */
- case LDNS_RR_TYPE_HINFO: /* not downcased */
- /* A6 not supported */
- default:
- /* nothing to do for unknown types */
- return;
- }
-}
-
-int rrset_canonical_equal(struct regional* region,
- struct ub_packed_rrset_key* k1, struct ub_packed_rrset_key* k2)
-{
- struct rbtree_type sortree1, sortree2;
- struct canon_rr *rrs1, *rrs2, *p1, *p2;
- struct packed_rrset_data* d1=(struct packed_rrset_data*)k1->entry.data;
- struct packed_rrset_data* d2=(struct packed_rrset_data*)k2->entry.data;
- struct ub_packed_rrset_key fk;
- struct packed_rrset_data fd;
- size_t flen[2];
- uint8_t* fdata[2];
-
- /* basic compare */
- if(k1->rk.dname_len != k2->rk.dname_len ||
- k1->rk.flags != k2->rk.flags ||
- k1->rk.type != k2->rk.type ||
- k1->rk.rrset_class != k2->rk.rrset_class ||
- query_dname_compare(k1->rk.dname, k2->rk.dname) != 0)
- return 0;
- if(d1->ttl != d2->ttl ||
- d1->count != d2->count ||
- d1->rrsig_count != d2->rrsig_count ||
- d1->trust != d2->trust ||
- d1->security != d2->security)
- return 0;
-
- /* init */
- memset(&fk, 0, sizeof(fk));
- memset(&fd, 0, sizeof(fd));
- fk.entry.data = &fd;
- fd.count = 2;
- fd.rr_len = flen;
- fd.rr_data = fdata;
- rbtree_init(&sortree1, &canonical_tree_compare);
- rbtree_init(&sortree2, &canonical_tree_compare);
- if(d1->count > RR_COUNT_MAX || d2->count > RR_COUNT_MAX)
- return 1; /* protection against integer overflow */
- rrs1 = regional_alloc(region, sizeof(struct canon_rr)*d1->count);
- rrs2 = regional_alloc(region, sizeof(struct canon_rr)*d2->count);
- if(!rrs1 || !rrs2) return 1; /* alloc failure */
-
- /* sort */
- canonical_sort(k1, d1, &sortree1, rrs1);
- canonical_sort(k2, d2, &sortree2, rrs2);
-
- /* compare canonical-sorted RRs for canonical-equality */
- if(sortree1.count != sortree2.count)
- return 0;
- p1 = (struct canon_rr*)rbtree_first(&sortree1);
- p2 = (struct canon_rr*)rbtree_first(&sortree2);
- while(p1 != (struct canon_rr*)RBTREE_NULL &&
- p2 != (struct canon_rr*)RBTREE_NULL) {
- flen[0] = d1->rr_len[p1->rr_idx];
- flen[1] = d2->rr_len[p2->rr_idx];
- fdata[0] = d1->rr_data[p1->rr_idx];
- fdata[1] = d2->rr_data[p2->rr_idx];
-
- if(canonical_compare(&fk, 0, 1) != 0)
- return 0;
- p1 = (struct canon_rr*)rbtree_next(&p1->node);
- p2 = (struct canon_rr*)rbtree_next(&p2->node);
- }
- return 1;
-}
-
-/**
- * Create canonical form of rrset in the scratch buffer.
- * @param region: temporary region.
- * @param buf: the buffer to use.
- * @param k: the rrset to insert.
- * @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 regional* region, sldns_buffer* buf,
- struct ub_packed_rrset_key* k, uint8_t* sig, size_t siglen,
- struct rbtree_type** sortree)
-{
- struct packed_rrset_data* d = (struct packed_rrset_data*)k->entry.data;
- uint8_t* can_owner = NULL;
- size_t can_owner_len = 0;
- struct canon_rr* walk;
- struct canon_rr* rrs;
-
- if(!*sortree) {
- *sortree = (struct rbtree_type*)regional_alloc(region,
- sizeof(rbtree_type));
- if(!*sortree)
- return 0;
- if(d->count > RR_COUNT_MAX)
- return 0; /* integer overflow protection */
- rrs = regional_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);
- }
-
- sldns_buffer_clear(buf);
- sldns_buffer_write(buf, sig, siglen);
- /* canonicalize signer name */
- query_dname_tolower(sldns_buffer_begin(buf)+18);
- RBTREE_FOR(walk, struct canon_rr*, (*sortree)) {
- /* see if there is enough space left in the buffer */
- if(sldns_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)
- sldns_buffer_write(buf, can_owner, can_owner_len);
- else insert_can_owner(buf, k, sig, &can_owner,
- &can_owner_len);
- sldns_buffer_write(buf, &k->rk.type, 2);
- sldns_buffer_write(buf, &k->rk.rrset_class, 2);
- sldns_buffer_write(buf, sig+4, 4);
- sldns_buffer_write(buf, d->rr_data[walk->rr_idx],
- d->rr_len[walk->rr_idx]);
- canonicalize_rdata(buf, k, d->rr_len[walk->rr_idx]);
- }
- sldns_buffer_flip(buf);
- return 1;
-}
-
-/** pretty print rrsig error with dates */
-static void
-sigdate_error(const char* str, int32_t expi, int32_t incep, int32_t now)
-{
- struct tm tm;
- char expi_buf[16];
- char incep_buf[16];
- char now_buf[16];
- time_t te, ti, tn;
-
- if(verbosity < VERB_QUERY)
- return;
- te = (time_t)expi;
- ti = (time_t)incep;
- tn = (time_t)now;
- memset(&tm, 0, sizeof(tm));
- if(gmtime_r(&te, &tm) && strftime(expi_buf, 15, "%Y%m%d%H%M%S", &tm)
- &&gmtime_r(&ti, &tm) && strftime(incep_buf, 15, "%Y%m%d%H%M%S", &tm)
- &&gmtime_r(&tn, &tm) && strftime(now_buf, 15, "%Y%m%d%H%M%S", &tm)) {
- log_info("%s expi=%s incep=%s now=%s", str, expi_buf,
- incep_buf, now_buf);
- } else
- log_info("%s expi=%u incep=%u now=%u", str, (unsigned)expi,
- (unsigned)incep, (unsigned)now);
-}
-
-/** check rrsig dates */
-static int
-check_dates(struct val_env* ve, uint32_t unow,
- uint8_t* expi_p, uint8_t* incep_p, char** reason)
-{
- /* read out the dates */
- int32_t expi, incep, now;
- memmove(&expi, expi_p, sizeof(expi));
- memmove(&incep, incep_p, sizeof(incep));
- expi = ntohl(expi);
- incep = ntohl(incep);
-
- /* get current date */
- if(ve->date_override) {
- if(ve->date_override == -1) {
- verbose(VERB_ALGO, "date override: ignore date");
- return 1;
- }
- now = ve->date_override;
- verbose(VERB_ALGO, "date override option %d", (int)now);
- } else now = (int32_t)unow;
-
- /* check them */
- if(incep - expi > 0) {
- sigdate_error("verify: inception after expiration, "
- "signature bad", expi, incep, now);
- *reason = "signature inception after expiration";
- return 0;
- }
- if(incep - now > 0) {
- /* within skew ? (calc here to avoid calculation normally) */
- int32_t skew = (expi-incep)/10;
- if(skew < ve->skew_min) skew = ve->skew_min;
- if(skew > ve->skew_max) skew = ve->skew_max;
- if(incep - now > skew) {
- sigdate_error("verify: signature bad, current time is"
- " before inception date", expi, incep, now);
- *reason = "signature before inception date";
- return 0;
- }
- sigdate_error("verify warning suspicious signature inception "
- " or bad local clock", expi, incep, now);
- }
- if(now - expi > 0) {
- int32_t skew = (expi-incep)/10;
- if(skew < ve->skew_min) skew = ve->skew_min;
- if(skew > ve->skew_max) skew = ve->skew_max;
- if(now - expi > skew) {
- sigdate_error("verify: signature expired", expi,
- incep, now);
- *reason = "signature expired";
- return 0;
- }
- sigdate_error("verify warning suspicious signature expiration "
- " or bad local clock", expi, incep, now);
- }
- return 1;
-}
-
-/** adjust rrset TTL for verified rrset, compare to original TTL and expi */
-static void
-adjust_ttl(struct val_env* ve, uint32_t unow,
- struct ub_packed_rrset_key* rrset, uint8_t* orig_p,
- uint8_t* expi_p, uint8_t* incep_p)
-{
- struct packed_rrset_data* d =
- (struct packed_rrset_data*)rrset->entry.data;
- /* read out the dates */
- int32_t origttl, expittl, expi, incep, now;
- memmove(&origttl, orig_p, sizeof(origttl));
- memmove(&expi, expi_p, sizeof(expi));
- memmove(&incep, incep_p, sizeof(incep));
- expi = ntohl(expi);
- incep = ntohl(incep);
- origttl = ntohl(origttl);
-
- /* get current date */
- if(ve->date_override) {
- now = ve->date_override;
- } else now = (int32_t)unow;
- expittl = expi - now;
-
- /* so now:
- * d->ttl: rrset ttl read from message or cache. May be reduced
- * origttl: original TTL from signature, authoritative TTL max.
- * MIN_TTL: minimum TTL from config.
- * expittl: TTL until the signature expires.
- *
- * Use the smallest of these, but don't let origttl set the TTL
- * below the minimum.
- */
- if(MIN_TTL > (time_t)origttl && d->ttl > MIN_TTL) {
- verbose(VERB_QUERY, "rrset TTL larger than original and minimum"
- " TTL, adjusting TTL downwards to minimum ttl");
- d->ttl = MIN_TTL;
- }
- else if(MIN_TTL <= origttl && d->ttl > (time_t)origttl) {
- verbose(VERB_QUERY, "rrset TTL larger than original TTL, "
- "adjusting TTL downwards to original ttl");
- d->ttl = origttl;
- }
-
- if(expittl > 0 && d->ttl > (time_t)expittl) {
- verbose(VERB_ALGO, "rrset TTL larger than sig expiration ttl,"
- " adjusting TTL downwards");
- d->ttl = expittl;
- }
-}
-
-enum sec_status
-dnskey_verify_rrset_sig(struct regional* region, sldns_buffer* buf,
- struct val_env* ve, time_t now,
- struct ub_packed_rrset_key* rrset, struct ub_packed_rrset_key* dnskey,
- size_t dnskey_idx, size_t sig_idx,
- struct rbtree_type** sortree, int* buf_canon, char** reason)
-{
- enum sec_status sec;
- uint8_t* sig; /* RRSIG rdata */
- size_t siglen;
- size_t rrnum = rrset_get_count(rrset);
- uint8_t* signer; /* rrsig signer name */
- size_t signer_len;
- unsigned char* sigblock; /* signature rdata field */
- unsigned int sigblock_len;
- uint16_t ktag; /* DNSKEY key tag */
- unsigned char* key; /* public key rdata field */
- unsigned int keylen;
- rrset_get_rdata(rrset, rrnum + sig_idx, &sig, &siglen);
- /* min length of rdatalen, fixed rrsig, root signer, 1 byte sig */
- if(siglen < 2+20) {
- verbose(VERB_QUERY, "verify: signature too short");
- *reason = "signature too short";
- return sec_status_bogus;
- }
-
- if(!(dnskey_get_flags(dnskey, dnskey_idx) & DNSKEY_BIT_ZSK)) {
- verbose(VERB_QUERY, "verify: dnskey without ZSK flag");
- *reason = "dnskey without ZSK flag";
- return sec_status_bogus;
- }
-
- if(dnskey_get_protocol(dnskey, dnskey_idx) != LDNS_DNSSEC_KEYPROTO) {
- /* RFC 4034 says DNSKEY PROTOCOL MUST be 3 */
- verbose(VERB_QUERY, "verify: dnskey has wrong key protocol");
- *reason = "dnskey has wrong protocolnumber";
- return sec_status_bogus;
- }
-
- /* verify as many fields in rrsig as possible */
- signer = sig+2+18;
- signer_len = dname_valid(signer, siglen-2-18);
- if(!signer_len) {
- verbose(VERB_QUERY, "verify: malformed signer name");
- *reason = "signer name malformed";
- return sec_status_bogus; /* signer name invalid */
- }
- if(!dname_subdomain_c(rrset->rk.dname, signer)) {
- verbose(VERB_QUERY, "verify: signer name is off-tree");
- *reason = "signer name off-tree";
- return sec_status_bogus; /* signer name offtree */
- }
- sigblock = (unsigned char*)signer+signer_len;
- if(siglen < 2+18+signer_len+1) {
- verbose(VERB_QUERY, "verify: too short, no signature data");
- *reason = "signature too short, no signature data";
- return sec_status_bogus; /* sig rdf is < 1 byte */
- }
- sigblock_len = (unsigned int)(siglen - 2 - 18 - signer_len);
-
- /* verify key dname == sig signer name */
- if(query_dname_compare(signer, dnskey->rk.dname) != 0) {
- verbose(VERB_QUERY, "verify: wrong key for rrsig");
- log_nametypeclass(VERB_QUERY, "RRSIG signername is",
- signer, 0, 0);
- log_nametypeclass(VERB_QUERY, "the key name is",
- dnskey->rk.dname, 0, 0);
- *reason = "signer name mismatches key name";
- return sec_status_bogus;
- }
-
- /* verify covered type */
- /* memcmp works because type is in network format for rrset */
- if(memcmp(sig+2, &rrset->rk.type, 2) != 0) {
- verbose(VERB_QUERY, "verify: wrong type covered");
- *reason = "signature covers wrong type";
- return sec_status_bogus;
- }
- /* verify keytag and sig algo (possibly again) */
- if((int)sig[2+2] != dnskey_get_algo(dnskey, dnskey_idx)) {
- verbose(VERB_QUERY, "verify: wrong algorithm");
- *reason = "signature has wrong algorithm";
- return sec_status_bogus;
- }
- ktag = htons(dnskey_calc_keytag(dnskey, dnskey_idx));
- if(memcmp(sig+2+16, &ktag, 2) != 0) {
- verbose(VERB_QUERY, "verify: wrong keytag");
- *reason = "signature has wrong keytag";
- return sec_status_bogus;
- }
-
- /* verify labels is in a valid range */
- if((int)sig[2+3] > dname_signame_label_count(rrset->rk.dname)) {
- verbose(VERB_QUERY, "verify: labelcount out of range");
- *reason = "signature labelcount out of range";
- return sec_status_bogus;
- }
-
- /* original ttl, always ok */
-
- 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 */
- dnskey_get_pubkey(dnskey, dnskey_idx, &key, &keylen);
- if(!key) {
- verbose(VERB_QUERY, "verify: short DNSKEY RR");
- return sec_status_unchecked;
- }
-
- /* verify */
- sec = verify_canonrrset(buf, (int)sig[2+2],
- sigblock, sigblock_len, key, keylen, reason);
-
- if(sec == sec_status_secure) {
- /* check if TTL is too high - reduce if so */
- adjust_ttl(ve, now, rrset, sig+2+4, sig+2+8, sig+2+12);
-
- /* verify inception, expiration dates
- * Do this last so that if you ignore expired-sigs the
- * rest is sure to be OK. */
- if(!check_dates(ve, now, sig+2+8, sig+2+12, reason)) {
- return sec_status_bogus;
- }
- }
-
- return sec;
-}
diff --git a/external/unbound/validator/val_sigcrypt.h b/external/unbound/validator/val_sigcrypt.h
deleted file mode 100644
index 5a975acff..000000000
--- a/external/unbound/validator/val_sigcrypt.h
+++ /dev/null
@@ -1,323 +0,0 @@
-/*
- * validator/val_sigcrypt.h - validator signature crypto functions.
- *
- * Copyright (c) 2007, NLnet Labs. All rights reserved.
- *
- * This software is open source.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- *
- * Redistributions of source code must retain the above copyright notice,
- * this list of conditions and the following disclaimer.
- *
- * Redistributions in binary form must reproduce the above copyright notice,
- * this list of conditions and the following disclaimer in the documentation
- * and/or other materials provided with the distribution.
- *
- * Neither the name of the NLNET LABS nor the names of its contributors may
- * be used to endorse or promote products derived from this software without
- * specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
- * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
- * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
- * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
- * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
- * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-/**
- * \file
- *
- * This file contains helper functions for the validator module.
- * The functions help with signature verification and checking, the
- * bridging between RR wireformat data and crypto calls.
- */
-
-#ifndef VALIDATOR_VAL_SIGCRYPT_H
-#define VALIDATOR_VAL_SIGCRYPT_H
-#include "util/data/packed_rrset.h"
-struct val_env;
-struct module_env;
-struct ub_packed_rrset_key;
-struct rbtree_type;
-struct regional;
-struct sldns_buffer;
-
-/** number of entries in algorithm needs array */
-#define ALGO_NEEDS_MAX 256
-
-/**
- * Storage for algorithm needs. DNSKEY algorithms.
- */
-struct algo_needs {
- /** the algorithms (8-bit) with each a number.
- * 0: not marked.
- * 1: marked 'necessary but not yet fulfilled'
- * 2: marked bogus.
- * Indexed by algorithm number.
- */
- uint8_t needs[ALGO_NEEDS_MAX];
- /** the number of entries in the array that are unfulfilled */
- size_t num;
-};
-
-/**
- * Initialize algo needs structure, set algos from rrset as needed.
- * Results are added to an existing need structure.
- * @param n: struct with storage.
- * @param dnskey: algos from this struct set as necessary. DNSKEY set.
- * @param sigalg: adds to signalled algorithm list too.
- */
-void algo_needs_init_dnskey_add(struct algo_needs* n,
- struct ub_packed_rrset_key* dnskey, uint8_t* sigalg);
-
-/**
- * Initialize algo needs structure from a signalled algo list.
- * @param n: struct with storage.
- * @param sigalg: signalled algorithm list, numbers ends with 0.
- */
-void algo_needs_init_list(struct algo_needs* n, uint8_t* sigalg);
-
-/**
- * Initialize algo needs structure, set algos from rrset as needed.
- * @param n: struct with storage.
- * @param ds: algos from this struct set as necessary. DS set.
- * @param fav_ds_algo: filter to use only this DS algo.
- * @param sigalg: list of signalled algos, constructed as output,
- * provide size ALGO_NEEDS_MAX+1. list of algonumbers, ends with a zero.
- */
-void algo_needs_init_ds(struct algo_needs* n, struct ub_packed_rrset_key* ds,
- int fav_ds_algo, uint8_t* sigalg);
-
-/**
- * Mark this algorithm as a success, sec_secure, and see if we are done.
- * @param n: storage structure processed.
- * @param algo: the algorithm processed to be secure.
- * @return if true, processing has finished successfully, we are satisfied.
- */
-int algo_needs_set_secure(struct algo_needs* n, uint8_t algo);
-
-/**
- * Mark this algorithm a failure, sec_bogus. It can later be overridden
- * by a success for this algorithm (with a different signature).
- * @param n: storage structure processed.
- * @param algo: the algorithm processed to be bogus.
- */
-void algo_needs_set_bogus(struct algo_needs* n, uint8_t algo);
-
-/**
- * See how many algorithms are missing (not bogus or secure, but not processed)
- * @param n: storage structure processed.
- * @return number of algorithms missing after processing.
- */
-size_t algo_needs_num_missing(struct algo_needs* n);
-
-/**
- * See which algo is missing.
- * @param n: struct after processing.
- * @return if 0 an algorithm was bogus, if a number, this algorithm was
- * missing. So on 0, report why that was bogus, on number report a missing
- * algorithm. There could be multiple missing, this reports the first one.
- */
-int algo_needs_missing(struct algo_needs* n);
-
-/**
- * Format error reason for algorithm missing.
- * @param env: module env with scratch for temp storage of string.
- * @param alg: DNSKEY-algorithm missing.
- * @param reason: destination.
- * @param s: string, appended with 'with algorithm ..'.
- */
-void algo_needs_reason(struct module_env* env, int alg, char** reason, char* s);
-
-/**
- * Check if dnskey matches a DS digest
- * Does not check dnskey-keyid footprint, just the digest.
- * @param env: module environment. Uses scratch space.
- * @param dnskey_rrset: DNSKEY rrset.
- * @param dnskey_idx: index of RR in rrset.
- * @param ds_rrset: DS rrset
- * @param ds_idx: index of RR in DS rrset.
- * @return true if it matches, false on error, not supported or no match.
- */
-int ds_digest_match_dnskey(struct module_env* env,
- struct ub_packed_rrset_key* dnskey_rrset, size_t dnskey_idx,
- struct ub_packed_rrset_key* ds_rrset, size_t ds_idx);
-
-/**
- * Get dnskey keytag, footprint value
- * @param dnskey_rrset: DNSKEY rrset.
- * @param dnskey_idx: index of RR in rrset.
- * @return the keytag or 0 for badly formatted DNSKEYs.
- */
-uint16_t dnskey_calc_keytag(struct ub_packed_rrset_key* dnskey_rrset,
- size_t dnskey_idx);
-
-/**
- * Get DS keytag, footprint value that matches the DNSKEY keytag it signs.
- * @param ds_rrset: DS rrset
- * @param ds_idx: index of RR in DS rrset.
- * @return the keytag or 0 for badly formatted DSs.
- */
-uint16_t ds_get_keytag(struct ub_packed_rrset_key* ds_rrset, size_t ds_idx);
-
-/**
- * See if DNSKEY algorithm is supported
- * @param dnskey_rrset: DNSKEY rrset.
- * @param dnskey_idx: index of RR in rrset.
- * @return true if supported.
- */
-int dnskey_algo_is_supported(struct ub_packed_rrset_key* dnskey_rrset,
- size_t dnskey_idx);
-
-/**
- * See if DS digest algorithm is supported
- * @param ds_rrset: DS rrset
- * @param ds_idx: index of RR in DS rrset.
- * @return true if supported.
- */
-int ds_digest_algo_is_supported(struct ub_packed_rrset_key* ds_rrset,
- size_t ds_idx);
-
-/**
- * Get DS RR digest algorithm
- * @param ds_rrset: DS rrset.
- * @param ds_idx: which DS.
- * @return algorithm or 0 if DS too short.
- */
-int ds_get_digest_algo(struct ub_packed_rrset_key* ds_rrset, size_t ds_idx);
-
-/**
- * See if DS key algorithm is supported
- * @param ds_rrset: DS rrset
- * @param ds_idx: index of RR in DS rrset.
- * @return true if supported.
- */
-int ds_key_algo_is_supported(struct ub_packed_rrset_key* ds_rrset,
- size_t ds_idx);
-
-/**
- * Get DS RR key algorithm. This value should match with the DNSKEY algo.
- * @param k: DS rrset.
- * @param idx: which DS.
- * @return algorithm or 0 if DS too short.
- */
-int ds_get_key_algo(struct ub_packed_rrset_key* k, size_t idx);
-
-/**
- * Get DNSKEY RR signature algorithm
- * @param k: DNSKEY rrset.
- * @param idx: which DNSKEY RR.
- * @return algorithm or 0 if DNSKEY too short.
- */
-int dnskey_get_algo(struct ub_packed_rrset_key* k, size_t idx);
-
-/**
- * Get DNSKEY RR flags
- * @param k: DNSKEY rrset.
- * @param idx: which DNSKEY RR.
- * @return flags or 0 if DNSKEY too short.
- */
-uint16_t dnskey_get_flags(struct ub_packed_rrset_key* k, size_t idx);
-
-/**
- * Verify rrset against dnskey rrset.
- * @param env: module environment, scratch space is used.
- * @param ve: validator environment, date settings.
- * @param rrset: to be validated.
- * @param dnskey: DNSKEY rrset, keyset to try.
- * @param sigalg: if nonNULL provide downgrade protection otherwise one
- * algorithm is enough.
- * @param reason: if bogus, a string returned, fixed or alloced in scratch.
- * @return SECURE if one key in the set verifies one rrsig.
- * UNCHECKED on allocation errors, unsupported algorithms, malformed data,
- * and BOGUS on verification failures (no keys match any signatures).
- */
-enum sec_status dnskeyset_verify_rrset(struct module_env* env,
- struct val_env* ve, struct ub_packed_rrset_key* rrset,
- struct ub_packed_rrset_key* dnskey, uint8_t* sigalg, char** reason);
-
-/**
- * verify rrset against one specific dnskey (from rrset)
- * @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 reason: if bogus, a string returned, fixed or alloced in scratch.
- * @return secure if *this* key signs any of the signatures on rrset.
- * unchecked on error or and bogus on bad signature.
- */
-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, char** reason);
-
-/**
- * verify rrset, with dnskey rrset, for a specific rrsig in rrset
- * @param env: module environment, scratch space is used.
- * @param ve: validator environment, date settings.
- * @param now: current time for validation (can be overridden).
- * @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.
- * @param reason: if bogus, a string returned, fixed or alloced in scratch.
- * @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, time_t now, struct ub_packed_rrset_key* rrset,
- struct ub_packed_rrset_key* dnskey, size_t sig_idx,
- struct rbtree_type** sortree, char** reason);
-
-/**
- * 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 ve: validator environment, date settings.
- * @param now: current time for validation (can be overridden).
- * @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.
- * @param reason: if bogus, a string returned, fixed or alloced in scratch.
- * @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 regional* region,
- struct sldns_buffer* buf, struct val_env* ve, time_t now,
- struct ub_packed_rrset_key* rrset, struct ub_packed_rrset_key* dnskey,
- size_t dnskey_idx, size_t sig_idx,
- struct rbtree_type** sortree, int* buf_canon, char** reason);
-
-/**
- * canonical compare for two tree entries
- */
-int canonical_tree_compare(const void* k1, const void* k2);
-
-/**
- * Compare two rrsets and see if they are the same, canonicalised.
- * The rrsets are not altered.
- * @param region: temporary region.
- * @param k1: rrset1
- * @param k2: rrset2
- * @return true if equal.
- */
-int rrset_canonical_equal(struct regional* region,
- struct ub_packed_rrset_key* k1, struct ub_packed_rrset_key* k2);
-
-#endif /* VALIDATOR_VAL_SIGCRYPT_H */
diff --git a/external/unbound/validator/val_utils.c b/external/unbound/validator/val_utils.c
deleted file mode 100644
index e3677e1d9..000000000
--- a/external/unbound/validator/val_utils.c
+++ /dev/null
@@ -1,1151 +0,0 @@
-/*
- * validator/val_utils.c - validator utility functions.
- *
- * Copyright (c) 2007, NLnet Labs. All rights reserved.
- *
- * This software is open source.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- *
- * Redistributions of source code must retain the above copyright notice,
- * this list of conditions and the following disclaimer.
- *
- * Redistributions in binary form must reproduce the above copyright notice,
- * this list of conditions and the following disclaimer in the documentation
- * and/or other materials provided with the distribution.
- *
- * Neither the name of the NLNET LABS nor the names of its contributors may
- * be used to endorse or promote products derived from this software without
- * specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
- * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
- * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
- * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
- * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
- * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-/**
- * \file
- *
- * This file contains helper functions for the validator module.
- */
-#include "config.h"
-#include "validator/val_utils.h"
-#include "validator/validator.h"
-#include "validator/val_kentry.h"
-#include "validator/val_sigcrypt.h"
-#include "validator/val_anchor.h"
-#include "validator/val_nsec.h"
-#include "validator/val_neg.h"
-#include "services/cache/rrset.h"
-#include "services/cache/dns.h"
-#include "util/data/msgreply.h"
-#include "util/data/packed_rrset.h"
-#include "util/data/dname.h"
-#include "util/net_help.h"
-#include "util/module.h"
-#include "util/regional.h"
-#include "sldns/wire2str.h"
-#include "sldns/parseutil.h"
-
-enum val_classification
-val_classify_response(uint16_t query_flags, struct query_info* origqinf,
- struct query_info* qinf, struct reply_info* rep, size_t skip)
-{
- int rcode = (int)FLAGS_GET_RCODE(rep->flags);
- size_t i;
-
- /* Normal Name Error's are easy to detect -- but don't mistake a CNAME
- * chain ending in NXDOMAIN. */
- if(rcode == LDNS_RCODE_NXDOMAIN && rep->an_numrrsets == 0)
- return VAL_CLASS_NAMEERROR;
-
- /* check for referral: nonRD query and it looks like a nodata */
- if(!(query_flags&BIT_RD) && rep->an_numrrsets == 0 &&
- rcode == LDNS_RCODE_NOERROR) {
- /* SOA record in auth indicates it is NODATA instead.
- * All validation requiring NODATA messages have SOA in
- * authority section. */
- /* uses fact that answer section is empty */
- int saw_ns = 0;
- for(i=0; i<rep->ns_numrrsets; i++) {
- if(ntohs(rep->rrsets[i]->rk.type) == LDNS_RR_TYPE_SOA)
- return VAL_CLASS_NODATA;
- if(ntohs(rep->rrsets[i]->rk.type) == LDNS_RR_TYPE_DS)
- return VAL_CLASS_REFERRAL;
- if(ntohs(rep->rrsets[i]->rk.type) == LDNS_RR_TYPE_NS)
- saw_ns = 1;
- }
- return saw_ns?VAL_CLASS_REFERRAL:VAL_CLASS_NODATA;
- }
- /* root referral where NS set is in the answer section */
- if(!(query_flags&BIT_RD) && rep->ns_numrrsets == 0 &&
- rep->an_numrrsets == 1 && rcode == LDNS_RCODE_NOERROR &&
- ntohs(rep->rrsets[0]->rk.type) == LDNS_RR_TYPE_NS &&
- query_dname_compare(rep->rrsets[0]->rk.dname,
- origqinf->qname) != 0)
- return VAL_CLASS_REFERRAL;
-
- /* dump bad messages */
- if(rcode != LDNS_RCODE_NOERROR && rcode != LDNS_RCODE_NXDOMAIN)
- return VAL_CLASS_UNKNOWN;
- /* next check if the skip into the answer section shows no answer */
- if(skip>0 && rep->an_numrrsets <= skip)
- return VAL_CLASS_CNAMENOANSWER;
-
- /* Next is NODATA */
- if(rcode == LDNS_RCODE_NOERROR && rep->an_numrrsets == 0)
- return VAL_CLASS_NODATA;
-
- /* We distinguish between CNAME response and other positive/negative
- * responses because CNAME answers require extra processing. */
-
- /* We distinguish between ANY and CNAME or POSITIVE because
- * ANY responses are validated differently. */
- if(rcode == LDNS_RCODE_NOERROR && qinf->qtype == LDNS_RR_TYPE_ANY)
- return VAL_CLASS_ANY;
-
- /* Note that DNAMEs will be ignored here, unless qtype=DNAME. Unless
- * qtype=CNAME, this will yield a CNAME response. */
- for(i=skip; i<rep->an_numrrsets; i++) {
- if(rcode == LDNS_RCODE_NOERROR &&
- ntohs(rep->rrsets[i]->rk.type) == qinf->qtype)
- return VAL_CLASS_POSITIVE;
- if(ntohs(rep->rrsets[i]->rk.type) == LDNS_RR_TYPE_CNAME)
- return VAL_CLASS_CNAME;
- }
- log_dns_msg("validator: error. failed to classify response message: ",
- qinf, rep);
- return VAL_CLASS_UNKNOWN;
-}
-
-/** Get signer name from RRSIG */
-static void
-rrsig_get_signer(uint8_t* data, size_t len, uint8_t** sname, size_t* slen)
-{
- /* RRSIG rdata is not allowed to be compressed, it is stored
- * uncompressed in memory as well, so return a ptr to the name */
- if(len < 21) {
- /* too short RRSig:
- * short, byte, byte, long, long, long, short, "." is
- * 2 1 1 4 4 4 2 1 = 19
- * and a skip of 18 bytes to the name.
- * +2 for the rdatalen is 21 bytes len for root label */
- *sname = NULL;
- *slen = 0;
- return;
- }
- data += 20; /* skip the fixed size bits */
- len -= 20;
- *slen = dname_valid(data, len);
- if(!*slen) {
- /* bad dname in this rrsig. */
- *sname = NULL;
- return;
- }
- *sname = data;
-}
-
-void
-val_find_rrset_signer(struct ub_packed_rrset_key* rrset, uint8_t** sname,
- size_t* slen)
-{
- struct packed_rrset_data* d = (struct packed_rrset_data*)
- rrset->entry.data;
- /* return signer for first signature, or NULL */
- if(d->rrsig_count == 0) {
- *sname = NULL;
- *slen = 0;
- return;
- }
- /* get rrsig signer name out of the signature */
- rrsig_get_signer(d->rr_data[d->count], d->rr_len[d->count],
- sname, slen);
-}
-
-/**
- * Find best signer name in this set of rrsigs.
- * @param rrset: which rrsigs to look through.
- * @param qinf: the query name that needs validation.
- * @param signer_name: the best signer_name. Updated if a better one is found.
- * @param signer_len: length of signer name.
- * @param matchcount: count of current best name (starts at 0 for no match).
- * Updated if match is improved.
- */
-static void
-val_find_best_signer(struct ub_packed_rrset_key* rrset,
- struct query_info* qinf, uint8_t** signer_name, size_t* signer_len,
- int* matchcount)
-{
- struct packed_rrset_data* d = (struct packed_rrset_data*)
- rrset->entry.data;
- uint8_t* sign;
- size_t i;
- int m;
- for(i=d->count; i<d->count+d->rrsig_count; i++) {
- sign = d->rr_data[i]+2+18;
- /* look at signatures that are valid (long enough),
- * and have a signer name that is a superdomain of qname,
- * and then check the number of labels in the shared topdomain
- * improve the match if possible */
- if(d->rr_len[i] > 2+19 && /* rdata, sig + root label*/
- dname_subdomain_c(qinf->qname, sign)) {
- (void)dname_lab_cmp(qinf->qname,
- dname_count_labels(qinf->qname),
- sign, dname_count_labels(sign), &m);
- if(m > *matchcount) {
- *matchcount = m;
- *signer_name = sign;
- (void)dname_count_size_labels(*signer_name,
- signer_len);
- }
- }
- }
-}
-
-void
-val_find_signer(enum val_classification subtype, struct query_info* qinf,
- struct reply_info* rep, size_t skip, uint8_t** signer_name,
- size_t* signer_len)
-{
- size_t i;
-
- if(subtype == VAL_CLASS_POSITIVE) {
- /* check for the answer rrset */
- for(i=skip; i<rep->an_numrrsets; i++) {
- if(query_dname_compare(qinf->qname,
- rep->rrsets[i]->rk.dname) == 0) {
- val_find_rrset_signer(rep->rrsets[i],
- signer_name, signer_len);
- return;
- }
- }
- *signer_name = NULL;
- *signer_len = 0;
- } else if(subtype == VAL_CLASS_CNAME) {
- /* check for the first signed cname/dname rrset */
- for(i=skip; i<rep->an_numrrsets; i++) {
- val_find_rrset_signer(rep->rrsets[i],
- signer_name, signer_len);
- if(*signer_name)
- return;
- if(ntohs(rep->rrsets[i]->rk.type) != LDNS_RR_TYPE_DNAME)
- break; /* only check CNAME after a DNAME */
- }
- *signer_name = NULL;
- *signer_len = 0;
- } else if(subtype == VAL_CLASS_NAMEERROR
- || subtype == VAL_CLASS_NODATA) {
- /*Check to see if the AUTH section NSEC record(s) have rrsigs*/
- for(i=rep->an_numrrsets; i<
- rep->an_numrrsets+rep->ns_numrrsets; i++) {
- if(ntohs(rep->rrsets[i]->rk.type) == LDNS_RR_TYPE_NSEC
- || ntohs(rep->rrsets[i]->rk.type) ==
- LDNS_RR_TYPE_NSEC3) {
- val_find_rrset_signer(rep->rrsets[i],
- signer_name, signer_len);
- return;
- }
- }
- } else if(subtype == VAL_CLASS_CNAMENOANSWER) {
- /* find closest superdomain signer name in authority section
- * NSEC and NSEC3s */
- int matchcount = 0;
- *signer_name = NULL;
- *signer_len = 0;
- for(i=rep->an_numrrsets; i<rep->an_numrrsets+rep->
- ns_numrrsets; i++) {
- if(ntohs(rep->rrsets[i]->rk.type) == LDNS_RR_TYPE_NSEC
- || ntohs(rep->rrsets[i]->rk.type) ==
- LDNS_RR_TYPE_NSEC3) {
- val_find_best_signer(rep->rrsets[i], qinf,
- signer_name, signer_len, &matchcount);
- }
- }
- } else if(subtype == VAL_CLASS_ANY) {
- /* check for one of the answer rrset that has signatures,
- * or potentially a DNAME is in use with a different qname */
- for(i=skip; i<rep->an_numrrsets; i++) {
- if(query_dname_compare(qinf->qname,
- rep->rrsets[i]->rk.dname) == 0) {
- val_find_rrset_signer(rep->rrsets[i],
- signer_name, signer_len);
- if(*signer_name)
- return;
- }
- }
- /* no answer RRSIGs with qname, try a DNAME */
- if(skip < rep->an_numrrsets &&
- ntohs(rep->rrsets[skip]->rk.type) ==
- LDNS_RR_TYPE_DNAME) {
- val_find_rrset_signer(rep->rrsets[skip],
- signer_name, signer_len);
- if(*signer_name)
- return;
- }
- *signer_name = NULL;
- *signer_len = 0;
- } else if(subtype == VAL_CLASS_REFERRAL) {
- /* find keys for the item at skip */
- if(skip < rep->rrset_count) {
- val_find_rrset_signer(rep->rrsets[skip],
- signer_name, signer_len);
- return;
- }
- *signer_name = NULL;
- *signer_len = 0;
- } else {
- verbose(VERB_QUERY, "find_signer: could not find signer name"
- " for unknown type response");
- *signer_name = NULL;
- *signer_len = 0;
- }
-}
-
-/** return number of rrs in an rrset */
-static size_t
-rrset_get_count(struct ub_packed_rrset_key* rrset)
-{
- struct packed_rrset_data* d = (struct packed_rrset_data*)
- rrset->entry.data;
- if(!d) return 0;
- return d->count;
-}
-
-/** return TTL of rrset */
-static uint32_t
-rrset_get_ttl(struct ub_packed_rrset_key* rrset)
-{
- struct packed_rrset_data* d = (struct packed_rrset_data*)
- rrset->entry.data;
- if(!d) return 0;
- return d->ttl;
-}
-
-enum sec_status
-val_verify_rrset(struct module_env* env, struct val_env* ve,
- struct ub_packed_rrset_key* rrset, struct ub_packed_rrset_key* keys,
- uint8_t* sigalg, char** reason)
-{
- enum sec_status sec;
- struct packed_rrset_data* d = (struct packed_rrset_data*)rrset->
- entry.data;
- if(d->security == sec_status_secure) {
- /* re-verify all other statuses, because keyset may change*/
- log_nametypeclass(VERB_ALGO, "verify rrset cached",
- rrset->rk.dname, ntohs(rrset->rk.type),
- ntohs(rrset->rk.rrset_class));
- return d->security;
- }
- /* check in the cache if verification has already been done */
- rrset_check_sec_status(env->rrset_cache, rrset, *env->now);
- if(d->security == sec_status_secure) {
- log_nametypeclass(VERB_ALGO, "verify rrset from cache",
- rrset->rk.dname, ntohs(rrset->rk.type),
- ntohs(rrset->rk.rrset_class));
- return d->security;
- }
- log_nametypeclass(VERB_ALGO, "verify rrset", rrset->rk.dname,
- ntohs(rrset->rk.type), ntohs(rrset->rk.rrset_class));
- sec = dnskeyset_verify_rrset(env, ve, rrset, keys, sigalg, reason);
- verbose(VERB_ALGO, "verify result: %s", sec_status_to_string(sec));
- regional_free_all(env->scratch);
-
- /* update rrset security status
- * only improves security status
- * and bogus is set only once, even if we rechecked the status */
- if(sec > d->security) {
- d->security = sec;
- if(sec == sec_status_secure)
- d->trust = rrset_trust_validated;
- else if(sec == sec_status_bogus) {
- size_t i;
- /* update ttl for rrset to fixed value. */
- d->ttl = ve->bogus_ttl;
- for(i=0; i<d->count+d->rrsig_count; i++)
- d->rr_ttl[i] = ve->bogus_ttl;
- /* leave RR specific TTL: not used for determine
- * if RRset timed out and clients see proper value. */
- lock_basic_lock(&ve->bogus_lock);
- ve->num_rrset_bogus++;
- lock_basic_unlock(&ve->bogus_lock);
- }
- /* if status updated - store in cache for reuse */
- rrset_update_sec_status(env->rrset_cache, rrset, *env->now);
- }
-
- return sec;
-}
-
-enum sec_status
-val_verify_rrset_entry(struct module_env* env, struct val_env* ve,
- struct ub_packed_rrset_key* rrset, struct key_entry_key* kkey,
- char** reason)
-{
- /* temporary dnskey rrset-key */
- struct ub_packed_rrset_key dnskey;
- struct key_entry_data* kd = (struct key_entry_data*)kkey->entry.data;
- enum sec_status sec;
- dnskey.rk.type = htons(kd->rrset_type);
- dnskey.rk.rrset_class = htons(kkey->key_class);
- dnskey.rk.flags = 0;
- dnskey.rk.dname = kkey->name;
- dnskey.rk.dname_len = kkey->namelen;
- dnskey.entry.key = &dnskey;
- dnskey.entry.data = kd->rrset_data;
- sec = val_verify_rrset(env, ve, rrset, &dnskey, kd->algo, reason);
- return sec;
-}
-
-/** verify that a DS RR hashes to a key and that key signs the set */
-static enum sec_status
-verify_dnskeys_with_ds_rr(struct module_env* env, struct val_env* ve,
- struct ub_packed_rrset_key* dnskey_rrset,
- struct ub_packed_rrset_key* ds_rrset, size_t ds_idx, char** reason)
-{
- enum sec_status sec = sec_status_bogus;
- size_t i, num, numchecked = 0, numhashok = 0;
- num = rrset_get_count(dnskey_rrset);
- for(i=0; i<num; i++) {
- /* Skip DNSKEYs that don't match the basic criteria. */
- if(ds_get_key_algo(ds_rrset, ds_idx)
- != dnskey_get_algo(dnskey_rrset, i)
- || dnskey_calc_keytag(dnskey_rrset, i)
- != ds_get_keytag(ds_rrset, ds_idx)) {
- continue;
- }
- numchecked++;
- 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(!ds_digest_match_dnskey(env, dnskey_rrset, i, ds_rrset,
- ds_idx)) {
- verbose(VERB_ALGO, "DS match attempt failed");
- continue;
- }
- numhashok++;
- verbose(VERB_ALGO, "DS match digest ok, trying signature");
-
- /* Otherwise, we have a match! Make sure that the DNSKEY
- * verifies *with this key* */
- sec = dnskey_verify_rrset(env, ve, dnskey_rrset,
- dnskey_rrset, i, reason);
- if(sec == sec_status_secure) {
- return sec;
- }
- /* If it didn't validate with the DNSKEY, try the next one! */
- }
- if(numchecked == 0)
- algo_needs_reason(env, ds_get_key_algo(ds_rrset, ds_idx),
- reason, "no keys have a DS");
- else if(numhashok == 0)
- *reason = "DS hash mismatches key";
- else if(!*reason)
- *reason = "keyset not secured by DNSKEY that matches DS";
- return sec_status_bogus;
-}
-
-int val_favorite_ds_algo(struct ub_packed_rrset_key* ds_rrset)
-{
- size_t i, num = rrset_get_count(ds_rrset);
- int d, digest_algo = 0; /* DS digest algo 0 is not used. */
- /* find favorite algo, for now, highest number supported */
- for(i=0; i<num; i++) {
- if(!ds_digest_algo_is_supported(ds_rrset, i) ||
- !ds_key_algo_is_supported(ds_rrset, i)) {
- continue;
- }
- d = ds_get_digest_algo(ds_rrset, i);
- if(d > digest_algo)
- digest_algo = d;
- }
- return digest_algo;
-}
-
-enum sec_status
-val_verify_DNSKEY_with_DS(struct module_env* env, struct val_env* ve,
- struct ub_packed_rrset_key* dnskey_rrset,
- struct ub_packed_rrset_key* ds_rrset, uint8_t* sigalg, char** reason)
-{
- /* as long as this is false, we can consider this DS rrset to be
- * equivalent to no DS rrset. */
- int has_useful_ds = 0, digest_algo, alg;
- struct algo_needs needs;
- size_t i, num;
- enum sec_status sec;
-
- if(dnskey_rrset->rk.dname_len != ds_rrset->rk.dname_len ||
- query_dname_compare(dnskey_rrset->rk.dname, ds_rrset->rk.dname)
- != 0) {
- verbose(VERB_QUERY, "DNSKEY RRset did not match DS RRset "
- "by name");
- *reason = "DNSKEY RRset did not match DS RRset by name";
- return sec_status_bogus;
- }
-
- if(sigalg) {
- /* harden against algo downgrade is enabled */
- digest_algo = val_favorite_ds_algo(ds_rrset);
- algo_needs_init_ds(&needs, ds_rrset, digest_algo, sigalg);
- } else {
- /* accept any key algo, any digest algo */
- digest_algo = -1;
- }
- num = rrset_get_count(ds_rrset);
- for(i=0; i<num; i++) {
- /* Check to see if we can understand this DS.
- * And check it is the strongest digest */
- if(!ds_digest_algo_is_supported(ds_rrset, i) ||
- !ds_key_algo_is_supported(ds_rrset, i) ||
- (sigalg && (ds_get_digest_algo(ds_rrset, i) != digest_algo))) {
- continue;
- }
-
- /* Once we see a single DS with a known digestID and
- * algorithm, we cannot return INSECURE (with a
- * "null" KeyEntry). */
- has_useful_ds = 1;
-
- sec = verify_dnskeys_with_ds_rr(env, ve, dnskey_rrset,
- ds_rrset, i, reason);
- if(sec == sec_status_secure) {
- if(!sigalg || algo_needs_set_secure(&needs,
- (uint8_t)ds_get_key_algo(ds_rrset, i))) {
- verbose(VERB_ALGO, "DS matched DNSKEY.");
- return sec_status_secure;
- }
- } else if(sigalg && sec == sec_status_bogus) {
- algo_needs_set_bogus(&needs,
- (uint8_t)ds_get_key_algo(ds_rrset, i));
- }
- }
-
- /* None of the DS's worked out. */
-
- /* If no DSs were understandable, then this is OK. */
- if(!has_useful_ds) {
- verbose(VERB_ALGO, "No usable DS records were found -- "
- "treating as insecure.");
- return sec_status_insecure;
- }
- /* If any were understandable, then it is bad. */
- verbose(VERB_QUERY, "Failed to match any usable DS to a DNSKEY.");
- if(sigalg && (alg=algo_needs_missing(&needs)) != 0) {
- algo_needs_reason(env, alg, reason, "missing verification of "
- "DNSKEY signature");
- }
- return sec_status_bogus;
-}
-
-struct key_entry_key*
-val_verify_new_DNSKEYs(struct regional* region, struct module_env* env,
- struct val_env* ve, struct ub_packed_rrset_key* dnskey_rrset,
- struct ub_packed_rrset_key* ds_rrset, int downprot, char** reason)
-{
- uint8_t sigalg[ALGO_NEEDS_MAX+1];
- enum sec_status sec = val_verify_DNSKEY_with_DS(env, ve,
- dnskey_rrset, ds_rrset, downprot?sigalg:NULL, reason);
-
- if(sec == sec_status_secure) {
- return key_entry_create_rrset(region,
- ds_rrset->rk.dname, ds_rrset->rk.dname_len,
- ntohs(ds_rrset->rk.rrset_class), dnskey_rrset,
- downprot?sigalg:NULL, *env->now);
- } else if(sec == sec_status_insecure) {
- return key_entry_create_null(region, ds_rrset->rk.dname,
- ds_rrset->rk.dname_len,
- ntohs(ds_rrset->rk.rrset_class),
- rrset_get_ttl(ds_rrset), *env->now);
- }
- return key_entry_create_bad(region, ds_rrset->rk.dname,
- ds_rrset->rk.dname_len, ntohs(ds_rrset->rk.rrset_class),
- BOGUS_KEY_TTL, *env->now);
-}
-
-enum sec_status
-val_verify_DNSKEY_with_TA(struct module_env* env, struct val_env* ve,
- struct ub_packed_rrset_key* dnskey_rrset,
- struct ub_packed_rrset_key* ta_ds,
- struct ub_packed_rrset_key* ta_dnskey, uint8_t* sigalg, char** reason)
-{
- /* as long as this is false, we can consider this anchor to be
- * equivalent to no anchor. */
- int has_useful_ta = 0, digest_algo = 0, alg;
- struct algo_needs needs;
- size_t i, num;
- enum sec_status sec;
-
- if(ta_ds && (dnskey_rrset->rk.dname_len != ta_ds->rk.dname_len ||
- query_dname_compare(dnskey_rrset->rk.dname, ta_ds->rk.dname)
- != 0)) {
- verbose(VERB_QUERY, "DNSKEY RRset did not match DS RRset "
- "by name");
- *reason = "DNSKEY RRset did not match DS RRset by name";
- return sec_status_bogus;
- }
- if(ta_dnskey && (dnskey_rrset->rk.dname_len != ta_dnskey->rk.dname_len
- || query_dname_compare(dnskey_rrset->rk.dname, ta_dnskey->rk.dname)
- != 0)) {
- verbose(VERB_QUERY, "DNSKEY RRset did not match anchor RRset "
- "by name");
- *reason = "DNSKEY RRset did not match anchor RRset by name";
- return sec_status_bogus;
- }
-
- if(ta_ds)
- digest_algo = val_favorite_ds_algo(ta_ds);
- if(sigalg) {
- if(ta_ds)
- algo_needs_init_ds(&needs, ta_ds, digest_algo, sigalg);
- else memset(&needs, 0, sizeof(needs));
- if(ta_dnskey)
- algo_needs_init_dnskey_add(&needs, ta_dnskey, sigalg);
- }
- if(ta_ds) {
- num = rrset_get_count(ta_ds);
- for(i=0; i<num; i++) {
- /* Check to see if we can understand this DS.
- * And check it is the strongest digest */
- if(!ds_digest_algo_is_supported(ta_ds, i) ||
- !ds_key_algo_is_supported(ta_ds, i) ||
- ds_get_digest_algo(ta_ds, i) != digest_algo)
- continue;
-
- /* Once we see a single DS with a known digestID and
- * algorithm, we cannot return INSECURE (with a
- * "null" KeyEntry). */
- has_useful_ta = 1;
-
- sec = verify_dnskeys_with_ds_rr(env, ve, dnskey_rrset,
- ta_ds, i, reason);
- if(sec == sec_status_secure) {
- if(!sigalg || algo_needs_set_secure(&needs,
- (uint8_t)ds_get_key_algo(ta_ds, i))) {
- verbose(VERB_ALGO, "DS matched DNSKEY.");
- return sec_status_secure;
- }
- } else if(sigalg && sec == sec_status_bogus) {
- algo_needs_set_bogus(&needs,
- (uint8_t)ds_get_key_algo(ta_ds, i));
- }
- }
- }
-
- /* None of the DS's worked out: check the DNSKEYs. */
- if(ta_dnskey) {
- num = rrset_get_count(ta_dnskey);
- for(i=0; i<num; i++) {
- /* Check to see if we can understand this DNSKEY */
- if(!dnskey_algo_is_supported(ta_dnskey, i))
- continue;
-
- /* we saw a useful TA */
- has_useful_ta = 1;
-
- sec = dnskey_verify_rrset(env, ve, dnskey_rrset,
- ta_dnskey, i, reason);
- if(sec == sec_status_secure) {
- if(!sigalg || algo_needs_set_secure(&needs,
- (uint8_t)dnskey_get_algo(ta_dnskey, i))) {
- verbose(VERB_ALGO, "anchor matched DNSKEY.");
- return sec_status_secure;
- }
- } else if(sigalg && sec == sec_status_bogus) {
- algo_needs_set_bogus(&needs,
- (uint8_t)dnskey_get_algo(ta_dnskey, i));
- }
- }
- }
-
- /* If no DSs were understandable, then this is OK. */
- if(!has_useful_ta) {
- verbose(VERB_ALGO, "No usable trust anchors were found -- "
- "treating as insecure.");
- return sec_status_insecure;
- }
- /* If any were understandable, then it is bad. */
- verbose(VERB_QUERY, "Failed to match any usable anchor to a DNSKEY.");
- if(sigalg && (alg=algo_needs_missing(&needs)) != 0) {
- algo_needs_reason(env, alg, reason, "missing verification of "
- "DNSKEY signature");
- }
- return sec_status_bogus;
-}
-
-struct key_entry_key*
-val_verify_new_DNSKEYs_with_ta(struct regional* region, struct module_env* env,
- struct val_env* ve, struct ub_packed_rrset_key* dnskey_rrset,
- struct ub_packed_rrset_key* ta_ds_rrset,
- struct ub_packed_rrset_key* ta_dnskey_rrset, int downprot,
- char** reason)
-{
- uint8_t sigalg[ALGO_NEEDS_MAX+1];
- enum sec_status sec = val_verify_DNSKEY_with_TA(env, ve,
- dnskey_rrset, ta_ds_rrset, ta_dnskey_rrset,
- downprot?sigalg:NULL, reason);
-
- if(sec == sec_status_secure) {
- return key_entry_create_rrset(region,
- dnskey_rrset->rk.dname, dnskey_rrset->rk.dname_len,
- ntohs(dnskey_rrset->rk.rrset_class), dnskey_rrset,
- downprot?sigalg:NULL, *env->now);
- } else if(sec == sec_status_insecure) {
- return key_entry_create_null(region, dnskey_rrset->rk.dname,
- dnskey_rrset->rk.dname_len,
- ntohs(dnskey_rrset->rk.rrset_class),
- rrset_get_ttl(dnskey_rrset), *env->now);
- }
- return key_entry_create_bad(region, dnskey_rrset->rk.dname,
- dnskey_rrset->rk.dname_len, ntohs(dnskey_rrset->rk.rrset_class),
- BOGUS_KEY_TTL, *env->now);
-}
-
-int
-val_dsset_isusable(struct ub_packed_rrset_key* ds_rrset)
-{
- size_t i;
- for(i=0; i<rrset_get_count(ds_rrset); i++) {
- if(ds_digest_algo_is_supported(ds_rrset, i) &&
- ds_key_algo_is_supported(ds_rrset, i))
- return 1;
- }
- if(verbosity < VERB_ALGO)
- return 0;
- if(rrset_get_count(ds_rrset) == 0)
- verbose(VERB_ALGO, "DS is not usable");
- else {
- /* report usability for the first DS RR */
- sldns_lookup_table *lt;
- char herr[64], aerr[64];
- lt = sldns_lookup_by_id(sldns_hashes,
- (int)ds_get_digest_algo(ds_rrset, i));
- if(lt) snprintf(herr, sizeof(herr), "%s", lt->name);
- else snprintf(herr, sizeof(herr), "%d",
- (int)ds_get_digest_algo(ds_rrset, i));
- lt = sldns_lookup_by_id(sldns_algorithms,
- (int)ds_get_key_algo(ds_rrset, i));
- if(lt) snprintf(aerr, sizeof(aerr), "%s", lt->name);
- else snprintf(aerr, sizeof(aerr), "%d",
- (int)ds_get_key_algo(ds_rrset, i));
- verbose(VERB_ALGO, "DS unsupported, hash %s %s, "
- "key algorithm %s %s", herr,
- (ds_digest_algo_is_supported(ds_rrset, 0)?
- "(supported)":"(unsupported)"), aerr,
- (ds_key_algo_is_supported(ds_rrset, 0)?
- "(supported)":"(unsupported)"));
- }
- return 0;
-}
-
-/** get label count for a signature */
-static uint8_t
-rrsig_get_labcount(struct packed_rrset_data* d, size_t sig)
-{
- if(d->rr_len[sig] < 2+4)
- return 0; /* bad sig length */
- return d->rr_data[sig][2+3];
-}
-
-int
-val_rrset_wildcard(struct ub_packed_rrset_key* rrset, uint8_t** wc)
-{
- struct packed_rrset_data* d = (struct packed_rrset_data*)rrset->
- entry.data;
- uint8_t labcount;
- int labdiff;
- uint8_t* wn;
- size_t i, wl;
- if(d->rrsig_count == 0) {
- return 1;
- }
- labcount = rrsig_get_labcount(d, d->count + 0);
- /* check rest of signatures identical */
- for(i=1; i<d->rrsig_count; i++) {
- if(labcount != rrsig_get_labcount(d, d->count + i)) {
- return 0;
- }
- }
- /* OK the rrsigs check out */
- /* if the RRSIG label count is shorter than the number of actual
- * labels, then this rrset was synthesized from a wildcard.
- * Note that the RRSIG label count doesn't count the root label. */
- wn = rrset->rk.dname;
- wl = rrset->rk.dname_len;
- /* skip a leading wildcard label in the dname (RFC4035 2.2) */
- if(dname_is_wild(wn)) {
- wn += 2;
- wl -= 2;
- }
- labdiff = (dname_count_labels(wn) - 1) - (int)labcount;
- if(labdiff > 0) {
- *wc = wn;
- dname_remove_labels(wc, &wl, labdiff);
- return 1;
- }
- return 1;
-}
-
-int
-val_chase_cname(struct query_info* qchase, struct reply_info* rep,
- size_t* cname_skip) {
- size_t i;
- /* skip any DNAMEs, go to the CNAME for next part */
- for(i = *cname_skip; i < rep->an_numrrsets; i++) {
- if(ntohs(rep->rrsets[i]->rk.type) == LDNS_RR_TYPE_CNAME &&
- query_dname_compare(qchase->qname, rep->rrsets[i]->
- rk.dname) == 0) {
- qchase->qname = NULL;
- get_cname_target(rep->rrsets[i], &qchase->qname,
- &qchase->qname_len);
- if(!qchase->qname)
- return 0; /* bad CNAME rdata */
- (*cname_skip) = i+1;
- return 1;
- }
- }
- return 0; /* CNAME classified but no matching CNAME ?! */
-}
-
-/** see if rrset has signer name as one of the rrsig signers */
-static int
-rrset_has_signer(struct ub_packed_rrset_key* rrset, uint8_t* name, size_t len)
-{
- struct packed_rrset_data* d = (struct packed_rrset_data*)rrset->
- entry.data;
- size_t i;
- for(i = d->count; i< d->count+d->rrsig_count; i++) {
- if(d->rr_len[i] > 2+18+len) {
- /* at least rdatalen + signature + signame (+1 sig)*/
- if(!dname_valid(d->rr_data[i]+2+18, d->rr_len[i]-2-18))
- continue;
- if(query_dname_compare(name, d->rr_data[i]+2+18) == 0)
- {
- return 1;
- }
- }
- }
- return 0;
-}
-
-void
-val_fill_reply(struct reply_info* chase, struct reply_info* orig,
- size_t skip, uint8_t* name, size_t len, uint8_t* signer)
-{
- size_t i;
- int seen_dname = 0;
- chase->rrset_count = 0;
- chase->an_numrrsets = 0;
- chase->ns_numrrsets = 0;
- chase->ar_numrrsets = 0;
- /* ANSWER section */
- for(i=skip; i<orig->an_numrrsets; i++) {
- if(!signer) {
- if(query_dname_compare(name,
- orig->rrsets[i]->rk.dname) == 0)
- chase->rrsets[chase->an_numrrsets++] =
- orig->rrsets[i];
- } else if(seen_dname && ntohs(orig->rrsets[i]->rk.type) ==
- LDNS_RR_TYPE_CNAME) {
- chase->rrsets[chase->an_numrrsets++] = orig->rrsets[i];
- seen_dname = 0;
- } else if(rrset_has_signer(orig->rrsets[i], name, len)) {
- chase->rrsets[chase->an_numrrsets++] = orig->rrsets[i];
- if(ntohs(orig->rrsets[i]->rk.type) ==
- LDNS_RR_TYPE_DNAME) {
- seen_dname = 1;
- }
- }
- }
- /* AUTHORITY section */
- for(i = (skip > orig->an_numrrsets)?skip:orig->an_numrrsets;
- i<orig->an_numrrsets+orig->ns_numrrsets;
- i++) {
- if(!signer) {
- if(query_dname_compare(name,
- orig->rrsets[i]->rk.dname) == 0)
- chase->rrsets[chase->an_numrrsets+
- chase->ns_numrrsets++] = orig->rrsets[i];
- } else if(rrset_has_signer(orig->rrsets[i], name, len)) {
- chase->rrsets[chase->an_numrrsets+
- chase->ns_numrrsets++] = orig->rrsets[i];
- }
- }
- /* ADDITIONAL section */
- for(i= (skip>orig->an_numrrsets+orig->ns_numrrsets)?
- skip:orig->an_numrrsets+orig->ns_numrrsets;
- i<orig->rrset_count; i++) {
- if(!signer) {
- if(query_dname_compare(name,
- orig->rrsets[i]->rk.dname) == 0)
- chase->rrsets[chase->an_numrrsets
- +orig->ns_numrrsets+chase->ar_numrrsets++]
- = orig->rrsets[i];
- } else if(rrset_has_signer(orig->rrsets[i], name, len)) {
- chase->rrsets[chase->an_numrrsets+orig->ns_numrrsets+
- chase->ar_numrrsets++] = orig->rrsets[i];
- }
- }
- chase->rrset_count = chase->an_numrrsets + chase->ns_numrrsets +
- chase->ar_numrrsets;
-}
-
-void val_reply_remove_auth(struct reply_info* rep, size_t index)
-{
- log_assert(index < rep->rrset_count);
- log_assert(index >= rep->an_numrrsets);
- log_assert(index < rep->an_numrrsets+rep->ns_numrrsets);
- memmove(rep->rrsets+index, rep->rrsets+index+1,
- sizeof(struct ub_packed_rrset_key*)*
- (rep->rrset_count - index - 1));
- rep->ns_numrrsets--;
- rep->rrset_count--;
-}
-
-void
-val_check_nonsecure(struct val_env* ve, struct reply_info* rep)
-{
- size_t i;
- /* authority */
- for(i=rep->an_numrrsets; i<rep->an_numrrsets+rep->ns_numrrsets; i++) {
- if(((struct packed_rrset_data*)rep->rrsets[i]->entry.data)
- ->security != sec_status_secure) {
- /* because we want to return the authentic original
- * message when presented with CD-flagged queries,
- * we need to preserve AUTHORITY section data.
- * However, this rrset is not signed or signed
- * with the wrong keys. Validation has tried to
- * verify this rrset with the keysets of import.
- * But this rrset did not verify.
- * Therefore the message is bogus.
- */
-
- /* check if authority consists of only an NS record
- * which is bad, and there is an answer section with
- * data. In that case, delete NS and additional to
- * be lenient and make a minimal response */
- if(rep->an_numrrsets != 0 && rep->ns_numrrsets == 1 &&
- ntohs(rep->rrsets[i]->rk.type)
- == LDNS_RR_TYPE_NS) {
- verbose(VERB_ALGO, "truncate to minimal");
- rep->ns_numrrsets = 0;
- rep->ar_numrrsets = 0;
- rep->rrset_count = rep->an_numrrsets;
- return;
- }
-
- log_nametypeclass(VERB_QUERY, "message is bogus, "
- "non secure rrset",
- rep->rrsets[i]->rk.dname,
- ntohs(rep->rrsets[i]->rk.type),
- ntohs(rep->rrsets[i]->rk.rrset_class));
- rep->security = sec_status_bogus;
- return;
- }
- }
- /* additional */
- if(!ve->clean_additional)
- return;
- for(i=rep->an_numrrsets+rep->ns_numrrsets; i<rep->rrset_count; i++) {
- if(((struct packed_rrset_data*)rep->rrsets[i]->entry.data)
- ->security != sec_status_secure) {
- /* This does not cause message invalidation. It was
- * simply unsigned data in the additional. The
- * RRSIG must have been truncated off the message.
- *
- * However, we do not want to return possible bogus
- * data to clients that rely on this service for
- * their authentication.
- */
- /* remove this unneeded additional rrset */
- memmove(rep->rrsets+i, rep->rrsets+i+1,
- sizeof(struct ub_packed_rrset_key*)*
- (rep->rrset_count - i - 1));
- rep->ar_numrrsets--;
- rep->rrset_count--;
- i--;
- }
- }
-}
-
-/** check no anchor and unlock */
-static int
-check_no_anchor(struct val_anchors* anchors, uint8_t* nm, size_t l, uint16_t c)
-{
- struct trust_anchor* ta;
- if((ta=anchors_lookup(anchors, nm, l, c))) {
- lock_basic_unlock(&ta->lock);
- }
- return !ta;
-}
-
-void
-val_mark_indeterminate(struct reply_info* rep, struct val_anchors* anchors,
- struct rrset_cache* r, struct module_env* env)
-{
- size_t i;
- struct packed_rrset_data* d;
- for(i=0; i<rep->rrset_count; i++) {
- d = (struct packed_rrset_data*)rep->rrsets[i]->entry.data;
- if(d->security == sec_status_unchecked &&
- check_no_anchor(anchors, rep->rrsets[i]->rk.dname,
- rep->rrsets[i]->rk.dname_len,
- ntohs(rep->rrsets[i]->rk.rrset_class)))
- {
- /* mark as indeterminate */
- d->security = sec_status_indeterminate;
- rrset_update_sec_status(r, rep->rrsets[i], *env->now);
- }
- }
-}
-
-void
-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;
- 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, kname)) {
- /* mark as insecure */
- d->security = sec_status_insecure;
- rrset_update_sec_status(r, rep->rrsets[i], *env->now);
- }
- }
-}
-
-size_t
-val_next_unchecked(struct reply_info* rep, size_t skip)
-{
- size_t i;
- struct packed_rrset_data* d;
- for(i=skip+1; i<rep->rrset_count; i++) {
- d = (struct packed_rrset_data*)rep->rrsets[i]->entry.data;
- if(d->security == sec_status_unchecked) {
- return i;
- }
- }
- return rep->rrset_count;
-}
-
-const char*
-val_classification_to_string(enum val_classification subtype)
-{
- switch(subtype) {
- case VAL_CLASS_UNTYPED: return "untyped";
- case VAL_CLASS_UNKNOWN: return "unknown";
- case VAL_CLASS_POSITIVE: return "positive";
- case VAL_CLASS_CNAME: return "cname";
- case VAL_CLASS_NODATA: return "nodata";
- case VAL_CLASS_NAMEERROR: return "nameerror";
- case VAL_CLASS_CNAMENOANSWER: return "cnamenoanswer";
- case VAL_CLASS_REFERRAL: return "referral";
- case VAL_CLASS_ANY: return "qtype_any";
- default:
- return "bad_val_classification";
- }
-}
-
-/** log a sock_list entry */
-static void
-sock_list_logentry(enum verbosity_value v, const char* s, struct sock_list* p)
-{
- if(p->len)
- log_addr(v, s, &p->addr, p->len);
- else verbose(v, "%s cache", s);
-}
-
-void val_blacklist(struct sock_list** blacklist, struct regional* region,
- struct sock_list* origin, int cross)
-{
- /* debug printout */
- if(verbosity >= VERB_ALGO) {
- struct sock_list* p;
- for(p=*blacklist; p; p=p->next)
- sock_list_logentry(VERB_ALGO, "blacklist", p);
- if(!origin)
- verbose(VERB_ALGO, "blacklist add: cache");
- for(p=origin; p; p=p->next)
- sock_list_logentry(VERB_ALGO, "blacklist add", p);
- }
- /* blacklist the IPs or the cache */
- if(!origin) {
- /* only add if nothing there. anything else also stops cache*/
- if(!*blacklist)
- sock_list_insert(blacklist, NULL, 0, region);
- } else if(!cross)
- sock_list_prepend(blacklist, origin);
- else sock_list_merge(blacklist, region, origin);
-}
-
-int val_has_signed_nsecs(struct reply_info* rep, char** reason)
-{
- size_t i, num_nsec = 0, num_nsec3 = 0;
- struct packed_rrset_data* d;
- for(i=rep->an_numrrsets; i<rep->an_numrrsets+rep->ns_numrrsets; i++) {
- if(rep->rrsets[i]->rk.type == htons(LDNS_RR_TYPE_NSEC))
- num_nsec++;
- else if(rep->rrsets[i]->rk.type == htons(LDNS_RR_TYPE_NSEC3))
- num_nsec3++;
- else continue;
- d = (struct packed_rrset_data*)rep->rrsets[i]->entry.data;
- if(d && d->rrsig_count != 0) {
- return 1;
- }
- }
- if(num_nsec == 0 && num_nsec3 == 0)
- *reason = "no DNSSEC records";
- else if(num_nsec != 0)
- *reason = "no signatures over NSECs";
- else *reason = "no signatures over NSEC3s";
- return 0;
-}
-
-struct dns_msg*
-val_find_DS(struct module_env* env, uint8_t* nm, size_t nmlen, uint16_t c,
- struct regional* region, uint8_t* topname)
-{
- struct dns_msg* msg;
- struct query_info qinfo;
- struct ub_packed_rrset_key *rrset = rrset_cache_lookup(
- env->rrset_cache, nm, nmlen, LDNS_RR_TYPE_DS, c, 0,
- *env->now, 0);
- if(rrset) {
- /* DS rrset exists. Return it to the validator immediately*/
- struct ub_packed_rrset_key* copy = packed_rrset_copy_region(
- rrset, region, *env->now);
- lock_rw_unlock(&rrset->entry.lock);
- if(!copy)
- return NULL;
- msg = dns_msg_create(nm, nmlen, LDNS_RR_TYPE_DS, c, region, 1);
- if(!msg)
- return NULL;
- msg->rep->rrsets[0] = copy;
- msg->rep->rrset_count++;
- msg->rep->an_numrrsets++;
- return msg;
- }
- /* lookup in rrset and negative cache for NSEC/NSEC3 */
- qinfo.qname = nm;
- qinfo.qname_len = nmlen;
- qinfo.qtype = LDNS_RR_TYPE_DS;
- qinfo.qclass = c;
- qinfo.local_alias = NULL;
- /* do not add SOA to reply message, it is going to be used internal */
- msg = val_neg_getmsg(env->neg_cache, &qinfo, region, env->rrset_cache,
- env->scratch_buffer, *env->now, 0, topname);
- return msg;
-}
diff --git a/external/unbound/validator/val_utils.h b/external/unbound/validator/val_utils.h
deleted file mode 100644
index 051824aba..000000000
--- a/external/unbound/validator/val_utils.h
+++ /dev/null
@@ -1,410 +0,0 @@
-/*
- * validator/val_utils.h - validator utility functions.
- *
- * Copyright (c) 2007, NLnet Labs. All rights reserved.
- *
- * This software is open source.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- *
- * Redistributions of source code must retain the above copyright notice,
- * this list of conditions and the following disclaimer.
- *
- * Redistributions in binary form must reproduce the above copyright notice,
- * this list of conditions and the following disclaimer in the documentation
- * and/or other materials provided with the distribution.
- *
- * Neither the name of the NLNET LABS nor the names of its contributors may
- * be used to endorse or promote products derived from this software without
- * specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
- * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
- * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
- * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
- * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
- * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-/**
- * \file
- *
- * This file contains helper functions for the validator module.
- */
-
-#ifndef VALIDATOR_VAL_UTILS_H
-#define VALIDATOR_VAL_UTILS_H
-#include "util/data/packed_rrset.h"
-struct query_info;
-struct reply_info;
-struct val_env;
-struct module_env;
-struct ub_packed_rrset_key;
-struct key_entry_key;
-struct regional;
-struct val_anchors;
-struct rrset_cache;
-struct sock_list;
-
-/**
- * Response classifications for the validator. The different types of proofs.
- */
-enum val_classification {
- /** Not subtyped yet. */
- VAL_CLASS_UNTYPED = 0,
- /** Not a recognized subtype. */
- VAL_CLASS_UNKNOWN,
- /** A positive, direct, response */
- VAL_CLASS_POSITIVE,
- /** A positive response, with a CNAME/DNAME chain. */
- VAL_CLASS_CNAME,
- /** A NOERROR/NODATA response. */
- VAL_CLASS_NODATA,
- /** A NXDOMAIN response. */
- VAL_CLASS_NAMEERROR,
- /** A CNAME/DNAME chain, and the offset is at the end of it,
- * but there is no answer here, it can be NAMERROR or NODATA. */
- VAL_CLASS_CNAMENOANSWER,
- /** A referral, from cache with a nonRD query. */
- VAL_CLASS_REFERRAL,
- /** A response to a qtype=ANY query. */
- VAL_CLASS_ANY
-};
-
-/**
- * Given a response, classify ANSWER responses into a subtype.
- * @param query_flags: query flags for the original query.
- * @param origqinf: query info. The original query name.
- * @param qinf: query info. The chased query name.
- * @param rep: response. The original response.
- * @param skip: offset into the original response answer section.
- * @return A subtype, all values possible except UNTYPED .
- * Once CNAME type is returned you can increase skip.
- * Then, another CNAME type, CNAME_NOANSWER or POSITIVE are possible.
- */
-enum val_classification val_classify_response(uint16_t query_flags,
- struct query_info* origqinf, struct query_info* qinf,
- struct reply_info* rep, size_t skip);
-
-/**
- * Given a response, determine the name of the "signer". This is primarily
- * to determine if the response is, in fact, signed at all, and, if so, what
- * is the name of the most pertinent keyset.
- *
- * @param subtype: the type from classify.
- * @param qinf: query, the chased query name.
- * @param rep: response to that, original response.
- * @param cname_skip: how many answer rrsets have been skipped due to CNAME
- * chains being chased around.
- * @param signer_name: signer name, if the response is signed
- * (even partially), or null if the response isn't signed.
- * @param signer_len: length of signer_name of 0 if signer_name is NULL.
- */
-void val_find_signer(enum val_classification subtype,
- struct query_info* qinf, struct reply_info* rep,
- size_t cname_skip, uint8_t** signer_name, size_t* signer_len);
-
-/**
- * Verify RRset with keys
- * @param env: module environment (scratch buffer)
- * @param ve: validator environment (verification settings)
- * @param rrset: what to verify
- * @param keys: dnskey rrset to verify with.
- * @param sigalg: if nonNULL provide downgrade protection otherwise one
- * algorithm is enough. Algo list is constructed in here.
- * @param reason: reason of failure. Fixed string or alloced in scratch.
- * @return security status of verification.
- */
-enum sec_status val_verify_rrset(struct module_env* env, struct val_env* ve,
- struct ub_packed_rrset_key* rrset, struct ub_packed_rrset_key* keys,
- uint8_t* sigalg, char** reason);
-
-/**
- * Verify RRset with keys from a keyset.
- * @param env: module environment (scratch buffer)
- * @param ve: validator environment (verification settings)
- * @param rrset: what to verify
- * @param kkey: key_entry to verify with.
- * @param reason: reason of failure. Fixed string or alloced in scratch.
- * @return security status of verification.
- */
-enum sec_status val_verify_rrset_entry(struct module_env* env,
- struct val_env* ve, struct ub_packed_rrset_key* rrset,
- struct key_entry_key* kkey, char** reason);
-
-/**
- * Verify DNSKEYs with DS rrset. Like val_verify_new_DNSKEYs but
- * returns a sec_status instead of a key_entry.
- * @param env: module environment (scratch buffer)
- * @param ve: validator environment (verification settings)
- * @param dnskey_rrset: DNSKEY rrset to verify
- * @param ds_rrset: DS rrset to verify with.
- * @param sigalg: if nonNULL provide downgrade protection otherwise one
- * algorithm is enough. The list of signalled algorithms is returned,
- * must have enough space for ALGO_NEEDS_MAX+1.
- * @param reason: reason of failure. Fixed string or alloced in scratch.
- * @return: sec_status_secure if a DS matches.
- * sec_status_insecure if end of trust (i.e., unknown algorithms).
- * sec_status_bogus if it fails.
- */
-enum sec_status val_verify_DNSKEY_with_DS(struct module_env* env,
- struct val_env* ve, struct ub_packed_rrset_key* dnskey_rrset,
- struct ub_packed_rrset_key* ds_rrset, uint8_t* sigalg, char** reason);
-
-/**
- * Verify DNSKEYs with DS and DNSKEY rrset. Like val_verify_DNSKEY_with_DS
- * but for a trust anchor.
- * @param env: module environment (scratch buffer)
- * @param ve: validator environment (verification settings)
- * @param dnskey_rrset: DNSKEY rrset to verify
- * @param ta_ds: DS rrset to verify with.
- * @param ta_dnskey: DNSKEY rrset to verify with.
- * @param sigalg: if nonNULL provide downgrade protection otherwise one
- * algorithm is enough. The list of signalled algorithms is returned,
- * must have enough space for ALGO_NEEDS_MAX+1.
- * @param reason: reason of failure. Fixed string or alloced in scratch.
- * @return: sec_status_secure if a DS matches.
- * sec_status_insecure if end of trust (i.e., unknown algorithms).
- * sec_status_bogus if it fails.
- */
-enum sec_status val_verify_DNSKEY_with_TA(struct module_env* env,
- struct val_env* ve, struct ub_packed_rrset_key* dnskey_rrset,
- struct ub_packed_rrset_key* ta_ds,
- struct ub_packed_rrset_key* ta_dnskey, uint8_t* sigalg, char** reason);
-
-/**
- * Verify new DNSKEYs with DS rrset. The DS contains hash values that should
- * match the DNSKEY keys.
- * match the DS to a DNSKEY and verify the DNSKEY rrset with that key.
- *
- * @param region: where to allocate key entry result.
- * @param env: module environment (scratch buffer)
- * @param ve: validator environment (verification settings)
- * @param dnskey_rrset: DNSKEY rrset to verify
- * @param ds_rrset: DS rrset to verify with.
- * @param downprot: if true provide downgrade protection otherwise one
- * algorithm is enough.
- * @param reason: reason of failure. Fixed string or alloced in scratch.
- * @return a KeyEntry. This will either contain the now trusted
- * dnskey_rrset, a "null" key entry indicating that this DS
- * rrset/DNSKEY pair indicate an secure end to the island of trust
- * (i.e., unknown algorithms), or a "bad" KeyEntry if the dnskey
- * rrset fails to verify. Note that the "null" response should
- * generally only occur in a private algorithm scenario: normally
- * this sort of thing is checked before fetching the matching DNSKEY
- * rrset.
- * if downprot is set, a key entry with an algo list is made.
- */
-struct key_entry_key* val_verify_new_DNSKEYs(struct regional* region,
- struct module_env* env, struct val_env* ve,
- struct ub_packed_rrset_key* dnskey_rrset,
- struct ub_packed_rrset_key* ds_rrset, int downprot, char** reason);
-
-
-/**
- * Verify rrset with trust anchor: DS and DNSKEY rrset.
- *
- * @param region: where to allocate key entry result.
- * @param env: module environment (scratch buffer)
- * @param ve: validator environment (verification settings)
- * @param dnskey_rrset: DNSKEY rrset to verify
- * @param ta_ds_rrset: DS rrset to verify with.
- * @param ta_dnskey_rrset: the DNSKEY rrset to verify with.
- * @param downprot: if true provide downgrade protection otherwise one
- * algorithm is enough.
- * @param reason: reason of failure. Fixed string or alloced in scratch.
- * @return a KeyEntry. This will either contain the now trusted
- * dnskey_rrset, a "null" key entry indicating that this DS
- * rrset/DNSKEY pair indicate an secure end to the island of trust
- * (i.e., unknown algorithms), or a "bad" KeyEntry if the dnskey
- * rrset fails to verify. Note that the "null" response should
- * generally only occur in a private algorithm scenario: normally
- * this sort of thing is checked before fetching the matching DNSKEY
- * rrset.
- * if downprot is set, a key entry with an algo list is made.
- */
-struct key_entry_key* val_verify_new_DNSKEYs_with_ta(struct regional* region,
- struct module_env* env, struct val_env* ve,
- struct ub_packed_rrset_key* dnskey_rrset,
- struct ub_packed_rrset_key* ta_ds_rrset,
- struct ub_packed_rrset_key* ta_dnskey_rrset,
- int downprot, char** reason);
-
-/**
- * Determine if DS rrset is usable for validator or not.
- * Returns true if the algorithms for key and DShash are supported,
- * for at least one RR.
- *
- * @param ds_rrset: the newly received DS rrset.
- * @return true or false if not usable.
- */
-int val_dsset_isusable(struct ub_packed_rrset_key* ds_rrset);
-
-/**
- * Determine by looking at a signed RRset whether or not the RRset name was
- * the result of a wildcard expansion. If so, return the name of the
- * generating wildcard.
- *
- * @param rrset The rrset to chedck.
- * @param wc: the wildcard name, if the rrset was synthesized from a wildcard.
- * unchanged if not. The wildcard name, without "*." in front, is
- * returned. This is a pointer into the rrset owner name.
- * @return false if the signatures are inconsistent in indicating the
- * wildcard status; possible spoofing of wildcard response for other
- * responses is being tried. We lost the status which rrsig was verified
- * after the verification routine finished, so we simply check if
- * the signatures are consistent; inserting a fake signature is a denial
- * of service; but in that you could also have removed the real
- * signature anyway.
- */
-int val_rrset_wildcard(struct ub_packed_rrset_key* rrset, uint8_t** wc);
-
-/**
- * Chase the cname to the next query name.
- * @param qchase: the current query name, updated to next target.
- * @param rep: original message reply to look at CNAMEs.
- * @param cname_skip: the skip into the answer section. Updated to skip
- * DNAME and CNAME to the next part of the answer.
- * @return false on error (bad rdata).
- */
-int val_chase_cname(struct query_info* qchase, struct reply_info* rep,
- size_t* cname_skip);
-
-/**
- * Fill up the chased reply with the content from the original reply;
- * as pointers to those rrsets. Select the part after the cname_skip into
- * the answer section, NS and AR sections that are signed with same signer.
- *
- * @param chase: chased reply, filled up.
- * @param orig: original reply.
- * @param cname_skip: which part of the answer section to skip.
- * The skipped part contains CNAME(and DNAME)s that have been chased.
- * @param name: the signer name to look for.
- * @param len: length of name.
- * @param signer: signer name or NULL if an unsigned RRset is considered.
- * If NULL, rrsets with the lookup name are copied over.
- */
-void val_fill_reply(struct reply_info* chase, struct reply_info* orig,
- size_t cname_skip, uint8_t* name, size_t len, uint8_t* signer);
-
-/**
- * Remove rrset with index from reply, from the authority section.
- * @param rep: reply to remove it from.
- * @param index: rrset to remove, must be in the authority section.
- */
-void val_reply_remove_auth(struct reply_info* rep, size_t index);
-
-/**
- * Remove all unsigned or non-secure status rrsets from NS and AR sections.
- * So that unsigned data does not get let through to clients, when we have
- * found the data to be secure.
- *
- * @param ve: validator environment with cleaning options.
- * @param rep: reply to dump all nonsecure stuff out of.
- */
-void val_check_nonsecure(struct val_env* ve, struct reply_info* rep);
-
-/**
- * Mark all unchecked rrset entries not below a trust anchor as indeterminate.
- * Only security==unchecked rrsets are updated.
- * @param rep: the reply with rrsets.
- * @param anchors: the trust anchors.
- * @param r: rrset cache to store updated security status into.
- * @param env: module environment
- */
-void val_mark_indeterminate(struct reply_info* rep,
- struct val_anchors* anchors, struct rrset_cache* r,
- struct module_env* env);
-
-/**
- * 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 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, uint8_t* kname,
- struct rrset_cache* r, struct module_env* env);
-
-/**
- * Find next unchecked rrset position, return it for skip.
- * @param rep: the original reply to look into.
- * @param skip: the skip now.
- * @return new skip, which may be at the rep->rrset_count position to signal
- * there are no unchecked items.
- */
-size_t val_next_unchecked(struct reply_info* rep, size_t skip);
-
-/**
- * Find the signer name for an RRset.
- * @param rrset: the rrset.
- * @param sname: signer name is returned or NULL if not signed.
- * @param slen: length of sname (or 0).
- */
-void val_find_rrset_signer(struct ub_packed_rrset_key* rrset, uint8_t** sname,
- size_t* slen);
-
-/**
- * Get string to denote the classification result.
- * @param subtype: from classification function.
- * @return static string to describe the classification.
- */
-const char* val_classification_to_string(enum val_classification subtype);
-
-/**
- * Add existing list to blacklist.
- * @param blacklist: the blacklist with result
- * @param region: the region where blacklist is allocated.
- * Allocation failures are logged.
- * @param origin: origin list to add, if NULL, a cache-entry is added to
- * the blacklist to stop cache from being used.
- * @param cross: if true this is a cross-qstate copy, and the 'origin'
- * list is not allocated in the same region as the blacklist.
- */
-void val_blacklist(struct sock_list** blacklist, struct regional* region,
- struct sock_list* origin, int cross);
-
-/**
- * check if has dnssec info, and if it has signed nsecs. gives error reason.
- * @param rep: reply to check.
- * @param reason: returned on fail.
- * @return false if message has no signed nsecs. Can not prove negatives.
- */
-int val_has_signed_nsecs(struct reply_info* rep, char** reason);
-
-/**
- * Return algo number for favorite (best) algorithm that we support in DS.
- * @param ds_rrset: the DSes in this rrset are inspected and best algo chosen.
- * @return algo number or 0 if none supported. 0 is unused as algo number.
- */
-int val_favorite_ds_algo(struct ub_packed_rrset_key* ds_rrset);
-
-/**
- * Find DS denial message in cache. Saves new qstate allocation and allows
- * the validator to use partial content which is not enough to construct a
- * message for network (or user) consumption. Without SOA for example,
- * which is a common occurrence in the unbound code since the referrals contain
- * NSEC/NSEC3 rrs without the SOA element, thus do not allow synthesis of a
- * full negative reply, but do allow synthesis of sufficient proof.
- * @param env: query env with caches and time.
- * @param nm: name of DS record sought.
- * @param nmlen: length of name.
- * @param c: class of DS RR.
- * @param region: where to allocate result.
- * @param topname: name of the key that is currently in use, that will get
- * used to validate the result, and thus no higher entries from the
- * negative cache need to be examined.
- * @return a dns_msg on success. NULL on failure.
- */
-struct dns_msg* val_find_DS(struct module_env* env, uint8_t* nm, size_t nmlen,
- uint16_t c, struct regional* region, uint8_t* topname);
-
-#endif /* VALIDATOR_VAL_UTILS_H */
diff --git a/external/unbound/validator/validator.c b/external/unbound/validator/validator.c
deleted file mode 100644
index 81ba5fa17..000000000
--- a/external/unbound/validator/validator.c
+++ /dev/null
@@ -1,3079 +0,0 @@
-/*
- * validator/validator.c - secure validator DNS query response module
- *
- * Copyright (c) 2007, NLnet Labs. All rights reserved.
- *
- * This software is open source.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- *
- * Redistributions of source code must retain the above copyright notice,
- * this list of conditions and the following disclaimer.
- *
- * Redistributions in binary form must reproduce the above copyright notice,
- * this list of conditions and the following disclaimer in the documentation
- * and/or other materials provided with the distribution.
- *
- * Neither the name of the NLNET LABS nor the names of its contributors may
- * be used to endorse or promote products derived from this software without
- * specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
- * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
- * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
- * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
- * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
- * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-/**
- * \file
- *
- * This file contains a module that performs validation of DNS queries.
- * According to RFC 4034.
- */
-#include "config.h"
-#include "validator/validator.h"
-#include "validator/val_anchor.h"
-#include "validator/val_kcache.h"
-#include "validator/val_kentry.h"
-#include "validator/val_utils.h"
-#include "validator/val_nsec.h"
-#include "validator/val_nsec3.h"
-#include "validator/val_neg.h"
-#include "validator/val_sigcrypt.h"
-#include "validator/autotrust.h"
-#include "services/cache/dns.h"
-#include "util/data/dname.h"
-#include "util/module.h"
-#include "util/log.h"
-#include "util/net_help.h"
-#include "util/regional.h"
-#include "util/config_file.h"
-#include "util/fptr_wlist.h"
-#include "sldns/rrdef.h"
-#include "sldns/wire2str.h"
-
-/* forward decl for cache response and normal super inform calls of a DS */
-static void process_ds_response(struct module_qstate* qstate,
- struct val_qstate* vq, int id, int rcode, struct dns_msg* msg,
- struct query_info* qinfo, struct sock_list* origin);
-
-/** fill up nsec3 key iterations config entry */
-static int
-fill_nsec3_iter(struct val_env* ve, char* s, int c)
-{
- char* e;
- int i;
- free(ve->nsec3_keysize);
- free(ve->nsec3_maxiter);
- ve->nsec3_keysize = (size_t*)calloc(sizeof(size_t), (size_t)c);
- ve->nsec3_maxiter = (size_t*)calloc(sizeof(size_t), (size_t)c);
- if(!ve->nsec3_keysize || !ve->nsec3_maxiter) {
- log_err("out of memory");
- return 0;
- }
- for(i=0; i<c; i++) {
- ve->nsec3_keysize[i] = (size_t)strtol(s, &e, 10);
- if(s == e) {
- log_err("cannot parse: %s", s);
- return 0;
- }
- s = e;
- ve->nsec3_maxiter[i] = (size_t)strtol(s, &e, 10);
- if(s == e) {
- log_err("cannot parse: %s", s);
- return 0;
- }
- s = e;
- if(i>0 && ve->nsec3_keysize[i-1] >= ve->nsec3_keysize[i]) {
- log_err("nsec3 key iterations not ascending: %d %d",
- (int)ve->nsec3_keysize[i-1],
- (int)ve->nsec3_keysize[i]);
- return 0;
- }
- verbose(VERB_ALGO, "validator nsec3cfg keysz %d mxiter %d",
- (int)ve->nsec3_keysize[i], (int)ve->nsec3_maxiter[i]);
- }
- return 1;
-}
-
-/** apply config settings to validator */
-static int
-val_apply_cfg(struct module_env* env, struct val_env* val_env,
- struct config_file* cfg)
-{
- int c;
- val_env->bogus_ttl = (uint32_t)cfg->bogus_ttl;
- val_env->clean_additional = cfg->val_clean_additional;
- val_env->permissive_mode = cfg->val_permissive_mode;
- if(!env->anchors)
- env->anchors = anchors_create();
- if(!env->anchors) {
- log_err("out of memory");
- return 0;
- }
- if(!val_env->kcache)
- val_env->kcache = key_cache_create(cfg);
- if(!val_env->kcache) {
- log_err("out of memory");
- return 0;
- }
- env->key_cache = val_env->kcache;
- if(!anchors_apply_cfg(env->anchors, cfg)) {
- log_err("validator: error in trustanchors config");
- return 0;
- }
- val_env->date_override = cfg->val_date_override;
- val_env->skew_min = cfg->val_sig_skew_min;
- val_env->skew_max = cfg->val_sig_skew_max;
- c = cfg_count_numbers(cfg->val_nsec3_key_iterations);
- if(c < 1 || (c&1)) {
- log_err("validator: unparseable or odd nsec3 key "
- "iterations: %s", cfg->val_nsec3_key_iterations);
- return 0;
- }
- val_env->nsec3_keyiter_count = c/2;
- if(!fill_nsec3_iter(val_env, cfg->val_nsec3_key_iterations, c/2)) {
- log_err("validator: cannot apply nsec3 key iterations");
- return 0;
- }
- if(!val_env->neg_cache)
- val_env->neg_cache = val_neg_create(cfg,
- val_env->nsec3_maxiter[val_env->nsec3_keyiter_count-1]);
- if(!val_env->neg_cache) {
- log_err("out of memory");
- return 0;
- }
- env->neg_cache = val_env->neg_cache;
- return 1;
-}
-
-#ifdef USE_ECDSA_EVP_WORKAROUND
-void ecdsa_evp_workaround_init(void);
-#endif
-int
-val_init(struct module_env* env, int id)
-{
- struct val_env* val_env = (struct val_env*)calloc(1,
- sizeof(struct val_env));
- if(!val_env) {
- log_err("malloc failure");
- return 0;
- }
- env->modinfo[id] = (void*)val_env;
- env->need_to_validate = 1;
- val_env->permissive_mode = 0;
- lock_basic_init(&val_env->bogus_lock);
- lock_protect(&val_env->bogus_lock, &val_env->num_rrset_bogus,
- sizeof(val_env->num_rrset_bogus));
-#ifdef USE_ECDSA_EVP_WORKAROUND
- ecdsa_evp_workaround_init();
-#endif
- if(!val_apply_cfg(env, val_env, env->cfg)) {
- log_err("validator: could not apply configuration settings.");
- return 0;
- }
-
- return 1;
-}
-
-void
-val_deinit(struct module_env* env, int id)
-{
- struct val_env* val_env;
- if(!env || !env->modinfo[id])
- return;
- val_env = (struct val_env*)env->modinfo[id];
- lock_basic_destroy(&val_env->bogus_lock);
- anchors_delete(env->anchors);
- env->anchors = NULL;
- key_cache_delete(val_env->kcache);
- neg_cache_delete(val_env->neg_cache);
- free(val_env->nsec3_keysize);
- free(val_env->nsec3_maxiter);
- free(val_env);
- env->modinfo[id] = NULL;
-}
-
-/** fill in message structure */
-static struct val_qstate*
-val_new_getmsg(struct module_qstate* qstate, struct val_qstate* vq)
-{
- if(!qstate->return_msg || qstate->return_rcode != LDNS_RCODE_NOERROR) {
- /* create a message to verify */
- verbose(VERB_ALGO, "constructing reply for validation");
- vq->orig_msg = (struct dns_msg*)regional_alloc(qstate->region,
- sizeof(struct dns_msg));
- if(!vq->orig_msg)
- return NULL;
- vq->orig_msg->qinfo = qstate->qinfo;
- vq->orig_msg->rep = (struct reply_info*)regional_alloc(
- qstate->region, sizeof(struct reply_info));
- if(!vq->orig_msg->rep)
- return NULL;
- memset(vq->orig_msg->rep, 0, sizeof(struct reply_info));
- vq->orig_msg->rep->flags = (uint16_t)(qstate->return_rcode&0xf)
- |BIT_QR|BIT_RA|(qstate->query_flags|(BIT_CD|BIT_RD));
- vq->orig_msg->rep->qdcount = 1;
- } else {
- vq->orig_msg = qstate->return_msg;
- }
- vq->qchase = qstate->qinfo;
- /* chase reply will be an edited (sub)set of the orig msg rrset ptrs */
- vq->chase_reply = regional_alloc_init(qstate->region,
- vq->orig_msg->rep,
- sizeof(struct reply_info) - sizeof(struct rrset_ref));
- if(!vq->chase_reply)
- return NULL;
- if(vq->orig_msg->rep->rrset_count > RR_COUNT_MAX)
- return NULL; /* protect against integer overflow */
- vq->chase_reply->rrsets = regional_alloc_init(qstate->region,
- vq->orig_msg->rep->rrsets, sizeof(struct ub_packed_rrset_key*)
- * vq->orig_msg->rep->rrset_count);
- if(!vq->chase_reply->rrsets)
- return NULL;
- vq->rrset_skip = 0;
- return vq;
-}
-
-/** allocate new validator query state */
-static struct val_qstate*
-val_new(struct module_qstate* qstate, int id)
-{
- struct val_qstate* vq = (struct val_qstate*)regional_alloc(
- qstate->region, sizeof(*vq));
- log_assert(!qstate->minfo[id]);
- if(!vq)
- return NULL;
- memset(vq, 0, sizeof(*vq));
- qstate->minfo[id] = vq;
- vq->state = VAL_INIT_STATE;
- return val_new_getmsg(qstate, vq);
-}
-
-/**
- * Exit validation with an error status
- *
- * @param qstate: query state
- * @param id: validator id.
- * @return false, for use by caller to return to stop processing.
- */
-static int
-val_error(struct module_qstate* qstate, int id)
-{
- qstate->ext_state[id] = module_error;
- qstate->return_rcode = LDNS_RCODE_SERVFAIL;
- return 0;
-}
-
-/**
- * Check to see if a given response needs to go through the validation
- * process. Typical reasons for this routine to return false are: CD bit was
- * on in the original request, or the response is a kind of message that
- * is unvalidatable (i.e., SERVFAIL, REFUSED, etc.)
- *
- * @param qstate: query state.
- * @param ret_rc: rcode for this message (if noerror - examine ret_msg).
- * @param ret_msg: return msg, can be NULL; look at rcode instead.
- * @return true if the response could use validation (although this does not
- * mean we can actually validate this response).
- */
-static int
-needs_validation(struct module_qstate* qstate, int ret_rc,
- struct dns_msg* ret_msg)
-{
- int rcode;
-
- /* If the CD bit is on in the original request, then you could think
- * that we don't bother to validate anything.
- * But this is signalled internally with the valrec flag.
- * User queries are validated with BIT_CD to make our cache clean
- * so that bogus messages get retried by the upstream also for
- * downstream validators that set BIT_CD.
- * For DNS64 bit_cd signals no dns64 processing, but we want to
- * provide validation there too */
- /*
- if(qstate->query_flags & BIT_CD) {
- verbose(VERB_ALGO, "not validating response due to CD bit");
- return 0;
- }
- */
- if(qstate->is_valrec) {
- verbose(VERB_ALGO, "not validating response, is valrec"
- "(validation recursion lookup)");
- return 0;
- }
-
- if(ret_rc != LDNS_RCODE_NOERROR || !ret_msg)
- rcode = ret_rc;
- else rcode = (int)FLAGS_GET_RCODE(ret_msg->rep->flags);
-
- if(rcode != LDNS_RCODE_NOERROR && rcode != LDNS_RCODE_NXDOMAIN) {
- if(verbosity >= VERB_ALGO) {
- char rc[16];
- rc[0]=0;
- (void)sldns_wire2str_rcode_buf(rcode, rc, sizeof(rc));
- verbose(VERB_ALGO, "cannot validate non-answer, rcode %s", rc);
- }
- return 0;
- }
-
- /* cannot validate positive RRSIG response. (negatives can) */
- if(qstate->qinfo.qtype == LDNS_RR_TYPE_RRSIG &&
- rcode == LDNS_RCODE_NOERROR && ret_msg &&
- ret_msg->rep->an_numrrsets > 0) {
- verbose(VERB_ALGO, "cannot validate RRSIG, no sigs on sigs.");
- return 0;
- }
- return 1;
-}
-
-/**
- * Check to see if the response has already been validated.
- * @param ret_msg: return msg, can be NULL
- * @return true if the response has already been validated
- */
-static int
-already_validated(struct dns_msg* ret_msg)
-{
- /* validate unchecked, and re-validate bogus messages */
- if (ret_msg && ret_msg->rep->security > sec_status_bogus)
- {
- verbose(VERB_ALGO, "response has already been validated: %s",
- sec_status_to_string(ret_msg->rep->security));
- return 1;
- }
- return 0;
-}
-
-/**
- * Generate a request for DNS data.
- *
- * @param qstate: query state that is the parent.
- * @param id: module id.
- * @param name: what name to query for.
- * @param namelen: length of name.
- * @param qtype: query type.
- * @param qclass: query class.
- * @param flags: additional flags, such as the CD bit (BIT_CD), or 0.
- * @return false on alloc failure.
- */
-static int
-generate_request(struct module_qstate* qstate, int id, uint8_t* name,
- size_t namelen, uint16_t qtype, uint16_t qclass, uint16_t flags)
-{
- struct val_qstate* vq = (struct val_qstate*)qstate->minfo[id];
- struct module_qstate* newq;
- struct query_info ask;
- int valrec;
- ask.qname = name;
- ask.qname_len = namelen;
- ask.qtype = qtype;
- ask.qclass = qclass;
- ask.local_alias = NULL;
- log_query_info(VERB_ALGO, "generate request", &ask);
- fptr_ok(fptr_whitelist_modenv_attach_sub(qstate->env->attach_sub));
- /* enable valrec flag to avoid recursion to the same validation
- * routine, this lookup is simply a lookup. DLVs need validation */
- if(qtype == LDNS_RR_TYPE_DLV)
- valrec = 0;
- else valrec = 1;
- if(!(*qstate->env->attach_sub)(qstate, &ask,
- (uint16_t)(BIT_RD|flags), 0, valrec, &newq)){
- log_err("Could not generate request: out of memory");
- return 0;
- }
- /* newq; validator does not need state created for that
- * query, and its a 'normal' for iterator as well */
- if(newq) {
- /* add our blacklist to the query blacklist */
- sock_list_merge(&newq->blacklist, newq->region,
- vq->chain_blacklist);
- }
- qstate->ext_state[id] = module_wait_subquery;
- return 1;
-}
-
-/**
- * Prime trust anchor for use.
- * Generate and dispatch a priming query for the given trust anchor.
- * The trust anchor can be DNSKEY or DS and does not have to be signed.
- *
- * @param qstate: query state.
- * @param vq: validator query state.
- * @param id: module id.
- * @param toprime: what to prime.
- * @return false on a processing error.
- */
-static int
-prime_trust_anchor(struct module_qstate* qstate, struct val_qstate* vq,
- int id, struct trust_anchor* toprime)
-{
- int ret = generate_request(qstate, id, toprime->name, toprime->namelen,
- LDNS_RR_TYPE_DNSKEY, toprime->dclass, BIT_CD);
- if(!ret) {
- log_err("Could not prime trust anchor: out of memory");
- return 0;
- }
- /* ignore newq; validator does not need state created for that
- * query, and its a 'normal' for iterator as well */
- vq->wait_prime_ta = 1; /* to elicit PRIME_RESP_STATE processing
- from the validator inform_super() routine */
- /* store trust anchor name for later lookup when prime returns */
- vq->trust_anchor_name = regional_alloc_init(qstate->region,
- toprime->name, toprime->namelen);
- vq->trust_anchor_len = toprime->namelen;
- vq->trust_anchor_labs = toprime->namelabs;
- if(!vq->trust_anchor_name) {
- log_err("Could not prime trust anchor: out of memory");
- return 0;
- }
- return 1;
-}
-
-/**
- * Validate if the ANSWER and AUTHORITY sections contain valid rrsets.
- * They must be validly signed with the given key.
- * Tries to validate ADDITIONAL rrsets as well, but only to check them.
- * Allows unsigned CNAME after a DNAME that expands the DNAME.
- *
- * Note that by the time this method is called, the process of finding the
- * trusted DNSKEY rrset that signs this response must already have been
- * completed.
- *
- * @param qstate: query state.
- * @param env: module env for verify.
- * @param ve: validator env for verify.
- * @param qchase: query that was made.
- * @param chase_reply: answer to validate.
- * @param key_entry: the key entry, which is trusted, and which matches
- * the signer of the answer. The key entry isgood().
- * @return false if any of the rrsets in the an or ns sections of the message
- * fail to verify. The message is then set to bogus.
- */
-static int
-validate_msg_signatures(struct module_qstate* qstate, struct module_env* env,
- struct val_env* ve, struct query_info* qchase,
- struct reply_info* chase_reply, struct key_entry_key* key_entry)
-{
- uint8_t* sname;
- size_t i, slen;
- struct ub_packed_rrset_key* s;
- enum sec_status sec;
- int dname_seen = 0;
- char* reason = NULL;
-
- /* validate the ANSWER section */
- for(i=0; i<chase_reply->an_numrrsets; i++) {
- s = chase_reply->rrsets[i];
- /* Skip the CNAME following a (validated) DNAME.
- * Because of the normalization routines in the iterator,
- * there will always be an unsigned CNAME following a DNAME
- * (unless qtype=DNAME). */
- if(dname_seen && ntohs(s->rk.type) == LDNS_RR_TYPE_CNAME) {
- dname_seen = 0;
- /* CNAME was synthesized by our own iterator */
- /* since the DNAME verified, mark the CNAME as secure */
- ((struct packed_rrset_data*)s->entry.data)->security =
- sec_status_secure;
- ((struct packed_rrset_data*)s->entry.data)->trust =
- rrset_trust_validated;
- continue;
- }
-
- /* Verify the answer rrset */
- sec = val_verify_rrset_entry(env, ve, s, key_entry, &reason);
- /* If the (answer) rrset failed to validate, then this
- * message is BAD. */
- if(sec != sec_status_secure) {
- log_nametypeclass(VERB_QUERY, "validator: response "
- "has failed ANSWER rrset:", s->rk.dname,
- ntohs(s->rk.type), ntohs(s->rk.rrset_class));
- errinf(qstate, reason);
- if(ntohs(s->rk.type) == LDNS_RR_TYPE_CNAME)
- errinf(qstate, "for CNAME");
- else if(ntohs(s->rk.type) == LDNS_RR_TYPE_DNAME)
- errinf(qstate, "for DNAME");
- errinf_origin(qstate, qstate->reply_origin);
- chase_reply->security = sec_status_bogus;
- return 0;
- }
-
- /* Notice a DNAME that should be followed by an unsigned
- * CNAME. */
- if(qchase->qtype != LDNS_RR_TYPE_DNAME &&
- ntohs(s->rk.type) == LDNS_RR_TYPE_DNAME) {
- dname_seen = 1;
- }
- }
-
- /* validate the AUTHORITY section */
- for(i=chase_reply->an_numrrsets; i<chase_reply->an_numrrsets+
- chase_reply->ns_numrrsets; i++) {
- s = chase_reply->rrsets[i];
- sec = val_verify_rrset_entry(env, ve, s, key_entry, &reason);
- /* If anything in the authority section fails to be secure,
- * we have a bad message. */
- if(sec != sec_status_secure) {
- log_nametypeclass(VERB_QUERY, "validator: response "
- "has failed AUTHORITY rrset:", s->rk.dname,
- ntohs(s->rk.type), ntohs(s->rk.rrset_class));
- errinf(qstate, reason);
- errinf_origin(qstate, qstate->reply_origin);
- errinf_rrset(qstate, s);
- chase_reply->security = sec_status_bogus;
- return 0;
- }
- }
-
- /* attempt to validate the ADDITIONAL section rrsets */
- if(!ve->clean_additional)
- return 1;
- for(i=chase_reply->an_numrrsets+chase_reply->ns_numrrsets;
- i<chase_reply->rrset_count; i++) {
- s = chase_reply->rrsets[i];
- /* only validate rrs that have signatures with the key */
- /* leave others unchecked, those get removed later on too */
- val_find_rrset_signer(s, &sname, &slen);
- if(sname && query_dname_compare(sname, key_entry->name)==0)
- (void)val_verify_rrset_entry(env, ve, s, key_entry,
- &reason);
- /* the additional section can fail to be secure,
- * it is optional, check signature in case we need
- * to clean the additional section later. */
- }
-
- return 1;
-}
-
-/**
- * Detect wrong truncated response (say from BIND 9.6.1 that is forwarding
- * and saw the NS record without signatures from a referral).
- * The positive response has a mangled authority section.
- * Remove that authority section and the additional section.
- * @param rep: reply
- * @return true if a wrongly truncated response.
- */
-static int
-detect_wrongly_truncated(struct reply_info* rep)
-{
- size_t i;
- /* only NS in authority, and it is bogus */
- if(rep->ns_numrrsets != 1 || rep->an_numrrsets == 0)
- return 0;
- if(ntohs(rep->rrsets[ rep->an_numrrsets ]->rk.type) != LDNS_RR_TYPE_NS)
- return 0;
- if(((struct packed_rrset_data*)rep->rrsets[ rep->an_numrrsets ]
- ->entry.data)->security == sec_status_secure)
- return 0;
- /* answer section is present and secure */
- for(i=0; i<rep->an_numrrsets; i++) {
- if(((struct packed_rrset_data*)rep->rrsets[ i ]
- ->entry.data)->security != sec_status_secure)
- return 0;
- }
- verbose(VERB_ALGO, "truncating to minimal response");
- return 1;
-}
-
-/**
- * For messages that are not referrals, if the chase reply contains an
- * unsigned NS record in the authority section it could have been
- * inserted by a (BIND) forwarder that thinks the zone is insecure, and
- * that has an NS record without signatures in cache. Remove the NS
- * record since the reply does not hinge on that record (in the authority
- * section), but do not remove it if it removes the last record from the
- * answer+authority sections.
- * @param chase_reply: the chased reply, we have a key for this contents,
- * so we should have signatures for these rrsets and not having
- * signatures means it will be bogus.
- * @param orig_reply: original reply, remove NS from there as well because
- * we cannot mark the NS record as DNSSEC valid because it is not
- * validated by signatures.
- */
-static void
-remove_spurious_authority(struct reply_info* chase_reply,
- struct reply_info* orig_reply)
-{
- size_t i, found = 0;
- int remove = 0;
- /* if no answer and only 1 auth RRset, do not remove that one */
- if(chase_reply->an_numrrsets == 0 && chase_reply->ns_numrrsets == 1)
- return;
- /* search authority section for unsigned NS records */
- for(i = chase_reply->an_numrrsets;
- i < chase_reply->an_numrrsets+chase_reply->ns_numrrsets; i++) {
- struct packed_rrset_data* d = (struct packed_rrset_data*)
- chase_reply->rrsets[i]->entry.data;
- if(ntohs(chase_reply->rrsets[i]->rk.type) == LDNS_RR_TYPE_NS
- && d->rrsig_count == 0) {
- found = i;
- remove = 1;
- break;
- }
- }
- /* see if we found the entry */
- if(!remove) return;
- log_rrset_key(VERB_ALGO, "Removing spurious unsigned NS record "
- "(likely inserted by forwarder)", chase_reply->rrsets[found]);
-
- /* find rrset in orig_reply */
- for(i = orig_reply->an_numrrsets;
- i < orig_reply->an_numrrsets+orig_reply->ns_numrrsets; i++) {
- if(ntohs(orig_reply->rrsets[i]->rk.type) == LDNS_RR_TYPE_NS
- && query_dname_compare(orig_reply->rrsets[i]->rk.dname,
- chase_reply->rrsets[found]->rk.dname) == 0) {
- /* remove from orig_msg */
- val_reply_remove_auth(orig_reply, i);
- break;
- }
- }
- /* remove rrset from chase_reply */
- val_reply_remove_auth(chase_reply, found);
-}
-
-/**
- * Given a "positive" response -- a response that contains an answer to the
- * question, and no CNAME chain, validate this response.
- *
- * The answer and authority RRsets must already be verified as secure.
- *
- * @param env: module env for verify.
- * @param ve: validator env for verify.
- * @param qchase: query that was made.
- * @param chase_reply: answer to that query to validate.
- * @param kkey: the key entry, which is trusted, and which matches
- * the signer of the answer. The key entry isgood().
- */
-static void
-validate_positive_response(struct module_env* env, struct val_env* ve,
- struct query_info* qchase, struct reply_info* chase_reply,
- struct key_entry_key* kkey)
-{
- uint8_t* wc = NULL;
- int wc_NSEC_ok = 0;
- int nsec3s_seen = 0;
- size_t i;
- struct ub_packed_rrset_key* s;
-
- /* validate the ANSWER section - this will be the answer itself */
- for(i=0; i<chase_reply->an_numrrsets; i++) {
- s = chase_reply->rrsets[i];
-
- /* Check to see if the rrset is the result of a wildcard
- * expansion. If so, an additional check will need to be
- * made in the authority section. */
- if(!val_rrset_wildcard(s, &wc)) {
- log_nametypeclass(VERB_QUERY, "Positive response has "
- "inconsistent wildcard sigs:", s->rk.dname,
- ntohs(s->rk.type), ntohs(s->rk.rrset_class));
- chase_reply->security = sec_status_bogus;
- return;
- }
- }
-
- /* validate the AUTHORITY section as well - this will generally be
- * the NS rrset (which could be missing, no problem) */
- for(i=chase_reply->an_numrrsets; i<chase_reply->an_numrrsets+
- chase_reply->ns_numrrsets; i++) {
- s = chase_reply->rrsets[i];
-
- /* If this is a positive wildcard response, and we have a
- * (just verified) NSEC record, try to use it to 1) prove
- * that qname doesn't exist and 2) that the correct wildcard
- * was used. */
- if(wc != NULL && ntohs(s->rk.type) == LDNS_RR_TYPE_NSEC) {
- if(val_nsec_proves_positive_wildcard(s, qchase, wc)) {
- wc_NSEC_ok = 1;
- }
- /* if not, continue looking for proof */
- }
-
- /* Otherwise, if this is a positive wildcard response and
- * we have NSEC3 records */
- if(wc != NULL && ntohs(s->rk.type) == LDNS_RR_TYPE_NSEC3) {
- nsec3s_seen = 1;
- }
- }
-
- /* If this was a positive wildcard response that we haven't already
- * proven, and we have NSEC3 records, try to prove it using the NSEC3
- * records. */
- if(wc != NULL && !wc_NSEC_ok && nsec3s_seen) {
- enum sec_status sec = nsec3_prove_wildcard(env, ve,
- chase_reply->rrsets+chase_reply->an_numrrsets,
- chase_reply->ns_numrrsets, qchase, kkey, wc);
- if(sec == sec_status_insecure) {
- verbose(VERB_ALGO, "Positive wildcard response is "
- "insecure");
- chase_reply->security = sec_status_insecure;
- return;
- } else if(sec == sec_status_secure)
- wc_NSEC_ok = 1;
- }
-
- /* If after all this, we still haven't proven the positive wildcard
- * response, fail. */
- if(wc != NULL && !wc_NSEC_ok) {
- verbose(VERB_QUERY, "positive response was wildcard "
- "expansion and did not prove original data "
- "did not exist");
- chase_reply->security = sec_status_bogus;
- return;
- }
-
- verbose(VERB_ALGO, "Successfully validated positive response");
- chase_reply->security = sec_status_secure;
-}
-
-/**
- * Validate a NOERROR/NODATA signed response -- a response that has a
- * NOERROR Rcode but no ANSWER section RRsets. This consists of making
- * certain that the authority section NSEC/NSEC3s proves that the qname
- * does exist and the qtype doesn't.
- *
- * The answer and authority RRsets must already be verified as secure.
- *
- * @param env: module env for verify.
- * @param ve: validator env for verify.
- * @param qchase: query that was made.
- * @param chase_reply: answer to that query to validate.
- * @param kkey: the key entry, which is trusted, and which matches
- * the signer of the answer. The key entry isgood().
- */
-static void
-validate_nodata_response(struct module_env* env, struct val_env* ve,
- struct query_info* qchase, struct reply_info* chase_reply,
- struct key_entry_key* kkey)
-{
- /* Since we are here, there must be nothing in the ANSWER section to
- * validate. */
- /* (Note: CNAME/DNAME responses will not directly get here --
- * instead, they are chased down into individual CNAME validations,
- * and at the end of the cname chain a POSITIVE, or CNAME_NOANSWER
- * validation.) */
-
- /* validate the AUTHORITY section */
- int has_valid_nsec = 0; /* If true, then the NODATA has been proven.*/
- uint8_t* ce = NULL; /* for wildcard nodata responses. This is the
- proven closest encloser. */
- uint8_t* wc = NULL; /* for wildcard nodata responses. wildcard nsec */
- int nsec3s_seen = 0; /* nsec3s seen */
- struct ub_packed_rrset_key* s;
- size_t i;
-
- for(i=chase_reply->an_numrrsets; i<chase_reply->an_numrrsets+
- chase_reply->ns_numrrsets; i++) {
- s = chase_reply->rrsets[i];
- /* If we encounter an NSEC record, try to use it to prove
- * NODATA.
- * This needs to handle the ENT NODATA case. */
- if(ntohs(s->rk.type) == LDNS_RR_TYPE_NSEC) {
- if(nsec_proves_nodata(s, qchase, &wc)) {
- has_valid_nsec = 1;
- /* sets wc-encloser if wildcard applicable */
- }
- if(val_nsec_proves_name_error(s, qchase->qname)) {
- ce = nsec_closest_encloser(qchase->qname, s);
- }
- if(val_nsec_proves_insecuredelegation(s, qchase)) {
- verbose(VERB_ALGO, "delegation is insecure");
- chase_reply->security = sec_status_insecure;
- return;
- }
- } else if(ntohs(s->rk.type) == LDNS_RR_TYPE_NSEC3) {
- nsec3s_seen = 1;
- }
- }
-
- /* check to see if we have a wildcard NODATA proof. */
-
- /* The wildcard NODATA is 1 NSEC proving that qname does not exist
- * (and also proving what the closest encloser is), and 1 NSEC
- * showing the matching wildcard, which must be *.closest_encloser. */
- if(wc && !ce)
- has_valid_nsec = 0;
- else if(wc && ce) {
- if(query_dname_compare(wc, ce) != 0) {
- has_valid_nsec = 0;
- }
- }
-
- if(!has_valid_nsec && nsec3s_seen) {
- enum sec_status sec = nsec3_prove_nodata(env, ve,
- chase_reply->rrsets+chase_reply->an_numrrsets,
- chase_reply->ns_numrrsets, qchase, kkey);
- if(sec == sec_status_insecure) {
- verbose(VERB_ALGO, "NODATA response is insecure");
- chase_reply->security = sec_status_insecure;
- return;
- } else if(sec == sec_status_secure)
- has_valid_nsec = 1;
- }
-
- if(!has_valid_nsec) {
- verbose(VERB_QUERY, "NODATA response failed to prove NODATA "
- "status with NSEC/NSEC3");
- if(verbosity >= VERB_ALGO)
- log_dns_msg("Failed NODATA", qchase, chase_reply);
- chase_reply->security = sec_status_bogus;
- return;
- }
-
- verbose(VERB_ALGO, "successfully validated NODATA response.");
- chase_reply->security = sec_status_secure;
-}
-
-/**
- * Validate a NAMEERROR signed response -- a response that has a NXDOMAIN
- * Rcode.
- * This consists of making certain that the authority section NSEC proves
- * that the qname doesn't exist and the covering wildcard also doesn't exist..
- *
- * The answer and authority RRsets must have already been verified as secure.
- *
- * @param env: module env for verify.
- * @param ve: validator env for verify.
- * @param qchase: query that was made.
- * @param chase_reply: answer to that query to validate.
- * @param kkey: the key entry, which is trusted, and which matches
- * the signer of the answer. The key entry isgood().
- * @param rcode: adjusted RCODE, in case of RCODE/proof mismatch leniency.
- */
-static void
-validate_nameerror_response(struct module_env* env, struct val_env* ve,
- struct query_info* qchase, struct reply_info* chase_reply,
- struct key_entry_key* kkey, int* rcode)
-{
- int has_valid_nsec = 0;
- int has_valid_wnsec = 0;
- int nsec3s_seen = 0;
- struct ub_packed_rrset_key* s;
- size_t i;
-
- for(i=chase_reply->an_numrrsets; i<chase_reply->an_numrrsets+
- chase_reply->ns_numrrsets; i++) {
- s = chase_reply->rrsets[i];
- if(ntohs(s->rk.type) == LDNS_RR_TYPE_NSEC) {
- if(val_nsec_proves_name_error(s, qchase->qname))
- has_valid_nsec = 1;
- if(val_nsec_proves_no_wc(s, qchase->qname,
- qchase->qname_len))
- has_valid_wnsec = 1;
- if(val_nsec_proves_insecuredelegation(s, qchase)) {
- verbose(VERB_ALGO, "delegation is insecure");
- chase_reply->security = sec_status_insecure;
- return;
- }
- } else if(ntohs(s->rk.type) == LDNS_RR_TYPE_NSEC3)
- nsec3s_seen = 1;
- }
-
- if((!has_valid_nsec || !has_valid_wnsec) && nsec3s_seen) {
- /* use NSEC3 proof, both answer and auth rrsets, in case
- * NSEC3s end up in the answer (due to qtype=NSEC3 or so) */
- chase_reply->security = nsec3_prove_nameerror(env, ve,
- chase_reply->rrsets, chase_reply->an_numrrsets+
- chase_reply->ns_numrrsets, qchase, kkey);
- if(chase_reply->security != sec_status_secure) {
- verbose(VERB_QUERY, "NameError response failed nsec, "
- "nsec3 proof was %s", sec_status_to_string(
- chase_reply->security));
- return;
- }
- has_valid_nsec = 1;
- has_valid_wnsec = 1;
- }
-
- /* If the message fails to prove either condition, it is bogus. */
- if(!has_valid_nsec) {
- verbose(VERB_QUERY, "NameError response has failed to prove: "
- "qname does not exist");
- chase_reply->security = sec_status_bogus;
- /* Be lenient with RCODE in NSEC NameError responses */
- validate_nodata_response(env, ve, qchase, chase_reply, kkey);
- if (chase_reply->security == sec_status_secure)
- *rcode = LDNS_RCODE_NOERROR;
- return;
- }
-
- if(!has_valid_wnsec) {
- verbose(VERB_QUERY, "NameError response has failed to prove: "
- "covering wildcard does not exist");
- chase_reply->security = sec_status_bogus;
- /* Be lenient with RCODE in NSEC NameError responses */
- validate_nodata_response(env, ve, qchase, chase_reply, kkey);
- if (chase_reply->security == sec_status_secure)
- *rcode = LDNS_RCODE_NOERROR;
- return;
- }
-
- /* Otherwise, we consider the message secure. */
- verbose(VERB_ALGO, "successfully validated NAME ERROR response.");
- chase_reply->security = sec_status_secure;
-}
-
-/**
- * Given a referral response, validate rrsets and take least trusted rrset
- * as the current validation status.
- *
- * Note that by the time this method is called, the process of finding the
- * trusted DNSKEY rrset that signs this response must already have been
- * completed.
- *
- * @param chase_reply: answer to validate.
- */
-static void
-validate_referral_response(struct reply_info* chase_reply)
-{
- size_t i;
- enum sec_status s;
- /* message security equals lowest rrset security */
- chase_reply->security = sec_status_secure;
- for(i=0; i<chase_reply->rrset_count; i++) {
- s = ((struct packed_rrset_data*)chase_reply->rrsets[i]
- ->entry.data)->security;
- if(s < chase_reply->security)
- chase_reply->security = s;
- }
- verbose(VERB_ALGO, "validated part of referral response as %s",
- sec_status_to_string(chase_reply->security));
-}
-
-/**
- * Given an "ANY" response -- a response that contains an answer to a
- * qtype==ANY question, with answers. This does no checking that all
- * types are present.
- *
- * NOTE: it may be possible to get parent-side delegation point records
- * here, which won't all be signed. Right now, this routine relies on the
- * upstream iterative resolver to not return these responses -- instead
- * treating them as referrals.
- *
- * NOTE: RFC 4035 is silent on this issue, so this may change upon
- * clarification. Clarification draft -05 says to not check all types are
- * present.
- *
- * Note that by the time this method is called, the process of finding the
- * trusted DNSKEY rrset that signs this response must already have been
- * completed.
- *
- * @param env: module env for verify.
- * @param ve: validator env for verify.
- * @param qchase: query that was made.
- * @param chase_reply: answer to that query to validate.
- * @param kkey: the key entry, which is trusted, and which matches
- * the signer of the answer. The key entry isgood().
- */
-static void
-validate_any_response(struct module_env* env, struct val_env* ve,
- struct query_info* qchase, struct reply_info* chase_reply,
- struct key_entry_key* kkey)
-{
- /* all answer and auth rrsets already verified */
- /* but check if a wildcard response is given, then check NSEC/NSEC3
- * for qname denial to see if wildcard is applicable */
- uint8_t* wc = NULL;
- int wc_NSEC_ok = 0;
- int nsec3s_seen = 0;
- size_t i;
- struct ub_packed_rrset_key* s;
-
- if(qchase->qtype != LDNS_RR_TYPE_ANY) {
- log_err("internal error: ANY validation called for non-ANY");
- chase_reply->security = sec_status_bogus;
- return;
- }
-
- /* validate the ANSWER section - this will be the answer itself */
- for(i=0; i<chase_reply->an_numrrsets; i++) {
- s = chase_reply->rrsets[i];
-
- /* Check to see if the rrset is the result of a wildcard
- * expansion. If so, an additional check will need to be
- * made in the authority section. */
- if(!val_rrset_wildcard(s, &wc)) {
- log_nametypeclass(VERB_QUERY, "Positive ANY response"
- " has inconsistent wildcard sigs:",
- s->rk.dname, ntohs(s->rk.type),
- ntohs(s->rk.rrset_class));
- chase_reply->security = sec_status_bogus;
- return;
- }
- }
-
- /* if it was a wildcard, check for NSEC/NSEC3s in both answer
- * and authority sections (NSEC may be moved to the ANSWER section) */
- if(wc != NULL)
- for(i=0; i<chase_reply->an_numrrsets+chase_reply->ns_numrrsets;
- i++) {
- s = chase_reply->rrsets[i];
-
- /* If this is a positive wildcard response, and we have a
- * (just verified) NSEC record, try to use it to 1) prove
- * that qname doesn't exist and 2) that the correct wildcard
- * was used. */
- if(ntohs(s->rk.type) == LDNS_RR_TYPE_NSEC) {
- if(val_nsec_proves_positive_wildcard(s, qchase, wc)) {
- wc_NSEC_ok = 1;
- }
- /* if not, continue looking for proof */
- }
-
- /* Otherwise, if this is a positive wildcard response and
- * we have NSEC3 records */
- if(ntohs(s->rk.type) == LDNS_RR_TYPE_NSEC3) {
- nsec3s_seen = 1;
- }
- }
-
- /* If this was a positive wildcard response that we haven't already
- * proven, and we have NSEC3 records, try to prove it using the NSEC3
- * records. */
- if(wc != NULL && !wc_NSEC_ok && nsec3s_seen) {
- /* look both in answer and auth section for NSEC3s */
- enum sec_status sec = nsec3_prove_wildcard(env, ve,
- chase_reply->rrsets,
- chase_reply->an_numrrsets+chase_reply->ns_numrrsets,
- qchase, kkey, wc);
- if(sec == sec_status_insecure) {
- verbose(VERB_ALGO, "Positive ANY wildcard response is "
- "insecure");
- chase_reply->security = sec_status_insecure;
- return;
- } else if(sec == sec_status_secure)
- wc_NSEC_ok = 1;
- }
-
- /* If after all this, we still haven't proven the positive wildcard
- * response, fail. */
- if(wc != NULL && !wc_NSEC_ok) {
- verbose(VERB_QUERY, "positive ANY response was wildcard "
- "expansion and did not prove original data "
- "did not exist");
- chase_reply->security = sec_status_bogus;
- return;
- }
-
- verbose(VERB_ALGO, "Successfully validated positive ANY response");
- chase_reply->security = sec_status_secure;
-}
-
-/**
- * Validate CNAME response, or DNAME+CNAME.
- * This is just like a positive proof, except that this is about a
- * DNAME+CNAME. Possible wildcard proof.
- * Difference with positive proof is that this routine refuses
- * wildcarded DNAMEs.
- *
- * The answer and authority rrsets must already be verified as secure.
- *
- * @param env: module env for verify.
- * @param ve: validator env for verify.
- * @param qchase: query that was made.
- * @param chase_reply: answer to that query to validate.
- * @param kkey: the key entry, which is trusted, and which matches
- * the signer of the answer. The key entry isgood().
- */
-static void
-validate_cname_response(struct module_env* env, struct val_env* ve,
- struct query_info* qchase, struct reply_info* chase_reply,
- struct key_entry_key* kkey)
-{
- uint8_t* wc = NULL;
- int wc_NSEC_ok = 0;
- int nsec3s_seen = 0;
- size_t i;
- struct ub_packed_rrset_key* s;
-
- /* validate the ANSWER section - this will be the CNAME (+DNAME) */
- for(i=0; i<chase_reply->an_numrrsets; i++) {
- s = chase_reply->rrsets[i];
-
- /* Check to see if the rrset is the result of a wildcard
- * expansion. If so, an additional check will need to be
- * made in the authority section. */
- if(!val_rrset_wildcard(s, &wc)) {
- log_nametypeclass(VERB_QUERY, "Cname response has "
- "inconsistent wildcard sigs:", s->rk.dname,
- ntohs(s->rk.type), ntohs(s->rk.rrset_class));
- chase_reply->security = sec_status_bogus;
- return;
- }
-
- /* Refuse wildcarded DNAMEs rfc 4597.
- * Do not follow a wildcarded DNAME because
- * its synthesized CNAME expansion is underdefined */
- if(qchase->qtype != LDNS_RR_TYPE_DNAME &&
- ntohs(s->rk.type) == LDNS_RR_TYPE_DNAME && wc) {
- log_nametypeclass(VERB_QUERY, "cannot validate a "
- "wildcarded DNAME:", s->rk.dname,
- ntohs(s->rk.type), ntohs(s->rk.rrset_class));
- chase_reply->security = sec_status_bogus;
- return;
- }
-
- /* If we have found a CNAME, stop looking for one.
- * The iterator has placed the CNAME chain in correct
- * order. */
- if (ntohs(s->rk.type) == LDNS_RR_TYPE_CNAME) {
- break;
- }
- }
-
- /* AUTHORITY section */
- for(i=chase_reply->an_numrrsets; i<chase_reply->an_numrrsets+
- chase_reply->ns_numrrsets; i++) {
- s = chase_reply->rrsets[i];
-
- /* If this is a positive wildcard response, and we have a
- * (just verified) NSEC record, try to use it to 1) prove
- * that qname doesn't exist and 2) that the correct wildcard
- * was used. */
- if(wc != NULL && ntohs(s->rk.type) == LDNS_RR_TYPE_NSEC) {
- if(val_nsec_proves_positive_wildcard(s, qchase, wc)) {
- wc_NSEC_ok = 1;
- }
- /* if not, continue looking for proof */
- }
-
- /* Otherwise, if this is a positive wildcard response and
- * we have NSEC3 records */
- if(wc != NULL && ntohs(s->rk.type) == LDNS_RR_TYPE_NSEC3) {
- nsec3s_seen = 1;
- }
- }
-
- /* If this was a positive wildcard response that we haven't already
- * proven, and we have NSEC3 records, try to prove it using the NSEC3
- * records. */
- if(wc != NULL && !wc_NSEC_ok && nsec3s_seen) {
- enum sec_status sec = nsec3_prove_wildcard(env, ve,
- chase_reply->rrsets+chase_reply->an_numrrsets,
- chase_reply->ns_numrrsets, qchase, kkey, wc);
- if(sec == sec_status_insecure) {
- verbose(VERB_ALGO, "wildcard CNAME response is "
- "insecure");
- chase_reply->security = sec_status_insecure;
- return;
- } else if(sec == sec_status_secure)
- wc_NSEC_ok = 1;
- }
-
- /* If after all this, we still haven't proven the positive wildcard
- * response, fail. */
- if(wc != NULL && !wc_NSEC_ok) {
- verbose(VERB_QUERY, "CNAME response was wildcard "
- "expansion and did not prove original data "
- "did not exist");
- chase_reply->security = sec_status_bogus;
- return;
- }
-
- verbose(VERB_ALGO, "Successfully validated CNAME response");
- chase_reply->security = sec_status_secure;
-}
-
-/**
- * Validate CNAME NOANSWER response, no more data after a CNAME chain.
- * This can be a NODATA or a NAME ERROR case, but not both at the same time.
- * We don't know because the rcode has been set to NOERROR by the CNAME.
- *
- * The answer and authority rrsets must already be verified as secure.
- *
- * @param env: module env for verify.
- * @param ve: validator env for verify.
- * @param qchase: query that was made.
- * @param chase_reply: answer to that query to validate.
- * @param kkey: the key entry, which is trusted, and which matches
- * the signer of the answer. The key entry isgood().
- */
-static void
-validate_cname_noanswer_response(struct module_env* env, struct val_env* ve,
- struct query_info* qchase, struct reply_info* chase_reply,
- struct key_entry_key* kkey)
-{
- int nodata_valid_nsec = 0; /* If true, then NODATA has been proven.*/
- uint8_t* ce = NULL; /* for wildcard nodata responses. This is the
- proven closest encloser. */
- uint8_t* wc = NULL; /* for wildcard nodata responses. wildcard nsec */
- int nxdomain_valid_nsec = 0; /* if true, namerror has been proven */
- int nxdomain_valid_wnsec = 0;
- int nsec3s_seen = 0; /* nsec3s seen */
- struct ub_packed_rrset_key* s;
- size_t i;
-
- /* the AUTHORITY section */
- for(i=chase_reply->an_numrrsets; i<chase_reply->an_numrrsets+
- chase_reply->ns_numrrsets; i++) {
- s = chase_reply->rrsets[i];
-
- /* If we encounter an NSEC record, try to use it to prove
- * NODATA. This needs to handle the ENT NODATA case.
- * Also try to prove NAMEERROR, and absence of a wildcard */
- if(ntohs(s->rk.type) == LDNS_RR_TYPE_NSEC) {
- if(nsec_proves_nodata(s, qchase, &wc)) {
- nodata_valid_nsec = 1;
- /* set wc encloser if wildcard applicable */
- }
- if(val_nsec_proves_name_error(s, qchase->qname)) {
- ce = nsec_closest_encloser(qchase->qname, s);
- nxdomain_valid_nsec = 1;
- }
- if(val_nsec_proves_no_wc(s, qchase->qname,
- qchase->qname_len))
- nxdomain_valid_wnsec = 1;
- if(val_nsec_proves_insecuredelegation(s, qchase)) {
- verbose(VERB_ALGO, "delegation is insecure");
- chase_reply->security = sec_status_insecure;
- return;
- }
- } else if(ntohs(s->rk.type) == LDNS_RR_TYPE_NSEC3) {
- nsec3s_seen = 1;
- }
- }
-
- /* check to see if we have a wildcard NODATA proof. */
-
- /* The wildcard NODATA is 1 NSEC proving that qname does not exists
- * (and also proving what the closest encloser is), and 1 NSEC
- * showing the matching wildcard, which must be *.closest_encloser. */
- if(wc && !ce)
- nodata_valid_nsec = 0;
- else if(wc && ce) {
- if(query_dname_compare(wc, ce) != 0) {
- nodata_valid_nsec = 0;
- }
- }
- if(nxdomain_valid_nsec && !nxdomain_valid_wnsec) {
- /* name error is missing wildcard denial proof */
- nxdomain_valid_nsec = 0;
- }
-
- if(nodata_valid_nsec && nxdomain_valid_nsec) {
- verbose(VERB_QUERY, "CNAMEchain to noanswer proves that name "
- "exists and not exists, bogus");
- chase_reply->security = sec_status_bogus;
- return;
- }
- if(!nodata_valid_nsec && !nxdomain_valid_nsec && nsec3s_seen) {
- int nodata;
- enum sec_status sec = nsec3_prove_nxornodata(env, ve,
- chase_reply->rrsets+chase_reply->an_numrrsets,
- chase_reply->ns_numrrsets, qchase, kkey, &nodata);
- if(sec == sec_status_insecure) {
- verbose(VERB_ALGO, "CNAMEchain to noanswer response "
- "is insecure");
- chase_reply->security = sec_status_insecure;
- return;
- } else if(sec == sec_status_secure) {
- if(nodata)
- nodata_valid_nsec = 1;
- else nxdomain_valid_nsec = 1;
- }
- }
-
- if(!nodata_valid_nsec && !nxdomain_valid_nsec) {
- verbose(VERB_QUERY, "CNAMEchain to noanswer response failed "
- "to prove status with NSEC/NSEC3");
- if(verbosity >= VERB_ALGO)
- log_dns_msg("Failed CNAMEnoanswer", qchase, chase_reply);
- chase_reply->security = sec_status_bogus;
- return;
- }
-
- if(nodata_valid_nsec)
- verbose(VERB_ALGO, "successfully validated CNAME chain to a "
- "NODATA response.");
- else verbose(VERB_ALGO, "successfully validated CNAME chain to a "
- "NAMEERROR response.");
- chase_reply->security = sec_status_secure;
-}
-
-/**
- * Process init state for validator.
- * Process the INIT state. First tier responses start in the INIT state.
- * This is where they are vetted for validation suitability, and the initial
- * key search is done.
- *
- * Currently, events the come through this routine will be either promoted
- * to FINISHED/CNAME_RESP (no validation needed), FINDKEY (next step to
- * validation), or will be (temporarily) retired and a new priming request
- * event will be generated.
- *
- * @param qstate: query state.
- * @param vq: validator query state.
- * @param ve: validator shared global environment.
- * @param id: module id.
- * @return true if the event should be processed further on return, false if
- * not.
- */
-static int
-processInit(struct module_qstate* qstate, struct val_qstate* vq,
- struct val_env* ve, int id)
-{
- uint8_t* lookup_name;
- size_t lookup_len;
- struct trust_anchor* anchor;
- enum val_classification subtype = val_classify_response(
- qstate->query_flags, &qstate->qinfo, &vq->qchase,
- vq->orig_msg->rep, vq->rrset_skip);
- if(vq->restart_count > VAL_MAX_RESTART_COUNT) {
- verbose(VERB_ALGO, "restart count exceeded");
- return val_error(qstate, id);
- }
- verbose(VERB_ALGO, "validator classification %s",
- val_classification_to_string(subtype));
- if(subtype == VAL_CLASS_REFERRAL &&
- vq->rrset_skip < vq->orig_msg->rep->rrset_count) {
- /* referral uses the rrset name as qchase, to find keys for
- * that rrset */
- vq->qchase.qname = vq->orig_msg->rep->
- rrsets[vq->rrset_skip]->rk.dname;
- vq->qchase.qname_len = vq->orig_msg->rep->
- rrsets[vq->rrset_skip]->rk.dname_len;
- vq->qchase.qtype = ntohs(vq->orig_msg->rep->
- rrsets[vq->rrset_skip]->rk.type);
- vq->qchase.qclass = ntohs(vq->orig_msg->rep->
- rrsets[vq->rrset_skip]->rk.rrset_class);
- }
- lookup_name = vq->qchase.qname;
- lookup_len = vq->qchase.qname_len;
- /* for type DS look at the parent side for keys/trustanchor */
- /* also for NSEC not at apex */
- if(vq->qchase.qtype == LDNS_RR_TYPE_DS ||
- (vq->qchase.qtype == LDNS_RR_TYPE_NSEC &&
- vq->orig_msg->rep->rrset_count > vq->rrset_skip &&
- ntohs(vq->orig_msg->rep->rrsets[vq->rrset_skip]->rk.type) ==
- LDNS_RR_TYPE_NSEC &&
- !(vq->orig_msg->rep->rrsets[vq->rrset_skip]->
- rk.flags&PACKED_RRSET_NSEC_AT_APEX))) {
- dname_remove_label(&lookup_name, &lookup_len);
- }
-
- val_mark_indeterminate(vq->chase_reply, qstate->env->anchors,
- qstate->env->rrset_cache, qstate->env);
- vq->key_entry = NULL;
- vq->empty_DS_name = NULL;
- vq->ds_rrset = 0;
- anchor = anchors_lookup(qstate->env->anchors,
- lookup_name, lookup_len, vq->qchase.qclass);
-
- /* Determine the signer/lookup name */
- val_find_signer(subtype, &vq->qchase, vq->orig_msg->rep,
- vq->rrset_skip, &vq->signer_name, &vq->signer_len);
- if(vq->signer_name != NULL &&
- !dname_subdomain_c(lookup_name, vq->signer_name)) {
- log_nametypeclass(VERB_ALGO, "this signer name is not a parent "
- "of lookupname, omitted", vq->signer_name, 0, 0);
- vq->signer_name = NULL;
- }
- if(vq->signer_name == NULL) {
- log_nametypeclass(VERB_ALGO, "no signer, using", lookup_name,
- 0, 0);
- } else {
- lookup_name = vq->signer_name;
- lookup_len = vq->signer_len;
- log_nametypeclass(VERB_ALGO, "signer is", lookup_name, 0, 0);
- }
-
- /* for NXDOMAIN it could be signed by a parent of the trust anchor */
- if(subtype == VAL_CLASS_NAMEERROR && vq->signer_name &&
- anchor && dname_strict_subdomain_c(anchor->name, lookup_name)){
- lock_basic_unlock(&anchor->lock);
- anchor = anchors_lookup(qstate->env->anchors,
- lookup_name, lookup_len, vq->qchase.qclass);
- if(!anchor) { /* unsigned parent denies anchor*/
- verbose(VERB_QUERY, "unsigned parent zone denies"
- " trust anchor, indeterminate");
- vq->chase_reply->security = sec_status_indeterminate;
- vq->state = VAL_FINISHED_STATE;
- return 1;
- }
- verbose(VERB_ALGO, "trust anchor NXDOMAIN by signed parent");
- } else if(subtype == VAL_CLASS_POSITIVE &&
- qstate->qinfo.qtype == LDNS_RR_TYPE_DNSKEY &&
- query_dname_compare(lookup_name, qstate->qinfo.qname) == 0) {
- /* is a DNSKEY so lookup a bit higher since we want to
- * get it from a parent or from trustanchor */
- dname_remove_label(&lookup_name, &lookup_len);
- }
-
- if(vq->rrset_skip > 0 || subtype == VAL_CLASS_CNAME ||
- subtype == VAL_CLASS_REFERRAL) {
- /* extract this part of orig_msg into chase_reply for
- * the eventual VALIDATE stage */
- val_fill_reply(vq->chase_reply, vq->orig_msg->rep,
- vq->rrset_skip, lookup_name, lookup_len,
- vq->signer_name);
- if(verbosity >= VERB_ALGO)
- log_dns_msg("chased extract", &vq->qchase,
- vq->chase_reply);
- }
-
- vq->key_entry = key_cache_obtain(ve->kcache, lookup_name, lookup_len,
- vq->qchase.qclass, qstate->region, *qstate->env->now);
-
- /* there is no key(from DLV) and no trust anchor */
- if(vq->key_entry == NULL && anchor == NULL) {
- /*response isn't under a trust anchor, so we cannot validate.*/
- vq->chase_reply->security = sec_status_indeterminate;
- /* go to finished state to cache this result */
- vq->state = VAL_FINISHED_STATE;
- return 1;
- }
- /* if not key, or if keyentry is *above* the trustanchor, i.e.
- * the keyentry is based on another (higher) trustanchor */
- else if(vq->key_entry == NULL || (anchor &&
- dname_strict_subdomain_c(anchor->name, vq->key_entry->name))) {
- /* trust anchor is an 'unsigned' trust anchor */
- if(anchor && anchor->numDS == 0 && anchor->numDNSKEY == 0) {
- vq->chase_reply->security = sec_status_insecure;
- val_mark_insecure(vq->chase_reply, anchor->name,
- qstate->env->rrset_cache, qstate->env);
- lock_basic_unlock(&anchor->lock);
- vq->dlv_checked=1; /* skip DLV check */
- /* 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, anchor)) {
- lock_basic_unlock(&anchor->lock);
- return val_error(qstate, id);
- }
- lock_basic_unlock(&anchor->lock);
- /* and otherwise, don't continue processing this event.
- * (it will be reactivated when the priming query returns). */
- vq->state = VAL_FINDKEY_STATE;
- return 0;
- }
- if(anchor) {
- lock_basic_unlock(&anchor->lock);
- }
-
- if(key_entry_isnull(vq->key_entry)) {
- /* response is under a null key, so we cannot validate
- * 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->name,
- qstate->env->rrset_cache, qstate->env);
- /* go to finished state to cache this result */
- vq->state = VAL_FINISHED_STATE;
- return 1;
- } else if(key_entry_isbad(vq->key_entry)) {
- /* key is bad, chain is bad, reply is bogus */
- errinf_dname(qstate, "key for validation", vq->key_entry->name);
- errinf(qstate, "is marked as invalid");
- if(key_entry_get_reason(vq->key_entry)) {
- errinf(qstate, "because of a previous");
- errinf(qstate, key_entry_get_reason(vq->key_entry));
- }
- /* no retries, stop bothering the authority until timeout */
- vq->restart_count = VAL_MAX_RESTART_COUNT;
- vq->chase_reply->security = sec_status_bogus;
- vq->state = VAL_FINISHED_STATE;
- return 1;
- }
-
- /* otherwise, we have our "closest" cached key -- continue
- * processing in the next state. */
- vq->state = VAL_FINDKEY_STATE;
- return 1;
-}
-
-/**
- * Process the FINDKEY state. Generally this just calculates the next name
- * to query and either issues a DS or a DNSKEY query. It will check to see
- * if the correct key has already been reached, in which case it will
- * advance the event to the next state.
- *
- * @param qstate: query state.
- * @param vq: validator query state.
- * @param id: module id.
- * @return true if the event should be processed further on return, false if
- * not.
- */
-static int
-processFindKey(struct module_qstate* qstate, struct val_qstate* vq, int id)
-{
- uint8_t* target_key_name, *current_key_name;
- size_t target_key_len;
- int strip_lab;
-
- log_query_info(VERB_ALGO, "validator: FindKey", &vq->qchase);
- /* We know that state.key_entry is not 0 or bad key -- if it were,
- * then previous processing should have directed this event to
- * a different state.
- * It could be an isnull key, which signals that a DLV was just
- * done and the DNSKEY after the DLV failed with dnssec-retry state
- * and the DNSKEY has to be performed again. */
- log_assert(vq->key_entry && !key_entry_isbad(vq->key_entry));
- if(key_entry_isnull(vq->key_entry)) {
- if(!generate_request(qstate, id, vq->ds_rrset->rk.dname,
- vq->ds_rrset->rk.dname_len, LDNS_RR_TYPE_DNSKEY,
- vq->qchase.qclass, BIT_CD)) {
- log_err("mem error generating DNSKEY request");
- return val_error(qstate, id);
- }
- return 0;
- }
-
- target_key_name = vq->signer_name;
- target_key_len = vq->signer_len;
- if(!target_key_name) {
- target_key_name = vq->qchase.qname;
- target_key_len = vq->qchase.qname_len;
- }
-
- current_key_name = vq->key_entry->name;
-
- /* If our current key entry matches our target, then we are done. */
- if(query_dname_compare(target_key_name, current_key_name) == 0) {
- vq->state = VAL_VALIDATE_STATE;
- return 1;
- }
-
- if(vq->empty_DS_name) {
- /* if the last empty nonterminal/emptyDS name we detected is
- * below the current key, use that name to make progress
- * along the chain of trust */
- if(query_dname_compare(target_key_name,
- vq->empty_DS_name) == 0) {
- /* do not query for empty_DS_name again */
- verbose(VERB_ALGO, "Cannot retrieve DS for signature");
- errinf(qstate, "no signatures");
- errinf_origin(qstate, qstate->reply_origin);
- vq->chase_reply->security = sec_status_bogus;
- vq->state = VAL_FINISHED_STATE;
- return 1;
- }
- current_key_name = vq->empty_DS_name;
- }
-
- log_nametypeclass(VERB_ALGO, "current keyname", current_key_name,
- LDNS_RR_TYPE_DNSKEY, LDNS_RR_CLASS_IN);
- log_nametypeclass(VERB_ALGO, "target keyname", target_key_name,
- LDNS_RR_TYPE_DNSKEY, LDNS_RR_CLASS_IN);
- /* assert we are walking down the DNS tree */
- if(!dname_subdomain_c(target_key_name, current_key_name)) {
- verbose(VERB_ALGO, "bad signer name");
- vq->chase_reply->security = sec_status_bogus;
- vq->state = VAL_FINISHED_STATE;
- return 1;
- }
- /* so this value is >= -1 */
- strip_lab = dname_count_labels(target_key_name) -
- dname_count_labels(current_key_name) - 1;
- log_assert(strip_lab >= -1);
- verbose(VERB_ALGO, "striplab %d", strip_lab);
- if(strip_lab > 0) {
- dname_remove_labels(&target_key_name, &target_key_len,
- strip_lab);
- }
- log_nametypeclass(VERB_ALGO, "next keyname", target_key_name,
- LDNS_RR_TYPE_DNSKEY, LDNS_RR_CLASS_IN);
-
- /* The next step is either to query for the next DS, or to query
- * for the next DNSKEY. */
- if(vq->ds_rrset)
- log_nametypeclass(VERB_ALGO, "DS RRset", vq->ds_rrset->rk.dname, LDNS_RR_TYPE_DS, LDNS_RR_CLASS_IN);
- else verbose(VERB_ALGO, "No DS RRset");
-
- if(vq->ds_rrset && query_dname_compare(vq->ds_rrset->rk.dname,
- vq->key_entry->name) != 0) {
- if(!generate_request(qstate, id, vq->ds_rrset->rk.dname,
- vq->ds_rrset->rk.dname_len, LDNS_RR_TYPE_DNSKEY,
- vq->qchase.qclass, BIT_CD)) {
- log_err("mem error generating DNSKEY request");
- return val_error(qstate, id);
- }
- return 0;
- }
-
- if(!vq->ds_rrset || query_dname_compare(vq->ds_rrset->rk.dname,
- target_key_name) != 0) {
- /* check if there is a cache entry : pick up an NSEC if
- * there is no DS, check if that NSEC has DS-bit unset, and
- * thus can disprove the secure delegation we seek.
- * We can then use that NSEC even in the absence of a SOA
- * record that would be required by the iterator to supply
- * a completely protocol-correct response.
- * Uses negative cache for NSEC3 lookup of DS responses. */
- /* only if cache not blacklisted, of course */
- struct dns_msg* msg;
- if(!qstate->blacklist && !vq->chain_blacklist &&
- (msg=val_find_DS(qstate->env, target_key_name,
- target_key_len, vq->qchase.qclass, qstate->region,
- vq->key_entry->name)) ) {
- verbose(VERB_ALGO, "Process cached DS response");
- process_ds_response(qstate, vq, id, LDNS_RCODE_NOERROR,
- msg, &msg->qinfo, NULL);
- return 1; /* continue processing ds-response results */
- }
- if(!generate_request(qstate, id, target_key_name,
- target_key_len, LDNS_RR_TYPE_DS, vq->qchase.qclass,
- BIT_CD)) {
- log_err("mem error generating DS request");
- return val_error(qstate, id);
- }
- return 0;
- }
-
- /* Otherwise, it is time to query for the DNSKEY */
- if(!generate_request(qstate, id, vq->ds_rrset->rk.dname,
- vq->ds_rrset->rk.dname_len, LDNS_RR_TYPE_DNSKEY,
- vq->qchase.qclass, BIT_CD)) {
- log_err("mem error generating DNSKEY request");
- return val_error(qstate, id);
- }
-
- return 0;
-}
-
-/**
- * Process the VALIDATE stage, the init and findkey stages are finished,
- * and the right keys are available to validate the response.
- * Or, there are no keys available, in order to invalidate the response.
- *
- * After validation, the status is recorded in the message and rrsets,
- * and finished state is started.
- *
- * @param qstate: query state.
- * @param vq: validator query state.
- * @param ve: validator shared global environment.
- * @param id: module id.
- * @return true if the event should be processed further on return, false if
- * not.
- */
-static int
-processValidate(struct module_qstate* qstate, struct val_qstate* vq,
- struct val_env* ve, int id)
-{
- enum val_classification subtype;
- int rcode;
-
- if(!vq->key_entry) {
- verbose(VERB_ALGO, "validate: no key entry, failed");
- return val_error(qstate, id);
- }
-
- /* This is the default next state. */
- vq->state = VAL_FINISHED_STATE;
-
- /* Unsigned responses must be underneath a "null" key entry.*/
- if(key_entry_isnull(vq->key_entry)) {
- 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->name,
- qstate->env->rrset_cache, qstate->env);
- key_cache_insert(ve->kcache, vq->key_entry, qstate);
- return 1;
- }
-
- if(key_entry_isbad(vq->key_entry)) {
- log_nametypeclass(VERB_DETAIL, "Could not establish a chain "
- "of trust to keys for", vq->key_entry->name,
- LDNS_RR_TYPE_DNSKEY, vq->key_entry->key_class);
- vq->chase_reply->security = sec_status_bogus;
- errinf(qstate, "while building chain of trust");
- if(vq->restart_count >= VAL_MAX_RESTART_COUNT)
- key_cache_insert(ve->kcache, vq->key_entry, qstate);
- return 1;
- }
-
- /* signerName being null is the indicator that this response was
- * unsigned */
- if(vq->signer_name == NULL) {
- log_query_info(VERB_ALGO, "processValidate: state has no "
- "signer name", &vq->qchase);
- verbose(VERB_DETAIL, "Could not establish validation of "
- "INSECURE status of unsigned response.");
- errinf(qstate, "no signatures");
- errinf_origin(qstate, qstate->reply_origin);
- vq->chase_reply->security = sec_status_bogus;
- return 1;
- }
- subtype = val_classify_response(qstate->query_flags, &qstate->qinfo,
- &vq->qchase, vq->orig_msg->rep, vq->rrset_skip);
- if(subtype != VAL_CLASS_REFERRAL)
- remove_spurious_authority(vq->chase_reply, vq->orig_msg->rep);
-
- /* check signatures in the message;
- * answer and authority must be valid, additional is only checked. */
- if(!validate_msg_signatures(qstate, qstate->env, ve, &vq->qchase,
- vq->chase_reply, vq->key_entry)) {
- /* workaround bad recursor out there that truncates (even
- * with EDNS4k) to 512 by removing RRSIG from auth section
- * for positive replies*/
- if((subtype == VAL_CLASS_POSITIVE || subtype == VAL_CLASS_ANY
- || subtype == VAL_CLASS_CNAME) &&
- detect_wrongly_truncated(vq->orig_msg->rep)) {
- /* truncate the message some more */
- vq->orig_msg->rep->ns_numrrsets = 0;
- vq->orig_msg->rep->ar_numrrsets = 0;
- vq->orig_msg->rep->rrset_count =
- vq->orig_msg->rep->an_numrrsets;
- vq->chase_reply->ns_numrrsets = 0;
- vq->chase_reply->ar_numrrsets = 0;
- vq->chase_reply->rrset_count =
- vq->chase_reply->an_numrrsets;
- qstate->errinf = NULL;
- }
- else {
- verbose(VERB_DETAIL, "Validate: message contains "
- "bad rrsets");
- return 1;
- }
- }
-
- switch(subtype) {
- case VAL_CLASS_POSITIVE:
- verbose(VERB_ALGO, "Validating a positive response");
- validate_positive_response(qstate->env, ve,
- &vq->qchase, vq->chase_reply, vq->key_entry);
- verbose(VERB_DETAIL, "validate(positive): %s",
- sec_status_to_string(
- vq->chase_reply->security));
- break;
-
- case VAL_CLASS_NODATA:
- verbose(VERB_ALGO, "Validating a nodata response");
- validate_nodata_response(qstate->env, ve,
- &vq->qchase, vq->chase_reply, vq->key_entry);
- verbose(VERB_DETAIL, "validate(nodata): %s",
- sec_status_to_string(
- vq->chase_reply->security));
- break;
-
- case VAL_CLASS_NAMEERROR:
- rcode = (int)FLAGS_GET_RCODE(vq->orig_msg->rep->flags);
- verbose(VERB_ALGO, "Validating a nxdomain response");
- validate_nameerror_response(qstate->env, ve,
- &vq->qchase, vq->chase_reply, vq->key_entry, &rcode);
- verbose(VERB_DETAIL, "validate(nxdomain): %s",
- sec_status_to_string(
- vq->chase_reply->security));
- FLAGS_SET_RCODE(vq->orig_msg->rep->flags, rcode);
- FLAGS_SET_RCODE(vq->chase_reply->flags, rcode);
- break;
-
- case VAL_CLASS_CNAME:
- verbose(VERB_ALGO, "Validating a cname response");
- validate_cname_response(qstate->env, ve,
- &vq->qchase, vq->chase_reply, vq->key_entry);
- verbose(VERB_DETAIL, "validate(cname): %s",
- sec_status_to_string(
- vq->chase_reply->security));
- break;
-
- case VAL_CLASS_CNAMENOANSWER:
- verbose(VERB_ALGO, "Validating a cname noanswer "
- "response");
- validate_cname_noanswer_response(qstate->env, ve,
- &vq->qchase, vq->chase_reply, vq->key_entry);
- verbose(VERB_DETAIL, "validate(cname_noanswer): %s",
- sec_status_to_string(
- vq->chase_reply->security));
- break;
-
- case VAL_CLASS_REFERRAL:
- verbose(VERB_ALGO, "Validating a referral response");
- validate_referral_response(vq->chase_reply);
- verbose(VERB_DETAIL, "validate(referral): %s",
- sec_status_to_string(
- vq->chase_reply->security));
- break;
-
- case VAL_CLASS_ANY:
- verbose(VERB_ALGO, "Validating a positive ANY "
- "response");
- validate_any_response(qstate->env, ve, &vq->qchase,
- vq->chase_reply, vq->key_entry);
- verbose(VERB_DETAIL, "validate(positive_any): %s",
- sec_status_to_string(
- vq->chase_reply->security));
- break;
-
- default:
- log_err("validate: unhandled response subtype: %d",
- subtype);
- }
- if(vq->chase_reply->security == sec_status_bogus) {
- if(subtype == VAL_CLASS_POSITIVE)
- errinf(qstate, "wildcard");
- else errinf(qstate, val_classification_to_string(subtype));
- errinf(qstate, "proof failed");
- errinf_origin(qstate, qstate->reply_origin);
- }
-
- return 1;
-}
-
-/**
- * Init DLV check.
- * DLV is going to be decommissioned, but the code is still here for some time.
- *
- * Called when a query is determined by other trust anchors to be insecure
- * (or indeterminate). Then we look if there is a key in the DLV.
- * Performs aggressive negative cache check to see if there is no key.
- * Otherwise, spawns a DLV query, and changes to the DLV wait state.
- *
- * @param qstate: query state.
- * @param vq: validator query state.
- * @param ve: validator shared global environment.
- * @param id: module id.
- * @return true if there is no DLV.
- * false: processing is finished for the validator operate().
- * This function may exit in three ways:
- * o no DLV (aggressive cache), so insecure. (true)
- * o error - stop processing (false)
- * o DLV lookup was started, stop processing (false)
- */
-static int
-val_dlv_init(struct module_qstate* qstate, struct val_qstate* vq,
- struct val_env* ve, int id)
-{
- uint8_t* nm;
- size_t nm_len;
- /* there must be a DLV configured */
- log_assert(qstate->env->anchors->dlv_anchor);
- /* this bool is true to avoid looping in the DLV checks */
- log_assert(vq->dlv_checked);
-
- /* init the DLV lookup variables */
- vq->dlv_lookup_name = NULL;
- vq->dlv_lookup_name_len = 0;
- vq->dlv_insecure_at = NULL;
- vq->dlv_insecure_at_len = 0;
-
- /* Determine the name for which we want to lookup DLV.
- * This name is for the current message, or
- * for the current RRset for CNAME, referral subtypes.
- * If there is a signer, use that, otherwise the domain name */
- if(vq->signer_name) {
- nm = vq->signer_name;
- nm_len = vq->signer_len;
- } else {
- /* use qchase */
- nm = vq->qchase.qname;
- nm_len = vq->qchase.qname_len;
- if(vq->qchase.qtype == LDNS_RR_TYPE_DS)
- dname_remove_label(&nm, &nm_len);
- }
- log_nametypeclass(VERB_ALGO, "DLV init look", nm, LDNS_RR_TYPE_DS,
- vq->qchase.qclass);
- log_assert(nm && nm_len);
- /* sanity check: no DLV lookups below the DLV anchor itself.
- * Like, an securely insecure delegation there makes no sense. */
- if(dname_subdomain_c(nm, qstate->env->anchors->dlv_anchor->name)) {
- verbose(VERB_ALGO, "DLV lookup within DLV repository denied");
- return 1;
- }
- /* concat name (minus root label) + dlv name */
- vq->dlv_lookup_name_len = nm_len - 1 +
- qstate->env->anchors->dlv_anchor->namelen;
- vq->dlv_lookup_name = regional_alloc(qstate->region,
- vq->dlv_lookup_name_len);
- if(!vq->dlv_lookup_name) {
- log_err("Out of memory preparing DLV lookup");
- return val_error(qstate, id);
- }
- memmove(vq->dlv_lookup_name, nm, nm_len-1);
- memmove(vq->dlv_lookup_name+nm_len-1,
- qstate->env->anchors->dlv_anchor->name,
- qstate->env->anchors->dlv_anchor->namelen);
- log_nametypeclass(VERB_ALGO, "DLV name", vq->dlv_lookup_name,
- LDNS_RR_TYPE_DLV, vq->qchase.qclass);
-
- /* determine where the insecure point was determined, the DLV must
- * be equal or below that to continue building the trust chain
- * down. May be NULL if no trust chain was built yet */
- nm = NULL;
- if(vq->key_entry && key_entry_isnull(vq->key_entry)) {
- nm = vq->key_entry->name;
- nm_len = vq->key_entry->namelen;
- }
- if(nm) {
- vq->dlv_insecure_at_len = nm_len - 1 +
- qstate->env->anchors->dlv_anchor->namelen;
- vq->dlv_insecure_at = regional_alloc(qstate->region,
- vq->dlv_insecure_at_len);
- if(!vq->dlv_insecure_at) {
- log_err("Out of memory preparing DLV lookup");
- return val_error(qstate, id);
- }
- memmove(vq->dlv_insecure_at, nm, nm_len-1);
- memmove(vq->dlv_insecure_at+nm_len-1,
- qstate->env->anchors->dlv_anchor->name,
- qstate->env->anchors->dlv_anchor->namelen);
- log_nametypeclass(VERB_ALGO, "insecure_at",
- vq->dlv_insecure_at, 0, vq->qchase.qclass);
- }
-
- /* If we can find the name in the aggressive negative cache,
- * give up; insecure is the answer */
- while(val_neg_dlvlookup(ve->neg_cache, vq->dlv_lookup_name,
- vq->dlv_lookup_name_len, vq->qchase.qclass,
- qstate->env->rrset_cache, *qstate->env->now)) {
- /* go up */
- dname_remove_label(&vq->dlv_lookup_name,
- &vq->dlv_lookup_name_len);
- /* too high? */
- if(!dname_subdomain_c(vq->dlv_lookup_name,
- qstate->env->anchors->dlv_anchor->name)) {
- verbose(VERB_ALGO, "ask above dlv repo");
- return 1; /* Above the repo is insecure */
- }
- /* above chain of trust? */
- if(vq->dlv_insecure_at && !dname_subdomain_c(
- vq->dlv_lookup_name, vq->dlv_insecure_at)) {
- verbose(VERB_ALGO, "ask above insecure endpoint");
- return 1;
- }
- }
-
- /* perform a lookup for the DLV; with validation */
- vq->state = VAL_DLVLOOKUP_STATE;
- if(!generate_request(qstate, id, vq->dlv_lookup_name,
- vq->dlv_lookup_name_len, LDNS_RR_TYPE_DLV,
- vq->qchase.qclass, 0)) {
- return val_error(qstate, id);
- }
-
- /* Find the closest encloser DLV from the repository.
- * then that is used to build another chain of trust
- * This may first require a query 'too low' that has NSECs in
- * the answer, from which we determine the closest encloser DLV.
- * When determine the closest encloser, skip empty nonterminals,
- * since we want a nonempty node in the DLV repository. */
-
- return 0;
-}
-
-/**
- * The Finished state. The validation status (good or bad) has been determined.
- *
- * @param qstate: query state.
- * @param vq: validator query state.
- * @param ve: validator shared global environment.
- * @param id: module id.
- * @return true if the event should be processed further on return, false if
- * not.
- */
-static int
-processFinished(struct module_qstate* qstate, struct val_qstate* vq,
- struct val_env* ve, int id)
-{
- enum val_classification subtype = val_classify_response(
- qstate->query_flags, &qstate->qinfo, &vq->qchase,
- vq->orig_msg->rep, vq->rrset_skip);
-
- /* if the result is insecure or indeterminate and we have not
- * checked the DLV yet, check the DLV */
- if((vq->chase_reply->security == sec_status_insecure ||
- vq->chase_reply->security == sec_status_indeterminate) &&
- qstate->env->anchors->dlv_anchor && !vq->dlv_checked) {
- vq->dlv_checked = 1;
- if(!val_dlv_init(qstate, vq, ve, id))
- return 0;
- }
-
- /* store overall validation result in orig_msg */
- if(vq->rrset_skip == 0)
- vq->orig_msg->rep->security = vq->chase_reply->security;
- else if(subtype != VAL_CLASS_REFERRAL ||
- vq->rrset_skip < vq->orig_msg->rep->an_numrrsets +
- vq->orig_msg->rep->ns_numrrsets) {
- /* ignore sec status of additional section if a referral
- * type message skips there and
- * use the lowest security status as end result. */
- if(vq->chase_reply->security < vq->orig_msg->rep->security)
- vq->orig_msg->rep->security =
- vq->chase_reply->security;
- }
-
- if(subtype == VAL_CLASS_REFERRAL) {
- /* for a referral, move to next unchecked rrset and check it*/
- vq->rrset_skip = val_next_unchecked(vq->orig_msg->rep,
- vq->rrset_skip);
- if(vq->rrset_skip < vq->orig_msg->rep->rrset_count) {
- /* and restart for this rrset */
- verbose(VERB_ALGO, "validator: go to next rrset");
- vq->chase_reply->security = sec_status_unchecked;
- vq->dlv_checked = 0; /* can do DLV for this RR */
- vq->state = VAL_INIT_STATE;
- return 1;
- }
- /* referral chase is done */
- }
- if(vq->chase_reply->security != sec_status_bogus &&
- subtype == VAL_CLASS_CNAME) {
- /* chase the CNAME; process next part of the message */
- if(!val_chase_cname(&vq->qchase, vq->orig_msg->rep,
- &vq->rrset_skip)) {
- verbose(VERB_ALGO, "validator: failed to chase CNAME");
- vq->orig_msg->rep->security = sec_status_bogus;
- } else {
- /* restart process for new qchase at rrset_skip */
- log_query_info(VERB_ALGO, "validator: chased to",
- &vq->qchase);
- vq->chase_reply->security = sec_status_unchecked;
- vq->dlv_checked = 0; /* can do DLV for this RR */
- vq->state = VAL_INIT_STATE;
- return 1;
- }
- }
-
- if(vq->orig_msg->rep->security == sec_status_secure) {
- /* If the message is secure, check that all rrsets are
- * secure (i.e. some inserted RRset for CNAME chain with
- * a different signer name). And drop additional rrsets
- * that are not secure (if clean-additional option is set) */
- /* this may cause the msg to be marked bogus */
- val_check_nonsecure(ve, vq->orig_msg->rep);
- if(vq->orig_msg->rep->security == sec_status_secure) {
- log_query_info(VERB_DETAIL, "validation success",
- &qstate->qinfo);
- }
- }
-
- /* if the result is bogus - set message ttl to bogus ttl to avoid
- * endless bogus revalidation */
- if(vq->orig_msg->rep->security == sec_status_bogus) {
- /* see if we can try again to fetch data */
- if(vq->restart_count < VAL_MAX_RESTART_COUNT) {
- int restart_count = vq->restart_count+1;
- verbose(VERB_ALGO, "validation failed, "
- "blacklist and retry to fetch data");
- val_blacklist(&qstate->blacklist, qstate->region,
- qstate->reply_origin, 0);
- qstate->reply_origin = NULL;
- qstate->errinf = NULL;
- memset(vq, 0, sizeof(*vq));
- vq->restart_count = restart_count;
- vq->state = VAL_INIT_STATE;
- verbose(VERB_ALGO, "pass back to next module");
- qstate->ext_state[id] = module_restart_next;
- return 0;
- }
-
- vq->orig_msg->rep->ttl = ve->bogus_ttl;
- vq->orig_msg->rep->prefetch_ttl =
- PREFETCH_TTL_CALC(vq->orig_msg->rep->ttl);
- if(qstate->env->cfg->val_log_level >= 1 &&
- !qstate->env->cfg->val_log_squelch) {
- if(qstate->env->cfg->val_log_level < 2)
- log_query_info(0, "validation failure",
- &qstate->qinfo);
- else {
- char* err = errinf_to_str(qstate);
- if(err) log_info("%s", err);
- free(err);
- }
- }
- /* If we are in permissive mode, bogus gets indeterminate */
- if(ve->permissive_mode)
- vq->orig_msg->rep->security = sec_status_indeterminate;
- }
-
- /* store results in cache */
- if(qstate->query_flags&BIT_RD) {
- /* if secure, this will override cache anyway, no need
- * to check if from parentNS */
- if(!qstate->no_cache_store) {
- if(!dns_cache_store(qstate->env, &vq->orig_msg->qinfo,
- vq->orig_msg->rep, 0, qstate->prefetch_leeway, 0, NULL,
- qstate->query_flags)) {
- log_err("out of memory caching validator results");
- }
- }
- } else {
- /* for a referral, store the verified RRsets */
- /* and this does not get prefetched, so no leeway */
- if(!dns_cache_store(qstate->env, &vq->orig_msg->qinfo,
- vq->orig_msg->rep, 1, 0, 0, NULL,
- qstate->query_flags)) {
- log_err("out of memory caching validator results");
- }
- }
- qstate->return_rcode = LDNS_RCODE_NOERROR;
- qstate->return_msg = vq->orig_msg;
- qstate->ext_state[id] = module_finished;
- return 0;
-}
-
-/**
- * The DLVLookup state. Process DLV lookups.
- *
- * @param qstate: query state.
- * @param vq: validator query state.
- * @param ve: validator shared global environment.
- * @param id: module id.
- * @return true if the event should be processed further on return, false if
- * not.
- */
-static int
-processDLVLookup(struct module_qstate* qstate, struct val_qstate* vq,
- struct val_env* ve, int id)
-{
- /* see if this we are ready to continue normal resolution */
- /* we may need more DLV lookups */
- if(vq->dlv_status==dlv_error)
- verbose(VERB_ALGO, "DLV woke up with status dlv_error");
- else if(vq->dlv_status==dlv_success)
- verbose(VERB_ALGO, "DLV woke up with status dlv_success");
- else if(vq->dlv_status==dlv_ask_higher)
- verbose(VERB_ALGO, "DLV woke up with status dlv_ask_higher");
- else if(vq->dlv_status==dlv_there_is_no_dlv)
- verbose(VERB_ALGO, "DLV woke up with status dlv_there_is_no_dlv");
- else verbose(VERB_ALGO, "DLV woke up with status unknown");
-
- if(vq->dlv_status == dlv_error) {
- verbose(VERB_QUERY, "failed DLV lookup");
- return val_error(qstate, id);
- } else if(vq->dlv_status == dlv_success) {
- uint8_t* nm;
- size_t nmlen;
- /* chain continues with DNSKEY, continue in FINDKEY */
- vq->state = VAL_FINDKEY_STATE;
-
- /* strip off the DLV suffix from the name; could result in . */
- log_assert(dname_subdomain_c(vq->ds_rrset->rk.dname,
- qstate->env->anchors->dlv_anchor->name));
- nmlen = vq->ds_rrset->rk.dname_len -
- qstate->env->anchors->dlv_anchor->namelen + 1;
- nm = regional_alloc_init(qstate->region,
- vq->ds_rrset->rk.dname, nmlen);
- if(!nm) {
- log_err("Out of memory in DLVLook");
- return val_error(qstate, id);
- }
- nm[nmlen-1] = 0;
-
- vq->ds_rrset->rk.dname = nm;
- vq->ds_rrset->rk.dname_len = nmlen;
-
- /* create a nullentry for the key so the dnskey lookup
- * can be retried after a validation failure for it */
- vq->key_entry = key_entry_create_null(qstate->region,
- nm, nmlen, vq->qchase.qclass, 0, 0);
- if(!vq->key_entry) {
- log_err("Out of memory in DLVLook");
- return val_error(qstate, id);
- }
-
- if(!generate_request(qstate, id, vq->ds_rrset->rk.dname,
- vq->ds_rrset->rk.dname_len, LDNS_RR_TYPE_DNSKEY,
- vq->qchase.qclass, BIT_CD)) {
- log_err("mem error generating DNSKEY request");
- return val_error(qstate, id);
- }
- return 0;
- } else if(vq->dlv_status == dlv_there_is_no_dlv) {
- /* continue with the insecure result we got */
- vq->state = VAL_FINISHED_STATE;
- return 1;
- }
- log_assert(vq->dlv_status == dlv_ask_higher);
-
- /* ask higher, make sure we stay in DLV repo, below dlv_at */
- if(!dname_subdomain_c(vq->dlv_lookup_name,
- qstate->env->anchors->dlv_anchor->name)) {
- /* just like, there is no DLV */
- verbose(VERB_ALGO, "ask above dlv repo");
- vq->state = VAL_FINISHED_STATE;
- return 1;
- }
- if(vq->dlv_insecure_at && !dname_subdomain_c(vq->dlv_lookup_name,
- vq->dlv_insecure_at)) {
- /* already checked a chain lower than dlv_lookup_name */
- verbose(VERB_ALGO, "ask above insecure endpoint");
- log_nametypeclass(VERB_ALGO, "enpt", vq->dlv_insecure_at, 0, 0);
- vq->state = VAL_FINISHED_STATE;
- return 1;
- }
-
- /* check negative cache before making new request */
- if(val_neg_dlvlookup(ve->neg_cache, vq->dlv_lookup_name,
- vq->dlv_lookup_name_len, vq->qchase.qclass,
- qstate->env->rrset_cache, *qstate->env->now)) {
- /* does not exist, go up one (go higher). */
- dname_remove_label(&vq->dlv_lookup_name,
- &vq->dlv_lookup_name_len);
- /* limit number of labels, limited number of recursion */
- return processDLVLookup(qstate, vq, ve, id);
- }
-
- if(!generate_request(qstate, id, vq->dlv_lookup_name,
- vq->dlv_lookup_name_len, LDNS_RR_TYPE_DLV,
- vq->qchase.qclass, 0)) {
- return val_error(qstate, id);
- }
-
- return 0;
-}
-
-/**
- * Handle validator state.
- * If a method returns true, the next state is started. If false, then
- * processing will stop.
- * @param qstate: query state.
- * @param vq: validator query state.
- * @param ve: validator shared global environment.
- * @param id: module id.
- */
-static void
-val_handle(struct module_qstate* qstate, struct val_qstate* vq,
- struct val_env* ve, int id)
-{
- int cont = 1;
- while(cont) {
- verbose(VERB_ALGO, "val handle processing q with state %s",
- val_state_to_string(vq->state));
- switch(vq->state) {
- case VAL_INIT_STATE:
- cont = processInit(qstate, vq, ve, id);
- break;
- case VAL_FINDKEY_STATE:
- cont = processFindKey(qstate, vq, id);
- break;
- case VAL_VALIDATE_STATE:
- cont = processValidate(qstate, vq, ve, id);
- break;
- case VAL_FINISHED_STATE:
- cont = processFinished(qstate, vq, ve, id);
- break;
- case VAL_DLVLOOKUP_STATE:
- cont = processDLVLookup(qstate, vq, ve, id);
- break;
- default:
- log_warn("validator: invalid state %d",
- vq->state);
- cont = 0;
- break;
- }
- }
-}
-
-void
-val_operate(struct module_qstate* qstate, enum module_ev event, int id,
- struct outbound_entry* outbound)
-{
- struct val_env* ve = (struct val_env*)qstate->env->modinfo[id];
- struct val_qstate* vq = (struct val_qstate*)qstate->minfo[id];
- verbose(VERB_QUERY, "validator[module %d] operate: extstate:%s "
- "event:%s", id, strextstate(qstate->ext_state[id]),
- strmodulevent(event));
- log_query_info(VERB_QUERY, "validator operate: query",
- &qstate->qinfo);
- if(vq && qstate->qinfo.qname != vq->qchase.qname)
- log_query_info(VERB_QUERY, "validator operate: chased to",
- &vq->qchase);
- (void)outbound;
- 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;
- return;
- }
- if(event == module_event_moddone) {
- /* check if validation is needed */
- verbose(VERB_ALGO, "validator: nextmodule returned");
-
- if(!needs_validation(qstate, qstate->return_rcode,
- qstate->return_msg)) {
- /* no need to validate this */
- if(qstate->return_msg)
- qstate->return_msg->rep->security =
- sec_status_indeterminate;
- qstate->ext_state[id] = module_finished;
- return;
- }
- if(already_validated(qstate->return_msg)) {
- qstate->ext_state[id] = module_finished;
- return;
- }
- /* qclass ANY should have validation result from spawned
- * queries. If we get here, it is bogus or an internal error */
- if(qstate->qinfo.qclass == LDNS_RR_CLASS_ANY) {
- verbose(VERB_ALGO, "cannot validate classANY: bogus");
- if(qstate->return_msg)
- qstate->return_msg->rep->security =
- sec_status_bogus;
- qstate->ext_state[id] = module_finished;
- return;
- }
- /* create state to start validation */
- qstate->ext_state[id] = module_error; /* override this */
- if(!vq) {
- vq = val_new(qstate, id);
- if(!vq) {
- log_err("validator: malloc failure");
- qstate->ext_state[id] = module_error;
- return;
- }
- } else if(!vq->orig_msg) {
- if(!val_new_getmsg(qstate, vq)) {
- log_err("validator: malloc failure");
- qstate->ext_state[id] = module_error;
- return;
- }
- }
- 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;
-}
-
-/**
- * Evaluate the response to a priming request.
- *
- * @param dnskey_rrset: DNSKEY rrset (can be NULL if none) in prime reply.
- * (this rrset is allocated in the wrong region, not the qstate).
- * @param ta: trust anchor.
- * @param qstate: qstate that needs key.
- * @param id: module id.
- * @return new key entry or NULL on allocation failure.
- * The key entry will either contain a validated DNSKEY rrset, or
- * represent a Null key (query failed, but validation did not), or a
- * Bad key (validation failed).
- */
-static struct key_entry_key*
-primeResponseToKE(struct ub_packed_rrset_key* dnskey_rrset,
- struct trust_anchor* ta, struct module_qstate* qstate, int id)
-{
- struct val_env* ve = (struct val_env*)qstate->env->modinfo[id];
- struct key_entry_key* kkey = NULL;
- enum sec_status sec = sec_status_unchecked;
- char* reason = NULL;
- int downprot = qstate->env->cfg->harden_algo_downgrade;
-
- if(!dnskey_rrset) {
- log_nametypeclass(VERB_OPS, "failed to prime trust anchor -- "
- "could not fetch DNSKEY rrset",
- ta->name, LDNS_RR_TYPE_DNSKEY, ta->dclass);
- if(qstate->env->cfg->harden_dnssec_stripped) {
- errinf(qstate, "no DNSKEY rrset");
- kkey = key_entry_create_bad(qstate->region, ta->name,
- ta->namelen, ta->dclass, BOGUS_KEY_TTL,
- *qstate->env->now);
- } else kkey = key_entry_create_null(qstate->region, ta->name,
- ta->namelen, ta->dclass, NULL_KEY_TTL,
- *qstate->env->now);
- if(!kkey) {
- log_err("out of memory: allocate fail prime key");
- return NULL;
- }
- return kkey;
- }
- /* attempt to verify with trust anchor DS and DNSKEY */
- kkey = val_verify_new_DNSKEYs_with_ta(qstate->region, qstate->env, ve,
- dnskey_rrset, ta->ds_rrset, ta->dnskey_rrset, downprot,
- &reason);
- if(!kkey) {
- log_err("out of memory: verifying prime TA");
- return NULL;
- }
- if(key_entry_isgood(kkey))
- sec = sec_status_secure;
- else
- sec = sec_status_bogus;
- verbose(VERB_DETAIL, "validate keys with anchor(DS): %s",
- sec_status_to_string(sec));
-
- if(sec != sec_status_secure) {
- log_nametypeclass(VERB_OPS, "failed to prime trust anchor -- "
- "DNSKEY rrset is not secure",
- ta->name, LDNS_RR_TYPE_DNSKEY, ta->dclass);
- /* NOTE: in this case, we should probably reject the trust
- * anchor for longer, perhaps forever. */
- if(qstate->env->cfg->harden_dnssec_stripped) {
- errinf(qstate, reason);
- kkey = key_entry_create_bad(qstate->region, ta->name,
- ta->namelen, ta->dclass, BOGUS_KEY_TTL,
- *qstate->env->now);
- } else kkey = key_entry_create_null(qstate->region, ta->name,
- ta->namelen, ta->dclass, NULL_KEY_TTL,
- *qstate->env->now);
- if(!kkey) {
- log_err("out of memory: allocate null prime key");
- return NULL;
- }
- return kkey;
- }
-
- log_nametypeclass(VERB_DETAIL, "Successfully primed trust anchor",
- ta->name, LDNS_RR_TYPE_DNSKEY, ta->dclass);
- return kkey;
-}
-
-/**
- * In inform supers, with the resulting message and rcode and the current
- * keyset in the super state, validate the DS response, returning a KeyEntry.
- *
- * @param qstate: query state that is validating and asked for a DS.
- * @param vq: validator query state
- * @param id: module id.
- * @param rcode: rcode result value.
- * @param msg: result message (if rcode is OK).
- * @param qinfo: from the sub query state, query info.
- * @param ke: the key entry to return. It returns
- * is_bad if the DS response fails to validate, is_null if the
- * DS response indicated an end to secure space, is_good if the DS
- * validated. It returns ke=NULL if the DS response indicated that the
- * request wasn't a delegation point.
- * @return 0 on servfail error (malloc failure).
- */
-static int
-ds_response_to_ke(struct module_qstate* qstate, struct val_qstate* vq,
- int id, int rcode, struct dns_msg* msg, struct query_info* qinfo,
- struct key_entry_key** ke)
-{
- struct val_env* ve = (struct val_env*)qstate->env->modinfo[id];
- char* reason = NULL;
- enum val_classification subtype;
- if(rcode != LDNS_RCODE_NOERROR) {
- char rc[16];
- rc[0]=0;
- (void)sldns_wire2str_rcode_buf(rcode, rc, sizeof(rc));
- /* errors here pretty much break validation */
- verbose(VERB_DETAIL, "DS response was error, thus bogus");
- errinf(qstate, rc);
- errinf(qstate, "no DS");
- goto return_bogus;
- }
-
- subtype = val_classify_response(BIT_RD, qinfo, qinfo, msg->rep, 0);
- if(subtype == VAL_CLASS_POSITIVE) {
- struct ub_packed_rrset_key* ds;
- enum sec_status sec;
- ds = reply_find_answer_rrset(qinfo, msg->rep);
- /* If there was no DS rrset, then we have mis-classified
- * this message. */
- if(!ds) {
- log_warn("internal error: POSITIVE DS response was "
- "missing DS.");
- errinf(qstate, "no DS record");
- goto return_bogus;
- }
- /* Verify only returns BOGUS or SECURE. If the rrset is
- * bogus, then we are done. */
- sec = val_verify_rrset_entry(qstate->env, ve, ds,
- vq->key_entry, &reason);
- if(sec != sec_status_secure) {
- verbose(VERB_DETAIL, "DS rrset in DS response did "
- "not verify");
- errinf(qstate, reason);
- goto return_bogus;
- }
-
- /* If the DS rrset validates, we still have to make sure
- * that they are usable. */
- if(!val_dsset_isusable(ds)) {
- /* If they aren't usable, then we treat it like
- * there was no DS. */
- *ke = key_entry_create_null(qstate->region,
- qinfo->qname, qinfo->qname_len, qinfo->qclass,
- ub_packed_rrset_ttl(ds), *qstate->env->now);
- return (*ke) != NULL;
- }
-
- /* Otherwise, we return the positive response. */
- log_query_info(VERB_DETAIL, "validated DS", qinfo);
- *ke = key_entry_create_rrset(qstate->region,
- qinfo->qname, qinfo->qname_len, qinfo->qclass, ds,
- NULL, *qstate->env->now);
- return (*ke) != NULL;
- } else if(subtype == VAL_CLASS_NODATA ||
- subtype == VAL_CLASS_NAMEERROR) {
- /* NODATA means that the qname exists, but that there was
- * no DS. This is a pretty normal case. */
- time_t proof_ttl = 0;
- enum sec_status sec;
-
- /* make sure there are NSECs or NSEC3s with signatures */
- if(!val_has_signed_nsecs(msg->rep, &reason)) {
- verbose(VERB_ALGO, "no NSECs: %s", reason);
- errinf(qstate, reason);
- goto return_bogus;
- }
-
- /* For subtype Name Error.
- * attempt ANS 2.8.1.0 compatibility where it sets rcode
- * to nxdomain, but really this is an Nodata/Noerror response.
- * Find and prove the empty nonterminal in that case */
-
- /* Try to prove absence of the DS with NSEC */
- sec = val_nsec_prove_nodata_dsreply(
- qstate->env, ve, qinfo, msg->rep, vq->key_entry,
- &proof_ttl, &reason);
- switch(sec) {
- case sec_status_secure:
- verbose(VERB_DETAIL, "NSEC RRset for the "
- "referral proved no DS.");
- *ke = key_entry_create_null(qstate->region,
- qinfo->qname, qinfo->qname_len,
- qinfo->qclass, proof_ttl,
- *qstate->env->now);
- return (*ke) != NULL;
- case sec_status_insecure:
- verbose(VERB_DETAIL, "NSEC RRset for the "
- "referral proved not a delegation point");
- *ke = NULL;
- return 1;
- case sec_status_bogus:
- verbose(VERB_DETAIL, "NSEC RRset for the "
- "referral did not prove no DS.");
- errinf(qstate, reason);
- goto return_bogus;
- case sec_status_unchecked:
- default:
- /* NSEC proof did not work, try next */
- break;
- }
-
- sec = nsec3_prove_nods(qstate->env, ve,
- msg->rep->rrsets + msg->rep->an_numrrsets,
- msg->rep->ns_numrrsets, qinfo, vq->key_entry, &reason);
- switch(sec) {
- case sec_status_insecure:
- /* case insecure also continues to unsigned
- * space. If nsec3-iter-count too high or
- * optout, then treat below as unsigned */
- case sec_status_secure:
- verbose(VERB_DETAIL, "NSEC3s for the "
- "referral proved no DS.");
- *ke = key_entry_create_null(qstate->region,
- qinfo->qname, qinfo->qname_len,
- qinfo->qclass, proof_ttl,
- *qstate->env->now);
- return (*ke) != NULL;
- case sec_status_indeterminate:
- verbose(VERB_DETAIL, "NSEC3s for the "
- "referral proved no delegation");
- *ke = NULL;
- return 1;
- case sec_status_bogus:
- verbose(VERB_DETAIL, "NSEC3s for the "
- "referral did not prove no DS.");
- errinf(qstate, reason);
- goto return_bogus;
- case sec_status_unchecked:
- default:
- /* NSEC3 proof did not work */
- break;
- }
-
- /* Apparently, no available NSEC/NSEC3 proved NODATA, so
- * this is BOGUS. */
- verbose(VERB_DETAIL, "DS %s ran out of options, so return "
- "bogus", val_classification_to_string(subtype));
- errinf(qstate, "no DS but also no proof of that");
- goto return_bogus;
- } else if(subtype == VAL_CLASS_CNAME ||
- subtype == VAL_CLASS_CNAMENOANSWER) {
- /* if the CNAME matches the exact name we want and is signed
- * properly, then also, we are sure that no DS exists there,
- * much like a NODATA proof */
- enum sec_status sec;
- struct ub_packed_rrset_key* cname;
- cname = reply_find_rrset_section_an(msg->rep, qinfo->qname,
- qinfo->qname_len, LDNS_RR_TYPE_CNAME, qinfo->qclass);
- if(!cname) {
- errinf(qstate, "validator classified CNAME but no "
- "CNAME of the queried name for DS");
- goto return_bogus;
- }
- if(((struct packed_rrset_data*)cname->entry.data)->rrsig_count
- == 0) {
- if(msg->rep->an_numrrsets != 0 && ntohs(msg->rep->
- rrsets[0]->rk.type)==LDNS_RR_TYPE_DNAME) {
- errinf(qstate, "DS got DNAME answer");
- } else {
- errinf(qstate, "DS got unsigned CNAME answer");
- }
- goto return_bogus;
- }
- sec = val_verify_rrset_entry(qstate->env, ve, cname,
- vq->key_entry, &reason);
- if(sec == sec_status_secure) {
- verbose(VERB_ALGO, "CNAME validated, "
- "proof that DS does not exist");
- /* and that it is not a referral point */
- *ke = NULL;
- return 1;
- }
- errinf(qstate, "CNAME in DS response was not secure.");
- errinf(qstate, reason);
- goto return_bogus;
- } else {
- verbose(VERB_QUERY, "Encountered an unhandled type of "
- "DS response, thus bogus.");
- errinf(qstate, "no DS and");
- if(FLAGS_GET_RCODE(msg->rep->flags) != LDNS_RCODE_NOERROR) {
- char rc[16];
- rc[0]=0;
- (void)sldns_wire2str_rcode_buf((int)FLAGS_GET_RCODE(
- msg->rep->flags), rc, sizeof(rc));
- errinf(qstate, rc);
- } else errinf(qstate, val_classification_to_string(subtype));
- errinf(qstate, "message fails to prove that");
- goto return_bogus;
- }
-return_bogus:
- *ke = key_entry_create_bad(qstate->region, qinfo->qname,
- qinfo->qname_len, qinfo->qclass,
- BOGUS_KEY_TTL, *qstate->env->now);
- return (*ke) != NULL;
-}
-
-/**
- * Process DS response. Called from inform_supers.
- * Because it is in inform_supers, the mesh itself is busy doing callbacks
- * for a state that is to be deleted soon; don't touch the mesh; instead
- * set a state in the super, as the super will be reactivated soon.
- * Perform processing to determine what state to set in the super.
- *
- * @param qstate: query state that is validating and asked for a DS.
- * @param vq: validator query state
- * @param id: module id.
- * @param rcode: rcode result value.
- * @param msg: result message (if rcode is OK).
- * @param qinfo: from the sub query state, query info.
- * @param origin: the origin of msg.
- */
-static void
-process_ds_response(struct module_qstate* qstate, struct val_qstate* vq,
- int id, int rcode, struct dns_msg* msg, struct query_info* qinfo,
- struct sock_list* origin)
-{
- struct key_entry_key* dske = NULL;
- uint8_t* olds = vq->empty_DS_name;
- vq->empty_DS_name = NULL;
- if(!ds_response_to_ke(qstate, vq, id, rcode, msg, qinfo, &dske)) {
- log_err("malloc failure in process_ds_response");
- vq->key_entry = NULL; /* make it error */
- vq->state = VAL_VALIDATE_STATE;
- return;
- }
- if(dske == NULL) {
- vq->empty_DS_name = regional_alloc_init(qstate->region,
- qinfo->qname, qinfo->qname_len);
- if(!vq->empty_DS_name) {
- log_err("malloc failure in empty_DS_name");
- vq->key_entry = NULL; /* make it error */
- vq->state = VAL_VALIDATE_STATE;
- return;
- }
- vq->empty_DS_len = qinfo->qname_len;
- vq->chain_blacklist = NULL;
- /* ds response indicated that we aren't on a delegation point.
- * Keep the forState.state on FINDKEY. */
- } else if(key_entry_isgood(dske)) {
- vq->ds_rrset = key_entry_get_rrset(dske, qstate->region);
- if(!vq->ds_rrset) {
- log_err("malloc failure in process DS");
- vq->key_entry = NULL; /* make it error */
- vq->state = VAL_VALIDATE_STATE;
- return;
- }
- vq->chain_blacklist = NULL; /* fresh blacklist for next part*/
- /* Keep the forState.state on FINDKEY. */
- } else if(key_entry_isbad(dske)
- && vq->restart_count < VAL_MAX_RESTART_COUNT) {
- vq->empty_DS_name = olds;
- val_blacklist(&vq->chain_blacklist, qstate->region, origin, 1);
- qstate->errinf = NULL;
- vq->restart_count++;
- } else {
- if(key_entry_isbad(dske)) {
- errinf_origin(qstate, origin);
- errinf_dname(qstate, "for DS", qinfo->qname);
- }
- /* NOTE: the reason for the DS to be not good (that is,
- * either bad or null) should have been logged by
- * dsResponseToKE. */
- vq->key_entry = dske;
- /* The FINDKEY phase has ended, so move on. */
- vq->state = VAL_VALIDATE_STATE;
- }
-}
-
-/**
- * Process DNSKEY response. Called from inform_supers.
- * Sets the key entry in the state.
- * Because it is in inform_supers, the mesh itself is busy doing callbacks
- * for a state that is to be deleted soon; don't touch the mesh; instead
- * set a state in the super, as the super will be reactivated soon.
- * Perform processing to determine what state to set in the super.
- *
- * @param qstate: query state that is validating and asked for a DNSKEY.
- * @param vq: validator query state
- * @param id: module id.
- * @param rcode: rcode result value.
- * @param msg: result message (if rcode is OK).
- * @param qinfo: from the sub query state, query info.
- * @param origin: the origin of msg.
- */
-static void
-process_dnskey_response(struct module_qstate* qstate, struct val_qstate* vq,
- int id, int rcode, struct dns_msg* msg, struct query_info* qinfo,
- struct sock_list* origin)
-{
- struct val_env* ve = (struct val_env*)qstate->env->modinfo[id];
- struct key_entry_key* old = vq->key_entry;
- struct ub_packed_rrset_key* dnskey = NULL;
- int downprot;
- char* reason = NULL;
-
- if(rcode == LDNS_RCODE_NOERROR)
- dnskey = reply_find_answer_rrset(qinfo, msg->rep);
-
- if(dnskey == NULL) {
- /* bad response */
- verbose(VERB_DETAIL, "Missing DNSKEY RRset in response to "
- "DNSKEY query.");
- if(vq->restart_count < VAL_MAX_RESTART_COUNT) {
- val_blacklist(&vq->chain_blacklist, qstate->region,
- origin, 1);
- qstate->errinf = NULL;
- vq->restart_count++;
- return;
- }
- vq->key_entry = key_entry_create_bad(qstate->region,
- qinfo->qname, qinfo->qname_len, qinfo->qclass,
- BOGUS_KEY_TTL, *qstate->env->now);
- if(!vq->key_entry) {
- log_err("alloc failure in missing dnskey response");
- /* key_entry is NULL for failure in Validate */
- }
- errinf(qstate, "No DNSKEY record");
- errinf_origin(qstate, origin);
- errinf_dname(qstate, "for key", qinfo->qname);
- vq->state = VAL_VALIDATE_STATE;
- return;
- }
- if(!vq->ds_rrset) {
- log_err("internal error: no DS rrset for new DNSKEY response");
- vq->key_entry = NULL;
- vq->state = VAL_VALIDATE_STATE;
- return;
- }
- downprot = qstate->env->cfg->harden_algo_downgrade;
- vq->key_entry = val_verify_new_DNSKEYs(qstate->region, qstate->env,
- ve, dnskey, vq->ds_rrset, downprot, &reason);
-
- if(!vq->key_entry) {
- log_err("out of memory in verify new DNSKEYs");
- vq->state = VAL_VALIDATE_STATE;
- return;
- }
- /* If the key entry isBad or isNull, then we can move on to the next
- * state. */
- if(!key_entry_isgood(vq->key_entry)) {
- if(key_entry_isbad(vq->key_entry)) {
- if(vq->restart_count < VAL_MAX_RESTART_COUNT) {
- val_blacklist(&vq->chain_blacklist,
- qstate->region, origin, 1);
- qstate->errinf = NULL;
- vq->restart_count++;
- vq->key_entry = old;
- return;
- }
- verbose(VERB_DETAIL, "Did not match a DS to a DNSKEY, "
- "thus bogus.");
- errinf(qstate, reason);
- errinf_origin(qstate, origin);
- errinf_dname(qstate, "for key", qinfo->qname);
- }
- vq->chain_blacklist = NULL;
- vq->state = VAL_VALIDATE_STATE;
- return;
- }
- vq->chain_blacklist = NULL;
- qstate->errinf = NULL;
-
- /* The DNSKEY validated, so cache it as a trusted key rrset. */
- key_cache_insert(ve->kcache, vq->key_entry, qstate);
-
- /* If good, we stay in the FINDKEY state. */
- log_query_info(VERB_DETAIL, "validated DNSKEY", qinfo);
-}
-
-/**
- * Process prime response
- * Sets the key entry in the state.
- *
- * @param qstate: query state that is validating and primed a trust anchor.
- * @param vq: validator query state
- * @param id: module id.
- * @param rcode: rcode result value.
- * @param msg: result message (if rcode is OK).
- * @param origin: the origin of msg.
- */
-static void
-process_prime_response(struct module_qstate* qstate, struct val_qstate* vq,
- int id, int rcode, struct dns_msg* msg, struct sock_list* origin)
-{
- struct val_env* ve = (struct val_env*)qstate->env->modinfo[id];
- struct ub_packed_rrset_key* dnskey_rrset = NULL;
- struct trust_anchor* ta = anchor_find(qstate->env->anchors,
- vq->trust_anchor_name, vq->trust_anchor_labs,
- vq->trust_anchor_len, vq->qchase.qclass);
- if(!ta) {
- /* trust anchor revoked, restart with less anchors */
- vq->state = VAL_INIT_STATE;
- if(!vq->trust_anchor_name)
- vq->state = VAL_VALIDATE_STATE; /* break a loop */
- vq->trust_anchor_name = NULL;
- return;
- }
- /* Fetch and validate the keyEntry that corresponds to the
- * current trust anchor. */
- if(rcode == LDNS_RCODE_NOERROR) {
- dnskey_rrset = reply_find_rrset_section_an(msg->rep,
- ta->name, ta->namelen, LDNS_RR_TYPE_DNSKEY,
- ta->dclass);
- }
- if(ta->autr) {
- if(!autr_process_prime(qstate->env, ve, ta, dnskey_rrset)) {
- /* trust anchor revoked, restart with less anchors */
- vq->state = VAL_INIT_STATE;
- vq->trust_anchor_name = NULL;
- return;
- }
- }
- vq->key_entry = primeResponseToKE(dnskey_rrset, ta, qstate, id);
- lock_basic_unlock(&ta->lock);
- if(vq->key_entry) {
- if(key_entry_isbad(vq->key_entry)
- && vq->restart_count < VAL_MAX_RESTART_COUNT) {
- val_blacklist(&vq->chain_blacklist, qstate->region,
- origin, 1);
- qstate->errinf = NULL;
- vq->restart_count++;
- vq->key_entry = NULL;
- vq->state = VAL_INIT_STATE;
- return;
- }
- vq->chain_blacklist = NULL;
- errinf_origin(qstate, origin);
- errinf_dname(qstate, "for trust anchor", ta->name);
- /* store the freshly primed entry in the cache */
- key_cache_insert(ve->kcache, vq->key_entry, qstate);
- }
-
- /* If the result of the prime is a null key, skip the FINDKEY state.*/
- if(!vq->key_entry || key_entry_isnull(vq->key_entry) ||
- key_entry_isbad(vq->key_entry)) {
- vq->state = VAL_VALIDATE_STATE;
- }
- /* the qstate will be reactivated after inform_super is done */
-}
-
-/**
- * Process DLV response. Called from inform_supers.
- * Because it is in inform_supers, the mesh itself is busy doing callbacks
- * for a state that is to be deleted soon; don't touch the mesh; instead
- * set a state in the super, as the super will be reactivated soon.
- * Perform processing to determine what state to set in the super.
- *
- * @param qstate: query state that is validating and asked for a DLV.
- * @param vq: validator query state
- * @param id: module id.
- * @param rcode: rcode result value.
- * @param msg: result message (if rcode is OK).
- * @param qinfo: from the sub query state, query info.
- */
-static void
-process_dlv_response(struct module_qstate* qstate, struct val_qstate* vq,
- int id, int rcode, struct dns_msg* msg, struct query_info* qinfo)
-{
- struct val_env* ve = (struct val_env*)qstate->env->modinfo[id];
-
- verbose(VERB_ALGO, "process dlv response to super");
- if(rcode != LDNS_RCODE_NOERROR) {
- /* lookup failed, set in vq to give up */
- vq->dlv_status = dlv_error;
- verbose(VERB_ALGO, "response is error");
- return;
- }
- if(msg->rep->security != sec_status_secure) {
- vq->dlv_status = dlv_error;
- verbose(VERB_ALGO, "response is not secure, %s",
- sec_status_to_string(msg->rep->security));
- return;
- }
- /* was the lookup a success? validated DLV? */
- if(FLAGS_GET_RCODE(msg->rep->flags) == LDNS_RCODE_NOERROR &&
- msg->rep->an_numrrsets == 1 &&
- msg->rep->security == sec_status_secure &&
- ntohs(msg->rep->rrsets[0]->rk.type) == LDNS_RR_TYPE_DLV &&
- ntohs(msg->rep->rrsets[0]->rk.rrset_class) == qinfo->qclass &&
- query_dname_compare(msg->rep->rrsets[0]->rk.dname,
- vq->dlv_lookup_name) == 0) {
- /* yay! it is just like a DS */
- vq->ds_rrset = (struct ub_packed_rrset_key*)
- regional_alloc_init(qstate->region,
- msg->rep->rrsets[0], sizeof(*vq->ds_rrset));
- if(!vq->ds_rrset) {
- log_err("out of memory in process_dlv");
- return;
- }
- vq->ds_rrset->entry.key = vq->ds_rrset;
- vq->ds_rrset->rk.dname = (uint8_t*)regional_alloc_init(
- qstate->region, vq->ds_rrset->rk.dname,
- vq->ds_rrset->rk.dname_len);
- if(!vq->ds_rrset->rk.dname) {
- log_err("out of memory in process_dlv");
- vq->dlv_status = dlv_error;
- return;
- }
- vq->ds_rrset->entry.data = regional_alloc_init(qstate->region,
- vq->ds_rrset->entry.data,
- packed_rrset_sizeof(vq->ds_rrset->entry.data));
- if(!vq->ds_rrset->entry.data) {
- log_err("out of memory in process_dlv");
- vq->dlv_status = dlv_error;
- return;
- }
- packed_rrset_ptr_fixup(vq->ds_rrset->entry.data);
- /* make vq do a DNSKEY query next up */
- vq->dlv_status = dlv_success;
- return;
- }
- /* store NSECs into negative cache */
- val_neg_addreply(ve->neg_cache, msg->rep);
-
- /* was the lookup a failure?
- * if we have to go up into the DLV for a higher DLV anchor
- * then set this in the vq, so it can make queries when activated.
- * See if the NSECs indicate that we should look for higher DLV
- * or, that there is no DLV securely */
- if(!val_nsec_check_dlv(qinfo, msg->rep, &vq->dlv_lookup_name,
- &vq->dlv_lookup_name_len)) {
- vq->dlv_status = dlv_error;
- verbose(VERB_ALGO, "nsec error");
- return;
- }
- if(!dname_subdomain_c(vq->dlv_lookup_name,
- qstate->env->anchors->dlv_anchor->name)) {
- vq->dlv_status = dlv_there_is_no_dlv;
- return;
- }
- vq->dlv_status = dlv_ask_higher;
-}
-
-/*
- * inform validator super.
- *
- * @param qstate: query state that finished.
- * @param id: module id.
- * @param super: the qstate to inform.
- */
-void
-val_inform_super(struct module_qstate* qstate, int id,
- struct module_qstate* super)
-{
- struct val_qstate* vq = (struct val_qstate*)super->minfo[id];
- log_query_info(VERB_ALGO, "validator: inform_super, sub is",
- &qstate->qinfo);
- log_query_info(VERB_ALGO, "super is", &super->qinfo);
- if(!vq) {
- verbose(VERB_ALGO, "super: has no validator state");
- return;
- }
- if(vq->wait_prime_ta) {
- vq->wait_prime_ta = 0;
- process_prime_response(super, vq, id, qstate->return_rcode,
- qstate->return_msg, qstate->reply_origin);
- return;
- }
- if(qstate->qinfo.qtype == LDNS_RR_TYPE_DS) {
- process_ds_response(super, vq, id, qstate->return_rcode,
- qstate->return_msg, &qstate->qinfo,
- qstate->reply_origin);
- return;
- } else if(qstate->qinfo.qtype == LDNS_RR_TYPE_DNSKEY) {
- process_dnskey_response(super, vq, id, qstate->return_rcode,
- qstate->return_msg, &qstate->qinfo,
- qstate->reply_origin);
- return;
- } else if(qstate->qinfo.qtype == LDNS_RR_TYPE_DLV) {
- process_dlv_response(super, vq, id, qstate->return_rcode,
- qstate->return_msg, &qstate->qinfo);
- return;
- }
- log_err("internal error in validator: no inform_supers possible");
-}
-
-void
-val_clear(struct module_qstate* qstate, int id)
-{
- if(!qstate)
- return;
- /* everything is allocated in the region, so assign NULL */
- qstate->minfo[id] = NULL;
-}
-
-size_t
-val_get_mem(struct module_env* env, int id)
-{
- struct val_env* ve = (struct val_env*)env->modinfo[id];
- if(!ve)
- return 0;
- return sizeof(*ve) + key_cache_get_mem(ve->kcache) +
- val_neg_get_mem(ve->neg_cache) +
- sizeof(size_t)*2*ve->nsec3_keyiter_count;
-}
-
-/**
- * The validator function block
- */
-static struct module_func_block val_block = {
- "validator",
- &val_init, &val_deinit, &val_operate, &val_inform_super, &val_clear,
- &val_get_mem
-};
-
-struct module_func_block*
-val_get_funcblock(void)
-{
- return &val_block;
-}
-
-const char*
-val_state_to_string(enum val_state state)
-{
- switch(state) {
- case VAL_INIT_STATE: return "VAL_INIT_STATE";
- case VAL_FINDKEY_STATE: return "VAL_FINDKEY_STATE";
- case VAL_VALIDATE_STATE: return "VAL_VALIDATE_STATE";
- case VAL_FINISHED_STATE: return "VAL_FINISHED_STATE";
- case VAL_DLVLOOKUP_STATE: return "VAL_DLVLOOKUP_STATE";
- }
- return "UNKNOWN VALIDATOR STATE";
-}
-
diff --git a/external/unbound/validator/validator.h b/external/unbound/validator/validator.h
deleted file mode 100644
index 23d307242..000000000
--- a/external/unbound/validator/validator.h
+++ /dev/null
@@ -1,294 +0,0 @@
-/*
- * validator/validator.h - secure validator DNS query response module
- *
- * Copyright (c) 2007, NLnet Labs. All rights reserved.
- *
- * This software is open source.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- *
- * Redistributions of source code must retain the above copyright notice,
- * this list of conditions and the following disclaimer.
- *
- * Redistributions in binary form must reproduce the above copyright notice,
- * this list of conditions and the following disclaimer in the documentation
- * and/or other materials provided with the distribution.
- *
- * Neither the name of the NLNET LABS nor the names of its contributors may
- * be used to endorse or promote products derived from this software without
- * specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
- * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
- * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
- * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
- * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
- * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-/**
- * \file
- *
- * This file contains a module that performs validation of DNS queries.
- * According to RFC 4034.
- */
-
-#ifndef VALIDATOR_VALIDATOR_H
-#define VALIDATOR_VALIDATOR_H
-#include "util/module.h"
-#include "util/data/msgreply.h"
-#include "validator/val_utils.h"
-struct val_anchors;
-struct key_cache;
-struct key_entry_key;
-struct val_neg_cache;
-struct config_strlist;
-
-/**
- * This is the TTL to use when a trust anchor fails to prime. A trust anchor
- * will be primed no more often than this interval. Used when harden-
- * dnssec-stripped is off and the trust anchor fails.
- */
-#define NULL_KEY_TTL 60 /* seconds */
-
-/**
- * TTL for bogus key entries. When a DS or DNSKEY fails in the chain of
- * trust the entire zone for that name is blacked out for this TTL.
- */
-#define BOGUS_KEY_TTL 60 /* seconds */
-
-/** max number of query restarts, number of IPs to probe */
-#define VAL_MAX_RESTART_COUNT 5
-
-/**
- * Global state for the validator.
- */
-struct val_env {
- /** key cache; these are validated keys. trusted keys only
- * end up here after being primed. */
- struct key_cache* kcache;
-
- /** aggressive negative cache. index into NSECs in rrset cache. */
- struct val_neg_cache* neg_cache;
-
- /** for debug testing a fixed validation date can be entered.
- * if 0, current time is used for rrsig validation */
- int32_t date_override;
-
- /** clock skew min for signatures */
- int32_t skew_min;
-
- /** clock skew max for signatures */
- int32_t skew_max;
-
- /** TTL for bogus data; used instead of untrusted TTL from data.
- * Bogus data will not be verified more often than this interval.
- * seconds. */
- uint32_t bogus_ttl;
-
- /** If set, the validator should clean the additional section of
- * secure messages.
- */
- int clean_additional;
-
- /**
- * If set, the validator will not make messages bogus, instead
- * indeterminate is issued, so that no clients receive SERVFAIL.
- * This allows an operator to run validation 'shadow' without
- * hurting responses to clients.
- */
- int permissive_mode;
-
- /**
- * Number of entries in the NSEC3 maximum iteration count table.
- * Keep this table short, and sorted by size
- */
- int nsec3_keyiter_count;
-
- /**
- * NSEC3 maximum iteration count per signing key size.
- * This array contains key size values (in increasing order)
- */
- size_t* nsec3_keysize;
-
- /**
- * NSEC3 maximum iteration count per signing key size.
- * This array contains the maximum iteration count for the keysize
- * in the keysize array.
- */
- size_t* nsec3_maxiter;
-
- /** lock on bogus counter */
- lock_basic_type bogus_lock;
- /** number of times rrsets marked bogus */
- size_t num_rrset_bogus;
-};
-
-/**
- * State of the validator for a query.
- */
-enum val_state {
- /** initial state for validation */
- VAL_INIT_STATE = 0,
- /** find the proper keys for validation, follow trust chain */
- VAL_FINDKEY_STATE,
- /** validate the answer, using found key entry */
- VAL_VALIDATE_STATE,
- /** finish up */
- VAL_FINISHED_STATE,
- /** DLV lookup state, processing DLV queries */
- VAL_DLVLOOKUP_STATE
-};
-
-/**
- * Per query state for the validator module.
- */
-struct val_qstate {
- /**
- * State of the validator module.
- */
- enum val_state state;
-
- /**
- * The original message we have been given to validate.
- */
- struct dns_msg* orig_msg;
-
- /**
- * The query restart count
- */
- int restart_count;
- /** The blacklist saved for chainoftrust elements */
- struct sock_list* chain_blacklist;
-
- /**
- * The query name we have chased to; qname after following CNAMEs
- */
- struct query_info qchase;
-
- /**
- * The chased reply, extract from original message. Can be:
- * o CNAME
- * o DNAME + CNAME
- * o answer
- * plus authority, additional (nsecs) that have same signature.
- */
- struct reply_info* chase_reply;
-
- /**
- * The cname skip value; the number of rrsets that have been skipped
- * due to chasing cnames. This is the offset into the
- * orig_msg->rep->rrsets array, into the answer section.
- * starts at 0 - for the full original message.
- * if it is >0 - qchase followed the cname, chase_reply setup to be
- * that message and relevant authority rrsets.
- *
- * The skip is also used for referral messages, where it will
- * range from 0, over the answer, authority and additional sections.
- */
- size_t rrset_skip;
-
- /** trust anchor name */
- uint8_t* trust_anchor_name;
- /** trust anchor labels */
- int trust_anchor_labs;
- /** trust anchor length */
- size_t trust_anchor_len;
-
- /** the DS rrset */
- struct ub_packed_rrset_key* ds_rrset;
-
- /** domain name for empty nonterminal detection */
- uint8_t* empty_DS_name;
- /** length of empty_DS_name */
- size_t empty_DS_len;
-
- /** the current key entry */
- struct key_entry_key* key_entry;
-
- /** subtype */
- enum val_classification subtype;
-
- /** signer name */
- uint8_t* signer_name;
- /** length of signer_name */
- size_t signer_len;
-
- /** true if this state is waiting to prime a trust anchor */
- int wait_prime_ta;
-
- /** have we already checked the DLV? */
- int dlv_checked;
- /** The name for which the DLV is looked up. For the current message
- * or for the current RRset (for CNAME, REFERRAL types).
- * If there is signer name, that may be it, else a domain name */
- uint8_t* dlv_lookup_name;
- /** length of dlv lookup name */
- size_t dlv_lookup_name_len;
- /** Name at which chain of trust stopped with insecure, starting DLV
- * DLV must result in chain going further down */
- uint8_t* dlv_insecure_at;
- /** length of dlv insecure point name */
- size_t dlv_insecure_at_len;
- /** status of DLV lookup. Indication to VAL_DLV_STATE what to do */
- enum dlv_status {
- dlv_error, /* server failure */
- dlv_success, /* got a DLV */
- dlv_ask_higher, /* ask again */
- dlv_there_is_no_dlv /* got no DLV, sure of it */
- } dlv_status;
-};
-
-/**
- * Get the validator function block.
- * @return: function block with function pointers to validator methods.
- */
-struct module_func_block* val_get_funcblock(void);
-
-/**
- * Get validator state as a string
- * @param state: to convert
- * @return constant string that is printable.
- */
-const char* val_state_to_string(enum val_state state);
-
-/** validator init */
-int val_init(struct module_env* env, int id);
-
-/** validator deinit */
-void val_deinit(struct module_env* env, int id);
-
-/** validator operate on a query */
-void val_operate(struct module_qstate* qstate, enum module_ev event, int id,
- struct outbound_entry* outbound);
-
-/**
- * inform validator super.
- *
- * @param qstate: query state that finished.
- * @param id: module id.
- * @param super: the qstate to inform.
- */
-void val_inform_super(struct module_qstate* qstate, int id,
- struct module_qstate* super);
-
-/** validator cleanup query state */
-void val_clear(struct module_qstate* qstate, int id);
-
-/**
- * Debug helper routine that assists worker in determining memory in
- * use.
- * @param env: module environment
- * @param id: module id.
- * @return memory in use in bytes.
- */
-size_t val_get_mem(struct module_env* env, int id);
-
-#endif /* VALIDATOR_VALIDATOR_H */