1 /* crypto/cryptlib.c */ 2 /* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com) 3 * All rights reserved. 4 * 5 * This package is an SSL implementation written 6 * by Eric Young (eay@cryptsoft.com). 7 * The implementation was written so as to conform with Netscapes SSL. 8 * 9 * This library is free for commercial and non-commercial use as long as 10 * the following conditions are aheared to. The following conditions 11 * apply to all code found in this distribution, be it the RC4, RSA, 12 * lhash, DES, etc., code; not just the SSL code. The SSL documentation 13 * included with this distribution is covered by the same copyright terms 14 * except that the holder is Tim Hudson (tjh@cryptsoft.com). 15 * 16 * Copyright remains Eric Young's, and as such any Copyright notices in 17 * the code are not to be removed. 18 * If this package is used in a product, Eric Young should be given attribution 19 * as the author of the parts of the library used. 20 * This can be in the form of a textual message at program startup or 21 * in documentation (online or textual) provided with the package. 22 * 23 * Redistribution and use in source and binary forms, with or without 24 * modification, are permitted provided that the following conditions 25 * are met: 26 * 1. Redistributions of source code must retain the copyright 27 * notice, this list of conditions and the following disclaimer. 28 * 2. Redistributions in binary form must reproduce the above copyright 29 * notice, this list of conditions and the following disclaimer in the 30 * documentation and/or other materials provided with the distribution. 31 * 3. All advertising materials mentioning features or use of this software 32 * must display the following acknowledgement: 33 * "This product includes cryptographic software written by 34 * Eric Young (eay@cryptsoft.com)" 35 * The word 'cryptographic' can be left out if the rouines from the library 36 * being used are not cryptographic related :-). 37 * 4. If you include any Windows specific code (or a derivative thereof) from 38 * the apps directory (application code) you must include an acknowledgement: 39 * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)" 40 * 41 * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND 42 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 43 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 44 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 45 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 46 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 47 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 48 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 49 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 50 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 51 * SUCH DAMAGE. 52 * 53 * The licence and distribution terms for any publically available version or 54 * derivative of this code cannot be changed. i.e. this code cannot simply be 55 * copied and put under another distribution licence 56 * [including the GNU Public Licence.] 57 */ 58 59 #include <stdio.h> 60 #include <string.h> 61 #include "cryptlib.h" 62 #include <openssl/crypto.h> 63 #include <openssl/safestack.h> 64 65 #if defined(OPENSSL_SYS_WIN32) || defined(OPENSSL_SYS_WIN16) 66 static double SSLeay_MSVC5_hack=0.0; /* and for VC1.5 */ 67 #endif 68 69 DECLARE_STACK_OF(CRYPTO_dynlock) 70 IMPLEMENT_STACK_OF(CRYPTO_dynlock) 71 72 /* real #defines in crypto.h, keep these upto date */ 73 static const char* lock_names[CRYPTO_NUM_LOCKS] = 74 { 75 "<<ERROR>>", 76 "err", 77 "ex_data", 78 "x509", 79 "x509_info", 80 "x509_pkey", 81 "x509_crl", 82 "x509_req", 83 "dsa", 84 "rsa", 85 "evp_pkey", 86 "x509_store", 87 "ssl_ctx", 88 "ssl_cert", 89 "ssl_session", 90 "ssl_sess_cert", 91 "ssl", 92 "ssl_method", 93 "rand", 94 "rand2", 95 "debug_malloc", 96 "BIO", 97 "gethostbyname", 98 "getservbyname", 99 "readdir", 100 "RSA_blinding", 101 "dh", 102 "debug_malloc2", 103 "dso", 104 "dynlock", 105 "engine", 106 "ui", 107 "hwcrhk", /* This is a HACK which will disappear in 0.9.8 */ 108 "fips", 109 "fips2", 110 #if CRYPTO_NUM_LOCKS != 35 111 # error "Inconsistency between crypto.h and cryptlib.c" 112 #endif 113 }; 114 115 /* This is for applications to allocate new type names in the non-dynamic 116 array of lock names. These are numbered with positive numbers. */ 117 static STACK *app_locks=NULL; 118 119 /* For applications that want a more dynamic way of handling threads, the 120 following stack is used. These are externally numbered with negative 121 numbers. */ 122 static STACK_OF(CRYPTO_dynlock) *dyn_locks=NULL; 123 124 125 static void (MS_FAR *locking_callback)(int mode,int type, 126 const char *file,int line)=NULL; 127 static int (MS_FAR *add_lock_callback)(int *pointer,int amount, 128 int type,const char *file,int line)=NULL; 129 static unsigned long (MS_FAR *id_callback)(void)=NULL; 130 static struct CRYPTO_dynlock_value *(MS_FAR *dynlock_create_callback) 131 (const char *file,int line)=NULL; 132 static void (MS_FAR *dynlock_lock_callback)(int mode, 133 struct CRYPTO_dynlock_value *l, const char *file,int line)=NULL; 134 static void (MS_FAR *dynlock_destroy_callback)(struct CRYPTO_dynlock_value *l, 135 const char *file,int line)=NULL; 136 137 int CRYPTO_get_new_lockid(char *name) 138 { 139 char *str; 140 int i; 141 142 #if defined(OPENSSL_SYS_WIN32) || defined(OPENSSL_SYS_WIN16) 143 /* A hack to make Visual C++ 5.0 work correctly when linking as 144 * a DLL using /MT. Without this, the application cannot use 145 * and floating point printf's. 146 * It also seems to be needed for Visual C 1.5 (win16) */ 147 SSLeay_MSVC5_hack=(double)name[0]*(double)name[1]; 148 #endif 149 150 if ((app_locks == NULL) && ((app_locks=sk_new_null()) == NULL)) 151 { 152 CRYPTOerr(CRYPTO_F_CRYPTO_GET_NEW_LOCKID,ERR_R_MALLOC_FAILURE); 153 return(0); 154 } 155 if ((str=BUF_strdup(name)) == NULL) 156 { 157 CRYPTOerr(CRYPTO_F_CRYPTO_GET_NEW_LOCKID,ERR_R_MALLOC_FAILURE); 158 return(0); 159 } 160 i=sk_push(app_locks,str); 161 if (!i) 162 OPENSSL_free(str); 163 else 164 i+=CRYPTO_NUM_LOCKS; /* gap of one :-) */ 165 return(i); 166 } 167 168 int CRYPTO_num_locks(void) 169 { 170 return CRYPTO_NUM_LOCKS; 171 } 172 173 int CRYPTO_get_new_dynlockid(void) 174 { 175 int i = 0; 176 CRYPTO_dynlock *pointer = NULL; 177 178 if (dynlock_create_callback == NULL) 179 { 180 CRYPTOerr(CRYPTO_F_CRYPTO_GET_NEW_DYNLOCKID,CRYPTO_R_NO_DYNLOCK_CREATE_CALLBACK); 181 return(0); 182 } 183 CRYPTO_w_lock(CRYPTO_LOCK_DYNLOCK); 184 if ((dyn_locks == NULL) 185 && ((dyn_locks=sk_CRYPTO_dynlock_new_null()) == NULL)) 186 { 187 CRYPTO_w_unlock(CRYPTO_LOCK_DYNLOCK); 188 CRYPTOerr(CRYPTO_F_CRYPTO_GET_NEW_DYNLOCKID,ERR_R_MALLOC_FAILURE); 189 return(0); 190 } 191 CRYPTO_w_unlock(CRYPTO_LOCK_DYNLOCK); 192 193 pointer = (CRYPTO_dynlock *)OPENSSL_malloc(sizeof(CRYPTO_dynlock)); 194 if (pointer == NULL) 195 { 196 CRYPTOerr(CRYPTO_F_CRYPTO_GET_NEW_DYNLOCKID,ERR_R_MALLOC_FAILURE); 197 return(0); 198 } 199 pointer->references = 1; 200 pointer->data = dynlock_create_callback(__FILE__,__LINE__); 201 if (pointer->data == NULL) 202 { 203 OPENSSL_free(pointer); 204 CRYPTOerr(CRYPTO_F_CRYPTO_GET_NEW_DYNLOCKID,ERR_R_MALLOC_FAILURE); 205 return(0); 206 } 207 208 CRYPTO_w_lock(CRYPTO_LOCK_DYNLOCK); 209 /* First, try to find an existing empty slot */ 210 i=sk_CRYPTO_dynlock_find(dyn_locks,NULL); 211 /* If there was none, push, thereby creating a new one */ 212 if (i == -1) 213 /* Since sk_push() returns the number of items on the 214 stack, not the location of the pushed item, we need 215 to transform the returned number into a position, 216 by decreasing it. */ 217 i=sk_CRYPTO_dynlock_push(dyn_locks,pointer) - 1; 218 else 219 /* If we found a place with a NULL pointer, put our pointer 220 in it. */ 221 sk_CRYPTO_dynlock_set(dyn_locks,i,pointer); 222 CRYPTO_w_unlock(CRYPTO_LOCK_DYNLOCK); 223 224 if (i == -1) 225 { 226 dynlock_destroy_callback(pointer->data,__FILE__,__LINE__); 227 OPENSSL_free(pointer); 228 } 229 else 230 i += 1; /* to avoid 0 */ 231 return -i; 232 } 233 234 void CRYPTO_destroy_dynlockid(int i) 235 { 236 CRYPTO_dynlock *pointer = NULL; 237 if (i) 238 i = -i-1; 239 if (dynlock_destroy_callback == NULL) 240 return; 241 242 CRYPTO_w_lock(CRYPTO_LOCK_DYNLOCK); 243 244 if (dyn_locks == NULL || i >= sk_CRYPTO_dynlock_num(dyn_locks)) 245 { 246 CRYPTO_w_unlock(CRYPTO_LOCK_DYNLOCK); 247 return; 248 } 249 pointer = sk_CRYPTO_dynlock_value(dyn_locks, i); 250 if (pointer != NULL) 251 { 252 --pointer->references; 253 #ifdef REF_CHECK 254 if (pointer->references < 0) 255 { 256 fprintf(stderr,"CRYPTO_destroy_dynlockid, bad reference count\n"); 257 abort(); 258 } 259 else 260 #endif 261 if (pointer->references <= 0) 262 { 263 sk_CRYPTO_dynlock_set(dyn_locks, i, NULL); 264 } 265 else 266 pointer = NULL; 267 } 268 CRYPTO_w_unlock(CRYPTO_LOCK_DYNLOCK); 269 270 if (pointer) 271 { 272 dynlock_destroy_callback(pointer->data,__FILE__,__LINE__); 273 OPENSSL_free(pointer); 274 } 275 } 276 277 struct CRYPTO_dynlock_value *CRYPTO_get_dynlock_value(int i) 278 { 279 CRYPTO_dynlock *pointer = NULL; 280 if (i) 281 i = -i-1; 282 283 CRYPTO_w_lock(CRYPTO_LOCK_DYNLOCK); 284 285 if (dyn_locks != NULL && i < sk_CRYPTO_dynlock_num(dyn_locks)) 286 pointer = sk_CRYPTO_dynlock_value(dyn_locks, i); 287 if (pointer) 288 pointer->references++; 289 290 CRYPTO_w_unlock(CRYPTO_LOCK_DYNLOCK); 291 292 if (pointer) 293 return pointer->data; 294 return NULL; 295 } 296 297 struct CRYPTO_dynlock_value *(*CRYPTO_get_dynlock_create_callback(void)) 298 (const char *file,int line) 299 { 300 return(dynlock_create_callback); 301 } 302 303 void (*CRYPTO_get_dynlock_lock_callback(void))(int mode, 304 struct CRYPTO_dynlock_value *l, const char *file,int line) 305 { 306 return(dynlock_lock_callback); 307 } 308 309 void (*CRYPTO_get_dynlock_destroy_callback(void)) 310 (struct CRYPTO_dynlock_value *l, const char *file,int line) 311 { 312 return(dynlock_destroy_callback); 313 } 314 315 void CRYPTO_set_dynlock_create_callback(struct CRYPTO_dynlock_value *(*func) 316 (const char *file, int line)) 317 { 318 dynlock_create_callback=func; 319 } 320 321 void CRYPTO_set_dynlock_lock_callback(void (*func)(int mode, 322 struct CRYPTO_dynlock_value *l, const char *file, int line)) 323 { 324 dynlock_lock_callback=func; 325 } 326 327 void CRYPTO_set_dynlock_destroy_callback(void (*func) 328 (struct CRYPTO_dynlock_value *l, const char *file, int line)) 329 { 330 dynlock_destroy_callback=func; 331 } 332 333 334 void (*CRYPTO_get_locking_callback(void))(int mode,int type,const char *file, 335 int line) 336 { 337 return(locking_callback); 338 } 339 340 int (*CRYPTO_get_add_lock_callback(void))(int *num,int mount,int type, 341 const char *file,int line) 342 { 343 return(add_lock_callback); 344 } 345 346 void CRYPTO_set_locking_callback(void (*func)(int mode,int type, 347 const char *file,int line)) 348 { 349 locking_callback=func; 350 } 351 352 void CRYPTO_set_add_lock_callback(int (*func)(int *num,int mount,int type, 353 const char *file,int line)) 354 { 355 add_lock_callback=func; 356 } 357 358 unsigned long (*CRYPTO_get_id_callback(void))(void) 359 { 360 return(id_callback); 361 } 362 363 void CRYPTO_set_id_callback(unsigned long (*func)(void)) 364 { 365 id_callback=func; 366 } 367 368 unsigned long CRYPTO_thread_id(void) 369 { 370 unsigned long ret=0; 371 372 if (id_callback == NULL) 373 { 374 #ifdef OPENSSL_SYS_WIN16 375 ret=(unsigned long)GetCurrentTask(); 376 #elif defined(OPENSSL_SYS_WIN32) 377 ret=(unsigned long)GetCurrentThreadId(); 378 #elif defined(GETPID_IS_MEANINGLESS) 379 ret=1L; 380 #else 381 ret=(unsigned long)getpid(); 382 #endif 383 } 384 else 385 ret=id_callback(); 386 return(ret); 387 } 388 389 void CRYPTO_lock(int mode, int type, const char *file, int line) 390 { 391 #ifdef LOCK_DEBUG 392 { 393 char *rw_text,*operation_text; 394 395 if (mode & CRYPTO_LOCK) 396 operation_text="lock "; 397 else if (mode & CRYPTO_UNLOCK) 398 operation_text="unlock"; 399 else 400 operation_text="ERROR "; 401 402 if (mode & CRYPTO_READ) 403 rw_text="r"; 404 else if (mode & CRYPTO_WRITE) 405 rw_text="w"; 406 else 407 rw_text="ERROR"; 408 409 fprintf(stderr,"lock:%08lx:(%s)%s %-18s %s:%d\n", 410 CRYPTO_thread_id(), rw_text, operation_text, 411 CRYPTO_get_lock_name(type), file, line); 412 } 413 #endif 414 if (type < 0) 415 { 416 if (dynlock_lock_callback != NULL) 417 { 418 struct CRYPTO_dynlock_value *pointer 419 = CRYPTO_get_dynlock_value(type); 420 421 OPENSSL_assert(pointer != NULL); 422 423 dynlock_lock_callback(mode, pointer, file, line); 424 425 CRYPTO_destroy_dynlockid(type); 426 } 427 } 428 else 429 if (locking_callback != NULL) 430 locking_callback(mode,type,file,line); 431 } 432 433 int CRYPTO_add_lock(int *pointer, int amount, int type, const char *file, 434 int line) 435 { 436 int ret = 0; 437 438 if (add_lock_callback != NULL) 439 { 440 #ifdef LOCK_DEBUG 441 int before= *pointer; 442 #endif 443 444 ret=add_lock_callback(pointer,amount,type,file,line); 445 #ifdef LOCK_DEBUG 446 fprintf(stderr,"ladd:%08lx:%2d+%2d->%2d %-18s %s:%d\n", 447 CRYPTO_thread_id(), 448 before,amount,ret, 449 CRYPTO_get_lock_name(type), 450 file,line); 451 #endif 452 } 453 else 454 { 455 CRYPTO_lock(CRYPTO_LOCK|CRYPTO_WRITE,type,file,line); 456 457 ret= *pointer+amount; 458 #ifdef LOCK_DEBUG 459 fprintf(stderr,"ladd:%08lx:%2d+%2d->%2d %-18s %s:%d\n", 460 CRYPTO_thread_id(), 461 *pointer,amount,ret, 462 CRYPTO_get_lock_name(type), 463 file,line); 464 #endif 465 *pointer=ret; 466 CRYPTO_lock(CRYPTO_UNLOCK|CRYPTO_WRITE,type,file,line); 467 } 468 return(ret); 469 } 470 471 const char *CRYPTO_get_lock_name(int type) 472 { 473 if (type < 0) 474 return("dynamic"); 475 else if (type < CRYPTO_NUM_LOCKS) 476 return(lock_names[type]); 477 else if (type-CRYPTO_NUM_LOCKS > sk_num(app_locks)) 478 return("ERROR"); 479 else 480 return(sk_value(app_locks,type-CRYPTO_NUM_LOCKS)); 481 } 482 483 #ifdef _DLL 484 #ifdef OPENSSL_SYS_WIN32 485 486 /* All we really need to do is remove the 'error' state when a thread 487 * detaches */ 488 489 BOOL WINAPI DLLEntryPoint(HINSTANCE hinstDLL, DWORD fdwReason, 490 LPVOID lpvReserved) 491 { 492 switch(fdwReason) 493 { 494 case DLL_PROCESS_ATTACH: 495 break; 496 case DLL_THREAD_ATTACH: 497 break; 498 case DLL_THREAD_DETACH: 499 ERR_remove_state(0); 500 break; 501 case DLL_PROCESS_DETACH: 502 break; 503 } 504 return(TRUE); 505 } 506 #endif 507 508 #endif 509 510 void OpenSSLDie(const char *file,int line,const char *assertion) 511 { 512 fprintf(stderr, 513 "%s(%d): OpenSSL internal error, assertion failed: %s\n", 514 file,line,assertion); 515 abort(); 516 } 517 518 #ifdef OPENSSL_FIPS 519 static int fips_started = 0; 520 static int fips_mode = 0; 521 static void *fips_rand_check = 0; 522 static unsigned long fips_thread = 0; 523 524 void fips_set_started(void) 525 { 526 fips_started = 1; 527 } 528 529 int fips_is_started(void) 530 { 531 return fips_started; 532 } 533 534 int fips_is_owning_thread(void) 535 { 536 int ret = 0; 537 538 if (fips_is_started()) 539 { 540 CRYPTO_r_lock(CRYPTO_LOCK_FIPS2); 541 if (fips_thread != 0 && fips_thread == CRYPTO_thread_id()) 542 ret = 1; 543 CRYPTO_r_unlock(CRYPTO_LOCK_FIPS2); 544 } 545 return ret; 546 } 547 548 int fips_set_owning_thread(void) 549 { 550 int ret = 0; 551 552 if (fips_is_started()) 553 { 554 CRYPTO_w_lock(CRYPTO_LOCK_FIPS2); 555 if (fips_thread == 0) 556 { 557 fips_thread = CRYPTO_thread_id(); 558 ret = 1; 559 } 560 CRYPTO_w_unlock(CRYPTO_LOCK_FIPS2); 561 } 562 return ret; 563 } 564 565 int fips_clear_owning_thread(void) 566 { 567 int ret = 0; 568 569 if (fips_is_started()) 570 { 571 CRYPTO_w_lock(CRYPTO_LOCK_FIPS2); 572 if (fips_thread == CRYPTO_thread_id()) 573 { 574 fips_thread = 0; 575 ret = 1; 576 } 577 CRYPTO_w_unlock(CRYPTO_LOCK_FIPS2); 578 } 579 return ret; 580 } 581 582 void fips_set_mode(int onoff) 583 { 584 int owning_thread = fips_is_owning_thread(); 585 586 if (fips_is_started()) 587 { 588 if (!owning_thread) CRYPTO_w_lock(CRYPTO_LOCK_FIPS); 589 fips_mode = onoff; 590 if (!owning_thread) CRYPTO_w_unlock(CRYPTO_LOCK_FIPS); 591 } 592 } 593 594 void fips_set_rand_check(void *rand_check) 595 { 596 int owning_thread = fips_is_owning_thread(); 597 598 if (fips_is_started()) 599 { 600 if (!owning_thread) CRYPTO_w_lock(CRYPTO_LOCK_FIPS); 601 fips_rand_check = rand_check; 602 if (!owning_thread) CRYPTO_w_unlock(CRYPTO_LOCK_FIPS); 603 } 604 } 605 606 int FIPS_mode(void) 607 { 608 int ret = 0; 609 int owning_thread = fips_is_owning_thread(); 610 611 if (fips_is_started()) 612 { 613 if (!owning_thread) CRYPTO_r_lock(CRYPTO_LOCK_FIPS); 614 ret = fips_mode; 615 if (!owning_thread) CRYPTO_r_unlock(CRYPTO_LOCK_FIPS); 616 } 617 return ret; 618 } 619 620 void *FIPS_rand_check(void) 621 { 622 void *ret = 0; 623 int owning_thread = fips_is_owning_thread(); 624 625 if (fips_is_started()) 626 { 627 if (!owning_thread) CRYPTO_r_lock(CRYPTO_LOCK_FIPS); 628 ret = fips_rand_check; 629 if (!owning_thread) CRYPTO_r_unlock(CRYPTO_LOCK_FIPS); 630 } 631 return ret; 632 } 633 634 #endif /* OPENSSL_FIPS */ 635 636