ssl pending buffered reads use linked list
[platform/upstream/libwebsockets.git] / lib / ssl.c
1 /*
2  * libwebsockets - small server side websockets and web server implementation
3  *
4  * Copyright (C) 2010-2014 Andy Green <andy@warmcat.com>
5  *
6  *  This library is free software; you can redistribute it and/or
7  *  modify it under the terms of the GNU Lesser General Public
8  *  License as published by the Free Software Foundation:
9  *  version 2.1 of the License.
10  *
11  *  This library 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 GNU
14  *  Lesser General Public License for more details.
15  *
16  *  You should have received a copy of the GNU Lesser General Public
17  *  License along with this library; if not, write to the Free Software
18  *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
19  *  MA  02110-1301  USA
20  */
21
22 #include "private-libwebsockets.h"
23  #include <openssl/err.h>
24
25 int openssl_websocket_private_data_index;
26
27 static int lws_context_init_ssl_pem_passwd_cb(char * buf, int size, int rwflag, void *userdata)
28 {
29         struct lws_context_creation_info * info = (struct lws_context_creation_info *)userdata;
30
31         strncpy(buf, info->ssl_private_key_password, size);
32         buf[size - 1] = '\0';
33
34         return strlen(buf);
35 }
36
37 static void lws_ssl_bind_passphrase(SSL_CTX *ssl_ctx,
38                                     struct lws_context_creation_info *info)
39 {
40         if (!info->ssl_private_key_password)
41                 return;
42         /*
43          * password provided, set ssl callback and user data
44          * for checking password which will be trigered during
45          * SSL_CTX_use_PrivateKey_file function
46          */
47         SSL_CTX_set_default_passwd_cb_userdata(ssl_ctx, (void *)info);
48         SSL_CTX_set_default_passwd_cb(ssl_ctx,
49                                       lws_context_init_ssl_pem_passwd_cb);
50 }
51
52 #ifndef LWS_NO_SERVER
53 static int
54 OpenSSL_verify_callback(int preverify_ok, X509_STORE_CTX *x509_ctx)
55 {
56         SSL *ssl;
57         int n;
58         struct libwebsocket_context *context;
59
60         ssl = X509_STORE_CTX_get_ex_data(x509_ctx,
61                 SSL_get_ex_data_X509_STORE_CTX_idx());
62
63         /*
64          * !!! nasty openssl requires the index to come as a library-scope
65          * static
66          */
67         context = SSL_get_ex_data(ssl, openssl_websocket_private_data_index);
68
69         n = context->protocols[0].callback(NULL, NULL,
70                 LWS_CALLBACK_OPENSSL_PERFORM_CLIENT_CERT_VERIFICATION,
71                                                    x509_ctx, ssl, preverify_ok);
72
73         /* convert return code from 0 = OK to 1 = OK */
74         return !n;
75 }
76
77 LWS_VISIBLE int
78 lws_context_init_server_ssl(struct lws_context_creation_info *info,
79                      struct libwebsocket_context *context)
80 {
81         SSL_METHOD *method;
82         int error;
83         int n;
84
85         if (info->port != CONTEXT_PORT_NO_LISTEN) {
86
87                 context->use_ssl = info->ssl_cert_filepath != NULL;
88
89 #ifdef USE_CYASSL
90                 lwsl_notice(" Compiled with CYASSL support\n");
91 #else
92                 lwsl_notice(" Compiled with OpenSSL support\n");
93 #endif
94                 
95                 if (info->ssl_cipher_list)
96                         lwsl_notice(" SSL ciphers: '%s'\n", info->ssl_cipher_list);
97
98                 if (context->use_ssl)
99                         lwsl_notice(" Using SSL mode\n");
100                 else
101                         lwsl_notice(" Using non-SSL mode\n");
102         }
103
104         /* basic openssl init */
105
106         SSL_library_init();
107
108         OpenSSL_add_all_algorithms();
109         SSL_load_error_strings();
110
111         openssl_websocket_private_data_index =
112                 SSL_get_ex_new_index(0, "libwebsockets", NULL, NULL, NULL);
113
114         /*
115          * Firefox insists on SSLv23 not SSLv3
116          * Konq disables SSLv2 by default now, SSLv23 works
117          *
118          * SSLv23_server_method() is the openssl method for "allow all TLS
119          * versions", compared to e.g. TLSv1_2_server_method() which only allows
120          * tlsv1.2. Unwanted versions must be disabled using SSL_CTX_set_options()
121          */
122
123         method = (SSL_METHOD *)SSLv23_server_method();
124         if (!method) {
125                 error = ERR_get_error();
126                 lwsl_err("problem creating ssl method %lu: %s\n", 
127                         error, ERR_error_string(error,
128                                               (char *)context->service_buffer));
129                 return 1;
130         }
131         context->ssl_ctx = SSL_CTX_new(method); /* create context */
132         if (!context->ssl_ctx) {
133                 error = ERR_get_error();
134                 lwsl_err("problem creating ssl context %lu: %s\n",
135                         error, ERR_error_string(error,
136                                               (char *)context->service_buffer));
137                 return 1;
138         }
139
140         /* Disable SSLv2 and SSLv3 */
141         SSL_CTX_set_options(context->ssl_ctx, SSL_OP_NO_SSLv2 | SSL_OP_NO_SSLv3);
142 #ifdef SSL_OP_NO_COMPRESSION
143         SSL_CTX_set_options(context->ssl_ctx, SSL_OP_NO_COMPRESSION);
144 #endif
145         SSL_CTX_set_options(context->ssl_ctx, SSL_OP_CIPHER_SERVER_PREFERENCE);
146         if (info->ssl_cipher_list)
147                 SSL_CTX_set_cipher_list(context->ssl_ctx,
148                                                 info->ssl_cipher_list);
149
150         /* as a server, are we requiring clients to identify themselves? */
151
152         if (info->options &
153                         LWS_SERVER_OPTION_REQUIRE_VALID_OPENSSL_CLIENT_CERT) {
154
155                 /* absolutely require the client cert */
156
157                 SSL_CTX_set_verify(context->ssl_ctx,
158                        SSL_VERIFY_PEER | SSL_VERIFY_FAIL_IF_NO_PEER_CERT,
159                                                        OpenSSL_verify_callback);
160
161                 /*
162                  * give user code a chance to load certs into the server
163                  * allowing it to verify incoming client certs
164                  */
165
166                 context->protocols[0].callback(context, NULL,
167                         LWS_CALLBACK_OPENSSL_LOAD_EXTRA_SERVER_VERIFY_CERTS,
168                                                      context->ssl_ctx, NULL, 0);
169         }
170
171         if (info->options & LWS_SERVER_OPTION_ALLOW_NON_SSL_ON_SSL_PORT) {
172                 /* Normally SSL listener rejects non-ssl, optionally allow */
173                 context->allow_non_ssl_on_ssl_port = 1;
174         }
175
176         if (context->use_ssl) {
177
178                 /* openssl init for server sockets */
179
180                 /* set the local certificate from CertFile */
181                 n = SSL_CTX_use_certificate_chain_file(context->ssl_ctx,
182                                         info->ssl_cert_filepath);
183                 if (n != 1) {
184                         error = ERR_get_error();
185                         lwsl_err("problem getting cert '%s' %lu: %s\n",
186                                 info->ssl_cert_filepath,
187                                 error,
188                                 ERR_error_string(error,
189                                               (char *)context->service_buffer));
190                         return 1;
191                 }
192                 lws_ssl_bind_passphrase(context->ssl_ctx, info);
193
194                 if (info->ssl_private_key_filepath != NULL) {
195                         /* set the private key from KeyFile */
196                         if (SSL_CTX_use_PrivateKey_file(context->ssl_ctx,
197                                      info->ssl_private_key_filepath,
198                                                        SSL_FILETYPE_PEM) != 1) {
199                                 error = ERR_get_error();
200                                 lwsl_err("ssl problem getting key '%s' %lu: %s\n",
201                                         info->ssl_private_key_filepath,
202                                                 error,
203                                                 ERR_error_string(error,
204                                                       (char *)context->service_buffer));
205                                 return 1;
206                         }
207                 }
208                 else {
209                         if (context->protocols[0].callback(context, NULL,
210                                 LWS_CALLBACK_OPENSSL_CONTEXT_REQUIRES_PRIVATE_KEY,
211                                                 context->ssl_ctx, NULL, 0)) {
212                                 lwsl_err("ssl private key not set\n");
213                                 return 1;
214                         }
215                 }
216
217                 /* verify private key */
218                 if (!SSL_CTX_check_private_key(context->ssl_ctx)) {
219                         lwsl_err("Private SSL key doesn't match cert\n");
220                         return 1;
221                 }
222
223                 /*
224                  * SSL is happy and has a cert it's content with
225                  * If we're supporting HTTP2, initialize that
226                  */
227                 
228                 lws_context_init_http2_ssl(context);
229         }
230         
231         return 0;
232 }
233 #endif
234
235 LWS_VISIBLE void
236 lws_ssl_destroy(struct libwebsocket_context *context)
237 {
238         if (context->ssl_ctx)
239                 SSL_CTX_free(context->ssl_ctx);
240         if (!context->user_supplied_ssl_ctx && context->ssl_client_ctx)
241                 SSL_CTX_free(context->ssl_client_ctx);
242
243 #if (OPENSSL_VERSION_NUMBER < 0x01000000) || defined(USE_CYASSL)
244         ERR_remove_state(0);
245 #else
246         ERR_remove_thread_state(NULL);
247 #endif
248         ERR_free_strings();
249         EVP_cleanup();
250         CRYPTO_cleanup_all_ex_data();
251 }
252
253 LWS_VISIBLE void
254 libwebsockets_decode_ssl_error(void)
255 {
256         char buf[256];
257         u_long err;
258
259         while ((err = ERR_get_error()) != 0) {
260                 ERR_error_string_n(err, buf, sizeof(buf));
261                 lwsl_err("*** %lu %s\n", err, buf);
262         }
263 }
264
265 #ifndef LWS_NO_CLIENT
266
267 int lws_context_init_client_ssl(struct lws_context_creation_info *info,
268                             struct libwebsocket_context *context)
269 {
270         int error;
271         int n;
272         SSL_METHOD *method;
273
274         if (info->provided_client_ssl_ctx) {
275                 /* use the provided OpenSSL context if given one */
276                 context->ssl_client_ctx = info->provided_client_ssl_ctx;
277                 /* nothing for lib to delete */
278                 context->user_supplied_ssl_ctx = 1;
279                 return 0;
280         }
281
282         if (info->port != CONTEXT_PORT_NO_LISTEN)
283                 return 0;
284
285         /* basic openssl init */
286
287         SSL_library_init();
288
289         OpenSSL_add_all_algorithms();
290         SSL_load_error_strings();
291
292         method = (SSL_METHOD *)SSLv23_client_method();
293         if (!method) {
294                 error = ERR_get_error();
295                 lwsl_err("problem creating ssl method %lu: %s\n",
296                         error, ERR_error_string(error,
297                                       (char *)context->service_buffer));
298                 return 1;
299         }
300         /* create context */
301         context->ssl_client_ctx = SSL_CTX_new(method);
302         if (!context->ssl_client_ctx) {
303                 error = ERR_get_error();
304                 lwsl_err("problem creating ssl context %lu: %s\n",
305                         error, ERR_error_string(error,
306                                       (char *)context->service_buffer));
307                 return 1;
308         }
309
310 #ifdef SSL_OP_NO_COMPRESSION
311         SSL_CTX_set_options(context->ssl_client_ctx,
312                                                  SSL_OP_NO_COMPRESSION);
313 #endif
314         SSL_CTX_set_options(context->ssl_client_ctx,
315                                        SSL_OP_CIPHER_SERVER_PREFERENCE);
316         if (info->ssl_cipher_list)
317                 SSL_CTX_set_cipher_list(context->ssl_client_ctx,
318                                                 info->ssl_cipher_list);
319
320 #ifdef LWS_SSL_CLIENT_USE_OS_CA_CERTS
321         if (!(info->options & LWS_SERVER_OPTION_DISABLE_OS_CA_CERTS))
322                 /* loads OS default CA certs */
323                 SSL_CTX_set_default_verify_paths(context->ssl_client_ctx);
324 #endif
325
326         /* openssl init for cert verification (for client sockets) */
327         if (!info->ssl_ca_filepath) {
328                 if (!SSL_CTX_load_verify_locations(
329                         context->ssl_client_ctx, NULL,
330                                              LWS_OPENSSL_CLIENT_CERTS))
331                         lwsl_err(
332                             "Unable to load SSL Client certs from %s "
333                             "(set by --with-client-cert-dir= "
334                             "in configure) --  client ssl isn't "
335                             "going to work", LWS_OPENSSL_CLIENT_CERTS);
336         } else
337                 if (!SSL_CTX_load_verify_locations(
338                         context->ssl_client_ctx, info->ssl_ca_filepath,
339                                                           NULL))
340                         lwsl_err(
341                                 "Unable to load SSL Client certs "
342                                 "file from %s -- client ssl isn't "
343                                 "going to work", info->ssl_ca_filepath);
344                 else
345                         lwsl_info("loaded ssl_ca_filepath\n");
346
347         /*
348          * callback allowing user code to load extra verification certs
349          * helping the client to verify server identity
350          */
351
352         /* support for client-side certificate authentication */
353         if (info->ssl_cert_filepath) {
354                 n = SSL_CTX_use_certificate_chain_file(
355                         context->ssl_client_ctx,
356                                         info->ssl_cert_filepath);
357                 if (n != 1) {
358                         lwsl_err("problem getting cert '%s' %lu: %s\n",
359                                 info->ssl_cert_filepath,
360                                 ERR_get_error(),
361                                 ERR_error_string(ERR_get_error(),
362                                 (char *)context->service_buffer));
363                         return 1;
364                 }
365         } 
366         if (info->ssl_private_key_filepath) {
367                 lws_ssl_bind_passphrase(context->ssl_client_ctx, info);
368                 /* set the private key from KeyFile */
369                 if (SSL_CTX_use_PrivateKey_file(context->ssl_client_ctx,
370                     info->ssl_private_key_filepath, SSL_FILETYPE_PEM) != 1) {
371                         lwsl_err("use_PrivateKey_file '%s' %lu: %s\n",
372                                 info->ssl_private_key_filepath,
373                                 ERR_get_error(),
374                                 ERR_error_string(ERR_get_error(),
375                                       (char *)context->service_buffer));
376                         return 1;
377                 }
378
379                 /* verify private key */
380                 if (!SSL_CTX_check_private_key(
381                                         context->ssl_client_ctx)) {
382                         lwsl_err("Private SSL key doesn't match cert\n");
383                         return 1;
384                 }
385         } 
386
387         context->protocols[0].callback(context, NULL,
388                 LWS_CALLBACK_OPENSSL_LOAD_EXTRA_CLIENT_VERIFY_CERTS,
389                 context->ssl_client_ctx, NULL, 0);
390         
391         return 0;
392 }
393 #endif
394
395 LWS_VISIBLE void
396 lws_ssl_remove_wsi_from_buffered_list(struct libwebsocket_context *context,
397                      struct libwebsocket *wsi)
398 {
399         if (!wsi->pending_read_list_prev &&
400             !wsi->pending_read_list_next &&
401             context->pending_read_list != wsi)
402                 /* we are not on the list */
403                 return;
404
405         /* point previous guy's next to our next */
406         if (!wsi->pending_read_list_prev)
407                 context->pending_read_list = wsi->pending_read_list_next;
408         else
409                 wsi->pending_read_list_prev->pending_read_list_next =
410                         wsi->pending_read_list_next;
411
412         /* point next guy's previous to our previous */
413         if (wsi->pending_read_list_next)
414                 wsi->pending_read_list_next->pending_read_list_prev =
415                         wsi->pending_read_list_prev;
416
417         wsi->pending_read_list_prev = NULL;
418         wsi->pending_read_list_next = NULL;
419 }
420
421 LWS_VISIBLE int
422 lws_ssl_capable_read(struct libwebsocket_context *context,
423                      struct libwebsocket *wsi, unsigned char *buf, int len)
424 {
425         int n;
426
427         if (!wsi->ssl)
428                 return lws_ssl_capable_read_no_ssl(context, wsi, buf, len);
429
430         n = SSL_read(wsi->ssl, buf, len);
431         if (n >= 0) {
432                 /* 
433                  * if it was our buffer that limited what we read,
434                  * check if SSL has additional data pending inside SSL buffers.
435                  * 
436                  * Because these won't signal at the network layer with POLLIN
437                  * and if we don't realize, this data will sit there forever
438                  */
439                 if (n == len && wsi->ssl && SSL_pending(wsi->ssl)) {
440                         assert(!wsi->pending_read_list_next && !wsi->pending_read_list_prev);
441                         /* add us to the linked list of guys with pending ssl */
442                         context->pending_read_list->pending_read_list_prev = wsi;
443                         wsi->pending_read_list_next = context->pending_read_list;
444                         wsi->pending_read_list_prev = NULL;
445                         context->pending_read_list = wsi;
446                 }
447
448                 return n;
449         }
450         n = SSL_get_error(wsi->ssl, n);
451         if (n ==  SSL_ERROR_WANT_READ || n ==  SSL_ERROR_WANT_WRITE)
452                 return LWS_SSL_CAPABLE_MORE_SERVICE;
453
454         return LWS_SSL_CAPABLE_ERROR; 
455 }
456
457 LWS_VISIBLE int
458 lws_ssl_capable_write(struct libwebsocket *wsi, unsigned char *buf, int len)
459 {
460         int n;
461
462         if (!wsi->ssl)
463                 return lws_ssl_capable_write_no_ssl(wsi, buf, len);
464         
465         n = SSL_write(wsi->ssl, buf, len);
466         if (n >= 0)
467                 return n;
468
469         n = SSL_get_error(wsi->ssl, n);
470         if (n == SSL_ERROR_WANT_READ || n == SSL_ERROR_WANT_WRITE) {
471                 if (n == SSL_ERROR_WANT_WRITE)
472                         lws_set_blocking_send(wsi);
473                 return LWS_SSL_CAPABLE_MORE_SERVICE;
474         }
475
476         return LWS_SSL_CAPABLE_ERROR;
477 }
478
479 LWS_VISIBLE int
480 lws_ssl_close(struct libwebsocket *wsi)
481 {
482         int n;
483
484         if (!wsi->ssl)
485                 return 0; /* not handled */
486
487         n = SSL_get_fd(wsi->ssl);
488         SSL_shutdown(wsi->ssl);
489         compatible_close(n);
490         SSL_free(wsi->ssl);
491
492         return 1; /* handled */
493 }
494
495 LWS_VISIBLE int
496 lws_server_socket_service_ssl(struct libwebsocket_context *context,
497                 struct libwebsocket **pwsi, struct libwebsocket *new_wsi,
498                         int accept_fd, struct libwebsocket_pollfd *pollfd)
499 {
500         int n, m;
501         struct libwebsocket *wsi = *pwsi;
502 #ifndef USE_CYASSL
503         BIO *bio;
504 #endif
505
506         if (!LWS_SSL_ENABLED(context))
507                 return 0;
508
509         switch (wsi->mode) {
510         case LWS_CONNMODE_SERVER_LISTENER:
511
512                 if (!new_wsi) {
513                         lwsl_err("no new_wsi\n");
514                         return 0;
515                 }
516
517                 new_wsi->ssl = SSL_new(context->ssl_ctx);
518                 if (new_wsi->ssl == NULL) {
519                         lwsl_err("SSL_new failed: %s\n",
520                             ERR_error_string(SSL_get_error(
521                             new_wsi->ssl, 0), NULL));
522                             libwebsockets_decode_ssl_error();
523                         lws_free(new_wsi);
524                         compatible_close(accept_fd);
525                         break;
526                 }
527
528                 SSL_set_ex_data(new_wsi->ssl,
529                         openssl_websocket_private_data_index, context);
530
531                 SSL_set_fd(new_wsi->ssl, accept_fd);
532
533 #ifdef USE_CYASSL
534                 CyaSSL_set_using_nonblock(new_wsi->ssl, 1);
535 #else
536                 SSL_set_mode(new_wsi->ssl, SSL_MODE_ACCEPT_MOVING_WRITE_BUFFER);
537                 bio = SSL_get_rbio(new_wsi->ssl);
538                 if (bio)
539                         BIO_set_nbio(bio, 1); /* nonblocking */
540                 else
541                         lwsl_notice("NULL rbio\n");
542                 bio = SSL_get_wbio(new_wsi->ssl);
543                 if (bio)
544                         BIO_set_nbio(bio, 1); /* nonblocking */
545                 else
546                         lwsl_notice("NULL rbio\n");
547 #endif
548
549                 /*
550                  * we are not accepted yet, but we need to enter ourselves
551                  * as a live connection.  That way we can retry when more
552                  * pieces come if we're not sorted yet
553                  */
554
555                 *pwsi = new_wsi;
556                 wsi = *pwsi;
557                 wsi->mode = LWS_CONNMODE_SSL_ACK_PENDING;
558                 insert_wsi_socket_into_fds(context, wsi);
559
560                 libwebsocket_set_timeout(wsi, PENDING_TIMEOUT_SSL_ACCEPT,
561                                                         AWAITING_TIMEOUT);
562
563                 lwsl_info("inserted SSL accept into fds, trying SSL_accept\n");
564
565                 /* fallthru */
566
567         case LWS_CONNMODE_SSL_ACK_PENDING:
568
569                 if (lws_change_pollfd(wsi, LWS_POLLOUT, 0))
570                         goto fail;
571
572                 lws_libev_io(context, wsi, LWS_EV_STOP | LWS_EV_WRITE);
573
574                 lws_latency_pre(context, wsi);
575
576                 n = recv(wsi->sock, context->service_buffer,
577                         sizeof(context->service_buffer), MSG_PEEK);
578
579                 /*
580                  * optionally allow non-SSL connect on SSL listening socket
581                  * This is disabled by default, if enabled it goes around any
582                  * SSL-level access control (eg, client-side certs) so leave
583                  * it disabled unless you know it's not a problem for you
584                  */
585
586                 if (context->allow_non_ssl_on_ssl_port && n >= 1 &&
587                                         context->service_buffer[0] >= ' ') {
588                         /*
589                          * TLS content-type for Handshake is 0x16
590                          * TLS content-type for ChangeCipherSpec Record is 0x14
591                          *
592                          * A non-ssl session will start with the HTTP method in
593                          * ASCII.  If we see it's not a legit SSL handshake
594                          * kill the SSL for this connection and try to handle
595                          * as a HTTP connection upgrade directly.
596                          */
597                         wsi->use_ssl = 0;
598                         SSL_shutdown(wsi->ssl);
599                         SSL_free(wsi->ssl);
600                         wsi->ssl = NULL;
601                         goto accepted;
602                 }
603
604                 /* normal SSL connection processing path */
605
606                 n = SSL_accept(wsi->ssl);
607                 lws_latency(context, wsi,
608                         "SSL_accept LWS_CONNMODE_SSL_ACK_PENDING\n", n, n == 1);
609
610                 if (n == 1)
611                         goto accepted;
612
613                 m = SSL_get_error(wsi->ssl, n);
614                 lwsl_debug("SSL_accept failed %d / %s\n",
615                                                   m, ERR_error_string(m, NULL));
616
617                 if (m == SSL_ERROR_WANT_READ) {
618                         if (lws_change_pollfd(wsi, 0, LWS_POLLIN))
619                                 goto fail;
620
621                         lws_libev_io(context, wsi, LWS_EV_START | LWS_EV_READ);
622
623                         lwsl_info("SSL_ERROR_WANT_READ\n");
624                         break;
625                 }
626                 if (m == SSL_ERROR_WANT_WRITE) {
627                         if (lws_change_pollfd(wsi, 0, LWS_POLLOUT))
628                                 goto fail;
629
630                         lws_libev_io(context, wsi, LWS_EV_START | LWS_EV_WRITE);
631                         break;
632                 }
633                 lwsl_debug("SSL_accept failed skt %u: %s\n",
634                                          pollfd->fd, ERR_error_string(m, NULL));
635                 goto fail;
636
637 accepted:
638                 /* OK, we are accepted... give him some time to negotiate */
639                 libwebsocket_set_timeout(wsi,
640                         PENDING_TIMEOUT_ESTABLISH_WITH_SERVER,
641                                                         AWAITING_TIMEOUT);
642
643                 wsi->mode = LWS_CONNMODE_HTTP_SERVING;
644
645                 lws_http2_configure_if_upgraded(wsi);
646
647                 lwsl_debug("accepted new SSL conn\n");
648                 break;
649         }
650
651         return 0;
652         
653 fail:
654         return 1;
655 }
656
657 LWS_VISIBLE void
658 lws_ssl_context_destroy(struct libwebsocket_context *context)
659 {
660         if (context->ssl_ctx)
661                 SSL_CTX_free(context->ssl_ctx);
662         if (!context->user_supplied_ssl_ctx && context->ssl_client_ctx)
663                 SSL_CTX_free(context->ssl_client_ctx);
664
665 #if (OPENSSL_VERSION_NUMBER < 0x01000000) || defined(USE_CYASSL)
666         ERR_remove_state(0);
667 #else
668         ERR_remove_thread_state(NULL);
669 #endif
670         ERR_free_strings();
671         EVP_cleanup();
672         CRYPTO_cleanup_all_ex_data();
673 }