mirror of
https://github.com/warmcat/libwebsockets.git
synced 2025-03-09 00:00:04 +01:00
ssl migrate client pieces to ssl.c
Some ssl-specific code was still hiding out in client.c instead of going in ssl.c Signed-off-by: Andy Green <andy@warmcat.com>
This commit is contained in:
parent
cd0c696a0d
commit
eefb13a0a7
3 changed files with 229 additions and 189 deletions
195
lib/client.c
195
lib/client.c
|
@ -148,125 +148,12 @@ lws_client_socket_service(struct lws_context *context, struct lws *wsi,
|
|||
#ifdef LWS_OPENSSL_SUPPORT
|
||||
/* we can retry this... just cook the SSL BIO the first time */
|
||||
|
||||
if (wsi->use_ssl && !wsi->ssl) {
|
||||
#if defined(CYASSL_SNI_HOST_NAME) || defined(WOLFSSL_SNI_HOST_NAME) || defined(SSL_CTRL_SET_TLSEXT_HOSTNAME)
|
||||
const char *hostname = lws_hdr_simple_ptr(wsi,
|
||||
_WSI_TOKEN_CLIENT_HOST);
|
||||
#endif
|
||||
|
||||
wsi->ssl = SSL_new(wsi->vhost->ssl_client_ctx);
|
||||
#ifndef USE_WOLFSSL
|
||||
SSL_set_mode(wsi->ssl,
|
||||
SSL_MODE_ACCEPT_MOVING_WRITE_BUFFER);
|
||||
#endif
|
||||
/*
|
||||
* use server name indication (SNI), if supported,
|
||||
* when establishing connection
|
||||
*/
|
||||
#ifdef USE_WOLFSSL
|
||||
#ifdef USE_OLD_CYASSL
|
||||
#ifdef CYASSL_SNI_HOST_NAME
|
||||
CyaSSL_UseSNI(wsi->ssl, CYASSL_SNI_HOST_NAME,
|
||||
hostname, strlen(hostname));
|
||||
#endif
|
||||
#else
|
||||
#ifdef WOLFSSL_SNI_HOST_NAME
|
||||
wolfSSL_UseSNI(wsi->ssl, WOLFSSL_SNI_HOST_NAME,
|
||||
hostname, strlen(hostname));
|
||||
#endif
|
||||
#endif
|
||||
#else
|
||||
#ifdef SSL_CTRL_SET_TLSEXT_HOSTNAME
|
||||
SSL_set_tlsext_host_name(wsi->ssl, hostname);
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifdef USE_WOLFSSL
|
||||
/*
|
||||
* wolfSSL/CyaSSL does certificate verification differently
|
||||
* from OpenSSL.
|
||||
* If we should ignore the certificate, we need to set
|
||||
* this before SSL_new and SSL_connect is called.
|
||||
* Otherwise the connect will simply fail with error
|
||||
* code -155
|
||||
*/
|
||||
#ifdef USE_OLD_CYASSL
|
||||
if (wsi->use_ssl == 2)
|
||||
CyaSSL_set_verify(wsi->ssl,
|
||||
SSL_VERIFY_NONE, NULL);
|
||||
#else
|
||||
if (wsi->use_ssl == 2)
|
||||
wolfSSL_set_verify(wsi->ssl,
|
||||
SSL_VERIFY_NONE, NULL);
|
||||
#endif
|
||||
#endif /* USE_WOLFSSL */
|
||||
|
||||
wsi->client_bio =
|
||||
BIO_new_socket(wsi->sock, BIO_NOCLOSE);
|
||||
SSL_set_bio(wsi->ssl, wsi->client_bio, wsi->client_bio);
|
||||
|
||||
#ifdef USE_WOLFSSL
|
||||
#ifdef USE_OLD_CYASSL
|
||||
CyaSSL_set_using_nonblock(wsi->ssl, 1);
|
||||
#else
|
||||
wolfSSL_set_using_nonblock(wsi->ssl, 1);
|
||||
#endif
|
||||
#else
|
||||
BIO_set_nbio(wsi->client_bio, 1); /* nonblocking */
|
||||
#endif
|
||||
|
||||
SSL_set_ex_data(wsi->ssl,
|
||||
openssl_websocket_private_data_index,
|
||||
context);
|
||||
}
|
||||
if (wsi->use_ssl && !wsi->ssl)
|
||||
lws_ssl_client_bio_create(wsi);
|
||||
|
||||
if (wsi->use_ssl) {
|
||||
lws_latency_pre(context, wsi);
|
||||
n = SSL_connect(wsi->ssl);
|
||||
lws_latency(context, wsi,
|
||||
"SSL_connect LWSCM_WSCL_ISSUE_HANDSHAKE", n, n > 0);
|
||||
|
||||
if (n < 0) {
|
||||
n = SSL_get_error(wsi->ssl, n);
|
||||
|
||||
if (n == SSL_ERROR_WANT_READ)
|
||||
goto some_wait;
|
||||
|
||||
if (n == SSL_ERROR_WANT_WRITE) {
|
||||
/*
|
||||
* wants us to retry connect due to
|
||||
* state of the underlying ssl layer...
|
||||
* but since it may be stalled on
|
||||
* blocked write, no incoming data may
|
||||
* arrive to trigger the retry.
|
||||
* Force (possibly many times if the SSL
|
||||
* state persists in returning the
|
||||
* condition code, but other sockets
|
||||
* are getting serviced inbetweentimes)
|
||||
* us to get called back when writable.
|
||||
*/
|
||||
lwsl_info("%s: WANT_WRITE... retrying\n", __func__);
|
||||
lws_callback_on_writable(wsi);
|
||||
some_wait:
|
||||
wsi->mode = LWSCM_WSCL_WAITING_SSL;
|
||||
|
||||
return 0; /* no error */
|
||||
}
|
||||
n = -1;
|
||||
}
|
||||
|
||||
if (n <= 0) {
|
||||
/*
|
||||
* retry if new data comes until we
|
||||
* run into the connection timeout or win
|
||||
*/
|
||||
n = ERR_get_error();
|
||||
if (n != SSL_ERROR_NONE) {
|
||||
lwsl_err("SSL connect error %lu: %s\n",
|
||||
n, ERR_error_string(n, sb));
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
if (!lws_ssl_client_connect1(wsi))
|
||||
return 0;
|
||||
} else
|
||||
wsi->ssl = NULL;
|
||||
|
||||
|
@ -275,78 +162,8 @@ some_wait:
|
|||
case LWSCM_WSCL_WAITING_SSL:
|
||||
|
||||
if (wsi->use_ssl) {
|
||||
if (wsi->mode == LWSCM_WSCL_WAITING_SSL) {
|
||||
lws_latency_pre(context, wsi);
|
||||
n = SSL_connect(wsi->ssl);
|
||||
lws_latency(context, wsi,
|
||||
"SSL_connect LWSCM_WSCL_WAITING_SSL",
|
||||
n, n > 0);
|
||||
|
||||
if (n < 0) {
|
||||
n = SSL_get_error(wsi->ssl, n);
|
||||
|
||||
if (n == SSL_ERROR_WANT_READ)
|
||||
goto some_wait;
|
||||
|
||||
if (n == SSL_ERROR_WANT_WRITE) {
|
||||
/*
|
||||
* wants us to retry connect due to
|
||||
* state of the underlying ssl layer...
|
||||
* but since it may be stalled on
|
||||
* blocked write, no incoming data may
|
||||
* arrive to trigger the retry.
|
||||
* Force (possibly many times if the SSL
|
||||
* state persists in returning the
|
||||
* condition code, but other sockets
|
||||
* are getting serviced inbetweentimes)
|
||||
* us to get called back when writable.
|
||||
*/
|
||||
lwsl_info("SSL_connect WANT_WRITE... retrying\n");
|
||||
lws_callback_on_writable(wsi);
|
||||
|
||||
goto some_wait;
|
||||
}
|
||||
n = -1;
|
||||
}
|
||||
|
||||
if (n <= 0) {
|
||||
/*
|
||||
* retry if new data comes until we
|
||||
* run into the connection timeout or win
|
||||
*/
|
||||
n = ERR_get_error();
|
||||
if (n != SSL_ERROR_NONE) {
|
||||
lwsl_err("SSL connect error %lu: %s\n",
|
||||
n, ERR_error_string(n, sb));
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#ifndef USE_WOLFSSL
|
||||
/*
|
||||
* See comment above about wolfSSL certificate
|
||||
* verification
|
||||
*/
|
||||
lws_latency_pre(context, wsi);
|
||||
n = SSL_get_verify_result(wsi->ssl);
|
||||
lws_latency(context, wsi,
|
||||
"SSL_get_verify_result LWS_CONNMODE..HANDSHAKE",
|
||||
n, n > 0);
|
||||
|
||||
if (n != X509_V_OK) {
|
||||
if ((n == X509_V_ERR_DEPTH_ZERO_SELF_SIGNED_CERT ||
|
||||
n == X509_V_ERR_SELF_SIGNED_CERT_IN_CHAIN) && wsi->use_ssl == 2) {
|
||||
lwsl_notice("accepting self-signed certificate\n");
|
||||
} else {
|
||||
lwsl_err("server's cert didn't look good, X509_V_ERR = %d: %s\n",
|
||||
n, ERR_error_string(n, sb));
|
||||
lws_close_free_wsi(wsi,
|
||||
LWS_CLOSE_STATUS_NOSTATUS);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
#endif /* USE_WOLFSSL */
|
||||
if (!lws_ssl_client_connect2(wsi))
|
||||
return 0;
|
||||
} else
|
||||
wsi->ssl = NULL;
|
||||
#endif
|
||||
|
|
|
@ -1511,6 +1511,12 @@ LWS_EXTERN void
|
|||
lws_ssl_context_destroy(struct lws_context *context);
|
||||
LWS_VISIBLE void
|
||||
lws_ssl_remove_wsi_from_buffered_list(struct lws *wsi);
|
||||
LWS_EXTERN int
|
||||
lws_ssl_client_bio_create(struct lws *wsi);
|
||||
LWS_EXTERN int
|
||||
lws_ssl_client_connect1(struct lws *wsi);
|
||||
LWS_EXTERN int
|
||||
lws_ssl_client_connect2(struct lws *wsi);
|
||||
#ifndef LWS_NO_SERVER
|
||||
LWS_EXTERN int
|
||||
lws_context_init_server_ssl(struct lws_context_creation_info *info,
|
||||
|
|
217
lib/ssl.c
217
lib/ssl.c
|
@ -471,6 +471,223 @@ lws_decode_ssl_error(void)
|
|||
|
||||
#ifndef LWS_NO_CLIENT
|
||||
|
||||
int
|
||||
lws_ssl_client_bio_create(struct lws *wsi)
|
||||
{
|
||||
struct lws_context *context = wsi->context;
|
||||
#if defined(CYASSL_SNI_HOST_NAME) || defined(WOLFSSL_SNI_HOST_NAME) || defined(SSL_CTRL_SET_TLSEXT_HOSTNAME)
|
||||
const char *hostname = lws_hdr_simple_ptr(wsi, _WSI_TOKEN_CLIENT_HOST);
|
||||
#endif
|
||||
|
||||
wsi->ssl = SSL_new(wsi->vhost->ssl_client_ctx);
|
||||
#ifndef USE_WOLFSSL
|
||||
SSL_set_mode(wsi->ssl, SSL_MODE_ACCEPT_MOVING_WRITE_BUFFER);
|
||||
#endif
|
||||
/*
|
||||
* use server name indication (SNI), if supported,
|
||||
* when establishing connection
|
||||
*/
|
||||
#ifdef USE_WOLFSSL
|
||||
#ifdef USE_OLD_CYASSL
|
||||
#ifdef CYASSL_SNI_HOST_NAME
|
||||
CyaSSL_UseSNI(wsi->ssl, CYASSL_SNI_HOST_NAME, hostname, strlen(hostname));
|
||||
#endif
|
||||
#else
|
||||
#ifdef WOLFSSL_SNI_HOST_NAME
|
||||
wolfSSL_UseSNI(wsi->ssl, WOLFSSL_SNI_HOST_NAME, hostname, strlen(hostname));
|
||||
#endif
|
||||
#endif
|
||||
#else
|
||||
#ifdef SSL_CTRL_SET_TLSEXT_HOSTNAME
|
||||
SSL_set_tlsext_host_name(wsi->ssl, hostname);
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifdef USE_WOLFSSL
|
||||
/*
|
||||
* wolfSSL/CyaSSL does certificate verification differently
|
||||
* from OpenSSL.
|
||||
* If we should ignore the certificate, we need to set
|
||||
* this before SSL_new and SSL_connect is called.
|
||||
* Otherwise the connect will simply fail with error code -155
|
||||
*/
|
||||
#ifdef USE_OLD_CYASSL
|
||||
if (wsi->use_ssl == 2)
|
||||
CyaSSL_set_verify(wsi->ssl, SSL_VERIFY_NONE, NULL);
|
||||
#else
|
||||
if (wsi->use_ssl == 2)
|
||||
wolfSSL_set_verify(wsi->ssl, SSL_VERIFY_NONE, NULL);
|
||||
#endif
|
||||
#endif /* USE_WOLFSSL */
|
||||
|
||||
wsi->client_bio = BIO_new_socket(wsi->sock, BIO_NOCLOSE);
|
||||
SSL_set_bio(wsi->ssl, wsi->client_bio, wsi->client_bio);
|
||||
|
||||
#ifdef USE_WOLFSSL
|
||||
#ifdef USE_OLD_CYASSL
|
||||
CyaSSL_set_using_nonblock(wsi->ssl, 1);
|
||||
#else
|
||||
wolfSSL_set_using_nonblock(wsi->ssl, 1);
|
||||
#endif
|
||||
#else
|
||||
BIO_set_nbio(wsi->client_bio, 1); /* nonblocking */
|
||||
#endif
|
||||
|
||||
SSL_set_ex_data(wsi->ssl, openssl_websocket_private_data_index,
|
||||
context);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
lws_ssl_client_connect1(struct lws *wsi)
|
||||
{
|
||||
struct lws_context *context = wsi->context;
|
||||
struct lws_context_per_thread *pt = &context->pt[(int)wsi->tsi];
|
||||
char *p = (char *)&pt->serv_buf[0];
|
||||
char *sb = p;
|
||||
int n;
|
||||
|
||||
lws_latency_pre(context, wsi);
|
||||
n = SSL_connect(wsi->ssl);
|
||||
lws_latency(context, wsi,
|
||||
"SSL_connect LWSCM_WSCL_ISSUE_HANDSHAKE", n, n > 0);
|
||||
|
||||
if (n < 0) {
|
||||
n = SSL_get_error(wsi->ssl, n);
|
||||
|
||||
if (n == SSL_ERROR_WANT_READ)
|
||||
goto some_wait;
|
||||
|
||||
if (n == SSL_ERROR_WANT_WRITE) {
|
||||
/*
|
||||
* wants us to retry connect due to
|
||||
* state of the underlying ssl layer...
|
||||
* but since it may be stalled on
|
||||
* blocked write, no incoming data may
|
||||
* arrive to trigger the retry.
|
||||
* Force (possibly many times if the SSL
|
||||
* state persists in returning the
|
||||
* condition code, but other sockets
|
||||
* are getting serviced inbetweentimes)
|
||||
* us to get called back when writable.
|
||||
*/
|
||||
lwsl_info("%s: WANT_WRITE... retrying\n", __func__);
|
||||
lws_callback_on_writable(wsi);
|
||||
some_wait:
|
||||
wsi->mode = LWSCM_WSCL_WAITING_SSL;
|
||||
|
||||
return 0; /* no error */
|
||||
}
|
||||
n = -1;
|
||||
}
|
||||
|
||||
if (n <= 0) {
|
||||
/*
|
||||
* retry if new data comes until we
|
||||
* run into the connection timeout or win
|
||||
*/
|
||||
n = ERR_get_error();
|
||||
if (n != SSL_ERROR_NONE) {
|
||||
lwsl_err("SSL connect error %lu: %s\n",
|
||||
n, ERR_error_string(n, sb));
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
int
|
||||
lws_ssl_client_connect2(struct lws *wsi)
|
||||
{
|
||||
struct lws_context *context = wsi->context;
|
||||
struct lws_context_per_thread *pt = &wsi->context->pt[(int)wsi->tsi];
|
||||
char *p = (char *)&pt->serv_buf[0];
|
||||
char *sb = p;
|
||||
int n;
|
||||
|
||||
if (wsi->mode == LWSCM_WSCL_WAITING_SSL) {
|
||||
lws_latency_pre(context, wsi);
|
||||
n = SSL_connect(wsi->ssl);
|
||||
lws_latency(context, wsi,
|
||||
"SSL_connect LWSCM_WSCL_WAITING_SSL", n, n > 0);
|
||||
|
||||
if (n < 0) {
|
||||
n = SSL_get_error(wsi->ssl, n);
|
||||
|
||||
if (n == SSL_ERROR_WANT_READ) {
|
||||
wsi->mode = LWSCM_WSCL_WAITING_SSL;
|
||||
|
||||
return 0; /* no error */
|
||||
}
|
||||
|
||||
if (n == SSL_ERROR_WANT_WRITE) {
|
||||
/*
|
||||
* wants us to retry connect due to
|
||||
* state of the underlying ssl layer...
|
||||
* but since it may be stalled on
|
||||
* blocked write, no incoming data may
|
||||
* arrive to trigger the retry.
|
||||
* Force (possibly many times if the SSL
|
||||
* state persists in returning the
|
||||
* condition code, but other sockets
|
||||
* are getting serviced inbetweentimes)
|
||||
* us to get called back when writable.
|
||||
*/
|
||||
lwsl_info("SSL_connect WANT_WRITE... retrying\n");
|
||||
lws_callback_on_writable(wsi);
|
||||
|
||||
wsi->mode = LWSCM_WSCL_WAITING_SSL;
|
||||
|
||||
return 0; /* no error */
|
||||
}
|
||||
n = -1;
|
||||
}
|
||||
|
||||
if (n <= 0) {
|
||||
/*
|
||||
* retry if new data comes until we
|
||||
* run into the connection timeout or win
|
||||
*/
|
||||
n = ERR_get_error();
|
||||
if (n != SSL_ERROR_NONE) {
|
||||
lwsl_err("SSL connect error %lu: %s\n",
|
||||
n, ERR_error_string(n, sb));
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#ifndef USE_WOLFSSL
|
||||
/*
|
||||
* See comment above about wolfSSL certificate
|
||||
* verification
|
||||
*/
|
||||
lws_latency_pre(context, wsi);
|
||||
n = SSL_get_verify_result(wsi->ssl);
|
||||
lws_latency(context, wsi,
|
||||
"SSL_get_verify_result LWS_CONNMODE..HANDSHAKE",
|
||||
n, n > 0);
|
||||
|
||||
if (n != X509_V_OK) {
|
||||
if ((n == X509_V_ERR_DEPTH_ZERO_SELF_SIGNED_CERT ||
|
||||
n == X509_V_ERR_SELF_SIGNED_CERT_IN_CHAIN) && wsi->use_ssl == 2) {
|
||||
lwsl_notice("accepting self-signed certificate\n");
|
||||
} else {
|
||||
lwsl_err("server's cert didn't look good, X509_V_ERR = %d: %s\n",
|
||||
n, ERR_error_string(n, sb));
|
||||
lws_close_free_wsi(wsi,
|
||||
LWS_CLOSE_STATUS_NOSTATUS);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
#endif /* USE_WOLFSSL */
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
int lws_context_init_client_ssl(struct lws_context_creation_info *info,
|
||||
struct lws_vhost *vhost)
|
||||
{
|
||||
|
|
Loading…
Add table
Reference in a new issue