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_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; } }
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; }
VALUE engine_read(VALUE self) { ms_conn* conn; char buf[512]; int bytes, n, error; Data_Get_Struct(self, ms_conn, conn); ERR_clear_error(); bytes = SSL_read(conn->ssl, (void*)buf, sizeof(buf)); if(bytes > 0) { return rb_str_new(buf, bytes); } if(SSL_want_read(conn->ssl)) return Qnil; error = SSL_get_error(conn->ssl, bytes); if(error == SSL_ERROR_ZERO_RETURN) { rb_eof_error(); } else { raise_error(conn->ssl, bytes); } return Qnil; }
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 }
/* * read data from the encrypted layer. */ int client_read_sslbuffer(StrBuf *buf, int timeout) { char sbuf[16384]; /* OpenSSL communicates in 16k blocks, so let's speak its native tongue. */ int rlen; char junk[1]; SSL *pssl = THREADSSL; if (pssl == NULL) return(-1); while (1) { if (SSL_want_read(pssl)) { if ((SSL_write(pssl, junk, 0)) < 1) { syslog(LOG_WARNING, "SSL_write in client_read\n"); } } rlen = SSL_read(pssl, sbuf, sizeof(sbuf)); if (rlen < 1) { long errval; errval = SSL_get_error(pssl, rlen); if (errval == SSL_ERROR_WANT_READ || errval == SSL_ERROR_WANT_WRITE) { sleeeeeeeeeep(1); continue; } syslog(LOG_WARNING, "SSL_read got error %ld\n", errval); endtls(); return (-1); } StrBufAppendBufPlain(buf, sbuf, rlen, 0); return rlen; } return (0); }
void cbtls_info(const SSL *s, int where, int ret) { const char *str, *state; int w; REQUEST *request = SSL_get_ex_data(s, FR_TLS_EX_INDEX_REQUEST); char buffer[1024]; w = where & ~SSL_ST_MASK; if (w & SSL_ST_CONNECT) str=" TLS_connect"; else if (w & SSL_ST_ACCEPT) str=" TLS_accept"; else str=" (other)"; state = SSL_state_string_long(s); state = state ? state : "NULL"; buffer[0] = '\0'; if (where & SSL_CB_LOOP) { RDEBUG2("%s: %s", str, state); } else if (where & SSL_CB_HANDSHAKE_START) { RDEBUG2("%s: %s", str, state); } else if (where & SSL_CB_HANDSHAKE_DONE) { RDEBUG2("%s: %s", str, state); } else if (where & SSL_CB_ALERT) { str=(where & SSL_CB_READ)?"read":"write"; snprintf(buffer, sizeof(buffer), "TLS Alert %s:%s:%s", str, SSL_alert_type_string_long(ret), SSL_alert_desc_string_long(ret)); } else if (where & SSL_CB_EXIT) { if (ret == 0) { snprintf(buffer, sizeof(buffer), "%s: failed in %s", str, state); } else if (ret < 0) { if (SSL_want_read(s)) { RDEBUG2("%s: Need to read more data: %s", str, state); } else { snprintf(buffer, sizeof(buffer), "%s: error in %s", str, state); } } } if (buffer[0]) { radlog(L_ERR, "%s", buffer); if (request) { VALUE_PAIR *vp; vp = pairmake("Module-Failure-Message", buffer, T_OP_ADD); if (vp) pairadd(&request->packet->vps, vp); } } }
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 more data has to be read\n\ "; static PyObject * ssl_Connection_want_read(ssl_ConnectionObj *self, PyObject *args) { if (!PyArg_ParseTuple(args, ":want_read")) return NULL; return PyLong_FromLong((long)SSL_want_read(self->ssl)); }
USES_APPLE_DEPRECATED_API /* OpenSSL API has been deprecated by Apple */ #include <freeradius-devel/radiusd.h> #ifdef WITH_TLS void cbtls_info(SSL const *s, int where, int ret) { char const *str, *state; int w; REQUEST *request = SSL_get_ex_data(s, FR_TLS_EX_INDEX_REQUEST); char buffer[1024]; w = where & ~SSL_ST_MASK; if (w & SSL_ST_CONNECT) str=" TLS_connect"; else if (w & SSL_ST_ACCEPT) str=" TLS_accept"; else str=" (other)"; state = SSL_state_string_long(s); state = state ? state : "NULL"; buffer[0] = '\0'; if (where & SSL_CB_LOOP) { RDEBUG2("%s: %s", str, state); } else if (where & SSL_CB_HANDSHAKE_START) { RDEBUG2("%s: %s", str, state); } else if (where & SSL_CB_HANDSHAKE_DONE) { RDEBUG2("%s: %s", str, state); } else if (where & SSL_CB_ALERT) { str=(where & SSL_CB_READ)?"read":"write"; snprintf(buffer, sizeof(buffer), "TLS Alert %s:%s:%s", str, SSL_alert_type_string_long(ret), SSL_alert_desc_string_long(ret)); } else if (where & SSL_CB_EXIT) { if (ret == 0) { snprintf(buffer, sizeof(buffer), "%s: failed in %s", str, state); } else if (ret < 0) { if (SSL_want_read(s)) { RDEBUG2("%s: Need to read more data: %s", str, state); } else { snprintf(buffer, sizeof(buffer), "%s: error in %s", str, state); } } } if (buffer[0] && request) { REDEBUG("SSL says: %s", buffer); } }
bool Connection::readHandshake() { log_trace("Connection::readHandshake"); std::streambuf* sb = _ios->rdbuf(); if( ! sb) return true; while(_ios->rdbuf()->in_avail() > 0) { const std::streamsize bufsize = 2000; char buf[bufsize]; std::streamsize gsize = std::min( sb->in_avail(), bufsize ); std::streamsize n = sb->sgetn(buf, gsize); const int written = BIO_write(_in, buf, static_cast<int>(n)); assert(written == n); if(written <= 0 || written != n) throw SslError("BIO_write"); log_debug("read " << n << " bytes from input"); } int ret = SSL_do_handshake(_ssl); log_debug("SSL_do_handshake returns " << ret); if( ret <= 0 ) { 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 && BIO_pending(_out) <= 0 ) { _connected = true; } return BIO_pending(_out) <= 0 && SSL_want_read(_ssl); }
void cbtls_info(const SSL *s, int where, int ret) { const char *str, *state; int w; REQUEST *request = SSL_get_ex_data(s, FR_TLS_EX_INDEX_REQUEST); char buffer[1024]; w = where & ~SSL_ST_MASK; if (w & SSL_ST_CONNECT) str=" TLS_connect"; else if (w & SSL_ST_ACCEPT) str=" TLS_accept"; else str=" (other)"; state = SSL_state_string_long(s); state = state ? state : "NULL"; buffer[0] = '\0'; if (where & SSL_CB_LOOP) { RDEBUG2("%s: %s", str, state); } else if (where & SSL_CB_HANDSHAKE_START) { RDEBUG2("%s: %s", str, state); } else if (where & SSL_CB_HANDSHAKE_DONE) { RDEBUG2("%s: %s", str, state); } else if (where & SSL_CB_ALERT) { str=(where & SSL_CB_READ)?"read":"write"; snprintf(buffer, sizeof(buffer), "TLS Alert %s:%s:%s", str, SSL_alert_type_string_long(ret), SSL_alert_desc_string_long(ret)); } else if (where & SSL_CB_EXIT) { if (ret == 0) { snprintf(buffer, sizeof(buffer), "%s: failed in %s", str, state); } else if (ret < 0) { if (SSL_want_read(s)) { RDEBUG2("%s: Need to read more data: %s", str, state); } else { snprintf(buffer, sizeof(buffer), "%s: error in %s", str, state); } } } if (buffer[0] && request) { RDEBUGE("SSL says: %s", buffer); } }
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; }
void cbtls_info(const SSL *s, int where, int ret) { const char *str, *state; int w; EAP_HANDLER *handler = (EAP_HANDLER *)SSL_get_ex_data(s, 0); REQUEST *request = NULL; if (handler) request = handler->request; w = where & ~SSL_ST_MASK; if (w & SSL_ST_CONNECT) str=" TLS_connect"; else if (w & SSL_ST_ACCEPT) str=" TLS_accept"; else str=" (other)"; state = SSL_state_string_long(s); state = state ? state : "NULL"; if (where & SSL_CB_LOOP) { RDEBUG2("%s: %s\n", str, state); } else if (where & SSL_CB_HANDSHAKE_START) { RDEBUG2("%s: %s\n", str, state); } else if (where & SSL_CB_HANDSHAKE_DONE) { RDEBUG2("%s: %s\n", str, state); } else if (where & SSL_CB_ALERT) { str=(where & SSL_CB_READ)?"read":"write"; radlog(L_ERR,"TLS Alert %s:%s:%s\n", str, SSL_alert_type_string_long(ret), SSL_alert_desc_string_long(ret)); } else if (where & SSL_CB_EXIT) { if (ret == 0) { radlog(L_ERR, "%s:failed in %s\n", str, state); } else if (ret < 0) { if (SSL_want_read(s)) { RDEBUG2("%s: Need to read more data: %s", str, state); } else { radlog(L_ERR, "%s:error in %s\n", str, state); } } } }
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; }
int as_tls_read(as_socket* sock, void* bufp, size_t len, uint32_t socket_timeout, uint64_t deadline) { uint8_t* buf = (uint8_t *) bufp; size_t pos = 0; while (true) { int rv = SSL_read(sock->ssl, buf + pos, (int)(len - pos)); if (rv > 0) { pos += rv; if (pos >= len) { return 0; } } else /* if (rv <= 0) */ { int sslerr; // Avoid the expensive call to SSL_get_error() in the most common case. BIO* bio = SSL_get_rbio(sock->ssl); if (SSL_want_read(sock->ssl) && BIO_should_read(bio) && BIO_should_retry(bio)) { sslerr = SSL_ERROR_WANT_READ; } else { sslerr = SSL_get_error(sock->ssl, rv); } unsigned long errcode; char errbuf[1024]; switch (sslerr) { case SSL_ERROR_WANT_READ: rv = wait_socket(sock->fd, socket_timeout, deadline, true); if (rv != 0) { return rv; } // loop back around and retry break; case SSL_ERROR_WANT_WRITE: rv = wait_socket(sock->fd, socket_timeout, deadline, false); if (rv != 0) { return rv; } // loop back around and retry break; case SSL_ERROR_SSL: log_verify_details(sock); errcode = ERR_get_error(); ERR_error_string_n(errcode, errbuf, sizeof(errbuf)); as_log_warn("SSL_read failed: %s", errbuf); return -1; case SSL_ERROR_SYSCALL: errcode = ERR_get_error(); if (errcode != 0) { ERR_error_string_n(errcode, errbuf, sizeof(errbuf)); as_log_warn("SSL_read I/O error: %s", errbuf); } else { if (rv == 0) { as_log_warn("SSL_read I/O error: unexpected EOF"); } else { as_log_warn("SSL_read I/O error: %d", as_last_error()); } } return -1; default: as_log_warn("SSL_read: unexpected ssl error: %d", sslerr); return -1; break; } } } }
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; }
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; }
/** Record session state changes * * Called by OpenSSL whenever the session state changes, an alert is received or an error occurs. * * @param[in] ssl session. * @param[in] where Which context the callback is being called in. * See https://www.openssl.org/docs/manmaster/ssl/SSL_CTX_set_info_callback.html * for additional info. * @param[in] ret 0 if an error occurred, or the alert type if an alert was received. */ void tls_session_info_cb(SSL const *ssl, int where, int ret) { char const *role, *state; REQUEST *request = SSL_get_ex_data(ssl, FR_TLS_EX_INDEX_REQUEST); if ((where & ~SSL_ST_MASK) & SSL_ST_CONNECT) { role = "Client "; } else if (((where & ~SSL_ST_MASK)) & SSL_ST_ACCEPT) { role = "Server "; } else { role = ""; } state = SSL_state_string_long(ssl); state = state ? state : "<INVALID>"; if ((where & SSL_CB_LOOP) || (where & SSL_CB_HANDSHAKE_START) || (where & SSL_CB_HANDSHAKE_DONE)) { if (RDEBUG_ENABLED3) { char const *abbrv = SSL_state_string(ssl); size_t len; /* * Trim crappy OpenSSL state strings... */ len = strlen(abbrv); if ((len > 1) && (abbrv[len - 1] == ' ')) len--; RDEBUG3("Handshake state [%.*s] - %s%s", (int)len, abbrv, role, state); } else { RDEBUG2("Handshake state - %s%s", role, state); } return; } if (where & SSL_CB_ALERT) { if ((ret & 0xff) == SSL_AD_CLOSE_NOTIFY) return; if (where & SSL_CB_READ) { VALUE_PAIR *vp; REDEBUG("Client sent %s TLS alert: %s", SSL_alert_type_string_long(ret), SSL_alert_desc_string_long(ret)); /* * Offer helpful advice... Should be expanded. */ switch (ret & 0xff) { case TLS1_AD_UNKNOWN_CA: REDEBUG("Verify client has copy of CA certificate, and trusts CA"); break; default: break; } MEM(pair_update_request(&vp, attr_tls_client_error_code) >= 0); vp->vp_uint8 = ret & 0xff; RDEBUG2("&TLS-Client-Error-Code := %pV", &vp->data); } else { REDEBUG("Sending client %s TLS alert: %s %i", SSL_alert_type_string_long(ret), SSL_alert_desc_string_long(ret), ret & 0xff); } return; } if (where & SSL_CB_EXIT) { if (ret == 0) { REDEBUG("Handshake exit state %s%s", role, state); return; } if (ret < 0) { if (SSL_want_read(ssl)) { RDEBUG2("Need more data from client"); /* State same as previous call, don't print */ return; } REDEBUG("Handshake exit state %s%s", role, state); } } }
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 */ }
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); }
int32 StartPollThread(void* punt) { MSNP* mainClass = (MSNP*) punt; MSN::NotificationServerConnection* mainConnection = mainClass->GetConnection(); mainConnection->connect("messenger.hotmail.com", 1863); while (1) { fflush(stdout); if (kPollSockets == NULL) continue; poll(kPollSockets, kSocketsCount, 3); for (int i = 0; i < kSocketsCount; i++) { if (kPollSockets[i].fd == -1) { continue; } if (kPollSockets[i].revents & POLLHUP) { kPollSockets[i].revents = 0; continue; } if (kPollSockets[i].revents & (POLLIN | POLLOUT | POLLPRI)) { MSN::Connection *c; c = mainConnection->connectionWithSocket((void*)kPollSockets[i].fd); if (c != NULL) { // TODO make the ssl code more styled and less bugged if (kSocketsSsl[i].isSSL && !kSocketsSsl[i].isConnected) { BIO *bio_socket_new; SSL_METHOD *meth=NULL; meth=const_cast<SSL_METHOD*>(SSLv23_client_method()); SSL_library_init(); kSocketsSsl[i].ctx = SSL_CTX_new(meth); kSocketsSsl[i].ssl = SSL_new(kSocketsSsl[i].ctx); bio_socket_new = BIO_new_socket(kPollSockets[i].fd, BIO_CLOSE); if (!kSocketsSsl[i].ssl) break; BIO_set_nbio(bio_socket_new, 0); SSL_set_bio(kSocketsSsl[i].ssl, bio_socket_new, bio_socket_new); SSL_set_mode(kSocketsSsl[i].ssl, SSL_MODE_AUTO_RETRY); // TODO - fix-me - not async and buggy // and handle errors /*int ret =*/ SSL_connect(kSocketsSsl[i].ssl); kSocketsSsl[i].isConnected = true; } if (c->isConnected() == false) c->socketConnectionCompleted(); if (kPollSockets[i].revents & POLLIN) { if (kSocketsSsl[i].isSSL && kSocketsSsl[i].isConnected) { if (SSL_want_read(kSocketsSsl[i].ssl)) { kPollSockets[i].revents = 0; continue; } } c->dataArrivedOnSocket(); } if (kPollSockets[i].revents & POLLOUT) { c->socketIsWritable(); } } } if (kPollSockets[i].revents & (POLLERR | POLLNVAL)) { MSN::Connection *c; c = mainConnection->connectionWithSocket((void*)kPollSockets[i].fd); if (c != NULL) { delete c; } kPollSockets[i].fd = -1; kPollSockets[i].revents = 0; continue; } } if (kPollSockets[0].revents & POLLIN) { kPollSockets[0].revents = 0; } } return 0; }
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; }