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: ______________________________________________________________________ OpenSSL Project http://www.openssl.org User Support Mailing List openssl-users@openssl.org Automated List Manager [EMAIL PROTECTED]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] |
- possible SSL_write bug Alessandro Pivi - GLOBALcom engineering
- RE: possible SSL_write bug David Schwartz
- Re: possible SSL_write bu... Alessandro Pivi - GLOBALcom engineering
- RE: possible SSL_writ... David Schwartz
- Re: possible SSL_... Alessandro Pivi - GLOBALcom engineering
- RE: possible... David Schwartz