xref: /openbsd/usr.bin/dig/lib/dns/tsig.c (revision e6c7c102)
1 /*
2  * Copyright (C) Internet Systems Consortium, Inc. ("ISC")
3  *
4  * Permission to use, copy, modify, and/or distribute this software for any
5  * purpose with or without fee is hereby granted, provided that the above
6  * copyright notice and this permission notice appear in all copies.
7  *
8  * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
9  * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
10  * AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
11  * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
12  * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
13  * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
14  * PERFORMANCE OF THIS SOFTWARE.
15  */
16 
17 /*
18  * $Id: tsig.c,v 1.15 2024/04/23 13:34:50 jsg Exp $
19  */
20 /*! \file */
21 
22 #include <stdlib.h>
23 #include <string.h>		/* Required for HP/UX (and others?) */
24 #include <time.h>
25 
26 #include <isc/util.h>
27 #include <isc/buffer.h>
28 #include <isc/refcount.h>
29 
30 #include <dns/keyvalues.h>
31 #include <dns/log.h>
32 #include <dns/message.h>
33 #include <dns/rdata.h>
34 #include <dns/rdatalist.h>
35 #include <dns/rdataset.h>
36 #include <dns/result.h>
37 #include <dns/tsig.h>
38 
39 #include <dst/result.h>
40 
41 #define is_response(msg) (msg->flags & DNS_MESSAGEFLAG_QR)
42 #define algname_is_allocated(algname) \
43 	((algname) != dns_tsig_hmacsha1_name && \
44 	 (algname) != dns_tsig_hmacsha224_name && \
45 	 (algname) != dns_tsig_hmacsha256_name && \
46 	 (algname) != dns_tsig_hmacsha384_name && \
47 	 (algname) != dns_tsig_hmacsha512_name)
48 
49 #define BADTIMELEN 6
50 
51 static unsigned char hmacsha1_ndata[] = "\011hmac-sha1";
52 static unsigned char hmacsha1_offsets[] = { 0, 10 };
53 static dns_name_t hmacsha1 =
54 	DNS_NAME_INITABSOLUTE(hmacsha1_ndata, hmacsha1_offsets);
55 dns_name_t *dns_tsig_hmacsha1_name = &hmacsha1;
56 
57 static unsigned char hmacsha224_ndata[] = "\013hmac-sha224";
58 static unsigned char hmacsha224_offsets[] = { 0, 12 };
59 static dns_name_t hmacsha224 =
60 	DNS_NAME_INITABSOLUTE(hmacsha224_ndata, hmacsha224_offsets);
61 dns_name_t *dns_tsig_hmacsha224_name = &hmacsha224;
62 
63 static unsigned char hmacsha256_ndata[] = "\013hmac-sha256";
64 static unsigned char hmacsha256_offsets[] = { 0, 12 };
65 static dns_name_t hmacsha256 =
66 	DNS_NAME_INITABSOLUTE(hmacsha256_ndata, hmacsha256_offsets);
67 dns_name_t *dns_tsig_hmacsha256_name = &hmacsha256;
68 
69 static unsigned char hmacsha384_ndata[] = "\013hmac-sha384";
70 static unsigned char hmacsha384_offsets[] = { 0, 12 };
71 static dns_name_t hmacsha384 =
72 	DNS_NAME_INITABSOLUTE(hmacsha384_ndata, hmacsha384_offsets);
73 dns_name_t *dns_tsig_hmacsha384_name = &hmacsha384;
74 
75 static unsigned char hmacsha512_ndata[] = "\013hmac-sha512";
76 static unsigned char hmacsha512_offsets[] = { 0, 12 };
77 static dns_name_t hmacsha512 =
78 	DNS_NAME_INITABSOLUTE(hmacsha512_ndata, hmacsha512_offsets);
79 dns_name_t *dns_tsig_hmacsha512_name = &hmacsha512;
80 
81 static isc_result_t
82 tsig_verify_tcp(isc_buffer_t *source, dns_message_t *msg);
83 
84 static void
85 tsig_log(dns_tsigkey_t *key, int level, const char *fmt, ...)
86      __attribute__((__format__(__printf__, 3, 4)));
87 
88 static void
89 tsigkey_free(dns_tsigkey_t *key);
90 
91 static void
tsig_log(dns_tsigkey_t * key,int level,const char * fmt,...)92 tsig_log(dns_tsigkey_t *key, int level, const char *fmt, ...) {
93 	va_list ap;
94 	char message[4096];
95 	char namestr[DNS_NAME_FORMATSIZE];
96 	char creatorstr[DNS_NAME_FORMATSIZE];
97 
98 	if (!isc_log_wouldlog(dns_lctx, level))
99 		return;
100 	if (key != NULL) {
101 		dns_name_format(&key->name, namestr, sizeof(namestr));
102 	} else {
103 		strlcpy(namestr, "<null>", sizeof(namestr));
104 	}
105 
106 	if (key != NULL && key->generated && key->creator) {
107 		dns_name_format(key->creator, creatorstr, sizeof(creatorstr));
108 	} else {
109 		strlcpy(creatorstr, "<null>", sizeof(creatorstr));
110 	}
111 
112 	va_start(ap, fmt);
113 	vsnprintf(message, sizeof(message), fmt, ap);
114 	va_end(ap);
115 	if (key != NULL && key->generated) {
116 		isc_log_write(dns_lctx,
117 			      DNS_LOGCATEGORY_DNSSEC, DNS_LOGMODULE_TSIG,
118 			      level, "tsig key '%s' (%s): %s",
119 			      namestr, creatorstr, message);
120 	} else {
121 		isc_log_write(dns_lctx,
122 			      DNS_LOGCATEGORY_DNSSEC, DNS_LOGMODULE_TSIG,
123 			      level, "tsig key '%s': %s", namestr, message);
124 	}
125 }
126 
127 isc_result_t
dns_tsigkey_createfromkey(dns_name_t * name,dns_name_t * algorithm,dst_key_t * dstkey,int generated,dns_name_t * creator,time_t inception,time_t expire,dns_tsigkey_t ** key)128 dns_tsigkey_createfromkey(dns_name_t *name, dns_name_t *algorithm,
129 			  dst_key_t *dstkey, int generated,
130 			  dns_name_t *creator, time_t inception,
131 			  time_t expire,
132 			  dns_tsigkey_t **key)
133 {
134 	dns_tsigkey_t *tkey;
135 	isc_result_t ret;
136 	unsigned int refs = 0;
137 
138 	REQUIRE(key == NULL || *key == NULL);
139 	REQUIRE(name != NULL);
140 	REQUIRE(algorithm != NULL);
141 	REQUIRE(key != NULL);
142 
143 	tkey = (dns_tsigkey_t *) malloc(sizeof(dns_tsigkey_t));
144 	if (tkey == NULL)
145 		return (ISC_R_NOMEMORY);
146 
147 	dns_name_init(&tkey->name, NULL);
148 	ret = dns_name_dup(name, &tkey->name);
149 	if (ret != ISC_R_SUCCESS)
150 		goto cleanup_key;
151 	(void)dns_name_downcase(&tkey->name, &tkey->name, NULL);
152 
153 	if (dns_name_equal(algorithm, DNS_TSIG_HMACSHA1_NAME)) {
154 		tkey->algorithm = DNS_TSIG_HMACSHA1_NAME;
155 		if (dstkey != NULL && dst_key_alg(dstkey) != DST_ALG_HMACSHA1) {
156 			ret = DNS_R_BADALG;
157 			goto cleanup_name;
158 		}
159 	} else if (dns_name_equal(algorithm, DNS_TSIG_HMACSHA224_NAME)) {
160 		tkey->algorithm = DNS_TSIG_HMACSHA224_NAME;
161 		if (dstkey != NULL &&
162 		    dst_key_alg(dstkey) != DST_ALG_HMACSHA224) {
163 			ret = DNS_R_BADALG;
164 			goto cleanup_name;
165 		}
166 	} else if (dns_name_equal(algorithm, DNS_TSIG_HMACSHA256_NAME)) {
167 		tkey->algorithm = DNS_TSIG_HMACSHA256_NAME;
168 		if (dstkey != NULL &&
169 		    dst_key_alg(dstkey) != DST_ALG_HMACSHA256) {
170 			ret = DNS_R_BADALG;
171 			goto cleanup_name;
172 		}
173 	} else if (dns_name_equal(algorithm, DNS_TSIG_HMACSHA384_NAME)) {
174 		tkey->algorithm = DNS_TSIG_HMACSHA384_NAME;
175 		if (dstkey != NULL &&
176 		    dst_key_alg(dstkey) != DST_ALG_HMACSHA384) {
177 			ret = DNS_R_BADALG;
178 			goto cleanup_name;
179 		}
180 	} else if (dns_name_equal(algorithm, DNS_TSIG_HMACSHA512_NAME)) {
181 		tkey->algorithm = DNS_TSIG_HMACSHA512_NAME;
182 		if (dstkey != NULL &&
183 		    dst_key_alg(dstkey) != DST_ALG_HMACSHA512) {
184 			ret = DNS_R_BADALG;
185 			goto cleanup_name;
186 		}
187 	} else {
188 		if (dstkey != NULL) {
189 			ret = DNS_R_BADALG;
190 			goto cleanup_name;
191 		}
192 		tkey->algorithm = malloc(sizeof(dns_name_t));
193 		if (tkey->algorithm == NULL) {
194 			ret = ISC_R_NOMEMORY;
195 			goto cleanup_name;
196 		}
197 		dns_name_init(tkey->algorithm, NULL);
198 		ret = dns_name_dup(algorithm, tkey->algorithm);
199 		if (ret != ISC_R_SUCCESS)
200 			goto cleanup_algorithm;
201 		(void)dns_name_downcase(tkey->algorithm, tkey->algorithm,
202 					NULL);
203 	}
204 
205 	if (creator != NULL) {
206 		tkey->creator = malloc(sizeof(dns_name_t));
207 		if (tkey->creator == NULL) {
208 			ret = ISC_R_NOMEMORY;
209 			goto cleanup_algorithm;
210 		}
211 		dns_name_init(tkey->creator, NULL);
212 		ret = dns_name_dup(creator, tkey->creator);
213 		if (ret != ISC_R_SUCCESS) {
214 			free(tkey->creator);
215 			goto cleanup_algorithm;
216 		}
217 	} else
218 		tkey->creator = NULL;
219 
220 	tkey->key = NULL;
221 	if (dstkey != NULL)
222 		dst_key_attach(dstkey, &tkey->key);
223 
224 	if (key != NULL)
225 		refs = 1;
226 
227 	ret = isc_refcount_init(&tkey->refs, refs);
228 	if (ret != ISC_R_SUCCESS)
229 		goto cleanup_creator;
230 
231 	tkey->generated = generated;
232 	tkey->inception = inception;
233 	tkey->expire = expire;
234 	ISC_LINK_INIT(tkey, link);
235 
236 	/*
237 	 * Ignore this if it's a GSS key, since the key size is meaningless.
238 	 */
239 	if (dstkey != NULL && dst_key_size(dstkey) < 64) {
240 		char namestr[DNS_NAME_FORMATSIZE];
241 		dns_name_format(name, namestr, sizeof(namestr));
242 		isc_log_write(dns_lctx, DNS_LOGCATEGORY_DNSSEC,
243 			      DNS_LOGMODULE_TSIG, ISC_LOG_INFO,
244 			      "the key '%s' is too short to be secure",
245 			      namestr);
246 	}
247 
248 	if (key != NULL)
249 		*key = tkey;
250 
251 	return (ISC_R_SUCCESS);
252 
253  cleanup_creator:
254 	if (tkey->key != NULL)
255 		dst_key_free(&tkey->key);
256 	if (tkey->creator != NULL) {
257 		dns_name_free(tkey->creator);
258 		free(tkey->creator);
259 	}
260  cleanup_algorithm:
261 	if (algname_is_allocated(tkey->algorithm)) {
262 		if (dns_name_dynamic(tkey->algorithm))
263 			dns_name_free(tkey->algorithm);
264 		free(tkey->algorithm);
265 	}
266  cleanup_name:
267 	dns_name_free(&tkey->name);
268  cleanup_key:
269 	free(tkey);
270 
271 	return (ret);
272 }
273 
274 isc_result_t
dns_tsigkey_create(dns_name_t * name,dns_name_t * algorithm,unsigned char * secret,int length,int generated,dns_name_t * creator,time_t inception,time_t expire,dns_tsigkey_t ** key)275 dns_tsigkey_create(dns_name_t *name, dns_name_t *algorithm,
276 		   unsigned char *secret, int length, int generated,
277 		   dns_name_t *creator, time_t inception,
278 		   time_t expire,
279 		   dns_tsigkey_t **key)
280 {
281 	dst_key_t *dstkey = NULL;
282 	isc_result_t result;
283 
284 	REQUIRE(length >= 0);
285 	if (length > 0)
286 		REQUIRE(secret != NULL);
287 
288 	if (dns_name_equal(algorithm, DNS_TSIG_HMACSHA1_NAME)) {
289 		if (secret != NULL) {
290 			isc_buffer_t b;
291 
292 			isc_buffer_init(&b, secret, length);
293 			isc_buffer_add(&b, length);
294 			result = dst_key_frombuffer(DST_ALG_HMACSHA1,
295 						    DNS_KEYOWNER_ENTITY,
296 						    DNS_KEYPROTO_DNSSEC,
297 						    &b, &dstkey);
298 			if (result != ISC_R_SUCCESS)
299 				return (result);
300 		}
301 	} else if (dns_name_equal(algorithm, DNS_TSIG_HMACSHA224_NAME)) {
302 		if (secret != NULL) {
303 			isc_buffer_t b;
304 
305 			isc_buffer_init(&b, secret, length);
306 			isc_buffer_add(&b, length);
307 			result = dst_key_frombuffer(DST_ALG_HMACSHA224,
308 						    DNS_KEYOWNER_ENTITY,
309 						    DNS_KEYPROTO_DNSSEC,
310 						    &b, &dstkey);
311 			if (result != ISC_R_SUCCESS)
312 				return (result);
313 		}
314 	} else if (dns_name_equal(algorithm, DNS_TSIG_HMACSHA256_NAME)) {
315 		if (secret != NULL) {
316 			isc_buffer_t b;
317 
318 			isc_buffer_init(&b, secret, length);
319 			isc_buffer_add(&b, length);
320 			result = dst_key_frombuffer(DST_ALG_HMACSHA256,
321 						    DNS_KEYOWNER_ENTITY,
322 						    DNS_KEYPROTO_DNSSEC,
323 						    &b, &dstkey);
324 			if (result != ISC_R_SUCCESS)
325 				return (result);
326 		}
327 	} else if (dns_name_equal(algorithm, DNS_TSIG_HMACSHA384_NAME)) {
328 		if (secret != NULL) {
329 			isc_buffer_t b;
330 
331 			isc_buffer_init(&b, secret, length);
332 			isc_buffer_add(&b, length);
333 			result = dst_key_frombuffer(DST_ALG_HMACSHA384,
334 						    DNS_KEYOWNER_ENTITY,
335 						    DNS_KEYPROTO_DNSSEC,
336 						    &b, &dstkey);
337 			if (result != ISC_R_SUCCESS)
338 				return (result);
339 		}
340 	} else if (dns_name_equal(algorithm, DNS_TSIG_HMACSHA512_NAME)) {
341 		if (secret != NULL) {
342 			isc_buffer_t b;
343 
344 			isc_buffer_init(&b, secret, length);
345 			isc_buffer_add(&b, length);
346 			result = dst_key_frombuffer(DST_ALG_HMACSHA512,
347 						    DNS_KEYOWNER_ENTITY,
348 						    DNS_KEYPROTO_DNSSEC,
349 						    &b, &dstkey);
350 			if (result != ISC_R_SUCCESS)
351 				return (result);
352 		}
353 	} else if (length > 0)
354 		return (DNS_R_BADALG);
355 
356 	result = dns_tsigkey_createfromkey(name, algorithm, dstkey,
357 					   generated, creator,
358 					   inception, expire, key);
359 	if (dstkey != NULL)
360 		dst_key_free(&dstkey);
361 	return (result);
362 }
363 
364 void
dns_tsigkey_attach(dns_tsigkey_t * source,dns_tsigkey_t ** targetp)365 dns_tsigkey_attach(dns_tsigkey_t *source, dns_tsigkey_t **targetp) {
366 	REQUIRE(targetp != NULL && *targetp == NULL);
367 
368 	isc_refcount_increment(&source->refs, NULL);
369 	*targetp = source;
370 }
371 
372 static void
tsigkey_free(dns_tsigkey_t * key)373 tsigkey_free(dns_tsigkey_t *key) {
374 	dns_name_free(&key->name);
375 	if (algname_is_allocated(key->algorithm)) {
376 		dns_name_free(key->algorithm);
377 		free(key->algorithm);
378 	}
379 	if (key->key != NULL)
380 		dst_key_free(&key->key);
381 	if (key->creator != NULL) {
382 		dns_name_free(key->creator);
383 		free(key->creator);
384 	}
385 	isc_refcount_destroy(&key->refs);
386 	free(key);
387 }
388 
389 void
dns_tsigkey_detach(dns_tsigkey_t ** keyp)390 dns_tsigkey_detach(dns_tsigkey_t **keyp) {
391 	dns_tsigkey_t *key;
392 	unsigned int refs;
393 
394 	REQUIRE(keyp != NULL);
395 
396 	key = *keyp;
397 	isc_refcount_decrement(&key->refs, &refs);
398 
399 	if (refs == 0)
400 		tsigkey_free(key);
401 
402 	*keyp = NULL;
403 }
404 
405 isc_result_t
dns_tsig_sign(dns_message_t * msg)406 dns_tsig_sign(dns_message_t *msg) {
407 	dns_tsigkey_t *key;
408 	dns_rdata_any_tsig_t tsig, querytsig;
409 	unsigned char data[128];
410 	isc_buffer_t databuf, sigbuf;
411 	isc_buffer_t *dynbuf;
412 	dns_name_t *owner;
413 	dns_rdata_t *rdata = NULL;
414 	dns_rdatalist_t *datalist;
415 	dns_rdataset_t *dataset;
416 	isc_region_t r;
417 	time_t now;
418 	dst_context_t *ctx = NULL;
419 	isc_result_t ret;
420 	unsigned char badtimedata[BADTIMELEN];
421 	unsigned int sigsize = 0;
422 	int response;
423 
424 	REQUIRE(msg != NULL);
425 	key = dns_message_gettsigkey(msg);
426 
427 	/*
428 	 * If this is a response, there should be a query tsig.
429 	 */
430 	response = is_response(msg);
431 	if (response && msg->querytsig == NULL)
432 		return (DNS_R_EXPECTEDTSIG);
433 
434 	dynbuf = NULL;
435 
436 	tsig.common.rdclass = dns_rdataclass_any;
437 	tsig.common.rdtype = dns_rdatatype_tsig;
438 	ISC_LINK_INIT(&tsig.common, link);
439 	dns_name_init(&tsig.algorithm, NULL);
440 	dns_name_clone(key->algorithm, &tsig.algorithm);
441 
442 	time(&now);
443 	tsig.timesigned = now + msg->timeadjust;
444 	tsig.fudge = DNS_TSIG_FUDGE;
445 
446 	tsig.originalid = msg->id;
447 
448 	isc_buffer_init(&databuf, data, sizeof(data));
449 
450 	if (response)
451 		tsig.error = msg->querytsigstatus;
452 	else
453 		tsig.error = dns_rcode_noerror;
454 
455 	if (tsig.error != dns_tsigerror_badtime) {
456 		tsig.otherlen = 0;
457 		tsig.other = NULL;
458 	} else {
459 		isc_buffer_t otherbuf;
460 
461 		tsig.otherlen = BADTIMELEN;
462 		tsig.other = badtimedata;
463 		isc_buffer_init(&otherbuf, tsig.other, tsig.otherlen);
464 		isc_buffer_putuint48(&otherbuf, tsig.timesigned);
465 	}
466 
467 	if ((key->key != NULL) &&
468 	    (tsig.error != dns_tsigerror_badsig) &&
469 	    (tsig.error != dns_tsigerror_badkey))
470 	{
471 		unsigned char header[DNS_MESSAGE_HEADERLEN];
472 		isc_buffer_t headerbuf;
473 		uint16_t digestbits;
474 
475 		/*
476 		 * If it is a response, we assume that the request MAC
477 		 * has validated at this point. This is why we include a
478 		 * MAC length > 0 in the reply.
479 		 */
480 		ret = dst_context_create3(key->key,
481 					  DNS_LOGCATEGORY_DNSSEC,
482 					  1, &ctx);
483 		if (ret != ISC_R_SUCCESS)
484 			return (ret);
485 
486 		/*
487 		 * If this is a response, digest the request's MAC.
488 		 */
489 		if (response) {
490 			dns_rdata_t querytsigrdata = DNS_RDATA_INIT;
491 
492 			INSIST(msg->verified_sig);
493 
494 			ret = dns_rdataset_first(msg->querytsig);
495 			if (ret != ISC_R_SUCCESS)
496 				goto cleanup_context;
497 			dns_rdataset_current(msg->querytsig, &querytsigrdata);
498 			ret = dns_rdata_tostruct_tsig(&querytsigrdata,
499 						      &querytsig);
500 			if (ret != ISC_R_SUCCESS)
501 				goto cleanup_context;
502 			isc_buffer_putuint16(&databuf, querytsig.siglen);
503 			if (isc_buffer_availablelength(&databuf) <
504 			    querytsig.siglen) {
505 				ret = ISC_R_NOSPACE;
506 				goto cleanup_context;
507 			}
508 			isc_buffer_putmem(&databuf, querytsig.signature,
509 					  querytsig.siglen);
510 			isc_buffer_usedregion(&databuf, &r);
511 			ret = dst_context_adddata(ctx, &r);
512 			if (ret != ISC_R_SUCCESS)
513 				goto cleanup_context;
514 		}
515 
516 		/*
517 		 * Digest the header.
518 		 */
519 		isc_buffer_init(&headerbuf, header, sizeof(header));
520 		dns_message_renderheader(msg, &headerbuf);
521 		isc_buffer_usedregion(&headerbuf, &r);
522 		ret = dst_context_adddata(ctx, &r);
523 		if (ret != ISC_R_SUCCESS)
524 			goto cleanup_context;
525 
526 		/*
527 		 * Digest the remainder of the message.
528 		 */
529 		isc_buffer_usedregion(msg->buffer, &r);
530 		isc_region_consume(&r, DNS_MESSAGE_HEADERLEN);
531 		ret = dst_context_adddata(ctx, &r);
532 		if (ret != ISC_R_SUCCESS)
533 			goto cleanup_context;
534 
535 		if (msg->tcp_continuation == 0) {
536 			/*
537 			 * Digest the name, class, ttl, alg.
538 			 */
539 			dns_name_toregion(&key->name, &r);
540 			ret = dst_context_adddata(ctx, &r);
541 			if (ret != ISC_R_SUCCESS)
542 				goto cleanup_context;
543 
544 			isc_buffer_clear(&databuf);
545 			isc_buffer_putuint16(&databuf, dns_rdataclass_any);
546 			isc_buffer_putuint32(&databuf, 0); /* ttl */
547 			isc_buffer_usedregion(&databuf, &r);
548 			ret = dst_context_adddata(ctx, &r);
549 			if (ret != ISC_R_SUCCESS)
550 				goto cleanup_context;
551 
552 			dns_name_toregion(&tsig.algorithm, &r);
553 			ret = dst_context_adddata(ctx, &r);
554 			if (ret != ISC_R_SUCCESS)
555 				goto cleanup_context;
556 
557 		}
558 		/* Digest the timesigned and fudge */
559 		isc_buffer_clear(&databuf);
560 		if (tsig.error == dns_tsigerror_badtime) {
561 			INSIST(response);
562 			tsig.timesigned = querytsig.timesigned;
563 		}
564 		isc_buffer_putuint48(&databuf, tsig.timesigned);
565 		isc_buffer_putuint16(&databuf, tsig.fudge);
566 		isc_buffer_usedregion(&databuf, &r);
567 		ret = dst_context_adddata(ctx, &r);
568 		if (ret != ISC_R_SUCCESS)
569 			goto cleanup_context;
570 
571 		if (msg->tcp_continuation == 0) {
572 			/*
573 			 * Digest the error and other data length.
574 			 */
575 			isc_buffer_clear(&databuf);
576 			isc_buffer_putuint16(&databuf, tsig.error);
577 			isc_buffer_putuint16(&databuf, tsig.otherlen);
578 
579 			isc_buffer_usedregion(&databuf, &r);
580 			ret = dst_context_adddata(ctx, &r);
581 			if (ret != ISC_R_SUCCESS)
582 				goto cleanup_context;
583 
584 			/*
585 			 * Digest other data.
586 			 */
587 			if (tsig.otherlen > 0) {
588 				r.length = tsig.otherlen;
589 				r.base = tsig.other;
590 				ret = dst_context_adddata(ctx, &r);
591 				if (ret != ISC_R_SUCCESS)
592 					goto cleanup_context;
593 			}
594 		}
595 
596 		ret = dst_key_sigsize(key->key, &sigsize);
597 		if (ret != ISC_R_SUCCESS)
598 			goto cleanup_context;
599 		tsig.signature = (unsigned char *) malloc(sigsize);
600 		if (tsig.signature == NULL) {
601 			ret = ISC_R_NOMEMORY;
602 			goto cleanup_context;
603 		}
604 
605 		isc_buffer_init(&sigbuf, tsig.signature, sigsize);
606 		ret = dst_context_sign(ctx, &sigbuf);
607 		if (ret != ISC_R_SUCCESS)
608 			goto cleanup_signature;
609 		dst_context_destroy(&ctx);
610 		digestbits = dst_key_getbits(key->key);
611 		if (digestbits != 0) {
612 			/*
613 			 * XXXRAY: Is this correct? What is the
614 			 * expected behavior when digestbits is not an
615 			 * integral multiple of 8? It looks like bytes
616 			 * should either be (digestbits/8) or
617 			 * (digestbits+7)/8.
618 			 *
619 			 * In any case, for current algorithms,
620 			 * digestbits are an integral multiple of 8, so
621 			 * it has the same effect as (digestbits/8).
622 			 */
623 			unsigned int bytes = (digestbits + 1) / 8;
624 			if (response && bytes < querytsig.siglen)
625 				bytes = querytsig.siglen;
626 			if (bytes > isc_buffer_usedlength(&sigbuf))
627 				bytes = isc_buffer_usedlength(&sigbuf);
628 			tsig.siglen = bytes;
629 		} else
630 			tsig.siglen = isc_buffer_usedlength(&sigbuf);
631 	} else {
632 		tsig.siglen = 0;
633 		tsig.signature = NULL;
634 	}
635 
636 	ret = dns_message_gettemprdata(msg, &rdata);
637 	if (ret != ISC_R_SUCCESS)
638 		goto cleanup_signature;
639 	ret = isc_buffer_allocate(&dynbuf, 512);
640 	if (ret != ISC_R_SUCCESS)
641 		goto cleanup_rdata;
642 	ret = dns_rdata_fromstruct_tsig(rdata, dns_rdataclass_any,
643 				        dns_rdatatype_tsig, &tsig, dynbuf);
644 	if (ret != ISC_R_SUCCESS)
645 		goto cleanup_dynbuf;
646 
647 	dns_message_takebuffer(msg, &dynbuf);
648 
649 	if (tsig.signature != NULL) {
650 		free(tsig.signature);
651 		tsig.signature = NULL;
652 	}
653 
654 	owner = NULL;
655 	ret = dns_message_gettempname(msg, &owner);
656 	if (ret != ISC_R_SUCCESS)
657 		goto cleanup_rdata;
658 	dns_name_init(owner, NULL);
659 	ret = dns_name_dup(&key->name, owner);
660 	if (ret != ISC_R_SUCCESS)
661 		goto cleanup_owner;
662 
663 	datalist = NULL;
664 	ret = dns_message_gettemprdatalist(msg, &datalist);
665 	if (ret != ISC_R_SUCCESS)
666 		goto cleanup_owner;
667 	dataset = NULL;
668 	ret = dns_message_gettemprdataset(msg, &dataset);
669 	if (ret != ISC_R_SUCCESS)
670 		goto cleanup_rdatalist;
671 	datalist->rdclass = dns_rdataclass_any;
672 	datalist->type = dns_rdatatype_tsig;
673 	ISC_LIST_APPEND(datalist->rdata, rdata, link);
674 	RUNTIME_CHECK(dns_rdatalist_tordataset(datalist, dataset)
675 		      == ISC_R_SUCCESS);
676 	msg->tsig = dataset;
677 	msg->tsigname = owner;
678 
679 	/* Windows does not like the tsig name being compressed. */
680 	msg->tsigname->attributes |= DNS_NAMEATTR_NOCOMPRESS;
681 
682 	return (ISC_R_SUCCESS);
683 
684  cleanup_rdatalist:
685 	dns_message_puttemprdatalist(msg, &datalist);
686  cleanup_owner:
687 	dns_message_puttempname(msg, &owner);
688 	goto cleanup_rdata;
689  cleanup_dynbuf:
690 	isc_buffer_free(&dynbuf);
691  cleanup_rdata:
692 	dns_message_puttemprdata(msg, &rdata);
693  cleanup_signature:
694 	if (tsig.signature != NULL)
695 		free(tsig.signature);
696  cleanup_context:
697 	if (ctx != NULL)
698 		dst_context_destroy(&ctx);
699 	return (ret);
700 }
701 
702 isc_result_t
dns_tsig_verify(isc_buffer_t * source,dns_message_t * msg)703 dns_tsig_verify(isc_buffer_t *source, dns_message_t *msg)
704 {
705 	dns_rdata_any_tsig_t tsig, querytsig;
706 	isc_region_t r, source_r, header_r, sig_r;
707 	isc_buffer_t databuf;
708 	unsigned char data[32];
709 	dns_name_t *keyname;
710 	dns_rdata_t rdata = DNS_RDATA_INIT;
711 	time_t now;
712 	isc_result_t ret;
713 	dns_tsigkey_t *tsigkey;
714 	dst_key_t *key = NULL;
715 	unsigned char header[DNS_MESSAGE_HEADERLEN];
716 	dst_context_t *ctx = NULL;
717 	uint16_t addcount, id;
718 	unsigned int siglen;
719 	unsigned int alg;
720 	int response;
721 
722 	REQUIRE(source != NULL);
723 	tsigkey = dns_message_gettsigkey(msg);
724 	response = is_response(msg);
725 
726 	msg->verify_attempted = 1;
727 	msg->verified_sig = 0;
728 	msg->tsigstatus = dns_tsigerror_badsig;
729 
730 	if (msg->tcp_continuation) {
731 		if (tsigkey == NULL || msg->querytsig == NULL)
732 			return (DNS_R_UNEXPECTEDTSIG);
733 		return (tsig_verify_tcp(source, msg));
734 	}
735 
736 	/*
737 	 * There should be a TSIG record...
738 	 */
739 	if (msg->tsig == NULL)
740 		return (DNS_R_EXPECTEDTSIG);
741 
742 	/*
743 	 * If this is a response and there's no key or query TSIG, there
744 	 * shouldn't be one on the response.
745 	 */
746 	if (response && (tsigkey == NULL || msg->querytsig == NULL))
747 		return (DNS_R_UNEXPECTEDTSIG);
748 
749 	/*
750 	 * If we're here, we know the message is well formed and contains a
751 	 * TSIG record.
752 	 */
753 
754 	keyname = msg->tsigname;
755 	ret = dns_rdataset_first(msg->tsig);
756 	if (ret != ISC_R_SUCCESS)
757 		return (ret);
758 	dns_rdataset_current(msg->tsig, &rdata);
759 	ret = dns_rdata_tostruct_tsig(&rdata, &tsig);
760 	if (ret != ISC_R_SUCCESS)
761 		return (ret);
762 	dns_rdata_reset(&rdata);
763 	if (response) {
764 		ret = dns_rdataset_first(msg->querytsig);
765 		if (ret != ISC_R_SUCCESS)
766 			return (ret);
767 		dns_rdataset_current(msg->querytsig, &rdata);
768 		ret = dns_rdata_tostruct_tsig(&rdata, &querytsig);
769 		if (ret != ISC_R_SUCCESS)
770 			return (ret);
771 	}
772 	/*
773 	 * Do the key name and algorithm match that of the query?
774 	 */
775 	if (response &&
776 	    (!dns_name_equal(keyname, &tsigkey->name) ||
777 	     !dns_name_equal(&tsig.algorithm, &querytsig.algorithm))) {
778 		msg->tsigstatus = dns_tsigerror_badkey;
779 		tsig_log(msg->tsigkey, 2,
780 			 "key name and algorithm do not match");
781 		return (DNS_R_TSIGVERIFYFAILURE);
782 	}
783 
784 	/*
785 	 * Get the current time.
786 	 */
787 	time(&now);
788 
789 	/*
790 	 * Find dns_tsigkey_t based on keyname.
791 	 */
792 	if (tsigkey == NULL) {
793 		ret = ISC_R_NOTFOUND;
794 		if (ret != ISC_R_SUCCESS) {
795 			msg->tsigstatus = dns_tsigerror_badkey;
796 			ret = dns_tsigkey_create(keyname, &tsig.algorithm,
797 						 NULL, 0, 0, NULL,
798 						 now, now,
799 						 &msg->tsigkey);
800 			if (ret != ISC_R_SUCCESS)
801 				return (ret);
802 			tsig_log(msg->tsigkey, 2, "unknown key");
803 			return (DNS_R_TSIGVERIFYFAILURE);
804 		}
805 		msg->tsigkey = tsigkey;
806 	}
807 
808 	key = tsigkey->key;
809 
810 	/*
811 	 * Check digest length.
812 	 */
813 	alg = dst_key_alg(key);
814 	ret = dst_key_sigsize(key, &siglen);
815 	if (ret != ISC_R_SUCCESS)
816 		return (ret);
817 	if (
818 	    alg == DST_ALG_HMACSHA1 ||
819 	    alg == DST_ALG_HMACSHA224 || alg == DST_ALG_HMACSHA256 ||
820 	    alg == DST_ALG_HMACSHA384 || alg == DST_ALG_HMACSHA512)
821 	{
822 		if (tsig.siglen > siglen) {
823 			tsig_log(msg->tsigkey, 2, "signature length too big");
824 			return (DNS_R_FORMERR);
825 		}
826 		if (tsig.siglen > 0 &&
827 		    (tsig.siglen < 10 || tsig.siglen < ((siglen + 1) / 2)))
828 		{
829 			tsig_log(msg->tsigkey, 2,
830 				 "signature length below minimum");
831 			return (DNS_R_FORMERR);
832 		}
833 	}
834 
835 	if (tsig.siglen > 0) {
836 		uint16_t addcount_n;
837 
838 		sig_r.base = tsig.signature;
839 		sig_r.length = tsig.siglen;
840 
841 		ret = dst_context_create3(key,
842 					  DNS_LOGCATEGORY_DNSSEC,
843 					  0, &ctx);
844 		if (ret != ISC_R_SUCCESS)
845 			return (ret);
846 
847 		if (response) {
848 			isc_buffer_init(&databuf, data, sizeof(data));
849 			isc_buffer_putuint16(&databuf, querytsig.siglen);
850 			isc_buffer_usedregion(&databuf, &r);
851 			ret = dst_context_adddata(ctx, &r);
852 			if (ret != ISC_R_SUCCESS)
853 				goto cleanup_context;
854 			if (querytsig.siglen > 0) {
855 				r.length = querytsig.siglen;
856 				r.base = querytsig.signature;
857 				ret = dst_context_adddata(ctx, &r);
858 				if (ret != ISC_R_SUCCESS)
859 					goto cleanup_context;
860 			}
861 		}
862 
863 		/*
864 		 * Extract the header.
865 		 */
866 		isc_buffer_usedregion(source, &r);
867 		memmove(header, r.base, DNS_MESSAGE_HEADERLEN);
868 		isc_region_consume(&r, DNS_MESSAGE_HEADERLEN);
869 
870 		/*
871 		 * Decrement the additional field counter.
872 		 */
873 		memmove(&addcount, &header[DNS_MESSAGE_HEADERLEN - 2], 2);
874 		addcount_n = ntohs(addcount);
875 		addcount = htons((uint16_t)(addcount_n - 1));
876 		memmove(&header[DNS_MESSAGE_HEADERLEN - 2], &addcount, 2);
877 
878 		/*
879 		 * Put in the original id.
880 		 */
881 		id = htons(tsig.originalid);
882 		memmove(&header[0], &id, 2);
883 
884 		/*
885 		 * Digest the modified header.
886 		 */
887 		header_r.base = (unsigned char *) header;
888 		header_r.length = DNS_MESSAGE_HEADERLEN;
889 		ret = dst_context_adddata(ctx, &header_r);
890 		if (ret != ISC_R_SUCCESS)
891 			goto cleanup_context;
892 
893 		/*
894 		 * Digest all non-TSIG records.
895 		 */
896 		isc_buffer_usedregion(source, &source_r);
897 		r.base = source_r.base + DNS_MESSAGE_HEADERLEN;
898 		r.length = msg->sigstart - DNS_MESSAGE_HEADERLEN;
899 		ret = dst_context_adddata(ctx, &r);
900 		if (ret != ISC_R_SUCCESS)
901 			goto cleanup_context;
902 
903 		/*
904 		 * Digest the key name.
905 		 */
906 		dns_name_toregion(&tsigkey->name, &r);
907 		ret = dst_context_adddata(ctx, &r);
908 		if (ret != ISC_R_SUCCESS)
909 			goto cleanup_context;
910 
911 		isc_buffer_init(&databuf, data, sizeof(data));
912 		isc_buffer_putuint16(&databuf, tsig.common.rdclass);
913 		isc_buffer_putuint32(&databuf, msg->tsig->ttl);
914 		isc_buffer_usedregion(&databuf, &r);
915 		ret = dst_context_adddata(ctx, &r);
916 		if (ret != ISC_R_SUCCESS)
917 			goto cleanup_context;
918 
919 		/*
920 		 * Digest the key algorithm.
921 		 */
922 		dns_name_toregion(tsigkey->algorithm, &r);
923 		ret = dst_context_adddata(ctx, &r);
924 		if (ret != ISC_R_SUCCESS)
925 			goto cleanup_context;
926 
927 		isc_buffer_clear(&databuf);
928 		isc_buffer_putuint48(&databuf, tsig.timesigned);
929 		isc_buffer_putuint16(&databuf, tsig.fudge);
930 		isc_buffer_putuint16(&databuf, tsig.error);
931 		isc_buffer_putuint16(&databuf, tsig.otherlen);
932 		isc_buffer_usedregion(&databuf, &r);
933 		ret = dst_context_adddata(ctx, &r);
934 		if (ret != ISC_R_SUCCESS)
935 			goto cleanup_context;
936 
937 		if (tsig.otherlen > 0) {
938 			r.base = tsig.other;
939 			r.length = tsig.otherlen;
940 			ret = dst_context_adddata(ctx, &r);
941 			if (ret != ISC_R_SUCCESS)
942 				goto cleanup_context;
943 		}
944 
945 		ret = dst_context_verify(ctx, &sig_r);
946 		if (ret == DST_R_VERIFYFAILURE) {
947 			ret = DNS_R_TSIGVERIFYFAILURE;
948 			tsig_log(msg->tsigkey, 2,
949 				 "signature failed to verify(1)");
950 			goto cleanup_context;
951 		} else if (ret != ISC_R_SUCCESS) {
952 			goto cleanup_context;
953 		}
954 		msg->verified_sig = 1;
955 	} else if (tsig.error != dns_tsigerror_badsig &&
956 		   tsig.error != dns_tsigerror_badkey) {
957 		tsig_log(msg->tsigkey, 2, "signature was empty");
958 		return (DNS_R_TSIGVERIFYFAILURE);
959 	}
960 
961 	/*
962 	 * Here at this point, the MAC has been verified. Even if any of
963 	 * the following code returns a TSIG error, the reply will be
964 	 * signed and WILL always include the request MAC in the digest
965 	 * computation.
966 	 */
967 
968 	/*
969 	 * Is the time ok?
970 	 */
971 	if (now + msg->timeadjust > (time_t)(tsig.timesigned + tsig.fudge)) {
972 		msg->tsigstatus = dns_tsigerror_badtime;
973 		tsig_log(msg->tsigkey, 2, "signature has expired");
974 		ret = DNS_R_CLOCKSKEW;
975 		goto cleanup_context;
976 	} else if (now + msg->timeadjust < (time_t)(tsig.timesigned -
977 	    tsig.fudge)) {
978 		msg->tsigstatus = dns_tsigerror_badtime;
979 		tsig_log(msg->tsigkey, 2, "signature is in the future");
980 		ret = DNS_R_CLOCKSKEW;
981 		goto cleanup_context;
982 	}
983 
984 	if (
985 	    alg == DST_ALG_HMACSHA1 ||
986 	    alg == DST_ALG_HMACSHA224 || alg == DST_ALG_HMACSHA256 ||
987 	    alg == DST_ALG_HMACSHA384 || alg == DST_ALG_HMACSHA512)
988 	{
989 		uint16_t digestbits = dst_key_getbits(key);
990 
991 		/*
992 		 * XXXRAY: Is this correct? What is the expected
993 		 * behavior when digestbits is not an integral multiple
994 		 * of 8? It looks like bytes should either be
995 		 * (digestbits/8) or (digestbits+7)/8.
996 		 *
997 		 * In any case, for current algorithms, digestbits are
998 		 * an integral multiple of 8, so it has the same effect
999 		 * as (digestbits/8).
1000 		 */
1001 		if (tsig.siglen > 0 && digestbits != 0 &&
1002 		    tsig.siglen < ((digestbits + 1) / 8))
1003 		{
1004 			msg->tsigstatus = dns_tsigerror_badtrunc;
1005 			tsig_log(msg->tsigkey, 2,
1006 				 "truncated signature length too small");
1007 			ret = DNS_R_TSIGVERIFYFAILURE;
1008 			goto cleanup_context;
1009 		}
1010 		if (tsig.siglen > 0 && digestbits == 0 &&
1011 		    tsig.siglen < siglen)
1012 		{
1013 			msg->tsigstatus = dns_tsigerror_badtrunc;
1014 			tsig_log(msg->tsigkey, 2, "signature length too small");
1015 			ret = DNS_R_TSIGVERIFYFAILURE;
1016 			goto cleanup_context;
1017 		}
1018 	}
1019 
1020 	if (tsig.error != dns_rcode_noerror) {
1021 		msg->tsigstatus = tsig.error;
1022 		if (tsig.error == dns_tsigerror_badtime)
1023 			ret = DNS_R_CLOCKSKEW;
1024 		else
1025 			ret = DNS_R_TSIGERRORSET;
1026 		goto cleanup_context;
1027 	}
1028 
1029 	msg->tsigstatus = dns_rcode_noerror;
1030 	ret = ISC_R_SUCCESS;
1031 
1032  cleanup_context:
1033 	if (ctx != NULL)
1034 		dst_context_destroy(&ctx);
1035 
1036 	return (ret);
1037 }
1038 
1039 static isc_result_t
tsig_verify_tcp(isc_buffer_t * source,dns_message_t * msg)1040 tsig_verify_tcp(isc_buffer_t *source, dns_message_t *msg) {
1041 	dns_rdata_any_tsig_t tsig, querytsig;
1042 	isc_region_t r, source_r, header_r, sig_r;
1043 	isc_buffer_t databuf;
1044 	unsigned char data[32];
1045 	dns_name_t *keyname;
1046 	dns_rdata_t rdata = DNS_RDATA_INIT;
1047 	time_t now;
1048 	isc_result_t ret;
1049 	dns_tsigkey_t *tsigkey;
1050 	dst_key_t *key = NULL;
1051 	unsigned char header[DNS_MESSAGE_HEADERLEN];
1052 	uint16_t addcount, id;
1053 	int has_tsig = 0;
1054 	unsigned int siglen;
1055 	unsigned int alg;
1056 
1057 	REQUIRE(source != NULL);
1058 	REQUIRE(msg != NULL);
1059 	REQUIRE(dns_message_gettsigkey(msg) != NULL);
1060 	REQUIRE(msg->tcp_continuation == 1);
1061 	REQUIRE(msg->querytsig != NULL);
1062 
1063 	msg->verified_sig = 0;
1064 	msg->tsigstatus = dns_tsigerror_badsig;
1065 
1066 	if (!is_response(msg))
1067 		return (DNS_R_EXPECTEDRESPONSE);
1068 
1069 	tsigkey = dns_message_gettsigkey(msg);
1070 	key = tsigkey->key;
1071 
1072 	/*
1073 	 * Extract and parse the previous TSIG
1074 	 */
1075 	ret = dns_rdataset_first(msg->querytsig);
1076 	if (ret != ISC_R_SUCCESS)
1077 		return (ret);
1078 	dns_rdataset_current(msg->querytsig, &rdata);
1079 	ret = dns_rdata_tostruct_tsig(&rdata, &querytsig);
1080 	if (ret != ISC_R_SUCCESS)
1081 		return (ret);
1082 	dns_rdata_reset(&rdata);
1083 
1084 	/*
1085 	 * If there is a TSIG in this message, do some checks.
1086 	 */
1087 	if (msg->tsig != NULL) {
1088 		has_tsig = 1;
1089 
1090 		keyname = msg->tsigname;
1091 		ret = dns_rdataset_first(msg->tsig);
1092 		if (ret != ISC_R_SUCCESS)
1093 			goto cleanup_querystruct;
1094 		dns_rdataset_current(msg->tsig, &rdata);
1095 		ret = dns_rdata_tostruct_tsig(&rdata, &tsig);
1096 		if (ret != ISC_R_SUCCESS)
1097 			goto cleanup_querystruct;
1098 
1099 		/*
1100 		 * Do the key name and algorithm match that of the query?
1101 		 */
1102 		if (!dns_name_equal(keyname, &tsigkey->name) ||
1103 		    !dns_name_equal(&tsig.algorithm, &querytsig.algorithm))
1104 		{
1105 			msg->tsigstatus = dns_tsigerror_badkey;
1106 			ret = DNS_R_TSIGVERIFYFAILURE;
1107 			tsig_log(msg->tsigkey, 2,
1108 				 "key name and algorithm do not match");
1109 			goto cleanup_querystruct;
1110 		}
1111 
1112 		/*
1113 		 * Check digest length.
1114 		 */
1115 		alg = dst_key_alg(key);
1116 		ret = dst_key_sigsize(key, &siglen);
1117 		if (ret != ISC_R_SUCCESS)
1118 			goto cleanup_querystruct;
1119 		if (
1120 			alg == DST_ALG_HMACSHA1 ||
1121 			alg == DST_ALG_HMACSHA224 ||
1122 			alg == DST_ALG_HMACSHA256 ||
1123 			alg == DST_ALG_HMACSHA384 ||
1124 			alg == DST_ALG_HMACSHA512)
1125 		{
1126 			if (tsig.siglen > siglen) {
1127 				tsig_log(tsigkey, 2,
1128 					 "signature length too big");
1129 				ret = DNS_R_FORMERR;
1130 				goto cleanup_querystruct;
1131 			}
1132 			if (tsig.siglen > 0 &&
1133 			    (tsig.siglen < 10 ||
1134 			     tsig.siglen < ((siglen + 1) / 2)))
1135 			{
1136 				tsig_log(tsigkey, 2,
1137 					 "signature length below minimum");
1138 				ret = DNS_R_FORMERR;
1139 				goto cleanup_querystruct;
1140 			}
1141 		}
1142 	}
1143 
1144 	if (msg->tsigctx == NULL) {
1145 		ret = dst_context_create3(key,
1146 					  DNS_LOGCATEGORY_DNSSEC,
1147 					  0, &msg->tsigctx);
1148 		if (ret != ISC_R_SUCCESS)
1149 			goto cleanup_querystruct;
1150 
1151 		/*
1152 		 * Digest the length of the query signature
1153 		 */
1154 		isc_buffer_init(&databuf, data, sizeof(data));
1155 		isc_buffer_putuint16(&databuf, querytsig.siglen);
1156 		isc_buffer_usedregion(&databuf, &r);
1157 		ret = dst_context_adddata(msg->tsigctx, &r);
1158 		if (ret != ISC_R_SUCCESS)
1159 			goto cleanup_context;
1160 
1161 		/*
1162 		 * Digest the data of the query signature
1163 		 */
1164 		if (querytsig.siglen > 0) {
1165 			r.length = querytsig.siglen;
1166 			r.base = querytsig.signature;
1167 			ret = dst_context_adddata(msg->tsigctx, &r);
1168 			if (ret != ISC_R_SUCCESS)
1169 				goto cleanup_context;
1170 		}
1171 	}
1172 
1173 	/*
1174 	 * Extract the header.
1175 	 */
1176 	isc_buffer_usedregion(source, &r);
1177 	memmove(header, r.base, DNS_MESSAGE_HEADERLEN);
1178 	isc_region_consume(&r, DNS_MESSAGE_HEADERLEN);
1179 
1180 	/*
1181 	 * Decrement the additional field counter if necessary.
1182 	 */
1183 	if (has_tsig) {
1184 		uint16_t addcount_n;
1185 
1186 		memmove(&addcount, &header[DNS_MESSAGE_HEADERLEN - 2], 2);
1187 		addcount_n = ntohs(addcount);
1188 		addcount = htons((uint16_t)(addcount_n - 1));
1189 		memmove(&header[DNS_MESSAGE_HEADERLEN - 2], &addcount, 2);
1190 
1191 		/*
1192 		 * Put in the original id.
1193 		 *
1194 		 * XXX Can TCP transfers be forwarded?  How would that
1195 		 * work?
1196 		 */
1197 		id = htons(tsig.originalid);
1198 		memmove(&header[0], &id, 2);
1199 	}
1200 
1201 	/*
1202 	 * Digest the modified header.
1203 	 */
1204 	header_r.base = (unsigned char *) header;
1205 	header_r.length = DNS_MESSAGE_HEADERLEN;
1206 	ret = dst_context_adddata(msg->tsigctx, &header_r);
1207 	if (ret != ISC_R_SUCCESS)
1208 		goto cleanup_context;
1209 
1210 	/*
1211 	 * Digest all non-TSIG records.
1212 	 */
1213 	isc_buffer_usedregion(source, &source_r);
1214 	r.base = source_r.base + DNS_MESSAGE_HEADERLEN;
1215 	if (has_tsig)
1216 		r.length = msg->sigstart - DNS_MESSAGE_HEADERLEN;
1217 	else
1218 		r.length = source_r.length - DNS_MESSAGE_HEADERLEN;
1219 	ret = dst_context_adddata(msg->tsigctx, &r);
1220 	if (ret != ISC_R_SUCCESS)
1221 		goto cleanup_context;
1222 
1223 	/*
1224 	 * Digest the time signed and fudge.
1225 	 */
1226 	if (has_tsig) {
1227 		isc_buffer_init(&databuf, data, sizeof(data));
1228 		isc_buffer_putuint48(&databuf, tsig.timesigned);
1229 		isc_buffer_putuint16(&databuf, tsig.fudge);
1230 		isc_buffer_usedregion(&databuf, &r);
1231 		ret = dst_context_adddata(msg->tsigctx, &r);
1232 		if (ret != ISC_R_SUCCESS)
1233 			goto cleanup_context;
1234 
1235 		sig_r.base = tsig.signature;
1236 		sig_r.length = tsig.siglen;
1237 		if (tsig.siglen == 0) {
1238 			if (tsig.error != dns_rcode_noerror) {
1239 				msg->tsigstatus = tsig.error;
1240 				if (tsig.error == dns_tsigerror_badtime) {
1241 					ret = DNS_R_CLOCKSKEW;
1242 				} else {
1243 					ret = DNS_R_TSIGERRORSET;
1244 				}
1245 			} else {
1246 				tsig_log(msg->tsigkey, 2,
1247 					 "signature is empty");
1248 				ret = DNS_R_TSIGVERIFYFAILURE;
1249 			}
1250 			goto cleanup_context;
1251 		}
1252 
1253 		ret = dst_context_verify(msg->tsigctx, &sig_r);
1254 		if (ret == DST_R_VERIFYFAILURE) {
1255 			tsig_log(msg->tsigkey, 2,
1256 				 "signature failed to verify(2)");
1257 			ret = DNS_R_TSIGVERIFYFAILURE;
1258 			goto cleanup_context;
1259 		} else if (ret != ISC_R_SUCCESS) {
1260 			goto cleanup_context;
1261 		}
1262 		msg->verified_sig = 1;
1263 
1264 		/*
1265 		 * Here at this point, the MAC has been verified. Even
1266 		 * if any of the following code returns a TSIG error,
1267 		 * the reply will be signed and WILL always include the
1268 		 * request MAC in the digest computation.
1269 		 */
1270 
1271 		/*
1272 		 * Is the time ok?
1273 		 */
1274 		time(&now);
1275 
1276 		if (now + msg->timeadjust > (time_t)(tsig.timesigned +
1277 		    tsig.fudge)) {
1278 			msg->tsigstatus = dns_tsigerror_badtime;
1279 			tsig_log(msg->tsigkey, 2, "signature has expired");
1280 			ret = DNS_R_CLOCKSKEW;
1281 			goto cleanup_context;
1282 		} else if (now + msg->timeadjust < (time_t)(tsig.timesigned -
1283 		    tsig.fudge)) {
1284 			msg->tsigstatus = dns_tsigerror_badtime;
1285 			tsig_log(msg->tsigkey, 2,
1286 				 "signature is in the future");
1287 			ret = DNS_R_CLOCKSKEW;
1288 			goto cleanup_context;
1289 		}
1290 
1291 		alg = dst_key_alg(key);
1292 		ret = dst_key_sigsize(key, &siglen);
1293 		if (ret != ISC_R_SUCCESS)
1294 			goto cleanup_context;
1295 		if (
1296 			alg == DST_ALG_HMACSHA1 ||
1297 			alg == DST_ALG_HMACSHA224 ||
1298 			alg == DST_ALG_HMACSHA256 ||
1299 			alg == DST_ALG_HMACSHA384 ||
1300 			alg == DST_ALG_HMACSHA512)
1301 		{
1302 			uint16_t digestbits = dst_key_getbits(key);
1303 
1304 			/*
1305 			 * XXXRAY: Is this correct? What is the
1306 			 * expected behavior when digestbits is not an
1307 			 * integral multiple of 8? It looks like bytes
1308 			 * should either be (digestbits/8) or
1309 			 * (digestbits+7)/8.
1310 			 *
1311 			 * In any case, for current algorithms,
1312 			 * digestbits are an integral multiple of 8, so
1313 			 * it has the same effect as (digestbits/8).
1314 			 */
1315 			if (tsig.siglen > 0 && digestbits != 0 &&
1316 			    tsig.siglen < ((digestbits + 1) / 8))
1317 			{
1318 				msg->tsigstatus = dns_tsigerror_badtrunc;
1319 				tsig_log(msg->tsigkey, 2,
1320 					 "truncated signature length "
1321 					 "too small");
1322 				ret = DNS_R_TSIGVERIFYFAILURE;
1323 				goto cleanup_context;
1324 			}
1325 			if (tsig.siglen > 0 && digestbits == 0 &&
1326 			    tsig.siglen < siglen)
1327 			{
1328 				msg->tsigstatus = dns_tsigerror_badtrunc;
1329 				tsig_log(msg->tsigkey, 2,
1330 					 "signature length too small");
1331 				ret = DNS_R_TSIGVERIFYFAILURE;
1332 				goto cleanup_context;
1333 			}
1334 		}
1335 
1336 		if (tsig.error != dns_rcode_noerror) {
1337 			msg->tsigstatus = tsig.error;
1338 			if (tsig.error == dns_tsigerror_badtime)
1339 				ret = DNS_R_CLOCKSKEW;
1340 			else
1341 				ret = DNS_R_TSIGERRORSET;
1342 			goto cleanup_context;
1343 		}
1344 	}
1345 
1346 	msg->tsigstatus = dns_rcode_noerror;
1347 	ret = ISC_R_SUCCESS;
1348 
1349  cleanup_context:
1350 	/*
1351 	 * Except in error conditions, don't destroy the DST context
1352 	 * for unsigned messages; it is a running sum till the next
1353 	 * TSIG signed message.
1354 	 */
1355 	if ((ret != ISC_R_SUCCESS || has_tsig) && msg->tsigctx != NULL) {
1356 		dst_context_destroy(&msg->tsigctx);
1357 	}
1358 
1359  cleanup_querystruct:
1360 	dns_rdata_freestruct_tsig(&querytsig);
1361 
1362 	return (ret);
1363 }
1364 
1365