From 048dc3177c0f542c66e55472e4d5db1c1d2f3e0e Mon Sep 17 00:00:00 2001 From: Nikos Mavrogiannopoulos Date: Wed, 14 Nov 2018 13:42:01 +0100 Subject: tests: added a test for detecting duplicate early data Resolves #610 Signed-off-by: Nikos Mavrogiannopoulos --- tests/Makefile.am | 2 +- tests/tls13-early-data-neg.c | 479 +++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 480 insertions(+), 1 deletion(-) create mode 100644 tests/tls13-early-data-neg.c diff --git a/tests/Makefile.am b/tests/Makefile.am index 1ccba11028..153062b71d 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..6c7a1f492d --- /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 + */ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include +#include + +#if defined(_WIN32) + +int main(void) +{ + exit(77); +} + +#else + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#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, gnutls_datum_t key, 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"); + + 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_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); + + 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; + 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 */ -- cgit v1.2.1 From e1cd3313acb4c15ffc0f009c89a859e1f9b3bed4 Mon Sep 17 00:00:00 2001 From: Nikos Mavrogiannopoulos Date: Wed, 14 Nov 2018 13:56:52 +0100 Subject: anti_replay: moved new add function into anti_replay structure The new function was not sharing anything with the existing gnutls_db_* backend, and moving it to anti_replay structure is more clean and allows for deviations from the old API conventions (e.g., now we can pass pointers for efficiency and pass the expiration time as part of the call). Signed-off-by: Nikos Mavrogiannopoulos --- NEWS | 4 +-- doc/cha-gtls-app.texi | 13 ++++----- lib/db.c | 23 ---------------- lib/ext/pre_shared_key.c | 2 +- lib/gnutls_int.h | 1 - lib/includes/gnutls/gnutls.h.in | 13 ++++++--- lib/libgnutls.map | 3 ++- lib/tls13/anti_replay.c | 59 ++++++++++++++++++++++++++++++++++++----- lib/tls13/anti_replay.h | 2 +- src/serv.c | 17 ++++++------ tests/tls13-early-data-neg.c | 18 ++++++------- tests/tls13-early-data.c | 17 ++++++------ tests/tls13/anti_replay.c | 32 +++++++++++----------- 13 files changed, 117 insertions(+), 87 deletions(-) diff --git a/NEWS b/NEWS index 3332ce7d16..efb7ea7003 100644 --- a/NEWS +++ b/NEWS @@ -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/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/lib/db.c b/lib/db.c index 414816fcc8..e01e5b94c5 100644 --- a/lib/db.c +++ b/lib/db.c @@ -55,29 +55,6 @@ gnutls_db_set_retrieve_function(gnutls_session_t session, session->internals.db_retrieve_func = retr_func; } -/** - * 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. 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/tests/tls13-early-data-neg.c b/tests/tls13-early-data-neg.c index 6c7a1f492d..35c635f63c 100644 --- a/tests/tls13-early-data-neg.c +++ b/tests/tls13-early-data-neg.c @@ -235,15 +235,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; } } @@ -255,11 +255,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++; @@ -308,6 +308,8 @@ static void server(int sds[]) 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]; @@ -323,8 +325,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); @@ -435,7 +435,7 @@ static void server(int sds[]) void doit(void) { int client_sds[SESSIONS], server_sds[SESSIONS]; - int i, status; + int i, status = 0; int ret; signal(SIGCHLD, SIG_IGN); 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); -- cgit v1.2.1 From a23bc3113169655b2f32e357d7a9b8f2b42ea105 Mon Sep 17 00:00:00 2001 From: Nikos Mavrogiannopoulos Date: Thu, 15 Nov 2018 16:03:38 +0100 Subject: updated auto-generated-files Signed-off-by: Nikos Mavrogiannopoulos --- doc/Makefile.am | 6 ++++-- doc/manpages/Makefile.am | 3 ++- symbols.last | 3 ++- 3 files changed, 8 insertions(+), 4 deletions(-) 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/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 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 -- cgit v1.2.1