Example #1
0
QCryptoTLSSessionHandshakeStatus
qcrypto_tls_session_get_handshake_status(QCryptoTLSSession *session)
{
    if (session->handshakeComplete) {
        return QCRYPTO_TLS_HANDSHAKE_COMPLETE;
    } else if (gnutls_record_get_direction(session->handle) == 0) {
        return QCRYPTO_TLS_HANDSHAKE_RECVING;
    } else {
        return QCRYPTO_TLS_HANDSHAKE_SENDING;
    }
}
Example #2
0
int CTlsSocket::ContinueHandshake()
{
	m_pOwner->LogMessage(Debug_Verbose, _T("CTlsSocket::ContinueHandshake()"));
	wxASSERT(m_session);
	wxASSERT(m_tlsState == handshake);

	int res = gnutls_handshake(m_session);
	while (res == GNUTLS_E_AGAIN || res == GNUTLS_E_INTERRUPTED)
	{
		if ( gnutls_record_get_direction(m_session) != 1 || !m_canWriteToSocket )
			break;

		res = gnutls_handshake(m_session);
	}
	if (!res)
	{
		m_pOwner->LogMessage(Debug_Info, _T("TLS Handshake successful"));

		if (ResumedSession())
			m_pOwner->LogMessage(Debug_Info, _T("TLS Session resumed"));

		const wxString protocol = GetProtocolName();
		const wxString keyExchange = GetKeyExchange();
		const wxString cipherName = GetCipherName();
		const wxString macName = GetMacName();

		m_pOwner->LogMessage(Debug_Info, _T("Protocol: %s, Key exchange: %s, Cipher: %s, MAC: %s"), protocol.c_str(), keyExchange.c_str(), cipherName.c_str(), macName.c_str());

		res = VerifyCertificate();
		if (res != FZ_REPLY_OK)
			return res;

		if (m_shutdown_requested)
		{
			int error = Shutdown();
			if (!error || error != EAGAIN)
			{
				CSocketEvent *evt = new CSocketEvent(m_pEvtHandler, this, CSocketEvent::close);
				CSocketEventDispatcher::Get().SendEvent(evt);
			}
		}

		return FZ_REPLY_OK;
	}
	else if (res == GNUTLS_E_AGAIN || res == GNUTLS_E_INTERRUPTED)
		return FZ_REPLY_WOULDBLOCK;

	Failure(res, ECONNABORTED);

	return FZ_REPLY_ERROR;
}
Example #3
0
void SslSocket::handshake(int revents)
{
	TRACE("handshake(0x%04x)", revents);
	int rv = gnutls_handshake(session_);

	if (rv == GNUTLS_E_SUCCESS) {
		// handshake either completed or failed
		TRACE("SSL handshake complete. (time: %.4f)", ev_now(loop()) - ctime_);

		setState(Operational);
		setMode(Read);

		if (handshakeCallback_) {
			handshakeCallback_(this, handshakeData_);
		}
	} else if (rv != GNUTLS_E_AGAIN && rv != GNUTLS_E_INTERRUPTED) {
		TRACE("SSL handshake failed (%d): %s", rv, gnutls_strerror(rv));

		close();

		if (handshakeCallback_) {
			handshakeCallback_(this, handshakeData_);
		}
	} else {
		TRACE("SSL partial handshake: (%d)", gnutls_record_get_direction(session_));
		switch (gnutls_record_get_direction(session_)) {
		case 0: // read
			setMode(Read);
			break;
		case 1: // write
			setMode(Write);
			break;
		default:
			break;
		}
	}
}
Example #4
0
static Eina_Bool
_process_data(gnutls_session_t client, Ecore_Fd_Handler * fd_handler)
{
	static int ret, lastret;
	static unsigned int count = 0;

	if (!done) {
		lastret = ret;
		ret = gnutls_handshake(client);
		count++;
		if (gnutls_record_get_direction(client))
			ecore_main_fd_handler_active_set(fd_handler,
							 ECORE_FD_WRITE);
		else
			ecore_main_fd_handler_active_set(fd_handler,
							 ECORE_FD_READ);
		/* avoid printing messages infinity times */
		if (lastret != ret && ret != 0 && ret != GNUTLS_E_AGAIN) {
			print("gnutls returned with: %s - %s",
			      gnutls_strerror_name(ret),
			      gnutls_strerror(ret));
			if ((ret == GNUTLS_E_WARNING_ALERT_RECEIVED)
			    || (ret == GNUTLS_E_FATAL_ALERT_RECEIVED))
				print("Also received alert: %s",
				      gnutls_alert_get_name
				      (gnutls_alert_get(client)));
			print("last out: %s",
			      SSL_GNUTLS_PRINT_HANDSHAKE_STATUS
			      (gnutls_handshake_get_last_out(client)));
			print("last in: %s",
			      SSL_GNUTLS_PRINT_HANDSHAKE_STATUS
			      (gnutls_handshake_get_last_in(client)));
		}

		if (gnutls_error_is_fatal(ret)) {
			print("yarrr this be an error!");
			exit(1);
		}

	}
	if (ret == GNUTLS_E_SUCCESS) {
		done = 1;
		//print("Handshake successful in %u handshake calls!", count);
		ecore_main_loop_quit();
	}

	return ECORE_CALLBACK_RENEW;
}
Example #5
0
int CTlsSocket::ContinueHandshake()
{
	m_pOwner->LogMessage(MessageType::Debug_Verbose, _T("CTlsSocket::ContinueHandshake()"));
	wxASSERT(m_session);
	wxASSERT(m_tlsState == TlsState::handshake);

	int res = gnutls_handshake(m_session);
	while (res == GNUTLS_E_AGAIN || res == GNUTLS_E_INTERRUPTED) {
		if (!(gnutls_record_get_direction(m_session) ? m_canWriteToSocket : m_canReadFromSocket)) {
			break;
		}
		res = gnutls_handshake(m_session);
	}
	if (!res) {
		m_pOwner->LogMessage(MessageType::Debug_Info, _T("TLS Handshake successful"));

		if (ResumedSession())
			m_pOwner->LogMessage(MessageType::Debug_Info, _T("TLS Session resumed"));

		const wxString protocol = GetProtocolName();
		const wxString keyExchange = GetKeyExchange();
		const wxString cipherName = GetCipherName();
		const wxString macName = GetMacName();

		m_pOwner->LogMessage(MessageType::Debug_Info, _T("Protocol: %s, Key exchange: %s, Cipher: %s, MAC: %s"), protocol, keyExchange, cipherName, macName);

		res = VerifyCertificate();
		if (res != FZ_REPLY_OK)
			return res;

		if (m_shutdown_requested) {
			int error = Shutdown();
			if (!error || error != EAGAIN) {
				m_pEvtHandler->send_event<CSocketEvent>(this, SocketEventType::close, 0);
			}
		}

		return FZ_REPLY_OK;
	}
	else if (res == GNUTLS_E_AGAIN || res == GNUTLS_E_INTERRUPTED)
		return FZ_REPLY_WOULDBLOCK;

	Failure(res, true);

	return FZ_REPLY_ERROR;
}
Example #6
0
	bool Handshake(issl_session* session, StreamSocket* user)
	{
		int ret = gnutls_handshake(session->sess);

		if (ret < 0)
		{
			if(ret == GNUTLS_E_AGAIN || ret == GNUTLS_E_INTERRUPTED)
			{
				// Handshake needs resuming later, read() or write() would have blocked.

				if(gnutls_record_get_direction(session->sess) == 0)
				{
					// gnutls_handshake() wants to read() again.
					session->status = ISSL_HANDSHAKING_READ;
					ServerInstance->SE->ChangeEventMask(user, FD_WANT_POLL_READ | FD_WANT_NO_WRITE);
				}
				else
				{
					// gnutls_handshake() wants to write() again.
					session->status = ISSL_HANDSHAKING_WRITE;
					ServerInstance->SE->ChangeEventMask(user, FD_WANT_NO_READ | FD_WANT_SINGLE_WRITE);
				}
			}
			else
			{
				user->SetError("Handshake Failed - " + std::string(gnutls_strerror(ret)));
				CloseSession(session);
				session->status = ISSL_CLOSING;
			}

			return false;
		}
		else
		{
			// Change the seesion state
			session->status = ISSL_HANDSHAKEN;

			VerifyCertificate(session,user);

			// Finish writing, if any left
			ServerInstance->SE->ChangeEventMask(user, FD_WANT_POLL_READ | FD_WANT_NO_WRITE | FD_ADD_TRIAL_WRITE);

			return true;
		}
	}
