2
0
mirror of https://gitlab.isc.org/isc-projects/bind9 synced 2025-08-31 14:35:26 +00:00

3671. [bug] Don't allow dnssec-importkey overwrite a existing

non-imported private key.
This commit is contained in:
Mark Andrews
2013-11-13 12:01:09 +11:00
parent c41afaf716
commit 6b0434299b
6 changed files with 127 additions and 30 deletions

View File

@@ -1,3 +1,6 @@
3671. [bug] Don't allow dnssec-importkey overwrite a existing
non-imported private key.
3670. [bug] Address read after free in server side of 3670. [bug] Address read after free in server side of
lwres_getrrsetbyname. [RT #29075] lwres_getrrsetbyname. [RT #29075]

View File

@@ -61,7 +61,9 @@ static dns_fixedname_t fixed;
static dns_name_t *name = NULL; static dns_name_t *name = NULL;
static isc_mem_t *mctx = NULL; static isc_mem_t *mctx = NULL;
static isc_boolean_t setpub = ISC_FALSE, setdel = ISC_FALSE; static isc_boolean_t setpub = ISC_FALSE, setdel = ISC_FALSE;
static isc_boolean_t setttl = ISC_FALSE;
static isc_stdtime_t pub = 0, del = 0; static isc_stdtime_t pub = 0, del = 0;
static dns_ttl_t ttl = 0;
static isc_result_t static isc_result_t
initname(char *setname) { initname(char *setname) {
@@ -190,9 +192,10 @@ static void
emit(const char *dir, dns_rdata_t *rdata) { emit(const char *dir, dns_rdata_t *rdata) {
isc_result_t result; isc_result_t result;
char keystr[DST_KEY_FORMATSIZE]; char keystr[DST_KEY_FORMATSIZE];
char newname[1024]; char pubname[1024];
char priname[1024];
isc_buffer_t buf; isc_buffer_t buf;
dst_key_t *key = NULL; dst_key_t *key = NULL, *tmp = NULL;
isc_buffer_init(&buf, rdata->data, rdata->length); isc_buffer_init(&buf, rdata->data, rdata->length);
isc_buffer_add(&buf, rdata->length); isc_buffer_add(&buf, rdata->length);
@@ -201,18 +204,36 @@ emit(const char *dir, dns_rdata_t *rdata) {
fatal("dst_key_fromdns: %s", isc_result_totext(result)); fatal("dst_key_fromdns: %s", isc_result_totext(result));
} }
dst_key_setexternal(key, ISC_TRUE); isc_buffer_init(&buf, pubname, sizeof(pubname));
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); result = dst_key_buildfilename(key, DST_TYPE_PUBLIC, dir, &buf);
if (result != ISC_R_SUCCESS) { if (result != ISC_R_SUCCESS) {
fatal("Failed to build public key filename: %s", fatal("Failed to build public key filename: %s",
isc_result_totext(result)); isc_result_totext(result));
} }
isc_buffer_init(&buf, priname, sizeof(priname));
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));
}
result = dst_key_fromfile(dst_key_name(key), dst_key_id(key),
dst_key_alg(key),
DST_TYPE_PUBLIC | DST_TYPE_PRIVATE,
dir, mctx, &tmp);
if (result == ISC_R_SUCCESS) {
if (dst_key_isprivate(tmp) && !dst_key_isexternal(tmp))
fatal("Private key already exists in %s", priname);
dst_key_free(&tmp);
}
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);
if (setttl)
dst_key_setttl(key, ttl);
result = dst_key_tofile(key, DST_TYPE_PUBLIC|DST_TYPE_PRIVATE, result = dst_key_tofile(key, DST_TYPE_PUBLIC|DST_TYPE_PRIVATE,
dir); dir);
@@ -221,8 +242,7 @@ emit(const char *dir, dns_rdata_t *rdata) {
fatal("Failed to write key %s: %s", keystr, fatal("Failed to write key %s: %s", keystr,
isc_result_totext(result)); isc_result_totext(result));
} }
printf("%s\n", pubname);
printf("%s\n", newname);
isc_buffer_clear(&buf); isc_buffer_clear(&buf);
result = dst_key_buildfilename(key, DST_TYPE_PRIVATE, dir, &buf); result = dst_key_buildfilename(key, DST_TYPE_PRIVATE, dir, &buf);
@@ -230,7 +250,7 @@ emit(const char *dir, dns_rdata_t *rdata) {
fatal("Failed to build private key filename: %s", fatal("Failed to build private key filename: %s",
isc_result_totext(result)); isc_result_totext(result));
} }
printf("%s\n", newname); printf("%s\n", priname);
dst_key_free(&key); dst_key_free(&key);
} }
@@ -240,13 +260,21 @@ usage(void) ISC_PLATFORM_NORETURN_POST;
static void static void
usage(void) { usage(void) {
fprintf(stderr, "Usage:\n"); fprintf(stderr, "Usage:\n");
fprintf(stderr, " %s options [-K dir] file\n\n", program); fprintf(stderr, " %s options [-K dir] keyfile\n\n", program);
fprintf(stderr, " %s options -f file [keyname]\n\n", program);
fprintf(stderr, "Version: %s\n", VERSION); fprintf(stderr, "Version: %s\n", VERSION);
fprintf(stderr, "Options:\n"); fprintf(stderr, "Options:\n");
fprintf(stderr, " -v <verbose level>\n"); fprintf(stderr, " -f file: read key from zone file\n");
fprintf(stderr, " -K <directory>: directory in which to store " fprintf(stderr, " -K <directory>: directory in which to store "
"the keyset files\n"); "the key files\n");
fprintf(stderr, " -f file: read keyset from zone file\n"); fprintf(stderr, " -L ttl: set default key TTL\n");
fprintf(stderr, " -v <verbose level>\n");
fprintf(stderr, " -h: print usage and exit\n");
fprintf(stderr, "Timing options:\n");
fprintf(stderr, " -P date/[+-]offset/none: set/unset key "
"publication date\n");
fprintf(stderr, " -D date/[+-]offset/none: set/unset key "
"deletion date\n");
exit (-1); exit (-1);
} }
@@ -278,7 +306,8 @@ main(int argc, char **argv) {
isc_commandline_errprint = ISC_FALSE; isc_commandline_errprint = ISC_FALSE;
while ((ch = isc_commandline_parse(argc, argv, "D:f:hK:P:v:")) != -1) { #define CMDLINE_FLAGS "D:f:hK:L:P:v:"
while ((ch = isc_commandline_parse(argc, argv, CMDLINE_FLAGS)) != -1) {
switch (ch) { switch (ch) {
case 'D': case 'D':
if (setdel) if (setdel)
@@ -292,6 +321,13 @@ main(int argc, char **argv) {
if (strlen(dir) == 0U) if (strlen(dir) == 0U)
fatal("directory must be non-empty string"); fatal("directory must be non-empty string");
break; break;
case 'L':
if (strcmp(isc_commandline_argument, "none") == 0)
ttl = 0;
else
ttl = strtottl(isc_commandline_argument);
setttl = ISC_TRUE;
break;
case 'P': case 'P':
if (setpub) if (setpub)
fatal("-P specified more than once"); fatal("-P specified more than once");
@@ -346,8 +382,8 @@ main(int argc, char **argv) {
dns_rdataset_init(&rdataset); dns_rdataset_init(&rdataset);
if (filename != NULL) { if (filename != NULL) {
if (argc < isc_commandline_index + 1 && filename != NULL) { if (argc < isc_commandline_index + 1) {
/* using zone name as the zone file name */ /* using filename as zone name */
namestr = filename; namestr = filename;
} else } else
namestr = argv[isc_commandline_index]; namestr = argv[isc_commandline_index];

View File

@@ -44,22 +44,45 @@
<refsynopsisdiv> <refsynopsisdiv>
<cmdsynopsis> <cmdsynopsis>
<command>dnssec-importkey</command> <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>-K <replaceable class="parameter">directory</replaceable></option></arg>
<arg><option>-L <replaceable class="parameter">ttl</replaceable></option></arg>
<arg><option>-P <replaceable class="parameter">date/offset</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>-D <replaceable class="parameter">date/offset</replaceable></option></arg>
<arg><option>-h</option></arg> <arg><option>-h</option></arg>
<arg><option>-v <replaceable class="parameter">level</replaceable></option></arg> <arg><option>-v <replaceable class="parameter">level</replaceable></option></arg>
<arg><option>keyname</option></arg> <arg choice="req"><option>keyfile</option></arg>
</cmdsynopsis>
<cmdsynopsis>
<command>dnssec-importkey</command>
<arg choice="req"><option>-f <replaceable class="parameter">filename</replaceable></option></arg>
<arg><option>-K <replaceable class="parameter">directory</replaceable></option></arg>
<arg><option>-L <replaceable class="parameter">ttl</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>dnsname</option></arg>
</cmdsynopsis> </cmdsynopsis>
</refsynopsisdiv> </refsynopsisdiv>
<refsect1> <refsect1>
<title>DESCRIPTION</title> <title>DESCRIPTION</title>
<para><command>dnssec-importkey</command> <para><command>dnssec-importkey</command>
read a DNSKEY record and generated a .key/.private key pair. reads a public DNSKEY record and generates a pair of
Publication (<option>-P</option>) and deletions (<option>-D</option>) .key/.private files. The DNSKEY record may be read from an
times can be set for the key. existing .key file, in which case a corresponding .private file
will be generated, or it may be read from any other file or
from the standard input, in which case both .key and .private
files will be generated.
</para>
<para>
The newly-created .private file does <emphasis>not</command>
contain private key data, and cannot be used for signing.
However, having a .private file makes it possible to set
publication (<option>-P</option>) and deletion
(<option>-D</option>) times for the key, which means the
public key can be added to and removed from the DNSKEY RRset
on schedule even if the true private key is stored offline.
</para> </para>
</refsect1> </refsect1>
@@ -71,7 +94,14 @@
<term>-f <replaceable class="parameter">filename</replaceable></term> <term>-f <replaceable class="parameter">filename</replaceable></term>
<listitem> <listitem>
<para> <para>
Filename to read the key from. Zone file mode: instead of a public keyfile name, the argument
is the DNS domain name of a zone master file, which can be read
from <option>file</option>. If the domain name is the same as
<option>file</option>, then it may be omitted.
</para>
<para>
If <option>file</option> is set to <literal>"-"</literal>, then
the zone data is read from the standard input.
</para> </para>
</listitem> </listitem>
</varlistentry> </varlistentry>
@@ -93,7 +123,7 @@
into a DNSKEY RR. If the key is imported into a zone, 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 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 already a DNSKEY RRset in place, in which case the existing TTL
would take precedence. importkey the default TTL to would take precedence. Setting the default TTL to
<literal>0</literal> or <literal>none</literal> removes it. <literal>0</literal> or <literal>none</literal> removes it.
</para> </para>
</listitem> </listitem>
@@ -159,6 +189,16 @@
</variablelist> </variablelist>
</refsect1> </refsect1>
<refsect1>
<title>FILES</title>
<para>
A keyfile can be designed by the key identification
<filename>Knnnn.+aaa+iiiii</filename> or the full file name
<filename>Knnnn.+aaa+iiiii.key</filename> as generated by
<refentrytitle>dnssec-keygen</refentrytitle><manvolnum>8</manvolnum>.
</para>
</refsect1>
<refsect1> <refsect1>
<title>SEE ALSO</title> <title>SEE ALSO</title>
<para><citerefentry> <para><citerefentry>

View File

@@ -82,3 +82,4 @@ rm -f */*.nzf
rm -f ns3/test-?.bk rm -f ns3/test-?.bk
rm -f ns3/test-?.bk.signed rm -f ns3/test-?.bk.signed
rm -f ns3/test-?.bk.signed.jnl rm -f ns3/test-?.bk.signed.jnl
rm -f import.key Kimport*

View File

@@ -128,7 +128,9 @@ rm -f ${k3}.* ${k4}.*
# #
# Convert k1 and k2 in to External Keys. # Convert k1 and k2 in to External Keys.
rm -f $k1.private rm -f $k1.private
$IMPORTKEY -P now -D now+3600 -f $k1.key $zone > /dev/null 2>&1 mv $k1.key a-file
$IMPORTKEY -P now -D now+3600 -f a-file $zone > /dev/null 2>&1
rm -f $k2.private rm -f $k2.private
$IMPORTKEY -f $k2.key $zone > /dev/null 2>&1 mv $k2.key a-file
$IMPORTKEY -f a-file $zone > /dev/null 2>&1
done done

View File

@@ -847,4 +847,19 @@ do
done done
status=`expr $status + $ret` status=`expr $status + $ret`
n=`expr $n + 1`
echo "I:testing imported key won't overwrite a private key ($n)"
ret=0
key=`$KEYGEN -r $RANDFILE -q import.example`
cp ${key}.key import.key
# import should fail
$IMPORTKEY -f import.key import.example > /dev/null 2>&1 && ret=1
rm -f ${key}.private
# private key removed; import should now succeed
$IMPORTKEY -f import.key import.example > /dev/null 2>&1 || ret=1
# now that it's an external key, re-import should succeed
$IMPORTKEY -f import.key import.example > /dev/null 2>&1 || ret=1
if [ $ret != 0 ]; then echo "I:failed"; fi
status=`expr $status + $ret`
exit $status exit $status