diff options
author | Nikos Mavrogiannopoulos <nmav@gnutls.org> | 2012-09-30 13:12:03 +0200 |
---|---|---|
committer | Nikos Mavrogiannopoulos <nmav@gnutls.org> | 2012-09-30 13:12:03 +0200 |
commit | 52f373cdf26d50e05f5dd49e4ecc8b29fc742535 (patch) | |
tree | 5309cc77e362e81106da59d5df09a6e58586502e | |
parent | 7c6414a3ce88b09bc0106c53ec6d1dfb07e65c1d (diff) | |
download | gnutls-52f373cdf26d50e05f5dd49e4ecc8b29fc742535.tar.gz |
Backported fix for receiving session tickets during session resumption.
-rw-r--r-- | NEWS | 9 | ||||
-rw-r--r-- | lib/ext/session_ticket.c | 2 | ||||
-rw-r--r-- | lib/gnutls_handshake.c | 275 | ||||
-rw-r--r-- | lib/gnutls_handshake.h | 5 | ||||
-rw-r--r-- | lib/gnutls_int.h | 6 |
5 files changed, 156 insertions, 141 deletions
@@ -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 |