Example #7
0
File: tls_g.c Project: 1ack/Impala
static int
tlsg_session_upflags( Sockbuf *sb, tls_session *session, int rc )
{
	tlsg_session *s = (tlsg_session *)session;

	if ( rc != GNUTLS_E_INTERRUPTED && rc != GNUTLS_E_AGAIN )
		return 0;

	switch (gnutls_record_get_direction (s->session)) {
	case 0: 
		sb->sb_trans_needs_read = 1;
		return 1;
	case 1:
		sb->sb_trans_needs_write = 1;
		return 1;
	}
	return 0;
}
Example #8
0
File: evcom.c Project: bernd/node
static int
stream__handshake (evcom_stream *stream)
{
  assert(SECURE(stream));

  int r = gnutls_handshake(stream->session);

  if (gnutls_error_is_fatal(r)) {
    stream->gnutls_errorno = r;
    stream->send_action = stream_send__close;
    stream->recv_action = stream_recv__close;
    return OKAY;
  }

  ev_timer_again(D_LOOP_(stream) &stream->timeout_watcher);

  if (r == GNUTLS_E_INTERRUPTED || r == GNUTLS_E_AGAIN) {
    if (0 == gnutls_record_get_direction((stream)->session)) {
      ev_io_start(D_LOOP_(stream) &(stream)->read_watcher); 
      ev_io_stop(D_LOOP_(stream) &(stream)->write_watcher); 
    } else {
      ev_io_stop(D_LOOP_(stream) &(stream)->read_watcher); 
      ev_io_start(D_LOOP_(stream) &(stream)->write_watcher);
    }
    assert(stream->recv_action == stream__handshake);
    assert(stream->send_action == stream__handshake);
    return AGAIN;
  }

  assert(!CONNECTED(stream));
  stream->flags |= EVCOM_CONNECTED;
  if (stream->on_connect) stream->on_connect(stream);

  /* evcom_stream_force_close might have been called. */
  if (stream->recvfd >= 0 && stream->sendfd >= 0) {
    ev_io_start(D_LOOP_(stream) &stream->read_watcher);
    ev_io_start(D_LOOP_(stream) &stream->write_watcher);

    stream->send_action = stream_send__data;
    stream->recv_action = stream_recv__data;
  }

  return OKAY;
}
Example #9
0
	// Returns 1 if handshake succeeded, 0 if it is still in progress, -1 if it failed
	int Handshake(StreamSocket* user)
	{
		int ret = gnutls_handshake(this->sess);

		if (ret < 0)
		{
			if(ret == GNUTLS_E_AGAIN || ret == GNUTLS_E_INTERRUPTED)
			{
				// Handshake needs resuming later, read() or write() would have blocked.
				this->status = ISSL_HANDSHAKING;

				if (gnutls_record_get_direction(this->sess) == 0)
				{
					// gnutls_handshake() wants to read() again.
					SocketEngine::ChangeEventMask(user, FD_WANT_POLL_READ | FD_WANT_NO_WRITE);
				}
				else
				{
					// gnutls_handshake() wants to write() again.
					SocketEngine::ChangeEventMask(user, FD_WANT_NO_READ | FD_WANT_SINGLE_WRITE);
				}

				return 0;
			}
			else
			{
				user->SetError("Handshake Failed - " + std::string(gnutls_strerror(ret)));
				CloseSession();
				return -1;
			}
		}
		else
		{
			// Change the seesion state
			this->status = ISSL_HANDSHAKEN;

			VerifyCertificate();

			// Finish writing, if any left
			SocketEngine::ChangeEventMask(user, FD_WANT_POLL_READ | FD_WANT_NO_WRITE | FD_ADD_TRIAL_WRITE);

			return 1;
		}
	}
Example #10
0
static int do_tls_poll(URLContext *h, int ret)
{
    TLSContext *c = h->priv_data;
    struct pollfd p = { c->fd, 0, 0 };
#if CONFIG_GNUTLS
    switch (ret) {
    case GNUTLS_E_AGAIN:
    case GNUTLS_E_INTERRUPTED:
        break;
    case GNUTLS_E_WARNING_ALERT_RECEIVED:
        av_log(h, AV_LOG_WARNING, "%s\n", gnutls_strerror(ret));
        break;
    default:
        av_log(h, AV_LOG_ERROR, "%s\n", gnutls_strerror(ret));
        return AVERROR(EIO);
    }
    if (gnutls_record_get_direction(c->session))
        p.events = POLLOUT;
    else
        p.events = POLLIN;
#elif CONFIG_OPENSSL
    ret = SSL_get_error(c->ssl, ret);
    if (ret == SSL_ERROR_WANT_READ) {
        p.events = POLLIN;
    } else if (ret == SSL_ERROR_WANT_WRITE) {
        p.events = POLLOUT;
    } else {
        av_log(h, AV_LOG_ERROR, "%s\n", ERR_error_string(ERR_get_error(), NULL));
        return AVERROR(EIO);
    }
#endif
    if (h->flags & AVIO_FLAG_NONBLOCK)
        return AVERROR(EAGAIN);
    while (1) {
        int n = poll(&p, 1, 100);
        if (n > 0)
            break;
        if (ff_check_interrupt(&h->interrupt_callback))
            return AVERROR(EINTR);
    }
    return 0;
}
Example #11
0
void CTlsSocket::OnSend()
{
	m_pOwner->LogMessage(Debug_Debug, _T("CTlsSocket::OnSend()"));

	m_canWriteToSocket = true;

	if (!m_session)
		return;

	if (!gnutls_record_get_direction(m_session))
		return;

	if (m_tlsState == handshake)
		Handshake();
	else if (m_tlsState == closing)
		ContinueShutdown();
	else if (m_tlsState == conn)
	{
		CheckResumeFailedWrite();
		TriggerEvents();
	}
}
Example #12
0
void CTlsSocket::OnSend()
{
	m_pOwner->LogMessage(MessageType::Debug_Debug, _T("CTlsSocket::OnSend()"));

	m_canWriteToSocket = true;

	if (!m_session)
		return;

	const int direction = gnutls_record_get_direction(m_session);
	if (!direction && !m_lastWriteFailed)
		return;

	if (m_tlsState == TlsState::handshake)
		ContinueHandshake();
	else if (m_tlsState == TlsState::closing)
		ContinueShutdown();
	else if (m_tlsState == TlsState::conn) {
		CheckResumeFailedReadWrite();
		TriggerEvents();
	}
}
Example #13
0
static int
do_ssl_handshake(rb_fde_t *F, PF * callback)
{
    int ret;
    int flags;

    ret = gnutls_handshake(SSL_P(F));
    if (ret < 0)
    {
        if ((ret == GNUTLS_E_INTERRUPTED && rb_ignore_errno(errno)) || ret == GNUTLS_E_AGAIN)
        {
            if (gnutls_record_get_direction(SSL_P(F)) == 0)
                flags = RB_SELECT_READ;
            else
                flags = RB_SELECT_WRITE;
            rb_setselect(F, flags, callback, NULL);
            return 0;
        }
        F->ssl_errno = ret;
        return -1;
    }
    return 1;       /* handshake is finished..go about life */
}
Example #14
0
void TLSSocket_GnuTLS::sendRaw(const byte_t* buffer, const size_t count) {

	m_status &= ~(STATUS_WANT_WRITE | STATUS_WANT_READ);

	for (size_t size = count ; size > 0 ; ) {

		resetException();

		ssize_t ret = gnutls_record_send(
			*m_session->m_gnutlsSession,
			buffer, static_cast <size_t>(size)
		);

		throwException();

		if (ret < 0) {

			if (ret == GNUTLS_E_AGAIN) {

				if (gnutls_record_get_direction(*m_session->m_gnutlsSession) == 0) {
					m_wrapped->waitForRead();
				} else {
					m_wrapped->waitForWrite();
				}

				continue;
			}

			TLSSession_GnuTLS::throwTLSException("gnutls_record_send", static_cast <int>(ret));

		} else {

			buffer += ret;
			size -= ret;
		}
	}
}
Example #15
0
File: evcom.c Project: bernd/node
static int
stream_send__gnutls_bye (evcom_stream *stream)
{
  assert(SECURE(stream));

  int r = gnutls_bye(stream->session, GNUTLS_SHUT_WR);

  if (r == GNUTLS_E_INTERRUPTED || r == GNUTLS_E_AGAIN) {
    assert(1 == gnutls_record_get_direction((stream)->session));
    assert(stream->send_action == stream_send__gnutls_bye);
    return AGAIN;
  }

  if (gnutls_error_is_fatal(r)) {
    stream->gnutls_errorno = r;
    stream->send_action = stream_send__close;
    return OKAY;
  }

  stream->flags &= ~EVCOM_WRITABLE;

  stream->send_action = stream_send__wait_for_eof;
  return OKAY;
}
Example #16
0
static int vncws_start_tls_handshake(struct VncState *vs)
{
    int ret = gnutls_handshake(vs->tls.session);

    if (ret < 0) {
        if (!gnutls_error_is_fatal(ret)) {
            VNC_DEBUG("Handshake interrupted (blocking)\n");
            if (!gnutls_record_get_direction(vs->tls.session)) {
                qemu_set_fd_handler(vs->csock, vncws_tls_handshake_io,
                                    NULL, vs);
            } else {
                qemu_set_fd_handler(vs->csock, NULL, vncws_tls_handshake_io,
                                    vs);
            }
            return 0;
        }
        VNC_DEBUG("Handshake failed %s\n", gnutls_strerror(ret));
        vnc_client_error(vs);
        return -1;
    }

    if (vs->vd->tls.x509verify) {
        if (vnc_tls_validate_certificate(vs) < 0) {
            VNC_DEBUG("Client verification failed\n");
            vnc_client_error(vs);
            return -1;
        } else {
            VNC_DEBUG("Client verification passed\n");
        }
    }

    VNC_DEBUG("Handshake done, switching to TLS data mode\n");
    qemu_set_fd_handler2(vs->csock, NULL, vncws_handshake_read, NULL, vs);

    return 0;
}
Example #17
0
/**
 * @return	TLS_HANDSHAKE_ERROR if the TLS handshake failed.
 *			TLS_HANDSHAKE_RETRY if the handshake is incomplete; thus
 *				tls_handshake() should called again on the next I/O event.
 *			TLS_HANDSHAKE_FINISHED if the TLS handshake succeeded. Note
 *				that this is also returned if TLS is disabled. Therefore
 *				this does not imply an encrypted connection.
 */
