1 /*
2  * keygen is a small programs that generate a dnskey and private key
3  * for a particular domain.
4  *
5  * (c) NLnet Labs, 2005 - 2008
6  * See the file LICENSE for the license
7  */
8 
9 #include "config.h"
10 
11 #include <ldns/ldns.h>
12 
13 #include <sys/types.h>
14 #include <sys/stat.h>
15 #include <fcntl.h>
16 #include <errno.h>
17 #include <unistd.h>
18 
19 #ifdef HAVE_SSL
20 static void
usage(FILE * fp,char * prog)21 usage(FILE *fp, char *prog) {
22 	fprintf(fp, "%s -a <algorithm> [-b bits] [-r /dev/random] [-s] [-f] [-v] domain\n",
23 		   prog);
24 	fprintf(fp, "  generate a new key pair for domain\n");
25 	fprintf(fp, "  -a <alg>\tuse the specified algorithm (-a list to");
26 	fprintf(fp, " show a list)\n");
27 	fprintf(fp, "  -k\t\tset the flags to 257; key signing key\n");
28 	fprintf(fp, "  -b <bits>\tspecify the keylength\n");
29 	fprintf(fp, "  -r <random>\tspecify a random device (defaults to /dev/random)\n");
30 	fprintf(fp, "\t\tto seed the random generator with\n");
31 	fprintf(fp, "  -s\t\tcreate additional symlinks with constant names\n");
32 	fprintf(fp, "  -f\t\tforce override of existing symlinks\n");
33 	fprintf(fp, "  -v\t\tshow the version and exit\n");
34 	fprintf(fp, "  The following files will be created:\n");
35 	fprintf(fp, "    K<name>+<alg>+<id>.key\tPublic key in RR format\n");
36 	fprintf(fp, "    K<name>+<alg>+<id>.private\tPrivate key in key format\n");
37 	fprintf(fp, "    K<name>+<alg>+<id>.ds\tDS in RR format (only for DNSSEC KSK keys)\n");
38 	fprintf(fp, "  The base name (K<name>+<alg>+<id> will be printed to stdout\n");
39 }
40 
41 static void
show_algorithms(FILE * out)42 show_algorithms(FILE *out)
43 {
44 	ldns_lookup_table *lt = ldns_signing_algorithms;
45 	fprintf(out, "Possible algorithms:\n");
46 
47 	while (lt->name) {
48 		fprintf(out, "%s\n", lt->name);
49 		lt++;
50 	}
51 }
52 
53 static int
remove_symlink(const char * symlink_name)54 remove_symlink(const char *symlink_name)
55 {
56 	int result;
57 
58 	if ((result = unlink(symlink_name)) == -1) {
59 		if (errno == ENOENT) {
60 			/* it's OK if the link simply didn't exist */
61 			result = 0;
62 		} else {
63 			/* error if unlink fail */
64 			fprintf(stderr, "Can't delete symlink %s: %s\n", symlink_name, strerror(errno));
65 		}
66 	}
67 	return result;
68 }
69 
70 static int
create_symlink(const char * symlink_destination,const char * symlink_name)71 create_symlink(const char *symlink_destination, const char *symlink_name)
72 {
73 	int result = 0;
74 
75 	if (!symlink_name)
76 		return result;  /* no arg "-s" at all */
77 
78 	if ((result = symlink(symlink_destination, symlink_name)) == -1) {
79 		fprintf(stderr, "Unable to create symlink %s -> %s: %s\n", symlink_name, symlink_destination, strerror(errno));
80 	}
81 	return result;
82 }
83 
84 int
main(int argc,char * argv[])85 main(int argc, char *argv[])
86 {
87 	int c;
88 	int fd;
89 	char *prog;
90 
91 	/* default key size */
92 	uint16_t def_bits = 1024;
93 	uint16_t bits = def_bits;
94 	bool had_bits = false;
95 	bool ksk;
96 
97 	FILE *file;
98 	FILE *random;
99 	char *filename;
100 	char *owner;
101 	bool symlink_create;
102 	bool symlink_override;
103 
104 	ldns_signing_algorithm algorithm;
105 	ldns_rdf *domain;
106 	ldns_rr *pubkey;
107 	ldns_key *key;
108 	ldns_rr *ds;
109 
110 	prog = strdup(argv[0]);
111 	algorithm = 0;
112 	random = NULL;
113 	ksk = false; /* don't create a ksk per default */
114 	symlink_create = false;
115 	symlink_override = false;
116 
117 	while ((c = getopt(argc, argv, "a:kb:r:sfv")) != -1) {
118 		switch (c) {
119 		case 'a':
120 			if (algorithm != 0) {
121 				fprintf(stderr, "The -a argument can only be used once\n");
122 				exit(1);
123 			}
124 			if (strncmp(optarg, "list", 5) == 0) {
125 				show_algorithms(stdout);
126 				exit(EXIT_SUCCESS);
127 			}
128 			algorithm = ldns_get_signing_algorithm_by_name(optarg);
129 			if (algorithm == 0) {
130 				fprintf(stderr, "Algorithm %s not found\n", optarg);
131 				show_algorithms(stderr);
132 				exit(EXIT_FAILURE);
133 			}
134 			break;
135 		case 'b':
136 			bits = (uint16_t) atoi(optarg);
137 			if (bits == 0) {
138 				fprintf(stderr, "%s: %s %d", prog, "Can not parse the -b argument, setting it to the default\n", (int) def_bits);
139 				bits = def_bits;
140 			} else
141 				had_bits = true;
142 			break;
143 		case 'k':
144 			ksk = true;
145 			break;
146 		case 'r':
147 			random = fopen(optarg, "r");
148 			if (!random) {
149 				fprintf(stderr, "Cannot open random file %s: %s\n", optarg, strerror(errno));
150 				exit(EXIT_FAILURE);
151 			}
152 			break;
153 		case 's':
154 			symlink_create = true;
155 			break;
156 		case 'f':
157 			symlink_override = true;
158 			break;
159 		case 'v':
160 			printf("DNSSEC key generator version %s (ldns version %s)\n", LDNS_VERSION, ldns_version());
161 			exit(EXIT_SUCCESS);
162 			break;
163 		default:
164 			usage(stderr, prog);
165 			exit(EXIT_FAILURE);
166 		}
167 	}
168 	argc -= optind;
169 	argv += optind;
170 
171 	if (algorithm == 0) {
172 		printf("Please use the -a argument to provide an algorithm\n");
173 		exit(1);
174 	}
175 
176 	if (argc != 1) {
177 		usage(stderr, prog);
178 		exit(EXIT_FAILURE);
179 	}
180 	free(prog);
181 
182 	/* check whether key size is within RFC boundaries */
183 	switch (algorithm) {
184 	case LDNS_SIGN_RSAMD5:
185 	case LDNS_SIGN_RSASHA1:
186 	case LDNS_SIGN_RSASHA1_NSEC3:
187 	case LDNS_SIGN_RSASHA256:
188 	case LDNS_SIGN_RSASHA512:
189 		if (bits < 512 || bits > 4096) {
190 			fprintf(stderr, "For RSA, the key size must be between ");
191 			fprintf(stderr, " 512 and 4096 bits. Aborting.\n");
192 			exit(1);
193 		}
194 		break;
195 #ifdef USE_DSA
196 	case LDNS_SIGN_DSA:
197 	case LDNS_SIGN_DSA_NSEC3:
198 		if (bits < 512 || bits > 1024) {
199 			fprintf(stderr, "For DSA, the key size must be between ");
200 			fprintf(stderr, " 512 and 1024 bits. Aborting.\n");
201 			exit(1);
202 		}
203 		break;
204 #endif /* USE_DSA */
205 #ifdef USE_GOST
206 	case LDNS_SIGN_ECC_GOST:
207 		if(!ldns_key_EVP_load_gost_id()) {
208 			fprintf(stderr, "error: libcrypto does not provide GOST\n");
209 			exit(EXIT_FAILURE);
210 		}
211 		break;
212 #endif
213 #ifdef USE_ECDSA
214 	case LDNS_SIGN_ECDSAP256SHA256:
215 	case LDNS_SIGN_ECDSAP384SHA384:
216 		break;
217 #endif
218 	case LDNS_SIGN_HMACMD5:
219 		if (!had_bits) {
220 			bits = 512;
221 		} else if (bits < 1 || bits > 512) {
222 			fprintf(stderr, "For hmac-md5, the key size must be ");
223 			fprintf(stderr, "between 1 and 512 bits. Aborting.\n");
224 			exit(1);
225 		}
226 		break;
227 	case LDNS_SIGN_HMACSHA1:
228 		if (!had_bits) {
229 			bits = 160;
230 		} else if (bits < 1 || bits > 160) {
231 			fprintf(stderr, "For hmac-sha1, the key size must be ");
232 			fprintf(stderr, "between 1 and 160 bits. Aborting.\n");
233 			exit(1);
234 		}
235 		break;
236 
237 	case LDNS_SIGN_HMACSHA224:
238 		if (!had_bits) {
239 			bits = 224;
240 		} else if (bits < 1 || bits > 224) {
241 			fprintf(stderr, "For hmac-sha224, the key size must be ");
242 			fprintf(stderr, "between 1 and 224 bits. Aborting.\n");
243 			exit(1);
244 		}
245 		break;
246 
247 	case LDNS_SIGN_HMACSHA256:
248 		if (!had_bits) {
249 			bits = 256;
250 		} else if (bits < 1 || bits > 256) {
251 			fprintf(stderr, "For hmac-sha256, the key size must be ");
252 			fprintf(stderr, "between 1 and 256 bits. Aborting.\n");
253 			exit(1);
254 		}
255 		break;
256 
257 	case LDNS_SIGN_HMACSHA384:
258 		if (!had_bits) {
259 			bits = 384;
260 		} else if (bits < 1 || bits > 384) {
261 			fprintf(stderr, "For hmac-sha384, the key size must be ");
262 			fprintf(stderr, "between 1 and 384 bits. Aborting.\n");
263 			exit(1);
264 		}
265 		break;
266 
267 	case LDNS_SIGN_HMACSHA512:
268 		if (!had_bits) {
269 			bits = 512;
270 		} else if (bits < 1 || bits > 512) {
271 			fprintf(stderr, "For hmac-sha512, the key size must be ");
272 			fprintf(stderr, "between 1 and 512 bits. Aborting.\n");
273 			exit(1);
274 		}
275 		break;
276 	default:
277 		break;
278 	}
279 
280 	if (!random) {
281 		random = fopen("/dev/random", "r");
282 		if (!random) {
283 			fprintf(stderr, "Cannot open random file %s: %s\n", optarg, strerror(errno));
284 			exit(EXIT_FAILURE);
285 		}
286 	}
287 
288 	(void)ldns_init_random(random, (unsigned int) bits/8);
289 	fclose(random);
290 
291 	/* create an rdf from the domain name */
292 	domain = ldns_dname_new_frm_str(argv[0]);
293 
294 	/* generate a new key */
295 	key = ldns_key_new_frm_algorithm(algorithm, bits);
296 	if(!key) {
297 		fprintf(stderr, "cannot generate key of algorithm %s\n",
298 			ldns_pkt_algorithm2str((ldns_algorithm)algorithm));
299 		exit(EXIT_FAILURE);
300 	}
301 
302 	/* set the owner name in the key - this is a /separate/ step */
303 	ldns_key_set_pubkey_owner(key, domain);
304 
305 	/* ksk flag */
306 	if (ksk) {
307 		ldns_key_set_flags(key, ldns_key_flags(key) + 1);
308 	}
309 
310 	/* create the public from the ldns_key */
311 	pubkey = ldns_key2rr(key);
312 	if (!pubkey) {
313 		fprintf(stderr, "Could not extract the public key from the key structure...");
314 		ldns_key_deep_free(key);
315 		exit(EXIT_FAILURE);
316 	}
317 	owner = ldns_rdf2str(ldns_rr_owner(pubkey));
318 
319 	/* calculate and set the keytag */
320 	ldns_key_set_keytag(key, ldns_calc_keytag(pubkey));
321 
322 	/* build the DS record */
323 	switch (algorithm) {
324 #ifdef USE_ECDSA
325 	case LDNS_SIGN_ECDSAP384SHA384:
326 		ds = ldns_key_rr2ds(pubkey, LDNS_SHA384);
327 		break;
328 	case LDNS_SIGN_ECDSAP256SHA256:
329 #endif
330 #ifdef USE_ED25519
331 	case LDNS_SIGN_ED25519:
332 #endif
333 #ifdef USE_ED448
334 	case LDNS_SIGN_ED448:
335 #endif
336 	case LDNS_SIGN_RSASHA256:
337 	case LDNS_SIGN_RSASHA512:
338 		ds = ldns_key_rr2ds(pubkey, LDNS_SHA256);
339 		break;
340 	case LDNS_SIGN_ECC_GOST:
341 #ifdef USE_GOST
342 		ds = ldns_key_rr2ds(pubkey, LDNS_HASH_GOST);
343 #else
344 		ds = ldns_key_rr2ds(pubkey, LDNS_SHA256);
345 #endif
346 		break;
347 	default:
348 		ds = ldns_key_rr2ds(pubkey, LDNS_SHA1);
349 		break;
350 	}
351 
352 	/* maybe a symlinks should be removed */
353 	if (symlink_create && symlink_override) {
354 		if (remove_symlink(".key") != 0) {
355 			exit(EXIT_FAILURE);
356 		}
357 		if (remove_symlink(".private") != 0) {
358 			exit(EXIT_FAILURE);
359 		}
360 		if (remove_symlink(".ds") != 0) {
361 			exit(EXIT_FAILURE);
362 		}
363 	}
364 
365 	/* print the public key RR to .key */
366 	filename = LDNS_XMALLOC(char, strlen(owner) + 17);
367 	snprintf(filename, strlen(owner) + 16, "K%s+%03u+%05u.key", owner, algorithm, (unsigned int) ldns_key_keytag(key));
368 	file = fopen(filename, "w");
369 	if (!file) {
370 		fprintf(stderr, "Unable to open %s: %s\n", filename, strerror(errno));
371 		ldns_key_deep_free(key);
372 		free(owner);
373 		ldns_rr_free(pubkey);
374 		ldns_rr_free(ds);
375 		LDNS_FREE(filename);
376 		exit(EXIT_FAILURE);
377 	} else {
378 		/* temporarily set question so that TTL is not printed */
379 		ldns_rr_set_question(pubkey, true);
380 		ldns_rr_print(file, pubkey);
381 		ldns_rr_set_question(pubkey, false);
382 		fclose(file);
383 		if (symlink_create) {
384 			if (create_symlink(filename, ".key") != 0) {
385 				goto silentfail;
386 			}
387 		}
388 		LDNS_FREE(filename);
389 	}
390 
391 	/* print the priv key to stderr */
392 	filename = LDNS_XMALLOC(char, strlen(owner) + 21);
393 	snprintf(filename, strlen(owner) + 20, "K%s+%03u+%05u.private", owner, algorithm, (unsigned int) ldns_key_keytag(key));
394 	/* use open() here to prevent creating world-readable private keys (CVE-2014-3209)*/
395 	fd = open(filename, O_WRONLY | O_CREAT | O_TRUNC, S_IRUSR | S_IWUSR);
396 	if (fd < 0) {
397 		goto fail;
398 	}
399 
400 	file = fdopen(fd, "w");
401 	if (!file) {
402 		goto fail;
403 	}
404 
405 	ldns_key_print(file, key);
406 	fclose(file);
407 	if (symlink_create) {
408 		if (create_symlink(filename, ".private") != 0) {
409 			goto silentfail;
410 		}
411 	}
412 	LDNS_FREE(filename);
413 
414 	/* print the DS to .ds */
415 	if (ksk && algorithm != LDNS_SIGN_HMACMD5 &&
416 		algorithm != LDNS_SIGN_HMACSHA1 &&
417 		algorithm != LDNS_SIGN_HMACSHA224 &&
418 		algorithm != LDNS_SIGN_HMACSHA256 &&
419 		algorithm != LDNS_SIGN_HMACSHA384 &&
420 		algorithm != LDNS_SIGN_HMACSHA512) {
421 		filename = LDNS_XMALLOC(char, strlen(owner) + 16);
422 		snprintf(filename, strlen(owner) + 15, "K%s+%03u+%05u.ds", owner, algorithm, (unsigned int) ldns_key_keytag(key));
423 		file = fopen(filename, "w");
424 		if (!file) {
425 			fprintf(stderr, "Unable to open %s: %s\n", filename, strerror(errno));
426 			ldns_key_deep_free(key);
427 			free(owner);
428 			ldns_rr_free(pubkey);
429 			ldns_rr_free(ds);
430 			LDNS_FREE(filename);
431 			exit(EXIT_FAILURE);
432 		} else {
433 			/* temporarily set question so that TTL is not printed */
434 			ldns_rr_set_question(ds, true);
435 			ldns_rr_print(file, ds);
436 			ldns_rr_set_question(ds, false);
437 			fclose(file);
438 			if (symlink_create) {
439 				if (create_symlink(filename, ".ds") != 0) {
440 					goto silentfail;
441 				}
442 			}
443 			LDNS_FREE(filename);
444 		}
445 	}
446 
447 	fprintf(stdout, "K%s+%03u+%05u\n", owner, algorithm, (unsigned int) ldns_key_keytag(key));
448 	ldns_key_deep_free(key);
449 	free(owner);
450 	ldns_rr_free(pubkey);
451 	ldns_rr_free(ds);
452 	exit(EXIT_SUCCESS);
453 
454 fail:
455 	fprintf(stderr, "Unable to open %s: %s\n", filename, strerror(errno));
456 silentfail:
457 	ldns_key_deep_free(key);
458 	free(owner);
459 	ldns_rr_free(pubkey);
460 	ldns_rr_free(ds);
461 	LDNS_FREE(filename);
462 	exit(EXIT_FAILURE);
463 }
464 #else
465 int
main(int argc,char ** argv)466 main(int argc, char **argv)
467 {
468 	fprintf(stderr, "ldns-keygen needs OpenSSL support, which has not been compiled in\n");
469 	return 1;
470 }
471 #endif /* HAVE_SSL */
472