/** * Returns the labels from the covering RRSIG RRs. * @note The number must be the same in all covering RRSIGs. * @param nsec NSEC RR. * @param sec Packet section. * @param Number of labels or (negative) error code. */ static int coverign_rrsig_labels(const knot_rrset_t *nsec, const knot_pktsection_t *sec) { assert(nsec && sec); int ret = kr_error(ENOENT); for (unsigned i = 0; i < sec->count; ++i) { const knot_rrset_t *rrset = knot_pkt_rr(sec, i); if ((rrset->type != KNOT_RRTYPE_RRSIG) || (!knot_dname_is_equal(rrset->owner, nsec->owner))) { continue; } for (uint16_t j = 0; j < rrset->rrs.rr_count; ++j) { if (knot_rrsig_type_covered(&rrset->rrs, j) != KNOT_RRTYPE_NSEC) { continue; } if (ret < 0) { ret = knot_rrsig_labels(&rrset->rrs, j); } else { if (ret != knot_rrsig_labels(&rrset->rrs, j)) { return kr_error(EINVAL); } } } } return ret; }
static bool rrset_is_nsec3rel(const knot_rrset_t *rr) { if (rr == NULL) { return false; } /* Is NSEC3 or non-empty RRSIG covering NSEC3. */ return ((rr->type == KNOT_RRTYPE_NSEC3) || (rr->type == KNOT_RRTYPE_RRSIG && knot_rrsig_type_covered(&rr->rrs, 0) == KNOT_RRTYPE_NSEC3)); }
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, bool has_nsec3) { struct dseckey *created_key = NULL; if (key == NULL) { const knot_rdata_t *krr = knot_rdataset_at(&keys->rrs, key_pos); int ret = kr_dnssec_key_from_rdata(&created_key, keys->owner, knot_rdata_data(krr), knot_rdata_rdlen(krr)); if (ret != 0) { return ret; } key = created_key; } uint16_t keytag = dnssec_key_get_keytag((dnssec_key_t *)key); int covered_labels = knot_dname_labels(covered->owner, NULL); if (knot_dname_is_wildcard(covered->owner)) { /* The asterisk does not count, RFC4034 3.1.3, paragraph 3. */ --covered_labels; } const knot_pktsection_t *sec = knot_pkt_section(pkt, section_id); for (unsigned i = 0; i < sec->count; ++i) { /* Consider every RRSIG that matches owner and covers the class/type. */ const knot_rrset_t *rrsig = knot_pkt_rr(sec, i); if (rrsig->type != KNOT_RRTYPE_RRSIG) { continue; } if ((covered->rclass != rrsig->rclass) || !knot_dname_is_equal(covered->owner, rrsig->owner)) { continue; } for (uint16_t j = 0; j < rrsig->rrs.rr_count; ++j) { int val_flgs = 0; int trim_labels = 0; if (knot_rrsig_type_covered(&rrsig->rrs, j) != covered->type) { continue; } if (validate_rrsig_rr(&val_flgs, covered_labels, rrsig, j, keys, key_pos, keytag, zone_name, timestamp) != 0) { continue; } if (val_flgs & FLG_WILDCARD_EXPANSION) { trim_labels = wildcard_radix_len_diff(covered->owner, rrsig, j); if (trim_labels < 0) { break; } } if (kr_check_signature(rrsig, j, (dnssec_key_t *) key, covered, trim_labels) != 0) { continue; } if (val_flgs & FLG_WILDCARD_EXPANSION) { int ret = 0; if (!has_nsec3) { ret = kr_nsec_wildcard_answer_response_check(pkt, KNOT_AUTHORITY, covered->owner); } else { ret = kr_nsec3_wildcard_answer_response_check(pkt, KNOT_AUTHORITY, covered->owner, trim_labels - 1); } if (ret != 0) { continue; } } /* Validated with current key, OK */ kr_dnssec_key_free(&created_key); return kr_ok(); } } /* No applicable key found, cannot be validated. */ kr_dnssec_key_free(&created_key); return kr_error(ENOENT); }