From 314b90dfddec4a507a28772e7e43566b89fc5c5b Mon Sep 17 00:00:00 2001 From: Matthijs Mekking Date: Thu, 17 Oct 2019 10:21:12 +0200 Subject: [PATCH] Useful dst_key functions 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 | 305 ++++++++++++++++++++++++++++++++++++ lib/dns/include/dst/dst.h | 68 ++++++++ lib/dns/win32/libdns.def.in | 6 + 3 files changed, 379 insertions(+) diff --git a/lib/dns/dst_api.c b/lib/dns/dst_api.c index 54dcd06d7d..d8d8869e4a 100644 --- a/lib/dns/dst_api.c +++ b/lib/dns/dst_api.c @@ -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; +} diff --git a/lib/dns/include/dst/dst.h b/lib/dns/include/dst/dst.h index 7f8517c4a9..a37725f404 100644 --- a/lib/dns/include/dst/dst.h +++ b/lib/dns/include/dst/dst.h @@ -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 diff --git a/lib/dns/win32/libdns.def.in b/lib/dns/win32/libdns.def.in index de79d7bfb1..72d39c478e 100644 --- a/lib/dns/win32/libdns.def.in +++ b/lib/dns/win32/libdns.def.in @@ -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