]> git.ipfire.org Git - thirdparty/bind9.git/commitdiff
Warn about deprecated DNSKEY and DS algorithms / digest types
authorMark Andrews <marka@isc.org>
Thu, 5 Jun 2025 04:49:10 +0000 (14:49 +1000)
committerMark Andrews <marka@isc.org>
Tue, 15 Jul 2025 23:14:22 +0000 (09:14 +1000)
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 cb6903c55e9ff6135a37c987fb6cee327967f0db)

bin/dnssec/dnssec-dsfromkey.c
bin/dnssec/dnssec-keyfromlabel.c
bin/dnssec/dnssec-keygen.c
bin/tests/system/checkconf/tests.sh
lib/dns/dnssec.c
lib/dns/include/dns/ds.h
lib/dns/zone.c
lib/isccfg/kaspconf.c

index d0d32b35526ebdeed33445b9b0701cddcc2b8d89..d4d8f3cc2eab1913855bb9e9dd35a57f4c385cc3 100644 (file)
@@ -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 "
index 6cf9ec98ad1c3f8aa7a8359ade3c9f562e818164..a42969d3ff99d9d48c106234193e95ae1d424fec 100644 (file)
@@ -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) {
index 5871cc9d3e76ce1c000043c5377eeba83074a804..c768c766aa88cc31913e4ff88a3aeff090ac35b7 100644 (file)
@@ -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);
                }
index 7d222ed863bb1fc451598548dbd4f78a0a0a7b6e..695067fe74a26129f636e68459f84c1b425d9693 100644 (file)
@@ -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))
 
index 954c914221c66bc04d7102c27fc848a4c92e4a7f..400a41f16ff22cd6db45362ec4dd1c695458b4cb 100644 (file)
@@ -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) {
index 629729bc3ac713a3855ab0aa6f0d424f37eb7ce9..649ca80065debfd258d77995220658cc251f9719 100644 (file)
@@ -23,6 +23,8 @@
 #define DNS_DSDIGEST_GOST   (3)
 #define DNS_DSDIGEST_SHA384 (4)
 
+#define DNS_DSDIGEST_MAX (255)
+
 /*
  * Assuming SHA-384 digest type.
  */
index 542403e489370a028debc78efdf420176c5ab3d2..8c22f0f8ec0caddb6d3ae99d0136208194836521 100644 (file)
@@ -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;
                        }
index 47e47cd8417b906a38ec87bd60b211a26e310b5e..b8491a8f1f0853d73307ad23fdaa2243bf3459bb 100644 (file)
@@ -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;