Add the basic EDE (RFC8914) cases (#604)

This commit is contained in:
tcarpay
2022-05-06 12:48:53 +02:00
committed by GitHub
parent b61b0af5d6
commit 0ce36e8289
90 changed files with 16257 additions and 13142 deletions
+2 -2
View File
@@ -1263,7 +1263,7 @@ verify_dnskey(struct module_env* env, struct val_env* ve,
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,
qstate);
NULL, 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
@@ -1312,7 +1312,7 @@ rr_is_selfsigned_revoked(struct module_env* env, struct val_env* ve,
/* 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, LDNS_SECTION_ANSWER, qstate);
&reason, NULL, LDNS_SECTION_ANSWER, qstate);
return (sec == sec_status_secure);
}
+1
View File
@@ -90,6 +90,7 @@ key_cache_insert(struct key_cache* kcache, struct key_entry_key* kkey,
qstate->env->cfg->val_log_level >= 2) {
/* on malloc failure there is simply no reason string */
key_entry_set_reason(k, errinf_to_str_bogus(qstate));
key_entry_set_reason_bogus(k, errinf_to_reason_bogus(qstate));
}
key_entry_hash(k);
slabhash_insert(kcache->slab, k->entry.hash, &k->entry,
+20
View File
@@ -244,6 +244,15 @@ key_entry_set_reason(struct key_entry_key* kkey, char* reason)
d->reason = reason;
}
void
key_entry_set_reason_bogus(struct key_entry_key* kkey, sldns_ede_code ede)
{
struct key_entry_data* d = (struct key_entry_data*)kkey->entry.data;
if (ede != LDNS_EDE_NONE) { /* reason_bogus init is LDNS_EDE_NONE already */
d->reason_bogus = ede;
}
}
char*
key_entry_get_reason(struct key_entry_key* kkey)
{
@@ -251,6 +260,14 @@ key_entry_get_reason(struct key_entry_key* kkey)
return d->reason;
}
sldns_ede_code
key_entry_get_reason_bogus(struct key_entry_key* kkey)
{
struct key_entry_data* d = (struct key_entry_data*)kkey->entry.data;
return d->reason_bogus;
}
/** setup key entry in region */
static int
key_entry_setup(struct regional* region,
@@ -286,6 +303,7 @@ key_entry_create_null(struct regional* region,
d->ttl = now + ttl;
d->isbad = 0;
d->reason = NULL;
d->reason_bogus = LDNS_EDE_NONE;
d->rrset_type = LDNS_RR_TYPE_DNSKEY;
d->rrset_data = NULL;
d->algo = NULL;
@@ -306,6 +324,7 @@ key_entry_create_rrset(struct regional* region,
d->ttl = rd->ttl + now;
d->isbad = 0;
d->reason = NULL;
d->reason_bogus = LDNS_EDE_NONE;
d->rrset_type = ntohs(rrset->rk.type);
d->rrset_data = (struct packed_rrset_data*)regional_alloc_init(region,
rd, packed_rrset_sizeof(rd));
@@ -332,6 +351,7 @@ key_entry_create_bad(struct regional* region,
d->ttl = now + ttl;
d->isbad = 1;
d->reason = NULL;
d->reason_bogus = LDNS_EDE_NONE;
d->rrset_type = LDNS_RR_TYPE_DNSKEY;
d->rrset_data = NULL;
d->algo = NULL;
+19
View File
@@ -45,6 +45,7 @@ struct packed_rrset_data;
struct regional;
struct ub_packed_rrset_key;
#include "util/storage/lruhash.h"
#include "sldns/rrdef.h"
/**
* A key entry for the validator.
@@ -80,6 +81,8 @@ struct key_entry_data {
struct packed_rrset_data* rrset_data;
/** not NULL sometimes to give reason why bogus */
char* reason;
/** not NULL to give reason why bogus */
sldns_ede_code reason_bogus;
/** list of algorithms signalled, ends with 0, or NULL */
uint8_t* algo;
/** DNS RR type of the rrset data (host order) */
@@ -150,6 +153,15 @@ int key_entry_isbad(struct key_entry_key* kkey);
*/
void key_entry_set_reason(struct key_entry_key* kkey, char* reason);
/**
* Set the EDE (RFC8914) code why the key is bad, if it
* exists (so not LDNS_EDE_NONE).
* @param kkey: bad key.
* @param ede: EDE code to attach to this key.
*/
void key_entry_set_reason_bogus(struct key_entry_key* kkey, sldns_ede_code ede);
/**
* Get reason why a key is bad.
* @param kkey: bad key
@@ -158,6 +170,13 @@ void key_entry_set_reason(struct key_entry_key* kkey, char* reason);
*/
char* key_entry_get_reason(struct key_entry_key* kkey);
/**
* Get the EDE (RFC8914) code why a key is bad. Can return LDNS_EDE_NONE.
* @param kkey: bad key
* @return the ede code.
*/
sldns_ede_code key_entry_get_reason_bogus(struct key_entry_key* kkey);
/**
* Create a null entry, in the given region.
* @param region: where to allocate
+1 -1
View File
@@ -187,7 +187,7 @@ nsec_verify_rrset(struct module_env* env, struct val_env* ve,
if(d->security == sec_status_secure)
return 1;
d->security = val_verify_rrset_entry(env, ve, nsec, kkey, reason,
LDNS_SECTION_AUTHORITY, qstate);
NULL, LDNS_SECTION_AUTHORITY, qstate);
if(d->security == sec_status_secure) {
rrset_update_sec_status(env->rrset_cache, nsec, *env->now);
return 1;
+7 -4
View File
@@ -1289,7 +1289,8 @@ nsec3_prove_wildcard(struct module_env* env, struct val_env* ve,
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 module_qstate* qstate)
struct key_entry_key* kkey, char** reason, sldns_ede_code *reason_bogus,
struct module_qstate* qstate)
{
struct packed_rrset_data* d;
size_t i;
@@ -1303,7 +1304,7 @@ list_is_secure(struct module_env* env, struct val_env* ve,
if(d->security == sec_status_secure)
continue;
d->security = val_verify_rrset_entry(env, ve, list[i], kkey,
reason, LDNS_SECTION_AUTHORITY, qstate);
reason, reason_bogus, LDNS_SECTION_AUTHORITY, qstate);
if(d->security != sec_status_secure) {
verbose(VERB_ALGO, "NSEC3 did not verify");
return 0;
@@ -1317,7 +1318,7 @@ 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 module_qstate* qstate)
sldns_ede_code* reason_bogus, struct module_qstate* qstate)
{
rbtree_type ct;
struct nsec3_filter flt;
@@ -1330,8 +1331,10 @@ nsec3_prove_nods(struct module_env* env, struct val_env* ve,
*reason = "no valid NSEC3s";
return sec_status_bogus; /* no valid NSEC3s, bogus */
}
if(!list_is_secure(env, ve, list, num, kkey, reason, qstate))
if(!list_is_secure(env, ve, list, num, kkey, reason, reason_bogus, qstate)) {
*reason = "not all NSEC3 records secure";
return sec_status_bogus; /* not all NSEC3 records secure */
}
rbtree_init(&ct, &nsec3_hash_cmp); /* init names-to-hash cache */
filter_init(&flt, list, num, qinfo); /* init RR iterator */
if(!flt.zone) {
+3 -1
View File
@@ -68,6 +68,7 @@
#define VALIDATOR_VAL_NSEC3_H
#include "util/rbtree.h"
#include "util/data/packed_rrset.h"
#include "sldns/rrdef.h"
struct val_env;
struct regional;
struct module_env;
@@ -186,6 +187,7 @@ nsec3_prove_wildcard(struct module_env* env, struct val_env* ve,
* @param qinfo: query that is verified for.
* @param kkey: key entry that signed the NSEC3s.
* @param reason: string for bogus result.
* @param reason_bogus: EDE (RFC8914) code paired with the reason of failure.
* @param qstate: qstate with region.
* @return:
* sec_status SECURE of the proposition is proven by the NSEC3 RRs,
@@ -197,7 +199,7 @@ 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 module_qstate* qstate);
sldns_ede_code* reason_bogus, struct module_qstate* qstate);
/**
* Prove NXDOMAIN or NODATA.
+78 -21
View File
@@ -525,11 +525,19 @@ int algo_needs_missing(struct algo_needs* n)
return 0;
}
static 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, sldns_ede_code *reason_bogus,
sldns_pkt_section section, struct module_qstate* qstate);
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, sldns_pkt_section section,
struct module_qstate* qstate)
uint8_t* sigalg, char** reason, sldns_ede_code *reason_bogus,
sldns_pkt_section section, struct module_qstate* qstate)
{
enum sec_status sec;
size_t i, num;
@@ -543,6 +551,8 @@ dnskeyset_verify_rrset(struct module_env* env, struct val_env* ve,
verbose(VERB_QUERY, "rrset failed to verify due to a lack of "
"signatures");
*reason = "no signatures";
if(reason_bogus)
*reason_bogus = LDNS_EDE_RRSIGS_MISSING;
return sec_status_bogus;
}
@@ -551,12 +561,15 @@ dnskeyset_verify_rrset(struct module_env* env, struct val_env* ve,
if(algo_needs_num_missing(&needs) == 0) {
verbose(VERB_QUERY, "zone has no known algorithms");
*reason = "zone has no known algorithms";
if(reason_bogus)
*reason_bogus = LDNS_EDE_UNSUPPORTED_DNSKEY_ALG;
return sec_status_insecure;
}
}
for(i=0; i<num; i++) {
sec = dnskeyset_verify_rrset_sig(env, ve, *env->now, rrset,
dnskey, i, &sortree, reason, section, qstate);
dnskey, i, &sortree, reason, reason_bogus,
section, qstate);
/* see which algorithm has been fixed up */
if(sec == sec_status_secure) {
if(!sigalg)
@@ -597,8 +610,8 @@ void algo_needs_reason(struct module_env* env, int alg, char** reason, char* s)
enum sec_status
dnskey_verify_rrset(struct module_env* env, struct val_env* ve,
struct ub_packed_rrset_key* rrset, struct ub_packed_rrset_key* dnskey,
size_t dnskey_idx, char** reason, sldns_pkt_section section,
struct module_qstate* qstate)
size_t dnskey_idx, char** reason, sldns_ede_code *reason_bogus,
sldns_pkt_section section, struct module_qstate* qstate)
{
enum sec_status sec;
size_t i, num, numchecked = 0;
@@ -612,6 +625,8 @@ dnskey_verify_rrset(struct module_env* env, struct val_env* ve,
verbose(VERB_QUERY, "rrset failed to verify due to a lack of "
"signatures");
*reason = "no signatures";
if(reason_bogus)
*reason_bogus = LDNS_EDE_RRSIGS_MISSING;
return sec_status_bogus;
}
for(i=0; i<num; i++) {
@@ -620,10 +635,10 @@ dnskey_verify_rrset(struct module_env* env, struct val_env* ve,
tag != rrset_get_sig_keytag(rrset, i))
continue;
buf_canon = 0;
sec = dnskey_verify_rrset_sig(env->scratch,
sec = dnskey_verify_rrset_sig(env->scratch,
env->scratch_buffer, ve, *env->now, rrset,
dnskey, dnskey_idx, i, &sortree, &buf_canon, reason,
section, qstate);
reason_bogus, section, qstate);
if(sec == sec_status_secure)
return sec;
numchecked ++;
@@ -633,12 +648,13 @@ dnskey_verify_rrset(struct module_env* env, struct val_env* ve,
return sec_status_bogus;
}
enum sec_status
dnskeyset_verify_rrset_sig(struct module_env* env, struct val_env* ve,
time_t now, struct ub_packed_rrset_key* rrset,
struct ub_packed_rrset_key* dnskey, size_t sig_idx,
struct rbtree_type** sortree, char** reason, sldns_pkt_section section,
struct module_qstate* qstate)
static 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, sldns_ede_code *reason_bogus,
sldns_pkt_section section, struct module_qstate* qstate)
{
/* find matching keys and check them */
enum sec_status sec = sec_status_bogus;
@@ -649,10 +665,12 @@ dnskeyset_verify_rrset_sig(struct module_env* env, struct val_env* ve,
int buf_canon = 0;
verbose(VERB_ALGO, "verify sig %d %d", (int)tag, algo);
if(!dnskey_algo_id_is_supported(algo)) {
if(reason_bogus)
*reason_bogus = LDNS_EDE_UNSUPPORTED_DNSKEY_ALG;
verbose(VERB_QUERY, "verify sig: unknown algorithm");
return sec_status_insecure;
}
for(i=0; i<num; i++) {
/* see if key matches keytag and algo */
if(algo != dnskey_get_algo(dnskey, i) ||
@@ -661,14 +679,17 @@ dnskeyset_verify_rrset_sig(struct module_env* env, struct val_env* ve,
numchecked ++;
/* see if key verifies */
sec = dnskey_verify_rrset_sig(env->scratch,
env->scratch_buffer, ve, now, rrset, dnskey, i,
sig_idx, sortree, &buf_canon, reason, section, qstate);
sec = dnskey_verify_rrset_sig(env->scratch,
env->scratch_buffer, ve, now, rrset, dnskey, i,
sig_idx, sortree, &buf_canon, reason, reason_bogus,
section, qstate);
if(sec == sec_status_secure)
return sec;
}
if(numchecked == 0) {
*reason = "signatures from unknown keys";
if(reason_bogus)
*reason_bogus = LDNS_EDE_DNSKEY_MISSING;
verbose(VERB_QUERY, "verify: could not find appropriate key");
return sec_status_bogus;
}
@@ -1361,8 +1382,8 @@ subtract_1982(uint32_t a, uint32_t b)
/** check rrsig dates */
static int
check_dates(struct val_env* ve, uint32_t unow,
uint8_t* expi_p, uint8_t* incep_p, char** reason)
check_dates(struct val_env* ve, uint32_t unow, uint8_t* expi_p,
uint8_t* incep_p, char** reason, sldns_ede_code *reason_bogus)
{
/* read out the dates */
uint32_t expi, incep, now;
@@ -1386,6 +1407,14 @@ check_dates(struct val_env* ve, uint32_t unow,
sigdate_error("verify: inception after expiration, "
"signature bad", expi, incep, now);
*reason = "signature inception after expiration";
if(reason_bogus){
/* from RFC8914 on Signature Not Yet Valid: The resolver
* attempted to perform DNSSEC validation, but no
* signatures are presently valid and at least some are
* not yet valid. */
*reason_bogus = LDNS_EDE_SIGNATURE_NOT_YET_VALID;
}
return 0;
}
if(compare_1982(incep, now) > 0) {
@@ -1397,6 +1426,8 @@ check_dates(struct val_env* ve, uint32_t unow,
sigdate_error("verify: signature bad, current time is"
" before inception date", expi, incep, now);
*reason = "signature before inception date";
if(reason_bogus)
*reason_bogus = LDNS_EDE_SIGNATURE_NOT_YET_VALID;
return 0;
}
sigdate_error("verify warning suspicious signature inception "
@@ -1410,6 +1441,8 @@ check_dates(struct val_env* ve, uint32_t unow,
sigdate_error("verify: signature expired", expi,
incep, now);
*reason = "signature expired";
if(reason_bogus)
*reason_bogus = LDNS_EDE_SIGNATURE_EXPIRED;
return 0;
}
sigdate_error("verify warning suspicious signature expiration "
@@ -1473,7 +1506,8 @@ dnskey_verify_rrset_sig(struct regional* region, sldns_buffer* buf,
struct val_env* ve, time_t now,
struct ub_packed_rrset_key* rrset, struct ub_packed_rrset_key* dnskey,
size_t dnskey_idx, size_t sig_idx,
struct rbtree_type** sortree, int* buf_canon, char** reason,
struct rbtree_type** sortree, int* buf_canon,
char** reason, sldns_ede_code *reason_bogus,
sldns_pkt_section section, struct module_qstate* qstate)
{
enum sec_status sec;
@@ -1492,12 +1526,16 @@ dnskey_verify_rrset_sig(struct regional* region, sldns_buffer* buf,
if(siglen < 2+20) {
verbose(VERB_QUERY, "verify: signature too short");
*reason = "signature too short";
if(reason_bogus)
*reason_bogus = LDNS_EDE_DNSSEC_BOGUS;
return sec_status_bogus;
}
if(!(dnskey_get_flags(dnskey, dnskey_idx) & DNSKEY_BIT_ZSK)) {
verbose(VERB_QUERY, "verify: dnskey without ZSK flag");
*reason = "dnskey without ZSK flag";
if(reason_bogus)
*reason_bogus = LDNS_EDE_NO_ZONE_KEY_BIT_SET;
return sec_status_bogus;
}
@@ -1505,6 +1543,8 @@ dnskey_verify_rrset_sig(struct regional* region, sldns_buffer* buf,
/* RFC 4034 says DNSKEY PROTOCOL MUST be 3 */
verbose(VERB_QUERY, "verify: dnskey has wrong key protocol");
*reason = "dnskey has wrong protocolnumber";
if(reason_bogus)
*reason_bogus = LDNS_EDE_DNSSEC_BOGUS;
return sec_status_bogus;
}
@@ -1514,17 +1554,23 @@ dnskey_verify_rrset_sig(struct regional* region, sldns_buffer* buf,
if(!signer_len) {
verbose(VERB_QUERY, "verify: malformed signer name");
*reason = "signer name malformed";
if(reason_bogus)
*reason_bogus = LDNS_EDE_DNSSEC_BOGUS;
return sec_status_bogus; /* signer name invalid */
}
if(!dname_subdomain_c(rrset->rk.dname, signer)) {
verbose(VERB_QUERY, "verify: signer name is off-tree");
*reason = "signer name off-tree";
if(reason_bogus)
*reason_bogus = LDNS_EDE_DNSSEC_BOGUS;
return sec_status_bogus; /* signer name offtree */
}
sigblock = (unsigned char*)signer+signer_len;
if(siglen < 2+18+signer_len+1) {
verbose(VERB_QUERY, "verify: too short, no signature data");
*reason = "signature too short, no signature data";
if(reason_bogus)
*reason_bogus = LDNS_EDE_DNSSEC_BOGUS;
return sec_status_bogus; /* sig rdf is < 1 byte */
}
sigblock_len = (unsigned int)(siglen - 2 - 18 - signer_len);
@@ -1537,6 +1583,8 @@ dnskey_verify_rrset_sig(struct regional* region, sldns_buffer* buf,
log_nametypeclass(VERB_QUERY, "the key name is",
dnskey->rk.dname, 0, 0);
*reason = "signer name mismatches key name";
if(reason_bogus)
*reason_bogus = LDNS_EDE_DNSSEC_BOGUS;
return sec_status_bogus;
}
@@ -1545,18 +1593,24 @@ dnskey_verify_rrset_sig(struct regional* region, sldns_buffer* buf,
if(memcmp(sig+2, &rrset->rk.type, 2) != 0) {
verbose(VERB_QUERY, "verify: wrong type covered");
*reason = "signature covers wrong type";
if(reason_bogus)
*reason_bogus = LDNS_EDE_DNSSEC_BOGUS;
return sec_status_bogus;
}
/* verify keytag and sig algo (possibly again) */
if((int)sig[2+2] != dnskey_get_algo(dnskey, dnskey_idx)) {
verbose(VERB_QUERY, "verify: wrong algorithm");
*reason = "signature has wrong algorithm";
if(reason_bogus)
*reason_bogus = LDNS_EDE_DNSSEC_BOGUS;
return sec_status_bogus;
}
ktag = htons(dnskey_calc_keytag(dnskey, dnskey_idx));
if(memcmp(sig+2+16, &ktag, 2) != 0) {
verbose(VERB_QUERY, "verify: wrong keytag");
*reason = "signature has wrong keytag";
if(reason_bogus)
*reason_bogus = LDNS_EDE_DNSSEC_BOGUS;
return sec_status_bogus;
}
@@ -1564,6 +1618,8 @@ dnskey_verify_rrset_sig(struct regional* region, sldns_buffer* buf,
if((int)sig[2+3] > dname_signame_label_count(rrset->rk.dname)) {
verbose(VERB_QUERY, "verify: labelcount out of range");
*reason = "signature labelcount out of range";
if(reason_bogus)
*reason_bogus = LDNS_EDE_DNSSEC_BOGUS;
return sec_status_bogus;
}
@@ -1598,7 +1654,8 @@ dnskey_verify_rrset_sig(struct regional* region, sldns_buffer* buf,
/* verify inception, expiration dates
* Do this last so that if you ignore expired-sigs the
* rest is sure to be OK. */
if(!check_dates(ve, now, sig+2+8, sig+2+12, reason)) {
if(!check_dates(ve, now, sig+2+8, sig+2+12,
reason, reason_bogus)) {
return sec_status_bogus;
}
}
+17 -32
View File
@@ -45,6 +45,7 @@
#define VALIDATOR_VAL_SIGCRYPT_H
#include "util/data/packed_rrset.h"
#include "sldns/pkthdr.h"
#include "sldns/rrdef.h"
struct val_env;
struct module_env;
struct module_qstate;
@@ -256,6 +257,7 @@ uint16_t dnskey_get_flags(struct ub_packed_rrset_key* k, size_t idx);
* @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 reason_bogus: EDE (RFC8914) code paired with the reason of failure.
* @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.
@@ -264,9 +266,11 @@ uint16_t dnskey_get_flags(struct ub_packed_rrset_key* k, size_t idx);
*/
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_ede_code *reason_bogus,
sldns_pkt_section section, struct module_qstate* qstate);
/**
* verify rrset against one specific dnskey (from rrset)
* @param env: module environment, scratch space is used.
@@ -275,38 +279,17 @@ enum sec_status dnskeyset_verify_rrset(struct module_env* env,
* @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 reason_bogus: EDE (RFC8914) code paired with the reason of failure.
* @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,
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, sldns_ede_code *reason_bogus,
sldns_pkt_section section, struct module_qstate* qstate);
/**
* 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.
* @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, sldns_pkt_section section,
struct module_qstate* qstate);
/**
* verify rrset, with specific dnskey(from set), for a specific rrsig
* @param region: scratch region used for temporary allocation.
@@ -323,17 +306,19 @@ enum sec_status dnskeyset_verify_rrset_sig(struct module_env* env,
* 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 reason_bogus: EDE (8914) code paired with the reason of failure.
* @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.
*/
enum sec_status dnskey_verify_rrset_sig(struct regional* region,
struct sldns_buffer* buf, struct val_env* ve, time_t now,
struct ub_packed_rrset_key* rrset, struct ub_packed_rrset_key* dnskey,
size_t dnskey_idx, size_t sig_idx,
struct rbtree_type** sortree, int* buf_canon, char** reason,
sldns_pkt_section section, struct module_qstate* qstate);
enum sec_status dnskey_verify_rrset_sig(struct regional* region,
struct sldns_buffer* buf, struct val_env* ve, time_t now,
struct ub_packed_rrset_key* rrset, struct ub_packed_rrset_key* dnskey,
size_t dnskey_idx, size_t sig_idx,
struct rbtree_type** sortree, int* buf_canon,
char** reason, sldns_ede_code *reason_bogus,
sldns_pkt_section section, struct module_qstate* qstate);
/**
* canonical compare for two tree entries
+37 -29
View File
@@ -332,11 +332,11 @@ rrset_get_ttl(struct ub_packed_rrset_key* rrset)
return d->ttl;
}
enum sec_status
static 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, sldns_pkt_section section,
struct module_qstate* qstate)
uint8_t* sigalg, char** reason, sldns_ede_code *reason_bogus,
sldns_pkt_section section, struct module_qstate* qstate)
{
enum sec_status sec;
struct packed_rrset_data* d = (struct packed_rrset_data*)rrset->
@@ -359,7 +359,7 @@ val_verify_rrset(struct module_env* env, struct val_env* ve,
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,
section, qstate);
reason_bogus, section, qstate);
verbose(VERB_ALGO, "verify result: %s", sec_status_to_string(sec));
regional_free_all(env->scratch);
@@ -392,7 +392,8 @@ val_verify_rrset(struct module_env* env, struct val_env* ve,
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, sldns_pkt_section section, struct module_qstate* qstate)
char** reason, sldns_ede_code *reason_bogus,
sldns_pkt_section section, struct module_qstate* qstate)
{
/* temporary dnskey rrset-key */
struct ub_packed_rrset_key dnskey;
@@ -406,16 +407,16 @@ val_verify_rrset_entry(struct module_env* env, struct val_env* ve,
dnskey.entry.key = &dnskey;
dnskey.entry.data = kd->rrset_data;
sec = val_verify_rrset(env, ve, rrset, &dnskey, kd->algo, reason,
section, qstate);
reason_bogus, section, qstate);
return sec;
}
/** verify that a DS RR hashes to a key and that key signs the set */
static enum sec_status
verify_dnskeys_with_ds_rr(struct module_env* env, struct val_env* ve,
struct ub_packed_rrset_key* dnskey_rrset,
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 module_qstate* qstate)
sldns_ede_code *reason_bogus, struct module_qstate* qstate)
{
enum sec_status sec = sec_status_bogus;
size_t i, num, numchecked = 0, numhashok = 0, numsizesupp = 0;
@@ -450,8 +451,8 @@ verify_dnskeys_with_ds_rr(struct module_env* env, struct val_env* ve,
/* 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, LDNS_SECTION_ANSWER, qstate);
sec = dnskey_verify_rrset(env, ve, dnskey_rrset, dnskey_rrset,
i, reason, reason_bogus, LDNS_SECTION_ANSWER, qstate);
if(sec == sec_status_secure) {
return sec;
}
@@ -488,11 +489,12 @@ int val_favorite_ds_algo(struct ub_packed_rrset_key* ds_rrset)
return digest_algo;
}
enum sec_status
// @TODO change the use of this function to _ede function in authzone.c:8111
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 module_qstate* qstate)
sldns_ede_code *reason_bogus, struct module_qstate* qstate)
{
/* as long as this is false, we can consider this DS rrset to be
* equivalent to no DS rrset. */
@@ -529,7 +531,7 @@ val_verify_DNSKEY_with_DS(struct module_env* env, struct val_env* ve,
}
sec = verify_dnskeys_with_ds_rr(env, ve, dnskey_rrset,
ds_rrset, i, reason, qstate);
ds_rrset, i, reason, reason_bogus, qstate);
if(sec == sec_status_insecure)
continue;
@@ -571,15 +573,16 @@ val_verify_DNSKEY_with_DS(struct module_env* env, struct val_env* ve,
return sec_status_bogus;
}
struct key_entry_key*
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 module_qstate* qstate)
sldns_ede_code *reason_bogus, 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, qstate);
enum sec_status sec = val_verify_DNSKEY_with_DS(env, ve,
dnskey_rrset, ds_rrset, downprot?sigalg:NULL, reason,
reason_bogus, qstate);
if(sec == sec_status_secure) {
return key_entry_create_rrset(region,
@@ -597,12 +600,12 @@ val_verify_new_DNSKEYs(struct regional* region, struct module_env* env,
BOGUS_KEY_TTL, *env->now);
}
enum sec_status
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 module_qstate* qstate)
sldns_ede_code *reason_bogus, struct module_qstate* qstate)
{
/* as long as this is false, we can consider this anchor to be
* equivalent to no anchor. */
@@ -617,6 +620,8 @@ val_verify_DNSKEY_with_TA(struct module_env* env, struct val_env* ve,
verbose(VERB_QUERY, "DNSKEY RRset did not match DS RRset "
"by name");
*reason = "DNSKEY RRset did not match DS RRset by name";
if(reason_bogus)
*reason_bogus = LDNS_EDE_DNSKEY_MISSING;
return sec_status_bogus;
}
if(ta_dnskey && (dnskey_rrset->rk.dname_len != ta_dnskey->rk.dname_len
@@ -625,6 +630,8 @@ val_verify_DNSKEY_with_TA(struct module_env* env, struct val_env* ve,
verbose(VERB_QUERY, "DNSKEY RRset did not match anchor RRset "
"by name");
*reason = "DNSKEY RRset did not match anchor RRset by name";
if(reason_bogus)
*reason_bogus = LDNS_EDE_DNSKEY_MISSING;
return sec_status_bogus;
}
@@ -648,7 +655,7 @@ val_verify_DNSKEY_with_TA(struct module_env* env, struct val_env* ve,
continue;
sec = verify_dnskeys_with_ds_rr(env, ve, dnskey_rrset,
ta_ds, i, reason, qstate);
ta_ds, i, reason, reason_bogus, qstate);
if(sec == sec_status_insecure)
continue;
@@ -688,7 +695,7 @@ val_verify_DNSKEY_with_TA(struct module_env* env, struct val_env* ve,
has_useful_ta = 1;
sec = dnskey_verify_rrset(env, ve, dnskey_rrset,
ta_dnskey, i, reason, LDNS_SECTION_ANSWER, qstate);
ta_dnskey, i, reason, NULL, LDNS_SECTION_ANSWER, qstate);
if(sec == sec_status_secure) {
if(!sigalg || algo_needs_set_secure(&needs,
(uint8_t)dnskey_get_algo(ta_dnskey, i))) {
@@ -723,24 +730,24 @@ val_verify_DNSKEY_with_TA(struct module_env* env, struct val_env* ve,
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 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, struct module_qstate* qstate)
char** reason, sldns_ede_code *reason_bogus, struct module_qstate* qstate)
{
uint8_t sigalg[ALGO_NEEDS_MAX+1];
enum sec_status sec = val_verify_DNSKEY_with_TA(env, ve,
enum sec_status sec = val_verify_DNSKEY_with_TA(env, ve,
dnskey_rrset, ta_ds_rrset, ta_dnskey_rrset,
downprot?sigalg:NULL, reason, qstate);
downprot?sigalg:NULL, reason, reason_bogus, qstate);
if(sec == sec_status_secure) {
return key_entry_create_rrset(region,
return key_entry_create_rrset(region,
dnskey_rrset->rk.dname, dnskey_rrset->rk.dname_len,
ntohs(dnskey_rrset->rk.rrset_class), dnskey_rrset,
downprot?sigalg:NULL, *env->now);
} else if(sec == sec_status_insecure) {
return key_entry_create_null(region, dnskey_rrset->rk.dname,
dnskey_rrset->rk.dname_len,
dnskey_rrset->rk.dname_len,
ntohs(dnskey_rrset->rk.rrset_class),
rrset_get_ttl(dnskey_rrset), *env->now);
}
@@ -749,7 +756,7 @@ val_verify_new_DNSKEYs_with_ta(struct regional* region, struct module_env* env,
BOGUS_KEY_TTL, *env->now);
}
int
int
val_dsset_isusable(struct ub_packed_rrset_key* ds_rrset)
{
size_t i;
@@ -776,6 +783,7 @@ val_dsset_isusable(struct ub_packed_rrset_key* ds_rrset)
if(lt) snprintf(aerr, sizeof(aerr), "%s", lt->name);
else snprintf(aerr, sizeof(aerr), "%d",
(int)ds_get_key_algo(ds_rrset, 0));
verbose(VERB_ALGO, "DS unsupported, hash %s %s, "
"key algorithm %s %s", herr,
(ds_digest_algo_is_supported(ds_rrset, 0)?
+27 -40
View File
@@ -43,6 +43,7 @@
#define VALIDATOR_VAL_UTILS_H
#include "util/data/packed_rrset.h"
#include "sldns/pkthdr.h"
#include "sldns/rrdef.h"
struct query_info;
struct reply_info;
struct val_env;
@@ -113,24 +114,6 @@ 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.
* @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, sldns_pkt_section section,
struct module_qstate* qstate);
/**
* Verify RRset with keys from a keyset.
* @param env: module environment (scratch buffer)
@@ -138,14 +121,15 @@ enum sec_status val_verify_rrset(struct module_env* env, struct val_env* ve,
* @param rrset: what to verify
* @param kkey: key_entry to verify with.
* @param reason: reason of failure. Fixed string or alloced in scratch.
* @param reason_bogus: EDE (RFC8914) code paired with the reason of failure.
* @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, sldns_pkt_section section,
struct module_qstate* qstate);
struct key_entry_key* kkey, char** reason, sldns_ede_code *reason_bogus,
sldns_pkt_section section, struct module_qstate* qstate);
/**
* Verify DNSKEYs with DS rrset. Like val_verify_new_DNSKEYs but
@@ -158,15 +142,16 @@ enum sec_status val_verify_rrset_entry(struct module_env* env,
* 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 reason_bogus: EDE (RFC8914) code paired with the reason of failure.
* @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 module_qstate* qstate);
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,
sldns_ede_code *reason_bogus, struct module_qstate* qstate);
/**
* Verify DNSKEYs with DS and DNSKEY rrset. Like val_verify_DNSKEY_with_DS
@@ -180,16 +165,17 @@ enum sec_status val_verify_DNSKEY_with_DS(struct module_env* env,
* 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 reason_bogus: EDE (RFC8914) code paired with the reason of failure.
* @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 module_qstate* qstate);
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,
sldns_ede_code *reason_bogus, struct module_qstate* qstate);
/**
* Verify new DNSKEYs with DS rrset. The DS contains hash values that should
@@ -204,6 +190,7 @@ enum sec_status val_verify_DNSKEY_with_TA(struct module_env* env,
* @param downprot: if true provide downgrade protection otherwise one
* algorithm is enough.
* @param reason: reason of failure. Fixed string or alloced in scratch.
* @param reason_bogus: EDE (RFC8914) code paired with the reason of failure.
* @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
@@ -215,12 +202,11 @@ enum sec_status val_verify_DNSKEY_with_TA(struct module_env* env,
* 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,
struct module_qstate* qstate);
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,
sldns_ede_code *reason_bogus, struct module_qstate* qstate);
/**
* Verify rrset with trust anchor: DS and DNSKEY rrset.
@@ -234,6 +220,7 @@ struct key_entry_key* val_verify_new_DNSKEYs(struct regional* region,
* @param downprot: if true provide downgrade protection otherwise one
* algorithm is enough.
* @param reason: reason of failure. Fixed string or alloced in scratch.
* @param reason_bogus: EDE (RFC8914) code paired with the reason of failure.
* @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
@@ -246,11 +233,11 @@ struct key_entry_key* val_verify_new_DNSKEYs(struct regional* region,
* 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, struct module_qstate* qstate);
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, sldns_ede_code *reason_bogus, struct module_qstate* qstate);
/**
* Determine if DS rrset is usable for validator or not.
+95 -28
View File
@@ -69,6 +69,20 @@ static void process_ds_response(struct module_qstate* qstate,
struct val_qstate* vq, int id, int rcode, struct dns_msg* msg,
struct query_info* qinfo, struct sock_list* origin);
/* Updates the suplied EDE (RFC8914) code selectively so we don't loose
* a more specific code
*/
static void
update_reason_bogus(struct reply_info* rep, sldns_ede_code reason_bogus)
{
if (rep->reason_bogus == LDNS_EDE_DNSSEC_BOGUS ||
rep->reason_bogus == LDNS_EDE_NONE) {
rep->reason_bogus = reason_bogus;
}
}
/** fill up nsec3 key iterations config entry */
static int
fill_nsec3_iter(struct val_env* ve, char* s, int c)
@@ -230,6 +244,7 @@ val_new_getmsg(struct module_qstate* qstate, struct val_qstate* vq)
vq->orig_msg->rep->flags = (uint16_t)(qstate->return_rcode&0xf)
|BIT_QR|BIT_RA|(qstate->query_flags|(BIT_CD|BIT_RD));
vq->orig_msg->rep->qdcount = 1;
vq->orig_msg->rep->reason_bogus = LDNS_EDE_NONE;
} else {
vq->orig_msg = qstate->return_msg;
}
@@ -592,6 +607,7 @@ validate_msg_signatures(struct module_qstate* qstate, struct module_env* env,
enum sec_status sec;
int dname_seen = 0;
char* reason = NULL;
sldns_ede_code reason_bogus = LDNS_EDE_DNSSEC_BOGUS;
/* validate the ANSWER section */
for(i=0; i<chase_reply->an_numrrsets; i++) {
@@ -613,20 +629,22 @@ validate_msg_signatures(struct module_qstate* qstate, struct module_env* env,
/* Verify the answer rrset */
sec = val_verify_rrset_entry(env, ve, s, key_entry, &reason,
LDNS_SECTION_ANSWER, qstate);
&reason_bogus, LDNS_SECTION_ANSWER, qstate);
/* If the (answer) rrset failed to validate, then this
* message is BAD. */
if(sec != sec_status_secure) {
log_nametypeclass(VERB_QUERY, "validator: response "
"has failed ANSWER rrset:", s->rk.dname,
ntohs(s->rk.type), ntohs(s->rk.rrset_class));
errinf(qstate, reason);
errinf_ede(qstate, reason, reason_bogus);
if(ntohs(s->rk.type) == LDNS_RR_TYPE_CNAME)
errinf(qstate, "for CNAME");
else if(ntohs(s->rk.type) == LDNS_RR_TYPE_DNAME)
errinf(qstate, "for DNAME");
errinf_origin(qstate, qstate->reply_origin);
chase_reply->security = sec_status_bogus;
update_reason_bogus(chase_reply, reason_bogus);
return 0;
}
@@ -643,17 +661,18 @@ validate_msg_signatures(struct module_qstate* qstate, struct module_env* env,
chase_reply->ns_numrrsets; i++) {
s = chase_reply->rrsets[i];
sec = val_verify_rrset_entry(env, ve, s, key_entry, &reason,
LDNS_SECTION_AUTHORITY, qstate);
&reason_bogus, LDNS_SECTION_AUTHORITY, qstate);
/* If anything in the authority section fails to be secure,
* we have a bad message. */
if(sec != sec_status_secure) {
log_nametypeclass(VERB_QUERY, "validator: response "
"has failed AUTHORITY rrset:", s->rk.dname,
ntohs(s->rk.type), ntohs(s->rk.rrset_class));
errinf(qstate, reason);
errinf_ede(qstate, reason, reason_bogus);
errinf_origin(qstate, qstate->reply_origin);
errinf_rrset(qstate, s);
chase_reply->security = sec_status_bogus;
update_reason_bogus(chase_reply, reason_bogus);
return 0;
}
}
@@ -669,9 +688,10 @@ validate_msg_signatures(struct module_qstate* qstate, struct module_env* env,
/* only validate rrs that have signatures with the key */
/* leave others unchecked, those get removed later on too */
val_find_rrset_signer(s, &sname, &slen);
if(sname && query_dname_compare(sname, key_entry->name)==0)
(void)val_verify_rrset_entry(env, ve, s, key_entry,
&reason, LDNS_SECTION_ADDITIONAL, qstate);
&reason, NULL, 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. */
@@ -804,6 +824,7 @@ validate_positive_response(struct module_env* env, struct val_env* ve,
"inconsistent wildcard sigs:", s->rk.dname,
ntohs(s->rk.type), ntohs(s->rk.rrset_class));
chase_reply->security = sec_status_bogus;
update_reason_bogus(chase_reply, LDNS_EDE_DNSSEC_BOGUS);
return;
}
if(wc && !wc_cached && env->cfg->aggressive_nsec) {
@@ -861,6 +882,7 @@ validate_positive_response(struct module_env* env, struct val_env* ve,
"expansion and did not prove original data "
"did not exist");
chase_reply->security = sec_status_bogus;
update_reason_bogus(chase_reply, LDNS_EDE_DNSSEC_BOGUS);
return;
}
@@ -959,6 +981,7 @@ validate_nodata_response(struct module_env* env, struct val_env* ve,
if(verbosity >= VERB_ALGO)
log_dns_msg("Failed NODATA", qchase, chase_reply);
chase_reply->security = sec_status_bogus;
update_reason_bogus(chase_reply, LDNS_EDE_DNSSEC_BOGUS);
return;
}
@@ -1045,6 +1068,7 @@ validate_nameerror_response(struct module_env* env, struct val_env* ve,
verbose(VERB_QUERY, "NameError response has failed to prove: "
"qname does not exist");
chase_reply->security = sec_status_bogus;
update_reason_bogus(chase_reply, LDNS_EDE_DNSSEC_BOGUS);
/* Be lenient with RCODE in NSEC NameError responses */
validate_nodata_response(env, ve, qchase, chase_reply, kkey);
if (chase_reply->security == sec_status_secure)
@@ -1056,6 +1080,7 @@ validate_nameerror_response(struct module_env* env, struct val_env* ve,
verbose(VERB_QUERY, "NameError response has failed to prove: "
"covering wildcard does not exist");
chase_reply->security = sec_status_bogus;
update_reason_bogus(chase_reply, LDNS_EDE_DNSSEC_BOGUS);
/* Be lenient with RCODE in NSEC NameError responses */
validate_nodata_response(env, ve, qchase, chase_reply, kkey);
if (chase_reply->security == sec_status_secure)
@@ -1138,6 +1163,7 @@ validate_any_response(struct module_env* env, struct val_env* ve,
if(qchase->qtype != LDNS_RR_TYPE_ANY) {
log_err("internal error: ANY validation called for non-ANY");
chase_reply->security = sec_status_bogus;
update_reason_bogus(chase_reply, LDNS_EDE_DNSSEC_BOGUS);
return;
}
@@ -1154,6 +1180,7 @@ validate_any_response(struct module_env* env, struct val_env* ve,
s->rk.dname, ntohs(s->rk.type),
ntohs(s->rk.rrset_class));
chase_reply->security = sec_status_bogus;
update_reason_bogus(chase_reply, LDNS_EDE_DNSSEC_BOGUS);
return;
}
}
@@ -1208,6 +1235,7 @@ validate_any_response(struct module_env* env, struct val_env* ve,
"expansion and did not prove original data "
"did not exist");
chase_reply->security = sec_status_bogus;
update_reason_bogus(chase_reply, LDNS_EDE_DNSSEC_BOGUS);
return;
}
@@ -1255,6 +1283,7 @@ validate_cname_response(struct module_env* env, struct val_env* ve,
"inconsistent wildcard sigs:", s->rk.dname,
ntohs(s->rk.type), ntohs(s->rk.rrset_class));
chase_reply->security = sec_status_bogus;
update_reason_bogus(chase_reply, LDNS_EDE_DNSSEC_BOGUS);
return;
}
@@ -1267,6 +1296,7 @@ validate_cname_response(struct module_env* env, struct val_env* ve,
"wildcarded DNAME:", s->rk.dname,
ntohs(s->rk.type), ntohs(s->rk.rrset_class));
chase_reply->security = sec_status_bogus;
update_reason_bogus(chase_reply, LDNS_EDE_DNSSEC_BOGUS);
return;
}
@@ -1324,6 +1354,7 @@ validate_cname_response(struct module_env* env, struct val_env* ve,
"expansion and did not prove original data "
"did not exist");
chase_reply->security = sec_status_bogus;
update_reason_bogus(chase_reply, LDNS_EDE_DNSSEC_BOGUS);
return;
}
@@ -1424,6 +1455,7 @@ validate_cname_noanswer_response(struct module_env* env, struct val_env* ve,
verbose(VERB_QUERY, "CNAMEchain to noanswer proves that name "
"exists and not exists, bogus");
chase_reply->security = sec_status_bogus;
update_reason_bogus(chase_reply, LDNS_EDE_DNSSEC_BOGUS);
return;
}
if(!nodata_valid_nsec && !nxdomain_valid_nsec && nsec3s_seen) {
@@ -1449,6 +1481,7 @@ validate_cname_noanswer_response(struct module_env* env, struct val_env* ve,
if(verbosity >= VERB_ALGO)
log_dns_msg("Failed CNAMEnoanswer", qchase, chase_reply);
chase_reply->security = sec_status_bogus;
update_reason_bogus(chase_reply, LDNS_EDE_DNSSEC_BOGUS);
return;
}
@@ -1492,6 +1525,10 @@ processInit(struct module_qstate* qstate, struct val_qstate* vq,
verbose(VERB_ALGO, "restart count exceeded");
return val_error(qstate, id);
}
/* correctly initialize reason_bogus */
update_reason_bogus(vq->chase_reply, LDNS_EDE_DNSSEC_BOGUS);
verbose(VERB_ALGO, "validator classification %s",
val_classification_to_string(subtype));
if(subtype == VAL_CLASS_REFERRAL &&
@@ -1557,6 +1594,7 @@ processInit(struct module_qstate* qstate, struct val_qstate* vq,
verbose(VERB_QUERY, "unsigned parent zone denies"
" trust anchor, indeterminate");
vq->chase_reply->security = sec_status_indeterminate;
update_reason_bogus(vq->chase_reply, LDNS_EDE_DNSSEC_INDETERMINATE);
vq->state = VAL_FINISHED_STATE;
return 1;
}
@@ -1588,6 +1626,7 @@ processInit(struct module_qstate* qstate, struct val_qstate* vq,
if(vq->key_entry == NULL && anchor == NULL) {
/*response isn't under a trust anchor, so we cannot validate.*/
vq->chase_reply->security = sec_status_indeterminate;
update_reason_bogus(vq->chase_reply, LDNS_EDE_DNSSEC_INDETERMINATE);
/* go to finished state to cache this result */
vq->state = VAL_FINISHED_STATE;
return 1;
@@ -1633,16 +1672,25 @@ processInit(struct module_qstate* qstate, struct val_qstate* vq,
vq->state = VAL_FINISHED_STATE;
return 1;
} else if(key_entry_isbad(vq->key_entry)) {
sldns_ede_code ede = LDNS_EDE_DNSSEC_BOGUS;
/* the key could have a more spefic EDE than just bogus */
if(key_entry_get_reason_bogus(vq->key_entry) != LDNS_EDE_NONE) {
ede = key_entry_get_reason_bogus(vq->key_entry);
}
/* key is bad, chain is bad, reply is bogus */
errinf_dname(qstate, "key for validation", vq->key_entry->name);
errinf(qstate, "is marked as invalid");
errinf_ede(qstate, "is marked as invalid", ede);
if(key_entry_get_reason(vq->key_entry)) {
errinf(qstate, "because of a previous");
errinf(qstate, key_entry_get_reason(vq->key_entry));
}
/* no retries, stop bothering the authority until timeout */
vq->restart_count = ve->max_restart;
vq->chase_reply->security = sec_status_bogus;
update_reason_bogus(vq->chase_reply, ede);
vq->state = VAL_FINISHED_STATE;
return 1;
}
@@ -1713,9 +1761,10 @@ processFindKey(struct module_qstate* qstate, struct val_qstate* vq, int id)
vq->empty_DS_name) == 0) {
/* do not query for empty_DS_name again */
verbose(VERB_ALGO, "Cannot retrieve DS for signature");
errinf(qstate, "no signatures");
errinf_ede(qstate, "no signatures", LDNS_EDE_RRSIGS_MISSING);
errinf_origin(qstate, qstate->reply_origin);
vq->chase_reply->security = sec_status_bogus;
update_reason_bogus(vq->chase_reply, LDNS_EDE_RRSIGS_MISSING);
vq->state = VAL_FINISHED_STATE;
return 1;
}
@@ -1848,7 +1897,10 @@ processValidate(struct module_qstate* qstate, struct val_qstate* vq,
"of trust to keys for", vq->key_entry->name,
LDNS_RR_TYPE_DNSKEY, vq->key_entry->key_class);
vq->chase_reply->security = sec_status_bogus;
errinf(qstate, "while building chain of trust");
update_reason_bogus(vq->chase_reply, LDNS_EDE_DNSKEY_MISSING);
errinf_ede(qstate, "while building chain of trust",
LDNS_EDE_DNSKEY_MISSING);
if(vq->restart_count >= ve->max_restart)
key_cache_insert(ve->kcache, vq->key_entry, qstate);
return 1;
@@ -1861,9 +1913,10 @@ processValidate(struct module_qstate* qstate, struct val_qstate* vq,
"signer name", &vq->qchase);
verbose(VERB_DETAIL, "Could not establish validation of "
"INSECURE status of unsigned response.");
errinf(qstate, "no signatures");
errinf_ede(qstate, "no signatures", LDNS_EDE_RRSIGS_MISSING);
errinf_origin(qstate, qstate->reply_origin);
vq->chase_reply->security = sec_status_bogus;
update_reason_bogus(vq->chase_reply, LDNS_EDE_RRSIGS_MISSING);
return 1;
}
subtype = val_classify_response(qstate->query_flags, &qstate->qinfo,
@@ -2001,17 +2054,20 @@ processFinished(struct module_qstate* qstate, struct val_qstate* vq,
vq->orig_msg->rep, vq->rrset_skip);
/* store overall validation result in orig_msg */
if(vq->rrset_skip == 0)
if(vq->rrset_skip == 0) {
vq->orig_msg->rep->security = vq->chase_reply->security;
else if(subtype != VAL_CLASS_REFERRAL ||
update_reason_bogus(vq->orig_msg->rep, vq->chase_reply->reason_bogus);
} else if(subtype != VAL_CLASS_REFERRAL ||
vq->rrset_skip < vq->orig_msg->rep->an_numrrsets +
vq->orig_msg->rep->ns_numrrsets) {
/* ignore sec status of additional section if a referral
* type message skips there and
* use the lowest security status as end result. */
if(vq->chase_reply->security < vq->orig_msg->rep->security)
if(vq->chase_reply->security < vq->orig_msg->rep->security) {
vq->orig_msg->rep->security =
vq->chase_reply->security;
update_reason_bogus(vq->orig_msg->rep, vq->chase_reply->reason_bogus);
}
}
if(subtype == VAL_CLASS_REFERRAL) {
@@ -2034,6 +2090,7 @@ processFinished(struct module_qstate* qstate, struct val_qstate* vq,
&vq->rrset_skip)) {
verbose(VERB_ALGO, "validator: failed to chase CNAME");
vq->orig_msg->rep->security = sec_status_bogus;
update_reason_bogus(vq->orig_msg->rep, LDNS_EDE_DNSSEC_BOGUS);
} else {
/* restart process for new qchase at rrset_skip */
log_query_info(VERB_ALGO, "validator: chased to",
@@ -2247,9 +2304,11 @@ val_operate(struct module_qstate* qstate, enum module_ev event, int id,
* queries. If we get here, it is bogus or an internal error */
if(qstate->qinfo.qclass == LDNS_RR_CLASS_ANY) {
verbose(VERB_ALGO, "cannot validate classANY: bogus");
if(qstate->return_msg)
if(qstate->return_msg) {
qstate->return_msg->rep->security =
sec_status_bogus;
update_reason_bogus(qstate->return_msg->rep, LDNS_EDE_DNSSEC_BOGUS);
}
qstate->ext_state[id] = module_finished;
return;
}
@@ -2304,6 +2363,7 @@ primeResponseToKE(struct ub_packed_rrset_key* dnskey_rrset,
struct key_entry_key* kkey = NULL;
enum sec_status sec = sec_status_unchecked;
char* reason = NULL;
sldns_ede_code reason_bogus = LDNS_EDE_DNSSEC_BOGUS;
int downprot = qstate->env->cfg->harden_algo_downgrade;
if(!dnskey_rrset) {
@@ -2311,7 +2371,7 @@ primeResponseToKE(struct ub_packed_rrset_key* dnskey_rrset,
"could not fetch DNSKEY rrset",
ta->name, LDNS_RR_TYPE_DNSKEY, ta->dclass);
if(qstate->env->cfg->harden_dnssec_stripped) {
errinf(qstate, "no DNSKEY rrset");
errinf_ede(qstate, "no DNSKEY rrset", LDNS_EDE_DNSKEY_MISSING);
kkey = key_entry_create_bad(qstate->region, ta->name,
ta->namelen, ta->dclass, BOGUS_KEY_TTL,
*qstate->env->now);
@@ -2327,7 +2387,7 @@ primeResponseToKE(struct ub_packed_rrset_key* dnskey_rrset,
/* 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, qstate);
&reason, &reason_bogus, qstate);
if(!kkey) {
log_err("out of memory: verifying prime TA");
return NULL;
@@ -2346,7 +2406,7 @@ primeResponseToKE(struct ub_packed_rrset_key* dnskey_rrset,
/* NOTE: in this case, we should probably reject the trust
* anchor for longer, perhaps forever. */
if(qstate->env->cfg->harden_dnssec_stripped) {
errinf(qstate, reason);
errinf_ede(qstate, reason, reason_bogus);
kkey = key_entry_create_bad(qstate->region, ta->name,
ta->namelen, ta->dclass, BOGUS_KEY_TTL,
*qstate->env->now);
@@ -2389,6 +2449,7 @@ ds_response_to_ke(struct module_qstate* qstate, struct val_qstate* vq,
{
struct val_env* ve = (struct val_env*)qstate->env->modinfo[id];
char* reason = NULL;
sldns_ede_code reason_bogus = LDNS_EDE_DNSSEC_BOGUS;
enum val_classification subtype;
if(rcode != LDNS_RCODE_NOERROR) {
char rc[16];
@@ -2397,7 +2458,8 @@ ds_response_to_ke(struct module_qstate* qstate, struct val_qstate* vq,
/* errors here pretty much break validation */
verbose(VERB_DETAIL, "DS response was error, thus bogus");
errinf(qstate, rc);
errinf(qstate, "no DS");
errinf_ede(qstate, "no DS", LDNS_EDE_NETWORK_ERROR);
goto return_bogus;
}
@@ -2411,17 +2473,17 @@ ds_response_to_ke(struct module_qstate* qstate, struct val_qstate* vq,
if(!ds) {
log_warn("internal error: POSITIVE DS response was "
"missing DS.");
errinf(qstate, "no DS record");
errinf_ede(qstate, "no DS record", LDNS_EDE_DNSSEC_BOGUS);
goto return_bogus;
}
/* Verify only returns BOGUS or SECURE. If the rrset is
* bogus, then we are done. */
sec = val_verify_rrset_entry(qstate->env, ve, ds,
vq->key_entry, &reason, LDNS_SECTION_ANSWER, qstate);
sec = val_verify_rrset_entry(qstate->env, ve, ds,
vq->key_entry, &reason, &reason_bogus, LDNS_SECTION_ANSWER, qstate);
if(sec != sec_status_secure) {
verbose(VERB_DETAIL, "DS rrset in DS response did "
"not verify");
errinf(qstate, reason);
errinf_ede(qstate, reason, reason_bogus);
goto return_bogus;
}
@@ -2430,6 +2492,9 @@ ds_response_to_ke(struct module_qstate* qstate, struct val_qstate* vq,
if(!val_dsset_isusable(ds)) {
/* If they aren't usable, then we treat it like
* there was no DS. */
// @TODO add EDE Unsupported DS Digest Type
*ke = key_entry_create_null(qstate->region,
qinfo->qname, qinfo->qname_len, qinfo->qclass,
ub_packed_rrset_ttl(ds), *qstate->env->now);
@@ -2452,7 +2517,7 @@ ds_response_to_ke(struct module_qstate* qstate, struct val_qstate* vq,
/* make sure there are NSECs or NSEC3s with signatures */
if(!val_has_signed_nsecs(msg->rep, &reason)) {
verbose(VERB_ALGO, "no NSECs: %s", reason);
errinf(qstate, reason);
errinf_ede(qstate, reason, LDNS_EDE_NSEC_MISSING);
goto return_bogus;
}
@@ -2493,7 +2558,7 @@ ds_response_to_ke(struct module_qstate* qstate, struct val_qstate* vq,
sec = nsec3_prove_nods(qstate->env, ve,
msg->rep->rrsets + msg->rep->an_numrrsets,
msg->rep->ns_numrrsets, qinfo, vq->key_entry, &reason,
qstate);
&reason_bogus, qstate);
switch(sec) {
case sec_status_insecure:
/* case insecure also continues to unsigned
@@ -2515,7 +2580,7 @@ ds_response_to_ke(struct module_qstate* qstate, struct val_qstate* vq,
case sec_status_bogus:
verbose(VERB_DETAIL, "NSEC3s for the "
"referral did not prove no DS.");
errinf(qstate, reason);
errinf_ede(qstate, reason, reason_bogus);
goto return_bogus;
case sec_status_unchecked:
default:
@@ -2554,7 +2619,7 @@ ds_response_to_ke(struct module_qstate* qstate, struct val_qstate* vq,
goto return_bogus;
}
sec = val_verify_rrset_entry(qstate->env, ve, cname,
vq->key_entry, &reason, LDNS_SECTION_ANSWER, qstate);
vq->key_entry, &reason, NULL, LDNS_SECTION_ANSWER, qstate);
if(sec == sec_status_secure) {
verbose(VERB_ALGO, "CNAME validated, "
"proof that DS does not exist");
@@ -2685,6 +2750,7 @@ process_dnskey_response(struct module_qstate* qstate, struct val_qstate* vq,
struct ub_packed_rrset_key* dnskey = NULL;
int downprot;
char* reason = NULL;
sldns_ede_code reason_bogus = LDNS_EDE_DNSSEC_BOGUS;
if(rcode == LDNS_RCODE_NOERROR)
dnskey = reply_find_answer_rrset(qinfo, msg->rep);
@@ -2693,6 +2759,7 @@ process_dnskey_response(struct module_qstate* qstate, struct val_qstate* vq,
/* bad response */
verbose(VERB_DETAIL, "Missing DNSKEY RRset in response to "
"DNSKEY query.");
if(vq->restart_count < ve->max_restart) {
val_blacklist(&vq->chain_blacklist, qstate->region,
origin, 1);
@@ -2707,7 +2774,7 @@ process_dnskey_response(struct module_qstate* qstate, struct val_qstate* vq,
log_err("alloc failure in missing dnskey response");
/* key_entry is NULL for failure in Validate */
}
errinf(qstate, "No DNSKEY record");
errinf_ede(qstate, "No DNSKEY record", LDNS_EDE_DNSKEY_MISSING);
errinf_origin(qstate, origin);
errinf_dname(qstate, "for key", qinfo->qname);
vq->state = VAL_VALIDATE_STATE;
@@ -2721,7 +2788,7 @@ process_dnskey_response(struct module_qstate* qstate, struct val_qstate* vq,
}
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, qstate);
ve, dnskey, vq->ds_rrset, downprot, &reason, &reason_bogus, qstate);
if(!vq->key_entry) {
log_err("out of memory in verify new DNSKEYs");
@@ -2742,7 +2809,7 @@ process_dnskey_response(struct module_qstate* qstate, struct val_qstate* vq,
}
verbose(VERB_DETAIL, "Did not match a DS to a DNSKEY, "
"thus bogus.");
errinf(qstate, reason);
errinf_ede(qstate, reason, reason_bogus);
errinf_origin(qstate, origin);
errinf_dname(qstate, "for key", qinfo->qname);
}