Hello.
The following two ssl3 negotiations illustrate a problem I have
been having with the local variable got_new_session in the
(s3_srvr.c) SSL3_accept function:
==================================================================
| My app (not using sockets) | openssl s_server
---------------------------------+--------------------------------
| SSL3_accept called | SSL3_accept called
| got_new_session = 0 | got_new_session = 0
| STATE SSL3_ST_SR_CLNT_HELLO_A | STATE SSL3_ST_SR_CLNT_HELLO_A
| got_new_session = 1 | got_new_session = 1
| STATE SSL3_ST_SW_SRVR_HELLO_A | STATE SSL3_ST_SW_SRVR_HELLO_A
| STATE SSL3_ST_SW_CERT_A | STATE SSL3_ST_SW_CERT_A
| STATE SSL3_ST_SW_KEY_EXCH_A | STATE SSL3_ST_SW_KEY_EXCH_A
| STATE SSL3_ST_SW_CERT_REQ_A | STATE SSL3_ST_SW_CERT_REQ_A
| STATE SSL3_ST_SW_FLUSH | STATE SSL3_ST_SW_FLUSH
| STATE SSL3_ST_SR_CERT_A | STATE SSL3_ST_SR_CERT_A
| |
| SSL_ERROR_WANT_READ |
| SSL3_accept called <-------- |
| got_new_session = 0 <-------- |
| |
| STATE SSL3_ST_SR_CERT_A |
| STATE SSL3_ST_SR_KEY_EXCH_A | STATE SSL3_ST_SR_KEY_EXCH_A
| STATE SSL3_ST_SR_CERT_VRFY_A | STATE SSL3_ST_SR_CERT_VRFY_A
| STATE SSL3_ST_SR_FINISHED_A | STATE SSL3_ST_SR_FINISHED_A
| STATE SSL3_ST_SW_CHANGE_A | STATE SSL3_ST_SW_CHANGE_A
| STATE SSL3_ST_SW_FINISHED_A | STATE SSL3_ST_SW_FINISHED_A
| STATE SSL3_ST_SW_FLUSH | STATE SSL3_ST_SW_FLUSH
| SSL_ST_OK | SSL_ST_OK
| got new session == 0 <------- | got new session == 1 <-------
| | session saved in cache
| | sess_accept_good++;
==================================================================
When trying to read the certificate, my application needs to
read more data (using (non-blocking) memory buffer BIO's), and
when SSL3_accept() is reentered, the local variable
got_new_session is reset to 0.
This means that in SSL_ST_OK, the session is not stored in the
cache and sess_accept_good is not incremented.
I have made a patch for this problem, placing the variable
got_new_session in the SSL connection "object". This way, the
variable is remembered across several SSL3_accept invocations.
Since I'm not very familiar with the code, I am uncertain
to which places this variable needs to be reset. As the
"constructor" SSL_new does a memset 0 on the entire structure
we AFAIK do not need to reset it initially.
In addition to that I reset the variable in the switch cases:
case SSL_ST_RENEGOTIATE:
s->new_session=1;
/* s->state=SSL_ST_ACCEPT; */
case SSL_ST_BEFORE:
case SSL_ST_ACCEPT:
case SSL_ST_BEFORE|SSL_ST_ACCEPT:
case SSL_ST_OK|SSL_ST_ACCEPT:
..and in SSL_ST_OK (right after checking if got_new_session != 0).
Patch files are attached (they probably contain MS-DOS line-breaks).
I apologize in advance if I should be blatantly wrong, the
problem is already known, or if I have messed up in any
other way.
At least, the patch fixes my problems.
I would also like to know why only the ssl3_accept uses
a variable like got_new_session. I did not find anything
similar in ssl2 accept.
Best Regards,
�ivind Hardy Danielsen, M.Sc. eMail: [EMAIL PROTECTED]
Senior System Architect
Cameon ANS - http://www.cameon.net/
--- ..\..\openssl\ssl\ssl.h Mon Mar 25 15:37:27 2002
+++ ssl.h Thu Apr 11 14:13:48 2002
@@ -591,6 +591,7 @@
* for received */
int state; /* where we are */
int rstate; /* where we are when reading */
+ int got_new_session;
BUF_MEM *init_buf; /* buffer used during init */
int init_num; /* amount read/written */
--- ..\..\openssl\ssl\s3_srvr.c Mon Mar 25 15:37:26 2002
+++ s3_srvr.c Thu Apr 11 14:12:32 2002
@@ -167,7 +167,6 @@
long num1;
int ret= -1;
int new_state,state,skip=0;
- int got_new_session=0;
RAND_add(&Time,sizeof(Time),0);
ERR_clear_error();
@@ -203,6 +202,7 @@
case SSL_ST_BEFORE|SSL_ST_ACCEPT:
case SSL_ST_OK|SSL_ST_ACCEPT:
+ s->got_new_session = 0;
s->server=1;
if (cb != NULL) cb(s,SSL_CB_HANDSHAKE_START,1);
@@ -280,7 +280,7 @@
s->shutdown=0;
ret=ssl3_get_client_hello(s);
if (ret <= 0) goto end;
- got_new_session=1;
+ s->got_new_session=1;
s->state=SSL3_ST_SW_SRVR_HELLO_A;
s->init_num=0;
break;
@@ -513,8 +513,9 @@
s->init_num=0;
- if (got_new_session) /* skipped if we just sent a HelloRequest
*/
+ if (s->got_new_session) /* skipped if we just sent a
+HelloRequest */
{
+ s->got_new_session = 0;
/* actually not necessarily a 'new' session */
s->new_session=0;