** API and ABI modifications:
GNUTLS_ENABLE_EARLY_START: Added
+gnutls_record_set_max_early_data_size: Added
* Version 3.6.3 (released 2018-07-16)
FUNCS += functions/gnutls_record_send2.short
FUNCS += functions/gnutls_record_send_range
FUNCS += functions/gnutls_record_send_range.short
+FUNCS += functions/gnutls_record_set_max_early_data_size
+FUNCS += functions/gnutls_record_set_max_early_data_size.short
FUNCS += functions/gnutls_record_set_max_size
FUNCS += functions/gnutls_record_set_max_size.short
FUNCS += functions/gnutls_record_set_state
APIMANS += gnutls_record_send.3
APIMANS += gnutls_record_send2.3
APIMANS += gnutls_record_send_range.3
+APIMANS += gnutls_record_set_max_early_data_size.3
APIMANS += gnutls_record_set_max_size.3
APIMANS += gnutls_record_set_state.3
APIMANS += gnutls_record_set_timeout.3
cookie.c cookie.h \
psk_ke_modes.c psk_ke_modes.h pre_shared_key.c pre_shared_key.h \
supported_groups.c supported_groups.h \
- ec_point_formats.c ec_point_formats.h
+ ec_point_formats.c ec_point_formats.h \
+ early_data.c early_data.h
if ENABLE_ALPN
libgnutls_ext_la_SOURCES += alpn.c alpn.h
--- /dev/null
+/*
+ * Copyright (C) 2018 Red Hat, Inc.
+ *
+ * Author: Daiki Ueno
+ *
+ * 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/>
+ *
+ */
+
+/* This file contains the code for the Early Data TLS 1.3 extension.
+ */
+
+#include "gnutls_int.h"
+#include "errors.h"
+#include "num.h"
+#include "hello_ext_lib.h"
+#include <ext/early_data.h>
+
+static int early_data_recv_params(gnutls_session_t session,
+ const uint8_t * data,
+ size_t data_size);
+static int early_data_send_params(gnutls_session_t session,
+ gnutls_buffer_st * extdata);
+
+const hello_ext_entry_st ext_mod_early_data = {
+ .name = "Early Data",
+ .tls_id = 42,
+ .gid = GNUTLS_EXTENSION_EARLY_DATA,
+ .validity = GNUTLS_EXT_FLAG_TLS | GNUTLS_EXT_FLAG_CLIENT_HELLO,
+ .parse_type = GNUTLS_EXT_MANDATORY, /* force parsing prior to EXT_TLS extensions */
+ .recv_func = early_data_recv_params,
+ .send_func = early_data_send_params,
+ .pack_func = NULL,
+ .unpack_func = NULL,
+ .deinit_func = _gnutls_hello_ext_default_deinit,
+ .cannot_be_overriden = 0
+};
+
+static int
+early_data_recv_params(gnutls_session_t session,
+ const uint8_t * data, size_t _data_size)
+{
+ const version_entry_st *vers = get_version(session);
+ if (!vers || !vers->tls13_sem)
+ return gnutls_assert_val(0);
+ if (session->security_parameters.entity == GNUTLS_SERVER)
+ session->internals.hsk_flags |= HSK_EARLY_DATA_IN_FLIGHT;
+
+ return 0;
+}
+
+/* returns data_size or a negative number on failure
+ */
+static int
+early_data_send_params(gnutls_session_t session,
+ gnutls_buffer_st * extdata)
+{
+ return 0;
+}
+
+/**
+ * gnutls_record_set_max_early_data_size:
+ * @session: is a #gnutls_session_t type.
+ * @size: is the new size
+ *
+ * This function sets the maximum early data size in this connection.
+ * This property can only be set to servers. The client may be
+ * provided with the maximum allowed size through the "early_data"
+ * extension of the NewSessionTicket handshake message.
+ *
+ * Returns: On success, %GNUTLS_E_SUCCESS (0) is returned,
+ * otherwise a negative error code is returned.
+ *
+ * Since: 3.6.4
+ **/
+int
+gnutls_record_set_max_early_data_size(gnutls_session_t session,
+ size_t size)
+{
+ if (session->security_parameters.entity == GNUTLS_CLIENT)
+ return GNUTLS_E_INVALID_REQUEST;
+
+ if (size > UINT32_MAX)
+ return GNUTLS_E_INVALID_REQUEST;
+
+ session->security_parameters.max_early_data_size = (uint32_t) size;
+
+ return 0;
+}
--- /dev/null
+/*
+ * Copyright (C) 2018 Red Hat, Inc.
+ *
+ * Author: Daiki Ueno
+ *
+ * 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/>
+ *
+ */
+
+#ifndef EXT_EARLY_DATA_H
+#define EXT_EARLY_DATA_H
+
+#include <hello_ext.h>
+
+extern const hello_ext_entry_st ext_mod_early_data;
+
+#endif
#define IS_DTLS(session) (session->internals.transport == GNUTLS_DGRAM)
#define DEFAULT_MAX_RECORD_SIZE 16384
+#define DEFAULT_MAX_EARLY_DATA_SIZE 16384
#define TLS_RECORD_HEADER_SIZE 5
#define DTLS_RECORD_HEADER_SIZE (TLS_RECORD_HEADER_SIZE+8)
#define RECORD_HEADER_SIZE(session) (IS_DTLS(session) ? DTLS_RECORD_HEADER_SIZE : TLS_RECORD_HEADER_SIZE)
GNUTLS_EXTENSION_SAFE_RENEGOTIATION,
GNUTLS_EXTENSION_SERVER_NAME,
GNUTLS_EXTENSION_COOKIE,
+ GNUTLS_EXTENSION_EARLY_DATA,
GNUTLS_EXTENSION_PSK_KE_MODES,
/*
* pre_shared_key and dumbfw must always be the last extensions,
*/
uint16_t max_record_send_size;
uint16_t max_record_recv_size;
+
+ /* The maximum amount of early data */
+ uint32_t max_early_data_size;
+
/* holds the negotiated certificate type */
gnutls_certificate_type_t cert_type;
*/
#define HSK_TICKET_RECEIVED (1<<20) /* client: a session ticket was received */
#define HSK_EARLY_START_USED (1<<21)
+#define HSK_EARLY_DATA_IN_FLIGHT (1<<22) /* server: early_data extension was seen in ClientHello */
/* The hsk_flags are for use within the ongoing handshake;
* they are reset to zero prior to handshake start by gnutls_handshake. */
tls13_ticket_t tls13_ticket;
+ /* the amount of early data received so far */
+ uint32_t early_data_received;
+
/* If you add anything here, check _gnutls_handshake_internal_state_clear().
*/
} internals_st;
#include <ext/psk_ke_modes.h>
#include <ext/etm.h>
#include <ext/cookie.h>
+#include <ext/early_data.h>
#include "extv.h"
#include <num.h>
[GNUTLS_EXTENSION_SIGNATURE_ALGORITHMS] = &ext_mod_sig,
[GNUTLS_EXTENSION_KEY_SHARE] = &ext_mod_key_share,
[GNUTLS_EXTENSION_COOKIE] = &ext_mod_cookie,
+ [GNUTLS_EXTENSION_EARLY_DATA] = &ext_mod_early_data,
#ifdef ENABLE_DTLS_SRTP
[GNUTLS_EXTENSION_SRTP] = &ext_mod_srtp,
#endif
size_t gnutls_record_check_pending(gnutls_session_t session);
size_t gnutls_record_check_corked(gnutls_session_t session);
+int gnutls_record_set_max_early_data_size(gnutls_session_t session, size_t size);
+
void gnutls_session_force_valid(gnutls_session_t session);
int gnutls_prf(gnutls_session_t session,
gnutls_priority_init2;
} GNUTLS_3_6_2;
+GNUTLS_3_6_4
+{
+ global:
+ gnutls_record_set_max_early_data_size;
+} GNUTLS_3_6_3;
+
GNUTLS_FIPS140_3_4 {
global:
gnutls_cipher_self_test;
_mbuffer_head_remove_bytes(&session->internals.record_recv_buffer,
record.header_size + record.length);
+
+ /* FIXME: as 0-RTT is not implemented yet, when early data is
+ * indicated, skip decryption failure up to
+ * max_early_data_size. Otherwise, if the record is properly
+ * decrypted, treat it as the start of client's second flight.
+ *
+ * This implements the first way suggested in 4.2.10 of
+ * draft-ietf-tls-tls13-28.
+ */
+ if (unlikely(session->internals.hsk_flags & HSK_EARLY_DATA_IN_FLIGHT)) {
+ if (record.type == GNUTLS_APPLICATION_DATA &&
+ (ret < 0 ||
+ /* early data must always be encrypted, treat it
+ * as decryption failure if otherwise */
+ record_params->cipher->id == GNUTLS_CIPHER_NULL)) {
+ if (record.length >
+ session->security_parameters.max_early_data_size -
+ session->internals.early_data_received) {
+ _gnutls_record_log
+ ("REC[%p]: max_early_data_size exceeded\n",
+ session);
+ ret = GNUTLS_E_UNEXPECTED_PACKET;
+ goto sanity_check_error;
+ }
+
+ _gnutls_record_log("REC[%p]: Discarded early data[%u] due to invalid decryption, length: %u\n",
+ session,
+ (unsigned int)
+ _gnutls_uint64touint32(packet_sequence),
+ (unsigned int)
+ record.length);
+ session->internals.early_data_received += record.length;
+ goto discard;
+ } else {
+ session->internals.hsk_flags &= ~HSK_EARLY_DATA_IN_FLIGHT;
+ }
+ }
+
if (ret < 0) {
gnutls_assert();
_gnutls_audit_log(session,
session->internals.tfo.connect_addrlen = 0;
session->internals.tfo.connect_only = 0;
+ session->internals.early_data_received = 0;
}
/**
(*session)->security_parameters.max_record_send_size =
DEFAULT_MAX_RECORD_SIZE;
+ /* set the default early data size for TLS
+ */
+ if ((*session)->security_parameters.entity == GNUTLS_SERVER) {
+ (*session)->security_parameters.max_early_data_size =
+ DEFAULT_MAX_EARLY_DATA_SIZE;
+ }
+
/* everything else not initialized here is initialized
* as NULL or 0. This is why calloc is used.
*/
#include "mbuffers.h"
#include "ext/pre_shared_key.h"
#include "ext/session_ticket.h"
+#include "ext/early_data.h"
#include "auth/cert.h"
#include "tls13/session_ticket.h"
#include "session_pack.h"
static int parse_nst_extension(void *ctx, unsigned tls_id, const unsigned char *data, unsigned data_size)
{
- /* ignore all extensions */
+ gnutls_session_t session = ctx;
+ if (tls_id == ext_mod_early_data.tls_id) {
+ uint32_t size;
+ 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;
+ }
return 0;
}
return gnutls_assert_val(ret);
/* Extensions */
- ret = _gnutls_extv_parse(NULL, parse_nst_extension, buf->data, buf->length);
+ ret = _gnutls_extv_parse(session, parse_nst_extension, buf->data, buf->length);
if (ret < 0)
return gnutls_assert_val(ret);
GNUTLS_3_6_0@GNUTLS_3_6_0
GNUTLS_3_6_2@GNUTLS_3_6_2
GNUTLS_3_6_3@GNUTLS_3_6_3
+GNUTLS_3_6_4@GNUTLS_3_6_4
_gnutls_global_init_skip@GNUTLS_3_4
gnutls_aead_cipher_decrypt@GNUTLS_3_4
gnutls_aead_cipher_deinit@GNUTLS_3_4
gnutls_record_send2@GNUTLS_3_6_3
gnutls_record_send@GNUTLS_3_4
gnutls_record_send_range@GNUTLS_3_4
+gnutls_record_set_max_early_data_size@GNUTLS_3_6_4
gnutls_record_set_max_size@GNUTLS_3_4
gnutls_record_set_state@GNUTLS_3_4
gnutls_record_set_timeout@GNUTLS_3_4