19 January 2018: Wouter
- tag 1.6.8 for release with CVE fix.
- trunk has 1.6.9 with fix and previous commits.
+ - patch for CVE-2017-15105: vulnerability in the processing of
+ wildcard synthesized NSEC records.
4 January 2018: Ralph
- Copy query and correctly set flags on REFUSED answers when cache
ntohs(rrset->rk.rrset_class));
}
setup_sigalg(dnskey, sigalg); /* check all algorithms in the dnskey */
- sec = dnskeyset_verify_rrset(env, ve, rrset, dnskey, sigalg, &reason);
+ /* ok to give null as qstate here, won't be used for answer section. */
+ sec = dnskeyset_verify_rrset(env, ve, rrset, dnskey, sigalg, &reason,
+ LDNS_SECTION_ANSWER, NULL);
if(vsig) {
printf("verify outcome is: %s %s\n", sec_status_to_string(sec),
reason?reason:"");
* @param ve: validator environment (with options) for verification.
* @param tp: trust point to verify with
* @param rrset: DNSKEY rrset to verify.
+ * @param qstate: qstate with region.
* @return false on failure, true if verification successful.
*/
static int
verify_dnskey(struct module_env* env, struct val_env* ve,
- struct trust_anchor* tp, struct ub_packed_rrset_key* rrset)
+ struct trust_anchor* tp, struct ub_packed_rrset_key* rrset,
+ struct module_qstate* qstate)
{
char* reason = NULL;
uint8_t sigalg[ALGO_NEEDS_MAX+1];
int downprot = env->cfg->harden_algo_downgrade;
enum sec_status sec = val_verify_DNSKEY_with_TA(env, ve, rrset,
- tp->ds_rrset, tp->dnskey_rrset, downprot?sigalg:NULL, &reason);
+ tp->ds_rrset, tp->dnskey_rrset, downprot?sigalg:NULL, &reason,
+ qstate);
/* sigalg is ignored, it returns algorithms signalled to exist, but
* in 5011 there are no other rrsets to check. if downprot is
* enabled, then it checks that the DNSKEY is signed with all
/** Is rr self-signed revoked key */
static int
rr_is_selfsigned_revoked(struct module_env* env, struct val_env* ve,
- struct ub_packed_rrset_key* dnskey_rrset, size_t i)
+ struct ub_packed_rrset_key* dnskey_rrset, size_t i,
+ struct module_qstate* qstate)
{
enum sec_status sec;
char* reason = NULL;
/* no algorithm downgrade protection necessary, if it is selfsigned
* revoked it can be removed. */
sec = dnskey_verify_rrset(env, ve, dnskey_rrset, dnskey_rrset, i,
- &reason);
+ &reason, LDNS_SECTION_ANSWER, qstate);
return (sec == sec_status_secure);
}
static void
check_contains_revoked(struct module_env* env, struct val_env* ve,
struct trust_anchor* tp, struct ub_packed_rrset_key* dnskey_rrset,
- int* changed)
+ int* changed, struct module_qstate* qstate)
{
struct packed_rrset_data* dd = (struct packed_rrset_data*)
dnskey_rrset->entry.data;
}
if(!ta)
continue; /* key not found */
- if(rr_is_selfsigned_revoked(env, ve, dnskey_rrset, i)) {
+ if(rr_is_selfsigned_revoked(env, ve, dnskey_rrset, i, qstate)) {
/* checked if there is an rrsig signed by this key. */
/* same keytag, but stored can be revoked already, so
* compare keytags, with +0 or +128(REVOKE flag) */
}
int autr_process_prime(struct module_env* env, struct val_env* ve,
- struct trust_anchor* tp, struct ub_packed_rrset_key* dnskey_rrset)
+ struct trust_anchor* tp, struct ub_packed_rrset_key* dnskey_rrset,
+ struct module_qstate* qstate)
{
int changed = 0;
log_assert(tp && tp->autr);
return 1; /* trust point exists */
}
/* check for revoked keys to remove immediately */
- check_contains_revoked(env, ve, tp, dnskey_rrset, &changed);
+ check_contains_revoked(env, ve, tp, dnskey_rrset, &changed, qstate);
if(changed) {
verbose(VERB_ALGO, "autotrust: revokedkeys, reassemble");
if(!autr_assemble(tp)) {
}
}
/* verify the dnskey rrset and see if it is valid. */
- if(!verify_dnskey(env, ve, tp, dnskey_rrset)) {
+ if(!verify_dnskey(env, ve, tp, dnskey_rrset, qstate)) {
verbose(VERB_ALGO, "autotrust: dnskey did not verify.");
/* only increase failure count if this is not the first prime,
* this means there was a previous successful probe */
struct trust_anchor;
struct ub_packed_rrset_key;
struct module_env;
+struct module_qstate;
struct val_env;
struct sldns_buffer;
* @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.
+ * @param qstate: qstate with region.
* @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);
+ struct trust_anchor* tp, struct ub_packed_rrset_key* dnskey_rrset,
+ struct module_qstate* qstate);
/**
* Debug printout of rfc5011 tracked anchors
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)
+ char** reason, struct module_qstate* qstate)
{
struct packed_rrset_data* d = (struct packed_rrset_data*)
nsec->entry.data;
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);
+ d->security = val_verify_rrset_entry(env, ve, nsec, kkey, reason,
+ LDNS_SECTION_AUTHORITY, qstate);
if(d->security == sec_status_secure) {
rrset_update_sec_status(env->rrset_cache, nsec, *env->now);
return 1;
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 key_entry_key* kkey, time_t* proof_ttl, char** reason,
+ struct module_qstate* qstate)
{
struct ub_packed_rrset_key* nsec = reply_find_rrset_section_ns(
rep, qinfo->qname, qinfo->qname_len, LDNS_RR_TYPE_NSEC,
* 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)) {
+ if(!nsec_verify_rrset(env, ve, nsec, kkey, reason, qstate)) {
verbose(VERB_ALGO, "NSEC RRset for the "
"referral did not verify.");
return sec_status_bogus;
i++) {
if(rep->rrsets[i]->rk.type != htons(LDNS_RR_TYPE_NSEC))
continue;
- if(!nsec_verify_rrset(env, ve, rep->rrsets[i], kkey, reason)) {
+ if(!nsec_verify_rrset(env, ve, rep->rrsets[i], kkey, reason,
+ qstate)) {
verbose(VERB_ALGO, "NSEC for empty non-terminal "
"did not verify.");
return sec_status_bogus;
#include "util/data/packed_rrset.h"
struct val_env;
struct module_env;
+struct module_qstate;
struct ub_packed_rrset_key;
struct reply_info;
struct query_info;
* @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.
+ * @param qstate: qstate with region.
* @return security status.
* SECURE: proved absence of DS.
* INSECURE: proved that this was not a delegation point.
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);
+ time_t* proof_ttl, char** reason, struct module_qstate* qstate);
/**
* nsec typemap check, takes an NSEC-type bitmap as argument, checks for type.
static int
list_is_secure(struct module_env* env, struct val_env* ve,
struct ub_packed_rrset_key** list, size_t num,
- struct key_entry_key* kkey, char** reason)
+ struct key_entry_key* kkey, char** reason, struct module_qstate* qstate)
{
struct packed_rrset_data* d;
size_t i;
if(d->security == sec_status_secure)
continue;
d->security = val_verify_rrset_entry(env, ve, list[i], kkey,
- reason);
+ reason, LDNS_SECTION_AUTHORITY, qstate);
if(d->security != sec_status_secure) {
verbose(VERB_ALGO, "NSEC3 did not verify");
return 0;
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)
+ struct query_info* qinfo, struct key_entry_key* kkey, char** reason,
+ struct module_qstate* qstate)
{
rbtree_type ct;
struct nsec3_filter flt;
*reason = "no valid NSEC3s";
return sec_status_bogus; /* no valid NSEC3s, bogus */
}
- if(!list_is_secure(env, ve, list, num, kkey, reason))
+ if(!list_is_secure(env, ve, list, num, kkey, reason, qstate))
return sec_status_bogus; /* not all NSEC3 records secure */
rbtree_init(&ct, &nsec3_hash_cmp); /* init names-to-hash cache */
filter_init(&flt, list, num, qinfo); /* init RR iterator */
struct val_env;
struct regional;
struct module_env;
+struct module_qstate;
struct ub_packed_rrset_key;
struct reply_info;
struct query_info;
* @param qinfo: query that is verified for.
* @param kkey: key entry that signed the NSEC3s.
* @param reason: string for bogus result.
+ * @param qstate: qstate with region.
* @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_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);
+ struct query_info* qinfo, struct key_entry_key* kkey, char** reason,
+ struct module_qstate* qstate);
/**
* Prove NXDOMAIN or NODATA.
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)
+ uint8_t* sigalg, char** reason, sldns_pkt_section section,
+ struct module_qstate* qstate)
{
enum sec_status sec;
size_t i, num;
}
for(i=0; i<num; i++) {
sec = dnskeyset_verify_rrset_sig(env, ve, *env->now, rrset,
- dnskey, i, &sortree, reason);
+ dnskey, i, &sortree, reason, section, qstate);
/* see which algorithm has been fixed up */
if(sec == sec_status_secure) {
if(!sigalg)
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)
+ size_t dnskey_idx, char** reason, sldns_pkt_section section,
+ struct module_qstate* qstate)
{
enum sec_status sec;
size_t i, num, numchecked = 0;
buf_canon = 0;
sec = dnskey_verify_rrset_sig(env->scratch,
env->scratch_buffer, ve, *env->now, rrset,
- dnskey, dnskey_idx, i, &sortree, &buf_canon, reason);
+ dnskey, dnskey_idx, i, &sortree, &buf_canon, reason,
+ section, qstate);
if(sec == sec_status_secure)
return sec;
numchecked ++;
dnskeyset_verify_rrset_sig(struct module_env* env, struct val_env* ve,
time_t now, struct ub_packed_rrset_key* rrset,
struct ub_packed_rrset_key* dnskey, size_t sig_idx,
- struct rbtree_type** sortree, char** reason)
+ struct rbtree_type** sortree, char** reason, sldns_pkt_section section,
+ struct module_qstate* qstate)
{
/* find matching keys and check them */
enum sec_status sec = sec_status_bogus;
/* see if key verifies */
sec = dnskey_verify_rrset_sig(env->scratch,
env->scratch_buffer, ve, now, rrset, dnskey, i,
- sig_idx, sortree, &buf_canon, reason);
+ sig_idx, sortree, &buf_canon, reason, section, qstate);
if(sec == sec_status_secure)
return sec;
}
* signer name length.
* @param sortree: if NULL is passed a new sorted rrset tree is built.
* Otherwise it is reused.
+ * @param section: section of packet where this rrset comes from.
+ * @param qstate: qstate with region.
* @return false on alloc error.
*/
static int
rrset_canonical(struct regional* region, sldns_buffer* buf,
struct ub_packed_rrset_key* k, uint8_t* sig, size_t siglen,
- struct rbtree_type** sortree)
+ struct rbtree_type** sortree, sldns_pkt_section section,
+ struct module_qstate* qstate)
{
struct packed_rrset_data* d = (struct packed_rrset_data*)k->entry.data;
uint8_t* can_owner = NULL;
canonicalize_rdata(buf, k, d->rr_len[walk->rr_idx]);
}
sldns_buffer_flip(buf);
+
+ /* Replace RR owner with canonical owner for NSEC records in authority
+ * section, to prevent that a wildcard synthesized NSEC can be used in
+ * the non-existence proves. */
+ if(ntohs(k->rk.type) == LDNS_RR_TYPE_NSEC &&
+ section == LDNS_SECTION_AUTHORITY) {
+ k->rk.dname = regional_alloc_init(qstate->region, can_owner,
+ can_owner_len);
+ if(!k->rk.dname)
+ return 0;
+ k->rk.dname_len = can_owner_len;
+ }
+
+
return 1;
}
struct val_env* ve, time_t now,
struct ub_packed_rrset_key* rrset, struct ub_packed_rrset_key* dnskey,
size_t dnskey_idx, size_t sig_idx,
- struct rbtree_type** sortree, int* buf_canon, char** reason)
+ struct rbtree_type** sortree, int* buf_canon, char** reason,
+ sldns_pkt_section section, struct module_qstate* qstate)
{
enum sec_status sec;
uint8_t* sig; /* RRSIG rdata */
/* create rrset canonical format in buffer, ready for
* signature */
if(!rrset_canonical(region, buf, rrset, sig+2,
- 18 + signer_len, sortree)) {
+ 18 + signer_len, sortree, section, qstate)) {
log_err("verify: failed due to alloc error");
return sec_status_unchecked;
}
#ifndef VALIDATOR_VAL_SIGCRYPT_H
#define VALIDATOR_VAL_SIGCRYPT_H
#include "util/data/packed_rrset.h"
+#include "sldns/pkthdr.h"
struct val_env;
struct module_env;
+struct module_qstate;
struct ub_packed_rrset_key;
struct rbtree_type;
struct regional;
* @param sigalg: if nonNULL provide downgrade protection otherwise one
* algorithm is enough.
* @param reason: if bogus, a string returned, fixed or alloced in scratch.
+ * @param section: section of packet where this rrset comes from.
+ * @param qstate: qstate with region.
* @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);
+ struct ub_packed_rrset_key* dnskey, uint8_t* sigalg, char** reason,
+ sldns_pkt_section section, struct module_qstate* qstate);
/**
* verify rrset against one specific dnskey (from rrset)
* @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.
+ * @param section: section of packet where this rrset comes from.
+ * @param qstate: qstate with region.
* @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);
+ struct ub_packed_rrset_key* dnskey, size_t dnskey_idx, char** reason,
+ sldns_pkt_section section, struct module_qstate* qstate);
/**
* verify rrset, with dnskey rrset, for a specific rrsig in rrset
* @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.
+ * @param section: section of packet where this rrset comes from.
+ * @param qstate: qstate with region.
* @return secure if any key signs *this* signature. bogus if no key signs it,
* or unchecked on error.
*/
enum sec_status dnskeyset_verify_rrset_sig(struct module_env* env,
struct val_env* ve, time_t now, struct ub_packed_rrset_key* rrset,
struct ub_packed_rrset_key* dnskey, size_t sig_idx,
- struct rbtree_type** sortree, char** reason);
+ struct rbtree_type** sortree, char** reason, sldns_pkt_section section,
+ struct module_qstate* qstate);
/**
* verify rrset, with specific dnskey(from set), for a specific rrsig
* 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.
+ * @param section: section of packet where this rrset comes from.
+ * @param qstate: qstate with region.
* @return secure if this key signs this signature. unchecked on error or
* bogus if it did not validate.
*/
struct sldns_buffer* buf, struct val_env* ve, time_t now,
struct ub_packed_rrset_key* rrset, struct ub_packed_rrset_key* dnskey,
size_t dnskey_idx, size_t sig_idx,
- struct rbtree_type** sortree, int* buf_canon, char** reason);
+ struct rbtree_type** sortree, int* buf_canon, char** reason,
+ sldns_pkt_section section, struct module_qstate* qstate);
/**
* canonical compare for two tree entries
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)
+ uint8_t* sigalg, char** reason, sldns_pkt_section section,
+ struct module_qstate* qstate)
{
enum sec_status sec;
struct packed_rrset_data* d = (struct packed_rrset_data*)rrset->
}
log_nametypeclass(VERB_ALGO, "verify rrset", rrset->rk.dname,
ntohs(rrset->rk.type), ntohs(rrset->rk.rrset_class));
- sec = dnskeyset_verify_rrset(env, ve, rrset, keys, sigalg, reason);
+ sec = dnskeyset_verify_rrset(env, ve, rrset, keys, sigalg, reason,
+ section, qstate);
verbose(VERB_ALGO, "verify result: %s", sec_status_to_string(sec));
regional_free_all(env->scratch);
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)
+ char** reason, sldns_pkt_section section, struct module_qstate* qstate)
{
/* temporary dnskey rrset-key */
struct ub_packed_rrset_key dnskey;
dnskey.rk.dname_len = kkey->namelen;
dnskey.entry.key = &dnskey;
dnskey.entry.data = kd->rrset_data;
- sec = val_verify_rrset(env, ve, rrset, &dnskey, kd->algo, reason);
+ sec = val_verify_rrset(env, ve, rrset, &dnskey, kd->algo, reason,
+ section, qstate);
return sec;
}
static enum sec_status
verify_dnskeys_with_ds_rr(struct module_env* env, struct val_env* ve,
struct ub_packed_rrset_key* dnskey_rrset,
- struct ub_packed_rrset_key* ds_rrset, size_t ds_idx, char** reason)
+ struct ub_packed_rrset_key* ds_rrset, size_t ds_idx, char** reason,
+ struct module_qstate* qstate)
{
enum sec_status sec = sec_status_bogus;
size_t i, num, numchecked = 0, numhashok = 0;
/* Otherwise, we have a match! Make sure that the DNSKEY
* verifies *with this key* */
sec = dnskey_verify_rrset(env, ve, dnskey_rrset,
- dnskey_rrset, i, reason);
+ dnskey_rrset, i, reason, LDNS_SECTION_ANSWER, qstate);
if(sec == sec_status_secure) {
return sec;
}
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)
+ struct ub_packed_rrset_key* ds_rrset, uint8_t* sigalg, char** reason,
+ struct module_qstate* qstate)
{
/* as long as this is false, we can consider this DS rrset to be
* equivalent to no DS rrset. */
has_useful_ds = 1;
sec = verify_dnskeys_with_ds_rr(env, ve, dnskey_rrset,
- ds_rrset, i, reason);
+ ds_rrset, i, reason, qstate);
if(sec == sec_status_secure) {
if(!sigalg || algo_needs_set_secure(&needs,
(uint8_t)ds_get_key_algo(ds_rrset, i))) {
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)
+ struct ub_packed_rrset_key* ds_rrset, int downprot, char** reason,
+ struct module_qstate* qstate)
{
uint8_t sigalg[ALGO_NEEDS_MAX+1];
enum sec_status sec = val_verify_DNSKEY_with_DS(env, ve,
- dnskey_rrset, ds_rrset, downprot?sigalg:NULL, reason);
+ dnskey_rrset, ds_rrset, downprot?sigalg:NULL, reason, qstate);
if(sec == sec_status_secure) {
return key_entry_create_rrset(region,
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)
+ struct ub_packed_rrset_key* ta_dnskey, uint8_t* sigalg, char** reason,
+ struct module_qstate* qstate)
{
/* as long as this is false, we can consider this anchor to be
* equivalent to no anchor. */
has_useful_ta = 1;
sec = verify_dnskeys_with_ds_rr(env, ve, dnskey_rrset,
- ta_ds, i, reason);
+ ta_ds, i, reason, qstate);
if(sec == sec_status_secure) {
if(!sigalg || algo_needs_set_secure(&needs,
(uint8_t)ds_get_key_algo(ta_ds, i))) {
has_useful_ta = 1;
sec = dnskey_verify_rrset(env, ve, dnskey_rrset,
- ta_dnskey, i, reason);
+ ta_dnskey, i, reason, LDNS_SECTION_ANSWER, qstate);
if(sec == sec_status_secure) {
if(!sigalg || algo_needs_set_secure(&needs,
(uint8_t)dnskey_get_algo(ta_dnskey, i))) {
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)
+ char** reason, struct module_qstate* qstate)
{
uint8_t sigalg[ALGO_NEEDS_MAX+1];
enum sec_status sec = val_verify_DNSKEY_with_TA(env, ve,
dnskey_rrset, ta_ds_rrset, ta_dnskey_rrset,
- downprot?sigalg:NULL, reason);
+ downprot?sigalg:NULL, reason, qstate);
if(sec == sec_status_secure) {
return key_entry_create_rrset(region,
#ifndef VALIDATOR_VAL_UTILS_H
#define VALIDATOR_VAL_UTILS_H
#include "util/data/packed_rrset.h"
+#include "sldns/pkthdr.h"
struct query_info;
struct reply_info;
struct val_env;
struct module_env;
+struct module_qstate;
struct ub_packed_rrset_key;
struct key_entry_key;
struct regional;
* @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.
+ * @param section: section of packet where this rrset comes from.
+ * @param qstate: qstate with region.
* @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);
+ uint8_t* sigalg, char** reason, sldns_pkt_section section,
+ struct module_qstate* qstate);
/**
* Verify RRset with keys from a keyset.
* @param rrset: what to verify
* @param kkey: key_entry to verify with.
* @param reason: reason of failure. Fixed string or alloced in scratch.
+ * @param section: section of packet where this rrset comes from.
+ * @param qstate: qstate with region.
* @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);
+ struct key_entry_key* kkey, char** reason, sldns_pkt_section section,
+ struct module_qstate* qstate);
/**
* Verify DNSKEYs with DS rrset. Like val_verify_new_DNSKEYs but
* 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.
+ * @param qstate: qstate with region.
* @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);
+ struct ub_packed_rrset_key* ds_rrset, uint8_t* sigalg, char** reason,
+ struct module_qstate* qstate);
/**
* Verify DNSKEYs with DS and DNSKEY rrset. Like val_verify_DNSKEY_with_DS
* 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.
+ * @param qstate: qstate with region.
* @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);
+ struct ub_packed_rrset_key* ta_dnskey, uint8_t* sigalg, char** reason,
+ struct module_qstate* qstate);
/**
* Verify new DNSKEYs with DS rrset. The DS contains hash values that should
* @param downprot: if true provide downgrade protection otherwise one
* algorithm is enough.
* @param reason: reason of failure. Fixed string or alloced in scratch.
+ * @param qstate: qstate with region.
* @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
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);
+ struct ub_packed_rrset_key* ds_rrset, int downprot, char** reason,
+ struct module_qstate* qstate);
/**
* @param downprot: if true provide downgrade protection otherwise one
* algorithm is enough.
* @param reason: reason of failure. Fixed string or alloced in scratch.
+ * @param qstate: qstate with region.
* @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
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);
+ int downprot, char** reason, struct module_qstate* qstate);
/**
* Determine if DS rrset is usable for validator or not.
* the result of a wildcard expansion. If so, return the name of the
* generating wildcard.
*
- * @param rrset The rrset to chedck.
+ * @param rrset The rrset to check.
* @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.
}
/* Verify the answer rrset */
- sec = val_verify_rrset_entry(env, ve, s, key_entry, &reason);
+ sec = val_verify_rrset_entry(env, ve, s, key_entry, &reason,
+ LDNS_SECTION_ANSWER, qstate);
/* If the (answer) rrset failed to validate, then this
* message is BAD. */
if(sec != sec_status_secure) {
for(i=chase_reply->an_numrrsets; i<chase_reply->an_numrrsets+
chase_reply->ns_numrrsets; i++) {
s = chase_reply->rrsets[i];
- sec = val_verify_rrset_entry(env, ve, s, key_entry, &reason);
+ sec = val_verify_rrset_entry(env, ve, s, key_entry, &reason,
+ LDNS_SECTION_AUTHORITY, qstate);
/* If anything in the authority section fails to be secure,
* we have a bad message. */
if(sec != sec_status_secure) {
val_find_rrset_signer(s, &sname, &slen);
if(sname && query_dname_compare(sname, key_entry->name)==0)
(void)val_verify_rrset_entry(env, ve, s, key_entry,
- &reason);
+ &reason, LDNS_SECTION_ADDITIONAL, qstate);
/* the additional section can fail to be secure,
* it is optional, check signature in case we need
* to clean the additional section later. */
/* attempt to verify with trust anchor DS and DNSKEY */
kkey = val_verify_new_DNSKEYs_with_ta(qstate->region, qstate->env, ve,
dnskey_rrset, ta->ds_rrset, ta->dnskey_rrset, downprot,
- &reason);
+ &reason, qstate);
if(!kkey) {
log_err("out of memory: verifying prime TA");
return NULL;
/* Verify only returns BOGUS or SECURE. If the rrset is
* bogus, then we are done. */
sec = val_verify_rrset_entry(qstate->env, ve, ds,
- vq->key_entry, &reason);
+ vq->key_entry, &reason, LDNS_SECTION_ANSWER, qstate);
if(sec != sec_status_secure) {
verbose(VERB_DETAIL, "DS rrset in DS response did "
"not verify");
/* Try to prove absence of the DS with NSEC */
sec = val_nsec_prove_nodata_dsreply(
qstate->env, ve, qinfo, msg->rep, vq->key_entry,
- &proof_ttl, &reason);
+ &proof_ttl, &reason, qstate);
switch(sec) {
case sec_status_secure:
verbose(VERB_DETAIL, "NSEC RRset for the "
sec = nsec3_prove_nods(qstate->env, ve,
msg->rep->rrsets + msg->rep->an_numrrsets,
- msg->rep->ns_numrrsets, qinfo, vq->key_entry, &reason);
+ msg->rep->ns_numrrsets, qinfo, vq->key_entry, &reason,
+ qstate);
switch(sec) {
case sec_status_insecure:
/* case insecure also continues to unsigned
goto return_bogus;
}
sec = val_verify_rrset_entry(qstate->env, ve, cname,
- vq->key_entry, &reason);
+ vq->key_entry, &reason, LDNS_SECTION_ANSWER, qstate);
if(sec == sec_status_secure) {
verbose(VERB_ALGO, "CNAME validated, "
"proof that DS does not exist");
}
downprot = qstate->env->cfg->harden_algo_downgrade;
vq->key_entry = val_verify_new_DNSKEYs(qstate->region, qstate->env,
- ve, dnskey, vq->ds_rrset, downprot, &reason);
+ ve, dnskey, vq->ds_rrset, downprot, &reason, qstate);
if(!vq->key_entry) {
log_err("out of memory in verify new DNSKEYs");
}
if(ta->autr) {
- if(!autr_process_prime(qstate->env, ve, ta, dnskey_rrset)) {
+ if(!autr_process_prime(qstate->env, ve, ta, dnskey_rrset,
+ qstate)) {
/* trust anchor revoked, restart with less anchors */
vq->state = VAL_INIT_STATE;
vq->trust_anchor_name = NULL;