]> git.ipfire.org Git - thirdparty/bind9.git/commitdiff
Useful dst_key functions
authorMatthijs Mekking <matthijs@isc.org>
Thu, 17 Oct 2019 08:21:12 +0000 (10:21 +0200)
committerMatthijs Mekking <matthijs@isc.org>
Wed, 6 Nov 2019 21:36:21 +0000 (22:36 +0100)
Add a couple of dst_key functions for determining hints that
consider key states if they are available.
- dst_key_is_unused:
  A key has no timing metadata set other than Created.
- dst_key_is_published:
  A key has publish timing metadata <= now, DNSKEY state in
  RUMOURED or OMNIPRESENT.
- dst_key_is_active:
  A key has active timing metadata <= now, RRSIG state in
  RUMOURED or OMNIPRESENT.
- dst_key_is_signing:
  KSK is_signing and is_active means different things than
  for a ZSK. A ZSK is active means it is also signing, but
  a KSK always signs its DNSKEY RRset but is considered
  active if its DS is present (rumoured or omnipresent).
- dst_key_is_revoked:
  A key has revoke timing metadata <= now.
- dst_key_is_removed:
  A key has delete timing metadata <= now, DNSKEY state in
  UNRETENTIVE or HIDDEN.

lib/dns/dst_api.c
lib/dns/include/dst/dst.h
lib/dns/win32/libdns.def.in

index 54dcd06d7df5d7afa832bdfde793e696852515ab..d8d8869e4a63b87d93b02ab89375eb0fb129a7f0 100644 (file)
@@ -2283,3 +2283,308 @@ dst_key_tkeytoken(const dst_key_t *key) {
        REQUIRE(VALID_KEY(key));
        return (key->key_tkeytoken);
 }
