]> git.ipfire.org Git - thirdparty/knot-resolver.git/commitdiff
lib/dnssec: add a simple validator API
authorVladimír Čunát <vladimir.cunat@nic.cz>
Fri, 24 Sep 2021 10:00:15 +0000 (12:00 +0200)
committerTomas Krizek <tomas.krizek@nic.cz>
Wed, 3 Nov 2021 14:38:41 +0000 (15:38 +0100)
lib/dnssec.c
lib/dnssec.h

index 50436c5f324b57b11621f48eecb80cef08c136c6..43ba201614695e16b2a88c98a8aa2b676cd515f0 100644 (file)
@@ -167,6 +167,11 @@ typedef struct {
        uint16_t tag;
 } kr_svldr_key_t;
 
+struct kr_svldr_ctx {
+       kr_rrset_validation_ctx_t vctx;
+       array_t(kr_svldr_key_t) keys; // owned(malloc), also insides via svldr_key_*
+};
+
 static int svldr_key_new(const knot_rdata_t *rdata, const knot_dname_t *owner,
                         kr_svldr_key_t *result)
 {
@@ -182,6 +187,48 @@ static inline void svldr_key_del(kr_svldr_key_t *skey)
        kr_dnssec_key_free(&skey->key);
 }
 
+void kr_svldr_free_ctx(struct kr_svldr_ctx *ctx)
+{
+       if (!ctx) return;
+       for (ssize_t i = 0; i < ctx->keys.len; ++i)
+               svldr_key_del(&ctx->keys.at[i]);
+       array_clear(ctx->keys);
+       free_const(ctx->vctx.zone_name);
+       free(ctx);
+}
+struct kr_svldr_ctx * kr_svldr_new_ctx(const knot_rrset_t *ds, knot_rrset_t *dnskey,
+               const knot_rdataset_t *dnskey_sigs, uint32_t timestamp)
+{
+       // Basic init.
+       struct kr_svldr_ctx *ctx = calloc(1, sizeof(*ctx));
+       if (unlikely(!ctx))
+               return NULL;
+       ctx->vctx.timestamp = timestamp;
+       ctx->vctx.zone_name = knot_dname_copy(ds->owner, NULL);
+       if (unlikely(!ctx->vctx.zone_name))
+               goto fail;
+       // Validate the DNSKEY set.
+       ctx->vctx.keys = dnskey;
+       if (kr_dnskeys_trusted(&ctx->vctx, dnskey_sigs, ds) != 0)
+               goto fail;
+       // Put usable DNSKEYs into ctx->keys.  (Some duplication of work happens, but OK.)
+       array_init(ctx->keys);
+       array_reserve(ctx->keys, dnskey->rrs.count);
+       knot_rdata_t *krr = dnskey->rrs.rdata;
+       for (int i = 0; i < dnskey->rrs.count; ++i, krr = knot_rdataset_next(krr)) {
+               if (!kr_dnssec_key_zsk(krr->data) || kr_dnssec_key_revoked(krr->data))
+                       continue; // key not usable for this
+               kr_svldr_key_t key;
+               if (unlikely(svldr_key_new(krr, NULL/*seems OK here*/, &key) != 0))
+                       goto fail;
+               array_push(ctx->keys, key);
+       }
+       return ctx;
+fail:
+       kr_svldr_free_ctx(ctx);
+       return NULL;
+}
+
 static int kr_svldr_rrset_with_key(knot_rrset_t *rrs, const knot_rdataset_t *rrsigs,
                                kr_rrset_validation_ctx_t *vctx, const kr_svldr_key_t *key)
 {
@@ -215,6 +262,20 @@ static int kr_svldr_rrset_with_key(knot_rrset_t *rrs, const knot_rdataset_t *rrs
        return vctx->result;
 }
 /* The implementation basically performs "parts of" kr_rrset_validate(). */
+int kr_svldr_rrset(knot_rrset_t *rrs, const knot_rdataset_t *rrsigs,
+                       struct kr_svldr_ctx *ctx)
+{
+       if (knot_dname_in_bailiwick(rrs->owner, ctx->vctx.zone_name) < 0) {
+               ctx->vctx.result = kr_error(EAGAIN);
+               return ctx->vctx.result;
+       }
+       for (ssize_t i = 0; i < ctx->keys.len; ++i) {
+               kr_svldr_rrset_with_key(rrs, rrsigs, &ctx->vctx, &ctx->keys.at[i]);
+               if (ctx->vctx.result == 0)
+                       break;
+       }
+       return ctx->vctx.result;
+}
 
 
 /**
index d69d88d0f1959312159b28a1d26235f874b46f8b..13ba176abb69fdec6ccaa8f394e4f6b40995cd8b 100644 (file)
@@ -147,3 +147,34 @@ void kr_dnssec_key_free(struct dnssec_key **key);
  */
 int kr_dnssec_matches_name_and_type(const ranked_rr_array_t *rrs, uint32_t qry_uid,
                                    const knot_dname_t *name, uint16_t type);
+
+
+/* Simple validator API.  Main use case: prefill module, i.e. RRs from a zone file. */
+
+/** Opaque context for simple validator. */
+struct kr_svldr_ctx;
+/**
+ * Create new context for validating within a given zone.
+ *
+ * - `ds` is assumed to be trusted, and it's used to validate `dnskey+dnskey_sigs`.
+ * - The TTL of `dnskey` may get trimmed.
+ * - The insides are placed on malloc heap (use _free_ctx).
+ */
+KR_EXPORT
+struct kr_svldr_ctx * kr_svldr_new_ctx(const knot_rrset_t *ds, knot_rrset_t *dnskey,
+               const knot_rdataset_t *dnskey_sigs, uint32_t timestamp);
+/** Free the context.  Passing NULL is OK. */
+KR_EXPORT
+void kr_svldr_free_ctx(struct kr_svldr_ctx *ctx);
+/**
+ * Validate an RRset with the associated signatures; assume no wildcard expansions.
+ *
+ * - It's caller's responsibility that rrsigs have matching owner, class and type.
+ * - The TTL of `rrs` may get trimmed.
+ * - If it's a wildcard other than in its simple `*.` form, it may fail to validate.
+ * - More generally, non-existence proofs are not supported.
+ */
+KR_EXPORT
+int kr_svldr_rrset(knot_rrset_t *rrs, const knot_rdataset_t *rrsigs,
+                       struct kr_svldr_ctx *ctx);
+