summaryrefslogtreecommitdiff
path: root/sbin/unwind/libunbound/validator
diff options
context:
space:
mode:
Diffstat (limited to 'sbin/unwind/libunbound/validator')
-rw-r--r--sbin/unwind/libunbound/validator/autotrust.c31
-rw-r--r--sbin/unwind/libunbound/validator/val_anchor.c7
-rw-r--r--sbin/unwind/libunbound/validator/val_nsec.c1
-rw-r--r--sbin/unwind/libunbound/validator/val_secalgo.c247
-rw-r--r--sbin/unwind/libunbound/validator/val_secalgo.h43
-rw-r--r--sbin/unwind/libunbound/validator/val_sigcrypt.c98
-rw-r--r--sbin/unwind/libunbound/validator/val_sigcrypt.h29
-rw-r--r--sbin/unwind/libunbound/validator/val_utils.c39
-rw-r--r--sbin/unwind/libunbound/validator/validator.c18
-rw-r--r--sbin/unwind/libunbound/validator/validator.h6
10 files changed, 448 insertions, 71 deletions
diff --git a/sbin/unwind/libunbound/validator/autotrust.c b/sbin/unwind/libunbound/validator/autotrust.c
index 7ce07e0d82d..9643a3ddb38 100644
--- a/sbin/unwind/libunbound/validator/autotrust.c
+++ b/sbin/unwind/libunbound/validator/autotrust.c
@@ -1077,6 +1077,17 @@ trustanchor_state2str(autr_state_type s)
return " UNKNOWN ";
}
+/** ctime r for autotrust */
+static char* autr_ctime_r(time_t* t, char* s)
+{
+ ctime_r(t, s);
+#ifdef USE_WINSOCK
+ if(strlen(s) > 10 && s[7]==' ' && s[8]=='0')
+ s[8]=' '; /* fix error in windows ctime */
+#endif
+ return s;
+}
+
/** print ID to file */
static int
print_id(FILE* out, char* fname, uint8_t* nm, size_t nmlen, uint16_t dclass)
@@ -1123,13 +1134,13 @@ autr_write_contents(FILE* out, char* fn, struct trust_anchor* tp)
}
if(fprintf(out, ";;last_queried: %u ;;%s",
(unsigned int)tp->autr->last_queried,
- ctime_r(&(tp->autr->last_queried), tmi)) < 0 ||
+ autr_ctime_r(&(tp->autr->last_queried), tmi)) < 0 ||
fprintf(out, ";;last_success: %u ;;%s",
(unsigned int)tp->autr->last_success,
- ctime_r(&(tp->autr->last_success), tmi)) < 0 ||
+ autr_ctime_r(&(tp->autr->last_success), tmi)) < 0 ||
fprintf(out, ";;next_probe_time: %u ;;%s",
(unsigned int)tp->autr->next_probe_time,
- ctime_r(&(tp->autr->next_probe_time), tmi)) < 0 ||
+ autr_ctime_r(&(tp->autr->next_probe_time), tmi)) < 0 ||
fprintf(out, ";;query_failed: %d\n", (int)tp->autr->query_failed)<0
|| fprintf(out, ";;query_interval: %d\n",
(int)tp->autr->query_interval) < 0 ||
@@ -1160,7 +1171,7 @@ autr_write_contents(FILE* out, char* fn, struct trust_anchor* tp)
";;lastchange=%u ;;%s", str, (int)ta->s,
trustanchor_state2str(ta->s), (int)ta->pending_count,
(unsigned int)ta->last_change,
- ctime_r(&(ta->last_change), tmi)) < 0) {
+ autr_ctime_r(&(ta->last_change), tmi)) < 0) {
log_err("could not write to %s: %s", fn, strerror(errno));
free(str);
return 0;
@@ -1579,6 +1590,7 @@ key_matches_a_ds(struct module_env* env, struct val_env* ve,
for(ds_idx=0; ds_idx<num; ds_idx++) {
if(!ds_digest_algo_is_supported(ds_rrset, ds_idx) ||
!ds_key_algo_is_supported(ds_rrset, ds_idx) ||
+ !dnskey_size_is_supported(dnskey_rrset, key_idx) ||
ds_get_digest_algo(ds_rrset, ds_idx) != d)
continue;
if(ds_get_key_algo(ds_rrset, ds_idx)
@@ -1633,7 +1645,8 @@ update_events(struct module_env* env, struct val_env* ve,
}
/* is a key of this type supported?. Note rr_list and
* packed_rrset are in the same order. */
- if(!dnskey_algo_is_supported(dnskey_rrset, i)) {
+ if(!dnskey_algo_is_supported(dnskey_rrset, i) ||
+ !dnskey_size_is_supported(dnskey_rrset, i)) {
/* skip unknown algorithm key, it is useless to us */
log_nametypeclass(VERB_DETAIL, "trust point has "
"unsupported algorithm at",
@@ -2262,7 +2275,7 @@ autr_debug_print_ta(struct autr_ta* ta)
return;
}
if(str[0]) str[strlen(str)-1]=0; /* remove newline */
- ctime_r(&ta->last_change, buf);
+ (void)autr_ctime_r(&ta->last_change, buf);
if(buf[0]) buf[strlen(buf)-1]=0; /* remove newline */
log_info("[%s] %s ;;state:%d ;;pending_count:%d%s%s last:%s",
trustanchor_state2str(ta->s), str, ta->s, ta->pending_count,
@@ -2289,13 +2302,13 @@ autr_debug_print_tp(struct trust_anchor* tp)
log_packed_rrset(NO_VERBOSE, "DNSKEY:", tp->dnskey_rrset);
}
log_info("file %s", tp->autr->file);
- ctime_r(&tp->autr->last_queried, buf);
+ (void)autr_ctime_r(&tp->autr->last_queried, buf);
if(buf[0]) buf[strlen(buf)-1]=0; /* remove newline */
log_info("last_queried: %u %s", (unsigned)tp->autr->last_queried, buf);
- ctime_r(&tp->autr->last_success, buf);
+ (void)autr_ctime_r(&tp->autr->last_success, buf);
if(buf[0]) buf[strlen(buf)-1]=0; /* remove newline */
log_info("last_success: %u %s", (unsigned)tp->autr->last_success, buf);
- ctime_r(&tp->autr->next_probe_time, buf);
+ (void)autr_ctime_r(&tp->autr->next_probe_time, buf);
if(buf[0]) buf[strlen(buf)-1]=0; /* remove newline */
log_info("next_probe_time: %u %s", (unsigned)tp->autr->next_probe_time,
buf);
diff --git a/sbin/unwind/libunbound/validator/val_anchor.c b/sbin/unwind/libunbound/validator/val_anchor.c
index 9b6574c5d24..b1a54e1f019 100644
--- a/sbin/unwind/libunbound/validator/val_anchor.c
+++ b/sbin/unwind/libunbound/validator/val_anchor.c
@@ -971,7 +971,8 @@ anchors_dnskey_unsupported(struct trust_anchor* ta)
{
size_t i, num = 0;
for(i=0; i<ta->numDNSKEY; i++) {
- if(!dnskey_algo_is_supported(ta->dnskey_rrset, i))
+ if(!dnskey_algo_is_supported(ta->dnskey_rrset, i) ||
+ !dnskey_size_is_supported(ta->dnskey_rrset, i))
num++;
}
return num;
@@ -1048,6 +1049,10 @@ anchors_apply_cfg(struct val_anchors* anchors, struct config_file* cfg)
const char** zstr;
char* nm;
sldns_buffer* parsebuf = sldns_buffer_new(65535);
+ if(!parsebuf) {
+ log_err("malloc error in anchors_apply_cfg.");
+ return 0;
+ }
if(cfg->insecure_lan_zones) {
for(zstr = as112_zones; *zstr; zstr++) {
if(!anchor_insert_insecure(anchors, *zstr)) {
diff --git a/sbin/unwind/libunbound/validator/val_nsec.c b/sbin/unwind/libunbound/validator/val_nsec.c
index 032d2ae03a4..a4e5b3137db 100644
--- a/sbin/unwind/libunbound/validator/val_nsec.c
+++ b/sbin/unwind/libunbound/validator/val_nsec.c
@@ -180,6 +180,7 @@ nsec_verify_rrset(struct module_env* env, struct val_env* ve,
{
struct packed_rrset_data* d = (struct packed_rrset_data*)
nsec->entry.data;
+ if(!d) return 0;
if(d->security == sec_status_secure)
return 1;
rrset_check_sec_status(env->rrset_cache, nsec, *env->now);
diff --git a/sbin/unwind/libunbound/validator/val_secalgo.c b/sbin/unwind/libunbound/validator/val_secalgo.c
index 15cccf017b4..7abf66f01d2 100644
--- a/sbin/unwind/libunbound/validator/val_secalgo.c
+++ b/sbin/unwind/libunbound/validator/val_secalgo.c
@@ -141,6 +141,69 @@ secalgo_hash_sha256(unsigned char* buf, size_t len, unsigned char* res)
#endif
}
+/** hash structure for keeping track of running hashes */
+struct secalgo_hash {
+ /** the openssl message digest context */
+ EVP_MD_CTX* ctx;
+};
+
+/** create secalgo hash with hash type */
+static struct secalgo_hash* secalgo_hash_create_md(const EVP_MD* md)
+{
+ struct secalgo_hash* h;
+ if(!md)
+ return NULL;
+ h = calloc(1, sizeof(*h));
+ if(!h)
+ return NULL;
+ h->ctx = EVP_MD_CTX_create();
+ if(!h->ctx) {
+ free(h);
+ return NULL;
+ }
+ if(!EVP_DigestInit_ex(h->ctx, md, NULL)) {
+ EVP_MD_CTX_destroy(h->ctx);
+ free(h);
+ return NULL;
+ }
+ return h;
+}
+
+struct secalgo_hash* secalgo_hash_create_sha384(void)
+{
+ return secalgo_hash_create_md(EVP_sha384());
+}
+
+struct secalgo_hash* secalgo_hash_create_sha512(void)
+{
+ return secalgo_hash_create_md(EVP_sha512());
+}
+
+int secalgo_hash_update(struct secalgo_hash* hash, uint8_t* data, size_t len)
+{
+ return EVP_DigestUpdate(hash->ctx, (unsigned char*)data,
+ (unsigned int)len);
+}
+
+int secalgo_hash_final(struct secalgo_hash* hash, uint8_t* result,
+ size_t maxlen, size_t* resultlen)
+{
+ if(EVP_MD_CTX_size(hash->ctx) > (int)maxlen) {
+ *resultlen = 0;
+ log_err("secalgo_hash_final: hash buffer too small");
+ return 0;
+ }
+ *resultlen = EVP_MD_CTX_size(hash->ctx);
+ return EVP_DigestFinal_ex(hash->ctx, result, NULL);
+}
+
+void secalgo_hash_delete(struct secalgo_hash* hash)
+{
+ if(!hash) return;
+ EVP_MD_CTX_destroy(hash->ctx);
+ free(hash);
+}
+
/**
* Return size of DS digest according to its hash algorithm.
* @param algo: DS digest algo.
@@ -450,29 +513,13 @@ static int
setup_key_digest(int algo, EVP_PKEY** evp_key, const EVP_MD** digest_type,
unsigned char* key, size_t keylen)
{
-#if defined(USE_DSA) && defined(USE_SHA1)
- DSA* dsa;
-#endif
- RSA* rsa;
-
switch(algo) {
#if defined(USE_DSA) && defined(USE_SHA1)
case LDNS_DSA:
case LDNS_DSA_NSEC3:
- *evp_key = EVP_PKEY_new();
+ *evp_key = sldns_key_dsa2pkey_raw(key, keylen);
if(!*evp_key) {
- log_err("verify: malloc failure in crypto");
- return 0;
- }
- dsa = sldns_key_buf2dsa_raw(key, keylen);
- if(!dsa) {
- verbose(VERB_QUERY, "verify: "
- "sldns_key_buf2dsa_raw failed");
- return 0;
- }
- if(EVP_PKEY_assign_DSA(*evp_key, dsa) == 0) {
- verbose(VERB_QUERY, "verify: "
- "EVP_PKEY_assign_DSA failed");
+ verbose(VERB_QUERY, "verify: sldns_key_dsa2pkey failed");
return 0;
}
#ifdef HAVE_EVP_DSS1
@@ -495,20 +542,9 @@ setup_key_digest(int algo, EVP_PKEY** evp_key, const EVP_MD** digest_type,
#if defined(HAVE_EVP_SHA512) && defined(USE_SHA2)
case LDNS_RSASHA512:
#endif
- *evp_key = EVP_PKEY_new();
+ *evp_key = sldns_key_rsa2pkey_raw(key, keylen);
if(!*evp_key) {
- log_err("verify: malloc failure in crypto");
- return 0;
- }
- rsa = sldns_key_buf2rsa_raw(key, keylen);
- if(!rsa) {
- verbose(VERB_QUERY, "verify: "
- "sldns_key_buf2rsa_raw SHA failed");
- return 0;
- }
- if(EVP_PKEY_assign_RSA(*evp_key, rsa) == 0) {
- verbose(VERB_QUERY, "verify: "
- "EVP_PKEY_assign_RSA SHA failed");
+ verbose(VERB_QUERY, "verify: sldns_key_rsa2pkey SHA failed");
return 0;
}
@@ -532,20 +568,9 @@ setup_key_digest(int algo, EVP_PKEY** evp_key, const EVP_MD** digest_type,
#endif /* defined(USE_SHA1) || (defined(HAVE_EVP_SHA256) && defined(USE_SHA2)) || (defined(HAVE_EVP_SHA512) && defined(USE_SHA2)) */
case LDNS_RSAMD5:
- *evp_key = EVP_PKEY_new();
+ *evp_key = sldns_key_rsa2pkey_raw(key, keylen);
if(!*evp_key) {
- log_err("verify: malloc failure in crypto");
- return 0;
- }
- rsa = sldns_key_buf2rsa_raw(key, keylen);
- if(!rsa) {
- verbose(VERB_QUERY, "verify: "
- "sldns_key_buf2rsa_raw MD5 failed");
- return 0;
- }
- if(EVP_PKEY_assign_RSA(*evp_key, rsa) == 0) {
- verbose(VERB_QUERY, "verify: "
- "EVP_PKEY_assign_RSA MD5 failed");
+ verbose(VERB_QUERY, "verify: sldns_key_rsa2pkey MD5 failed");
return 0;
}
*digest_type = EVP_md5();
@@ -823,6 +848,64 @@ secalgo_hash_sha256(unsigned char* buf, size_t len, unsigned char* res)
(void)HASH_HashBuf(HASH_AlgSHA256, res, buf, (unsigned long)len);
}
+/** the secalgo hash structure */
+struct secalgo_hash {
+ /** hash context */
+ HASHContext* ctx;
+};
+
+/** create hash struct of type */
+static struct secalgo_hash* secalgo_hash_create_type(HASH_HashType tp)
+{
+ struct secalgo_hash* h = calloc(1, sizeof(*h));
+ if(!h)
+ return NULL;
+ h->ctx = HASH_Create(tp);
+ if(!h->ctx) {
+ free(h);
+ return NULL;
+ }
+ return h;
+}
+
+struct secalgo_hash* secalgo_hash_create_sha384(void)
+{
+ return secalgo_hash_create_type(HASH_AlgSHA384);
+}
+
+struct secalgo_hash* secalgo_hash_create_sha512(void)
+{
+ return secalgo_hash_create_type(HASH_AlgSHA512);
+}
+
+int secalgo_hash_update(struct secalgo_hash* hash, uint8_t* data, size_t len)
+{
+ HASH_Update(hash->ctx, (unsigned char*)data, (unsigned int)len);
+ return 1;
+}
+
+int secalgo_hash_final(struct secalgo_hash* hash, uint8_t* result,
+ size_t maxlen, size_t* resultlen)
+{
+ unsigned int reslen = 0;
+ if(HASH_ResultLenContext(hash->ctx) > (unsigned int)maxlen) {
+ *resultlen = 0;
+ log_err("secalgo_hash_final: hash buffer too small");
+ return 0;
+ }
+ HASH_End(hash->ctx, (unsigned char*)result, &reslen,
+ (unsigned int)maxlen);
+ *resultlen = (size_t)reslen;
+ return 1;
+}
+
+void secalgo_hash_delete(struct secalgo_hash* hash)
+{
+ if(!hash) return;
+ HASH_Destroy(hash->ctx);
+ free(hash);
+}
+
size_t
ds_digest_size_supported(int algo)
{
@@ -1451,6 +1534,82 @@ secalgo_hash_sha256(unsigned char* buf, size_t len, unsigned char* res)
_digest_nettle(SHA256_DIGEST_SIZE, (uint8_t*)buf, len, res);
}
+/** secalgo hash structure */
+struct secalgo_hash {
+ /** if it is 384 or 512 */
+ int active;
+ /** context for sha384 */
+ struct sha384_ctx ctx384;
+ /** context for sha512 */
+ struct sha512_ctx ctx512;
+};
+
+struct secalgo_hash* secalgo_hash_create_sha384(void)
+{
+ struct secalgo_hash* h = calloc(1, sizeof(*h));
+ if(!h)
+ return NULL;
+ h->active = 384;
+ sha384_init(&h->ctx384);
+ return h;
+}
+
+struct secalgo_hash* secalgo_hash_create_sha512(void)
+{
+ struct secalgo_hash* h = calloc(1, sizeof(*h));
+ if(!h)
+ return NULL;
+ h->active = 512;
+ sha512_init(&h->ctx512);
+ return h;
+}
+
+int secalgo_hash_update(struct secalgo_hash* hash, uint8_t* data, size_t len)
+{
+ if(hash->active == 384) {
+ sha384_update(&hash->ctx384, len, data);
+ } else if(hash->active == 512) {
+ sha512_update(&hash->ctx512, len, data);
+ } else {
+ return 0;
+ }
+ return 1;
+}
+
+int secalgo_hash_final(struct secalgo_hash* hash, uint8_t* result,
+ size_t maxlen, size_t* resultlen)
+{
+ if(hash->active == 384) {
+ if(SHA384_DIGEST_SIZE > maxlen) {
+ *resultlen = 0;
+ log_err("secalgo_hash_final: hash buffer too small");
+ return 0;
+ }
+ *resultlen = SHA384_DIGEST_SIZE;
+ sha384_digest(&hash->ctx384, SHA384_DIGEST_SIZE,
+ (unsigned char*)result);
+ } else if(hash->active == 512) {
+ if(SHA512_DIGEST_SIZE > maxlen) {
+ *resultlen = 0;
+ log_err("secalgo_hash_final: hash buffer too small");
+ return 0;
+ }
+ *resultlen = SHA512_DIGEST_SIZE;
+ sha512_digest(&hash->ctx512, SHA512_DIGEST_SIZE,
+ (unsigned char*)result);
+ } else {
+ *resultlen = 0;
+ return 0;
+ }
+ return 1;
+}
+
+void secalgo_hash_delete(struct secalgo_hash* hash)
+{
+ if(!hash) return;
+ free(hash);
+}
+
/**
* Return size of DS digest according to its hash algorithm.
* @param algo: DS digest algo.
diff --git a/sbin/unwind/libunbound/validator/val_secalgo.h b/sbin/unwind/libunbound/validator/val_secalgo.h
index 52aaeb9f6d3..8b6080dc24a 100644
--- a/sbin/unwind/libunbound/validator/val_secalgo.h
+++ b/sbin/unwind/libunbound/validator/val_secalgo.h
@@ -43,6 +43,7 @@
#ifndef VALIDATOR_VAL_SECALGO_H
#define VALIDATOR_VAL_SECALGO_H
struct sldns_buffer;
+struct secalgo_hash;
/** Return size of nsec3 hash algorithm, 0 if not supported */
size_t nsec3_hash_algo_size_supported(int id);
@@ -68,6 +69,48 @@ int secalgo_nsec3_hash(int algo, unsigned char* buf, size_t len,
void secalgo_hash_sha256(unsigned char* buf, size_t len, unsigned char* res);
/**
+ * Start a hash of type sha384. Allocates structure, then inits it,
+ * so that a series of updates can be performed, before the final result.
+ * @return hash structure. NULL on malloc failure or no support.
+ */
+struct secalgo_hash* secalgo_hash_create_sha384(void);
+
+/**
+ * Start a hash of type sha512. Allocates structure, then inits it,
+ * so that a series of updates can be performed, before the final result.
+ * @return hash structure. NULL on malloc failure or no support.
+ */
+struct secalgo_hash* secalgo_hash_create_sha512(void);
+
+/**
+ * Update a hash with more information to add to it.
+ * @param hash: the hash that is updated.
+ * @param data: data to add.
+ * @param len: length of data.
+ * @return false on failure.
+ */
+int secalgo_hash_update(struct secalgo_hash* hash, uint8_t* data, size_t len);
+
+/**
+ * Get the final result of the hash.
+ * @param hash: the hash that has had updates to it.
+ * @param result: where to store the result.
+ * @param maxlen: length of the result buffer, eg. size of the allocation.
+ * If not large enough the routine fails.
+ * @param resultlen: the length of the result, returned to the caller.
+ * How much of maxlen is used.
+ * @return false on failure.
+ */
+int secalgo_hash_final(struct secalgo_hash* hash, uint8_t* result,
+ size_t maxlen, size_t* resultlen);
+
+/**
+ * Delete the hash structure.
+ * @param hash: the hash to delete.
+ */
+void secalgo_hash_delete(struct secalgo_hash* hash);
+
+/**
* Return size of DS digest according to its hash algorithm.
* @param algo: DS digest algo.
* @return size in bytes of digest, or 0 if not supported.
diff --git a/sbin/unwind/libunbound/validator/val_sigcrypt.c b/sbin/unwind/libunbound/validator/val_sigcrypt.c
index de730f68189..b15fba3f499 100644
--- a/sbin/unwind/libunbound/validator/val_sigcrypt.c
+++ b/sbin/unwind/libunbound/validator/val_sigcrypt.c
@@ -386,6 +386,49 @@ int dnskey_algo_is_supported(struct ub_packed_rrset_key* dnskey_rrset,
dnskey_idx));
}
+int dnskey_size_is_supported(struct ub_packed_rrset_key* dnskey_rrset,
+ size_t dnskey_idx)
+{
+#ifdef DEPRECATE_RSA_1024
+ uint8_t* rdata;
+ size_t len;
+ int alg = dnskey_get_algo(dnskey_rrset, dnskey_idx);
+ size_t keysize;
+
+ rrset_get_rdata(dnskey_rrset, dnskey_idx, &rdata, &len);
+ if(len < 2+4)
+ return 0;
+ keysize = sldns_rr_dnskey_key_size_raw(rdata+2+4, len-2-4, alg);
+
+ switch((sldns_algorithm)alg) {
+ case LDNS_RSAMD5:
+ case LDNS_RSASHA1:
+ case LDNS_RSASHA1_NSEC3:
+ case LDNS_RSASHA256:
+ case LDNS_RSASHA512:
+ /* reject RSA keys of 1024 bits and shorter */
+ if(keysize <= 1024)
+ return 0;
+ break;
+ default:
+ break;
+ }
+#else
+ (void)dnskey_rrset; (void)dnskey_idx;
+#endif /* DEPRECATE_RSA_1024 */
+ return 1;
+}
+
+int dnskeyset_size_is_supported(struct ub_packed_rrset_key* dnskey_rrset)
+{
+ size_t i, num = rrset_get_count(dnskey_rrset);
+ for(i=0; i<num; i++) {
+ if(!dnskey_size_is_supported(dnskey_rrset, i))
+ return 0;
+ }
+ return 1;
+}
+
void algo_needs_init_dnskey_add(struct algo_needs* n,
struct ub_packed_rrset_key* dnskey, uint8_t* sigalg)
{
@@ -1187,7 +1230,7 @@ rrset_canonical(struct regional* region, sldns_buffer* buf,
* section, to prevent that a wildcard synthesized NSEC can be used in
* the non-existence proves. */
if(ntohs(k->rk.type) == LDNS_RR_TYPE_NSEC &&
- section == LDNS_SECTION_AUTHORITY) {
+ section == LDNS_SECTION_AUTHORITY && qstate) {
k->rk.dname = regional_alloc_init(qstate->region, can_owner,
can_owner_len);
if(!k->rk.dname)
@@ -1199,6 +1242,59 @@ rrset_canonical(struct regional* region, sldns_buffer* buf,
return 1;
}
+int
+rrset_canonicalize_to_buffer(struct regional* region, sldns_buffer* buf,
+ struct ub_packed_rrset_key* k)
+{
+ struct rbtree_type* sortree = NULL;
+ struct packed_rrset_data* d = (struct packed_rrset_data*)k->entry.data;
+ uint8_t* can_owner = NULL;
+ size_t can_owner_len = 0;
+ struct canon_rr* walk;
+ struct canon_rr* rrs;
+
+ sortree = (struct rbtree_type*)regional_alloc(region,
+ sizeof(rbtree_type));
+ if(!sortree)
+ return 0;
+ if(d->count > RR_COUNT_MAX)
+ return 0; /* integer overflow protection */
+ rrs = regional_alloc(region, sizeof(struct canon_rr)*d->count);
+ if(!rrs) {
+ return 0;
+ }
+ rbtree_init(sortree, &canonical_tree_compare);
+ canonical_sort(k, d, sortree, rrs);
+
+ sldns_buffer_clear(buf);
+ RBTREE_FOR(walk, struct canon_rr*, sortree) {
+ /* see if there is enough space left in the buffer */
+ if(sldns_buffer_remaining(buf) < can_owner_len + 2 + 2 + 4
+ + d->rr_len[walk->rr_idx]) {
+ log_err("verify: failed to canonicalize, "
+ "rrset too big");
+ return 0;
+ }
+ /* determine canonical owner name */
+ if(can_owner)
+ sldns_buffer_write(buf, can_owner, can_owner_len);
+ else {
+ can_owner = sldns_buffer_current(buf);
+ sldns_buffer_write(buf, k->rk.dname, k->rk.dname_len);
+ query_dname_tolower(can_owner);
+ can_owner_len = k->rk.dname_len;
+ }
+ sldns_buffer_write(buf, &k->rk.type, 2);
+ sldns_buffer_write(buf, &k->rk.rrset_class, 2);
+ sldns_buffer_write_u32(buf, d->rr_ttl[walk->rr_idx]);
+ sldns_buffer_write(buf, d->rr_data[walk->rr_idx],
+ d->rr_len[walk->rr_idx]);
+ canonicalize_rdata(buf, k, d->rr_len[walk->rr_idx]);
+ }
+ sldns_buffer_flip(buf);
+ return 1;
+}
+
/** pretty print rrsig error with dates */
static void
sigdate_error(const char* str, int32_t expi, int32_t incep, int32_t now)
diff --git a/sbin/unwind/libunbound/validator/val_sigcrypt.h b/sbin/unwind/libunbound/validator/val_sigcrypt.h
index 755a1d6e126..bbb95780d7f 100644
--- a/sbin/unwind/libunbound/validator/val_sigcrypt.h
+++ b/sbin/unwind/libunbound/validator/val_sigcrypt.h
@@ -180,6 +180,23 @@ uint16_t ds_get_keytag(struct ub_packed_rrset_key* ds_rrset, size_t ds_idx);
int dnskey_algo_is_supported(struct ub_packed_rrset_key* dnskey_rrset,
size_t dnskey_idx);
+/**
+ * See if the DNSKEY size at that algorithm is supported.
+ * @param dnskey_rrset: DNSKEY rrset.
+ * @param dnskey_idx: index of RR in rrset.
+ * @return true if supported.
+ */
+int dnskey_size_is_supported(struct ub_packed_rrset_key* dnskey_rrset,
+ size_t dnskey_idx);
+
+/**
+ * See if the DNSKEY size at that algorithm is supported for all the
+ * RRs in the DNSKEY RRset.
+ * @param dnskey_rrset: DNSKEY rrset.
+ * @return true if supported.
+ */
+int dnskeyset_size_is_supported(struct ub_packed_rrset_key* dnskey_rrset);
+
/**
* See if DS digest algorithm is supported
* @param ds_rrset: DS rrset
@@ -334,4 +351,16 @@ int canonical_tree_compare(const void* k1, const void* k2);
int rrset_canonical_equal(struct regional* region,
struct ub_packed_rrset_key* k1, struct ub_packed_rrset_key* k2);
+/**
+ * Canonicalize an rrset into the buffer. For an auth zone record, so
+ * this does not use a signature, or the RRSIG TTL or the wildcard label
+ * count from the RRSIG.
+ * @param region: temporary region.
+ * @param buf: the buffer to use.
+ * @param k: the rrset to insert.
+ * @return false on alloc error.
+ */
+int rrset_canonicalize_to_buffer(struct regional* region,
+ struct sldns_buffer* buf, struct ub_packed_rrset_key* k);
+
#endif /* VALIDATOR_VAL_SIGCRYPT_H */
diff --git a/sbin/unwind/libunbound/validator/val_utils.c b/sbin/unwind/libunbound/validator/val_utils.c
index 2f36fccfd4f..dd8d320e515 100644
--- a/sbin/unwind/libunbound/validator/val_utils.c
+++ b/sbin/unwind/libunbound/validator/val_utils.c
@@ -418,7 +418,7 @@ verify_dnskeys_with_ds_rr(struct module_env* env, struct val_env* ve,
struct module_qstate* qstate)
{
enum sec_status sec = sec_status_bogus;
- size_t i, num, numchecked = 0, numhashok = 0;
+ size_t i, num, numchecked = 0, numhashok = 0, numsizesupp = 0;
num = rrset_get_count(dnskey_rrset);
for(i=0; i<num; i++) {
/* Skip DNSKEYs that don't match the basic criteria. */
@@ -441,6 +441,11 @@ verify_dnskeys_with_ds_rr(struct module_env* env, struct val_env* ve,
continue;
}
numhashok++;
+ if(!dnskey_size_is_supported(dnskey_rrset, i)) {
+ verbose(VERB_ALGO, "DS okay but that DNSKEY size is not supported");
+ numsizesupp++;
+ continue;
+ }
verbose(VERB_ALGO, "DS match digest ok, trying signature");
/* Otherwise, we have a match! Make sure that the DNSKEY
@@ -452,6 +457,10 @@ verify_dnskeys_with_ds_rr(struct module_env* env, struct val_env* ve,
}
/* If it didn't validate with the DNSKEY, try the next one! */
}
+ if(numsizesupp != 0) {
+ /* there is a working DS, but that DNSKEY is not supported */
+ return sec_status_insecure;
+ }
if(numchecked == 0)
algo_needs_reason(env, ds_get_key_algo(ds_rrset, ds_idx),
reason, "no keys have a DS");
@@ -519,17 +528,24 @@ val_verify_DNSKEY_with_DS(struct module_env* env, struct val_env* ve,
continue;
}
+ sec = verify_dnskeys_with_ds_rr(env, ve, dnskey_rrset,
+ ds_rrset, i, reason, qstate);
+ if(sec == sec_status_insecure)
+ continue;
+
/* Once we see a single DS with a known digestID and
* algorithm, we cannot return INSECURE (with a
* "null" KeyEntry). */
has_useful_ds = 1;
- sec = verify_dnskeys_with_ds_rr(env, ve, dnskey_rrset,
- ds_rrset, i, reason, qstate);
if(sec == sec_status_secure) {
if(!sigalg || algo_needs_set_secure(&needs,
(uint8_t)ds_get_key_algo(ds_rrset, i))) {
verbose(VERB_ALGO, "DS matched DNSKEY.");
+ if(!dnskeyset_size_is_supported(dnskey_rrset)) {
+ verbose(VERB_ALGO, "DS works, but dnskeyset contain keys that are unsupported, treat as insecure");
+ return sec_status_insecure;
+ }
return sec_status_secure;
}
} else if(sigalg && sec == sec_status_bogus) {
@@ -631,17 +647,24 @@ val_verify_DNSKEY_with_TA(struct module_env* env, struct val_env* ve,
ds_get_digest_algo(ta_ds, i) != digest_algo)
continue;
+ sec = verify_dnskeys_with_ds_rr(env, ve, dnskey_rrset,
+ ta_ds, i, reason, qstate);
+ if(sec == sec_status_insecure)
+ continue;
+
/* Once we see a single DS with a known digestID and
* algorithm, we cannot return INSECURE (with a
* "null" KeyEntry). */
has_useful_ta = 1;
- sec = verify_dnskeys_with_ds_rr(env, ve, dnskey_rrset,
- ta_ds, i, reason, qstate);
if(sec == sec_status_secure) {
if(!sigalg || algo_needs_set_secure(&needs,
(uint8_t)ds_get_key_algo(ta_ds, i))) {
verbose(VERB_ALGO, "DS matched DNSKEY.");
+ if(!dnskeyset_size_is_supported(dnskey_rrset)) {
+ verbose(VERB_ALGO, "trustanchor works, but dnskeyset contain keys that are unsupported, treat as insecure");
+ return sec_status_insecure;
+ }
return sec_status_secure;
}
} else if(sigalg && sec == sec_status_bogus) {
@@ -658,6 +681,8 @@ val_verify_DNSKEY_with_TA(struct module_env* env, struct val_env* ve,
/* Check to see if we can understand this DNSKEY */
if(!dnskey_algo_is_supported(ta_dnskey, i))
continue;
+ if(!dnskey_size_is_supported(ta_dnskey, i))
+ continue;
/* we saw a useful TA */
has_useful_ta = 1;
@@ -668,6 +693,10 @@ val_verify_DNSKEY_with_TA(struct module_env* env, struct val_env* ve,
if(!sigalg || algo_needs_set_secure(&needs,
(uint8_t)dnskey_get_algo(ta_dnskey, i))) {
verbose(VERB_ALGO, "anchor matched DNSKEY.");
+ if(!dnskeyset_size_is_supported(dnskey_rrset)) {
+ verbose(VERB_ALGO, "trustanchor works, but dnskeyset contain keys that are unsupported, treat as insecure");
+ return sec_status_insecure;
+ }
return sec_status_secure;
}
} else if(sigalg && sec == sec_status_bogus) {
diff --git a/sbin/unwind/libunbound/validator/validator.c b/sbin/unwind/libunbound/validator/validator.c
index e12180b4bbd..d4d48d95689 100644
--- a/sbin/unwind/libunbound/validator/validator.c
+++ b/sbin/unwind/libunbound/validator/validator.c
@@ -137,6 +137,7 @@ val_apply_cfg(struct module_env* env, struct val_env* val_env,
val_env->date_override = cfg->val_date_override;
val_env->skew_min = cfg->val_sig_skew_min;
val_env->skew_max = cfg->val_sig_skew_max;
+ val_env->max_restart = cfg->val_max_restart;
c = cfg_count_numbers(cfg->val_nsec3_key_iterations);
if(c < 1 || (c&1)) {
log_err("validator: unparseable or odd nsec3 key "
@@ -1487,7 +1488,7 @@ processInit(struct module_qstate* qstate, struct val_qstate* vq,
enum val_classification subtype = val_classify_response(
qstate->query_flags, &qstate->qinfo, &vq->qchase,
vq->orig_msg->rep, vq->rrset_skip);
- if(vq->restart_count > VAL_MAX_RESTART_COUNT) {
+ if(vq->restart_count > ve->max_restart) {
verbose(VERB_ALGO, "restart count exceeded");
return val_error(qstate, id);
}
@@ -1640,7 +1641,7 @@ processInit(struct module_qstate* qstate, struct val_qstate* vq,
errinf(qstate, key_entry_get_reason(vq->key_entry));
}
/* no retries, stop bothering the authority until timeout */
- vq->restart_count = VAL_MAX_RESTART_COUNT;
+ vq->restart_count = ve->max_restart;
vq->chase_reply->security = sec_status_bogus;
vq->state = VAL_FINISHED_STATE;
return 1;
@@ -1848,7 +1849,7 @@ processValidate(struct module_qstate* qstate, struct val_qstate* vq,
LDNS_RR_TYPE_DNSKEY, vq->key_entry->key_class);
vq->chase_reply->security = sec_status_bogus;
errinf(qstate, "while building chain of trust");
- if(vq->restart_count >= VAL_MAX_RESTART_COUNT)
+ if(vq->restart_count >= ve->max_restart)
key_cache_insert(ve->kcache, vq->key_entry, qstate);
return 1;
}
@@ -2064,7 +2065,7 @@ processFinished(struct module_qstate* qstate, struct val_qstate* vq,
* endless bogus revalidation */
if(vq->orig_msg->rep->security == sec_status_bogus) {
/* see if we can try again to fetch data */
- if(vq->restart_count < VAL_MAX_RESTART_COUNT) {
+ if(vq->restart_count < ve->max_restart) {
int restart_count = vq->restart_count+1;
verbose(VERB_ALGO, "validation failed, "
"blacklist and retry to fetch data");
@@ -2605,6 +2606,7 @@ 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)
{
+ struct val_env* ve = (struct val_env*)qstate->env->modinfo[id];
struct key_entry_key* dske = NULL;
uint8_t* olds = vq->empty_DS_name;
vq->empty_DS_name = NULL;
@@ -2638,7 +2640,7 @@ process_ds_response(struct module_qstate* qstate, struct val_qstate* vq,
vq->chain_blacklist = NULL; /* fresh blacklist for next part*/
/* Keep the forState.state on FINDKEY. */
} else if(key_entry_isbad(dske)
- && vq->restart_count < VAL_MAX_RESTART_COUNT) {
+ && vq->restart_count < ve->max_restart) {
vq->empty_DS_name = olds;
val_blacklist(&vq->chain_blacklist, qstate->region, origin, 1);
qstate->errinf = NULL;
@@ -2691,7 +2693,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 < VAL_MAX_RESTART_COUNT) {
+ if(vq->restart_count < ve->max_restart) {
val_blacklist(&vq->chain_blacklist, qstate->region,
origin, 1);
qstate->errinf = NULL;
@@ -2730,7 +2732,7 @@ process_dnskey_response(struct module_qstate* qstate, struct val_qstate* vq,
* state. */
if(!key_entry_isgood(vq->key_entry)) {
if(key_entry_isbad(vq->key_entry)) {
- if(vq->restart_count < VAL_MAX_RESTART_COUNT) {
+ if(vq->restart_count < ve->max_restart) {
val_blacklist(&vq->chain_blacklist,
qstate->region, origin, 1);
qstate->errinf = NULL;
@@ -2807,7 +2809,7 @@ process_prime_response(struct module_qstate* qstate, struct val_qstate* vq,
lock_basic_unlock(&ta->lock);
if(vq->key_entry) {
if(key_entry_isbad(vq->key_entry)
- && vq->restart_count < VAL_MAX_RESTART_COUNT) {
+ && vq->restart_count < ve->max_restart) {
val_blacklist(&vq->chain_blacklist, qstate->region,
origin, 1);
qstate->errinf = NULL;
diff --git a/sbin/unwind/libunbound/validator/validator.h b/sbin/unwind/libunbound/validator/validator.h
index 35da1920aa3..a928e10a65d 100644
--- a/sbin/unwind/libunbound/validator/validator.h
+++ b/sbin/unwind/libunbound/validator/validator.h
@@ -64,9 +64,6 @@ struct config_strlist;
*/
#define BOGUS_KEY_TTL 60 /* seconds */
-/** max number of query restarts, number of IPs to probe */
-#define VAL_MAX_RESTART_COUNT 5
-
/** Root key sentinel is ta preamble */
#define SENTINEL_IS "root-key-sentinel-is-ta-"
/** Root key sentinel is not ta preamble */
@@ -95,6 +92,9 @@ struct val_env {
/** clock skew max for signatures */
int32_t skew_max;
+ /** max number of query restarts, number of IPs to probe */
+ int32_t max_restart;
+
/** TTL for bogus data; used instead of untrusted TTL from data.
* Bogus data will not be verified more often than this interval.
* seconds. */