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