1/*
2 * Copyright (C) 2004, 2005, 2007, 2009-2014  Internet Systems Consortium, Inc. ("ISC")
3 * Copyright (C) 2000, 2001, 2003  Internet Software Consortium.
4 *
5 * Permission to use, copy, modify, and/or distribute this software for any
6 * purpose with or without fee is hereby granted, provided that the above
7 * copyright notice and this permission notice appear in all copies.
8 *
9 * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
10 * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
11 * AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
12 * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
13 * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
14 * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
15 * PERFORMANCE OF THIS SOFTWARE.
16 */
17
18/* $Id: dnssectool.c,v 1.63 2011/10/21 03:55:33 marka Exp $ */
19
20/*! \file */
21
22/*%
23 * DNSSEC Support Routines.
24 */
25
26#include <config.h>
27
28#include <stdlib.h>
29
30#include <isc/base32.h>
31#include <isc/buffer.h>
32#include <isc/dir.h>
33#include <isc/entropy.h>
34#include <isc/heap.h>
35#include <isc/list.h>
36#include <isc/mem.h>
37#include <isc/string.h>
38#include <isc/time.h>
39#include <isc/util.h>
40#include <isc/print.h>
41
42#include <dns/db.h>
43#include <dns/dbiterator.h>
44#include <dns/dnssec.h>
45#include <dns/fixedname.h>
46#include <dns/keyvalues.h>
47#include <dns/log.h>
48#include <dns/name.h>
49#include <dns/nsec.h>
50#include <dns/nsec3.h>
51#include <dns/rdatastruct.h>
52#include <dns/rdataclass.h>
53#include <dns/rdataset.h>
54#include <dns/rdatasetiter.h>
55#include <dns/rdatatype.h>
56#include <dns/result.h>
57#include <dns/secalg.h>
58#include <dns/time.h>
59
60#include "dnssectool.h"
61
62static isc_heap_t *expected_chains, *found_chains;
63
64struct nsec3_chain_fixed {
65	isc_uint8_t	hash;
66	isc_uint8_t	salt_length;
67	isc_uint8_t	next_length;
68	isc_uint16_t	iterations;
69	/* unsigned char salt[0]; */
70	/* unsigned char owner[0]; */
71	/* unsigned char next[0]; */
72};
73
74extern int verbose;
75extern const char *program;
76
77typedef struct entropysource entropysource_t;
78
79struct entropysource {
80	isc_entropysource_t *source;
81	isc_mem_t *mctx;
82	ISC_LINK(entropysource_t) link;
83};
84
85static ISC_LIST(entropysource_t) sources;
86static fatalcallback_t *fatalcallback = NULL;
87
88void
89fatal(const char *format, ...) {
90	va_list args;
91
92	fprintf(stderr, "%s: fatal: ", program);
93	va_start(args, format);
94	vfprintf(stderr, format, args);
95	va_end(args);
96	fprintf(stderr, "\n");
97	if (fatalcallback != NULL)
98		(*fatalcallback)();
99	exit(1);
100}
101
102void
103setfatalcallback(fatalcallback_t *callback) {
104	fatalcallback = callback;
105}
106
107void
108check_result(isc_result_t result, const char *message) {
109	if (result != ISC_R_SUCCESS)
110		fatal("%s: %s", message, isc_result_totext(result));
111}
112
113void
114vbprintf(int level, const char *fmt, ...) {
115	va_list ap;
116	if (level > verbose)
117		return;
118	va_start(ap, fmt);
119	fprintf(stderr, "%s: ", program);
120	vfprintf(stderr, fmt, ap);
121	va_end(ap);
122}
123
124void
125type_format(const dns_rdatatype_t type, char *cp, unsigned int size) {
126	isc_buffer_t b;
127	isc_region_t r;
128	isc_result_t result;
129
130	isc_buffer_init(&b, cp, size - 1);
131	result = dns_rdatatype_totext(type, &b);
132	check_result(result, "dns_rdatatype_totext()");
133	isc_buffer_usedregion(&b, &r);
134	r.base[r.length] = 0;
135}
136
137void
138sig_format(dns_rdata_rrsig_t *sig, char *cp, unsigned int size) {
139	char namestr[DNS_NAME_FORMATSIZE];
140	char algstr[DNS_NAME_FORMATSIZE];
141
142	dns_name_format(&sig->signer, namestr, sizeof(namestr));
143	dns_secalg_format(sig->algorithm, algstr, sizeof(algstr));
144	snprintf(cp, size, "%s/%s/%d", namestr, algstr, sig->keyid);
145}
146
147void
148setup_logging(int verbose, isc_mem_t *mctx, isc_log_t **logp) {
149	isc_result_t result;
150	isc_logdestination_t destination;
151	isc_logconfig_t *logconfig = NULL;
152	isc_log_t *log = NULL;
153	int level;
154
155	if (verbose < 0)
156		verbose = 0;
157	switch (verbose) {
158	case 0:
159		/*
160		 * We want to see warnings about things like out-of-zone
161		 * data in the master file even when not verbose.
162		 */
163		level = ISC_LOG_WARNING;
164		break;
165	case 1:
166		level = ISC_LOG_INFO;
167		break;
168	default:
169		level = ISC_LOG_DEBUG(verbose - 2 + 1);
170		break;
171	}
172
173	RUNTIME_CHECK(isc_log_create(mctx, &log, &logconfig) == ISC_R_SUCCESS);
174	isc_log_setcontext(log);
175	dns_log_init(log);
176	dns_log_setcontext(log);
177
178	RUNTIME_CHECK(isc_log_settag(logconfig, program) == ISC_R_SUCCESS);
179
180	/*
181	 * Set up a channel similar to default_stderr except:
182	 *  - the logging level is passed in
183	 *  - the program name and logging level are printed
184	 *  - no time stamp is printed
185	 */
186	destination.file.stream = stderr;
187	destination.file.name = NULL;
188	destination.file.versions = ISC_LOG_ROLLNEVER;
189	destination.file.maximum_size = 0;
190	result = isc_log_createchannel(logconfig, "stderr",
191				       ISC_LOG_TOFILEDESC,
192				       level,
193				       &destination,
194				       ISC_LOG_PRINTTAG|ISC_LOG_PRINTLEVEL);
195	check_result(result, "isc_log_createchannel()");
196
197	RUNTIME_CHECK(isc_log_usechannel(logconfig, "stderr",
198					 NULL, NULL) == ISC_R_SUCCESS);
199
200	*logp = log;
201}
202
203void
204cleanup_logging(isc_log_t **logp) {
205	isc_log_t *log;
206
207	REQUIRE(logp != NULL);
208
209	log = *logp;
210	if (log == NULL)
211		return;
212	isc_log_destroy(&log);
213	isc_log_setcontext(NULL);
214	dns_log_setcontext(NULL);
215	logp = NULL;
216}
217
218void
219setup_entropy(isc_mem_t *mctx, const char *randomfile, isc_entropy_t **ectx) {
220	isc_result_t result;
221	isc_entropysource_t *source = NULL;
222	entropysource_t *elt;
223	int usekeyboard = ISC_ENTROPY_KEYBOARDMAYBE;
224
225	REQUIRE(ectx != NULL);
226
227	if (*ectx == NULL) {
228		result = isc_entropy_create(mctx, ectx);
229		if (result != ISC_R_SUCCESS)
230			fatal("could not create entropy object");
231		ISC_LIST_INIT(sources);
232	}
233
234	if (randomfile != NULL && strcmp(randomfile, "keyboard") == 0) {
235		usekeyboard = ISC_ENTROPY_KEYBOARDYES;
236		randomfile = NULL;
237	}
238
239	result = isc_entropy_usebestsource(*ectx, &source, randomfile,
240					   usekeyboard);
241
242	if (result != ISC_R_SUCCESS)
243		fatal("could not initialize entropy source: %s",
244		      isc_result_totext(result));
245
246	if (source != NULL) {
247		elt = isc_mem_get(mctx, sizeof(*elt));
248		if (elt == NULL)
249			fatal("out of memory");
250		elt->source = source;
251		elt->mctx = mctx;
252		ISC_LINK_INIT(elt, link);
253		ISC_LIST_APPEND(sources, elt, link);
254	}
255}
256
257void
258cleanup_entropy(isc_entropy_t **ectx) {
259	entropysource_t *source;
260	while (!ISC_LIST_EMPTY(sources)) {
261		source = ISC_LIST_HEAD(sources);
262		ISC_LIST_UNLINK(sources, source, link);
263		isc_entropy_destroysource(&source->source);
264		isc_mem_put(source->mctx, source, sizeof(*source));
265	}
266	isc_entropy_detach(ectx);
267}
268
269static isc_stdtime_t
270time_units(isc_stdtime_t offset, char *suffix, const char *str) {
271	switch (suffix[0]) {
272	    case 'Y': case 'y':
273		return (offset * (365 * 24 * 3600));
274	    case 'M': case 'm':
275		switch (suffix[1]) {
276		    case 'O': case 'o':
277			return (offset * (30 * 24 * 3600));
278		    case 'I': case 'i':
279			return (offset * 60);
280		    case '\0':
281			fatal("'%s' ambiguous: use 'mi' for minutes "
282			      "or 'mo' for months", str);
283		    default:
284			fatal("time value %s is invalid", str);
285		}
286		/* NOTREACHED */
287		break;
288	    case 'W': case 'w':
289		return (offset * (7 * 24 * 3600));
290	    case 'D': case 'd':
291		return (offset * (24 * 3600));
292	    case 'H': case 'h':
293		return (offset * 3600);
294	    case 'S': case 's': case '\0':
295		return (offset);
296	    default:
297		fatal("time value %s is invalid", str);
298	}
299	/* NOTREACHED */
300	return(0); /* silence compiler warning */
301}
302
303dns_ttl_t
304strtottl(const char *str) {
305	const char *orig = str;
306	dns_ttl_t ttl;
307	char *endp;
308
309	ttl = strtol(str, &endp, 0);
310	if (ttl == 0 && endp == str)
311		fatal("TTL must be numeric");
312	ttl = time_units(ttl, endp, orig);
313	return (ttl);
314}
315
316isc_stdtime_t
317strtotime(const char *str, isc_int64_t now, isc_int64_t base) {
318	isc_int64_t val, offset;
319	isc_result_t result;
320	const char *orig = str;
321	char *endp;
322	int n;
323
324	if ((str[0] == '0' || str[0] == '-') && str[1] == '\0')
325		return ((isc_stdtime_t) 0);
326
327	/*
328	 * We accept times in the following formats:
329	 *   now([+-]offset)
330	 *   YYYYMMDD([+-]offset)
331	 *   YYYYMMDDhhmmss([+-]offset)
332	 *   [+-]offset
333	 */
334	n = strspn(str, "0123456789");
335	if ((n == 8 || n == 14) &&
336	    (str[n] == '\0' || str[n] == '-' || str[n] == '+'))
337	{
338		char timestr[15];
339
340		strlcpy(timestr, str, sizeof(timestr));
341		timestr[n] = 0;
342		if (n == 8)
343			strlcat(timestr, "000000", sizeof(timestr));
344		result = dns_time64_fromtext(timestr, &val);
345		if (result != ISC_R_SUCCESS)
346			fatal("time value %s is invalid: %s", orig,
347			      isc_result_totext(result));
348		base = val;
349		str += n;
350	} else if (strncmp(str, "now", 3) == 0) {
351		base = now;
352		str += 3;
353	}
354
355	if (str[0] == '\0')
356		return ((isc_stdtime_t) base);
357	else if (str[0] == '+') {
358		offset = strtol(str + 1, &endp, 0);
359		offset = time_units((isc_stdtime_t) offset, endp, orig);
360		val = base + offset;
361	} else if (str[0] == '-') {
362		offset = strtol(str + 1, &endp, 0);
363		offset = time_units((isc_stdtime_t) offset, endp, orig);
364		val = base - offset;
365	} else
366		fatal("time value %s is invalid", orig);
367
368	return ((isc_stdtime_t) val);
369}
370
371dns_rdataclass_t
372strtoclass(const char *str) {
373	isc_textregion_t r;
374	dns_rdataclass_t rdclass;
375	isc_result_t ret;
376
377	if (str == NULL)
378		return dns_rdataclass_in;
379	DE_CONST(str, r.base);
380	r.length = strlen(str);
381	ret = dns_rdataclass_fromtext(&rdclass, &r);
382	if (ret != ISC_R_SUCCESS)
383		fatal("unknown class %s", str);
384	return (rdclass);
385}
386
387isc_result_t
388try_dir(const char *dirname) {
389	isc_result_t result;
390	isc_dir_t d;
391
392	isc_dir_init(&d);
393	result = isc_dir_open(&d, dirname);
394	if (result == ISC_R_SUCCESS) {
395		isc_dir_close(&d);
396	}
397	return (result);
398}
399
400/*
401 * Check private key version compatibility.
402 */
403void
404check_keyversion(dst_key_t *key, char *keystr) {
405	int major, minor;
406	dst_key_getprivateformat(key, &major, &minor);
407	INSIST(major <= DST_MAJOR_VERSION); /* invalid private key */
408
409	if (major < DST_MAJOR_VERSION || minor < DST_MINOR_VERSION)
410		fatal("Key %s has incompatible format version %d.%d, "
411		      "use -f to force upgrade to new version.",
412		      keystr, major, minor);
413	if (minor > DST_MINOR_VERSION)
414		fatal("Key %s has incompatible format version %d.%d, "
415		      "use -f to force downgrade to current version.",
416		      keystr, major, minor);
417}
418
419void
420set_keyversion(dst_key_t *key) {
421	int major, minor;
422	dst_key_getprivateformat(key, &major, &minor);
423	INSIST(major <= DST_MAJOR_VERSION);
424
425	if (major != DST_MAJOR_VERSION || minor != DST_MINOR_VERSION)
426		dst_key_setprivateformat(key, DST_MAJOR_VERSION,
427					 DST_MINOR_VERSION);
428
429	/*
430	 * If the key is from a version older than 1.3, set
431	 * set the creation date
432	 */
433	if (major < 1 || (major == 1 && minor <= 2)) {
434		isc_stdtime_t now;
435		isc_stdtime_get(&now);
436		dst_key_settime(key, DST_TIME_CREATED, now);
437	}
438}
439
440isc_boolean_t
441key_collision(dst_key_t *dstkey, dns_name_t *name, const char *dir,
442	      isc_mem_t *mctx, isc_boolean_t *exact)
443{
444	isc_result_t result;
445	isc_boolean_t conflict = ISC_FALSE;
446	dns_dnsseckeylist_t matchkeys;
447	dns_dnsseckey_t *key = NULL;
448	isc_uint16_t id, oldid;
449	isc_uint32_t rid, roldid;
450	dns_secalg_t alg;
451
452	if (exact != NULL)
453		*exact = ISC_FALSE;
454
455	id = dst_key_id(dstkey);
456	rid = dst_key_rid(dstkey);
457	alg = dst_key_alg(dstkey);
458
459	ISC_LIST_INIT(matchkeys);
460	result = dns_dnssec_findmatchingkeys(name, dir, mctx, &matchkeys);
461	if (result == ISC_R_NOTFOUND)
462		return (ISC_FALSE);
463
464	while (!ISC_LIST_EMPTY(matchkeys) && !conflict) {
465		key = ISC_LIST_HEAD(matchkeys);
466		if (dst_key_alg(key->key) != alg)
467			goto next;
468
469		oldid = dst_key_id(key->key);
470		roldid = dst_key_rid(key->key);
471
472		if (oldid == rid || roldid == id || id == oldid) {
473			conflict = ISC_TRUE;
474			if (id != oldid) {
475				if (verbose > 1)
476					fprintf(stderr, "Key ID %d could "
477						"collide with %d\n",
478						id, oldid);
479			} else {
480				if (exact != NULL)
481					*exact = ISC_TRUE;
482				if (verbose > 1)
483					fprintf(stderr, "Key ID %d exists\n",
484						id);
485			}
486		}
487
488 next:
489		ISC_LIST_UNLINK(matchkeys, key, link);
490		dns_dnsseckey_destroy(mctx, &key);
491	}
492
493	/* Finish freeing the list */
494	while (!ISC_LIST_EMPTY(matchkeys)) {
495		key = ISC_LIST_HEAD(matchkeys);
496		ISC_LIST_UNLINK(matchkeys, key, link);
497		dns_dnsseckey_destroy(mctx, &key);
498	}
499
500	return (conflict);
501}
502
503isc_boolean_t
504is_delegation(dns_db_t *db, dns_dbversion_t *ver, dns_name_t *origin,
505	      dns_name_t *name, dns_dbnode_t *node, isc_uint32_t *ttlp)
506{
507	dns_rdataset_t nsset;
508	isc_result_t result;
509
510	if (dns_name_equal(name, origin))
511		return (ISC_FALSE);
512
513	dns_rdataset_init(&nsset);
514	result = dns_db_findrdataset(db, node, ver, dns_rdatatype_ns,
515				     0, 0, &nsset, NULL);
516	if (dns_rdataset_isassociated(&nsset)) {
517		if (ttlp != NULL)
518			*ttlp = nsset.ttl;
519		dns_rdataset_disassociate(&nsset);
520	}
521
522	return (ISC_TF(result == ISC_R_SUCCESS));
523}
524
525static isc_boolean_t
526goodsig(dns_name_t *origin, dns_rdata_t *sigrdata, dns_name_t *name,
527	dns_rdataset_t *keyrdataset, dns_rdataset_t *rdataset, isc_mem_t *mctx)
528{
529	dns_rdata_dnskey_t key;
530	dns_rdata_rrsig_t sig;
531	dst_key_t *dstkey = NULL;
532	isc_result_t result;
533
534	result = dns_rdata_tostruct(sigrdata, &sig, NULL);
535	check_result(result, "dns_rdata_tostruct()");
536
537	for (result = dns_rdataset_first(keyrdataset);
538	     result == ISC_R_SUCCESS;
539	     result = dns_rdataset_next(keyrdataset)) {
540		dns_rdata_t rdata = DNS_RDATA_INIT;
541		dns_rdataset_current(keyrdataset, &rdata);
542		result = dns_rdata_tostruct(&rdata, &key, NULL);
543		check_result(result, "dns_rdata_tostruct()");
544		result = dns_dnssec_keyfromrdata(origin, &rdata, mctx,
545						 &dstkey);
546		if (result != ISC_R_SUCCESS)
547			return (ISC_FALSE);
548		if (sig.algorithm != key.algorithm ||
549		    sig.keyid != dst_key_id(dstkey) ||
550		    !dns_name_equal(&sig.signer, origin)) {
551			dst_key_free(&dstkey);
552			continue;
553		}
554		result = dns_dnssec_verify(name, rdataset, dstkey, ISC_FALSE,
555					   mctx, sigrdata);
556		dst_key_free(&dstkey);
557		if (result == ISC_R_SUCCESS)
558			return(ISC_TRUE);
559	}
560	return (ISC_FALSE);
561}
562
563static isc_result_t
564verifynsec(dns_db_t *db, dns_dbversion_t *ver, dns_name_t *name,
565	   dns_dbnode_t *node, dns_name_t *nextname)
566{
567	unsigned char buffer[DNS_NSEC_BUFFERSIZE];
568	char namebuf[DNS_NAME_FORMATSIZE];
569	char nextbuf[DNS_NAME_FORMATSIZE];
570	char found[DNS_NAME_FORMATSIZE];
571	dns_rdataset_t rdataset;
572	dns_rdata_t rdata = DNS_RDATA_INIT;
573	dns_rdata_t tmprdata = DNS_RDATA_INIT;
574	dns_rdata_nsec_t nsec;
575	isc_result_t result;
576
577	dns_rdataset_init(&rdataset);
578	result = dns_db_findrdataset(db, node, ver, dns_rdatatype_nsec,
579				     0, 0, &rdataset, NULL);
580	if (result != ISC_R_SUCCESS) {
581		dns_name_format(name, namebuf, sizeof(namebuf));
582		fprintf(stderr, "Missing NSEC record for %s\n", namebuf);
583		goto failure;
584	}
585
586	result = dns_rdataset_first(&rdataset);
587	check_result(result, "dns_rdataset_first()");
588
589	dns_rdataset_current(&rdataset, &rdata);
590	result = dns_rdata_tostruct(&rdata, &nsec, NULL);
591	check_result(result, "dns_rdata_tostruct()");
592	/* Check bit next name is consistent */
593	if (!dns_name_equal(&nsec.next, nextname)) {
594		dns_name_format(name, namebuf, sizeof(namebuf));
595		dns_name_format(nextname, nextbuf, sizeof(nextbuf));
596		dns_name_format(&nsec.next, found, sizeof(found));
597		fprintf(stderr, "Bad NSEC record for %s, next name "
598				"mismatch (expected:%s, found:%s)\n", namebuf,
599				nextbuf, found);
600		goto failure;
601	}
602	/* Check bit map is consistent */
603	result = dns_nsec_buildrdata(db, ver, node, nextname, buffer,
604				     &tmprdata);
605	check_result(result, "dns_nsec_buildrdata()");
606	if (dns_rdata_compare(&rdata, &tmprdata) != 0) {
607		dns_name_format(name, namebuf, sizeof(namebuf));
608		fprintf(stderr, "Bad NSEC record for %s, bit map "
609				"mismatch\n", namebuf);
610		goto failure;
611	}
612	result = dns_rdataset_next(&rdataset);
613	if (result != ISC_R_NOMORE) {
614		dns_name_format(name, namebuf, sizeof(namebuf));
615		fprintf(stderr, "Multipe NSEC records for %s\n", namebuf);
616		goto failure;
617
618	}
619	dns_rdataset_disassociate(&rdataset);
620	return (ISC_R_SUCCESS);
621 failure:
622	if (dns_rdataset_isassociated(&rdataset))
623		dns_rdataset_disassociate(&rdataset);
624	return (ISC_R_FAILURE);
625}
626
627static void
628check_no_rrsig(dns_db_t *db, dns_dbversion_t *ver, dns_rdataset_t *rdataset,
629	       dns_name_t *name, dns_dbnode_t *node)
630{
631	char namebuf[DNS_NAME_FORMATSIZE];
632	char typebuf[80];
633	dns_rdataset_t sigrdataset;
634	dns_rdatasetiter_t *rdsiter = NULL;
635	isc_result_t result;
636
637	dns_rdataset_init(&sigrdataset);
638	result = dns_db_allrdatasets(db, node, ver, 0, &rdsiter);
639	check_result(result, "dns_db_allrdatasets()");
640	for (result = dns_rdatasetiter_first(rdsiter);
641	     result == ISC_R_SUCCESS;
642	     result = dns_rdatasetiter_next(rdsiter)) {
643		dns_rdatasetiter_current(rdsiter, &sigrdataset);
644		if (sigrdataset.type == dns_rdatatype_rrsig &&
645		    sigrdataset.covers == rdataset->type)
646			break;
647		dns_rdataset_disassociate(&sigrdataset);
648	}
649	if (result == ISC_R_SUCCESS) {
650		dns_name_format(name, namebuf, sizeof(namebuf));
651		type_format(rdataset->type, typebuf, sizeof(typebuf));
652		fprintf(stderr, "Warning: Found unexpected signatures for "
653			"%s/%s\n", namebuf, typebuf);
654	}
655	if (dns_rdataset_isassociated(&sigrdataset))
656		dns_rdataset_disassociate(&sigrdataset);
657	dns_rdatasetiter_destroy(&rdsiter);
658}
659
660static isc_boolean_t
661chain_compare(void *arg1, void *arg2) {
662	struct nsec3_chain_fixed *e1 = arg1, *e2 = arg2;
663	size_t len;
664
665	/*
666	 * Do each element in turn to get a stable sort.
667	 */
668	if (e1->hash < e2->hash)
669		return (ISC_TRUE);
670	if (e1->hash > e2->hash)
671		return (ISC_FALSE);
672	if (e1->iterations < e2->iterations)
673		return (ISC_TRUE);
674	if (e1->iterations > e2->iterations)
675		return (ISC_FALSE);
676	if (e1->salt_length < e2->salt_length)
677		return (ISC_TRUE);
678	if (e1->salt_length > e2->salt_length)
679		return (ISC_FALSE);
680	if (e1->next_length < e2->next_length)
681		return (ISC_TRUE);
682	if (e1->next_length > e2->next_length)
683		return (ISC_FALSE);
684	len = e1->salt_length + 2 * e1->next_length;
685	if (memcmp(e1 + 1, e2 + 1, len) < 0)
686		return (ISC_TRUE);
687	return (ISC_FALSE);
688}
689
690static isc_boolean_t
691chain_equal(struct nsec3_chain_fixed *e1, struct nsec3_chain_fixed *e2) {
692	size_t len;
693
694	if (e1->hash != e2->hash)
695		return (ISC_FALSE);
696	if (e1->iterations != e2->iterations)
697		return (ISC_FALSE);
698	if (e1->salt_length != e2->salt_length)
699		return (ISC_FALSE);
700	if (e1->next_length != e2->next_length)
701		return (ISC_FALSE);
702	len = e1->salt_length + 2 * e1->next_length;
703	if (memcmp(e1 + 1, e2 + 1, len) != 0)
704		return (ISC_FALSE);
705	return (ISC_TRUE);
706}
707
708static isc_result_t
709record_nsec3(const unsigned char *rawhash, const dns_rdata_nsec3_t *nsec3,
710	     isc_mem_t *mctx, isc_heap_t *chains)
711{
712	struct nsec3_chain_fixed *element;
713	size_t len;
714	unsigned char *cp;
715	isc_result_t result;
716
717	len = sizeof(*element) + nsec3->next_length * 2 + nsec3->salt_length;
718
719	element = isc_mem_get(mctx, len);
720	if (element == NULL)
721		return (ISC_R_NOMEMORY);
722	memset(element, 0, len);
723	element->hash = nsec3->hash;
724	element->salt_length = nsec3->salt_length;
725	element->next_length = nsec3->next_length;
726	element->iterations = nsec3->iterations;
727	cp = (unsigned char *)(element + 1);
728	memmove(cp, nsec3->salt, nsec3->salt_length);
729	cp += nsec3->salt_length;
730	memmove(cp, rawhash, nsec3->next_length);
731	cp += nsec3->next_length;
732	memmove(cp, nsec3->next, nsec3->next_length);
733	result = isc_heap_insert(chains, element);
734	if (result != ISC_R_SUCCESS) {
735		fprintf(stderr, "isc_heap_insert failed: %s\n",
736			isc_result_totext(result));
737		isc_mem_put(mctx, element, len);
738	}
739	return (result);
740}
741
742static isc_result_t
743match_nsec3(dns_name_t *name, isc_mem_t *mctx,
744	    dns_rdata_nsec3param_t *nsec3param, dns_rdataset_t *rdataset,
745	    unsigned char types[8192], unsigned int maxtype,
746	    unsigned char *rawhash, size_t rhsize)
747{
748	unsigned char cbm[8244];
749	char namebuf[DNS_NAME_FORMATSIZE];
750	dns_rdata_nsec3_t nsec3;
751	isc_result_t result;
752	unsigned int len;
753
754	/*
755	 * Find matching NSEC3 record.
756	 */
757	for (result = dns_rdataset_first(rdataset);
758	     result == ISC_R_SUCCESS;
759	     result = dns_rdataset_next(rdataset)) {
760		dns_rdata_t rdata = DNS_RDATA_INIT;
761		dns_rdataset_current(rdataset, &rdata);
762		result = dns_rdata_tostruct(&rdata, &nsec3, NULL);
763		check_result(result, "dns_rdata_tostruct()");
764		if (nsec3.hash == nsec3param->hash &&
765		    nsec3.next_length == rhsize &&
766		    nsec3.iterations == nsec3param->iterations &&
767		    nsec3.salt_length == nsec3param->salt_length &&
768		    memcmp(nsec3.salt, nsec3param->salt,
769			   nsec3param->salt_length) == 0)
770			break;
771	}
772	if (result != ISC_R_SUCCESS) {
773		dns_name_format(name, namebuf, sizeof(namebuf));
774		fprintf(stderr, "Missing NSEC3 record for %s\n", namebuf);
775		return (result);
776	}
777
778	/*
779	 * Check the type list.
780	 */
781	len = dns_nsec_compressbitmap(cbm, types, maxtype);
782	if (nsec3.len != len || memcmp(cbm, nsec3.typebits, len) != 0) {
783		dns_name_format(name, namebuf, sizeof(namebuf));
784		fprintf(stderr, "Bad NSEC3 record for %s, bit map "
785				"mismatch\n", namebuf);
786		return (ISC_R_FAILURE);
787	}
788
789	/*
790	 * Record chain.
791	 */
792	result = record_nsec3(rawhash, &nsec3, mctx, expected_chains);
793	check_result(result, "record_nsec3()");
794
795	/*
796	 * Make sure there is only one NSEC3 record with this set of
797	 * parameters.
798	 */
799	for (result = dns_rdataset_next(rdataset);
800	     result == ISC_R_SUCCESS;
801	     result = dns_rdataset_next(rdataset)) {
802		dns_rdata_t rdata = DNS_RDATA_INIT;
803		dns_rdataset_current(rdataset, &rdata);
804		result = dns_rdata_tostruct(&rdata, &nsec3, NULL);
805		check_result(result, "dns_rdata_tostruct()");
806		if (nsec3.hash == nsec3param->hash &&
807		    nsec3.iterations == nsec3param->iterations &&
808		    nsec3.salt_length == nsec3param->salt_length &&
809		    memcmp(nsec3.salt, nsec3param->salt,
810			   nsec3.salt_length) == 0) {
811			dns_name_format(name, namebuf, sizeof(namebuf));
812			fprintf(stderr, "Multiple NSEC3 records with the "
813				"same parameter set for %s", namebuf);
814			result = DNS_R_DUPLICATE;
815			break;
816		}
817	}
818	if (result != ISC_R_NOMORE)
819		return (result);
820
821	result = ISC_R_SUCCESS;
822	return (result);
823}
824
825static isc_boolean_t
826innsec3params(dns_rdata_nsec3_t *nsec3, dns_rdataset_t *nsec3paramset) {
827	dns_rdata_nsec3param_t nsec3param;
828	isc_result_t result;
829
830	for (result = dns_rdataset_first(nsec3paramset);
831	     result == ISC_R_SUCCESS;
832	     result = dns_rdataset_next(nsec3paramset)) {
833		dns_rdata_t rdata = DNS_RDATA_INIT;
834
835		dns_rdataset_current(nsec3paramset, &rdata);
836		result = dns_rdata_tostruct(&rdata, &nsec3param, NULL);
837		check_result(result, "dns_rdata_tostruct()");
838		if (nsec3param.flags == 0 &&
839		    nsec3param.hash == nsec3->hash &&
840		    nsec3param.iterations == nsec3->iterations &&
841		    nsec3param.salt_length == nsec3->salt_length &&
842		    memcmp(nsec3param.salt, nsec3->salt,
843			   nsec3->salt_length) == 0)
844			return (ISC_TRUE);
845	}
846	return (ISC_FALSE);
847}
848
849static isc_result_t
850record_found(dns_db_t *db, dns_dbversion_t *ver, isc_mem_t *mctx,
851	     dns_name_t *name, dns_dbnode_t *node,
852	     dns_rdataset_t *nsec3paramset)
853{
854	unsigned char owner[NSEC3_MAX_HASH_LENGTH];
855	dns_rdata_nsec3_t nsec3;
856	dns_rdataset_t rdataset;
857	dns_label_t hashlabel;
858	isc_buffer_t b;
859	isc_result_t result;
860
861	if (nsec3paramset == NULL || !dns_rdataset_isassociated(nsec3paramset))
862		return (ISC_R_SUCCESS);
863
864	dns_rdataset_init(&rdataset);
865	result = dns_db_findrdataset(db, node, ver, dns_rdatatype_nsec3,
866				     0, 0, &rdataset, NULL);
867	if (result != ISC_R_SUCCESS)
868		return (ISC_R_SUCCESS);
869
870	dns_name_getlabel(name, 0, &hashlabel);
871	isc_region_consume(&hashlabel, 1);
872	isc_buffer_init(&b, owner, sizeof(owner));
873	result = isc_base32hex_decoderegion(&hashlabel, &b);
874	if (result != ISC_R_SUCCESS)
875		goto cleanup;
876
877	for (result = dns_rdataset_first(&rdataset);
878	     result == ISC_R_SUCCESS;
879	     result = dns_rdataset_next(&rdataset)) {
880		dns_rdata_t rdata = DNS_RDATA_INIT;
881		dns_rdataset_current(&rdataset, &rdata);
882		result = dns_rdata_tostruct(&rdata, &nsec3, NULL);
883		check_result(result, "dns_rdata_tostruct()");
884		if (nsec3.next_length != isc_buffer_usedlength(&b))
885			continue;
886		/*
887		 * We only care about NSEC3 records that match a NSEC3PARAM
888		 * record.
889		 */
890		if (!innsec3params(&nsec3, nsec3paramset))
891			continue;
892
893		/*
894		 * Record chain.
895		 */
896		result = record_nsec3(owner, &nsec3, mctx, found_chains);
897		check_result(result, "record_nsec3()");
898	}
899
900 cleanup:
901	dns_rdataset_disassociate(&rdataset);
902	return (ISC_R_SUCCESS);
903}
904
905static isc_boolean_t
906isoptout(dns_db_t *db, dns_dbversion_t *ver, dns_name_t *origin,
907	 dns_rdata_t *nsec3rdata)
908{
909	dns_rdataset_t rdataset;
910	dns_rdata_t rdata = DNS_RDATA_INIT;
911	dns_rdata_nsec3_t nsec3;
912	dns_rdata_nsec3param_t nsec3param;
913	dns_fixedname_t fixed;
914	dns_name_t *hashname;
915	isc_result_t result;
916	dns_dbnode_t *node = NULL;
917	unsigned char rawhash[NSEC3_MAX_HASH_LENGTH];
918	size_t rhsize = sizeof(rawhash);
919	isc_boolean_t ret;
920
921	result = dns_rdata_tostruct(nsec3rdata, &nsec3param, NULL);
922	check_result(result, "dns_rdata_tostruct()");
923
924	dns_fixedname_init(&fixed);
925	result = dns_nsec3_hashname(&fixed, rawhash, &rhsize, origin, origin,
926				    nsec3param.hash, nsec3param.iterations,
927				    nsec3param.salt, nsec3param.salt_length);
928	check_result(result, "dns_nsec3_hashname()");
929
930	dns_rdataset_init(&rdataset);
931	hashname = dns_fixedname_name(&fixed);
932	result = dns_db_findnsec3node(db, hashname, ISC_FALSE, &node);
933	if (result == ISC_R_SUCCESS)
934		result = dns_db_findrdataset(db, node, ver, dns_rdatatype_nsec3,
935					     0, 0, &rdataset, NULL);
936	if (result != ISC_R_SUCCESS)
937		return (ISC_FALSE);
938
939	result = dns_rdataset_first(&rdataset);
940	check_result(result, "dns_rdataset_first()");
941
942	dns_rdataset_current(&rdataset, &rdata);
943
944	result = dns_rdata_tostruct(&rdata, &nsec3, NULL);
945	if (result != ISC_R_SUCCESS)
946		ret = ISC_FALSE;
947	else
948		ret = ISC_TF((nsec3.flags & DNS_NSEC3FLAG_OPTOUT) != 0);
949
950	if (dns_rdataset_isassociated(&rdataset))
951		dns_rdataset_disassociate(&rdataset);
952	if (node != NULL)
953		dns_db_detachnode(db, &node);
954
955	return (ret);
956}
957
958static isc_result_t
959verifynsec3(dns_db_t *db, dns_dbversion_t *ver, dns_name_t *origin,
960	    isc_mem_t *mctx, dns_name_t *name, dns_rdata_t *rdata,
961	    isc_boolean_t delegation, isc_boolean_t empty,
962	    unsigned char types[8192], unsigned int maxtype)
963{
964	char namebuf[DNS_NAME_FORMATSIZE];
965	char hashbuf[DNS_NAME_FORMATSIZE];
966	dns_rdataset_t rdataset;
967	dns_rdata_nsec3param_t nsec3param;
968	dns_fixedname_t fixed;
969	dns_name_t *hashname;
970	isc_result_t result;
971	dns_dbnode_t *node = NULL;
972	unsigned char rawhash[NSEC3_MAX_HASH_LENGTH];
973	size_t rhsize = sizeof(rawhash);
974	isc_boolean_t optout;
975
976	result = dns_rdata_tostruct(rdata, &nsec3param, NULL);
977	check_result(result, "dns_rdata_tostruct()");
978
979	if (nsec3param.flags != 0)
980		return (ISC_R_SUCCESS);
981
982	if (!dns_nsec3_supportedhash(nsec3param.hash))
983		return (ISC_R_SUCCESS);
984
985	optout = isoptout(db, ver, origin, rdata);
986
987	dns_fixedname_init(&fixed);
988	result = dns_nsec3_hashname(&fixed, rawhash, &rhsize, name, origin,
989				    nsec3param.hash, nsec3param.iterations,
990				    nsec3param.salt, nsec3param.salt_length);
991	check_result(result, "dns_nsec3_hashname()");
992
993	/*
994	 * We don't use dns_db_find() here as it works with the choosen
995	 * nsec3 chain and we may also be called with uncommitted data
996	 * from dnssec-signzone so the secure status of the zone may not
997	 * be up to date.
998	 */
999	dns_rdataset_init(&rdataset);
1000	hashname = dns_fixedname_name(&fixed);
1001	result = dns_db_findnsec3node(db, hashname, ISC_FALSE, &node);
1002	if (result == ISC_R_SUCCESS)
1003		result = dns_db_findrdataset(db, node, ver, dns_rdatatype_nsec3,
1004					     0, 0, &rdataset, NULL);
1005	if (result != ISC_R_SUCCESS &&
1006	    (!delegation || (empty && !optout) ||
1007	     (!empty && dns_nsec_isset(types, dns_rdatatype_ds))))
1008	{
1009		dns_name_format(name, namebuf, sizeof(namebuf));
1010		dns_name_format(hashname, hashbuf, sizeof(hashbuf));
1011		fprintf(stderr, "Missing NSEC3 record for %s (%s)\n",
1012			namebuf, hashbuf);
1013	} else if (result == ISC_R_NOTFOUND &&
1014		   delegation && (!empty || optout))
1015	{
1016		result = ISC_R_SUCCESS;
1017	} else if (result == ISC_R_SUCCESS) {
1018		result = match_nsec3(name, mctx, &nsec3param, &rdataset,
1019				     types, maxtype, rawhash, rhsize);
1020	}
1021
1022	if (dns_rdataset_isassociated(&rdataset))
1023		dns_rdataset_disassociate(&rdataset);
1024	if (node != NULL)
1025		dns_db_detachnode(db, &node);
1026
1027	return (result);
1028}
1029
1030static isc_result_t
1031verifynsec3s(dns_db_t *db, dns_dbversion_t *ver, dns_name_t *origin,
1032	     isc_mem_t *mctx, dns_name_t *name, dns_rdataset_t *nsec3paramset,
1033	     isc_boolean_t delegation, isc_boolean_t empty,
1034	     unsigned char types[8192], unsigned int maxtype)
1035{
1036	isc_result_t result;
1037
1038	for (result = dns_rdataset_first(nsec3paramset);
1039	     result == ISC_R_SUCCESS;
1040	     result = dns_rdataset_next(nsec3paramset)) {
1041		dns_rdata_t rdata = DNS_RDATA_INIT;
1042
1043		dns_rdataset_current(nsec3paramset, &rdata);
1044		result = verifynsec3(db, ver, origin, mctx, name, &rdata,
1045				     delegation, empty, types, maxtype);
1046		if (result != ISC_R_SUCCESS)
1047			break;
1048	}
1049	if (result == ISC_R_NOMORE)
1050		result = ISC_R_SUCCESS;
1051	return (result);
1052}
1053
1054static void
1055verifyset(dns_db_t *db, dns_dbversion_t *ver, dns_name_t *origin,
1056	  isc_mem_t *mctx, dns_rdataset_t *rdataset, dns_name_t *name,
1057	  dns_dbnode_t *node, dns_rdataset_t *keyrdataset,
1058	  unsigned char *act_algorithms, unsigned char *bad_algorithms)
1059{
1060	unsigned char set_algorithms[256];
1061	char namebuf[DNS_NAME_FORMATSIZE];
1062	char algbuf[80];
1063	char typebuf[80];
1064	dns_rdataset_t sigrdataset;
1065	dns_rdatasetiter_t *rdsiter = NULL;
1066	isc_result_t result;
1067	int i;
1068
1069	dns_rdataset_init(&sigrdataset);
1070	result = dns_db_allrdatasets(db, node, ver, 0, &rdsiter);
1071	check_result(result, "dns_db_allrdatasets()");
1072	for (result = dns_rdatasetiter_first(rdsiter);
1073	     result == ISC_R_SUCCESS;
1074	     result = dns_rdatasetiter_next(rdsiter)) {
1075		dns_rdatasetiter_current(rdsiter, &sigrdataset);
1076		if (sigrdataset.type == dns_rdatatype_rrsig &&
1077		    sigrdataset.covers == rdataset->type)
1078			break;
1079		dns_rdataset_disassociate(&sigrdataset);
1080	}
1081	if (result != ISC_R_SUCCESS) {
1082		dns_name_format(name, namebuf, sizeof(namebuf));
1083		type_format(rdataset->type, typebuf, sizeof(typebuf));
1084		fprintf(stderr, "No signatures for %s/%s\n", namebuf, typebuf);
1085		for (i = 0; i < 256; i++)
1086			if (act_algorithms[i] != 0)
1087				bad_algorithms[i] = 1;
1088		dns_rdatasetiter_destroy(&rdsiter);
1089		return;
1090	}
1091
1092	memset(set_algorithms, 0, sizeof(set_algorithms));
1093	for (result = dns_rdataset_first(&sigrdataset);
1094	     result == ISC_R_SUCCESS;
1095	     result = dns_rdataset_next(&sigrdataset)) {
1096		dns_rdata_t rdata = DNS_RDATA_INIT;
1097		dns_rdata_rrsig_t sig;
1098
1099		dns_rdataset_current(&sigrdataset, &rdata);
1100		result = dns_rdata_tostruct(&rdata, &sig, NULL);
1101		check_result(result, "dns_rdata_tostruct()");
1102		if (rdataset->ttl != sig.originalttl) {
1103			dns_name_format(name, namebuf, sizeof(namebuf));
1104			type_format(rdataset->type, typebuf, sizeof(typebuf));
1105			fprintf(stderr, "TTL mismatch for %s %s keytag %u\n",
1106				namebuf, typebuf, sig.keyid);
1107			continue;
1108		}
1109		if ((set_algorithms[sig.algorithm] != 0) ||
1110		    (act_algorithms[sig.algorithm] == 0))
1111			continue;
1112		if (goodsig(origin, &rdata, name, keyrdataset, rdataset, mctx))
1113			set_algorithms[sig.algorithm] = 1;
1114	}
1115	dns_rdatasetiter_destroy(&rdsiter);
1116	if (memcmp(set_algorithms, act_algorithms, sizeof(set_algorithms))) {
1117		dns_name_format(name, namebuf, sizeof(namebuf));
1118		type_format(rdataset->type, typebuf, sizeof(typebuf));
1119		for (i = 0; i < 256; i++)
1120			if ((act_algorithms[i] != 0) &&
1121			    (set_algorithms[i] == 0)) {
1122				dns_secalg_format(i, algbuf, sizeof(algbuf));
1123				fprintf(stderr, "No correct %s signature for "
1124					"%s %s\n", algbuf, namebuf, typebuf);
1125				bad_algorithms[i] = 1;
1126			}
1127	}
1128	dns_rdataset_disassociate(&sigrdataset);
1129}
1130
1131static isc_result_t
1132verifynode(dns_db_t *db, dns_dbversion_t *ver, dns_name_t *origin,
1133	   isc_mem_t *mctx, dns_name_t *name, dns_dbnode_t *node,
1134	   isc_boolean_t delegation, dns_rdataset_t *keyrdataset,
1135	   unsigned char *act_algorithms, unsigned char *bad_algorithms,
1136	   dns_rdataset_t *nsecset, dns_rdataset_t *nsec3paramset,
1137	   dns_name_t *nextname)
1138{
1139	unsigned char types[8192];
1140	unsigned int maxtype = 0;
1141	dns_rdataset_t rdataset; dns_rdatasetiter_t *rdsiter = NULL;
1142	isc_result_t result, tresult;
1143
1144	memset(types, 0, sizeof(types));
1145	result = dns_db_allrdatasets(db, node, ver, 0, &rdsiter);
1146	check_result(result, "dns_db_allrdatasets()");
1147	result = dns_rdatasetiter_first(rdsiter);
1148	dns_rdataset_init(&rdataset);
1149	while (result == ISC_R_SUCCESS) {
1150		dns_rdatasetiter_current(rdsiter, &rdataset);
1151		/*
1152		 * If we are not at a delegation then everything should be
1153		 * signed.  If we are at a delegation then only the DS set
1154		 * is signed.  The NS set is not signed at a delegation but
1155		 * its existance is recorded in the bit map.  Anything else
1156		 * other than NSEC and DS is not signed at a delegation.
1157		 */
1158		if (rdataset.type != dns_rdatatype_rrsig &&
1159		    rdataset.type != dns_rdatatype_dnskey &&
1160		    (!delegation || rdataset.type == dns_rdatatype_ds ||
1161		     rdataset.type == dns_rdatatype_nsec)) {
1162			verifyset(db, ver, origin, mctx, &rdataset,
1163				  name, node, keyrdataset,
1164				  act_algorithms, bad_algorithms);
1165			dns_nsec_setbit(types, rdataset.type, 1);
1166			if (rdataset.type > maxtype)
1167				maxtype = rdataset.type;
1168		} else if (rdataset.type != dns_rdatatype_rrsig &&
1169			   rdataset.type != dns_rdatatype_dnskey) {
1170			if (rdataset.type == dns_rdatatype_ns)
1171				dns_nsec_setbit(types, rdataset.type, 1);
1172			check_no_rrsig(db, ver, &rdataset, name, node);
1173		} else
1174			dns_nsec_setbit(types, rdataset.type, 1);
1175		dns_rdataset_disassociate(&rdataset);
1176		result = dns_rdatasetiter_next(rdsiter);
1177	}
1178	if (result != ISC_R_NOMORE)
1179		fatal("rdataset iteration failed: %s",
1180		      isc_result_totext(result));
1181	dns_rdatasetiter_destroy(&rdsiter);
1182
1183	result = ISC_R_SUCCESS;
1184
1185	if (nsecset != NULL && dns_rdataset_isassociated(nsecset))
1186		result = verifynsec(db, ver, name, node, nextname);
1187
1188	if (nsec3paramset != NULL && dns_rdataset_isassociated(nsec3paramset)) {
1189		tresult = verifynsec3s(db, ver, origin, mctx, name,
1190				       nsec3paramset, delegation, ISC_FALSE,
1191				       types, maxtype);
1192		if (result == ISC_R_SUCCESS && tresult != ISC_R_SUCCESS)
1193			result = tresult;
1194	}
1195	return (result);
1196}
1197
1198static isc_boolean_t
1199is_empty(dns_db_t *db, dns_dbversion_t *ver, dns_dbnode_t *node) {
1200	dns_rdatasetiter_t *rdsiter = NULL;
1201	isc_result_t result;
1202
1203	result = dns_db_allrdatasets(db, node, ver, 0, &rdsiter);
1204	check_result(result, "dns_db_allrdatasets()");
1205	result = dns_rdatasetiter_first(rdsiter);
1206	dns_rdatasetiter_destroy(&rdsiter);
1207	if (result == ISC_R_NOMORE)
1208		return (ISC_TRUE);
1209	return (ISC_FALSE);
1210}
1211
1212static void
1213check_no_nsec(dns_name_t *name, dns_dbnode_t *node, dns_db_t *db,
1214	      dns_dbversion_t *ver)
1215{
1216	dns_rdataset_t rdataset;
1217	isc_result_t result;
1218
1219	dns_rdataset_init(&rdataset);
1220	result = dns_db_findrdataset(db, node, ver, dns_rdatatype_nsec,
1221				     0, 0, &rdataset, NULL);
1222	if (result != ISC_R_NOTFOUND) {
1223		char namebuf[DNS_NAME_FORMATSIZE];
1224		dns_name_format(name, namebuf, sizeof(namebuf));
1225		fatal("unexpected NSEC RRset at %s\n", namebuf);
1226	}
1227
1228	if (dns_rdataset_isassociated(&rdataset))
1229		dns_rdataset_disassociate(&rdataset);
1230}
1231
1232static isc_boolean_t
1233newchain(const struct nsec3_chain_fixed *first,
1234	 const struct nsec3_chain_fixed *e)
1235{
1236	if (first->hash != e->hash ||
1237	    first->iterations != e->iterations ||
1238	    first->salt_length != e->salt_length ||
1239	    first->next_length != e->next_length ||
1240	    memcmp(first + 1, e + 1, first->salt_length) != 0)
1241		return (ISC_TRUE);
1242	return (ISC_FALSE);
1243}
1244
1245static void
1246free_element(isc_mem_t *mctx, struct nsec3_chain_fixed *e) {
1247	size_t len;
1248
1249	len = sizeof(*e) + e->salt_length + 2 * e->next_length;
1250	isc_mem_put(mctx, e, len);
1251}
1252
1253static isc_boolean_t
1254checknext(const struct nsec3_chain_fixed *first,
1255	  const struct nsec3_chain_fixed *e)
1256{
1257	char buf[512];
1258	const unsigned char *d1 = (const unsigned char *)(first + 1);
1259	const unsigned char *d2 = (const unsigned char *)(e + 1);
1260	isc_buffer_t b;
1261	isc_region_t sr;
1262
1263	d1 += first->salt_length + first->next_length;
1264	d2 += e->salt_length;
1265
1266	if (memcmp(d1, d2, first->next_length) == 0)
1267		return (ISC_TRUE);
1268
1269	DE_CONST(d1 - first->next_length, sr.base);
1270	sr.length = first->next_length;
1271	isc_buffer_init(&b, buf, sizeof(buf));
1272	isc_base32hex_totext(&sr, 1, "", &b);
1273	fprintf(stderr, "Break in NSEC3 chain at: %.*s\n",
1274		(int) isc_buffer_usedlength(&b), buf);
1275
1276	DE_CONST(d1, sr.base);
1277	sr.length = first->next_length;
1278	isc_buffer_init(&b, buf, sizeof(buf));
1279	isc_base32hex_totext(&sr, 1, "", &b);
1280	fprintf(stderr, "Expected: %.*s\n", (int) isc_buffer_usedlength(&b),
1281		buf);
1282
1283	DE_CONST(d2, sr.base);
1284	sr.length = first->next_length;
1285	isc_buffer_init(&b, buf, sizeof(buf));
1286	isc_base32hex_totext(&sr, 1, "", &b);
1287	fprintf(stderr, "Found: %.*s\n", (int) isc_buffer_usedlength(&b), buf);
1288
1289	return (ISC_FALSE);
1290}
1291
1292#define EXPECTEDANDFOUND "Expected and found NSEC3 chains not equal\n"
1293
1294static isc_result_t
1295verify_nsec3_chains(isc_mem_t *mctx) {
1296	isc_result_t result = ISC_R_SUCCESS;
1297	struct nsec3_chain_fixed *e, *f = NULL;
1298	struct nsec3_chain_fixed *first = NULL, *prev = NULL;
1299
1300	while ((e = isc_heap_element(expected_chains, 1)) != NULL) {
1301		isc_heap_delete(expected_chains, 1);
1302		if (f == NULL)
1303			f = isc_heap_element(found_chains, 1);
1304		if (f != NULL) {
1305			isc_heap_delete(found_chains, 1);
1306
1307			/*
1308			 * Check that they match.
1309			 */
1310			if (chain_equal(e, f)) {
1311				free_element(mctx, f);
1312				f = NULL;
1313			} else {
1314				if (result == ISC_R_SUCCESS)
1315					fprintf(stderr, EXPECTEDANDFOUND);
1316				result = ISC_R_FAILURE;
1317				/*
1318				 * Attempt to resync found_chain.
1319				 */
1320				while (f != NULL && !chain_compare(e, f)) {
1321					free_element(mctx, f);
1322					f = isc_heap_element(found_chains, 1);
1323					if (f != NULL)
1324						isc_heap_delete(found_chains, 1);
1325					if (f != NULL && chain_equal(e, f)) {
1326						free_element(mctx, f);
1327						f = NULL;
1328						break;
1329					}
1330				}
1331			}
1332		} else if (result == ISC_R_SUCCESS) {
1333			fprintf(stderr, EXPECTEDANDFOUND);
1334			result = ISC_R_FAILURE;
1335		}
1336		if (first == NULL || newchain(first, e)) {
1337			if (prev != NULL) {
1338				if (!checknext(prev, first))
1339					result = ISC_R_FAILURE;
1340				if (prev != first)
1341					free_element(mctx, prev);
1342			}
1343			if (first != NULL)
1344				free_element(mctx, first);
1345			prev = first = e;
1346			continue;
1347		}
1348		if (!checknext(prev, e))
1349			result = ISC_R_FAILURE;
1350		if (prev != first)
1351			free_element(mctx, prev);
1352		prev = e;
1353	}
1354	if (prev != NULL) {
1355		if (!checknext(prev, first))
1356			result = ISC_R_FAILURE;
1357		if (prev != first)
1358			free_element(mctx, prev);
1359	}
1360	if (first != NULL)
1361		free_element(mctx, first);
1362	do {
1363		if (f != NULL) {
1364			if (result == ISC_R_SUCCESS) {
1365				fprintf(stderr, EXPECTEDANDFOUND);
1366				result = ISC_R_FAILURE;
1367			}
1368			free_element(mctx, f);
1369		}
1370		f = isc_heap_element(found_chains, 1);
1371		if (f != NULL)
1372			isc_heap_delete(found_chains, 1);
1373	} while (f != NULL);
1374
1375	return (result);
1376}
1377
1378static isc_result_t
1379verifyemptynodes(dns_db_t *db, dns_dbversion_t *ver, dns_name_t *origin,
1380		 isc_mem_t *mctx, dns_name_t *name, dns_name_t *prevname,
1381		 isc_boolean_t isdelegation, dns_rdataset_t *nsec3paramset)
1382{
1383	dns_namereln_t reln;
1384	int order;
1385	unsigned int labels, nlabels, i;
1386	dns_name_t suffix;
1387	isc_result_t result = ISC_R_SUCCESS, tresult;
1388
1389	reln = dns_name_fullcompare(prevname, name, &order, &labels);
1390	if (order >= 0)
1391		return (result);
1392
1393	nlabels = dns_name_countlabels(name);
1394
1395	if (reln == dns_namereln_commonancestor ||
1396	    reln == dns_namereln_contains) {
1397		dns_name_init(&suffix, NULL);
1398		for (i = labels + 1; i < nlabels; i++) {
1399			dns_name_getlabelsequence(name, nlabels - i, i,
1400						  &suffix);
1401			if (nsec3paramset != NULL &&
1402			     dns_rdataset_isassociated(nsec3paramset)) {
1403				tresult = verifynsec3s(db, ver, origin, mctx,
1404						       &suffix, nsec3paramset,
1405						       isdelegation, ISC_TRUE,
1406						       NULL, 0);
1407				if (result == ISC_R_SUCCESS &&
1408				    tresult != ISC_R_SUCCESS)
1409					result = tresult;
1410			}
1411		}
1412	}
1413	return (result);
1414}
1415
1416/*%
1417 * Verify that certain things are sane:
1418 *
1419 *   The apex has a DNSKEY record with at least one KSK, and at least
1420 *   one ZSK if the -x flag was not used.
1421 *
1422 *   The DNSKEY record was signed with at least one of the KSKs in this
1423 *   set.
1424 *
1425 *   The rest of the zone was signed with at least one of the ZSKs
1426 *   present in the DNSKEY RRSET.
1427 */
1428void
1429verifyzone(dns_db_t *db, dns_dbversion_t *ver,
1430	   dns_name_t *origin, isc_mem_t *mctx,
1431	   isc_boolean_t ignore_kskflag, isc_boolean_t keyset_kskonly)
1432{
1433	char algbuf[80];
1434	dns_dbiterator_t *dbiter = NULL;
1435	dns_dbnode_t *node = NULL, *nextnode = NULL;
1436	dns_fixedname_t fname, fnextname, fprevname, fzonecut;
1437	dns_name_t *name, *nextname, *prevname, *zonecut;
1438	dns_rdata_dnskey_t dnskey;
1439	dns_rdata_t rdata = DNS_RDATA_INIT;
1440	dns_rdataset_t keyset, soaset;
1441	dns_rdataset_t keysigs, soasigs;
1442	dns_rdataset_t nsecset, nsecsigs;
1443	dns_rdataset_t nsec3paramset, nsec3paramsigs;
1444	int i;
1445	isc_boolean_t done = ISC_FALSE;
1446	isc_boolean_t first = ISC_TRUE;
1447	isc_boolean_t goodksk = ISC_FALSE;
1448	isc_boolean_t goodzsk = ISC_FALSE;
1449	isc_result_t result, vresult = ISC_R_UNSET;
1450	unsigned char revoked_ksk[256];
1451	unsigned char revoked_zsk[256];
1452	unsigned char standby_ksk[256];
1453	unsigned char standby_zsk[256];
1454	unsigned char ksk_algorithms[256];
1455	unsigned char zsk_algorithms[256];
1456	unsigned char bad_algorithms[256];
1457	unsigned char act_algorithms[256];
1458
1459	result = isc_heap_create(mctx, chain_compare, NULL, 1024,
1460				 &expected_chains);
1461	check_result(result, "isc_heap_create()");
1462	result = isc_heap_create(mctx, chain_compare, NULL, 1024,
1463				 &found_chains);
1464	check_result(result, "isc_heap_create()");
1465
1466	result = dns_db_findnode(db, origin, ISC_FALSE, &node);
1467	if (result != ISC_R_SUCCESS)
1468		fatal("failed to find the zone's origin: %s",
1469		      isc_result_totext(result));
1470
1471	dns_rdataset_init(&keyset);
1472	dns_rdataset_init(&keysigs);
1473	dns_rdataset_init(&soaset);
1474	dns_rdataset_init(&soasigs);
1475	dns_rdataset_init(&nsecset);
1476	dns_rdataset_init(&nsecsigs);
1477	dns_rdataset_init(&nsec3paramset);
1478	dns_rdataset_init(&nsec3paramsigs);
1479	result = dns_db_findrdataset(db, node, ver, dns_rdatatype_dnskey,
1480				     0, 0, &keyset, &keysigs);
1481	if (result != ISC_R_SUCCESS)
1482		fatal("Zone contains no DNSSEC keys\n");
1483
1484	result = dns_db_findrdataset(db, node, ver, dns_rdatatype_soa,
1485				     0, 0, &soaset, &soasigs);
1486	if (result != ISC_R_SUCCESS)
1487		fatal("Zone contains no SOA record\n");
1488
1489	result = dns_db_findrdataset(db, node, ver, dns_rdatatype_nsec,
1490				     0, 0, &nsecset, &nsecsigs);
1491	if (result != ISC_R_SUCCESS && result != ISC_R_NOTFOUND)
1492		fatal("NSEC lookup failed\n");
1493
1494	result = dns_db_findrdataset(db, node, ver, dns_rdatatype_nsec3param,
1495				     0, 0, &nsec3paramset, &nsec3paramsigs);
1496	if (result != ISC_R_SUCCESS && result != ISC_R_NOTFOUND)
1497		fatal("NSEC3PARAM lookup failed\n");
1498
1499	if (!dns_rdataset_isassociated(&keysigs))
1500		fatal("DNSKEY is not signed (keys offline or inactive?)\n");
1501
1502	if (!dns_rdataset_isassociated(&soasigs))
1503		fatal("SOA is not signed (keys offline or inactive?)\n");
1504
1505	if (dns_rdataset_isassociated(&nsecset) &&
1506	    !dns_rdataset_isassociated(&nsecsigs))
1507		fatal("NSEC is not signed (keys offline or inactive?)\n");
1508
1509	if (dns_rdataset_isassociated(&nsec3paramset) &&
1510	    !dns_rdataset_isassociated(&nsec3paramsigs))
1511		fatal("NSEC3PARAM is not signed (keys offline or inactive?)\n");
1512
1513	if (!dns_rdataset_isassociated(&nsecset) &&
1514	    !dns_rdataset_isassociated(&nsec3paramset))
1515		fatal("No valid NSEC/NSEC3 chain for testing\n");
1516
1517	dns_db_detachnode(db, &node);
1518
1519	memset(revoked_ksk, 0, sizeof(revoked_ksk));
1520	memset(revoked_zsk, 0, sizeof(revoked_zsk));
1521	memset(standby_ksk, 0, sizeof(standby_ksk));
1522	memset(standby_zsk, 0, sizeof(standby_zsk));
1523	memset(ksk_algorithms, 0, sizeof(ksk_algorithms));
1524	memset(zsk_algorithms, 0, sizeof(zsk_algorithms));
1525	memset(bad_algorithms, 0, sizeof(bad_algorithms));
1526	memset(act_algorithms, 0, sizeof(act_algorithms));
1527
1528	/*
1529	 * Check that the DNSKEY RR has at least one self signing KSK
1530	 * and one ZSK per algorithm in it (or, if -x was used, one
1531	 * self-signing KSK).
1532	 */
1533	for (result = dns_rdataset_first(&keyset);
1534	     result == ISC_R_SUCCESS;
1535	     result = dns_rdataset_next(&keyset)) {
1536		dns_rdataset_current(&keyset, &rdata);
1537		result = dns_rdata_tostruct(&rdata, &dnskey, NULL);
1538		check_result(result, "dns_rdata_tostruct");
1539
1540		if ((dnskey.flags & DNS_KEYOWNER_ZONE) == 0)
1541			;
1542		else if ((dnskey.flags & DNS_KEYFLAG_REVOKE) != 0) {
1543			if ((dnskey.flags & DNS_KEYFLAG_KSK) != 0 &&
1544			    !dns_dnssec_selfsigns(&rdata, origin, &keyset,
1545						  &keysigs, ISC_FALSE,
1546						  mctx)) {
1547				char namebuf[DNS_NAME_FORMATSIZE];
1548				char buffer[1024];
1549				isc_buffer_t buf;
1550
1551				dns_name_format(origin, namebuf,
1552						sizeof(namebuf));
1553				isc_buffer_init(&buf, buffer, sizeof(buffer));
1554				result = dns_rdata_totext(&rdata, NULL, &buf);
1555				check_result(result, "dns_rdata_totext");
1556				fatal("revoked KSK is not self signed:\n"
1557				      "%s DNSKEY %.*s", namebuf,
1558				      (int)isc_buffer_usedlength(&buf), buffer);
1559			}
1560			if ((dnskey.flags & DNS_KEYFLAG_KSK) != 0 &&
1561			     revoked_ksk[dnskey.algorithm] != 255)
1562				revoked_ksk[dnskey.algorithm]++;
1563			else if ((dnskey.flags & DNS_KEYFLAG_KSK) == 0 &&
1564				 revoked_zsk[dnskey.algorithm] != 255)
1565				revoked_zsk[dnskey.algorithm]++;
1566		} else if ((dnskey.flags & DNS_KEYFLAG_KSK) != 0) {
1567			if (dns_dnssec_selfsigns(&rdata, origin, &keyset,
1568						 &keysigs, ISC_FALSE, mctx)) {
1569				if (ksk_algorithms[dnskey.algorithm] != 255)
1570					ksk_algorithms[dnskey.algorithm]++;
1571				goodksk = ISC_TRUE;
1572			} else {
1573				if (standby_ksk[dnskey.algorithm] != 255)
1574					standby_ksk[dnskey.algorithm]++;
1575			}
1576		} else if (dns_dnssec_selfsigns(&rdata, origin, &keyset,
1577						&keysigs, ISC_FALSE, mctx)) {
1578			if (zsk_algorithms[dnskey.algorithm] != 255)
1579				zsk_algorithms[dnskey.algorithm]++;
1580			goodzsk = ISC_TRUE;
1581		} else if (dns_dnssec_signs(&rdata, origin, &soaset,
1582					    &soasigs, ISC_FALSE, mctx)) {
1583			if (zsk_algorithms[dnskey.algorithm] != 255)
1584				zsk_algorithms[dnskey.algorithm]++;
1585		} else {
1586			if (standby_zsk[dnskey.algorithm] != 255)
1587				standby_zsk[dnskey.algorithm]++;
1588		}
1589		dns_rdata_freestruct(&dnskey);
1590		dns_rdata_reset(&rdata);
1591	}
1592	dns_rdataset_disassociate(&keysigs);
1593	dns_rdataset_disassociate(&soaset);
1594	dns_rdataset_disassociate(&soasigs);
1595	if (dns_rdataset_isassociated(&nsecsigs))
1596		dns_rdataset_disassociate(&nsecsigs);
1597	if (dns_rdataset_isassociated(&nsec3paramsigs))
1598		dns_rdataset_disassociate(&nsec3paramsigs);
1599
1600	if (ignore_kskflag ) {
1601		if (!goodksk && !goodzsk)
1602			fatal("No self-signed DNSKEY found.");
1603	} else if (!goodksk)
1604		fatal("No self-signed KSK DNSKEY found.  Supply an active\n"
1605		      "key with the KSK flag set, or use '-P'.");
1606
1607	fprintf(stderr, "Verifying the zone using the following algorithms:");
1608	for (i = 0; i < 256; i++) {
1609		if (ignore_kskflag)
1610			act_algorithms[i] = (ksk_algorithms[i] != 0 ||
1611					     zsk_algorithms[i] != 0) ? 1 : 0;
1612		else
1613			act_algorithms[i] = ksk_algorithms[i] != 0 ? 1 : 0;
1614		if (act_algorithms[i] != 0) {
1615			dns_secalg_format(i, algbuf, sizeof(algbuf));
1616			fprintf(stderr, " %s", algbuf);
1617		}
1618	}
1619	fprintf(stderr, ".\n");
1620
1621	if (!ignore_kskflag && !keyset_kskonly) {
1622		for (i = 0; i < 256; i++) {
1623			/*
1624			 * The counts should both be zero or both be non-zero.
1625			 * Mark the algorithm as bad if this is not met.
1626			 */
1627			if ((ksk_algorithms[i] != 0) ==
1628			    (zsk_algorithms[i] != 0))
1629				continue;
1630			dns_secalg_format(i, algbuf, sizeof(algbuf));
1631			fprintf(stderr, "Missing %s for algorithm %s\n",
1632				(ksk_algorithms[i] != 0)
1633				   ? "ZSK"
1634				   : "self-signed KSK",
1635				algbuf);
1636			bad_algorithms[i] = 1;
1637		}
1638	}
1639
1640	/*
1641	 * Check that all the other records were signed by keys that are
1642	 * present in the DNSKEY RRSET.
1643	 */
1644
1645	dns_fixedname_init(&fname);
1646	name = dns_fixedname_name(&fname);
1647	dns_fixedname_init(&fnextname);
1648	nextname = dns_fixedname_name(&fnextname);
1649	dns_fixedname_init(&fprevname);
1650	prevname = NULL;
1651	dns_fixedname_init(&fzonecut);
1652	zonecut = NULL;
1653
1654	result = dns_db_createiterator(db, DNS_DB_NONSEC3, &dbiter);
1655	check_result(result, "dns_db_createiterator()");
1656
1657	result = dns_dbiterator_first(dbiter);
1658	check_result(result, "dns_dbiterator_first()");
1659
1660	while (!done) {
1661		isc_boolean_t isdelegation = ISC_FALSE;
1662
1663		result = dns_dbiterator_current(dbiter, &node, name);
1664		check_dns_dbiterator_current(result);
1665		if (!dns_name_issubdomain(name, origin)) {
1666			check_no_nsec(name, node, db, ver);
1667			dns_db_detachnode(db, &node);
1668			result = dns_dbiterator_next(dbiter);
1669			if (result == ISC_R_NOMORE)
1670				done = ISC_TRUE;
1671			else
1672				check_result(result, "dns_dbiterator_next()");
1673			continue;
1674		}
1675		if (is_delegation(db, ver, origin, name, node, NULL)) {
1676			zonecut = dns_fixedname_name(&fzonecut);
1677			dns_name_copy(name, zonecut, NULL);
1678			isdelegation = ISC_TRUE;
1679		}
1680		nextnode = NULL;
1681		result = dns_dbiterator_next(dbiter);
1682		while (result == ISC_R_SUCCESS) {
1683			result = dns_dbiterator_current(dbiter, &nextnode,
1684							nextname);
1685			check_dns_dbiterator_current(result);
1686			if (!dns_name_issubdomain(nextname, origin) ||
1687			    (zonecut != NULL &&
1688			     dns_name_issubdomain(nextname, zonecut)))
1689			{
1690				check_no_nsec(nextname, nextnode, db, ver);
1691				dns_db_detachnode(db, &nextnode);
1692				result = dns_dbiterator_next(dbiter);
1693				continue;
1694			}
1695			if (is_empty(db, ver, nextnode)) {
1696				dns_db_detachnode(db, &nextnode);
1697				result = dns_dbiterator_next(dbiter);
1698				continue;
1699			}
1700			dns_db_detachnode(db, &nextnode);
1701			break;
1702		}
1703		if (result == ISC_R_NOMORE) {
1704			done = ISC_TRUE;
1705			nextname = origin;
1706		} else if (result != ISC_R_SUCCESS)
1707			fatal("iterating through the database failed: %s",
1708			      isc_result_totext(result));
1709		result = verifynode(db, ver, origin, mctx, name, node,
1710				    isdelegation, &keyset, act_algorithms,
1711				    bad_algorithms, &nsecset, &nsec3paramset,
1712				    nextname);
1713		if (vresult == ISC_R_UNSET)
1714			vresult = ISC_R_SUCCESS;
1715		if (vresult == ISC_R_SUCCESS && result != ISC_R_SUCCESS)
1716			vresult = result;
1717		if (prevname != NULL) {
1718			result = verifyemptynodes(db, ver, origin, mctx, name,
1719						  prevname, isdelegation,
1720						  &nsec3paramset);
1721		} else
1722			prevname = dns_fixedname_name(&fprevname);
1723		dns_name_copy(name, prevname, NULL);
1724		if (vresult == ISC_R_SUCCESS && result != ISC_R_SUCCESS)
1725			vresult = result;
1726		dns_db_detachnode(db, &node);
1727	}
1728
1729	dns_dbiterator_destroy(&dbiter);
1730
1731	result = dns_db_createiterator(db, DNS_DB_NSEC3ONLY, &dbiter);
1732	check_result(result, "dns_db_createiterator()");
1733
1734	for (result = dns_dbiterator_first(dbiter);
1735	     result == ISC_R_SUCCESS;
1736	     result = dns_dbiterator_next(dbiter) ) {
1737		result = dns_dbiterator_current(dbiter, &node, name);
1738		check_dns_dbiterator_current(result);
1739		result = verifynode(db, ver, origin, mctx, name, node,
1740				    ISC_FALSE, &keyset, act_algorithms,
1741				    bad_algorithms, NULL, NULL, NULL);
1742		check_result(result, "verifynode");
1743		record_found(db, ver, mctx, name, node, &nsec3paramset);
1744		dns_db_detachnode(db, &node);
1745	}
1746	dns_dbiterator_destroy(&dbiter);
1747
1748	dns_rdataset_disassociate(&keyset);
1749	if (dns_rdataset_isassociated(&nsecset))
1750		dns_rdataset_disassociate(&nsecset);
1751	if (dns_rdataset_isassociated(&nsec3paramset))
1752		dns_rdataset_disassociate(&nsec3paramset);
1753
1754	result = verify_nsec3_chains(mctx);
1755	if (vresult == ISC_R_UNSET)
1756		vresult = ISC_R_SUCCESS;
1757	if (result != ISC_R_SUCCESS && vresult == ISC_R_SUCCESS)
1758		vresult = result;
1759	isc_heap_destroy(&expected_chains);
1760	isc_heap_destroy(&found_chains);
1761
1762	/*
1763	 * If we made it this far, we have what we consider a properly signed
1764	 * zone.  Set the good flag.
1765	 */
1766	for (i = 0; i < 256; i++) {
1767		if (bad_algorithms[i] != 0) {
1768			if (first)
1769				fprintf(stderr, "The zone is not fully signed "
1770					"for the following algorithms:");
1771			dns_secalg_format(i, algbuf, sizeof(algbuf));
1772			fprintf(stderr, " %s", algbuf);
1773			first = ISC_FALSE;
1774		}
1775	}
1776	if (!first) {
1777		fprintf(stderr, ".\n");
1778		fatal("DNSSEC completeness test failed.");
1779	}
1780
1781	if (vresult != ISC_R_SUCCESS)
1782		fatal("DNSSEC completeness test failed (%s).",
1783		      dns_result_totext(vresult));
1784
1785	if (goodksk || ignore_kskflag) {
1786		/*
1787		 * Print the success summary.
1788		 */
1789		fprintf(stderr, "Zone fully signed:\n");
1790		for (i = 0; i < 256; i++) {
1791			if ((ksk_algorithms[i] != 0) ||
1792			    (standby_ksk[i] != 0) ||
1793			    (revoked_zsk[i] != 0) ||
1794			    (zsk_algorithms[i] != 0) ||
1795			    (standby_zsk[i] != 0) ||
1796			    (revoked_zsk[i] != 0)) {
1797				dns_secalg_format(i, algbuf, sizeof(algbuf));
1798				fprintf(stderr, "Algorithm: %s: KSKs: "
1799					"%u active, %u stand-by, %u revoked\n",
1800					algbuf, ksk_algorithms[i],
1801					standby_ksk[i], revoked_ksk[i]);
1802				fprintf(stderr, "%*sZSKs: "
1803					"%u active, %u %s, %u revoked\n",
1804					(int) strlen(algbuf) + 13, "",
1805					zsk_algorithms[i],
1806					standby_zsk[i],
1807					keyset_kskonly ? "present" : "stand-by",
1808					revoked_zsk[i]);
1809			}
1810		}
1811	}
1812}
1813