@@ -2,3 +2,37 @@ buggy_openssl_with_fullduplex | |||||
============================= | ============================= | ||||
Toy code which shows problems with non-blocking, fullduplex I/O & renegotiation in OpenSSL | Toy code which shows problems with non-blocking, fullduplex I/O & renegotiation in OpenSSL | ||||
How it works: | |||||
Client & Server: | |||||
- it has two threads - sender & receiver | |||||
- writes and reads are mutexed | |||||
Client: | |||||
- I/O is blocking (but can be non-blocking) | |||||
Server: | |||||
- I/O is non-blocking | |||||
- each thread runs it's own select() | |||||
1. After client & server are connected (and SSL handshake done) client sender | |||||
thread starts sending first message (in a loop). | |||||
2. When server receives first query it starts sending string EXCHANGE_STRING for | |||||
SEND_ITERATIONS number of times. So now we have 4 threads that are sending | |||||
and receiving traffic at the same time ( 2 send/receive threads on each | |||||
server and client side ) | |||||
3. When client receives RENEG_INIT_LEN number of characters it starts | |||||
renegotiation ( if other one is not pending ). Bug starts to occure here | |||||
BUG: | |||||
Client side: client starts to report SSL_ERROR_SYSCALL | |||||
Server side: server reports SSL_ERROR_WANT_READ when receive function is called | |||||
TCP: | |||||
In TCP exchange we can see that transfer between client & server is OK until | |||||
client sends "Client Hello" packet. This packet is sent when SSL_renegotiate | |||||
is called |
@@ -45,9 +45,11 @@ bool handle_error_code(int& len, SSL* SSLHandler, int code, const char* func) | |||||
break; | break; | ||||
case SSL_ERROR_WANT_READ: | case SSL_ERROR_WANT_READ: | ||||
cout << func << " WANT READ" << endl; | cout << func << " WANT READ" << endl; | ||||
return true; | |||||
break; | break; | ||||
case SSL_ERROR_WANT_WRITE: | case SSL_ERROR_WANT_WRITE: | ||||
cout << func << " WANT WRITE" << endl; | cout << func << " WANT WRITE" << endl; | ||||
return true; | |||||
break; | break; | ||||
case SSL_ERROR_SYSCALL: | case SSL_ERROR_SYSCALL: | ||||
cout << func << " ESYSCALL" << endl; | cout << func << " ESYSCALL" << endl; | ||||
@@ -55,10 +57,12 @@ bool handle_error_code(int& len, SSL* SSLHandler, int code, const char* func) | |||||
break; | break; | ||||
case SSL_ERROR_SSL: | case SSL_ERROR_SSL: | ||||
cout << func << " ESSL" << endl; | cout << func << " ESSL" << endl; | ||||
return true; | |||||
exit(1); | exit(1); | ||||
break; | break; | ||||
default: | default: | ||||
cout << func << " SOMETHING ELSE" << endl; | cout << func << " SOMETHING ELSE" << endl; | ||||
return true; | |||||
exit(1); | exit(1); | ||||
} | } | ||||
@@ -75,9 +79,7 @@ void Sender() | |||||
int len = 0; | int len = 0; | ||||
do | do | ||||
{ | { | ||||
bool flag = true; | |||||
while( flag ) | |||||
while( 1 ) | |||||
{ | { | ||||
lock_guard<mutex> lock(WriteReadMutex); | lock_guard<mutex> lock(WriteReadMutex); | ||||
cout << "SSL_write: start" << endl; | cout << "SSL_write: start" << endl; | ||||