]> git.ipfire.org Git - thirdparty/bind9.git/commitdiff
Add code to store SKR
authorMatthijs Mekking <matthijs@isc.org>
Wed, 19 Jun 2024 09:09:29 +0000 (11:09 +0200)
committerMatthijs Mekking <matthijs@isc.org>
Thu, 22 Aug 2024 06:21:52 +0000 (08:21 +0200)
This added source code stores SKR data. It is loosely based on:
https://www.iana.org/dnssec/archive/files/draft-icann-dnssec-keymgmt-01.txt

A SKR contains a list of signed DNSKEY RRsets. Each change in data
should be stored in a separate bundle. So if the RRSIG is refreshed that
means it is stored in the next bundle. Likewise, if there is a new ZSK
pre-published, it is in the next bundle.

In addition (not mentioned in the draft), each bundle may contain
signed CDS and CDNSKEY RRsets.

Each bundle has an inception time. These will determine when we need
to re-sign or re-key the zone.

lib/dns/Makefile.am
lib/dns/include/dns/skr.h [new file with mode: 0644]
lib/dns/include/dns/types.h
lib/dns/skr.c [new file with mode: 0644]

index d5e96faa5e7b64c4b4d1b3cce6b12e9a04e3caf4..fb91857fc37590ea18c8314ff6712e66e8e239f7 100644 (file)
@@ -121,6 +121,7 @@ libdns_la_HEADERS =                 \
        include/dns/sdlz.h              \
        include/dns/secalg.h            \
        include/dns/secproto.h          \
+       include/dns/skr.h               \
        include/dns/soa.h               \
        include/dns/ssu.h               \
        include/dns/stats.h             \
@@ -238,6 +239,7 @@ libdns_la_SOURCES =                 \
        rrl.c                           \
        rriterator.c                    \
        sdlz.c                          \
+       skr.c                           \
        soa.c                           \
        ssu.c                           \
        ssu_external.c                  \
