2
0
mirror of https://gitlab.isc.org/isc-projects/bind9 synced 2025-09-01 06:55:30 +00:00

3642. [func] Allow externally generated DNSKEY to be imported

into the DNSKEY management framework.  A new tool
                        dnssec-importkey is used to this. [RT #34698]
This commit is contained in:
Mark Andrews
2013-09-04 13:53:02 +10:00
parent b5f4cc132e
commit 0c91911b4d
28 changed files with 1107 additions and 82 deletions

View File

@@ -1,3 +1,7 @@
3642. [func] Allow externally generated DNSKEY to be imported
into the DNSKEY management framework. A new tool
dnssec-importkey is used to this. [RT #34698]
3641. [bug] Handle changes to sig-validity-interval settings 3641. [bug] Handle changes to sig-validity-interval settings
better. [RT #34625] better. [RT #34625]

View File

@@ -7,4 +7,5 @@ dnssec-settime
dnssec-signkey dnssec-signkey
dnssec-signzone dnssec-signzone
dnssec-verify dnssec-verify
dnssec-importkey
.libs .libs

View File

@@ -45,13 +45,13 @@ NOSYMLIBS = ${DNSLIBS} ${ISCNOSYMLIBS} @LIBS@
TARGETS = dnssec-keygen@EXEEXT@ dnssec-signzone@EXEEXT@ \ TARGETS = dnssec-keygen@EXEEXT@ dnssec-signzone@EXEEXT@ \
dnssec-keyfromlabel@EXEEXT@ dnssec-dsfromkey@EXEEXT@ \ dnssec-keyfromlabel@EXEEXT@ dnssec-dsfromkey@EXEEXT@ \
dnssec-revoke@EXEEXT@ dnssec-settime@EXEEXT@ \ dnssec-revoke@EXEEXT@ dnssec-settime@EXEEXT@ \
dnssec-verify@EXEEXT@ dnssec-verify@EXEEXT@ dnssec-importkey@EXEEXT@
OBJS = dnssectool.@O@ OBJS = dnssectool.@O@
SRCS = dnssec-dsfromkey.c dnssec-keyfromlabel.c dnssec-keygen.c \ SRCS = dnssec-dsfromkey.c dnssec-keyfromlabel.c dnssec-keygen.c \
dnssec-revoke.c dnssec-settime.c dnssec-signzone.c \ dnssec-revoke.c dnssec-settime.c dnssec-signzone.c \
dnssec-verify.c dnssectool.c dnssec-verify.c dnssec-importkey.c dnssectool.c
MANPAGES = dnssec-dsfromkey.8 dnssec-keyfromlabel.8 dnssec-keygen.8 \ MANPAGES = dnssec-dsfromkey.8 dnssec-keyfromlabel.8 dnssec-keygen.8 \
dnssec-revoke.8 dnssec-settime.8 dnssec-signzone.8 \ dnssec-revoke.8 dnssec-settime.8 dnssec-signzone.8 \
@@ -102,6 +102,10 @@ dnssec-settime@EXEEXT@: dnssec-settime.@O@ ${OBJS} ${DEPLIBS}
${LIBTOOL_MODE_LINK} ${PURIFY} ${CC} ${CFLAGS} ${LDFLAGS} -o $@ \ ${LIBTOOL_MODE_LINK} ${PURIFY} ${CC} ${CFLAGS} ${LDFLAGS} -o $@ \
dnssec-settime.@O@ ${OBJS} ${LIBS} dnssec-settime.@O@ ${OBJS} ${LIBS}
dnssec-importkey@EXEEXT@: dnssec-importkey.@O@ ${OBJS} ${DEPLIBS}
${LIBTOOL_MODE_LINK} ${PURIFY} ${CC} ${CFLAGS} ${LDFLAGS} -o $@ \
dnssec-importkey.@O@ ${OBJS} ${LIBS}
doc man:: ${MANOBJS} doc man:: ${MANOBJS}
docclean manclean maintainer-clean:: docclean manclean maintainer-clean::

View File

@@ -0,0 +1,112 @@
.\" Copyright (C) 2013 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$
.\"
.hy 0
.ad l
'\" t
.\" Title: dnssec-importkey
.\" Author: [see the "AUTHOR" section]
.\" Generator: DocBook XSL Stylesheets v1.78.1 <http://docbook.sf.net/>
.\" Date: August 30, 2013
.\" Manual: BIND9
.\" Source: BIND9
.\" Language: English
.\"
.TH "DNSSEC\-IMPORTKEY" "8" "August 30, 2013" "BIND9" "BIND9"
.\" -----------------------------------------------------------------
.\" * Define some portability stuff
.\" -----------------------------------------------------------------
.\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
.\" http://bugs.debian.org/507673
.\" http://lists.gnu.org/archive/html/groff/2009-02/msg00013.html
.\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
.ie \n(.g .ds Aq \(aq
.el .ds Aq '
.\" -----------------------------------------------------------------
.\" * set default formatting
.\" -----------------------------------------------------------------
.\" disable hyphenation
.nh
.\" disable justification (adjust text to left margin only)
.ad l
.\" -----------------------------------------------------------------
.\" * MAIN CONTENT STARTS HERE *
.\" -----------------------------------------------------------------
.SH "NAME"
dnssec-importkey \- Import DNSKEY records from external systems so they can be managed\&.
.SH "SYNOPSIS"
.HP 17
\fBdnssec\-importkey\fR [\fB\-f\ \fR\fB\fIfilename\fR\fR] [\fB\-K\ \fR\fB\fIdirectory\fR\fR] [\fB\-P\ \fR\fB\fIdate/offset\fR\fR] [\fB\-D\ \fR\fB\fIdate/offset\fR\fR] [\fB\-h\fR] [\fB\-v\ \fR\fB\fIlevel\fR\fR] [\fBkeyname\fR]
.SH "DESCRIPTION"
.PP
\fBdnssec\-importkey\fR
read a DNSKEY record and generated a \&.key/\&.private key pair\&. Publication (\fB\-P\fR) and deletions (\fB\-D\fR) times can be set for the key\&.
.SH "OPTIONS"
.PP
\-f \fIfilename\fR
.RS 4
Filename to read the key from\&.
.RE
.PP
\-K \fIdirectory\fR
.RS 4
Sets the directory in which the key files are to reside\&.
.RE
.PP
\-L \fIttl\fR
.RS 4
Sets the default TTL to use for this key when it is converted into a DNSKEY RR\&. If the key is imported into a zone, this is the TTL that will be used for it, unless there was already a DNSKEY RRset in place, in which case the existing TTL would take precedence\&. importkey the default TTL to
0
or
none
removes it\&.
.RE
.PP
\-h
.RS 4
Emit usage message and exit\&.
.RE
.PP
\-v \fIlevel\fR
.RS 4
Sets the debugging level\&.
.RE
.SH "TIMING OPTIONS"
.PP
Dates can be expressed in the format YYYYMMDD or YYYYMMDDHHMMSS\&. If the argument begins with a \*(Aq+\*(Aq or \*(Aq\-\*(Aq, it is interpreted as an offset from the present time\&. For convenience, if such an offset is followed by one of the suffixes \*(Aqy\*(Aq, \*(Aqmo\*(Aq, \*(Aqw\*(Aq, \*(Aqd\*(Aq, \*(Aqh\*(Aq, or \*(Aqmi\*(Aq, then the offset is computed in years (defined as 365 24\-hour days, ignoring leap years), months (defined as 30 24\-hour days), weeks, days, hours, or minutes, respectively\&. Without a suffix, the offset is computed in seconds\&. To unset a date, use \*(Aqnone\*(Aq\&.
.PP
\-P \fIdate/offset\fR
.RS 4
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\&.
.RE
.PP
\-D \fIdate/offset\fR
.RS 4
Sets the date on which the key is to be deleted\&. After that date, the key will no longer be included in the zone\&. (It may remain in the key repository, however\&.)
.RE
.SH "SEE ALSO"
.PP
\fBdnssec-keygen\fR(8),
\fBdnssec-signzone\fR(8),
BIND 9 Administrator Reference Manual,
RFC 5011\&.
.SH "AUTHOR"
.PP
Internet Systems Consortium
.SH "COPYRIGHT"
.br
Copyright \(co 2013 Internet Systems Consortium, Inc. ("ISC")
.br

View File

@@ -0,0 +1,399 @@
/*
* Copyright (C) 2008-2012 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.
*/
/*! \file */
#include <config.h>
#include <stdlib.h>
#include <isc/buffer.h>
#include <isc/commandline.h>
#include <isc/entropy.h>
#include <isc/hash.h>
#include <isc/mem.h>
#include <isc/print.h>
#include <isc/string.h>
#include <isc/util.h>
#include <dns/callbacks.h>
#include <dns/db.h>
#include <dns/dbiterator.h>
#include <dns/ds.h>
#include <dns/fixedname.h>
#include <dns/keyvalues.h>
#include <dns/log.h>
#include <dns/master.h>
#include <dns/name.h>
#include <dns/rdata.h>
#include <dns/rdataclass.h>
#include <dns/rdataset.h>
#include <dns/rdatasetiter.h>
#include <dns/rdatatype.h>
#include <dns/result.h>
#include <dst/dst.h>
#include "dnssectool.h"
#ifndef PATH_MAX
#define PATH_MAX 1024 /* AIX, WIN32, and others don't define this. */
#endif
const char *program = "dnssec-importkey";
int verbose;
static dns_rdataclass_t rdclass;
static dns_fixedname_t fixed;
static dns_name_t *name = NULL;
static isc_mem_t *mctx = NULL;
static isc_boolean_t setpub = ISC_FALSE, setdel = ISC_FALSE;
static isc_stdtime_t pub = 0, del = 0;
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, 0, NULL);
return (result);
}
static void
db_load_from_stream(dns_db_t *db, FILE *fp) {
isc_result_t result;
dns_rdatacallbacks_t callbacks;
dns_rdatacallbacks_init(&callbacks);
result = dns_db_beginload(db, &callbacks);
if (result != ISC_R_SUCCESS)
fatal("dns_db_beginload failed: %s", isc_result_totext(result));
result = dns_master_loadstream(fp, name, name, rdclass, 0,
&callbacks, mctx);
if (result != ISC_R_SUCCESS)
fatal("can't load from input: %s", isc_result_totext(result));
result = dns_db_endload(db, &callbacks);
if (result != ISC_R_SUCCESS)
fatal("dns_db_endload failed: %s", isc_result_totext(result));
}
static isc_result_t
loadset(const 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];
dns_name_format(name, setname, sizeof(setname));
result = dns_db_create(mctx, "rbt", name, dns_dbtype_zone,
rdclass, 0, NULL, &db);
if (result != ISC_R_SUCCESS)
fatal("can't create database");
if (strcmp(filename, "-") == 0) {
db_load_from_stream(db, stdin);
filename = "input";
} else {
result = dns_db_load3(db, filename, dns_masterformat_text,
DNS_MASTER_NOTTL);
if (result != ISC_R_SUCCESS && result != DNS_R_SEENINCLUDE)
fatal("can't load %s: %s", filename,
isc_result_totext(result));
}
result = dns_db_findnode(db, name, ISC_FALSE, &node);
if (result != ISC_R_SUCCESS)
fatal("can't find %s node in %s", setname, filename);
result = dns_db_findrdataset(db, node, NULL, dns_rdatatype_dnskey,
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 void
loadkey(char *filename, unsigned char *key_buf, unsigned int key_buf_size,
dns_rdata_t *rdata)
{
isc_result_t result;
dst_key_t *key = NULL;
isc_buffer_t keyb;
isc_region_t r;
dns_rdata_init(rdata);
isc_buffer_init(&keyb, key_buf, key_buf_size);
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));
if (verbose > 2) {
char keystr[DST_KEY_FORMATSIZE];
dst_key_format(key, keystr, sizeof(keystr));
fprintf(stderr, "%s: %s\n", program, keystr);
}
result = dst_key_todns(key, &keyb);
if (result != ISC_R_SUCCESS)
fatal("can't decode key");
isc_buffer_usedregion(&keyb, &r);
dns_rdata_fromregion(rdata, dst_key_class(key),
dns_rdatatype_dnskey, &r);
rdclass = dst_key_class(key);
dns_fixedname_init(&fixed);
name = dns_fixedname_name(&fixed);
result = dns_name_copy(dst_key_name(key), name, NULL);
if (result != ISC_R_SUCCESS)
fatal("can't copy name");
dst_key_free(&key);
}
static void
emit(const char *dir, dns_rdata_t *rdata) {
isc_result_t result;
char keystr[DST_KEY_FORMATSIZE];
char newname[1024];
isc_buffer_t buf;
dst_key_t *key = NULL;
isc_buffer_init(&buf, rdata->data, rdata->length);
isc_buffer_add(&buf, rdata->length);
result = dst_key_fromdns(name, rdclass, &buf, mctx, &key);
if (result != ISC_R_SUCCESS) {
fatal("dst_key_fromdns: %s", isc_result_totext(result));
}
dst_key_setexternal(key, ISC_TRUE);
if (setpub)
dst_key_settime(key, DST_TIME_PUBLISH, pub);
if (setdel)
dst_key_settime(key, DST_TIME_DELETE, del);
isc_buffer_init(&buf, newname, sizeof(newname));
result = dst_key_buildfilename(key, DST_TYPE_PUBLIC, dir, &buf);
if (result != ISC_R_SUCCESS) {
fatal("Failed to build public key filename: %s",
isc_result_totext(result));
}
result = dst_key_tofile(key, DST_TYPE_PUBLIC|DST_TYPE_PRIVATE,
dir);
if (result != ISC_R_SUCCESS) {
dst_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);
result = dst_key_buildfilename(key, DST_TYPE_PRIVATE, dir, &buf);
if (result != ISC_R_SUCCESS) {
fatal("Failed to build private key filename: %s",
isc_result_totext(result));
}
printf("%s\n", newname);
dst_key_free(&key);
}
ISC_PLATFORM_NORETURN_PRE static void
usage(void) ISC_PLATFORM_NORETURN_POST;
static void
usage(void) {
fprintf(stderr, "Usage:\n");
fprintf(stderr, " %s options [-K dir] file\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 store "
"the keyset files\n");
fprintf(stderr, " -f file: read keyset from zone file\n");
exit (-1);
}
int
main(int argc, char **argv) {
char *classname = NULL;
char *filename = NULL, *dir = NULL, *namestr;
char *endp;
int ch;
isc_result_t result;
isc_log_t *log = NULL;
isc_entropy_t *ectx = NULL;
dns_rdataset_t rdataset;
dns_rdata_t rdata;
isc_stdtime_t now;
dns_rdata_init(&rdata);
isc_stdtime_get(&now);
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;
while ((ch = isc_commandline_parse(argc, argv, "D:f:hK:P:v:")) != -1) {
switch (ch) {
case 'D':
if (setdel)
fatal("-D specified more than once");
setdel = ISC_TRUE;
del = strtotime(isc_commandline_argument, now, now);
break;
case 'K':
dir = isc_commandline_argument;
if (strlen(dir) == 0U)
fatal("directory must be non-empty string");
break;
case 'P':
if (setpub)
fatal("-P specified more than once");
setpub = ISC_TRUE;
pub = strtotime(isc_commandline_argument, now, now);
break;
case 'f':
filename = 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 '?':
if (isc_commandline_option != '?')
fprintf(stderr, "%s: invalid argument -%c\n",
program, isc_commandline_option);
/* FALLTHROUGH */
case 'h':
usage();
default:
fprintf(stderr, "%s: unhandled option -%c\n",
program, isc_commandline_option);
exit(1);
}
}
rdclass = strtoclass(classname);
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");
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: %s",
isc_result_totext(result));
isc_entropy_stopcallbacksources(ectx);
setup_logging(verbose, mctx, &log);
dns_rdataset_init(&rdataset);
if (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);
result = loadset(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(&rdataset)) {
dns_rdata_init(&rdata);
dns_rdataset_current(&rdataset, &rdata);
emit(dir, &rdata);
}
} else {
unsigned char key_buf[DST_KEY_MAXSIZE];
loadkey(argv[isc_commandline_index], key_buf,
DST_KEY_MAXSIZE, &rdata);
emit(dir, &rdata);
}
if (dns_rdataset_isassociated(&rdataset))
dns_rdataset_disassociate(&rdataset);
cleanup_logging(&log);
dst_lib_destroy();
isc_hash_destroy();
cleanup_entropy(&ectx);
dns_name_destroy();
if (verbose > 10)
isc_mem_stats(mctx, stdout);
isc_mem_destroy(&mctx);
fflush(stdout);
if (ferror(stdout)) {
fprintf(stderr, "write error\n");
return (1);
} else
return (0);
}

View File

@@ -0,0 +1,185 @@
<!DOCTYPE book PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN"
"http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd"
[<!ENTITY mdash "&#8212;">]>
<!--
- Copyright (C) 2009-2011 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-importkey.docbook,v 1.15 2011/11/03 20:21:37 each Exp $ -->
<refentry id="man.dnssec-importkey">
<refentryinfo>
<date>August 30, 2013</date>
</refentryinfo>
<refmeta>
<refentrytitle><application>dnssec-importkey</application></refentrytitle>
<manvolnum>8</manvolnum>
<refmiscinfo>BIND9</refmiscinfo>
</refmeta>
<refnamediv>
<refname><application>dnssec-importkey</application></refname>
<refpurpose>Import DNSKEY records from external systems so they can be managed.</refpurpose>
</refnamediv>
<docinfo>
<copyright>
<year>2013</year>
<holder>Internet Systems Consortium, Inc. ("ISC")</holder>
</copyright>
</docinfo>
<refsynopsisdiv>
<cmdsynopsis>
<command>dnssec-importkey</command>
<arg><option>-f <replaceable class="parameter">filename</replaceable></option></arg>
<arg><option>-K <replaceable class="parameter">directory</replaceable></option></arg>
<arg><option>-P <replaceable class="parameter">date/offset</replaceable></option></arg>
<arg><option>-D <replaceable class="parameter">date/offset</replaceable></option></arg>
<arg><option>-h</option></arg>
<arg><option>-v <replaceable class="parameter">level</replaceable></option></arg>
<arg><option>keyname</option></arg>
</cmdsynopsis>
</refsynopsisdiv>
<refsect1>
<title>DESCRIPTION</title>
<para><command>dnssec-importkey</command>
read a DNSKEY record and generated a .key/.private key pair.
Publication (<option>-P</option>) and deletions (<option>-D</option>)
times can be set for the key.
</para>
</refsect1>
<refsect1>
<title>OPTIONS</title>
<variablelist>
<varlistentry>
<term>-f <replaceable class="parameter">filename</replaceable></term>
<listitem>
<para>
Filename to read the key from.
</para>
</listitem>
</varlistentry>
<varlistentry>
<term>-K <replaceable class="parameter">directory</replaceable></term>
<listitem>
<para>
Sets the directory in which the key files are to reside.
</para>
</listitem>
</varlistentry>
<varlistentry>
<term>-L <replaceable class="parameter">ttl</replaceable></term>
<listitem>
<para>
Sets the default TTL to use for this key when it is converted
into a DNSKEY RR. If the key is imported into a zone,
this is the TTL that will be used for it, unless there was
already a DNSKEY RRset in place, in which case the existing TTL
would take precedence. importkey the default TTL to
<literal>0</literal> or <literal>none</literal> removes it.
</para>
</listitem>
</varlistentry>
<varlistentry>
<term>-h</term>
<listitem>
<para>
Emit usage message and exit.
</para>
</listitem>
</varlistentry>
<varlistentry>
<term>-v <replaceable class="parameter">level</replaceable></term>
<listitem>
<para>
Sets the debugging level.
</para>
</listitem>
</varlistentry>
</variablelist>
</refsect1>
<refsect1>
<title>TIMING OPTIONS</title>
<para>
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. For convenience, if such an offset
is followed by one of the suffixes 'y', 'mo', 'w', 'd', 'h', or 'mi',
then the offset is computed in years (defined as 365 24-hour days,
ignoring leap years), months (defined as 30 24-hour days), weeks,
days, hours, or minutes, respectively. Without a suffix, the offset
is computed in seconds. To unset a date, use 'none'.
</para>
<variablelist>
<varlistentry>
<term>-P <replaceable class="parameter">date/offset</replaceable></term>
<listitem>
<para>
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.
</para>
</listitem>
</varlistentry>
<varlistentry>
<term>-D <replaceable class="parameter">date/offset</replaceable></term>
<listitem>
<para>
Sets the date on which the key is to be deleted. After that
date, the key will no longer be included in the zone. (It
may remain in the key repository, however.)
</para>
</listitem>
</varlistentry>
</variablelist>
</refsect1>
<refsect1>
<title>SEE ALSO</title>
<para><citerefentry>
<refentrytitle>dnssec-keygen</refentrytitle><manvolnum>8</manvolnum>
</citerefentry>,
<citerefentry>
<refentrytitle>dnssec-signzone</refentrytitle><manvolnum>8</manvolnum>
</citerefentry>,
<citetitle>BIND 9 Administrator Reference Manual</citetitle>,
<citetitle>RFC 5011</citetitle>.
</para>
</refsect1>
<refsect1>
<title>AUTHOR</title>
<para><corpauthor>Internet Systems Consortium</corpauthor>
</para>
</refsect1>
</refentry><!--
- Local variables:
- mode: sgml
- End:
-->

View File

@@ -0,0 +1,112 @@
<!--
- Copyright (C) 2013 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$ -->
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
<title>dnssec-importkey</title>
<meta name="generator" content="DocBook XSL Stylesheets V1.78.1">
</head>
<body bgcolor="white" text="black" link="#0000FF" vlink="#840084" alink="#0000FF"><div class="refentry">
<a name="man.dnssec-importkey"></a><div class="titlepage"></div>
<div class="refnamediv">
<h2>Name</h2>
<p><span class="application">dnssec-importkey</span> &#8212; Import DNSKEY records from external systems so they can be managed.</p>
</div>
<div class="refsynopsisdiv">
<h2>Synopsis</h2>
<div class="cmdsynopsis"><p><code class="command">dnssec-importkey</code> [<code class="option">-f <em class="replaceable"><code>filename</code></em></code>] [<code class="option">-K <em class="replaceable"><code>directory</code></em></code>] [<code class="option">-P <em class="replaceable"><code>date/offset</code></em></code>] [<code class="option">-D <em class="replaceable"><code>date/offset</code></em></code>] [<code class="option">-h</code>] [<code class="option">-v <em class="replaceable"><code>level</code></em></code>] [<code class="option">keyname</code>]</p></div>
</div>
<div class="refsect1">
<a name="idp5321760"></a><h2>DESCRIPTION</h2>
<p><span class="command"><strong>dnssec-importkey</strong></span>
read a DNSKEY record and generated a .key/.private key pair.
Publication (<code class="option">-P</code>) and deletions (<code class="option">-D</code>)
times can be set for the key.
</p>
</div>
<div class="refsect1">
<a name="idp5324080"></a><h2>OPTIONS</h2>
<div class="variablelist"><dl class="variablelist">
<dt><span class="term">-f <em class="replaceable"><code>filename</code></em></span></dt>
<dd><p>
Filename to read the key from.
</p></dd>
<dt><span class="term">-K <em class="replaceable"><code>directory</code></em></span></dt>
<dd><p>
Sets the directory in which the key files are to reside.
</p></dd>
<dt><span class="term">-L <em class="replaceable"><code>ttl</code></em></span></dt>
<dd><p>
Sets the default TTL to use for this key when it is converted
into a DNSKEY RR. If the key is imported into a zone,
this is the TTL that will be used for it, unless there was
already a DNSKEY RRset in place, in which case the existing TTL
would take precedence. importkey the default TTL to
<code class="literal">0</code> or <code class="literal">none</code> removes it.
</p></dd>
<dt><span class="term">-h</span></dt>
<dd><p>
Emit usage message and exit.
</p></dd>
<dt><span class="term">-v <em class="replaceable"><code>level</code></em></span></dt>
<dd><p>
Sets the debugging level.
</p></dd>
</dl></div>
</div>
<div class="refsect1">
<a name="idp5336224"></a><h2>TIMING OPTIONS</h2>
<p>
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. For convenience, if such an offset
is followed by one of the suffixes 'y', 'mo', 'w', 'd', 'h', or 'mi',
then the offset is computed in years (defined as 365 24-hour days,
ignoring leap years), months (defined as 30 24-hour days), weeks,
days, hours, or minutes, respectively. Without a suffix, the offset
is computed in seconds. To unset a date, use 'none'.
</p>
<div class="variablelist"><dl class="variablelist">
<dt><span class="term">-P <em class="replaceable"><code>date/offset</code></em></span></dt>
<dd><p>
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.
</p></dd>
<dt><span class="term">-D <em class="replaceable"><code>date/offset</code></em></span></dt>
<dd><p>
Sets the date on which the key is to be deleted. After that
date, the key will no longer be included in the zone. (It
may remain in the key repository, however.)
</p></dd>
</dl></div>
</div>
<div class="refsect1">
<a name="idp5342816"></a><h2>SEE ALSO</h2>
<p><span class="citerefentry"><span class="refentrytitle">dnssec-keygen</span>(8)</span>,
<span class="citerefentry"><span class="refentrytitle">dnssec-signzone</span>(8)</span>,
<em class="citetitle">BIND 9 Administrator Reference Manual</em>,
<em class="citetitle">RFC 5011</em>.
</p>
</div>
<div class="refsect1">
<a name="idp5346704"></a><h2>AUTHOR</h2>
<p><span class="corpauthor">Internet Systems Consortium</span>
</p>
</div>
</div></body>
</html>

View File

@@ -370,7 +370,7 @@ main(int argc, char **argv) {
if (result != ISC_R_SUCCESS) if (result != ISC_R_SUCCESS)
fatal("Invalid keyfile %s: %s", fatal("Invalid keyfile %s: %s",
filename, isc_result_totext(result)); filename, isc_result_totext(result));
if (!dst_key_isprivate(prevkey)) if (!dst_key_isprivate(prevkey) && !dst_key_isexternal(prevkey))
fatal("%s is not a private key", filename); fatal("%s is not a private key", filename);
name = dst_key_name(prevkey); name = dst_key_name(prevkey);
@@ -462,7 +462,7 @@ main(int argc, char **argv) {
fatal("Invalid keyfile %s: %s", fatal("Invalid keyfile %s: %s",
filename, isc_result_totext(result)); filename, isc_result_totext(result));
if (!dst_key_isprivate(key)) if (!dst_key_isprivate(key) && !dst_key_isexternal(key))
fatal("%s is not a private key", filename); fatal("%s is not a private key", filename);
dst_key_format(key, keystr, sizeof(keystr)); dst_key_format(key, keystr, sizeof(keystr));

View File

@@ -43,6 +43,7 @@ SIGNER=$TOP/bin/dnssec/dnssec-signzone
REVOKE=$TOP/bin/dnssec/dnssec-revoke REVOKE=$TOP/bin/dnssec/dnssec-revoke
SETTIME=$TOP/bin/dnssec/dnssec-settime SETTIME=$TOP/bin/dnssec/dnssec-settime
DSFROMKEY=$TOP/bin/dnssec/dnssec-dsfromkey DSFROMKEY=$TOP/bin/dnssec/dnssec-dsfromkey
IMPORTKEY=$TOP/bin/dnssec/dnssec-importkey
CHECKDS=$TOP/bin/python/dnssec-checkds CHECKDS=$TOP/bin/python/dnssec-checkds
COVERAGE=$TOP/bin/python/dnssec-coverage COVERAGE=$TOP/bin/python/dnssec-coverage
CHECKZONE=$TOP/bin/check/named-checkzone CHECKZONE=$TOP/bin/check/named-checkzone

View File

@@ -60,6 +60,9 @@ rm -f ns3/retransfer.bk
rm -f ns3/retransfer.bk.jnl rm -f ns3/retransfer.bk.jnl
rm -f ns3/retransfer.bk.signed rm -f ns3/retransfer.bk.signed
rm -f ns3/retransfer.bk.signed.jnl rm -f ns3/retransfer.bk.signed.jnl
rm -f ns3/externalkey.db
rm -f ns3/externalkey.db.signed
rm -f ns3/externalkey.db.signed.jnl
rm -f ns4/K* rm -f ns4/K*
rm -f ns4/noixfr.db rm -f ns4/noixfr.db
rm -f ns4/noixfr.db.jnl rm -f ns4/noixfr.db.jnl

View File

@@ -50,3 +50,6 @@ ns3.retransfer. A 10.53.0.3
nsec3. NS ns3.nsec3. nsec3. NS ns3.nsec3.
ns3.nsec3. A 10.53.0.3 ns3.nsec3. A 10.53.0.3
externalkey. NS ns3.externalkey.
ns3.externalkey. A 10.53.0.3

View File

@@ -103,3 +103,11 @@ zone "nsec3" {
allow-update { any; }; allow-update { any; };
file "nsec3.db"; file "nsec3.db";
}; };
zone "externalkey" {
type master;
inline-signing yes;
auto-dnssec maintain;
allow-update { any; };
file "externalkey.db";
};

View File

@@ -92,3 +92,32 @@ do
keyname=`$KEYGEN -q -r $RANDFILE -a RSASHA1 -b 768 -n zone $zone` keyname=`$KEYGEN -q -r $RANDFILE -a RSASHA1 -b 768 -n zone $zone`
keyname=`$KEYGEN -q -r $RANDFILE -a RSASHA1 -b 1024 -n zone -f KSK $zone` keyname=`$KEYGEN -q -r $RANDFILE -a RSASHA1 -b 1024 -n zone -f KSK $zone`
done done
zone=externalkey
rm -f K${zone}.+*+*.key
rm -f K${zone}.+*+*.private
for alg in ECDSAP256SHA256 NSEC3RSASHA1 DSA ECCGOST
do
if test $alg = ECCGOST
then
sh ../../gost/prereq.sh 2> /dev/null || continue
fi
k1=`$KEYGEN -q -r $RANDFILE -a $alg -b 1024 -n zone -f KSK $zone`
k2=`$KEYGEN -q -r $RANDFILE -a $alg -b 1024 -n zone $zone`
k3=`$KEYGEN -q -r $RANDFILE -a $alg -b 1024 -n zone $zone`
k4=`$KEYGEN -q -r $RANDFILE -a $alg -b 1024 -n zone $zone`
keyname=`$KEYGEN -q -r $RANDFILE -a $alg -b 1024 -n zone $zone`
keyname=`$KEYGEN -q -r $RANDFILE -a $alg -b 1024 -n zone -f KSK $zone`
$DSFROMKEY -T 1200 $keyname >> ../ns1/root.db
rm -f ${k3}.* ${k4}.*
#
# Convert k1 and k2 in to External Keys.
rm -f $k1.private
$IMPORTKEY -P now -D now+3600 -f $k1.key $zone
rm -f $k2.private
$IMPORTKEY -f $k2.key $zone
done

View File

@@ -29,6 +29,7 @@ cp ns3/master.db.in ns3/dynamic.db
cp ns3/master.db.in ns3/updated.db cp ns3/master.db.in ns3/updated.db
cp ns3/master.db.in ns3/expired.db cp ns3/master.db.in ns3/expired.db
cp ns3/master.db.in ns3/nsec3.db cp ns3/master.db.in ns3/nsec3.db
cp ns3/master.db.in ns3/externalkey.db
touch ns4/trusted.conf touch ns4/trusted.conf
cp ns4/noixfr.db.in ns4/noixfr.db cp ns4/noixfr.db.in ns4/noixfr.db

View File

@@ -809,7 +809,22 @@ $RNDC -c ../common/rndc.conf -s 10.53.0.3 -p 9953 addzone test-$zone \
$RNDC -c ../common/rndc.conf -s 10.53.0.3 -p 9953 delzone test-$zone $RNDC -c ../common/rndc.conf -s 10.53.0.3 -p 9953 delzone test-$zone
done done
if [ $ret != 0 ]; then echo "I:failed"; fi n=`expr $n + 1`
echo "I:testing adding external keys to a inline zone ($n)"
ret=0
$DIG $DIGOPTS @10.53.0.3 -p 5300 dnskey externalkey > dig.out.ns3.test$n
for alg in 3 7 12 13
do
if test $alg = 12
then
sh ../gost/prereq.sh 2>/dev/null || continue;
fi
dnskeys=`grep "IN.DNSKEY.25[67] [0-9]* $alg " dig.out.ns3.test$n | wc -l`
rrsigs=`grep "RRSIG.DNSKEY $alg " dig.out.ns3.test$n | wc -l`
test ${dnskeys:-0} -eq 3 || { echo "I: failed $alg (dnskeys ${dnskeys:-0})"; ret=1; }
test ${rrsigs:-0} -eq 2 || { echo "I: failed $alg (rrsigs ${rrsigs:-0})"; ret=1; }
done
status=`expr $status + $ret` status=`expr $status + $ret`
exit $status exit $status

View File

@@ -684,6 +684,7 @@ dns_dnssec_findzonekeys2(dns_db_t *db, dns_dbversion_t *ver,
isc_stdtime_get(&now); isc_stdtime_get(&now);
*nkeys = 0; *nkeys = 0;
memset(keys, 0, sizeof(*keys) * maxkeys);
dns_rdataset_init(&rdataset); dns_rdataset_init(&rdataset);
RETERR(dns_db_findrdataset(db, node, ver, dns_rdatatype_dnskey, 0, 0, RETERR(dns_db_findrdataset(db, node, ver, dns_rdatatype_dnskey, 0, 0,
&rdataset, NULL)); &rdataset, NULL));
@@ -1312,9 +1313,9 @@ dns_dnssec_findmatchingkeys(dns_name_t *origin, const char *directory,
isc_dir_t dir; isc_dir_t dir;
dns_dnsseckey_t *key = NULL; dns_dnsseckey_t *key = NULL;
dst_key_t *dstkey = NULL; dst_key_t *dstkey = NULL;
char namebuf[DNS_NAME_FORMATSIZE], *p; char namebuf[DNS_NAME_FORMATSIZE];
isc_buffer_t b; isc_buffer_t b;
unsigned int len; unsigned int len, i;
isc_stdtime_t now; isc_stdtime_t now;
REQUIRE(keylist != NULL); REQUIRE(keylist != NULL);
@@ -1334,49 +1335,62 @@ dns_dnssec_findmatchingkeys(dns_name_t *origin, const char *directory,
isc_stdtime_get(&now); isc_stdtime_get(&now);
while (isc_dir_read(&dir) == ISC_R_SUCCESS) { while (isc_dir_read(&dir) == ISC_R_SUCCESS) {
if (dir.entry.name[0] == 'K' && if (dir.entry.name[0] != 'K' ||
dir.entry.length > len + 1 && dir.entry.length < len + 1 ||
dir.entry.name[len + 1] == '+' && dir.entry.name[len + 1] != '+' ||
strncasecmp(dir.entry.name + 1, namebuf, len) == 0) { strncasecmp(dir.entry.name + 1, namebuf, len) != 0)
p = strrchr(dir.entry.name, '.'); continue;
if (p != NULL && strcmp(p, ".private") != 0)
for (i = len + 1 + 1; i < dir.entry.length ; i++)
if (dir.entry.name[i] < '0' || dir.entry.name[i] > '9')
break;
if (i == len + 1 + 1 || i >= dir.entry.length ||
dir.entry.name[i] != '+')
continue;
for (i++ ; i < dir.entry.length ; i++)
if (dir.entry.name[i] < '0' || dir.entry.name[i] > '9')
break;
if (strcmp(dir.entry.name + i, ".private") != 0)
continue; continue;
dstkey = NULL; dstkey = NULL;
result = dst_key_fromnamedfile(dir.entry.name, result = dst_key_fromnamedfile(dir.entry.name,
directory, directory,
DST_TYPE_PUBLIC | DST_TYPE_PUBLIC |
DST_TYPE_PRIVATE, DST_TYPE_PRIVATE,
mctx, &dstkey); mctx, &dstkey);
if (result != ISC_R_SUCCESS) { if (result != ISC_R_SUCCESS) {
isc_log_write(dns_lctx, isc_log_write(dns_lctx,
DNS_LOGCATEGORY_GENERAL, DNS_LOGCATEGORY_GENERAL,
DNS_LOGMODULE_DNSSEC, DNS_LOGMODULE_DNSSEC,
ISC_LOG_WARNING, ISC_LOG_WARNING,
"dns_dnssec_findmatchingkeys: " "dns_dnssec_findmatchingkeys: "
"error reading key file %s: %s", "error reading key file %s: %s",
dir.entry.name, dir.entry.name,
isc_result_totext(result)); isc_result_totext(result));
continue; continue;
} }
RETERR(dns_dnsseckey_create(mctx, &dstkey, &key)); RETERR(dns_dnsseckey_create(mctx, &dstkey, &key));
key->source = dns_keysource_repository; key->source = dns_keysource_repository;
get_hints(key, now); get_hints(key, now);
if (key->legacy) { if (key->legacy) {
dns_dnsseckey_destroy(mctx, &key); dns_dnsseckey_destroy(mctx, &key);
} else { } else {
ISC_LIST_APPEND(list, key, link); ISC_LIST_APPEND(list, key, link);
key = NULL; key = NULL;
}
} }
} }
if (!ISC_LIST_EMPTY(list)) if (!ISC_LIST_EMPTY(list)) {
result = ISC_R_SUCCESS;
ISC_LIST_APPENDLIST(*keylist, list, link); ISC_LIST_APPENDLIST(*keylist, list, link);
else } else
result = ISC_R_NOTFOUND; result = ISC_R_NOTFOUND;
failure: failure:
@@ -1794,7 +1808,13 @@ dns_dnssec_updatekeys(dns_dnsseckeylist_t *keys, dns_dnsseckeylist_t *newkeys,
for (key2 = ISC_LIST_HEAD(*keys); for (key2 = ISC_LIST_HEAD(*keys);
key2 != NULL; key2 != NULL;
key2 = ISC_LIST_NEXT(key2, link)) { key2 = ISC_LIST_NEXT(key2, link)) {
if (dst_key_pubcompare(key1->key, key2->key, int f1 = dst_key_flags(key1->key);
int f2 = dst_key_flags(key2->key);
int nr1 = f1 & ~DNS_KEYFLAG_REVOKE;
int nr2 = f2 & ~DNS_KEYFLAG_REVOKE;
if (nr1 == nr2 &&
dst_key_alg(key1->key) == dst_key_alg(key2->key) &&
dst_key_pubcompare(key1->key, key2->key,
ISC_TRUE)) { ISC_TRUE)) {
int r1, r2; int r1, r2;
r1 = dst_key_flags(key1->key) & r1 = dst_key_flags(key1->key) &

View File

@@ -448,6 +448,16 @@ dst_key_tofile(const dst_key_t *key, int type, const char *directory) {
return (ISC_R_SUCCESS); return (ISC_R_SUCCESS);
} }
void
dst_key_setexternal(dst_key_t *key, isc_boolean_t value) {
key->external = value;
}
isc_boolean_t
dst_key_isexternal(dst_key_t *key) {
return (key->external);
}
isc_result_t isc_result_t
dst_key_fromfile(dns_name_t *name, dns_keytag_t id, dst_key_fromfile(dns_name_t *name, dns_keytag_t id,
unsigned int alg, int type, const char *directory, unsigned int alg, int type, const char *directory,

View File

@@ -128,6 +128,7 @@ struct dst_key {
isc_boolean_t numset[DST_MAX_NUMERIC + 1]; /*%< data set? */ isc_boolean_t numset[DST_MAX_NUMERIC + 1]; /*%< data set? */
isc_boolean_t inactive; /*%< private key not present as it is isc_boolean_t inactive; /*%< private key not present as it is
inactive */ inactive */
isc_boolean_t external; /*%< external key */
int fmt_major; /*%< private key format, major version */ int fmt_major; /*%< private key format, major version */
int fmt_minor; /*%< private key format, minor version */ int fmt_minor; /*%< private key format, minor version */

View File

@@ -178,14 +178,18 @@ find_numericdata(const char *s) {
} }
static int static int
check_rsa(const dst_private_t *priv) { check_rsa(const dst_private_t *priv, isc_boolean_t external) {
int i, j; int i, j;
isc_boolean_t have[RSA_NTAGS]; isc_boolean_t have[RSA_NTAGS];
isc_boolean_t ok; isc_boolean_t ok;
unsigned int mask; unsigned int mask;
if (external)
return ((priv->nelements == 0) ? 0 : -1);
for (i = 0; i < RSA_NTAGS; i++) for (i = 0; i < RSA_NTAGS; i++)
have[i] = ISC_FALSE; have[i] = ISC_FALSE;
for (j = 0; j < priv->nelements; j++) { for (j = 0; j < priv->nelements; j++) {
for (i = 0; i < RSA_NTAGS; i++) for (i = 0; i < RSA_NTAGS; i++)
if (priv->elements[j].tag == TAG(DST_ALG_RSAMD5, i)) if (priv->elements[j].tag == TAG(DST_ALG_RSAMD5, i))
@@ -231,10 +235,15 @@ check_dh(const dst_private_t *priv) {
} }
static int static int
check_dsa(const dst_private_t *priv) { check_dsa(const dst_private_t *priv, isc_boolean_t external) {
int i, j; int i, j;
if (external)
return ((priv->nelements == 0)? 0 : -1);
if (priv->nelements != DSA_NTAGS) if (priv->nelements != DSA_NTAGS)
return (-1); return (-1);
for (i = 0; i < DSA_NTAGS; i++) { for (i = 0; i < DSA_NTAGS; i++) {
for (j = 0; j < priv->nelements; j++) for (j = 0; j < priv->nelements; j++)
if (priv->elements[j].tag == TAG(DST_ALG_DSA, i)) if (priv->elements[j].tag == TAG(DST_ALG_DSA, i))
@@ -246,7 +255,11 @@ check_dsa(const dst_private_t *priv) {
} }
static int static int
check_gost(const dst_private_t *priv) { check_gost(const dst_private_t *priv, isc_boolean_t external) {
if (external)
return ((priv->nelements == 0)? 0 : -1);
if (priv->nelements != GOST_NTAGS) if (priv->nelements != GOST_NTAGS)
return (-1); return (-1);
if (priv->elements[0].tag != TAG(DST_ALG_ECCGOST, 0)) if (priv->elements[0].tag != TAG(DST_ALG_ECCGOST, 0))
@@ -255,7 +268,11 @@ check_gost(const dst_private_t *priv) {
} }
static int static int
check_ecdsa(const dst_private_t *priv) { check_ecdsa(const dst_private_t *priv, isc_boolean_t external) {
if (external)
return ((priv->nelements == 0) ? 0 : -1);
if (priv->nelements != ECDSA_NTAGS) if (priv->nelements != ECDSA_NTAGS)
return (-1); return (-1);
if (priv->elements[0].tag != TAG(DST_ALG_ECDSA256, 0)) if (priv->elements[0].tag != TAG(DST_ALG_ECDSA256, 0))
@@ -309,7 +326,7 @@ check_hmac_sha(const dst_private_t *priv, unsigned int ntags,
static int static int
check_data(const dst_private_t *priv, const unsigned int alg, check_data(const dst_private_t *priv, const unsigned int alg,
isc_boolean_t old) isc_boolean_t old, isc_boolean_t external)
{ {
/* XXXVIX this switch statement is too sparse to gen a jump table. */ /* XXXVIX this switch statement is too sparse to gen a jump table. */
switch (alg) { switch (alg) {
@@ -318,17 +335,17 @@ check_data(const dst_private_t *priv, const unsigned int alg,
case DST_ALG_NSEC3RSASHA1: case DST_ALG_NSEC3RSASHA1:
case DST_ALG_RSASHA256: case DST_ALG_RSASHA256:
case DST_ALG_RSASHA512: case DST_ALG_RSASHA512:
return (check_rsa(priv)); return (check_rsa(priv, external));
case DST_ALG_DH: case DST_ALG_DH:
return (check_dh(priv)); return (check_dh(priv));
case DST_ALG_DSA: case DST_ALG_DSA:
case DST_ALG_NSEC3DSA: case DST_ALG_NSEC3DSA:
return (check_dsa(priv)); return (check_dsa(priv, external));
case DST_ALG_ECCGOST: case DST_ALG_ECCGOST:
return (check_gost(priv)); return (check_gost(priv, external));
case DST_ALG_ECDSA256: case DST_ALG_ECDSA256:
case DST_ALG_ECDSA384: case DST_ALG_ECDSA384:
return (check_ecdsa(priv)); return (check_ecdsa(priv, external));
case DST_ALG_HMACMD5: case DST_ALG_HMACMD5:
return (check_hmac_md5(priv, old)); return (check_hmac_md5(priv, old));
case DST_ALG_HMACSHA1: case DST_ALG_HMACSHA1:
@@ -372,6 +389,7 @@ dst__privstruct_parse(dst_key_t *key, unsigned int alg, isc_lex_t *lex,
unsigned int opt = ISC_LEXOPT_EOL; unsigned int opt = ISC_LEXOPT_EOL;
isc_stdtime_t when; isc_stdtime_t when;
isc_result_t ret; isc_result_t ret;
isc_boolean_t external = ISC_FALSE;
REQUIRE(priv != NULL); REQUIRE(priv != NULL);
@@ -467,9 +485,15 @@ dst__privstruct_parse(dst_key_t *key, unsigned int alg, isc_lex_t *lex,
if (token.type != isc_tokentype_string) { if (token.type != isc_tokentype_string) {
ret = DST_R_INVALIDPRIVATEKEY; ret = DST_R_INVALIDPRIVATEKEY;
NEXTTOKEN(lex, opt, &token);
goto fail; goto fail;
} }
if (strcmp(DST_AS_STR(token), "External:") == 0) {
external = ISC_TRUE;
goto next;
}
/* Numeric metadata */ /* Numeric metadata */
tag = find_numericdata(DST_AS_STR(token)); tag = find_numericdata(DST_AS_STR(token));
if (tag >= 0) { if (tag >= 0) {
@@ -534,8 +558,14 @@ dst__privstruct_parse(dst_key_t *key, unsigned int alg, isc_lex_t *lex,
READLINE(lex, opt, &token); READLINE(lex, opt, &token);
data = NULL; data = NULL;
} }
done: done:
check = check_data(priv, alg, ISC_TRUE); if (external && priv->nelements != 0) {
ret = DST_R_INVALIDPRIVATEKEY;
goto fail;
}
check = check_data(priv, alg, ISC_TRUE, external);
if (check < 0) { if (check < 0) {
ret = DST_R_INVALIDPRIVATEKEY; ret = DST_R_INVALIDPRIVATEKEY;
goto fail; goto fail;
@@ -544,6 +574,8 @@ dst__privstruct_parse(dst_key_t *key, unsigned int alg, isc_lex_t *lex,
goto fail; goto fail;
} }
key->external = external;
return (ISC_R_SUCCESS); return (ISC_R_SUCCESS);
fail: fail:
@@ -573,7 +605,7 @@ dst__privstruct_writefile(const dst_key_t *key, const dst_private_t *priv,
REQUIRE(priv != NULL); REQUIRE(priv != NULL);
ret = check_data(priv, dst_key_alg(key), ISC_FALSE); ret = check_data(priv, dst_key_alg(key), ISC_FALSE, key->external);
if (ret < 0) if (ret < 0)
return (DST_R_INVALIDPRIVATEKEY); return (DST_R_INVALIDPRIVATEKEY);
else if (ret != ISC_R_SUCCESS) else if (ret != ISC_R_SUCCESS)
@@ -691,6 +723,9 @@ dst__privstruct_writefile(const dst_key_t *key, const dst_private_t *priv,
fprintf(fp, "%s %.*s\n", s, (int)r.length, r.base); fprintf(fp, "%s %.*s\n", s, (int)r.length, r.base);
} }
if (key->external)
fprintf(fp, "External:\n");
/* Add the metadata tags */ /* Add the metadata tags */
if (major > 1 || (major == 1 && minor >= 3)) { if (major > 1 || (major == 1 && minor >= 3)) {
for (i = 0; i < NUMERIC_NTAGS; i++) { for (i = 0; i < NUMERIC_NTAGS; i++) {
@@ -706,14 +741,14 @@ dst__privstruct_writefile(const dst_key_t *key, const dst_private_t *priv,
isc_buffer_init(&b, buffer, sizeof(buffer)); isc_buffer_init(&b, buffer, sizeof(buffer));
result = dns_time32_totext(when, &b); result = dns_time32_totext(when, &b);
if (result != ISC_R_SUCCESS) { if (result != ISC_R_SUCCESS) {
fclose(fp); fclose(fp);
return (DST_R_INVALIDPRIVATEKEY); return (DST_R_INVALIDPRIVATEKEY);
} }
isc_buffer_usedregion(&b, &r); isc_buffer_usedregion(&b, &r);
fprintf(fp, "%s %.*s\n", timetags[i], (int)r.length, fprintf(fp, "%s %.*s\n", timetags[i], (int)r.length,
r.base); r.base);
} }
} }

View File

@@ -35,7 +35,7 @@ static const char *text[DST_R_NRESULTS] = {
"illegal operation for a null key", /*%< 3 */ "illegal operation for a null key", /*%< 3 */
"public key is invalid", /*%< 4 */ "public key is invalid", /*%< 4 */
"private key is invalid", /*%< 5 */ "private key is invalid", /*%< 5 */
"UNUSED6", /*%< 6 */ "external key", /*%< 6 */
"error occurred writing key to disk", /*%< 7 */ "error occurred writing key to disk", /*%< 7 */
"invalid algorithm specific parameter", /*%< 8 */ "invalid algorithm specific parameter", /*%< 8 */
"UNUSED9", /*%< 9 */ "UNUSED9", /*%< 9 */

View File

@@ -57,6 +57,7 @@
#define DNS_MASTER_RESIGN 0x00002000 #define DNS_MASTER_RESIGN 0x00002000
#define DNS_MASTER_KEY 0x00004000 /*%< Loading a key zone master file. */ #define DNS_MASTER_KEY 0x00004000 /*%< Loading a key zone master file. */
#define DNS_MASTER_NOTTL 0x00008000 /*%< Don't require ttl. */
ISC_LANG_BEGINDECLS ISC_LANG_BEGINDECLS

View File

@@ -953,6 +953,12 @@ dst_key_setinactive(dst_key_t *key, isc_boolean_t inactive);
* 'key' to be valid. * 'key' to be valid.
*/ */
void
dst_key_setexternal(dst_key_t *key, isc_boolean_t value);
isc_boolean_t
dst_key_isexternal(dst_key_t *key);
ISC_LANG_ENDDECLS ISC_LANG_ENDDECLS
#endif /* DST_DST_H */ #endif /* DST_DST_H */

View File

@@ -592,9 +592,9 @@ loadctx_create(dns_masterformat_t format, isc_mem_t *mctx,
isc_lex_setcomments(lctx->lex, ISC_LEXCOMMENT_DNSMASTERFILE); isc_lex_setcomments(lctx->lex, ISC_LEXCOMMENT_DNSMASTERFILE);
} }
lctx->ttl_known = ISC_FALSE; lctx->ttl_known = ISC_TF((options & DNS_MASTER_NOTTL) != 0);
lctx->ttl = 0; lctx->ttl = 0;
lctx->default_ttl_known = ISC_FALSE; lctx->default_ttl_known = lctx->ttl_known;
lctx->default_ttl = 0; lctx->default_ttl = 0;
lctx->warn_1035 = ISC_TRUE; /* XXX Argument? */ lctx->warn_1035 = ISC_TRUE; /* XXX Argument? */
lctx->warn_tcr = ISC_TRUE; /* XXX Argument? */ lctx->warn_tcr = ISC_TRUE; /* XXX Argument? */

View File

@@ -522,6 +522,11 @@ openssldsa_tofile(const dst_key_t *key, const char *directory) {
if (key->keydata.dsa == NULL) if (key->keydata.dsa == NULL)
return (DST_R_NULLKEY); return (DST_R_NULLKEY);
if (key->external) {
priv.nelements = 0;
return (dst__privstruct_writefile(key, &priv, directory));
}
dsa = key->keydata.dsa; dsa = key->keydata.dsa;
@@ -569,6 +574,7 @@ openssldsa_parse(dst_key_t *key, isc_lex_t *lexer, dst_key_t *pub) {
#define DST_RET(a) {ret = a; goto err;} #define DST_RET(a) {ret = a; goto err;}
UNUSED(pub); UNUSED(pub);
/* read private key file */ /* read private key file */
ret = dst__privstruct_parse(key, DST_ALG_DSA, lexer, mctx, &priv); ret = dst__privstruct_parse(key, DST_ALG_DSA, lexer, mctx, &priv);
if (ret != ISC_R_SUCCESS) if (ret != ISC_R_SUCCESS)
@@ -607,6 +613,19 @@ openssldsa_parse(dst_key_t *key, isc_lex_t *lexer, dst_key_t *pub) {
} }
dst__privstruct_free(&priv, mctx); dst__privstruct_free(&priv, mctx);
if (key->external) {
if (pub == NULL)
DST_RET(DST_R_INVALIDPRIVATEKEY);
dsa->q = pub->keydata.dsa->q;
pub->keydata.dsa->q = NULL;
dsa->p = pub->keydata.dsa->p;
pub->keydata.dsa->p = NULL;
dsa->g = pub->keydata.dsa->g;
pub->keydata.dsa->g = NULL;
dsa->pub_key = pub->keydata.dsa->pub_key;
pub->keydata.dsa->pub_key = NULL;
}
key->key_size = BN_num_bits(dsa->p); key->key_size = BN_num_bits(dsa->p);
return (ISC_R_SUCCESS); return (ISC_R_SUCCESS);

View File

@@ -453,6 +453,11 @@ opensslecdsa_tofile(const dst_key_t *key, const char *directory) {
if (key->keydata.pkey == NULL) if (key->keydata.pkey == NULL)
return (DST_R_NULLKEY); return (DST_R_NULLKEY);
if (key->external) {
priv.nelements = 0;
return (dst__privstruct_writefile(key, &priv, directory));
}
pkey = key->keydata.pkey; pkey = key->keydata.pkey;
eckey = EVP_PKEY_get1_EC_KEY(pkey); eckey = EVP_PKEY_get1_EC_KEY(pkey);
if (eckey == NULL) if (eckey == NULL)
@@ -514,8 +519,9 @@ static isc_result_t
opensslecdsa_parse(dst_key_t *key, isc_lex_t *lexer, dst_key_t *pub) { opensslecdsa_parse(dst_key_t *key, isc_lex_t *lexer, dst_key_t *pub) {
dst_private_t priv; dst_private_t priv;
isc_result_t ret; isc_result_t ret;
EVP_PKEY *pkey; EVP_PKEY *pkey, *pubpkey;
EC_KEY *eckey = NULL; EC_KEY *eckey = NULL, *pubeckey = NULL;
const EC_POINT *pubkey;
BIGNUM *privkey; BIGNUM *privkey;
int group_nid; int group_nid;
isc_mem_t *mctx = key->mctx; isc_mem_t *mctx = key->mctx;
@@ -537,17 +543,36 @@ opensslecdsa_parse(dst_key_t *key, isc_lex_t *lexer, dst_key_t *pub) {
if (ret != ISC_R_SUCCESS) if (ret != ISC_R_SUCCESS)
goto err; goto err;
privkey = BN_bin2bn(priv.elements[0].data, if (key->external) {
priv.elements[0].length, NULL); /*
if (privkey == NULL) * Copy the public key to this new key.
DST_RET(ISC_R_NOMEMORY); */
if (!EC_KEY_set_private_key(eckey, privkey)) if (pub == NULL)
DST_RET(ISC_R_NOMEMORY); DST_RET(DST_R_INVALIDPRIVATEKEY);
if (ecdsa_check(eckey, pub) != ISC_R_SUCCESS) pubpkey = pub->keydata.pkey;
DST_RET(DST_R_INVALIDPRIVATEKEY); pubeckey = EVP_PKEY_get1_EC_KEY(pubpkey);
dst__privstruct_free(&priv, mctx); if (pubeckey == NULL)
memset(&priv, 0, sizeof(priv)); DST_RET(DST_R_INVALIDPRIVATEKEY);
pubkey = EC_KEY_get0_public_key(pubeckey);
if (pubkey == NULL)
DST_RET(DST_R_INVALIDPRIVATEKEY);
if (EC_KEY_set_public_key(eckey, pubkey) != 1)
DST_RET(DST_R_INVALIDPRIVATEKEY);
if (EC_KEY_check_key(eckey) != 1)
DST_RET(DST_R_INVALIDPRIVATEKEY);
} else {
privkey = BN_bin2bn(priv.elements[0].data,
priv.elements[0].length, NULL);
if (privkey == NULL)
DST_RET(ISC_R_NOMEMORY);
if (!EC_KEY_set_private_key(eckey, privkey))
DST_RET(ISC_R_NOMEMORY);
if (ecdsa_check(eckey, pub) != ISC_R_SUCCESS)
DST_RET(DST_R_INVALIDPRIVATEKEY);
dst__privstruct_free(&priv, mctx);
memset(&priv, 0, sizeof(priv));
}
pkey = EVP_PKEY_new(); pkey = EVP_PKEY_new();
if (pkey == NULL) if (pkey == NULL)
DST_RET (ISC_R_NOMEMORY); DST_RET (ISC_R_NOMEMORY);
@@ -561,6 +586,8 @@ opensslecdsa_parse(dst_key_t *key, isc_lex_t *lexer, dst_key_t *pub) {
err: err:
if (eckey != NULL) if (eckey != NULL)
EC_KEY_free(eckey); EC_KEY_free(eckey);
if (pubeckey != NULL)
EC_KEY_free(pubeckey);
dst__privstruct_free(&priv, mctx); dst__privstruct_free(&priv, mctx);
memset(&priv, 0, sizeof(priv)); memset(&priv, 0, sizeof(priv));
return (ret); return (ret);

View File

@@ -296,6 +296,11 @@ opensslgost_tofile(const dst_key_t *key, const char *directory) {
if (key->keydata.pkey == NULL) if (key->keydata.pkey == NULL)
return (DST_R_NULLKEY); return (DST_R_NULLKEY);
if (key->external) {
priv.nelements = 0;
return (dst__privstruct_writefile(key, &priv, directory));
}
pkey = key->keydata.pkey; pkey = key->keydata.pkey;
len = i2d_PrivateKey(pkey, NULL); len = i2d_PrivateKey(pkey, NULL);
@@ -337,13 +342,21 @@ opensslgost_parse(dst_key_t *key, isc_lex_t *lexer, dst_key_t *pub) {
if (ret != ISC_R_SUCCESS) if (ret != ISC_R_SUCCESS)
return (ret); return (ret);
INSIST(priv.elements[0].tag == TAG_GOST_PRIVASN1); if (key->external) {
p = priv.elements[0].data; INSIST(priv.nelements == 0);
if (d2i_PrivateKey(NID_id_GostR3410_2001, &pkey, &p, if (pub == NULL)
(long) priv.elements[0].length) == NULL) DST_RET(DST_R_INVALIDPRIVATEKEY);
DST_RET(dst__openssl_toresult2("d2i_PrivateKey", key->keydata.pkey = pub->keydata.pkey;
DST_R_INVALIDPRIVATEKEY)); pub->keydata.pkey = NULL;
key->keydata.pkey = pkey; } else {
INSIST(priv.elements[0].tag == TAG_GOST_PRIVASN1);
p = priv.elements[0].data;
if (d2i_PrivateKey(NID_id_GostR3410_2001, &pkey, &p,
(long) priv.elements[0].length) == NULL)
DST_RET(dst__openssl_toresult2("d2i_PrivateKey",
DST_R_INVALIDPRIVATEKEY));
key->keydata.pkey = pkey;
}
key->key_size = EVP_PKEY_bits(pkey); key->key_size = EVP_PKEY_bits(pkey);
dst__privstruct_free(&priv, mctx); dst__privstruct_free(&priv, mctx);
memset(&priv, 0, sizeof(priv)); memset(&priv, 0, sizeof(priv));

View File

@@ -1048,8 +1048,14 @@ opensslrsa_tofile(const dst_key_t *key, const char *directory) {
return (DST_R_NULLKEY); return (DST_R_NULLKEY);
rsa = key->keydata.rsa; rsa = key->keydata.rsa;
#endif #endif
memset(bufs, 0, sizeof(bufs)); memset(bufs, 0, sizeof(bufs));
if (key->external) {
priv.nelements = 0;
result = dst__privstruct_writefile(key, &priv, directory);
goto fail;
}
for (i = 0; i < 8; i++) { for (i = 0; i < 8; i++) {
bufs[i] = isc_mem_get(key->mctx, BN_num_bytes(rsa->n)); bufs[i] = isc_mem_get(key->mctx, BN_num_bytes(rsa->n));
if (bufs[i] == NULL) { if (bufs[i] == NULL) {
@@ -1205,6 +1211,9 @@ opensslrsa_parse(dst_key_t *key, isc_lex_t *lexer, dst_key_t *pub) {
if (ret != ISC_R_SUCCESS) if (ret != ISC_R_SUCCESS)
goto err; goto err;
if (key->external && priv.nelements != 0)
DST_RET(DST_R_INVALIDPRIVATEKEY);
for (i = 0; i < priv.nelements; i++) { for (i = 0; i < priv.nelements; i++) {
switch (priv.elements[i].tag) { switch (priv.elements[i].tag) {
case TAG_RSA_ENGINE: case TAG_RSA_ENGINE:
@@ -1217,6 +1226,7 @@ opensslrsa_parse(dst_key_t *key, isc_lex_t *lexer, dst_key_t *pub) {
break; break;
} }
} }
/* /*
* Is this key is stored in a HSM? * Is this key is stored in a HSM?
* See if we can fetch it. * See if we can fetch it.
@@ -1328,8 +1338,10 @@ opensslrsa_parse(dst_key_t *key, isc_lex_t *lexer, dst_key_t *pub) {
if (rsa_check(rsa, pubrsa) != ISC_R_SUCCESS) if (rsa_check(rsa, pubrsa) != ISC_R_SUCCESS)
DST_RET(DST_R_INVALIDPRIVATEKEY); DST_RET(DST_R_INVALIDPRIVATEKEY);
if (BN_num_bits(rsa->e) > RSA_MAX_PUBEXP_BITS) if (!key->external) {
DST_RET(ISC_R_RANGE); if (BN_num_bits(rsa->e) > RSA_MAX_PUBEXP_BITS)
DST_RET(ISC_R_RANGE);
}
key->key_size = BN_num_bits(rsa->n); key->key_size = BN_num_bits(rsa->n);
if (pubrsa != NULL) if (pubrsa != NULL)
RSA_free(pubrsa); RSA_free(pubrsa);

View File

@@ -5545,6 +5545,7 @@ find_zone_keys(dns_zone_t *zone, dns_db_t *db, dns_dbversion_t *ver,
const char *directory = dns_zone_getkeydirectory(zone); const char *directory = dns_zone_getkeydirectory(zone);
CHECK(dns_db_findnode(db, dns_db_origin(db), ISC_FALSE, &node)); CHECK(dns_db_findnode(db, dns_db_origin(db), ISC_FALSE, &node));
memset(keys, 0, sizeof(*keys) * maxkeys);
result = dns_dnssec_findzonekeys2(db, ver, node, dns_db_origin(db), result = dns_dnssec_findzonekeys2(db, ver, node, dns_db_origin(db),
directory, mctx, maxkeys, keys, directory, mctx, maxkeys, keys,
nkeys); nkeys);
@@ -13132,6 +13133,7 @@ sync_secure_db(dns_zone_t *seczone, dns_db_t *secdb,
static void static void
receive_secure_serial(isc_task_t *task, isc_event_t *event) { receive_secure_serial(isc_task_t *task, isc_event_t *event) {
static char me[] = "receive_secure_serial";
isc_result_t result; isc_result_t result;
dns_journal_t *rjournal = NULL; dns_journal_t *rjournal = NULL;
isc_uint32_t start, end; isc_uint32_t start, end;
@@ -13147,6 +13149,8 @@ receive_secure_serial(isc_task_t *task, isc_event_t *event) {
end = ((struct secure_event *)event)->serial; end = ((struct secure_event *)event)->serial;
isc_event_free(&event); isc_event_free(&event);
ENTER;
LOCK_ZONE(zone); LOCK_ZONE(zone);
dns_diff_init(zone->mctx, &diff); dns_diff_init(zone->mctx, &diff);