Home | History | Annotate | Line # | Download | only in dist
      1 /*
      2  * tsig-openssl.h -- Interface to OpenSSL for TSIG support.
      3  *
      4  * Copyright (c) 2001-2006, NLnet Labs. All rights reserved.
      5  *
      6  * See LICENSE for the license.
      7  *
      8  */
      9 
     10 #include "config.h"
     11 
     12 #if defined(HAVE_SSL)
     13 
     14 #ifdef HAVE_OPENSSL_CORE_NAMES_H
     15 #include <openssl/core_names.h>
     16 #endif
     17 #include "tsig-openssl.h"
     18 #include "tsig.h"
     19 #include "util.h"
     20 
     21 static void *create_context(region_type *region);
     22 static void init_context(void *context,
     23 			 tsig_algorithm_type *algorithm,
     24 			 tsig_key_type *key);
     25 static void update(void *context, const void *data, size_t size);
     26 static void final(void *context, uint8_t *digest, size_t *size);
     27 
     28 #ifdef HAVE_EVP_MAC_CTX_NEW
     29 struct tsig_openssl_data {
     30 	/* the MAC for the algorithm, 'hmac' */
     31 	EVP_MAC* mac;
     32 	/* the digest name for creating the EVP_MAC_CTX with, 'sha256' */
     33 	const char* digest;
     34 };
     35 
     36 struct tsig_openssl_context {
     37 	/* the evp mac context, if notNULL it has algo and key set. */
     38 	EVP_MAC_CTX* hmac_ctx;
     39 	/* the size of destination buffers */
     40 	size_t outsize;
     41 };
     42 
     43 static void
     44 cleanup_tsig_openssl_data(void *data)
     45 {
     46 	struct tsig_openssl_data* d = (struct tsig_openssl_data*)data;
     47 	EVP_MAC_free(d->mac);
     48 	d->mac = NULL;
     49 }
     50 #endif
     51 
     52 static int
     53 tsig_openssl_init_algorithm(region_type* region,
     54 	const char* digest, const char* name, const char* wireformat)
     55 {
     56 	tsig_algorithm_type* algorithm;
     57 #ifndef HAVE_EVP_MAC_CTX_NEW
     58 	const EVP_MD *hmac_algorithm;
     59 
     60 	hmac_algorithm = EVP_get_digestbyname(digest);
     61 	if (!hmac_algorithm) {
     62 		/* skip but don't error */
     63 		return 0;
     64 	}
     65 #else
     66 	struct tsig_openssl_data* data;
     67 	EVP_MAC_CTX* hmac_ctx;
     68 	OSSL_PARAM params[3];
     69 	data = region_alloc(region, sizeof(*data));
     70 	data->digest = digest;
     71 	data->mac = EVP_MAC_fetch(NULL, "hmac", NULL);
     72 	if(!data->mac) {
     73 		log_msg(LOG_ERR, "could not fetch MAC implementation 'hmac' with EVP_MAC_fetch");
     74 		return 0;
     75 	}
     76 	/* this context is created to see what size the output is */
     77 	hmac_ctx = EVP_MAC_CTX_new(data->mac);
     78 	if(!hmac_ctx) {
     79 		EVP_MAC_free(data->mac);
     80 		return 0;
     81 	}
     82 	params[0] = OSSL_PARAM_construct_utf8_string(OSSL_MAC_PARAM_DIGEST,
     83 		(char*)digest, 0);
     84 	params[1] = OSSL_PARAM_construct_octet_string(OSSL_MAC_PARAM_KEY,
     85 		"", 1);
     86 	params[2] = OSSL_PARAM_construct_end();
     87 #ifdef HAVE_EVP_MAC_CTX_SET_PARAMS
     88 	if(EVP_MAC_CTX_set_params(hmac_ctx, params) <= 0) {
     89 		log_msg(LOG_ERR, "could not EVP_MAC_CTX_set_params");
     90 		EVP_MAC_CTX_free(hmac_ctx);
     91 		EVP_MAC_free(data->mac);
     92 		return 0;
     93 	}
     94 #else
     95 	if(EVP_MAC_set_ctx_params(hmac_ctx, params) <= 0) {
     96 		log_msg(LOG_ERR, "could not EVP_MAC_set_ctx_params");
     97 		EVP_MAC_CTX_free(hmac_ctx);
     98 		EVP_MAC_free(data->mac);
     99 		return 0;
    100 	}
    101 #endif
    102 #endif
    103 
    104 	algorithm = (tsig_algorithm_type *) region_alloc(
    105 		region, sizeof(tsig_algorithm_type));
    106 	algorithm->short_name = name;
    107 	algorithm->wireformat_name
    108 		= dname_parse(region, wireformat);
    109 	if (!algorithm->wireformat_name) {
    110 		log_msg(LOG_ERR, "cannot parse %s algorithm", wireformat);
    111 #ifdef HAVE_EVP_MAC_CTX_NEW
    112 		EVP_MAC_CTX_free(hmac_ctx);
    113 		EVP_MAC_free(data->mac);
    114 #endif
    115 		return 0;
    116 	}
    117 #ifdef HAVE_EVP_MAC_CTX_GET_MAC_SIZE
    118 	algorithm->maximum_digest_size = EVP_MAC_CTX_get_mac_size(hmac_ctx);
    119 #elif !defined(HAVE_EVP_MAC_CTX_NEW)
    120 	algorithm->maximum_digest_size = EVP_MD_size(hmac_algorithm);
    121 #else
    122 	algorithm->maximum_digest_size = EVP_MAC_size(hmac_ctx);
    123 #endif
    124 	if(algorithm->maximum_digest_size < 20)
    125 		algorithm->maximum_digest_size = EVP_MAX_MD_SIZE;
    126 #ifndef HAVE_EVP_MAC_CTX_NEW
    127 	algorithm->data = hmac_algorithm;
    128 #else
    129 	algorithm->data = data;
    130 	region_add_cleanup(region, cleanup_tsig_openssl_data, data);
    131 #endif
    132 	algorithm->hmac_create_context = create_context;
    133 	algorithm->hmac_init_context = init_context;
    134 	algorithm->hmac_update = update;
    135 	algorithm->hmac_final = final;
    136 	tsig_add_algorithm(algorithm);
    137 
    138 #ifdef HAVE_EVP_MAC_CTX_NEW
    139 	EVP_MAC_CTX_free(hmac_ctx);
    140 #endif
    141 	return 1;
    142 }
    143 
    144 int
    145 tsig_openssl_init(region_type *region)
    146 {
    147 	int count = 0;
    148 #if OPENSSL_VERSION_NUMBER < 0x10100000 || !defined(HAVE_OPENSSL_INIT_CRYPTO)
    149 	OpenSSL_add_all_digests();
    150 #else
    151 	OPENSSL_init_crypto(OPENSSL_INIT_ADD_ALL_DIGESTS, NULL);
    152 #endif
    153 
    154 	count += tsig_openssl_init_algorithm(region,
    155 	    "md5", "hmac-md5","hmac-md5.sig-alg.reg.int.");
    156 	count += tsig_openssl_init_algorithm(region,
    157 	    "sha1", "hmac-sha1", "hmac-sha1.");
    158 	count += tsig_openssl_init_algorithm(region,
    159 	    "sha224", "hmac-sha224", "hmac-sha224.");
    160 	count += tsig_openssl_init_algorithm(region,
    161 	    "sha256", "hmac-sha256", "hmac-sha256.");
    162 	count += tsig_openssl_init_algorithm(region,
    163 	    "sha384", "hmac-sha384", "hmac-sha384.");
    164 	count += tsig_openssl_init_algorithm(region,
    165 	    "sha512", "hmac-sha512", "hmac-sha512.");
    166 
    167 	return count;
    168 }
    169 
    170 static void
    171 cleanup_context(void *data)
    172 {
    173 #ifndef HAVE_EVP_MAC_CTX_NEW
    174 	HMAC_CTX *context = (HMAC_CTX *) data;
    175 #ifdef HAVE_HMAC_CTX_NEW
    176 	HMAC_CTX_free(context);
    177 #else
    178 	HMAC_CTX_cleanup(context);
    179 	free(context);
    180 #endif
    181 #else
    182 	struct tsig_openssl_context* c = (struct tsig_openssl_context*)data;
    183 	EVP_MAC_CTX_free(c->hmac_ctx);
    184 	c->hmac_ctx = NULL;
    185 #endif
    186 }
    187 
    188 static void *
    189 create_context(region_type *region)
    190 {
    191 #ifndef HAVE_EVP_MAC_CTX_NEW
    192 #ifdef HAVE_HMAC_CTX_NEW
    193 	HMAC_CTX *context = HMAC_CTX_new();
    194 #else
    195 	HMAC_CTX *context = (HMAC_CTX *) malloc(sizeof(HMAC_CTX));
    196 #endif
    197 	region_add_cleanup(region, cleanup_context, context);
    198 #ifdef HAVE_HMAC_CTX_RESET
    199 	HMAC_CTX_reset(context);
    200 #else
    201 	HMAC_CTX_init(context);
    202 #endif
    203 #else
    204 	struct tsig_openssl_context* context = region_alloc(region,
    205 		sizeof(*context));
    206 	memset(context, 0, sizeof(*context));
    207 	region_add_cleanup(region, cleanup_context, context);
    208 #endif
    209 	return context;
    210 }
    211 
    212 static void
    213 init_context(void *context,
    214 			  tsig_algorithm_type *algorithm,
    215 			  tsig_key_type *key)
    216 {
    217 #ifndef HAVE_EVP_MAC_CTX_NEW
    218 	HMAC_CTX *ctx = (HMAC_CTX *) context;
    219 	const EVP_MD *md = (const EVP_MD *) algorithm->data;
    220 	HMAC_Init_ex(ctx, key->data, key->size, md, NULL);
    221 #else
    222 	OSSL_PARAM params[3];
    223 	struct tsig_openssl_data* algo_data = (struct tsig_openssl_data*)
    224 		algorithm->data;
    225 	struct tsig_openssl_context* c = (struct tsig_openssl_context*)context;
    226 	if(c->hmac_ctx) {
    227 		EVP_MAC_CTX_free(c->hmac_ctx);
    228 	}
    229 	c->hmac_ctx = EVP_MAC_CTX_new(algo_data->mac);
    230 	if(!c->hmac_ctx) {
    231 		log_msg(LOG_ERR, "could not EVP_MAC_CTX_new");
    232 		return;
    233 	}
    234 	params[0] = OSSL_PARAM_construct_utf8_string(OSSL_MAC_PARAM_DIGEST,
    235 		(char*)algo_data->digest, 0);
    236 	params[1] = OSSL_PARAM_construct_octet_string(OSSL_MAC_PARAM_KEY,
    237 		key->data, key->size);
    238 	params[2] = OSSL_PARAM_construct_end();
    239 #ifdef HAVE_EVP_MAC_CTX_SET_PARAMS
    240 	if(EVP_MAC_CTX_set_params(c->hmac_ctx, params) <= 0) {
    241 		log_msg(LOG_ERR, "could not EVP_MAC_CTX_set_params");
    242 		EVP_MAC_CTX_free(c->hmac_ctx);
    243 		c->hmac_ctx = NULL;
    244 		return;
    245 	}
    246 #else
    247 	if(EVP_MAC_set_ctx_params(hmac_ctx, params) <= 0) {
    248 		log_msg(LOG_ERR, "could not EVP_MAC_set_ctx_params");
    249 		EVP_MAC_CTX_free(c->hmac_ctx);
    250 		c->hmac_ctx = NULL;
    251 		return;
    252 	}
    253 #endif
    254 	c->outsize = algorithm->maximum_digest_size;
    255 #endif
    256 }
    257 
    258 static void
    259 update(void *context, const void *data, size_t size)
    260 {
    261 #ifndef HAVE_EVP_MAC_CTX_NEW
    262 	HMAC_CTX *ctx = (HMAC_CTX *) context;
    263 	HMAC_Update(ctx, (unsigned char *) data, (int) size);
    264 #else
    265 	struct tsig_openssl_context* c = (struct tsig_openssl_context*)context;
    266 	if(EVP_MAC_update(c->hmac_ctx, data, size) <= 0) {
    267 		log_msg(LOG_ERR, "could not EVP_MAC_update");
    268 	}
    269 #endif
    270 }
    271 
    272 static void
    273 final(void *context, uint8_t *digest, size_t *size)
    274 {
    275 #ifndef HAVE_EVP_MAC_CTX_NEW
    276 	HMAC_CTX *ctx = (HMAC_CTX *) context;
    277 	unsigned len = (unsigned) *size;
    278 	HMAC_Final(ctx, digest, &len);
    279 	*size = (size_t) len;
    280 #else
    281 	struct tsig_openssl_context* c = (struct tsig_openssl_context*)context;
    282 	if(EVP_MAC_final(c->hmac_ctx, digest, size, c->outsize) <= 0) {
    283 		log_msg(LOG_ERR, "could not EVP_MAC_final");
    284 	}
    285 #endif
    286 }
    287 
    288 void
    289 tsig_openssl_finalize()
    290 {
    291 #ifdef HAVE_EVP_CLEANUP
    292 	EVP_cleanup();
    293 #endif
    294 }
    295 
    296 #endif /* defined(HAVE_SSL) */
    297