diff options
author | Nikos Mavrogiannopoulos <nmav@redhat.com> | 2016-02-23 09:40:26 +0100 |
---|---|---|
committer | Nikos Mavrogiannopoulos <nmav@gnutls.org> | 2016-02-27 22:13:43 +0100 |
commit | dd8fb0e3e104836d69654d208129f7c762e3cdc0 (patch) | |
tree | f4fc0571261deda9f4ccf38a444496298120c748 /lib/handshake.c | |
parent | 72fcf7dfe9f0388ea3ea9a03078b5ba1c183adcd (diff) | |
download | gnutls-dd8fb0e3e104836d69654d208129f7c762e3cdc0.tar.gz |
Added gnutls_handshake_set_false_start_function()
This function allows to use TLS False-start, by using the provided
function to send data just after finished message.
Diffstat (limited to 'lib/handshake.c')
-rw-r--r-- | lib/handshake.c | 78 |
1 files changed, 76 insertions, 2 deletions
diff --git a/lib/handshake.c b/lib/handshake.c index 8fa0b24a11..d54bc264e1 100644 --- a/lib/handshake.c +++ b/lib/handshake.c @@ -1276,6 +1276,8 @@ _gnutls_send_handshake(gnutls_session_t session, mbuffer_st * bufel, return ret; } + /* The messages which are followed by another are not sent by default + * but are cached instead */ switch (type) { case GNUTLS_HANDSHAKE_CERTIFICATE_PKT: /* this one is followed by ServerHelloDone * or ClientKeyExchange always. @@ -2413,6 +2415,44 @@ int gnutls_rehandshake(gnutls_session_t session) return 0; } +/** + * gnutls_handshake_set_false_start_function: + * @session: is a #gnutls_session_t type. + * @func: is the function to be called + * @flags: should be zero + * + * This function in client side will ensure that @func is called + * after the client's side of the handshake is complete. That is, + * it can be used to send data before gnutls_handshake() completes + * (i.e., before the peer's Finished message is received) + * and reduce the handshake to a single round-trip. + * + * This callback must return 0 on success or a gnutls error code to + * terminate the handshake. Typically it should include a call to + * gnutls_record_send(). + * + * Note that, this utilises the so-called TLS False Start, + * which may increase the risk of cryptographic failure when + * combined with certain ciphers and key exchanges. For that + * GnuTLS will call the provided function prior to receiving + * the finished messages only in case of known to be secure ciphers. + * Otherwise @func is called after the handshake is fully complete. + * + * On the server side this function always fail. + * + * Returns: %GNUTLS_E_SUCCESS on success, otherwise a negative error code. + **/ +int gnutls_handshake_set_false_start_function(gnutls_session_t session, + gnutls_handshake_simple_hook_func func, unsigned flags) +{ + if (session->security_parameters.entity == GNUTLS_CLIENT) { + session->internals.false_start_func = func; + return 0; + } + + return gnutls_assert_val(GNUTLS_E_INVALID_REQUEST); +} + inline static int _gnutls_abort_handshake(gnutls_session_t session, int ret) { @@ -2738,6 +2778,23 @@ static int run_verify_callback(gnutls_session_t session, unsigned int side) return 0; } +static bool can_send_false_start(gnutls_session_t session) +{ + const version_entry_st *vers; + + vers = get_version(session); + if (unlikely(vers == NULL || !vers->false_start)) + return 0; + + if (session->internals.selected_cert_list != NULL) + return 0; + + if (!_gnutls_kx_allows_false_start(session)) + return 0; + + return 1; +} + /* * handshake_client * This function performs the client side of the handshake of the TLS/SSL protocol. @@ -2906,6 +2963,16 @@ static int handshake_client(gnutls_session_t session) case STATE17: STATE = STATE17; + if (session->internals.resumed == RESUME_FALSE && can_send_false_start(session) && session->internals.false_start_func != 0) { + session->internals.false_start_used = 1; + ret = session->internals.false_start_func(session); + IMED_RET("false start", ret, 1); + } else { + session->internals.false_start_used = 0; + } + + case STATE18: + STATE = STATE18; if (session->internals.resumed == RESUME_FALSE) { #ifdef ENABLE_SESSION_TICKETS ret = _gnutls_recv_new_session_ticket(session); @@ -2917,8 +2984,8 @@ static int handshake_client(gnutls_session_t session) IMED_RET("recv handshake final", ret, 1); } - case STATE18: - STATE = STATE18; + case STATE19: + STATE = STATE19; if (session->internals.resumed == RESUME_FALSE) { ret = recv_handshake_final(session, FALSE); IMED_RET("recv handshake final 2", ret, 1); @@ -2927,6 +2994,13 @@ static int handshake_client(gnutls_session_t session) IMED_RET("send handshake final", ret, 1); } + case STATE20: + STATE = STATE20; + if ((session->internals.resumed != RESUME_FALSE || !can_send_false_start(session)) && session->internals.false_start_func != 0) { + ret = session->internals.false_start_func(session); + IMED_RET("false start", ret, 1); + } + STATE = STATE0; default: break; |