GCC Code Coverage Report
Directory: ./ Exec Total Coverage
File: src/ssl.c Lines: 0 236 0.0 %
Date: 2020-12-10 21:44:00 Branches: 0 74 0.0 %

Line Branch Exec Source
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
}