added unbound to external deps
This commit is contained in:
2393
external/unbound/validator/autotrust.c
vendored
Normal file
2393
external/unbound/validator/autotrust.c
vendored
Normal file
File diff suppressed because it is too large
Load Diff
208
external/unbound/validator/autotrust.h
vendored
Normal file
208
external/unbound/validator/autotrust.h
vendored
Normal file
@@ -0,0 +1,208 @@
|
||||
/*
|
||||
* 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_t;
|
||||
|
||||
/**
|
||||
* 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_t 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_t 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_t 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 */
|
||||
1256
external/unbound/validator/val_anchor.c
vendored
Normal file
1256
external/unbound/validator/val_anchor.c
vendored
Normal file
File diff suppressed because it is too large
Load Diff
219
external/unbound/validator/val_anchor.h
vendored
Normal file
219
external/unbound/validator/val_anchor.h
vendored
Normal file
@@ -0,0 +1,219 @@
|
||||
/*
|
||||
* 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_t 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_t* 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_t node;
|
||||
/** lock on the entire anchor and its keys; for autotrust changes */
|
||||
lock_basic_t 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);
|
||||
|
||||
#endif /* VALIDATOR_VAL_ANCHOR_H */
|
||||
172
external/unbound/validator/val_kcache.c
vendored
Normal file
172
external/unbound/validator/val_kcache.c
vendored
Normal file
@@ -0,0 +1,172 @@
|
||||
/*
|
||||
* 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);
|
||||
}
|
||||
118
external/unbound/validator/val_kcache.h
vendored
Normal file
118
external/unbound/validator/val_kcache.h
vendored
Normal file
@@ -0,0 +1,118 @@
|
||||
/*
|
||||
* 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 */
|
||||
413
external/unbound/validator/val_kentry.c
vendored
Normal file
413
external/unbound/validator/val_kentry.c
vendored
Normal file
@@ -0,0 +1,413 @@
|
||||
/*
|
||||
* 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 "ldns/rrdef.h"
|
||||
#include "ldns/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;
|
||||
}
|
||||
220
external/unbound/validator/val_kentry.h
vendored
Normal file
220
external/unbound/validator/val_kentry.h
vendored
Normal file
@@ -0,0 +1,220 @@
|
||||
/*
|
||||
* 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 */
|
||||
1460
external/unbound/validator/val_neg.c
vendored
Normal file
1460
external/unbound/validator/val_neg.c
vendored
Normal file
File diff suppressed because it is too large
Load Diff
315
external/unbound/validator/val_neg.h
vendored
Normal file
315
external/unbound/validator/val_neg.h
vendored
Normal file
@@ -0,0 +1,315 @@
|
||||
/*
|
||||
* 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 existance, 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_t lock;
|
||||
/** The zone rbtree. contents sorted canonical, type val_neg_zone */
|
||||
rbtree_t 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_t 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_t 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_t 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 */
|
||||
602
external/unbound/validator/val_nsec.c
vendored
Normal file
602
external/unbound/validator/val_nsec.c
vendored
Normal file
@@ -0,0 +1,602 @@
|
||||
/*
|
||||
* validator/val_nsec.c - validator NSEC denial of existance 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 existance, 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 conlusively 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;
|
||||
}
|
||||
}
|
||||
|
||||
/* 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;
|
||||
}
|
||||
182
external/unbound/validator/val_nsec.h
vendored
Normal file
182
external/unbound/validator/val_nsec.h
vendored
Normal file
@@ -0,0 +1,182 @@
|
||||
/*
|
||||
* validator/val_nsec.h - validator NSEC denial of existance 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 existance, 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 sucessfully 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 */
|
||||
1488
external/unbound/validator/val_nsec3.c
vendored
Normal file
1488
external/unbound/validator/val_nsec3.c
vendored
Normal file
File diff suppressed because it is too large
Load Diff
380
external/unbound/validator/val_nsec3.h
vendored
Normal file
380
external/unbound/validator/val_nsec3.h
vendored
Normal file
@@ -0,0 +1,380 @@
|
||||
/*
|
||||
* validator/val_nsec3.h - validator NSEC3 denial of existance 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 existance, 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_t 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 inited 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_t* 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 */
|
||||
1072
external/unbound/validator/val_secalgo.c
vendored
Normal file
1072
external/unbound/validator/val_secalgo.c
vendored
Normal file
File diff suppressed because it is too large
Load Diff
84
external/unbound/validator/val_secalgo.h
vendored
Normal file
84
external/unbound/validator/val_secalgo.h
vendored
Normal file
@@ -0,0 +1,84 @@
|
||||
/*
|
||||
* 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 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 */
|
||||
1437
external/unbound/validator/val_sigcrypt.c
vendored
Normal file
1437
external/unbound/validator/val_sigcrypt.c
vendored
Normal file
File diff suppressed because it is too large
Load Diff
323
external/unbound/validator/val_sigcrypt.h
vendored
Normal file
323
external/unbound/validator/val_sigcrypt.h
vendored
Normal file
@@ -0,0 +1,323 @@
|
||||
/*
|
||||
* 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_t;
|
||||
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_t** 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_t** 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 */
|
||||
1083
external/unbound/validator/val_utils.c
vendored
Normal file
1083
external/unbound/validator/val_utils.c
vendored
Normal file
File diff suppressed because it is too large
Load Diff
403
external/unbound/validator/val_utils.h
vendored
Normal file
403
external/unbound/validator/val_utils.h
vendored
Normal file
@@ -0,0 +1,403 @@
|
||||
/*
|
||||
* 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 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 occurence 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 */
|
||||
2985
external/unbound/validator/validator.c
vendored
Normal file
2985
external/unbound/validator/validator.c
vendored
Normal file
File diff suppressed because it is too large
Load Diff
294
external/unbound/validator/validator.h
vendored
Normal file
294
external/unbound/validator/validator.h
vendored
Normal file
@@ -0,0 +1,294 @@
|
||||
/*
|
||||
* 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_t 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 */
|
||||
Reference in New Issue
Block a user