Update repub branch u/fanf2/patch to rebasing branch u/fanf2/rebasing revision v9_15_...
[ipreg/bind9.git] / bin / dnssec / dnssec-importkey.c
CommitLineData
0c91911b 1/*
843d3896 2 * Copyright (C) Internet Systems Consortium, Inc. ("ISC")
0c91911b 3 *
0c27b3fe
MA
4 * This Source Code Form is subject to the terms of the Mozilla Public
5 * License, v. 2.0. If a copy of the MPL was not distributed with this
6 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
843d3896
OS
7 *
8 * See the COPYRIGHT file distributed with this work for additional
9 * information regarding copyright ownership.
0c91911b
MA
10 */
11
12/*! \file */
13
994e6569 14#include <stdbool.h>
0c91911b
MA
15#include <stdlib.h>
16
17#include <isc/buffer.h>
18#include <isc/commandline.h>
0c91911b
MA
19#include <isc/hash.h>
20#include <isc/mem.h>
21#include <isc/print.h>
22#include <isc/string.h>
23#include <isc/util.h>
24
25#include <dns/callbacks.h>
26#include <dns/db.h>
27#include <dns/dbiterator.h>
28#include <dns/ds.h>
29#include <dns/fixedname.h>
30#include <dns/keyvalues.h>
31#include <dns/log.h>
32#include <dns/master.h>
33#include <dns/name.h>
34#include <dns/rdata.h>
35#include <dns/rdataclass.h>
36#include <dns/rdataset.h>
37#include <dns/rdatasetiter.h>
38#include <dns/rdatatype.h>
39#include <dns/result.h>
40
41#include <dst/dst.h>
42
c3b8130f 43#if USE_PKCS11
acbb301e
EH
44#include <pk11/result.h>
45#endif
46
0c91911b
MA
47#include "dnssectool.h"
48
0c91911b 49const char *program = "dnssec-importkey";
0c91911b
MA
50
51static dns_rdataclass_t rdclass;
52static dns_fixedname_t fixed;
53static dns_name_t *name = NULL;
54static isc_mem_t *mctx = NULL;
994e6569
OS
55static bool setpub = false, setdel = false;
56static bool setttl = false;
0c91911b 57static isc_stdtime_t pub = 0, del = 0;
6b043429 58static dns_ttl_t ttl = 0;
e939674d 59static isc_stdtime_t syncadd = 0, syncdel = 0;
994e6569
OS
60static bool setsyncadd = false;
61static bool setsyncdel = false;
0c91911b
MA
62
63static isc_result_t
64initname(char *setname) {
65 isc_result_t result;
66 isc_buffer_t buf;
67
4df4a8e7 68 name = dns_fixedname_initname(&fixed);
0c91911b
MA
69
70 isc_buffer_init(&buf, setname, strlen(setname));
71 isc_buffer_add(&buf, strlen(setname));
72 result = dns_name_fromtext(name, &buf, dns_rootname, 0, NULL);
73 return (result);
74}
75
76static void
77db_load_from_stream(dns_db_t *db, FILE *fp) {
78 isc_result_t result;
79 dns_rdatacallbacks_t callbacks;
80
81 dns_rdatacallbacks_init(&callbacks);
82 result = dns_db_beginload(db, &callbacks);
83 if (result != ISC_R_SUCCESS)
84 fatal("dns_db_beginload failed: %s", isc_result_totext(result));
85
86 result = dns_master_loadstream(fp, name, name, rdclass, 0,
87 &callbacks, mctx);
88 if (result != ISC_R_SUCCESS)
89 fatal("can't load from input: %s", isc_result_totext(result));
90
91 result = dns_db_endload(db, &callbacks);
92 if (result != ISC_R_SUCCESS)
93 fatal("dns_db_endload failed: %s", isc_result_totext(result));
94}
95
96static isc_result_t
97loadset(const char *filename, dns_rdataset_t *rdataset) {
98 isc_result_t result;
99 dns_db_t *db = NULL;
100 dns_dbnode_t *node = NULL;
101 char setname[DNS_NAME_FORMATSIZE];
102
103 dns_name_format(name, setname, sizeof(setname));
104
105 result = dns_db_create(mctx, "rbt", name, dns_dbtype_zone,
106 rdclass, 0, NULL, &db);
107 if (result != ISC_R_SUCCESS)
108 fatal("can't create database");
109
110 if (strcmp(filename, "-") == 0) {
111 db_load_from_stream(db, stdin);
112 filename = "input";
113 } else {
275a6a3b
WK
114 result = dns_db_load(db, filename, dns_masterformat_text,
115 DNS_MASTER_NOTTL);
0c91911b
MA
116 if (result != ISC_R_SUCCESS && result != DNS_R_SEENINCLUDE)
117 fatal("can't load %s: %s", filename,
118 isc_result_totext(result));
119 }
120
994e6569 121 result = dns_db_findnode(db, name, false, &node);
0c91911b
MA
122 if (result != ISC_R_SUCCESS)
123 fatal("can't find %s node in %s", setname, filename);
124
125 result = dns_db_findrdataset(db, node, NULL, dns_rdatatype_dnskey,
126 0, 0, rdataset, NULL);
127
128 if (result == ISC_R_NOTFOUND)
129 fatal("no DNSKEY RR for %s in %s", setname, filename);
130 else if (result != ISC_R_SUCCESS)
131 fatal("dns_db_findrdataset");
132
133 if (node != NULL)
134 dns_db_detachnode(db, &node);
135 if (db != NULL)
136 dns_db_detach(&db);
137 return (result);
138}
139
140static void
141loadkey(char *filename, unsigned char *key_buf, unsigned int key_buf_size,
142 dns_rdata_t *rdata)
143{
144 isc_result_t result;
145 dst_key_t *key = NULL;
146 isc_buffer_t keyb;
147 isc_region_t r;
148
149 dns_rdata_init(rdata);
150
151 isc_buffer_init(&keyb, key_buf, key_buf_size);
152
153 result = dst_key_fromnamedfile(filename, NULL, DST_TYPE_PUBLIC,
154 mctx, &key);
155 if (result != ISC_R_SUCCESS)
156 fatal("invalid keyfile name %s: %s",
157 filename, isc_result_totext(result));
158
159 if (verbose > 2) {
160 char keystr[DST_KEY_FORMATSIZE];
161
162 dst_key_format(key, keystr, sizeof(keystr));
163 fprintf(stderr, "%s: %s\n", program, keystr);
164 }
165
166 result = dst_key_todns(key, &keyb);
167 if (result != ISC_R_SUCCESS)
168 fatal("can't decode key");
169
170 isc_buffer_usedregion(&keyb, &r);
171 dns_rdata_fromregion(rdata, dst_key_class(key),
172 dns_rdatatype_dnskey, &r);
173
174 rdclass = dst_key_class(key);
175
4df4a8e7 176 name = dns_fixedname_initname(&fixed);
0c91911b
MA
177 result = dns_name_copy(dst_key_name(key), name, NULL);
178 if (result != ISC_R_SUCCESS)
179 fatal("can't copy name");
180
181 dst_key_free(&key);
182}
183
184static void
185emit(const char *dir, dns_rdata_t *rdata) {
186 isc_result_t result;
187 char keystr[DST_KEY_FORMATSIZE];
6b043429
MA
188 char pubname[1024];
189 char priname[1024];
0c91911b 190 isc_buffer_t buf;
6b043429 191 dst_key_t *key = NULL, *tmp = NULL;
0c91911b
MA
192
193 isc_buffer_init(&buf, rdata->data, rdata->length);
194 isc_buffer_add(&buf, rdata->length);
195 result = dst_key_fromdns(name, rdclass, &buf, mctx, &key);
196 if (result != ISC_R_SUCCESS) {
197 fatal("dst_key_fromdns: %s", isc_result_totext(result));
198 }
199
6b043429 200 isc_buffer_init(&buf, pubname, sizeof(pubname));
0c91911b
MA
201 result = dst_key_buildfilename(key, DST_TYPE_PUBLIC, dir, &buf);
202 if (result != ISC_R_SUCCESS) {
203 fatal("Failed to build public key filename: %s",
204 isc_result_totext(result));
205 }
6b043429
MA
206 isc_buffer_init(&buf, priname, sizeof(priname));
207 result = dst_key_buildfilename(key, DST_TYPE_PRIVATE, dir, &buf);
208 if (result != ISC_R_SUCCESS) {
209 fatal("Failed to build private key filename: %s",
210 isc_result_totext(result));
211 }
212
213 result = dst_key_fromfile(dst_key_name(key), dst_key_id(key),
214 dst_key_alg(key),
215 DST_TYPE_PUBLIC | DST_TYPE_PRIVATE,
216 dir, mctx, &tmp);
217 if (result == ISC_R_SUCCESS) {
218 if (dst_key_isprivate(tmp) && !dst_key_isexternal(tmp))
219 fatal("Private key already exists in %s", priname);
220 dst_key_free(&tmp);
221 }
222
994e6569 223 dst_key_setexternal(key, true);
6b043429
MA
224 if (setpub)
225 dst_key_settime(key, DST_TIME_PUBLISH, pub);
226 if (setdel)
227 dst_key_settime(key, DST_TIME_DELETE, del);
e939674d
MA
228 if (setsyncadd)
229 dst_key_settime(key, DST_TIME_SYNCPUBLISH, syncadd);
230 if (setsyncdel)
231 dst_key_settime(key, DST_TIME_SYNCDELETE, syncdel);
232
6b043429
MA
233 if (setttl)
234 dst_key_setttl(key, ttl);
0c91911b
MA
235
236 result = dst_key_tofile(key, DST_TYPE_PUBLIC|DST_TYPE_PRIVATE,
237 dir);
238 if (result != ISC_R_SUCCESS) {
239 dst_key_format(key, keystr, sizeof(keystr));
240 fatal("Failed to write key %s: %s", keystr,
241 isc_result_totext(result));
242 }
6b043429 243 printf("%s\n", pubname);
0c91911b
MA
244
245 isc_buffer_clear(&buf);
246 result = dst_key_buildfilename(key, DST_TYPE_PRIVATE, dir, &buf);
247 if (result != ISC_R_SUCCESS) {
248 fatal("Failed to build private key filename: %s",
249 isc_result_totext(result));
250 }
6b043429 251 printf("%s\n", priname);
0c91911b
MA
252 dst_key_free(&key);
253}
254
255ISC_PLATFORM_NORETURN_PRE static void
256usage(void) ISC_PLATFORM_NORETURN_POST;
257
258static void
259usage(void) {
260 fprintf(stderr, "Usage:\n");
6b043429
MA
261 fprintf(stderr, " %s options [-K dir] keyfile\n\n", program);
262 fprintf(stderr, " %s options -f file [keyname]\n\n", program);
0c91911b
MA
263 fprintf(stderr, "Version: %s\n", VERSION);
264 fprintf(stderr, "Options:\n");
6b043429 265 fprintf(stderr, " -f file: read key from zone file\n");
0c91911b 266 fprintf(stderr, " -K <directory>: directory in which to store "
6b043429
MA
267 "the key files\n");
268 fprintf(stderr, " -L ttl: set default key TTL\n");
269 fprintf(stderr, " -v <verbose level>\n");
42782931 270 fprintf(stderr, " -V: print version information\n");
6b043429
MA
271 fprintf(stderr, " -h: print usage and exit\n");
272 fprintf(stderr, "Timing options:\n");
273 fprintf(stderr, " -P date/[+-]offset/none: set/unset key "
274 "publication date\n");
e939674d
MA
275 fprintf(stderr, " -P sync date/[+-]offset/none: set/unset "
276 "CDS and CDNSKEY publication date\n");
6b043429
MA
277 fprintf(stderr, " -D date/[+-]offset/none: set/unset key "
278 "deletion date\n");
e939674d
MA
279 fprintf(stderr, " -D sync date/[+-]offset/none: set/unset "
280 "CDS and CDNSKEY deletion date\n");
0c91911b
MA
281
282 exit (-1);
283}
284
285int
286main(int argc, char **argv) {
287 char *classname = NULL;
288 char *filename = NULL, *dir = NULL, *namestr;
289 char *endp;
290 int ch;
291 isc_result_t result;
292 isc_log_t *log = NULL;
0c91911b
MA
293 dns_rdataset_t rdataset;
294 dns_rdata_t rdata;
295 isc_stdtime_t now;
296
297 dns_rdata_init(&rdata);
298 isc_stdtime_get(&now);
299
300 if (argc == 1)
301 usage();
302
303 result = isc_mem_create(0, 0, &mctx);
304 if (result != ISC_R_SUCCESS)
305 fatal("out of memory");
306
c3b8130f 307#if USE_PKCS11
acbb301e
EH
308 pk11_result_register();
309#endif
0c91911b
MA
310 dns_result_register();
311
994e6569 312 isc_commandline_errprint = false;
0c91911b 313
42782931 314#define CMDLINE_FLAGS "D:f:hK:L:P:v:V"
6b043429 315 while ((ch = isc_commandline_parse(argc, argv, CMDLINE_FLAGS)) != -1) {
0c91911b 316 switch (ch) {
63737247 317 case 'D':
e939674d
MA
318 /* -Dsync ? */
319 if (isoptarg("sync", argv, usage)) {
320 if (setsyncdel)
321 fatal("-D sync specified more than "
322 "once");
323
324 syncdel = strtotime(isc_commandline_argument,
325 now, now, &setsyncdel);
326 break;
327 }
328 /* -Ddnskey ? */
329 (void)isoptarg("dnskey", argv, usage);
63737247
TU
330 if (setdel)
331 fatal("-D specified more than once");
0c91911b 332
a165a17a
EH
333 del = strtotime(isc_commandline_argument,
334 now, now, &setdel);
0c91911b
MA
335 break;
336 case 'K':
337 dir = isc_commandline_argument;
338 if (strlen(dir) == 0U)
339 fatal("directory must be non-empty string");
340 break;
6b043429 341 case 'L':
a165a17a 342 ttl = strtottl(isc_commandline_argument);
994e6569 343 setttl = true;
6b043429 344 break;
63737247 345 case 'P':
e939674d
MA
346 /* -Psync ? */
347 if (isoptarg("sync", argv, usage)) {
348 if (setsyncadd)
349 fatal("-P sync specified more than "
350 "once");
351
352 syncadd = strtotime(isc_commandline_argument,
353 now, now, &setsyncadd);
354 break;
355 }
356 /* -Pdnskey ? */
357 (void)isoptarg("dnskey", argv, usage);
63737247
TU
358 if (setpub)
359 fatal("-P specified more than once");
0c91911b 360
a165a17a
EH
361 pub = strtotime(isc_commandline_argument,
362 now, now, &setpub);
63737247 363 break;
0c91911b
MA
364 case 'f':
365 filename = isc_commandline_argument;
366 break;
367 case 'v':
368 verbose = strtol(isc_commandline_argument, &endp, 0);
369 if (*endp != '\0')
370 fatal("-v must be followed by a number");
371 break;
372 case '?':
373 if (isc_commandline_option != '?')
374 fprintf(stderr, "%s: invalid argument -%c\n",
375 program, isc_commandline_option);
376 /* FALLTHROUGH */
377 case 'h':
42782931 378 /* Does not return. */
0c91911b
MA
379 usage();
380
42782931
MS
381 case 'V':
382 /* Does not return. */
383 version(program);
384
0c91911b
MA
385 default:
386 fprintf(stderr, "%s: unhandled option -%c\n",
387 program, isc_commandline_option);
388 exit(1);
389 }
390 }
391
392 rdclass = strtoclass(classname);
393
394 if (argc < isc_commandline_index + 1 && filename == NULL)
395 fatal("the key file name was not specified");
396 if (argc > isc_commandline_index + 1)
397 fatal("extraneous arguments");
398
3a4f820d 399 result = dst_lib_init(mctx, NULL);
0c91911b
MA
400 if (result != ISC_R_SUCCESS)
401 fatal("could not initialize dst: %s",
402 isc_result_totext(result));
0c91911b 403
11463c0a 404 setup_logging(mctx, &log);
0c91911b
MA
405
406 dns_rdataset_init(&rdataset);
407
408 if (filename != NULL) {
6b043429
MA
409 if (argc < isc_commandline_index + 1) {
410 /* using filename as zone name */
0c91911b
MA
411 namestr = filename;
412 } else
413 namestr = argv[isc_commandline_index];
414
415 result = initname(namestr);
416 if (result != ISC_R_SUCCESS)
417 fatal("could not initialize name %s", namestr);
418
419 result = loadset(filename, &rdataset);
420
421 if (result != ISC_R_SUCCESS)
422 fatal("could not load DNSKEY set: %s\n",
423 isc_result_totext(result));
424
425 for (result = dns_rdataset_first(&rdataset);
426 result == ISC_R_SUCCESS;
427 result = dns_rdataset_next(&rdataset)) {
428
429 dns_rdata_init(&rdata);
430 dns_rdataset_current(&rdataset, &rdata);
431 emit(dir, &rdata);
432 }
433 } else {
434 unsigned char key_buf[DST_KEY_MAXSIZE];
435
436 loadkey(argv[isc_commandline_index], key_buf,
437 DST_KEY_MAXSIZE, &rdata);
438
439 emit(dir, &rdata);
440 }
441
442 if (dns_rdataset_isassociated(&rdataset))
443 dns_rdataset_disassociate(&rdataset);
444 cleanup_logging(&log);
586e65ea 445 dst_lib_destroy();
0c91911b
MA
446 dns_name_destroy();
447 if (verbose > 10)
448 isc_mem_stats(mctx, stdout);
449 isc_mem_destroy(&mctx);
450
451 fflush(stdout);
452 if (ferror(stdout)) {
453 fprintf(stderr, "write error\n");
454 return (1);
455 } else
456 return (0);
457}