Hi,

I'm trying to create an library for transfering special info between
an client and a webserver. But I have run into some strange problems.

I can connect to all kinds of webservers but one is allways failing.

I've debugged with returning the sslstate within the program, giving me:

Before connect
Before ssl connect
SSL_connect:before/connect initialization
SSL_connect:SSLv3 write client hello A
SSL_connect:error in SSLv3 read server hello A
SSL connect failed
Out

If I run the openssl program using the s_client option I can get
it to work... What am i doing wrong ???


Source code:

testssl.c :
#include <stdio.h>


int main (int argc, char **argv)
{
        char ticket[100000];
        int t=0;
        char call[] = "GET /\n\n";
        char host[] = "www.paynet.no";
        int port = 443;

        memset(ticket,0,100000);



        sendSSL(call, strlen(call), ticket, 100000, host, port);


        printf("Out %s\n", ticket);
}



sslclient.c :

/*
 * An SSL simple client
 *
 * This is a simple client. The client will try to open a socket
 * on a specified port. This socket is hereafter read until
 *
 */


#include <stdio.h>
#include <stdlib.h>

#ifdef WINNT
#include <winsock2.h>
#else
#include <netdb.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#endif

// #include <sys/types.h>


#include "ssl.h"
#include "sslclient.h"

#define PROTOCOL "tcp"
#define MESSAGE_EXTEND 2048

static char sslclient_error_[4096];
static char *skeyphrase;

int verify_callback(int, X509_STORE_CTX*);
void apps_ssl_info_callback(SSL *, int, int);





/**
 * Callback for getting key
 */
int returnKey(keybuf, maxlength, verify)
     char *keybuf;
     int maxlength;
     int verify;
{
  if(maxlength>strlen(skeyphrase)) {
    memcpy(keybuf,skeyphrase,strlen(skeyphrase));
    return strlen(skeyphrase);
  }
  else
    return -1;

}


/* Verify if passphrase works for keyfile */
int verifyKey(char* keyfile, char* passphrase)
{
        SSL_METHOD *meth=NULL;
        SSL_CTX *ctx=NULL;
        int t=0;

        skeyphrase = passphrase;

        SSLeay_add_ssl_algorithms();

        if((meth=SSLv3_client_method()) &&
                (ctx=SSL_CTX_new(meth)))
        {
                SSL_CTX_set_default_passwd_cb(ctx,*returnKey);

                t = SSL_CTX_use_RSAPrivateKey_file(ctx, keyfile, SSL_FILETYPE_PEM);

                if (ctx) SSL_CTX_free(ctx);
        }
        return (t>0);
}



/**
 * Send a ssl message
 *
 * This involves to open a port to the host set by setPGWPort and
 * setPGWHostName. The data to be sendt should be stored in 'buf' of
 * and the length of buf is passed to the function in 'length'.
 *
 * The return from the PGW is put into a buffer structure.
 *
 * It is the responsibillity of the caller to free both the buffer structure
 * and the buffer within (the buf element)
 *
 */