+
+/*
+ * A key is considered unused if it does not have any timing metadata set
+ * other than "Created".
+ *
+ */
+bool
+dst_key_is_unused(dst_key_t* key)
+{
+       isc_stdtime_t val;
+       dst_key_state_t st;
+       int state_type;
+       bool state_type_set;
+
+       REQUIRE(VALID_KEY(key));
+
+       /*
+        * None of the key timing metadata, except Created, may be set.  Key
+        * state times may be set only if their respective state is HIDDEN.
+        */
+       for (int i = 0; i < DST_MAX_TIMES+1; i++) {
+               state_type_set = false;
+
+               switch (i) {
+               case DST_TIME_CREATED:
+                       break;
+               case DST_TIME_DNSKEY:
+                       state_type = DST_KEY_DNSKEY;
+                       state_type_set = true;
+                       break;
+               case DST_TIME_ZRRSIG:
+                       state_type = DST_KEY_ZRRSIG;
+                       state_type_set = true;
+                       break;
+               case DST_TIME_KRRSIG:
+                       state_type = DST_KEY_KRRSIG;
+                       state_type_set = true;
+                       break;
+               case DST_TIME_DS:
+                       state_type = DST_KEY_DS;
+                       state_type_set = true;
+                       break;
+               default:
+                       break;
+               }
+
+               /* Created is fine. */
+               if (i == DST_TIME_CREATED) {
+                       continue;
+               }
+               /* No such timing metadata found, that is fine too. */
+               if (dst_key_gettime(key, i, &val) == ISC_R_NOTFOUND) {
+                       continue;
+               }
+               /*
+                * Found timing metadata and it is not related to key states.
+                * This key is used.
+                */
+               if (!state_type_set) {
+                       return false;
+               }
+               /*
+                * If the state is not HIDDEN, the key is in use.
+                * If the state is not set, this is odd and we default to NA.
+                */
+               if (dst_key_getstate(key, state_type, &st) != ISC_R_SUCCESS) {
+                       st = DST_KEY_STATE_NA;
+               }
+               if (st != DST_KEY_STATE_HIDDEN) {
+                       return false;
+               }
+       }
+       /* This key is unused. */
+       return true;
+}
+
+
+static void
+get_ksk_zsk(dst_key_t *key, bool *ksk, bool *zsk)
+{
+       bool k = false, z = false;
+
+       if (dst_key_getbool(key, DST_BOOL_KSK, &k) == ISC_R_SUCCESS) {
+               *ksk = k;
+       } else {
+               *ksk = ((dst_key_flags(key) & DNS_KEYFLAG_KSK) != 0);
+       }
+       if (dst_key_getbool(key, DST_BOOL_ZSK, &z) == ISC_R_SUCCESS) {
+               *zsk = z;
+       } else {
+               *zsk = ((dst_key_flags(key) & DNS_KEYFLAG_KSK) == 0);
+       }
+}
+
+/* Hints on key whether it can be published and/or used for signing. */
+
+bool
+dst_key_is_published(dst_key_t *key, isc_stdtime_t now,
+                    isc_stdtime_t *publish)
+{
+       dst_key_state_t state;
+       isc_result_t result;
+       isc_stdtime_t when;
+       bool state_ok = true, time_ok = false;
+
+       REQUIRE(VALID_KEY(key));
+
+       result = dst_key_gettime(key, DST_TIME_PUBLISH, &when);
+       if (result == ISC_R_SUCCESS) {
+               *publish = when;
+               time_ok = (when <= now);
+       }
+
+       /* Check key states:
+        * If the DNSKEY state is RUMOURED or OMNIPRESENT, it means it
+        * should be published.
+        */
+       result = dst_key_getstate(key, DST_KEY_DNSKEY, &state);
+       if (result == ISC_R_SUCCESS) {
+               state_ok = ((state == DST_KEY_STATE_RUMOURED) ||
+                           (state == DST_KEY_STATE_OMNIPRESENT));
+               /*
+                * Key states trump timing metadata.
+                * Ignore inactive time.
+                */
+               time_ok = true;
+       }
+
+       return state_ok && time_ok;
+}
+
+bool
+dst_key_is_active(dst_key_t *key, isc_stdtime_t now)
+{
+       dst_key_state_t state;
+       isc_result_t result;
+       isc_stdtime_t when = 0;
+       bool ksk = false, zsk = false, inactive = false;
+       bool ds_ok = true, zrrsig_ok = true, time_ok = false;
+
+       REQUIRE(VALID_KEY(key));
+
+       result = dst_key_gettime(key, DST_TIME_INACTIVE, &when);
+       if (result == ISC_R_SUCCESS) {
+               inactive = (when <= now);
+       }
+
+       result = dst_key_gettime(key, DST_TIME_ACTIVATE, &when);
+       if (result == ISC_R_SUCCESS) {
+               time_ok = (when <= now);
+       }
+
+       get_ksk_zsk(key, &ksk, &zsk);
+
+       /* Check key states:
+        * KSK: If the DS is RUMOURED or OMNIPRESENT the key is considered
+        * active.
+        */
+       if (ksk) {
+               result = dst_key_getstate(key, DST_KEY_DS, &state);
+               if (result == ISC_R_SUCCESS) {
+                       ds_ok = ((state == DST_KEY_STATE_RUMOURED) ||
+                                (state == DST_KEY_STATE_OMNIPRESENT));
+                       /*
+                        * Key states trump timing metadata.
+                        * Ignore inactive time.
+                        */
+                       time_ok = true;
+                       inactive = false;
+               }
+       }
+       /*
+        * ZSK: If the ZRRSIG state is RUMOURED or OMNIPRESENT, it means the
+        * key is active.
+        */
+       if (zsk) {
+               result = dst_key_getstate(key, DST_KEY_ZRRSIG, &state);
+               if (result == ISC_R_SUCCESS) {
+                       zrrsig_ok = ((state == DST_KEY_STATE_RUMOURED) ||
+                                   (state == DST_KEY_STATE_OMNIPRESENT));
+                       /*
+                        * Key states trump timing metadata.
+                        * Ignore inactive time.
+                        */
+                       time_ok = true;
+                       inactive = false;
+               }
+       }
+       return ds_ok && zrrsig_ok && time_ok && !inactive;
+}
+
+
+bool
+dst_key_is_signing(dst_key_t *key, isc_stdtime_t now, isc_stdtime_t *active)
+{
+       dst_key_state_t state;
+       isc_result_t result;
+       isc_stdtime_t when = 0;
+       bool ksk = false, zsk = false, inactive = false;
+       bool krrsig_ok = true, zrrsig_ok = true, time_ok = false;
+
+       REQUIRE(VALID_KEY(key));
+
+       result = dst_key_gettime(key, DST_TIME_INACTIVE, &when);
+       if (result == ISC_R_SUCCESS) {
+               inactive = (when <= now);
+       }
+
+       result = dst_key_gettime(key, DST_TIME_ACTIVATE, &when);
+       if (result == ISC_R_SUCCESS) {
+               *active = when;
+               time_ok = (when <= now);
+       }
+
+       get_ksk_zsk(key, &ksk, &zsk);
+
+       /* Check key states:
+        * If the RRSIG state is RUMOURED or OMNIPRESENT, it means the key
+        * is active.
+        */
+       if (ksk) {
+               result = dst_key_getstate(key, DST_KEY_KRRSIG, &state);
+               if (result == ISC_R_SUCCESS) {
+                       krrsig_ok = ((state == DST_KEY_STATE_RUMOURED) ||
+                                   (state == DST_KEY_STATE_OMNIPRESENT));
+                       /*
+                        * Key states trump timing metadata.
+                        * Ignore inactive time.
+                        */
+                       time_ok = true;
+                       inactive = false;
+               }
+       }
+       if (zsk) {
+               result = dst_key_getstate(key, DST_KEY_ZRRSIG, &state);
+               if (result == ISC_R_SUCCESS) {
+                       zrrsig_ok = ((state == DST_KEY_STATE_RUMOURED) ||
+                                   (state == DST_KEY_STATE_OMNIPRESENT));
+                       /*
+                        * Key states trump timing metadata.
+                        * Ignore inactive time.
+                        */
+                       time_ok = true;
+                       inactive = false;
+               }
+       }
+       return krrsig_ok && zrrsig_ok && time_ok && !inactive;
+}
+
+bool
+dst_key_is_revoked(dst_key_t *key, isc_stdtime_t now, isc_stdtime_t *revoke)
+{
+       isc_result_t result;
+       isc_stdtime_t when = 0;
+       bool time_ok = false;
+
+       REQUIRE(VALID_KEY(key));
+
+       result = dst_key_gettime(key, DST_TIME_REVOKE, &when);
+       if (result == ISC_R_SUCCESS) {
+               *revoke = when;
+               time_ok = (when <= now);
+       }
+
+       return time_ok;
+}
+
+bool
+dst_key_is_removed(dst_key_t *key, isc_stdtime_t now, isc_stdtime_t *remove)
+{
+       dst_key_state_t state;
+       isc_result_t result;
+       isc_stdtime_t when = 0;
+       bool state_ok = true, time_ok = false;
+
+       REQUIRE(VALID_KEY(key));
+
+       if (dst_key_is_unused(key)) {
+               /* This key was never used. */
+               return false;
+       }
+
+       result = dst_key_gettime(key, DST_TIME_DELETE, &when);
+       if (result == ISC_R_SUCCESS) {
+               *remove = when;
+               time_ok = (when <= now);
+       }
+
+       /* Check key states:
+        * If the DNSKEY state is UNRETENTIVE or HIDDEN, it means the key
+        * should not be published.
+        */
+       result = dst_key_getstate(key, DST_KEY_DNSKEY, &state);
+       if (result == ISC_R_SUCCESS) {
+               state_ok = ((state == DST_KEY_STATE_UNRETENTIVE) ||
+                           (state == DST_KEY_STATE_HIDDEN));
+               /*
+                * Key states trump timing metadata.
+                * Ignore delete time.
+                */
+               time_ok = true;
+       }
+
+       return state_ok && time_ok;
+}
index 7f8517c4a91b209bd0c2ad3ff04ab76623af96f0..a37725f404e7603c188a8886fe3642bb977e5d45 100644 (file)
@@ -1093,9 +1093,77 @@ dst_key_setinactive(dst_key_t *key, bool inactive);
 
 void
 dst_key_setexternal(dst_key_t *key, bool value);
