xref: /openbsd-src/usr.sbin/nsd/tsig-openssl.c (revision a904e10382628c737f903abd24b9073d85e51e87)
162ac0c33Sjakob /*
262ac0c33Sjakob  * tsig-openssl.h -- Interface to OpenSSL for TSIG support.
362ac0c33Sjakob  *
4d3fecca9Ssthen  * Copyright (c) 2001-2006, NLnet Labs. All rights reserved.
562ac0c33Sjakob  *
662ac0c33Sjakob  * See LICENSE for the license.
762ac0c33Sjakob  *
862ac0c33Sjakob  */
962ac0c33Sjakob 
10aee1b7aaSsthen #include "config.h"
1162ac0c33Sjakob 
12d65f3523Sjakob #if defined(HAVE_SSL)
1362ac0c33Sjakob 
143b24e79eSsthen #ifdef HAVE_OPENSSL_CORE_NAMES_H
153b24e79eSsthen #include <openssl/core_names.h>
163b24e79eSsthen #endif
1762ac0c33Sjakob #include "tsig-openssl.h"
1862ac0c33Sjakob #include "tsig.h"
1962ac0c33Sjakob #include "util.h"
2062ac0c33Sjakob 
2162ac0c33Sjakob static void *create_context(region_type *region);
2262ac0c33Sjakob static void init_context(void *context,
2362ac0c33Sjakob 			 tsig_algorithm_type *algorithm,
2462ac0c33Sjakob 			 tsig_key_type *key);
2562ac0c33Sjakob static void update(void *context, const void *data, size_t size);
2662ac0c33Sjakob static void final(void *context, uint8_t *digest, size_t *size);
2762ac0c33Sjakob 
283b24e79eSsthen #ifdef HAVE_EVP_MAC_CTX_NEW
293b24e79eSsthen struct tsig_openssl_data {
303b24e79eSsthen 	/* the MAC for the algorithm, 'hmac' */
313b24e79eSsthen 	EVP_MAC* mac;
323b24e79eSsthen 	/* the digest name for creating the EVP_MAC_CTX with, 'sha256' */
333b24e79eSsthen 	const char* digest;
343b24e79eSsthen };
353b24e79eSsthen 
363b24e79eSsthen struct tsig_openssl_context {
373b24e79eSsthen 	/* the evp mac context, if notNULL it has algo and key set. */
383b24e79eSsthen 	EVP_MAC_CTX* hmac_ctx;
393b24e79eSsthen 	/* the size of destination buffers */
403b24e79eSsthen 	size_t outsize;
413b24e79eSsthen };
423b24e79eSsthen 
433b24e79eSsthen static void
cleanup_tsig_openssl_data(void * data)443b24e79eSsthen cleanup_tsig_openssl_data(void *data)
453b24e79eSsthen {
463b24e79eSsthen 	struct tsig_openssl_data* d = (struct tsig_openssl_data*)data;
473b24e79eSsthen 	EVP_MAC_free(d->mac);
483b24e79eSsthen 	d->mac = NULL;
493b24e79eSsthen }
503b24e79eSsthen #endif
513b24e79eSsthen 
5262ac0c33Sjakob static int
tsig_openssl_init_algorithm(region_type * region,const char * digest,const char * name,const char * wireformat)5362ac0c33Sjakob tsig_openssl_init_algorithm(region_type* region,
5462ac0c33Sjakob 	const char* digest, const char* name, const char* wireformat)
5562ac0c33Sjakob {
5662ac0c33Sjakob 	tsig_algorithm_type* algorithm;
573b24e79eSsthen #ifndef HAVE_EVP_MAC_CTX_NEW
5862ac0c33Sjakob 	const EVP_MD *hmac_algorithm;
5962ac0c33Sjakob 
6062ac0c33Sjakob 	hmac_algorithm = EVP_get_digestbyname(digest);
6162ac0c33Sjakob 	if (!hmac_algorithm) {
622c1ae072Ssthen 		/* skip but don't error */
6362ac0c33Sjakob 		return 0;
6462ac0c33Sjakob 	}
653b24e79eSsthen #else
663b24e79eSsthen 	struct tsig_openssl_data* data;
673b24e79eSsthen 	EVP_MAC_CTX* hmac_ctx;
683b24e79eSsthen 	OSSL_PARAM params[3];
693b24e79eSsthen 	data = region_alloc(region, sizeof(*data));
703b24e79eSsthen 	data->digest = digest;
713b24e79eSsthen 	data->mac = EVP_MAC_fetch(NULL, "hmac", NULL);
723b24e79eSsthen 	if(!data->mac) {
733b24e79eSsthen 		log_msg(LOG_ERR, "could not fetch MAC implementation 'hmac' with EVP_MAC_fetch");
743b24e79eSsthen 		return 0;
753b24e79eSsthen 	}
763b24e79eSsthen 	/* this context is created to see what size the output is */
773b24e79eSsthen 	hmac_ctx = EVP_MAC_CTX_new(data->mac);
783b24e79eSsthen 	if(!hmac_ctx) {
793b24e79eSsthen 		EVP_MAC_free(data->mac);
803b24e79eSsthen 		return 0;
813b24e79eSsthen 	}
823b24e79eSsthen 	params[0] = OSSL_PARAM_construct_utf8_string(OSSL_MAC_PARAM_DIGEST,
833b24e79eSsthen 		(char*)digest, 0);
843b24e79eSsthen 	params[1] = OSSL_PARAM_construct_octet_string(OSSL_MAC_PARAM_KEY,
853b24e79eSsthen 		"", 1);
863b24e79eSsthen 	params[2] = OSSL_PARAM_construct_end();
873b24e79eSsthen #ifdef HAVE_EVP_MAC_CTX_SET_PARAMS
883b24e79eSsthen 	if(EVP_MAC_CTX_set_params(hmac_ctx, params) <= 0) {
893b24e79eSsthen 		log_msg(LOG_ERR, "could not EVP_MAC_CTX_set_params");
903b24e79eSsthen 		EVP_MAC_CTX_free(hmac_ctx);
913b24e79eSsthen 		EVP_MAC_free(data->mac);
923b24e79eSsthen 		return 0;
933b24e79eSsthen 	}
943b24e79eSsthen #else
953b24e79eSsthen 	if(EVP_MAC_set_ctx_params(hmac_ctx, params) <= 0) {
963b24e79eSsthen 		log_msg(LOG_ERR, "could not EVP_MAC_set_ctx_params");
973b24e79eSsthen 		EVP_MAC_CTX_free(hmac_ctx);
983b24e79eSsthen 		EVP_MAC_free(data->mac);
993b24e79eSsthen 		return 0;
1003b24e79eSsthen 	}
1013b24e79eSsthen #endif
1023b24e79eSsthen #endif
10362ac0c33Sjakob 
10462ac0c33Sjakob 	algorithm = (tsig_algorithm_type *) region_alloc(
10562ac0c33Sjakob 		region, sizeof(tsig_algorithm_type));
10662ac0c33Sjakob 	algorithm->short_name = name;
10762ac0c33Sjakob 	algorithm->wireformat_name
10862ac0c33Sjakob 		= dname_parse(region, wireformat);
10962ac0c33Sjakob 	if (!algorithm->wireformat_name) {
11062ac0c33Sjakob 		log_msg(LOG_ERR, "cannot parse %s algorithm", wireformat);
1113b24e79eSsthen #ifdef HAVE_EVP_MAC_CTX_NEW
1123b24e79eSsthen 		EVP_MAC_CTX_free(hmac_ctx);
1133b24e79eSsthen 		EVP_MAC_free(data->mac);
1143b24e79eSsthen #endif
11562ac0c33Sjakob 		return 0;
11662ac0c33Sjakob 	}
117*a904e103Sflorian #ifdef HAVE_EVP_MAC_CTX_GET_MAC_SIZE
118*a904e103Sflorian 	algorithm->maximum_digest_size = EVP_MAC_CTX_get_mac_size(hmac_ctx);
119*a904e103Sflorian #elif !defined(HAVE_EVP_MAC_CTX_NEW)
1203126abd5Ssthen 	algorithm->maximum_digest_size = EVP_MD_size(hmac_algorithm);
1213b24e79eSsthen #else
1223b24e79eSsthen 	algorithm->maximum_digest_size = EVP_MAC_size(hmac_ctx);
1233b24e79eSsthen #endif
1243126abd5Ssthen 	if(algorithm->maximum_digest_size < 20)
12562ac0c33Sjakob 		algorithm->maximum_digest_size = EVP_MAX_MD_SIZE;
1263b24e79eSsthen #ifndef HAVE_EVP_MAC_CTX_NEW
12762ac0c33Sjakob 	algorithm->data = hmac_algorithm;
1283b24e79eSsthen #else
1293b24e79eSsthen 	algorithm->data = data;
1303b24e79eSsthen 	region_add_cleanup(region, cleanup_tsig_openssl_data, data);
1313b24e79eSsthen #endif
13262ac0c33Sjakob 	algorithm->hmac_create_context = create_context;
13362ac0c33Sjakob 	algorithm->hmac_init_context = init_context;
13462ac0c33Sjakob 	algorithm->hmac_update = update;
13562ac0c33Sjakob 	algorithm->hmac_final = final;
13662ac0c33Sjakob 	tsig_add_algorithm(algorithm);
13762ac0c33Sjakob 
1383b24e79eSsthen #ifdef HAVE_EVP_MAC_CTX_NEW
1393b24e79eSsthen 	EVP_MAC_CTX_free(hmac_ctx);
1403b24e79eSsthen #endif
14162ac0c33Sjakob 	return 1;
14262ac0c33Sjakob }
14362ac0c33Sjakob 
14462ac0c33Sjakob int
tsig_openssl_init(region_type * region)14562ac0c33Sjakob tsig_openssl_init(region_type *region)
14662ac0c33Sjakob {
1472c1ae072Ssthen 	int count = 0;
148c1e73312Sflorian #if OPENSSL_VERSION_NUMBER < 0x10100000 || !defined(HAVE_OPENSSL_INIT_CRYPTO)
14962ac0c33Sjakob 	OpenSSL_add_all_digests();
150c1e73312Sflorian #else
151c1e73312Sflorian 	OPENSSL_init_crypto(OPENSSL_INIT_ADD_ALL_DIGESTS, NULL);
152c1e73312Sflorian #endif
15362ac0c33Sjakob 
154c939baa4Ssthen 	count += tsig_openssl_init_algorithm(region,
155c939baa4Ssthen 	    "md5", "hmac-md5","hmac-md5.sig-alg.reg.int.");
156c939baa4Ssthen 	count += tsig_openssl_init_algorithm(region,
157c939baa4Ssthen 	    "sha1", "hmac-sha1", "hmac-sha1.");
158c939baa4Ssthen 	count += tsig_openssl_init_algorithm(region,
159c939baa4Ssthen 	    "sha224", "hmac-sha224", "hmac-sha224.");
160c939baa4Ssthen 	count += tsig_openssl_init_algorithm(region,
161c939baa4Ssthen 	    "sha256", "hmac-sha256", "hmac-sha256.");
162c939baa4Ssthen 	count += tsig_openssl_init_algorithm(region,
163c939baa4Ssthen 	    "sha384", "hmac-sha384", "hmac-sha384.");
164c939baa4Ssthen 	count += tsig_openssl_init_algorithm(region,
165c939baa4Ssthen 	    "sha512", "hmac-sha512", "hmac-sha512.");
16662ac0c33Sjakob 
1672c1ae072Ssthen 	return count;
16862ac0c33Sjakob }
16962ac0c33Sjakob 
17062ac0c33Sjakob static void
cleanup_context(void * data)17162ac0c33Sjakob cleanup_context(void *data)
17262ac0c33Sjakob {
1733b24e79eSsthen #ifndef HAVE_EVP_MAC_CTX_NEW
17462ac0c33Sjakob 	HMAC_CTX *context = (HMAC_CTX *) data;
175275a8d89Sflorian #ifdef HAVE_HMAC_CTX_NEW
176275a8d89Sflorian 	HMAC_CTX_free(context);
177275a8d89Sflorian #else
17862ac0c33Sjakob 	HMAC_CTX_cleanup(context);
179275a8d89Sflorian 	free(context);
180275a8d89Sflorian #endif
1813b24e79eSsthen #else
1823b24e79eSsthen 	struct tsig_openssl_context* c = (struct tsig_openssl_context*)data;
1833b24e79eSsthen 	EVP_MAC_CTX_free(c->hmac_ctx);
1843b24e79eSsthen 	c->hmac_ctx = NULL;
1853b24e79eSsthen #endif
18662ac0c33Sjakob }
18762ac0c33Sjakob 
18862ac0c33Sjakob static void *
create_context(region_type * region)18962ac0c33Sjakob create_context(region_type *region)
19062ac0c33Sjakob {
1913b24e79eSsthen #ifndef HAVE_EVP_MAC_CTX_NEW
192275a8d89Sflorian #ifdef HAVE_HMAC_CTX_NEW
193275a8d89Sflorian 	HMAC_CTX *context = HMAC_CTX_new();
194275a8d89Sflorian #else
195275a8d89Sflorian 	HMAC_CTX *context = (HMAC_CTX *) malloc(sizeof(HMAC_CTX));
196275a8d89Sflorian #endif
19762ac0c33Sjakob 	region_add_cleanup(region, cleanup_context, context);
198275a8d89Sflorian #ifdef HAVE_HMAC_CTX_RESET
199275a8d89Sflorian 	HMAC_CTX_reset(context);
200275a8d89Sflorian #else
20162ac0c33Sjakob 	HMAC_CTX_init(context);
202275a8d89Sflorian #endif
2033b24e79eSsthen #else
2043b24e79eSsthen 	struct tsig_openssl_context* context = region_alloc(region,
2053b24e79eSsthen 		sizeof(*context));
2063b24e79eSsthen 	memset(context, 0, sizeof(*context));
2073b24e79eSsthen 	region_add_cleanup(region, cleanup_context, context);
2083b24e79eSsthen #endif
20962ac0c33Sjakob 	return context;
21062ac0c33Sjakob }
21162ac0c33Sjakob 
21262ac0c33Sjakob static void
init_context(void * context,tsig_algorithm_type * algorithm,tsig_key_type * key)21362ac0c33Sjakob init_context(void *context,
21462ac0c33Sjakob 			  tsig_algorithm_type *algorithm,
21562ac0c33Sjakob 			  tsig_key_type *key)
21662ac0c33Sjakob {
2173b24e79eSsthen #ifndef HAVE_EVP_MAC_CTX_NEW
21862ac0c33Sjakob 	HMAC_CTX *ctx = (HMAC_CTX *) context;
21962ac0c33Sjakob 	const EVP_MD *md = (const EVP_MD *) algorithm->data;
22062ac0c33Sjakob 	HMAC_Init_ex(ctx, key->data, key->size, md, NULL);
2213b24e79eSsthen #else
2223b24e79eSsthen 	OSSL_PARAM params[3];
2233b24e79eSsthen 	struct tsig_openssl_data* algo_data = (struct tsig_openssl_data*)
2243b24e79eSsthen 		algorithm->data;
2253b24e79eSsthen 	struct tsig_openssl_context* c = (struct tsig_openssl_context*)context;
2263b24e79eSsthen 	if(c->hmac_ctx) {
2273b24e79eSsthen 		EVP_MAC_CTX_free(c->hmac_ctx);
2283b24e79eSsthen 	}
2293b24e79eSsthen 	c->hmac_ctx = EVP_MAC_CTX_new(algo_data->mac);
2303b24e79eSsthen 	if(!c->hmac_ctx) {
2313b24e79eSsthen 		log_msg(LOG_ERR, "could not EVP_MAC_CTX_new");
2323b24e79eSsthen 		return;
2333b24e79eSsthen 	}
2343b24e79eSsthen 	params[0] = OSSL_PARAM_construct_utf8_string(OSSL_MAC_PARAM_DIGEST,
2353b24e79eSsthen 		(char*)algo_data->digest, 0);
2363b24e79eSsthen 	params[1] = OSSL_PARAM_construct_octet_string(OSSL_MAC_PARAM_KEY,
2373b24e79eSsthen 		key->data, key->size);
2383b24e79eSsthen 	params[2] = OSSL_PARAM_construct_end();
2393b24e79eSsthen #ifdef HAVE_EVP_MAC_CTX_SET_PARAMS
2403b24e79eSsthen 	if(EVP_MAC_CTX_set_params(c->hmac_ctx, params) <= 0) {
2413b24e79eSsthen 		log_msg(LOG_ERR, "could not EVP_MAC_CTX_set_params");
2423b24e79eSsthen 		EVP_MAC_CTX_free(c->hmac_ctx);
2433b24e79eSsthen 		c->hmac_ctx = NULL;
2443b24e79eSsthen 		return;
2453b24e79eSsthen 	}
2463b24e79eSsthen #else
2473b24e79eSsthen 	if(EVP_MAC_set_ctx_params(hmac_ctx, params) <= 0) {
2483b24e79eSsthen 		log_msg(LOG_ERR, "could not EVP_MAC_set_ctx_params");
2493b24e79eSsthen 		EVP_MAC_CTX_free(c->hmac_ctx);
2503b24e79eSsthen 		c->hmac_ctx = NULL;
2513b24e79eSsthen 		return;
2523b24e79eSsthen 	}
2533b24e79eSsthen #endif
2543b24e79eSsthen 	c->outsize = algorithm->maximum_digest_size;
2553b24e79eSsthen #endif
25662ac0c33Sjakob }
25762ac0c33Sjakob 
25862ac0c33Sjakob static void
update(void * context,const void * data,size_t size)25962ac0c33Sjakob update(void *context, const void *data, size_t size)
26062ac0c33Sjakob {
2613b24e79eSsthen #ifndef HAVE_EVP_MAC_CTX_NEW
26262ac0c33Sjakob 	HMAC_CTX *ctx = (HMAC_CTX *) context;
26362ac0c33Sjakob 	HMAC_Update(ctx, (unsigned char *) data, (int) size);
2643b24e79eSsthen #else
2653b24e79eSsthen 	struct tsig_openssl_context* c = (struct tsig_openssl_context*)context;
2663b24e79eSsthen 	if(EVP_MAC_update(c->hmac_ctx, data, size) <= 0) {
2673b24e79eSsthen 		log_msg(LOG_ERR, "could not EVP_MAC_update");
2683b24e79eSsthen 	}
2693b24e79eSsthen #endif
27062ac0c33Sjakob }
27162ac0c33Sjakob 
27262ac0c33Sjakob static void
final(void * context,uint8_t * digest,size_t * size)27362ac0c33Sjakob final(void *context, uint8_t *digest, size_t *size)
27462ac0c33Sjakob {
2753b24e79eSsthen #ifndef HAVE_EVP_MAC_CTX_NEW
27662ac0c33Sjakob 	HMAC_CTX *ctx = (HMAC_CTX *) context;
27762ac0c33Sjakob 	unsigned len = (unsigned) *size;
27862ac0c33Sjakob 	HMAC_Final(ctx, digest, &len);
27962ac0c33Sjakob 	*size = (size_t) len;
2803b24e79eSsthen #else
2813b24e79eSsthen 	struct tsig_openssl_context* c = (struct tsig_openssl_context*)context;
2823b24e79eSsthen 	if(EVP_MAC_final(c->hmac_ctx, digest, size, c->outsize) <= 0) {
2833b24e79eSsthen 		log_msg(LOG_ERR, "could not EVP_MAC_final");
2843b24e79eSsthen 	}
2853b24e79eSsthen #endif
28662ac0c33Sjakob }
28762ac0c33Sjakob 
28862ac0c33Sjakob void
tsig_openssl_finalize()28962ac0c33Sjakob tsig_openssl_finalize()
29062ac0c33Sjakob {
291c1e73312Sflorian #ifdef HAVE_EVP_CLEANUP
29262ac0c33Sjakob 	EVP_cleanup();
293c1e73312Sflorian #endif
29462ac0c33Sjakob }
29562ac0c33Sjakob 
296d65f3523Sjakob #endif /* defined(HAVE_SSL) */
297