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                    openssl-users@openssl.org
Automated List Manager                           majord...@openssl.org

Reply via email to