leeway = 0;
lock_rw_unlock(&e->lock);
+ // @TODO test this
// // stale answer?
// if (worker->env.cfg->serve_expired &&
// *worker->env.now >= ((struct reply_info*)e->data)->ttl) {
- // // EDE Error Code 3 - Stale Answer
- // EDNS_OPT_LIST_APPEND_EDE(&edns.opt_list_out, worker->scratchpad,
- // LDNS_EDE_STALE_ANSWER, "");
+ // EDNS_OPT_LIST_APPEND_EDE(&edns.opt_list_out,
+ // worker->scratchpad, LDNS_EDE_STALE_ANSWER, "");
// }
// add EDNS struct?
return local_encode(qinfo, env, edns, repinfo, buf, temp, &r, 1,
LDNS_RCODE_NOERROR);
}
- // @TODO add EDE?
- return local_encode(qinfo, env, edns, repinfo, buf, temp, lr->rrset, 1,
- LDNS_RCODE_NOERROR);
+ return local_encode_ede(z, qinfo, env, edns, repinfo, buf, temp, lr->rrset, 1,
+ LDNS_RCODE_NOERROR, LDNS_EDE_FORGED_ANSWER, "", do_ede);
}
/**
if(!inplace_cb_reply_servfail_call(m->s.env, &m->s.qinfo, &m->s,
rep, LDNS_RCODE_SERVFAIL, &r->edns, &r->query_reply, m->s.region, &r->start_time))
r->edns.opt_list_inplace_cb_out = NULL;
- // @TODO EDE?
+ /* internal server error (probably malloc failure) so no
+ * EDE (RFC8914) needed */
error_encode(r_buffer, LDNS_RCODE_SERVFAIL,
&m->s.qinfo, r->qid, r->qflags, &r->edns);
}
int info_code = get_ede_info_code(query_pkt, len);
if(info_code == -1 ||
(uint16_t)info_code != p->ede_info_code) {
- verbose(3, "bad EDE INFO-CODE\n");
+ verbose(3, "bad EDE INFO-CODE. Expected: %d, and got: %d\n",
+ p->ede_info_code, info_code);
continue;
}
}
; recursion happens here.
STEP 10 CHECK_ANSWER
ENTRY_BEGIN
-MATCH all_noedns ede=6
+MATCH all_noedns ede=7
REPLY QR RD RA DO SERVFAIL
SECTION QUESTION
www.sub.example.com. IN A
; recursion happens here.
STEP 10 CHECK_ANSWER
ENTRY_BEGIN
-MATCH all_noedns ede=6
+MATCH all_noedns ede=7
REPLY QR RD RA DO SERVFAIL
SECTION QUESTION
www.sub.example.com. IN A
; recursion happens here.
STEP 10 CHECK_ANSWER
ENTRY_BEGIN
-MATCH all_noedns ede=6
+MATCH all_noedns ede=7
REPLY QR RD RA DO SERVFAIL
SECTION QUESTION
www.example.com. IN A
; recursion happens here.
STEP 10 CHECK_ANSWER
ENTRY_BEGIN
-MATCH all_noedns ede=6
+MATCH all_noedns ede=12
REPLY QR RD RA DO SERVFAIL
SECTION QUESTION
ns1.example. IN MX
; recursion happens here.
STEP 10 CHECK_ANSWER
ENTRY_BEGIN
-MATCH all_noedns ede=6
+MATCH all_noedns ede=10
REPLY QR RD RA DO SERVFAIL
SECTION QUESTION
www.sub.example.com. IN A
* This string is malloced and has to be freed by caller.
*/
char* errinf_to_str_bogus(struct module_qstate* qstate);
-
-// @TODO write this
+/**
+ * Check the sldns_ede_code of the qstate.
+ * @param qstate: query state.
+ * @return LDNS_EDE_DNSSEC_BOGUS by default, or another sldns_ede_code
+ * if this is set.
+ */
sldns_ede_code errinf_to_reason_bogus(struct module_qstate* qstate);
/**
reason, NULL, section, qstate);
}
+static enum sec_status
+dnskey_verify_rrset_sig_ede(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, sldns_ede_code *reason_bogus,
+ sldns_pkt_section section, struct module_qstate* qstate);
+
enum sec_status
dnskey_verify_rrset_ede(struct module_env* env, struct val_env* ve,
struct ub_packed_rrset_key* rrset, struct ub_packed_rrset_key* dnskey,
tag != rrset_get_sig_keytag(rrset, i))
continue;
buf_canon = 0;
- // @TODO should this be _ede verion as well?
- sec = dnskey_verify_rrset_sig(env->scratch,
+ sec = dnskey_verify_rrset_sig_ede(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 ++;
return sec_status_bogus;
}
-static enum sec_status
-dnskey_verify_rrset_sig_ede(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, sldns_ede_code *reason_bogus,
- 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,
int buf_canon = 0;
verbose(VERB_ALGO, "verify sig %d %d", (int)tag, algo);
if(!dnskey_algo_id_is_supported(algo)) {
- // @TODO do we do LDNS_EDE_UNSUPPORTED_DNSKEY_ALG here?
- // if (reason_bogus)
- // *reason_bogus = LDNS_EDE_UNSUPPORTED_DNSKEY_ALG;
+ if (reason_bogus)
+ *reason_bogus = LDNS_EDE_UNSUPPORTED_DNSKEY_ALG;
verbose(VERB_QUERY, "verify sig: unknown algorithm");
return sec_status_insecure;
}
}
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;
}
sigdate_error("verify: inception after expiration, "
"signature bad", expi, incep, now);
*reason = "signature inception after expiration";
- /* @TODO Tom, wat hier te doen? */
+ 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(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;
}
/* 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;
}
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);
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;
}
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;
}
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;
}
if(!has_useful_ds) {
verbose(VERB_ALGO, "No usable DS records were found -- "
"treating as insecure.");
- // @TODO add ede DNSSEC Indeterminate?
- return sec_status_insecure;
+ return sec_status_insecure;
}
/* If any were understandable, then it is bad. */
verbose(VERB_QUERY, "Failed to match any usable DS to a DNSKEY.");
else snprintf(aerr, sizeof(aerr), "%d",
(int)ds_get_key_algo(ds_rrset, i));
- // @TODO do we want to add EDE Unsupported DS Digest Type here?
-
verbose(VERB_ALGO, "DS unsupported, hash %s %s, "
"key algorithm %s %s", herr,
(ds_digest_algo_is_supported(ds_rrset, 0)?
/* 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);
verbose(VERB_QUERY, "unsigned parent zone denies"
" trust anchor, indeterminate");
vq->chase_reply->security = sec_status_indeterminate;
+ vq->chase_reply->reason_bogus = LDNS_EDE_DNSSEC_INDETERMINATE;
vq->state = VAL_FINISHED_STATE;
return 1;
}
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;
+ vq->chase_reply->reason_bogus = LDNS_EDE_DNSSEC_INDETERMINATE;
/* go to finished state to cache this result */
vq->state = VAL_FINISHED_STATE;
return 1;
return 1;
} else if(key_entry_isbad(vq->key_entry)) {
/* key is bad, chain is bad, reply is bogus */
-
- // @TODO ADD Error Code 6 - DNSSEC Bogus + text chain of trust?
-
errinf_dname(qstate, "key for validation", vq->key_entry->name);
- errinf(qstate, "is marked as invalid");
+ errinf_ede(qstate, "is marked as invalid", LDNS_EDE_DNSSEC_BOGUS);
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;
+ vq->chase_reply->reason_bogus = LDNS_EDE_DNSSEC_BOGUS;
vq->state = VAL_FINISHED_STATE;
return 1;
}
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");
- vq->chase_reply->reason_bogus = LDNS_EDE_RRSIGS_MISSING;
+ errinf_ede(qstate, "no signatures", LDNS_EDE_RRSIGS_MISSING);
errinf_origin(qstate, qstate->reply_origin);
vq->chase_reply->security = sec_status_bogus;
- // @TODO add EDE 10 - RRSIGs Missing
+ vq->chase_reply->reason_bogus = LDNS_EDE_RRSIGS_MISSING;
vq->state = VAL_FINISHED_STATE;
return 1;
}
"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");
-
- // @TODO ADD Error Code 6 - DNSSEC Bogus + text chain of trust?
-
+ vq->chase_reply->reason_bogus = LDNS_EDE_DNSSEC_BOGUS;
+ errinf_ede(qstate, "while building chain of trust",
+ LDNS_EDE_DNSSEC_BOGUS);
if(vq->restart_count >= ve->max_restart)
key_cache_insert(ve->kcache, vq->key_entry, qstate);
return 1;
"signer name", &vq->qchase);
verbose(VERB_DETAIL, "Could not establish validation of "
"INSECURE status of unsigned response.");
- errinf(qstate, "no signatures");
- vq->chase_reply->reason_bogus = LDNS_EDE_RRSIGS_MISSING;
+ errinf_ede(qstate, "no signatures", LDNS_EDE_RRSIGS_MISSING);
errinf_origin(qstate, qstate->reply_origin);
vq->chase_reply->security = sec_status_bogus;
+ vq->chase_reply->reason_bogus = LDNS_EDE_RRSIGS_MISSING;
return 1;
}
subtype = val_classify_response(qstate->query_flags, &qstate->qinfo,
/* 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,
{
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];
/* 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", reason_bogus);
goto return_bogus;
}
if(!ds) {
log_warn("internal error: POSITIVE DS response was "
"missing DS.");
- errinf(qstate, "no DS record");
+ errinf_ede(qstate, "no DS record", reason_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_ede(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;
}
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);
/* 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;
}
goto return_bogus;
}
return_bogus:
-
- // @TODO add EDE NSEC MISSING
-
*ke = key_entry_create_bad(qstate->region, qinfo->qname,
qinfo->qname_len, qinfo->qclass,
BOGUS_KEY_TTL, *qstate->env->now);
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);
verbose(VERB_DETAIL, "Missing DNSKEY RRset in response to "
"DNSKEY query.");
- // @TODO add EDE 9 - DNSKEY Missing
+ reason_bogus = LDNS_EDE_DNSKEY_MISSING;
if(vq->restart_count < ve->max_restart) {
val_blacklist(&vq->chain_blacklist, qstate->region,
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", reason_bogus);
errinf_origin(qstate, origin);
errinf_dname(qstate, "for key", qinfo->qname);
vq->state = VAL_VALIDATE_STATE;
return;
}
downprot = qstate->env->cfg->harden_algo_downgrade;
- // @TODO add _ede
- vq->key_entry = val_verify_new_DNSKEYs(qstate->region, qstate->env,
- ve, dnskey, vq->ds_rrset, downprot, &reason, qstate);
+ vq->key_entry = val_verify_new_DNSKEYs_ede(qstate->region, qstate->env,
+ ve, dnskey, vq->ds_rrset, downprot, &reason, &reason_bogus, qstate);
if(!vq->key_entry) {
log_err("out of memory in verify new DNSKEYs");
}
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);
}