Commit f9ffeca9 authored by Grigorii Demidov's avatar Grigorii Demidov Committed by Marek Vavrusa

lib/dnssec: nsec, nsec3 (no-optout) referrals to unsigned subzones

parent 5426dc70
......@@ -22,6 +22,7 @@
#include <libknot/rrset.h>
#include <libknot/rrtype/nsec.h>
#include <libknot/rrtype/rrsig.h>
#include <dnssec/error.h>
#include "lib/defines.h"
#include "lib/dnssec/nsec.h"
......@@ -325,3 +326,66 @@ int kr_nsec_existence_denial(const knot_pkt_t *pkt, knot_section_t section_id,
return kr_nsec_existence_denied(flags) ? kr_ok() : kr_error(ENOENT);
}
int kr_nsec_ref_to_unsigned(const knot_pkt_t *pkt)
{
int nsec_found = 0;
uint8_t *bm = NULL;
uint16_t bm_size = 0;
const knot_pktsection_t *sec = knot_pkt_section(pkt, KNOT_AUTHORITY);
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) {
return kr_error(EEXIST);
}
if (ns->type != KNOT_RRTYPE_NS) {
continue;
}
nsec_found = 0;
for (unsigned j = 0; j < sec->count; ++j) {
const knot_rrset_t *nsec = knot_pkt_rr(sec, j);
if (nsec->type == KNOT_RRTYPE_DS) {
return kr_error(EEXIST);
}
if (nsec->type != KNOT_RRTYPE_NSEC) {
continue;
}
/* nsec found
* check if owner name matches the delegation name
*/
if (knot_dname_is_equal(nsec->owner, ns->owner)) {
/* nsec does not match the delegation */
continue;
}
nsec_found = 1;
knot_nsec_bitmap(&nsec->rrs, &bm, &bm_size);
if (!bm) {
return kr_error(EINVAL);
}
if (kr_nsec_bitmap_contains_type(bm, bm_size,
KNOT_RRTYPE_NS) &&
!kr_nsec_bitmap_contains_type(bm, bm_size,
KNOT_RRTYPE_DS) &&
!kr_nsec_bitmap_contains_type(bm, bm_size,
KNOT_RRTYPE_SOA)) {
/* rfc4035, 5.2 */
return kr_ok();
}
}
if (nsec_found) {
/* nsec which owner matches
* the delegation name was found,
* but nsec type bitmap contains wrong types
*/
return kr_error(EINVAL);
} else {
/* nsec that matches delegation was not found */
return kr_error(DNSSEC_NOT_FOUND);
}
}
return kr_error(EINVAL);
}
......@@ -70,3 +70,15 @@ int kr_nsec_wildcard_answer_response_check(const knot_pkt_t *pkt, knot_section_t
*/
int kr_nsec_existence_denial(const knot_pkt_t *pkt, knot_section_t section_id,
const knot_dname_t *sname, uint16_t stype);
/**
* Referral to unsigned subzone check (RFC4035 5.2).
* @note No RRSIGs are validated.
* @param pkt Packet structure to be processed.
* @return 0 or error code:
* DNSSEC_NOT_FOUND - neither ds nor nsec records
* were not found.
* EEXIST - ds record was found.
* EINVAL - bogus.
*/
int kr_nsec_ref_to_unsigned(const knot_pkt_t *pkt);
......@@ -703,3 +703,85 @@ int kr_nsec3_no_data(const knot_pkt_t *pkt, knot_section_t section_id,
return ret;
}
int kr_nsec3_ref_to_unsigned(const knot_pkt_t *pkt)
{
int ret = kr_error(EINVAL);
int flags = 0;
uint8_t *bm = NULL;
uint16_t bm_size = 0;
const knot_pktsection_t *sec = knot_pkt_section(pkt, KNOT_AUTHORITY);
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) {
return kr_error(EEXIST);
}
if (ns->type != KNOT_RRTYPE_NS) {
continue;
}
flags = 0;
for (unsigned j = 0; j < sec->count; ++j) {
const knot_rrset_t *nsec3 = knot_pkt_rr(sec, j);
if (nsec3->type == KNOT_RRTYPE_DS) {
return kr_error(EEXIST);
}
if (nsec3->type != KNOT_RRTYPE_NSEC3) {
continue;
}
/* nsec3 found, check if owner name matches
* the delegation name
*/
ret = matches_name(&flags, nsec3, ns->owner);
if (ret != 0) {
return kr_error(EINVAL);
}
if (!(flags & FLG_NAME_MATCHED)) {
/* nsec3 owner name does not match
* the delegation name
*/
continue;
}
knot_nsec3_bitmap(&nsec3->rrs, 0, &bm, &bm_size);
if (!bm) {
return kr_error(EINVAL);
}
if (kr_nsec_bitmap_contains_type(bm, bm_size,
KNOT_RRTYPE_NS) &&
!kr_nsec_bitmap_contains_type(bm, bm_size,
KNOT_RRTYPE_DS) &&
!kr_nsec_bitmap_contains_type(bm, bm_size,
KNOT_RRTYPE_SOA)) {
/* Satisfies rfc5155, 8.9. paragraph 2 */
return kr_ok();
}
}
if (flags & FLG_NAME_MATCHED) {
/* nsec3 which owner matches
* the delegation name was found,
* but nsec3 type bitmap contains wrong types
*/
return kr_error(EINVAL);
}
/* nsec3 that matches the delegation was not found.
* Check rfc5155, 8.9. paragraph 4.
* Find closest provable encloser.
*/
const knot_dname_t *encloser_name = NULL;
const knot_rrset_t *covering_next_nsec3 = NULL;
ret = closest_encloser_proof(pkt, KNOT_AUTHORITY, ns->owner, &encloser_name,
NULL, &covering_next_nsec3);
if (ret != 0) {
return kr_error(EINVAL);
}
if (has_optout(covering_next_nsec3)) {
return kr_error(DNSSEC_NOT_FOUND);
} else {
return kr_error(EINVAL);
}
}
return kr_error(EINVAL);
}
......@@ -53,3 +53,15 @@ int kr_nsec3_wildcard_answer_response_check(const knot_pkt_t *pkt, knot_section_
*/
int kr_nsec3_no_data(const knot_pkt_t *pkt, knot_section_t section_id,
const knot_dname_t *sname, uint16_t stype);
/**
* Referral to unsigned subzone check (RFC5155 8.9).
* @note No RRSIGs are validated.
* @param pkt Packet structure to be processed.
* @return 0 or error code:
* DNSSEC_NOT_FOUND - denial of existence can't be proven
* due to opt-out.
* EEXIST - ds record was found.
* EINVAL - bogus.
*/
int kr_nsec3_ref_to_unsigned(const knot_pkt_t *pkt);
......@@ -277,7 +277,6 @@ static int update_delegation(struct kr_request *req, struct kr_query *qry, knot_
* If it contains neither, the referral is bogus (or an attempted downgrade attack).
*/
/* Aggregate DS records (if using multiple keys) */
unsigned section = KNOT_ANSWER;
if (!knot_wire_get_aa(answer->wire)) { /* Referral */
section = KNOT_AUTHORITY;
......@@ -287,17 +286,30 @@ static int update_delegation(struct kr_request *req, struct kr_query *qry, knot_
return kr_ok();
}
/* No DS provided, check for proof of non-existence. */
int ret = 0;
const knot_dname_t *proved_name = knot_pkt_qname(answer);
/* Aggregate DS records (if using multiple keys) */
knot_rrset_t *new_ds = update_ds(cut, knot_pkt_section(answer, section));
if (!new_ds) {
/* No DS provided, check for proof of non-existence. */
if (!has_nsec3) {
ret = kr_nsec_existence_denial(answer, KNOT_AUTHORITY, proved_name, KNOT_RRTYPE_DS);
if (!knot_wire_get_aa(answer->wire)) {
/* Referral, check if it is referral to unsigned, rfc4035 5.2 */
ret = kr_nsec_ref_to_unsigned(answer);
} else {
/* No-data answer */
ret = kr_nsec_existence_denial(answer, KNOT_AUTHORITY, proved_name, KNOT_RRTYPE_DS);
}
} else {
ret = kr_nsec3_no_data(answer, KNOT_AUTHORITY, proved_name, KNOT_RRTYPE_DS);
if (!knot_wire_get_aa(answer->wire)) {
/* Referral, check if it is referral to unsigned, rfc5155 8.9 */
ret = kr_nsec3_ref_to_unsigned(answer);
} else {
/* No-data answer, QTYPE is DS, rfc5155 8.6 */
ret = kr_nsec3_no_data(answer, KNOT_AUTHORITY, proved_name, KNOT_RRTYPE_DS);
}
if (ret == kr_error(DNSSEC_NOT_FOUND)) {
/* Not bogus, but going insecure */
/* Not bogus, going insecure due to optout */
ret = 0;
}
}
......
Subproject commit e73a0854552d94e8bc5306e75c3a2229bc739531
Subproject commit 8b1a6c6873067d78e88adda48d381142aa107bd4
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment