#include <libknot/rdataset.h>
#include <libknot/rrset.h>
#include <libknot/rrtype/dnskey.h>
+#include <libknot/rrtype/nsec.h>
#include <libknot/rrtype/rrsig.h>
if (trim_labels > 0) {
/**/
for (int i = 0; i < trim_labels; ++i) {
- owner = knot_wire_next_label(owner, NULL);
+ owner = (uint8_t *) knot_wire_next_label(owner, NULL);
}
*(--owner) = '*';
*(--owner) = 1;
}
+
dnssec_binary_t rrset_wire = { 0 };
rrset_wire.size = written - (owner - rrwf);
rrset_wire.data = owner;
return knot_dname_labels(expanded, NULL) - knot_rrsig_labels(&rrsigs->rrs, sig_pos);
}
-int kr_rrset_validate(const knot_pktsection_t *sec, const knot_rrset_t *covered,
- const knot_rrset_t *keys, const knot_dname_t *zone_name, uint32_t timestamp)
+/* RFC4035 5.4, bullet 2 */
+static int nsec_nomatch_validate(const knot_rrset_t *nsec, const knot_dname_t *name)
+{
+ const knot_dname_t *next = knot_nsec_next(&nsec->rrs);
+
+ if ((knot_dname_cmp(nsec->owner, name) < 0) &&
+ (knot_dname_cmp(name, next) < 0)) {
+ return kr_ok();
+ } else {
+ return 1;
+ }
+
+#warning TODO: Is an additional request for NSEC name or wildcard necessary?
+}
+
+/**
+ * Validates the non-existence of closer/exact match.
+ * @param pkt Packet to be validated.
+ * @param section_id Section to work with.
+ * @param name The name to be checked.
+ * @return 0 or error code.
+ */
+static int closer_match_nonexistence_validate(const knot_pkt_t *pkt, knot_section_t section_id,
+ const knot_dname_t *name)
+{
+ if (!pkt || !name) {
+ return kr_error(EINVAL);
+ }
+
+ /* Signatures are checked elsewhere. */
+
+ const knot_pktsection_t *sec = knot_pkt_section(pkt, section_id);
+ if (!sec) {
+ return kr_error(EINVAL);
+ }
+ for (unsigned i = 0; i < sec->count; ++i) {
+ const knot_rrset_t *rrset = knot_pkt_rr(sec, i);
+ if ((rrset->type != KNOT_RRTYPE_NSEC) &&
+ (rrset->type != KNOT_RRTYPE_NSEC3)) {
+ continue;
+ }
+ if (rrset->type == KNOT_RRTYPE_NSEC) {
+ if (nsec_nomatch_validate(rrset, name) == 0) {
+ return kr_ok();
+ }
+ } else {
+#warning TODO: NSEC3 currently not supported
+ return kr_error(ENOSYS);
+ }
+ }
+
+ return kr_error(EINVAL);
+}
+
+int kr_rrset_validate(const knot_pkt_t *pkt, knot_section_t section_id,
+ const knot_rrset_t *covered, const knot_rrset_t *keys,
+ const knot_dname_t *zone_name, uint32_t timestamp)
{
- if (!sec || !covered || !keys || !zone_name) {
+ if (!pkt || !covered || !keys || !zone_name) {
return kr_error(EINVAL);
}
int ret = kr_error(KNOT_DNSSEC_ENOKEY);
for (unsigned i = 0; i < keys->rrs.rr_count; ++i) {
- ret = kr_rrset_validate_with_key(sec, covered, keys, i, NULL, zone_name, timestamp);
+ ret = kr_rrset_validate_with_key(pkt, section_id, covered, keys, i, NULL, zone_name, timestamp);
if (ret == 0) {
break;
}
return ret;
}
-int kr_rrset_validate_with_key(const knot_pktsection_t *sec, const knot_rrset_t *covered,
- const knot_rrset_t *keys, size_t key_pos, const struct dseckey *key,
+int kr_rrset_validate_with_key(const knot_pkt_t *pkt, knot_section_t section_id,
+ const knot_rrset_t *covered, const knot_rrset_t *keys,
+ size_t key_pos, const struct dseckey *key,
const knot_dname_t *zone_name, uint32_t timestamp)
{
int ret;
}
ret = kr_error(KNOT_DNSSEC_ENOKEY);
+ const knot_pktsection_t *sec = knot_pkt_section(pkt, section_id);
for (unsigned i = 0; i < sec->count; ++i) {
/* Try every RRSIG. */
const knot_rrset_t *rrsig = knot_pkt_rr(sec, i);
if (check_signature(rrsig, j, (dnssec_key_t *) key, covered, trim_labels) != 0) {
continue;
}
+ if (val_flgs & FLG_WILDCARD_EXPANSION) {
+ if (closer_match_nonexistence_validate(pkt, KNOT_AUTHORITY, covered->owner) != 0) {
+ continue;
+ }
+ }
ret = kr_ok();
break;
}
return ret;
}
-int kr_dnskeys_trusted(const knot_pktsection_t *sec, const knot_rrset_t *keys,
+int kr_dnskeys_trusted(const knot_pkt_t *pkt, knot_section_t section_id, const knot_rrset_t *keys,
const knot_rrset_t *ta, const knot_dname_t *zone_name, uint32_t timestamp)
{
- if (!sec || !keys || !ta) {
+ if (!pkt || !keys || !ta) {
return kr_error(EINVAL);
}
kr_dnssec_key_free(&key);
continue;
}
- if (kr_rrset_validate_with_key(sec, keys, keys, i, key, zone_name, timestamp) != 0) {
+ if (kr_rrset_validate_with_key(pkt, section_id, keys, keys, i, key, zone_name, timestamp) != 0) {
kr_dnssec_key_free(&key);
continue;
}
/**
* Validate RRSet.
- * @param sec Packet section containing the RRSet to be validated.
- * @param covered RRSet covered by a signature. It must be in canonical format.
- * @param keys DNSKEY RRSet.
- * @param zone_name Name of the zone containing the RRSIG RRSet.
- * @param timestamp Validation time.
- * @return 0 or error code.
+ * @param pkt Packet to be validated.
+ * @param section_id Section to work with.
+ * @param covered RRSet covered by a signature. It must be in canonical format.
+ * @param keys DNSKEY RRSet.
+ * @param zone_name Name of the zone containing the RRSIG RRSet.
+ * @param timestamp Validation time.
+ * @return 0 or error code.
*/
-int kr_rrset_validate(const knot_pktsection_t *sec, const knot_rrset_t *covered,
- const knot_rrset_t *keys, const knot_dname_t *zone_name, uint32_t timestamp);
+int kr_rrset_validate(const knot_pkt_t *pkt, knot_section_t section_id,
+ const knot_rrset_t *covered, const knot_rrset_t *keys,
+ const knot_dname_t *zone_name, uint32_t timestamp);
/**
- * Validate RRSet usins a specific key.
- * @param sec Packet section containing the RRSet to be validated.
- * @param covered RRSet covered by a signature. It must be in canonical format.
- * @param keys DNSKEY RRSet.
- * @param key_pos Position of the key to be validated with.
- * @param key Key to be used to validate. If NULL, then key from DNSKEY RRSet is used.
- * @param zone_name Name of the zone containing the RRSIG RRSet.
- * @param timestamp Validation time.
- * @return 0 or error code.
+ * Validate RRSet using a specific key.
+ * @param pkt Packet to be validated.
+ * @param section_id Section to work with.
+ * @param covered RRSet covered by a signature. It must be in canonical format.
+ * @param keys DNSKEY RRSet.
+ * @param key_pos Position of the key to be validated with.
+ * @param key Key to be used to validate. If NULL, then key from DNSKEY RRSet is used.
+ * @param zone_name Name of the zone containing the RRSIG RRSet.
+ * @param timestamp Validation time.
+ * @return 0 or error code.
*/
-int kr_rrset_validate_with_key(const knot_pktsection_t *sec, const knot_rrset_t *covered,
- const knot_rrset_t *keys, size_t key_pos, const struct dseckey *key,
+int kr_rrset_validate_with_key(const knot_pkt_t *pkt, knot_section_t section_id,
+ const knot_rrset_t *covered, const knot_rrset_t *keys,
+ size_t key_pos, const struct dseckey *key,
const knot_dname_t *zone_name, uint32_t timestamp);
/**
* Check whether the DNSKEY rrset matches the supplied trust anchor RRSet.
- * @param sec Packet section containing the DNSKEY RRSet including its signatures.
- * @param keys DNSKEY RRSet to check.
- * @param ta Trust anchor RRSet against which to validate the DNSKEY RRSet.
- * @param zone_name Name of the zone containing the RRSet.
- * @param timestamp Time stamp.
+ * @param pkt Packet to be validated.
+ * @param section_id Section to work with.
+ * @param keys DNSKEY RRSet to check.
+ * @param ta Trust anchor RRSet against which to validate the DNSKEY RRSet.
+ * @param zone_name Name of the zone containing the RRSet.
+ * @param timestamp Time stamp.
* @return 0 or error code.
*/
-int kr_dnskeys_trusted(const knot_pktsection_t *sec, const knot_rrset_t *keys,
+int kr_dnskeys_trusted(const knot_pkt_t *pkt, knot_section_t section_id, const knot_rrset_t *keys,
const knot_rrset_t *ta, const knot_dname_t *zone_name, uint32_t timestamp);
/**
* change when updating cut information before validation.
*/
const knot_dname_t *zone_name = qry->zone_cut.key ? qry->zone_cut.key->owner : NULL;
- ret = kr_rrset_validate(sec, covered, qry->zone_cut.key, zone_name, qry->timestamp.tv_sec);
+ ret = kr_rrset_validate(answer, section_id, covered, qry->zone_cut.key, zone_name, qry->timestamp.tv_sec);
if (ret != 0) {
break;
}
#warning TODO: Ensure canonical format of the whole DNSKEY RRSet. (Also remove duplicities?)
/* Check if there's a key for current TA. */
- int ret = kr_dnskeys_trusted(an, qry->zone_cut.key, qry->zone_cut.trust_anchor, qry->zone_cut.name, qry->timestamp.tv_sec);
+ int ret = kr_dnskeys_trusted(answer, KNOT_ANSWER, qry->zone_cut.key,
+ qry->zone_cut.trust_anchor, qry->zone_cut.name,
+ qry->timestamp.tv_sec);
if (ret != 0) {
knot_rrset_free(&qry->zone_cut.key, qry->zone_cut.pool);
return ret;