xref: /netbsd-src/external/mpl/bind/dist/bin/dnssec/dnssec-signzone.c (revision bcda20f65a8566e103791ec395f7f499ef322704)
1 /*	$NetBSD: dnssec-signzone.c,v 1.13 2025/01/26 16:24:32 christos Exp $	*/
2 
3 /*
4  * Portions Copyright (C) Internet Systems Consortium, Inc. ("ISC")
5  *
6  * SPDX-License-Identifier: MPL-2.0
7  *
8  * This Source Code Form is subject to the terms of the Mozilla Public
9  * License, v. 2.0. If a copy of the MPL was not distributed with this
10  * file, you can obtain one at https://mozilla.org/MPL/2.0/.
11  *
12  * See the COPYRIGHT file distributed with this work for additional
13  * information regarding copyright ownership.
14  *
15  * Portions Copyright (C) Network Associates, Inc.
16  *
17  * Permission to use, copy, modify, and/or distribute this software for any
18  * purpose with or without fee is hereby granted, provided that the above
19  * copyright notice and this permission notice appear in all copies.
20  *
21  * THE SOFTWARE IS PROVIDED "AS IS" AND ISC AND NETWORK ASSOCIATES DISCLAIMS
22  * ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
23  * WARRANTIES OF MERCHANTABILITY AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE
24  * FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
25  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
26  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR
27  * IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
28  */
29 
30 /*! \file */
31 
32 #include <inttypes.h>
33 #include <stdbool.h>
34 #include <stdlib.h>
35 #include <time.h>
36 #include <unistd.h>
37 
38 #include <openssl/opensslv.h>
39 
40 #include <isc/async.h>
41 #include <isc/atomic.h>
42 #include <isc/attributes.h>
43 #include <isc/base32.h>
44 #include <isc/commandline.h>
45 #include <isc/dir.h>
46 #include <isc/file.h>
47 #include <isc/fips.h>
48 #include <isc/hash.h>
49 #include <isc/hex.h>
50 #include <isc/loop.h>
51 #include <isc/managers.h>
52 #include <isc/md.h>
53 #include <isc/mem.h>
54 #include <isc/mutex.h>
55 #include <isc/os.h>
56 #include <isc/random.h>
57 #include <isc/result.h>
58 #include <isc/rwlock.h>
59 #include <isc/safe.h>
60 #include <isc/serial.h>
61 #include <isc/stdio.h>
62 #include <isc/string.h>
63 #include <isc/tid.h>
64 #include <isc/time.h>
65 #include <isc/util.h>
66 
67 #include <dns/db.h>
68 #include <dns/dbiterator.h>
69 #include <dns/diff.h>
70 #include <dns/dnssec.h>
71 #include <dns/ds.h>
72 #include <dns/fixedname.h>
73 #include <dns/kasp.h>
74 #include <dns/keyvalues.h>
75 #include <dns/log.h>
76 #include <dns/master.h>
77 #include <dns/masterdump.h>
78 #include <dns/nsec.h>
79 #include <dns/nsec3.h>
80 #include <dns/rdata.h>
81 #include <dns/rdataclass.h>
82 #include <dns/rdatalist.h>
83 #include <dns/rdataset.h>
84 #include <dns/rdatasetiter.h>
85 #include <dns/rdatastruct.h>
86 #include <dns/rdatatype.h>
87 #include <dns/soa.h>
88 #include <dns/time.h>
89 #include <dns/update.h>
90 #include <dns/zoneverify.h>
91 
92 #include <dst/dst.h>
93 #if OPENSSL_VERSION_NUMBER >= 0x30000000L && OPENSSL_API_LEVEL >= 30000
94 #include <openssl/err.h>
95 #include <openssl/provider.h>
96 #endif
97 
98 #include "dnssectool.h"
99 
100 const char *program = "dnssec-signzone";
101 
102 typedef struct hashlist hashlist_t;
103 
104 static int nsec_datatype = dns_rdatatype_nsec;
105 
106 #define check_dns_dbiterator_current(result)                               \
107 	check_result((result == DNS_R_NEWORIGIN) ? ISC_R_SUCCESS : result, \
108 		     "dns_dbiterator_current()")
109 
110 #define IS_NSEC3  (nsec_datatype == dns_rdatatype_nsec3)
111 #define OPTOUT(x) (((x) & DNS_NSEC3FLAG_OPTOUT) != 0)
112 
113 #define REVOKE(x) ((dst_key_flags(x) & DNS_KEYFLAG_REVOKE) != 0)
114 
115 #define BUFSIZE	  2048
116 #define MAXDSKEYS 8
117 
118 #define SIGNER_EVENTCLASS  ISC_EVENTCLASS(0x4453)
119 #define SIGNER_EVENT_WRITE (SIGNER_EVENTCLASS + 0)
120 #define SIGNER_EVENT_WORK  (SIGNER_EVENTCLASS + 1)
121 
122 #define SOA_SERIAL_KEEP	     0
123 #define SOA_SERIAL_INCREMENT 1
124 #define SOA_SERIAL_UNIXTIME  2
125 #define SOA_SERIAL_DATE	     3
126 
127 static dns_dnsseckeylist_t keylist;
128 static unsigned int keycount = 0;
129 static isc_rwlock_t keylist_lock;
130 static isc_stdtime_t starttime = 0, endtime = 0, dnskey_endtime = 0, now;
131 static int cycle = -1;
132 static int jitter = 0;
133 static bool tryverify = false;
134 static bool printstats = false;
135 static isc_mem_t *mctx = NULL;
136 static dns_ttl_t zone_soa_min_ttl;
137 static dns_ttl_t soa_ttl;
138 static FILE *outfp = NULL;
139 static char *tempfile = NULL;
140 static const dns_master_style_t *masterstyle;
141 static dns_masterformat_t inputformat = dns_masterformat_text;
142 static dns_masterformat_t outputformat = dns_masterformat_text;
143 static uint32_t rawversion = 1, serialnum = 0;
144 static bool snset = false;
145 static atomic_uint_fast32_t nsigned = 0, nretained = 0, ndropped = 0;
146 static atomic_uint_fast32_t nverified = 0, nverifyfailed = 0;
147 static const char *directory = NULL, *dsdir = NULL;
148 static isc_mutex_t namelock;
149 static isc_nm_t *netmgr = NULL;
150 static isc_loopmgr_t *loopmgr = NULL;
151 static dns_db_t *gdb;		  /* The database */
152 static dns_dbversion_t *gversion; /* The database version */
153 static dns_dbiterator_t *gdbiter; /* The database iterator */
154 static dns_rdataclass_t gclass;	  /* The class */
155 static dns_name_t *gorigin;	  /* The database origin */
156 static int nsec3flags = 0;
157 static dns_iterations_t nsec3iter = 0U;
158 static unsigned char saltbuf[255];
159 static unsigned char *gsalt = saltbuf;
160 static size_t salt_length = 0;
161 static unsigned int nloops = 0;
162 static atomic_bool shuttingdown;
163 static atomic_bool finished;
164 static bool nokeys = false;
165 static bool removefile = false;
166 static bool generateds = false;
167 static bool ignore_kskflag = false;
168 static bool keyset_kskonly = false;
169 static dns_master_style_t *dsstyle = NULL;
170 static unsigned int serialformat = SOA_SERIAL_KEEP;
171 static unsigned int hash_length = 0;
172 static bool unknownalg = false;
173 static bool disable_zone_check = false;
174 static bool update_chain = false;
175 static bool set_keyttl = false;
176 static dns_ttl_t keyttl;
177 static bool smartsign = false;
178 static bool remove_orphansigs = false;
179 static bool remove_inactkeysigs = false;
180 static bool output_dnssec_only = false;
181 static bool output_stdout = false;
182 static bool set_maxttl = false;
183 static dns_ttl_t maxttl = 0;
184 static bool no_max_check = false;
185 static const char *sync_records = "cdnskey,cds:sha-256";
186 
187 #define INCSTAT(counter)                               \
188 	if (printstats) {                              \
189 		atomic_fetch_add_relaxed(&counter, 1); \
190 	}
191 
192 /*%
193  * Store a copy of 'name' in 'fzonecut' and return a pointer to that copy.
194  */
195 static dns_name_t *
196 savezonecut(dns_fixedname_t *fzonecut, dns_name_t *name) {
197 	dns_name_t *result;
198 
199 	result = dns_fixedname_initname(fzonecut);
200 	dns_name_copy(name, result);
201 
202 	return result;
203 }
204 
205 static void
206 dumpnode(dns_name_t *name, dns_dbnode_t *node) {
207 	dns_rdataset_t rds;
208 	dns_rdatasetiter_t *iter = NULL;
209 	isc_buffer_t *buffer = NULL;
210 	isc_region_t r;
211 	isc_result_t result;
212 	unsigned int bufsize = 4096;
213 
214 	if (!output_dnssec_only) {
215 		return;
216 	}
217 
218 	result = dns_db_allrdatasets(gdb, node, gversion, 0, 0, &iter);
219 	check_result(result, "dns_db_allrdatasets");
220 
221 	dns_rdataset_init(&rds);
222 
223 	isc_buffer_allocate(mctx, &buffer, bufsize);
224 
225 	for (result = dns_rdatasetiter_first(iter); result == ISC_R_SUCCESS;
226 	     result = dns_rdatasetiter_next(iter))
227 	{
228 		dns_rdatasetiter_current(iter, &rds);
229 
230 		if (rds.type != dns_rdatatype_rrsig &&
231 		    rds.type != dns_rdatatype_nsec &&
232 		    rds.type != dns_rdatatype_nsec3 &&
233 		    rds.type != dns_rdatatype_nsec3param &&
234 		    (!smartsign || rds.type != dns_rdatatype_dnskey))
235 		{
236 			dns_rdataset_disassociate(&rds);
237 			continue;
238 		}
239 
240 		for (;;) {
241 			result = dns_master_rdatasettotext(
242 				name, &rds, masterstyle, NULL, buffer);
243 			if (result != ISC_R_NOSPACE) {
244 				break;
245 			}
246 
247 			bufsize <<= 1;
248 			isc_buffer_free(&buffer);
249 			isc_buffer_allocate(mctx, &buffer, bufsize);
250 		}
251 		check_result(result, "dns_master_rdatasettotext");
252 
253 		isc_buffer_usedregion(buffer, &r);
254 		result = isc_stdio_write(r.base, 1, r.length, outfp, NULL);
255 		check_result(result, "isc_stdio_write");
256 		isc_buffer_clear(buffer);
257 
258 		dns_rdataset_disassociate(&rds);
259 	}
260 
261 	isc_buffer_free(&buffer);
262 	dns_rdatasetiter_destroy(&iter);
263 }
264 
265 static void
266 lock_and_dumpnode(dns_name_t *name, dns_dbnode_t *node) {
267 	if (!output_dnssec_only) {
268 		return;
269 	}
270 
271 	LOCK(&namelock);
272 	dumpnode(name, node);
273 	UNLOCK(&namelock);
274 }
275 
276 /*%
277  * Sign the given RRset with given key, and add the signature record to the
278  * given tuple.
279  */
280 static void
281 signwithkey(dns_name_t *name, dns_rdataset_t *rdataset, dst_key_t *key,
282 	    dns_ttl_t ttl, dns_diff_t *add, const char *logmsg) {
283 	isc_result_t result;
284 	isc_stdtime_t jendtime, expiry;
285 	char keystr[DST_KEY_FORMATSIZE];
286 	dns_rdata_t trdata = DNS_RDATA_INIT;
287 	unsigned char array[BUFSIZE];
288 	isc_buffer_t b;
289 	dns_difftuple_t *tuple;
290 
291 	dst_key_format(key, keystr, sizeof(keystr));
292 	vbprintf(1, "\t%s %s\n", logmsg, keystr);
293 
294 	if (rdataset->type == dns_rdatatype_dnskey) {
295 		expiry = dnskey_endtime;
296 	} else {
297 		expiry = endtime;
298 	}
299 
300 	jendtime = (jitter != 0) ? expiry - isc_random_uniform(jitter) : expiry;
301 	isc_buffer_init(&b, array, sizeof(array));
302 	result = dns_dnssec_sign(name, rdataset, key, &starttime, &jendtime,
303 				 mctx, &b, &trdata);
304 	if (result != ISC_R_SUCCESS) {
305 		fatal("dnskey '%s' failed to sign data: %s", keystr,
306 		      isc_result_totext(result));
307 	}
308 	INCSTAT(nsigned);
309 
310 	if (tryverify) {
311 		result = dns_dnssec_verify(name, rdataset, key, true, 0, mctx,
312 					   &trdata, NULL);
313 		if (result == ISC_R_SUCCESS || result == DNS_R_FROMWILDCARD) {
314 			vbprintf(3, "\tsignature verified\n");
315 			INCSTAT(nverified);
316 		} else {
317 			vbprintf(3, "\tsignature failed to verify\n");
318 			INCSTAT(nverifyfailed);
319 		}
320 	}
321 
322 	tuple = NULL;
323 	result = dns_difftuple_create(mctx, DNS_DIFFOP_ADDRESIGN, name, ttl,
324 				      &trdata, &tuple);
325 	check_result(result, "dns_difftuple_create");
326 	dns_diff_append(add, &tuple);
327 }
328 
329 static bool
330 issigningkey(dns_dnsseckey_t *key) {
331 	return key->force_sign || key->hint_sign;
332 }
333 
334 static bool
335 ispublishedkey(dns_dnsseckey_t *key) {
336 	return (key->force_publish || key->hint_publish) && !key->hint_remove;
337 }
338 
339 static bool
340 iszonekey(dns_dnsseckey_t *key) {
341 	return dns_name_equal(dst_key_name(key->key), gorigin) &&
342 	       dst_key_iszonekey(key->key);
343 }
344 
345 static bool
346 isksk(dns_dnsseckey_t *key) {
347 	return key->ksk;
348 }
349 
350 static bool
351 iszsk(dns_dnsseckey_t *key) {
352 	return ignore_kskflag || !key->ksk;
353 }
354 
355 /*%
356  * Find the key that generated an RRSIG, if it is in the key list.  If
357  * so, return a pointer to it, otherwise return NULL.
358  *
359  * No locking is performed here, this must be done by the caller.
360  */
361 static dns_dnsseckey_t *
362 keythatsigned_unlocked(dns_rdata_rrsig_t *rrsig) {
363 	dns_dnsseckey_t *key;
364 
365 	for (key = ISC_LIST_HEAD(keylist); key != NULL;
366 	     key = ISC_LIST_NEXT(key, link))
367 	{
368 		if (rrsig->keyid == dst_key_id(key->key) &&
369 		    rrsig->algorithm == dst_key_alg(key->key) &&
370 		    dns_name_equal(&rrsig->signer, dst_key_name(key->key)))
371 		{
372 			return key;
373 		}
374 	}
375 	return NULL;
376 }
377 
378 /*%
379  * Finds the key that generated a RRSIG, if possible.  First look at the keys
380  * that we've loaded already, and then see if there's a key on disk.
381  */
382 static dns_dnsseckey_t *
383 keythatsigned(dns_rdata_rrsig_t *rrsig) {
384 	isc_result_t result;
385 	dst_key_t *pubkey = NULL, *privkey = NULL;
386 	dns_dnsseckey_t *key = NULL;
387 
388 	RWLOCK(&keylist_lock, isc_rwlocktype_read);
389 	key = keythatsigned_unlocked(rrsig);
390 	RWUNLOCK(&keylist_lock, isc_rwlocktype_read);
391 	if (key != NULL) {
392 		return key;
393 	}
394 
395 	/*
396 	 * We did not find the key in our list.  Get a write lock now, since
397 	 * we may be modifying the bits.  We could do the tryupgrade() dance,
398 	 * but instead just get a write lock and check once again to see if
399 	 * it is on our list.  It's possible someone else may have added it
400 	 * after all.
401 	 */
402 	isc_rwlock_lock(&keylist_lock, isc_rwlocktype_write);
403 	key = keythatsigned_unlocked(rrsig);
404 	if (key != NULL) {
405 		isc_rwlock_unlock(&keylist_lock, isc_rwlocktype_write);
406 		return key;
407 	}
408 
409 	result = dst_key_fromfile(&rrsig->signer, rrsig->keyid,
410 				  rrsig->algorithm, DST_TYPE_PUBLIC, directory,
411 				  mctx, &pubkey);
412 	if (result != ISC_R_SUCCESS) {
413 		isc_rwlock_unlock(&keylist_lock, isc_rwlocktype_write);
414 		return NULL;
415 	}
416 
417 	result = dst_key_fromfile(
418 		&rrsig->signer, rrsig->keyid, rrsig->algorithm,
419 		DST_TYPE_PUBLIC | DST_TYPE_PRIVATE, directory, mctx, &privkey);
420 	if (result == ISC_R_SUCCESS) {
421 		dst_key_free(&pubkey);
422 		dns_dnsseckey_create(mctx, &privkey, &key);
423 	} else {
424 		dns_dnsseckey_create(mctx, &pubkey, &key);
425 	}
426 
427 	key->force_publish = false;
428 	key->force_sign = false;
429 	key->index = keycount++;
430 	ISC_LIST_APPEND(keylist, key, link);
431 
432 	isc_rwlock_unlock(&keylist_lock, isc_rwlocktype_write);
433 	return key;
434 }
435 
436 /*%
437  * Check to see if we expect to find a key at this name.  If we see a RRSIG
438  * and can't find the signing key that we expect to find, we drop the rrsig.
439  * I'm not sure if this is completely correct, but it seems to work.
440  */
441 static bool
442 expecttofindkey(dns_name_t *name) {
443 	unsigned int options = DNS_DBFIND_NOWILD;
444 	dns_fixedname_t fname;
445 	isc_result_t result;
446 	char namestr[DNS_NAME_FORMATSIZE];
447 
448 	dns_fixedname_init(&fname);
449 	result = dns_db_find(gdb, name, gversion, dns_rdatatype_dnskey, options,
450 			     0, NULL, dns_fixedname_name(&fname), NULL, NULL);
451 	switch (result) {
452 	case ISC_R_SUCCESS:
453 	case DNS_R_NXDOMAIN:
454 	case DNS_R_NXRRSET:
455 		return true;
456 	case DNS_R_DELEGATION:
457 	case DNS_R_CNAME:
458 	case DNS_R_DNAME:
459 		return false;
460 	default:
461 		break;
462 	}
463 	dns_name_format(name, namestr, sizeof(namestr));
464 	fatal("failure looking for '%s DNSKEY' in database: %s", namestr,
465 	      isc_result_totext(result));
466 	UNREACHABLE();
467 	return false; /* removes a warning */
468 }
469 
470 static bool
471 setverifies(dns_name_t *name, dns_rdataset_t *set, dst_key_t *key,
472 	    dns_rdata_t *rrsig) {
473 	isc_result_t result;
474 	result = dns_dnssec_verify(name, set, key, false, 0, mctx, rrsig, NULL);
475 	if (result == ISC_R_SUCCESS || result == DNS_R_FROMWILDCARD) {
476 		INCSTAT(nverified);
477 		return true;
478 	} else {
479 		INCSTAT(nverifyfailed);
480 		return false;
481 	}
482 }
483 
484 /*%
485  * Signs a set.  Goes through contortions to decide if each RRSIG should
486  * be dropped or retained, and then determines if any new SIGs need to
487  * be generated.
488  */
489 static void
490 signset(dns_diff_t *del, dns_diff_t *add, dns_dbnode_t *node, dns_name_t *name,
491 	dns_rdataset_t *set) {
492 	dns_rdataset_t sigset;
493 	dns_rdata_t sigrdata = DNS_RDATA_INIT;
494 	dns_rdata_rrsig_t rrsig;
495 	dns_dnsseckey_t *key;
496 	isc_result_t result;
497 	bool nosigs = false;
498 	bool *wassignedby, *nowsignedby;
499 	int arraysize;
500 	dns_difftuple_t *tuple;
501 	dns_ttl_t ttl;
502 	int i;
503 	char namestr[DNS_NAME_FORMATSIZE];
504 	char typestr[DNS_RDATATYPE_FORMATSIZE];
505 	char sigstr[SIG_FORMATSIZE];
506 
507 	dns_name_format(name, namestr, sizeof(namestr));
508 	dns_rdatatype_format(set->type, typestr, sizeof(typestr));
509 
510 	ttl = ISC_MIN(set->ttl, endtime - starttime);
511 
512 	dns_rdataset_init(&sigset);
513 	result = dns_db_findrdataset(gdb, node, gversion, dns_rdatatype_rrsig,
514 				     set->type, 0, &sigset, NULL);
515 	if (result == ISC_R_NOTFOUND) {
516 		vbprintf(2, "no existing signatures for %s/%s\n", namestr,
517 			 typestr);
518 		result = ISC_R_SUCCESS;
519 		nosigs = true;
520 	}
521 	if (result != ISC_R_SUCCESS) {
522 		fatal("failed while looking for '%s RRSIG %s': %s", namestr,
523 		      typestr, isc_result_totext(result));
524 	}
525 
526 	vbprintf(1, "%s/%s:\n", namestr, typestr);
527 
528 	arraysize = keycount;
529 	if (!nosigs) {
530 		arraysize += dns_rdataset_count(&sigset);
531 	}
532 	wassignedby = isc_mem_cget(mctx, arraysize, sizeof(bool));
533 	nowsignedby = isc_mem_cget(mctx, arraysize, sizeof(bool));
534 
535 	for (i = 0; i < arraysize; i++) {
536 		wassignedby[i] = nowsignedby[i] = false;
537 	}
538 
539 	if (nosigs) {
540 		result = ISC_R_NOMORE;
541 	} else {
542 		result = dns_rdataset_first(&sigset);
543 	}
544 
545 	while (result == ISC_R_SUCCESS) {
546 		bool expired, future;
547 		bool keep = false, resign = false;
548 
549 		dns_rdataset_current(&sigset, &sigrdata);
550 
551 		result = dns_rdata_tostruct(&sigrdata, &rrsig, NULL);
552 		check_result(result, "dns_rdata_tostruct");
553 
554 		future = isc_serial_lt(now, rrsig.timesigned);
555 
556 		key = keythatsigned(&rrsig);
557 		sig_format(&rrsig, sigstr, sizeof(sigstr));
558 		expired = isc_serial_gt(now + cycle, rrsig.timeexpire);
559 
560 		if (isc_serial_gt(rrsig.timesigned, rrsig.timeexpire)) {
561 			/* rrsig is dropped and not replaced */
562 			vbprintf(2,
563 				 "\trrsig by %s dropped - "
564 				 "invalid validity period\n",
565 				 sigstr);
566 		} else if (key == NULL && !future &&
567 			   expecttofindkey(&rrsig.signer))
568 		{
569 			/* rrsig is dropped and not replaced */
570 			vbprintf(2,
571 				 "\trrsig by %s dropped - "
572 				 "private dnskey not found\n",
573 				 sigstr);
574 		} else if (key == NULL || future) {
575 			keep = (!expired && !remove_orphansigs);
576 			vbprintf(2, "\trrsig by %s %s - dnskey not found\n",
577 				 keep ? "retained" : "dropped", sigstr);
578 		} else if (!dns_dnssec_keyactive(key->key, now) &&
579 			   remove_inactkeysigs)
580 		{
581 			keep = false;
582 			vbprintf(2, "\trrsig by %s dropped - key inactive\n",
583 				 sigstr);
584 		} else if (issigningkey(key)) {
585 			wassignedby[key->index] = true;
586 
587 			if (!expired && rrsig.originalttl == set->ttl &&
588 			    setverifies(name, set, key->key, &sigrdata))
589 			{
590 				vbprintf(2, "\trrsig by %s retained\n", sigstr);
591 				keep = true;
592 			} else {
593 				vbprintf(2, "\trrsig by %s dropped - %s\n",
594 					 sigstr,
595 					 expired ? "expired"
596 					 : rrsig.originalttl != set->ttl
597 						 ? "ttl change"
598 						 : "failed to "
599 						   "verify");
600 				resign = true;
601 			}
602 		} else if (!ispublishedkey(key) && remove_orphansigs) {
603 			vbprintf(2, "\trrsig by %s dropped - dnskey removed\n",
604 				 sigstr);
605 		} else if (iszonekey(key)) {
606 			wassignedby[key->index] = true;
607 
608 			if (!expired && rrsig.originalttl == set->ttl &&
609 			    setverifies(name, set, key->key, &sigrdata))
610 			{
611 				vbprintf(2, "\trrsig by %s retained\n", sigstr);
612 				keep = true;
613 			} else {
614 				vbprintf(2, "\trrsig by %s dropped - %s\n",
615 					 sigstr,
616 					 expired ? "expired"
617 					 : rrsig.originalttl != set->ttl
618 						 ? "ttl change"
619 						 : "failed to "
620 						   "verify");
621 			}
622 		} else if (!expired) {
623 			vbprintf(2, "\trrsig by %s retained\n", sigstr);
624 			keep = true;
625 		} else {
626 			vbprintf(2, "\trrsig by %s expired\n", sigstr);
627 		}
628 
629 		if (keep) {
630 			if (key != NULL) {
631 				nowsignedby[key->index] = true;
632 			}
633 			INCSTAT(nretained);
634 			if (sigset.ttl != ttl) {
635 				vbprintf(2, "\tfixing ttl %s\n", sigstr);
636 				tuple = NULL;
637 				result = dns_difftuple_create(
638 					mctx, DNS_DIFFOP_DELRESIGN, name,
639 					sigset.ttl, &sigrdata, &tuple);
640 				check_result(result, "dns_difftuple_create");
641 				dns_diff_append(del, &tuple);
642 				result = dns_difftuple_create(
643 					mctx, DNS_DIFFOP_ADDRESIGN, name, ttl,
644 					&sigrdata, &tuple);
645 				check_result(result, "dns_difftuple_create");
646 				dns_diff_append(add, &tuple);
647 			}
648 		} else {
649 			tuple = NULL;
650 			vbprintf(2, "\tremoving signature by %s\n", sigstr);
651 			result = dns_difftuple_create(
652 				mctx, DNS_DIFFOP_DELRESIGN, name, sigset.ttl,
653 				&sigrdata, &tuple);
654 			check_result(result, "dns_difftuple_create");
655 			dns_diff_append(del, &tuple);
656 			INCSTAT(ndropped);
657 		}
658 
659 		if (resign) {
660 			INSIST(!keep);
661 
662 			signwithkey(name, set, key->key, ttl, add,
663 				    "resigning with dnskey");
664 			nowsignedby[key->index] = true;
665 		}
666 
667 		dns_rdata_reset(&sigrdata);
668 		dns_rdata_freestruct(&rrsig);
669 		result = dns_rdataset_next(&sigset);
670 	}
671 	if (result == ISC_R_NOMORE) {
672 		result = ISC_R_SUCCESS;
673 	}
674 
675 	check_result(result, "dns_rdataset_first/next");
676 	if (dns_rdataset_isassociated(&sigset)) {
677 		dns_rdataset_disassociate(&sigset);
678 	}
679 
680 	for (key = ISC_LIST_HEAD(keylist); key != NULL;
681 	     key = ISC_LIST_NEXT(key, link))
682 	{
683 		if (nowsignedby[key->index]) {
684 			continue;
685 		}
686 
687 		if (!issigningkey(key)) {
688 			continue;
689 		}
690 
691 		if ((set->type == dns_rdatatype_cds ||
692 		     set->type == dns_rdatatype_cdnskey ||
693 		     set->type == dns_rdatatype_dnskey) &&
694 		    dns_name_equal(name, gorigin))
695 		{
696 			bool have_ksk;
697 			dns_dnsseckey_t *curr;
698 
699 			have_ksk = isksk(key);
700 			for (curr = ISC_LIST_HEAD(keylist); curr != NULL;
701 			     curr = ISC_LIST_NEXT(curr, link))
702 			{
703 				if (dst_key_alg(key->key) !=
704 				    dst_key_alg(curr->key))
705 				{
706 					continue;
707 				}
708 				if (REVOKE(curr->key)) {
709 					continue;
710 				}
711 				if (isksk(curr)) {
712 					have_ksk = true;
713 				}
714 			}
715 			if (isksk(key) || !have_ksk ||
716 			    (iszsk(key) && !keyset_kskonly))
717 			{
718 				signwithkey(name, set, key->key, ttl, add,
719 					    "signing with dnskey");
720 			}
721 		} else if (iszsk(key)) {
722 			/*
723 			 * Sign with the ZSK unless there is a predecessor
724 			 * key that already signs this RRset.
725 			 */
726 			bool have_pre_sig = false;
727 			dns_dnsseckey_t *curr;
728 			uint32_t pre;
729 			isc_result_t ret = dst_key_getnum(
730 				key->key, DST_NUM_PREDECESSOR, &pre);
731 			if (ret == ISC_R_SUCCESS) {
732 				/*
733 				 * This key has a predecessor, look for the
734 				 * corresponding key in the keylist. The
735 				 * key we are looking for must be:
736 				 * - From the same cryptographic algorithm.
737 				 * - Have the ZSK type (iszsk).
738 				 * - Have key ID equal to the predecessor id.
739 				 * - Have a successor that matches 'key' id.
740 				 */
741 				for (curr = ISC_LIST_HEAD(keylist);
742 				     curr != NULL;
743 				     curr = ISC_LIST_NEXT(curr, link))
744 				{
745 					uint32_t suc;
746 
747 					if (dst_key_alg(key->key) !=
748 						    dst_key_alg(curr->key) ||
749 					    !iszsk(curr) ||
750 					    dst_key_id(curr->key) != pre)
751 					{
752 						continue;
753 					}
754 					ret = dst_key_getnum(curr->key,
755 							     DST_NUM_SUCCESSOR,
756 							     &suc);
757 					if (ret != ISC_R_SUCCESS ||
758 					    dst_key_id(key->key) != suc)
759 					{
760 						continue;
761 					}
762 
763 					/*
764 					 * curr is the predecessor we were
765 					 * looking for. Check if this key
766 					 * signs this RRset.
767 					 */
768 					if (nowsignedby[curr->index]) {
769 						have_pre_sig = true;
770 					}
771 				}
772 			}
773 
774 			/*
775 			 * If we have a signature of a predecessor key,
776 			 * skip signing with this key.
777 			 */
778 			if (!have_pre_sig) {
779 				signwithkey(name, set, key->key, ttl, add,
780 					    "signing with dnskey");
781 			}
782 		}
783 	}
784 
785 	isc_mem_cput(mctx, wassignedby, arraysize, sizeof(bool));
786 	isc_mem_cput(mctx, nowsignedby, arraysize, sizeof(bool));
787 }
788 
789 struct hashlist {
790 	unsigned char *hashbuf;
791 	size_t entries;
792 	size_t size;
793 	size_t length;
794 };
795 
796 static void
797 hashlist_init(hashlist_t *l, unsigned int nodes, unsigned int length) {
798 	l->entries = 0;
799 	l->length = length + 1;
800 
801 	if (nodes != 0) {
802 		l->size = nodes;
803 		l->hashbuf = malloc(l->size * l->length);
804 		if (l->hashbuf == NULL) {
805 			l->size = 0;
806 		}
807 	} else {
808 		l->size = 0;
809 		l->hashbuf = NULL;
810 	}
811 }
812 
813 static void
814 hashlist_free(hashlist_t *l) {
815 	if (l->hashbuf) {
816 		free(l->hashbuf);
817 		l->hashbuf = NULL;
818 		l->entries = 0;
819 		l->length = 0;
820 		l->size = 0;
821 	}
822 }
823 
824 static void
825 hashlist_add(hashlist_t *l, const unsigned char *hash, size_t len) {
826 	REQUIRE(len <= l->length);
827 
828 	if (l->entries == l->size) {
829 		l->size = l->size * 2 + 100;
830 		l->hashbuf = realloc(l->hashbuf, l->size * l->length);
831 		if (l->hashbuf == NULL) {
832 			fatal("unable to grow hashlist: out of memory");
833 		}
834 	}
835 	memset(l->hashbuf + l->entries * l->length, 0, l->length);
836 	memmove(l->hashbuf + l->entries * l->length, hash, len);
837 	l->entries++;
838 }
839 
840 static void
841 hashlist_add_dns_name(hashlist_t *l,
842 		      /*const*/ dns_name_t *name, unsigned int hashalg,
843 		      unsigned int iterations, const unsigned char *salt,
844 		      size_t salt_len, bool speculative) {
845 	char nametext[DNS_NAME_FORMATSIZE];
846 	unsigned char hash[NSEC3_MAX_HASH_LENGTH + 1];
847 	unsigned int len;
848 	size_t i;
849 
850 	len = isc_iterated_hash(hash, hashalg, iterations, salt, (int)salt_len,
851 				name->ndata, name->length);
852 	if (verbose) {
853 		dns_name_format(name, nametext, sizeof nametext);
854 		for (i = 0; i < len; i++) {
855 			fprintf(stderr, "%02x", hash[i]);
856 		}
857 		fprintf(stderr, " %s\n", nametext);
858 	}
859 	hash[len++] = speculative ? 1 : 0;
860 	hashlist_add(l, hash, len);
861 }
862 
863 static int
864 hashlist_comp(const void *a, const void *b) {
865 	return memcmp(a, b, hash_length + 1);
866 }
867 
868 static void
869 hashlist_sort(hashlist_t *l) {
870 	INSIST(l->hashbuf != NULL || l->length == 0);
871 	if (l->length > 0) {
872 		qsort(l->hashbuf, l->entries, l->length, hashlist_comp);
873 	}
874 }
875 
876 static bool
877 hashlist_hasdup(hashlist_t *l) {
878 	unsigned char *current;
879 	unsigned char *next = l->hashbuf;
880 	size_t entries = l->entries;
881 
882 	/*
883 	 * Skip initial speculative wild card hashes.
884 	 */
885 	while (entries > 0U && next[l->length - 1] != 0U) {
886 		next += l->length;
887 		entries--;
888 	}
889 
890 	current = next;
891 	while (entries-- > 1U) {
892 		next += l->length;
893 		if (next[l->length - 1] != 0) {
894 			continue;
895 		}
896 		if (isc_safe_memequal(current, next, l->length - 1)) {
897 			return true;
898 		}
899 		current = next;
900 	}
901 	return false;
902 }
903 
904 static const unsigned char *
905 hashlist_findnext(const hashlist_t *l,
906 		  const unsigned char hash[NSEC3_MAX_HASH_LENGTH]) {
907 	size_t entries = l->entries;
908 	const unsigned char *next = bsearch(hash, l->hashbuf, l->entries,
909 					    l->length, hashlist_comp);
910 	INSIST(next != NULL);
911 
912 	do {
913 		if (next < l->hashbuf + (l->entries - 1) * l->length) {
914 			next += l->length;
915 		} else {
916 			next = l->hashbuf;
917 		}
918 		if (next[l->length - 1] == 0) {
919 			break;
920 		}
921 	} while (entries-- > 1U);
922 	INSIST(entries != 0U);
923 	return next;
924 }
925 
926 static bool
927 hashlist_exists(const hashlist_t *l,
928 		const unsigned char hash[NSEC3_MAX_HASH_LENGTH]) {
929 	if (bsearch(hash, l->hashbuf, l->entries, l->length, hashlist_comp)) {
930 		return true;
931 	} else {
932 		return false;
933 	}
934 }
935 
936 static void
937 addnowildcardhash(hashlist_t *l,
938 		  /*const*/ dns_name_t *name, unsigned int hashalg,
939 		  unsigned int iterations, const unsigned char *salt,
940 		  size_t salt_len) {
941 	dns_fixedname_t fixed;
942 	dns_name_t *wild;
943 	dns_dbnode_t *node = NULL;
944 	isc_result_t result;
945 	char namestr[DNS_NAME_FORMATSIZE];
946 
947 	wild = dns_fixedname_initname(&fixed);
948 
949 	result = dns_name_concatenate(dns_wildcardname, name, wild, NULL);
950 	if (result == ISC_R_NOSPACE) {
951 		return;
952 	}
953 	check_result(result, "addnowildcardhash: dns_name_concatenate()");
954 
955 	result = dns_db_findnode(gdb, wild, false, &node);
956 	if (result == ISC_R_SUCCESS) {
957 		dns_db_detachnode(gdb, &node);
958 		return;
959 	}
960 
961 	if (verbose) {
962 		dns_name_format(wild, namestr, sizeof(namestr));
963 		fprintf(stderr, "adding no-wildcardhash for %s\n", namestr);
964 	}
965 
966 	hashlist_add_dns_name(l, wild, hashalg, iterations, salt, salt_len,
967 			      true);
968 }
969 
970 static void
971 opendb(const char *prefix, dns_name_t *name, dns_rdataclass_t rdclass,
972        dns_db_t **dbp) {
973 	char filename[PATH_MAX];
974 	isc_buffer_t b;
975 	isc_result_t result;
976 
977 	isc_buffer_init(&b, filename, sizeof(filename));
978 	if (dsdir != NULL) {
979 		/* allow room for a trailing slash */
980 		if (strlen(dsdir) >= isc_buffer_availablelength(&b)) {
981 			fatal("path '%s' is too long", dsdir);
982 		}
983 		isc_buffer_putstr(&b, dsdir);
984 		if (dsdir[strlen(dsdir) - 1] != '/') {
985 			isc_buffer_putstr(&b, "/");
986 		}
987 	}
988 	if (strlen(prefix) > isc_buffer_availablelength(&b)) {
989 		fatal("path '%s' is too long", dsdir);
990 	}
991 	isc_buffer_putstr(&b, prefix);
992 	result = dns_name_tofilenametext(name, false, &b);
993 	check_result(result, "dns_name_tofilenametext()");
994 	if (isc_buffer_availablelength(&b) == 0) {
995 		char namestr[DNS_NAME_FORMATSIZE];
996 		dns_name_format(name, namestr, sizeof(namestr));
997 		fatal("name '%s' is too long", namestr);
998 	}
999 	isc_buffer_putuint8(&b, 0);
1000 
1001 	result = dns_db_create(mctx, ZONEDB_DEFAULT, dns_rootname,
1002 			       dns_dbtype_zone, rdclass, 0, NULL, dbp);
1003 	check_result(result, "dns_db_create()");
1004 
1005 	result = dns_db_load(*dbp, filename, inputformat, DNS_MASTER_HINT);
1006 	if (result != ISC_R_SUCCESS && result != DNS_R_SEENINCLUDE) {
1007 		dns_db_detach(dbp);
1008 	}
1009 }
1010 
1011 /*%
1012  * Load the DS set for a child zone, if a dsset-* file can be found.
1013  * If not, try to find a keyset-* file from an earlier version of
1014  * dnssec-signzone, and build DS records from that.
1015  */
1016 static isc_result_t
1017 loadds(dns_name_t *name, uint32_t ttl, dns_rdataset_t *dsset) {
1018 	dns_db_t *db = NULL;
1019 	dns_dbversion_t *ver = NULL;
1020 	dns_dbnode_t *node = NULL;
1021 	isc_result_t result;
1022 	dns_rdataset_t keyset;
1023 	dns_rdata_t key, ds;
1024 	unsigned char dsbuf[DNS_DS_BUFFERSIZE];
1025 	dns_diff_t diff;
1026 	dns_difftuple_t *tuple = NULL;
1027 
1028 	opendb("dsset-", name, gclass, &db);
1029 	if (db != NULL) {
1030 		result = dns_db_findnode(db, name, false, &node);
1031 		if (result == ISC_R_SUCCESS) {
1032 			dns_rdataset_init(dsset);
1033 			result = dns_db_findrdataset(db, node, NULL,
1034 						     dns_rdatatype_ds, 0, 0,
1035 						     dsset, NULL);
1036 			dns_db_detachnode(db, &node);
1037 			if (result == ISC_R_SUCCESS) {
1038 				vbprintf(2, "found DS records\n");
1039 				dsset->ttl = ttl;
1040 				dns_db_detach(&db);
1041 				return result;
1042 			}
1043 		}
1044 		dns_db_detach(&db);
1045 	}
1046 
1047 	/* No DS records found; try again, looking for DNSKEY records */
1048 	opendb("keyset-", name, gclass, &db);
1049 	if (db == NULL) {
1050 		return ISC_R_NOTFOUND;
1051 	}
1052 
1053 	result = dns_db_findnode(db, name, false, &node);
1054 	if (result != ISC_R_SUCCESS) {
1055 		dns_db_detach(&db);
1056 		return result;
1057 	}
1058 
1059 	dns_rdataset_init(&keyset);
1060 	result = dns_db_findrdataset(db, node, NULL, dns_rdatatype_dnskey, 0, 0,
1061 				     &keyset, NULL);
1062 	if (result != ISC_R_SUCCESS) {
1063 		dns_db_detachnode(db, &node);
1064 		dns_db_detach(&db);
1065 		return result;
1066 	}
1067 	vbprintf(2, "found DNSKEY records\n");
1068 
1069 	result = dns_db_newversion(db, &ver);
1070 	check_result(result, "dns_db_newversion");
1071 	dns_diff_init(mctx, &diff);
1072 
1073 	for (result = dns_rdataset_first(&keyset); result == ISC_R_SUCCESS;
1074 	     result = dns_rdataset_next(&keyset))
1075 	{
1076 		dns_rdata_init(&key);
1077 		dns_rdata_init(&ds);
1078 		dns_rdataset_current(&keyset, &key);
1079 		result = dns_ds_buildrdata(name, &key, DNS_DSDIGEST_SHA256,
1080 					   dsbuf, &ds);
1081 		check_result(result, "dns_ds_buildrdata");
1082 
1083 		result = dns_difftuple_create(mctx, DNS_DIFFOP_ADDRESIGN, name,
1084 					      ttl, &ds, &tuple);
1085 		check_result(result, "dns_difftuple_create");
1086 		dns_diff_append(&diff, &tuple);
1087 	}
1088 
1089 	result = dns_diff_apply(&diff, db, ver);
1090 	check_result(result, "dns_diff_apply");
1091 	dns_diff_clear(&diff);
1092 
1093 	dns_db_closeversion(db, &ver, true);
1094 
1095 	result = dns_db_findrdataset(db, node, NULL, dns_rdatatype_ds, 0, 0,
1096 				     dsset, NULL);
1097 	check_result(result, "dns_db_findrdataset");
1098 
1099 	dns_rdataset_disassociate(&keyset);
1100 	dns_db_detachnode(db, &node);
1101 	dns_db_detach(&db);
1102 	return result;
1103 }
1104 
1105 static bool
1106 secure(dns_name_t *name, dns_dbnode_t *node) {
1107 	dns_rdataset_t dsset;
1108 	isc_result_t result;
1109 
1110 	if (dns_name_equal(name, gorigin)) {
1111 		return false;
1112 	}
1113 
1114 	dns_rdataset_init(&dsset);
1115 	result = dns_db_findrdataset(gdb, node, gversion, dns_rdatatype_ds, 0,
1116 				     0, &dsset, NULL);
1117 	if (dns_rdataset_isassociated(&dsset)) {
1118 		dns_rdataset_disassociate(&dsset);
1119 	}
1120 
1121 	return result == ISC_R_SUCCESS;
1122 }
1123 
1124 static bool
1125 is_delegation(dns_db_t *db, dns_dbversion_t *ver, dns_name_t *origin,
1126 	      dns_name_t *name, dns_dbnode_t *node, uint32_t *ttlp) {
1127 	dns_rdataset_t nsset;
1128 	isc_result_t result;
1129 
1130 	if (dns_name_equal(name, origin)) {
1131 		return false;
1132 	}
1133 
1134 	dns_rdataset_init(&nsset);
1135 	result = dns_db_findrdataset(db, node, ver, dns_rdatatype_ns, 0, 0,
1136 				     &nsset, NULL);
1137 	if (dns_rdataset_isassociated(&nsset)) {
1138 		if (ttlp != NULL) {
1139 			*ttlp = nsset.ttl;
1140 		}
1141 		dns_rdataset_disassociate(&nsset);
1142 	}
1143 
1144 	return result == ISC_R_SUCCESS;
1145 }
1146 
1147 /*%
1148  * Return true if version 'ver' of database 'db' contains a DNAME RRset at
1149  * 'node'; return false otherwise.
1150  */
1151 static bool
1152 has_dname(dns_db_t *db, dns_dbversion_t *ver, dns_dbnode_t *node) {
1153 	dns_rdataset_t dnameset;
1154 	isc_result_t result;
1155 
1156 	dns_rdataset_init(&dnameset);
1157 	result = dns_db_findrdataset(db, node, ver, dns_rdatatype_dname, 0, 0,
1158 				     &dnameset, NULL);
1159 	if (dns_rdataset_isassociated(&dnameset)) {
1160 		dns_rdataset_disassociate(&dnameset);
1161 	}
1162 
1163 	return result == ISC_R_SUCCESS;
1164 }
1165 
1166 /*%
1167  * Signs all records at a name.
1168  */
1169 static void
1170 signname(dns_dbnode_t *node, bool apex, dns_name_t *name) {
1171 	isc_result_t result;
1172 	dns_rdataset_t rdataset;
1173 	dns_rdatasetiter_t *rdsiter;
1174 	bool isdelegation = false;
1175 	dns_diff_t del, add;
1176 	char namestr[DNS_NAME_FORMATSIZE];
1177 
1178 	dns_rdataset_init(&rdataset);
1179 	dns_name_format(name, namestr, sizeof(namestr));
1180 
1181 	/*
1182 	 * Determine if this is a delegation point.
1183 	 */
1184 	if (is_delegation(gdb, gversion, gorigin, name, node, NULL)) {
1185 		isdelegation = true;
1186 	}
1187 
1188 	/*
1189 	 * Now iterate through the rdatasets.
1190 	 */
1191 	dns_diff_init(mctx, &del);
1192 	dns_diff_init(mctx, &add);
1193 	rdsiter = NULL;
1194 	result = dns_db_allrdatasets(gdb, node, gversion, 0, 0, &rdsiter);
1195 	check_result(result, "dns_db_allrdatasets()");
1196 	result = dns_rdatasetiter_first(rdsiter);
1197 	while (result == ISC_R_SUCCESS) {
1198 		dns_rdatasetiter_current(rdsiter, &rdataset);
1199 
1200 		/* If this is a RRSIG set, skip it. */
1201 		if (rdataset.type == dns_rdatatype_rrsig) {
1202 			goto skip;
1203 		}
1204 
1205 		/*
1206 		 * If this name is a delegation point, skip all records
1207 		 * except NSEC and DS sets.  Otherwise check that there
1208 		 * isn't a DS record.
1209 		 */
1210 		if (isdelegation) {
1211 			if (rdataset.type != nsec_datatype &&
1212 			    rdataset.type != dns_rdatatype_ds)
1213 			{
1214 				goto skip;
1215 			}
1216 		} else if (rdataset.type == dns_rdatatype_ds) {
1217 			char namebuf[DNS_NAME_FORMATSIZE];
1218 			dns_name_format(name, namebuf, sizeof(namebuf));
1219 			fatal("'%s': found DS RRset without NS RRset\n",
1220 			      namebuf);
1221 		} else if (rdataset.type == dns_rdatatype_dnskey && !apex) {
1222 			char namebuf[DNS_NAME_FORMATSIZE];
1223 			dns_name_format(name, namebuf, sizeof(namebuf));
1224 			fatal("'%s': Non-apex DNSKEY RRset\n", namebuf);
1225 		}
1226 
1227 		signset(&del, &add, node, name, &rdataset);
1228 
1229 	skip:
1230 		dns_rdataset_disassociate(&rdataset);
1231 		result = dns_rdatasetiter_next(rdsiter);
1232 	}
1233 	if (result != ISC_R_NOMORE) {
1234 		fatal("rdataset iteration for name '%s' failed: %s", namestr,
1235 		      isc_result_totext(result));
1236 	}
1237 
1238 	dns_rdatasetiter_destroy(&rdsiter);
1239 
1240 	result = dns_diff_applysilently(&del, gdb, gversion);
1241 	if (result != ISC_R_SUCCESS) {
1242 		fatal("failed to delete SIGs at node '%s': %s", namestr,
1243 		      isc_result_totext(result));
1244 	}
1245 
1246 	result = dns_diff_applysilently(&add, gdb, gversion);
1247 	if (result != ISC_R_SUCCESS) {
1248 		fatal("failed to add SIGs at node '%s': %s", namestr,
1249 		      isc_result_totext(result));
1250 	}
1251 
1252 	dns_diff_clear(&del);
1253 	dns_diff_clear(&add);
1254 }
1255 
1256 /*
1257  * See if the node contains any non RRSIG/NSEC records and report to
1258  * caller.  Clean out extraneous RRSIG records for node.
1259  */
1260 static bool
1261 active_node(dns_dbnode_t *node) {
1262 	dns_rdatasetiter_t *rdsiter = NULL;
1263 	dns_rdatasetiter_t *rdsiter2 = NULL;
1264 	bool active = false;
1265 	isc_result_t result;
1266 	dns_rdataset_t rdataset;
1267 	dns_rdatatype_t type;
1268 	dns_rdatatype_t covers;
1269 	bool found;
1270 
1271 	dns_rdataset_init(&rdataset);
1272 	result = dns_db_allrdatasets(gdb, node, gversion, 0, 0, &rdsiter);
1273 	check_result(result, "dns_db_allrdatasets()");
1274 	result = dns_rdatasetiter_first(rdsiter);
1275 	while (result == ISC_R_SUCCESS) {
1276 		dns_rdatasetiter_current(rdsiter, &rdataset);
1277 		if (rdataset.type != dns_rdatatype_nsec &&
1278 		    rdataset.type != dns_rdatatype_nsec3 &&
1279 		    rdataset.type != dns_rdatatype_rrsig)
1280 		{
1281 			active = true;
1282 		}
1283 		dns_rdataset_disassociate(&rdataset);
1284 		if (!active) {
1285 			result = dns_rdatasetiter_next(rdsiter);
1286 		} else {
1287 			result = ISC_R_NOMORE;
1288 		}
1289 	}
1290 	if (result != ISC_R_NOMORE) {
1291 		fatal("rdataset iteration failed: %s",
1292 		      isc_result_totext(result));
1293 	}
1294 
1295 	if (!active && nsec_datatype == dns_rdatatype_nsec) {
1296 		/*%
1297 		 * The node is empty of everything but NSEC / RRSIG records.
1298 		 */
1299 		for (result = dns_rdatasetiter_first(rdsiter);
1300 		     result == ISC_R_SUCCESS;
1301 		     result = dns_rdatasetiter_next(rdsiter))
1302 		{
1303 			dns_rdatasetiter_current(rdsiter, &rdataset);
1304 			result = dns_db_deleterdataset(gdb, node, gversion,
1305 						       rdataset.type,
1306 						       rdataset.covers);
1307 			check_result(result, "dns_db_deleterdataset()");
1308 			dns_rdataset_disassociate(&rdataset);
1309 		}
1310 		if (result != ISC_R_NOMORE) {
1311 			fatal("rdataset iteration failed: %s",
1312 			      isc_result_totext(result));
1313 		}
1314 	} else {
1315 		/*
1316 		 * Delete RRSIGs for types that no longer exist.
1317 		 */
1318 		result = dns_db_allrdatasets(gdb, node, gversion, 0, 0,
1319 					     &rdsiter2);
1320 		check_result(result, "dns_db_allrdatasets()");
1321 		for (result = dns_rdatasetiter_first(rdsiter);
1322 		     result == ISC_R_SUCCESS;
1323 		     result = dns_rdatasetiter_next(rdsiter))
1324 		{
1325 			dns_rdatasetiter_current(rdsiter, &rdataset);
1326 			type = rdataset.type;
1327 			covers = rdataset.covers;
1328 			dns_rdataset_disassociate(&rdataset);
1329 			/*
1330 			 * Delete the NSEC chain if we are signing with
1331 			 * NSEC3.
1332 			 */
1333 			if (nsec_datatype == dns_rdatatype_nsec3 &&
1334 			    (type == dns_rdatatype_nsec ||
1335 			     covers == dns_rdatatype_nsec))
1336 			{
1337 				result = dns_db_deleterdataset(
1338 					gdb, node, gversion, type, covers);
1339 				check_result(result, "dns_db_deleterdataset("
1340 						     "nsec/rrsig)");
1341 				continue;
1342 			}
1343 			if (type != dns_rdatatype_rrsig) {
1344 				continue;
1345 			}
1346 			found = false;
1347 			for (result = dns_rdatasetiter_first(rdsiter2);
1348 			     !found && result == ISC_R_SUCCESS;
1349 			     result = dns_rdatasetiter_next(rdsiter2))
1350 			{
1351 				dns_rdatasetiter_current(rdsiter2, &rdataset);
1352 				if (rdataset.type == covers) {
1353 					found = true;
1354 				}
1355 				dns_rdataset_disassociate(&rdataset);
1356 			}
1357 			if (!found) {
1358 				if (result != ISC_R_NOMORE) {
1359 					fatal("rdataset iteration failed: %s",
1360 					      isc_result_totext(result));
1361 				}
1362 				result = dns_db_deleterdataset(
1363 					gdb, node, gversion, type, covers);
1364 				check_result(result, "dns_db_deleterdataset("
1365 						     "rrsig)");
1366 			} else if (result != ISC_R_NOMORE &&
1367 				   result != ISC_R_SUCCESS)
1368 			{
1369 				fatal("rdataset iteration failed: %s",
1370 				      isc_result_totext(result));
1371 			}
1372 		}
1373 		if (result != ISC_R_NOMORE) {
1374 			fatal("rdataset iteration failed: %s",
1375 			      isc_result_totext(result));
1376 		}
1377 		dns_rdatasetiter_destroy(&rdsiter2);
1378 	}
1379 	dns_rdatasetiter_destroy(&rdsiter);
1380 
1381 	return active;
1382 }
1383 
1384 /*%
1385  * Extracts the minimum TTL from the SOA record, and the SOA record's TTL.
1386  */
1387 static void
1388 get_soa_ttls(void) {
1389 	dns_rdataset_t soaset;
1390 	dns_fixedname_t fname;
1391 	dns_name_t *name;
1392 	isc_result_t result;
1393 	dns_rdata_t rdata = DNS_RDATA_INIT;
1394 
1395 	name = dns_fixedname_initname(&fname);
1396 	dns_rdataset_init(&soaset);
1397 	result = dns_db_find(gdb, gorigin, gversion, dns_rdatatype_soa, 0, 0,
1398 			     NULL, name, &soaset, NULL);
1399 	if (result != ISC_R_SUCCESS) {
1400 		fatal("failed to find an SOA at the zone apex: %s",
1401 		      isc_result_totext(result));
1402 	}
1403 
1404 	result = dns_rdataset_first(&soaset);
1405 	check_result(result, "dns_rdataset_first");
1406 	dns_rdataset_current(&soaset, &rdata);
1407 	soa_ttl = soaset.ttl;
1408 	zone_soa_min_ttl = ISC_MIN(dns_soa_getminimum(&rdata), soa_ttl);
1409 	if (set_maxttl) {
1410 		zone_soa_min_ttl = ISC_MIN(zone_soa_min_ttl, maxttl);
1411 		soa_ttl = ISC_MIN(soa_ttl, maxttl);
1412 	}
1413 	dns_rdataset_disassociate(&soaset);
1414 }
1415 
1416 /*%
1417  * Increment (or set if nonzero) the SOA serial
1418  */
1419 static isc_result_t
1420 setsoaserial(uint32_t serial, dns_updatemethod_t method) {
1421 	isc_result_t result;
1422 	dns_dbnode_t *node = NULL;
1423 	dns_rdataset_t rdataset;
1424 	dns_rdata_t rdata = DNS_RDATA_INIT;
1425 	uint32_t old_serial, new_serial = 0;
1426 	dns_updatemethod_t used = dns_updatemethod_none;
1427 
1428 	result = dns_db_getoriginnode(gdb, &node);
1429 	if (result != ISC_R_SUCCESS) {
1430 		return result;
1431 	}
1432 
1433 	dns_rdataset_init(&rdataset);
1434 
1435 	result = dns_db_findrdataset(gdb, node, gversion, dns_rdatatype_soa, 0,
1436 				     0, &rdataset, NULL);
1437 	if (result != ISC_R_SUCCESS) {
1438 		goto cleanup;
1439 	}
1440 
1441 	result = dns_rdataset_first(&rdataset);
1442 	RUNTIME_CHECK(result == ISC_R_SUCCESS);
1443 
1444 	dns_rdataset_current(&rdataset, &rdata);
1445 
1446 	old_serial = dns_soa_getserial(&rdata);
1447 
1448 	if (method == dns_updatemethod_date ||
1449 	    method == dns_updatemethod_unixtime)
1450 	{
1451 		new_serial = dns_update_soaserial(old_serial, method, &used);
1452 	} else if (serial != 0 || method == dns_updatemethod_none) {
1453 		/* Set SOA serial to the value provided. */
1454 		new_serial = serial;
1455 		used = method;
1456 	} else {
1457 		new_serial = dns_update_soaserial(old_serial, method, &used);
1458 	}
1459 
1460 	if (method != used) {
1461 		fprintf(stderr,
1462 			"%s: warning: Serial number would not advance, "
1463 			"using increment method instead\n",
1464 			program);
1465 	}
1466 
1467 	/* If the new serial is not likely to cause a zone transfer
1468 	 * (a/ixfr) from servers having the old serial, warn the user.
1469 	 *
1470 	 * RFC1982 section 7 defines the maximum increment to be
1471 	 * (2^(32-1))-1.  Using u_int32_t arithmetic, we can do a single
1472 	 * comparison.  (5 - 6 == (2^32)-1, not negative-one)
1473 	 */
1474 	if (new_serial == old_serial || (new_serial - old_serial) > 0x7fffffffU)
1475 	{
1476 		fprintf(stderr,
1477 			"%s: warning: Serial number not advanced, "
1478 			"zone may not transfer\n",
1479 			program);
1480 	}
1481 
1482 	dns_soa_setserial(new_serial, &rdata);
1483 
1484 	result = dns_db_deleterdataset(gdb, node, gversion, dns_rdatatype_soa,
1485 				       0);
1486 	check_result(result, "dns_db_deleterdataset");
1487 	if (result != ISC_R_SUCCESS) {
1488 		goto cleanup;
1489 	}
1490 
1491 	result = dns_db_addrdataset(gdb, node, gversion, 0, &rdataset, 0, NULL);
1492 	check_result(result, "dns_db_addrdataset");
1493 	if (result != ISC_R_SUCCESS) {
1494 		goto cleanup;
1495 	}
1496 
1497 cleanup:
1498 	dns_rdataset_disassociate(&rdataset);
1499 	if (node != NULL) {
1500 		dns_db_detachnode(gdb, &node);
1501 	}
1502 	dns_rdata_reset(&rdata);
1503 
1504 	return result;
1505 }
1506 
1507 /*%
1508  * Set up the iterator and global state before starting the tasks.
1509  */
1510 static void
1511 presign(void) {
1512 	isc_result_t result;
1513 
1514 	gdbiter = NULL;
1515 	result = dns_db_createiterator(gdb, 0, &gdbiter);
1516 	check_result(result, "dns_db_createiterator()");
1517 }
1518 
1519 /*%
1520  * Clean up the iterator and global state after the tasks complete.
1521  */
1522 static void
1523 postsign(void) {
1524 	dns_dbiterator_destroy(&gdbiter);
1525 }
1526 
1527 /*%
1528  * Sign the apex of the zone.
1529  * Note the origin may not be the first node if there are out of zone
1530  * records.
1531  */
1532 static void
1533 signapex(void) {
1534 	dns_dbnode_t *node = NULL;
1535 	dns_fixedname_t fixed;
1536 	dns_name_t *name;
1537 	isc_result_t result;
1538 
1539 	name = dns_fixedname_initname(&fixed);
1540 	result = dns_dbiterator_seek(gdbiter, gorigin);
1541 	check_result(result, "dns_dbiterator_seek()");
1542 	result = dns_dbiterator_current(gdbiter, &node, name);
1543 	check_dns_dbiterator_current(result);
1544 	signname(node, true, name);
1545 	dumpnode(name, node);
1546 	dns_db_detachnode(gdb, &node);
1547 	result = dns_dbiterator_first(gdbiter);
1548 	if (result == ISC_R_NOMORE) {
1549 		atomic_store(&finished, true);
1550 	} else if (result != ISC_R_SUCCESS) {
1551 		fatal("failure iterating database: %s",
1552 		      isc_result_totext(result));
1553 	}
1554 }
1555 
1556 static void
1557 abortwork(void *arg) {
1558 	UNUSED(arg);
1559 
1560 	atomic_store(&shuttingdown, true);
1561 }
1562 
1563 /*%
1564  * Assigns a node to a worker thread.  This is protected by the main task's
1565  * lock.
1566  */
1567 static void
1568 assignwork(void *arg) {
1569 	dns_fixedname_t fname;
1570 	dns_name_t *name = NULL;
1571 	dns_dbnode_t *node = NULL;
1572 	dns_rdataset_t nsec;
1573 	bool found;
1574 	isc_result_t result;
1575 	static dns_name_t *zonecut = NULL; /* Protected by namelock. */
1576 	static dns_fixedname_t fzonecut;   /* Protected by namelock. */
1577 	static unsigned int ended = 0;	   /* Protected by namelock. */
1578 
1579 	UNUSED(arg);
1580 
1581 	if (atomic_load(&shuttingdown)) {
1582 		return;
1583 	}
1584 
1585 	LOCK(&namelock);
1586 	if (atomic_load(&finished)) {
1587 		ended++;
1588 		if (ended == nloops) {
1589 			isc_loopmgr_shutdown(loopmgr);
1590 		}
1591 		UNLOCK(&namelock);
1592 		return;
1593 	}
1594 
1595 	name = dns_fixedname_initname(&fname);
1596 	node = NULL;
1597 	found = false;
1598 	while (!found) {
1599 		result = dns_dbiterator_current(gdbiter, &node, name);
1600 		check_dns_dbiterator_current(result);
1601 		/*
1602 		 * The origin was handled by signapex().
1603 		 */
1604 		if (dns_name_equal(name, gorigin)) {
1605 			dns_db_detachnode(gdb, &node);
1606 			goto next;
1607 		}
1608 		/*
1609 		 * Sort the zone data from the glue and out-of-zone data.
1610 		 * For NSEC zones nodes with zone data have NSEC records.
1611 		 * For NSEC3 zones the NSEC3 nodes are zone data but
1612 		 * outside of the zone name space.  For the rest we need
1613 		 * to track the bottom of zone cuts.
1614 		 * Nodes which don't need to be signed are dumped here.
1615 		 */
1616 		dns_rdataset_init(&nsec);
1617 		result = dns_db_findrdataset(gdb, node, gversion, nsec_datatype,
1618 					     0, 0, &nsec, NULL);
1619 		if (dns_rdataset_isassociated(&nsec)) {
1620 			dns_rdataset_disassociate(&nsec);
1621 		}
1622 		if (result == ISC_R_SUCCESS) {
1623 			found = true;
1624 		} else if (nsec_datatype == dns_rdatatype_nsec3) {
1625 			if (dns_name_issubdomain(name, gorigin) &&
1626 			    (zonecut == NULL ||
1627 			     !dns_name_issubdomain(name, zonecut)))
1628 			{
1629 				if (is_delegation(gdb, gversion, gorigin, name,
1630 						  node, NULL))
1631 				{
1632 					zonecut = savezonecut(&fzonecut, name);
1633 					if (!OPTOUT(nsec3flags) ||
1634 					    secure(name, node))
1635 					{
1636 						found = true;
1637 					}
1638 				} else if (has_dname(gdb, gversion, node)) {
1639 					zonecut = savezonecut(&fzonecut, name);
1640 					found = true;
1641 				} else {
1642 					found = true;
1643 				}
1644 			}
1645 		}
1646 
1647 		if (!found) {
1648 			dumpnode(name, node);
1649 			dns_db_detachnode(gdb, &node);
1650 		}
1651 
1652 	next:
1653 		result = dns_dbiterator_next(gdbiter);
1654 		if (result == ISC_R_NOMORE) {
1655 			atomic_store(&finished, true);
1656 			break;
1657 		} else if (result != ISC_R_SUCCESS) {
1658 			fatal("failure iterating database: %s",
1659 			      isc_result_totext(result));
1660 		}
1661 	}
1662 	if (!found) {
1663 		ended++;
1664 		if (ended == nloops) {
1665 			isc_loopmgr_shutdown(loopmgr);
1666 		}
1667 		UNLOCK(&namelock);
1668 		return;
1669 	}
1670 
1671 	UNLOCK(&namelock);
1672 
1673 	signname(node, false, dns_fixedname_name(&fname));
1674 
1675 	/*%
1676 	 * Write a node to the output file, and restart the worker task.
1677 	 */
1678 	lock_and_dumpnode(dns_fixedname_name(&fname), node);
1679 	dns_db_detachnode(gdb, &node);
1680 
1681 	isc_async_current(assignwork, NULL);
1682 }
1683 
1684 /*%
1685  * Update / remove the DS RRset.  Preserve RRSIG(DS) if possible.
1686  */
1687 static void
1688 add_ds(dns_name_t *name, dns_dbnode_t *node, uint32_t nsttl) {
1689 	dns_rdataset_t dsset;
1690 	dns_rdataset_t sigdsset;
1691 	isc_result_t result;
1692 
1693 	dns_rdataset_init(&dsset);
1694 	dns_rdataset_init(&sigdsset);
1695 	result = dns_db_findrdataset(gdb, node, gversion, dns_rdatatype_ds, 0,
1696 				     0, &dsset, &sigdsset);
1697 	if (result == ISC_R_SUCCESS) {
1698 		dns_rdataset_disassociate(&dsset);
1699 		result = dns_db_deleterdataset(gdb, node, gversion,
1700 					       dns_rdatatype_ds, 0);
1701 		check_result(result, "dns_db_deleterdataset");
1702 	}
1703 
1704 	result = loadds(name, nsttl, &dsset);
1705 	if (result == ISC_R_SUCCESS) {
1706 		result = dns_db_addrdataset(gdb, node, gversion, 0, &dsset, 0,
1707 					    NULL);
1708 		check_result(result, "dns_db_addrdataset");
1709 		dns_rdataset_disassociate(&dsset);
1710 		if (dns_rdataset_isassociated(&sigdsset)) {
1711 			dns_rdataset_disassociate(&sigdsset);
1712 		}
1713 	} else if (dns_rdataset_isassociated(&sigdsset)) {
1714 		result = dns_db_deleterdataset(gdb, node, gversion,
1715 					       dns_rdatatype_rrsig,
1716 					       dns_rdatatype_ds);
1717 		check_result(result, "dns_db_deleterdataset");
1718 		dns_rdataset_disassociate(&sigdsset);
1719 	}
1720 }
1721 
1722 /*
1723  * Remove records of the given type and their signatures.
1724  */
1725 static void
1726 remove_records(dns_dbnode_t *node, dns_rdatatype_t which, bool checknsec) {
1727 	isc_result_t result;
1728 	dns_rdatatype_t type, covers;
1729 	dns_rdatasetiter_t *rdsiter = NULL;
1730 	dns_rdataset_t rdataset;
1731 
1732 	dns_rdataset_init(&rdataset);
1733 
1734 	/*
1735 	 * Delete any records of the given type at the apex.
1736 	 */
1737 	result = dns_db_allrdatasets(gdb, node, gversion, 0, 0, &rdsiter);
1738 	check_result(result, "dns_db_allrdatasets()");
1739 	for (result = dns_rdatasetiter_first(rdsiter); result == ISC_R_SUCCESS;
1740 	     result = dns_rdatasetiter_next(rdsiter))
1741 	{
1742 		dns_rdatasetiter_current(rdsiter, &rdataset);
1743 		type = rdataset.type;
1744 		covers = rdataset.covers;
1745 		dns_rdataset_disassociate(&rdataset);
1746 		if (type == which || covers == which) {
1747 			if (which == dns_rdatatype_nsec && checknsec &&
1748 			    !update_chain)
1749 			{
1750 				fatal("Zone contains NSEC records.  Use -u "
1751 				      "to update to NSEC3.");
1752 			}
1753 			if (which == dns_rdatatype_nsec3param && checknsec &&
1754 			    !update_chain)
1755 			{
1756 				fatal("Zone contains NSEC3 chains.  Use -u "
1757 				      "to update to NSEC.");
1758 			}
1759 			result = dns_db_deleterdataset(gdb, node, gversion,
1760 						       type, covers);
1761 			check_result(result, "dns_db_deleterdataset()");
1762 		}
1763 	}
1764 	dns_rdatasetiter_destroy(&rdsiter);
1765 }
1766 
1767 /*
1768  * Remove signatures covering the given type.  If type == 0,
1769  * then remove all signatures, unless this is a delegation, in
1770  * which case remove all signatures except for DS or nsec_datatype
1771  */
1772 static void
1773 remove_sigs(dns_dbnode_t *node, bool delegation, dns_rdatatype_t which) {
1774 	isc_result_t result;
1775 	dns_rdatatype_t type, covers;
1776 	dns_rdatasetiter_t *rdsiter = NULL;
1777 	dns_rdataset_t rdataset;
1778 
1779 	dns_rdataset_init(&rdataset);
1780 	result = dns_db_allrdatasets(gdb, node, gversion, 0, 0, &rdsiter);
1781 	check_result(result, "dns_db_allrdatasets()");
1782 	for (result = dns_rdatasetiter_first(rdsiter); result == ISC_R_SUCCESS;
1783 	     result = dns_rdatasetiter_next(rdsiter))
1784 	{
1785 		dns_rdatasetiter_current(rdsiter, &rdataset);
1786 		type = rdataset.type;
1787 		covers = rdataset.covers;
1788 		dns_rdataset_disassociate(&rdataset);
1789 
1790 		if (type != dns_rdatatype_rrsig) {
1791 			continue;
1792 		}
1793 
1794 		if (which == 0 && delegation &&
1795 		    (dns_rdatatype_atparent(covers) ||
1796 		     (nsec_datatype == dns_rdatatype_nsec &&
1797 		      covers == nsec_datatype)))
1798 		{
1799 			continue;
1800 		}
1801 
1802 		if (which != 0 && covers != which) {
1803 			continue;
1804 		}
1805 
1806 		result = dns_db_deleterdataset(gdb, node, gversion, type,
1807 					       covers);
1808 		check_result(result, "dns_db_deleterdataset()");
1809 	}
1810 	dns_rdatasetiter_destroy(&rdsiter);
1811 }
1812 
1813 /*%
1814  * Generate NSEC records for the zone and remove NSEC3/NSEC3PARAM records.
1815  */
1816 static void
1817 nsecify(void) {
1818 	dns_dbiterator_t *dbiter = NULL;
1819 	dns_dbnode_t *node = NULL, *nextnode = NULL;
1820 	dns_fixedname_t fname, fnextname, fzonecut;
1821 	dns_name_t *name, *nextname, *zonecut;
1822 	dns_rdataset_t rdataset;
1823 	dns_rdatasetiter_t *rdsiter = NULL;
1824 	dns_rdatatype_t type, covers;
1825 	bool done = false;
1826 	isc_result_t result;
1827 	uint32_t nsttl = 0;
1828 
1829 	dns_rdataset_init(&rdataset);
1830 	name = dns_fixedname_initname(&fname);
1831 	nextname = dns_fixedname_initname(&fnextname);
1832 	zonecut = NULL;
1833 
1834 	/*
1835 	 * Remove any NSEC3 chains.
1836 	 */
1837 	result = dns_db_createiterator(gdb, DNS_DB_NSEC3ONLY, &dbiter);
1838 	check_result(result, "dns_db_createiterator()");
1839 	for (result = dns_dbiterator_first(dbiter); result == ISC_R_SUCCESS;
1840 	     result = dns_dbiterator_next(dbiter))
1841 	{
1842 		result = dns_dbiterator_current(dbiter, &node, name);
1843 		check_dns_dbiterator_current(result);
1844 		result = dns_db_allrdatasets(gdb, node, gversion, 0, 0,
1845 					     &rdsiter);
1846 		check_result(result, "dns_db_allrdatasets()");
1847 		for (result = dns_rdatasetiter_first(rdsiter);
1848 		     result == ISC_R_SUCCESS;
1849 		     result = dns_rdatasetiter_next(rdsiter))
1850 		{
1851 			dns_rdatasetiter_current(rdsiter, &rdataset);
1852 			type = rdataset.type;
1853 			covers = rdataset.covers;
1854 			dns_rdataset_disassociate(&rdataset);
1855 			result = dns_db_deleterdataset(gdb, node, gversion,
1856 						       type, covers);
1857 			check_result(result, "dns_db_deleterdataset(nsec3param/"
1858 					     "rrsig)");
1859 		}
1860 		dns_rdatasetiter_destroy(&rdsiter);
1861 		dns_db_detachnode(gdb, &node);
1862 	}
1863 	dns_dbiterator_destroy(&dbiter);
1864 
1865 	result = dns_db_createiterator(gdb, DNS_DB_NONSEC3, &dbiter);
1866 	check_result(result, "dns_db_createiterator()");
1867 
1868 	result = dns_dbiterator_first(dbiter);
1869 	check_result(result, "dns_dbiterator_first()");
1870 
1871 	while (!done) {
1872 		result = dns_dbiterator_current(dbiter, &node, name);
1873 		check_dns_dbiterator_current(result);
1874 		/*
1875 		 * Skip out-of-zone records.
1876 		 */
1877 		if (!dns_name_issubdomain(name, gorigin)) {
1878 			result = dns_dbiterator_next(dbiter);
1879 			if (result == ISC_R_NOMORE) {
1880 				done = true;
1881 			} else {
1882 				check_result(result, "dns_dbiterator_next()");
1883 			}
1884 			dns_db_detachnode(gdb, &node);
1885 			continue;
1886 		}
1887 
1888 		if (dns_name_equal(name, gorigin)) {
1889 			remove_records(node, dns_rdatatype_nsec3param, true);
1890 			/* Clean old rrsigs at apex. */
1891 			(void)active_node(node);
1892 		}
1893 
1894 		if (is_delegation(gdb, gversion, gorigin, name, node, &nsttl)) {
1895 			zonecut = savezonecut(&fzonecut, name);
1896 			remove_sigs(node, true, 0);
1897 			if (generateds) {
1898 				add_ds(name, node, nsttl);
1899 			}
1900 		} else if (has_dname(gdb, gversion, node)) {
1901 			zonecut = savezonecut(&fzonecut, name);
1902 		}
1903 
1904 		result = dns_dbiterator_next(dbiter);
1905 		nextnode = NULL;
1906 		while (result == ISC_R_SUCCESS) {
1907 			bool active = false;
1908 			result = dns_dbiterator_current(dbiter, &nextnode,
1909 							nextname);
1910 			check_dns_dbiterator_current(result);
1911 			active = active_node(nextnode);
1912 			if (!active) {
1913 				dns_db_detachnode(gdb, &nextnode);
1914 				result = dns_dbiterator_next(dbiter);
1915 				continue;
1916 			}
1917 			if (!dns_name_issubdomain(nextname, gorigin) ||
1918 			    (zonecut != NULL &&
1919 			     dns_name_issubdomain(nextname, zonecut)))
1920 			{
1921 				remove_sigs(nextnode, false, 0);
1922 				remove_records(nextnode, dns_rdatatype_nsec,
1923 					       false);
1924 				dns_db_detachnode(gdb, &nextnode);
1925 				result = dns_dbiterator_next(dbiter);
1926 				continue;
1927 			}
1928 			dns_db_detachnode(gdb, &nextnode);
1929 			break;
1930 		}
1931 		if (result == ISC_R_NOMORE) {
1932 			dns_name_clone(gorigin, nextname);
1933 			done = true;
1934 		} else if (result != ISC_R_SUCCESS) {
1935 			fatal("iterating through the database failed: %s",
1936 			      isc_result_totext(result));
1937 		}
1938 		dns_dbiterator_pause(dbiter);
1939 		result = dns_nsec_build(gdb, gversion, node, nextname,
1940 					zone_soa_min_ttl);
1941 		check_result(result, "dns_nsec_build()");
1942 		dns_db_detachnode(gdb, &node);
1943 	}
1944 
1945 	dns_dbiterator_destroy(&dbiter);
1946 }
1947 
1948 static void
1949 addnsec3param(const unsigned char *salt, size_t salt_len,
1950 	      dns_iterations_t iterations) {
1951 	dns_dbnode_t *node = NULL;
1952 	dns_rdata_nsec3param_t nsec3param;
1953 	unsigned char nsec3parambuf[5 + 255];
1954 	dns_rdatalist_t rdatalist;
1955 	dns_rdataset_t rdataset;
1956 	dns_rdata_t rdata = DNS_RDATA_INIT;
1957 	isc_buffer_t b;
1958 	isc_result_t result;
1959 
1960 	dns_rdataset_init(&rdataset);
1961 
1962 	nsec3param.common.rdclass = gclass;
1963 	nsec3param.common.rdtype = dns_rdatatype_nsec3param;
1964 	ISC_LINK_INIT(&nsec3param.common, link);
1965 	nsec3param.mctx = NULL;
1966 	nsec3param.flags = 0;
1967 	nsec3param.hash = unknownalg ? DNS_NSEC3_UNKNOWNALG : dns_hash_sha1;
1968 	nsec3param.iterations = iterations;
1969 	nsec3param.salt_length = (unsigned char)salt_len;
1970 	nsec3param.salt = UNCONST(salt);
1971 
1972 	isc_buffer_init(&b, nsec3parambuf, sizeof(nsec3parambuf));
1973 	result = dns_rdata_fromstruct(&rdata, gclass, dns_rdatatype_nsec3param,
1974 				      &nsec3param, &b);
1975 	check_result(result, "dns_rdata_fromstruct()");
1976 	dns_rdatalist_init(&rdatalist);
1977 	rdatalist.rdclass = rdata.rdclass;
1978 	rdatalist.type = rdata.type;
1979 	ISC_LIST_APPEND(rdatalist.rdata, &rdata, link);
1980 	dns_rdatalist_tordataset(&rdatalist, &rdataset);
1981 
1982 	result = dns_db_findnode(gdb, gorigin, true, &node);
1983 	check_result(result, "dns_db_findnode(gorigin)");
1984 
1985 	/*
1986 	 * Delete any current NSEC3PARAM records.
1987 	 */
1988 	result = dns_db_deleterdataset(gdb, node, gversion,
1989 				       dns_rdatatype_nsec3param, 0);
1990 	if (result == DNS_R_UNCHANGED) {
1991 		result = ISC_R_SUCCESS;
1992 	}
1993 	check_result(result, "dddnsec3param: dns_db_deleterdataset()");
1994 
1995 	result = dns_db_addrdataset(gdb, node, gversion, 0, &rdataset,
1996 				    DNS_DBADD_MERGE, NULL);
1997 	if (result == DNS_R_UNCHANGED) {
1998 		result = ISC_R_SUCCESS;
1999 	}
2000 	check_result(result, "addnsec3param: dns_db_addrdataset()");
2001 	dns_db_detachnode(gdb, &node);
2002 }
2003 
2004 static void
2005 addnsec3(dns_name_t *name, dns_dbnode_t *node, const unsigned char *salt,
2006 	 size_t salt_len, unsigned int iterations, hashlist_t *hashlist,
2007 	 dns_ttl_t ttl) {
2008 	unsigned char hash[NSEC3_MAX_HASH_LENGTH];
2009 	const unsigned char *nexthash;
2010 	unsigned char nsec3buffer[DNS_NSEC3_BUFFERSIZE];
2011 	dns_fixedname_t hashname;
2012 	dns_rdatalist_t rdatalist;
2013 	dns_rdataset_t rdataset;
2014 	dns_rdata_t rdata = DNS_RDATA_INIT;
2015 	isc_result_t result;
2016 	dns_dbnode_t *nsec3node = NULL;
2017 	char namebuf[DNS_NAME_FORMATSIZE];
2018 	size_t hash_len;
2019 
2020 	dns_name_format(name, namebuf, sizeof(namebuf));
2021 
2022 	dns_fixedname_init(&hashname);
2023 	dns_rdataset_init(&rdataset);
2024 
2025 	dns_name_downcase(name, name, NULL);
2026 	result = dns_nsec3_hashname(&hashname, hash, &hash_len, name, gorigin,
2027 				    dns_hash_sha1, iterations, salt, salt_len);
2028 	check_result(result, "addnsec3: dns_nsec3_hashname()");
2029 	nexthash = hashlist_findnext(hashlist, hash);
2030 	result = dns_nsec3_buildrdata(
2031 		gdb, gversion, node,
2032 		unknownalg ? DNS_NSEC3_UNKNOWNALG : dns_hash_sha1, nsec3flags,
2033 		iterations, salt, salt_len, nexthash, ISC_SHA1_DIGESTLENGTH,
2034 		nsec3buffer, &rdata);
2035 	check_result(result, "addnsec3: dns_nsec3_buildrdata()");
2036 	dns_rdatalist_init(&rdatalist);
2037 	rdatalist.rdclass = rdata.rdclass;
2038 	rdatalist.type = rdata.type;
2039 	rdatalist.ttl = ttl;
2040 	ISC_LIST_APPEND(rdatalist.rdata, &rdata, link);
2041 	dns_rdatalist_tordataset(&rdatalist, &rdataset);
2042 	result = dns_db_findnsec3node(gdb, dns_fixedname_name(&hashname), true,
2043 				      &nsec3node);
2044 	check_result(result, "addnsec3: dns_db_findnode()");
2045 	result = dns_db_addrdataset(gdb, nsec3node, gversion, 0, &rdataset, 0,
2046 				    NULL);
2047 	if (result == DNS_R_UNCHANGED) {
2048 		result = ISC_R_SUCCESS;
2049 	}
2050 	check_result(result, "addnsec3: dns_db_addrdataset()");
2051 	dns_db_detachnode(gdb, &nsec3node);
2052 }
2053 
2054 /*%
2055  * Clean out NSEC3 record and RRSIG(NSEC3) that are not in the hash list.
2056  *
2057  * Extract the hash from the first label of 'name' then see if it
2058  * is in hashlist.  If 'name' is not in the hashlist then delete the
2059  * any NSEC3 records which have the same parameters as the chain we
2060  * are building.
2061  *
2062  * XXXMPA Should we also check that it of the form &lt;hash&gt;.&lt;origin&gt;?
2063  */
2064 static void
2065 nsec3clean(dns_name_t *name, dns_dbnode_t *node, unsigned int hashalg,
2066 	   unsigned int iterations, const unsigned char *salt, size_t salt_len,
2067 	   hashlist_t *hashlist) {
2068 	dns_label_t label;
2069 	dns_rdata_nsec3_t nsec3;
2070 	dns_rdata_t rdata, delrdata;
2071 	dns_rdatalist_t rdatalist;
2072 	dns_rdataset_t rdataset, delrdataset;
2073 	bool delete_rrsigs = false;
2074 	isc_buffer_t target;
2075 	isc_result_t result;
2076 	unsigned char hash[NSEC3_MAX_HASH_LENGTH + 1];
2077 	bool exists;
2078 
2079 	/*
2080 	 * Get the first label.
2081 	 */
2082 	dns_name_getlabel(name, 0, &label);
2083 
2084 	/*
2085 	 * We want just the label contents.
2086 	 */
2087 	isc_region_consume(&label, 1);
2088 
2089 	/*
2090 	 * Decode base32hex string.
2091 	 */
2092 	isc_buffer_init(&target, hash, sizeof(hash) - 1);
2093 	result = isc_base32hex_decoderegion(&label, &target);
2094 	if (result != ISC_R_SUCCESS) {
2095 		return;
2096 	}
2097 
2098 	hash[isc_buffer_usedlength(&target)] = 0;
2099 
2100 	exists = hashlist_exists(hashlist, hash);
2101 
2102 	/*
2103 	 * Verify that the NSEC3 parameters match the current ones
2104 	 * otherwise we are dealing with a different NSEC3 chain.
2105 	 */
2106 	dns_rdataset_init(&rdataset);
2107 	dns_rdataset_init(&delrdataset);
2108 
2109 	result = dns_db_findrdataset(gdb, node, gversion, dns_rdatatype_nsec3,
2110 				     0, 0, &rdataset, NULL);
2111 	if (result != ISC_R_SUCCESS) {
2112 		return;
2113 	}
2114 
2115 	/*
2116 	 * Delete any NSEC3 records which are not part of the current
2117 	 * NSEC3 chain.
2118 	 */
2119 	for (result = dns_rdataset_first(&rdataset); result == ISC_R_SUCCESS;
2120 	     result = dns_rdataset_next(&rdataset))
2121 	{
2122 		dns_rdata_init(&rdata);
2123 		dns_rdataset_current(&rdataset, &rdata);
2124 		result = dns_rdata_tostruct(&rdata, &nsec3, NULL);
2125 		check_result(result, "dns_rdata_tostruct");
2126 		if (exists && nsec3.hash == hashalg &&
2127 		    nsec3.iterations == iterations &&
2128 		    nsec3.salt_length == salt_len &&
2129 		    isc_safe_memequal(nsec3.salt, salt, salt_len))
2130 		{
2131 			continue;
2132 		}
2133 		dns_rdatalist_init(&rdatalist);
2134 		rdatalist.rdclass = rdata.rdclass;
2135 		rdatalist.type = rdata.type;
2136 		if (set_maxttl) {
2137 			rdatalist.ttl = ISC_MIN(rdataset.ttl, maxttl);
2138 		}
2139 		dns_rdata_init(&delrdata);
2140 		dns_rdata_clone(&rdata, &delrdata);
2141 		ISC_LIST_APPEND(rdatalist.rdata, &delrdata, link);
2142 		dns_rdatalist_tordataset(&rdatalist, &delrdataset);
2143 		result = dns_db_subtractrdataset(gdb, node, gversion,
2144 						 &delrdataset, 0, NULL);
2145 		dns_rdataset_disassociate(&delrdataset);
2146 		if (result != ISC_R_SUCCESS && result != DNS_R_NXRRSET) {
2147 			check_result(result, "dns_db_subtractrdataset(NSEC3)");
2148 		}
2149 		delete_rrsigs = true;
2150 	}
2151 	dns_rdataset_disassociate(&rdataset);
2152 	if (result != ISC_R_NOMORE) {
2153 		check_result(result, "dns_rdataset_first/next");
2154 	}
2155 
2156 	if (!delete_rrsigs) {
2157 		return;
2158 	}
2159 	/*
2160 	 * Delete the NSEC3 RRSIGs
2161 	 */
2162 	result = dns_db_deleterdataset(gdb, node, gversion, dns_rdatatype_rrsig,
2163 				       dns_rdatatype_nsec3);
2164 	if (result != ISC_R_SUCCESS && result != DNS_R_UNCHANGED) {
2165 		check_result(result, "dns_db_deleterdataset(RRSIG(NSEC3))");
2166 	}
2167 }
2168 
2169 static void
2170 rrset_cleanup(dns_name_t *name, dns_rdataset_t *rdataset, dns_diff_t *add,
2171 	      dns_diff_t *del) {
2172 	isc_result_t result;
2173 	unsigned int count1 = 0;
2174 	dns_rdataset_t tmprdataset;
2175 	char namestr[DNS_NAME_FORMATSIZE];
2176 	char typestr[DNS_RDATATYPE_FORMATSIZE];
2177 
2178 	dns_name_format(name, namestr, sizeof(namestr));
2179 	dns_rdatatype_format(rdataset->type, typestr, sizeof(typestr));
2180 
2181 	dns_rdataset_init(&tmprdataset);
2182 	for (result = dns_rdataset_first(rdataset); result == ISC_R_SUCCESS;
2183 	     result = dns_rdataset_next(rdataset))
2184 	{
2185 		dns_rdata_t rdata1 = DNS_RDATA_INIT;
2186 		unsigned int count2 = 0;
2187 
2188 		count1++;
2189 		dns_rdataset_current(rdataset, &rdata1);
2190 		dns_rdataset_clone(rdataset, &tmprdataset);
2191 		for (result = dns_rdataset_first(&tmprdataset);
2192 		     result == ISC_R_SUCCESS;
2193 		     result = dns_rdataset_next(&tmprdataset))
2194 		{
2195 			dns_rdata_t rdata2 = DNS_RDATA_INIT;
2196 			dns_difftuple_t *tuple = NULL;
2197 			count2++;
2198 			dns_rdataset_current(&tmprdataset, &rdata2);
2199 			if (count1 < count2 &&
2200 			    dns_rdata_casecompare(&rdata1, &rdata2) == 0)
2201 			{
2202 				vbprintf(2, "removing duplicate at %s/%s\n",
2203 					 namestr, typestr);
2204 				result = dns_difftuple_create(
2205 					mctx, DNS_DIFFOP_DELRESIGN, name,
2206 					rdataset->ttl, &rdata2, &tuple);
2207 				check_result(result, "dns_difftuple_create");
2208 				dns_diff_append(del, &tuple);
2209 			} else if (set_maxttl && rdataset->ttl > maxttl) {
2210 				vbprintf(2,
2211 					 "reducing ttl of %s/%s "
2212 					 "from %d to %d\n",
2213 					 namestr, typestr, rdataset->ttl,
2214 					 maxttl);
2215 				result = dns_difftuple_create(
2216 					mctx, DNS_DIFFOP_DELRESIGN, name,
2217 					rdataset->ttl, &rdata2, &tuple);
2218 				check_result(result, "dns_difftuple_create");
2219 				dns_diff_append(del, &tuple);
2220 				tuple = NULL;
2221 				result = dns_difftuple_create(
2222 					mctx, DNS_DIFFOP_ADDRESIGN, name,
2223 					maxttl, &rdata2, &tuple);
2224 				check_result(result, "dns_difftuple_create");
2225 				dns_diff_append(add, &tuple);
2226 			}
2227 		}
2228 		dns_rdataset_disassociate(&tmprdataset);
2229 	}
2230 }
2231 
2232 static void
2233 cleanup_zone(void) {
2234 	isc_result_t result;
2235 	dns_dbiterator_t *dbiter = NULL;
2236 	dns_rdatasetiter_t *rdsiter = NULL;
2237 	dns_diff_t add, del;
2238 	dns_dbnode_t *node = NULL;
2239 	dns_rdataset_t rdataset;
2240 	dns_fixedname_t fname;
2241 	dns_name_t *name;
2242 
2243 	dns_diff_init(mctx, &add);
2244 	dns_diff_init(mctx, &del);
2245 	name = dns_fixedname_initname(&fname);
2246 	dns_rdataset_init(&rdataset);
2247 
2248 	result = dns_db_createiterator(gdb, 0, &dbiter);
2249 	check_result(result, "dns_db_createiterator()");
2250 
2251 	for (result = dns_dbiterator_first(dbiter); result == ISC_R_SUCCESS;
2252 	     result = dns_dbiterator_next(dbiter))
2253 	{
2254 		result = dns_dbiterator_current(dbiter, &node, name);
2255 		check_dns_dbiterator_current(result);
2256 		result = dns_db_allrdatasets(gdb, node, gversion, 0, 0,
2257 					     &rdsiter);
2258 		check_result(result, "dns_db_allrdatasets()");
2259 		for (result = dns_rdatasetiter_first(rdsiter);
2260 		     result == ISC_R_SUCCESS;
2261 		     result = dns_rdatasetiter_next(rdsiter))
2262 		{
2263 			dns_rdatasetiter_current(rdsiter, &rdataset);
2264 			rrset_cleanup(name, &rdataset, &add, &del);
2265 			dns_rdataset_disassociate(&rdataset);
2266 		}
2267 		if (result != ISC_R_NOMORE) {
2268 			fatal("rdatasets iteration failed.");
2269 		}
2270 		dns_rdatasetiter_destroy(&rdsiter);
2271 		dns_db_detachnode(gdb, &node);
2272 	}
2273 	if (result != ISC_R_NOMORE) {
2274 		fatal("zone iteration failed.");
2275 	}
2276 
2277 	result = dns_diff_applysilently(&del, gdb, gversion);
2278 	check_result(result, "dns_diff_applysilently");
2279 
2280 	result = dns_diff_applysilently(&add, gdb, gversion);
2281 	check_result(result, "dns_diff_applysilently");
2282 
2283 	dns_diff_clear(&del);
2284 	dns_diff_clear(&add);
2285 	dns_dbiterator_destroy(&dbiter);
2286 }
2287 
2288 /*
2289  * Generate NSEC3 records for the zone.
2290  */
2291 static void
2292 nsec3ify(unsigned int hashalg, dns_iterations_t iterations,
2293 	 const unsigned char *salt, size_t salt_len, hashlist_t *hashlist) {
2294 	dns_dbiterator_t *dbiter = NULL;
2295 	dns_dbnode_t *node = NULL, *nextnode = NULL;
2296 	dns_fixedname_t fname, fnextname, fzonecut;
2297 	dns_name_t *name, *nextname, *zonecut;
2298 	dns_rdataset_t rdataset;
2299 	int order;
2300 	bool active;
2301 	bool done = false;
2302 	isc_result_t result;
2303 	uint32_t nsttl = 0;
2304 	unsigned int count, nlabels;
2305 
2306 	dns_rdataset_init(&rdataset);
2307 	name = dns_fixedname_initname(&fname);
2308 	nextname = dns_fixedname_initname(&fnextname);
2309 	zonecut = NULL;
2310 
2311 	/*
2312 	 * Walk the zone generating the hash names.
2313 	 */
2314 	result = dns_db_createiterator(gdb, DNS_DB_NONSEC3, &dbiter);
2315 	check_result(result, "dns_db_createiterator()");
2316 
2317 	result = dns_dbiterator_first(dbiter);
2318 	check_result(result, "dns_dbiterator_first()");
2319 
2320 	while (!done) {
2321 		result = dns_dbiterator_current(dbiter, &node, name);
2322 		check_dns_dbiterator_current(result);
2323 		/*
2324 		 * Skip out-of-zone records.
2325 		 */
2326 		if (!dns_name_issubdomain(name, gorigin)) {
2327 			result = dns_dbiterator_next(dbiter);
2328 			if (result == ISC_R_NOMORE) {
2329 				done = true;
2330 			} else {
2331 				check_result(result, "dns_dbiterator_next()");
2332 			}
2333 			dns_db_detachnode(gdb, &node);
2334 			continue;
2335 		}
2336 
2337 		if (dns_name_equal(name, gorigin)) {
2338 			remove_records(node, dns_rdatatype_nsec, true);
2339 			/* Clean old rrsigs at apex. */
2340 			(void)active_node(node);
2341 		}
2342 
2343 		if (has_dname(gdb, gversion, node)) {
2344 			zonecut = savezonecut(&fzonecut, name);
2345 		}
2346 
2347 		result = dns_dbiterator_next(dbiter);
2348 		nextnode = NULL;
2349 		while (result == ISC_R_SUCCESS) {
2350 			result = dns_dbiterator_current(dbiter, &nextnode,
2351 							nextname);
2352 			check_dns_dbiterator_current(result);
2353 			active = active_node(nextnode);
2354 			if (!active) {
2355 				dns_db_detachnode(gdb, &nextnode);
2356 				result = dns_dbiterator_next(dbiter);
2357 				continue;
2358 			}
2359 			if (!dns_name_issubdomain(nextname, gorigin) ||
2360 			    (zonecut != NULL &&
2361 			     dns_name_issubdomain(nextname, zonecut)))
2362 			{
2363 				remove_sigs(nextnode, false, 0);
2364 				dns_db_detachnode(gdb, &nextnode);
2365 				result = dns_dbiterator_next(dbiter);
2366 				continue;
2367 			}
2368 			if (is_delegation(gdb, gversion, gorigin, nextname,
2369 					  nextnode, &nsttl))
2370 			{
2371 				zonecut = savezonecut(&fzonecut, nextname);
2372 				remove_sigs(nextnode, true, 0);
2373 				if (generateds) {
2374 					add_ds(nextname, nextnode, nsttl);
2375 				}
2376 				if (OPTOUT(nsec3flags) &&
2377 				    !secure(nextname, nextnode))
2378 				{
2379 					dns_db_detachnode(gdb, &nextnode);
2380 					result = dns_dbiterator_next(dbiter);
2381 					continue;
2382 				}
2383 			} else if (has_dname(gdb, gversion, nextnode)) {
2384 				zonecut = savezonecut(&fzonecut, nextname);
2385 			}
2386 			dns_db_detachnode(gdb, &nextnode);
2387 			break;
2388 		}
2389 		if (result == ISC_R_NOMORE) {
2390 			dns_name_copy(gorigin, nextname);
2391 			done = true;
2392 		} else if (result != ISC_R_SUCCESS) {
2393 			fatal("iterating through the database failed: %s",
2394 			      isc_result_totext(result));
2395 		}
2396 		dns_name_downcase(name, name, NULL);
2397 		hashlist_add_dns_name(hashlist, name, hashalg, iterations, salt,
2398 				      salt_len, false);
2399 		dns_db_detachnode(gdb, &node);
2400 		/*
2401 		 * Add hashes for empty nodes.  Use closest encloser logic.
2402 		 * The closest encloser either has data or is a empty
2403 		 * node for another <name,nextname> span so we don't add
2404 		 * it here.  Empty labels on nextname are within the span.
2405 		 */
2406 		dns_name_downcase(nextname, nextname, NULL);
2407 		dns_name_fullcompare(name, nextname, &order, &nlabels);
2408 		addnowildcardhash(hashlist, name, hashalg, iterations, salt,
2409 				  salt_len);
2410 		count = dns_name_countlabels(nextname);
2411 		while (count > nlabels + 1) {
2412 			count--;
2413 			dns_name_split(nextname, count, NULL, nextname);
2414 			hashlist_add_dns_name(hashlist, nextname, hashalg,
2415 					      iterations, salt, salt_len,
2416 					      false);
2417 			addnowildcardhash(hashlist, nextname, hashalg,
2418 					  iterations, salt, salt_len);
2419 		}
2420 	}
2421 	dns_dbiterator_destroy(&dbiter);
2422 
2423 	/*
2424 	 * We have all the hashes now so we can sort them.
2425 	 */
2426 	hashlist_sort(hashlist);
2427 
2428 	/*
2429 	 * Check for duplicate hashes.  If found the salt needs to
2430 	 * be changed.
2431 	 */
2432 	if (hashlist_hasdup(hashlist)) {
2433 		fatal("Duplicate hash detected. Pick a different salt.");
2434 	}
2435 
2436 	/*
2437 	 * Generate the nsec3 records.
2438 	 */
2439 	zonecut = NULL;
2440 	done = false;
2441 
2442 	addnsec3param(salt, salt_len, iterations);
2443 
2444 	/*
2445 	 * Clean out NSEC3 records which don't match this chain.
2446 	 */
2447 	result = dns_db_createiterator(gdb, DNS_DB_NSEC3ONLY, &dbiter);
2448 	check_result(result, "dns_db_createiterator()");
2449 
2450 	for (result = dns_dbiterator_first(dbiter); result == ISC_R_SUCCESS;
2451 	     result = dns_dbiterator_next(dbiter))
2452 	{
2453 		result = dns_dbiterator_current(dbiter, &node, name);
2454 		check_dns_dbiterator_current(result);
2455 		nsec3clean(name, node, hashalg, iterations, salt, salt_len,
2456 			   hashlist);
2457 		dns_db_detachnode(gdb, &node);
2458 	}
2459 	dns_dbiterator_destroy(&dbiter);
2460 
2461 	/*
2462 	 * Generate / complete the new chain.
2463 	 */
2464 	result = dns_db_createiterator(gdb, DNS_DB_NONSEC3, &dbiter);
2465 	check_result(result, "dns_db_createiterator()");
2466 
2467 	result = dns_dbiterator_first(dbiter);
2468 	check_result(result, "dns_dbiterator_first()");
2469 
2470 	while (!done) {
2471 		result = dns_dbiterator_current(dbiter, &node, name);
2472 		check_dns_dbiterator_current(result);
2473 		/*
2474 		 * Skip out-of-zone records.
2475 		 */
2476 		if (!dns_name_issubdomain(name, gorigin)) {
2477 			result = dns_dbiterator_next(dbiter);
2478 			if (result == ISC_R_NOMORE) {
2479 				done = true;
2480 			} else {
2481 				check_result(result, "dns_dbiterator_next()");
2482 			}
2483 			dns_db_detachnode(gdb, &node);
2484 			continue;
2485 		}
2486 
2487 		if (has_dname(gdb, gversion, node)) {
2488 			zonecut = savezonecut(&fzonecut, name);
2489 		}
2490 
2491 		result = dns_dbiterator_next(dbiter);
2492 		nextnode = NULL;
2493 		while (result == ISC_R_SUCCESS) {
2494 			result = dns_dbiterator_current(dbiter, &nextnode,
2495 							nextname);
2496 			check_dns_dbiterator_current(result);
2497 			active = active_node(nextnode);
2498 			if (!active) {
2499 				dns_db_detachnode(gdb, &nextnode);
2500 				result = dns_dbiterator_next(dbiter);
2501 				continue;
2502 			}
2503 			if (!dns_name_issubdomain(nextname, gorigin) ||
2504 			    (zonecut != NULL &&
2505 			     dns_name_issubdomain(nextname, zonecut)))
2506 			{
2507 				dns_db_detachnode(gdb, &nextnode);
2508 				result = dns_dbiterator_next(dbiter);
2509 				continue;
2510 			}
2511 			if (is_delegation(gdb, gversion, gorigin, nextname,
2512 					  nextnode, NULL))
2513 			{
2514 				zonecut = savezonecut(&fzonecut, nextname);
2515 				if (OPTOUT(nsec3flags) &&
2516 				    !secure(nextname, nextnode))
2517 				{
2518 					dns_db_detachnode(gdb, &nextnode);
2519 					result = dns_dbiterator_next(dbiter);
2520 					continue;
2521 				}
2522 			} else if (has_dname(gdb, gversion, nextnode)) {
2523 				zonecut = savezonecut(&fzonecut, nextname);
2524 			}
2525 			dns_db_detachnode(gdb, &nextnode);
2526 			break;
2527 		}
2528 		if (result == ISC_R_NOMORE) {
2529 			dns_name_copy(gorigin, nextname);
2530 			done = true;
2531 		} else if (result != ISC_R_SUCCESS) {
2532 			fatal("iterating through the database failed: %s",
2533 			      isc_result_totext(result));
2534 		}
2535 		/*
2536 		 * We need to pause here to release the lock on the database.
2537 		 */
2538 		dns_dbiterator_pause(dbiter);
2539 		addnsec3(name, node, salt, salt_len, iterations, hashlist,
2540 			 zone_soa_min_ttl);
2541 		dns_db_detachnode(gdb, &node);
2542 		/*
2543 		 * Add NSEC3's for empty nodes.  Use closest encloser logic.
2544 		 */
2545 		dns_name_fullcompare(name, nextname, &order, &nlabels);
2546 		count = dns_name_countlabels(nextname);
2547 		while (count > nlabels + 1) {
2548 			count--;
2549 			dns_name_split(nextname, count, NULL, nextname);
2550 			addnsec3(nextname, NULL, salt, salt_len, iterations,
2551 				 hashlist, zone_soa_min_ttl);
2552 		}
2553 	}
2554 	dns_dbiterator_destroy(&dbiter);
2555 }
2556 
2557 /*%
2558  * Load the zone file from disk
2559  */
2560 static void
2561 loadzone(char *file, char *origin, dns_rdataclass_t rdclass, dns_db_t **db) {
2562 	isc_buffer_t b;
2563 	int len;
2564 	dns_fixedname_t fname;
2565 	dns_name_t *name;
2566 	isc_result_t result;
2567 
2568 	len = strlen(origin);
2569 	isc_buffer_init(&b, origin, len);
2570 	isc_buffer_add(&b, len);
2571 
2572 	name = dns_fixedname_initname(&fname);
2573 	result = dns_name_fromtext(name, &b, dns_rootname, 0, NULL);
2574 	if (result != ISC_R_SUCCESS) {
2575 		fatal("failed converting name '%s' to dns format: %s", origin,
2576 		      isc_result_totext(result));
2577 	}
2578 
2579 	result = dns_db_create(mctx, ZONEDB_DEFAULT, name, dns_dbtype_zone,
2580 			       rdclass, 0, NULL, db);
2581 	check_result(result, "dns_db_create()");
2582 
2583 	result = dns_db_load(*db, file, inputformat, 0);
2584 	if (result != ISC_R_SUCCESS && result != DNS_R_SEENINCLUDE) {
2585 		fatal("failed loading zone from '%s': %s", file,
2586 		      isc_result_totext(result));
2587 	}
2588 }
2589 
2590 /*%
2591  * Finds all public zone keys in the zone, and attempts to load the
2592  * private keys from disk.
2593  */
2594 static void
2595 loadzonekeys(bool preserve_keys, bool load_public) {
2596 	dns_dbnode_t *node;
2597 	dns_dbversion_t *currentversion = NULL;
2598 	isc_result_t result;
2599 	dns_rdataset_t rdataset, keysigs, soasigs;
2600 
2601 	node = NULL;
2602 	result = dns_db_findnode(gdb, gorigin, false, &node);
2603 	if (result != ISC_R_SUCCESS) {
2604 		fatal("failed to find the zone's origin: %s",
2605 		      isc_result_totext(result));
2606 	}
2607 
2608 	dns_db_currentversion(gdb, &currentversion);
2609 
2610 	dns_rdataset_init(&rdataset);
2611 	dns_rdataset_init(&soasigs);
2612 	dns_rdataset_init(&keysigs);
2613 
2614 	/* Make note of the keys which signed the SOA, if any */
2615 	result = dns_db_findrdataset(gdb, node, currentversion,
2616 				     dns_rdatatype_soa, 0, 0, &rdataset,
2617 				     &soasigs);
2618 	if (result != ISC_R_SUCCESS) {
2619 		goto cleanup;
2620 	}
2621 
2622 	/* Preserve the TTL of the DNSKEY RRset, if any */
2623 	dns_rdataset_disassociate(&rdataset);
2624 	result = dns_db_findrdataset(gdb, node, currentversion,
2625 				     dns_rdatatype_dnskey, 0, 0, &rdataset,
2626 				     &keysigs);
2627 
2628 	if (result != ISC_R_SUCCESS) {
2629 		goto cleanup;
2630 	}
2631 
2632 	if (set_keyttl && keyttl != rdataset.ttl) {
2633 		fprintf(stderr,
2634 			"User-specified TTL %u conflicts "
2635 			"with existing DNSKEY RRset TTL.\n",
2636 			keyttl);
2637 		fprintf(stderr,
2638 			"Imported keys will use the RRSet "
2639 			"TTL %u instead.\n",
2640 			rdataset.ttl);
2641 	}
2642 	keyttl = rdataset.ttl;
2643 
2644 	/* Load keys corresponding to the existing DNSKEY RRset. */
2645 	result = dns_dnssec_keylistfromrdataset(
2646 		gorigin, NULL, directory, mctx, &rdataset, &keysigs, &soasigs,
2647 		preserve_keys, load_public, &keylist);
2648 	if (result != ISC_R_SUCCESS) {
2649 		fatal("failed to load the zone keys: %s",
2650 		      isc_result_totext(result));
2651 	}
2652 
2653 cleanup:
2654 	if (dns_rdataset_isassociated(&rdataset)) {
2655 		dns_rdataset_disassociate(&rdataset);
2656 	}
2657 	if (dns_rdataset_isassociated(&keysigs)) {
2658 		dns_rdataset_disassociate(&keysigs);
2659 	}
2660 	if (dns_rdataset_isassociated(&soasigs)) {
2661 		dns_rdataset_disassociate(&soasigs);
2662 	}
2663 	dns_db_detachnode(gdb, &node);
2664 	dns_db_closeversion(gdb, &currentversion, false);
2665 }
2666 
2667 static void
2668 loadexplicitkeys(char *keyfiles[], int n, bool setksk) {
2669 	isc_result_t result;
2670 	int i;
2671 
2672 	for (i = 0; i < n; i++) {
2673 		dns_dnsseckey_t *key = NULL;
2674 		dst_key_t *newkey = NULL;
2675 
2676 		result = dst_key_fromnamedfile(
2677 			keyfiles[i], directory,
2678 			DST_TYPE_PUBLIC | DST_TYPE_PRIVATE, mctx, &newkey);
2679 		if (result != ISC_R_SUCCESS) {
2680 			fatal("cannot load dnskey %s: %s", keyfiles[i],
2681 			      isc_result_totext(result));
2682 		}
2683 
2684 		if (!dns_name_equal(gorigin, dst_key_name(newkey))) {
2685 			fatal("key %s not at origin\n", keyfiles[i]);
2686 		}
2687 
2688 		if (!dst_key_isprivate(newkey)) {
2689 			fatal("cannot sign zone with non-private dnskey %s",
2690 			      keyfiles[i]);
2691 		}
2692 
2693 		/* Skip any duplicates */
2694 		for (key = ISC_LIST_HEAD(keylist); key != NULL;
2695 		     key = ISC_LIST_NEXT(key, link))
2696 		{
2697 			if (dst_key_id(key->key) == dst_key_id(newkey) &&
2698 			    dst_key_alg(key->key) == dst_key_alg(newkey))
2699 			{
2700 				break;
2701 			}
2702 		}
2703 
2704 		if (key == NULL) {
2705 			/* We haven't seen this key before */
2706 			dns_dnsseckey_create(mctx, &newkey, &key);
2707 			ISC_LIST_APPEND(keylist, key, link);
2708 			key->source = dns_keysource_user;
2709 		} else {
2710 			dst_key_free(&key->key);
2711 			key->key = newkey;
2712 		}
2713 
2714 		key->force_publish = true;
2715 		key->force_sign = true;
2716 
2717 		if (setksk) {
2718 			key->ksk = true;
2719 		}
2720 	}
2721 }
2722 
2723 static void
2724 report(const char *format, ...) {
2725 	if (!quiet) {
2726 		FILE *out = output_stdout ? stderr : stdout;
2727 		char buf[4096];
2728 		va_list args;
2729 
2730 		va_start(args, format);
2731 		vsnprintf(buf, sizeof(buf), format, args);
2732 		va_end(args);
2733 		fprintf(out, "%s\n", buf);
2734 	}
2735 }
2736 
2737 static void
2738 clear_keylist(dns_dnsseckeylist_t *list) {
2739 	dns_dnsseckey_t *key;
2740 	while (!ISC_LIST_EMPTY(*list)) {
2741 		key = ISC_LIST_HEAD(*list);
2742 		ISC_LIST_UNLINK(*list, key, link);
2743 		dns_dnsseckey_destroy(mctx, &key);
2744 	}
2745 }
2746 
2747 static void
2748 add_digest(char *str, size_t dlen, dns_kasp_digestlist_t *digests,
2749 	   bool *cdnskey) {
2750 	isc_result_t result;
2751 	isc_textregion_t r;
2752 	dns_dsdigest_t alg;
2753 	dns_kasp_digest_t *digest;
2754 
2755 	if (dlen == 7 && strncmp(str, "cdnskey", dlen) == 0) {
2756 		*cdnskey = true;
2757 		return;
2758 	}
2759 
2760 	if (dlen < 5 || strncmp(str, "cds:", 4) != 0) {
2761 		fatal("digest must specify cds:algorithm ('%.*s')", (int)dlen,
2762 		      str);
2763 	}
2764 
2765 	r.base = str + 4;
2766 	r.length = dlen - 4;
2767 	result = dns_dsdigest_fromtext(&alg, &r);
2768 	if (result == DNS_R_UNKNOWN) {
2769 		fatal("bad digest '%.*s'", (int)dlen, str);
2770 	} else if (result != ISC_R_SUCCESS) {
2771 		fatal("bad digest '%.*s': %s", (int)dlen, str,
2772 		      isc_result_totext(result));
2773 	} else if (!dst_ds_digest_supported(alg)) {
2774 		fatal("unsupported digest '%.*s'", (int)dlen, str);
2775 	}
2776 
2777 	/* Suppress duplicates */
2778 	for (dns_kasp_digest_t *d = ISC_LIST_HEAD(*digests); d != NULL;
2779 	     d = ISC_LIST_NEXT(d, link))
2780 	{
2781 		if (d->digest == alg) {
2782 			return;
2783 		}
2784 	}
2785 
2786 	digest = isc_mem_get(mctx, sizeof(*digest));
2787 	digest->digest = alg;
2788 	ISC_LINK_INIT(digest, link);
2789 	ISC_LIST_APPEND(*digests, digest, link);
2790 }
2791 
2792 static void
2793 build_final_keylist(void) {
2794 	isc_result_t result;
2795 	dns_dbnode_t *node = NULL;
2796 	dns_dbversion_t *ver = NULL;
2797 	dns_diff_t diff;
2798 	dns_dnsseckeylist_t rmkeys, matchkeys;
2799 	char name[DNS_NAME_FORMATSIZE];
2800 	dns_rdataset_t cdsset, cdnskeyset, soaset;
2801 	dns_kasp_digestlist_t digests;
2802 	dns_kasp_digest_t *d, *d_next;
2803 	bool cdnskey = false;
2804 
2805 	ISC_LIST_INIT(rmkeys);
2806 	ISC_LIST_INIT(matchkeys);
2807 	ISC_LIST_INIT(digests);
2808 
2809 	dns_rdataset_init(&soaset);
2810 	dns_rdataset_init(&cdsset);
2811 	dns_rdataset_init(&cdnskeyset);
2812 
2813 	if (strlen(sync_records) > 0) {
2814 		const char delim = ',';
2815 		char *digest;
2816 		char *s;
2817 		size_t dlen;
2818 
2819 		digest = UNCONST(sync_records);
2820 	next_digest:
2821 		s = strchr(digest, delim);
2822 		if (s == NULL) {
2823 			dlen = strlen(digest);
2824 			add_digest(digest, dlen, &digests, &cdnskey);
2825 			goto findkeys;
2826 		}
2827 		dlen = s - digest;
2828 		add_digest(digest, dlen, &digests, &cdnskey);
2829 		digest = s + 1;
2830 		goto next_digest;
2831 	}
2832 
2833 findkeys:
2834 	/*
2835 	 * Find keys that match this zone in the key repository.
2836 	 */
2837 	result = dns_dnssec_findmatchingkeys(gorigin, NULL, directory, NULL,
2838 					     now, mctx, &matchkeys);
2839 	if (result == ISC_R_NOTFOUND) {
2840 		result = ISC_R_SUCCESS;
2841 	}
2842 	check_result(result, "dns_dnssec_findmatchingkeys");
2843 
2844 	result = dns_db_newversion(gdb, &ver);
2845 	check_result(result, "dns_db_newversion");
2846 
2847 	result = dns_db_getoriginnode(gdb, &node);
2848 	check_result(result, "dns_db_getoriginnode");
2849 
2850 	/* Get the CDS rdataset */
2851 	result = dns_db_findrdataset(gdb, node, ver, dns_rdatatype_cds,
2852 				     dns_rdatatype_none, 0, &cdsset, NULL);
2853 	if (result != ISC_R_SUCCESS && dns_rdataset_isassociated(&cdsset)) {
2854 		dns_rdataset_disassociate(&cdsset);
2855 	}
2856 
2857 	/* Get the CDNSKEY rdataset */
2858 	result = dns_db_findrdataset(gdb, node, ver, dns_rdatatype_cdnskey,
2859 				     dns_rdatatype_none, 0, &cdnskeyset, NULL);
2860 	if (result != ISC_R_SUCCESS && dns_rdataset_isassociated(&cdnskeyset)) {
2861 		dns_rdataset_disassociate(&cdnskeyset);
2862 	}
2863 
2864 	dns_diff_init(mctx, &diff);
2865 
2866 	/*
2867 	 * Update keylist with information from from the key repository.
2868 	 */
2869 	dns_dnssec_updatekeys(&keylist, &matchkeys, NULL, gorigin, keyttl,
2870 			      &diff, mctx, report);
2871 
2872 	/*
2873 	 * Update keylist with sync records.
2874 	 */
2875 
2876 	dns_dnssec_syncupdate(&keylist, &rmkeys, &cdsset, &cdnskeyset, now,
2877 			      &digests, cdnskey, keyttl, &diff, mctx);
2878 
2879 	dns_name_format(gorigin, name, sizeof(name));
2880 
2881 	result = dns_diff_applysilently(&diff, gdb, ver);
2882 	if (result != ISC_R_SUCCESS) {
2883 		fatal("failed to update DNSKEY RRset at node '%s': %s", name,
2884 		      isc_result_totext(result));
2885 	}
2886 
2887 	dns_db_detachnode(gdb, &node);
2888 	dns_db_closeversion(gdb, &ver, true);
2889 
2890 	dns_diff_clear(&diff);
2891 
2892 	if (dns_rdataset_isassociated(&cdsset)) {
2893 		dns_rdataset_disassociate(&cdsset);
2894 	}
2895 	if (dns_rdataset_isassociated(&cdnskeyset)) {
2896 		dns_rdataset_disassociate(&cdnskeyset);
2897 	}
2898 
2899 	clear_keylist(&rmkeys);
2900 	clear_keylist(&matchkeys);
2901 
2902 	for (d = ISC_LIST_HEAD(digests); d != NULL; d = d_next) {
2903 		d_next = ISC_LIST_NEXT(d, link);
2904 		ISC_LIST_UNLINK(digests, d, link);
2905 		isc_mem_put(mctx, d, sizeof(*d));
2906 	}
2907 	INSIST(ISC_LIST_EMPTY(digests));
2908 }
2909 
2910 static void
2911 warnifallksk(dns_db_t *db) {
2912 	dns_dbversion_t *currentversion = NULL;
2913 	dns_dbnode_t *node = NULL;
2914 	dns_rdataset_t rdataset;
2915 	dns_rdata_t rdata = DNS_RDATA_INIT;
2916 	isc_result_t result;
2917 	dns_rdata_dnskey_t dnskey;
2918 	bool have_non_ksk = false;
2919 
2920 	dns_db_currentversion(db, &currentversion);
2921 
2922 	result = dns_db_findnode(db, gorigin, false, &node);
2923 	if (result != ISC_R_SUCCESS) {
2924 		fatal("failed to find the zone's origin: %s",
2925 		      isc_result_totext(result));
2926 	}
2927 
2928 	dns_rdataset_init(&rdataset);
2929 	result = dns_db_findrdataset(db, node, currentversion,
2930 				     dns_rdatatype_dnskey, 0, 0, &rdataset,
2931 				     NULL);
2932 	if (result != ISC_R_SUCCESS) {
2933 		fatal("failed to find keys at the zone apex: %s",
2934 		      isc_result_totext(result));
2935 	}
2936 	result = dns_rdataset_first(&rdataset);
2937 	check_result(result, "dns_rdataset_first");
2938 	while (result == ISC_R_SUCCESS) {
2939 		dns_rdata_reset(&rdata);
2940 		dns_rdataset_current(&rdataset, &rdata);
2941 		result = dns_rdata_tostruct(&rdata, &dnskey, NULL);
2942 		check_result(result, "dns_rdata_tostruct");
2943 		if ((dnskey.flags & DNS_KEYFLAG_KSK) == 0) {
2944 			have_non_ksk = true;
2945 			result = ISC_R_NOMORE;
2946 		} else {
2947 			result = dns_rdataset_next(&rdataset);
2948 		}
2949 		dns_rdata_freestruct(&dnskey);
2950 	}
2951 	dns_rdataset_disassociate(&rdataset);
2952 	dns_db_detachnode(db, &node);
2953 	dns_db_closeversion(db, &currentversion, false);
2954 	if (!have_non_ksk && !ignore_kskflag) {
2955 		if (disable_zone_check) {
2956 			fprintf(stderr,
2957 				"%s: warning: No non-KSK DNSKEY found; "
2958 				"supply a ZSK or use '-z'.\n",
2959 				program);
2960 		} else {
2961 			fatal("No non-KSK DNSKEY found; "
2962 			      "supply a ZSK or use '-z'.");
2963 		}
2964 	}
2965 }
2966 
2967 static void
2968 set_nsec3params(bool update, bool set_salt, bool set_optout, bool set_iter) {
2969 	isc_result_t result;
2970 	dns_dbversion_t *ver = NULL;
2971 	dns_dbnode_t *node = NULL;
2972 	dns_rdataset_t rdataset;
2973 	dns_rdata_t rdata = DNS_RDATA_INIT;
2974 	dns_rdata_nsec3_t nsec3;
2975 	dns_fixedname_t fname;
2976 	dns_name_t *hashname;
2977 	unsigned char orig_salt[255];
2978 	size_t orig_saltlen;
2979 	dns_hash_t orig_hash;
2980 	uint16_t orig_iter;
2981 
2982 	dns_db_currentversion(gdb, &ver);
2983 	dns_rdataset_init(&rdataset);
2984 
2985 	orig_saltlen = sizeof(orig_salt);
2986 	result = dns_db_getnsec3parameters(gdb, ver, &orig_hash, NULL,
2987 					   &orig_iter, orig_salt,
2988 					   &orig_saltlen);
2989 	if (result != ISC_R_SUCCESS) {
2990 		goto cleanup;
2991 	}
2992 
2993 	nsec_datatype = dns_rdatatype_nsec3;
2994 
2995 	if (!update && set_salt) {
2996 		if (salt_length != orig_saltlen ||
2997 		    !isc_safe_memequal(saltbuf, orig_salt, salt_length))
2998 		{
2999 			fatal("An NSEC3 chain exists with a different salt. "
3000 			      "Use -u to update it.");
3001 		}
3002 	} else if (!set_salt) {
3003 		salt_length = orig_saltlen;
3004 		memmove(saltbuf, orig_salt, orig_saltlen);
3005 		gsalt = saltbuf;
3006 	}
3007 
3008 	if (!update && set_iter) {
3009 		if (nsec3iter != orig_iter) {
3010 			fatal("An NSEC3 chain exists with different "
3011 			      "iterations. Use -u to update it.");
3012 		}
3013 	} else if (!set_iter) {
3014 		nsec3iter = orig_iter;
3015 	}
3016 
3017 	/*
3018 	 * Find an NSEC3 record to get the current OPTOUT value.
3019 	 * (This assumes all NSEC3 records agree.)
3020 	 */
3021 
3022 	hashname = dns_fixedname_initname(&fname);
3023 	result = dns_nsec3_hashname(&fname, NULL, NULL, gorigin, gorigin,
3024 				    dns_hash_sha1, orig_iter, orig_salt,
3025 				    orig_saltlen);
3026 	check_result(result, "dns_nsec3_hashname");
3027 
3028 	result = dns_db_findnsec3node(gdb, hashname, false, &node);
3029 	if (result != ISC_R_SUCCESS) {
3030 		goto cleanup;
3031 	}
3032 
3033 	result = dns_db_findrdataset(gdb, node, ver, dns_rdatatype_nsec3, 0, 0,
3034 				     &rdataset, NULL);
3035 	if (result != ISC_R_SUCCESS) {
3036 		goto cleanup;
3037 	}
3038 
3039 	result = dns_rdataset_first(&rdataset);
3040 	check_result(result, "dns_rdataset_first");
3041 	dns_rdataset_current(&rdataset, &rdata);
3042 	result = dns_rdata_tostruct(&rdata, &nsec3, NULL);
3043 	check_result(result, "dns_rdata_tostruct");
3044 
3045 	if (!update && set_optout) {
3046 		if (nsec3flags != nsec3.flags) {
3047 			fatal("An NSEC3 chain exists with%s OPTOUT. "
3048 			      "Use -u -%s to %s it.",
3049 			      OPTOUT(nsec3.flags) ? "" : "out",
3050 			      OPTOUT(nsec3.flags) ? "AA" : "A",
3051 			      OPTOUT(nsec3.flags) ? "clear" : "set");
3052 		}
3053 	} else if (!set_optout) {
3054 		nsec3flags = nsec3.flags;
3055 	}
3056 
3057 	dns_rdata_freestruct(&nsec3);
3058 
3059 cleanup:
3060 	if (dns_rdataset_isassociated(&rdataset)) {
3061 		dns_rdataset_disassociate(&rdataset);
3062 	}
3063 	if (node != NULL) {
3064 		dns_db_detachnode(gdb, &node);
3065 	}
3066 	dns_db_closeversion(gdb, &ver, false);
3067 }
3068 
3069 static void
3070 writeset(const char *prefix, dns_rdatatype_t type) {
3071 	char *filename;
3072 	char namestr[DNS_NAME_FORMATSIZE];
3073 	dns_db_t *db = NULL;
3074 	dns_dbversion_t *dbversion = NULL;
3075 	dns_diff_t diff;
3076 	dns_difftuple_t *tuple = NULL;
3077 	dns_name_t *name;
3078 	dns_rdata_t rdata, ds;
3079 	bool have_ksk = false;
3080 	bool have_non_ksk = false;
3081 	isc_buffer_t b;
3082 	isc_buffer_t namebuf;
3083 	isc_region_t r;
3084 	isc_result_t result;
3085 	dns_dnsseckey_t *key, *curr;
3086 	unsigned char dsbuf[DNS_DS_BUFFERSIZE];
3087 	unsigned char keybuf[DST_KEY_MAXSIZE];
3088 	unsigned int filenamelen;
3089 	const dns_master_style_t *style = (type == dns_rdatatype_dnskey)
3090 						  ? masterstyle
3091 						  : dsstyle;
3092 
3093 	isc_buffer_init(&namebuf, namestr, sizeof(namestr));
3094 	result = dns_name_tofilenametext(gorigin, false, &namebuf);
3095 	check_result(result, "dns_name_tofilenametext");
3096 	isc_buffer_putuint8(&namebuf, 0);
3097 	filenamelen = strlen(prefix) + strlen(namestr) + 1;
3098 	if (dsdir != NULL) {
3099 		filenamelen += strlen(dsdir) + 1;
3100 	}
3101 	filename = isc_mem_get(mctx, filenamelen);
3102 	if (dsdir != NULL) {
3103 		snprintf(filename, filenamelen, "%s/", dsdir);
3104 	} else {
3105 		filename[0] = 0;
3106 	}
3107 	strlcat(filename, prefix, filenamelen);
3108 	strlcat(filename, namestr, filenamelen);
3109 
3110 	dns_diff_init(mctx, &diff);
3111 
3112 	name = gorigin;
3113 
3114 	for (key = ISC_LIST_HEAD(keylist); key != NULL;
3115 	     key = ISC_LIST_NEXT(key, link))
3116 	{
3117 		if (REVOKE(key->key)) {
3118 			continue;
3119 		}
3120 		if (isksk(key)) {
3121 			have_ksk = true;
3122 			have_non_ksk = false;
3123 		} else {
3124 			have_ksk = false;
3125 			have_non_ksk = true;
3126 		}
3127 		for (curr = ISC_LIST_HEAD(keylist); curr != NULL;
3128 		     curr = ISC_LIST_NEXT(curr, link))
3129 		{
3130 			if (dst_key_alg(key->key) != dst_key_alg(curr->key)) {
3131 				continue;
3132 			}
3133 			if (REVOKE(curr->key)) {
3134 				continue;
3135 			}
3136 			if (isksk(curr)) {
3137 				have_ksk = true;
3138 			} else {
3139 				have_non_ksk = true;
3140 			}
3141 		}
3142 		if (have_ksk && have_non_ksk && !isksk(key)) {
3143 			continue;
3144 		}
3145 		dns_rdata_init(&rdata);
3146 		dns_rdata_init(&ds);
3147 		isc_buffer_init(&b, keybuf, sizeof(keybuf));
3148 		result = dst_key_todns(key->key, &b);
3149 		check_result(result, "dst_key_todns");
3150 		isc_buffer_usedregion(&b, &r);
3151 		dns_rdata_fromregion(&rdata, gclass, dns_rdatatype_dnskey, &r);
3152 		if (type != dns_rdatatype_dnskey) {
3153 			result = dns_ds_buildrdata(gorigin, &rdata,
3154 						   DNS_DSDIGEST_SHA256, dsbuf,
3155 						   &ds);
3156 			check_result(result, "dns_ds_buildrdata");
3157 			result = dns_difftuple_create(mctx,
3158 						      DNS_DIFFOP_ADDRESIGN,
3159 						      name, 0, &ds, &tuple);
3160 		} else {
3161 			result = dns_difftuple_create(
3162 				mctx, DNS_DIFFOP_ADDRESIGN, gorigin,
3163 				zone_soa_min_ttl, &rdata, &tuple);
3164 		}
3165 		check_result(result, "dns_difftuple_create");
3166 		dns_diff_append(&diff, &tuple);
3167 	}
3168 
3169 	result = dns_db_create(mctx, ZONEDB_DEFAULT, dns_rootname,
3170 			       dns_dbtype_zone, gclass, 0, NULL, &db);
3171 	check_result(result, "dns_db_create");
3172 
3173 	result = dns_db_newversion(db, &dbversion);
3174 	check_result(result, "dns_db_newversion");
3175 
3176 	result = dns_diff_apply(&diff, db, dbversion);
3177 	check_result(result, "dns_diff_apply");
3178 	dns_diff_clear(&diff);
3179 
3180 	result = dns_master_dump(mctx, db, dbversion, style, filename,
3181 				 dns_masterformat_text, NULL);
3182 	check_result(result, "dns_master_dump");
3183 
3184 	isc_mem_put(mctx, filename, filenamelen);
3185 
3186 	dns_db_closeversion(db, &dbversion, false);
3187 	dns_db_detach(&db);
3188 }
3189 
3190 static void
3191 print_time(FILE *fp) {
3192 	time_t currenttime = time(NULL);
3193 	struct tm t, *tm = localtime_r(&currenttime, &t);
3194 	unsigned int flen;
3195 	char timebuf[80];
3196 
3197 	if (tm == NULL || outputformat != dns_masterformat_text) {
3198 		return;
3199 	}
3200 
3201 	flen = strftime(timebuf, sizeof(timebuf), "%a %b %e %H:%M:%S %Y", tm);
3202 	INSIST(flen > 0U && flen < sizeof(timebuf));
3203 	fprintf(fp, "; File written on %s\n", timebuf);
3204 }
3205 
3206 static void
3207 print_version(FILE *fp) {
3208 	if (outputformat != dns_masterformat_text) {
3209 		return;
3210 	}
3211 
3212 	fprintf(fp, "; %s version %s\n", program, PACKAGE_VERSION);
3213 }
3214 
3215 noreturn static void
3216 usage(void);
3217 
3218 static void
3219 usage(void) {
3220 	fprintf(stderr, "Usage:\n");
3221 	fprintf(stderr, "\t%s [options] zonefile [keys]\n", program);
3222 
3223 	fprintf(stderr, "\n");
3224 
3225 	fprintf(stderr, "Version: %s\n", PACKAGE_VERSION);
3226 
3227 	fprintf(stderr, "Options: (default value in parenthesis) \n");
3228 	fprintf(stderr, "\t-S:\tsmart signing: automatically finds key files\n"
3229 			"\t\tfor the zone and determines how they are to "
3230 			"be used\n");
3231 	fprintf(stderr, "\t-K directory:\n");
3232 	fprintf(stderr, "\t\tdirectory to find key files (.)\n");
3233 	fprintf(stderr, "\t-d directory:\n");
3234 	fprintf(stderr, "\t\tdirectory to find dsset-* files (.)\n");
3235 	fprintf(stderr, "\t-F:\tFIPS mode\n");
3236 	fprintf(stderr, "\t-g:\t");
3237 	fprintf(stderr, "update DS records based on child zones' "
3238 			"dsset-* files\n");
3239 	fprintf(stderr, "\t-G sync-records:\t");
3240 	fprintf(stderr, "what CDNSKEY and CDS to publish\n");
3241 	fprintf(stderr, "\t-s [YYYYMMDDHHMMSS|+offset]:\n");
3242 	fprintf(stderr, "\t\tRRSIG start time "
3243 			"- absolute|offset (now - 1 hour)\n");
3244 	fprintf(stderr, "\t-e [YYYYMMDDHHMMSS|+offset|\"now\"+offset]:\n");
3245 	fprintf(stderr, "\t\tRRSIG end time "
3246 			"- absolute|from start|from now "
3247 			"(now + 30 days)\n");
3248 	fprintf(stderr, "\t-X [YYYYMMDDHHMMSS|+offset|\"now\"+offset]:\n");
3249 	fprintf(stderr, "\t\tDNSKEY RRSIG end "
3250 			"- absolute|from start|from now "
3251 			"(matches -e)\n");
3252 	fprintf(stderr, "\t-i interval:\n");
3253 	fprintf(stderr, "\t\tcycle interval - resign "
3254 			"if < interval from end ( (end-start)/4 )\n");
3255 	fprintf(stderr, "\t-j jitter:\n");
3256 	fprintf(stderr, "\t\trandomize signature end time up to jitter "
3257 			"seconds\n");
3258 	fprintf(stderr, "\t-v debuglevel (0)\n");
3259 	fprintf(stderr, "\t-q quiet\n");
3260 	fprintf(stderr, "\t-V:\tprint version information\n");
3261 	fprintf(stderr, "\t-o origin:\n");
3262 	fprintf(stderr, "\t\tzone origin (name of zonefile)\n");
3263 	fprintf(stderr, "\t-f outfile:\n");
3264 	fprintf(stderr, "\t\tfile the signed zone is written in "
3265 			"(zonefile + .signed)\n");
3266 	fprintf(stderr, "\t-I format:\n");
3267 	fprintf(stderr, "\t\tfile format of input zonefile (text)\n");
3268 	fprintf(stderr, "\t-O format:\n");
3269 	fprintf(stderr, "\t\tfile format of signed zone file (text)\n");
3270 	fprintf(stderr, "\t-N format:\n");
3271 	fprintf(stderr, "\t\tsoa serial format of signed zone file (keep)\n");
3272 	fprintf(stderr, "\t-D:\n");
3273 	fprintf(stderr, "\t\toutput only DNSSEC-related records\n");
3274 	fprintf(stderr, "\t-a:\t");
3275 	fprintf(stderr, "verify generated signatures\n");
3276 	fprintf(stderr, "\t-c class (IN)\n");
3277 	fprintf(stderr, "\t-E engine:\n");
3278 	fprintf(stderr, "\t\tname of an OpenSSL engine to use\n");
3279 	fprintf(stderr, "\t-P:\t");
3280 	fprintf(stderr, "disable post-sign verification\n");
3281 	fprintf(stderr, "\t-Q:\t");
3282 	fprintf(stderr, "remove signatures from keys that are no "
3283 			"longer active\n");
3284 	fprintf(stderr, "\t-R:\t");
3285 	fprintf(stderr, "remove signatures from keys that no longer exist\n");
3286 	fprintf(stderr, "\t-T TTL:\tTTL for newly added DNSKEYs\n");
3287 	fprintf(stderr, "\t-t:\t");
3288 	fprintf(stderr, "print statistics\n");
3289 	fprintf(stderr, "\t-u:\t");
3290 	fprintf(stderr, "update or replace an existing NSEC/NSEC3 chain\n");
3291 	fprintf(stderr, "\t-x:\tsign DNSKEY record with KSKs only, not ZSKs\n");
3292 	fprintf(stderr, "\t-z:\tsign all records with KSKs\n");
3293 	fprintf(stderr, "\t-C:\tgenerate a keyset file, for compatibility\n"
3294 			"\t\twith older versions of dnssec-signzone -g\n");
3295 	fprintf(stderr, "\t-n ncpus (number of cpus present)\n");
3296 	fprintf(stderr, "\t-k key_signing_key\n");
3297 	fprintf(stderr, "\t-3 NSEC3 salt\n");
3298 	fprintf(stderr, "\t-H NSEC3 iterations (10)\n");
3299 	fprintf(stderr, "\t-A NSEC3 optout\n");
3300 
3301 	fprintf(stderr, "\n");
3302 
3303 	fprintf(stderr, "Signing Keys: ");
3304 	fprintf(stderr, "(default: all zone keys that have private keys)\n");
3305 	fprintf(stderr, "\tkeyfile (Kname+alg+tag)\n");
3306 
3307 	exit(EXIT_FAILURE);
3308 }
3309 
3310 static void
3311 removetempfile(void) {
3312 	if (removefile) {
3313 		isc_file_remove(tempfile);
3314 	}
3315 }
3316 
3317 static void
3318 print_stats(isc_time_t *timer_start, isc_time_t *timer_finish,
3319 	    isc_time_t *sign_start, isc_time_t *sign_finish) {
3320 	uint64_t time_us; /* Time in microseconds */
3321 	uint64_t time_ms; /* Time in milliseconds */
3322 	uint64_t sig_ms;  /* Signatures per millisecond */
3323 	FILE *out = output_stdout ? stderr : stdout;
3324 
3325 	fprintf(out, "Signatures generated:               %10" PRIuFAST32 "\n",
3326 		atomic_load(&nsigned));
3327 	fprintf(out, "Signatures retained:                %10" PRIuFAST32 "\n",
3328 		atomic_load(&nretained));
3329 	fprintf(out, "Signatures dropped:                 %10" PRIuFAST32 "\n",
3330 		atomic_load(&ndropped));
3331 	fprintf(out, "Signatures successfully verified:   %10" PRIuFAST32 "\n",
3332 		atomic_load(&nverified));
3333 	fprintf(out, "Signatures unsuccessfully verified: %10" PRIuFAST32 "\n",
3334 		atomic_load(&nverifyfailed));
3335 
3336 	time_us = isc_time_microdiff(sign_finish, sign_start);
3337 	time_ms = time_us / 1000;
3338 	fprintf(out, "Signing time in seconds:           %7u.%03u\n",
3339 		(unsigned int)(time_ms / 1000), (unsigned int)(time_ms % 1000));
3340 	if (time_us > 0) {
3341 		sig_ms = ((uint64_t)atomic_load(&nsigned) * 1000000000) /
3342 			 time_us;
3343 		fprintf(out, "Signatures per second:             %7u.%03u\n",
3344 			(unsigned int)sig_ms / 1000,
3345 			(unsigned int)sig_ms % 1000);
3346 	}
3347 
3348 	time_us = isc_time_microdiff(timer_finish, timer_start);
3349 	time_ms = time_us / 1000;
3350 	fprintf(out, "Runtime in seconds:                %7u.%03u\n",
3351 		(unsigned int)(time_ms / 1000), (unsigned int)(time_ms % 1000));
3352 }
3353 
3354 int
3355 main(int argc, char *argv[]) {
3356 	int ch;
3357 	char *startstr = NULL, *endstr = NULL, *classname = NULL;
3358 	char *dnskey_endstr = NULL;
3359 	char *origin = NULL, *file = NULL, *output = NULL;
3360 	char *inputformatstr = NULL, *outputformatstr = NULL;
3361 	char *serialformatstr = NULL;
3362 	char *dskeyfile[MAXDSKEYS];
3363 	int ndskeys = 0;
3364 	char *endp;
3365 	isc_time_t timer_start, timer_finish;
3366 	isc_time_t sign_start, sign_finish;
3367 	dns_dnsseckey_t *key;
3368 	isc_result_t result, vresult;
3369 	isc_log_t *log = NULL;
3370 	const char *engine = NULL;
3371 	bool free_output = false;
3372 	int tempfilelen = 0;
3373 	dns_rdataclass_t rdclass;
3374 	hashlist_t hashlist;
3375 	bool make_keyset = false;
3376 	bool set_salt = false;
3377 	bool set_optout = false;
3378 	bool set_iter = false;
3379 	bool nonsecify = false;
3380 	bool set_fips_mode = false;
3381 #if OPENSSL_VERSION_NUMBER >= 0x30000000L && OPENSSL_API_LEVEL >= 30000
3382 	OSSL_PROVIDER *fips = NULL, *base = NULL;
3383 #endif
3384 
3385 	atomic_init(&shuttingdown, false);
3386 	atomic_init(&finished, false);
3387 
3388 	/* Unused letters: Bb G J q Yy (and F is reserved). */
3389 #define CMDLINE_FLAGS                                                          \
3390 	"3:AaCc:Dd:E:e:f:FgG:hH:i:I:j:J:K:k:L:l:m:M:n:N:o:O:PpQqRr:s:ST:tuUv:" \
3391 	"VX:xzZ:"
3392 
3393 	/*
3394 	 * Process memory debugging argument first.
3395 	 */
3396 	while ((ch = isc_commandline_parse(argc, argv, CMDLINE_FLAGS)) != -1) {
3397 		switch (ch) {
3398 		case 'm':
3399 			if (strcasecmp(isc_commandline_argument, "record") == 0)
3400 			{
3401 				isc_mem_debugging |= ISC_MEM_DEBUGRECORD;
3402 			}
3403 			if (strcasecmp(isc_commandline_argument, "trace") == 0)
3404 			{
3405 				isc_mem_debugging |= ISC_MEM_DEBUGTRACE;
3406 			}
3407 			if (strcasecmp(isc_commandline_argument, "usage") == 0)
3408 			{
3409 				isc_mem_debugging |= ISC_MEM_DEBUGUSAGE;
3410 			}
3411 			break;
3412 		default:
3413 			break;
3414 		}
3415 	}
3416 	isc_commandline_reset = true;
3417 
3418 	masterstyle = &dns_master_style_explicitttl;
3419 
3420 	isc_commandline_errprint = false;
3421 	while ((ch = isc_commandline_parse(argc, argv, CMDLINE_FLAGS)) != -1) {
3422 		switch (ch) {
3423 		case '3':
3424 			set_salt = true;
3425 			nsec_datatype = dns_rdatatype_nsec3;
3426 			if (strcmp(isc_commandline_argument, "-") != 0) {
3427 				isc_buffer_t target;
3428 				char *sarg;
3429 
3430 				sarg = isc_commandline_argument;
3431 				isc_buffer_init(&target, saltbuf,
3432 						sizeof(saltbuf));
3433 				result = isc_hex_decodestring(sarg, &target);
3434 				check_result(result, "isc_hex_decodestring("
3435 						     "salt)");
3436 				salt_length = isc_buffer_usedlength(&target);
3437 			}
3438 			break;
3439 
3440 		case 'A':
3441 			set_optout = true;
3442 			if (OPTOUT(nsec3flags)) {
3443 				nsec3flags &= ~DNS_NSEC3FLAG_OPTOUT;
3444 			} else {
3445 				nsec3flags |= DNS_NSEC3FLAG_OPTOUT;
3446 			}
3447 			break;
3448 
3449 		case 'a':
3450 			tryverify = true;
3451 			break;
3452 
3453 		case 'C':
3454 			make_keyset = true;
3455 			break;
3456 
3457 		case 'c':
3458 			classname = isc_commandline_argument;
3459 			break;
3460 
3461 		case 'd':
3462 			dsdir = isc_commandline_argument;
3463 			if (strlen(dsdir) == 0U) {
3464 				fatal("DS directory must be non-empty string");
3465 			}
3466 			result = try_dir(dsdir);
3467 			if (result != ISC_R_SUCCESS) {
3468 				fatal("cannot open directory %s: %s", dsdir,
3469 				      isc_result_totext(result));
3470 			}
3471 			break;
3472 
3473 		case 'D':
3474 			output_dnssec_only = true;
3475 			break;
3476 
3477 		case 'E':
3478 			engine = isc_commandline_argument;
3479 			break;
3480 
3481 		case 'e':
3482 			endstr = isc_commandline_argument;
3483 			break;
3484 
3485 		case 'f':
3486 			output = isc_commandline_argument;
3487 			if (strcmp(output, "-") == 0) {
3488 				output_stdout = true;
3489 			}
3490 			break;
3491 
3492 		case 'g':
3493 			generateds = true;
3494 			break;
3495 
3496 		case 'G':
3497 			sync_records = isc_commandline_argument;
3498 			break;
3499 
3500 		case 'H':
3501 			set_iter = true;
3502 			/* too-many is NOT DOCUMENTED */
3503 			if (strcmp(isc_commandline_argument, "too-many") == 0) {
3504 				nsec3iter = 51;
3505 				no_max_check = true;
3506 				break;
3507 			}
3508 			nsec3iter = strtoul(isc_commandline_argument, &endp, 0);
3509 			if (*endp != '\0') {
3510 				fatal("iterations must be numeric");
3511 			}
3512 			if (nsec3iter > 0xffffU) {
3513 				fatal("iterations too big");
3514 			}
3515 			break;
3516 
3517 		case 'I':
3518 			inputformatstr = isc_commandline_argument;
3519 			break;
3520 
3521 		case 'i':
3522 			endp = NULL;
3523 			cycle = strtol(isc_commandline_argument, &endp, 0);
3524 			if (*endp != '\0' || cycle < 0) {
3525 				fatal("cycle period must be numeric and "
3526 				      "positive");
3527 			}
3528 			break;
3529 
3530 		case 'j':
3531 			endp = NULL;
3532 			jitter = strtol(isc_commandline_argument, &endp, 0);
3533 			if (*endp != '\0' || jitter < 0) {
3534 				fatal("jitter must be numeric and positive");
3535 			}
3536 			break;
3537 
3538 		case 'J':
3539 			journal = isc_commandline_argument;
3540 			break;
3541 
3542 		case 'K':
3543 			directory = isc_commandline_argument;
3544 			break;
3545 
3546 		case 'k':
3547 			if (ndskeys == MAXDSKEYS) {
3548 				fatal("too many key-signing keys specified");
3549 			}
3550 			dskeyfile[ndskeys++] = isc_commandline_argument;
3551 			break;
3552 
3553 		case 'L':
3554 			snset = true;
3555 			endp = NULL;
3556 			serialnum = strtol(isc_commandline_argument, &endp, 0);
3557 			if (*endp != '\0') {
3558 				fprintf(stderr, "source serial number "
3559 						"must be numeric");
3560 				exit(EXIT_FAILURE);
3561 			}
3562 			break;
3563 
3564 		case 'l':
3565 			fatal("-l option (DLV lookaside) is obsolete");
3566 			break;
3567 
3568 		case 'M':
3569 			endp = NULL;
3570 			set_maxttl = true;
3571 			maxttl = strtol(isc_commandline_argument, &endp, 0);
3572 			if (*endp != '\0') {
3573 				fprintf(stderr, "maximum TTL "
3574 						"must be numeric");
3575 				exit(EXIT_FAILURE);
3576 			}
3577 			break;
3578 
3579 		case 'm':
3580 			break;
3581 
3582 		case 'N':
3583 			serialformatstr = isc_commandline_argument;
3584 			break;
3585 
3586 		case 'n':
3587 			endp = NULL;
3588 			nloops = strtol(isc_commandline_argument, &endp, 0);
3589 			if (*endp != '\0' || nloops > INT32_MAX) {
3590 				fatal("number of cpus must be numeric");
3591 			}
3592 			break;
3593 
3594 		case 'O':
3595 			outputformatstr = isc_commandline_argument;
3596 			break;
3597 
3598 		case 'o':
3599 			origin = isc_commandline_argument;
3600 			break;
3601 
3602 		case 'P':
3603 			disable_zone_check = true;
3604 			break;
3605 
3606 		case 'p':
3607 			fatal("The -p option has been deprecated.\n");
3608 			break;
3609 
3610 		case 'Q':
3611 			remove_inactkeysigs = true;
3612 			break;
3613 
3614 		case 'R':
3615 			remove_orphansigs = true;
3616 			break;
3617 
3618 		case 'r':
3619 			fatal("The -r options has been deprecated.\n");
3620 			break;
3621 
3622 		case 'S':
3623 			smartsign = true;
3624 			break;
3625 
3626 		case 's':
3627 			startstr = isc_commandline_argument;
3628 			break;
3629 
3630 		case 'T':
3631 			endp = NULL;
3632 			set_keyttl = true;
3633 			keyttl = strtottl(isc_commandline_argument);
3634 			break;
3635 
3636 		case 't':
3637 			printstats = true;
3638 			break;
3639 
3640 		case 'U': /* Undocumented for testing only. */
3641 			unknownalg = true;
3642 			break;
3643 
3644 		case 'u':
3645 			update_chain = true;
3646 			break;
3647 
3648 		case 'v':
3649 			endp = NULL;
3650 			verbose = strtol(isc_commandline_argument, &endp, 0);
3651 			if (*endp != '\0') {
3652 				fatal("verbose level must be numeric");
3653 			}
3654 			break;
3655 
3656 		case 'q':
3657 			quiet = true;
3658 			break;
3659 
3660 		case 'X':
3661 			dnskey_endstr = isc_commandline_argument;
3662 			break;
3663 
3664 		case 'x':
3665 			keyset_kskonly = true;
3666 			break;
3667 
3668 		case 'z':
3669 			ignore_kskflag = true;
3670 			break;
3671 
3672 		case 'F':
3673 			set_fips_mode = true;
3674 			break;
3675 
3676 		case '?':
3677 			if (isc_commandline_option != '?') {
3678 				fprintf(stderr, "%s: invalid argument -%c\n",
3679 					program, isc_commandline_option);
3680 			}
3681 			FALLTHROUGH;
3682 		case 'h':
3683 			/* Does not return. */
3684 			usage();
3685 
3686 		case 'V':
3687 			/* Does not return. */
3688 			version(program);
3689 
3690 		case 'Z': /* Undocumented test options */
3691 			if (!strcmp(isc_commandline_argument, "nonsecify")) {
3692 				nonsecify = true;
3693 			}
3694 			break;
3695 
3696 		default:
3697 			fprintf(stderr, "%s: unhandled option -%c\n", program,
3698 				isc_commandline_option);
3699 			exit(EXIT_FAILURE);
3700 		}
3701 	}
3702 
3703 	now = isc_stdtime_now();
3704 
3705 	if (startstr != NULL) {
3706 		starttime = strtotime(startstr, now, now, NULL);
3707 	} else {
3708 		starttime = now - 3600; /* Allow for some clock skew. */
3709 	}
3710 
3711 	if (endstr != NULL) {
3712 		endtime = strtotime(endstr, now, starttime, NULL);
3713 	} else {
3714 		endtime = starttime + (30 * 24 * 60 * 60);
3715 	}
3716 
3717 	if (dnskey_endstr != NULL) {
3718 		dnskey_endtime = strtotime(dnskey_endstr, now, starttime, NULL);
3719 		if (endstr != NULL && dnskey_endtime == endtime) {
3720 			fprintf(stderr, "WARNING: -e and -X were both set, "
3721 					"but have identical values.\n");
3722 		}
3723 	} else {
3724 		dnskey_endtime = endtime;
3725 	}
3726 
3727 	if (cycle == -1) {
3728 		cycle = (endtime - starttime) / 4;
3729 	}
3730 
3731 	if (nloops == 0) {
3732 		nloops = isc_os_ncpus();
3733 	}
3734 	vbprintf(4, "using %d cpus\n", nloops);
3735 
3736 	rdclass = strtoclass(classname);
3737 
3738 	if (directory == NULL) {
3739 		directory = ".";
3740 	}
3741 
3742 	isc_managers_create(&mctx, nloops, &loopmgr, &netmgr);
3743 
3744 	if (set_fips_mode) {
3745 #if OPENSSL_VERSION_NUMBER >= 0x30000000L && OPENSSL_API_LEVEL >= 30000
3746 		fips = OSSL_PROVIDER_load(NULL, "fips");
3747 		if (fips == NULL) {
3748 			ERR_clear_error();
3749 			fatal("Failed to load FIPS provider");
3750 		}
3751 		base = OSSL_PROVIDER_load(NULL, "base");
3752 		if (base == NULL) {
3753 			OSSL_PROVIDER_unload(fips);
3754 			ERR_clear_error();
3755 			fatal("Failed to load base provider");
3756 		}
3757 #endif
3758 		if (!isc_fips_mode()) {
3759 			if (isc_fips_set_mode(1) != ISC_R_SUCCESS) {
3760 				fatal("setting FIPS mode failed");
3761 			}
3762 		}
3763 	}
3764 
3765 	result = dst_lib_init(mctx, engine);
3766 	if (result != ISC_R_SUCCESS) {
3767 		fatal("could not initialize dst: %s",
3768 		      isc_result_totext(result));
3769 	}
3770 
3771 	setup_logging(mctx, &log);
3772 
3773 	argc -= isc_commandline_index;
3774 	argv += isc_commandline_index;
3775 
3776 	if (argc < 1) {
3777 		usage();
3778 	}
3779 
3780 	file = argv[0];
3781 
3782 	argc -= 1;
3783 	argv += 1;
3784 
3785 	if (origin == NULL) {
3786 		origin = file;
3787 	}
3788 
3789 	if (output == NULL) {
3790 		size_t size;
3791 		free_output = true;
3792 		size = strlen(file) + strlen(".signed") + 1;
3793 		output = isc_mem_allocate(mctx, size);
3794 		snprintf(output, size, "%s.signed", file);
3795 	}
3796 
3797 	if (inputformatstr != NULL) {
3798 		if (strcasecmp(inputformatstr, "text") == 0) {
3799 			inputformat = dns_masterformat_text;
3800 		} else if (strcasecmp(inputformatstr, "raw") == 0) {
3801 			inputformat = dns_masterformat_raw;
3802 		} else if (strncasecmp(inputformatstr, "raw=", 4) == 0) {
3803 			inputformat = dns_masterformat_raw;
3804 			fprintf(stderr, "WARNING: input format version "
3805 					"ignored\n");
3806 		} else {
3807 			fatal("unknown file format: %s", inputformatstr);
3808 		}
3809 	}
3810 
3811 	if (outputformatstr != NULL) {
3812 		if (strcasecmp(outputformatstr, "text") == 0) {
3813 			outputformat = dns_masterformat_text;
3814 		} else if (strcasecmp(outputformatstr, "full") == 0) {
3815 			outputformat = dns_masterformat_text;
3816 			masterstyle = &dns_master_style_full;
3817 		} else if (strcasecmp(outputformatstr, "raw") == 0) {
3818 			outputformat = dns_masterformat_raw;
3819 		} else if (strncasecmp(outputformatstr, "raw=", 4) == 0) {
3820 			char *end;
3821 
3822 			outputformat = dns_masterformat_raw;
3823 			rawversion = strtol(outputformatstr + 4, &end, 10);
3824 			if (end == outputformatstr + 4 || *end != '\0' ||
3825 			    rawversion > 1U)
3826 			{
3827 				fprintf(stderr, "unknown raw format version\n");
3828 				exit(EXIT_FAILURE);
3829 			}
3830 		} else {
3831 			fatal("unknown file format: %s", outputformatstr);
3832 		}
3833 	}
3834 
3835 	if (serialformatstr != NULL) {
3836 		if (strcasecmp(serialformatstr, "keep") == 0) {
3837 			serialformat = SOA_SERIAL_KEEP;
3838 		} else if (strcasecmp(serialformatstr, "increment") == 0 ||
3839 			   strcasecmp(serialformatstr, "incr") == 0)
3840 		{
3841 			serialformat = SOA_SERIAL_INCREMENT;
3842 		} else if (strcasecmp(serialformatstr, "unixtime") == 0) {
3843 			serialformat = SOA_SERIAL_UNIXTIME;
3844 		} else if (strcasecmp(serialformatstr, "date") == 0) {
3845 			serialformat = SOA_SERIAL_DATE;
3846 		} else {
3847 			fatal("unknown soa serial format: %s", serialformatstr);
3848 		}
3849 	}
3850 
3851 	if (output_dnssec_only && outputformat != dns_masterformat_text) {
3852 		fatal("option -D can only be used with \"-O text\"");
3853 	}
3854 
3855 	if (output_dnssec_only && serialformat != SOA_SERIAL_KEEP) {
3856 		fatal("option -D can only be used with \"-N keep\"");
3857 	}
3858 
3859 	if (output_dnssec_only && set_maxttl) {
3860 		fatal("option -D cannot be used with -M");
3861 	}
3862 
3863 	result = dns_master_stylecreate(&dsstyle, DNS_STYLEFLAG_NO_TTL, 0, 24,
3864 					0, 0, 0, 8, 0xffffffff, mctx);
3865 	check_result(result, "dns_master_stylecreate");
3866 
3867 	gdb = NULL;
3868 	timer_start = isc_time_now();
3869 	loadzone(file, origin, rdclass, &gdb);
3870 	if (journal != NULL) {
3871 		loadjournal(mctx, gdb, journal);
3872 	}
3873 	gorigin = dns_db_origin(gdb);
3874 	gclass = dns_db_class(gdb);
3875 	get_soa_ttls();
3876 
3877 	if (set_maxttl && set_keyttl && keyttl > maxttl) {
3878 		fprintf(stderr,
3879 			"%s: warning: Specified key TTL %u "
3880 			"exceeds maximum zone TTL; reducing to %u\n",
3881 			program, keyttl, maxttl);
3882 		keyttl = maxttl;
3883 	}
3884 
3885 	if (!set_keyttl) {
3886 		keyttl = soa_ttl;
3887 	}
3888 
3889 	/*
3890 	 * Check for any existing NSEC3 parameters in the zone,
3891 	 * and use them as defaults if -u was not specified.
3892 	 */
3893 	if (update_chain && !set_optout && !set_iter && !set_salt) {
3894 		nsec_datatype = dns_rdatatype_nsec;
3895 	} else {
3896 		set_nsec3params(update_chain, set_salt, set_optout, set_iter);
3897 	}
3898 
3899 	/*
3900 	 * We need to do this early on, as we start messing with the list
3901 	 * of keys rather early.
3902 	 */
3903 	ISC_LIST_INIT(keylist);
3904 	isc_rwlock_init(&keylist_lock);
3905 
3906 	/*
3907 	 * Fill keylist with:
3908 	 * 1) Keys listed in the DNSKEY set that have
3909 	 *    private keys associated, *if* no keys were
3910 	 *    set on the command line.
3911 	 * 2) ZSKs set on the command line
3912 	 * 3) KSKs set on the command line
3913 	 * 4) Any keys remaining in the DNSKEY set which
3914 	 *    do not have private keys associated and were
3915 	 *    not specified on the command line.
3916 	 */
3917 	if (argc == 0 || smartsign) {
3918 		loadzonekeys(!smartsign, false);
3919 	}
3920 	loadexplicitkeys(argv, argc, false);
3921 	loadexplicitkeys(dskeyfile, ndskeys, true);
3922 	loadzonekeys(!smartsign, true);
3923 
3924 	/*
3925 	 * If we're doing smart signing, look in the key repository for
3926 	 * key files with metadata, and merge them with the keylist
3927 	 * we have now.
3928 	 */
3929 	if (smartsign) {
3930 		build_final_keylist();
3931 	}
3932 
3933 	/* Now enumerate the key list */
3934 	for (key = ISC_LIST_HEAD(keylist); key != NULL;
3935 	     key = ISC_LIST_NEXT(key, link))
3936 	{
3937 		key->index = keycount++;
3938 	}
3939 
3940 	if (keycount == 0) {
3941 		if (disable_zone_check) {
3942 			fprintf(stderr,
3943 				"%s: warning: No keys specified "
3944 				"or found\n",
3945 				program);
3946 		} else {
3947 			fatal("No signing keys specified or found.");
3948 		}
3949 		nokeys = true;
3950 	}
3951 
3952 	warnifallksk(gdb);
3953 
3954 	if (IS_NSEC3) {
3955 		bool answer;
3956 
3957 		hash_length = dns_nsec3_hashlength(dns_hash_sha1);
3958 		hashlist_init(&hashlist,
3959 			      dns_db_nodecount(gdb, dns_dbtree_main) * 2,
3960 			      hash_length);
3961 		result = dns_nsec_nseconly(gdb, gversion, NULL, &answer);
3962 		if (result == ISC_R_NOTFOUND) {
3963 			fprintf(stderr,
3964 				"%s: warning: NSEC3 generation "
3965 				"requested with no DNSKEY; ignoring\n",
3966 				program);
3967 		} else if (result != ISC_R_SUCCESS) {
3968 			check_result(result, "dns_nsec_nseconly");
3969 		} else if (answer) {
3970 			fatal("NSEC3 generation requested with "
3971 			      "NSEC-only DNSKEY");
3972 		}
3973 
3974 		if (nsec3iter > dns_nsec3_maxiterations()) {
3975 			if (no_max_check) {
3976 				fprintf(stderr,
3977 					"Ignoring max iterations check.\n");
3978 			} else {
3979 				fatal("NSEC3 iterations too big. Maximum "
3980 				      "iterations allowed %u.",
3981 				      dns_nsec3_maxiterations());
3982 			}
3983 		}
3984 	} else {
3985 		hashlist_init(&hashlist, 0, 0); /* silence clang */
3986 	}
3987 
3988 	gversion = NULL;
3989 	result = dns_db_newversion(gdb, &gversion);
3990 	check_result(result, "dns_db_newversion()");
3991 
3992 	switch (serialformat) {
3993 	case SOA_SERIAL_INCREMENT:
3994 		setsoaserial(0, dns_updatemethod_increment);
3995 		break;
3996 	case SOA_SERIAL_UNIXTIME:
3997 		setsoaserial(now, dns_updatemethod_unixtime);
3998 		break;
3999 	case SOA_SERIAL_DATE:
4000 		setsoaserial(now, dns_updatemethod_date);
4001 		break;
4002 	case SOA_SERIAL_KEEP:
4003 	default:
4004 		/* do nothing */
4005 		break;
4006 	}
4007 
4008 	/* Remove duplicates and cap TTLs at maxttl */
4009 	cleanup_zone();
4010 
4011 	if (!nonsecify) {
4012 		if (IS_NSEC3) {
4013 			nsec3ify(dns_hash_sha1, nsec3iter, gsalt, salt_length,
4014 				 &hashlist);
4015 		} else {
4016 			nsecify();
4017 		}
4018 	}
4019 
4020 	if (!nokeys) {
4021 		writeset("dsset-", dns_rdatatype_ds);
4022 		if (make_keyset) {
4023 			writeset("keyset-", dns_rdatatype_dnskey);
4024 		}
4025 	}
4026 
4027 	if (output_stdout) {
4028 		outfp = stdout;
4029 		if (outputformatstr == NULL) {
4030 			masterstyle = &dns_master_style_full;
4031 		}
4032 	} else {
4033 		tempfilelen = strlen(output) + 20;
4034 		tempfile = isc_mem_get(mctx, tempfilelen);
4035 
4036 		result = isc_file_mktemplate(output, tempfile, tempfilelen);
4037 		check_result(result, "isc_file_mktemplate");
4038 
4039 		result = isc_file_openunique(tempfile, &outfp);
4040 		if (result != ISC_R_SUCCESS) {
4041 			fatal("failed to open temporary output file: %s",
4042 			      isc_result_totext(result));
4043 		}
4044 		removefile = true;
4045 		setfatalcallback(&removetempfile);
4046 	}
4047 
4048 	print_time(outfp);
4049 	print_version(outfp);
4050 
4051 	isc_mutex_init(&namelock);
4052 
4053 	presign();
4054 	sign_start = isc_time_now();
4055 	signapex();
4056 	if (!atomic_load(&finished)) {
4057 		/*
4058 		 * There is more work to do.  Spread it out over multiple
4059 		 * processors if possible.
4060 		 */
4061 		isc_loopmgr_setup(loopmgr, assignwork, NULL);
4062 		isc_loopmgr_teardown(loopmgr, abortwork, NULL);
4063 		isc_loopmgr_run(loopmgr);
4064 
4065 		if (!atomic_load(&finished)) {
4066 			fatal("process aborted by user");
4067 		}
4068 	}
4069 	postsign();
4070 	sign_finish = isc_time_now();
4071 
4072 	if (disable_zone_check) {
4073 		vresult = ISC_R_SUCCESS;
4074 	} else {
4075 		vresult = dns_zoneverify_dnssec(NULL, gdb, gversion, gorigin,
4076 						NULL, mctx, ignore_kskflag,
4077 						keyset_kskonly, report);
4078 		if (vresult != ISC_R_SUCCESS) {
4079 			fprintf(output_stdout ? stderr : stdout,
4080 				"Zone verification failed (%s)\n",
4081 				isc_result_totext(vresult));
4082 		}
4083 	}
4084 
4085 	if (!output_dnssec_only) {
4086 		dns_masterrawheader_t header;
4087 		dns_master_initrawheader(&header);
4088 		if (rawversion == 0U) {
4089 			header.flags = DNS_MASTERRAW_COMPAT;
4090 		} else if (snset) {
4091 			header.flags = DNS_MASTERRAW_SOURCESERIALSET;
4092 			header.sourceserial = serialnum;
4093 		}
4094 		result = dns_master_dumptostream(mctx, gdb, gversion,
4095 						 masterstyle, outputformat,
4096 						 &header, outfp);
4097 		check_result(result, "dns_master_dumptostream");
4098 	}
4099 
4100 	if (!output_stdout) {
4101 		result = isc_stdio_close(outfp);
4102 		check_result(result, "isc_stdio_close");
4103 		removefile = false;
4104 
4105 		if (vresult == ISC_R_SUCCESS) {
4106 			result = isc_file_rename(tempfile, output);
4107 			if (result != ISC_R_SUCCESS) {
4108 				fatal("failed to rename temp file to %s: %s",
4109 				      output, isc_result_totext(result));
4110 			}
4111 			printf("%s\n", output);
4112 		} else {
4113 			isc_file_remove(tempfile);
4114 		}
4115 	}
4116 
4117 	dns_db_closeversion(gdb, &gversion, false);
4118 	dns_db_detach(&gdb);
4119 
4120 	hashlist_free(&hashlist);
4121 
4122 	while (!ISC_LIST_EMPTY(keylist)) {
4123 		key = ISC_LIST_HEAD(keylist);
4124 		ISC_LIST_UNLINK(keylist, key, link);
4125 		dns_dnsseckey_destroy(mctx, &key);
4126 	}
4127 
4128 	if (tempfilelen != 0) {
4129 		isc_mem_put(mctx, tempfile, tempfilelen);
4130 	}
4131 
4132 	if (free_output) {
4133 		isc_mem_free(mctx, output);
4134 	}
4135 
4136 	dns_master_styledestroy(&dsstyle, mctx);
4137 
4138 	cleanup_logging(&log);
4139 	dst_lib_destroy();
4140 	if (verbose > 10) {
4141 		isc_mem_stats(mctx, stdout);
4142 	}
4143 
4144 #if OPENSSL_VERSION_NUMBER >= 0x30000000L && OPENSSL_API_LEVEL >= 30000
4145 	if (base != NULL) {
4146 		OSSL_PROVIDER_unload(base);
4147 	}
4148 	if (fips != NULL) {
4149 		OSSL_PROVIDER_unload(fips);
4150 	}
4151 #endif
4152 
4153 	isc_managers_destroy(&mctx, &loopmgr, &netmgr);
4154 
4155 	if (printstats) {
4156 		timer_finish = isc_time_now();
4157 		print_stats(&timer_start, &timer_finish, &sign_start,
4158 			    &sign_finish);
4159 	}
4160 	isc_mutex_destroy(&namelock);
4161 
4162 	return vresult == ISC_R_SUCCESS ? 0 : 1;
4163 }
4164