From 102d40e6b6486076f37a46708604ec387834f16c Mon Sep 17 00:00:00 2001 From: Andy Green Date: Sat, 11 Mar 2017 11:51:06 +0800 Subject: [PATCH] esp32: openssl --- CMakeLists.txt | 2 +- lib/libwebsockets.h | 2 +- lib/lws-plat-esp32.c | 3 +- lib/ssl-client.c | 6 +-- lib/ssl-server.c | 69 ++++++++++++++++++++++++++++---- lib/ssl.c | 109 ++++++++++++++++++++++++++++++++++++++++++--------- 6 files changed, 159 insertions(+), 32 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index be757da..9f3ddda 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -165,7 +165,7 @@ endif() if (LWS_WITH_ESP32) set(LWS_WITH_SHARED OFF) - set(LWS_WITH_SSL OFF) + set(LWS_WITH_SSL ON) set(LWS_WITH_ZLIB OFF) # set(LWS_WITHOUT_CLIENT ON) set(LWS_WITHOUT_TESTAPPS ON) diff --git a/lib/libwebsockets.h b/lib/libwebsockets.h index 9e92e22..1e292c3 100644 --- a/lib/libwebsockets.h +++ b/lib/libwebsockets.h @@ -114,7 +114,7 @@ struct sockaddr_in; #include #define LWS_INVALID_FILE -1 #else -#define getdtablesize() (20) +#define getdtablesize() (30) #if defined(LWS_WITH_ESP32) #define LWS_INVALID_FILE NULL #else diff --git a/lib/lws-plat-esp32.c b/lib/lws-plat-esp32.c index d787005..63315f2 100644 --- a/lib/lws-plat-esp32.c +++ b/lib/lws-plat-esp32.c @@ -743,7 +743,7 @@ lws_esp32_wlan_start(void) ESP_ERROR_CHECK( esp_wifi_init(&cfg)); ESP_ERROR_CHECK( esp_wifi_set_storage(WIFI_STORAGE_RAM)); - ESP_ERROR_CHECK( esp_wifi_set_country(lws_esp32_region)); + esp_wifi_set_country(lws_esp32_region); if (!lws_esp32_is_booting_in_ap_mode() && !lws_esp32_force_ap) { ESP_ERROR_CHECK( esp_wifi_set_mode(WIFI_MODE_STA)); @@ -754,6 +754,7 @@ lws_esp32_wlan_start(void) } ESP_ERROR_CHECK( esp_wifi_start()); + tcpip_adapter_set_hostname(TCPIP_ADAPTER_IF_STA, (const char *)&ap_config.ap.ssid[7]); if (!lws_esp32_is_booting_in_ap_mode() && !lws_esp32_force_ap) diff --git a/lib/ssl-client.c b/lib/ssl-client.c index 6cbfd78..c89d3c8 100644 --- a/lib/ssl-client.c +++ b/lib/ssl-client.c @@ -29,7 +29,7 @@ lws_ssl_bind_passphrase(SSL_CTX *ssl_ctx, struct lws_context_creation_info *info extern int lws_ssl_get_error(struct lws *wsi, int n); -#ifdef USE_WOLFSSL +#if defined(USE_WOLFSSL) || defined(LWS_WITH_ESP32) #else static int @@ -137,14 +137,14 @@ lws_ssl_client_bio_create(struct lws *wsi) #endif -#ifndef USE_WOLFSSL +#if !defined(USE_WOLFSSL) && !defined(LWS_WITH_ESP32) #ifndef USE_OLD_CYASSL /* OpenSSL_client_verify_callback will be called @ SSL_connect() */ SSL_set_verify(wsi->ssl, SSL_VERIFY_PEER, OpenSSL_client_verify_callback); #endif #endif -#ifndef USE_WOLFSSL +#if !defined(USE_WOLFSSL) && !defined(LWS_WITH_ESP32) SSL_set_mode(wsi->ssl, SSL_MODE_ACCEPT_MOVING_WRITE_BUFFER); #endif /* diff --git a/lib/ssl-server.c b/lib/ssl-server.c index 91e3b58..6406011 100644 --- a/lib/ssl-server.c +++ b/lib/ssl-server.c @@ -27,6 +27,7 @@ extern int openssl_websocket_private_data_index, extern void lws_ssl_bind_passphrase(SSL_CTX *ssl_ctx, struct lws_context_creation_info *info); +#if !defined(LWS_WITH_ESP32) static int OpenSSL_verify_callback(int preverify_ok, X509_STORE_CTX *x509_ctx) { @@ -50,6 +51,7 @@ OpenSSL_verify_callback(int preverify_ok, X509_STORE_CTX *x509_ctx) /* convert return code from 0 = OK to 1 = OK */ return !n; } +#endif static int lws_context_ssl_init_ecdh(struct lws_vhost *vhost) @@ -226,7 +228,7 @@ lws_context_init_server_ssl(struct lws_context_creation_info *info, * versions", compared to e.g. TLSv1_2_server_method() which only allows * tlsv1.2. Unwanted versions must be disabled using SSL_CTX_set_options() */ - +#if !defined(LWS_WITH_ESP32) { SSL_METHOD *method; @@ -247,12 +249,24 @@ lws_context_init_server_ssl(struct lws_context_creation_info *info, return 1; } } +#else + { + const SSL_METHOD *method = TLSv1_2_server_method(); + + vhost->ssl_ctx = SSL_CTX_new(method); /* create context */ + if (!vhost->ssl_ctx) { + lwsl_err("problem creating ssl context\n"); + return 1; + } + + } +#endif +#if !defined(LWS_WITH_ESP32) /* associate the lws context with the SSL_CTX */ SSL_CTX_set_ex_data(vhost->ssl_ctx, - openssl_SSL_CTX_private_data_index, vhost->context); - + openssl_SSL_CTX_private_data_index, (char *)vhost->context); /* Disable SSLv2 and SSLv3 */ SSL_CTX_set_options(vhost->ssl_ctx, SSL_OP_NO_SSLv2 | SSL_OP_NO_SSLv3); #ifdef SSL_OP_NO_COMPRESSION @@ -260,9 +274,11 @@ lws_context_init_server_ssl(struct lws_context_creation_info *info, #endif SSL_CTX_set_options(vhost->ssl_ctx, SSL_OP_SINGLE_DH_USE); SSL_CTX_set_options(vhost->ssl_ctx, SSL_OP_CIPHER_SERVER_PREFERENCE); + if (info->ssl_cipher_list) SSL_CTX_set_cipher_list(vhost->ssl_ctx, info->ssl_cipher_list); +#endif /* as a server, are we requiring clients to identify themselves? */ @@ -274,6 +290,7 @@ lws_context_init_server_ssl(struct lws_context_creation_info *info, LWS_SERVER_OPTION_PEER_CERT_NOT_REQUIRED)) verify_options |= SSL_VERIFY_FAIL_IF_NO_PEER_CERT; +#if !defined(LWS_WITH_ESP32) SSL_CTX_set_session_id_context(vhost->ssl_ctx, (unsigned char *)context, sizeof(void *)); @@ -281,6 +298,7 @@ lws_context_init_server_ssl(struct lws_context_creation_info *info, SSL_CTX_set_verify(vhost->ssl_ctx, verify_options, OpenSSL_verify_callback); +#endif } #ifndef OPENSSL_NO_TLSEXT @@ -292,13 +310,13 @@ lws_context_init_server_ssl(struct lws_context_creation_info *info, * give user code a chance to load certs into the server * allowing it to verify incoming client certs */ - +#if !defined(LWS_WITH_ESP32) if (info->ssl_ca_filepath && !SSL_CTX_load_verify_locations(vhost->ssl_ctx, info->ssl_ca_filepath, NULL)) { lwsl_err("%s: SSL_CTX_load_verify_locations unhappy\n", __func__); } - +#endif if (vhost->use_ssl) { if (lws_context_ssl_init_ecdh_curve(info, vhost)) return -1; @@ -326,7 +344,7 @@ lws_context_init_server_ssl(struct lws_context_creation_info *info, if (vhost->use_ssl) { /* openssl init for server sockets */ - +#if !defined(LWS_WITH_ESP32) /* set the local certificate from CertFile */ n = SSL_CTX_use_certificate_chain_file(vhost->ssl_ctx, info->ssl_cert_filepath); @@ -340,8 +358,42 @@ lws_context_init_server_ssl(struct lws_context_creation_info *info, return 1; } lws_ssl_bind_passphrase(vhost->ssl_ctx, info); +#else + uint8_t *p; + lws_filepos_t flen; + int err; + + if (alloc_file(vhost->context, info->ssl_cert_filepath, &p, + &flen)) { + lwsl_err("couldn't find cert file %s\n", + info->ssl_cert_filepath); + + return 1; + } + err = SSL_CTX_use_certificate_ASN1(vhost->ssl_ctx, flen, p); + if (!err) { + lwsl_err("Problem loading cert\n"); + return 1; + } + + if (alloc_file(vhost->context, + info->ssl_private_key_filepath, &p, &flen)) { + lwsl_err("couldn't find cert file %s\n", + info->ssl_cert_filepath); + return 1; + } + err = SSL_CTX_use_PrivateKey_ASN1(0, vhost->ssl_ctx, p, flen); + if (!err) { + lwsl_err("Problem loading key\n"); + + return 1; + } + +// free(p); +#endif if (info->ssl_private_key_filepath != NULL) { +#if !defined(LWS_WITH_ESP32) /* set the private key from KeyFile */ if (SSL_CTX_use_PrivateKey_file(vhost->ssl_ctx, info->ssl_private_key_filepath, @@ -353,6 +405,7 @@ lws_context_init_server_ssl(struct lws_context_creation_info *info, (char *)context->pt[0].serv_buf)); return 1; } +#endif } else if (vhost->protocols[0].callback(&wsi, LWS_CALLBACK_OPENSSL_CONTEXT_REQUIRES_PRIVATE_KEY, @@ -361,13 +414,13 @@ lws_context_init_server_ssl(struct lws_context_creation_info *info, return 1; } - +#if !defined(LWS_WITH_ESP32) /* verify private key */ if (!SSL_CTX_check_private_key(vhost->ssl_ctx)) { lwsl_err("Private SSL key doesn't match cert\n"); return 1; } - +#endif if (lws_context_ssl_init_ecdh(vhost)) return 1; diff --git a/lib/ssl.c b/lib/ssl.c index 3b6c4a0..a884942 100644 --- a/lib/ssl.c +++ b/lib/ssl.c @@ -21,12 +21,44 @@ #include "private-libwebsockets.h" +#if defined(LWS_WITH_ESP32) +int alloc_file(struct lws_context *context, const char *filename, uint8_t **buf, + lws_filepos_t *amount) +{ + lws_filepos_t len; + lws_fop_flags_t flags = LWS_O_RDONLY; + lws_fop_fd_t fops_fd = lws_vfs_file_open( + lws_get_fops(context), filename, &flags); + int ret = 1; + + if (!fops_fd) + return 1; + + len = lws_vfs_get_length(fops_fd); + + *buf = malloc(len); + if (!buf) + goto bail; + + if (lws_vfs_file_read(fops_fd, amount, *buf, len)) + goto bail; + + ret = 0; +bail: + lws_vfs_file_close(&fops_fd); + + return ret; +} +#endif int openssl_websocket_private_data_index, openssl_SSL_CTX_private_data_index; int lws_ssl_get_error(struct lws *wsi, int n) { + if (!wsi->ssl) + return 99; + lwsl_debug("%s: %p %d\n", __func__, wsi->ssl, n); return SSL_get_error(wsi->ssl, n); } @@ -77,6 +109,8 @@ char* lws_ssl_get_error_string(int status, int ret, char *buf, size_t len) { void lws_ssl_elaborate_error(void) { +#if defined(LWS_WITH_ESP32) +#else char buf[256]; u_long err; @@ -84,8 +118,11 @@ lws_ssl_elaborate_error(void) ERR_error_string_n(err, buf, sizeof(buf)); lwsl_err("*** %s\n", buf); } +#endif } +#if !defined(LWS_WITH_ESP32) + static int lws_context_init_ssl_pem_passwd_cb(char * buf, int size, int rwflag, void *userdata) { @@ -103,7 +140,6 @@ lws_ssl_bind_passphrase(SSL_CTX *ssl_ctx, struct lws_context_creation_info *info { if (!info->ssl_private_key_password) return; - /* * password provided, set ssl callback and user data * for checking password which will be trigered during @@ -112,6 +148,7 @@ lws_ssl_bind_passphrase(SSL_CTX *ssl_ctx, struct lws_context_creation_info *info SSL_CTX_set_default_passwd_cb_userdata(ssl_ctx, (void *)info); SSL_CTX_set_default_passwd_cb(ssl_ctx, lws_context_init_ssl_pem_passwd_cb); } +#endif int lws_context_init_ssl_library(struct lws_context_creation_info *info) @@ -138,8 +175,8 @@ lws_context_init_ssl_library(struct lws_context_creation_info *info) lwsl_notice("Doing SSL library init\n"); +#if !defined(LWS_WITH_ESP32) SSL_library_init(); - OpenSSL_add_all_algorithms(); SSL_load_error_strings(); @@ -148,11 +185,11 @@ lws_context_init_ssl_library(struct lws_context_creation_info *info) openssl_SSL_CTX_private_data_index = SSL_CTX_get_ex_new_index(0, NULL, NULL, NULL, NULL); +#endif return 0; } - LWS_VISIBLE void lws_ssl_destroy(struct lws_vhost *vhost) { @@ -164,6 +201,7 @@ lws_ssl_destroy(struct lws_vhost *vhost) SSL_CTX_free(vhost->ssl_ctx); if (!vhost->user_supplied_ssl_ctx && vhost->ssl_client_ctx) SSL_CTX_free(vhost->ssl_client_ctx); +#if !defined(LWS_WITH_ESP32) // after 1.1.0 no need #if (OPENSSL_VERSION_NUMBER < 0x10100000) @@ -183,17 +221,21 @@ lws_ssl_destroy(struct lws_vhost *vhost) EVP_cleanup(); CRYPTO_cleanup_all_ex_data(); #endif +#endif } LWS_VISIBLE void lws_decode_ssl_error(void) { +#if defined(LWS_WITH_ESP32) +#else char buf[256]; u_long err; while ((err = ERR_get_error()) != 0) { ERR_error_string_n(err, buf, sizeof(buf)); lwsl_err("*** %lu %s\n", err, buf); } +#endif } LWS_VISIBLE void @@ -230,27 +272,39 @@ lws_ssl_capable_read(struct lws *wsi, unsigned char *buf, int len) struct lws_context *context = wsi->context; struct lws_context_per_thread *pt = &context->pt[(int)wsi->tsi]; int n = 0; - int ssl_read_errno = 0; +#if !defined(LWS_WITH_ESP32) + int ssl_read_errno = 0; +#endif if (!wsi->ssl) return lws_ssl_capable_read_no_ssl(wsi, buf, len); + errno = 0; n = SSL_read(wsi->ssl, buf, len); +#if defined(LWS_WITH_ESP32) + if (!n && errno == ENOTCONN) { + lwsl_debug("%p: SSL_read ENOTCONN\n", wsi); + return LWS_SSL_CAPABLE_ERROR; + } +#endif + lwsl_debug("%p: SSL_read says %d\n", wsi, n); /* manpage: returning 0 means connection shut down */ if (!n) { n = lws_ssl_get_error(wsi, n); - +lwsl_debug("%p: ssl err %d errno %d\n", wsi, n, errno); if (n == SSL_ERROR_ZERO_RETURN) return LWS_SSL_CAPABLE_ERROR; if (n == SSL_ERROR_SYSCALL) { +#if !defined(LWS_WITH_ESP32) int err = ERR_get_error(); if (err == 0 && (ssl_read_errno == EPIPE || ssl_read_errno == ECONNABORTED || ssl_read_errno == 0)) - return LWS_SSL_CAPABLE_ERROR; + return LWS_SSL_CAPABLE_ERROR; +#endif } lwsl_err("%s failed: %s\n",__func__, @@ -338,15 +392,18 @@ lws_ssl_capable_write(struct lws *wsi, unsigned char *buf, int len) n = lws_ssl_get_error(wsi, n); if (n == SSL_ERROR_WANT_READ || n == SSL_ERROR_WANT_WRITE) { - if (n == SSL_ERROR_WANT_WRITE) + if (n == SSL_ERROR_WANT_WRITE) { lws_set_blocking_send(wsi); + } return LWS_SSL_CAPABLE_MORE_SERVICE; } if (n == SSL_ERROR_ZERO_RETURN) return LWS_SSL_CAPABLE_ERROR; +#if !defined(LWS_WITH_ESP32) if (n == SSL_ERROR_SYSCALL) { + int err = ERR_get_error(); if (err == 0 && (ssl_read_errno == EPIPE @@ -354,6 +411,7 @@ lws_ssl_capable_write(struct lws *wsi, unsigned char *buf, int len) || ssl_read_errno == 0)) return LWS_SSL_CAPABLE_ERROR; } +#endif lwsl_err("%s failed: %s\n",__func__, ERR_error_string(lws_ssl_get_error(wsi, 0), NULL)); @@ -365,7 +423,7 @@ lws_ssl_capable_write(struct lws *wsi, unsigned char *buf, int len) LWS_VISIBLE int lws_ssl_close(struct lws *wsi) { - int n; + lws_sockfd_type n; if (!wsi->ssl) return 0; /* not handled */ @@ -387,7 +445,7 @@ lws_server_socket_service_ssl(struct lws *wsi, lws_sockfd_type accept_fd) struct lws_context *context = wsi->context; struct lws_context_per_thread *pt = &context->pt[(int)wsi->tsi]; int n, m; -#if !defined(USE_WOLFSSL) +#if !defined(USE_WOLFSSL) && !defined(LWS_WITH_ESP32) BIO *bio; #endif char buf[256]; @@ -403,19 +461,21 @@ lws_server_socket_service_ssl(struct lws *wsi, lws_sockfd_type accept_fd) if (accept_fd == LWS_SOCK_INVALID) assert(0); + errno = 0; wsi->ssl = SSL_new(wsi->vhost->ssl_ctx); if (wsi->ssl == NULL) { - lwsl_err("SSL_new failed: %s\n", - ERR_error_string(lws_ssl_get_error(wsi, 0), NULL)); + lwsl_err("SSL_new failed: %s (errno %d)\n", + ERR_error_string(lws_ssl_get_error(wsi, 0), NULL), errno); + lws_decode_ssl_error(); if (accept_fd != LWS_SOCK_INVALID) compatible_close(accept_fd); goto fail; } - +#if !defined(LWS_WITH_ESP32) SSL_set_ex_data(wsi->ssl, openssl_websocket_private_data_index, wsi); - +#endif SSL_set_fd(wsi->ssl, accept_fd); #ifdef USE_WOLFSSL @@ -425,6 +485,8 @@ lws_server_socket_service_ssl(struct lws *wsi, lws_sockfd_type accept_fd) wolfSSL_set_using_nonblock(wsi->ssl, 1); #endif #else +#if defined(LWS_WITH_ESP32) +#else SSL_set_mode(wsi->ssl, SSL_MODE_ACCEPT_MOVING_WRITE_BUFFER); bio = SSL_get_rbio(wsi->ssl); if (bio) @@ -437,6 +499,7 @@ lws_server_socket_service_ssl(struct lws *wsi, lws_sockfd_type accept_fd) else lwsl_notice("NULL rbio\n"); #endif +#endif /* * we are not accepted yet, but we need to enter ourselves @@ -457,7 +520,7 @@ lws_server_socket_service_ssl(struct lws *wsi, lws_sockfd_type accept_fd) lws_set_timeout(wsi, PENDING_TIMEOUT_SSL_ACCEPT, context->timeout_secs); - lwsl_info("inserted SSL accept into fds, trying SSL_accept\n"); + lwsl_debug("inserted SSL accept into fds, trying SSL_accept\n"); /* fallthru */ @@ -470,8 +533,10 @@ lws_server_socket_service_ssl(struct lws *wsi, lws_sockfd_type accept_fd) lws_latency_pre(context, wsi); - n = recv(wsi->desc.sockfd, (char *)pt->serv_buf, context->pt_serv_buf_size, - MSG_PEEK); + if (wsi->vhost->allow_non_ssl_on_ssl_port) { + + n = recv(wsi->desc.sockfd, (char *)pt->serv_buf, context->pt_serv_buf_size, + MSG_PEEK); /* * optionally allow non-SSL connect on SSL listening socket @@ -480,7 +545,6 @@ lws_server_socket_service_ssl(struct lws *wsi, lws_sockfd_type accept_fd) * it disabled unless you know it's not a problem for you */ - if (wsi->vhost->allow_non_ssl_on_ssl_port) { if (n >= 1 && pt->serv_buf[0] >= ' ') { /* * TLS content-type for Handshake is 0x16, and @@ -526,11 +590,17 @@ lws_server_socket_service_ssl(struct lws *wsi, lws_sockfd_type accept_fd) n = SSL_accept(wsi->ssl); lws_latency(context, wsi, "SSL_accept LWSCM_SSL_ACK_PENDING\n", n, n == 1); - + lwsl_info("SSL_accept says %d\n", n); if (n == 1) goto accepted; m = lws_ssl_get_error(wsi, n); + +#if defined(LWS_WITH_ESP32) + if (m == 5 && errno == 11) + m = SSL_ERROR_WANT_READ; +#endif + go_again: if (m == SSL_ERROR_WANT_READ) { if (lws_change_pollfd(wsi, 0, LWS_POLLIN)) { @@ -591,6 +661,8 @@ void lws_ssl_context_destroy(struct lws_context *context) { +#if !defined(LWS_WITH_ESP32) + // after 1.1.0 no need #if (OPENSSL_VERSION_NUMBER < 0x10100000) // <= 1.0.1f = old api, 1.0.1g+ = new api @@ -609,4 +681,5 @@ lws_ssl_context_destroy(struct lws_context *context) EVP_cleanup(); CRYPTO_cleanup_all_ex_data(); #endif +#endif } -- 2.7.4