summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--NEWS1
-rw-r--r--doc/Makefile.am2
-rw-r--r--doc/manpages/Makefile.am1
-rw-r--r--lib/ext/Makefile.am3
-rw-r--r--lib/ext/early_data.c102
-rw-r--r--lib/ext/early_data.h30
-rw-r--r--lib/gnutls_int.h10
-rw-r--r--lib/hello_ext.c2
-rw-r--r--lib/includes/gnutls/gnutls.h.in2
-rw-r--r--lib/libgnutls.map6
-rw-r--r--lib/record.c38
-rw-r--r--lib/state.c8
-rw-r--r--lib/tls13/session_ticket.c12
-rw-r--r--symbols.last2
-rw-r--r--tests/suite/tls-fuzzer/gnutls-nocert-tls13.json4
m---------tests/suite/tls-fuzzer/tlsfuzzer0
m---------tests/suite/tls-fuzzer/tlslite-ng0
17 files changed, 219 insertions, 4 deletions
diff --git a/NEWS b/NEWS
index b864a10b9d..1482a60ef5 100644
--- a/NEWS
+++ b/NEWS
@@ -17,6 +17,7 @@ See the end for copying conditions.
** 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)
diff --git a/doc/Makefile.am b/doc/Makefile.am
index de4a7711b4..5d6cd0c1bc 100644
--- a/doc/Makefile.am
+++ b/doc/Makefile.am
@@ -1812,6 +1812,8 @@ FUNCS += functions/gnutls_record_send2
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
diff --git a/doc/manpages/Makefile.am b/doc/manpages/Makefile.am
index 6a802077b0..b4dc4ae8c9 100644
--- a/doc/manpages/Makefile.am
+++ b/doc/manpages/Makefile.am
@@ -701,6 +701,7 @@ APIMANS += gnutls_record_recv_seq.3
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
diff --git a/lib/ext/Makefile.am b/lib/ext/Makefile.am
index 626d9bae96..cbd68c8588 100644
--- a/lib/ext/Makefile.am
+++ b/lib/ext/Makefile.am
@@ -46,7 +46,8 @@ libgnutls_ext_la_SOURCES = max_record.c \
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
diff --git a/lib/ext/early_data.c b/lib/ext/early_data.c
new file mode 100644
index 0000000000..daa0d8fcb7
--- /dev/null
+++ b/lib/ext/early_data.c
@@ -0,0 +1,102 @@
+/*
+ * 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;
+}
diff --git a/lib/ext/early_data.h b/lib/ext/early_data.h
new file mode 100644
index 0000000000..dece833efd
--- /dev/null
+++ b/lib/ext/early_data.h
@@ -0,0 +1,30 @@
+/*
+ * 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
diff --git a/lib/gnutls_int.h b/lib/gnutls_int.h
index c19a909225..fc60f7cc3e 100644
--- a/lib/gnutls_int.h
+++ b/lib/gnutls_int.h
@@ -193,6 +193,7 @@ typedef enum record_send_state_t {
#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)
@@ -338,6 +339,7 @@ typedef enum extensions_t {
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,
@@ -749,6 +751,10 @@ typedef struct {
*/
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;
@@ -1287,6 +1293,7 @@ typedef struct {
*/
#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. */
@@ -1388,6 +1395,9 @@ typedef struct {
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;
diff --git a/lib/hello_ext.c b/lib/hello_ext.c
index f72afe77fd..ac0fc1ba03 100644
--- a/lib/hello_ext.c
+++ b/lib/hello_ext.c
@@ -51,6 +51,7 @@
#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>
@@ -82,6 +83,7 @@ static hello_ext_entry_st const *extfunc[MAX_EXT_TYPES+1] = {
[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
diff --git a/lib/includes/gnutls/gnutls.h.in b/lib/includes/gnutls/gnutls.h.in
index 2252be0224..984febe83b 100644
--- a/lib/includes/gnutls/gnutls.h.in
+++ b/lib/includes/gnutls/gnutls.h.in
@@ -1384,6 +1384,8 @@ ssize_t gnutls_record_set_max_size(gnutls_session_t session, size_t size);
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,
diff --git a/lib/libgnutls.map b/lib/libgnutls.map
index b3208dc875..4a43c07093 100644
--- a/lib/libgnutls.map
+++ b/lib/libgnutls.map
@@ -1237,6 +1237,12 @@ GNUTLS_3_6_3
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;
diff --git a/lib/record.c b/lib/record.c
index 1cc328cb93..4589765524 100644
--- a/lib/record.c
+++ b/lib/record.c
@@ -1334,6 +1334,44 @@ _gnutls_recv_in_buffers(gnutls_session_t session, content_type_t type,
_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,
diff --git a/lib/state.c b/lib/state.c
index 8469339c7a..ab0021a64e 100644
--- a/lib/state.c
+++ b/lib/state.c
@@ -276,6 +276,7 @@ void _gnutls_handshake_internal_state_clear(gnutls_session_t session)
session->internals.tfo.connect_addrlen = 0;
session->internals.tfo.connect_only = 0;
+ session->internals.early_data_received = 0;
}
/**
@@ -354,6 +355,13 @@ int gnutls_init(gnutls_session_t * session, unsigned int flags)
(*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.
*/
diff --git a/lib/tls13/session_ticket.c b/lib/tls13/session_ticket.c
index 184c0ac271..8087ba7a8b 100644
--- a/lib/tls13/session_ticket.c
+++ b/lib/tls13/session_ticket.c
@@ -27,6 +27,7 @@
#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"
@@ -329,7 +330,14 @@ cleanup:
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;
}
@@ -382,7 +390,7 @@ int _gnutls13_recv_session_ticket(gnutls_session_t session, gnutls_buffer_st *bu
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);
diff --git a/symbols.last b/symbols.last
index cf609caf43..66b2400794 100644
--- a/symbols.last
+++ b/symbols.last
@@ -2,6 +2,7 @@ GNUTLS_3_4@GNUTLS_3_4
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
@@ -680,6 +681,7 @@ gnutls_record_recv_seq@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
diff --git a/tests/suite/tls-fuzzer/gnutls-nocert-tls13.json b/tests/suite/tls-fuzzer/gnutls-nocert-tls13.json
index a31eec4858..db351652bb 100644
--- a/tests/suite/tls-fuzzer/gnutls-nocert-tls13.json
+++ b/tests/suite/tls-fuzzer/gnutls-nocert-tls13.json
@@ -55,7 +55,9 @@
"-e", "padding - cipher TLS_AES_128_GCM_SHA256, pad_byte 0, pad_left 0, pad_right 16777183",
"-e", "padding - cipher TLS_AES_256_GCM_SHA384, pad_byte 0, pad_left 0, pad_right 16777167"]},
{"name" : "test-tls13-count-tickets.py",
- "arguments": ["-p", "@PORT@", "-t", "1"]}
+ "arguments": ["-p", "@PORT@", "-t", "1"]},
+ {"name" : "test-tls13-0rtt-garbage.py",
+ "arguments": ["-p", "@PORT@"]}
]
}
]
diff --git a/tests/suite/tls-fuzzer/tlsfuzzer b/tests/suite/tls-fuzzer/tlsfuzzer
-Subproject 23d66d990f1773af5701fb510a3a0ffa59beac5
+Subproject 4433cc402c3902750c2e25848d28463df9bc666
diff --git a/tests/suite/tls-fuzzer/tlslite-ng b/tests/suite/tls-fuzzer/tlslite-ng
-Subproject 3029e014231ffe34445d29300f0193a4be4b6cc
+Subproject 02852484e5ca9ea5e0c69d525ff45a3a999b386