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 #ifndef HAVE_EVP_MAC_CTX_NEW 118 algorithm->maximum_digest_size = EVP_MD_size(hmac_algorithm); 119 #else 120 algorithm->maximum_digest_size = EVP_MAC_size(hmac_ctx); 121 #endif 122 if(algorithm->maximum_digest_size < 20) 123 algorithm->maximum_digest_size = EVP_MAX_MD_SIZE; 124 #ifndef HAVE_EVP_MAC_CTX_NEW 125 algorithm->data = hmac_algorithm; 126 #else 127 algorithm->data = data; 128 region_add_cleanup(region, cleanup_tsig_openssl_data, data); 129 #endif 130 algorithm->hmac_create_context = create_context; 131 algorithm->hmac_init_context = init_context; 132 algorithm->hmac_update = update; 133 algorithm->hmac_final = final; 134 tsig_add_algorithm(algorithm); 135 136 #ifdef HAVE_EVP_MAC_CTX_NEW 137 EVP_MAC_CTX_free(hmac_ctx); 138 #endif 139 return 1; 140 } 141 142 int 143 tsig_openssl_init(region_type *region) 144 { 145 int count = 0; 146 #if OPENSSL_VERSION_NUMBER < 0x10100000 || !defined(HAVE_OPENSSL_INIT_CRYPTO) 147 OpenSSL_add_all_digests(); 148 #else 149 OPENSSL_init_crypto(OPENSSL_INIT_ADD_ALL_DIGESTS, NULL); 150 #endif 151 152 count += tsig_openssl_init_algorithm(region, 153 "md5", "hmac-md5","hmac-md5.sig-alg.reg.int."); 154 count += tsig_openssl_init_algorithm(region, 155 "sha1", "hmac-sha1", "hmac-sha1."); 156 count += tsig_openssl_init_algorithm(region, 157 "sha224", "hmac-sha224", "hmac-sha224."); 158 count += tsig_openssl_init_algorithm(region, 159 "sha256", "hmac-sha256", "hmac-sha256."); 160 count += tsig_openssl_init_algorithm(region, 161 "sha384", "hmac-sha384", "hmac-sha384."); 162 count += tsig_openssl_init_algorithm(region, 163 "sha512", "hmac-sha512", "hmac-sha512."); 164 165 return count; 166 } 167 168 static void 169 cleanup_context(void *data) 170 { 171 #ifndef HAVE_EVP_MAC_CTX_NEW 172 HMAC_CTX *context = (HMAC_CTX *) data; 173 #ifdef HAVE_HMAC_CTX_NEW 174 HMAC_CTX_free(context); 175 #else 176 HMAC_CTX_cleanup(context); 177 free(context); 178 #endif 179 #else 180 struct tsig_openssl_context* c = (struct tsig_openssl_context*)data; 181 EVP_MAC_CTX_free(c->hmac_ctx); 182 c->hmac_ctx = NULL; 183 #endif 184 } 185 186 static void * 187 create_context(region_type *region) 188 { 189 #ifndef HAVE_EVP_MAC_CTX_NEW 190 #ifdef HAVE_HMAC_CTX_NEW 191 HMAC_CTX *context = HMAC_CTX_new(); 192 #else 193 HMAC_CTX *context = (HMAC_CTX *) malloc(sizeof(HMAC_CTX)); 194 #endif 195 region_add_cleanup(region, cleanup_context, context); 196 #ifdef HAVE_HMAC_CTX_RESET 197 HMAC_CTX_reset(context); 198 #else 199 HMAC_CTX_init(context); 200 #endif 201 #else 202 struct tsig_openssl_context* context = region_alloc(region, 203 sizeof(*context)); 204 memset(context, 0, sizeof(*context)); 205 region_add_cleanup(region, cleanup_context, context); 206 #endif 207 return context; 208 } 209 210 static void 211 init_context(void *context, 212 tsig_algorithm_type *algorithm, 213 tsig_key_type *key) 214 { 215 #ifndef HAVE_EVP_MAC_CTX_NEW 216 HMAC_CTX *ctx = (HMAC_CTX *) context; 217 const EVP_MD *md = (const EVP_MD *) algorithm->data; 218 HMAC_Init_ex(ctx, key->data, key->size, md, NULL); 219 #else 220 OSSL_PARAM params[3]; 221 struct tsig_openssl_data* algo_data = (struct tsig_openssl_data*) 222 algorithm->data; 223 struct tsig_openssl_context* c = (struct tsig_openssl_context*)context; 224 if(c->hmac_ctx) { 225 EVP_MAC_CTX_free(c->hmac_ctx); 226 } 227 c->hmac_ctx = EVP_MAC_CTX_new(algo_data->mac); 228 if(!c->hmac_ctx) { 229 log_msg(LOG_ERR, "could not EVP_MAC_CTX_new"); 230 return; 231 } 232 params[0] = OSSL_PARAM_construct_utf8_string(OSSL_MAC_PARAM_DIGEST, 233 (char*)algo_data->digest, 0); 234 params[1] = OSSL_PARAM_construct_octet_string(OSSL_MAC_PARAM_KEY, 235 key->data, key->size); 236 params[2] = OSSL_PARAM_construct_end(); 237 #ifdef HAVE_EVP_MAC_CTX_SET_PARAMS 238 if(EVP_MAC_CTX_set_params(c->hmac_ctx, params) <= 0) { 239 log_msg(LOG_ERR, "could not EVP_MAC_CTX_set_params"); 240 EVP_MAC_CTX_free(c->hmac_ctx); 241 c->hmac_ctx = NULL; 242 return; 243 } 244 #else 245 if(EVP_MAC_set_ctx_params(hmac_ctx, params) <= 0) { 246 log_msg(LOG_ERR, "could not EVP_MAC_set_ctx_params"); 247 EVP_MAC_CTX_free(c->hmac_ctx); 248 c->hmac_ctx = NULL; 249 return; 250 } 251 #endif 252 c->outsize = algorithm->maximum_digest_size; 253 #endif 254 } 255 256 static void 257 update(void *context, const void *data, size_t size) 258 { 259 #ifndef HAVE_EVP_MAC_CTX_NEW 260 HMAC_CTX *ctx = (HMAC_CTX *) context; 261 HMAC_Update(ctx, (unsigned char *) data, (int) size); 262 #else 263 struct tsig_openssl_context* c = (struct tsig_openssl_context*)context; 264 if(EVP_MAC_update(c->hmac_ctx, data, size) <= 0) { 265 log_msg(LOG_ERR, "could not EVP_MAC_update"); 266 } 267 #endif 268 } 269 270 static void 271 final(void *context, uint8_t *digest, size_t *size) 272 { 273 #ifndef HAVE_EVP_MAC_CTX_NEW 274 HMAC_CTX *ctx = (HMAC_CTX *) context; 275 unsigned len = (unsigned) *size; 276 HMAC_Final(ctx, digest, &len); 277 *size = (size_t) len; 278 #else 279 struct tsig_openssl_context* c = (struct tsig_openssl_context*)context; 280 if(EVP_MAC_final(c->hmac_ctx, digest, size, c->outsize) <= 0) { 281 log_msg(LOG_ERR, "could not EVP_MAC_final"); 282 } 283 #endif 284 } 285 286 void 287 tsig_openssl_finalize() 288 { 289 #ifdef HAVE_EVP_CLEANUP 290 EVP_cleanup(); 291 #endif 292 } 293 294 #endif /* defined(HAVE_SSL) */ 295