* SPDX-License-Identifier: GPL-3.0-or-later
*/
-#include <assert.h>
#include <string.h>
#include <libdnssec/binary.h>
#include "lib/defines.h"
#include "lib/dnssec/nsec.h"
#include "lib/dnssec/nsec3.h"
+#include "lib/utils.h"
#define OPT_OUT_BIT 0x01
*/
static int nsec3_parameters(dnssec_nsec3_params_t *params, const knot_rrset_t *nsec3)
{
- assert(params && nsec3);
+ if (!kr_assume(params && nsec3))
+ return kr_error(EINVAL);
const knot_rdata_t *rr = knot_rdataset_at(&nsec3->rrs, 0);
- assert(rr);
+ if (!kr_assume(rr))
+ return kr_error(EINVAL);
/* Every NSEC3 RR contains data from NSEC3PARAMS. */
const size_t SALT_OFFSET = 5; /* First 5 octets contain { Alg, Flags, Iterations, Salt length } */
return kr_error(EMSGSIZE);
int ret = dnssec_nsec3_params_from_rdata(params, &rdata);
- if (ret != DNSSEC_EOK) {
+ if (ret != DNSSEC_EOK)
return kr_error(EINVAL);
- }
return kr_ok();
}
static int hash_name(dnssec_binary_t *hash, const dnssec_nsec3_params_t *params,
const knot_dname_t *name)
{
- assert(hash && params);
+ if (!kr_assume(hash && params))
+ return kr_error(EINVAL);
if (!name)
return kr_error(EINVAL);
- if (params->iterations > KR_NSEC3_MAX_ITERATIONS) {
- assert(false); // This if is mainly defensive; it shouldn't happen.
+ if (!kr_assume(params->iterations <= KR_NSEC3_MAX_ITERATIONS)) {
+ /* This if is mainly defensive; it shouldn't happen. */
return kr_error(EINVAL);
}
*/
static int read_owner_hash(dnssec_binary_t *hash, size_t max_hash_size, const knot_rrset_t *nsec3)
{
- assert(hash && nsec3);
- assert(hash->data);
+ if (!kr_assume(hash && nsec3 && hash->data))
+ return kr_error(EINVAL);
int32_t ret = base32hex_decode(nsec3->owner + 1, nsec3->owner[0], hash->data, max_hash_size);
- if (ret < 0) {
+ if (ret < 0)
return kr_error(EILSEQ);
- }
hash->size = ret;
return kr_ok();
static int closest_encloser_match(int *flags, const knot_rrset_t *nsec3,
const knot_dname_t *name, unsigned *skipped)
{
- assert(flags && nsec3 && name && skipped);
+ if (!kr_assume(flags && nsec3 && name && skipped))
+ return kr_error(EINVAL);
uint8_t hash_data[MAX_HASH_BYTES] = {0, };
dnssec_binary_t owner_hash = { 0, hash_data };
dnssec_binary_t name_hash = { 0, };
int ret = read_owner_hash(&owner_hash, MAX_HASH_BYTES, nsec3);
- if (ret != 0) {
+ if (ret != 0)
goto fail;
- }
ret = nsec3_parameters(¶ms, nsec3);
- if (ret != 0) {
+ if (ret != 0)
goto fail;
- }
/* Root label has no encloser */
if (!name[0]) {
while(encloser) {
ret = hash_name(&name_hash, ¶ms, encloser);
- if (ret != 0) {
+ if (ret != 0)
goto fail;
- }
if ((owner_hash.size == name_hash.size) &&
(memcmp(owner_hash.data, name_hash.data, owner_hash.size) == 0)) {
ret = kr_ok();
fail:
- if (params.salt.data) {
+ if (params.salt.data)
dnssec_nsec3_params_free(¶ms);
- }
- if (name_hash.data) {
+ if (name_hash.data)
dnssec_binary_free(&name_hash);
- }
return ret;
}
*/
static int covers_name(int *flags, const knot_rrset_t *nsec3, const knot_dname_t *name)
{
- assert(flags && nsec3 && name);
+ if (!kr_assume(flags && nsec3 && name))
+ return kr_error(EINVAL);
uint8_t hash_data[MAX_HASH_BYTES] = { 0, };
dnssec_binary_t owner_hash = { 0, hash_data };
dnssec_binary_t name_hash = { 0, };
int ret = read_owner_hash(&owner_hash, MAX_HASH_BYTES, nsec3);
- if (ret != 0) {
+ if (ret != 0)
goto fail;
- }
ret = nsec3_parameters(¶ms, nsec3);
- if (ret != 0) {
+ if (ret != 0)
goto fail;
- }
ret = hash_name(&name_hash, ¶ms, name);
- if (ret != 0) {
+ if (ret != 0)
goto fail;
- }
uint8_t next_size = knot_nsec3_next_len(nsec3->rrs.rdata);
const uint8_t *next_hash = knot_nsec3_next(nsec3->rrs.rdata);
}
fail:
- if (params.salt.data) {
+ if (params.salt.data)
dnssec_nsec3_params_free(¶ms);
- }
- if (name_hash.data) {
+ if (name_hash.data)
dnssec_binary_free(&name_hash);
- }
return ret;
}
*/
static bool has_optout(const knot_rrset_t *nsec3)
{
- if (!nsec3) {
+ if (!nsec3)
return false;
- }
uint8_t nsec3_flags = knot_nsec3_flags(nsec3->rrs.rdata);
if (nsec3_flags & ~OPT_OUT_BIT) {
*/
static int matches_name(const knot_rrset_t *nsec3, const knot_dname_t *name)
{
- assert(nsec3 && name);
+ if (!kr_assume(nsec3 && name))
+ return kr_error(EINVAL);
uint8_t hash_data[MAX_HASH_BYTES] = { 0, };
dnssec_binary_t owner_hash = { 0, hash_data };
dnssec_binary_t name_hash = { 0, };
int ret = read_owner_hash(&owner_hash, MAX_HASH_BYTES, nsec3);
- if (ret != 0) {
+ if (ret != 0)
goto fail;
- }
ret = nsec3_parameters(¶ms, nsec3);
- if (ret != 0) {
+ if (ret != 0)
goto fail;
- }
ret = hash_name(&name_hash, ¶ms, name);
- if (ret != 0) {
+ if (ret != 0)
goto fail;
- }
if ((owner_hash.size == name_hash.size) &&
(memcmp(owner_hash.data, name_hash.data, owner_hash.size) == 0)) {
}
fail:
- if (params.salt.data) {
+ if (params.salt.data)
dnssec_nsec3_params_free(¶ms);
- }
- if (name_hash.data) {
+ if (name_hash.data)
dnssec_binary_free(&name_hash);
- }
return ret;
}
#undef MAX_HASH_BYTES
*/
static int prepend_asterisk(uint8_t *tgt, size_t maxlen, const knot_dname_t *name)
{
- assert(maxlen >= 3);
+ if (!kr_assume(maxlen >= 3))
+ return kr_error(EINVAL);
memcpy(tgt, "\1*", 3);
return knot_dname_to_wire(tgt + 2, name, maxlen - 2);
}
const knot_rrset_t **covering_next_nsec3)
{
const knot_pktsection_t *sec = knot_pkt_section(pkt, section_id);
- if (!sec || !sname) {
+ if (!sec || !sname)
return kr_error(EINVAL);
- }
const knot_rrset_t *matching = NULL;
const knot_rrset_t *covering = NULL;
const knot_dname_t *next_closer = NULL;
for (unsigned i = 0; i < sec->count; ++i) {
const knot_rrset_t *rrset = knot_pkt_rr(sec, i);
- if (rrset->type != KNOT_RRTYPE_NSEC3) {
+ if (rrset->type != KNOT_RRTYPE_NSEC3)
continue;
- }
/* Also skip the NSEC3-to-match an ancestor of sname if it's
* a parent-side delegation, as that would mean the owner
* does not really exist (authoritatively in this zone,
*/
const uint8_t *bm = knot_nsec3_bitmap(rrset->rrs.rdata);
uint16_t bm_size = knot_nsec3_bitmap_len(rrset->rrs.rdata);
- if (kr_nsec_children_in_zone_check(bm, bm_size) != 0) {
+ if (kr_nsec_children_in_zone_check(bm, bm_size) != 0)
continue; /* no fatal errors from bad RRs */
- }
/* Match the NSEC3 to sname or one of its ancestors. */
unsigned skipped = 0;
flags = 0;
int ret = closest_encloser_match(&flags, rrset, sname, &skipped);
- if (ret != 0) {
+ if (ret != 0)
return ret;
- }
- if (!(flags & FLG_CLOSEST_PROVABLE_ENCLOSER)) {
+ if (!(flags & FLG_CLOSEST_PROVABLE_ENCLOSER))
continue;
- }
matching = rrset;
/* Construct the next closer name and try to cover it. */
--skipped;
next_closer = sname;
for (unsigned j = 0; j < skipped; ++j) {
- assert(next_closer[0]);
+ if (!kr_assume(next_closer[0]))
+ return kr_error(EINVAL);
next_closer = knot_wire_next_label(next_closer, NULL);
}
for (unsigned j = 0; j < sec->count; ++j) {
const knot_rrset_t *rrset_j = knot_pkt_rr(sec, j);
- if (rrset_j->type != KNOT_RRTYPE_NSEC3) {
+ if (rrset_j->type != KNOT_RRTYPE_NSEC3)
continue;
- }
ret = covers_name(&flags, rrset_j, next_closer);
- if (ret != 0) {
+ if (ret != 0)
return ret;
- }
if (flags & FLG_NAME_COVERED) {
covering = rrset_j;
break;
}
}
- if (flags & FLG_NAME_COVERED) {
+ if (flags & FLG_NAME_COVERED)
break;
- }
flags = 0; //
}
if ((flags & FLG_CLOSEST_PROVABLE_ENCLOSER) && (flags & FLG_NAME_COVERED) && next_closer) {
- if (encloser_name && next_closer[0]) {
+ if (encloser_name && next_closer[0])
*encloser_name = knot_wire_next_label(next_closer, NULL);
- }
- if (matching_encloser_nsec3) {
+ if (matching_encloser_nsec3)
*matching_encloser_nsec3 = matching;
- }
- if (covering_next_nsec3) {
+ if (covering_next_nsec3)
*covering_next_nsec3 = covering;
- }
return kr_ok();
}
const knot_dname_t *encloser)
{
const knot_pktsection_t *sec = knot_pkt_section(pkt, section_id);
- if (!sec || !encloser) {
+ if (!sec || !encloser)
return kr_error(EINVAL);
- }
uint8_t wildcard[KNOT_DNAME_MAXLEN];
wildcard[0] = 1;
wildcard[1] = '*';
int encloser_len = knot_dname_size(encloser);
- if (encloser_len < 0) {
+ if (encloser_len < 0)
return encloser_len;
- }
memcpy(wildcard + 2, encloser, encloser_len);
int flags = 0;
for (unsigned i = 0; i < sec->count; ++i) {
const knot_rrset_t *rrset = knot_pkt_rr(sec, i);
- if (rrset->type != KNOT_RRTYPE_NSEC3) {
+ if (rrset->type != KNOT_RRTYPE_NSEC3)
continue;
- }
int ret = covers_name(&flags, rrset, wildcard);
- if (ret != 0) {
+ if (ret != 0)
return ret;
- }
if (flags & FLG_NAME_COVERED) {
return has_optout(rrset) ?
kr_error(KNOT_ERANGE) : kr_ok();
const knot_rrset_t *covering_next_nsec3 = NULL;
int ret = closest_encloser_proof(pkt, section_id, sname,
&encloser, NULL, &covering_next_nsec3);
- if (ret != 0) {
+ if (ret != 0)
return ret;
- }
ret = covers_closest_encloser_wildcard(pkt, section_id, encloser);
if (ret != 0) {
/* OK, but NSEC3 for wildcard at encloser has opt-out;
const knot_dname_t *name, const uint16_t type)
{
const knot_pktsection_t *sec = knot_pkt_section(pkt, section_id);
- if (!sec || !name) {
+ if (!sec || !name)
return kr_error(EINVAL);
- }
for (unsigned i = 0; i < sec->count; ++i) {
const knot_rrset_t *nsec3 = knot_pkt_rr(sec, i);
const uint8_t *bm = knot_nsec3_bitmap(nsec3->rrs.rdata);
uint16_t bm_size = knot_nsec3_bitmap_len(nsec3->rrs.rdata);
- if (kr_nsec_bitmap_nodata_check(bm, bm_size, type, nsec3->owner) == kr_ok()) {
+ if (kr_nsec_bitmap_nodata_check(bm, bm_size, type, nsec3->owner) == kr_ok())
return kr_ok();
- }
}
return kr_error(ENOENT);
const knot_dname_t *encloser, uint16_t stype)
{
const knot_pktsection_t *sec = knot_pkt_section(pkt, section_id);
- if (!sec || !encloser) {
+ if (!sec || !encloser)
return kr_error(EINVAL);
- }
uint8_t wildcard[KNOT_DNAME_MAXLEN]; /**< the source of synthesis */
int ret = prepend_asterisk(wildcard, sizeof(wildcard), encloser);
- if (ret < 0) {
+ if (ret < 0)
return ret;
- }
- assert(ret >= 3);
+ kr_require(ret >= 3);
return nodata_find(pkt, section_id, wildcard, stype);
}
const knot_dname_t *sname, int trim_to_next)
{
const knot_pktsection_t *sec = knot_pkt_section(pkt, section_id);
- if (!sec || !sname) {
+ if (!sec || !sname)
return kr_error(EINVAL);
- }
/* Compute the next closer name. */
for (int i = 0; i < trim_to_next; ++i) {
- assert(sname[0]);
+ if (!kr_assume(sname[0]))
+ return kr_error(EINVAL);
sname = knot_wire_next_label(sname, NULL);
}
int flags = 0;
for (unsigned i = 0; i < sec->count; ++i) {
const knot_rrset_t *rrset = knot_pkt_rr(sec, i);
- if (rrset->type != KNOT_RRTYPE_NSEC3) {
+ if (rrset->type != KNOT_RRTYPE_NSEC3)
continue;
- }
if (knot_nsec3_iters(rrset->rrs.rdata) > KR_NSEC3_MAX_ITERATIONS) {
/* Avoid hashing with too many iterations.
* If we get here, the `sname` wildcard probably ends up bogus,
continue;
}
int ret = covers_name(&flags, rrset, sname);
- if (ret != 0) {
+ if (ret != 0)
return ret;
- }
if (flags & FLG_NAME_COVERED) {
return has_optout(rrset) ?
kr_error(KNOT_ERANGE) : kr_ok();
const knot_rrset_t *covering_next_nsec3 = NULL;
ret = closest_encloser_proof(pkt, section_id, sname, &encloser_name,
NULL, &covering_next_nsec3);
- if (ret != 0) {
+ if (ret != 0)
return ret;
- }
- assert(encloser_name && covering_next_nsec3);
+ if (!kr_assume(encloser_name && covering_next_nsec3))
+ return kr_error(EFAULT);
ret = matches_closest_encloser_wildcard(pkt, section_id,
encloser_name, stype);
if (ret == 0) {
/* Bogus */
ret = kr_error(ENOENT);
} else {
- /*
+ /*
* Satisfies RFC5155 8.6 (QTYPE == DS), 2nd paragraph.
* Also satisfies ERRATA 3441 8.5 (QTYPE != DS), 3rd paragraph.
* - (wildcard) empty nonterminal
int kr_nsec3_ref_to_unsigned(const knot_pkt_t *pkt)
{
const knot_pktsection_t *sec = knot_pkt_section(pkt, KNOT_AUTHORITY);
- if (!sec) {
+ if (!sec)
return kr_error(EINVAL);
- }
for (unsigned i = 0; i < sec->count; ++i) {
const knot_rrset_t *ns = knot_pkt_rr(sec, i);
- if (ns->type == KNOT_RRTYPE_DS) {
+ if (ns->type == KNOT_RRTYPE_DS)
return kr_error(EEXIST);
- }
- if (ns->type != KNOT_RRTYPE_NS) {
+ if (ns->type != KNOT_RRTYPE_NS)
continue;
- }
int flags = 0;
bool nsec3_found = false;
for (unsigned j = 0; j < sec->count; ++j) {
const knot_rrset_t *nsec3 = knot_pkt_rr(sec, j);
- if (nsec3->type == KNOT_RRTYPE_DS) {
+ if (nsec3->type == KNOT_RRTYPE_DS)
return kr_error(EEXIST);
- }
- if (nsec3->type != KNOT_RRTYPE_NSEC3) {
+ if (nsec3->type != KNOT_RRTYPE_NSEC3)
continue;
- }
nsec3_found = true;
/* nsec3 found, check if owner name matches the delegation name.
* Just skip in case of *any* errors. */
- if (matches_name(nsec3, ns->owner) != kr_ok()) {
+ if (matches_name(nsec3, ns->owner) != kr_ok())
continue;
- }
const uint8_t *bm = knot_nsec3_bitmap(nsec3->rrs.rdata);
uint16_t bm_size = knot_nsec3_bitmap_len(nsec3->rrs.rdata);
- if (!bm) {
+ if (!bm)
return kr_error(EINVAL);
- }
if (dnssec_nsec_bitmap_contains(bm, bm_size,
KNOT_RRTYPE_NS) &&
!dnssec_nsec_bitmap_contains(bm, bm_size,
return kr_ok();
}
}
- if (!nsec3_found) {
+ if (!nsec3_found)
return kr_error(DNSSEC_NOT_FOUND);
- }
if (flags & FLG_NAME_MATCHED) {
/* nsec3 which owner matches
* the delegation name was found,
const knot_rrset_t *covering_next_nsec3 = NULL;
int ret = closest_encloser_proof(pkt, KNOT_AUTHORITY, ns->owner,
&encloser_name, NULL, &covering_next_nsec3);
- if (ret != 0) {
+ if (ret != 0)
return kr_error(EINVAL);
- }
if (has_optout(covering_next_nsec3)) {
return kr_error(KNOT_ERANGE);
/* It's not secure enough to just check a single bit for (some) other types,
* but we don't (currently) only use this API for NS. See RFC 6840 sec. 4.
*/
- if (type != KNOT_RRTYPE_NS) {
- assert(!EINVAL);
+ if (!kr_assume(type == KNOT_RRTYPE_NS))
return kr_error(EINVAL);
- }
int ret = matches_name(nsec3, name);
- if (ret) {
+ if (ret)
return kr_error(ret);
- }
const uint8_t *bm = knot_nsec3_bitmap(nsec3->rrs.rdata);
uint16_t bm_size = knot_nsec3_bitmap_len(nsec3->rrs.rdata);
- if (!bm) {
+ if (!bm)
return kr_error(EINVAL);
- }
if (dnssec_nsec_bitmap_contains(bm, bm_size, type)) {
return kr_ok();
} else {