Hi,

I found out that if I keep calling SSL_write, if the connection is closed remotely (killing stunnel), my application hangs. I made some tests, and saw that the error happens only if I keep calling SSL_write. The first SSL_write after closing the connection returns a positive value, as if the closing wasn't seen. The second causes the hanging. If I call SSL_read and SSL_write, the first SSL_read after closing the connection remotely returns an error code, so I can notice what happened and close the connection even in the application.

This is my sample code, you can comment and decomment #define BUG_FIX to switch between the two behaviors. In my example I use a dummy 0 byte read to prevent the hanging. I removed certificate verification and private key loading here to make the application more readable, but the behavior was exactly the same with these operations.

//////////////////////////////////////////////////////////////////
//test ssl
//////////////////////////////////////////////////////////////////
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <pthread.h>
#include <termios.h>
#include <unistd.h>
#include <sys/ioctl.h>
#include <sys/types.h>
#include <sys/signal.h>
#include <sys/socket.h>
#include <string.h>
#include <fcntl.h>
#include <signal.h>
#include <errno.h>
#include <netdb.h>
#include <netinet/in.h>
#include <ctype.h>
#include <openssl/bio.h>
#include <openssl/err.h>
#include <openssl/rand.h>
#include <openssl/ssl.h>
#include <openssl/x509v3.h>
//////////////////////////////////////////////////////////////////
#define int_error(msg)  {fprintf(stderr, "** %s:%i %s\n", __FILE__, __LINE__, msg); exit(0);}
//////////////////////////////////////////////////////////////////
#define CIPHER_LIST "ALL:!ADH:!LOW:!EXP:!MD5:@STRENGTH"
#define HOST    "127.0.0.1"
#define PORT    16001

#define NON_BLOCKING

#define BUG_FIX
//////////////////////////////////////////////////////////////////
BIO     * conn = NULL;
SSL     * ssl = NULL;
SSL_CTX * ctx = NULL;

static int check_err(SSL *ssl, int ret)
{
    int r =SSL_get_error(ssl, ret);
   
    switch(r)
    {
        case SSL_ERROR_NONE:
            fprintf(stderr, "SSL_ERROR_NONE\n");
            break;
        case SSL_ERROR_ZERO_RETURN:
            fprintf(stderr, "SSL_ERROR_ZERO_RETURN\n");
            break;
        case SSL_ERROR_WANT_READ:
            fprintf(stderr,"SSL_ERROR_WANT_READ\n");
            break;
        case SSL_ERROR_WANT_WRITE:
            fprintf(stderr, "SSL_ERROR_WANT_WRITE\n");
            break;
        case SSL_ERROR_WANT_CONNECT:
            fprintf(stderr,"SSL_ERROR_WANT_CONNECT\n");
            break;
        case SSL_ERROR_WANT_ACCEPT:
            fprintf(stderr, "SSL_ERROR_WANT_ACCEPT\n");
            break;
        case SSL_ERROR_WANT_X509_LOOKUP:
            fprintf(stderr, "SSL_ERROR_WANT_X509_LOOKUP\n");
            break;
        case SSL_ERROR_SYSCALL:
            fprintf(stderr, "SSL_ERROR_SYSCALL\n");
            break;
        case SSL_ERROR_SSL:
            fprintf(stderr, "SSL_ERROR_SSL\n");
            break;
        default:
            fprintf(stderr, "SSL_???\n");
            break;   
    }

    return r;
}

static SSL_CTX *setup_client_ctx()
{
    SSL_CTX *ctx;
 
    ctx = SSL_CTX_new(SSLv23_method());
   
    if(ctx == NULL)
        return NULL;
   
    SSL_CTX_set_options(ctx, SSL_OP_ALL|SSL_OP_NO_SSLv2);
   
    if (SSL_CTX_set_cipher_list(ctx, CIPHER_LIST) != 1)
    {
        int_error("Error setting cipher list (no valid ciphers)");
        SSL_CTX_free(ctx);
        return NULL;
    }
    return ctx;
}

int closeSocketSSL()
{
   
    if(ssl != NULL)
    {
        SSL_shutdown(ssl);
        SSL_free(ssl);
       
        ssl = NULL;
    }
   
    if(ctx != NULL)
    {
        SSL_CTX_free(ctx);
        ctx = NULL;
    }
   
    if(conn != NULL)
    {
        conn = NULL;
    }
   
    return 0;
}