diff --git a/lib/dns/include/dns/skr.h b/lib/dns/include/dns/skr.h
new file mode 100644 (file)
index 0000000..872d936
--- /dev/null
@@ -0,0 +1,168 @@
+/*
+ * Copyright (C) Internet Systems Consortium, Inc. ("ISC")
+ *
+ * SPDX-License-Identifier: MPL-2.0
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, you can obtain one at https://mozilla.org/MPL/2.0/.
+ *
+ * See the COPYRIGHT file distributed with this work for additional
+ * information regarding copyright ownership.
+ */
+
+#pragma once
+
+/*! \file dns/skr.h
+ * \brief
+ * A skr is a convenience type representing a Signed Key Response (SKR),
+ * determining which DNSKEY, CDS, CDNSKEY and corresponding signatures
+ * should be published at a given time. It is based on terminology used in
+ * https://www.iana.org/dnssec/archive/files/draft-icann-dnssec-keymgmt-01.txt
+ */
+
+#include <isc/stdtime.h>
+
+#include <dns/diff.h>
+#include <dns/types.h>
+
+ISC_LANG_BEGINDECLS
+
+#define DNS_SKR_MAGIC   ISC_MAGIC('S', 'K', 'R', '-')
+#define DNS_SKR_VALID(t) ISC_MAGIC_VALID(t, DNS_SKR_MAGIC)
+
+#define DNS_SKRBUNDLE_MAGIC    ISC_MAGIC('S', 'K', 'R', 'B')
+#define DNS_SKRBUNDLE_VALID(t) ISC_MAGIC_VALID(t, DNS_SKRBUNDLE_MAGIC)
+
+typedef struct dns_skrbundle dns_skrbundle_t;
+typedef ISC_LIST(dns_skrbundle_t) dns_skrbundlelist_t;
+
+/* Stores a Signed Key Response (SKR) */
+struct dns_skr {
+       unsigned int        magic;
+       isc_mem_t          *mctx;
+       char               *filename;
+       isc_time_t          loadtime;
+       dns_skrbundlelist_t bundles;
+       isc_refcount_t      references;
+};
+
+struct dns_skrbundle {
+       unsigned int  magic;
+       isc_stdtime_t inception;
+       dns_diff_t    diff;
+       ISC_LINK(dns_skrbundle_t) link;
+};
+
+void
+dns_skrbundle_create(isc_mem_t *mctx, dns_name_t *name,
+                    dns_rdataclass_t rdclass, isc_stdtime_t inception,
+                    dns_skrbundle_t **bp);
+/*%<
+ * Create a single bundle.
+ *
+ * Requires:
+ * \li   *bp != NULL && *bp == NULL
+ */
+
+void
+dns_skrbundle_addtuple(dns_skrbundle_t *bundle, dns_difftuple_t **tuple);
+/*%<
+ * Add a single tuple to a key bundle.
+ *
+ * \li   'bundle' is a valid bundle
+ * \li   '*tuple' is a valid tuple
+ */
+
+isc_result_t
+dns_skrbundle_getsig(dns_skrbundle_t *bundle, dst_key_t *key,
+                    dns_rdatatype_t covering_type, dns_rdata_t *sigrdata);
+/*%<
+ * Retrieve the RRSIG rdata for 'covering_type' generated by 'key' from the
+ * given 'bundle'.
+ *
+ * Requires:
+ * \li   'bundle' is a valid bundle
+ *
+ * Returns:
+ * \li   a possible error if we fail to convert the rdata to a struct
+ * \li   ISC_R_SUCCESS if the signature is found
+ * \li   ISC_R_NOTFOUND otherwise
+ */
+
+void
+dns_skr_create(isc_mem_t *mctx, const char *filename, dns_name_t *origin,
+              dns_rdataclass_t rdclass, dns_skr_t **skrp);
+/*%<
+ * Create a SKR.
+ *
+ * Requires:
+ * \li   mctx != NULL
+ * \li   *skrp != NULL && *skrp == NULL
+ */
+
+void
+dns_skr_addbundle(dns_skr_t *skr, dns_skrbundle_t **bundlep);
+/*%<
+ * Add a single bundle to a SKR.
+ *
+ * Requires:
+ * \li   'skr' is a valid SKR
+ * \li   'bundle' is a valid bundle
+ */
+
+dns_skrbundle_t *
+dns_skr_lookup(dns_skr_t *skr, isc_stdtime_t time, uint32_t sigval);
+/*%<
+ * Look up the currently active bundle. The active bundle is the one which
+ * inception time is prior to 'time' and the next bundle inception is after
+ " 'time'. In case of the last bundle in the SKR, 'time' is expected to be
+ * lower than the last bundle inception time plus 'sigval'.
+ *
+ * Requires:
+ * \li   'skr' is a valid SKR
+ *
+ * Returns:
+ * \li   The currently active bundle, or NULL if no such bundle is found.
+ */
+
+void
+dns_skr_attach(dns_skr_t *source, dns_skr_t **targetp);
+/*%<
+ * Attach '*targetp' to 'source'.
+ *
+ * Requires:
+ *
+ *\li   'source' is a valid SKR.
+ *
+ *\li   'targetp' points to a NULL dns_skr_t *.
+ *
+ * Ensures:
+ *
+ *\li   *targetp is attached to source.
+ */
+
+void
+dns_skr_detach(dns_skr_t **skrp);
+/*%<
+ * Detach SKR.
+ *
+ * Requires:
+ *
+ *\li   'skrp' points to a valid dns_skr_t *
+ *
+ * Ensures:
+ *
+ *\li   *skrp is NULL.
+ */
+
+void
+dns_skr_destroy(dns_skr_t *skr);
+/*%<
+ * Destroy a SKR.
+ *
+ * Requires:
+ * \li   'skr' is a valid SKR
+ */
+
+ISC_LANG_ENDDECLS
index 7784d126f60cd8c09eb953e7b3f66f3ff1234c67..c4353aef4c2bd6567760d91195dd2ff79d44ca33 100644 (file)
@@ -150,6 +150,7 @@ typedef struct dns_qpnode   dns_qpnode_t;
 typedef uint8_t                        dns_secalg_t;
 typedef uint8_t                        dns_secproto_t;
 typedef struct dns_signature   dns_signature_t;
