Home | History | Annotate | Line # | Download | only in dist
      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
     25 int 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 
     77 static region_type *tsig_region;
     78 
     79 struct tsig_key_table
     80 {
     81 	rbnode_type node; /* by dname */
     82 	tsig_key_type *key;
     83 };
     84 typedef struct tsig_key_table tsig_key_table_type;
     85 static rbtree_type *tsig_key_table;
     86 
     87 struct tsig_algorithm_table
     88 {
     89 	struct tsig_algorithm_table *next;
     90 	tsig_algorithm_type *algorithm;
     91 };
     92 typedef struct tsig_algorithm_table tsig_algorithm_table_type;
     93 static tsig_algorithm_table_type *tsig_algorithm_table;
     94 static size_t max_algo_digest_size = 0;
     95 
     96 static void
     97 tsig_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 
    143 static int
    144 tree_dname_compare(const void* a, const void* b)
    145 {
    146 	return dname_compare((const dname_type*)a, (const dname_type*)b);
    147 }
    148 
    149 int
    150 tsig_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 
    162 void
    163 tsig_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 
    172 void
    173 tsig_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 
    182 tsig_key_type*
    183 tsig_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 
    192 void
    193 tsig_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  */
    208 int
    209 tsig_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  */
    237 tsig_algorithm_type *
    238 tsig_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 
    259 const char *
    260 tsig_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 
    288 static void
    289 tsig_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 
    296 void
    297 tsig_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 
    303 void
    304 tsig_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 
    316 void
    317 tsig_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 
    325 void
    326 tsig_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 
    342 int
    343 tsig_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 
    437 void
    438 tsig_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 
    456 void
    457 tsig_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 
    484 void
    485 tsig_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 
    505 void
    506 tsig_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 
    523 int
    524 tsig_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 
    545 int
    546 tsig_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 
    581 int
    582 tsig_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 
    671 void
    672 tsig_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 	if(tsig->mac_size != 0)
    695 		buffer_write(packet, tsig->mac_data, tsig->mac_size);
    696 	buffer_write_u16(packet, tsig->original_query_id);
    697 	buffer_write_u16(packet, tsig->error_code);
    698 	buffer_write_u16(packet, tsig->other_size);
    699 	if(tsig->other_size != 0)
    700 		buffer_write(packet, tsig->other_data, tsig->other_size);
    701 
    702 	buffer_write_u16_at(packet, rdlength_pos,
    703 			    buffer_position(packet) - rdlength_pos
    704 			    - sizeof(uint16_t));
    705 }
    706 
    707 size_t
    708 tsig_reserved_space(tsig_record_type *tsig)
    709 {
    710 	if (tsig->status == TSIG_NOT_PRESENT)
    711 		return 0;
    712 
    713 	return (
    714 		(tsig->key_name?tsig->key_name->name_size:1)   /* Owner */
    715 		+ sizeof(uint16_t)	    /* Type */
    716 		+ sizeof(uint16_t)	    /* Class */
    717 		+ sizeof(uint32_t)	    /* TTL */
    718 		+ sizeof(uint16_t)	    /* RDATA length */
    719 		+ (tsig->algorithm_name?tsig->algorithm_name->name_size:1)
    720 		+ sizeof(uint16_t)	    /* Signed time (high) */
    721 		+ sizeof(uint32_t)	    /* Signed time (low) */
    722 		+ sizeof(uint16_t)	    /* Signed time fudge */
    723 		+ sizeof(uint16_t)	    /* MAC size */
    724 		+ max_algo_digest_size 	    /* MAC data */
    725 		+ sizeof(uint16_t)	    /* Original query ID */
    726 		+ sizeof(uint16_t)	    /* Error code */
    727 		+ sizeof(uint16_t)	    /* Other size */
    728 		+ tsig->other_size);	    /* Other data */
    729 }
    730 
    731 void
    732 tsig_error_reply(tsig_record_type *tsig)
    733 {
    734 	if(tsig->mac_data)
    735 		memset(tsig->mac_data, 0, tsig->mac_size);
    736 	tsig->mac_size = 0;
    737 }
    738 
    739 void
    740 tsig_finalize()
    741 {
    742 #if defined(HAVE_SSL)
    743 	tsig_openssl_finalize();
    744 #endif /* defined(HAVE_SSL) */
    745 }
    746