summaryrefslogtreecommitdiff
path: root/validator
diff options
context:
space:
mode:
Diffstat (limited to 'validator')
-rw-r--r--validator/val_neg.c28
-rw-r--r--validator/val_nsec3.c76
-rw-r--r--validator/val_nsec3.h6
-rw-r--r--validator/val_utils.c4
4 files changed, 106 insertions, 8 deletions
diff --git a/validator/val_neg.c b/validator/val_neg.c
index 66fd818994ed..e82f335b9ad9 100644
--- a/validator/val_neg.c
+++ b/validator/val_neg.c
@@ -62,6 +62,13 @@
#include "sldns/rrdef.h"
#include "sldns/sbuffer.h"
+/**
+ * The maximum salt length that the negative cache is willing to use.
+ * Larger salt increases the computation time, while recommendations are
+ * for zero salt length for zones.
+ */
+#define MAX_SALT_LENGTH 64
+
int val_neg_data_compare(const void* a, const void* b)
{
struct val_neg_data* x = (struct val_neg_data*)a;
@@ -826,7 +833,11 @@ void neg_insert_data(struct val_neg_cache* neg,
(slen != 0 && zone->nsec3_salt && s
&& memcmp(zone->nsec3_salt, s, slen) != 0))) {
- if(slen > 0) {
+ if(slen > MAX_SALT_LENGTH) {
+ /* RFC 9276 s3.1: operators SHOULD NOT use a salt; large
+ * salts inflate per-hash block count. Decline to cache. */
+ return;
+ } else if(slen > 0) {
uint8_t* sa = memdup(s, slen);
if(sa) {
free(zone->nsec3_salt);
@@ -1165,6 +1176,15 @@ neg_find_nsec3_ce(struct val_neg_zone* zone, uint8_t* qname, size_t qname_len,
uint8_t hashce[NSEC3_SHA_LEN];
uint8_t b32[257];
size_t celen, b32len;
+ int hashmax = MAX_NSEC3_CALCULATIONS;
+ if(qlabs > hashmax) {
+ /* strip leading labels so the walk costs at most
+ * MAX_NSEC3_CALCULATIONS hashes, mirroring val_nsec3.c */
+ while(qlabs > hashmax) {
+ dname_remove_label(&qname, &qname_len);
+ qlabs--;
+ }
+ }
*nclen = 0;
while(qlabs > 0) {
@@ -1265,6 +1285,12 @@ neg_nsec3_proof_ds(struct val_neg_zone* zone, uint8_t* qname, size_t qname_len,
if(!zone->nsec3_hash)
return NULL; /* not nsec3 zone */
+ if(!topname && qlabs > zone->labs + 1)
+ return NULL; /* iterator caller; opt-out proof would be discarded
+ * at the !topname check below anyway.
+ * The qlabs check allows the exact-match for
+ * the one-label-below-zone case. */
+
if(!(data=neg_find_nsec3_ce(zone, qname, qname_len, qlabs, buf,
hashnc, &nclen))) {
return NULL;
diff --git a/validator/val_nsec3.c b/validator/val_nsec3.c
index 998fcc4e38ee..62effde2093f 100644
--- a/validator/val_nsec3.c
+++ b/validator/val_nsec3.c
@@ -60,11 +60,6 @@
#include "util/config_file.h"
/**
- * Max number of NSEC3 calculations at once, suspend query for later.
- * 8 is low enough and allows for cases where multiple proofs are needed.
- */
-#define MAX_NSEC3_CALCULATIONS 8
-/**
* When all allowed NSEC3 calculations at once resulted in error treat as
* bogus. NSEC3 hash errors are not cached and this helps breaks loops with
* erroneous data.
@@ -456,6 +451,67 @@ filter_init(struct nsec3_filter* filter, struct ub_packed_rrset_key** list,
}
}
+/** Check if the NSEC3s have the same parameter set. */
+static int
+param_set_same(struct nsec3_filter* flt, char** reason)
+{
+ size_t rrsetnum;
+ int rrnum;
+ struct ub_packed_rrset_key* rrset;
+ int have_params = 0;
+ int first_algo = 0;
+ size_t first_iter = 0;
+ uint8_t* first_salt = NULL;
+ size_t first_saltlen = 0;
+
+ /* If the NSEC3 parameter sets have distinct values, then they are
+ * from different NSEC3 chains, and we do not want that. */
+ for(rrset=filter_first(flt, &rrsetnum, &rrnum); rrset;
+ rrset=filter_next(flt, &rrsetnum, &rrnum)) {
+ if(!have_params) {
+ first_algo = nsec3_get_algo(rrset, rrnum);
+ first_iter = nsec3_get_iter(rrset, rrnum);
+ if(!nsec3_get_salt(rrset, rrnum, &first_salt,
+ &first_saltlen)) {
+ verbose(VERB_ALGO, "NSEC3 salt malformed");
+ if(reason)
+ *reason = "NSEC3 salt malformed";
+ return 0;
+ }
+ have_params = 1;
+ } else {
+ uint8_t* salt = NULL;
+ size_t saltlen = 0;
+ if(nsec3_get_algo(rrset, rrnum) != first_algo) {
+ verbose(VERB_ALGO, "NSEC3 algorithm mismatch");
+ if(reason)
+ *reason = "NSEC3 algorithm mismatch";
+ return 0;
+ }
+ if(nsec3_get_iter(rrset, rrnum) != first_iter) {
+ verbose(VERB_ALGO, "NSEC3 iterations mismatch");
+ if(reason)
+ *reason = "NSEC3 iterations mismatch";
+ return 0;
+ }
+ if(!nsec3_get_salt(rrset, rrnum, &salt, &saltlen)) {
+ verbose(VERB_ALGO, "NSEC3 salt malformed");
+ if(reason)
+ *reason = "NSEC3 salt malformed";
+ return 0;
+ }
+ if(saltlen != first_saltlen ||
+ memcmp(salt, first_salt, saltlen) != 0) {
+ verbose(VERB_ALGO, "NSEC3 salt mismatch");
+ if(reason)
+ *reason = "NSEC3 salt mismatch";
+ return 0;
+ }
+ }
+ }
+ return 1;
+}
+
/**
* Find max iteration count using config settings and key size
* @param ve: validator environment with iteration count config settings.
@@ -1192,6 +1248,8 @@ nsec3_prove_nameerror(struct module_env* env, struct val_env* ve,
filter_init(&flt, list, num, qinfo); /* init RR iterator */
if(!flt.zone)
return sec_status_bogus; /* no RRs */
+ if(!param_set_same(&flt, NULL))
+ return sec_status_bogus; /* nsec3 params from distinct chains*/
if(nsec3_iteration_count_high(ve, &flt, kkey))
return sec_status_insecure; /* iteration count too high */
log_nametypeclass(VERB_ALGO, "start nsec3 nameerror proof, zone",
@@ -1378,6 +1436,8 @@ nsec3_prove_nodata(struct module_env* env, struct val_env* ve,
filter_init(&flt, list, num, qinfo); /* init RR iterator */
if(!flt.zone)
return sec_status_bogus; /* no RRs */
+ if(!param_set_same(&flt, NULL))
+ return sec_status_bogus; /* nsec3 params from distinct chains*/
if(nsec3_iteration_count_high(ve, &flt, kkey))
return sec_status_insecure; /* iteration count too high */
return nsec3_do_prove_nodata(env, &flt, ct, qinfo, calc);
@@ -1401,6 +1461,8 @@ nsec3_prove_wildcard(struct module_env* env, struct val_env* ve,
filter_init(&flt, list, num, qinfo); /* init RR iterator */
if(!flt.zone)
return sec_status_bogus; /* no RRs */
+ if(!param_set_same(&flt, NULL))
+ return sec_status_bogus; /* nsec3 params from distinct chains*/
if(nsec3_iteration_count_high(ve, &flt, kkey))
return sec_status_insecure; /* iteration count too high */
@@ -1503,6 +1565,8 @@ nsec3_prove_nods(struct module_env* env, struct val_env* ve,
*reason = "no NSEC3 records";
return sec_status_bogus; /* no RRs */
}
+ if(!param_set_same(&flt, reason))
+ return sec_status_bogus; /* nsec3 params from distinct chains*/
if(nsec3_iteration_count_high(ve, &flt, kkey))
return sec_status_insecure; /* iteration count too high */
@@ -1596,6 +1660,8 @@ nsec3_prove_nxornodata(struct module_env* env, struct val_env* ve,
filter_init(&flt, list, num, qinfo); /* init RR iterator */
if(!flt.zone)
return sec_status_bogus; /* no RRs */
+ if(!param_set_same(&flt, NULL))
+ return sec_status_bogus; /* nsec3 params from distinct chains*/
if(nsec3_iteration_count_high(ve, &flt, kkey))
return sec_status_insecure; /* iteration count too high */
diff --git a/validator/val_nsec3.h b/validator/val_nsec3.h
index f668a270ff12..a13e92991106 100644
--- a/validator/val_nsec3.h
+++ b/validator/val_nsec3.h
@@ -99,6 +99,12 @@ struct sldns_buffer;
#define NSEC3_HASH_SHA1 0x01
/**
+ * Max number of NSEC3 calculations at once, suspend query for later.
+ * 8 is low enough and allows for cases where multiple proofs are needed.
+ */
+#define MAX_NSEC3_CALCULATIONS 8
+
+/**
* Cache table for NSEC3 hashes.
* It keeps a *pointer* to the region its items are allocated.
*/
diff --git a/validator/val_utils.c b/validator/val_utils.c
index 411a63b25c5b..8e4c9190043d 100644
--- a/validator/val_utils.c
+++ b/validator/val_utils.c
@@ -1066,10 +1066,10 @@ val_fill_reply(struct reply_info* chase, struct reply_info* orig,
if(query_dname_compare(name,
orig->rrsets[i]->rk.dname) == 0)
chase->rrsets[chase->an_numrrsets
- +orig->ns_numrrsets+chase->ar_numrrsets++]
+ +chase->ns_numrrsets+chase->ar_numrrsets++]
= orig->rrsets[i];
} else if(rrset_has_signer(orig->rrsets[i], name, len)) {
- chase->rrsets[chase->an_numrrsets+orig->ns_numrrsets+
+ chase->rrsets[chase->an_numrrsets+chase->ns_numrrsets+
chase->ar_numrrsets++] = orig->rrsets[i];
}
}