]> git.ipfire.org Git - thirdparty/knot-resolver.git/commitdiff
lib/dnssec: make kr_dnskeys_trusted() cleaner
authorVladimír Čunát <vladimir.cunat@nic.cz>
Tue, 14 Sep 2021 15:46:19 +0000 (17:46 +0200)
committerTomas Krizek <tomas.krizek@nic.cz>
Wed, 3 Nov 2021 14:38:41 +0000 (15:38 +0100)
This way it will be easier to re-use (and more efficient).
I really disliked those searches for RRSIGs embedded deep inside.

Uh, I tried to keep the new function as clean as possible,
moving hacks to outside.

lib/dnssec.c
lib/dnssec.h
lib/layer/validate.c

index c1935b4834f2a25b93a3207e2a21313831ef0fdf..50436c5f324b57b11621f48eecb80cef08c136c6 100644 (file)
@@ -348,12 +348,13 @@ bool kr_ds_algo_support(const knot_rrset_t *ta)
        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);
 
@@ -361,28 +362,24 @@ int kr_dnskeys_trusted(kr_rrset_validation_ctx_t *vctx, const knot_rrset_t *ta)
         * 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 */
index 731ddf7adddaf86e84b938a0e3f7f43b07e51ab4..d69d88d0f1959312159b28a1d26235f874b46f8b 100644 (file)
@@ -76,11 +76,14 @@ bool kr_ds_algo_support(const knot_rrset_t *ta);
 
 /**
  * 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
index fb906efdbb4872f6b36fe54410a5e3bda057e051..0d48514db75012432744362d45315e47e8e5cf00 100644 (file)
@@ -340,6 +340,26 @@ static int validate_keyset(struct kr_request *req, knot_pkt_t *answer, bool has_
 
        /* 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,
@@ -354,7 +374,12 @@ static int validate_keyset(struct kr_request *req, knot_pkt_t *answer, bool has_
                        .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)) {