/* * XXX bad assumption here that conn_wrap_fd for SSL can only happens * for the server side!!!! FIXME !!!! */ Connection *conn_wrap_fd(int fd, int ssl) { Connection *conn; if (socket_set_blocking(fd, 0) < 0) return NULL; conn = gw_malloc(sizeof(*conn)); conn->inlock = mutex_create(); conn->outlock = mutex_create(); conn->claimed = 0; conn->outbuf = octstr_create(""); conn->outbufpos = 0; conn->inbuf = octstr_create(""); conn->inbufpos = 0; conn->fd = fd; conn->connected = yes; conn->read_eof = 0; conn->io_error = 0; conn->output_buffering = DEFAULT_OUTPUT_BUFFERING; conn->registered = NULL; conn->callback = NULL; conn->callback_data = NULL; conn->callback_data_destroyer = NULL; conn->listening_pollin = 0; conn->listening_pollout = 0; #ifdef HAVE_LIBSSL /* * do all the SSL magic for this connection */ if (ssl) { conn->ssl = SSL_new(global_server_ssl_context); conn->peer_certificate = NULL; /* SSL_set_fd can fail, so check it */ if (SSL_set_fd(conn->ssl, conn->fd) == 0) { /* SSL_set_fd failed, log error and return NULL */ error(errno, "SSL: OpenSSL: %.256s", ERR_error_string(ERR_get_error(), NULL)); conn_destroy(conn); return NULL; } /* SSL_set_verify(conn->ssl, 0, NULL); */ /* set read/write BIO layer to non-blocking mode */ BIO_set_nbio(SSL_get_rbio(conn->ssl), 1); BIO_set_nbio(SSL_get_wbio(conn->ssl), 1); /* set accept state , SSL-Handshake will be handled transparent while SSL_[read|write] */ SSL_set_accept_state(conn->ssl); } else { conn->ssl = NULL; conn->peer_certificate = NULL; } #endif /* HAVE_LIBSSL */ return conn; }
int zc_socket_ssl_handshake(zcSocket *s) { int ret; int err; int sockstate, nonblocking; /* just in case the blocking state of the socket has been changed */ nonblocking = !s->blocked; //(self->Socket->sock_timeout >= 0.0); BIO_set_nbio(SSL_get_rbio(s->ssl), nonblocking); BIO_set_nbio(SSL_get_wbio(s->ssl), nonblocking); /* Actually negotiate SSL connection */ /* XXX If SSL_do_handshake() returns 0, it's also a failure. */ sockstate = 0; do { ret = SSL_do_handshake(s->ssl); err = SSL_get_error(s->ssl, ret); if (err == SSL_ERROR_WANT_READ) { sockstate = zc_socket_select(s, 0); //check_socket_and_wait_for_timeout(s->fd, 0); } else if (err == SSL_ERROR_WANT_WRITE) { sockstate = zc_socket_select(s, 1); //check_socket_and_wait_for_timeout(s->fd, 1); } else { sockstate = ZC_SSL_SOCKET_OPERATION_OK; } if (sockstate == ZC_SSL_SOCKET_HAS_TIMED_OUT) { //PyErr_SetString(PySSLErrorObject, ERRSTR("The handshake operation timed out")); ZCWARN("The handshake operation timed out"); return ZC_ERR; } else if (sockstate == ZC_SSL_SOCKET_HAS_BEEN_CLOSED) { //PyErr_SetString(PySSLErrorObject, ERRSTR("Underlying socket has been closed.")); ZCWARN("Underlying socket has been closed."); return ZC_ERR; } else if (sockstate == ZC_SSL_SOCKET_TOO_LARGE_FOR_SELECT) { //PyErr_SetString(PySSLErrorObject, ERRSTR("Underlying socket too large for select().")); ZCWARN("Underlying socket too large for select()."); return ZC_ERR; } else if (sockstate == ZC_SSL_SOCKET_IS_NONBLOCKING) { break; } } while (err == SSL_ERROR_WANT_READ || err == SSL_ERROR_WANT_WRITE); if (ret < 1) { ZCWARN("handshak error:%d", ret); return ZC_ERR; } //return PySSL_SetError(self, ret, __FILE__, __LINE__); if (s->peer_cert) X509_free (s->peer_cert); if ((s->peer_cert = SSL_get_peer_certificate(s->ssl))) { X509_NAME_oneline(X509_get_subject_name(s->peer_cert), s->server, X509_NAME_MAXLEN); X509_NAME_oneline(X509_get_issuer_name(s->peer_cert), s->issuer, X509_NAME_MAXLEN); } return ZC_OK; }
int zc_socket_ssl_send(zcSocket *s, char *buf, int blen) { //char *data; int len; //int count; int sockstate; int err; int nonblocking; /* just in case the blocking state of the socket has been changed */ nonblocking = !s->blocked; //(self->Socket->sock_timeout >= 0.0); BIO_set_nbio(SSL_get_rbio(s->ssl), nonblocking); BIO_set_nbio(SSL_get_wbio(s->ssl), nonblocking); //sockstate = check_socket_and_wait_for_timeout(self->Socket, 1); sockstate = zc_socket_select(s, 1); if (sockstate == ZC_SSL_SOCKET_HAS_TIMED_OUT) { ZCWARN("The write operation timed out"); return ZC_ERR; } else if (sockstate == ZC_SSL_SOCKET_HAS_BEEN_CLOSED) { ZCWARN("Underlying socket has been closed."); return ZC_ERR; } else if (sockstate == ZC_SSL_SOCKET_TOO_LARGE_FOR_SELECT) { ZCWARN("Underlying socket too large for select()."); return ZC_ERR; } do { err = 0; len = SSL_write(s->ssl, buf, blen); err = SSL_get_error(s->ssl, len); if (err == SSL_ERROR_WANT_READ) { sockstate = zc_socket_select(s, 0); } else if (err == SSL_ERROR_WANT_WRITE) { sockstate = zc_socket_select(s, 1); } else { sockstate = ZC_SSL_SOCKET_OPERATION_OK; } if (sockstate == ZC_SSL_SOCKET_HAS_TIMED_OUT) { ZCWARN("The write operation timed out"); return ZC_ERR; } else if (sockstate == ZC_SSL_SOCKET_HAS_BEEN_CLOSED) { ZCWARN("Underlying socket has been closed."); return ZC_ERR; } else if (sockstate == ZC_SSL_SOCKET_IS_NONBLOCKING) { break; } } while (err == SSL_ERROR_WANT_READ || err == SSL_ERROR_WANT_WRITE); if (len > 0) //return PyInt_FromLong(len); return len; else //return PySSL_SetError(self, len, __FILE__, __LINE__); return len; }
int lws_tls_server_new_nonblocking(struct lws *wsi, lws_sockfd_type accept_fd) { #if !defined(USE_WOLFSSL) BIO *bio; #endif errno = 0; wsi->tls.ssl = SSL_new(wsi->vhost->tls.ssl_ctx); if (wsi->tls.ssl == NULL) { lwsl_err("SSL_new failed: %d (errno %d)\n", lws_ssl_get_error(wsi, 0), errno); lws_tls_err_describe(); return 1; } SSL_set_ex_data(wsi->tls.ssl, openssl_websocket_private_data_index, wsi); SSL_set_fd(wsi->tls.ssl, (int)(long long)accept_fd); #ifdef USE_WOLFSSL #ifdef USE_OLD_CYASSL CyaSSL_set_using_nonblock(wsi->tls.ssl, 1); #else wolfSSL_set_using_nonblock(wsi->tls.ssl, 1); #endif #else SSL_set_mode(wsi->tls.ssl, SSL_MODE_ACCEPT_MOVING_WRITE_BUFFER | SSL_MODE_RELEASE_BUFFERS); bio = SSL_get_rbio(wsi->tls.ssl); if (bio) BIO_set_nbio(bio, 1); /* nonblocking */ else lwsl_notice("NULL rbio\n"); bio = SSL_get_wbio(wsi->tls.ssl); if (bio) BIO_set_nbio(bio, 1); /* nonblocking */ else lwsl_notice("NULL rbio\n"); #endif #if defined (LWS_HAVE_SSL_SET_INFO_CALLBACK) if (wsi->vhost->tls.ssl_info_event_mask) SSL_set_info_callback(wsi->tls.ssl, lws_ssl_info_callback); #endif return 0; }
void set_nonblocking(BIO *bio) { if(BIO_method_type(bio) == BIO_TYPE_CONNECT) { BIO_set_nbio(bio, 1); } if(BIO_method_type(bio) == BIO_TYPE_ACCEPT) { BIO_set_nbio_accept(bio, 1); } #ifdef DTLS_IMPLEMENTED if(BIO_method_type(bio) == BIO_TYPE_DGRAM) { int fd = BIO_get_fd(bio, NULL); #ifdef WIN32 unsigned long nonzero = 1; SocketResetErrorStatus(); ioctlsocket(fd, FIONBIO, &nonzero); #else fcntl(fd, F_SETFL, FASYNC | O_NONBLOCK); #endif } #endif }
static LUA_FUNCTION(openssl_bio_nbio) { BIO* bio = CHECK_OBJECT(1, BIO, "openssl.bio"); int nbio = lua_toboolean(L, 2); int ret = BIO_set_nbio(bio, nbio); return openssl_pushresult(L, ret); }
ms_conn* engine_alloc(VALUE klass, VALUE* obj) { ms_conn* conn; *obj = Data_Make_Struct(klass, ms_conn, 0, engine_free, conn); conn->read = BIO_new(BIO_s_mem()); BIO_set_nbio(conn->read, 1); conn->write = BIO_new(BIO_s_mem()); BIO_set_nbio(conn->write, 1); conn->ssl = 0; conn->ctx = 0; return conn; }
static enum pbpal_resolv_n_connect_result resolv_and_connect_wout_SSL(pubnub_t *pb) { PUBNUB_LOG_TRACE("resolv_and_connect_wout_SSL\n"); if (NULL == pb->pal.socket) { char const*origin = PUBNUB_ORIGIN_SETTABLE ? pb->origin : PUBNUB_ORIGIN; PUBNUB_LOG_TRACE("pb=%p: Don't have BIO\n", pb); pb->pal.socket = BIO_new_connect((char*)origin); } if (NULL == pb->pal.socket) { return pbpal_resolv_resource_failure; } BIO_set_conn_port(pb->pal.socket, "http"); BIO_set_nbio(pb->pal.socket, !pb->options.use_blocking_io); WATCH_ENUM(pb->options.use_blocking_io); if (BIO_do_connect(pb->pal.socket) <= 0) { if (BIO_should_retry(pb->pal.socket)) { return pbpal_connect_wouldblock; } ERR_print_errors_cb(print_to_pubnub_log, NULL); PUBNUB_LOG_ERROR("BIO_do_connect failed\n"); return pbpal_connect_failed; } PUBNUB_LOG_TRACE("pb=%p: BIO connected\n", pb); { int fd = BIO_get_fd(pb->pal.socket, NULL); socket_set_rcv_timeout(fd, pb->transaction_timeout_ms); } return pbpal_connect_success; }
static int handshake (struct stream_data *data) { int ret; int finished; SSL_library_init(); SSL_load_error_strings(); data->ssl_ctx = SSL_CTX_new(TLSv1_method()); if(!data->ssl_ctx) return IKS_NOMEM; data->ssl = SSL_new(data->ssl_ctx); if(!data->ssl) return IKS_NOMEM; if( SSL_set_fd(data->ssl, (int)(intptr_t)data->sock) != 1 ) return IKS_NOMEM; /* Set both the read and write BIO's to non-blocking mode */ BIO_set_nbio(SSL_get_rbio(data->ssl), 1); BIO_set_nbio(SSL_get_wbio(data->ssl), 1); finished = 0; do { ret = SSL_connect(data->ssl); if( ret != 1 ) { if( wait_for_data(data, ret, 1) != IKS_OK ) { finished = 1; SSL_free(data->ssl); } } } while( ret != 1 && finished != 1 ); if( ret == 1 ) { data->flags &= (~SF_TRY_SECURE); data->flags |= SF_SECURE; iks_send_header (data->prs, data->server); } return ret == 1 ? IKS_OK : IKS_NET_TLSFAIL; }
static int conn_init_client_ssl(Connection *ret, Octstr *certkeyfile) { ret->ssl = SSL_new(global_ssl_context); /* * The current thread's error queue must be empty before * the TLS/SSL I/O operation is attempted, or SSL_get_error() * will not work reliably. */ ERR_clear_error(); if (certkeyfile != NULL) { SSL_use_certificate_file(ret->ssl, octstr_get_cstr(certkeyfile), SSL_FILETYPE_PEM); SSL_use_PrivateKey_file(ret->ssl, octstr_get_cstr(certkeyfile), SSL_FILETYPE_PEM); if (SSL_check_private_key(ret->ssl) != 1) { error(0, "conn_open_ssl: private key isn't consistent with the " "certificate from file %s (or failed reading the file)", octstr_get_cstr(certkeyfile)); return -1; } } /* SSL_set_fd can fail, so check it */ if (SSL_set_fd(ret->ssl, ret->fd) == 0) { /* SSL_set_fd failed, log error */ error(errno, "SSL: OpenSSL: %.256s", ERR_error_string(ERR_get_error(), NULL)); return -1; } /* * make sure the socket is non-blocking while we do SSL_connect */ if (socket_set_blocking(ret->fd, 0) < 0) { return -1; } BIO_set_nbio(SSL_get_rbio(ret->ssl), 1); BIO_set_nbio(SSL_get_wbio(ret->ssl), 1); SSL_set_connect_state(ret->ssl); return 0; }
/** Associate an SSL object with a socket and return it. * \param sock socket descriptor to associate with an SSL object. * \return pointer to SSL object. */ SSL * ssl_setup_socket(int sock) { SSL *ssl; BIO *bio; ssl = SSL_new(ctx); bio = BIO_new_socket(sock, BIO_NOCLOSE); BIO_set_nbio(bio, 1); SSL_set_bio(ssl, bio, bio); return ssl; }
/** Associate an SSL object with a socket and return it. * \param sock socket descriptor to associate with an SSL object. * \return pointer to SSL object. */ SSL * ssl_setup_socket(int sock) { SSL *ssl; BIO *bio; ssl = ssl_alloc_struct(); bio = BIO_new_socket(sock, BIO_NOCLOSE); BIO_set_nbio(bio, 1); SSL_set_bio(ssl, bio, bio); return ssl; }
Connection::Connection(Context& ctx, std::ios& ios, OpenMode omode) : _ios(&ios) , _connected(false) , _in(0) , _out(0) , _ssl(0) { // Create the SSL objects _in = BIO_new( BIO_s_mem() ); _out = BIO_new( BIO_s_mem() ); _ssl = SSL_new( ctx.impl()->ctx() ); // Connect the BIO BIO_set_nbio(_in, 1); BIO_set_nbio(_out, 1); SSL_set_bio(_ssl, _in, _out); if(omode == Accept) SSL_set_accept_state(_ssl); else SSL_set_connect_state(_ssl); assert(_ssl); }
int ssl_connect(thread_t * thread) { SOCK *sock_obj = THREAD_ARG(thread); int ret; sock_obj->ssl = SSL_new(req->ctx); sock_obj->bio = BIO_new_socket(sock_obj->fd, BIO_NOCLOSE); BIO_set_nbio(sock_obj->bio, 1); /* Set the Non-Blocking flag */ SSL_set_bio(sock_obj->ssl, sock_obj->bio, sock_obj->bio); ret = SSL_connect(sock_obj->ssl); DBG(" SSL_connect return code = %d on fd:%d\n", ret, thread->u.fd); ssl_printerr(SSL_get_error(sock_obj->ssl, ret)); return (ret > 0) ? 1 : 0; }
void set_blocking(BIO *bio) { if(BIO_method_type(bio) == BIO_TYPE_CONNECT) { BIO_set_nbio(bio, 0); } if(BIO_method_type(bio) == BIO_TYPE_ACCEPT) { BIO_set_nbio_accept(bio, 0); } #ifdef DTLS_IMPLEMENTED if(BIO_method_type(bio) == BIO_TYPE_DGRAM) { int fd, flags; if((fd = BIO_get_fd(bio, NULL))) { flags = fcntl(fd, F_GETFL); flags &= ~O_NONBLOCK; fcntl(fd, F_SETFL, flags); } } #endif }
static HANDSHAKE_RESULT *do_handshake_internal( SSL_CTX *server_ctx, SSL_CTX *server2_ctx, SSL_CTX *client_ctx, const SSL_TEST_CTX *test_ctx, SSL_SESSION *session_in, SSL_SESSION **session_out) { SSL *server, *client; BIO *client_to_server, *server_to_client; HANDSHAKE_EX_DATA server_ex_data, client_ex_data; CTX_DATA client_ctx_data, server_ctx_data, server2_ctx_data; HANDSHAKE_RESULT *ret = HANDSHAKE_RESULT_new(); int client_turn = 1, shutdown = 0; peer_status_t client_status = PEER_RETRY, server_status = PEER_RETRY; handshake_status_t status = HANDSHAKE_RETRY; unsigned char* tick = NULL; size_t tick_len = 0; SSL_SESSION* sess = NULL; const unsigned char *proto = NULL; /* API dictates unsigned int rather than size_t. */ unsigned int proto_len = 0; memset(&server_ctx_data, 0, sizeof(server_ctx_data)); memset(&server2_ctx_data, 0, sizeof(server2_ctx_data)); memset(&client_ctx_data, 0, sizeof(client_ctx_data)); configure_handshake_ctx(server_ctx, server2_ctx, client_ctx, test_ctx, &server_ctx_data, &server2_ctx_data, &client_ctx_data); server = SSL_new(server_ctx); client = SSL_new(client_ctx); OPENSSL_assert(server != NULL && client != NULL); configure_handshake_ssl(server, client, test_ctx); if (session_in != NULL) { /* In case we're testing resumption without tickets. */ OPENSSL_assert(SSL_CTX_add_session(server_ctx, session_in)); OPENSSL_assert(SSL_set_session(client, session_in)); } memset(&server_ex_data, 0, sizeof(server_ex_data)); memset(&client_ex_data, 0, sizeof(client_ex_data)); ret->result = SSL_TEST_INTERNAL_ERROR; client_to_server = BIO_new(BIO_s_mem()); server_to_client = BIO_new(BIO_s_mem()); OPENSSL_assert(client_to_server != NULL && server_to_client != NULL); /* Non-blocking bio. */ BIO_set_nbio(client_to_server, 1); BIO_set_nbio(server_to_client, 1); SSL_set_connect_state(client); SSL_set_accept_state(server); /* The bios are now owned by the SSL object. */ SSL_set_bio(client, server_to_client, client_to_server); OPENSSL_assert(BIO_up_ref(server_to_client) > 0); OPENSSL_assert(BIO_up_ref(client_to_server) > 0); SSL_set_bio(server, client_to_server, server_to_client); ex_data_idx = SSL_get_ex_new_index(0, "ex data", NULL, NULL, NULL); OPENSSL_assert(ex_data_idx >= 0); OPENSSL_assert(SSL_set_ex_data(server, ex_data_idx, &server_ex_data) == 1); OPENSSL_assert(SSL_set_ex_data(client, ex_data_idx, &client_ex_data) == 1); SSL_set_info_callback(server, &info_cb); SSL_set_info_callback(client, &info_cb); /* * Half-duplex handshake loop. * Client and server speak to each other synchronously in the same process. * We use non-blocking BIOs, so whenever one peer blocks for read, it * returns PEER_RETRY to indicate that it's the other peer's turn to write. * The handshake succeeds once both peers have succeeded. If one peer * errors out, we also let the other peer retry (and presumably fail). */ for(;;) { if (client_turn) { client_status = do_handshake_step(client, shutdown); status = handshake_status(client_status, server_status, 1 /* client went last */); } else { server_status = do_handshake_step(server, shutdown); status = handshake_status(server_status, client_status, 0 /* server went last */); } switch (status) { case HANDSHAKE_SUCCESS: if (shutdown) { ret->result = SSL_TEST_SUCCESS; goto err; } else { client_status = server_status = PEER_RETRY; shutdown = 1; client_turn = 1; break; } case CLIENT_ERROR: ret->result = SSL_TEST_CLIENT_FAIL; goto err; case SERVER_ERROR: ret->result = SSL_TEST_SERVER_FAIL; goto err; case INTERNAL_ERROR: ret->result = SSL_TEST_INTERNAL_ERROR; goto err; case HANDSHAKE_RETRY: /* Continue. */ client_turn ^= 1; break; } } err: ret->server_alert_sent = server_ex_data.alert_sent; ret->server_alert_received = client_ex_data.alert_received; ret->client_alert_sent = client_ex_data.alert_sent; ret->client_alert_received = server_ex_data.alert_received; ret->server_protocol = SSL_version(server); ret->client_protocol = SSL_version(client); ret->servername = server_ex_data.servername; if ((sess = SSL_get0_session(client)) != NULL) SSL_SESSION_get0_ticket(sess, &tick, &tick_len); if (tick == NULL || tick_len == 0) ret->session_ticket = SSL_TEST_SESSION_TICKET_NO; else ret->session_ticket = SSL_TEST_SESSION_TICKET_YES; ret->session_ticket_do_not_call = server_ex_data.session_ticket_do_not_call; SSL_get0_next_proto_negotiated(client, &proto, &proto_len); ret->client_npn_negotiated = dup_str(proto, proto_len); SSL_get0_next_proto_negotiated(server, &proto, &proto_len); ret->server_npn_negotiated = dup_str(proto, proto_len); SSL_get0_alpn_selected(client, &proto, &proto_len); ret->client_alpn_negotiated = dup_str(proto, proto_len); SSL_get0_alpn_selected(server, &proto, &proto_len); ret->server_alpn_negotiated = dup_str(proto, proto_len); ret->client_resumed = SSL_session_reused(client); ret->server_resumed = SSL_session_reused(server); if (session_out != NULL) *session_out = SSL_get1_session(client); ctx_data_free_data(&server_ctx_data); ctx_data_free_data(&server2_ctx_data); ctx_data_free_data(&client_ctx_data); SSL_free(server); SSL_free(client); return ret; }
int openconnect_open_https(struct openconnect_info *vpninfo) { method_const SSL_METHOD *ssl3_method; SSL *https_ssl; BIO *https_bio; int ssl_sock; int err; if (vpninfo->https_ssl) return 0; if (vpninfo->peer_cert) { X509_free(vpninfo->peer_cert); vpninfo->peer_cert = NULL; } ssl_sock = connect_https_socket(vpninfo); if (ssl_sock < 0) return ssl_sock; ssl3_method = TLSv1_client_method(); if (!vpninfo->https_ctx) { vpninfo->https_ctx = SSL_CTX_new(ssl3_method); /* Some servers (or their firewalls) really don't like seeing extensions. */ #ifdef SSL_OP_NO_TICKET SSL_CTX_set_options(vpninfo->https_ctx, SSL_OP_NO_TICKET); #endif if (vpninfo->cert) { err = load_certificate(vpninfo); if (err) { vpn_progress(vpninfo, PRG_ERR, _("Loading certificate failed. Aborting.\n")); SSL_CTX_free(vpninfo->https_ctx); vpninfo->https_ctx = NULL; close(ssl_sock); return err; } check_certificate_expiry(vpninfo); } /* We just want to do: SSL_CTX_set_purpose(vpninfo->https_ctx, X509_PURPOSE_ANY); ... but it doesn't work with OpenSSL < 0.9.8k because of problems with inheritance (fixed in v1.1.4.6 of crypto/x509/x509_vpm.c) so we have to play silly buggers instead. This trick doesn't work _either_ in < 0.9.7 but I don't know of _any_ workaround which will, and can't be bothered to find out either. */ #if OPENSSL_VERSION_NUMBER >= 0x00908000 SSL_CTX_set_cert_verify_callback(vpninfo->https_ctx, ssl_app_verify_callback, NULL); #endif SSL_CTX_set_default_verify_paths(vpninfo->https_ctx); #ifdef ANDROID_KEYSTORE if (vpninfo->cafile && !strncmp(vpninfo->cafile, "keystore:", 9)) { STACK_OF(X509_INFO) *stack; X509_STORE *store; X509_INFO *info; BIO *b = BIO_from_keystore(vpninfo, vpninfo->cafile); if (!b) { SSL_CTX_free(vpninfo->https_ctx); vpninfo->https_ctx = NULL; close(ssl_sock); return -EINVAL; } stack = PEM_X509_INFO_read_bio(b, NULL, NULL, NULL); BIO_free(b); if (!stack) { vpn_progress(vpninfo, PRG_ERR, _("Failed to read certs from CA file '%s'\n"), vpninfo->cafile); openconnect_report_ssl_errors(vpninfo); SSL_CTX_free(vpninfo->https_ctx); vpninfo->https_ctx = NULL; close(ssl_sock); return -ENOENT; } store = SSL_CTX_get_cert_store(vpninfo->https_ctx); while ((info = sk_X509_INFO_pop(stack))) { if (info->x509) X509_STORE_add_cert(store, info->x509); if (info->crl) X509_STORE_add_crl(store, info->crl); X509_INFO_free(info); } sk_X509_INFO_free(stack); } else #endif if (vpninfo->cafile) { if (!SSL_CTX_load_verify_locations(vpninfo->https_ctx, vpninfo->cafile, NULL)) { vpn_progress(vpninfo, PRG_ERR, _("Failed to open CA file '%s'\n"), vpninfo->cafile); openconnect_report_ssl_errors(vpninfo); SSL_CTX_free(vpninfo->https_ctx); vpninfo->https_ctx = NULL; close(ssl_sock); return -EINVAL; } } } https_ssl = SSL_new(vpninfo->https_ctx); workaround_openssl_certchain_bug(vpninfo, https_ssl); https_bio = BIO_new_socket(ssl_sock, BIO_NOCLOSE); BIO_set_nbio(https_bio, 1); SSL_set_bio(https_ssl, https_bio, https_bio); vpn_progress(vpninfo, PRG_INFO, _("SSL negotiation with %s\n"), vpninfo->hostname); while ((err = SSL_connect(https_ssl)) <= 0) { fd_set wr_set, rd_set; int maxfd = ssl_sock; FD_ZERO(&wr_set); FD_ZERO(&rd_set); err = SSL_get_error(https_ssl, err); if (err == SSL_ERROR_WANT_READ) FD_SET(ssl_sock, &rd_set); else if (err == SSL_ERROR_WANT_WRITE) FD_SET(ssl_sock, &wr_set); else { vpn_progress(vpninfo, PRG_ERR, _("SSL connection failure\n")); openconnect_report_ssl_errors(vpninfo); SSL_free(https_ssl); close(ssl_sock); return -EINVAL; } cmd_fd_set(vpninfo, &rd_set, &maxfd); select(maxfd + 1, &rd_set, &wr_set, NULL, NULL); if (is_cancel_pending(vpninfo, &rd_set)) { vpn_progress(vpninfo, PRG_ERR, _("SSL connection cancelled\n")); SSL_free(https_ssl); close(ssl_sock); return -EINVAL; } } if (verify_peer(vpninfo, https_ssl)) { SSL_free(https_ssl); close(ssl_sock); return -EINVAL; } vpninfo->ssl_fd = ssl_sock; vpninfo->https_ssl = https_ssl; /* Stash this now, because it might not be available later if the server has disconnected. */ vpninfo->peer_cert = SSL_get_peer_certificate(vpninfo->https_ssl); vpn_progress(vpninfo, PRG_INFO, _("Connected to HTTPS on %s\n"), vpninfo->hostname); return 0; }
static int context_connect(lua_State *T) { struct lem_ssl_context *c; const char *hostname; int port; BIO *bio; SSL *ssl; int ret; const char *msg; struct lem_ssl_stream *s; luaL_checktype(T, 1, LUA_TUSERDATA); c = lua_touserdata(T, 1); hostname = luaL_checkstring(T, 2); port = (int)luaL_optnumber(T, 3, -1); if (c->ctx == NULL) { lua_pushnil(T); lua_pushliteral(T, "closed"); return 2; } bio = BIO_new(BIO_s_connect()); if (bio == NULL) { lua_pushnil(T); lua_pushfstring(T, "error creating BIO: %s", ERR_reason_error_string(ERR_get_error())); return 2; } BIO_set_conn_hostname(bio, hostname); if (port > 0) BIO_set_conn_int_port(bio, (char *)&port); BIO_set_nbio(bio, 1); ssl = SSL_new(c->ctx); if (ssl == NULL) { lua_pushnil(T); lua_pushfstring(T, "error creating SSL connection: %s", ERR_reason_error_string(ERR_get_error())); return 2; } SSL_set_bio(ssl, bio, bio); ret = SSL_connect(ssl); switch (SSL_get_error(ssl, ret)) { case SSL_ERROR_NONE: lem_debug("SSL_ERROR_NONE"); s = stream_new(T, ssl, NULL, 0); return 1; case SSL_ERROR_ZERO_RETURN: lem_debug("SSL_ERROR_ZERO_RETURN"); msg = "connection closed unexpectedly"; break; case SSL_ERROR_WANT_READ: lem_debug("SSL_ERROR_WANT_READ"); lua_settop(T, 0); s = stream_new(T, ssl, connect_handler, EV_READ); s->T = T; ev_io_start(EV_G_ &s->w); return lua_yield(T, 1); case SSL_ERROR_WANT_WRITE: lem_debug("SSL_ERROR_WANT_WRITE"); case SSL_ERROR_WANT_CONNECT: lem_debug("SSL_ERROR_WANT_CONNECT"); lua_settop(T, 0); s = stream_new(T, ssl, connect_handler, EV_WRITE); s->T = T; ev_io_start(EV_G_ &s->w); return lua_yield(T, 1); case SSL_ERROR_SYSCALL: lem_debug("SSL_ERROR_SYSCALL"); { long e = ERR_get_error(); if (e) msg = ERR_reason_error_string(e); else if (ret == 0) msg = "connection closed unexpectedly"; else msg = strerror(errno); } break; case SSL_ERROR_SSL: lem_debug("SSL_ERROR_SSL"); msg = ERR_reason_error_string(ERR_get_error()); break; default: lem_debug("SSL_ERROR_* (default)"); msg = "unexpected error from SSL library"; } lua_pushnil(T); lua_pushfstring(T, "error establishing SSL connection: %s", msg); SSL_free(ssl); return 2; }
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; }
long BIO_set_nbio_shim(BIO *b, long enabled) { return BIO_set_nbio(b, enabled); }
int zc_socket_ssl(zcSocket *s, char *key_file, char *cert_file, zcSSLCertRequire certreq, zcSSLVer ver, char *cacerts_file, bool isclient) { char *errstr = NULL; int ret; //int err; //int sockstate; if (!isclient && (key_file == NULL || cert_file == NULL)) { ZCERROR("both key and cert files must be specified for server"); goto zc_socket_ssl_fail; } memset(s->server, '\0', sizeof(char) * X509_NAME_MAXLEN); memset(s->issuer, '\0', sizeof(char) * X509_NAME_MAXLEN); s->peer_cert = NULL; s->ssl = NULL; s->ctx = NULL; //s->Socket = NULL; /* Init OpenSSL */ SSL_load_error_strings(); SSL_library_init(); OpenSSL_add_all_algorithms(); (void) ERR_get_state(); ERR_clear_error(); if ((key_file && !cert_file) || (!key_file && cert_file)) { errstr = "Both the key & certificate files must be specified"; goto zc_socket_ssl_fail; } //SSL_load_error_strings(); //SSLeay_add_ssl_algorithms(); if (s->sslver == ZC_SSL_VER_TLS1) s->ctx = SSL_CTX_new(TLSv1_method()); /* Set up context */ else if (ver == ZC_SSL_VER_SSL3) s->ctx = SSL_CTX_new(SSLv3_method()); /* Set up context */ else if (ver == ZC_SSL_VER_SSL2) s->ctx = SSL_CTX_new(SSLv2_method()); /* Set up context */ else if (ver == ZC_SSL_VER_SSL23) s->ctx = SSL_CTX_new(SSLv23_method()); /* Set up context */ //s->ctx = SSL_CTX_new(SSLv23_method()); /* Set up context */ if (s->ctx == NULL) { errstr = "SSL_CTX_new error"; goto zc_socket_ssl_fail; } if (certreq != ZC_SSL_CERT_NONE) { if (cacerts_file == NULL) { errstr = "No root certificates specified for verification of other-side certificates."; goto zc_socket_ssl_fail; } else { ret = SSL_CTX_load_verify_locations(s->ctx, cacerts_file, NULL); if (ret != 1) { //_setSSLError(NULL, 0, __FILE__, __LINE__); ZCERROR("load verify locations error: %d", ret); goto zc_socket_ssl_fail; } } } if (key_file) { ret = SSL_CTX_use_PrivateKey_file(s->ctx, key_file, SSL_FILETYPE_PEM); if (ret != 1) { //_setSSLError(NULL, ret, __FILE__, __LINE__); ZCERROR("use privatekey file error:%d", ret); goto zc_socket_ssl_fail; } ret = SSL_CTX_use_certificate_chain_file(s->ctx, cert_file); if (ret != 1) { /* fprintf(stderr, "ret is %d, errcode is %lu, %lu, with file \"%s\"\n", ret, ERR_peek_error(), ERR_peek_last_error(), cert_file); */ if (ERR_peek_last_error() != 0) { //_setSSLError(NULL, ret, __FILE__, __LINE__); ZCERROR("peek last error failed:%d", ret); goto zc_socket_ssl_fail; } } } /* ssl compatibility */ SSL_CTX_set_options(s->ctx, SSL_OP_ALL); int verification_mode = SSL_VERIFY_NONE; if (certreq == ZC_SSL_CERT_OPTIONAL) verification_mode = SSL_VERIFY_PEER; else if (certreq == ZC_SSL_CERT_REQUIRED) verification_mode = (SSL_VERIFY_PEER | SSL_VERIFY_FAIL_IF_NO_PEER_CERT); SSL_CTX_set_verify(s->ctx, verification_mode, NULL); /* set verify lvl */ s->ssl = SSL_new(s->ctx); /* New ssl struct */ SSL_set_fd(s->ssl, s->fd); /* Set the socket for SSL */ #ifdef SSL_MODE_AUTO_RETRY SSL_set_mode(s->ssl, SSL_MODE_AUTO_RETRY); #endif /* If the socket is in non-blocking mode or timeout mode, set the BIO * to non-blocking mode (blocking is the default) */ if (!s->blocked) { /* Set both the read and write BIO's to non-blocking mode */ BIO_set_nbio(SSL_get_rbio(s->ssl), 1); BIO_set_nbio(SSL_get_wbio(s->ssl), 1); } if (isclient) { SSL_set_connect_state(s->ssl); }else{ SSL_set_accept_state(s->ssl); } if (isclient) { ret = zc_socket_ssl_handshake(s); if (ret != ZC_OK) { ZCERROR("ssl handshake error: %d", ret); goto zc_socket_ssl_fail; } } return ZC_OK; zc_socket_ssl_fail: if (errstr) { ZCERROR("ssl error: %s\n", errstr); } return -1; }
LWS_VISIBLE int lws_server_socket_service_ssl(struct lws *wsi, lws_sockfd_type accept_fd) { struct lws_context *context = wsi->context; struct lws_context_per_thread *pt = &context->pt[(int)wsi->tsi]; int n, m; #ifndef USE_WOLFSSL BIO *bio; #endif if (!LWS_SSL_ENABLED(context)) return 0; lwsl_err("%s: mode %d, state %d\n", __func__, wsi->mode, wsi->state); switch (wsi->mode) { case LWSCM_SSL_INIT: if (!wsi) return 0; wsi->ssl = SSL_new(context->ssl_ctx); if (wsi->ssl == NULL) { lwsl_err("SSL_new failed: %s\n", ERR_error_string(SSL_get_error(wsi->ssl, 0), NULL)); lws_decode_ssl_error(); compatible_close(accept_fd); goto fail; } SSL_set_ex_data(wsi->ssl, openssl_websocket_private_data_index, context); 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 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 /* * 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 */ wsi->mode = LWSCM_SSL_ACK_PENDING; if (insert_wsi_socket_into_fds(context, wsi)) goto fail; lws_set_timeout(wsi, PENDING_TIMEOUT_SSL_ACCEPT, AWAITING_TIMEOUT); lwsl_info("inserted SSL accept into fds, trying SSL_accept\n"); /* fallthru */ case LWSCM_SSL_ACK_PENDING: if (lws_change_pollfd(wsi, LWS_POLLOUT, 0)) goto fail; lws_libev_io(wsi, LWS_EV_STOP | LWS_EV_WRITE); lws_latency_pre(context, wsi); n = recv(wsi->sock, (char *)pt->serv_buf, LWS_MAX_SOCKET_IO_BUF, 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 (context->allow_non_ssl_on_ssl_port) { 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; 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 */ n = SSL_accept(wsi->ssl); lws_latency(context, wsi, "SSL_accept LWSCM_SSL_ACK_PENDING\n", n, n == 1); if (n == 1) goto accepted; m = SSL_get_error(wsi->ssl, n); lwsl_debug("SSL_accept failed %d / %s\n", m, ERR_error_string(m, NULL)); go_again: if (m == SSL_ERROR_WANT_READ) { if (lws_change_pollfd(wsi, 0, LWS_POLLIN)) goto fail; lws_libev_io(wsi, LWS_EV_START | LWS_EV_READ); lwsl_info("SSL_ERROR_WANT_READ\n"); break; } if (m == SSL_ERROR_WANT_WRITE) { if (lws_change_pollfd(wsi, 0, LWS_POLLOUT)) goto fail; lws_libev_io(wsi, LWS_EV_START | LWS_EV_WRITE); break; } lwsl_debug("SSL_accept failed skt %u: %s\n", wsi->sock, ERR_error_string(m, NULL)); goto fail; accepted: /* OK, we are accepted... give him some time to negotiate */ lws_set_timeout(wsi, PENDING_TIMEOUT_ESTABLISH_WITH_SERVER, AWAITING_TIMEOUT); wsi->mode = LWSCM_HTTP_SERVING; lws_http2_configure_if_upgraded(wsi); lwsl_debug("accepted new SSL conn\n"); break; } return 0; fail: return 1; }
int zc_socket_ssl_recv(zcSocket *s, char *buf, int len) { int count = 0; int sockstate; int err; int nonblocking; /* just in case the blocking state of the socket has been changed */ nonblocking = !s->blocked; //(self->Socket->sock_timeout >= 0.0); BIO_set_nbio(SSL_get_rbio(s->ssl), nonblocking); BIO_set_nbio(SSL_get_wbio(s->ssl), nonblocking); /* first check if there are bytes ready to be read */ count = SSL_pending(s->ssl); if (!count) { sockstate = zc_socket_select(s, 0); if (sockstate == ZC_SSL_SOCKET_HAS_TIMED_OUT) { ZCWARN("The read operation timed out"); return ZC_ERR; } else if (sockstate == ZC_SSL_SOCKET_TOO_LARGE_FOR_SELECT) { ZCWARN("Underlying socket too large for select()."); return ZC_ERR; } else if (sockstate == ZC_SSL_SOCKET_HAS_BEEN_CLOSED) { if (SSL_get_shutdown(s->ssl) != SSL_RECEIVED_SHUTDOWN) { ZCWARN("Socket closed without SSL shutdown handshake"); return ZC_ERR; } else { /* should contain a zero-length string */ //_PyString_Resize(&buf, 0); //return buf; return 0; } } } do { err = 0; count = SSL_read(s->ssl, buf, len); err = SSL_get_error(s->ssl, count); if (err == SSL_ERROR_WANT_READ) { sockstate = zc_socket_select(s, 0); } else if (err == SSL_ERROR_WANT_WRITE) { sockstate = zc_socket_select(s, 1); } else if ((err == SSL_ERROR_ZERO_RETURN) && (SSL_get_shutdown(s->ssl) == SSL_RECEIVED_SHUTDOWN)) { //_PyString_Resize(&buf, 0); return 0; } else { sockstate = ZC_SSL_SOCKET_OPERATION_OK; } if (sockstate == ZC_SSL_SOCKET_HAS_TIMED_OUT) { ZCWARN("The read operation timed out"); return ZC_ERR; } else if (sockstate == ZC_SSL_SOCKET_IS_NONBLOCKING) { break; } } while (err == SSL_ERROR_WANT_READ || err == SSL_ERROR_WANT_WRITE); if (count <= 0) { ZCERROR("count error: %d", count); return ZC_ERR; } return count; }
LWS_VISIBLE int lws_server_socket_service_ssl(struct libwebsocket_context *context, struct libwebsocket **pwsi, struct libwebsocket *new_wsi, int accept_fd, struct libwebsocket_pollfd *pollfd) { int n, m; struct libwebsocket *wsi = *pwsi; #ifndef USE_CYASSL BIO *bio; #endif if (!LWS_SSL_ENABLED(context)) return 0; switch (wsi->mode) { case LWS_CONNMODE_SERVER_LISTENER: if (!new_wsi) { lwsl_err("no new_wsi\n"); return 0; } new_wsi->ssl = SSL_new(context->ssl_ctx); if (new_wsi->ssl == NULL) { lwsl_err("SSL_new failed: %s\n", ERR_error_string(SSL_get_error( new_wsi->ssl, 0), NULL)); libwebsockets_decode_ssl_error(); lws_free(new_wsi); compatible_close(accept_fd); break; } SSL_set_ex_data(new_wsi->ssl, openssl_websocket_private_data_index, context); SSL_set_fd(new_wsi->ssl, accept_fd); #ifdef USE_CYASSL CyaSSL_set_using_nonblock(new_wsi->ssl, 1); #else SSL_set_mode(new_wsi->ssl, SSL_MODE_ACCEPT_MOVING_WRITE_BUFFER); bio = SSL_get_rbio(new_wsi->ssl); if (bio) BIO_set_nbio(bio, 1); /* nonblocking */ else lwsl_notice("NULL rbio\n"); bio = SSL_get_wbio(new_wsi->ssl); if (bio) BIO_set_nbio(bio, 1); /* nonblocking */ else lwsl_notice("NULL rbio\n"); #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 */ *pwsi = new_wsi; wsi = *pwsi; wsi->mode = LWS_CONNMODE_SSL_ACK_PENDING; insert_wsi_socket_into_fds(context, wsi); libwebsocket_set_timeout(wsi, PENDING_TIMEOUT_SSL_ACCEPT, AWAITING_TIMEOUT); lwsl_info("inserted SSL accept into fds, trying SSL_accept\n"); /* fallthru */ case LWS_CONNMODE_SSL_ACK_PENDING: if (lws_change_pollfd(wsi, LWS_POLLOUT, 0)) goto fail; lws_libev_io(context, wsi, LWS_EV_STOP | LWS_EV_WRITE); lws_latency_pre(context, wsi); n = recv(wsi->sock, context->service_buffer, sizeof(context->service_buffer), 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 (context->allow_non_ssl_on_ssl_port && n >= 1 && context->service_buffer[0] >= ' ') { /* * TLS content-type for Handshake is 0x16 * TLS content-type for ChangeCipherSpec Record is 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; goto accepted; } /* normal SSL connection processing path */ n = SSL_accept(wsi->ssl); lws_latency(context, wsi, "SSL_accept LWS_CONNMODE_SSL_ACK_PENDING\n", n, n == 1); if (n == 1) goto accepted; m = SSL_get_error(wsi->ssl, n); lwsl_debug("SSL_accept failed %d / %s\n", m, ERR_error_string(m, NULL)); if (m == SSL_ERROR_WANT_READ) { if (lws_change_pollfd(wsi, 0, LWS_POLLIN)) goto fail; lws_libev_io(context, wsi, LWS_EV_START | LWS_EV_READ); lwsl_info("SSL_ERROR_WANT_READ\n"); break; } if (m == SSL_ERROR_WANT_WRITE) { if (lws_change_pollfd(wsi, 0, LWS_POLLOUT)) goto fail; lws_libev_io(context, wsi, LWS_EV_START | LWS_EV_WRITE); break; } lwsl_debug("SSL_accept failed skt %u: %s\n", pollfd->fd, ERR_error_string(m, NULL)); goto fail; accepted: /* OK, we are accepted... give him some time to negotiate */ libwebsocket_set_timeout(wsi, PENDING_TIMEOUT_ESTABLISH_WITH_SERVER, AWAITING_TIMEOUT); wsi->mode = LWS_CONNMODE_HTTP_SERVING; lws_http2_configure_if_upgraded(wsi); lwsl_debug("accepted new SSL conn\n"); break; } return 0; fail: return 1; }
int start_dtls_handshake(struct openconnect_info *vpninfo, int dtls_fd) { STACK_OF(SSL_CIPHER) *ciphers; method_const SSL_METHOD *dtls_method; SSL_SESSION *dtls_session; SSL *dtls_ssl; BIO *dtls_bio; int dtlsver = DTLS1_BAD_VER; const char *cipher = vpninfo->dtls_cipher; #ifdef HAVE_DTLS12 if (!strcmp(cipher, "OC-DTLS1_2-AES128-GCM")) { dtlsver = DTLS1_2_VERSION; cipher = "AES128-GCM-SHA256"; } else if (!strcmp(cipher, "OC-DTLS1_2-AES256-GCM")) { dtlsver = DTLS1_2_VERSION; cipher = "AES256-GCM-SHA384"; #ifndef OPENSSL_NO_PSK } else if (!strcmp(cipher, "PSK-NEGOTIATE")) { dtlsver = 0; /* Let it negotiate */ #endif } #endif if (!vpninfo->dtls_ctx) { #ifdef HAVE_DTLS12 dtls_method = DTLS_client_method(); #endif #if OPENSSL_VERSION_NUMBER < 0x10100000L || defined(LIBRESSL_VERSION_NUMBER) if (dtlsver == DTLS1_BAD_VER) dtls_method = DTLSv1_client_method(); #ifdef HAVE_DTLS12 else if (dtlsver == DTLS1_2_VERSION) dtls_method = DTLSv1_2_client_method(); #endif #endif vpninfo->dtls_ctx = SSL_CTX_new(dtls_method); if (!vpninfo->dtls_ctx) { vpn_progress(vpninfo, PRG_ERR, _("Initialise DTLSv1 CTX failed\n")); openconnect_report_ssl_errors(vpninfo); vpninfo->dtls_attempt_period = 0; return -EINVAL; } if (dtlsver) { #if OPENSSL_VERSION_NUMBER < 0x10100000L || defined(LIBRESSL_VERSION_NUMBER) if (dtlsver == DTLS1_BAD_VER) SSL_CTX_set_options(vpninfo->dtls_ctx, SSL_OP_CISCO_ANYCONNECT); #else if (!SSL_CTX_set_min_proto_version(vpninfo->dtls_ctx, dtlsver) || !SSL_CTX_set_max_proto_version(vpninfo->dtls_ctx, dtlsver)) { vpn_progress(vpninfo, PRG_ERR, _("Set DTLS CTX version failed\n")); openconnect_report_ssl_errors(vpninfo); SSL_CTX_free(vpninfo->dtls_ctx); vpninfo->dtls_ctx = NULL; vpninfo->dtls_attempt_period = 0; return -EINVAL; } #endif #if defined (HAVE_DTLS12) && !defined(OPENSSL_NO_PSK) } else { SSL_CTX_set_psk_client_callback(vpninfo->dtls_ctx, psk_callback); /* For PSK we override the DTLS master secret with one derived * from the HTTPS session. */ if (!SSL_export_keying_material(vpninfo->https_ssl, vpninfo->dtls_secret, PSK_KEY_SIZE, PSK_LABEL, PSK_LABEL_SIZE, NULL, 0, 0)) { vpn_progress(vpninfo, PRG_ERR, _("Failed to generate DTLS key\n")); openconnect_report_ssl_errors(vpninfo); SSL_CTX_free(vpninfo->dtls_ctx); vpninfo->dtls_ctx = NULL; vpninfo->dtls_attempt_period = 0; return -EINVAL; } SSL_CTX_add_client_custom_ext(vpninfo->dtls_ctx, DTLS_APP_ID_EXT, pskident_add, pskident_free, vpninfo, pskident_parse, vpninfo); /* For SSL_CTX_set_cipher_list() */ cipher = "PSK"; #endif } /* If we don't readahead, then we do short reads and throw away the tail of data packets. */ SSL_CTX_set_read_ahead(vpninfo->dtls_ctx, 1); if (!SSL_CTX_set_cipher_list(vpninfo->dtls_ctx, cipher)) { vpn_progress(vpninfo, PRG_ERR, _("Set DTLS cipher list failed\n")); SSL_CTX_free(vpninfo->dtls_ctx); vpninfo->dtls_ctx = NULL; vpninfo->dtls_attempt_period = 0; return -EINVAL; } } dtls_ssl = SSL_new(vpninfo->dtls_ctx); SSL_set_connect_state(dtls_ssl); SSL_set_app_data(dtls_ssl, vpninfo); if (dtlsver) { ciphers = SSL_get_ciphers(dtls_ssl); if (dtlsver != 0 && sk_SSL_CIPHER_num(ciphers) != 1) { vpn_progress(vpninfo, PRG_ERR, _("Not precisely one DTLS cipher\n")); SSL_CTX_free(vpninfo->dtls_ctx); SSL_free(dtls_ssl); vpninfo->dtls_ctx = NULL; vpninfo->dtls_attempt_period = 0; return -EINVAL; } /* We're going to "resume" a session which never existed. Fake it... */ dtls_session = generate_dtls_session(vpninfo, dtlsver, sk_SSL_CIPHER_value(ciphers, 0)); if (!dtls_session) { SSL_CTX_free(vpninfo->dtls_ctx); SSL_free(dtls_ssl); vpninfo->dtls_ctx = NULL; vpninfo->dtls_attempt_period = 0; return -EINVAL; } /* Add the generated session to the SSL */ if (!SSL_set_session(dtls_ssl, dtls_session)) { vpn_progress(vpninfo, PRG_ERR, _("SSL_set_session() failed with old protocol version 0x%x\n" "Are you using a version of OpenSSL older than 0.9.8m?\n" "See http://rt.openssl.org/Ticket/Display.html?id=1751\n" "Use the --no-dtls command line option to avoid this message\n"), DTLS1_BAD_VER); SSL_CTX_free(vpninfo->dtls_ctx); SSL_free(dtls_ssl); vpninfo->dtls_ctx = NULL; vpninfo->dtls_attempt_period = 0; SSL_SESSION_free(dtls_session); return -EINVAL; } /* We don't need our own refcount on it any more */ SSL_SESSION_free(dtls_session); } dtls_bio = BIO_new_socket(dtls_fd, BIO_NOCLOSE); /* Set non-blocking */ BIO_set_nbio(dtls_bio, 1); SSL_set_bio(dtls_ssl, dtls_bio, dtls_bio); vpninfo->dtls_ssl = dtls_ssl; return 0; }
void *netConnectHttpsThread(void *threadParam) /* use a thread to run socket back to user */ { /* child */ struct netConnectHttpsParams *params = threadParam; pthread_detach(params->thread); // this thread will never join back with it's progenitor int fd=0; char hostnameProto[256]; BIO *sbio; SSL_CTX *ctx; SSL *ssl; openSslInit(); ctx = SSL_CTX_new(SSLv23_client_method()); fd_set readfds; fd_set writefds; int err; struct timeval tv; /* TODO checking certificates char *certFile = NULL; char *certPath = NULL; if (certFile || certPath) { SSL_CTX_load_verify_locations(ctx,certFile,certPath); #if (OPENSSL_VERSION_NUMBER < 0x0090600fL) SSL_CTX_set_verify_depth(ctx,1); #endif } // verify paths and mode. */ sbio = BIO_new_ssl_connect(ctx); BIO_get_ssl(sbio, &ssl); if(!ssl) { xerr("Can't locate SSL pointer"); goto cleanup; } /* Don't want any retries since we are non-blocking bio now */ //SSL_set_mode(ssl, SSL_MODE_AUTO_RETRY); safef(hostnameProto,sizeof(hostnameProto),"%s:%d",params->hostName,params->port); BIO_set_conn_hostname(sbio, hostnameProto); BIO_set_nbio(sbio, 1); /* non-blocking mode */ while (1) { if (BIO_do_connect(sbio) == 1) { break; /* Connected */ } if (! BIO_should_retry(sbio)) { xerr("BIO_do_connect() failed"); char s[256]; safef(s, sizeof s, "SSL error: %s", ERR_reason_error_string(ERR_get_error())); xerr(s); goto cleanup; } fd = BIO_get_fd(sbio, NULL); if (fd == -1) { xerr("unable to get BIO descriptor"); goto cleanup; } FD_ZERO(&readfds); FD_ZERO(&writefds); if (BIO_should_read(sbio)) { FD_SET(fd, &readfds); } else if (BIO_should_write(sbio)) { FD_SET(fd, &writefds); } else { /* BIO_should_io_special() */ FD_SET(fd, &readfds); FD_SET(fd, &writefds); } tv.tv_sec = 10; // timeout tv.tv_usec = 0; err = select(fd + 1, &readfds, &writefds, NULL, &tv); if (err < 0) { xerr("select() error"); goto cleanup; } if (err == 0) { char s[256]; safef(s, sizeof s, "connection timeout to %s", params->hostName); xerr(s); goto cleanup; } } /* TODO checking certificates if (certFile || certPath) if (!check_cert(ssl, host)) return -1; */ /* we need to wait on both the user's socket and the BIO SSL socket * to see if we need to ferry data from one to the other */ char sbuf[32768]; // socket buffer sv[1] to user char bbuf[32768]; // bio buffer int srd = 0; int swt = 0; int brd = 0; int bwt = 0; while (1) { // Do NOT move this outside the while loop. /* Get underlying file descriptor, needed for select call */ fd = BIO_get_fd(sbio, NULL); if (fd == -1) { xerr("BIO doesn't seem to be initialized in https, unable to get descriptor."); goto cleanup; } FD_ZERO(&readfds); FD_ZERO(&writefds); if (brd == 0) FD_SET(fd, &readfds); if (swt < srd) FD_SET(fd, &writefds); if (srd == 0) FD_SET(params->sv[1], &readfds); tv.tv_sec = 10; // timeout tv.tv_usec = 0; err = select(max(fd,params->sv[1]) + 1, &readfds, &writefds, NULL, &tv); /* Evaluate select() return code */ if (err < 0) { xerr("error during select()"); goto cleanup; } else if (err == 0) { /* Timed out - just quit */ xerr("https timeout expired"); goto cleanup; } else { if (FD_ISSET(params->sv[1], &readfds)) { swt = 0; srd = read(params->sv[1], sbuf, 32768); if (srd == -1) { if (errno != 104) // udcCache often closes causing "Connection reset by peer" xerrno("error reading https socket"); goto cleanup; } if (srd == 0) break; // user closed socket, we are done } if (FD_ISSET(fd, &writefds)) { int swtx = BIO_write(sbio, sbuf+swt, srd-swt); if (swtx <= 0) { if (!BIO_should_write(sbio)) { ERR_print_errors_fp(stderr); xerr("Error writing SSL connection"); goto cleanup; } } else { swt += swtx; if (swt >= srd) { swt = 0; srd = 0; } } } if (FD_ISSET(fd, &readfds)) { bwt = 0; brd = BIO_read(sbio, bbuf, 32768); if (brd <= 0) { if (BIO_should_read(sbio)) { brd = 0; continue; } else { if (brd == 0) break; ERR_print_errors_fp(stderr); xerr("Error reading SSL connection"); goto cleanup; } } // write the https data received immediately back on socket to user, and it's ok if it blocks. while(bwt < brd) { int bwtx = write(params->sv[1], bbuf+bwt, brd-bwt); if (bwtx == -1) { if ((errno != 104) // udcCache often closes causing "Connection reset by peer" && (errno != 32)) // udcCache often closes causing "Broken pipe" xerrno("error writing https data back to user socket"); goto cleanup; } bwt += bwtx; } brd = 0; bwt = 0; } } } cleanup: BIO_free_all(sbio); close(params->sv[1]); /* we are done with it */ return NULL; }
/* * Establishes the connection to the Duo server. On successful return, * req->cbio is connected and ready to use. * Return HTTPS_OK on success, error code on failure. */ static HTTPScode _establish_connection(struct https_request * const req, const char * const api_host, const char * const api_port) { #ifndef HAVE_GETADDRINFO /* Systems that don't have getaddrinfo can use the BIO wrappers, but only get IPv4 support. */ int n; if ((req->cbio = BIO_new(BIO_s_connect())) == NULL) { ctx->errstr = _SSL_strerror(); return HTTPS_ERR_LIB; } BIO_set_conn_hostname(req->cbio, api_host); BIO_set_conn_port(req->cbio, api_port); BIO_set_nbio(req->cbio, 1); while (BIO_do_connect(req->cbio) <= 0) { if ((n = _BIO_wait(req->cbio, 10000)) != 1) { ctx->errstr = n ? _SSL_strerror() : "Connection timed out"; return (n ? HTTPS_ERR_SYSTEM : HTTPS_ERR_SERVER); } } return HTTPS_OK; #else /* HAVE_GETADDRINFO */ /* IPv6 Support * BIO wrapped io does not support IPv6 addressing. To work around, * resolve the address and connect the socket manually. Then pass * the connected socket to the BIO wrapper with BIO_new_socket. */ int connected_socket = -1; int socket_error = 0; /* Address Lookup */ struct addrinfo *res = NULL; struct addrinfo *cur_res = NULL; struct addrinfo hints; int error; memset(&hints, 0, sizeof(hints)); hints.ai_family = PF_UNSPEC; hints.ai_socktype = SOCK_STREAM; error = getaddrinfo(api_host, api_port, &hints, &res); if (error) { ctx->errstr = gai_strerror(error); return HTTPS_ERR_SYSTEM; } /* Connect */ for (cur_res = res; cur_res; cur_res = cur_res->ai_next) { int connretries = 3; while (connected_socket == -1 && connretries--) { int sock_flags; connected_socket = socket(cur_res->ai_family, cur_res->ai_socktype, cur_res->ai_protocol); if (connected_socket == -1) { continue; } sock_flags = fcntl(connected_socket, F_GETFL, 0); fcntl(connected_socket, F_SETFL, sock_flags|O_NONBLOCK); if (connect(connected_socket, cur_res->ai_addr, cur_res->ai_addrlen) != 0 && errno != EINPROGRESS) { close(connected_socket); connected_socket = -1; break; } socket_error = _fd_wait(connected_socket, 10000); if (socket_error != 1) { close(connected_socket); connected_socket = -1; continue; } /* Connected! */ break; } } cur_res = NULL; freeaddrinfo(res); res = NULL; if (connected_socket == -1) { ctx->errstr = "Failed to connect"; return socket_error ? HTTPS_ERR_SYSTEM : HTTPS_ERR_SERVER; } if ((req->cbio = BIO_new_socket(connected_socket, BIO_CLOSE)) == NULL) { ctx->errstr = _SSL_strerror(); return (HTTPS_ERR_LIB); } BIO_set_conn_hostname(req->cbio, api_host); BIO_set_conn_port(req->cbio, api_port); BIO_set_nbio(req->cbio, 1); return HTTPS_OK; #endif /* HAVE_GETADDRINFO */ }
int lws_ssl_client_bio_create(struct lws *wsi) { #if defined(LWS_USE_POLARSSL) return 0; #else #if defined(LWS_USE_MBEDTLS) #else struct lws_context *context = wsi->context; const char *hostname = lws_hdr_simple_ptr(wsi, _WSI_TOKEN_CLIENT_HOST); X509_VERIFY_PARAM *param; (void)hostname; (void)param; wsi->ssl = SSL_new(wsi->vhost->ssl_client_ctx); #if defined LWS_HAVE_X509_VERIFY_PARAM_set1_host if (!(wsi->use_ssl & LCCSCF_SKIP_SERVER_CERT_HOSTNAME_CHECK)) { param = SSL_get0_param(wsi->ssl); /* Enable automatic hostname checks */ X509_VERIFY_PARAM_set_hostflags(param, X509_CHECK_FLAG_NO_PARTIAL_WILDCARDS); X509_VERIFY_PARAM_set1_host(param, hostname, 0); /* Configure a non-zero callback if desired */ SSL_set_verify(wsi->ssl, SSL_VERIFY_PEER, 0); } #endif #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; #endif #endif }
int lws_client_socket_service(struct lws_context *context, struct lws *wsi, struct lws_pollfd *pollfd) { struct lws_context_per_thread *pt = &context->pt[(int)wsi->tsi]; char *p = (char *)&pt->serv_buf[0]; char *sb = p; unsigned char c; int n, len; switch (wsi->mode) { case LWSCM_WSCL_WAITING_CONNECT: /* * we are under PENDING_TIMEOUT_SENT_CLIENT_HANDSHAKE * timeout protection set in client-handshake.c */ if (!lws_client_connect_2(wsi)) { /* closed */ lwsl_client("closed\n"); return -1; } /* either still pending connection, or changed mode */ return 0; case LWSCM_WSCL_WAITING_PROXY_REPLY: /* handle proxy hung up on us */ if (pollfd->revents & LWS_POLLHUP) { lwsl_warn("Proxy connection %p (fd=%d) dead\n", (void *)wsi, pollfd->fd); lws_close_free_wsi(wsi, LWS_CLOSE_STATUS_NOSTATUS); return 0; } n = recv(wsi->sock, sb, LWS_MAX_SOCKET_IO_BUF, 0); if (n < 0) { if (LWS_ERRNO == LWS_EAGAIN) { lwsl_debug("Proxy read returned EAGAIN... retrying\n"); return 0; } lws_close_free_wsi(wsi, LWS_CLOSE_STATUS_NOSTATUS); lwsl_err("ERROR reading from proxy socket\n"); return 0; } pt->serv_buf[13] = '\0'; if (strcmp(sb, "HTTP/1.0 200 ") && strcmp(sb, "HTTP/1.1 200 ")) { lws_close_free_wsi(wsi, LWS_CLOSE_STATUS_NOSTATUS); lwsl_err("ERROR proxy: %s\n", sb); return 0; } /* clear his proxy connection timeout */ lws_set_timeout(wsi, NO_PENDING_TIMEOUT, 0); /* fallthru */ case LWSCM_WSCL_ISSUE_HANDSHAKE: /* * we are under PENDING_TIMEOUT_SENT_CLIENT_HANDSHAKE * timeout protection set in client-handshake.c * * take care of our lws_callback_on_writable * happening at a time when there's no real connection yet */ if (lws_change_pollfd(wsi, LWS_POLLOUT, 0)) return -1; lws_libev_io(wsi, LWS_EV_STOP | LWS_EV_WRITE); #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(context->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) { 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; } } } else wsi->ssl = NULL; /* fallthru */ 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 */ } else wsi->ssl = NULL; #endif wsi->mode = LWSCM_WSCL_ISSUE_HANDSHAKE2; lws_set_timeout(wsi, PENDING_TIMEOUT_AWAITING_CLIENT_HS_SEND, AWAITING_TIMEOUT); /* fallthru */ case LWSCM_WSCL_ISSUE_HANDSHAKE2: p = lws_generate_client_handshake(wsi, p); if (p == NULL) { lwsl_err("Failed to generate handshake for client\n"); lws_close_free_wsi(wsi, LWS_CLOSE_STATUS_NOSTATUS); return 0; } /* send our request to the server */ lws_latency_pre(context, wsi); n = lws_ssl_capable_write(wsi, (unsigned char *)sb, p - sb); lws_latency(context, wsi, "send lws_issue_raw", n, n == p - sb); switch (n) { case LWS_SSL_CAPABLE_ERROR: lwsl_debug("ERROR writing to client socket\n"); lws_close_free_wsi(wsi, LWS_CLOSE_STATUS_NOSTATUS); return 0; case LWS_SSL_CAPABLE_MORE_SERVICE: lws_callback_on_writable(wsi); break; } wsi->u.hdr.parser_state = WSI_TOKEN_NAME_PART; wsi->u.hdr.lextable_pos = 0; wsi->mode = LWSCM_WSCL_WAITING_SERVER_REPLY; lws_set_timeout(wsi, PENDING_TIMEOUT_AWAITING_SERVER_RESPONSE, AWAITING_TIMEOUT); break; case LWSCM_WSCL_WAITING_SERVER_REPLY: /* handle server hung up on us */ if (pollfd->revents & LWS_POLLHUP) { lwsl_debug("Server connection %p (fd=%d) dead\n", (void *)wsi, pollfd->fd); goto bail3; } if (!(pollfd->revents & LWS_POLLIN)) break; /* interpret the server response */ /* * HTTP/1.1 101 Switching Protocols * Upgrade: websocket * Connection: Upgrade * Sec-WebSocket-Accept: me89jWimTRKTWwrS3aRrL53YZSo= * Sec-WebSocket-Nonce: AQIDBAUGBwgJCgsMDQ4PEC== * Sec-WebSocket-Protocol: chat */ /* * we have to take some care here to only take from the * socket bytewise. The browser may (and has been seen to * in the case that onopen() performs websocket traffic) * coalesce both handshake response and websocket traffic * in one packet, since at that point the connection is * definitively ready from browser pov. */ len = 1; while (wsi->u.hdr.parser_state != WSI_PARSING_COMPLETE && len > 0) { n = lws_ssl_capable_read(wsi, &c, 1); lws_latency(context, wsi, "send lws_issue_raw", n, n == 1); switch (n) { case 0: case LWS_SSL_CAPABLE_ERROR: goto bail3; case LWS_SSL_CAPABLE_MORE_SERVICE: return 0; } if (lws_parse(wsi, c)) { lwsl_warn("problems parsing header\n"); goto bail3; } } /* * hs may also be coming in multiple packets, there is a 5-sec * libwebsocket timeout still active here too, so if parsing did * not complete just wait for next packet coming in this state */ if (wsi->u.hdr.parser_state != WSI_PARSING_COMPLETE) break; /* * otherwise deal with the handshake. If there's any * packet traffic already arrived we'll trigger poll() again * right away and deal with it that way */ return lws_client_interpret_server_handshake(wsi); bail3: lwsl_info("closing conn at LWS_CONNMODE...SERVER_REPLY\n"); lws_close_free_wsi(wsi, LWS_CLOSE_STATUS_NOSTATUS); return -1; case LWSCM_WSCL_WAITING_EXTENSION_CONNECT: lwsl_ext("LWSCM_WSCL_WAITING_EXTENSION_CONNECT\n"); break; case LWSCM_WSCL_PENDING_CANDIDATE_CHILD: lwsl_ext("LWSCM_WSCL_PENDING_CANDIDATE_CHILD\n"); break; default: break; } return 0; }
BOOL tcp_connect(rdpTcp* tcp, const char* hostname, int port, int timeout) { int status; UINT32 option_value; socklen_t option_len; if (!hostname) return FALSE; if (hostname[0] == '/') { tcp->sockfd = freerdp_uds_connect(hostname); if (tcp->sockfd < 0) return FALSE; tcp->socketBio = BIO_new_fd(tcp->sockfd, 1); if (!tcp->socketBio) return FALSE; } else { fd_set cfds; struct timeval tv; tcp->socketBio = BIO_new(BIO_s_connect()); if (!tcp->socketBio) return FALSE; if (BIO_set_conn_hostname(tcp->socketBio, hostname) < 0 || BIO_set_conn_int_port(tcp->socketBio, &port) < 0) return FALSE; BIO_set_nbio(tcp->socketBio, 1); status = BIO_do_connect(tcp->socketBio); if ((status <= 0) && !BIO_should_retry(tcp->socketBio)) return FALSE; tcp->sockfd = BIO_get_fd(tcp->socketBio, NULL); if (tcp->sockfd < 0) return FALSE; if (status <= 0) { FD_ZERO(&cfds); FD_SET(tcp->sockfd, &cfds); tv.tv_sec = timeout; tv.tv_usec = 0; status = select(tcp->sockfd + 1, NULL, &cfds, NULL, &tv); if (status == 0) { return FALSE; /* timeout */ } } BIO_set_close(tcp->socketBio, BIO_NOCLOSE); BIO_free(tcp->socketBio); tcp->socketBio = BIO_new(BIO_s_simple_socket()); if (!tcp->socketBio) return -1; BIO_set_fd(tcp->socketBio, tcp->sockfd, BIO_CLOSE); } SetEventFileDescriptor(tcp->event, tcp->sockfd); tcp_get_ip_address(tcp); tcp_get_mac_address(tcp); option_value = 1; option_len = sizeof(option_value); if (setsockopt(tcp->sockfd, IPPROTO_TCP, TCP_NODELAY, (void*) &option_value, option_len) < 0) fprintf(stderr, "%s: unable to set TCP_NODELAY\n", __FUNCTION__); /* receive buffer must be a least 32 K */ if (getsockopt(tcp->sockfd, SOL_SOCKET, SO_RCVBUF, (void*) &option_value, &option_len) == 0) { if (option_value < (1024 * 32)) { option_value = 1024 * 32; option_len = sizeof(option_value); if (setsockopt(tcp->sockfd, SOL_SOCKET, SO_RCVBUF, (void*) &option_value, option_len) < 0) { fprintf(stderr, "%s: unable to set receive buffer len\n", __FUNCTION__); return FALSE; } } } if (!tcp_set_keep_alive_mode(tcp)) return FALSE; tcp->bufferedBio = BIO_new(BIO_s_buffered_socket()); if (!tcp->bufferedBio) return FALSE; tcp->bufferedBio->ptr = tcp; tcp->bufferedBio = BIO_push(tcp->bufferedBio, tcp->socketBio); return TRUE; }