static gboolean sock_check(GSource *source) { SockInfo *sock = ((SockSource *)source)->sock; struct timeval timeout = {0, 0}; fd_set fds; GIOCondition condition = sock->condition; #if USE_SSL if (sock->ssl) { if (condition & G_IO_IN) { if (SSL_pending(sock->ssl) > 0) return TRUE; if (SSL_want_write(sock->ssl)) condition |= G_IO_OUT; } if (condition & G_IO_OUT) { if (SSL_want_read(sock->ssl)) condition |= G_IO_IN; } } #endif FD_ZERO(&fds); FD_SET(sock->sock, &fds); select(sock->sock + 1, (condition & G_IO_IN) ? &fds : NULL, (condition & G_IO_OUT) ? &fds : NULL, NULL, &timeout); return FD_ISSET(sock->sock, &fds) != 0; }
enum lws_ssl_capable_status __lws_tls_shutdown(struct lws *wsi) { int n = SSL_shutdown(wsi->tls.ssl); lwsl_debug("SSL_shutdown=%d for fd %d\n", n, wsi->desc.sockfd); switch (n) { case 1: /* successful completion */ n = shutdown(wsi->desc.sockfd, SHUT_WR); return LWS_SSL_CAPABLE_DONE; case 0: /* needs a retry */ __lws_change_pollfd(wsi, 0, LWS_POLLIN); return LWS_SSL_CAPABLE_MORE_SERVICE; default: /* fatal error, or WANT */ n = SSL_get_error(wsi->tls.ssl, n); if (n != SSL_ERROR_SYSCALL && n != SSL_ERROR_SSL) { if (SSL_want_read(wsi->tls.ssl)) { lwsl_debug("(wants read)\n"); __lws_change_pollfd(wsi, 0, LWS_POLLIN); return LWS_SSL_CAPABLE_MORE_SERVICE_READ; } if (SSL_want_write(wsi->tls.ssl)) { lwsl_debug("(wants write)\n"); __lws_change_pollfd(wsi, 0, LWS_POLLOUT); return LWS_SSL_CAPABLE_MORE_SERVICE_WRITE; } } return LWS_SSL_CAPABLE_ERROR; } }
LWS_VISIBLE int lws_ssl_capable_write(struct lws *wsi, unsigned char *buf, int len) { int n, m; if (!wsi->tls.ssl) return lws_ssl_capable_write_no_ssl(wsi, buf, len); n = SSL_write(wsi->tls.ssl, buf, len); if (n > 0) return n; m = SSL_get_error(wsi->tls.ssl, n); if (m != SSL_ERROR_SYSCALL) { if (m == SSL_ERROR_WANT_READ || SSL_want_read(wsi->tls.ssl)) { lwsl_notice("%s: want read\n", __func__); return LWS_SSL_CAPABLE_MORE_SERVICE; } if (m == SSL_ERROR_WANT_WRITE || SSL_want_write(wsi->tls.ssl)) { lws_set_blocking_send(wsi); lwsl_notice("%s: want write\n", __func__); return LWS_SSL_CAPABLE_MORE_SERVICE; } } lwsl_debug("%s failed: %d\n",__func__, m); wsi->socket_is_permanently_unusable = 1; return LWS_SSL_CAPABLE_ERROR; }
enum lws_ssl_capable_status lws_tls_client_connect(struct lws *wsi) { int m, n = SSL_connect(wsi->tls.ssl); const unsigned char *prot; unsigned int len; if (n == 1) { SSL_get0_alpn_selected(wsi->tls.ssl, &prot, &len); lws_role_call_alpn_negotiated(wsi, (const char *)prot); lwsl_info("client connect OK\n"); return LWS_SSL_CAPABLE_DONE; } m = SSL_get_error(wsi->tls.ssl, n); if (m == SSL_ERROR_WANT_READ || SSL_want_read(wsi->tls.ssl)) return LWS_SSL_CAPABLE_MORE_SERVICE_READ; if (m == SSL_ERROR_WANT_WRITE || SSL_want_write(wsi->tls.ssl)) return LWS_SSL_CAPABLE_MORE_SERVICE_WRITE; if (!n) /* we don't know what he wants, but he says to retry */ return LWS_SSL_CAPABLE_MORE_SERVICE; return LWS_SSL_CAPABLE_ERROR; }
static void log_state (GstDtlsConnection * self, const gchar * str) { GstDtlsConnectionPrivate *priv = self->priv; guint states = 0; states |= (! !SSL_is_init_finished (priv->ssl) << 0); states |= (! !SSL_in_init (priv->ssl) << 4); states |= (! !SSL_in_before (priv->ssl) << 8); states |= (! !SSL_in_connect_init (priv->ssl) << 12); states |= (! !SSL_in_accept_init (priv->ssl) << 16); states |= (! !SSL_want_write (priv->ssl) << 20); states |= (! !SSL_want_read (priv->ssl) << 24); #if OPENSSL_VERSION_NUMBER < 0x10100001L GST_LOG_OBJECT (self, "%s: role=%s buf=(%d,%p:%d/%d) %x|%x %s", str, priv->is_client ? "client" : "server", pqueue_size (priv->ssl->d1->sent_messages), priv->bio_buffer, priv->bio_buffer_offset, priv->bio_buffer_len, states, SSL_get_state (priv->ssl), SSL_state_string_long (priv->ssl)); #else GST_LOG_OBJECT (self, "%s: role=%s buf=(%p:%d/%d) %x|%x %s", str, priv->is_client ? "client" : "server", priv->bio_buffer, priv->bio_buffer_offset, priv->bio_buffer_len, states, SSL_get_state (priv->ssl), SSL_state_string_long (priv->ssl)); #endif }
enum lws_ssl_capable_status lws_tls_server_accept(struct lws *wsi) { union lws_tls_cert_info_results ir; int m, n = SSL_accept(wsi->tls.ssl); struct lws_context_per_thread *pt = &wsi->context->pt[(int)wsi->tsi]; if (n == 1) { n = lws_tls_peer_cert_info(wsi, LWS_TLS_CERT_INFO_COMMON_NAME, &ir, sizeof(ir.ns.name)); if (!n) lwsl_notice("%s: client cert CN '%s'\n", __func__, ir.ns.name); else lwsl_info("%s: no client cert CN\n", __func__); lws_openssl_describe_cipher(wsi); if (SSL_pending(wsi->tls.ssl) && lws_dll_is_detached(&wsi->tls.dll_pending_tls, &pt->tls.dll_pending_tls_head)) lws_dll_add_head(&wsi->tls.dll_pending_tls, &pt->tls.dll_pending_tls_head); return LWS_SSL_CAPABLE_DONE; } lws_tls_err_describe(); m = lws_ssl_get_error(wsi, n); if (m == SSL_ERROR_SYSCALL || m == SSL_ERROR_SSL) return LWS_SSL_CAPABLE_ERROR; if (m == SSL_ERROR_WANT_READ || (m != SSL_ERROR_ZERO_RETURN && SSL_want_read(wsi->tls.ssl))) { if (lws_change_pollfd(wsi, 0, LWS_POLLIN)) { lwsl_info("%s: WANT_READ change_pollfd failed\n", __func__); return LWS_SSL_CAPABLE_ERROR; } lwsl_info("SSL_ERROR_WANT_READ: m %d\n", m); return LWS_SSL_CAPABLE_MORE_SERVICE_READ; } if (m == SSL_ERROR_WANT_WRITE || SSL_want_write(wsi->tls.ssl)) { lwsl_debug("%s: WANT_WRITE\n", __func__); if (lws_change_pollfd(wsi, 0, LWS_POLLOUT)) { lwsl_info("%s: WANT_WRITE change_pollfd failed\n", __func__); return LWS_SSL_CAPABLE_ERROR; } return LWS_SSL_CAPABLE_MORE_SERVICE_WRITE; } return LWS_SSL_CAPABLE_ERROR; }
@return: True iff there is data to write\n\ "; static PyObject * ssl_Connection_want_write(ssl_ConnectionObj *self, PyObject *args) { if (!PyArg_ParseTuple(args, ":want_write")) return NULL; return PyLong_FromLong((long)SSL_want_write(self->ssl)); }
bool Connection::writeHandshake() { log_trace("Connection::writeHandshake"); std::streambuf* sb = _ios->rdbuf(); if( ! sb) return false; int ret = SSL_do_handshake(_ssl); log_debug("SSL_do_handshake returns " << ret); if(ret <= 0) { const int sslerr = SSL_get_error(_ssl, ret); if(sslerr != SSL_ERROR_WANT_READ && sslerr != SSL_ERROR_WANT_WRITE) { if(sslerr == SSL_ERROR_SSL) { char buf[255]; ERR_error_string_n(ERR_get_error(), buf, sizeof(buf)); log_warn("handshake failed: " << buf); } throw HandshakeFailed("SSL handshake failed"); } } if(ret == 1) { _connected = true; } if( BIO_pending(_out) ) { char buff[1000]; const int n = BIO_read(_out, buff, sizeof(buff)); log_debug("wrote " << n << " bytes to output"); if(n <= 0) throw SslError("BIO_read"); sb->sputn(buff, n); return true; } return SSL_want_write(_ssl); }
enum lws_ssl_capable_status lws_tls_server_accept(struct lws *wsi) { union lws_tls_cert_info_results ir; int m, n = SSL_accept(wsi->ssl); if (n == 1) { n = lws_tls_peer_cert_info(wsi, LWS_TLS_CERT_INFO_COMMON_NAME, &ir, sizeof(ir.ns.name)); if (!n) lwsl_notice("%s: client cert CN '%s'\n", __func__, ir.ns.name); else lwsl_info("%s: couldn't get client cert CN\n", __func__); return LWS_SSL_CAPABLE_DONE; } m = SSL_get_error(wsi->ssl, n); // mbedtls wrapper only if (m == SSL_ERROR_SYSCALL && errno == 11) return LWS_SSL_CAPABLE_MORE_SERVICE_READ; if (m == SSL_ERROR_SYSCALL || m == SSL_ERROR_SSL) return LWS_SSL_CAPABLE_ERROR; if (m == SSL_ERROR_WANT_READ || SSL_want_read(wsi->ssl)) { if (lws_change_pollfd(wsi, 0, LWS_POLLIN)) { lwsl_info("%s: WANT_READ change_pollfd failed\n", __func__); return LWS_SSL_CAPABLE_ERROR; } lwsl_info("SSL_ERROR_WANT_READ\n"); return LWS_SSL_CAPABLE_MORE_SERVICE_READ; } if (m == SSL_ERROR_WANT_WRITE || SSL_want_write(wsi->ssl)) { lwsl_debug("%s: WANT_WRITE\n", __func__); if (lws_change_pollfd(wsi, 0, LWS_POLLOUT)) { lwsl_info("%s: WANT_WRITE change_pollfd failed\n", __func__); return LWS_SSL_CAPABLE_ERROR; } return LWS_SSL_CAPABLE_MORE_SERVICE_WRITE; } return LWS_SSL_CAPABLE_ERROR; }
gint gst_dtls_connection_process (GstDtlsConnection * self, gpointer data, gint len) { GstDtlsConnectionPrivate *priv; gint result; g_return_val_if_fail (GST_IS_DTLS_CONNECTION (self), 0); g_return_val_if_fail (self->priv->ssl, 0); g_return_val_if_fail (self->priv->bio, 0); priv = self->priv; GST_TRACE_OBJECT (self, "locking @ process"); g_mutex_lock (&priv->mutex); GST_TRACE_OBJECT (self, "locked @ process"); g_warn_if_fail (!priv->bio_buffer); priv->bio_buffer = data; priv->bio_buffer_len = len; priv->bio_buffer_offset = 0; log_state (self, "process start"); if (SSL_want_write (priv->ssl)) { openssl_poll (self); log_state (self, "process want write, after poll"); } result = SSL_read (priv->ssl, data, len); log_state (self, "process after read"); openssl_poll (self); log_state (self, "process after poll"); GST_DEBUG_OBJECT (self, "read result: %d", result); GST_TRACE_OBJECT (self, "unlocking @ process"); g_mutex_unlock (&priv->mutex); return result; }
VALUE engine_write(VALUE self, VALUE str) { ms_conn* conn; char buf[512]; int bytes; Data_Get_Struct(self, ms_conn, conn); StringValue(str); bytes = SSL_write(conn->ssl, (void*)RSTRING_PTR(str), (int)RSTRING_LEN(str)); if(bytes > 0) { return INT2FIX(bytes); } if(SSL_want_write(conn->ssl)) return Qnil; raise_error(conn->ssl, bytes); return Qnil; }
/* * Send binary data to the client encrypted. */ int client_write_ssl(const StrBuf *Buf) { const char *buf; int retval; int nremain; long nbytes; char junk[1]; if (THREADSSL == NULL) return -1; nbytes = nremain = StrLength(Buf); buf = ChrPtr(Buf); while (nremain > 0) { if (SSL_want_write(THREADSSL)) { if ((SSL_read(THREADSSL, junk, 0)) < 1) { syslog(LOG_WARNING, "SSL_read in client_write: %s\n", ERR_reason_error_string(ERR_get_error())); } } retval = SSL_write(THREADSSL, &buf[nbytes - nremain], nremain); if (retval < 1) { long errval; errval = SSL_get_error(THREADSSL, retval); if (errval == SSL_ERROR_WANT_READ || errval == SSL_ERROR_WANT_WRITE) { sleeeeeeeeeep(1); continue; } syslog(LOG_WARNING, "SSL_write got error %ld, ret %d\n", errval, retval); if (retval == -1) { syslog(LOG_WARNING, "errno is %d\n", errno); } endtls(); return -1; } nremain -= retval; } return 0; }
LWS_VISIBLE int lws_ssl_capable_write(struct lws *wsi, unsigned char *buf, int len) { int n, m; if (!wsi->ssl) return lws_ssl_capable_write_no_ssl(wsi, buf, len); n = SSL_write(wsi->ssl, buf, len); if (n > 0) return n; m = lws_ssl_get_error(wsi, n); if (m != SSL_ERROR_SYSCALL) { if (SSL_want_read(wsi->ssl)) { lwsl_notice("%s: want read\n", __func__); return LWS_SSL_CAPABLE_MORE_SERVICE; } if (SSL_want_write(wsi->ssl)) { lws_set_blocking_send(wsi); lwsl_notice("%s: want write\n", __func__); return LWS_SSL_CAPABLE_MORE_SERVICE; } } lwsl_debug("%s failed: %s\n",__func__, ERR_error_string(m, NULL)); lws_ssl_elaborate_error(); wsi->socket_is_permanently_unusable = 1; return LWS_SSL_CAPABLE_ERROR; }
LWS_VISIBLE int lws_server_socket_service_ssl(struct lws *wsi, lws_sockfd_type accept_fd) { struct lws_context *context = wsi->context; struct lws_vhost *vh; struct lws_context_per_thread *pt = &context->pt[(int)wsi->tsi]; int n, m; #if !defined(USE_WOLFSSL) && !defined(LWS_WITH_MBEDTLS) BIO *bio; #endif char buf[256]; (void)buf; if (!LWS_SSL_ENABLED(wsi->vhost)) return 0; switch (wsi->mode) { case LWSCM_SSL_INIT: case LWSCM_SSL_INIT_RAW: if (wsi->ssl) lwsl_err("%s: leaking ssl\n", __func__); if (accept_fd == LWS_SOCK_INVALID) assert(0); if (context->simultaneous_ssl_restriction && context->simultaneous_ssl >= context->simultaneous_ssl_restriction) { lwsl_notice("unable to deal with SSL connection\n"); return 1; } errno = 0; wsi->ssl = SSL_new(wsi->vhost->ssl_ctx); if (wsi->ssl == NULL) { lwsl_err("SSL_new failed: %d (errno %d)\n", lws_ssl_get_error(wsi, 0), errno); lws_ssl_elaborate_error(); if (accept_fd != LWS_SOCK_INVALID) compatible_close(accept_fd); goto fail; } #if defined (LWS_HAVE_SSL_SET_INFO_CALLBACK) if (wsi->vhost->ssl_info_event_mask) SSL_set_info_callback(wsi->ssl, lws_ssl_info_callback); #endif if (context->simultaneous_ssl_restriction && ++context->simultaneous_ssl == context->simultaneous_ssl_restriction) /* that was the last allowed SSL connection */ lws_gate_accepts(context, 0); #if defined(LWS_WITH_STATS) context->updated = 1; #endif #if !defined(LWS_WITH_MBEDTLS) SSL_set_ex_data(wsi->ssl, openssl_websocket_private_data_index, wsi); #endif SSL_set_fd(wsi->ssl, accept_fd); #ifdef USE_WOLFSSL #ifdef USE_OLD_CYASSL CyaSSL_set_using_nonblock(wsi->ssl, 1); #else wolfSSL_set_using_nonblock(wsi->ssl, 1); #endif #else #if defined(LWS_WITH_MBEDTLS) lws_plat_set_socket_options(wsi->vhost, accept_fd); #else SSL_set_mode(wsi->ssl, SSL_MODE_ACCEPT_MOVING_WRITE_BUFFER); bio = SSL_get_rbio(wsi->ssl); if (bio) BIO_set_nbio(bio, 1); /* nonblocking */ else lwsl_notice("NULL rbio\n"); bio = SSL_get_wbio(wsi->ssl); if (bio) BIO_set_nbio(bio, 1); /* nonblocking */ else lwsl_notice("NULL rbio\n"); #endif #endif /* * we are not accepted yet, but we need to enter ourselves * as a live connection. That way we can retry when more * pieces come if we're not sorted yet */ if (wsi->mode == LWSCM_SSL_INIT) wsi->mode = LWSCM_SSL_ACK_PENDING; else wsi->mode = LWSCM_SSL_ACK_PENDING_RAW; if (insert_wsi_socket_into_fds(context, wsi)) { lwsl_err("%s: failed to insert into fds\n", __func__); goto fail; } lws_set_timeout(wsi, PENDING_TIMEOUT_SSL_ACCEPT, context->timeout_secs); lwsl_debug("inserted SSL accept into fds, trying SSL_accept\n"); /* fallthru */ case LWSCM_SSL_ACK_PENDING: case LWSCM_SSL_ACK_PENDING_RAW: if (lws_change_pollfd(wsi, LWS_POLLOUT, 0)) { lwsl_err("%s: lws_change_pollfd failed\n", __func__); goto fail; } lws_latency_pre(context, wsi); 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 * This is disabled by default, if enabled it goes around any * SSL-level access control (eg, client-side certs) so leave * it disabled unless you know it's not a problem for you */ if (n >= 1 && pt->serv_buf[0] >= ' ') { /* * TLS content-type for Handshake is 0x16, and * for ChangeCipherSpec Record, it's 0x14 * * A non-ssl session will start with the HTTP * method in ASCII. If we see it's not a legit * SSL handshake kill the SSL for this * connection and try to handle as a HTTP * connection upgrade directly. */ wsi->use_ssl = 0; SSL_shutdown(wsi->ssl); SSL_free(wsi->ssl); wsi->ssl = NULL; if (lws_check_opt(context->options, LWS_SERVER_OPTION_REDIRECT_HTTP_TO_HTTPS)) wsi->redirect_to_https = 1; goto accepted; } if (!n) /* * connection is gone, or nothing to read * if it's gone, we will timeout on * PENDING_TIMEOUT_SSL_ACCEPT */ break; if (n < 0 && (LWS_ERRNO == LWS_EAGAIN || LWS_ERRNO == LWS_EWOULDBLOCK)) { /* * well, we get no way to know ssl or not * so go around again waiting for something * to come and give us a hint, or timeout the * connection. */ m = SSL_ERROR_WANT_READ; goto go_again; } } /* normal SSL connection processing path */ #if defined(LWS_WITH_STATS) if (!wsi->accept_start_us) wsi->accept_start_us = time_in_microseconds(); #endif errno = 0; lws_stats_atomic_bump(wsi->context, pt, LWSSTATS_C_SSL_CONNECTIONS_ACCEPT_SPIN, 1); 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_MBEDTLS) if (m == SSL_ERROR_SYSCALL && errno == 11) m = SSL_ERROR_WANT_READ; #endif if (m == SSL_ERROR_SYSCALL || m == SSL_ERROR_SSL) goto failed; go_again: if (m == SSL_ERROR_WANT_READ || SSL_want_read(wsi->ssl)) { if (lws_change_pollfd(wsi, 0, LWS_POLLIN)) { lwsl_info("%s: WANT_READ change_pollfd failed\n", __func__); goto fail; } lwsl_info("SSL_ERROR_WANT_READ\n"); break; } if (m == SSL_ERROR_WANT_WRITE || SSL_want_write(wsi->ssl)) { lwsl_debug("%s: WANT_WRITE\n", __func__); if (lws_change_pollfd(wsi, 0, LWS_POLLOUT)) { lwsl_info("%s: WANT_WRITE change_pollfd failed\n", __func__); goto fail; } break; } failed: lws_stats_atomic_bump(wsi->context, pt, LWSSTATS_C_SSL_CONNECTIONS_FAILED, 1); wsi->socket_is_permanently_unusable = 1; lwsl_info("SSL_accept failed socket %u: %s\n", wsi->desc.sockfd, lws_ssl_get_error_string(m, n, buf, sizeof(buf))); lws_ssl_elaborate_error(); goto fail; accepted: lws_stats_atomic_bump(wsi->context, pt, LWSSTATS_C_SSL_CONNECTIONS_ACCEPTED, 1); #if defined(LWS_WITH_STATS) lws_stats_atomic_bump(wsi->context, pt, LWSSTATS_MS_SSL_CONNECTIONS_ACCEPTED_DELAY, time_in_microseconds() - wsi->accept_start_us); wsi->accept_start_us = time_in_microseconds(); #endif /* adapt our vhost to match the SNI SSL_CTX that was chosen */ vh = context->vhost_list; while (vh) { if (!vh->being_destroyed && wsi->ssl && vh->ssl_ctx == SSL_get_SSL_CTX(wsi->ssl)) { lwsl_info("setting wsi to vh %s\n", vh->name); wsi->vhost = vh; break; } vh = vh->vhost_next; } /* OK, we are accepted... give him some time to negotiate */ lws_set_timeout(wsi, PENDING_TIMEOUT_ESTABLISH_WITH_SERVER, context->timeout_secs); if (wsi->mode == LWSCM_SSL_ACK_PENDING_RAW) wsi->mode = LWSCM_RAW; else wsi->mode = LWSCM_HTTP_SERVING; #if defined(LWS_WITH_HTTP2) if (lws_h2_configure_if_upgraded(wsi)) goto fail; #endif lwsl_debug("accepted new SSL conn\n"); break; } return 0; fail: return 1; }
int ACE_SSL_SOCK_Acceptor::ssl_accept (ACE_SSL_SOCK_Stream &new_stream, ACE_Time_Value *timeout) const { SSL *ssl = new_stream.ssl (); if (SSL_is_init_finished (ssl)) return 0; if (!SSL_in_accept_init (ssl)) ::SSL_set_accept_state (ssl); ACE_HANDLE handle = new_stream.get_handle (); // We're going to call SSL_accept, optionally doing ACE::select and // retrying the SSL_accept, until the SSL handshake is done or // it fails. // To get the timeout affect, set the socket to nonblocking mode // before beginning if there is a timeout specified. If the timeout // is 0 (wait as long as it takes) then don't worry about the blocking // status; we'll block in SSL_accept if the socket is blocking, and // block in ACE::select if not. int reset_blocking_mode = 0; if (timeout != 0) { reset_blocking_mode = ACE_BIT_DISABLED (ACE::get_flags (handle), ACE_NONBLOCK); // Set the handle into non-blocking mode if it's not already // in it. if (reset_blocking_mode && ACE::set_flags (handle, ACE_NONBLOCK) == -1) return -1; } // Take into account the time between each select() call below. ACE_Countdown_Time countdown (timeout); int status; do { // These handle sets are used to set up for whatever SSL_accept // says it wants next. They're reset on each pass around the loop. ACE_Handle_Set rd_handle; ACE_Handle_Set wr_handle; status = ::SSL_accept (ssl); switch (::SSL_get_error (ssl, status)) { case SSL_ERROR_NONE: status = 0; // To tell caller about success break; // Done case SSL_ERROR_WANT_WRITE: wr_handle.set_bit (handle); status = 1; // Wait for more activity break; case SSL_ERROR_WANT_READ: rd_handle.set_bit (handle); status = 1; // Wait for more activity break; case SSL_ERROR_ZERO_RETURN: // The peer has notified us that it is shutting down via // the SSL "close_notify" message so we need to // shutdown, too. status = -1; break; case SSL_ERROR_SYSCALL: // On some platforms (e.g. MS Windows) OpenSSL does not // store the last error in errno so explicitly do so. // // Explicitly check for EWOULDBLOCK since it doesn't get // converted to an SSL_ERROR_WANT_{READ,WRITE} on some // platforms. If SSL_accept failed outright, though, don't // bother checking more. This can happen if the socket gets // closed during the handshake. if (ACE_OS::set_errno_to_last_error () == EWOULDBLOCK && status == -1) { // Although the SSL_ERROR_WANT_READ/WRITE isn't getting // set correctly, the read/write state should be valid. // Use that to decide what to do. status = 1; // Wait for more activity if (SSL_want_write (ssl)) wr_handle.set_bit (handle); else if (SSL_want_read (ssl)) rd_handle.set_bit (handle); else status = -1; // Doesn't want anything - bail out } else status = -1; break; default: ACE_SSL_Context::report_error (); status = -1; break; } if (status == 1) { // Must have at least one handle to wait for at this point. ACE_ASSERT (rd_handle.num_set() == 1 || wr_handle.num_set () == 1); status = ACE::select (int (handle) + 1, &rd_handle, &wr_handle, 0, timeout); (void) countdown.update (); // 0 is timeout, so we're done. // -1 is error, so we're done. // Could be both handles set (same handle in both masks) so // set to 1. if (status >= 1) status = 1; else // Timeout or failure status = -1; } } while (status == 1 && !SSL_is_init_finished (ssl)); if (reset_blocking_mode) { ACE_Errno_Guard eguard (errno); ACE::clr_flags (handle, ACE_NONBLOCK); } return (status == -1 ? -1 : 0); }
static int transfer(CLI *c) { /* transfer data */ fd_set rd_set, wr_set; int num, err, fdno; int check_SSL_pending; int ssl_closing; /* 0=not closing SSL, 1=initiate SSL_shutdown, * 2=retry SSL_shutdown, 3=SSL_shutdown done */ int ready; struct timeval tv; /* fdno=max(c->sock_rfd->fd, c->sock_wfd->fd, * fdno=c->ssl_rfd->fd, fdno=c->ssl_wfd->fd)+1 */ fdno=c->sock_rfd->fd; if(c->sock_wfd->fd>fdno) fdno=c->sock_wfd->fd; if(c->ssl_rfd->fd>fdno) fdno=c->ssl_rfd->fd; if(c->ssl_wfd->fd>fdno) fdno=c->ssl_wfd->fd; fdno+=1; c->sock_ptr=c->ssl_ptr=0; sock_rd=sock_wr=ssl_rd=ssl_wr=1; c->sock_bytes=c->ssl_bytes=0; ssl_closing=0; while(((sock_rd||c->sock_ptr)&&ssl_wr)||((ssl_rd||c->ssl_ptr)&&sock_wr)) { FD_ZERO(&rd_set); /* Setup rd_set */ if(sock_rd && c->sock_ptr<BUFFSIZE) /* socket input buffer not full*/ FD_SET(c->sock_rfd->fd, &rd_set); if(ssl_rd && ( c->ssl_ptr<BUFFSIZE || /* SSL input buffer not full */ ((c->sock_ptr||ssl_closing) && SSL_want_read(c->ssl)) /* I want to SSL_write or SSL_shutdown but read from the * underlying socket needed for the SSL protocol */ )) { FD_SET(c->ssl_rfd->fd, &rd_set); } FD_ZERO(&wr_set); /* Setup wr_set */ if(sock_wr && c->ssl_ptr) /* SSL input buffer not empty */ FD_SET(c->sock_wfd->fd, &wr_set); if (ssl_wr && ( c->sock_ptr || /* socket input buffer not empty */ ssl_closing==1 || /* initiate SSL_shutdown */ ((c->ssl_ptr<BUFFSIZE || ssl_closing==2) && SSL_want_write(c->ssl)) /* I want to SSL_read or SSL_shutdown but write to the * underlying socket needed for the SSL protocol */ )) { FD_SET(c->ssl_wfd->fd, &wr_set); } tv.tv_sec=sock_rd || (ssl_wr&&c->sock_ptr) || (sock_wr&&c->ssl_ptr) ? c->opt->timeout_idle : c->opt->timeout_close; tv.tv_usec=0; ready=sselect(fdno, &rd_set, &wr_set, NULL, &tv); if(ready<0) { /* Break the connection for others */ sockerror("select"); return -1; } if(!ready) { /* Timeout */ if(sock_rd) { /* No traffic for a long time */ log(LOG_DEBUG, "select timeout: connection reset"); return -1; } else { /* Timeout waiting for SSL close_notify */ log(LOG_DEBUG, "select timeout waiting for SSL close_notify"); break; /* Leave the while() loop */ } } if(ssl_closing==1 /* initiate SSL_shutdown */ || (ssl_closing==2 && ( (SSL_want_read(c->ssl) && FD_ISSET(c->ssl_rfd->fd, &rd_set)) || (SSL_want_write(c->ssl) && FD_ISSET(c->ssl_wfd->fd, &wr_set)) ))) { switch(SSL_shutdown(c->ssl)) { /* Send close_notify */ case 1: /* the shutdown was successfully completed */ log(LOG_INFO, "SSL_shutdown successfully sent close_notify"); ssl_wr=0; /* SSL write closed */ /* TODO: It's not really closed. We need to distinguish * closed SSL and closed underlying file descriptor */ ssl_closing=3; /* done! */ break; case 0: /* the shutdown is not yet finished */ log(LOG_DEBUG, "SSL_shutdown retrying"); ssl_closing=2; /* next time just retry SSL_shutdown */ break; case -1: /* a fatal error occurred */ sslerror("SSL_shutdown"); return -1; } } /* Set flag to try and read any buffered SSL data if we made */ /* room in the buffer by writing to the socket */ check_SSL_pending = 0; if(sock_wr && FD_ISSET(c->sock_wfd->fd, &wr_set)) { switch(num=writesocket(c->sock_wfd->fd, c->ssl_buff, c->ssl_ptr)) { case -1: /* error */ switch(get_last_socket_error()) { case EINTR: log(LOG_DEBUG, "writesocket interrupted by a signal: retrying"); break; case EWOULDBLOCK: log(LOG_NOTICE, "writesocket would block: retrying"); break; default: sockerror("writesocket"); return -1; } break; case 0: log(LOG_DEBUG, "No data written to the socket: retrying"); break; default: memmove(c->ssl_buff, c->ssl_buff+num, c->ssl_ptr-num); if(c->ssl_ptr==BUFFSIZE) check_SSL_pending=1; c->ssl_ptr-=num; c->sock_bytes+=num; if(!ssl_rd && !c->ssl_ptr) { shutdown(c->sock_wfd->fd, SHUT_WR); log(LOG_DEBUG, "Socket write shutdown (no more data to send)"); sock_wr=0; } } } if(ssl_wr && ( /* SSL sockets are still open */ (c->sock_ptr && FD_ISSET(c->ssl_wfd->fd, &wr_set)) || /* See if application data can be written */ (SSL_want_read(c->ssl) && FD_ISSET(c->ssl_rfd->fd, &rd_set)) /* I want to SSL_write but read from the underlying */ /* socket needed for the SSL protocol */ )) { num=SSL_write(c->ssl, c->sock_buff, c->sock_ptr); err=SSL_get_error(c->ssl, num); switch(err) { case SSL_ERROR_NONE: memmove(c->sock_buff, c->sock_buff+num, c->sock_ptr-num); c->sock_ptr-=num; c->ssl_bytes+=num; if(!ssl_closing && !sock_rd && !c->sock_ptr && ssl_wr) { log(LOG_DEBUG, "SSL write shutdown (no more data to send)"); ssl_closing=1; } break; case SSL_ERROR_WANT_WRITE: case SSL_ERROR_WANT_READ: case SSL_ERROR_WANT_X509_LOOKUP: log(LOG_DEBUG, "SSL_write returned WANT_: retrying"); break; case SSL_ERROR_SYSCALL: if(num<0) { /* really an error */ switch(get_last_socket_error()) { case EINTR: log(LOG_DEBUG, "SSL_write interrupted by a signal: retrying"); break; case EAGAIN: log(LOG_DEBUG, "SSL_write returned EAGAIN: retrying"); break; default: sockerror("SSL_write (ERROR_SYSCALL)"); return -1; } } break; case SSL_ERROR_ZERO_RETURN: /* close_notify received */ log(LOG_DEBUG, "SSL closed on SSL_write"); ssl_rd=ssl_wr=0; break; case SSL_ERROR_SSL: sslerror("SSL_write"); return -1; default: log(LOG_ERR, "SSL_write/SSL_get_error returned %d", err); return -1; } } if(sock_rd && FD_ISSET(c->sock_rfd->fd, &rd_set)) { switch(num=readsocket(c->sock_rfd->fd, c->sock_buff+c->sock_ptr, BUFFSIZE-c->sock_ptr)) { case -1: switch(get_last_socket_error()) { case EINTR: log(LOG_DEBUG, "readsocket interrupted by a signal: retrying"); break; case EWOULDBLOCK: log(LOG_NOTICE, "readsocket would block: retrying"); break; default: sockerror("readsocket"); return -1; } break; case 0: /* close */ log(LOG_DEBUG, "Socket closed on read"); sock_rd=0; if(!ssl_closing && !c->sock_ptr && ssl_wr) { log(LOG_DEBUG, "SSL write shutdown (output buffer empty)"); ssl_closing=1; } break; default: c->sock_ptr+=num; } } if(ssl_rd && ( /* SSL sockets are still open */ (c->ssl_ptr<BUFFSIZE && FD_ISSET(c->ssl_rfd->fd, &rd_set)) || /* See if there's any application data coming in */ (SSL_want_write(c->ssl) && FD_ISSET(c->ssl_wfd->fd, &wr_set)) || /* I want to SSL_read but write to the underlying */ /* socket needed for the SSL protocol */ (check_SSL_pending && SSL_pending(c->ssl)) /* Write made space from full buffer */ )) { num=SSL_read(c->ssl, c->ssl_buff+c->ssl_ptr, BUFFSIZE-c->ssl_ptr); err=SSL_get_error(c->ssl, num); switch(err) { case SSL_ERROR_NONE: c->ssl_ptr+=num; break; case SSL_ERROR_WANT_WRITE: case SSL_ERROR_WANT_READ: case SSL_ERROR_WANT_X509_LOOKUP: log(LOG_DEBUG, "SSL_read returned WANT_: retrying"); break; case SSL_ERROR_SYSCALL: if(num<0) { /* not EOF */ switch(get_last_socket_error()) { case EINTR: log(LOG_DEBUG, "SSL_read interrupted by a signal: retrying"); break; case EAGAIN: log(LOG_DEBUG, "SSL_read returned EAGAIN: retrying"); break; default: sockerror("SSL_read (ERROR_SYSCALL)"); return -1; } } else { /* EOF */ log(LOG_DEBUG, "SSL socket closed on SSL_read"); ssl_rd=ssl_wr=0; } break; case SSL_ERROR_ZERO_RETURN: /* close_notify received */ log(LOG_DEBUG, "SSL closed on SSL_read"); ssl_rd=0; if(!ssl_closing && !c->sock_ptr && ssl_wr) { log(LOG_DEBUG, "SSL write shutdown (output buffer empty)"); ssl_closing=1; } if(!c->ssl_ptr && sock_wr) { shutdown(c->sock_wfd->fd, SHUT_WR); log(LOG_DEBUG, "Socket write shutdown (output buffer empty)"); sock_wr=0; } break; case SSL_ERROR_SSL: sslerror("SSL_read"); return -1; default: log(LOG_ERR, "SSL_read/SSL_get_error returned %d", err); return -1; } } } return 0; /* OK */ }
LWS_VISIBLE int 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, m; if (!wsi->ssl) return lws_ssl_capable_read_no_ssl(wsi, buf, len); lws_stats_atomic_bump(context, pt, LWSSTATS_C_API_READ, 1); 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 #if defined(LWS_WITH_STATS) if (!wsi->seen_rx) { lws_stats_atomic_bump(wsi->context, pt, LWSSTATS_MS_SSL_RX_DELAY, time_in_microseconds() - wsi->accept_start_us); lws_stats_atomic_bump(wsi->context, pt, LWSSTATS_C_SSL_CONNS_HAD_RX, 1); wsi->seen_rx = 1; } #endif lwsl_debug("%p: SSL_read says %d\n", wsi, n); /* manpage: returning 0 means connection shut down */ if (!n || (n == -1 && errno == ENOTCONN)) { wsi->socket_is_permanently_unusable = 1; return LWS_SSL_CAPABLE_ERROR; } if (n < 0) { m = lws_ssl_get_error(wsi, n); lwsl_debug("%p: ssl err %d errno %d\n", wsi, m, errno); if (m == SSL_ERROR_ZERO_RETURN || m == SSL_ERROR_SYSCALL) return LWS_SSL_CAPABLE_ERROR; if (m == SSL_ERROR_WANT_READ || SSL_want_read(wsi->ssl)) { lwsl_debug("%s: WANT_READ\n", __func__); lwsl_debug("%p: LWS_SSL_CAPABLE_MORE_SERVICE\n", wsi); return LWS_SSL_CAPABLE_MORE_SERVICE; } if (m == SSL_ERROR_WANT_WRITE || SSL_want_write(wsi->ssl)) { lwsl_debug("%s: WANT_WRITE\n", __func__); lwsl_debug("%p: LWS_SSL_CAPABLE_MORE_SERVICE\n", wsi); return LWS_SSL_CAPABLE_MORE_SERVICE; } wsi->socket_is_permanently_unusable = 1; return LWS_SSL_CAPABLE_ERROR; } lws_stats_atomic_bump(context, pt, LWSSTATS_B_READ, n); if (wsi->vhost) wsi->vhost->conn_stats.rx += n; lws_restart_ws_ping_pong_timer(wsi); /* * if it was our buffer that limited what we read, * check if SSL has additional data pending inside SSL buffers. * * Because these won't signal at the network layer with POLLIN * and if we don't realize, this data will sit there forever */ if (n != len) goto bail; if (!wsi->ssl) goto bail; if (!SSL_pending(wsi->ssl)) goto bail; if (wsi->pending_read_list_next) return n; if (wsi->pending_read_list_prev) return n; if (pt->pending_read_list == wsi) return n; /* add us to the linked list of guys with pending ssl */ if (pt->pending_read_list) pt->pending_read_list->pending_read_list_prev = wsi; wsi->pending_read_list_next = pt->pending_read_list; wsi->pending_read_list_prev = NULL; pt->pending_read_list = wsi; return n; bail: lws_ssl_remove_wsi_from_buffered_list(wsi); return n; }
LWS_VISIBLE int 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, m; if (!wsi->tls.ssl) return lws_ssl_capable_read_no_ssl(wsi, buf, len); lws_stats_atomic_bump(context, pt, LWSSTATS_C_API_READ, 1); errno = 0; n = SSL_read(wsi->tls.ssl, buf, len); #if defined(LWS_WITH_ESP32) if (!n && errno == LWS_ENOTCONN) { lwsl_debug("%p: SSL_read ENOTCONN\n", wsi); return LWS_SSL_CAPABLE_ERROR; } #endif #if defined(LWS_WITH_STATS) if (!wsi->seen_rx && wsi->accept_start_us) { lws_stats_atomic_bump(wsi->context, pt, LWSSTATS_MS_SSL_RX_DELAY, lws_time_in_microseconds() - wsi->accept_start_us); lws_stats_atomic_bump(wsi->context, pt, LWSSTATS_C_SSL_CONNS_HAD_RX, 1); wsi->seen_rx = 1; } #endif lwsl_debug("%p: SSL_read says %d\n", wsi, n); /* manpage: returning 0 means connection shut down * * 2018-09-10: https://github.com/openssl/openssl/issues/1903 * * So, in summary, if you get a 0 or -1 return from SSL_read() / * SSL_write(), you should call SSL_get_error(): * * - If you get back SSL_ERROR_RETURN_ZERO then you know the connection * has been cleanly shutdown by the peer. To fully close the * connection you may choose to call SSL_shutdown() to send a * close_notify back. * * - If you get back SSL_ERROR_SSL then some kind of internal or * protocol error has occurred. More details will be on the SSL error * queue. You can also call SSL_get_shutdown(). If this indicates a * state of SSL_RECEIVED_SHUTDOWN then you know a fatal alert has * been received from the peer (if it had been a close_notify then * SSL_get_error() would have returned SSL_ERROR_RETURN_ZERO). * SSL_ERROR_SSL is considered fatal - you should not call * SSL_shutdown() in this case. * * - If you get back SSL_ERROR_SYSCALL then some kind of fatal (i.e. * non-retryable) error has occurred in a system call. */ if (n <= 0) { m = lws_ssl_get_error(wsi, n); lwsl_debug("%p: ssl err %d errno %d\n", wsi, m, errno); if (m == SSL_ERROR_ZERO_RETURN) /* cleanly shut down */ return LWS_SSL_CAPABLE_ERROR; /* hm not retryable.. could be 0 size pkt or error */ if (m == SSL_ERROR_SSL || m == SSL_ERROR_SYSCALL || errno == LWS_ENOTCONN) { /* unclean, eg closed conn */ wsi->socket_is_permanently_unusable = 1; return LWS_SSL_CAPABLE_ERROR; } /* retryable? */ if (SSL_want_read(wsi->tls.ssl)) { lwsl_debug("%s: WANT_READ\n", __func__); lwsl_debug("%p: LWS_SSL_CAPABLE_MORE_SERVICE\n", wsi); return LWS_SSL_CAPABLE_MORE_SERVICE; } if (SSL_want_write(wsi->tls.ssl)) { lwsl_debug("%s: WANT_WRITE\n", __func__); lwsl_debug("%p: LWS_SSL_CAPABLE_MORE_SERVICE\n", wsi); return LWS_SSL_CAPABLE_MORE_SERVICE; } /* keep on trucking it seems */ } lws_stats_atomic_bump(context, pt, LWSSTATS_B_READ, n); if (wsi->vhost) wsi->vhost->conn_stats.rx += n; // lwsl_hexdump_err(buf, n); /* * if it was our buffer that limited what we read, * check if SSL has additional data pending inside SSL buffers. * * Because these won't signal at the network layer with POLLIN * and if we don't realize, this data will sit there forever */ if (n != len) goto bail; if (!wsi->tls.ssl) goto bail; if (!SSL_pending(wsi->tls.ssl)) goto bail; if (wsi->tls.pending_read_list_next) return n; if (wsi->tls.pending_read_list_prev) return n; if (pt->tls.pending_read_list == wsi) return n; /* add us to the linked list of guys with pending ssl */ if (pt->tls.pending_read_list) pt->tls.pending_read_list->tls.pending_read_list_prev = wsi; wsi->tls.pending_read_list_next = pt->tls.pending_read_list; wsi->tls.pending_read_list_prev = NULL; pt->tls.pending_read_list = wsi; return n; bail: lws_ssl_remove_wsi_from_buffered_list(wsi); return n; }