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]

Reply via email to