summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDaiki Ueno <dueno@redhat.com>2018-10-15 13:35:43 +0200
committerDaiki Ueno <dueno@redhat.com>2018-11-12 14:58:01 +0100
commit4429256c40161b088847f8e058c8a4cfb8d5b5f1 (patch)
treeac5bc4ccd7e76e4722e7ec492d3d180d956122b3
parent16d8812337db0a65b2593f0d7c30cc1a6a79e657 (diff)
downloadgnutls-4429256c40161b088847f8e058c8a4cfb8d5b5f1.tar.gz
doc: mention 0-RTTtmp-0rtt
Signed-off-by: Daiki Ueno <dueno@redhat.com>
-rw-r--r--NEWS11
-rw-r--r--doc/cha-gtls-app.texi142
2 files changed, 153 insertions, 0 deletions
diff --git a/NEWS b/NEWS
index ea9fb34697..3332ce7d16 100644
--- a/NEWS
+++ b/NEWS
@@ -27,6 +27,8 @@ See the end for copying conditions.
** gnutls-serv: It applies the default settings when no --priority option is given,
using gnutls_set_default_priority().
+** libgnutls: Added support for TLS 1.3 zero round-trip (0-RTT) mode (#127)
+
** API and ABI modifications:
GNUTLS_AUTO_REAUTH: Added
GNUTLS_CIPHER_AES_128_CFB8: Added
@@ -34,6 +36,15 @@ GNUTLS_CIPHER_AES_192_CFB8: Added
GNUTLS_CIPHER_AES_256_CFB8: Added
GNUTLS_MAC_AES_CMAC_128: Added
GNUTLS_MAC_AES_CMAC_256: Added
+gnutls_record_get_max_early_data_size: Added
+gnutls_record_send_early_data: Added
+gnutls_record_recv_early_data: Added
+gnutls_db_entry_is_expired: Added
+gnutls_db_set_add_function: Added
+gnutls_anti_replay_init: Added
+gnutls_anti_replay_deinit: Added
+gnutls_anti_replay_set_window: Added
+gnutls_anti_replay_enable: Added
* Version 3.6.4 (released 2018-09-24)
diff --git a/doc/cha-gtls-app.texi b/doc/cha-gtls-app.texi
index 90accd3d31..b7b6d6a87e 100644
--- a/doc/cha-gtls-app.texi
+++ b/doc/cha-gtls-app.texi
@@ -814,6 +814,8 @@ remaining until the next retransmission, or better the time until
@menu
* Asynchronous operation::
* Reducing round-trips::
+* Zero-roundtrip mode::
+* Anti-replay protection::
* DTLS sessions::
* DTLS and SCTP::
@end menu
@@ -916,6 +918,142 @@ It can be enabled by setting the @acronym{GNUTLS_ENABLE_EARLY_START} on
return early, allowing the server to send data earlier.
+@node Zero-roundtrip mode
+@subsection Zero-roundtrip mode
+
+Under TLS 1.3, when the client has already connected to the server and
+is resuming a session, it can start transmitting application data during
+handshake. This is called zero round-trip time (0-RTT) mode, and the
+application data sent in this mode is called early data. The client can
+send early data with @funcref{gnutls_record_send_early_data}. The
+client should call this function before calling
+@funcref{gnutls_handshake} and after calling
+@funcref{gnutls_session_set_data}.
+
+Note, however, that early data has weaker security properties than
+normal application data sent after handshake, such as lack of forward
+secrecy, no guarantees of non-replay between connections. Thus it is
+disabled on the server side by default. To enable it, the server
+needs to:
+@enumerate
+@item Set @acronym{GNUTLS_ENABLE_EARLY_DATA} on @funcref{gnutls_init}. Note that this option only has effect on server.
+
+@item Enable anti-replay measure. See @ref{Anti-replay protection} for the details.
+@end enumerate
+
+The server caches the received early data until it is read. To set the
+maximum amount of data to be stored in the cache, use
+@funcref{gnutls_record_set_max_early_data_size}. After receiving the
+EndOfEarlyData handshake message, the server can start retrieving the
+received data with @funcref{gnutls_record_recv_early_data}. You can
+call the function either after the handshake is complete, or through a
+handshake hook (@funcref{gnutls_handshake_set_hook_function}).
+
+On the client side, to check whether the sent early data was accepted by
+the server, use @funcref{gnutls_session_get_flags} and compare the
+result with @acronym{GNUTLS_SFLAGS_EARLY_DATA}. Similarly, on the
+server side, the same function and flag can be used to check whether it
+has actually accepted early data.
+
+
+@node Anti-replay protection
+@subsection Anti-replay protection
+
+When 0-RTT mode is used, the server must protect itself from replay
+attacks, where adversary client reuses duplicate session ticket to send
+early data, before the server authenticates the client.
+
+GnuTLS provides a simple mechanism against replay attacks, following the
+method called ClientHello recording. When a session ticket is accepted,
+the server checks if the ClientHello message has been already seen. If
+there is a duplicate, the server rejects early data.
+
+The problem of this approach is that the number of recorded messages
+grows indefinitely. To prevent that, the server can limit the recording
+to a certain time window, which can be configured with
+@funcref{gnutls_anti_replay_set_window}.
+
+The anti-replay mechanism shall be globally initialized with
+@funcref{gnutls_anti_replay_init}, and then attached to a session using
+@funcref{gnutls_anti_replay_enable}. It can be deinitialized with
+@funcref{gnutls_anti_replay_deinit}.
+
+The server must also set up a database back-end to store ClientHello
+messages. That can be achieved using
+@funcref{gnutls_db_set_add_function} (see @ref{Session resumption}).
+
+Note that, if the back-end stores arbitrary number of ClientHello, it
+needs to periodically clean up the stored entries based on the time
+window set with @funcref{gnutls_anti_replay_set_window}. The cleanup
+can be implemented by iterating through the database entries and calling
+@funcref{gnutls_db_check_entry_expire_time}. This is similar to session
+database cleanup used by TLS1.2 sessions.
+
+The full set up of the server using early data would be like the
+following example:
+@example
+#define MAX_EARLY_DATA_SIZE 16384
+
+static int
+db_add_func(void *dbf, gnutls_datum_t key, gnutls_datum_t data)
+@{
+ /* Return GNUTLS_E_DB_ENTRY_EXISTS, if KEY is found in the database.
+ * Otherwise, store it and return 0.
+ */
+@}
+
+static int
+handshake_hook_func(gnutls_session_t session, unsigned int htype,
+ unsigned when, unsigned int incoming, const gnutls_datum_t *msg)
+@{
+ int ret;
+ char buf[MAX_EARLY_DATA_SIZE];
+
+ assert(htype == GNUTLS_HANDSHAKE_END_OF_EARLY_DATA);
+ assert(when == GNUTLS_HOOK_POST);
+
+ if (gnutls_session_get_flags(session) & GNUTLS_SFLAGS_EARLY_DATA) @{
+ ret = gnutls_record_recv_early_data(session, buf, sizeof(buf));
+ assert(ret >= 0);
+ @}
+
+ return ret;
+@}
+
+int main()
+@{
+ ...
+ /* Initialize anti-replay measure, which can be shared
+ * among multiple sessions.
+ */
+ gnutls_anti_replay_init(&anti_replay);
+
+ ...
+
+ gnutls_init(&server, GNUTLS_SERVER | GNUTLS_ENABLE_EARLY_DATA);
+ gnutls_record_set_max_early_data_size(server, MAX_EARLY_DATA_SIZE);
+ ...
+
+ /* Set the database back-end function for the session.
+ */
+ gnutls_db_set_add_function(server, db_add_func);
+ ...
+
+ /* Set the anti-replay measure to the session.
+ */
+ gnutls_anti_replay_enable(server, anti_replay);
+ ...
+
+ /* Retrieve early data in a handshake hook;
+ * you can also do that after handshake.
+ */
+ gnutls_handshake_set_hook_function(server, GNUTLS_HANDSHAKE_END_OF_EARLY_DATA,
+ GNUTLS_HOOK_POST, handshake_hook_func);
+ ...
+@}
+@end example
+
+
@node DTLS sessions
@subsection DTLS sessions
@@ -1637,6 +1775,8 @@ static int
handshake_hook_func(gnutls_session_t session, unsigned int htype,
unsigned when, unsigned int incoming, const gnutls_datum_t *msg)
@{
+ int ret;
+
assert(htype == GNUTLS_HANDSHAKE_CLIENT_HELLO);
assert(when == GNUTLS_HOOK_PRE);
@@ -1645,6 +1785,8 @@ handshake_hook_func(gnutls_session_t session, unsigned int htype,
assert(ret >= 0);
gnutls_credentials_set(session, GNUTLS_CRD_CERTIFICATE, cred);
+
+ return ret;
@}
int main()