aboutsummaryrefslogtreecommitdiff
path: root/ssl/s3_clnt.c
diff options
context:
space:
mode:
authorDr. Stephen Henson <steve@openssl.org>2007-08-11 23:18:29 +0000
committerDr. Stephen Henson <steve@openssl.org>2007-08-11 23:18:29 +0000
commit6434abbfc6ac0d5cb882844ed10fef5821039cf6 (patch)
tree04b0b4626e1ccd18fb80965716957144ceb839b9 /ssl/s3_clnt.c
parente45c100762baaaa0bfd9e9db136192ec09286a55 (diff)
downloadopenssl-6434abbfc6ac0d5cb882844ed10fef5821039cf6.zip
openssl-6434abbfc6ac0d5cb882844ed10fef5821039cf6.tar.gz
openssl-6434abbfc6ac0d5cb882844ed10fef5821039cf6.tar.bz2
RFC4507 (including RFC4507bis) TLS stateless session resumption support
for OpenSSL.
Diffstat (limited to 'ssl/s3_clnt.c')
-rw-r--r--ssl/s3_clnt.c130
1 files changed, 129 insertions, 1 deletions
diff --git a/ssl/s3_clnt.c b/ssl/s3_clnt.c
index adc8738..fc628b5 100644
--- a/ssl/s3_clnt.c
+++ b/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