]> CyberLeo.Net >> Repos - FreeBSD/releng/9.2.git/blob - contrib/bind9/lib/dns/openssl_link.c
- Copy stable/9 to releng/9.2 as part of the 9.2-RELEASE cycle.
[FreeBSD/releng/9.2.git] / contrib / bind9 / lib / dns / openssl_link.c
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 <dns/log.h>
49
50 #include <dst/result.h>
51
52 #include "dst_internal.h"
53 #include "dst_openssl.h"
54
55 #ifdef USE_ENGINE
56 #include <openssl/engine.h>
57 #endif
58
59 static RAND_METHOD *rm = NULL;
60
61 static isc_mutex_t *locks = NULL;
62 static int nlocks;
63
64 #ifdef USE_ENGINE
65 static ENGINE *e = NULL;
66 #endif
67
68 static int
69 entropy_get(unsigned char *buf, int num) {
70         isc_result_t result;
71         if (num < 0)
72                 return (-1);
73         result = dst__entropy_getdata(buf, (unsigned int) num, ISC_FALSE);
74         return (result == ISC_R_SUCCESS ? 1 : -1);
75 }
76
77 static int
78 entropy_status(void) {
79         return (dst__entropy_status() > 32);
80 }
81
82 static int
83 entropy_getpseudo(unsigned char *buf, int num) {
84         isc_result_t result;
85         if (num < 0)
86                 return (-1);
87         result = dst__entropy_getdata(buf, (unsigned int) num, ISC_TRUE);
88         return (result == ISC_R_SUCCESS ? 1 : -1);
89 }
90
91 static void
92 entropy_add(const void *buf, int num, double entropy) {
93         /*
94          * Do nothing.  The only call to this provides no useful data anyway.
95          */
96         UNUSED(buf);
97         UNUSED(num);
98         UNUSED(entropy);
99 }
100
101 static void
102 lock_callback(int mode, int type, const char *file, int line) {
103         UNUSED(file);
104         UNUSED(line);
105         if ((mode & CRYPTO_LOCK) != 0)
106                 LOCK(&locks[type]);
107         else
108                 UNLOCK(&locks[type]);
109 }
110
111 static unsigned long
112 id_callback(void) {
113         return ((unsigned long)isc_thread_self());
114 }
115
116 static void *
117 mem_alloc(size_t size) {
118 #ifdef OPENSSL_LEAKS
119         void *ptr;
120
121         INSIST(dst__memory_pool != NULL);
122         ptr = isc_mem_allocate(dst__memory_pool, size);
123         return (ptr);
124 #else
125         INSIST(dst__memory_pool != NULL);
126         return (isc_mem_allocate(dst__memory_pool, size));
127 #endif
128 }
129
130 static void
131 mem_free(void *ptr) {
132         INSIST(dst__memory_pool != NULL);
133         if (ptr != NULL)
134                 isc_mem_free(dst__memory_pool, ptr);
135 }
136
137 static void *
138 mem_realloc(void *ptr, size_t size) {
139 #ifdef OPENSSL_LEAKS
140         void *rptr;
141
142         INSIST(dst__memory_pool != NULL);
143         rptr = isc_mem_reallocate(dst__memory_pool, ptr, size);
144         return (rptr);
145 #else
146         INSIST(dst__memory_pool != NULL);
147         return (isc_mem_reallocate(dst__memory_pool, ptr, size));
148 #endif
149 }
150
151 isc_result_t
152 dst__openssl_init(const char *engine) {
153         isc_result_t result;
154 #ifdef USE_ENGINE
155         ENGINE *re;
156 #else
157
158         UNUSED(engine);
159 #endif
160
161 #ifdef  DNS_CRYPTO_LEAKS
162         CRYPTO_malloc_debug_init();
163         CRYPTO_set_mem_debug_options(V_CRYPTO_MDEBUG_ALL);
164         CRYPTO_mem_ctrl(CRYPTO_MEM_CHECK_ON);
165 #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         if (locks == NULL)
170                 return (ISC_R_NOMEMORY);
171         result = isc_mutexblock_init(locks, nlocks);
172         if (result != ISC_R_SUCCESS)
173                 goto cleanup_mutexalloc;
174         CRYPTO_set_locking_callback(lock_callback);
175         CRYPTO_set_id_callback(id_callback);
176
177         ERR_load_crypto_strings();
178
179         rm = mem_alloc(sizeof(RAND_METHOD));
180         if (rm == NULL) {
181                 result = ISC_R_NOMEMORY;
182                 goto cleanup_mutexinit;
183         }
184         rm->seed = NULL;
185         rm->bytes = entropy_get;
186         rm->cleanup = NULL;
187         rm->add = entropy_add;
188         rm->pseudorand = entropy_getpseudo;
189         rm->status = entropy_status;
190
191 #ifdef USE_ENGINE
192         OPENSSL_config(NULL);
193
194         if (engine != NULL && *engine == '\0')
195                 engine = NULL;
196
197         if (engine != NULL) {
198                 e = ENGINE_by_id(engine);
199                 if (e == NULL) {
200                         result = DST_R_NOENGINE;
201                         goto cleanup_rm;
202                 }
203                 /* This will init the engine. */
204                 if (!ENGINE_set_default(e, ENGINE_METHOD_ALL)) {
205                         result = DST_R_NOENGINE;
206                         goto cleanup_rm;
207                 }
208         }
209
210         re = ENGINE_get_default_RAND();
211         if (re == NULL) {
212                 re = ENGINE_new();
213                 if (re == NULL) {
214                         result = ISC_R_NOMEMORY;
215                         goto cleanup_rm;
216                 }
217                 ENGINE_set_RAND(re, rm);
218                 ENGINE_set_default_RAND(re);
219                 ENGINE_free(re);
220         } else
221                 ENGINE_finish(re);
222 #else
223         RAND_set_rand_method(rm);
224 #endif /* USE_ENGINE */
225         return (ISC_R_SUCCESS);
226
227 #ifdef USE_ENGINE
228  cleanup_rm:
229         if (e != NULL)
230                 ENGINE_free(e);
231         e = NULL;
232         mem_free(rm);
233         rm = NULL;
234 #endif
235  cleanup_mutexinit:
236         CRYPTO_set_locking_callback(NULL);
237         DESTROYMUTEXBLOCK(locks, nlocks);
238  cleanup_mutexalloc:
239         mem_free(locks);
240         locks = NULL;
241         return (result);
242 }
243
244 void
245 dst__openssl_destroy() {
246
247         /*
248          * Sequence taken from apps_shutdown() in <apps/apps.h>.
249          */
250         if (rm != NULL) {
251 #if OPENSSL_VERSION_NUMBER >= 0x00907000L
252                 RAND_cleanup();
253 #endif
254                 mem_free(rm);
255                 rm = NULL;
256         }
257 #if (OPENSSL_VERSION_NUMBER >= 0x00907000L)
258         CONF_modules_free();
259 #endif
260         OBJ_cleanup();
261         EVP_cleanup();
262 #if defined(USE_ENGINE)
263         if (e != NULL)
264                 ENGINE_free(e);
265         e = NULL;
266 #if defined(USE_ENGINE) && OPENSSL_VERSION_NUMBER >= 0x00907000L
267         ENGINE_cleanup();
268 #endif
269 #endif
270 #if (OPENSSL_VERSION_NUMBER >= 0x00907000L)
271         CRYPTO_cleanup_all_ex_data();
272 #endif
273         ERR_clear_error();
274         ERR_remove_state(0);
275         ERR_free_strings();
276
277 #ifdef  DNS_CRYPTO_LEAKS
278         CRYPTO_mem_leaks_fp(stderr);
279 #endif
280
281         if (locks != NULL) {
282                 CRYPTO_set_locking_callback(NULL);
283                 DESTROYMUTEXBLOCK(locks, nlocks);
284                 mem_free(locks);
285                 locks = NULL;
286         }
287 }
288
289 isc_result_t
290 dst__openssl_toresult(isc_result_t fallback) {
291         isc_result_t result = fallback;
292         unsigned long err = ERR_get_error();
293
294         switch (ERR_GET_REASON(err)) {
295         case ERR_R_MALLOC_FAILURE:
296                 result = ISC_R_NOMEMORY;
297                 break;
298         default:
299                 break;
300         }
301         ERR_clear_error();
302         return (result);
303 }
304
305 isc_result_t
306 dst__openssl_toresult2(const char *funcname, isc_result_t fallback) {
307         isc_result_t result = fallback;
308         unsigned long err = ERR_peek_error();
309         const char *file, *data;
310         int line, flags;
311         char buf[256];
312
313         switch (ERR_GET_REASON(err)) {
314         case ERR_R_MALLOC_FAILURE:
315                 result = ISC_R_NOMEMORY;
316                 goto done;
317         default:
318                 break;
319         }
320         isc_log_write(dns_lctx, DNS_LOGCATEGORY_GENERAL,
321                       DNS_LOGMODULE_CRYPTO, ISC_LOG_WARNING,
322                       "%s failed", funcname);
323         for (;;) {
324                 err = ERR_get_error_line_data(&file, &line, &data, &flags);
325                 if (err == 0U)
326                         goto done;
327                 ERR_error_string_n(err, buf, sizeof(buf));
328                 isc_log_write(dns_lctx, DNS_LOGCATEGORY_GENERAL,
329                               DNS_LOGMODULE_CRYPTO, ISC_LOG_INFO,
330                               "%s:%s:%d:%s", buf, file, line,
331                               (flags & ERR_TXT_STRING) ? data : "");
332         }
333
334     done:
335         ERR_clear_error();
336         return (result);
337 }
338
339 #if defined(USE_ENGINE)
340 ENGINE *
341 dst__openssl_getengine(const char *engine) {
342
343         if (engine == NULL)
344                 return (NULL);
345         if (e == NULL)
346                 return (NULL);
347         if (strcmp(engine, ENGINE_get_id(e)) == 0)
348                 return (e);
349         return (NULL);
350 }
351 #endif
352
353 #else /* OPENSSL */
354
355 #include <isc/util.h>
356
357 EMPTY_TRANSLATION_UNIT
358
359 #endif /* OPENSSL */
360 /*! \file */