int openSocketSSL(const char * host, unsigned short port)
{   
    int ret;
    long    err;
   
    if (!SSL_library_init())
    {
        fprintf(stderr, "** OpenSSL initialization failed!");
        return -1;
    }
   
    RAND_load_file("/dev/urandom", 1024);
        
    conn = NULL;
    ssl = NULL;
    ctx = NULL;
   
    ctx = setup_client_ctx();
   
    if(ctx == NULL)
    {
        closeSocketSSL();
        return -1;
    }

    {
        char buff[512];
        sprintf(buff, "%s:%d", (host != NULL) ? host : "127.0.0.1" , port);   
        printf(buff);
        conn = BIO_new_connect(buff/*SERVER ":" PORT*/);
    }
    if (!conn)
    {
        int_error("Error creating connection BIO");
        closeSocketSSL();
        return -1;
    }

#ifdef    NON_BLOCKING
    if(BIO_set_nbio(conn,1)!= 1)
    {
        int_error("Error setting non-blocking IO");
        closeSocketSSL();
        return -1;
    }   
#endif   
   
    while((err=BIO_do_connect(conn)) <= 0)
    {
        if(!BIO_should_retry(conn))
        {
           
            int_error("Error connecting to remote machine");
            closeSocketSSL();
            return -1;
        }
        usleep(5000);
    }

    ssl = SSL_new(ctx);
    SSL_set_bio(ssl, conn, conn);
    while ((ret = SSL_connect(ssl)) <= 0)
    {
        if(!BIO_should_retry(conn))
        {
            check_err(ssl, ret);
            int_error("Error connecting SSL object");
            closeSocketSSL();
            return -1;
        }
        usleep(5000);
    }
   
    fprintf(stderr,"SSL Connection opened\n");
   
    return 0;
}

int readSocketSSL(unsigned char * msg, unsigned short len)
{
    int r;
   
   
    if(ssl == NULL)
        return -1;
   
    r = SSL_read(ssl,msg,len);

    if(r > 0)
        return r;
           
    if(SSL_get_error(ssl, r) == SSL_ERROR_WANT_READ)
        return 0;
   
    SSL_clear(ssl);
    SSL_free(ssl);
    ssl=NULL;   
    closeSocketSSL();
   
    return -1;
}

int writeSocketSSL(const unsigned char * msg, unsigned short len)
{
    int r;
 
    if(ssl == NULL)
        return -1;   
   
///////////////////////////////////////////////////////////////////////
//fix - this null read prevents program hanging if connection closed //
//      by killing stunnel server                                    //
///////////////////////////////////////////////////////////////////////
#ifdef BUG_FIX
    {
        r = readSocketSSL(NULL, 0);
           
        if(r < 0)
        {
            fprintf(stderr,"err read\n");
            return -1;
        }
    }
#endif
///////////////////////////////////////////////////////////////////////
   
    r = SSL_write(ssl, msg, len);
   
    if(r<=0)
    {
        fprintf(stderr,"err write\n");
        check_err(ssl, r);
    }

    return r;
}

int main(int argc, char *argv[])
{
    unsigned short port = PORT;
    char host[] = HOST;
       
    fprintf(stderr,"h:%s\nport:%d\n",host,port);
   
   
    if(openSocketSSL(host, port) != 0)
    {
        fprintf(stderr,"error opening connection\n");
        return -1;
    }
   
    //infinite loop until I have a write error
    while(1)
    {
        int n;

       
        fprintf(stderr,"start op\n");
       
        n=writeSocketSSL((const unsigned char *) "hello\r\n",7);    /* start reading and writting */
        fprintf(stderr,"w: %d\n", n);
        sleep(1);
       
        if(n<=0)
            break;
    }
   
    //if I got here the application didn't hang
    fprintf(stderr,"closing...\n");
    closeSocketSSL();           
    fprintf(stderr,"closed OK\n");
   
   
    return 0;   
}
////////////////////////////////////////////////////



David Schwartz ha scritto:
If I close stunnel, the next SSL_write will return a positive value,
as if everything is ok, the second causes sudden application termination.
    

Make a build with debugging symbols, get a core dump, and analyze it with
'gdb' or similar. Alternatively, post the smallest complete, compilable
example of code that demonstrates the problem.

DS


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


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

Reply via email to