dnssec-keyfromlabel.c 14.6 KB
Newer Older
Francis Dupont's avatar
Francis Dupont committed
1
/*
Automatic Updater's avatar
Automatic Updater committed
2
 * Copyright (C) 2007-2009  Internet Systems Consortium, Inc. ("ISC")
Francis Dupont's avatar
Francis Dupont committed
3
4
5
6
7
 *
 * Permission to use, copy, modify, and/or distribute this software for any
 * purpose with or without fee is hereby granted, provided that the above
 * copyright notice and this permission notice appear in all copies.
 *
Automatic Updater's avatar
Automatic Updater committed
8
9
10
11
12
13
14
 * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
 * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
 * AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
 * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
 * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
 * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
 * PERFORMANCE OF THIS SOFTWARE.
Francis Dupont's avatar
Francis Dupont committed
15
16
 */

17
/* $Id: dnssec-keyfromlabel.c,v 1.20 2009/10/06 23:22:51 each Exp $ */
Francis Dupont's avatar
Francis Dupont committed
18
19
20
21
22

/*! \file */

#include <config.h>

Francis Dupont's avatar
Francis Dupont committed
23
#include <ctype.h>
Francis Dupont's avatar
Francis Dupont committed
24
25
26
27
28
29
30
#include <stdlib.h>

#include <isc/buffer.h>
#include <isc/commandline.h>
#include <isc/entropy.h>
#include <isc/mem.h>
#include <isc/region.h>
31
#include <isc/print.h>
Francis Dupont's avatar
Francis Dupont committed
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
#include <isc/string.h>
#include <isc/util.h>

#include <dns/fixedname.h>
#include <dns/keyvalues.h>
#include <dns/log.h>
#include <dns/name.h>
#include <dns/rdataclass.h>
#include <dns/result.h>
#include <dns/secalg.h>

#include <dst/dst.h>

#include "dnssectool.h"

#define MAX_RSA 4096 /* should be long enough... */

const char *program = "dnssec-keyfromlabel";
int verbose;

52
53
54
#define DEFAULT_ALGORITHM "RSASHA1"
#define DEFAULT_NSEC3_ALGORITHM "NSEC3RSASHA1"

55
56
static const char *algs = "RSA | RSAMD5 | DH | DSA | RSASHA1 |"
			  " NSEC3DSA | NSEC3RSASHA1";
Francis Dupont's avatar
Francis Dupont committed
57

Francis Dupont's avatar
Francis Dupont committed
58
59
60
ISC_PLATFORM_NORETURN_PRE static void
usage(void) ISC_PLATFORM_NORETURN_POST;

