diff options
author | Nikos Mavrogiannopoulos <nmav@gnutls.org> | 2018-11-16 08:02:27 +0000 |
---|---|---|
committer | Nikos Mavrogiannopoulos <nmav@gnutls.org> | 2018-11-16 08:02:27 +0000 |
commit | 7e488b042f408c6f934c6b198d7c5d3a27e3bdb6 (patch) | |
tree | 4bbd5bf7f508fff7c2fbdee573476933e22a2080 | |
parent | 9e58b6b67cebcc4fb0d1b7550d0663947fedf09f (diff) | |
parent | a23bc3113169655b2f32e357d7a9b8f2b42ea105 (diff) | |
download | gnutls-7e488b042f408c6f934c6b198d7c5d3a27e3bdb6.tar.gz |
Merge branch 'tmp-anti-replay-updates' into 'master'
updates in anti-replay subsystem
Closes #610
See merge request gnutls/gnutls!805
-rw-r--r-- | NEWS | 4 | ||||
-rw-r--r-- | doc/Makefile.am | 6 | ||||
-rw-r--r-- | doc/cha-gtls-app.texi | 13 | ||||
-rw-r--r-- | doc/manpages/Makefile.am | 3 | ||||
-rw-r--r-- | lib/db.c | 23 | ||||
-rw-r--r-- | lib/ext/pre_shared_key.c | 2 | ||||
-rw-r--r-- | lib/gnutls_int.h | 1 | ||||
-rw-r--r-- | lib/includes/gnutls/gnutls.h.in | 13 | ||||
-rw-r--r-- | lib/libgnutls.map | 3 | ||||
-rw-r--r-- | lib/tls13/anti_replay.c | 59 | ||||
-rw-r--r-- | lib/tls13/anti_replay.h | 2 | ||||
-rw-r--r-- | src/serv.c | 17 | ||||
-rw-r--r-- | symbols.last | 3 | ||||
-rw-r--r-- | tests/Makefile.am | 2 | ||||
-rw-r--r-- | tests/tls13-early-data-neg.c | 479 | ||||
-rw-r--r-- | tests/tls13-early-data.c | 17 | ||||
-rw-r--r-- | tests/tls13/anti_replay.c | 32 |
17 files changed, 596 insertions, 83 deletions
@@ -39,8 +39,8 @@ 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_db_check_entry_expire_time: Added +gnutls_anti_replay_set_add_function: Added gnutls_anti_replay_init: Added gnutls_anti_replay_deinit: Added gnutls_anti_replay_set_window: Added diff --git a/doc/Makefile.am b/doc/Makefile.am index 6d6865fce9..e6d5e14c6e 100644 --- a/doc/Makefile.am +++ b/doc/Makefile.am @@ -679,6 +679,10 @@ FUNCS += functions/gnutls_anti_replay_enable FUNCS += functions/gnutls_anti_replay_enable.short FUNCS += functions/gnutls_anti_replay_init FUNCS += functions/gnutls_anti_replay_init.short +FUNCS += functions/gnutls_anti_replay_set_add_function +FUNCS += functions/gnutls_anti_replay_set_add_function.short +FUNCS += functions/gnutls_anti_replay_set_ptr +FUNCS += functions/gnutls_anti_replay_set_ptr.short FUNCS += functions/gnutls_anti_replay_set_window FUNCS += functions/gnutls_anti_replay_set_window.short FUNCS += functions/gnutls_auth_client_get_type @@ -895,8 +899,6 @@ FUNCS += functions/gnutls_db_get_ptr FUNCS += functions/gnutls_db_get_ptr.short FUNCS += functions/gnutls_db_remove_session FUNCS += functions/gnutls_db_remove_session.short -FUNCS += functions/gnutls_db_set_add_function -FUNCS += functions/gnutls_db_set_add_function.short FUNCS += functions/gnutls_db_set_cache_expiration FUNCS += functions/gnutls_db_set_cache_expiration.short FUNCS += functions/gnutls_db_set_ptr diff --git a/doc/cha-gtls-app.texi b/doc/cha-gtls-app.texi index b7b6d6a87e..da21995cb7 100644 --- a/doc/cha-gtls-app.texi +++ b/doc/cha-gtls-app.texi @@ -980,7 +980,8 @@ The anti-replay mechanism shall be globally initialized with 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}). +@funcref{gnutls_anti_replay_set_add_function} and +@funcref{gnutls_anti_replay_set_ptr}. Note that, if the back-end stores arbitrary number of ClientHello, it needs to periodically clean up the stored entries based on the time @@ -1028,15 +1029,15 @@ int main() */ gnutls_anti_replay_init(&anti_replay); + /* Set the database back-end function for the anti-replay data. */ + gnutls_anti_replay_set_add_function(anti_replay, db_add_func); + gnutls_anti_replay_set_ptr(anti_replay, NULL); + ... 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. @@ -1850,7 +1851,7 @@ A storing server needs to specify callback functions to store, retrieve and dele registered with the functions below. The stored sessions in the database can be checked using @funcref{gnutls_db_check_entry} for expiration. -@showfuncE{gnutls_db_set_retrieve_function,gnutls_db_set_store_function,gnutls_db_set_ptr,gnutls_db_set_remove_function,gnutls_db_set_add_function} +@showfuncD{gnutls_db_set_retrieve_function,gnutls_db_set_store_function,gnutls_db_set_ptr,gnutls_db_set_remove_function} @showfuncA{gnutls_db_check_entry} A server supporting session tickets must generate ticket encryption diff --git a/doc/manpages/Makefile.am b/doc/manpages/Makefile.am index 75c3aa7793..3bac791f3e 100644 --- a/doc/manpages/Makefile.am +++ b/doc/manpages/Makefile.am @@ -141,6 +141,8 @@ APIMANS += gnutls_anon_set_server_params_function.3 APIMANS += gnutls_anti_replay_deinit.3 APIMANS += gnutls_anti_replay_enable.3 APIMANS += gnutls_anti_replay_init.3 +APIMANS += gnutls_anti_replay_set_add_function.3 +APIMANS += gnutls_anti_replay_set_ptr.3 APIMANS += gnutls_anti_replay_set_window.3 APIMANS += gnutls_auth_client_get_type.3 APIMANS += gnutls_auth_get_type.3 @@ -249,7 +251,6 @@ APIMANS += gnutls_db_check_entry_time.3 APIMANS += gnutls_db_get_default_cache_expiration.3 APIMANS += gnutls_db_get_ptr.3 APIMANS += gnutls_db_remove_session.3 -APIMANS += gnutls_db_set_add_function.3 APIMANS += gnutls_db_set_cache_expiration.3 APIMANS += gnutls_db_set_ptr.3 APIMANS += gnutls_db_set_remove_function.3 @@ -56,29 +56,6 @@ gnutls_db_set_retrieve_function(gnutls_session_t session, } /** - * gnutls_db_set_add_function: - * @session: is a #gnutls_session_t type. - * @add_func: is the function. - * - * Sets the function that will be used to store an entry if it is not - * already present in the resumed sessions database. This function returns 0 - * if the entry is successfully stored, and a negative error code - * otherwise. In particular, if the entry is found in the database, - * it returns %GNUTLS_E_DB_ENTRY_EXISTS. - * - * The first argument to @add_func will be null unless - * gnutls_db_set_ptr() has been called. - * - * Since: 3.6.5 - **/ -void -gnutls_db_set_add_function(gnutls_session_t session, - gnutls_db_add_func add_func) -{ - session->internals.db_add_func = add_func; -} - -/** * gnutls_db_set_remove_function: * @session: is a #gnutls_session_t type. * @rem_func: is the function. diff --git a/lib/ext/pre_shared_key.c b/lib/ext/pre_shared_key.c index bc7fc8aa95..c42bd1646b 100644 --- a/lib/ext/pre_shared_key.c +++ b/lib/ext/pre_shared_key.c @@ -621,7 +621,7 @@ static int server_recv_params(gnutls_session_t session, } else { if (session->internals.hsk_flags & HSK_EARLY_DATA_ACCEPTED) { if (session->internals.anti_replay) { - ret = _gnutls_anti_replay_check(session, + ret = _gnutls_anti_replay_check(session->internals.anti_replay, ticket_age, &ticket_creation_time, &binder_recvd); diff --git a/lib/gnutls_int.h b/lib/gnutls_int.h index e34bea85b8..16881d8827 100644 --- a/lib/gnutls_int.h +++ b/lib/gnutls_int.h @@ -1216,7 +1216,6 @@ typedef struct { gnutls_db_store_func db_store_func; gnutls_db_retr_func db_retrieve_func; gnutls_db_remove_func db_remove_func; - gnutls_db_add_func db_add_func; void *db_ptr; /* post client hello callback (server side only) diff --git a/lib/includes/gnutls/gnutls.h.in b/lib/includes/gnutls/gnutls.h.in index 2af09bb24a..789e374315 100644 --- a/lib/includes/gnutls/gnutls.h.in +++ b/lib/includes/gnutls/gnutls.h.in @@ -1783,8 +1783,6 @@ typedef int (*gnutls_db_store_func) (void *, gnutls_datum_t key, gnutls_datum_t data); typedef int (*gnutls_db_remove_func) (void *, gnutls_datum_t key); typedef gnutls_datum_t(*gnutls_db_retr_func) (void *, gnutls_datum_t key); -typedef int (*gnutls_db_add_func) (void *, gnutls_datum_t key, - gnutls_datum_t data); void gnutls_db_set_cache_expiration(gnutls_session_t session, int seconds); unsigned gnutls_db_get_default_cache_expiration(void); @@ -1796,8 +1794,6 @@ void gnutls_db_set_remove_function(gnutls_session_t session, gnutls_db_remove_func rem_func); void gnutls_db_set_store_function(gnutls_session_t session, gnutls_db_store_func store_func); -void gnutls_db_set_add_function(gnutls_session_t session, - gnutls_db_add_func add_func); void gnutls_db_set_ptr(gnutls_session_t session, void *ptr); void *gnutls_db_get_ptr(gnutls_session_t session); int gnutls_db_check_entry(gnutls_session_t session, @@ -3002,6 +2998,15 @@ void gnutls_anti_replay_set_window(gnutls_anti_replay_t anti_replay, void gnutls_anti_replay_enable(gnutls_session_t session, gnutls_anti_replay_t anti_replay); +typedef int (*gnutls_db_add_func) (void *, time_t exp_time, const gnutls_datum_t *key, + const gnutls_datum_t *data); + +void gnutls_anti_replay_set_add_function(gnutls_anti_replay_t, + gnutls_db_add_func add_func); + +void gnutls_anti_replay_set_ptr(gnutls_anti_replay_t, void *ptr); + + /* FIPS140-2 related functions */ unsigned gnutls_fips140_mode_enabled(void); diff --git a/lib/libgnutls.map b/lib/libgnutls.map index 3cfc0c450b..06181f04ee 100644 --- a/lib/libgnutls.map +++ b/lib/libgnutls.map @@ -1255,7 +1255,8 @@ GNUTLS_3_6_5 gnutls_record_send_early_data; gnutls_record_recv_early_data; gnutls_db_check_entry_expire_time; - gnutls_db_set_add_function; + gnutls_anti_replay_set_add_function; + gnutls_anti_replay_set_ptr; gnutls_anti_replay_init; gnutls_anti_replay_deinit; gnutls_anti_replay_set_window; diff --git a/lib/tls13/anti_replay.c b/lib/tls13/anti_replay.c index 5ae9926afd..a99266928c 100644 --- a/lib/tls13/anti_replay.c +++ b/lib/tls13/anti_replay.c @@ -32,6 +32,8 @@ struct gnutls_anti_replay_st { uint32_t window; struct timespec start_time; + gnutls_db_add_func db_add_func; + void *db_ptr; }; /** @@ -121,13 +123,13 @@ gnutls_anti_replay_enable(gnutls_session_t session, } int -_gnutls_anti_replay_check(gnutls_session_t session, +_gnutls_anti_replay_check(gnutls_anti_replay_t anti_replay, uint32_t client_ticket_age, struct timespec *ticket_creation_time, gnutls_datum_t *id) { - gnutls_anti_replay_t anti_replay = session->internals.anti_replay; struct timespec now; + time_t window; uint32_t server_ticket_age, diff; gnutls_datum_t key = { NULL, 0 }; gnutls_datum_t entry = { NULL, 0 }; @@ -176,7 +178,7 @@ _gnutls_anti_replay_check(gnutls_session_t session, /* Check if the ClientHello is stored in the database. */ - if (!session->internals.db_add_func) + if (!anti_replay->db_add_func) return gnutls_assert_val(GNUTLS_E_EARLY_DATA_REJECTED); /* Create a key for database lookup, prefixing window start @@ -198,20 +200,21 @@ _gnutls_anti_replay_check(gnutls_session_t session, /* Create an entry to be stored on database if the lookup * failed. This is formatted so that - * gnutls_db_entry_is_expired() work. + * gnutls_db_check_entry_expire_time() work. */ p = entry_buffer; _gnutls_write_uint32(PACKED_SESSION_MAGIC, p); p += 4; _gnutls_write_uint32(now.tv_sec, p); p += 4; - _gnutls_write_uint32(anti_replay->window / 1000, p); + window = anti_replay->window / 1000; + _gnutls_write_uint32(window, p); p += 4; entry.data = entry_buffer; entry.size = p - entry_buffer; - ret = session->internals.db_add_func(session->internals.db_ptr, - key, entry); + ret = anti_replay->db_add_func(anti_replay->db_ptr, + (uint64_t)now.tv_sec+(uint64_t)window, &key, &entry); if (ret < 0) { _gnutls_handshake_log("anti_replay: duplicate ClientHello found\n"); return gnutls_assert_val(GNUTLS_E_EARLY_DATA_REJECTED); @@ -219,3 +222,45 @@ _gnutls_anti_replay_check(gnutls_session_t session, return 0; } + +/** + * gnutls_anti_replay_set_ptr: + * @anti_replay: is a #gnutls_anti_replay_t type. + * @ptr: is the pointer + * + * Sets the pointer that will be provided to db add function + * as the first argument. + **/ +void gnutls_anti_replay_set_ptr(gnutls_anti_replay_t anti_replay, void *ptr) +{ + anti_replay->db_ptr = ptr; +} + +/** + * gnutls_anti_replay_set_add_function: + * @anti_replay: is a #gnutls_anti_replay_t type. + * @add_func: is the function. + * + * Sets the function that will be used to store an entry if it is not + * already present in the resumed sessions database. This function returns 0 + * if the entry is successfully stored, and a negative error code + * otherwise. In particular, if the entry is found in the database, + * it returns %GNUTLS_E_DB_ENTRY_EXISTS. + * + * The arguments to the @add_func are: + * - %ptr: the pointer set with gnutls_anti_replay_set_ptr() + * - %exp_time: the expiration time of the entry + * - %key: a pointer to the key + * - %data: a pointer to data to store + * + * The data set by this function can be examined using + * gnutls_db_check_entry_expire_time() and gnutls_db_check_entry_time(). + * + * Since: 3.6.5 + **/ +void +gnutls_anti_replay_set_add_function(gnutls_anti_replay_t anti_replay, + gnutls_db_add_func add_func) +{ + anti_replay->db_add_func = add_func; +} diff --git a/lib/tls13/anti_replay.h b/lib/tls13/anti_replay.h index e44186c910..8d9bea4b5c 100644 --- a/lib/tls13/anti_replay.h +++ b/lib/tls13/anti_replay.h @@ -20,7 +20,7 @@ * */ -int _gnutls_anti_replay_check(gnutls_session_t session, +int _gnutls_anti_replay_check(gnutls_anti_replay_t, uint32_t client_ticket_age, struct timespec *ticket_creation_time, gnutls_datum_t *id); diff --git a/src/serv.c b/src/serv.c index 75871270a5..d0b5914bc0 100644 --- a/src/serv.c +++ b/src/serv.c @@ -126,8 +126,8 @@ static int wrap_db_store(void *dbf, gnutls_datum_t key, gnutls_datum_t data); static gnutls_datum_t wrap_db_fetch(void *dbf, gnutls_datum_t key); static int wrap_db_delete(void *dbf, gnutls_datum_t key); -static int wrap_db_add(void *dbf, gnutls_datum_t key, - gnutls_datum_t data); +static int anti_replay_db_add(void *dbf, time_t exp, const gnutls_datum_t *key, + const gnutls_datum_t *data); static void cmd_parser(int argc, char **argv); @@ -401,7 +401,6 @@ gnutls_session_t initialize_session(int dtls) gnutls_db_set_retrieve_function(session, wrap_db_fetch); gnutls_db_set_remove_function(session, wrap_db_delete); gnutls_db_set_store_function(session, wrap_db_store); - gnutls_db_set_add_function(session, wrap_db_add); gnutls_db_set_ptr(session, NULL); } @@ -1270,6 +1269,8 @@ int main(int argc, char **argv) fprintf(stderr, "Error while initializing anti-replay: %s\n", gnutls_strerror(ret)); exit(1); } + gnutls_anti_replay_set_add_function(anti_replay, anti_replay_db_add); + gnutls_anti_replay_set_ptr(anti_replay, NULL); } if (HAVE_OPT(MTU)) @@ -1897,19 +1898,19 @@ static int wrap_db_delete(void *dbf, gnutls_datum_t key) } static int -wrap_db_add(void *dbf, gnutls_datum_t key, gnutls_datum_t data) +anti_replay_db_add(void *dbf, time_t exp, const gnutls_datum_t *key, const gnutls_datum_t *data) { time_t now = time(0); int i; for (i = 0; i < cache_db_ptr; i++) { - if (key.size == cache_db[i].session_id_size && - memcmp(key.data, cache_db[i].session_id, - key.size) == 0 && + if (key->size == cache_db[i].session_id_size && + memcmp(key->data, cache_db[i].session_id, + key->size) == 0 && now < gnutls_db_check_entry_expire_time(&cache_db[i]. session_data)) return GNUTLS_E_DB_ENTRY_EXISTS; } - return wrap_db_store(dbf, key, data); + return wrap_db_store(dbf, *key, *data); } diff --git a/symbols.last b/symbols.last index 878c5c30b7..820821219e 100644 --- a/symbols.last +++ b/symbols.last @@ -28,6 +28,8 @@ gnutls_anon_set_server_params_function@GNUTLS_3_4 gnutls_anti_replay_deinit@GNUTLS_3_6_5 gnutls_anti_replay_enable@GNUTLS_3_6_5 gnutls_anti_replay_init@GNUTLS_3_6_5 +gnutls_anti_replay_set_add_function@GNUTLS_3_6_5 +gnutls_anti_replay_set_ptr@GNUTLS_3_6_5 gnutls_anti_replay_set_window@GNUTLS_3_6_5 gnutls_auth_client_get_type@GNUTLS_3_4 gnutls_auth_get_type@GNUTLS_3_4 @@ -146,7 +148,6 @@ gnutls_db_check_entry_time@GNUTLS_3_4 gnutls_db_get_default_cache_expiration@GNUTLS_3_4 gnutls_db_get_ptr@GNUTLS_3_4 gnutls_db_remove_session@GNUTLS_3_4 -gnutls_db_set_add_function@GNUTLS_3_6_5 gnutls_db_set_cache_expiration@GNUTLS_3_4 gnutls_db_set_ptr@GNUTLS_3_4 gnutls_db_set_remove_function@GNUTLS_3_4 diff --git a/tests/Makefile.am b/tests/Makefile.am index 7c11c90ec0..826e6ef697 100644 --- a/tests/Makefile.am +++ b/tests/Makefile.am @@ -398,7 +398,7 @@ endif if HAVE_FORK ctests += x509self x509dn anonself pskself dhepskself \ setcredcrash tls12-resume-x509 tls12-resume-psk tls12-resume-anon \ - tls13-resume-x509 tls13-resume-psk tls13-early-data + tls13-resume-x509 tls13-resume-psk tls13-early-data tls13-early-data-neg endif gc_CPPFLAGS = $(AM_CPPFLAGS) \ diff --git a/tests/tls13-early-data-neg.c b/tests/tls13-early-data-neg.c new file mode 100644 index 0000000000..35c635f63c --- /dev/null +++ b/tests/tls13-early-data-neg.c @@ -0,0 +1,479 @@ +/* + * Copyright (C) 2012-2018 Free Software Foundation, Inc. + * + * Author: Nikos Mavrogiannopoulos, Daiki Ueno + * + * 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 Lesser General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/> + */ + +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif + +#include <stdio.h> +#include <stdlib.h> + +#if defined(_WIN32) + +int main(void) +{ + exit(77); +} + +#else + +#include <string.h> +#include <sys/types.h> +#include <netinet/in.h> +#include <sys/socket.h> +#include <sys/wait.h> +#include <arpa/inet.h> +#include <unistd.h> +#include <gnutls/gnutls.h> +#include <gnutls/crypto.h> +#include <gnutls/dtls.h> +#include <signal.h> +#include <sys/wait.h> +#include <assert.h> + +#include "cert-common.h" +#include "utils.h" +#include "virt-time.h" + +/* This program tests the robustness of record sending with padding. + */ + +static void server_log_func(int level, const char *str) +{ + fprintf(stderr, "server|<%d>| %s", level, str); +} + +static void client_log_func(int level, const char *str) +{ + fprintf(stderr, "client|<%d>| %s", level, str); +} + + +#define SESSIONS 3 +#define MAX_BUF 1024 +#define MSG "Hello TLS" +#define EARLY_MSG "Hello TLS, it's early" +#define PRIORITY "NORMAL:-VERS-ALL:+VERS-TLS1.3" + +static const +gnutls_datum_t hrnd = {(void*)"\x00\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00", 32}; + +static int gnutls_rnd_works; + +int __attribute__ ((visibility ("protected"))) +gnutls_rnd(gnutls_rnd_level_t level, void *data, size_t len) +{ + gnutls_rnd_works = 1; + + memset(data, 0xff, len); + + /* Flip the first byte to avoid infinite loop in the RSA + * blinding code of Nettle */ + if (len > 0) + memset(data, 0x0, 1); + return 0; +} + +gnutls_datum_t client_hello_msg = {NULL, 0}; + +static int handshake_callback(gnutls_session_t session, unsigned int htype, + unsigned post, unsigned int incoming, const gnutls_datum_t *msg) +{ + assert(client_hello_msg.data == NULL); + + client_hello_msg.data = gnutls_malloc(msg->size+9); + assert(client_hello_msg.data != NULL); + client_hello_msg.size = msg->size+9; + memcpy(client_hello_msg.data+9, msg->data, msg->size); + /* reconstruct record header */ + client_hello_msg.data[0] = 22; + client_hello_msg.data[1] = 3; + client_hello_msg.data[2] = 3; + client_hello_msg.data[3] = (msg->size+4) >> 8; + client_hello_msg.data[4] = (msg->size+4); + + client_hello_msg.data[5] = GNUTLS_HANDSHAKE_CLIENT_HELLO; + client_hello_msg.data[6] = 0; + client_hello_msg.data[7] = msg->size >> 8; + client_hello_msg.data[8] = msg->size; + + return 0; +} + +static void client(int sds[]) +{ + int ret; + char buffer[MAX_BUF + 1]; + gnutls_certificate_credentials_t x509_cred; + gnutls_session_t session; + int t; + gnutls_datum_t session_data = {NULL, 0}; + + if (debug) { + gnutls_global_set_log_function(client_log_func); + gnutls_global_set_log_level(7); + } + + /* Generate the same ob_ticket_age value, which affects the + * binder calculation. + */ + virt_time_init(); + + gnutls_certificate_allocate_credentials(&x509_cred); + + for (t = 0; t < SESSIONS-1; t++) { + int sd = sds[t]; + + assert(gnutls_init(&session, GNUTLS_CLIENT)>=0); + assert(gnutls_priority_set_direct(session, PRIORITY, NULL)>=0); + + gnutls_credentials_set(session, GNUTLS_CRD_CERTIFICATE, x509_cred); + + gnutls_transport_set_int(session, sd); + + 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); + assert(gnutls_handshake_set_random(session, &hrnd) >= 0); + + gnutls_handshake_set_hook_function(session, GNUTLS_HANDSHAKE_CLIENT_HELLO, + GNUTLS_HOOK_POST, + handshake_callback); + } + + /* Perform the TLS handshake + */ + gnutls_handshake_set_timeout(session, 20 * 1000); + do { + ret = gnutls_handshake(session); + } + while (ret < 0 && gnutls_error_is_fatal(ret) == 0); + + if (ret < 0) { + fail("client: Handshake failed\n"); + gnutls_perror(ret); + exit(1); + } else { + if (debug) + success("client: Handshake was completed\n"); + } + + if (t == 0) { + /* get the session data size */ + ret = + gnutls_session_get_data2(session, + &session_data); + if (ret < 0) + fail("client: Getting resume data failed\n"); + } + + if (t > 0) { + if (!gnutls_session_is_resumed(session)) { + fail("client: session_is_resumed error (%d)\n", t); + } + } + + gnutls_record_send(session, MSG, strlen(MSG)); + + do { + ret = gnutls_record_recv(session, buffer, sizeof(buffer)); + } while (ret == GNUTLS_E_AGAIN); + if (ret == 0) { + if (debug) + success + ("client: Peer has closed the TLS connection\n"); + goto end; + } else if (ret < 0) { + fail("client: Error: %s\n", gnutls_strerror(ret)); + goto end; + } + + gnutls_bye(session, GNUTLS_SHUT_WR); + + close(sd); + + gnutls_deinit(session); + } + + assert(client_hello_msg.data != NULL); + + ret = send(sds[SESSIONS-1], client_hello_msg.data, client_hello_msg.size, 0); + assert(ret == (int)client_hello_msg.size); + + end: + gnutls_free(client_hello_msg.data); + gnutls_free(session_data.data); + gnutls_certificate_free_credentials(x509_cred); +} + + +static pid_t child; + +#define MAX_CLIENT_HELLO_RECORDED 10 + +struct storage_st { + gnutls_datum_t entries[MAX_CLIENT_HELLO_RECORDED]; + size_t num_entries; +}; + +static int +storage_add(void *ptr, time_t expires, const gnutls_datum_t *key, const gnutls_datum_t *value) +{ + struct storage_st *storage = ptr; + gnutls_datum_t *datum; + size_t i; + + for (i = 0; i < storage->num_entries; i++) { + if (key->size == storage->entries[i].size && + memcmp(storage->entries[i].data, key->data, key->size) == 0) { + return GNUTLS_E_DB_ENTRY_EXISTS; + } + } + + /* If the maximum number of ClientHello exceeded, reject early + * data until next time. + */ + if (storage->num_entries == MAX_CLIENT_HELLO_RECORDED) + return GNUTLS_E_DB_ERROR; + + datum = &storage->entries[storage->num_entries]; + datum->data = gnutls_malloc(key->size); + if (!datum->data) + return GNUTLS_E_MEMORY_ERROR; + memcpy(datum->data, key->data, key->size); + datum->size = key->size; + + storage->num_entries++; + + return 0; +} + +static void +storage_clear(struct storage_st *storage) +{ + size_t i; + + for (i = 0; i < storage->num_entries; i++) + gnutls_free(storage->entries[i].data); + storage->num_entries = 0; +} + +static void server(int sds[]) +{ + int ret; + char buffer[MAX_BUF + 1]; + gnutls_session_t session; + gnutls_certificate_credentials_t x509_cred; + gnutls_datum_t session_ticket_key = { NULL, 0 }; + struct storage_st storage; + gnutls_anti_replay_t anti_replay; + int t; + + /* this must be called once in the program + */ + global_init(); + memset(buffer, 0, sizeof(buffer)); + memset(&storage, 0, sizeof(storage)); + + if (debug) { + gnutls_global_set_log_function(server_log_func); + gnutls_global_set_log_level(4711); + } + + gnutls_certificate_allocate_credentials(&x509_cred); + gnutls_certificate_set_x509_key_mem(x509_cred, &server_cert, + &server_key, + GNUTLS_X509_FMT_PEM); + + gnutls_session_ticket_key_generate(&session_ticket_key); + + ret = gnutls_anti_replay_init(&anti_replay); + if (ret < 0) + fail("server: failed to initialize anti-replay\n"); + gnutls_anti_replay_set_add_function(anti_replay, storage_add); + gnutls_anti_replay_set_ptr(anti_replay, &storage); + + for (t = 0; t < SESSIONS; t++) { + int sd = sds[t]; + + success("=== session %d ===\n", t); + + assert(gnutls_init(&session, GNUTLS_SERVER|GNUTLS_ENABLE_EARLY_DATA)>=0); + + assert(gnutls_priority_set_direct(session, PRIORITY, NULL)>=0); + + gnutls_credentials_set(session, GNUTLS_CRD_CERTIFICATE, x509_cred); + + gnutls_session_ticket_enable_server(session, + &session_ticket_key); + + gnutls_anti_replay_enable(session, anti_replay); + + gnutls_transport_set_int(session, sd); + + do { + ret = gnutls_handshake(session); + } while (ret < 0 && gnutls_error_is_fatal(ret) == 0); + + if (t == SESSIONS-1) { + /* duplicate data expected */ + if (ret < 0 && !(gnutls_session_get_flags(session) & GNUTLS_SFLAGS_EARLY_DATA)) { + success("we detected the duplicate data!\n"); + close(sd); + gnutls_deinit(session); + goto cleanup; + } else { + fail("server: duplicate early data was not detected (%d)\n", t); + } + } + + if (ret < 0) { + close(sd); + gnutls_deinit(session); + fail("server[%d]: Handshake has failed (%s)\n\n", + t, gnutls_strerror(ret)); + return; + } + if (debug) + success("server: Handshake was completed\n"); + + if (t > 0) { + if (!gnutls_session_is_resumed(session)) { + fail("server: session_is_resumed error (%d)\n", t); + } + + /* as we reuse the same ticket twice, expect + * early data only on the first resumption */ + if (t == 1) { + if (gnutls_rnd_works) { + if (!(gnutls_session_get_flags(session) & GNUTLS_SFLAGS_EARLY_DATA)) { + fail("server: early data is not received (%d)\n", t); + } + } else { + success("server: gnutls_rnd() could not be overridden, skip checking replay (%d)\n", t); + } + + ret = gnutls_record_recv_early_data(session, buffer, sizeof(buffer)); + if (ret < 0) { + fail("server: failed to retrieve early data: %s\n", + gnutls_strerror(ret)); + } + + if (ret != sizeof(EARLY_MSG) || memcmp(buffer, EARLY_MSG, ret)) + fail("server: early data mismatch\n"); + } else { + if (gnutls_rnd_works) { + if (gnutls_session_get_flags(session) & GNUTLS_SFLAGS_EARLY_DATA) { + fail("server: early data is not rejected (%d)\n", t); + } + } else { + success("server: gnutls_rnd() could not be overridden, skip checking replay (%d)\n", t); + } + } + } + + for (;;) { + memset(buffer, 0, MAX_BUF + 1); + ret = gnutls_record_recv(session, buffer, MAX_BUF); + + if (ret == 0) { + if (debug) + success + ("server: Peer has closed the GnuTLS connection\n"); + break; + } else if (ret < 0) { + kill(child, SIGTERM); + fail("server: Received corrupted data(%d). Closing...\n", ret); + break; + } else if (ret > 0) { + /* echo data back to the client + */ + gnutls_record_send(session, buffer, + strlen(buffer)); + } + } + /* do not wait for the peer to close the connection. + */ + gnutls_bye(session, GNUTLS_SHUT_WR); + + close(sd); + + gnutls_deinit(session); + } + + cleanup: + gnutls_anti_replay_deinit(anti_replay); + + storage_clear(&storage); + + gnutls_free(session_ticket_key.data); + + gnutls_certificate_free_credentials(x509_cred); + + if (debug) + success("server: finished\n"); +} + +void doit(void) +{ + int client_sds[SESSIONS], server_sds[SESSIONS]; + int i, status = 0; + int ret; + + signal(SIGCHLD, SIG_IGN); + signal(SIGPIPE, SIG_IGN); + + for (i = 0; i < SESSIONS; i++) { + int sockets[2]; + + ret = socketpair(AF_UNIX, SOCK_STREAM, 0, sockets); + if (ret < 0) { + perror("socketpair"); + exit(1); + } + + server_sds[i] = sockets[0]; + client_sds[i] = sockets[1]; + } + + child = fork(); + if (child < 0) { + perror("fork"); + fail("fork"); + exit(1); + } + + if (child) { + /* parent */ + for (i = 0; i < SESSIONS; i++) + close(client_sds[i]); + server(server_sds); + wait(&status); + check_wait_status(status); + } else { + for (i = 0; i < SESSIONS; i++) + close(server_sds[i]); + client(client_sds); + exit(0); + } +} + +#endif /* _WIN32 */ diff --git a/tests/tls13-early-data.c b/tests/tls13-early-data.c index f23aec77fa..c922ae0ba6 100644 --- a/tests/tls13-early-data.c +++ b/tests/tls13-early-data.c @@ -201,15 +201,15 @@ struct storage_st { }; static int -storage_add(void *ptr, gnutls_datum_t key, gnutls_datum_t value) +storage_add(void *ptr, time_t expires, const gnutls_datum_t *key, const gnutls_datum_t *value) { struct storage_st *storage = ptr; gnutls_datum_t *datum; size_t i; for (i = 0; i < storage->num_entries; i++) { - if (key.size == storage->entries[i].size && - memcmp(storage->entries[i].data, key.data, key.size) == 0) { + if (key->size == storage->entries[i].size && + memcmp(storage->entries[i].data, key->data, key->size) == 0) { return GNUTLS_E_DB_ENTRY_EXISTS; } } @@ -221,11 +221,11 @@ storage_add(void *ptr, gnutls_datum_t key, gnutls_datum_t value) return GNUTLS_E_DB_ERROR; datum = &storage->entries[storage->num_entries]; - datum->data = gnutls_malloc(key.size); + datum->data = gnutls_malloc(key->size); if (!datum->data) return GNUTLS_E_MEMORY_ERROR; - memcpy(datum->data, key.data, key.size); - datum->size = key.size; + memcpy(datum->data, key->data, key->size); + datum->size = key->size; storage->num_entries++; @@ -275,6 +275,9 @@ static void server(int sds[]) if (ret < 0) fail("server: failed to initialize anti-replay\n"); + gnutls_anti_replay_set_add_function(anti_replay, storage_add); + gnutls_anti_replay_set_ptr(anti_replay, &storage); + for (t = 0; t < SESSIONS; t++) { int sd = sds[t]; @@ -287,8 +290,6 @@ static void server(int sds[]) gnutls_session_ticket_enable_server(session, &session_ticket_key); - gnutls_db_set_add_function(session, storage_add); - gnutls_db_set_ptr(session, &storage); gnutls_anti_replay_enable(session, anti_replay); gnutls_transport_set_int(session, sd); diff --git a/tests/tls13/anti_replay.c b/tests/tls13/anti_replay.c index 090dcabbdb..31ab517151 100644 --- a/tests/tls13/anti_replay.c +++ b/tests/tls13/anti_replay.c @@ -37,15 +37,15 @@ struct storage_st { }; static int -storage_add(void *ptr, gnutls_datum_t key, gnutls_datum_t value) +storage_add(void *ptr, time_t expires, const gnutls_datum_t *key, const gnutls_datum_t *value) { struct storage_st *storage = ptr; gnutls_datum_t *datum; size_t i; for (i = 0; i < storage->num_entries; i++) { - if (key.size == storage->entries[i].size && - memcmp(storage->entries[i].data, key.data, key.size) == 0) { + if (key->size == storage->entries[i].size && + memcmp(storage->entries[i].data, key->data, key->size) == 0) { return GNUTLS_E_DB_ENTRY_EXISTS; } } @@ -57,11 +57,11 @@ storage_add(void *ptr, gnutls_datum_t key, gnutls_datum_t value) return GNUTLS_E_DB_ERROR; datum = &storage->entries[storage->num_entries]; - datum->data = gnutls_malloc(key.size); + datum->data = gnutls_malloc(key->size); if (!datum->data) return GNUTLS_E_MEMORY_ERROR; - memcpy(datum->data, key.data, key.size); - datum->size = key.size; + memcpy(datum->data, key->data, key->size); + datum->size = key->size; storage->num_entries++; @@ -94,12 +94,12 @@ void doit(void) ret = gnutls_anti_replay_init(&anti_replay); assert(ret == 0); gnutls_anti_replay_set_window(anti_replay, 10000); + gnutls_anti_replay_set_add_function(anti_replay, storage_add); + gnutls_anti_replay_set_ptr(anti_replay, &storage); gnutls_init(&session, GNUTLS_SERVER); - gnutls_db_set_add_function(session, storage_add); - gnutls_db_set_ptr(session, &storage); gnutls_anti_replay_enable(session, anti_replay); mygettime(&creation_time); - ret = _gnutls_anti_replay_check(session, 10000, &creation_time, &key); + ret = _gnutls_anti_replay_check(anti_replay, 10000, &creation_time, &key); if (ret != GNUTLS_E_ILLEGAL_PARAMETER) fail("error is not returned, while server_ticket_age < client_ticket_age\n"); gnutls_deinit(session); @@ -109,14 +109,14 @@ void doit(void) /* server_ticket_age - client_ticket_age > window */ ret = gnutls_anti_replay_init(&anti_replay); assert(ret == 0); + gnutls_anti_replay_set_add_function(anti_replay, storage_add); + gnutls_anti_replay_set_ptr(anti_replay, &storage); gnutls_anti_replay_set_window(anti_replay, 10000); gnutls_init(&session, GNUTLS_SERVER); - gnutls_db_set_add_function(session, storage_add); - gnutls_db_set_ptr(session, &storage); gnutls_anti_replay_enable(session, anti_replay); mygettime(&creation_time); virt_sec_sleep(30); - ret = _gnutls_anti_replay_check(session, 10000, &creation_time, &key); + ret = _gnutls_anti_replay_check(anti_replay, 10000, &creation_time, &key); if (ret != GNUTLS_E_EARLY_DATA_REJECTED) fail("early data is NOT rejected, while freshness check fails\n"); gnutls_deinit(session); @@ -126,17 +126,17 @@ void doit(void) /* server_ticket_age - client_ticket_age < window */ ret = gnutls_anti_replay_init(&anti_replay); assert(ret == 0); + gnutls_anti_replay_set_add_function(anti_replay, storage_add); + gnutls_anti_replay_set_ptr(anti_replay, &storage); gnutls_anti_replay_set_window(anti_replay, 10000); gnutls_init(&session, GNUTLS_SERVER); - gnutls_db_set_add_function(session, storage_add); - gnutls_db_set_ptr(session, &storage); gnutls_anti_replay_enable(session, anti_replay); mygettime(&creation_time); virt_sec_sleep(15); - ret = _gnutls_anti_replay_check(session, 10000, &creation_time, &key); + ret = _gnutls_anti_replay_check(anti_replay, 10000, &creation_time, &key); if (ret != 0) fail("early data is rejected, while freshness check succeeds\n"); - ret = _gnutls_anti_replay_check(session, 10000, &creation_time, &key); + ret = _gnutls_anti_replay_check(anti_replay, 10000, &creation_time, &key); if (ret != GNUTLS_E_EARLY_DATA_REJECTED) fail("early data is NOT rejected for a duplicate key\n"); gnutls_deinit(session); |