openssl_link.c 8.02 KB
Newer Older
1
/*
Tinderbox User's avatar
Tinderbox User committed
2
 * Portions Copyright (C) 2004-2012  Internet Systems Consortium, Inc. ("ISC")
Mark Andrews's avatar
Mark Andrews committed
3
 * Portions Copyright (C) 1999-2003  Internet Software Consortium.
Automatic Updater's avatar
Automatic Updater committed
4 5 6 7 8 9 10 11 12 13 14 15 16
 *
 * Permission to use, copy, modify, and/or distribute this software for any
 * purpose with or without fee is hereby granted, provided that the above
 * copyright notice and this permission notice appear in all copies.
 *
 * THE SOFTWARE IS PROVIDED "AS IS" AND ISC AND NETWORK ASSOCIATES DISCLAIMS
 * ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
 * WARRANTIES OF MERCHANTABILITY AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE
 * FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR
 * IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 *
17
 * Portions Copyright (C) 1995-2000 by Network Associates, Inc.
18
 *
Automatic Updater's avatar
Automatic Updater committed
19
 * Permission to use, copy, modify, and/or distribute this software for any
20 21
 * purpose with or without fee is hereby granted, provided that the above
 * copyright notice and this permission notice appear in all copies.
22
 *
Mark Andrews's avatar
Mark Andrews committed
23 24 25 26 27 28 29
 * THE SOFTWARE IS PROVIDED "AS IS" AND ISC AND NETWORK ASSOCIATES DISCLAIMS
 * ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
 * WARRANTIES OF MERCHANTABILITY AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE
 * FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR
 * IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
30 31 32 33
 */

/*
 * Principal Author: Brian Wellington
Mark Andrews's avatar
Mark Andrews committed
34
 * $Id$
35
 */
36
#ifdef OPENSSL
37 38 39

#include <config.h>

Brian Wellington's avatar
Brian Wellington committed
40
#include <isc/entropy.h>
41
#include <isc/mem.h>
42 43
#include <isc/mutex.h>
#include <isc/mutexblock.h>
44
#include <isc/string.h>
45
#include <isc/thread.h>
Bob Halley's avatar
Bob Halley committed
46
#include <isc/util.h>
47

48 49
#include <dns/log.h>

Francis Dupont's avatar
Francis Dupont committed
50 51
#include <dst/result.h>

52
#include "dst_internal.h"
53
#include "dst_openssl.h"
54

55
#ifdef USE_ENGINE
56 57
#include <openssl/engine.h>
#endif
58

59
static RAND_METHOD *rm = NULL;
60

61 62
static isc_mutex_t *locks = NULL;
static int nlocks;
63

64
#ifdef USE_ENGINE
Francis Dupont's avatar
Francis Dupont committed
65
static ENGINE *e = NULL;
66 67
#endif

Brian Wellington's avatar
Brian Wellington committed
68 69 70 71 72
static int
entropy_get(unsigned char *buf, int num) {
	isc_result_t result;
	if (num < 0)
		return (-1);
73
	result = dst__entropy_getdata(buf, (unsigned int) num, ISC_FALSE);
74
	return (result == ISC_R_SUCCESS ? 1 : -1);
75 76
}

77 78 79 80 81
static int
entropy_status(void) {
	return (dst__entropy_status() > 32);
}

82 83 84 85 86 87
static int
entropy_getpseudo(unsigned char *buf, int num) {
	isc_result_t result;
	if (num < 0)
		return (-1);
	result = dst__entropy_getdata(buf, (unsigned int) num, ISC_TRUE);
88
	return (result == ISC_R_SUCCESS ? 1 : -1);
Brian Wellington's avatar
Brian Wellington committed
89 90 91 92 93 94 95 96 97 98 99 100
}

static void
entropy_add(const void *buf, int num, double entropy) {
	/*
	 * Do nothing.  The only call to this provides no useful data anyway.
	 */
	UNUSED(buf);
	UNUSED(num);
	UNUSED(entropy);
}

101 102
static void
lock_callback(int mode, int type, const char *file, int line) {
103 104
	UNUSED(file);
	UNUSED(line);
105 106 107 108 109 110 111 112 113 114 115
	if ((mode & CRYPTO_LOCK) != 0)
		LOCK(&locks[type]);
	else
		UNLOCK(&locks[type]);
}

static unsigned long
id_callback(void) {
	return ((unsigned long)isc_thread_self());
}

116 117
static void *
mem_alloc(size_t size) {
Francis Dupont's avatar
Francis Dupont committed
118 119 120 121 122 123 124
#ifdef OPENSSL_LEAKS
	void *ptr;

	INSIST(dst__memory_pool != NULL);
	ptr = isc_mem_allocate(dst__memory_pool, size);
	return (ptr);
#else
Mark Andrews's avatar
Mark Andrews committed
125 126
	INSIST(dst__memory_pool != NULL);
	return (isc_mem_allocate(dst__memory_pool, size));
Francis Dupont's avatar
Francis Dupont committed
127
#endif
128 129 130 131
}

