- TSAN can't handle more than 64 locks in one thread, lock ADB bucket-by-bucket
in TSAN mode. This means that the dump won't be consistent but it's good
enough for testing
- Use proper order when unlocking adb->namelocks and adb->entrylocks when
dumping ADB.
use empty placeholder KEYDATA records for all trust anchors, not just
DS-style trust anchors.
this revealed a pre-existing bug: keyfetch_done() skips keys without
the SEP bit when populating the managed-keys zone. consequently, if a
zone only has a single ZSK which is configured as trust anchor and no
KSKs, then no KEYDATA record is ever written to the managed-keys zone
when keys are refreshed.
that was how the root server in the dnssec system test was configured.
however, previously, the KEYDATA was created when the key was
initialized; this prevented us from noticing the bug until now.
configuring a ZSK as an RFC 5011 trust anchor is not forbidden by the
spec, but it is highly unusual and not well defined. so for the time
being, I have modified the system test to generate both a KSK and ZSK
for the root zone, enabling the test to pass.
we should consider adding code to detect this condition and allow keys
without the SEP bit to be used as trust anchors if no key with the SEP
bit is available, or at minimum, log a warning.
note: this also needs further refactoring.
- when initializing RFC 5011 for a name, we populate the managed-keys
zone with KEYDATA records derived from the initial-key trust anchors.
however, with initial-ds trust anchors, there is no key. but the
managed-keys zone still must have a KEYDATA record for the name,
otherwise zone_refreshkeys() won't refresh that key. so, for
initial-ds trust anchors, we now add an empty KEYDATA record and set
the key refresh timer so that the real keys will be looked up as soon
as possible.
- when a key refresh query is done, we verify it against the
trust anchor; this is done in two ways, one with the DS RRset
set up during configuration if present, or with the keys linked
from each keynode in the list if not. because there are two different
verification methods, the loop structure is overly complex and should
be simplified.
- the keyfetch_done() and sync_keyzone() functions are both too long
and should be broken into smaller functions.
note: this is a frankensteinian kluge which needs further refactoring.
the keytable started as an RBT where the node->data points to a list of
dns_keynode structures, each of which points to a single dst_key.
later it was modified so that the list could instead point to a single
"null" keynode structure, which does not reference a key; this means
a trust anchor has been configured but the RFC 5011 refresh failed.
in this branch it is further updated to allow the first keynode in
the list to point to an rdatalist of DS-style trust anchors. these will
be used by the validator to populate 'val->dsset' when validating a zone
key.
a DS style trust anchor can be updated as a result of RFC 5011
processing to contain DST keys instead; this results in the DS list
being freed. the reverse is not possible; attempting to add a DS-style
trust anchor if a key-style trust anchor is already in place results
in an error.
later, this should be refactored to use rdatalists for both DS-style
and key-style trust anchors, but we're keeping the existing code for
old-style trust anchors for now.
- val->keynode and val->seensig were set but never used.
- val->nearest, val->soaset, val->soaname, val->nsecset and val->nsec3set
were never used at all.
- pull out the code that checks whether a key was signed by a trust
anchor into a separate function, anchor_signed().
- pull out the code that looks up a DS while validating a zone key
into a separate function, get_dsset().
- check in create_validator() whether the sigrdataset is bound, so that
we can always pass in &val->fsigrdataset during an insecurity proof;
this will allow a reduction of code duplication.
- also simplified some calls: don't pass siginfo where val->siginfo
is sufficient, don't INSIST where returning false is sufficient.
- also added header comments to several local functions.
- ns__client_request() is now called by netmgr with an isc_nmhandle_t
parameter. The handle can then be permanently associated with an
ns_client object.
- The task manager is paused so that isc_task events that may be
triggred during client processing will not fire until after the netmgr is
finished with it. Before any asynchronous event, the client MUST
call isc_nmhandle_ref(client->handle), to prevent the client from
being reset and reused while waiting for an event to process. When
the asynchronous event is complete, isc_nmhandle_unref(client->handle)
must be called to ensure the handle can be reused later.
- reference counting of client objects is now handled in the nmhandle
object. when the handle references drop to zero, the client's "reset"
callback is used to free temporary resources and reiniialize it,
whereupon the handle (and associated client) is placed in the
"inactive handles" queue. when the sysstem is shutdown and the
handles are cleaned up, the client's "put" callback is called to free
all remaining resources.
- because client allocation is no longer handled in the same way,
the '-T clienttest' option has now been removed and is no longer
used by any system tests.
- the unit tests require wrapping the isc_nmhandle_unref() function;
when LD_WRAP is supported, that is used. otherwise we link a
libwrap.so interposer library and use that.
When a task manager is created, we can now specify an `isc_nm`
object to associate with it; thereafter when the task manager is
placed into exclusive mode, the network manager will be paused.
The double-locked queue implementation is still currently in use
in ns_client, but will be replaced by a fetch-and-add array queue.
This commit moves it from queue.h to list.h so that queue.h can be
used for the new data structure, and clean up dependencies between
list.h and types.h. Later, when the ISC_QUEUE is no longer is use,
it will be removed completely.
The kasp system tests are updated with 'check_cds' calls that will
verify that the correct CDS and CDNSKEY records are published during
a rollover and that they are signed with the correct KSK.
This requires a change in 'dnssec.c' to check the kasp key states
whether the CDS/CDNSKEY of a key should be published or not. If no
kasp state exist, fall back to key timings.
The 'sign_apex()' function has special processing for signing the
DNSKEY RRset such that it will always be signed with the active
KSK. Since CDS and CDNSKEY are also signed with the KSK, it
should have the same special processing. The special processing is
moved into a new function 'tickle_apex_rrset()' and is applied to
all three RR types (DNSKEY, CDS, CDNSKEY).
In addition, when kasp is involved, update the DNSKEY TTL accordingly
to what is in the policy.
Update dns_dnssec_keyactive to differentiate between the roles ZSK
and KSK. A key is active if it is signing but that differs per role.
A ZSK is signing if its ZRRSIG state is in RUMOURED or OMNIPRESENT,
a KSK is signing if its KRRSIG state is in RUMOURED or OMNIPRESENT.
This means that a key can be actively signing for one role but not
the other. Add checks in inline signing (zone.c and update.c) to
cover the case where a CSK is active in its KSK role but not the ZSK
role.
Update the signing code in lib/dns/zone.c and lib/dns/update.c to
use kasp logic if a dnssec-policy is enabled.
This means zones with dnssec-policy should no longer follow
'update-check-ksk' and 'dnssec-dnskey-kskonly' logic, instead the
KASP keys configured dictate which RRset gets signed with what key.
Also use the next rekey event from the key manager rather than
setting it to one hour.
Mark the zone dynamic, as otherwise a zone with dnssec-policy is
not eligble for automatic DNSSEC maintenance.
Update dns_dnssec_get_hints and dns_dnssec_keyactive to use dst_key
functions and thus if dnssec-policy/KASP is used the key states are
being considered.
Add a new variable to 'struct dns_dnsseckey' to signal whether this
key is a zone-signing key (it is no longer true that ksk == !zsk).
Also introduce a hint for revoke.
Update 'dns_dnssec_findzonekeys' and 'dns_dnssec_findmatchingkeys'
to also read the key state file, if available.
Remove 'allzsk' from 'dns_dnssec_updatekeys' as this was only a
hint for logging.
Also make get_hints() (now dns_dnssec_get_hints()) public so that
we can use it in the key manager.
Add a key manager to named. If a 'dnssec-policy' is set, 'named'
will run a key manager on the matching keys. This will do a couple
of things:
1. Create keys when needed (in case of rollover for example)
according to the set policy.
2. Retire keys that are in excess of the policy.
3. Maintain key states according to "Flexible and Robust Key
Rollover" [1]. After key manager ran, key files will be saved to
disk.
[1] https://matthijsmekking.nl/static/pdf/satin2012-Schaeffer.pdf
KEY GENERATION
Create keys according to DNSSEC policy. Zones configured with
'dnssec-policy' will allow 'named' to create DNSSEC keys (similar
to dnssec-keymgr) if not available.
KEY ROLLOVER
Rather than determining the desired state from timing metadata,
add a key state goal. Any keys that are created or picked from the
key ring and selected to be a successor has its key state goal set
to OMNIPRESENT (this key wants to be signing!). At the same time,
a key that is being retired has its key state goal set to HIDDEN.
The keymgr state machine with the three rules will make sure no
introduction or withdrawal of DNSSEC records happens too soon.
KEY TIMINGS
All timings are based on RFC 7583.
The keymgr will return when the next action is happening so
that the zone can set the proper rekey event. Prior to this change
the rekey event will run every hour by default (configurable),
but with kasp we can determine exactly when we need to run again.
The prepublication time is derived from policy.
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.
When doing rollover in a timely manner we need to have access to the
relevant kasp configured durations.
Most of these are simple get functions, but 'dns_kasp_signdelay'
will calculate the maximum time that is needed with this policy to
resign the complete zone (taking into account the refresh interval
and signature validity).
Introduce parent-propagation-delay, parent-registration-delay,
parent-ds-ttl, zone-max-ttl, zone-propagation-delay.
When signing a zone with dnssec-policy, we don't mind DNSSEC records.
This is useful for testing purposes, and perhaps it is better to
signal this behavior with a different configuration option.
Introduce a new option '-s' for dnssec-settime that when manipulating
timing metadata, it also updates the key state file.
For testing purposes, add options to dnssec-settime to set key
states and when they last changed.
The dst code adds ways to write and read the new key states and
timing metadata. It updates the parsing code for private key files
to not parse the newly introduced metadata (these are for state
files only).
Introduce key goal (the state the key wants to be in).
When reading a key from file, you can set the DST_TYPE_STATE option
to also read the key state.
This expects the Algorithm and Length fields go above the metadata,
so update the write functionality to do so accordingly.
Introduce new DST metadata types for KSK, ZSK, Lifetime and the
timing metadata used in state files.
Write functions to access various elements of the kasp structure,
and the kasp keys. This in preparation of code in dnssec-keygen,
dnssec-settime, named...
Add a number of metadata variables (lifetime, ksk and zsk role).
For the roles we add a new type of metadata (booleans).
Add a function to write the state of the key to a separate file.
Only write out known metadata to private file. With the
introduction of the numeric metadata "Lifetime", adjust the write
private key file functionality to only write out metadata it knows
about.