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 :
This is just for testing
----------------------------------------------------------------------------
----
#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 :
Here all the work is done
----------------------------------------------------------------------------
----
/*
* 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]