diff options
author | Dr. Stephen Henson <steve@openssl.org> | 2007-08-11 23:18:29 +0000 |
---|---|---|
committer | Dr. Stephen Henson <steve@openssl.org> | 2007-08-11 23:18:29 +0000 |
commit | 6434abbfc6ac0d5cb882844ed10fef5821039cf6 (patch) | |
tree | 04b0b4626e1ccd18fb80965716957144ceb839b9 /ssl/s3_clnt.c | |
parent | e45c100762baaaa0bfd9e9db136192ec09286a55 (diff) | |
download | openssl-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.c | 130 |
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 |