]> CyberLeo.Net >> Repos - FreeBSD/releng/9.3.git/blob - crypto/openssl/crypto/dyn_lck.c
Fix multiple OpenSSL vulnerabilities.
[FreeBSD/releng/9.3.git] / crypto / openssl / crypto / dyn_lck.c
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)
121 static double SSLeay_MSVC5_hack = 0.0; /* and for VC1.5 */
122 #endif
123
124 DECLARE_STACK_OF(CRYPTO_dynlock)
125 IMPLEMENT_STACK_OF(CRYPTO_dynlock)
126
127 /* real #defines in crypto.h, keep these upto date */
128 static 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  */
185 static 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  */
192 static STACK_OF(CRYPTO_dynlock) *dyn_locks = NULL;
193
194 static struct CRYPTO_dynlock_value *(MS_FAR *dynlock_create_callback)
195  (const char *file, int line) = NULL;
196 static void (MS_FAR *dynlock_lock_callback) (int mode,
197                                              struct CRYPTO_dynlock_value *l,
198                                              const char *file, int line) =
199     NULL;
200 static void (MS_FAR *dynlock_destroy_callback) (struct CRYPTO_dynlock_value
201                                                 *l, const char *file,
202                                                 int line) = NULL;
203
204 int 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
234 int 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
292 void 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
329 struct 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
349 struct CRYPTO_dynlock_value *(*CRYPTO_get_dynlock_create_callback(void))
350  (const char *file, int line) {
351     return (dynlock_create_callback);
352 }
353
354 void (*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
361 void (*CRYPTO_get_dynlock_destroy_callback(void))
362  (struct CRYPTO_dynlock_value *l, const char *file, int line) {
363     return (dynlock_destroy_callback);
364 }
365
366 void CRYPTO_set_dynlock_create_callback(struct CRYPTO_dynlock_value *(*func)
367                                          (const char *file, int line))
368 {
369     dynlock_create_callback = func;
370 }
371
372 static 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
385 void 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
405 void 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
412 const 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 }