+typedef struct dns_skr         dns_skr_t;
 typedef struct dns_slabheader  dns_slabheader_t;
 typedef ISC_LIST(dns_slabheader_t) dns_slabheaderlist_t;
 typedef struct dns_sortlist_arg          dns_sortlist_arg_t;
diff --git a/lib/dns/skr.c b/lib/dns/skr.c
new file mode 100644 (file)
index 0000000..0926cc7
--- /dev/null
@@ -0,0 +1,188 @@
+/*
+ * Copyright (C) Internet Systems Consortium, Inc. ("ISC")
+ *
+ * SPDX-License-Identifier: MPL-2.0
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, you can obtain one at https://mozilla.org/MPL/2.0/.
+ *
+ * See the COPYRIGHT file distributed with this work for additional
+ * information regarding copyright ownership.
+ */
+
+/*! \file */
+
+#include <dns/skr.h>
+
+void
+dns_skrbundle_create(isc_mem_t *mctx, dns_name_t *name,
+                    dns_rdataclass_t rdclass, isc_stdtime_t inception,
+                    dns_skrbundle_t **bp) {
+       dns_skrbundle_t *b;
+
+       REQUIRE(bp != NULL && *bp == NULL);
+
+       UNUSED(name);
+       UNUSED(rdclass);
+
+       b = isc_mem_get(mctx, sizeof(*b));
+       b->magic = DNS_SKRBUNDLE_MAGIC;
+       b->inception = inception;
+       dns_diff_init(mctx, &b->diff);
+
+       ISC_LINK_INIT(b, link);
+
+       *bp = b;
+}
+
+void
+dns_skrbundle_addtuple(dns_skrbundle_t *bundle, dns_difftuple_t **tuple) {
+       REQUIRE(DNS_DIFFTUPLE_VALID(*tuple));
+       REQUIRE(DNS_SKRBUNDLE_VALID(bundle));
+       REQUIRE(DNS_DIFF_VALID(&bundle->diff));
+
+       dns_diff_append(&bundle->diff, tuple);
+}
+
+isc_result_t
+dns_skrbundle_getsig(dns_skrbundle_t *bundle, dst_key_t *key,
+                    dns_rdatatype_t covering_type, dns_rdata_t *sigrdata) {
+       isc_result_t result = ISC_R_SUCCESS;
+
+       REQUIRE(DNS_SKRBUNDLE_VALID(bundle));
+       REQUIRE(DNS_DIFF_VALID(&bundle->diff));
+
+       dns_difftuple_t *tuple = ISC_LIST_HEAD(bundle->diff.tuples);
+       while (tuple != NULL) {
+               dns_rdata_rrsig_t rrsig;
+
+               if (tuple->op != DNS_DIFFOP_ADDRESIGN) {
+                       tuple = ISC_LIST_NEXT(tuple, link);
+                       continue;
+               }
+               INSIST(tuple->rdata.type == dns_rdatatype_rrsig);
+
+               result = dns_rdata_tostruct(&tuple->rdata, &rrsig, NULL);
+               if (result != ISC_R_SUCCESS) {
+                       return (result);
+               }
+
+               /*
+                * Check if covering type matches, and if the signature is
+                * generated by 'key'.
+                */
+               if (rrsig.covered == covering_type &&
+                   rrsig.keyid == dst_key_id(key))
+               {
+                       dns_rdata_clone(&tuple->rdata, sigrdata);
+                       return (ISC_R_SUCCESS);
+               }
+
+               tuple = ISC_LIST_NEXT(tuple, link);
+       }
+
+       return (ISC_R_NOTFOUND);
+}
+
+void
+dns_skr_create(isc_mem_t *mctx, const char *filename, dns_name_t *origin,
+              dns_rdataclass_t rdclass, dns_skr_t **skrp) {
+       isc_time_t now;
+       dns_skr_t *skr = NULL;
+
+       REQUIRE(skrp != NULL && *skrp == NULL);
+       REQUIRE(mctx != NULL);
+
+       UNUSED(origin);
+       UNUSED(rdclass);
+
+       now = isc_time_now();
+       skr = isc_mem_get(mctx, sizeof(*skr));
+       *skr = (dns_skr_t){
+               .magic = DNS_SKR_MAGIC,
+               .filename = isc_mem_strdup(mctx, filename),
+               .loadtime = now,
+       };
+       /*
+        * A list is not the best structure to store bundles that
+        * we need to look up, but we don't expect many bundles
+        * per SKR so it is acceptable for now.
+        */
+       ISC_LIST_INIT(skr->bundles);
+
+       isc_mem_attach(mctx, &skr->mctx);
+       isc_refcount_init(&skr->references, 1);
+       *skrp = skr;
+}
+
+void
+dns_skr_addbundle(dns_skr_t *skr, dns_skrbundle_t **bundlep) {
+       REQUIRE(DNS_SKR_VALID(skr));
+       REQUIRE(DNS_SKRBUNDLE_VALID(*bundlep));
+
+       ISC_LIST_APPEND(skr->bundles, *bundlep, link);
+       *bundlep = NULL;
+}
+
+dns_skrbundle_t *
+dns_skr_lookup(dns_skr_t *skr, isc_stdtime_t time, uint32_t sigval) {
+       dns_skrbundle_t *b, *next;
+
+       REQUIRE(DNS_SKR_VALID(skr));
+
+       for (b = ISC_LIST_HEAD(skr->bundles); b != NULL; b = next) {
+               next = ISC_LIST_NEXT(b, link);
+               if (next == NULL) {
+                       isc_stdtime_t expired = b->inception + sigval;
+                       if (b->inception <= time && time < expired) {
+                               return (b);
+                       }
+                       return (NULL);
+               }
+               if (b->inception <= time && time < next->inception) {
+                       return (b);
+               }
+       }
+
+       return (NULL);
+}
+
+void
+dns_skr_attach(dns_skr_t *source, dns_skr_t **targetp) {
+       REQUIRE(DNS_SKR_VALID(source));
+       REQUIRE(targetp != NULL && *targetp == NULL);
+
+       isc_refcount_increment(&source->references);
+       *targetp = source;
+}
+
+void
+dns_skr_detach(dns_skr_t **skrp) {
+       REQUIRE(skrp != NULL && DNS_SKR_VALID(*skrp));
+
+       dns_skr_t *skr = *skrp;
+       *skrp = NULL;
+
+       if (isc_refcount_decrement(&skr->references) == 1) {
+               dns_skr_destroy(skr);
+       }
+}
+
+void
+dns_skr_destroy(dns_skr_t *skr) {
+       dns_skrbundle_t *b, *next;
+
+       REQUIRE(DNS_SKR_VALID(skr));
+
+       for (b = ISC_LIST_HEAD(skr->bundles); b != NULL; b = next) {
+               next = ISC_LIST_NEXT(b, link);
+               ISC_LIST_UNLINK(skr->bundles, b, link);
+               dns_diff_clear(&b->diff);
+               isc_mem_put(skr->mctx, b, sizeof(*b));
+       }
+       INSIST(ISC_LIST_EMPTY(skr->bundles));
+
+       isc_mem_free(skr->mctx, skr->filename);
+       isc_mem_putanddetach(&skr->mctx, skr, sizeof(*skr));
+}