]> git.ipfire.org Git - thirdparty/gnutls.git/commitdiff
ext/record_size_limit: new extension
authorDaiki Ueno <dueno@redhat.com>
Fri, 10 Aug 2018 12:06:16 +0000 (14:06 +0200)
committerDaiki Ueno <dueno@redhat.com>
Mon, 20 Aug 2018 11:37:26 +0000 (13:37 +0200)
This implements the record_size_limit extension as defined in RFC 8449.

Although it obsoletes the max_record_size extension, for compatibility
reasons GnuTLS still sends it on certain occasions.  For example, when
the new size is representable as the codepoint defined for
max_record_size.

Signed-off-by: Daiki Ueno <dueno@redhat.com>
NEWS
lib/ext/Makefile.am
lib/ext/max_record.c
lib/ext/record_size_limit.c [new file with mode: 0644]
lib/ext/record_size_limit.h [new file with mode: 0644]
lib/gnutls_int.h
lib/hello_ext.c
lib/record.c
tests/Makefile.am
tests/tls-record-size-limit.c [new file with mode: 0644]
tests/tls13/prf.c

diff --git a/NEWS b/NEWS
index e6e4ffb6bb9ac6a8611b43ff5541bebcef897e28..7b9a53d00ab0f1b2f2aae4b85209b6c25876f7f1 100644 (file)
--- a/NEWS
+++ b/NEWS
@@ -15,6 +15,9 @@ See the end for copying conditions.
    certificate is presented by client and the gnutls_init() flag GNUTLS_ENABLE_EARLY_START
    is specified.
 
+** libgnutls: The 'record size limit' extension is added and preferred to the
+   'max record size' extension when possible.
+
 ** API and ABI modifications:
 GNUTLS_ENABLE_EARLY_START: Added
 gnutls_record_set_max_early_data_size: Added
index cbd68c85882eff27daad0e7c302e96fd9495debd..b7f204f1d96cf1121a4dd4dea43bea6bd0416886 100644 (file)
@@ -47,7 +47,8 @@ libgnutls_ext_la_SOURCES = max_record.c \
        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 \
-       early_data.c early_data.h
+       early_data.c early_data.h \
+       record_size_limit.c record_size_limit.h
 
 if ENABLE_ALPN
 libgnutls_ext_la_SOURCES += alpn.c alpn.h
