xref: /minix/external/bsd/bind/dist/lib/dns/openssl_link.c (revision 00b67f09)
1 /*	$NetBSD: openssl_link.c,v 1.11 2014/12/10 04:37:58 christos Exp $	*/
2 
3 /*
4  * Portions Copyright (C) 2004-2012, 2014  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 
61 static RAND_METHOD *rm = NULL;
62 
63 static isc_mutex_t *locks = NULL;
64 static int nlocks;
65 
66 #ifdef USE_ENGINE
67 static ENGINE *e = NULL;
68 #endif
69 
70 static int
entropy_get(unsigned char * buf,int num)71 entropy_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 
79 static int
entropy_status(void)80 entropy_status(void) {
81 	return (dst__entropy_status() > 32);
82 }
83 
84 static int
entropy_getpseudo(unsigned char * buf,int num)85 entropy_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
94 static void
95 #else
96 static int
97 #endif
entropy_add(const void * buf,int num,double entropy)98 entropy_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 
110 static void
lock_callback(int mode,int type,const char * file,int line)111 lock_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 
120 static unsigned long
id_callback(void)121 id_callback(void) {
122 	return ((unsigned long)isc_thread_self());
123 }
124 
125 static void *
mem_alloc(size_t size)126 mem_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 
139 static void
mem_free(void * ptr)140 mem_free(void *ptr) {
141 	INSIST(dst__memory_pool != NULL);
142 	if (ptr != NULL)
143 		isc_mem_free(dst__memory_pool, ptr);
144 }
145 
146 static void *
mem_realloc(void * ptr,size_t size)147 mem_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 
160 isc_result_t
dst__openssl_init(const char * engine)161 dst__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 
253 void
dst__openssl_destroy(void)254 dst__openssl_destroy(void) {
255 	/*
256 	 * Sequence taken from apps_shutdown() in <apps/apps.h>.
257 	 */
258 	if (rm != NULL) {
259 #if OPENSSL_VERSION_NUMBER >= 0x00907000L
260 		RAND_cleanup();
261 #endif
262 		mem_free(rm);
263 		rm = NULL;
264 	}
265 #if (OPENSSL_VERSION_NUMBER >= 0x00907000L)
266 	CONF_modules_free();
267 #endif
268 	OBJ_cleanup();
269 	EVP_cleanup();
270 #if defined(USE_ENGINE)
271 	if (e != NULL)
272 		ENGINE_free(e);
273 	e = NULL;
274 #if defined(USE_ENGINE) && OPENSSL_VERSION_NUMBER >= 0x00907000L
275 	ENGINE_cleanup();
276 #endif
277 #endif
278 #if (OPENSSL_VERSION_NUMBER >= 0x00907000L)
279 	CRYPTO_cleanup_all_ex_data();
280 #endif
281 	ERR_clear_error();
282 	ERR_remove_state(0);
283 	ERR_free_strings();
284 
285 #ifdef  DNS_CRYPTO_LEAKS
286 	CRYPTO_mem_leaks_fp(stderr);
287 #endif
288 
289 	if (locks != NULL) {
290 		CRYPTO_set_locking_callback(NULL);
291 		DESTROYMUTEXBLOCK(locks, nlocks);
292 		mem_free(locks);
293 		locks = NULL;
294 	}
295 }
296 
297 static isc_result_t
toresult(isc_result_t fallback)298 toresult(isc_result_t fallback) {
299 	isc_result_t result = fallback;
300 	unsigned long err = ERR_get_error();
301 #ifdef HAVE_OPENSSL_ECDSA
302 	int lib = ERR_GET_LIB(err);
303 #endif
304 	int reason = ERR_GET_REASON(err);
305 
306 	switch (reason) {
307 	/*
308 	 * ERR_* errors are globally unique; others
309 	 * are unique per sublibrary
310 	 */
311 	case ERR_R_MALLOC_FAILURE:
312 		result = ISC_R_NOMEMORY;
313 		break;
314 	default:
315 #ifdef HAVE_OPENSSL_ECDSA
316 		if (lib == ERR_R_ECDSA_LIB &&
317 		    reason == ECDSA_R_RANDOM_NUMBER_GENERATION_FAILED) {
318 			result = ISC_R_NOENTROPY;
319 			break;
320 		}
321 #endif
322 		break;
323 	}
324 
325 	return (result);
326 }
327 
328 isc_result_t
dst__openssl_toresult(isc_result_t fallback)329 dst__openssl_toresult(isc_result_t fallback) {
330 	isc_result_t result;
331 
332 	result = toresult(fallback);
333 
334 	ERR_clear_error();
335 	return (result);
336 }
337 
338 isc_result_t
dst__openssl_toresult2(const char * funcname,isc_result_t fallback)339 dst__openssl_toresult2(const char *funcname, isc_result_t fallback) {
340 	return (dst__openssl_toresult3(DNS_LOGCATEGORY_GENERAL,
341 				       funcname, fallback));
342 }
343 
344 isc_result_t
dst__openssl_toresult3(isc_logcategory_t * category,const char * funcname,isc_result_t fallback)345 dst__openssl_toresult3(isc_logcategory_t *category,
346 		       const char *funcname, isc_result_t fallback) {
347 	isc_result_t result;
348 	unsigned long err;
349 	const char *file, *data;
350 	int line, flags;
351 	char buf[256];
352 
353 	result = toresult(fallback);
354 
355 	isc_log_write(dns_lctx, category,
356 		      DNS_LOGMODULE_CRYPTO, ISC_LOG_WARNING,
357 		      "%s failed (%s)", funcname,
358 		      isc_result_totext(result));
359 
360 	if (result == ISC_R_NOMEMORY)
361 		goto done;
362 
363 	for (;;) {
364 		err = ERR_get_error_line_data(&file, &line, &data, &flags);
365 		if (err == 0U)
366 			goto done;
367 		ERR_error_string_n(err, buf, sizeof(buf));
368 		isc_log_write(dns_lctx, category,
369 			      DNS_LOGMODULE_CRYPTO, ISC_LOG_INFO,
370 			      "%s:%s:%d:%s", buf, file, line,
371 			      (flags & ERR_TXT_STRING) ? data : "");
372 	}
373 
374     done:
375 	ERR_clear_error();
376 	return (result);
377 }
378 
379 #if defined(USE_ENGINE)
380 ENGINE *
dst__openssl_getengine(const char * engine)381 dst__openssl_getengine(const char *engine) {
382 
383 	if (engine == NULL)
384 		return (NULL);
385 	if (e == NULL)
386 		return (NULL);
387 	if (strcmp(engine, ENGINE_get_id(e)) == 0)
388 		return (e);
389 	return (NULL);
390 }
391 #endif
392 
393 #else /* OPENSSL */
394 
395 #include <isc/util.h>
396 
397 EMPTY_TRANSLATION_UNIT
398 
399 #endif /* OPENSSL */
400 /*! \file */
401