mirror of
https://github.com/NLnetLabs/unbound.git
synced 2026-09-30 21:54:57 +02:00
Add the basic EDE (RFC8914) cases (#604)
This commit is contained in:
@@ -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);
|
||||
}
|
||||
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user