Francis Dupont's avatar
Francis Dupont committed
61
62
63
static void
usage(void) {
	fprintf(stderr, "Usage:\n");
64
	fprintf(stderr, "    %s -l label [options] name\n\n",
Francis Dupont's avatar
Francis Dupont committed
65
66
67
		program);
	fprintf(stderr, "Version: %s\n", VERSION);
	fprintf(stderr, "Required options:\n");
68
	fprintf(stderr, "    -l label: label of the key pair\n");
Francis Dupont's avatar
Francis Dupont committed
69
70
	fprintf(stderr, "    name: owner of the key\n");
	fprintf(stderr, "Other options:\n");
71
72
73
74
	fprintf(stderr, "    -a algorithm: %s\n", algs);
	fprintf(stderr, "       (default: RSASHA1, or "
			       "NSEC3RSASHA1 if using -3)\n");
	fprintf(stderr, "    -3: use NSEC3-capable algorithm\n");
Francis Dupont's avatar
Francis Dupont committed
75
76
77
	fprintf(stderr, "    -c class (default: IN)\n");
#ifdef USE_PKCS11
	fprintf(stderr, "    -E enginename (default: pkcs11)\n");
78
79
#else
	fprintf(stderr, "    -E enginename\n");
Francis Dupont's avatar
Francis Dupont committed
80
#endif
Francis Dupont's avatar
Francis Dupont committed
81
	fprintf(stderr, "    -f keyflag: KSK | REVOKE\n");
82
83
	fprintf(stderr, "    -K directory: directory in which to place "
			"key files\n");
Francis Dupont's avatar
Francis Dupont committed
84
85
86
	fprintf(stderr, "    -k : generate a TYPE=KEY key\n");
	fprintf(stderr, "    -n nametype: ZONE | HOST | ENTITY | USER | OTHER\n");
	fprintf(stderr, "        (DNSKEY generation defaults to ZONE\n");
Francis Dupont's avatar
Francis Dupont committed
87
88
	fprintf(stderr, "    -p protocol: default: 3 [dnssec]\n");
	fprintf(stderr, "    -t type: "
Francis Dupont's avatar
Francis Dupont committed
89
90
		"AUTHCONF | NOAUTHCONF | NOAUTH | NOCONF "
		"(default: AUTHCONF)\n");
Francis Dupont's avatar
Francis Dupont committed
91
	fprintf(stderr, "    -v verbose level\n");
Francis Dupont's avatar
Francis Dupont committed
92
93
94
95
	fprintf(stderr, "Date options:\n");
	fprintf(stderr, "    -P date/[+-]offset: set key publication date\n");
	fprintf(stderr, "    -A date/[+-]offset: set key activation date\n");
	fprintf(stderr, "    -R date/[+-]offset: set key revocation date\n");
96
	fprintf(stderr, "    -I date/[+-]offset: set key inactivation date\n");
Francis Dupont's avatar
Francis Dupont committed
97
	fprintf(stderr, "    -D date/[+-]offset: set key deletion date\n");
98
	fprintf(stderr, "    -G: generate key only; do not set -P or -A\n");
Francis Dupont's avatar
Francis Dupont committed
99
	fprintf(stderr, "    -C: generate a backward-compatible key, omitting"
100
			" all dates\n");
Francis Dupont's avatar
Francis Dupont committed
101
102
	fprintf(stderr, "Output:\n");
	fprintf(stderr, "     K<name>+<alg>+<id>.key, "
Francis Dupont's avatar
Francis Dupont committed
103
			"K<name>+<alg>+<id>.private\n");
Francis Dupont's avatar
Francis Dupont committed
104
105
106
107
108
109
110

	exit (-1);
}

