1 /* $NetBSD: dnssec-importkey.c,v 1.6 2015/07/08 17:28:55 christos Exp $ */
4 * Copyright (C) 2013-2015 Internet Systems Consortium, Inc. ("ISC")
6 * Permission to use, copy, modify, and/or distribute this software for any
7 * purpose with or without fee is hereby granted, provided that the above
8 * copyright notice and this permission notice appear in all copies.
10 * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
11 * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
12 * AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
13 * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
14 * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
15 * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
16 * PERFORMANCE OF THIS SOFTWARE.
25 #include <isc/buffer.h>
26 #include <isc/commandline.h>
27 #include <isc/entropy.h>
30 #include <isc/print.h>
31 #include <isc/string.h>
34 #include <dns/callbacks.h>
36 #include <dns/dbiterator.h>
38 #include <dns/fixedname.h>
39 #include <dns/keyvalues.h>
41 #include <dns/master.h>
43 #include <dns/rdata.h>
44 #include <dns/rdataclass.h>
45 #include <dns/rdataset.h>
46 #include <dns/rdatasetiter.h>
47 #include <dns/rdatatype.h>
48 #include <dns/result.h>
53 #include <pk11/result.h>
56 #include "dnssectool.h"
59 #define PATH_MAX 1024 /* AIX, WIN32, and others don't define this. */
62 const char *program
= "dnssec-importkey";
65 static dns_rdataclass_t rdclass
;
66 static dns_fixedname_t fixed
;
67 static dns_name_t
*name
= NULL
;
68 static isc_mem_t
*mctx
= NULL
;
69 static isc_boolean_t setpub
= ISC_FALSE
, setdel
= ISC_FALSE
;
70 static isc_boolean_t setttl
= ISC_FALSE
;
71 static isc_stdtime_t pub
= 0, del
= 0;
72 static dns_ttl_t ttl
= 0;
75 initname(char *setname
) {
79 dns_fixedname_init(&fixed
);
80 name
= dns_fixedname_name(&fixed
);
82 isc_buffer_init(&buf
, setname
, strlen(setname
));
83 isc_buffer_add(&buf
, strlen(setname
));
84 result
= dns_name_fromtext(name
, &buf
, dns_rootname
, 0, NULL
);
89 db_load_from_stream(dns_db_t
*db
, FILE *fp
) {
91 dns_rdatacallbacks_t callbacks
;
93 dns_rdatacallbacks_init(&callbacks
);
94 result
= dns_db_beginload(db
, &callbacks
);
95 if (result
!= ISC_R_SUCCESS
)
96 fatal("dns_db_beginload failed: %s", isc_result_totext(result
));
98 result
= dns_master_loadstream(fp
, name
, name
, rdclass
, 0,
100 if (result
!= ISC_R_SUCCESS
)
101 fatal("can't load from input: %s", isc_result_totext(result
));
103 result
= dns_db_endload(db
, &callbacks
);
104 if (result
!= ISC_R_SUCCESS
)
105 fatal("dns_db_endload failed: %s", isc_result_totext(result
));
109 loadset(const char *filename
, dns_rdataset_t
*rdataset
) {
112 dns_dbnode_t
*node
= NULL
;
113 char setname
[DNS_NAME_FORMATSIZE
];
115 dns_name_format(name
, setname
, sizeof(setname
));
117 result
= dns_db_create(mctx
, "rbt", name
, dns_dbtype_zone
,
118 rdclass
, 0, NULL
, &db
);
119 if (result
!= ISC_R_SUCCESS
)
120 fatal("can't create database");
122 if (strcmp(filename
, "-") == 0) {
123 db_load_from_stream(db
, stdin
);
126 result
= dns_db_load3(db
, filename
, dns_masterformat_text
,
128 if (result
!= ISC_R_SUCCESS
&& result
!= DNS_R_SEENINCLUDE
)
129 fatal("can't load %s: %s", filename
,
130 isc_result_totext(result
));
133 result
= dns_db_findnode(db
, name
, ISC_FALSE
, &node
);
134 if (result
!= ISC_R_SUCCESS
)
135 fatal("can't find %s node in %s", setname
, filename
);
137 result
= dns_db_findrdataset(db
, node
, NULL
, dns_rdatatype_dnskey
,
138 0, 0, rdataset
, NULL
);
140 if (result
== ISC_R_NOTFOUND
)
141 fatal("no DNSKEY RR for %s in %s", setname
, filename
);
142 else if (result
!= ISC_R_SUCCESS
)
143 fatal("dns_db_findrdataset");
146 dns_db_detachnode(db
, &node
);
153 loadkey(char *filename
, unsigned char *key_buf
, unsigned int key_buf_size
,
157 dst_key_t
*key
= NULL
;
161 dns_rdata_init(rdata
);
163 isc_buffer_init(&keyb
, key_buf
, key_buf_size
);
165 result
= dst_key_fromnamedfile(filename
, NULL
, DST_TYPE_PUBLIC
,
167 if (result
!= ISC_R_SUCCESS
)
168 fatal("invalid keyfile name %s: %s",
169 filename
, isc_result_totext(result
));
172 char keystr
[DST_KEY_FORMATSIZE
];
174 dst_key_format(key
, keystr
, sizeof(keystr
));
175 fprintf(stderr
, "%s: %s\n", program
, keystr
);
178 result
= dst_key_todns(key
, &keyb
);
179 if (result
!= ISC_R_SUCCESS
)
180 fatal("can't decode key");
182 isc_buffer_usedregion(&keyb
, &r
);
183 dns_rdata_fromregion(rdata
, dst_key_class(key
),
184 dns_rdatatype_dnskey
, &r
);
186 rdclass
= dst_key_class(key
);
188 dns_fixedname_init(&fixed
);
189 name
= dns_fixedname_name(&fixed
);
190 result
= dns_name_copy(dst_key_name(key
), name
, NULL
);
191 if (result
!= ISC_R_SUCCESS
)
192 fatal("can't copy name");
198 emit(const char *dir
, dns_rdata_t
*rdata
) {
200 char keystr
[DST_KEY_FORMATSIZE
];
204 dst_key_t
*key
= NULL
, *tmp
= NULL
;
206 isc_buffer_init(&buf
, rdata
->data
, rdata
->length
);
207 isc_buffer_add(&buf
, rdata
->length
);
208 result
= dst_key_fromdns(name
, rdclass
, &buf
, mctx
, &key
);
209 if (result
!= ISC_R_SUCCESS
) {
210 fatal("dst_key_fromdns: %s", isc_result_totext(result
));
213 isc_buffer_init(&buf
, pubname
, sizeof(pubname
));
214 result
= dst_key_buildfilename(key
, DST_TYPE_PUBLIC
, dir
, &buf
);
215 if (result
!= ISC_R_SUCCESS
) {
216 fatal("Failed to build public key filename: %s",
217 isc_result_totext(result
));
219 isc_buffer_init(&buf
, priname
, sizeof(priname
));
220 result
= dst_key_buildfilename(key
, DST_TYPE_PRIVATE
, dir
, &buf
);
221 if (result
!= ISC_R_SUCCESS
) {
222 fatal("Failed to build private key filename: %s",
223 isc_result_totext(result
));
226 result
= dst_key_fromfile(dst_key_name(key
), dst_key_id(key
),
228 DST_TYPE_PUBLIC
| DST_TYPE_PRIVATE
,
230 if (result
== ISC_R_SUCCESS
) {
231 if (dst_key_isprivate(tmp
) && !dst_key_isexternal(tmp
))
232 fatal("Private key already exists in %s", priname
);
236 dst_key_setexternal(key
, ISC_TRUE
);
238 dst_key_settime(key
, DST_TIME_PUBLISH
, pub
);
240 dst_key_settime(key
, DST_TIME_DELETE
, del
);
242 dst_key_setttl(key
, ttl
);
244 result
= dst_key_tofile(key
, DST_TYPE_PUBLIC
|DST_TYPE_PRIVATE
,
246 if (result
!= ISC_R_SUCCESS
) {
247 dst_key_format(key
, keystr
, sizeof(keystr
));
248 fatal("Failed to write key %s: %s", keystr
,
249 isc_result_totext(result
));
251 printf("%s\n", pubname
);
253 isc_buffer_clear(&buf
);
254 result
= dst_key_buildfilename(key
, DST_TYPE_PRIVATE
, dir
, &buf
);
255 if (result
!= ISC_R_SUCCESS
) {
256 fatal("Failed to build private key filename: %s",
257 isc_result_totext(result
));
259 printf("%s\n", priname
);
263 ISC_PLATFORM_NORETURN_PRE
static void
264 usage(void) ISC_PLATFORM_NORETURN_POST
;
268 fprintf(stderr
, "Usage:\n");
269 fprintf(stderr
, " %s options [-K dir] keyfile\n\n", program
);
270 fprintf(stderr
, " %s options -f file [keyname]\n\n", program
);
271 fprintf(stderr
, "Version: %s\n", VERSION
);
272 fprintf(stderr
, "Options:\n");
273 fprintf(stderr
, " -f file: read key from zone file\n");
274 fprintf(stderr
, " -K <directory>: directory in which to store "
276 fprintf(stderr
, " -L ttl: set default key TTL\n");
277 fprintf(stderr
, " -v <verbose level>\n");
278 fprintf(stderr
, " -V: print version information\n");
279 fprintf(stderr
, " -h: print usage and exit\n");
280 fprintf(stderr
, "Timing options:\n");
281 fprintf(stderr
, " -P date/[+-]offset/none: set/unset key "
282 "publication date\n");
283 fprintf(stderr
, " -D date/[+-]offset/none: set/unset key "
290 main(int argc
, char **argv
) {
291 char *classname
= NULL
;
292 char *filename
= NULL
, *dir
= NULL
, *namestr
;
296 isc_log_t
*log
= NULL
;
297 isc_entropy_t
*ectx
= NULL
;
298 dns_rdataset_t rdataset
;
302 dns_rdata_init(&rdata
);
303 isc_stdtime_get(&now
);
308 result
= isc_mem_create(0, 0, &mctx
);
309 if (result
!= ISC_R_SUCCESS
)
310 fatal("out of memory");
313 pk11_result_register();
315 dns_result_register();
317 isc_commandline_errprint
= ISC_FALSE
;
319 #define CMDLINE_FLAGS "D:f:hK:L:P:v:V"
320 while ((ch
= isc_commandline_parse(argc
, argv
, CMDLINE_FLAGS
)) != -1) {
324 fatal("-D specified more than once");
326 del
= strtotime(isc_commandline_argument
,
330 dir
= isc_commandline_argument
;
331 if (strlen(dir
) == 0U)
332 fatal("directory must be non-empty string");
335 ttl
= strtottl(isc_commandline_argument
);
340 fatal("-P specified more than once");
342 pub
= strtotime(isc_commandline_argument
,
346 filename
= isc_commandline_argument
;
349 verbose
= strtol(isc_commandline_argument
, &endp
, 0);
351 fatal("-v must be followed by a number");
354 if (isc_commandline_option
!= '?')
355 fprintf(stderr
, "%s: invalid argument -%c\n",
356 program
, isc_commandline_option
);
359 /* Does not return. */
363 /* Does not return. */
367 fprintf(stderr
, "%s: unhandled option -%c\n",
368 program
, isc_commandline_option
);
373 rdclass
= strtoclass(classname
);
375 if (argc
< isc_commandline_index
+ 1 && filename
== NULL
)
376 fatal("the key file name was not specified");
377 if (argc
> isc_commandline_index
+ 1)
378 fatal("extraneous arguments");
381 setup_entropy(mctx
, NULL
, &ectx
);
382 result
= isc_hash_create(mctx
, ectx
, DNS_NAME_MAXWIRE
);
383 if (result
!= ISC_R_SUCCESS
)
384 fatal("could not initialize hash");
385 result
= dst_lib_init(mctx
, ectx
,
386 ISC_ENTROPY_BLOCKING
| ISC_ENTROPY_GOODONLY
);
387 if (result
!= ISC_R_SUCCESS
)
388 fatal("could not initialize dst: %s",
389 isc_result_totext(result
));
390 isc_entropy_stopcallbacksources(ectx
);
392 setup_logging(mctx
, &log
);
394 dns_rdataset_init(&rdataset
);
396 if (filename
!= NULL
) {
397 if (argc
< isc_commandline_index
+ 1) {
398 /* using filename as zone name */
401 namestr
= argv
[isc_commandline_index
];
403 result
= initname(namestr
);
404 if (result
!= ISC_R_SUCCESS
)
405 fatal("could not initialize name %s", namestr
);
407 result
= loadset(filename
, &rdataset
);
409 if (result
!= ISC_R_SUCCESS
)
410 fatal("could not load DNSKEY set: %s\n",
411 isc_result_totext(result
));
413 for (result
= dns_rdataset_first(&rdataset
);
414 result
== ISC_R_SUCCESS
;
415 result
= dns_rdataset_next(&rdataset
)) {
417 dns_rdata_init(&rdata
);
418 dns_rdataset_current(&rdataset
, &rdata
);
422 unsigned char key_buf
[DST_KEY_MAXSIZE
];
424 loadkey(argv
[isc_commandline_index
], key_buf
,
425 DST_KEY_MAXSIZE
, &rdata
);
430 if (dns_rdataset_isassociated(&rdataset
))
431 dns_rdataset_disassociate(&rdataset
);
432 cleanup_logging(&log
);
435 cleanup_entropy(&ectx
);
438 isc_mem_stats(mctx
, stdout
);
439 isc_mem_destroy(&mctx
);
442 if (ferror(stdout
)) {
443 fprintf(stderr
, "write error\n");