main.c 7.64 KB
/*
 * "Software PW3270, desenvolvido com base nos códigos fontes do WC3270  e  X3270
 * (Paul Mattes Paul.Mattes@usa.net), de emulação de terminal 3270 para acesso a
 * aplicativos mainframe. Registro no INPI sob o nome G3270.
 *
 * Copyright (C) <2008> <Banco do Brasil S.A.>
 *
 * Este programa é software livre. Você pode redistribuí-lo e/ou modificá-lo sob
 * os termos da GPL v.2 - Licença Pública Geral  ',  conforme  publicado  pela
 * Free Software Foundation.
 *
 * Este programa é distribuído na expectativa de  ser  útil,  mas  SEM  QUALQUER
 * GARANTIA; sem mesmo a garantia implícita de COMERCIALIZAÇÃO ou  de  ADEQUAÇÃO
 * A QUALQUER PROPÓSITO EM PARTICULAR. Consulte a Licença Pública Geral GNU para
 * obter mais detalhes.
 *
 * Você deve ter recebido uma cópia da Licença Pública Geral GNU junto com este
 * programa; se não, escreva para a Free Software Foundation, Inc., 51 Franklin
 * St, Fifth Floor, Boston, MA  02110-1301  USA
 *
 * Este programa está nomeado como openssl.c e possui - linhas de código.
 *
 * Contatos:
 *
 * perry.werneck@gmail.com	(Alexandre Perry de Souza Werneck)
 * erico.mendonca@gmail.com	(Erico Mascarenhas de Mendonça)
 *
 */

 /**
  * @brief OpenSSL based networking methods.
  *
  */

 #include "private.h"


static void crl_free(LIB3270_NET_CONTEXT *context) {
	if(context->crl.cert) {
		X509_CRL_free(context->crl.cert);
		context->crl.cert = NULL;
	}
}

static void openssl_network_finalize(H3270 *hSession) {

	debug("%s",__FUNCTION__);

	if(hSession->network.context) {

		// Cleanupp
		LIB3270_NET_CONTEXT *context = hSession->network.context;

		crl_free(context);

		// Release network context.
		lib3270_free(hSession->network.context);
		hSession->network.context = NULL;
	}

}

static int openssl_network_disconnect(H3270 *hSession) {

	LIB3270_NET_CONTEXT * context = hSession->network.context;

	if(context->con) {
		SSL_shutdown(context->con);
		SSL_free(context->con);
		context->con = NULL;
	}

	if(context->sock > 0) {
		shutdown(context->sock, 2);
#ifdef _WIN32
		sockclose(context->sock);
#else
		close(context->sock);
#endif // _WIN32
		context->sock = -1;
	}

	return 0;

}

ssize_t openssl_network_send(H3270 *hSession, const void *buffer, size_t length) {

}

static ssize_t openssl_network_recv(H3270 *hSession, void *buf, size_t len) {

}

static int openssl_network_getsockname(const H3270 *hSession, struct sockaddr *addr, socklen_t *addrlen) {

}

static void * openssl_network_add_poll(H3270 *hSession, LIB3270_IO_FLAG flag, void(*call)(H3270 *, int, LIB3270_IO_FLAG, void *), void *userdata) {

}

static int openssl_network_non_blocking(H3270 *hSession, const unsigned char on) {

}

static int openssl_network_is_connected(H3270 *hSession) {

}

static int openssl_network_setsockopt(H3270 *hSession, int level, int optname, const void *optval, size_t optlen) {

}

static int openssl_network_getsockopt(H3270 *hSession, int level, int optname, void *optval, socklen_t *optlen) {
}

static int openssl_network_init(H3270 *hSession, LIB3270_NETWORK_STATE *state) {

	set_ssl_state(hSession,LIB3270_SSL_UNDEFINED);

	SSL_CTX * ctx_context = (SSL_CTX *) lib3270_openssl_get_context(state,state);
	if(!ctx_context)
		return -1;

	LIB3270_NET_CONTEXT * context = hSession->network.context;

	return 0;
}

static int openssl_network_connect(H3270 *hSession, LIB3270_NETWORK_STATE *state) {

	LIB3270_NET_CONTEXT * context = hSession->network.context;

	if(context->crl.cert) {

		// Has CRL, release if expired.
		// https://stackoverflow.com/questions/23407376/testing-x509-certificate-expiry-date-with-c
		// X509_CRL_get_nextUpdate is deprecated in openssl 1.1.0

		#if OPENSSL_VERSION_NUMBER < 0x10100000L
			const ASN1_TIME * next_update = X509_CRL_get_nextUpdate(context->crl.cert);
		#else
			const ASN1_TIME * next_update = X509_CRL_get0_nextUpdate(context->crl.cert);
		#endif

		if(X509_cmp_current_time(next_update) == 1)
		{
			int day, sec;
			if(ASN1_TIME_diff(&day, &sec, NULL, next_update))
			{
				trace_ssl(hSession,"CRL is valid for %d day(s) and %d second(s)\n",day,sec);
			}
			else
			{
				trace_ssl(hSession,"Can't get CRL next update, discarding it\n");
				crl_free(context);
			}

		}
		else
		{
			trace_ssl(hSession,"CRL is no longer valid\n");
			crl_free(context);
		}

	}

	//
	// Enable SSL & Connect to host.
	//
	set_ssl_state(hSession,LIB3270_SSL_UNDEFINED);

	hSession->ssl.host = 1;
	context->sock = lib3270_network_connect(hSession, state);

	return (context->sock < 0 ? -1 : 0);

}