int
main(int argc, char **argv) {
	char		*algname = NULL, *nametype = NULL, *type = NULL;
Francis Dupont's avatar
Francis Dupont committed
111
	const char	*directory = NULL;
Francis Dupont's avatar
Francis Dupont committed
112
113
114
115
116
#ifdef USE_PKCS11
	const char	*engine = "pkcs11";
#else
	const char	*engine = NULL;
#endif
Francis Dupont's avatar
Francis Dupont committed
117
118
	char		*classname = NULL;
	char		*endp;
119
	dst_key_t	*key = NULL, *oldkey = NULL;
Francis Dupont's avatar
Francis Dupont committed
120
121
	dns_fixedname_t	fname;
	dns_name_t	*name;
Francis Dupont's avatar
Francis Dupont committed
122
	isc_uint16_t	flags = 0, kskflag = 0, revflag = 0;
Francis Dupont's avatar
Francis Dupont committed
123
	dns_secalg_t	alg;
Francis Dupont's avatar
Francis Dupont committed
124
	isc_boolean_t	oldstyle = ISC_FALSE;
Francis Dupont's avatar
Francis Dupont committed
125
126
127
128
129
130
131
132
133
134
135
	isc_mem_t	*mctx = NULL;
	int		ch;
	int		protocol = -1, signatory = 0;
	isc_result_t	ret;
	isc_textregion_t r;
	char		filename[255];
	isc_buffer_t	buf;
	isc_log_t	*log = NULL;
	isc_entropy_t	*ectx = NULL;
	dns_rdataclass_t rdclass;
	int		options = DST_TYPE_PRIVATE | DST_TYPE_PUBLIC;
Francis Dupont's avatar
Francis Dupont committed
136
	char		*label = NULL;
Francis Dupont's avatar
Francis Dupont committed
137
	isc_stdtime_t	publish = 0, activate = 0, revoke = 0;
138
	isc_stdtime_t	inactive = 0, delete = 0;
Francis Dupont's avatar
Francis Dupont committed
139
140
	isc_stdtime_t	now;
	isc_boolean_t	setpub = ISC_FALSE, setact = ISC_FALSE;
141
	isc_boolean_t	setrev = ISC_FALSE, setinact = ISC_FALSE;
Francis Dupont's avatar
Francis Dupont committed
142
143
	isc_boolean_t	setdel = ISC_FALSE;
	isc_boolean_t	unsetpub = ISC_FALSE, unsetact = ISC_FALSE;
144
	isc_boolean_t	unsetrev = ISC_FALSE, unsetinact = ISC_FALSE;
Francis Dupont's avatar
Francis Dupont committed
145
	isc_boolean_t	unsetdel = ISC_FALSE;
146
	isc_boolean_t	genonly = ISC_FALSE;
147
	isc_boolean_t	use_nsec3 = ISC_FALSE;
Francis Dupont's avatar
Francis Dupont committed
148
149
150
151
152
153
154
155
156
157

	if (argc == 1)
		usage();

	RUNTIME_CHECK(isc_mem_create(0, 0, &mctx) == ISC_R_SUCCESS);

	dns_result_register();

	isc_commandline_errprint = ISC_FALSE;

Francis Dupont's avatar
Francis Dupont committed
158
159
	isc_stdtime_get(&now);

Francis Dupont's avatar
Francis Dupont committed
160
	while ((ch = isc_commandline_parse(argc, argv,
161
				"3a:Cc:E:f:K:kl:n:p:t:v:FhGP:A:R:I:D:")) != -1)
Francis Dupont's avatar
Francis Dupont committed
162
163
	{
	    switch (ch) {
164
165
166
		case '3':
			use_nsec3 = ISC_TRUE;
			break;
Francis Dupont's avatar
Francis Dupont committed
167
168
169
		case 'a':
			algname = isc_commandline_argument;
			break;
Francis Dupont's avatar
Francis Dupont committed
170
171
172
		case 'C':
			oldstyle = ISC_TRUE;
			break;
Francis Dupont's avatar
Francis Dupont committed
173
174
175
		case 'c':
			classname = isc_commandline_argument;
			break;
Francis Dupont's avatar
Francis Dupont committed
176
177
178
		case 'E':
			engine = isc_commandline_argument;
			break;
Francis Dupont's avatar
Francis Dupont committed
179
		case 'f':
Francis Dupont's avatar
Francis Dupont committed
180
181
182
183
			if (toupper(isc_commandline_argument[0]) == 'K')
				kskflag = DNS_KEYFLAG_KSK;
			else if (toupper(isc_commandline_argument[0]) == 'R')
				revflag = DNS_KEYFLAG_REVOKE;
Francis Dupont's avatar
Francis Dupont committed
184
185
186
187
			else
				fatal("unknown flag '%s'",
				      isc_commandline_argument);
			break;
188
189
190
		case 'K':
			directory = isc_commandline_argument;
			break;
Francis Dupont's avatar
Francis Dupont committed
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
		case 'k':
			options |= DST_TYPE_KEY;
			break;
		case 'l':
			label = isc_commandline_argument;
			break;
		case 'n':
			nametype = isc_commandline_argument;
			break;
		case 'p':
			protocol = strtol(isc_commandline_argument, &endp, 10);
			if (*endp != '\0' || protocol < 0 || protocol > 255)
				fatal("-p must be followed by a number "
				      "[0..255]");
			break;
		case 't':
			type = isc_commandline_argument;
			break;
		case 'v':
			verbose = strtol(isc_commandline_argument, &endp, 0);
			if (*endp != '\0')
				fatal("-v must be followed by a number");
			break;
214
215
216
		case 'G':
			genonly = ISC_TRUE;
			break;
Francis Dupont's avatar
Francis Dupont committed
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
		case 'P':
			if (setpub || unsetpub)
				fatal("-P specified more than once");

			if (strcasecmp(isc_commandline_argument, "none")) {
				setpub = ISC_TRUE;
				publish = strtotime(isc_commandline_argument,
						    now, now);
			} else {
				unsetpub = ISC_TRUE;
			}
			break;
		case 'A':
			if (setact || unsetact)
				fatal("-A specified more than once");

			if (strcasecmp(isc_commandline_argument, "none")) {
				setact = ISC_TRUE;
				activate = strtotime(isc_commandline_argument,
						     now, now);
			} else {
				unsetact = ISC_TRUE;
			}
			break;
		case 'R':
			if (setrev || unsetrev)
				fatal("-R specified more than once");

			if (strcasecmp(isc_commandline_argument, "none")) {
				setrev = ISC_TRUE;
				revoke = strtotime(isc_commandline_argument,
						   now, now);
			} else {
				unsetrev = ISC_TRUE;
			}
			break;
253
254
255
		case 'I':
			if (setinact || unsetinact)
				fatal("-I specified more than once");
Francis Dupont's avatar
Francis Dupont committed
256
257

			if (strcasecmp(isc_commandline_argument, "none")) {
258
259
260
				setinact = ISC_TRUE;
				inactive = strtotime(isc_commandline_argument,
						     now, now);
Francis Dupont's avatar
Francis Dupont committed
261
			} else {
262
				unsetinact = ISC_TRUE;
Francis Dupont's avatar
Francis Dupont committed
263
264
265
266
267
268
269
270
271
272
273
274
275
276
			}
			break;
		case 'D':
			if (setdel || unsetdel)
				fatal("-D specified more than once");

			if (strcasecmp(isc_commandline_argument, "none")) {
				setdel = ISC_TRUE;
				delete = strtotime(isc_commandline_argument,
						   now, now);
			} else {
				unsetdel = ISC_TRUE;
			}
			break;
Francis Dupont's avatar
Francis Dupont committed
277
278
279
		case 'F':
			/* Reserved for FIPS mode */
			/* FALLTHROUGH */
Francis Dupont's avatar
Francis Dupont committed
280
281
282
283
		case '?':
			if (isc_commandline_option != '?')
				fprintf(stderr, "%s: invalid argument -%c\n",
					program, isc_commandline_option);
Francis Dupont's avatar
Francis Dupont committed
284
			/* FALLTHROUGH */
Francis Dupont's avatar
Francis Dupont committed
285
286
287
288
289
290
291
292
293
294
295
296
		case 'h':
			usage();

		default:
			fprintf(stderr, "%s: unhandled option -%c\n",
				program, isc_commandline_option);
			exit(1);
		}
	}

	if (ectx == NULL)
		setup_entropy(mctx, NULL, &ectx);
Francis Dupont's avatar
Francis Dupont committed
297
298
	ret = dst_lib_init2(mctx, ectx, engine,
			    ISC_ENTROPY_BLOCKING | ISC_ENTROPY_GOODONLY);
Francis Dupont's avatar
Francis Dupont committed
299
	if (ret != ISC_R_SUCCESS)
Francis Dupont's avatar
Francis Dupont committed
300
301
		fatal("could not initialize dst: %s",
		      isc_result_totext(ret));
Francis Dupont's avatar
Francis Dupont committed
302
303
304
305
306
307
308
309
310
311

	setup_logging(verbose, mctx, &log);

	if (label == NULL)
		fatal("the key label was not specified");
	if (argc < isc_commandline_index + 1)
		fatal("the key name was not specified");
	if (argc > isc_commandline_index + 1)
		fatal("extraneous arguments");

312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
	if (strchr(label, ':') == NULL &&
	    engine != NULL && strlen(engine) != 0) {
		char *l;
		int len;

		len = strlen(label) + strlen(engine) + 2;
		l = isc_mem_get(mctx, len);
		snprintf(l, len, "%s:%s", engine, label);
		label = l;
	}

	if (algname == NULL) {
		if (use_nsec3)
			algname = strdup(DEFAULT_NSEC3_ALGORITHM);
		else
			algname = strdup(DEFAULT_ALGORITHM);
		if (verbose > 0)
			fprintf(stderr, "no algorithm specified; "
				"defaulting to %s\n", algname);
	}

Francis Dupont's avatar
Francis Dupont committed
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
	if (strcasecmp(algname, "RSA") == 0) {
		fprintf(stderr, "The use of RSA (RSAMD5) is not recommended.\n"
				"If you still wish to use RSA (RSAMD5) please "
				"specify \"-a RSAMD5\"\n");
		return (1);
	} else {
		r.base = algname;
		r.length = strlen(algname);
		ret = dns_secalg_fromtext(&alg, &r);
		if (ret != ISC_R_SUCCESS)
			fatal("unknown algorithm %s", algname);
		if (alg == DST_ALG_DH)
			options |= DST_TYPE_KEY;
	}

348
349
350
351
352
353
	if (use_nsec3 &&
	    alg != DST_ALG_NSEC3DSA && alg != DST_ALG_NSEC3RSASHA1) {
		fatal("%s is incompatible with NSEC3; "
		      "do not use the -3 option", algname);
	}

Francis Dupont's avatar
Francis Dupont committed
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
	if (type != NULL && (options & DST_TYPE_KEY) != 0) {
		if (strcasecmp(type, "NOAUTH") == 0)
			flags |= DNS_KEYTYPE_NOAUTH;
		else if (strcasecmp(type, "NOCONF") == 0)
			flags |= DNS_KEYTYPE_NOCONF;
		else if (strcasecmp(type, "NOAUTHCONF") == 0) {
			flags |= (DNS_KEYTYPE_NOAUTH | DNS_KEYTYPE_NOCONF);
		}
		else if (strcasecmp(type, "AUTHCONF") == 0)
			/* nothing */;
		else
			fatal("invalid type %s", type);
	}

	if (nametype == NULL) {
		if ((options & DST_TYPE_KEY) != 0) /* KEY */
			fatal("no nametype specified");
		flags |= DNS_KEYOWNER_ZONE;	/* DNSKEY */
	} else if (strcasecmp(nametype, "zone") == 0)
		flags |= DNS_KEYOWNER_ZONE;
	else if ((options & DST_TYPE_KEY) != 0)	{ /* KEY */
		if (strcasecmp(nametype, "host") == 0 ||
			 strcasecmp(nametype, "entity") == 0)
			flags |= DNS_KEYOWNER_ENTITY;
		else if (strcasecmp(nametype, "user") == 0)
			flags |= DNS_KEYOWNER_USER;
		else
			fatal("invalid KEY nametype %s", nametype);
	} else if (strcasecmp(nametype, "other") != 0) /* DNSKEY */
		fatal("invalid DNSKEY nametype %s", nametype);

	rdclass = strtoclass(classname);

Francis Dupont's avatar
Francis Dupont committed
387
388
389
	if (directory == NULL)
		directory = ".";

Francis Dupont's avatar
Francis Dupont committed
390
391
	if ((options & DST_TYPE_KEY) != 0)  /* KEY */
		flags |= signatory;
392
	else if ((flags & DNS_KEYOWNER_ZONE) != 0) { /* DNSKEY */
Francis Dupont's avatar
Francis Dupont committed
393
394
		flags |= kskflag;
		flags |= revflag;
Automatic Updater's avatar
Automatic Updater committed
395
	}
Francis Dupont's avatar
Francis Dupont committed
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417

	if (protocol == -1)
		protocol = DNS_KEYPROTO_DNSSEC;
	else if ((options & DST_TYPE_KEY) == 0 &&
		 protocol != DNS_KEYPROTO_DNSSEC)
		fatal("invalid DNSKEY protocol: %d", protocol);

	if ((flags & DNS_KEYFLAG_TYPEMASK) == DNS_KEYTYPE_NOKEY) {
		if ((flags & DNS_KEYFLAG_SIGNATORYMASK) != 0)
			fatal("specified null key with signing authority");
	}

	if ((flags & DNS_KEYFLAG_OWNERMASK) == DNS_KEYOWNER_ZONE &&
	    alg == DNS_KEYALG_DH)
		fatal("a key with algorithm '%s' cannot be a zone key",
		      algname);

	dns_fixedname_init(&fname);
	name = dns_fixedname_name(&fname);
	isc_buffer_init(&buf, argv[isc_commandline_index],
			strlen(argv[isc_commandline_index]));
	isc_buffer_add(&buf, strlen(argv[isc_commandline_index]));
418
	ret = dns_name_fromtext(name, &buf, dns_rootname, 0, NULL);
Francis Dupont's avatar
Francis Dupont committed
419
420
421
422
423
424
425
426
	if (ret != ISC_R_SUCCESS)
		fatal("invalid key name %s: %s", argv[isc_commandline_index],
		      isc_result_totext(ret));

	isc_buffer_init(&buf, filename, sizeof(filename) - 1);

	/* associate the key */
	ret = dst_key_fromlabel(name, alg, flags, protocol,
Francis Dupont's avatar
Francis Dupont committed
427
				rdclass, engine, label, NULL, mctx, &key);
Francis Dupont's avatar
Francis Dupont committed
428
429
430
431
432
433
434
	isc_entropy_stopcallbacksources(ectx);

	if (ret != ISC_R_SUCCESS) {
		char namestr[DNS_NAME_FORMATSIZE];
		char algstr[ALG_FORMATSIZE];
		dns_name_format(name, namestr, sizeof(namestr));
		alg_format(alg, algstr, sizeof(algstr));
Francis Dupont's avatar
Francis Dupont committed
435
		fatal("failed to get key %s/%s: %s\n",
Francis Dupont's avatar
Francis Dupont committed
436
		      namestr, algstr, isc_result_totext(ret));
Evan Hunt's avatar
Evan Hunt committed
437
		/* NOTREACHED */
Francis Dupont's avatar
Francis Dupont committed
438
439
440
		exit(-1);
	}

Francis Dupont's avatar
Francis Dupont committed
441
442
	/*
	 * Set key timing metadata (unless using -C)
443
444
445
	 *
	 * Publish and activation dates are set to "now" by default, but
	 * can be overridden.  Creation date is always set to "now".
Francis Dupont's avatar
Francis Dupont committed
446
447
448
449
	 */
	if (!oldstyle) {
		dst_key_settime(key, DST_TIME_CREATED, now);

450
451
452
		if (genonly && (setpub || setact))
			fatal("cannot use -G together with -P or -A options");

Francis Dupont's avatar
Francis Dupont committed
453
454
		if (setpub)
			dst_key_settime(key, DST_TIME_PUBLISH, publish);
455
456
457
		else if (!genonly)
			dst_key_settime(key, DST_TIME_PUBLISH, now);

Francis Dupont's avatar
Francis Dupont committed
458
459
		if (setact)
			dst_key_settime(key, DST_TIME_ACTIVATE, activate);
460
461
462
		else if (!genonly)
			dst_key_settime(key, DST_TIME_ACTIVATE, now);

463
464
465
466
467
468
469
		if (setrev) {
			if (kskflag == 0)
				fprintf(stderr, "%s: warning: Key is "
					"not flagged as a KSK, but -R "
					"was used. Revoking a ZSK is "
					"legal, but undefined.\n",
					program);
Francis Dupont's avatar
Francis Dupont committed
470
			dst_key_settime(key, DST_TIME_REVOKE, revoke);
471
		}
472
473
474
475

		if (setinact)
			dst_key_settime(key, DST_TIME_INACTIVE, inactive);

Francis Dupont's avatar
Francis Dupont committed
476
477
478
		if (setdel)
			dst_key_settime(key, DST_TIME_DELETE, delete);
	} else {
479
		if (setpub || setact || setrev || setinact ||
Francis Dupont's avatar
Francis Dupont committed
480
		    setdel || unsetpub || unsetact ||
481
		    unsetrev || unsetinact || unsetdel || genonly)
Francis Dupont's avatar
Francis Dupont committed
482
			fatal("cannot use -C together with "
483
			      "-P, -A, -R, -I, -D, or -G options");
Francis Dupont's avatar
Francis Dupont committed
484
485
486
487
488
489
490
		/*
		 * Compatibility mode: Private-key-format
		 * should be set to 1.2.
		 */
		dst_key_setprivateformat(key, 1, 2);
	}

Francis Dupont's avatar
Francis Dupont committed
491
492
	/*
	 * Try to read a key with the same name, alg and id from disk.
Francis Dupont's avatar
Francis Dupont committed
493
	 * If there is one we must return failure.
Francis Dupont's avatar
Francis Dupont committed
494
495
	 */
	ret = dst_key_fromfile(name, dst_key_id(key), alg,
496
			       DST_TYPE_PRIVATE, directory, mctx, &oldkey);
Francis Dupont's avatar
Francis Dupont committed
497
498
499
	/* do not overwrite an existing key  */
	if (ret == ISC_R_SUCCESS) {
		isc_buffer_clear(&buf);
500
		ret = dst_key_buildfilename(key, 0, directory, &buf);
Francis Dupont's avatar
Francis Dupont committed
501
		fatal("%s: %s already exists\n", program, filename);
Francis Dupont's avatar
Francis Dupont committed
502
503
	}

504
	ret = dst_key_tofile(key, options, directory);
Francis Dupont's avatar
Francis Dupont committed
505
506
507
508
509
510
511
512
	if (ret != ISC_R_SUCCESS) {
		char keystr[KEY_FORMATSIZE];
		key_format(key, keystr, sizeof(keystr));
		fatal("failed to write key %s: %s\n", keystr,
		      isc_result_totext(ret));
	}

	isc_buffer_clear(&buf);
Francis Dupont's avatar
Francis Dupont committed
513
	ret = dst_key_buildfilename(key, 0, NULL, &buf);
Francis Dupont's avatar
Francis Dupont committed
514
515
516
517
518
519
520
521
522
523
524
525
526
	printf("%s\n", filename);
	dst_key_free(&key);

	cleanup_logging(&log);
	cleanup_entropy(&ectx);
	dst_lib_destroy();
	dns_name_destroy();
	if (verbose > 10)
		isc_mem_stats(mctx, stdout);
	isc_mem_destroy(&mctx);

	return (0);
}