aboutsummaryrefslogtreecommitdiff
path: root/validator
diff options
context:
space:
mode:
authorDag-Erling Smørgrav <des@FreeBSD.org>2018-05-12 11:54:35 +0000
committerDag-Erling Smørgrav <des@FreeBSD.org>2018-05-12 11:54:35 +0000
commit15de2de8449b4f5063f93578ae68aa0bc79a205c (patch)
treef0a7e3230212205e7ff88a2900de97026940f63c /validator
parent689b65913bba5320ef50befddf4743c6dafde873 (diff)
Vendor import of Unbound 1.6.4.vendor/unbound/1.6.4
Diffstat (limited to 'validator')
-rw-r--r--validator/val_secalgo.c51
-rw-r--r--validator/val_utils.c5
-rw-r--r--validator/val_utils.h4
-rw-r--r--validator/validator.c142
-rw-r--r--validator/validator.h13
5 files changed, 170 insertions, 45 deletions
diff --git a/validator/val_secalgo.c b/validator/val_secalgo.c
index be88ff438660..88d23472118f 100644
--- a/validator/val_secalgo.c
+++ b/validator/val_secalgo.c
@@ -228,6 +228,9 @@ dnskey_algo_id_is_supported(int id)
case LDNS_ECDSAP256SHA256:
case LDNS_ECDSAP384SHA384:
#endif
+#ifdef USE_ED25519
+ case LDNS_ED25519:
+#endif
#if (defined(HAVE_EVP_SHA256) && defined(USE_SHA2)) || (defined(HAVE_EVP_SHA512) && defined(USE_SHA2)) || defined(USE_ECDSA)
return 1;
#endif
@@ -555,6 +558,17 @@ setup_key_digest(int algo, EVP_PKEY** evp_key, const EVP_MD** digest_type,
#endif
break;
#endif /* USE_ECDSA */
+#ifdef USE_ED25519
+ case LDNS_ED25519:
+ *evp_key = sldns_ed255192pkey_raw(key, keylen);
+ if(!*evp_key) {
+ verbose(VERB_QUERY, "verify: "
+ "sldns_ed255192pkey_raw failed");
+ return 0;
+ }
+ *digest_type = NULL;
+ break;
+#endif /* USE_ED25519 */
default:
verbose(VERB_QUERY, "verify: unknown algorithm %d",
algo);
@@ -644,18 +658,29 @@ verify_canonrrset(sldns_buffer* buf, int algo, unsigned char* sigblock,
else if(docrypto_free) OPENSSL_free(sigblock);
return sec_status_unchecked;
}
- if(EVP_VerifyInit(ctx, digest_type) == 0) {
- verbose(VERB_QUERY, "verify: EVP_VerifyInit failed");
+#ifndef HAVE_EVP_DIGESTVERIFY
+ if(EVP_DigestInit(ctx, digest_type) == 0) {
+ verbose(VERB_QUERY, "verify: EVP_DigestInit failed");
+#ifdef HAVE_EVP_MD_CTX_NEW
EVP_MD_CTX_destroy(ctx);
+#else
+ EVP_MD_CTX_cleanup(ctx);
+ free(ctx);
+#endif
EVP_PKEY_free(evp_key);
if(dofree) free(sigblock);
else if(docrypto_free) OPENSSL_free(sigblock);
return sec_status_unchecked;
}
- if(EVP_VerifyUpdate(ctx, (unsigned char*)sldns_buffer_begin(buf),
+ if(EVP_DigestUpdate(ctx, (unsigned char*)sldns_buffer_begin(buf),
(unsigned int)sldns_buffer_limit(buf)) == 0) {
- verbose(VERB_QUERY, "verify: EVP_VerifyUpdate failed");
+ verbose(VERB_QUERY, "verify: EVP_DigestUpdate failed");
+#ifdef HAVE_EVP_MD_CTX_NEW
EVP_MD_CTX_destroy(ctx);
+#else
+ EVP_MD_CTX_cleanup(ctx);
+ free(ctx);
+#endif
EVP_PKEY_free(evp_key);
if(dofree) free(sigblock);
else if(docrypto_free) OPENSSL_free(sigblock);
@@ -663,6 +688,24 @@ verify_canonrrset(sldns_buffer* buf, int algo, unsigned char* sigblock,
}
res = EVP_VerifyFinal(ctx, sigblock, sigblock_len, evp_key);
+#else /* HAVE_EVP_DIGESTVERIFY */
+ if(EVP_DigestVerifyInit(ctx, NULL, digest_type, NULL, evp_key) == 0) {
+ verbose(VERB_QUERY, "verify: EVP_DigestVerifyInit failed");
+#ifdef HAVE_EVP_MD_CTX_NEW
+ EVP_MD_CTX_destroy(ctx);
+#else
+ EVP_MD_CTX_cleanup(ctx);
+ free(ctx);
+#endif
+ EVP_PKEY_free(evp_key);
+ if(dofree) free(sigblock);
+ else if(docrypto_free) OPENSSL_free(sigblock);
+ return sec_status_unchecked;
+ }
+ res = EVP_DigestVerify(ctx, sigblock, sigblock_len,
+ (unsigned char*)sldns_buffer_begin(buf),
+ sldns_buffer_limit(buf));
+#endif
#ifdef HAVE_EVP_MD_CTX_NEW
EVP_MD_CTX_destroy(ctx);
#else
diff --git a/validator/val_utils.c b/validator/val_utils.c
index e3677e1d9ceb..e4eff1b2523b 100644
--- a/validator/val_utils.c
+++ b/validator/val_utils.c
@@ -54,6 +54,7 @@
#include "util/net_help.h"
#include "util/module.h"
#include "util/regional.h"
+#include "util/config_file.h"
#include "sldns/wire2str.h"
#include "sldns/parseutil.h"
@@ -914,7 +915,7 @@ void val_reply_remove_auth(struct reply_info* rep, size_t index)
}
void
-val_check_nonsecure(struct val_env* ve, struct reply_info* rep)
+val_check_nonsecure(struct module_env* env, struct reply_info* rep)
{
size_t i;
/* authority */
@@ -955,7 +956,7 @@ val_check_nonsecure(struct val_env* ve, struct reply_info* rep)
}
}
/* additional */
- if(!ve->clean_additional)
+ if(!env->cfg->val_clean_additional)
return;
for(i=rep->an_numrrsets+rep->ns_numrrsets; i<rep->rrset_count; i++) {
if(((struct packed_rrset_data*)rep->rrsets[i]->entry.data)
diff --git a/validator/val_utils.h b/validator/val_utils.h
index 051824abaf84..649adc2d6559 100644
--- a/validator/val_utils.h
+++ b/validator/val_utils.h
@@ -306,10 +306,10 @@ void val_reply_remove_auth(struct reply_info* rep, size_t index);
* So that unsigned data does not get let through to clients, when we have
* found the data to be secure.
*
- * @param ve: validator environment with cleaning options.
+ * @param env: environment with cleaning options.
* @param rep: reply to dump all nonsecure stuff out of.
*/
-void val_check_nonsecure(struct val_env* ve, struct reply_info* rep);
+void val_check_nonsecure(struct module_env* env, struct reply_info* rep);
/**
* Mark all unchecked rrset entries not below a trust anchor as indeterminate.
diff --git a/validator/validator.c b/validator/validator.c
index 81ba5fa17ba2..5f4a1eb4ebed 100644
--- a/validator/validator.c
+++ b/validator/validator.c
@@ -60,6 +60,7 @@
#include "util/fptr_wlist.h"
#include "sldns/rrdef.h"
#include "sldns/wire2str.h"
+#include "sldns/str2wire.h"
/* forward decl for cache response and normal super inform calls of a DS */
static void process_ds_response(struct module_qstate* qstate,
@@ -112,8 +113,6 @@ val_apply_cfg(struct module_env* env, struct val_env* val_env,
{
int c;
val_env->bogus_ttl = (uint32_t)cfg->bogus_ttl;
- val_env->clean_additional = cfg->val_clean_additional;
- val_env->permissive_mode = cfg->val_permissive_mode;
if(!env->anchors)
env->anchors = anchors_create();
if(!env->anchors) {
@@ -170,7 +169,6 @@ val_init(struct module_env* env, int id)
}
env->modinfo[id] = (void*)val_env;
env->need_to_validate = 1;
- val_env->permissive_mode = 0;
lock_basic_init(&val_env->bogus_lock);
lock_protect(&val_env->bogus_lock, &val_env->num_rrset_bogus,
sizeof(val_env->num_rrset_bogus));
@@ -364,14 +362,17 @@ already_validated(struct dns_msg* ret_msg)
* @param qtype: query type.
* @param qclass: query class.
* @param flags: additional flags, such as the CD bit (BIT_CD), or 0.
+ * @param newq: If the subquery is newly created, it is returned,
+ * otherwise NULL is returned
+ * @param detached: true if this qstate should not attach to the subquery
* @return false on alloc failure.
*/
static int
generate_request(struct module_qstate* qstate, int id, uint8_t* name,
- size_t namelen, uint16_t qtype, uint16_t qclass, uint16_t flags)
+ size_t namelen, uint16_t qtype, uint16_t qclass, uint16_t flags,
+ struct module_qstate** newq, int detached)
{
struct val_qstate* vq = (struct val_qstate*)qstate->minfo[id];
- struct module_qstate* newq;
struct query_info ask;
int valrec;
ask.qname = name;
@@ -380,22 +381,35 @@ generate_request(struct module_qstate* qstate, int id, uint8_t* name,
ask.qclass = qclass;
ask.local_alias = NULL;
log_query_info(VERB_ALGO, "generate request", &ask);
- fptr_ok(fptr_whitelist_modenv_attach_sub(qstate->env->attach_sub));
/* enable valrec flag to avoid recursion to the same validation
* routine, this lookup is simply a lookup. DLVs need validation */
if(qtype == LDNS_RR_TYPE_DLV)
valrec = 0;
else valrec = 1;
- if(!(*qstate->env->attach_sub)(qstate, &ask,
- (uint16_t)(BIT_RD|flags), 0, valrec, &newq)){
- log_err("Could not generate request: out of memory");
- return 0;
+ if(detached) {
+ struct mesh_state* sub = NULL;
+ fptr_ok(fptr_whitelist_modenv_add_sub(
+ qstate->env->add_sub));
+ if(!(*qstate->env->add_sub)(qstate, &ask,
+ (uint16_t)(BIT_RD|flags), 0, valrec, newq, &sub)){
+ log_err("Could not generate request: out of memory");
+ return 0;
+ }
+ }
+ else {
+ fptr_ok(fptr_whitelist_modenv_attach_sub(
+ qstate->env->attach_sub));
+ if(!(*qstate->env->attach_sub)(qstate, &ask,
+ (uint16_t)(BIT_RD|flags), 0, valrec, newq)){
+ log_err("Could not generate request: out of memory");
+ return 0;
+ }
}
/* newq; validator does not need state created for that
* query, and its a 'normal' for iterator as well */
- if(newq) {
+ if(*newq) {
/* add our blacklist to the query blacklist */
- sock_list_merge(&newq->blacklist, newq->region,
+ sock_list_merge(&(*newq)->blacklist, (*newq)->region,
vq->chain_blacklist);
}
qstate->ext_state[id] = module_wait_subquery;
@@ -403,6 +417,66 @@ generate_request(struct module_qstate* qstate, int id, uint8_t* name,
}
/**
+ * Generate, send and detach key tag signaling query.
+ *
+ * @param qstate: query state.
+ * @param id: module id.
+ * @param ta: trust anchor, locked.
+ * @return false on a processing error.
+ */
+static int
+generate_keytag_query(struct module_qstate* qstate, int id,
+ struct trust_anchor* ta)
+{
+ /* 3 bytes for "_ta", 5 bytes per tag (4 bytes + "-") */
+#define MAX_LABEL_TAGS (LDNS_MAX_LABELLEN-3)/5
+ size_t i, numtag;
+ uint16_t tags[MAX_LABEL_TAGS];
+ char tagstr[LDNS_MAX_LABELLEN+1] = "_ta"; /* +1 for NULL byte */
+ size_t tagstr_left = sizeof(tagstr) - strlen(tagstr);
+ char* tagstr_pos = tagstr + strlen(tagstr);
+ uint8_t dnamebuf[LDNS_MAX_DOMAINLEN+1]; /* +1 for label length byte */
+ size_t dnamebuf_len = sizeof(dnamebuf);
+ uint8_t* keytagdname;
+ struct module_qstate* newq = NULL;
+ enum module_ext_state ext_state = qstate->ext_state[id];
+
+ numtag = anchor_list_keytags(ta, tags, MAX_LABEL_TAGS);
+ if(numtag == 0)
+ return 0;
+
+ for(i=0; i<numtag; i++) {
+ /* Buffer can't overflow; numtag is limited to tags that fit in
+ * the buffer. */
+ snprintf(tagstr_pos, tagstr_left, "-%04x", (unsigned)tags[i]);
+ tagstr_left -= strlen(tagstr_pos);
+ tagstr_pos += strlen(tagstr_pos);
+ }
+
+ sldns_str2wire_dname_buf_origin(tagstr, dnamebuf, &dnamebuf_len,
+ ta->name, ta->namelen);
+ if(!(keytagdname = (uint8_t*)regional_alloc_init(qstate->region,
+ dnamebuf, dnamebuf_len))) {
+ log_err("could not generate key tag query: out of memory");
+ return 0;
+ }
+
+ log_nametypeclass(VERB_ALGO, "keytag query", keytagdname,
+ LDNS_RR_TYPE_NULL, ta->dclass);
+ if(!generate_request(qstate, id, keytagdname, dnamebuf_len,
+ LDNS_RR_TYPE_NULL, ta->dclass, 0, &newq, 1)) {
+ log_err("failed to generate key tag signaling request");
+ return 0;
+ }
+
+ /* Not interrested in subquery response. Restore the ext_state,
+ * that might be changed by generate_request() */
+ qstate->ext_state[id] = ext_state;
+
+ return 1;
+}
+
+/**
* Prime trust anchor for use.
* Generate and dispatch a priming query for the given trust anchor.
* The trust anchor can be DNSKEY or DS and does not have to be signed.
@@ -417,8 +491,16 @@ static int
prime_trust_anchor(struct module_qstate* qstate, struct val_qstate* vq,
int id, struct trust_anchor* toprime)
{
+ struct module_qstate* newq = NULL;
int ret = generate_request(qstate, id, toprime->name, toprime->namelen,
- LDNS_RR_TYPE_DNSKEY, toprime->dclass, BIT_CD);
+ LDNS_RR_TYPE_DNSKEY, toprime->dclass, BIT_CD, &newq, 0);
+
+ if(newq && qstate->env->cfg->trust_anchor_signaling &&
+ !generate_keytag_query(qstate, id, toprime)) {
+ log_err("keytag signaling query failed");
+ return 0;
+ }
+
if(!ret) {
log_err("Could not prime trust anchor: out of memory");
return 0;
@@ -534,9 +616,11 @@ validate_msg_signatures(struct module_qstate* qstate, struct module_env* env,
}
}
- /* attempt to validate the ADDITIONAL section rrsets */
- if(!ve->clean_additional)
+ /* If set, the validator should clean the additional section of
+ * secure messages. */
+ if(!env->cfg->val_clean_additional)
return 1;
+ /* attempt to validate the ADDITIONAL section rrsets */
for(i=chase_reply->an_numrrsets+chase_reply->ns_numrrsets;
i<chase_reply->rrset_count; i++) {
s = chase_reply->rrsets[i];
@@ -1510,6 +1594,7 @@ processFindKey(struct module_qstate* qstate, struct val_qstate* vq, int id)
uint8_t* target_key_name, *current_key_name;
size_t target_key_len;
int strip_lab;
+ struct module_qstate* newq = NULL;
log_query_info(VERB_ALGO, "validator: FindKey", &vq->qchase);
/* We know that state.key_entry is not 0 or bad key -- if it were,
@@ -1522,7 +1607,7 @@ processFindKey(struct module_qstate* qstate, struct val_qstate* vq, int id)
if(key_entry_isnull(vq->key_entry)) {
if(!generate_request(qstate, id, vq->ds_rrset->rk.dname,
vq->ds_rrset->rk.dname_len, LDNS_RR_TYPE_DNSKEY,
- vq->qchase.qclass, BIT_CD)) {
+ vq->qchase.qclass, BIT_CD, &newq, 0)) {
log_err("mem error generating DNSKEY request");
return val_error(qstate, id);
}
@@ -1594,7 +1679,7 @@ processFindKey(struct module_qstate* qstate, struct val_qstate* vq, int id)
vq->key_entry->name) != 0) {
if(!generate_request(qstate, id, vq->ds_rrset->rk.dname,
vq->ds_rrset->rk.dname_len, LDNS_RR_TYPE_DNSKEY,
- vq->qchase.qclass, BIT_CD)) {
+ vq->qchase.qclass, BIT_CD, &newq, 0)) {
log_err("mem error generating DNSKEY request");
return val_error(qstate, id);
}
@@ -1623,7 +1708,7 @@ processFindKey(struct module_qstate* qstate, struct val_qstate* vq, int id)
}
if(!generate_request(qstate, id, target_key_name,
target_key_len, LDNS_RR_TYPE_DS, vq->qchase.qclass,
- BIT_CD)) {
+ BIT_CD, &newq, 0)) {
log_err("mem error generating DS request");
return val_error(qstate, id);
}
@@ -1633,7 +1718,7 @@ processFindKey(struct module_qstate* qstate, struct val_qstate* vq, int id)
/* Otherwise, it is time to query for the DNSKEY */
if(!generate_request(qstate, id, vq->ds_rrset->rk.dname,
vq->ds_rrset->rk.dname_len, LDNS_RR_TYPE_DNSKEY,
- vq->qchase.qclass, BIT_CD)) {
+ vq->qchase.qclass, BIT_CD, &newq, 0)) {
log_err("mem error generating DNSKEY request");
return val_error(qstate, id);
}
@@ -1847,6 +1932,7 @@ val_dlv_init(struct module_qstate* qstate, struct val_qstate* vq,
{
uint8_t* nm;
size_t nm_len;
+ struct module_qstate* newq = NULL;
/* there must be a DLV configured */
log_assert(qstate->env->anchors->dlv_anchor);
/* this bool is true to avoid looping in the DLV checks */
@@ -1948,7 +2034,7 @@ val_dlv_init(struct module_qstate* qstate, struct val_qstate* vq,
vq->state = VAL_DLVLOOKUP_STATE;
if(!generate_request(qstate, id, vq->dlv_lookup_name,
vq->dlv_lookup_name_len, LDNS_RR_TYPE_DLV,
- vq->qchase.qclass, 0)) {
+ vq->qchase.qclass, 0, &newq, 0)) {
return val_error(qstate, id);
}
@@ -2042,7 +2128,7 @@ processFinished(struct module_qstate* qstate, struct val_qstate* vq,
* a different signer name). And drop additional rrsets
* that are not secure (if clean-additional option is set) */
/* this may cause the msg to be marked bogus */
- val_check_nonsecure(ve, vq->orig_msg->rep);
+ val_check_nonsecure(qstate->env, vq->orig_msg->rep);
if(vq->orig_msg->rep->security == sec_status_secure) {
log_query_info(VERB_DETAIL, "validation success",
&qstate->qinfo);
@@ -2083,8 +2169,14 @@ processFinished(struct module_qstate* qstate, struct val_qstate* vq,
free(err);
}
}
+ /*
+ * If set, the validator will not make messages bogus, instead
+ * indeterminate is issued, so that no clients receive SERVFAIL.
+ * This allows an operator to run validation 'shadow' without
+ * hurting responses to clients.
+ */
/* If we are in permissive mode, bogus gets indeterminate */
- if(ve->permissive_mode)
+ if(qstate->env->cfg->val_permissive_mode)
vq->orig_msg->rep->security = sec_status_indeterminate;
}
@@ -2128,6 +2220,7 @@ static int
processDLVLookup(struct module_qstate* qstate, struct val_qstate* vq,
struct val_env* ve, int id)
{
+ struct module_qstate* newq = NULL;
/* see if this we are ready to continue normal resolution */
/* we may need more DLV lookups */
if(vq->dlv_status==dlv_error)
@@ -2176,7 +2269,7 @@ processDLVLookup(struct module_qstate* qstate, struct val_qstate* vq,
if(!generate_request(qstate, id, vq->ds_rrset->rk.dname,
vq->ds_rrset->rk.dname_len, LDNS_RR_TYPE_DNSKEY,
- vq->qchase.qclass, BIT_CD)) {
+ vq->qchase.qclass, BIT_CD, &newq, 0)) {
log_err("mem error generating DNSKEY request");
return val_error(qstate, id);
}
@@ -2218,7 +2311,7 @@ processDLVLookup(struct module_qstate* qstate, struct val_qstate* vq,
if(!generate_request(qstate, id, vq->dlv_lookup_name,
vq->dlv_lookup_name_len, LDNS_RR_TYPE_DLV,
- vq->qchase.qclass, 0)) {
+ vq->qchase.qclass, 0, &newq, 0)) {
return val_error(qstate, id);
}
@@ -2857,6 +2950,7 @@ process_prime_response(struct module_qstate* qstate, struct val_qstate* vq,
ta->name, ta->namelen, LDNS_RR_TYPE_DNSKEY,
ta->dclass);
}
+
if(ta->autr) {
if(!autr_process_prime(qstate->env, ve, ta, dnskey_rrset)) {
/* trust anchor revoked, restart with less anchors */
diff --git a/validator/validator.h b/validator/validator.h
index 23d3072427a2..9a591078f71c 100644
--- a/validator/validator.h
+++ b/validator/validator.h
@@ -93,19 +93,6 @@ struct val_env {
* seconds. */
uint32_t bogus_ttl;
- /** If set, the validator should clean the additional section of
- * secure messages.
- */
- int clean_additional;
-
- /**
- * If set, the validator will not make messages bogus, instead
- * indeterminate is issued, so that no clients receive SERVFAIL.
- * This allows an operator to run validation 'shadow' without
- * hurting responses to clients.
- */
- int permissive_mode;
-
/**
* Number of entries in the NSEC3 maximum iteration count table.
* Keep this table short, and sorted by size