Blob Blame Raw
diff -up openssl-1.0.1e/ssl/ssl_err.c.ticket-race openssl-1.0.1e/ssl/ssl_err.c
--- openssl-1.0.1e/ssl/ssl_err.c.ticket-race	2015-06-09 15:40:41.000000000 +0200
+++ openssl-1.0.1e/ssl/ssl_err.c	2015-06-09 15:45:06.879198463 +0200
@@ -245,6 +245,7 @@ static ERR_STRING_DATA SSL_str_functs[]=
 {ERR_FUNC(SSL_F_SSL_READ),	"SSL_read"},
 {ERR_FUNC(SSL_F_SSL_RSA_PRIVATE_DECRYPT),	"SSL_RSA_PRIVATE_DECRYPT"},
 {ERR_FUNC(SSL_F_SSL_RSA_PUBLIC_ENCRYPT),	"SSL_RSA_PUBLIC_ENCRYPT"},
+{ERR_FUNC(SSL_F_SSL_SESSION_DUP),	"ssl_session_dup"},
 {ERR_FUNC(SSL_F_SSL_SESSION_NEW),	"SSL_SESSION_new"},
 {ERR_FUNC(SSL_F_SSL_SESSION_PRINT_FP),	"SSL_SESSION_print_fp"},
 {ERR_FUNC(SSL_F_SSL_SESSION_SET1_ID_CONTEXT),	"SSL_SESSION_set1_id_context"},
diff -up openssl-1.0.1e/ssl/ssl.h.ticket-race openssl-1.0.1e/ssl/ssl.h
--- openssl-1.0.1e/ssl/ssl.h.ticket-race	2015-06-09 15:40:41.000000000 +0200
+++ openssl-1.0.1e/ssl/ssl.h	2015-06-09 15:44:22.696191291 +0200
@@ -2176,6 +2176,7 @@ void ERR_load_SSL_strings(void);
 #define SSL_F_SSL_READ					 223
 #define SSL_F_SSL_RSA_PRIVATE_DECRYPT			 187
 #define SSL_F_SSL_RSA_PUBLIC_ENCRYPT			 188
+#define SSL_F_SSL_SESSION_DUP				 348
 #define SSL_F_SSL_SESSION_NEW				 189
 #define SSL_F_SSL_SESSION_PRINT_FP			 190
 #define SSL_F_SSL_SESSION_SET1_ID_CONTEXT		 312
diff -up openssl-1.0.1e/ssl/ssl_locl.h.ticket-race openssl-1.0.1e/ssl/ssl_locl.h
--- openssl-1.0.1e/ssl/ssl_locl.h.ticket-race	2015-06-09 15:40:41.000000000 +0200
+++ openssl-1.0.1e/ssl/ssl_locl.h	2015-06-09 16:02:41.105243796 +0200
@@ -822,6 +822,7 @@ 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, const unsigned char *limit);
+SSL_SESSION *ssl_session_dup(SSL_SESSION *src, int ticket);
 int ssl_cipher_id_cmp(const SSL_CIPHER *a,const SSL_CIPHER *b);
 DECLARE_OBJ_BSEARCH_GLOBAL_CMP_FN(SSL_CIPHER, SSL_CIPHER,
 				  ssl_cipher_id);
diff -up openssl-1.0.1e/ssl/ssl_sess.c.ticket-race openssl-1.0.1e/ssl/ssl_sess.c
--- openssl-1.0.1e/ssl/ssl_sess.c.ticket-race	2013-02-11 16:26:04.000000000 +0100
+++ openssl-1.0.1e/ssl/ssl_sess.c	2015-06-11 13:48:26.724348868 +0200
@@ -224,6 +224,146 @@ SSL_SESSION *SSL_SESSION_new(void)
 	return(ss);
 	}
 
