diff options
author | Nikos Mavrogiannopoulos <nmav@gnutls.org> | 2018-11-19 11:44:58 +0000 |
---|---|---|
committer | Nikos Mavrogiannopoulos <nmav@gnutls.org> | 2018-11-19 11:44:58 +0000 |
commit | 639d1df7e4e249559b4a20b9eaad57a93b2ecdce (patch) | |
tree | 7eb7d64006e7c0a540fedffb5afdce0c65d6f7b0 | |
parent | 5ad1afa2c65c1ce9d0946dbb835edf93ec6d0ead (diff) | |
parent | 01202d84f45c62cf1e0499fbe012ffa5f02b9e17 (diff) | |
download | gnutls-639d1df7e4e249559b4a20b9eaad57a93b2ecdce.tar.gz |
Merge branch 'tmp-fix-max-early-data-size' into 'master'
Fix max_early_data_size handling
See merge request gnutls/gnutls!811
-rw-r--r-- | lib/record.c | 11 | ||||
-rw-r--r-- | lib/state.c | 3 | ||||
-rw-r--r-- | lib/tls13/session_ticket.c | 6 | ||||
-rw-r--r-- | src/serv-args.def | 8 | ||||
-rw-r--r-- | src/serv.c | 10 | ||||
-rwxr-xr-x | tests/suite/testcompat-tls13-openssl.sh | 18 | ||||
-rw-r--r-- | tests/tls13-early-data.c | 34 |
7 files changed, 77 insertions, 13 deletions
diff --git a/lib/record.c b/lib/record.c index 5514ddcef1..19f5b52282 100644 --- a/lib/record.c +++ b/lib/record.c @@ -52,6 +52,7 @@ #include <dtls.h> #include <dh.h> #include <random.h> +#include <xsize.h> struct tls_record_st { uint16_t header_size; @@ -2041,7 +2042,9 @@ gnutls_record_send2(gnutls_session_t session, const void *data, * as gnutls_record_send(). * * There may be a limit to the amount of data sent as early data. Use - * gnutls_record_get_max_early_data_size() to check the limit. + * gnutls_record_get_max_early_data_size() to check the limit. If the + * limit exceeds, this function returns + * %GNUTLS_E_RECORD_LIMIT_REACHED. * * Returns: The number of bytes sent, or a negative error code. The * number of bytes sent might be less than @data_size. The maximum @@ -2059,6 +2062,12 @@ ssize_t gnutls_record_send_early_data(gnutls_session_t session, if (session->security_parameters.entity != GNUTLS_CLIENT) return gnutls_assert_val(GNUTLS_E_INVALID_REQUEST); + if (xsum(session->internals. + early_data_presend_buffer.length, + data_size) > + session->security_parameters.max_early_data_size) + return gnutls_assert_val(GNUTLS_E_RECORD_LIMIT_REACHED); + ret = _gnutls_buffer_append_data(&session->internals. early_data_presend_buffer, data, diff --git a/lib/state.c b/lib/state.c index 5364d5e727..7e6354f9fe 100644 --- a/lib/state.c +++ b/lib/state.c @@ -518,6 +518,9 @@ int gnutls_init(gnutls_session_t * session, unsigned int flags) if ((*session)->security_parameters.entity == GNUTLS_SERVER) { (*session)->security_parameters.max_early_data_size = DEFAULT_MAX_EARLY_DATA_SIZE; + } else { + (*session)->security_parameters.max_early_data_size = + UINT32_MAX; } /* everything else not initialized here is initialized diff --git a/lib/tls13/session_ticket.c b/lib/tls13/session_ticket.c index 7ea2b00f82..f254a73036 100644 --- a/lib/tls13/session_ticket.c +++ b/lib/tls13/session_ticket.c @@ -388,12 +388,10 @@ static int parse_nst_extension(void *ctx, unsigned tls_id, const unsigned char * { 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); - if (size < session->security_parameters.max_early_data_size) - session->security_parameters.max_early_data_size = size; + session->security_parameters.max_early_data_size = + _gnutls_read_uint32(data); } return 0; } diff --git a/src/serv-args.def b/src/serv-args.def index 6c17998da0..7c4c32479c 100644 --- a/src/serv-args.def +++ b/src/serv-args.def @@ -49,6 +49,14 @@ flag = { }; flag = { + name = maxearlydata; + arg-type = number; + arg-range = "1->4294967296"; + descrip = "The maximum early data size to accept"; + doc = ""; +}; + +flag = { name = nocookie; descrip = "Don't require cookie on DTLS sessions"; doc = ""; diff --git a/src/serv.c b/src/serv.c index d0b5914bc0..2ceb3dbf1f 100644 --- a/src/serv.c +++ b/src/serv.c @@ -408,8 +408,16 @@ gnutls_session_t initialize_session(int dtls) gnutls_session_ticket_enable_server(session, &session_ticket_key); - if (earlydata) + if (earlydata) { gnutls_anti_replay_enable(session, anti_replay); + if (HAVE_OPT(MAXEARLYDATA)) { + ret = gnutls_record_set_max_early_data_size(session, OPT_VALUE_MAXEARLYDATA); + if (ret < 0) { + fprintf(stderr, "Could not set max early data size: %s\n", gnutls_strerror(ret)); + exit(1); + } + } + } if (sni_hostname != NULL) gnutls_handshake_set_post_client_hello_function(session, diff --git a/tests/suite/testcompat-tls13-openssl.sh b/tests/suite/testcompat-tls13-openssl.sh index c573182870..27ca3826e3 100755 --- a/tests/suite/testcompat-tls13-openssl.sh +++ b/tests/suite/testcompat-tls13-openssl.sh @@ -530,6 +530,24 @@ _EOF_ kill ${PID} wait + + echo_cmd "${PREFIX}Checking TLS 1.3 with resumption and early data with small limit..." + testdir=`create_testdir tls13-openssl-resumption` + eval "${GETPORT}" + launch_server $$ --priority "NORMAL:-VERS-ALL:+VERS-TLS1.3${ADD}" --x509certfile "${RSA_CERT}" --x509keyfile "${RSA_KEY}" --x509cafile "${CA_CERT}" --earlydata --maxearlydata 1 >>${OUTPUT} 2>&1 + PID=$! + wait_server ${PID} + + echo "This file contains early data sent by the client" > "${testdir}/earlydata.txt" + { echo a; sleep 1; } | \ + ${OPENSSL_CLI} s_client -host localhost -port "${PORT}" -CAfile "${CA_CERT}" -sess_out "${testdir}/sess-earlydata.pem" 2>&1 | grep "\:error\:" && \ + fail ${PID} "Failed" + ${OPENSSL_CLI} s_client -host localhost -port "${PORT}" -CAfile "${CA_CERT}" -sess_in "${testdir}/sess-earlydata.pem" -early_data "${testdir}/earlydata.txt" </dev/null 2>&1 > "${testdir}/server.out" + grep "^Early data was rejected" "${testdir}/server.out" || \ + fail ${PID} "Failed" + + kill ${PID} + wait rm -rf "${testdir}" } diff --git a/tests/tls13-early-data.c b/tests/tls13-early-data.c index c922ae0ba6..e98f394dac 100644 --- a/tests/tls13-early-data.c +++ b/tests/tls13-early-data.c @@ -51,6 +51,7 @@ int main(void) #include "cert-common.h" #include "utils.h" #include "virt-time.h" +#define MIN(x,y) (((x)<(y))?(x):(y)) /* This program tests the robustness of record sending with padding. */ @@ -94,7 +95,7 @@ gnutls_rnd(gnutls_rnd_level_t level, void *data, size_t len) return 0; } -static void client(int sds[]) +static void client(int sds[], const char *data, size_t size, size_t maxsize) { int ret; char buffer[MAX_BUF + 1]; @@ -127,7 +128,12 @@ static void client(int sds[]) if (t > 0) { assert(gnutls_session_set_data(session, session_data.data, session_data.size) >= 0); - assert(gnutls_record_send_early_data(session, EARLY_MSG, sizeof(EARLY_MSG)) >= 0); + /* The server should have advertised the same maximum. */ + if (gnutls_record_get_max_early_data_size(session) != maxsize) + fail("client: max_early_data_size mismatch %d != %d\n", + (int) gnutls_record_get_max_early_data_size(session), + (int) maxsize); + assert(gnutls_record_send_early_data(session, data, MIN(size, maxsize)) >= 0); assert(gnutls_handshake_set_random(session, &hrnd) >= 0); } @@ -242,7 +248,7 @@ storage_clear(struct storage_st *storage) storage->num_entries = 0; } -static void server(int sds[]) +static void server(int sds[], const char *data, size_t size, size_t maxsize) { int ret; char buffer[MAX_BUF + 1]; @@ -292,6 +298,12 @@ static void server(int sds[]) gnutls_anti_replay_enable(session, anti_replay); + /* on the replay connection, early data is skipped + * until max_early_data_size without decryption + */ + if (t < 2) + (void) gnutls_record_set_max_early_data_size(session, maxsize); + gnutls_transport_set_int(session, sd); do { @@ -330,7 +342,8 @@ static void server(int sds[]) gnutls_strerror(ret)); } - if (ret != sizeof(EARLY_MSG) || memcmp(buffer, EARLY_MSG, ret)) + if ((size_t) ret != MIN(size, maxsize) || + memcmp(buffer, data, ret)) fail("server: early data mismatch\n"); } else { if (gnutls_rnd_works) { @@ -387,7 +400,8 @@ static void server(int sds[]) success("server: finished\n"); } -void doit(void) +static void +start(const char *data, size_t size, size_t maxsize) { int client_sds[SESSIONS], server_sds[SESSIONS]; int i; @@ -420,14 +434,20 @@ void doit(void) /* parent */ for (i = 0; i < SESSIONS; i++) close(client_sds[i]); - server(server_sds); + server(server_sds, data, size, maxsize); kill(child, SIGTERM); } else { for (i = 0; i < SESSIONS; i++) close(server_sds[i]); - client(client_sds); + client(client_sds, data, size, maxsize); exit(0); } } +void doit(void) +{ + start(EARLY_MSG, sizeof(EARLY_MSG), MAX_BUF); + start(EARLY_MSG, sizeof(EARLY_MSG), 10); +} + #endif /* _WIN32 */ |