RFC4507 (including RFC4507bis) TLS stateless session resumption support
for OpenSSL.
This commit is contained in:
parent
e45c100762
commit
6434abbfc6
18
CHANGES
18
CHANGES
@ -4,6 +4,24 @@
|
||||
|
||||
Changes between 0.9.8f and 0.9.9 [xx XXX xxxx]
|
||||
|
||||
*) Add RFC4507 support to OpenSSL. This includes the corrections in
|
||||
RFC4507bis. The encrypted ticket format is an encrypted encoded
|
||||
SSL_SESSION structure, that way new session features are automatically
|
||||
supported.
|
||||
|
||||
If a client application caches session in an SSL_SESSION support it
|
||||
should automatically be supported because an extension includes the
|
||||
ticket in the structure. The SSL_CTX structure automatically generates
|
||||
keys for ticket protection in servers so again support should be possible
|
||||
with no application modification.
|
||||
|
||||
If a client or server wishes to disable RFC4507 support then the option
|
||||
SSL_OP_NO_TICKET can be set.
|
||||
|
||||
Add a TLS extension debugging callback to allow the contents of any client
|
||||
or server extensions to be examined.
|
||||
[Steve Henson]
|
||||
|
||||
*) Final changes to avoid use of pointer pointer casts in OpenSSL.
|
||||
OpenSSL should now compile cleanly on gcc 4.2
|
||||
[Peter Hartley <pdh@utter.chaos.org.uk>, Steve Henson]
|
||||
|
@ -167,4 +167,7 @@ long MS_CALLBACK bio_dump_callback(BIO *bio, int cmd, const char *argp,
|
||||
#ifdef HEADER_SSL_H
|
||||
void MS_CALLBACK apps_ssl_info_callback(const SSL *s, int where, int ret);
|
||||
void MS_CALLBACK msg_cb(int write_p, int version, int content_type, const void *buf, size_t len, SSL *ssl, void *arg);
|
||||
void MS_CALLBACK tlsext_cb(SSL *s, int client_server, int type,
|
||||
unsigned char *data, int len,
|
||||
void *arg);
|
||||
#endif
|
||||
|
59
apps/s_cb.c
59
apps/s_cb.c
@ -592,3 +592,62 @@ void MS_CALLBACK msg_cb(int write_p, int version, int content_type, const void *
|
||||
}
|
||||
BIO_flush(bio);
|
||||
}
|
||||
|
||||
void MS_CALLBACK tlsext_cb(SSL *s, int client_server, int type,
|
||||
unsigned char *data, int len,
|
||||
void *arg)
|
||||
{
|
||||
BIO *bio = arg;
|
||||
char *extname;
|
||||
|
||||
switch(type)
|
||||
{
|
||||
case TLSEXT_TYPE_server_name:
|
||||
extname = "server name";
|
||||
break;
|
||||
|
||||
case TLSEXT_TYPE_max_fragment_length:
|
||||
extname = "max fragment length";
|
||||
break;
|
||||
|
||||
case TLSEXT_TYPE_client_certificate_url:
|
||||
extname = "client certificate URL";
|
||||
break;
|
||||
|
||||
case TLSEXT_TYPE_trusted_ca_keys:
|
||||
extname = "trusted CA keys";
|
||||
break;
|
||||
|
||||
case TLSEXT_TYPE_truncated_hmac:
|
||||
extname = "truncated HMAC";
|
||||
break;
|
||||
|
||||
case TLSEXT_TYPE_status_request:
|
||||
extname = "status request";
|
||||
break;
|
||||
|
||||
case TLSEXT_TYPE_elliptic_curves:
|
||||
extname = "elliptic curves";
|
||||
break;
|
||||
|
||||
case TLSEXT_TYPE_ec_point_formats:
|
||||
extname = "EC point formats";
|
||||
break;
|
||||
|
||||
case TLSEXT_TYPE_session_ticket:
|
||||
extname = "server ticket";
|
||||
break;
|
||||
|
||||
|
||||
default:
|
||||
extname = "unknown";
|
||||
break;
|
||||
|
||||
}
|
||||
|
||||
BIO_printf(bio, "TLS %s extension \"%s\" (id=%d), len=%d\n",
|
||||
client_server ? "server": "client",
|
||||
extname, type, len);
|
||||
BIO_dump(bio, data, len);
|
||||
BIO_flush(bio);
|
||||
}
|
||||
|
@ -194,6 +194,9 @@ static int c_nbio=0;
|
||||
#endif
|
||||
static int c_Pause=0;
|
||||
static int c_debug=0;
|
||||
#ifndef OPENSSL_NO_TLSEXT
|
||||
static int c_tlsextdebug=0;
|
||||
#endif
|
||||
static int c_msg=0;
|
||||
static int c_showcerts=0;
|
||||
|
||||
@ -406,6 +409,8 @@ int MAIN(int argc, char **argv)
|
||||
tlsextctx tlsextcbp =
|
||||
{NULL,0};
|
||||
#endif
|
||||
char *sess_in = NULL;
|
||||
char *sess_out = NULL;
|
||||
struct sockaddr peer;
|
||||
int peerlen = sizeof(peer);
|
||||
int enable_timeouts = 0 ;
|
||||
@ -480,6 +485,16 @@ int MAIN(int argc, char **argv)
|
||||
if (--argc < 1) goto bad;
|
||||
cert_file= *(++argv);
|
||||
}
|
||||
else if (strcmp(*argv,"-sess_out") == 0)
|
||||
{
|
||||
if (--argc < 1) goto bad;
|
||||
sess_out = *(++argv);
|
||||
}
|
||||
else if (strcmp(*argv,"-sess_in") == 0)
|
||||
{
|
||||
if (--argc < 1) goto bad;
|
||||
sess_in = *(++argv);
|
||||
}
|
||||
else if (strcmp(*argv,"-certform") == 0)
|
||||
{
|
||||
if (--argc < 1) goto bad;
|
||||
@ -506,6 +521,10 @@ int MAIN(int argc, char **argv)
|
||||
c_Pause=1;
|
||||
else if (strcmp(*argv,"-debug") == 0)
|
||||
c_debug=1;
|
||||
#ifndef OPENSSL_NO_TLSEXT
|
||||
else if (strcmp(*argv,"-tlsextdebug") == 0)
|
||||
c_tlsextdebug=1;
|
||||
#endif
|
||||
#ifdef WATT32
|
||||
else if (strcmp(*argv,"-wdebug") == 0)
|
||||
dbug_init();
|
||||
@ -604,6 +623,10 @@ int MAIN(int argc, char **argv)
|
||||
off|=SSL_OP_NO_SSLv2;
|
||||
else if (strcmp(*argv,"-no_comp") == 0)
|
||||
{ off|=SSL_OP_NO_COMPRESSION; }
|
||||
#ifndef OPENSSL_NO_TLSEXT
|
||||
else if (strcmp(*argv,"-no_ticket") == 0)
|
||||
{ off|=SSL_OP_NO_TICKET; }
|
||||
#endif
|
||||
else if (strcmp(*argv,"-serverpref") == 0)
|
||||
off|=SSL_OP_CIPHER_SERVER_PREFERENCE;
|
||||
else if (strcmp(*argv,"-cipher") == 0)
|
||||
@ -791,6 +814,29 @@ bad:
|
||||
#endif
|
||||
|
||||
con=SSL_new(ctx);
|
||||
if (sess_in)
|
||||
{
|
||||
SSL_SESSION *sess;
|
||||
BIO *stmp = BIO_new_file(sess_in, "r");
|
||||
if (!stmp)
|
||||
{
|
||||
BIO_printf(bio_err, "Can't open session file %s\n",
|
||||
sess_in);
|
||||
ERR_print_errors(bio_err);
|
||||
goto end;
|
||||
}
|
||||
sess = PEM_read_bio_SSL_SESSION(stmp, NULL, 0, NULL);
|
||||
BIO_free(stmp);
|
||||
if (!sess)
|
||||
{
|
||||
BIO_printf(bio_err, "Can't open session file %s\n",
|
||||
sess_in);
|
||||
ERR_print_errors(bio_err);
|
||||
goto end;
|
||||
}
|
||||
SSL_set_session(con, sess);
|
||||
SSL_SESSION_free(sess);
|
||||
}
|
||||
#ifndef OPENSSL_NO_TLSEXT
|
||||
if (servername != NULL)
|
||||
{
|
||||
@ -893,6 +939,13 @@ re_start:
|
||||
SSL_set_msg_callback(con, msg_cb);
|
||||
SSL_set_msg_callback_arg(con, bio_c_out);
|
||||
}
|
||||
#ifndef OPENSSL_NO_TLSEXT
|
||||
if (c_tlsextdebug)
|
||||
{
|
||||
SSL_set_tlsext_debug_callback(con, tlsext_cb);
|
||||
SSL_set_tlsext_debug_arg(con, bio_c_out);
|
||||
}
|
||||
#endif
|
||||
|
||||
SSL_set_bio(con,sbio,sbio);
|
||||
SSL_set_connect_state(con);
|
||||
@ -1022,6 +1075,17 @@ re_start:
|
||||
BIO_printf(bio_c_out,"Server did %sacknowledge servername extension.\n",tlsextcbp.ack?"":"not ");
|
||||
}
|
||||
#endif
|
||||
if (sess_out)
|
||||
{
|
||||
BIO *stmp = BIO_new_file(sess_out, "w");
|
||||
if (stmp)
|
||||
{
|
||||
PEM_write_bio_SSL_SESSION(stmp, SSL_get_session(con));
|
||||
BIO_free(stmp);
|
||||
}
|
||||
else
|
||||
BIO_printf(bio_err, "Error writing session file %s\n", sess_out);
|
||||
}
|
||||
print_stuff(bio_c_out,con,full_log);
|
||||
if (full_log > 0) full_log--;
|
||||
|
||||
|
@ -281,6 +281,9 @@ static int www=0;
|
||||
|
||||
static BIO *bio_s_out=NULL;
|
||||
static int s_debug=0;
|
||||
#ifndef OPENSSL_NO_TLSEXT
|
||||
static int s_tlsextdebug=0;
|
||||
#endif
|
||||
static int s_msg=0;
|
||||
static int s_quiet=0;
|
||||
|
||||
@ -869,6 +872,10 @@ int MAIN(int argc, char *argv[])
|
||||
}
|
||||
else if (strcmp(*argv,"-debug") == 0)
|
||||
{ s_debug=1; }
|
||||
#ifndef OPENSSL_NO_TLSEXT
|
||||
else if (strcmp(*argv,"-tlsextdebug") == 0)
|
||||
s_tlsextdebug=1;
|
||||
#endif
|
||||
else if (strcmp(*argv,"-msg") == 0)
|
||||
{ s_msg=1; }
|
||||
else if (strcmp(*argv,"-hack") == 0)
|
||||
@ -922,6 +929,10 @@ int MAIN(int argc, char *argv[])
|
||||
{ off|=SSL_OP_NO_TLSv1; }
|
||||
else if (strcmp(*argv,"-no_comp") == 0)
|
||||
{ off|=SSL_OP_NO_COMPRESSION; }
|
||||
#ifndef OPENSSL_NO_TLSEXT
|
||||
else if (strcmp(*argv,"-no_ticket") == 0)
|
||||
{ off|=SSL_OP_NO_TICKET; }
|
||||
#endif
|
||||
#ifndef OPENSSL_NO_SSL2
|
||||
else if (strcmp(*argv,"-ssl2") == 0)
|
||||
{ meth=SSLv2_server_method(); }
|
||||
@ -1541,6 +1552,13 @@ static int sv_body(char *hostname, int s, unsigned char *context)
|
||||
|
||||
if (con == NULL) {
|
||||
con=SSL_new(ctx);
|
||||
#ifndef OPENSSL_NO_TLSEXT
|
||||
if (s_tlsextdebug)
|
||||
{
|
||||
SSL_set_tlsext_debug_callback(con, tlsext_cb);
|
||||
SSL_set_tlsext_debug_arg(con, bio_s_out);
|
||||
}
|
||||
#endif
|
||||
#ifndef OPENSSL_NO_KRB5
|
||||
if ((con->kssl_ctx = kssl_ctx_new()) != NULL)
|
||||
{
|
||||
@ -1610,6 +1628,13 @@ static int sv_body(char *hostname, int s, unsigned char *context)
|
||||
SSL_set_msg_callback(con, msg_cb);
|
||||
SSL_set_msg_callback_arg(con, bio_s_out);
|
||||
}
|
||||
#ifndef OPENSSL_NO_TLSEXT
|
||||
if (s_tlsextdebug)
|
||||
{
|
||||
SSL_set_tlsext_debug_callback(con, tlsext_cb);
|
||||
SSL_set_tlsext_debug_arg(con, bio_s_out);
|
||||
}
|
||||
#endif
|
||||
|
||||
width=s+1;
|
||||
for (;;)
|
||||
@ -1989,6 +2014,13 @@ static int www_body(char *hostname, int s, unsigned char *context)
|
||||
if (!BIO_set_write_buffer_size(io,bufsize)) goto err;
|
||||
|
||||
if ((con=SSL_new(ctx)) == NULL) goto err;
|
||||
#ifndef OPENSSL_NO_TLSEXT
|
||||
if (s_tlsextdebug)
|
||||
{
|
||||
SSL_set_tlsext_debug_callback(con, tlsext_cb);
|
||||
SSL_set_tlsext_debug_arg(con, bio_s_out);
|
||||
}
|
||||
#endif
|
||||
#ifndef OPENSSL_NO_KRB5
|
||||
if ((con->kssl_ctx = kssl_ctx_new()) != NULL)
|
||||
{
|
||||
|
@ -607,7 +607,7 @@ static int get_client_hello(SSL *s)
|
||||
else
|
||||
{
|
||||
i=ssl_get_prev_session(s,&(p[s->s2->tmp.cipher_spec_length]),
|
||||
s->s2->tmp.session_id_length);
|
||||
s->s2->tmp.session_id_length, NULL);
|
||||
if (i == 1)
|
||||
{ /* previous session */
|
||||
s->hit=1;
|
||||
|
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
|
||||
|
@ -2338,6 +2338,9 @@ long ssl3_ctrl(SSL *s, int cmd, long larg, void *parg)
|
||||
}
|
||||
s->options |= SSL_OP_NO_SSLv2; /* can't use extension w/ SSL 2.0 format */
|
||||
break;
|
||||
case SSL_CTRL_SET_TLSEXT_DEBUG_ARG:
|
||||
s->tlsext_debug_arg=parg;
|
||||
break;
|
||||
#endif /* !OPENSSL_NO_TLSEXT */
|
||||
default:
|
||||
break;
|
||||
@ -2389,6 +2392,12 @@ long ssl3_callback_ctrl(SSL *s, int cmd, void (*fp)(void))
|
||||
s->cert->ecdh_tmp_cb = (EC_KEY *(*)(SSL *, int, int))fp;
|
||||
}
|
||||
break;
|
||||
#endif
|
||||
#ifndef OPENSSL_NO_TLSEXT
|
||||
case SSL_CTRL_SET_TLSEXT_DEBUG_CB:
|
||||
s->tlsext_debug_cb=(void (*)(SSL *,int ,int,
|
||||
unsigned char *, int, void *))fp;
|
||||
break;
|
||||
#endif
|
||||
default:
|
||||
break;
|
||||
|
107
ssl/s3_srvr.c
107
ssl/s3_srvr.c
@ -158,6 +158,7 @@
|
||||
#include <openssl/rand.h>
|
||||
#include <openssl/objects.h>
|
||||
#include <openssl/evp.h>
|
||||
#include <openssl/hmac.h>
|
||||
#include <openssl/x509.h>
|
||||
#ifndef OPENSSL_NO_DH
|
||||
#include <openssl/dh.h>
|
||||
@ -529,11 +530,26 @@ int ssl3_accept(SSL *s)
|
||||
if (ret <= 0) goto end;
|
||||
if (s->hit)
|
||||
s->state=SSL_ST_OK;
|
||||
#ifndef OPENSSL_NO_TLSEXT
|
||||
else if (s->tlsext_ticket_expected)
|
||||
s->state=SSL3_ST_SW_SESSION_TICKET_A;
|
||||
#endif
|
||||
else
|
||||
s->state=SSL3_ST_SW_CHANGE_A;
|
||||
s->init_num=0;
|
||||
break;
|
||||
|
||||
#ifndef OPENSSL_NO_TLSEXT
|
||||
case SSL3_ST_SW_SESSION_TICKET_A:
|
||||
case SSL3_ST_SW_SESSION_TICKET_B:
|
||||
ret=ssl3_send_newsession_ticket(s);
|
||||
if (ret <= 0) goto end;
|
||||
s->state=SSL3_ST_SW_CHANGE_A;
|
||||
s->init_num=0;
|
||||
break;
|
||||
|
||||
#endif
|
||||
|
||||
case SSL3_ST_SW_CHANGE_A:
|
||||
case SSL3_ST_SW_CHANGE_B:
|
||||
|
||||
@ -762,14 +778,14 @@ int ssl3_get_client_hello(SSL *s)
|
||||
* might be written that become totally unsecure when compiled with
|
||||
* an earlier library version)
|
||||
*/
|
||||
if (j == 0 || (s->new_session && (s->options & SSL_OP_NO_SESSION_RESUMPTION_ON_RENEGOTIATION)))
|
||||
if ((s->new_session && (s->options & SSL_OP_NO_SESSION_RESUMPTION_ON_RENEGOTIATION)))
|
||||
{
|
||||
if (!ssl_get_new_session(s,1))
|
||||
goto err;
|
||||
}
|
||||
else
|
||||
{
|
||||
i=ssl_get_prev_session(s,p,j);
|
||||
i=ssl_get_prev_session(s, p, j, d + n);
|
||||
if (i == 1)
|
||||
{ /* previous session */
|
||||
s->hit=1;
|
||||
@ -2714,3 +2730,90 @@ int ssl3_send_server_certificate(SSL *s)
|
||||
/* SSL3_ST_SW_CERT_B */
|
||||
return(ssl3_do_write(s,SSL3_RT_HANDSHAKE));
|
||||
}
|
||||
#ifndef OPENSSLP_NO_TLSEXT
|
||||
int ssl3_send_newsession_ticket(SSL *s)
|
||||
{
|
||||
if (s->state == SSL3_ST_SW_SESSION_TICKET_A)
|
||||
{
|
||||
unsigned char *p, *senc, *macstart;
|
||||
int len, slen;
|
||||
unsigned int hlen;
|
||||
EVP_CIPHER_CTX ctx;
|
||||
HMAC_CTX hctx;
|
||||
|
||||
/* get session encoding length */
|
||||
slen = i2d_SSL_SESSION(s->session, NULL);
|
||||
/* Some length values are 16 bits, so forget it if session is
|
||||
* too long
|
||||
*/
|
||||
if (slen > 0xFF00)
|
||||
return -1;
|
||||
/* Grow buffer if need be: the length calculation is as
|
||||
* follows 1 (size of message name) + 3 (message length
|
||||
* bytes) + 4 (ticket lifetime hint) + 2 (ticket length) +
|
||||
* 16 (key name) + max_iv_len (iv length) +
|
||||
* session_length + max_enc_block_size (max encrypted session
|
||||
* length) + max_md_size (HMAC).
|
||||
*/
|
||||
if (!BUF_MEM_grow(s->init_buf,
|
||||
26 + EVP_MAX_IV_LENGTH + EVP_MAX_BLOCK_LENGTH +
|
||||
EVP_MAX_MD_SIZE + slen))
|
||||
return -1;
|
||||
senc = OPENSSL_malloc(slen);
|
||||
if (!senc)
|
||||
return -1;
|
||||
p = senc;
|
||||
i2d_SSL_SESSION(s->session, &p);
|
||||
|
||||
p=(unsigned char *)s->init_buf->data;
|
||||
/* do the header */
|
||||
*(p++)=SSL3_MT_NEWSESSION_TICKET;
|
||||
/* Skip message length for now */
|
||||
p += 3;
|
||||
l2n(s->session->tlsext_tick_lifetime_hint, p);
|
||||
/* Skip ticket length for now */
|
||||
p += 2;
|
||||
/* Output key name */
|
||||
macstart = p;
|
||||
memcpy(p, s->ctx->tlsext_tick_key_name, 16);
|
||||
p += 16;
|
||||
/* Generate and output IV */
|
||||
RAND_pseudo_bytes(p, 16);
|
||||
EVP_CIPHER_CTX_init(&ctx);
|
||||
/* Encrypt session data */
|
||||
EVP_EncryptInit_ex(&ctx, EVP_aes_128_cbc(), NULL,
|
||||
s->ctx->tlsext_tick_aes_key, p);
|
||||
p += 16;
|
||||
EVP_EncryptUpdate(&ctx, p, &len, senc, slen);
|
||||
p += len;
|
||||
EVP_EncryptFinal(&ctx, p, &len);
|
||||
p += len;
|
||||
EVP_CIPHER_CTX_cleanup(&ctx);
|
||||
|
||||
HMAC_CTX_init(&hctx);
|
||||
HMAC_Init_ex(&hctx, s->ctx->tlsext_tick_hmac_key, 16,
|
||||
EVP_sha1(), NULL);
|
||||
HMAC_Update(&hctx, macstart, p - macstart);
|
||||
HMAC_Final(&hctx, p, &hlen);
|
||||
HMAC_CTX_cleanup(&hctx);
|
||||
|
||||
p += hlen;
|
||||
/* Now write out lengths: p points to end of data written */
|
||||
/* Total length */
|
||||
len = p - (unsigned char *)s->init_buf->data;
|
||||
p=(unsigned char *)s->init_buf->data + 1;
|
||||
l2n3(len - 4, p); /* Message length */
|
||||
p += 4;
|
||||
s2n(len - 10, p); /* Ticket length */
|
||||
|
||||
/* number of bytes to write */
|
||||
s->init_num= len;
|
||||
s->state=SSL3_ST_SW_SESSION_TICKET_B;
|
||||
s->init_off=0;
|
||||
OPENSSL_free(senc);
|
||||
}
|
||||
|
||||
/* SSL3_ST_SW_SESSION_TICKET_B */
|
||||
return(ssl3_do_write(s,SSL3_RT_HANDSHAKE));
|
||||
}
|
||||
#endif
|
||||
|
21
ssl/ssl.h
21
ssl/ssl.h
@ -500,6 +500,10 @@ typedef struct ssl_session_st
|
||||
size_t tlsext_ellipticcurvelist_length;
|
||||
unsigned char *tlsext_ellipticcurvelist; /* peer's list */
|
||||
#endif /* OPENSSL_NO_EC */
|
||||
/* RFC4507 info */
|
||||
unsigned char *tlsext_tick; /* Session ticket */
|
||||
size_t tlsext_ticklen; /* Session ticket length */
|
||||
long tlsext_tick_lifetime_hint; /* Session lifetime hint in seconds */
|
||||
#endif
|
||||
} SSL_SESSION;
|
||||
|
||||
@ -529,6 +533,8 @@ typedef struct ssl_session_st
|
||||
#define SSL_OP_NO_QUERY_MTU 0x00001000L
|
||||
/* Turn on Cookie Exchange (on relevant for servers) */
|
||||
#define SSL_OP_COOKIE_EXCHANGE 0x00002000L
|
||||
/* Don't use RFC4507 ticket extension */
|
||||
#define SSL_OP_NO_TICKET 0x00004000L
|
||||
|
||||
/* As server, disallow session resumption on renegotiation */
|
||||
#define SSL_OP_NO_SESSION_RESUMPTION_ON_RENEGOTIATION 0x00010000L
|
||||
@ -789,6 +795,10 @@ struct ssl_ctx_st
|
||||
/* TLS extensions servername callback */
|
||||
int (*tlsext_servername_callback)(SSL*, int *, void *);
|
||||
void *tlsext_servername_arg;
|
||||
/* RFC 4507 session ticket keys */
|
||||
unsigned char tlsext_tick_key_name[16];
|
||||
unsigned char tlsext_tick_hmac_key[16];
|
||||
unsigned char tlsext_tick_aes_key[16];
|
||||
#endif
|
||||
#ifndef OPENSSL_NO_PSK
|
||||
char *psk_identity_hint;
|
||||
@ -1057,12 +1067,19 @@ struct ssl_st
|
||||
* SSLv3/TLS rollback check */
|
||||
unsigned int max_send_fragment;
|
||||
#ifndef OPENSSL_NO_TLSEXT
|
||||
/* TLS extension debug callback */
|
||||
void (*tlsext_debug_cb)(SSL *s, int client_server, int type,
|
||||
unsigned char *data, int len,
|
||||
void *arg);
|
||||
void *tlsext_debug_arg;
|
||||
char *tlsext_hostname;
|
||||
int servername_done; /* no further mod of servername
|
||||
0 : call the servername extension callback.
|
||||
1 : prepare 2, allow last ack just after in server callback.
|
||||
2 : don't call servername callback, no ack in server hello
|
||||
*/
|
||||
/* RFC4507 session ticket expected to be received or sent */
|
||||
int tlsext_ticket_expected;
|
||||
#ifndef OPENSSL_NO_EC
|
||||
size_t tlsext_ecpointformatlist_length;
|
||||
unsigned char *tlsext_ecpointformatlist; /* our list */
|
||||
@ -1283,6 +1300,8 @@ DECLARE_PEM_rw(SSL_SESSION, SSL_SESSION)
|
||||
#define SSL_CTRL_SET_TLSEXT_SERVERNAME_CB 53
|
||||
#define SSL_CTRL_SET_TLSEXT_SERVERNAME_ARG 54
|
||||
#define SSL_CTRL_SET_TLSEXT_HOSTNAME 55
|
||||
#define SSL_CTRL_SET_TLSEXT_DEBUG_CB 56
|
||||
#define SSL_CTRL_SET_TLSEXT_DEBUG_ARG 57
|
||||
#endif
|
||||
|
||||
#define SSL_session_reused(ssl) \
|
||||
@ -1739,10 +1758,12 @@ void ERR_load_SSL_strings(void);
|
||||
#define SSL_F_SSL3_GET_FINISHED 140
|
||||
#define SSL_F_SSL3_GET_KEY_EXCHANGE 141
|
||||
#define SSL_F_SSL3_GET_MESSAGE 142
|
||||
#define SSL_F_SSL3_GET_NEW_SESSION_TICKET 283
|
||||
#define SSL_F_SSL3_GET_RECORD 143
|
||||
#define SSL_F_SSL3_GET_SERVER_CERTIFICATE 144
|
||||
#define SSL_F_SSL3_GET_SERVER_DONE 145
|
||||
#define SSL_F_SSL3_GET_SERVER_HELLO 146
|
||||
#define SSL_F_SSL3_NEW_SESSION_TICKET 284
|
||||
#define SSL_F_SSL3_OUTPUT_CERT_CHAIN 147
|
||||
#define SSL_F_SSL3_PEEK 235
|
||||
#define SSL_F_SSL3_READ_BYTES 148
|
||||
|
@ -533,6 +533,8 @@ typedef struct ssl3_state_st
|
||||
#define SSL3_ST_CR_CHANGE_B (0x1C1|SSL_ST_CONNECT)
|
||||
#define SSL3_ST_CR_FINISHED_A (0x1D0|SSL_ST_CONNECT)
|
||||
#define SSL3_ST_CR_FINISHED_B (0x1D1|SSL_ST_CONNECT)
|
||||
#define SSL3_ST_CR_SESSION_TICKET_A (0x1E0|SSL_ST_CONNECT)
|
||||
#define SSL3_ST_CR_SESSION_TICKET_B (0x1E1|SSL_ST_CONNECT)
|
||||
|
||||
/* server */
|
||||
/* extra state */
|
||||
@ -574,10 +576,13 @@ typedef struct ssl3_state_st
|
||||
#define SSL3_ST_SW_CHANGE_B (0x1D1|SSL_ST_ACCEPT)
|
||||
#define SSL3_ST_SW_FINISHED_A (0x1E0|SSL_ST_ACCEPT)
|
||||
#define SSL3_ST_SW_FINISHED_B (0x1E1|SSL_ST_ACCEPT)
|
||||
#define SSL3_ST_SW_SESSION_TICKET_A (0x1F0|SSL_ST_CONNECT)
|
||||
#define SSL3_ST_SW_SESSION_TICKET_B (0x1F1|SSL_ST_CONNECT)
|
||||
|
||||
#define SSL3_MT_HELLO_REQUEST 0
|
||||
#define SSL3_MT_CLIENT_HELLO 1
|
||||
#define SSL3_MT_SERVER_HELLO 2
|
||||
#define SSL3_MT_NEWSESSION_TICKET 4
|
||||
#define SSL3_MT_CERTIFICATE 11
|
||||
#define SSL3_MT_SERVER_KEY_EXCHANGE 12
|
||||
#define SSL3_MT_CERTIFICATE_REQUEST 13
|
||||
|
@ -106,6 +106,8 @@ typedef struct ssl_session_asn1_st
|
||||
ASN1_INTEGER verify_result;
|
||||
#ifndef OPENSSL_NO_TLSEXT
|
||||
ASN1_OCTET_STRING tlsext_hostname;
|
||||
ASN1_INTEGER tlsext_tick_lifetime;
|
||||
ASN1_OCTET_STRING tlsext_tick;
|
||||
#endif /* OPENSSL_NO_TLSEXT */
|
||||
#ifndef OPENSSL_NO_PSK
|
||||
ASN1_OCTET_STRING psk_identity_hint;
|
||||
@ -116,9 +118,10 @@ typedef struct ssl_session_asn1_st
|
||||
int i2d_SSL_SESSION(SSL_SESSION *in, unsigned char **pp)
|
||||
{
|
||||
#define LSIZE2 (sizeof(long)*2)
|
||||
int v1=0,v2=0,v3=0,v4=0,v5=0,v6=0,v7=0,v8=0;
|
||||
int v1=0,v2=0,v3=0,v4=0,v5=0,v6=0,v7=0,v8=0,v9=0,v10=0;
|
||||
unsigned char buf[4],ibuf1[LSIZE2],ibuf2[LSIZE2];
|
||||
unsigned char ibuf3[LSIZE2],ibuf4[LSIZE2],ibuf5[LSIZE2];
|
||||
unsigned char ibuf6[LSIZE2];
|
||||
long l;
|
||||
SSL_SESSION_ASN1 a;
|
||||
M_ASN1_I2D_vars(in);
|
||||
@ -217,7 +220,25 @@ int i2d_SSL_SESSION(SSL_SESSION *in, unsigned char **pp)
|
||||
a.tlsext_hostname.length=strlen(in->tlsext_hostname);
|
||||
a.tlsext_hostname.type=V_ASN1_OCTET_STRING;
|
||||
a.tlsext_hostname.data=(unsigned char *)in->tlsext_hostname;
|
||||
}
|
||||
}
|
||||
if (in->tlsext_tick)
|
||||
{
|
||||
a.tlsext_tick.length= in->tlsext_ticklen;
|
||||
a.tlsext_tick.type=V_ASN1_OCTET_STRING;
|
||||
a.tlsext_tick.data=(unsigned char *)in->tlsext_tick;
|
||||
/* If we have a ticket set session ID to empty because
|
||||
* it will be bogus.
|
||||
*/
|
||||
if (in->tlsext_ticklen)
|
||||
a.session_id.length=0;
|
||||
}
|
||||
if (in->tlsext_tick_lifetime_hint != 0)
|
||||
{
|
||||
a.tlsext_tick_lifetime.length=LSIZE2;
|
||||
a.tlsext_tick_lifetime.type=V_ASN1_INTEGER;
|
||||
a.tlsext_tick_lifetime.data=ibuf6;
|
||||
ASN1_INTEGER_set(&a.tlsext_tick_lifetime,in->tlsext_tick_lifetime_hint);
|
||||
}
|
||||
#endif /* OPENSSL_NO_TLSEXT */
|
||||
#ifndef OPENSSL_NO_PSK
|
||||
if (in->psk_identity_hint)
|
||||
@ -256,6 +277,10 @@ int i2d_SSL_SESSION(SSL_SESSION *in, unsigned char **pp)
|
||||
M_ASN1_I2D_len_EXP_opt(&(a.verify_result),i2d_ASN1_INTEGER,5,v5);
|
||||
|
||||
#ifndef OPENSSL_NO_TLSEXT
|
||||
if (in->tlsext_tick_lifetime_hint)
|
||||
M_ASN1_I2D_len_EXP_opt(&a.tlsext_tick_lifetime, i2d_ASN1_INTEGER,9,v9);
|
||||
if (in->tlsext_tick)
|
||||
M_ASN1_I2D_len_EXP_opt(&(a.tlsext_tick), i2d_ASN1_OCTET_STRING,10,v10);
|
||||
if (in->tlsext_hostname)
|
||||
M_ASN1_I2D_len_EXP_opt(&(a.tlsext_hostname), i2d_ASN1_OCTET_STRING,6,v6);
|
||||
#endif /* OPENSSL_NO_TLSEXT */
|
||||
@ -299,6 +324,12 @@ int i2d_SSL_SESSION(SSL_SESSION *in, unsigned char **pp)
|
||||
if (in->psk_identity)
|
||||
M_ASN1_I2D_put_EXP_opt(&(a.psk_identity), i2d_ASN1_OCTET_STRING,8,v8);
|
||||
#endif /* OPENSSL_NO_PSK */
|
||||
#ifndef OPENSSL_NO_TLSEXT
|
||||
if (in->tlsext_tick_lifetime_hint)
|
||||
M_ASN1_I2D_put_EXP_opt(&a.tlsext_tick_lifetime, i2d_ASN1_INTEGER,9,v9);
|
||||
if (in->tlsext_tick)
|
||||
M_ASN1_I2D_put_EXP_opt(&(a.tlsext_tick), i2d_ASN1_OCTET_STRING,10,v10);
|
||||
#endif /* OPENSSL_NO_TLSEXT */
|
||||
M_ASN1_I2D_finish();
|
||||
}
|
||||
|
||||
@ -488,7 +519,7 @@ SSL_SESSION *d2i_SSL_SESSION(SSL_SESSION **a, const unsigned char **pp,
|
||||
#ifndef OPENSSL_NO_PSK
|
||||
os.length=0;
|
||||
os.data=NULL;
|
||||
M_ASN1_D2I_get_EXP_opt(osp,d2i_ASN1_OCTET_STRING,9);
|
||||
M_ASN1_D2I_get_EXP_opt(osp,d2i_ASN1_OCTET_STRING,7);
|
||||
if (os.data)
|
||||
{
|
||||
ret->psk_identity_hint = BUF_strndup((char *)os.data, os.length);
|
||||
@ -498,20 +529,44 @@ SSL_SESSION *d2i_SSL_SESSION(SSL_SESSION **a, const unsigned char **pp,
|
||||
}
|
||||
else
|
||||
ret->psk_identity_hint=NULL;
|
||||
#endif /* OPENSSL_NO_PSK */
|
||||
|
||||
#ifndef OPENSSL_NO_TLSEXT
|
||||
ai.length=0;
|
||||
M_ASN1_D2I_get_EXP_opt(aip,d2i_ASN1_INTEGER,9);
|
||||
if (ai.data != NULL)
|
||||
{
|
||||
ret->tlsext_tick_lifetime_hint=ASN1_INTEGER_get(aip);
|
||||
OPENSSL_free(ai.data); ai.data=NULL; ai.length=0;
|
||||
}
|
||||
else
|
||||
ret->tlsext_tick_lifetime_hint=0;
|
||||
os.length=0;
|
||||
os.data=NULL;
|
||||
M_ASN1_D2I_get_EXP_opt(osp,d2i_ASN1_OCTET_STRING,10);
|
||||
if (os.data)
|
||||
{
|
||||
ret->psk_identity = BUF_strndup((char *)os.data, os.length);
|
||||
OPENSSL_free(os.data);
|
||||
ret->tlsext_tick = os.data;
|
||||
ret->tlsext_ticklen = os.length;
|
||||
os.data = NULL;
|
||||
os.length = 0;
|
||||
#if 0
|
||||
/* There are two ways to detect a resumed ticket sesion.
|
||||
* One is to set a random session ID and then the server
|
||||
* must return a match in ServerHello. This allows the normal
|
||||
* client session ID matching to work.
|
||||
*/
|
||||
if (ret->session_id_length == 0)
|
||||
{
|
||||
ret->session_id_length=SSL3_MAX_SSL_SESSION_ID_LENGTH;
|
||||
RAND_pseudo_bytes(ret->session_id,
|
||||
ret->session_id_length);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
else
|
||||
ret->psk_identity=NULL;
|
||||
#endif /* OPENSSL_NO_KRB5 */
|
||||
ret->tlsext_tick=NULL;
|
||||
#endif /* OPENSSL_NO_TLSEXT */
|
||||
|
||||
M_ASN1_D2I_Finish(a,SSL_SESSION_free,SSL_F_D2I_SSL_SESSION);
|
||||
}
|
||||
|
@ -147,10 +147,12 @@ static ERR_STRING_DATA SSL_str_functs[]=
|
||||
{ERR_FUNC(SSL_F_SSL3_GET_FINISHED), "SSL3_GET_FINISHED"},
|
||||
{ERR_FUNC(SSL_F_SSL3_GET_KEY_EXCHANGE), "SSL3_GET_KEY_EXCHANGE"},
|
||||
{ERR_FUNC(SSL_F_SSL3_GET_MESSAGE), "SSL3_GET_MESSAGE"},
|
||||
{ERR_FUNC(SSL_F_SSL3_GET_NEW_SESSION_TICKET), "SSL3_GET_NEW_SESSION_TICKET"},
|
||||
{ERR_FUNC(SSL_F_SSL3_GET_RECORD), "SSL3_GET_RECORD"},
|
||||
{ERR_FUNC(SSL_F_SSL3_GET_SERVER_CERTIFICATE), "SSL3_GET_SERVER_CERTIFICATE"},
|
||||
{ERR_FUNC(SSL_F_SSL3_GET_SERVER_DONE), "SSL3_GET_SERVER_DONE"},
|
||||
{ERR_FUNC(SSL_F_SSL3_GET_SERVER_HELLO), "SSL3_GET_SERVER_HELLO"},
|
||||
{ERR_FUNC(SSL_F_SSL3_NEW_SESSION_TICKET), "SSL3_NEW_SESSION_TICKET"},
|
||||
{ERR_FUNC(SSL_F_SSL3_OUTPUT_CERT_CHAIN), "SSL3_OUTPUT_CERT_CHAIN"},
|
||||
{ERR_FUNC(SSL_F_SSL3_PEEK), "SSL3_PEEK"},
|
||||
{ERR_FUNC(SSL_F_SSL3_READ_BYTES), "SSL3_READ_BYTES"},
|
||||
|
@ -151,6 +151,7 @@
|
||||
#include <openssl/objects.h>
|
||||
#include <openssl/lhash.h>
|
||||
#include <openssl/x509v3.h>
|
||||
#include <openssl/rand.h>
|
||||
#ifndef OPENSSL_NO_DH
|
||||
#include <openssl/dh.h>
|
||||
#endif
|
||||
@ -336,6 +337,9 @@ SSL *SSL_new(SSL_CTX *ctx)
|
||||
CRYPTO_add(&ctx->references,1,CRYPTO_LOCK_SSL_CTX);
|
||||
s->ctx=ctx;
|
||||
#ifndef OPENSSL_NO_TLSEXT
|
||||
s->tlsext_debug_cb = 0;
|
||||
s->tlsext_debug_arg = NULL;
|
||||
s->tlsext_ticket_expected = 0;
|
||||
CRYPTO_add(&ctx->references,1,CRYPTO_LOCK_SSL_CTX);
|
||||
s->initial_ctx=ctx;
|
||||
#endif
|
||||
@ -1545,6 +1549,12 @@ SSL_CTX *SSL_CTX_new(const SSL_METHOD *meth)
|
||||
#ifndef OPENSSL_NO_TLSEXT
|
||||
ret->tlsext_servername_callback = 0;
|
||||
ret->tlsext_servername_arg = NULL;
|
||||
/* Setup RFC4507 ticket keys */
|
||||
if ((RAND_pseudo_bytes(ret->tlsext_tick_key_name, 16) <= 0)
|
||||
|| (RAND_bytes(ret->tlsext_tick_hmac_key, 16) <= 0)
|
||||
|| (RAND_bytes(ret->tlsext_tick_aes_key, 16) <= 0))
|
||||
ret->options |= SSL_OP_NO_TICKET;
|
||||
|
||||
#endif
|
||||
#ifndef OPENSSL_NO_PSK
|
||||
ret->psk_identity_hint=NULL;
|
||||
|
@ -740,7 +740,7 @@ SESS_CERT *ssl_sess_cert_new(void);
|
||||
void ssl_sess_cert_free(SESS_CERT *sc);
|
||||
int ssl_set_peer_cert_type(SESS_CERT *c, int type);
|
||||
int ssl_get_new_session(SSL *s, int session);
|
||||
int ssl_get_prev_session(SSL *s, unsigned char *session,int len);
|
||||
int ssl_get_prev_session(SSL *s, unsigned char *session,int len, const unsigned char *limit);
|
||||
int ssl_cipher_id_cmp(const SSL_CIPHER *a,const SSL_CIPHER *b);
|
||||
int ssl_cipher_ptr_id_cmp(const SSL_CIPHER * const *ap,
|
||||
const SSL_CIPHER * const *bp);
|
||||
@ -800,6 +800,7 @@ SSL_CIPHER *ssl3_get_cipher_by_char(const unsigned char *p);
|
||||
int ssl3_put_cipher_by_char(const SSL_CIPHER *c,unsigned char *p);
|
||||
void ssl3_init_finished_mac(SSL *s);
|
||||
int ssl3_send_server_certificate(SSL *s);
|
||||
int ssl3_send_newsession_ticket(SSL *s);
|
||||
int ssl3_get_finished(SSL *s,int state_a,int state_b);
|
||||
int ssl3_setup_key_block(SSL *s);
|
||||
int ssl3_send_change_cipher_spec(SSL *s,int state_a,int state_b);
|
||||
@ -890,6 +891,7 @@ long dtls1_default_timeout(void);
|
||||
int ssl3_client_hello(SSL *s);
|
||||
int ssl3_get_server_hello(SSL *s);
|
||||
int ssl3_get_certificate_request(SSL *s);
|
||||
int ssl3_get_new_session_ticket(SSL *s);
|
||||
int ssl3_get_server_done(SSL *s);
|
||||
int ssl3_send_client_verify(SSL *s);
|
||||
int ssl3_send_client_certificate(SSL *s);
|
||||
@ -985,6 +987,8 @@ int ssl_prepare_clienthello_tlsext(SSL *s);
|
||||
int ssl_prepare_serverhello_tlsext(SSL *s);
|
||||
int ssl_check_clienthello_tlsext(SSL *s);
|
||||
int ssl_check_serverhello_tlsext(SSL *s);
|
||||
int tls1_process_ticket(SSL *s, unsigned char *session_id, int len,
|
||||
const unsigned char *limit, SSL_SESSION **ret);
|
||||
EVP_MD_CTX* ssl_replace_hash(EVP_MD_CTX **hash,const EVP_MD *md) ;
|
||||
void ssl_clear_hash_ctx(EVP_MD_CTX **hash);
|
||||
#endif
|
||||
|
@ -308,6 +308,14 @@ int ssl_get_new_session(SSL *s, int session)
|
||||
SSL_SESSION_free(ss);
|
||||
return(0);
|
||||
}
|
||||
#ifndef OPENSSL_NO_TLSEXT
|
||||
/* If RFC4507 ticket use empty session ID */
|
||||
if (s->tlsext_ticket_expected)
|
||||
{
|
||||
ss->session_id_length = 0;
|
||||
goto sess_id_done;
|
||||
}
|
||||
#endif
|
||||
/* Choose which callback will set the session ID */
|
||||
CRYPTO_r_lock(CRYPTO_LOCK_SSL_CTX);
|
||||
if(s->generate_session_id)
|
||||
@ -350,6 +358,7 @@ int ssl_get_new_session(SSL *s, int session)
|
||||
return(0);
|
||||
}
|
||||
#ifndef OPENSSL_NO_TLSEXT
|
||||
sess_id_done:
|
||||
if (s->tlsext_hostname) {
|
||||
ss->tlsext_hostname = BUF_strdup(s->tlsext_hostname);
|
||||
if (ss->tlsext_hostname == NULL) {
|
||||
@ -406,21 +415,39 @@ int ssl_get_new_session(SSL *s, int session)
|
||||
return(1);
|
||||
}
|
||||
|
||||
int ssl_get_prev_session(SSL *s, unsigned char *session_id, int len)
|
||||
int ssl_get_prev_session(SSL *s, unsigned char *session_id, int len,
|
||||
const unsigned char *limit)
|
||||
{
|
||||
/* This is used only by servers. */
|
||||
|
||||
SSL_SESSION *ret=NULL,data;
|
||||
SSL_SESSION *ret=NULL;
|
||||
int fatal = 0;
|
||||
#ifndef OPENSSL_NO_TLSEXT
|
||||
int r;
|
||||
#endif
|
||||
|
||||
data.ssl_version=s->version;
|
||||
data.session_id_length=len;
|
||||
if (len > SSL_MAX_SSL_SESSION_ID_LENGTH)
|
||||
goto err;
|
||||
memcpy(data.session_id,session_id,len);
|
||||
|
||||
if (!(s->session_ctx->session_cache_mode & SSL_SESS_CACHE_NO_INTERNAL_LOOKUP))
|
||||
#ifndef OPENSSL_NO_TLSEXT
|
||||
r = tls1_process_ticket(s, session_id, len, limit, &ret);
|
||||
if (r == -1)
|
||||
{
|
||||
fatal = 1;
|
||||
goto err;
|
||||
}
|
||||
else if (r == 0)
|
||||
goto err;
|
||||
else if (!ret && !(s->session_ctx->session_cache_mode & SSL_SESS_CACHE_NO_INTERNAL_LOOKUP))
|
||||
#else
|
||||
if (!(s->session_ctx->session_cache_mode & SSL_SESS_CACHE_NO_INTERNAL_LOOKUP))
|
||||
#endif
|
||||
{
|
||||
SSL_SESSION data;
|
||||
data.ssl_version=s->version;
|
||||
data.session_id_length=len;
|
||||
if (len == 0)
|
||||
return 0;
|
||||
memcpy(data.session_id,session_id,len);
|
||||
CRYPTO_r_lock(CRYPTO_LOCK_SSL_CTX);
|
||||
ret=(SSL_SESSION *)lh_retrieve(s->session_ctx->sessions,&data);
|
||||
if (ret != NULL)
|
||||
@ -678,6 +705,7 @@ void SSL_SESSION_free(SSL_SESSION *ss)
|
||||
if (ss->ciphers != NULL) sk_SSL_CIPHER_free(ss->ciphers);
|
||||
#ifndef OPENSSL_NO_TLSEXT
|
||||
if (ss->tlsext_hostname != NULL) OPENSSL_free(ss->tlsext_hostname);
|
||||
if (ss->tlsext_tick != NULL) OPENSSL_free(ss->tlsext_tick);
|
||||
#ifndef OPENSSL_NO_EC
|
||||
ss->tlsext_ecpointformatlist_length = 0;
|
||||
if (ss->tlsext_ecpointformatlist != NULL) OPENSSL_free(ss->tlsext_ecpointformatlist);
|
||||
|
@ -183,6 +183,22 @@ int SSL_SESSION_print(BIO *bp, const SSL_SESSION *x)
|
||||
if (BIO_puts(bp,"\n PSK identity hint: ") <= 0) goto err;
|
||||
if (BIO_printf(bp, "%s", x->psk_identity_hint ? x->psk_identity_hint : "None") <= 0) goto err;
|
||||
#endif
|
||||
#ifndef OPENSSL_NO_TLSEXT
|
||||
if (x->tlsext_tick_lifetime_hint)
|
||||
{
|
||||
if (BIO_printf(bp,
|
||||
"\n TLS session ticket lifetime hint: %ld (seconds)",
|
||||
x->tlsext_tick_lifetime_hint) <=0)
|
||||
goto err;
|
||||
}
|
||||
if (x->tlsext_tick)
|
||||
{
|
||||
if (BIO_puts(bp, "\n TLS session ticket:\n") <= 0) goto err;
|
||||
if (BIO_dump_indent(bp, (char *)x->tlsext_tick, x->tlsext_ticklen, 4) <= 0)
|
||||
goto err;
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifndef OPENSSL_NO_COMP
|
||||
if (x->compress_meth != 0)
|
||||
{
|
||||
|
202
ssl/t1_lib.c
202
ssl/t1_lib.c
@ -111,10 +111,16 @@
|
||||
|
||||
#include <stdio.h>
|
||||
#include <openssl/objects.h>
|
||||
#include <openssl/evp.h>
|
||||
#include <openssl/hmac.h>
|
||||
#include "ssl_locl.h"
|
||||
|
||||
const char tls1_version_str[]="TLSv1" OPENSSL_VERSION_PTEXT;
|
||||
|
||||
static int tls_decrypt_ticket(SSL *s, const unsigned char *tick, int ticklen,
|
||||
const unsigned char *sess_id, int sesslen,
|
||||
SSL_SESSION **psess);
|
||||
|
||||
SSL3_ENC_METHOD TLSv1_enc_data={
|
||||
tls1_enc,
|
||||
tls1_mac,
|
||||
@ -164,6 +170,7 @@ unsigned char *ssl_add_clienthello_tlsext(SSL *s, unsigned char *p, unsigned cha
|
||||
ret+=2;
|
||||
|
||||
if (ret>=limit) return NULL; /* this really never occurs, but ... */
|
||||
|
||||
if (s->tlsext_hostname != NULL)
|
||||
{
|
||||
/* Add TLS extension servername to the Client Hello message */
|
||||
@ -243,6 +250,27 @@ unsigned char *ssl_add_clienthello_tlsext(SSL *s, unsigned char *p, unsigned cha
|
||||
}
|
||||
#endif /* OPENSSL_NO_EC */
|
||||
|
||||
if (!(SSL_get_options(s) & SSL_OP_NO_TICKET))
|
||||
{
|
||||
int ticklen;
|
||||
if (s->session && s->session->tlsext_tick)
|
||||
ticklen = s->session->tlsext_ticklen;
|
||||
else
|
||||
ticklen = 0;
|
||||
/* Check for enough room 2 for extension type, 2 for len
|
||||
* rest for ticket
|
||||
*/
|
||||
if (limit - p - 4 - ticklen < 0)
|
||||
return NULL;
|
||||
s2n(TLSEXT_TYPE_session_ticket,ret);
|
||||
s2n(ticklen,ret);
|
||||
if (ticklen)
|
||||
{
|
||||
memcpy(ret, s->session->tlsext_tick, ticklen);
|
||||
ret += ticklen;
|
||||
}
|
||||
}
|
||||
|
||||
if ((extdatalen = ret-p-2)== 0)
|
||||
return p;
|
||||
|
||||
@ -289,6 +317,14 @@ unsigned char *ssl_add_serverhello_tlsext(SSL *s, unsigned char *p, unsigned cha
|
||||
/* Currently the server should not respond with a SupportedCurves extension */
|
||||
#endif /* OPENSSL_NO_EC */
|
||||
|
||||
if (s->tlsext_ticket_expected
|
||||
&& !(SSL_get_options(s) & SSL_OP_NO_TICKET))
|
||||
{
|
||||
if (limit - p - 4 < 0) return NULL;
|
||||
s2n(TLSEXT_TYPE_session_ticket,ret);
|
||||
s2n(0,ret);
|
||||
}
|
||||
|
||||
if ((extdatalen = ret-p-2)== 0)
|
||||
return p;
|
||||
|
||||
@ -318,7 +354,10 @@ int ssl_parse_clienthello_tlsext(SSL *s, unsigned char **p, unsigned char *d, in
|
||||
|
||||
if (data+size > (d+n))
|
||||
return 1;
|
||||
|
||||
|
||||
if (s->tlsext_debug_cb)
|
||||
s->tlsext_debug_cb(s, 0, type, data, size,
|
||||
s->tlsext_debug_arg);
|
||||
/* The servername extension is treated as follows:
|
||||
|
||||
- Only the hostname type is supported with a maximum length of 255.
|
||||
@ -472,9 +511,10 @@ int ssl_parse_clienthello_tlsext(SSL *s, unsigned char **p, unsigned char *d, in
|
||||
#endif
|
||||
}
|
||||
#endif /* OPENSSL_NO_EC */
|
||||
data+=size;
|
||||
/* session ticket processed earlier */
|
||||
data+=size;
|
||||
}
|
||||
|
||||
|
||||
*p = data;
|
||||
return 1;
|
||||
}
|
||||
@ -501,6 +541,10 @@ int ssl_parse_serverhello_tlsext(SSL *s, unsigned char **p, unsigned char *d, in
|
||||
if (data+size > (d+n))
|
||||
return 1;
|
||||
|
||||
if (s->tlsext_debug_cb)
|
||||
s->tlsext_debug_cb(s, 1, type, data, size,
|
||||
s->tlsext_debug_arg);
|
||||
|
||||
if (type == TLSEXT_TYPE_server_name)
|
||||
{
|
||||
if (s->tlsext_hostname == NULL || size > 0)
|
||||
@ -540,6 +584,17 @@ int ssl_parse_serverhello_tlsext(SSL *s, unsigned char **p, unsigned char *d, in
|
||||
#endif
|
||||
}
|
||||
#endif /* OPENSSL_NO_EC */
|
||||
|
||||
else if (type == TLSEXT_TYPE_session_ticket)
|
||||
{
|
||||
if ((SSL_get_options(s) & SSL_OP_NO_TICKET)
|
||||
|| (size > 0))
|
||||
{
|
||||
*al = TLS1_AD_UNSUPPORTED_EXTENSION;
|
||||
return 0;
|
||||
}
|
||||
s->tlsext_ticket_expected = 1;
|
||||
}
|
||||
data+=size;
|
||||
}
|
||||
|
||||
@ -854,5 +909,144 @@ int ssl_check_serverhello_tlsext(SSL *s)
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Since the server cache lookup is done early on in the processing of client
|
||||
* hello and other operations depend on the result we need to handle any TLS
|
||||
* session ticket extension at the same time.
|
||||
*/
|
||||
|
||||
int tls1_process_ticket(SSL *s, unsigned char *session_id, int len,
|
||||
const unsigned char *limit, SSL_SESSION **ret)
|
||||
{
|
||||
/* Point after session ID in client hello */
|
||||
const unsigned char *p = session_id + len;
|
||||
unsigned short i;
|
||||
if ((s->version <= SSL3_VERSION) || !limit)
|
||||
return 1;
|
||||
if (p >= limit)
|
||||
return -1;
|
||||
/* Skip past cipher list */
|
||||
n2s(p, i);
|
||||
p+= i;
|
||||
if (p >= limit)
|
||||
return -1;
|
||||
/* Skip past compression algorithm list */
|
||||
i = *(p++);
|
||||
p += i;
|
||||
if (p > limit)
|
||||
return -1;
|
||||
/* Now at start of extensions */
|
||||
if ((p + 2) >= limit)
|
||||
return 1;
|
||||
n2s(p, i);
|
||||
while ((p + 4) <= limit)
|
||||
{
|
||||
unsigned short type, size;
|
||||
n2s(p, type);
|
||||
n2s(p, size);
|
||||
if (p + size > limit)
|
||||
return 1;
|
||||
if (type == TLSEXT_TYPE_session_ticket)
|
||||
{
|
||||
/* If tickets disabled indicate cache miss which will
|
||||
* trigger a full handshake
|
||||
*/
|
||||
if (SSL_get_options(s) & SSL_OP_NO_TICKET)
|
||||
return 0;
|
||||
/* If zero length not client will accept a ticket
|
||||
* and indicate cache miss to trigger full handshake
|
||||
*/
|
||||
if (size == 0)
|
||||
{
|
||||
s->tlsext_ticket_expected = 1;
|
||||
return 0; /* Cache miss */
|
||||
}
|
||||
return tls_decrypt_ticket(s, p, size, session_id, len,
|
||||
ret);
|
||||
}
|
||||
p += size;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int tls_decrypt_ticket(SSL *s, const unsigned char *etick, int eticklen,
|
||||
const unsigned char *sess_id, int sesslen,
|
||||
SSL_SESSION **psess)
|
||||
{
|
||||
SSL_SESSION *sess;
|
||||
unsigned char *sdec;
|
||||
const unsigned char *p;
|
||||
int slen, mlen;
|
||||
unsigned char tick_hmac[EVP_MAX_MD_SIZE];
|
||||
HMAC_CTX hctx;
|
||||
EVP_CIPHER_CTX ctx;
|
||||
/* Attempt to process session ticket, first conduct sanity and
|
||||
* integrity checks on ticket.
|
||||
*/
|
||||
mlen = EVP_MD_size(EVP_sha1());
|
||||
eticklen -= mlen;
|
||||
/* Need at least keyname + iv + some encrypted data */
|
||||
if (eticklen < 48)
|
||||
goto tickerr;
|
||||
/* Check key name matches */
|
||||
if (memcmp(etick, s->ctx->tlsext_tick_key_name, 16))
|
||||
goto tickerr;
|
||||
fprintf(stderr, "Ticket match OK\n");
|
||||
/* Check HMAC of encrypted ticket */
|
||||
HMAC_CTX_init(&hctx);
|
||||
HMAC_Init_ex(&hctx, s->ctx->tlsext_tick_hmac_key, 16,
|
||||
EVP_sha1(), NULL);
|
||||
HMAC_Update(&hctx, etick, eticklen);
|
||||
HMAC_Final(&hctx, tick_hmac, NULL);
|
||||
HMAC_CTX_cleanup(&hctx);
|
||||
if (memcmp(tick_hmac, etick + eticklen, mlen))
|
||||
goto tickerr;
|
||||
fprintf(stderr, "HMAC match OK\n");
|
||||
/* Set p to start of IV */
|
||||
p = etick + 16;
|
||||
EVP_CIPHER_CTX_init(&ctx);
|
||||
/* Attempt to decrypt session data */
|
||||
EVP_DecryptInit_ex(&ctx, EVP_aes_128_cbc(), NULL,
|
||||
s->ctx->tlsext_tick_aes_key, p);
|
||||
/* Move p after IV to start of encrypted ticket, update length */
|
||||
p += 16;
|
||||
eticklen -= 32;
|
||||
sdec = OPENSSL_malloc(eticklen);
|
||||
if (!sdec)
|
||||
{
|
||||
EVP_CIPHER_CTX_cleanup(&ctx);
|
||||
return -1;
|
||||
}
|
||||
EVP_DecryptUpdate(&ctx, sdec, &slen, p, eticklen);
|
||||
if (EVP_DecryptFinal(&ctx, sdec + slen, &mlen) <= 0)
|
||||
goto tickerr;
|
||||
fprintf(stderr, "Decrypt OK\n");
|
||||
slen += mlen;
|
||||
EVP_CIPHER_CTX_cleanup(&ctx);
|
||||
p = sdec;
|
||||
|
||||
sess = d2i_SSL_SESSION(NULL, &p, slen);
|
||||
OPENSSL_free(sdec);
|
||||
if (sess)
|
||||
{
|
||||
/* The session ID if non-empty is used by some clients to
|
||||
* detect that the ticket has been accepted. So we copy it to
|
||||
* the session structure. If it is empty set length to zero
|
||||
* as required by standard.
|
||||
*/
|
||||
if (sesslen)
|
||||
memcpy(sess->session_id, sess_id, sesslen);
|
||||
sess->session_id_length = sesslen;
|
||||
*psess = sess;
|
||||
return 1;
|
||||
}
|
||||
/* If session decrypt failure indicate a cache miss and set state to
|
||||
* send a new ticket
|
||||
*/
|
||||
tickerr:
|
||||
s->tlsext_ticket_expected = 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
#endif
|
||||
|
@ -192,6 +192,7 @@ extern "C" {
|
||||
#define TLSEXT_TYPE_status_request 5
|
||||
#define TLSEXT_TYPE_elliptic_curves 10
|
||||
#define TLSEXT_TYPE_ec_point_formats 11
|
||||
#define TLSEXT_TYPE_session_ticket 35
|
||||
|
||||
/* NameType value from RFC 3546 */
|
||||
#define TLSEXT_NAMETYPE_host_name 0
|
||||
@ -213,6 +214,12 @@ int SSL_get_servername_type(const SSL *s) ;
|
||||
#define SSL_set_tlsext_host_name(s,name) \
|
||||
SSL_ctrl(s,SSL_CTRL_SET_TLSEXT_HOSTNAME,TLSEXT_NAMETYPE_host_name,(char *)name)
|
||||
|
||||
#define SSL_set_tlsext_debug_callback(ssl, cb) \
|
||||
SSL_callback_ctrl(ssl,SSL_CTRL_SET_TLSEXT_DEBUG_CB,(void (*)(void))cb)
|
||||
|
||||
#define SSL_set_tlsext_debug_arg(ssl, arg) \
|
||||
SSL_ctrl(ssl,SSL_CTRL_SET_TLSEXT_DEBUG_ARG,0, (void *)arg)
|
||||
|
||||
#define SSL_CTX_set_tlsext_servername_callback(ctx, cb) \
|
||||
SSL_CTX_callback_ctrl(ctx,SSL_CTRL_SET_TLSEXT_SERVERNAME_CB,(void (*)(void))cb)
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user