/* Open resolution context */
ctx->trust_anchors = trie_create(NULL);
ctx->negative_anchors = trie_create(NULL);
+ ctx->vld_limit_crypto = KR_VLD_LIMIT_CRYPTO_DEFAULT;
ctx->pool = engine->pool;
ctx->modules = &engine->modules;
ctx->cache_rtt_tout_retry_interval = KR_NS_TIMEOUT_RETRY_INTERVAL;
struct kr_qflags forward_flags;
uint32_t secret;
uint32_t uid;
+ int32_t vld_limit_crypto_remains;
+ uint32_t vld_limit_uid;
uint64_t creation_time_mono;
uint64_t timestamp_mono;
struct timeval timestamp;
knot_rrset_t *upstream_opt_rr;
trie_t *trust_anchors;
trie_t *negative_anchors;
+ int32_t vld_limit_crypto;
struct kr_zonecut root_hints;
struct kr_cache cache;
unsigned int cache_rtt_tout_retry_interval;
struct kr_qflags forward_flags;
uint32_t secret;
uint32_t uid;
+ int32_t vld_limit_crypto_remains;
+ uint32_t vld_limit_uid;
uint64_t creation_time_mono;
uint64_t timestamp_mono;
struct timeval timestamp;
knot_rrset_t *upstream_opt_rr;
trie_t *trust_anchors;
trie_t *negative_anchors;
+ int32_t vld_limit_crypto;
struct kr_zonecut root_hints;
struct kr_cache cache;
unsigned int cache_rtt_tout_retry_interval;
struct kr_qflags forward_flags;
uint32_t secret;
uint32_t uid;
+ int32_t vld_limit_crypto_remains;
+ uint32_t vld_limit_uid;
uint64_t creation_time_mono;
uint64_t timestamp_mono;
struct timeval timestamp;
knot_rrset_t *upstream_opt_rr;
trie_t *trust_anchors;
trie_t *negative_anchors;
+ int32_t vld_limit_crypto;
struct kr_zonecut root_hints;
struct kr_cache cache;
unsigned int cache_rtt_tout_retry_interval;
#define KR_COUNT_NO_NSADDR_LIMIT 5
#define KR_CONSUME_FAIL_ROW_LIMIT 3 /* Maximum number of KR_STATE_FAIL in a row. */
+#define KR_VLD_LIMIT_CRYPTO_DEFAULT 32 /**< default for struct kr_query::vld_limit_crypto */
+
/*
* Defines.
*/
return NULL;
}
+/// Return if we want to afford yet another crypto-validation (and account it).
+static bool check_crypto_limit(const kr_rrset_validation_ctx_t *vctx)
+{
+ if (vctx->limit_crypto_remains == NULL)
+ return true; // no limiting
+ if (*vctx->limit_crypto_remains > 0) {
+ --*vctx->limit_crypto_remains;
+ return true;
+ }
+ // We got over limit. There are optional actions to do.
+ if (vctx->log_qry && kr_log_is_debug_qry(VALIDATOR, vctx->log_qry)) {
+ auto_free char *name_str = kr_dname_text(vctx->zone_name);
+ kr_log_q(vctx->log_qry, VALIDATOR,
+ "expensive crypto limited, mitigating CVE-2023-50387, current zone: %s\n",
+ name_str);
+ }
+ if (vctx->log_qry && vctx->log_qry->request) {
+ kr_request_set_extended_error(vctx->log_qry->request, KNOT_EDNS_EDE_BOGUS,
+ "EAIE: expensive crypto limited, mitigating CVE-2023-50387");
+ }
+ return false;
+}
+
static int kr_svldr_rrset_with_key(knot_rrset_t *rrs, const knot_rdataset_t *rrsigs,
kr_rrset_validation_ctx_t *vctx, const kr_svldr_key_t *key)
{
} else if (retv != 0) {
continue;
}
+ if (!check_crypto_limit(vctx))
+ return vctx->result = kr_error(E2BIG);
// We only expect non-expanded wildcard records in input;
// that also means we don't need to perform non-existence proofs.
const int trim_labels = (val_flgs & FLG_WILDCARD_EXPANSION) ? 1 : 0;
break;
}
}
+ if (!check_crypto_limit(vctx)) {
+ goto finish;
+ }
if (kr_check_signature(rdata_j, key, covered, trim_labels) != 0) {
vctx->rrs_counters.crypto_invalid++;
continue;
uint32_t flags; /*!< Output - Flags. */
uint32_t err_cnt; /*!< Output - Number of validation failures. */
uint32_t cname_norrsig_cnt; /*!< Output - Number of CNAMEs missing RRSIGs. */
+ int32_t *limit_crypto_remains; /*!< Optional pointer to struct kr_query::vld_limit_crypto_remains */
/** Validation result: kr_error() code.
*
.err_cnt = 0,
.cname_norrsig_cnt = 0,
.result = 0,
+ .limit_crypto_remains = &qry->vld_limit_crypto_remains,
.log_qry = qry,
};
.has_nsec3 = has_nsec3,
.flags = 0,
.result = 0,
+ .limit_crypto_remains = &qry->vld_limit_crypto_remains,
.log_qry = qry,
};
int ret = kr_dnskeys_trusted(&vctx, sig_rds, qry->zone_cut.trust_anchor);
struct kr_request *req = ctx->req;
struct kr_query *qry = req->current_query;
+ if (qry->vld_limit_uid != qry->uid) {
+ qry->vld_limit_uid = qry->uid;
+ qry->vld_limit_crypto_remains = req->ctx->vld_limit_crypto;
+ }
+
/* Ignore faulty or unprocessed responses. */
if (ctx->state & (KR_STATE_FAIL|KR_STATE_CONSUME)) {
return ctx->state;
trie_t *trust_anchors;
trie_t *negative_anchors;
+ /** Validator's limit on the number of cryptographic steps for a single upstream packet. */
+ int32_t vld_limit_crypto;
+
struct kr_zonecut root_hints;
struct kr_cache cache;
unsigned cache_rtt_tout_retry_interval;
struct kr_qflags forward_flags;
uint32_t secret;
uint32_t uid; /**< Query iteration number, unique within the kr_rplan. */
+
+ /** Remaining limit; see kr_query::vld_limit_crypto docs */
+ int32_t vld_limit_crypto_remains;
+ /** ::uid value to which this remaining limit applies. */
+ uint32_t vld_limit_uid;
+
uint64_t creation_time_mono; /* The time of query's creation (milliseconds).
* Or time of creation of an oldest
* ancestor if it is a subquery. */