int sendSSL(sbuf,slength,mbuf,mlength,hostname,port)
     char *sbuf,*mbuf;
     int slength,mlength;
     char *hostname;
     int port;
{
  /* ----------- VARIABLE DECLARATION ------------------- */
  int t,tt,size;
  int fd,c_ret;
  struct protoent *pe;
  struct hostent *he;
  struct sockaddr_in sin;
  char *tmp;
  // Method for the correct ssl version
  SSL_METHOD *meth=NULL;

  // create an SSL structure
  SSL *con = NULL;
  SSL_CTX *ctx=NULL;

  X509*    server_cert;
  char*    str;
  int r;


  /* ----------- CODE START ------------------- */

#ifdef WINNT

  struct WSAData wsa_state;
  int wsa_init_done=0,err;

  memset(&wsa_state,0,sizeof(wsa_state));

  if (WSAStartup(0x0101,&wsa_state)!=0)
  {
        err=WSAGetLastError();
    return(0);
  }
#endif


  // ---------- Establish plain socket connection

  pe = getprotobyname(PROTOCOL);

  // Open a new socket
  fd = socket(AF_INET,SOCK_STREAM,pe->p_proto);
  if(fd==-1) {
    sprintf(sslclient_error_,
             "Could not create new socket");
    goto error;
  }


  // Get the PGWHostName

  if(hostname == NULL) {
    sprintf(sslclient_error_,"PGWHostName not set");
    goto error;
  }

  he = gethostbyname(hostname);

  if(he == NULL || he->h_addr == NULL) {
    sprintf(sslclient_error_,
             "Could not gethostbyname for host:%s",hostname);
    goto error;
  }

  sin.sin_family = AF_INET;
  sin.sin_port = htons(port);


  memcpy((void *)&sin.sin_addr, (void *)he->h_addr, he->h_length);

#ifdef DEBUG
  printf("Before connect\n");
#endif


  c_ret = connect(fd,(struct sockaddr *)&sin, sizeof(sin));



  if(c_ret==-1){
    sprintf(sslclient_error_,
             "Could not connect to port %d",port);
    goto error;
  }

  // ---------- Establish ssl on top of the socket

  // Add algorithms
  //OpenSSL_add_ssl_algorithms();

  SSLeay_add_ssl_algorithms();

  // Set the method to SSLv3
  meth=SSLv3_client_method();

  // Create a new context for communication
  ctx=SSL_CTX_new(meth);
  SSL_load_error_strings();

  if (ctx == NULL) {
    sprintf(sslclient_error_,
             "Could not create new CTX structure");
    goto error;
  }
  SSL_CTX_set_timeout(ctx, 3);
  SSL_CTX_set_options(ctx,0);
  SSL_CTX_set_info_callback(ctx,apps_ssl_info_callback);



  // Get connection
  con=(SSL *)SSL_new(ctx);
  if(con == NULL) {
    sprintf(sslclient_error_,
             "Could not create new SSL structure");
    goto error;
  }

  // Set a file descriptor for the connection
  SSL_set_fd(con,fd);
  // SSL_set_connect_state(con);


#ifdef DEBUG
  printf("Before ssl connect\n");
#endif


  // Connection i.e. handshake SSL
  t = SSL_connect(con);

  if(t < 0) {
    sprintf(sslclient_error_,
             "SSL connect failed");
    goto error;
  }

#ifdef DEBUG
  printf("Connect:%d\n",t);

  printf("Negotiated cipher:%s\n",SSL_get_cipher(con));
#endif
  //sleep(1);

  if(strcmp(SSL_get_cipher(con),"(NONE)")==0) {
    sprintf(sslclient_error_,
             "No cipher could be negotiated");
    goto error;
  }

  server_cert = SSL_get_peer_certificate (con);
  if(server_cert) {
#ifdef DEBUG
    printf ("Server certificate:\n");
#endif

    str = X509_NAME_oneline (X509_get_subject_name (server_cert),0,0);
    if(str) {
#ifdef DEBUG
      printf ("\t subject: %s\n", str);
#endif
      free(str);

      str = X509_NAME_oneline (X509_get_issuer_name  (server_cert),0,0);
      if(str) {
#ifdef DEBUG
        printf ("\t issuer: %s\n", str);
#endif
        free(str);
      }
    }
  }


  // Write the buffer to the server
#ifdef DEBUG
  printf("writing buffer with length:%d\n",slength);
#endif
  t=0;
  do {
    tt = SSL_write(con,sbuf+t,slength-t);
    switch (SSL_get_error(con,tt))
    {
    case SSL_ERROR_NONE:
     break;
    case SSL_ERROR_WANT_WRITE:
     printf("write W BLOCK\n");
     break;
    case SSL_ERROR_WANT_READ:
     printf("write R BLOCK\n");
     break;
    case SSL_ERROR_WANT_X509_LOOKUP:
     printf("write X BLOCK\n");
     break;
    case SSL_ERROR_ZERO_RETURN:
     printf("shutdown\n");
     goto error;

    case SSL_ERROR_SYSCALL:
    printf("write:errno=");
     goto error;
    case SSL_ERROR_SSL:
     printf("SSL_ERROR_SSL");
   }


#ifdef DEBUG
    printf("Wrote:%d\n",tt);
#endif
    if(tt<=0) {
      sprintf(sslclient_error_,
               "Could not write");
      goto error;
    }
    t += tt;
  } while(t<slength);
  //sleep(8);
#ifdef DEBUG
  puts("reading buffer");
  //SSL_CTX_flush_sessions(ctx , 0);
#endif

  // Read the result
  tt = 0;
  while(1==1) {
    t=SSL_read(con, mbuf + tt, mlength-tt);
    if(t==-1 || t==0)
      break;

#ifdef DEBUG
  printf("read %d\n",t);
#endif

    tt+=t;
  }

#ifdef DEBUG
  printf("finished reading\n");
#endif


  if (con != NULL) {
    SSL_shutdown(con);
    close(SSL_get_fd(con));
    SSL_free(con);
  }
  if (ctx != NULL) SSL_CTX_free(ctx);
  if(fd != 0) close(fd);
#ifdef WINNT
  WSACleanup();
#endif
  return tt;

 error:
#ifdef DEBUG
puts(sslclient_error_);
#endif

  if (ctx != NULL) SSL_CTX_free(ctx);

  if (con != NULL) SSL_free(con);
#ifdef WINNT
  if(fd != 0) closesocket(fd);
  WSACleanup();
#else
  if(fd != 0) close(fd);
#endif

  return 0;


}


