diff --git a/CHANGES b/CHANGES index f8b2ab0343..587bd10c72 100644 --- a/CHANGES +++ b/CHANGES @@ -1,3 +1,6 @@ +5230. [protocol] The SHA-1 hash algorithm is no longer used when + generating DS and CDS records. [GL #1015] + 5229. [protocol] Enforce known SSHFP fingerprint lengths. [GL #852] 5228. [func] If trusted-keys and managed-keys were configured diff --git a/bin/dnssec/dnssec-cds.c b/bin/dnssec/dnssec-cds.c index dfbc327aff..ba54acbd8a 100644 --- a/bin/dnssec/dnssec-cds.c +++ b/bin/dnssec/dnssec-cds.c @@ -59,12 +59,7 @@ #include "dnssectool.h" -#ifndef PATH_MAX -#define PATH_MAX 1024 /* WIN32, and others don't define this. */ -#endif - const char *program = "dnssec-cds"; -int verbose; /* * Infrastructure @@ -80,12 +75,6 @@ static dns_fixedname_t fixed; static dns_name_t *name = NULL; static dns_rdataclass_t rdclass = dns_rdataclass_in; -/* - * List of digest types used by ds_from_cdnskey(), filled in by add_dtype() - * from -a arguments. The size of the array is an arbitrary limit. - */ -static dns_dsdigest_t dtype[8]; - static const char *startstr = NULL; /* from which we derive notbefore */ static isc_stdtime_t notbefore = 0; /* restrict sig inception times */ static dns_rdata_rrsig_t oldestsig; /* for recording inception time */ @@ -836,34 +825,6 @@ ds_from_cdnskey(dns_rdatalist_t *dslist, isc_buffer_t *buf, return (ISC_R_SUCCESS); } -/* - * For sorting the digest types so that DS records generated - * from CDNSKEY records are in canonical order. - */ -static int -cmp_dtype(const void *ap, const void *bp) { - int a = *(const dns_dsdigest_t *)ap; - int b = *(const dns_dsdigest_t *)bp; - return (a - b); -} - -static void -add_dtype(const char *dn) { - dns_dsdigest_t dt; - unsigned i, n; - - dt = strtodsdigest(dn); - n = sizeof(dtype)/sizeof(dtype[0]); - for (i = 0; i < n; i++) { - if (dtype[i] == 0 || dtype[i] == dt) { - dtype[i] = dt; - qsort(dtype, i+1, 1, cmp_dtype); - return; - } - } - fatal("too many -a digest type arguments"); -} - static void make_new_ds_set(ds_maker_func_t *ds_from_rdata, uint32_t ttl, dns_rdataset_t *rdset) @@ -1152,7 +1113,7 @@ main(int argc, char *argv[]) { while ((ch = isc_commandline_parse(argc, argv, OPTIONS)) != -1) { switch (ch) { case 'a': - add_dtype(isc_commandline_argument); + add_dtype(strtodsdigest(isc_commandline_argument)); break; case 'c': rdclass = strtoclass(isc_commandline_argument); diff --git a/bin/dnssec/dnssec-dsfromkey.c b/bin/dnssec/dnssec-dsfromkey.c index 8aecb5f477..5ea294b93e 100644 --- a/bin/dnssec/dnssec-dsfromkey.c +++ b/bin/dnssec/dnssec-dsfromkey.c @@ -47,12 +47,7 @@ #include "dnssectool.h" -#ifndef PATH_MAX -#define PATH_MAX 1024 /* WIN32, and others don't define this. */ -#endif - const char *program = "dnssec-dsfromkey"; -int verbose; static dns_rdataclass_t rdclass; static dns_fixedname_t fixed; @@ -233,7 +228,7 @@ logkey(dns_rdata_t *rdata) } static void -emit(dns_dsdigest_t dtype, bool showall, char *lookaside, +emit(dns_dsdigest_t dt, bool showall, char *lookaside, bool cds, dns_rdata_t *rdata) { isc_result_t result; @@ -259,7 +254,7 @@ emit(dns_dsdigest_t dtype, bool showall, char *lookaside, if ((dnskey.flags & DNS_KEYFLAG_KSK) == 0 && !showall) return; - result = dns_ds_buildrdata(name, rdata, dtype, buf, &ds); + result = dns_ds_buildrdata(name, rdata, dt, buf, &ds); if (result != ISC_R_SUCCESS) fatal("can't build record"); @@ -310,6 +305,18 @@ emit(dns_dsdigest_t dtype, bool showall, char *lookaside, printf("%.*s\n", (int)r.length, r.base); } +static void +emits(bool showall, char *lookaside, bool cds, dns_rdata_t *rdata) { + unsigned i, n; + + n = sizeof(dtype)/sizeof(dtype[0]); + for (i = 0; i < n; i++) { + if (dtype[i] != 0) { + emit(dtype[i], showall, lookaside, cds, rdata); + } + } +} + ISC_PLATFORM_NORETURN_PRE static void usage(void) ISC_PLATFORM_NORETURN_POST; @@ -348,11 +355,9 @@ main(int argc, char **argv) { char *lookaside = NULL; char *endp; int ch; - dns_dsdigest_t dtype = DNS_DSDIGEST_SHA1; - bool cds = false; - bool both = true; - bool usekeyset = false; - bool showall = false; + bool cds = false; + bool usekeyset = false; + bool showall = false; isc_result_t result; isc_log_t *log = NULL; dns_rdataset_t rdataset; @@ -360,12 +365,14 @@ main(int argc, char **argv) { dns_rdata_init(&rdata); - if (argc == 1) + if (argc == 1) { usage(); + } result = isc_mem_create(0, 0, &mctx); - if (result != ISC_R_SUCCESS) + if (result != ISC_R_SUCCESS) { fatal("out of memory"); + } #if USE_PKCS11 pk11_result_register(); @@ -378,19 +385,16 @@ main(int argc, char **argv) { while ((ch = isc_commandline_parse(argc, argv, OPTIONS)) != -1) { switch (ch) { case '1': - dtype = DNS_DSDIGEST_SHA1; - both = false; + add_dtype(DNS_DSDIGEST_SHA1); break; case '2': - dtype = DNS_DSDIGEST_SHA256; - both = false; + add_dtype(DNS_DSDIGEST_SHA256); break; case 'A': showall = true; break; case 'a': - dtype = strtodsdigest(isc_commandline_argument); - both = false; + add_dtype(strtodsdigest(isc_commandline_argument)); break; case 'C': if (lookaside != NULL) @@ -458,22 +462,32 @@ main(int argc, char **argv) { rdclass = strtoclass(classname); - if (usekeyset && filename != NULL) + if (usekeyset && filename != NULL) { fatal("cannot use both -s and -f"); + } /* When not using -f, -A is implicit */ - if (filename == NULL) + if (filename == NULL) { showall = true; + } - if (argc < isc_commandline_index + 1 && filename == NULL) + /* Default digest type if none specified. */ + if (dtype[0] == 0) { + dtype[0] = DNS_DSDIGEST_SHA256; + } + + if (argc < isc_commandline_index + 1 && filename == NULL) { fatal("the key file name was not specified"); - if (argc > isc_commandline_index + 1) + } + if (argc > isc_commandline_index + 1) { fatal("extraneous arguments"); + } result = dst_lib_init(mctx, NULL); - if (result != ISC_R_SUCCESS) + if (result != ISC_R_SUCCESS) { fatal("could not initialize dst: %s", isc_result_totext(result)); + } setup_logging(mctx, &log); @@ -483,38 +497,38 @@ main(int argc, char **argv) { if (argc < isc_commandline_index + 1 && filename != NULL) { /* using zone name as the zone file name */ namestr = filename; - } else + } else { namestr = argv[isc_commandline_index]; + } result = initname(namestr); - if (result != ISC_R_SUCCESS) + if (result != ISC_R_SUCCESS) { fatal("could not initialize name %s", namestr); + } - if (usekeyset) + if (usekeyset) { result = loadkeyset(dir, &rdataset); - else + } else { result = loadset(filename, &rdataset); + } - if (result != ISC_R_SUCCESS) + if (result != ISC_R_SUCCESS) { fatal("could not load DNSKEY set: %s\n", isc_result_totext(result)); + } for (result = dns_rdataset_first(&rdataset); result == ISC_R_SUCCESS; - result = dns_rdataset_next(&rdataset)) { + result = dns_rdataset_next(&rdataset)) + { dns_rdata_init(&rdata); dns_rdataset_current(&rdataset, &rdata); - if (verbose > 2) + if (verbose > 2) { logkey(&rdata); + } - if (both) { - emit(DNS_DSDIGEST_SHA1, showall, lookaside, - cds, &rdata); - emit(DNS_DSDIGEST_SHA256, showall, lookaside, - cds, &rdata); - } else - emit(dtype, showall, lookaside, cds, &rdata); + emits(showall, lookaside, cds, &rdata); } } else { unsigned char key_buf[DST_KEY_MAXSIZE]; @@ -522,28 +536,25 @@ main(int argc, char **argv) { loadkey(argv[isc_commandline_index], key_buf, DST_KEY_MAXSIZE, &rdata); - if (both) { - emit(DNS_DSDIGEST_SHA1, showall, lookaside, cds, - &rdata); - emit(DNS_DSDIGEST_SHA256, showall, lookaside, cds, - &rdata); - } else - emit(dtype, showall, lookaside, cds, &rdata); + emits(showall, lookaside, cds, &rdata); } - if (dns_rdataset_isassociated(&rdataset)) + if (dns_rdataset_isassociated(&rdataset)) { dns_rdataset_disassociate(&rdataset); + } cleanup_logging(&log); dst_lib_destroy(); dns_name_destroy(); - if (verbose > 10) + if (verbose > 10) { isc_mem_stats(mctx, stdout); + } isc_mem_destroy(&mctx); fflush(stdout); if (ferror(stdout)) { fprintf(stderr, "write error\n"); return (1); - } else + } else { return (0); + } } diff --git a/bin/dnssec/dnssec-dsfromkey.docbook b/bin/dnssec/dnssec-dsfromkey.docbook index 7f0039ebb1..d67e404178 100644 --- a/bin/dnssec/dnssec-dsfromkey.docbook +++ b/bin/dnssec/dnssec-dsfromkey.docbook @@ -12,7 +12,7 @@ - 2012-05-02 + 2019-05-08 ISC @@ -150,7 +150,9 @@ -1 - An abbreviation for + An abbreviation for . + (Note: The SHA-1 algorithm is no longer recommended for use + when generating new DS and CDS records.) @@ -159,7 +161,7 @@ -2 - An abbreviation for + An abbreviation for . @@ -178,6 +180,8 @@ SHA-1, SHA-256, or SHA-384. These values are case insensitive, and the hyphen may be omitted. If no algorithm is specified, the default is SHA-256. + (Note: The SHA-1 algorithm is no longer recommended for use + when generating new DS and CDS records.) diff --git a/bin/dnssec/dnssec-importkey.c b/bin/dnssec/dnssec-importkey.c index 195909f9ce..494535bd10 100644 --- a/bin/dnssec/dnssec-importkey.c +++ b/bin/dnssec/dnssec-importkey.c @@ -46,12 +46,7 @@ #include "dnssectool.h" -#ifndef PATH_MAX -#define PATH_MAX 1024 /* WIN32, and others don't define this. */ -#endif - const char *program = "dnssec-importkey"; -int verbose; static dns_rdataclass_t rdclass; static dns_fixedname_t fixed; diff --git a/bin/dnssec/dnssec-keyfromlabel.c b/bin/dnssec/dnssec-keyfromlabel.c index 741c047450..ea156c7677 100644 --- a/bin/dnssec/dnssec-keyfromlabel.c +++ b/bin/dnssec/dnssec-keyfromlabel.c @@ -46,7 +46,6 @@ #define MAX_RSA 4096 /* should be long enough... */ const char *program = "dnssec-keyfromlabel"; -int verbose; ISC_PLATFORM_NORETURN_PRE static void usage(void) ISC_PLATFORM_NORETURN_POST; diff --git a/bin/dnssec/dnssec-keygen.c b/bin/dnssec/dnssec-keygen.c index 203f1507a7..aae310341d 100644 --- a/bin/dnssec/dnssec-keygen.c +++ b/bin/dnssec/dnssec-keygen.c @@ -61,7 +61,6 @@ #define MAX_RSA 4096 /* should be long enough... */ const char *program = "dnssec-keygen"; -int verbose; ISC_PLATFORM_NORETURN_PRE static void usage(void) ISC_PLATFORM_NORETURN_POST; diff --git a/bin/dnssec/dnssec-revoke.c b/bin/dnssec/dnssec-revoke.c index 17f158397a..6c8f38b5d7 100644 --- a/bin/dnssec/dnssec-revoke.c +++ b/bin/dnssec/dnssec-revoke.c @@ -37,7 +37,6 @@ #include "dnssectool.h" const char *program = "dnssec-revoke"; -int verbose; static isc_mem_t *mctx = NULL; diff --git a/bin/dnssec/dnssec-settime.c b/bin/dnssec/dnssec-settime.c index ff49aea0be..f362162be3 100644 --- a/bin/dnssec/dnssec-settime.c +++ b/bin/dnssec/dnssec-settime.c @@ -40,7 +40,6 @@ #include "dnssectool.h" const char *program = "dnssec-settime"; -int verbose; static isc_mem_t *mctx = NULL; diff --git a/bin/dnssec/dnssec-signzone.c b/bin/dnssec/dnssec-signzone.c index da3bfb3031..f3a24cb1c3 100644 --- a/bin/dnssec/dnssec-signzone.c +++ b/bin/dnssec/dnssec-signzone.c @@ -86,12 +86,7 @@ #include "dnssectool.h" -#ifndef PATH_MAX -#define PATH_MAX 1024 /* WIN32, and others don't define this. */ -#endif - const char *program = "dnssec-signzone"; -int verbose; typedef struct hashlist hashlist_t; @@ -992,16 +987,6 @@ loadds(dns_name_t *name, uint32_t ttl, dns_rdataset_t *dsset) { dns_rdata_init(&key); dns_rdata_init(&ds); dns_rdataset_current(&keyset, &key); - result = dns_ds_buildrdata(name, &key, DNS_DSDIGEST_SHA1, - dsbuf, &ds); - check_result(result, "dns_ds_buildrdata"); - - result = dns_difftuple_create(mctx, DNS_DIFFOP_ADDRESIGN, name, - ttl, &ds, &tuple); - check_result(result, "dns_difftuple_create"); - dns_diff_append(&diff, &tuple); - - dns_rdata_reset(&ds); result = dns_ds_buildrdata(name, &key, DNS_DSDIGEST_SHA256, dsbuf, &ds); check_result(result, "dns_ds_buildrdata"); @@ -3000,19 +2985,6 @@ writeset(const char *prefix, dns_rdatatype_t type) { isc_buffer_usedregion(&b, &r); dns_rdata_fromregion(&rdata, gclass, dns_rdatatype_dnskey, &r); if (type != dns_rdatatype_dnskey) { - result = dns_ds_buildrdata(gorigin, &rdata, - DNS_DSDIGEST_SHA1, - dsbuf, &ds); - check_result(result, "dns_ds_buildrdata"); - if (type == dns_rdatatype_dlv) - ds.type = dns_rdatatype_dlv; - result = dns_difftuple_create(mctx, - DNS_DIFFOP_ADDRESIGN, - name, 0, &ds, &tuple); - check_result(result, "dns_difftuple_create"); - dns_diff_append(&diff, &tuple); - - dns_rdata_reset(&ds); result = dns_ds_buildrdata(gorigin, &rdata, DNS_DSDIGEST_SHA256, dsbuf, &ds); @@ -3023,11 +2995,12 @@ writeset(const char *prefix, dns_rdatatype_t type) { DNS_DIFFOP_ADDRESIGN, name, 0, &ds, &tuple); - } else + } else { result = dns_difftuple_create(mctx, DNS_DIFFOP_ADDRESIGN, gorigin, zone_soa_min_ttl, &rdata, &tuple); + } check_result(result, "dns_difftuple_create"); dns_diff_append(&diff, &tuple); } diff --git a/bin/dnssec/dnssec-verify.c b/bin/dnssec/dnssec-verify.c index 2d14eb0660..b38368b2df 100644 --- a/bin/dnssec/dnssec-verify.c +++ b/bin/dnssec/dnssec-verify.c @@ -67,7 +67,6 @@ #include "dnssectool.h" const char *program = "dnssec-verify"; -int verbose; static isc_stdtime_t now; static isc_mem_t *mctx = NULL; diff --git a/bin/dnssec/dnssectool.c b/bin/dnssec/dnssectool.c index 81d9cc04d9..e1205d05f8 100644 --- a/bin/dnssec/dnssectool.c +++ b/bin/dnssec/dnssectool.c @@ -57,8 +57,8 @@ #include "dnssectool.h" -extern int verbose; -extern const char *program; +int verbose; +uint8_t dtype[8]; static fatalcallback_t *fatalcallback = NULL; @@ -344,6 +344,32 @@ strtodsdigest(const char *algname) { } } +static int +cmp_dtype(const void *ap, const void *bp) { + int a = *(const uint8_t *)ap; + int b = *(const uint8_t *)bp; + return (a - b); +} + +void +add_dtype(unsigned int dt) { + unsigned i, n; + + /* ensure there is space for a zero terminator */ + n = sizeof(dtype)/sizeof(dtype[0]) - 1; + for (i = 0; i < n; i++) { + if (dtype[i] == dt) { + return; + } + if (dtype[i] == 0) { + dtype[i] = dt; + qsort(dtype, i+1, 1, cmp_dtype); + return; + } + } + fatal("too many -a digest type arguments"); +} + isc_result_t try_dir(const char *dirname) { isc_result_t result; diff --git a/bin/dnssec/dnssectool.h b/bin/dnssec/dnssectool.h index aeae3a18b3..e4798e8336 100644 --- a/bin/dnssec/dnssectool.h +++ b/bin/dnssec/dnssectool.h @@ -21,6 +21,25 @@ #include #include +#ifndef PATH_MAX +#define PATH_MAX 1024 /* WIN32, and others don't define this. */ +#endif + +/*! verbosity: set by -v option in each program, defined in dnssectool.c */ +extern int verbose; + +/*! program name, statically initialized in each program */ +extern const char *program; + +/*! + * List of DS digest types used by dnssec-cds and dnssec-dsfromkey, + * defined in dnssectool.c. Filled in by add_dtype() from -a + * arguments, sorted (so that DS records are in a canonical order) and + * terminated by a zero. The size of the array is an arbitrary limit + * which should be greater than the number of known digest types. + */ +extern uint8_t dtype[8]; + typedef void (fatalcallback_t)(void); ISC_PLATFORM_NORETURN_PRE void @@ -55,11 +74,14 @@ isc_stdtime_t strtotime(const char *str, int64_t now, int64_t base, bool *setp); +dns_rdataclass_t +strtoclass(const char *str); + unsigned int strtodsdigest(const char *str); -dns_rdataclass_t -strtoclass(const char *str); +void +add_dtype(unsigned int dt); isc_result_t try_dir(const char *dirname); diff --git a/bin/python/dnssec-checkds.docbook b/bin/python/dnssec-checkds.docbook index 113e47ceb0..bc18b616f6 100644 --- a/bin/python/dnssec-checkds.docbook +++ b/bin/python/dnssec-checkds.docbook @@ -67,8 +67,26 @@ OPTIONS - + + + -a algorithm + + + Specify a digest algorithm to use when converting the + zone's DNSKEY records to expected DS or DLV records. This + option can be repeated, so that multiple records are + checked for each DNSKEY record. + + + The algorithm must be one of + SHA-1, SHA-256, or SHA-384. These values are case insensitive, + and the hyphen may be omitted. If no algorithm is specified, + the default is SHA-256. + + + + -f file diff --git a/bin/python/isc/checkds.py.in b/bin/python/isc/checkds.py.in index b5cbe3fd05..f20d6bf564 100644 --- a/bin/python/isc/checkds.py.in +++ b/bin/python/isc/checkds.py.in @@ -114,19 +114,19 @@ def check(zone, args): klist = [] + cmd = [args.dsfromkey] + for algo in args.algo: + cmd += ['-a', algo] + if args.lookaside: + cmd += ["-l", args.lookaside] + if args.masterfile: - cmd = [args.dsfromkey, "-f", args.masterfile] - if args.lookaside: - cmd += ["-l", args.lookaside] - cmd.append(zone) + cmd += ["-f", args.masterfile, zone] fp, _ = Popen(cmd, stdout=PIPE).communicate() else: intods, _ = Popen([args.dig, "+noall", "+answer", "-t", "dnskey", "-q", zone], stdout=PIPE).communicate() - cmd = [args.dsfromkey, "-f", "-"] - if args.lookaside: - cmd += ["-l", args.lookaside] - cmd.append(zone) + cmd += ["-f", "-", zone] fp, _ = Popen(cmd, stdin=PIPE, stdout=PIPE).communicate(intods) for line in fp.splitlines(): @@ -138,23 +138,27 @@ def check(zone, args): print("No DNSKEY records found in zone apex") return False - found = False + match = True + for rr in rrlist: + if rr not in klist: + print("KSK for %s %s/%03d/%05d (%s) missing from child" % + (rr.rrtype, rr.rrname.strip('.'), rr.keyalg, + rr.keyid, SECRR.hashalgs[rr.hashalg])) + match = False + for rr in klist: + if rr not in rrlist: + print("%s for KSK %s/%03d/%05d (%s) missing from parent" % + (rr.rrtype, rr.rrname.strip('.'), rr.keyalg, + rr.keyid, SECRR.hashalgs[rr.hashalg])) + match = False for rr in klist: if rr in rrlist: print("%s for KSK %s/%03d/%05d (%s) found in parent" % (rr.rrtype, rr.rrname.strip('.'), rr.keyalg, rr.keyid, SECRR.hashalgs[rr.hashalg])) - found = True - else: - print("%s for KSK %s/%03d/%05d (%s) missing from parent" % - (rr.rrtype, rr.rrname.strip('.'), rr.keyalg, - rr.keyid, SECRR.hashalgs[rr.hashalg])) - if not found: - print("No %s records were found for any DNSKEY" % - ("DLV" if args.lookaside else "DS")) + return match - return found ############################################################################ # parse_args: @@ -167,6 +171,8 @@ def parse_args(): sbindir = 'bin' if os.name == 'nt' else 'sbin' parser.add_argument('zone', type=str, help='zone to check') + parser.add_argument('-a', '--algo', dest='algo', action='append', + default=[], type=str, help='DS digest algorithm') parser.add_argument('-d', '--dig', dest='dig', default=os.path.join(prefix(bindir), 'dig'), type=str, help='path to \'dig\'') @@ -196,5 +202,5 @@ def parse_args(): ############################################################################ def main(): args = parse_args() - found = check(args.zone, args) - exit(0 if found else 1) + match = check(args.zone, args) + exit(0 if match else 1) diff --git a/bin/tests/system/cds/setup.sh b/bin/tests/system/cds/setup.sh index ca13261af5..92bd9c94d4 100644 --- a/bin/tests/system/cds/setup.sh +++ b/bin/tests/system/cds/setup.sh @@ -44,7 +44,7 @@ tac() { convert() { key=$1 n=$2 - $DSFROMKEY $key >DS.$n + $DSFROMKEY -12 $key >DS.$n grep ' 8 1 ' DS.$n >DS.$n-1 grep ' 8 2 ' DS.$n >DS.$n-2 sed 's/ IN DS / IN CDS /' >CDS.$n diff --git a/bin/tests/system/checkds/tests.sh b/bin/tests/system/checkds/tests.sh index 2d2faba9cd..1d46bc53c4 100644 --- a/bin/tests/system/checkds/tests.sh +++ b/bin/tests/system/checkds/tests.sh @@ -15,10 +15,10 @@ SYSTEMTESTTOP=.. if [ "$CYGWIN" ]; then DIG=".\dig.bat" WINDSFROMKEY=`cygpath -w $DSFROMKEY` - CHECKDS="$CHECKDS -d $DIG -D $WINDSFROMKEY" + CHECKDS="$CHECKDS -a sha1 -a sha256 -d $DIG -D $WINDSFROMKEY" else DIG="./dig.sh" - CHECKDS="$CHECKDS -d $DIG -D $DSFROMKEY" + CHECKDS="$CHECKDS -a sha1 -a sha256 -d $DIG -D $DSFROMKEY" fi chmod +x $DIG @@ -61,7 +61,7 @@ n=`expr $n + 1` if [ $ret != 0 ]; then echo_i "failed"; fi status=`expr $status + $ret` -echo_i "checking for incorrect DS, lowronging up key via 'dig' ($n)" +echo_i "checking for incorrect DS, looking up key via 'dig' ($n)" ret=0 $CHECKDS wrong.example > checkds.out.$n 2>&1 || ret=1 grep 'SHA-1' checkds.out.$n > /dev/null 2>&1 || ret=1 @@ -79,7 +79,7 @@ n=`expr $n + 1` if [ $ret != 0 ]; then echo_i "failed"; fi status=`expr $status + $ret` -echo_i "checking for incorrect DLV, lowronging up key via 'dig' ($n)" +echo_i "checking for incorrect DLV, looking up key via 'dig' ($n)" ret=0 $CHECKDS -l dlv.example wrong.example > checkds.out.$n 2>&1 || ret=1 grep 'SHA-1' checkds.out.$n > /dev/null 2>&1 || ret=1 @@ -97,10 +97,9 @@ n=`expr $n + 1` if [ $ret != 0 ]; then echo_i "failed"; fi status=`expr $status + $ret` - echo_i "checking for partially missing DS, looking up key via 'dig' ($n)" ret=0 -$CHECKDS missing.example > checkds.out.$n 2>&1 || ret=1 +$CHECKDS missing.example > checkds.out.$n 2>&1 && ret=1 grep 'SHA-1.*found' checkds.out.$n > /dev/null 2>&1 || ret=1 grep 'SHA-256.*found' checkds.out.$n > /dev/null 2>&1 || ret=1 grep 'SHA-1.*missing' checkds.out.$n > /dev/null 2>&1 || ret=1 @@ -111,7 +110,7 @@ status=`expr $status + $ret` echo_i "checking for partially missing DS, obtaining key from file ($n)" ret=0 -$CHECKDS -f missing.example.dnskey.db missing.example > checkds.out.$n 2>&1 || ret=1 +$CHECKDS -f missing.example.dnskey.db missing.example > checkds.out.$n 2>&1 && ret=1 grep 'SHA-1.*found' checkds.out.$n > /dev/null 2>&1 || ret=1 grep 'SHA-256.*found' checkds.out.$n > /dev/null 2>&1 || ret=1 grep 'SHA-1.*missing' checkds.out.$n > /dev/null 2>&1 || ret=1 @@ -122,7 +121,7 @@ status=`expr $status + $ret` echo_i "checking for partially missing DLV, looking up key via 'dig' ($n)" ret=0 -$CHECKDS -l dlv.example missing.example > checkds.out.$n 2>&1 || ret=1 +$CHECKDS -l dlv.example missing.example > checkds.out.$n 2>&1 && ret=1 grep 'SHA-1.*found' checkds.out.$n > /dev/null 2>&1 || ret=1 grep 'SHA-256.*found' checkds.out.$n > /dev/null 2>&1 || ret=1 grep 'SHA-1.*missing' checkds.out.$n > /dev/null 2>&1 || ret=1 @@ -133,7 +132,7 @@ status=`expr $status + $ret` echo_i "checking for partially missing DLV, obtaining key from file ($n)" ret=0 -$CHECKDS -l dlv.example -f missing.example.dnskey.db missing.example > checkds.out.$n 2>&1 || ret=1 +$CHECKDS -l dlv.example -f missing.example.dnskey.db missing.example > checkds.out.$n 2>&1 && ret=1 grep 'SHA-1.*found' checkds.out.$n > /dev/null 2>&1 || ret=1 grep 'SHA-256.*found' checkds.out.$n > /dev/null 2>&1 || ret=1 grep 'SHA-1.*missing' checkds.out.$n > /dev/null 2>&1 || ret=1 @@ -145,7 +144,8 @@ status=`expr $status + $ret` echo_i "checking for entirely missing DS, looking up key via 'dig' ($n)" ret=0 $CHECKDS none.example > checkds.out.$n 2>&1 && ret=1 -grep 'No DS' checkds.out.$n > /dev/null 2>&1 || ret=1 +grep 'SHA-1.*found' checkds.out.$n > /dev/null 2>&1 && ret=1 +grep 'SHA-256.*found' checkds.out.$n > /dev/null 2>&1 && ret=1 n=`expr $n + 1` if [ $ret != 0 ]; then echo_i "failed"; fi status=`expr $status + $ret` @@ -153,7 +153,8 @@ status=`expr $status + $ret` echo_i "checking for entirely missing DS, obtaining key from file ($n)" ret=0 $CHECKDS -f none.example.dnskey.db none.example > checkds.out.$n 2>&1 && ret=1 -grep 'No DS' checkds.out.$n > /dev/null 2>&1 || ret=1 +grep 'SHA-1.*found' checkds.out.$n > /dev/null 2>&1 && ret=1 +grep 'SHA-256.*found' checkds.out.$n > /dev/null 2>&1 && ret=1 n=`expr $n + 1` if [ $ret != 0 ]; then echo_i "failed"; fi status=`expr $status + $ret` @@ -161,7 +162,8 @@ status=`expr $status + $ret` echo_i "checking for entirely missing DLV, looking up key via 'dig' ($n)" ret=0 $CHECKDS -l dlv.example none.example > checkds.out.$n 2>&1 && ret=1 -grep 'No DLV' checkds.out.$n > /dev/null 2>&1 || ret=1 +grep 'SHA-1.*found' checkds.out.$n > /dev/null 2>&1 && ret=1 +grep 'SHA-256.*found' checkds.out.$n > /dev/null 2>&1 && ret=1 n=`expr $n + 1` if [ $ret != 0 ]; then echo_i "failed"; fi status=`expr $status + $ret` @@ -169,7 +171,8 @@ status=`expr $status + $ret` echo_i "checking for entirely missing DLV, obtaining key from file ($n)" ret=0 $CHECKDS -l dlv.example -f none.example.dnskey.db none.example > checkds.out.$n 2>&1 && ret=1 -grep 'No DLV' checkds.out.$n > /dev/null 2>&1 || ret=1 +grep 'SHA-1.*found' checkds.out.$n > /dev/null 2>&1 && ret=1 +grep 'SHA-256.*found' checkds.out.$n > /dev/null 2>&1 && ret=1 n=`expr $n + 1` if [ $ret != 0 ]; then echo_i "failed"; fi status=`expr $status + $ret` diff --git a/bin/tests/system/dnssec/tests.sh b/bin/tests/system/dnssec/tests.sh index 4cf69f0beb..a60c0f0696 100644 --- a/bin/tests/system/dnssec/tests.sh +++ b/bin/tests/system/dnssec/tests.sh @@ -3337,7 +3337,7 @@ echo update delete cds-update.secure CDS echo send dig_with_opts +noall +answer @10.53.0.2 dnskey cds-update.secure | grep "DNSKEY.257" | -$DSFROMKEY -C -f - -T 1 cds-update.secure | +$DSFROMKEY -12 -C -f - -T 1 cds-update.secure | sed "s/^/update add /" echo send ) | $NSUPDATE @@ -3360,7 +3360,7 @@ echo update delete cds-kskonly.secure CDS echo send dig_with_opts +noall +answer @10.53.0.2 dnskey cds-kskonly.secure | grep "DNSKEY.257" | -$DSFROMKEY -C -f - -T 1 cds-kskonly.secure | +$DSFROMKEY -12 -C -f - -T 1 cds-kskonly.secure | sed "s/^/update add /" echo send ) | $NSUPDATE @@ -3394,11 +3394,11 @@ echo update delete cds-update.secure CDS echo send dig_with_opts +noall +answer @10.53.0.2 dnskey cds-update.secure | grep "DNSKEY.257" | -$DSFROMKEY -C -f - -T 1 cds-update.secure | +$DSFROMKEY -12 -C -f - -T 1 cds-update.secure | sed "s/^/update add /" dig_with_opts +noall +answer @10.53.0.2 dnskey cds-update.secure | grep "DNSKEY.257" | sed 's/DNSKEY.257/DNSKEY 258/' | -$DSFROMKEY -C -A -f - -T 1 cds-update.secure | +$DSFROMKEY -12 -C -A -f - -T 1 cds-update.secure | sed "s/^/update add /" echo send ) | $NSUPDATE diff --git a/bin/tests/system/resolver/tests.sh b/bin/tests/system/resolver/tests.sh index 3d32e31ad6..6706e65675 100755 --- a/bin/tests/system/resolver/tests.sh +++ b/bin/tests/system/resolver/tests.sh @@ -470,16 +470,16 @@ n=`expr $n + 1` echo_i "check prefetch of validated DS's RRSIG TTL is updated (${n})" ret=0 $DIG $DIGOPTS +dnssec @10.53.0.5 ds.example.net ds > dig.out.1.${n} || ret=1 -ttl1=`awk '$4 == "DS" && $7 == "1" { print $2 - 2 }' dig.out.1.${n}` +ttl1=`awk '$4 == "DS" && $7 == "2" { print $2 - 2 }' dig.out.1.${n}` # sleep so we are in prefetch range sleep ${ttl1:-0} # trigger prefetch $DIG $DIGOPTS @10.53.0.5 ds.example.net ds > dig.out.2.${n} || ret=1 -ttl1=`awk '$4 == "DS" && $7 == "1" { print $2 }' dig.out.2.${n}` +ttl1=`awk '$4 == "DS" && $7 == "2" { print $2 }' dig.out.2.${n}` sleep 1 # check that prefetch occured $DIG $DIGOPTS @10.53.0.5 ds.example.net ds +dnssec > dig.out.3.${n} || ret=1 -dsttl=`awk '$4 == "DS" && $7 == "1" { print $2 }' dig.out.3.${n}` +dsttl=`awk '$4 == "DS" && $7 == "2" { print $2 }' dig.out.3.${n}` sigttl=`awk '$4 == "RRSIG" && $5 == "DS" { print $2 }' dig.out.3.${n}` test ${dsttl:-0} -gt ${ttl2:-1} || ret=1 test ${sigttl:-0} -gt ${ttl2:-1} || ret=1 diff --git a/doc/arm/notes.xml b/doc/arm/notes.xml index 2781c728a8..732da2f8da 100644 --- a/doc/arm/notes.xml +++ b/doc/arm/notes.xml @@ -144,6 +144,21 @@ configuration error. [GL #868] + + + DS and CDS records are now generated with SHA-256 digests + only, instead of both SHA-1 and SHA-256. This affects the + default output of dnssec-dsfromkey, the + dsset files generated by + dnssec-signzone, the DS records added to + a zone by dnssec-signzone based on + keyset files, the CDS records added to + a zone by named and + dnssec-signzone based on "sync" timing + parameters in key files, and the checks performed by + dnssec-checkds. + + diff --git a/lib/dns/dnssec.c b/lib/dns/dnssec.c index 4dfa7276fb..b51f411dac 100644 --- a/lib/dns/dnssec.c +++ b/lib/dns/dnssec.c @@ -1909,8 +1909,8 @@ dns_dnssec_syncupdate(dns_dnsseckeylist_t *keys, dns_dnsseckeylist_t *rmkeys, for (key = ISC_LIST_HEAD(*keys); key != NULL; key = ISC_LIST_NEXT(key, link)) { - dns_rdata_t cdsrdata1 = DNS_RDATA_INIT; - dns_rdata_t cdsrdata2 = DNS_RDATA_INIT; + dns_rdata_t cds_sha1 = DNS_RDATA_INIT; + dns_rdata_t cds_sha256 = DNS_RDATA_INIT; dns_rdata_t cdnskeyrdata = DNS_RDATA_INIT; dns_name_t *origin = dst_key_name(key->key); @@ -1918,69 +1918,83 @@ dns_dnssec_syncupdate(dns_dnsseckeylist_t *keys, dns_dnsseckeylist_t *rmkeys, &cdnskeyrdata)); /* + * We construct the SHA-1 version of the record so we can + * delete any old records generated by previous versions of + * BIND. We only add SHA-256 records. + * * XXXMPA we need to be able to specify the DS algorithms * to be used here and below with rmkeys. */ RETERR(dns_ds_buildrdata(origin, &cdnskeyrdata, DNS_DSDIGEST_SHA1, dsbuf1, - &cdsrdata1)); + &cds_sha1)); RETERR(dns_ds_buildrdata(origin, &cdnskeyrdata, DNS_DSDIGEST_SHA256, dsbuf2, - &cdsrdata2)); + &cds_sha256)); /* * Now that the we have created the DS records convert * the rdata to CDNSKEY and CDS for comparison. */ cdnskeyrdata.type = dns_rdatatype_cdnskey; - cdsrdata1.type = dns_rdatatype_cds; - cdsrdata2.type = dns_rdatatype_cds; + cds_sha1.type = dns_rdatatype_cds; + cds_sha256.type = dns_rdatatype_cds; if (syncpublish(key->key, now)) { if (!dns_rdataset_isassociated(cdnskey) || !exists(cdnskey, &cdnskeyrdata)) + { RETERR(publish(&cdnskeyrdata, diff, origin, ttl, mctx)); + } + /* Only publish SHA-256 (SHA-1 is deprecated) */ if (!dns_rdataset_isassociated(cds) || - !exists(cds, &cdsrdata1)) - RETERR(publish(&cdsrdata1, diff, origin, - ttl, mctx)); - if (!dns_rdataset_isassociated(cds) || - !exists(cds, &cdsrdata2)) - RETERR(publish(&cdsrdata2, diff, origin, + !exists(cds, &cds_sha256)) + { + RETERR(publish(&cds_sha256, diff, origin, ttl, mctx)); + } } if (dns_rdataset_isassociated(cds) && - syncdelete(key->key, now)) { - if (exists(cds, &cdsrdata1)) - RETERR(delrdata(&cdsrdata1, diff, origin, + syncdelete(key->key, now)) + { + /* Delete both SHA-1 and SHA-256 */ + if (exists(cds, &cds_sha1)) { + RETERR(delrdata(&cds_sha1, diff, origin, cds->ttl, mctx)); - if (exists(cds, &cdsrdata2)) - RETERR(delrdata(&cdsrdata2, diff, origin, + } + if (exists(cds, &cds_sha256)) { + RETERR(delrdata(&cds_sha256, diff, origin, cds->ttl, mctx)); + } } if (dns_rdataset_isassociated(cdnskey) && - syncdelete(key->key, now)) { - if (exists(cdnskey, &cdnskeyrdata)) + syncdelete(key->key, now)) + { + if (exists(cdnskey, &cdnskeyrdata)) { RETERR(delrdata(&cdnskeyrdata, diff, origin, cdnskey->ttl, mctx)); + } } } if (!dns_rdataset_isassociated(cds) && !dns_rdataset_isassociated(cdnskey)) + { return (ISC_R_SUCCESS); + } /* * Unconditionaly remove CDS/DNSKEY records for removed keys. */ for (key = ISC_LIST_HEAD(*rmkeys); key != NULL; - key = ISC_LIST_NEXT(key, link)) { - dns_rdata_t cdsrdata1 = DNS_RDATA_INIT; - dns_rdata_t cdsrdata2 = DNS_RDATA_INIT; + key = ISC_LIST_NEXT(key, link)) + { + dns_rdata_t cds_sha1 = DNS_RDATA_INIT; + dns_rdata_t cds_sha256 = DNS_RDATA_INIT; dns_rdata_t cdnskeyrdata = DNS_RDATA_INIT; dns_name_t *origin = dst_key_name(key->key); @@ -1990,22 +2004,25 @@ dns_dnssec_syncupdate(dns_dnsseckeylist_t *keys, dns_dnsseckeylist_t *rmkeys, if (dns_rdataset_isassociated(cds)) { RETERR(dns_ds_buildrdata(origin, &cdnskeyrdata, DNS_DSDIGEST_SHA1, dsbuf1, - &cdsrdata1)); + &cds_sha1)); RETERR(dns_ds_buildrdata(origin, &cdnskeyrdata, DNS_DSDIGEST_SHA256, dsbuf2, - &cdsrdata2)); - if (exists(cds, &cdsrdata1)) - RETERR(delrdata(&cdsrdata1, diff, origin, + &cds_sha256)); + if (exists(cds, &cds_sha1)) { + RETERR(delrdata(&cds_sha1, diff, origin, cds->ttl, mctx)); - if (exists(cds, &cdsrdata2)) - RETERR(delrdata(&cdsrdata2, diff, origin, + } + if (exists(cds, &cds_sha256)) { + RETERR(delrdata(&cds_sha256, diff, origin, cds->ttl, mctx)); + } } if (dns_rdataset_isassociated(cdnskey)) { - if (exists(cdnskey, &cdnskeyrdata)) + if (exists(cdnskey, &cdnskeyrdata)) { RETERR(delrdata(&cdnskeyrdata, diff, origin, cdnskey->ttl, mctx)); + } } }