enum tls_handshake_result
tls_handshake(struct gnutella_socket *s)
{
    gnutls_session session;
    bool do_warn;
    int ret;

    socket_check(s);

    /*
     * For connect-back probes, the handshake will probably fail. We use
     * TLS anyway to avoid getting blocked which the remote peer would
     * not notice. Thus suppress warnings for failed handshakes in this
     * case.
     */
    do_warn = SOCK_TYPE_CONNBACK != s->type;

    session = tls_socket_get_session(s);
    g_return_val_if_fail(session, TLS_HANDSHAKE_ERROR);
    g_return_val_if_fail(SOCK_TLS_INITIALIZED == s->tls.stage,
    TLS_HANDSHAKE_ERROR);

    ret = gnutls_handshake(session);
    switch (ret) {
    case 0:
        if (GNET_PROPERTY(tls_debug) > 3) {
            g_debug("TLS handshake succeeded");
        }
        tls_socket_evt_change(s, SOCK_CONN_INCOMING == s->direction
                              ? INPUT_EVENT_R : INPUT_EVENT_W);
        if (GNET_PROPERTY(tls_debug > 3)) {
            tls_print_session_info(s->addr, s->port, session,
                                   SOCK_CONN_INCOMING == s->direction);
        }
        tls_signal_pending(s);
        return TLS_HANDSHAKE_FINISHED;
    case GNUTLS_E_AGAIN:
    case GNUTLS_E_INTERRUPTED:
        tls_socket_evt_change(s, gnutls_record_get_direction(session)
                              ? INPUT_EVENT_WX : INPUT_EVENT_RX);
        if (GNET_PROPERTY(tls_debug) > 3) {
            g_debug("TLS handshake proceeding...");
        }
        tls_signal_pending(s);
        return TLS_HANDSHAKE_RETRY;
    case GNUTLS_E_PULL_ERROR:
    case GNUTLS_E_PUSH_ERROR:
        /* Logging already done by tls_transport_debug() */
        break;
    case GNUTLS_E_UNEXPECTED_PACKET_LENGTH:
        if ((SOCK_F_EOF | SOCK_F_CONNRESET) & s->flags) {
            /* Remote peer has hung up */
            break;
        }
    /* FALLTHROUGH */
    default:
        if (do_warn && GNET_PROPERTY(tls_debug)) {
            g_carp("gnutls_handshake() failed: host=%s (%s) error=\"%s\"",
                   host_addr_port_to_string(s->addr, s->port),
                   SOCK_CONN_INCOMING == s->direction ? "incoming" : "outgoing",
                   gnutls_strerror(ret));
        }
    }
    return TLS_HANDSHAKE_ERROR;
}
Example #18
0
int dtls_mainloop(struct openconnect_info *vpninfo, int *timeout)
{
	int work_done = 0;
	char magic_pkt;

	while (1) {
		int len = vpninfo->ip_info.mtu;
		unsigned char *buf;

		if (!dtls_pkt || len > dtls_pkt_max) {
			realloc_inplace(dtls_pkt, sizeof(struct pkt) + len);
			if (!dtls_pkt) {
				vpn_progress(vpninfo, PRG_ERR, "Allocation failed\n");
				break;
			}
			dtls_pkt_max = len;
		}

		buf = dtls_pkt->data - 1;
		len = DTLS_RECV(vpninfo->dtls_ssl, buf, len + 1);
		if (len <= 0)
			break;

		vpn_progress(vpninfo, PRG_TRACE,
			     _("Received DTLS packet 0x%02x of %d bytes\n"),
			     buf[0], len);

		vpninfo->dtls_times.last_rx = time(NULL);

		switch (buf[0]) {
		case AC_PKT_DATA:
			dtls_pkt->len = len - 1;
			queue_packet(&vpninfo->incoming_queue, dtls_pkt);
			dtls_pkt = NULL;
			work_done = 1;
			break;

		case AC_PKT_DPD_OUT:
			vpn_progress(vpninfo, PRG_TRACE, _("Got DTLS DPD request\n"));

			/* FIXME: What if the packet doesn't get through? */
			magic_pkt = AC_PKT_DPD_RESP;
			if (DTLS_SEND(vpninfo->dtls_ssl, &magic_pkt, 1) != 1)
				vpn_progress(vpninfo, PRG_ERR,
					     _("Failed to send DPD response. Expect disconnect\n"));
			continue;

		case AC_PKT_DPD_RESP:
			vpn_progress(vpninfo, PRG_TRACE, _("Got DTLS DPD response\n"));
			break;

		case AC_PKT_KEEPALIVE:
			vpn_progress(vpninfo, PRG_TRACE, _("Got DTLS Keepalive\n"));
			break;

		default:
			vpn_progress(vpninfo, PRG_ERR,
				     _("Unknown DTLS packet type %02x, len %d\n"),
				     buf[0], len);
			if (1) {
				/* Some versions of OpenSSL have bugs with receiving out-of-order
				 * packets. Not only do they wrongly decide to drop packets if
				 * two packets get swapped in transit, but they also _fail_ to
				 * drop the packet in non-blocking mode; instead they return
				 * the appropriate length of garbage. So don't abort... for now. */
				break;
			} else {
				vpninfo->quit_reason = "Unknown packet received";
				return 1;
			}

		}
	}

	switch (keepalive_action(&vpninfo->dtls_times, timeout)) {
	case KA_REKEY: {
		int ret;

		vpn_progress(vpninfo, PRG_INFO, _("DTLS rekey due\n"));

		/* There ought to be a method of rekeying DTLS without tearing down
		   the CSTP session and restarting, but we don't (yet) know it */
		ret = cstp_reconnect(vpninfo);
		if (ret) {
			vpn_progress(vpninfo, PRG_ERR, _("Reconnect failed\n"));
			vpninfo->quit_reason = "CSTP reconnect failed";
			return ret;
		}

		if (dtls_restart(vpninfo))
			vpn_progress(vpninfo, PRG_ERR, _("DTLS rekey failed\n"));
		return 1;
	}

	case KA_DPD_DEAD:
		vpn_progress(vpninfo, PRG_ERR, _("DTLS Dead Peer Detection detected dead peer!\n"));
		/* Fall back to SSL, and start a new DTLS connection */
		dtls_restart(vpninfo);
		return 1;

	case KA_DPD:
		vpn_progress(vpninfo, PRG_TRACE, _("Send DTLS DPD\n"));

		magic_pkt = AC_PKT_DPD_OUT;
		if (DTLS_SEND(vpninfo->dtls_ssl, &magic_pkt, 1) != 1)
			vpn_progress(vpninfo, PRG_ERR,
				     _("Failed to send DPD request. Expect disconnect\n"));

		/* last_dpd will just have been set */
		vpninfo->dtls_times.last_tx = vpninfo->dtls_times.last_dpd;
		work_done = 1;
		break;

	case KA_KEEPALIVE:
		/* No need to send an explicit keepalive
		   if we have real data to send */
		if (vpninfo->outgoing_queue)
			break;

		vpn_progress(vpninfo, PRG_TRACE, _("Send DTLS Keepalive\n"));

		magic_pkt = AC_PKT_KEEPALIVE;
		if (DTLS_SEND(vpninfo->dtls_ssl, &magic_pkt, 1) != 1)
			vpn_progress(vpninfo, PRG_ERR,
				     _("Failed to send keepalive request. Expect disconnect\n"));
		time(&vpninfo->dtls_times.last_tx);
		work_done = 1;
		break;

	case KA_NONE:
		;
	}

	/* Service outgoing packet queue */
	FD_CLR(vpninfo->dtls_fd, &vpninfo->select_wfds);
	while (vpninfo->outgoing_queue) {
		struct pkt *this = vpninfo->outgoing_queue;
		int ret;

		vpninfo->outgoing_queue = this->next;
		vpninfo->outgoing_qlen--;

		/* One byte of header */
		this->hdr[7] = AC_PKT_DATA;

#if defined(DTLS_OPENSSL)
		ret = SSL_write(vpninfo->dtls_ssl, &this->hdr[7], this->len + 1);
		if (ret <= 0) {
			ret = SSL_get_error(vpninfo->dtls_ssl, ret);

			if (ret == SSL_ERROR_WANT_WRITE) {
				FD_SET(vpninfo->dtls_fd, &vpninfo->select_wfds);
				vpninfo->outgoing_queue = this;
				vpninfo->outgoing_qlen++;

			} else if (ret != SSL_ERROR_WANT_READ) {
				/* If it's a real error, kill the DTLS connection and
				   requeue the packet to be sent over SSL */
				vpn_progress(vpninfo, PRG_ERR,
					     _("DTLS got write error %d. Falling back to SSL\n"),
					     ret);
				openconnect_report_ssl_errors(vpninfo);
				dtls_restart(vpninfo);
				vpninfo->outgoing_queue = this;
				vpninfo->outgoing_qlen++;
				work_done = 1;
			}
			return work_done;
		}
#elif defined(DTLS_GNUTLS)
		ret = gnutls_record_send(vpninfo->dtls_ssl, &this->hdr[7], this->len + 1);
		if (ret <= 0) {
			if (ret != GNUTLS_E_AGAIN) {
				vpn_progress(vpninfo, PRG_ERR,
					     _("DTLS got write error: %s. Falling back to SSL\n"),
					     gnutls_strerror(ret));
				dtls_restart(vpninfo);
				vpninfo->outgoing_queue = this;
				vpninfo->outgoing_qlen++;
				work_done = 1;
			} else if (gnutls_record_get_direction(vpninfo->dtls_ssl)) {
				FD_SET(vpninfo->dtls_fd, &vpninfo->select_wfds);
				vpninfo->outgoing_queue = this;
				vpninfo->outgoing_qlen++;
			}

			return work_done;
		}
#endif
		time(&vpninfo->dtls_times.last_tx);
		vpn_progress(vpninfo, PRG_TRACE,
			     _("Sent DTLS packet of %d bytes; DTLS send returned %d\n"),
			     this->len, ret);
		free(this);
	}

	return work_done;
}
Example #19
0
/* this function does a SSL/TLS (re-)handshake */
static CURLcode handshake(struct connectdata *conn,
                          int sockindex,
                          bool duringconnect,
                          bool nonblocking)
{
  struct SessionHandle *data = conn->data;
  struct ssl_connect_data *connssl = &conn->ssl[sockindex];
  gnutls_session session = conn->ssl[sockindex].session;
  curl_socket_t sockfd = conn->sock[sockindex];
  long timeout_ms;
  int rc;
  int what;

  for(;;) {
    /* check allowed time left */
    timeout_ms = Curl_timeleft(data, NULL, duringconnect);

    if(timeout_ms < 0) {
      /* no need to continue if time already is up */
      failf(data, "SSL connection timeout");
      return CURLE_OPERATION_TIMEDOUT;
    }

    /* if ssl is expecting something, check if it's available. */
    if(connssl->connecting_state == ssl_connect_2_reading
       || connssl->connecting_state == ssl_connect_2_writing) {

      curl_socket_t writefd = ssl_connect_2_writing==
        connssl->connecting_state?sockfd:CURL_SOCKET_BAD;
      curl_socket_t readfd = ssl_connect_2_reading==
        connssl->connecting_state?sockfd:CURL_SOCKET_BAD;

      what = Curl_socket_ready(readfd, writefd,
                               nonblocking?0:
                               timeout_ms?timeout_ms:1000);
      if(what < 0) {
        /* fatal error */
        failf(data, "select/poll on SSL socket, errno: %d", SOCKERRNO);
        return CURLE_SSL_CONNECT_ERROR;
      }
      else if(0 == what) {
        if(nonblocking)
          return CURLE_OK;
        else if(timeout_ms) {
          /* timeout */
          failf(data, "SSL connection timeout at %ld", timeout_ms);
          return CURLE_OPERATION_TIMEDOUT;
        }
      }
      /* socket is readable or writable */
    }

    rc = gnutls_handshake(session);

    if((rc == GNUTLS_E_AGAIN) || (rc == GNUTLS_E_INTERRUPTED)) {
      connssl->connecting_state =
        gnutls_record_get_direction(session)?
        ssl_connect_2_writing:ssl_connect_2_reading;
      continue;
      if(nonblocking)
        return CURLE_OK;
    }
    else if((rc < 0) && !gnutls_error_is_fatal(rc)) {
      const char *strerr = NULL;

      if(rc == GNUTLS_E_WARNING_ALERT_RECEIVED) {
        int alert = gnutls_alert_get(session);
        strerr = gnutls_alert_get_name(alert);
      }

      if(strerr == NULL)
        strerr = gnutls_strerror(rc);

      failf(data, "gnutls_handshake() warning: %s", strerr);
    }
    else if(rc < 0) {
      const char *strerr = NULL;

      if(rc == GNUTLS_E_FATAL_ALERT_RECEIVED) {
        int alert = gnutls_alert_get(session);
        strerr = gnutls_alert_get_name(alert);
      }

      if(strerr == NULL)
        strerr = gnutls_strerror(rc);

      failf(data, "gnutls_handshake() failed: %s", strerr);
      return CURLE_SSL_CONNECT_ERROR;
    }

    /* Reset our connect state machine */
    connssl->connecting_state = ssl_connect_1;
    return CURLE_OK;
  }
}
Example #20
0
b_input_condition ssl_getdirection( void *conn )
{
	return( gnutls_record_get_direction( ((struct scd*)conn)->session ) ?
	        B_EV_IO_WRITE : B_EV_IO_READ );
}
bool session::get_record_direction () const
{
    return gnutls_record_get_direction (s);
}
Example #22
0
int CTlsSocket::DoCallGnutlsRecordRecv(void* data, size_t len)
{
	int res = gnutls_record_recv(m_session, data, len);
	while( (res == GNUTLS_E_AGAIN || res == GNUTLS_E_INTERRUPTED) && m_canReadFromSocket && !gnutls_record_get_direction(m_session)) {
		// Spurious EAGAIN. Can happen if GnuTLS gets a partial
		// record and the socket got closed.
		// The unexpected close is being ignored in this case, unless
		// gnutls_record_recv is being called again.
		// Manually call gnutls_record_recv as in case of eof on the socket,
		// we are not getting another receive event.
		m_pOwner->LogMessage(MessageType::Debug_Verbose, _T("gnutls_record_recv returned spurious EAGAIN"));
		res = gnutls_record_recv(m_session, data, len);
	}

	return res;
}
Example #23
0
/**
 * Check and handle error return codes after failed calls to SSL functions.
 *
 * OpenSSL:
 * SSL_connect(), SSL_accept(), SSL_do_handshake(), SSL_read(), SSL_peek(), or
 * SSL_write() on ssl.
 *
 * GnuTLS:
 * gnutlsssl_read(), gnutls_write() or gnutls_handshake().
 *
 * @param c The connection handle.
 * @prarm code The return code.
 * @param fname The name of the function in which the error occurred.
 * @return -1 on fatal errors, 0 if we can try again later.
 */
