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