diff options
author | Daiki Ueno <dueno@redhat.com> | 2018-10-15 11:29:56 +0200 |
---|---|---|
committer | Daiki Ueno <dueno@redhat.com> | 2018-11-12 13:26:43 +0100 |
commit | 3d6d94b5d148a34f1ce2fb327eda02a525e439e8 (patch) | |
tree | 6f55e1401edabc97f87c7070d963244ec3ff9809 | |
parent | 5c8d543e9554292f22200b91a0595d3dfa26cecf (diff) | |
download | gnutls-3d6d94b5d148a34f1ce2fb327eda02a525e439e8.tar.gz |
tests: add tests for early data
Signed-off-by: Daiki Ueno <dueno@redhat.com>
-rw-r--r-- | .gitignore | 1 | ||||
-rw-r--r-- | tests/Makefile.am | 2 | ||||
-rw-r--r-- | tests/tls13-early-data.c | 325 |
3 files changed, 327 insertions, 1 deletions
diff --git a/.gitignore b/.gitignore index 3fc64789dd..d4a06fe3f7 100644 --- a/.gitignore +++ b/.gitignore @@ -764,6 +764,7 @@ tests/tls13-cert-key-exchange tests/tls13/change_cipher_spec tests/tls13-cipher-neg tests/tls13/cookie +tests/tls13-early-data tests/tls13-early-start tests/tls13/hello_random_value tests/tls13/hello_retry_request diff --git a/tests/Makefile.am b/tests/Makefile.am index 021da722ae..b3fee01e00 100644 --- a/tests/Makefile.am +++ b/tests/Makefile.am @@ -397,7 +397,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-resume-x509 tls13-resume-psk tls13-early-data endif gc_CPPFLAGS = $(AM_CPPFLAGS) \ diff --git a/tests/tls13-early-data.c b/tests/tls13-early-data.c new file mode 100644 index 0000000000..1189eb10c1 --- /dev/null +++ b/tests/tls13-early-data.c @@ -0,0 +1,325 @@ +/* + * 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/dtls.h> +#include <signal.h> +#include <assert.h> + +#include "cert-common.h" +#include "utils.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); +} + + +/* A very basic TLS client. + */ + +#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 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); + } + + gnutls_certificate_allocate_credentials(&x509_cred); + + for (t = 0; t < SESSIONS; 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); + } + + /* 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 == 1) { + 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); + } + + end: + gnutls_free(session_data.data); + gnutls_certificate_free_credentials(x509_cred); +} + + +static pid_t child; + +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 }; + int t; + + /* this must be called once in the program + */ + global_init(); + memset(buffer, 0, sizeof(buffer)); + + 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); + + for (t = 0; t < SESSIONS; t++) { + int sd = sds[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_transport_set_int(session, sd); + + do { + ret = gnutls_handshake(session); + } + while (ret < 0 && gnutls_error_is_fatal(ret) == 0); + if (ret < 0) { + close(sd); + gnutls_deinit(session); + fail("server: Handshake has failed (%s)\n\n", + gnutls_strerror(ret)); + return; + } + if (debug) + success("server: Handshake was completed\n"); + + if (t == 1) { + if (!gnutls_session_is_resumed(session)) { + fail("server: session_is_resumed error (%d)\n", t); + } + + if (!(gnutls_session_get_flags(session) & GNUTLS_SFLAGS_EARLY_DATA)) { + fail("server: early data is not received (%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"); + } + + /* see the Getting peer's information example */ + /* print_info(session); */ + + 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); + } + + 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; + 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); + kill(child, SIGTERM); + } else { + for (i = 0; i < SESSIONS; i++) + close(server_sds[i]); + client(client_sds); + exit(0); + } +} + +#endif /* _WIN32 */ |