+/*
+ * Create a new SSL_SESSION and duplicate the contents of |src| into it. If
+ * ticket == 0 then no ticket information is duplicated, otherwise it is.
+ */
+SSL_SESSION *ssl_session_dup(SSL_SESSION *src, int ticket)
+{
+	SSL_SESSION *dest;
+
+	dest = OPENSSL_malloc(sizeof(*src));
+	if (dest == NULL)
+		{
+		goto err;
+		}
+	memcpy(dest, src, sizeof(*dest));
+
+	/*
+	 * Set the various pointers to NULL so that we can call SSL_SESSION_free in
+	 * the case of an error whilst halfway through constructing dest
+	 */
+#ifndef OPENSSL_NO_PSK
+	dest->psk_identity_hint = NULL;
+	dest->psk_identity = NULL;
+#endif
+	dest->ciphers = NULL;
+#ifndef OPENSSL_NO_TLSEXT
+	dest->tlsext_hostname = NULL;
+# ifndef OPENSSL_NO_EC
+	dest->tlsext_ecpointformatlist = NULL;
+	dest->tlsext_ellipticcurvelist = NULL;
+# endif
+#endif
+	dest->tlsext_tick = NULL;
+#ifndef OPENSSL_NO_SRP
+	dest->srp_username = NULL;
+#endif
+	memset(&dest->ex_data, 0, sizeof(dest->ex_data));
+
+	/* We deliberately don't copy the prev and next pointers */
+	dest->prev = NULL;
+	dest->next = NULL;
+
+	dest->references = 1;
+
+	if (src->sess_cert != NULL)
+		CRYPTO_add(&src->sess_cert->references, 1, CRYPTO_LOCK_SSL_SESS_CERT);
+
+	if (src->peer != NULL)
+		CRYPTO_add(&src->peer->references, 1, CRYPTO_LOCK_X509);
+
+#ifndef OPENSSL_NO_PSK
+	if (src->psk_identity_hint)
+		{
+		dest->psk_identity_hint = BUF_strdup(src->psk_identity_hint);
+		if (dest->psk_identity_hint == NULL)
+			{
+			goto err;
+			}
+		}
+	if (src->psk_identity)
+		{
+		dest->psk_identity = BUF_strdup(src->psk_identity);
+		if (dest->psk_identity == NULL)
+			{
+			goto err;
+			}
+		}
+#endif
+
+	if(src->ciphers != NULL)
+		{
+		dest->ciphers = sk_SSL_CIPHER_dup(src->ciphers);
+		if (dest->ciphers == NULL)
+			goto err;
+		}
+
+	if (!CRYPTO_dup_ex_data(CRYPTO_EX_INDEX_SSL_SESSION,
+				&dest->ex_data, &src->ex_data))
+		{
+		goto err;
+		}
+
+#ifndef OPENSSL_NO_TLSEXT
+	if (src->tlsext_hostname)
+		{
+		dest->tlsext_hostname = BUF_strdup(src->tlsext_hostname);
+		if (dest->tlsext_hostname == NULL)
+			{
+			goto err;
+			}
+		}
+# ifndef OPENSSL_NO_EC
+	if (src->tlsext_ecpointformatlist)
+		{
+		dest->tlsext_ecpointformatlist =
+			BUF_memdup(src->tlsext_ecpointformatlist,
+				src->tlsext_ecpointformatlist_length);
+		if (dest->tlsext_ecpointformatlist == NULL)
+			goto err;
+		}
+	if (src->tlsext_ellipticcurvelist)
+		{
+		dest->tlsext_ellipticcurvelist =
+			BUF_memdup(src->tlsext_ellipticcurvelist,
+				src->tlsext_ellipticcurvelist_length);
+		if (dest->tlsext_ellipticcurvelist == NULL)
+			goto err;
+		}
+# endif
+#endif
+
+	if (ticket != 0)
+		{
+		dest->tlsext_tick = BUF_memdup(src->tlsext_tick, src->tlsext_ticklen);
+        	if(dest->tlsext_tick == NULL)
+			goto err;
+		}
+	else
+		{
+		dest->tlsext_tick_lifetime_hint = 0;
+		dest->tlsext_ticklen = 0;
+		}
+
+#ifndef OPENSSL_NO_SRP
+	if (src->srp_username)
+		{
+		dest->srp_username = BUF_strdup(src->srp_username);
+		if (dest->srp_username == NULL)
+			{
+			goto err;
+			}
+		}
+#endif
+
+	return dest;
+err:
+	SSLerr(SSL_F_SSL_SESSION_DUP, ERR_R_MALLOC_FAILURE);
+	SSL_SESSION_free(dest);
+	return NULL;
+}
+
 const unsigned char *SSL_SESSION_get_id(const SSL_SESSION *s, unsigned int *len)
 	{
 	if(len)
diff -up openssl-1.0.1e/ssl/s3_clnt.c.ticket-race openssl-1.0.1e/ssl/s3_clnt.c
--- openssl-1.0.1e/ssl/s3_clnt.c.ticket-race	2015-06-09 15:40:41.000000000 +0200
+++ openssl-1.0.1e/ssl/s3_clnt.c	2015-06-09 15:39:56.315119013 +0200
@@ -2092,6 +2092,44 @@ int ssl3_get_new_session_ticket(SSL *s)
 		}
 
 	p=d=(unsigned char *)s->init_msg;
+
+	if (s->session->session_id_length > 0)
+		{
+		int i = s->session_ctx->session_cache_mode;
+		SSL_SESSION *new_sess;
+		/*
+		 * We reused an existing session, so we need to replace it with a new
+		 * one
+		 */
+		if (i & SSL_SESS_CACHE_CLIENT)
+			{
+			/*
+			 * Remove the old session from the cache
+			 */
+			if (i & SSL_SESS_CACHE_NO_INTERNAL_STORE)
+				{
+				if (s->session_ctx->remove_session_cb != NULL)
+					s->session_ctx->remove_session_cb(s->session_ctx,
+						s->session);
+				}
+			else
+				{
+				/* We carry on if this fails */
+				SSL_CTX_remove_session(s->session_ctx, s->session);
+				}
+			}
+
+		if ((new_sess = ssl_session_dup(s->session, 0)) == 0)
+			{
+			al = SSL_AD_INTERNAL_ERROR;
+			SSLerr(SSL_F_SSL3_GET_NEW_SESSION_TICKET, ERR_R_MALLOC_FAILURE);
+			goto f_err;
+			}
+
+		SSL_SESSION_free(s->session);
+		s->session = new_sess;
+		}
+
 	n2l(p, s->session->tlsext_tick_lifetime_hint);
 	n2s(p, ticklen);
 	/* ticket_lifetime_hint + ticket_length + ticket */