2 * Copyright (C) 2013, 2014 Internet Systems Consortium, Inc. ("ISC")
4 * Permission to use, copy, modify, and/or distribute this software for any
5 * purpose with or without fee is hereby granted, provided that the above
6 * copyright notice and this permission notice appear in all copies.
8 * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
9 * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
10 * AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
11 * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
12 * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
13 * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
14 * PERFORMANCE OF THIS SOFTWARE.
23 #include <isc/buffer.h>
24 #include <isc/commandline.h>
25 #include <isc/entropy.h>
28 #include <isc/print.h>
29 #include <isc/string.h>
32 #include <dns/callbacks.h>
34 #include <dns/dbiterator.h>
36 #include <dns/fixedname.h>
37 #include <dns/keyvalues.h>
39 #include <dns/master.h>
41 #include <dns/rdata.h>
42 #include <dns/rdataclass.h>
43 #include <dns/rdataset.h>
44 #include <dns/rdatasetiter.h>
45 #include <dns/rdatatype.h>
46 #include <dns/result.h>
50 #include "dnssectool.h"
53 #define PATH_MAX 1024 /* AIX, WIN32, and others don't define this. */
56 const char *program = "dnssec-importkey";
59 static dns_rdataclass_t rdclass;
60 static dns_fixedname_t fixed;
61 static dns_name_t *name = NULL;
62 static isc_mem_t *mctx = NULL;
63 static isc_boolean_t setpub = ISC_FALSE, setdel = ISC_FALSE;
64 static isc_boolean_t setttl = ISC_FALSE;
65 static isc_stdtime_t pub = 0, del = 0;
66 static dns_ttl_t ttl = 0;
69 initname(char *setname) {
73 dns_fixedname_init(&fixed);
74 name = dns_fixedname_name(&fixed);
76 isc_buffer_init(&buf, setname, strlen(setname));
77 isc_buffer_add(&buf, strlen(setname));
78 result = dns_name_fromtext(name, &buf, dns_rootname, 0, NULL);
83 db_load_from_stream(dns_db_t *db, FILE *fp) {
85 dns_rdatacallbacks_t callbacks;
87 dns_rdatacallbacks_init(&callbacks);
88 result = dns_db_beginload(db, &callbacks.add, &callbacks.add_private);
89 if (result != ISC_R_SUCCESS)
90 fatal("dns_db_beginload failed: %s", isc_result_totext(result));
92 result = dns_master_loadstream(fp, name, name, rdclass, 0,
94 if (result != ISC_R_SUCCESS)
95 fatal("can't load from input: %s", isc_result_totext(result));
97 result = dns_db_endload(db, &callbacks.add_private);
98 if (result != ISC_R_SUCCESS)
99 fatal("dns_db_endload failed: %s", isc_result_totext(result));
103 loadset(const char *filename, dns_rdataset_t *rdataset) {
106 dns_dbnode_t *node = NULL;
107 char setname[DNS_NAME_FORMATSIZE];
109 dns_name_format(name, setname, sizeof(setname));
111 result = dns_db_create(mctx, "rbt", name, dns_dbtype_zone,
112 rdclass, 0, NULL, &db);
113 if (result != ISC_R_SUCCESS)
114 fatal("can't create database");
116 if (strcmp(filename, "-") == 0) {
117 db_load_from_stream(db, stdin);
120 result = dns_db_load3(db, filename, dns_masterformat_text,
122 if (result != ISC_R_SUCCESS && result != DNS_R_SEENINCLUDE)
123 fatal("can't load %s: %s", filename,
124 isc_result_totext(result));
127 result = dns_db_findnode(db, name, ISC_FALSE, &node);
128 if (result != ISC_R_SUCCESS)
129 fatal("can't find %s node in %s", setname, filename);
131 result = dns_db_findrdataset(db, node, NULL, dns_rdatatype_dnskey,
132 0, 0, rdataset, NULL);
134 if (result == ISC_R_NOTFOUND)
135 fatal("no DNSKEY RR for %s in %s", setname, filename);
136 else if (result != ISC_R_SUCCESS)
137 fatal("dns_db_findrdataset");
140 dns_db_detachnode(db, &node);
147 loadkey(char *filename, unsigned char *key_buf, unsigned int key_buf_size,
151 dst_key_t *key = NULL;
155 dns_rdata_init(rdata);
157 isc_buffer_init(&keyb, key_buf, key_buf_size);
159 result = dst_key_fromnamedfile(filename, NULL, DST_TYPE_PUBLIC,
161 if (result != ISC_R_SUCCESS)
162 fatal("invalid keyfile name %s: %s",
163 filename, isc_result_totext(result));
166 char keystr[DST_KEY_FORMATSIZE];
168 dst_key_format(key, keystr, sizeof(keystr));
169 fprintf(stderr, "%s: %s\n", program, keystr);
172 result = dst_key_todns(key, &keyb);
173 if (result != ISC_R_SUCCESS)
174 fatal("can't decode key");
176 isc_buffer_usedregion(&keyb, &r);
177 dns_rdata_fromregion(rdata, dst_key_class(key),
178 dns_rdatatype_dnskey, &r);
180 rdclass = dst_key_class(key);
182 dns_fixedname_init(&fixed);
183 name = dns_fixedname_name(&fixed);
184 result = dns_name_copy(dst_key_name(key), name, NULL);
185 if (result != ISC_R_SUCCESS)
186 fatal("can't copy name");
192 emit(const char *dir, dns_rdata_t *rdata) {
194 char keystr[DST_KEY_FORMATSIZE];
198 dst_key_t *key = NULL, *tmp = NULL;
200 isc_buffer_init(&buf, rdata->data, rdata->length);
201 isc_buffer_add(&buf, rdata->length);
202 result = dst_key_fromdns(name, rdclass, &buf, mctx, &key);
203 if (result != ISC_R_SUCCESS) {
204 fatal("dst_key_fromdns: %s", isc_result_totext(result));
207 isc_buffer_init(&buf, pubname, sizeof(pubname));
208 result = dst_key_buildfilename(key, DST_TYPE_PUBLIC, dir, &buf);
209 if (result != ISC_R_SUCCESS) {
210 fatal("Failed to build public key filename: %s",
211 isc_result_totext(result));
213 isc_buffer_init(&buf, priname, sizeof(priname));
214 result = dst_key_buildfilename(key, DST_TYPE_PRIVATE, dir, &buf);
215 if (result != ISC_R_SUCCESS) {
216 fatal("Failed to build private key filename: %s",
217 isc_result_totext(result));
220 result = dst_key_fromfile(dst_key_name(key), dst_key_id(key),
222 DST_TYPE_PUBLIC | DST_TYPE_PRIVATE,
224 if (result == ISC_R_SUCCESS) {
225 if (dst_key_isprivate(tmp) && !dst_key_isexternal(tmp))
226 fatal("Private key already exists in %s", priname);
230 dst_key_setexternal(key, ISC_TRUE);
232 dst_key_settime(key, DST_TIME_PUBLISH, pub);
234 dst_key_settime(key, DST_TIME_DELETE, del);
236 dst_key_setttl(key, ttl);
238 result = dst_key_tofile(key, DST_TYPE_PUBLIC|DST_TYPE_PRIVATE,
240 if (result != ISC_R_SUCCESS) {
241 dst_key_format(key, keystr, sizeof(keystr));
242 fatal("Failed to write key %s: %s", keystr,
243 isc_result_totext(result));
245 printf("%s\n", pubname);
247 isc_buffer_clear(&buf);
248 result = dst_key_buildfilename(key, DST_TYPE_PRIVATE, dir, &buf);
249 if (result != ISC_R_SUCCESS) {
250 fatal("Failed to build private key filename: %s",
251 isc_result_totext(result));
253 printf("%s\n", priname);
257 ISC_PLATFORM_NORETURN_PRE static void
258 usage(void) ISC_PLATFORM_NORETURN_POST;
262 fprintf(stderr, "Usage:\n");
263 fprintf(stderr, " %s options [-K dir] keyfile\n\n", program);
264 fprintf(stderr, " %s options -f file [keyname]\n\n", program);
265 fprintf(stderr, "Version: %s\n", VERSION);
266 fprintf(stderr, "Options:\n");
267 fprintf(stderr, " -f file: read key from zone file\n");
268 fprintf(stderr, " -K <directory>: directory in which to store "
270 fprintf(stderr, " -L ttl: set default key TTL\n");
271 fprintf(stderr, " -v <verbose level>\n");
272 fprintf(stderr, " -V: print version information\n");
273 fprintf(stderr, " -h: print usage and exit\n");
274 fprintf(stderr, "Timing options:\n");
275 fprintf(stderr, " -P date/[+-]offset/none: set/unset key "
276 "publication date\n");
277 fprintf(stderr, " -D date/[+-]offset/none: set/unset key "
284 main(int argc, char **argv) {
285 char *classname = NULL;
286 char *filename = NULL, *dir = NULL, *namestr;
290 isc_log_t *log = NULL;
291 isc_entropy_t *ectx = NULL;
292 dns_rdataset_t rdataset;
296 dns_rdata_init(&rdata);
297 isc_stdtime_get(&now);
302 result = isc_mem_create(0, 0, &mctx);
303 if (result != ISC_R_SUCCESS)
304 fatal("out of memory");
306 dns_result_register();
308 isc_commandline_errprint = ISC_FALSE;
310 #define CMDLINE_FLAGS "D:f:hK:L:P:v:V"
311 while ((ch = isc_commandline_parse(argc, argv, CMDLINE_FLAGS)) != -1) {
315 fatal("-D specified more than once");
317 del = strtotime(isc_commandline_argument,
321 dir = isc_commandline_argument;
322 if (strlen(dir) == 0U)
323 fatal("directory must be non-empty string");
326 ttl = strtottl(isc_commandline_argument);
331 fatal("-P specified more than once");
333 pub = strtotime(isc_commandline_argument,
337 filename = isc_commandline_argument;
340 verbose = strtol(isc_commandline_argument, &endp, 0);
342 fatal("-v must be followed by a number");
345 if (isc_commandline_option != '?')
346 fprintf(stderr, "%s: invalid argument -%c\n",
347 program, isc_commandline_option);
350 /* Does not return. */
354 /* Does not return. */
358 fprintf(stderr, "%s: unhandled option -%c\n",
359 program, isc_commandline_option);
364 rdclass = strtoclass(classname);
366 if (argc < isc_commandline_index + 1 && filename == NULL)
367 fatal("the key file name was not specified");
368 if (argc > isc_commandline_index + 1)
369 fatal("extraneous arguments");
372 setup_entropy(mctx, NULL, &ectx);
373 result = isc_hash_create(mctx, ectx, DNS_NAME_MAXWIRE);
374 if (result != ISC_R_SUCCESS)
375 fatal("could not initialize hash");
376 result = dst_lib_init(mctx, ectx,
377 ISC_ENTROPY_BLOCKING | ISC_ENTROPY_GOODONLY);
378 if (result != ISC_R_SUCCESS)
379 fatal("could not initialize dst: %s",
380 isc_result_totext(result));
381 isc_entropy_stopcallbacksources(ectx);
383 setup_logging(verbose, mctx, &log);
385 dns_rdataset_init(&rdataset);
387 if (filename != NULL) {
388 if (argc < isc_commandline_index + 1) {
389 /* using filename as zone name */
392 namestr = argv[isc_commandline_index];
394 result = initname(namestr);
395 if (result != ISC_R_SUCCESS)
396 fatal("could not initialize name %s", namestr);
398 result = loadset(filename, &rdataset);
400 if (result != ISC_R_SUCCESS)
401 fatal("could not load DNSKEY set: %s\n",
402 isc_result_totext(result));
404 for (result = dns_rdataset_first(&rdataset);
405 result == ISC_R_SUCCESS;
406 result = dns_rdataset_next(&rdataset)) {
408 dns_rdata_init(&rdata);
409 dns_rdataset_current(&rdataset, &rdata);
413 unsigned char key_buf[DST_KEY_MAXSIZE];
415 loadkey(argv[isc_commandline_index], key_buf,
416 DST_KEY_MAXSIZE, &rdata);
421 if (dns_rdataset_isassociated(&rdataset))
422 dns_rdataset_disassociate(&rdataset);
423 cleanup_logging(&log);
426 cleanup_entropy(&ectx);
429 isc_mem_stats(mctx, stdout);
430 isc_mem_destroy(&mctx);
433 if (ferror(stdout)) {
434 fprintf(stderr, "write error\n");