/**
 * Get an error
 */
char *getSSLError() {
  return sslclient_error_;
}

int verify_callback(int ok, X509_STORE_CTX *ctx)
        {
        char buf[256];
        X509 *err_cert;
        int err,depth;

        err_cert=X509_STORE_CTX_get_current_cert(ctx);
        err=    X509_STORE_CTX_get_error(ctx);
        depth=  X509_STORE_CTX_get_error_depth(ctx);

        X509_NAME_oneline(X509_get_subject_name(err_cert),buf,256);
        printf("depth=%d %s\n",depth,buf);
        if (!ok)
                {
                printf("verify error:num=%d:%s\n",err,
                        X509_verify_cert_error_string(err));
                if (1 >= depth)
                        {
                        ok=1;
                        printf("verify_error=X509_V_OK");
                        }
                else
                        {
                        ok=0;

printf("verify_error=X509_V_ERR_CERT_CHAIN_TOO_LONG");
                        }
                }
        switch (ctx->error)
                {
        case X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT:

X509_NAME_oneline(X509_get_issuer_name(ctx->current_cert),buf,256);
                printf("issuer= %s\n",buf);
                break;
        case X509_V_ERR_CERT_NOT_YET_VALID:
        case X509_V_ERR_ERROR_IN_CERT_NOT_BEFORE_FIELD:
                printf("notBefore=");
                ASN1_TIME_print(0,X509_get_notBefore(ctx->current_cert));
                printf("\n");
                break;
        case X509_V_ERR_CERT_HAS_EXPIRED:
        case X509_V_ERR_ERROR_IN_CERT_NOT_AFTER_FIELD:
                printf("notAfter=");
                ASN1_TIME_print(0,X509_get_notAfter(ctx->current_cert));
                printf("\n");
                break;
                }
        printf("verify return:%d\n",ok);
        return(ok);
        }


void apps_ssl_info_callback(SSL *s, int where, int ret)
        {
        char *str;
        int w,i;

        w=where& ~SSL_ST_MASK;

        if (w & SSL_ST_CONNECT) str="SSL_connect";
        else if (w & SSL_ST_ACCEPT) str="SSL_accept";
        else str="undefined";

        if (where & SSL_CB_LOOP)
                {
#ifdef DEBUG
                printf("%s:%s\n",str,SSL_state_string_long(s));
#endif
                }
        else if (where & SSL_CB_ALERT)
                {
                str=(where & SSL_CB_READ)?"read":"write";
#ifdef DEBUG
                printf("SSL3 alert %s:%s:%s\n",
                        str,
                        SSL_alert_type_string_long(ret),
                        SSL_alert_desc_string_long(ret));
#endif
                }
        else if (where & SSL_CB_EXIT)
                {
                if (ret == 0) {
#ifdef DEBUG
                        printf("%s:failed in %s\n",
                                str,SSL_state_string_long(s));
#endif
                } else if (ret < 0)
                        {
#ifdef DEBUG
                        printf("%s:error in %s\n",
                                str,SSL_state_string_long(s));
#endif
                        }
                }
        }











mvh,
Carsten Rhod Gregersen
Email: [EMAIL PROTECTED], Tlf: 70211360 Web: http://www.logiva.dk
Address: Logiva A/S, Klamsagervej 12, 8230 Åbyhøj, Denmark

______________________________________________________________________
OpenSSL Project                                 http://www.openssl.org
User Support Mailing List                    [EMAIL PROTECTED]
Automated List Manager                           [EMAIL PROTECTED]

Reply via email to