No empty .Rs/.Re
[netbsd-mini2440.git] / external / bsd / bind / dist / bin / dnssec / dnssec-dsfromkey.c
blob950fb0bc14e48df81c001eaed0c81dfa315b40ad
1 /* $NetBSD$ */
3 /*
4 * Copyright (C) 2008, 2009 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.
19 /* Id: dnssec-dsfromkey.c,v 1.16 2009/10/12 20:48:10 each Exp */
21 /*! \file */
23 #include <config.h>
25 #include <stdlib.h>
27 #include <isc/buffer.h>
28 #include <isc/commandline.h>
29 #include <isc/entropy.h>
30 #include <isc/hash.h>
31 #include <isc/mem.h>
32 #include <isc/print.h>
33 #include <isc/string.h>
34 #include <isc/util.h>
36 #include <dns/db.h>
37 #include <dns/dbiterator.h>
38 #include <dns/ds.h>
39 #include <dns/fixedname.h>
40 #include <dns/log.h>
41 #include <dns/keyvalues.h>
42 #include <dns/master.h>
43 #include <dns/name.h>
44 #include <dns/rdata.h>
45 #include <dns/rdataclass.h>
46 #include <dns/rdataset.h>
47 #include <dns/rdatasetiter.h>
48 #include <dns/rdatatype.h>
49 #include <dns/result.h>
51 #include <dst/dst.h>
53 #include "dnssectool.h"
55 #ifndef PATH_MAX
56 #define PATH_MAX 1024 /* AIX, WIN32, and others don't define this. */
57 #endif
59 const char *program = "dnssec-dsfromkey";
60 int verbose;
62 static dns_rdataclass_t rdclass;
63 static dns_fixedname_t fixed;
64 static dns_name_t *name = NULL;
65 static isc_mem_t *mctx = NULL;
67 static isc_result_t
68 initname(char *setname) {
69 isc_result_t result;
70 isc_buffer_t buf;
72 dns_fixedname_init(&fixed);
73 name = dns_fixedname_name(&fixed);
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);
81 static isc_result_t
82 loadsetfromfile(char *filename, dns_rdataset_t *rdataset) {
83 isc_result_t result;
84 dns_db_t *db = NULL;
85 dns_dbnode_t *node = NULL;
86 char setname[DNS_NAME_FORMATSIZE];
88 dns_name_format(name, setname, sizeof(setname));
90 result = dns_db_create(mctx, "rbt", name, dns_dbtype_zone,
91 rdclass, 0, NULL, &db);
92 if (result != ISC_R_SUCCESS)
93 fatal("can't create database");
95 result = dns_db_load(db, filename);
96 if (result != ISC_R_SUCCESS && result != DNS_R_SEENINCLUDE)
97 fatal("can't load %s: %s", filename, isc_result_totext(result));
99 result = dns_db_findnode(db, name, ISC_FALSE, &node);
100 if (result != ISC_R_SUCCESS)
101 fatal("can't find %s node in %s", setname, filename);
103 result = dns_db_findrdataset(db, node, NULL, dns_rdatatype_dnskey,
104 0, 0, rdataset, NULL);
106 if (result == ISC_R_NOTFOUND)
107 fatal("no DNSKEY RR for %s in %s", setname, filename);
108 else if (result != ISC_R_SUCCESS)
109 fatal("dns_db_findrdataset");
111 if (node != NULL)
112 dns_db_detachnode(db, &node);
113 if (db != NULL)
114 dns_db_detach(&db);
115 return (result);
118 static isc_result_t
119 loadkeyset(char *dirname, dns_rdataset_t *rdataset) {
120 isc_result_t result;
121 char filename[PATH_MAX + 1];
122 isc_buffer_t buf;
124 dns_rdataset_init(rdataset);
126 isc_buffer_init(&buf, filename, sizeof(filename));
127 if (dirname != NULL) {
128 /* allow room for a trailing slash */
129 if (strlen(dirname) >= isc_buffer_availablelength(&buf))
130 return (ISC_R_NOSPACE);
131 isc_buffer_putstr(&buf, dirname);
132 if (dirname[strlen(dirname) - 1] != '/')
133 isc_buffer_putstr(&buf, "/");
136 if (isc_buffer_availablelength(&buf) < 7)
137 return (ISC_R_NOSPACE);
138 isc_buffer_putstr(&buf, "keyset-");
140 result = dns_name_tofilenametext(name, ISC_FALSE, &buf);
141 check_result(result, "dns_name_tofilenametext()");
142 if (isc_buffer_availablelength(&buf) == 0)
143 return (ISC_R_NOSPACE);
144 isc_buffer_putuint8(&buf, 0);
146 return (loadsetfromfile(filename, rdataset));
149 static void
150 loadkey(char *filename, unsigned char *key_buf, unsigned int key_buf_size,
151 dns_rdata_t *rdata)
153 isc_result_t result;
154 dst_key_t *key = NULL;
155 isc_buffer_t keyb;
156 isc_region_t r;
158 dns_rdata_init(rdata);
160 isc_buffer_init(&keyb, key_buf, key_buf_size);
162 result = dst_key_fromnamedfile(filename, NULL, DST_TYPE_PUBLIC,
163 mctx, &key);
164 if (result != ISC_R_SUCCESS)
165 fatal("invalid keyfile name %s: %s",
166 filename, isc_result_totext(result));
168 if (verbose > 2) {
169 char keystr[DST_KEY_FORMATSIZE];
171 dst_key_format(key, keystr, sizeof(keystr));
172 fprintf(stderr, "%s: %s\n", program, keystr);
175 result = dst_key_todns(key, &keyb);
176 if (result != ISC_R_SUCCESS)
177 fatal("can't decode key");
179 isc_buffer_usedregion(&keyb, &r);
180 dns_rdata_fromregion(rdata, dst_key_class(key),
181 dns_rdatatype_dnskey, &r);
183 rdclass = dst_key_class(key);
185 dns_fixedname_init(&fixed);
186 name = dns_fixedname_name(&fixed);
187 result = dns_name_copy(dst_key_name(key), name, NULL);
188 if (result != ISC_R_SUCCESS)
189 fatal("can't copy name");
191 dst_key_free(&key);
194 static void
195 logkey(dns_rdata_t *rdata)
197 isc_result_t result;
198 dst_key_t *key = NULL;
199 isc_buffer_t buf;
200 char keystr[DST_KEY_FORMATSIZE];
202 isc_buffer_init(&buf, rdata->data, rdata->length);
203 isc_buffer_add(&buf, rdata->length);
204 result = dst_key_fromdns(name, rdclass, &buf, mctx, &key);
205 if (result != ISC_R_SUCCESS)
206 return;
208 dst_key_format(key, keystr, sizeof(keystr));
209 fprintf(stderr, "%s: %s\n", program, keystr);
211 dst_key_free(&key);
214 static void
215 emit(unsigned int dtype, isc_boolean_t showall, char *lookaside,
216 dns_rdata_t *rdata)
218 isc_result_t result;
219 unsigned char buf[DNS_DS_BUFFERSIZE];
220 char text_buf[DST_KEY_MAXTEXTSIZE];
221 char name_buf[DNS_NAME_MAXWIRE];
222 char class_buf[10];
223 isc_buffer_t textb, nameb, classb;
224 isc_region_t r;
225 dns_rdata_t ds;
226 dns_rdata_dnskey_t dnskey;
228 isc_buffer_init(&textb, text_buf, sizeof(text_buf));
229 isc_buffer_init(&nameb, name_buf, sizeof(name_buf));
230 isc_buffer_init(&classb, class_buf, sizeof(class_buf));
232 dns_rdata_init(&ds);
234 result = dns_rdata_tostruct(rdata, &dnskey, NULL);
235 if (result != ISC_R_SUCCESS)
236 fatal("can't convert DNSKEY");
238 if ((dnskey.flags & DNS_KEYFLAG_KSK) == 0 && !showall)
239 return;
241 result = dns_ds_buildrdata(name, rdata, dtype, buf, &ds);
242 if (result != ISC_R_SUCCESS)
243 fatal("can't build record");
245 result = dns_name_totext(name, ISC_FALSE, &nameb);
246 if (result != ISC_R_SUCCESS)
247 fatal("can't print name");
249 /* Add lookaside origin, if set */
250 if (lookaside != NULL) {
251 if (isc_buffer_availablelength(&nameb) < strlen(lookaside))
252 fatal("DLV origin '%s' is too long", lookaside);
253 isc_buffer_putstr(&nameb, lookaside);
254 if (lookaside[strlen(lookaside) - 1] != '.') {
255 if (isc_buffer_availablelength(&nameb) < 1)
256 fatal("DLV origin '%s' is too long", lookaside);
257 isc_buffer_putstr(&nameb, ".");
261 result = dns_rdata_totext(&ds, (dns_name_t *) NULL, &textb);
262 if (result != ISC_R_SUCCESS)
263 fatal("can't print rdata");
265 result = dns_rdataclass_totext(rdclass, &classb);
266 if (result != ISC_R_SUCCESS)
267 fatal("can't print class");
269 isc_buffer_usedregion(&nameb, &r);
270 fwrite(r.base, 1, r.length, stdout);
272 putchar(' ');
274 isc_buffer_usedregion(&classb, &r);
275 fwrite(r.base, 1, r.length, stdout);
277 if (lookaside == NULL)
278 printf(" DS ");
279 else
280 printf(" DLV ");
282 isc_buffer_usedregion(&textb, &r);
283 fwrite(r.base, 1, r.length, stdout);
284 putchar('\n');
287 ISC_PLATFORM_NORETURN_PRE static void
288 usage(void) ISC_PLATFORM_NORETURN_POST;
290 static void
291 usage(void) {
292 fprintf(stderr, "Usage:\n");
293 fprintf(stderr, " %s options [-K dir] keyfile\n\n", program);
294 fprintf(stderr, " %s options [-K dir] [-c class] -s dnsname\n\n",
295 program);
296 fprintf(stderr, " %s options -f zonefile (as zone name)\n\n", program);
297 fprintf(stderr, " %s options -f zonefile zonename\n\n", program);
298 fprintf(stderr, "Version: %s\n", VERSION);
299 fprintf(stderr, "Options:\n");
300 fprintf(stderr, " -v <verbose level>\n");
301 fprintf(stderr, " -K <directory>: directory in which to find "
302 "key file or keyset file\n");
303 fprintf(stderr, " -a algorithm: digest algorithm "
304 "(SHA-1 or SHA-256)\n");
305 fprintf(stderr, " -1: use SHA-1\n");
306 fprintf(stderr, " -2: use SHA-256\n");
307 fprintf(stderr, " -l: add lookaside zone and print DLV records\n");
308 fprintf(stderr, " -s: read keyset from keyset-<dnsname> file\n");
309 fprintf(stderr, " -c class: rdata class for DS set (default: IN)\n");
310 fprintf(stderr, " -f file: read keyset from zone file\n");
311 fprintf(stderr, " -A: when used with -f, "
312 "include all keys in DS set, not just KSKs\n");
313 fprintf(stderr, "Output: DS or DLV RRs\n");
315 exit (-1);
319 main(int argc, char **argv) {
320 char *algname = NULL, *classname = NULL;
321 char *filename = NULL, *dir = NULL, *namestr;
322 char *lookaside = NULL;
323 char *endp;
324 int ch;
325 unsigned int dtype = DNS_DSDIGEST_SHA1;
326 isc_boolean_t both = ISC_TRUE;
327 isc_boolean_t usekeyset = ISC_FALSE;
328 isc_boolean_t showall = ISC_FALSE;
329 isc_result_t result;
330 isc_log_t *log = NULL;
331 isc_entropy_t *ectx = NULL;
332 dns_rdataset_t rdataset;
333 dns_rdata_t rdata;
335 dns_rdata_init(&rdata);
337 if (argc == 1)
338 usage();
340 result = isc_mem_create(0, 0, &mctx);
341 if (result != ISC_R_SUCCESS)
342 fatal("out of memory");
344 dns_result_register();
346 isc_commandline_errprint = ISC_FALSE;
348 while ((ch = isc_commandline_parse(argc, argv,
349 "12Aa:c:d:Ff:K:l:sv:h")) != -1) {
350 switch (ch) {
351 case '1':
352 dtype = DNS_DSDIGEST_SHA1;
353 both = ISC_FALSE;
354 break;
355 case '2':
356 dtype = DNS_DSDIGEST_SHA256;
357 both = ISC_FALSE;
358 break;
359 case 'A':
360 showall = ISC_TRUE;
361 break;
362 case 'a':
363 algname = isc_commandline_argument;
364 both = ISC_FALSE;
365 break;
366 case 'c':
367 classname = isc_commandline_argument;
368 break;
369 case 'd':
370 fprintf(stderr, "%s: the -d option is deprecated; "
371 "use -K\n", program);
372 /* fall through */
373 case 'K':
374 dir = isc_commandline_argument;
375 if (strlen(dir) == 0U)
376 fatal("directory must be non-empty string");
377 break;
378 case 'f':
379 filename = isc_commandline_argument;
380 break;
381 case 'l':
382 lookaside = isc_commandline_argument;
383 if (strlen(lookaside) == 0U)
384 fatal("lookaside must be a non-empty string");
385 break;
386 case 's':
387 usekeyset = ISC_TRUE;
388 break;
389 case 'v':
390 verbose = strtol(isc_commandline_argument, &endp, 0);
391 if (*endp != '\0')
392 fatal("-v must be followed by a number");
393 break;
394 case 'F':
395 /* Reserved for FIPS mode */
396 /* FALLTHROUGH */
397 case '?':
398 if (isc_commandline_option != '?')
399 fprintf(stderr, "%s: invalid argument -%c\n",
400 program, isc_commandline_option);
401 /* FALLTHROUGH */
402 case 'h':
403 usage();
405 default:
406 fprintf(stderr, "%s: unhandled option -%c\n",
407 program, isc_commandline_option);
408 exit(1);
412 if (algname != NULL) {
413 if (strcasecmp(algname, "SHA1") == 0 ||
414 strcasecmp(algname, "SHA-1") == 0)
415 dtype = DNS_DSDIGEST_SHA1;
416 else if (strcasecmp(algname, "SHA256") == 0 ||
417 strcasecmp(algname, "SHA-256") == 0)
418 dtype = DNS_DSDIGEST_SHA256;
419 else
420 fatal("unknown algorithm %s", algname);
423 rdclass = strtoclass(classname);
425 if (usekeyset && filename != NULL)
426 fatal("cannot use both -s and -f");
428 /* When not using -f, -A is implicit */
429 if (filename == NULL)
430 showall = ISC_TRUE;
432 if (argc < isc_commandline_index + 1 && filename == NULL)
433 fatal("the key file name was not specified");
434 if (argc > isc_commandline_index + 1)
435 fatal("extraneous arguments");
437 if (ectx == NULL)
438 setup_entropy(mctx, NULL, &ectx);
439 result = isc_hash_create(mctx, ectx, DNS_NAME_MAXWIRE);
440 if (result != ISC_R_SUCCESS)
441 fatal("could not initialize hash");
442 result = dst_lib_init(mctx, ectx,
443 ISC_ENTROPY_BLOCKING | ISC_ENTROPY_GOODONLY);
444 if (result != ISC_R_SUCCESS)
445 fatal("could not initialize dst: %s",
446 isc_result_totext(result));
447 isc_entropy_stopcallbacksources(ectx);
449 setup_logging(verbose, mctx, &log);
451 dns_rdataset_init(&rdataset);
453 if (usekeyset || filename != NULL) {
454 if (argc < isc_commandline_index + 1 && filename != NULL) {
455 /* using zone name as the zone file name */
456 namestr = filename;
457 } else
458 namestr = argv[isc_commandline_index];
460 result = initname(namestr);
461 if (result != ISC_R_SUCCESS)
462 fatal("could not initialize name %s", namestr);
464 if (usekeyset)
465 result = loadkeyset(dir, &rdataset);
466 else
467 result = loadsetfromfile(filename, &rdataset);
469 if (result != ISC_R_SUCCESS)
470 fatal("could not load DNSKEY set: %s\n",
471 isc_result_totext(result));
473 for (result = dns_rdataset_first(&rdataset);
474 result == ISC_R_SUCCESS;
475 result = dns_rdataset_next(&rdataset)) {
476 dns_rdata_init(&rdata);
477 dns_rdataset_current(&rdataset, &rdata);
479 if (verbose > 2)
480 logkey(&rdata);
482 if (both) {
483 emit(DNS_DSDIGEST_SHA1, showall, lookaside,
484 &rdata);
485 emit(DNS_DSDIGEST_SHA256, showall, lookaside,
486 &rdata);
487 } else
488 emit(dtype, showall, lookaside, &rdata);
490 } else {
491 unsigned char key_buf[DST_KEY_MAXSIZE];
493 loadkey(argv[isc_commandline_index], key_buf,
494 DST_KEY_MAXSIZE, &rdata);
496 if (both) {
497 emit(DNS_DSDIGEST_SHA1, showall, lookaside, &rdata);
498 emit(DNS_DSDIGEST_SHA256, showall, lookaside, &rdata);
499 } else
500 emit(dtype, showall, lookaside, &rdata);
503 if (dns_rdataset_isassociated(&rdataset))
504 dns_rdataset_disassociate(&rdataset);
505 cleanup_logging(&log);
506 dst_lib_destroy();
507 isc_hash_destroy();
508 cleanup_entropy(&ectx);
509 dns_name_destroy();
510 if (verbose > 10)
511 isc_mem_stats(mctx, stdout);
512 isc_mem_destroy(&mctx);
514 fflush(stdout);
515 if (ferror(stdout)) {
516 fprintf(stderr, "write error\n");
517 return (1);
518 } else
519 return (0);