static void
mem_free(void *ptr) {
Mark Andrews's avatar
Mark Andrews committed
132
	INSIST(dst__memory_pool != NULL);
133
	if (ptr != NULL)
Mark Andrews's avatar
Mark Andrews committed
134
		isc_mem_free(dst__memory_pool, ptr);
135 136 137 138
}

static void *
mem_realloc(void *ptr, size_t size) {
Francis Dupont's avatar
Francis Dupont committed
139 140 141 142 143 144 145
#ifdef OPENSSL_LEAKS
	void *rptr;

	INSIST(dst__memory_pool != NULL);
	rptr = isc_mem_reallocate(dst__memory_pool, ptr, size);
	return (rptr);
#else
Mark Andrews's avatar
Mark Andrews committed
146
	INSIST(dst__memory_pool != NULL);
147
	return (isc_mem_reallocate(dst__memory_pool, ptr, size));
Francis Dupont's avatar
Francis Dupont committed
148
#endif
149 150
}

Brian Wellington's avatar
Brian Wellington committed
151
isc_result_t
Francis Dupont's avatar
Francis Dupont committed
152
dst__openssl_init(const char *engine) {
153
	isc_result_t result;
Francis Dupont's avatar
Francis Dupont committed
154 155
#ifdef USE_ENGINE
	ENGINE *re;
Francis Dupont's avatar
Francis Dupont committed
156 157 158
#else

	UNUSED(engine);
Francis Dupont's avatar
Francis Dupont committed
159
#endif
160

161 162 163 164 165
#ifdef  DNS_CRYPTO_LEAKS
	CRYPTO_malloc_debug_init();
	CRYPTO_set_mem_debug_options(V_CRYPTO_MDEBUG_ALL);
	CRYPTO_mem_ctrl(CRYPTO_MEM_CHECK_ON);
#endif
166
	CRYPTO_set_mem_functions(mem_alloc, mem_realloc, mem_free);
167
	nlocks = CRYPTO_num_locks();
168
	locks = mem_alloc(sizeof(isc_mutex_t) * nlocks);
169 170 171
	if (locks == NULL)
		return (ISC_R_NOMEMORY);
	result = isc_mutexblock_init(locks, nlocks);
172 173
	if (result != ISC_R_SUCCESS)
		goto cleanup_mutexalloc;
174 175
	CRYPTO_set_locking_callback(lock_callback);
	CRYPTO_set_id_callback(id_callback);
176

177 178
	ERR_load_crypto_strings();

179
	rm = mem_alloc(sizeof(RAND_METHOD));
180 181 182 183
	if (rm == NULL) {
		result = ISC_R_NOMEMORY;
		goto cleanup_mutexinit;
	}
184 185 186 187 188
	rm->seed = NULL;
	rm->bytes = entropy_get;
	rm->cleanup = NULL;
	rm->add = entropy_add;
	rm->pseudorand = entropy_getpseudo;
189
	rm->status = entropy_status;
Francis Dupont's avatar
Francis Dupont committed
190

191
#ifdef USE_ENGINE
Francis Dupont's avatar
Francis Dupont committed
192
	OPENSSL_config(NULL);
Francis Dupont's avatar
Francis Dupont committed
193 194 195 196 197 198

	if (engine != NULL && *engine == '\0')
		engine = NULL;

	if (engine != NULL) {
		e = ENGINE_by_id(engine);
Francis Dupont's avatar
Francis Dupont committed
199
		if (e == NULL) {
Francis Dupont's avatar
Francis Dupont committed
200
			result = DST_R_NOENGINE;
Francis Dupont's avatar
Francis Dupont committed
201 202
			goto cleanup_rm;
		}
Francis Dupont's avatar
Francis Dupont committed
203 204 205
		/* This will init the engine. */
		if (!ENGINE_set_default(e, ENGINE_METHOD_ALL)) {
			result = DST_R_NOENGINE;
Francis Dupont's avatar
Francis Dupont committed
206 207 208
			goto cleanup_rm;
		}
	}
Francis Dupont's avatar
Francis Dupont committed
209

Francis Dupont's avatar
Francis Dupont committed
210 211 212 213 214 215 216 217 218 219 220 221
	re = ENGINE_get_default_RAND();
	if (re == NULL) {
		re = ENGINE_new();
		if (re == NULL) {
			result = ISC_R_NOMEMORY;
			goto cleanup_rm;
		}
		ENGINE_set_RAND(re, rm);
		ENGINE_set_default_RAND(re);
		ENGINE_free(re);
	} else
		ENGINE_finish(re);
222
#else
223
	RAND_set_rand_method(rm);
224
#endif /* USE_ENGINE */
Brian Wellington's avatar
Brian Wellington committed
225
	return (ISC_R_SUCCESS);
226

227
#ifdef USE_ENGINE
228
 cleanup_rm:
Francis Dupont's avatar
Francis Dupont committed
229 230 231
	if (e != NULL)
		ENGINE_free(e);
	e = NULL;
232
	mem_free(rm);
Francis Dupont's avatar
Francis Dupont committed
233
	rm = NULL;
234 235
#endif
 cleanup_mutexinit:
236
	CRYPTO_set_locking_callback(NULL);
237
	DESTROYMUTEXBLOCK(locks, nlocks);
238
 cleanup_mutexalloc:
239
	mem_free(locks);
Francis Dupont's avatar
Francis Dupont committed
240
	locks = NULL;
241
	return (result);
Brian Wellington's avatar
Brian Wellington committed
242 243
}

