2 * Portions Copyright (C) 2004-2007 Internet Systems Consortium, Inc. ("ISC")
3 * Portions Copyright (C) 1999-2003 Internet Software Consortium.
4 * Portions Copyright (C) 1995-2000 by Network Associates, Inc.
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 AND NETWORK ASSOCIATES DISCLAIMS
11 * ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
12 * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE
13 * FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR
16 * IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
19 /* $Id: dnssec-keygen.c,v 1.66.18.10 2007/08/28 07:19:55 tbox Exp $ */
27 #include <isc/buffer.h>
28 #include <isc/commandline.h>
29 #include <isc/entropy.h>
31 #include <isc/region.h>
32 #include <isc/string.h>
35 #include <dns/fixedname.h>
36 #include <dns/keyvalues.h>
39 #include <dns/rdataclass.h>
40 #include <dns/result.h>
41 #include <dns/secalg.h>
45 #include "dnssectool.h"
47 #define MAX_RSA 4096 /* should be long enough... */
49 const char *program
= "dnssec-keygen";
52 static const char *algs
= "RSA | RSAMD5 | DH | DSA | RSASHA1 | HMAC-MD5 |"
53 " HMAC-SHA1 | HMAC-SHA224 | HMAC-SHA256 | "
54 " HMAC-SHA384 | HMAC-SHA512";
57 dsa_size_ok(int size
) {
58 return (ISC_TF(size
>= 512 && size
<= 1024 && size
% 64 == 0));
63 fprintf(stderr
, "Usage:\n");
64 fprintf(stderr
, " %s -a alg -b bits -n type [options] name\n\n",
66 fprintf(stderr
, "Version: %s\n", VERSION
);
67 fprintf(stderr
, "Required options:\n");
68 fprintf(stderr
, " -a algorithm: %s\n", algs
);
69 fprintf(stderr
, " -b key size, in bits:\n");
70 fprintf(stderr
, " RSAMD5:\t\t[512..%d]\n", MAX_RSA
);
71 fprintf(stderr
, " RSASHA1:\t\t[512..%d]\n", MAX_RSA
);
72 fprintf(stderr
, " DH:\t\t[128..4096]\n");
73 fprintf(stderr
, " DSA:\t\t[512..1024] and divisible by 64\n");
74 fprintf(stderr
, " HMAC-MD5:\t[1..512]\n");
75 fprintf(stderr
, " HMAC-SHA1:\t[1..160]\n");
76 fprintf(stderr
, " HMAC-SHA224:\t[1..224]\n");
77 fprintf(stderr
, " HMAC-SHA256:\t[1..256]\n");
78 fprintf(stderr
, " HMAC-SHA384:\t[1..384]\n");
79 fprintf(stderr
, " HMAC-SHA512:\t[1..512]\n");
80 fprintf(stderr
, " -n nametype: ZONE | HOST | ENTITY | USER | OTHER\n");
81 fprintf(stderr
, " name: owner of the key\n");
82 fprintf(stderr
, "Other options:\n");
83 fprintf(stderr
, " -c <class> (default: IN)\n");
84 fprintf(stderr
, " -d <digest bits> (0 => max, default)\n");
85 fprintf(stderr
, " -e use large exponent (RSAMD5/RSASHA1 only)\n");
86 fprintf(stderr
, " -f keyflag: KSK\n");
87 fprintf(stderr
, " -g <generator> use specified generator "
89 fprintf(stderr
, " -t <type>: "
90 "AUTHCONF | NOAUTHCONF | NOAUTH | NOCONF "
91 "(default: AUTHCONF)\n");
92 fprintf(stderr
, " -p <protocol>: "
93 "default: 3 [dnssec]\n");
94 fprintf(stderr
, " -s <strength> strength value this key signs DNS "
95 "records with (default: 0)\n");
96 fprintf(stderr
, " -r <randomdev>: a file containing random data\n");
97 fprintf(stderr
, " -v <verbose level>\n");
98 fprintf(stderr
, " -k : generate a TYPE=KEY key\n");
99 fprintf(stderr
, "Output:\n");
100 fprintf(stderr
, " K<name>+<alg>+<id>.key, "
101 "K<name>+<alg>+<id>.private\n");
107 main(int argc
, char **argv
) {
108 char *algname
= NULL
, *nametype
= NULL
, *type
= NULL
;
109 char *classname
= NULL
;
111 dst_key_t
*key
= NULL
, *oldkey
;
112 dns_fixedname_t fname
;
114 isc_uint16_t flags
= 0, ksk
= 0;
116 isc_boolean_t conflict
= ISC_FALSE
, null_key
= ISC_FALSE
;
117 isc_mem_t
*mctx
= NULL
;
118 int ch
, rsa_exp
= 0, generator
= 0, param
= 0;
119 int protocol
= -1, size
= -1, signatory
= 0;
124 isc_log_t
*log
= NULL
;
125 isc_entropy_t
*ectx
= NULL
;
126 dns_rdataclass_t rdclass
;
127 int options
= DST_TYPE_PRIVATE
| DST_TYPE_PUBLIC
;
133 RUNTIME_CHECK(isc_mem_create(0, 0, &mctx
) == ISC_R_SUCCESS
);
135 dns_result_register();
137 while ((ch
= isc_commandline_parse(argc
, argv
,
138 "a:b:c:d:ef:g:kn:t:p:s:r:v:h")) != -1)
142 algname
= isc_commandline_argument
;
145 size
= strtol(isc_commandline_argument
, &endp
, 10);
146 if (*endp
!= '\0' || size
< 0)
147 fatal("-b requires a non-negative number");
150 classname
= isc_commandline_argument
;
153 dbits
= strtol(isc_commandline_argument
, &endp
, 10);
154 if (*endp
!= '\0' || dbits
< 0)
155 fatal("-d requires a non-negative number");
161 if (strcasecmp(isc_commandline_argument
, "KSK") == 0)
162 ksk
= DNS_KEYFLAG_KSK
;
164 fatal("unknown flag '%s'",
165 isc_commandline_argument
);
168 generator
= strtol(isc_commandline_argument
,
170 if (*endp
!= '\0' || generator
<= 0)
171 fatal("-g requires a positive number");
174 options
|= DST_TYPE_KEY
;
177 nametype
= isc_commandline_argument
;
180 type
= isc_commandline_argument
;
183 protocol
= strtol(isc_commandline_argument
, &endp
, 10);
184 if (*endp
!= '\0' || protocol
< 0 || protocol
> 255)
185 fatal("-p must be followed by a number "
189 signatory
= strtol(isc_commandline_argument
,
191 if (*endp
!= '\0' || signatory
< 0 || signatory
> 15)
192 fatal("-s must be followed by a number "
196 setup_entropy(mctx
, isc_commandline_argument
, &ectx
);
200 verbose
= strtol(isc_commandline_argument
, &endp
, 0);
202 fatal("-v must be followed by a number");
208 fprintf(stderr
, "%s: invalid argument -%c\n",
215 setup_entropy(mctx
, NULL
, &ectx
);
216 ret
= dst_lib_init(mctx
, ectx
,
217 ISC_ENTROPY_BLOCKING
| ISC_ENTROPY_GOODONLY
);
218 if (ret
!= ISC_R_SUCCESS
)
219 fatal("could not initialize dst");
221 setup_logging(verbose
, mctx
, &log
);
223 if (argc
< isc_commandline_index
+ 1)
224 fatal("the key name was not specified");
225 if (argc
> isc_commandline_index
+ 1)
226 fatal("extraneous arguments");
229 fatal("no algorithm was specified");
230 if (strcasecmp(algname
, "RSA") == 0) {
231 fprintf(stderr
, "The use of RSA (RSAMD5) is not recommended.\n"
232 "If you still wish to use RSA (RSAMD5) please "
233 "specify \"-a RSAMD5\"\n");
235 } else if (strcasecmp(algname
, "HMAC-MD5") == 0) {
236 options
|= DST_TYPE_KEY
;
237 alg
= DST_ALG_HMACMD5
;
238 } else if (strcasecmp(algname
, "HMAC-SHA1") == 0) {
239 options
|= DST_TYPE_KEY
;
240 alg
= DST_ALG_HMACSHA1
;
241 } else if (strcasecmp(algname
, "HMAC-SHA224") == 0) {
242 options
|= DST_TYPE_KEY
;
243 alg
= DST_ALG_HMACSHA224
;
244 } else if (strcasecmp(algname
, "HMAC-SHA256") == 0) {
245 options
|= DST_TYPE_KEY
;
246 alg
= DST_ALG_HMACSHA256
;
247 } else if (strcasecmp(algname
, "HMAC-SHA384") == 0) {
248 options
|= DST_TYPE_KEY
;
249 alg
= DST_ALG_HMACSHA384
;
250 } else if (strcasecmp(algname
, "HMAC-SHA512") == 0) {
251 options
|= DST_TYPE_KEY
;
252 alg
= DST_ALG_HMACSHA512
;
255 r
.length
= strlen(algname
);
256 ret
= dns_secalg_fromtext(&alg
, &r
);
257 if (ret
!= ISC_R_SUCCESS
)
258 fatal("unknown algorithm %s", algname
);
259 if (alg
== DST_ALG_DH
)
260 options
|= DST_TYPE_KEY
;
263 if (type
!= NULL
&& (options
& DST_TYPE_KEY
) != 0) {
264 if (strcasecmp(type
, "NOAUTH") == 0)
265 flags
|= DNS_KEYTYPE_NOAUTH
;
266 else if (strcasecmp(type
, "NOCONF") == 0)
267 flags
|= DNS_KEYTYPE_NOCONF
;
268 else if (strcasecmp(type
, "NOAUTHCONF") == 0) {
269 flags
|= (DNS_KEYTYPE_NOAUTH
| DNS_KEYTYPE_NOCONF
);
273 else if (strcasecmp(type
, "AUTHCONF") == 0)
276 fatal("invalid type %s", type
);
280 fatal("key size not specified (-b option)");
283 case DNS_KEYALG_RSAMD5
:
284 case DNS_KEYALG_RSASHA1
:
285 if (size
!= 0 && (size
< 512 || size
> MAX_RSA
))
286 fatal("RSA key size %d out of range", size
);
289 if (size
!= 0 && (size
< 128 || size
> 4096))
290 fatal("DH key size %d out of range", size
);
293 if (size
!= 0 && !dsa_size_ok(size
))
294 fatal("invalid DSS key size: %d", size
);
296 case DST_ALG_HMACMD5
:
297 if (size
< 1 || size
> 512)
298 fatal("HMAC-MD5 key size %d out of range", size
);
299 if (dbits
!= 0 && (dbits
< 80 || dbits
> 128))
300 fatal("HMAC-MD5 digest bits %d out of range", dbits
);
301 if ((dbits
% 8) != 0)
302 fatal("HMAC-MD5 digest bits %d not divisible by 8",
305 case DST_ALG_HMACSHA1
:
306 if (size
< 1 || size
> 160)
307 fatal("HMAC-SHA1 key size %d out of range", size
);
308 if (dbits
!= 0 && (dbits
< 80 || dbits
> 160))
309 fatal("HMAC-SHA1 digest bits %d out of range", dbits
);
310 if ((dbits
% 8) != 0)
311 fatal("HMAC-SHA1 digest bits %d not divisible by 8",
314 case DST_ALG_HMACSHA224
:
315 if (size
< 1 || size
> 224)
316 fatal("HMAC-SHA224 key size %d out of range", size
);
317 if (dbits
!= 0 && (dbits
< 112 || dbits
> 224))
318 fatal("HMAC-SHA224 digest bits %d out of range", dbits
);
319 if ((dbits
% 8) != 0)
320 fatal("HMAC-SHA224 digest bits %d not divisible by 8",
323 case DST_ALG_HMACSHA256
:
324 if (size
< 1 || size
> 256)
325 fatal("HMAC-SHA256 key size %d out of range", size
);
326 if (dbits
!= 0 && (dbits
< 128 || dbits
> 256))
327 fatal("HMAC-SHA256 digest bits %d out of range", dbits
);
328 if ((dbits
% 8) != 0)
329 fatal("HMAC-SHA256 digest bits %d not divisible by 8",
332 case DST_ALG_HMACSHA384
:
333 if (size
< 1 || size
> 384)
334 fatal("HMAC-384 key size %d out of range", size
);
335 if (dbits
!= 0 && (dbits
< 192 || dbits
> 384))
336 fatal("HMAC-SHA384 digest bits %d out of range", dbits
);
337 if ((dbits
% 8) != 0)
338 fatal("HMAC-SHA384 digest bits %d not divisible by 8",
341 case DST_ALG_HMACSHA512
:
342 if (size
< 1 || size
> 512)
343 fatal("HMAC-SHA512 key size %d out of range", size
);
344 if (dbits
!= 0 && (dbits
< 256 || dbits
> 512))
345 fatal("HMAC-SHA512 digest bits %d out of range", dbits
);
346 if ((dbits
% 8) != 0)
347 fatal("HMAC-SHA512 digest bits %d not divisible by 8",
352 if (!(alg
== DNS_KEYALG_RSAMD5
|| alg
== DNS_KEYALG_RSASHA1
) &&
354 fatal("specified RSA exponent for a non-RSA key");
356 if (alg
!= DNS_KEYALG_DH
&& generator
!= 0)
357 fatal("specified DH generator for a non-DH key");
359 if (nametype
== NULL
)
360 fatal("no nametype specified");
361 if (strcasecmp(nametype
, "zone") == 0)
362 flags
|= DNS_KEYOWNER_ZONE
;
363 else if ((options
& DST_TYPE_KEY
) != 0) { /* KEY */
364 if (strcasecmp(nametype
, "host") == 0 ||
365 strcasecmp(nametype
, "entity") == 0)
366 flags
|= DNS_KEYOWNER_ENTITY
;
367 else if (strcasecmp(nametype
, "user") == 0)
368 flags
|= DNS_KEYOWNER_USER
;
370 fatal("invalid KEY nametype %s", nametype
);
371 } else if (strcasecmp(nametype
, "other") != 0) /* DNSKEY */
372 fatal("invalid DNSKEY nametype %s", nametype
);
374 rdclass
= strtoclass(classname
);
376 if ((options
& DST_TYPE_KEY
) != 0) /* KEY */
378 else if ((flags
& DNS_KEYOWNER_ZONE
) != 0) /* DNSKEY */
382 protocol
= DNS_KEYPROTO_DNSSEC
;
383 else if ((options
& DST_TYPE_KEY
) == 0 &&
384 protocol
!= DNS_KEYPROTO_DNSSEC
)
385 fatal("invalid DNSKEY protocol: %d", protocol
);
387 if ((flags
& DNS_KEYFLAG_TYPEMASK
) == DNS_KEYTYPE_NOKEY
) {
389 fatal("specified null key with non-zero size");
390 if ((flags
& DNS_KEYFLAG_SIGNATORYMASK
) != 0)
391 fatal("specified null key with signing authority");
394 if ((flags
& DNS_KEYFLAG_OWNERMASK
) == DNS_KEYOWNER_ZONE
&&
395 (alg
== DNS_KEYALG_DH
|| alg
== DST_ALG_HMACMD5
||
396 alg
== DST_ALG_HMACSHA1
|| alg
== DST_ALG_HMACSHA224
||
397 alg
== DST_ALG_HMACSHA256
|| alg
== DST_ALG_HMACSHA384
||
398 alg
== DST_ALG_HMACSHA512
))
399 fatal("a key with algorithm '%s' cannot be a zone key",
402 dns_fixedname_init(&fname
);
403 name
= dns_fixedname_name(&fname
);
404 isc_buffer_init(&buf
, argv
[isc_commandline_index
],
405 strlen(argv
[isc_commandline_index
]));
406 isc_buffer_add(&buf
, strlen(argv
[isc_commandline_index
]));
407 ret
= dns_name_fromtext(name
, &buf
, dns_rootname
, ISC_FALSE
, NULL
);
408 if (ret
!= ISC_R_SUCCESS
)
409 fatal("invalid key name %s: %s", argv
[isc_commandline_index
],
410 isc_result_totext(ret
));
413 case DNS_KEYALG_RSAMD5
:
414 case DNS_KEYALG_RSASHA1
:
421 case DST_ALG_HMACMD5
:
422 case DST_ALG_HMACSHA1
:
423 case DST_ALG_HMACSHA224
:
424 case DST_ALG_HMACSHA256
:
425 case DST_ALG_HMACSHA384
:
426 case DST_ALG_HMACSHA512
:
431 if ((flags
& DNS_KEYFLAG_TYPEMASK
) == DNS_KEYTYPE_NOKEY
)
434 isc_buffer_init(&buf
, filename
, sizeof(filename
) - 1);
437 conflict
= ISC_FALSE
;
440 /* generate the key */
441 ret
= dst_key_generate(name
, alg
, size
, param
, flags
, protocol
,
442 rdclass
, mctx
, &key
);
443 isc_entropy_stopcallbacksources(ectx
);
445 if (ret
!= ISC_R_SUCCESS
) {
446 char namestr
[DNS_NAME_FORMATSIZE
];
447 char algstr
[ALG_FORMATSIZE
];
448 dns_name_format(name
, namestr
, sizeof(namestr
));
449 alg_format(alg
, algstr
, sizeof(algstr
));
450 fatal("failed to generate key %s/%s: %s\n",
451 namestr
, algstr
, isc_result_totext(ret
));
455 dst_key_setbits(key
, dbits
);
458 * Try to read a key with the same name, alg and id from disk.
459 * If there is one we must continue generating a new one
460 * unless we were asked to generate a null key, in which
461 * case we return failure.
463 ret
= dst_key_fromfile(name
, dst_key_id(key
), alg
,
464 DST_TYPE_PRIVATE
, NULL
, mctx
, &oldkey
);
465 /* do not overwrite an existing key */
466 if (ret
== ISC_R_SUCCESS
) {
467 dst_key_free(&oldkey
);
472 if (conflict
== ISC_TRUE
) {
474 isc_buffer_clear(&buf
);
475 ret
= dst_key_buildfilename(key
, 0, NULL
, &buf
);
477 "%s: %s already exists, "
478 "generating a new key\n",
484 } while (conflict
== ISC_TRUE
);
487 fatal("cannot generate a null key when a key with id 0 "
490 ret
= dst_key_tofile(key
, options
, NULL
);
491 if (ret
!= ISC_R_SUCCESS
) {
492 char keystr
[KEY_FORMATSIZE
];
493 key_format(key
, keystr
, sizeof(keystr
));
494 fatal("failed to write key %s: %s\n", keystr
,
495 isc_result_totext(ret
));
498 isc_buffer_clear(&buf
);
499 ret
= dst_key_buildfilename(key
, 0, NULL
, &buf
);
500 printf("%s\n", filename
);
503 cleanup_logging(&log
);
504 cleanup_entropy(&ectx
);
508 isc_mem_stats(mctx
, stdout
);
509 isc_mem_destroy(&mctx
);