1 |
|
|
#if defined(USE_OPENSSL) |
2 |
|
|
|
3 |
|
|
#include <openssl/ssl.h> |
4 |
|
|
#include <openssl/pem.h> |
5 |
|
|
#include <openssl/err.h> |
6 |
|
|
#include <openssl/dh.h> |
7 |
|
|
|
8 |
|
|
#if defined(OPENSSL_IS_BORINGSSL) |
9 |
|
|
|
10 |
|
|
#include "b64.h" |
11 |
|
|
|
12 |
|
|
#else |
13 |
|
|
|
14 |
|
|
#include <openssl/bn.h> |
15 |
|
|
#include <openssl/bio.h> |
16 |
|
|
#include <openssl/evp.h> |
17 |
|
|
#include <openssl/buffer.h> |
18 |
|
|
|
19 |
|
|
#endif |
20 |
|
|
|
21 |
|
|
#elif defined(USE_WOLFSSL) |
22 |
|
|
|
23 |
|
|
#include <wolfssl/options.h> |
24 |
|
|
#include <wolfssl/ssl.h> |
25 |
|
|
#include "b64.h" |
26 |
|
|
|
27 |
|
|
#else |
28 |
|
|
|
29 |
|
|
#include "sha1.h" |
30 |
|
|
#include "b64.h" |
31 |
|
|
|
32 |
|
|
#endif |
33 |
|
|
|
34 |
|
|
#ifndef SSL_SUCCESS |
35 |
|
|
#define SSL_SUCCESS 1 |
36 |
|
|
#endif |
37 |
|
|
|
38 |
|
|
#include <errno.h> |
39 |
|
|
|
40 |
|
|
#include "worker.h" |
41 |
|
|
#include "event.h" |
42 |
|
|
#include "ssl.h" |
43 |
|
|
#include "log.h" |
44 |
|
|
#include "predict.h" |
45 |
|
|
|
46 |
|
|
/** |
47 |
|
|
* Function initializes SSL context that can be used to serve over https. |
48 |
|
|
* |
49 |
|
|
* @param server [wss_server_t *] "The server instance" |
50 |
|
|
* @return [wss_error_t] "The error status" |
51 |
|
|
*/ |
52 |
|
|
wss_error_t WSS_http_ssl(wss_server_t *server) { |
53 |
|
|
#if defined(USE_OPENSSL) |
54 |
|
|
FILE *f; |
55 |
|
|
DH *dh; |
56 |
|
|
const SSL_METHOD *method; |
57 |
|
|
int error_size = 1024; |
58 |
|
|
char error[error_size]; |
59 |
|
|
|
60 |
|
|
SSL_library_init(); |
61 |
|
|
|
62 |
|
|
#if ! defined(OPENSSL_IS_BORINGSSL) && ! defined(LIBRESSL_VERSION_NUMBER) |
63 |
|
|
FIPS_mode_set(1); |
64 |
|
|
#endif |
65 |
|
|
|
66 |
|
|
ERR_load_crypto_strings(); |
67 |
|
|
SSL_load_error_strings(); |
68 |
|
|
OpenSSL_add_ssl_algorithms(); |
69 |
|
|
OpenSSL_add_all_algorithms(); |
70 |
|
|
|
71 |
|
|
method = TLS_method(); |
72 |
|
|
server->ssl_ctx = SSL_CTX_new(method); |
73 |
|
|
if ( unlikely(!server->ssl_ctx) ) { |
74 |
|
|
ERR_error_string_n(ERR_get_error(), error, error_size); |
75 |
|
|
WSS_log_error("Unable to create ssl context: %s", error); |
76 |
|
|
return WSS_SSL_CTX_ERROR; |
77 |
|
|
} |
78 |
|
|
|
79 |
|
|
WSS_log_trace("Assign CA certificate(s) to ssl context"); |
80 |
|
|
if ( unlikely(SSL_SUCCESS != SSL_CTX_load_verify_locations(server->ssl_ctx, server->config->ssl_ca_file, server->config->ssl_ca_path)) ) { |
81 |
|
|
ERR_error_string_n(ERR_get_error(), error, error_size); |
82 |
|
|
WSS_log_error("Unable to load CA certificates: %s", error); |
83 |
|
|
return WSS_SSL_CA_ERROR; |
84 |
|
|
} |
85 |
|
|
|
86 |
|
|
WSS_log_trace("Assign certificate to ssl context"); |
87 |
|
|
if ( unlikely(SSL_SUCCESS != SSL_CTX_use_certificate_file(server->ssl_ctx, server->config->ssl_cert, SSL_FILETYPE_PEM)) ) { |
88 |
|
|
ERR_error_string_n(ERR_get_error(), error, error_size); |
89 |
|
|
WSS_log_error("Unable to load server certificate: %s", error); |
90 |
|
|
return WSS_SSL_CERT_ERROR; |
91 |
|
|
} |
92 |
|
|
|
93 |
|
|
WSS_log_trace("Assign private key to ssl context"); |
94 |
|
|
if ( unlikely(SSL_SUCCESS != SSL_CTX_use_PrivateKey_file(server->ssl_ctx, server->config->ssl_key, SSL_FILETYPE_PEM)) ) { |
95 |
|
|
ERR_error_string_n(ERR_get_error(), error, error_size); |
96 |
|
|
WSS_log_error("Unable to load server private key: %s", error); |
97 |
|
|
return WSS_SSL_KEY_ERROR; |
98 |
|
|
} |
99 |
|
|
|
100 |
|
|
WSS_log_trace("Validate private key"); |
101 |
|
|
if ( unlikely(SSL_SUCCESS != SSL_CTX_check_private_key(server->ssl_ctx)) ) { |
102 |
|
|
ERR_error_string_n(ERR_get_error(), error, error_size); |
103 |
|
|
WSS_log_error("Failed check of private key: %s", error); |
104 |
|
|
return WSS_SSL_KEY_ERROR; |
105 |
|
|
} |
106 |
|
|
|
107 |
|
|
WSS_log_trace("Use most appropriate client curve"); |
108 |
|
|
#if ! defined(LIBRESSL_VERSION_NUMBER) |
109 |
|
|
SSL_CTX_set_options(server->ssl_ctx, SSL_OP_SINGLE_ECDH_USE); |
110 |
|
|
#endif |
111 |
|
|
|
112 |
|
|
#if ! defined(OPENSSL_IS_BORINGSSL) |
113 |
|
|
SSL_CTX_set_ecdh_auto(server->ssl_ctx, 1); |
114 |
|
|
#endif |
115 |
|
|
|
116 |
|
|
if (! server->config->ssl_peer_cert) { |
117 |
|
|
SSL_CTX_set_verify(server->ssl_ctx, SSL_VERIFY_NONE, 0); |
118 |
|
|
} else { |
119 |
|
|
SSL_CTX_set_verify(server->ssl_ctx, SSL_VERIFY_PEER|SSL_VERIFY_FAIL_IF_NO_PEER_CERT, 0); |
120 |
|
|
} |
121 |
|
|
|
122 |
|
|
WSS_log_trace("Allow writes to be partial"); |
123 |
|
|
SSL_CTX_set_mode(server->ssl_ctx, SSL_MODE_ENABLE_PARTIAL_WRITE); |
124 |
|
|
|
125 |
|
|
//WSS_log_trace("Allow write buffer to be moving as it is allocated on the heap"); |
126 |
|
|
//SSL_CTX_set_mode(server->ssl_ctx, SSL_MODE_ACCEPT_MOVING_WRITE_BUFFER); |
127 |
|
|
|
128 |
|
|
WSS_log_trace("Allow read and write buffers to be released when they are no longer needed"); |
129 |
|
|
SSL_CTX_set_mode(server->ssl_ctx, SSL_MODE_RELEASE_BUFFERS); |
130 |
|
|
|
131 |
|
|
if (! server->config->ssl_compression) { |
132 |
|
|
WSS_log_trace("Do not use compression even if it is supported."); |
133 |
|
|
SSL_CTX_set_mode(server->ssl_ctx, SSL_OP_NO_COMPRESSION); |
134 |
|
|
} |
135 |
|
|
|
136 |
|
|
WSS_log_trace("When choosing a cipher, use the server's preferences instead of the client preferences."); |
137 |
|
|
SSL_CTX_set_mode(server->ssl_ctx, SSL_OP_CIPHER_SERVER_PREFERENCE); |
138 |
|
|
|
139 |
|
|
WSS_log_trace("Disable use of session and ticket cache and resumption"); |
140 |
|
|
SSL_CTX_set_session_cache_mode(server->ssl_ctx, SSL_SESS_CACHE_OFF); |
141 |
|
|
|
142 |
|
|
#if ! defined(LIBRESSL_VERSION_NUMBER) |
143 |
|
|
SSL_CTX_set_options(server->ssl_ctx, SSL_OP_NO_TICKET); |
144 |
|
|
#endif |
145 |
|
|
|
146 |
|
|
#if ! defined(LIBRESSL_VERSION_NUMBER) && ! defined(OPENSSL_IS_BORINGSSL) |
147 |
|
|
if ( SSL_SUCCESS != SSL_CTX_set_num_tickets(server->ssl_ctx, 0) ) { |
148 |
|
|
WSS_log_error("Failed to set number of ticket to zero"); |
149 |
|
|
return WSS_SSL_CTX_ERROR; |
150 |
|
|
} |
151 |
|
|
#endif |
152 |
|
|
|
153 |
|
|
#if ! defined(LIBRESSL_VERSION_NUMBER) |
154 |
|
|
SSL_CTX_set_options(server->ssl_ctx, SSL_OP_NO_SESSION_RESUMPTION_ON_RENEGOTIATION); |
155 |
|
|
#endif |
156 |
|
|
|
157 |
|
|
if ( NULL != server->config->ssl_cipher_list ) { |
158 |
|
|
WSS_log_trace("Setting cipher list"); |
159 |
|
|
SSL_CTX_set_cipher_list(server->ssl_ctx, server->config->ssl_cipher_list); |
160 |
|
|
} |
161 |
|
|
|
162 |
|
|
if ( NULL != server->config->ssl_cipher_suites ) { |
163 |
|
|
#if ! defined(LIBRESSL_VERSION_NUMBER) && ! defined(OPENSSL_IS_BORINGSSL) |
164 |
|
|
WSS_log_trace("Setting cipher suites"); |
165 |
|
|
SSL_CTX_set_ciphersuites(server->ssl_ctx, server->config->ssl_cipher_suites); |
166 |
|
|
#else |
167 |
|
|
if ( NULL != server->config->ssl_cipher_list ) { |
168 |
|
|
char list[strlen(server->config->ssl_cipher_list)+strlen(server->config->ssl_cipher_list)+2]; |
169 |
|
|
memset(list, '\0', strlen(server->config->ssl_cipher_list)+strlen(server->config->ssl_cipher_list)+2); |
170 |
|
|
memcpy(list, server->config->ssl_cipher_list, strlen(server->config->ssl_cipher_list)); |
171 |
|
|
list[strlen(server->config->ssl_cipher_list)] = ':'; |
172 |
|
|
memcpy(list+(strlen(server->config->ssl_cipher_list)+1), server->config->ssl_cipher_suites, strlen(server->config->ssl_cipher_suites)); |
173 |
|
|
SSL_CTX_set_cipher_list(server->ssl_ctx, list); |
174 |
|
|
} else { |
175 |
|
|
SSL_CTX_set_cipher_list(server->ssl_ctx, server->config->ssl_cipher_suites); |
176 |
|
|
} |
177 |
|
|
|
178 |
|
|
WSS_log_trace("Setting cipher suites"); |
179 |
|
|
#endif |
180 |
|
|
} |
181 |
|
|
|
182 |
|
|
if ( NULL != server->config->ssl_dhparam ) { |
183 |
|
|
if ( NULL != (f = fopen(server->config->ssl_dhparam, "r")) ) { |
184 |
|
|
if ( NULL != (dh = PEM_read_DHparams(f, NULL, NULL, NULL)) ) { |
185 |
|
|
#if ! defined(LIBRESSL_VERSION_NUMBER) |
186 |
|
|
SSL_CTX_set_options(server->ssl_ctx, SSL_OP_SINGLE_DH_USE); |
187 |
|
|
#endif |
188 |
|
|
if ( SSL_SUCCESS != SSL_CTX_set_tmp_dh(server->ssl_ctx, dh) ) { |
189 |
|
|
ERR_error_string_n(ERR_get_error(), error, error_size); |
190 |
|
|
WSS_log_error("Setting dhparam failed: %s", error); |
191 |
|
|
} |
192 |
|
|
DH_free(dh); |
193 |
|
|
} else { |
194 |
|
|
ERR_error_string_n(ERR_get_error(), error, error_size); |
195 |
|
|
WSS_log_error("Unable load dhparam: %s", error); |
196 |
|
|
} |
197 |
|
|
|
198 |
|
|
fclose(f); |
199 |
|
|
} else { |
200 |
|
|
WSS_log_error("Unable to open dhparam file: %s", strerror(errno)); |
201 |
|
|
} |
202 |
|
|
} |
203 |
|
|
|
204 |
|
|
#if defined(LIBRESSL_VERSION_NUMBER) |
205 |
|
|
WSS_log_info("SSL was setup using 'LibreSSL'"); |
206 |
|
|
#elif defined(OPENSSL_IS_BORINGSSL) |
207 |
|
|
WSS_log_info("SSL was setup using 'BoringSSL'"); |
208 |
|
|
#else |
209 |
|
|
WSS_log_info("SSL was setup using 'OpenSSL'"); |
210 |
|
|
#endif |
211 |
|
|
|
212 |
|
|
return WSS_SUCCESS; |
213 |
|
|
#elif defined(USE_WOLFSSL) |
214 |
|
|
WOLFSSL_METHOD *method; |
215 |
|
|
int error_size = 1024; |
216 |
|
|
char error[error_size]; |
217 |
|
|
|
218 |
|
|
wolfSSL_Init(); |
219 |
|
|
|
220 |
|
|
method = TLS_method(); |
221 |
|
|
server->ssl_ctx = wolfSSL_CTX_new(method); |
222 |
|
|
if ( unlikely(!server->ssl_ctx) ) { |
223 |
|
|
wolfSSL_ERR_error_string_n(wolfSSL_ERR_get_error(), error, error_size); |
224 |
|
|
WSS_log_error("Unable to create ssl context: %s", error); |
225 |
|
|
return WSS_SSL_CTX_ERROR; |
226 |
|
|
} |
227 |
|
|
|
228 |
|
|
WSS_log_trace("Assign CA certificate(s) to ssl context"); |
229 |
|
|
if ( unlikely(SSL_SUCCESS != wolfSSL_CTX_load_verify_locations(server->ssl_ctx, server->config->ssl_ca_file, server->config->ssl_ca_path)) ) { |
230 |
|
|
wolfSSL_ERR_error_string_n(wolfSSL_ERR_get_error(), error, error_size); |
231 |
|
|
WSS_log_error("Unable to load CA certificates: %s", error); |
232 |
|
|
return WSS_SSL_CA_ERROR; |
233 |
|
|
} |
234 |
|
|
|
235 |
|
|
WSS_log_trace("Assign certificate to ssl context"); |
236 |
|
|
if ( unlikely(SSL_SUCCESS != wolfSSL_CTX_use_certificate_file(server->ssl_ctx, server->config->ssl_cert, SSL_FILETYPE_PEM)) ) { |
237 |
|
|
wolfSSL_ERR_error_string_n(wolfSSL_ERR_get_error(), error, error_size); |
238 |
|
|
WSS_log_error("Unable to load server certificate: %s", error); |
239 |
|
|
return WSS_SSL_CERT_ERROR; |
240 |
|
|
} |
241 |
|
|
|
242 |
|
|
WSS_log_trace("Assign private key to ssl context"); |
243 |
|
|
if ( unlikely(SSL_SUCCESS != wolfSSL_CTX_use_PrivateKey_file(server->ssl_ctx, server->config->ssl_key, SSL_FILETYPE_PEM)) ) { |
244 |
|
|
wolfSSL_ERR_error_string_n(wolfSSL_ERR_get_error(), error, error_size); |
245 |
|
|
WSS_log_error("Unable to load server private key: %s", error); |
246 |
|
|
return WSS_SSL_KEY_ERROR; |
247 |
|
|
} |
248 |
|
|
|
249 |
|
|
WSS_log_trace("Validate private key"); |
250 |
|
|
if ( unlikely(SSL_SUCCESS != wolfSSL_CTX_check_private_key(server->ssl_ctx)) ) { |
251 |
|
|
wolfSSL_ERR_error_string_n(wolfSSL_ERR_get_error(), error, error_size); |
252 |
|
|
WSS_log_error("Failed check of private key: %s", error); |
253 |
|
|
return WSS_SSL_KEY_ERROR; |
254 |
|
|
} |
255 |
|
|
|
256 |
|
|
WSS_log_trace("Use most appropriate client curve"); |
257 |
|
|
wolfSSL_CTX_set_options(server->ssl_ctx, SSL_OP_SINGLE_ECDH_USE); |
258 |
|
|
|
259 |
|
|
if (! server->config->ssl_peer_cert) { |
260 |
|
|
wolfSSL_CTX_set_verify(server->ssl_ctx, SSL_VERIFY_NONE, 0); |
261 |
|
|
} else { |
262 |
|
|
wolfSSL_CTX_set_verify(server->ssl_ctx, SSL_VERIFY_PEER|SSL_VERIFY_FAIL_IF_NO_PEER_CERT, 0); |
263 |
|
|
} |
264 |
|
|
|
265 |
|
|
WSS_log_trace("Allow writes to be partial"); |
266 |
|
|
wolfSSL_CTX_set_mode(server->ssl_ctx, SSL_MODE_ENABLE_PARTIAL_WRITE); |
267 |
|
|
|
268 |
|
|
//WSS_log_trace("Allow write buffer to be moving as it is allocated on the heap"); |
269 |
|
|
//wolfSSL_CTX_set_mode(server->ssl_ctx, SSL_MODE_ACCEPT_MOVING_WRITE_BUFFER); |
270 |
|
|
|
271 |
|
|
WSS_log_trace("Allow read and write buffers to be released when they are no longer needed"); |
272 |
|
|
wolfSSL_CTX_set_mode(server->ssl_ctx, SSL_MODE_RELEASE_BUFFERS); |
273 |
|
|
|
274 |
|
|
if (! server->config->ssl_compression) { |
275 |
|
|
WSS_log_trace("Do not use compression even if it is supported."); |
276 |
|
|
wolfSSL_CTX_set_mode(server->ssl_ctx, SSL_OP_NO_COMPRESSION); |
277 |
|
|
} |
278 |
|
|
|
279 |
|
|
WSS_log_trace("When choosing a cipher, use the server's preferences instead of the client preferences."); |
280 |
|
|
wolfSSL_CTX_set_mode(server->ssl_ctx, SSL_OP_CIPHER_SERVER_PREFERENCE); |
281 |
|
|
|
282 |
|
|
WSS_log_trace("Disable use of session and ticket cache and resumption"); |
283 |
|
|
wolfSSL_CTX_set_session_cache_mode(server->ssl_ctx, SSL_SESS_CACHE_OFF); |
284 |
|
|
wolfSSL_CTX_set_options(server->ssl_ctx, SSL_OP_NO_TICKET); |
285 |
|
|
wolfSSL_CTX_set_options(server->ssl_ctx, SSL_OP_NO_SESSION_RESUMPTION_ON_RENEGOTIATION); |
286 |
|
|
|
287 |
|
|
if ( NULL != server->config->ssl_cipher_list ) { |
288 |
|
|
WSS_log_trace("Setting cipher list"); |
289 |
|
|
wolfSSL_CTX_set_cipher_list(server->ssl_ctx, server->config->ssl_cipher_list); |
290 |
|
|
} |
291 |
|
|
|
292 |
|
|
if ( NULL != server->config->ssl_cipher_suites ) { |
293 |
|
|
if ( NULL != server->config->ssl_cipher_list ) { |
294 |
|
|
char list[strlen(server->config->ssl_cipher_list)+strlen(server->config->ssl_cipher_list)+2]; |
295 |
|
|
memset(list, '\0', strlen(server->config->ssl_cipher_list)+strlen(server->config->ssl_cipher_list)+2); |
296 |
|
|
memcpy(list, server->config->ssl_cipher_list, strlen(server->config->ssl_cipher_list)); |
297 |
|
|
list[strlen(server->config->ssl_cipher_list)] = ':'; |
298 |
|
|
memcpy(list+(strlen(server->config->ssl_cipher_list)+1), server->config->ssl_cipher_suites, strlen(server->config->ssl_cipher_suites)); |
299 |
|
|
SSL_CTX_set_cipher_list(server->ssl_ctx, list); |
300 |
|
|
} else { |
301 |
|
|
SSL_CTX_set_cipher_list(server->ssl_ctx, server->config->ssl_cipher_suites); |
302 |
|
|
} |
303 |
|
|
WSS_log_trace("Setting cipher suites"); |
304 |
|
|
} |
305 |
|
|
|
306 |
|
|
if ( NULL != server->config->ssl_dhparam ) { |
307 |
|
|
if ( SSL_SUCCESS != wolfSSL_SetTmpDH_file(server->ssl_ctx, server->config->ssl_dhparam, SSL_FILETYPE_PEM) ) { |
308 |
|
|
wolfSSL_ERR_error_string_n(wolfSSL_ERR_get_error(), error, error_size); |
309 |
|
|
WSS_log_error("Setting dhparam failed: %s", error); |
310 |
|
|
} |
311 |
|
|
} |
312 |
|
|
|
313 |
|
|
WSS_log_info("SSL was setup using 'WolfSSL'"); |
314 |
|
|
|
315 |
|
|
return WSS_SUCCESS; |
316 |
|
|
#else |
317 |
|
|
return WSS_SSL_CTX_ERROR; |
318 |
|
|
#endif |
319 |
|
|
} |
320 |
|
|
|
321 |
|
|
/** |
322 |
|
|
* Function frees SSL context that was used to serve over https. |
323 |
|
|
* |
324 |
|
|
* @param server [wss_server_t *] "The server instance" |
325 |
|
|
* @return [void] |
326 |
|
|
*/ |
327 |
|
|
void WSS_http_ssl_free(wss_server_t *server) { |
328 |
|
|
#if defined(USE_OPENSSL) |
329 |
|
|
SSL_CTX_free(server->ssl_ctx); |
330 |
|
|
|
331 |
|
|
#if ! defined(LIBRESSL_VERSION_NUMBER) && ! defined(OPENSSL_IS_BORINGSSL) |
332 |
|
|
FIPS_mode_set(0); |
333 |
|
|
#endif |
334 |
|
|
|
335 |
|
|
EVP_cleanup(); |
336 |
|
|
CRYPTO_cleanup_all_ex_data(); |
337 |
|
|
ERR_free_strings(); |
338 |
|
|
#elif defined(USE_WOLFSSL) |
339 |
|
|
wolfSSL_CTX_free(server->ssl_ctx); |
340 |
|
|
wolfSSL_Cleanup(); |
341 |
|
|
#endif |
342 |
|
|
} |
343 |
|
|
|
344 |
|
|
/** |
345 |
|
|
* Function that performs a ssl read from the connecting client. |
346 |
|
|
* |
347 |
|
|
* @param server [wss_server_t *] "The server implementation" |
348 |
|
|
* @param session [wss_session_t *] "The connecting client session" |
349 |
|
|
* @param buffer [char *] "The buffer to use" |
350 |
|
|
* @return [int] |
351 |
|
|
*/ |
352 |
|
|
int WSS_ssl_read(wss_server_t *server, wss_session_t *session, char *buffer) { |
353 |
|
|
#if defined(USE_OPENSSL) | defined(USE_WOLFSSL) |
354 |
|
|
int n; |
355 |
|
|
unsigned long err; |
356 |
|
|
|
357 |
|
|
#if defined(USE_OPENSSL) |
358 |
|
|
n = SSL_read(session->ssl, buffer, server->config->size_buffer); |
359 |
|
|
err = SSL_get_error(session->ssl, n); |
360 |
|
|
#elif defined(USE_WOLFSSL) |
361 |
|
|
n = wolfSSL_read(session->ssl, buffer, server->config->size_buffer); |
362 |
|
|
err = SSL_get_error(session->ssl, n); |
363 |
|
|
#endif |
364 |
|
|
|
365 |
|
|
// There's no more to read from the kernel |
366 |
|
|
if ( unlikely(err == SSL_ERROR_WANT_READ) ) { |
367 |
|
|
n = 0; |
368 |
|
|
} else |
369 |
|
|
|
370 |
|
|
// There's no space to write to the kernel, wait for filedescriptor. |
371 |
|
|
if ( unlikely(err == SSL_ERROR_WANT_WRITE) ) { |
372 |
|
|
WSS_log_debug("SSL_ERROR_WANT_WRITE"); |
373 |
|
|
|
374 |
|
|
n = -2; |
375 |
|
|
} else |
376 |
|
|
|
377 |
|
|
// Some error has occured. |
378 |
|
|
if ( unlikely(err != SSL_ERROR_NONE && err != SSL_ERROR_ZERO_RETURN) ) { |
379 |
|
|
char msg[1024]; |
380 |
|
|
#if defined(USE_OPENSSL) |
381 |
|
|
while ( (err = ERR_get_error()) != 0 ) { |
382 |
|
|
memset(msg, '\0', 1024); |
383 |
|
|
ERR_error_string_n(err, msg, 1024); |
384 |
|
|
WSS_log_error("SSL read failed: %s", msg); |
385 |
|
|
} |
386 |
|
|
#elif defined(USE_WOLFSSL) |
387 |
|
|
while ( (err = wolfSSL_ERR_get_error()) != 0 ) { |
388 |
|
|
memset(msg, '\0', 1024); |
389 |
|
|
wolfSSL_ERR_error_string_n(err, msg, 1024); |
390 |
|
|
WSS_log_error("SSL read failed: %s", msg); |
391 |
|
|
} |
392 |
|
|
#endif |
393 |
|
|
|
394 |
|
|
n = -1; |
395 |
|
|
} else |
396 |
|
|
|
397 |
|
|
// If this was one of the error codes that we do accept, return 0 |
398 |
|
|
if ( unlikely(n < 0) ) { |
399 |
|
|
n = 0; |
400 |
|
|
} |
401 |
|
|
|
402 |
|
|
return n; |
403 |
|
|
#else |
404 |
|
|
return 0; |
405 |
|
|
#endif |
406 |
|
|
} |
407 |
|
|
|
408 |
|
|
/** |
409 |
|
|
* Function that performs a ssl write to the connecting client. |
410 |
|
|
* |
411 |
|
|
* @param session [wss_session_t *] "The connecting client session" |
412 |
|
|
* @param message_index [unsigned int] "The message index" |
413 |
|
|
* @param message [wss_message_t *] "The message" |
414 |
|
|
* @param bytes_sent [unsigned int] "The amount of bytes currently sent" |
415 |
|
|
* @return [bool] |
416 |
|
|
*/ |
417 |
|
|
bool WSS_ssl_write_partial(wss_session_t *session, unsigned int message_index, wss_message_t *message, unsigned int *bytes_sent) { |
418 |
|
|
#if defined(USE_OPENSSL) | defined(USE_WOLFSSL) |
419 |
|
|
int n; |
420 |
|
|
unsigned long err; |
421 |
|
|
unsigned int message_length = message->length; |
422 |
|
|
|
423 |
|
|
#if defined(USE_OPENSSL) |
424 |
|
|
n = SSL_write(session->ssl, message->msg+*bytes_sent, message_length-*bytes_sent); |
425 |
|
|
err = SSL_get_error(session->ssl, n); |
426 |
|
|
#elif defined(USE_WOLFSSL) |
427 |
|
|
n = wolfSSL_write(session->ssl, message->msg+*bytes_sent, message_length-*bytes_sent); |
428 |
|
|
err = SSL_get_error(session->ssl, n); |
429 |
|
|
#endif |
430 |
|
|
|
431 |
|
|
// If something more needs to be read in order for the handshake to finish |
432 |
|
|
if ( unlikely(err == SSL_ERROR_WANT_READ) ) { |
433 |
|
|
WSS_log_trace("Needs to wait for further reads"); |
434 |
|
|
|
435 |
|
|
session->written = *bytes_sent; |
436 |
|
|
ringbuf_release(session->ringbuf, message_index); |
437 |
|
|
|
438 |
|
|
session->event = READ; |
439 |
|
|
|
440 |
|
|
return false; |
441 |
|
|
} |
442 |
|
|
|
443 |
|
|
// If something more needs to be written in order for the handshake to finish |
444 |
|
|
if ( unlikely(err == SSL_ERROR_WANT_WRITE) ) { |
445 |
|
|
WSS_log_trace("Needs to wait for further writes"); |
446 |
|
|
|
447 |
|
|
session->written = *bytes_sent; |
448 |
|
|
|
449 |
|
|
ringbuf_release(session->ringbuf, message_index); |
450 |
|
|
|
451 |
|
|
session->event = WRITE; |
452 |
|
|
|
453 |
|
|
return false; |
454 |
|
|
} |
455 |
|
|
|
456 |
|
|
if ( unlikely(err != SSL_ERROR_NONE && err != SSL_ERROR_ZERO_RETURN) ) { |
457 |
|
|
char msg[1024]; |
458 |
|
|
#if defined(USE_OPENSSL) |
459 |
|
|
while ( (err = ERR_get_error()) != 0 ) { |
460 |
|
|
ERR_error_string_n(err, msg, 1024); |
461 |
|
|
WSS_log_error("SSL write failed: %s", msg); |
462 |
|
|
} |
463 |
|
|
#elif defined(USE_WOLFSSL) |
464 |
|
|
while ( (err = wolfSSL_ERR_get_error()) != 0 ) { |
465 |
|
|
wolfSSL_ERR_error_string_n(err, msg, 1024); |
466 |
|
|
WSS_log_error("SSL write failed: %s", msg); |
467 |
|
|
} |
468 |
|
|
#endif |
469 |
|
|
session->closing = true; |
470 |
|
|
|
471 |
|
|
return false; |
472 |
|
|
} else { |
473 |
|
|
if (unlikely(n < 0)) { |
474 |
|
|
n = 0; |
475 |
|
|
} |
476 |
|
|
*bytes_sent += n; |
477 |
|
|
} |
478 |
|
|
|
479 |
|
|
return true; |
480 |
|
|
#else |
481 |
|
|
return false; |
482 |
|
|
#endif |
483 |
|
|
} |
484 |
|
|
|
485 |
|
|
/** |
486 |
|
|
* Function that performs a ssl write to the connecting client. |
487 |
|
|
* |
488 |
|
|
* @param session [wss_session_t *] "The connecting client session" |
489 |
|
|
* @param message [char *] "The message" |
490 |
|
|
* @param message_length [size_t] "The message length" |
491 |
|
|
* @return [void] |
492 |
|
|
*/ |
493 |
|
|
void WSS_ssl_write(wss_session_t *session, char *message, unsigned int message_length) { |
494 |
|
|
#if defined(USE_OPENSSL) | defined(USE_WOLFSSL) |
495 |
|
|
int n; |
496 |
|
|
size_t written = 0; |
497 |
|
|
|
498 |
|
|
do { |
499 |
|
|
#if defined(USE_OPENSSL) |
500 |
|
|
n = SSL_write(session->ssl, message+written, message_length-written); |
501 |
|
|
#elif defined(USE_WOLFSSL) |
502 |
|
|
n = wolfSSL_write(session->ssl, message+written, message_length-written); |
503 |
|
|
#endif |
504 |
|
|
if (n < 0) { |
505 |
|
|
break; |
506 |
|
|
} |
507 |
|
|
written += n; |
508 |
|
|
} while ( written < message_length ); |
509 |
|
|
#endif |
510 |
|
|
} |
511 |
|
|
|
512 |
|
|
/** |
513 |
|
|
* Function that performs a ssl handshake with the connecting client. |
514 |
|
|
* |
515 |
|
|
* @param server [wss_server_t *] "The server implementation" |
516 |
|
|
* @param session [wss_session_t *] "The connecting client session" |
517 |
|
|
* @return [void] |
518 |
|
|
*/ |
519 |
|
|
void WSS_ssl_handshake(wss_server_t *server, wss_session_t *session) { |
520 |
|
|
#if defined(USE_OPENSSL) | defined(USE_WOLFSSL) |
521 |
|
|
int ret; |
522 |
|
|
unsigned long err; |
523 |
|
|
|
524 |
|
|
WSS_log_trace("Performing SSL handshake"); |
525 |
|
|
|
526 |
|
|
#if defined(USE_OPENSSL) |
527 |
|
|
ret = SSL_do_handshake(session->ssl); |
528 |
|
|
err = SSL_get_error(session->ssl, ret); |
529 |
|
|
#elif defined(USE_WOLFSSL) |
530 |
|
|
ret = wolfSSL_SSL_do_handshake(session->ssl); |
531 |
|
|
err = wolfSSL_get_error(session->ssl, ret); |
532 |
|
|
#endif |
533 |
|
|
|
534 |
|
|
// If something more needs to be read in order for the handshake to finish |
535 |
|
|
if ( unlikely(err == SSL_ERROR_WANT_READ) ) { |
536 |
|
|
WSS_log_trace("Need to wait for further reads"); |
537 |
|
|
|
538 |
|
|
clock_gettime(CLOCK_MONOTONIC, &session->alive); |
539 |
|
|
|
540 |
|
|
WSS_poll_set_read(server, session->fd); |
541 |
|
|
|
542 |
|
|
return; |
543 |
|
|
} |
544 |
|
|
|
545 |
|
|
// If something more needs to be written in order for the handshake to finish |
546 |
|
|
if ( unlikely(err == SSL_ERROR_WANT_WRITE) ) { |
547 |
|
|
WSS_log_trace("Need to wait for further writes"); |
548 |
|
|
|
549 |
|
|
clock_gettime(CLOCK_MONOTONIC, &session->alive); |
550 |
|
|
|
551 |
|
|
WSS_poll_set_write(server, session->fd); |
552 |
|
|
|
553 |
|
|
return; |
554 |
|
|
} |
555 |
|
|
|
556 |
|
|
if ( unlikely(err != SSL_ERROR_NONE && err != SSL_ERROR_ZERO_RETURN) ) { |
557 |
|
|
char message[1024]; |
558 |
|
|
#if defined(USE_OPENSSL) |
559 |
|
|
while ( (err = ERR_get_error()) != 0 ) { |
560 |
|
|
memset(message, '\0', 1024); |
561 |
|
|
ERR_error_string_n(err, message, 1024); |
562 |
|
|
WSS_log_error("Handshake error: %s", message); |
563 |
|
|
} |
564 |
|
|
#elif defined(USE_WOLFSSL) |
565 |
|
|
while ( (err = wolfSSL_ERR_get_error()) != 0 ) { |
566 |
|
|
memset(message, '\0', 1024); |
567 |
|
|
wolfSSL_ERR_error_string_n(err, message, 1024); |
568 |
|
|
WSS_log_error("Handshake error: %s", message); |
569 |
|
|
} |
570 |
|
|
#endif |
571 |
|
|
|
572 |
|
|
WSS_disconnect(server, session); |
573 |
|
|
return; |
574 |
|
|
} |
575 |
|
|
|
576 |
|
|
WSS_log_trace("SSL handshake was successfull"); |
577 |
|
|
|
578 |
|
|
session->ssl_connected = true; |
579 |
|
|
|
580 |
|
|
WSS_log_info("Client with session %d connected", session->fd); |
581 |
|
|
|
582 |
|
|
session->state = IDLE; |
583 |
|
|
|
584 |
|
|
clock_gettime(CLOCK_MONOTONIC, &session->alive); |
585 |
|
|
|
586 |
|
|
WSS_poll_set_read(server, session->fd); |
587 |
|
|
#endif |
588 |
|
|
} |
589 |
|
|
|
590 |
|
|
/** |
591 |
|
|
* Function initializes SSL context that can be used to serve over https. |
592 |
|
|
* |
593 |
|
|
* @param server [wss_server_t *] "The server instance" |
594 |
|
|
* @param session [wss_session_t *] "The session instance" |
595 |
|
|
* @return [bool] "Whether function was successful" |
596 |
|
|
*/ |
597 |
|
|
bool WSS_session_ssl(wss_server_t *server, wss_session_t *session) { |
598 |
|
|
#if defined(USE_OPENSSL) |
599 |
|
|
char ssl_msg[1024]; |
600 |
|
|
|
601 |
|
|
WSS_log_trace("Creating ssl client structure"); |
602 |
|
|
if ( unlikely(NULL == (session->ssl = SSL_new(server->ssl_ctx))) ) { |
603 |
|
|
ERR_error_string_n(ERR_get_error(), ssl_msg, 1024); |
604 |
|
|
WSS_log_error("Unable to create SSL structure: %s", ssl_msg); |
605 |
|
|
WSS_disconnect(server, session); |
606 |
|
|
return false; |
607 |
|
|
} |
608 |
|
|
|
609 |
|
|
WSS_log_trace("Associating structure with client filedescriptor"); |
610 |
|
|
if ( unlikely(SSL_set_fd(session->ssl, session->fd) != 1) ) { |
611 |
|
|
ERR_error_string_n(ERR_get_error(), ssl_msg, 1024); |
612 |
|
|
WSS_log_error("Unable to bind filedescriptor to SSL structure: %s", ssl_msg); |
613 |
|
|
WSS_disconnect(server, session); |
614 |
|
|
return false; |
615 |
|
|
} |
616 |
|
|
|
617 |
|
|
WSS_log_trace("Setting accept state"); |
618 |
|
|
SSL_set_accept_state(session->ssl); |
619 |
|
|
|
620 |
|
|
return true; |
621 |
|
|
#elif defined(USE_WOLFSSL) |
622 |
|
|
char ssl_msg[1024]; |
623 |
|
|
|
624 |
|
|
WSS_log_trace("Creating ssl client structure"); |
625 |
|
|
if ( unlikely(NULL == (session->ssl = wolfSSL_new(server->ssl_ctx))) ) { |
626 |
|
|
wolfSSL_ERR_error_string_n(wolfSSL_ERR_get_error(), ssl_msg, 1024); |
627 |
|
|
WSS_log_error("Unable to create SSL structure: %s", ssl_msg); |
628 |
|
|
WSS_disconnect(server, session); |
629 |
|
|
return false; |
630 |
|
|
} |
631 |
|
|
|
632 |
|
|
WSS_log_trace("Associating structure with client filedescriptor"); |
633 |
|
|
if ( unlikely(wolfSSL_set_fd(session->ssl, session->fd) != 1) ) { |
634 |
|
|
wolfSSL_ERR_error_string_n(wolfSSL_ERR_get_error(), ssl_msg, 1024); |
635 |
|
|
WSS_log_error("Unable to bind filedescriptor to SSL structure: %s", ssl_msg); |
636 |
|
|
WSS_disconnect(server, session); |
637 |
|
|
return false; |
638 |
|
|
} |
639 |
|
|
|
640 |
|
|
WSS_log_trace("Setting accept state"); |
641 |
|
|
wolfSSL_set_accept_state(session->ssl); |
642 |
|
|
|
643 |
|
|
return true; |
644 |
|
|
#else |
645 |
|
|
return false; |
646 |
|
|
#endif |
647 |
|
|
} |
648 |
|
|
|
649 |
|
|
/** |
650 |
|
|
* Function frees SSL session instance that was used to serve over https. |
651 |
|
|
* |
652 |
|
|
* @param session [wss_session_t *] "The session instance" |
653 |
|
|
* @param lock [pthread_rwlock_t *] "The read/write session lock" |
654 |
|
|
* @return [wss_error_t] "An error or success" |
655 |
|
|
*/ |
656 |
|
|
wss_error_t WSS_session_ssl_free(wss_session_t *session, pthread_rwlock_t *lock) { |
657 |
|
|
int err = WSS_SUCCESS; |
658 |
|
|
|
659 |
|
|
#if defined(USE_OPENSSL) |
660 |
|
|
WSS_log_trace("Free ssl structure"); |
661 |
|
|
if ( unlikely((err = SSL_shutdown(session->ssl)) < 0) ) { |
662 |
|
|
err = SSL_get_error(session->ssl, err); |
663 |
|
|
switch (err) { |
664 |
|
|
case SSL_ERROR_WANT_READ: |
665 |
|
|
pthread_rwlock_unlock(lock); |
666 |
|
|
return WSS_SSL_SHUTDOWN_READ_ERROR; |
667 |
|
|
case SSL_ERROR_WANT_WRITE: |
668 |
|
|
pthread_rwlock_unlock(lock); |
669 |
|
|
return WSS_SSL_SHUTDOWN_WRITE_ERROR; |
670 |
|
|
case SSL_ERROR_SYSCALL: |
671 |
|
|
WSS_log_error("SSL_shutdown failed: %s", strerror(errno)); |
672 |
|
|
break; |
673 |
|
|
default: |
674 |
|
|
WSS_log_error("SSL_shutdown error code: %d", err); |
675 |
|
|
break; |
676 |
|
|
} |
677 |
|
|
|
678 |
|
|
char message[1024]; |
679 |
|
|
while ( (err = ERR_get_error()) != 0 ) { |
680 |
|
|
memset(message, '\0', 1024); |
681 |
|
|
ERR_error_string_n(err, message, 1024); |
682 |
|
|
WSS_log_error("SSL_shutdown error: %s", message); |
683 |
|
|
} |
684 |
|
|
|
685 |
|
|
err = WSS_SSL_SHUTDOWN_ERROR; |
686 |
|
|
} |
687 |
|
|
SSL_free(session->ssl); |
688 |
|
|
session->ssl = NULL; |
689 |
|
|
#elif defined(USE_WOLFSSL) |
690 |
|
|
if ( unlikely((err = wolfSSL_shutdown(session->ssl)) < 0) ) { |
691 |
|
|
err = SSL_get_error(session->ssl, err); |
692 |
|
|
switch (err) { |
693 |
|
|
case SSL_ERROR_WANT_READ: |
694 |
|
|
pthread_rwlock_unlock(lock); |
695 |
|
|
return WSS_SSL_SHUTDOWN_READ_ERROR; |
696 |
|
|
case SSL_ERROR_WANT_WRITE: |
697 |
|
|
pthread_rwlock_unlock(lock); |
698 |
|
|
return WSS_SSL_SHUTDOWN_WRITE_ERROR; |
699 |
|
|
case SSL_ERROR_SYSCALL: |
700 |
|
|
WSS_log_error("SSL_shutdown failed: %s", strerror(errno)); |
701 |
|
|
break; |
702 |
|
|
default: |
703 |
|
|
WSS_log_error("SSL_shutdown error code: %d", err); |
704 |
|
|
break; |
705 |
|
|
} |
706 |
|
|
|
707 |
|
|
char message[1024]; |
708 |
|
|
while ( (err = wolfSSL_ERR_get_error()) != 0 ) { |
709 |
|
|
memset(message, '\0', 1024); |
710 |
|
|
wolfSSL_ERR_error_string_n(err, message, 1024); |
711 |
|
|
WSS_log_error("SSL_shutdown error: %s", message); |
712 |
|
|
} |
713 |
|
|
|
714 |
|
|
err = WSS_SSL_SHUTDOWN_ERROR; |
715 |
|
|
} |
716 |
|
|
wolfSSL_free(session->ssl); |
717 |
|
|
session->ssl = NULL; |
718 |
|
|
#endif |
719 |
|
|
|
720 |
|
|
return err; |
721 |
|
|
} |
722 |
|
|
|
723 |
|
|
/** |
724 |
|
|
* Function creates a sha1 hash of the key. |
725 |
|
|
* |
726 |
|
|
* @param key [char *] "The key to be hashed" |
727 |
|
|
* @param key_length [pthread_rwlock_t *] "The length of the key" |
728 |
|
|
* @param hash [hash **] "A pointer to where the hash should be stored" |
729 |
|
|
* @return [size_t] "The length of the hash" |
730 |
|
|
*/ |
731 |
|
|
size_t WSS_sha1(char *key, size_t key_length, char **hash) { |
732 |
|
|
memset(*hash, '\0', SHA_DIGEST_LENGTH); |
733 |
|
|
|
734 |
|
|
#if defined(USE_OPENSSL) |
735 |
|
|
SHA1((const unsigned char *)key, key_length, (unsigned char*) *hash); |
736 |
|
|
#elif defined(USE_WOLFSSL) |
737 |
|
|
Sha sha; |
738 |
|
|
wc_InitSha(&sha); |
739 |
|
|
wc_ShaUpdate(&sha, (const unsigned char *) key, key_length); |
740 |
|
|
wc_ShaFinal(&sha, (unsigned char *)*hash); |
741 |
|
|
#else |
742 |
|
|
SHA1Context sha; |
743 |
|
|
int i, b; |
744 |
|
|
memset(*hash, '\0', SHA_DIGEST_LENGTH); |
745 |
|
|
|
746 |
|
|
SHA1Reset(&sha); |
747 |
|
|
SHA1Input(&sha, (const unsigned char*) key, key_length); |
748 |
|
|
if ( likely(SHA1Result(&sha)) ) { |
749 |
|
|
for (i = 0; likely(i < 5); i++) { |
750 |
|
|
b = htonl(sha.Message_Digest[i]); |
751 |
|
|
memcpy(*hash+(4*i), (unsigned char *) &b, 4); |
752 |
|
|
} |
753 |
|
|
} |
754 |
|
|
#endif |
755 |
|
|
|
756 |
|
|
return SHA_DIGEST_LENGTH; |
757 |
|
|
} |
758 |
|
|
|
759 |
|
|
/** |
760 |
|
|
* Function creates a sha1 hash of the key and base64 encodes it. |
761 |
|
|
* |
762 |
|
|
* @param key [char *] "The key to be hashed" |
763 |
|
|
* @param key_length [pthread_rwlock_t *] "The length of the key" |
764 |
|
|
* @param accept_key [char **] "A pointer to where the hash should be stored" |
765 |
|
|
* @return [size_t] "Length of accept_key" |
766 |
|
|
*/ |
767 |
|
|
size_t WSS_base64_encode_sha1(char *key, size_t key_length, char **accept_key) { |
768 |
|
|
size_t acceptKeyLength; |
769 |
|
|
char sha1Key[SHA_DIGEST_LENGTH]; |
770 |
|
|
memset(sha1Key, '\0', SHA_DIGEST_LENGTH); |
771 |
|
|
|
772 |
|
|
#if defined(USE_OPENSSL) && ! defined(OPENSSL_IS_BORINGSSL) |
773 |
|
|
SHA1((const unsigned char *)key, key_length, (unsigned char*) sha1Key); |
774 |
|
|
|
775 |
|
|
#pragma GCC diagnostic push |
776 |
|
|
#pragma GCC diagnostic ignored "-Wunused-value" |
777 |
|
|
BIO *b64_bio, *mem_bio; // Declares two OpenSSL BIOs: a base64 filter and a memory BIO. |
778 |
|
|
BUF_MEM *mem_bio_mem_ptr; // Pointer to a "memory BIO" structure holding our base64 data. |
779 |
|
|
b64_bio = BIO_new(BIO_f_base64()); // Initialize our base64 filter BIO. |
780 |
|
|
mem_bio = BIO_new(BIO_s_mem()); // Initialize our memory sink BIO. |
781 |
|
|
b64_bio = BIO_push(b64_bio, mem_bio); // Link the BIOs by creating a filter-sink BIO chain. |
782 |
|
|
BIO_set_flags(b64_bio, BIO_FLAGS_BASE64_NO_NL); // No newlines every 64 characters or less. |
783 |
|
|
BIO_set_close(mem_bio, BIO_CLOSE); // Permit access to mem_ptr after BIOs are destroyed. |
784 |
|
|
BIO_write(b64_bio, sha1Key, SHA_DIGEST_LENGTH); // Records base64 encoded data. |
785 |
|
|
BIO_flush(b64_bio); // Flush data. Necessary for b64 encoding, because of pad characters. |
786 |
|
|
BIO_get_mem_ptr(mem_bio, &mem_bio_mem_ptr); // Store address of mem_bio's memory structure. |
787 |
|
|
#pragma GCC diagnostic pop |
788 |
|
|
|
789 |
|
|
acceptKeyLength = mem_bio_mem_ptr->length; |
790 |
|
|
if ( unlikely(NULL == (*accept_key = WSS_malloc(acceptKeyLength))) ) { |
791 |
|
|
return 0; |
792 |
|
|
} |
793 |
|
|
memcpy(*accept_key, (*mem_bio_mem_ptr).data, acceptKeyLength); |
794 |
|
|
|
795 |
|
|
BIO_free_all(b64_bio); // Destroys all BIOs in chain, starting with b64 (i.e. the 1st one). |
796 |
|
|
#elif defined(OPENSSL_IS_BORINGSSL) |
797 |
|
|
SHA1((const unsigned char *)key, key_length, (unsigned char*) sha1Key); |
798 |
|
|
|
799 |
|
|
*accept_key = b64_encode((const unsigned char *) sha1Key, SHA_DIGEST_LENGTH); |
800 |
|
|
acceptKeyLength = strlen(*accept_key); |
801 |
|
|
#elif defined(USE_WOLFSSL) |
802 |
|
|
Sha sha; |
803 |
|
|
wc_InitSha(&sha); |
804 |
|
|
wc_ShaUpdate(&sha, (const unsigned char *) key, key_length); |
805 |
|
|
wc_ShaFinal(&sha, (unsigned char *)sha1Key); |
806 |
|
|
|
807 |
|
|
if ( unlikely(NULL == (*accept_key = WSS_malloc((SHA_DIGEST_LENGTH*4)/3+1))) ) { |
808 |
|
|
return 0; |
809 |
|
|
} |
810 |
|
|
|
811 |
|
|
*accept_key = b64_encode((const unsigned char *) sha1Key, SHA_DIGEST_LENGTH); |
812 |
|
|
acceptKeyLength = strlen(*accept_key); |
813 |
|
|
#else |
814 |
|
|
SHA1Context sha; |
815 |
|
|
int i, b; |
816 |
|
|
|
817 |
|
|
SHA1Reset(&sha); |
818 |
|
|
SHA1Input(&sha, (const unsigned char*) key, key_length); |
819 |
|
|
if ( likely(SHA1Result(&sha)) ) { |
820 |
|
|
for (i = 0; likely(i < 5); i++) { |
821 |
|
|
b = htonl(sha.Message_Digest[i]); |
822 |
|
|
memcpy(sha1Key+(4*i), (unsigned char *) &b, 4); |
823 |
|
|
} |
824 |
|
|
} else { |
825 |
|
|
return 0; |
826 |
|
|
} |
827 |
|
|
|
828 |
|
|
*accept_key = b64_encode((const unsigned char *) sha1Key, SHA_DIGEST_LENGTH); |
829 |
|
|
acceptKeyLength = strlen(*accept_key); |
830 |
|
|
#endif |
831 |
|
|
|
832 |
|
|
return acceptKeyLength; |
833 |
|
|
} |