mirror of
https://github.com/isc-projects/bind9.git
synced 2026-05-27 12:13:20 -04:00
Warn about deprecated DNSKEY and DS algorithms / digest types
DNSKEY algorithms RSASHA1 and RSASHA-NSEC3-SHA1 and DS digest type
SHA1 are deprecated. Log when these are present in primary zone
files and when generating new DNSKEYs, DS and CDS records.
(cherry picked from commit cb6903c55e)
This commit is contained in:
parent
e2f539035d
commit
2db0806b6c
8 changed files with 244 additions and 21 deletions
|
|
@ -318,6 +318,11 @@ emits(bool showall, bool cds, dns_rdata_t *rdata) {
|
|||
|
||||
n = sizeof(dtype) / sizeof(dtype[0]);
|
||||
for (i = 0; i < n; i++) {
|
||||
if (dtype[i] == DNS_DSDIGEST_SHA1) {
|
||||
fprintf(stderr,
|
||||
"WARNING: DS digest type %u is deprecated\n",
|
||||
i);
|
||||
}
|
||||
if (dtype[i] != 0) {
|
||||
emit(dtype[i], showall, cds, rdata);
|
||||
}
|
||||
|
|
@ -336,10 +341,10 @@ usage(void) {
|
|||
fprintf(stderr, " %s [-h|-V]\n\n", program);
|
||||
fprintf(stderr, "Version: %s\n", PACKAGE_VERSION);
|
||||
fprintf(stderr, "Options:\n"
|
||||
" -1: digest algorithm SHA-1\n"
|
||||
" -1: digest algorithm SHA-1 (deprecated)\n"
|
||||
" -2: digest algorithm SHA-256\n"
|
||||
" -a algorithm: digest algorithm (SHA-1, SHA-256 or "
|
||||
"SHA-384)\n"
|
||||
" -a algorithm: digest algorithm (SHA-1 "
|
||||
"(deprecated), SHA-256 or SHA-384)\n"
|
||||
" -A: include all keys in DS set, not just KSKs (-f "
|
||||
"only)\n"
|
||||
" -c class: rdata class for DS set (default IN) (-f "
|
||||
|
|
|
|||
|
|
@ -57,8 +57,8 @@ usage(void) {
|
|||
fprintf(stderr, " name: owner of the key\n");
|
||||
fprintf(stderr, "Other options:\n");
|
||||
fprintf(stderr, " -a algorithm: \n"
|
||||
" DH | RSASHA1 |\n"
|
||||
" NSEC3RSASHA1 |\n"
|
||||
" RSASHA1 (deprecated) |\n"
|
||||
" NSEC3RSASHA1 (deprecated) |\n"
|
||||
" RSASHA256 | RSASHA512 |\n"
|
||||
" ECDSAP256SHA256 | ECDSAP384SHA384 |\n"
|
||||
" ED25519 | ED448\n");
|
||||
|
|
@ -571,6 +571,21 @@ main(int argc, char **argv) {
|
|||
fatal("invalid DNSKEY nametype %s", nametype);
|
||||
}
|
||||
|
||||
switch (alg) {
|
||||
case DST_ALG_RSASHA1:
|
||||
case DST_ALG_NSEC3RSASHA1: {
|
||||
char algstr[DNS_SECALG_FORMATSIZE];
|
||||
dns_secalg_format(alg, algstr, sizeof(algstr));
|
||||
fprintf(stderr,
|
||||
"WARNING: DNSKEY algorithm '%s' is deprecated. Please "
|
||||
"migrate to another algorithm\n",
|
||||
algstr);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
rdclass = strtoclass(classname);
|
||||
|
||||
if (directory == NULL) {
|
||||
|
|
|
|||
|
|
@ -141,14 +141,17 @@ usage(void) {
|
|||
fprintf(stderr, " -l <file>: configuration file with dnssec-policy "
|
||||
"statement\n");
|
||||
fprintf(stderr, " -a <algorithm>:\n");
|
||||
fprintf(stderr, " RSASHA1 | NSEC3RSASHA1 |\n");
|
||||
fprintf(stderr,
|
||||
" RSASHA1 (deprecated) | NSEC3RSASHA1 (deprecated) |\n");
|
||||
fprintf(stderr, " RSASHA256 | RSASHA512 |\n");
|
||||
fprintf(stderr, " ECDSAP256SHA256 | ECDSAP384SHA384 |\n");
|
||||
fprintf(stderr, " ED25519 | ED448 | DH\n");
|
||||
fprintf(stderr, " -3: use NSEC3-capable algorithm\n");
|
||||
fprintf(stderr, " -b <key size in bits>:\n");
|
||||
fprintf(stderr, " RSASHA1:\t[1024..%d]\n", MAX_RSA);
|
||||
fprintf(stderr, " NSEC3RSASHA1:\t[1024..%d]\n", MAX_RSA);
|
||||
fprintf(stderr, " RSASHA1 (deprecated) :\t[1024..%d]\n",
|
||||
MAX_RSA);
|
||||
fprintf(stderr, " NSEC3RSASHA1 (deprecated) :\t[1024..%d]\n",
|
||||
MAX_RSA);
|
||||
fprintf(stderr, " RSASHA256:\t[1024..%d]\n", MAX_RSA);
|
||||
fprintf(stderr, " RSASHA512:\t[1024..%d]\n", MAX_RSA);
|
||||
fprintf(stderr, " DH:\t\t[128..4096]\n");
|
||||
|
|
@ -522,21 +525,34 @@ keygen(keygen_ctx_t *ctx, isc_mem_t *mctx, int argc, char **argv) {
|
|||
}
|
||||
|
||||
switch (ctx->alg) {
|
||||
case DNS_KEYALG_RSASHA1:
|
||||
case DNS_KEYALG_NSEC3RSASHA1:
|
||||
case DNS_KEYALG_RSASHA256:
|
||||
case DST_ALG_RSASHA1:
|
||||
case DST_ALG_NSEC3RSASHA1:
|
||||
dns_secalg_format(ctx->alg, algstr, sizeof(algstr));
|
||||
fprintf(stderr,
|
||||
"WARNING: DNSKEY algorithm '%s' is deprecated. Please "
|
||||
"migrate to another algorithm\n",
|
||||
algstr);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
switch (ctx->alg) {
|
||||
case DST_ALG_RSASHA1:
|
||||
case DST_ALG_NSEC3RSASHA1:
|
||||
case DST_ALG_RSASHA256:
|
||||
if (ctx->size != 0 && (ctx->size < 1024 || ctx->size > MAX_RSA))
|
||||
{
|
||||
fatal("RSA key size %d out of range", ctx->size);
|
||||
}
|
||||
break;
|
||||
case DNS_KEYALG_RSASHA512:
|
||||
case DST_ALG_RSASHA512:
|
||||
if (ctx->size != 0 && (ctx->size < 1024 || ctx->size > MAX_RSA))
|
||||
{
|
||||
fatal("RSA key size %d out of range", ctx->size);
|
||||
}
|
||||
break;
|
||||
case DNS_KEYALG_DH:
|
||||
case DST_ALG_DH:
|
||||
if (ctx->size != 0 && (ctx->size < 128 || ctx->size > 4096)) {
|
||||
fatal("DH key size %d out of range", ctx->size);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -650,7 +650,7 @@ ret=0
|
|||
$CHECKCONF kasp-bad-nsec3-iter.conf >checkconf.out$n 2>&1 && ret=1
|
||||
grep "dnssec-policy: nsec3 iterations value 151 out of range" <checkconf.out$n >/dev/null || ret=1
|
||||
lines=$(wc -l <"checkconf.out$n")
|
||||
if [ $lines -ne 3 ]; then ret=1; fi
|
||||
if [ $lines -ne 5 ]; then ret=1; fi
|
||||
if [ $ret -ne 0 ]; then echo_i "failed"; fi
|
||||
status=$((status + ret))
|
||||
|
||||
|
|
|
|||
|
|
@ -411,7 +411,7 @@ dns_dnssec_verify(const dns_name_t *name, dns_rdataset_t *set, dst_key_t *key,
|
|||
}
|
||||
|
||||
/*
|
||||
* NS, SOA and DNSSKEY records are signed by their owner.
|
||||
* NS, SOA and DNSKEY records are signed by their owner.
|
||||
* DS records are signed by the parent.
|
||||
*/
|
||||
switch (set->type) {
|
||||
|
|
|
|||
|
|
@ -23,6 +23,8 @@
|
|||
#define DNS_DSDIGEST_GOST (3)
|
||||
#define DNS_DSDIGEST_SHA384 (4)
|
||||
|
||||
#define DNS_DSDIGEST_MAX (255)
|
||||
|
||||
/*
|
||||
* Assuming SHA-384 digest type.
|
||||
*/
|
||||
|
|
|
|||
185
lib/dns/zone.c
185
lib/dns/zone.c
|
|
@ -3327,16 +3327,17 @@ integrity_checks(dns_zone_t *zone, dns_db_t *db) {
|
|||
dns_rdata_mx_t mx;
|
||||
dns_rdata_ns_t ns;
|
||||
dns_rdata_in_srv_t srv;
|
||||
dns_rdata_t rdata;
|
||||
dns_name_t *name;
|
||||
dns_name_t *bottom;
|
||||
isc_result_t result;
|
||||
bool ok = true, have_spf, have_txt;
|
||||
char namebuf[DNS_NAME_FORMATSIZE];
|
||||
bool logged_algorithm[DST_MAX_ALGS];
|
||||
bool logged_digest_type[DNS_DSDIGEST_MAX + 1];
|
||||
|
||||
name = dns_fixedname_initname(&fixed);
|
||||
bottom = dns_fixedname_initname(&fixedbottom);
|
||||
dns_rdataset_init(&rdataset);
|
||||
dns_rdata_init(&rdata);
|
||||
|
||||
result = dns_db_createiterator(db, 0, &dbiterator);
|
||||
if (result != ISC_R_SUCCESS) {
|
||||
|
|
@ -3362,6 +3363,55 @@ integrity_checks(dns_zone_t *zone, dns_db_t *db) {
|
|||
|
||||
dns_dbiterator_pause(dbiterator);
|
||||
|
||||
/*
|
||||
* Check for deprecated KEY algorithms
|
||||
*/
|
||||
result = dns_db_findrdataset(db, node, NULL, dns_rdatatype_key,
|
||||
0, 0, &rdataset, NULL);
|
||||
if (result != ISC_R_SUCCESS) {
|
||||
goto checkforns;
|
||||
}
|
||||
|
||||
memset(logged_algorithm, 0, sizeof(logged_algorithm));
|
||||
for (result = dns_rdataset_first(&rdataset);
|
||||
result == ISC_R_SUCCESS;
|
||||
result = dns_rdataset_next(&rdataset))
|
||||
{
|
||||
dns_rdata_t rdata = DNS_RDATA_INIT;
|
||||
dns_rdata_key_t key;
|
||||
dns_rdataset_current(&rdataset, &rdata);
|
||||
|
||||
result = dns_rdata_tostruct(&rdata, &key, NULL);
|
||||
RUNTIME_CHECK(result == ISC_R_SUCCESS);
|
||||
|
||||
/*
|
||||
* If we ever deprecate a private algorithm use
|
||||
* dst_algorithm_fromdata() here.
|
||||
*/
|
||||
switch (key.algorithm) {
|
||||
case DNS_KEYALG_RSASHA1:
|
||||
case DNS_KEYALG_NSEC3RSASHA1:
|
||||
if (!logged_algorithm[key.algorithm]) {
|
||||
char algbuf[DNS_SECALG_FORMATSIZE];
|
||||
dns_name_format(name, namebuf,
|
||||
sizeof(namebuf));
|
||||
dns_secalg_format(key.algorithm, algbuf,
|
||||
sizeof(algbuf));
|
||||
dnssec_log(zone, ISC_LOG_WARNING,
|
||||
"%s/KEY deprecated "
|
||||
"algorithm %u (%s)",
|
||||
namebuf, key.algorithm,
|
||||
algbuf);
|
||||
logged_algorithm[key.algorithm] = true;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
dns_rdataset_disassociate(&rdataset);
|
||||
|
||||
checkforns:
|
||||
/*
|
||||
* Don't check the NS records at the origin.
|
||||
*/
|
||||
|
|
@ -3374,6 +3424,7 @@ integrity_checks(dns_zone_t *zone, dns_db_t *db) {
|
|||
if (result != ISC_R_SUCCESS) {
|
||||
goto checkfordname;
|
||||
}
|
||||
|
||||
/*
|
||||
* Remember bottom of zone due to NS.
|
||||
*/
|
||||
|
|
@ -3381,6 +3432,7 @@ integrity_checks(dns_zone_t *zone, dns_db_t *db) {
|
|||
|
||||
result = dns_rdataset_first(&rdataset);
|
||||
while (result == ISC_R_SUCCESS) {
|
||||
dns_rdata_t rdata = DNS_RDATA_INIT;
|
||||
dns_rdataset_current(&rdataset, &rdata);
|
||||
result = dns_rdata_tostruct(&rdata, &ns, NULL);
|
||||
RUNTIME_CHECK(result == ISC_R_SUCCESS);
|
||||
|
|
@ -3391,6 +3443,73 @@ integrity_checks(dns_zone_t *zone, dns_db_t *db) {
|
|||
result = dns_rdataset_next(&rdataset);
|
||||
}
|
||||
dns_rdataset_disassociate(&rdataset);
|
||||
|
||||
/*
|
||||
* Check for deprecated DS digest types.
|
||||
*/
|
||||
result = dns_db_findrdataset(db, node, NULL, dns_rdatatype_ds,
|
||||
0, 0, &rdataset, NULL);
|
||||
if (result != ISC_R_SUCCESS) {
|
||||
goto next;
|
||||
}
|
||||
|
||||
memset(logged_algorithm, 0, sizeof(logged_algorithm));
|
||||
memset(logged_digest_type, 0, sizeof(logged_digest_type));
|
||||
for (result = dns_rdataset_first(&rdataset);
|
||||
result == ISC_R_SUCCESS;
|
||||
result = dns_rdataset_next(&rdataset))
|
||||
{
|
||||
dns_rdata_t rdata = DNS_RDATA_INIT;
|
||||
dns_rdataset_current(&rdataset, &rdata);
|
||||
dns_rdata_ds_t ds;
|
||||
|
||||
result = dns_rdata_tostruct(&rdata, &ds, NULL);
|
||||
RUNTIME_CHECK(result == ISC_R_SUCCESS);
|
||||
switch (ds.digest_type) {
|
||||
case DNS_DSDIGEST_SHA1:
|
||||
if (!logged_digest_type[ds.digest_type]) {
|
||||
char algbuf[DNS_DSDIGEST_FORMATSIZE];
|
||||
dns_name_format(name, namebuf,
|
||||
sizeof(namebuf));
|
||||
dns_dsdigest_format(ds.digest_type,
|
||||
algbuf,
|
||||
sizeof(algbuf));
|
||||
dnssec_log(zone, ISC_LOG_WARNING,
|
||||
"%s/DS deprecated digest "
|
||||
"type %u (%s)",
|
||||
namebuf, ds.digest_type,
|
||||
algbuf);
|
||||
logged_digest_type[ds.digest_type] =
|
||||
true;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
/*
|
||||
* If we ever deprecate a private algorithm use
|
||||
* dst_algorithm_fromdata() here.
|
||||
*/
|
||||
switch (ds.algorithm) {
|
||||
case DNS_KEYALG_RSASHA1:
|
||||
case DNS_KEYALG_NSEC3RSASHA1:
|
||||
if (!logged_algorithm[ds.algorithm]) {
|
||||
char algbuf[DNS_SECALG_FORMATSIZE];
|
||||
dns_name_format(name, namebuf,
|
||||
sizeof(namebuf));
|
||||
dns_secalg_format(ds.algorithm, algbuf,
|
||||
sizeof(algbuf));
|
||||
dnssec_log(zone, ISC_LOG_WARNING,
|
||||
"%s/DS deprecated algorithm "
|
||||
"%u (%s)",
|
||||
namebuf, ds.algorithm,
|
||||
algbuf);
|
||||
logged_algorithm[ds.algorithm] = true;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
dns_rdataset_disassociate(&rdataset);
|
||||
|
||||
goto next;
|
||||
|
||||
checkfordname:
|
||||
|
|
@ -3412,6 +3531,7 @@ integrity_checks(dns_zone_t *zone, dns_db_t *db) {
|
|||
}
|
||||
result = dns_rdataset_first(&rdataset);
|
||||
while (result == ISC_R_SUCCESS) {
|
||||
dns_rdata_t rdata = DNS_RDATA_INIT;
|
||||
dns_rdataset_current(&rdataset, &rdata);
|
||||
result = dns_rdata_tostruct(&rdata, &mx, NULL);
|
||||
RUNTIME_CHECK(result == ISC_R_SUCCESS);
|
||||
|
|
@ -3434,6 +3554,7 @@ integrity_checks(dns_zone_t *zone, dns_db_t *db) {
|
|||
}
|
||||
result = dns_rdataset_first(&rdataset);
|
||||
while (result == ISC_R_SUCCESS) {
|
||||
dns_rdata_t rdata = DNS_RDATA_INIT;
|
||||
dns_rdataset_current(&rdataset, &rdata);
|
||||
result = dns_rdata_tostruct(&rdata, &srv, NULL);
|
||||
RUNTIME_CHECK(result == ISC_R_SUCCESS);
|
||||
|
|
@ -3470,6 +3591,7 @@ integrity_checks(dns_zone_t *zone, dns_db_t *db) {
|
|||
}
|
||||
result = dns_rdataset_first(&rdataset);
|
||||
while (result == ISC_R_SUCCESS) {
|
||||
dns_rdata_t rdata = DNS_RDATA_INIT;
|
||||
dns_rdataset_current(&rdataset, &rdata);
|
||||
have_txt = isspf(&rdata);
|
||||
dns_rdata_reset(&rdata);
|
||||
|
|
@ -3482,8 +3604,6 @@ integrity_checks(dns_zone_t *zone, dns_db_t *db) {
|
|||
|
||||
notxt:
|
||||
if (have_spf && !have_txt) {
|
||||
char namebuf[DNS_NAME_FORMATSIZE];
|
||||
|
||||
dns_name_format(name, namebuf, sizeof(namebuf));
|
||||
dns_zone_log(zone, ISC_LOG_WARNING,
|
||||
"'%s' found type "
|
||||
|
|
@ -3516,9 +3636,10 @@ zone_check_dnskeys(dns_zone_t *zone, dns_db_t *db) {
|
|||
dns_dbnode_t *node = NULL;
|
||||
dns_dbversion_t *version = NULL;
|
||||
dns_rdata_dnskey_t dnskey;
|
||||
dns_rdata_t rdata = DNS_RDATA_INIT;
|
||||
dns_rdataset_t rdataset;
|
||||
isc_result_t result;
|
||||
bool logged_algorithm[DST_MAX_ALGS] = { 0 };
|
||||
bool alldeprecated = true;
|
||||
|
||||
result = dns_db_findnode(db, &zone->origin, false, &node);
|
||||
if (result != ISC_R_SUCCESS) {
|
||||
|
|
@ -3536,6 +3657,8 @@ zone_check_dnskeys(dns_zone_t *zone, dns_db_t *db) {
|
|||
for (result = dns_rdataset_first(&rdataset); result == ISC_R_SUCCESS;
|
||||
result = dns_rdataset_next(&rdataset))
|
||||
{
|
||||
char algbuf[DNS_SECALG_FORMATSIZE];
|
||||
dns_rdata_t rdata = DNS_RDATA_INIT;
|
||||
dns_rdataset_current(&rdataset, &rdata);
|
||||
result = dns_rdata_tostruct(&rdata, &dnskey, NULL);
|
||||
INSIST(result == ISC_R_SUCCESS);
|
||||
|
|
@ -3577,10 +3700,36 @@ zone_check_dnskeys(dns_zone_t *zone, dns_db_t *db) {
|
|||
algorithm, dnskey.algorithm,
|
||||
dst_region_computeid(&r));
|
||||
}
|
||||
dns_rdata_reset(&rdata);
|
||||
|
||||
switch (dnskey.algorithm) {
|
||||
case DNS_KEYALG_RSAMD5:
|
||||
case DNS_KEYALG_DSA:
|
||||
case DNS_KEYALG_RSASHA1:
|
||||
case DNS_KEYALG_NSEC3DSA:
|
||||
case DNS_KEYALG_NSEC3RSASHA1:
|
||||
case DNS_KEYALG_ECCGOST:
|
||||
if (!logged_algorithm[dnskey.algorithm]) {
|
||||
dns_secalg_format(dnskey.algorithm, algbuf,
|
||||
sizeof(algbuf));
|
||||
dnssec_log(zone, ISC_LOG_WARNING,
|
||||
"deprecated DNSKEY algorithm found: "
|
||||
"%u (%s)\n",
|
||||
dnskey.algorithm, algbuf);
|
||||
logged_algorithm[dnskey.algorithm] = true;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
alldeprecated = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
dns_rdataset_disassociate(&rdataset);
|
||||
|
||||
if (alldeprecated) {
|
||||
dnssec_log(zone, ISC_LOG_WARNING,
|
||||
"all DNSKEY algorithms found are deprecated");
|
||||
}
|
||||
|
||||
cleanup:
|
||||
if (node != NULL) {
|
||||
dns_db_detachnode(db, &node);
|
||||
|
|
@ -22873,6 +23022,7 @@ dns_zone_cdscheck(dns_zone_t *zone, dns_db_t *db, dns_dbversion_t *version) {
|
|||
* record which must be by itself.
|
||||
*/
|
||||
if (dns_rdataset_isassociated(&cds)) {
|
||||
bool logged_digest_type[DNS_DSDIGEST_MAX + 1] = { 0 };
|
||||
bool delete = false;
|
||||
memset(algorithms, notexpected, sizeof(algorithms));
|
||||
for (result = dns_rdataset_first(&cds); result == ISC_R_SUCCESS;
|
||||
|
|
@ -22900,6 +23050,29 @@ dns_zone_cdscheck(dns_zone_t *zone, dns_db_t *db, dns_dbversion_t *version) {
|
|||
}
|
||||
|
||||
CHECK(dns_rdata_tostruct(&crdata, &structcds, NULL));
|
||||
|
||||
/*
|
||||
* Log deprecated CDS digest types.
|
||||
*/
|
||||
switch (structcds.digest_type) {
|
||||
case DNS_DSDIGEST_SHA1:
|
||||
if (!logged_digest_type[structcds.digest_type])
|
||||
{
|
||||
char algbuf[DNS_DSDIGEST_FORMATSIZE];
|
||||
dns_dsdigest_format(
|
||||
structcds.digest_type, algbuf,
|
||||
sizeof(algbuf));
|
||||
dnssec_log(zone, ISC_LOG_WARNING,
|
||||
"deprecated CDS digest type "
|
||||
"%u (%s)",
|
||||
structcds.digest_type,
|
||||
algbuf);
|
||||
logged_digest_type[structcds.digest_type] =
|
||||
true;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
if (algorithms[structcds.algorithm] == 0) {
|
||||
algorithms[structcds.algorithm] = expected;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -171,6 +171,18 @@ cfg_kaspkey_fromconfig(const cfg_obj_t *config, dns_kasp_t *kasp,
|
|||
goto cleanup;
|
||||
}
|
||||
|
||||
switch (key->algorithm) {
|
||||
case DST_ALG_RSASHA1:
|
||||
case DST_ALG_NSEC3RSASHA1:
|
||||
cfg_obj_log(obj, logctx, ISC_LOG_WARNING,
|
||||
"dnssec-policy: DNSSEC algorithm %s is "
|
||||
"deprecated",
|
||||
alg.base);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
obj = cfg_tuple_get(config, "length");
|
||||
if (cfg_obj_isuint32(obj)) {
|
||||
uint32_t min, size;
|
||||
|
|
|
|||
Loading…
Reference in a new issue