dnssec.c revision 222395
1/*
2 * Copyright (C) 2004-2009  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.93.12.6 2009-06-22 23:47:18 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/mem.h>
30#include <isc/serial.h>
31#include <isc/string.h>
32#include <isc/util.h>
33
34#include <dns/db.h>
35#include <dns/dnssec.h>
36#include <dns/fixedname.h>
37#include <dns/keyvalues.h>
38#include <dns/message.h>
39#include <dns/rdata.h>
40#include <dns/rdatalist.h>
41#include <dns/rdataset.h>
42#include <dns/rdatastruct.h>
43#include <dns/result.h>
44#include <dns/tsig.h>		/* for DNS_TSIG_FUDGE */
45
46#include <dst/result.h>
47
48#define is_response(msg) (msg->flags & DNS_MESSAGEFLAG_QR)
49
50#define RETERR(x) do { \
51	result = (x); \
52	if (result != ISC_R_SUCCESS) \
53		goto failure; \
54	} while (0)
55
56
57#define TYPE_SIGN 0
58#define TYPE_VERIFY 1
59
60static isc_result_t
61digest_callback(void *arg, isc_region_t *data);
62
63static int
64rdata_compare_wrapper(const void *rdata1, const void *rdata2);
65
66static isc_result_t
67rdataset_to_sortedarray(dns_rdataset_t *set, isc_mem_t *mctx,
68			dns_rdata_t **rdata, int *nrdata);
69
70static isc_result_t
71digest_callback(void *arg, isc_region_t *data) {
72	dst_context_t *ctx = arg;
73
74	return (dst_context_adddata(ctx, data));
75}
76
77/*
78 * Make qsort happy.
79 */
80static int
81rdata_compare_wrapper(const void *rdata1, const void *rdata2) {
82	return (dns_rdata_compare((const dns_rdata_t *)rdata1,
83				  (const dns_rdata_t *)rdata2));
84}
85
86/*
87 * Sort the rdataset into an array.
88 */
89static isc_result_t
90rdataset_to_sortedarray(dns_rdataset_t *set, isc_mem_t *mctx,
91			dns_rdata_t **rdata, int *nrdata)
92{
93	isc_result_t ret;
94	int i = 0, n;
95	dns_rdata_t *data;
96	dns_rdataset_t rdataset;
97
98	n = dns_rdataset_count(set);
99
100	data = isc_mem_get(mctx, n * sizeof(dns_rdata_t));
101	if (data == NULL)
102		return (ISC_R_NOMEMORY);
103
104	dns_rdataset_init(&rdataset);
105	dns_rdataset_clone(set, &rdataset);
106	ret = dns_rdataset_first(&rdataset);
107	if (ret != ISC_R_SUCCESS) {
108		dns_rdataset_disassociate(&rdataset);
109		isc_mem_put(mctx, data, n * sizeof(dns_rdata_t));
110		return (ret);
111	}
112
113	/*
114	 * Put them in the array.
115	 */
116	do {
117		dns_rdata_init(&data[i]);
118		dns_rdataset_current(&rdataset, &data[i++]);
119	} while (dns_rdataset_next(&rdataset) == ISC_R_SUCCESS);
120
121	/*
122	 * Sort the array.
123	 */
124	qsort(data, n, sizeof(dns_rdata_t), rdata_compare_wrapper);
125	*rdata = data;
126	*nrdata = n;
127	dns_rdataset_disassociate(&rdataset);
128	return (ISC_R_SUCCESS);
129}
130
131isc_result_t
132dns_dnssec_keyfromrdata(dns_name_t *name, dns_rdata_t *rdata, isc_mem_t *mctx,
133			dst_key_t **key)
134{
135	isc_buffer_t b;
136	isc_region_t r;
137
138	INSIST(name != NULL);
139	INSIST(rdata != NULL);
140	INSIST(mctx != NULL);
141	INSIST(key != NULL);
142	INSIST(*key == NULL);
143	REQUIRE(rdata->type == dns_rdatatype_key ||
144		rdata->type == dns_rdatatype_dnskey);
145
146	dns_rdata_toregion(rdata, &r);
147	isc_buffer_init(&b, r.base, r.length);
148	isc_buffer_add(&b, r.length);
149	return (dst_key_fromdns(name, rdata->rdclass, &b, mctx, key));
150}
151
152static isc_result_t
153digest_sig(dst_context_t *ctx, dns_rdata_t *sigrdata, dns_rdata_rrsig_t *sig) {
154	isc_region_t r;
155	isc_result_t ret;
156	dns_fixedname_t fname;
157
158	dns_rdata_toregion(sigrdata, &r);
159	INSIST(r.length >= 19);
160
161	r.length = 18;
162	ret = dst_context_adddata(ctx, &r);
163	if (ret != ISC_R_SUCCESS)
164		return (ret);
165	dns_fixedname_init(&fname);
166	RUNTIME_CHECK(dns_name_downcase(&sig->signer,
167					dns_fixedname_name(&fname), NULL)
168		      == ISC_R_SUCCESS);
169	dns_name_toregion(dns_fixedname_name(&fname), &r);
170	return (dst_context_adddata(ctx, &r));
171}
172
173isc_result_t
174dns_dnssec_sign(dns_name_t *name, dns_rdataset_t *set, dst_key_t *key,
175		isc_stdtime_t *inception, isc_stdtime_t *expire,
176		isc_mem_t *mctx, isc_buffer_t *buffer, dns_rdata_t *sigrdata)
177{
178	dns_rdata_rrsig_t sig;
179	dns_rdata_t tmpsigrdata;
180	dns_rdata_t *rdatas;
181	int nrdatas, i;
182	isc_buffer_t sigbuf, envbuf;
183	isc_region_t r;
184	dst_context_t *ctx = NULL;
185	isc_result_t ret;
186	isc_buffer_t *databuf = NULL;
187	char data[256 + 8];
188	isc_uint32_t flags;
189	unsigned int sigsize;
190	dns_fixedname_t fnewname;
191
192	REQUIRE(name != NULL);
193	REQUIRE(dns_name_countlabels(name) <= 255);
194	REQUIRE(set != NULL);
195	REQUIRE(key != NULL);
196	REQUIRE(inception != NULL);
197	REQUIRE(expire != NULL);
198	REQUIRE(mctx != NULL);
199	REQUIRE(sigrdata != NULL);
200
201	if (*inception >= *expire)
202		return (DNS_R_INVALIDTIME);
203
204	/*
205	 * Is the key allowed to sign data?
206	 */
207	flags = dst_key_flags(key);
208	if (flags & DNS_KEYTYPE_NOAUTH)
209		return (DNS_R_KEYUNAUTHORIZED);
210	if ((flags & DNS_KEYFLAG_OWNERMASK) != DNS_KEYOWNER_ZONE)
211		return (DNS_R_KEYUNAUTHORIZED);
212
213	sig.mctx = mctx;
214	sig.common.rdclass = set->rdclass;
215	sig.common.rdtype = dns_rdatatype_rrsig;
216	ISC_LINK_INIT(&sig.common, link);
217
218	dns_name_init(&sig.signer, NULL);
219	dns_name_clone(dst_key_name(key), &sig.signer);
220
221	sig.covered = set->type;
222	sig.algorithm = dst_key_alg(key);
223	sig.labels = dns_name_countlabels(name) - 1;
224	if (dns_name_iswildcard(name))
225		sig.labels--;
226	sig.originalttl = set->ttl;
227	sig.timesigned = *inception;
228	sig.timeexpire = *expire;
229	sig.keyid = dst_key_id(key);
230	ret = dst_key_sigsize(key, &sigsize);
231	if (ret != ISC_R_SUCCESS)
232		return (ret);
233	sig.siglen = sigsize;
234	/*
235	 * The actual contents of sig.signature are not important yet, since
236	 * they're not used in digest_sig().
237	 */
238	sig.signature = isc_mem_get(mctx, sig.siglen);
239	if (sig.signature == NULL)
240		return (ISC_R_NOMEMORY);
241
242	ret = isc_buffer_allocate(mctx, &databuf, sigsize + 256 + 18);
243	if (ret != ISC_R_SUCCESS)
244		goto cleanup_signature;
245
246	dns_rdata_init(&tmpsigrdata);
247	ret = dns_rdata_fromstruct(&tmpsigrdata, sig.common.rdclass,
248				   sig.common.rdtype, &sig, databuf);
249	if (ret != ISC_R_SUCCESS)
250		goto cleanup_databuf;
251
252	ret = dst_context_create(key, mctx, &ctx);
253	if (ret != ISC_R_SUCCESS)
254		goto cleanup_databuf;
255
256	/*
257	 * Digest the SIG rdata.
258	 */
259	ret = digest_sig(ctx, &tmpsigrdata, &sig);
260	if (ret != ISC_R_SUCCESS)
261		goto cleanup_context;
262
263	dns_fixedname_init(&fnewname);
264	RUNTIME_CHECK(dns_name_downcase(name, dns_fixedname_name(&fnewname),
265					NULL) == ISC_R_SUCCESS);
266	dns_name_toregion(dns_fixedname_name(&fnewname), &r);
267
268	/*
269	 * Create an envelope for each rdata: <name|type|class|ttl>.
270	 */
271	isc_buffer_init(&envbuf, data, sizeof(data));
272	memcpy(data, r.base, r.length);
273	isc_buffer_add(&envbuf, r.length);
274	isc_buffer_putuint16(&envbuf, set->type);
275	isc_buffer_putuint16(&envbuf, set->rdclass);
276	isc_buffer_putuint32(&envbuf, set->ttl);
277
278	ret = rdataset_to_sortedarray(set, mctx, &rdatas, &nrdatas);
279	if (ret != ISC_R_SUCCESS)
280		goto cleanup_context;
281	isc_buffer_usedregion(&envbuf, &r);
282
283	for (i = 0; i < nrdatas; i++) {
284		isc_uint16_t len;
285		isc_buffer_t lenbuf;
286		isc_region_t lenr;
287
288		/*
289		 * Skip duplicates.
290		 */
291		if (i > 0 && dns_rdata_compare(&rdatas[i], &rdatas[i-1]) == 0)
292		    continue;
293
294		/*
295		 * Digest the envelope.
296		 */
297		ret = dst_context_adddata(ctx, &r);
298		if (ret != ISC_R_SUCCESS)
299			goto cleanup_array;
300
301		/*
302		 * Digest the length of the rdata.
303		 */
304		isc_buffer_init(&lenbuf, &len, sizeof(len));
305		INSIST(rdatas[i].length < 65536);
306		isc_buffer_putuint16(&lenbuf, (isc_uint16_t)rdatas[i].length);
307		isc_buffer_usedregion(&lenbuf, &lenr);
308		ret = dst_context_adddata(ctx, &lenr);
309		if (ret != ISC_R_SUCCESS)
310			goto cleanup_array;
311
312		/*
313		 * Digest the rdata.
314		 */
315		ret = dns_rdata_digest(&rdatas[i], digest_callback, ctx);
316		if (ret != ISC_R_SUCCESS)
317			goto cleanup_array;
318	}
319
320	isc_buffer_init(&sigbuf, sig.signature, sig.siglen);
321	ret = dst_context_sign(ctx, &sigbuf);
322	if (ret != ISC_R_SUCCESS)
323		goto cleanup_array;
324	isc_buffer_usedregion(&sigbuf, &r);
325	if (r.length != sig.siglen) {
326		ret = ISC_R_NOSPACE;
327		goto cleanup_array;
328	}
329	memcpy(sig.signature, r.base, sig.siglen);
330
331	ret = dns_rdata_fromstruct(sigrdata, sig.common.rdclass,
332				  sig.common.rdtype, &sig, buffer);
333
334cleanup_array:
335	isc_mem_put(mctx, rdatas, nrdatas * sizeof(dns_rdata_t));
336cleanup_context:
337	dst_context_destroy(&ctx);
338cleanup_databuf:
339	isc_buffer_free(&databuf);
340cleanup_signature:
341	isc_mem_put(mctx, sig.signature, sig.siglen);
342
343	return (ret);
344}
345
346isc_result_t
347dns_dnssec_verify2(dns_name_t *name, dns_rdataset_t *set, dst_key_t *key,
348		   isc_boolean_t ignoretime, isc_mem_t *mctx,
349		   dns_rdata_t *sigrdata, dns_name_t *wild)
350{
351	dns_rdata_rrsig_t sig;
352	dns_fixedname_t fnewname;
353	isc_region_t r;
354	isc_buffer_t envbuf;
355	dns_rdata_t *rdatas;
356	int nrdatas, i;
357	isc_stdtime_t now;
358	isc_result_t ret;
359	unsigned char data[300];
360	dst_context_t *ctx = NULL;
361	int labels = 0;
362	isc_uint32_t flags;
363
364	REQUIRE(name != NULL);
365	REQUIRE(set != NULL);
366	REQUIRE(key != NULL);
367	REQUIRE(mctx != NULL);
368	REQUIRE(sigrdata != NULL && sigrdata->type == dns_rdatatype_rrsig);
369
370	ret = dns_rdata_tostruct(sigrdata, &sig, NULL);
371	if (ret != ISC_R_SUCCESS)
372		return (ret);
373
374	if (set->type != sig.covered)
375		return (DNS_R_SIGINVALID);
376
377	if (isc_serial_lt(sig.timeexpire, sig.timesigned))
378		return (DNS_R_SIGINVALID);
379
380	if (!ignoretime) {
381		isc_stdtime_get(&now);
382
383		/*
384		 * Is SIG temporally valid?
385		 */
386		if (isc_serial_lt((isc_uint32_t)now, sig.timesigned))
387			return (DNS_R_SIGFUTURE);
388		else if (isc_serial_lt(sig.timeexpire, (isc_uint32_t)now))
389			return (DNS_R_SIGEXPIRED);
390	}
391
392	/*
393	 * NS, SOA and DNSSKEY records are signed by their owner.
394	 * DS records are signed by the parent.
395	 */
396	switch (set->type) {
397	case dns_rdatatype_ns:
398	case dns_rdatatype_soa:
399	case dns_rdatatype_dnskey:
400		if (!dns_name_equal(name, &sig.signer))
401			return (DNS_R_SIGINVALID);
402		break;
403	case dns_rdatatype_ds:
404		if (dns_name_equal(name, &sig.signer))
405			return (DNS_R_SIGINVALID);
406		/* FALLTHROUGH */
407	default:
408		if (!dns_name_issubdomain(name, &sig.signer))
409			return (DNS_R_SIGINVALID);
410		break;
411	}
412
413	/*
414	 * Is the key allowed to sign data?
415	 */
416	flags = dst_key_flags(key);
417	if (flags & DNS_KEYTYPE_NOAUTH)
418		return (DNS_R_KEYUNAUTHORIZED);
419	if ((flags & DNS_KEYFLAG_OWNERMASK) != DNS_KEYOWNER_ZONE)
420		return (DNS_R_KEYUNAUTHORIZED);
421
422	ret = dst_context_create(key, mctx, &ctx);
423	if (ret != ISC_R_SUCCESS)
424		goto cleanup_struct;
425
426	/*
427	 * Digest the SIG rdata (not including the signature).
428	 */
429	ret = digest_sig(ctx, sigrdata, &sig);
430	if (ret != ISC_R_SUCCESS)
431		goto cleanup_context;
432
433	/*
434	 * If the name is an expanded wildcard, use the wildcard name.
435	 */
436	dns_fixedname_init(&fnewname);
437	labels = dns_name_countlabels(name) - 1;
438	RUNTIME_CHECK(dns_name_downcase(name, dns_fixedname_name(&fnewname),
439					NULL) == ISC_R_SUCCESS);
440	if (labels - sig.labels > 0)
441		dns_name_split(dns_fixedname_name(&fnewname), sig.labels + 1,
442			       NULL, dns_fixedname_name(&fnewname));
443
444	dns_name_toregion(dns_fixedname_name(&fnewname), &r);
445
446	/*
447	 * Create an envelope for each rdata: <name|type|class|ttl>.
448	 */
449	isc_buffer_init(&envbuf, data, sizeof(data));
450	if (labels - sig.labels > 0) {
451		isc_buffer_putuint8(&envbuf, 1);
452		isc_buffer_putuint8(&envbuf, '*');
453		memcpy(data + 2, r.base, r.length);
454	}
455	else
456		memcpy(data, r.base, r.length);
457	isc_buffer_add(&envbuf, r.length);
458	isc_buffer_putuint16(&envbuf, set->type);
459	isc_buffer_putuint16(&envbuf, set->rdclass);
460	isc_buffer_putuint32(&envbuf, sig.originalttl);
461
462	ret = rdataset_to_sortedarray(set, mctx, &rdatas, &nrdatas);
463	if (ret != ISC_R_SUCCESS)
464		goto cleanup_context;
465
466	isc_buffer_usedregion(&envbuf, &r);
467
468	for (i = 0; i < nrdatas; i++) {
469		isc_uint16_t len;
470		isc_buffer_t lenbuf;
471		isc_region_t lenr;
472
473		/*
474		 * Skip duplicates.
475		 */
476		if (i > 0 && dns_rdata_compare(&rdatas[i], &rdatas[i-1]) == 0)
477		    continue;
478
479		/*
480		 * Digest the envelope.
481		 */
482		ret = dst_context_adddata(ctx, &r);
483		if (ret != ISC_R_SUCCESS)
484			goto cleanup_array;
485
486		/*
487		 * Digest the rdata length.
488		 */
489		isc_buffer_init(&lenbuf, &len, sizeof(len));
490		INSIST(rdatas[i].length < 65536);
491		isc_buffer_putuint16(&lenbuf, (isc_uint16_t)rdatas[i].length);
492		isc_buffer_usedregion(&lenbuf, &lenr);
493
494		/*
495		 * Digest the rdata.
496		 */
497		ret = dst_context_adddata(ctx, &lenr);
498		if (ret != ISC_R_SUCCESS)
499			goto cleanup_array;
500		ret = dns_rdata_digest(&rdatas[i], digest_callback, ctx);
501		if (ret != ISC_R_SUCCESS)
502			goto cleanup_array;
503	}
504
505	r.base = sig.signature;
506	r.length = sig.siglen;
507	ret = dst_context_verify(ctx, &r);
508	if (ret == DST_R_VERIFYFAILURE)
509		ret = DNS_R_SIGINVALID;
510
511cleanup_array:
512	isc_mem_put(mctx, rdatas, nrdatas * sizeof(dns_rdata_t));
513cleanup_context:
514	dst_context_destroy(&ctx);
515cleanup_struct:
516	dns_rdata_freestruct(&sig);
517
518	if (ret == ISC_R_SUCCESS && labels - sig.labels > 0) {
519		if (wild != NULL)
520			RUNTIME_CHECK(dns_name_concatenate(dns_wildcardname,
521						 dns_fixedname_name(&fnewname),
522						 wild, NULL) == ISC_R_SUCCESS);
523		ret = DNS_R_FROMWILDCARD;
524	}
525	return (ret);
526}
527
528isc_result_t
529dns_dnssec_verify(dns_name_t *name, dns_rdataset_t *set, dst_key_t *key,
530		  isc_boolean_t ignoretime, isc_mem_t *mctx,
531		  dns_rdata_t *sigrdata)
532{
533	isc_result_t result;
534
535	result = dns_dnssec_verify2(name, set, key, ignoretime, mctx,
536				    sigrdata, NULL);
537	if (result == DNS_R_FROMWILDCARD)
538		result = ISC_R_SUCCESS;
539	return (result);
540}
541
542#define is_zone_key(key) ((dst_key_flags(key) & DNS_KEYFLAG_OWNERMASK) \
543			  == DNS_KEYOWNER_ZONE)
544
545isc_result_t
546dns_dnssec_findzonekeys2(dns_db_t *db, dns_dbversion_t *ver,
547			 dns_dbnode_t *node, dns_name_t *name,
548			 const char *directory, isc_mem_t *mctx,
549			 unsigned int maxkeys, dst_key_t **keys,
550			 unsigned int *nkeys)
551{
552	dns_rdataset_t rdataset;
553	dns_rdata_t rdata = DNS_RDATA_INIT;
554	isc_result_t result;
555	dst_key_t *pubkey = NULL;
556	unsigned int count = 0;
557
558	REQUIRE(nkeys != NULL);
559	REQUIRE(keys != NULL);
560
561	*nkeys = 0;
562	dns_rdataset_init(&rdataset);
563	RETERR(dns_db_findrdataset(db, node, ver, dns_rdatatype_dnskey, 0, 0,
564				   &rdataset, NULL));
565	RETERR(dns_rdataset_first(&rdataset));
566	while (result == ISC_R_SUCCESS && count < maxkeys) {
567		pubkey = NULL;
568		dns_rdataset_current(&rdataset, &rdata);
569		RETERR(dns_dnssec_keyfromrdata(name, &rdata, mctx, &pubkey));
570		if (!is_zone_key(pubkey) ||
571		    (dst_key_flags(pubkey) & DNS_KEYTYPE_NOAUTH) != 0)
572			goto next;
573		/* Corrupted .key file? */
574		if (!dns_name_equal(name, dst_key_name(pubkey)))
575			goto next;
576		keys[count] = NULL;
577		result = dst_key_fromfile(dst_key_name(pubkey),
578					  dst_key_id(pubkey),
579					  dst_key_alg(pubkey),
580					  DST_TYPE_PUBLIC|DST_TYPE_PRIVATE,
581					  directory,
582					  mctx, &keys[count]);
583		if (result == ISC_R_FILENOTFOUND) {
584			keys[count] = pubkey;
585			pubkey = NULL;
586			count++;
587			goto next;
588		}
589		if (result != ISC_R_SUCCESS)
590			goto failure;
591		if ((dst_key_flags(keys[count]) & DNS_KEYTYPE_NOAUTH) != 0) {
592			/* We should never get here. */
593			dst_key_free(&keys[count]);
594			goto next;
595		}
596		count++;
597 next:
598		if (pubkey != NULL)
599			dst_key_free(&pubkey);
600		dns_rdata_reset(&rdata);
601		result = dns_rdataset_next(&rdataset);
602	}
603	if (result != ISC_R_NOMORE)
604		goto failure;
605	if (count == 0)
606		result = ISC_R_NOTFOUND;
607	else
608		result = ISC_R_SUCCESS;
609
610 failure:
611	if (dns_rdataset_isassociated(&rdataset))
612		dns_rdataset_disassociate(&rdataset);
613	if (pubkey != NULL)
614		dst_key_free(&pubkey);
615	if (result != ISC_R_SUCCESS)
616		while (count > 0)
617			dst_key_free(&keys[--count]);
618	*nkeys = count;
619	return (result);
620}
621
622isc_result_t
623dns_dnssec_findzonekeys(dns_db_t *db, dns_dbversion_t *ver,
624			dns_dbnode_t *node, dns_name_t *name, isc_mem_t *mctx,
625			unsigned int maxkeys, dst_key_t **keys,
626			unsigned int *nkeys)
627{
628	return (dns_dnssec_findzonekeys2(db, ver, node, name, NULL, mctx,
629					 maxkeys, keys, nkeys));
630}
631
632isc_result_t
633dns_dnssec_signmessage(dns_message_t *msg, dst_key_t *key) {
634	dns_rdata_sig_t sig;	/* SIG(0) */
635	unsigned char data[512];
636	unsigned char header[DNS_MESSAGE_HEADERLEN];
637	isc_buffer_t headerbuf, databuf, sigbuf;
638	unsigned int sigsize;
639	isc_buffer_t *dynbuf = NULL;
640	dns_rdata_t *rdata;
641	dns_rdatalist_t *datalist;
642	dns_rdataset_t *dataset;
643	isc_region_t r;
644	isc_stdtime_t now;
645	dst_context_t *ctx = NULL;
646	isc_mem_t *mctx;
647	isc_result_t result;
648	isc_boolean_t signeedsfree = ISC_TRUE;
649
650	REQUIRE(msg != NULL);
651	REQUIRE(key != NULL);
652
653	if (is_response(msg))
654		REQUIRE(msg->query.base != NULL);
655
656	mctx = msg->mctx;
657
658	memset(&sig, 0, sizeof(sig));
659
660	sig.mctx = mctx;
661	sig.common.rdclass = dns_rdataclass_any;
662	sig.common.rdtype = dns_rdatatype_sig;	/* SIG(0) */
663	ISC_LINK_INIT(&sig.common, link);
664
665	sig.covered = 0;
666	sig.algorithm = dst_key_alg(key);
667	sig.labels = 0; /* the root name */
668	sig.originalttl = 0;
669
670	isc_stdtime_get(&now);
671	sig.timesigned = now - DNS_TSIG_FUDGE;
672	sig.timeexpire = now + DNS_TSIG_FUDGE;
673
674	sig.keyid = dst_key_id(key);
675
676	dns_name_init(&sig.signer, NULL);
677	dns_name_clone(dst_key_name(key), &sig.signer);
678
679	sig.siglen = 0;
680	sig.signature = NULL;
681
682	isc_buffer_init(&databuf, data, sizeof(data));
683
684	RETERR(dst_context_create(key, mctx, &ctx));
685
686	/*
687	 * Digest the fields of the SIG - we can cheat and use
688	 * dns_rdata_fromstruct.  Since siglen is 0, the digested data
689	 * is identical to dns format.
690	 */
691	RETERR(dns_rdata_fromstruct(NULL, dns_rdataclass_any,
692				    dns_rdatatype_sig /* SIG(0) */,
693				    &sig, &databuf));
694	isc_buffer_usedregion(&databuf, &r);
695	RETERR(dst_context_adddata(ctx, &r));
696
697	/*
698	 * If this is a response, digest the query.
699	 */
700	if (is_response(msg))
701		RETERR(dst_context_adddata(ctx, &msg->query));
702
703	/*
704	 * Digest the header.
705	 */
706	isc_buffer_init(&headerbuf, header, sizeof(header));
707	dns_message_renderheader(msg, &headerbuf);
708	isc_buffer_usedregion(&headerbuf, &r);
709	RETERR(dst_context_adddata(ctx, &r));
710
711	/*
712	 * Digest the remainder of the message.
713	 */
714	isc_buffer_usedregion(msg->buffer, &r);
715	isc_region_consume(&r, DNS_MESSAGE_HEADERLEN);
716	RETERR(dst_context_adddata(ctx, &r));
717
718	RETERR(dst_key_sigsize(key, &sigsize));
719	sig.siglen = sigsize;
720	sig.signature = (unsigned char *) isc_mem_get(mctx, sig.siglen);
721	if (sig.signature == NULL) {
722		result = ISC_R_NOMEMORY;
723		goto failure;
724	}
725
726	isc_buffer_init(&sigbuf, sig.signature, sig.siglen);
727	RETERR(dst_context_sign(ctx, &sigbuf));
728	dst_context_destroy(&ctx);
729
730	rdata = NULL;
731	RETERR(dns_message_gettemprdata(msg, &rdata));
732	RETERR(isc_buffer_allocate(msg->mctx, &dynbuf, 1024));
733	RETERR(dns_rdata_fromstruct(rdata, dns_rdataclass_any,
734				    dns_rdatatype_sig /* SIG(0) */,
735				    &sig, dynbuf));
736
737	isc_mem_put(mctx, sig.signature, sig.siglen);
738	signeedsfree = ISC_FALSE;
739
740	dns_message_takebuffer(msg, &dynbuf);
741
742	datalist = NULL;
743	RETERR(dns_message_gettemprdatalist(msg, &datalist));
744	datalist->rdclass = dns_rdataclass_any;
745	datalist->type = dns_rdatatype_sig;	/* SIG(0) */
746	datalist->covers = 0;
747	datalist->ttl = 0;
748	ISC_LIST_INIT(datalist->rdata);
749	ISC_LIST_APPEND(datalist->rdata, rdata, link);
750	dataset = NULL;
751	RETERR(dns_message_gettemprdataset(msg, &dataset));
752	dns_rdataset_init(dataset);
753	RUNTIME_CHECK(dns_rdatalist_tordataset(datalist, dataset) == ISC_R_SUCCESS);
754	msg->sig0 = dataset;
755
756	return (ISC_R_SUCCESS);
757
758failure:
759	if (dynbuf != NULL)
760		isc_buffer_free(&dynbuf);
761	if (signeedsfree)
762		isc_mem_put(mctx, sig.signature, sig.siglen);
763	if (ctx != NULL)
764		dst_context_destroy(&ctx);
765
766	return (result);
767}
768
769isc_result_t
770dns_dnssec_verifymessage(isc_buffer_t *source, dns_message_t *msg,
771			 dst_key_t *key)
772{
773	dns_rdata_sig_t sig;	/* SIG(0) */
774	unsigned char header[DNS_MESSAGE_HEADERLEN];
775	dns_rdata_t rdata = DNS_RDATA_INIT;
776	isc_region_t r, source_r, sig_r, header_r;
777	isc_stdtime_t now;
778	dst_context_t *ctx = NULL;
779	isc_mem_t *mctx;
780	isc_result_t result;
781	isc_uint16_t addcount;
782	isc_boolean_t signeedsfree = ISC_FALSE;
783
784	REQUIRE(source != NULL);
785	REQUIRE(msg != NULL);
786	REQUIRE(key != NULL);
787
788	mctx = msg->mctx;
789
790	msg->verify_attempted = 1;
791
792	if (is_response(msg)) {
793		if (msg->query.base == NULL)
794			return (DNS_R_UNEXPECTEDTSIG);
795	}
796
797	isc_buffer_usedregion(source, &source_r);
798
799	RETERR(dns_rdataset_first(msg->sig0));
800	dns_rdataset_current(msg->sig0, &rdata);
801
802	RETERR(dns_rdata_tostruct(&rdata, &sig, NULL));
803	signeedsfree = ISC_TRUE;
804
805	if (sig.labels != 0) {
806		result = DNS_R_SIGINVALID;
807		goto failure;
808	}
809
810	if (isc_serial_lt(sig.timeexpire, sig.timesigned)) {
811		result = DNS_R_SIGINVALID;
812		msg->sig0status = dns_tsigerror_badtime;
813		goto failure;
814	}
815
816	isc_stdtime_get(&now);
817	if (isc_serial_lt((isc_uint32_t)now, sig.timesigned)) {
818		result = DNS_R_SIGFUTURE;
819		msg->sig0status = dns_tsigerror_badtime;
820		goto failure;
821	}
822	else if (isc_serial_lt(sig.timeexpire, (isc_uint32_t)now)) {
823		result = DNS_R_SIGEXPIRED;
824		msg->sig0status = dns_tsigerror_badtime;
825		goto failure;
826	}
827
828	if (!dns_name_equal(dst_key_name(key), &sig.signer)) {
829		result = DNS_R_SIGINVALID;
830		msg->sig0status = dns_tsigerror_badkey;
831		goto failure;
832	}
833
834	RETERR(dst_context_create(key, mctx, &ctx));
835
836	/*
837	 * Digest the SIG(0) record, except for the signature.
838	 */
839	dns_rdata_toregion(&rdata, &r);
840	r.length -= sig.siglen;
841	RETERR(dst_context_adddata(ctx, &r));
842
843	/*
844	 * If this is a response, digest the query.
845	 */
846	if (is_response(msg))
847		RETERR(dst_context_adddata(ctx, &msg->query));
848
849	/*
850	 * Extract the header.
851	 */
852	memcpy(header, source_r.base, DNS_MESSAGE_HEADERLEN);
853
854	/*
855	 * Decrement the additional field counter.
856	 */
857	memcpy(&addcount, &header[DNS_MESSAGE_HEADERLEN - 2], 2);
858	addcount = htons((isc_uint16_t)(ntohs(addcount) - 1));
859	memcpy(&header[DNS_MESSAGE_HEADERLEN - 2], &addcount, 2);
860
861	/*
862	 * Digest the modified header.
863	 */
864	header_r.base = (unsigned char *) header;
865	header_r.length = DNS_MESSAGE_HEADERLEN;
866	RETERR(dst_context_adddata(ctx, &header_r));
867
868	/*
869	 * Digest all non-SIG(0) records.
870	 */
871	r.base = source_r.base + DNS_MESSAGE_HEADERLEN;
872	r.length = msg->sigstart - DNS_MESSAGE_HEADERLEN;
873	RETERR(dst_context_adddata(ctx, &r));
874
875	sig_r.base = sig.signature;
876	sig_r.length = sig.siglen;
877	result = dst_context_verify(ctx, &sig_r);
878	if (result != ISC_R_SUCCESS) {
879		msg->sig0status = dns_tsigerror_badsig;
880		goto failure;
881	}
882
883	msg->verified_sig = 1;
884
885	dst_context_destroy(&ctx);
886	dns_rdata_freestruct(&sig);
887
888	return (ISC_R_SUCCESS);
889
890failure:
891	if (signeedsfree)
892		dns_rdata_freestruct(&sig);
893	if (ctx != NULL)
894		dst_context_destroy(&ctx);
895
896	return (result);
897}
898
899/*%
900 * Does this key ('rdata') self sign the rrset ('rdataset')?
901 */
902isc_boolean_t
903dns_dnssec_selfsigns(dns_rdata_t *rdata, dns_name_t *name,
904		     dns_rdataset_t *rdataset, dns_rdataset_t *sigrdataset,
905		     isc_boolean_t ignoretime, isc_mem_t *mctx)
906{
907	dst_key_t *dstkey = NULL;
908	dns_keytag_t keytag;
909	dns_rdata_dnskey_t key;
910	dns_rdata_rrsig_t sig;
911	dns_rdata_t sigrdata = DNS_RDATA_INIT;
912	isc_result_t result;
913
914	INSIST(rdataset->type == dns_rdatatype_key ||
915	       rdataset->type == dns_rdatatype_dnskey);
916	if (rdataset->type == dns_rdatatype_key) {
917		INSIST(sigrdataset->type == dns_rdatatype_sig);
918		INSIST(sigrdataset->covers == dns_rdatatype_key);
919	} else {
920		INSIST(sigrdataset->type == dns_rdatatype_rrsig);
921		INSIST(sigrdataset->covers == dns_rdatatype_dnskey);
922	}
923
924	result = dns_dnssec_keyfromrdata(name, rdata, mctx, &dstkey);
925	if (result != ISC_R_SUCCESS)
926		return (ISC_FALSE);
927	result = dns_rdata_tostruct(rdata, &key, NULL);
928	RUNTIME_CHECK(result == ISC_R_SUCCESS);
929
930	keytag = dst_key_id(dstkey);
931	for (result = dns_rdataset_first(sigrdataset);
932	     result == ISC_R_SUCCESS;
933	     result = dns_rdataset_next(sigrdataset))
934	{
935		dns_rdata_reset(&sigrdata);
936		dns_rdataset_current(sigrdataset, &sigrdata);
937		result = dns_rdata_tostruct(&sigrdata, &sig, NULL);
938		RUNTIME_CHECK(result == ISC_R_SUCCESS);
939
940		if (sig.algorithm == key.algorithm &&
941		    sig.keyid == keytag) {
942			result = dns_dnssec_verify2(name, rdataset, dstkey,
943						    ignoretime, mctx,
944						    &sigrdata, NULL);
945			if (result == ISC_R_SUCCESS) {
946				dst_key_free(&dstkey);
947				return (ISC_TRUE);
948			}
949		}
950	}
951	dst_key_free(&dstkey);
952	return (ISC_FALSE);
953}
954