Merge branch '1134-dnssec-made-easy' into 'master'

DNSSEC Made Easy

Closes #1134

See merge request isc-projects/bind9!2458
This commit is contained in:
Matthijs Mekking 2019-11-06 22:40:53 +00:00
commit e7a9f52f50
96 changed files with 12292 additions and 1303 deletions

View file

@ -421,7 +421,7 @@ configure_zone(const char *vclass, const char *view,
obj = NULL;
if (get_maps(maps, "max-zone-ttl", &obj)) {
maxttl = cfg_obj_asuint32(obj);
maxttl = cfg_obj_asduration(obj);
zone_options |= DNS_ZONEOPT_CHECKTTL;
}

View file

@ -15,24 +15,26 @@ VERSION=@BIND9_VERSION@
@BIND9_MAKE_INCLUDES@
CINCLUDES = ${DNS_INCLUDES} ${ISC_INCLUDES} \
CINCLUDES = ${DNS_INCLUDES} ${ISC_INCLUDES} ${ISCCFG_INCLUDES} \
${OPENSSL_CFLAGS}
CDEFINES = -DVERSION=\"${VERSION}\"
CDEFINES = -DVERSION=\"${VERSION}\" -DNAMED_CONFFILE=\"${sysconfdir}/named.conf\"
CWARNINGS =
DNSLIBS = ../../lib/dns/libdns.@A@ ${MAXMINDDB_LIBS} @DNS_CRYPTO_LIBS@
ISCCFGLIBS = ../../lib/isccfg/libisccfg.@A@
ISCLIBS = ../../lib/isc/libisc.@A@ ${OPENSSL_LIBS} ${JSON_C_LIBS} ${LIBXML2_LIBS}
ISCNOSYMLIBS = ../../lib/isc/libisc-nosymtbl.@A@ ${OPENSSL_LIBS} ${JSON_C_LIBS} ${LIBXML2_LIBS}
DNSDEPLIBS = ../../lib/dns/libdns.@A@
ISCDEPLIBS = ../../lib/isc/libisc.@A@
ISCCFGDEPLIBS = ../../lib/isccfg/libisccfg.@A@
DEPLIBS = ${DNSDEPLIBS} ${ISCDEPLIBS}
DEPLIBS = ${DNSDEPLIBS} ${ISCCFGDEPLIBS} ${ISCDEPLIBS}
LIBS = ${DNSLIBS} ${ISCLIBS} @LIBS@
LIBS = ${DNSLIBS} ${ISCCFGLIBS} ${ISCLIBS} @LIBS@
NOSYMLIBS = ${DNSLIBS} ${ISCNOSYMLIBS} @LIBS@
NOSYMLIBS = ${DNSLIBS} ${ISCCFGLIBS} ${ISCNOSYMLIBS} @LIBS@
# Alphabetically
TARGETS = dnssec-cds@EXEEXT@ dnssec-dsfromkey@EXEEXT@ \
@ -48,7 +50,7 @@ SRCS = dnssec-cds.c dnssec-dsfromkey.c dnssec-importkey.c \
dnssec-settime.c dnssec-signzone.c dnssec-verify.c \
dnssectool.c
MANPAGES = dnssec-cds.8 dnssec-dsfromkey.8 dnssec-importkey.8 \
MANPAGES = dnssec-cds.8 dnssec-dsfromkey.8 dnssec-importkey.8 \
dnssec-keyfromlabel.8 dnssec-keygen.8 dnssec-revoke.8 \
dnssec-settime.8 dnssec-signzone.8 dnssec-verify.8

File diff suppressed because it is too large Load diff

View file

@ -66,6 +66,7 @@
<arg choice="opt" rep="norepeat"><option>-c <replaceable class="parameter">class</replaceable></option></arg>
<arg choice="opt" rep="norepeat"><option>-D <replaceable class="parameter">date/offset</replaceable></option></arg>
<arg choice="opt" rep="norepeat"><option>-D sync <replaceable class="parameter">date/offset</replaceable></option></arg>
<arg choice="opt" rep="norepeat"><option>-d <replaceable class="parameter">bits</replaceable></option></arg>
<arg choice="opt" rep="norepeat"><option>-E <replaceable class="parameter">engine</replaceable></option></arg>
<arg choice="opt" rep="norepeat"><option>-f <replaceable class="parameter">flag</replaceable></option></arg>
<arg choice="opt" rep="norepeat"><option>-G</option></arg>
@ -74,8 +75,9 @@
<arg choice="opt" rep="norepeat"><option>-I <replaceable class="parameter">date/offset</replaceable></option></arg>
<arg choice="opt" rep="norepeat"><option>-i <replaceable class="parameter">interval</replaceable></option></arg>
<arg choice="opt" rep="norepeat"><option>-K <replaceable class="parameter">directory</replaceable></option></arg>
<arg choice="opt" rep="norepeat"><option>-k</option></arg>
<arg choice="opt" rep="norepeat"><option>-k <replaceable class="parameter">policy</replaceable></option></arg>
<arg choice="opt" rep="norepeat"><option>-L <replaceable class="parameter">ttl</replaceable></option></arg>
<arg choice="opt" rep="norepeat"><option>-l <replaceable class="parameter">file</replaceable></option></arg>
<arg choice="opt" rep="norepeat"><option>-n <replaceable class="parameter">nametype</replaceable></option></arg>
<arg choice="opt" rep="norepeat"><option>-P <replaceable class="parameter">date/offset</replaceable></option></arg>
<arg choice="opt" rep="norepeat"><option>-P sync <replaceable class="parameter">date/offset</replaceable></option></arg>
@ -84,6 +86,7 @@
<arg choice="opt" rep="norepeat"><option>-R <replaceable class="parameter">date/offset</replaceable></option></arg>
<arg choice="opt" rep="norepeat"><option>-S <replaceable class="parameter">key</replaceable></option></arg>
<arg choice="opt" rep="norepeat"><option>-s <replaceable class="parameter">strength</replaceable></option></arg>
<arg choice="opt" rep="norepeat"><option>-T <replaceable class="parameter">rrtype</replaceable></option></arg>
<arg choice="opt" rep="norepeat"><option>-t <replaceable class="parameter">type</replaceable></option></arg>
<arg choice="opt" rep="norepeat"><option>-V</option></arg>
<arg choice="opt" rep="norepeat"><option>-v <replaceable class="parameter">level</replaceable></option></arg>
@ -207,6 +210,18 @@
</listitem>
</varlistentry>
<varlistentry>
<term>-d <replaceable class="parameter">bits</replaceable></term>
<listitem>
<para>
Key size in bits. For the algorithms RSASHA1, NSEC3RSASA1,
RSASHA256 and RSASHA512 the key size must be in range 1024-4096.
DH size is between 128 and 4096. This option is ignored for
algorithms ECDSAP256SHA256, ECDSAP384SHA384, ED25519 and ED448.
</para>
</listitem>
</varlistentry>
<varlistentry>
<term>-E <replaceable class="parameter">engine</replaceable></term>
<listitem>
@ -275,6 +290,24 @@
</listitem>
</varlistentry>
<varlistentry>
<term>-k <replaceable class="parameter">policy</replaceable></term>
<listitem>
<para>
Create keys for a specific dnssec-policy. If a policy uses
multiple keys, <command>dnssec-keygen</command> will generate
multiple keys. This will also create a ".state" file to keep
track of the key state.
</para>
<para>
This option creates keys according to the dnssec-policy
configuration, hence it cannot be used together with many of
the other options that <command>dnssec-keygen</command>
provides.
</para>
</listitem>
</varlistentry>
<varlistentry>
<term>-L <replaceable class="parameter">ttl</replaceable></term>
<listitem>
@ -291,6 +324,16 @@
</listitem>
</varlistentry>
<varlistentry>
<term>-l <replaceable class="parameter">file</replaceable></term>
<listitem>
<para>
Provide a configuration file that contains a dnssec-policy
statement (matching the policy set with <command>-k</command>).
</para>
</listitem>
</varlistentry>
<varlistentry>
<term>-n <replaceable class="parameter">nametype</replaceable></term>
<listitem>

View file

@ -88,6 +88,15 @@ usage(void) {
fprintf(stderr, " -i <interval>: prepublication interval for "
"successor key "
"(default: 30 days)\n");
fprintf(stderr, "Key state options:\n");
fprintf(stderr, " -s: update key state file (default no)\n");
fprintf(stderr, " -g state: set the goal state for this key\n");
fprintf(stderr, " -d state date/[+-]offset: set the DS state\n");
fprintf(stderr, " -k state date/[+-]offset: set the DNSKEY state\n");
fprintf(stderr, " -r state date/[+-]offset: set the RRSIG (KSK) "
"state\n");
fprintf(stderr, " -z state date/[+-]offset: set the RRSIG (ZSK) "
"state\n");
fprintf(stderr, "Printing options:\n");
fprintf(stderr, " -p C/P/Psync/A/R/I/D/Dsync/all: print a "
"particular time value or values\n");
@ -123,29 +132,87 @@ printtime(dst_key_t *key, int type, const char *tag, bool epoch,
}
}
static void
writekey(dst_key_t *key, const char *directory, bool write_state)
{
char newname[1024];
char keystr[DST_KEY_FORMATSIZE];
isc_buffer_t buf;
isc_result_t result;
int options = DST_TYPE_PUBLIC|DST_TYPE_PRIVATE;
if (write_state) {
options |= DST_TYPE_STATE;
}
isc_buffer_init(&buf, newname, sizeof(newname));
result = dst_key_buildfilename(key, DST_TYPE_PUBLIC, directory, &buf);
if (result != ISC_R_SUCCESS) {
fatal("Failed to build public key filename: %s",
isc_result_totext(result));
}
result = dst_key_tofile(key, options, directory);
if (result != ISC_R_SUCCESS) {
dst_key_format(key, keystr, sizeof(keystr));
fatal("Failed to write key %s: %s", keystr,
isc_result_totext(result));
}
printf("%s\n", newname);
isc_buffer_clear(&buf);
result = dst_key_buildfilename(key, DST_TYPE_PRIVATE, directory, &buf);
if (result != ISC_R_SUCCESS) {
fatal("Failed to build private key filename: %s",
isc_result_totext(result));
}
printf("%s\n", newname);
if (write_state) {
isc_buffer_clear(&buf);
result = dst_key_buildfilename(key, DST_TYPE_STATE, directory,
&buf);
if (result != ISC_R_SUCCESS) {
fatal("Failed to build key state filename: %s",
isc_result_totext(result));
}
printf("%s\n", newname);
}
}
int
main(int argc, char **argv) {
isc_result_t result;
const char *engine = NULL;
const char *filename = NULL;
char *directory = NULL;
char newname[1024];
char keystr[DST_KEY_FORMATSIZE];
char *endp, *p;
int ch;
const char *predecessor = NULL;
dst_key_t *prevkey = NULL;
dst_key_t *key = NULL;
isc_buffer_t buf;
dns_name_t *name = NULL;
dns_secalg_t alg = 0;
unsigned int size = 0;
uint16_t flags = 0;
int prepub = -1;
int options;
dns_ttl_t ttl = 0;
isc_stdtime_t now;
isc_stdtime_t dstime = 0, dnskeytime = 0;
isc_stdtime_t krrsigtime = 0, zrrsigtime = 0;
isc_stdtime_t pub = 0, act = 0, rev = 0, inact = 0, del = 0;
isc_stdtime_t prevact = 0, previnact = 0, prevdel = 0;
dst_key_state_t goal = DST_KEY_STATE_NA;
dst_key_state_t ds = DST_KEY_STATE_NA;
dst_key_state_t dnskey = DST_KEY_STATE_NA;
dst_key_state_t krrsig = DST_KEY_STATE_NA;
dst_key_state_t zrrsig = DST_KEY_STATE_NA;
bool setgoal = false, setds = false, setdnskey = false;
bool setkrrsig = false, setzrrsig = false;
bool setdstime = false, setdnskeytime = false;
bool setkrrsigtime = false, setzrrsigtime = false;
bool setpub = false, setact = false;
bool setrev = false, setinact = false;
bool setdel = false, setttl = false;
@ -156,14 +223,17 @@ main(int argc, char **argv) {
bool printact = false, printrev = false;
bool printinact = false, printdel = false;
bool force = false;
bool epoch = false;
bool changed = false;
bool epoch = false;
bool changed = false;
bool write_state = false;
isc_log_t *log = NULL;
isc_stdtime_t syncadd = 0, syncdel = 0;
bool unsetsyncadd = false, setsyncadd = false;
bool unsetsyncdel = false, setsyncdel = false;
bool printsyncadd = false, printsyncdel = false;
options = DST_TYPE_PUBLIC|DST_TYPE_PRIVATE|DST_TYPE_STATE;
if (argc == 1)
usage();
@ -180,7 +250,7 @@ main(int argc, char **argv) {
isc_stdtime_get(&now);
#define CMDLINE_FLAGS "A:D:E:fhI:i:K:L:P:p:R:S:uv:V"
#define CMDLINE_FLAGS "A:D:d:E:fg:hI:i:K:k:L:P:p:R:r:S:suv:Vz:"
while ((ch = isc_commandline_parse(argc, argv, CMDLINE_FLAGS)) != -1) {
switch (ch) {
case 'E':
@ -339,6 +409,70 @@ main(int argc, char **argv) {
case 'i':
prepub = strtottl(isc_commandline_argument);
break;
case 's':
write_state = true;
break;
case 'g':
if (setgoal) {
fatal("-g specified more than once");
}
goal = strtokeystate(isc_commandline_argument);
if (goal != DST_KEY_STATE_NA &&
goal != DST_KEY_STATE_HIDDEN &&
goal != DST_KEY_STATE_OMNIPRESENT) {
fatal("-g must be either none, hidden, or "
"omnipresent");
}
setgoal = true;
break;
case 'd':
if (setds) {
fatal("-d specified more than once");
}
ds = strtokeystate(isc_commandline_argument);
setds = true;
/* time */
(void)isoptarg(isc_commandline_argument, argv, usage);
dstime = strtotime(isc_commandline_argument,
now, now, &setdstime);
break;
case 'k':
if (setdnskey) {
fatal("-k specified more than once");
}
dnskey = strtokeystate(isc_commandline_argument);
setdnskey = true;
/* time */
(void)isoptarg(isc_commandline_argument, argv, usage);
dnskeytime = strtotime(isc_commandline_argument,
now, now, &setdnskeytime);
break;
case 'r':
if (setkrrsig) {
fatal("-r specified more than once");
}
krrsig = strtokeystate(isc_commandline_argument);
setkrrsig = true;
/* time */
(void)isoptarg(isc_commandline_argument, argv, usage);
krrsigtime = strtotime(isc_commandline_argument,
now, now, &setkrrsigtime);
break;
case 'z':
if (setzrrsig) {
fatal("-z specified more than once");
}
zrrsig = strtokeystate(isc_commandline_argument);
setzrrsig = true;
(void)isoptarg(isc_commandline_argument, argv, usage);
zrrsigtime = strtotime(isc_commandline_argument,
now, now, &setzrrsigtime);
break;
case '?':
if (isc_commandline_option != '?')
fprintf(stderr, "%s: invalid argument -%c\n",
@ -365,6 +499,12 @@ main(int argc, char **argv) {
if (argc > isc_commandline_index + 1)
fatal("Extraneous arguments");
if ((setgoal || setds || setdnskey || setkrrsig || setzrrsig) &&
!write_state)
{
fatal("Options -g, -d, -k, -r and -z require -s to be set");
}
result = dst_lib_init(mctx, engine);
if (result != ISC_R_SUCCESS)
fatal("Could not initialize dst: %s",
@ -381,9 +521,7 @@ main(int argc, char **argv) {
if (setact || unsetact)
fatal("-S and -A cannot be used together");
result = dst_key_fromnamedfile(predecessor, directory,
DST_TYPE_PUBLIC |
DST_TYPE_PRIVATE,
result = dst_key_fromnamedfile(predecessor, directory, options,
mctx, &prevkey);
if (result != ISC_R_SUCCESS)
fatal("Invalid keyfile %s: %s",
@ -475,9 +613,8 @@ main(int argc, char **argv) {
isc_result_totext(result));
}
result = dst_key_fromnamedfile(filename, directory,
DST_TYPE_PUBLIC | DST_TYPE_PRIVATE,
mctx, &key);
result = dst_key_fromnamedfile(filename, directory, options, mctx,
&key);
if (result != ISC_R_SUCCESS)
fatal("Invalid keyfile %s: %s",
filename, isc_result_totext(result));
@ -578,6 +715,11 @@ main(int argc, char **argv) {
if (setttl)
dst_key_setttl(key, ttl);
if (predecessor != NULL && prevkey != NULL) {
dst_key_setnum(prevkey, DST_NUM_SUCCESSOR, dst_key_id(key));
dst_key_setnum(key, DST_NUM_PREDECESSOR, dst_key_id(prevkey));
}
/*
* No metadata changes were made but we're forcing an upgrade
* to the new format anyway: use "-P now -A now" as the default
@ -588,6 +730,63 @@ main(int argc, char **argv) {
changed = true;
}
/*
* Make sure the key state goals are written.
*/
if (write_state) {
if (setgoal) {
if (goal == DST_KEY_STATE_NA) {
dst_key_unsetstate(key, DST_KEY_GOAL);
} else {
dst_key_setstate(key, DST_KEY_GOAL, goal);
}
changed = true;
}
if (setds) {
if (ds == DST_KEY_STATE_NA) {
dst_key_unsetstate(key, DST_KEY_DS);
dst_key_unsettime(key, DST_TIME_DS);
} else {
dst_key_setstate(key, DST_KEY_DS, ds);
dst_key_settime(key, DST_TIME_DS, dstime);
}
changed = true;
}
if (setdnskey) {
if (dnskey == DST_KEY_STATE_NA) {
dst_key_unsetstate(key, DST_KEY_DNSKEY);
dst_key_unsettime(key, DST_TIME_DNSKEY);
} else {
dst_key_setstate(key, DST_KEY_DNSKEY, dnskey);
dst_key_settime(key, DST_TIME_DNSKEY,
dnskeytime);
}
changed = true;
}
if (setkrrsig) {
if (krrsig == DST_KEY_STATE_NA) {
dst_key_unsetstate(key, DST_KEY_KRRSIG);
dst_key_unsettime(key, DST_TIME_KRRSIG);
} else {
dst_key_setstate(key, DST_KEY_KRRSIG, krrsig);
dst_key_settime(key, DST_TIME_KRRSIG,
krrsigtime);
}
changed = true;
}
if (setzrrsig) {
if (zrrsig == DST_KEY_STATE_NA) {
dst_key_unsetstate(key, DST_KEY_ZRRSIG);
dst_key_unsettime(key, DST_TIME_ZRRSIG);
} else {
dst_key_setstate(key, DST_KEY_ZRRSIG, zrrsig);
dst_key_settime(key, DST_TIME_ZRRSIG,
zrrsigtime);
}
changed = true;
}
}
if (!changed && setttl)
changed = true;
@ -621,32 +820,10 @@ main(int argc, char **argv) {
epoch, stdout);
if (changed) {
isc_buffer_init(&buf, newname, sizeof(newname));
result = dst_key_buildfilename(key, DST_TYPE_PUBLIC, directory,
&buf);
if (result != ISC_R_SUCCESS) {
fatal("Failed to build public key filename: %s",
isc_result_totext(result));
writekey(key, directory, write_state);
if (predecessor != NULL && prevkey != NULL) {
writekey(prevkey, directory, write_state);
}
result = dst_key_tofile(key, DST_TYPE_PUBLIC|DST_TYPE_PRIVATE,
directory);
if (result != ISC_R_SUCCESS) {
dst_key_format(key, keystr, sizeof(keystr));
fatal("Failed to write key %s: %s", keystr,
isc_result_totext(result));
}
printf("%s\n", newname);
isc_buffer_clear(&buf);
result = dst_key_buildfilename(key, DST_TYPE_PRIVATE, directory,
&buf);
if (result != ISC_R_SUCCESS) {
fatal("Failed to build private key filename: %s",
isc_result_totext(result));
}
printf("%s\n", newname);
}
if (prevkey != NULL)

View file

@ -64,6 +64,12 @@
<arg choice="opt" rep="norepeat"><option>-V</option></arg>
<arg choice="opt" rep="norepeat"><option>-v <replaceable class="parameter">level</replaceable></option></arg>
<arg choice="opt" rep="norepeat"><option>-E <replaceable class="parameter">engine</replaceable></option></arg>
<arg choice="opt" rep="norepeat"><option>-s</option></arg>
<arg choice="opt" rep="norepeat"><option>-g <replaceable class="parameter">state</replaceable></option></arg>
<arg choice="opt" rep="norepeat"><option>-d <replaceable class="parameter">state</replaceable> <replaceable class="parameter">date/offset</replaceable></option></arg>
<arg choice="opt" rep="norepeat"><option>-k <replaceable class="parameter">state</replaceable> <replaceable class="parameter">date/offset</replaceable></option></arg>
<arg choice="opt" rep="norepeat"><option>-r <replaceable class="parameter">state</replaceable> <replaceable class="parameter">date/offset</replaceable></option></arg>
<arg choice="opt" rep="norepeat"><option>-z <replaceable class="parameter">state</replaceable> <replaceable class="parameter">date/offset</replaceable></option></arg>
<arg choice="req" rep="norepeat">keyfile</arg>
</cmdsynopsis>
</refsynopsisdiv>
@ -88,11 +94,30 @@
When key metadata fields are changed, both files of a key
pair (<filename>Knnnn.+aaa+iiiii.key</filename> and
<filename>Knnnn.+aaa+iiiii.private</filename>) are regenerated.
</para>
<para>
Metadata fields are stored in the private file. A human-readable
description of the metadata is also placed in comments in the key
file. The private file's permissions are always set to be
inaccessible to anyone other than the owner (mode 0600).
</para>
<para>
When working with state files, it is possible to update the timing
metadata in those files as well with <option>-s</option>. If this
option is used you can also update key states with <option>-d</option>
(DS), <option>-k</option> (DNSKEY), <option>-r</option> (RRSIG of KSK),
or <option>-z</option> (RRSIG of ZSK). Allowed states are HIDDEN,
RUMOURED, OMNIPRESENT, and UNRETENTIVE.
</para>
<para>
You can also set the goal state of the key with <option>-g</option>.
This should be either HIDDEN or OMNIPRESENT (representing whether the
key should be removed from the zone, or published).
</para>
<para>
It is NOT RECOMMENDED to manipulate state files manually except for
testing purposes.
</para>
</refsection>
<refsection><info><title>OPTIONS</title></info>
@ -319,6 +344,74 @@
</variablelist>
</refsection>
<refsection><info><title>KEY STATE OPTIONS</title></info>
<para>
Known key states are HIDDEN, RUMOURED, OMNIPRESENT and UNRETENTIVE.
These should not be set manually except for testing purposes.
</para>
<variablelist>
<varlistentry>
<term>-s</term>
<listitem>
<para>
When setting key timing data, also update the state file.
</para>
</listitem>
</varlistentry>
<varlistentry>
<term>-g</term>
<listitem>
<para>
Set the goal state for this key. Must be HIDDEN or OMNIPRESENT.
</para>
</listitem>
</varlistentry>
<varlistentry>
<term>-d</term>
<listitem>
<para>
Set the DS state for this key, and when it was last changed.
</para>
</listitem>
</varlistentry>
<varlistentry>
<term>-k</term>
<listitem>
<para>
Set the DNSKEY state for this key, and when it was last changed.
</para>
</listitem>
</varlistentry>
<varlistentry>
<term>-r</term>
<listitem>
<para>
Set the RRSIG (KSK) state for this key, and when it was last
changed.
</para>
</listitem>
</varlistentry>
<varlistentry>
<term>-z</term>
<listitem>
<para>
Set the RRSIG (ZSK) state for this key, and when it was last
changed.
</para>
</listitem>
</varlistentry>
</variablelist>
</refsection>
<refsection><info><title>PRINTING OPTIONS</title></info>
<para>

View file

@ -2717,7 +2717,7 @@ build_final_keylist(void) {
* Update keylist with information from from the key repository.
*/
dns_dnssec_updatekeys(&keylist, &matchkeys, NULL, gorigin, keyttl,
&diff, ignore_kskflag, mctx, report);
&diff, mctx, report);
/*
* Update keylist with sync records.

View file

@ -57,6 +57,11 @@
#include "dnssectool.h"
#define KEYSTATES_NVALUES 4
static const char *keystates[KEYSTATES_NVALUES] = {
"hidden", "rumoured", "omnipresent", "unretentive",
};
int verbose = 0;
bool quiet = false;
uint8_t dtype[8];
@ -244,6 +249,21 @@ strtottl(const char *str) {
return (ttl);
}
dst_key_state_t
strtokeystate(const char *str) {
if (isnone(str)) {
return (DST_KEY_STATE_NA);
}
for (int i = 0; i < KEYSTATES_NVALUES; i++) {
if (keystates[i] != NULL &&
strcasecmp(str, keystates[i]) == 0) {
return (dst_key_state_t) i;
}
}
fatal("unknown key state");
}
isc_stdtime_t
strtotime(const char *str, int64_t now, int64_t base,
bool *setp)

View file

@ -71,6 +71,8 @@ cleanup_logging(isc_log_t **logp);
dns_ttl_t strtottl(const char *str);
dst_key_state_t strtokeystate(const char *str);
isc_stdtime_t
strtotime(const char *str, int64_t now, int64_t base,
bool *setp);

View file

@ -66,15 +66,15 @@
<ProgramDataBaseFileName>$(OutDir)$(TargetName).pdb</ProgramDataBaseFileName>
<BrowseInformation>true</BrowseInformation>
<ForcedIncludeFiles>..\..\..\config.h</ForcedIncludeFiles>
<AdditionalIncludeDirectories>.\;..\..\..\;@LIBXML2_INC@@OPENSSL_INC@..\..\..\lib\isc\win32;..\..\..\lib\isc\win32\include;..\..\..\lib\isc\include;..\..\..\lib\dns\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<AdditionalIncludeDirectories>.\;..\..\..\;@LIBXML2_INC@@OPENSSL_INC@..\..\..\lib\isc\win32;..\..\..\lib\isc\win32\include;..\..\..\lib\isc\include;..\..\..\lib\isccfg\win32;..\..\..\lib\isccfg\include;..\..\..\lib\dns\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<CompileAs>CompileAsC</CompileAs>
</ClCompile>
<Link>
<SubSystem>Console</SubSystem>
<GenerateDebugInformation>true</GenerateDebugInformation>
<OutputFile>..\..\..\Build\$(Configuration)\$(TargetName)$(TargetExt)</OutputFile>
<AdditionalDependencies>@OPENSSL_LIB@dnssectool.lib;libisc.lib;libdns.lib;ws2_32.lib;%(AdditionalDependencies)</AdditionalDependencies>
<AdditionalLibraryDirectories>$(Configuration);..\..\..\lib\isc\win32\$(Configuration);..\..\..\lib\dns\win32\$(Configuration);%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
<AdditionalDependencies>@OPENSSL_LIB@dnssectool.lib;libisc.lib;libisccfg.lib;libdns.lib;ws2_32.lib;%(AdditionalDependencies)</AdditionalDependencies>
<AdditionalLibraryDirectories>$(Configuration);..\..\..\lib\isc\win32\$(Configuration);..\..\..\lib\isccfg\win32\$(Configuration);..\..\..\lib\dns\win32\$(Configuration);%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|@PLATFORM@'">
@ -94,7 +94,7 @@
<ObjectFileName>.\$(Configuration)\</ObjectFileName>
<ProgramDataBaseFileName>$(OutDir)$(TargetName).pdb</ProgramDataBaseFileName>
<ForcedIncludeFiles>..\..\..\config.h</ForcedIncludeFiles>
<AdditionalIncludeDirectories>.\;..\..\..\;@LIBXML2_INC@@OPENSSL_INC@..\..\..\lib\isc\win32;..\..\..\lib\isc\win32\include;..\..\..\lib\isc\include;..\..\..\lib\dns\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<AdditionalIncludeDirectories>.\;..\..\..\;@LIBXML2_INC@@OPENSSL_INC@..\..\..\lib\isc\win32;..\..\..\lib\isc\win32\include;..\..\..\lib\isc\include;..\..\..\lib\isccfg\win32;..\..\..\lib\isccfg\include;..\..\..\lib\dns\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<CompileAs>CompileAsC</CompileAs>
</ClCompile>
<Link>
@ -104,8 +104,8 @@
<OptimizeReferences>true</OptimizeReferences>
<OutputFile>..\..\..\Build\$(Configuration)\$(TargetName)$(TargetExt)</OutputFile>
<LinkTimeCodeGeneration>Default</LinkTimeCodeGeneration>
<AdditionalDependencies>@OPENSSL_LIB@dnssectool.lib;libisc.lib;libdns.lib;ws2_32.lib;%(AdditionalDependencies)</AdditionalDependencies>
<AdditionalLibraryDirectories>$(Configuration);..\..\..\lib\isc\win32\$(Configuration);..\..\..\lib\dns\win32\$(Configuration);%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
<AdditionalDependencies>@OPENSSL_LIB@dnssectool.lib;libisc.lib;libisccfg.lib;libdns.lib;ws2_32.lib;%(AdditionalDependencies)</AdditionalDependencies>
<AdditionalLibraryDirectories>$(Configuration);..\..\..\lib\isc\win32\$(Configuration);..\..\..\lib\isccfg\win32\$(Configuration);..\..\..\lib\dns\win32\$(Configuration);%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
</Link>
</ItemDefinitionGroup>
<ItemGroup>

View file

@ -58,6 +58,7 @@ options {\n\
"\
# deallocate-on-exit <obsolete>;\n\
# directory <none>\n\
dnssec-policy \"none\";\n\
dump-file \"named_dump.db\";\n\
edns-udp-size 4096;\n\
# fake-iquery <obsolete>;\n"

View file

@ -64,6 +64,7 @@ struct named_server {
dns_loadmgr_t * loadmgr;
dns_zonemgr_t * zonemgr;
dns_viewlist_t viewlist;
dns_kasplist_t kasplist;
ns_interfacemgr_t * interfacemgr;
dns_db_t * in_roothints;

View file

@ -27,19 +27,18 @@ ISC_LANG_BEGINDECLS
isc_result_t
named_zone_configure(const cfg_obj_t *config, const cfg_obj_t *vconfig,
const cfg_obj_t *zconfig, cfg_aclconfctx_t *ac,
dns_zone_t *zone, dns_zone_t *raw);
dns_kasplist_t* kasplist, dns_zone_t *zone,
dns_zone_t *raw);
/*%<
* Configure or reconfigure a zone according to the named.conf
* data in 'cctx' and 'czone'.
* data.
*
* The zone origin is not configured, it is assumed to have been set
* at zone creation time.
*
* Require:
* \li 'lctx' to be initialized or NULL.
* \li 'cctx' to be initialized or NULL.
* \li 'ac' to point to an initialized cfg_aclconfctx_t.
* \li 'czone' to be initialized.
* \li 'kasplist' to be initialized.
* \li 'zone' to be initialized.
*/

View file

@ -208,7 +208,7 @@ options {
[ dscp <replaceable>integer</replaceable> ] { ( <replaceable>masters</replaceable> | <replaceable>ipv4_address</replaceable> [ port
<replaceable>integer</replaceable> ] | <replaceable>ipv6_address</replaceable> [ port <replaceable>integer</replaceable> ] ) [ key
<replaceable>string</replaceable> ]; ... } ] [ zone-directory <replaceable>quoted_string</replaceable> ] [
in-memory <replaceable>boolean</replaceable> ] [ min-update-interval <replaceable>ttlval</replaceable> ]; ... };
in-memory <replaceable>boolean</replaceable> ] [ min-update-interval <replaceable>duration</replaceable> ]; ... };
check-dup-records ( fail | warn | ignore );
check-integrity <replaceable>boolean</replaceable>;
check-mx ( fail | warn | ignore );
@ -290,18 +290,18 @@ options {
fstrm-set-output-notify-threshold <replaceable>integer</replaceable>;
fstrm-set-output-queue-model ( mpsc | spsc );
fstrm-set-output-queue-size <replaceable>integer</replaceable>;
fstrm-set-reopen-interval <replaceable>ttlval</replaceable>;
fstrm-set-reopen-interval <replaceable>duration</replaceable>;
geoip-directory ( <replaceable>quoted_string</replaceable> | none );
glue-cache <replaceable>boolean</replaceable>;
heartbeat-interval <replaceable>integer</replaceable>;
hostname ( <replaceable>quoted_string</replaceable> | none );
inline-signing <replaceable>boolean</replaceable>;
interface-interval <replaceable>ttlval</replaceable>;
interface-interval <replaceable>duration</replaceable>;
ixfr-from-differences ( primary | master | secondary | slave |
<replaceable>boolean</replaceable> );
keep-response-order { <replaceable>address_match_element</replaceable>; ... };
key-directory <replaceable>quoted_string</replaceable>;
lame-ttl <replaceable>ttlval</replaceable>;
lame-ttl <replaceable>duration</replaceable>;
listen-on [ port <replaceable>integer</replaceable> ] [ dscp
<replaceable>integer</replaceable> ] {
<replaceable>address_match_element</replaceable>; ... };
@ -315,28 +315,28 @@ options {
masterfile-style ( full | relative );
match-mapped-addresses <replaceable>boolean</replaceable>;
max-cache-size ( default | unlimited | <replaceable>sizeval</replaceable> | <replaceable>percentage</replaceable> );
max-cache-ttl <replaceable>ttlval</replaceable>;
max-cache-ttl <replaceable>duration</replaceable>;
max-clients-per-query <replaceable>integer</replaceable>;
max-journal-size ( default | unlimited | <replaceable>sizeval</replaceable> );
max-ncache-ttl <replaceable>ttlval</replaceable>;
max-ncache-ttl <replaceable>duration</replaceable>;
max-records <replaceable>integer</replaceable>;
max-recursion-depth <replaceable>integer</replaceable>;
max-recursion-queries <replaceable>integer</replaceable>;
max-refresh-time <replaceable>integer</replaceable>;
max-retry-time <replaceable>integer</replaceable>;
max-rsa-exponent-size <replaceable>integer</replaceable>;
max-stale-ttl <replaceable>ttlval</replaceable>;
max-stale-ttl <replaceable>duration</replaceable>;
max-transfer-idle-in <replaceable>integer</replaceable>;
max-transfer-idle-out <replaceable>integer</replaceable>;
max-transfer-time-in <replaceable>integer</replaceable>;
max-transfer-time-out <replaceable>integer</replaceable>;
max-udp-size <replaceable>integer</replaceable>;
max-zone-ttl ( unlimited | <replaceable>ttlval</replaceable> );
max-zone-ttl ( unlimited | <replaceable>duration</replaceable> );
memstatistics <replaceable>boolean</replaceable>;
memstatistics-file <replaceable>quoted_string</replaceable>;
message-compression <replaceable>boolean</replaceable>;
min-cache-ttl <replaceable>ttlval</replaceable>;
min-ncache-ttl <replaceable>ttlval</replaceable>;
min-cache-ttl <replaceable>duration</replaceable>;
min-ncache-ttl <replaceable>duration</replaceable>;
min-refresh-time <replaceable>integer</replaceable>;
min-retry-time <replaceable>integer</replaceable>;
minimal-any <replaceable>boolean</replaceable>;
@ -353,8 +353,8 @@ options {
notify-source-v6 ( <replaceable>ipv6_address</replaceable> | * ) [ port ( <replaceable>integer</replaceable> | * ) ]
[ dscp <replaceable>integer</replaceable> ];
notify-to-soa <replaceable>boolean</replaceable>;
nta-lifetime <replaceable>ttlval</replaceable>;
nta-recheck <replaceable>ttlval</replaceable>;
nta-lifetime <replaceable>duration</replaceable>;
nta-recheck <replaceable>duration</replaceable>;
nxdomain-redirect <replaceable>string</replaceable>;
pid-file ( <replaceable>quoted_string</replaceable> | none );
port <replaceable>integer</replaceable>;
@ -401,13 +401,13 @@ options {
response-padding { <replaceable>address_match_element</replaceable>; ... } block-size
<replaceable>integer</replaceable>;
response-policy { zone <replaceable>string</replaceable> [ add-soa <replaceable>boolean</replaceable> ] [ log
<replaceable>boolean</replaceable> ] [ max-policy-ttl <replaceable>ttlval</replaceable> ] [ min-update-interval
<replaceable>ttlval</replaceable> ] [ policy ( cname | disabled | drop | given | no-op |
<replaceable>boolean</replaceable> ] [ max-policy-ttl <replaceable>duration</replaceable> ] [ min-update-interval
<replaceable>duration</replaceable> ] [ policy ( cname | disabled | drop | given | no-op |
nodata | nxdomain | passthru | tcp-only <replaceable>quoted_string</replaceable> ) ] [
recursive-only <replaceable>boolean</replaceable> ] [ nsip-enable <replaceable>boolean</replaceable> ] [
nsdname-enable <replaceable>boolean</replaceable> ]; ... } [ add-soa <replaceable>boolean</replaceable> ] [
break-dnssec <replaceable>boolean</replaceable> ] [ max-policy-ttl <replaceable>ttlval</replaceable> ] [
min-update-interval <replaceable>ttlval</replaceable> ] [ min-ns-dots <replaceable>integer</replaceable> ] [
break-dnssec <replaceable>boolean</replaceable> ] [ max-policy-ttl <replaceable>duration</replaceable> ] [
min-update-interval <replaceable>duration</replaceable> ] [ min-ns-dots <replaceable>integer</replaceable> ] [
nsip-wait-recurse <replaceable>boolean</replaceable> ] [ qname-wait-recurse <replaceable>boolean</replaceable> ]
[ recursive-only <replaceable>boolean</replaceable> ] [ nsip-enable <replaceable>boolean</replaceable> ] [
nsdname-enable <replaceable>boolean</replaceable> ] [ dnsrps-enable <replaceable>boolean</replaceable> ] [
@ -421,7 +421,7 @@ options {
serial-query-rate <replaceable>integer</replaceable>;
serial-update-method ( date | increment | unixtime );
server-id ( <replaceable>quoted_string</replaceable> | none | hostname );
servfail-ttl <replaceable>ttlval</replaceable>;
servfail-ttl <replaceable>duration</replaceable>;
session-keyalg <replaceable>string</replaceable>;
session-keyfile ( <replaceable>quoted_string</replaceable> | none );
session-keyname <replaceable>string</replaceable>;
@ -432,7 +432,7 @@ options {
sortlist { <replaceable>address_match_element</replaceable>; ... };
stacksize ( default | unlimited | <replaceable>sizeval</replaceable> );
stale-answer-enable <replaceable>boolean</replaceable>;
stale-answer-ttl <replaceable>ttlval</replaceable>;
stale-answer-ttl <replaceable>duration</replaceable>;
startup-notify-rate <replaceable>integer</replaceable>;
statistics-file <replaceable>quoted_string</replaceable>;
synth-from-dnssec <replaceable>boolean</replaceable>;
@ -564,7 +564,7 @@ view <replaceable>string</replaceable> [ <replaceable>class</replaceable> ] {
[ dscp <replaceable>integer</replaceable> ] { ( <replaceable>masters</replaceable> | <replaceable>ipv4_address</replaceable> [ port
<replaceable>integer</replaceable> ] | <replaceable>ipv6_address</replaceable> [ port <replaceable>integer</replaceable> ] ) [ key
<replaceable>string</replaceable> ]; ... } ] [ zone-directory <replaceable>quoted_string</replaceable> ] [
in-memory <replaceable>boolean</replaceable> ] [ min-update-interval <replaceable>ttlval</replaceable> ]; ... };
in-memory <replaceable>boolean</replaceable> ] [ min-update-interval <replaceable>duration</replaceable> ]; ... };
check-dup-records ( fail | warn | ignore );
check-integrity <replaceable>boolean</replaceable>;
check-mx ( fail | warn | ignore );
@ -642,7 +642,7 @@ view <replaceable>string</replaceable> [ <replaceable>class</replaceable> ] {
secret <replaceable>string</replaceable>;
};
key-directory <replaceable>quoted_string</replaceable>;
lame-ttl <replaceable>ttlval</replaceable>;
lame-ttl <replaceable>duration</replaceable>;
lmdb-mapsize <replaceable>sizeval</replaceable>;
managed-keys { <replaceable>string</replaceable> (
static-key | initial-key
@ -655,25 +655,25 @@ view <replaceable>string</replaceable> [ <replaceable>class</replaceable> ] {
match-destinations { <replaceable>address_match_element</replaceable>; ... };
match-recursive-only <replaceable>boolean</replaceable>;
max-cache-size ( default | unlimited | <replaceable>sizeval</replaceable> | <replaceable>percentage</replaceable> );
max-cache-ttl <replaceable>ttlval</replaceable>;
max-cache-ttl <replaceable>duration</replaceable>;
max-clients-per-query <replaceable>integer</replaceable>;
max-journal-size ( default | unlimited | <replaceable>sizeval</replaceable> );
max-ncache-ttl <replaceable>ttlval</replaceable>;
max-ncache-ttl <replaceable>duration</replaceable>;
max-records <replaceable>integer</replaceable>;
max-recursion-depth <replaceable>integer</replaceable>;
max-recursion-queries <replaceable>integer</replaceable>;
max-refresh-time <replaceable>integer</replaceable>;
max-retry-time <replaceable>integer</replaceable>;
max-stale-ttl <replaceable>ttlval</replaceable>;
max-stale-ttl <replaceable>duration</replaceable>;
max-transfer-idle-in <replaceable>integer</replaceable>;
max-transfer-idle-out <replaceable>integer</replaceable>;
max-transfer-time-in <replaceable>integer</replaceable>;
max-transfer-time-out <replaceable>integer</replaceable>;
max-udp-size <replaceable>integer</replaceable>;
max-zone-ttl ( unlimited | <replaceable>ttlval</replaceable> );
max-zone-ttl ( unlimited | <replaceable>duration</replaceable> );
message-compression <replaceable>boolean</replaceable>;
min-cache-ttl <replaceable>ttlval</replaceable>;
min-ncache-ttl <replaceable>ttlval</replaceable>;
min-cache-ttl <replaceable>duration</replaceable>;
min-ncache-ttl <replaceable>duration</replaceable>;
min-refresh-time <replaceable>integer</replaceable>;
min-retry-time <replaceable>integer</replaceable>;
minimal-any <replaceable>boolean</replaceable>;
@ -689,8 +689,8 @@ view <replaceable>string</replaceable> [ <replaceable>class</replaceable> ] {
notify-source-v6 ( <replaceable>ipv6_address</replaceable> | * ) [ port ( <replaceable>integer</replaceable> | * ) ]
[ dscp <replaceable>integer</replaceable> ];
notify-to-soa <replaceable>boolean</replaceable>;
nta-lifetime <replaceable>ttlval</replaceable>;
nta-recheck <replaceable>ttlval</replaceable>;
nta-lifetime <replaceable>duration</replaceable>;
nta-recheck <replaceable>duration</replaceable>;
nxdomain-redirect <replaceable>string</replaceable>;
plugin ( query ) <replaceable>string</replaceable> [ {
<replaceable>unspecified-text</replaceable> } ];
@ -732,13 +732,13 @@ view <replaceable>string</replaceable> [ <replaceable>class</replaceable> ] {
response-padding { <replaceable>address_match_element</replaceable>; ... } block-size
<replaceable>integer</replaceable>;
response-policy { zone <replaceable>string</replaceable> [ add-soa <replaceable>boolean</replaceable> ] [ log
<replaceable>boolean</replaceable> ] [ max-policy-ttl <replaceable>ttlval</replaceable> ] [ min-update-interval
<replaceable>ttlval</replaceable> ] [ policy ( cname | disabled | drop | given | no-op |
<replaceable>boolean</replaceable> ] [ max-policy-ttl <replaceable>duration</replaceable> ] [ min-update-interval
<replaceable>duration</replaceable> ] [ policy ( cname | disabled | drop | given | no-op |
nodata | nxdomain | passthru | tcp-only <replaceable>quoted_string</replaceable> ) ] [
recursive-only <replaceable>boolean</replaceable> ] [ nsip-enable <replaceable>boolean</replaceable> ] [
nsdname-enable <replaceable>boolean</replaceable> ]; ... } [ add-soa <replaceable>boolean</replaceable> ] [
break-dnssec <replaceable>boolean</replaceable> ] [ max-policy-ttl <replaceable>ttlval</replaceable> ] [
min-update-interval <replaceable>ttlval</replaceable> ] [ min-ns-dots <replaceable>integer</replaceable> ] [
break-dnssec <replaceable>boolean</replaceable> ] [ max-policy-ttl <replaceable>duration</replaceable> ] [
min-update-interval <replaceable>duration</replaceable> ] [ min-ns-dots <replaceable>integer</replaceable> ] [
nsip-wait-recurse <replaceable>boolean</replaceable> ] [ qname-wait-recurse <replaceable>boolean</replaceable> ]
[ recursive-only <replaceable>boolean</replaceable> ] [ nsip-enable <replaceable>boolean</replaceable> ] [
nsdname-enable <replaceable>boolean</replaceable> ] [ dnsrps-enable <replaceable>boolean</replaceable> ] [
@ -783,14 +783,14 @@ view <replaceable>string</replaceable> [ <replaceable>class</replaceable> ] {
<replaceable>integer</replaceable> | * ) ] [ dscp <replaceable>integer</replaceable> ];
transfers <replaceable>integer</replaceable>;
};
servfail-ttl <replaceable>ttlval</replaceable>;
servfail-ttl <replaceable>duration</replaceable>;
sig-signing-nodes <replaceable>integer</replaceable>;
sig-signing-signatures <replaceable>integer</replaceable>;
sig-signing-type <replaceable>integer</replaceable>;
sig-validity-interval <replaceable>integer</replaceable> [ <replaceable>integer</replaceable> ];
sortlist { <replaceable>address_match_element</replaceable>; ... };
stale-answer-enable <replaceable>boolean</replaceable>;
stale-answer-ttl <replaceable>ttlval</replaceable>;
stale-answer-ttl <replaceable>duration</replaceable>;
synth-from-dnssec <replaceable>boolean</replaceable>;
transfer-format ( many-answers | one-answer );
transfer-source ( <replaceable>ipv4_address</replaceable> | * ) [ port ( <replaceable>integer</replaceable> | * ) ] [
@ -842,6 +842,7 @@ view <replaceable>string</replaceable> [ <replaceable>class</replaceable> ] {
dnskey-sig-validity <replaceable>integer</replaceable>;
dnssec-dnskey-kskonly <replaceable>boolean</replaceable>;
dnssec-loadkeys-interval <replaceable>integer</replaceable>;
dnssec-policy <replaceable>string</replaceable>;
dnssec-secure-to-insecure <replaceable>boolean</replaceable>;
dnssec-update-mode ( maintain | no-resign );
file <replaceable>quoted_string</replaceable>;
@ -867,7 +868,7 @@ view <replaceable>string</replaceable> [ <replaceable>class</replaceable> ] {
max-transfer-idle-out <replaceable>integer</replaceable>;
max-transfer-time-in <replaceable>integer</replaceable>;
max-transfer-time-out <replaceable>integer</replaceable>;
max-zone-ttl ( unlimited | <replaceable>ttlval</replaceable> );
max-zone-ttl ( unlimited | <replaceable>duration</replaceable> );
min-refresh-time <replaceable>integer</replaceable>;
min-retry-time <replaceable>integer</replaceable>;
multi-master <replaceable>boolean</replaceable>;
@ -943,6 +944,7 @@ zone <replaceable>string</replaceable> [ <replaceable>class</replaceable> ] {
dnskey-sig-validity <replaceable>integer</replaceable>;
dnssec-dnskey-kskonly <replaceable>boolean</replaceable>;
dnssec-loadkeys-interval <replaceable>integer</replaceable>;
dnssec-policy <replaceable>string</replaceable>;
dnssec-secure-to-insecure <replaceable>boolean</replaceable>;
dnssec-update-mode ( maintain | no-resign );
file <replaceable>quoted_string</replaceable>;
@ -967,7 +969,7 @@ zone <replaceable>string</replaceable> [ <replaceable>class</replaceable> ] {
max-transfer-idle-out <replaceable>integer</replaceable>;
max-transfer-time-in <replaceable>integer</replaceable>;
max-transfer-time-out <replaceable>integer</replaceable>;
max-zone-ttl ( unlimited | <replaceable>ttlval</replaceable> );
max-zone-ttl ( unlimited | <replaceable>duration</replaceable> );
min-refresh-time <replaceable>integer</replaceable>;
min-retry-time <replaceable>integer</replaceable>;
multi-master <replaceable>boolean</replaceable>;
@ -1008,6 +1010,26 @@ zone <replaceable>string</replaceable> [ <replaceable>class</replaceable> ] {
</literallayout>
</refsection>
<refsection><info><title>DNSSEC-POLICY</title></info>
<literallayout class="normal">
dnssec-policy <replaceable>string</replaceable> {
dnskey-ttl <replaceable>ttlval</replaceable>;
keys { ( csk | ksk | zsk ) key-directory lifetime <replaceable>duration</replaceable> algorithm <replaceable>integer</replaceable> [ <replaceable>integer</replaceable> ] ; ... };
parent-ds-ttl <replaceable>duration</replaceable>;
parent-propagation-delay <replaceable>duration</replaceable>;
parent-registration-delay <replaceable>duration</replaceable>;
publish-safety <replaceable>duration</replaceable>;
retire-safety <replaceable>duration</replaceable>;
signatures-refresh <replaceable>duration</replaceable>;
signatures-validity <replaceable>duration</replaceable>;
signatures-validity-dnskey <replaceable>duration</replaceable>;
zone-max-ttl <replaceable>duration</replaceable>;
zone-propagation-delay <replaceable>duration</replaceable>;
};
</literallayout>
</refsection>
<refsection><info><title>FILES</title></info>
<para><filename>/etc/named.conf</filename>

View file

@ -50,6 +50,7 @@
#include <isc/util.h>
#include <isccfg/grammar.h>
#include <isccfg/kaspconf.h>
#include <isccfg/namedconf.h>
#include <bind9/check.h>
@ -68,6 +69,7 @@
#include <dns/forward.h>
#include <dns/fixedname.h>
#include <dns/journal.h>
#include <dns/kasp.h>
#include <dns/keytable.h>
#include <dns/keyvalues.h>
#include <dns/lib.h>
@ -459,8 +461,8 @@ configure_alternates(const cfg_obj_t *config, dns_view_t *view,
static isc_result_t
configure_zone(const cfg_obj_t *config, const cfg_obj_t *zconfig,
const cfg_obj_t *vconfig, isc_mem_t *mctx, dns_view_t *view,
dns_viewlist_t *viewlist, cfg_aclconfctx_t *aclconf,
bool added, bool old_rpz_ok,
dns_viewlist_t *viewlist, dns_kasplist_t* kasplist,
cfg_aclconfctx_t *aclconf, bool added, bool old_rpz_ok,
bool modify);
static isc_result_t
@ -2039,7 +2041,13 @@ conf_dnsrps_num(const cfg_obj_t *obj, const char *name,
return;
}
conf_dnsrps_sadd(ctx, " %s %d", name, cfg_obj_asuint32(sub_obj));
if (cfg_obj_isduration(sub_obj)) {
conf_dnsrps_sadd(ctx, " %s %d", name,
cfg_obj_asduration(sub_obj));
} else {
conf_dnsrps_sadd(ctx, " %s %d", name,
cfg_obj_asuint32(sub_obj));
}
}
/*
@ -2221,15 +2229,15 @@ configure_rpz_zone(dns_view_t *view, const cfg_listelt_t *element,
}
obj = cfg_tuple_get(rpz_obj, "max-policy-ttl");
if (cfg_obj_isuint32(obj)) {
zone->max_policy_ttl = cfg_obj_asuint32(obj);
if (cfg_obj_isduration(obj)) {
zone->max_policy_ttl = cfg_obj_asduration(obj);
} else {
zone->max_policy_ttl = ttl_default;
}
obj = cfg_tuple_get(rpz_obj, "min-update-interval");
if (cfg_obj_isuint32(obj)) {
zone->min_update_interval = cfg_obj_asuint32(obj);
if (cfg_obj_isduration(obj)) {
zone->min_update_interval = cfg_obj_asduration(obj);
} else {
zone->min_update_interval = minupdateinterval_default;
}
@ -2448,14 +2456,14 @@ configure_rpz(dns_view_t *view, const cfg_obj_t **maps,
}
sub_obj = cfg_tuple_get(rpz_obj, "max-policy-ttl");
if (cfg_obj_isuint32(sub_obj))
ttl_default = cfg_obj_asuint32(sub_obj);
if (cfg_obj_isduration(sub_obj))
ttl_default = cfg_obj_asduration(sub_obj);
else
ttl_default = DNS_RPZ_MAX_TTL_DEFAULT;
sub_obj = cfg_tuple_get(rpz_obj, "min-update-interval");
if (cfg_obj_isuint32(sub_obj))
minupdateinterval_default = cfg_obj_asuint32(sub_obj);
if (cfg_obj_isduration(sub_obj))
minupdateinterval_default = cfg_obj_asduration(sub_obj);
else
minupdateinterval_default = DNS_RPZ_MINUPDATEINTERVAL_DEFAULT;
@ -2679,7 +2687,8 @@ catz_addmodzone_taskaction(isc_task_t *task, isc_event_t *event0) {
dns_view_thaw(ev->view);
result = configure_zone(cfg->config, zoneobj, cfg->vconfig,
ev->cbd->server->mctx, ev->view,
&ev->cbd->server->viewlist, cfg->actx,
&ev->cbd->server->viewlist,
&ev->cbd->server->kasplist, cfg->actx,
true, false, ev->mod);
dns_view_freeze(ev->view);
isc_task_endexclusive(task);
@ -2992,8 +3001,8 @@ configure_catz_zone(dns_view_t *view, const cfg_obj_t *config,
}
obj = cfg_tuple_get(catz_obj, "min-update-interval");
if (obj != NULL && cfg_obj_isuint32(obj))
opts->min_update_interval = cfg_obj_asuint32(obj);
if (obj != NULL && cfg_obj_isduration(obj))
opts->min_update_interval = cfg_obj_asduration(obj);
cleanup:
if (pview != NULL)
@ -3641,7 +3650,7 @@ configure_dnstap(const cfg_obj_t **maps, dns_view_t *view) {
result = named_config_get(maps, "fstrm-set-reopen-interval",
&obj);
if (result == ISC_R_SUCCESS) {
i = cfg_obj_asuint32(obj);
i = cfg_obj_asduration(obj);
fstrm_iothr_options_set_reopen_interval(fopt, i);
}
@ -3764,11 +3773,10 @@ register_one_plugin(const cfg_obj_t *config, const cfg_obj_t *obj,
* global defaults in 'config' used exclusively.
*/
static isc_result_t
configure_view(dns_view_t *view, dns_viewlist_t *viewlist,
cfg_obj_t *config, cfg_obj_t *vconfig,
named_cachelist_t *cachelist, const cfg_obj_t *bindkeys,
isc_mem_t *mctx, cfg_aclconfctx_t *actx,
bool need_hints)
configure_view(dns_view_t *view, dns_viewlist_t *viewlist, cfg_obj_t *config,
cfg_obj_t *vconfig, named_cachelist_t *cachelist,
dns_kasplist_t *kasplist, const cfg_obj_t *bindkeys,
isc_mem_t *mctx, cfg_aclconfctx_t *actx, bool need_hints)
{
const cfg_obj_t *maps[4];
const cfg_obj_t *cfgmaps[3];
@ -3895,8 +3903,8 @@ configure_view(dns_view_t *view, dns_viewlist_t *viewlist,
{
const cfg_obj_t *zconfig = cfg_listelt_value(element);
CHECK(configure_zone(config, zconfig, vconfig, mctx, view,
viewlist, actx, false, old_rpz_ok,
false));
viewlist, kasplist, actx, false,
old_rpz_ok, false));
}
/*
@ -4217,22 +4225,22 @@ configure_view(dns_view_t *view, dns_viewlist_t *viewlist,
obj = NULL;
result = named_config_get(maps, "max-cache-ttl", &obj);
INSIST(result == ISC_R_SUCCESS);
view->maxcachettl = cfg_obj_asuint32(obj);
view->maxcachettl = cfg_obj_asduration(obj);
obj = NULL;
result = named_config_get(maps, "max-ncache-ttl", &obj);
INSIST(result == ISC_R_SUCCESS);
view->maxncachettl = cfg_obj_asuint32(obj);
view->maxncachettl = cfg_obj_asduration(obj);
obj = NULL;
result = named_config_get(maps, "min-cache-ttl", &obj);
INSIST(result == ISC_R_SUCCESS);
view->mincachettl = cfg_obj_asuint32(obj);
view->mincachettl = cfg_obj_asduration(obj);
obj = NULL;
result = named_config_get(maps, "min-ncache-ttl", &obj);
INSIST(result == ISC_R_SUCCESS);
view->minncachettl = cfg_obj_asuint32(obj);
view->minncachettl = cfg_obj_asduration(obj);
obj = NULL;
result = named_config_get(maps, "synth-from-dnssec", &obj);
@ -4242,7 +4250,7 @@ configure_view(dns_view_t *view, dns_viewlist_t *viewlist,
obj = NULL;
result = named_config_get(maps, "max-stale-ttl", &obj);
INSIST(result == ISC_R_SUCCESS);
max_stale_ttl = ISC_MAX(cfg_obj_asuint32(obj), 1);
max_stale_ttl = ISC_MAX(cfg_obj_asduration(obj), 1);
obj = NULL;
result = named_config_get(maps, "stale-answer-enable", &obj);
@ -4392,7 +4400,7 @@ configure_view(dns_view_t *view, dns_viewlist_t *viewlist,
obj = NULL;
result = named_config_get(maps, "stale-answer-ttl", &obj);
INSIST(result == ISC_R_SUCCESS);
view->staleanswerttl = ISC_MAX(cfg_obj_asuint32(obj), 1);
view->staleanswerttl = ISC_MAX(cfg_obj_asduration(obj), 1);
/*
* Resolver.
@ -4512,7 +4520,7 @@ configure_view(dns_view_t *view, dns_viewlist_t *viewlist,
obj = NULL;
result = named_config_get(maps, "lame-ttl", &obj);
INSIST(result == ISC_R_SUCCESS);
lame_ttl = cfg_obj_asuint32(obj);
lame_ttl = cfg_obj_asduration(obj);
if (lame_ttl > 1800)
lame_ttl = 1800;
dns_resolver_setlamettl(view->resolver, lame_ttl);
@ -5216,12 +5224,12 @@ configure_view(dns_view_t *view, dns_viewlist_t *viewlist,
obj = NULL;
result = named_config_get(maps, "nta-recheck", &obj);
INSIST(result == ISC_R_SUCCESS);
view->nta_recheck = cfg_obj_asuint32(obj);
view->nta_recheck = cfg_obj_asduration(obj);
obj = NULL;
result = named_config_get(maps, "nta-lifetime", &obj);
INSIST(result == ISC_R_SUCCESS);
view->nta_lifetime = cfg_obj_asuint32(obj);
view->nta_lifetime = cfg_obj_asduration(obj);
obj = NULL;
result = named_config_get(maps, "preferred-glue", &obj);
@ -5464,7 +5472,7 @@ configure_view(dns_view_t *view, dns_viewlist_t *viewlist,
obj = NULL;
result = named_config_get(maps, "servfail-ttl", &obj);
INSIST(result == ISC_R_SUCCESS);
fail_ttl = cfg_obj_asuint32(obj);
fail_ttl = cfg_obj_asduration(obj);
if (fail_ttl > 30)
fail_ttl = 30;
dns_view_setfailttl(view, fail_ttl);
@ -5893,8 +5901,8 @@ create_view(const cfg_obj_t *vconfig, dns_viewlist_t *viewlist,
static isc_result_t
configure_zone(const cfg_obj_t *config, const cfg_obj_t *zconfig,
const cfg_obj_t *vconfig, isc_mem_t *mctx, dns_view_t *view,
dns_viewlist_t *viewlist, cfg_aclconfctx_t *aclconf,
bool added, bool old_rpz_ok,
dns_viewlist_t *viewlist, dns_kasplist_t *kasplist,
cfg_aclconfctx_t *aclconf, bool added, bool old_rpz_ok,
bool modify)
{
dns_view_t *pview = NULL; /* Production view */
@ -6111,8 +6119,8 @@ configure_zone(const cfg_obj_t *config, const cfg_obj_t *zconfig,
zone));
dns_zone_setstats(zone, named_g_server->zonestats);
}
CHECK(named_zone_configure(config, vconfig, zconfig,
aclconf, zone, NULL));
CHECK(named_zone_configure(config, vconfig, zconfig, aclconf,
kasplist, zone, NULL));
dns_zone_attach(zone, &view->redirect);
goto cleanup;
}
@ -6249,8 +6257,11 @@ configure_zone(const cfg_obj_t *config, const cfg_obj_t *zconfig,
strcasecmp(ztypestr, "master") == 0 ||
strcasecmp(ztypestr, "secondary") == 0 ||
strcasecmp(ztypestr, "slave") == 0) &&
cfg_map_get(zoptions, "inline-signing", &signing) == ISC_R_SUCCESS &&
cfg_obj_asboolean(signing))
((cfg_map_get(zoptions, "inline-signing", &signing) ==
ISC_R_SUCCESS && cfg_obj_asboolean(signing)) ||
(cfg_map_get(zoptions, "dnssec-policy", &signing) ==
ISC_R_SUCCESS && signing != NULL &&
strcmp(cfg_obj_asstring(signing), "none") != 0)))
{
dns_zone_getraw(zone, &raw);
if (raw == NULL) {
@ -6274,8 +6285,8 @@ configure_zone(const cfg_obj_t *config, const cfg_obj_t *zconfig,
/*
* Configure the zone.
*/
CHECK(named_zone_configure(config, vconfig, zconfig,
aclconf, zone, raw));
CHECK(named_zone_configure(config, vconfig, zconfig, aclconf, kasplist,
zone, raw));
/*
* Add the zone to its view in the new view list.
@ -7567,9 +7578,10 @@ configure_newzones(dns_view_t *view, cfg_obj_t *config, cfg_obj_t *vconfig,
element = cfg_list_next(element))
{
const cfg_obj_t *zconfig = cfg_listelt_value(element);
CHECK(configure_zone(config, zconfig, vconfig, mctx,
view, &named_g_server->viewlist, actx,
true, false, false));
CHECK(configure_zone(config, zconfig, vconfig, mctx, view,
&named_g_server->viewlist,
&named_g_server->kasplist, actx, true,
false, false));
}
result = ISC_R_SUCCESS;
@ -7753,8 +7765,9 @@ configure_newzone(const cfg_obj_t *zconfig, cfg_obj_t *config,
cfg_aclconfctx_t *actx)
{
return (configure_zone(config, zconfig, vconfig, mctx, view,
&named_g_server->viewlist, actx, true,
false, false));
&named_g_server->viewlist,
&named_g_server->kasplist, actx, true, false,
false));
}
/*%
@ -7989,9 +8002,13 @@ load_configuration(const char *filename, named_server_t *server,
const cfg_obj_t *obj;
const cfg_obj_t *options;
const cfg_obj_t *usev4ports, *avoidv4ports, *usev6ports, *avoidv6ports;
const cfg_obj_t *kasps;
dns_kasp_t *kasp = NULL;
dns_kasp_t *kasp_next = NULL;
dns_kasplist_t tmpkasplist, kasplist;
const cfg_obj_t *views;
dns_view_t *view = NULL;
dns_view_t *view_next;
dns_view_t *view_next = NULL;
dns_viewlist_t tmpviewlist;
dns_viewlist_t viewlist, builtin_viewlist;
in_port_t listen_port, udpport_low, udpport_high;
@ -8020,6 +8037,7 @@ load_configuration(const char *filename, named_server_t *server,
dns_aclenv_t *env =
ns_interfacemgr_getaclenv(named_g_server->interfacemgr);
ISC_LIST_INIT(kasplist);
ISC_LIST_INIT(viewlist);
ISC_LIST_INIT(builtin_viewlist);
ISC_LIST_INIT(cachelist);
@ -8560,7 +8578,7 @@ load_configuration(const char *filename, named_server_t *server,
obj = NULL;
result = named_config_get(maps, "interface-interval", &obj);
INSIST(result == ISC_R_SUCCESS);
interface_interval = cfg_obj_asuint32(obj) * 60;
interface_interval = cfg_obj_asduration(obj);
if (interface_interval == 0) {
CHECK(isc_timer_reset(server->interface_timer,
isc_timertype_inactive,
@ -8634,6 +8652,39 @@ load_configuration(const char *filename, named_server_t *server,
*/
(void)configure_session_key(maps, server, named_g_mctx);
/*
* Create the DNSSEC key and signing policies (KASP).
*/
kasps = NULL;
(void)cfg_map_get(config, "dnssec-policy", &kasps);
for (element = cfg_list_first(kasps);
element != NULL;
element = cfg_list_next(element))
{
cfg_obj_t *kconfig = cfg_listelt_value(element);
kasp = NULL;
CHECK(cfg_kasp_fromconfig(kconfig, named_g_mctx, &kasplist,
&kasp));
INSIST(kasp != NULL);
dns_kasp_freeze(kasp);
dns_kasp_detach(&kasp);
}
/*
* Create the default kasp.
*/
kasp = NULL;
CHECK(cfg_kasp_fromconfig(NULL, named_g_mctx, &kasplist, &kasp));
INSIST(kasp != NULL);
dns_kasp_freeze(kasp);
dns_kasp_detach(&kasp);
tmpkasplist = server->kasplist;
server->kasplist = kasplist;
kasplist = tmpkasplist;
/*
* Configure the views.
*/
views = NULL;
(void)cfg_map_get(config, "view", &views);
@ -8712,8 +8763,8 @@ load_configuration(const char *filename, named_server_t *server,
view = NULL;
CHECK(find_view(vconfig, &viewlist, &view));
CHECK(configure_view(view, &viewlist, config, vconfig,
&cachelist, bindkeys, named_g_mctx,
named_g_aclconfctx, true));
&cachelist, &server->kasplist, bindkeys,
named_g_mctx, named_g_aclconfctx, true));
dns_view_freeze(view);
dns_view_detach(&view);
}
@ -8726,9 +8777,8 @@ load_configuration(const char *filename, named_server_t *server,
view = NULL;
CHECK(find_view(NULL, &viewlist, &view));
CHECK(configure_view(view, &viewlist, config, NULL,
&cachelist, bindkeys,
named_g_mctx, named_g_aclconfctx,
true));
&cachelist, &server->kasplist, bindkeys,
named_g_mctx, named_g_aclconfctx, true));
dns_view_freeze(view);
dns_view_detach(&view);
}
@ -8747,9 +8797,8 @@ load_configuration(const char *filename, named_server_t *server,
CHECK(create_view(vconfig, &builtin_viewlist, &view));
CHECK(configure_view(view, &viewlist, config, vconfig,
&cachelist, bindkeys,
named_g_mctx, named_g_aclconfctx,
false));
&cachelist, &server->kasplist, bindkeys,
named_g_mctx, named_g_aclconfctx, false));
dns_view_freeze(view);
dns_view_detach(&view);
view = NULL;
@ -9185,6 +9234,10 @@ load_configuration(const char *filename, named_server_t *server,
dns_view_detach(&view);
}
if (kasp != NULL) {
dns_kasp_detach(&kasp);
}
ISC_LIST_APPENDLIST(viewlist, builtin_viewlist, link);
/*
@ -9207,6 +9260,15 @@ load_configuration(const char *filename, named_server_t *server,
dns_view_detach(&view);
}
/*
* Same cleanup for kasp list.
*/
for (kasp = ISC_LIST_HEAD(kasplist); kasp != NULL; kasp = kasp_next) {
kasp_next = ISC_LIST_NEXT(kasp, link);
ISC_LIST_UNLINK(kasplist, kasp, link);
dns_kasp_detach(&kasp);
}
/* Same cleanup for cache list. */
while ((nsc = ISC_LIST_HEAD(cachelist)) != NULL) {
ISC_LIST_UNLINK(cachelist, nsc, link);
@ -9454,7 +9516,8 @@ named_server_flushonshutdown(named_server_t *server, bool flush) {
static void
shutdown_server(isc_task_t *task, isc_event_t *event) {
isc_result_t result;
dns_view_t *view, *view_next;
dns_view_t *view, *view_next = NULL;
dns_kasp_t *kasp, *kasp_next = NULL;
named_server_t *server = (named_server_t *)event->ev_arg;
bool flush = server->flushonshutdown;
named_cache_t *nsc;
@ -9484,9 +9547,17 @@ shutdown_server(isc_task_t *task, isc_event_t *event) {
(void) named_server_saventa(server);
for (view = ISC_LIST_HEAD(server->viewlist);
view != NULL;
view = view_next) {
for (kasp = ISC_LIST_HEAD(server->kasplist); kasp != NULL;
kasp = kasp_next)
{
kasp_next = ISC_LIST_NEXT(kasp, link);
ISC_LIST_UNLINK(server->kasplist, kasp, link);
dns_kasp_detach(&kasp);
}
for (view = ISC_LIST_HEAD(server->viewlist); view != NULL;
view = view_next)
{
view_next = ISC_LIST_NEXT(view, link);
ISC_LIST_UNLINK(server->viewlist, view, link);
if (flush)
@ -9604,6 +9675,7 @@ named_server_create(isc_mem_t *mctx, named_server_t **serverp) {
/* Initialize server data structures. */
server->interfacemgr = NULL;
ISC_LIST_INIT(server->kasplist);
ISC_LIST_INIT(server->viewlist);
server->in_roothints = NULL;
@ -9791,6 +9863,7 @@ named_server_destroy(named_server_t **serverp) {
isc_event_free(&server->reload_event);
INSIST(ISC_LIST_EMPTY(server->kasplist));
INSIST(ISC_LIST_EMPTY(server->viewlist));
INSIST(ISC_LIST_EMPTY(server->cachelist));
@ -11760,7 +11833,10 @@ named_server_rekey(named_server_t *server, isc_lex_t *lex,
keyopts = dns_zone_getkeyopts(zone);
/* "rndc loadkeys" requires "auto-dnssec maintain". */
/*
* "rndc loadkeys" requires "auto-dnssec maintain"
* or a "dnssec-policy".
*/
if ((keyopts & DNS_ZONEKEY_ALLOW) == 0)
result = ISC_R_NOPERM;
else if ((keyopts & DNS_ZONEKEY_MAINTAIN) == 0 && !fullsign)
@ -12925,7 +13001,8 @@ do_addzone(named_server_t *server, ns_cfgctx_t *cfg, dns_view_t *view,
dns_view_thaw(view);
result = configure_zone(cfg->config, zoneobj, cfg->vconfig,
server->mctx, view, &server->viewlist,
cfg->actx, true, false, false);
&server->kasplist, cfg->actx, true, false,
false);
dns_view_freeze(view);
isc_task_endexclusive(server->task);
@ -13103,7 +13180,8 @@ do_modzone(named_server_t *server, ns_cfgctx_t *cfg, dns_view_t *view,
dns_view_thaw(view);
result = configure_zone(cfg->config, zoneobj, cfg->vconfig,
server->mctx, view, &server->viewlist,
cfg->actx, true, false, true);
&server->kasplist, cfg->actx, true, false,
true);
dns_view_freeze(view);
exclusive = false;

View file

@ -25,6 +25,7 @@
#include <dns/ipkeylist.h>
#include <dns/fixedname.h>
#include <dns/journal.h>
#include <dns/kasp.h>
#include <dns/log.h>
#include <dns/name.h>
#include <dns/masterdump.h>
@ -840,8 +841,9 @@ process_notifytype(dns_notifytype_t ntype, dns_zonetype_t ztype,
isc_result_t
named_zone_configure(const cfg_obj_t *config, const cfg_obj_t *vconfig,
const cfg_obj_t *zconfig, cfg_aclconfctx_t *ac,
dns_zone_t *zone, dns_zone_t *raw)
const cfg_obj_t *zconfig, cfg_aclconfctx_t *ac,
dns_kasplist_t *kasplist, dns_zone_t *zone,
dns_zone_t *raw)
{
isc_result_t result;
const char *zname;
@ -853,6 +855,7 @@ named_zone_configure(const cfg_obj_t *config, const cfg_obj_t *vconfig,
const cfg_obj_t *options = NULL;
const cfg_obj_t *obj;
const char *filename = NULL;
const char *kaspname = NULL;
const char *dupcheck;
dns_notifytype_t notifytype = dns_notifytype_yes;
uint32_t count;
@ -868,7 +871,8 @@ named_zone_configure(const cfg_obj_t *config, const cfg_obj_t *vconfig,
int32_t journal_size;
bool multi;
bool alt;
dns_view_t *view;
dns_view_t *view = NULL;
dns_kasp_t *kasp = NULL;
bool check = false, fail = false;
bool warn = false, ignore = false;
bool ixfrdiff;
@ -1045,8 +1049,8 @@ named_zone_configure(const cfg_obj_t *config, const cfg_obj_t *vconfig,
} else if (result == ISC_R_SUCCESS) {
dns_ttl_t maxttl = 0; /* unlimited */
if (cfg_obj_isuint32(obj))
maxttl = cfg_obj_asuint32(obj);
if (cfg_obj_isduration(obj))
maxttl = cfg_obj_asduration(obj);
dns_zone_setmaxttl(zone, maxttl);
if (raw != NULL)
dns_zone_setmaxttl(raw, maxttl);
@ -1192,6 +1196,24 @@ named_zone_configure(const cfg_obj_t *config, const cfg_obj_t *vconfig,
*/
if (ztype != dns_zone_stub && ztype != dns_zone_staticstub &&
ztype != dns_zone_redirect) {
obj = NULL;
result = named_config_get(maps, "dnssec-policy", &obj);
if (result == ISC_R_SUCCESS) {
kaspname = cfg_obj_asstring(obj);
if (strcmp(kaspname, "none") != 0) {
result = dns_kasplist_find(kasplist, kaspname,
&kasp);
if (result != ISC_R_SUCCESS) {
cfg_obj_log(obj, named_g_lctx,
ISC_LOG_ERROR,
"'dnssec-policy '%s' not "
"found ", kaspname);
RETERR(result);
}
dns_zone_setkasp(zone, kasp);
}
}
obj = NULL;
result = named_config_get(maps, "notify", &obj);
INSIST(result == ISC_R_SUCCESS && obj != NULL);
@ -1481,38 +1503,52 @@ named_zone_configure(const cfg_obj_t *config, const cfg_obj_t *vconfig,
bool allow = false, maint = false;
bool sigvalinsecs;
obj = NULL;
result = named_config_get(maps, "dnskey-sig-validity", &obj);
INSIST(result == ISC_R_SUCCESS && obj != NULL);
seconds = cfg_obj_asuint32(obj) * 86400;
if (kasp) {
seconds = (uint32_t) dns_kasp_sigvalidity_dnskey(kasp);
} else {
obj = NULL;
result = named_config_get(maps, "dnskey-sig-validity",
&obj);
INSIST(result == ISC_R_SUCCESS && obj != NULL);
seconds = cfg_obj_asuint32(obj) * 86400;
}
dns_zone_setkeyvalidityinterval(zone, seconds);
obj = NULL;
result = named_config_get(maps, "sig-validity-interval", &obj);
INSIST(result == ISC_R_SUCCESS && obj != NULL);
sigvalinsecs = ns_server_getoption(named_g_server->sctx,
NS_SERVER_SIGVALINSECS);
validity = cfg_tuple_get(obj, "validity");
seconds = cfg_obj_asuint32(validity);
if (!sigvalinsecs) {
seconds *= 86400;
}
dns_zone_setsigvalidityinterval(zone, seconds);
resign = cfg_tuple_get(obj, "re-sign");
if (cfg_obj_isvoid(resign)) {
seconds /= 4;
} else if (!sigvalinsecs) {
if (seconds > 7 * 86400) {
seconds = cfg_obj_asuint32(resign) * 86400;
} else {
seconds = cfg_obj_asuint32(resign) * 3600;
}
if (kasp) {
seconds = (uint32_t) dns_kasp_sigvalidity(kasp);
dns_zone_setsigvalidityinterval(zone, seconds);
seconds = (uint32_t) dns_kasp_sigrefresh(kasp);
dns_zone_setsigresigninginterval(zone, seconds);
} else {
seconds = cfg_obj_asuint32(resign);
obj = NULL;
result = named_config_get(maps, "sig-validity-interval",
&obj);
INSIST(result == ISC_R_SUCCESS && obj != NULL);
sigvalinsecs = ns_server_getoption(named_g_server->sctx,
NS_SERVER_SIGVALINSECS);
validity = cfg_tuple_get(obj, "validity");
seconds = cfg_obj_asuint32(validity);
if (!sigvalinsecs) {
seconds *= 86400;
}
dns_zone_setsigvalidityinterval(zone, seconds);
resign = cfg_tuple_get(obj, "re-sign");
if (cfg_obj_isvoid(resign)) {
seconds /= 4;
} else if (!sigvalinsecs) {
seconds = cfg_obj_asuint32(resign);
if (seconds > 7 * 86400) {
seconds *= 86400;
} else {
seconds *= 3600;
}
} else {
seconds = cfg_obj_asuint32(resign);
}
dns_zone_setsigresigninginterval(zone, seconds);
}
dns_zone_setsigresigninginterval(zone, seconds);
obj = NULL;
result = named_config_get(maps, "key-directory", &obj);
@ -1541,12 +1577,20 @@ named_zone_configure(const cfg_obj_t *config, const cfg_obj_t *vconfig,
INSIST(result == ISC_R_SUCCESS && obj != NULL);
dns_zone_setoption(zone, DNS_ZONEOPT_UPDATECHECKKSK,
cfg_obj_asboolean(obj));
/*
* This setting will be ignored if dnssec-policy is used.
* named-checkconf will error if both are configured.
*/
obj = NULL;
result = named_config_get(maps, "dnssec-dnskey-kskonly", &obj);
INSIST(result == ISC_R_SUCCESS && obj != NULL);
dns_zone_setoption(zone, DNS_ZONEOPT_DNSKEYKSKONLY,
cfg_obj_asboolean(obj));
/*
* This setting will be ignored if dnssec-policy is used.
* named-checkconf will error if both are configured.
*/
obj = NULL;
result = named_config_get(maps, "dnssec-loadkeys-interval",
@ -1557,7 +1601,11 @@ named_zone_configure(const cfg_obj_t *config, const cfg_obj_t *vconfig,
obj = NULL;
result = cfg_map_get(zoptions, "auto-dnssec", &obj);
if (result == ISC_R_SUCCESS) {
if (dns_zone_getkasp(zone) != NULL) {
dns_zone_setkeyopt(zone, DNS_ZONEKEY_ALLOW, true);
dns_zone_setkeyopt(zone, DNS_ZONEKEY_CREATE, true);
dns_zone_setkeyopt(zone, DNS_ZONEKEY_MAINTAIN, true);
} else if (result == ISC_R_SUCCESS) {
const char *arg = cfg_obj_asstring(obj);
if (strcasecmp(arg, "allow") == 0) {
allow = true;
@ -1570,6 +1618,7 @@ named_zone_configure(const cfg_obj_t *config, const cfg_obj_t *vconfig,
ISC_UNREACHABLE();
}
dns_zone_setkeyopt(zone, DNS_ZONEKEY_ALLOW, allow);
dns_zone_setkeyopt(zone, DNS_ZONEKEY_CREATE, false);
dns_zone_setkeyopt(zone, DNS_ZONEKEY_MAINTAIN, maint);
}
}

View file

@ -443,7 +443,8 @@
allowed to incrementally re-sign over time.
</para>
<para>
This command requires that the
This command requires that the zone is configured with a
<command>dnssec-policy</command>, or that the
<command>auto-dnssec</command> zone option
be set to <literal>maintain</literal>,
and also requires the zone to be configured to
@ -849,7 +850,8 @@
re-signed with the new key set.
</para>
<para>
This command requires that the
This command requires that the zone is configured with a
<command>dnssec-policy</command>, or that the
<command>auto-dnssec</command> zone option be set
to <literal>allow</literal> or
<literal>maintain</literal>,

View file

@ -0,0 +1,22 @@
/*
* Copyright (C) Internet Systems Consortium, Inc. ("ISC")
*
* 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 http://mozilla.org/MPL/2.0/.
*
* See the COPYRIGHT file distributed with this work for additional
* information regarding copyright ownership.
*/
// Using the keyword 'default' is not allowed.
dnssec-policy "default" {
signatures-refresh P5D;
};
zone "example.net" {
type master;
file "example.db";
dnssec-policy "default";
};

View file

@ -0,0 +1,22 @@
/*
* Copyright (C) Internet Systems Consortium, Inc. ("ISC")
*
* 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 http://mozilla.org/MPL/2.0/.
*
* See the COPYRIGHT file distributed with this work for additional
* information regarding copyright ownership.
*/
include "good-kasp.conf";
// Bad zone configuration because this has dnssec-policy and other DNSSEC sign
// configuration options (auto-dnssec).
zone "example.net" {
type master;
file "example.db";
dnssec-policy "test";
auto-dnssec maintain;
allow-update { any; };
};

View file

@ -0,0 +1,22 @@
/*
* Copyright (C) Internet Systems Consortium, Inc. ("ISC")
*
* 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 http://mozilla.org/MPL/2.0/.
*
* See the COPYRIGHT file distributed with this work for additional
* information regarding copyright ownership.
*/
include "good-kasp.conf";
// Bad zone configuration because this has dnssec-policy with no matching
// dnssec-policy configuration (good-kasp.conf has "test", zone refers to
// "nosuchpolicy".
zone "example.net" {
type master;
file "example.db";
dnssec-policy "nosuchpolicy";
};

View file

@ -0,0 +1,23 @@
/*
* Copyright (C) Internet Systems Consortium, Inc. ("ISC")
*
* 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 http://mozilla.org/MPL/2.0/.
*
* See the COPYRIGHT file distributed with this work for additional
* information regarding copyright ownership.
*/
// Bad kasp configuration because this has an invalid duration for
// signatures-refresh.
dnssec-policy "badduration" {
signatures-refresh PT20Sabcd;
};
zone "example.net" {
type master;
file "example.db";
dnssec-policy "badduration";
};

View file

@ -0,0 +1,22 @@
/*
* Copyright (C) Internet Systems Consortium, Inc. ("ISC")
*
* 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 http://mozilla.org/MPL/2.0/.
*
* See the COPYRIGHT file distributed with this work for additional
* information regarding copyright ownership.
*/
// Using the keyword 'none' is not allowed.
dnssec-policy "none" {
signatures-refresh P5D;
};
zone "example.net" {
type master;
file "example.db";
dnssec-policy "none";
};

View file

@ -10,6 +10,7 @@
# information regarding copyright ownership.
rm -f good.conf.in good.conf.out badzero.conf *.out
rm -f good-kasp.conf.in
rm -rf test.keydir
rm -f checkconf.out*
rm -f diff.out*

View file

@ -0,0 +1,56 @@
/*
* Copyright (C) Internet Systems Consortium, Inc. ("ISC")
*
* 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 http://mozilla.org/MPL/2.0/.
*
* See the COPYRIGHT file distributed with this work for additional
* information regarding copyright ownership.
*/
/*
* This is just a random selection of DNSSEC configuration options.
*/
/* cut here */
dnssec-policy "test" {
dnskey-ttl 3600;
keys {
ksk key-directory lifetime P1Y algorithm 13 256;
zsk key-directory lifetime P30D algorithm 13;
csk key-directory lifetime P30D algorithm 8 2048;
};
publish-safety PT3600S;
retire-safety PT3600S;
signatures-refresh P3D;
signatures-validity P2W;
signatures-validity-dnskey P14D;
zone-max-ttl 86400;
zone-propagation-delay PT5M;
parent-ds-ttl 7200;
parent-propagation-delay PT1H;
parent-registration-delay P1D;
};
options {
dnssec-policy "default";
};
zone "example1" {
type master;
file "example1.db";
};
zone "example2" {
type master;
file "example2.db";
dnssec-policy "test";
};
zone "example3" {
type master;
file "example3.db";
dnssec-policy "default";
};
zone "example4" {
type master;
file "example4.db";
dnssec-policy "none";
};

View file

@ -14,6 +14,24 @@
*/
/* cut here */
dnssec-policy "test" {
dnskey-ttl 3600;
keys {
ksk key-directory lifetime P1Y algorithm 13 256;
zsk key-directory lifetime P30D algorithm 13;
csk key-directory lifetime P30D algorithm 8 2048;
};
publish-safety PT3600S;
retire-safety PT3600S;
signatures-refresh P3D;
signatures-validity P2W;
signatures-validity-dnskey P14D;
zone-max-ttl 86400;
zone-propagation-delay PT5M;
parent-ds-ttl 7200;
parent-propagation-delay PT1H;
parent-registration-delay P1D;
};
options {
avoid-v4-udp-ports {
100;
@ -60,6 +78,7 @@ options {
validate-except {
"corp";
};
dnssec-policy "test";
transfer-source 0.0.0.0 dscp 63;
zone-statistics none;
};
@ -140,6 +159,28 @@ view "third" {
};
};
};
view "fourth" {
zone "dnssec-test" {
type master;
file "dnssec-test.db";
dnssec-policy "test";
};
zone "dnssec-default" {
type master;
file "dnssec-default.db";
dnssec-policy "default";
};
zone "dnssec-inherit" {
type master;
file "dnssec-inherit.db";
};
zone "dnssec-none" {
type master;
file "dnssec-none.db";
dnssec-policy "none";
};
dnssec-policy "default";
};
view "chaos" chaos {
zone "hostname.bind" chaos {
type master;

View file

@ -8,4 +8,8 @@ clone IN third in-view first
dnssec IN third master
p IN third primary
s IN third secondary
dnssec-test IN fourth master
dnssec-default IN fourth master
dnssec-inherit IN fourth master
dnssec-none IN fourth master
hostname.bind chaos chaos master

View file

@ -0,0 +1,28 @@
/*
* Copyright (C) Internet Systems Consortium, Inc. ("ISC")
*
* 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 http://mozilla.org/MPL/2.0/.
*
* See the COPYRIGHT file distributed with this work for additional
* information regarding copyright ownership.
*/
include "good-kasp.conf";
zone "nsec3.net" {
type master;
file "nsec3.db";
dnssec-policy "test";
auto-dnssec maintain;
dnskey-sig-validity 3600;
dnssec-dnskey-kskonly yes;
dnssec-secure-to-insecure yes;
dnssec-update-mode maintain;
inline-signing yes;
sig-validity-interval 3600;
update-check-ksk yes;
allow-update { any; };
};

View file

@ -466,5 +466,38 @@ grep "'geoip-use-ecs' is obsolete" < checkconf.out$n > /dev/null || ret=1
if [ $ret != 0 ]; then echo_i "failed"; ret=1; fi
status=`expr $status + $ret`
n=`expr $n + 1`
echo_i "checking named-checkconf kasp warnings ($n)"
ret=0
$CHECKCONF kasp-and-other-dnssec-options.conf > checkconf.out$n 2>&1
grep "'auto-dnssec maintain;' cannot be configured if dnssec-policy is also set" < checkconf.out$n > /dev/null || ret=1
grep "dnskey-sig-validity: cannot be configured if dnssec-policy is also set" < checkconf.out$n > /dev/null || ret=1
grep "dnssec-dnskey-kskonly: cannot be configured if dnssec-policy is also set" < checkconf.out$n > /dev/null || ret=1
grep "dnssec-secure-to-insecure: cannot be configured if dnssec-policy is also set" < checkconf.out$n > /dev/null || ret=1
grep "dnssec-update-mode: cannot be configured if dnssec-policy is also set" < checkconf.out$n > /dev/null || ret=1
grep "inline-signing: cannot be configured if dnssec-policy is also set" < checkconf.out$n > /dev/null || ret=1
grep "sig-validity-interval: cannot be configured if dnssec-policy is also set" < checkconf.out$n > /dev/null || ret=1
grep "update-check-ksk: cannot be configured if dnssec-policy is also set" < checkconf.out$n > /dev/null || ret=1
if [ $ret != 0 ]; then echo_i "failed"; fi
status=`expr $status + $ret`
n=`expr $n + 1`
echo_i "check that a good 'kasp' configuration is accepted ($n)"
ret=0
$CHECKCONF good-kasp.conf > checkconf.out$n 2>/dev/null || ret=1
if [ $ret != 0 ]; then echo_i "failed"; fi
status=`expr $status + $ret`
n=`expr $n + 1`
echo_i "checking that named-checkconf prints a known good kasp config ($n)"
ret=0
awk 'BEGIN { ok = 0; } /cut here/ { ok = 1; getline } ok == 1 { print }' good-kasp.conf > good-kasp.conf.in
[ -s good-kasp.conf.in ] || ret=1
$CHECKCONF -p good-kasp.conf.in | grep -v '^good-kasp.conf.in:' > good-kasp.conf.out 2>&1 || ret=1
cmp good-kasp.conf.in good-kasp.conf.out || ret=1
if [ $ret != 0 ]; then echo_i "failed"; fi
status=`expr $status + $ret`
echo_i "exit status: $status"
[ $status -eq 0 ] || exit 1

View file

@ -1485,7 +1485,7 @@ n=$((n+1))
test "$ret" -eq 0 || echo_i "failed"
status=$((status+ret))
echo_i "checking that dnsssec-signzone updates originalttl on ttl changes ($n)"
echo_i "checking that dnssec-signzone updates originalttl on ttl changes ($n)"
ret=0
zone=example
key1=$($KEYGEN -K signer -q -a RSASHA1 -b 1024 -n zone $zone)

View file

@ -0,0 +1,13 @@
Copyright (C) Internet Systems Consortium, Inc. ("ISC")
See COPYRIGHT in the source root or http://isc.org/copyright.html for terms.
The test setup for the KASP tests.
ns1 is reserved for the root server.
ns2 is running primary service for ns3.
ns3 is an authoritative server for the various test domains.
ns4 and ns5 are authoritative servers for various test domains related to views.

View file

@ -0,0 +1,26 @@
#!/bin/sh
#
# Copyright (C) Internet Systems Consortium, Inc. ("ISC")
#
# 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 http://mozilla.org/MPL/2.0/.
#
# See the COPYRIGHT file distributed with this work for additional
# information regarding copyright ownership.
set -e
rm -f ./keygen.*
rm -f ./K*.private ./K*.key ./K*.state ./K*.cmp
rm -rf ./keys/
rm -f dig.out* rrsig.out.* keyevent.out.*
rm -f ns*/named.conf ns*/named.memstats ns*/named.run*
rm -f ns*/*.jnl ns*/*.jbk
rm -f ns*/K*.private ns*/K*.key ns*/K*.state
rm -f ns*/dsset-* ns*/*.db ns*/*.db.signed
rm -f ns*/keygen.out.* ns*/settime.out.* ns*/signer.out.*
rm -f ns*/managed-keys.bind
rm -f ns*/*.mkeys
# NS3 specific
rm -f ns3/zones ns3/*.db.infile

View file

@ -0,0 +1,25 @@
/*
* Copyright (C) Internet Systems Consortium, Inc. ("ISC")
*
* 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 http://mozilla.org/MPL/2.0/.
*
* See the COPYRIGHT file distributed with this work for additional
* information regarding copyright ownership.
*/
/*
* This is just a random selection of configuration options.
*/
dnssec-policy "kasp" {
dnskey-ttl 200;
keys {
csk key-directory lifetime P1Y algorithm 13;
ksk key-directory lifetime P1Y algorithm 8;
zsk key-directory lifetime P30D algorithm 8 1024;
zsk key-directory lifetime P6M algorithm 8 2000;
};
};

View file

@ -0,0 +1,58 @@
/*
* Copyright (C) Internet Systems Consortium, Inc. ("ISC")
*
* 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 http://mozilla.org/MPL/2.0/.
*
* See the COPYRIGHT file distributed with this work for additional
* information regarding copyright ownership.
*/
// NS2
options {
query-source address 10.53.0.2;
notify-source 10.53.0.2;
transfer-source 10.53.0.2;
port @PORT@;
pid-file "named.pid";
listen-on { 10.53.0.2; };
listen-on-v6 { none; };
allow-transfer { any; };
recursion no;
dnssec-policy "none";
};
key rndc_key {
secret "1234abcd8765";
algorithm hmac-sha256;
};
controls {
inet 10.53.0.2 port @CONTROLPORT@ allow { any; } keys { rndc_key; };
};
/* Inherit dnssec-policy (which is none) */
zone "unsigned.tld" {
type master;
file "unsigned.tld.db";
};
/* Override dnssec-policy */
zone "signed.tld" {
type master;
dnssec-policy "default";
file "signed.tld.db";
};
/* Primary service for ns3 */
zone "secondary.kasp" {
type master;
file "secondary.kasp.db";
allow-transfer { 10.53.0.3; };
notify yes;
};

View file

@ -0,0 +1,27 @@
; Copyright (C) Internet Systems Consortium, Inc. ("ISC")
;
; 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 http://mozilla.org/MPL/2.0/.
;
; See the COPYRIGHT file distributed with this work for additional
; information regarding copyright ownership.
$TTL 300
@ IN SOA secondary.kasp. hostmaster.kasp. (
1 ; serial
20 ; refresh (20 seconds)
20 ; retry (20 seconds)
1814400 ; expire (3 weeks)
3600 ; minimum (1 hour)
)
NS ns2
NS ns3
ns2 A 10.53.0.2
ns3 A 10.53.0.3
a A 10.0.0.1
b A 10.0.0.2
c A 10.0.0.3

View file

@ -0,0 +1,28 @@
; Copyright (C) Internet Systems Consortium, Inc. ("ISC")
;
; 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 http://mozilla.org/MPL/2.0/.
;
; See the COPYRIGHT file distributed with this work for additional
; information regarding copyright ownership.
$TTL 300
@ IN SOA secondary.kasp. hostmaster.kasp. (
2 ; serial
20 ; refresh (20 seconds)
20 ; retry (20 seconds)
1814400 ; expire (3 weeks)
3600 ; minimum (1 hour)
)
NS ns2
NS ns3
ns2 A 10.53.0.2
ns3 A 10.53.0.3
a A 10.0.0.11
b A 10.0.0.2
c A 10.0.0.3
d A 10.0.0.4

View file

@ -0,0 +1,33 @@
#!/bin/sh -e
#
# Copyright (C) Internet Systems Consortium, Inc. ("ISC")
#
# 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 http://mozilla.org/MPL/2.0/.
#
# See the COPYRIGHT file distributed with this work for additional
# information regarding copyright ownership.
# shellcheck source=conf.sh
. "$SYSTEMTESTTOP/conf.sh"
echo_i "ns2/setup.sh"
zone="secondary.kasp"
echo_i "setting up zone: $zone"
zonefile="${zone}.db"
infile="${zonefile}.in"
cp $infile $zonefile
zone="signed.tld"
echo_i "setting up zone: $zone"
zonefile="${zone}.db"
infile="template.tld.db.in"
cp $infile $zonefile
zone="unsigned.tld"
echo_i "setting up zone: $zone"
zonefile="${zone}.db"
infile="template.tld.db.in"
cp $infile $zonefile

View file

@ -0,0 +1,25 @@
; Copyright (C) Internet Systems Consortium, Inc. ("ISC")
;
; 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 http://mozilla.org/MPL/2.0/.
;
; See the COPYRIGHT file distributed with this work for additional
; information regarding copyright ownership.
$TTL 300
@ IN SOA secondary.kasp. hostmaster.kasp. (
1 ; serial
20 ; refresh (20 seconds)
20 ; retry (20 seconds)
1814400 ; expire (3 weeks)
3600 ; minimum (1 hour)
)
NS ns2
ns2 A 10.53.0.2
a A 10.0.0.1
b A 10.0.0.2
c A 10.0.0.3

View file

@ -0,0 +1,319 @@
/*
* Copyright (C) Internet Systems Consortium, Inc. ("ISC")
*
* 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 http://mozilla.org/MPL/2.0/.
*
* See the COPYRIGHT file distributed with this work for additional
* information regarding copyright ownership.
*/
// NS3
include "policies/kasp.conf";
include "policies/autosign.conf";
options {
query-source address 10.53.0.3;
notify-source 10.53.0.3;
transfer-source 10.53.0.3;
port @PORT@;
pid-file "named.pid";
listen-on { 10.53.0.3; };
listen-on-v6 { none; };
allow-transfer { any; };
recursion no;
dnssec-policy "rsasha1";
};
key rndc_key {
secret "1234abcd8765";
algorithm hmac-sha256;
};
controls {
inet 10.53.0.3 port @CONTROLPORT@ allow { any; } keys { rndc_key; };
};
/* Zones that are getting initially signed */
/* The default case: No keys created, using default policy. */
zone "default.kasp" {
type master;
file "default.kasp.db";
dnssec-policy "default";
};
/* A master zone with dnssec-policy, no keys created. */
zone "rsasha1.kasp" {
type master;
file "rsasha1.kasp.db";
dnssec-policy "rsasha1";
};
/* A zone that inherits dnssec-policy. */
zone "inherit.kasp" {
type master;
file "inherit.kasp.db";
};
/* A zone that overrides dnssec-policy. */
zone "unsigned.kasp" {
type master;
file "unsigned.kasp.db";
dnssec-policy "none";
};
/* A master zone with dnssec-policy but keys already created. */
zone "dnssec-keygen.kasp" {
type master;
file "dnssec-keygen.kasp.db";
dnssec-policy "rsasha1";
};
/* A secondary zone with dnssec-policy. */
zone "secondary.kasp" {
type secondary;
masters { 10.53.0.2; };
file "secondary.kasp.db";
dnssec-policy "rsasha1";
};
/*
* A configured dnssec-policy but some keys already created.
*/
zone "some-keys.kasp" {
type master;
file "some-keys.kasp.db";
dnssec-policy "rsasha1";
};
/*
* A configured dnssec-policy but some keys already in use.
*/
zone "legacy-keys.kasp" {
type master;
file "legacy-keys.kasp.db";
dnssec-policy "rsasha1";
};
/*
* A configured dnssec-policy with (too) many keys pregenerated.
*/
zone "pregenerated.kasp" {
type master;
file "pregenerated.kasp.db";
dnssec-policy "rsasha1";
};
/*
* Different algorithms.
*/
zone "rsasha1-nsec3.kasp" {
type master;
file "rsasha1-nsec3.kasp.db";
dnssec-policy "rsasha1-nsec3";
};
zone "rsasha256.kasp" {
type master;
file "rsasha256.kasp.db";
dnssec-policy "rsasha256";
};
zone "rsasha512.kasp" {
type master;
file "rsasha512.kasp.db";
dnssec-policy "rsasha512";
};
zone "ecdsa256.kasp" {
type master;
file "ecdsa256.kasp.db";
dnssec-policy "ecdsa256";
};
zone "ecdsa384.kasp" {
type master;
file "ecdsa384.kasp.db";
dnssec-policy "ecdsa384";
};
/*
* Zones in different signing states.
*/
/*
* Zone that has expired signatures.
*/
zone "expired-sigs.autosign" {
type master;
file "expired-sigs.autosign.db";
dnssec-policy "autosign";
};
/*
* Zone that has valid, fresh signatures.
*/
zone "fresh-sigs.autosign" {
type master;
file "fresh-sigs.autosign.db";
dnssec-policy "autosign";
};
/*
* Zone that has unfresh signatures.
*/
zone "unfresh-sigs.autosign" {
type master;
file "unfresh-sigs.autosign.db";
dnssec-policy "autosign";
};
/*
* Zone that has missing private ZSK.
*/
zone "zsk-missing.autosign" {
type master;
file "zsk-missing.autosign.db";
dnssec-policy "autosign";
};
/*
* Zone that has inactive ZSK.
*/
zone "zsk-retired.autosign" {
type master;
file "zsk-retired.autosign.db";
dnssec-policy "autosign";
};
/*
* Zones for testing ZSK Pre-Publication steps.
*/
zone "step1.zsk-prepub.autosign" {
type master;
file "step1.zsk-prepub.autosign.db";
dnssec-policy "zsk-prepub";
};
zone "step2.zsk-prepub.autosign" {
type master;
file "step2.zsk-prepub.autosign.db";
dnssec-policy "zsk-prepub";
};
zone "step3.zsk-prepub.autosign" {
type master;
file "step3.zsk-prepub.autosign.db";
dnssec-policy "zsk-prepub";
};
zone "step4.zsk-prepub.autosign" {
type master;
file "step4.zsk-prepub.autosign.db";
dnssec-policy "zsk-prepub";
};
zone "step5.zsk-prepub.autosign" {
type master;
file "step5.zsk-prepub.autosign.db";
dnssec-policy "zsk-prepub";
};
/*
* Zones for testing KSK Double-KSK steps.
*/
zone "step1.ksk-doubleksk.autosign" {
type master;
file "step1.ksk-doubleksk.autosign.db";
dnssec-policy "ksk-doubleksk";
};
zone "step2.ksk-doubleksk.autosign" {
type master;
file "step2.ksk-doubleksk.autosign.db";
dnssec-policy "ksk-doubleksk";
};
zone "step3.ksk-doubleksk.autosign" {
type master;
file "step3.ksk-doubleksk.autosign.db";
dnssec-policy "ksk-doubleksk";
};
zone "step4.ksk-doubleksk.autosign" {
type master;
file "step4.ksk-doubleksk.autosign.db";
dnssec-policy "ksk-doubleksk";
};
zone "step5.ksk-doubleksk.autosign" {
type master;
file "step5.ksk-doubleksk.autosign.db";
dnssec-policy "ksk-doubleksk";
};
zone "step6.ksk-doubleksk.autosign" {
type master;
file "step6.ksk-doubleksk.autosign.db";
dnssec-policy "ksk-doubleksk";
};
/*
* Zones for testing CSK rollover steps.
*/
zone "step1.csk-roll.autosign" {
type master;
file "step1.csk-roll.autosign.db";
dnssec-policy "csk-roll";
};
zone "step2.csk-roll.autosign" {
type master;
file "step2.csk-roll.autosign.db";
dnssec-policy "csk-roll";
};
zone "step3.csk-roll.autosign" {
type master;
file "step3.csk-roll.autosign.db";
dnssec-policy "csk-roll";
};
zone "step4.csk-roll.autosign" {
type master;
file "step4.csk-roll.autosign.db";
dnssec-policy "csk-roll";
};
zone "step5.csk-roll.autosign" {
type master;
file "step5.csk-roll.autosign.db";
dnssec-policy "csk-roll";
};
zone "step6.csk-roll.autosign" {
type master;
file "step6.csk-roll.autosign.db";
dnssec-policy "csk-roll";
};
zone "step7.csk-roll.autosign" {
type master;
file "step7.csk-roll.autosign.db";
dnssec-policy "csk-roll";
};
zone "step1.csk-roll2.autosign" {
type master;
file "step1.csk-roll2.autosign.db";
dnssec-policy "csk-roll2";
};
zone "step2.csk-roll2.autosign" {
type master;
file "step2.csk-roll2.autosign.db";
dnssec-policy "csk-roll2";
};
zone "step3.csk-roll2.autosign" {
type master;
file "step3.csk-roll2.autosign.db";
dnssec-policy "csk-roll2";
};
zone "step4.csk-roll2.autosign" {
type master;
file "step4.csk-roll2.autosign.db";
dnssec-policy "csk-roll2";
};
zone "step5.csk-roll2.autosign" {
type master;
file "step5.csk-roll2.autosign.db";
dnssec-policy "csk-roll2";
};
zone "step6.csk-roll2.autosign" {
type master;
file "step6.csk-roll2.autosign.db";
dnssec-policy "csk-roll2";
};

View file

@ -0,0 +1,110 @@
/*
* Copyright (C) Internet Systems Consortium, Inc. ("ISC")
*
* 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 http://mozilla.org/MPL/2.0/.
*
* See the COPYRIGHT file distributed with this work for additional
* information regarding copyright ownership.
*/
dnssec-policy "autosign" {
signatures-refresh P1W;
signatures-validity P2W;
signatures-validity-dnskey P2W;
dnskey-ttl 300;
keys {
ksk key-directory lifetime P2Y algorithm 13;
zsk key-directory lifetime P1Y algorithm 13;
};
};
dnssec-policy "zsk-prepub" {
signatures-refresh P1W;
signatures-validity P2W;
signatures-validity-dnskey P2W;
dnskey-ttl 3600;
publish-safety P1D;
retire-safety P2D;
keys {
ksk key-directory lifetime P2Y algorithm 13;
zsk key-directory lifetime P30D algorithm 13;
};
zone-propagation-delay PT1H;
zone-max-ttl 1d;
};
dnssec-policy "ksk-doubleksk" {
signatures-refresh P1W;
signatures-validity P2W;
signatures-validity-dnskey P2W;
dnskey-ttl 2h;
publish-safety P1D;
retire-safety P2D;
keys {
ksk key-directory lifetime P60D algorithm 13;
zsk key-directory lifetime P1Y algorithm 13;
};
zone-propagation-delay PT1H;
zone-max-ttl 1d;
parent-ds-ttl 3600;
parent-registration-delay P1D;
parent-propagation-delay PT1H;
};
dnssec-policy "csk-roll" {
signatures-refresh P5D;
signatures-validity 30d;
signatures-validity-dnskey 30d;
dnskey-ttl 1h;
publish-safety PT1H;
retire-safety 2h;
keys {
csk key-directory lifetime P6M algorithm 13;
};
zone-propagation-delay 1h;
zone-max-ttl P1D;
parent-ds-ttl 1h;
parent-registration-delay 1d;
parent-propagation-delay 1h;
};
dnssec-policy "csk-roll2" {
signatures-refresh 12h;
signatures-validity P1D;
signatures-validity-dnskey P1D;
dnskey-ttl 1h;
publish-safety PT1H;
retire-safety 1h;
keys {
csk key-directory lifetime P6M algorithm 13;
};
zone-propagation-delay PT1H;
zone-max-ttl 1d;
parent-ds-ttl PT1H;
parent-registration-delay P1W;
parent-propagation-delay PT1H;
};

View file

@ -0,0 +1,70 @@
/*
* Copyright (C) Internet Systems Consortium, Inc. ("ISC")
*
* 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 http://mozilla.org/MPL/2.0/.
*
* See the COPYRIGHT file distributed with this work for additional
* information regarding copyright ownership.
*/
dnssec-policy "rsasha1" {
dnskey-ttl 1234;
keys {
ksk key-directory lifetime P10Y algorithm 5;
zsk key-directory lifetime P5Y algorithm 5;
zsk key-directory lifetime P1Y algorithm 5 2000;
};
};
dnssec-policy "rsasha1-nsec3" {
dnskey-ttl 1234;
keys {
ksk key-directory lifetime P10Y algorithm 7;
zsk key-directory lifetime P5Y algorithm 7;
zsk key-directory lifetime P1Y algorithm 7 2000;
};
};
dnssec-policy "rsasha256" {
dnskey-ttl 1234;
keys {
ksk key-directory lifetime P10Y algorithm 8;
zsk key-directory lifetime P5Y algorithm 8;
zsk key-directory lifetime P1Y algorithm 8 2000;
};
};
dnssec-policy "rsasha512" {
dnskey-ttl 1234;
keys {
ksk key-directory lifetime P10Y algorithm 10;
zsk key-directory lifetime P5Y algorithm 10;
zsk key-directory lifetime P1Y algorithm 10 2000;
};
};
dnssec-policy "ecdsa256" {
dnskey-ttl 1234;
keys {
ksk key-directory lifetime P10Y algorithm 13;
zsk key-directory lifetime P5Y algorithm 13;
zsk key-directory lifetime P1Y algorithm 13 256;
};
};
dnssec-policy "ecdsa384" {
dnskey-ttl 1234;
keys {
ksk key-directory lifetime P10Y algorithm 14;
zsk key-directory lifetime P5Y algorithm 14;
zsk key-directory lifetime P1Y algorithm 14 384;
};
};

View file

@ -0,0 +1,654 @@
#!/bin/sh -e
#
# Copyright (C) Internet Systems Consortium, Inc. ("ISC")
#
# 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 http://mozilla.org/MPL/2.0/.
#
# See the COPYRIGHT file distributed with this work for additional
# information regarding copyright ownership.
# shellcheck source=conf.sh
. "$SYSTEMTESTTOP/conf.sh"
echo_i "ns3/setup.sh"
setup() {
zone="$1"
echo_i "setting up zone: $zone"
zonefile="${zone}.db"
infile="${zone}.db.infile"
echo $zone >> zones
}
private_type_record() {
_zone=$1
_algorithm=$2
_keyfile=$3
_id=$(keyfile_to_key_id "$_keyfile")
printf "%s. 0 IN TYPE65534 \# 5 %02x%04x0000\n" $_zone $_algorithm $_id
}
# Make lines shorter by storing key states in environment variables.
H="HIDDEN"
R="RUMOURED"
O="OMNIPRESENT"
U="UNRETENTIVE"
#
# Set up zones that will be initially signed.
#
for zn in default rsasha1 dnssec-keygen some-keys legacy-keys pregenerated \
rsasha1-nsec3 rsasha256 rsasha512 ecdsa256 ecdsa384 inherit
do
setup "${zn}.kasp"
cp template.db.in $zonefile
done
# Set up zone that stays unsigned.
zone="unsigned.kasp"
echo_i "setting up zone: $zone"
zonefile="${zone}.db"
infile="${zone}.db.infile"
cp template.db.in $zonefile
# Some of these zones already have keys.
zone="dnssec-keygen.kasp"
$KEYGEN -k rsasha1 -l policies/kasp.conf $zone > keygen.out.$zone.1 2>&1
zone="some-keys.kasp"
$KEYGEN -P none -A none -a RSASHA1 -b 2000 -L 1234 $zone > keygen.out.$zone.1 2>&1
$KEYGEN -P none -A none -a RSASHA1 -f KSK -L 1234 $zone > keygen.out.$zone.2 2>&1
zone="legacy.kasp"
$KEYGEN -a RSASHA1 -b 2000 -L 1234 $zone > keygen.out.$zone.1 2>&1
$KEYGEN -a RSASHA1 -f KSK -L 1234 $zone > keygen.out.$zone.2 2>&1
zone="pregenerated.kasp"
$KEYGEN -k rsasha1 -l policies/kasp.conf $zone > keygen.out.$zone.1 2>&1
$KEYGEN -k rsasha1 -l policies/kasp.conf $zone > keygen.out.$zone.2 2>&1
#
# Set up zones that are already signed.
#
# These signatures are set to expire long in the past, update immediately.
setup expired-sigs.autosign
KSK=`$KEYGEN -a ECDSAP256SHA256 -f KSK -L 300 $zone 2> keygen.out.$zone.1`
ZSK=`$KEYGEN -a ECDSAP256SHA256 -L 300 $zone 2> keygen.out.$zone.2`
T="now-6mo"
$SETTIME -s -P $T -A $T -g $O -d $O $T -k $O $T -r $O $T $KSK > settime.out.$zone.1 2>&1
$SETTIME -s -P $T -A $T -g $O -k $O $T -z $O $T $ZSK > settime.out.$zone.2 2>&1
cat template.db.in "${KSK}.key" "${ZSK}.key" > "$infile"
private_type_record $zone 13 $KSK >> "$infile"
private_type_record $zone 13 $ZSK >> "$infile"
$SIGNER -PS -x -s now-2mo -e now-1mo -o $zone -O full -f $zonefile $infile > signer.out.$zone.1 2>&1
# These signatures are still good, and can be reused.
setup fresh-sigs.autosign
KSK=`$KEYGEN -a ECDSAP256SHA256 -f KSK -L 300 $zone 2> keygen.out.$zone.1`
ZSK=`$KEYGEN -a ECDSAP256SHA256 -L 300 $zone 2> keygen.out.$zone.2`
T="now-6mo"
$SETTIME -s -P $T -A $T -g $O -d $O $T -k $O $T -r $O $T $KSK > settime.out.$zone.1 2>&1
$SETTIME -s -P $T -A $T -g $O -k $O $T -z $O $T $ZSK > settime.out.$zone.2 2>&1
cat template.db.in "${KSK}.key" "${ZSK}.key" > "$infile"
private_type_record $zone 13 $KSK >> "$infile"
private_type_record $zone 13 $ZSK >> "$infile"
$SIGNER -S -x -s now-1h -e now+2w -o $zone -O full -f $zonefile $infile > signer.out.$zone.1 2>&1
# These signatures are still good, but not fresh enough, update immediately.
setup unfresh-sigs.autosign
KSK=`$KEYGEN -a ECDSAP256SHA256 -f KSK -L 300 $zone 2> keygen.out.$zone.1`
ZSK=`$KEYGEN -a ECDSAP256SHA256 -L 300 $zone 2> keygen.out.$zone.2`
T="now-6mo"
$SETTIME -s -P $T -A $T -g $O -d $O $T -k $O $T -r $O $T $KSK > settime.out.$zone.1 2>&1
$SETTIME -s -P $T -A $T -g $O -k $O $T -z $O $T $ZSK > settime.out.$zone.2 2>&1
cat template.db.in "${KSK}.key" "${ZSK}.key" > "$infile"
private_type_record $zone 13 $KSK >> "$infile"
private_type_record $zone 13 $ZSK >> "$infile"
$SIGNER -S -x -s now-1w -e now+1w -o $zone -O full -f $zonefile $infile > signer.out.$zone.1 2>&1
# These signatures are already expired, and the private ZSK is missing.
setup zsk-missing.autosign
KSK=`$KEYGEN -a ECDSAP256SHA256 -f KSK -L 300 $zone 2> keygen.out.$zone.1`
ZSK=`$KEYGEN -a ECDSAP256SHA256 -L 300 $zone 2> keygen.out.$zone.2`
T="now-6mo"
$SETTIME -s -P $T -A $T -g $O -d $O $T -k $O $T -r $O $T $KSK > settime.out.$zone.1 2>&1
$SETTIME -s -P $T -A $T -g $O -k $O $T -z $O $T $ZSK > settime.out.$zone.2 2>&1
cat template.db.in "${KSK}.key" "${ZSK}.key" > "$infile"
private_type_record $zone 13 $KSK >> "$infile"
private_type_record $zone 13 $ZSK >> "$infile"
$SIGNER -PS -x -s now-2w -e now-1mi -o $zone -O full -f $zonefile $infile > signer.out.$zone.1 2>&1
rm -f ${ZSK}.private
# These signatures are already expired, and the private ZSK is retired.
setup zsk-retired.autosign
KSK=`$KEYGEN -a ECDSAP256SHA256 -f KSK -L 300 $zone 2> keygen.out.$zone.1`
ZSK=`$KEYGEN -a ECDSAP256SHA256 -L 300 $zone 2> keygen.out.$zone.2`
T="now-6mo"
$SETTIME -s -P $T -A $T -g $O -d $O $T -k $O $T -r $O $T $KSK > settime.out.$zone.1 2>&1
$SETTIME -s -P $T -A $T -g $O -k $O $T -z $O $T $ZSK > settime.out.$zone.2 2>&1
cat template.db.in "${KSK}.key" "${ZSK}.key" > "$infile"
private_type_record $zone 13 $KSK >> "$infile"
private_type_record $zone 13 $ZSK >> "$infile"
$SIGNER -PS -x -s now-2w -e now-1mi -o $zone -O full -f $zonefile $infile > signer.out.$zone.1 2>&1
$SETTIME -s -I now -g HIDDEN $ZSK > settime.out.$zone.3 2>&1
#
# The zones at zsk-prepub.autosign represent the various steps of a ZSK
# Pre-Publication rollover.
#
# Step 1:
# Introduce the first key. This will immediately be active.
setup step1.zsk-prepub.autosign
KSK=`$KEYGEN -a ECDSAP256SHA256 -f KSK -L 3600 $zone 2> keygen.out.$zone.1`
ZSK=`$KEYGEN -a ECDSAP256SHA256 -L 3600 $zone 2> keygen.out.$zone.2`
TactN="now"
$SETTIME -s -P $TactN -A $TactN -g $O -k $O $TactN -r $O $TactN -d $O $TactN $KSK > settime.out.$zone.1 2>&1
$SETTIME -s -P $TactN -A $TactN -g $O -k $O $TactN -z $O $TactN $ZSK > settime.out.$zone.2 2>&1
cat template.db.in "${KSK}.key" "${ZSK}.key" > "$infile"
private_type_record $zone 13 $KSK >> "$infile"
private_type_record $zone 13 $ZSK >> "$infile"
$SIGNER -S -x -s now-1h -e now+2w -o $zone -O full -f $zonefile $infile > signer.out.$zone.1 2>&1
# Step 2:
# It is time to pre-publish the successor ZSK.
setup step2.zsk-prepub.autosign
KSK=`$KEYGEN -a ECDSAP256SHA256 -f KSK -L 3600 $zone 2> keygen.out.$zone.1`
ZSK=`$KEYGEN -a ECDSAP256SHA256 -L 3600 $zone 2> keygen.out.$zone.2`
# According to RFC 7583: Tpub(N+1) <= Tact(N) + Lzsk - Ipub
# Also: Ipub = Dprp + TTLkey (+publish-safety)
# so: Tact(N) = Tpub(N+1) + Ipub - Lzsk = now + (1d2h) - 30d =
# now + 26h - 30d = now 694h
TactN="now-694h"
$SETTIME -s -P $TactN -A $TactN -g $O -k $O $TactN -r $O $TactN -d $O $TactN $KSK > settime.out.$zone.1 2>&1
$SETTIME -s -P $TactN -A $TactN -g $O -k $O $TactN -z $O $TactN $ZSK > settime.out.$zone.2 2>&1
cat template.db.in "${KSK}.key" "${ZSK}.key" > "$infile"
private_type_record $zone 13 $KSK >> "$infile"
private_type_record $zone 13 $ZSK >> "$infile"
$SIGNER -S -x -s now-1h -e now+2w -o $zone -O full -f $zonefile $infile > signer.out.$zone.1 2>&1
# Step 3:
# After the publication interval has passed the DNSKEY of the successor ZSK
# is OMNIPRESENT and the zone can thus be signed with the successor ZSK.
setup step3.zsk-prepub.autosign
KSK=`$KEYGEN -a ECDSAP256SHA256 -f KSK -L 3600 $zone 2> keygen.out.$zone.1`
ZSK1=`$KEYGEN -a ECDSAP256SHA256 -L 3600 $zone 2> keygen.out.$zone.2`
ZSK2=`$KEYGEN -a ECDSAP256SHA256 -L 3600 $zone 2> keygen.out.$zone.3`
# According to RFC 7583: Tpub(N+1) <= Tact(N) + Lzsk - Ipub
# Also: Tret(N) = Tact(N+1) = Tact(N) + Lzsk
# so: Tact(N) = Tact(N+1) - Lzsk = now - 30d
# and: Tpub(N+1) = Tact(N+1) - Ipub = now - 26h
# and: Tret(N+1) = Tact(N+1) + Lzsk
TactN="now-30d"
TpubN1="now-26h"
TretN1="now+30d"
$SETTIME -s -P $TactN -A $TactN -g $O -k $O $TactN -r $O $TactN -d $O $TactN $KSK > settime.out.$zone.1 2>&1
$SETTIME -s -P $TactN -A $TactN -I now -g $H -k $O $TactN -z $O $TactN $ZSK1 > settime.out.$zone.2 2>&1
$SETTIME -s -S $ZSK1 -i 0 $ZSK2 > settime.out.$zone.3 2>&1
$SETTIME -s -P $TpubN1 -A now -I $TretN1 -g $O -k $R $TpubN1 -z $H $TpubN1 $ZSK2 > settime.out.$zone.4 2>&1
cat template.db.in "${KSK}.key" "${ZSK1}.key" "${ZSK2}.key" > "$infile"
private_type_record $zone 13 $KSK >> "$infile"
private_type_record $zone 13 $ZSK1 >> "$infile"
private_type_record $zone 13 $ZSK2 >> "$infile"
$SIGNER -S -x -s now-1h -e now+2w -o $zone -O full -f $zonefile $infile > signer.out.$zone.1 2>&1
# Step 4:
# After the retire interval has passed the predecessor DNSKEY can be
# removed from the zone.
setup step4.zsk-prepub.autosign
KSK=`$KEYGEN -a ECDSAP256SHA256 -f KSK -L 3600 $zone 2> keygen.out.$zone.1`
ZSK1=`$KEYGEN -a ECDSAP256SHA256 -L 3600 $zone 2> keygen.out.$zone.2`
ZSK2=`$KEYGEN -a ECDSAP256SHA256 -L 3600 $zone 2> keygen.out.$zone.3`
# According to RFC 7583: Tret(N) = Tact(N) + Lzsk
# Also: Tdea(N) = Tret(N) + Iret
# Also: Iret = Dsgn + Dprp + TTLsig (+retire-safety)
# so: Tact(N) = Tdea(N) - Iret - Lzsk = now - (1w1h1d2d) - 30d =
# now - (10d1h) - 30d = now - 961h
# and: Tret(N) = Tdea(N) - Iret = now - (10d1h) = now - 241h
# and: Tpub(N+1) = Tdea(N) - Iret - Ipub = now - (10d1h) - 26h =
# now - 267h
# and: Tact(N+1) = Tdea(N) - Iret = Tret(N)
# and: Tret(N+1) = Tdea(N) - Iret + Lzsk = now - (10d1h) + 30d =
# now + 479h
TactN="now-961h"
TretN="now-241h"
TpubN1="now-267h"
TactN1="${TretN}"
TretN1="now+479h"
$SETTIME -s -P $TactN -A $TactN -g $O -k $O $TactN -r $O $TactN -d $O $TactN $KSK > settime.out.$zone.1 2>&1
$SETTIME -s -P $TactN -A $TactN -I $TretN -g $H -k $O $TactN -z $U $TretN $ZSK1 > settime.out.$zone.2 2>&1
$SETTIME -s -S $ZSK1 -i 0 $ZSK2 > settime.out.$zone.3 2>&1
$SETTIME -s -P $TpubN1 -A $TactN1 -I $TretN1 -g $O -k $O $TactN1 -z $R $TactN1 $ZSK2 > settime.out.$zone.4 2>&1
cat template.db.in "${KSK}.key" "${ZSK1}.key" "${ZSK2}.key" > "$infile"
$SIGNER -PS -x -s now-2w -e now-1mi -o $zone -O full -f $zonefile $infile > signer.out.$zone.1 2>&1
# Step 5:
# The predecessor DNSKEY is removed long enough that is has become HIDDEN.
setup step5.zsk-prepub.autosign
KSK=`$KEYGEN -a ECDSAP256SHA256 -f KSK -L 3600 $zone 2> keygen.out.$zone.1`
ZSK1=`$KEYGEN -a ECDSAP256SHA256 -L 3600 $zone 2> keygen.out.$zone.2`
ZSK2=`$KEYGEN -a ECDSAP256SHA256 -L 3600 $zone 2> keygen.out.$zone.3`
# Substract DNSKEY TTL from all the times (1h).
TactN="now-962h"
TretN="now-242h"
TpubN1="now-268h"
TactN1="${TretN}"
TretN1="now+478h"
$SETTIME -s -P $TactN -A $TactN -g $O -k $O $TactN -r $O $TactN -d $O $TactN $KSK > settime.out.$zone.1 2>&1
$SETTIME -s -P $TactN -A $TactN -I $TretN -D now -g $H -k $U $TretN -z $U $TretN $ZSK1 > settime.out.$zone.2 2>&1
$SETTIME -s -S $ZSK1 -i 0 $ZSK2 > settime.out.$zone.3 2>&1
$SETTIME -s -P $TpubN1 -A $TactN1 -I $TretN1 -g $O -k $O $TactN1 -z $R $TactN1 $ZSK2 > settime.out.$zone.4 2>&1
cat template.db.in "${KSK}.key" "${ZSK1}.key" "${ZSK2}.key" > "$infile"
private_type_record $zone 13 $KSK >> "$infile"
private_type_record $zone 13 $ZSK1 >> "$infile"
private_type_record $zone 13 $ZSK2 >> "$infile"
$SIGNER -S -x -s now-1h -e now+2w -o $zone -O full -f $zonefile $infile > signer.out.$zone.1 2>&1
#
# The zones at ksk-doubleksk.autosign represent the various steps of a KSK
# Double-KSK rollover.
#
# Step 1:
# Introduce the first key. This will immediately be active.
setup step1.ksk-doubleksk.autosign
KSK=`$KEYGEN -a ECDSAP256SHA256 -f KSK -L 7200 $zone 2> keygen.out.$zone.1`
ZSK=`$KEYGEN -a ECDSAP256SHA256 -L 7200 $zone 2> keygen.out.$zone.2`
TactN="now"
$SETTIME -s -P $TactN -A $TactN -g $O -k $O $TactN -r $O $TactN -d $O $TactN $KSK > settime.out.$zone.1 2>&1
$SETTIME -s -P $TactN -A $TactN -g $O -k $O $TactN -z $O $TactN $ZSK > settime.out.$zone.2 2>&1
cat template.db.in "${KSK}.key" "${ZSK}.key" > "$infile"
$SIGNER -S -x -s now-1h -e now+2w -o $zone -O full -f $zonefile $infile > signer.out.$zone.1 2>&1
# Step 2:
# It is time to submit the introduce the new KSK.
setup step2.ksk-doubleksk.autosign
KSK=`$KEYGEN -a ECDSAP256SHA256 -f KSK -L 7200 $zone 2> keygen.out.$zone.1`
ZSK=`$KEYGEN -a ECDSAP256SHA256 -L 7200 $zone 2> keygen.out.$zone.2`
# According to RFC 7583: Tpub(N+1) <= Tact(N) + Lksk - Dreg - IpubC
# Also: IpubC = DprpC + TTLkey (+publish-safety)
# so: Tact(N) = Tpub(N+1) - Lksk + Dreg + IpubC = now - 60d + (1d3h)
# now - 1440h + 27h = now - 1413h
TactN="now-1413h"
$SETTIME -s -P $TactN -A $TactN -g $O -k $O $TactN -r $O $TactN -d $O $TactN $KSK > settime.out.$zone.1 2>&1
$SETTIME -s -P $TactN -A $TactN -g $O -k $O $TactN -z $O $TactN $ZSK > settime.out.$zone.2 2>&1
cat template.db.in "${KSK}.key" "${ZSK}.key" > "$infile"
private_type_record $zone 13 $KSK >> "$infile"
private_type_record $zone 13 $ZSK >> "$infile"
$SIGNER -S -x -s now-1h -e now+2w -o $zone -O full -f $zonefile $infile > signer.out.$zone.1 2>&1
# Step 3:
# It is time to submit the DS.
setup step3.ksk-doubleksk.autosign
KSK1=`$KEYGEN -a ECDSAP256SHA256 -f KSK -L 7200 $zone 2> keygen.out.$zone.1`
KSK2=`$KEYGEN -a ECDSAP256SHA256 -f KSK -L 7200 $zone 2> keygen.out.$zone.2`
ZSK=`$KEYGEN -a ECDSAP256SHA256 -L 7200 $zone 2> keygen.out.$zone.3`
# According to RFC 7583: Tsbm(N+1) >= Trdy(N+1)
# Also: Tact(N+1) = Tsbm(N+1) + Dreg
# so: Tact(N) = Tsbm(N+1) + Dreg - Lksk = now + 1d - 60d = now - 59d
# and: Tret(N) = Tsbm(N+1) + Dreg = now + 1d
# and: Tpub(N+1) <= Tsbm(N+1) - IpubC = now + 27h
# and: Tret(N+1) = Tsbm(N+1) + Dreg + Lksk = 1d + 60d
TactN="now-59d"
TretN="now+1d"
TpubN1="now-27h"
TretN1="now+61d"
$SETTIME -s -P $TactN -A $TactN -I $TretN -g $H -k $O $TactN -r $O $TactN -d $O $TactN $KSK1 > settime.out.$zone.1 2>&1
$SETTIME -s -S $KSK1 -i 0 $KSK2 > settime.out.$zone.3 2>&1
$SETTIME -s -P $TpubN1 -A $TretN -I $TretN1 -g $O -k $R $TpubN1 -r $R $TpubN1 -d $H $TpubN1 $KSK2 > settime.out.$zone.1 2>&1
$SETTIME -s -P $TactN -A $TactN -g $O -k $O $TactN -z $O $TactN $ZSK > settime.out.$zone.2 2>&1
cat template.db.in "${KSK1}.key" "${KSK2}.key" "${ZSK}.key" > "$infile"
private_type_record $zone 13 $KSK1 >> "$infile"
private_type_record $zone 13 $KSK2 >> "$infile"
private_type_record $zone 13 $ZSK >> "$infile"
$SIGNER -S -x -s now-1h -e now+2w -o $zone -O full -f $zonefile $infile > signer.out.$zone.1 2>&1
# Step 4:
# The DS should be swapped now.
setup step4.ksk-doubleksk.autosign
KSK1=`$KEYGEN -a ECDSAP256SHA256 -f KSK -L 7200 $zone 2> keygen.out.$zone.1`
KSK2=`$KEYGEN -a ECDSAP256SHA256 -f KSK -L 7200 $zone 2> keygen.out.$zone.2`
ZSK=`$KEYGEN -a ECDSAP256SHA256 -L 7200 $zone 2> keygen.out.$zone.3`
# According to RFC 7583: Tdea(N) = Tret(N) + Iret
# Also: Tret(N) = Tsbm(N+1) + Dreg
# Also: Tact(N+1) = Tret(N)
# Also: Iret = DprpP + TTLds (+retire-safety)
# so: Tact(N) = Tdea(N) - Lksk - Iret = now - 60d - 2d2h = now - 1490h
# and: Tret(N) = Tdea(N) - Iret = now - 2d2h = 50h
# and: Tpub(N+1) = Tdea(N) - Iret - Dreg - IpubC = now - 50h - 1d - 1d3h = now - 101h
# and: Tsbm(N+1) = Tdea(N) - Iret - Dreg = now - 50h - 1d = now - 74h
# and: Tact(N+1) = Tret(N)
# and: Tret(N+1) = Tdea(N) + Lksk - Iret = now + 60d - 2d2h = now + 1390h
TactN="now-1490h"
TretN="now-50h"
TpubN1="now-101h"
TsbmN1="now-74h"
TactN1="${TretN}"
TretN1="now+1390h"
$SETTIME -s -P $TactN -A $TactN -I $TretN -g $H -k $O $TactN -r $O $TactN -d $U $TsbmN1 $KSK1 > settime.out.$zone.1 2>&1
$SETTIME -s -S $KSK1 -i 0 $KSK2 > settime.out.$zone.3 2>&1
$SETTIME -s -P $TpubN1 -A $TactN1 -I $TretN1 -g $O -k $O $TsbmN1 -r $O $TsbmN1 -d $R $TsbmN1 $KSK2 > settime.out.$zone.1 2>&1
$SETTIME -s -P $TactN -A $TactN -g $O -k $O $TactN -z $O $TactN $ZSK > settime.out.$zone.2 2>&1
cat template.db.in "${KSK1}.key" "${KSK2}.key" "${ZSK}.key" > "$infile"
private_type_record $zone 13 $KSK1 >> "$infile"
private_type_record $zone 13 $KSK2 >> "$infile"
private_type_record $zone 13 $ZSK >> "$infile"
$SIGNER -S -x -s now-1h -e now+2w -o $zone -O full -f $zonefile $infile > signer.out.$zone.1 2>&1
# Step 5:
# The predecessor DNSKEY is removed long enough that is has become HIDDEN.
setup step5.ksk-doubleksk.autosign
KSK1=`$KEYGEN -a ECDSAP256SHA256 -f KSK -L 7200 $zone 2> keygen.out.$zone.1`
KSK2=`$KEYGEN -a ECDSAP256SHA256 -f KSK -L 7200 $zone 2> keygen.out.$zone.2`
ZSK=`$KEYGEN -a ECDSAP256SHA256 -L 7200 $zone 2> keygen.out.$zone.3`
# Substract DNSKEY TTL from all the times (2h).
TactN="now-1492h"
TretN="now-52h"
TpubN1="now-102h"
TsbmN1="now-75h"
TactN1="${TretN}"
TretN1="now+1388h"
$SETTIME -s -P $TactN -A $TactN -I $TretN -g $H -k $U $TretN -r $U $TretN -d $H $TretN $KSK1 > settime.out.$zone.1 2>&1
$SETTIME -s -S $KSK1 -i 0 $KSK2 > settime.out.$zone.3 2>&1
$SETTIME -s -P $TpubN1 -A $TactN1 -I $TretN1 -g $O -k $O $TactN1 -r $O $TactN1 -d $O $TactN1 $KSK2 > settime.out.$zone.1 2>&1
$SETTIME -s -P $TactN -A $TactN -g $O -k $O $TactN -z $O $TactN $ZSK > settime.out.$zone.2 2>&1
cat template.db.in "${KSK1}.key" "${KSK2}.key" "${ZSK}.key" > "$infile"
private_type_record $zone 13 $KSK1 >> "$infile"
private_type_record $zone 13 $KSK2 >> "$infile"
private_type_record $zone 13 $ZSK >> "$infile"
$SIGNER -S -x -s now-1h -e now+2w -o $zone -O full -f $zonefile $infile > signer.out.$zone.1 2>&1
#
# The zones at csk-roll.autosign represent the various steps of a CSK rollover
# (which is essentially a ZSK Pre-Publication / KSK Double-KSK rollover).
#
# Step 1:
# Introduce the first key. This will immediately be active.
setup step1.csk-roll.autosign
CSK=`$KEYGEN -k csk-roll -l policies/autosign.conf $zone 2> keygen.out.$zone.1`
TactN="now"
$SETTIME -s -P $TactN -A $TactN -g $O -k $O $TactN -r $O $TactN -d $O $TactN -z $O $TactN $CSK > settime.out.$zone.1 2>&1
cat template.db.in "${CSK}.key" > "$infile"
private_type_record $zone 13 $CSK >> "$infile"
$SIGNER -S -z -x -s now-1h -e now+30d -o $zone -O full -f $zonefile $infile > signer.out.$zone.1 2>&1
# Step 2:
# It is time to introduce the new CSK.
setup step2.csk-roll.autosign
CSK=`$KEYGEN -k csk-roll -l policies/autosign.conf $zone 2> keygen.out.$zone.1`
# According to RFC 7583: ZSK: Tpub(N+1) <= Tact(N) + Lzsk - Ipub
# According to RFC 7583: KSK: Tpub(N+1) <= Tact(N) + Lksk - Dreg - IpubC
# Also: Ipub = Dprp + TTLkey (+publish-safety)
# Also: IpubC = DprpC + TTLkey (+publish-safety)
# Both sums are almost the same, but the KSK case has Dreg in the equation.
# so: Tact(N) = Tpub(N+1) - Lcsk + Dreg + IpubC = now - 6mo + 1d + 3h =
# now - 4464h + 24h + 3h = now - 4437h
TactN="now-4437h"
$SETTIME -s -P $TactN -A $TactN -g $O -k $O $TactN -r $O $TactN -d $O $TactN -z $O $TactN $CSK > settime.out.$zone.1 2>&1
cat template.db.in "${CSK}.key" > "$infile"
private_type_record $zone 13 $CSK >> "$infile"
$SIGNER -S -z -x -s now-1h -e now+30d -o $zone -O full -f $zonefile $infile > signer.out.$zone.1 2>&1
# Step 3:
# It is time to submit the DS and to roll signatures.
setup step3.csk-roll.autosign
CSK1=`$KEYGEN -k csk-roll -l policies/autosign.conf $zone 2> keygen.out.$zone.1`
CSK2=`$KEYGEN -k csk-roll -l policies/autosign.conf $zone 2> keygen.out.$zone.1`
# According to RFC 7583: Tsbm(N+1) >= Trdy(N+1)
# Also: Tact(N+1) = Tsbm(N+1) + Dreg
# so: Tact(N) = Tsbm(N+1) + Dreg - Lksk = now + 1d - 6mo = now - 185d
# and: Tret(N) = Tsbm(N+1) + Dreg = now + 1d
# and: Tpub(N+1) <= Tsbm(N+1) - IpubC = now - 3h
# and: Tret(N+1) = Tsbm(N+1) + Dreg + Lksk = now + 1d + 6mo = now + 187d
TactN="now-185d"
TretN="now+1d"
TpubN1="now-3h"
TretN1="now+187d"
$SETTIME -s -P $TactN -A $TactN -I $TretN -g $H -k $O $TactN -r $O $TactN -d $O $TactN -z $O $TactN $CSK1 > settime.out.$zone.1 2>&1
$SETTIME -s -S $CSK1 -i 0 $CSK2 > settime.out.$zone.3 2>&1
$SETTIME -s -P $TpubN1 -A $TretN -I $TretN1 -g $O -k $R $TpubN1 -r $R $TpubN1 -d $H $TpubN1 -z $H $TpubN1 $CSK2 > settime.out.$zone.1 2>&1
cat template.db.in "${CSK1}.key" "${CSK2}.key" > "$infile"
private_type_record $zone 13 $CSK1 >> "$infile"
private_type_record $zone 13 $CSK2 >> "$infile"
$SIGNER -S -z -x -s now-1h -e now+30d -o $zone -O full -f $zonefile $infile > signer.out.$zone.1 2>&1
# Step 4:
# Some time later all the ZRRSIG records should be from the new CSK, and the
# DS should be swapped. The ZRRSIG records are all replaced after Iret
# which is Dsgn + Dprp + TTLsig + retire-safety (25d + 1h + 1d + 2h = 26d3h).
# The DS is swapped after Dreg + DprpP + TTLds + retire-safety
# (1d + 1h + 1h + 2h = 1d4h). In other words, the DS is swapped before all
# zone signatures are replaced.
setup step4.csk-roll.autosign
CSK1=`$KEYGEN -k csk-roll -l policies/autosign.conf $zone 2> keygen.out.$zone.1`
CSK2=`$KEYGEN -k csk-roll -l policies/autosign.conf $zone 2> keygen.out.$zone.1`
# According to RFC 7583: Tdea(N) = Tret(N) + Iret
# Also: Iret = 1h + 1h + 2h = 4h
# Also: Tact(N+1) = Tret(N)
# so: Tact(N) = Tdea(N) - Lksk - Iret = now - 6mo - 4h = now - 4468h
# and: Tret(N) = Tdea(N) - Iret = now - 4h = now - 4h
# and: Tpub(N+1) = Tdea(N) - Iret - Dreg - IpubC = now - 4h - 1d - 3h = now - 31h
# and: Tsbm(N+1) = Tdea(N) - Iret - Dreg = now - 4h - 1d = now - 28h
# and: Tact(N+1) = Tret(N)
# and: Tret(N+1) = Tdea(N) + Lksk - Iret = now + 6mo - 4h = now + 4460h
TactN="now-4468h"
TretN="now-4h"
TpubN1="now-31h"
TsbmN1="now-28h"
TactN1="${TretN}"
TretN1="now+4460h"
$SETTIME -s -P $TactN -A $TactN -I $TretN -g $H -k $O $TactN -r $O $TactN -d $U $TsbmN1 -z $U $TsbmN1 $CSK1 > settime.out.$zone.1 2>&1
$SETTIME -s -S $CSK1 -i 0 $CSK2 > settime.out.$zone.3 2>&1
$SETTIME -s -P $TpubN1 -A $TactN1 -I $TretN1 -g $O -k $O $TsbmN1 -r $O $TsbmN1 -d $R $TsbmN1 -z $R $TsbmN1 $CSK2 > settime.out.$zone.1 2>&1
cat template.db.in "${CSK1}.key" "${CSK2}.key" > "$infile"
private_type_record $zone 13 $CSK1 >> "$infile"
private_type_record $zone 13 $CSK2 >> "$infile"
$SIGNER -S -z -x -s now-1h -e now+30d -o $zone -O full -f $zonefile $infile > signer.out.$zone.1 2>&1
# Step 5:
# After the DS is swapped in step 4, also the KRRSIG records can be removed.
# At this time these have all become hidden.
setup step5.csk-roll.autosign
CSK1=`$KEYGEN -k csk-roll -l policies/autosign.conf $zone 2> keygen.out.$zone.1`
CSK2=`$KEYGEN -k csk-roll -l policies/autosign.conf $zone 2> keygen.out.$zone.1`
# Substract DNSKEY TTL plus zone propagation delay from all the times (2h).
TactN="now-4470h"
TretN="now-6h"
TdeaN="now-2h"
TpubN1="now-33h"
TsbmN1="now-30h"
TactN1="${TretN}"
TretN1="now+4458h"
$SETTIME -s -P $TactN -A $TactN -I $TretN -g $H -k $O $TactN -r $U $TdeaN -d $H $TdeaN -z $U $TsbmN1 $CSK1 > settime.out.$zone.1 2>&1
$SETTIME -s -S $CSK1 -i 0 $CSK2 > settime.out.$zone.3 2>&1
$SETTIME -s -P $TpubN1 -A $TactN1 -I $TretN1 -g $O -k $O $TsbmN1 -r $O $TsbmN1 -d $O $TdeaN -z $R $TsbmN1 $CSK2 > settime.out.$zone.1 2>&1
cat template.db.in "${CSK1}.key" "${CSK2}.key" > "$infile"
private_type_record $zone 13 $CSK1 >> "$infile"
private_type_record $zone 13 $CSK2 >> "$infile"
$SIGNER -S -z -x -s now-1h -e now+30d -o $zone -O full -f $zonefile $infile > signer.out.$zone.1 2>&1
# Step 6:
# After the retire interval has passed the predecessor DNSKEY can be
# removed from the zone.
setup step6.csk-roll.autosign
CSK1=`$KEYGEN -k csk-roll -l policies/autosign.conf $zone 2> keygen.out.$zone.1`
CSK2=`$KEYGEN -k csk-roll -l policies/autosign.conf $zone 2> keygen.out.$zone.1`
# According to RFC 7583: Tdea(N) = Tret(N) + Iret
# Also: Tret(N) = Tact(N) + Lzsk
# Also: Iret = Dsgn + Dprp + TTLsig (+retire-safety)
# so: Tact(N) = Tdea(N) - Iret - Lzsk = now - 25d1h1d2h - 6mo =
# now - 26d3h - 6mo = now - 627h - 4464h = now - 5091h
# and: Tret(N) = Tdea(N) - Iret = now - 627h
# and: Tpub(N+1) = Tdea(N) - Iret - Ipub = now - 627h - 3h = now - 630h
# and: Tact(N+1) = Tdea(N) - Iret = Tret(N)
# and: Tret(N+1) = Tdea(N) - Iret + Lzsk = now - 627h + 6mo = now + 3837h
TactN="now-5091h"
TretN="now-627h"
TdeaN="now-623h"
TpubN1="now-630h"
TsbmN1="now-627h"
TactN1="${TretN}"
TretN1="now+3837h"
$SETTIME -s -P $TactN -A $TactN -I $TretN -g $H -k $O $TactN -r $H $TdeaN -d $H $TdeaN -z $U $TsbmN1 $CSK1 > settime.out.$zone.1 2>&1
$SETTIME -s -S $CSK1 -i 0 $CSK2 > settime.out.$zone.3 2>&1
$SETTIME -s -P $TpubN1 -A $TactN1 -I $TretN1 -g $O -k $O $TsbmN1 -r $O $TsbmN1 -d $O $TdeaN -z $R $TsbmN1 $CSK2 > settime.out.$zone.1 2>&1
cat template.db.in "${CSK1}.key" "${CSK2}.key" > "$infile"
private_type_record $zone 13 $CSK1 >> "$infile"
private_type_record $zone 13 $CSK2 >> "$infile"
$SIGNER -S -z -x -s now-1h -e now+30d -o $zone -O full -f $zonefile $infile > signer.out.$zone.1 2>&1
# Step 7:
# Some time later the predecessor DNSKEY enters the HIDDEN state.
setup step7.csk-roll.autosign
CSK1=`$KEYGEN -k csk-roll -l policies/autosign.conf $zone 2> keygen.out.$zone.1`
CSK2=`$KEYGEN -k csk-roll -l policies/autosign.conf $zone 2> keygen.out.$zone.1`
# Substract DNSKEY TTL plus zone propagation delay from all the times (2h).
TactN="now-5093h"
TretN="now-629h"
TdeaN="now-625h"
TpubN1="now-632h"
TsbmN1="now-629h"
TactN1="${TretN}"
TretN1="now+3835h"
$SETTIME -s -P $TactN -A $TactN -I $TretN -g $H -k $U now-2h -r $H $TdeaN -d $H $TdeaN -z $H $TsbmN1 $CSK1 > settime.out.$zone.1 2>&1
$SETTIME -s -S $CSK1 -i 0 $CSK2 > settime.out.$zone.3 2>&1
$SETTIME -s -P $TpubN1 -A $TactN1 -I $TretN1 -g $O -k $O $TsbmN1 -r $O $TsbmN1 -d $O $TdeaN -z $O $TsbmN1 $CSK2 > settime.out.$zone.1 2>&1
cat template.db.in "${CSK1}.key" "${CSK2}.key" > "$infile"
private_type_record $zone 13 $CSK1 >> "$infile"
private_type_record $zone 13 $CSK2 >> "$infile"
$SIGNER -S -z -x -s now-1h -e now+30d -o $zone -O full -f $zonefile $infile > signer.out.$zone.1 2>&1
#
# The zones at csk-roll2.autosign represent the various steps of a CSK rollover
# (which is essentially a ZSK Pre-Publication / KSK Double-KSK rollover).
# This scenario differs from the above one because the zone signatures (ZRRSIG)
# are replaced with the new key sooner than the DS is swapped.
#
# Step 1:
# Introduce the first key. This will immediately be active.
setup step1.csk-roll2.autosign
CSK=`$KEYGEN -k csk-roll2 -l policies/autosign.conf $zone 2> keygen.out.$zone.1`
TactN="now"
$SETTIME -s -P $TactN -A $TactN -g $O -k $O $TactN -r $O $TactN -d $O $TactN -z $O $TactN $CSK > settime.out.$zone.1 2>&1
cat template.db.in "${CSK}.key" > "$infile"
private_type_record $zone 13 $CSK >> "$infile"
$SIGNER -S -z -x -s now-1h -e now+30d -o $zone -O full -f $zonefile $infile > signer.out.$zone.1 2>&1
# Step 2:
# It is time to introduce the new CSK.
setup step2.csk-roll2.autosign
CSK=`$KEYGEN -k csk-roll2 -l policies/autosign.conf $zone 2> keygen.out.$zone.1`
# According to RFC 7583: ZSK: Tpub(N+1) <= Tact(N) + Lzsk - Ipub
# According to RFC 7583: KSK: Tpub(N+1) <= Tact(N) + Lksk - Dreg - IpubC
# Also: Ipub = Dprp + TTLkey (+publish-safety)
# Also: IpubC = DprpC + TTLkey (+publish-safety)
# Both sums are almost the same, but the KSK case has Dreg in the equation.
# so: Tact(N) = Tpub(N+1) - Lcsk + Dreg + IpubC = now - 6mo + 1w + 3h =
# now - 4464h + 168h + 3h = now - 4635h
TactN="now-4635h"
$SETTIME -s -P $TactN -A $TactN -g $O -k $O $TactN -r $O $TactN -d $O $TactN -z $O $TactN $CSK > settime.out.$zone.1 2>&1
cat template.db.in "${CSK}.key" > "$infile"
private_type_record $zone 13 $CSK >> "$infile"
$SIGNER -S -z -x -s now-1h -e now+30d -o $zone -O full -f $zonefile $infile > signer.out.$zone.1 2>&1
# Step 3:
# It is time to submit the DS and to roll signatures.
setup step3.csk-roll2.autosign
CSK1=`$KEYGEN -k csk-roll2 -l policies/autosign.conf $zone 2> keygen.out.$zone.1`
CSK2=`$KEYGEN -k csk-roll2 -l policies/autosign.conf $zone 2> keygen.out.$zone.1`
# According to RFC 7583: Tsbm(N+1) >= Trdy(N+1)
# Also: Tact(N+1) = Tsbm(N+1) + Dreg
# so: Tact(N) = Tsbm(N+1) + Dreg - Lksk = now + 1w - 6mo = now - 179d
# and: Tret(N) = Tsbm(N+1) + Dreg = now + 1w
# and: Tpub(N+1) <= Tsbm(N+1) - IpubC = now - 3h
# and: Tret(N+1) = Tsbm(N+1) + Dreg + Lksk = now + 1w + 6mo = now + 193d
TactN="now-179d"
TretN="now+1w"
TpubN1="now-3h"
TretN1="now+193d"
$SETTIME -s -P $TactN -A $TactN -I $TretN -g $H -k $O $TactN -r $O $TactN -d $O $TactN -z $O $TactN $CSK1 > settime.out.$zone.1 2>&1
$SETTIME -s -S $CSK1 -i 0 $CSK2 > settime.out.$zone.3 2>&1
$SETTIME -s -P $TpubN1 -A $TretN -I $TretN1 -g $O -k $R $TpubN1 -r $R $TpubN1 -d $H $TpubN1 -z $H $TpubN1 $CSK2 > settime.out.$zone.1 2>&1
cat template.db.in "${CSK1}.key" "${CSK2}.key" > "$infile"
private_type_record $zone 13 $CSK1 >> "$infile"
private_type_record $zone 13 $CSK2 >> "$infile"
$SIGNER -S -z -x -s now-1h -e now+30d -o $zone -O full -f $zonefile $infile > signer.out.$zone.1 2>&1
# Step 4:
# Some time later all the ZRRSIG records should be from the new CSK, and the
# DS should be swapped. The ZRRSIG records are all replaced after Iret
# which is Dsgn + Dprp + TTLsig + retire-safety (12h + 1h + 1d + 2h = 38h).
# The DS is swapped after Dreg + DprpP + TTLds + retire-safety
# (1w + 1h + 1h + 1h = 1w3h). In other words, the zone signatures are
# replaced before the DS is swapped.
setup step4.csk-roll2.autosign
CSK1=`$KEYGEN -k csk-roll2 -l policies/autosign.conf $zone 2> keygen.out.$zone.1`
CSK2=`$KEYGEN -k csk-roll2 -l policies/autosign.conf $zone 2> keygen.out.$zone.1`
# According to RFC 7583: Tdea(N) = Tret(N) + Iret
# Also: Tret(N) = Tact(N) + Lzsk
# Also: Iret = Dsgn + Dprp + TTLsig (+retire-safety)
# so: Tact(N) = Tdea(N) - Iret - Lzsk = now - 38h - 6mo = now - 4502h
# and: Tret(N) = Tdea(N) - Iret = now - 38h
# and: Tpub(N+1) = Tdea(N) - Iret - Ipub = now - 41h
# and: Tact(N+1) = Tdea(N) - Iret = Tret(N)
# and: Tret(N+1) = Tdea(N) - Iret + Lzsk = now - 38h + 6mo = now + 4426h
TactN="now-4502h"
TretN="now-38h"
TpubN1="now-41h"
TactN1="${TretN}"
TretN1="now+4426"
$SETTIME -s -P $TactN -A $TactN -I $TretN -g $H -k $O $TactN -r $O $TactN -d $U $TretN -z $U $TretN $CSK1 > settime.out.$zone.1 2>&1
$SETTIME -s -S $CSK1 -i 0 $CSK2 > settime.out.$zone.3 2>&1
$SETTIME -s -P $TpubN1 -A $TactN1 -I $TretN1 -g $O -k $O $TretN -r $O $TretN -d $R $TretN -z $R $TretN $CSK2 > settime.out.$zone.1 2>&1
cat template.db.in "${CSK1}.key" "${CSK2}.key" > "$infile"
private_type_record $zone 13 $CSK1 >> "$infile"
private_type_record $zone 13 $CSK2 >> "$infile"
$SIGNER -S -z -x -s now-1h -e now+30d -o $zone -O full -f $zonefile $infile > signer.out.$zone.1 2>&1
# Step 5:
# Some time later the DS can be swapped and the old DNSKEY can be removed from
# the zone.
setup step5.csk-roll2.autosign
CSK1=`$KEYGEN -k csk-roll2 -l policies/autosign.conf $zone 2> keygen.out.$zone.1`
CSK2=`$KEYGEN -k csk-roll2 -l policies/autosign.conf $zone 2> keygen.out.$zone.1`
# Substract Dreg + Iret (174h).
TactN="now-4676h"
TretN="now-212h"
TpubN1="now-215h"
TactN1="${TretN}"
TretN1="now+4252h"
$SETTIME -s -P $TactN -A $TactN -I $TretN -g $H -k $O $TactN -r $O $TactN -d $U $TretN -z $H $TretN $CSK1 > settime.out.$zone.1 2>&1
$SETTIME -s -S $CSK1 -i 0 $CSK2 > settime.out.$zone.3 2>&1
$SETTIME -s -P $TpubN1 -A $TactN1 -I $TretN1 -g $O -k $O $TretN -r $O $TretN -d $R $TretN -z $O $TretN $CSK2 > settime.out.$zone.1 2>&1
cat template.db.in "${CSK1}.key" "${CSK2}.key" > "$infile"
private_type_record $zone 13 $CSK1 >> "$infile"
private_type_record $zone 13 $CSK2 >> "$infile"
$SIGNER -S -z -x -s now-1h -e now+30d -o $zone -O full -f $zonefile $infile > signer.out.$zone.1 2>&1
# Step 6:
# Some time later the predecessor DNSKEY enters the HIDDEN state.
setup step6.csk-roll2.autosign
CSK1=`$KEYGEN -k csk-roll2 -l policies/autosign.conf $zone 2> keygen.out.$zone.1`
CSK2=`$KEYGEN -k csk-roll2 -l policies/autosign.conf $zone 2> keygen.out.$zone.1`
# Substract DNSKEY TTL plus zone propagation delay (2h).
TactN="now-4678h"
TretN="now-214h"
TdeaN="now-2h"
TpubN1="now-217h"
TactN1="${TretN}"
TretN1="now+4250h"
$SETTIME -s -P $TactN -A $TactN -I $TretN -g $H -k $U $TdeaN -r $U $TdeaN -d $H $TretN -z $H $TretN $CSK1 > settime.out.$zone.1 2>&1
$SETTIME -s -S $CSK1 -i 0 $CSK2 > settime.out.$zone.3 2>&1
$SETTIME -s -P $TpubN1 -A $TactN1 -I $TretN1 -g $O -k $O $TretN -r $O $TretN -d $O $TretN -z $O $TretN $CSK2 > settime.out.$zone.1 2>&1
cat template.db.in "${CSK1}.key" "${CSK2}.key" > "$infile"
private_type_record $zone 13 $CSK1 >> "$infile"
private_type_record $zone 13 $CSK2 >> "$infile"
$SIGNER -S -z -x -s now-1h -e now+30d -o $zone -O full -f $zonefile $infile > signer.out.$zone.1 2>&1

View file

@ -0,0 +1,25 @@
; Copyright (C) Internet Systems Consortium, Inc. ("ISC")
;
; 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 http://mozilla.org/MPL/2.0/.
;
; See the COPYRIGHT file distributed with this work for additional
; information regarding copyright ownership.
$TTL 300
@ IN SOA mname1. . (
1 ; serial
20 ; refresh (20 seconds)
20 ; retry (20 seconds)
1814400 ; expire (3 weeks)
3600 ; minimum (1 hour)
)
NS ns3
ns3 A 10.53.0.3
a A 10.0.0.1
b A 10.0.0.2
c A 10.0.0.3

View file

@ -0,0 +1,25 @@
; Copyright (C) Internet Systems Consortium, Inc. ("ISC")
;
; 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 http://mozilla.org/MPL/2.0/.
;
; See the COPYRIGHT file distributed with this work for additional
; information regarding copyright ownership.
$TTL 300
@ IN SOA mname1. . (
2 ; serial
20 ; refresh (20 seconds)
20 ; retry (20 seconds)
1814400 ; expire (3 weeks)
3600 ; minimum (1 hour)
)
NS ns3
ns3 A 10.53.0.3
a A 10.0.0.11
b A 10.0.0.2
c A 10.0.0.3
d A 10.0.0.4

View file

@ -0,0 +1,117 @@
/*
* Copyright (C) Internet Systems Consortium, Inc. ("ISC")
*
* 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 http://mozilla.org/MPL/2.0/.
*
* See the COPYRIGHT file distributed with this work for additional
* information regarding copyright ownership.
*/
// NS4
key "sha1" {
algorithm "hmac-sha1";
secret "FrSt77yPTFx6hTs4i2tKLB9LmE0=";
};
key "sha224" {
algorithm "hmac-sha224";
secret "hXfwwwiag2QGqblopofai9NuW28q/1rH4CaTnA==";
};
key "sha256" {
algorithm "hmac-sha256";
secret "R16NojROxtxH/xbDl//ehDsHm5DjWTQ2YXV+hGC2iBY=";
};
dnssec-policy "test" {
keys {
csk key-directory lifetime 0 algorithm 14;
};
};
options {
query-source address 10.53.0.4;
port @PORT@;
pid-file "named.pid";
listen-on { 10.53.0.4; };
listen-on-v6 { none; };
recursion no;
dnssec-policy "test";
};
view "inherit" {
match-clients { key "sha1"; };
/* Inherit dnssec-policy 'test' */
zone "inherit.inherit.signed" {
type master;
file "inherit.inherit.signed.db";
};
/* Override dnssec-policy */
zone "override.inherit.signed" {
type master;
dnssec-policy "default";
file "override.inherit.signed.db";
};
/* Unset dnssec-policy */
zone "none.inherit.signed" {
type master;
dnssec-policy "none";
file "none.inherit.signed.db";
};
};
view "override" {
match-clients { key "sha224"; };
dnssec-policy "default";
/* Inherit dnssec-policy 'test' */
zone "inherit.override.signed" {
type master;
file "inherit.override.signed.db";
};
/* Override dnssec-policy */
zone "override.override.signed" {
type master;
dnssec-policy "test";
file "override.override.signed.db";
};
/* Unset dnssec-policy */
zone "none.override.signed" {
type master;
dnssec-policy "none";
file "none.override.signed.db";
};
};
view "none" {
match-clients { key "sha256"; };
dnssec-policy "none";
/* Inherit dnssec-policy 'none' */
zone "inherit.none.signed" {
type master;
file "inherit.none.signed.db";
};
/* Override dnssec-policy */
zone "override.none.signed" {
type master;
dnssec-policy "test";
file "override.none.signed.db";
};
/* Unset dnssec-policy */
zone "none.none.signed" {
type master;
dnssec-policy "none";
file "none.none.signed.db";
};
};

View file

@ -0,0 +1,28 @@
#!/bin/sh -e
#
# Copyright (C) Internet Systems Consortium, Inc. ("ISC")
#
# 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 http://mozilla.org/MPL/2.0/.
#
# See the COPYRIGHT file distributed with this work for additional
# information regarding copyright ownership.
# shellcheck source=conf.sh
. "$SYSTEMTESTTOP/conf.sh"
echo_i "ns4/setup.sh"
#
# Set up zones that potentially will be initially signed.
#
for zn in inherit.inherit override.inherit none.inherit \
inherit.override override.override none.override \
inherit.none override.none none.none
do
zone="$zn.signed"
echo_i "setting up zone: $zone"
zonefile="${zone}.db"
cp template.db.in $zonefile
done

View file

@ -0,0 +1,25 @@
; Copyright (C) Internet Systems Consortium, Inc. ("ISC")
;
; 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 http://mozilla.org/MPL/2.0/.
;
; See the COPYRIGHT file distributed with this work for additional
; information regarding copyright ownership.
$TTL 300
@ IN SOA mname1. . (
1 ; serial
20 ; refresh (20 seconds)
20 ; retry (20 seconds)
1814400 ; expire (3 weeks)
3600 ; minimum (1 hour)
)
NS ns4
ns4 A 10.53.0.4
a A 10.0.0.1
b A 10.0.0.2
c A 10.0.0.3

View file

@ -0,0 +1,117 @@
/*
* Copyright (C) Internet Systems Consortium, Inc. ("ISC")
*
* 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 http://mozilla.org/MPL/2.0/.
*
* See the COPYRIGHT file distributed with this work for additional
* information regarding copyright ownership.
*/
// NS5
key "sha1" {
algorithm "hmac-sha1";
secret "FrSt77yPTFx6hTs4i2tKLB9LmE0=";
};
key "sha224" {
algorithm "hmac-sha224";
secret "hXfwwwiag2QGqblopofai9NuW28q/1rH4CaTnA==";
};
key "sha256" {
algorithm "hmac-sha256";
secret "R16NojROxtxH/xbDl//ehDsHm5DjWTQ2YXV+hGC2iBY=";
};
dnssec-policy "test" {
keys {
csk key-directory lifetime 0 algorithm 14;
};
};
options {
query-source address 10.53.0.5;
port @PORT@;
pid-file "named.pid";
listen-on { 10.53.0.5; };
listen-on-v6 { none; };
recursion no;
dnssec-policy "none";
};
view "inherit" {
match-clients { key "sha1"; };
/* Inherit dnssec-policy 'none' */
zone "inherit.inherit.unsigned" {
type master;
file "inherit.inherit.unsigned.db";
};
/* Override dnssec-policy */
zone "override.inherit.unsigned" {
type master;
dnssec-policy "default";
file "override.inherit.unsigned.db";
};
/* Unset dnssec-policy */
zone "none.inherit.unsigned" {
type master;
dnssec-policy "none";
file "none.inherit.unsigned.db";
};
};
view "override" {
match-clients { key "sha224"; };
dnssec-policy "default";
/* Inherit dnssec-policy 'default' */
zone "inherit.override.unsigned" {
type master;
file "inherit.override.unsigned.db";
};
/* Override dnssec-policy */
zone "override.override.unsigned" {
type master;
dnssec-policy "test";
file "override.override.unsigned.db";
};
/* Unset dnssec-policy */
zone "none.override.unsigned" {
type master;
dnssec-policy "none";
file "none.override.unsigned.db";
};
};
view "none" {
match-clients { key "sha256"; };
dnssec-policy "none";
/* Inherit dnssec-policy 'none' */
zone "inherit.none.unsigned" {
type master;
file "inherit.none.unsigned.db";
};
/* Override dnssec-policy */
zone "override.none.unsigned" {
type master;
dnssec-policy "test";
file "override.none.unsigned.db";
};
/* Unset dnssec-policy */
zone "none.none.unsigned" {
type master;
dnssec-policy "none";
file "none.none.unsigned.db";
};
};

View file

@ -0,0 +1,28 @@
#!/bin/sh -e
#
# Copyright (C) Internet Systems Consortium, Inc. ("ISC")
#
# 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 http://mozilla.org/MPL/2.0/.
#
# See the COPYRIGHT file distributed with this work for additional
# information regarding copyright ownership.
# shellcheck source=conf.sh
. "$SYSTEMTESTTOP/conf.sh"
echo_i "ns5/setup.sh"
#
# Set up zones that potentially will be initially signed.
#
for zn in inherit.inherit override.inherit none.inherit \
inherit.override override.override none.override \
inherit.none override.none none.none
do
zone="$zn.unsigned"
echo_i "setting up zone: $zone"
zonefile="${zone}.db"
cp template.db.in $zonefile
done

View file

@ -0,0 +1,25 @@
; Copyright (C) Internet Systems Consortium, Inc. ("ISC")
;
; 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 http://mozilla.org/MPL/2.0/.
;
; See the COPYRIGHT file distributed with this work for additional
; information regarding copyright ownership.
$TTL 300
@ IN SOA mname1. . (
1 ; serial
20 ; refresh (20 seconds)
20 ; retry (20 seconds)
1814400 ; expire (3 weeks)
3600 ; minimum (1 hour)
)
NS ns5
ns5 A 10.53.0.5
a A 10.0.0.1
b A 10.0.0.2
c A 10.0.0.3

View file

@ -0,0 +1,42 @@
#!/bin/sh -e
#
# Copyright (C) Internet Systems Consortium, Inc. ("ISC")
#
# 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 http://mozilla.org/MPL/2.0/.
#
# See the COPYRIGHT file distributed with this work for additional
# information regarding copyright ownership.
# shellcheck source=conf.sh
. "$SYSTEMTESTTOP/conf.sh"
set -e
$SHELL clean.sh
mkdir keys
copy_setports ns2/named.conf.in ns2/named.conf
copy_setports ns3/named.conf.in ns3/named.conf
copy_setports ns4/named.conf.in ns4/named.conf
copy_setports ns5/named.conf.in ns5/named.conf
# Setup zones
(
cd ns2
$SHELL setup.sh
)
(
cd ns3
$SHELL setup.sh
)
(
cd ns4
$SHELL setup.sh
)
(
cd ns5
$SHELL setup.sh
)

File diff suppressed because it is too large Load diff

View file

@ -3120,6 +3120,16 @@ $ORIGIN 0.0.0.0.0.0.0.0.8.b.d.0.1.0.0.2.ip6.arpa.
</para>
</entry>
</row>
<row rowsep="0">
<entry colname="1">
<para><command>dnssec-policy</command></para>
</entry>
<entry colname="2">
<para>
describes a DNSSEC key and signing policy for zones.
</para>
</entry>
</row>
<row rowsep="0">
<entry colname="1">
<para><command>include</command></para>
@ -11004,6 +11014,224 @@ example.com CNAME rpz-tcp-only.
</para>
</section>
<section xml:id="dnssec_policy_grammar"><info><title><command>dnssec-policy</command> Statement Grammar</title></info>
<xi:include xmlns:xi="http://www.w3.org/2001/XInclude" href="dnssec-policy.grammar.xml"/>
</section>
<section xml:id="dnssec_policy"><info><title><command>dnssec-policy</command> Statement Definition
and Usage</title></info>
<para>
The <command>dnssec-policy</command> statement defines a key and
signing policy (KASP) for zones.
</para>
<para>
KASP is used to determine how one or more zones need to be signed
with DNSSEC. For example, how often RRSIG records need to be
refreshed, or what cryptographic algorithms to use.
</para>
<para>
You can configure multiple policies. To attach a policy to a zone
simply add <userinput>dnssec-policy "policy_name"</userinput>
option to the <command>zone</command> statement with a matching
policy name.
</para>
<variablelist>
<varlistentry>
<term><command>dnskey-ttl</command></term>
<listitem>
<para>
The TTL of the DNSKEY resource records.
Default is <constant>3600</constant> seconds.
</para>
</listitem>
</varlistentry>
<varlistentry>
<term><command>keys</command></term>
<listitem>
<para>
A list of keys to use. Each line represents one key. Here is
an example (for illustration purposes only) of some possible
keys in a <command>dnssec-policy</command>:
</para>
<programlisting>keys {
ksk key-directory lifetime P5Y algorithm 8 2048;
zsk key-directory lifetime P30D algorithm 8;
csk key-directory lifetime P6MT12H3M15S algorithm 13;
};
</programlisting>
<para>
This example lists three keys. The first token determines
what RRsets the key will sign. If set to
<userinput>ksk</userinput> the key will sign the DNSKEY, CDS,
and CDNSKEY RRsets, if set to <userinput>zsk</userinput> the
key will sign the other RRsets, and if set to
<userinput>csk</userinput> the key will sign all RRsets.
</para>
<para>
The following part determines where the key will be stored.
Currently keys can only be stored in the configured
<command>key-directory</command>.
</para>
<para>
The third token tells how long the key may be used. In the
example the first key has a lifetime of 5 years, the second
key may be used for 30 days and the third key has a rather
peculiar lifetime of 6 months, 12 hours, 3 minutes and 15
seconds.
</para>
<para>
The last token(s) are the key's algorithm and algorithm length.
The length may be omitted as shown in the example for the
second and third key.
</para>
</listitem>
</varlistentry>
<varlistentry>
<term><command>publish-safety</command></term>
<listitem>
<para>
A margin that is added to the publish interval in key timing
equations to give some extra time to cover unforeseen events.
Default is <constant>PT5M</constant> (5 minutes).
</para>
</listitem>
</varlistentry>
<varlistentry>
<term><command>retire-safety</command></term>
<listitem>
<para>
A margin that is added to the retire interval in key timing
equations to give some extra time to cover unforeseen events.
Default is <constant>PT5M</constant> (5 minutes).
</para>
</listitem>
</varlistentry>
<varlistentry>
<term><command>signatures-refresh</command></term>
<listitem>
<para>
This determines when a RRSIG record needs to be refreshed.
The signatures is renewed when the time until the expiration
time is closer than <command>signatures-refresh</command>.
<command>signatures-resign</command> interval.
Default is <constant>P5D</constant> (5 days), meaning a
signature that will expire in 5 days or sooner will be
refreshed.
</para>
</listitem>
</varlistentry>
<varlistentry>
<term><command>signatures-validity</command></term>
<listitem>
<para>
The validity period of an RRSIG record (minus the inception
offset and jitter). Default is <constant>P2W</constant>
(2 weeks).
</para>
</listitem>
</varlistentry>
<varlistentry>
<term><command>signatures-validity-dnskey</command></term>
<listitem>
<para>
Like <command>signatures-validity</command> but for DNSKEY
records. Default is <constant>P2W</constant> (2 weeks).
</para>
</listitem>
</varlistentry>
<varlistentry>
<term><command>zone-max-ttl</command></term>
<listitem>
<para>
Like <command>max-zone-ttl</command>, specifies the maximum
permissible TTL value in seconds. When loading a zone file
using a <option>masterfile-format</option> or
<constant>text</constant> or <constant>raw</constant>,
any record encountered with a TTL higher than
<option>zone-max-ttl</option> will be capped to the maximum
permissible TTL value.
</para>
<para>
This is needed in DNSSEC-maintained zones because when
rolling to a new DNSKEY, the old key needs to remain
available until RRSIG records have expired from
caches. The <option>zone-max-ttl</option> option guarantees
that the largest TTL in the zone will be no higher than the
set value.
</para>
<para>
(NOTE: Because <constant>map</constant>-format files
load directly into memory, this option cannot be
used with them.)
</para>
<para>
The default value is <constant>PT24H</constant> (24 hours).
A <option>zone-max-ttl</option> of zero is treated as if
the default value is in use.
</para>
</listitem>
</varlistentry>
<varlistentry>
<term><command>zone-propagation-delay</command></term>
<listitem>
<para>
The expected propagation delay from when a zone is updated
and when the new version of the zone is served by all its
name servers. Default is <constant>PT5M</constant> (5 minutes).
</para>
</listitem>
</varlistentry>
<varlistentry>
<term><command>parent-ds-ttl</command></term>
<listitem>
<para>
The TTL of the DS RRset that the parent uses. Default is
<constant>PT1H</constant> (1 hour).
</para>
</listitem>
</varlistentry>
<varlistentry>
<term><command>parent-propagation-delay</command></term>
<listitem>
<para>
The expected propagation delay from when the parent zone is
updated and when the new version of the parent zone is served
by all its name servers. Default is
<constant>PT1H</constant> (1 hour).
</para>
</listitem>
</varlistentry>
<varlistentry>
<term><command>parent-registration-delay</command></term>
<listitem>
<para>
The expected registration delay from when a DS RRset change
is requested and when the DS RRset has been updated in the
parent zone. Default is <constant>P1D</constant> (1 day).
</para>
</listitem>
</varlistentry>
</variablelist>
</section>
<section xml:id="managed-keys"><info><title><command>managed-keys</command> Statement Grammar</title></info>
<xi:include xmlns:xi="http://www.w3.org/2001/XInclude" href="managed-keys.grammar.xml"/>
</section>
@ -11878,6 +12106,17 @@ view "external" {
</listitem>
</varlistentry>
<varlistentry>
<term><command>dnssec-policy</command></term>
<listitem>
<para>
The key and signing policy for this zone. Set to
<userinput>"default"</userinput> if you want to make use
of the default policy.
</para>
</listitem>
</varlistentry>
<varlistentry>
<term><command>dnssec-update-mode</command></term>
<listitem>

View file

@ -0,0 +1,30 @@
<!--
- Copyright (C) Internet Systems Consortium, Inc. ("ISC")
-
- 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 http://mozilla.org/MPL/2.0/.
-
- See the COPYRIGHT file distributed with this work for additional
- information regarding copyright ownership.
-->
<!-- Generated by doc/misc/docbook-options.pl -->
<programlisting>
<command>dnssec-policy</command> <replaceable>string</replaceable> {
<command>dnskey-ttl</command> <replaceable>ttlval</replaceable>;
<command>keys</command> { ( csk | ksk | zsk ) key-directory <replaceable>duration</replaceable> <replaceable>integer</replaceable> [ <replaceable>integer</replaceable> ] ; ... };
<command>parent-ds-ttl</command> <replaceable>duration</replaceable>;
<command>parent-propagation-delay</command> <replaceable>duration</replaceable>;
<command>parent-registration-delay</command> <replaceable>duration</replaceable>;
<command>publish-safety</command> <replaceable>duration</replaceable>;
<command>retire-safety</command> <replaceable>duration</replaceable>;
<command>signatures-refresh</command> <replaceable>duration</replaceable>;
<command>signatures-validity</command> <replaceable>duration</replaceable>;
<command>signatures-validity-dnskey</command> <replaceable>duration</replaceable>;
<command>zone-max-ttl</command> <replaceable>duration</replaceable>;
<command>zone-propagation-delay</command> <replaceable>duration</replaceable>;
};
</programlisting>

View file

@ -15,30 +15,50 @@
<section><info><title>Converting from insecure to secure</title></info>
</section>
<para>Changing a zone from insecure to secure can be done in two
ways: using a dynamic DNS update, or the
<command>auto-dnssec</command> zone option.</para>
<para>For either method, you need to configure
<command>named</command> so that it can see the
<filename>K*</filename> files which contain the public and private
parts of the keys that will be used to sign the zone. These files
will have been generated by
<command>dnssec-keygen</command>. You can do this by placing them
in the key-directory, as specified in
<filename>named.conf</filename>:</para>
<programlisting>
<para>
Changing a zone from insecure to secure can be done in three
ways: using a dynamic DNS update, use the
<command>auto-dnssec</command> zone option, or set a DNSSEC
policy for the zone with <command>dnssec-policy</command>.
</para>
<para>
For either method, you need to configure
<command>named</command> so that it can see the
<filename>K*</filename> files which contain the public and private
parts of the keys that will be used to sign the zone. These files
will have been generated by
<command>dnssec-keygen</command> (or created when needed by
<command>named</command> if <command>dnssec-policy</command> is
used). Keys should be placed in the key-directory, as specified in
<filename>named.conf</filename>:</para>
<programlisting>
zone example.net {
type master;
update-policy local;
file "dynamic/example.net/example.net";
key-directory "dynamic/example.net";
};
</programlisting>
<para>If one KSK and one ZSK DNSKEY key have been generated, this
configuration will cause all records in the zone to be signed
with the ZSK, and the DNSKEY RRset to be signed with the KSK as
well. An NSEC chain will be generated as part of the initial
signing process.</para>
</programlisting>
<para>
If one KSK and one ZSK DNSKEY key have been generated, this
configuration will cause all records in the zone to be signed
with the ZSK, and the DNSKEY RRset to be signed with the KSK as
well. An NSEC chain will be generated as part of the initial
signing process.
</para>
<para>
With <command>dnssec-policy</command> you specify what keys should
be KSK and/or ZSK. If you want a key to sign all records with a key
you will need to specify a CSK:
</para>
<programlisting>
dnssec-policy csk {
keys {
csk key-directory lifetime P5Y algorithm 13;
};
};
</programlisting>
<section><info><title>Dynamic DNS update method</title></info>
</section>
@ -50,16 +70,20 @@
&gt; update add example.net DNSKEY 257 3 7 AwEAAd/7odU/64o2LGsifbLtQmtO8dFDtTAZXSX2+X3e/UNlq9IHq3Y0 XtC0Iuawl/qkaKVxXe2lo8Ct+dM6UehyCqk=
&gt; send
</screen>
<para>While the update request will complete almost immediately,
the zone will not be completely signed until
<command>named</command> has had time to walk the zone and
generate the NSEC and RRSIG records. The NSEC record at the apex
will be added last, to signal that there is a complete NSEC
chain.</para>
<para>If you wish to sign using NSEC3 instead of NSEC, you should
add an NSEC3PARAM record to the initial update request. If you
wish the NSEC3 chain to have the OPTOUT bit set, set it in the
flags field of the NSEC3PARAM record.</para>
<para>
While the update request will complete almost immediately,
the zone will not be completely signed until
<command>named</command> has had time to walk the zone and
generate the NSEC and RRSIG records. The NSEC record at the apex
will be added last, to signal that there is a complete NSEC
chain.
</para>
<para>
If you wish to sign using NSEC3 instead of NSEC, you should
add an NSEC3PARAM record to the initial update request. If you
wish the NSEC3 chain to have the OPTOUT bit set, set it in the
flags field of the NSEC3PARAM record.
</para>
<screen>
% nsupdate
&gt; ttl 3600
@ -68,90 +92,113 @@
&gt; update add example.net NSEC3PARAM 1 1 100 1234567890
&gt; send
</screen>
<para>Again, this update request will complete almost
immediately; however, the record won't show up until
<command>named</command> has had a chance to build/remove the
relevant chain. A private type record will be created to record
the state of the operation (see below for more details), and will
be removed once the operation completes.</para>
<para>While the initial signing and NSEC/NSEC3 chain generation
is happening, other updates are possible as well.</para>
<para>
Again, this update request will complete almost
immediately; however, the record won't show up until
<command>named</command> has had a chance to build/remove the
relevant chain. A private type record will be created to record
the state of the operation (see below for more details), and will
be removed once the operation completes.
</para>
<para>
While the initial signing and NSEC/NSEC3 chain generation
is happening, other updates are possible as well.
</para>
<section><info><title>Fully automatic zone signing</title></info>
</section>
<para>To enable automatic signing, add the
<command>auto-dnssec</command> option to the zone statement in
<filename>named.conf</filename>.
<command>auto-dnssec</command> has two possible arguments:
<constant>allow</constant> or
<constant>maintain</constant>.</para>
<para>With
<command>auto-dnssec allow</command>,
<command>named</command> can search the key directory for keys
matching the zone, insert them into the zone, and use them to
sign the zone. It will do so only when it receives an
<command>rndc sign &lt;zonename&gt;</command>.</para>
<para>
<!-- TODO: this is repeated in the ARM -->
<command>auto-dnssec maintain</command> includes the above
functionality, but will also automatically adjust the zone's
DNSKEY records on schedule according to the keys' timing metadata.
(See <xref linkend="man.dnssec-keygen"/> and
<xref linkend="man.dnssec-settime"/> for more information.)
To enable automatic signing, you can set a
<command>dnssec-policy</command>, or add the
<command>auto-dnssec</command> option to the zone statement in
<filename>named.conf</filename>.
<command>auto-dnssec</command> has two possible arguments:
<constant>allow</constant> or
<constant>maintain</constant>.
</para>
<para>
<command>named</command> will periodically search the key directory
for keys matching the zone, and if the keys' metadata indicates
that any change should be made the zone, such as adding, removing,
or revoking a key, then that action will be carried out. By default,
the key directory is checked for changes every 60 minutes; this period
can be adjusted with the <option>dnssec-loadkeys-interval</option>, up
to a maximum of 24 hours. The <command>rndc loadkeys</command> forces
<command>named</command> to check for key updates immediately.
With <command>auto-dnssec allow</command>,
<command>named</command> can search the key directory for keys
matching the zone, insert them into the zone, and use them to
sign the zone. It will do so only when it receives an
<command>rndc sign &lt;zonename&gt;</command>.
</para>
<para>
If keys are present in the key directory the first time the zone
is loaded, the zone will be signed immediately, without waiting for an
<command>rndc sign</command> or <command>rndc loadkeys</command>
command. (Those commands can still be used when there are unscheduled
key changes, however.)
<!-- TODO: this is repeated in the ARM -->
<command>auto-dnssec maintain</command> includes the above
functionality, but will also automatically adjust the zone's
DNSKEY records on schedule according to the keys' timing metadata.
(See <xref linkend="man.dnssec-keygen"/> and
<xref linkend="man.dnssec-settime"/> for more information.)
</para>
<para>
When new keys are added to a zone, the TTL is set to match that
of any existing DNSKEY RRset. If there is no existing DNSKEY RRset,
then the TTL will be set to the TTL specified when the key was
created (using the <command>dnssec-keygen -L</command> option), if
any, or to the SOA TTL.
<command>dnssec-policy</command> is like
<command>auto-dnssec maintain</command>, but will also automatically
create new keys when necessary. Also any configuration related
to DNSSEC signing is retrieved from the policy (ignoring existing
DNSSEC named.conf options).
</para>
<para>
If you wish the zone to be signed using NSEC3 instead of NSEC,
submit an NSEC3PARAM record via dynamic update prior to the
scheduled publication and activation of the keys. If you wish the
NSEC3 chain to have the OPTOUT bit set, set it in the flags field
of the NSEC3PARAM record. The NSEC3PARAM record will not appear in
the zone immediately, but it will be stored for later reference. When
the zone is signed and the NSEC3 chain is completed, the NSEC3PARAM
record will appear in the zone.
<command>named</command> will periodically search the key directory
for keys matching the zone, and if the keys' metadata indicates
that any change should be made the zone, such as adding, removing,
or revoking a key, then that action will be carried out. By default,
the key directory is checked for changes every 60 minutes; this period
can be adjusted with the <option>dnssec-loadkeys-interval</option>, up
to a maximum of 24 hours. The <command>rndc loadkeys</command> forces
<command>named</command> to check for key updates immediately.
</para>
<para>Using the
<command>auto-dnssec</command> option requires the zone to be
configured to allow dynamic updates, by adding an
<command>allow-update</command> or
<command>update-policy</command> statement to the zone
configuration. If this has not been done, the configuration will
fail.</para>
<para>
If keys are present in the key directory the first time the zone
is loaded, the zone will be signed immediately, without waiting for an
<command>rndc sign</command> or <command>rndc loadkeys</command>
command. (Those commands can still be used when there are unscheduled
key changes, however.)
</para>
<para>
When new keys are added to a zone, the TTL is set to match that
of any existing DNSKEY RRset. If there is no existing DNSKEY RRset,
then the TTL will be set to the TTL specified when the key was
created (using the <command>dnssec-keygen -L</command> option), if
any, or to the SOA TTL.
</para>
<para>
If you wish the zone to be signed using NSEC3 instead of NSEC,
submit an NSEC3PARAM record via dynamic update prior to the
scheduled publication and activation of the keys. If you wish the
NSEC3 chain to have the OPTOUT bit set, set it in the flags field
of the NSEC3PARAM record. The NSEC3PARAM record will not appear in
the zone immediately, but it will be stored for later reference. When
the zone is signed and the NSEC3 chain is completed, the NSEC3PARAM
record will appear in the zone.
</para>
<para>
Using the
<command>auto-dnssec</command> option requires the zone to be
configured to allow dynamic updates, by adding an
<command>allow-update</command> or
<command>update-policy</command> statement to the zone
configuration. If this has not been done, the configuration will
fail.
</para>
<section><info><title>Private-type records</title></info>
</section>
<para>The state of the signing process is signaled by
private-type records (with a default type value of 65534). When
signing is complete, these records will have a nonzero value for
the final octet (for those records which have a nonzero initial
octet).</para>
<para>The private type record format: If the first octet is
non-zero then the record indicates that the zone needs to be
signed with the key matching the record, or that all signatures
that match the record should be removed.</para>
<para>
The state of the signing process is signaled by
private-type records (with a default type value of 65534). When
signing is complete, these records will have a nonzero value for
the final octet (for those records which have a nonzero initial
octet).
</para>
<para>
The private type record format: If the first octet is
non-zero then the record indicates that the zone needs to be
signed with the key matching the record, or that all signatures
that match the record should be removed.
</para>
<para>
<literallayout>
<!-- TODO: how to format this? -->
@ -161,14 +208,18 @@
complete flag (octet 5)
</literallayout>
</para>
<para>Only records flagged as "complete" can be removed via
dynamic update. Attempts to remove other private type records
will be silently ignored.</para>
<para>If the first octet is zero (this is a reserved algorithm
number that should never appear in a DNSKEY record) then the
record indicates changes to the NSEC3 chains are in progress. The
rest of the record contains an NSEC3PARAM record. The flag field
tells what operation to perform based on the flag bits.</para>
<para>
Only records flagged as "complete" can be removed via
dynamic update. Attempts to remove other private type records
will be silently ignored.
</para>
<para>
If the first octet is zero (this is a reserved algorithm
number that should never appear in a DNSKEY record) then the
record indicates changes to the NSEC3 chains are in progress. The
rest of the record contains an NSEC3PARAM record. The flag field
tells what operation to perform based on the flag bits.
</para>
<para>
<literallayout>
<!-- TODO: how to format this? -->
@ -181,106 +232,139 @@
<section><info><title>DNSKEY rollovers</title></info>
</section>
<para>As with insecure-to-secure conversions, rolling DNSSEC
keys can be done in two ways: using a dynamic DNS update, or the
<command>auto-dnssec</command> zone option.</para>
<para>
As with insecure-to-secure conversions, rolling DNSSEC
keys can be done in two ways: using a dynamic DNS update, or the
<command>auto-dnssec</command> zone option.
</para>
<section><info><title>Dynamic DNS update method</title></info>
</section>
<para> To perform key rollovers via dynamic update, you need to add
the <filename>K*</filename> files for the new keys so that
<command>named</command> can find them. You can then add the new
DNSKEY RRs via dynamic update.
<command>named</command> will then cause the zone to be signed
with the new keys. When the signing is complete the private type
records will be updated so that the last octet is non
zero.</para>
<para>If this is for a KSK you need to inform the parent and any
trust anchor repositories of the new KSK.</para>
<para>You should then wait for the maximum TTL in the zone before
removing the old DNSKEY. If it is a KSK that is being updated,
you also need to wait for the DS RRset in the parent to be
updated and its TTL to expire. This ensures that all clients will
be able to verify at least one signature when you remove the old
DNSKEY.</para>
<para>The old DNSKEY can be removed via UPDATE. Take care to
specify the correct key.
<command>named</command> will clean out any signatures generated
by the old key after the update completes.</para>
<para>
To perform key rollovers via dynamic update, you need to add
the <filename>K*</filename> files for the new keys so that
<command>named</command> can find them. You can then add the new
DNSKEY RRs via dynamic update.
<command>named</command> will then cause the zone to be signed
with the new keys. When the signing is complete the private type
records will be updated so that the last octet is non
zero.
</para>
<para>
If this is for a KSK you need to inform the parent and any
trust anchor repositories of the new KSK.
</para>
<para>
You should then wait for the maximum TTL in the zone before
removing the old DNSKEY. If it is a KSK that is being updated,
you also need to wait for the DS RRset in the parent to be
updated and its TTL to expire. This ensures that all clients will
be able to verify at least one signature when you remove the old
DNSKEY.
</para>
<para>
The old DNSKEY can be removed via UPDATE. Take care to
specify the correct key.
<command>named</command> will clean out any signatures generated
by the old key after the update completes.
</para>
<section><info><title>Automatic key rollovers</title></info>
</section>
<para>When a new key reaches its activation date (as set by
<command>dnssec-keygen</command> or <command>dnssec-settime</command>),
if the <command>auto-dnssec</command> zone option is set to
<constant>maintain</constant>, <command>named</command> will
automatically carry out the key rollover. If the key's algorithm
has not previously been used to sign the zone, then the zone will
be fully signed as quickly as possible. However, if the new key
is replacing an existing key of the same algorithm, then the
zone will be re-signed incrementally, with signatures from the
old key being replaced with signatures from the new key as their
signature validity periods expire. By default, this rollover
completes in 30 days, after which it will be safe to remove the
old key from the DNSKEY RRset.</para>
<para>
When a new key reaches its activation date (as set by
<command>dnssec-keygen</command> or <command>dnssec-settime</command>),
if the <command>auto-dnssec</command> zone option is set to
<constant>maintain</constant>, <command>named</command> will
automatically carry out the key rollover. If the key's algorithm
has not previously been used to sign the zone, then the zone will
be fully signed as quickly as possible. However, if the new key
is replacing an existing key of the same algorithm, then the
zone will be re-signed incrementally, with signatures from the
old key being replaced with signatures from the new key as their
signature validity periods expire. By default, this rollover
completes in 30 days, after which it will be safe to remove the
old key from the DNSKEY RRset.
</para>
<section><info><title>NSEC3PARAM rollovers via UPDATE</title></info>
</section>
<para>Add the new NSEC3PARAM record via dynamic update. When the
new NSEC3 chain has been generated, the NSEC3PARAM flag field
will be zero. At this point you can remove the old NSEC3PARAM
record. The old chain will be removed after the update request
completes.</para>
<para>
Add the new NSEC3PARAM record via dynamic update. When the
new NSEC3 chain has been generated, the NSEC3PARAM flag field
will be zero. At this point you can remove the old NSEC3PARAM
record. The old chain will be removed after the update request
completes.
</para>
<section><info><title>Converting from NSEC to NSEC3</title></info>
</section>
<para>To do this, you just need to add an NSEC3PARAM record. When
the conversion is complete, the NSEC chain will have been removed
and the NSEC3PARAM record will have a zero flag field. The NSEC3
chain will be generated before the NSEC chain is
destroyed.</para>
<para>
To do this, you just need to add an NSEC3PARAM record. When
the conversion is complete, the NSEC chain will have been removed
and the NSEC3PARAM record will have a zero flag field. The NSEC3
chain will be generated before the NSEC chain is
destroyed.
</para>
<para>
NSEC3 is not supported yet with <command>dnssec-policy</command>.
</para>
<section><info><title>Converting from NSEC3 to NSEC</title></info>
</section>
<para>To do this, use <command>nsupdate</command> to
remove all NSEC3PARAM records with a zero flag
field. The NSEC chain will be generated before the NSEC3 chain is
removed.</para>
<para>
To do this, use <command>nsupdate</command> to
remove all NSEC3PARAM records with a zero flag
field. The NSEC chain will be generated before the NSEC3 chain is
removed.
</para>
<section><info><title>Converting from secure to insecure</title></info>
</section>
<para>To convert a signed zone to unsigned using dynamic DNS,
delete all the DNSKEY records from the zone apex using
<command>nsupdate</command>. All signatures, NSEC or NSEC3 chains,
and associated NSEC3PARAM records will be removed automatically.
This will take place after the update request completes.</para>
<para> This requires the
<command>dnssec-secure-to-insecure</command> option to be set to
<userinput>yes</userinput> in
<filename>named.conf</filename>.</para>
<para>In addition, if the <command>auto-dnssec maintain</command>
zone statement is used, it should be removed or changed to
<command>allow</command> instead (or it will re-sign).
<para>
To convert a signed zone to unsigned using dynamic DNS,
delete all the DNSKEY records from the zone apex using
<command>nsupdate</command>. All signatures, NSEC or NSEC3 chains,
and associated NSEC3PARAM records will be removed automatically.
This will take place after the update request completes.</para>
<para> This requires the
<command>dnssec-secure-to-insecure</command> option to be set to
<userinput>yes</userinput> in
<filename>named.conf</filename>.</para>
<para>In addition, if the <command>auto-dnssec maintain</command>
zone statement is used, it should be removed or changed to
<command>allow</command> instead (or it will re-sign).
</para>
<section><info><title>Periodic re-signing</title></info>
</section>
<para>In any secure zone which supports dynamic updates, <command>named</command>
will periodically re-sign RRsets which have not been re-signed as
a result of some update action. The signature lifetimes will be
adjusted so as to spread the re-sign load over time rather than
all at once.</para>
<para>
In any secure zone which supports dynamic updates, <command>named</command>
will periodically re-sign RRsets which have not been re-signed as
a result of some update action. The signature lifetimes will be
adjusted so as to spread the re-sign load over time rather than
all at once.
</para>
<section><info><title>NSEC3 and OPTOUT</title></info>
</section>
<para>
<command>named</command> only supports creating new NSEC3 chains
where all the NSEC3 records in the zone have the same OPTOUT
state.
<command>named</command> supports UPDATES to zones where the NSEC3
records in the chain have mixed OPTOUT state.
<command>named</command> does not support changing the OPTOUT
state of an individual NSEC3 record, the entire chain needs to be
changed if the OPTOUT state of an individual NSEC3 needs to be
changed.</para>
<command>named</command> only supports creating new NSEC3 chains
where all the NSEC3 records in the zone have the same OPTOUT
state.
<command>named</command> supports UPDATES to zones where the NSEC3
records in the chain have mixed OPTOUT state.
<command>named</command> does not support changing the OPTOUT
state of an individual NSEC3 record, the entire chain needs to be
changed if the OPTOUT state of an individual NSEC3 needs to be
changed.
</para>
</section>

View file

@ -36,6 +36,7 @@
<command>dnskey-sig-validity</command> <replaceable>integer</replaceable>;
<command>dnssec-dnskey-kskonly</command> <replaceable>boolean</replaceable>;
<command>dnssec-loadkeys-interval</command> <replaceable>integer</replaceable>;
<command>dnssec-policy</command> <replaceable>string</replaceable>;
<command>dnssec-secure-to-insecure</command> <replaceable>boolean</replaceable>;
<command>dnssec-update-mode</command> ( maintain | no-resign );
<command>file</command> <replaceable>quoted_string</replaceable>;
@ -51,7 +52,7 @@
<command>max-records</command> <replaceable>integer</replaceable>;
<command>max-transfer-idle-out</command> <replaceable>integer</replaceable>;
<command>max-transfer-time-out</command> <replaceable>integer</replaceable>;
<command>max-zone-ttl</command> ( unlimited | <replaceable>ttlval</replaceable> );
<command>max-zone-ttl</command> ( unlimited | <replaceable>duration</replaceable> );
<command>notify</command> ( explicit | master-only | <replaceable>boolean</replaceable> );
<command>notify-delay</command> <replaceable>integer</replaceable>;
<command>notify-source</command> ( <replaceable>ipv4_address</replaceable> | * ) [ port ( <replaceable>integer</replaceable> | * ) ] [ dscp <replaceable>integer</replaceable> ];

View file

@ -45,7 +45,7 @@
[ dscp <replaceable>integer</replaceable> ] { ( <replaceable>masters</replaceable> | <replaceable>ipv4_address</replaceable> [ port
<replaceable>integer</replaceable> ] | <replaceable>ipv6_address</replaceable> [ port <replaceable>integer</replaceable> ] ) [ key
<replaceable>string</replaceable> ]; ... } ] [ zone-directory <replaceable>quoted_string</replaceable> ] [
<command>in-memory</command> <replaceable>boolean</replaceable> ] [ min-update-interval <replaceable>ttlval</replaceable> ]; ... };
<command>in-memory</command> <replaceable>boolean</replaceable> ] [ min-update-interval <replaceable>duration</replaceable> ]; ... };
<command>check-dup-records</command> ( fail | warn | ignore );
<command>check-integrity</command> <replaceable>boolean</replaceable>;
<command>check-mx</command> ( fail | warn | ignore );
@ -127,18 +127,18 @@
<command>fstrm-set-output-notify-threshold</command> <replaceable>integer</replaceable>;
<command>fstrm-set-output-queue-model</command> ( mpsc | spsc );
<command>fstrm-set-output-queue-size</command> <replaceable>integer</replaceable>;
<command>fstrm-set-reopen-interval</command> <replaceable>ttlval</replaceable>;
<command>fstrm-set-reopen-interval</command> <replaceable>duration</replaceable>;
<command>geoip-directory</command> ( <replaceable>quoted_string</replaceable> | none );
<command>glue-cache</command> <replaceable>boolean</replaceable>;
<command>heartbeat-interval</command> <replaceable>integer</replaceable>;
<command>hostname</command> ( <replaceable>quoted_string</replaceable> | none );
<command>inline-signing</command> <replaceable>boolean</replaceable>;
<command>interface-interval</command> <replaceable>ttlval</replaceable>;
<command>interface-interval</command> <replaceable>duration</replaceable>;
<command>ixfr-from-differences</command> ( primary | master | secondary | slave |
<replaceable>boolean</replaceable> );
<command>keep-response-order</command> { <replaceable>address_match_element</replaceable>; ... };
<command>key-directory</command> <replaceable>quoted_string</replaceable>;
<command>lame-ttl</command> <replaceable>ttlval</replaceable>;
<command>lame-ttl</command> <replaceable>duration</replaceable>;
<command>listen-on</command> [ port <replaceable>integer</replaceable> ] [ dscp
<replaceable>integer</replaceable> ] {
<replaceable>address_match_element</replaceable>; ... };
@ -152,28 +152,28 @@
<command>masterfile-style</command> ( full | relative );
<command>match-mapped-addresses</command> <replaceable>boolean</replaceable>;
<command>max-cache-size</command> ( default | unlimited | <replaceable>sizeval</replaceable> | <replaceable>percentage</replaceable> );
<command>max-cache-ttl</command> <replaceable>ttlval</replaceable>;
<command>max-cache-ttl</command> <replaceable>duration</replaceable>;
<command>max-clients-per-query</command> <replaceable>integer</replaceable>;
<command>max-journal-size</command> ( default | unlimited | <replaceable>sizeval</replaceable> );
<command>max-ncache-ttl</command> <replaceable>ttlval</replaceable>;
<command>max-ncache-ttl</command> <replaceable>duration</replaceable>;
<command>max-records</command> <replaceable>integer</replaceable>;
<command>max-recursion-depth</command> <replaceable>integer</replaceable>;
<command>max-recursion-queries</command> <replaceable>integer</replaceable>;
<command>max-refresh-time</command> <replaceable>integer</replaceable>;
<command>max-retry-time</command> <replaceable>integer</replaceable>;
<command>max-rsa-exponent-size</command> <replaceable>integer</replaceable>;
<command>max-stale-ttl</command> <replaceable>ttlval</replaceable>;
<command>max-stale-ttl</command> <replaceable>duration</replaceable>;
<command>max-transfer-idle-in</command> <replaceable>integer</replaceable>;
<command>max-transfer-idle-out</command> <replaceable>integer</replaceable>;
<command>max-transfer-time-in</command> <replaceable>integer</replaceable>;
<command>max-transfer-time-out</command> <replaceable>integer</replaceable>;
<command>max-udp-size</command> <replaceable>integer</replaceable>;
<command>max-zone-ttl</command> ( unlimited | <replaceable>ttlval</replaceable> );
<command>max-zone-ttl</command> ( unlimited | <replaceable>duration</replaceable> );
<command>memstatistics</command> <replaceable>boolean</replaceable>;
<command>memstatistics-file</command> <replaceable>quoted_string</replaceable>;
<command>message-compression</command> <replaceable>boolean</replaceable>;
<command>min-cache-ttl</command> <replaceable>ttlval</replaceable>;
<command>min-ncache-ttl</command> <replaceable>ttlval</replaceable>;
<command>min-cache-ttl</command> <replaceable>duration</replaceable>;
<command>min-ncache-ttl</command> <replaceable>duration</replaceable>;
<command>min-refresh-time</command> <replaceable>integer</replaceable>;
<command>min-retry-time</command> <replaceable>integer</replaceable>;
<command>minimal-any</command> <replaceable>boolean</replaceable>;
@ -190,8 +190,8 @@
<command>notify-source-v6</command> ( <replaceable>ipv6_address</replaceable> | * ) [ port ( <replaceable>integer</replaceable> | * ) ]
[ dscp <replaceable>integer</replaceable> ];
<command>notify-to-soa</command> <replaceable>boolean</replaceable>;
<command>nta-lifetime</command> <replaceable>ttlval</replaceable>;
<command>nta-recheck</command> <replaceable>ttlval</replaceable>;
<command>nta-lifetime</command> <replaceable>duration</replaceable>;
<command>nta-recheck</command> <replaceable>duration</replaceable>;
<command>nxdomain-redirect</command> <replaceable>string</replaceable>;
<command>pid-file</command> ( <replaceable>quoted_string</replaceable> | none );
<command>port</command> <replaceable>integer</replaceable>;
@ -238,13 +238,13 @@
<command>response-padding</command> { <replaceable>address_match_element</replaceable>; ... } block-size
<replaceable>integer</replaceable>;
<command>response-policy</command> { zone <replaceable>string</replaceable> [ add-soa <replaceable>boolean</replaceable> ] [ log
<replaceable>boolean</replaceable> ] [ max-policy-ttl <replaceable>ttlval</replaceable> ] [ min-update-interval
<replaceable>ttlval</replaceable> ] [ policy ( cname | disabled | drop | given | no-op |
<replaceable>boolean</replaceable> ] [ max-policy-ttl <replaceable>duration</replaceable> ] [ min-update-interval
<replaceable>duration</replaceable> ] [ policy ( cname | disabled | drop | given | no-op |
<command>nodata</command> | nxdomain | passthru | tcp-only <replaceable>quoted_string</replaceable> ) ] [
<command>recursive-only</command> <replaceable>boolean</replaceable> ] [ nsip-enable <replaceable>boolean</replaceable> ] [
<command>nsdname-enable</command> <replaceable>boolean</replaceable> ]; ... } [ add-soa <replaceable>boolean</replaceable> ] [
<command>break-dnssec</command> <replaceable>boolean</replaceable> ] [ max-policy-ttl <replaceable>ttlval</replaceable> ] [
<command>min-update-interval</command> <replaceable>ttlval</replaceable> ] [ min-ns-dots <replaceable>integer</replaceable> ] [
<command>break-dnssec</command> <replaceable>boolean</replaceable> ] [ max-policy-ttl <replaceable>duration</replaceable> ] [
<command>min-update-interval</command> <replaceable>duration</replaceable> ] [ min-ns-dots <replaceable>integer</replaceable> ] [
<command>nsip-wait-recurse</command> <replaceable>boolean</replaceable> ] [ qname-wait-recurse <replaceable>boolean</replaceable> ]
[ recursive-only <replaceable>boolean</replaceable> ] [ nsip-enable <replaceable>boolean</replaceable> ] [
<command>nsdname-enable</command> <replaceable>boolean</replaceable> ] [ dnsrps-enable <replaceable>boolean</replaceable> ] [
@ -258,7 +258,7 @@
<command>serial-query-rate</command> <replaceable>integer</replaceable>;
<command>serial-update-method</command> ( date | increment | unixtime );
<command>server-id</command> ( <replaceable>quoted_string</replaceable> | none | hostname );
<command>servfail-ttl</command> <replaceable>ttlval</replaceable>;
<command>servfail-ttl</command> <replaceable>duration</replaceable>;
<command>session-keyalg</command> <replaceable>string</replaceable>;
<command>session-keyfile</command> ( <replaceable>quoted_string</replaceable> | none );
<command>session-keyname</command> <replaceable>string</replaceable>;
@ -269,7 +269,7 @@
<command>sortlist</command> { <replaceable>address_match_element</replaceable>; ... };
<command>stacksize</command> ( default | unlimited | <replaceable>sizeval</replaceable> );
<command>stale-answer-enable</command> <replaceable>boolean</replaceable>;
<command>stale-answer-ttl</command> <replaceable>ttlval</replaceable>;
<command>stale-answer-ttl</command> <replaceable>duration</replaceable>;
<command>startup-notify-rate</command> <replaceable>integer</replaceable>;
<command>statistics-file</command> <replaceable>quoted_string</replaceable>;
<command>synth-from-dnssec</command> <replaceable>boolean</replaceable>;

View file

@ -21,7 +21,7 @@
<command>masterfile-style</command> ( full | relative );
<command>masters</command> [ port <replaceable>integer</replaceable> ] [ dscp <replaceable>integer</replaceable> ] { ( <replaceable>masters</replaceable> | <replaceable>ipv4_address</replaceable> [ port <replaceable>integer</replaceable> ] | <replaceable>ipv6_address</replaceable> [ port <replaceable>integer</replaceable> ] ) [ key <replaceable>string</replaceable> ]; ... };
<command>max-records</command> <replaceable>integer</replaceable>;
<command>max-zone-ttl</command> ( unlimited | <replaceable>ttlval</replaceable> );
<command>max-zone-ttl</command> ( unlimited | <replaceable>duration</replaceable> );
<command>zone-statistics</command> ( full | terse | none | <replaceable>boolean</replaceable> );
};
</programlisting>

View file

@ -29,6 +29,7 @@
<command>dnskey-sig-validity</command> <replaceable>integer</replaceable>;
<command>dnssec-dnskey-kskonly</command> <replaceable>boolean</replaceable>;
<command>dnssec-loadkeys-interval</command> <replaceable>integer</replaceable>;
<command>dnssec-policy</command> <replaceable>string</replaceable>;
<command>dnssec-update-mode</command> ( maintain | no-resign );
<command>file</command> <replaceable>quoted_string</replaceable>;
<command>forward</command> ( first | only );

226
doc/design/dnssec-policy Normal file
View file

@ -0,0 +1,226 @@
Copyright (C) Internet Systems Consortium, Inc. ("ISC")
See COPYRIGHT in the source root or http://isc.org/copyright.html for terms.
# DNSSEC Key and Signing Policy
A DNSSEC key and signing policy (KASP) defines a DNSSEC policy that can be
applied to one or more zones.
For some background information, see:
https://www.ietf.org/archive/id/draft-mekking-dnsop-kasp-00.txt
# DNSSEC in BIND 9
DNSSEC is first implemented in BIND 9. Many adaptations have been made since
then. A lot of configuration knobs were added. One aim with introducing KASP
configuration is that all these configuration options are grouped together,
making the named configuration more intuitive when it comes to DNSSEC, and
making it easier to turn on DNSSEC for zones. Instead of configuring many
different options per zone, you would be able to do the following:
```
zone "example.com." {
...
dnssec-policy "_default";
};
```
## Existing DNSSEC configuration options
### Signing
The following configuration options exist nowadays for `named` to maintain
DNSSEC signed zones. These will no longer work if an explicit DNSSEC policy
is set for a zone.
1. `auto-dnssec`: When setting a DNSSEC policy for a zone instead, the
behavior will be as if `auto-dnssec` was set to `maintain`.
1. `dnskey-sig-validity`: This option will be replaced in favor of the KASP
configuration value `signatures-validity-dnskey`.
1. `dnssec-dnskey-kskonly`: This option will be removed and the key
configuration from the policy will be used to determine what RRsets will be
signed with which keys (Keys will have a role "KSK" and/or "ZSK").
1. `dnssec-loadkeys-interval`: This option will determine how the period that
BIND 9 will check its key repository (default once per hour) to see if
there are new keys added or if existing keys metadata has changed. This
option might go away because the entity that performs DNSSEC maintenance
knows exactly when the next step needs to happen. We can set the interval
accordingly. This does mean that whenever a new key is added or deprecated
manually, the interval needs to be set to now. Alternatively, we keep this
option and only pick up new keys when at a certain interval.
1. `dnssec-secure-to-insecure`: This option allows a dynamic zone to
transition from secure to insecure. This seems to be a safety check
when named is not responsible for signing. This will likely go away
because explicitly removing the dnssec-policy will be the same signal
to (safely) make the zone insecure.
1. `dnssec-update-mode`: This option determines how DNSSEC signed dynamic
zones are updated. Default is `maintain` and it is unclear how it is
different from `auto-dnssec`. With KASP, the behavior will be as if
the `dnssec-update-mode` was set to `maintain`. If you want DNSSEC
maintenance to be done outside `named`, you should not configure a
`dnssec-policy` for that zone.
1. `inline-signing`: When set to "yes", this option will sign transferred
unsigned zones, and unsigned zone from file. This is also no longer needed
when KASP is introduced because when setting a `dnssec-policy` for a
secondary zone or a zone with zone file, this indicates that
`inline-signing` is desired.
1. `max-zone-ttl`: This will cap all TTLs in a zone file to the specified
value. Although this option may be used for non-DNSSEC zones, it is really
only useful for DNSSEC-signed zones because when performing key rollovers
the timing depends on the largest TTL in the zone. The value set in the
`dnssec-policy` statement will override the existing `max-zone-ttl` value.
1. `sig-signing-nodes`: This specifies the number of nodes to be examined
in a quantum when signing a zone with a new DNSKEY. This presumable is
to avoid keeping the database connection open for a long time. With the
current database approach this probably needs to stay.
1. `sig-signing-signatures`: This specifies a threshold number of how many
signatures will be generated in a quantum. Similar to `sig-signing-nodes`.
1. `sig-signing-type`: Internal record type number, used to track zone
signing process. This likely will go away in favor of a new method.
1. `sig-validity-interval`: Specifies the number of days a signature is valid.
The second optional value is the refresh interval. Thos option will
be replaced by KASP configuration values "signatures-validity" and
"signatures-refresh".
1. `update-check-ksk`: When set to "no", KSK will also sign non-DNSKEY RRsets.
This option will go away and key roles will be used to determine what
keys sign which RRsets (A KSK that should sign all RRsets will have both
the KSK and ZSK role and is referred to as a CSK).
Other DNSSEC related configuration options that are not related to the policy
are likely to stay:
1. `key-directory`: This is where the DNSKEY key files can be found.
1. `serial-update-method`: This is used for dynamic zones to determne how
the SOA SERIAL should be updated. There will likely be a separate
configuration option for the serial update method when resigning a zone.
# KASP Configuration
The KASP Configuration may look something like the example configuration
below. This includes all options as described in the KASP draft, but we may
decide that some options are not required.
```
dnssec-policy "nsec3" {
description "policy for zones that require zone walking mitigation";
// Signatures
signatures-refresh P3D;
signatures-validity P14D;
signatures-validity-dnskey P14D;
// Denial of existence
denial-type nsec3;
nsec3-param ttl 0 hash algorithm 1 iterations 5 optout;
nsec3-salt length 8 resalt P100D;
// Keys
dnskey-ttl 3600;
publish-safety PT3600S;
retire-safety PT3600S;
share-keys no;
purge-keys-after P14D;
keys {
ksk key-directory P5Y ECDSAP256SHA256;
zsk key-directory P30D ECDSAP256SHA256;
csk key-directory PT0S 8 2048;
};
// Parent synchronization
cds yes;
cdnskey yes;
check-ds { 127.0.0.53; };
check-ds-interval PT3600S;
// Zone properties
zone-propagation-delay PT3600S;
zone-registration-delay PT3600S;
zone-soa-ttl 3600;
zone-soa-minimum 3600;
zone-soa-serial-update-method unixtime;
zone-max-ttl 24h;
// Parent properties
parent-propagation-delay PT24H;
parent-ds-ttl 3600;
parent-soa-ttl 3600;
parent-soa-minimum 3600;
};
```
# KASP design
## dnssec-policy versus dnssec-keymgr
Key management in BIND 9 is currently implemented with a Python script
called `dnssec-keymgr`. It uses the DNSSEC tools for manipulating DNSSEC key
metadata.
With `dnssec-policy` configured in `named.conf` you no longer need to manually
call `dnssec-keymgr` or the tools it wraps around, `dnssec-keygen` and
`dnssec-settime` (although it is still possible to use them). The policy in
`named.conf` will make `named` create keys when necessary and set the key
timings accordingly.
## Key roles
BIND 9.14 allows sign your zones with a Zone Signing Key (ZSK) and a
Key Signing Key (KSK). If you provide only one key, the zone will be signed
with just one key (effectively acting as a Combined Signing Key (CSK). If
one of the keys is offline, BIND 9 will temporarily change the key usage: A
KSK may sign DNSKEY unrelated RRsets.
With BIND 9.14, ZSKs by default sign the complete zone, except when
`dnssec-dnskey-kskonly` and `update-check-ksk` are both set to `yes`.
KASP introduces key roles making key usage more explicit, without depending
on state of the keys or additional configuration values. A key that has the
KSK role will always sign only DNSKEY related RRsets, and a key with a ZSK role
will always sign only DNSKEY unrelated RRsets. A key can have both roles, which
is referred to as a CSK. Below is an example configuration for the three types
of keys:
```
keys {
ksk key-directory lifetime P5Y algorithm ECDSAP256SHA256;
zsk key-directory lifetime P30D algorithm ECDSAP256SHA256;
csk key-directory lifetime PT0S algorithm 8 2048;
};
```
## NSEC3
Currently if you want to sign your zone with NSEC3 you can do so by introducing
an NSEC3PARAM record via Dynamic Update. This is no longer necessary with
`dnssec-policy` as you can configure NSEC3 usage in `named.conf`.
## Changing policies
You can change a zone's policy by referring to a different `dnssec-policy`
or by changing the `dnssec-policy` itself. After a reload of the configuration
key timings may be adjusted. This may trigger a key rollover (for example if
the key lifetimes have been shortened, or if other key properties have changed.
## Key state machines
Rollover correctness are guaranteed by key state machines. See for more
information:
https://nlnetlabs.nl/downloads/publications/satin2012-Schaeffer.pdf

View file

@ -23,6 +23,7 @@ zone <string> [ <class> ] {
dnskey-sig-validity <integer>;
dnssec-dnskey-kskonly <boolean>;
dnssec-loadkeys-interval <integer>;
dnssec-policy <string>;
dnssec-secure-to-insecure <boolean>;
dnssec-update-mode ( maintain | no-resign );
file <quoted_string>;

View file

@ -25,6 +25,22 @@ dnssec-keys { <string> ( static-key |
initial-key ) <integer> <integer> <integer>
<quoted_string>; ... }; // may occur multiple times
dnssec-policy <string> {
dnskey-ttl <ttlval>;
keys { ( csk | ksk | zsk ) key-directory lifetime <duration> algorithm <integer>
[ <integer> ]; ... };
parent-ds-ttl <duration>;
parent-propagation-delay <duration>;
parent-registration-delay <duration>;
publish-safety <duration>;
retire-safety <duration>;
signatures-refresh <duration>;
signatures-validity <duration>;
signatures-validity-dnskey <duration>;
zone-max-ttl <duration>;
zone-propagation-delay <duration>;
}; // may occur multiple times
dyndb <string> <quoted_string> {
<unspecified-text> }; // may occur multiple times

View file

@ -16,6 +16,7 @@ zone <string> [ <class> ] {
dnskey-sig-validity <integer>;
dnssec-dnskey-kskonly <boolean>;
dnssec-loadkeys-interval <integer>;
dnssec-policy <string>;
dnssec-update-mode ( maintain | no-resign );
file <quoted_string>;
forward ( first | only );

View file

@ -842,6 +842,21 @@ check_name(const char *str) {
return (dns_name_fromstring(dns_fixedname_name(&fixed), str, 0, NULL));
}
static bool
kasp_name_allowed(const cfg_listelt_t *element)
{
const char* name = cfg_obj_asstring(cfg_tuple_get(
cfg_listelt_value(element), "name"));
if (strcmp("none", name) == 0) {
return false;
}
if (strcmp("default", name) == 0) {
return false;
}
return true;
}
static isc_result_t
check_options(const cfg_obj_t *options, isc_log_t *logctx, isc_mem_t *mctx,
optlevel_t optlevel)
@ -856,6 +871,7 @@ check_options(const cfg_obj_t *options, isc_log_t *logctx, isc_mem_t *mctx,
const char *str;
isc_buffer_t b;
uint32_t lifetime = 3600;
bool has_dnssecpolicy = false;
const char *ccalg = "siphash24";
/*
@ -929,7 +945,11 @@ check_options(const cfg_obj_t *options, isc_log_t *logctx, isc_mem_t *mctx,
(void)cfg_map_get(options, intervals[i].name, &obj);
if (obj == NULL)
continue;
val = cfg_obj_asuint32(obj);
if (cfg_obj_isduration(obj)) {
val = cfg_obj_asduration(obj);
} else {
val = cfg_obj_asuint32(obj);
}
if (val > intervals[i].max) {
cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
"%s '%u' is out of range (0..%u)",
@ -944,6 +964,56 @@ check_options(const cfg_obj_t *options, isc_log_t *logctx, isc_mem_t *mctx,
}
}
/*
* Check dnssec-policy.
*/
obj = NULL;
(void)cfg_map_get(options, "dnssec-policy", &obj);
if (obj != NULL) {
bool bad_kasp = false;
bool bad_name = false;
if (optlevel != optlevel_config && !cfg_obj_isstring(obj)) {
bad_kasp = true;
} else if (optlevel == optlevel_config) {
if (cfg_obj_islist(obj)) {
for (element = cfg_list_first(obj);
element != NULL;
element = cfg_list_next(element))
{
if (!cfg_obj_istuple(
cfg_listelt_value(element)))
{
bad_kasp = true;
}
if (!kasp_name_allowed(element)) {
bad_name = true;
}
}
}
}
if (bad_kasp) {
cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
"dnssec-policy may only be configured at "
"the top level, please use name reference "
"at the zone level");
if (result == ISC_R_SUCCESS) {
result = ISC_R_FAILURE;
}
}
if (bad_name) {
cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
"dnssec-policy name may not be 'none' or "
"'default' (which is the built-in policy)");
if (result == ISC_R_SUCCESS) {
result = ISC_R_FAILURE;
}
}
has_dnssecpolicy = true;
}
obj = NULL;
cfg_map_get(options, "max-rsa-exponent-size", &obj);
if (obj != NULL) {
@ -992,6 +1062,13 @@ check_options(const cfg_obj_t *options, isc_log_t *logctx, isc_mem_t *mctx,
result = ISC_R_RANGE;
}
}
if (has_dnssecpolicy) {
cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
"sig-validity-interval: cannot be "
"configured if dnssec-policy is also set");
result = ISC_R_FAILURE;
}
}
obj = NULL;
@ -1008,6 +1085,12 @@ check_options(const cfg_obj_t *options, isc_log_t *logctx, isc_mem_t *mctx,
result = ISC_R_RANGE;
}
if (has_dnssecpolicy) {
cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
"dnskey-sig-validity: cannot be "
"configured if dnssec-policy is also set");
result = ISC_R_FAILURE;
}
}
obj = NULL;
@ -1113,8 +1196,9 @@ check_options(const cfg_obj_t *options, isc_log_t *logctx, isc_mem_t *mctx,
if (result == ISC_R_SUCCESS && tresult != ISC_R_SUCCESS)
result = tresult;
}
if (symtab != NULL)
if (symtab != NULL) {
isc_symtab_destroy(&symtab);
}
}
/*
@ -1176,7 +1260,7 @@ check_options(const cfg_obj_t *options, isc_log_t *logctx, isc_mem_t *mctx,
obj = NULL;
(void)cfg_map_get(options, "nta-lifetime", &obj);
if (obj != NULL) {
lifetime = cfg_obj_asuint32(obj);
lifetime = cfg_obj_asduration(obj);
if (lifetime > 604800) { /* 7 days */
cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
"'nta-lifetime' cannot exceed one week");
@ -1193,7 +1277,7 @@ check_options(const cfg_obj_t *options, isc_log_t *logctx, isc_mem_t *mctx,
obj = NULL;
(void)cfg_map_get(options, "nta-recheck", &obj);
if (obj != NULL) {
uint32_t recheck = cfg_obj_asuint32(obj);
uint32_t recheck = cfg_obj_asduration(obj);
if (recheck > 604800) { /* 7 days */
cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
"'nta-recheck' cannot exceed one week");
@ -1271,7 +1355,11 @@ check_options(const cfg_obj_t *options, isc_log_t *logctx, isc_mem_t *mctx,
if (obj == NULL)
continue;
value = cfg_obj_asuint32(obj);
if (cfg_obj_isduration(obj)) {
value = cfg_obj_asduration(obj);
} else {
value = cfg_obj_asuint32(obj);
}
if (value < fstrm[i].min ||
(fstrm[i].max != 0U && value > fstrm[i].max)) {
if (fstrm[i].max != 0U)
@ -1850,6 +1938,7 @@ check_zoneconf(const cfg_obj_t *zconfig, const cfg_obj_t *voptions,
bool dlz;
dns_masterformat_t masterformat;
bool ddns = false;
bool has_dnssecpolicy = false;
const void *clauses = NULL;
const char *option = NULL;
static const char *acls[] = {
@ -2062,6 +2151,45 @@ check_zoneconf(const cfg_obj_t *zconfig, const cfg_obj_t *voptions,
if (check_nonzero(zoptions, logctx) != ISC_R_SUCCESS)
result = ISC_R_FAILURE;
/*
* Check if a dnssec-policy is set.
*/
obj = NULL;
(void)cfg_map_get(zoptions, "dnssec-policy", &obj);
if (obj != NULL) {
const cfg_obj_t *kasps = NULL;
const char* kaspname = cfg_obj_asstring(obj);
if (strcmp(kaspname, "default") == 0) {
has_dnssecpolicy = true;
} else if (strcmp(kaspname, "none") == 0) {
has_dnssecpolicy = false;
} else {
(void)cfg_map_get(config, "dnssec-policy", &kasps);
for (element = cfg_list_first(kasps); element != NULL;
element = cfg_list_next(element))
{
const char* kn = cfg_obj_asstring(
cfg_tuple_get(cfg_listelt_value(element),
"name"));
if (strcmp(kaspname, kn) == 0) {
has_dnssecpolicy = true;
}
}
if (!has_dnssecpolicy) {
cfg_obj_log(zconfig, logctx, ISC_LOG_ERROR,
"zone '%s': option "
"'dnssec-policy %s' has no "
"matching dnssec-policy config",
znamestr, kaspname);
if (result == ISC_R_SUCCESS) {
result = ISC_R_FAILURE;
}
}
}
}
/*
* Check validity of the zone options.
*/
@ -2248,19 +2376,36 @@ check_zoneconf(const cfg_obj_t *zconfig, const cfg_obj_t *voptions,
if (res1 == ISC_R_SUCCESS)
signing = cfg_obj_asboolean(obj);
if (signing && has_dnssecpolicy) {
cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
"inline-signing: cannot be configured if "
"dnssec-policy is also set");
result = ISC_R_FAILURE;
}
obj = NULL;
arg = "off";
res3 = cfg_map_get(zoptions, "auto-dnssec", &obj);
if (res3 == ISC_R_SUCCESS)
if (res3 == ISC_R_SUCCESS) {
arg = cfg_obj_asstring(obj);
if (strcasecmp(arg, "off") != 0 && !ddns && !signing) {
cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
"'auto-dnssec %s;' requires%s "
"inline-signing to be configured for "
"the zone", arg,
(ztype == CFG_ZONE_MASTER) ?
" dynamic DNS or" : "");
result = ISC_R_FAILURE;
}
if (strcasecmp(arg, "off") != 0) {
if (!ddns && !signing) {
cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
"'auto-dnssec %s;' requires%s "
"inline-signing to be configured "
"for the zone", arg,
(ztype == CFG_ZONE_MASTER) ?
" dynamic DNS or" : "");
result = ISC_R_FAILURE;
}
if (has_dnssecpolicy) {
cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
"'auto-dnssec %s;' cannot be "
"configured if dnssec-policy is "
"also set", arg);
result = ISC_R_FAILURE;
}
}
obj = NULL;
@ -2285,6 +2430,21 @@ check_zoneconf(const cfg_obj_t *zconfig, const cfg_obj_t *voptions,
"inline-signing when used in slave zone");
result = ISC_R_FAILURE;
}
if (res1 == ISC_R_SUCCESS && has_dnssecpolicy) {
cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
"dnssec-dnskey-kskonly: cannot be "
"configured if dnssec-policy is also set");
result = ISC_R_FAILURE;
}
obj = NULL;
res1 = cfg_map_get(zoptions, "dnssec-secure-to-insecure", &obj);
if (res1 == ISC_R_SUCCESS && has_dnssecpolicy) {
cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
"dnssec-secure-to-insecure: cannot be "
"configured if dnssec-policy is also set");
result = ISC_R_FAILURE;
}
obj = NULL;
res1 = cfg_map_get(zoptions, "dnssec-loadkeys-interval", &obj);
@ -2307,6 +2467,21 @@ check_zoneconf(const cfg_obj_t *zconfig, const cfg_obj_t *voptions,
"inline-signing when used in slave zone");
result = ISC_R_FAILURE;
}
if (res1 == ISC_R_SUCCESS && has_dnssecpolicy) {
cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
"update-check-ksk: cannot be configured "
"if dnssec-policy is also set");
result = ISC_R_FAILURE;
}
obj = NULL;
res1 = cfg_map_get(zoptions, "dnssec-update-mode", &obj);
if (res1 == ISC_R_SUCCESS && has_dnssecpolicy) {
cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
"dnssec-update-mode: cannot be configured "
"if dnssec-policy is also set");
result = ISC_R_FAILURE;
}
}
/*

View file

@ -64,8 +64,8 @@ DNSOBJS = acl.@O@ adb.@O@ badcache.@O@ byaddr.@O@ \
db.@O@ dbiterator.@O@ dbtable.@O@ diff.@O@ dispatch.@O@ \
dlz.@O@ dns64.@O@ dnsrps.@O@ dnssec.@O@ ds.@O@ dyndb.@O@ \
ecs.@O@ fixedname.@O@ forward.@O@ \
ipkeylist.@O@ iptable.@O@ journal.@O@ keydata.@O@ \
keytable.@O@ lib.@O@ log.@O@ lookup.@O@ \
ipkeylist.@O@ iptable.@O@ journal.@O@ kasp.@O@ keydata.@O@ \
keymgr.@O@ keytable.@O@ lib.@O@ log.@O@ lookup.@O@ \
master.@O@ masterdump.@O@ message.@O@ \
name.@O@ ncache.@O@ nsec.@O@ nsec3.@O@ nta.@O@ \
order.@O@ peer.@O@ portlist.@O@ private.@O@ \
@ -100,9 +100,9 @@ DNSSRCS = acl.c adb.c badcache. byaddr.c \
cache.c callbacks.c clientinfo.c compress.c \
db.c dbiterator.c dbtable.c diff.c dispatch.c \
dlz.c dns64.c dnsrps.c dnssec.c ds.c dyndb.c \
ecs.c fixedname.c forward.c \
ipkeylist.c iptable.c journal.c keydata.c keytable.c lib.c \
log.c lookup.c master.c masterdump.c message.c \
ecs.c fixedname.c forward.c ipkeylist.c iptable.c \
journal.c kasp.c keydata.c keymgr.c keytable.c \
lib.c log.c lookup.c master.c masterdump.c message.c \
name.c ncache.c nsec.c nsec3.c nta.c \
order.c peer.c portlist.c \
rbt.c rbtdb.c rcode.c rdata.c rdatalist.c \

View file

@ -29,6 +29,7 @@
#include <dns/diff.h>
#include <dns/dnssec.h>
#include <dns/fixedname.h>
#include <dns/kasp.h>
#include <dns/keyvalues.h>
#include <dns/log.h>
#include <dns/message.h>
@ -582,52 +583,51 @@ cleanup_struct:
bool
dns_dnssec_keyactive(dst_key_t *key, isc_stdtime_t now) {
isc_result_t result;
isc_stdtime_t publish, active, revoke, inactive, deltime;
bool pubset = false, actset = false;
bool revset = false, inactset = false;
bool delset = false;
isc_stdtime_t publish, active, revoke, remove;
bool hint_publish, hint_zsign, hint_ksign, hint_revoke, hint_remove;
int major, minor;
bool ksk = false, zsk = false;
isc_result_t ret;
/* Is this an old-style key? */
result = dst_key_getprivateformat(key, &major, &minor);
RUNTIME_CHECK(result == ISC_R_SUCCESS);
/* Is this a KSK? */
ret = dst_key_getbool(key, DST_BOOL_KSK, &ksk);
if (ret != ISC_R_SUCCESS) {
ksk = ((dst_key_flags(key) & DNS_KEYFLAG_KSK) != 0);
}
ret = dst_key_getbool(key, DST_BOOL_ZSK, &zsk);
if (ret != ISC_R_SUCCESS) {
zsk = ((dst_key_flags(key) & DNS_KEYFLAG_KSK) == 0);
}
/*
* Smart signing started with key format 1.3; prior to that, all
* keys are assumed active
* keys are assumed active.
*/
if (major == 1 && minor <= 2)
return (true);
result = dst_key_gettime(key, DST_TIME_PUBLISH, &publish);
if (result == ISC_R_SUCCESS)
pubset = true;
hint_publish = dst_key_is_published(key, now, &publish);
hint_zsign = dst_key_is_signing(key, DST_BOOL_ZSK, now, &active);
hint_ksign = dst_key_is_signing(key, DST_BOOL_KSK, now, &active);
hint_revoke = dst_key_is_revoked(key, now, &revoke);
hint_remove = dst_key_is_removed(key, now, &remove);
result = dst_key_gettime(key, DST_TIME_ACTIVATE, &active);
if (result == ISC_R_SUCCESS)
actset = true;
result = dst_key_gettime(key, DST_TIME_REVOKE, &revoke);
if (result == ISC_R_SUCCESS)
revset = true;
result = dst_key_gettime(key, DST_TIME_INACTIVE, &inactive);
if (result == ISC_R_SUCCESS)
inactset = true;
result = dst_key_gettime(key, DST_TIME_DELETE, &deltime);
if (result == ISC_R_SUCCESS)
delset = true;
if ((inactset && inactive <= now) || (delset && deltime <= now))
if (hint_remove) {
return (false);
if (revset && revoke <= now && pubset && publish <= now)
}
if (hint_publish && hint_revoke) {
return (true);
if (actset && active <= now)
}
if (hint_zsign && zsk) {
return (true);
}
if (hint_ksign && ksk) {
return (true);
}
return (false);
}
@ -635,7 +635,10 @@ dns_dnssec_keyactive(dst_key_t *key, isc_stdtime_t now) {
* Indicate whether a key is scheduled to to have CDS/CDNSKEY records
* published now.
*
* Returns true iff.
* Returns true if.
* - kasp says the DS record should be published (e.g. the DS state is in
* RUMOURED or OMNIPRESENT state).
* Or:
* - SyncPublish is set and in the past, AND
* - SyncDelete is unset or in the future
*/
@ -643,6 +646,7 @@ static bool
syncpublish(dst_key_t *key, isc_stdtime_t now) {
isc_result_t result;
isc_stdtime_t when;
dst_key_state_t state;
int major, minor;
/*
@ -654,18 +658,29 @@ syncpublish(dst_key_t *key, isc_stdtime_t now) {
/*
* Smart signing started with key format 1.3
*/
if (major == 1 && minor <= 2)
if (major == 1 && minor <= 2) {
return (false);
}
/* Check kasp state first. */
result = dst_key_getstate(key, DST_KEY_DS, &state);
if (result == ISC_R_SUCCESS) {
return (state == DST_KEY_STATE_RUMOURED ||
state == DST_KEY_STATE_OMNIPRESENT);
}
/* If no kasp state, check timings. */
result = dst_key_gettime(key, DST_TIME_SYNCPUBLISH, &when);
if (result != ISC_R_SUCCESS)
if (result != ISC_R_SUCCESS) {
return (false);
}
result = dst_key_gettime(key, DST_TIME_SYNCDELETE, &when);
if (result != ISC_R_SUCCESS)
if (result != ISC_R_SUCCESS) {
return (true);
if (when <= now)
}
if (when <= now) {
return (false);
}
return (true);
}
@ -673,12 +688,17 @@ syncpublish(dst_key_t *key, isc_stdtime_t now) {
* Indicate whether a key is scheduled to to have CDS/CDNSKEY records
* deleted now.
*
* Returns true iff. SyncDelete is set and in the past.
* Returns true if:
* - kasp says the DS record should be unpublished (e.g. the DS state is in
* UNRETENTIVE or HIDDEN state).
* Or:
* - SyncDelete is set and in the past.
*/
static bool
syncdelete(dst_key_t *key, isc_stdtime_t now) {
isc_result_t result;
isc_stdtime_t when;
dst_key_state_t state;
int major, minor;
/*
@ -690,14 +710,25 @@ syncdelete(dst_key_t *key, isc_stdtime_t now) {
/*
* Smart signing started with key format 1.3.
*/
if (major == 1 && minor <= 2)
if (major == 1 && minor <= 2) {
return (false);
}
/* Check kasp state first. */
result = dst_key_getstate(key, DST_KEY_DS, &state);
if (result == ISC_R_SUCCESS) {
return (state == DST_KEY_STATE_UNRETENTIVE ||
state == DST_KEY_STATE_HIDDEN);
}
/* If no kasp state, check timings. */
result = dst_key_gettime(key, DST_TIME_SYNCDELETE, &when);
if (result != ISC_R_SUCCESS)
if (result != ISC_R_SUCCESS) {
return (false);
if (when <= now)
}
if (when <= now) {
return (true);
}
return (false);
}
@ -742,7 +773,8 @@ dns_dnssec_findzonekeys(dns_db_t *db, dns_dbversion_t *ver,
result = dst_key_fromfile(dst_key_name(pubkey),
dst_key_id(pubkey),
dst_key_alg(pubkey),
DST_TYPE_PUBLIC|DST_TYPE_PRIVATE,
DST_TYPE_PUBLIC|DST_TYPE_PRIVATE|
DST_TYPE_STATE,
directory,
mctx, &keys[count]);
@ -761,7 +793,8 @@ dns_dnssec_findzonekeys(dns_db_t *db, dns_dbversion_t *ver,
dst_key_id(pubkey),
dst_key_alg(pubkey),
DST_TYPE_PUBLIC|
DST_TYPE_PRIVATE,
DST_TYPE_PRIVATE|
DST_TYPE_STATE,
directory,
mctx, &keys[count]);
if (result == ISC_R_SUCCESS &&
@ -784,8 +817,9 @@ dns_dnssec_findzonekeys(dns_db_t *db, dns_dbversion_t *ver,
result2 = dst_key_getfilename(dst_key_name(pubkey),
dst_key_id(pubkey),
dst_key_alg(pubkey),
(DST_TYPE_PUBLIC |
DST_TYPE_PRIVATE),
(DST_TYPE_PUBLIC|
DST_TYPE_PRIVATE|
DST_TYPE_STATE),
directory, mctx,
&buf);
if (result2 != ISC_R_SUCCESS) {
@ -1219,6 +1253,7 @@ dns_dnsseckey_create(isc_mem_t *mctx, dst_key_t **dstkey,
dk->force_sign = false;
dk->hint_publish = false;
dk->hint_sign = false;
dk->hint_revoke = false;
dk->hint_remove = false;
dk->first_sign = false;
dk->is_active = false;
@ -1227,7 +1262,14 @@ dns_dnsseckey_create(isc_mem_t *mctx, dst_key_t **dstkey,
dk->index = 0;
/* KSK or ZSK? */
dk->ksk = ((dst_key_flags(dk->key) & DNS_KEYFLAG_KSK) != 0);
result = dst_key_getbool(dk->key, DST_BOOL_KSK, &dk->ksk);
if (result != ISC_R_SUCCESS) {
dk->ksk = ((dst_key_flags(dk->key) & DNS_KEYFLAG_KSK) != 0);
}
result = dst_key_getbool(dk->key, DST_BOOL_ZSK, &dk->zsk);
if (result != ISC_R_SUCCESS) {
dk->zsk = ((dst_key_flags(dk->key) & DNS_KEYFLAG_KSK) == 0);
}
/* Is this an old-style key? */
result = dst_key_getprivateformat(dk->key, &major, &minor);
@ -1253,80 +1295,48 @@ dns_dnsseckey_destroy(isc_mem_t *mctx, dns_dnsseckey_t **dkp) {
*dkp = NULL;
}
static void
get_hints(dns_dnsseckey_t *key, isc_stdtime_t now) {
isc_result_t result;
isc_stdtime_t publish, active, revoke, inactive, deltime;
bool pubset = false, actset = false;
bool revset = false, inactset = false;
bool delset = false;
void
dns_dnssec_get_hints(dns_dnsseckey_t *key, isc_stdtime_t now) {
isc_stdtime_t publish = 0, active = 0, revoke = 0, remove = 0;
REQUIRE(key != NULL && key->key != NULL);
result = dst_key_gettime(key->key, DST_TIME_PUBLISH, &publish);
if (result == ISC_R_SUCCESS)
pubset = true;
key->hint_publish = dst_key_is_published(key->key, now, &publish);
key->hint_sign = dst_key_is_signing(key->key, DST_BOOL_ZSK, now,
&active);
key->hint_revoke = dst_key_is_revoked(key->key, now, &revoke);
key->hint_remove = dst_key_is_removed(key->key, now, &remove);
result = dst_key_gettime(key->key, DST_TIME_ACTIVATE, &active);
if (result == ISC_R_SUCCESS)
actset = true;
result = dst_key_gettime(key->key, DST_TIME_REVOKE, &revoke);
if (result == ISC_R_SUCCESS)
revset = true;
result = dst_key_gettime(key->key, DST_TIME_INACTIVE, &inactive);
if (result == ISC_R_SUCCESS)
inactset = true;
result = dst_key_gettime(key->key, DST_TIME_DELETE, &deltime);
if (result == ISC_R_SUCCESS)
delset = true;
/* Metadata says publish (but possibly not activate) */
if (pubset && publish <= now)
/*
* Activation date is set (maybe in the future), but publication date
* isn't. Most likely the user wants to publish now and activate later.
* Most likely because this is true for most rollovers, except for:
* 1. The unpopular ZSK Double-RRSIG method.
* 2. When introducing a new algorithm.
* These two cases are rare enough that we will set hint_publish
* anyway when hint_sign is set, because BIND 9 natively does not
* support the ZSK Double-RRSIG method, and when introducing a new
* algorihtm, we strive to publish its signatures and DNSKEY records
* at the same time.
*/
if (key->hint_sign && publish == 0) {
key->hint_publish = true;
/* Metadata says activate (so we must also publish) */
if (actset && active <= now) {
key->hint_sign = true;
/* Only publish if publish time has already passed. */
if (pubset && publish <= now)
key->hint_publish = true;
}
/*
* Activation date is set (maybe in the future), but
* publication date isn't. Most likely the user wants to
* publish now and activate later.
* If activation date is in the future, make note of how far off.
*/
if (actset && !pubset)
key->hint_publish = true;
/*
* If activation date is in the future, make note of how far off
*/
if (key->hint_publish && actset && active > now) {
if (key->hint_publish && active > now) {
key->prepublish = active - now;
}
/*
* Key has been marked inactive: we can continue publishing,
* but don't sign.
*/
if (key->hint_publish && inactset && inactive <= now) {
key->hint_sign = false;
}
/*
* Metadata says revoke. If the key is published,
* we *have to* sign with it per RFC5011--even if it was
* not active before.
* Metadata says revoke. If the key is published, we *have to* sign
* with it per RFC5011 -- even if it was not active before.
*
* If it hasn't already been done, we should also revoke it now.
*/
if (key->hint_publish && (revset && revoke <= now)) {
if (key->hint_publish && key->hint_revoke) {
uint32_t flags;
key->hint_sign = true;
flags = dst_key_flags(key->key);
@ -1337,17 +1347,17 @@ get_hints(dns_dnsseckey_t *key, isc_stdtime_t now) {
}
/*
* Metadata says delete, so don't publish this key or sign with it.
* Metadata says delete, so don't publish this key or sign with it
* (note that signatures of a removed key may still be reused).
*/
if (delset && deltime <= now) {
if (key->hint_remove) {
key->hint_publish = false;
key->hint_sign = false;
key->hint_remove = true;
}
}
/*%
* Get a list of DNSSEC keys from the key repository
* Get a list of DNSSEC keys from the key repository.
*/
isc_result_t
dns_dnssec_findmatchingkeys(const dns_name_t *origin, const char *directory,
@ -1416,10 +1426,10 @@ dns_dnssec_findmatchingkeys(const dns_name_t *origin, const char *directory,
continue;
dstkey = NULL;
result = dst_key_fromnamedfile(dir.entry.name,
directory,
result = dst_key_fromnamedfile(dir.entry.name, directory,
DST_TYPE_PUBLIC |
DST_TYPE_PRIVATE,
DST_TYPE_PRIVATE |
DST_TYPE_STATE,
mctx, &dstkey);
switch (alg) {
@ -1447,7 +1457,7 @@ dns_dnssec_findmatchingkeys(const dns_name_t *origin, const char *directory,
RETERR(dns_dnsseckey_create(mctx, &dstkey, &key));
key->source = dns_keysource_repository;
get_hints(key, now);
dns_dnssec_get_hints(key, now);
if (key->legacy) {
dns_dnsseckey_destroy(mctx, &key);
@ -1638,7 +1648,8 @@ dns_dnssec_keylistfromrdataset(const dns_name_t *origin,
result = dst_key_fromfile(dst_key_name(pubkey),
dst_key_id(pubkey),
dst_key_alg(pubkey),
DST_TYPE_PUBLIC|DST_TYPE_PRIVATE,
(DST_TYPE_PUBLIC|DST_TYPE_PRIVATE|
DST_TYPE_STATE),
directory, mctx, &privkey);
/*
@ -1655,8 +1666,9 @@ dns_dnssec_keylistfromrdataset(const dns_name_t *origin,
result = dst_key_fromfile(dst_key_name(pubkey),
dst_key_id(pubkey),
dst_key_alg(pubkey),
DST_TYPE_PUBLIC|
DST_TYPE_PRIVATE,
(DST_TYPE_PUBLIC|
DST_TYPE_PRIVATE|
DST_TYPE_STATE),
directory,
mctx, &privkey);
if (result == ISC_R_SUCCESS &&
@ -1680,7 +1692,8 @@ dns_dnssec_keylistfromrdataset(const dns_name_t *origin,
dst_key_id(pubkey),
dst_key_alg(pubkey),
(DST_TYPE_PUBLIC |
DST_TYPE_PRIVATE),
DST_TYPE_PRIVATE|
DST_TYPE_STATE),
directory, mctx,
&buf);
if (result2 != ISC_R_SUCCESS) {
@ -1800,7 +1813,7 @@ delrdata(dns_rdata_t *rdata, dns_diff_t *diff, const dns_name_t *origin,
static isc_result_t
publish_key(dns_diff_t *diff, dns_dnsseckey_t *key, const dns_name_t *origin,
dns_ttl_t ttl, isc_mem_t *mctx, bool allzsk,
dns_ttl_t ttl, isc_mem_t *mctx,
void (*report)(const char *, ...))
{
isc_result_t result;
@ -1813,7 +1826,7 @@ publish_key(dns_diff_t *diff, dns_dnsseckey_t *key, const dns_name_t *origin,
dst_key_format(key->key, keystr, sizeof(keystr));
report("Fetching %s (%s) from key %s.\n",
keystr, key->ksk ? (allzsk ? "KSK/ZSK" : "KSK") : "ZSK",
keystr, key->ksk ? (key->zsk ? "CSK" : "KSK") : "ZSK",
key->source == dns_keysource_user ? "file" : "repository");
if (key->prepublish && ttl > key->prepublish) {
@ -2023,8 +2036,7 @@ dns_dnssec_syncupdate(dns_dnsseckeylist_t *keys, dns_dnsseckeylist_t *rmkeys,
isc_result_t
dns_dnssec_updatekeys(dns_dnsseckeylist_t *keys, dns_dnsseckeylist_t *newkeys,
dns_dnsseckeylist_t *removed, const dns_name_t *origin,
dns_ttl_t hint_ttl, dns_diff_t *diff,
bool allzsk, isc_mem_t *mctx,
dns_ttl_t hint_ttl, dns_diff_t *diff, isc_mem_t *mctx,
void (*report)(const char *, ...))
{
isc_result_t result;
@ -2047,8 +2059,8 @@ dns_dnssec_updatekeys(dns_dnsseckeylist_t *keys, dns_dnsseckeylist_t *newkeys,
if (key->source == dns_keysource_user &&
(key->hint_publish || key->force_publish))
{
RETERR(publish_key(diff, key, origin, ttl,
mctx, allzsk, report));
RETERR(publish_key(diff, key, origin, ttl, mctx,
report));
}
if (key->source == dns_keysource_zoneapex) {
ttl = dst_key_getttl(key->key);
@ -2125,14 +2137,14 @@ dns_dnssec_updatekeys(dns_dnsseckeylist_t *keys, dns_dnsseckeylist_t *newkeys,
(key1->hint_publish || key1->force_publish))
{
RETERR(publish_key(diff, key1, origin, ttl,
mctx, allzsk, report));
mctx, report));
isc_log_write(dns_lctx,
DNS_LOGCATEGORY_DNSSEC,
DNS_LOGMODULE_DNSSEC,
ISC_LOG_INFO,
"DNSKEY %s (%s) is now published",
keystr1, key1->ksk ?
(allzsk ? "KSK/ZSK" : "KSK") :
(key1->zsk ? "CSK" : "KSK") :
"ZSK");
if (key1->hint_sign || key1->force_sign) {
key1->first_sign = true;
@ -2143,7 +2155,7 @@ dns_dnssec_updatekeys(dns_dnsseckeylist_t *keys, dns_dnsseckeylist_t *newkeys,
"DNSKEY %s (%s) is now "
"active",
keystr1, key1->ksk ?
(allzsk ? "KSK/ZSK" :
(key1->zsk ? "CSK" :
"KSK") : "ZSK");
}
}
@ -2154,6 +2166,9 @@ dns_dnssec_updatekeys(dns_dnsseckeylist_t *keys, dns_dnsseckeylist_t *newkeys,
/* Printable version of key2 (the old key, if any) */
dst_key_format(key2->key, keystr2, sizeof(keystr2));
/* Copy key metadata. */
dst_key_copy_metadata(key2->key, key1->key);
/* Match found: remove or update it as needed */
if (key1->hint_remove) {
RETERR(remove_key(diff, key2, origin, ttl, mctx,
@ -2167,8 +2182,8 @@ dns_dnssec_updatekeys(dns_dnsseckeylist_t *keys, dns_dnsseckeylist_t *newkeys,
DNS_LOGMODULE_DNSSEC,
ISC_LOG_INFO,
"DNSKEY %s (%s) is now deleted",
keystr2, key2->ksk ? (allzsk ?
"KSK/ZSK" : "KSK") : "ZSK");
keystr2, key2->ksk ? (key2->zsk ?
"CSK" : "KSK") : "ZSK");
} else {
dns_dnsseckey_destroy(mctx, &key2);
}
@ -2192,15 +2207,15 @@ dns_dnssec_updatekeys(dns_dnsseckeylist_t *keys, dns_dnsseckeylist_t *newkeys,
ISC_LOG_INFO,
"DNSKEY %s (%s) is now revoked; "
"new ID is %05d",
keystr2, key2->ksk ? (allzsk ?
"KSK/ZSK" : "KSK") : "ZSK",
keystr2, key2->ksk ? (key2->zsk ?
"CSK" : "KSK") : "ZSK",
dst_key_id(key1->key));
} else {
dns_dnsseckey_destroy(mctx, &key2);
}
RETERR(publish_key(diff, key1, origin, ttl,
mctx, allzsk, report));
RETERR(publish_key(diff, key1, origin, ttl, mctx,
report));
ISC_LIST_UNLINK(*newkeys, key1, link);
ISC_LIST_APPEND(*keys, key1, link);
@ -2224,8 +2239,8 @@ dns_dnssec_updatekeys(dns_dnsseckeylist_t *keys, dns_dnsseckeylist_t *newkeys,
DNS_LOGMODULE_DNSSEC,
ISC_LOG_INFO,
"DNSKEY %s (%s) is now active",
keystr1, key1->ksk ? (allzsk ?
"KSK/ZSK" : "KSK") : "ZSK");
keystr1, key1->ksk ? (key1->zsk ?
"CSK" : "KSK") : "ZSK");
} else if (key2->is_active &&
!key1->hint_sign && !key1->force_sign)
{
@ -2234,8 +2249,8 @@ dns_dnssec_updatekeys(dns_dnsseckeylist_t *keys, dns_dnsseckeylist_t *newkeys,
DNS_LOGMODULE_DNSSEC,
ISC_LOG_INFO,
"DNSKEY %s (%s) is now inactive",
keystr1, key1->ksk ? (allzsk ?
"KSK/ZSK" : "KSK") : "ZSK");
keystr1, key1->ksk ? (key1->zsk ?
"CSK" : "KSK") : "ZSK");
}
key2->hint_sign = key1->hint_sign;

File diff suppressed because it is too large Load diff

View file

@ -107,11 +107,18 @@ struct dst_key {
} keydata; /*%< pointer to key in crypto pkg fmt */
isc_stdtime_t times[DST_MAX_TIMES + 1]; /*%< timing metadata */
bool timeset[DST_MAX_TIMES + 1]; /*%< data set? */
isc_stdtime_t nums[DST_MAX_NUMERIC + 1]; /*%< numeric metadata */
bool numset[DST_MAX_NUMERIC + 1]; /*%< data set? */
bool inactive; /*%< private key not present as it is
inactive */
bool timeset[DST_MAX_TIMES + 1]; /*%< data set? */
uint32_t nums[DST_MAX_NUMERIC + 1]; /*%< numeric metadata */
bool numset[DST_MAX_NUMERIC + 1]; /*%< data set? */
bool bools[DST_MAX_BOOLEAN + 1]; /*%< boolean metadata */
bool boolset[DST_MAX_BOOLEAN + 1]; /*%< data set? */
dst_key_state_t keystates[DST_MAX_KEYSTATES + 1]; /*%< key states */
bool keystateset[DST_MAX_KEYSTATES + 1]; /*%< data set? */
bool inactive; /*%< private key not present as it is inactive */
bool external; /*%< external key */
int fmt_major; /*%< private key format, major version */

View file

@ -61,7 +61,11 @@ static const char *timetags[TIMING_NTAGS] = {
"Delete:",
"DSPublish:",
"SyncPublish:",
"SyncDelete:"
"SyncDelete:",
NULL,
NULL,
NULL,
NULL
};
#define NUMERIC_NTAGS (DST_MAX_NUMERIC + 1)
@ -69,7 +73,8 @@ static const char *numerictags[NUMERIC_NTAGS] = {
"Predecessor:",
"Successor:",
"MaxTTL:",
"RollPeriod:"
"RollPeriod:",
NULL
};
struct parse_map {
@ -734,7 +739,9 @@ dst__privstruct_writefile(const dst_key_t *key, const dst_private_t *priv,
result = dst_key_getnum(key, i, &value);
if (result != ISC_R_SUCCESS)
continue;
fprintf(fp, "%s %u\n", numerictags[i], value);
if (numerictags[i] != NULL) {
fprintf(fp, "%s %u\n", numerictags[i], value);
}
}
for (i = 0; i < TIMING_NTAGS; i++) {
result = dst_key_gettime(key, i, &when);
@ -750,8 +757,10 @@ dst__privstruct_writefile(const dst_key_t *key, const dst_private_t *priv,
isc_buffer_usedregion(&b, &r);
fprintf(fp, "%s %.*s\n", timetags[i], (int)r.length,
r.base);
if (timetags[i] != NULL) {
fprintf(fp, "%s %.*s\n", timetags[i],
(int)r.length, r.base);
}
}
}

View file

@ -53,12 +53,14 @@ struct dns_dnsseckey {
bool force_publish; /*% publish regardless of metadata */
bool hint_sign; /*% metadata says to sign with this key */
bool force_sign; /*% sign with key regardless of metadata */
bool hint_revoke; /*% metadata says revoke key */
bool hint_remove; /*% metadata says *don't* publish */
bool is_active; /*% key is already active */
bool first_sign; /*% key is newly becoming active */
unsigned int prepublish; /*% how long until active? */
dns_keysource_t source; /*% how the key was found */
bool ksk; /*% this is a key-signing key */
bool zsk; /*% this is a zone-signing key */
bool legacy; /*% this is old-style key with no
metadata (possibly generated by
an older version of BIND9) and
@ -267,6 +269,16 @@ dns_dnsseckey_destroy(isc_mem_t *mctx, dns_dnsseckey_t **dkp);
*\li '*dkp' is NULL.
*/
void
dns_dnssec_get_hints(dns_dnsseckey_t *key, isc_stdtime_t now);
/*%<
* Get hints on DNSSEC key whether this key can be published
* and/or is active. Timing metadata is compared to 'now'.
*
* Requires:
*\li 'key' is a pointer to a DNSSEC key and is not NULL.
*/
isc_result_t
dns_dnssec_findmatchingkeys(const dns_name_t *origin, const char *directory,
isc_stdtime_t now, isc_mem_t *mctx,
@ -312,8 +324,8 @@ dns_dnssec_keylistfromrdataset(const dns_name_t *origin,
isc_result_t
dns_dnssec_updatekeys(dns_dnsseckeylist_t *keys, dns_dnsseckeylist_t *newkeys,
dns_dnsseckeylist_t *removed, const dns_name_t *origin,
dns_ttl_t hint_ttl, dns_diff_t *diff, bool allzsk,
isc_mem_t *mctx, void (*report)(const char *, ...));
dns_ttl_t hint_ttl, dns_diff_t *diff, isc_mem_t *mctx,
void (*report)(const char *, ...));
/*%<
* Update the list of keys in 'keys' with new key information in 'newkeys'.
*
@ -328,9 +340,6 @@ dns_dnssec_updatekeys(dns_dnsseckeylist_t *keys, dns_dnsseckeylist_t *newkeys,
* copy the key into that list; otherwise destroy it.
* - Otherwise, make sure keys has current metadata.
*
* If 'allzsk' is true, we are allowing KSK-flagged keys to be used as
* ZSKs.
*
* 'hint_ttl' is the TTL to use for the DNSKEY RRset if there is no
* existing RRset, and if none of the keys to be added has a default TTL
* (in which case we would use the shortest one). If the TTL is longer

635
lib/dns/include/dns/kasp.h Normal file
View file

@ -0,0 +1,635 @@
/*
* Copyright (C) Internet Systems Consortium, Inc. ("ISC")
*
* 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 http://mozilla.org/MPL/2.0/.
*
* See the COPYRIGHT file distributed with this work for additional
* information regarding copyright ownership.
*/
#ifndef DNS_KASP_H
#define DNS_KASP_H 1
/*****
***** Module Info
*****/
/*! \file dns/kasp.h
* \brief
* DNSSEC Key and Signing Policy (KASP)
*
* A "kasp" is a DNSSEC policy, that determines how a zone should be
* signed and maintained.
*/
#include <isc/lang.h>
#include <isc/magic.h>
#include <isc/mutex.h>
#include <isc/refcount.h>
#include <dns/types.h>
ISC_LANG_BEGINDECLS
/* Stores a KASP key */
struct dns_kasp_key {
isc_mem_t* mctx;
/* Locked by themselves. */
isc_refcount_t references;
/* Under owner's locking control. */
ISC_LINK(struct dns_kasp_key) link;
/* Configuration */
uint32_t lifetime;
uint32_t algorithm;
int length;
uint8_t role;
};
/* Stores a DNSSEC policy */
struct dns_kasp {
unsigned int magic;
isc_mem_t* mctx;
char* name;
/* Internals. */
isc_mutex_t lock;
bool frozen;
/* Locked by themselves. */
isc_refcount_t references;
/* Under owner's locking control. */
ISC_LINK(struct dns_kasp) link;
/* Configuration: signatures */
uint32_t signatures_refresh;
uint32_t signatures_validity;
uint32_t signatures_validity_dnskey;
/* Configuration: Keys */
dns_kasp_keylist_t keys;
dns_ttl_t dnskey_ttl;
/* Configuration: Timings */
uint32_t publish_safety;
uint32_t retire_safety;
/* Zone settings */
dns_ttl_t zone_max_ttl;
uint32_t zone_propagation_delay;
/* Parent settings */
dns_ttl_t parent_ds_ttl;
uint32_t parent_propagation_delay;
uint32_t parent_registration_delay;
// TODO: The rest of the KASP configuration
};
#define DNS_KASP_MAGIC ISC_MAGIC('K','A','S','P')
#define DNS_KASP_VALID(kasp) ISC_MAGIC_VALID(kasp, DNS_KASP_MAGIC)
/* Defaults */
#define DNS_KASP_SIG_REFRESH (86400*5)
#define DNS_KASP_SIG_VALIDITY (86400*14)
#define DNS_KASP_SIG_VALIDITY_DNSKEY (86400*14)
#define DNS_KASP_KEY_TTL (3600)
#define DNS_KASP_DS_TTL (3600)
#define DNS_KASP_PUBLISH_SAFETY (300)
#define DNS_KASP_RETIRE_SAFETY (300)
#define DNS_KASP_ZONE_MAXTTL (86400)
#define DNS_KASP_ZONE_PROPDELAY (300)
#define DNS_KASP_PARENT_PROPDELAY (3600)
#define DNS_KASP_PARENT_REGDELAY (86400)
/* Key roles */
#define DNS_KASP_KEY_ROLE_KSK 0x01
#define DNS_KASP_KEY_ROLE_ZSK 0x02
isc_result_t
dns_kasp_create(isc_mem_t *mctx, const char* name, dns_kasp_t **kaspp);
/*%<
* Create a KASP.
*
* Requires:
*
*\li 'mctx' is a valid memory context.
*
*\li 'name' is a valid C string.
*
*\li kaspp != NULL && *kaspp == NULL
*
* Returns:
*
*\li #ISC_R_SUCCESS
*\li #ISC_R_NOMEMORY
*
*\li Other errors are possible.
*/
void
dns_kasp_attach(dns_kasp_t *source, dns_kasp_t **targetp);
/*%<
* Attach '*targetp' to 'source'.
*
* Requires:
*
*\li 'source' is a valid, frozen kasp.
*
*\li 'targetp' points to a NULL dns_kasp_t *.
*
* Ensures:
*
*\li *targetp is attached to source.
*
*\li While *targetp is attached, the kasp will not shut down.
*/
void
dns_kasp_detach(dns_kasp_t **kaspp);
/*%<
* Detach KASP.
*
* Requires:
*
*\li 'kaspp' points to a valid dns_kasp_t *
*
* Ensures:
*
*\li *kaspp is NULL.
*/
void
dns_kasp_freeze(dns_kasp_t *kasp);
/*%<
* Freeze kasp. No changes can be made to kasp configuration while frozen.
*
* Requires:
*
*\li 'kasp' is a valid, unfrozen kasp.
*
* Ensures:
*
*\li 'kasp' is frozen.
*/
void
dns_kasp_thaw(dns_kasp_t *kasp);
/*%<
* Thaw kasp.
*
* Requires:
*
*\li 'kasp' is a valid, frozen kasp.
*
* Ensures:
*
*\li 'kasp' is no longer frozen.
*/
const char*
dns_kasp_getname(dns_kasp_t *kasp);
/*%<
* Get kasp name.
*
* Requires:
*
*\li 'kasp' is a valid kasp.
*
* Returns:
*
*\li name of 'kasp'.
*/
uint32_t
dns_kasp_signdelay(dns_kasp_t *kasp);
/*%<
* Get the delay that is needed to ensure that all existing RRsets have been
* re-signed with a successor key. This is the signature validity minus the
* signature refresh time (that indicates how far before signature expiry an
* RRSIG should be refreshed).
*
* Requires:
*
*\li 'kasp' is a valid, frozen kasp.
*
* Returns:
*
*\li signature refresh interval.
*/
uint32_t
dns_kasp_sigrefresh(dns_kasp_t *kasp);
/*%<
* Get signature refresh interval.
*
* Requires:
*
*\li 'kasp' is a valid, frozen kasp.
*
* Returns:
*
*\li signature refresh interval.
*/
void
dns_kasp_setsigrefresh(dns_kasp_t *kasp, uint32_t value);
/*%<
* Set signature refresh interval.
*
* Requires:
*
*\li 'kasp' is a valid, thawed kasp.
*/
uint32_t
dns_kasp_sigvalidity(dns_kasp_t *kasp);
uint32_t
dns_kasp_sigvalidity_dnskey(dns_kasp_t *kasp);
/*%<
* Get signature validity.
*
* Requires:
*
*\li 'kasp' is a valid, frozen kasp.
*
* Returns:
*
*\li signature validity.
*/
void
dns_kasp_setsigvalidity(dns_kasp_t *kasp, uint32_t value);
void
dns_kasp_setsigvalidity_dnskey(dns_kasp_t *kasp, uint32_t value);
/*%<
* Set signature validity.
*
* Requires:
*
*\li 'kasp' is a valid, thawed kasp.
*/
dns_ttl_t
dns_kasp_dnskeyttl(dns_kasp_t *kasp);
/*%<
* Get DNSKEY TTL.
*
* Requires:
*
*\li 'kasp' is a valid, frozen kasp.
*
* Returns:
*
*\li DNSKEY TTL.
*/
void
dns_kasp_setdnskeyttl(dns_kasp_t *kasp, dns_ttl_t ttl);
/*%<
* Set DNSKEY TTL.
*
* Requires:
*
*\li 'kasp' is a valid, thawed kasp.
*/
uint32_t
dns_kasp_publishsafety(dns_kasp_t *kasp);
/*%<
* Get publish safety interval.
*
* Requires:
*
*\li 'kasp' is a valid, frozen kasp.
*
* Returns:
*
*\li Publish safety interval.
*/
void
dns_kasp_setpublishsafety(dns_kasp_t *kasp, uint32_t value);
/*%<
* Set publish safety interval.
*
* Requires:
*
*\li 'kasp' is a valid, thawed kasp.
*/
uint32_t
dns_kasp_retiresafety(dns_kasp_t *kasp);
/*%<
* Get retire safety interval.
*
* Requires:
*
*\li 'kasp' is a valid, frozen kasp.
*
* Returns:
*
*\li Retire safety interval.
*/
void
dns_kasp_setretiresafety(dns_kasp_t *kasp, uint32_t value);
/*%<
* Set retire safety interval.
*
* Requires:
*
*\li 'kasp' is a valid, thawed kasp.
*/
dns_ttl_t
dns_kasp_zonemaxttl(dns_kasp_t *kasp);
/*%<
* Get maximum zone TTL.
*
* Requires:
*
*\li 'kasp' is a valid, frozen kasp.
*
* Returns:
*
*\li Maximum zone TTL.
*/
void
dns_kasp_setzonemaxttl(dns_kasp_t *kasp, dns_ttl_t ttl);
/*%<
* Set maximum zone TTL.
*
* Requires:
*
*\li 'kasp' is a valid, thawed kasp.
*/
uint32_t
dns_kasp_zonepropagationdelay(dns_kasp_t *kasp);
/*%<
* Get zone propagation delay.
*
* Requires:
*
*\li 'kasp' is a valid, frozen kasp.
*
* Returns:
*
*\li Zone propagation delay.
*/
void
dns_kasp_setzonepropagationdelay(dns_kasp_t *kasp, uint32_t value);
/*%<
* Set zone propagation delay.
*
* Requires:
*
*\li 'kasp' is a valid, thawed kasp.
*/
dns_ttl_t
dns_kasp_dsttl(dns_kasp_t *kasp);
/*%<
* Get DS TTL (should match that of the parent DS record).
*
* Requires:
*
*\li 'kasp' is a valid, frozen kasp.
*
* Returns:
*
*\li Expected parent DS TTL.
*/
void
dns_kasp_setdsttl(dns_kasp_t *kasp, dns_ttl_t ttl);
/*%<
* Set DS TTL.
*
* Requires:
*
*\li 'kasp' is a valid, thawed kasp.
*/
uint32_t
dns_kasp_parentpropagationdelay(dns_kasp_t *kasp);
/*%<
* Get parent zone propagation delay.
*
* Requires:
*
*\li 'kasp' is a valid, frozen kasp.
*
* Returns:
*
*\li Parent zone propagation delay.
*/
void
dns_kasp_setparentpropagationdelay(dns_kasp_t *kasp, uint32_t value);
/*%<
* Set parent propagation delay.
*
* Requires:
*
*\li 'kasp' is a valid, thawed kasp.
*/
uint32_t
dns_kasp_parentregistrationdelay(dns_kasp_t *kasp);
/*%<
* Get parent registration delay for submitting new DS.
*
* Requires:
*
*\li 'kasp' is a valid, frozen kasp.
*
* Returns:
*
*\li Parent registration delay.
*/
void
dns_kasp_setparentregistrationdelay(dns_kasp_t *kasp, uint32_t value);
/*%<
* Set parent registration delay.
*
* Requires:
*
*\li 'kasp' is a valid, thawed kasp.
*/
isc_result_t
dns_kasplist_find(dns_kasplist_t *list, const char *name, dns_kasp_t **kaspp);
/*%<
* Search for a kasp with name 'name' in 'list'.
* If found, '*kaspp' is (strongly) attached to it.
*
* Requires:
*
*\li 'kaspp' points to a NULL dns_kasp_t *.
*
* Returns:
*
*\li #ISC_R_SUCCESS A matching kasp was found.
*\li #ISC_R_NOTFOUND No matching kasp was found.
*/
dns_kasp_keylist_t
dns_kasp_keys(dns_kasp_t *kasp);
/*%<
* Get the list of kasp keys.
*
* Requires:
*
*\li 'kasp' is a valid, frozen kasp.
*
* Returns:
*
*\li #ISC_R_SUCCESS
*\li #ISC_R_NOMEMORY
*
*\li Other errors are possible.
*/
bool
dns_kasp_keylist_empty(dns_kasp_t *kasp);
/*%<
* Check if the keylist is empty.
*
* Requires:
*
*\li 'kasp' is a valid kasp.
*
* Returns:
*
*\li true if the keylist is empty, false otherwise.
*/
void
dns_kasp_addkey(dns_kasp_t *kasp, dns_kasp_key_t *key);
/*%<
* Add a key.
*
* Requires:
*
*\li 'kasp' is a valid, thawed kasp.
*\li 'key' is not NULL.
*/
isc_result_t
dns_kasp_key_create(dns_kasp_t *kasp, dns_kasp_key_t **keyp);
/*%<
* Create a key inside a KASP.
*
* Requires:
*
*\li 'kasp' is a valid kasp.
*
*\li keyp != NULL && *keyp == NULL
*
* Returns:
*
*\li #ISC_R_SUCCESS
*\li #ISC_R_NOMEMORY
*
*\li Other errors are possible.
*/
void
dns_kasp_key_destroy(dns_kasp_key_t* key);
/*%<
* Destroy a KASP key.
*
* Requires:
*
*\li key != NULL
*/
uint32_t
dns_kasp_key_algorithm(dns_kasp_key_t *key);
/*%<
* Get the key algorithm.
*
* Requires:
*
*\li key != NULL
*
* Returns:
*
*\li Key algorithm.
*/
unsigned int
dns_kasp_key_size(dns_kasp_key_t *key);
/*%<
* Get the key size.
*
* Requires:
*
*\li key != NULL
*
* Returns:
*
*\li Configured key size, or default key size for key algorithm if no size
* configured.
*/
uint32_t
dns_kasp_key_lifetime(dns_kasp_key_t *key);
/*%<
* The lifetime of this key (how long may this key be active?)
*
* Requires:
*
*\li key != NULL
*
* Returns:
*
*\li Lifetime of key.
*
*/
bool
dns_kasp_key_ksk(dns_kasp_key_t *key);
/*%<
* Does this key act as a KSK?
*
* Requires:
*
*\li key != NULL
*
* Returns:
*
*\li True, if the key role has DNS_KASP_KEY_ROLE_KSK set.
*\li False, otherwise.
*
*/
bool
dns_kasp_key_zsk(dns_kasp_key_t *key);
/*%<
* Does this key act as a ZSK?
*
* Requires:
*
*\li key != NULL
*
* Returns:
*
*\li True, if the key role has DNS_KASP_KEY_ROLE_ZSK set.
*\li False, otherwise.
*
*/
ISC_LANG_ENDDECLS
#endif /* DNS_KASP_H */

View file

@ -0,0 +1,57 @@
/*
* Copyright (C) Internet Systems Consortium, Inc. ("ISC")
*
* 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 http://mozilla.org/MPL/2.0/.
*
* See the COPYRIGHT file distributed with this work for additional
* information regarding copyright ownership.
*/
#ifndef DNS_KEYMGR_H
#define DNS_KEYMGR_H 1
/*! \file dns/keymgr.h */
#include <isc/lang.h>
#include <isc/stdtime.h>
#include <dns/types.h>
#include <dst/dst.h>
ISC_LANG_BEGINDECLS
isc_result_t
dns_keymgr_run(const dns_name_t *origin, dns_rdataclass_t rdclass,
const char *directory, isc_mem_t *mctx,
dns_dnsseckeylist_t *keyring, dns_kasp_t *kasp,
isc_stdtime_t now, isc_stdtime_t *nexttime);
/*%<
* Manage keys in 'keylist' and update timing data according to 'kasp' policy.
* Create new keys for 'origin' if necessary in 'directory'. Append all such
* keys, along with use hints gleaned from their metadata, onto 'keylist'.
*
* Update key states and store changes back to disk. Store when to run next
* in 'nexttime'.
*
* Requires:
*\li 'origin' is a valid FQDN.
*\li 'mctx' is a valid memory context.
*\li 'keyring' is not NULL.
*\li 'kasp' is not NULL.
*
* Returns:
*\li #ISC_R_SUCCESS
*\li any error returned by dst_key_generate(), isc_dir_open(),
* dst_key_to_file(), or dns_dnsseckey_create().
*
* Ensures:
*\li On error, keypool is unchanged
*/
ISC_LANG_ENDDECLS
#endif /* DNS_KEYMGR_H */

View file

@ -91,6 +91,10 @@ typedef struct dns_fwdtable dns_fwdtable_t;
typedef struct dns_geoip_databases dns_geoip_databases_t;
typedef struct dns_iptable dns_iptable_t;
typedef uint32_t dns_iterations_t;
typedef struct dns_kasp dns_kasp_t;
typedef ISC_LIST(dns_kasp_t) dns_kasplist_t;
typedef struct dns_kasp_key dns_kasp_key_t;
typedef ISC_LIST(dns_kasp_key_t) dns_kasp_keylist_t;
typedef uint16_t dns_keyflags_t;
typedef struct dns_keynode dns_keynode_t;
typedef ISC_LIST(dns_keynode_t) dns_keynodelist_t;

View file

@ -665,6 +665,24 @@ dns_zone_unload(dns_zone_t *zone);
*\li 'zone' to be a valid zone.
*/
dns_kasp_t*
dns_zone_getkasp(dns_zone_t *zone);
/*%<
* Returns the current kasp.
*
* Require:
*\li 'zone' to be a valid zone.
*/
void
dns_zone_setkasp(dns_zone_t *zone, dns_kasp_t* kasp);
/*%<
* Set kasp for zone. If a kasp is already set, it will be detached.
*
* Requires:
*\li 'zone' to be a valid zone.
*/
void
dns_zone_setoption(dns_zone_t *zone, dns_zoneopt_t option,
bool value);

View file

@ -44,6 +44,38 @@ ISC_LANG_BEGINDECLS
typedef struct dst_key dst_key_t;
typedef struct dst_context dst_context_t;
/*%
* Key states for the DNSSEC records related to a key: DNSKEY, RRSIG (ksk),
* RRSIG (zsk), and DS.
*
* DST_KEY_STATE_HIDDEN: Records of this type are not published in zone.
* This may be because the key parts were never
* introduced in the zone, or because the key has
* retired and has no records of this type left in
* the zone.
* DST_KEY_STATE_RUMOURED: Records of this type are published in zone, but
* not long enough to ensure all resolvers know
* about it.
* DST_KEY_STATE_OMNIPRESENT: Records of this type are published in zone long
* enough so that all resolvers that know about
* these records, no longer have outdated data.
* DST_KEY_STATE_UNRETENTIVE: Records of this type have been removed from the
* zone, but there may be resolvers that still have
* have predecessor records cached. Note that RRSIG
* records in this state may actually still be in the
* zone because they are reused, but retired RRSIG
* records will never be refreshed: A successor key
* is used to create signatures.
* DST_KEY_STATE_NA: The state is not applicable for this record type.
*/
typedef enum dst_key_state {
DST_KEY_STATE_HIDDEN = 0,
DST_KEY_STATE_RUMOURED = 1,
DST_KEY_STATE_OMNIPRESENT = 2,
DST_KEY_STATE_UNRETENTIVE = 3,
DST_KEY_STATE_NA = 4
} dst_key_state_t;
/* DST algorithm codes */
#define DST_ALG_UNKNOWN 0
#define DST_ALG_RSA 1 /* Used for parsing RSASHA1, RSASHA256 and RSASHA512 */
@ -85,6 +117,7 @@ typedef struct dst_context dst_context_t;
#define DST_TYPE_KEY 0x1000000 /* KEY key */
#define DST_TYPE_PRIVATE 0x2000000
#define DST_TYPE_PUBLIC 0x4000000
#define DST_TYPE_STATE 0x8000000
/* Key timing metadata definitions */
#define DST_TIME_CREATED 0
@ -96,14 +129,32 @@ typedef struct dst_context dst_context_t;
#define DST_TIME_DSPUBLISH 6
#define DST_TIME_SYNCPUBLISH 7
#define DST_TIME_SYNCDELETE 8
#define DST_MAX_TIMES 8
#define DST_TIME_DNSKEY 9
#define DST_TIME_ZRRSIG 10
#define DST_TIME_KRRSIG 11
#define DST_TIME_DS 12
#define DST_MAX_TIMES 12
/* Numeric metadata definitions */
#define DST_NUM_PREDECESSOR 0
#define DST_NUM_SUCCESSOR 1
#define DST_NUM_MAXTTL 2
#define DST_NUM_ROLLPERIOD 3
#define DST_MAX_NUMERIC 3
#define DST_NUM_LIFETIME 4
#define DST_MAX_NUMERIC 4
/* Boolean metadata definitions */
#define DST_BOOL_KSK 0
#define DST_BOOL_ZSK 1
#define DST_MAX_BOOLEAN 1
/* Key state metadata definitions */
#define DST_KEY_DNSKEY 0
#define DST_KEY_ZRRSIG 1
#define DST_KEY_KRRSIG 2
#define DST_KEY_DS 3
#define DST_KEY_GOAL 4
#define DST_MAX_KEYSTATES 4
/*
* Current format version number of the private key parser.
@ -310,16 +361,17 @@ dst_key_fromfile(dns_name_t *name, dns_keytag_t id, unsigned int alg, int type,
const char *directory, isc_mem_t *mctx, dst_key_t **keyp);
/*%<
* Reads a key from permanent storage. The key can either be a public or
* private key, and is specified by name, algorithm, and id. If a private key
* is specified, the public key must also be present. If directory is NULL,
* the current directory is assumed.
* private key, or a key state. It specified by name, algorithm, and id. If
* a private key or key state is specified, the public key must also be
* present. If directory is NULL, the current directory is assumed.
*
* Requires:
* \li "name" is a valid absolute dns name.
* \li "id" is a valid key tag identifier.
* \li "alg" is a supported key algorithm.
* \li "type" is DST_TYPE_PUBLIC, DST_TYPE_PRIVATE, or the bitwise union.
* DST_TYPE_KEY look for a KEY record otherwise DNSKEY
* \li "type" is DST_TYPE_PUBLIC, DST_TYPE_PRIVATE or the bitwise union.
* DST_TYPE_KEY look for a KEY record otherwise DNSKEY.
* DST_TYPE_STATE to also read the key state.
* \li "mctx" is a valid memory context.
* \li "keyp" is not NULL and "*keyp" is NULL.
*
@ -336,8 +388,8 @@ dst_key_fromnamedfile(const char *filename, const char *dirname,
int type, isc_mem_t *mctx, dst_key_t **keyp);
/*%<
* Reads a key from permanent storage. The key can either be a public or
* key, and is specified by filename. If a private key is specified, the
* public key must also be present.
* private key, or a key stae. It is specified by filename. If a private key
* or key state is specified, the public key must also be present.
*
* If 'dirname' is not NULL, and 'filename' is a relative path,
* then the file is looked up relative to the given directory.
@ -345,8 +397,9 @@ dst_key_fromnamedfile(const char *filename, const char *dirname,
*
* Requires:
* \li "filename" is not NULL
* \li "type" is DST_TYPE_PUBLIC, DST_TYPE_PRIVATE, or the bitwise union
* DST_TYPE_KEY look for a KEY record otherwise DNSKEY
* \li "type" is DST_TYPE_PUBLIC, DST_TYPE_PRIVATE, or the bitwise union.
* DST_TYPE_KEY look for a KEY record otherwise DNSKEY.
* DST_TYPE_STATE to also read the key state.
* \li "mctx" is a valid memory context
* \li "keyp" is not NULL and "*keyp" is NULL.
*
@ -366,9 +419,9 @@ dst_key_read_public(const char *filename, int type,
* Reads a public key from permanent storage. The key must be a public key.
*
* Requires:
* \li "filename" is not NULL
* \li "type" is DST_TYPE_KEY look for a KEY record otherwise DNSKEY
* \li "mctx" is a valid memory context
* \li "filename" is not NULL.
* \li "type" is DST_TYPE_KEY look for a KEY record otherwise DNSKEY.
* \li "mctx" is a valid memory context.
* \li "keyp" is not NULL and "*keyp" is NULL.
*
* Returns:
@ -381,6 +434,22 @@ dst_key_read_public(const char *filename, int type,
* \li If successful, *keyp will contain a valid key.
*/
isc_result_t
dst_key_read_state(const char *filename, isc_mem_t *mctx, dst_key_t **keyp);
/*%<
* Reads a key state from permanent storage.
*
* Requires:
* \li "filename" is not NULL.
* \li "mctx" is a valid memory context.
* \li "keyp" is not NULL and "*keyp" is NULL.
*
* Returns:
* \li ISC_R_SUCCESS
* \li ISC_R_UNEXPECTEDTOKEN if the file can not be parsed as a public key
* \li any other result indicates failure
*/
isc_result_t
dst_key_tofile(const dst_key_t *key, int type, const char *directory);
/*%<
@ -811,6 +880,37 @@ dst_key_setflags(dst_key_t *key, uint32_t flags);
* "key" is a valid key.
*/
isc_result_t
dst_key_getbool(const dst_key_t *key, int type, bool *valuep);
/*%<
* Get a member of the boolean metadata array and place it in '*valuep'.
*
* Requires:
* "key" is a valid key.
* "type" is no larger than DST_MAX_BOOLEAN
* "valuep" is not null.
*/
void
dst_key_setbool(dst_key_t *key, int type, bool value);
/*%<
* Set a member of the boolean metadata array.
*
* Requires:
* "key" is a valid key.
* "type" is no larger than DST_MAX_BOOLEAN
*/
void
dst_key_unsetbool(dst_key_t *key, int type);
/*%<
* Flag a member of the boolean metadata array as "not set".
*
* Requires:
* "key" is a valid key.
* "type" is no larger than DST_MAX_BOOLEAN
*/
isc_result_t
dst_key_getnum(const dst_key_t *key, int type, uint32_t *valuep);
/*%<
@ -819,7 +919,7 @@ dst_key_getnum(const dst_key_t *key, int type, uint32_t *valuep);
* Requires:
* "key" is a valid key.
* "type" is no larger than DST_MAX_NUMERIC
* "timep" is not null.
* "valuep" is not null.
*/
void
@ -873,6 +973,38 @@ dst_key_unsettime(dst_key_t *key, int type);
* "type" is no larger than DST_MAX_TIMES
*/
isc_result_t
dst_key_getstate(const dst_key_t *key, int type, dst_key_state_t *statep);
/*%<
* Get a member of the keystate metadata array and place it in '*statep'.
*
* Requires:
* "key" is a valid key.
* "type" is no larger than DST_MAX_KEYSTATES
* "statep" is not null.
*/
void
dst_key_setstate(dst_key_t *key, int type, dst_key_state_t state);
/*%<
* Set a member of the keystate metadata array.
*
* Requires:
* "key" is a valid key.
* "state" is a valid state.
* "type" is no larger than DST_MAX_KEYSTATES
*/
void
dst_key_unsetstate(dst_key_t *key, int type);
/*%<
* Flag a member of the keystate metadata array as "not set".
*
* Requires:
* "key" is a valid key.
* "type" is no larger than DST_MAX_KEYSTATES
*/
isc_result_t
dst_key_getprivateformat(const dst_key_t *key, int *majorp, int *minorp);
/*%<
@ -961,9 +1093,88 @@ 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, int role, isc_stdtime_t now,
isc_stdtime_t *active);
/*%<
* Check if it is safe to use this key for signing, given the role.
*
* 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.
*/
void
dst_key_copy_metadata(dst_key_t *to, dst_key_t *from);
/*%<
* Copy key metadata from one key to another.
*
* Requires:
* 'to' and 'from' to be valid.
*/
ISC_LANG_ENDDECLS

442
lib/dns/kasp.c Normal file
View file

@ -0,0 +1,442 @@
/*
* Copyright (C) Internet Systems Consortium, Inc. ("ISC")
*
* 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 http://mozilla.org/MPL/2.0/.
*
* See the COPYRIGHT file distributed with this work for additional
* information regarding copyright ownership.
*/
/*! \file */
#include <string.h>
#include <isc/assertions.h>
#include <isc/file.h>
#include <isc/log.h>
#include <isc/mem.h>
#include <isc/util.h>
#include <dns/log.h>
#include <dns/kasp.h>
#include <dns/keyvalues.h>
isc_result_t
dns_kasp_create(isc_mem_t *mctx, const char *name, dns_kasp_t **kaspp)
{
dns_kasp_t *kasp;
REQUIRE(name != NULL);
REQUIRE(kaspp != NULL && *kaspp == NULL);
kasp = isc_mem_get(mctx, sizeof(*kasp));
kasp->mctx = NULL;
isc_mem_attach(mctx, &kasp->mctx);
kasp->name = isc_mem_strdup(mctx, name);
isc_mutex_init(&kasp->lock);
kasp->frozen = false;
isc_refcount_init(&kasp->references, 1);
ISC_LINK_INIT(kasp, link);
kasp->signatures_refresh = DNS_KASP_SIG_REFRESH;
kasp->signatures_validity = DNS_KASP_SIG_VALIDITY;
kasp->signatures_validity_dnskey = DNS_KASP_SIG_VALIDITY_DNSKEY;
ISC_LIST_INIT(kasp->keys);
kasp->dnskey_ttl = DNS_KASP_KEY_TTL;
kasp->publish_safety = DNS_KASP_PUBLISH_SAFETY;
kasp->retire_safety = DNS_KASP_RETIRE_SAFETY;
kasp->zone_max_ttl = DNS_KASP_ZONE_MAXTTL;
kasp->zone_propagation_delay = DNS_KASP_ZONE_PROPDELAY;
kasp->parent_ds_ttl = DNS_KASP_DS_TTL;
kasp->parent_propagation_delay = DNS_KASP_PARENT_PROPDELAY;
kasp->parent_registration_delay = DNS_KASP_PARENT_REGDELAY;
// TODO: The rest of the KASP configuration
kasp->magic = DNS_KASP_MAGIC;
*kaspp = kasp;
return (ISC_R_SUCCESS);
}
void
dns_kasp_attach(dns_kasp_t *source, dns_kasp_t **targetp) {
REQUIRE(DNS_KASP_VALID(source));
REQUIRE(targetp != NULL && *targetp == NULL);
isc_refcount_increment(&source->references);
*targetp = source;
}
static inline void
destroy(dns_kasp_t *kasp) {
dns_kasp_key_t *key;
dns_kasp_key_t *key_next;
ISC_INSIST(!ISC_LINK_LINKED(kasp, link));
for (key = ISC_LIST_HEAD(kasp->keys); key != NULL; key = key_next) {
key_next = ISC_LIST_NEXT(key, link);
ISC_LIST_UNLINK(kasp->keys, key, link);
dns_kasp_key_destroy(key);
}
ISC_INSIST(ISC_LIST_EMPTY(kasp->keys));
isc_mem_free(kasp->mctx, kasp->name);
isc_mem_putanddetach(&kasp->mctx, kasp, sizeof(*kasp));
}
void
dns_kasp_detach(dns_kasp_t **kaspp) {
REQUIRE(kaspp != NULL && DNS_KASP_VALID(*kaspp));
dns_kasp_t *kasp = *kaspp;
*kaspp = NULL;
if (isc_refcount_decrement(&kasp->references) == 1) {
destroy(kasp);
}
}
const char*
dns_kasp_getname(dns_kasp_t *kasp) {
REQUIRE(DNS_KASP_VALID(kasp));
return (kasp->name);
}
void
dns_kasp_freeze(dns_kasp_t *kasp) {
REQUIRE(DNS_KASP_VALID(kasp));
REQUIRE(!kasp->frozen);
kasp->frozen = true;
}
void
dns_kasp_thaw(dns_kasp_t *kasp) {
REQUIRE(DNS_KASP_VALID(kasp));
REQUIRE(kasp->frozen);
kasp->frozen = false;
}
uint32_t
dns_kasp_signdelay(dns_kasp_t *kasp) {
REQUIRE(DNS_KASP_VALID(kasp));
REQUIRE(kasp->frozen);
return (kasp->signatures_validity - kasp->signatures_refresh);
}
uint32_t
dns_kasp_sigrefresh(dns_kasp_t *kasp) {
REQUIRE(DNS_KASP_VALID(kasp));
REQUIRE(kasp->frozen);
return (kasp->signatures_refresh);
}
void
dns_kasp_setsigrefresh(dns_kasp_t *kasp, uint32_t value) {
REQUIRE(DNS_KASP_VALID(kasp));
REQUIRE(!kasp->frozen);
kasp->signatures_refresh = value;
}
uint32_t
dns_kasp_sigvalidity(dns_kasp_t *kasp) {
REQUIRE(DNS_KASP_VALID(kasp));
REQUIRE(kasp->frozen);
return (kasp->signatures_validity);
}
void
dns_kasp_setsigvalidity(dns_kasp_t *kasp, uint32_t value) {
REQUIRE(DNS_KASP_VALID(kasp));
REQUIRE(!kasp->frozen);
kasp->signatures_validity = value;
}
uint32_t
dns_kasp_sigvalidity_dnskey(dns_kasp_t *kasp) {
REQUIRE(DNS_KASP_VALID(kasp));
REQUIRE(kasp->frozen);
return (kasp->signatures_validity_dnskey);
}
void
dns_kasp_setsigvalidity_dnskey(dns_kasp_t *kasp, uint32_t value) {
REQUIRE(DNS_KASP_VALID(kasp));
REQUIRE(!kasp->frozen);
kasp->signatures_validity = value;
}
dns_ttl_t
dns_kasp_dnskeyttl(dns_kasp_t *kasp) {
REQUIRE(DNS_KASP_VALID(kasp));
REQUIRE(kasp->frozen);
return (kasp->dnskey_ttl);
}
void
dns_kasp_setdnskeyttl(dns_kasp_t *kasp, dns_ttl_t ttl) {
REQUIRE(DNS_KASP_VALID(kasp));
REQUIRE(!kasp->frozen);
kasp->dnskey_ttl = ttl;
}
uint32_t
dns_kasp_publishsafety(dns_kasp_t *kasp) {
REQUIRE(DNS_KASP_VALID(kasp));
REQUIRE(kasp->frozen);
return (kasp->publish_safety);
}
void
dns_kasp_setpublishsafety(dns_kasp_t *kasp, uint32_t value) {
REQUIRE(DNS_KASP_VALID(kasp));
REQUIRE(!kasp->frozen);
kasp->publish_safety = value;
}
uint32_t
dns_kasp_retiresafety(dns_kasp_t *kasp) {
REQUIRE(DNS_KASP_VALID(kasp));
REQUIRE(kasp->frozen);
return (kasp->retire_safety);
}
void
dns_kasp_setretiresafety(dns_kasp_t *kasp, uint32_t value) {
REQUIRE(DNS_KASP_VALID(kasp));
REQUIRE(!kasp->frozen);
kasp->retire_safety = value;
}
dns_ttl_t
dns_kasp_zonemaxttl(dns_kasp_t *kasp) {
REQUIRE(DNS_KASP_VALID(kasp));
REQUIRE(kasp->frozen);
return (kasp->zone_max_ttl);
}
void
dns_kasp_setzonemaxttl(dns_kasp_t *kasp, dns_ttl_t ttl) {
REQUIRE(DNS_KASP_VALID(kasp));
REQUIRE(!kasp->frozen);
kasp->zone_max_ttl = ttl;
}
uint32_t
dns_kasp_zonepropagationdelay(dns_kasp_t *kasp) {
REQUIRE(DNS_KASP_VALID(kasp));
REQUIRE(kasp->frozen);
return (kasp->zone_propagation_delay);
}
void
dns_kasp_setzonepropagationdelay(dns_kasp_t *kasp, uint32_t value) {
REQUIRE(DNS_KASP_VALID(kasp));
REQUIRE(!kasp->frozen);
kasp->zone_propagation_delay = value;
}
dns_ttl_t
dns_kasp_dsttl(dns_kasp_t *kasp) {
REQUIRE(DNS_KASP_VALID(kasp));
REQUIRE(kasp->frozen);
return (kasp->parent_ds_ttl);
}
void
dns_kasp_setdsttl(dns_kasp_t *kasp, dns_ttl_t ttl) {
REQUIRE(DNS_KASP_VALID(kasp));
REQUIRE(!kasp->frozen);
kasp->parent_ds_ttl = ttl;
}
uint32_t
dns_kasp_parentpropagationdelay(dns_kasp_t *kasp) {
REQUIRE(DNS_KASP_VALID(kasp));
REQUIRE(kasp->frozen);
return (kasp->parent_propagation_delay);
}
void
dns_kasp_setparentpropagationdelay(dns_kasp_t *kasp, uint32_t value) {
REQUIRE(DNS_KASP_VALID(kasp));
REQUIRE(!kasp->frozen);
kasp->parent_propagation_delay = value;
}
uint32_t
dns_kasp_parentregistrationdelay(dns_kasp_t *kasp) {
REQUIRE(DNS_KASP_VALID(kasp));
REQUIRE(kasp->frozen);
return (kasp->parent_registration_delay);
}
void
dns_kasp_setparentregistrationdelay(dns_kasp_t *kasp, uint32_t value) {
REQUIRE(DNS_KASP_VALID(kasp));
REQUIRE(!kasp->frozen);
kasp->parent_registration_delay = value;
}
isc_result_t
dns_kasplist_find(dns_kasplist_t *list, const char *name, dns_kasp_t **kaspp)
{
dns_kasp_t *kasp = NULL;
REQUIRE(kaspp != NULL && *kaspp == NULL);
if (list == NULL) {
return (ISC_R_NOTFOUND);
}
INSIST(list != NULL);
for (kasp = ISC_LIST_HEAD(*list); kasp != NULL;
kasp = ISC_LIST_NEXT(kasp, link))
{
if (strcmp(kasp->name, name) == 0) {
break;
}
}
if (kasp == NULL) {
return (ISC_R_NOTFOUND);
}
dns_kasp_attach(kasp, kaspp);
return (ISC_R_SUCCESS);
}
dns_kasp_keylist_t
dns_kasp_keys(dns_kasp_t *kasp)
{
REQUIRE(DNS_KASP_VALID(kasp));
REQUIRE(kasp->frozen);
return (kasp->keys);
}
bool
dns_kasp_keylist_empty(dns_kasp_t *kasp)
{
REQUIRE(DNS_KASP_VALID(kasp));
return (ISC_LIST_EMPTY(kasp->keys));
}
void
dns_kasp_addkey(dns_kasp_t *kasp, dns_kasp_key_t *key)
{
REQUIRE(DNS_KASP_VALID(kasp));
REQUIRE(!kasp->frozen);
REQUIRE(key != NULL);
ISC_LIST_APPEND(kasp->keys, key, link);
}
isc_result_t
dns_kasp_key_create(dns_kasp_t *kasp, dns_kasp_key_t **keyp)
{
dns_kasp_key_t *key;
REQUIRE(DNS_KASP_VALID(kasp));
REQUIRE(keyp != NULL && *keyp == NULL);
key = isc_mem_get(kasp->mctx, sizeof(*key));
key->mctx = NULL;
isc_mem_attach(kasp->mctx, &key->mctx);
ISC_LINK_INIT(key, link);
key->lifetime = 0;
key->algorithm = 0;
key->length = -1;
key->role = 0;
*keyp = key;
return (ISC_R_SUCCESS);
}
void
dns_kasp_key_destroy(dns_kasp_key_t* key)
{
REQUIRE(key != NULL);
isc_mem_putanddetach(&key->mctx, key, sizeof(*key));
}
uint32_t
dns_kasp_key_algorithm(dns_kasp_key_t *key) {
REQUIRE(key != NULL);
return (key->algorithm);
}
unsigned int
dns_kasp_key_size(dns_kasp_key_t *key) {
unsigned int size = 0;
unsigned int min = 0;
REQUIRE(key != NULL);
switch (key->algorithm) {
case DNS_KEYALG_RSASHA1:
case DNS_KEYALG_NSEC3RSASHA1:
case DNS_KEYALG_RSASHA256:
case DNS_KEYALG_RSASHA512:
min = DNS_KEYALG_RSASHA512 ? 1024 : 512;
if (key->length > -1) {
size = (unsigned int) key->length;
if (size < min) {
size = min;
}
if (size > 4096) {
size = 4096;
}
} else if (key->role & DNS_KASP_KEY_ROLE_KSK) {
size = 2048;
} else {
size = 1024;
}
break;
case DNS_KEYALG_ECDSA256:
size = 256;
break;
case DNS_KEYALG_ECDSA384:
size = 384;
break;
case DNS_KEYALG_ED25519:
size = 32;
break;
case DNS_KEYALG_ED448:
size = 57;
break;
default:
/* unsupported */
break;
}
return (size);
}
uint32_t
dns_kasp_key_lifetime(dns_kasp_key_t *key) {
REQUIRE(key != NULL);
return (key->lifetime);
}
bool
dns_kasp_key_ksk(dns_kasp_key_t *key) {
REQUIRE(key != NULL);
return (key->role & DNS_KASP_KEY_ROLE_KSK);
}
bool
dns_kasp_key_zsk(dns_kasp_key_t *key) {
REQUIRE(key != NULL);
return (key->role & DNS_KASP_KEY_ROLE_ZSK);
}

1573
lib/dns/keymgr.c Normal file

File diff suppressed because it is too large Load diff

View file

@ -35,6 +35,7 @@
#include <dns/events.h>
#include <dns/fixedname.h>
#include <dns/journal.h>
#include <dns/kasp.h>
#include <dns/keyvalues.h>
#include <dns/log.h>
#include <dns/message.h>
@ -1076,6 +1077,7 @@ add_sigs(dns_update_log_t *log, dns_zone_t *zone, dns_db_t *db,
{
isc_result_t result;
dns_dbnode_t *node = NULL;
dns_kasp_t *kasp = dns_zone_getkasp(zone);
dns_rdataset_t rdataset;
dns_rdata_t sig_rdata = DNS_RDATA_INIT;
dns_stats_t* dnssecsignstats = dns_zone_getdnssecsignstats(zone);
@ -1085,6 +1087,11 @@ add_sigs(dns_update_log_t *log, dns_zone_t *zone, dns_db_t *db,
bool added_sig = false;
isc_mem_t *mctx = diff->mctx;
if (kasp != NULL) {
check_ksk = false;
keyset_kskonly = true;
}
dns_rdataset_init(&rdataset);
isc_buffer_init(&buffer, data, sizeof(data));
@ -1155,7 +1162,63 @@ add_sigs(dns_update_log_t *log, dns_zone_t *zone, dns_db_t *db,
}
}
if (both) {
if (kasp != NULL) {
/*
* A dnssec-policy is found. Check what RRsets this
* key should sign.
*/
isc_stdtime_t when;
isc_result_t kresult;
bool ksk = false;
bool zsk = false;
kresult = dst_key_getbool(keys[i], DST_BOOL_KSK, &ksk);
if (kresult != ISC_R_SUCCESS) {
if (KSK(keys[i])) {
ksk = true;
}
}
kresult = dst_key_getbool(keys[i], DST_BOOL_ZSK, &zsk);
if (kresult != ISC_R_SUCCESS) {
if (!KSK(keys[i])) {
zsk = true;
}
}
if (type == dns_rdatatype_dnskey ||
type == dns_rdatatype_cdnskey ||
type == dns_rdatatype_cds)
{
/*
* DNSKEY RRset is signed with KSK.
* CDS and CDNSKEY RRsets too (RFC 7344, 4.1).
*/
if (!ksk) {
continue;
}
} else if (!zsk) {
/*
* Other RRsets are signed with ZSK.
*/
continue;
} else if (zsk && !dst_key_is_signing(keys[i],
DST_BOOL_ZSK,
inception,
&when)) {
/*
* This key is not active for zone-signing.
*/
continue;
}
/*
* If this key is revoked, it may only sign the
* DNSKEY RRset.
*/
if (REVOKE(keys[i]) && type != dns_rdatatype_dnskey) {
continue;
}
} else if (both) {
/*
* CDS and CDNSKEY are signed with KSK (RFC 7344, 4.1).
*/

View file

@ -316,6 +316,7 @@ dns_dns64_next
dns_dns64_unlink
dns_dnssec_findmatchingkeys
dns_dnssec_findzonekeys
dns_dnssec_get_hints
dns_dnssec_keyactive
dns_dnssec_keyfromrdata
dns_dnssec_keylistfromrdataset
@ -413,9 +414,50 @@ dns_journal_rollforward
dns_journal_set_sourceserial
dns_journal_write_transaction
dns_journal_writediff
dns_kasp_addkey
dns_kasp_attach
dns_kasp_create
dns_kasp_detach
dns_kasp_dnskeyttl
dns_kasp_dsttl
dns_kasp_freeze
dns_kasp_getname
dns_kasp_key_algorithm
dns_kasp_key_create
dns_kasp_key_destroy
dns_kasp_key_ksk
dns_kasp_key_lifetime
dns_kasp_key_size
dns_kasp_key_zsk
dns_kasp_keylist_empty
dns_kasp_keys
dns_kasp_parentpropagationdelay
dns_kasp_parentregistrationdelay
dns_kasp_publishsafety
dns_kasp_retiresafety
dns_kasp_setdnskeyttl
dns_kasp_setdsttl
dns_kasp_setparentpropagationdelay
dns_kasp_setparentregistrationdelay
dns_kasp_setpublishsafety
dns_kasp_setretiresafety
dns_kasp_setsigrefresh
dns_kasp_setsigvalidity
dns_kasp_setsigvalidity_dnskey
dns_kasp_setzonemaxttl
dns_kasp_setzonepropagationdelay
dns_kasp_signdelay
dns_kasp_sigrefresh
dns_kasp_sigvalidity
dns_kasp_sigvalidity_dnskey
dns_kasp_thaw
dns_kasp_zonemaxttl
dns_kasp_zonepropagationdelay
dns_kasplist_find
dns_keydata_fromdnskey
dns_keydata_todnskey
dns_keyflags_fromtext
dns_keymgr_run
dns_keynode_attach
dns_keynode_create
dns_keynode_detach
@ -1154,6 +1196,7 @@ dns_zone_getidleout
dns_zone_getincludes
dns_zone_getjournal
dns_zone_getjournalsize
dns_zone_getkasp
dns_zone_getkeydirectory
dns_zone_getkeyopts
dns_zone_getkeyvalidityinterval
@ -1255,6 +1298,7 @@ dns_zone_setidleout
dns_zone_setisself
dns_zone_setjournal
dns_zone_setjournalsize
dns_zone_setkasp
dns_zone_setkeydirectory
dns_zone_setkeyopt
dns_zone_setkeyvalidityinterval
@ -1375,6 +1419,7 @@ dst_key_attach
dst_key_buildfilename
dst_key_buildinternal
dst_key_class
dst_key_copy_metadata
dst_key_compare
dst_key_computesecret
dst_key_dump
@ -1389,13 +1434,21 @@ dst_key_fromlabel
dst_key_fromnamedfile
dst_key_generate
dst_key_getbits
dst_key_getbool
dst_key_getfilename
dst_key_getgssctx
dst_key_getnum
dst_key_getprivateformat
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
@ -1407,15 +1460,18 @@ dst_key_privatefrombuffer
dst_key_proto
dst_key_pubcompare
dst_key_read_public
dst_key_read_state
dst_key_restore
dst_key_rid
dst_key_secretsize
dst_key_setbits
dst_key_setbool
dst_key_setexternal
dst_key_setflags
dst_key_setinactive
dst_key_setnum
dst_key_setprivateformat
dst_key_setstate
dst_key_settime
dst_key_setttl
dst_key_sigsize
@ -1424,7 +1480,9 @@ dst_key_tkeytoken
dst_key_tobuffer
dst_key_todns
dst_key_tofile
dst_key_unsetbool
dst_key_unsetnum
dst_key_unsetstate
dst_key_unsettime
dst_lib_destroy
dst_lib_init

View file

@ -116,9 +116,15 @@
<ClCompile Include="..\journal.c">
<Filter>Library Source Files</Filter>
</ClCompile>
<ClCompile Include="..\kasp.c">
<Filter>Library Source Files</Filter>
</ClCompile>
<ClCompile Include="..\keydata.c">
<Filter>Library Source Files</Filter>
</ClCompile>
<ClCompile Include="..\keymgr.c">
<Filter>Library Source Files</Filter>
</ClCompile>
<ClCompile Include="..\keytable.c">
<Filter>Library Source Files</Filter>
</ClCompile>
@ -449,12 +455,18 @@
<ClInclude Include="..\include\dns\journal.h">
<Filter>Library Header Files</Filter>
</ClInclude>
<ClInclude Include="..\include\dns\kasp.h">
<Filter>Library Header Files</Filter>
</ClInclude>
<ClInclude Include="..\include\dns\keydata.h">
<Filter>Library Header Files</Filter>
</ClInclude>
<ClInclude Include="..\include\dns\keyflags.h">
<Filter>Library Header Files</Filter>
</ClInclude>
<ClInclude Include="..\include\dns\keymgr.h">
<Filter>Library Header Files</Filter>
</ClInclude>
<ClInclude Include="..\include\dns\keytable.h">
<Filter>Library Header Files</Filter>
</ClInclude>

View file

@ -150,7 +150,9 @@
<ClCompile Include="..\ipkeylist.c" />
<ClCompile Include="..\iptable.c" />
<ClCompile Include="..\journal.c" />
<ClCompile Include="..\kasp.c" />
<ClCompile Include="..\key.c" />
<ClCompile Include="..\keymgr.c" />
<ClCompile Include="..\keydata.c" />
<ClCompile Include="..\keytable.c" />
<ClCompile Include="..\lib.c" />
@ -265,8 +267,10 @@
<ClInclude Include="..\include\dns\ipkeylist.h" />
<ClInclude Include="..\include\dns\iptable.h" />
<ClInclude Include="..\include\dns\journal.h" />
<ClInclude Include="..\include\dns\kasp.h" />
<ClInclude Include="..\include\dns\keydata.h" />
<ClInclude Include="..\include\dns\keyflags.h" />
<ClInclude Include="..\include\dns\keymgr.h" />
<ClInclude Include="..\include\dns\keytable.h" />
<ClInclude Include="..\include\dns\keyvalues.h" />
<ClInclude Include="..\include\dns\lib.h" />

View file

@ -45,7 +45,9 @@
#include <dns/dnssec.h>
#include <dns/events.h>
#include <dns/journal.h>
#include <dns/kasp.h>
#include <dns/keydata.h>
#include <dns/keymgr.h>
#include <dns/keytable.h>
#include <dns/keyvalues.h>
#include <dns/log.h>
@ -303,6 +305,7 @@ struct dns_zone {
uint32_t sigresigninginterval;
dns_view_t *view;
dns_view_t *prev_view;
dns_kasp_t *kasp;
dns_checkmxfunc_t checkmx;
dns_checksrvfunc_t checksrv;
dns_checknsfunc_t checkns;
@ -1014,6 +1017,7 @@ dns_zone_create(dns_zone_t **zonep, isc_mem_t *mctx) {
zone->sigvalidityinterval = 30 * 24 * 3600;
zone->keyvalidityinterval = 0;
zone->sigresigninginterval = 7 * 24 * 3600;
zone->kasp = NULL;
zone->view = NULL;
zone->prev_view = NULL;
zone->checkmx = NULL;
@ -1184,6 +1188,9 @@ zone_free(dns_zone_t *zone) {
isc_mem_free(zone->mctx, zone->keydirectory);
}
zone->keydirectory = NULL;
if (zone->kasp != NULL) {
dns_kasp_detach(&zone->kasp);
}
zone->journalsize = -1;
if (zone->journal != NULL) {
isc_mem_free(zone->mctx, zone->journal);
@ -1880,7 +1887,7 @@ zone_load(dns_zone_t *zone, unsigned int flags, bool locked) {
isc_time_t now;
isc_time_t loadtime;
dns_db_t *db = NULL;
bool rbt, hasraw;
bool rbt, hasraw, is_dynamic;
REQUIRE(DNS_ZONE_VALID(zone));
@ -1945,11 +1952,13 @@ zone_load(dns_zone_t *zone, unsigned int flags, bool locked) {
goto cleanup;
}
if (zone->db != NULL && dns_zone_isdynamic(zone, false)) {
is_dynamic = dns_zone_isdynamic(zone, false) ||
dns_zone_getkasp(zone) != NULL;
if (zone->db != NULL && is_dynamic) {
/*
* This is a slave, stub, or dynamically updated
* zone being reloaded. Do nothing - the database
* we already have is guaranteed to be up-to-date.
* This is a slave, stub, dynamically updated, or kasp enabled
* zone being reloaded. Do nothing - the database we already
* have is guaranteed to be up-to-date.
*/
if (zone->type == dns_zone_master && !hasraw)
result = DNS_R_DYNAMIC;
@ -3647,8 +3656,9 @@ set_resigntime(dns_zone_t *zone) {
dns_db_t *db = NULL;
/* We only re-sign zones that can be dynamically updated */
if (zone->update_disabled)
if (zone->update_disabled) {
return;
}
if (!inline_secure(zone) && (zone->type != dns_zone_master ||
(zone->ssutable == NULL &&
@ -3674,10 +3684,11 @@ set_resigntime(dns_zone_t *zone) {
goto cleanup;
}
resign = rdataset.resign - zone->sigresigninginterval;
resign = rdataset.resign - dns_zone_getsigresigninginterval(zone);
dns_rdataset_disassociate(&rdataset);
nanosecs = isc_random_uniform(1000000000);
isc_time_set(&zone->resigntime, resign, nanosecs);
cleanup:
dns_db_detach(&db);
return;
@ -3694,6 +3705,7 @@ check_nsec3param(dns_zone_t *zone, dns_db_t *db) {
dns_rdata_t rdata = DNS_RDATA_INIT;
bool dynamic = (zone->type == dns_zone_master)
? dns_zone_isdynamic(zone, false) : false;
dynamic = dynamic || dns_zone_getkasp(zone);
dns_rdataset_init(&rdataset);
result = dns_db_findnode(db, &zone->origin, false, &node);
@ -4500,6 +4512,7 @@ zone_postload(dns_zone_t *zone, dns_db_t *db, isc_time_t loadtime,
bool had_db = false;
unsigned int options;
dns_include_t *inc;
bool is_dynamic = false;
INSIST(LOCKED_ZONE(zone));
if (inline_raw(zone)) {
@ -4640,7 +4653,9 @@ zone_postload(dns_zone_t *zone, dns_db_t *db, isc_time_t loadtime,
* journal file if it isn't, as we wouldn't be able to apply
* updates otherwise.
*/
if (zone->journal != NULL && dns_zone_isdynamic(zone, true) &&
is_dynamic = dns_zone_isdynamic(zone, true) ||
dns_zone_getkasp(zone) != NULL;
if (zone->journal != NULL && is_dynamic &&
! DNS_ZONE_OPTION(zone, DNS_ZONEOPT_IXFRFROMDIFFS))
{
uint32_t jserial;
@ -4812,7 +4827,7 @@ zone_postload(dns_zone_t *zone, dns_db_t *db, isc_time_t loadtime,
if (zone->type == dns_zone_master &&
(zone->update_acl != NULL || zone->ssutable != NULL) &&
zone->sigresigninginterval < (3 * refresh) &&
dns_zone_getsigresigninginterval(zone) < (3 * refresh) &&
dns_db_issecure(db))
{
dns_zone_logc(zone, DNS_LOGCATEGORY_ZONELOAD,
@ -4944,10 +4959,11 @@ zone_postload(dns_zone_t *zone, dns_db_t *db, isc_time_t loadtime,
resume_addnsec3chain(zone);
}
is_dynamic = dns_zone_isdynamic(zone, false) ||
dns_zone_getkasp(zone) != NULL;
if (zone->type == dns_zone_master &&
!DNS_ZONEKEY_OPTION(zone, DNS_ZONEKEY_NORESIGN) &&
dns_zone_isdynamic(zone, false) &&
dns_db_issecure(db))
is_dynamic && dns_db_issecure(db))
{
dns_name_t *name;
dns_fixedname_t fixed;
@ -4970,7 +4986,7 @@ zone_postload(dns_zone_t *zone, dns_db_t *db, isc_time_t loadtime,
"next resign: %s/%s "
"in %d seconds", namebuf, typebuf,
next.resign - timenow -
zone->sigresigninginterval);
dns_zone_getsigresigninginterval(zone));
dns_rdataset_disassociate(&next);
} else {
dnssec_log(zone, ISC_LOG_WARNING,
@ -5007,7 +5023,7 @@ zone_postload(dns_zone_t *zone, dns_db_t *db, isc_time_t loadtime,
zone->nincludes++;
}
if (! dns_db_ispersistent(db)) {
if (!dns_db_ispersistent(db)) {
dns_zone_logc(zone, DNS_LOGCATEGORY_ZONELOAD,
ISC_LOG_INFO, "loaded serial %u%s", serial,
dns_db_issecure(db) ? " (DNSSEC signed)" : "");
@ -5063,7 +5079,7 @@ zone_postload(dns_zone_t *zone, dns_db_t *db, isc_time_t loadtime,
} else if (zone->type == dns_zone_master ||
zone->type == dns_zone_redirect)
{
if (! (inline_secure(zone) && result == ISC_R_FILENOTFOUND)) {
if (!(inline_secure(zone) && result == ISC_R_FILENOTFOUND)) {
dns_zone_logc(zone, DNS_LOGCATEGORY_ZONELOAD,
ISC_LOG_ERROR,
"not loaded due to errors.");
@ -5537,6 +5553,29 @@ dns_zone_setflag(dns_zone_t *zone, unsigned int flags, bool value) {
}
}
void
dns_zone_setkasp(dns_zone_t *zone, dns_kasp_t* kasp)
{
REQUIRE(DNS_ZONE_VALID(zone));
LOCK_ZONE(zone);
if (zone->kasp != NULL) {
dns_kasp_t* oldkasp = zone->kasp;
zone->kasp = NULL;
dns_kasp_detach(&oldkasp);
}
zone->kasp = kasp;
UNLOCK_ZONE(zone);
}
dns_kasp_t*
dns_zone_getkasp(dns_zone_t *zone)
{
REQUIRE(DNS_ZONE_VALID(zone));
return (zone->kasp);
}
void
dns_zone_setoption(dns_zone_t *zone, dns_zoneopt_t option,
bool value)
@ -6231,22 +6270,41 @@ delsig_ok(dns_rdata_rrsig_t *rrsig_ptr, dst_key_t **keys, unsigned int nkeys,
bool *warn)
{
unsigned int i = 0;
isc_result_t ret;
bool have_ksk = false, have_zsk = false;
bool have_pksk = false, have_pzsk = false;
for (i = 0; i < nkeys; i++) {
if (rrsig_ptr->algorithm != dst_key_alg(keys[i]))
bool ksk, zsk;
if (have_pksk && have_ksk && have_pzsk && have_zsk) {
break;
}
if (rrsig_ptr->algorithm != dst_key_alg(keys[i])) {
continue;
if (dst_key_isprivate(keys[i])) {
if (KSK(keys[i]))
have_ksk = have_pksk = true;
else
have_zsk = have_pzsk = true;
} else {
if (KSK(keys[i]))
have_ksk = true;
else
have_zsk = true;
}
ret = dst_key_getbool(keys[i], DST_BOOL_KSK, &ksk);
if (ret != ISC_R_SUCCESS) {
ksk = KSK(keys[i]);
}
ret = dst_key_getbool(keys[i], DST_BOOL_ZSK, &zsk);
if (ret != ISC_R_SUCCESS) {
zsk = !KSK(keys[i]);
}
if (ksk) {
have_ksk = true;
if (dst_key_isprivate(keys[i])) {
have_pksk = true;
}
}
if (zsk) {
have_zsk = true;
if (dst_key_isprivate(keys[i])) {
have_pzsk = true;
}
}
}
@ -6325,7 +6383,9 @@ del_sigs(dns_zone_t *zone, dns_db_t *db, dns_dbversion_t *ver, dns_name_t *name,
result = dns_rdata_tostruct(&rdata, &rrsig, NULL);
RUNTIME_CHECK(result == ISC_R_SUCCESS);
if (type != dns_rdatatype_dnskey) {
if (type != dns_rdatatype_dnskey &&
type != dns_rdatatype_cds &&
type != dns_rdatatype_cdnskey) {
bool warn = false, deleted = false;
if (delsig_ok(&rrsig, keys, nkeys, &warn)) {
result = update_one_rr(db, ver, zonediff->diff,
@ -6380,7 +6440,7 @@ del_sigs(dns_zone_t *zone, dns_db_t *db, dns_dbversion_t *ver, dns_name_t *name,
}
/*
* RRSIG(DNSKEY) requires special processing.
* KSK RRSIGs requires special processing.
*/
found = false;
for (i = 0; i < nkeys; i++) {
@ -6388,7 +6448,7 @@ del_sigs(dns_zone_t *zone, dns_db_t *db, dns_dbversion_t *ver, dns_name_t *name,
rrsig.keyid == dst_key_id(keys[i])) {
found = true;
/*
* Mark offline RRSIG(DNSKEY).
* Mark offline DNSKEY.
* We want the earliest offline expire time
* iff there is a new offline signature.
*/
@ -6465,6 +6525,7 @@ add_sigs(dns_db_t *db, dns_dbversion_t *ver, dns_name_t *name,
{
isc_result_t result;
dns_dbnode_t *node = NULL;
dns_kasp_t *kasp = dns_zone_getkasp(zone);
dns_stats_t* dnssecsignstats;
dns_stats_t* dnssecrefreshstats;
dns_rdataset_t rdataset;
@ -6473,6 +6534,11 @@ add_sigs(dns_db_t *db, dns_dbversion_t *ver, dns_name_t *name,
isc_buffer_t buffer;
unsigned int i, j;
if (kasp != NULL) {
check_ksk = false;
keyset_kskonly = true;
}
dns_rdataset_init(&rdataset);
isc_buffer_init(&buffer, data, sizeof(data));
@ -6546,7 +6612,61 @@ add_sigs(dns_db_t *db, dns_dbversion_t *ver, dns_name_t *name,
}
}
if (both) {
if (kasp != NULL) {
/*
* A dnssec-policy is found. Check what RRsets this
* key should sign.
*/
isc_result_t kresult;
isc_stdtime_t when;
bool ksk = false;
bool zsk = false;
kresult = dst_key_getbool(keys[i], DST_BOOL_KSK, &ksk);
if (kresult != ISC_R_SUCCESS) {
if (KSK(keys[i])) {
ksk = true;
}
}
kresult = dst_key_getbool(keys[i], DST_BOOL_ZSK, &zsk);
if (kresult != ISC_R_SUCCESS) {
if (!KSK(keys[i])) {
zsk = true;
}
}
if (type == dns_rdatatype_dnskey ||
type == dns_rdatatype_cdnskey ||
type == dns_rdatatype_cds)
{
/*
* DNSKEY RRset is signed with KSK.
* CDS and CDNSKEY RRsets too (RFC 7344, 4.1).
*/
if (!ksk) {
continue;
}
} else if (!zsk) {
/*
* Other RRsets are signed with ZSK.
*/
continue;
} else if (!dst_key_is_signing(keys[i], DST_BOOL_ZSK,
inception, &when)) {
/*
* This key is not active for zone-signing.
*/
continue;
}
/*
* If this key is revoked, it may only sign the
* DNSKEY RRset.
*/
if (REVOKE(keys[i]) && type != dns_rdatatype_dnskey) {
continue;
}
} else if (both) {
/*
* CDS and CDNSKEY are signed with KSK (RFC 7344, 4.1).
*/
@ -6659,7 +6779,7 @@ zone_resigninc(dns_zone_t *zone) {
goto failure;
}
sigvalidityinterval = zone->sigvalidityinterval;
sigvalidityinterval = dns_zone_getsigvalidityinterval(zone);
inception = now - 3600; /* Allow for clock skew. */
soaexpire = now + sigvalidityinterval;
expiryinterval = dns_zone_getsigresigninginterval(zone);
@ -6706,7 +6826,8 @@ zone_resigninc(dns_zone_t *zone) {
i = 0;
while (result == ISC_R_SUCCESS) {
resign = rdataset.resign - zone->sigresigninginterval;
resign = rdataset.resign -
dns_zone_getsigresigninginterval(zone);
covers = rdataset.covers;
dns_rdataset_disassociate(&rdataset);
@ -6878,13 +6999,16 @@ next_active(dns_db_t *db, dns_dbversion_t *version, dns_name_t *oldname,
}
static bool
signed_with_key(dns_db_t *db, dns_dbnode_t *node, dns_dbversion_t *version,
dns_rdatatype_t type, dst_key_t *key)
signed_with_good_key(dns_zone_t* zone, dns_db_t *db, dns_dbnode_t *node,
dns_dbversion_t *version, dns_rdatatype_t type,
dst_key_t *key)
{
isc_result_t result;
dns_rdataset_t rdataset;
dns_rdata_t rdata = DNS_RDATA_INIT;
dns_rdata_rrsig_t rrsig;
int count = 0;
dns_kasp_t *kasp = dns_zone_getkasp(zone);
dns_rdataset_init(&rdataset);
result = dns_db_findrdataset(db, node, version, dns_rdatatype_rrsig,
@ -6904,8 +7028,46 @@ signed_with_key(dns_db_t *db, dns_dbnode_t *node, dns_dbversion_t *version,
dns_rdataset_disassociate(&rdataset);
return (true);
}
if (rrsig.algorithm == dst_key_alg(key)) {
count++;
}
dns_rdata_reset(&rdata);
}
if (kasp) {
dns_kasp_key_t* kkey;
int zsk_count = 0;
bool approved;
for (kkey = ISC_LIST_HEAD(dns_kasp_keys(kasp)); kkey != NULL;
kkey = ISC_LIST_NEXT(kkey, link))
{
if (dns_kasp_key_algorithm(kkey) != dst_key_alg(key)) {
continue;
}
if (dns_kasp_key_zsk(kkey)) {
zsk_count++;
}
}
if (type == dns_rdatatype_dnskey ||
type == dns_rdatatype_cdnskey || type == dns_rdatatype_cds)
{
/*
* CDS and CDNSKEY are signed with KSK like DNSKEY.
* (RFC 7344, section 4.1 specifies that they must
* be signed with a key in the current DS RRset,
* which would only include KSK's.)
*/
approved = false;
} else {
approved = (zsk_count == count);
}
dns_rdataset_disassociate(&rdataset);
return (approved);
}
dns_rdataset_disassociate(&rdataset);
return (false);
}
@ -6988,11 +7150,12 @@ sign_a_node(dns_db_t *db, dns_zone_t *zone, dns_name_t *name,
dns_dbnode_t *node, dns_dbversion_t *version,
bool build_nsec3, bool build_nsec, dst_key_t *key,
isc_stdtime_t inception, isc_stdtime_t expire,
unsigned int minimum, bool is_ksk,
unsigned int minimum, bool is_ksk, bool is_zsk,
bool keyset_kskonly, bool is_bottom_of_zone,
dns_diff_t *diff, int32_t *signatures, isc_mem_t *mctx)
{
isc_result_t result;
dns_kasp_t *kasp = dns_zone_getkasp(zone);
dns_rdatasetiter_t *iterator = NULL;
dns_rdataset_t rdataset;
dns_rdata_t rdata = DNS_RDATA_INIT;
@ -7060,6 +7223,8 @@ sign_a_node(dns_db_t *db, dns_zone_t *zone, dns_name_t *name,
}
result = dns_rdatasetiter_first(iterator);
while (result == ISC_R_SUCCESS) {
isc_stdtime_t when;
dns_rdatasetiter_current(iterator, &rdataset);
if (rdataset.type == dns_rdatatype_soa ||
rdataset.type == dns_rdatatype_rrsig)
@ -7079,18 +7244,26 @@ sign_a_node(dns_db_t *db, dns_zone_t *zone, dns_name_t *name,
if (!is_ksk && keyset_kskonly) {
goto next_rdataset;
}
} else if (is_ksk) {
} else if (!is_zsk) {
goto next_rdataset;
} else if (is_zsk && !dst_key_is_signing(key, DST_BOOL_ZSK,
inception, &when)) {
/* Only applies to dnssec-policy. */
if (kasp != NULL) {
goto next_rdataset;
}
}
if (seen_ns && !seen_soa &&
rdataset.type != dns_rdatatype_ds &&
rdataset.type != dns_rdatatype_nsec)
{
goto next_rdataset;
}
if (signed_with_key(db, node, version, rdataset.type, key)) {
if (signed_with_good_key(zone, db, node, version, rdataset.type, key)) {
goto next_rdataset;
}
/* Calculate the signature, creating a RRSIG RDATA. */
isc_buffer_clear(&buffer);
CHECK(dns_dnssec_sign(name, &rdataset, key, &inception,
@ -8680,13 +8853,14 @@ zone_sign(dns_zone_t *zone) {
dns__zonediff_t zonediff;
dns_fixedname_t fixed;
dns_fixedname_t nextfixed;
dns_kasp_t *kasp;
dns_name_t *name, *nextname;
dns_rdataset_t rdataset;
dns_signing_t *signing, *nextsigning;
dns_signinglist_t cleanup;
dst_key_t *zone_keys[DNS_MAXZONEKEYS];
int32_t signatures;
bool check_ksk, keyset_kskonly, is_ksk;
bool check_ksk, keyset_kskonly, is_ksk, is_zsk;
bool with_ksk, with_zsk;
bool commit = false;
bool is_bottom_of_zone;
@ -8747,6 +8921,8 @@ zone_sign(dns_zone_t *zone) {
goto cleanup;
}
kasp = dns_zone_getkasp(zone);
sigvalidityinterval = dns_zone_getsigvalidityinterval(zone);
inception = now - 3600; /* Allow for clock skew. */
soaexpire = now + sigvalidityinterval;
@ -8783,8 +8959,10 @@ zone_sign(dns_zone_t *zone) {
signing = ISC_LIST_HEAD(zone->signing);
first = true;
check_ksk = DNS_ZONE_OPTION(zone, DNS_ZONEOPT_UPDATECHECKKSK);
keyset_kskonly = DNS_ZONE_OPTION(zone, DNS_ZONEOPT_DNSKEYKSKONLY);
check_ksk = (kasp != NULL) ? false :
DNS_ZONE_OPTION(zone, DNS_ZONEOPT_UPDATECHECKKSK);
keyset_kskonly = (kasp != NULL) ? true :
DNS_ZONE_OPTION(zone, DNS_ZONEOPT_DNSKEYKSKONLY);
/* Determine which type of chain to build */
CHECK(dns_private_chains(db, version, zone->privatetype,
@ -8802,7 +8980,7 @@ zone_sign(dns_zone_t *zone) {
ZONEDB_LOCK(&zone->dblock, isc_rwlocktype_read);
if (signing->done || signing->db != zone->db) {
/*
* The zone has been reloaded. We will have
* The zone has been reloaded. We will have to
* created new signings as part of the reload
* process so we can destroy this one.
*/
@ -8830,8 +9008,15 @@ zone_sign(dns_zone_t *zone) {
if (ALG(zone_keys[i]) == signing->algorithm &&
dst_key_id(zone_keys[i]) == signing->keyid)
{
if (KSK(zone_keys[i]))
bool ksk = false;
isc_result_t ret = dst_key_getbool(
zone_keys[i], DST_BOOL_KSK, &ksk);
if (ret != ISC_R_SUCCESS) {
ksk = KSK(zone_keys[i]);
}
if (ksk) {
dst_key_free(&zone_keys[i]);
}
continue;
}
zone_keys[j] = zone_keys[i];
@ -8962,10 +9147,39 @@ zone_sign(dns_zone_t *zone) {
}
}
}
if (both || REVOKE(zone_keys[i])) {
if (kasp != NULL) {
/*
* A dnssec-policy is found. Check what
* RRsets this key can sign.
*/
isc_result_t kresult;
is_ksk = false;
kresult = dst_key_getbool(zone_keys[i],
DST_BOOL_KSK,
&is_ksk);
if (kresult != ISC_R_SUCCESS) {
if (KSK(zone_keys[i])) {
is_ksk = true;
}
}
is_zsk = false;
kresult = dst_key_getbool(zone_keys[i],
DST_BOOL_ZSK,
&is_zsk);
if (kresult != ISC_R_SUCCESS) {
if (!KSK(zone_keys[i])) {
is_zsk = true;
}
}
/* Treat as if we have both KSK and ZSK. */
both = true;
} else if (both || REVOKE(zone_keys[i])) {
is_ksk = KSK(zone_keys[i]);
is_zsk = !KSK(zone_keys[i]);
} else {
is_ksk = false;
is_zsk = true;
}
/*
@ -8973,7 +9187,7 @@ zone_sign(dns_zone_t *zone) {
* the RRset is still signed at least once by a
* KSK and a ZSK.
*/
if (signing->deleteit && !is_ksk && with_zsk) {
if (signing->deleteit && is_zsk && with_zsk) {
continue;
}
@ -8984,7 +9198,7 @@ zone_sign(dns_zone_t *zone) {
CHECK(sign_a_node(db, zone, name, node, version,
build_nsec3, build_nsec,
zone_keys[i], inception, expire,
zone->minimum, is_ksk,
zone->minimum, is_ksk, is_zsk,
(both && keyset_kskonly),
is_bottom_of_zone, zonediff.diff,
&signatures, zone->mctx));
@ -8995,10 +9209,10 @@ zone_sign(dns_zone_t *zone) {
if (!signing->deleteit) {
break;
}
if (!is_ksk) {
if (is_zsk) {
with_zsk = true;
}
if (KSK(zone_keys[i])) {
if (is_ksk) {
with_ksk = true;
}
}
@ -15317,8 +15531,14 @@ receive_secure_db(isc_task_t *task, isc_event_t *event) {
rdataset.type == dns_rdatatype_nsec3 ||
rdataset.type == dns_rdatatype_dnskey ||
rdataset.type == dns_rdatatype_nsec3param) {
dns_rdataset_disassociate(&rdataset);
continue;
/*
* Allow DNSSEC records with dnssec-policy.
* WMM: Perhaps add config option for it.
*/
if (dns_zone_getkasp(zone) == NULL) {
dns_rdataset_disassociate(&rdataset);
continue;
}
}
if (rdataset.type == dns_rdatatype_soa &&
have_oldserial) {
@ -18150,6 +18370,57 @@ add_signing_records(dns_db_t *db, dns_rdatatype_t privatetype,
return (result);
}
/*
* See if dns__zone_updatesigs() will update signature for RRset 'rrtype' at
* the apex, and if not tickle them and cause to sign so that newly activated
* keys are used.
*/
static isc_result_t
tickle_apex_rrset(dns_rdatatype_t rrtype, dns_zone_t *zone, dns_db_t *db,
dns_dbversion_t *ver, isc_stdtime_t now, dns_diff_t *diff,
dns__zonediff_t *zonediff, dst_key_t **keys,
unsigned int nkeys, isc_stdtime_t inception,
isc_stdtime_t keyexpire, bool check_ksk, bool keyset_kskonly)
{
dns_difftuple_t *tuple;
isc_result_t result;
for (tuple = ISC_LIST_HEAD(diff->tuples);
tuple != NULL;
tuple = ISC_LIST_NEXT(tuple, link))
{
if (tuple->rdata.type == rrtype &&
dns_name_equal(&tuple->name, &zone->origin))
{
break;
}
}
if (tuple == NULL) {
result = del_sigs(zone, db, ver, &zone->origin, rrtype,
zonediff, keys, nkeys, now, false);
if (result != ISC_R_SUCCESS) {
dnssec_log(zone, ISC_LOG_ERROR,
"sign_apex:del_sigs -> %s",
dns_result_totext(result));
return (result);
}
result = add_sigs(db, ver, &zone->origin, zone, rrtype,
zonediff->diff, keys, nkeys, zone->mctx,
inception, keyexpire, check_ksk,
keyset_kskonly);
if (result != ISC_R_SUCCESS) {
dnssec_log(zone, ISC_LOG_ERROR,
"sign_apex:add_sigs -> %s",
dns_result_totext(result));
return (result);
}
}
return (ISC_R_SUCCESS);
}
static isc_result_t
sign_apex(dns_zone_t *zone, dns_db_t *db, dns_dbversion_t *ver,
isc_stdtime_t now, dns_diff_t *diff, dns__zonediff_t *zonediff)
@ -18159,7 +18430,6 @@ sign_apex(dns_zone_t *zone, dns_db_t *db, dns_dbversion_t *ver,
bool check_ksk, keyset_kskonly;
dst_key_t *zone_keys[DNS_MAXZONEKEYS];
unsigned int nkeys = 0, i;
dns_difftuple_t *tuple;
result = dns__zone_findkeys(zone, db, ver, now, zone->mctx,
DNS_MAXZONEKEYS, zone_keys, &nkeys);
@ -18184,40 +18454,27 @@ sign_apex(dns_zone_t *zone, dns_db_t *db, dns_dbversion_t *ver,
keyset_kskonly = DNS_ZONE_OPTION(zone, DNS_ZONEOPT_DNSKEYKSKONLY);
/*
* See if dns__zone_updatesigs() will update DNSKEY signature and if
* not cause them to sign so that newly activated keys are used.
* See if dns__zone_updatesigs() will update DNSKEY/CDS/CDNSKEY
* signature and if not cause them to sign so that newly activated
* keys are used.
*/
for (tuple = ISC_LIST_HEAD(diff->tuples);
tuple != NULL;
tuple = ISC_LIST_NEXT(tuple, link))
{
if (tuple->rdata.type == dns_rdatatype_dnskey &&
dns_name_equal(&tuple->name, &zone->origin))
{
break;
}
result = tickle_apex_rrset(dns_rdatatype_dnskey, zone, db, ver, now,
diff, zonediff, zone_keys, nkeys, inception,
keyexpire, check_ksk, keyset_kskonly);
if (result != ISC_R_SUCCESS) {
goto failure;
}
if (tuple == NULL) {
result = del_sigs(zone, db, ver, &zone->origin,
dns_rdatatype_dnskey, zonediff,
zone_keys, nkeys, now, false);
if (result != ISC_R_SUCCESS) {
dnssec_log(zone, ISC_LOG_ERROR,
"sign_apex:del_sigs -> %s",
dns_result_totext(result));
goto failure;
}
result = add_sigs(db, ver, &zone->origin, zone,
dns_rdatatype_dnskey, zonediff->diff,
zone_keys, nkeys, zone->mctx, inception,
keyexpire, check_ksk, keyset_kskonly);
if (result != ISC_R_SUCCESS) {
dnssec_log(zone, ISC_LOG_ERROR,
"sign_apex:add_sigs -> %s",
dns_result_totext(result));
goto failure;
}
result = tickle_apex_rrset(dns_rdatatype_cds, zone, db, ver, now,
diff, zonediff, zone_keys, nkeys, inception,
keyexpire, check_ksk, keyset_kskonly);
if (result != ISC_R_SUCCESS) {
goto failure;
}
result = tickle_apex_rrset(dns_rdatatype_cdnskey, zone, db, ver, now,
diff, zonediff, zone_keys, nkeys, inception,
keyexpire, check_ksk, keyset_kskonly);
if (result != ISC_R_SUCCESS) {
goto failure;
}
result = dns__zone_updatesigs(diff, db, ver, zone_keys, nkeys, zone,
@ -18394,6 +18651,7 @@ zone_rekey(dns_zone_t *zone) {
dns_dnsseckeylist_t dnskeys, keys, rmkeys;
dns_dnsseckey_t *key = NULL;
dns_diff_t diff, _sig_diff;
dns_kasp_t *kasp;
dns__zonediff_t zonediff;
bool commit = false, newactive = false;
bool newalg = false;
@ -18401,7 +18659,7 @@ zone_rekey(dns_zone_t *zone) {
dns_ttl_t ttl = 3600;
const char *dir = NULL;
isc_mem_t *mctx = NULL;
isc_stdtime_t now;
isc_stdtime_t now, nexttime = 0;
isc_time_t timenow;
isc_interval_t ival;
char timebuf[80];
@ -18470,17 +18728,34 @@ zone_rekey(dns_zone_t *zone) {
* True when called from "rndc sign". Indicates the zone should be
* fully signed now.
*/
kasp = dns_zone_getkasp(zone);
fullsign = DNS_ZONEKEY_OPTION(zone, DNS_ZONEKEY_FULLSIGN);
result = dns_dnssec_findmatchingkeys(&zone->origin, dir, now, mctx,
&keys);
if (result != ISC_R_SUCCESS) {
dnssec_log(zone, ISC_LOG_DEBUG(1),
"zone_rekey:dns_dnssec_findmatchingkeys failed: %s",
isc_result_totext(result));
}
if (kasp && (result == ISC_R_SUCCESS || result == ISC_R_NOTFOUND)) {
ttl = dns_kasp_dnskeyttl(kasp);
result = dns_keymgr_run(&zone->origin, zone->rdclass, dir,
mctx, &keys, kasp, now, &nexttime);
if (result != ISC_R_SUCCESS) {
dnssec_log(zone, ISC_LOG_ERROR,
"zone_rekey:dns_dnssec_keymgr failed: %s",
isc_result_totext(result));
goto failure;
}
}
if (result == ISC_R_SUCCESS) {
bool check_ksk;
check_ksk = DNS_ZONE_OPTION(zone, DNS_ZONEOPT_UPDATECHECKKSK);
result = dns_dnssec_updatekeys(&dnskeys, &keys, &rmkeys,
&zone->origin, ttl, &diff,
!check_ksk, mctx,
dnssec_report);
mctx, dnssec_report);
/*
* Keys couldn't be updated for some reason;
* try again later.
@ -18531,7 +18806,7 @@ zone_rekey(dns_zone_t *zone) {
/*
* This isn't a new algorithm; clear
* first_sign so we won't sign the
* whole zone with this key later
* whole zone with this key later.
*/
key->first_sign = false;
} else {
@ -18698,12 +18973,30 @@ zone_rekey(dns_zone_t *zone) {
isc_time_settoepoch(&zone->refreshkeytime);
/*
* If keymgr provided a next time, use the calculated next rekey time.
*/
if (kasp != NULL && nexttime > 0) {
isc_time_t timenext;
LOCK_ZONE(zone);
DNS_ZONE_TIME_ADD(&timenow, nexttime - now, &timenext);
zone->refreshkeytime = timenext;
UNLOCK_ZONE(zone);
zone_settimer(zone, &timenow);
isc_time_formattimestamp(&zone->refreshkeytime, timebuf, 80);
dnssec_log(zone, ISC_LOG_DEBUG(3),
"next key event in %u seconds: %s",
(nexttime - now), timebuf);
dnssec_log(zone, ISC_LOG_INFO, "next key event: %s", timebuf);
}
/*
* If we're doing key maintenance, set the key refresh timer to
* the next scheduled key event or to 'dnssec-loadkeys-interval'
* seconds in the future, whichever is sooner.
*/
if (DNS_ZONEKEY_OPTION(zone, DNS_ZONEKEY_MAINTAIN)) {
else if (DNS_ZONEKEY_OPTION(zone, DNS_ZONEKEY_MAINTAIN)) {
isc_time_t timethen;
isc_stdtime_t then;
@ -19889,7 +20182,8 @@ dns_zone_setserial(dns_zone_t *zone, uint32_t serial) {
LOCK_ZONE(zone);
if (!inline_secure(zone)) {
if (!dns_zone_isdynamic(zone, true)) {
if (!dns_zone_isdynamic(zone, true) &&
dns_zone_getkasp(zone) == NULL) {
result = DNS_R_NOTDYNAMIC;
goto failure;
}

View file

@ -35,11 +35,11 @@ SUBDIRS = include
TESTDIRS = @UNITTESTS@
# Alphabetically
OBJS = aclconf.@O@ dnsconf.@O@ log.@O@ namedconf.@O@ \
OBJS = aclconf.@O@ dnsconf.@O@ kaspconf.@O@ log.@O@ namedconf.@O@ \
parser.@O@ version.@O@
# Alphabetically
SRCS = aclconf.c dnsconf.c log.c namedconf.c \
SRCS = aclconf.c dnsconf.c kaspconf.c log.c namedconf.c \
parser.c version.c
TARGETS = timestamp

View file

@ -27,6 +27,7 @@
#include <inttypes.h>
#include <stdbool.h>
#include <time.h>
#include <isc/formatcheck.h>
#include <isc/lang.h>
@ -331,6 +332,24 @@ cfg_obj_aspercentage(const cfg_obj_t *obj);
* \li A 32-bit unsigned integer.
*/
bool
cfg_obj_isduration(const cfg_obj_t *obj);
/*%<
* Return true iff 'obj' is of duration type.
*/
uint32_t
cfg_obj_asduration(const cfg_obj_t *obj);
/*%<
* Returns the value of a configuration object of duration
*
* Requires:
* \li 'obj' points to a valid configuration object of duration type.
*
* Returns:
* \li A duration in seconds.
*/
bool
cfg_obj_isstring(const cfg_obj_t *obj);
/*%<

View file

@ -82,6 +82,9 @@ typedef struct cfg_printer cfg_printer_t;
typedef ISC_LIST(cfg_listelt_t) cfg_list_t;
typedef struct cfg_map cfg_map_t;
typedef struct cfg_rep cfg_rep_t;
typedef struct cfg_duration cfg_duration_t;
#define CFG_DURATION_MAXLEN 64
/*
* Function types for configuration object methods
@ -154,6 +157,24 @@ struct cfg_netprefix {
unsigned int prefixlen;
};
/*%
* A configuration object to store ISO 8601 durations.
*/
struct cfg_duration {
/*
* The duration is stored in multiple parts:
* [0] Years
* [1] Months
* [2] Weeks
* [3] Days
* [4] Hours
* [5] Minutes
* [6] Seconds
*/
uint32_t parts[7];
bool iso8601;
};
/*%
* A configuration data representation.
*/
@ -183,6 +204,7 @@ struct cfg_obj {
isc_dscp_t dscp;
} sockaddrdscp;
cfg_netprefix_t netprefix;
cfg_duration_t duration;
} value;
isc_refcount_t references; /*%< reference counter */
const char * file;
@ -290,6 +312,7 @@ LIBISCCFG_EXTERNAL_DATA extern cfg_rep_t cfg_rep_netprefix;
LIBISCCFG_EXTERNAL_DATA extern cfg_rep_t cfg_rep_void;
LIBISCCFG_EXTERNAL_DATA extern cfg_rep_t cfg_rep_fixedpoint;
LIBISCCFG_EXTERNAL_DATA extern cfg_rep_t cfg_rep_percentage;
LIBISCCFG_EXTERNAL_DATA extern cfg_rep_t cfg_rep_duration;
/*@}*/
/*@{*/
@ -320,6 +343,7 @@ LIBISCCFG_EXTERNAL_DATA extern cfg_type_t cfg_type_token;
LIBISCCFG_EXTERNAL_DATA extern cfg_type_t cfg_type_unsupported;
LIBISCCFG_EXTERNAL_DATA extern cfg_type_t cfg_type_fixedpoint;
LIBISCCFG_EXTERNAL_DATA extern cfg_type_t cfg_type_percentage;
LIBISCCFG_EXTERNAL_DATA extern cfg_type_t cfg_type_duration;
/*@}*/
isc_result_t
@ -504,6 +528,13 @@ cfg_parse_percentage(cfg_parser_t *pctx, const cfg_type_t *type,
void
cfg_print_percentage(cfg_printer_t *pctx, const cfg_obj_t *obj);
isc_result_t
cfg_parse_duration(cfg_parser_t *pctx, const cfg_type_t *type,
cfg_obj_t **ret);
void
cfg_print_duration(cfg_printer_t *pctx, const cfg_obj_t *obj);
isc_result_t
cfg_parse_obj(cfg_parser_t *pctx, const cfg_type_t *type, cfg_obj_t **ret);

View file

@ -0,0 +1,56 @@
/*
* Copyright (C) Internet Systems Consortium, Inc. ("ISC")
*
* 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 http://mozilla.org/MPL/2.0/.
*
* See the COPYRIGHT file distributed with this work for additional
* information regarding copyright ownership.
*/
#ifndef ISCCFG_KASPCONF_H
#define ISCCFG_KASPCONF_H 1
#include <isc/lang.h>
#include <isccfg/cfg.h>
#include <dns/types.h>
/***
*** Functions
***/
ISC_LANG_BEGINDECLS
isc_result_t
cfg_kasp_fromconfig(const cfg_obj_t *config, isc_mem_t* mctx,
dns_kasplist_t *kasplist, dns_kasp_t **kaspp);
/*%<
* Create and configure a KASP. If 'config' is NULL, the default configuration
* is used. If a 'kasplist' is provided, a lookup happens and if a KASP
* already exists with the same name, no new KASP is created, and no attach to
* 'kaspp' happens.
*
* Requires:
*
*\li 'mctx' is a valid memory context.
*
*\li 'name' is a valid C string.
*
*\li kaspp != NULL && *kaspp == NULL
*
* Returns:
*
*\li #ISC_R_SUCCESS If creating and configuring the KASP succeeds.
*\li #ISC_R_EXISTS If 'kasplist' already has a kasp structure with 'name'.
*\li #ISC_R_NOMEMORY
*
*\li Other errors are possible.
*/
ISC_LANG_ENDDECLS
#endif /* ISCCFG_KASPCONF_H */

View file

@ -49,4 +49,7 @@ LIBISCCFG_EXTERNAL_DATA extern cfg_type_t cfg_type_keyref;
/*%< Zone options */
LIBISCCFG_EXTERNAL_DATA extern cfg_type_t cfg_type_zoneopts;
/*%< DNSSEC Key and Signing Policy options */
LIBISCCFG_EXTERNAL_DATA extern cfg_type_t cfg_type_dnssecpolicyopts;
#endif /* ISCCFG_NAMEDCONF_H */

226
lib/isccfg/kaspconf.c Normal file
View file

@ -0,0 +1,226 @@
/*
* Copyright (C) Internet Systems Consortium, Inc. ("ISC")
*
* 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 http://mozilla.org/MPL/2.0/.
*
* See the COPYRIGHT file distributed with this work for additional
* information regarding copyright ownership.
*/
#include <inttypes.h>
#include <stdbool.h>
#include <stdlib.h>
#include <isc/mem.h>
#include <isc/print.h>
#include <isc/string.h>
#include <isc/util.h>
#include <isccfg/namedconf.h>
#include <isccfg/cfg.h>
#include <isccfg/kaspconf.h>
#include <dns/kasp.h>
#include <dns/keyvalues.h>
#include <dns/log.h>
/*
* Utility function for getting a configuration option.
*/
static isc_result_t
confget(cfg_obj_t const * const *maps, const char *name, const cfg_obj_t **obj)
{
for (size_t i = 0;; i++) {
if (maps[i] == NULL) {
return (ISC_R_NOTFOUND);
}
if (cfg_map_get(maps[i], name, obj) == ISC_R_SUCCESS) {
return (ISC_R_SUCCESS);
}
}
}
/*
* Utility function for configuring durations.
*/
static uint32_t
get_duration(const cfg_obj_t **maps, const char* option, uint32_t dfl)
{
const cfg_obj_t *obj;
isc_result_t result;
obj = NULL;
result = confget(maps, option, &obj);
if (result == ISC_R_NOTFOUND) {
return (dfl);
}
INSIST(result == ISC_R_SUCCESS);
return (cfg_obj_asduration(obj));
}
/*
* Create a new kasp key derived from configuration.
*/
static isc_result_t
cfg_kaspkey_fromconfig(const cfg_obj_t *config, dns_kasp_t* kasp)
{
isc_result_t result;
dns_kasp_key_t *key = NULL;
/* Create a new key reference. */
result = dns_kasp_key_create(kasp, &key);
if (result != ISC_R_SUCCESS) {
return (result);
}
if (config == NULL) {
/* We are creating a key reference for the default kasp. */
key->role |= DNS_KASP_KEY_ROLE_KSK | DNS_KASP_KEY_ROLE_ZSK;
key->lifetime = 0;
key->algorithm = DNS_KEYALG_ECDSA256;
key->length = -1;
} else {
const char* rolestr;
const cfg_obj_t* obj;
rolestr = cfg_obj_asstring(cfg_tuple_get(config, "role"));
if (strcmp(rolestr, "ksk") == 0) {
key->role |= DNS_KASP_KEY_ROLE_KSK;
} else if (strcmp(rolestr, "zsk") == 0) {
key->role |= DNS_KASP_KEY_ROLE_ZSK;
} else if (strcmp(rolestr, "csk") == 0) {
key->role |= DNS_KASP_KEY_ROLE_KSK;
key->role |= DNS_KASP_KEY_ROLE_ZSK;
}
key->lifetime = cfg_obj_asduration(
cfg_tuple_get(config, "lifetime"));
key->algorithm = cfg_obj_asuint32(
cfg_tuple_get(config, "algorithm"));
obj = cfg_tuple_get(config, "length");
if (cfg_obj_isuint32(obj)) {
key->length = cfg_obj_asuint32(obj);
}
}
dns_kasp_addkey(kasp, key);
return (result);
}
isc_result_t
cfg_kasp_fromconfig(const cfg_obj_t *config, isc_mem_t* mctx,
dns_kasplist_t *kasplist, dns_kasp_t **kaspp)
{
isc_result_t result;
const cfg_obj_t *maps[2];
const cfg_obj_t *koptions = NULL;
const cfg_obj_t *keys = NULL;
const cfg_listelt_t *element = NULL;
const char *kaspname = NULL;
dns_kasp_t *kasp = NULL;
int i = 0;
REQUIRE(kaspp != NULL && *kaspp == NULL);
kaspname = (config != NULL) ?
cfg_obj_asstring(cfg_tuple_get(config, "name")) :
"default";
REQUIRE(strcmp(kaspname, "none") != 0);
result = dns_kasplist_find(kasplist, kaspname, &kasp);
if (result == ISC_R_SUCCESS) {
return (ISC_R_EXISTS);
}
if (result != ISC_R_NOTFOUND) {
return (result);
}
/* No kasp with configured name was found in list, create new one. */
INSIST(kasp == NULL);
result = dns_kasp_create(mctx, kaspname, &kasp);
if (result != ISC_R_SUCCESS) {
return (result);
}
INSIST(kasp != NULL);
/* Now configure. */
INSIST(DNS_KASP_VALID(kasp));
if (config != NULL) {
koptions = cfg_tuple_get(config, "options");
maps[i++] = koptions;
}
maps[i] = NULL;
/* Configuration: Signatures */
dns_kasp_setsigrefresh(kasp, get_duration(maps, "signatures-refresh",
DNS_KASP_SIG_REFRESH));
dns_kasp_setsigvalidity(kasp, get_duration(maps, "signatures-validity",
DNS_KASP_SIG_VALIDITY));
dns_kasp_setsigvalidity_dnskey(kasp, get_duration(maps,
"signatures-validity-dnskey",
DNS_KASP_SIG_VALIDITY_DNSKEY));
/* Configuration: Keys */
dns_kasp_setdnskeyttl(kasp, get_duration(maps, "dnskey-ttl",
DNS_KASP_KEY_TTL));
dns_kasp_setpublishsafety(kasp, get_duration(maps, "publish-safety",
DNS_KASP_PUBLISH_SAFETY));
dns_kasp_setretiresafety(kasp, get_duration(maps, "retire-safety",
DNS_KASP_RETIRE_SAFETY));
(void)confget(maps, "keys", &keys);
if (keys == NULL) {
result = cfg_kaspkey_fromconfig(NULL, kasp);
if (result != ISC_R_SUCCESS) {
goto cleanup;
}
} else {
for (element = cfg_list_first(keys); element != NULL;
element = cfg_list_next(element))
{
cfg_obj_t *kobj = cfg_listelt_value(element);
result = cfg_kaspkey_fromconfig(kobj, kasp);
if (result != ISC_R_SUCCESS) {
goto cleanup;
}
}
}
ISC_INSIST(!(dns_kasp_keylist_empty(kasp)));
/* Configuration: Zone settings */
dns_kasp_setzonemaxttl(kasp, get_duration(maps, "zone-max-ttl",
DNS_KASP_ZONE_MAXTTL));
dns_kasp_setzonepropagationdelay(kasp, get_duration(maps,
"zone-propagation-delay",
DNS_KASP_ZONE_PROPDELAY));
/* Configuration: Parent settings */
dns_kasp_setdsttl(kasp, get_duration(maps, "parent-ds-ttl",
DNS_KASP_DS_TTL));
dns_kasp_setparentpropagationdelay(kasp, get_duration(maps,
"parent-propagation-delay",
DNS_KASP_PARENT_PROPDELAY));
dns_kasp_setparentregistrationdelay(kasp, get_duration(maps,
"parent-registration-delay",
DNS_KASP_PARENT_REGDELAY));
// TODO: Rest of the configuration
/* Append it to the list for future lookups. */
ISC_LIST_APPEND(*kasplist, kasp, link);
ISC_INSIST(!(ISC_LIST_EMPTY(*kasplist)));
/* Success: Attach the kasp to the pointer and return. */
dns_kasp_attach(kasp, kaspp);
/* Don't detach as kasp is on '*kasplist' */
return (ISC_R_SUCCESS);
cleanup:
/* Something bad happened, detach (destroys kasp) and return error. */
dns_kasp_detach(&kasp);
return (result);
}

View file

@ -18,6 +18,7 @@
#include <isc/lex.h>
#include <isc/mem.h>
#include <isc/print.h>
#include <isc/result.h>
#include <isc/string.h>
#include <isc/util.h>
@ -82,6 +83,7 @@ static cfg_type_t cfg_type_controls_sockaddr;
static cfg_type_t cfg_type_destinationlist;
static cfg_type_t cfg_type_dialuptype;
static cfg_type_t cfg_type_dlz;
static cfg_type_t cfg_type_dnssecpolicy;
static cfg_type_t cfg_type_dnstap;
static cfg_type_t cfg_type_dnstapoutput;
static cfg_type_t cfg_type_dyndb;
@ -121,7 +123,6 @@ static cfg_type_t cfg_type_sizeval;
static cfg_type_t cfg_type_sockaddr4wild;
static cfg_type_t cfg_type_sockaddr6wild;
static cfg_type_t cfg_type_statschannels;
static cfg_type_t cfg_type_ttlval;
static cfg_type_t cfg_type_view;
static cfg_type_t cfg_type_viewopts;
static cfg_type_t cfg_type_zone;
@ -411,6 +412,20 @@ static cfg_type_t cfg_type_zone = {
&cfg_rep_tuple, zone_fields
};
/*%
* A dnssec-policy statement.
*/
static cfg_tuplefielddef_t dnssecpolicy_fields[] = {
{ "name", &cfg_type_astring, 0 },
{ "options", &cfg_type_dnssecpolicyopts, 0 },
{ NULL, NULL, 0 }
};
static cfg_type_t cfg_type_dnssecpolicy = {
"dnssec-policy", cfg_parse_tuple, cfg_print_tuple, cfg_doc_tuple,
&cfg_rep_tuple, dnssecpolicy_fields
};
/*%
* A "category" clause in the "logging" statement.
*/
@ -466,6 +481,55 @@ static cfg_type_t cfg_type_managedkey = {
&cfg_rep_tuple, managedkey_fields
};
/*%
* DNSSEC key roles.
*/
static const char *dnsseckeyrole_enums[] = { "csk", "ksk", "zsk", NULL };
static cfg_type_t cfg_type_dnsseckeyrole = {
"dnssec-key-role", cfg_parse_enum, cfg_print_ustring, cfg_doc_enum,
&cfg_rep_string, &dnsseckeyrole_enums
};
/*%
* DNSSEC key storage types.
*/
static const char *dnsseckeystore_enums[] = { "key-directory", NULL };
static cfg_type_t cfg_type_dnsseckeystore = {
"dnssec-key-storage", cfg_parse_enum, cfg_print_ustring, cfg_doc_enum,
&cfg_rep_string, &dnsseckeystore_enums
};
/*%
* A dnssec key, as used in the "keys" statement in a "dnssec-policy".
*/
static keyword_type_t algorithm_kw = { "algorithm", &cfg_type_uint32 };
static cfg_type_t cfg_type_algorithm = {
"algorithm", parse_keyvalue, print_keyvalue,
doc_keyvalue, &cfg_rep_uint32, &algorithm_kw
};
static keyword_type_t lifetime_kw = { "lifetime", &cfg_type_duration };
static cfg_type_t cfg_type_lifetime = {
"lifetime", parse_keyvalue, print_keyvalue,
doc_keyvalue, &cfg_rep_duration, &lifetime_kw
};
static cfg_tuplefielddef_t kaspkey_fields[] = {
{ "role", &cfg_type_dnsseckeyrole, 0 },
{ "keystore-type", &cfg_type_dnsseckeystore, 0 },
{ "lifetime", &cfg_type_lifetime, 0 },
{ "algorithm", &cfg_type_algorithm, 0 },
{ "length", &cfg_type_optional_uint32, 0 },
{ NULL, NULL, 0 }
};
static cfg_type_t cfg_type_kaspkey = {
"kaspkey", cfg_parse_tuple, cfg_print_tuple, cfg_doc_tuple,
&cfg_rep_tuple, kaspkey_fields
};
/*%
* Wild class, type, name.
*/
static keyword_type_t wild_class_kw = { "class", &cfg_type_ustring };
static cfg_type_t cfg_type_optional_wild_class = {
@ -638,6 +702,14 @@ static cfg_type_t cfg_type_dnsseckeys = {
cfg_doc_bracketed_list, &cfg_rep_list, &cfg_type_managedkey
};
/*%
* A list of key entries, used in a DNSSEC Key and Signing Policy.
*/
static cfg_type_t cfg_type_kaspkeys = {
"kaspkeys", cfg_parse_bracketed_list, cfg_print_bracketed_list,
cfg_doc_bracketed_list, &cfg_rep_list, &cfg_type_kaspkey
};
static const char *forwardtype_enums[] = { "first", "only", NULL };
static cfg_type_t cfg_type_forwardtype = {
"forwardtype", cfg_parse_enum, cfg_print_ustring, cfg_doc_enum,
@ -963,6 +1035,7 @@ static cfg_clausedef_t
namedconf_clauses[] = {
{ "acl", &cfg_type_acl, CFG_CLAUSEFLAG_MULTI },
{ "controls", &cfg_type_controls, CFG_CLAUSEFLAG_MULTI },
{ "dnssec-policy", &cfg_type_dnssecpolicy, CFG_CLAUSEFLAG_MULTI },
{ "logging", &cfg_type_logging, 0 },
{ "lwres", &cfg_type_bracketed_text,
CFG_CLAUSEFLAG_MULTI | CFG_CLAUSEFLAG_OBSOLETE },
@ -1054,7 +1127,7 @@ options_clauses[] = {
{ "fstrm-set-output-notify-threshold", &cfg_type_uint32, 0 },
{ "fstrm-set-output-queue-model", &cfg_type_fstrm_model, 0 },
{ "fstrm-set-output-queue-size", &cfg_type_uint32, 0 },
{ "fstrm-set-reopen-interval", &cfg_type_ttlval, 0 },
{ "fstrm-set-reopen-interval", &cfg_type_duration, 0 },
#else
{ "fstrm-set-buffer-hint", &cfg_type_uint32,
CFG_CLAUSEFLAG_NOTCONFIGURED },
@ -1068,7 +1141,7 @@ options_clauses[] = {
CFG_CLAUSEFLAG_NOTCONFIGURED },
{ "fstrm-set-output-queue-size", &cfg_type_uint32,
CFG_CLAUSEFLAG_NOTCONFIGURED },
{ "fstrm-set-reopen-interval", &cfg_type_ttlval,
{ "fstrm-set-reopen-interval", &cfg_type_duration,
CFG_CLAUSEFLAG_NOTCONFIGURED },
#endif /* HAVE_DNSTAP */
#if defined(HAVE_GEOIP2)
@ -1083,7 +1156,7 @@ options_clauses[] = {
{ "host-statistics", &cfg_type_boolean, CFG_CLAUSEFLAG_ANCIENT },
{ "host-statistics-max", &cfg_type_uint32, CFG_CLAUSEFLAG_ANCIENT },
{ "hostname", &cfg_type_qstringornone, 0 },
{ "interface-interval", &cfg_type_ttlval, 0 },
{ "interface-interval", &cfg_type_duration, 0 },
{ "keep-response-order", &cfg_type_bracketed_aml, 0 },
{ "listen-on", &cfg_type_listenon, CFG_CLAUSEFLAG_MULTI },
{ "listen-on-v6", &cfg_type_listenon, CFG_CLAUSEFLAG_MULTI },
@ -1611,8 +1684,8 @@ static cfg_tuplefielddef_t rpz_zone_fields[] = {
{ "zone name", &cfg_type_rpz_zone, 0 },
{ "add-soa", &cfg_type_boolean, 0 },
{ "log", &cfg_type_boolean, 0 },
{ "max-policy-ttl", &cfg_type_ttlval, 0 },
{ "min-update-interval", &cfg_type_ttlval, 0 },
{ "max-policy-ttl", &cfg_type_duration, 0 },
{ "min-update-interval", &cfg_type_duration, 0 },
{ "policy", &cfg_type_rpz_policy, 0 },
{ "recursive-only", &cfg_type_boolean, 0 },
{ "nsip-enable", &cfg_type_boolean, 0 },
@ -1633,8 +1706,8 @@ static cfg_tuplefielddef_t rpz_fields[] = {
{ "zone list", &cfg_type_rpz_list, 0 },
{ "add-soa", &cfg_type_boolean, 0 },
{ "break-dnssec", &cfg_type_boolean, 0 },
{ "max-policy-ttl", &cfg_type_ttlval, 0 },
{ "min-update-interval", &cfg_type_ttlval, 0 },
{ "max-policy-ttl", &cfg_type_duration, 0 },
{ "min-update-interval", &cfg_type_duration, 0 },
{ "min-ns-dots", &cfg_type_uint32, 0 },
{ "nsip-wait-recurse", &cfg_type_boolean, 0 },
{ "qname-wait-recurse", &cfg_type_boolean, 0 },
@ -1671,7 +1744,7 @@ static cfg_tuplefielddef_t catz_zone_fields[] = {
{ "default-masters", &cfg_type_namesockaddrkeylist, 0 },
{ "zone-directory", &cfg_type_qstring, 0 },
{ "in-memory", &cfg_type_boolean, 0 },
{ "min-update-interval", &cfg_type_ttlval, 0 },
{ "min-update-interval", &cfg_type_duration, 0 },
{ NULL, NULL, 0 }
};
static cfg_type_t cfg_type_catz_tuple = {
@ -1899,7 +1972,7 @@ view_clauses[] = {
{ "filter-aaaa-on-v6", &cfg_type_boolean, CFG_CLAUSEFLAG_OBSOLETE },
{ "glue-cache", &cfg_type_boolean, 0 },
{ "ixfr-from-differences", &cfg_type_ixfrdifftype, 0 },
{ "lame-ttl", &cfg_type_ttlval, 0 },
{ "lame-ttl", &cfg_type_duration, 0 },
#ifdef HAVE_LMDB
{ "lmdb-mapsize", &cfg_type_sizeval, 0 },
#else
@ -1907,16 +1980,16 @@ view_clauses[] = {
#endif
{ "max-acache-size", &cfg_type_sizenodefault, CFG_CLAUSEFLAG_OBSOLETE },
{ "max-cache-size", &cfg_type_sizeorpercent, 0 },
{ "max-cache-ttl", &cfg_type_ttlval, 0 },
{ "max-cache-ttl", &cfg_type_duration, 0 },
{ "max-clients-per-query", &cfg_type_uint32, 0 },
{ "max-ncache-ttl", &cfg_type_ttlval, 0 },
{ "max-ncache-ttl", &cfg_type_duration, 0 },
{ "max-recursion-depth", &cfg_type_uint32, 0 },
{ "max-recursion-queries", &cfg_type_uint32, 0 },
{ "max-stale-ttl", &cfg_type_ttlval, 0 },
{ "max-stale-ttl", &cfg_type_duration, 0 },
{ "max-udp-size", &cfg_type_uint32, 0 },
{ "message-compression", &cfg_type_boolean, 0 },
{ "min-cache-ttl", &cfg_type_ttlval, 0 },
{ "min-ncache-ttl", &cfg_type_ttlval, 0 },
{ "min-cache-ttl", &cfg_type_duration, 0 },
{ "min-ncache-ttl", &cfg_type_duration, 0 },
{ "min-roots", &cfg_type_uint32, CFG_CLAUSEFLAG_ANCIENT },
{ "minimal-any", &cfg_type_boolean, 0 },
{ "minimal-responses", &cfg_type_minimal, 0 },
@ -1924,8 +1997,8 @@ view_clauses[] = {
{ "no-case-compress", &cfg_type_bracketed_aml, 0 },
{ "nocookie-udp-size", &cfg_type_uint32, 0 },
{ "nosit-udp-size", &cfg_type_uint32, CFG_CLAUSEFLAG_OBSOLETE },
{ "nta-lifetime", &cfg_type_ttlval, 0 },
{ "nta-recheck", &cfg_type_ttlval, 0 },
{ "nta-lifetime", &cfg_type_duration, 0 },
{ "nta-recheck", &cfg_type_duration, 0 },
{ "nxdomain-redirect", &cfg_type_astring, 0 },
{ "preferred-glue", &cfg_type_astring, 0 },
{ "prefetch", &cfg_type_prefetch, 0 },
@ -1955,10 +2028,10 @@ view_clauses[] = {
{ "root-key-sentinel", &cfg_type_boolean, 0 },
{ "rrset-order", &cfg_type_rrsetorder, 0 },
{ "send-cookie", &cfg_type_boolean, 0 },
{ "servfail-ttl", &cfg_type_ttlval, 0 },
{ "servfail-ttl", &cfg_type_duration, 0 },
{ "sortlist", &cfg_type_bracketed_aml, 0 },
{ "stale-answer-enable", &cfg_type_boolean, 0 },
{ "stale-answer-ttl", &cfg_type_ttlval, 0 },
{ "stale-answer-ttl", &cfg_type_duration, 0 },
{ "suppress-initial-notify", &cfg_type_boolean, CFG_CLAUSEFLAG_NYI },
{ "synth-from-dnssec", &cfg_type_boolean, 0 },
{ "topology", &cfg_type_bracketed_aml, CFG_CLAUSEFLAG_ANCIENT },
@ -1998,6 +2071,26 @@ static cfg_type_t cfg_type_validityinterval = {
&cfg_rep_tuple, validityinterval_fields
};
/*%
* Clauses that can be found in a 'dnssec-policy' statement.
*/
static cfg_clausedef_t
dnssecpolicy_clauses[] = {
{ "dnskey-ttl", &cfg_type_duration, 0 },
{ "keys", &cfg_type_kaspkeys, 0 },
{ "publish-safety", &cfg_type_duration, 0 },
{ "retire-safety", &cfg_type_duration, 0 },
{ "signatures-refresh", &cfg_type_duration, 0 },
{ "signatures-validity", &cfg_type_duration, 0 },
{ "signatures-validity-dnskey", &cfg_type_duration, 0 },
{ "zone-max-ttl", &cfg_type_duration, 0 },
{ "zone-propagation-delay", &cfg_type_duration, 0 },
{ "parent-ds-ttl", &cfg_type_duration, 0 },
{ "parent-propagation-delay", &cfg_type_duration, 0 },
{ "parent-registration-delay", &cfg_type_duration, 0 },
{ NULL, NULL, 0 }
};
/*%
* Clauses that can be found in a 'zone' statement,
* with defaults in the 'view' or 'options' statement.
@ -2072,6 +2165,9 @@ zone_clauses[] = {
{ "dnssec-loadkeys-interval", &cfg_type_uint32,
CFG_ZONE_MASTER | CFG_ZONE_SLAVE
},
{ "dnssec-policy", &cfg_type_astring,
CFG_ZONE_MASTER | CFG_ZONE_SLAVE
},
{ "dnssec-secure-to-insecure", &cfg_type_boolean,
CFG_ZONE_MASTER
},
@ -2346,6 +2442,16 @@ LIBISCCFG_EXTERNAL_DATA cfg_type_t cfg_type_zoneopts = {
"zoneopts", cfg_parse_map, cfg_print_map,
cfg_doc_map, &cfg_rep_map, zone_clausesets };
/*% The "dnssec-policy" statement syntax. */
static cfg_clausedef_t *
dnssecpolicy_clausesets[] = {
dnssecpolicy_clauses,
NULL
};
LIBISCCFG_EXTERNAL_DATA cfg_type_t cfg_type_dnssecpolicyopts = {
"dnssecpolicyopts", cfg_parse_map, cfg_print_map,
cfg_doc_map, &cfg_rep_map, dnssecpolicy_clausesets };
/*% The "dynamically loadable zones" statement syntax. */
static cfg_clausedef_t
@ -3761,54 +3867,14 @@ static cfg_type_t cfg_type_masterselement = {
doc_masterselement, NULL, NULL
};
static isc_result_t
parse_ttlval(cfg_parser_t *pctx, const cfg_type_t *type, cfg_obj_t **ret) {
isc_result_t result;
cfg_obj_t *obj = NULL;
uint32_t ttl;
UNUSED(type);
CHECK(cfg_gettoken(pctx, 0));
if (pctx->token.type != isc_tokentype_string) {
result = ISC_R_UNEXPECTEDTOKEN;
goto cleanup;
}
result = dns_ttl_fromtext(&pctx->token.value.as_textregion, &ttl);
if (result == ISC_R_RANGE ) {
cfg_parser_error(pctx, CFG_LOG_NEAR, "TTL out of range ");
return (result);
} else if (result != ISC_R_SUCCESS)
goto cleanup;
CHECK(cfg_create_obj(pctx, &cfg_type_uint32, &obj));
obj->value.uint32 = ttl;
*ret = obj;
return (ISC_R_SUCCESS);
cleanup:
cfg_parser_error(pctx, CFG_LOG_NEAR,
"expected integer and optional unit");
return (result);
}
/*%
* A TTL value (number + optional unit).
*/
static cfg_type_t cfg_type_ttlval = {
"ttlval", parse_ttlval, cfg_print_uint64, cfg_doc_terminal,
&cfg_rep_uint64, NULL
};
static isc_result_t
parse_maxttl(cfg_parser_t *pctx, const cfg_type_t *type, cfg_obj_t **ret) {
return (cfg_parse_enum_or_other(pctx, type, &cfg_type_ttlval, ret));
return (cfg_parse_enum_or_other(pctx, type, &cfg_type_duration, ret));
}
static void
doc_maxttl(cfg_printer_t *pctx, const cfg_type_t *type) {
cfg_doc_enum_or_other(pctx, type, &cfg_type_ttlval);
cfg_doc_enum_or_other(pctx, type, &cfg_type_duration);
}
/*%

View file

@ -34,6 +34,8 @@
#include <isccfg/grammar.h>
#include <isccfg/log.h>
#include <dns/ttl.h>
/* Shorthand */
#define CAT CFG_LOGCATEGORY_CONFIG
#define MOD CFG_LOGMODULE_PARSER
@ -132,6 +134,7 @@ LIBISCCFG_EXTERNAL_DATA cfg_rep_t cfg_rep_fixedpoint =
{ "fixedpoint", free_noop };
LIBISCCFG_EXTERNAL_DATA cfg_rep_t cfg_rep_percentage =
{ "percentage", free_noop };
LIBISCCFG_EXTERNAL_DATA cfg_rep_t cfg_rep_duration = { "duration", free_noop };
/*
* Configuration type definitions.
@ -977,9 +980,353 @@ LIBISCCFG_EXTERNAL_DATA cfg_type_t cfg_type_uint64 = {
&cfg_rep_uint64, NULL
};
/*
* Get the number of digits in a number.
*/
static size_t
numlen(uint32_t num) {
uint32_t period = num;
size_t count = 0;
if (period == 0) {
return 1;
}
while (period > 0) {
count++;
period /= 10;
}
return (count);
}
/*
* duration
*/
void
cfg_print_duration(cfg_printer_t *pctx, const cfg_obj_t *obj) {
char buf[CFG_DURATION_MAXLEN];
char *str;
const char *indicators = "YMWDHMS";
int count, i;
int durationlen[7];
cfg_duration_t duration;
/*
* D ? The duration has a date part.
* T ? The duration has a time part.
*/
bool D = false, T = false;
REQUIRE(pctx != NULL);
REQUIRE(obj != NULL);
duration = obj->value.duration;
/* If this is not an ISO 8601 duration, just print it as a number. */
if (!duration.iso8601) {
return (cfg_print_rawuint(pctx, duration.parts[6]));
}
/* Calculate length of string. */
buf[0] = 'P';
buf[1] = '\0';
str = &buf[1];
count = 2;
for (i = 0; i < 6; i++) {
if (duration.parts[i] > 0) {
durationlen[i] = 1 + numlen(duration.parts[i]);
if (i < 4) {
D = true;
} else {
T = true;
}
} else {
durationlen[i] = 0;
}
count += durationlen[i];
}
/*
* Special case for seconds which is not taken into account in the
* above for loop: Count the length of the seconds part if it is
* non-zero, or if all the other parts are also zero. In the latter
* case this function will print "PT0S".
*/
if (duration.parts[6] > 0 ||
(!D && !duration.parts[4] && !duration.parts[5])) {
durationlen[6] = 1 + numlen(duration.parts[6]);
T = true;
count += durationlen[6];
}
/* Add one character for the time indicator. */
if (T) {
count++;
}
INSIST(count < CFG_DURATION_MAXLEN);
/* Now print the duration. */
for (i = 0; i < 6; i++) {
/*
* We don't check here if weeks and other time indicator are
* used mutually exclusively.
*/
if (duration.parts[i] > 0) {
snprintf(str, durationlen[i]+2, "%u%c",
(uint32_t) duration.parts[i], indicators[i]);
str += durationlen[i]+1;
}
if (i == 3 && T) {
snprintf(str, 2, "T");
str += 1;
}
}
/* Special case for seconds. */
if (duration.parts[6] > 0 ||
(!D && !duration.parts[4] && !duration.parts[3])) {
snprintf(str, durationlen[6]+2, "%u%c",
(uint32_t) duration.parts[6], indicators[6]);
}
cfg_print_chars(pctx, buf, strlen(buf));
}
bool
cfg_obj_isduration(const cfg_obj_t *obj) {
REQUIRE(obj != NULL);
return (obj->type->rep == &cfg_rep_duration);
}
uint32_t
cfg_obj_asduration(const cfg_obj_t *obj) {
REQUIRE(obj != NULL && obj->type->rep == &cfg_rep_duration);
uint32_t duration = 0;
duration += obj->value.duration.parts[6]; // Seconds
duration += obj->value.duration.parts[5]*60; // Minutes
duration += obj->value.duration.parts[4]*3600; // Hours
duration += obj->value.duration.parts[3]*86400; // Days
duration += obj->value.duration.parts[2]*86400*7; // Weaks
/*
* The below additions are not entirely correct
* because days may very per month and per year.
*/
duration += obj->value.duration.parts[1]*86400*31; // Months
duration += obj->value.duration.parts[0]*86400*365; // Years
return (duration);
}
/*
* duration_fromtext initially taken from OpenDNSSEC code base.
* Modified to fit the BIND 9 code.
*
* Copyright (c) 2009-2018 NLNet Labs.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
* GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
* IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
* OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
* IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
static isc_result_t
duration_fromtext(isc_textregion_t *source, cfg_duration_t *duration) {
char buf[CFG_DURATION_MAXLEN];
char *P, *X, *T, *W, *str;
bool not_weeks = false;
int i;
/*
* Copy the buffer as it may not be NULL terminated.
* Anyone having a duration longer than 63 characters is crazy.
*/
if (source->length > sizeof(buf) - 1) {
return (ISC_R_BADNUMBER);
}
/* Copy source->length bytes and NULL terminate. */
snprintf(buf, sizeof(buf), "%.*s", (int)source->length, source->base);
str = buf;
/* Clear out duration. */
for (i = 0; i < 7; i++) {
duration->parts[i] = 0;
}
/* Every duration starts with 'P' */
P = strchr(str, 'P');
if (!P) {
return (ISC_R_BADNUMBER);
}
/* Record the time indicator. */
T = strchr(str, 'T');
/* Record years. */
X = strchr(str, 'Y');
if (X) {
duration->parts[0] = atoi(str+1);
str = X;
not_weeks = true;
}
/* Record months. */
X = strchr(str, 'M');
/*
* M could be months or minutes. This is months if there is no time
* part, or this M indicator is before the time indicator.
*/
if (X && (!T || (size_t) (X-P) < (size_t) (T-P))) {
duration->parts[1] = atoi(str+1);
str = X;
not_weeks = true;
}
/* Record days. */
X = strchr(str, 'D');
if (X) {
duration->parts[3] = atoi(str+1);
str = X;
not_weeks = true;
}
/* Time part? */
if (T) {
str = T;
not_weeks = true;
}
/* Record hours. */
X = strchr(str, 'H');
if (X && T) {
duration->parts[4] = atoi(str+1);
str = X;
not_weeks = true;
}
/* Record minutes. */
X = strrchr(str, 'M');
/*
* M could be months or minutes. This is minutes if there is a time
* part and the M indicator is behind the time indicator.
*/
if (X && T && (size_t) (X-P) > (size_t) (T-P)) {
duration->parts[5] = atoi(str+1);
str = X;
not_weeks = true;
}
/* Record seconds. */
X = strchr(str, 'S');
if (X && T) {
duration->parts[6] = atoi(str+1);
str = X;
not_weeks = true;
}
/* Or is the duration configured in weeks? */
W = strchr(buf, 'W');
if (W) {
if (not_weeks) {
/* Mix of weeks and other indicators is not allowed */
return (ISC_R_BADNUMBER);
} else {
duration->parts[2] = atoi(str+1);
str = W;
}
}
/* Deal with trailing garbage. */
if (str[1] != '\0') {
return (ISC_R_BADNUMBER);
}
return (ISC_R_SUCCESS);
}
isc_result_t
cfg_parse_duration(cfg_parser_t *pctx, const cfg_type_t *type,
cfg_obj_t **ret)
{
isc_result_t result;
cfg_obj_t *obj = NULL;
cfg_duration_t duration;
UNUSED(type);
CHECK(cfg_gettoken(pctx, 0));
if (pctx->token.type != isc_tokentype_string) {
result = ISC_R_UNEXPECTEDTOKEN;
goto cleanup;
}
if (TOKEN_STRING(pctx)[0] == 'P') {
result = duration_fromtext(&pctx->token.value.as_textregion,
&duration);
duration.iso8601 = true;
} else {
uint32_t ttl;
result = dns_ttl_fromtext(&pctx->token.value.as_textregion,
&ttl);
/*
* With dns_ttl_fromtext() the information on optional units.
* is lost, and is treated as seconds from now on.
*/
duration.parts[0] = 0;
duration.parts[1] = 0;
duration.parts[2] = 0;
duration.parts[3] = 0;
duration.parts[4] = 0;
duration.parts[5] = 0;
duration.parts[6] = ttl;
duration.iso8601 = false;
}
if (result == ISC_R_RANGE) {
cfg_parser_error(pctx, CFG_LOG_NEAR,
"duration or TTL out of range");
return (result);
} else if (result != ISC_R_SUCCESS) {
goto cleanup;
}
CHECK(cfg_create_obj(pctx, &cfg_type_duration, &obj));
obj->value.duration = duration;
*ret = obj;
return (ISC_R_SUCCESS);
cleanup:
cfg_parser_error(pctx, CFG_LOG_NEAR,
"expected ISO 8601 duration or TTL value");
return (result);
}
/*%
* A duration as defined by ISO 8601 (P[n]Y[n]M[n]DT[n]H[n]M[n]S).
* - P is the duration indicator ("period") placed at the start.
* - Y is the year indicator that follows the value for the number of years.
* - M is the month indicator that follows the value for the number of months.
* - D is the day indicator that follows the value for the number of days.
* - T is the time indicator that precedes the time components.
* - H is the hour indicator that follows the value for the number of hours.
* - M is the minute indicator that follows the value for the number of
* minutes.
* - S is the second indicator that follows the value for the number of
* seconds.
*
* A duration can also be a TTL value (number + optional unit).
*/
LIBISCCFG_EXTERNAL_DATA cfg_type_t cfg_type_duration = {
"duration", cfg_parse_duration, cfg_print_duration, cfg_doc_terminal,
&cfg_rep_duration, NULL
};
/*
* qstring (quoted string), ustring (unquoted string), astring
* (any string)
* (any string), sstring (secret string)
*/
/* Create a string object from a null-terminated C string. */

View file

@ -1,4 +1,5 @@
syntax(2)
test_suite('bind9')
tap_test_program{name='duration_test'}
tap_test_program{name='parser_test'}

View file

@ -30,13 +30,18 @@ ISCCFGDEPLIBS = ../libisccfg.@A@
LIBS = @LIBS@ @CMOCKA_LIBS@
OBJS =
SRCS = parser_test.c
SRCS = duration_test.c parser_test.c
SUBDIRS =
TARGETS = parser_test@EXEEXT@
TARGETS = duration_test@EXEEXT@ parser_test@EXEEXT@
@BIND9_MAKE_RULES@
duration_test@EXEEXT@: duration_test.@O@ ${ISCDEPLIBS} ${DNSDEPLIBS} ${ISCCFGDEPLIBS}
${LIBTOOL_MODE_LINK} ${PURIFY} ${CC} ${CFLAGS} \
${LDFLAGS} -o $@ duration_test.@O@ \
${ISCCFGLIBS} ${DNSLIBS} ${ISCLIBS} ${LIBS}
parser_test@EXEEXT@: parser_test.@O@ ${ISCDEPLIBS} ${DNSDEPLIBS} ${ISCCFGDEPLIBS}
${LIBTOOL_MODE_LINK} ${PURIFY} ${CC} ${CFLAGS} \
${LDFLAGS} -o $@ parser_test.@O@ \

View file

@ -0,0 +1,207 @@
/*
* Copyright (C) Internet Systems Consortium, Inc. ("ISC")
*
* 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 http://mozilla.org/MPL/2.0/.
*
* See the COPYRIGHT file distributed with this work for additional
* information regarding copyright ownership.
*/
#if HAVE_CMOCKA
#include <stdarg.h>
#include <stddef.h>
#include <setjmp.h>
#include <sched.h> /* IWYU pragma: keep */
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#define UNIT_TESTING
#include <cmocka.h>
#include <isc/buffer.h>
#include <isc/lex.h>
#include <isc/log.h>
#include <isc/mem.h>
#include <isc/types.h>
#include <isc/util.h>
#include <isccfg/cfg.h>
#include <isccfg/grammar.h>
#include <isccfg/namedconf.h>
#define CHECK(r) \
do { \
result = (r); \
if (result != ISC_R_SUCCESS) \
goto cleanup; \
} while (0)
isc_mem_t *mctx = NULL;
isc_log_t *lctx = NULL;
static isc_logcategory_t categories[] = {
{ "", 0 },
{ "client", 0 },
{ "network", 0 },
{ "update", 0 },
{ "queries", 0 },
{ "unmatched", 0 },
{ "update-security", 0 },
{ "query-errors", 0 },
{ NULL, 0 }
};
static void
cleanup() {
if (lctx != NULL) {
isc_log_destroy(&lctx);
}
if (mctx != NULL) {
isc_mem_destroy(&mctx);
}
}
static isc_result_t
setup() {
isc_result_t result;
isc_mem_debugging |= ISC_MEM_DEBUGRECORD;
isc_mem_create(&mctx);
isc_logdestination_t destination;
isc_logconfig_t *logconfig = NULL;
CHECK(isc_log_create(mctx, &lctx, &logconfig));
isc_log_registercategories(lctx, categories);
isc_log_setcontext(lctx);
destination.file.stream = stderr;
destination.file.name = NULL;
destination.file.versions = ISC_LOG_ROLLNEVER;
destination.file.maximum_size = 0;
CHECK(isc_log_createchannel(logconfig, "stderr",
ISC_LOG_TOFILEDESC,
ISC_LOG_DYNAMIC,
&destination, 0));
CHECK(isc_log_usechannel(logconfig, "stderr", NULL, NULL));
return (ISC_R_SUCCESS);
cleanup:
cleanup();
return (result);
}
struct duration_conf {
const char* string;
uint32_t time;
};
typedef struct duration_conf duration_conf_t;
/* test cfg_obj_asduration() */
static void
cfg_obj_asduration_test(void **state) {
isc_result_t result;
duration_conf_t durations[] = {
{ .string = "PT0S", .time = 0 },
{ .string = "PT42S", .time = 42 },
{ .string = "PT10M", .time = 600 },
{ .string = "PT10M4S", .time = 604 },
{ .string = "PT2H", .time = 7200 },
{ .string = "PT2H3S", .time = 7203 },
{ .string = "PT2H1M3S", .time = 7263 },
{ .string = "P7D", .time = 604800 },
{ .string = "P7DT2H", .time = 612000 },
{ .string = "P2W", .time = 1209600 },
{ .string = "P3M", .time = 8035200 },
{ .string = "P3MT10M", .time = 8035800 },
{ .string = "P5Y", .time = 157680000 },
{ .string = "P5YT2H", .time = 157687200 },
{ .string = "P1Y1M1DT1H1M1S", .time = 34304461 },
{ .string = "0", .time = 0 },
{ .string = "30", .time = 30 },
{ .string = "42s", .time = 42 },
{ .string = "10m", .time = 600 },
{ .string = "2h", .time = 7200 },
{ .string = "7d", .time = 604800 },
{ .string = "2w", .time = 1209600 },
};
int num = 22;
isc_buffer_t buf1;
cfg_parser_t *p1 = NULL;
cfg_obj_t *c1 = NULL;
UNUSED(state);
setup();
for (int i = 0; i < num; i++) {
const cfg_listelt_t *element;
const cfg_obj_t *kasps = NULL;
char conf[64];
sprintf(&conf[0],
"dnssec-policy \"dp\"\n{\nsignatures-refresh %s;\n};\n",
durations[i].string);
isc_buffer_init(&buf1, conf, strlen(conf) - 1);
isc_buffer_add(&buf1, strlen(conf) - 1);
/* Parse with default line numbering */
result = cfg_parser_create(mctx, lctx, &p1);
assert_int_equal(result, ISC_R_SUCCESS);
result = cfg_parse_buffer(p1, &buf1, "text1", 0,
&cfg_type_namedconf, 0, &c1);
assert_int_equal(result, ISC_R_SUCCESS);
(void)cfg_map_get(c1, "dnssec-policy", &kasps);
assert_non_null(kasps);
for (element = cfg_list_first(kasps);
element != NULL;
element = cfg_list_next(element))
{
const cfg_obj_t *d1 = NULL;
const cfg_obj_t *kopts = NULL;
cfg_obj_t *kconf = cfg_listelt_value(element);
assert_non_null(kconf);
kopts = cfg_tuple_get(kconf, "options");
result = cfg_map_get(kopts, "signatures-refresh", &d1);
assert_int_equal(result, ISC_R_SUCCESS);
assert_int_equal(durations[i].time,
cfg_obj_asduration(d1));
}
cfg_obj_destroy(p1, &c1);
cfg_parser_destroy(&p1);
}
cleanup();
}
int
main(void) {
const struct CMUnitTest tests[] = {
cmocka_unit_test(cfg_obj_asduration_test),
};
return (cmocka_run_group_tests(tests, NULL, NULL));
}
#else /* HAVE_CMOCKA */
#include <stdio.h>
int
main(void) {
printf("1..0 # Skipped: cmocka not available\n");
return (0);
}
#endif

View file

@ -24,6 +24,7 @@ cfg_doc_tuple
cfg_doc_void
cfg_gettoken
cfg_is_enum
cfg_kasp_fromconfig
cfg_list_first
cfg_list_length
cfg_list_next
@ -36,6 +37,7 @@ cfg_map_get
cfg_map_getname
cfg_map_nextclause
cfg_obj_asboolean
cfg_obj_asduration
cfg_obj_asfixedpoint
cfg_obj_asnetprefix
cfg_obj_aspercentage
@ -48,6 +50,7 @@ cfg_obj_destroy
cfg_obj_file
cfg_obj_getdscp
cfg_obj_isboolean
cfg_obj_isduration
cfg_obj_isfixedpoint
cfg_obj_islist
cfg_obj_ismap
@ -68,6 +71,7 @@ cfg_parse_boolean
cfg_parse_bracketed_list
cfg_parse_buffer
cfg_parse_dscp
cfg_parse_duration
cfg_parse_enum
cfg_parse_enum_or_other
cfg_parse_file
@ -107,6 +111,7 @@ cfg_print_bracketed_list
cfg_print_chars
cfg_print_clauseflags
cfg_print_cstr
cfg_print_duration
cfg_print_fixedpoint
cfg_print_grammar
cfg_print_indent
@ -131,6 +136,7 @@ cfg_ungettoken
; Exported Data
;cfg_rep_boolean
;cfg_rep_duration
;cfg_rep_fixedpoint
;cfg_rep_list
;cfg_rep_map

View file

@ -30,6 +30,9 @@
<ClCompile Include="..\dnsconf.c">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="..\kaspconf.c">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="..\log.c">
<Filter>Source Files</Filter>
</ClCompile>
@ -53,6 +56,9 @@
<ClInclude Include="..\include\isccfg\grammar.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="..\include\isccfg\kaspconf.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="..\include\isccfg\log.h">
<Filter>Header Files</Filter>
</ClInclude>
@ -63,4 +69,4 @@
<Filter>Header Files</Filter>
</ClInclude>
</ItemGroup>
</Project>
</Project>

View file

@ -116,6 +116,7 @@
<ItemGroup>
<ClCompile Include="..\aclconf.c" />
<ClCompile Include="..\dnsconf.c" />
<ClCompile Include="..\kaspconf.c" />
<ClCompile Include="..\log.c" />
<ClCompile Include="..\namedconf.c" />
<ClCompile Include="..\parser.c" />
@ -127,6 +128,7 @@
<ClInclude Include="..\include\isccfg\dnsconf.h" />
<ClInclude Include="..\include\isccfg\cfg.h" />
<ClInclude Include="..\include\isccfg\grammar.h" />
<ClInclude Include="..\include\isccfg\kaspconf.h" />
<ClInclude Include="..\include\isccfg\log.h" />
<ClInclude Include="..\include\isccfg\namedconf.h" />
<ClInclude Include="..\include\isccfg\version.h" />

View file

@ -694,6 +694,14 @@
./bin/tests/system/ixfr/prereq.sh SH 2001,2004,2007,2012,2014,2016,2018,2019
./bin/tests/system/ixfr/setup.sh SH 2001,2004,2007,2011,2012,2013,2014,2016,2018,2019
./bin/tests/system/ixfr/tests.sh SH 2001,2004,2007,2011,2012,2014,2016,2018,2019
./bin/tests/system/kasp/README TXT.BRIEF 2019
./bin/tests/system/kasp/clean.sh SH 2019
./bin/tests/system/kasp/ns2/setup.sh SH 2019
./bin/tests/system/kasp/ns3/setup.sh SH 2019
./bin/tests/system/kasp/ns4/setup.sh SH 2019
./bin/tests/system/kasp/ns5/setup.sh SH 2019
./bin/tests/system/kasp/setup.sh SH 2019
./bin/tests/system/kasp/tests.sh SH 2019
./bin/tests/system/keepalive/clean.sh SH 2017,2018,2019
./bin/tests/system/keepalive/expected X 2017,2018,2019
./bin/tests/system/keepalive/setup.sh SH 2017,2018,2019
@ -1410,6 +1418,7 @@
./doc/arm/delegation-only.zoneopt.xml SGML 2018,2019
./doc/arm/dlz.xml SGML 2012,2013,2014,2015,2016,2018,2019
./doc/arm/dnssec-keys.grammar.xml SGML 2019
./doc/arm/dnssec-policy.grammar.xml SGML 2019
./doc/arm/dnssec.xml SGML 2010,2011,2015,2016,2017,2018,2019
./doc/arm/dyndb.xml SGML 2015,2016,2018,2019
./doc/arm/forward.zoneopt.xml SGML 2018,2019
@ -1499,6 +1508,7 @@
./doc/design/db_rules TXT.BRIEF 1999,2000,2001,2004,2016,2018,2019
./doc/design/decompression TXT.BRIEF 1999,2000,2001,2004,2016,2018,2019
./doc/design/dispatch TXT.BRIEF 2000,2001,2004,2016,2018,2019
./doc/design/dnssec-policy TXT.BRIEF 2019
./doc/design/dscp TXT.BRIEF 2013,2016,2018,2019
./doc/design/keydone TXT.BRIEF 2011,2016,2018,2019
./doc/design/logging TXT.BRIEF 1999,2000,2001,2004,2016,2018,2019
@ -1675,8 +1685,10 @@
./lib/dns/include/dns/ipkeylist.h C 2016,2018,2019
./lib/dns/include/dns/iptable.h C 2007,2012,2014,2016,2018,2019
./lib/dns/include/dns/journal.h C 1999,2000,2001,2004,2005,2006,2007,2008,2009,2011,2013,2016,2017,2018,2019
./lib/dns/include/dns/kasp.h C 2019
./lib/dns/include/dns/keydata.h C 2009,2016,2018,2019
./lib/dns/include/dns/keyflags.h C 1999,2000,2001,2004,2005,2006,2007,2016,2018,2019
./lib/dns/include/dns/keymgr.h C 2019
./lib/dns/include/dns/keytable.h C 2000,2001,2004,2005,2007,2009,2010,2014,2015,2016,2017,2018,2019
./lib/dns/include/dns/keyvalues.h C 1999,2000,2001,2003,2004,2005,2006,2007,2008,2009,2010,2012,2016,2017,2018,2019
./lib/dns/include/dns/lib.h C 1999,2000,2001,2004,2005,2006,2007,2009,2016,2017,2018,2019
@ -1742,8 +1754,10 @@
./lib/dns/ipkeylist.c C 2016,2018,2019
./lib/dns/iptable.c C 2007,2008,2009,2013,2014,2016,2017,2018,2019
./lib/dns/journal.c C 1999,2000,2001,2002,2004,2005,2007,2008,2009,2010,2011,2013,2014,2015,2016,2017,2018,2019
./lib/dns/kasp.c C 2019
./lib/dns/key.c C 2001,2004,2005,2006,2007,2011,2016,2018,2019
./lib/dns/keydata.c C 2009,2014,2016,2018,2019
./lib/dns/keymgr.c C 2019
./lib/dns/keytable.c C 2000,2001,2004,2005,2007,2009,2010,2013,2014,2015,2016,2017,2018,2019
./lib/dns/lib.c C 1999,2000,2001,2004,2005,2007,2009,2013,2014,2015,2016,2017,2018,2019
./lib/dns/log.c C 1999,2000,2001,2003,2004,2005,2006,2007,2009,2011,2012,2013,2014,2015,2016,2017,2018,2019
@ -2433,13 +2447,16 @@
./lib/isccfg/include/isccfg/cfg.h C 2000,2001,2002,2004,2005,2006,2007,2010,2013,2014,2015,2016,2018,2019
./lib/isccfg/include/isccfg/dnsconf.h C 2009,2016,2018,2019
./lib/isccfg/include/isccfg/grammar.h C 2002,2003,2004,2005,2006,2007,2008,2009,2010,2011,2013,2014,2015,2016,2017,2018,2019
./lib/isccfg/include/isccfg/kaspconf.h C 2019
./lib/isccfg/include/isccfg/log.h C 2001,2004,2005,2006,2007,2009,2016,2018,2019
./lib/isccfg/include/isccfg/namedconf.h C 2002,2004,2005,2006,2007,2009,2010,2014,2016,2018,2019
./lib/isccfg/include/isccfg/version.h C 2001,2004,2005,2006,2007,2016,2018,2019
./lib/isccfg/kaspconf.c C 2019
./lib/isccfg/log.c C 2001,2004,2005,2006,2007,2016,2018,2019
./lib/isccfg/namedconf.c C 2002,2003,2004,2005,2006,2007,2008,2009,2010,2011,2012,2013,2014,2015,2016,2017,2018,2019
./lib/isccfg/parser.c C 2000,2001,2002,2003,2004,2005,2006,2007,2008,2009,2010,2011,2012,2013,2014,2015,2016,2017,2018,2019
./lib/isccfg/tests/Kyuafile X 2017,2018,2019
./lib/isccfg/tests/duration_test.c C 2019
./lib/isccfg/tests/parser_test.c C 2016,2018,2019
./lib/isccfg/version.c C 1998,1999,2000,2001,2004,2005,2007,2016,2018,2019
./lib/isccfg/win32/DLLMain.c C 2001,2004,2007,2016,2018,2019