static int
ConnSSL_HandleError(CONNECTION * c, const int code, const char *fname)
{
#ifdef HAVE_LIBSSL
	int ret = SSL_ERROR_SYSCALL;
	unsigned long sslerr;
	int real_errno = errno;

	ret = SSL_get_error(c->ssl_state.ssl, code);

	switch (ret) {
	case SSL_ERROR_WANT_READ:
		io_event_del(c->sock, IO_WANTWRITE);
		Conn_OPTION_ADD(c, CONN_SSL_WANT_READ);
		return 0;	/* try again later */
	case SSL_ERROR_WANT_WRITE:
		io_event_del(c->sock, IO_WANTREAD);
		Conn_OPTION_ADD(c, CONN_SSL_WANT_WRITE); /* fall through */
	case SSL_ERROR_NONE:
		return 0;	/* try again later */
	case SSL_ERROR_ZERO_RETURN:
		LogDebug("SSL connection shut down normally.");
		break;
	case SSL_ERROR_SYSCALL:
		/* SSL_ERROR_WANT_CONNECT, SSL_ERROR_WANT_ACCEPT,
		 * and SSL_ERROR_WANT_X509_LOOKUP */
		sslerr = ERR_get_error();
		if (sslerr) {
			Log(LOG_ERR, "SSL error: %s [in %s()]!",
			    ERR_error_string(sslerr, NULL), fname);
		} else {
			switch (code) {	/* EOF that violated protocol */
			case 0:
				Log(LOG_ERR,
				    "SSL error, client disconnected [in %s()]!",
				    fname);
				break;
			case -1:	/* low level socket I/O error, check errno */
				Log(LOG_ERR, "SSL error: %s [in %s()]!",
				    strerror(real_errno), fname);
			}
		}
		break;
	case SSL_ERROR_SSL:
		LogOpenSSLError("SSL protocol error", fname);
		break;
	default:
		Log(LOG_ERR, "Unknown SSL error %d [in %s()]!", ret, fname);
	}
	ConnSSL_Free(c);
	return -1;
#endif
#ifdef HAVE_LIBGNUTLS
	switch (code) {
	case GNUTLS_E_AGAIN:
	case GNUTLS_E_INTERRUPTED:
		if (gnutls_record_get_direction(c->ssl_state.gnutls_session)) {
			Conn_OPTION_ADD(c, CONN_SSL_WANT_WRITE);
			io_event_del(c->sock, IO_WANTREAD);
		} else {
			Conn_OPTION_ADD(c, CONN_SSL_WANT_READ);
			io_event_del(c->sock, IO_WANTWRITE);
		}
		break;
	default:
		assert(code < 0);
		if (gnutls_error_is_fatal(code)) {
			Log(LOG_ERR, "SSL error: %s [%s].",
			    gnutls_strerror(code), fname);
			ConnSSL_Free(c);
			return -1;
		}
	}
	return 0;
#endif
}
Example #24
0
static Ecore_Con_Ssl_Error
_ecore_con_ssl_client_init_gnutls(Ecore_Con_Client *cl)
{
   const gnutls_datum_t *cert_list;
   unsigned int iter, cert_list_size;
   const char *priority = "NONE:%VERIFY_ALLOW_X509_V1_CA_CRT:+RSA:+DHE-RSA:+DHE-DSS:+ANON-DH:+COMP-DEFLATE:+COMP-NULL:+CTYPE-X509:+SHA1:+SHA256:+SHA384:+SHA512:+AES-256-CBC:+AES-128-CBC:+3DES-CBC:+VERS-TLS1.2:+VERS-TLS1.1:+VERS-TLS1.0:+VERS-SSL3.0";
   int ret = 0;

   switch (cl->ssl_state)
     {
      case ECORE_CON_SSL_STATE_DONE:
        return ECORE_CON_SSL_ERROR_NONE;

      case ECORE_CON_SSL_STATE_INIT:
        if (cl->host_server->type & ECORE_CON_USE_SSL2) /* not supported because of security issues */
          return ECORE_CON_SSL_ERROR_SSL2_NOT_SUPPORTED;

        switch (cl->host_server->type & ECORE_CON_SSL)
          {
           case ECORE_CON_USE_SSL3:
           case ECORE_CON_USE_SSL3 | ECORE_CON_LOAD_CERT:
             priority = "NONE:%VERIFY_ALLOW_X509_V1_CA_CRT:+RSA:+DHE-RSA:+DHE-DSS:+ANON-DH:+COMP-DEFLATE:+COMP-NULL:+CTYPE-X509:+SHA1:+SHA256:+SHA384:+SHA512:+AES-256-CBC:+AES-128-CBC:+3DES-CBC:!VERS-TLS1.0:!VERS-TLS1.1";
             break;

           case ECORE_CON_USE_TLS:
           case ECORE_CON_USE_TLS | ECORE_CON_LOAD_CERT:
             priority = "NONE:%VERIFY_ALLOW_X509_V1_CA_CRT:+RSA:+DHE-RSA:+DHE-DSS:+ANON-DH:+COMP-DEFLATE:+COMP-NULL:+CTYPE-X509:+SHA1:+SHA256:+SHA384:+SHA512:+AES-256-CBC:+AES-128-CBC:+3DES-CBC:!VERS-SSL3.0";
             break;

           case ECORE_CON_USE_MIXED:
           case ECORE_CON_USE_MIXED | ECORE_CON_LOAD_CERT:
             break;

           default:
             return ECORE_CON_SSL_ERROR_NONE;
          }

        _client_connected++;

        SSL_ERROR_CHECK_GOTO_ERROR(ret = gnutls_init(&cl->session, GNUTLS_SERVER));
        SSL_ERROR_CHECK_GOTO_ERROR(ret = gnutls_session_ticket_key_generate(&cl->session_ticket));
        SSL_ERROR_CHECK_GOTO_ERROR(ret = gnutls_session_ticket_enable_server(cl->session, &cl->session_ticket));
        INF("Applying priority string: %s", priority);
        SSL_ERROR_CHECK_GOTO_ERROR(ret = gnutls_priority_set_direct(cl->session, priority, NULL));
        SSL_ERROR_CHECK_GOTO_ERROR(ret = gnutls_credentials_set(cl->session, GNUTLS_CRD_CERTIFICATE, cl->host_server->cert));
        //  SSL_ERROR_CHECK_GOTO_ERROR(ret = gnutls_credentials_set(cl->session, GNUTLS_CRD_PSK, cl->host_server->pskcred_s));
        if (!cl->host_server->use_cert)
          SSL_ERROR_CHECK_GOTO_ERROR(ret = gnutls_credentials_set(cl->session, GNUTLS_CRD_ANON, cl->host_server->anoncred_s));

        gnutls_certificate_server_set_request(cl->session, GNUTLS_CERT_REQUEST);

        gnutls_dh_set_prime_bits(cl->session, 2048);
        gnutls_transport_set_ptr(cl->session, (gnutls_transport_ptr_t)((intptr_t)cl->fd));
        cl->ssl_state = ECORE_CON_SSL_STATE_HANDSHAKING;

      case ECORE_CON_SSL_STATE_HANDSHAKING:
        if (!cl->session)
          {
             DBG("Client was previously lost, going to error condition");
             goto error;
          }
        DBG("calling gnutls_handshake()");
        ret = gnutls_handshake(cl->session);
        SSL_ERROR_CHECK_GOTO_ERROR(gnutls_error_is_fatal(ret));

        if (!ret)
          {
             cl->handshaking = EINA_FALSE;
             cl->ssl_state = ECORE_CON_SSL_STATE_DONE;
          }
        else
          {
             if (gnutls_record_get_direction(cl->session))
               ecore_main_fd_handler_active_set(cl->fd_handler, ECORE_FD_WRITE);
             else
               ecore_main_fd_handler_active_set(cl->fd_handler, ECORE_FD_READ);
             return ECORE_CON_SSL_ERROR_NONE;
          }

      default:
        break;
     }

   if (!cl->host_server->verify)
     /* not verifying certificates, so we're done! */
     return ECORE_CON_SSL_ERROR_NONE;
   ret = 0;
   /* use CRL/CA lists to verify */
   SSL_ERROR_CHECK_GOTO_ERROR(ret = gnutls_certificate_verify_peers2(cl->session, &iter));
   if (iter & GNUTLS_CERT_INVALID)
     ERR("The certificate is not trusted.");
   else if (iter & GNUTLS_CERT_SIGNER_NOT_FOUND)
     ERR("The certificate hasn't got a known issuer.");
   else if (iter & GNUTLS_CERT_REVOKED)
     ERR("The certificate has been revoked.");
   else if (iter & GNUTLS_CERT_EXPIRED)
     ERR("The certificate has expired");
   else if (iter & GNUTLS_CERT_NOT_ACTIVATED)
     ERR("The certificate is not yet activated");

   if (iter)
     goto error;

   if (gnutls_certificate_type_get(cl->session) != GNUTLS_CRT_X509)
     {
        ERR("Warning: PGP certificates are not yet supported!");
        goto error;
     }

   SSL_ERROR_CHECK_GOTO_ERROR(!(cert_list = gnutls_certificate_get_peers(cl->session, &cert_list_size)));
   SSL_ERROR_CHECK_GOTO_ERROR(!cert_list_size);

   DBG("SSL certificate verification succeeded!");
   return ECORE_CON_SSL_ERROR_NONE;

error:
   _gnutls_print_errors(ret);
   if ((ret == GNUTLS_E_WARNING_ALERT_RECEIVED) || (ret == GNUTLS_E_FATAL_ALERT_RECEIVED))
     ERR("Also received alert: %s", gnutls_alert_get_name(gnutls_alert_get(cl->session)));
   if (cl->session && (cl->ssl_state != ECORE_CON_SSL_STATE_DONE))
     {
        ERR("last out: %s", SSL_GNUTLS_PRINT_HANDSHAKE_STATUS(gnutls_handshake_get_last_out(cl->session)));
        ERR("last in: %s", SSL_GNUTLS_PRINT_HANDSHAKE_STATUS(gnutls_handshake_get_last_in(cl->session)));
     }
   _ecore_con_ssl_client_shutdown_gnutls(cl);
   return ECORE_CON_SSL_ERROR_SERVER_INIT_FAILED;
}
Example #25
0
File: evcom.c Project: bernd/node
static int
stream_recv__data (evcom_stream *stream)
{
  char buf[EVCOM_CHUNKSIZE];
  size_t buf_size = EVCOM_CHUNKSIZE;
  ssize_t recved;

  while (READABLE(stream)) {
    assert(CONNECTED(stream));

    if (PAUSED(stream)) {
      stream->recv_action = stream_recv__wait_for_resume;
      return OKAY;
    }


#if EVCOM_HAVE_GNUTLS
    if (SECURE(stream)) {
      recved = gnutls_record_recv(stream->session, buf, buf_size);

      if (gnutls_error_is_fatal(recved)) {
        stream->gnutls_errorno = recved;
        stream->recv_action = stream_recv__close;
        return OKAY;
      }

      if (recved == GNUTLS_E_INTERRUPTED || recved == GNUTLS_E_AGAIN) {
        if (1 == gnutls_record_get_direction((stream)->session)) {
          fprintf(stderr, "(evcom) gnutls recv: unexpected switch direction!\n");
          ev_io_stop(D_LOOP_(stream) &(stream)->read_watcher); 
          ev_io_start(D_LOOP_(stream) &(stream)->write_watcher);
        }
        return AGAIN;
      }

      /* A server may also receive GNUTLS_E_REHANDSHAKE when a client has
       * initiated a andshake. In that case the server can only initiate a
       * handshake or terminate the connection. */
      if (recved == GNUTLS_E_REHANDSHAKE) {
        assert(WRITABLE(stream));
        stream->recv_action = stream__handshake;
        stream->send_action = stream__handshake;
        return OKAY;
      }
    } else 
#endif /* EVCOM_HAVE_GNUTLS */
    {
      recved = read(stream->recvfd, buf, buf_size);
    }

    if (recved < 0) {
      if (errno == EAGAIN || errno == EINTR) {
        assert(stream->recv_action == stream_recv__data);
        return AGAIN;
      } 
      
      if (errno != ECONNRESET) {
        evcom_perror("recv()", stream->errorno);
      }

      stream->errorno = errno;
      stream->recv_action = stream_recv__close;
      return OKAY;
    }

    ev_timer_again(D_LOOP_(stream) &stream->timeout_watcher);

    assert(recved >= 0);

    if (recved == 0) {
      stream->flags &= ~EVCOM_READABLE;
      ev_io_stop(D_LOOP_(stream) &stream->read_watcher);
      stream->recv_action = stream_recv__wait_for_close;
    }

    /* NOTE: EOF is signaled with recved == 0 on callback */
    if (stream->on_read) stream->on_read(stream, buf, recved);

    if (recved == 0) {
      return OKAY;
    }
  }
  return AGAIN;
}
Example #26
0
File: evcom.c Project: bernd/node
static int
stream_send__data (evcom_stream *stream)
{
  ssize_t sent;

  while (!evcom_queue_empty(&stream->out)) {
    assert(WRITABLE(stream));

    evcom_queue *q = evcom_queue_last(&stream->out);
    evcom_buf *buf = evcom_queue_data(q, evcom_buf, queue);

#if EVCOM_HAVE_GNUTLS
    if (SECURE(stream)) {
      sent = gnutls_record_send(stream->session,
          buf->base + buf->written,
          buf->len - buf->written);

      if (sent == GNUTLS_E_INTERRUPTED || sent == GNUTLS_E_AGAIN) {
        if (0 == gnutls_record_get_direction((stream)->session)) {
          fprintf(stderr, "(evcom) gnutls send: unexpected switch direction!\n");
          ev_io_start(D_LOOP_(stream) &(stream)->read_watcher); 
          ev_io_stop(D_LOOP_(stream) &(stream)->write_watcher);
        }
        return AGAIN;
      }

      if (gnutls_error_is_fatal(sent)) {
        stream->gnutls_errorno = sent;
        stream->send_action = stream_send__close;
        return OKAY;
      }
    } else
#endif // EVCOM_HAVE_GNUTLS
    {
      /* TODO use writev() here? */
      sent = nosigpipe_stream_send(stream,
          buf->base + buf->written,
          buf->len - buf->written);
    }

    if (sent <= 0) {
      switch (errno) {
        case EAGAIN:
        case EINTR:
          assert(stream->send_action == stream_send__data);
          return AGAIN;

        default:
          stream->errorno = errno;
          evcom_perror("send()", errno);
          /* pass through */
        case EPIPE:
          stream->send_action = stream_send__close;
          return OKAY;
      }
    }

    ev_timer_again(D_LOOP_(stream) &stream->timeout_watcher);

    assert(sent >= 0);

    buf->written += sent;

    if (buf->written == buf->len) {
      evcom_queue_remove(q);
      if (buf->release) buf->release(buf);
    }
  }

  assert(evcom_queue_empty(&stream->out));

  stream->send_action = stream_send__drain;
  return OKAY;
}
Example #27
0
File: gtls.c Project: markjeee/curl
/* this function does a SSL/TLS (re-)handshake */
static CURLcode handshake(struct connectdata *conn,
                          int sockindex,
                          bool duringconnect,
                          bool nonblocking)
{
  struct SessionHandle *data = conn->data;
  struct ssl_connect_data *connssl = &conn->ssl[sockindex];
  gnutls_session session = conn->ssl[sockindex].session;
  curl_socket_t sockfd = conn->sock[sockindex];
  long timeout_ms;
  int rc;
  int what;

  while(1) {
    /* check allowed time left */
    timeout_ms = Curl_timeleft(conn, NULL, duringconnect);

    if(timeout_ms < 0) {
      /* no need to continue if time already is up */
      failf(data, "SSL connection timeout");
      return CURLE_OPERATION_TIMEDOUT;
    }

    /* if ssl is expecting something, check if it's available. */
    if(connssl->connecting_state == ssl_connect_2_reading
       || connssl->connecting_state == ssl_connect_2_writing) {

      curl_socket_t writefd = ssl_connect_2_writing==
        connssl->connecting_state?sockfd:CURL_SOCKET_BAD;
      curl_socket_t readfd = ssl_connect_2_reading==
        connssl->connecting_state?sockfd:CURL_SOCKET_BAD;

      what = Curl_socket_ready(readfd, writefd,
                               nonblocking?0:(int)timeout_ms);
      if(what < 0) {
        /* fatal error */
        failf(data, "select/poll on SSL socket, errno: %d", SOCKERRNO);
        return CURLE_SSL_CONNECT_ERROR;
      }
      else if(0 == what) {
        if(nonblocking) {
          return CURLE_OK;
        }
        else {
          /* timeout */
          failf(data, "SSL connection timeout");
          return CURLE_OPERATION_TIMEDOUT;
        }
      }
      /* socket is readable or writable */
    }

    rc = gnutls_handshake(session);

    if((rc == GNUTLS_E_AGAIN) || (rc == GNUTLS_E_INTERRUPTED)) {
      connssl->connecting_state =
        gnutls_record_get_direction(session)?
        ssl_connect_2_writing:ssl_connect_2_reading;
      if(nonblocking) {
        return CURLE_OK;
      }
    } else if (rc < 0) {
      failf(data, "gnutls_handshake() failed: %s", gnutls_strerror(rc));
    } else {
      /* Reset our connect state machine */
      connssl->connecting_state = ssl_connect_1;
      return CURLE_OK;
    }
  }
}
Example #28
0
int
network_connect_gnutls_handshake_fd_cb (void *arg_hook_connect, int fd)
{
    struct t_hook *hook_connect;
    int rc, direction, flags;

    /* make C compiler happy */
    (void) fd;

    hook_connect = (struct t_hook *)arg_hook_connect;

    rc = gnutls_handshake (*HOOK_CONNECT(hook_connect, gnutls_sess));

    if ((rc == GNUTLS_E_AGAIN) || (rc == GNUTLS_E_INTERRUPTED))
    {
        direction = gnutls_record_get_direction (*HOOK_CONNECT(hook_connect, gnutls_sess));
        flags = HOOK_FD(HOOK_CONNECT(hook_connect, handshake_hook_fd), flags);
        if ((((flags & HOOK_FD_FLAG_READ) == HOOK_FD_FLAG_READ)
             && (direction != 0))
            || (((flags & HOOK_FD_FLAG_WRITE) == HOOK_FD_FLAG_WRITE)
                && (direction != 1)))
        {
            HOOK_FD(HOOK_CONNECT(hook_connect, handshake_hook_fd), flags) =
                (direction) ? HOOK_FD_FLAG_WRITE: HOOK_FD_FLAG_READ;
        }
    }
    else if (rc != GNUTLS_E_SUCCESS)
    {
        (void) (HOOK_CONNECT(hook_connect, callback))
            (hook_connect->callback_data,
             WEECHAT_HOOK_CONNECT_GNUTLS_HANDSHAKE_ERROR,
             rc,
             gnutls_strerror (rc),
             HOOK_CONNECT(hook_connect, handshake_ip_address));
        unhook (hook_connect);
    }
    else
    {
        fcntl (HOOK_CONNECT(hook_connect, sock), F_SETFL,
               HOOK_CONNECT(hook_connect, handshake_fd_flags));
#if LIBGNUTLS_VERSION_NUMBER < 0x02090a
        /*
         * gnutls only has the gnutls_certificate_set_verify_function()
         * function since version 2.9.10. We need to call our verify
         * function manually after the handshake for old gnutls versions
         */
        if (hook_connect_gnutls_verify_certificates (*HOOK_CONNECT(hook_connect, gnutls_sess)) != 0)
        {
            (void) (HOOK_CONNECT(hook_connect, callback))
                (hook_connect->callback_data,
                 WEECHAT_HOOK_CONNECT_GNUTLS_HANDSHAKE_ERROR,
                 rc,
                 "Error in the certificate.",
                 HOOK_CONNECT(hook_connect, handshake_ip_address));
            unhook (hook_connect);
            return WEECHAT_RC_OK;
        }
#endif
        unhook (HOOK_CONNECT(hook_connect, handshake_hook_fd));
        (void) (HOOK_CONNECT(hook_connect, callback))
                (hook_connect->callback_data, WEECHAT_HOOK_CONNECT_OK, 0, NULL,
                 HOOK_CONNECT(hook_connect, handshake_ip_address));
        unhook (hook_connect);
    }

    return WEECHAT_RC_OK;
}
Example #29
0
void TLSSocket_GnuTLS::handshake() {

	shared_ptr <timeoutHandler> toHandler = m_wrapped->getTimeoutHandler();

	if (toHandler) {
		toHandler->resetTimeOut();
	}

	if (getTracer()) {
		getTracer()->traceSend("Beginning SSL/TLS handshake");
	}

	// Start handshaking process
	try {

		while (true) {

			resetException();

			const int ret = gnutls_handshake(*m_session->m_gnutlsSession);

			throwException();

			if (ret < 0) {

				if (ret == GNUTLS_E_AGAIN) {

					if (gnutls_record_get_direction(*m_session->m_gnutlsSession) == 0) {
						m_wrapped->waitForRead();
					} else {
						m_wrapped->waitForWrite();
					}

				} else if (ret == GNUTLS_E_INTERRUPTED) {

					// Non-fatal error

				} else {

					TLSSession_GnuTLS::throwTLSException("gnutls_handshake", ret);
				}

			} else {

				// Successful handshake
				break;
			}
		}

	} catch (...) {

		throw;
	}

	// Verify server's certificate(s)
	shared_ptr <security::cert::certificateChain> certs = getPeerCertificates();

	if (certs == NULL) {
		throw exceptions::tls_exception("No peer certificate.");
	}

	m_session->getCertificateVerifier()->verify(certs, getPeerName());

	m_connected = true;
}
Example #30
0
int
network_connect_child_read_cb (void *arg_hook_connect, int fd)
{
    struct t_hook *hook_connect;
    char buffer[1], buf_size[6], *cb_error, *cb_ip_address, *error;
    int num_read;
    long size_msg;
#ifdef HAVE_GNUTLS
    int rc, direction;
#endif

    /* make C compiler happy */
    (void) fd;

    hook_connect = (struct t_hook *)arg_hook_connect;

    cb_error = NULL;
    cb_ip_address = NULL;

    num_read = read (HOOK_CONNECT(hook_connect, child_read),
                     buffer, sizeof (buffer));
    if (num_read > 0)
    {
        if (buffer[0] - '0' == WEECHAT_HOOK_CONNECT_OK)
        {
            /* connection ok, read IP address */
            buf_size[5] = '\0';
            num_read = read (HOOK_CONNECT(hook_connect, child_read),
                             buf_size, 5);
            if (num_read == 5)
            {
                error = NULL;
                size_msg = strtol (buf_size, &error, 10);
                if (error && !error[0] && (size_msg > 0))
                {
                    cb_ip_address = malloc (size_msg + 1);
                    if (cb_ip_address)
                    {
                        num_read = read (HOOK_CONNECT(hook_connect, child_read),
                                         cb_ip_address, size_msg);
                        if (num_read == size_msg)
                            cb_ip_address[size_msg] = '\0';
                        else
                        {
                            free (cb_ip_address);
                            cb_ip_address = NULL;
                        }
                    }
                }
            }
#ifdef HAVE_GNUTLS
            if (HOOK_CONNECT(hook_connect, gnutls_sess))
            {
                /*
                 * the socket needs to be non-blocking since the call to
                 * gnutls_handshake can block
                 */
                HOOK_CONNECT(hook_connect, handshake_fd_flags) =
                    fcntl (HOOK_CONNECT(hook_connect, sock), F_GETFL);
                if (HOOK_CONNECT(hook_connect, handshake_fd_flags) == -1)
                    HOOK_CONNECT(hook_connect, handshake_fd_flags) = 0;
                fcntl (HOOK_CONNECT(hook_connect, sock), F_SETFL,
                       HOOK_CONNECT(hook_connect, handshake_fd_flags) | O_NONBLOCK);
                gnutls_transport_set_ptr (*HOOK_CONNECT(hook_connect, gnutls_sess),
                                          (gnutls_transport_ptr) ((ptrdiff_t) HOOK_CONNECT(hook_connect, sock)));
                if (HOOK_CONNECT(hook_connect, gnutls_dhkey_size) > 0)
                {
                    gnutls_dh_set_prime_bits (*HOOK_CONNECT(hook_connect, gnutls_sess),
                                              (unsigned int) HOOK_CONNECT(hook_connect, gnutls_dhkey_size));
                }
                rc = gnutls_handshake (*HOOK_CONNECT(hook_connect, gnutls_sess));
                if ((rc == GNUTLS_E_AGAIN) || (rc == GNUTLS_E_INTERRUPTED))
                {
                    /*
                     * gnutls was unable to proceed with the handshake without
                     * blocking: non fatal error, we just have to wait for an
                     * event about handshake
                     */
                    unhook (HOOK_CONNECT(hook_connect, hook_fd));
                    HOOK_CONNECT(hook_connect, hook_fd) = NULL;
                    direction = gnutls_record_get_direction (*HOOK_CONNECT(hook_connect, gnutls_sess));
                    HOOK_CONNECT(hook_connect, handshake_ip_address) = cb_ip_address;
                    HOOK_CONNECT(hook_connect, handshake_hook_fd) =
                        hook_fd (hook_connect->plugin,
                                 HOOK_CONNECT(hook_connect, sock),
                                 (!direction ? 1 : 0), (direction  ? 1 : 0), 0,
                                 &network_connect_gnutls_handshake_fd_cb,
                                 hook_connect);
                    HOOK_CONNECT(hook_connect, handshake_hook_timer) =
                        hook_timer (hook_connect->plugin,
                                    CONFIG_INTEGER(config_network_gnutls_handshake_timeout) * 1000,
                                    0, 1,
                                    &network_connect_gnutls_handshake_timer_cb,
                                    hook_connect);
                    return WEECHAT_RC_OK;
                }
                else if (rc != GNUTLS_E_SUCCESS)
                {
                    (void) (HOOK_CONNECT(hook_connect, callback))
                        (hook_connect->callback_data,
                         WEECHAT_HOOK_CONNECT_GNUTLS_HANDSHAKE_ERROR,
                         rc,
                         gnutls_strerror (rc),
                         cb_ip_address);
                    unhook (hook_connect);
                    if (cb_ip_address)
                        free (cb_ip_address);
                    return WEECHAT_RC_OK;
                }
                fcntl (HOOK_CONNECT(hook_connect, sock), F_SETFL,
                       HOOK_CONNECT(hook_connect, handshake_fd_flags));
#if LIBGNUTLS_VERSION_NUMBER < 0x02090a
                /*
                 * gnutls only has the gnutls_certificate_set_verify_function()
                 * function since version 2.9.10. We need to call our verify
                 * function manually after the handshake for old gnutls versions
                 */
                if (hook_connect_gnutls_verify_certificates (*HOOK_CONNECT(hook_connect, gnutls_sess)) != 0)
                {
                    (void) (HOOK_CONNECT(hook_connect, callback))
                        (hook_connect->callback_data,
                         WEECHAT_HOOK_CONNECT_GNUTLS_HANDSHAKE_ERROR,
                         rc,
                         "Error in the certificate.",
                         cb_ip_address);
                    unhook (hook_connect);
                    if (cb_ip_address)
                        free (cb_ip_address);
                    return WEECHAT_RC_OK;
                }
#endif
            }
#endif
        }
        else
        {
            /* connection error, read error */
            buf_size[5] = '\0';
            num_read = read (HOOK_CONNECT(hook_connect, child_read),
                             buf_size, 5);
            if (num_read == 5)
            {
                error = NULL;
                size_msg = strtol (buf_size, &error, 10);
                if (error && !error[0] && (size_msg > 0))
                {
                    cb_error = malloc (size_msg + 1);
                    if (cb_error)
                    {
                        num_read = read (HOOK_CONNECT(hook_connect, child_read),
                                         cb_error, size_msg);
                        if (num_read == size_msg)
                            cb_error[size_msg] = '\0';
                        else
                        {
                            free (cb_error);
                            cb_error = NULL;
                        }
                    }
                }
            }
        }
        (void) (HOOK_CONNECT(hook_connect, callback))
            (hook_connect->callback_data, buffer[0] - '0', 0,
             cb_error, cb_ip_address);
        unhook (hook_connect);
    }

    if (cb_error)
        free (cb_error);
    if (cb_ip_address)
        free (cb_ip_address);

    return WEECHAT_RC_OK;
}