Line data Source code
1 : /*
2 : START OF LICENSE STUB
3 : DeDOS: Declarative Dispersion-Oriented Software
4 : Copyright (C) 2017 University of Pennsylvania, Georgetown University
5 :
6 : This program is free software: you can redistribute it and/or modify
7 : it under the terms of the GNU General Public License as published by
8 : the Free Software Foundation, either version 3 of the License, or
9 : (at your option) any later version.
10 :
11 : This program is distributed in the hope that it will be useful,
12 : but WITHOUT ANY WARRANTY; without even the implied warranty of
13 : MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 : GNU General Public License for more details.
15 :
16 : You should have received a copy of the GNU General Public License
17 : along with this program. If not, see <http://www.gnu.org/licenses/>.
18 : END OF LICENSE STUB
19 : */
20 : #include "webserver/sslops.h"
21 : #include "webserver/webserver.h"
22 : #include "logging.h"
23 : #include <pthread.h>
24 : #include <openssl/err.h>
25 :
26 : #ifdef __GNUC__
27 : #define UNUSED __attribute__ ((unused))
28 : #else
29 : #define UNUSED
30 : #endif
31 :
32 : //#define PRINT_REQUEST_ERRORS
33 :
34 : #ifdef PRINT_REQUEST_ERRORS
35 : #define print_request_error(fmt, ...)\
36 : log_error(fmt, ##__VA_ARGS__);
37 : #else
38 : #define print_request_error(...)
39 : #endif
40 :
41 : /**
42 : * Explains an SSL error. Written as a macro so we have traceability in the log_error statements
43 : */
44 : //FIXME: calling ERR_get_error in the case SSL_ERROR_SSL breaks consistency of this function
45 : // (which otherwise reads the stack and doesn't pop it)
46 : #ifdef PRINT_REQUEST_ERRORS
47 : #define print_ssl_error(ssl, rtn) { \
48 : int _err = SSL_get_error(ssl, rtn); \
49 : const char* UNUSED error_str = ERR_error_string(_err, NULL); \
50 : switch (_err) { \
51 : case SSL_ERROR_ZERO_RETURN: { \
52 : print_request_error("SSL_ERROR_ZERO_RETURN (%d): %s\n", _err, error_str); \
53 : break; \
54 : } \
55 : case SSL_ERROR_WANT_READ: { \
56 : print_request_error("SSL_ERROR_WANT_READ (%d): %s\n", _err, error_str);\
57 : break;\
58 : }\
59 : case SSL_ERROR_WANT_WRITE: {\
60 : print_request_error("SSL_ERROR_WANT_WRITE (%d): %s\n", _err, error_str);\
61 : break;\
62 : }\
63 : case SSL_ERROR_WANT_CONNECT: {\
64 : print_request_error("SSL_ERROR_WANT_CONNECT (%d): %s\n", _err, error_str);\
65 : break;\
66 : }\
67 : case SSL_ERROR_WANT_ACCEPT: {\
68 : print_request_error("SSL_ERROR_WANT_ACCEPT (%d): %s\n", _err, error_str);\
69 : break;\
70 : }\
71 : case SSL_ERROR_WANT_X509_LOOKUP: {\
72 : print_request_error("SSL_ERROR_WANT_X509_LOOKUP (%d): %s\n", _err, error_str);\
73 : break;\
74 : }\
75 : case SSL_ERROR_SYSCALL: {\
76 : print_request_error("SSL_ERROR_SYSCALL (%d): %s\n", _err, error_str);\
77 : break;\
78 : }\
79 : case SSL_ERROR_SSL: {\
80 : unsigned long UNUSED err2 = ERR_get_error(); \
81 : print_request_error("SSL_ERROR_SSL (%d, %lx): %s\n", _err, err2, error_str);\
82 : break;\
83 : }\
84 : default:\
85 : break;\
86 : }\
87 : }
88 : #else
89 : #define print_ssl_error(ssl, rtn)
90 : #endif
91 :
92 : static pthread_mutex_t *lockarray;
93 :
94 8751479 : static void crypto_locking_callback(int mode, int n,
95 : const char UNUSED *file, int UNUSED line) {
96 8751479 : if (mode & CRYPTO_LOCK) {
97 4375655 : pthread_mutex_lock(&(lockarray[n]));
98 : } else {
99 4375824 : pthread_mutex_unlock(&(lockarray[n]));
100 : }
101 8751988 : }
102 :
103 793132 : static unsigned long crypto_id_function(void) {
104 793132 : return (unsigned long)pthread_self();
105 : }
106 :
107 164 : void init_ssl_locks(void) {
108 : #if defined(OPENSSL_THREADS)
109 : #else
110 : log_error("no OPENSSL thread support!");
111 : #endif
112 164 : lockarray = OPENSSL_malloc(CRYPTO_num_locks() * sizeof(*lockarray));
113 6888 : for (int i=0; i < CRYPTO_num_locks(); i++) {
114 6724 : pthread_mutex_init(&(lockarray[i]), NULL);
115 : }
116 164 : CRYPTO_set_id_callback(crypto_id_function);
117 164 : CRYPTO_set_locking_callback(crypto_locking_callback);
118 164 : }
119 :
120 : SSL_CTX *ssl_ctx = NULL;
121 :
122 35 : void kill_ssl_locks(void) {
123 35 : CRYPTO_set_locking_callback(NULL);
124 1470 : for (int i=0; i<CRYPTO_num_locks(); i++) {
125 1435 : pthread_mutex_destroy(&(lockarray[i]));
126 : }
127 35 : if (ssl_ctx != NULL) {
128 35 : SSL_CTX_free(ssl_ctx);
129 35 : ssl_ctx = NULL;
130 : }
131 35 : }
132 :
133 :
134 40 : int init_ssl_context(void) {
135 40 : if (ssl_ctx != NULL) {
136 0 : log_warn("SSL context already initialized. Not initializing again.");
137 0 : return 1;
138 : }
139 :
140 40 : SSL_library_init();
141 40 : OpenSSL_add_all_algorithms();
142 40 : SSL_load_error_strings();
143 :
144 : /* Create new SSL context */
145 40 : const SSL_METHOD *method = TLSv1_2_server_method();
146 40 : ssl_ctx = SSL_CTX_new(method);
147 40 : SSL_CTX_set_session_cache_mode(ssl_ctx, SSL_SESS_CACHE_OFF);
148 40 : SSL_CTX_set_options(ssl_ctx,
149 : SSL_OP_NO_SSLv3 | SSL_OP_NO_TICKET | SSL_OP_SINGLE_DH_USE);
150 :
151 40 : int rtn = SSL_CTX_set_cipher_list(ssl_ctx, "HIGH:!aNULL:!MD5:!RC4");
152 40 : if ( rtn <= 0 ) {
153 0 : log_error("Could not set cipger list for SSL context");
154 0 : return -1;
155 : }
156 :
157 40 : return 0;
158 : }
159 :
160 40 : int load_ssl_certificate(char *cert_file, char *key_file) {
161 : /* set the local certificate from CertFile */
162 40 : if ( SSL_CTX_use_certificate_chain_file(ssl_ctx, cert_file) <= 0 ) {
163 0 : return -1;
164 : }
165 : /* set the private key from KeyFile (may be the same as CertFile) */
166 40 : if ( SSL_CTX_use_PrivateKey_file(ssl_ctx, cert_file, SSL_FILETYPE_PEM) <= 0 ) {
167 0 : return -1;
168 : }
169 : /* verify private key */
170 40 : if ( !SSL_CTX_check_private_key(ssl_ctx) ) {
171 0 : return -1;
172 : }
173 40 : return 0;
174 : }
175 :
176 148 : SSL *init_ssl_connection(int fd) {
177 148 : SSL *ssl = SSL_new(ssl_ctx);
178 148 : SSL_set_fd(ssl, fd);
179 148 : return ssl;
180 : }
181 :
182 : #define CHECK_SSL_WANTS(ssl, rtn) \
183 : do { \
184 : int err = SSL_get_error(ssl, rtn); \
185 : if (err != SSL_ERROR_WANT_READ && err != SSL_ERROR_WANT_WRITE) { \
186 : print_ssl_error(ssl, rtn); \
187 : return WS_ERROR; \
188 : } else if ( err == SSL_ERROR_WANT_READ) { \
189 : return WS_INCOMPLETE_READ; \
190 : } else if ( err == SSL_ERROR_WANT_WRITE) { \
191 : return WS_INCOMPLETE_WRITE; \
192 : } \
193 : } while (0);
194 :
195 294 : int accept_ssl(SSL *ssl) {
196 294 : ERR_clear_error();
197 294 : int rtn = SSL_accept(ssl);
198 294 : if (rtn == 0) {
199 0 : log_warn("The TLS/SSL handshake was not successful "
200 : "but was shut down controlled and by the "
201 : "specifications of the TLS/SSL protocol");
202 : print_ssl_error(ssl, rtn);
203 0 : return -1;
204 : }
205 294 : if (rtn < 0) {
206 148 : CHECK_SSL_WANTS(ssl, rtn);
207 : }
208 146 : return WS_COMPLETE;
209 : }
210 :
211 293 : int read_ssl(SSL *ssl, char *buf, int *buf_size) {
212 293 : ERR_clear_error();
213 293 : int num_bytes = SSL_read(ssl, buf, *buf_size);
214 293 : if (num_bytes > 0) {
215 144 : *buf_size = num_bytes;
216 144 : return WS_COMPLETE;
217 : } else {
218 149 : CHECK_SSL_WANTS(ssl, num_bytes);
219 : }
220 0 : log_warn("Shouldn't ever get here...");
221 0 : return WS_ERROR;
222 : }
223 :
224 281 : int write_ssl(SSL *ssl, char *buf, int *buf_size) {
225 281 : ERR_clear_error();
226 281 : int num_bytes = SSL_write(ssl, buf, *buf_size);
227 281 : if (num_bytes > 0) {
228 280 : if (num_bytes != *buf_size) {
229 0 : log_warn("Didn't write the requested amount (written: %d, requested: %d)...",
230 : num_bytes, *buf_size);
231 : }
232 280 : *buf_size = num_bytes;
233 280 : return WS_COMPLETE;
234 : } else {
235 1 : CHECK_SSL_WANTS(ssl, num_bytes);
236 : }
237 0 : log_warn("Shouldn't ever get here...");
238 0 : return WS_ERROR;
239 : }
240 :
241 142 : int close_ssl(SSL *ssl) {
242 142 : ERR_clear_error();
243 142 : int rtn = SSL_get_shutdown(ssl);
244 142 : if (rtn >= 0) {
245 142 : rtn = SSL_shutdown(ssl);
246 142 : if (rtn == -1) {
247 1 : log(WS_ERROR, "Error shutting down SSL connection");
248 1 : SSL_free(ssl);
249 1 : return WS_ERROR;
250 : }
251 141 : if (rtn == 0) {
252 : //See the man page to understand this way of handling error on SSL_shutdown()
253 : //TODO: need too handle WANT_READ and WANT_WRITE on BOTH calls
254 : //see https://stackoverflow.com/questions/28056056/handling-ssl-shutdown-correctly
255 141 : rtn = SSL_shutdown(ssl);
256 141 : if (rtn == -1) {
257 : // log_error("Error shutting down SSL connection");
258 107 : SSL_free(ssl);
259 107 : return WS_ERROR;
260 : }
261 : }
262 : }
263 :
264 34 : SSL_free(ssl);
265 34 : return WS_COMPLETE;
266 : }
|