mirror of
https://github.com/isc-projects/bind9.git
synced 2026-05-25 10:52:13 -04:00
new: usr: Add dnssec-policy keys configuration check to named-checkconf
A new option `-k` is added to `named-checkconf` that allows checking the `dnssec-policy` `keys` configuration against the configured key stores. If the found key files are not in sync with the given `dnssec-policy`, the check will fail. This is useful to run before migrating to `dnssec-policy`. Closes #5486 Merge branch '5486-named-checkconf-dnssec-policy-key-directory' into 'main' See merge request isc-projects/bind9!10907
This commit is contained in:
commit
23a79b42ea
26 changed files with 1173 additions and 196 deletions
|
|
@ -57,7 +57,7 @@ usage(void);
|
|||
static void
|
||||
usage(void) {
|
||||
fprintf(stderr,
|
||||
"usage: %s [-achijlvz] [-p [-x]] [-t directory] "
|
||||
"usage: %s [-achijklvz] [-p [-x]] [-t directory] "
|
||||
"[named.conf]\n",
|
||||
isc_commandline_progname);
|
||||
exit(EXIT_SUCCESS);
|
||||
|
|
@ -593,7 +593,7 @@ main(int argc, char **argv) {
|
|||
/*
|
||||
* Process memory debugging argument first.
|
||||
*/
|
||||
#define CMDLINE_FLAGS "acdhijlm:nt:pvxz"
|
||||
#define CMDLINE_FLAGS "acdhijklm:nt:pvxz"
|
||||
while ((c = isc_commandline_parse(argc, argv, CMDLINE_FLAGS)) != -1) {
|
||||
switch (c) {
|
||||
case 'm':
|
||||
|
|
@ -638,6 +638,10 @@ main(int argc, char **argv) {
|
|||
nomerge = false;
|
||||
break;
|
||||
|
||||
case 'k':
|
||||
checkflags |= BIND_CHECK_KEYS;
|
||||
break;
|
||||
|
||||
case 'l':
|
||||
list_zones = true;
|
||||
break;
|
||||
|
|
|
|||
|
|
@ -21,7 +21,7 @@ named-checkconf - named configuration file syntax checking tool
|
|||
Synopsis
|
||||
~~~~~~~~
|
||||
|
||||
:program:`named-checkconf` [**-achjlnvz**] [**-p** [**-x** ]] [**-t** directory] {filename}
|
||||
:program:`named-checkconf` [**-achjklnvz**] [**-p** [**-x** ]] [**-t** directory] {filename}
|
||||
|
||||
Description
|
||||
~~~~~~~~~~~
|
||||
|
|
@ -56,6 +56,12 @@ Options
|
|||
|
||||
When loading a zonefile, this option instructs :iscman:`named` to read the journal if it exists.
|
||||
|
||||
.. option:: -k
|
||||
|
||||
Check the `dnssec-policy`'s DNSSEC keys against the key files in
|
||||
the `key-directory`. This is useful when checking a `named.conf`
|
||||
to ensure a DNSSEC policy matches the existing keys.
|
||||
|
||||
.. option:: -l
|
||||
|
||||
This option lists all the configured zones. Each line of output contains the zone
|
||||
|
|
|
|||
|
|
@ -601,6 +601,9 @@ kasp_from_conf(cfg_obj_t *config, isc_mem_t *mctx, const char *name,
|
|||
const cfg_obj_t *keystores = NULL;
|
||||
dns_keystore_t *keystore = NULL;
|
||||
dns_keystorelist_t kslist;
|
||||
unsigned int options = (ISCCFG_KASPCONF_CHECK_ALGORITHMS |
|
||||
ISCCFG_KASPCONF_CHECK_KEYLIST |
|
||||
ISCCFG_KASPCONF_LOG_ERRORS);
|
||||
|
||||
ISC_LIST_INIT(kasplist);
|
||||
ISC_LIST_INIT(kslist);
|
||||
|
|
@ -635,8 +638,8 @@ kasp_from_conf(cfg_obj_t *config, isc_mem_t *mctx, const char *name,
|
|||
continue;
|
||||
}
|
||||
|
||||
result = cfg_kasp_fromconfig(kconfig, NULL, true, mctx, &kslist,
|
||||
&kasplist, &kasp);
|
||||
result = cfg_kasp_fromconfig(kconfig, NULL, options, mctx,
|
||||
&kslist, &kasplist, &kasp);
|
||||
if (result != ISC_R_SUCCESS) {
|
||||
fatal("failed to configure dnssec-policy '%s': %s",
|
||||
cfg_obj_asstring(cfg_tuple_get(kconfig, "name")),
|
||||
|
|
|
|||
|
|
@ -8052,6 +8052,9 @@ configure_kasplist(const cfg_obj_t *config, dns_kasplist_t *kasplist,
|
|||
isc_result_t result = ISC_R_SUCCESS;
|
||||
dns_kasp_t *default_kasp = NULL;
|
||||
const cfg_obj_t *kasps = NULL;
|
||||
unsigned int kaspopts = (ISCCFG_KASPCONF_CHECK_ALGORITHMS |
|
||||
ISCCFG_KASPCONF_CHECK_KEYLIST |
|
||||
ISCCFG_KASPCONF_LOG_ERRORS);
|
||||
|
||||
APPLY_CONFIGURATION_SUBROUTINE_LOG;
|
||||
|
||||
|
|
@ -8063,7 +8066,7 @@ configure_kasplist(const cfg_obj_t *config, dns_kasplist_t *kasplist,
|
|||
cfg_obj_t *kconfig = cfg_listelt_value(element);
|
||||
dns_kasp_t *kasp = NULL;
|
||||
|
||||
result = cfg_kasp_fromconfig(kconfig, default_kasp, true,
|
||||
result = cfg_kasp_fromconfig(kconfig, default_kasp, kaspopts,
|
||||
isc_g_mctx, keystorelist, kasplist,
|
||||
&kasp);
|
||||
if (result != ISC_R_SUCCESS) {
|
||||
|
|
@ -8091,7 +8094,7 @@ configure_kasplist(const cfg_obj_t *config, dns_kasplist_t *kasplist,
|
|||
cfg_obj_t *kconfig = cfg_listelt_value(element);
|
||||
dns_kasp_t *kasp = NULL;
|
||||
|
||||
result = cfg_kasp_fromconfig(kconfig, default_kasp, true,
|
||||
result = cfg_kasp_fromconfig(kconfig, default_kasp, kaspopts,
|
||||
isc_g_mctx, keystorelist, kasplist,
|
||||
&kasp);
|
||||
if (result != ISC_R_SUCCESS) {
|
||||
|
|
|
|||
25
bin/tests/system/checkconf-keys/bad-algorithm.conf.j2
Normal file
25
bin/tests/system/checkconf-keys/bad-algorithm.conf.j2
Normal file
|
|
@ -0,0 +1,25 @@
|
|||
/*
|
||||
* Copyright (C) Internet Systems Consortium, Inc. ("ISC")
|
||||
*
|
||||
* SPDX-License-Identifier: MPL-2.0
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, you can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
*
|
||||
* See the COPYRIGHT file distributed with this work for additional
|
||||
* information regarding copyright ownership.
|
||||
*/
|
||||
|
||||
dnssec-policy "alternative-kz" {
|
||||
keys {
|
||||
ksk key-directory lifetime unlimited algorithm RSASHA256;
|
||||
zsk key-directory lifetime unlimited algorithm RSASHA256;
|
||||
};
|
||||
};
|
||||
|
||||
zone "bad-algorithm.kz.example" {
|
||||
type primary;
|
||||
file "bad-algorithm.kz.example.db";
|
||||
dnssec-policy "alternative-kz";
|
||||
};
|
||||
|
|
@ -0,0 +1,18 @@
|
|||
/*
|
||||
* Copyright (C) Internet Systems Consortium, Inc. ("ISC")
|
||||
*
|
||||
* SPDX-License-Identifier: MPL-2.0
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, you can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
*
|
||||
* See the COPYRIGHT file distributed with this work for additional
|
||||
* information regarding copyright ownership.
|
||||
*/
|
||||
|
||||
zone "bad-default-algorithm.example" {
|
||||
type primary;
|
||||
file "bad-default-algorithm.example.db";
|
||||
dnssec-policy "default";
|
||||
};
|
||||
18
bin/tests/system/checkconf-keys/bad-default-kz.conf.j2
Normal file
18
bin/tests/system/checkconf-keys/bad-default-kz.conf.j2
Normal file
|
|
@ -0,0 +1,18 @@
|
|||
/*
|
||||
* Copyright (C) Internet Systems Consortium, Inc. ("ISC")
|
||||
*
|
||||
* SPDX-License-Identifier: MPL-2.0
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, you can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
*
|
||||
* See the COPYRIGHT file distributed with this work for additional
|
||||
* information regarding copyright ownership.
|
||||
*/
|
||||
|
||||
zone "bad-default-kz.example" {
|
||||
type primary;
|
||||
file "bad-default-kz.example.db";
|
||||
dnssec-policy "default";
|
||||
};
|
||||
33
bin/tests/system/checkconf-keys/bad-keystore.conf.j2
Normal file
33
bin/tests/system/checkconf-keys/bad-keystore.conf.j2
Normal file
|
|
@ -0,0 +1,33 @@
|
|||
/*
|
||||
* Copyright (C) Internet Systems Consortium, Inc. ("ISC")
|
||||
*
|
||||
* SPDX-License-Identifier: MPL-2.0
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, you can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
*
|
||||
* See the COPYRIGHT file distributed with this work for additional
|
||||
* information regarding copyright ownership.
|
||||
*/
|
||||
|
||||
key-store "ksk" {
|
||||
directory "ksk";
|
||||
};
|
||||
|
||||
key-store "zsk" {
|
||||
directory "zsk";
|
||||
};
|
||||
|
||||
dnssec-policy "keystores-kz" {
|
||||
keys {
|
||||
ksk key-store "ksk" lifetime unlimited algorithm ECDSAP256SHA256;
|
||||
zsk key-store "zsk" lifetime unlimited algorithm ECDSAP256SHA256;
|
||||
};
|
||||
};
|
||||
|
||||
zone "bad-keystores.kz.example" {
|
||||
type primary;
|
||||
file "bad-keystores.kz.example.db";
|
||||
dnssec-policy "keystores-kz";
|
||||
};
|
||||
24
bin/tests/system/checkconf-keys/bad-length.conf.j2
Normal file
24
bin/tests/system/checkconf-keys/bad-length.conf.j2
Normal file
|
|
@ -0,0 +1,24 @@
|
|||
/*
|
||||
* Copyright (C) Internet Systems Consortium, Inc. ("ISC")
|
||||
*
|
||||
* SPDX-License-Identifier: MPL-2.0
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, you can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
*
|
||||
* See the COPYRIGHT file distributed with this work for additional
|
||||
* information regarding copyright ownership.
|
||||
*/
|
||||
|
||||
dnssec-policy "alternative-csk" {
|
||||
keys {
|
||||
csk key-directory lifetime unlimited algorithm RSASHA256 2048;
|
||||
};
|
||||
};
|
||||
|
||||
zone "bad-length.csk.example" {
|
||||
type primary;
|
||||
file "bad-length.csk.example.db";
|
||||
dnssec-policy "alternative-csk";
|
||||
};
|
||||
25
bin/tests/system/checkconf-keys/bad-missing-keyfile.conf.j2
Normal file
25
bin/tests/system/checkconf-keys/bad-missing-keyfile.conf.j2
Normal file
|
|
@ -0,0 +1,25 @@
|
|||
/*
|
||||
* Copyright (C) Internet Systems Consortium, Inc. ("ISC")
|
||||
*
|
||||
* SPDX-License-Identifier: MPL-2.0
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, you can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
*
|
||||
* See the COPYRIGHT file distributed with this work for additional
|
||||
* information regarding copyright ownership.
|
||||
*/
|
||||
|
||||
dnssec-policy "default-kz" {
|
||||
keys {
|
||||
ksk key-directory lifetime unlimited algorithm ECDSAP256SHA256;
|
||||
zsk key-directory lifetime unlimited algorithm ECDSAP256SHA256;
|
||||
};
|
||||
};
|
||||
|
||||
zone "missing-keyfile.kz.example" {
|
||||
type primary;
|
||||
file "missing-keyfile.kz.example.db";
|
||||
dnssec-policy "default-kz";
|
||||
};
|
||||
25
bin/tests/system/checkconf-keys/bad-role.conf.j2
Normal file
25
bin/tests/system/checkconf-keys/bad-role.conf.j2
Normal file
|
|
@ -0,0 +1,25 @@
|
|||
/*
|
||||
* Copyright (C) Internet Systems Consortium, Inc. ("ISC")
|
||||
*
|
||||
* SPDX-License-Identifier: MPL-2.0
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, you can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
*
|
||||
* See the COPYRIGHT file distributed with this work for additional
|
||||
* information regarding copyright ownership.
|
||||
*/
|
||||
|
||||
dnssec-policy "default-kz" {
|
||||
keys {
|
||||
ksk key-directory lifetime unlimited algorithm ECDSAP256SHA256;
|
||||
zsk key-directory lifetime unlimited algorithm ECDSAP256SHA256;
|
||||
};
|
||||
};
|
||||
|
||||
zone "bad-role.kz.example" {
|
||||
type primary;
|
||||
file "bad-role.kz.example.db";
|
||||
dnssec-policy "default-kz";
|
||||
};
|
||||
|
|
@ -0,0 +1,25 @@
|
|||
/*
|
||||
* Copyright (C) Internet Systems Consortium, Inc. ("ISC")
|
||||
*
|
||||
* SPDX-License-Identifier: MPL-2.0
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, you can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
*
|
||||
* See the COPYRIGHT file distributed with this work for additional
|
||||
* information regarding copyright ownership.
|
||||
*/
|
||||
|
||||
dnssec-policy "default-kz" {
|
||||
keys {
|
||||
ksk key-directory lifetime unlimited algorithm ECDSAP256SHA256;
|
||||
zsk key-directory lifetime unlimited algorithm ECDSAP256SHA256;
|
||||
};
|
||||
};
|
||||
|
||||
zone "superfluous-keyfile.kz.example" {
|
||||
type primary;
|
||||
file "superfluous-keyfile.kz.example.db";
|
||||
dnssec-policy "default-kz";
|
||||
};
|
||||
24
bin/tests/system/checkconf-keys/bad-tagrange.conf.j2
Normal file
24
bin/tests/system/checkconf-keys/bad-tagrange.conf.j2
Normal file
|
|
@ -0,0 +1,24 @@
|
|||
/*
|
||||
* Copyright (C) Internet Systems Consortium, Inc. ("ISC")
|
||||
*
|
||||
* SPDX-License-Identifier: MPL-2.0
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, you can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
*
|
||||
* See the COPYRIGHT file distributed with this work for additional
|
||||
* information regarding copyright ownership.
|
||||
*/
|
||||
|
||||
dnssec-policy "tagrange-csk" {
|
||||
keys {
|
||||
csk key-directory lifetime unlimited algorithm ECDSAP256SHA256 tag-range 0 32767;
|
||||
};
|
||||
};
|
||||
|
||||
zone "bad-tagrange.csk.example" {
|
||||
type primary;
|
||||
file "bad-tagrange.csk.example.db";
|
||||
dnssec-policy "tagrange-csk";
|
||||
};
|
||||
90
bin/tests/system/checkconf-keys/named.conf.j2
Normal file
90
bin/tests/system/checkconf-keys/named.conf.j2
Normal file
|
|
@ -0,0 +1,90 @@
|
|||
/*
|
||||
* Copyright (C) Internet Systems Consortium, Inc. ("ISC")
|
||||
*
|
||||
* SPDX-License-Identifier: MPL-2.0
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, you can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
*
|
||||
* See the COPYRIGHT file distributed with this work for additional
|
||||
* information regarding copyright ownership.
|
||||
*/
|
||||
|
||||
key-store "ksk" {
|
||||
directory "ksk";
|
||||
};
|
||||
|
||||
key-store "zsk" {
|
||||
directory "zsk";
|
||||
};
|
||||
|
||||
dnssec-policy "alternative-kz" {
|
||||
keys {
|
||||
ksk key-directory lifetime unlimited algorithm RSASHA256 2048;
|
||||
zsk key-directory lifetime unlimited algorithm RSASHA256 2048;
|
||||
};
|
||||
};
|
||||
|
||||
dnssec-policy "alternative-csk" {
|
||||
keys {
|
||||
csk key-directory lifetime unlimited algorithm RSASHA256 2048;
|
||||
};
|
||||
};
|
||||
|
||||
dnssec-policy "default-kz" {
|
||||
keys {
|
||||
ksk key-directory lifetime unlimited algorithm ECDSAP256SHA256;
|
||||
zsk key-directory lifetime unlimited algorithm ECDSAP256SHA256;
|
||||
};
|
||||
};
|
||||
|
||||
dnssec-policy "default-csk" {
|
||||
keys {
|
||||
csk key-directory lifetime unlimited algorithm ECDSAP256SHA256;
|
||||
};
|
||||
};
|
||||
|
||||
|
||||
dnssec-policy "keystores-kz" {
|
||||
keys {
|
||||
ksk key-store "ksk" lifetime unlimited algorithm ECDSAP256SHA256;
|
||||
zsk key-store "zsk" lifetime unlimited algorithm ECDSAP256SHA256;
|
||||
};
|
||||
};
|
||||
|
||||
zone "default.example" {
|
||||
type primary;
|
||||
file "default.example.db";
|
||||
dnssec-policy "default";
|
||||
};
|
||||
|
||||
zone "alternative.kz.example" {
|
||||
type primary;
|
||||
file "alternative.kz.example.db";
|
||||
dnssec-policy "alternative-kz";
|
||||
};
|
||||
|
||||
zone "alternative.csk.example" {
|
||||
type primary;
|
||||
file "alternative.csk.example.db";
|
||||
dnssec-policy "alternative-csk";
|
||||
};
|
||||
|
||||
zone "default.kz.example" {
|
||||
type primary;
|
||||
file "default.kz.example.db";
|
||||
dnssec-policy "default-kz";
|
||||
};
|
||||
|
||||
zone "default.csk.example" {
|
||||
type primary;
|
||||
file "default.csk.example.db";
|
||||
dnssec-policy "default-csk";
|
||||
};
|
||||
|
||||
zone "keystores.kz.example" {
|
||||
type primary;
|
||||
file "keystores.kz.example.db";
|
||||
dnssec-policy "keystores-kz";
|
||||
};
|
||||
85
bin/tests/system/checkconf-keys/setup.sh
Normal file
85
bin/tests/system/checkconf-keys/setup.sh
Normal file
|
|
@ -0,0 +1,85 @@
|
|||
#!/bin/sh -e
|
||||
|
||||
# Copyright (C) Internet Systems Consortium, Inc. ("ISC")
|
||||
#
|
||||
# SPDX-License-Identifier: MPL-2.0
|
||||
#
|
||||
# This Source Code Form is subject to the terms of the Mozilla Public
|
||||
# License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
# file, you can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
#
|
||||
# See the COPYRIGHT file distributed with this work for additional
|
||||
# information regarding copyright ownership.
|
||||
|
||||
# shellcheck source=conf.sh
|
||||
. ../conf.sh
|
||||
|
||||
set -e
|
||||
|
||||
mkdir ksk
|
||||
mkdir zsk
|
||||
|
||||
zone="default.example"
|
||||
cp template.db.in "${zone}.db"
|
||||
$KEYGEN -a 13 -fK $zone 2>keygen.out.$zone.1
|
||||
|
||||
zone="bad-default-kz.example"
|
||||
cp template.db.in "${zone}.db"
|
||||
$KEYGEN -a 13 -fK $zone 2>keygen.out.$zone.1
|
||||
$KEYGEN -a 13 $zone 2>keygen.out.$zone.2
|
||||
|
||||
zone="bad-default-algorithm.example"
|
||||
cp template.db.in "${zone}.db"
|
||||
$KEYGEN -a 8 -fK $zone 2>keygen.out.$zone.1
|
||||
|
||||
zone="alternative.kz.example"
|
||||
cp template.db.in "${zone}.db"
|
||||
$KEYGEN -a RSASHA256 -b 2048 $zone 2>keygen.out.$zone.1
|
||||
$KEYGEN -a RSASHA256 -b 2048 -fK $zone 2>keygen.out.$zone.2
|
||||
|
||||
zone="alternative.csk.example"
|
||||
cp template.db.in "${zone}.db"
|
||||
$KEYGEN -a RSASHA256 -b 2048 -fK $zone 2>keygen.out.$zone.2
|
||||
|
||||
zone="default.kz.example"
|
||||
cp template.db.in "${zone}.db"
|
||||
$KEYGEN -a 13 $zone 2>keygen.out.$zone.1
|
||||
$KEYGEN -a 13 -fK $zone 2>keygen.out.$zone.2
|
||||
|
||||
zone="default.csk.example"
|
||||
cp template.db.in "${zone}.db"
|
||||
$KEYGEN -a 13 -fK $zone 2>keygen.out.$zone.2
|
||||
|
||||
zone="keystores.kz.example"
|
||||
cp template.db.in "${zone}.db"
|
||||
$KEYGEN -a 13 -fK -K ksk $zone 2>keygen.out.$zone.2
|
||||
$KEYGEN -a 13 -K zsk $zone 2>keygen.out.$zone.2
|
||||
|
||||
zone="superfluous-keyfile.kz.example"
|
||||
cp template.db.in "${zone}.db"
|
||||
$KEYGEN -a 13 $zone 2>keygen.out.$zone.1
|
||||
$KEYGEN -a 13 -fK $zone 2>keygen.out.$zone.2
|
||||
$KEYGEN -a 13 $zone 2>keygen.out.$zone.3 # superfluous
|
||||
|
||||
zone="missing-keyfile.kz.example"
|
||||
cp template.db.in "${zone}.db"
|
||||
$KEYGEN -a 13 $zone 2>keygen.out.$zone.1
|
||||
# no ksk
|
||||
|
||||
zone="bad-algorithm.kz.example"
|
||||
cp template.db.in "${zone}.db"
|
||||
$KEYGEN -a 13 $zone 2>keygen.out.$zone.1
|
||||
$KEYGEN -a 13 -fK $zone 2>keygen.out.$zone.2
|
||||
|
||||
zone="bad-length.csk.example"
|
||||
cp template.db.in "${zone}.db"
|
||||
$KEYGEN -a 8 -b 4096 -fK $zone 2>keygen.out.$zone.2
|
||||
|
||||
zone="bad-tagrange.csk.example"
|
||||
cp template.db.in "${zone}.db"
|
||||
$KEYGEN -a 13 -M 32768:65535 -fK $zone 2>keygen.out.$zone.2
|
||||
|
||||
zone="bad-role.kz.example"
|
||||
cp template.db.in "${zone}.db"
|
||||
$KEYGEN -a 13 -fK $zone 2>keygen.out.$zone.1
|
||||
$KEYGEN -a 13 -fK $zone 2>keygen.out.$zone.2
|
||||
27
bin/tests/system/checkconf-keys/template.db.in
Normal file
27
bin/tests/system/checkconf-keys/template.db.in
Normal file
|
|
@ -0,0 +1,27 @@
|
|||
; Copyright (C) Internet Systems Consortium, Inc. ("ISC")
|
||||
;
|
||||
; SPDX-License-Identifier: MPL-2.0
|
||||
;
|
||||
; This Source Code Form is subject to the terms of the Mozilla Public
|
||||
; License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
; file, you can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
;
|
||||
; See the COPYRIGHT file distributed with this work for additional
|
||||
; information regarding copyright ownership.
|
||||
|
||||
$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
|
||||
|
||||
162
bin/tests/system/checkconf-keys/tests_checkconf_keys.py
Normal file
162
bin/tests/system/checkconf-keys/tests_checkconf_keys.py
Normal file
|
|
@ -0,0 +1,162 @@
|
|||
# Copyright (C) Internet Systems Consortium, Inc. ("ISC")
|
||||
#
|
||||
# SPDX-License-Identifier: MPL-2.0
|
||||
#
|
||||
# This Source Code Form is subject to the terms of the Mozilla Public
|
||||
# License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
# file, you can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
#
|
||||
# See the COPYRIGHT file distributed with this work for additional
|
||||
# information regarding copyright ownership.
|
||||
|
||||
import os
|
||||
|
||||
import pytest
|
||||
|
||||
import isctest
|
||||
|
||||
pytestmark = pytest.mark.extra_artifacts(
|
||||
[
|
||||
"bad-*.conf",
|
||||
"K*.key",
|
||||
"K*.private",
|
||||
"K*.state",
|
||||
"keygen.out.*",
|
||||
"named.conf",
|
||||
"*.db",
|
||||
"ksk/",
|
||||
"zsk/",
|
||||
]
|
||||
)
|
||||
|
||||
CHECKCONF = os.environ["CHECKCONF"]
|
||||
|
||||
|
||||
def test_dnssecpolicy_keystore():
|
||||
# Good configuration.
|
||||
isctest.run.cmd([CHECKCONF, "-k", "named.conf"])
|
||||
|
||||
# Superfluous key file.
|
||||
zone = "superfluous-keyfile.kz.example"
|
||||
out = isctest.run.cmd(
|
||||
[CHECKCONF, "-k", "bad-superfluous-keyfile.conf"], raise_on_exception=False
|
||||
)
|
||||
err = out.stdout.decode("utf-8")
|
||||
assert f"zone '{zone}': wrong number of key files (3, expected 2)" in err
|
||||
|
||||
# Missing key file.
|
||||
zone = "missing-keyfile.kz.example"
|
||||
out = isctest.run.cmd(
|
||||
[CHECKCONF, "-k", "bad-missing-keyfile.conf"], raise_on_exception=False
|
||||
)
|
||||
err = out.stdout.decode("utf-8")
|
||||
assert f"zone '{zone}': wrong number of key files (1, expected 2)" in err
|
||||
|
||||
# Mismatch algorithm.
|
||||
zone = "bad-algorithm.kz.example"
|
||||
out = isctest.run.cmd(
|
||||
[CHECKCONF, "-k", "bad-algorithm.conf"], raise_on_exception=False
|
||||
)
|
||||
err = out.stdout.decode("utf-8")
|
||||
keys = isctest.kasp.keydir_to_keylist(zone)
|
||||
assert len(keys) == 2
|
||||
assert (
|
||||
f"zone '{zone}': key file '{zone}/ECDSAP256SHA256/{keys[0].tag}' does not match dnssec-policy alternative-kz"
|
||||
in err
|
||||
)
|
||||
assert (
|
||||
f"zone '{zone}': key file '{zone}/ECDSAP256SHA256/{keys[1].tag}' does not match dnssec-policy alternative-kz"
|
||||
in err
|
||||
)
|
||||
assert (
|
||||
f"zone '{zone}': no key file found matching dnssec-policy alternative-kz key:'ksk algorithm:RSASHA256 length:2048 tag-range:0-65535'"
|
||||
in err
|
||||
)
|
||||
assert (
|
||||
f"zone '{zone}': no key file found matching dnssec-policy alternative-kz key:'zsk algorithm:RSASHA256 length:2048 tag-range:0-65535'"
|
||||
in err
|
||||
)
|
||||
|
||||
# Mismatch length
|
||||
zone = "bad-length.csk.example"
|
||||
out = isctest.run.cmd(
|
||||
[CHECKCONF, "-k", "bad-length.conf"], raise_on_exception=False
|
||||
)
|
||||
err = out.stdout.decode("utf-8")
|
||||
keys = isctest.kasp.keydir_to_keylist(zone)
|
||||
assert len(keys) == 1
|
||||
assert (
|
||||
f"zone '{zone}': key file '{zone}/RSASHA256/{keys[0].tag}' does not match dnssec-policy alternative-csk"
|
||||
in err
|
||||
)
|
||||
assert (
|
||||
f"zone '{zone}': no key file found matching dnssec-policy alternative-csk key:'csk algorithm:RSASHA256 length:2048 tag-range:0-65535'"
|
||||
in err
|
||||
)
|
||||
|
||||
# Mismatch tag range
|
||||
zone = "bad-tagrange.csk.example"
|
||||
out = isctest.run.cmd(
|
||||
[CHECKCONF, "-k", "bad-tagrange.conf"], raise_on_exception=False
|
||||
)
|
||||
err = out.stdout.decode("utf-8")
|
||||
keys = isctest.kasp.keydir_to_keylist(zone)
|
||||
assert len(keys) == 1
|
||||
assert (
|
||||
f"zone '{zone}': key file '{zone}/ECDSAP256SHA256/{keys[0].tag}' does not match dnssec-policy tagrange-csk"
|
||||
in err
|
||||
)
|
||||
assert (
|
||||
f"zone '{zone}': no key file found matching dnssec-policy tagrange-csk key:'csk algorithm:ECDSAP256SHA256 length:256 tag-range:0-32767'"
|
||||
in err
|
||||
)
|
||||
|
||||
# Mismatch role
|
||||
zone = "bad-role.kz.example"
|
||||
out = isctest.run.cmd([CHECKCONF, "-k", "bad-role.conf"], raise_on_exception=False)
|
||||
err = out.stdout.decode("utf-8")
|
||||
keys = isctest.kasp.keydir_to_keylist(zone)
|
||||
assert len(keys) == 2
|
||||
assert (
|
||||
f"zone '{zone}': no key file found matching dnssec-policy default-kz key:'zsk algorithm:ECDSAP256SHA256 length:256 tag-range:0-65535'"
|
||||
in err
|
||||
)
|
||||
|
||||
# Mismatch algorithm (default policy)
|
||||
zone = "bad-default-algorithm.example"
|
||||
out = isctest.run.cmd(
|
||||
[CHECKCONF, "-k", "bad-default-algorithm.conf"], raise_on_exception=False
|
||||
)
|
||||
err = out.stdout.decode("utf-8")
|
||||
keys = isctest.kasp.keydir_to_keylist(zone)
|
||||
assert len(keys) == 1
|
||||
assert (
|
||||
f"zone '{zone}': key file '{zone}/RSASHA256/{keys[0].tag}' does not match dnssec-policy default"
|
||||
in err
|
||||
)
|
||||
assert (
|
||||
f"zone '{zone}': no key file found matching dnssec-policy default key:'csk algorithm:ECDSAP256SHA256 length:256 tag-range:0-65535'"
|
||||
in err
|
||||
)
|
||||
|
||||
# Mismatch role (default policy)
|
||||
zone = "bad-default-kz.example"
|
||||
out = isctest.run.cmd(
|
||||
[CHECKCONF, "-k", "bad-default-kz.conf"], raise_on_exception=False
|
||||
)
|
||||
err = out.stdout.decode("utf-8")
|
||||
keys = isctest.kasp.keydir_to_keylist(zone)
|
||||
assert len(keys) == 2
|
||||
assert (
|
||||
f"zone '{zone}': key file '{zone}/ECDSAP256SHA256/{keys[0].tag}' does not match dnssec-policy default"
|
||||
in err
|
||||
)
|
||||
assert (
|
||||
f"zone '{zone}': key file '{zone}/ECDSAP256SHA256/{keys[1].tag}' does not match dnssec-policy default"
|
||||
in err
|
||||
)
|
||||
assert (
|
||||
f"zone '{zone}': no key file found matching dnssec-policy default key:'csk algorithm:ECDSAP256SHA256 length:256 tag-range:0-65535'"
|
||||
in err
|
||||
)
|
||||
assert f"zone '{zone}': wrong number of key files (2, expected 1)" in err
|
||||
|
|
@ -31,6 +31,7 @@
|
|||
|
||||
#include <dns/dnssec.h>
|
||||
#include <dns/keystore.h>
|
||||
#include <dns/name.h>
|
||||
#include <dns/types.h>
|
||||
|
||||
/* For storing a list of digest types */
|
||||
|
|
@ -137,6 +138,8 @@ struct dns_kasp {
|
|||
#define DNS_KASP_KEY_ROLE_KSK 0x01
|
||||
#define DNS_KASP_KEY_ROLE_ZSK 0x02
|
||||
|
||||
#define DNS_KASP_KEY_FORMATSIZE (DNS_NAME_FORMATSIZE + 64)
|
||||
|
||||
void
|
||||
dns_kasp_create(isc_mem_t *mctx, const char *name, dns_kasp_t **kaspp);
|
||||
/*%<
|
||||
|
|
@ -764,6 +767,17 @@ dns_kasp_key_match(dns_kasp_key_t *key, dns_dnsseckey_t *dkey);
|
|||
*\li False, otherwise.
|
||||
*/
|
||||
|
||||
void
|
||||
dns_kasp_key_format(dns_kasp_key_t *key, char *cp, unsigned int size);
|
||||
/*%<
|
||||
* Write the identifying information about the policy key (role,
|
||||
* algorithm, tag range) into a string 'cp' of size 'size'.
|
||||
* Requires:
|
||||
*
|
||||
*\li key != NULL
|
||||
*\li cp != NULL
|
||||
*/
|
||||
|
||||
bool
|
||||
dns_kasp_nsec3(dns_kasp_t *kasp);
|
||||
/*%<
|
||||
|
|
|
|||
|
|
@ -37,6 +37,21 @@ dns_keymgr_settime_syncpublish(dst_key_t *key, dns_kasp_t *kasp, bool first);
|
|||
*\li 'kasp' is a valid DNSSEC policy.
|
||||
*/
|
||||
|
||||
void
|
||||
dns_keymgr_key_init(dns_dnsseckey_t *key, dns_kasp_t *kasp, isc_stdtime_t now,
|
||||
bool csk);
|
||||
/*
|
||||
* Initialize this key's properties if not already present. A key created
|
||||
* and derived from a dnssec-policy will have the required metadata available,
|
||||
* otherwise these may be missing and need to be initialized. The key states
|
||||
* will be initialized according to existing timing metadata. If 'csk' is
|
||||
* set to true, the key is considered a combined signing key (CSK).
|
||||
*
|
||||
* Requires:
|
||||
*\li 'key' is a valid DNSSEC key.
|
||||
*\li 'kasp' is a valid DNSSEC policy.
|
||||
*/
|
||||
|
||||
isc_result_t
|
||||
dns_keymgr_run(const dns_name_t *origin, dns_rdataclass_t rdclass,
|
||||
isc_mem_t *mctx, dns_dnsseckeylist_t *keyring,
|
||||
|
|
|
|||
|
|
@ -1221,7 +1221,6 @@ dst_algorithm_totext(dst_algorithm_t alg, isc_buffer_t *target);
|
|||
*\li ISC_R_NOSPACE target buffer is too small
|
||||
*/
|
||||
|
||||
#define DST_ALGORITHM_FORMATSIZE 20
|
||||
void
|
||||
dst_algorithm_format(dst_algorithm_t dst_alg, char *data, unsigned int length);
|
||||
/*%<
|
||||
|
|
|
|||
|
|
@ -559,6 +559,21 @@ dns_kasp_key_match(dns_kasp_key_t *key, dns_dnsseckey_t *dkey) {
|
|||
return true;
|
||||
}
|
||||
|
||||
void
|
||||
dns_kasp_key_format(dns_kasp_key_t *key, char *cp, unsigned int size) {
|
||||
REQUIRE(key != NULL);
|
||||
REQUIRE(cp != NULL);
|
||||
|
||||
char algstr[DNS_NAME_FORMATSIZE];
|
||||
bool csk = dns_kasp_key_ksk(key) && dns_kasp_key_zsk(key);
|
||||
const char *rolestr = (csk ? "csk"
|
||||
: (dns_kasp_key_ksk(key) ? "ksk" : "zsk"));
|
||||
|
||||
dst_algorithm_format(key->algorithm, algstr, sizeof(algstr));
|
||||
snprintf(cp, size, "%s algorithm:%s length:%u tag-range:%u-%u", rolestr,
|
||||
algstr, dns_kasp_key_size(key), key->tag_min, key->tag_max);
|
||||
}
|
||||
|
||||
uint8_t
|
||||
dns_kasp_nsec3iter(dns_kasp_t *kasp) {
|
||||
REQUIRE(kasp != NULL);
|
||||
|
|
|
|||
|
|
@ -1635,16 +1635,9 @@ transition:
|
|||
return result;
|
||||
}
|
||||
|
||||
/*
|
||||
* See if this key needs to be initialized with properties. A key created
|
||||
* and derived from a dnssec-policy will have the required metadata available,
|
||||
* otherwise these may be missing and need to be initialized. The key states
|
||||
* will be initialized according to existing timing metadata.
|
||||
*
|
||||
*/
|
||||
static void
|
||||
keymgr_key_init(dns_dnsseckey_t *key, dns_kasp_t *kasp, isc_stdtime_t now,
|
||||
bool csk) {
|
||||
void
|
||||
dns_keymgr_key_init(dns_dnsseckey_t *key, dns_kasp_t *kasp, isc_stdtime_t now,
|
||||
bool csk) {
|
||||
bool ksk, zsk;
|
||||
isc_result_t ret;
|
||||
isc_stdtime_t active = 0, pub = 0, syncpub = 0, retire = 0, remove = 0;
|
||||
|
|
@ -1926,7 +1919,7 @@ keymgr_key_rollover(dns_kasp_key_t *kaspkey, dns_dnsseckey_t *active_key,
|
|||
dst_key_setttl(dst_key, dns_kasp_dnskeyttl(kasp));
|
||||
dst_key_settime(dst_key, DST_TIME_CREATED, now);
|
||||
dns_dnsseckey_create(mctx, &dst_key, &new_key);
|
||||
keymgr_key_init(new_key, kasp, now, csk);
|
||||
dns_keymgr_key_init(new_key, kasp, now, csk);
|
||||
keycreated = true;
|
||||
}
|
||||
dst_key_setnum(new_key->key, DST_NUM_LIFETIME, lifetime);
|
||||
|
|
@ -2174,7 +2167,7 @@ dns_keymgr_run(const dns_name_t *origin, dns_rdataclass_t rdclass,
|
|||
ISC_LIST_FOREACH(*keyring, dkey, link) {
|
||||
bool found_match = false;
|
||||
|
||||
keymgr_key_init(dkey, kasp, now, numkeys == 1);
|
||||
dns_keymgr_key_init(dkey, kasp, now, numkeys == 1);
|
||||
|
||||
ISC_LIST_FOREACH(dns_kasp_keys(kasp), kkey, link) {
|
||||
if (dns_kasp_key_match(kkey, dkey)) {
|
||||
|
|
@ -2785,7 +2778,7 @@ dns_keymgr_offline(const dns_name_t *origin, dns_dnsseckeylist_t *keyring,
|
|||
continue;
|
||||
}
|
||||
|
||||
keymgr_key_init(dkey, kasp, now, false);
|
||||
dns_keymgr_key_init(dkey, kasp, now, false);
|
||||
|
||||
/* Get current metadata */
|
||||
RETERR(dst_key_getstate(dkey->key, DST_KEY_DNSKEY,
|
||||
|
|
|
|||
|
|
@ -47,6 +47,7 @@
|
|||
#include <dns/fixedname.h>
|
||||
#include <dns/journal.h>
|
||||
#include <dns/kasp.h>
|
||||
#include <dns/keymgr.h>
|
||||
#include <dns/keystore.h>
|
||||
#include <dns/keyvalues.h>
|
||||
#include <dns/peer.h>
|
||||
|
|
@ -1397,6 +1398,11 @@ check_options(const cfg_obj_t *options, const cfg_obj_t *config,
|
|||
if (obj != NULL) {
|
||||
bool bad_kasp = false;
|
||||
bool bad_name = false;
|
||||
unsigned int kaspopts = (ISCCFG_KASPCONF_CHECK_KEYLIST |
|
||||
ISCCFG_KASPCONF_LOG_ERRORS);
|
||||
if (check_algorithms) {
|
||||
kaspopts |= ISCCFG_KASPCONF_CHECK_ALGORITHMS;
|
||||
}
|
||||
|
||||
if (optlevel != optlevel_config && !cfg_obj_isstring(obj)) {
|
||||
bad_kasp = true;
|
||||
|
|
@ -1422,8 +1428,8 @@ check_options(const cfg_obj_t *options, const cfg_obj_t *config,
|
|||
}
|
||||
|
||||
ret = cfg_kasp_fromconfig(
|
||||
kconfig, NULL, check_algorithms,
|
||||
mctx, &kslist, &list, &kasp);
|
||||
kconfig, NULL, kaspopts, mctx,
|
||||
&kslist, &list, &kasp);
|
||||
if (ret != ISC_R_SUCCESS) {
|
||||
if (result == ISC_R_SUCCESS) {
|
||||
result = ret;
|
||||
|
|
@ -2815,29 +2821,30 @@ cleanup:
|
|||
|
||||
static isc_result_t
|
||||
check_keydir(const cfg_obj_t *config, const cfg_obj_t *zconfig,
|
||||
dns_name_t *zname, const char *name, const char *keydir,
|
||||
isc_symtab_t *keydirs, isc_mem_t *mctx) {
|
||||
dns_name_t *origin, const char *zname, const char *name,
|
||||
const char *keydir, isc_symtab_t *keydirs, isc_mem_t *mctx,
|
||||
bool check_keys) {
|
||||
const char *dir = keydir;
|
||||
isc_result_t ret, result = ISC_R_SUCCESS;
|
||||
bool do_cleanup = false;
|
||||
bool done = false;
|
||||
bool keystore = false;
|
||||
const cfg_obj_t *kasps = NULL;
|
||||
const cfg_obj_t *kaspobj = NULL;
|
||||
const cfg_obj_t *obj = NULL;
|
||||
dns_kasp_t *default_kasp = NULL;
|
||||
dns_kasp_t *kasp = NULL;
|
||||
dns_kasplist_t kasplist;
|
||||
const cfg_obj_t *keystores = NULL;
|
||||
dns_keystorelist_t kslist;
|
||||
isc_time_t timenow;
|
||||
isc_stdtime_t now;
|
||||
|
||||
timenow = isc_time_now();
|
||||
now = isc_time_seconds(&timenow);
|
||||
|
||||
/* If no dnssec-policy or key-store, use the dir (key-directory) */
|
||||
(void)cfg_map_get(config, "dnssec-policy", &kasps);
|
||||
(void)cfg_map_get(config, "key-store", &keystores);
|
||||
if (kasps == NULL || keystores == NULL) {
|
||||
goto check;
|
||||
}
|
||||
|
||||
ISC_LIST_INIT(kasplist);
|
||||
ISC_LIST_INIT(kslist);
|
||||
do_cleanup = true;
|
||||
|
||||
/*
|
||||
* Build the keystore list.
|
||||
|
|
@ -2849,36 +2856,86 @@ check_keydir(const cfg_obj_t *config, const cfg_obj_t *zconfig,
|
|||
(void)cfg_keystore_fromconfig(NULL, mctx, &kslist, NULL);
|
||||
|
||||
/*
|
||||
* Look for the dnssec-policy by name, which is the dnssec-policy
|
||||
* for the zone in question.
|
||||
* dnssec-policy "default".
|
||||
*/
|
||||
ret = cfg_kasp_builtinconfig(mctx, "default", &kslist, &kasplist,
|
||||
&default_kasp);
|
||||
if (ret != ISC_R_SUCCESS) {
|
||||
cfg_obj_log(config, ISC_LOG_ERROR,
|
||||
"failed to load the 'default' dnssec-policy: %s",
|
||||
isc_result_totext(ret));
|
||||
result = ret;
|
||||
goto check;
|
||||
}
|
||||
dns_kasp_freeze(default_kasp);
|
||||
|
||||
/*
|
||||
* dnssec-policy "insecure".
|
||||
*/
|
||||
ret = cfg_kasp_builtinconfig(mctx, "insecure", &kslist, &kasplist,
|
||||
&kasp);
|
||||
if (ret != ISC_R_SUCCESS) {
|
||||
cfg_obj_log(config, ISC_LOG_ERROR,
|
||||
"failed to load the 'insecure' dnssec-policy: %s",
|
||||
isc_result_totext(ret));
|
||||
result = ret;
|
||||
goto check;
|
||||
}
|
||||
dns_kasp_freeze(kasp);
|
||||
dns_kasp_detach(&kasp);
|
||||
|
||||
/*
|
||||
* Configured dnssec-policy clauses.
|
||||
*/
|
||||
CFG_LIST_FOREACH(kasps, element) {
|
||||
cfg_obj_t *kconfig = cfg_listelt_value(element);
|
||||
const cfg_obj_t *kaspobj = NULL;
|
||||
obj = NULL;
|
||||
|
||||
if (!cfg_obj_istuple(kconfig)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
kaspobj = cfg_tuple_get(kconfig, "name");
|
||||
if (strcmp(name, cfg_obj_asstring(kaspobj)) != 0) {
|
||||
continue;
|
||||
}
|
||||
|
||||
ret = cfg_kasp_fromconfig(kconfig, NULL, false, mctx, &kslist,
|
||||
&kasplist, &kasp);
|
||||
obj = cfg_tuple_get(kconfig, "name");
|
||||
ret = cfg_kasp_fromconfig(kconfig, default_kasp, 0, mctx,
|
||||
&kslist, &kasplist, &kasp);
|
||||
if (ret != ISC_R_SUCCESS) {
|
||||
kasp = NULL;
|
||||
result = ret;
|
||||
goto check;
|
||||
}
|
||||
|
||||
break;
|
||||
if (strcmp(name, cfg_obj_asstring(obj)) == 0) {
|
||||
kaspobj = obj;
|
||||
dns_kasp_freeze(kasp);
|
||||
}
|
||||
dns_kasp_detach(&kasp);
|
||||
}
|
||||
if (kasp == NULL) {
|
||||
|
||||
/*
|
||||
* Look for the dnssec-policy by name, which is the dnssec-policy
|
||||
* for the zone in question.
|
||||
*/
|
||||
ret = dns_kasplist_find(&kasplist, name, &kasp);
|
||||
if (ret != ISC_R_SUCCESS) {
|
||||
cfg_obj_log(config, ISC_LOG_ERROR,
|
||||
"no dnssec-policy found for zone '%s'", zname);
|
||||
result = ISC_R_NOTFOUND;
|
||||
goto check;
|
||||
}
|
||||
INSIST(kasp != NULL);
|
||||
|
||||
if (kaspobj == NULL) {
|
||||
kaspobj = kasps == NULL ? config : kasps;
|
||||
}
|
||||
|
||||
if (strcmp(name, "insecure") == 0 || strcmp(name, "default") == 0) {
|
||||
ret = keydirexist(zconfig, "key-directory", origin, dir, name,
|
||||
keydirs, mctx);
|
||||
if (ret != ISC_R_SUCCESS) {
|
||||
result = ret;
|
||||
}
|
||||
}
|
||||
|
||||
/* Check key-stores of keys */
|
||||
dns_kasp_freeze(kasp);
|
||||
ISC_LIST_FOREACH(dns_kasp_keys(kasp), kkey, link) {
|
||||
dns_keystore_t *kks = dns_kasp_key_keystore(kkey);
|
||||
dir = dns_keystore_directory(kks, keydir);
|
||||
|
|
@ -2888,35 +2945,108 @@ check_keydir(const cfg_obj_t *config, const cfg_obj_t *zconfig,
|
|||
ret = keydirexist(zconfig,
|
||||
keystore ? "key-store directory"
|
||||
: "key-directory",
|
||||
zname, dir, name, keydirs, mctx);
|
||||
origin, dir, name, keydirs, mctx);
|
||||
if (ret != ISC_R_SUCCESS) {
|
||||
result = ret;
|
||||
}
|
||||
}
|
||||
dns_kasp_thaw(kasp);
|
||||
done = true;
|
||||
|
||||
if (check_keys) {
|
||||
/* Find matching key files. */
|
||||
dns_dnsseckeylist_t keys;
|
||||
int numkaspkeys = 0;
|
||||
int numkeyfiles = 0;
|
||||
|
||||
ISC_LIST_INIT(keys);
|
||||
ret = dns_dnssec_findmatchingkeys(origin, kasp, keydir, &kslist,
|
||||
now, mctx, &keys);
|
||||
if (ret != ISC_R_SUCCESS) {
|
||||
result = ret;
|
||||
}
|
||||
|
||||
ISC_LIST_FOREACH(keys, dkey, link) {
|
||||
numkeyfiles++;
|
||||
}
|
||||
|
||||
ISC_LIST_FOREACH(keys, dkey, link) {
|
||||
bool found_match = false;
|
||||
|
||||
dns_keymgr_key_init(dkey, kasp, now, numkeyfiles == 1);
|
||||
|
||||
ISC_LIST_FOREACH(dns_kasp_keys(kasp), kkey, link) {
|
||||
if (dns_kasp_key_match(kkey, dkey)) {
|
||||
found_match = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!found_match) {
|
||||
char keystr[DST_KEY_FORMATSIZE];
|
||||
dst_key_format(dkey->key, keystr,
|
||||
sizeof(keystr));
|
||||
cfg_obj_log(kaspobj, ISC_LOG_ERROR,
|
||||
"zone '%s': key file '%s' does not "
|
||||
"match dnssec-policy %s",
|
||||
zname, keystr,
|
||||
dns_kasp_getname(kasp));
|
||||
result = ISC_R_NOTFOUND;
|
||||
}
|
||||
}
|
||||
|
||||
ISC_LIST_FOREACH(dns_kasp_keys(kasp), kkey, link) {
|
||||
bool found_match = false;
|
||||
|
||||
numkaspkeys++;
|
||||
|
||||
ISC_LIST_FOREACH(keys, dkey, link) {
|
||||
if (dns_kasp_key_match(kkey, dkey)) {
|
||||
found_match = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!found_match) {
|
||||
char keystr[DNS_KASP_KEY_FORMATSIZE];
|
||||
dns_kasp_key_format(kkey, keystr,
|
||||
sizeof(keystr));
|
||||
|
||||
cfg_obj_log(
|
||||
kaspobj, ISC_LOG_ERROR,
|
||||
"zone '%s': no key file found matching "
|
||||
"dnssec-policy %s key:'%s'",
|
||||
zname, dns_kasp_getname(kasp), keystr);
|
||||
result = ISC_R_NOTFOUND;
|
||||
}
|
||||
}
|
||||
|
||||
if (numkaspkeys != numkeyfiles) {
|
||||
cfg_obj_log(kaspobj, ISC_LOG_ERROR,
|
||||
"zone '%s': wrong number of key files (%d, "
|
||||
"expected %d)",
|
||||
zname, numkeyfiles, numkaspkeys);
|
||||
result = ISC_R_FAILURE;
|
||||
}
|
||||
|
||||
ISC_LIST_FOREACH(keys, key, link) {
|
||||
ISC_LIST_UNLINK(keys, key, link);
|
||||
dns_dnsseckey_destroy(mctx, &key);
|
||||
}
|
||||
}
|
||||
|
||||
check:
|
||||
if (!done) {
|
||||
ret = keydirexist(zconfig, "key-directory", zname, dir, name,
|
||||
keydirs, mctx);
|
||||
if (ret != ISC_R_SUCCESS) {
|
||||
result = ret;
|
||||
}
|
||||
if (default_kasp != NULL) {
|
||||
dns_kasp_detach(&default_kasp);
|
||||
}
|
||||
|
||||
if (do_cleanup) {
|
||||
if (kasp != NULL) {
|
||||
dns_kasp_detach(&kasp);
|
||||
}
|
||||
ISC_LIST_FOREACH(kasplist, k, link) {
|
||||
ISC_LIST_UNLINK(kasplist, k, link);
|
||||
dns_kasp_detach(&k);
|
||||
}
|
||||
ISC_LIST_FOREACH(kslist, ks, link) {
|
||||
ISC_LIST_UNLINK(kslist, ks, link);
|
||||
dns_keystore_detach(&ks);
|
||||
}
|
||||
if (kasp != NULL) {
|
||||
dns_kasp_detach(&kasp);
|
||||
}
|
||||
ISC_LIST_FOREACH(kasplist, k, link) {
|
||||
ISC_LIST_UNLINK(kasplist, k, link);
|
||||
dns_kasp_detach(&k);
|
||||
}
|
||||
ISC_LIST_FOREACH(kslist, ks, link) {
|
||||
ISC_LIST_UNLINK(kslist, ks, link);
|
||||
dns_keystore_detach(&ks);
|
||||
}
|
||||
|
||||
return result;
|
||||
|
|
@ -3046,6 +3176,7 @@ isccfg_check_zoneconf(const cfg_obj_t *zconfig, const cfg_obj_t *voptions,
|
|||
bool has_dnssecpolicy = false;
|
||||
bool kasp_inlinesigning = false;
|
||||
bool inline_signing = false;
|
||||
bool check_keys = (flags & BIND_CHECK_KEYS) != 0;
|
||||
const void *clauses = NULL;
|
||||
const char *option = NULL;
|
||||
const char *kaspname = NULL;
|
||||
|
|
@ -3821,8 +3952,9 @@ isccfg_check_zoneconf(const cfg_obj_t *zconfig, const cfg_obj_t *voptions,
|
|||
*/
|
||||
if (zname != NULL && keydirs != NULL) {
|
||||
if (has_dnssecpolicy) {
|
||||
tresult = check_keydir(config, zconfig, zname, kaspname,
|
||||
dir, keydirs, mctx);
|
||||
tresult = check_keydir(config, zconfig, zname, znamestr,
|
||||
kaspname, dir, keydirs, mctx,
|
||||
check_keys);
|
||||
} else {
|
||||
tresult = keydirexist(zconfig, "key-directory", zname,
|
||||
dir, kaspname, keydirs, mctx);
|
||||
|
|
|
|||
|
|
@ -41,6 +41,11 @@
|
|||
* Check the dnssec-policy DNSSEC algorithms against those
|
||||
* supported by the crypto provider.
|
||||
*/
|
||||
#define BIND_CHECK_KEYS 0x00000004
|
||||
/*%<
|
||||
* Check the dnssec-policy DNSSEC keys against the key files
|
||||
* in the key stores.
|
||||
*/
|
||||
|
||||
isc_result_t
|
||||
isccfg_check_namedconf(const cfg_obj_t *config, unsigned int flags,
|
||||
|
|
|
|||
|
|
@ -15,13 +15,17 @@
|
|||
|
||||
#include <isccfg/cfg.h>
|
||||
|
||||
#define ISCCFG_KASPCONF_CHECK_ALGORITHMS 0x01
|
||||
#define ISCCFG_KASPCONF_CHECK_KEYLIST 0x02
|
||||
#define ISCCFG_KASPCONF_LOG_ERRORS 0x04
|
||||
|
||||
/***
|
||||
*** Functions
|
||||
***/
|
||||
|
||||
isc_result_t
|
||||
cfg_kasp_fromconfig(const cfg_obj_t *config, dns_kasp_t *default_kasp,
|
||||
bool check_algorithms, isc_mem_t *mctx,
|
||||
unsigned int options, isc_mem_t *mctx,
|
||||
dns_keystorelist_t *keystorelist, dns_kasplist_t *kasplist,
|
||||
dns_kasp_t **kaspp);
|
||||
/*%<
|
||||
|
|
@ -34,8 +38,16 @@ cfg_kasp_fromconfig(const cfg_obj_t *config, dns_kasp_t *default_kasp,
|
|||
*
|
||||
* The 'keystorelist' is where to lookup key stores if KASP keys are using them.
|
||||
*
|
||||
* If 'check_algorithms' is true then the dnssec-policy DNSSEC key
|
||||
* algorithms are checked against those supported by the crypto provider.
|
||||
* If 'options' has ISCCFG_KASPCONF_CHECK_ALGORITHMS set, then the dnssec-policy
|
||||
* DNSSEC key algorithms are checked against those supported by the crypto
|
||||
* provider.
|
||||
*
|
||||
* If 'options' has ISCCFG_KASPCONF_CHECK_KEYLIST set, then this function
|
||||
* insists that the key list is not empty, unless the policy is "insecure"
|
||||
* (then the key list must be empty).
|
||||
*
|
||||
* If 'options' has ISCCFG_KASPCONF_LOG_ERRORS set, then configuration errors
|
||||
* and warnings are logged to the global logging context.
|
||||
*
|
||||
* Requires:
|
||||
*
|
||||
|
|
@ -55,6 +67,30 @@ cfg_kasp_fromconfig(const cfg_obj_t *config, dns_kasp_t *default_kasp,
|
|||
*\li Other errors are possible.
|
||||
*/
|
||||
|
||||
isc_result_t
|
||||
cfg_kasp_builtinconfig(isc_mem_t *mctx, const char *name,
|
||||
dns_keystorelist_t *keystorelist,
|
||||
dns_kasplist_t *kasplist, dns_kasp_t **kaspp);
|
||||
/*%<
|
||||
* Create built-in KASP.
|
||||
*
|
||||
* 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 kaspp != NULL && *kaspp == NULL
|
||||
*
|
||||
* Returns:
|
||||
*
|
||||
*\li #ISC_R_SUCCESS If creating and configuring the KASP succeeds.
|
||||
*\li #ISC_R_EXISTS If 'kasplist' already has the default policy.
|
||||
*
|
||||
*\li Other errors are possible.
|
||||
*/
|
||||
|
||||
isc_result_t
|
||||
cfg_keystore_fromconfig(const cfg_obj_t *config, isc_mem_t *mctx,
|
||||
dns_keystorelist_t *keystorelist,
|
||||
|
|
|
|||
|
|
@ -114,7 +114,7 @@ get_string(const cfg_obj_t **maps, const char *option) {
|
|||
*/
|
||||
static isc_result_t
|
||||
cfg_kaspkey_fromconfig(const cfg_obj_t *config, dns_kasp_t *kasp,
|
||||
bool check_algorithms, bool offline_ksk,
|
||||
bool check_algorithms, bool log_errors, bool offline_ksk,
|
||||
dns_keystorelist_t *keystorelist,
|
||||
uint32_t ksk_min_lifetime, uint32_t zsk_min_lifetime) {
|
||||
isc_result_t result;
|
||||
|
|
@ -151,10 +151,13 @@ cfg_kaspkey_fromconfig(const cfg_obj_t *config, dns_kasp_t *kasp,
|
|||
key->role |= DNS_KASP_KEY_ROLE_ZSK;
|
||||
} else if (strcmp(rolestr, "csk") == 0) {
|
||||
if (offline_ksk) {
|
||||
cfg_obj_log(
|
||||
config, ISC_LOG_ERROR,
|
||||
"dnssec-policy: csk keys are not "
|
||||
"allowed when offline-ksk is enabled");
|
||||
if (log_errors) {
|
||||
cfg_obj_log(config, ISC_LOG_ERROR,
|
||||
"dnssec-policy: csk keys "
|
||||
"are not "
|
||||
"allowed when offline-ksk "
|
||||
"is enabled");
|
||||
}
|
||||
result = ISC_R_FAILURE;
|
||||
goto cleanup;
|
||||
}
|
||||
|
|
@ -172,14 +175,20 @@ cfg_kaspkey_fromconfig(const cfg_obj_t *config, dns_kasp_t *kasp,
|
|||
result = dns_keystorelist_find(keystorelist, keydir,
|
||||
&key->keystore);
|
||||
if (result == ISC_R_NOTFOUND) {
|
||||
cfg_obj_log(obj, ISC_LOG_ERROR,
|
||||
"dnssec-policy: keystore %s does not exist",
|
||||
keydir);
|
||||
if (log_errors) {
|
||||
cfg_obj_log(obj, ISC_LOG_ERROR,
|
||||
"dnssec-policy: keystore %s does "
|
||||
"not exist",
|
||||
keydir);
|
||||
}
|
||||
result = ISC_R_FAILURE;
|
||||
goto cleanup;
|
||||
} else if (result != ISC_R_SUCCESS) {
|
||||
cfg_obj_log(obj, ISC_LOG_ERROR,
|
||||
"dnssec-policy: bad keystore %s", keydir);
|
||||
if (log_errors) {
|
||||
cfg_obj_log(obj, ISC_LOG_ERROR,
|
||||
"dnssec-policy: bad keystore %s",
|
||||
keydir);
|
||||
}
|
||||
result = ISC_R_FAILURE;
|
||||
goto cleanup;
|
||||
}
|
||||
|
|
@ -192,9 +201,12 @@ cfg_kaspkey_fromconfig(const cfg_obj_t *config, dns_kasp_t *kasp,
|
|||
}
|
||||
if (key->lifetime > 0) {
|
||||
if (key->lifetime < 30 * (24 * 3600)) {
|
||||
cfg_obj_log(obj, ISC_LOG_WARNING,
|
||||
"dnssec-policy: key lifetime is "
|
||||
"shorter than 30 days");
|
||||
if (log_errors) {
|
||||
cfg_obj_log(obj, ISC_LOG_WARNING,
|
||||
"dnssec-policy: key "
|
||||
"lifetime is "
|
||||
"shorter than 30 days");
|
||||
}
|
||||
}
|
||||
if ((key->role & DNS_KASP_KEY_ROLE_KSK) != 0 &&
|
||||
key->lifetime <= ksk_min_lifetime)
|
||||
|
|
@ -207,10 +219,14 @@ cfg_kaspkey_fromconfig(const cfg_obj_t *config, dns_kasp_t *kasp,
|
|||
error = true;
|
||||
}
|
||||
if (error) {
|
||||
cfg_obj_log(obj, ISC_LOG_ERROR,
|
||||
"dnssec-policy: key lifetime is "
|
||||
"shorter than the time it takes to "
|
||||
"do a rollover");
|
||||
if (log_errors) {
|
||||
cfg_obj_log(obj, ISC_LOG_ERROR,
|
||||
"dnssec-policy: key "
|
||||
"lifetime is "
|
||||
"shorter than the time it "
|
||||
"takes to "
|
||||
"do a rollover");
|
||||
}
|
||||
result = ISC_R_FAILURE;
|
||||
goto cleanup;
|
||||
}
|
||||
|
|
@ -222,9 +238,11 @@ cfg_kaspkey_fromconfig(const cfg_obj_t *config, dns_kasp_t *kasp,
|
|||
result = dst_algorithm_fromtext(&key->algorithm,
|
||||
(isc_textregion_t *)&alg);
|
||||
if (result != ISC_R_SUCCESS) {
|
||||
cfg_obj_log(obj, ISC_LOG_ERROR,
|
||||
"dnssec-policy: bad algorithm %s",
|
||||
alg.base);
|
||||
if (log_errors) {
|
||||
cfg_obj_log(obj, ISC_LOG_ERROR,
|
||||
"dnssec-policy: bad algorithm %s",
|
||||
alg.base);
|
||||
}
|
||||
result = DNS_R_BADALG;
|
||||
goto cleanup;
|
||||
}
|
||||
|
|
@ -232,10 +250,13 @@ cfg_kaspkey_fromconfig(const cfg_obj_t *config, dns_kasp_t *kasp,
|
|||
(key->algorithm == DST_ALG_RSASHA1 ||
|
||||
key->algorithm == DST_ALG_NSEC3RSASHA1))
|
||||
{
|
||||
cfg_obj_log(obj, ISC_LOG_ERROR,
|
||||
"dnssec-policy: algorithm %s not supported "
|
||||
"in FIPS mode",
|
||||
alg.base);
|
||||
if (log_errors) {
|
||||
cfg_obj_log(obj, ISC_LOG_ERROR,
|
||||
"dnssec-policy: algorithm %s not "
|
||||
"supported "
|
||||
"in FIPS mode",
|
||||
alg.base);
|
||||
}
|
||||
result = DNS_R_BADALG;
|
||||
goto cleanup;
|
||||
}
|
||||
|
|
@ -243,9 +264,12 @@ cfg_kaspkey_fromconfig(const cfg_obj_t *config, dns_kasp_t *kasp,
|
|||
if (check_algorithms &&
|
||||
!dst_algorithm_supported(key->algorithm))
|
||||
{
|
||||
cfg_obj_log(obj, ISC_LOG_ERROR,
|
||||
"dnssec-policy: algorithm %s not supported",
|
||||
alg.base);
|
||||
if (log_errors) {
|
||||
cfg_obj_log(obj, ISC_LOG_ERROR,
|
||||
"dnssec-policy: algorithm %s not "
|
||||
"supported",
|
||||
alg.base);
|
||||
}
|
||||
result = DNS_R_BADALG;
|
||||
goto cleanup;
|
||||
}
|
||||
|
|
@ -253,10 +277,13 @@ cfg_kaspkey_fromconfig(const cfg_obj_t *config, dns_kasp_t *kasp,
|
|||
switch (key->algorithm) {
|
||||
case DST_ALG_RSASHA1:
|
||||
case DST_ALG_NSEC3RSASHA1:
|
||||
cfg_obj_log(obj, ISC_LOG_WARNING,
|
||||
"dnssec-policy: DNSSEC algorithm %s is "
|
||||
"deprecated",
|
||||
alg.base);
|
||||
if (log_errors) {
|
||||
cfg_obj_log(
|
||||
obj, ISC_LOG_WARNING,
|
||||
"dnssec-policy: DNSSEC algorithm %s is "
|
||||
"deprecated",
|
||||
alg.base);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
|
|
@ -280,11 +307,15 @@ cfg_kaspkey_fromconfig(const cfg_obj_t *config, dns_kasp_t *kasp,
|
|||
min = DST_ALG_RSASHA512 ? 1024 : 512;
|
||||
}
|
||||
if (size < min || size > 4096) {
|
||||
cfg_obj_log(obj, ISC_LOG_ERROR,
|
||||
"dnssec-policy: key with "
|
||||
"algorithm %s has invalid "
|
||||
"key length %u",
|
||||
alg.base, size);
|
||||
if (log_errors) {
|
||||
cfg_obj_log(obj, ISC_LOG_ERROR,
|
||||
"dnssec-policy: "
|
||||
"key with "
|
||||
"algorithm %s has "
|
||||
"invalid "
|
||||
"key length %u",
|
||||
alg.base, size);
|
||||
}
|
||||
result = ISC_R_RANGE;
|
||||
goto cleanup;
|
||||
}
|
||||
|
|
@ -293,11 +324,15 @@ cfg_kaspkey_fromconfig(const cfg_obj_t *config, dns_kasp_t *kasp,
|
|||
case DST_ALG_ECDSA384:
|
||||
case DST_ALG_ED25519:
|
||||
case DST_ALG_ED448:
|
||||
cfg_obj_log(obj, ISC_LOG_WARNING,
|
||||
"dnssec-policy: key algorithm %s "
|
||||
"has predefined length; ignoring "
|
||||
"length value %u",
|
||||
alg.base, size);
|
||||
if (log_errors) {
|
||||
cfg_obj_log(obj, ISC_LOG_WARNING,
|
||||
"dnssec-policy: key "
|
||||
"algorithm %s "
|
||||
"has predefined length; "
|
||||
"ignoring "
|
||||
"length value %u",
|
||||
alg.base, size);
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
|
@ -311,25 +346,31 @@ cfg_kaspkey_fromconfig(const cfg_obj_t *config, dns_kasp_t *kasp,
|
|||
obj = cfg_tuple_get(tagrange, "tag-min");
|
||||
tag_min = cfg_obj_asuint32(obj);
|
||||
if (tag_min > 0xffff) {
|
||||
cfg_obj_log(obj, ISC_LOG_ERROR,
|
||||
"dnssec-policy: tag-min "
|
||||
"too big");
|
||||
if (log_errors) {
|
||||
cfg_obj_log(obj, ISC_LOG_ERROR,
|
||||
"dnssec-policy: tag-min "
|
||||
"too big");
|
||||
}
|
||||
result = ISC_R_RANGE;
|
||||
goto cleanup;
|
||||
}
|
||||
obj = cfg_tuple_get(tagrange, "tag-max");
|
||||
tag_max = cfg_obj_asuint32(obj);
|
||||
if (tag_max > 0xffff) {
|
||||
cfg_obj_log(obj, ISC_LOG_ERROR,
|
||||
"dnssec-policy: tag-max "
|
||||
"too big");
|
||||
if (log_errors) {
|
||||
cfg_obj_log(obj, ISC_LOG_ERROR,
|
||||
"dnssec-policy: tag-max "
|
||||
"too big");
|
||||
}
|
||||
result = ISC_R_RANGE;
|
||||
goto cleanup;
|
||||
}
|
||||
if (tag_min >= tag_max) {
|
||||
cfg_obj_log(
|
||||
obj, ISC_LOG_ERROR,
|
||||
"dnssec-policy: tag-min >= tag_max");
|
||||
if (log_errors) {
|
||||
cfg_obj_log(obj, ISC_LOG_ERROR,
|
||||
"dnssec-policy: tag-min >= "
|
||||
"tag_max");
|
||||
}
|
||||
result = ISC_R_RANGE;
|
||||
goto cleanup;
|
||||
}
|
||||
|
|
@ -348,7 +389,8 @@ cleanup:
|
|||
}
|
||||
|
||||
static isc_result_t
|
||||
cfg_nsec3param_fromconfig(const cfg_obj_t *config, dns_kasp_t *kasp) {
|
||||
cfg_nsec3param_fromconfig(const cfg_obj_t *config, dns_kasp_t *kasp,
|
||||
bool log_errors) {
|
||||
unsigned int min_keysize = 4096;
|
||||
const cfg_obj_t *obj = NULL;
|
||||
uint32_t iter = DEFAULT_NSEC3PARAM_ITER;
|
||||
|
|
@ -382,18 +424,22 @@ cfg_nsec3param_fromconfig(const cfg_obj_t *config, dns_kasp_t *kasp) {
|
|||
if (badalg > 0) {
|
||||
char algstr[DNS_SECALG_FORMATSIZE];
|
||||
dns_secalg_format((dns_secalg_t)badalg, algstr, sizeof(algstr));
|
||||
cfg_obj_log(
|
||||
obj, ISC_LOG_ERROR,
|
||||
"dnssec-policy: cannot use nsec3 with algorithm '%s'",
|
||||
algstr);
|
||||
if (log_errors) {
|
||||
cfg_obj_log(obj, ISC_LOG_ERROR,
|
||||
"dnssec-policy: cannot use nsec3 with "
|
||||
"algorithm '%s'",
|
||||
algstr);
|
||||
}
|
||||
return DNS_R_NSEC3BADALG;
|
||||
}
|
||||
|
||||
if (iter != DEFAULT_NSEC3PARAM_ITER) {
|
||||
cfg_obj_log(obj, ISC_LOG_ERROR,
|
||||
"dnssec-policy: nsec3 iterations value %u "
|
||||
"not allowed, must be zero",
|
||||
iter);
|
||||
if (log_errors) {
|
||||
cfg_obj_log(obj, ISC_LOG_ERROR,
|
||||
"dnssec-policy: nsec3 iterations value %u "
|
||||
"not allowed, must be zero",
|
||||
iter);
|
||||
}
|
||||
return DNS_R_NSEC3ITERRANGE;
|
||||
}
|
||||
|
||||
|
|
@ -409,9 +455,12 @@ cfg_nsec3param_fromconfig(const cfg_obj_t *config, dns_kasp_t *kasp) {
|
|||
saltlen = cfg_obj_asuint32(obj);
|
||||
}
|
||||
if (saltlen > 0xff) {
|
||||
cfg_obj_log(obj, ISC_LOG_ERROR,
|
||||
"dnssec-policy: nsec3 salt length %u too high",
|
||||
saltlen);
|
||||
if (log_errors) {
|
||||
cfg_obj_log(
|
||||
obj, ISC_LOG_ERROR,
|
||||
"dnssec-policy: nsec3 salt length %u too high",
|
||||
saltlen);
|
||||
}
|
||||
return DNS_R_NSEC3SALTRANGE;
|
||||
}
|
||||
|
||||
|
|
@ -420,7 +469,7 @@ cfg_nsec3param_fromconfig(const cfg_obj_t *config, dns_kasp_t *kasp) {
|
|||
}
|
||||
|
||||
static isc_result_t
|
||||
add_digest(dns_kasp_t *kasp, const cfg_obj_t *digest) {
|
||||
add_digest(dns_kasp_t *kasp, const cfg_obj_t *digest, bool log_errors) {
|
||||
isc_result_t result = ISC_R_SUCCESS;
|
||||
isc_textregion_t r;
|
||||
dns_dsdigest_t alg;
|
||||
|
|
@ -430,21 +479,28 @@ add_digest(dns_kasp_t *kasp, const cfg_obj_t *digest) {
|
|||
r.length = strlen(str);
|
||||
result = dns_dsdigest_fromtext(&alg, &r);
|
||||
if (result != ISC_R_SUCCESS) {
|
||||
cfg_obj_log(digest, ISC_LOG_ERROR,
|
||||
"dnssec-policy: bad cds digest-type %s", str);
|
||||
if (log_errors) {
|
||||
cfg_obj_log(digest, ISC_LOG_ERROR,
|
||||
"dnssec-policy: bad cds digest-type %s",
|
||||
str);
|
||||
}
|
||||
result = DNS_R_BADALG;
|
||||
} else if (!dst_ds_digest_supported(alg)) {
|
||||
cfg_obj_log(digest, ISC_LOG_ERROR,
|
||||
"dnssec-policy: unsupported cds "
|
||||
"digest-type %s",
|
||||
str);
|
||||
if (log_errors) {
|
||||
cfg_obj_log(digest, ISC_LOG_ERROR,
|
||||
"dnssec-policy: unsupported cds "
|
||||
"digest-type %s",
|
||||
str);
|
||||
}
|
||||
result = DST_R_UNSUPPORTEDALG;
|
||||
} else {
|
||||
if (alg == DNS_DSDIGEST_SHA1) {
|
||||
cfg_obj_log(
|
||||
digest, ISC_LOG_WARNING,
|
||||
"dnssec-policy: deprecated CDS digest-type %s",
|
||||
str);
|
||||
if (log_errors) {
|
||||
cfg_obj_log(digest, ISC_LOG_WARNING,
|
||||
"dnssec-policy: deprecated CDS "
|
||||
"digest-type %s",
|
||||
str);
|
||||
}
|
||||
}
|
||||
dns_kasp_adddigest(kasp, alg);
|
||||
}
|
||||
|
|
@ -453,7 +509,7 @@ add_digest(dns_kasp_t *kasp, const cfg_obj_t *digest) {
|
|||
|
||||
isc_result_t
|
||||
cfg_kasp_fromconfig(const cfg_obj_t *config, dns_kasp_t *default_kasp,
|
||||
bool check_algorithms, isc_mem_t *mctx,
|
||||
unsigned int options, isc_mem_t *mctx,
|
||||
dns_keystorelist_t *keystorelist, dns_kasplist_t *kasplist,
|
||||
dns_kasp_t **kaspp) {
|
||||
isc_result_t result;
|
||||
|
|
@ -474,6 +530,10 @@ cfg_kasp_fromconfig(const cfg_obj_t *config, dns_kasp_t *default_kasp,
|
|||
uint32_t ipub = 0, iret = 0;
|
||||
uint32_t ksk_min_lifetime = 0, zsk_min_lifetime = 0;
|
||||
bool offline_ksk = false, manual_mode = false;
|
||||
bool check_algorithms = (options & ISCCFG_KASPCONF_CHECK_ALGORITHMS) !=
|
||||
0;
|
||||
bool check_keylist = (options & ISCCFG_KASPCONF_CHECK_KEYLIST) != 0;
|
||||
bool log_errors = (options & ISCCFG_KASPCONF_LOG_ERRORS) != 0;
|
||||
|
||||
REQUIRE(config != NULL);
|
||||
REQUIRE(kaspp != NULL && *kaspp == NULL);
|
||||
|
|
@ -487,10 +547,12 @@ cfg_kasp_fromconfig(const cfg_obj_t *config, dns_kasp_t *default_kasp,
|
|||
result = dns_kasplist_find(kasplist, kaspname, &kasp);
|
||||
|
||||
if (result == ISC_R_SUCCESS) {
|
||||
cfg_obj_log(
|
||||
config, ISC_LOG_ERROR,
|
||||
"dnssec-policy: duplicately named policy found '%s'",
|
||||
kaspname);
|
||||
if (log_errors) {
|
||||
cfg_obj_log(config, ISC_LOG_ERROR,
|
||||
"dnssec-policy: duplicately named policy "
|
||||
"found '%s'",
|
||||
kaspname);
|
||||
}
|
||||
dns_kasp_detach(&kasp);
|
||||
return ISC_R_EXISTS;
|
||||
}
|
||||
|
|
@ -508,10 +570,8 @@ cfg_kasp_fromconfig(const cfg_obj_t *config, dns_kasp_t *default_kasp,
|
|||
/* Now configure. */
|
||||
INSIST(DNS_KASP_VALID(kasp));
|
||||
|
||||
if (config != NULL) {
|
||||
koptions = cfg_tuple_get(config, "options");
|
||||
maps[i++] = koptions;
|
||||
}
|
||||
koptions = cfg_tuple_get(config, "options");
|
||||
maps[i++] = koptions;
|
||||
maps[i] = NULL;
|
||||
|
||||
/* Configuration: Signatures */
|
||||
|
|
@ -526,42 +586,51 @@ cfg_kasp_fromconfig(const cfg_obj_t *config, dns_kasp_t *default_kasp,
|
|||
sigvalidity = get_duration(maps, "signatures-validity-dnskey",
|
||||
DNS_KASP_SIG_VALIDITY_DNSKEY);
|
||||
if (sigrefresh >= (sigvalidity * 0.9)) {
|
||||
cfg_obj_log(
|
||||
config, ISC_LOG_ERROR,
|
||||
"dnssec-policy: policy '%s' signatures-refresh must be "
|
||||
"at most 90%% of the signatures-validity-dnskey",
|
||||
kaspname);
|
||||
if (log_errors) {
|
||||
cfg_obj_log(config, ISC_LOG_ERROR,
|
||||
"dnssec-policy: policy '%s' "
|
||||
"signatures-refresh must be "
|
||||
"at most 90%% of the "
|
||||
"signatures-validity-dnskey",
|
||||
kaspname);
|
||||
}
|
||||
result = ISC_R_FAILURE;
|
||||
}
|
||||
dns_kasp_setsigvalidity_dnskey(kasp, sigvalidity);
|
||||
|
||||
if (sigjitter > sigvalidity) {
|
||||
cfg_obj_log(
|
||||
config, ISC_LOG_ERROR,
|
||||
"dnssec-policy: policy '%s' signatures-jitter cannot "
|
||||
"be larger than signatures-validity-dnskey",
|
||||
kaspname);
|
||||
if (log_errors) {
|
||||
cfg_obj_log(config, ISC_LOG_ERROR,
|
||||
"dnssec-policy: policy '%s' "
|
||||
"signatures-jitter cannot "
|
||||
"be larger than signatures-validity-dnskey",
|
||||
kaspname);
|
||||
}
|
||||
result = ISC_R_FAILURE;
|
||||
}
|
||||
|
||||
sigvalidity = get_duration(maps, "signatures-validity",
|
||||
DNS_KASP_SIG_VALIDITY);
|
||||
if (sigrefresh >= (sigvalidity * 0.9)) {
|
||||
cfg_obj_log(
|
||||
config, ISC_LOG_ERROR,
|
||||
"dnssec-policy: policy '%s' signatures-refresh must be "
|
||||
"at most 90%% of the signatures-validity",
|
||||
kaspname);
|
||||
if (log_errors) {
|
||||
cfg_obj_log(config, ISC_LOG_ERROR,
|
||||
"dnssec-policy: policy '%s' "
|
||||
"signatures-refresh must be "
|
||||
"at most 90%% of the signatures-validity",
|
||||
kaspname);
|
||||
}
|
||||
result = ISC_R_FAILURE;
|
||||
}
|
||||
dns_kasp_setsigvalidity(kasp, sigvalidity);
|
||||
|
||||
if (sigjitter > sigvalidity) {
|
||||
cfg_obj_log(
|
||||
config, ISC_LOG_ERROR,
|
||||
"dnssec-policy: policy '%s' signatures-jitter cannot "
|
||||
"be larger than signatures-validity",
|
||||
kaspname);
|
||||
if (log_errors) {
|
||||
cfg_obj_log(config, ISC_LOG_ERROR,
|
||||
"dnssec-policy: policy '%s' "
|
||||
"signatures-jitter cannot "
|
||||
"be larger than signatures-validity",
|
||||
kaspname);
|
||||
}
|
||||
result = ISC_R_FAILURE;
|
||||
}
|
||||
|
||||
|
|
@ -619,7 +688,8 @@ cfg_kasp_fromconfig(const cfg_obj_t *config, dns_kasp_t *default_kasp,
|
|||
(void)confget(maps, "cds-digest-types", &cds);
|
||||
if (cds != NULL) {
|
||||
CFG_LIST_FOREACH(cds, element) {
|
||||
result = add_digest(kasp, cfg_listelt_value(element));
|
||||
result = add_digest(kasp, cfg_listelt_value(element),
|
||||
log_errors);
|
||||
if (result != ISC_R_SUCCESS) {
|
||||
goto cleanup;
|
||||
}
|
||||
|
|
@ -658,14 +728,16 @@ cfg_kasp_fromconfig(const cfg_obj_t *config, dns_kasp_t *default_kasp,
|
|||
CFG_LIST_FOREACH(keys, element) {
|
||||
cfg_obj_t *kobj = cfg_listelt_value(element);
|
||||
result = cfg_kaspkey_fromconfig(
|
||||
kobj, kasp, check_algorithms, offline_ksk,
|
||||
keystorelist, ksk_min_lifetime,
|
||||
kobj, kasp, check_algorithms, log_errors,
|
||||
offline_ksk, keystorelist, ksk_min_lifetime,
|
||||
zsk_min_lifetime);
|
||||
if (result != ISC_R_SUCCESS) {
|
||||
cfg_obj_log(kobj, ISC_LOG_ERROR,
|
||||
"dnssec-policy: failed to "
|
||||
"configure keys (%s)",
|
||||
isc_result_totext(result));
|
||||
if (log_errors) {
|
||||
cfg_obj_log(kobj, ISC_LOG_ERROR,
|
||||
"dnssec-policy: failed to "
|
||||
"configure keys (%s)",
|
||||
isc_result_totext(result));
|
||||
}
|
||||
goto cleanup;
|
||||
}
|
||||
}
|
||||
|
|
@ -698,19 +770,22 @@ cfg_kasp_fromconfig(const cfg_obj_t *config, dns_kasp_t *default_kasp,
|
|||
if (role[i] !=
|
||||
(DNS_KASP_KEY_ROLE_ZSK | DNS_KASP_KEY_ROLE_KSK))
|
||||
{
|
||||
cfg_obj_log(keys, ISC_LOG_ERROR,
|
||||
"dnssec-policy: algorithm %zu "
|
||||
"requires both KSK and ZSK roles",
|
||||
i);
|
||||
if (log_errors) {
|
||||
cfg_obj_log(keys, ISC_LOG_ERROR,
|
||||
"dnssec-policy: algorithm "
|
||||
"%zu requires both KSK and "
|
||||
"ZSK roles",
|
||||
i);
|
||||
}
|
||||
result = ISC_R_FAILURE;
|
||||
}
|
||||
if (warn[i][0]) {
|
||||
if (warn[i][0] && log_errors) {
|
||||
cfg_obj_log(keys, ISC_LOG_WARNING,
|
||||
"dnssec-policy: algorithm %zu has "
|
||||
"multiple keys with ZSK role",
|
||||
i);
|
||||
}
|
||||
if (warn[i][1]) {
|
||||
if (warn[i][1] && log_errors) {
|
||||
cfg_obj_log(keys, ISC_LOG_WARNING,
|
||||
"dnssec-policy: algorithm %zu has "
|
||||
"multiple keys with KSK role",
|
||||
|
|
@ -744,20 +819,22 @@ cfg_kasp_fromconfig(const cfg_obj_t *config, dns_kasp_t *default_kasp,
|
|||
keystorelist, DNS_KEYSTORE_KEYDIRECTORY,
|
||||
&new_key->keystore);
|
||||
if (result != ISC_R_SUCCESS) {
|
||||
cfg_obj_log(config, ISC_LOG_ERROR,
|
||||
"dnssec-policy: failed to "
|
||||
"find keystore (%s)",
|
||||
isc_result_totext(result));
|
||||
if (log_errors) {
|
||||
cfg_obj_log(config, ISC_LOG_ERROR,
|
||||
"dnssec-policy: failed to "
|
||||
"find keystore (%s)",
|
||||
isc_result_totext(result));
|
||||
}
|
||||
goto cleanup;
|
||||
}
|
||||
dns_kasp_addkey(kasp, new_key);
|
||||
}
|
||||
}
|
||||
|
||||
if (strcmp(kaspname, "insecure") == 0) {
|
||||
if (strcmp(kaspname, "insecure") == 0 && check_keylist) {
|
||||
/* "dnssec-policy insecure": key list must be empty */
|
||||
INSIST(dns_kasp_keylist_empty(kasp));
|
||||
} else if (default_kasp != NULL) {
|
||||
} else if (default_kasp != NULL && check_keylist) {
|
||||
/* There must be keys configured. */
|
||||
INSIST(!(dns_kasp_keylist_empty(kasp)));
|
||||
}
|
||||
|
|
@ -775,7 +852,7 @@ cfg_kasp_fromconfig(const cfg_obj_t *config, dns_kasp_t *default_kasp,
|
|||
}
|
||||
} else {
|
||||
dns_kasp_setnsec3(kasp, true);
|
||||
result = cfg_nsec3param_fromconfig(nsec3, kasp);
|
||||
result = cfg_nsec3param_fromconfig(nsec3, kasp, log_errors);
|
||||
if (result != ISC_R_SUCCESS) {
|
||||
goto cleanup;
|
||||
}
|
||||
|
|
@ -798,6 +875,100 @@ cleanup:
|
|||
return result;
|
||||
}
|
||||
|
||||
isc_result_t
|
||||
cfg_kasp_builtinconfig(isc_mem_t *mctx, const char *name,
|
||||
dns_keystorelist_t *keystorelist,
|
||||
dns_kasplist_t *kasplist, dns_kasp_t **kaspp) {
|
||||
isc_result_t result;
|
||||
dns_kasp_t *kasp = NULL;
|
||||
|
||||
REQUIRE(kaspp != NULL && *kaspp == NULL);
|
||||
REQUIRE(strcmp(name, "default") == 0 || strcmp(name, "insecure") == 0);
|
||||
|
||||
result = dns_kasplist_find(kasplist, name, &kasp);
|
||||
if (result == ISC_R_SUCCESS) {
|
||||
dns_kasp_detach(&kasp);
|
||||
return ISC_R_EXISTS;
|
||||
}
|
||||
if (result != ISC_R_NOTFOUND) {
|
||||
return result;
|
||||
}
|
||||
result = ISC_R_SUCCESS;
|
||||
|
||||
/* No kasp with configured name was found in list, create new one. */
|
||||
INSIST(kasp == NULL);
|
||||
dns_kasp_create(mctx, name, &kasp);
|
||||
INSIST(kasp != NULL);
|
||||
|
||||
/* Now configure. */
|
||||
INSIST(DNS_KASP_VALID(kasp));
|
||||
|
||||
/* Configuration: Signatures */
|
||||
dns_kasp_setsigjitter(kasp, parse_duration(DNS_KASP_SIG_JITTER));
|
||||
dns_kasp_setsigrefresh(kasp, parse_duration(DNS_KASP_SIG_REFRESH));
|
||||
dns_kasp_setsigvalidity_dnskey(
|
||||
kasp, parse_duration(DNS_KASP_SIG_VALIDITY_DNSKEY));
|
||||
dns_kasp_setsigvalidity(kasp, parse_duration(DNS_KASP_SIG_VALIDITY));
|
||||
|
||||
/* Configuration: Zone settings */
|
||||
dns_kasp_setinlinesigning(kasp, true);
|
||||
dns_kasp_setmanualmode(kasp, false);
|
||||
dns_kasp_setzonemaxttl(kasp, parse_duration(DNS_KASP_ZONE_MAXTTL));
|
||||
dns_kasp_setzonepropagationdelay(
|
||||
kasp, parse_duration(DNS_KASP_ZONE_PROPDELAY));
|
||||
|
||||
/* Configuration: Parent settings */
|
||||
dns_kasp_setdsttl(kasp, parse_duration(DNS_KASP_DS_TTL));
|
||||
dns_kasp_setparentpropagationdelay(
|
||||
kasp, parse_duration(DNS_KASP_PARENT_PROPDELAY));
|
||||
|
||||
/* Configuration: Keys */
|
||||
dns_kasp_setofflineksk(kasp, false);
|
||||
dns_kasp_setcdnskey(kasp, true);
|
||||
dns_kasp_adddigest(kasp, DNS_DSDIGEST_SHA256);
|
||||
dns_kasp_setdnskeyttl(kasp, parse_duration(DNS_KASP_KEY_TTL));
|
||||
dns_kasp_setpublishsafety(kasp,
|
||||
parse_duration(DNS_KASP_PUBLISH_SAFETY));
|
||||
dns_kasp_setretiresafety(kasp, parse_duration(DNS_KASP_RETIRE_SAFETY));
|
||||
|
||||
dns_kasp_setpurgekeys(kasp, parse_duration(DNS_KASP_PURGE_KEYS));
|
||||
|
||||
if (strcmp(name, "default") == 0) {
|
||||
dns_kasp_key_t *new_key = NULL;
|
||||
dns_kasp_key_create(kasp, &new_key);
|
||||
new_key->role |= DNS_KASP_KEY_ROLE_KSK;
|
||||
new_key->role |= DNS_KASP_KEY_ROLE_ZSK;
|
||||
new_key->lifetime = 0;
|
||||
new_key->algorithm = DST_ALG_ECDSA256;
|
||||
new_key->length = 256;
|
||||
result = dns_keystorelist_find(keystorelist,
|
||||
DNS_KEYSTORE_KEYDIRECTORY,
|
||||
&new_key->keystore);
|
||||
if (result != ISC_R_SUCCESS) {
|
||||
goto cleanup;
|
||||
}
|
||||
dns_kasp_addkey(kasp, new_key);
|
||||
}
|
||||
|
||||
/* Configuration: Denial of existence */
|
||||
dns_kasp_setnsec3(kasp, false);
|
||||
|
||||
/* Append it to the list for future lookups. */
|
||||
ISC_LIST_APPEND(*kasplist, kasp, link);
|
||||
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;
|
||||
}
|
||||
|
||||
isc_result_t
|
||||
cfg_keystore_fromconfig(const cfg_obj_t *config, isc_mem_t *mctx,
|
||||
dns_keystorelist_t *keystorelist,
|
||||
|
|
|
|||
Loading…
Reference in a new issue