Commit 553ead32 authored by Evan Hunt's avatar Evan Hunt

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]
parent 4a979d35
--- 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]
......
......@@ -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:
- 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.)
BIND 9.7.0 includes a number of changes from BIND 9.6 and earlier
releases. Most are intended to simplify DNSSEC configuration.
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
......
......@@ -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);
......
......@@ -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::
......
......@@ -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 <dns/ds.h>
#include <dns/fixedname.h>
#include <dns/log.h>
#include <dns/keyvalues.h>
#include <dns/master.h>
#include <dns/name.h>
#include <dns/rdata.h>
#include <dns/rdataclass.h>
......@@ -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)
{
isc_result_t result;
char filename[1024];
isc_buffer_t buf;
dns_rdataset_init(&keyset);
dns_fixedname_init(&fixed);
name = dns_fixedname_name(&fixed);
static isc_result_t
initname(char *setname) {
isc_result_t result;
isc_buffer_t buf;
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);
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);
}
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, "/");
}
}
static isc_result_t
loadsetfromfile(char *filename, dns_rdataset_t *rdataset) {
isc_result_t result;
dns_db_t *db = NULL;
dns_dbnode_t *node = NULL;
char setname[DNS_NAME_FORMATSIZE];
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 <verbose level>\n");
fprintf(stderr, " -K <directory>: 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-<dnsname> 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);
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];
for (result = dns_rdataset_first(&keyset);
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();
......
......@@ -17,7 +17,7 @@
- PERFORMANCE OF THIS SOFTWARE.
-->
<!-- $Id: dnssec-dsfromkey.docbook,v 1.8 2009/06/17 23:53:04 tbox Exp $ -->
<!-- $Id: dnssec-dsfromkey.docbook,v 1.9 2009/07/19 04:18:04 each Exp $ -->
<refentry id="man.dnssec-dsfromkey">
<refentryinfo>
<date>November 29, 2008</date>
......@@ -54,12 +54,15 @@
<cmdsynopsis>
<command>dnssec-dsfromkey</command>
<arg choice="req">-s</arg>
<arg><option>-v <replaceable class="parameter">level</replaceable></option></arg>
<arg><option>-1</option></arg>
<arg><option>-2</option></arg>
<arg><option>-a <replaceable class="parameter">alg</replaceable></option></arg>
<arg><option>-K <replaceable class="parameter">directory</replaceable></option></arg>
<arg><option>-s</option></arg>
<arg><option>-c <replaceable class="parameter">class</replaceable></option></arg>
<arg><option>-d <replaceable class="parameter">dir</replaceable></option></arg>
<arg><option>-f <replaceable class="parameter">file</replaceable></option></arg>
<arg><option>-A</option></arg>
<arg><option>-v <replaceable class="parameter">level</replaceable></option></arg>
<arg choice="req">dnsname</arg>
</cmdsynopsis>
</refsynopsisdiv>
......@@ -107,10 +110,35 @@
</varlistentry>
<varlistentry>
<term>-v <replaceable class="parameter">level</replaceable></term>
<term>-K <replaceable class="parameter">directory</replaceable></term>
<listitem>
<para>
Sets the debugging level.
Look for key files (or, in keyset mode,
<filename>keyset-</filename> files) in
<option>directory</option>.
</para>
</listitem>
</varlistentry>
<varlistentry>
<term>-f <replaceable class="parameter">file</replaceable></term>
<listitem>
<para>
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 <option>file</option>. If the zone name is the same as
<option>file</option>, then it may be omitted.
</para>
</listitem>
</varlistentry>
<varlistentry>
<term>-A</term>
<listitem>
<para>
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.
</para>
</listitem>
</varlistentry>
......@@ -131,8 +159,7 @@
<listitem>
<para>
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.
</para>
</listitem>
</varlistentry>
......@@ -141,23 +168,20 @@
<term>-c <replaceable class="parameter">class</replaceable></term>
<listitem>
<para>
Specifies the DNS class (default is IN), useful only
in the keyset mode.