diff --git a/bin/dnssec/dnssec-dsfromkey.c b/bin/dnssec/dnssec-dsfromkey.c index d0d32b3552..d4d8f3cc2e 100644 --- a/bin/dnssec/dnssec-dsfromkey.c +++ b/bin/dnssec/dnssec-dsfromkey.c @@ -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 " diff --git a/bin/dnssec/dnssec-keyfromlabel.c b/bin/dnssec/dnssec-keyfromlabel.c index 6cf9ec98ad..a42969d3ff 100644 --- a/bin/dnssec/dnssec-keyfromlabel.c +++ b/bin/dnssec/dnssec-keyfromlabel.c @@ -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) { diff --git a/bin/dnssec/dnssec-keygen.c b/bin/dnssec/dnssec-keygen.c index 5871cc9d3e..c768c766aa 100644 --- a/bin/dnssec/dnssec-keygen.c +++ b/bin/dnssec/dnssec-keygen.c @@ -141,14 +141,17 @@ usage(void) { fprintf(stderr, " -l : configuration file with dnssec-policy " "statement\n"); fprintf(stderr, " -a :\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 :\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); } diff --git a/bin/tests/system/checkconf/tests.sh b/bin/tests/system/checkconf/tests.sh index 7d222ed863..695067fe74 100644 --- a/bin/tests/system/checkconf/tests.sh +++ b/bin/tests/system/checkconf/tests.sh @@ -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" /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)) diff --git a/lib/dns/dnssec.c b/lib/dns/dnssec.c index 954c914221..400a41f16f 100644 --- a/lib/dns/dnssec.c +++ b/lib/dns/dnssec.c @@ -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) { diff --git a/lib/dns/include/dns/ds.h b/lib/dns/include/dns/ds.h index 629729bc3a..649ca80065 100644 --- a/lib/dns/include/dns/ds.h +++ b/lib/dns/include/dns/ds.h @@ -23,6 +23,8 @@ #define DNS_DSDIGEST_GOST (3) #define DNS_DSDIGEST_SHA384 (4) +#define DNS_DSDIGEST_MAX (255) + /* * Assuming SHA-384 digest type. */ diff --git a/lib/dns/zone.c b/lib/dns/zone.c index 542403e489..8c22f0f8ec 100644 --- a/lib/dns/zone.c +++ b/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; } diff --git a/lib/isccfg/kaspconf.c b/lib/isccfg/kaspconf.c index 47e47cd841..b8491a8f1f 100644 --- a/lib/isccfg/kaspconf.c +++ b/lib/isccfg/kaspconf.c @@ -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;