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