Re: ssl client write / server accept seems broken

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



IM inclined top think the code for the certs is ok, but  can really say, and im not an openssl programmer by any means... just need someone to put eyes on the code and fix it really.


The cert looks ok - at least nothing obviously wrong. 2048 bit RSA key.

yes freshly generated

when i run the client - i get an error on the client side Tue Mar 23 02:13:58 2021 user.err : ac_ssl_client_write(): Error SSL_ERROR_SSL - return code: -1. Tue Mar 23 02:13:58 2021 user.info : ac_send_init(): Error

It would be useful to see any errors on the OpenSSL error stack which might provide more details about specifically what has failed. For example you can call the `ERR_print_errors_fp` function to dump the error stack to a `FILE *`. Or alternatively use the `ERR_*` functions to examine the stack and print it to your log:

Yupp above my head.... :(

Ah. That's a shame - we could really use understanding the real error behind this. "SSL_ERROR_SSL" just means "libssl encountered an error". You have to modify your code to print more detailed error information

There doesn't look to be anything obviously wrong from the snippets of code that you have shared. I suspect some kind of config issue - but without more detailed error information its difficult to say for sure.

Would you be able to get a packet capture of a failing connection? That might give us some kind of clue.

Do you know if your application is statically linked or dynamically linked to OpenSSL?
Ive attached the code in question if it helps

just compiled with gcc, i see no -lstatic in the makefile ... ive attached the ssl .c and .h files in question if you want to see them

as for a packet capture i can try, they are both remote systems




and lastly if it helps


Unfortunately, not really. This appears to show a working TLSv1.3 connection.

Matt

#include <ac_ssl.h>
#include <ac_logging.h>

/* Transforms the error code from SSL function to more meaningful message - check man SSL_get_error */
int ac_ssl_handle_err(ac_ssl_conn_t *ssl_con, int ret_val, const char* custom_prefix, const char* custom_msg)
{
	int err_code;
        if (!ret_val)
               return 0;
	
	err_code = SSL_get_error(ssl_con->ssl, ret_val);
	
	switch(err_code) {
		case SSL_ERROR_NONE:
			return 0;
		case SSL_ERROR_ZERO_RETURN:
			LOG(LOG_ERR, "%s: Error SSL_ERROR_ZERO_RETURN - return code: %d. %s\n", custom_prefix, ret_val, custom_msg);
			break;
		case SSL_ERROR_WANT_READ:
			LOG(LOG_ERR, "%s: Error SSL_ERROR_WANT_READ - return code: %d. %s\n", custom_prefix, ret_val, custom_msg);
			break;
		case SSL_ERROR_WANT_WRITE:
			LOG(LOG_ERR, "%s: Error SSL_ERROR_WANT_WRITE - return code: %d. %s\n", custom_prefix, ret_val, custom_msg);
			break;
		case SSL_ERROR_WANT_CONNECT:
			LOG(LOG_ERR, "%s: Error SSL_ERROR_WANT_CONNECT - return code: %d. %s\n", custom_prefix, ret_val, custom_msg);
			break;
		case SSL_ERROR_WANT_ACCEPT:
			LOG(LOG_ERR, "%s: Error SSL_ERROR_WANT_ACCEPT - return code: %d. %s\n", custom_prefix, ret_val, custom_msg);
			break;
		case SSL_ERROR_WANT_X509_LOOKUP:
			LOG(LOG_ERR, "%s: Error SSL_ERROR_WANT_X509_LOOKUP - return code: %d. %s\n", custom_prefix, ret_val, custom_msg);
			break;
		case SSL_ERROR_SYSCALL:
				LOG(LOG_ERR, "%s: Error SSL_ERROR_SYSCALL - return code: %d. %s\n", custom_prefix, ret_val, custom_msg);
			break;
		case SSL_ERROR_SSL:
			LOG(LOG_ERR, "%s: Error SSL_ERROR_SSL - return code: %d. %s\n", custom_prefix, ret_val, custom_msg);
			break;
	}
	
	ERR_print_errors_fp(stderr);fflush(stderr);
	
	return 1;
}

#ifndef _AC_SSL_H_
#define _AC_SSL_H_

#include <ac.h>

#include <string.h>
#include <stdlib.h>

#include <openssl/ssl.h>
#include <openssl/err.h>
#include <openssl/md5.h>

typedef struct _ssl_conn {
	int socket;
	SSL_CTX *ctx;
	SSL *ssl;
	char* server;
	int port;
	char* key_file;
	char* key_pass;
	char* cert_file;
	char* ca_file;
} ac_ssl_conn_t;


int ac_ssl_client_init(ac_ssl_conn_t *ssl_con);
int ac_ssl_client_connect(ac_ssl_conn_t *ssl_con);
int ac_ssl_client_read(ac_ssl_conn_t *ssl_con, void *buf, int buf_len);
int ac_ssl_client_write(ac_ssl_conn_t *ssl_con, void *buf, int buf_len);
int ac_ssl_client_close(ac_ssl_conn_t *ssl_con);

int ac_ssl_server_init(ac_ssl_conn_t *ssl_con);
int ac_ssl_server_accept(ac_ssl_conn_t *ssl_con);
int ac_ssl_server_peer_name(ac_ssl_conn_t *ssl_con, char *cname, int cname_len);
int ac_ssl_server_read(ac_ssl_conn_t *ssl_con, void *buf, int buf_len);
int ac_ssl_server_write(ac_ssl_conn_t *ssl_con, void *buf, int buf_len);
int ac_ssl_server_close(ac_ssl_conn_t *ssl_con);

/* this is common function for both server and client, but it's declared in ac_client.c I think it's useless for now to move it in its own source file */
int ac_ssl_handle_err(ac_ssl_conn_t *ssl_con, int ret_val, const char* custom_prefix, const char* custom_msg);

#endif

#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netdb.h>
#include <unistd.h>

#include <ac_client.h>
#include <ac_ssl.h>
#include <ac_logging.h>

/* Initialize SSL Library */
int ac_ssl_client_init(ac_ssl_conn_t *ssl_con)
{
	SSL_library_init();

	return 0;
}

/* Create Client Socket */
int ac_ssl_client_socket(ac_ssl_conn_t *ssl_con)
{
	struct hostent *he = NULL;        
	struct sockaddr_in their_addr;
	int i = 0;

	if ((he = gethostbyname(ssl_con->server)) == NULL) {
		LOG(LOG_ERR, "gethostbyname: %s\n", strerror(errno));
		return -1;
	}

	if ((ssl_con->socket = socket(AF_INET, SOCK_STREAM, 0)) == -1) {
		LOG(LOG_ERR, "socket: %s\n", strerror(errno));
		return -1;
	}

	if (setsockopt(ssl_con->socket, SOL_SOCKET, SO_KEEPALIVE, (char *)&i, sizeof(i)) == -1) {
		LOG(LOG_ERR, "setsockopt: %s\n", strerror(errno));
		return -1;
	}

	their_addr.sin_family = AF_INET;
	their_addr.sin_port = htons(ssl_con->port);
	their_addr.sin_addr = *((struct in_addr *)he->h_addr);

	if (connect(ssl_con->socket, (struct sockaddr *)&their_addr, sizeof(their_addr)) == -1) {
		LOG(LOG_ERR, "connect: %s\n", strerror(errno));
		return -1;
	}

	return 0;
}

/* Load Certficate/Key Files */
int ac_ssl_client_certs(ac_ssl_conn_t *ssl_con)
{
	int res;
	if ((ssl_con->ctx = SSL_CTX_new(TLS_server_method())) == NULL) {	
                LOG(LOG_ERR, "Error SSL_CTX_new()\n");
                return -1;
        }


	if((res = SSL_CTX_load_verify_locations(ssl_con->ctx, ssl_con->ca_file, NULL)) != 1) {
		LOG(LOG_ERR, "Error loading CA certificate %s.\n", ssl_con->ca_file);
		return -2;
	}
	
	SSL_CTX_set_default_verify_paths(ssl_con->ctx);
	
	if((res = SSL_CTX_use_certificate_file(ssl_con->ctx, ssl_con->cert_file, SSL_FILETYPE_PEM)) != 1) {
		LOG(LOG_ERR, "Error loading certificate %s.\n", ssl_con->cert_file);
		return -4;
	}
	
	if((res = SSL_CTX_use_PrivateKey_file(ssl_con->ctx, ssl_con->key_file, SSL_FILETYPE_PEM)) != 1) {
		LOG(LOG_ERR, "Error loading private key %s.\n", ssl_con->key_file);
		return -5;
	}

	if((res = SSL_CTX_check_private_key(ssl_con->ctx)) != 1) {
		ac_ssl_handle_err(ssl_con, res, "ac_ssl_client_certs()", "");
		LOG(LOG_ERR, "SSL_CTX_check_private_key(): Certificate/Key Mismatch\n");
		return -6;
	}

#if 0
	/* Set to require peer (client) certificate verification */
	SSL_CTX_set_verify(ssl_con->ctx, SSL_VERIFY_PEER, NULL);

	/* Set the verification depth to 1 */
	SSL_CTX_set_verify_depth(ssl_con->ctx, 1);
#endif

	return 0;
}

/* Connect Client to SSL/TLS-enabled Server */
int ac_ssl_client_connect(ac_ssl_conn_t *ssl_con)
{
	int rc = -1;

	if ((rc = ac_ssl_client_socket(ssl_con)) != 0) {
		LOG(LOG_ERR, "ac_ssl_client_socket(): Error code %d\n", rc);
		close(ssl_con->socket);
		return -1;
	}

	if ((rc = ac_ssl_client_certs(ssl_con)) != 0) {
		LOG(LOG_ERR, "ac_ssl_client_certs(): Error code %d\n", rc);
		close(ssl_con->socket);
		if (ssl_con->ctx != NULL)
			SSL_CTX_free(ssl_con->ctx);
		return -1;
	}

	if ((ssl_con->ssl = SSL_new(ssl_con->ctx)) == NULL) {
		LOG(LOG_ERR, "SSL_new(): Error\n");
		close(ssl_con->socket);
		if (ssl_con->ctx != NULL)
			SSL_CTX_free(ssl_con->ctx);		
		return -1;
	}

	SSL_set_fd(ssl_con->ssl, ssl_con->socket);
	SSL_set_connect_state(ssl_con->ssl);

	rc = SSL_connect(ssl_con->ssl);
	if(ac_ssl_handle_err(ssl_con, rc, "ac_ssl_client_connect()", "") != 0) {
		SSL_shutdown(ssl_con->ssl);
		close(ssl_con->socket);
		SSL_free(ssl_con->ssl);
		SSL_CTX_free(ssl_con->ctx);
		return -1;
	}

	return 0;
}

/* Read Data from SSL Connection */
int ac_ssl_client_read(ac_ssl_conn_t *ssl_con, void *buf, int buf_len)
{
	fd_set read_fds;
	struct timeval tv;
	int rc = -1;

	tv.tv_sec = TIMEOUT_READ;
	tv.tv_usec = 0;

	FD_ZERO(&read_fds);
	FD_SET(ssl_con->socket, &read_fds);


	if ((rc = select(ssl_con->socket + 1, &read_fds, NULL, NULL, &tv)) == 1) {
		if (FD_ISSET(ssl_con->socket, &read_fds)) {
			rc = SSL_read(ssl_con->ssl, buf, buf_len);

			if(ac_ssl_handle_err(ssl_con, rc, "ac_ssl_client_read()", "") != 0)
				return -1;
		}
	}

	FD_CLR(ssl_con->socket, &read_fds);

	return rc;
}

/* Write Data to SSL Connection */
int ac_ssl_client_write(ac_ssl_conn_t *ssl_con, void *buf, int buf_len)
{
	fd_set write_fds;
	struct timeval tv;
	int rc = -1;

	tv.tv_sec = TIMEOUT_WRITE;
	tv.tv_usec = 0;

	FD_ZERO(&write_fds);
	FD_SET(ssl_con->socket, &write_fds);


	if ((rc = select(ssl_con->socket + 1, NULL, &write_fds, NULL, &tv)) == 1) {
		if (FD_ISSET(ssl_con->socket, &write_fds)) {
			rc = SSL_write(ssl_con->ssl, buf, buf_len);

			if(ac_ssl_handle_err(ssl_con, rc, "ac_ssl_client_write()", "") != 0)
				return -1;
		}
	}

	FD_CLR(ssl_con->socket, &write_fds);
			
	return rc;
}

/* End SSL/TLS Connection */
int ac_ssl_client_close(ac_ssl_conn_t *ssl_con)
{
	SSL_shutdown(ssl_con->ssl);
	close(ssl_con->socket);
	SSL_free(ssl_con->ssl);
	SSL_CTX_free(ssl_con->ctx);

	return 0;
}
#include <unistd.h>

#include <ac_server.h>
#include <ac_ssl.h>
#include <ac_logging.h>

/* Initialize SSL Library */
int ac_ssl_server_init(ac_ssl_conn_t *ssl_con)
{
	SSL_library_init();

	return 0;
}

/* Load Certficate/Key Files */
int ac_ssl_server_certs(ac_ssl_conn_t *ssl_con)
{
	int res;
	if ((ssl_con->ctx = SSL_CTX_new(TLS_server_method())) == NULL) {	
		LOG(LOG_ERR, "Error SSL_CTX_new()\n");
		return -1;
	}

	SSL_CTX_load_verify_locations(ssl_con->ctx, ssl_con->ca_file, NULL);
       if (!ssl_con->ca_file) {
               LOG(LOG_ERR, "ca_file not set\n");
               return -1;
       }

       if (SSL_CTX_load_verify_locations(ssl_con->ctx, ssl_con->ca_file, NULL) == 0) {
               LOG(LOG_ERR, "Error SSL_CTX_load_verify_locations()\n");
               return -1;
       }


	SSL_CTX_set_default_verify_paths(ssl_con->ctx);
	SSL_CTX_use_certificate_file(ssl_con->ctx, ssl_con->cert_file, SSL_FILETYPE_PEM);
	SSL_CTX_use_PrivateKey_file(ssl_con->ctx, ssl_con->key_file, SSL_FILETYPE_PEM);

	if((res = SSL_CTX_check_private_key(ssl_con->ctx)) != 1) {
		ac_ssl_handle_err(ssl_con, res, "ac_ssl_client_certs()", "SSL_CTX_check_private_key()");
		return -2;
	}

	/* Set to require peer (client) certificate verification */
	SSL_CTX_set_verify(ssl_con->ctx, SSL_VERIFY_PEER, NULL);

	/* Set the verification depth to 1 */
	SSL_CTX_set_verify_depth(ssl_con->ctx, 1);

	return 0;
}

/* Accept SSL Connection */
int ac_ssl_server_accept(ac_ssl_conn_t *ssl_con)
{
	int rc = -1;
	/* Load Key and Certficates */
	if ((rc = ac_ssl_server_certs(ssl_con)) != 0) {
		LOG(LOG_ERR, "ac_ssl_server_certs(): Error code %d\n", rc);
		return -1;
	}

	if ((ssl_con->ssl = SSL_new(ssl_con->ctx)) == NULL) {
		LOG(LOG_ERR, "SSL_new(): Error\n");
		close(ssl_con->socket);
		if (ssl_con->ctx != NULL)
			SSL_CTX_free(ssl_con->ctx);		
		return -2;
	}

	SSL_set_fd(ssl_con->ssl, ssl_con->socket);
	SSL_set_accept_state(ssl_con->ssl);

	rc = SSL_accept(ssl_con->ssl);
	if(ac_ssl_handle_err(ssl_con, rc, "ac_ssl_server_accept()", "SSL_accept()") == 1)
		return -3;


	return 0;
}

/* Obtain Peer Common Name */
int ac_ssl_server_peer_name(ac_ssl_conn_t *ssl_con, char *cname, int cname_len)
{
	X509 *client_cert = NULL;
	char *str = NULL, *t = NULL;

	if (cname == NULL)
		return -1;

	/* Get the client's certificate (optional) */
	if ((client_cert = SSL_get_peer_certificate(ssl_con->ssl)) != NULL)  {
		str = X509_NAME_oneline(X509_get_subject_name(client_cert), 0, 0);

		/* Get the CN here or return error */		
		if ((t = strstr(str, "CN=")) != NULL) {
			memcpy(cname, t + 3, cname_len);
		} else {
			free(str);
			X509_free(client_cert);
			return -1;
		}

		free (str);
		X509_free(client_cert);
	} else
		return -1;

	return 0;
}

/* Read Data from SSL Connection */
int ac_ssl_server_read(ac_ssl_conn_t *ssl_con, void *buf, int buf_len)
{
	fd_set read_fds;
	struct timeval tv;
	int rc = -1;

	tv.tv_sec = TIMEOUT_READ;
	tv.tv_usec = 0;

	FD_ZERO(&read_fds);
	FD_SET(ssl_con->socket, &read_fds);

	if ((rc = select(ssl_con->socket + 1, &read_fds, NULL, NULL, &tv)) == 1) {
		if (FD_ISSET(ssl_con->socket, &read_fds)) {
			rc = SSL_read(ssl_con->ssl, buf, buf_len);

			if(ac_ssl_handle_err(ssl_con, rc, "ac_ssl_server_read()", "") != 0)
				return -1;
		}
	}

	FD_CLR(ssl_con->socket, &read_fds);

	return rc;
}

/* Write Data to SSL Connection */
int ac_ssl_server_write(ac_ssl_conn_t *ssl_con, void *buf, int buf_len)
{
	fd_set write_fds;
	struct timeval tv;
	int rc = -1;

	tv.tv_sec = TIMEOUT_WRITE;
	tv.tv_usec = 0;

	FD_ZERO(&write_fds);
	FD_SET(ssl_con->socket, &write_fds);


	if ((rc = select(ssl_con->socket + 1, NULL, &write_fds, NULL, &tv)) == 1) {
		if (FD_ISSET(ssl_con->socket, &write_fds)) {
			rc = SSL_write(ssl_con->ssl, buf, buf_len);

			if(ac_ssl_handle_err(ssl_con, rc, "ac_ssl_server_write()", "") != 0)
				return -1;
		}
	}

	FD_CLR(ssl_con->socket, &write_fds);		

	return rc;
}

/* End SSL/TLS Connection */
int ac_ssl_server_close(ac_ssl_conn_t *ssl_con)
{
	SSL_shutdown(ssl_con->ssl);
	close(ssl_con->socket);
	SSL_free(ssl_con->ssl);
	SSL_CTX_free(ssl_con->ctx);

	return 0;
}


[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[Index of Archives]     [Linux ARM Kernel]     [Linux ARM]     [Linux Omap]     [Fedora ARM]     [IETF Annouce]     [Security]     [Bugtraq]     [Linux]     [Linux OMAP]     [Linux MIPS]     [ECOS]     [Asterisk Internet PBX]     [Linux API]

  Powered by Linux