1 /* $NetBSD: dnssec-dsfromkey.c,v 1.11 2015/07/08 17:28:55 christos Exp $ */
4 * Copyright (C) 2008-2012, 2014, 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-dsfromkey";
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_uint32_t ttl
;
70 static isc_boolean_t emitttl
= ISC_FALSE
;
73 initname(char *setname
) {
77 dns_fixedname_init(&fixed
);
78 name
= dns_fixedname_name(&fixed
);
80 isc_buffer_init(&buf
, setname
, strlen(setname
));
81 isc_buffer_add(&buf
, strlen(setname
));
82 result
= dns_name_fromtext(name
, &buf
, dns_rootname
, 0, NULL
);
87 db_load_from_stream(dns_db_t
*db
, FILE *fp
) {
89 dns_rdatacallbacks_t callbacks
;
91 dns_rdatacallbacks_init(&callbacks
);
92 result
= dns_db_beginload(db
, &callbacks
);
93 if (result
!= ISC_R_SUCCESS
)
94 fatal("dns_db_beginload failed: %s", isc_result_totext(result
));
96 result
= dns_master_loadstream(fp
, name
, name
, rdclass
, 0,
98 if (result
!= ISC_R_SUCCESS
)
99 fatal("can't load from input: %s", isc_result_totext(result
));
101 result
= dns_db_endload(db
, &callbacks
);
102 if (result
!= ISC_R_SUCCESS
)
103 fatal("dns_db_endload failed: %s", isc_result_totext(result
));
107 loadset(const char *filename
, dns_rdataset_t
*rdataset
) {
110 dns_dbnode_t
*node
= NULL
;
111 char setname
[DNS_NAME_FORMATSIZE
];
113 dns_name_format(name
, setname
, sizeof(setname
));
115 result
= dns_db_create(mctx
, "rbt", name
, dns_dbtype_zone
,
116 rdclass
, 0, NULL
, &db
);
117 if (result
!= ISC_R_SUCCESS
)
118 fatal("can't create database");
120 if (strcmp(filename
, "-") == 0) {
121 db_load_from_stream(db
, stdin
);
124 result
= dns_db_load(db
, filename
);
125 if (result
!= ISC_R_SUCCESS
&& result
!= DNS_R_SEENINCLUDE
)
126 fatal("can't load %s: %s", filename
,
127 isc_result_totext(result
));
130 result
= dns_db_findnode(db
, name
, ISC_FALSE
, &node
);
131 if (result
!= ISC_R_SUCCESS
)
132 fatal("can't find %s node in %s", setname
, filename
);
134 result
= dns_db_findrdataset(db
, node
, NULL
, dns_rdatatype_dnskey
,
135 0, 0, rdataset
, NULL
);
137 if (result
== ISC_R_NOTFOUND
)
138 fatal("no DNSKEY RR for %s in %s", setname
, filename
);
139 else if (result
!= ISC_R_SUCCESS
)
140 fatal("dns_db_findrdataset");
143 dns_db_detachnode(db
, &node
);
150 loadkeyset(char *dirname
, dns_rdataset_t
*rdataset
) {
152 char filename
[PATH_MAX
+ 1];
155 dns_rdataset_init(rdataset
);
157 isc_buffer_init(&buf
, filename
, sizeof(filename
));
158 if (dirname
!= NULL
) {
159 /* allow room for a trailing slash */
160 if (strlen(dirname
) >= isc_buffer_availablelength(&buf
))
161 return (ISC_R_NOSPACE
);
162 isc_buffer_putstr(&buf
, dirname
);
163 if (dirname
[strlen(dirname
) - 1] != '/')
164 isc_buffer_putstr(&buf
, "/");
167 if (isc_buffer_availablelength(&buf
) < 7)
168 return (ISC_R_NOSPACE
);
169 isc_buffer_putstr(&buf
, "keyset-");
171 result
= dns_name_tofilenametext(name
, ISC_FALSE
, &buf
);
172 check_result(result
, "dns_name_tofilenametext()");
173 if (isc_buffer_availablelength(&buf
) == 0)
174 return (ISC_R_NOSPACE
);
175 isc_buffer_putuint8(&buf
, 0);
177 return (loadset(filename
, rdataset
));
181 loadkey(char *filename
, unsigned char *key_buf
, unsigned int key_buf_size
,
185 dst_key_t
*key
= NULL
;
189 dns_rdata_init(rdata
);
191 isc_buffer_init(&keyb
, key_buf
, key_buf_size
);
193 result
= dst_key_fromnamedfile(filename
, NULL
, DST_TYPE_PUBLIC
,
195 if (result
!= ISC_R_SUCCESS
)
196 fatal("invalid keyfile name %s: %s",
197 filename
, isc_result_totext(result
));
200 char keystr
[DST_KEY_FORMATSIZE
];
202 dst_key_format(key
, keystr
, sizeof(keystr
));
203 fprintf(stderr
, "%s: %s\n", program
, keystr
);
206 result
= dst_key_todns(key
, &keyb
);
207 if (result
!= ISC_R_SUCCESS
)
208 fatal("can't decode key");
210 isc_buffer_usedregion(&keyb
, &r
);
211 dns_rdata_fromregion(rdata
, dst_key_class(key
),
212 dns_rdatatype_dnskey
, &r
);
214 rdclass
= dst_key_class(key
);
216 dns_fixedname_init(&fixed
);
217 name
= dns_fixedname_name(&fixed
);
218 result
= dns_name_copy(dst_key_name(key
), name
, NULL
);
219 if (result
!= ISC_R_SUCCESS
)
220 fatal("can't copy name");
226 logkey(dns_rdata_t
*rdata
)
229 dst_key_t
*key
= NULL
;
231 char keystr
[DST_KEY_FORMATSIZE
];
233 isc_buffer_init(&buf
, rdata
->data
, rdata
->length
);
234 isc_buffer_add(&buf
, rdata
->length
);
235 result
= dst_key_fromdns(name
, rdclass
, &buf
, mctx
, &key
);
236 if (result
!= ISC_R_SUCCESS
)
239 dst_key_format(key
, keystr
, sizeof(keystr
));
240 fprintf(stderr
, "%s: %s\n", program
, keystr
);
246 emit(unsigned int dtype
, isc_boolean_t showall
, char *lookaside
,
250 unsigned char buf
[DNS_DS_BUFFERSIZE
];
251 char text_buf
[DST_KEY_MAXTEXTSIZE
];
252 char name_buf
[DNS_NAME_MAXWIRE
];
254 isc_buffer_t textb
, nameb
, classb
;
257 dns_rdata_dnskey_t dnskey
;
259 isc_buffer_init(&textb
, text_buf
, sizeof(text_buf
));
260 isc_buffer_init(&nameb
, name_buf
, sizeof(name_buf
));
261 isc_buffer_init(&classb
, class_buf
, sizeof(class_buf
));
265 result
= dns_rdata_tostruct(rdata
, &dnskey
, NULL
);
266 if (result
!= ISC_R_SUCCESS
)
267 fatal("can't convert DNSKEY");
269 if ((dnskey
.flags
& DNS_KEYFLAG_KSK
) == 0 && !showall
)
272 result
= dns_ds_buildrdata(name
, rdata
, dtype
, buf
, &ds
);
273 if (result
!= ISC_R_SUCCESS
)
274 fatal("can't build record");
276 result
= dns_name_totext(name
, ISC_FALSE
, &nameb
);
277 if (result
!= ISC_R_SUCCESS
)
278 fatal("can't print name");
280 /* Add lookaside origin, if set */
281 if (lookaside
!= NULL
) {
282 if (isc_buffer_availablelength(&nameb
) < strlen(lookaside
))
283 fatal("DLV origin '%s' is too long", lookaside
);
284 isc_buffer_putstr(&nameb
, lookaside
);
285 if (lookaside
[strlen(lookaside
) - 1] != '.') {
286 if (isc_buffer_availablelength(&nameb
) < 1)
287 fatal("DLV origin '%s' is too long", lookaside
);
288 isc_buffer_putstr(&nameb
, ".");
292 result
= dns_rdata_tofmttext(&ds
, (dns_name_t
*) NULL
, 0, 0, 0, "",
295 if (result
!= ISC_R_SUCCESS
)
296 fatal("can't print rdata");
298 result
= dns_rdataclass_totext(rdclass
, &classb
);
299 if (result
!= ISC_R_SUCCESS
)
300 fatal("can't print class");
302 isc_buffer_usedregion(&nameb
, &r
);
303 printf("%.*s ", (int)r
.length
, r
.base
);
308 isc_buffer_usedregion(&classb
, &r
);
309 printf("%.*s", (int)r
.length
, r
.base
);
311 if (lookaside
== NULL
)
316 isc_buffer_usedregion(&textb
, &r
);
317 printf("%.*s\n", (int)r
.length
, r
.base
);
320 ISC_PLATFORM_NORETURN_PRE
static void
321 usage(void) ISC_PLATFORM_NORETURN_POST
;
325 fprintf(stderr
, "Usage:\n");
326 fprintf(stderr
, " %s options [-K dir] keyfile\n\n", program
);
327 fprintf(stderr
, " %s options [-K dir] [-c class] -s dnsname\n\n",
329 fprintf(stderr
, " %s options -f zonefile (as zone name)\n\n", program
);
330 fprintf(stderr
, " %s options -f zonefile zonename\n\n", program
);
331 fprintf(stderr
, "Version: %s\n", VERSION
);
332 fprintf(stderr
, "Options:\n");
333 fprintf(stderr
, " -v <verbose level>\n");
334 fprintf(stderr
, " -V: print version information\n");
335 fprintf(stderr
, " -K <directory>: directory in which to find "
336 "key file or keyset file\n");
337 fprintf(stderr
, " -a algorithm: digest algorithm "
338 "(SHA-1, SHA-256, GOST or SHA-384)\n");
339 fprintf(stderr
, " -1: use SHA-1\n");
340 fprintf(stderr
, " -2: use SHA-256\n");
341 fprintf(stderr
, " -l: add lookaside zone and print DLV records\n");
342 fprintf(stderr
, " -s: read keyset from keyset-<dnsname> file\n");
343 fprintf(stderr
, " -c class: rdata class for DS set (default: IN)\n");
344 fprintf(stderr
, " -T TTL\n");
345 fprintf(stderr
, " -f file: read keyset from zone file\n");
346 fprintf(stderr
, " -A: when used with -f, "
347 "include all keys in DS set, not just KSKs\n");
348 fprintf(stderr
, "Output: DS or DLV RRs\n");
354 main(int argc
, char **argv
) {
355 char *algname
= NULL
, *classname
= NULL
;
356 char *filename
= NULL
, *dir
= NULL
, *namestr
;
357 char *lookaside
= NULL
;
360 unsigned int dtype
= DNS_DSDIGEST_SHA1
;
361 isc_boolean_t both
= ISC_TRUE
;
362 isc_boolean_t usekeyset
= ISC_FALSE
;
363 isc_boolean_t showall
= ISC_FALSE
;
365 isc_log_t
*log
= NULL
;
366 isc_entropy_t
*ectx
= NULL
;
367 dns_rdataset_t rdataset
;
370 dns_rdata_init(&rdata
);
375 result
= isc_mem_create(0, 0, &mctx
);
376 if (result
!= ISC_R_SUCCESS
)
377 fatal("out of memory");
380 pk11_result_register();
382 dns_result_register();
384 isc_commandline_errprint
= ISC_FALSE
;
386 while ((ch
= isc_commandline_parse(argc
, argv
,
387 "12Aa:c:d:Ff:K:l:sT:v:hV")) != -1) {
390 dtype
= DNS_DSDIGEST_SHA1
;
394 dtype
= DNS_DSDIGEST_SHA256
;
401 algname
= isc_commandline_argument
;
405 classname
= isc_commandline_argument
;
408 fprintf(stderr
, "%s: the -d option is deprecated; "
409 "use -K\n", program
);
412 dir
= isc_commandline_argument
;
413 if (strlen(dir
) == 0U)
414 fatal("directory must be non-empty string");
417 filename
= isc_commandline_argument
;
420 lookaside
= isc_commandline_argument
;
421 if (strlen(lookaside
) == 0U)
422 fatal("lookaside must be a non-empty string");
425 usekeyset
= ISC_TRUE
;
429 ttl
= atol(isc_commandline_argument
);
432 verbose
= strtol(isc_commandline_argument
, &endp
, 0);
434 fatal("-v must be followed by a number");
437 /* Reserved for FIPS mode */
440 if (isc_commandline_option
!= '?')
441 fprintf(stderr
, "%s: invalid argument -%c\n",
442 program
, isc_commandline_option
);
445 /* Does not return. */
449 /* Does not return. */
453 fprintf(stderr
, "%s: unhandled option -%c\n",
454 program
, isc_commandline_option
);
459 if (algname
!= NULL
) {
460 if (strcasecmp(algname
, "SHA1") == 0 ||
461 strcasecmp(algname
, "SHA-1") == 0)
462 dtype
= DNS_DSDIGEST_SHA1
;
463 else if (strcasecmp(algname
, "SHA256") == 0 ||
464 strcasecmp(algname
, "SHA-256") == 0)
465 dtype
= DNS_DSDIGEST_SHA256
;
466 #if defined(HAVE_OPENSSL_GOST) || defined(HAVE_PKCS11_GOST)
467 else if (strcasecmp(algname
, "GOST") == 0)
468 dtype
= DNS_DSDIGEST_GOST
;
470 else if (strcasecmp(algname
, "SHA384") == 0 ||
471 strcasecmp(algname
, "SHA-384") == 0)
472 dtype
= DNS_DSDIGEST_SHA384
;
474 fatal("unknown algorithm %s", algname
);
477 rdclass
= strtoclass(classname
);
479 if (usekeyset
&& filename
!= NULL
)
480 fatal("cannot use both -s and -f");
482 /* When not using -f, -A is implicit */
483 if (filename
== NULL
)
486 if (argc
< isc_commandline_index
+ 1 && filename
== NULL
)
487 fatal("the key file name was not specified");
488 if (argc
> isc_commandline_index
+ 1)
489 fatal("extraneous arguments");
492 setup_entropy(mctx
, NULL
, &ectx
);
493 result
= isc_hash_create(mctx
, ectx
, DNS_NAME_MAXWIRE
);
494 if (result
!= ISC_R_SUCCESS
)
495 fatal("could not initialize hash");
496 result
= dst_lib_init(mctx
, ectx
,
497 ISC_ENTROPY_BLOCKING
| ISC_ENTROPY_GOODONLY
);
498 if (result
!= ISC_R_SUCCESS
)
499 fatal("could not initialize dst: %s",
500 isc_result_totext(result
));
501 isc_entropy_stopcallbacksources(ectx
);
503 setup_logging(mctx
, &log
);
505 dns_rdataset_init(&rdataset
);
507 if (usekeyset
|| filename
!= NULL
) {
508 if (argc
< isc_commandline_index
+ 1 && filename
!= NULL
) {
509 /* using zone name as the zone file name */
512 namestr
= argv
[isc_commandline_index
];
514 result
= initname(namestr
);
515 if (result
!= ISC_R_SUCCESS
)
516 fatal("could not initialize name %s", namestr
);
519 result
= loadkeyset(dir
, &rdataset
);
521 result
= loadset(filename
, &rdataset
);
523 if (result
!= ISC_R_SUCCESS
)
524 fatal("could not load DNSKEY set: %s\n",
525 isc_result_totext(result
));
527 for (result
= dns_rdataset_first(&rdataset
);
528 result
== ISC_R_SUCCESS
;
529 result
= dns_rdataset_next(&rdataset
)) {
530 dns_rdata_init(&rdata
);
531 dns_rdataset_current(&rdataset
, &rdata
);
537 emit(DNS_DSDIGEST_SHA1
, showall
, lookaside
,
539 emit(DNS_DSDIGEST_SHA256
, showall
, lookaside
,
542 emit(dtype
, showall
, lookaside
, &rdata
);
545 unsigned char key_buf
[DST_KEY_MAXSIZE
];
547 loadkey(argv
[isc_commandline_index
], key_buf
,
548 DST_KEY_MAXSIZE
, &rdata
);
551 emit(DNS_DSDIGEST_SHA1
, showall
, lookaside
, &rdata
);
552 emit(DNS_DSDIGEST_SHA256
, showall
, lookaside
, &rdata
);
554 emit(dtype
, showall
, lookaside
, &rdata
);
557 if (dns_rdataset_isassociated(&rdataset
))
558 dns_rdataset_disassociate(&rdataset
);
559 cleanup_logging(&log
);
562 cleanup_entropy(&ectx
);
565 isc_mem_stats(mctx
, stdout
);
566 isc_mem_destroy(&mctx
);
569 if (ferror(stdout
)) {
570 fprintf(stderr
, "write error\n");