]> CyberLeo.Net >> Repos - FreeBSD/releng/8.1.git/blob - contrib/bind9/lib/dns/openssl_link.c
Copy stable/8 to releng/8.1 in preparation for 8.1-RC1.
[FreeBSD/releng/8.1.git] / contrib / bind9 / lib / dns / openssl_link.c
1 /*
2  * Portions Copyright (C) 2004-2009  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: openssl_link.c,v 1.22.112.3 2009/02/11 03:07:01 jinmei Exp $
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_internal.h"
49 #include "dst_openssl.h"
50
51 #include <openssl/err.h>
52 #include <openssl/rand.h>
53 #include <openssl/evp.h>
54 #include <openssl/conf.h>
55 #include <openssl/crypto.h>
56
57 #if defined(CRYPTO_LOCK_ENGINE) && (OPENSSL_VERSION_NUMBER >= 0x0090707f)
58 #define USE_ENGINE 1
59 #endif
60
61 #ifdef USE_ENGINE
62 #include <openssl/engine.h>
63
64 #ifdef ENGINE_ID
65 const char *engine_id = ENGINE_ID;
66 #else
67 const char *engine_id;
68 #endif
69 #endif
70
71 static RAND_METHOD *rm = NULL;
72
73 static isc_mutex_t *locks = NULL;
74 static int nlocks;
75
76 #ifdef USE_ENGINE
77 static ENGINE *e;
78 static ENGINE *he;
79 #endif
80
81 #ifdef USE_PKCS11
82 static isc_result_t
83 dst__openssl_load_engine(const char *name, const char *engine_id,
84                          const char **pre_cmds, int pre_num,
85                          const char **post_cmds, int post_num);
86 #endif
87
88 static int
89 entropy_get(unsigned char *buf, int num) {
90         isc_result_t result;
91         if (num < 0)
92                 return (-1);
93         result = dst__entropy_getdata(buf, (unsigned int) num, ISC_FALSE);
94         return (result == ISC_R_SUCCESS ? num : -1);
95 }
96
97 static int
98 entropy_status(void) {
99         return (dst__entropy_status() > 32);
100 }
101
102 static int
103 entropy_getpseudo(unsigned char *buf, int num) {
104         isc_result_t result;
105         if (num < 0)
106                 return (-1);
107         result = dst__entropy_getdata(buf, (unsigned int) num, ISC_TRUE);
108         return (result == ISC_R_SUCCESS ? num : -1);
109 }
110
111 static void
112 entropy_add(const void *buf, int num, double entropy) {
113         /*
114          * Do nothing.  The only call to this provides no useful data anyway.
115          */
116         UNUSED(buf);
117         UNUSED(num);
118         UNUSED(entropy);
119 }
120
121 static void
122 lock_callback(int mode, int type, const char *file, int line) {
123         UNUSED(file);
124         UNUSED(line);
125         if ((mode & CRYPTO_LOCK) != 0)
126                 LOCK(&locks[type]);
127         else
128                 UNLOCK(&locks[type]);
129 }
130
131 static unsigned long
132 id_callback(void) {
133         return ((unsigned long)isc_thread_self());
134 }
135
136 static void *
137 mem_alloc(size_t size) {
138         INSIST(dst__memory_pool != NULL);
139         return (isc_mem_allocate(dst__memory_pool, size));
140 }
141
142 static void
143 mem_free(void *ptr) {
144         INSIST(dst__memory_pool != NULL);
145         if (ptr != NULL)
146                 isc_mem_free(dst__memory_pool, ptr);
147 }
148
149 static void *
150 mem_realloc(void *ptr, size_t size) {
151         INSIST(dst__memory_pool != NULL);
152         return (isc_mem_reallocate(dst__memory_pool, ptr, size));
153 }
154
155 isc_result_t
156 dst__openssl_init() {
157         isc_result_t result;
158 #ifdef USE_ENGINE
159         /* const char  *name; */
160         ENGINE *re;
161 #endif
162
163 #ifdef  DNS_CRYPTO_LEAKS
164         CRYPTO_malloc_debug_init();
165         CRYPTO_set_mem_debug_options(V_CRYPTO_MDEBUG_ALL);
166         CRYPTO_mem_ctrl(CRYPTO_MEM_CHECK_ON);
167 #endif
168         CRYPTO_set_mem_functions(mem_alloc, mem_realloc, mem_free);
169         nlocks = CRYPTO_num_locks();
170         locks = mem_alloc(sizeof(isc_mutex_t) * nlocks);
171         if (locks == NULL)
172                 return (ISC_R_NOMEMORY);
173         result = isc_mutexblock_init(locks, nlocks);
174         if (result != ISC_R_SUCCESS)
175                 goto cleanup_mutexalloc;
176         CRYPTO_set_locking_callback(lock_callback);
177         CRYPTO_set_id_callback(id_callback);
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 #ifdef USE_ENGINE
191         OPENSSL_config(NULL);
192 #ifdef USE_PKCS11
193 #ifndef PKCS11_SO_PATH
194 #define PKCS11_SO_PATH          "/usr/local/lib/engines/engine_pkcs11.so"
195 #endif
196 #ifndef PKCS11_MODULE_PATH
197 #define PKCS11_MODULE_PATH      "/usr/lib/libpkcs11.so"
198 #endif
199         {
200                 /*
201                  * to use this to config the PIN, add in openssl.cnf:
202                  *  - at the beginning: "openssl_conf = openssl_def"
203                  *  - at any place these sections:
204                  * [ openssl_def ]
205                  * engines = engine_section
206                  * [ engine_section ]
207                  * pkcs11 = pkcs11_section
208                  * [ pkcs11_section ]
209                  * PIN = my___pin
210                  */
211
212                 const char *pre_cmds[] = {
213                         "SO_PATH", PKCS11_SO_PATH,
214                         "LOAD", NULL,
215                         "MODULE_PATH", PKCS11_MODULE_PATH
216                 };
217                 const char *post_cmds[] = {
218                         /* "PIN", "my___pin" */
219                 };
220                 result = dst__openssl_load_engine("pkcs11", "pkcs11",
221                                                   pre_cmds, 0,
222                                                   post_cmds, /*1*/ 0);
223                 if (result != ISC_R_SUCCESS)
224                         goto cleanup_rm;
225         }
226 #endif /* USE_PKCS11 */
227         if (engine_id != NULL) {
228                 e = ENGINE_by_id(engine_id);
229                 if (e == NULL) {
230                         result = ISC_R_NOTFOUND;
231                         goto cleanup_rm;
232                 }
233                 if (!ENGINE_init(e)) {
234                         result = ISC_R_FAILURE;
235                         ENGINE_free(e);
236                         goto cleanup_rm;
237                 }
238                 ENGINE_set_default(e, ENGINE_METHOD_ALL);
239                 ENGINE_free(e);
240         } else {
241                 ENGINE_register_all_complete();
242                 for (e = ENGINE_get_first(); e != NULL; e = ENGINE_get_next(e)) {
243
244                         /*
245                          * Something weird here. If we call ENGINE_finish()
246                          * ENGINE_get_default_RAND() will fail.
247                          */
248                         if (ENGINE_init(e)) {
249                                 if (he == NULL)
250                                         he = e;
251                         }
252                 }
253         }
254         re = ENGINE_get_default_RAND();
255         if (re == NULL) {
256                 re = ENGINE_new();
257                 if (re == NULL) {
258                         result = ISC_R_NOMEMORY;
259                         goto cleanup_rm;
260                 }
261                 ENGINE_set_RAND(re, rm);
262                 ENGINE_set_default_RAND(re);
263                 ENGINE_free(re);
264         } else
265                 ENGINE_finish(re);
266
267 #else
268         RAND_set_rand_method(rm);
269 #endif /* USE_ENGINE */
270         return (ISC_R_SUCCESS);
271
272 #ifdef USE_ENGINE
273  cleanup_rm:
274         mem_free(rm);
275 #endif
276  cleanup_mutexinit:
277         CRYPTO_set_locking_callback(NULL);
278         DESTROYMUTEXBLOCK(locks, nlocks);
279  cleanup_mutexalloc:
280         mem_free(locks);
281         return (result);
282 }
283
284 void
285 dst__openssl_destroy() {
286
287         /*
288          * Sequence taken from apps_shutdown() in <apps/apps.h>.
289          */
290 #if (OPENSSL_VERSION_NUMBER >= 0x00907000L)
291         CONF_modules_unload(1);
292 #endif
293         EVP_cleanup();
294 #if defined(USE_ENGINE)
295         if (e != NULL) {
296                 ENGINE_finish(e);
297                 e = NULL;
298         }
299 #if defined(USE_ENGINE) && OPENSSL_VERSION_NUMBER >= 0x00907000L
300         ENGINE_cleanup();
301 #endif
302 #endif
303 #if (OPENSSL_VERSION_NUMBER >= 0x00907000L)
304         CRYPTO_cleanup_all_ex_data();
305 #endif
306         ERR_clear_error();
307         ERR_free_strings();
308         ERR_remove_state(0);
309
310 #ifdef  DNS_CRYPTO_LEAKS
311         CRYPTO_mem_leaks_fp(stderr);
312 #endif
313
314         if (rm != NULL) {
315 #if OPENSSL_VERSION_NUMBER >= 0x00907000L
316                 RAND_cleanup();
317 #endif
318                 mem_free(rm);
319         }
320         if (locks != NULL) {
321                 CRYPTO_set_locking_callback(NULL);
322                 DESTROYMUTEXBLOCK(locks, nlocks);
323                 mem_free(locks);
324         }
325 }
326
327 isc_result_t
328 dst__openssl_toresult(isc_result_t fallback) {
329         isc_result_t result = fallback;
330         int err = ERR_get_error();
331
332         switch (ERR_GET_REASON(err)) {
333         case ERR_R_MALLOC_FAILURE:
334                 result = ISC_R_NOMEMORY;
335                 break;
336         default:
337                 break;
338         }
339         ERR_clear_error();
340         return (result);
341 }
342
343 ENGINE *
344 dst__openssl_getengine(const char *name) {
345
346         UNUSED(name);
347
348
349 #if defined(USE_ENGINE)
350         return (he);
351 #else
352         return (NULL);
353 #endif
354 }
355
356 isc_result_t
357 dst__openssl_setdefault(const char *name) {
358
359         UNUSED(name);
360
361 #if defined(USE_ENGINE)
362         ENGINE_set_default(e, ENGINE_METHOD_ALL);
363 #endif
364         /*
365          * XXXMPA If the engine does not have a default RAND method
366          * restore our method.
367          */
368         return (ISC_R_SUCCESS);
369 }
370
371 #ifdef USE_PKCS11
372 /*
373  * 'name' is the name the engine is known by to the dst library.
374  * This may or may not match the name the engine is known by to
375  * openssl.  It is the name that is stored in the private key file.
376  *
377  * 'engine_id' is the openssl engine name.
378  *
379  * pre_cmds and post_cmds a sequence if command argument pairs
380  * pre_num and post_num are a count of those pairs.
381  *
382  * "SO_PATH", PKCS11_SO_PATH ("/usr/local/lib/engines/engine_pkcs11.so")
383  * "LOAD", NULL
384  * "MODULE_PATH", PKCS11_MODULE_PATH ("/usr/lib/libpkcs11.so")
385  */
386 static isc_result_t
387 dst__openssl_load_engine(const char *name, const char *engine_id,
388                          const char **pre_cmds, int pre_num,
389                          const char **post_cmds, int post_num)
390 {
391         ENGINE *e;
392
393         UNUSED(name);
394
395         if (!strcasecmp(engine_id, "dynamic"))
396                 ENGINE_load_dynamic();
397         e = ENGINE_by_id(engine_id);
398         if (e == NULL)
399                 return (ISC_R_NOTFOUND);
400         while (pre_num--) {
401                 if (!ENGINE_ctrl_cmd_string(e, pre_cmds[0], pre_cmds[1], 0)) {
402                         ENGINE_free(e);
403                         return (ISC_R_FAILURE);
404                 }
405                 pre_cmds += 2;
406         }
407         if (!ENGINE_init(e)) {
408                 ENGINE_free(e);
409                 return (ISC_R_FAILURE);
410         }
411         /*
412          * ENGINE_init() returned a functional reference, so free the
413          * structural reference from ENGINE_by_id().
414          */
415         ENGINE_free(e);
416         while (post_num--) {
417                 if (!ENGINE_ctrl_cmd_string(e, post_cmds[0], post_cmds[1], 0)) {
418                         ENGINE_free(e);
419                         return (ISC_R_FAILURE);
420                 }
421                 post_cmds += 2;
422         }
423         if (he != NULL)
424                 ENGINE_finish(he);
425         he = e;
426         return (ISC_R_SUCCESS);
427 }
428 #endif /* USE_PKCS11 */
429
430 #else /* OPENSSL */
431
432 #include <isc/util.h>
433
434 EMPTY_TRANSLATION_UNIT
435
436 #endif /* OPENSSL */
437 /*! \file */