Add ECDH support.
[openssl.git] / crypto / cryptlib.c
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  * Copyright 2002 Sun Microsystems, Inc. ALL RIGHTS RESERVED.
60  * ECDH support in OpenSSL originally developed by 
61  * SUN MICROSYSTEMS, INC., and contributed to the OpenSSL project.
62  */
63
64 #include <stdio.h>
65 #include <string.h>
66 #include "cryptlib.h"
67 #include <openssl/crypto.h>
68 #include <openssl/safestack.h>
69
70 #if defined(OPENSSL_SYS_WIN32) || defined(OPENSSL_SYS_WIN16)
71 static double SSLeay_MSVC5_hack=0.0; /* and for VC1.5 */
72 #endif
73
74 DECLARE_STACK_OF(CRYPTO_dynlock)
75 IMPLEMENT_STACK_OF(CRYPTO_dynlock)
76
77 /* real #defines in crypto.h, keep these upto date */
78 static const char* lock_names[CRYPTO_NUM_LOCKS] =
79         {
80         "<<ERROR>>",
81         "err",
82         "ex_data",
83         "x509",
84         "x509_info",
85         "x509_pkey",
86         "x509_crl",
87         "x509_req",
88         "dsa",
89         "rsa",
90         "evp_pkey",
91         "x509_store",
92         "ssl_ctx",
93         "ssl_cert",
94         "ssl_session",
95         "ssl_sess_cert",
96         "ssl",
97         "rand",
98         "rand2",
99         "debug_malloc",
100         "BIO",
101         "gethostbyname",
102         "getservbyname",
103         "readdir",
104         "RSA_blinding",
105         "dh",
106         "debug_malloc2",
107         "dso",
108         "dynlock",
109         "engine",
110         "ui",
111         "ecdsa",
112         "ec",
113         "ecdh",
114 #if CRYPTO_NUM_LOCKS != 34
115 # error "Inconsistency between crypto.h and cryptlib.c"
116 #endif
117         };
118
119 /* This is for applications to allocate new type names in the non-dynamic
120    array of lock names.  These are numbered with positive numbers.  */
121 static STACK *app_locks=NULL;
122
123 /* For applications that want a more dynamic way of handling threads, the
124    following stack is used.  These are externally numbered with negative
125    numbers.  */
126 static STACK_OF(CRYPTO_dynlock) *dyn_locks=NULL;
127
128
129 static void (MS_FAR *locking_callback)(int mode,int type,
130         const char *file,int line)=NULL;
131 static int (MS_FAR *add_lock_callback)(int *pointer,int amount,
132         int type,const char *file,int line)=NULL;
133 static unsigned long (MS_FAR *id_callback)(void)=NULL;
134 static struct CRYPTO_dynlock_value *(MS_FAR *dynlock_create_callback)
135         (const char *file,int line)=NULL;
136 static void (MS_FAR *dynlock_lock_callback)(int mode,
137         struct CRYPTO_dynlock_value *l, const char *file,int line)=NULL;
138 static void (MS_FAR *dynlock_destroy_callback)(struct CRYPTO_dynlock_value *l,
139         const char *file,int line)=NULL;
140
141 int CRYPTO_get_new_lockid(char *name)
142         {
143         char *str;
144         int i;
145
146 #if defined(OPENSSL_SYS_WIN32) || defined(OPENSSL_SYS_WIN16)
147         /* A hack to make Visual C++ 5.0 work correctly when linking as
148          * a DLL using /MT. Without this, the application cannot use
149          * and floating point printf's.
150          * It also seems to be needed for Visual C 1.5 (win16) */
151         SSLeay_MSVC5_hack=(double)name[0]*(double)name[1];
152 #endif
153
154         if ((app_locks == NULL) && ((app_locks=sk_new_null()) == NULL))
155                 {
156                 CRYPTOerr(CRYPTO_F_CRYPTO_GET_NEW_LOCKID,ERR_R_MALLOC_FAILURE);
157                 return(0);
158                 }
159         if ((str=BUF_strdup(name)) == NULL)
160                 {
161                 CRYPTOerr(CRYPTO_F_CRYPTO_GET_NEW_LOCKID,ERR_R_MALLOC_FAILURE);
162                 return(0);
163                 }
164         i=sk_push(app_locks,str);
165         if (!i)
166                 OPENSSL_free(str);
167         else
168                 i+=CRYPTO_NUM_LOCKS; /* gap of one :-) */
169         return(i);
170         }
171
172 int CRYPTO_num_locks(void)
173         {
174         return CRYPTO_NUM_LOCKS;
175         }
176
177 int CRYPTO_get_new_dynlockid(void)
178         {
179         int i = 0;
180         CRYPTO_dynlock *pointer = NULL;
181
182         if (dynlock_create_callback == NULL)
183                 {
184                 CRYPTOerr(CRYPTO_F_CRYPTO_GET_NEW_DYNLOCKID,CRYPTO_R_NO_DYNLOCK_CREATE_CALLBACK);
185                 return(0);
186                 }
187         CRYPTO_w_lock(CRYPTO_LOCK_DYNLOCK);
188         if ((dyn_locks == NULL)
189                 && ((dyn_locks=sk_CRYPTO_dynlock_new_null()) == NULL))
190                 {
191                 CRYPTO_w_unlock(CRYPTO_LOCK_DYNLOCK);
192                 CRYPTOerr(CRYPTO_F_CRYPTO_GET_NEW_DYNLOCKID,ERR_R_MALLOC_FAILURE);
193                 return(0);
194                 }
195         CRYPTO_w_unlock(CRYPTO_LOCK_DYNLOCK);
196
197         pointer = (CRYPTO_dynlock *)OPENSSL_malloc(sizeof(CRYPTO_dynlock));
198         if (pointer == NULL)
199                 {
200                 CRYPTOerr(CRYPTO_F_CRYPTO_GET_NEW_DYNLOCKID,ERR_R_MALLOC_FAILURE);
201                 return(0);
202                 }
203         pointer->references = 1;
204         pointer->data = dynlock_create_callback(__FILE__,__LINE__);
205         if (pointer->data == NULL)
206                 {
207                 OPENSSL_free(pointer);
208                 CRYPTOerr(CRYPTO_F_CRYPTO_GET_NEW_DYNLOCKID,ERR_R_MALLOC_FAILURE);
209                 return(0);
210                 }
211
212         CRYPTO_w_lock(CRYPTO_LOCK_DYNLOCK);
213         /* First, try to find an existing empty slot */
214         i=sk_CRYPTO_dynlock_find(dyn_locks,NULL);
215         /* If there was none, push, thereby creating a new one */
216         if (i == -1)
217                 i=sk_CRYPTO_dynlock_push(dyn_locks,pointer);
218         CRYPTO_w_unlock(CRYPTO_LOCK_DYNLOCK);
219
220         if (!i)
221                 {
222                 dynlock_destroy_callback(pointer->data,__FILE__,__LINE__);
223                 OPENSSL_free(pointer);
224                 }
225         else
226                 i += 1; /* to avoid 0 */
227         return -i;
228         }
229
230 void CRYPTO_destroy_dynlockid(int i)
231         {
232         CRYPTO_dynlock *pointer = NULL;
233         if (i)
234                 i = -i-1;
235         if (dynlock_destroy_callback == NULL)
236                 return;
237
238         CRYPTO_w_lock(CRYPTO_LOCK_DYNLOCK);
239
240         if (dyn_locks == NULL || i >= sk_CRYPTO_dynlock_num(dyn_locks))
241                 {
242                 CRYPTO_w_unlock(CRYPTO_LOCK_DYNLOCK);
243                 return;
244                 }
245         pointer = sk_CRYPTO_dynlock_value(dyn_locks, i);
246         if (pointer != NULL)
247                 {
248                 --pointer->references;
249 #ifdef REF_CHECK
250                 if (pointer->references < 0)
251                         {
252                         fprintf(stderr,"CRYPTO_destroy_dynlockid, bad reference count\n");
253                         abort();
254                         }
255                 else
256 #endif
257                         if (pointer->references <= 0)
258                                 {
259                                 sk_CRYPTO_dynlock_set(dyn_locks, i, NULL);
260                                 }
261                         else
262                                 pointer = NULL;
263                 }
264         CRYPTO_w_unlock(CRYPTO_LOCK_DYNLOCK);
265
266         if (pointer)
267                 {
268                 dynlock_destroy_callback(pointer->data,__FILE__,__LINE__);
269                 OPENSSL_free(pointer);
270                 }
271         }
272
273 struct CRYPTO_dynlock_value *CRYPTO_get_dynlock_value(int i)
274         {
275         CRYPTO_dynlock *pointer = NULL;
276         if (i)
277                 i = -i-1;
278
279         CRYPTO_w_lock(CRYPTO_LOCK_DYNLOCK);
280
281         if (dyn_locks != NULL && i < sk_CRYPTO_dynlock_num(dyn_locks))
282                 pointer = sk_CRYPTO_dynlock_value(dyn_locks, i);
283         if (pointer)
284                 pointer->references++;
285
286         CRYPTO_w_unlock(CRYPTO_LOCK_DYNLOCK);
287
288         if (pointer)
289                 return pointer->data;
290         return NULL;
291         }
292
293 struct CRYPTO_dynlock_value *(*CRYPTO_get_dynlock_create_callback(void))
294         (const char *file,int line)
295         {
296         return(dynlock_create_callback);
297         }
298
299 void (*CRYPTO_get_dynlock_lock_callback(void))(int mode,
300         struct CRYPTO_dynlock_value *l, const char *file,int line)
301         {
302         return(dynlock_lock_callback);
303         }
304
305 void (*CRYPTO_get_dynlock_destroy_callback(void))
306         (struct CRYPTO_dynlock_value *l, const char *file,int line)
307         {
308         return(dynlock_destroy_callback);
309         }
310
311 void CRYPTO_set_dynlock_create_callback(struct CRYPTO_dynlock_value *(*func)
312         (const char *file, int line))
313         {
314         dynlock_create_callback=func;
315         }
316
317 void CRYPTO_set_dynlock_lock_callback(void (*func)(int mode,
318         struct CRYPTO_dynlock_value *l, const char *file, int line))
319         {
320         dynlock_lock_callback=func;
321         }
322
323 void CRYPTO_set_dynlock_destroy_callback(void (*func)
324         (struct CRYPTO_dynlock_value *l, const char *file, int line))
325         {
326         dynlock_destroy_callback=func;
327         }
328
329
330 void (*CRYPTO_get_locking_callback(void))(int mode,int type,const char *file,
331                 int line)
332         {
333         return(locking_callback);
334         }
335
336 int (*CRYPTO_get_add_lock_callback(void))(int *num,int mount,int type,
337                                           const char *file,int line)
338         {
339         return(add_lock_callback);
340         }
341
342 void CRYPTO_set_locking_callback(void (*func)(int mode,int type,
343                                               const char *file,int line))
344         {
345         locking_callback=func;
346         }
347
348 void CRYPTO_set_add_lock_callback(int (*func)(int *num,int mount,int type,
349                                               const char *file,int line))
350         {
351         add_lock_callback=func;
352         }
353
354 unsigned long (*CRYPTO_get_id_callback(void))(void)
355         {
356         return(id_callback);
357         }
358
359 void CRYPTO_set_id_callback(unsigned long (*func)(void))
360         {
361         id_callback=func;
362         }
363
364 unsigned long CRYPTO_thread_id(void)
365         {
366         unsigned long ret=0;
367
368         if (id_callback == NULL)
369                 {
370 #ifdef OPENSSL_SYS_WIN16
371                 ret=(unsigned long)GetCurrentTask();
372 #elif defined(OPENSSL_SYS_WIN32)
373                 ret=(unsigned long)GetCurrentThreadId();
374 #elif defined(GETPID_IS_MEANINGLESS)
375                 ret=1L;
376 #else
377                 ret=(unsigned long)getpid();
378 #endif
379                 }
380         else
381                 ret=id_callback();
382         return(ret);
383         }
384
385 void CRYPTO_lock(int mode, int type, const char *file, int line)
386         {
387 #ifdef LOCK_DEBUG
388                 {
389                 char *rw_text,*operation_text;
390
391                 if (mode & CRYPTO_LOCK)
392                         operation_text="lock  ";
393                 else if (mode & CRYPTO_UNLOCK)
394                         operation_text="unlock";
395                 else
396                         operation_text="ERROR ";
397
398                 if (mode & CRYPTO_READ)
399                         rw_text="r";
400                 else if (mode & CRYPTO_WRITE)
401                         rw_text="w";
402                 else
403                         rw_text="ERROR";
404
405                 fprintf(stderr,"lock:%08lx:(%s)%s %-18s %s:%d\n",
406                         CRYPTO_thread_id(), rw_text, operation_text,
407                         CRYPTO_get_lock_name(type), file, line);
408                 }
409 #endif
410         if (type < 0)
411                 {
412                 struct CRYPTO_dynlock_value *pointer
413                         = CRYPTO_get_dynlock_value(type);
414
415                 if (pointer && dynlock_lock_callback)
416                         {
417                         dynlock_lock_callback(mode, pointer, file, line);
418                         }
419
420                 CRYPTO_destroy_dynlockid(type);
421                 }
422         else
423                 if (locking_callback != NULL)
424                         locking_callback(mode,type,file,line);
425         }
426
427 int CRYPTO_add_lock(int *pointer, int amount, int type, const char *file,
428              int line)
429         {
430         int ret = 0;
431
432         if (add_lock_callback != NULL)
433                 {
434 #ifdef LOCK_DEBUG
435                 int before= *pointer;
436 #endif
437
438                 ret=add_lock_callback(pointer,amount,type,file,line);
439 #ifdef LOCK_DEBUG
440                 fprintf(stderr,"ladd:%08lx:%2d+%2d->%2d %-18s %s:%d\n",
441                         CRYPTO_thread_id(),
442                         before,amount,ret,
443                         CRYPTO_get_lock_name(type),
444                         file,line);
445 #endif
446                 }
447         else
448                 {
449                 CRYPTO_lock(CRYPTO_LOCK|CRYPTO_WRITE,type,file,line);
450
451                 ret= *pointer+amount;
452 #ifdef LOCK_DEBUG
453                 fprintf(stderr,"ladd:%08lx:%2d+%2d->%2d %-18s %s:%d\n",
454                         CRYPTO_thread_id(),
455                         *pointer,amount,ret,
456                         CRYPTO_get_lock_name(type),
457                         file,line);
458 #endif
459                 *pointer=ret;
460                 CRYPTO_lock(CRYPTO_UNLOCK|CRYPTO_WRITE,type,file,line);
461                 }
462         return(ret);
463         }
464
465 const char *CRYPTO_get_lock_name(int type)
466         {
467         if (type < 0)
468                 return("dynamic");
469         else if (type < CRYPTO_NUM_LOCKS)
470                 return(lock_names[type]);
471         else if (type-CRYPTO_NUM_LOCKS >= sk_num(app_locks))
472                 return("ERROR");
473         else
474                 return(sk_value(app_locks,type-CRYPTO_NUM_LOCKS));
475         }
476
477 #ifdef _DLL
478 #ifdef OPENSSL_SYS_WIN32
479
480 /* All we really need to do is remove the 'error' state when a thread
481  * detaches */
482
483 BOOL WINAPI DLLEntryPoint(HINSTANCE hinstDLL, DWORD fdwReason,
484              LPVOID lpvReserved)
485         {
486         switch(fdwReason)
487                 {
488         case DLL_PROCESS_ATTACH:
489                 break;
490         case DLL_THREAD_ATTACH:
491                 break;
492         case DLL_THREAD_DETACH:
493                 ERR_remove_state(0);
494                 break;
495         case DLL_PROCESS_DETACH:
496                 break;
497                 }
498         return(TRUE);
499         }
500 #endif
501
502 #endif