return false;
}
-int kr_dnskeys_trusted(kr_rrset_validation_ctx_t *vctx, const knot_rrset_t *ta)
+int kr_dnskeys_trusted(kr_rrset_validation_ctx_t *vctx, const knot_rdataset_t *sigs,
+ const knot_rrset_t *ta)
{
- knot_rrset_t *keys = vctx->keys;
-
+ knot_rrset_t *keys = vctx->keys;
const bool ok = keys && ta && ta->rrs.count && ta->rrs.rdata
- && ta->type == KNOT_RRTYPE_DS;
+ && ta->type == KNOT_RRTYPE_DS
+ && knot_dname_is_equal(ta->owner, keys->owner);
if (kr_fails_assert(ok))
return kr_error(EINVAL);
* The supplied DS record has been authenticated.
* It has been validated or is part of a configured trust anchor.
*/
- memset(&vctx->rrs_counters, 0, sizeof(vctx->rrs_counters));
- for (uint16_t i = 0; i < keys->rrs.count; ++i) {
+ knot_rdata_t *krr = keys->rrs.rdata;
+ for (int i = 0; i < keys->rrs.count; ++i, krr = knot_rdataset_next(krr)) {
/* RFC4035 5.3.1, bullet 8 */ /* ZSK */
- /* LATER(optim.): more efficient way to iterate than _at() */
- knot_rdata_t *krr = knot_rdataset_at(&keys->rrs, i);
if (!kr_dnssec_key_zsk(krr->data) || kr_dnssec_key_revoked(krr->data))
continue;
- struct dnssec_key *key = NULL;
- if (kr_dnssec_key_from_rdata(&key, keys->owner, krr->data, krr->len) != 0)
- continue;
- if (kr_authenticate_referral(ta, key) != 0) {
- kr_dnssec_key_free(&key);
- continue;
- }
- if (kr_rrset_validate_with_key(vctx, keys, i, key) != 0) {
- kr_dnssec_key_free(&key);
- continue;
+ kr_svldr_key_t key;
+ if (svldr_key_new(krr, keys->owner, &key) != 0)
+ continue; // it might e.g. be malformed
+
+ int ret = kr_authenticate_referral(ta, key.key);
+ if (ret == 0)
+ ret = kr_svldr_rrset_with_key(keys, sigs, vctx, &key);
+ svldr_key_del(&key);
+ if (ret == 0) {
+ kr_assert(vctx->result == 0);
+ return vctx->result;
}
- kr_dnssec_key_free(&key);
- kr_assert(vctx->result == 0);
- return vctx->result;
}
/* No useable key found */
/**
* Check whether the DNSKEY rrset matches the supplied trust anchor RRSet.
+ *
* @param vctx Pointer to validation context. Note that TTL of vctx->keys may get lowered.
- * @param ta Trust anchor RRSet against which to validate the DNSKEY RRSet.
+ * @param sigs RRSIGs for this DNSKEY set
+ * @param ta Trusted DS RRSet against which to validate the DNSKEY RRSet.
* @return 0 or error code, same as vctx->result.
*/
-int kr_dnskeys_trusted(kr_rrset_validation_ctx_t *vctx, const knot_rrset_t *ta);
+int kr_dnskeys_trusted(kr_rrset_validation_ctx_t *vctx, const knot_rdataset_t *sigs,
+ const knot_rrset_t *ta);
/** Return true if the DNSKEY can be used as a ZSK. */
KR_EXPORT KR_PURE
/* Check if there's a key for current TA. */
if (updated_key && !(qry->flags.CACHED)) {
+ /* Find signatures for the DNSKEY; selected by iterator from ANSWER. */
+ int sig_index = -1;
+ for (int i = req->answ_selected.len - 1; i >= 0; --i) {
+ const knot_rrset_t *rrsig = req->answ_selected.at[i]->rr;
+ const bool ok = req->answ_selected.at[i]->qry_uid == qry->uid
+ && rrsig->type == KNOT_RRTYPE_RRSIG
+ && knot_rrsig_type_covered(rrsig->rrs.rdata)
+ == KNOT_RRTYPE_DNSKEY
+ && rrsig->rclass == KNOT_CLASS_IN
+ && knot_dname_is_equal(rrsig->owner,
+ qry->zone_cut.key->owner);
+ if (ok) {
+ sig_index = i;
+ break;
+ }
+ }
+ if (sig_index < 0) {
+ return kr_error(ENOENT);
+ }
+ const knot_rdataset_t *sig_rds = &req->answ_selected.at[sig_index]->rr->rrs;
kr_rrset_validation_ctx_t vctx = {
.pkt = answer,
.result = 0,
.log_qry = qry,
};
- int ret = kr_dnskeys_trusted(&vctx, qry->zone_cut.trust_anchor);
+ int ret = kr_dnskeys_trusted(&vctx, sig_rds, qry->zone_cut.trust_anchor);
+ /* Set rank of the RRSIG. This may be needed, but I don't know why.
+ * In particular, black_ent.rpl may get broken otherwise. */
+ kr_rank_set(&req->answ_selected.at[sig_index]->rank,
+ ret == 0 ? KR_RANK_SECURE : KR_RANK_BOGUS);
+
if (ret != 0) {
if (ret != kr_error(DNSSEC_INVALID_DS_ALGORITHM) &&
ret != kr_error(EAGAIN)) {