xref: /openbsd-src/usr.sbin/nsd/tsig.c (revision 308d25095010cc66b1b67286e27e62e265360b59)
162ac0c33Sjakob /*
2d3fecca9Ssthen  * tsig.c -- TSIG implementation (RFC 2845).
362ac0c33Sjakob  *
4d3fecca9Ssthen  * Copyright (c) 2001-2006, NLnet Labs. All rights reserved.
562ac0c33Sjakob  *
662ac0c33Sjakob  * See LICENSE for the license.
762ac0c33Sjakob  *
862ac0c33Sjakob  */
962ac0c33Sjakob 
1062ac0c33Sjakob 
11aee1b7aaSsthen #include "config.h"
1262ac0c33Sjakob #include <stdlib.h>
1362ac0c33Sjakob #include <ctype.h>
1462ac0c33Sjakob 
1562ac0c33Sjakob #include "tsig.h"
1662ac0c33Sjakob #include "tsig-openssl.h"
1762ac0c33Sjakob #include "dns.h"
1862ac0c33Sjakob #include "packet.h"
19d3fecca9Ssthen #include "query.h"
20d3fecca9Ssthen #include "rbtree.h"
2162ac0c33Sjakob 
225435475dSsthen #if !defined(HAVE_SSL) || !defined(HAVE_CRYPTO_MEMCMP)
23eab1363eSsthen /* we need fixed time compare */
24eab1363eSsthen #define CRYPTO_memcmp memcmp_fixedtime
memcmp_fixedtime(const void * s1,const void * s2,size_t n)25eab1363eSsthen int memcmp_fixedtime(const void *s1, const void *s2, size_t n)
26eab1363eSsthen {
27eab1363eSsthen 	size_t i;
28eab1363eSsthen 	const uint8_t* u1 = (const uint8_t*)s1;
29eab1363eSsthen 	const uint8_t* u2 = (const uint8_t*)s2;
30eab1363eSsthen 	int ret = 0, haveit = 0, bret = 0, bhaveit = 0;
31eab1363eSsthen 	/* this routine loops for every byte in the strings.
32eab1363eSsthen 	 * every loop, it tests ==, < and >.  All three.  One succeeds,
33eab1363eSsthen 	 * as every time it must be equal, smaller or larger.  The one
34eab1363eSsthen 	 * that succeeds has one if-comparison and two assignments. */
35eab1363eSsthen 	for(i=0; i<n; i++) {
36eab1363eSsthen 		if(u1[i] == u2[i]) {
37eab1363eSsthen 			/* waste time equal to < and > statements */
38eab1363eSsthen 			if(haveit) {
39eab1363eSsthen 				bret = -1; /* waste time */
40eab1363eSsthen 				bhaveit = 1;
41eab1363eSsthen 			} else {
42eab1363eSsthen 				bret = 1; /* waste time */
43eab1363eSsthen 				bhaveit = 1;
44eab1363eSsthen 			}
45eab1363eSsthen 		}
46eab1363eSsthen 		if(u1[i] < u2[i]) {
47eab1363eSsthen 			if(haveit) {
48eab1363eSsthen 				bret = -1; /* waste time equal to the else */
49eab1363eSsthen 				bhaveit = 1;
50eab1363eSsthen 			} else {
51eab1363eSsthen 				ret = -1;
52eab1363eSsthen 				haveit = 1;
53eab1363eSsthen 			}
54eab1363eSsthen 		}
55eab1363eSsthen 		if(u1[i] > u2[i]) {
56eab1363eSsthen 			if(haveit) {
57eab1363eSsthen 				bret = 1; /* waste time equal to the else */
58eab1363eSsthen 				bhaveit = 1;
59eab1363eSsthen 			} else {
60eab1363eSsthen 				ret = 1;
61eab1363eSsthen 				haveit = 1;
62eab1363eSsthen 			}
63eab1363eSsthen 		}
64eab1363eSsthen 	}
65eab1363eSsthen 	/* use the variables to stop the compiler from excluding them */
66eab1363eSsthen 	if(bhaveit) {
67eab1363eSsthen 		if(bret == -2)
68eab1363eSsthen 			ret = 0; /* never happens */
69eab1363eSsthen 	} else {
70eab1363eSsthen 		if(bret == -2)
71eab1363eSsthen 			ret = 0; /* never happens */
72eab1363eSsthen 	}
73eab1363eSsthen 	return ret;
74eab1363eSsthen }
75eab1363eSsthen #endif
76eab1363eSsthen 
7762ac0c33Sjakob static region_type *tsig_region;
7862ac0c33Sjakob 
7962ac0c33Sjakob struct tsig_key_table
8062ac0c33Sjakob {
81fe5fe5f6Sflorian 	rbnode_type node; /* by dname */
8262ac0c33Sjakob 	tsig_key_type *key;
8362ac0c33Sjakob };
8462ac0c33Sjakob typedef struct tsig_key_table tsig_key_table_type;
85fe5fe5f6Sflorian static rbtree_type *tsig_key_table;
8662ac0c33Sjakob 
8762ac0c33Sjakob struct tsig_algorithm_table
8862ac0c33Sjakob {
8962ac0c33Sjakob 	struct tsig_algorithm_table *next;
9062ac0c33Sjakob 	tsig_algorithm_type *algorithm;
9162ac0c33Sjakob };
9262ac0c33Sjakob typedef struct tsig_algorithm_table tsig_algorithm_table_type;
9362ac0c33Sjakob static tsig_algorithm_table_type *tsig_algorithm_table;
9462ac0c33Sjakob static size_t max_algo_digest_size = 0;
9562ac0c33Sjakob 
9662ac0c33Sjakob static void
tsig_digest_variables(tsig_record_type * tsig,int tsig_timers_only)9762ac0c33Sjakob tsig_digest_variables(tsig_record_type *tsig, int tsig_timers_only)
9862ac0c33Sjakob {
9962ac0c33Sjakob 	uint16_t klass = htons(CLASS_ANY);
10062ac0c33Sjakob 	uint32_t ttl = htonl(0);
10162ac0c33Sjakob 	uint16_t signed_time_high = htons(tsig->signed_time_high);
10262ac0c33Sjakob 	uint32_t signed_time_low = htonl(tsig->signed_time_low);
10362ac0c33Sjakob 	uint16_t signed_time_fudge = htons(tsig->signed_time_fudge);
10462ac0c33Sjakob 	uint16_t error_code = htons(tsig->error_code);
10562ac0c33Sjakob 	uint16_t other_size = htons(tsig->other_size);
10662ac0c33Sjakob 
10762ac0c33Sjakob 	if (!tsig_timers_only) {
10862ac0c33Sjakob 		tsig->algorithm->hmac_update(tsig->context,
10962ac0c33Sjakob 					     dname_name(tsig->key_name),
11062ac0c33Sjakob 					     tsig->key_name->name_size);
11162ac0c33Sjakob 		tsig->algorithm->hmac_update(tsig->context,
11262ac0c33Sjakob 					     &klass,
11362ac0c33Sjakob 					     sizeof(klass));
11462ac0c33Sjakob 		tsig->algorithm->hmac_update(tsig->context,
11562ac0c33Sjakob 					     &ttl,
11662ac0c33Sjakob 					     sizeof(ttl));
11762ac0c33Sjakob 		tsig->algorithm->hmac_update(tsig->context,
11862ac0c33Sjakob 					     dname_name(tsig->algorithm_name),
11962ac0c33Sjakob 					     tsig->algorithm_name->name_size);
12062ac0c33Sjakob 	}
12162ac0c33Sjakob 	tsig->algorithm->hmac_update(tsig->context,
12262ac0c33Sjakob 				     &signed_time_high,
12362ac0c33Sjakob 				     sizeof(signed_time_high));
12462ac0c33Sjakob 	tsig->algorithm->hmac_update(tsig->context,
12562ac0c33Sjakob 				     &signed_time_low,
12662ac0c33Sjakob 				     sizeof(signed_time_low));
12762ac0c33Sjakob 	tsig->algorithm->hmac_update(tsig->context,
12862ac0c33Sjakob 				     &signed_time_fudge,
12962ac0c33Sjakob 				     sizeof(signed_time_fudge));
13062ac0c33Sjakob 	if (!tsig_timers_only) {
13162ac0c33Sjakob 		tsig->algorithm->hmac_update(tsig->context,
13262ac0c33Sjakob 					     &error_code,
13362ac0c33Sjakob 					     sizeof(error_code));
13462ac0c33Sjakob 		tsig->algorithm->hmac_update(tsig->context,
13562ac0c33Sjakob 					     &other_size,
13662ac0c33Sjakob 					     sizeof(other_size));
13762ac0c33Sjakob 		tsig->algorithm->hmac_update(tsig->context,
13862ac0c33Sjakob 					     tsig->other_data,
13962ac0c33Sjakob 					     tsig->other_size);
14062ac0c33Sjakob 	}
14162ac0c33Sjakob }
14262ac0c33Sjakob 
143d3fecca9Ssthen static int
tree_dname_compare(const void * a,const void * b)144d3fecca9Ssthen tree_dname_compare(const void* a, const void* b)
145d3fecca9Ssthen {
146d3fecca9Ssthen 	return dname_compare((const dname_type*)a, (const dname_type*)b);
147d3fecca9Ssthen }
148d3fecca9Ssthen 
14962ac0c33Sjakob int
tsig_init(region_type * region)15062ac0c33Sjakob tsig_init(region_type *region)
15162ac0c33Sjakob {
15262ac0c33Sjakob 	tsig_region = region;
153d3fecca9Ssthen 	tsig_key_table = rbtree_create(region, &tree_dname_compare);
15462ac0c33Sjakob 	tsig_algorithm_table = NULL;
15562ac0c33Sjakob 
156d65f3523Sjakob #if defined(HAVE_SSL)
15762ac0c33Sjakob 	return tsig_openssl_init(region);
158217deabeSjakob #endif /* defined(HAVE_SSL) */
15962ac0c33Sjakob 	return 1;
16062ac0c33Sjakob }
16162ac0c33Sjakob 
16262ac0c33Sjakob void
tsig_add_key(tsig_key_type * key)16362ac0c33Sjakob tsig_add_key(tsig_key_type *key)
16462ac0c33Sjakob {
165d3fecca9Ssthen 	tsig_key_table_type *entry = (tsig_key_table_type *) region_alloc_zero(
16662ac0c33Sjakob 		tsig_region, sizeof(tsig_key_table_type));
16762ac0c33Sjakob 	entry->key = key;
168d3fecca9Ssthen 	entry->node.key = entry->key->name;
169d3fecca9Ssthen 	(void)rbtree_insert(tsig_key_table, &entry->node);
170d3fecca9Ssthen }
171d3fecca9Ssthen 
172d3fecca9Ssthen void
tsig_del_key(tsig_key_type * key)173d3fecca9Ssthen tsig_del_key(tsig_key_type *key)
174d3fecca9Ssthen {
175d3fecca9Ssthen 	tsig_key_table_type *entry;
176d3fecca9Ssthen 	if(!key) return;
177d3fecca9Ssthen 	entry = (tsig_key_table_type*)rbtree_delete(tsig_key_table, key->name);
178d3fecca9Ssthen 	if(!entry) return;
179d3fecca9Ssthen 	region_recycle(tsig_region, entry, sizeof(tsig_key_table_type));
180d3fecca9Ssthen }
181d3fecca9Ssthen 
182d3fecca9Ssthen tsig_key_type*
tsig_find_key(const dname_type * name)183d3fecca9Ssthen tsig_find_key(const dname_type* name)
184d3fecca9Ssthen {
185d3fecca9Ssthen 	tsig_key_table_type* entry;
186d3fecca9Ssthen 	entry = (tsig_key_table_type*)rbtree_search(tsig_key_table, name);
187d3fecca9Ssthen 	if(entry)
188d3fecca9Ssthen 		return entry->key;
189d3fecca9Ssthen 	return NULL;
19062ac0c33Sjakob }
19162ac0c33Sjakob 
19262ac0c33Sjakob void
tsig_add_algorithm(tsig_algorithm_type * algorithm)19362ac0c33Sjakob tsig_add_algorithm(tsig_algorithm_type *algorithm)
19462ac0c33Sjakob {
19562ac0c33Sjakob 	tsig_algorithm_table_type *entry
19662ac0c33Sjakob 		= (tsig_algorithm_table_type *) region_alloc(
19762ac0c33Sjakob 			tsig_region, sizeof(tsig_algorithm_table_type));
19862ac0c33Sjakob 	entry->algorithm = algorithm;
19962ac0c33Sjakob 	entry->next = tsig_algorithm_table;
20062ac0c33Sjakob 	tsig_algorithm_table = entry;
20162ac0c33Sjakob 	if(algorithm->maximum_digest_size > max_algo_digest_size)
20262ac0c33Sjakob 		max_algo_digest_size = algorithm->maximum_digest_size;
20362ac0c33Sjakob }
20462ac0c33Sjakob 
20562ac0c33Sjakob /**
20662ac0c33Sjakob  * compare a tsig algorithm string lowercased
20762ac0c33Sjakob  */
20862ac0c33Sjakob int
tsig_strlowercmp(const char * str1,const char * str2)20962ac0c33Sjakob tsig_strlowercmp(const char* str1, const char* str2)
21062ac0c33Sjakob {
21162ac0c33Sjakob 	while (str1 && str2 && *str1 != '\0' && *str2 != '\0') {
21282cafdebSmillert 		if(tolower((unsigned char)*str1) != tolower((unsigned char)*str2)) {
21382cafdebSmillert 			if(tolower((unsigned char)*str1) < tolower((unsigned char)*str2))
21462ac0c33Sjakob 				return -1;
21562ac0c33Sjakob 			return 1;
21662ac0c33Sjakob 		}
21762ac0c33Sjakob 		str1++;
21862ac0c33Sjakob 		str2++;
21962ac0c33Sjakob 	}
22062ac0c33Sjakob 	if (str1 && str2) {
22162ac0c33Sjakob 		if (*str1 == *str2)
22262ac0c33Sjakob 			return 0;
22362ac0c33Sjakob 		else if (*str1 == '\0')
22462ac0c33Sjakob 			return -1;
22562ac0c33Sjakob 	}
22662ac0c33Sjakob 	else if (!str1 && !str2)
22762ac0c33Sjakob 		return 0;
22862ac0c33Sjakob 	else if (!str1 && str2)
22962ac0c33Sjakob 		return -1;
23062ac0c33Sjakob 	return 1;
23162ac0c33Sjakob }
23262ac0c33Sjakob 
23362ac0c33Sjakob 
23462ac0c33Sjakob /*
23562ac0c33Sjakob  * Find an HMAC algorithm based on its short name.
23662ac0c33Sjakob  */
23762ac0c33Sjakob tsig_algorithm_type *
tsig_get_algorithm_by_name(const char * name)23862ac0c33Sjakob tsig_get_algorithm_by_name(const char *name)
23962ac0c33Sjakob {
24062ac0c33Sjakob 	tsig_algorithm_table_type *algorithm_entry;
24162ac0c33Sjakob 
24262ac0c33Sjakob 	for (algorithm_entry = tsig_algorithm_table;
24362ac0c33Sjakob 	     algorithm_entry;
24462ac0c33Sjakob 	     algorithm_entry = algorithm_entry->next)
24562ac0c33Sjakob 	{
24662ac0c33Sjakob 		if (tsig_strlowercmp(name, algorithm_entry->algorithm->short_name) == 0)
24762ac0c33Sjakob 		{
24862ac0c33Sjakob 			return algorithm_entry->algorithm;
24962ac0c33Sjakob 		}
250c1e73312Sflorian 		if(strncmp("hmac-", algorithm_entry->algorithm->short_name, 5) == 0 && tsig_strlowercmp(name, algorithm_entry->algorithm->short_name+5) == 0) {
251c1e73312Sflorian 			return algorithm_entry->algorithm;
252c1e73312Sflorian 		}
25362ac0c33Sjakob 	}
25462ac0c33Sjakob 
25562ac0c33Sjakob 	return NULL;
25662ac0c33Sjakob }
25762ac0c33Sjakob 
25862ac0c33Sjakob 
25962ac0c33Sjakob const char *
tsig_error(int error_code)26062ac0c33Sjakob tsig_error(int error_code)
26162ac0c33Sjakob {
26262ac0c33Sjakob 	static char message[1000];
26362ac0c33Sjakob 
26462ac0c33Sjakob 	switch (error_code) {
26562ac0c33Sjakob 	case TSIG_ERROR_NOERROR:
26662ac0c33Sjakob 		return "No Error";
26762ac0c33Sjakob 		break;
26862ac0c33Sjakob 	case TSIG_ERROR_BADSIG:
26962ac0c33Sjakob 		return "Bad Signature";
27062ac0c33Sjakob 		break;
27162ac0c33Sjakob 	case TSIG_ERROR_BADKEY:
27262ac0c33Sjakob 		return "Bad Key";
27362ac0c33Sjakob 		break;
27462ac0c33Sjakob 	case TSIG_ERROR_BADTIME:
27562ac0c33Sjakob 		return "Bad Time";
27662ac0c33Sjakob 		break;
27762ac0c33Sjakob 	default:
27862ac0c33Sjakob 		if(error_code < 16) /* DNS rcodes */
27962ac0c33Sjakob 			return rcode2str(error_code);
28062ac0c33Sjakob 
28162ac0c33Sjakob 		snprintf(message, sizeof(message),
28262ac0c33Sjakob 			 "Unknown Error %d", error_code);
28362ac0c33Sjakob 		break;
28462ac0c33Sjakob 	}
28562ac0c33Sjakob 	return message;
28662ac0c33Sjakob }
28762ac0c33Sjakob 
28862ac0c33Sjakob static void
tsig_cleanup(void * data)28962ac0c33Sjakob tsig_cleanup(void *data)
29062ac0c33Sjakob {
29162ac0c33Sjakob 	tsig_record_type *tsig = (tsig_record_type *) data;
29262ac0c33Sjakob 	region_destroy(tsig->rr_region);
29362ac0c33Sjakob 	region_destroy(tsig->context_region);
29462ac0c33Sjakob }
29562ac0c33Sjakob 
29662ac0c33Sjakob void
tsig_create_record(tsig_record_type * tsig,region_type * region)29762ac0c33Sjakob tsig_create_record(tsig_record_type *tsig, region_type *region)
29862ac0c33Sjakob {
29962ac0c33Sjakob 	tsig_create_record_custom(tsig, region, DEFAULT_CHUNK_SIZE,
30062ac0c33Sjakob 		DEFAULT_LARGE_OBJECT_SIZE, DEFAULT_INITIAL_CLEANUP_SIZE);
30162ac0c33Sjakob }
30262ac0c33Sjakob 
30362ac0c33Sjakob void
tsig_create_record_custom(tsig_record_type * tsig,region_type * region,size_t chunk_size,size_t large_object_size,size_t initial_cleanup_size)30462ac0c33Sjakob tsig_create_record_custom(tsig_record_type *tsig, region_type *region,
30562ac0c33Sjakob 	size_t chunk_size, size_t large_object_size, size_t initial_cleanup_size)
30662ac0c33Sjakob {
30762ac0c33Sjakob 	tsig->rr_region = region_create_custom(xalloc, free, chunk_size,
30862ac0c33Sjakob 		large_object_size, initial_cleanup_size, 0);
30962ac0c33Sjakob 	tsig->context_region = region_create_custom(xalloc, free, chunk_size,
31062ac0c33Sjakob 		large_object_size, initial_cleanup_size, 0);
311d3fecca9Ssthen 	if(region)
31262ac0c33Sjakob 		region_add_cleanup(region, tsig_cleanup, tsig);
31362ac0c33Sjakob 	tsig_init_record(tsig, NULL, NULL);
31462ac0c33Sjakob }
31562ac0c33Sjakob 
31662ac0c33Sjakob void
tsig_delete_record(tsig_record_type * tsig,region_type * region)317d3fecca9Ssthen tsig_delete_record(tsig_record_type* tsig, region_type* region)
318d3fecca9Ssthen {
319d3fecca9Ssthen 	if(region)
320d3fecca9Ssthen 		region_remove_cleanup(region, tsig_cleanup, tsig);
321d3fecca9Ssthen 	region_destroy(tsig->rr_region);
322d3fecca9Ssthen 	region_destroy(tsig->context_region);
323d3fecca9Ssthen }
324d3fecca9Ssthen 
325d3fecca9Ssthen void
tsig_init_record(tsig_record_type * tsig,tsig_algorithm_type * algorithm,tsig_key_type * key)32662ac0c33Sjakob tsig_init_record(tsig_record_type *tsig,
32762ac0c33Sjakob 		 tsig_algorithm_type *algorithm,
32862ac0c33Sjakob 		 tsig_key_type *key)
32962ac0c33Sjakob {
33062ac0c33Sjakob 	tsig->status = TSIG_NOT_PRESENT;
33162ac0c33Sjakob 	tsig->error_code = TSIG_ERROR_NOERROR;
33262ac0c33Sjakob 	tsig->position = 0;
33362ac0c33Sjakob 	tsig->response_count = 0;
33462ac0c33Sjakob 	tsig->context = NULL;
33562ac0c33Sjakob 	tsig->algorithm = algorithm;
33662ac0c33Sjakob 	tsig->key = key;
33762ac0c33Sjakob 	tsig->prior_mac_size = 0;
33862ac0c33Sjakob 	tsig->prior_mac_data = NULL;
33962ac0c33Sjakob 	region_free_all(tsig->context_region);
34062ac0c33Sjakob }
34162ac0c33Sjakob 
34262ac0c33Sjakob int
tsig_from_query(tsig_record_type * tsig)34362ac0c33Sjakob tsig_from_query(tsig_record_type *tsig)
34462ac0c33Sjakob {
34562ac0c33Sjakob 	tsig_key_type *key = NULL;
34662ac0c33Sjakob 	tsig_algorithm_table_type *algorithm_entry;
34762ac0c33Sjakob 	tsig_algorithm_type *algorithm = NULL;
34862ac0c33Sjakob 	uint64_t current_time;
34962ac0c33Sjakob 	uint64_t signed_time;
35062ac0c33Sjakob 
35162ac0c33Sjakob 	assert(tsig->status == TSIG_OK);
35262ac0c33Sjakob 	assert(!tsig->algorithm);
35362ac0c33Sjakob 	assert(!tsig->key);
35462ac0c33Sjakob 
355d3fecca9Ssthen 	key = (tsig_key_type*)tsig_find_key(tsig->key_name);
35662ac0c33Sjakob 
35762ac0c33Sjakob 	for (algorithm_entry = tsig_algorithm_table;
35862ac0c33Sjakob 	     algorithm_entry;
35962ac0c33Sjakob 	     algorithm_entry = algorithm_entry->next)
36062ac0c33Sjakob 	{
36162ac0c33Sjakob 		if (dname_compare(
36262ac0c33Sjakob 			    tsig->algorithm_name,
36362ac0c33Sjakob 			    algorithm_entry->algorithm->wireformat_name) == 0)
36462ac0c33Sjakob 		{
36562ac0c33Sjakob 			algorithm = algorithm_entry->algorithm;
36662ac0c33Sjakob 			break;
36762ac0c33Sjakob 		}
36862ac0c33Sjakob 	}
36962ac0c33Sjakob 
37062ac0c33Sjakob 	if (!algorithm || !key) {
37162ac0c33Sjakob 		/* Algorithm or key is unknown, cannot authenticate.  */
37262ac0c33Sjakob 		tsig->error_code = TSIG_ERROR_BADKEY;
37362ac0c33Sjakob 		return 0;
37462ac0c33Sjakob 	}
37562ac0c33Sjakob 
37662ac0c33Sjakob 	if ((tsig->algorithm && algorithm != tsig->algorithm)
37762ac0c33Sjakob 	    || (tsig->key && key != tsig->key))
37862ac0c33Sjakob 	{
37962ac0c33Sjakob 		/*
38062ac0c33Sjakob 		 * Algorithm or key changed during a single connection,
38162ac0c33Sjakob 		 * return error.
38262ac0c33Sjakob 		 */
38362ac0c33Sjakob 		tsig->error_code = TSIG_ERROR_BADKEY;
38462ac0c33Sjakob 		return 0;
38562ac0c33Sjakob 	}
38662ac0c33Sjakob 
38762ac0c33Sjakob 	signed_time = ((((uint64_t) tsig->signed_time_high) << 32) |
38862ac0c33Sjakob 		       ((uint64_t) tsig->signed_time_low));
38962ac0c33Sjakob 
39062ac0c33Sjakob 	current_time = (uint64_t) time(NULL);
39162ac0c33Sjakob 	if ((current_time < signed_time - tsig->signed_time_fudge)
39262ac0c33Sjakob 	    || (current_time > signed_time + tsig->signed_time_fudge))
39362ac0c33Sjakob 	{
39462ac0c33Sjakob 		uint16_t current_time_high;
39562ac0c33Sjakob 		uint32_t current_time_low;
39662ac0c33Sjakob 
39762ac0c33Sjakob #if 0 /* debug */
39862ac0c33Sjakob 		char current_time_text[26];
39962ac0c33Sjakob 		char signed_time_text[26];
40062ac0c33Sjakob 		time_t clock;
40162ac0c33Sjakob 
40262ac0c33Sjakob 		clock = (time_t) current_time;
40362ac0c33Sjakob 		ctime_r(&clock, current_time_text);
40462ac0c33Sjakob 		current_time_text[24] = '\0';
40562ac0c33Sjakob 
40662ac0c33Sjakob 		clock = (time_t) signed_time;
40762ac0c33Sjakob 		ctime_r(&clock, signed_time_text);
40862ac0c33Sjakob 		signed_time_text[24] = '\0';
40962ac0c33Sjakob 
41062ac0c33Sjakob 		log_msg(LOG_ERR,
41162ac0c33Sjakob 			"current server time %s is outside the range of TSIG"
41262ac0c33Sjakob 			" signed time %s with fudge %u",
41362ac0c33Sjakob 			current_time_text,
41462ac0c33Sjakob 			signed_time_text,
41562ac0c33Sjakob 			(unsigned) tsig->signed_time_fudge);
41662ac0c33Sjakob #endif
41762ac0c33Sjakob 
41862ac0c33Sjakob 		tsig->error_code = TSIG_ERROR_BADTIME;
41962ac0c33Sjakob 		current_time_high = (uint16_t) (current_time >> 32);
42062ac0c33Sjakob 		current_time_low = (uint32_t) current_time;
42162ac0c33Sjakob 		tsig->other_size = 6;
42262ac0c33Sjakob 		tsig->other_data = (uint8_t *) region_alloc(
42362ac0c33Sjakob 			tsig->rr_region, sizeof(uint16_t) + sizeof(uint32_t));
42462ac0c33Sjakob 		write_uint16(tsig->other_data, current_time_high);
42562ac0c33Sjakob 		write_uint32(tsig->other_data + 2, current_time_low);
42662ac0c33Sjakob 		return 0;
42762ac0c33Sjakob 	}
42862ac0c33Sjakob 
42962ac0c33Sjakob 	tsig->algorithm = algorithm;
43062ac0c33Sjakob 	tsig->key = key;
43162ac0c33Sjakob 	tsig->response_count = 0;
43262ac0c33Sjakob 	tsig->prior_mac_size = 0;
43362ac0c33Sjakob 
43462ac0c33Sjakob 	return 1;
43562ac0c33Sjakob }
43662ac0c33Sjakob 
43762ac0c33Sjakob void
tsig_init_query(tsig_record_type * tsig,uint16_t original_query_id)43862ac0c33Sjakob tsig_init_query(tsig_record_type *tsig, uint16_t original_query_id)
43962ac0c33Sjakob {
44062ac0c33Sjakob 	assert(tsig);
44162ac0c33Sjakob 	assert(tsig->algorithm);
44262ac0c33Sjakob 	assert(tsig->key);
44362ac0c33Sjakob 
44462ac0c33Sjakob 	tsig->response_count = 0;
44562ac0c33Sjakob 	tsig->prior_mac_size = 0;
44662ac0c33Sjakob 	tsig->algorithm_name = tsig->algorithm->wireformat_name;
44762ac0c33Sjakob 	tsig->key_name = tsig->key->name;
44862ac0c33Sjakob 	tsig->mac_size = 0;
44962ac0c33Sjakob 	tsig->mac_data = NULL;
45062ac0c33Sjakob 	tsig->original_query_id = original_query_id;
45162ac0c33Sjakob 	tsig->error_code = TSIG_ERROR_NOERROR;
45262ac0c33Sjakob 	tsig->other_size = 0;
45362ac0c33Sjakob 	tsig->other_data = NULL;
45462ac0c33Sjakob }
45562ac0c33Sjakob 
45662ac0c33Sjakob void
tsig_prepare(tsig_record_type * tsig)45762ac0c33Sjakob tsig_prepare(tsig_record_type *tsig)
45862ac0c33Sjakob {
45962ac0c33Sjakob 	if (!tsig->context) {
46062ac0c33Sjakob 		assert(tsig->algorithm);
46162ac0c33Sjakob 		tsig->context = tsig->algorithm->hmac_create_context(
46262ac0c33Sjakob 			tsig->context_region);
46362ac0c33Sjakob 		tsig->prior_mac_data = (uint8_t *) region_alloc(
46462ac0c33Sjakob 			tsig->context_region,
46562ac0c33Sjakob 			tsig->algorithm->maximum_digest_size);
46662ac0c33Sjakob 	}
46762ac0c33Sjakob 	tsig->algorithm->hmac_init_context(tsig->context,
46862ac0c33Sjakob 					   tsig->algorithm,
46962ac0c33Sjakob 					   tsig->key);
47062ac0c33Sjakob 
47162ac0c33Sjakob 	if (tsig->prior_mac_size > 0) {
47262ac0c33Sjakob 		uint16_t mac_size = htons(tsig->prior_mac_size);
47362ac0c33Sjakob 		tsig->algorithm->hmac_update(tsig->context,
47462ac0c33Sjakob 					     &mac_size,
47562ac0c33Sjakob 					     sizeof(mac_size));
47662ac0c33Sjakob 		tsig->algorithm->hmac_update(tsig->context,
47762ac0c33Sjakob 					     tsig->prior_mac_data,
47862ac0c33Sjakob 					     tsig->prior_mac_size);
47962ac0c33Sjakob 	}
48062ac0c33Sjakob 
48162ac0c33Sjakob 	tsig->updates_since_last_prepare = 0;
48262ac0c33Sjakob }
48362ac0c33Sjakob 
48462ac0c33Sjakob void
tsig_update(tsig_record_type * tsig,buffer_type * packet,size_t length)48562ac0c33Sjakob tsig_update(tsig_record_type *tsig, buffer_type *packet, size_t length)
48662ac0c33Sjakob {
48762ac0c33Sjakob 	uint16_t original_query_id = htons(tsig->original_query_id);
48862ac0c33Sjakob 
48962ac0c33Sjakob 	assert(length <= buffer_limit(packet));
49062ac0c33Sjakob 
49162ac0c33Sjakob 	tsig->algorithm->hmac_update(tsig->context,
49262ac0c33Sjakob 				     &original_query_id,
49362ac0c33Sjakob 				     sizeof(original_query_id));
49462ac0c33Sjakob 	tsig->algorithm->hmac_update(
49562ac0c33Sjakob 		tsig->context,
49662ac0c33Sjakob 		buffer_at(packet, sizeof(original_query_id)),
49762ac0c33Sjakob 		length - sizeof(original_query_id));
49862ac0c33Sjakob 	if (QR(packet)) {
49962ac0c33Sjakob 		++tsig->response_count;
50062ac0c33Sjakob 	}
50162ac0c33Sjakob 
50262ac0c33Sjakob 	++tsig->updates_since_last_prepare;
50362ac0c33Sjakob }
50462ac0c33Sjakob 
50562ac0c33Sjakob void
tsig_sign(tsig_record_type * tsig)50662ac0c33Sjakob tsig_sign(tsig_record_type *tsig)
50762ac0c33Sjakob {
50862ac0c33Sjakob 	uint64_t current_time = (uint64_t) time(NULL);
50962ac0c33Sjakob 	tsig->signed_time_high = (uint16_t) (current_time >> 32);
51062ac0c33Sjakob 	tsig->signed_time_low = (uint32_t) current_time;
51162ac0c33Sjakob 	tsig->signed_time_fudge = 300; /* XXX; hardcoded value */
51262ac0c33Sjakob 
51362ac0c33Sjakob 	tsig_digest_variables(tsig, tsig->response_count > 1);
51462ac0c33Sjakob 
51562ac0c33Sjakob 	tsig->algorithm->hmac_final(tsig->context,
51662ac0c33Sjakob 				    tsig->prior_mac_data,
51762ac0c33Sjakob 				    &tsig->prior_mac_size);
51862ac0c33Sjakob 
51962ac0c33Sjakob 	tsig->mac_size = tsig->prior_mac_size;
52062ac0c33Sjakob 	tsig->mac_data = tsig->prior_mac_data;
52162ac0c33Sjakob }
52262ac0c33Sjakob 
52362ac0c33Sjakob int
tsig_verify(tsig_record_type * tsig)52462ac0c33Sjakob tsig_verify(tsig_record_type *tsig)
52562ac0c33Sjakob {
52662ac0c33Sjakob 	tsig_digest_variables(tsig, tsig->response_count > 1);
52762ac0c33Sjakob 
52862ac0c33Sjakob 	tsig->algorithm->hmac_final(tsig->context,
52962ac0c33Sjakob 				    tsig->prior_mac_data,
53062ac0c33Sjakob 				    &tsig->prior_mac_size);
53162ac0c33Sjakob 
53262ac0c33Sjakob 	if (tsig->mac_size != tsig->prior_mac_size
533388c4084Sflorian 	    || CRYPTO_memcmp(tsig->mac_data,
53462ac0c33Sjakob 		      tsig->prior_mac_data,
53562ac0c33Sjakob 		      tsig->mac_size) != 0)
53662ac0c33Sjakob 	{
53762ac0c33Sjakob 		/* Digest is incorrect, cannot authenticate.  */
53862ac0c33Sjakob 		tsig->error_code = TSIG_ERROR_BADSIG;
53962ac0c33Sjakob 		return 0;
54062ac0c33Sjakob 	} else {
54162ac0c33Sjakob 		return 1;
54262ac0c33Sjakob 	}
54362ac0c33Sjakob }
54462ac0c33Sjakob 
54562ac0c33Sjakob int
tsig_find_rr(tsig_record_type * tsig,buffer_type * packet)54662ac0c33Sjakob tsig_find_rr(tsig_record_type *tsig, buffer_type *packet)
54762ac0c33Sjakob {
54862ac0c33Sjakob 	size_t saved_position = buffer_position(packet);
549*308d2509Sflorian 	size_t rrcount = ((size_t)QDCOUNT(packet)
550*308d2509Sflorian 			  + (size_t)ANCOUNT(packet)
551*308d2509Sflorian 			  + (size_t)NSCOUNT(packet)
552*308d2509Sflorian 			  + (size_t)ARCOUNT(packet));
55362ac0c33Sjakob 	size_t i;
55462ac0c33Sjakob 	int result;
55562ac0c33Sjakob 
55662ac0c33Sjakob 	if (ARCOUNT(packet) == 0) {
55762ac0c33Sjakob 		tsig->status = TSIG_NOT_PRESENT;
55862ac0c33Sjakob 		return 1;
55962ac0c33Sjakob 	}
560*308d2509Sflorian 	if(rrcount > 65530) {
561*308d2509Sflorian 		/* impossibly high number of records in 64k, reject packet */
562*308d2509Sflorian 		buffer_set_position(packet, saved_position);
563*308d2509Sflorian 		return 0;
564*308d2509Sflorian 	}
56562ac0c33Sjakob 
56662ac0c33Sjakob 	buffer_set_position(packet, QHEADERSZ);
56762ac0c33Sjakob 
56862ac0c33Sjakob 	/* TSIG must be the last record, so skip all others. */
56962ac0c33Sjakob 	for (i = 0; i < rrcount - 1; ++i) {
57062ac0c33Sjakob 		if (!packet_skip_rr(packet, i < QDCOUNT(packet))) {
57162ac0c33Sjakob 			buffer_set_position(packet, saved_position);
57262ac0c33Sjakob 			return 0;
57362ac0c33Sjakob 		}
57462ac0c33Sjakob 	}
57562ac0c33Sjakob 
57662ac0c33Sjakob 	result = tsig_parse_rr(tsig, packet);
57762ac0c33Sjakob 	buffer_set_position(packet, saved_position);
57862ac0c33Sjakob 	return result;
57962ac0c33Sjakob }
58062ac0c33Sjakob 
58162ac0c33Sjakob int
tsig_parse_rr(tsig_record_type * tsig,buffer_type * packet)58262ac0c33Sjakob tsig_parse_rr(tsig_record_type *tsig, buffer_type *packet)
58362ac0c33Sjakob {
58462ac0c33Sjakob 	uint16_t type;
58562ac0c33Sjakob 	uint16_t klass;
58662ac0c33Sjakob 	uint32_t ttl;
58762ac0c33Sjakob 	uint16_t rdlen;
58862ac0c33Sjakob 
58962ac0c33Sjakob 	tsig->status = TSIG_NOT_PRESENT;
59062ac0c33Sjakob 	tsig->position = buffer_position(packet);
59162ac0c33Sjakob 	tsig->key_name = NULL;
59262ac0c33Sjakob 	tsig->algorithm_name = NULL;
59362ac0c33Sjakob 	tsig->mac_data = NULL;
59462ac0c33Sjakob 	tsig->other_data = NULL;
59562ac0c33Sjakob 	region_free_all(tsig->rr_region);
59662ac0c33Sjakob 
59762ac0c33Sjakob 	tsig->key_name = dname_make_from_packet(tsig->rr_region, packet, 1, 1);
59862ac0c33Sjakob 	if (!tsig->key_name) {
59962ac0c33Sjakob 		buffer_set_position(packet, tsig->position);
60062ac0c33Sjakob 		return 0;
60162ac0c33Sjakob 	}
60262ac0c33Sjakob 
60362ac0c33Sjakob 	if (!buffer_available(packet, 10)) {
60462ac0c33Sjakob 		buffer_set_position(packet, tsig->position);
60562ac0c33Sjakob 		return 0;
60662ac0c33Sjakob 	}
60762ac0c33Sjakob 
60862ac0c33Sjakob 	type = buffer_read_u16(packet);
60962ac0c33Sjakob 	klass = buffer_read_u16(packet);
61062ac0c33Sjakob 
61162ac0c33Sjakob 	/* TSIG not present */
61262ac0c33Sjakob 	if (type != TYPE_TSIG || klass != CLASS_ANY) {
61362ac0c33Sjakob 		buffer_set_position(packet, tsig->position);
61462ac0c33Sjakob 		return 1;
61562ac0c33Sjakob 	}
61662ac0c33Sjakob 
61762ac0c33Sjakob 	ttl = buffer_read_u32(packet);
61862ac0c33Sjakob 	rdlen = buffer_read_u16(packet);
61962ac0c33Sjakob 
62062ac0c33Sjakob 	tsig->status = TSIG_ERROR;
62162ac0c33Sjakob 	tsig->error_code = RCODE_FORMAT;
62262ac0c33Sjakob 	if (ttl != 0 || !buffer_available(packet, rdlen)) {
62362ac0c33Sjakob 		buffer_set_position(packet, tsig->position);
62462ac0c33Sjakob 		return 0;
62562ac0c33Sjakob 	}
62662ac0c33Sjakob 
62762ac0c33Sjakob 	tsig->algorithm_name = dname_make_from_packet(
62862ac0c33Sjakob 		tsig->rr_region, packet, 1, 1);
62962ac0c33Sjakob 	if (!tsig->algorithm_name || !buffer_available(packet, 10)) {
63062ac0c33Sjakob 		buffer_set_position(packet, tsig->position);
63162ac0c33Sjakob 		return 0;
63262ac0c33Sjakob 	}
63362ac0c33Sjakob 
63462ac0c33Sjakob 	tsig->signed_time_high = buffer_read_u16(packet);
63562ac0c33Sjakob 	tsig->signed_time_low = buffer_read_u32(packet);
63662ac0c33Sjakob 	tsig->signed_time_fudge = buffer_read_u16(packet);
63762ac0c33Sjakob 	tsig->mac_size = buffer_read_u16(packet);
63862ac0c33Sjakob 	if (!buffer_available(packet, tsig->mac_size)) {
63962ac0c33Sjakob 		buffer_set_position(packet, tsig->position);
64062ac0c33Sjakob 		tsig->mac_size = 0;
64162ac0c33Sjakob 		return 0;
64262ac0c33Sjakob 	}
643*308d2509Sflorian 	if(tsig->mac_size > 16384) {
644*308d2509Sflorian 		/* the hash should not be too big, really 512/8=64 bytes */
645*308d2509Sflorian 		buffer_set_position(packet, tsig->position);
646*308d2509Sflorian 		tsig->mac_size = 0;
647*308d2509Sflorian 		return 0;
648*308d2509Sflorian 	}
64962ac0c33Sjakob 	tsig->mac_data = (uint8_t *) region_alloc_init(
65062ac0c33Sjakob 		tsig->rr_region, buffer_current(packet), tsig->mac_size);
65162ac0c33Sjakob 	buffer_skip(packet, tsig->mac_size);
65262ac0c33Sjakob 	if (!buffer_available(packet, 6)) {
65362ac0c33Sjakob 		buffer_set_position(packet, tsig->position);
65462ac0c33Sjakob 		return 0;
65562ac0c33Sjakob 	}
65662ac0c33Sjakob 	tsig->original_query_id = buffer_read_u16(packet);
65762ac0c33Sjakob 	tsig->error_code = buffer_read_u16(packet);
65862ac0c33Sjakob 	tsig->other_size = buffer_read_u16(packet);
65962ac0c33Sjakob 	if (!buffer_available(packet, tsig->other_size) || tsig->other_size > 16) {
66062ac0c33Sjakob 		tsig->other_size = 0;
66162ac0c33Sjakob 		buffer_set_position(packet, tsig->position);
66262ac0c33Sjakob 		return 0;
66362ac0c33Sjakob 	}
66462ac0c33Sjakob 	tsig->other_data = (uint8_t *) region_alloc_init(
66562ac0c33Sjakob 		tsig->rr_region, buffer_current(packet), tsig->other_size);
66662ac0c33Sjakob 	buffer_skip(packet, tsig->other_size);
66762ac0c33Sjakob 	tsig->status = TSIG_OK;
66862ac0c33Sjakob 	return 1;
66962ac0c33Sjakob }
67062ac0c33Sjakob 
67162ac0c33Sjakob void
tsig_append_rr(tsig_record_type * tsig,buffer_type * packet)67262ac0c33Sjakob tsig_append_rr(tsig_record_type *tsig, buffer_type *packet)
67362ac0c33Sjakob {
67462ac0c33Sjakob 	size_t rdlength_pos;
67562ac0c33Sjakob 
67662ac0c33Sjakob 	/* XXX: TODO key name compression? */
67762ac0c33Sjakob 	if(tsig->key_name)
67862ac0c33Sjakob 		buffer_write(packet, dname_name(tsig->key_name),
67962ac0c33Sjakob 		     tsig->key_name->name_size);
68062ac0c33Sjakob 	else	buffer_write_u8(packet, 0);
68162ac0c33Sjakob 	buffer_write_u16(packet, TYPE_TSIG);
68262ac0c33Sjakob 	buffer_write_u16(packet, CLASS_ANY);
68362ac0c33Sjakob 	buffer_write_u32(packet, 0); /* TTL */
68462ac0c33Sjakob 	rdlength_pos = buffer_position(packet);
68562ac0c33Sjakob 	buffer_skip(packet, sizeof(uint16_t));
68662ac0c33Sjakob 	if(tsig->algorithm_name)
68762ac0c33Sjakob 		buffer_write(packet, dname_name(tsig->algorithm_name),
68862ac0c33Sjakob 		     tsig->algorithm_name->name_size);
68962ac0c33Sjakob 	else 	buffer_write_u8(packet, 0);
69062ac0c33Sjakob 	buffer_write_u16(packet, tsig->signed_time_high);
69162ac0c33Sjakob 	buffer_write_u32(packet, tsig->signed_time_low);
69262ac0c33Sjakob 	buffer_write_u16(packet, tsig->signed_time_fudge);
69362ac0c33Sjakob 	buffer_write_u16(packet, tsig->mac_size);
69462ac0c33Sjakob 	buffer_write(packet, tsig->mac_data, tsig->mac_size);
69562ac0c33Sjakob 	buffer_write_u16(packet, tsig->original_query_id);
69662ac0c33Sjakob 	buffer_write_u16(packet, tsig->error_code);
69762ac0c33Sjakob 	buffer_write_u16(packet, tsig->other_size);
69862ac0c33Sjakob 	buffer_write(packet, tsig->other_data, tsig->other_size);
69962ac0c33Sjakob 
70062ac0c33Sjakob 	buffer_write_u16_at(packet, rdlength_pos,
70162ac0c33Sjakob 			    buffer_position(packet) - rdlength_pos
70262ac0c33Sjakob 			    - sizeof(uint16_t));
70362ac0c33Sjakob }
70462ac0c33Sjakob 
70562ac0c33Sjakob size_t
tsig_reserved_space(tsig_record_type * tsig)70662ac0c33Sjakob tsig_reserved_space(tsig_record_type *tsig)
70762ac0c33Sjakob {
70862ac0c33Sjakob 	if (tsig->status == TSIG_NOT_PRESENT)
70962ac0c33Sjakob 		return 0;
71062ac0c33Sjakob 
71162ac0c33Sjakob 	return (
71262ac0c33Sjakob 		(tsig->key_name?tsig->key_name->name_size:1)   /* Owner */
71362ac0c33Sjakob 		+ sizeof(uint16_t)	    /* Type */
71462ac0c33Sjakob 		+ sizeof(uint16_t)	    /* Class */
71562ac0c33Sjakob 		+ sizeof(uint32_t)	    /* TTL */
71662ac0c33Sjakob 		+ sizeof(uint16_t)	    /* RDATA length */
71762ac0c33Sjakob 		+ (tsig->algorithm_name?tsig->algorithm_name->name_size:1)
71862ac0c33Sjakob 		+ sizeof(uint16_t)	    /* Signed time (high) */
71962ac0c33Sjakob 		+ sizeof(uint32_t)	    /* Signed time (low) */
72062ac0c33Sjakob 		+ sizeof(uint16_t)	    /* Signed time fudge */
72162ac0c33Sjakob 		+ sizeof(uint16_t)	    /* MAC size */
72262ac0c33Sjakob 		+ max_algo_digest_size 	    /* MAC data */
72362ac0c33Sjakob 		+ sizeof(uint16_t)	    /* Original query ID */
72462ac0c33Sjakob 		+ sizeof(uint16_t)	    /* Error code */
72562ac0c33Sjakob 		+ sizeof(uint16_t)	    /* Other size */
72662ac0c33Sjakob 		+ tsig->other_size);	    /* Other data */
72762ac0c33Sjakob }
72862ac0c33Sjakob 
72962ac0c33Sjakob void
tsig_error_reply(tsig_record_type * tsig)73062ac0c33Sjakob tsig_error_reply(tsig_record_type *tsig)
73162ac0c33Sjakob {
73262ac0c33Sjakob 	if(tsig->mac_data)
73362ac0c33Sjakob 		memset(tsig->mac_data, 0, tsig->mac_size);
73462ac0c33Sjakob 	tsig->mac_size = 0;
73562ac0c33Sjakob }
73662ac0c33Sjakob 
73762ac0c33Sjakob void
tsig_finalize()73862ac0c33Sjakob tsig_finalize()
73962ac0c33Sjakob {
740d65f3523Sjakob #if defined(HAVE_SSL)
74162ac0c33Sjakob 	tsig_openssl_finalize();
742217deabeSjakob #endif /* defined(HAVE_SSL) */
74362ac0c33Sjakob }
744