]> CyberLeo.Net >> Repos - FreeBSD/stable/9.git/blob - contrib/bind9/lib/dns/openssl_link.c
Update BIND to 9.9.8
[FreeBSD/stable/9.git] / contrib / bind9 / lib / dns / openssl_link.c
1 /*
2  * Portions Copyright (C) 2004-2012, 2014, 2015  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 #if OPENSSL_VERSION_NUMBER < 0x10100000L
92 static void
93 entropy_add(const void *buf, int num, double entropy) {
94         /*
95          * Do nothing.  The only call to this provides no useful data anyway.
96          */
97         UNUSED(buf);
98         UNUSED(num);
99         UNUSED(entropy);
100 }
101 #else
102 static int
103 entropy_add(const void *buf, int num, double entropy) {
104         /*
105          * Do nothing.  The only call to this provides no useful data anyway.
106          */
107         UNUSED(buf);
108         UNUSED(num);
109         UNUSED(entropy);
110         return (1);
111 }
112 #endif
113
114 static void
115 lock_callback(int mode, int type, const char *file, int line) {
116         UNUSED(file);
117         UNUSED(line);
118         if ((mode & CRYPTO_LOCK) != 0)
119                 LOCK(&locks[type]);
120         else
121                 UNLOCK(&locks[type]);
122 }
123
124 #if OPENSSL_VERSION_NUMBER < 0x10100000L
125 static unsigned long
126 id_callback(void) {
127         return ((unsigned long)isc_thread_self());
128 }
129 #endif
130
131 static void *
132 mem_alloc(size_t size) {
133 #ifdef OPENSSL_LEAKS
134         void *ptr;
135
136         INSIST(dst__memory_pool != NULL);
137         ptr = isc_mem_allocate(dst__memory_pool, size);
138         return (ptr);
139 #else
140         INSIST(dst__memory_pool != NULL);
141         return (isc_mem_allocate(dst__memory_pool, size));
142 #endif
143 }
144
145 static void
146 mem_free(void *ptr) {
147         INSIST(dst__memory_pool != NULL);
148         if (ptr != NULL)
149                 isc_mem_free(dst__memory_pool, ptr);
150 }
151
152 static void *
153 mem_realloc(void *ptr, size_t size) {
154 #ifdef OPENSSL_LEAKS
155         void *rptr;
156
157         INSIST(dst__memory_pool != NULL);
158         rptr = isc_mem_reallocate(dst__memory_pool, ptr, size);
159         return (rptr);
160 #else
161         INSIST(dst__memory_pool != NULL);
162         return (isc_mem_reallocate(dst__memory_pool, ptr, size));
163 #endif
164 }
165
166 isc_result_t
167 dst__openssl_init(const char *engine) {
168         isc_result_t result;
169 #ifdef USE_ENGINE
170         ENGINE *re;
171 #else
172
173         UNUSED(engine);
174 #endif
175
176 #ifdef  DNS_CRYPTO_LEAKS
177         CRYPTO_malloc_debug_init();
178         CRYPTO_set_mem_debug_options(V_CRYPTO_MDEBUG_ALL);
179         CRYPTO_mem_ctrl(CRYPTO_MEM_CHECK_ON);
180 #endif
181         CRYPTO_set_mem_functions(mem_alloc, mem_realloc, mem_free);
182         nlocks = CRYPTO_num_locks();
183         locks = mem_alloc(sizeof(isc_mutex_t) * nlocks);
184         if (locks == NULL)
185                 return (ISC_R_NOMEMORY);
186         result = isc_mutexblock_init(locks, nlocks);
187         if (result != ISC_R_SUCCESS)
188                 goto cleanup_mutexalloc;
189         CRYPTO_set_locking_callback(lock_callback);
190 #if OPENSSL_VERSION_NUMBER < 0x10100000L
191         CRYPTO_set_id_callback(id_callback);
192 #endif
193
194         ERR_load_crypto_strings();
195
196         rm = mem_alloc(sizeof(RAND_METHOD));
197         if (rm == NULL) {
198                 result = ISC_R_NOMEMORY;
199                 goto cleanup_mutexinit;
200         }
201         rm->seed = NULL;
202         rm->bytes = entropy_get;
203         rm->cleanup = NULL;
204         rm->add = entropy_add;
205         rm->pseudorand = entropy_getpseudo;
206         rm->status = entropy_status;
207
208 #ifdef USE_ENGINE
209         OPENSSL_config(NULL);
210
211         if (engine != NULL && *engine == '\0')
212                 engine = NULL;
213
214         if (engine != NULL) {
215                 e = ENGINE_by_id(engine);
216                 if (e == NULL) {
217                         result = DST_R_NOENGINE;
218                         goto cleanup_rm;
219                 }
220                 /* This will init the engine. */
221                 if (!ENGINE_set_default(e, ENGINE_METHOD_ALL)) {
222                         result = DST_R_NOENGINE;
223                         goto cleanup_rm;
224                 }
225         }
226
227         re = ENGINE_get_default_RAND();
228         if (re == NULL) {
229                 re = ENGINE_new();
230                 if (re == NULL) {
231                         result = ISC_R_NOMEMORY;
232                         goto cleanup_rm;
233                 }
234                 ENGINE_set_RAND(re, rm);
235                 ENGINE_set_default_RAND(re);
236                 ENGINE_free(re);
237         } else
238                 ENGINE_finish(re);
239 #else
240         RAND_set_rand_method(rm);
241 #endif /* USE_ENGINE */
242         return (ISC_R_SUCCESS);
243
244 #ifdef USE_ENGINE
245  cleanup_rm:
246         if (e != NULL)
247                 ENGINE_free(e);
248         e = NULL;
249         mem_free(rm);
250         rm = NULL;
251 #endif
252  cleanup_mutexinit:
253         CRYPTO_set_locking_callback(NULL);
254         DESTROYMUTEXBLOCK(locks, nlocks);
255  cleanup_mutexalloc:
256         mem_free(locks);
257         locks = NULL;
258         return (result);
259 }
260
261 void
262 dst__openssl_destroy(void) {
263         /*
264          * Sequence taken from apps_shutdown() in <apps/apps.h>.
265          */
266         if (rm != NULL) {
267 #if OPENSSL_VERSION_NUMBER >= 0x00907000L
268                 RAND_cleanup();
269 #endif
270                 mem_free(rm);
271                 rm = NULL;
272         }
273 #if (OPENSSL_VERSION_NUMBER >= 0x00907000L)
274         CONF_modules_free();
275 #endif
276         OBJ_cleanup();
277         EVP_cleanup();
278 #if defined(USE_ENGINE)
279         if (e != NULL)
280                 ENGINE_free(e);
281         e = NULL;
282 #if defined(USE_ENGINE) && OPENSSL_VERSION_NUMBER >= 0x00907000L
283         ENGINE_cleanup();
284 #endif
285 #endif
286 #if (OPENSSL_VERSION_NUMBER >= 0x00907000L)
287         CRYPTO_cleanup_all_ex_data();
288 #endif
289         ERR_clear_error();
290 #if OPENSSL_VERSION_NUMBER < 0x10100000L
291         ERR_remove_state(0);
292 #endif
293         ERR_free_strings();
294
295 #ifdef  DNS_CRYPTO_LEAKS
296         CRYPTO_mem_leaks_fp(stderr);
297 #endif
298
299         if (locks != NULL) {
300                 CRYPTO_set_locking_callback(NULL);
301                 DESTROYMUTEXBLOCK(locks, nlocks);
302                 mem_free(locks);
303                 locks = NULL;
304         }
305 }
306
307 static isc_result_t
308 toresult(isc_result_t fallback) {
309         isc_result_t result = fallback;
310         unsigned long err = ERR_get_error();
311 #ifdef HAVE_OPENSSL_ECDSA
312         int lib = ERR_GET_LIB(err);
313 #endif
314         int reason = ERR_GET_REASON(err);
315
316         switch (reason) {
317         /*
318          * ERR_* errors are globally unique; others
319          * are unique per sublibrary
320          */
321         case ERR_R_MALLOC_FAILURE:
322                 result = ISC_R_NOMEMORY;
323                 break;
324         default:
325 #ifdef HAVE_OPENSSL_ECDSA
326                 if (lib == ERR_R_ECDSA_LIB &&
327                     reason == ECDSA_R_RANDOM_NUMBER_GENERATION_FAILED) {
328                         result = ISC_R_NOENTROPY;
329                         break;
330                 }
331 #endif
332                 break;
333         }
334
335         return (result);
336 }
337
338 isc_result_t
339 dst__openssl_toresult(isc_result_t fallback) {
340         isc_result_t result;
341
342         result = toresult(fallback);
343
344         ERR_clear_error();
345         return (result);
346 }
347
348 isc_result_t
349 dst__openssl_toresult2(const char *funcname, isc_result_t fallback) {
350         return (dst__openssl_toresult3(DNS_LOGCATEGORY_GENERAL,
351                                        funcname, fallback));
352 }
353
354 isc_result_t
355 dst__openssl_toresult3(isc_logcategory_t *category,
356                        const char *funcname, isc_result_t fallback) {
357         isc_result_t result;
358         unsigned long err;
359         const char *file, *data;
360         int line, flags;
361         char buf[256];
362
363         result = toresult(fallback);
364
365         isc_log_write(dns_lctx, category,
366                       DNS_LOGMODULE_CRYPTO, ISC_LOG_WARNING,
367                       "%s failed (%s)", funcname,
368                       isc_result_totext(result));
369
370         if (result == ISC_R_NOMEMORY)
371                 goto done;
372
373         for (;;) {
374                 err = ERR_get_error_line_data(&file, &line, &data, &flags);
375                 if (err == 0U)
376                         goto done;
377                 ERR_error_string_n(err, buf, sizeof(buf));
378                 isc_log_write(dns_lctx, category,
379                               DNS_LOGMODULE_CRYPTO, ISC_LOG_INFO,
380                               "%s:%s:%d:%s", buf, file, line,
381                               (flags & ERR_TXT_STRING) ? data : "");
382         }
383
384     done:
385         ERR_clear_error();
386         return (result);
387 }
388
389 #if defined(USE_ENGINE)
390 ENGINE *
391 dst__openssl_getengine(const char *engine) {
392
393         if (engine == NULL)
394                 return (NULL);
395         if (e == NULL)
396                 return (NULL);
397         if (strcmp(engine, ENGINE_get_id(e)) == 0)
398                 return (e);
399         return (NULL);
400 }
401 #endif
402
403 #else /* OPENSSL */
404
405 #include <isc/util.h>
406
407 EMPTY_TRANSLATION_UNIT
408
409 #endif /* OPENSSL */
410 /*! \file */