From 553ead32ff5b00284e574dcabc39115d4d74ec66 Mon Sep 17 00:00:00 2001 From: Evan Hunt Date: Sun, 19 Jul 2009 04:18:05 +0000 Subject: [PATCH] 2636. [func] Simplify zone signing and key maintenance with the dnssec-* tools. Major changes: - all dnssec-* tools now take a -K option to specify a directory in which key files will be stored - DNSSEC can now store metadata indicating when they are scheduled to be published, acttivated, revoked or removed; these values can be set by dnssec-keygen or overwritten by the new dnssec-settime command - dnssec-signzone -S (for "smart") option reads key metadata and uses it to determine automatically which keys to publish to the zone, use for signing, revoke, or remove from the zone [RT #19816] --- CHANGES | 18 + README | 38 +- bin/dig/dighost.c | 9 +- bin/dnssec/Makefile.in | 15 +- bin/dnssec/dnssec-dsfromkey.c | 242 ++++++---- bin/dnssec/dnssec-dsfromkey.docbook | 52 ++- bin/dnssec/dnssec-keyfromlabel.c | 18 +- bin/dnssec/dnssec-keyfromlabel.docbook | 12 +- bin/dnssec/dnssec-keygen.c | 246 +++++++--- bin/dnssec/dnssec-keygen.docbook | 171 ++++++- bin/dnssec/dnssec-revoke.c | 16 +- bin/dnssec/dnssec-revoke.docbook | 6 +- bin/dnssec/dnssec-settime.8 | 84 ++++ bin/dnssec/dnssec-settime.c | 272 +++++++++++ bin/dnssec/dnssec-settime.docbook | 228 ++++++++++ bin/dnssec/dnssec-settime.html | 140 ++++++ bin/dnssec/dnssec-signzone.c | 601 ++++++++++++++++++------- bin/dnssec/dnssec-signzone.docbook | 132 +++++- bin/dnssec/dnssectool.c | 56 ++- bin/nsupdate/nsupdate.c | 4 +- bin/tests/system/dnssec/ns1/sign.sh | 8 +- bin/tests/system/dnssec/ns2/sign.sh | 4 +- bin/tests/system/tkey/keycreate.c | 4 +- bin/tests/system/tkey/keydelete.c | 4 +- bin/tests/system/tkey/ns1/setup.sh | 4 +- bin/tests/system/tkey/tests.sh | 4 +- doc/arm/Bv9ARM-book.xml | 3 +- lib/dns/db.c | 11 +- lib/dns/dnssec.c | 208 ++++++++- lib/dns/dst_api.c | 106 ++++- lib/dns/dst_internal.h | 9 +- lib/dns/dst_parse.c | 112 ++++- lib/dns/dst_parse.h | 11 +- lib/dns/include/dns/db.h | 6 +- lib/dns/include/dns/dnssec.h | 82 +++- lib/dns/include/dns/types.h | 4 +- lib/dns/include/dst/dst.h | 45 +- lib/dns/opensslrsa_link.c | 5 +- version | 4 +- 39 files changed, 2499 insertions(+), 495 deletions(-) create mode 100644 bin/dnssec/dnssec-settime.8 create mode 100644 bin/dnssec/dnssec-settime.c create mode 100644 bin/dnssec/dnssec-settime.docbook create mode 100644 bin/dnssec/dnssec-settime.html diff --git a/CHANGES b/CHANGES index e4f611b740..a1f785ff96 100644 --- a/CHANGES +++ b/CHANGES @@ -1,3 +1,21 @@ + --- 9.7.0a2 released --- + +2636. [func] Simplify zone signing and key maintenance with the + dnssec-* tools. Major changes: + - all dnssec-* tools now take a -K option to + specify a directory in which key files will be + stored + - DNSSEC can now store metadata indicating when + they are scheduled to be published, acttivated, + revoked or removed; these values can be set by + dnssec-keygen or overwritten by the new + dnssec-settime command + - dnssec-signzone -S (for "smart") option reads key + metadata and uses it to determine automatically + which keys to publish to the zone, use for + signing, revoke, or remove from the zone + [RT #19816] + 2635. [bug] isc_inet_ntop() incorrectly handled 0.0/16 addresses. [RT #19716] diff --git a/README b/README index a613a31bbd..51dd578120 100644 --- a/README +++ b/README @@ -44,28 +44,34 @@ BIND 9 BIND 9.7.0 - BIND 9.7.0 includes a number of changes from BIND 9.6 and earlier - releases. Most are intended to simplify DNSSEC configuration. - New features include: + BIND 9.7.0 includes a number of changes from BIND 9.6 and earlier + releases. Most are intended to simplify DNSSEC configuration. - - Simplified configuration of DNSSEC Lookaside Validation (DLV). - - Simplified configuration of Dynamic DNS, using the "ddns-confgen" - command line tool or the "ddns-autoconf" zone option. (As a side - effect, this also makes it easier to configure automatic zone - re-signing.) + Please note that configuration syntax and APIs for new features + are still experimental and are subject to change before the final + release. + + New features include: + + - Simplified configuration of DNSSEC Lookaside Validation (DLV). + - Simplified configuration of Dynamic DNS, using the "ddns-confgen" + command line tool or the "local" update-policy option. (As a side + effect, this also makes it easier to configure automatic zone + re-signing.) - New named option "attach-cache" that allows multiple views to share a single cache. - - New logging category "query-errors" to provide detailed - internal information about query failures, especially about - server failures. - DNS rebinding attack prevention. - - New default values for dnssec-keygen parameters. + - New default values for dnssec-keygen parameters. + - Support for RFC 5011 (automated trust anchor maintenance) + - Smart signing: simplified tools for zone signing and key + maintenance + - The "statistics-channels" option is now available on Windows - Planned but not complete in alpha: + Planned but not complete in this alpha: - - Support for RFC 5011 (automated trust anchor maintenance) - - Simplified tools for zone signing and key maintenance - - Fully automatic signing of zones by "named" + - Fully automatic signing of zones by "named" + - DNSSEC-aware libdns API + - Improved PKCS#11 support, including Keyper support BIND 9.6.0 diff --git a/bin/dig/dighost.c b/bin/dig/dighost.c index 295a0f3b63..271f806e49 100644 --- a/bin/dig/dighost.c +++ b/bin/dig/dighost.c @@ -15,7 +15,7 @@ * PERFORMANCE OF THIS SOFTWARE. */ -/* $Id: dighost.c,v 1.322 2009/06/24 02:51:29 marka Exp $ */ +/* $Id: dighost.c,v 1.323 2009/07/19 04:18:03 each Exp $ */ /*! \file * \note @@ -948,8 +948,9 @@ setup_file_key(void) { dst_key_t *dstkey = NULL; debug("setup_file_key()"); - result = dst_key_fromnamedfile(keyfile, DST_TYPE_PRIVATE | DST_TYPE_KEY, - mctx, &dstkey); + result = dst_key_fromnamedfile(keyfile, NULL, + DST_TYPE_PRIVATE | DST_TYPE_KEY, mctx, + &dstkey); if (result != ISC_R_SUCCESS) { fprintf(stderr, "Couldn't read key from %s: %s\n", keyfile, isc_result_totext(result)); @@ -4051,7 +4052,7 @@ get_trusted_key(isc_mem_t *mctx) return (ISC_R_FAILURE); } fclose(fptemp); - result = dst_key_fromnamedfile(filetemp, DST_TYPE_PUBLIC, + result = dst_key_fromnamedfile(filetemp, NULL, DST_TYPE_PUBLIC, mctx, &key); removetmpkey(mctx, filetemp); isc_mem_free(mctx, filetemp); diff --git a/bin/dnssec/Makefile.in b/bin/dnssec/Makefile.in index 9207281106..af6f3a556f 100644 --- a/bin/dnssec/Makefile.in +++ b/bin/dnssec/Makefile.in @@ -13,7 +13,7 @@ # OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR # PERFORMANCE OF THIS SOFTWARE. -# $Id: Makefile.in,v 1.37 2009/07/01 23:47:36 tbox Exp $ +# $Id: Makefile.in,v 1.38 2009/07/19 04:18:04 each Exp $ srcdir = @srcdir@ VPATH = @srcdir@ @@ -41,18 +41,19 @@ LIBS = ${DNSLIBS} ${ISCLIBS} @LIBS@ # Alphabetically TARGETS = dnssec-keygen@EXEEXT@ dnssec-signzone@EXEEXT@ \ dnssec-keyfromlabel@EXEEXT@ dnssec-dsfromkey@EXEEXT@ \ - dnssec-revoke@EXEEXT@ + dnssec-revoke@EXEEXT@ dnssec-settime@EXEEXT@ OBJS = dnssectool.@O@ SRCS = dnssec-dsfromkey.c dnssec-keyfromlabel.c dnssec-keygen.c \ - dnssec-revoke.c dnssec-signzone.c dnssectool.c + dnssec-revoke.c dnssec-settime.c dnssec-signzone.c dnssectool.c MANPAGES = dnssec-dsfromkey.8 dnssec-keyfromlabel.8 dnssec-keygen.8 \ - dnssec-revoke.8 dnssec-signzone.8 + dnssec-revoke.8 dnssec-settime.8 dnssec-signzone.8 HTMLPAGES = dnssec-dsfromkey.html dnssec-keyfromlabel.html \ - dnssec-keygen.html dnssec-revoke.html dnssec-signzone.html + dnssec-keygen.html dnssec-revoke.html \ + dnssec-settime.html dnssec-signzone.html MANOBJS = ${MANPAGES} ${HTMLPAGES} @@ -82,6 +83,10 @@ dnssec-revoke@EXEEXT@: dnssec-revoke.@O@ ${OBJS} ${DEPLIBS} ${LIBTOOL_MODE_LINK} ${PURIFY} ${CC} ${CFLAGS} ${LDFLAGS} -o $@ \ dnssec-revoke.@O@ ${OBJS} ${LIBS} +dnssec-settime@EXEEXT@: dnssec-settime.@O@ ${OBJS} ${DEPLIBS} + ${LIBTOOL_MODE_LINK} ${PURIFY} ${CC} ${CFLAGS} ${LDFLAGS} -o $@ \ + dnssec-settime.@O@ ${OBJS} ${LIBS} + doc man:: ${MANOBJS} docclean manclean maintainer-clean:: diff --git a/bin/dnssec/dnssec-dsfromkey.c b/bin/dnssec/dnssec-dsfromkey.c index a92b742443..c00f9860d9 100644 --- a/bin/dnssec/dnssec-dsfromkey.c +++ b/bin/dnssec/dnssec-dsfromkey.c @@ -14,7 +14,7 @@ * PERFORMANCE OF THIS SOFTWARE. */ -/* $Id: dnssec-dsfromkey.c,v 1.8 2009/06/17 23:53:04 tbox Exp $ */ +/* $Id: dnssec-dsfromkey.c,v 1.9 2009/07/19 04:18:04 each Exp $ */ /*! \file */ @@ -36,6 +36,8 @@ #include #include #include +#include +#include #include #include #include @@ -48,54 +50,40 @@ #include "dnssectool.h" +#ifndef PATH_MAX +#define PATH_MAX 1024 /* AIX and others don't define this. */ +#endif + const char *program = "dnssec-dsfromkey"; int verbose; static dns_rdataclass_t rdclass; static dns_fixedname_t fixed; static dns_name_t *name = NULL; -static dns_db_t *db = NULL; -static dns_dbnode_t *node = NULL; -static dns_rdataset_t keyset; static isc_mem_t *mctx = NULL; -static void -loadkeys(char *dirname, char *setname) -{ +static isc_result_t +initname(char *setname) { + isc_result_t result; + isc_buffer_t buf; + + dns_fixedname_init(&fixed); + name = dns_fixedname_name(&fixed); + + isc_buffer_init(&buf, setname, strlen(setname)); + isc_buffer_add(&buf, strlen(setname)); + result = dns_name_fromtext(name, &buf, dns_rootname, ISC_FALSE, NULL); + return (result); +} + +static isc_result_t +loadsetfromfile(char *filename, dns_rdataset_t *rdataset) { isc_result_t result; - char filename[1024]; - isc_buffer_t buf; + dns_db_t *db = NULL; + dns_dbnode_t *node = NULL; + char setname[DNS_NAME_FORMATSIZE]; - dns_rdataset_init(&keyset); - dns_fixedname_init(&fixed); - name = dns_fixedname_name(&fixed); - - isc_buffer_init(&buf, setname, strlen(setname)); - isc_buffer_add(&buf, strlen(setname)); - result = dns_name_fromtext(name, &buf, dns_rootname, ISC_FALSE, NULL); - if (result != ISC_R_SUCCESS) - fatal("can't convert DNS name %s", setname); - - isc_buffer_init(&buf, filename, sizeof(filename)); - if (dirname != NULL) { - if (isc_buffer_availablelength(&buf) < strlen(dirname)) - fatal("directory name '%s' too long", dirname); - isc_buffer_putstr(&buf, dirname); - if (dirname[strlen(dirname) - 1] != '/') { - if (isc_buffer_availablelength(&buf) < 1) - fatal("directory name '%s' too long", dirname); - isc_buffer_putstr(&buf, "/"); - } - } - - if (isc_buffer_availablelength(&buf) < strlen("keyset-")) - fatal("directory name '%s' too long", dirname); - isc_buffer_putstr(&buf, "keyset-"); - result = dns_name_tofilenametext(name, ISC_FALSE, &buf); - check_result(result, "dns_name_tofilenametext()"); - if (isc_buffer_availablelength(&buf) == 0) - fatal("name %s too long", setname); - isc_buffer_putuint8(&buf, 0); + dns_name_format(name, setname, sizeof(setname)); result = dns_db_create(mctx, "rbt", name, dns_dbtype_zone, rdclass, 0, NULL, &db); @@ -111,11 +99,49 @@ loadkeys(char *dirname, char *setname) fatal("can't find %s node in %s", setname, filename); result = dns_db_findrdataset(db, node, NULL, dns_rdatatype_dnskey, - 0, 0, &keyset, NULL); + 0, 0, rdataset, NULL); + if (result == ISC_R_NOTFOUND) fatal("no DNSKEY RR for %s in %s", setname, filename); else if (result != ISC_R_SUCCESS) fatal("dns_db_findrdataset"); + + if (node != NULL) + dns_db_detachnode(db, &node); + if (db != NULL) + dns_db_detach(&db); + return (result); +} + +static isc_result_t +loadkeyset(char *dirname, dns_rdataset_t *rdataset) { + isc_result_t result; + char filename[PATH_MAX + 1]; + isc_buffer_t buf; + + dns_rdataset_init(rdataset); + + isc_buffer_init(&buf, filename, sizeof(filename)); + if (dirname != NULL) { + /* allow room for a trailing slash */ + if (strlen(dirname) >= isc_buffer_availablelength(&buf)) + return (ISC_R_NOSPACE); + isc_buffer_putstr(&buf, dirname); + if (dirname[strlen(dirname) - 1] != '/') + isc_buffer_putstr(&buf, "/"); + } + + if (isc_buffer_availablelength(&buf) < 7) + return (ISC_R_NOSPACE); + isc_buffer_putstr(&buf, "keyset-"); + + result = dns_name_tofilenametext(name, ISC_FALSE, &buf); + check_result(result, "dns_name_tofilenametext()"); + if (isc_buffer_availablelength(&buf) == 0) + return (ISC_R_NOSPACE); + isc_buffer_putuint8(&buf, 0); + + return (loadsetfromfile(filename, rdataset)); } static void @@ -127,12 +153,12 @@ loadkey(char *filename, unsigned char *key_buf, unsigned int key_buf_size, isc_buffer_t keyb; isc_region_t r; - dns_rdataset_init(&keyset); dns_rdata_init(rdata); isc_buffer_init(&keyb, key_buf, key_buf_size); - result = dst_key_fromnamedfile(filename, DST_TYPE_PUBLIC, mctx, &key); + result = dst_key_fromnamedfile(filename, NULL, DST_TYPE_PUBLIC, + mctx, &key); if (result != ISC_R_SUCCESS) fatal("invalid keyfile name %s: %s", filename, isc_result_totext(result)); @@ -184,16 +210,18 @@ logkey(dns_rdata_t *rdata) } static void -emit(unsigned int dtype, dns_rdata_t *rdata, char *lookaside) +emit(unsigned int dtype, isc_boolean_t showall, char *lookaside, + dns_rdata_t *rdata) { - isc_result_t result; - unsigned char buf[DNS_DS_BUFFERSIZE]; - char text_buf[DST_KEY_MAXTEXTSIZE]; - char name_buf[DNS_NAME_MAXWIRE]; - char class_buf[10]; - isc_buffer_t textb, nameb, classb; - isc_region_t r; - dns_rdata_t ds; + isc_result_t result; + unsigned char buf[DNS_DS_BUFFERSIZE]; + char text_buf[DST_KEY_MAXTEXTSIZE]; + char name_buf[DNS_NAME_MAXWIRE]; + char class_buf[10]; + isc_buffer_t textb, nameb, classb; + isc_region_t r; + dns_rdata_t ds; + dns_rdata_dnskey_t dnskey; isc_buffer_init(&textb, text_buf, sizeof(text_buf)); isc_buffer_init(&nameb, name_buf, sizeof(name_buf)); @@ -201,6 +229,13 @@ emit(unsigned int dtype, dns_rdata_t *rdata, char *lookaside) dns_rdata_init(&ds); + result = dns_rdata_tostruct(rdata, &dnskey, NULL); + if (result != ISC_R_SUCCESS) + fatal("can't convert DNSKEY"); + + if ((dnskey.flags & DNS_KEYFLAG_KSK) == 0 && !showall) + return; + result = dns_ds_buildrdata(name, rdata, dtype, buf, &ds); if (result != ISC_R_SUCCESS) fatal("can't build record"); @@ -250,20 +285,26 @@ emit(unsigned int dtype, dns_rdata_t *rdata, char *lookaside) static void usage(void) { fprintf(stderr, "Usage:\n"); - fprintf(stderr, " %s options keyfile\n\n", program); - fprintf(stderr, " %s options [-c class] [-d dir] [-l lookaside] -s dnsname\n\n", + fprintf(stderr, " %s options [-K dir] keyfile\n\n", program); + fprintf(stderr, " %s options [-K dir] [-c class] -s dnsname\n\n", program); + fprintf(stderr, " %s options -f zonefile (as zone name)\n\n", program); + fprintf(stderr, " %s options -f zonefile zonename\n\n", program); fprintf(stderr, "Version: %s\n", VERSION); fprintf(stderr, "Options:\n"); fprintf(stderr, " -v \n"); + fprintf(stderr, " -K : directory in which to find " + "key file or keyset file\n"); + fprintf(stderr, " -a algorithm: digest algorithm " + "(SHA-1 or SHA-256)\n"); fprintf(stderr, " -1: use SHA-1\n"); fprintf(stderr, " -2: use SHA-256\n"); - fprintf(stderr, " -a algorithm: use algorithm\n"); - fprintf(stderr, "Keyset options:\n"); - fprintf(stderr, " -s: keyset mode\n"); fprintf(stderr, " -l: add lookaside zone and print DLV records\n"); - fprintf(stderr, " -c class\n"); - fprintf(stderr, " -d directory\n"); + fprintf(stderr, " -s: read keyset from keyset- file\n"); + fprintf(stderr, " -c class: rdata class for DS set (default: IN)\n"); + fprintf(stderr, " -f file: read keyset from zone file\n"); + fprintf(stderr, " -A: when used with -f, " + "include all keys in DS set, not just KSKs\n"); fprintf(stderr, "Output: DS or DLV RRs\n"); exit (-1); @@ -271,16 +312,19 @@ usage(void) { int main(int argc, char **argv) { - char *algname = NULL, *classname = NULL, *dirname = NULL; + char *algname = NULL, *classname = NULL; + char *filename = NULL, *dir = NULL, *namestr; char *lookaside = NULL; char *endp; int ch; unsigned int dtype = DNS_DSDIGEST_SHA1; isc_boolean_t both = ISC_TRUE; isc_boolean_t usekeyset = ISC_FALSE; + isc_boolean_t showall = ISC_FALSE; isc_result_t result; - isc_log_t *log = NULL; + isc_log_t *log = NULL; isc_entropy_t *ectx = NULL; + dns_rdataset_t rdataset; dns_rdata_t rdata; dns_rdata_init(&rdata); @@ -297,7 +341,7 @@ main(int argc, char **argv) { isc_commandline_errprint = ISC_FALSE; while ((ch = isc_commandline_parse(argc, argv, - "12a:c:d:l:sv:Fh")) != -1) { + "12Aa:c:d:Ff:K:l:sv:h")) != -1) { switch (ch) { case '1': dtype = DNS_DSDIGEST_SHA1; @@ -307,6 +351,9 @@ main(int argc, char **argv) { dtype = DNS_DSDIGEST_SHA256; both = ISC_FALSE; break; + case 'A': + showall = ISC_TRUE; + break; case 'a': algname = isc_commandline_argument; both = ISC_FALSE; @@ -315,9 +362,16 @@ main(int argc, char **argv) { classname = isc_commandline_argument; break; case 'd': - dirname = isc_commandline_argument; - if (strlen(dirname) == 0) - fatal("dir must be a non-empty string"); + fprintf(stderr, "%s: the -d option is deprecated; " + "use -K\n", program); + /* fall through */ + case 'K': + dir = isc_commandline_argument; + if (strlen(dir) == 0) + fatal("directory must be non-empty string"); + break; + case 'f': + filename = isc_commandline_argument; break; case 'l': lookaside = isc_commandline_argument; @@ -363,7 +417,14 @@ main(int argc, char **argv) { rdclass = strtoclass(classname); - if (argc < isc_commandline_index + 1) + if (usekeyset && filename != NULL) + fatal("cannot use both -s and -f"); + + /* When not using -f, -A is implicit */ + if (filename == NULL) + showall = ISC_TRUE; + + if (argc < isc_commandline_index + 1 && filename == NULL) fatal("the key file name was not specified"); if (argc > isc_commandline_index + 1) fatal("extraneous arguments"); @@ -381,23 +442,44 @@ main(int argc, char **argv) { setup_logging(verbose, mctx, &log); - if (usekeyset) { - loadkeys(dirname, argv[isc_commandline_index]); + dns_rdataset_init(&rdataset); - for (result = dns_rdataset_first(&keyset); + if (usekeyset || filename != NULL) { + if (argc < isc_commandline_index + 1 && filename != NULL) { + /* using zone name as the zone file name */ + namestr = filename; + } else + namestr = argv[isc_commandline_index]; + + result = initname(namestr); + if (result != ISC_R_SUCCESS) + fatal("could not initialize name %s", namestr); + + if (usekeyset) + result = loadkeyset(dir, &rdataset); + else + result = loadsetfromfile(filename, &rdataset); + + 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(&keyset)) { + result = dns_rdataset_next(&rdataset)) { dns_rdata_init(&rdata); - dns_rdataset_current(&keyset, &rdata); + dns_rdataset_current(&rdataset, &rdata); if (verbose > 2) logkey(&rdata); if (both) { - emit(DNS_DSDIGEST_SHA1, &rdata, lookaside); - emit(DNS_DSDIGEST_SHA256, &rdata, lookaside); + emit(DNS_DSDIGEST_SHA1, showall, lookaside, + &rdata); + emit(DNS_DSDIGEST_SHA256, showall, lookaside, + &rdata); } else - emit(dtype, &rdata, lookaside); + emit(dtype, showall, lookaside, &rdata); } } else { unsigned char key_buf[DST_KEY_MAXSIZE]; @@ -406,18 +488,14 @@ main(int argc, char **argv) { DST_KEY_MAXSIZE, &rdata); if (both) { - emit(DNS_DSDIGEST_SHA1, &rdata, lookaside); - emit(DNS_DSDIGEST_SHA256, &rdata, lookaside); + emit(DNS_DSDIGEST_SHA1, showall, lookaside, &rdata); + emit(DNS_DSDIGEST_SHA256, showall, lookaside, &rdata); } else - emit(dtype, &rdata, lookaside); + emit(dtype, showall, lookaside, &rdata); } - if (dns_rdataset_isassociated(&keyset)) - dns_rdataset_disassociate(&keyset); - if (node != NULL) - dns_db_detachnode(db, &node); - if (db != NULL) - dns_db_detach(&db); + if (dns_rdataset_isassociated(&rdataset)) + dns_rdataset_disassociate(&rdataset); cleanup_logging(&log); dst_lib_destroy(); isc_hash_destroy(); diff --git a/bin/dnssec/dnssec-dsfromkey.docbook b/bin/dnssec/dnssec-dsfromkey.docbook index bd8f468b4d..7f777b7645 100644 --- a/bin/dnssec/dnssec-dsfromkey.docbook +++ b/bin/dnssec/dnssec-dsfromkey.docbook @@ -17,7 +17,7 @@ - PERFORMANCE OF THIS SOFTWARE. --> - + November 29, 2008 @@ -54,12 +54,15 @@ dnssec-dsfromkey -s - + + - + + + dnsname @@ -107,10 +110,35 @@ - -v level + -K directory - Sets the debugging level. + Look for key files (or, in keyset mode, + keyset- files) in + . + + + + + + -f file + + + Zone file mode: in place of the keyfile name, the argument is + the DNS domain name of a zone master file, which can be read + from . If the zone name is the same as + , then it may be omitted. + + + + + + -A + + + Include ZSK's when generating DS records. Without this option, + only keys which have the KSK flag set will be converted to DS + records and printed. Useful only in zone file mode. @@ -131,8 +159,7 @@ Keyset mode: in place of the keyfile name, the argument is - the DNS domain name of a keyset file. Following options make sense - only in this mode. + the DNS domain name of a keyset file. @@ -141,23 +168,20 @@ -c class - Specifies the DNS class (default is IN), useful only - in the keyset mode. + Specifies the DNS class (default is IN). Useful only + in keyset or zone file mode. - -d directory + -v level - Look for keyset files in - as the directory, ignored when - not in the keyset mode. + Sets the debugging level. - diff --git a/bin/dnssec/dnssec-keyfromlabel.c b/bin/dnssec/dnssec-keyfromlabel.c index 130bc1f3f0..02bba62a11 100644 --- a/bin/dnssec/dnssec-keyfromlabel.c +++ b/bin/dnssec/dnssec-keyfromlabel.c @@ -14,7 +14,7 @@ * PERFORMANCE OF THIS SOFTWARE. */ -/* $Id: dnssec-keyfromlabel.c,v 1.8 2009/06/30 23:48:00 tbox Exp $ */ +/* $Id: dnssec-keyfromlabel.c,v 1.9 2009/07/19 04:18:04 each Exp $ */ /*! \file */ @@ -65,6 +65,8 @@ usage(void) { fprintf(stderr, " (DNSKEY generation defaults to ZONE\n"); fprintf(stderr, " -c (default: IN)\n"); fprintf(stderr, " -f keyflag (KSK or REVOKE)\n"); + fprintf(stderr, " -K directory: directory in which to place " + "key files\n"); fprintf(stderr, " -t : " "AUTHCONF | NOAUTHCONF | NOAUTH | NOCONF " "(default: AUTHCONF)\n"); @@ -82,6 +84,7 @@ usage(void) { int main(int argc, char **argv) { char *algname = NULL, *nametype = NULL, *type = NULL; + char *directory = NULL; char *classname = NULL; char *endp; dst_key_t *key = NULL, *oldkey; @@ -113,7 +116,7 @@ main(int argc, char **argv) { isc_commandline_errprint = ISC_FALSE; while ((ch = isc_commandline_parse(argc, argv, - "a:c:f:kl:n:p:t:v:Fh")) != -1) + "a:c:f:K:kl:n:p:t:v:Fh")) != -1) { switch (ch) { case 'a': @@ -132,6 +135,9 @@ main(int argc, char **argv) { fatal("unknown flag '%s'", isc_commandline_argument); break; + case 'K': + directory = isc_commandline_argument; + break; case 'k': options |= DST_TYPE_KEY; break; @@ -299,18 +305,18 @@ main(int argc, char **argv) { * case we return failure. */ ret = dst_key_fromfile(name, dst_key_id(key), alg, - DST_TYPE_PRIVATE, NULL, mctx, &oldkey); + DST_TYPE_PRIVATE, directory, mctx, &oldkey); /* do not overwrite an existing key */ if (ret == ISC_R_SUCCESS) { isc_buffer_clear(&buf); - ret = dst_key_buildfilename(key, 0, NULL, &buf); + ret = dst_key_buildfilename(key, 0, directory, &buf); fprintf(stderr, "%s: %s already exists\n", program, filename); dst_key_free(&key); exit (1); } - ret = dst_key_tofile(key, options, NULL); + ret = dst_key_tofile(key, options, directory); if (ret != ISC_R_SUCCESS) { char keystr[KEY_FORMATSIZE]; key_format(key, keystr, sizeof(keystr)); @@ -319,7 +325,7 @@ main(int argc, char **argv) { } isc_buffer_clear(&buf); - ret = dst_key_buildfilename(key, 0, NULL, &buf); + ret = dst_key_buildfilename(key, 0, directory, &buf); printf("%s\n", filename); dst_key_free(&key); diff --git a/bin/dnssec/dnssec-keyfromlabel.docbook b/bin/dnssec/dnssec-keyfromlabel.docbook index 2bcf0a48da..f7af284dff 100644 --- a/bin/dnssec/dnssec-keyfromlabel.docbook +++ b/bin/dnssec/dnssec-keyfromlabel.docbook @@ -17,7 +17,7 @@ - PERFORMANCE OF THIS SOFTWARE. --> - + February 8, 2008 @@ -49,6 +49,7 @@ + @@ -144,6 +145,15 @@ + + -K directory + + + Sets the directory in which the key files are to be written. + + + + -k diff --git a/bin/dnssec/dnssec-keygen.c b/bin/dnssec/dnssec-keygen.c index 546b2c5020..454bce9f81 100644 --- a/bin/dnssec/dnssec-keygen.c +++ b/bin/dnssec/dnssec-keygen.c @@ -29,12 +29,13 @@ * IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ -/* $Id: dnssec-keygen.c,v 1.87 2009/06/30 23:48:00 tbox Exp $ */ +/* $Id: dnssec-keygen.c,v 1.88 2009/07/19 04:18:04 each Exp $ */ /*! \file */ #include +#include #include #include @@ -62,10 +63,8 @@ const char *program = "dnssec-keygen"; int verbose; -static const char *algs = "RSA | RSAMD5 | DH | DSA | RSASHA1 | NSEC3DSA |" - " NSEC3RSASHA1 | HMAC-MD5 |" - " HMAC-SHA1 | HMAC-SHA224 | HMAC-SHA256 |" - " HMAC-SHA384 | HMAC-SHA512"; +#define DEFAULT_ALGORITHM "RSASHA1" +#define DEFAULT_NSEC3_ALGORITHM "NSEC3RSASHA1" #define DEFAULT_ALGORITHM "RSASHA1" @@ -77,47 +76,71 @@ dsa_size_ok(int size) { static void usage(void) { fprintf(stderr, "Usage:\n"); - fprintf(stderr, " %s [options] name\n\n", - program); + fprintf(stderr, " %s [options] name\n\n", program); fprintf(stderr, "Version: %s\n", VERSION); fprintf(stderr, " name: owner of the key\n"); fprintf(stderr, "Options:\n"); - fprintf(stderr, " -a algorithm: %s (default RSASHA1)\n", algs); - fprintf(stderr, " -b key size, in bits:\n"); - fprintf(stderr, " RSAMD5:\t\t[512..%d]\n", MAX_RSA); - fprintf(stderr, " RSASHA1:\t\t[512..%d]\n", MAX_RSA); - fprintf(stderr, " NSEC3RSASHA1:\t\t[512..%d]\n", MAX_RSA); - fprintf(stderr, " DH:\t\t[128..4096]\n"); - fprintf(stderr, " DSA:\t\t[512..1024] and divisible by 64\n"); - fprintf(stderr, " NSEC3DSA:\t\t[512..1024] and divisible by 64\n"); - fprintf(stderr, " HMAC-MD5:\t[1..512]\n"); - fprintf(stderr, " HMAC-SHA1:\t[1..160]\n"); - fprintf(stderr, " HMAC-SHA224:\t[1..224]\n"); - fprintf(stderr, " HMAC-SHA256:\t[1..256]\n"); - fprintf(stderr, " HMAC-SHA384:\t[1..384]\n"); - fprintf(stderr, " HMAC-SHA512:\t[1..512]\n"); - fprintf(stderr, " (default 1024 for RSASHA1 ZSK, 2048 for KSK\n"); - fprintf(stderr, " -n nametype: ZONE | HOST | ENTITY | USER | OTHER\n"); - fprintf(stderr, " (DNSKEY generation defaults to ZONE)\n"); - fprintf(stderr, " -c (default: IN)\n"); + fprintf(stderr, " -K : write keys into directory\n"); + fprintf(stderr, " -a :\n"); + fprintf(stderr, " RSA | RSAMD5 | DSA | RSASHA1 | " + "NSEC3RSASHA1 | NSEC3DSA |\n"); + fprintf(stderr, " DH | HMAC-MD5 | HMAC-SHA1 | HMAC-SHA224 | " + "HMAC-SHA256 | \n"); + fprintf(stderr, " HMAC-SHA384 | HMAC-SHA512\n"); + fprintf(stderr, " (default: RSASHA1, or " + "NSEC3RSASHA1 if using -3)\n"); + fprintf(stderr, " -3: use NSEC3-capable algorithm\n"); + fprintf(stderr, " -b :\n"); + fprintf(stderr, " RSAMD5:\t[512..%d]\n", MAX_RSA); + fprintf(stderr, " RSASHA1:\t[512..%d]\n", MAX_RSA); + fprintf(stderr, " NSEC3RSASHA1:\t[512..%d]\n", MAX_RSA); + fprintf(stderr, " DH:\t\t[128..4096]\n"); + fprintf(stderr, " DSA:\t\t[512..1024] and divisible by 64\n"); + fprintf(stderr, " NSEC3DSA:\t[512..1024] and divisible " + "by 64\n"); + fprintf(stderr, " HMAC-MD5:\t[1..512]\n"); + fprintf(stderr, " HMAC-SHA1:\t[1..160]\n"); + fprintf(stderr, " HMAC-SHA224:\t[1..224]\n"); + fprintf(stderr, " HMAC-SHA256:\t[1..256]\n"); + fprintf(stderr, " HMAC-SHA384:\t[1..384]\n"); + fprintf(stderr, " HMAC-SHA512:\t[1..512]\n"); + fprintf(stderr, " (if using the default algorithm, key size\n" + " defaults to 2048 for KSK, or 1024 for all " + "others)\n"); + fprintf(stderr, " -n : ZONE | HOST | ENTITY | " + "USER | OTHER\n"); + fprintf(stderr, " (DNSKEY generation defaults to ZONE)\n"); + fprintf(stderr, " -c : (default: IN)\n"); fprintf(stderr, " -d (0 => max, default)\n"); - fprintf(stderr, " -e use large exponent (RSAMD5/RSASHA1 only)\n"); - fprintf(stderr, " -f keyflag (KSK or REVOKE)\n"); - fprintf(stderr, " -g use specified generator " - "(DH only)\n"); + fprintf(stderr, " -e: use large exponent (RSAMD5/RSASHA1 only)\n"); + fprintf(stderr, " -f : KSK | REVOKE\n"); + fprintf(stderr, " -g : use specified generator " + "(DH only)\n"); + fprintf(stderr, " -p : (default: 3 [dnssec])\n"); + fprintf(stderr, " -s : strength value this key signs DNS " + "records with (default: 0)\n"); + fprintf(stderr, " -T : DNSKEY | KEY (default: DNSKEY; " + "use KEY for SIG(0))\n"); fprintf(stderr, " -t : " - "AUTHCONF | NOAUTHCONF | NOAUTH | NOCONF " - "(default: AUTHCONF)\n"); - fprintf(stderr, " -p : " - "default: 3 [dnssec]\n"); - fprintf(stderr, " -s strength value this key signs DNS " - "records with (default: 0)\n"); + "AUTHCONF | NOAUTHCONF | NOAUTH | NOCONF " + "(default: AUTHCONF)\n"); fprintf(stderr, " -r : a file containing random data\n"); - fprintf(stderr, " -v \n"); - fprintf(stderr, " -k : generate a TYPE=KEY key\n"); + + fprintf(stderr, " -h: print usage and exit\n"); + fprintf(stderr, " -m :\n"); + fprintf(stderr, " usage | trace | record | size | mctx\n"); + fprintf(stderr, " -v : set verbosity level (0 - 10)\n"); + fprintf(stderr, "Date options:\n"); + fprintf(stderr, " -P date/[+-]offset: set key publication date\n"); + fprintf(stderr, " -A date/[+-]offset: set key activation date\n"); + fprintf(stderr, " -R date/[+-]offset: set key revocation date\n"); + fprintf(stderr, " -U date/[+-]offset: set key unpublication date\n"); + fprintf(stderr, " -D date/[+-]offset: set key deletion date\n"); + fprintf(stderr, " -C: generate a backward-compatible key, omitting " + "dates\n"); fprintf(stderr, "Output:\n"); fprintf(stderr, " K++.key, " - "K++.private\n"); + "K++.private\n"); exit (-1); } @@ -130,36 +153,68 @@ main(int argc, char **argv) { dst_key_t *key = NULL, *oldkey; dns_fixedname_t fname; dns_name_t *name; - isc_uint16_t flags = 0, ksk = 0, revoke = 0; + isc_uint16_t flags = 0, kskflag = 0, revflag = 0; dns_secalg_t alg; isc_boolean_t conflict = ISC_FALSE, null_key = ISC_FALSE; + isc_boolean_t oldstyle = ISC_FALSE; isc_mem_t *mctx = NULL; int ch, rsa_exp = 0, generator = 0, param = 0; int protocol = -1, size = -1, signatory = 0; isc_result_t ret; isc_textregion_t r; char filename[255]; + const char *directory = NULL; isc_buffer_t buf; isc_log_t *log = NULL; isc_entropy_t *ectx = NULL; dns_rdataclass_t rdclass; int options = DST_TYPE_PRIVATE | DST_TYPE_PUBLIC; int dbits = 0; - isc_boolean_t use_default = ISC_FALSE; + isc_boolean_t use_default = ISC_FALSE, use_nsec3 = ISC_FALSE; + isc_stdtime_t publish = 0, activate = 0, revoke = 0; + isc_stdtime_t unpublish = 0, delete = 0; + isc_stdtime_t now; if (argc == 1) usage(); - RUNTIME_CHECK(isc_mem_create(0, 0, &mctx) == ISC_R_SUCCESS); - dns_result_register(); isc_commandline_errprint = ISC_FALSE; - while ((ch = isc_commandline_parse(argc, argv, - "a:b:c:d:ef:g:kn:t:p:s:r:v:Fh")) != -1) - { + /* + * Process memory debugging argument first. + */ +#define CMDLINE_FLAGS "3a:b:Cc:d:eFf:g:K:km:n:p:r:s:T:t:v:hP:A:R:U:D:" + while ((ch = isc_commandline_parse(argc, argv, CMDLINE_FLAGS)) != -1) { + switch (ch) { + case 'm': + if (strcasecmp(isc_commandline_argument, "record") == 0) + isc_mem_debugging |= ISC_MEM_DEBUGRECORD; + if (strcasecmp(isc_commandline_argument, "trace") == 0) + isc_mem_debugging |= ISC_MEM_DEBUGTRACE; + if (strcasecmp(isc_commandline_argument, "usage") == 0) + isc_mem_debugging |= ISC_MEM_DEBUGUSAGE; + if (strcasecmp(isc_commandline_argument, "size") == 0) + isc_mem_debugging |= ISC_MEM_DEBUGSIZE; + if (strcasecmp(isc_commandline_argument, "mctx") == 0) + isc_mem_debugging |= ISC_MEM_DEBUGCTX; + break; + default: + break; + } + } + isc_commandline_reset = ISC_TRUE; + + RUNTIME_CHECK(isc_mem_create(0, 0, &mctx) == ISC_R_SUCCESS); + + isc_stdtime_get(&now); + + while ((ch = isc_commandline_parse(argc, argv, CMDLINE_FLAGS)) != -1) { switch (ch) { + case '3': + use_nsec3 = ISC_TRUE; + break; case 'a': algname = isc_commandline_argument; break; @@ -168,6 +223,9 @@ main(int argc, char **argv) { if (*endp != '\0' || size < 0) fatal("-b requires a non-negative number"); break; + case 'C': + oldstyle = ISC_TRUE; + break; case 'c': classname = isc_commandline_argument; break; @@ -180,11 +238,10 @@ main(int argc, char **argv) { rsa_exp = 1; break; case 'f': - if (strcasecmp(isc_commandline_argument, "KSK") == 0) - ksk = DNS_KEYFLAG_KSK; - else if (strcasecmp(isc_commandline_argument, - "REVOKE") == 0) - revoke = DNS_KEYFLAG_REVOKE; + if (toupper(isc_commandline_argument[0]) == 'K') + kskflag = DNS_KEYFLAG_KSK; + else if (toupper(isc_commandline_argument[0]) == 'R') + revflag = DNS_KEYFLAG_REVOKE; else fatal("unknown flag '%s'", isc_commandline_argument); @@ -195,14 +252,18 @@ main(int argc, char **argv) { if (*endp != '\0' || generator <= 0) fatal("-g requires a positive number"); break; + case 'K': + directory = isc_commandline_argument; + break; case 'k': - options |= DST_TYPE_KEY; + fatal("The -k option has been deprecated.\n" + "To generate a key-signing key, use -f KSK.\n" + "To generate a key with TYPE=KEY, use -T KEY.\n"); break; case 'n': nametype = isc_commandline_argument; break; - case 't': - type = isc_commandline_argument; + case 'm': break; case 'p': protocol = strtol(isc_commandline_argument, &endp, 10); @@ -210,6 +271,9 @@ main(int argc, char **argv) { fatal("-p must be followed by a number " "[0..255]"); break; + case 'r': + setup_entropy(mctx, isc_commandline_argument, &ectx); + break; case 's': signatory = strtol(isc_commandline_argument, &endp, 10); @@ -217,8 +281,19 @@ main(int argc, char **argv) { fatal("-s must be followed by a number " "[0..15]"); break; - case 'r': - setup_entropy(mctx, isc_commandline_argument, &ectx); + case 'T': + if (strcasecmp(isc_commandline_argument, "KEY") == 0) + options |= DST_TYPE_KEY; + else if (strcasecmp(isc_commandline_argument, + "DNSKEY") == 0) + /* default behavior */ + ; + else + fatal("unknown type '%s'", + isc_commandline_argument); + break; + case 't': + type = isc_commandline_argument; break; case 'v': endp = NULL; @@ -226,6 +301,29 @@ main(int argc, char **argv) { if (*endp != '\0') fatal("-v must be followed by a number"); break; + case 'z': + /* already the default */ + break; + case 'P': + publish = strtotime(isc_commandline_argument, + now, now); + break; + case 'A': + activate = strtotime(isc_commandline_argument, + now, now); + break; + case 'R': + revoke = strtotime(isc_commandline_argument, + now, now); + break; + case 'U': + unpublish = strtotime(isc_commandline_argument, + now, now); + break; + case 'D': + delete = strtotime(isc_commandline_argument, + now, now); + break; case 'F': /* Reserved for FIPS mode */ /* FALLTHROUGH */ @@ -259,8 +357,11 @@ main(int argc, char **argv) { fatal("extraneous arguments"); if (algname == NULL) { - algname = strdup(DEFAULT_ALGORITHM); use_default = ISC_TRUE; + if (use_nsec3) + algname = strdup(DEFAULT_NSEC3_ALGORITHM); + else + algname = strdup(DEFAULT_ALGORITHM); if (verbose > 0) fprintf(stderr, "no algorithm specified; " "defaulting to %s\n", algname); @@ -299,6 +400,12 @@ main(int argc, char **argv) { options |= DST_TYPE_KEY; } + if (use_nsec3 && + alg != DST_ALG_NSEC3DSA && alg != DST_ALG_NSEC3RSASHA1) { + fatal("%s is incompatible with NSEC3; " + "do not use the -3 option", algname); + } + if (type != NULL && (options & DST_TYPE_KEY) != 0) { if (strcasecmp(type, "NOAUTH") == 0) flags |= DNS_KEYTYPE_NOAUTH; @@ -317,7 +424,7 @@ main(int argc, char **argv) { if (size < 0) { if (use_default) { - size = (ksk != 0) ? 2048 : 1024; + size = ((kskflag & DNS_KEYFLAG_KSK) != 0) ? 2048 : 1024; if (verbose > 0) fprintf(stderr, "key size not specified; " "defaulting to %d\n", size); @@ -424,11 +531,14 @@ main(int argc, char **argv) { rdclass = strtoclass(classname); + if (directory == NULL) + directory = "."; + if ((options & DST_TYPE_KEY) != 0) /* KEY / HMAC */ flags |= signatory; else if ((flags & DNS_KEYOWNER_ZONE) != 0) { /* DNSKEY */ - flags |= ksk; - flags |= revoke; + flags |= kskflag; + flags |= revflag; } if (protocol == -1) @@ -507,6 +617,22 @@ main(int argc, char **argv) { dst_key_setbits(key, dbits); + /* + * Set key timing metadata + */ + if (!oldstyle) { + dst_key_settime(key, DST_TIME_CREATED, now); + dst_key_settime(key, DST_TIME_PUBLISH, publish); + dst_key_settime(key, DST_TIME_ACTIVATE, activate); + dst_key_settime(key, DST_TIME_REVOKE, revoke); + dst_key_settime(key, DST_TIME_REMOVE, unpublish); + dst_key_settime(key, DST_TIME_DELETE, delete); + } else if (publish != 0 || activate != 0 || revoke != 0 || + unpublish != 0 || delete != 0) { + fatal("cannot use -C together with " + "-P, -A, -R, -U, or -D options"); + } + /* * Try to read a key with the same name, alg and id from disk. * If there is one we must continue generating a new one @@ -540,7 +666,7 @@ main(int argc, char **argv) { fatal("cannot generate a null key when a key with id 0 " "already exists"); - ret = dst_key_tofile(key, options, NULL); + ret = dst_key_tofile(key, options, directory); if (ret != ISC_R_SUCCESS) { char keystr[KEY_FORMATSIZE]; key_format(key, keystr, sizeof(keystr)); diff --git a/bin/dnssec/dnssec-keygen.docbook b/bin/dnssec/dnssec-keygen.docbook index 903da941a7..5ba3862ea1 100644 --- a/bin/dnssec/dnssec-keygen.docbook +++ b/bin/dnssec/dnssec-keygen.docbook @@ -18,7 +18,7 @@ - PERFORMANCE OF THIS SOFTWARE. --> - + June 30, 2000 @@ -59,17 +59,26 @@ + + + + + + + + + name @@ -79,7 +88,8 @@ dnssec-keygen generates keys for DNSSEC (Secure DNS), as defined in RFC 2535 and RFC 4034. It can also generate keys for use with - TSIG (Transaction Signatures), as defined in RFC 2845. + TSIG (Transaction Signatures) as defined in RFC 2845, or TKEY + (Transaction Key) as defined in RFC 2930. @@ -91,11 +101,17 @@ -a algorithm - Selects the cryptographic algorithm. The value of - must be one of RSAMD5 (RSA) or RSASHA1, - DSA, NSEC3RSASHA1, NSEC3DSA, DH (Diffie Hellman), or HMAC-MD5. - These values are case insensitive. The default is RSASHA1 for - DNSSEC key generation. + Selects the cryptographic algorithm. For DNSSEC keys, the value + of must be one of RSAMD5, RSASHA1, + DSA, NSEC3RSASHA1, or NSEC3DSA. For TSIG/TKEY, the value must + be DH (Diffie Hellman), HMAC-MD5, HMAC-SHA1, HMAC-SHA224, + HMAC-SHA256, HMAC-SHA384, or HMAC-SHA512. These values are + case insensitive. + + + If no algorithm is specified, then RSASHA1 will be used by + default, unless the option is specified, + in which case NSEC3RSASHA1 will be used instead. Note 1: that for DNSSEC, RSASHA1 is a mandatory to implement @@ -103,7 +119,8 @@ mandatory. - Note 2: HMAC-MD5 and DH automatically set the -k flag. + Note 2: DH, HMAC-MD5, and HMAC-SHA1 through HMAC-SHA512 + automatically set the -T KEY option. @@ -119,9 +136,14 @@ bits and an exact multiple of 64. HMAC-MD5 keys must be between 1 and 512 bits. - When generating a DNSSEC key with the default algorithm, this - value defaults to 1024, or 2048 if the KSK flag is set. + The key size does not need to be specified if using a default + algorithm. The default key size is 1024 bits for zone signing + keys (ZSK's) and 2048 bits for key signing keys (KSK's, + generated with ). However, if an + algorithm is explicitly specified with the , + then there is no default key size, and the + must be used. @@ -141,6 +163,33 @@ + + -3 + + + Use an NSEC3-capable algorithm to generate a DNSSEC key. + If this option is used and no algorithm is explicitly + set on the command line, NSEC3RSASHA1 will be used by + default. + + + + + + -C + + + Compatibility mode: generates an old-style key, without + any metadata. By default, dnssec-keygen + will include the key's creation date in the metadata stored + with the private key, and other dates may be set there as well + (publication date, activation date, etc). Keys that include + this data may be incompatible with older versions of BIND; the + option suppresses them. + + + + -c class @@ -165,7 +214,7 @@ Set the specified flag in the flag field of the KEY/DNSKEY record. - The only recognized flag is KSK (Key Signing Key) DNSKEY. + The only recognized flags are KSK (Key Signing Key) and REVOKE. @@ -192,11 +241,20 @@ + + -K directory + + + Sets the directory in which the key files are to be written. + + + + -k - Generate KEY records rather than DNSKEY records. + Deprecated in favor of -T KEY. @@ -241,6 +299,22 @@ + + -T rrtype + + + Specifies the resource record type to use for the key. + must be either DNSKEY or KEY. The + default is DNSKEY when using a DNSSEC algorithm, but it can be + overridden to KEY for use with SIG(0). + + + Using any TSIG algorithm (HMAC-* or DH) forces this option + to KEY. + + + + -t type @@ -265,6 +339,79 @@ + + TIMING OPTIONS + + + Dates can be expressed in the format YYYYMMDD or YYYYMMDDHHMMSS. + If the argument begins with a '+' or '-', it is interpreted as + an offset from the present time. If such an offset is followed + by one of the characters 'y', 'm', 'w', 'd', or 'h', then the + offset is computed in years, months, weeks, days, or hours, + respectively; otherwise it is computed in seconds. + + + + + -P date/offset + + + Sets the date on which a key is to be published to the zone. + After that date, the key will be included in the zone but will + not be used to sign it. + + + + + + -A date/offset + + + Sets the date on which the key is to be activated. After that + date, the key will be included and the zone and used to sign + it. + + + + + + -R date/offset + + + Sets the date on which the key is to be revoked. After that + date, the key will be flagged as revoked. It will be included + in the zone and will be used to sign it. + + + + + + -U date/offset + + + Sets the date on which the key is to be unpublished. After that + date, the key will no longer be included in the zone, but it + may remain in the key repository. + + + + + + -D date/offset + + + Sets the date on which the key is to be deleted. After that + date, the key can be removed from the key repository. + NOTE: Keys are not currently deleted automatically; this field + is included for informational purposes and for future + development. + + + + + + + GENERATED KEYS diff --git a/bin/dnssec/dnssec-revoke.c b/bin/dnssec/dnssec-revoke.c index 7da15b037c..a1bef44cd7 100644 --- a/bin/dnssec/dnssec-revoke.c +++ b/bin/dnssec/dnssec-revoke.c @@ -14,7 +14,7 @@ * PERFORMANCE OF THIS SOFTWARE. */ -/* $Id: dnssec-revoke.c,v 1.4 2009/07/17 23:47:40 tbox Exp $ */ +/* $Id: dnssec-revoke.c,v 1.5 2009/07/19 04:18:04 each Exp $ */ /*! \file */ @@ -50,8 +50,8 @@ usage(void) { fprintf(stderr, "Usage:\n"); fprintf(stderr, " %s [options] keyfile\n\n", program); fprintf(stderr, "Version: %s\n", VERSION); - fprintf(stderr, " -f: force ovewrite\n"); - fprintf(stderr, " -d directory: use directory for key files\n"); + fprintf(stderr, " -f: force overwrite\n"); + fprintf(stderr, " -K directory: use directory for key files\n"); fprintf(stderr, " -h: help\n"); fprintf(stderr, " -r: remove old keyfiles after " "creating revoked version\n"); @@ -89,14 +89,14 @@ main(int argc, char **argv) { isc_commandline_errprint = ISC_FALSE; - while ((ch = isc_commandline_parse(argc, argv, "d:fhrv:")) != -1) { + while ((ch = isc_commandline_parse(argc, argv, "fK:rhv:")) != -1) { switch (ch) { - case 'd': - dir = isc_commandline_argument; - break; case 'f': force = ISC_TRUE; break; + case 'K': + dir = isc_commandline_argument; + break; case 'r': remove = ISC_TRUE; break; @@ -163,7 +163,7 @@ main(int argc, char **argv) { fatal("Could not initialize dst"); isc_entropy_stopcallbacksources(ectx); - result = dst_key_fromnamedfile(filename, + result = dst_key_fromnamedfile(filename, dir, DST_TYPE_PUBLIC|DST_TYPE_PRIVATE, mctx, &key); if (result != ISC_R_SUCCESS) diff --git a/bin/dnssec/dnssec-revoke.docbook b/bin/dnssec/dnssec-revoke.docbook index c8c58c725e..2d01c561be 100644 --- a/bin/dnssec/dnssec-revoke.docbook +++ b/bin/dnssec/dnssec-revoke.docbook @@ -17,7 +17,7 @@ - PERFORMANCE OF THIS SOFTWARE. --> - + June 1, 2009 @@ -46,7 +46,7 @@ dnssec-revoke - + keyfile @@ -75,7 +75,7 @@ - -d directory + -K directory Sets the directory in which the key files are to reside. diff --git a/bin/dnssec/dnssec-settime.8 b/bin/dnssec/dnssec-settime.8 new file mode 100644 index 0000000000..70383ee4ae --- /dev/null +++ b/bin/dnssec/dnssec-settime.8 @@ -0,0 +1,84 @@ +.\" Copyright (C) 2009 Internet Systems Consortium, Inc. ("ISC") +.\" +.\" Permission to use, copy, modify, and distribute this software for any +.\" purpose with or without fee is hereby granted, provided that the above +.\" copyright notice and this permission notice appear in all copies. +.\" +.\" THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH +.\" REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY +.\" AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT, +.\" INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM +.\" LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE +.\" OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR +.\" PERFORMANCE OF THIS SOFTWARE. +.\" +.\" $Id: dnssec-settime.8,v 1.2 2009/07/19 04:18:04 each Exp $ +.\" +.hy 0 +.ad l +.\"Generated by db2man.xsl. Don't modify this, modify the source. +.de Sh \" Subsection +.br +.if t .Sp +.ne 5 +.PP +\fB\\$1\fR +.PP +.. +.de Sp \" Vertical space (when we can't use .PP) +.if t .sp .5v +.if n .sp +.. +.de Ip \" List item +.br +.ie \\n(.$>=3 .ne \\$3 +.el .ne 3 +.IP "\\$1" \\$2 +.. +.TH "DNSSEC-REVOKE" 8 "June 29, 2009" "" "" +.SH NAME +dnssec-settime \- Set the key timing metadata for a DNSSEC key +.SH "SYNOPSIS" +.HP 14 +\fBdnssec\-revoke\fR [\fB\-hr\fR] [\fB\-K\ \fIdirectory\fR\fR] [\fB\-P\ \fIdate/offset\fR\fR] [\fB\-A\ \fIdate/offset\fR\fR] [\fB\-R\ \fIdate/offset\fR\fR] [\fB\-U\ \fIdate/offset\fR\fR] [\fB\-D\ \fIdate/offset\fR\fR] [\fB\-v\ \fIlevel\fR\fR] {keyfile} +.SH "DESCRIPTION" +.PP +\fBdnssec\-settime\fR reads a DNSSEC private key file, sets the key timing metadata as specified by the \fB\-P\fR, \fB\-A\fR, \fB\-R\fR, \fB\-U\fR, and \fB\-D\fR options\&. +.PP +If none of these options is set on the command line, then \fBdnssec\-settime\fR simply prints the key timing metadata already stored in the key\&. +.SH "OPTIONS" +.TP +\-h +Emit usage message and exit\&. +.TP +\-K \fIdirectory\fR +Sets the directory in which the key files are to reside\&. +.TP +\-P \fIdate/offset\fR +Sets the date on which a key is to be published to the zone\&. After that date, the key will be included in the zone but will not be used to sign it\&. +Dates can be expressed in the format YYYYMMDD or YYYYMMDDHHMMSS\&. If the argument begins with a '+' or '\-', it is interpreted as an offset from the present time\&. If an offset is followed by one of the characters 'y', 'm', 'w', 'd', or 'h', then the offset is computed in years, months, weeks, days, or hours, respectively; otherwise it is computed in seconds\&. +.TP +\-A \fIdate/offset\fR +Sets the date on which the key is to be activated\&. After that date, the key will be included and the zone and used to sign it\&. +The date/offset syntax is identical to that in the \fB\-P\fR option\&. +.TP +\-R \fIdate/offset\fR +Sets the date on which the key is to be revoked\&. After that date, the key will be flagged as revoked\&. It will be included in the zone and will be used to sign it\&. +The date/offset syntax is identical to that in the \fB\-P\fR option\&. +.TP +\-U \fIdate/offset\fR +Sets the date on which the key is to be unpublished\&. After that date, the key will no longer be included in the zone, but it may remain in the key repository\&. +The date/offset syntax is identical to that in the \fB\-P\fR option\&. +.TP +\-D \fIdate/offset\fR +Sets the date on which the key is to be deleted\&. After that date, the key can be removed from the key repository\&. +The date/offset syntax is identical to that in the \fB\-P\fR option\&. +.TP +\-v \fIlevel\fR +Sets the debugging level\&. +.SH "SEE ALSO" +.PP +\fBdnssec\-keygen\fR(8), BIND 9 Administrator Reference Manual, RFC 5011\&. +.SH "AUTHOR" +.PP +Internet Systems Consortium diff --git a/bin/dnssec/dnssec-settime.c b/bin/dnssec/dnssec-settime.c new file mode 100644 index 0000000000..1a3b441985 --- /dev/null +++ b/bin/dnssec/dnssec-settime.c @@ -0,0 +1,272 @@ +/* + * Copyright (C) 2009 Internet Systems Consortium, Inc. ("ISC") + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH + * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY + * AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT, + * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM + * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE + * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +/* $Id: dnssec-settime.c,v 1.2 2009/07/19 04:18:04 each Exp $ */ + +/*! \file */ + +#include + +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include + +#include "dnssectool.h" + +const char *program = "dnssec-settime"; +int verbose; + +static isc_mem_t *mctx = NULL; + +static void +usage(void) { + fprintf(stderr, "Usage:\n"); + fprintf(stderr, " %s [options] keyfile\n\n", program); + fprintf(stderr, "Version: %s\n", VERSION); + fprintf(stderr, "Options:\n"); + fprintf(stderr, " -f: force update of old-style " + "keys\n"); + fprintf(stderr, " -K directory: set key file location\n"); + fprintf(stderr, " -h: help\n"); + fprintf(stderr, " -v level: set level of verbosity\n"); + fprintf(stderr, "Timing options:\n"); + fprintf(stderr, " -P date/[+-]offset: set key publication date\n"); + fprintf(stderr, " -A date/[+-]offset: set key activation date\n"); + fprintf(stderr, " -R date/[+-]offset: set key revocation date\n"); + fprintf(stderr, " -U date/[+-]offset: set key unpublication date\n"); + fprintf(stderr, " -D date/[+-]offset: set key deletion date\n"); + fprintf(stderr, "Output:\n"); + fprintf(stderr, " K++.key, " + "K++.private\n"); + + exit (-1); +} + +static void +printtime(dst_key_t *key, int type, const char *tag, FILE *stream) { + isc_result_t result; + time_t when; + const char *output; + + result = dst_key_gettime(key, type, (isc_stdtime_t *) &when); + if (result == ISC_R_NOTFOUND || when == 0) { + fprintf(stream, "%s: NOT SET\n", tag); + return; + } + + output = ctime(&when); + fprintf(stream, "%s: %s", tag, output); +} + +int +main(int argc, char **argv) { + isc_result_t result; + char *filename = NULL, *directory = NULL; + char newname[1024]; + char keystr[KEY_FORMATSIZE]; + char *endp; + int ch; + isc_entropy_t *ectx = NULL; + dst_key_t *key = NULL; + isc_buffer_t buf; + isc_stdtime_t now, when; + isc_stdtime_t pub = 0, act = 0, rev = 0, unpub = 0, del = 0; + isc_boolean_t setpub = ISC_FALSE, setact = ISC_FALSE; + isc_boolean_t setrev = ISC_FALSE, setunpub = ISC_FALSE; + isc_boolean_t setdel = ISC_FALSE; + isc_boolean_t forceupdate = ISC_FALSE; + isc_boolean_t print = ISC_TRUE; + + if (argc == 1) + usage(); + + result = isc_mem_create(0, 0, &mctx); + if (result != ISC_R_SUCCESS) + fatal("Out of memory"); + + dns_result_register(); + + isc_commandline_errprint = ISC_FALSE; + + isc_stdtime_get(&now); + + while ((ch = isc_commandline_parse(argc, argv, + "fK:hv:P:A:R:U:D:")) != -1) { + switch (ch) { + case 'f': + forceupdate = ISC_TRUE; + break; + case 'K': + directory = isc_commandline_argument; + break; + case 'v': + verbose = strtol(isc_commandline_argument, &endp, 0); + if (*endp != '\0') + fatal("-v must be followed by a number"); + break; + case 'P': + print = ISC_FALSE; + setpub = ISC_TRUE; + pub = strtotime(isc_commandline_argument, now, now); + break; + case 'A': + print = ISC_FALSE; + setact = ISC_TRUE; + act = strtotime(isc_commandline_argument, now, now); + break; + case 'R': + print = ISC_FALSE; + setrev = ISC_TRUE; + rev = strtotime(isc_commandline_argument, now, now); + break; + case 'U': + print = ISC_FALSE; + setunpub = ISC_TRUE; + unpub = strtotime(isc_commandline_argument, now, now); + break; + case 'D': + print = ISC_FALSE; + setdel = ISC_TRUE; + del = strtotime(isc_commandline_argument, now, now); + break; + case '?': + if (isc_commandline_option != '?') + fprintf(stderr, "%s: invalid argument -%c\n", + program, isc_commandline_option); + /* Falls into */ + case 'h': + usage(); + + default: + fprintf(stderr, "%s: unhandled option -%c\n", + program, isc_commandline_option); + exit(1); + } + } + + if (argc < isc_commandline_index + 1 || + argv[isc_commandline_index] == NULL) + fatal("The key file name was not specified"); + if (argc > isc_commandline_index + 1) + fatal("Extraneous arguments"); + + if (directory == NULL) + directory = dirname(argv[isc_commandline_index]); + filename = basename(argv[isc_commandline_index]); + + if (ectx == NULL) + setup_entropy(mctx, NULL, &ectx); + result = isc_hash_create(mctx, ectx, DNS_NAME_MAXWIRE); + if (result != ISC_R_SUCCESS) + fatal("Could not initialize hash"); + result = dst_lib_init(mctx, ectx, + ISC_ENTROPY_BLOCKING | ISC_ENTROPY_GOODONLY); + if (result != ISC_R_SUCCESS) + fatal("Could not initialize dst"); + isc_entropy_stopcallbacksources(ectx); + + result = dst_key_fromnamedfile(filename, directory, + DST_TYPE_PUBLIC | DST_TYPE_PRIVATE, + mctx, &key); + if (result != ISC_R_SUCCESS) + fatal("Invalid keyfile %s: %s", + filename, isc_result_totext(result)); + + if (!dst_key_isprivate(key)) + fatal("%s is not a private key", filename); + + key_format(key, keystr, sizeof(keystr)); + + /* Is this an old-style key? */ + result = dst_key_gettime(key, DST_TIME_CREATED, &when); + if (result == ISC_R_NOTFOUND) { + if (forceupdate) + dst_key_settime(key, DST_TIME_CREATED, now); + else + fatal("Incompatible key %s, " + "use -f force update.", keystr); + } + + if (verbose > 2) + fprintf(stderr, "%s: %s\n", program, keystr); + + if (print) { + printtime(key, DST_TIME_CREATED, "Created", stdout); + printtime(key, DST_TIME_PUBLISH, "Publish", stdout); + printtime(key, DST_TIME_ACTIVATE, "Activate", stdout); + printtime(key, DST_TIME_REVOKE, "Revoke", stdout); + printtime(key, DST_TIME_REMOVE, "Remove", stdout); + printtime(key, DST_TIME_DELETE, "Delete", stdout); + } else { + if (setpub) + dst_key_settime(key, DST_TIME_PUBLISH, pub); + + if (setact) + dst_key_settime(key, DST_TIME_ACTIVATE, act); + + if (setrev) + dst_key_settime(key, DST_TIME_REVOKE, rev); + + if (setunpub) + dst_key_settime(key, DST_TIME_REMOVE, unpub); + + if (setdel) + dst_key_settime(key, DST_TIME_DELETE, del); + + isc_buffer_init(&buf, newname, sizeof(newname)); + dst_key_buildfilename(key, DST_TYPE_PUBLIC, directory, &buf); + + result = dst_key_tofile(key, DST_TYPE_PUBLIC|DST_TYPE_PRIVATE, + directory); + if (result != ISC_R_SUCCESS) { + key_format(key, keystr, sizeof(keystr)); + fatal("Failed to write key %s: %s", keystr, + isc_result_totext(result)); + } + + printf("%s\n", newname); + + isc_buffer_clear(&buf); + dst_key_buildfilename(key, DST_TYPE_PRIVATE, directory, &buf); + printf("%s\n", newname); + } + + dst_key_free(&key); + dst_lib_destroy(); + isc_hash_destroy(); + cleanup_entropy(&ectx); + if (verbose > 10) + isc_mem_stats(mctx, stdout); + isc_mem_destroy(&mctx); + + return (0); +} diff --git a/bin/dnssec/dnssec-settime.docbook b/bin/dnssec/dnssec-settime.docbook new file mode 100644 index 0000000000..7e0142e87a --- /dev/null +++ b/bin/dnssec/dnssec-settime.docbook @@ -0,0 +1,228 @@ +]> + + + + + + July 15, 2009 + + + + dnssec-settime + 8 + BIND9 + + + + dnssec-settime + Set the key timing metadata for a DNSSEC key + + + + + 2009 + Internet Systems Consortium, Inc. ("ISC") + + + + + + dnssec-settime + + + + + + + + + + keyfile + + + + + DESCRIPTION + dnssec-settime + reads a DNSSEC private key file and sets the key timing metadata + as specified by the , , + , , and + options. The metadata can then be used by + dnssec-signzone or other signing software to + determine when a key is to be published, whether it should be + used for signing a zone, etc. + + + If none of these options is set on the command line, + then dnssec-settime simply prints the key timing + metadata already stored in the key. + + + When key metadata fields are changed, both files of a key + pair (Knnnn.+aaa+iiiii.key and + Knnnn.+aaa+iiiii.private) are regenerated. + Metadata fields are stored in the private file. A human-readable + description of the metadata is also placed in comments in the key + file. + + + + + OPTIONS + + + + -f + + + Force an update of an old-format key with no metadata fields. + Without this option, dnssec-settime will + fail when attempting to update a legacy key. With this option, + the key will be recreated in the new format, but with the + original key data retained. The key's creation date will be + set to the present time. + + + + + + -K directory + + + Sets the directory in which the key files are to reside. + + + + + + -h + + + Emit usage message and exit. + + + + + + -v level + + + Sets the debugging level. + + + + + + + + TIMING OPTIONS + + Dates can be expressed in the format YYYYMMDD or YYYYMMDDHHMMSS. + If the argument begins with a '+' or '-', it is interpreted as + an offset from the present time. If such an offset is followed + by one of the characters 'y', 'm', 'w', 'd', or 'h', then the + offset is computed in years, months, weeks, days, or hours, + respectively; otherwise it is computed in seconds. + + + + + -P date/offset + + + Sets the date on which a key is to be published to the zone. + After that date, the key will be included in the zone but will + not be used to sign it. + + + + + + -A date/offset + + + Sets the date on which the key is to be activated. After that + date, the key will be included and the zone and used to sign + it. + + + + + + -R date/offset + + + Sets the date on which the key is to be revoked. After that + date, the key will be flagged as revoked. It will be included + in the zone and will be used to sign it. + + + + + + -U date/offset + + + Sets the date on which the key is to be unpublished. After that + date, the key will no longer be included in the zone, but it + may remain in the key repository. + + + + + + -D date/offset + + + Sets the date on which the key is to be deleted. After that + date, the key can be removed from the key repository. + NOTE: Keys are not currently deleted automatically; this field + is included for informational purposes and for future + development. + + + + + + + + + SEE ALSO + + dnssec-keygen8 + , + + dnssec-signzone8 + , + BIND 9 Administrator Reference Manual, + RFC 5011. + + + + + AUTHOR + Internet Systems Consortium + + + + diff --git a/bin/dnssec/dnssec-settime.html b/bin/dnssec/dnssec-settime.html new file mode 100644 index 0000000000..19ccf4157b --- /dev/null +++ b/bin/dnssec/dnssec-settime.html @@ -0,0 +1,140 @@ + + + + + +dnssec-revoke + + +
+
+
+

Name

+

dnssec-settime — Set the key timing metadata for a DNSSEC key

+
+
+

Synopsis

+

dnssec-revoke [-hr] [-K directory] [-P date/offset] [-A date/offset] [-R date/offset] [-U date/offset] [-D date/offset] [-v level] {keyfile}

+
+
+

DESCRIPTION

+

dnssec-settime + reads a DNSSEC private key file, sets the key timing metadata + as specified by the -P, -A, + -R, -U, and -D + options. +

+

+ If none of these options is set on the command line, + then dnssec-settime simply prints the key timing + metadata already stored in the key. +

+
+
+

OPTIONS

+
+
-h
+

+ Emit usage message and exit. +

+
-K directory
+

+ Sets the directory in which the key files are to reside. +

+
-P date/offset
+
+

+ Sets the date on which a key is to be published to the zone. + After that date, the key will be included in the zone but will + not be used to sign it. +

+

+ Dates can be expressed in the format YYYYMMDD or YYYYMMDDHHMMSS. + If the argument begins with a '+' or '-', it is interpreted as + an offset from the present time. If an offset is followed by + one of the characters 'y', 'm', 'w', 'd', or 'h', then the + offset is computed in years, months, weeks, days, or hours, + respectively; otherwise it is computed in seconds. +

+
+
-A date/offset
+
+

+ Sets the date on which the key is to be activated. After that + date, the key will be included and the zone and used to sign + it. +

+

+ The date/offset syntax is identical to that in the + -P option. +

+
+
-R date/offset
+
+

+ Sets the date on which the key is to be revoked. After that + date, the key will be flagged as revoked. It will be included + in the zone and will be used to sign it. +

+

+ The date/offset syntax is identical to that in the + -P option. +

+
+
-U date/offset
+
+

+ Sets the date on which the key is to be unpublished. After that + date, the key will no longer be included in the zone, but it + may remain in the key repository. +

+

+ The date/offset syntax is identical to that in the + -P option. +

+
+
-D date/offset
+
+

+ Sets the date on which the key is to be deleted. After that + date, the key can be removed from the key repository. +

+

+ The date/offset syntax is identical to that in the + -P option. +

+
+
-v level
+

+ Sets the debugging level. +

+
+
+
+

SEE ALSO

+

dnssec-keygen(8), + BIND 9 Administrator Reference Manual, + RFC 5011. +

+
+
+

AUTHOR

+

Internet Systems Consortium +

+
+
+ diff --git a/bin/dnssec/dnssec-signzone.c b/bin/dnssec/dnssec-signzone.c index 1dc2891b40..17975dd598 100644 --- a/bin/dnssec/dnssec-signzone.c +++ b/bin/dnssec/dnssec-signzone.c @@ -29,7 +29,7 @@ * IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ -/* $Id: dnssec-signzone.c,v 1.220 2009/06/24 01:27:06 marka Exp $ */ +/* $Id: dnssec-signzone.c,v 1.221 2009/07/19 04:18:04 each Exp $ */ /*! \file */ @@ -100,19 +100,6 @@ static int nsec_datatype = dns_rdatatype_nsec; #define BUFSIZE 2048 #define MAXDSKEYS 8 -typedef struct signer_key_struct signer_key_t; - -struct signer_key_struct { - dst_key_t *key; - isc_boolean_t issigningkey; - isc_boolean_t isdsk; - isc_boolean_t isksk; - isc_boolean_t wasused; - isc_boolean_t commandline; - unsigned int position; - ISC_LINK(signer_key_t) link; -}; - #define SIGNER_EVENTCLASS ISC_EVENTCLASS(0x4453) #define SIGNER_EVENT_WRITE (SIGNER_EVENTCLASS + 0) #define SIGNER_EVENT_WORK (SIGNER_EVENTCLASS + 1) @@ -128,7 +115,7 @@ struct signer_event { dns_dbnode_t *node; }; -static ISC_LIST(signer_key_t) keylist; +static dns_dnsseckeylist_t keylist; static unsigned int keycount = 0; isc_rwlock_t keylist_lock; static isc_stdtime_t starttime = 0, endtime = 0, now; @@ -138,7 +125,7 @@ static isc_boolean_t tryverify = ISC_FALSE; static isc_boolean_t printstats = ISC_FALSE; static isc_mem_t *mctx = NULL; static isc_entropy_t *ectx = NULL; -static dns_ttl_t zonettl; +static dns_ttl_t zone_soa_min_ttl; static FILE *fp; static char *tempfile = NULL; static const dns_master_style_t *masterstyle; @@ -146,7 +133,7 @@ static dns_masterformat_t inputformat = dns_masterformat_text; static dns_masterformat_t outputformat = dns_masterformat_text; static unsigned int nsigned = 0, nretained = 0, ndropped = 0; static unsigned int nverified = 0, nverifyfailed = 0; -static const char *directory; +static const char *directory = NULL, *dsdir = NULL; static isc_mutex_t namelock, statslock; static isc_taskmgr_t *taskmgr = NULL; static dns_db_t *gdb; /* The database */ @@ -161,7 +148,7 @@ static isc_boolean_t shuttingdown = ISC_FALSE, finished = ISC_FALSE; static isc_boolean_t nokeys = ISC_FALSE; static isc_boolean_t removefile = ISC_FALSE; static isc_boolean_t generateds = ISC_FALSE; -static isc_boolean_t ignoreksk = ISC_FALSE; +static isc_boolean_t ignore_kskflag = ISC_FALSE; static dns_name_t *dlv = NULL; static dns_fixedname_t dlv_fixed; static dns_master_style_t *dsstyle = NULL; @@ -169,6 +156,7 @@ static unsigned int serialformat = SOA_SERIAL_KEEP; static unsigned int hash_length = 0; static isc_boolean_t unknownalg = ISC_FALSE; static isc_boolean_t disable_zone_check = ISC_FALSE; +static int keyttl = 3600; #define INCSTAT(counter) \ if (printstats) { \ @@ -194,40 +182,19 @@ dumpnode(dns_name_t *name, dns_dbnode_t *node) { check_result(result, "dns_master_dumpnodetostream"); } -static signer_key_t * -newkeystruct(dst_key_t *dstkey, isc_boolean_t signwithkey) { - signer_key_t *key; - - key = isc_mem_get(mctx, sizeof(signer_key_t)); - if (key == NULL) - fatal("out of memory"); - key->key = dstkey; - if ((dst_key_flags(dstkey) & DNS_KEYFLAG_KSK) != 0) { - key->issigningkey = signwithkey; - key->isksk = ISC_TRUE; - key->isdsk = ISC_FALSE; - } else { - key->issigningkey = signwithkey; - key->isksk = ISC_FALSE; - key->isdsk = ISC_TRUE; - } - key->wasused = ISC_FALSE; - key->commandline = ISC_FALSE; - key->position = keycount++; - ISC_LINK_INIT(key, link); - return (key); -} - static void signwithkey(dns_name_t *name, dns_rdataset_t *rdataset, dns_rdata_t *rdata, - dst_key_t *key, isc_buffer_t *b) + dst_key_t *key) { isc_result_t result; isc_stdtime_t jendtime; + unsigned char array[BUFSIZE]; + isc_buffer_t b; jendtime = (jitter != 0) ? isc_random_jitter(endtime, jitter) : endtime; + isc_buffer_init(&b, array, sizeof(array)); result = dns_dnssec_sign(name, rdataset, key, &starttime, &jendtime, - mctx, b, rdata); + mctx, &b, rdata); isc_entropy_stopcallbacksources(ectx); if (result != ISC_R_SUCCESS) { char keystr[KEY_FORMATSIZE]; @@ -251,23 +218,35 @@ signwithkey(dns_name_t *name, dns_rdataset_t *rdataset, dns_rdata_t *rdata, } static inline isc_boolean_t -issigningkey(signer_key_t *key) { - return (key->issigningkey); +issigningkey(dns_dnsseckey_t *key) { + return (key->force_sign || key->hint_sign); } static inline isc_boolean_t -iszonekey(signer_key_t *key) { +iszonekey(dns_dnsseckey_t *key) { return (ISC_TF(dns_name_equal(dst_key_name(key->key), gorigin) && dst_key_iszonekey(key->key))); } +static inline isc_boolean_t +isksk(dns_dnsseckey_t *key) { + return (key->ksk); +} + +static inline isc_boolean_t +iszsk(dns_dnsseckey_t *key) { + return (ignore_kskflag || !key->ksk); +} + /*% - * Find the key if it is in our list. If it is, return it, otherwise null. + * Find the key that generated an RRSIG, if it is in the key list. If + * so, return a pointer to it, otherwise return NULL. + * * No locking is performed here, this must be done by the caller. */ -static signer_key_t * +static dns_dnsseckey_t * keythatsigned_unlocked(dns_rdata_rrsig_t *rrsig) { - signer_key_t *key; + dns_dnsseckey_t *key; key = ISC_LIST_HEAD(keylist); while (key != NULL) { @@ -284,11 +263,11 @@ keythatsigned_unlocked(dns_rdata_rrsig_t *rrsig) { * Finds the key that generated a RRSIG, if possible. First look at the keys * that we've loaded already, and then see if there's a key on disk. */ -static signer_key_t * +static dns_dnsseckey_t * keythatsigned(dns_rdata_rrsig_t *rrsig) { isc_result_t result; dst_key_t *pubkey = NULL, *privkey = NULL; - signer_key_t *key; + dns_dnsseckey_t *key = NULL; isc_rwlock_lock(&keylist_lock, isc_rwlocktype_read); key = keythatsigned_unlocked(rrsig); @@ -304,7 +283,6 @@ keythatsigned(dns_rdata_rrsig_t *rrsig) { * after all. */ isc_rwlock_lock(&keylist_lock, isc_rwlocktype_write); - key = keythatsigned_unlocked(rrsig); if (key != NULL) { isc_rwlock_unlock(&keylist_lock, isc_rwlocktype_write); @@ -313,7 +291,7 @@ keythatsigned(dns_rdata_rrsig_t *rrsig) { result = dst_key_fromfile(&rrsig->signer, rrsig->keyid, rrsig->algorithm, DST_TYPE_PUBLIC, - NULL, mctx, &pubkey); + directory, mctx, &pubkey); if (result != ISC_R_SUCCESS) { isc_rwlock_unlock(&keylist_lock, isc_rwlocktype_write); return (NULL); @@ -322,12 +300,17 @@ keythatsigned(dns_rdata_rrsig_t *rrsig) { result = dst_key_fromfile(&rrsig->signer, rrsig->keyid, rrsig->algorithm, DST_TYPE_PUBLIC | DST_TYPE_PRIVATE, - NULL, mctx, &privkey); + directory, mctx, &privkey); if (result == ISC_R_SUCCESS) { dst_key_free(&pubkey); - key = newkeystruct(privkey, ISC_FALSE); - } else - key = newkeystruct(pubkey, ISC_FALSE); + dns_dnsseckey_create(mctx, &privkey, &key); + key->force_publish = ISC_TRUE; + key->force_sign = ISC_FALSE; + } else { + dns_dnsseckey_create(mctx, &pubkey, &key); + key->force_publish = ISC_TRUE; + key->force_sign = ISC_FALSE; + } ISC_LIST_APPEND(keylist, key, link); isc_rwlock_unlock(&keylist_lock, isc_rwlocktype_write); @@ -366,7 +349,7 @@ expecttofindkey(dns_name_t *name) { } static inline isc_boolean_t -setverifies(dns_name_t *name, dns_rdataset_t *set, signer_key_t *key, +setverifies(dns_name_t *name, dns_rdataset_t *set, dns_dnsseckey_t *key, dns_rdata_t *rrsig) { isc_result_t result; @@ -392,7 +375,7 @@ signset(dns_diff_t *del, dns_diff_t *add, dns_dbnode_t *node, dns_name_t *name, dns_rdataset_t sigset; dns_rdata_t sigrdata = DNS_RDATA_INIT; dns_rdata_rrsig_t rrsig; - signer_key_t *key; + dns_dnsseckey_t *key; isc_result_t result; isc_boolean_t nosigs = ISC_FALSE; isc_boolean_t *wassignedby, *nowsignedby; @@ -478,15 +461,14 @@ signset(dns_diff_t *del, dns_diff_t *add, dns_dbnode_t *node, dns_name_t *name, { vbprintf(2, "\trrsig by %s retained\n", sigstr); keep = ISC_TRUE; - wassignedby[key->position] = ISC_TRUE; - nowsignedby[key->position] = ISC_TRUE; - key->wasused = ISC_TRUE; + wassignedby[key->index] = ISC_TRUE; + nowsignedby[key->index] = ISC_TRUE; } else { vbprintf(2, "\trrsig by %s dropped - %s\n", sigstr, expired ? "expired" : "failed to verify"); - wassignedby[key->position] = ISC_TRUE; + wassignedby[key->index] = ISC_TRUE; resign = ISC_TRUE; } } else if (iszonekey(key)) { @@ -494,15 +476,14 @@ signset(dns_diff_t *del, dns_diff_t *add, dns_dbnode_t *node, dns_name_t *name, { vbprintf(2, "\trrsig by %s retained\n", sigstr); keep = ISC_TRUE; - wassignedby[key->position] = ISC_TRUE; - nowsignedby[key->position] = ISC_TRUE; - key->wasused = ISC_TRUE; + wassignedby[key->index] = ISC_TRUE; + nowsignedby[key->index] = ISC_TRUE; } else { vbprintf(2, "\trrsig by %s dropped - %s\n", sigstr, expired ? "expired" : "failed to verify"); - wassignedby[key->position] = ISC_TRUE; + wassignedby[key->index] = ISC_TRUE; } } else if (!expired) { vbprintf(2, "\trrsig by %s retained\n", sigstr); @@ -512,7 +493,7 @@ signset(dns_diff_t *del, dns_diff_t *add, dns_dbnode_t *node, dns_name_t *name, } if (keep) { - nowsignedby[key->position] = ISC_TRUE; + nowsignedby[key->index] = ISC_TRUE; INCSTAT(nretained); if (sigset.ttl != ttl) { vbprintf(2, "\tfixing ttl %s\n", sigstr); @@ -543,19 +524,15 @@ signset(dns_diff_t *del, dns_diff_t *add, dns_dbnode_t *node, dns_name_t *name, } if (resign) { - isc_buffer_t b; dns_rdata_t trdata = DNS_RDATA_INIT; - unsigned char array[BUFSIZE]; char keystr[KEY_FORMATSIZE]; INSIST(!keep); key_format(key->key, keystr, sizeof(keystr)); vbprintf(1, "\tresigning with dnskey %s\n", keystr); - isc_buffer_init(&b, array, sizeof(array)); - signwithkey(name, set, &trdata, key->key, &b); - nowsignedby[key->position] = ISC_TRUE; - key->wasused = ISC_TRUE; + signwithkey(name, set, &trdata, key->key); + nowsignedby[key->index] = ISC_TRUE; tuple = NULL; result = dns_difftuple_create(mctx, DNS_DIFFOP_ADD, name, ttl, &trdata, @@ -579,33 +556,29 @@ signset(dns_diff_t *del, dns_diff_t *add, dns_dbnode_t *node, dns_name_t *name, key != NULL; key = ISC_LIST_NEXT(key, link)) { - isc_buffer_t b; dns_rdata_t trdata; - unsigned char array[BUFSIZE]; char keystr[KEY_FORMATSIZE]; - if (nowsignedby[key->position]) + if (nowsignedby[key->index]) continue; - if (!key->issigningkey) - continue; - if (!(ignoreksk || key->isdsk || - (key->isksk && - set->type == dns_rdatatype_dnskey && - dns_name_equal(name, gorigin)))) + if (!issigningkey(key)) continue; - key_format(key->key, keystr, sizeof(keystr)); - vbprintf(1, "\tsigning with dnskey %s\n", keystr); - dns_rdata_init(&trdata); - isc_buffer_init(&b, array, sizeof(array)); - signwithkey(name, set, &trdata, key->key, &b); - key->wasused = ISC_TRUE; - tuple = NULL; - result = dns_difftuple_create(mctx, DNS_DIFFOP_ADD, name, - ttl, &trdata, &tuple); - check_result(result, "dns_difftuple_create"); - dns_diff_append(add, &tuple); + if (iszsk(key) || + (isksk(key) && set->type == dns_rdatatype_dnskey && + dns_name_equal(name, gorigin))) { + key_format(key->key, keystr, sizeof(keystr)); + vbprintf(1, "\tsigning with dnskey %s\n", keystr); + dns_rdata_init(&trdata); + signwithkey(name, set, &trdata, key->key); + tuple = NULL; + result = dns_difftuple_create(mctx, DNS_DIFFOP_ADD, + name, ttl, &trdata, + &tuple); + check_result(result, "dns_difftuple_create"); + dns_diff_append(add, &tuple); + } } isc_mem_put(mctx, wassignedby, arraysize * sizeof(isc_boolean_t)); @@ -779,16 +752,21 @@ static void opendb(const char *prefix, dns_name_t *name, dns_rdataclass_t rdclass, dns_db_t **dbp) { - char filename[256]; + char filename[PATH_MAX]; isc_buffer_t b; isc_result_t result; isc_buffer_init(&b, filename, sizeof(filename)); - if (directory != NULL) { - isc_buffer_putstr(&b, directory); - if (directory[strlen(directory) - 1] != '/') + if (dsdir != NULL) { + /* allow room for a trailing slash */ + if (strlen(dsdir) >= isc_buffer_availablelength(&b)) + fatal("path '%s' is too long", dsdir); + isc_buffer_putstr(&b, dsdir); + if (dsdir[strlen(dsdir) - 1] != '/') isc_buffer_putstr(&b, "/"); } + if (strlen(prefix) > isc_buffer_availablelength(&b)) + fatal("path '%s' is too long", dsdir); isc_buffer_putstr(&b, prefix); result = dns_name_tofilenametext(name, ISC_FALSE, &b); check_result(result, "dns_name_tofilenametext()"); @@ -803,13 +781,15 @@ opendb(const char *prefix, dns_name_t *name, dns_rdataclass_t rdclass, rdclass, 0, NULL, dbp); check_result(result, "dns_db_create()"); - result = dns_db_load(*dbp, filename); + result = dns_db_load3(*dbp, filename, inputformat, DNS_MASTER_HINT); if (result != ISC_R_SUCCESS && result != DNS_R_SEENINCLUDE) dns_db_detach(dbp); } /*% - * Loads the key set for a child zone, if there is one, and builds DS records. + * Load the DS set for a child zone, if a dsset-* file can be found. + * If not, try to find a keyset-* file from an earlier version of + * dnssec-signzone, and build DS records from that. */ static isc_result_t loadds(dns_name_t *name, isc_uint32_t ttl, dns_rdataset_t *dsset) { @@ -823,15 +803,31 @@ loadds(dns_name_t *name, isc_uint32_t ttl, dns_rdataset_t *dsset) { dns_diff_t diff; dns_difftuple_t *tuple = NULL; - opendb("keyset-", name, gclass, &db); - if (db == NULL) - return (ISC_R_NOTFOUND); - - result = dns_db_findnode(db, name, ISC_FALSE, &node); - if (result != ISC_R_SUCCESS) { + opendb("dsset-", name, gclass, &db); + if (db != NULL) { + result = dns_db_findnode(db, name, ISC_FALSE, &node); + if (result == ISC_R_SUCCESS) { + dns_rdataset_init(dsset); + result = dns_db_findrdataset(db, node, NULL, + dns_rdatatype_ds, 0, 0, + dsset, NULL); + dns_db_detachnode(db, &node); + if (result == ISC_R_SUCCESS) { + vbprintf(2, "found DS records\n"); + dsset->ttl = ttl; + dns_db_detach(&db); + return (result); + } + } dns_db_detach(&db); - return (DNS_R_BADDB); } + + /* No DS records found; try again, looking for DNSKEY records */ + opendb("keyset-", name, gclass, &db); + if (db == NULL) { + return (ISC_R_NOTFOUND); + } + dns_rdataset_init(&keyset); result = dns_db_findrdataset(db, node, NULL, dns_rdatatype_dnskey, 0, 0, &keyset, NULL); @@ -840,12 +836,10 @@ loadds(dns_name_t *name, isc_uint32_t ttl, dns_rdataset_t *dsset) { dns_db_detach(&db); return (result); } - vbprintf(2, "found DNSKEY records\n"); result = dns_db_newversion(db, &ver); check_result(result, "dns_db_newversion"); - dns_diff_init(mctx, &diff); for (result = dns_rdataset_first(&keyset); @@ -874,6 +868,7 @@ loadds(dns_name_t *name, isc_uint32_t ttl, dns_rdataset_t *dsset) { check_result(result, "dns_difftuple_create"); dns_diff_append(&diff, &tuple); } + result = dns_diff_apply(&diff, db, ver); check_result(result, "dns_diff_apply"); dns_diff_clear(&diff); @@ -1129,10 +1124,10 @@ active_node(dns_dbnode_t *node) { } /*% - * Extracts the TTL from the SOA. + * Extracts the minimum TTL from the SOA. */ static dns_ttl_t -soattl(void) { +soa_min_ttl(void) { dns_rdataset_t soaset; dns_fixedname_t fname; dns_name_t *name; @@ -1932,6 +1927,7 @@ add_ds(dns_name_t *name, dns_dbnode_t *node, isc_uint32_t nsttl) { dns_rdatatype_ds, 0); check_result(result, "dns_db_deleterdataset"); } + result = loadds(name, nsttl, &dsset); if (result == ISC_R_SUCCESS) { result = dns_db_addrdataset(gdb, node, gversion, 0, @@ -2015,7 +2011,7 @@ nsecify(void) { fatal("iterating through the database failed: %s", isc_result_totext(result)); result = dns_nsec_build(gdb, gversion, node, nextname, - zonettl); + zone_soa_min_ttl); check_result(result, "dns_nsec_build()"); dns_db_detachnode(gdb, &node); } @@ -2452,7 +2448,7 @@ nsec3ify(unsigned int hashalg, unsigned int iterations, */ dns_dbiterator_pause(dbiter); addnsec3(name, node, salt, salt_length, iterations, - hashlist, zonettl); + hashlist, zone_soa_min_ttl); dns_db_detachnode(gdb, &node); /* * Add NSEC3's for empty nodes. Use closest encloser logic. @@ -2463,7 +2459,7 @@ nsec3ify(unsigned int hashalg, unsigned int iterations, count--; dns_name_split(nextname, count, NULL, nextname); addnsec3(nextname, NULL, salt, salt_length, - iterations, hashlist, zonettl); + iterations, hashlist, zone_soa_min_ttl); } } dns_dbiterator_destroy(&dbiter); @@ -2512,6 +2508,7 @@ loadzonekeys(dns_db_t *db) { isc_result_t result; dst_key_t *keys[20]; unsigned int nkeys, i; + dns_rdataset_t rdataset; currentversion = NULL; dns_db_currentversion(db, ¤tversion); @@ -2522,20 +2519,41 @@ loadzonekeys(dns_db_t *db) { fatal("failed to find the zone's origin: %s", isc_result_totext(result)); - result = dns_dnssec_findzonekeys(db, currentversion, node, gorigin, - mctx, 20, keys, &nkeys); - if (result == ISC_R_NOTFOUND) + /* Preserve the TTL of the DNSKEY RRset, if any */ + dns_rdataset_init(&rdataset); + result = dns_db_findrdataset(db, node, currentversion, + dns_rdatatype_dnskey, 0, 0, + &rdataset, NULL); + + if (result == ISC_R_SUCCESS) { + keyttl = rdataset.ttl; + if (dns_rdataset_isassociated(&rdataset)) + dns_rdataset_disassociate(&rdataset); + } + + /* Load keys corresponding to the existing DNSKEY RRset */ + result = dns_dnssec_findzonekeys2(db, currentversion, node, gorigin, + directory, mctx, 20, keys, &nkeys); + if (result == ISC_R_NOTFOUND) { result = ISC_R_SUCCESS; + goto cleanup; + } + if (result != ISC_R_SUCCESS) fatal("failed to find the zone keys: %s", isc_result_totext(result)); for (i = 0; i < nkeys; i++) { - signer_key_t *key; + dns_dnsseckey_t *key = NULL; - key = newkeystruct(keys[i], dst_key_isprivate(keys[i])); + dns_dnsseckey_create(mctx, &keys[i], &key); + key->force_publish = ISC_TRUE; + key->force_sign = dst_key_isprivate(key->key); + key->source = dns_keysource_zoneapex; ISC_LIST_APPEND(keylist, key, link); } + + cleanup: dns_db_detachnode(db, &node); dns_db_closeversion(db, ¤tversion, ISC_FALSE); } @@ -2550,7 +2568,6 @@ loadzonepubkeys(dns_db_t *db) { dns_rdataset_t rdataset; dns_rdata_t rdata = DNS_RDATA_INIT; dst_key_t *pubkey; - signer_key_t *key; isc_result_t result; dns_db_currentversion(db, ¤tversion); @@ -2562,13 +2579,18 @@ loadzonepubkeys(dns_db_t *db) { dns_rdataset_init(&rdataset); result = dns_db_findrdataset(db, node, currentversion, - dns_rdatatype_dnskey, 0, 0, &rdataset, NULL); - if (result != ISC_R_SUCCESS) - fatal("failed to find keys at the zone apex: %s", - isc_result_totext(result)); + dns_rdatatype_dnskey, 0, 0, &rdataset, + NULL); + if (result != ISC_R_SUCCESS) { + vbprintf(2, "failed to find keys at the zone apex: %s", + isc_result_totext(result)); + goto cleanup; + } + result = dns_rdataset_first(&rdataset); check_result(result, "dns_rdataset_first"); while (result == ISC_R_SUCCESS) { + dns_dnsseckey_t *key = NULL; pubkey = NULL; dns_rdata_reset(&rdata); dns_rdataset_current(&rdataset, &rdata); @@ -2581,14 +2603,188 @@ loadzonepubkeys(dns_db_t *db) { goto next; } - key = newkeystruct(pubkey, ISC_FALSE); + dns_dnsseckey_create(mctx, &pubkey, &key); + key->force_publish = ISC_TRUE; + key->force_sign = ISC_FALSE; ISC_LIST_APPEND(keylist, key, link); next: result = dns_rdataset_next(&rdataset); } - dns_rdataset_disassociate(&rdataset); - dns_db_detachnode(db, &node); - dns_db_closeversion(db, ¤tversion, ISC_FALSE); + + cleanup: + if (dns_rdataset_isassociated(&rdataset)) + dns_rdataset_disassociate(&rdataset); + if (node != NULL) + dns_db_detachnode(db, &node); + if (currentversion != NULL) + dns_db_closeversion(db, ¤tversion, ISC_FALSE); +} + +static isc_result_t +make_dnskey(dst_key_t *key, dns_rdata_t *target) { + isc_result_t result; + unsigned char data[DST_KEY_MAXSIZE]; + isc_buffer_t b; + isc_region_t r; + + isc_buffer_init(&b, data, sizeof(data)); + result = dst_key_todns(key, &b); + check_result(result, "dst_key_todns"); + + dns_rdata_reset(target); + isc_buffer_usedregion(&b, &r); + dns_rdata_fromregion(target, dst_key_class(key), + dns_rdatatype_dnskey, &r); + return (ISC_R_SUCCESS); +} + +static void +build_final_keylist(dns_db_t *db, const char *directory, isc_mem_t *mctx) { + isc_result_t result; + dns_dbversion_t *ver = NULL; + dns_diff_t del, add; + dns_difftuple_t *tuple = NULL; + dns_rdata_t dnskey = DNS_RDATA_INIT; + dns_dnsseckeylist_t matchkeys; + dns_dnsseckey_t *key1, *key2; + char name[DNS_NAME_FORMATSIZE]; + char alg[80]; + + dns_name_format(gorigin, name, sizeof(name)); + + ISC_LIST_INIT(matchkeys); + result = dns_dnssec_findmatchingkeys(gorigin, directory, + mctx, &matchkeys); + if (result == ISC_R_NOTFOUND) + result = ISC_R_SUCCESS; + check_result(result, "dns_dnssec_findmatchingkeys"); + + result = dns_db_newversion(db, &ver); + check_result(result, "dns_db_newversion"); + + dns_diff_init(mctx, &del); + dns_diff_init(mctx, &add); + + /* + * For each key in matchkeys, see if it has a match in keylist. + * - If not, and if the metadata says it should be published: + * add it to keylist and to the DNSKEY set + * - If so, and if the metadata says it should be removed: + * remove it from keylist and from the DNSKEY set + * - Otherwise, make sure keylist has up-to-date metadata + * + * (XXXEACH: logic is needed to make sure revoked keys + * can be matched correctly with nonrevoked) + */ + + key1 = ISC_LIST_HEAD(matchkeys); + while (key1 != NULL) { + for (key2 = ISC_LIST_HEAD(keylist); + key2 != NULL; + key2 = ISC_LIST_NEXT(key2, link)) { + if (dst_key_compare(key1->key, key2->key)) + break; + } + + /* + * No matching key found in keylist, so move the key + * we found into keylist + */ + if (key2 == NULL) { + dns_dnsseckey_t *next; + + /* move key from matchkeys to keylist */ + next = ISC_LIST_NEXT(key1, link); + ISC_LIST_UNLINK(matchkeys, key1, link); + ISC_LIST_APPEND(keylist, key1, link); + + key1 = next; + continue; + } + + /* Match found: remove it or update it as needed */ + if (key1->hint_remove) { + ISC_LIST_UNLINK(keylist, key2, link); + dns_dnsseckey_destroy(mctx, &key2); + + make_dnskey(key1->key, &dnskey); + alg_format(dst_key_alg(key1->key), alg, sizeof(alg)); + fprintf(stderr, "Removing expired key %d/%s from " + "DNSKEY RRset.\n", + dst_key_id(key1->key), alg); + + result = dns_difftuple_create(mctx, DNS_DIFFOP_DEL, + gorigin, keyttl, + &dnskey, &tuple); + check_result(result, "dns_difftuple_create"); + dns_diff_append(&del, &tuple); + } else { + key2->hint_publish = key1->hint_publish; + key2->hint_sign = key1->hint_sign; + } + + key1 = ISC_LIST_NEXT(key1, link); + } + + /* + * If a key was not in the zone already and needs to be published, + * add it now. + */ + for (key1 = ISC_LIST_HEAD(keylist); + key1 != NULL; + key1 = ISC_LIST_NEXT(key1, link)) { + if (key1->source == dns_keysource_zoneapex) + continue; + + if (key1->hint_publish || key1->force_publish) { + make_dnskey(key1->key, &dnskey); + + alg_format(dst_key_alg(key1->key), alg, sizeof(alg)); + fprintf(stderr, "Fetching %s %d/%s from key %s.\n", + isksk(key1) ? + (iszsk(key1) ? "KSK/ZSK" : "KSK") : + "ZSK", + dst_key_id(key1->key), alg, + key1->source == dns_keysource_user ? + "file" : + "repository"); + + /* add key to the zone */ + result = dns_difftuple_create(mctx, DNS_DIFFOP_ADD, + gorigin, keyttl, + &dnskey, &tuple); + check_result(result, "dns_difftuple_create"); + dns_diff_append(&add, &tuple); + } else { + vbprintf(1, "%s %d/%s: not published.\n", + isksk(key1) ? + (iszsk(key1) ? "KSK/ZSK" : "KSK") : + "ZSK", + dst_key_id(key1->key), alg); + } + } + + /* free matchkeys */ + while (!ISC_LIST_EMPTY(matchkeys)) { + key1 = ISC_LIST_HEAD(matchkeys); + ISC_LIST_UNLINK(matchkeys, key1, link); + dns_dnsseckey_destroy(mctx, &key1); + } + + result = dns_diff_applysilently(&del, db, ver); + if (result != ISC_R_SUCCESS) + fatal("failed to delete DNSKEYs at node '%s': %s", + name, isc_result_totext(result)); + + result = dns_diff_applysilently(&add, db, ver); + if (result != ISC_R_SUCCESS) + fatal("failed to add DNSKEYs at node '%s': %s", + name, isc_result_totext(result)); + + dns_db_closeversion(db, &ver, ISC_TRUE); + + dns_diff_clear(&del); + dns_diff_clear(&add); } static void @@ -2610,7 +2806,8 @@ warnifallksk(dns_db_t *db) { dns_rdataset_init(&rdataset); result = dns_db_findrdataset(db, node, currentversion, - dns_rdatatype_dnskey, 0, 0, &rdataset, NULL); + dns_rdatatype_dnskey, 0, 0, &rdataset, + NULL); if (result != ISC_R_SUCCESS) fatal("failed to find keys at the zone apex: %s", isc_result_totext(result)); @@ -2631,14 +2828,14 @@ warnifallksk(dns_db_t *db) { dns_rdataset_disassociate(&rdataset); dns_db_detachnode(db, &node); dns_db_closeversion(db, ¤tversion, ISC_FALSE); - if (!have_non_ksk && !ignoreksk) { + if (!have_non_ksk && !ignore_kskflag) { if (disable_zone_check) - fprintf(stderr, "%s: warning: No non-KSK dnskey found. " - "Supply non-KSK dnskey or use '-z'.\n", + fprintf(stderr, "%s: warning: No non-KSK DNSKEY found; " + "supply a ZSK or use '-z'.\n", program); else - fatal("No non-KSK dnskey found. " - "Supply non-KSK dnskey or use '-z'."); + fatal("No non-KSK DNSKEY found; " + "supply a ZSK or use '-z'."); } } @@ -2659,7 +2856,7 @@ writeset(const char *prefix, dns_rdatatype_t type) { isc_buffer_t namebuf; isc_region_t r; isc_result_t result; - signer_key_t *key; + dns_dnsseckey_t *key; unsigned char dsbuf[DNS_DS_BUFFERSIZE]; unsigned char keybuf[DST_KEY_MAXSIZE]; unsigned int filenamelen; @@ -2671,13 +2868,13 @@ writeset(const char *prefix, dns_rdatatype_t type) { check_result(result, "dns_name_tofilenametext"); isc_buffer_putuint8(&namebuf, 0); filenamelen = strlen(prefix) + strlen(namestr); - if (directory != NULL) - filenamelen += strlen(directory) + 1; + if (dsdir != NULL) + filenamelen += strlen(dsdir) + 1; filename = isc_mem_get(mctx, filenamelen + 1); if (filename == NULL) fatal("out of memory"); - if (directory != NULL) - sprintf(filename, "%s/", directory); + if (dsdir != NULL) + sprintf(filename, "%s/", dsdir); else filename[0] = 0; strcat(filename, prefix); @@ -2688,7 +2885,7 @@ writeset(const char *prefix, dns_rdatatype_t type) { for (key = ISC_LIST_HEAD(keylist); key != NULL; key = ISC_LIST_NEXT(key, link)) - if (!key->isksk) { + if (!isksk(key)) { have_non_ksk = ISC_TRUE; break; } @@ -2696,7 +2893,7 @@ writeset(const char *prefix, dns_rdatatype_t type) { for (key = ISC_LIST_HEAD(keylist); key != NULL; key = ISC_LIST_NEXT(key, link)) - if (key->isksk) { + if (isksk(key)) { have_ksk = ISC_TRUE; break; } @@ -2719,7 +2916,7 @@ writeset(const char *prefix, dns_rdatatype_t type) { key != NULL; key = ISC_LIST_NEXT(key, link)) { - if (have_ksk && have_non_ksk && !key->isksk) + if (have_ksk && have_non_ksk && !isksk(key)) continue; dns_rdata_init(&rdata); dns_rdata_init(&ds); @@ -2752,7 +2949,7 @@ writeset(const char *prefix, dns_rdatatype_t type) { } else result = dns_difftuple_create(mctx, DNS_DIFFOP_ADD, - gorigin, zonettl, + gorigin, zone_soa_min_ttl, &rdata, &tuple); check_result(result, "dns_difftuple_create"); dns_diff_append(&diff, &tuple); @@ -2807,11 +3004,16 @@ usage(void) { fprintf(stderr, "Version: %s\n", VERSION); fprintf(stderr, "Options: (default value in parenthesis) \n"); - fprintf(stderr, "\t-c class (IN)\n"); - fprintf(stderr, "\t-d directory\n"); - fprintf(stderr, "\t\tdirectory to find keyset files (.)\n"); + fprintf(stderr, "\t-S:\tsmart signing: automatically finds key\n" + "\t\tfiles for the zone and determines they are to\n" + "\t\tbe used\n"); + fprintf(stderr, "\t-K directory:\n"); + fprintf(stderr, "\t\tdirectory to find key files (.)\n"); + fprintf(stderr, "\t-d directory:\n"); + fprintf(stderr, "\t\tdirectory to find dsset files (.)\n"); fprintf(stderr, "\t-g:\t"); - fprintf(stderr, "generate DS records from keyset files\n"); + fprintf(stderr, "generate dsset file, and/or include DS records\n" + "\t\tfrom child zones' dsset files\n"); fprintf(stderr, "\t-s [YYYYMMDDHHMMSS|+offset]:\n"); fprintf(stderr, "\t\tRRSIG start time - absolute|offset (now - 1 hour)\n"); fprintf(stderr, "\t-e [YYYYMMDDHHMMSS|+offset|\"now\"+offset]:\n"); @@ -2838,12 +3040,16 @@ usage(void) { fprintf(stderr, "\t\ta file containing random data\n"); fprintf(stderr, "\t-a:\t"); fprintf(stderr, "verify generated signatures\n"); + fprintf(stderr, "\t-c class (IN)\n"); fprintf(stderr, "\t-p:\t"); fprintf(stderr, "use pseudorandom data (faster but less secure)\n"); fprintf(stderr, "\t-P:\t"); fprintf(stderr, "disable post-sign verification\n"); + fprintf(stderr, "\t-T TTL:\tTTL for newly added DNSKEYs"); fprintf(stderr, "\t-t:\t"); fprintf(stderr, "print statistics\n"); + fprintf(stderr, "\t-C:\tgenerate a keyset file, for compatibility\n" + "\t\twith older versions of dnssec-signzone -g\n"); fprintf(stderr, "\t-n ncpus (number of cpus present)\n"); fprintf(stderr, "\t-k key_signing_key\n"); fprintf(stderr, "\t-l lookasidezone\n"); @@ -2903,7 +3109,7 @@ main(int argc, char *argv[]) { int ndskeys = 0; char *endp; isc_time_t timer_start, timer_finish; - signer_key_t *key; + dns_dnsseckey_t *key; isc_result_t result; isc_log_t *log = NULL; isc_boolean_t pseudorandom = ISC_FALSE; @@ -2919,8 +3125,10 @@ main(int argc, char *argv[]) { size_t salt_length = 0; unsigned char saltbuf[255]; hashlist_t hashlist; + isc_boolean_t smartsign = ISC_FALSE; + isc_boolean_t make_keyset = ISC_FALSE; -#define CMDLINE_FLAGS "3:aAc:d:e:f:FghH:i:I:j:k:l:m:n:N:o:O:pPr:s:StUv:z" +#define CMDLINE_FLAGS "3:AaCc:Dd:e:f:FghH:i:I:j:K:k:l:m:n:N:o:O:pPr:s:ST:tUv:z" /* * Process memory debugging argument first. @@ -2987,11 +3195,21 @@ main(int argc, char *argv[]) { tryverify = ISC_TRUE; break; + case 'C': + make_keyset = ISC_TRUE; + break; + case 'c': classname = isc_commandline_argument; break; case 'd': + dsdir = isc_commandline_argument; + if (strlen(dsdir) == 0) + fatal("DS directory must be non-empty string"); + break; + + case 'K': directory = isc_commandline_argument; break; @@ -3096,9 +3314,15 @@ main(int argc, char *argv[]) { break; case 'S': - /* This is intentionally undocumented */ - /* -S: simple output style */ - masterstyle = &dns_master_style_simple; + smartsign = ISC_TRUE; + generateds = ISC_TRUE; + break; + + case 'T': + endp = NULL; + keyttl = strtol(isc_commandline_argument, &endp, 0); + if (*endp != '\0') + fatal("key TTL must be numeric"); break; case 't': @@ -3117,7 +3341,7 @@ main(int argc, char *argv[]) { break; case 'z': - ignoreksk = ISC_TRUE; + ignore_kskflag = ISC_TRUE; break; case 'F': @@ -3153,14 +3377,18 @@ main(int argc, char *argv[]) { isc_stdtime_get(&now); - if (startstr != NULL) + if (startstr != NULL) { + if (startstr[0] == '-' || strncmp(startstr, "now-", 4) == 0) + fatal("time value %s is invalid", startstr); starttime = strtotime(startstr, now, now); - else + } else starttime = now - 3600; /* Allow for some clock skew. */ - if (endstr != NULL) + if (endstr != NULL) { + if (endstr[0] == '-' || strncmp(endstr, "now-", 4) == 0) + fatal("time value %s is invalid", endstr); endtime = strtotime(endstr, now, starttime); - else + } else endtime = starttime + (30 * 24 * 60 * 60); if (cycle == -1) @@ -3172,6 +3400,9 @@ main(int argc, char *argv[]) { rdclass = strtoclass(classname); + if (directory == NULL) + directory = "."; + setup_logging(verbose, mctx, &log); argc -= isc_commandline_index; @@ -3236,7 +3467,7 @@ main(int argc, char *argv[]) { loadzone(file, origin, rdclass, &gdb); gorigin = dns_db_origin(gdb); gclass = dns_db_class(gdb); - zonettl = soattl(); + zone_soa_min_ttl = soa_min_ttl(); if (IS_NSEC3) { isc_boolean_t answer; @@ -3263,7 +3494,7 @@ main(int argc, char *argv[]) { for (i = 0; i < argc; i++) { dst_key_t *newkey = NULL; - result = dst_key_fromnamedfile(argv[i], + result = dst_key_fromnamedfile(argv[i], directory, DST_TYPE_PUBLIC | DST_TYPE_PRIVATE, mctx, &newkey); @@ -3291,8 +3522,10 @@ main(int argc, char *argv[]) { key = ISC_LIST_NEXT(key, link); } if (key == NULL) { - key = newkeystruct(newkey, ISC_TRUE); - key->commandline = ISC_TRUE; + dns_dnsseckey_create(mctx, &newkey, &key); + key->force_publish = ISC_TRUE; + key->force_sign = ISC_TRUE; + key->source = dns_keysource_user; ISC_LIST_APPEND(keylist, key, link); } else dst_key_free(&newkey); @@ -3304,7 +3537,7 @@ main(int argc, char *argv[]) { for (i = 0; i < ndskeys; i++) { dst_key_t *newkey = NULL; - result = dst_key_fromnamedfile(dskeyfile[i], + result = dst_key_fromnamedfile(dskeyfile[i], directory, DST_TYPE_PUBLIC | DST_TYPE_PRIVATE, mctx, &newkey); @@ -3324,9 +3557,10 @@ main(int argc, char *argv[]) { dst_key_name(newkey))) { /* Override key flags. */ - key->issigningkey = ISC_TRUE; - key->isksk = ISC_TRUE; - key->isdsk = ISC_FALSE; + key->force_publish = ISC_TRUE; + key->force_sign = ISC_TRUE; + key->source = dns_keysource_user; + key->ksk = ISC_TRUE; dst_key_free(&dkey); key->key = newkey; break; @@ -3335,17 +3569,34 @@ main(int argc, char *argv[]) { } if (key == NULL) { /* Override dnskey flags. */ - key = newkeystruct(newkey, ISC_TRUE); - key->isksk = ISC_TRUE; - key->isdsk = ISC_FALSE; + dns_dnsseckey_create(mctx, &newkey, &key); + key->force_publish = ISC_TRUE; + key->force_sign = ISC_TRUE; + key->source = dns_keysource_user; + key->ksk = ISC_TRUE; ISC_LIST_APPEND(keylist, key, link); } } - if (ISC_LIST_EMPTY(keylist)) { + /* + * If we're doing smart signing, look in the key repository for + * key files with metadata, and merge them with the keylist + * we have now. + */ + if (smartsign) + build_final_keylist(gdb, directory, mctx); + + /* Now enumerate the key list */ + for (key = ISC_LIST_HEAD(keylist); + key != NULL; + key = ISC_LIST_NEXT(key, link)) { + key->index = keycount++; + } + + if (keycount == 0) { if (disable_zone_check) - fprintf(stderr, "%s: warning: No keys specified or found\n", - program); + fprintf(stderr, "%s: warning: No keys specified " + "or found\n", program); else fatal("No signing keys specified or found."); nokeys = ISC_TRUE; @@ -3386,8 +3637,9 @@ main(int argc, char *argv[]) { nsecify(); if (!nokeys) { - writeset("keyset-", dns_rdatatype_dnskey); writeset("dsset-", dns_rdatatype_ds); + if (make_keyset) + writeset("keyset-", dns_rdatatype_dnskey); if (dlv != NULL) { writeset("dlvset-", dns_rdatatype_dlv); } @@ -3492,8 +3744,7 @@ main(int argc, char *argv[]) { while (!ISC_LIST_EMPTY(keylist)) { key = ISC_LIST_HEAD(keylist); ISC_LIST_UNLINK(keylist, key, link); - dst_key_free(&key->key); - isc_mem_put(mctx, key, sizeof(signer_key_t)); + dns_dnsseckey_destroy(mctx, &key); } isc_mem_put(mctx, tempfile, tempfilelen); diff --git a/bin/dnssec/dnssec-signzone.docbook b/bin/dnssec/dnssec-signzone.docbook index 1d6ba01cb9..d22fd6c0f9 100644 --- a/bin/dnssec/dnssec-signzone.docbook +++ b/bin/dnssec/dnssec-signzone.docbook @@ -18,7 +18,7 @@ - PERFORMANCE OF THIS SOFTWARE. --> - + June 05, 2009 @@ -64,6 +64,7 @@ + @@ -75,7 +76,9 @@ + + @@ -121,6 +124,37 @@
+ + -d directory + + + Look for dsset- or + keyset- files in . + + + + + + -g + + + Generate DS records for child zones from + dsset- or keyset- + file. Existing DS records will be removed. + + + + + + -K directory + + + Key repository: Specify a directory to search for DNSSEC keys. + If not specified, defaults to the current directory. + + + + -k key @@ -141,26 +175,6 @@ - - -d directory - - - Look for keyset files in - as the directory - - - - - - -g - - - Generate DS records for child zones from keyset files. - Existing DS records will be removed. - - - - -s start-time @@ -393,6 +407,82 @@ + + -S + + + Smart signing: Instructs dnssec-signzone to + search the key repository for keys that match the zone being + signed, and to include them in the zone if appropriate. + + + When a key is found, its timing metadata is examined to + determine how it should be used, according to the following + rules. Each successive rule takes priority over the prior + ones: + + + + + + If no timing metadata has been set for the key, the key is + published in the zone and used to sign the zone. + + + + + + + + If the key's publication date is set and is in the past, the + key is published in the zone. + + + + + + + + If the key's activation date is set and in the past, the + key is published (regardless of publication date) and + used to sign the zone. + + + + + + + + If the key's revocation date is set and in the past, and the + key is published, then the key is revoked, and the revoked key + is used to sign the zone. + + + + + + + + If either of the key's unpublication or deletion dates are set + and in the past, the key is NOT published or used to sign the + zone, regardless of any other metadata. + + + + + + + + + -T ttl + + + Specifies the TTL of new DNSKEY records imported to the zone + from the key repository. Only useful with the -S option. + + + + -t diff --git a/bin/dnssec/dnssectool.c b/bin/dnssec/dnssectool.c index bd1467a72e..14d888f25f 100644 --- a/bin/dnssec/dnssectool.c +++ b/bin/dnssec/dnssectool.c @@ -15,7 +15,7 @@ * PERFORMANCE OF THIS SOFTWARE. */ -/* $Id: dnssectool.c,v 1.47 2009/06/04 02:56:47 tbox Exp $ */ +/* $Id: dnssectool.c,v 1.48 2009/07/19 04:18:04 each Exp $ */ /*! \file */ @@ -265,32 +265,66 @@ cleanup_entropy(isc_entropy_t **ectx) { isc_entropy_detach(ectx); } +static isc_stdtime_t +time_units(isc_stdtime_t offset, char suffix, const char *str) { + switch(suffix) { + case 'Y': case 'y': + return (offset * (365 * 24 * 3600)); + case 'M': case 'm': + return (offset * (30 * 24 * 3600)); + case 'W': case 'w': + return (offset * (7 * 24 * 3600)); + case 'D': case 'd': + return (offset * (24 * 3600)); + case 'H': case 'h': + return (offset * 3600); + case 'S': case 's': case '\0': + return (offset); + default: + fatal("time value %s is invalid", str); + } + return(0); /* silence compiler warning */ +} + isc_stdtime_t strtotime(const char *str, isc_int64_t now, isc_int64_t base) { isc_int64_t val, offset; isc_result_t result; + const char *orig = str; char *endp; - if (str[0] == '+') { + if (strlen(str) == 1 && (str[0] == '0' || str[0] == '-')) + return ((isc_stdtime_t) 0); + + if (strncmp(str, "now", 3) == 0) { + base = now; + str += 3; + } + + if (str[0] == '\0') + return ((isc_stdtime_t) base); + else if (str[0] == '+') { offset = strtol(str + 1, &endp, 0); - if (*endp != '\0') - fatal("time value %s is invalid", str); + offset = time_units(offset, *endp, orig); val = base + offset; - } else if (strncmp(str, "now+", 4) == 0) { - offset = strtol(str + 4, &endp, 0); - if (*endp != '\0') - fatal("time value %s is invalid", str); - val = now + offset; + } else if (str[0] == '-') { + offset = strtol(str + 1, &endp, 0); + offset = time_units(offset, *endp, orig); + val = base - offset; } else if (strlen(str) == 8U) { char timestr[15]; sprintf(timestr, "%s000000", str); result = dns_time64_fromtext(timestr, &val); if (result != ISC_R_SUCCESS) - fatal("time value %s is invalid", str); + fatal("time value %s is invalid: %s", orig, + isc_result_totext(result)); + } else if (strlen(str) > 14U) { + fatal("time value %s is invalid", orig); } else { result = dns_time64_fromtext(str, &val); if (result != ISC_R_SUCCESS) - fatal("time value %s is invalid", str); + fatal("time value %s is invalid: %s", orig, + isc_result_totext(result)); } return ((isc_stdtime_t) val); diff --git a/bin/nsupdate/nsupdate.c b/bin/nsupdate/nsupdate.c index a7990c30e6..27c61742e0 100644 --- a/bin/nsupdate/nsupdate.c +++ b/bin/nsupdate/nsupdate.c @@ -15,7 +15,7 @@ * PERFORMANCE OF THIS SOFTWARE. */ -/* $Id: nsupdate.c,v 1.170 2009/07/14 23:47:54 tbox Exp $ */ +/* $Id: nsupdate.c,v 1.171 2009/07/19 04:18:04 each Exp $ */ /*! \file */ @@ -626,7 +626,7 @@ setup_keyfile(isc_mem_t *mctx, isc_log_t *lctx) { debug("Creating key..."); /* Try reading the key from a K* pair */ - result = dst_key_fromnamedfile(keyfile, + result = dst_key_fromnamedfile(keyfile, NULL, DST_TYPE_PRIVATE | DST_TYPE_KEY, mctx, &dstkey); diff --git a/bin/tests/system/dnssec/ns1/sign.sh b/bin/tests/system/dnssec/ns1/sign.sh index a467db9e6e..410450aeca 100644 --- a/bin/tests/system/dnssec/ns1/sign.sh +++ b/bin/tests/system/dnssec/ns1/sign.sh @@ -15,7 +15,7 @@ # OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR # PERFORMANCE OF THIS SOFTWARE. -# $Id: sign.sh,v 1.27 2009/06/04 02:56:47 tbox Exp $ +# $Id: sign.sh,v 1.28 2009/07/19 04:18:04 each Exp $ SYSTEMTESTTOP=../.. . $SYSTEMTESTTOP/conf.sh @@ -28,8 +28,8 @@ zonefile=root.db (cd ../ns2 && sh sign.sh ) -cp ../ns2/keyset-example. . -cp ../ns2/keyset-dlv. . +cp ../ns2/dsset-example. . +cp ../ns2/dsset-dlv. . keyname=`$KEYGEN -r $RANDFILE -a RSAMD5 -b 768 -n zone $zone` @@ -39,7 +39,7 @@ $SIGNER -P -g -r $RANDFILE -o $zone $zonefile > /dev/null # Configure the resolving server with a trusted key. -cat $keyname.key | $PERL -n -e ' +cat $keyname.key | grep -v '^; ' | $PERL -n -e ' local ($dn, $class, $type, $flags, $proto, $alg, @rest) = split; local $key = join("", @rest); print < @@ -285,7 +285,7 @@ main(int argc, char *argv[]) { ourkey = NULL; type = DST_TYPE_PUBLIC | DST_TYPE_PRIVATE | DST_TYPE_KEY; - result = dst_key_fromnamedfile(ourkeyname, type, mctx, &ourkey); + result = dst_key_fromnamedfile(ourkeyname, NULL, type, mctx, &ourkey); CHECK("dst_key_fromnamedfile", result); isc_buffer_init(&nonce, noncedata, sizeof(noncedata)); diff --git a/bin/tests/system/tkey/keydelete.c b/bin/tests/system/tkey/keydelete.c index cb028adc8c..66ac7dd290 100644 --- a/bin/tests/system/tkey/keydelete.c +++ b/bin/tests/system/tkey/keydelete.c @@ -15,7 +15,7 @@ * PERFORMANCE OF THIS SOFTWARE. */ -/* $Id: keydelete.c,v 1.11 2007/06/19 23:47:06 tbox Exp $ */ +/* $Id: keydelete.c,v 1.12 2009/07/19 04:18:04 each Exp $ */ #include @@ -226,7 +226,7 @@ main(int argc, char **argv) { dstkey = NULL; type = DST_TYPE_PUBLIC | DST_TYPE_PRIVATE | DST_TYPE_KEY; - result = dst_key_fromnamedfile(keyname, type, mctx, &dstkey); + result = dst_key_fromnamedfile(keyname, NULL, type, mctx, &dstkey); CHECK("dst_key_fromnamedfile", result); result = dns_tsigkey_createfromkey(dst_key_name(dstkey), DNS_TSIG_HMACMD5_NAME, diff --git a/bin/tests/system/tkey/ns1/setup.sh b/bin/tests/system/tkey/ns1/setup.sh index c54e17f1ec..269710a8c2 100644 --- a/bin/tests/system/tkey/ns1/setup.sh +++ b/bin/tests/system/tkey/ns1/setup.sh @@ -15,11 +15,11 @@ # OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR # PERFORMANCE OF THIS SOFTWARE. -# $Id: setup.sh,v 1.8 2007/06/19 23:47:06 tbox Exp $ +# $Id: setup.sh,v 1.9 2009/07/19 04:18:04 each Exp $ RANDFILE=../random.data -keyname=`$KEYGEN -k -a DH -b 768 -n host -r $RANDFILE server` +keyname=`$KEYGEN -T KEY -a DH -b 768 -n host -r $RANDFILE server` keyid=`echo $keyname | $PERL -p -e 's/^.*\+0*//;'` rm -f named.conf perl -p -e "s/KEYID/$keyid/;" < named.conf.in > named.conf diff --git a/bin/tests/system/tkey/tests.sh b/bin/tests/system/tkey/tests.sh index 199a3b9dae..f53b2d2df9 100644 --- a/bin/tests/system/tkey/tests.sh +++ b/bin/tests/system/tkey/tests.sh @@ -15,7 +15,7 @@ # OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR # PERFORMANCE OF THIS SOFTWARE. -# $Id: tests.sh,v 1.7 2007/06/19 23:47:06 tbox Exp $ +# $Id: tests.sh,v 1.8 2009/07/19 04:18:04 each Exp $ SYSTEMTESTTOP=.. . $SYSTEMTESTTOP/conf.sh @@ -28,7 +28,7 @@ RANDFILE=random.data echo "I:generating new DH key" ret=0 -dhkeyname=`$KEYGEN -k -a DH -b 768 -n host -r $RANDFILE client` || ret=1 +dhkeyname=`$KEYGEN -T KEY -a DH -b 768 -n host -r $RANDFILE client` || ret=1 if [ $ret != 0 ]; then echo "I:failed" echo "I:exit status: $status" diff --git a/doc/arm/Bv9ARM-book.xml b/doc/arm/Bv9ARM-book.xml index 716914140b..6d0cac62b7 100644 --- a/doc/arm/Bv9ARM-book.xml +++ b/doc/arm/Bv9ARM-book.xml @@ -18,7 +18,7 @@ - PERFORMANCE OF THIS SOFTWARE. --> - + BIND 9 Administrator Reference Manual @@ -15264,6 +15264,7 @@ zone "example.com" { + diff --git a/lib/dns/db.c b/lib/dns/db.c index 58726b8eed..ed2a06c14b 100644 --- a/lib/dns/db.c +++ b/lib/dns/db.c @@ -15,7 +15,7 @@ * PERFORMANCE OF THIS SOFTWARE. */ -/* $Id: db.c,v 1.91 2009/06/30 02:52:32 each Exp $ */ +/* $Id: db.c,v 1.92 2009/07/19 04:18:05 each Exp $ */ /*! \file */ @@ -320,14 +320,19 @@ dns_db_endload(dns_db_t *db, dns_dbload_t **dbloadp) { isc_result_t dns_db_load(dns_db_t *db, const char *filename) { - return (dns_db_load2(db, filename, dns_masterformat_text)); + return (dns_db_load3(db, filename, dns_masterformat_text, 0)); } isc_result_t dns_db_load2(dns_db_t *db, const char *filename, dns_masterformat_t format) { + return (dns_db_load3(db, filename, format, 0)); +} + +isc_result_t +dns_db_load3(dns_db_t *db, const char *filename, dns_masterformat_t format, + unsigned int options) { isc_result_t result, eresult; dns_rdatacallbacks_t callbacks; - unsigned int options = 0; /* * Load master file 'filename' into 'db'. diff --git a/lib/dns/dnssec.c b/lib/dns/dnssec.c index 1bfee7c6d7..e34eb394cd 100644 --- a/lib/dns/dnssec.c +++ b/lib/dns/dnssec.c @@ -16,7 +16,7 @@ */ /* - * $Id: dnssec.c,v 1.95 2009/06/04 02:56:47 tbox Exp $ + * $Id: dnssec.c,v 1.96 2009/07/19 04:18:05 each Exp $ */ /*! \file */ @@ -26,6 +26,7 @@ #include #include +#include #include #include #include @@ -951,3 +952,208 @@ dns_dnssec_selfsigns(dns_rdata_t *rdata, dns_name_t *name, dst_key_free(&dstkey); return (ISC_FALSE); } + +isc_result_t +dns_dnsseckey_create(isc_mem_t *mctx, dst_key_t **dstkey, + dns_dnsseckey_t **dkp) +{ + isc_result_t result; + isc_stdtime_t when; + dns_dnsseckey_t *dk; + + REQUIRE(dkp != NULL && *dkp == NULL); + dk = isc_mem_get(mctx, sizeof(dns_dnsseckey_t)); + if (dk == NULL) + return (ISC_R_NOMEMORY); + + dk->key = *dstkey; + *dstkey = NULL; + dk->force_publish = ISC_FALSE; + dk->force_sign = ISC_FALSE; + dk->hint_publish = ISC_FALSE; + dk->hint_sign = ISC_FALSE; + dk->hint_remove = ISC_FALSE; + dk->source = dns_keysource_unknown; + dk->index = 0; + + /* KSK or ZSK? */ + dk->ksk = ISC_TF((dst_key_flags(dk->key) & DNS_KEYFLAG_KSK) != 0); + + /* Is this an old-style key? */ + result = dst_key_gettime(dk->key, DST_TIME_CREATED, &when); + dk->legacy = ISC_TF(result != ISC_R_SUCCESS); + + ISC_LINK_INIT(dk, link); + *dkp = dk; + return (ISC_R_SUCCESS); +} + +void +dns_dnsseckey_destroy(isc_mem_t *mctx, dns_dnsseckey_t **dkp) { + dns_dnsseckey_t *dk; + + REQUIRE(dkp != NULL && *dkp != NULL); + dk = *dkp; + if (dk->key != NULL) + dst_key_free(&dk->key); + isc_mem_put(mctx, dk, sizeof(dns_dnsseckey_t)); + *dkp = NULL; +} + +static void +get_hints(dns_dnsseckey_t *key) { + isc_result_t result; + isc_stdtime_t now, publish, active, revoke, remove, delete; + isc_boolean_t pubset = ISC_FALSE, actset = ISC_FALSE; + isc_boolean_t revset = ISC_FALSE, remset = ISC_FALSE; + isc_boolean_t delset = ISC_FALSE; + + REQUIRE(key != NULL && key->key != NULL); + + isc_stdtime_get(&now); + + result = dst_key_gettime(key->key, DST_TIME_PUBLISH, &publish); + if (result == ISC_R_SUCCESS) + pubset = ISC_TRUE; + + result = dst_key_gettime(key->key, DST_TIME_ACTIVATE, &active); + if (result == ISC_R_SUCCESS) + actset = ISC_TRUE; + + result = dst_key_gettime(key->key, DST_TIME_REVOKE, &revoke); + if (result == ISC_R_SUCCESS) + revset = ISC_TRUE; + + result = dst_key_gettime(key->key, DST_TIME_REMOVE, &remove); + if (result == ISC_R_SUCCESS) + remset = ISC_TRUE; + + result = dst_key_gettime(key->key, DST_TIME_DELETE, &delete); + if (result == ISC_R_SUCCESS) + delset = ISC_TRUE; + + /* No metadata set: Publish and sign. */ + if (!pubset && !actset && !revset && !remset && !delset) { + key->hint_sign = ISC_TRUE; + key->hint_publish = ISC_TRUE; + } + + /* Metadata says publish (but possibly not activate) */ + if (pubset && publish < now) + key->hint_publish = ISC_TRUE; + + /* Metadata says activate (so we must also publish) */ + if (actset && active < now) { + key->hint_sign = ISC_TRUE; + key->hint_publish = ISC_TRUE; + } + + /* + * Activation date is set (maybe in the future), but + * publication date isn't. Most likely the user wants to + * publish now and activate later. + */ + if (actset && !pubset) + key->hint_publish = ISC_TRUE; + + /* + * Metadata says revoke. If the key is published, + * we *have to* sign with it per RFC5011--even if it was + * not active before. + * + * If it hasn't already been done, we should also revoke it now. + */ + if (key->hint_publish && (revset && revoke < now)) { + isc_uint32_t flags; + key->hint_sign = ISC_TRUE; + flags = dst_key_flags(key->key); + if ((flags & DNS_KEYFLAG_REVOKE) == 0) { + flags |= DNS_KEYFLAG_REVOKE; + dst_key_setflags(dstkey, flags); + } + } + + /* + * Metadata says remove or delete, so don't publish + * this key or sign with it. + */ + if ((remset && remove < now) || + (delset && delete < now)) { + key->hint_publish = ISC_FALSE; + key->hint_sign = ISC_FALSE; + key->hint_remove = ISC_TRUE; + } +} + +/*% + * Get a list of DNSSEC keys from the key repository + */ +isc_result_t +dns_dnssec_findmatchingkeys(dns_name_t *origin, const char *directory, + isc_mem_t *mctx, dns_dnsseckeylist_t *keylist) +{ + isc_result_t result = ISC_R_SUCCESS; + dns_dnsseckeylist_t list; + isc_dir_t dir; + dns_dnsseckey_t *key = NULL; + dst_key_t *dstkey = NULL; + char namebuf[DNS_NAME_FORMATSIZE], *p; + isc_buffer_t b; + unsigned int len; + + REQUIRE(keylist != NULL); + ISC_LIST_INIT(list); + + isc_buffer_init(&b, namebuf, sizeof(namebuf) - 1); + RETERR(dns_name_totext(origin, ISC_FALSE, &b)); + len = isc_buffer_usedlength(&b); + namebuf[len] = '\0'; + + isc_dir_init(&dir); + RETERR(isc_dir_open(&dir, directory)); + + while (isc_dir_read(&dir) == ISC_R_SUCCESS) { + if (dir.entry.name[0] == 'K' && + dir.entry.length > len + 1 && + dir.entry.name[len + 1] == '+' && + strncasecmp(dir.entry.name + 1, namebuf, len) == 0) { + p = strrchr(dir.entry.name, '.'); + if (strcmp(p, ".private") != 0) + continue; + + dstkey = NULL; + RETERR(dst_key_fromnamedfile(dir.entry.name, directory, + DST_TYPE_PUBLIC | DST_TYPE_PRIVATE, + mctx, &dstkey)); + + RETERR(dns_dnsseckey_create(mctx, &dstkey, &key)); + key->source = dns_keysource_repository; + get_hints(key); + + if (key->legacy) { + dns_dnsseckey_destroy(mctx, &key); + } else { + ISC_LIST_APPEND(list, key, link); + key = NULL; + } + } + } + + if (!ISC_LIST_EMPTY(list)) + ISC_LIST_APPENDLIST(*keylist, list, link); + else + result = ISC_R_NOTFOUND; + + failure: + isc_dir_close(&dir); + INSIST(key == NULL); + while ((key = ISC_LIST_HEAD(list)) != NULL) { + ISC_LIST_UNLINK(list, key, link); + INSIST(key->key != NULL); + dst_key_free(&key->key); + dns_dnsseckey_destroy(mctx, &key); + } + if (dstkey != NULL) + dst_key_free(&dstkey); + return (result); +} diff --git a/lib/dns/dst_api.c b/lib/dns/dst_api.c index 96ad88ec2c..66915338e9 100644 --- a/lib/dns/dst_api.c +++ b/lib/dns/dst_api.c @@ -31,7 +31,7 @@ /* * Principal Author: Brian Wellington - * $Id: dst_api.c,v 1.22 2009/06/30 23:48:01 tbox Exp $ + * $Id: dst_api.c,v 1.23 2009/07/19 04:18:05 each Exp $ */ /*! \file */ @@ -108,7 +108,8 @@ static isc_result_t frombuffer(dns_name_t *name, static isc_result_t algorithm_status(unsigned int alg); static isc_result_t addsuffix(char *filename, unsigned int len, - const char *ofilename, const char *suffix); + const char *dirname, const char *ofilename, + const char *suffix); #define RETERR(x) \ do { \ @@ -394,7 +395,7 @@ dst_key_fromfile(dns_name_t *name, dns_keytag_t id, return (result); key = NULL; - result = dst_key_fromnamedfile(filename, type, mctx, &key); + result = dst_key_fromnamedfile(filename, NULL, type, mctx, &key); if (result != ISC_R_SUCCESS) return (result); @@ -416,8 +417,8 @@ dst_key_fromfile(dns_name_t *name, dns_keytag_t id, } isc_result_t -dst_key_fromnamedfile(const char *filename, int type, isc_mem_t *mctx, - dst_key_t **keyp) +dst_key_fromnamedfile(const char *filename, const char *dirname, + int type, isc_mem_t *mctx, dst_key_t **keyp) { isc_result_t result; dst_key_t *pubkey = NULL, *key = NULL; @@ -432,11 +433,23 @@ dst_key_fromnamedfile(const char *filename, int type, isc_mem_t *mctx, REQUIRE(mctx != NULL); REQUIRE(keyp != NULL && *keyp == NULL); + /* If an absolute path is specified, don't use the key directory */ +#ifndef WIN32 + if (filename[0] == '/') + dirname = NULL; +#else /* WIN32 */ + if (filename[0] == '/' || filename[0] == '\\') + dirname = NULL; +#endif + newfilenamelen = strlen(filename) + 5; + if (dirname != NULL) + newfilenamelen += strlen(dirname) + 1; newfilename = isc_mem_get(mctx, newfilenamelen); if (newfilename == NULL) return (ISC_R_NOMEMORY); - result = addsuffix(newfilename, newfilenamelen, filename, ".key"); + result = addsuffix(newfilename, newfilenamelen, + dirname, filename, ".key"); INSIST(result == ISC_R_SUCCESS); result = dst_key_read_public(newfilename, type, mctx, &pubkey); @@ -476,10 +489,13 @@ dst_key_fromnamedfile(const char *filename, int type, isc_mem_t *mctx, RETERR(DST_R_UNSUPPORTEDALG); newfilenamelen = strlen(filename) + 9; + if (dirname != NULL) + newfilenamelen += strlen(dirname) + 1; newfilename = isc_mem_get(mctx, newfilenamelen); if (newfilename == NULL) RETERR(ISC_R_NOMEMORY); - result = addsuffix(newfilename, newfilenamelen, filename, ".private"); + result = addsuffix(newfilename, newfilenamelen, + dirname, filename, ".private"); INSIST(result == ISC_R_SUCCESS); RETERR(isc_lex_create(mctx, 1500, &lex)); @@ -755,6 +771,24 @@ dst_key_generate(dns_name_t *name, unsigned int alg, return (ISC_R_SUCCESS); } +isc_result_t +dst_key_gettime(const dst_key_t *key, int type, isc_stdtime_t *timep) { + REQUIRE(VALID_KEY(key)); + REQUIRE(timep != NULL); + REQUIRE(type <= DST_MAX_TIMES); + if (key->times[type] == 0) + return (ISC_R_NOTFOUND); + *timep = key->times[type]; + return (ISC_R_SUCCESS); +} + +void +dst_key_settime(dst_key_t *key, int type, isc_stdtime_t when) { + REQUIRE(VALID_KEY(key)); + REQUIRE(type <= DST_MAX_TIMES); + key->times[type] = when; +} + isc_boolean_t dst_key_compare(const dst_key_t *key1, const dst_key_t *key2) { REQUIRE(dst_initialized == ISC_TRUE); @@ -933,6 +967,7 @@ get_key_struct(dns_name_t *name, unsigned int alg, key->key_alg = alg; key->key_flags = flags; key->key_proto = protocol; + memset(key->times, 0, sizeof(key->times)); key->mctx = mctx; key->keydata.generic = NULL; key->key_size = bits; @@ -1094,6 +1129,23 @@ issymmetric(const dst_key_t *key) { } } +/*% + * Write key timing metadata to a file pointer, preceded by 'tag' + */ +static void +printtime(const dst_key_t *key, int type, const char *tag, FILE *stream) { + isc_result_t result; + isc_stdtime_t when; + const char *output; + + result = dst_key_gettime(key, type, &when); + if (result == ISC_R_NOTFOUND) + return; + + output = ctime((time_t *) &when); + fprintf(stream, "%s: %s", tag, output); +} + /*% * Writes a public key to disk in DNS format. */ @@ -1153,12 +1205,34 @@ write_public_key(const dst_key_t *key, int type, const char *directory) { (void)isc_fsaccess_set(filename, access); } - ret = dns_name_print(key->key_name, fp); - if (ret != ISC_R_SUCCESS) { - fclose(fp); - return (ret); + /* Write key information in comments */ + if ((type & DST_TYPE_KEY) == 0) { + fprintf(fp, "; This is a %s%s-signing key, keyid %d, for ", + (key->key_flags & DNS_KEYFLAG_REVOKE) != 0 ? + "revoked " : + "", + (key->key_flags & DNS_KEYFLAG_KSK) != 0 ? + "key" : + "zone", + key->key_id); + ret = dns_name_print(key->key_name, fp); + if (ret != ISC_R_SUCCESS) { + fclose(fp); + return (ret); + } + fputc('\n', fp); + + printtime(key, DST_TIME_CREATED, "; Created", fp); + printtime(key, DST_TIME_PUBLISH, "; Publish", fp); + printtime(key, DST_TIME_ACTIVATE, "; Activate", fp); + printtime(key, DST_TIME_REVOKE, "; Revoke", fp); + printtime(key, DST_TIME_REMOVE, "; Remove", fp); + printtime(key, DST_TIME_DELETE, "; Delete", fp); } + /* Now print the actual key */ + ret = dns_name_print(key->key_name, fp); + fprintf(fp, " "); isc_buffer_usedregion(&classb, &r); @@ -1292,8 +1366,8 @@ algorithm_status(unsigned int alg) { } static isc_result_t -addsuffix(char *filename, unsigned int len, const char *ofilename, - const char *suffix) +addsuffix(char *filename, unsigned int len, const char *odirname, + const char *ofilename, const char *suffix) { int olen = strlen(ofilename); int n; @@ -1305,7 +1379,11 @@ addsuffix(char *filename, unsigned int len, const char *ofilename, else if (olen > 4 && strcmp(ofilename + olen - 4, ".key") == 0) olen -= 4; - n = snprintf(filename, len, "%.*s%s", olen, ofilename, suffix); + if (odirname == NULL) + n = snprintf(filename, len, "%.*s%s", olen, ofilename, suffix); + else + n = snprintf(filename, len, "%s/%.*s%s", + odirname, olen, ofilename, suffix); if (n < 0) return (ISC_R_NOSPACE); return (ISC_R_SUCCESS); diff --git a/lib/dns/dst_internal.h b/lib/dns/dst_internal.h index 7ff8d0d984..6bdd5ed2e6 100644 --- a/lib/dns/dst_internal.h +++ b/lib/dns/dst_internal.h @@ -29,7 +29,7 @@ * IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ -/* $Id: dst_internal.h,v 1.14 2009/06/30 02:52:32 each Exp $ */ +/* $Id: dst_internal.h,v 1.15 2009/07/19 04:18:05 each Exp $ */ #ifndef DST_DST_INTERNAL_H #define DST_DST_INTERNAL_H 1 @@ -42,9 +42,12 @@ #include #include #include +#include #include #include +#include + #include #ifdef OPENSSL @@ -112,7 +115,9 @@ struct dst_key { dst_hmacsha512_key_t *hmacsha512; } keydata; /*%< pointer to key in crypto pkg fmt */ - dst_func_t * func; /*%< crypto package specific functions*/ + + isc_stdtime_t times[DST_MAX_TIMES + 1]; /*%< key timing metadata */ + dst_func_t * func; /*%< crypto package specific functions */ }; struct dst_context { diff --git a/lib/dns/dst_parse.c b/lib/dns/dst_parse.c index 2fe626c561..6fa3eb9f4d 100644 --- a/lib/dns/dst_parse.c +++ b/lib/dns/dst_parse.c @@ -31,7 +31,7 @@ /*% * Principal Author: Brian Wellington - * $Id: dst_parse.c,v 1.17 2009/06/17 06:51:44 each Exp $ + * $Id: dst_parse.c,v 1.18 2009/07/19 04:18:05 each Exp $ */ #include @@ -41,9 +41,12 @@ #include #include #include +#include #include #include +#include + #include "dst_internal.h" #include "dst_parse.h" #include "dst/result.h" @@ -53,6 +56,16 @@ #define PRIVATE_KEY_STR "Private-key-format:" #define ALGORITHM_STR "Algorithm:" +#define METADATA_NTAGS 6 +static const char *metatags[METADATA_NTAGS] = { + "Created:", + "Publish:", + "Activate:", + "Revoke:", + "Remove:", + "Delete:" +}; + struct parse_map { const int value; const char *tag; @@ -107,15 +120,26 @@ static int find_value(const char *s, const unsigned int alg) { int i; - for (i = 0; ; i++) { - if (map[i].tag == NULL) - return (-1); - else if (strcasecmp(s, map[i].tag) == 0 && - TAG_ALG(map[i].value) == alg) + for (i = 0; map[i].tag != NULL; i++) { + if (strcasecmp(s, map[i].tag) == 0 && + (TAG_ALG(map[i].value) == alg)) return (map[i].value); } + return (-1); } +static int +find_metadata(const char *s) { + int i; + + for (i = 0; i < METADATA_NTAGS; i++) { + if (strcasecmp(s, metatags[i]) == 0) + return (i); + } + + return (-1); +} + static const char * find_tag(const int value) { int i; @@ -294,6 +318,7 @@ dst__privstruct_parse(dst_key_t *key, unsigned int alg, isc_lex_t *lex, isc_token_t token; unsigned char *data = NULL; unsigned int opt = ISC_LEXOPT_EOL; + isc_stdtime_t when; isc_result_t ret; REQUIRE(priv != NULL); @@ -377,7 +402,6 @@ dst__privstruct_parse(dst_key_t *key, unsigned int alg, isc_lex_t *lex, for (n = 0; n < MAXFIELDS; n++) { int tag; isc_region_t r; - do { ret = isc_lex_gettoken(lex, opt, &token); if (ret == ISC_R_EOF) @@ -391,8 +415,29 @@ dst__privstruct_parse(dst_key_t *key, unsigned int alg, isc_lex_t *lex, goto fail; } + /* Key timing metadata */ + tag = find_metadata(DST_AS_STR(token)); + if (tag >= 0) { + INSIST(tag < METADATA_NTAGS); + + NEXTTOKEN(lex, opt, &token); + if (token.type != isc_tokentype_string) { + ret = DST_R_INVALIDPRIVATEKEY; + goto fail; + } + + ret = dns_time32_fromtext(DST_AS_STR(token), &when); + if (ret != ISC_R_SUCCESS) + goto fail; + + dst_key_settime(key, tag, when); + + goto next; + } + + /* Key data */ tag = find_value(DST_AS_STR(token), alg); - if (tag < 0 || TAG_ALG(tag) != alg) { + if (tag < 0) { ret = DST_R_INVALIDPRIVATEKEY; goto fail; } @@ -409,20 +454,19 @@ dst__privstruct_parse(dst_key_t *key, unsigned int alg, isc_lex_t *lex, isc_buffer_usedregion(&b, &r); priv->elements[n].length = r.length; priv->elements[n].data = r.base; + priv->nelements++; + next: READLINE(lex, opt, &token); data = NULL; } done: - priv->nelements = n; - if (check_data(priv, alg, ISC_TRUE) < 0) goto fail; return (ISC_R_SUCCESS); fail: - priv->nelements = n; dst__privstruct_free(priv, mctx); if (data != NULL) isc_mem_put(mctx, data, MAXFIELDSIZE); @@ -436,11 +480,13 @@ dst__privstruct_writefile(const dst_key_t *key, const dst_private_t *priv, { FILE *fp; int ret, i; - isc_result_t iret; + isc_result_t result; char filename[ISC_DIR_NAMEMAX]; char buffer[MAXFIELDSIZE * 2]; - isc_buffer_t b; isc_fsaccess_t access; + isc_stdtime_t when; + isc_buffer_t b; + isc_region_t r; REQUIRE(priv != NULL); @@ -480,6 +526,12 @@ dst__privstruct_writefile(const dst_key_t *key, const dst_private_t *priv, case DST_ALG_RSASHA1: fprintf(fp, "(RSASHA1)\n"); break; + case DST_ALG_NSEC3RSASHA1: + fprintf(fp, "(NSEC3RSASHA1)\n"); + break; + case DST_ALG_NSEC3DSA: + fprintf(fp, "(NSEC3DSA)\n"); + break; case DST_ALG_HMACMD5: fprintf(fp, "(HMAC_MD5)\n"); break; @@ -498,20 +550,12 @@ dst__privstruct_writefile(const dst_key_t *key, const dst_private_t *priv, case DST_ALG_HMACSHA512: fprintf(fp, "(HMAC_SHA512)\n"); break; - case DST_ALG_NSEC3DSA: - fprintf(fp, "(NSEC3DSA)\n"); - break; - case DST_ALG_NSEC3RSASHA1: - fprintf(fp, "(NSEC3RSASHA1)\n"); - break; default: fprintf(fp, "(?)\n"); break; } for (i = 0; i < priv->nelements; i++) { - isc_buffer_t b; - isc_region_t r; const char *s; s = find_tag(priv->elements[i].tag); @@ -519,8 +563,8 @@ dst__privstruct_writefile(const dst_key_t *key, const dst_private_t *priv, r.base = priv->elements[i].data; r.length = priv->elements[i].length; isc_buffer_init(&b, buffer, sizeof(buffer)); - iret = isc_base64_totext(&r, sizeof(buffer), "", &b); - if (iret != ISC_R_SUCCESS) { + result = isc_base64_totext(&r, sizeof(buffer), "", &b); + if (result != ISC_R_SUCCESS) { fclose(fp); return (DST_R_INVALIDPRIVATEKEY); } @@ -531,10 +575,28 @@ dst__privstruct_writefile(const dst_key_t *key, const dst_private_t *priv, fprintf(fp, "\n"); } + /* Add the timing metadata tags */ + for (i = 0; i < METADATA_NTAGS; i++) { + result = dst_key_gettime(key, i, &when); + if (result != ISC_R_SUCCESS) + continue; + + isc_buffer_init(&b, buffer, sizeof(buffer)); + result = dns_time32_totext(when, &b); + if (result != ISC_R_SUCCESS) + continue; + + isc_buffer_usedregion(&b, &r); + + fprintf(fp, "%s ", metatags[i]); + fwrite(r.base, 1, r.length, fp); + fprintf(fp, "\n"); + } + fflush(fp); - iret = ferror(fp) ? DST_R_WRITEERROR : ISC_R_SUCCESS; + result = ferror(fp) ? DST_R_WRITEERROR : ISC_R_SUCCESS; fclose(fp); - return (iret); + return (result); } /*! \file */ diff --git a/lib/dns/dst_parse.h b/lib/dns/dst_parse.h index 27c7580e54..effc4c6af4 100644 --- a/lib/dns/dst_parse.h +++ b/lib/dns/dst_parse.h @@ -29,7 +29,7 @@ * IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ -/* $Id: dst_parse.h,v 1.11 2008/05/15 00:50:26 each Exp $ */ +/* $Id: dst_parse.h,v 1.12 2009/07/19 04:18:05 each Exp $ */ /*! \file */ #ifndef DST_DST_PARSE_H @@ -40,10 +40,15 @@ #include #define MAJOR_VERSION 1 -#define MINOR_VERSION 2 +#define MINOR_VERSION 3 #define MAXFIELDSIZE 512 -#define MAXFIELDS 12 + +/* + * Maximum number of fields in a private file is 18 (12 algorithm- + * specific fields for RSA, plus 6 generic fields). + */ +#define MAXFIELDS 12+6 #define TAG_SHIFT 4 #define TAG_ALG(tag) ((unsigned int)(tag) >> TAG_SHIFT) diff --git a/lib/dns/include/dns/db.h b/lib/dns/include/dns/db.h index db396bed7b..5e3c214d1e 100644 --- a/lib/dns/include/dns/db.h +++ b/lib/dns/include/dns/db.h @@ -15,7 +15,7 @@ * PERFORMANCE OF THIS SOFTWARE. */ -/* $Id: db.h,v 1.98 2009/06/30 02:52:32 each Exp $ */ +/* $Id: db.h,v 1.99 2009/07/19 04:18:05 each Exp $ */ #ifndef DNS_DB_H #define DNS_DB_H 1 @@ -493,6 +493,10 @@ dns_db_load(dns_db_t *db, const char *filename); isc_result_t dns_db_load2(dns_db_t *db, const char *filename, dns_masterformat_t format); + +isc_result_t +dns_db_load3(dns_db_t *db, const char *filename, dns_masterformat_t format, + unsigned int options); /*%< * Load master file 'filename' into 'db'. * diff --git a/lib/dns/include/dns/dnssec.h b/lib/dns/include/dns/dnssec.h index 09ada3cd2c..ea1c916761 100644 --- a/lib/dns/include/dns/dnssec.h +++ b/lib/dns/include/dns/dnssec.h @@ -15,7 +15,7 @@ * PERFORMANCE OF THIS SOFTWARE. */ -/* $Id: dnssec.h,v 1.34 2009/06/04 02:56:47 tbox Exp $ */ +/* $Id: dnssec.h,v 1.35 2009/07/19 04:18:05 each Exp $ */ #ifndef DNS_DNSSEC_H #define DNS_DNSSEC_H 1 @@ -31,6 +31,38 @@ ISC_LANG_BEGINDECLS +/* + * Indicates how the signer found this key: in the key repository, at the + * zone apex, or specified by the user. + */ +typedef enum { + dns_keysource_unknown, + dns_keysource_repository, + dns_keysource_zoneapex, + dns_keysource_user +} dns_keysource_t; + +/* + * A DNSSEC key and hints about its intended use gleaned from metadata + */ +struct dns_dnsseckey { + dst_key_t *key; + isc_boolean_t hint_publish; /*% metadata says to publish */ + isc_boolean_t force_publish; /*% publish regardless of metadata */ + isc_boolean_t hint_sign; /*% metadata says to sign with this key */ + isc_boolean_t force_sign; /*% sign with key regardless of metadata */ + isc_boolean_t hint_remove; /*% metadata says *don't* publish */ + dns_keysource_t source; /*% how the key was found */ + isc_boolean_t ksk; /*% this is a key-signing key */ + isc_boolean_t legacy; /*% this is old-style key with no + metadata (possibly generated by + an older version of BIND9) and + should be ignored when searching + for keys to import into the zone */ + unsigned int index; /*% position in list */ + ISC_LINK(dns_dnsseckey_t) link; +}; + isc_result_t dns_dnssec_keyfromrdata(dns_name_t *name, dns_rdata_t *rdata, isc_mem_t *mctx, dst_key_t **key); @@ -184,6 +216,54 @@ dns_dnssec_selfsigns(dns_rdata_t *rdata, dns_name_t *name, isc_boolean_t ignoretime, isc_mem_t *mctx); +isc_result_t +dns_dnsseckey_create(isc_mem_t *mctx, dst_key_t **dstkey, + dns_dnsseckey_t **dkp); +/*%< + * Create and initialize a dns_dnsseckey_t structure. + * + * Requires: + *\li 'dkp' is not NULL and '*dkp' is NULL. + * + * Returns: + *\li #ISC_R_SUCCESS + *\li #ISC_R_NOMEMORY + */ + +void +dns_dnsseckey_destroy(isc_mem_t *mctx, dns_dnsseckey_t **dkp); +/*%< + * Reclaim a dns_dnsseckey_t structure. + * + * Requires: + *\li 'dkp' is not NULL and '*dkp' is not NULL. + * + * Ensures: + *\li '*dkp' is NULL. + */ + +isc_result_t +dns_dnssec_findmatchingkeys(dns_name_t *origin, const char *directory, + isc_mem_t *mctx, dns_dnsseckeylist_t *keylist); +/*%< + * Search 'directory' for K* key files matching the name in 'origin'. + * Append all such keys, along with use hints gleaned from their + * metadata, onto 'keylist'. + * + * Requires: + *\li 'keylist' is not NULL + * + * Returns: + *\li #ISC_R_SUCCESS + *\li #ISC_R_NOTFOUND + *\li #ISC_R_NOMEMORY + *\li any error returned by dns_name_totext(), isc_dir_open(), or + * dst_key_fromnamedfile() + * + * Ensures: + *\li On error, keylist is unchanged + */ + ISC_LANG_ENDDECLS #endif /* DNS_DNSSEC_H */ diff --git a/lib/dns/include/dns/types.h b/lib/dns/include/dns/types.h index d6d97b05af..2e100d317e 100644 --- a/lib/dns/include/dns/types.h +++ b/lib/dns/include/dns/types.h @@ -15,7 +15,7 @@ * PERFORMANCE OF THIS SOFTWARE. */ -/* $Id: types.h,v 1.134 2009/06/30 02:52:32 each Exp $ */ +/* $Id: types.h,v 1.135 2009/07/19 04:18:05 each Exp $ */ #ifndef DNS_TYPES_H #define DNS_TYPES_H 1 @@ -63,6 +63,8 @@ typedef struct dns_dispatchevent dns_dispatchevent_t; typedef struct dns_dispatchlist dns_dispatchlist_t; typedef struct dns_dispatchmgr dns_dispatchmgr_t; typedef struct dns_dispentry dns_dispentry_t; +typedef struct dns_dnsseckey dns_dnsseckey_t; +typedef ISC_LIST(dns_dnsseckey_t) dns_dnsseckeylist_t; typedef struct dns_dumpctx dns_dumpctx_t; typedef struct dns_fetch dns_fetch_t; typedef struct dns_fixedname dns_fixedname_t; diff --git a/lib/dns/include/dst/dst.h b/lib/dns/include/dst/dst.h index b122a6addb..0236248f60 100644 --- a/lib/dns/include/dst/dst.h +++ b/lib/dns/include/dst/dst.h @@ -15,7 +15,7 @@ * PERFORMANCE OF THIS SOFTWARE. */ -/* $Id: dst.h,v 1.15 2009/06/30 02:52:32 each Exp $ */ +/* $Id: dst.h,v 1.16 2009/07/19 04:18:05 each Exp $ */ #ifndef DST_DST_H #define DST_DST_H 1 @@ -23,6 +23,7 @@ /*! \file dst/dst.h */ #include +#include #include @@ -78,6 +79,15 @@ typedef struct dst_context dst_context_t; #define DST_TYPE_PRIVATE 0x2000000 #define DST_TYPE_PUBLIC 0x4000000 +/* Key timing metadata definitions */ +#define DST_TIME_CREATED 0 +#define DST_TIME_PUBLISH 1 +#define DST_TIME_ACTIVATE 2 +#define DST_TIME_REVOKE 3 +#define DST_TIME_REMOVE 4 +#define DST_TIME_DELETE 5 +#define DST_MAX_TIMES 5 + /*** *** Functions ***/ @@ -242,13 +252,17 @@ dst_key_fromfile(dns_name_t *name, dns_keytag_t id, unsigned int alg, int type, */ isc_result_t -dst_key_fromnamedfile(const char *filename, int type, isc_mem_t *mctx, - dst_key_t **keyp); +dst_key_fromnamedfile(const char *filename, const char *dirname, + int type, isc_mem_t *mctx, dst_key_t **keyp); /*%< * Reads a key from permanent storage. The key can either be a public or * key, and is specified by filename. If a private key is specified, the * public key must also be present. * + * If 'dirname' is not NULL, and 'filename' is a relative path, + * then the file is looked up relative to the given directory. + * If 'filename' is an absolute path, 'dirname' is ignored. + * * Requires: * \li "filename" is not NULL * \li "type" is DST_TYPE_PUBLIC, DST_TYPE_PRIVATE, or the bitwise union @@ -623,7 +637,7 @@ dst_region_computeid(const isc_region_t *source, unsigned int alg); isc_uint16_t dst_key_getbits(const dst_key_t *key); -/* +/*%< * Get the number of digest bits required (0 == MAX). * * Requires: @@ -632,7 +646,7 @@ dst_key_getbits(const dst_key_t *key); void dst_key_setbits(dst_key_t *key, isc_uint16_t bits); -/* +/*%< * Set the number of digest bits required (0 == MAX). * * Requires: @@ -648,6 +662,27 @@ dst_key_setflags(dst_key_t *key, isc_uint32_t flags); * "key" is a valid key. */ +isc_result_t +dst_key_gettime(const dst_key_t *key, int type, isc_stdtime_t *timep); +/*%< + * Get a member of the timing metadata array and place it in '*timep'. + * + * Requires: + * "key" is a valid key. + * "type" is no larger than DST_MAX_TIMES + * "timep" is not null. + */ + +void +dst_key_settime(dst_key_t *key, int type, isc_stdtime_t when); +/*%< + * Set a member of the timing metadata array. + * + * Requires: + * "key" is a valid key. + * "type" is no larger than DST_MAX_TIMES + */ + ISC_LANG_ENDDECLS #endif /* DST_DST_H */ diff --git a/lib/dns/opensslrsa_link.c b/lib/dns/opensslrsa_link.c index 8f0733d2a8..131b4cb520 100644 --- a/lib/dns/opensslrsa_link.c +++ b/lib/dns/opensslrsa_link.c @@ -17,7 +17,7 @@ /* * Principal Author: Brian Wellington - * $Id: opensslrsa_link.c,v 1.23 2009/01/17 14:41:43 fdupont Exp $ + * $Id: opensslrsa_link.c,v 1.24 2009/07/19 04:18:05 each Exp $ */ #ifdef OPENSSL #ifndef USE_EVP @@ -751,8 +751,9 @@ opensslrsa_tofile(const dst_key_t *key, const char *directory) { i++; } + priv.nelements = i; - result = dst__privstruct_writefile(key, &priv, directory); + result = dst__privstruct_writefile(key, &priv, directory); fail: #if USE_EVP RSA_free(rsa); diff --git a/version b/version index 8ff4c904dd..80321bfc0f 100644 --- a/version +++ b/version @@ -1,4 +1,4 @@ -# $Id: version,v 1.45 2009/06/12 02:33:21 each Exp $ +# $Id: version,v 1.46 2009/07/19 04:18:03 each Exp $ # # This file must follow /bin/sh rules. It is imported directly via # configure. @@ -7,4 +7,4 @@ MAJORVER=9 MINORVER=7 PATCHVER=0 RELEASETYPE=a -RELEASEVER=1 +RELEASEVER=2