This has been driving me nuts for the past few weeks... I've written a
simple app that demonstrates the problem I'm running into. Basically, a
client connects to a server, they do the handshake, and all is well... or
should be. Both machines are running linux. Below is the source, and below
that is some sample output for the client and server:
source:
---------------------------------------------------------------------------
#include <openssl/ssl.h>
#include <openssl/err.h>
#include <sys/select.h>
#include <errno.h>
#include <stdio.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <sys/types.h>
struct sbio
{
BIO * bio;
BIO * abio;
SSL * ssl;
int sock;
struct sbio * next;
};
int max_val(int a, int b)
{
if(a > b)
return a;
return b;
}
SSL_CTX * init_ctx(SSL_METHOD * method)
{
SSL_CTX * ctx;
if(!(ctx = SSL_CTX_new(method)))
{
fprintf(stderr, "SSL_CTX_new: %s\n",
ERR_error_string(ERR_get_error(), NULL));
exit(1);
}
SSL_CTX_set_verify(ctx, SSL_VERIFY_PEER | SSL_VERIFY_CLIENT_ONCE,
NULL);
SSL_CTX_set_verify_depth(ctx, 1);
SSL_CTX_set_session_cache_mode(ctx, SSL_SESS_CACHE_OFF);
if(SSL_CTX_use_certificate_chain_file(ctx, "cert.pem") != 1)
{ // load certificate file
fprintf(stderr, "SSL_CTX_use_certificate_chain_file:
%s\n", ERR_error_string(ERR_get_error(), NULL));
SSL_CTX_free(ctx);
exit(1);
}
if(SSL_CTX_use_PrivateKey_file(ctx, "key.pem", SSL_FILETYPE_PEM)
!= 1)
{ // load private key
fprintf(stderr, "SSL_CTX_use_PrivateKey_file: %s\n",
ERR_error_string(ERR_get_error(), NULL));
SSL_CTX_free(ctx);
exit(1);
}
if(!SSL_CTX_check_private_key(ctx))
{ // check private key
fprintf(stderr, "SSL_CTX_check_private_key: %s\n",
ERR_error_string(ERR_get_error(), NULL));
SSL_CTX_free(ctx);
exit(1);
}
if(!SSL_CTX_load_verify_locations(ctx, "/tmp/ca.pem", NULL))
{ // load CA file
fprintf(stderr, "SSL_CTX_load_verify_locations: %s\n",
ERR_error_string(ERR_get_error(), NULL));
SSL_CTX_free(ctx);
exit(1);
}
return ctx;
}
int main(int argc, char ** argv)
{
int client = 0; // client or server
int n, counter, nfds;
SSL_METHOD method;
SSL_CTX * ctx;
fd_set afds, rfds;
struct sbio mysock;
struct sbio * client_head = NULL, * sbiotmp, * sbiotmp1;
char buffer[0xff];
mysock.next = NULL;
if(!strcmp(argv[1], "client"))
{
client = 1;
}
SSL_load_error_strings();
ERR_load_BIO_strings();
OpenSSL_add_all_algorithms();
SSL_library_init();
if(client)
{
memcpy(&method, SSLv3_client_method(), sizeof(SSL_METHOD));
}
else
{
memcpy(&method, SSLv3_server_method(), sizeof(SSL_METHOD));
}
ctx = init_ctx(&method);
if(!client)
{ // run server...
if(!(mysock.bio = BIO_new_ssl(ctx, 0)))
{
fprintf(stderr, "BIO_new_ssl: %s",
ERR_error_string(ERR_get_error(), NULL));
return 1;
}
BIO_get_ssl(mysock.bio, &mysock.ssl);
snprintf(buffer, 0xff, "%s:%d", argv[2], ntohs(5555));
if(!(mysock.abio = BIO_new_accept(buffer)))
{
fprintf(stderr, "BIO_new_ssl_accept: %s\n",
ERR_error_string(ERR_get_error(), NULL));
return 1;
}
BIO_set_accept_bios(mysock.abio, mysock.bio);
if(BIO_do_accept(mysock.abio) <= 0)
{
fprintf(stderr, "BIO_do_accept: %s\n",
ERR_error_string(ERR_get_error(), NULL));
return 1;
}
if(BIO_get_fd(mysock.abio, &mysock.sock) == -1)
{
fprintf(stderr, "BIO_get_fd: %s\n",
ERR_error_string(ERR_get_error(), NULL));
return 1;
}
while(1)
{
FD_ZERO(&afds);
FD_SET(mysock.sock, &afds);
nfds = mysock.sock;
for(sbiotmp = client_head; sbiotmp; sbiotmp =
sbiotmp->next)
{
FD_SET(sbiotmp->sock, &afds);
nfds = max_val(nfds, sbiotmp->sock);
}
memcpy((char *)&rfds, (char *)&afds, sizeof(fd_set));
if((n = select(nfds + 1, &rfds, NULL, NULL, NULL))
< 0)
{
fprintf(stderr, "select: %s\n",
strerror(errno));
return 1;
}
if(FD_ISSET(mysock.sock, &rfds))
{
printf("Adding a client\n");
if(BIO_do_accept(mysock.abio) <= 0)
{
fprintf(stderr, "BIO_do_accept:
%s\n",
ERR_error_string(ERR_get_error(),
NULL));
return 1;
}
sbiotmp = (sbio *)malloc(sizeof(struct
sbio));
client = sizeof(struct sockaddr_in);
sbiotmp->bio = BIO_pop(mysock.bio);
sbiotmp->abio = NULL;
sbiotmp->ssl = NULL;
if(BIO_do_handshake(sbiotmp->bio) <= 0)
{
fprintf(stderr, "BIO_do_handshake:
%s\n",
ERR_error_string(ERR_get_error(),
NULL));
return 1;
}
if(BIO_get_fd(sbiotmp->bio,
&sbiotmp->sock) == -1)
{
fprintf(stderr, "BIO_get_fd:
%s\n",
ERR_error_string(ERR_get_error(),
NULL));
return 1;
}
sbiotmp->next = client_head;
client_head = sbiotmp;
}
for(sbiotmp = client_head; sbiotmp; sbiotmp =
sbiotmp->next)
{
if(FD_ISSET(sbiotmp->sock, &rfds))
{
if(BIO_read(sbiotmp->bio, buffer,
1) <= 0)
{
printf("Removing a
client\n");
if(client_head == sbiotmp)
{
client_head =
sbiotmp->next;
}
else
{
for(sbiotmp1 =
client_head;
sbiotmp1; sbiotmp1
= sbiotmp1->next)
{
if(sbiotmp1->next
==
sbiotmp)
{
sbiotmp1->next
=
sbiotmp->next;
}
}
}
}
else
{
printf("Received
character: %c\n",
buffer[0]);
}
}
}
}
}
else
{ // run client...
mysock.abio = NULL;
snprintf(buffer, 0xff, "%d", ntohs(5555));
if(!(mysock.bio = BIO_new_ssl_connect(ctx)))
{
fprintf(stderr, "BIO_new_ssl_connect: %s\n",
ERR_error_string(ERR_get_error(), NULL));
return 1;
}
BIO_get_ssl(mysock.bio, &mysock.ssl);
SSL_set_mode(mysock.ssl, SSL_MODE_AUTO_RETRY);
BIO_set_conn_hostname(mysock.bio, argv[2]);
BIO_set_conn_port(mysock.bio, buffer);
if(BIO_do_connect(mysock.bio->next_bio) <= 0)
{
fprintf(stderr, "BIO_do_connect: %s\n",
ERR_error_string(ERR_get_error(), NULL));
BIO_free_all(mysock.bio);
return 1;
}
if(SSL_get_verify_result(mysock.ssl) != X509_V_OK)
{
fprintf(stderr, "SSL_get_verify_result: %ld\n",
SSL_get_verify_result(mysock.ssl));
BIO_free_all(mysock.bio);
return 1;
}
if(BIO_get_fd(mysock.bio, &mysock.sock) == -1)
{
fprintf(stderr, "BIO_get_fd: %s\n",
ERR_error_string(ERR_get_error(), NULL));
BIO_free_all(mysock.bio);
return 1;
}
if(BIO_write(mysock.bio, "a", 1) <= 0)
{
fprintf(stderr, "BIO_write\n");
return 1;
}
}
}
Client output:
----------------------------------------------------------------------------
./a.out client some.ip
BIO_write
Server output:
----------------------------------------------------------------------------
./a.out server some.ip
Adding a client
BIO_do_handshake: error:00000000:lib(0):func(0):reason(0)
As you can see... the error is very helpful indeed. Any idea what's
happening? I've tried to simplify this as much as possible.
--
Life without passion is death in disguise
-----------------------------------------
This email was sent using SquirrelMail.
"Webmail for nuts!"
http://squirrelmail.org/
______________________________________________________________________
OpenSSL Project http://www.openssl.org
User Support Mailing List [email protected]
Automated List Manager [email protected]