1 /*
2  * ldns-signzone signs a zone file
3  *
4  * (c) NLnet Labs, 2005 - 2008
5  * See the file LICENSE for the license
6  */
7 
8 #include <stdio.h>
9 
10 #include "config.h"
11 
12 #ifdef HAVE_SSL
13 
14 #include <stdlib.h>
15 #include <unistd.h>
16 
17 #include <errno.h>
18 
19 #include <time.h>
20 
21 #include <ldns/ldns.h>
22 #include <ldns/keys.h>
23 
24 #include <openssl/conf.h>
25 #ifndef OPENSSL_NO_ENGINE
26 #include <openssl/engine.h>
27 #endif
28 #include <openssl/err.h>
29 
30 #define MAX_FILENAME_LEN 250
31 
32 char *prog;
33 int verbosity = 1;
34 
35 static void
usage(FILE * fp,const char * prog)36 usage(FILE *fp, const char *prog) {
37 	fprintf(fp, "%s [OPTIONS] zonefile key [key [key]]\n", prog);
38 	fprintf(fp, "  signs the zone with the given key(s)\n");
39 	fprintf(fp, "  -b\t\tuse layout in signed zone and print comments DNSSEC records\n");
40 	fprintf(fp, "  -d\t\tused keys are not added to the zone\n");
41 	fprintf(fp, "  -e <date>\texpiration date\n");
42 	fprintf(fp, "  -f <file>\toutput zone to file (default <name>.signed)\n");
43 	fprintf(fp, "  -i <date>\tinception date\n");
44 	fprintf(fp, "  -o <domain>\torigin for the zone\n");
45 	fprintf(fp, "  -u\t\tset SOA serial to the number of seconds since 1-1-1970\n");
46 	fprintf(fp, "  -v\t\tprint version and exit\n");
47 	fprintf(fp, "  -z <[scheme:]hash>\tAdd ZONEMD resource record\n");
48 	fprintf(fp, "\t\t<scheme> should be \"simple\" (or 1)\n");
49 	fprintf(fp, "\t\t<hash> should be \"sha384\" or \"sha512\" (or 1 or 2)\n");
50 	fprintf(fp, "\t\tthis option can be given more than once\n");
51 	fprintf(fp, "  -Z\t\tAllow ZONEMDs to be added without signing\n");
52 	fprintf(fp, "  -A\t\tsign DNSKEY with all keys instead of minimal\n");
53 	fprintf(fp, "  -U\t\tSign with every unique algorithm in the provided keys\n");
54 #ifndef OPENSSL_NO_ENGINE
55 	fprintf(fp, "  -E <name>\tuse <name> as the crypto engine for signing\n");
56 	fprintf(fp, "           \tThis can have a lot of extra options, see the manual page for more info\n");
57 	fprintf(fp, "  -k <algorithm>,<key>\tuse `key' with `algorithm' from engine as ZSK\n");
58 	fprintf(fp, "  -K <algorithm>,<key>\tuse `key' with `algorithm' from engine as KSK\n");
59 #endif
60 	fprintf(fp, "  -n\t\tuse NSEC3 instead of NSEC.\n");
61 	fprintf(fp, "\t\tIf you use NSEC3, you can specify the following extra options:\n");
62 	fprintf(fp, "\t\t-a [algorithm] hashing algorithm\n");
63 	fprintf(fp, "\t\t-t [number] number of hash iterations\n");
64 	fprintf(fp, "\t\t-s [string] salt\n");
65 	fprintf(fp, "\t\t-p set the opt-out flag on all nsec3 rrs\n");
66 	fprintf(fp, "\n");
67 	fprintf(fp, "  keys must be specified by their base name (usually K<name>+<alg>+<id>),\n");
68 	fprintf(fp, "  i.e. WITHOUT the .private extension.\n");
69 	fprintf(fp, "  If the public part of the key is not present in the zone, the DNSKEY RR\n");
70 	fprintf(fp, "  will be read from the file called <base name>.key. If that does not exist,\n");
71 	fprintf(fp, "  a default DNSKEY will be generated from the private key and added to the zone.\n");
72 	fprintf(fp, "  A date can be a timestamp (seconds since the epoch), or of\n  the form <YYYYMMdd[hhmmss]>\n");
73 #ifndef OPENSSL_NO_ENGINE
74 	fprintf(fp, "  For -k or -K, the algorithm can be specified as an integer or a symbolic name:" );
75 
76 #define __LIST(x) fprintf ( fp, " %3d: %-15s", LDNS_SIGN_ ## x, # x )
77 
78 	fprintf ( fp, "\n " );
79 	__LIST ( RSAMD5 );
80 #ifdef USE_DSA
81 	__LIST ( DSA );
82 #endif
83 	__LIST ( RSASHA1 );
84 	fprintf ( fp, "\n " );
85 #ifdef USE_DSA
86 	__LIST ( DSA_NSEC3 );
87 #endif
88 	__LIST ( RSASHA1_NSEC3 );
89 	__LIST ( RSASHA256 );
90 	fprintf ( fp, "\n " );
91 	__LIST ( RSASHA512 );
92 	__LIST ( ECC_GOST );
93 	__LIST ( ECDSAP256SHA256 );
94 	fprintf ( fp, "\n " );
95 	__LIST ( ECDSAP384SHA384 );
96 
97 #ifdef USE_ED25519
98 	__LIST ( ED25519 );
99 #endif
100 
101 #ifdef USE_ED448
102 	__LIST ( ED448 );
103 #endif
104 	fprintf ( fp, "\n" );
105 
106 #undef __LIST
107 #endif
108 }
109 
check_tm(struct tm tm)110 static void check_tm(struct tm tm)
111 {
112 	if (tm.tm_year < 70) {
113 		fprintf(stderr, "You cannot specify dates before 1970\n");
114 		exit(EXIT_FAILURE);
115 	}
116 	if (tm.tm_mon < 0 || tm.tm_mon > 11) {
117 		fprintf(stderr, "The month must be in the range 1 to 12\n");
118 		exit(EXIT_FAILURE);
119 	}
120 	if (tm.tm_mday < 1 || tm.tm_mday > 31) {
121 		fprintf(stderr, "The day must be in the range 1 to 31\n");
122 		exit(EXIT_FAILURE);
123 	}
124 
125 	if (tm.tm_hour < 0 || tm.tm_hour > 23) {
126 		fprintf(stderr, "The hour must be in the range 0-23\n");
127 		exit(EXIT_FAILURE);
128 	}
129 
130 	if (tm.tm_min < 0 || tm.tm_min > 59) {
131 		fprintf(stderr, "The minute must be in the range 0-59\n");
132 		exit(EXIT_FAILURE);
133 	}
134 
135 	if (tm.tm_sec < 0 || tm.tm_sec > 59) {
136 		fprintf(stderr, "The second must be in the range 0-59\n");
137 		exit(EXIT_FAILURE);
138 	}
139 
140 }
141 
142 /*
143  * if the ttls are different, make them equal
144  * if one of the ttls equals LDNS_DEFAULT_TTL, that one is changed
145  * otherwise, rr2 will get the ttl of rr1
146  *
147  * prints a warning if a non-default TTL is changed
148  */
149 static void
equalize_ttls(ldns_rr * rr1,ldns_rr * rr2,uint32_t default_ttl)150 equalize_ttls(ldns_rr *rr1, ldns_rr *rr2, uint32_t default_ttl)
151 {
152 	uint32_t ttl1, ttl2;
153 
154 	ttl1 = ldns_rr_ttl(rr1);
155 	ttl2 = ldns_rr_ttl(rr2);
156 
157 	if (ttl1 != ttl2) {
158 		if (ttl1 == default_ttl) {
159 			ldns_rr_set_ttl(rr1, ttl2);
160 		} else if (ttl2 == default_ttl) {
161 			ldns_rr_set_ttl(rr2, ttl1);
162 		} else {
163 			ldns_rr_set_ttl(rr2, ttl1);
164 			fprintf(stderr,
165 			        "warning: changing non-default TTL %u to %u\n",
166 			        (unsigned int) ttl2, (unsigned int)  ttl1);
167 		}
168 	}
169 }
170 
171 static void
equalize_ttls_rr_list(ldns_rr_list * rr_list,ldns_rr * rr,uint32_t default_ttl)172 equalize_ttls_rr_list(ldns_rr_list *rr_list, ldns_rr *rr, uint32_t default_ttl)
173 {
174 	size_t i;
175 	ldns_rr *cur_rr;
176 
177 	for (i = 0; i < ldns_rr_list_rr_count(rr_list); i++) {
178 		cur_rr = ldns_rr_list_rr(rr_list, i);
179 		if (ldns_rr_compare_no_rdata(cur_rr, rr) == 0) {
180 			equalize_ttls(cur_rr, rr, default_ttl);
181 		}
182 	}
183 }
184 
185 static ldns_rr *
find_key_in_zone(ldns_rr * pubkey_gen,ldns_zone * zone)186 find_key_in_zone(ldns_rr *pubkey_gen, ldns_zone *zone) {
187 	size_t key_i;
188 	ldns_rr *pubkey;
189 
190 	for (key_i = 0;
191 		key_i < ldns_rr_list_rr_count(ldns_zone_rrs(zone));
192 		key_i++) {
193 		pubkey = ldns_rr_list_rr(ldns_zone_rrs(zone), key_i);
194 		if (ldns_rr_get_type(pubkey) == LDNS_RR_TYPE_DNSKEY &&
195 			(ldns_calc_keytag(pubkey)
196 				==
197 				ldns_calc_keytag(pubkey_gen) ||
198 					 /* KSK has gen-keytag + 1 */
199 					 ldns_calc_keytag(pubkey)
200 					 ==
201 					 ldns_calc_keytag(pubkey_gen) + 1)
202 			   ) {
203 				if (verbosity >= 2) {
204 					fprintf(stderr, "Found it in the zone!\n");
205 				}
206 				return pubkey;
207 		}
208 	}
209 	return NULL;
210 }
211 
212 static ldns_rr *
find_key_in_file(const char * keyfile_name_base,ldns_key * ATTR_UNUSED (key),uint32_t zone_ttl)213 find_key_in_file(const char *keyfile_name_base, ldns_key* ATTR_UNUSED(key),
214 	uint32_t zone_ttl)
215 {
216 	char *keyfile_name;
217 	FILE *keyfile;
218 	int line_nr;
219 	uint32_t default_ttl = zone_ttl;
220 
221 	ldns_rr *pubkey = NULL;
222 	keyfile_name = LDNS_XMALLOC(char,
223 	                            strlen(keyfile_name_base) + 5);
224 	snprintf(keyfile_name,
225 		 strlen(keyfile_name_base) + 5,
226 		 "%s.key",
227 		 keyfile_name_base);
228 	if (verbosity >= 2) {
229 		fprintf(stderr, "Trying to read %s\n", keyfile_name);
230 	}
231 	keyfile = fopen(keyfile_name, "r");
232 	line_nr = 0;
233 	if (keyfile) {
234 		if (ldns_rr_new_frm_fp_l(&pubkey,
235 					 keyfile,
236 					 &default_ttl,
237 					 NULL,
238 					 NULL,
239 					 &line_nr) ==
240 		    LDNS_STATUS_OK) {
241 			if (verbosity >= 2) {
242 				printf("Key found in file: %s\n", keyfile_name);
243 			}
244 		}
245 		fclose(keyfile);
246 	}
247 	LDNS_FREE(keyfile_name);
248 	return pubkey;
249 }
250 
251 /* this function tries to find the specified keys either in the zone that
252  * has been read, or in a <basename>.key file. If the key is not found,
253  * a public key is generated, and it is assumed the key is a ZSK
254  *
255  * if add_keys is true; the DNSKEYs are added to the zone prior to signing
256  * if it is false, they are not added.
257  * Even if keys are not added, the function is still needed, to check
258  * whether keys of which we only have key data are KSKs or ZSKS
259  */
260 static void
find_or_create_pubkey(const char * keyfile_name_base,ldns_key * key,ldns_zone * orig_zone,bool add_keys,uint32_t default_ttl)261 find_or_create_pubkey(const char *keyfile_name_base, ldns_key *key, ldns_zone *orig_zone, bool add_keys, uint32_t default_ttl) {
262 	ldns_rr *pubkey_gen, *pubkey;
263 	int key_in_zone;
264 
265 	if (default_ttl == LDNS_DEFAULT_TTL) {
266 		default_ttl = ldns_rr_ttl(ldns_zone_soa(orig_zone));
267 	}
268 
269 	if (!ldns_key_pubkey_owner(key)) {
270 		ldns_key_set_pubkey_owner(key, ldns_rdf_clone(ldns_rr_owner(ldns_zone_soa(orig_zone))));
271 	}
272 
273 	/* find the public key in the zone, or in a
274 	 * separate file
275 	 * we 'generate' one anyway,
276 	 * then match that to any present in the zone,
277 	 * if it matches, we drop our own. If not,
278 	 * we try to see if there is a .key file present.
279 	 * If not, we use our own generated one, with
280 	 * some default values
281 	 *
282 	 * Even if -d (do-not-add-keys) is specified,
283 	 * we still need to do this, because we need
284 	 * to have any key flags that are set this way
285 	 */
286 	pubkey_gen = ldns_key2rr(key);
287 	ldns_rr_set_ttl(pubkey_gen, default_ttl);
288 
289 	if (verbosity >= 2) {
290 		fprintf(stderr,
291 			   "Looking for key with keytag %u or %u\n",
292 			   (unsigned int) ldns_calc_keytag(pubkey_gen),
293 			   (unsigned int) ldns_calc_keytag(pubkey_gen)+1
294 			   );
295 	}
296 
297 	pubkey = find_key_in_zone(pubkey_gen, orig_zone);
298 	key_in_zone = 1;
299 	if (!pubkey) {
300 		key_in_zone = 0;
301 		/* it was not in the zone, try to read a .key file */
302 		pubkey = find_key_in_file(keyfile_name_base, key, default_ttl);
303 		if (!pubkey && !(ldns_key_flags(key) & LDNS_KEY_SEP_KEY)) {
304 			/* maybe it is a ksk? */
305 			ldns_key_set_keytag(key, ldns_key_keytag(key) + 1);
306 			pubkey = find_key_in_file(keyfile_name_base, key, default_ttl);
307 			if (!pubkey) {
308 				/* ok, no file, set back to ZSK */
309 				ldns_key_set_keytag(key, ldns_key_keytag(key) - 1);
310 			}
311 		}
312 		if(pubkey && ldns_dname_compare(ldns_rr_owner(pubkey), ldns_rr_owner(ldns_zone_soa(orig_zone))) != 0) {
313 			fprintf(stderr, "Error %s.key has wrong name: %s\n",
314 				keyfile_name_base, ldns_rdf2str(ldns_rr_owner(pubkey)));
315 			exit(EXIT_FAILURE); /* leak rdf2str, but we exit */
316 		}
317 	}
318 
319 	if (!pubkey) {
320 		/* okay, no public key found,
321 		   just use our generated one */
322 		pubkey = pubkey_gen;
323 		if (verbosity >= 2) {
324 			fprintf(stderr, "Not in zone, no .key file, generating ZSK DNSKEY from private key data\n");
325 		}
326 	} else {
327 		ldns_rr_free(pubkey_gen);
328 	}
329 	ldns_key_set_flags(key, ldns_rdf2native_int16(ldns_rr_rdf(pubkey, 0)));
330 	ldns_key_set_keytag(key, ldns_calc_keytag(pubkey));
331 
332 	if (add_keys && !key_in_zone) {
333 		equalize_ttls_rr_list(ldns_zone_rrs(orig_zone), pubkey, default_ttl);
334 		ldns_zone_push_rr(orig_zone, pubkey);
335 	}
336 }
337 
338 #ifndef OPENSSL_NO_ENGINE
339 /*
340  * For keys coming from the engine (-k or -K), parse algorithm specification.
341  */
342 static enum ldns_enum_signing_algorithm
parse_algspec(const char * const p)343 parse_algspec ( const char * const p )
344 {
345 	if ( p == NULL )
346 		return 0;
347 
348 	if ( isdigit ( (const unsigned char)*p ) ) {
349 		const char *nptr = NULL;
350 		const long id = strtol ( p, (char **) &nptr, 10 );
351 		return id > 0 && nptr != NULL && *nptr == ',' ? id : 0;
352 	}
353 
354 #define __MATCH(x)							\
355 	if ( !memcmp ( # x, p, sizeof ( # x ) - 1 )			\
356 	     && p [ sizeof ( # x ) - 1 ] == ',' ) {			\
357 		return LDNS_SIGN_ ## x;					\
358 	}
359 
360 	__MATCH ( RSAMD5 );
361 	__MATCH ( RSASHA1 );
362 #ifdef USE_DSA
363 	__MATCH ( DSA );
364 #endif
365 	__MATCH ( RSASHA1_NSEC3 );
366 	__MATCH ( RSASHA256 );
367 	__MATCH ( RSASHA512 );
368 #ifdef USE_DSA
369 	__MATCH ( DSA_NSEC3 );
370 #endif
371 	__MATCH ( ECC_GOST );
372 	__MATCH ( ECDSAP256SHA256 );
373 	__MATCH ( ECDSAP384SHA384 );
374 
375 #ifdef USE_ED25519
376 	__MATCH ( ED25519 );
377 #endif
378 
379 #ifdef USE_ED448
380 	__MATCH ( ED448 );
381 #endif
382 
383 #undef __MATCH
384 
385 	return 0;
386 }
387 
388 /*
389  * For keys coming from the engine (-k or -K), parse key specification
390  * in the form of <algorithm>,<key-id>. No whitespace is allowed
391  * between <algorithm> and the comma, and between the comma and
392  * <key-id>. <key-id> format is specific to the engine at hand, i.e.
393  * it can be the old OpenSC syntax or a PKCS #11 URI as defined in RFC 7512
394  * and (partially) supported by OpenSC (as of 20180312).
395  */
396 static const char *
parse_keyspec(const char * const p,enum ldns_enum_signing_algorithm * const algorithm,const char ** const id)397 parse_keyspec ( const char * const p,
398 		enum ldns_enum_signing_algorithm * const algorithm,
399 		const char ** const id )
400 {
401 	const char * const comma = strchr ( p, ',' );
402 
403 	if ( comma == NULL || !(*algorithm = parse_algspec ( p )) )
404 		return NULL;
405 	return comma [ 1 ] ? *id = comma + 1 : NULL;
406 }
407 
408 /*
409  * Load a key from the engine.
410  */
411 static ldns_key *
load_key(const char * const p,ENGINE * const e)412 load_key ( const char * const p, ENGINE * const e )
413 {
414 	enum ldns_enum_signing_algorithm alg = 0;
415 	const char *id = NULL;
416 	ldns_status status = LDNS_STATUS_ERR;
417 	ldns_key *key = NULL;
418 
419 	/* Parse key specification. */
420 	if ( parse_keyspec ( p, &alg, &id ) == NULL ) {
421 		fprintf ( stderr,
422 			  "Failed to parse key specification `%s'.\n",
423 			  p );
424 		usage ( stderr, prog );
425 		exit ( EXIT_FAILURE );
426 	}
427 
428 	/* Validate that the algorithm can be used for signing. */
429 	switch ( alg ) {
430 	case LDNS_SIGN_RSAMD5:
431 	case LDNS_SIGN_RSASHA1:
432 	case LDNS_SIGN_RSASHA1_NSEC3:
433 	case LDNS_SIGN_RSASHA256:
434 	case LDNS_SIGN_RSASHA512:
435 #ifdef USE_DSA
436 	case LDNS_SIGN_DSA:
437 	case LDNS_SIGN_DSA_NSEC3:
438 #endif
439 	case LDNS_SIGN_ECC_GOST:
440 #ifdef USE_ECDSA
441 	case LDNS_SIGN_ECDSAP256SHA256:
442 	case LDNS_SIGN_ECDSAP384SHA384:
443 #endif
444 		break;
445 	default:
446 		fprintf ( stderr,
447 			  "Algorithm %d cannot be used for signing.\n",
448 			  alg );
449 		usage ( stderr, prog );
450 		exit ( EXIT_FAILURE );
451 	}
452 
453 	printf ( "Engine key id: %s, algo %d\n", id, alg );
454 
455 	/* Attempt to load the key from the engine. */
456 	status = ldns_key_new_frm_engine (
457 			&key, e, (char *) id, (ldns_algorithm)alg );
458 	if ( status != LDNS_STATUS_OK ) {
459 		ERR_print_errors_fp ( stderr );
460 		exit ( EXIT_FAILURE );
461 	}
462 
463 	return key;
464 }
465 
466 /*
467  * For keys coming from the engine (-k or -K), set key parameters
468  * and determine whether the key is listed in the zone file.
469  */
470 static void
post_process_engine_key(ldns_key_list * const keys,ldns_key * const key,ldns_zone * const zone,const bool add_keys,const uint32_t ttl,const uint32_t inception,const uint32_t expiration)471 post_process_engine_key ( ldns_key_list * const keys,
472 			  ldns_key * const key,
473 			  ldns_zone * const zone,
474 			  const bool add_keys,
475 			  const uint32_t ttl,
476 			  const uint32_t inception,
477 			  const uint32_t expiration )
478 {
479 	if ( key == NULL ) return;
480 
481 	if ( expiration ) ldns_key_set_expiration ( key, expiration );
482 
483 	if ( inception ) ldns_key_set_inception ( key, inception );
484 
485 	ldns_key_list_push_key ( keys, key );
486 	find_or_create_pubkey ( "", key, zone, add_keys, ttl );
487 }
488 
489 /*
490  * Initialize OpenSSL, for versions 1.1 and newer.
491  */
492 static ENGINE *
init_openssl_engine(const char * const id)493 init_openssl_engine ( const char * const id )
494 {
495 	ENGINE *e = NULL;
496 
497 #ifdef HAVE_ERR_LOAD_CRYPTO_STRINGS
498         ERR_load_crypto_strings();
499 #endif
500 #if OPENSSL_VERSION_NUMBER < 0x10100000 || defined(HAVE_LIBRESSL) || !defined(HAVE_OPENSSL_INIT_CRYPTO)
501         OpenSSL_add_all_algorithms();
502 #else
503 	if ( !OPENSSL_init_crypto ( OPENSSL_INIT_LOAD_CONFIG, NULL ) ) {
504 		fprintf ( stderr, "OPENSSL_init_crypto(3) failed.\n" );
505 		ERR_print_errors_fp ( stderr );
506 		exit ( EXIT_FAILURE );
507 	}
508 #endif
509 
510 	if ( (e = ENGINE_by_id ( id )) == NULL ) {
511 		fprintf ( stderr, "ENGINE_by_id(3) failed.\n" );
512 		ERR_print_errors_fp ( stderr );
513 		exit ( EXIT_FAILURE );
514 	}
515 
516 	if (  !ENGINE_set_default_DSA ( e ) ) {
517 		fprintf ( stderr, "ENGINE_set_default_DSA(3) failed.\n" );
518 		ERR_print_errors_fp ( stderr );
519 		exit ( EXIT_FAILURE );
520 	}
521 
522 	if (  !ENGINE_set_default_RSA ( e ) ) {
523 		fprintf ( stderr, "ENGINE_set_default_RSA(3) failed.\n" );
524 		ERR_print_errors_fp ( stderr );
525 		exit ( EXIT_FAILURE );
526 	}
527 
528 	return e;
529 }
530 
531 /*
532  * De-initialize OpenSSL, for versions 1.1 and newer.
533  *
534  * All of that is not strictly necessary because the process exits
535  * anyway, however, when an engine is used, this is the only hope
536  * of letting the engine's driver know that the program terminates
537  * (for the fear that the driver's reference counting may go awry, etc.)
538  * Still, there is no guarantee that this function helps...
539  */
540 static void
shutdown_openssl(ENGINE * const e)541 shutdown_openssl ( ENGINE * const e )
542 {
543 	if ( e != NULL ) {
544 #ifdef HAVE_ENGINE_FREE
545 		ENGINE_free ( e );
546 #endif
547 #ifdef HAVE_ENGINE_CLEANUP
548 		ENGINE_cleanup ();
549 #endif
550 	}
551 
552 #ifdef HAVE_CONF_MODULES_UNLOAD
553 	CONF_modules_unload ( 1 );
554 #endif
555 #ifdef HAVE_EVP_CLEANUP
556 	EVP_cleanup ();
557 #endif
558 #ifdef HAVE_CRYPTO_CLEANUP_ALL_EX_DATA
559 	CRYPTO_cleanup_all_ex_data ();
560 #endif
561 #ifdef HAVE_ERR_FREE_STRINGS
562 	ERR_free_strings ();
563 #endif
564 }
565 #endif
566 
str2zonemd_signflag(const char * str,const char ** reason)567 int str2zonemd_signflag(const char *str, const char **reason)
568 {
569 	char *colon;
570 
571 	static const char *reasons[] = {
572 	      "Unknown <scheme>, should be \"simple\""
573 	    , "Syntax error in <hash>, should be \"sha384\" or \"sha512\""
574 	    , "Unknown <hash>, should be \"sha384\" or \"sha512\""
575 	};
576 
577 	if (!str)
578 		return LDNS_STATUS_NULL;
579 
580 	if ((colon = strchr(str, ':'))) {
581 		if ((colon - str != 1 || str[0] != '1')
582 		&&  (colon - str != 6 || strncasecmp(str, "simple", 6))) {
583 			if (reason) *reason = reasons[0];
584 			return 0;
585 		}
586 
587 		if (strchr(colon + 1, ':')) {
588 			if (reason) *reason = reasons[1];
589 			return 0;
590 		}
591 		return str2zonemd_signflag(colon + 1, reason);
592 	}
593 	if (!strcasecmp(str, "1") || !strcasecmp(str, "sha384"))
594 		return LDNS_SIGN_WITH_ZONEMD_SIMPLE_SHA384;
595 	if (!strcasecmp(str, "2") || !strcasecmp(str, "sha512"))
596 		return LDNS_SIGN_WITH_ZONEMD_SIMPLE_SHA512;
597 
598 	if (reason) *reason = reasons[2];
599 	return 0;
600 }
601 
602 int
main(int argc,char * argv[])603 main(int argc, char *argv[])
604 {
605 	const char *zonefile_name;
606 	FILE *zonefile = NULL;
607 	int line_nr = 0;
608 	int c;
609 	int argi;
610 #ifndef OPENSSL_NO_ENGINE
611 	ENGINE *engine = NULL;
612 #endif
613 	ldns_zone *orig_zone;
614 	ldns_rr_list *orig_rrs = NULL;
615 	ldns_rr *orig_soa = NULL;
616 	ldns_dnssec_zone *signed_zone;
617 
618 	char *keyfile_name_base;
619 	char *keyfile_name = NULL;
620 	FILE *keyfile = NULL;
621 	ldns_key *key = NULL;
622 #ifndef OPENSSL_NO_ENGINE
623 	ldns_key *eng_ksk = NULL; /* KSK specified with -K */
624 	ldns_key *eng_zsk = NULL; /* ZSK specified with -k */
625 #endif
626 	ldns_key_list *keys;
627 	ldns_status s;
628 	size_t i;
629 	ldns_rr_list *added_rrs;
630 
631 	char *outputfile_name = NULL;
632 	FILE *outputfile;
633 
634 	bool use_nsec3 = false;
635 	int signflags = 0;
636 	bool unixtime_serial = false;
637 
638 	/* Add the given keys to the zone if they are not yet present */
639 	bool add_keys = true;
640 	uint8_t nsec3_algorithm = 1;
641 	uint8_t nsec3_flags = 0;
642 	size_t nsec3_iterations_cmd = 1;
643 	uint16_t nsec3_iterations = 1;
644 	uint8_t nsec3_salt_length = 0;
645 	uint8_t *nsec3_salt = NULL;
646 
647 	/* we need to know the origin before reading ksk's,
648 	 * so keep an array of filenames until we know it
649 	 */
650 	struct tm tm;
651 	uint32_t inception;
652 	uint32_t expiration;
653 	ldns_rdf *origin = NULL;
654 	uint32_t ttl = LDNS_DEFAULT_TTL;
655 	ldns_rr_class class = LDNS_RR_CLASS_IN;
656 
657 	ldns_status result;
658 
659 	ldns_output_format_storage fmt_st;
660 	ldns_output_format* fmt = ldns_output_format_init(&fmt_st);
661 
662 	/* For parson zone digest parameters */
663 	int flag;
664 	const char *reason = NULL;
665 
666 	prog = strdup(argv[0]);
667 	inception = 0;
668 	expiration = 0;
669 
670 	keys = ldns_key_list_new();
671 
672 	while ((c = getopt(argc, argv, "a:bde:f:i:k:no:ps:t:uvz:ZAUE:K:")) != -1) {
673 		switch (c) {
674 		case 'a':
675 			nsec3_algorithm = (uint8_t) atoi(optarg);
676 			if (nsec3_algorithm != 1) {
677 				fprintf(stderr, "Bad NSEC3 algorithm, only RSASHA1 allowed\n");
678 				exit(EXIT_FAILURE);
679 			}
680 			break;
681 		case 'b':
682 			ldns_output_format_set(fmt, LDNS_COMMENT_FLAGS
683 						  | LDNS_COMMENT_LAYOUT
684 						  | LDNS_COMMENT_NSEC3_CHAIN
685 						  | LDNS_COMMENT_BUBBLEBABBLE);
686 			break;
687 		case 'd':
688 			add_keys = false;
689 			break;
690 		case 'e':
691 			/* try to parse YYYYMMDD first,
692 			 * if that doesn't work, it
693 			 * should be a timestamp (seconds since epoch)
694 			 */
695 			memset(&tm, 0, sizeof(tm));
696 
697 			if (strlen(optarg) == 8 &&
698 			    sscanf(optarg, "%4d%2d%2d", &tm.tm_year, &tm.tm_mon, &tm.tm_mday)
699 			    ) {
700 			   	tm.tm_year -= 1900;
701 			   	tm.tm_mon--;
702 			   	check_tm(tm);
703 				expiration =
704 					(uint32_t) ldns_mktime_from_utc(&tm);
705 			} else if (strlen(optarg) == 14 &&
706 					 sscanf(optarg, "%4d%2d%2d%2d%2d%2d", &tm.tm_year, &tm.tm_mon, &tm.tm_mday, &tm.tm_hour, &tm.tm_min, &tm.tm_sec)
707 					 ) {
708 			   	tm.tm_year -= 1900;
709 			   	tm.tm_mon--;
710 			   	check_tm(tm);
711 				expiration =
712 					(uint32_t) ldns_mktime_from_utc(&tm);
713 			} else {
714 				expiration = (uint32_t) atol(optarg);
715 			}
716 			break;
717 		case 'f':
718 			outputfile_name = LDNS_XMALLOC(char, MAX_FILENAME_LEN + 1);
719 			strncpy(outputfile_name, optarg, MAX_FILENAME_LEN);
720 			break;
721 		case 'i':
722 			memset(&tm, 0, sizeof(tm));
723 
724 			if (strlen(optarg) == 8 &&
725 			    sscanf(optarg, "%4d%2d%2d", &tm.tm_year, &tm.tm_mon, &tm.tm_mday)
726 			    ) {
727 			   	tm.tm_year -= 1900;
728 			   	tm.tm_mon--;
729 			   	check_tm(tm);
730 				inception =
731 					(uint32_t) ldns_mktime_from_utc(&tm);
732 			} else if (strlen(optarg) == 14 &&
733 					 sscanf(optarg, "%4d%2d%2d%2d%2d%2d", &tm.tm_year, &tm.tm_mon, &tm.tm_mday, &tm.tm_hour, &tm.tm_min, &tm.tm_sec)
734 					 ) {
735 			   	tm.tm_year -= 1900;
736 			   	tm.tm_mon--;
737 			   	check_tm(tm);
738 				inception =
739 					(uint32_t) ldns_mktime_from_utc(&tm);
740 			} else {
741 				inception = (uint32_t) atol(optarg);
742 			}
743 			break;
744 		case 'n':
745 			use_nsec3 = true;
746 			break;
747 		case 'o':
748 			if (ldns_str2rdf_dname(&origin, optarg) != LDNS_STATUS_OK) {
749 				fprintf(stderr, "Bad origin, not a correct domain name\n");
750 				usage(stderr, prog);
751 				exit(EXIT_FAILURE);
752 			}
753 			break;
754 		case 'p':
755 			nsec3_flags = nsec3_flags | LDNS_NSEC3_VARS_OPTOUT_MASK;
756 			break;
757 		case 'u':
758 			unixtime_serial = true;
759 			break;
760 		case 'v':
761 			printf("zone signer version %s (ldns version %s)\n", LDNS_VERSION, ldns_version());
762 			exit(EXIT_SUCCESS);
763 			break;
764 		case 'z':
765 			flag = str2zonemd_signflag(optarg, &reason);
766 			if (flag)
767 				signflags |= flag;
768 			else {
769 				fprintf( stderr
770 				       , "%s\nwith zone digest parameters:"
771 				         " \"%s\"\n"
772 				       , reason, optarg);
773 				exit(EXIT_FAILURE);
774 			}
775 			break;
776 		case 'Z':
777 			signflags |= LDNS_SIGN_NO_KEYS_NO_NSECS;
778 			break;
779 		case 'A':
780 			signflags |= LDNS_SIGN_DNSKEY_WITH_ZSK;
781 			break;
782 		case 'E':
783 #ifndef OPENSSL_NO_ENGINE
784 			engine = init_openssl_engine ( optarg );
785 			break;
786 #else
787 			/* fallthrough */
788 #endif
789 		case 'k':
790 #ifndef OPENSSL_NO_ENGINE
791 			eng_zsk = load_key ( optarg, engine );
792 			break;
793 #else
794 			/* fallthrough */
795 #endif
796 		case 'K':
797 #ifndef OPENSSL_NO_ENGINE
798 			eng_ksk = load_key ( optarg, engine );
799 			/* I apologize for that, there is no API. */
800 			eng_ksk -> _extra.dnssec.flags |= LDNS_KEY_SEP_KEY;
801 #else
802 			fprintf(stderr, "%s compiled without engine support\n"
803 			              , prog);
804 			exit(EXIT_FAILURE);
805 #endif
806 			break;
807 		case 'U':
808 			signflags |= LDNS_SIGN_WITH_ALL_ALGORITHMS;
809 			break;
810 		case 's':
811 			if (strlen(optarg) % 2 != 0) {
812 				fprintf(stderr, "Salt value is not valid hex data, not a multiple of 2 characters\n");
813 				exit(EXIT_FAILURE);
814 			}
815 			nsec3_salt_length = (uint8_t) strlen(optarg) / 2;
816 			nsec3_salt = LDNS_XMALLOC(uint8_t, nsec3_salt_length);
817 			for (c = 0; c < (int) strlen(optarg); c += 2) {
818 				if (isxdigit((int) optarg[c]) && isxdigit((int) optarg[c+1])) {
819 					nsec3_salt[c/2] = (uint8_t) ldns_hexdigit_to_int(optarg[c]) * 16 +
820 						ldns_hexdigit_to_int(optarg[c+1]);
821 				} else {
822 					fprintf(stderr, "Salt value is not valid hex data.\n");
823 					exit(EXIT_FAILURE);
824 				}
825 			}
826 
827 			break;
828 		case 't':
829 			nsec3_iterations_cmd = (size_t) atol(optarg);
830 			if (nsec3_iterations_cmd > LDNS_NSEC3_MAX_ITERATIONS) {
831 				fprintf(stderr, "Iterations count can not exceed %u, quitting\n", LDNS_NSEC3_MAX_ITERATIONS);
832 				exit(EXIT_FAILURE);
833 			}
834 			nsec3_iterations = (uint16_t) nsec3_iterations_cmd;
835 			break;
836 		default:
837 			usage(stderr, prog);
838 			exit(EXIT_SUCCESS);
839 		}
840 	}
841 
842 	argc -= optind;
843 	argv += optind;
844 
845 	if (argc < 1) {
846 		printf("Error: not enough arguments\n");
847 		usage(stdout, prog);
848 		exit(EXIT_FAILURE);
849 	} else {
850 		zonefile_name = argv[0];
851 	}
852 
853 	/* read zonefile first to find origin if not specified */
854 
855 	if (strncmp(zonefile_name, "-", 2) == 0) {
856 		s = ldns_zone_new_frm_fp_l(&orig_zone,
857 					   stdin,
858 					   origin,
859 					   ttl,
860 					   class,
861 					   &line_nr);
862 			if (s != LDNS_STATUS_OK) {
863 				fprintf(stderr, "Zone not read, error: %s at stdin line %d\n",
864 					   ldns_get_errorstr_by_id(s),
865 					   line_nr);
866 				exit(EXIT_FAILURE);
867 			} else {
868 				orig_soa = ldns_zone_soa(orig_zone);
869 				if (!orig_soa) {
870 					fprintf(stderr,
871 						   "Error reading zonefile: missing SOA record\n");
872 					exit(EXIT_FAILURE);
873 				}
874 				orig_rrs = ldns_zone_rrs(orig_zone);
875 				if (!orig_rrs) {
876 					fprintf(stderr,
877 						   "Error reading zonefile: no resource records\n");
878 					exit(EXIT_FAILURE);
879 				}
880 			}
881 	} else {
882 		zonefile = fopen(zonefile_name, "r");
883 
884 		if (!zonefile) {
885 			fprintf(stderr,
886 				   "Error: unable to read %s (%s)\n",
887 				   zonefile_name,
888 				   strerror(errno));
889 			exit(EXIT_FAILURE);
890 		} else {
891 			s = ldns_zone_new_frm_fp_l(&orig_zone,
892 			                           zonefile,
893 			                           origin,
894 			                           ttl,
895 			                           class,
896 			                           &line_nr);
897 			if (s != LDNS_STATUS_OK) {
898 				fprintf(stderr, "Zone not read, error: %s at %s line %d\n",
899 					   ldns_get_errorstr_by_id(s),
900 					   zonefile_name, line_nr);
901 				exit(EXIT_FAILURE);
902 			} else {
903 				orig_soa = ldns_zone_soa(orig_zone);
904 				if (!orig_soa) {
905 					fprintf(stderr,
906 						   "Error reading zonefile: missing SOA record\n");
907 					exit(EXIT_FAILURE);
908 				}
909 				orig_rrs = ldns_zone_rrs(orig_zone);
910 				if (!orig_rrs) {
911 					fprintf(stderr,
912 						   "Error reading zonefile: no resource records\n");
913 					exit(EXIT_FAILURE);
914 				}
915 			}
916 			fclose(zonefile);
917 		}
918 	}
919 
920 	/* read the ZSKs */
921 	argi = 1;
922 	while (argi < argc) {
923 		keyfile_name_base = argv[argi];
924 		keyfile_name = LDNS_XMALLOC(char, strlen(keyfile_name_base) + 9);
925 		snprintf(keyfile_name,
926 			    strlen(keyfile_name_base) + 9,
927 			    "%s.private",
928 			    keyfile_name_base);
929 		keyfile = fopen(keyfile_name, "r");
930 		line_nr = 0;
931 		if (!keyfile) {
932 			fprintf(stderr,
933 				   "Error: unable to read %s: %s\n",
934 				   keyfile_name,
935 				   strerror(errno));
936 		} else {
937 			s = ldns_key_new_frm_fp_l(&key, keyfile, &line_nr);
938 			fclose(keyfile);
939 			if (s == LDNS_STATUS_OK) {
940 				/* set times in key? they will end up
941 				   in the rrsigs
942 				*/
943 				if (expiration != 0) {
944 					ldns_key_set_expiration(key, expiration);
945 				}
946 				if (inception != 0) {
947 					ldns_key_set_inception(key, inception);
948 				}
949 
950 				LDNS_FREE(keyfile_name);
951 
952 				ldns_key_list_push_key(keys, key);
953 			} else {
954 				fprintf(stderr, "Error reading key from %s at line %d: %s\n", argv[argi], line_nr, ldns_get_errorstr_by_id(s));
955 			}
956 		}
957 		/* and, if not unset by -p, find or create the corresponding DNSKEY record */
958 		if (key) {
959 			find_or_create_pubkey(keyfile_name_base, key,
960 			                      orig_zone, add_keys, ttl);
961 		}
962 		argi++;
963 	}
964 
965 #ifndef OPENSSL_NO_ENGINE
966        /*
967 	* The user may have loaded a KSK and a ZSK from the engine.
968 	* Since these keys carry no meta-information which is
969 	* relevant to DNS (origin, TTL, etc), and because that
970 	* information becomes known only after the command line
971 	* and the zone file are parsed completely, the program
972 	* needs to post-process these keys before they become usable.
973 	*/
974 
975 	/* The engine's KSK. */
976 	post_process_engine_key ( keys,
977 				  eng_ksk,
978 				  orig_zone,
979 				  add_keys,
980 				  ttl,
981 				  inception,
982 				  expiration );
983 
984 	/* The engine's ZSK. */
985 	post_process_engine_key ( keys,
986 				  eng_zsk,
987 				  orig_zone,
988 				  add_keys,
989 				  ttl,
990 				  inception,
991 				  expiration );
992 #endif
993 	if (ldns_key_list_key_count(keys) < 1
994 	&&  !(signflags & LDNS_SIGN_NO_KEYS_NO_NSECS)) {
995 
996 		fprintf(stderr, "Error: no keys to sign with. Aborting.\n\n");
997 		usage(stderr, prog);
998 		exit(EXIT_FAILURE);
999 	}
1000 
1001 	signed_zone = ldns_dnssec_zone_new();
1002 	if (unixtime_serial) {
1003 		ldns_rr_soa_increment_func_int(ldns_zone_soa(orig_zone),
1004 			ldns_soa_serial_unixtime, 0);
1005 	}
1006 	if (ldns_dnssec_zone_add_rr(signed_zone, ldns_zone_soa(orig_zone)) !=
1007 	    LDNS_STATUS_OK) {
1008 		fprintf(stderr,
1009 		  "Error adding SOA to dnssec zone, skipping record\n");
1010 	}
1011 
1012 	for (i = 0;
1013 	     i < ldns_rr_list_rr_count(ldns_zone_rrs(orig_zone));
1014 	     i++) {
1015 		if (ldns_dnssec_zone_add_rr(signed_zone,
1016 		         ldns_rr_list_rr(ldns_zone_rrs(orig_zone),
1017 		         i)) !=
1018 		    LDNS_STATUS_OK) {
1019 			fprintf(stderr,
1020 			        "Error adding RR to dnssec zone");
1021 			fprintf(stderr, ", skipping record:\n");
1022 			ldns_rr_print(stderr,
1023 			  ldns_rr_list_rr(ldns_zone_rrs(orig_zone), i));
1024 		}
1025 	}
1026 	/* list to store newly created rrs, so we can free them later */
1027 	added_rrs = ldns_rr_list_new();
1028 
1029 	if (use_nsec3) {
1030 		if (verbosity < 1)
1031 			; /* pass */
1032 
1033 		else if (nsec3_iterations > 500)
1034 			fprintf(stderr, "Warning! NSEC3 iterations larger than "
1035 			    "500 may cause validating resolvers to return "
1036 			    "SERVFAIL!\n"
1037 			    "See: https://datatracker.ietf.org/doc/html/"
1038 			    "draft-hardaker-dnsop-nsec3-guidance-03#section-4\n");
1039 
1040 		else if (nsec3_iterations > 100)
1041 			fprintf(stderr, "Warning! NSEC3 iterations larger than "
1042 			    "100 may cause validating resolvers to return "
1043 			    "insecure responses!\n"
1044 			    "See: https://datatracker.ietf.org/doc/html/"
1045 			    "draft-hardaker-dnsop-nsec3-guidance-03#section-4\n");
1046 
1047 		result = ldns_dnssec_zone_sign_nsec3_flg_mkmap(signed_zone,
1048 			added_rrs,
1049 			keys,
1050 			ldns_dnssec_default_replace_signatures,
1051 			NULL,
1052 			nsec3_algorithm,
1053 			nsec3_flags,
1054 			nsec3_iterations,
1055 			nsec3_salt_length,
1056 			nsec3_salt,
1057 			signflags,
1058 			&fmt_st.hashmap);
1059 	} else {
1060 		result = ldns_dnssec_zone_sign_flg(signed_zone,
1061 				added_rrs,
1062 				keys,
1063 				ldns_dnssec_default_replace_signatures,
1064 				NULL,
1065 				signflags);
1066 	}
1067 	if (result != LDNS_STATUS_OK) {
1068 		fprintf(stderr, "Error signing zone: %s\n",
1069 			   ldns_get_errorstr_by_id(result));
1070 	}
1071 
1072 	if (!outputfile_name) {
1073 		outputfile_name = LDNS_XMALLOC(char, MAX_FILENAME_LEN);
1074 		snprintf(outputfile_name, MAX_FILENAME_LEN, "%s.signed", zonefile_name);
1075 	}
1076 
1077 	if (signed_zone) {
1078 		if (strncmp(outputfile_name, "-", 2) == 0) {
1079 			ldns_dnssec_zone_print(stdout, signed_zone);
1080 		} else {
1081 			outputfile = fopen(outputfile_name, "w");
1082 			if (!outputfile) {
1083 				fprintf(stderr, "Unable to open %s for writing: %s\n",
1084 					   outputfile_name, strerror(errno));
1085 			} else {
1086 				ldns_dnssec_zone_print_fmt(
1087 						outputfile, fmt, signed_zone);
1088 				fclose(outputfile);
1089 			}
1090 		}
1091 	} else {
1092 		fprintf(stderr, "Error signing zone.\n");
1093 
1094 #ifdef HAVE_SSL
1095 		if (ERR_peek_error()) {
1096 #if OPENSSL_VERSION_NUMBER < 0x10100000L || defined(HAVE_LIBRESSL)
1097 #ifdef HAVE_ERR_LOAD_CRYPTO_STRINGS
1098 			ERR_load_crypto_strings();
1099 #endif
1100 #endif
1101 			ERR_print_errors_fp(stderr);
1102 #if OPENSSL_VERSION_NUMBER < 0x10100000L || defined(HAVE_LIBRESSL)
1103 #ifdef HAVE_ERR_FREE_STRINGS
1104 			ERR_free_strings ();
1105 #endif
1106 #endif
1107 		}
1108 #endif
1109 		exit(EXIT_FAILURE);
1110 	}
1111 
1112 	ldns_key_list_free(keys);
1113 	/* since the ldns_rr records are pointed to in both the ldns_zone
1114 	 * and the ldns_dnssec_zone, we can either deep_free the
1115 	 * dnssec_zone and 'shallow' free the original zone and added
1116 	 * records, or the other way around
1117 	 */
1118 	ldns_dnssec_zone_free(signed_zone);
1119 	ldns_zone_deep_free(orig_zone);
1120 	ldns_rr_list_deep_free(added_rrs);
1121 	ldns_rdf_deep_free(origin);
1122 	LDNS_FREE(outputfile_name);
1123 
1124 #ifndef OPENSSL_NO_ENGINE
1125 	shutdown_openssl ( engine );
1126 #else
1127 #if OPENSSL_VERSION_NUMBER < 0x10100000 || defined(HAVE_LIBRESSL)
1128 #ifdef HAVE_CRYPTO_CLEANUP_ALL_EX_DATA
1129 	CRYPTO_cleanup_all_ex_data ();
1130 #endif
1131 #endif
1132 #endif
1133 
1134 	free(prog);
1135 	exit(EXIT_SUCCESS);
1136 }
1137 
1138 #else /* !HAVE_SSL */
1139 int
main(int argc,char ** argv)1140 main(int argc __attribute__((unused)),
1141      char **argv __attribute__((unused)))
1142 {
1143        fprintf(stderr, "ldns-signzone needs OpenSSL support, which has not been compiled in\n");
1144        return 1;
1145 }
1146 #endif /* HAVE_SSL */
1147