Hi, I have developed a Linux-based proxy server that successfully transfers data
between a client and an API server. I am trying to layer OpenSSL onto the client and
proxy server, using s_client & s_server as examples. I am receiving from the client
the error: ...routines:SSL23_WRITE:ssl handshake failure:s23_lib.c:216:
Simplifying my code and viewing s23_lib.c does not help. What am I doing wrong? A
condensed listing of my code follows. Thank-you for taking the time to help me!
/*
* This sample program is a stand-alone client to the API server.
* It works by being passed the input parameter of an input file.
*/
#include <stdio.h>
#include <errno.h>
#include <netdb.h>
#include <unistd.h>
#include <sys/file.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netinet/tcp.h>
#include <arpa/inet.h>
#include <stdlib.h>
#include <ctype.h>
#include <string.h>
#include <limits.h>
#include <errno.h>
#include "api_client.h"
#include "/usr/local/openssl/openssl-0.9.5/apps.h"
#include <openssl/crypto.h>
#include <openssl/ssl.h>
#include <openssl/lhash.h>
#include <openssl/bn.h>
#include <openssl/err.h>
#include <openssl/pem.h>
#include <openssl/e_os.h>
#include <openssl/buffer.h>
#include <openssl/bio.h>
#include <openssl/x509.h>
#include "/usr/local/openssl/openssl-0.9.5/s_apps.h"
#define REMOTE_HOST_URL "192.246.48.16"
#define SERVER_API_PORT 9100
#define LOGIN "rwilliam"
#define PASSWORD "mypassword"
#define SERVICE "myserver"
#define VERBOSE 1
#define TEST_CLIENT_CERT "/usr/local/openssl/openssl-0.9.5/apps/client.pem"
#define TEST_CLIENT_KEY "/usr/local/openssl/openssl-0.9.5/apps/client.pem"
extern char *sys_errlist[];
int connect_to_api_server(int *client_socket, char **error_message);
int disconnect_from_api_server(int *client_socket, char **error_message);
int send_msg(int client_socket, char *in_message, unsigned short message_size, SSL
*con);
void end_program(int client_socket, FILE *input_file);
/*
* Write a TCP message to the api server
*/
int send_msg (int sd, char *msg, unsigned short msg_size, SSL *ssl)
{
int data_size;
int err_code;
int fd = 0;
fd_set writefds;
data_size = (int)(msg_size);
#ifdef VERBOSE
printf("Size of message being sent: %d Msg: %s\n", data_size, msg);
#endif
/* write the data to the server socket */
err_code = (SSL_write (ssl, msg, (unsigned int)data_size));
switch (SSL_get_error(ssl, err_code))
{
case SSL_ERROR_NONE:
printf("No errors in SSL_write\n");
break;
case SSL_ERROR_WANT_WRITE:
printf("write W BLOCK\n");
break;
case SSL_ERROR_WANT_READ:
printf("write W BLOCK\n");
break;
case SSL_ERROR_WANT_X509_LOOKUP:
printf("write X BLOCK\n");
break;
case SSL_ERROR_ZERO_RETURN:
printf("Error zero return\n");
break;
case SSL_ERROR_SYSCALL:
printf("Error syscall\n");
ERR_get_error();
break;
case SSL_ERROR_SSL:
printf("Error ssl\n");
break;
default:
break;
}
ERR_print_errors_fp(stdout);
return 0;
}
/*
* Read a TCP message from the api server
*/
int read_response(int sd, char *msg)
{
int status; /* return status from read() */
/* read msg from server socket */
status = recv (sd, msg, RETURNMSGSIZE, 0);
if (status == -1)
{
/* printf("Module read_response: TCP read error: %s Error reading from socket %d\n",
sys_errlist[errno], sd); */
return TRASHED;
}
else if (status == 0)
{
printf("Module read_response: TCP read: detected broken connection (EOF) on socket
%d\n",
sd);
return EOF;
}
/* else if (status < RETURNMSGSIZE) */
else if (status < 1)
{
/* incorrect read, indicates problems */
printf("Module read_response: TCP read error: read %d bytes, expected %d\n", status,
RETURNMSGSIZE);
return TRASHED;
}
return 0;
}
/*
* Connect to the api server
*/
int connect_to_api_server(int *my_socket, char **error_message)
{
int status;
char remote_host[15];
unsigned long remote_host_address;
int max_buf_size = RETURNMSGSIZE;
char buf[RETURNMSGSIZE];
int client_socket;
struct sockaddr_in cli_addr;
int i;
/* open the socket */
if ((client_socket = socket(AF_INET, SOCK_STREAM, 0)) == -1)
{
sprintf(buf, "Failed to open socket for writing\n");
*error_message = (char *)malloc(strlen(buf) + 1);
if (*error_message != (char *)(NULL))
{
strcpy(*error_message, buf);
}
return -1;
}
/* set up the socket buffers */
if (setsockopt(client_socket, SOL_SOCKET, SO_SNDBUF, &max_buf_size,
sizeof(max_buf_size)) < 0)
{
printf("Setsockopt for SO_SNDBUF failed\n");
return -1;
}
if (setsockopt(client_socket, SOL_SOCKET, SO_RCVBUF, &max_buf_size,
sizeof(max_buf_size)) < 0)
{
printf("Setsockopt for SO_RCVBUF failed\n");
close(client_socket);
return -1;
}
cli_addr.sin_family = AF_INET;
cli_addr.sin_port = htons(SERVER_API_PORT);
/*
* NOTE: remote_host is presumed to be a "XXX.XXX.XXX.XXX" format
* address, instead of a hostname. Interpret the internet address
* using the inet_addr() library routine.
*/
strcpy(remote_host, REMOTE_HOST_URL);
remote_host_address = inet_addr(remote_host);
if (remote_host_address == -1)
{
sprintf(buf, "remote_host %s is a malformed address\n", remote_host);
*error_message = (char *)malloc(strlen(buf) + 1);
if (*error_message != (char *)(NULL))
{
strcpy(*error_message, buf);
}
close(client_socket);
}
else
{
cli_addr.sin_addr.s_addr = remote_host_address;
}
for (i=0; i<8; i++)
{
cli_addr.sin_zero[i] = 0;
}
/* start a connection */
#ifdef VERBOSE
printf("Getting ready to connect\n");
#endif
if ((status = connect(client_socket, (struct sockaddr *)(&cli_addr),
sizeof(cli_addr))) != 0)
{
/*
sprintf(buf, "Connect failed: %s; Errno: %d\n", sys_errlist[errno], errno);
*error_message = (char *)malloc(strlen(buf) + 1);
if (*error_message != (char *)(NULL))
{
strcpy(*error_message, buf);
}
*/
close(client_socket);
return -1;
}
*my_socket = client_socket;
return 0;
}
/*
* API Client Program
*/
int main (int argc, char **argv)
{
int status, i;
int client_socket;
int transaction_id;
char *path_to_input_file = (char *)(NULL);
char *p_error_message = (char *)(NULL);
char in_buffer[MAXDATASIZE];
char new_in_buffer[MAXDATASIZE+PROXYHEADERSIZE+1];
char proxy_buf[PROXYHEADERSIZE+1];
char msg_hdr[MESSAGEHEADERSIZE+1];
char out_buffer[RETURNMSGSIZE];
char *p_char;
char buf[RETURNMSGSIZE];
FILE *input_file = (FILE *)(NULL);
unsigned short data_size;
int s, off = 0, verify = SSL_VERIFY_NONE;
SSL *con = NULL;
SSL_METHOD *meth = NULL;
SSL_CTX *ctx = NULL;
X509 *server_cert;
BIO *sbio;
char CApath[] = "/usr1/devfs5/arms/devl/src/c/api";
char CAfile[] = "/usr1/devfs5/arms/devl/src/c/api/cert.pem";
char *cert_file=NULL, *key_file=NULL;
char *client_cert = TEST_CLIENT_CERT;
char *client_key = TEST_CLIENT_KEY;
/* ssl */
meth = SSLv23_client_method();
apps_startup(); /* not sure about this, but most every OpenSSL program includes it */
OpenSSL_add_ssl_algorithms();
ctx = SSL_CTX_new(meth);
if(ctx == NULL) printf(" NULL CTX! - die!\n");
SSL_CTX_set_options(ctx, off);
SSL_CTX_set_cipher_list(ctx, "SSL_CIPHER");
SSL_CTX_set_verify(ctx, SSL_VERIFY_PEER | SSL_VERIFY_FAIL_IF_NO_PEER_CERT, NULL);
if (SSL_CTX_use_certificate_file(ctx, client_cert, SSL_FILETYPE_PEM) <= 0)
{
printf("Cannot use_certificate_file! - die!\n");
ERR_print_errors_fp(stdout);
}
if (SSL_CTX_use_PrivateKey_file(ctx, client_key, SSL_FILETYPE_PEM) <= 0)
{
printf("Cannot use_PrivateKey_file! - die!\n");
ERR_print_errors_fp(stdout);
}
if (!SSL_CTX_load_verify_locations (ctx, CAfile, CApath))
{
printf("Cannot load_verify_locations! - die!\n");
ERR_print_errors_fp(stdout);
}
if (!SSL_CTX_set_default_verify_paths(ctx))
{
printf("Cannot set_default_verify! - die!\n");
ERR_print_errors_fp(stdout);
}
SSL_load_error_strings();
con = SSL_new(ctx);
if(con == NULL) printf(" NULL CON! - die!\n");
/* parse arguments */
for (i=0; i< argc; i++)
{
if (!strcmp(argv[i], "-i"))
{
i++;
path_to_input_file = argv[i];
}
}
/* check our parameters - we need an input file */
if (path_to_input_file == (char *)(NULL))
{
printf("usage: %s -i <input_file>\n", argv[0]);
end_program(client_socket, input_file);
exit(-1);
}
/* open the input file */
input_file = fopen(path_to_input_file, "r");
if (input_file == (FILE *)(NULL))
{
printf("%s: Unable to open %s for reading\n", argv[0],
path_to_input_file);
end_program(client_socket, input_file);
exit(-1);
}
/* start up our connection to the api server */
status = connect_to_api_server(&client_socket, &p_error_message);
if (status != 0)
{
printf("Unable to connect to api_server: %s\n", p_error_message);
fclose(input_file);
end_program(client_socket, input_file);
exit(-1);
}
#ifdef VERBOSE
printf("Connected to api_server\n");
#endif
/* ssl */
sbio = BIO_new_socket(s,BIO_NOCLOSE);
SSL_set_bio(con, sbio, sbio);
SSL_set_connect_state(con);
SSL_set_fd(con, client_socket);
SSL_connect(con);
SSL_get_cipher(con);
/*
* First we need to send the transaction header to the api server
*/
data_size = 72;
memset(proxy_buf, ' ', 72);
p_char = proxy_buf;
memcpy(p_char, LOGIN, sizeof(LOGIN)-1);
p_char += 24;
memcpy(p_char, PASSWORD, sizeof(PASSWORD)-1);
p_char += 24;
memcpy(p_char, SERVICE, sizeof(SERVICE)-1);
p_char += 24;
/* send the transaction-header message to the api server. */
status = send_msg(client_socket, proxy_buf, data_size, con);
}
} /* end main */
void end_program(int client_socket, FILE *input_file)
{
close(client_socket);
fclose(input_file);
}
------------------------------------------------------------
/*
* This program is a portion of a API proxy transfer server
* that is called via inetd, utilizing OpenSSL. For
* simplicity, most of the server-side code is deleted.
*/
#include <stdio.h>
#include <errno.h>
#include <netdb.h>
#include <unistd.h>
#include <sys/file.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netinet/tcp.h>
#include <arpa/inet.h>
#include <stdlib.h>
#include <ctype.h>
#include <string.h>
#include <limits.h>
#include <signal.h>
#include <search.h>
#include <sys/time.h>
#include <cstypes.h>
#include "api_xfer.h"
#include "stringlib.h"
#include "/usr/local/openssl/openssl-0.9.5/apps/apps.h"
#include <openssl/crypto.h>
#include <openssl/ssl.h>
#include <openssl/lhash.h>
#include <openssl/bn.h>
#include <openssl/err.h>
#include <openssl/pem.h>
#include <openssl/e_os.h>
#include <openssl/buffer.h>
#include <openssl/bio.h>
#include <openssl/x509.h>
#include "/usr/local/openssl/openssl-0.9.5/apps/s_apps.h"
#define TEST_SERVER_CERT "/home/www/code/arms/api_xfer/server.pem"
#define TEST_SERVER_KEY "/home/www/code/arms/api_xfer/ca-key.pem"
#define OPENSSL_C /* tells apps.h to use complete apps_startup() */
#define SSLeay_add_ssl_algorithms() SSL_library_init()
#define OpenSSL_add_ssl_algorithms() SSL_library_init()
int client_socket; /* socket descriptor for server socket */
int server_socket; /* socket descriptor for client socket */
FILE *log_file; /* log file for all errors, events */
char log_file_dir[40];
char full_file_path[256];
unsigned char client_msg[MAXDATASIZE];
unsigned char client_resp[MAXDATASIZE];
char trans_hdr[PROXYHDRSIZE];
struct servent *arms_service;
static BIO *bio_stdout=NULL;
static const char rnd_seed[] = "string to make the random number generator think it
has entropy";
/*
* FUNCTION connect_to_api_client
* Connect to the api client
*/
int connect_to_api_client(int *my_socket, char **error_message)
{
char remote_host[15];
unsigned long remote_host_address;
struct sockaddr_in cli_addr;
struct linger linger;
int max_buf_size = MAXDATASIZE;
int addrlen;
int i;
/* get the address of the client-side socket */
addrlen = sizeof(cli_addr);
if (getpeername(0, (struct sockaddr *) &cli_addr, &addrlen) < 0)
{
fprintf(log_file, "Getpeername failed: %s\n",sys_errlist[errno]);
fflush(log_file);
close(0); close(1); close(2);
exit (-1);
}
/* since we don't know who might connect, we'll cheat and hard-code our proxy
address */
cli_addr.sin_family = AF_INET;
cli_addr.sin_port = htons(CLIENT_API_PORT);
strcpy(remote_host, REDHOOK_HOST_URL);
remote_host_address = inet_addr(remote_host);
cli_addr.sin_addr.s_addr = remote_host_address;
for (i=0; i<8; i++)
{
cli_addr.sin_zero[i] = 0;
}
fprintf(log_file, "Remote_host: %s Remote_host_addr: %ld\n", remote_host,
remote_host_address);
/* set our client-side socket options */
linger.l_onoff = 1;
linger.l_linger = 60;
if (setsockopt(0, SOL_SOCKET, SO_LINGER, (char *) &linger, sizeof(linger)) < 0)
{
fprintf(log_file, "Setsockopt for SO_LINGER failed\n"); /* may not be an error? */
fflush(log_file);
}
if (setsockopt(0, SOL_SOCKET, SO_SNDBUF, &max_buf_size, sizeof(max_buf_size)) < 0)
{
fprintf(log_file, "Setsockopt for SO_SNDBUF failed\n");
fflush(log_file);
close(0); close(1); close(2);
exit(-1);
}
if (setsockopt(0, SOL_SOCKET, SO_RCVBUF, &max_buf_size, sizeof(max_buf_size)) < 0)
{
fprintf(log_file, "Setsockopt for SO_RCVBUF failed\n");
fflush(log_file);
close(0); close(1); close(2);
exit(-1);
}
client_socket = 1; /* socket (write) */
fprintf(log_file, "Connected to client successfully with client_socket %d.\n",
client_socket);
fflush(log_file);
*my_socket = server_socket;
return 0;
}
/*
* FUNCTION main
* API Proxy Transfer Server Program
*/
void main (int argc, char **argv)
{
int status, i, message_length;
char *p_error_message = (char *)(NULL);
char out_buffer[MAXDATASIZE];
char buf[MAXDATASIZE];
char proxy_buf[MAXDATASIZE];
char msg_len[MESSAGEIDSIZE+RETURNCODESIZE];
char *p_char;
char *message;
char proxy_login[LOGINIDSIZE];
char proxy_passwd[PASSWORDSIZE];
char proxy_file_login[MAXDATASIZE];
char proxy_file_passwd[MAXDATASIZE];
char crypt_passwd[MAXDATASIZE];
char salt[3];
unsigned short data_size;
FILE *fp;
int maxfd, nfound;
fd_set readFds;
struct timeval timeout;
int s, err;
SSL *con = NULL;
SSL_CTX *ctx = NULL;
BIO *sbio;
SSL_METHOD *meth = NULL;
unsigned long sl=1;
X509 *client_cert;
char *CApath = NULL;
char CAfile[] = "/home/www/code/arms/api_xfer/cert.pem";
char *server_cert = TEST_SERVER_CERT;
char *server_key = TEST_SERVER_KEY;
/* open a log file */
GetPrivateProfileString("LOGINFO","LogFileDir","",log_file_dir,
sizeof(log_file_dir), INIFILE);
sprintf(full_file_path, "%s/%s", log_file_dir, "api_xfer.log");
if ((log_file = fopen(full_file_path, "a")) == (FILE *)(NULL))
{
close(0); close(1); close(2);
exit(-1);
}
/* ssl */
CRYPTO_malloc_init(); /* not sure about this */
CRYPTO_mem_ctrl(CRYPTO_MEM_CHECK_ON);
RAND_seed(rnd_seed, sizeof rnd_seed);
RAND_load_file ("random.log", 1024);
bio_err = BIO_new_fp(stderr, BIO_NOCLOSE);
bio_stdout = BIO_new_fp(stdout, BIO_NOCLOSE);
SSL_load_error_strings();
OpenSSL_add_ssl_algorithms();
SSL_library_init();
meth = SSLv23_server_method();
apps_startup();
ctx = SSL_CTX_new(meth);
if (ctx == NULL)
{
fprintf(log_file, "Error in SSL_CTX_new.\n");
fflush(log_file);
ERR_print_errors_fp(log_file);
}
if (SSL_CTX_use_certificate_file(ctx, server_cert, SSL_FILETYPE_PEM) < 0)
{
fprintf(log_file, "Error in SSL_CTX_use_certificate_file.\n");
fflush(log_file);
ERR_print_errors_fp(log_file);
}
if (SSL_CTX_use_RSAPrivateKey_file(ctx, server_key, SSL_FILETYPE_PEM) < 0)
{
fprintf(log_file, "Error in SSL_CTX_use_RSAPrivateKey_file.\n");
fflush(log_file);
ERR_print_errors_fp(log_file);
}
if (SSL_CTX_check_private_key(ctx) < 0)
{
fprintf(log_file, "Error in SSL_CTX_check_private_key.\n");
fflush(log_file);
ERR_print_errors_fp(log_file);
}
if (!SSL_CTX_load_verify_locations (ctx, CAfile, CApath))
{
fprintf(log_file, "Cannot load_verify_locations! - die!\n");
fflush(log_file);
ERR_print_errors_fp(log_file);
}
SSL_CTX_set_client_CA_list(ctx, SSL_load_client_CA_file(CAfile));
if (!SSL_CTX_set_default_verify_paths(ctx))
{
fprintf(log_file, "Cannot set_default_verify_paths! - die!\n");
fflush(log_file);
ERR_print_errors_fp(log_file);
}
/* set timeout for select() calls (waiting for read/write) */
timeout.tv_sec = 60;
timeout.tv_usec = 0;
/* set server socket descriptor bits */
FD_ZERO (&readFds);
FD_SET (server_socket, &readFds);
maxfd = server_socket;
/* set client socket descriptor bits */
FD_ZERO (&readFds);
FD_SET (client_socket, &readFds);
maxfd = client_socket;
/*
* Start up our connection to the api client
*/
status = connect_to_api_client(&client_socket, &p_error_message);
if (status != 0)
{
strcpy(msg_len, "-4");
fprintf(log_file, "You are Unable to connect to api_client: %s\n",
p_error_message);
shutdown_proxy_server(msg_len);
}
/* ssl */
if (BIO_socket_ioctl(s,0,&sl) < 0)
{
fprintf(log_file, "BIO_socket_ioctl error.\n");
fflush (log_file);
}
sbio = BIO_new_socket(s, BIO_NOCLOSE);
SSL_set_bio(con,sbio,sbio);
SSL_set_accept_state(con);
SSL_use_RSAPrivateKey(con, (RSA *)"server.rsa");
SSL_use_certificate(con, (X509 *)"server.cert");
con = SSL_new(ctx);
SSL_set_fd(con, client_socket);
if (SSL_accept(con) <= 0)
{
fprintf(log_file, "SSL_accept error.\n");
fflush(log_file);
ERR_print_errors_fp(log_file);
fflush(log_file);
}
if (con == NULL)
{
fprintf(log_file, "Connection struct 'con' not established - error\n");
fflush(log_file);
}
fprintf(log_file, "SSL connection using cipher: %s\n", SSL_get_cipher(con));
fflush(log_file);
client_cert = SSL_get_peer_certificate(con);
if (client_cert == NULL)
{
fprintf(log_file, "Client does not have a certificate.\n");
fflush(log_file);
}
fprintf(log_file, "Ready to read the client's transaction hdr.\n");
fflush(log_file);
/*
* Read the client's message
*/
for(;;)
{
nfound = select (maxfd+1, &readFds, NULL, NULL, &timeout);
if (nfound <= 0)
{
strcpy(msg_len, "-1");
if (nfound == 0)
fprintf(log_file, "Select() returned zero; Unable to read client data.\n");
else
fprintf(log_file, "Unable to Select data: %s\n", sys_errlist[errno]);
shutdown_proxy_server(msg_len);
}
if (nfound > 0)
{
status = SSL_read (ssl, trans_hdr, PROXYHDRSIZE);
if (status < 0)
{
strcpy(msg_len, "-1");
fprintf(log_file, "Unable to read a msg from the API client\n");
shutdown_proxy_server(msg_len);
}
else fprintf("Read the message: %s\n", trans_hdr);
}
exit(0);
}
} /* end main */
Rodger Williams
Systems Specialist
Illuminet, Inc
(360)923-3498
Fax: (360)923-3400
[EMAIL PROTECTED]
______________________________________________________________________
OpenSSL Project http://www.openssl.org
User Support Mailing List [EMAIL PROTECTED]
Automated List Manager [EMAIL PROTECTED]