+/*%<
+ * Set key external state.
+ *
+ * Requires:
+ *     'key' to be valid.
+ */
 
 bool
 dst_key_isexternal(dst_key_t *key);
+/*%<
+ * Check if this is an external key.
+ *
+ * Requires:
+ *     'key' to be valid.
+ */
+
+bool
+dst_key_is_unused(dst_key_t *key);
+/*%<
+ * Check if this key is unused.
+ *
+ * Requires:
+ *     'key' to be valid.
+ */
+
+bool
+dst_key_is_published(dst_key_t *key, isc_stdtime_t now, isc_stdtime_t *publish);
+/*%<
+ * Check if it is safe to publish this key (e.g. put the DNSKEY in the zone).
+ *
+ * Requires:
+ *     'key' to be valid.
+ */
+
+bool
+dst_key_is_active(dst_key_t *key, isc_stdtime_t now);
+/*%<
+ * Check if this key is active. This means that it is creating RRSIG records
+ * (ZSK), or that it is used to create a chain of trust (KSK), or both (CSK).
+ *
+ * Requires:
+ *     'key' to be valid.
+ */
+
+bool
+dst_key_is_signing(dst_key_t *key, isc_stdtime_t now, isc_stdtime_t *active);
+/*%<
+ * Check if it is safe to use this key for signing.
+ *
+ * Requires:
+ *     'key' to be valid.
+ */
+
+bool
+dst_key_is_revoked(dst_key_t *key, isc_stdtime_t now, isc_stdtime_t *revoke);
+/*%<
+ * Check if this key is revoked.
+ *
+ * Requires:
+ *     'key' to be valid.
+ */
+
+bool
+dst_key_is_removed(dst_key_t *key, isc_stdtime_t now, isc_stdtime_t *remove);
+/*%<
+ * Check if this key is removed from the zone (e.g. the DNSKEY record should
+ * no longer be in the zone).
+ *
+ * Requires:
+ *     'key' to be valid.
+ */
 
 ISC_LANG_ENDDECLS
 
index de79d7bfb1045473485186324fb2cbe00441bde5..72d39c478ef0154bc2ef0371d77412ac36cbb2b4 100644 (file)
@@ -1426,6 +1426,12 @@ dst_key_getstate
 dst_key_gettime
 dst_key_getttl
 dst_key_id
+dst_key_is_active
+dst_key_is_published
+dst_key_is_removed
+dst_key_is_revoked
+dst_key_is_signing
+dst_key_is_unused
 dst_key_inactive
 dst_key_isexternal
 dst_key_isnullkey