index 8edf5a2183ee633a2ea4afeead5ea8bf04b1f8ad..2a7a9d349629289f30cfe80ed457d34691ab9024 100644 (file)
@@ -70,6 +70,9 @@ _gnutls_max_record_recv_params(gnutls_session_t session,
        ssize_t new_size;
        ssize_t data_size = _data_size;
 
+       if (session->internals.hsk_flags & HSK_RECORD_SIZE_LIMIT_NEGOTIATED)
+               return 0;
+
        if (session->security_parameters.entity == GNUTLS_SERVER) {
                if (data_size > 0) {
                        DECR_LEN(data_size, 1);
@@ -96,8 +99,12 @@ _gnutls_max_record_recv_params(gnutls_session_t session,
 
                        new_size = _gnutls_mre_num2record(data[0]);
 
-                       if (new_size < 0 ||
-                           new_size != session->security_parameters.
+                       if (new_size < 0) {
+                               gnutls_assert();
+                               return new_size;
+                       }
+
+                       if (new_size != session->security_parameters.
                            max_record_send_size) {
                                gnutls_assert();
                                return GNUTLS_E_RECEIVED_ILLEGAL_PARAMETER;
@@ -127,11 +134,16 @@ _gnutls_max_record_send_params(gnutls_session_t session,
        if (session->security_parameters.entity == GNUTLS_CLIENT) {
                if (session->security_parameters.max_record_send_size !=
                    DEFAULT_MAX_RECORD_SIZE) {
-                       p = (uint8_t)
-                           _gnutls_mre_record2num
-                           (session->security_parameters.
-                            max_record_send_size);
+                       ret = _gnutls_mre_record2num
+                             (session->security_parameters.
+                              max_record_send_size);
+
+                       /* it's not an error, as long as we send the
+                        * record_size_limit extension with that value */
+                       if (ret < 0)
+                               return 0;
 
+                       p = (uint8_t) ret;
                        ret = _gnutls_buffer_append_data(extdata, &p, 1);
                        if (ret < 0)
                                return gnutls_assert_val(ret);
@@ -143,11 +155,16 @@ _gnutls_max_record_send_params(gnutls_session_t session,
 
                if (session->security_parameters.max_record_recv_size !=
                    DEFAULT_MAX_RECORD_SIZE) {
-                       p = (uint8_t)
-                           _gnutls_mre_record2num
-                           (session->security_parameters.
-                            max_record_recv_size);
+                       ret = _gnutls_mre_record2num
+                             (session->security_parameters.
+                              max_record_recv_size);
 
+                       /* it's not an error, as long as we send the
+                        * record_size_limit extension with that value */
+                       if (ret < 0)
+                               return 0;
+
+                       p = (uint8_t) ret;
                        ret = _gnutls_buffer_append_data(extdata, &p, 1);
                        if (ret < 0)
                                return gnutls_assert_val(ret);
@@ -226,30 +243,28 @@ size_t gnutls_record_get_max_size(gnutls_session_t session)
  * connection.  This property can only be set to clients.  The server
  * may choose not to accept the requested size.
  *
- * Acceptable values are 512(=2^9), 1024(=2^10), 2048(=2^11) and
- * 4096(=2^12).  The requested record size does get in effect
- * immediately only while sending data. The receive part will take
- * effect after a successful handshake.
+ * The requested record size does get in effect immediately only while
+ * sending data. The receive part will take effect after a successful
+ * handshake.
  *
- * This function uses a TLS extension called 'max record size'.  Not
- * all TLS implementations use or even understand this extension.
+ * Prior to 3.6.4, this function was implemented using a TLS extension
+ * called 'max record size', which limits the acceptable values to
+ * 512(=2^9), 1024(=2^10), 2048(=2^11) and 4096(=2^12). Since 3.6.4,
+ * it uses another TLS extension called 'record size limit', which
+ * doesn't have the limitation, as long as the value ranges between
+ * 512 and 16384.  Note that not all TLS implementations use or even
+ * understand those extension.
  *
  * Returns: On success, %GNUTLS_E_SUCCESS (0) is returned,
  *   otherwise a negative error code is returned.
  **/
 ssize_t gnutls_record_set_max_size(gnutls_session_t session, size_t size)
 {
-       ssize_t new_size;
-
        if (session->security_parameters.entity == GNUTLS_SERVER)
                return GNUTLS_E_INVALID_REQUEST;
 
-       new_size = _gnutls_mre_record2num(size);
-
-       if (new_size < 0) {
-               gnutls_assert();
-               return new_size;
-       }
+       if (size < MIN_RECORD_SIZE || size > DEFAULT_MAX_RECORD_SIZE)
+               return GNUTLS_E_INVALID_REQUEST;
 
        session->security_parameters.max_record_send_size = size;
 
diff --git a/lib/ext/record_size_limit.c b/lib/ext/record_size_limit.c
new file mode 100644 (file)
index 0000000..bb8d0c4
--- /dev/null
@@ -0,0 +1,98 @@
+/*
+ * 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 Record Size Limit TLS extension.
+ */
+
+#include "gnutls_int.h"
+#include "errors.h"
+#include "num.h"
+#include <hello_ext.h>
+#include <ext/record_size_limit.h>
+
+static int _gnutls_record_size_limit_recv_params(gnutls_session_t session,
+                                                const uint8_t * data,
+                                                size_t data_size);
+static int _gnutls_record_size_limit_send_params(gnutls_session_t session,
+                                                gnutls_buffer_st * extdata);
+
+const hello_ext_entry_st ext_mod_record_size_limit = {
+       .name = "Record Size Limit",
+       .tls_id = 28,
+       .gid = GNUTLS_EXTENSION_RECORD_SIZE_LIMIT,
+       .parse_type = GNUTLS_EXT_TLS,
+       .validity = GNUTLS_EXT_FLAG_TLS | GNUTLS_EXT_FLAG_DTLS | GNUTLS_EXT_FLAG_CLIENT_HELLO |
+                   GNUTLS_EXT_FLAG_EE,
+       .recv_func = _gnutls_record_size_limit_recv_params,
+       .send_func = _gnutls_record_size_limit_send_params
+};
+
+static int
+_gnutls_record_size_limit_recv_params(gnutls_session_t session,
+                                     const uint8_t * data, size_t _data_size)
+{
+       ssize_t new_size;
+       ssize_t data_size = _data_size;
+
+       DECR_LEN(data_size, 2);
+       new_size = _gnutls_read_uint16(data);
+
+       /* protocol error */
+       if (new_size < 64)
+               return gnutls_assert_val(GNUTLS_E_RECEIVED_ILLEGAL_PARAMETER);
+
+       /* we do not want to accept sizes less than our minimum */
+       if (new_size < MIN_RECORD_SIZE)
+               return 0;
+
+       session->internals.hsk_flags |= HSK_RECORD_SIZE_LIMIT_NEGOTIATED;
+
+       /* if a larger record size limit than the protocol limit is
+        * provided by the peer, ignore it and stick to the default */
+       if (unlikely(new_size > DEFAULT_MAX_RECORD_SIZE))
+               return gnutls_assert_val(0);
+
+       session->security_parameters.max_record_send_size = new_size;
+       session->security_parameters.max_record_recv_size = new_size;
+
+       return 0;
+}
+
+/* returns data_size or a negative number on failure
+ */
+static int
+_gnutls_record_size_limit_send_params(gnutls_session_t session,
+                                     gnutls_buffer_st * extdata)
+{
+       int ret;
+
+       assert(session->security_parameters.max_record_send_size >= 64 &&
+              session->security_parameters.max_record_send_size <=
+              DEFAULT_MAX_RECORD_SIZE);
+
+       ret = _gnutls_buffer_append_prefix(extdata, 16,
+                                          session->security_parameters.max_record_send_size);
+       if (ret < 0)
+               return gnutls_assert_val(ret);
+
+       return 2;
+}
diff --git a/lib/ext/record_size_limit.h b/lib/ext/record_size_limit.h
new file mode 100644 (file)
index 0000000..16e027c
--- /dev/null
@@ -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_RECORD_SIZE_LIMIT_H
+#define EXT_RECORD_SIZE_LIMIT_H
+
+#include <hello_ext.h>
+
+extern const hello_ext_entry_st ext_mod_record_size_limit;
+
+#endif
index f4dc71bb3c32194c8d44649c227ccd954fe9c1e7..dfec39ec33a63d9f824fca6366497bc3967f3045 100644 (file)
@@ -201,6 +201,8 @@ typedef enum record_send_state_t {
 #define RECORD_HEADER_SIZE(session) (IS_DTLS(session) ? DTLS_RECORD_HEADER_SIZE : TLS_RECORD_HEADER_SIZE)
 #define MAX_RECORD_HEADER_SIZE DTLS_RECORD_HEADER_SIZE
 
+#define MIN_RECORD_SIZE 512
+
 /* The following macro is used to calculate the overhead when sending.
  * when receiving we use a different way as there are implementations that
  * store more data than allowed.
@@ -343,6 +345,7 @@ typedef enum extensions_t {
        GNUTLS_EXTENSION_COOKIE,
        GNUTLS_EXTENSION_EARLY_DATA,
        GNUTLS_EXTENSION_PSK_KE_MODES,
+       GNUTLS_EXTENSION_RECORD_SIZE_LIMIT,
        /*
         * pre_shared_key and dumbfw must always be the last extensions,
         * in that order */
@@ -1300,6 +1303,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 */
+#define HSK_RECORD_SIZE_LIMIT_NEGOTIATED (1<<23)
 
        /* The hsk_flags are for use within the ongoing handshake;
         * they are reset to zero prior to handshake start by gnutls_handshake. */
index 6197dd56641d9f6de978e6303fb200e8046ed40e..9e30bd5413d2b53d20d5ff5b6f77808db16a170d 100644 (file)
@@ -52,6 +52,7 @@
 #include <ext/etm.h>
 #include <ext/cookie.h>
 #include <ext/early_data.h>
+#include <ext/record_size_limit.h>
 #include "extv.h"
 #include <num.h>
 
@@ -92,6 +93,9 @@ static hello_ext_entry_st const *extfunc[MAX_EXT_TYPES+1] = {
 #endif
        [GNUTLS_EXTENSION_PSK_KE_MODES] = &ext_psk_ke_modes,
        [GNUTLS_EXTENSION_PRE_SHARED_KEY] = &ext_pre_shared_key,
+       [GNUTLS_EXTENSION_RECORD_SIZE_LIMIT] = &ext_mod_record_size_limit,
+       /* This must be the last extension registered.
+        */
        [GNUTLS_EXTENSION_DUMBFW] = &ext_mod_dumbfw,
 };
 
index f0bf192cb800d930784552197e0305684cc7ca29..745969a7326cc93e93a1a0ea508fbf508680062f 100644 (file)
@@ -46,7 +46,6 @@
 #include "record.h"
 #include "datum.h"
 #include "constate.h"
-#include "ext/max_record.h"
 #include "tls13/key_update.h"
 #include <ext/heartbeat.h>
 #include <state.h>
index 646aa819bd0b30870e37ff4b315e21a74e7beb15..3a42b90bf9a7c733d21755c25746c3768370cdc8 100644 (file)
@@ -202,7 +202,7 @@ ctests += mini-record-2 simple gnutls_hmac_fast set_pkcs12_cred cert certuniquei
         ip-check mini-x509-ipaddr trust-store base64-raw random-art dhex509self \
         dss-sig-val sign-pk-api tls-session-ext-override record-pad \
         tls13-server-kx-neg gnutls_ext_raw_parse_dtls key-export-pkcs8 \
-        null_retrieve_function
+        null_retrieve_function tls-record-size-limit
 
 if HAVE_SECCOMP_TESTS
 ctests += dtls-with-seccomp tls-with-seccomp dtls-client-with-seccomp tls-client-with-seccomp
diff --git a/tests/tls-record-size-limit.c b/tests/tls-record-size-limit.c
new file mode 100644 (file)
index 0000000..7a56c0e
--- /dev/null
@@ -0,0 +1,434 @@
+/*
+ * Copyright (C) 2015 Red Hat, Inc.
+ *
+ * Author: Nikos Mavrogiannopoulos
+ *
+ * This file is part of GnuTLS.
+ *
+ * GnuTLS is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * GnuTLS 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
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with GnuTLS; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <assert.h>
+#include <stdbool.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+#include <gnutls/gnutls.h>
+#include "utils.h"
+
+#define SKIP16(pos, total) { \
+       uint16_t _s; \
+       if (pos+2 > total) fail("error\n"); \
+       _s = (msg->data[pos] << 8) | msg->data[pos+1]; \
+       if ((size_t)(pos+2+_s) > total) fail("error\n"); \
+       pos += 2+_s; \
+       }
+
+#define SKIP8(pos, total) { \
+       uint8_t _s; \
+       if (pos+1 > total) fail("error\n"); \
+       _s = msg->data[pos]; \
+       if ((size_t)(pos+1+_s) > total) fail("error\n"); \
+       pos += 1+_s; \
+       }
+
+#define HANDSHAKE_SESSION_ID_POS 34
+
+static size_t max_record_size;
+
+#define SERVER_PUSH_ADD if (len > max_record_size + 5+32) fail("max record set to %d, len: %d\n", (int)max_record_size, (int)len);
+#include "eagain-common.h"
+
+#include "cert-common.h"
+
+/* This tests whether the max-record extension is respected on TLS.
+ */
+
+const char *side;
+
+static void tls_log_func(int level, const char *str)
+{
+       fprintf(stderr, "%s|<%d>| %s", side, level, str);
+}
+
+struct handshake_cb_data_st {
+       gnutls_session_t session;
+       bool found_max_record_size;
+       bool found_record_size_limit;
+};
+
+static struct handshake_cb_data_st server_handshake_cb_data;
+static struct handshake_cb_data_st client_handshake_cb_data;
+
+static int ext_callback(void *ctx, unsigned tls_id, const unsigned char *data, unsigned size)
+{
+       struct handshake_cb_data_st *cb_data = ctx;
+       if (tls_id == 1) {      /* max record size */
+               cb_data->found_max_record_size = 1;
+       } else if (tls_id == 28) { /* record size limit */
+               cb_data->found_record_size_limit = 1;
+       }
+       return 0;
+}
+
+static int handshake_callback(gnutls_session_t session, unsigned int htype,
+       unsigned post, unsigned int incoming, const gnutls_datum_t *msg)
+{
+       int ret;
+       unsigned pos;
+       gnutls_datum_t mmsg;
+
+       if (!post)
+               return 0;
+
+       switch (htype) {
+       case GNUTLS_HANDSHAKE_CLIENT_HELLO:
+               assert(msg->size >= HANDSHAKE_SESSION_ID_POS);
+               pos = HANDSHAKE_SESSION_ID_POS;
+               SKIP8(pos, msg->size);
+               SKIP16(pos, msg->size);
+               SKIP8(pos, msg->size);
+
+               mmsg.data = &msg->data[pos];
+               mmsg.size = msg->size - pos;
+               ret = gnutls_ext_raw_parse(&server_handshake_cb_data, ext_callback, &mmsg, 0);
+               assert(ret >= 0);
+               break;
+       case GNUTLS_HANDSHAKE_ENCRYPTED_EXTENSIONS:
+               ret = gnutls_ext_raw_parse(&client_handshake_cb_data, ext_callback, msg, 0);
+               assert(ret >= 0);
+               break;
+       default:
+               abort();
+       }
+       return 0;
+}
+
+#define MAX_BUF 16384
+static char buffer[MAX_BUF];
+
+struct test_ext_st {
+       bool max_record_size;
+       bool record_size_limit;
+};
+
+struct test_st {
+       const char *prio;
+       size_t max_size;
+
+       int expect_error;
+       size_t expect_size;
+       struct test_ext_st expect_server_ext;
+       struct test_ext_st expect_client_ext;
+};
+
+static void check_exts(const struct test_ext_st *exp,
+                      struct handshake_cb_data_st *data)
+{
+       if (exp->max_record_size && !data->found_max_record_size)
+               fail("%s: didn't see max_record_size\n", side);
+       if (!exp->max_record_size && data->found_max_record_size)
+               fail("%s: did see max_record_size\n", side);
+
+       if (exp->record_size_limit && !data->found_record_size_limit)
+               fail("%s: didn't see record_size_limit\n", side);
+       if (!exp->record_size_limit && data->found_record_size_limit)
+               fail("%s: did see record_size_limit\n", side);
+}
+
+static void start(const struct test_st *test)
+{
+       int ret;
+       /* Server stuff. */
+       gnutls_certificate_credentials_t serverx509cred;
+       gnutls_session_t server;
+       int sret = GNUTLS_E_AGAIN;
+       /* Client stuff. */
+       gnutls_certificate_credentials_t clientx509cred;
+       gnutls_session_t client;
+       int cret = GNUTLS_E_AGAIN;
+
+       memset(&server_handshake_cb_data, 0, sizeof(server_handshake_cb_data));
+       memset(&client_handshake_cb_data, 0, sizeof(client_handshake_cb_data));
+
+       global_init();
+
+       /* General init. */
+       gnutls_global_set_log_function(tls_log_func);
+       if (debug)
+               gnutls_global_set_log_level(6);
+
+       /* Init server */
+       gnutls_certificate_allocate_credentials(&serverx509cred);
+       gnutls_certificate_set_x509_key_mem(serverx509cred,
+                                           &server2_cert, &server2_key,
+                                           GNUTLS_X509_FMT_PEM);
+
+       gnutls_init(&server, GNUTLS_SERVER);
+       gnutls_credentials_set(server, GNUTLS_CRD_CERTIFICATE,
+                               serverx509cred);
+
+       gnutls_priority_set_direct(server, test->prio, NULL);
+       gnutls_transport_set_push_function(server, server_push);
+       gnutls_transport_set_pull_function(server, server_pull);
+       gnutls_transport_set_pull_timeout_function(server,
+                                                  server_pull_timeout_func);
+       gnutls_transport_set_ptr(server, server);
+
+       server_handshake_cb_data.session = server;
+       gnutls_handshake_set_hook_function(server,
+                                          GNUTLS_HANDSHAKE_CLIENT_HELLO,
+                                          GNUTLS_HOOK_POST,
+                                          handshake_callback);
+
+
+       /* Init client */
+
+       ret = gnutls_certificate_allocate_credentials(&clientx509cred);
+       if (ret < 0)
+               exit(1);
+
+       ret = gnutls_certificate_set_x509_trust_mem(clientx509cred, &ca2_cert, GNUTLS_X509_FMT_PEM);
+       if (ret < 0)
+               exit(1);
+
+       ret = gnutls_init(&client, GNUTLS_CLIENT);
+       if (ret < 0)
+               exit(1);
+
+       ret = gnutls_credentials_set(client, GNUTLS_CRD_CERTIFICATE,
+                               clientx509cred);
+       if (ret < 0)
+               exit(1);
+
+       ret = gnutls_priority_set_direct(client, test->prio, NULL);
+       if (ret < 0)
+               exit(1);
+
+       ret = gnutls_record_set_max_size(client, test->max_size);
+       if (ret != test->expect_error)
+               fail("unexpected error from gnutls_record_set_max_size()");
+       if (ret == 0)
+               max_record_size = test->max_size;
+       else
+               max_record_size = MAX_BUF;
+
+       gnutls_transport_set_push_function(client, client_push);
+       gnutls_transport_set_pull_function(client, client_pull);
+       gnutls_transport_set_pull_timeout_function(client,
+                                                  client_pull_timeout_func);
+       gnutls_transport_set_ptr(client, client);
+
+       client_handshake_cb_data.session = client;
+       gnutls_handshake_set_hook_function(client,
+                                          GNUTLS_HANDSHAKE_ENCRYPTED_EXTENSIONS,
+                                          GNUTLS_HOOK_POST,
+                                          handshake_callback);
+
+       HANDSHAKE(client, server);
+
+       memset(buffer, 1, sizeof(buffer));
+       ret = gnutls_record_send(server, buffer, max_record_size + 1);
+       if (ret < 0) {
+               gnutls_perror(ret);
+               exit(1);
+       }
+       if (ret != (int)test->expect_size)
+               fail("unexpected record size sent: %d (%d)\n",
+                    ret, (int)test->expect_size);
+       success("did not send a %d-byte packet\n", (int)max_record_size + 1);
+
+       ret = gnutls_record_send(server, buffer, max_record_size);
+       if (ret < 0) {
+               gnutls_perror(ret);
+               exit(1);
+       }
+       success("did send a %d-byte packet\n", (int)max_record_size);
+
+       gnutls_bye(client, GNUTLS_SHUT_RDWR);
+       gnutls_bye(server, GNUTLS_SHUT_RDWR);
+
+       gnutls_deinit(client);
+       gnutls_deinit(server);
+
+       gnutls_certificate_free_credentials(serverx509cred);
+       gnutls_certificate_free_credentials(clientx509cred);
+
+       gnutls_global_deinit();
+
+       reset_buffers();
+
+       check_exts(&test->expect_server_ext,
+                  &server_handshake_cb_data);
+       check_exts(&test->expect_client_ext,
+                  &client_handshake_cb_data);
+}
+
+static const struct test_st tests[] = {
+       {
+               .prio = "NORMAL:-VERS-ALL:+VERS-TLS1.2",
+               .max_size = 511,
+               .expect_error = GNUTLS_E_INVALID_REQUEST,
+               .expect_size = 16384,
+               .expect_server_ext = {
+                       .max_record_size = 0,
+                       .record_size_limit = 1
+               },
+               .expect_client_ext = {
+                       .max_record_size = 0,
+                       .record_size_limit = 0
+               }
+       },
+       {
+               .prio = "NORMAL:-VERS-ALL:+VERS-TLS1.2",
+               .max_size = 512,
+               .expect_error = 0,
+               .expect_size = 512,
+               .expect_server_ext = {
+                       .max_record_size = 1,
+                       .record_size_limit = 1
+               },
+               .expect_client_ext = {
+                       .max_record_size = 0,
+                       .record_size_limit = 0
+               }
+       },
+       {
+               .prio = "NORMAL:-VERS-ALL:+VERS-TLS1.2",
+               .max_size = 8192,
+               .expect_error = 0,
+               .expect_size = 8192,
+               .expect_server_ext = {
+                       .max_record_size = 0,
+                       .record_size_limit = 1
+               },
+               .expect_client_ext = {
+                       .max_record_size = 0,
+                       .record_size_limit = 0
+               }
+       },
+       {
+               .prio = "NORMAL:-VERS-ALL:+VERS-TLS1.2",
+               .max_size = 16384,
+               .expect_error = 0,
+               .expect_size = 16384,
+               .expect_server_ext = {
+                       .max_record_size = 0,
+                       .record_size_limit = 1
+               },
+               .expect_client_ext = {
+                       .max_record_size = 0,
+                       .record_size_limit = 0
+               }
+       },
+       {
+               .prio = "NORMAL:-VERS-ALL:+VERS-TLS1.2",
+               .max_size = 16385,
+               .expect_error = GNUTLS_E_INVALID_REQUEST,
+               .expect_size = 16384,
+               .expect_server_ext = {
+                       .max_record_size = 0,
+                       .record_size_limit = 1
+               },
+               .expect_client_ext = {
+                       .max_record_size = 0,
+                       .record_size_limit = 0
+               }
+       },
+
+       {
+               .prio = "NORMAL:-VERS-ALL:+VERS-TLS1.3",
+               .max_size = 511,
+               .expect_error = GNUTLS_E_INVALID_REQUEST,
+               .expect_size = 16384,
+               .expect_server_ext = {
+                       .max_record_size = 0,
+                       .record_size_limit = 1
+               },
+               .expect_client_ext = {
+                       .max_record_size = 0,
+                       .record_size_limit = 1
+               }
+               },
+       {
+               .prio = "NORMAL:-VERS-ALL:+VERS-TLS1.3",
+               .max_size = 512,
+               .expect_error = 0,
+               .expect_size = 512,
+               .expect_server_ext = {
+                       .max_record_size = 1,
+                       .record_size_limit = 1
+               },
+               .expect_client_ext = {
+                       .max_record_size = 0,
+                       .record_size_limit = 1
+               }
+       },
+       {
+               .prio = "NORMAL:-VERS-ALL:+VERS-TLS1.3",
+               .max_size = 8192,
+               .expect_error = 0,
+               .expect_size = 8192,
+               .expect_server_ext = {
+                       .max_record_size = 0,
+                       .record_size_limit = 1
+               },
+               .expect_client_ext = {
+                       .max_record_size = 0,
+                       .record_size_limit = 1
+               }
+       },
+       {
+               .prio = "NORMAL:-VERS-ALL:+VERS-TLS1.3",
+               .max_size = 16384,
+               .expect_error = 0,
+               .expect_size = 16384,
+               .expect_server_ext = {
+                       .max_record_size = 0,
+                       .record_size_limit = 1
+               },
+               .expect_client_ext = {
+                       .max_record_size = 0,
+                       .record_size_limit = 1
+               }
+       },
+       {
+               .prio = "NORMAL:-VERS-ALL:+VERS-TLS1.3",
+               .max_size = 16385,
+               .expect_error = GNUTLS_E_INVALID_REQUEST,
+               .expect_size = 16384,
+               .expect_server_ext = {
+                       .max_record_size = 0,
+                       .record_size_limit = 1
+               },
+               .expect_client_ext = {
+                       .max_record_size = 0,
+                       .record_size_limit = 1
+               }
+       }
+};
+
+void doit(void)
+{
+       size_t i;
+       for (i = 0; i < sizeof(tests)/sizeof(tests[0]); i++)
+               start(&tests[i]);
+}
index 61b96b246b653be50b0fa72288728ab6c172661a..dc34973e8ff0fe7ee85932bb4c5294ebf12215be 100644 (file)
@@ -126,10 +126,10 @@ static void dump(const char *name, const uint8_t *data, unsigned data_size)
        } \
        }
 
-#define KEY_EXP_VALUE "\x2b\x6f\x94\xc8\xbc\xa0\x59\x4b\x61\xc8\x23\x12\x01\x8e\xb2\x3a\xdf\x48\x06\x98\x96\xaf\xf9\xe7\xcf\xd5\xa4\x56\x29\x6b\x84\xd3\xfc\x81"
-#define HELLO_VALUE "\x93\x78\x2d\x00\x88\x02\xd8\xd1\x75\xfe\x1d\xae\x99\x13\xf4\x36\xe0\x10\xc9\xfc\xae\xb8\xc0\x72\xd2\x99\x6e\xc3\x71\xf5\x1b"
-#define CONTEXT_VALUE "\x1e\x95\x2e\xa5\xb9\xff\xe4\xb0\xbe\xa3\x8b\x1f\x6c\x31\x74\x62\x4f\x9d\x0b\xf8\x1d\x5f\x3d\xa5\xa7\x45\x07\x99\xea\xfc\xa2"
-#define NULL_CONTEXT_VALUE "\x2f\x7e\x07\x52\xd4\x23\x0b\x7a\xa0\x7e\x2f\xad\xb5\xcc\xcf\x63\x8f\x6c\x27\x7e\xbb\x9e\xb8\xd3\xa0\x92\x3d\xd0\xaa\xe4\xb0"
+#define KEY_EXP_VALUE "\x42\xba\x1d\x14\x6d\x09\x4f\x64\x7a\x65\xc0\x39\xf8\xd6\x98\xa7\x71\xcd\xb5\xd1\x8d\xf7\x70\xca\x22\x2d\xad\x3f\xac\x47\xe9\x13\xfa\xd0"
+#define HELLO_VALUE "\x0a\xc9\xa4\x5b\xf8\x19\x07\x1c\x56\x61\x7f\xcf\x71\x8b\xff\x0d\xc3\x74\xd7\xf3\x12\xd8\xde\xa8\x33\xcb\x3d\xf3\xc2\x78\x51"
+#define CONTEXT_VALUE "\x7c\x89\xaf\x6f\x98\xbd\xa4\xc4\xad\x10\x54\xc2\x6d\x87\xb3\x94\x02\x62\x2f\x1f\x64\x82\x10\x30\xb6\x49\x08\x2f\x0d\x82\xc1"
+#define NULL_CONTEXT_VALUE "\xa6\xf4\x67\x86\x16\x06\xd0\x53\xcf\x19\xc7\x26\xa4\x94\xc4\x78\xea\xeb\x51\x8e\x04\x0b\x53\xaf\x9f\xde\x0b\xe8\xc3\x08\x04"
 static void check_prfs(gnutls_session_t session)
 {
        unsigned char key_material[512];