244
void
Mark Andrews's avatar
Mark Andrews committed
245
dst__openssl_destroy() {
246 247 248 249

	/*
	 * Sequence taken from apps_shutdown() in <apps/apps.h>.
	 */
Francis Dupont's avatar
Francis Dupont committed
250 251 252 253 254 255 256
	if (rm != NULL) {
#if OPENSSL_VERSION_NUMBER >= 0x00907000L
		RAND_cleanup();
#endif
		mem_free(rm);
		rm = NULL;
	}
257
#if (OPENSSL_VERSION_NUMBER >= 0x00907000L)
Francis Dupont's avatar
Francis Dupont committed
258
	CONF_modules_free();
259
#endif
Francis Dupont's avatar
Francis Dupont committed
260
	OBJ_cleanup();
261
	EVP_cleanup();
Francis Dupont's avatar
Francis Dupont committed
262
#if defined(USE_ENGINE)
Francis Dupont's avatar
Francis Dupont committed
263 264 265
	if (e != NULL)
		ENGINE_free(e);
	e = NULL;
266
#if defined(USE_ENGINE) && OPENSSL_VERSION_NUMBER >= 0x00907000L
267 268
	ENGINE_cleanup();
#endif
Francis Dupont's avatar
Francis Dupont committed
269
#endif
270
#if (OPENSSL_VERSION_NUMBER >= 0x00907000L)
271
	CRYPTO_cleanup_all_ex_data();
272
#endif
273 274
	ERR_clear_error();
	ERR_remove_state(0);
Francis Dupont's avatar
Francis Dupont committed
275
	ERR_free_strings();
276 277 278 279 280

#ifdef  DNS_CRYPTO_LEAKS
	CRYPTO_mem_leaks_fp(stderr);
#endif

281 282 283 284
	if (locks != NULL) {
		CRYPTO_set_locking_callback(NULL);
		DESTROYMUTEXBLOCK(locks, nlocks);
		mem_free(locks);
Francis Dupont's avatar
Francis Dupont committed
285
		locks = NULL;
286
	}
287 288
}

289 290 291
isc_result_t
dst__openssl_toresult(isc_result_t fallback) {
	isc_result_t result = fallback;
292
	unsigned long err = ERR_get_error();
293 294 295 296 297 298 299 300 301 302 303 304

	switch (ERR_GET_REASON(err)) {
	case ERR_R_MALLOC_FAILURE:
		result = ISC_R_NOMEMORY;
		break;
	default:
		break;
	}
	ERR_clear_error();
	return (result);
}

305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338
isc_result_t
dst__openssl_toresult2(const char *funcname, isc_result_t fallback) {
	isc_result_t result = fallback;
	unsigned long err = ERR_peek_error();
	const char *file, *data;
	int line, flags;
	char buf[256];

	switch (ERR_GET_REASON(err)) {
	case ERR_R_MALLOC_FAILURE:
		result = ISC_R_NOMEMORY;
		goto done;
	default:
		break;
	}
	isc_log_write(dns_lctx, DNS_LOGCATEGORY_GENERAL,
		      DNS_LOGMODULE_CRYPTO, ISC_LOG_WARNING,
		      "%s failed", funcname);
	for (;;) {
		err = ERR_get_error_line_data(&file, &line, &data, &flags);
		if (err == 0)
			goto done;
		ERR_error_string_n(err, buf, sizeof(buf));
		isc_log_write(dns_lctx, DNS_LOGCATEGORY_GENERAL,
			      DNS_LOGMODULE_CRYPTO, ISC_LOG_INFO,
			      "%s:%s:%d:%s", buf, file, line,
			      (flags & ERR_TXT_STRING) ? data : "");
	}

    done:
	ERR_clear_error();
	return (result);
}

339
#if defined(USE_ENGINE)
Francis Dupont's avatar
Francis Dupont committed
340
ENGINE *
Francis Dupont's avatar
Francis Dupont committed
341
dst__openssl_getengine(const char *engine) {
Francis Dupont's avatar
Francis Dupont committed
342

Francis Dupont's avatar
Francis Dupont committed
343 344
	if (engine == NULL)
		return (NULL);
Francis Dupont's avatar
Francis Dupont committed
345
	if (e == NULL)
Francis Dupont's avatar
Francis Dupont committed
346 347 348 349
		return (NULL);
	if (strcmp(engine, ENGINE_get_id(e)) == 0)
		return (e);
	return (NULL);
Francis Dupont's avatar
Francis Dupont committed
350
}
351
#endif
Francis Dupont's avatar
Francis Dupont committed
352

353 354 355 356
#else /* OPENSSL */

#include <isc/util.h>

Mark Andrews's avatar
Mark Andrews committed
357
EMPTY_TRANSLATION_UNIT
358

359
#endif /* OPENSSL */
360
/*! \file */