static int openssl_network_start_tls(H3270 *hSession, LIB3270_NETWORK_STATE *state) {

	SSL_CTX * ctx_context = (SSL_CTX *) lib3270_openssl_get_context(state,state);
	if(!ctx_context)
		return -1;

	LIB3270_NET_CONTEXT * context = hSession->network.context;

	debug("%s",__FUNCTION__);

	set_ssl_state(hSession,LIB3270_SSL_NEGOTIATING);
	context->con = SSL_new(ctx_context);
	if(context->con == NULL)
	{
		static const LIB3270_POPUP popup = {
			.type = LIB3270_NOTIFY_SECURE,
			.summary = N_( "Cant create a new SSL structure for current connection." )
		};

		state->popup = &popup;
		return -1;
	}

	SSL_set_ex_data(context->con,lib3270_openssl_get_ex_index(hSession),(char *) hSession);
//	SSL_set_verify(context->con, SSL_VERIFY_FAIL_IF_NO_PEER_CERT, NULL);
	SSL_set_verify(context->con, 0, NULL);

	if(SSL_set_fd(context->con, context->sock) != 1)
	{
		trace_ssl(hSession,"%s","SSL_set_fd failed!\n");

		static const LIB3270_NETWORK_POPUP popup = {
			.summary = N_( "SSL negotiation failed" ),
			.body = N_( "Cant set the file descriptor for the input/output facility for the TLS/SSL (encrypted) side of ssl." )
		};

		state->popup = &popup;
		return -1;

	}

	trace_ssl(hSession, "%s","Running SSL_connect\n");
	int rv = SSL_connect(context->con);
	trace_ssl(hSession, "SSL_connect exits with rc=%d\n",rv);

	if (rv != 1)
	{
		int code = SSL_get_error(context->con,rv);

		if(code == SSL_ERROR_SYSCALL && hSession->ssl.error)
			code = hSession->ssl.error;

		state->error_message = ERR_lib_error_string(code);

		trace_ssl(hSession,"SSL_connect failed: %s\n",ERR_reason_error_string(code));

		static const LIB3270_POPUP popup = {
			.type = LIB3270_NOTIFY_ERROR,
			.summary = N_( "SSL Connect failed" ),
		};

		state->popup = &popup;
		return -1;

	}

	//
	// Connection succeeded, do we need to download the CRL?
	//
	if(lib3270_ssl_get_crl_download(hSession)) {


	} else {

		trace_ssl(hSession,"CRL download is disabled\n");

	}

	return 0;
}

void lib3270_set_openssl_network_module(H3270 *hSession) {

	static const LIB3270_NET_MODULE module = {
		.name = "tn3270s",
		.service = "tn3270s",
		.init = openssl_network_init,
		.finalize = openssl_network_finalize,
		.connect = openssl_network_connect,
		.disconnect = openssl_network_disconnect,
		.start_tls = openssl_network_start_tls,
		.send = openssl_network_send,
		.recv = openssl_network_recv,
		.add_poll = openssl_network_add_poll,
		.non_blocking = openssl_network_non_blocking,
		.is_connected = openssl_network_is_connected,
		.getsockname = openssl_network_getsockname,
		.setsockopt = openssl_network_setsockopt,
		.getsockopt = openssl_network_getsockopt
	};

 	debug("%s",__FUNCTION__);

	if(hSession->network.context) {
		// Has context, finalize it.
		hSession->network.module->finalize(hSession);
	}

	hSession->ssl.host = 1;
	hSession->network.context = lib3270_malloc(sizeof(LIB3270_NET_CONTEXT));
	memset(hSession->network.context,0,sizeof(LIB3270_NET_CONTEXT));

	hSession->network.context->sock = -1;

	hSession->network.module = &module;
}

int lib3270_activate_ssl_network_module(H3270 *hSession, int sock, LIB3270_NETWORK_STATE *state) {

	lib3270_set_openssl_network_module(hSession);

	int rc = openssl_network_init(hSession, state);

	hSession->network.context->sock = sock;

	return rc;

}