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