1/*
2 * tsig.c -- TSIG implementation (RFC 2845).
3 *
4 * Copyright (c) 2001-2006, NLnet Labs. All rights reserved.
5 *
6 * See LICENSE for the license.
7 *
8 */
9
10
11#include "config.h"
12#include <stdlib.h>
13#include <ctype.h>
14
15#include "tsig.h"
16#include "tsig-openssl.h"
17#include "dns.h"
18#include "packet.h"
19#include "query.h"
20#include "rbtree.h"
21
22#if !defined(HAVE_SSL) || !defined(HAVE_CRYPTO_MEMCMP)
23/* we need fixed time compare */
24#define CRYPTO_memcmp memcmp_fixedtime
25int memcmp_fixedtime(const void *s1, const void *s2, size_t n)
26{
27	size_t i;
28	const uint8_t* u1 = (const uint8_t*)s1;
29	const uint8_t* u2 = (const uint8_t*)s2;
30	int ret = 0, haveit = 0, bret = 0, bhaveit = 0;
31	/* this routine loops for every byte in the strings.
32	 * every loop, it tests ==, < and >.  All three.  One succeeds,
33	 * as every time it must be equal, smaller or larger.  The one
34	 * that succeeds has one if-comparison and two assignments. */
35	for(i=0; i<n; i++) {
36		if(u1[i] == u2[i]) {
37			/* waste time equal to < and > statements */
38			if(haveit) {
39				bret = -1; /* waste time */
40				bhaveit = 1;
41			} else {
42				bret = 1; /* waste time */
43				bhaveit = 1;
44			}
45		}
46		if(u1[i] < u2[i]) {
47			if(haveit) {
48				bret = -1; /* waste time equal to the else */
49				bhaveit = 1;
50			} else {
51				ret = -1;
52				haveit = 1;
53			}
54		}
55		if(u1[i] > u2[i]) {
56			if(haveit) {
57				bret = 1; /* waste time equal to the else */
58				bhaveit = 1;
59			} else {
60				ret = 1;
61				haveit = 1;
62			}
63		}
64	}
65	/* use the variables to stop the compiler from excluding them */
66	if(bhaveit) {
67		if(bret == -2)
68			ret = 0; /* never happens */
69	} else {
70		if(bret == -2)
71			ret = 0; /* never happens */
72	}
73	return ret;
74}
75#endif
76
77static region_type *tsig_region;
78
79struct tsig_key_table
80{
81	rbnode_type node; /* by dname */
82	tsig_key_type *key;
83};
84typedef struct tsig_key_table tsig_key_table_type;
85static rbtree_type *tsig_key_table;
86
87struct tsig_algorithm_table
88{
89	struct tsig_algorithm_table *next;
90	tsig_algorithm_type *algorithm;
91};
92typedef struct tsig_algorithm_table tsig_algorithm_table_type;
93static tsig_algorithm_table_type *tsig_algorithm_table;
94static size_t max_algo_digest_size = 0;
95
96static void
97tsig_digest_variables(tsig_record_type *tsig, int tsig_timers_only)
98{
99	uint16_t klass = htons(CLASS_ANY);
100	uint32_t ttl = htonl(0);
101	uint16_t signed_time_high = htons(tsig->signed_time_high);
102	uint32_t signed_time_low = htonl(tsig->signed_time_low);
103	uint16_t signed_time_fudge = htons(tsig->signed_time_fudge);
104	uint16_t error_code = htons(tsig->error_code);
105	uint16_t other_size = htons(tsig->other_size);
106
107	if (!tsig_timers_only) {
108		tsig->algorithm->hmac_update(tsig->context,
109					     dname_name(tsig->key_name),
110					     tsig->key_name->name_size);
111		tsig->algorithm->hmac_update(tsig->context,
112					     &klass,
113					     sizeof(klass));
114		tsig->algorithm->hmac_update(tsig->context,
115					     &ttl,
116					     sizeof(ttl));
117		tsig->algorithm->hmac_update(tsig->context,
118					     dname_name(tsig->algorithm_name),
119					     tsig->algorithm_name->name_size);
120	}
121	tsig->algorithm->hmac_update(tsig->context,
122				     &signed_time_high,
123				     sizeof(signed_time_high));
124	tsig->algorithm->hmac_update(tsig->context,
125				     &signed_time_low,
126				     sizeof(signed_time_low));
127	tsig->algorithm->hmac_update(tsig->context,
128				     &signed_time_fudge,
129				     sizeof(signed_time_fudge));
130	if (!tsig_timers_only) {
131		tsig->algorithm->hmac_update(tsig->context,
132					     &error_code,
133					     sizeof(error_code));
134		tsig->algorithm->hmac_update(tsig->context,
135					     &other_size,
136					     sizeof(other_size));
137		tsig->algorithm->hmac_update(tsig->context,
138					     tsig->other_data,
139					     tsig->other_size);
140	}
141}
142
143static int
144tree_dname_compare(const void* a, const void* b)
145{
146	return dname_compare((const dname_type*)a, (const dname_type*)b);
147}
148
149int
150tsig_init(region_type *region)
151{
152	tsig_region = region;
153	tsig_key_table = rbtree_create(region, &tree_dname_compare);
154	tsig_algorithm_table = NULL;
155
156#if defined(HAVE_SSL)
157	return tsig_openssl_init(region);
158#endif /* defined(HAVE_SSL) */
159	return 1;
160}
161
162void
163tsig_add_key(tsig_key_type *key)
164{
165	tsig_key_table_type *entry = (tsig_key_table_type *) region_alloc_zero(
166		tsig_region, sizeof(tsig_key_table_type));
167	entry->key = key;
168	entry->node.key = entry->key->name;
169	(void)rbtree_insert(tsig_key_table, &entry->node);
170}
171
172void
173tsig_del_key(tsig_key_type *key)
174{
175	tsig_key_table_type *entry;
176	if(!key) return;
177	entry = (tsig_key_table_type*)rbtree_delete(tsig_key_table, key->name);
178	if(!entry) return;
179	region_recycle(tsig_region, entry, sizeof(tsig_key_table_type));
180}
181
182tsig_key_type*
183tsig_find_key(const dname_type* name)
184{
185	tsig_key_table_type* entry;
186	entry = (tsig_key_table_type*)rbtree_search(tsig_key_table, name);
187	if(entry)
188		return entry->key;
189	return NULL;
190}
191
192void
193tsig_add_algorithm(tsig_algorithm_type *algorithm)
194{
195	tsig_algorithm_table_type *entry
196		= (tsig_algorithm_table_type *) region_alloc(
197			tsig_region, sizeof(tsig_algorithm_table_type));
198	entry->algorithm = algorithm;
199	entry->next = tsig_algorithm_table;
200	tsig_algorithm_table = entry;
201	if(algorithm->maximum_digest_size > max_algo_digest_size)
202		max_algo_digest_size = algorithm->maximum_digest_size;
203}
204
205/**
206 * compare a tsig algorithm string lowercased
207 */
208int
209tsig_strlowercmp(const char* str1, const char* str2)
210{
211	while (str1 && str2 && *str1 != '\0' && *str2 != '\0') {
212		if(tolower((unsigned char)*str1) != tolower((unsigned char)*str2)) {
213			if(tolower((unsigned char)*str1) < tolower((unsigned char)*str2))
214				return -1;
215			return 1;
216		}
217		str1++;
218		str2++;
219	}
220	if (str1 && str2) {
221		if (*str1 == *str2)
222			return 0;
223		else if (*str1 == '\0')
224			return -1;
225	}
226	else if (!str1 && !str2)
227		return 0;
228	else if (!str1 && str2)
229		return -1;
230	return 1;
231}
232
233
234/*
235 * Find an HMAC algorithm based on its short name.
236 */
237tsig_algorithm_type *
238tsig_get_algorithm_by_name(const char *name)
239{
240	tsig_algorithm_table_type *algorithm_entry;
241
242	for (algorithm_entry = tsig_algorithm_table;
243	     algorithm_entry;
244	     algorithm_entry = algorithm_entry->next)
245	{
246		if (tsig_strlowercmp(name, algorithm_entry->algorithm->short_name) == 0)
247		{
248			return algorithm_entry->algorithm;
249		}
250		if(strncmp("hmac-", algorithm_entry->algorithm->short_name, 5) == 0 && tsig_strlowercmp(name, algorithm_entry->algorithm->short_name+5) == 0) {
251			return algorithm_entry->algorithm;
252		}
253	}
254
255	return NULL;
256}
257
258
259const char *
260tsig_error(int error_code)
261{
262	static char message[1000];
263
264	switch (error_code) {
265	case TSIG_ERROR_NOERROR:
266		return "No Error";
267		break;
268	case TSIG_ERROR_BADSIG:
269		return "Bad Signature";
270		break;
271	case TSIG_ERROR_BADKEY:
272		return "Bad Key";
273		break;
274	case TSIG_ERROR_BADTIME:
275		return "Bad Time";
276		break;
277	default:
278		if(error_code < 16) /* DNS rcodes */
279			return rcode2str(error_code);
280
281		snprintf(message, sizeof(message),
282			 "Unknown Error %d", error_code);
283		break;
284	}
285	return message;
286}
287
288static void
289tsig_cleanup(void *data)
290{
291	tsig_record_type *tsig = (tsig_record_type *) data;
292	region_destroy(tsig->rr_region);
293	region_destroy(tsig->context_region);
294}
295
296void
297tsig_create_record(tsig_record_type *tsig, region_type *region)
298{
299	tsig_create_record_custom(tsig, region, DEFAULT_CHUNK_SIZE,
300		DEFAULT_LARGE_OBJECT_SIZE, DEFAULT_INITIAL_CLEANUP_SIZE);
301}
302
303void
304tsig_create_record_custom(tsig_record_type *tsig, region_type *region,
305	size_t chunk_size, size_t large_object_size, size_t initial_cleanup_size)
306{
307	tsig->rr_region = region_create_custom(xalloc, free, chunk_size,
308		large_object_size, initial_cleanup_size, 0);
309	tsig->context_region = region_create_custom(xalloc, free, chunk_size,
310		large_object_size, initial_cleanup_size, 0);
311	if(region)
312		region_add_cleanup(region, tsig_cleanup, tsig);
313	tsig_init_record(tsig, NULL, NULL);
314}
315
316void
317tsig_delete_record(tsig_record_type* tsig, region_type* region)
318{
319	if(region)
320		region_remove_cleanup(region, tsig_cleanup, tsig);
321	region_destroy(tsig->rr_region);
322	region_destroy(tsig->context_region);
323}
324
325void
326tsig_init_record(tsig_record_type *tsig,
327		 tsig_algorithm_type *algorithm,
328		 tsig_key_type *key)
329{
330	tsig->status = TSIG_NOT_PRESENT;
331	tsig->error_code = TSIG_ERROR_NOERROR;
332	tsig->position = 0;
333	tsig->response_count = 0;
334	tsig->context = NULL;
335	tsig->algorithm = algorithm;
336	tsig->key = key;
337	tsig->prior_mac_size = 0;
338	tsig->prior_mac_data = NULL;
339	region_free_all(tsig->context_region);
340}
341
342int
343tsig_from_query(tsig_record_type *tsig)
344{
345	tsig_key_type *key = NULL;
346	tsig_algorithm_table_type *algorithm_entry;
347	tsig_algorithm_type *algorithm = NULL;
348	uint64_t current_time;
349	uint64_t signed_time;
350
351	assert(tsig->status == TSIG_OK);
352	assert(!tsig->algorithm);
353	assert(!tsig->key);
354
355	key = (tsig_key_type*)tsig_find_key(tsig->key_name);
356
357	for (algorithm_entry = tsig_algorithm_table;
358	     algorithm_entry;
359	     algorithm_entry = algorithm_entry->next)
360	{
361		if (dname_compare(
362			    tsig->algorithm_name,
363			    algorithm_entry->algorithm->wireformat_name) == 0)
364		{
365			algorithm = algorithm_entry->algorithm;
366			break;
367		}
368	}
369
370	if (!algorithm || !key) {
371		/* Algorithm or key is unknown, cannot authenticate.  */
372		tsig->error_code = TSIG_ERROR_BADKEY;
373		return 0;
374	}
375
376	if ((tsig->algorithm && algorithm != tsig->algorithm)
377	    || (tsig->key && key != tsig->key))
378	{
379		/*
380		 * Algorithm or key changed during a single connection,
381		 * return error.
382		 */
383		tsig->error_code = TSIG_ERROR_BADKEY;
384		return 0;
385	}
386
387	signed_time = ((((uint64_t) tsig->signed_time_high) << 32) |
388		       ((uint64_t) tsig->signed_time_low));
389
390	current_time = (uint64_t) time(NULL);
391	if ((current_time < signed_time - tsig->signed_time_fudge)
392	    || (current_time > signed_time + tsig->signed_time_fudge))
393	{
394		uint16_t current_time_high;
395		uint32_t current_time_low;
396
397#if 0 /* debug */
398		char current_time_text[26];
399		char signed_time_text[26];
400		time_t clock;
401
402		clock = (time_t) current_time;
403		ctime_r(&clock, current_time_text);
404		current_time_text[24] = '\0';
405
406		clock = (time_t) signed_time;
407		ctime_r(&clock, signed_time_text);
408		signed_time_text[24] = '\0';
409
410		log_msg(LOG_ERR,
411			"current server time %s is outside the range of TSIG"
412			" signed time %s with fudge %u",
413			current_time_text,
414			signed_time_text,
415			(unsigned) tsig->signed_time_fudge);
416#endif
417
418		tsig->error_code = TSIG_ERROR_BADTIME;
419		current_time_high = (uint16_t) (current_time >> 32);
420		current_time_low = (uint32_t) current_time;
421		tsig->other_size = 6;
422		tsig->other_data = (uint8_t *) region_alloc(
423			tsig->rr_region, sizeof(uint16_t) + sizeof(uint32_t));
424		write_uint16(tsig->other_data, current_time_high);
425		write_uint32(tsig->other_data + 2, current_time_low);
426		return 0;
427	}
428
429	tsig->algorithm = algorithm;
430	tsig->key = key;
431	tsig->response_count = 0;
432	tsig->prior_mac_size = 0;
433
434	return 1;
435}
436
437void
438tsig_init_query(tsig_record_type *tsig, uint16_t original_query_id)
439{
440	assert(tsig);
441	assert(tsig->algorithm);
442	assert(tsig->key);
443
444	tsig->response_count = 0;
445	tsig->prior_mac_size = 0;
446	tsig->algorithm_name = tsig->algorithm->wireformat_name;
447	tsig->key_name = tsig->key->name;
448	tsig->mac_size = 0;
449	tsig->mac_data = NULL;
450	tsig->original_query_id = original_query_id;
451	tsig->error_code = TSIG_ERROR_NOERROR;
452	tsig->other_size = 0;
453	tsig->other_data = NULL;
454}
455
456void
457tsig_prepare(tsig_record_type *tsig)
458{
459	if (!tsig->context) {
460		assert(tsig->algorithm);
461		tsig->context = tsig->algorithm->hmac_create_context(
462			tsig->context_region);
463		tsig->prior_mac_data = (uint8_t *) region_alloc(
464			tsig->context_region,
465			tsig->algorithm->maximum_digest_size);
466	}
467	tsig->algorithm->hmac_init_context(tsig->context,
468					   tsig->algorithm,
469					   tsig->key);
470
471	if (tsig->prior_mac_size > 0) {
472		uint16_t mac_size = htons(tsig->prior_mac_size);
473		tsig->algorithm->hmac_update(tsig->context,
474					     &mac_size,
475					     sizeof(mac_size));
476		tsig->algorithm->hmac_update(tsig->context,
477					     tsig->prior_mac_data,
478					     tsig->prior_mac_size);
479	}
480
481	tsig->updates_since_last_prepare = 0;
482}
483
484void
485tsig_update(tsig_record_type *tsig, buffer_type *packet, size_t length)
486{
487	uint16_t original_query_id = htons(tsig->original_query_id);
488
489	assert(length <= buffer_limit(packet));
490
491	tsig->algorithm->hmac_update(tsig->context,
492				     &original_query_id,
493				     sizeof(original_query_id));
494	tsig->algorithm->hmac_update(
495		tsig->context,
496		buffer_at(packet, sizeof(original_query_id)),
497		length - sizeof(original_query_id));
498	if (QR(packet)) {
499		++tsig->response_count;
500	}
501
502	++tsig->updates_since_last_prepare;
503}
504
505void
506tsig_sign(tsig_record_type *tsig)
507{
508	uint64_t current_time = (uint64_t) time(NULL);
509	tsig->signed_time_high = (uint16_t) (current_time >> 32);
510	tsig->signed_time_low = (uint32_t) current_time;
511	tsig->signed_time_fudge = 300; /* XXX; hardcoded value */
512
513	tsig_digest_variables(tsig, tsig->response_count > 1);
514
515	tsig->algorithm->hmac_final(tsig->context,
516				    tsig->prior_mac_data,
517				    &tsig->prior_mac_size);
518
519	tsig->mac_size = tsig->prior_mac_size;
520	tsig->mac_data = tsig->prior_mac_data;
521}
522
523int
524tsig_verify(tsig_record_type *tsig)
525{
526	tsig_digest_variables(tsig, tsig->response_count > 1);
527
528	tsig->algorithm->hmac_final(tsig->context,
529				    tsig->prior_mac_data,
530				    &tsig->prior_mac_size);
531
532	if (tsig->mac_size != tsig->prior_mac_size
533	    || CRYPTO_memcmp(tsig->mac_data,
534		      tsig->prior_mac_data,
535		      tsig->mac_size) != 0)
536	{
537		/* Digest is incorrect, cannot authenticate.  */
538		tsig->error_code = TSIG_ERROR_BADSIG;
539		return 0;
540	} else {
541		return 1;
542	}
543}
544
545int
546tsig_find_rr(tsig_record_type *tsig, buffer_type *packet)
547{
548	size_t saved_position = buffer_position(packet);
549	size_t rrcount = ((size_t)QDCOUNT(packet)
550			  + (size_t)ANCOUNT(packet)
551			  + (size_t)NSCOUNT(packet)
552			  + (size_t)ARCOUNT(packet));
553	size_t i;
554	int result;
555
556	if (ARCOUNT(packet) == 0) {
557		tsig->status = TSIG_NOT_PRESENT;
558		return 1;
559	}
560	if(rrcount > 65530) {
561		/* impossibly high number of records in 64k, reject packet */
562		buffer_set_position(packet, saved_position);
563		return 0;
564	}
565
566	buffer_set_position(packet, QHEADERSZ);
567
568	/* TSIG must be the last record, so skip all others. */
569	for (i = 0; i < rrcount - 1; ++i) {
570		if (!packet_skip_rr(packet, i < QDCOUNT(packet))) {
571			buffer_set_position(packet, saved_position);
572			return 0;
573		}
574	}
575
576	result = tsig_parse_rr(tsig, packet);
577	buffer_set_position(packet, saved_position);
578	return result;
579}
580
581int
582tsig_parse_rr(tsig_record_type *tsig, buffer_type *packet)
583{
584	uint16_t type;
585	uint16_t klass;
586	uint32_t ttl;
587	uint16_t rdlen;
588
589	tsig->status = TSIG_NOT_PRESENT;
590	tsig->position = buffer_position(packet);
591	tsig->key_name = NULL;
592	tsig->algorithm_name = NULL;
593	tsig->mac_data = NULL;
594	tsig->other_data = NULL;
595	region_free_all(tsig->rr_region);
596
597	tsig->key_name = dname_make_from_packet(tsig->rr_region, packet, 1, 1);
598	if (!tsig->key_name) {
599		buffer_set_position(packet, tsig->position);
600		return 0;
601	}
602
603	if (!buffer_available(packet, 10)) {
604		buffer_set_position(packet, tsig->position);
605		return 0;
606	}
607
608	type = buffer_read_u16(packet);
609	klass = buffer_read_u16(packet);
610
611	/* TSIG not present */
612	if (type != TYPE_TSIG || klass != CLASS_ANY) {
613		buffer_set_position(packet, tsig->position);
614		return 1;
615	}
616
617	ttl = buffer_read_u32(packet);
618	rdlen = buffer_read_u16(packet);
619
620	tsig->status = TSIG_ERROR;
621	tsig->error_code = RCODE_FORMAT;
622	if (ttl != 0 || !buffer_available(packet, rdlen)) {
623		buffer_set_position(packet, tsig->position);
624		return 0;
625	}
626
627	tsig->algorithm_name = dname_make_from_packet(
628		tsig->rr_region, packet, 1, 1);
629	if (!tsig->algorithm_name || !buffer_available(packet, 10)) {
630		buffer_set_position(packet, tsig->position);
631		return 0;
632	}
633
634	tsig->signed_time_high = buffer_read_u16(packet);
635	tsig->signed_time_low = buffer_read_u32(packet);
636	tsig->signed_time_fudge = buffer_read_u16(packet);
637	tsig->mac_size = buffer_read_u16(packet);
638	if (!buffer_available(packet, tsig->mac_size)) {
639		buffer_set_position(packet, tsig->position);
640		tsig->mac_size = 0;
641		return 0;
642	}
643	if(tsig->mac_size > 16384) {
644		/* the hash should not be too big, really 512/8=64 bytes */
645		buffer_set_position(packet, tsig->position);
646		tsig->mac_size = 0;
647		return 0;
648	}
649	tsig->mac_data = (uint8_t *) region_alloc_init(
650		tsig->rr_region, buffer_current(packet), tsig->mac_size);
651	buffer_skip(packet, tsig->mac_size);
652	if (!buffer_available(packet, 6)) {
653		buffer_set_position(packet, tsig->position);
654		return 0;
655	}
656	tsig->original_query_id = buffer_read_u16(packet);
657	tsig->error_code = buffer_read_u16(packet);
658	tsig->other_size = buffer_read_u16(packet);
659	if (!buffer_available(packet, tsig->other_size) || tsig->other_size > 16) {
660		tsig->other_size = 0;
661		buffer_set_position(packet, tsig->position);
662		return 0;
663	}
664	tsig->other_data = (uint8_t *) region_alloc_init(
665		tsig->rr_region, buffer_current(packet), tsig->other_size);
666	buffer_skip(packet, tsig->other_size);
667	tsig->status = TSIG_OK;
668	return 1;
669}
670
671void
672tsig_append_rr(tsig_record_type *tsig, buffer_type *packet)
673{
674	size_t rdlength_pos;
675
676	/* XXX: TODO key name compression? */
677	if(tsig->key_name)
678		buffer_write(packet, dname_name(tsig->key_name),
679		     tsig->key_name->name_size);
680	else	buffer_write_u8(packet, 0);
681	buffer_write_u16(packet, TYPE_TSIG);
682	buffer_write_u16(packet, CLASS_ANY);
683	buffer_write_u32(packet, 0); /* TTL */
684	rdlength_pos = buffer_position(packet);
685	buffer_skip(packet, sizeof(uint16_t));
686	if(tsig->algorithm_name)
687		buffer_write(packet, dname_name(tsig->algorithm_name),
688		     tsig->algorithm_name->name_size);
689	else 	buffer_write_u8(packet, 0);
690	buffer_write_u16(packet, tsig->signed_time_high);
691	buffer_write_u32(packet, tsig->signed_time_low);
692	buffer_write_u16(packet, tsig->signed_time_fudge);
693	buffer_write_u16(packet, tsig->mac_size);
694	buffer_write(packet, tsig->mac_data, tsig->mac_size);
695	buffer_write_u16(packet, tsig->original_query_id);
696	buffer_write_u16(packet, tsig->error_code);
697	buffer_write_u16(packet, tsig->other_size);
698	buffer_write(packet, tsig->other_data, tsig->other_size);
699
700	buffer_write_u16_at(packet, rdlength_pos,
701			    buffer_position(packet) - rdlength_pos
702			    - sizeof(uint16_t));
703}
704
705size_t
706tsig_reserved_space(tsig_record_type *tsig)
707{
708	if (tsig->status == TSIG_NOT_PRESENT)
709		return 0;
710
711	return (
712		(tsig->key_name?tsig->key_name->name_size:1)   /* Owner */
713		+ sizeof(uint16_t)	    /* Type */
714		+ sizeof(uint16_t)	    /* Class */
715		+ sizeof(uint32_t)	    /* TTL */
716		+ sizeof(uint16_t)	    /* RDATA length */
717		+ (tsig->algorithm_name?tsig->algorithm_name->name_size:1)
718		+ sizeof(uint16_t)	    /* Signed time (high) */
719		+ sizeof(uint32_t)	    /* Signed time (low) */
720		+ sizeof(uint16_t)	    /* Signed time fudge */
721		+ sizeof(uint16_t)	    /* MAC size */
722		+ max_algo_digest_size 	    /* MAC data */
723		+ sizeof(uint16_t)	    /* Original query ID */
724		+ sizeof(uint16_t)	    /* Error code */
725		+ sizeof(uint16_t)	    /* Other size */
726		+ tsig->other_size);	    /* Other data */
727}
728
729void
730tsig_error_reply(tsig_record_type *tsig)
731{
732	if(tsig->mac_data)
733		memset(tsig->mac_data, 0, tsig->mac_size);
734	tsig->mac_size = 0;
735}
736
737void
738tsig_finalize()
739{
740#if defined(HAVE_SSL)
741	tsig_openssl_finalize();
742#endif /* defined(HAVE_SSL) */
743}
744