RFC4507 (including RFC4507bis) TLS stateless session resumption support
for OpenSSL.
This commit is contained in:
130
ssl/s3_clnt.c
130
ssl/s3_clnt.c
@@ -163,6 +163,9 @@
|
||||
|
||||
static const SSL_METHOD *ssl3_get_client_method(int ver);
|
||||
static int ca_dn_cmp(const X509_NAME * const *a,const X509_NAME * const *b);
|
||||
#ifndef OPENSSL_NO_TLSEXT
|
||||
static int ssl3_check_finished(SSL *s);
|
||||
#endif
|
||||
|
||||
static const SSL_METHOD *ssl3_get_client_method(int ver)
|
||||
{
|
||||
@@ -286,6 +289,17 @@ int ssl3_connect(SSL *s)
|
||||
|
||||
case SSL3_ST_CR_CERT_A:
|
||||
case SSL3_ST_CR_CERT_B:
|
||||
#ifndef OPENSSL_NO_TLSEXT
|
||||
ret=ssl3_check_finished(s);
|
||||
if (ret <= 0) goto end;
|
||||
if (ret == 2)
|
||||
{
|
||||
s->hit = 1;
|
||||
s->state=SSL3_ST_CR_FINISHED_A;
|
||||
s->init_num=0;
|
||||
break;
|
||||
}
|
||||
#endif
|
||||
/* Check if it is anon DH/ECDH */
|
||||
/* or PSK */
|
||||
if (!(s->s3->tmp.new_cipher->algorithm_auth & SSL_aNULL) &&
|
||||
@@ -439,11 +453,27 @@ int ssl3_connect(SSL *s)
|
||||
}
|
||||
else
|
||||
{
|
||||
#ifndef OPENSSL_NO_TLSEXT
|
||||
/* Allow NewSessionTicket if ticket expected */
|
||||
if (s->tlsext_ticket_expected)
|
||||
s->s3->tmp.next_state=SSL3_ST_CR_SESSION_TICKET_A;
|
||||
else
|
||||
#endif
|
||||
|
||||
s->s3->tmp.next_state=SSL3_ST_CR_FINISHED_A;
|
||||
}
|
||||
s->init_num=0;
|
||||
break;
|
||||
|
||||
#ifndef OPENSSL_NO_TLSEXT
|
||||
case SSL3_ST_CR_SESSION_TICKET_A:
|
||||
case SSL3_ST_CR_SESSION_TICKET_B:
|
||||
ret=ssl3_get_new_session_ticket(s);
|
||||
s->state=SSL3_ST_CR_FINISHED_A;
|
||||
s->init_num=0;
|
||||
break;
|
||||
#endif
|
||||
|
||||
case SSL3_ST_CR_FINISHED_A:
|
||||
case SSL3_ST_CR_FINISHED_B:
|
||||
|
||||
@@ -671,7 +701,7 @@ int ssl3_get_server_hello(SSL *s)
|
||||
SSL3_ST_CR_SRVR_HELLO_A,
|
||||
SSL3_ST_CR_SRVR_HELLO_B,
|
||||
-1,
|
||||
300, /* ?? */
|
||||
20000, /* ?? */
|
||||
&ok);
|
||||
|
||||
if (!ok) return((int)n);
|
||||
@@ -1693,6 +1723,74 @@ static int ca_dn_cmp(const X509_NAME * const *a, const X509_NAME * const *b)
|
||||
{
|
||||
return(X509_NAME_cmp(*a,*b));
|
||||
}
|
||||
#ifndef OPENSSL_NO_TLSEXT
|
||||
int ssl3_get_new_session_ticket(SSL *s)
|
||||
{
|
||||
int ok,al,ret=0, ticklen;
|
||||
long n;
|
||||
const unsigned char *p;
|
||||
unsigned char *d;
|
||||
|
||||
n=s->method->ssl_get_message(s,
|
||||
SSL3_ST_CR_SESSION_TICKET_A,
|
||||
SSL3_ST_CR_SESSION_TICKET_B,
|
||||
-1,
|
||||
16384,
|
||||
&ok);
|
||||
|
||||
if (!ok)
|
||||
return((int)n);
|
||||
|
||||
if (s->s3->tmp.message_type == SSL3_MT_FINISHED)
|
||||
{
|
||||
s->s3->tmp.reuse_message=1;
|
||||
return(1);
|
||||
}
|
||||
if (s->s3->tmp.message_type != SSL3_MT_NEWSESSION_TICKET)
|
||||
{
|
||||
al=SSL_AD_UNEXPECTED_MESSAGE;
|
||||
SSLerr(SSL_F_SSL3_GET_NEW_SESSION_TICKET,SSL_R_BAD_MESSAGE_TYPE);
|
||||
goto f_err;
|
||||
}
|
||||
if (n < 6)
|
||||
{
|
||||
/* need at least ticket_lifetime_hint + ticket length */
|
||||
al = SSL3_AL_FATAL,SSL_AD_DECODE_ERROR;
|
||||
SSLerr(SSL_F_SSL3_GET_NEW_SESSION_TICKET,SSL_R_LENGTH_MISMATCH);
|
||||
goto f_err;
|
||||
}
|
||||
p=d=(unsigned char *)s->init_msg;
|
||||
n2l(p, s->session->tlsext_tick_lifetime_hint);
|
||||
n2s(p, ticklen);
|
||||
/* ticket_lifetime_hint + ticket_length + ticket */
|
||||
if (ticklen + 6 != n)
|
||||
{
|
||||
al = SSL3_AL_FATAL,SSL_AD_DECODE_ERROR;
|
||||
SSLerr(SSL_F_SSL3_NEW_SESSION_TICKET,SSL_R_LENGTH_MISMATCH);
|
||||
goto f_err;
|
||||
}
|
||||
if (s->session->tlsext_tick)
|
||||
{
|
||||
OPENSSL_free(s->session->tlsext_tick);
|
||||
s->session->tlsext_ticklen = 0;
|
||||
}
|
||||
s->session->tlsext_tick = OPENSSL_malloc(ticklen);
|
||||
if (!s->session->tlsext_tick)
|
||||
{
|
||||
SSLerr(SSL_F_SSL3_NEW_SESSION_TICKET,ERR_R_MALLOC_FAILURE);
|
||||
goto err;
|
||||
}
|
||||
memcpy(s->session->tlsext_tick, p, ticklen);
|
||||
s->session->tlsext_ticklen = ticklen;
|
||||
|
||||
ret=1;
|
||||
return(ret);
|
||||
f_err:
|
||||
ssl3_send_alert(s,SSL3_AL_FATAL,al);
|
||||
err:
|
||||
return(-1);
|
||||
}
|
||||
#endif
|
||||
|
||||
int ssl3_get_server_done(SSL *s)
|
||||
{
|
||||
@@ -2600,3 +2698,33 @@ f_err:
|
||||
err:
|
||||
return(0);
|
||||
}
|
||||
|
||||
/* Check to see if handshake is full or resumed. Usually this is just a
|
||||
* case of checking to see if a cache hit has occurred. In the case of
|
||||
* session tickets we have to check the next message to be sure.
|
||||
*/
|
||||
|
||||
#ifndef OPENSSL_NO_TLSEXT
|
||||
static int ssl3_check_finished(SSL *s)
|
||||
{
|
||||
int ok;
|
||||
long n;
|
||||
if (!s->session->tlsext_tick)
|
||||
return 1;
|
||||
/* this function is called when we really expect a Certificate
|
||||
* message, so permit appropriate message length */
|
||||
n=s->method->ssl_get_message(s,
|
||||
SSL3_ST_CR_CERT_A,
|
||||
SSL3_ST_CR_CERT_B,
|
||||
-1,
|
||||
s->max_cert_list,
|
||||
&ok);
|
||||
if (!ok) return((int)n);
|
||||
s->s3->tmp.reuse_message = 1;
|
||||
if ((s->s3->tmp.message_type == SSL3_MT_FINISHED)
|
||||
|| (s->s3->tmp.message_type == SSL3_MT_NEWSESSION_TICKET))
|
||||
return 2;
|
||||
|
||||
return 1;
|
||||
}
|
||||
#endif
|
||||
|
Reference in New Issue
Block a user