dyn_lck.c revision 296465
1/* crypto/cryptlib.c */ 2/* ==================================================================== 3 * Copyright (c) 1998-2003 The OpenSSL Project. All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 9 * 1. Redistributions of source code must retain the above copyright 10 * notice, this list of conditions and the following disclaimer. 11 * 12 * 2. Redistributions in binary form must reproduce the above copyright 13 * notice, this list of conditions and the following disclaimer in 14 * the documentation and/or other materials provided with the 15 * distribution. 16 * 17 * 3. All advertising materials mentioning features or use of this 18 * software must display the following acknowledgment: 19 * "This product includes software developed by the OpenSSL Project 20 * for use in the OpenSSL Toolkit. (http://www.openssl.org/)" 21 * 22 * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to 23 * endorse or promote products derived from this software without 24 * prior written permission. For written permission, please contact 25 * openssl-core@openssl.org. 26 * 27 * 5. Products derived from this software may not be called "OpenSSL" 28 * nor may "OpenSSL" appear in their names without prior written 29 * permission of the OpenSSL Project. 30 * 31 * 6. Redistributions of any form whatsoever must retain the following 32 * acknowledgment: 33 * "This product includes software developed by the OpenSSL Project 34 * for use in the OpenSSL Toolkit (http://www.openssl.org/)" 35 * 36 * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY 37 * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 38 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 39 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE OpenSSL PROJECT OR 40 * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 41 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 42 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 43 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 44 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 45 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 46 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED 47 * OF THE POSSIBILITY OF SUCH DAMAGE. 48 * ==================================================================== 49 * 50 * This product includes cryptographic software written by Eric Young 51 * (eay@cryptsoft.com). This product includes software written by Tim 52 * Hudson (tjh@cryptsoft.com). 53 * 54 */ 55/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com) 56 * All rights reserved. 57 * 58 * This package is an SSL implementation written 59 * by Eric Young (eay@cryptsoft.com). 60 * The implementation was written so as to conform with Netscapes SSL. 61 * 62 * This library is free for commercial and non-commercial use as long as 63 * the following conditions are aheared to. The following conditions 64 * apply to all code found in this distribution, be it the RC4, RSA, 65 * lhash, DES, etc., code; not just the SSL code. The SSL documentation 66 * included with this distribution is covered by the same copyright terms 67 * except that the holder is Tim Hudson (tjh@cryptsoft.com). 68 * 69 * Copyright remains Eric Young's, and as such any Copyright notices in 70 * the code are not to be removed. 71 * If this package is used in a product, Eric Young should be given attribution 72 * as the author of the parts of the library used. 73 * This can be in the form of a textual message at program startup or 74 * in documentation (online or textual) provided with the package. 75 * 76 * Redistribution and use in source and binary forms, with or without 77 * modification, are permitted provided that the following conditions 78 * are met: 79 * 1. Redistributions of source code must retain the copyright 80 * notice, this list of conditions and the following disclaimer. 81 * 2. Redistributions in binary form must reproduce the above copyright 82 * notice, this list of conditions and the following disclaimer in the 83 * documentation and/or other materials provided with the distribution. 84 * 3. All advertising materials mentioning features or use of this software 85 * must display the following acknowledgement: 86 * "This product includes cryptographic software written by 87 * Eric Young (eay@cryptsoft.com)" 88 * The word 'cryptographic' can be left out if the rouines from the library 89 * being used are not cryptographic related :-). 90 * 4. If you include any Windows specific code (or a derivative thereof) from 91 * the apps directory (application code) you must include an acknowledgement: 92 * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)" 93 * 94 * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND 95 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 96 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 97 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 98 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 99 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 100 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 101 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 102 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 103 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 104 * SUCH DAMAGE. 105 * 106 * The licence and distribution terms for any publically available version or 107 * derivative of this code cannot be changed. i.e. this code cannot simply be 108 * copied and put under another distribution licence 109 * [including the GNU Public Licence.] 110 */ 111/* ==================================================================== 112 * Copyright 2002 Sun Microsystems, Inc. ALL RIGHTS RESERVED. 113 * ECDH support in OpenSSL originally developed by 114 * SUN MICROSYSTEMS, INC., and contributed to the OpenSSL project. 115 */ 116 117#include "cryptlib.h" 118#include <openssl/safestack.h> 119 120#if defined(OPENSSL_SYS_WIN32) || defined(OPENSSL_SYS_WIN16) 121static double SSLeay_MSVC5_hack = 0.0; /* and for VC1.5 */ 122#endif 123 124DECLARE_STACK_OF(CRYPTO_dynlock) 125IMPLEMENT_STACK_OF(CRYPTO_dynlock) 126 127/* real #defines in crypto.h, keep these upto date */ 128static const char *const lock_names[CRYPTO_NUM_LOCKS] = { 129 "<<ERROR>>", 130 "err", 131 "ex_data", 132 "x509", 133 "x509_info", 134 "x509_pkey", 135 "x509_crl", 136 "x509_req", 137 "dsa", 138 "rsa", 139 "evp_pkey", 140 "x509_store", 141 "ssl_ctx", 142 "ssl_cert", 143 "ssl_session", 144 "ssl_sess_cert", 145 "ssl", 146 "ssl_method", 147 "rand", 148 "rand2", 149 "debug_malloc", 150 "BIO", 151 "gethostbyname", 152 "getservbyname", 153 "readdir", 154 "RSA_blinding", 155 "dh", 156 "debug_malloc2", 157 "dso", 158 "dynlock", 159 "engine", 160 "ui", 161 "ecdsa", 162 "ec", 163 "ecdh", 164 "bn", 165 "ec_pre_comp", 166 "store", 167 "comp", 168#ifndef OPENSSL_FIPS 169# if CRYPTO_NUM_LOCKS != 39 170# error "Inconsistency between crypto.h and cryptlib.c" 171# endif 172#else 173 "fips", 174 "fips2", 175# if CRYPTO_NUM_LOCKS != 41 176# error "Inconsistency between crypto.h and cryptlib.c" 177# endif 178#endif 179}; 180 181/* 182 * This is for applications to allocate new type names in the non-dynamic 183 * array of lock names. These are numbered with positive numbers. 184 */ 185static STACK *app_locks = NULL; 186 187/* 188 * For applications that want a more dynamic way of handling threads, the 189 * following stack is used. These are externally numbered with negative 190 * numbers. 191 */ 192static STACK_OF(CRYPTO_dynlock) *dyn_locks = NULL; 193 194static struct CRYPTO_dynlock_value *(MS_FAR *dynlock_create_callback) 195 (const char *file, int line) = NULL; 196static void (MS_FAR *dynlock_lock_callback) (int mode, 197 struct CRYPTO_dynlock_value *l, 198 const char *file, int line) = 199 NULL; 200static void (MS_FAR *dynlock_destroy_callback) (struct CRYPTO_dynlock_value 201 *l, const char *file, 202 int line) = NULL; 203 204int CRYPTO_get_new_lockid(char *name) 205{ 206 char *str; 207 int i; 208 209#if defined(OPENSSL_SYS_WIN32) || defined(OPENSSL_SYS_WIN16) 210 /* 211 * A hack to make Visual C++ 5.0 work correctly when linking as a DLL 212 * using /MT. Without this, the application cannot use and floating point 213 * printf's. It also seems to be needed for Visual C 1.5 (win16) 214 */ 215 SSLeay_MSVC5_hack = (double)name[0] * (double)name[1]; 216#endif 217 218 if ((app_locks == NULL) && ((app_locks = sk_new_null()) == NULL)) { 219 CRYPTOerr(CRYPTO_F_CRYPTO_GET_NEW_LOCKID, ERR_R_MALLOC_FAILURE); 220 return (0); 221 } 222 if ((str = BUF_strdup(name)) == NULL) { 223 CRYPTOerr(CRYPTO_F_CRYPTO_GET_NEW_LOCKID, ERR_R_MALLOC_FAILURE); 224 return (0); 225 } 226 i = sk_push(app_locks, str); 227 if (!i) 228 OPENSSL_free(str); 229 else 230 i += CRYPTO_NUM_LOCKS; /* gap of one :-) */ 231 return (i); 232} 233 234int CRYPTO_get_new_dynlockid(void) 235{ 236 int i = 0; 237 CRYPTO_dynlock *pointer = NULL; 238 239 if (dynlock_create_callback == NULL) { 240 CRYPTOerr(CRYPTO_F_CRYPTO_GET_NEW_DYNLOCKID, 241 CRYPTO_R_NO_DYNLOCK_CREATE_CALLBACK); 242 return (0); 243 } 244 CRYPTO_w_lock(CRYPTO_LOCK_DYNLOCK); 245 if ((dyn_locks == NULL) 246 && ((dyn_locks = sk_CRYPTO_dynlock_new_null()) == NULL)) { 247 CRYPTO_w_unlock(CRYPTO_LOCK_DYNLOCK); 248 CRYPTOerr(CRYPTO_F_CRYPTO_GET_NEW_DYNLOCKID, ERR_R_MALLOC_FAILURE); 249 return (0); 250 } 251 CRYPTO_w_unlock(CRYPTO_LOCK_DYNLOCK); 252 253 pointer = (CRYPTO_dynlock *) OPENSSL_malloc(sizeof(CRYPTO_dynlock)); 254 if (pointer == NULL) { 255 CRYPTOerr(CRYPTO_F_CRYPTO_GET_NEW_DYNLOCKID, ERR_R_MALLOC_FAILURE); 256 return (0); 257 } 258 pointer->references = 1; 259 pointer->data = dynlock_create_callback(__FILE__, __LINE__); 260 if (pointer->data == NULL) { 261 OPENSSL_free(pointer); 262 CRYPTOerr(CRYPTO_F_CRYPTO_GET_NEW_DYNLOCKID, ERR_R_MALLOC_FAILURE); 263 return (0); 264 } 265 266 CRYPTO_w_lock(CRYPTO_LOCK_DYNLOCK); 267 /* First, try to find an existing empty slot */ 268 i = sk_CRYPTO_dynlock_find(dyn_locks, NULL); 269 /* If there was none, push, thereby creating a new one */ 270 if (i == -1) 271 /* 272 * Since sk_push() returns the number of items on the stack, not the 273 * location of the pushed item, we need to transform the returned 274 * number into a position, by decreasing it. 275 */ 276 i = sk_CRYPTO_dynlock_push(dyn_locks, pointer) - 1; 277 else 278 /* 279 * If we found a place with a NULL pointer, put our pointer in it. 280 */ 281 (void)sk_CRYPTO_dynlock_set(dyn_locks, i, pointer); 282 CRYPTO_w_unlock(CRYPTO_LOCK_DYNLOCK); 283 284 if (i == -1) { 285 dynlock_destroy_callback(pointer->data, __FILE__, __LINE__); 286 OPENSSL_free(pointer); 287 } else 288 i += 1; /* to avoid 0 */ 289 return -i; 290} 291 292void CRYPTO_destroy_dynlockid(int i) 293{ 294 CRYPTO_dynlock *pointer = NULL; 295 if (i) 296 i = -i - 1; 297 if (dynlock_destroy_callback == NULL) 298 return; 299 300 CRYPTO_w_lock(CRYPTO_LOCK_DYNLOCK); 301 302 if (dyn_locks == NULL || i >= sk_CRYPTO_dynlock_num(dyn_locks)) { 303 CRYPTO_w_unlock(CRYPTO_LOCK_DYNLOCK); 304 return; 305 } 306 pointer = sk_CRYPTO_dynlock_value(dyn_locks, i); 307 if (pointer != NULL) { 308 --pointer->references; 309#ifdef REF_CHECK 310 if (pointer->references < 0) { 311 fprintf(stderr, 312 "CRYPTO_destroy_dynlockid, bad reference count\n"); 313 abort(); 314 } else 315#endif 316 if (pointer->references <= 0) { 317 (void)sk_CRYPTO_dynlock_set(dyn_locks, i, NULL); 318 } else 319 pointer = NULL; 320 } 321 CRYPTO_w_unlock(CRYPTO_LOCK_DYNLOCK); 322 323 if (pointer) { 324 dynlock_destroy_callback(pointer->data, __FILE__, __LINE__); 325 OPENSSL_free(pointer); 326 } 327} 328 329struct CRYPTO_dynlock_value *CRYPTO_get_dynlock_value(int i) 330{ 331 CRYPTO_dynlock *pointer = NULL; 332 if (i) 333 i = -i - 1; 334 335 CRYPTO_w_lock(CRYPTO_LOCK_DYNLOCK); 336 337 if (dyn_locks != NULL && i < sk_CRYPTO_dynlock_num(dyn_locks)) 338 pointer = sk_CRYPTO_dynlock_value(dyn_locks, i); 339 if (pointer) 340 pointer->references++; 341 342 CRYPTO_w_unlock(CRYPTO_LOCK_DYNLOCK); 343 344 if (pointer) 345 return pointer->data; 346 return NULL; 347} 348 349struct CRYPTO_dynlock_value *(*CRYPTO_get_dynlock_create_callback(void)) 350 (const char *file, int line) { 351 return (dynlock_create_callback); 352} 353 354void (*CRYPTO_get_dynlock_lock_callback(void)) (int mode, 355 struct CRYPTO_dynlock_value 356 *l, const char *file, 357 int line) { 358 return (dynlock_lock_callback); 359} 360 361void (*CRYPTO_get_dynlock_destroy_callback(void)) 362 (struct CRYPTO_dynlock_value *l, const char *file, int line) { 363 return (dynlock_destroy_callback); 364} 365 366void CRYPTO_set_dynlock_create_callback(struct CRYPTO_dynlock_value *(*func) 367 (const char *file, int line)) 368{ 369 dynlock_create_callback = func; 370} 371 372static void do_dynlock(int mode, int type, const char *file, int line) 373{ 374 if (dynlock_lock_callback != NULL) { 375 struct CRYPTO_dynlock_value *pointer = CRYPTO_get_dynlock_value(type); 376 377 OPENSSL_assert(pointer != NULL); 378 379 dynlock_lock_callback(mode, pointer, file, line); 380 381 CRYPTO_destroy_dynlockid(type); 382 } 383} 384 385void CRYPTO_set_dynlock_lock_callback(void (*func) (int mode, 386 struct 387 CRYPTO_dynlock_value *l, 388 const char *file, 389 int line)) 390{ 391 /* 392 * Set callback so CRYPTO_lock() can now handle dynamic locks. This is OK 393 * because at this point and application shouldn't be using OpenSSL from 394 * multiple threads because it is setting up the locking callbacks. 395 */ 396 static int done = 0; 397 if (!done) { 398 int_CRYPTO_set_do_dynlock_callback(do_dynlock); 399 done = 1; 400 } 401 402 dynlock_lock_callback = func; 403} 404 405void CRYPTO_set_dynlock_destroy_callback(void (*func) 406 (struct CRYPTO_dynlock_value *l, 407 const char *file, int line)) 408{ 409 dynlock_destroy_callback = func; 410} 411 412const char *CRYPTO_get_lock_name(int type) 413{ 414 if (type < 0) 415 return ("dynamic"); 416 else if (type < CRYPTO_NUM_LOCKS) 417 return (lock_names[type]); 418 else if (type - CRYPTO_NUM_LOCKS > sk_num(app_locks)) 419 return ("ERROR"); 420 else 421 return (sk_value(app_locks, type - CRYPTO_NUM_LOCKS)); 422} 423