openssl_link.c

Go to the documentation of this file.
00001 /*
00002  * Portions Copyright (C) 2004-2012, 2014  Internet Systems Consortium, Inc. ("ISC")
00003  * Portions Copyright (C) 1999-2003  Internet Software Consortium.
00004  *
00005  * Permission to use, copy, modify, and/or distribute this software for any
00006  * purpose with or without fee is hereby granted, provided that the above
00007  * copyright notice and this permission notice appear in all copies.
00008  *
00009  * THE SOFTWARE IS PROVIDED "AS IS" AND ISC AND NETWORK ASSOCIATES DISCLAIMS
00010  * ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
00011  * WARRANTIES OF MERCHANTABILITY AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE
00012  * FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
00013  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
00014  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR
00015  * IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
00016  *
00017  * Portions Copyright (C) 1995-2000 by Network Associates, Inc.
00018  *
00019  * Permission to use, copy, modify, and/or distribute this software for any
00020  * purpose with or without fee is hereby granted, provided that the above
00021  * copyright notice and this permission notice appear in all copies.
00022  *
00023  * THE SOFTWARE IS PROVIDED "AS IS" AND ISC AND NETWORK ASSOCIATES DISCLAIMS
00024  * ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
00025  * WARRANTIES OF MERCHANTABILITY AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE
00026  * FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
00027  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
00028  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR
00029  * IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
00030  */
00031 
00032 /*
00033  * Principal Author: Brian Wellington
00034  * $Id$
00035  */
00036 #ifdef OPENSSL
00037 
00038 #include <config.h>
00039 
00040 #include <isc/entropy.h>
00041 #include <isc/mem.h>
00042 #include <isc/mutex.h>
00043 #include <isc/mutexblock.h>
00044 #include <isc/string.h>
00045 #include <isc/thread.h>
00046 #include <isc/util.h>
00047 
00048 #include <dns/log.h>
00049 
00050 #include <dst/result.h>
00051 
00052 #include "dst_internal.h"
00053 #include "dst_openssl.h"
00054 
00055 #ifdef USE_ENGINE
00056 #include <openssl/engine.h>
00057 #endif
00058 
00059 static RAND_METHOD *rm = NULL;
00060 
00061 static isc_mutex_t *locks = NULL;
00062 static int nlocks;
00063 
00064 #ifdef USE_ENGINE
00065 static ENGINE *e = NULL;
00066 #endif
00067 
00068 static int
00069 entropy_get(unsigned char *buf, int num) {
00070         isc_result_t result;
00071         if (num < 0)
00072                 return (-1);
00073         result = dst__entropy_getdata(buf, (unsigned int) num, ISC_FALSE);
00074         return (result == ISC_R_SUCCESS ? 1 : -1);
00075 }
00076 
00077 static int
00078 entropy_status(void) {
00079         return (dst__entropy_status() > 32);
00080 }
00081 
00082 static int
00083 entropy_getpseudo(unsigned char *buf, int num) {
00084         isc_result_t result;
00085         if (num < 0)
00086                 return (-1);
00087         result = dst__entropy_getdata(buf, (unsigned int) num, ISC_TRUE);
00088         return (result == ISC_R_SUCCESS ? 1 : -1);
00089 }
00090 
00091 static void
00092 entropy_add(const void *buf, int num, double entropy) {
00093         /*
00094          * Do nothing.  The only call to this provides no useful data anyway.
00095          */
00096         UNUSED(buf);
00097         UNUSED(num);
00098         UNUSED(entropy);
00099 }
00100 
00101 static void
00102 lock_callback(int mode, int type, const char *file, int line) {
00103         UNUSED(file);
00104         UNUSED(line);
00105         if ((mode & CRYPTO_LOCK) != 0)
00106                 LOCK(&locks[type]);
00107         else
00108                 UNLOCK(&locks[type]);
00109 }
00110 
00111 static unsigned long
00112 id_callback(void) {
00113         return ((unsigned long)isc_thread_self());
00114 }
00115 
00116 static void *
00117 mem_alloc(size_t size) {
00118 #ifdef OPENSSL_LEAKS
00119         void *ptr;
00120 
00121         INSIST(dst__memory_pool != NULL);
00122         ptr = isc_mem_allocate(dst__memory_pool, size);
00123         return (ptr);
00124 #else
00125         INSIST(dst__memory_pool != NULL);
00126         return (isc_mem_allocate(dst__memory_pool, size));
00127 #endif
00128 }
00129 
00130 static void
00131 mem_free(void *ptr) {
00132         INSIST(dst__memory_pool != NULL);
00133         if (ptr != NULL)
00134                 isc_mem_free(dst__memory_pool, ptr);
00135 }
00136 
00137 static void *
00138 mem_realloc(void *ptr, size_t size) {
00139 #ifdef OPENSSL_LEAKS
00140         void *rptr;
00141 
00142         INSIST(dst__memory_pool != NULL);
00143         rptr = isc_mem_reallocate(dst__memory_pool, ptr, size);
00144         return (rptr);
00145 #else
00146         INSIST(dst__memory_pool != NULL);
00147         return (isc_mem_reallocate(dst__memory_pool, ptr, size));
00148 #endif
00149 }
00150 
00151 isc_result_t
00152 dst__openssl_init(const char *engine) {
00153         isc_result_t result;
00154 #ifdef USE_ENGINE
00155         ENGINE *re;
00156 #else
00157 
00158         UNUSED(engine);
00159 #endif
00160 
00161 #ifdef  DNS_CRYPTO_LEAKS
00162         CRYPTO_malloc_debug_init();
00163         CRYPTO_set_mem_debug_options(V_CRYPTO_MDEBUG_ALL);
00164         CRYPTO_mem_ctrl(CRYPTO_MEM_CHECK_ON);
00165 #endif
00166         CRYPTO_set_mem_functions(mem_alloc, mem_realloc, mem_free);
00167         nlocks = CRYPTO_num_locks();
00168         locks = mem_alloc(sizeof(isc_mutex_t) * nlocks);
00169         if (locks == NULL)
00170                 return (ISC_R_NOMEMORY);
00171         result = isc_mutexblock_init(locks, nlocks);
00172         if (result != ISC_R_SUCCESS)
00173                 goto cleanup_mutexalloc;
00174         CRYPTO_set_locking_callback(lock_callback);
00175         CRYPTO_set_id_callback(id_callback);
00176 
00177         ERR_load_crypto_strings();
00178 
00179         rm = mem_alloc(sizeof(RAND_METHOD));
00180         if (rm == NULL) {
00181                 result = ISC_R_NOMEMORY;
00182                 goto cleanup_mutexinit;
00183         }
00184         rm->seed = NULL;
00185         rm->bytes = entropy_get;
00186         rm->cleanup = NULL;
00187         rm->add = entropy_add;
00188         rm->pseudorand = entropy_getpseudo;
00189         rm->status = entropy_status;
00190 
00191 #ifdef USE_ENGINE
00192         OPENSSL_config(NULL);
00193 
00194         if (engine != NULL && *engine == '\0')
00195                 engine = NULL;
00196 
00197         if (engine != NULL) {
00198                 e = ENGINE_by_id(engine);
00199                 if (e == NULL) {
00200                         result = DST_R_NOENGINE;
00201                         goto cleanup_rm;
00202                 }
00203                 /* This will init the engine. */
00204                 if (!ENGINE_set_default(e, ENGINE_METHOD_ALL)) {
00205                         result = DST_R_NOENGINE;
00206                         goto cleanup_rm;
00207                 }
00208         }
00209 
00210         re = ENGINE_get_default_RAND();
00211         if (re == NULL) {
00212                 re = ENGINE_new();
00213                 if (re == NULL) {
00214                         result = ISC_R_NOMEMORY;
00215                         goto cleanup_rm;
00216                 }
00217                 ENGINE_set_RAND(re, rm);
00218                 ENGINE_set_default_RAND(re);
00219                 ENGINE_free(re);
00220         } else
00221                 ENGINE_finish(re);
00222 #else
00223         RAND_set_rand_method(rm);
00224 #endif /* USE_ENGINE */
00225         return (ISC_R_SUCCESS);
00226 
00227 #ifdef USE_ENGINE
00228  cleanup_rm:
00229         if (e != NULL)
00230                 ENGINE_free(e);
00231         e = NULL;
00232         mem_free(rm);
00233         rm = NULL;
00234 #endif
00235  cleanup_mutexinit:
00236         CRYPTO_set_locking_callback(NULL);
00237         DESTROYMUTEXBLOCK(locks, nlocks);
00238  cleanup_mutexalloc:
00239         mem_free(locks);
00240         locks = NULL;
00241         return (result);
00242 }
00243 
00244 void
00245 dst__openssl_destroy(void) {
00246         /*
00247          * Sequence taken from apps_shutdown() in <apps/apps.h>.
00248          */
00249         if (rm != NULL) {
00250 #if OPENSSL_VERSION_NUMBER >= 0x00907000L
00251                 RAND_cleanup();
00252 #endif
00253                 mem_free(rm);
00254                 rm = NULL;
00255         }
00256 #if (OPENSSL_VERSION_NUMBER >= 0x00907000L)
00257         CONF_modules_free();
00258 #endif
00259         OBJ_cleanup();
00260         EVP_cleanup();
00261 #if defined(USE_ENGINE)
00262         if (e != NULL)
00263                 ENGINE_free(e);
00264         e = NULL;
00265 #if defined(USE_ENGINE) && OPENSSL_VERSION_NUMBER >= 0x00907000L
00266         ENGINE_cleanup();
00267 #endif
00268 #endif
00269 #if (OPENSSL_VERSION_NUMBER >= 0x00907000L)
00270         CRYPTO_cleanup_all_ex_data();
00271 #endif
00272         ERR_clear_error();
00273         ERR_remove_state(0);
00274         ERR_free_strings();
00275 
00276 #ifdef  DNS_CRYPTO_LEAKS
00277         CRYPTO_mem_leaks_fp(stderr);
00278 #endif
00279 
00280         if (locks != NULL) {
00281                 CRYPTO_set_locking_callback(NULL);
00282                 DESTROYMUTEXBLOCK(locks, nlocks);
00283                 mem_free(locks);
00284                 locks = NULL;
00285         }
00286 }
00287 
00288 static isc_result_t
00289 toresult(isc_result_t fallback) {
00290         isc_result_t result = fallback;
00291         unsigned long err = ERR_get_error();
00292 #ifdef HAVE_OPENSSL_ECDSA
00293         int lib = ERR_GET_LIB(err);
00294 #endif
00295         int reason = ERR_GET_REASON(err);
00296 
00297         switch (reason) {
00298         /*
00299          * ERR_* errors are globally unique; others
00300          * are unique per sublibrary
00301          */
00302         case ERR_R_MALLOC_FAILURE:
00303                 result = ISC_R_NOMEMORY;
00304                 break;
00305         default:
00306 #ifdef HAVE_OPENSSL_ECDSA
00307                 if (lib == ERR_R_ECDSA_LIB &&
00308                     reason == ECDSA_R_RANDOM_NUMBER_GENERATION_FAILED) {
00309                         result = ISC_R_NOENTROPY;
00310                         break;
00311                 }
00312 #endif
00313                 break;
00314         }
00315 
00316         return (result);
00317 }
00318 
00319 isc_result_t
00320 dst__openssl_toresult(isc_result_t fallback) {
00321         isc_result_t result;
00322 
00323         result = toresult(fallback);
00324 
00325         ERR_clear_error();
00326         return (result);
00327 }
00328 
00329 isc_result_t
00330 dst__openssl_toresult2(const char *funcname, isc_result_t fallback) {
00331         return (dst__openssl_toresult3(DNS_LOGCATEGORY_GENERAL,
00332                                        funcname, fallback));
00333 }
00334 
00335 isc_result_t
00336 dst__openssl_toresult3(isc_logcategory_t *category,
00337                        const char *funcname, isc_result_t fallback) {
00338         isc_result_t result;
00339         unsigned long err;
00340         const char *file, *data;
00341         int line, flags;
00342         char buf[256];
00343 
00344         result = toresult(fallback);
00345 
00346         isc_log_write(dns_lctx, category,
00347                       DNS_LOGMODULE_CRYPTO, ISC_LOG_WARNING,
00348                       "%s failed (%s)", funcname,
00349                       isc_result_totext(result));
00350 
00351         if (result == ISC_R_NOMEMORY)
00352                 goto done;
00353 
00354         for (;;) {
00355                 err = ERR_get_error_line_data(&file, &line, &data, &flags);
00356                 if (err == 0U)
00357                         goto done;
00358                 ERR_error_string_n(err, buf, sizeof(buf));
00359                 isc_log_write(dns_lctx, category,
00360                               DNS_LOGMODULE_CRYPTO, ISC_LOG_INFO,
00361                               "%s:%s:%d:%s", buf, file, line,
00362                               (flags & ERR_TXT_STRING) ? data : "");
00363         }
00364 
00365     done:
00366         ERR_clear_error();
00367         return (result);
00368 }
00369 
00370 #if defined(USE_ENGINE)
00371 ENGINE *
00372 dst__openssl_getengine(const char *engine) {
00373 
00374         if (engine == NULL)
00375                 return (NULL);
00376         if (e == NULL)
00377                 return (NULL);
00378         if (strcmp(engine, ENGINE_get_id(e)) == 0)
00379                 return (e);
00380         return (NULL);
00381 }
00382 #endif
00383 
00384 #else /* OPENSSL */
00385 
00386 #include <isc/util.h>
00387 
00388 EMPTY_TRANSLATION_UNIT
00389 
00390 #endif /* OPENSSL */
00391 /*! \file */

Generated on Tue Apr 28 17:40:58 2015 by Doxygen 1.5.4 for BIND9 Internals 9.11.0pre-alpha