diff options
author | Daiki Ueno <dueno@redhat.com> | 2018-10-12 11:45:59 +0200 |
---|---|---|
committer | Daiki Ueno <dueno@redhat.com> | 2018-11-11 07:03:43 +0100 |
commit | 957f7537604b21653c0d456e55fabed600052508 (patch) | |
tree | 0e818d620669b1efe8f024eb1e4caf3f1d4217bd /lib/tls13 | |
parent | f39af59c4e7f7062b548c6c97e785bb6b6284371 (diff) | |
download | gnutls-957f7537604b21653c0d456e55fabed600052508.tar.gz |
handshake: handle early data
This plumbers early data handling in the handshake processes, which
consists of:
- traffic key updates taking into account of client_early_traffic_secret
- early data buffering in both server and client
- the EndOfEarlyData message handling
- making use of max_early_data_size extension in NewSessionTicket
Signed-off-by: Daiki Ueno <dueno@redhat.com>
Diffstat (limited to 'lib/tls13')
-rw-r--r-- | lib/tls13/early_data.c | 101 | ||||
-rw-r--r-- | lib/tls13/early_data.h | 25 | ||||
-rw-r--r-- | lib/tls13/session_ticket.c | 41 |
3 files changed, 164 insertions, 3 deletions
diff --git a/lib/tls13/early_data.c b/lib/tls13/early_data.c new file mode 100644 index 0000000000..dd977fc410 --- /dev/null +++ b/lib/tls13/early_data.c @@ -0,0 +1,101 @@ +/* + * Copyright (C) 2017 Red Hat, Inc. + * + * Author: Nikos Mavrogiannopoulos + * + * This file is part of GnuTLS. + * + * The GnuTLS is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public License + * as published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/> + * + */ + +#include "gnutls_int.h" +#include "handshake.h" +#include "tls13/early_data.h" + +int _gnutls13_send_early_data(gnutls_session_t session) +{ + int ret; + + if (!(session->security_parameters.entity == GNUTLS_CLIENT && + session->internals.hsk_flags & HSK_EARLY_DATA_IN_FLIGHT)) + return 0; + + while (session->internals.early_data_presend_buffer.length > 0) { + ret = + gnutls_record_send(session, + session->internals. + early_data_presend_buffer.data, + session->internals. + early_data_presend_buffer. + length); + if (ret < 0) + return gnutls_assert_val(ret); + + session->internals.early_data_presend_buffer.data += ret; + session->internals.early_data_presend_buffer.length -= ret; + } + + + return 0; +} + +int _gnutls13_send_end_of_early_data(gnutls_session_t session, unsigned again) +{ + int ret; + mbuffer_st *bufel = NULL; + gnutls_buffer_st buf; + + if (!(session->security_parameters.entity == GNUTLS_CLIENT && + session->internals.hsk_flags & HSK_EARLY_DATA_ACCEPTED)) + return 0; + + if (again == 0) { + ret = _gnutls_buffer_init_handshake_mbuffer(&buf); + if (ret < 0) + return gnutls_assert_val(ret); + + bufel = _gnutls_buffer_to_mbuffer(&buf); + } + + return _gnutls_send_handshake(session, bufel, GNUTLS_HANDSHAKE_END_OF_EARLY_DATA); +} + +int _gnutls13_recv_end_of_early_data(gnutls_session_t session) +{ + int ret; + gnutls_buffer_st buf; + + if (!(session->security_parameters.entity == GNUTLS_SERVER && + session->internals.hsk_flags & HSK_EARLY_DATA_ACCEPTED)) + return 0; + + ret = _gnutls_recv_handshake(session, GNUTLS_HANDSHAKE_END_OF_EARLY_DATA, 0, &buf); + if (ret < 0) + return gnutls_assert_val(ret); + + if (buf.length != 0) { + gnutls_assert(); + ret = GNUTLS_E_RECEIVED_ILLEGAL_PARAMETER; + goto cleanup; + } + + session->internals.hsk_flags &= ~HSK_EARLY_DATA_IN_FLIGHT; + + ret = 0; +cleanup: + + _gnutls_buffer_clear(&buf); + return ret; +} diff --git a/lib/tls13/early_data.h b/lib/tls13/early_data.h new file mode 100644 index 0000000000..ddbd983293 --- /dev/null +++ b/lib/tls13/early_data.h @@ -0,0 +1,25 @@ +/* + * Copyright (C) 2017 Red Hat, Inc. + * + * Author: Nikos Mavrogiannopoulos + * + * This file is part of GnuTLS. + * + * The GnuTLS is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public License + * as published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/> + * + */ + +int _gnutls13_send_end_of_early_data(gnutls_session_t session, unsigned again); +int _gnutls13_recv_end_of_early_data(gnutls_session_t session); +int _gnutls13_send_early_data(gnutls_session_t session); diff --git a/lib/tls13/session_ticket.c b/lib/tls13/session_ticket.c index ad04a60919..b34de41029 100644 --- a/lib/tls13/session_ticket.c +++ b/lib/tls13/session_ticket.c @@ -229,6 +229,23 @@ generate_session_ticket(gnutls_session_t session, tls13_ticket_st *ticket) return 0; } +static int append_nst_extension(void *ctx, gnutls_buffer_st *buf) +{ + gnutls_session_t session = ctx; + int ret; + + if (!(session->internals.flags & GNUTLS_ENABLE_EARLY_DATA)) + return 0; + + ret = _gnutls_buffer_append_prefix(buf, 32, + session->security_parameters. + max_early_data_size); + if (ret < 0) + gnutls_assert(); + + return ret; +} + int _gnutls13_send_session_ticket(gnutls_session_t session, unsigned nr, unsigned again) { int ret = 0; @@ -253,6 +270,8 @@ int _gnutls13_send_session_ticket(gnutls_session_t session, unsigned nr, unsigne if (again == 0) { for (i=0;i<nr;i++) { + unsigned init_pos; + memset(&ticket, 0, sizeof(tls13_ticket_st)); bufel = NULL; @@ -296,13 +315,28 @@ int _gnutls13_send_session_ticket(gnutls_session_t session, unsigned nr, unsigne goto cleanup; } - ret = _gnutls_buffer_append_prefix(&buf, 16, 0); + _gnutls_free_datum(&ticket.ticket); + + /* append extensions */ + ret = _gnutls_extv_append_init(&buf); if (ret < 0) { gnutls_assert(); goto cleanup; } + init_pos = ret; - _gnutls_free_datum(&ticket.ticket); + ret = _gnutls_extv_append(&buf, ext_mod_early_data.tls_id, session, + (extv_append_func)append_nst_extension); + if (ret < 0) { + gnutls_assert(); + goto cleanup; + } + + ret = _gnutls_extv_append_final(&buf, init_pos); + if (ret < 0) { + gnutls_assert(); + goto cleanup; + } bufel = _gnutls_buffer_to_mbuffer(&buf); @@ -337,7 +371,8 @@ static int parse_nst_extension(void *ctx, unsigned tls_id, const unsigned char * if (data_size < 4) return gnutls_assert_val(GNUTLS_E_TLS_PACKET_DECODING_ERROR); size = _gnutls_read_uint32(data); - session->security_parameters.max_early_data_size = size; + if (size < session->security_parameters.max_early_data_size) + session->security_parameters.max_early_data_size = size; } return 0; } |