summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorNikos Mavrogiannopoulos <nmav@gnutls.org>2012-09-30 13:12:03 +0200
committerNikos Mavrogiannopoulos <nmav@gnutls.org>2012-09-30 13:12:03 +0200
commit52f373cdf26d50e05f5dd49e4ecc8b29fc742535 (patch)
tree5309cc77e362e81106da59d5df09a6e58586502e
parent7c6414a3ce88b09bc0106c53ec6d1dfb07e65c1d (diff)
downloadgnutls-52f373cdf26d50e05f5dd49e4ecc8b29fc742535.tar.gz
Backported fix for receiving session tickets during session resumption.
-rw-r--r--NEWS9
-rw-r--r--lib/ext/session_ticket.c2
-rw-r--r--lib/gnutls_handshake.c275
-rw-r--r--lib/gnutls_handshake.h5
-rw-r--r--lib/gnutls_int.h6
5 files changed, 156 insertions, 141 deletions
diff --git a/NEWS b/NEWS
index ce910afa74..345148d403 100644
--- a/NEWS
+++ b/NEWS
@@ -2,6 +2,15 @@ GnuTLS NEWS -- History of user-visible changes. -*- outline -*-
Copyright (C) 2000-2012 Free Software Foundation, Inc.
See the end for copying conditions.
+* Version 3.0.25 (unreleased)
+
+** libgnutls: Fixed the receipt of session tickets during session resumption.
+Reported by danblack at http://savannah.gnu.org/support/?108146
+
+** API and ABI modifications:
+No changes since last version.
+
+
* Version 3.0.24 (released 2012-09-26)
** libgnutls: The %COMPAT keyword, if specified, will tolerate
diff --git a/lib/ext/session_ticket.c b/lib/ext/session_ticket.c
index 626c976e45..38a4538eea 100644
--- a/lib/ext/session_ticket.c
+++ b/lib/ext/session_ticket.c
@@ -54,7 +54,7 @@ static void session_ticket_deinit_data (extension_priv_data_t priv);
extension_entry_st ext_mod_session_ticket = {
.name = "SESSION TICKET",
.type = GNUTLS_EXTENSION_SESSION_TICKET,
- .parse_type = GNUTLS_EXT_TLS,
+ .parse_type = GNUTLS_EXT_MANDATORY,
.recv_func = session_ticket_recv_params,
.send_func = session_ticket_send_params,
diff --git a/lib/gnutls_handshake.c b/lib/gnutls_handshake.c
index cc664b8143..31d9d1f838 100644
--- a/lib/gnutls_handshake.c
+++ b/lib/gnutls_handshake.c
@@ -71,6 +71,13 @@ _gnutls_remove_unwanted_ciphersuites (gnutls_session_t session,
int cipher_suites_size,
gnutls_pk_algorithm_t *pk_algos,
size_t pk_algos_size);
+static int _gnutls_handshake_client (gnutls_session_t session);
+static int _gnutls_handshake_server (gnutls_session_t session);
+
+static int
+_gnutls_recv_handshake_final (gnutls_session_t session, int init);
+static int
+_gnutls_send_handshake_final (gnutls_session_t session, int init);
/* Empties but does not free the buffer
*/
@@ -1150,8 +1157,8 @@ _gnutls_send_handshake (gnutls_session_t session, mbuffer_st * bufel,
switch (type)
{
case GNUTLS_HANDSHAKE_CERTIFICATE_PKT: /* this one is followed by ServerHelloDone
- * or ClientKeyExchange always.
- */
+ * or ClientKeyExchange always.
+ */
case GNUTLS_HANDSHAKE_SERVER_KEY_EXCHANGE: /* as above */
case GNUTLS_HANDSHAKE_SERVER_HELLO: /* as above */
case GNUTLS_HANDSHAKE_CERTIFICATE_REQUEST: /* as above */
@@ -2398,17 +2405,8 @@ gnutls_handshake (gnutls_session_t session)
return ret;
}
- ret = _gnutls_handshake_common (session);
-
- if (ret < 0)
- {
- if (_gnutls_abort_handshake (session, ret) == 0)
- STATE = STATE0;
-
- return ret;
- }
-
- STATE = STATE0;
+ /* clear handshake buffer */
+ _gnutls_handshake_hash_buffers_clear (session);
if (IS_DTLS(session)==0)
{
@@ -2426,7 +2424,6 @@ gnutls_handshake (gnutls_session_t session)
return 0;
}
-
#define IMED_RET( str, ret, allow_alert) do { \
if (ret < 0) { \
/* EAGAIN and INTERRUPTED are always non-fatal */ \
@@ -2441,12 +2438,11 @@ gnutls_handshake (gnutls_session_t session)
} } while (0)
-
/*
* _gnutls_handshake_client
* This function performs the client side of the handshake of the TLS/SSL protocol.
*/
-int
+static int
_gnutls_handshake_client (gnutls_session_t session)
{
int ret = 0;
@@ -2471,14 +2467,14 @@ _gnutls_handshake_client (gnutls_session_t session)
STATE = STATE1;
IMED_RET ("send hello", ret, 1);
- case STATE11:
+ case STATE2:
if (IS_DTLS (session))
{
ret =
_gnutls_recv_handshake (session,
GNUTLS_HANDSHAKE_HELLO_VERIFY_REQUEST,
1, NULL);
- STATE = STATE11;
+ STATE = STATE2;
IMED_RET ("recv hello verify", ret, 1);
if (ret == 1)
@@ -2487,91 +2483,130 @@ _gnutls_handshake_client (gnutls_session_t session)
return 1;
}
}
- case STATE2:
+ case STATE3:
/* receive the server hello */
ret =
_gnutls_recv_handshake (session,
GNUTLS_HANDSHAKE_SERVER_HELLO,
0, NULL);
- STATE = STATE2;
+ STATE = STATE3;
IMED_RET ("recv hello", ret, 1);
- case STATE70:
+ case STATE4:
if (session->security_parameters.do_recv_supplemental)
{
ret = _gnutls_recv_supplemental (session);
- STATE = STATE70;
+ STATE = STATE4;
IMED_RET ("recv supplemental", ret, 1);
}
- case STATE3:
+ case STATE5:
/* RECV CERTIFICATE */
if (session->internals.resumed == RESUME_FALSE) /* if we are not resuming */
ret = _gnutls_recv_server_certificate (session);
- STATE = STATE3;
+ STATE = STATE5;
IMED_RET ("recv server certificate", ret, 1);
- case STATE4:
+ case STATE8:
/* receive the server key exchange */
if (session->internals.resumed == RESUME_FALSE) /* if we are not resuming */
ret = _gnutls_recv_server_kx_message (session);
- STATE = STATE4;
+ STATE = STATE8;
IMED_RET ("recv server kx message", ret, 1);
- case STATE5:
+ case STATE9:
/* receive the server certificate request - if any
*/
if (session->internals.resumed == RESUME_FALSE) /* if we are not resuming */
ret = _gnutls_recv_server_crt_request (session);
- STATE = STATE5;
+ STATE = STATE9;
IMED_RET ("recv server certificate request message", ret, 1);
- case STATE6:
+ case STATE10:
/* receive the server hello done */
if (session->internals.resumed == RESUME_FALSE) /* if we are not resuming */
ret =
_gnutls_recv_handshake (session,
GNUTLS_HANDSHAKE_SERVER_HELLO_DONE,
0, NULL);
- STATE = STATE6;
+ STATE = STATE10;
IMED_RET ("recv server hello done", ret, 1);
- case STATE71:
+
+ case STATE11:
if (session->security_parameters.do_send_supplemental)
{
- ret = _gnutls_send_supplemental (session, AGAIN (STATE71));
- STATE = STATE71;
+ ret = _gnutls_send_supplemental (session, AGAIN (STATE11));
+ STATE = STATE11;
IMED_RET ("send supplemental", ret, 0);
}
- case STATE7:
+ case STATE12:
/* send our certificate - if any and if requested
*/
if (session->internals.resumed == RESUME_FALSE) /* if we are not resuming */
- ret = _gnutls_send_client_certificate (session, AGAIN (STATE7));
- STATE = STATE7;
+ ret = _gnutls_send_client_certificate (session, AGAIN (STATE12));
+ STATE = STATE12;
IMED_RET ("send client certificate", ret, 0);
- case STATE8:
+ case STATE13:
if (session->internals.resumed == RESUME_FALSE) /* if we are not resuming */
- ret = _gnutls_send_client_kx_message (session, AGAIN (STATE8));
- STATE = STATE8;
+ ret = _gnutls_send_client_kx_message (session, AGAIN (STATE13));
+ STATE = STATE13;
IMED_RET ("send client kx", ret, 0);
- case STATE9:
+ case STATE14:
/* send client certificate verify */
if (session->internals.resumed == RESUME_FALSE) /* if we are not resuming */
ret =
- _gnutls_send_client_certificate_verify (session, AGAIN (STATE9));
- STATE = STATE9;
+ _gnutls_send_client_certificate_verify (session, AGAIN (STATE14));
+ STATE = STATE14;
IMED_RET ("send client certificate verify", ret, 1);
+ case STATE15:
+ STATE = STATE15;
+ if (session->internals.resumed == RESUME_FALSE)
+ {
+ ret = _gnutls_send_handshake_final (session, TRUE);
+ IMED_RET ("send handshake final 2", ret, 1);
+ }
+ else
+ {
+ ret = _gnutls_recv_new_session_ticket (session);
+ IMED_RET ("recv handshake new session ticket", ret, 1);
+ }
+
+ case STATE16:
+ STATE = STATE16;
+ if (session->internals.resumed == RESUME_FALSE)
+ {
+ ret = _gnutls_recv_new_session_ticket (session);
+ IMED_RET ("recv handshake new session ticket", ret, 1);
+ }
+ else
+ {
+ ret = _gnutls_recv_handshake_final (session, TRUE);
+ IMED_RET ("recv handshake final", ret, 1);
+ }
+
+ case STATE17:
+ STATE = STATE17;
+ if (session->internals.resumed == RESUME_FALSE)
+ {
+ ret = _gnutls_recv_handshake_final (session, FALSE);
+ IMED_RET ("recv handshake final 2", ret, 1);
+ }
+ else
+ {
+ ret = _gnutls_send_handshake_final (session, FALSE);
+ IMED_RET ("send handshake final", ret, 1);
+ }
+
STATE = STATE0;
default:
break;
}
-
return 0;
}
@@ -2630,12 +2665,12 @@ _gnutls_send_handshake_final (gnutls_session_t session, int init)
/* Send the CHANGE CIPHER SPEC PACKET */
- switch (STATE)
+ switch (FINAL_STATE)
{
case STATE0:
- case STATE20:
- ret = send_change_cipher_spec (session, AGAIN (STATE20));
- STATE = STATE0;
+ case STATE1:
+ ret = send_change_cipher_spec (session, FAGAIN (STATE1));
+ FINAL_STATE = STATE0;
if (ret < 0)
{
@@ -2662,10 +2697,10 @@ _gnutls_send_handshake_final (gnutls_session_t session, int init)
return ret;
}
- case STATE21:
+ case STATE2:
/* send the finished message */
- ret = _gnutls_send_finished (session, AGAIN (STATE21));
- STATE = STATE21;
+ ret = _gnutls_send_finished (session, FAGAIN (STATE2));
+ FINAL_STATE = STATE2;
if (ret < 0)
{
ERR ("send Finished", ret);
@@ -2673,7 +2708,7 @@ _gnutls_send_handshake_final (gnutls_session_t session, int init)
return ret;
}
- STATE = STATE0;
+ FINAL_STATE = STATE0;
default:
break;
}
@@ -2691,12 +2726,12 @@ _gnutls_recv_handshake_final (gnutls_session_t session, int init)
int ret = 0;
uint8_t ch;
unsigned int ccs_len = 1;
-
- switch (STATE)
+
+ switch (FINAL_STATE)
{
case STATE0:
case STATE30:
- STATE = STATE30;
+ FINAL_STATE = STATE30;
/* This is the last flight and peer cannot be sure
* we have received it unless we notify him. So we
@@ -2743,7 +2778,7 @@ _gnutls_recv_handshake_final (gnutls_session_t session, int init)
}
case STATE31:
- STATE = STATE31;
+ FINAL_STATE = STATE31;
if (IS_DTLS(session) && !_dtls_is_async(session) &&
(gnutls_record_check_pending( session) +
@@ -2761,7 +2796,7 @@ _gnutls_recv_handshake_final (gnutls_session_t session, int init)
gnutls_assert ();
return ret;
}
- STATE = STATE0;
+ FINAL_STATE = STATE0;
default:
break;
}
@@ -2774,7 +2809,7 @@ _gnutls_recv_handshake_final (gnutls_session_t session, int init)
* _gnutls_handshake_server
* This function does the server stuff of the handshake protocol.
*/
-int
+static int
_gnutls_handshake_server (gnutls_session_t session)
{
int ret = 0;
@@ -2812,29 +2847,29 @@ _gnutls_handshake_server (gnutls_session_t session)
STATE = STATE3;
IMED_RET ("send server certificate", ret, 0);
- case STATE4:
+ case STATE5:
/* send server key exchange (A) */
if (session->internals.resumed == RESUME_FALSE)
- ret = _gnutls_send_server_kx_message (session, AGAIN (STATE4));
- STATE = STATE4;
+ ret = _gnutls_send_server_kx_message (session, AGAIN (STATE5));
+ STATE = STATE5;
IMED_RET ("send server kx", ret, 0);
- case STATE5:
+ case STATE6:
/* Send certificate request - if requested to */
if (session->internals.resumed == RESUME_FALSE)
ret =
- _gnutls_send_server_crt_request (session, AGAIN (STATE5));
- STATE = STATE5;
+ _gnutls_send_server_crt_request (session, AGAIN (STATE6));
+ STATE = STATE6;
IMED_RET ("send server cert request", ret, 0);
- case STATE6:
+ case STATE7:
/* send the server hello done */
if (session->internals.resumed == RESUME_FALSE) /* if we are not resuming */
ret =
_gnutls_send_empty_handshake (session,
GNUTLS_HANDSHAKE_SERVER_HELLO_DONE,
- AGAIN (STATE6));
- STATE = STATE6;
+ AGAIN (STATE7));
+ STATE = STATE7;
IMED_RET ("send server hello done", ret, 1);
case STATE71:
@@ -2846,103 +2881,73 @@ _gnutls_handshake_server (gnutls_session_t session)
}
/* RECV CERTIFICATE + KEYEXCHANGE + CERTIFICATE_VERIFY */
- case STATE7:
+ case STATE8:
/* receive the client certificate message */
if (session->internals.resumed == RESUME_FALSE) /* if we are not resuming */
ret = _gnutls_recv_client_certificate (session);
- STATE = STATE7;
+ STATE = STATE8;
IMED_RET ("recv client certificate", ret, 1);
- case STATE8:
+ case STATE10:
/* receive the client key exchange message */
if (session->internals.resumed == RESUME_FALSE) /* if we are not resuming */
ret = _gnutls_recv_client_kx_message (session);
- STATE = STATE8;
+ STATE = STATE10;
IMED_RET ("recv client kx", ret, 1);
- case STATE9:
+ case STATE11:
/* receive the client certificate verify message */
if (session->internals.resumed == RESUME_FALSE) /* if we are not resuming */
ret = _gnutls_recv_client_certificate_verify_message (session);
- STATE = STATE9;
+ STATE = STATE11;
IMED_RET ("recv client certificate verify", ret, 1);
- STATE = STATE0; /* finished thus clear session */
- default:
- break;
- }
-
- return 0;
-}
-
-int
-_gnutls_handshake_common (gnutls_session_t session)
-{
- int ret = 0;
-
- /* send and recv the change cipher spec and finished messages */
- if ((session->internals.resumed != RESUME_FALSE
- && session->security_parameters.entity == GNUTLS_CLIENT)
- || (session->internals.resumed == RESUME_FALSE
- && session->security_parameters.entity == GNUTLS_SERVER))
- {
- /* if we are a client resuming - or we are a server not resuming */
- ret = _gnutls_recv_handshake_final (session, TRUE);
- IMED_RET ("recv handshake final", ret, 1);
-
- switch (STATE)
- {
- case STATE0:
- case STATE40:
- ret = _gnutls_send_new_session_ticket (session, AGAIN (STATE40));
- STATE = STATE40;
- IMED_RET ("send handshake new session ticket", ret, 0);
- STATE = STATE0;
- default:
- break;
+ case STATE12:
+ STATE = STATE12;
+ if (session->internals.resumed == RESUME_FALSE) /* if we are not resuming */
+ {
+ ret = _gnutls_recv_handshake_final (session, TRUE);
+ IMED_RET ("recv handshake final", ret, 1);
}
-
- ret = _gnutls_send_handshake_final (session, FALSE);
- IMED_RET ("send handshake final", ret, 1);
-
- /* only store if we are not resuming a session and we didn't previously send a ticket
- */
- if (session->security_parameters.entity == GNUTLS_SERVER && session->internals.ticket_sent == 0)
+ else
{
- /* in order to support session resuming */
- _gnutls_server_register_current_session (session);
+ ret = _gnutls_send_handshake_final (session, TRUE);
+ IMED_RET ("send handshake final 2", ret, 1);
}
- }
- else
- { /* if we are a client not resuming - or we are a server resuming */
- ret = _gnutls_send_handshake_final (session, TRUE);
- IMED_RET ("send handshake final 2", ret, 1);
+ case STATE13:
+ ret = _gnutls_send_new_session_ticket (session, AGAIN (STATE13));
+ STATE = STATE13;
+ IMED_RET ("send handshake new session ticket", ret, 0);
- switch (STATE)
+ case STATE14:
+ STATE = STATE14;
+ if (session->internals.resumed == RESUME_FALSE) /* if we are not resuming */
{
- case STATE0:
- case STATE41:
- ret = _gnutls_recv_new_session_ticket (session);
- STATE = STATE41;
- IMED_RET ("recv handshake new session ticket", ret, 1);
- STATE = STATE0;
- default:
- break;
+ ret = _gnutls_send_handshake_final (session, FALSE);
+ IMED_RET ("send handshake final", ret, 1);
+ }
+ else
+ {
+ ret = _gnutls_recv_handshake_final (session, FALSE);
+ IMED_RET ("recv handshake final 2", ret, 1);
}
- ret = _gnutls_recv_handshake_final (session, FALSE);
- IMED_RET ("recv handshake final 2", ret, 1);
+ if (session->security_parameters.entity == GNUTLS_SERVER && session->internals.ticket_sent == 0)
+ {
+ /* if no ticket, save session data */
+ _gnutls_server_register_current_session (session);
+ }
+ STATE = STATE0;
+ default:
+ break;
}
-
- /* clear handshake buffer */
- _gnutls_handshake_hash_buffers_clear (session);
- return ret;
-
+ return 0;
}
+
int
_gnutls_generate_session_id (uint8_t * session_id, uint8_t * len)
{
diff --git a/lib/gnutls_handshake.h b/lib/gnutls_handshake.h
index 39c9c8a517..b3fb1af356 100644
--- a/lib/gnutls_handshake.h
+++ b/lib/gnutls_handshake.h
@@ -33,9 +33,6 @@ int _gnutls_recv_handshake (gnutls_session_t session,
gnutls_handshake_description_t type,
unsigned int optional, gnutls_buffer_st* buf);
int _gnutls_generate_session_id (uint8_t * session_id, uint8_t * len);
-int _gnutls_handshake_common (gnutls_session_t session);
-int _gnutls_handshake_client (gnutls_session_t session);
-int _gnutls_handshake_server (gnutls_session_t session);
void _gnutls_set_server_random (gnutls_session_t session, uint8_t * rnd);
void _gnutls_set_client_random (gnutls_session_t session, uint8_t * rnd);
int _gnutls_tls_create_random (uint8_t * dst);
@@ -52,10 +49,12 @@ int _gnutls_user_hello_func (gnutls_session_t session,
void _gnutls_handshake_hash_buffers_clear (gnutls_session_t session);
#define STATE session->internals.handshake_state
+#define FINAL_STATE session->internals.handshake_final_state
/* This returns true if we have got there
* before (and not finished due to an interrupt).
*/
#define AGAIN(target) (STATE==target?1:0)
+#define FAGAIN(target) (FINAL_STATE==target?1:0)
#define AGAIN2(state, target) (state==target?1:0)
#endif
diff --git a/lib/gnutls_int.h b/lib/gnutls_int.h
index fee1401531..414a2003b7 100644
--- a/lib/gnutls_int.h
+++ b/lib/gnutls_int.h
@@ -223,8 +223,9 @@ typedef struct
typedef enum handshake_state_t
{ STATE0 = 0, STATE1, STATE2,
- STATE3, STATE4, STATE5,
- STATE6, STATE7, STATE8, STATE9, STATE11 = 11,
+ STATE3, STATE4, STATE5, STATE6, STATE7, STATE8,
+ STATE9, STATE10, STATE11, STATE12, STATE13, STATE14,
+ STATE15, STATE16, STATE17,
STATE20 = 20, STATE21, STATE22,
STATE30 = 30, STATE31, STATE40 = 40, STATE41, STATE50 = 50,
STATE60 = 60, STATE61, STATE62, STATE70, STATE71
@@ -673,6 +674,7 @@ typedef struct
* message */
unsigned int resumable:1; /* TRUE or FALSE - if we can resume that session */
unsigned int ticket_sent:1; /* whether a session ticket was sent */
+ handshake_state_t handshake_final_state;
handshake_state_t handshake_state; /* holds
* a number which indicates where
* the handshake procedure has been