00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034
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
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
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
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
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
00300
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
00385
00386 #include <isc/util.h>
00387
00388 EMPTY_TRANSLATION_UNIT
00389
00390 #endif
00391