1/* $NetBSD: openssl_link.c,v 1.8 2012/12/04 23:38:42 spz Exp $ */ 2 3/* 4 * Portions Copyright (C) 2004-2012 Internet Systems Consortium, Inc. ("ISC") 5 * Portions Copyright (C) 1999-2003 Internet Software Consortium. 6 * 7 * Permission to use, copy, modify, and/or distribute this software for any 8 * purpose with or without fee is hereby granted, provided that the above 9 * copyright notice and this permission notice appear in all copies. 10 * 11 * THE SOFTWARE IS PROVIDED "AS IS" AND ISC AND NETWORK ASSOCIATES DISCLAIMS 12 * ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED 13 * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE 14 * FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 15 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 16 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR 17 * IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 18 * 19 * Portions Copyright (C) 1995-2000 by Network Associates, Inc. 20 * 21 * Permission to use, copy, modify, and/or distribute this software for any 22 * purpose with or without fee is hereby granted, provided that the above 23 * copyright notice and this permission notice appear in all copies. 24 * 25 * THE SOFTWARE IS PROVIDED "AS IS" AND ISC AND NETWORK ASSOCIATES DISCLAIMS 26 * ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED 27 * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE 28 * FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 29 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 30 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR 31 * IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 32 */ 33 34/* 35 * Principal Author: Brian Wellington 36 * Id 37 */ 38#ifdef OPENSSL 39 40#include <config.h> 41 42#include <isc/entropy.h> 43#include <isc/mem.h> 44#include <isc/mutex.h> 45#include <isc/mutexblock.h> 46#include <isc/string.h> 47#include <isc/thread.h> 48#include <isc/util.h> 49 50#include <dns/log.h> 51 52#include <dst/result.h> 53 54#include "dst_internal.h" 55#include "dst_openssl.h" 56 57#ifdef USE_ENGINE 58#include <openssl/engine.h> 59#endif 60 61static RAND_METHOD *rm = NULL; 62 63static isc_mutex_t *locks = NULL; 64static int nlocks; 65 66#ifdef USE_ENGINE 67static ENGINE *e = NULL; 68#endif 69 70static int 71entropy_get(unsigned char *buf, int num) { 72 isc_result_t result; 73 if (num < 0) 74 return (-1); 75 result = dst__entropy_getdata(buf, (unsigned int) num, ISC_FALSE); 76 return (result == ISC_R_SUCCESS ? 1 : -1); 77} 78 79static int 80entropy_status(void) { 81 return (dst__entropy_status() > 32); 82} 83 84static int 85entropy_getpseudo(unsigned char *buf, int num) { 86 isc_result_t result; 87 if (num < 0) 88 return (-1); 89 result = dst__entropy_getdata(buf, (unsigned int) num, ISC_TRUE); 90 return (result == ISC_R_SUCCESS ? 1 : -1); 91} 92 93#if OPENSSL_VERSION_NUMBER < 0x10100000L 94static void 95#else 96static int 97#endif 98entropy_add(const void *buf, int num, double entropy) { 99 /* 100 * Do nothing. The only call to this provides no useful data anyway. 101 */ 102 UNUSED(buf); 103 UNUSED(num); 104 UNUSED(entropy); 105#if OPENSSL_VERSION_NUMBER >= 0x10100000L 106 return 0; 107#endif 108} 109 110static void 111lock_callback(int mode, int type, const char *file, int line) { 112 UNUSED(file); 113 UNUSED(line); 114 if ((mode & CRYPTO_LOCK) != 0) 115 LOCK(&locks[type]); 116 else 117 UNLOCK(&locks[type]); 118} 119 120static unsigned long 121id_callback(void) { 122 return ((unsigned long)isc_thread_self()); 123} 124 125static void * 126mem_alloc(size_t size) { 127#ifdef OPENSSL_LEAKS 128 void *ptr; 129 130 INSIST(dst__memory_pool != NULL); 131 ptr = isc_mem_allocate(dst__memory_pool, size); 132 return (ptr); 133#else 134 INSIST(dst__memory_pool != NULL); 135 return (isc_mem_allocate(dst__memory_pool, size)); 136#endif 137} 138 139static void 140mem_free(void *ptr) { 141 INSIST(dst__memory_pool != NULL); 142 if (ptr != NULL) 143 isc_mem_free(dst__memory_pool, ptr); 144} 145 146static void * 147mem_realloc(void *ptr, size_t size) { 148#ifdef OPENSSL_LEAKS 149 void *rptr; 150 151 INSIST(dst__memory_pool != NULL); 152 rptr = isc_mem_reallocate(dst__memory_pool, ptr, size); 153 return (rptr); 154#else 155 INSIST(dst__memory_pool != NULL); 156 return (isc_mem_reallocate(dst__memory_pool, ptr, size)); 157#endif 158} 159 160isc_result_t 161dst__openssl_init(const char *engine) { 162 isc_result_t result; 163#ifdef USE_ENGINE 164 ENGINE *re; 165#else 166 167 UNUSED(engine); 168#endif 169 170#ifdef DNS_CRYPTO_LEAKS 171 CRYPTO_malloc_debug_init(); 172 CRYPTO_set_mem_debug_options(V_CRYPTO_MDEBUG_ALL); 173 CRYPTO_mem_ctrl(CRYPTO_MEM_CHECK_ON); 174#endif 175 CRYPTO_set_mem_functions(mem_alloc, mem_realloc, mem_free); 176 nlocks = CRYPTO_num_locks(); 177 locks = mem_alloc(sizeof(isc_mutex_t) * nlocks); 178 if (locks == NULL) 179 return (ISC_R_NOMEMORY); 180 result = isc_mutexblock_init(locks, nlocks); 181 if (result != ISC_R_SUCCESS) 182 goto cleanup_mutexalloc; 183 CRYPTO_set_locking_callback(lock_callback); 184 CRYPTO_set_id_callback(id_callback); 185 186 ERR_load_crypto_strings(); 187 188 rm = mem_alloc(sizeof(RAND_METHOD)); 189 if (rm == NULL) { 190 result = ISC_R_NOMEMORY; 191 goto cleanup_mutexinit; 192 } 193 rm->seed = NULL; 194 rm->bytes = entropy_get; 195 rm->cleanup = NULL; 196 rm->add = entropy_add; 197 rm->pseudorand = entropy_getpseudo; 198 rm->status = entropy_status; 199 200#ifdef USE_ENGINE 201 OPENSSL_config(NULL); 202 203 if (engine != NULL && *engine == '\0') 204 engine = NULL; 205 206 if (engine != NULL) { 207 e = ENGINE_by_id(engine); 208 if (e == NULL) { 209 result = DST_R_NOENGINE; 210 goto cleanup_rm; 211 } 212 /* This will init the engine. */ 213 if (!ENGINE_set_default(e, ENGINE_METHOD_ALL)) { 214 result = DST_R_NOENGINE; 215 goto cleanup_rm; 216 } 217 } 218 219 re = ENGINE_get_default_RAND(); 220 if (re == NULL) { 221 re = ENGINE_new(); 222 if (re == NULL) { 223 result = ISC_R_NOMEMORY; 224 goto cleanup_rm; 225 } 226 ENGINE_set_RAND(re, rm); 227 ENGINE_set_default_RAND(re); 228 ENGINE_free(re); 229 } else 230 ENGINE_finish(re); 231#else 232 RAND_set_rand_method(rm); 233#endif /* USE_ENGINE */ 234 return (ISC_R_SUCCESS); 235 236#ifdef USE_ENGINE 237 cleanup_rm: 238 if (e != NULL) 239 ENGINE_free(e); 240 e = NULL; 241 mem_free(rm); 242 rm = NULL; 243#endif 244 cleanup_mutexinit: 245 CRYPTO_set_locking_callback(NULL); 246 DESTROYMUTEXBLOCK(locks, nlocks); 247 cleanup_mutexalloc: 248 mem_free(locks); 249 locks = NULL; 250 return (result); 251} 252 253void 254dst__openssl_destroy() { 255 256 /* 257 * Sequence taken from apps_shutdown() in <apps/apps.h>. 258 */ 259 if (rm != NULL) { 260#if OPENSSL_VERSION_NUMBER >= 0x00907000L 261 RAND_cleanup(); 262#endif 263 mem_free(rm); 264 rm = NULL; 265 } 266#if (OPENSSL_VERSION_NUMBER >= 0x00907000L) 267 CONF_modules_free(); 268#endif 269 OBJ_cleanup(); 270 EVP_cleanup(); 271#if defined(USE_ENGINE) 272 if (e != NULL) 273 ENGINE_free(e); 274 e = NULL; 275#if defined(USE_ENGINE) && OPENSSL_VERSION_NUMBER >= 0x00907000L 276 ENGINE_cleanup(); 277#endif 278#endif 279#if (OPENSSL_VERSION_NUMBER >= 0x00907000L) 280 CRYPTO_cleanup_all_ex_data(); 281#endif 282 ERR_clear_error(); 283 ERR_remove_state(0); 284 ERR_free_strings(); 285 286#ifdef DNS_CRYPTO_LEAKS 287 CRYPTO_mem_leaks_fp(stderr); 288#endif 289 290 if (locks != NULL) { 291 CRYPTO_set_locking_callback(NULL); 292 DESTROYMUTEXBLOCK(locks, nlocks); 293 mem_free(locks); 294 locks = NULL; 295 } 296} 297 298isc_result_t 299dst__openssl_toresult(isc_result_t fallback) { 300 isc_result_t result = fallback; 301 unsigned long err = ERR_get_error(); 302 303 switch (ERR_GET_REASON(err)) { 304 case ERR_R_MALLOC_FAILURE: 305 result = ISC_R_NOMEMORY; 306 break; 307 default: 308 break; 309 } 310 ERR_clear_error(); 311 return (result); 312} 313 314isc_result_t 315dst__openssl_toresult2(const char *funcname, isc_result_t fallback) { 316 isc_result_t result = fallback; 317 unsigned long err = ERR_peek_error(); 318 const char *file, *data; 319 int line, flags; 320 char buf[256]; 321 322 switch (ERR_GET_REASON(err)) { 323 case ERR_R_MALLOC_FAILURE: 324 result = ISC_R_NOMEMORY; 325 goto done; 326 default: 327 break; 328 } 329 isc_log_write(dns_lctx, DNS_LOGCATEGORY_GENERAL, 330 DNS_LOGMODULE_CRYPTO, ISC_LOG_WARNING, 331 "%s failed", funcname); 332 for (;;) { 333 err = ERR_get_error_line_data(&file, &line, &data, &flags); 334 if (err == 0U) 335 goto done; 336 ERR_error_string_n(err, buf, sizeof(buf)); 337 isc_log_write(dns_lctx, DNS_LOGCATEGORY_GENERAL, 338 DNS_LOGMODULE_CRYPTO, ISC_LOG_INFO, 339 "%s:%s:%d:%s", buf, file, line, 340 (flags & ERR_TXT_STRING) ? data : ""); 341 } 342 343 done: 344 ERR_clear_error(); 345 return (result); 346} 347 348#if defined(USE_ENGINE) 349ENGINE * 350dst__openssl_getengine(const char *engine) { 351 352 if (engine == NULL) 353 return (NULL); 354 if (e == NULL) 355 return (NULL); 356 if (strcmp(engine, ENGINE_get_id(e)) == 0) 357 return (e); 358 return (NULL); 359} 360#endif 361 362#else /* OPENSSL */ 363 364#include <isc/util.h> 365 366EMPTY_TRANSLATION_UNIT 367 368#endif /* OPENSSL */ 369/*! \file */ 370