From 796a6c4e4e5872a85289097ee1e7f5eaed16c8a6 Mon Sep 17 00:00:00 2001 From: Tony Finch Date: Thu, 31 Jan 2019 17:05:57 +0000 Subject: [PATCH] Deprecate SHA-1 in `dnssec-dsfromkey` This makes the `-12a` options to `dnssec-dsfromkey` work more like `dnssec-cds`, in that you can specify more than one digest and you will get multiple records. (Previously you could only get one non-default digest type at a time.) The default is now `-2`. You can get the old behaviour with `-12`. Tests and tools that use `dnssec-dsfromkey` have been updated to use `-12` where necessary. This is for conformance with the DS/CDS algorithm requirements in https://tools.ietf.org/html/draft-ietf-dnsop-algorithm-update --- bin/dnssec/dnssec-cds.c | 36 +--------- bin/dnssec/dnssec-dsfromkey.c | 104 ++++++++++++++++------------ bin/dnssec/dnssec-dsfromkey.docbook | 10 ++- bin/dnssec/dnssectool.c | 27 ++++++++ bin/dnssec/dnssectool.h | 16 ++++- bin/python/isc/checkds.py.in | 4 +- bin/tests/system/cds/setup.sh | 2 +- bin/tests/system/dnssec/tests.sh | 10 +-- 8 files changed, 117 insertions(+), 92 deletions(-) diff --git a/bin/dnssec/dnssec-cds.c b/bin/dnssec/dnssec-cds.c index 198ebcf959..ba54acbd8a 100644 --- a/bin/dnssec/dnssec-cds.c +++ b/bin/dnssec/dnssec-cds.c @@ -75,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 */ @@ -831,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) @@ -1147,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 1fdded5ebb..5ea294b93e 100644 --- a/bin/dnssec/dnssec-dsfromkey.c +++ b/bin/dnssec/dnssec-dsfromkey.c @@ -228,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; @@ -254,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"); @@ -305,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; @@ -343,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; @@ -355,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(); @@ -373,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) @@ -453,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); @@ -478,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]; @@ -517,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/dnssectool.c b/bin/dnssec/dnssectool.c index 5cfd8e74d6..e1205d05f8 100644 --- a/bin/dnssec/dnssectool.c +++ b/bin/dnssec/dnssectool.c @@ -58,6 +58,7 @@ #include "dnssectool.h" int verbose; +uint8_t dtype[8]; static fatalcallback_t *fatalcallback = NULL; @@ -343,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 16533669a6..e4798e8336 100644 --- a/bin/dnssec/dnssectool.h +++ b/bin/dnssec/dnssectool.h @@ -31,6 +31,15 @@ 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 @@ -65,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/isc/checkds.py.in b/bin/python/isc/checkds.py.in index b5cbe3fd05..1f1963f3ae 100644 --- a/bin/python/isc/checkds.py.in +++ b/bin/python/isc/checkds.py.in @@ -115,7 +115,7 @@ def check(zone, args): klist = [] if args.masterfile: - cmd = [args.dsfromkey, "-f", args.masterfile] + cmd = [args.dsfromkey, "-12f", args.masterfile] if args.lookaside: cmd += ["-l", args.lookaside] cmd.append(zone) @@ -123,7 +123,7 @@ def check(zone, args): else: intods, _ = Popen([args.dig, "+noall", "+answer", "-t", "dnskey", "-q", zone], stdout=PIPE).communicate() - cmd = [args.dsfromkey, "-f", "-"] + cmd = [args.dsfromkey, "-12f", "-"] if args.lookaside: cmd += ["-l", args.lookaside] cmd.append(zone) 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/dnssec/tests.sh b/bin/tests/system/dnssec/tests.sh index 4cf69f0beb..5dc48d7cf8 100644 --- a/bin/tests/system/dnssec/tests.sh +++ b/bin/tests/system/dnssec/tests.sh @@ -2752,7 +2752,7 @@ status=$((status+ret)) echo_i "check dnssec-dsfromkey from stdin ($n)" ret=0 dig_with_opts dnskey algroll. @10.53.0.2 | \ - $DSFROMKEY -f - algroll. > dig.out.ns2.test$n || ret=1 + $DSFROMKEY -12 -f - algroll. > dig.out.ns2.test$n || ret=1 NF=$(awk '{print NF}' dig.out.ns2.test$n | sort -u) [ "${NF}" = 7 ] || ret=1 # make canonical @@ -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