1/*
2 * Copyright (C) 2004-2014  Internet Systems Consortium, Inc. ("ISC")
3 * Copyright (C) 1999-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/*
19 * $Id$
20 */
21
22/*! \file */
23
24#include <config.h>
25
26#include <stdlib.h>
27
28#include <isc/buffer.h>
29#include <isc/dir.h>
30#include <isc/mem.h>
31#include <isc/serial.h>
32#include <isc/string.h>
33#include <isc/util.h>
34
35#include <dns/db.h>
36#include <dns/diff.h>
37#include <dns/dnssec.h>
38#include <dns/fixedname.h>
39#include <dns/keyvalues.h>
40#include <dns/log.h>
41#include <dns/message.h>
42#include <dns/rdata.h>
43#include <dns/rdatalist.h>
44#include <dns/rdataset.h>
45#include <dns/rdatastruct.h>
46#include <dns/result.h>
47#include <dns/stats.h>
48#include <dns/tsig.h>		/* for DNS_TSIG_FUDGE */
49
50#include <dst/result.h>
51
52LIBDNS_EXTERNAL_DATA isc_stats_t *dns_dnssec_stats;
53
54#define is_response(msg) (msg->flags & DNS_MESSAGEFLAG_QR)
55
56#define RETERR(x) do { \
57	result = (x); \
58	if (result != ISC_R_SUCCESS) \
59		goto failure; \
60	} while (0)
61
62
63#define TYPE_SIGN 0
64#define TYPE_VERIFY 1
65
66static isc_result_t
67digest_callback(void *arg, isc_region_t *data);
68
69static int
70rdata_compare_wrapper(const void *rdata1, const void *rdata2);
71
72static isc_result_t
73rdataset_to_sortedarray(dns_rdataset_t *set, isc_mem_t *mctx,
74			dns_rdata_t **rdata, int *nrdata);
75
76static isc_result_t
77digest_callback(void *arg, isc_region_t *data) {
78	dst_context_t *ctx = arg;
79
80	return (dst_context_adddata(ctx, data));
81}
82
83static inline void
84inc_stat(isc_statscounter_t counter) {
85	if (dns_dnssec_stats != NULL)
86		isc_stats_increment(dns_dnssec_stats, counter);
87}
88
89/*
90 * Make qsort happy.
91 */
92static int
93rdata_compare_wrapper(const void *rdata1, const void *rdata2) {
94	return (dns_rdata_compare((const dns_rdata_t *)rdata1,
95				  (const dns_rdata_t *)rdata2));
96}
97
98/*
99 * Sort the rdataset into an array.
100 */
101static isc_result_t
102rdataset_to_sortedarray(dns_rdataset_t *set, isc_mem_t *mctx,
103			dns_rdata_t **rdata, int *nrdata)
104{
105	isc_result_t ret;
106	int i = 0, n;
107	dns_rdata_t *data;
108	dns_rdataset_t rdataset;
109
110	n = dns_rdataset_count(set);
111
112	data = isc_mem_get(mctx, n * sizeof(dns_rdata_t));
113	if (data == NULL)
114		return (ISC_R_NOMEMORY);
115
116	dns_rdataset_init(&rdataset);
117	dns_rdataset_clone(set, &rdataset);
118	ret = dns_rdataset_first(&rdataset);
119	if (ret != ISC_R_SUCCESS) {
120		dns_rdataset_disassociate(&rdataset);
121		isc_mem_put(mctx, data, n * sizeof(dns_rdata_t));
122		return (ret);
123	}
124
125	/*
126	 * Put them in the array.
127	 */
128	do {
129		dns_rdata_init(&data[i]);
130		dns_rdataset_current(&rdataset, &data[i++]);
131	} while (dns_rdataset_next(&rdataset) == ISC_R_SUCCESS);
132
133	/*
134	 * Sort the array.
135	 */
136	qsort(data, n, sizeof(dns_rdata_t), rdata_compare_wrapper);
137	*rdata = data;
138	*nrdata = n;
139	dns_rdataset_disassociate(&rdataset);
140	return (ISC_R_SUCCESS);
141}
142
143isc_result_t
144dns_dnssec_keyfromrdata(dns_name_t *name, dns_rdata_t *rdata, isc_mem_t *mctx,
145			dst_key_t **key)
146{
147	isc_buffer_t b;
148	isc_region_t r;
149
150	INSIST(name != NULL);
151	INSIST(rdata != NULL);
152	INSIST(mctx != NULL);
153	INSIST(key != NULL);
154	INSIST(*key == NULL);
155	REQUIRE(rdata->type == dns_rdatatype_key ||
156		rdata->type == dns_rdatatype_dnskey);
157
158	dns_rdata_toregion(rdata, &r);
159	isc_buffer_init(&b, r.base, r.length);
160	isc_buffer_add(&b, r.length);
161	return (dst_key_fromdns(name, rdata->rdclass, &b, mctx, key));
162}
163
164static isc_result_t
165digest_sig(dst_context_t *ctx, isc_boolean_t downcase, dns_rdata_t *sigrdata,
166	   dns_rdata_rrsig_t *rrsig)
167{
168	isc_region_t r;
169	isc_result_t ret;
170	dns_fixedname_t fname;
171
172	dns_rdata_toregion(sigrdata, &r);
173	INSIST(r.length >= 19);
174
175	r.length = 18;
176	ret = dst_context_adddata(ctx, &r);
177	if (ret != ISC_R_SUCCESS)
178		return (ret);
179	if (downcase) {
180		dns_fixedname_init(&fname);
181
182		RUNTIME_CHECK(dns_name_downcase(&rrsig->signer,
183						dns_fixedname_name(&fname),
184						NULL) == ISC_R_SUCCESS);
185		dns_name_toregion(dns_fixedname_name(&fname), &r);
186	} else
187		dns_name_toregion(&rrsig->signer, &r);
188
189	return (dst_context_adddata(ctx, &r));
190}
191
192isc_result_t
193dns_dnssec_sign(dns_name_t *name, dns_rdataset_t *set, dst_key_t *key,
194		isc_stdtime_t *inception, isc_stdtime_t *expire,
195		isc_mem_t *mctx, isc_buffer_t *buffer, dns_rdata_t *sigrdata)
196{
197	dns_rdata_rrsig_t sig;
198	dns_rdata_t tmpsigrdata;
199	dns_rdata_t *rdatas;
200	int nrdatas, i;
201	isc_buffer_t sigbuf, envbuf;
202	isc_region_t r;
203	dst_context_t *ctx = NULL;
204	isc_result_t ret;
205	isc_buffer_t *databuf = NULL;
206	char data[256 + 8];
207	isc_uint32_t flags;
208	unsigned int sigsize;
209	dns_fixedname_t fnewname;
210	dns_fixedname_t fsigner;
211
212	REQUIRE(name != NULL);
213	REQUIRE(dns_name_countlabels(name) <= 255);
214	REQUIRE(set != NULL);
215	REQUIRE(key != NULL);
216	REQUIRE(inception != NULL);
217	REQUIRE(expire != NULL);
218	REQUIRE(mctx != NULL);
219	REQUIRE(sigrdata != NULL);
220
221	if (*inception >= *expire)
222		return (DNS_R_INVALIDTIME);
223
224	/*
225	 * Is the key allowed to sign data?
226	 */
227	flags = dst_key_flags(key);
228	if (flags & DNS_KEYTYPE_NOAUTH)
229		return (DNS_R_KEYUNAUTHORIZED);
230	if ((flags & DNS_KEYFLAG_OWNERMASK) != DNS_KEYOWNER_ZONE)
231		return (DNS_R_KEYUNAUTHORIZED);
232
233	sig.mctx = mctx;
234	sig.common.rdclass = set->rdclass;
235	sig.common.rdtype = dns_rdatatype_rrsig;
236	ISC_LINK_INIT(&sig.common, link);
237
238	/*
239	 * Downcase signer.
240	 */
241	dns_name_init(&sig.signer, NULL);
242	dns_fixedname_init(&fsigner);
243	RUNTIME_CHECK(dns_name_downcase(dst_key_name(key),
244		      dns_fixedname_name(&fsigner), NULL) == ISC_R_SUCCESS);
245	dns_name_clone(dns_fixedname_name(&fsigner), &sig.signer);
246
247	sig.covered = set->type;
248	sig.algorithm = dst_key_alg(key);
249	sig.labels = dns_name_countlabels(name) - 1;
250	if (dns_name_iswildcard(name))
251		sig.labels--;
252	sig.originalttl = set->ttl;
253	sig.timesigned = *inception;
254	sig.timeexpire = *expire;
255	sig.keyid = dst_key_id(key);
256	ret = dst_key_sigsize(key, &sigsize);
257	if (ret != ISC_R_SUCCESS)
258		return (ret);
259	sig.siglen = sigsize;
260	/*
261	 * The actual contents of sig.signature are not important yet, since
262	 * they're not used in digest_sig().
263	 */
264	sig.signature = isc_mem_get(mctx, sig.siglen);
265	if (sig.signature == NULL)
266		return (ISC_R_NOMEMORY);
267
268	ret = isc_buffer_allocate(mctx, &databuf, sigsize + 256 + 18);
269	if (ret != ISC_R_SUCCESS)
270		goto cleanup_signature;
271
272	dns_rdata_init(&tmpsigrdata);
273	ret = dns_rdata_fromstruct(&tmpsigrdata, sig.common.rdclass,
274				   sig.common.rdtype, &sig, databuf);
275	if (ret != ISC_R_SUCCESS)
276		goto cleanup_databuf;
277
278	ret = dst_context_create2(key, mctx, DNS_LOGCATEGORY_DNSSEC, &ctx);
279	if (ret != ISC_R_SUCCESS)
280		goto cleanup_databuf;
281
282	/*
283	 * Digest the SIG rdata.
284	 */
285	ret = digest_sig(ctx, ISC_FALSE, &tmpsigrdata, &sig);
286	if (ret != ISC_R_SUCCESS)
287		goto cleanup_context;
288
289	dns_fixedname_init(&fnewname);
290	RUNTIME_CHECK(dns_name_downcase(name, dns_fixedname_name(&fnewname),
291					NULL) == ISC_R_SUCCESS);
292	dns_name_toregion(dns_fixedname_name(&fnewname), &r);
293
294	/*
295	 * Create an envelope for each rdata: <name|type|class|ttl>.
296	 */
297	isc_buffer_init(&envbuf, data, sizeof(data));
298	memmove(data, r.base, r.length);
299	isc_buffer_add(&envbuf, r.length);
300	isc_buffer_putuint16(&envbuf, set->type);
301	isc_buffer_putuint16(&envbuf, set->rdclass);
302	isc_buffer_putuint32(&envbuf, set->ttl);
303
304	ret = rdataset_to_sortedarray(set, mctx, &rdatas, &nrdatas);
305	if (ret != ISC_R_SUCCESS)
306		goto cleanup_context;
307	isc_buffer_usedregion(&envbuf, &r);
308
309	for (i = 0; i < nrdatas; i++) {
310		isc_uint16_t len;
311		isc_buffer_t lenbuf;
312		isc_region_t lenr;
313
314		/*
315		 * Skip duplicates.
316		 */
317		if (i > 0 && dns_rdata_compare(&rdatas[i], &rdatas[i-1]) == 0)
318		    continue;
319
320		/*
321		 * Digest the envelope.
322		 */
323		ret = dst_context_adddata(ctx, &r);
324		if (ret != ISC_R_SUCCESS)
325			goto cleanup_array;
326
327		/*
328		 * Digest the length of the rdata.
329		 */
330		isc_buffer_init(&lenbuf, &len, sizeof(len));
331		INSIST(rdatas[i].length < 65536);
332		isc_buffer_putuint16(&lenbuf, (isc_uint16_t)rdatas[i].length);
333		isc_buffer_usedregion(&lenbuf, &lenr);
334		ret = dst_context_adddata(ctx, &lenr);
335		if (ret != ISC_R_SUCCESS)
336			goto cleanup_array;
337
338		/*
339		 * Digest the rdata.
340		 */
341		ret = dns_rdata_digest(&rdatas[i], digest_callback, ctx);
342		if (ret != ISC_R_SUCCESS)
343			goto cleanup_array;
344	}
345
346	isc_buffer_init(&sigbuf, sig.signature, sig.siglen);
347	ret = dst_context_sign(ctx, &sigbuf);
348	if (ret != ISC_R_SUCCESS)
349		goto cleanup_array;
350	isc_buffer_usedregion(&sigbuf, &r);
351	if (r.length != sig.siglen) {
352		ret = ISC_R_NOSPACE;
353		goto cleanup_array;
354	}
355
356	ret = dns_rdata_fromstruct(sigrdata, sig.common.rdclass,
357				   sig.common.rdtype, &sig, buffer);
358
359cleanup_array:
360	isc_mem_put(mctx, rdatas, nrdatas * sizeof(dns_rdata_t));
361cleanup_context:
362	dst_context_destroy(&ctx);
363cleanup_databuf:
364	isc_buffer_free(&databuf);
365cleanup_signature:
366	isc_mem_put(mctx, sig.signature, sig.siglen);
367
368	return (ret);
369}
370
371isc_result_t
372dns_dnssec_verify2(dns_name_t *name, dns_rdataset_t *set, dst_key_t *key,
373		   isc_boolean_t ignoretime, isc_mem_t *mctx,
374		   dns_rdata_t *sigrdata, dns_name_t *wild)
375{
376	return (dns_dnssec_verify3(name, set, key, ignoretime, 0, mctx,
377				   sigrdata, wild));
378}
379
380isc_result_t
381dns_dnssec_verify3(dns_name_t *name, dns_rdataset_t *set, dst_key_t *key,
382		   isc_boolean_t ignoretime, unsigned int maxbits,
383		   isc_mem_t *mctx, dns_rdata_t *sigrdata, dns_name_t *wild)
384{
385	dns_rdata_rrsig_t sig;
386	dns_fixedname_t fnewname;
387	isc_region_t r;
388	isc_buffer_t envbuf;
389	dns_rdata_t *rdatas;
390	int nrdatas, i;
391	isc_stdtime_t now;
392	isc_result_t ret;
393	unsigned char data[300];
394	dst_context_t *ctx = NULL;
395	int labels = 0;
396	isc_uint32_t flags;
397	isc_boolean_t downcase = ISC_FALSE;
398
399	REQUIRE(name != NULL);
400	REQUIRE(set != NULL);
401	REQUIRE(key != NULL);
402	REQUIRE(mctx != NULL);
403	REQUIRE(sigrdata != NULL && sigrdata->type == dns_rdatatype_rrsig);
404
405	ret = dns_rdata_tostruct(sigrdata, &sig, NULL);
406	if (ret != ISC_R_SUCCESS)
407		return (ret);
408
409	if (set->type != sig.covered)
410		return (DNS_R_SIGINVALID);
411
412	if (isc_serial_lt(sig.timeexpire, sig.timesigned)) {
413		inc_stat(dns_dnssecstats_fail);
414		return (DNS_R_SIGINVALID);
415	}
416
417	if (!ignoretime) {
418		isc_stdtime_get(&now);
419
420		/*
421		 * Is SIG temporally valid?
422		 */
423		if (isc_serial_lt((isc_uint32_t)now, sig.timesigned)) {
424			inc_stat(dns_dnssecstats_fail);
425			return (DNS_R_SIGFUTURE);
426		} else if (isc_serial_lt(sig.timeexpire, (isc_uint32_t)now)) {
427			inc_stat(dns_dnssecstats_fail);
428			return (DNS_R_SIGEXPIRED);
429		}
430	}
431
432	/*
433	 * NS, SOA and DNSSKEY records are signed by their owner.
434	 * DS records are signed by the parent.
435	 */
436	switch (set->type) {
437	case dns_rdatatype_ns:
438	case dns_rdatatype_soa:
439	case dns_rdatatype_dnskey:
440		if (!dns_name_equal(name, &sig.signer)) {
441			inc_stat(dns_dnssecstats_fail);
442			return (DNS_R_SIGINVALID);
443		}
444		break;
445	case dns_rdatatype_ds:
446		if (dns_name_equal(name, &sig.signer)) {
447			inc_stat(dns_dnssecstats_fail);
448			return (DNS_R_SIGINVALID);
449		}
450		/* FALLTHROUGH */
451	default:
452		if (!dns_name_issubdomain(name, &sig.signer)) {
453			inc_stat(dns_dnssecstats_fail);
454			return (DNS_R_SIGINVALID);
455		}
456		break;
457	}
458
459	/*
460	 * Is the key allowed to sign data?
461	 */
462	flags = dst_key_flags(key);
463	if (flags & DNS_KEYTYPE_NOAUTH) {
464		inc_stat(dns_dnssecstats_fail);
465		return (DNS_R_KEYUNAUTHORIZED);
466	}
467	if ((flags & DNS_KEYFLAG_OWNERMASK) != DNS_KEYOWNER_ZONE) {
468		inc_stat(dns_dnssecstats_fail);
469		return (DNS_R_KEYUNAUTHORIZED);
470	}
471
472 again:
473	ret = dst_context_create2(key, mctx, DNS_LOGCATEGORY_DNSSEC, &ctx);
474	if (ret != ISC_R_SUCCESS)
475		goto cleanup_struct;
476
477	/*
478	 * Digest the SIG rdata (not including the signature).
479	 */
480	ret = digest_sig(ctx, downcase, sigrdata, &sig);
481	if (ret != ISC_R_SUCCESS)
482		goto cleanup_context;
483
484	/*
485	 * If the name is an expanded wildcard, use the wildcard name.
486	 */
487	dns_fixedname_init(&fnewname);
488	labels = dns_name_countlabels(name) - 1;
489	RUNTIME_CHECK(dns_name_downcase(name, dns_fixedname_name(&fnewname),
490					NULL) == ISC_R_SUCCESS);
491	if (labels - sig.labels > 0)
492		dns_name_split(dns_fixedname_name(&fnewname), sig.labels + 1,
493			       NULL, dns_fixedname_name(&fnewname));
494
495	dns_name_toregion(dns_fixedname_name(&fnewname), &r);
496
497	/*
498	 * Create an envelope for each rdata: <name|type|class|ttl>.
499	 */
500	isc_buffer_init(&envbuf, data, sizeof(data));
501	if (labels - sig.labels > 0) {
502		isc_buffer_putuint8(&envbuf, 1);
503		isc_buffer_putuint8(&envbuf, '*');
504		memmove(data + 2, r.base, r.length);
505	}
506	else
507		memmove(data, r.base, r.length);
508	isc_buffer_add(&envbuf, r.length);
509	isc_buffer_putuint16(&envbuf, set->type);
510	isc_buffer_putuint16(&envbuf, set->rdclass);
511	isc_buffer_putuint32(&envbuf, sig.originalttl);
512
513	ret = rdataset_to_sortedarray(set, mctx, &rdatas, &nrdatas);
514	if (ret != ISC_R_SUCCESS)
515		goto cleanup_context;
516
517	isc_buffer_usedregion(&envbuf, &r);
518
519	for (i = 0; i < nrdatas; i++) {
520		isc_uint16_t len;
521		isc_buffer_t lenbuf;
522		isc_region_t lenr;
523
524		/*
525		 * Skip duplicates.
526		 */
527		if (i > 0 && dns_rdata_compare(&rdatas[i], &rdatas[i-1]) == 0)
528		    continue;
529
530		/*
531		 * Digest the envelope.
532		 */
533		ret = dst_context_adddata(ctx, &r);
534		if (ret != ISC_R_SUCCESS)
535			goto cleanup_array;
536
537		/*
538		 * Digest the rdata length.
539		 */
540		isc_buffer_init(&lenbuf, &len, sizeof(len));
541		INSIST(rdatas[i].length < 65536);
542		isc_buffer_putuint16(&lenbuf, (isc_uint16_t)rdatas[i].length);
543		isc_buffer_usedregion(&lenbuf, &lenr);
544
545		/*
546		 * Digest the rdata.
547		 */
548		ret = dst_context_adddata(ctx, &lenr);
549		if (ret != ISC_R_SUCCESS)
550			goto cleanup_array;
551		ret = dns_rdata_digest(&rdatas[i], digest_callback, ctx);
552		if (ret != ISC_R_SUCCESS)
553			goto cleanup_array;
554	}
555
556	r.base = sig.signature;
557	r.length = sig.siglen;
558	ret = dst_context_verify2(ctx, maxbits, &r);
559	if (ret == ISC_R_SUCCESS && downcase) {
560		char namebuf[DNS_NAME_FORMATSIZE];
561		dns_name_format(&sig.signer, namebuf, sizeof(namebuf));
562		isc_log_write(dns_lctx, DNS_LOGCATEGORY_DNSSEC,
563			      DNS_LOGMODULE_DNSSEC, ISC_LOG_DEBUG(1),
564			      "successfully validated after lower casing "
565			      "signer '%s'", namebuf);
566		inc_stat(dns_dnssecstats_downcase);
567	} else if (ret == ISC_R_SUCCESS)
568		inc_stat(dns_dnssecstats_asis);
569
570cleanup_array:
571	isc_mem_put(mctx, rdatas, nrdatas * sizeof(dns_rdata_t));
572cleanup_context:
573	dst_context_destroy(&ctx);
574	if (ret == DST_R_VERIFYFAILURE && !downcase) {
575		downcase = ISC_TRUE;
576		goto again;
577	}
578cleanup_struct:
579	dns_rdata_freestruct(&sig);
580
581	if (ret == DST_R_VERIFYFAILURE)
582		ret = DNS_R_SIGINVALID;
583
584	if (ret != ISC_R_SUCCESS)
585		inc_stat(dns_dnssecstats_fail);
586
587	if (ret == ISC_R_SUCCESS && labels - sig.labels > 0) {
588		if (wild != NULL)
589			RUNTIME_CHECK(dns_name_concatenate(dns_wildcardname,
590						 dns_fixedname_name(&fnewname),
591						 wild, NULL) == ISC_R_SUCCESS);
592		inc_stat(dns_dnssecstats_wildcard);
593		ret = DNS_R_FROMWILDCARD;
594	}
595	return (ret);
596}
597
598isc_result_t
599dns_dnssec_verify(dns_name_t *name, dns_rdataset_t *set, dst_key_t *key,
600		  isc_boolean_t ignoretime, isc_mem_t *mctx,
601		  dns_rdata_t *sigrdata)
602{
603	isc_result_t result;
604
605	result = dns_dnssec_verify2(name, set, key, ignoretime, mctx,
606				    sigrdata, NULL);
607	if (result == DNS_R_FROMWILDCARD)
608		result = ISC_R_SUCCESS;
609	return (result);
610}
611
612isc_boolean_t
613dns_dnssec_keyactive(dst_key_t *key, isc_stdtime_t now) {
614	isc_result_t result;
615	isc_stdtime_t publish, active, revoke, inactive, delete;
616	isc_boolean_t pubset = ISC_FALSE, actset = ISC_FALSE;
617	isc_boolean_t revset = ISC_FALSE, inactset = ISC_FALSE;
618	isc_boolean_t delset = ISC_FALSE;
619	int major, minor;
620
621	/* Is this an old-style key? */
622	result = dst_key_getprivateformat(key, &major, &minor);
623	RUNTIME_CHECK(result == ISC_R_SUCCESS);
624
625	/*
626	 * Smart signing started with key format 1.3; prior to that, all
627	 * keys are assumed active
628	 */
629	if (major == 1 && minor <= 2)
630		return (ISC_TRUE);
631
632	result = dst_key_gettime(key, DST_TIME_PUBLISH, &publish);
633	if (result == ISC_R_SUCCESS)
634		pubset = ISC_TRUE;
635
636	result = dst_key_gettime(key, DST_TIME_ACTIVATE, &active);
637	if (result == ISC_R_SUCCESS)
638		actset = ISC_TRUE;
639
640	result = dst_key_gettime(key, DST_TIME_REVOKE, &revoke);
641	if (result == ISC_R_SUCCESS)
642		revset = ISC_TRUE;
643
644	result = dst_key_gettime(key, DST_TIME_INACTIVE, &inactive);
645	if (result == ISC_R_SUCCESS)
646		inactset = ISC_TRUE;
647
648	result = dst_key_gettime(key, DST_TIME_DELETE, &delete);
649	if (result == ISC_R_SUCCESS)
650		delset = ISC_TRUE;
651
652	if ((inactset && inactive <= now) || (delset && delete <= now))
653		return (ISC_FALSE);
654
655	if (revset && revoke <= now && pubset && publish <= now)
656		return (ISC_TRUE);
657
658	if (actset && active <= now)
659		return (ISC_TRUE);
660
661	return (ISC_FALSE);
662}
663
664#define is_zone_key(key) ((dst_key_flags(key) & DNS_KEYFLAG_OWNERMASK) \
665			  == DNS_KEYOWNER_ZONE)
666
667isc_result_t
668dns_dnssec_findzonekeys2(dns_db_t *db, dns_dbversion_t *ver,
669			 dns_dbnode_t *node, dns_name_t *name,
670			 const char *directory, isc_mem_t *mctx,
671			 unsigned int maxkeys, dst_key_t **keys,
672			 unsigned int *nkeys)
673{
674	dns_rdataset_t rdataset;
675	dns_rdata_t rdata = DNS_RDATA_INIT;
676	isc_result_t result;
677	dst_key_t *pubkey = NULL;
678	unsigned int count = 0;
679	isc_stdtime_t now;
680
681	REQUIRE(nkeys != NULL);
682	REQUIRE(keys != NULL);
683
684	isc_stdtime_get(&now);
685
686	*nkeys = 0;
687	memset(keys, 0, sizeof(*keys) * maxkeys);
688	dns_rdataset_init(&rdataset);
689	RETERR(dns_db_findrdataset(db, node, ver, dns_rdatatype_dnskey, 0, 0,
690				   &rdataset, NULL));
691	RETERR(dns_rdataset_first(&rdataset));
692	while (result == ISC_R_SUCCESS && count < maxkeys) {
693		pubkey = NULL;
694		dns_rdataset_current(&rdataset, &rdata);
695		RETERR(dns_dnssec_keyfromrdata(name, &rdata, mctx, &pubkey));
696		dst_key_setttl(pubkey, rdataset.ttl);
697
698		if (!is_zone_key(pubkey) ||
699		    (dst_key_flags(pubkey) & DNS_KEYTYPE_NOAUTH) != 0)
700			goto next;
701		/* Corrupted .key file? */
702		if (!dns_name_equal(name, dst_key_name(pubkey)))
703			goto next;
704		keys[count] = NULL;
705		result = dst_key_fromfile(dst_key_name(pubkey),
706					  dst_key_id(pubkey),
707					  dst_key_alg(pubkey),
708					  DST_TYPE_PUBLIC|DST_TYPE_PRIVATE,
709					  directory,
710					  mctx, &keys[count]);
711
712		/*
713		 * If the key was revoked and the private file
714		 * doesn't exist, maybe it was revoked internally
715		 * by named.  Try loading the unrevoked version.
716		 */
717		if (result == ISC_R_FILENOTFOUND) {
718			isc_uint32_t flags;
719			flags = dst_key_flags(pubkey);
720			if ((flags & DNS_KEYFLAG_REVOKE) != 0) {
721				dst_key_setflags(pubkey,
722						 flags & ~DNS_KEYFLAG_REVOKE);
723				result = dst_key_fromfile(dst_key_name(pubkey),
724							  dst_key_id(pubkey),
725							  dst_key_alg(pubkey),
726							  DST_TYPE_PUBLIC|
727							  DST_TYPE_PRIVATE,
728							  directory,
729							  mctx, &keys[count]);
730				if (result == ISC_R_SUCCESS &&
731				    dst_key_pubcompare(pubkey, keys[count],
732						       ISC_FALSE)) {
733					dst_key_setflags(keys[count], flags);
734				}
735				dst_key_setflags(pubkey, flags);
736			}
737		}
738
739		if (result != ISC_R_SUCCESS) {
740			char keybuf[DNS_NAME_FORMATSIZE];
741			char algbuf[DNS_SECALG_FORMATSIZE];
742			dns_name_format(dst_key_name(pubkey), keybuf,
743					sizeof(keybuf));
744			dns_secalg_format(dst_key_alg(pubkey), algbuf,
745					  sizeof(algbuf));
746			isc_log_write(dns_lctx, DNS_LOGCATEGORY_GENERAL,
747				      DNS_LOGMODULE_DNSSEC, ISC_LOG_WARNING,
748				      "dns_dnssec_findzonekeys2: error "
749				      "reading private key file %s/%s/%d: %s",
750				      keybuf, algbuf, dst_key_id(pubkey),
751				      isc_result_totext(result));
752		}
753
754		if (result == ISC_R_FILENOTFOUND || result == ISC_R_NOPERM) {
755			keys[count] = pubkey;
756			pubkey = NULL;
757			count++;
758			goto next;
759		}
760
761		if (result != ISC_R_SUCCESS)
762			goto failure;
763
764		/*
765		 * If a key is marked inactive, skip it
766		 */
767		if (!dns_dnssec_keyactive(keys[count], now)) {
768			dst_key_setinactive(pubkey, ISC_TRUE);
769			dst_key_free(&keys[count]);
770			keys[count] = pubkey;
771			pubkey = NULL;
772			count++;
773			goto next;
774		}
775
776		/*
777		 * Whatever the key's default TTL may have
778		 * been, the rdataset TTL takes priority.
779		 */
780		dst_key_setttl(keys[count], rdataset.ttl);
781
782		if ((dst_key_flags(keys[count]) & DNS_KEYTYPE_NOAUTH) != 0) {
783			/* We should never get here. */
784			dst_key_free(&keys[count]);
785			goto next;
786		}
787		count++;
788 next:
789		if (pubkey != NULL)
790			dst_key_free(&pubkey);
791		dns_rdata_reset(&rdata);
792		result = dns_rdataset_next(&rdataset);
793	}
794	if (result != ISC_R_NOMORE)
795		goto failure;
796	if (count == 0)
797		result = ISC_R_NOTFOUND;
798	else
799		result = ISC_R_SUCCESS;
800
801 failure:
802	if (dns_rdataset_isassociated(&rdataset))
803		dns_rdataset_disassociate(&rdataset);
804	if (pubkey != NULL)
805		dst_key_free(&pubkey);
806	if (result != ISC_R_SUCCESS)
807		while (count > 0)
808			dst_key_free(&keys[--count]);
809	*nkeys = count;
810	return (result);
811}
812
813isc_result_t
814dns_dnssec_findzonekeys(dns_db_t *db, dns_dbversion_t *ver,
815			dns_dbnode_t *node, dns_name_t *name, isc_mem_t *mctx,
816			unsigned int maxkeys, dst_key_t **keys,
817			unsigned int *nkeys)
818{
819	return (dns_dnssec_findzonekeys2(db, ver, node, name, NULL, mctx,
820					 maxkeys, keys, nkeys));
821}
822
823isc_result_t
824dns_dnssec_signmessage(dns_message_t *msg, dst_key_t *key) {
825	dns_rdata_sig_t sig;	/* SIG(0) */
826	unsigned char data[512];
827	unsigned char header[DNS_MESSAGE_HEADERLEN];
828	isc_buffer_t headerbuf, databuf, sigbuf;
829	unsigned int sigsize;
830	isc_buffer_t *dynbuf = NULL;
831	dns_rdata_t *rdata;
832	dns_rdatalist_t *datalist;
833	dns_rdataset_t *dataset;
834	isc_region_t r;
835	isc_stdtime_t now;
836	dst_context_t *ctx = NULL;
837	isc_mem_t *mctx;
838	isc_result_t result;
839	isc_boolean_t signeedsfree = ISC_TRUE;
840
841	REQUIRE(msg != NULL);
842	REQUIRE(key != NULL);
843
844	if (is_response(msg))
845		REQUIRE(msg->query.base != NULL);
846
847	mctx = msg->mctx;
848
849	memset(&sig, 0, sizeof(sig));
850
851	sig.mctx = mctx;
852	sig.common.rdclass = dns_rdataclass_any;
853	sig.common.rdtype = dns_rdatatype_sig;	/* SIG(0) */
854	ISC_LINK_INIT(&sig.common, link);
855
856	sig.covered = 0;
857	sig.algorithm = dst_key_alg(key);
858	sig.labels = 0; /* the root name */
859	sig.originalttl = 0;
860
861	isc_stdtime_get(&now);
862	sig.timesigned = now - DNS_TSIG_FUDGE;
863	sig.timeexpire = now + DNS_TSIG_FUDGE;
864
865	sig.keyid = dst_key_id(key);
866
867	dns_name_init(&sig.signer, NULL);
868	dns_name_clone(dst_key_name(key), &sig.signer);
869
870	sig.siglen = 0;
871	sig.signature = NULL;
872
873	isc_buffer_init(&databuf, data, sizeof(data));
874
875	RETERR(dst_context_create2(key, mctx, DNS_LOGCATEGORY_DNSSEC, &ctx));
876
877	/*
878	 * Digest the fields of the SIG - we can cheat and use
879	 * dns_rdata_fromstruct.  Since siglen is 0, the digested data
880	 * is identical to dns format.
881	 */
882	RETERR(dns_rdata_fromstruct(NULL, dns_rdataclass_any,
883				    dns_rdatatype_sig /* SIG(0) */,
884				    &sig, &databuf));
885	isc_buffer_usedregion(&databuf, &r);
886	RETERR(dst_context_adddata(ctx, &r));
887
888	/*
889	 * If this is a response, digest the query.
890	 */
891	if (is_response(msg))
892		RETERR(dst_context_adddata(ctx, &msg->query));
893
894	/*
895	 * Digest the header.
896	 */
897	isc_buffer_init(&headerbuf, header, sizeof(header));
898	dns_message_renderheader(msg, &headerbuf);
899	isc_buffer_usedregion(&headerbuf, &r);
900	RETERR(dst_context_adddata(ctx, &r));
901
902	/*
903	 * Digest the remainder of the message.
904	 */
905	isc_buffer_usedregion(msg->buffer, &r);
906	isc_region_consume(&r, DNS_MESSAGE_HEADERLEN);
907	RETERR(dst_context_adddata(ctx, &r));
908
909	RETERR(dst_key_sigsize(key, &sigsize));
910	sig.siglen = sigsize;
911	sig.signature = (unsigned char *) isc_mem_get(mctx, sig.siglen);
912	if (sig.signature == NULL) {
913		result = ISC_R_NOMEMORY;
914		goto failure;
915	}
916
917	isc_buffer_init(&sigbuf, sig.signature, sig.siglen);
918	RETERR(dst_context_sign(ctx, &sigbuf));
919	dst_context_destroy(&ctx);
920
921	rdata = NULL;
922	RETERR(dns_message_gettemprdata(msg, &rdata));
923	RETERR(isc_buffer_allocate(msg->mctx, &dynbuf, 1024));
924	RETERR(dns_rdata_fromstruct(rdata, dns_rdataclass_any,
925				    dns_rdatatype_sig /* SIG(0) */,
926				    &sig, dynbuf));
927
928	isc_mem_put(mctx, sig.signature, sig.siglen);
929	signeedsfree = ISC_FALSE;
930
931	dns_message_takebuffer(msg, &dynbuf);
932
933	datalist = NULL;
934	RETERR(dns_message_gettemprdatalist(msg, &datalist));
935	datalist->rdclass = dns_rdataclass_any;
936	datalist->type = dns_rdatatype_sig;	/* SIG(0) */
937	datalist->covers = 0;
938	datalist->ttl = 0;
939	ISC_LIST_INIT(datalist->rdata);
940	ISC_LIST_APPEND(datalist->rdata, rdata, link);
941	dataset = NULL;
942	RETERR(dns_message_gettemprdataset(msg, &dataset));
943	dns_rdataset_init(dataset);
944	RUNTIME_CHECK(dns_rdatalist_tordataset(datalist, dataset) == ISC_R_SUCCESS);
945	msg->sig0 = dataset;
946
947	return (ISC_R_SUCCESS);
948
949failure:
950	if (dynbuf != NULL)
951		isc_buffer_free(&dynbuf);
952	if (signeedsfree)
953		isc_mem_put(mctx, sig.signature, sig.siglen);
954	if (ctx != NULL)
955		dst_context_destroy(&ctx);
956
957	return (result);
958}
959
960isc_result_t
961dns_dnssec_verifymessage(isc_buffer_t *source, dns_message_t *msg,
962			 dst_key_t *key)
963{
964	dns_rdata_sig_t sig;	/* SIG(0) */
965	unsigned char header[DNS_MESSAGE_HEADERLEN];
966	dns_rdata_t rdata = DNS_RDATA_INIT;
967	isc_region_t r, source_r, sig_r, header_r;
968	isc_stdtime_t now;
969	dst_context_t *ctx = NULL;
970	isc_mem_t *mctx;
971	isc_result_t result;
972	isc_uint16_t addcount;
973	isc_boolean_t signeedsfree = ISC_FALSE;
974
975	REQUIRE(source != NULL);
976	REQUIRE(msg != NULL);
977	REQUIRE(key != NULL);
978
979	mctx = msg->mctx;
980
981	msg->verify_attempted = 1;
982
983	if (is_response(msg)) {
984		if (msg->query.base == NULL)
985			return (DNS_R_UNEXPECTEDTSIG);
986	}
987
988	isc_buffer_usedregion(source, &source_r);
989
990	RETERR(dns_rdataset_first(msg->sig0));
991	dns_rdataset_current(msg->sig0, &rdata);
992
993	RETERR(dns_rdata_tostruct(&rdata, &sig, NULL));
994	signeedsfree = ISC_TRUE;
995
996	if (sig.labels != 0) {
997		result = DNS_R_SIGINVALID;
998		goto failure;
999	}
1000
1001	if (isc_serial_lt(sig.timeexpire, sig.timesigned)) {
1002		result = DNS_R_SIGINVALID;
1003		msg->sig0status = dns_tsigerror_badtime;
1004		goto failure;
1005	}
1006
1007	isc_stdtime_get(&now);
1008	if (isc_serial_lt((isc_uint32_t)now, sig.timesigned)) {
1009		result = DNS_R_SIGFUTURE;
1010		msg->sig0status = dns_tsigerror_badtime;
1011		goto failure;
1012	}
1013	else if (isc_serial_lt(sig.timeexpire, (isc_uint32_t)now)) {
1014		result = DNS_R_SIGEXPIRED;
1015		msg->sig0status = dns_tsigerror_badtime;
1016		goto failure;
1017	}
1018
1019	if (!dns_name_equal(dst_key_name(key), &sig.signer)) {
1020		result = DNS_R_SIGINVALID;
1021		msg->sig0status = dns_tsigerror_badkey;
1022		goto failure;
1023	}
1024
1025	RETERR(dst_context_create2(key, mctx, DNS_LOGCATEGORY_DNSSEC, &ctx));
1026
1027	/*
1028	 * Digest the SIG(0) record, except for the signature.
1029	 */
1030	dns_rdata_toregion(&rdata, &r);
1031	r.length -= sig.siglen;
1032	RETERR(dst_context_adddata(ctx, &r));
1033
1034	/*
1035	 * If this is a response, digest the query.
1036	 */
1037	if (is_response(msg))
1038		RETERR(dst_context_adddata(ctx, &msg->query));
1039
1040	/*
1041	 * Extract the header.
1042	 */
1043	memmove(header, source_r.base, DNS_MESSAGE_HEADERLEN);
1044
1045	/*
1046	 * Decrement the additional field counter.
1047	 */
1048	memmove(&addcount, &header[DNS_MESSAGE_HEADERLEN - 2], 2);
1049	addcount = htons((isc_uint16_t)(ntohs(addcount) - 1));
1050	memmove(&header[DNS_MESSAGE_HEADERLEN - 2], &addcount, 2);
1051
1052	/*
1053	 * Digest the modified header.
1054	 */
1055	header_r.base = (unsigned char *) header;
1056	header_r.length = DNS_MESSAGE_HEADERLEN;
1057	RETERR(dst_context_adddata(ctx, &header_r));
1058
1059	/*
1060	 * Digest all non-SIG(0) records.
1061	 */
1062	r.base = source_r.base + DNS_MESSAGE_HEADERLEN;
1063	r.length = msg->sigstart - DNS_MESSAGE_HEADERLEN;
1064	RETERR(dst_context_adddata(ctx, &r));
1065
1066	sig_r.base = sig.signature;
1067	sig_r.length = sig.siglen;
1068	result = dst_context_verify(ctx, &sig_r);
1069	if (result != ISC_R_SUCCESS) {
1070		msg->sig0status = dns_tsigerror_badsig;
1071		goto failure;
1072	}
1073
1074	msg->verified_sig = 1;
1075
1076	dst_context_destroy(&ctx);
1077	dns_rdata_freestruct(&sig);
1078
1079	return (ISC_R_SUCCESS);
1080
1081failure:
1082	if (signeedsfree)
1083		dns_rdata_freestruct(&sig);
1084	if (ctx != NULL)
1085		dst_context_destroy(&ctx);
1086
1087	return (result);
1088}
1089
1090/*%
1091 * Does this key ('rdata') self sign the rrset ('rdataset')?
1092 */
1093isc_boolean_t
1094dns_dnssec_selfsigns(dns_rdata_t *rdata, dns_name_t *name,
1095		     dns_rdataset_t *rdataset, dns_rdataset_t *sigrdataset,
1096		     isc_boolean_t ignoretime, isc_mem_t *mctx)
1097{
1098	INSIST(rdataset->type == dns_rdatatype_key ||
1099	       rdataset->type == dns_rdatatype_dnskey);
1100	if (rdataset->type == dns_rdatatype_key) {
1101		INSIST(sigrdataset->type == dns_rdatatype_sig);
1102		INSIST(sigrdataset->covers == dns_rdatatype_key);
1103	} else {
1104		INSIST(sigrdataset->type == dns_rdatatype_rrsig);
1105		INSIST(sigrdataset->covers == dns_rdatatype_dnskey);
1106	}
1107
1108	return (dns_dnssec_signs(rdata, name, rdataset, sigrdataset,
1109				 ignoretime, mctx));
1110
1111}
1112
1113isc_boolean_t
1114dns_dnssec_signs(dns_rdata_t *rdata, dns_name_t *name,
1115		     dns_rdataset_t *rdataset, dns_rdataset_t *sigrdataset,
1116		     isc_boolean_t ignoretime, isc_mem_t *mctx)
1117{
1118	dst_key_t *dstkey = NULL;
1119	dns_keytag_t keytag;
1120	dns_rdata_dnskey_t key;
1121	dns_rdata_rrsig_t sig;
1122	dns_rdata_t sigrdata = DNS_RDATA_INIT;
1123	isc_result_t result;
1124
1125	INSIST(sigrdataset->type == dns_rdatatype_rrsig);
1126	if (sigrdataset->covers != rdataset->type)
1127		return (ISC_FALSE);
1128
1129	result = dns_dnssec_keyfromrdata(name, rdata, mctx, &dstkey);
1130	if (result != ISC_R_SUCCESS)
1131		return (ISC_FALSE);
1132	result = dns_rdata_tostruct(rdata, &key, NULL);
1133	RUNTIME_CHECK(result == ISC_R_SUCCESS);
1134
1135	keytag = dst_key_id(dstkey);
1136	for (result = dns_rdataset_first(sigrdataset);
1137	     result == ISC_R_SUCCESS;
1138	     result = dns_rdataset_next(sigrdataset))
1139	{
1140		dns_rdata_reset(&sigrdata);
1141		dns_rdataset_current(sigrdataset, &sigrdata);
1142		result = dns_rdata_tostruct(&sigrdata, &sig, NULL);
1143		RUNTIME_CHECK(result == ISC_R_SUCCESS);
1144
1145		if (sig.algorithm == key.algorithm &&
1146		    sig.keyid == keytag) {
1147			result = dns_dnssec_verify2(name, rdataset, dstkey,
1148						    ignoretime, mctx,
1149						    &sigrdata, NULL);
1150			if (result == ISC_R_SUCCESS) {
1151				dst_key_free(&dstkey);
1152				return (ISC_TRUE);
1153			}
1154		}
1155	}
1156	dst_key_free(&dstkey);
1157	return (ISC_FALSE);
1158}
1159
1160isc_result_t
1161dns_dnsseckey_create(isc_mem_t *mctx, dst_key_t **dstkey,
1162		     dns_dnsseckey_t **dkp)
1163{
1164	isc_result_t result;
1165	dns_dnsseckey_t *dk;
1166	int major, minor;
1167
1168	REQUIRE(dkp != NULL && *dkp == NULL);
1169	dk = isc_mem_get(mctx, sizeof(dns_dnsseckey_t));
1170	if (dk == NULL)
1171		return (ISC_R_NOMEMORY);
1172
1173	dk->key = *dstkey;
1174	*dstkey = NULL;
1175	dk->force_publish = ISC_FALSE;
1176	dk->force_sign = ISC_FALSE;
1177	dk->hint_publish = ISC_FALSE;
1178	dk->hint_sign = ISC_FALSE;
1179	dk->hint_remove = ISC_FALSE;
1180	dk->first_sign = ISC_FALSE;
1181	dk->is_active = ISC_FALSE;
1182	dk->prepublish = 0;
1183	dk->source = dns_keysource_unknown;
1184	dk->index = 0;
1185
1186	/* KSK or ZSK? */
1187	dk->ksk = ISC_TF((dst_key_flags(dk->key) & DNS_KEYFLAG_KSK) != 0);
1188
1189	/* Is this an old-style key? */
1190	result = dst_key_getprivateformat(dk->key, &major, &minor);
1191	INSIST(result == ISC_R_SUCCESS);
1192
1193	/* Smart signing started with key format 1.3 */
1194	dk->legacy = ISC_TF(major == 1 && minor <= 2);
1195
1196	ISC_LINK_INIT(dk, link);
1197	*dkp = dk;
1198	return (ISC_R_SUCCESS);
1199}
1200
1201void
1202dns_dnsseckey_destroy(isc_mem_t *mctx, dns_dnsseckey_t **dkp) {
1203	dns_dnsseckey_t *dk;
1204
1205	REQUIRE(dkp != NULL && *dkp != NULL);
1206	dk = *dkp;
1207	if (dk->key != NULL)
1208		dst_key_free(&dk->key);
1209	isc_mem_put(mctx, dk, sizeof(dns_dnsseckey_t));
1210	*dkp = NULL;
1211}
1212
1213static void
1214get_hints(dns_dnsseckey_t *key, isc_stdtime_t now) {
1215	isc_result_t result;
1216	isc_stdtime_t publish, active, revoke, inactive, delete;
1217	isc_boolean_t pubset = ISC_FALSE, actset = ISC_FALSE;
1218	isc_boolean_t revset = ISC_FALSE, inactset = ISC_FALSE;
1219	isc_boolean_t delset = ISC_FALSE;
1220
1221	REQUIRE(key != NULL && key->key != NULL);
1222
1223	result = dst_key_gettime(key->key, DST_TIME_PUBLISH, &publish);
1224	if (result == ISC_R_SUCCESS)
1225		pubset = ISC_TRUE;
1226
1227	result = dst_key_gettime(key->key, DST_TIME_ACTIVATE, &active);
1228	if (result == ISC_R_SUCCESS)
1229		actset = ISC_TRUE;
1230
1231	result = dst_key_gettime(key->key, DST_TIME_REVOKE, &revoke);
1232	if (result == ISC_R_SUCCESS)
1233		revset = ISC_TRUE;
1234
1235	result = dst_key_gettime(key->key, DST_TIME_INACTIVE, &inactive);
1236	if (result == ISC_R_SUCCESS)
1237		inactset = ISC_TRUE;
1238
1239	result = dst_key_gettime(key->key, DST_TIME_DELETE, &delete);
1240	if (result == ISC_R_SUCCESS)
1241		delset = ISC_TRUE;
1242
1243	/* Metadata says publish (but possibly not activate) */
1244	if (pubset && publish <= now)
1245		key->hint_publish = ISC_TRUE;
1246
1247	/* Metadata says activate (so we must also publish) */
1248	if (actset && active <= now) {
1249		key->hint_sign = ISC_TRUE;
1250		key->hint_publish = ISC_TRUE;
1251	}
1252
1253	/*
1254	 * Activation date is set (maybe in the future), but
1255	 * publication date isn't. Most likely the user wants to
1256	 * publish now and activate later.
1257	 */
1258	if (actset && !pubset)
1259		key->hint_publish = ISC_TRUE;
1260
1261	/*
1262	 * If activation date is in the future, make note of how far off
1263	 */
1264	if (key->hint_publish && actset && active > now) {
1265		key->prepublish = active - now;
1266	}
1267
1268	/*
1269	 * Key has been marked inactive: we can continue publishing,
1270	 * but don't sign.
1271	 */
1272	if (key->hint_publish && inactset && inactive <= now) {
1273		key->hint_sign = ISC_FALSE;
1274	}
1275
1276	/*
1277	 * Metadata says revoke.  If the key is published,
1278	 * we *have to* sign with it per RFC5011--even if it was
1279	 * not active before.
1280	 *
1281	 * If it hasn't already been done, we should also revoke it now.
1282	 */
1283	if (key->hint_publish && (revset && revoke <= now)) {
1284		isc_uint32_t flags;
1285		key->hint_sign = ISC_TRUE;
1286		flags = dst_key_flags(key->key);
1287		if ((flags & DNS_KEYFLAG_REVOKE) == 0) {
1288			flags |= DNS_KEYFLAG_REVOKE;
1289			dst_key_setflags(key->key, flags);
1290		}
1291	}
1292
1293	/*
1294	 * Metadata says delete, so don't publish this key or sign with it.
1295	 */
1296	if (delset && delete <= now) {
1297		key->hint_publish = ISC_FALSE;
1298		key->hint_sign = ISC_FALSE;
1299		key->hint_remove = ISC_TRUE;
1300	}
1301}
1302
1303/*%
1304 * Get a list of DNSSEC keys from the key repository
1305 */
1306isc_result_t
1307dns_dnssec_findmatchingkeys(dns_name_t *origin, const char *directory,
1308			    isc_mem_t *mctx, dns_dnsseckeylist_t *keylist)
1309{
1310	isc_result_t result = ISC_R_SUCCESS;
1311	isc_boolean_t dir_open = ISC_FALSE;
1312	dns_dnsseckeylist_t list;
1313	isc_dir_t dir;
1314	dns_dnsseckey_t *key = NULL;
1315	dst_key_t *dstkey = NULL;
1316	char namebuf[DNS_NAME_FORMATSIZE];
1317	isc_buffer_t b;
1318	unsigned int len, i;
1319	isc_stdtime_t now;
1320
1321	REQUIRE(keylist != NULL);
1322	ISC_LIST_INIT(list);
1323	isc_dir_init(&dir);
1324
1325	isc_buffer_init(&b, namebuf, sizeof(namebuf) - 1);
1326	RETERR(dns_name_tofilenametext(origin, ISC_FALSE, &b));
1327	len = isc_buffer_usedlength(&b);
1328	namebuf[len] = '\0';
1329
1330	if (directory == NULL)
1331		directory = ".";
1332	RETERR(isc_dir_open(&dir, directory));
1333	dir_open = ISC_TRUE;
1334
1335	isc_stdtime_get(&now);
1336
1337	while (isc_dir_read(&dir) == ISC_R_SUCCESS) {
1338		if (dir.entry.name[0] != 'K' ||
1339		    dir.entry.length < len + 1 ||
1340		    dir.entry.name[len + 1] != '+' ||
1341		    strncasecmp(dir.entry.name + 1, namebuf, len) != 0)
1342			continue;
1343
1344		for (i = len + 1 + 1; i < dir.entry.length ; i++)
1345			if (dir.entry.name[i] < '0' || dir.entry.name[i] > '9')
1346				break;
1347
1348		if (i == len + 1 + 1 || i >= dir.entry.length ||
1349		    dir.entry.name[i] != '+')
1350			continue;
1351
1352		for (i++ ; i < dir.entry.length ; i++)
1353			if (dir.entry.name[i] < '0' || dir.entry.name[i] > '9')
1354				break;
1355
1356		if (strcmp(dir.entry.name + i, ".private") != 0)
1357				continue;
1358
1359		dstkey = NULL;
1360		result = dst_key_fromnamedfile(dir.entry.name,
1361					       directory,
1362					       DST_TYPE_PUBLIC |
1363					       DST_TYPE_PRIVATE,
1364					       mctx, &dstkey);
1365
1366		if (result != ISC_R_SUCCESS) {
1367			isc_log_write(dns_lctx,
1368				      DNS_LOGCATEGORY_GENERAL,
1369				      DNS_LOGMODULE_DNSSEC,
1370				      ISC_LOG_WARNING,
1371				      "dns_dnssec_findmatchingkeys: "
1372				      "error reading key file %s: %s",
1373				      dir.entry.name,
1374				      isc_result_totext(result));
1375			continue;
1376		}
1377
1378		RETERR(dns_dnsseckey_create(mctx, &dstkey, &key));
1379		key->source = dns_keysource_repository;
1380		get_hints(key, now);
1381
1382		if (key->legacy) {
1383			dns_dnsseckey_destroy(mctx, &key);
1384		} else {
1385			ISC_LIST_APPEND(list, key, link);
1386			key = NULL;
1387		}
1388	}
1389
1390	if (!ISC_LIST_EMPTY(list)) {
1391		result = ISC_R_SUCCESS;
1392		ISC_LIST_APPENDLIST(*keylist, list, link);
1393	} else
1394		result = ISC_R_NOTFOUND;
1395
1396 failure:
1397	if (dir_open)
1398		isc_dir_close(&dir);
1399	INSIST(key == NULL);
1400	while ((key = ISC_LIST_HEAD(list)) != NULL) {
1401		ISC_LIST_UNLINK(list, key, link);
1402		INSIST(key->key != NULL);
1403		dst_key_free(&key->key);
1404		dns_dnsseckey_destroy(mctx, &key);
1405	}
1406	if (dstkey != NULL)
1407		dst_key_free(&dstkey);
1408	return (result);
1409}
1410
1411/*%
1412 * Add 'newkey' to 'keylist' if it's not already there.
1413 *
1414 * If 'savekeys' is ISC_TRUE, then we need to preserve all
1415 * the keys in the keyset, regardless of whether they have
1416 * metadata indicating they should be deactivated or removed.
1417 */
1418static isc_result_t
1419addkey(dns_dnsseckeylist_t *keylist, dst_key_t **newkey,
1420       isc_boolean_t savekeys, isc_mem_t *mctx)
1421{
1422	dns_dnsseckey_t *key;
1423	isc_result_t result;
1424
1425	/* Skip duplicates */
1426	for (key = ISC_LIST_HEAD(*keylist);
1427	     key != NULL;
1428	     key = ISC_LIST_NEXT(key, link)) {
1429		if (dst_key_id(key->key) == dst_key_id(*newkey) &&
1430		    dst_key_alg(key->key) == dst_key_alg(*newkey) &&
1431		    dns_name_equal(dst_key_name(key->key),
1432				   dst_key_name(*newkey)))
1433			break;
1434	}
1435
1436	if (key != NULL) {
1437		/*
1438		 * Found a match.  If the old key was only public and the
1439		 * new key is private, replace the old one; otherwise
1440		 * leave it.  But either way, mark the key as having
1441		 * been found in the zone.
1442		 */
1443		if (dst_key_isprivate(key->key)) {
1444			dst_key_free(newkey);
1445		} else if (dst_key_isprivate(*newkey)) {
1446			dst_key_free(&key->key);
1447			key->key = *newkey;
1448		}
1449
1450		key->source = dns_keysource_zoneapex;
1451		return (ISC_R_SUCCESS);
1452	}
1453
1454	result = dns_dnsseckey_create(mctx, newkey, &key);
1455	if (result != ISC_R_SUCCESS)
1456		return (result);
1457	if (key->legacy || savekeys) {
1458		key->force_publish = ISC_TRUE;
1459		key->force_sign = dst_key_isprivate(key->key);
1460	}
1461	key->source = dns_keysource_zoneapex;
1462	ISC_LIST_APPEND(*keylist, key, link);
1463	*newkey = NULL;
1464	return (ISC_R_SUCCESS);
1465}
1466
1467
1468/*%
1469 * Mark all keys which signed the DNSKEY/SOA RRsets as "active",
1470 * for future reference.
1471 */
1472static isc_result_t
1473mark_active_keys(dns_dnsseckeylist_t *keylist, dns_rdataset_t *rrsigs) {
1474	isc_result_t result = ISC_R_SUCCESS;
1475	dns_rdata_t rdata = DNS_RDATA_INIT;
1476	dns_rdataset_t sigs;
1477	dns_dnsseckey_t *key;
1478
1479	REQUIRE(rrsigs != NULL && dns_rdataset_isassociated(rrsigs));
1480
1481	dns_rdataset_init(&sigs);
1482	dns_rdataset_clone(rrsigs, &sigs);
1483	for (key = ISC_LIST_HEAD(*keylist);
1484	     key != NULL;
1485	     key = ISC_LIST_NEXT(key, link)) {
1486		isc_uint16_t keyid, sigid;
1487		dns_secalg_t keyalg, sigalg;
1488		keyid = dst_key_id(key->key);
1489		keyalg = dst_key_alg(key->key);
1490
1491		for (result = dns_rdataset_first(&sigs);
1492		     result == ISC_R_SUCCESS;
1493		     result = dns_rdataset_next(&sigs)) {
1494			dns_rdata_rrsig_t sig;
1495
1496			dns_rdata_reset(&rdata);
1497			dns_rdataset_current(&sigs, &rdata);
1498			result = dns_rdata_tostruct(&rdata, &sig, NULL);
1499			RUNTIME_CHECK(result == ISC_R_SUCCESS);
1500			sigalg = sig.algorithm;
1501			sigid = sig.keyid;
1502			if (keyid == sigid && keyalg == sigalg) {
1503				key->is_active = ISC_TRUE;
1504				break;
1505			}
1506		}
1507	}
1508
1509	if (result == ISC_R_NOMORE)
1510		result = ISC_R_SUCCESS;
1511
1512	if (dns_rdataset_isassociated(&sigs))
1513		dns_rdataset_disassociate(&sigs);
1514	return (result);
1515}
1516
1517/*%
1518 * Add the contents of a DNSKEY rdataset 'keyset' to 'keylist'.
1519 */
1520isc_result_t
1521dns_dnssec_keylistfromrdataset(dns_name_t *origin,
1522			       const char *directory, isc_mem_t *mctx,
1523			       dns_rdataset_t *keyset, dns_rdataset_t *keysigs,
1524			       dns_rdataset_t *soasigs, isc_boolean_t savekeys,
1525			       isc_boolean_t public,
1526			       dns_dnsseckeylist_t *keylist)
1527{
1528	dns_rdataset_t keys;
1529	dns_rdata_t rdata = DNS_RDATA_INIT;
1530	dst_key_t *pubkey = NULL, *privkey = NULL;
1531	isc_result_t result;
1532
1533	REQUIRE(keyset != NULL && dns_rdataset_isassociated(keyset));
1534
1535	dns_rdataset_init(&keys);
1536
1537	dns_rdataset_clone(keyset, &keys);
1538	for (result = dns_rdataset_first(&keys);
1539	     result == ISC_R_SUCCESS;
1540	     result = dns_rdataset_next(&keys)) {
1541		dns_rdata_reset(&rdata);
1542		dns_rdataset_current(&keys, &rdata);
1543		RETERR(dns_dnssec_keyfromrdata(origin, &rdata, mctx, &pubkey));
1544		dst_key_setttl(pubkey, keys.ttl);
1545
1546		if (!is_zone_key(pubkey) ||
1547		    (dst_key_flags(pubkey) & DNS_KEYTYPE_NOAUTH) != 0)
1548			goto skip;
1549
1550		/* Corrupted .key file? */
1551		if (!dns_name_equal(origin, dst_key_name(pubkey)))
1552			goto skip;
1553
1554		if (public) {
1555			RETERR(addkey(keylist, &pubkey, savekeys, mctx));
1556			goto skip;
1557		}
1558
1559		result = dst_key_fromfile(dst_key_name(pubkey),
1560					  dst_key_id(pubkey),
1561					  dst_key_alg(pubkey),
1562					  DST_TYPE_PUBLIC|DST_TYPE_PRIVATE,
1563					  directory, mctx, &privkey);
1564
1565		/*
1566		 * If the key was revoked and the private file
1567		 * doesn't exist, maybe it was revoked internally
1568		 * by named.  Try loading the unrevoked version.
1569		 */
1570		if (result == ISC_R_FILENOTFOUND) {
1571			isc_uint32_t flags;
1572			flags = dst_key_flags(pubkey);
1573			if ((flags & DNS_KEYFLAG_REVOKE) != 0) {
1574				dst_key_setflags(pubkey,
1575						 flags & ~DNS_KEYFLAG_REVOKE);
1576				result = dst_key_fromfile(dst_key_name(pubkey),
1577							  dst_key_id(pubkey),
1578							  dst_key_alg(pubkey),
1579							  DST_TYPE_PUBLIC|
1580							  DST_TYPE_PRIVATE,
1581							  directory,
1582							  mctx, &privkey);
1583				if (result == ISC_R_SUCCESS &&
1584				    dst_key_pubcompare(pubkey, privkey,
1585						       ISC_FALSE)) {
1586					dst_key_setflags(privkey, flags);
1587				}
1588				dst_key_setflags(pubkey, flags);
1589			}
1590		}
1591
1592		if (result != ISC_R_SUCCESS) {
1593			char keybuf[DNS_NAME_FORMATSIZE];
1594			char algbuf[DNS_SECALG_FORMATSIZE];
1595			dns_name_format(dst_key_name(pubkey), keybuf,
1596					sizeof(keybuf));
1597			dns_secalg_format(dst_key_alg(pubkey), algbuf,
1598					  sizeof(algbuf));
1599			isc_log_write(dns_lctx, DNS_LOGCATEGORY_GENERAL,
1600				      DNS_LOGMODULE_DNSSEC, ISC_LOG_WARNING,
1601				      "dns_dnssec_keylistfromrdataset: error "
1602				      "reading private key file %s/%s/%d: %s",
1603				      keybuf, algbuf, dst_key_id(pubkey),
1604				      isc_result_totext(result));
1605		}
1606
1607		if (result == ISC_R_FILENOTFOUND || result == ISC_R_NOPERM) {
1608			RETERR(addkey(keylist, &pubkey, savekeys, mctx));
1609			goto skip;
1610		}
1611		RETERR(result);
1612
1613		/* This should never happen. */
1614		if ((dst_key_flags(privkey) & DNS_KEYTYPE_NOAUTH) != 0)
1615			goto skip;
1616
1617		/*
1618		 * Whatever the key's default TTL may have
1619		 * been, the rdataset TTL takes priority.
1620		 */
1621		dst_key_setttl(privkey, dst_key_getttl(pubkey));
1622
1623		RETERR(addkey(keylist, &privkey, savekeys, mctx));
1624 skip:
1625		if (pubkey != NULL)
1626			dst_key_free(&pubkey);
1627		if (privkey != NULL)
1628			dst_key_free(&privkey);
1629	}
1630
1631	if (result != ISC_R_NOMORE)
1632		RETERR(result);
1633
1634	if (keysigs != NULL && dns_rdataset_isassociated(keysigs))
1635		RETERR(mark_active_keys(keylist, keysigs));
1636
1637	if (soasigs != NULL && dns_rdataset_isassociated(soasigs))
1638		RETERR(mark_active_keys(keylist, soasigs));
1639
1640	result = ISC_R_SUCCESS;
1641
1642 failure:
1643	if (dns_rdataset_isassociated(&keys))
1644		dns_rdataset_disassociate(&keys);
1645	if (pubkey != NULL)
1646		dst_key_free(&pubkey);
1647	if (privkey != NULL)
1648		dst_key_free(&privkey);
1649	return (result);
1650}
1651
1652static isc_result_t
1653make_dnskey(dst_key_t *key, unsigned char *buf, int bufsize,
1654	    dns_rdata_t *target)
1655{
1656	isc_result_t result;
1657	isc_buffer_t b;
1658	isc_region_t r;
1659
1660	isc_buffer_init(&b, buf, bufsize);
1661	result = dst_key_todns(key, &b);
1662	if (result != ISC_R_SUCCESS)
1663		return (result);
1664
1665	dns_rdata_reset(target);
1666	isc_buffer_usedregion(&b, &r);
1667	dns_rdata_fromregion(target, dst_key_class(key),
1668			     dns_rdatatype_dnskey, &r);
1669	return (ISC_R_SUCCESS);
1670}
1671
1672static isc_result_t
1673publish_key(dns_diff_t *diff, dns_dnsseckey_t *key, dns_name_t *origin,
1674	    dns_ttl_t ttl, isc_mem_t *mctx, isc_boolean_t allzsk,
1675	    void (*report)(const char *, ...))
1676{
1677	isc_result_t result;
1678	dns_difftuple_t *tuple = NULL;
1679	unsigned char buf[DST_KEY_MAXSIZE];
1680	dns_rdata_t dnskey = DNS_RDATA_INIT;
1681	char alg[80];
1682
1683	dns_rdata_reset(&dnskey);
1684	RETERR(make_dnskey(key->key, buf, sizeof(buf), &dnskey));
1685
1686	dns_secalg_format(dst_key_alg(key->key), alg, sizeof(alg));
1687	report("Fetching %s %d/%s from key %s.",
1688	       key->ksk ?  (allzsk ?  "KSK/ZSK" : "KSK") : "ZSK",
1689	       dst_key_id(key->key), alg,
1690	       key->source == dns_keysource_user ?  "file" : "repository");
1691
1692	if (key->prepublish && ttl > key->prepublish) {
1693		char keystr[DST_KEY_FORMATSIZE];
1694		isc_stdtime_t now;
1695
1696		dst_key_format(key->key, keystr, sizeof(keystr));
1697		report("Key %s: Delaying activation to match the DNSKEY TTL.\n",
1698		       keystr, ttl);
1699
1700		isc_stdtime_get(&now);
1701		dst_key_settime(key->key, DST_TIME_ACTIVATE, now + ttl);
1702	}
1703
1704	/* publish key */
1705	RETERR(dns_difftuple_create(mctx, DNS_DIFFOP_ADD, origin, ttl,
1706				    &dnskey, &tuple));
1707	dns_diff_appendminimal(diff, &tuple);
1708	result = ISC_R_SUCCESS;
1709
1710 failure:
1711	return (result);
1712}
1713
1714static isc_result_t
1715remove_key(dns_diff_t *diff, dns_dnsseckey_t *key, dns_name_t *origin,
1716	  dns_ttl_t ttl, isc_mem_t *mctx, const char *reason,
1717	  void (*report)(const char *, ...))
1718{
1719	isc_result_t result;
1720	dns_difftuple_t *tuple = NULL;
1721	unsigned char buf[DST_KEY_MAXSIZE];
1722	dns_rdata_t dnskey = DNS_RDATA_INIT;
1723	char alg[80];
1724
1725	dns_secalg_format(dst_key_alg(key->key), alg, sizeof(alg));
1726	report("Removing %s key %d/%s from DNSKEY RRset.",
1727	       reason, dst_key_id(key->key), alg);
1728
1729	RETERR(make_dnskey(key->key, buf, sizeof(buf), &dnskey));
1730	RETERR(dns_difftuple_create(mctx, DNS_DIFFOP_DEL, origin, ttl, &dnskey,
1731				    &tuple));
1732	dns_diff_appendminimal(diff, &tuple);
1733	result = ISC_R_SUCCESS;
1734
1735 failure:
1736	return (result);
1737}
1738
1739/*
1740 * Update 'keys' with information from 'newkeys'.
1741 *
1742 * If 'removed' is not NULL, any keys that are being removed from
1743 * the zone will be added to the list for post-removal processing.
1744 */
1745isc_result_t
1746dns_dnssec_updatekeys(dns_dnsseckeylist_t *keys, dns_dnsseckeylist_t *newkeys,
1747		      dns_dnsseckeylist_t *removed, dns_name_t *origin,
1748		      dns_ttl_t hint_ttl, dns_diff_t *diff,
1749		      isc_boolean_t allzsk, isc_mem_t *mctx,
1750		      void (*report)(const char *, ...))
1751{
1752	isc_result_t result;
1753	dns_dnsseckey_t *key, *key1, *key2, *next;
1754	isc_boolean_t found_ttl = ISC_FALSE;
1755	dns_ttl_t ttl = hint_ttl;
1756
1757	/*
1758	 * First, look through the existing key list to find keys
1759	 * supplied from the command line which are not in the zone.
1760	 * Update the zone to include them.
1761	 *
1762	 * Also, if there are keys published in the zone already,
1763	 * use their TTL for all subsequent published keys.
1764	 */
1765	for (key = ISC_LIST_HEAD(*keys);
1766	     key != NULL;
1767	     key = ISC_LIST_NEXT(key, link)) {
1768		if (key->source == dns_keysource_user &&
1769		    (key->hint_publish || key->force_publish)) {
1770			RETERR(publish_key(diff, key, origin, ttl,
1771					   mctx, allzsk, report));
1772		}
1773		if (key->source == dns_keysource_zoneapex) {
1774			ttl = dst_key_getttl(key->key);
1775			found_ttl = ISC_TRUE;
1776		}
1777	}
1778
1779	/*
1780	 * If there were no existing keys, use the smallest nonzero
1781	 * TTL of the keys found in the repository.
1782	 */
1783	if (!found_ttl && !ISC_LIST_EMPTY(*newkeys)) {
1784		dns_ttl_t shortest = 0;
1785
1786		for (key = ISC_LIST_HEAD(*newkeys);
1787		     key != NULL;
1788		     key = ISC_LIST_NEXT(key, link)) {
1789			dns_ttl_t thisttl = dst_key_getttl(key->key);
1790			if (thisttl != 0 &&
1791			    (shortest == 0 || thisttl < shortest))
1792				shortest = thisttl;
1793		}
1794
1795		if (shortest != 0)
1796			ttl = shortest;
1797	}
1798
1799	/*
1800	 * Second, scan the list of newly found keys looking for matches
1801	 * with known keys, and update accordingly.
1802	 */
1803	for (key1 = ISC_LIST_HEAD(*newkeys); key1 != NULL; key1 = next) {
1804		isc_boolean_t key_revoked = ISC_FALSE;
1805
1806		next = ISC_LIST_NEXT(key1, link);
1807
1808		for (key2 = ISC_LIST_HEAD(*keys);
1809		     key2 != NULL;
1810		     key2 = ISC_LIST_NEXT(key2, link)) {
1811			int f1 = dst_key_flags(key1->key);
1812			int f2 = dst_key_flags(key2->key);
1813			int nr1 = f1 & ~DNS_KEYFLAG_REVOKE;
1814			int nr2 = f2 & ~DNS_KEYFLAG_REVOKE;
1815			if (nr1 == nr2 &&
1816			    dst_key_alg(key1->key) == dst_key_alg(key2->key) &&
1817			    dst_key_pubcompare(key1->key, key2->key,
1818					       ISC_TRUE)) {
1819				int r1, r2;
1820				r1 = dst_key_flags(key1->key) &
1821					DNS_KEYFLAG_REVOKE;
1822				r2 = dst_key_flags(key2->key) &
1823					DNS_KEYFLAG_REVOKE;
1824				key_revoked = ISC_TF(r1 != r2);
1825				break;
1826			}
1827		}
1828
1829		/* No match found in keys; add the new key. */
1830		if (key2 == NULL) {
1831			ISC_LIST_UNLINK(*newkeys, key1, link);
1832			ISC_LIST_APPEND(*keys, key1, link);
1833
1834			if (key1->source != dns_keysource_zoneapex &&
1835			    (key1->hint_publish || key1->force_publish)) {
1836				RETERR(publish_key(diff, key1, origin, ttl,
1837						   mctx, allzsk, report));
1838				if (key1->hint_sign || key1->force_sign)
1839					key1->first_sign = ISC_TRUE;
1840			}
1841
1842			continue;
1843		}
1844
1845		/* Match found: remove or update it as needed */
1846		if (key1->hint_remove) {
1847			RETERR(remove_key(diff, key2, origin, ttl, mctx,
1848					  "expired", report));
1849			ISC_LIST_UNLINK(*keys, key2, link);
1850			if (removed != NULL)
1851				ISC_LIST_APPEND(*removed, key2, link);
1852			else
1853				dns_dnsseckey_destroy(mctx, &key2);
1854		} else if (key_revoked &&
1855			 (dst_key_flags(key1->key) & DNS_KEYFLAG_REVOKE) != 0) {
1856
1857			/*
1858			 * A previously valid key has been revoked.
1859			 * We need to remove the old version and pull
1860			 * in the new one.
1861			 */
1862			RETERR(remove_key(diff, key2, origin, ttl, mctx,
1863					  "revoked", report));
1864			ISC_LIST_UNLINK(*keys, key2, link);
1865			if (removed != NULL)
1866				ISC_LIST_APPEND(*removed, key2, link);
1867			else
1868				dns_dnsseckey_destroy(mctx, &key2);
1869
1870			RETERR(publish_key(diff, key1, origin, ttl,
1871					   mctx, allzsk, report));
1872			ISC_LIST_UNLINK(*newkeys, key1, link);
1873			ISC_LIST_APPEND(*keys, key1, link);
1874
1875			/*
1876			 * XXX: The revoke flag is only defined for trust
1877			 * anchors.  Setting the flag on a non-KSK is legal,
1878			 * but not defined in any RFC.  It seems reasonable
1879			 * to treat it the same as a KSK: keep it in the
1880			 * zone, sign the DNSKEY set with it, but not
1881			 * sign other records with it.
1882			 */
1883			key1->ksk = ISC_TRUE;
1884			continue;
1885		} else {
1886			if (!key2->is_active &&
1887			    (key1->hint_sign || key1->force_sign))
1888				key2->first_sign = ISC_TRUE;
1889			key2->hint_sign = key1->hint_sign;
1890			key2->hint_publish = key1->hint_publish;
1891		}
1892	}
1893
1894	/* Free any leftover keys in newkeys */
1895	while (!ISC_LIST_EMPTY(*newkeys)) {
1896		key1 = ISC_LIST_HEAD(*newkeys);
1897		ISC_LIST_UNLINK(*newkeys, key1, link);
1898		dns_dnsseckey_destroy(mctx, &key1);
1899	}
1900
1901	result = ISC_R_SUCCESS;
1902
1903 failure:
1904	return (result);
1905}
1906