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