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