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