Merge "res_rtp_asterisk.c: Fix rtp source address learning for broken clients"
[asterisk/asterisk.git] / main / libasteriskssl.c
1 /*
2  * Asterisk -- An open source telephony toolkit.
3  *
4  * Copyright (C) 2009-2012, Digium, Inc.
5  *
6  * Russell Bryant <russell@digium.com>
7  *
8  * See http://www.asterisk.org for more information about
9  * the Asterisk project. Please do not directly contact
10  * any of the maintainers of this project for assistance;
11  * the project provides a web site, mailing lists and IRC
12  * channels for your use.
13  *
14  * This program is free software, distributed under the terms of
15  * the GNU General Public License Version 2. See the LICENSE file
16  * at the top of the source tree.
17  */
18
19 /*!
20  * \file
21  * \brief Common OpenSSL support code
22  *
23  * \author Russell Bryant <russell@digium.com>
24  */
25
26 /*** MODULEINFO
27         <support_level>core</support_level>
28  ***/
29
30 #include "asterisk.h"
31
32 #include "asterisk/_private.h" /* ast_ssl_init() */
33
34 #ifdef HAVE_OPENSSL
35 #include <openssl/ssl.h>
36 #include <openssl/err.h>
37 #endif
38
39 #if defined(HAVE_OPENSSL) && \
40         (!defined(OPENSSL_VERSION_NUMBER) || OPENSSL_VERSION_NUMBER < 0x10100000L || defined(LIBRESSL_VERSION_NUMBER))
41
42 #include <dlfcn.h>
43
44 #include "asterisk/utils.h"
45 #include "asterisk/lock.h"
46
47 #define get_OpenSSL_function(func) do { real_##func = dlsym(RTLD_NEXT, __stringify(func)); } while(0)
48
49 static int startup_complete;
50
51 static ast_mutex_t *ssl_locks;
52
53 static int ssl_num_locks;
54
55 static unsigned long ssl_threadid(void)
56 {
57         return (unsigned long) pthread_self();
58 }
59
60 static void ssl_lock(int mode, int n, const char *file, int line)
61 {
62         if (n < 0 || n >= ssl_num_locks) {
63                 ast_log(LOG_ERROR, "OpenSSL is full of LIES!!! - "
64                                 "ssl_num_locks '%d' - n '%d'\n",
65                                 ssl_num_locks, n);
66                 return;
67         }
68
69         if (mode & 0x1) {
70                 ast_mutex_lock(&ssl_locks[n]);
71         } else {
72                 ast_mutex_unlock(&ssl_locks[n]);
73         }
74 }
75
76 int SSL_library_init(void)
77 {
78 #if defined(AST_DEVMODE)
79         if (startup_complete) {
80                 ast_debug(1, "Called after startup... ignoring!\n");
81         }
82 #endif
83         return 1;
84 }
85
86 void SSL_load_error_strings(void)
87 {
88 #if defined(AST_DEVMODE)
89         if (startup_complete) {
90                 ast_debug(1, "Called after startup... ignoring!\n");
91         }
92 #endif
93 }
94
95 void CRYPTO_set_id_callback(unsigned long (*func)(void))
96 {
97 #if defined(AST_DEVMODE)
98         if (startup_complete) {
99                 ast_debug(1, "Called after startup... ignoring!\n");
100         }
101 #endif
102 }
103
104 void CRYPTO_set_locking_callback(void (*func)(int mode,int type, const char *file, int line))
105 {
106 #if defined(AST_DEVMODE)
107         if (startup_complete) {
108                 ast_debug(1, "Called after startup... ignoring!\n");
109         }
110 #endif
111 }
112
113 void ERR_free_strings(void)
114 {
115         /* we can't allow this to be called, ever */
116 }
117
118 /*!
119  * \internal
120  * \brief Common OpenSSL initialization for all of Asterisk.
121  *
122  * Not needed for OpenSSL versions >= 1.1.0
123  */
124 int ast_ssl_init(void)
125 {
126         unsigned int i;
127         int (*real_SSL_library_init)(void);
128         void (*real_CRYPTO_set_id_callback)(unsigned long (*)(void));
129         void (*real_CRYPTO_set_locking_callback)(void (*)(int, int, const char *, int));
130         void (*real_SSL_load_error_strings)(void);
131         const char *errstr;
132
133         /* clear any previous dynamic linker errors */
134         dlerror();
135         get_OpenSSL_function(SSL_library_init);
136         if ((errstr = dlerror()) != NULL) {
137                 ast_debug(1, "unable to get real address of SSL_library_init: %s\n", errstr);
138                 /* there is no way to continue in this situation... SSL will
139                  * likely be broken in this process
140                  */
141                 return -1;
142         } else {
143                 real_SSL_library_init();
144         }
145
146         /* Make OpenSSL usage thread-safe. */
147
148         dlerror();
149         get_OpenSSL_function(CRYPTO_set_id_callback);
150         if ((errstr = dlerror()) != NULL) {
151                 ast_debug(1, "unable to get real address of CRYPTO_set_id_callback: %s\n", errstr);
152                 /* there is no way to continue in this situation... SSL will
153                  * likely be broken in this process
154                  */
155                 return -1;
156         } else {
157                 real_CRYPTO_set_id_callback(ssl_threadid);
158         }
159
160         dlerror();
161         get_OpenSSL_function(CRYPTO_set_locking_callback);
162         if ((errstr = dlerror()) != NULL) {
163                 ast_debug(1, "unable to get real address of CRYPTO_set_locking_callback: %s\n", errstr);
164                 /* there is no way to continue in this situation... SSL will
165                  * likely be broken in this process
166                  */
167                 return -1;
168         } else {
169                 ssl_num_locks = CRYPTO_num_locks();
170                 if (!(ssl_locks = ast_calloc(ssl_num_locks, sizeof(ssl_locks[0])))) {
171                         return -1;
172                 }
173                 for (i = 0; i < ssl_num_locks; i++) {
174                         ast_mutex_init(&ssl_locks[i]);
175                 }
176                 real_CRYPTO_set_locking_callback(ssl_lock);
177         }
178
179         /* after this point, we don't check for errors from the dlsym() calls,
180          * under the assumption that if the ones above were successful, all
181          * the rest will be too. this assumption holds as long as OpenSSL still
182          * provides all of these functions.
183          */
184
185         get_OpenSSL_function(SSL_load_error_strings);
186         real_SSL_load_error_strings();
187
188         startup_complete = 1;
189
190         return 0;
191 }
192
193 #else
194
195 int ast_ssl_init(void)
196 {
197         return 0;
198 }
199
200 #endif