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