diff options
-rw-r--r-- | .gitignore | 3 | ||||
-rw-r--r-- | lib/gnutls_buffers.c | 31 | ||||
-rw-r--r-- | lib/gnutls_dtls.c | 107 | ||||
-rw-r--r-- | lib/gnutls_int.h | 20 | ||||
-rw-r--r-- | lib/gnutls_state.c | 8 | ||||
-rw-r--r-- | lib/includes/gnutls/gnutls.h.in | 2 | ||||
-rw-r--r-- | lib/system.h | 17 | ||||
-rw-r--r-- | tests/Makefile.am | 4 | ||||
-rw-r--r-- | tests/eagain-common.h | 144 | ||||
-rw-r--r-- | tests/mini-eagain-dtls.c | 219 | ||||
-rw-r--r-- | tests/mini-eagain.c | 169 | ||||
-rw-r--r-- | tests/utils.c | 2 |
12 files changed, 564 insertions, 162 deletions
diff --git a/.gitignore b/.gitignore index d286453d44..4b94e31cb9 100644 --- a/.gitignore +++ b/.gitignore @@ -412,6 +412,8 @@ src/psktool src/srptool stamp-h1 tags +tests/rng-fork +tests/mini-eagain-dtls tests/*/out tests/Makefile tests/Makefile.in @@ -446,6 +448,7 @@ tests/mpi tests/netconf-psk tests/nul-in-x509-names tests/openpgp-auth +tests/openpgp-auth2 tests/openpgp-certs/Makefile tests/openpgp-certs/Makefile.in tests/openpgp-keyring diff --git a/lib/gnutls_buffers.c b/lib/gnutls_buffers.c index 778af8d0bc..39657a0ed6 100644 --- a/lib/gnutls_buffers.c +++ b/lib/gnutls_buffers.c @@ -54,6 +54,7 @@ #include <system.h> #include <gnutls_constate.h> /* gnutls_epoch_get */ #include <errno.h> +#include <system.h> #ifndef EAGAIN #define EAGAIN EWOULDBLOCK @@ -61,7 +62,7 @@ /* this is the maximum number of messages allowed to queue. */ -#define MAX_QUEUE 16 +#define MAX_QUEUE 32 /* Buffers received packets of type APPLICATION DATA and * HANDSHAKE DATA. @@ -553,7 +554,7 @@ _gnutls_io_write_flush (gnutls_session_t session) tosend += msg.size; /* we buffer up to MAX_QUEUE messages */ - if (i >= sizeof (iovec) / sizeof (iovec[0])) + if (i >= MAX_QUEUE) { gnutls_assert (); return GNUTLS_E_INTERNAL_ERROR; @@ -676,7 +677,6 @@ _gnutls_handshake_io_write_flush (gnutls_session_t session) } return _gnutls_io_write_flush (session); - } @@ -914,7 +914,7 @@ handshake_buffer_st* recv_buf = session->internals.handshake_recv_buffer; { if (session->internals.handshake_recv_buffer_size == 0 || (session->internals.dtls.hsk_read_seq != recv_buf[LAST_ELEMENT].sequence)) - return gnutls_assert_val(GNUTLS_E_AGAIN); + goto timeout; if (htype != recv_buf[LAST_ELEMENT].htype) { @@ -932,7 +932,7 @@ handshake_buffer_st* recv_buf = session->internals.handshake_recv_buffer; return 0; } else - return gnutls_assert_val(GNUTLS_E_AGAIN); + goto timeout; } else /* TLS */ { @@ -949,7 +949,18 @@ handshake_buffer_st* recv_buf = session->internals.handshake_recv_buffer; return 0; } else - return GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE; + return gnutls_assert_val(GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE); + } + +timeout: + if (time(0)-session->internals.dtls.handshake_start_time > session->internals.dtls.total_timeout/1000) + return gnutls_assert_val(GNUTLS_E_TIMEDOUT); + else + { + if (session->internals.dtls.blocking != 0) + millisleep(50); + + return gnutls_assert_val(GNUTLS_E_AGAIN); } } @@ -1108,7 +1119,7 @@ next: while(session->internals.handshake_recv_buffer_size > 0 && recv_buf[LAST_ELEMENT].sequence < session->internals.dtls.hsk_read_seq) { - _gnutls_audit_log("Discarded replayed handshake packet with sequence %d\n", tmp.sequence); + _gnutls_audit_log("Discarded replayed handshake packet with sequence %d\n", recv_buf[LAST_ELEMENT].sequence); _gnutls_handshake_buffer_clear(&recv_buf[LAST_ELEMENT]); session->internals.handshake_recv_buffer_size--; } @@ -1128,8 +1139,10 @@ _gnutls_handshake_io_recv_int (gnutls_session_t session, int ret; ret = get_last_packet(session, htype, hsk); - if (ret >= 0) - return ret; + if (ret != GNUTLS_E_AGAIN && ret != GNUTLS_E_INTERRUPTED && ret != GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE) + { + return gnutls_assert_val(ret); + } /* try using the already existing records before * trying to receive. diff --git a/lib/gnutls_dtls.c b/lib/gnutls_dtls.c index 076be8c643..89dc0661bb 100644 --- a/lib/gnutls_dtls.c +++ b/lib/gnutls_dtls.c @@ -1,7 +1,8 @@ /* - * Copyright (C) 2009 Free Software Foundation (copyright assignement pending) + * Copyright (C) 2009,2011 Free Software Foundation * - * Author: Jonathan Bastien-Filiatrault + * Authors: Jonathan Bastien-Filiatrault + * Nikos Mavrogiannopoulos * * This file is part of GNUTLS. * @@ -155,6 +156,10 @@ time_t now = time(0); } +#define UPDATE_TIMER \ + session->internals.dtls.actual_retrans_timeout *= 2; \ + session->internals.dtls.actual_retrans_timeout %= MAX_DTLS_TIMEOUT + /* This function transmits the flight that has been previously * buffered. * @@ -170,13 +175,52 @@ int ret; mbuffer_head_st *const send_buffer = &session->internals.handshake_send_buffer; mbuffer_st *cur; - unsigned int total_timeout = 0; - unsigned int timeout = session->internals.dtls.retrans_timeout; gnutls_handshake_description_t last_type = 0; + time_t now = time(0); + + /* If we have already sent a flight and we are operating in a + * non blocking way, check if it is time to retransmit or just + * return. + */ + if (session->internals.dtls.flight_init != 0 && session->internals.dtls.blocking == 0) + { + /* just in case previous run was interrupted */ + ret = _gnutls_io_write_flush (session); + + if (session->internals.dtls.last_flight == 0) + { + /* check for ACK */ + ret = _gnutls_io_check_recv(session, 0); + if (ret == GNUTLS_E_TIMEDOUT) + { + /* if no retransmission is required yet just return + */ + if (now-session->internals.dtls.handshake_start_time < session->internals.dtls.actual_retrans_timeout) + { + session->internals.dtls.handshake_last_call = now; + goto nb_timeout; + } + } + else /* received ack */ + { + ret = 0; + goto cleanup; + } + } + else + return ret; + } + do { - _gnutls_dtls_log ("DTLS[%p]: Start of flight transmission.\n", session); + if (now-session->internals.dtls.handshake_start_time >= session->internals.dtls.total_timeout/1000) + { + ret = gnutls_assert_val(GNUTLS_E_TIMEDOUT); + goto cleanup; + } + + _gnutls_dtls_log ("DTLS[%p]: %sstart of flight transmission.\n", session, (session->internals.dtls.flight_init == 0)?"":"re-"); for (cur = send_buffer->head; cur != NULL; cur = cur->next) @@ -185,12 +229,32 @@ int ret; last_type = cur->htype; } + if (session->internals.dtls.flight_init == 0) + { + session->internals.dtls.flight_init = 1; + session->internals.dtls.handshake_last_call = now; + session->internals.dtls.actual_retrans_timeout = session->internals.dtls.retrans_timeout; + + if (last_type == GNUTLS_HANDSHAKE_FINISHED && _dtls_is_async(session)) + { + /* we cannot do anything here. We just return 0 and + * if a retransmission occurs because peer didn't receive it + * we rely on the record layer calling this function again. + */ + session->internals.dtls.last_flight = 1; + } + else + session->internals.dtls.last_flight = 0; + + + } + ret = _gnutls_io_write_flush (session); if (ret < 0) return gnutls_assert_val(ret); /* last message in handshake -> no ack */ - if (last_type == GNUTLS_HANDSHAKE_FINISHED && _dtls_is_async(session)) + if (session->internals.dtls.last_flight != 0) { /* we cannot do anything here. We just return 0 and * if a retransmission occurs because peer didn't receive it @@ -200,17 +264,21 @@ int ret; } else /* all other messages -> implicit ack (receive of next flight) */ { - ret = _gnutls_io_check_recv(session, timeout); + if (session->internals.dtls.blocking != 0) + ret = _gnutls_io_check_recv(session, session->internals.dtls.actual_retrans_timeout); + else + { + ret = _gnutls_io_check_recv(session, 0); + if (ret == GNUTLS_E_TIMEDOUT) + { + UPDATE_TIMER; + goto nb_timeout; + } + } } - total_timeout += timeout; - timeout *= 2; - timeout %= MAX_DTLS_TIMEOUT; - - if (total_timeout >= session->internals.dtls.total_timeout) { - ret = gnutls_assert_val(GNUTLS_E_TIMEDOUT); - goto cleanup; - } + UPDATE_TIMER; + now = time(0); } while(ret == GNUTLS_E_TIMEDOUT); if (ret < 0) @@ -219,15 +287,20 @@ int ret; goto cleanup; } - _gnutls_dtls_log ("DTLS[%p]: End of flight transmission.\n", session); ret = 0; cleanup: + _gnutls_dtls_log ("DTLS[%p]: End of flight transmission.\n", session); + + session->internals.dtls.flight_init = 0; drop_usage_count(session, send_buffer); _mbuffer_head_clear(send_buffer); /* SENDING -> WAITING state transition */ return ret; + +nb_timeout: + return GNUTLS_E_AGAIN; } #define window_table session->internals.dtls.record_sw @@ -352,7 +425,7 @@ int i, offset = 0; void gnutls_dtls_set_timeouts (gnutls_session_t session, unsigned int retrans_timeout, unsigned int total_timeout) { - session->internals.dtls.retrans_timeout = retrans_timeout; + session->internals.dtls.retrans_timeout = retrans_timeout; session->internals.dtls.total_timeout = total_timeout; } diff --git a/lib/gnutls_int.h b/lib/gnutls_int.h index c44b9cab33..b11df42fcf 100644 --- a/lib/gnutls_int.h +++ b/lib/gnutls_int.h @@ -581,17 +581,30 @@ typedef struct /* For DTLS handshake fragmentation and reassembly. */ uint16_t hsk_write_seq; - int hsk_read_seq; + unsigned int hsk_read_seq; uint16_t mtu; + /* a flight transmission is in process */ + unsigned int flight_init:1; + /* whether this is the last flight in the protocol */ + unsigned int last_flight:1; unsigned int retrans_timeout; unsigned int total_timeout; unsigned int hsk_hello_verify_requests; uint64_t record_sw[DTLS_RECORD_WINDOW_SIZE]; - int record_sw_size; - + unsigned int record_sw_size; + + /* non blocking stuff variables */ + unsigned int blocking:1; + /* starting time of current handshake */ + time_t handshake_start_time; + /* time in seconds of the last handshake call */ + time_t handshake_last_call; + /* The actual retrans_timeout for the next message (e.g. doubled or so) */ + unsigned int actual_retrans_timeout; + /* timers to handle async handshake after gnutls_handshake() * has terminated. Required to handle retransmissions. */ @@ -850,7 +863,6 @@ struct gnutls_session_int }; - /* functions */ void _gnutls_set_current_version (gnutls_session_t session, diff --git a/lib/gnutls_state.c b/lib/gnutls_state.c index b268971cb0..f14927db18 100644 --- a/lib/gnutls_state.c +++ b/lib/gnutls_state.c @@ -258,6 +258,7 @@ _gnutls_handshake_internal_state_init (gnutls_session_t session) session->internals.dtls.hsk_read_seq = 0; session->internals.dtls.hsk_write_seq = 0; + session->internals.dtls.handshake_start_time = time(0); } void @@ -380,6 +381,13 @@ gnutls_init (gnutls_session_t * session, unsigned int flags) (*session)->internals.dtls.record_sw_size = 0; } + else + (*session)->internals.transport = GNUTLS_STREAM; + + if (flags & GNUTLS_NONBLOCK) + (*session)->internals.dtls.blocking = 0; + else + (*session)->internals.dtls.blocking = 1; return 0; } diff --git a/lib/includes/gnutls/gnutls.h.in b/lib/includes/gnutls/gnutls.h.in index 674ca60532..821002135b 100644 --- a/lib/includes/gnutls/gnutls.h.in +++ b/lib/includes/gnutls/gnutls.h.in @@ -284,12 +284,14 @@ extern "C" * @GNUTLS_SERVER: Connection end is a server. * @GNUTLS_CLIENT: Connection end is a client. * @GNUTLS_DATAGRAM: Connection is datagram oriented (DTLS). + * @GNUTLS_NONBLOCK: Connection should not block (DTLS). * * Enumeration of different TLS connection end types. */ #define GNUTLS_SERVER 1 #define GNUTLS_CLIENT (1<<1) #define GNUTLS_DATAGRAM (1<<2) +#define GNUTLS_NONBLOCK (1<<3) /** * gnutls_alert_level_t: diff --git a/lib/system.h b/lib/system.h index b1f556557a..849090ee3a 100644 --- a/lib/system.h +++ b/lib/system.h @@ -4,7 +4,9 @@ #include <gnutls_int.h> #ifndef _WIN32 -#include <sys/uio.h> /* for writev */ +# include <sys/uio.h> /* for writev */ +#else +# include <windows.h> /* for Sleep */ #endif int system_errno (gnutls_transport_ptr_t); @@ -35,4 +37,17 @@ ssize_t system_read_peek (gnutls_transport_ptr_t ptr, void *data, int _gnutls_atfork (void (*prepare) (void), void (*parent) (void), void (*child) (void)); +static inline void millisleep(unsigned int ms) +{ +#ifdef _WIN32 + Sleep(ms); +#else +struct timespec ts; + ts.tv_sec = 0; + ts.tv_nsec = ms*1000*1000; + + nanosleep(&ts, NULL); +#endif +} + #endif /* SYSTEM_H */ diff --git a/tests/Makefile.am b/tests/Makefile.am index 2d5e2d4d23..cef6bd66ec 100644 --- a/tests/Makefile.am +++ b/tests/Makefile.am @@ -27,7 +27,7 @@ if ENABLE_OPENPGP SUBDIRS += openpgp-certs endif -EXTRA_DIST = libgcrypt.supp +EXTRA_DIST = libgcrypt.supp eagain-common.h AM_CFLAGS = $(WARN_CFLAGS) $(WERROR_CFLAGS) AM_CPPFLAGS = \ @@ -60,7 +60,7 @@ ctests = simple gc set_pkcs12_cred certder certuniqueid mpi \ crq_key_id x509sign-verify cve-2009-1415 cve-2009-1416 \ crq_apis init_roundtrip pkcs12_s2k_pem dn2 mini-eagain \ nul-in-x509-names x509_altname pkcs12_encode mini-x509 \ - mini-x509-rehandshake rng-fork #gendh + mini-x509-rehandshake rng-fork mini-eagain-dtls #gendh if ENABLE_OPENSSL ctests += openssl diff --git a/tests/eagain-common.h b/tests/eagain-common.h new file mode 100644 index 0000000000..5fb436e453 --- /dev/null +++ b/tests/eagain-common.h @@ -0,0 +1,144 @@ +#define min(x,y) ((x)<(y)?(x):(y)) +//#define EAGAIN_DEBUG +#define RANDOMIZE + +static char to_server[64*1024]; +static size_t to_server_len = 0; + +static char to_client[64*1024]; +static size_t to_client_len = 0; + +#ifdef RANDOMIZE +#define RETURN_RND_EAGAIN() \ + static unsigned char rnd = 0; \ + if (rnd++ % 2 == 0) \ + { \ + gnutls_transport_set_global_errno (EAGAIN); \ + return -1; \ + } +#else +#define RETURN_RND_EAGAIN() +#endif + +static ssize_t +client_push (gnutls_transport_ptr_t tr, const void *data, size_t len) +{ + size_t newlen; + RETURN_RND_EAGAIN(); + + len = min(len, sizeof(to_server)-to_server_len); + + newlen = to_server_len + len; + memcpy (to_server + to_server_len, data, len); + to_server_len = newlen; +#ifdef EAGAIN_DEBUG + fprintf(stderr, "eagain: pushed %d bytes to server (avail: %d)\n", (int)len, (int)to_server_len); +#endif + return len; +} + +static ssize_t +client_pull (gnutls_transport_ptr_t tr, void *data, size_t len) +{ + RETURN_RND_EAGAIN(); + + if (to_client_len == 0) + { +#ifdef EAGAIN_DEBUG + fprintf(stderr, "eagain: Not enough data by server (asked for: %d, have: %d)\n", (int)len, (int)to_client_len); +#endif + gnutls_transport_set_global_errno (EAGAIN); + return -1; + } + + len = min(len, to_client_len); + + memcpy (data, to_client, len); + + memmove (to_client, to_client + len, to_client_len - len); + to_client_len -= len; +#ifdef EAGAIN_DEBUG + fprintf(stderr, "eagain: pulled %d bytes by client (avail: %d)\n", (int)len, (int)to_client_len); +#endif + return len; +} + +static ssize_t +server_pull (gnutls_transport_ptr_t tr, void *data, size_t len) +{ + //success ("server_pull len %d has %d\n", len, to_server_len); + RETURN_RND_EAGAIN(); + + if (to_server_len == 0) + { +#ifdef EAGAIN_DEBUG + fprintf(stderr, "eagain: Not enough data by client (asked for: %d, have: %d)\n", (int)len, (int)to_server_len); +#endif + gnutls_transport_set_global_errno (EAGAIN); + return -1; + } + + len = min(len, to_server_len); +#ifdef EAGAIN_DEBUG + fprintf(stderr, "eagain: pulled %d bytes by server (avail: %d)\n", (int)len, (int)to_server_len); +#endif + memcpy (data, to_server, len); + + memmove (to_server, to_server + len, to_server_len - len); + to_server_len -= len; + + return len; +} + +static ssize_t +server_push (gnutls_transport_ptr_t tr, const void *data, size_t len) +{ + size_t newlen; + RETURN_RND_EAGAIN(); + +// hexprint (data, len); + + len = min(len, sizeof(to_client)-to_client_len); + + newlen = to_client_len + len; + memcpy (to_client + to_client_len, data, len); + to_client_len = newlen; +#ifdef EAGAIN_DEBUG + fprintf(stderr, "eagain: pushed %d bytes to client (avail: %d)\n", (int)len, (int)to_client_len); +#endif + + return len; +} + +/* inline is used to avoid a gcc warning if used in mini-eagain */ +inline static int server_pull_timeout_func(gnutls_transport_ptr_t ptr, unsigned int ms) +{ +int ret; + + if (to_server_len > 0) + ret = 1; /* available data */ + else + ret = 0; /* timeout */ + +#ifdef EAGAIN_DEBUG + fprintf(stderr, "eagain: server_pull_timeout: %d\n", ret); +#endif + + return ret; +} + +inline static int client_pull_timeout_func(gnutls_transport_ptr_t ptr, unsigned int ms) +{ +int ret; + + if (to_client_len > 0) + ret = 1; + else + ret = 0; + +#ifdef EAGAIN_DEBUG + fprintf(stderr, "eagain: client_pull_timeout: %d\n", ret); +#endif + + return ret; +} diff --git a/tests/mini-eagain-dtls.c b/tests/mini-eagain-dtls.c new file mode 100644 index 0000000000..0b3ed4791d --- /dev/null +++ b/tests/mini-eagain-dtls.c @@ -0,0 +1,219 @@ +/* + * Copyright (C) 2008, 2010 Free Software Foundation, Inc. + * + * Author: Simon Josefsson, 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 <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <errno.h> +#include <gnutls/gnutls.h> +#include <gnutls/crypto.h> +#include "utils.h" +#include "eagain-common.h" + +static void +tls_log_func (int level, const char *str) +{ + fprintf (stderr, "|<%d>| %s", level, str); +} + +static int handshake = 0; + +#define MAX_BUF 1024 +#define MSG "Hello TLS, and hi and how are you and more data here... and more... and even more and even more more data..." + +void +doit (void) +{ + /* Server stuff. */ + gnutls_anon_server_credentials_t s_anoncred; + const gnutls_datum_t p3 = { (char *) pkcs3, strlen (pkcs3) }; + static gnutls_dh_params_t dh_params; + gnutls_session_t server; + int sret, cret; + /* Client stuff. */ + gnutls_anon_client_credentials_t c_anoncred; + gnutls_session_t client; + /* Need to enable anonymous KX specifically. */ + char buffer[MAX_BUF + 1]; + ssize_t ns; + int ret, transferred = 0, msglen; + + /* General init. */ + gnutls_global_init (); + gnutls_global_set_log_function (tls_log_func); + if (debug) + gnutls_global_set_log_level (99); + + /* Init server */ + gnutls_anon_allocate_server_credentials (&s_anoncred); + gnutls_dh_params_init (&dh_params); + gnutls_dh_params_import_pkcs3 (dh_params, &p3, GNUTLS_X509_FMT_PEM); + gnutls_anon_set_server_dh_params (s_anoncred, dh_params); + gnutls_init (&server, GNUTLS_SERVER|GNUTLS_DATAGRAM|GNUTLS_NONBLOCK); + ret = gnutls_priority_set_direct (server, "NONE:+VERS-DTLS1.0:+CIPHER-ALL:+MAC-ALL:+SIGN-ALL:+COMP-ALL:+ANON-DH", NULL); + if (ret < 0) + exit(1); + gnutls_credentials_set (server, GNUTLS_CRD_ANON, s_anoncred); + gnutls_dh_set_prime_bits (server, 1024); + 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); + + /* Init client */ + gnutls_anon_allocate_client_credentials (&c_anoncred); + gnutls_init (&client, GNUTLS_CLIENT|GNUTLS_DATAGRAM|GNUTLS_NONBLOCK); + cret = gnutls_priority_set_direct (client, "NONE:+VERS-DTLS1.0:+CIPHER-ALL:+MAC-ALL:+SIGN-ALL:+COMP-ALL:+ANON-DH", NULL); + if (cret < 0) + exit(1); + gnutls_credentials_set (client, GNUTLS_CRD_ANON, c_anoncred); + 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); + + handshake = 1; + sret = cret = GNUTLS_E_AGAIN; + do + { + if (cret == GNUTLS_E_AGAIN) + { + //success ("loop invoking client:\n"); + cret = gnutls_handshake (client); + //success ("client %d: %s\n", cret, gnutls_strerror (cret)); + } + + if (sret == GNUTLS_E_AGAIN) + { + //success ("loop invoking server:\n"); + sret = gnutls_handshake (server); + //success ("server %d: %s\n", sret, gnutls_strerror (sret)); + } + } + while ((cret == GNUTLS_E_AGAIN && gnutls_error_is_fatal(sret)==0) || (sret == GNUTLS_E_AGAIN && gnutls_error_is_fatal(cret)==0)); + + if (cret < 0 || sret < 0) + { + fprintf(stderr, "client: %s\n", gnutls_strerror(cret)); + fprintf(stderr, "server: %s\n", gnutls_strerror(sret)); + fail("Handshake failed\n"); + exit(1); + } + + handshake = 0; + if (debug) + success ("Handshake established\n"); + + do + { + ret = gnutls_record_send (client, MSG, strlen (MSG)); + } + while(ret == GNUTLS_E_AGAIN); + //success ("client: sent %d\n", ns); + + do + { + //success("transferred: %d\n", transferred); + + do + { + ret = gnutls_record_recv (server, buffer, MAX_BUF); + } + while(ret == GNUTLS_E_AGAIN); + + if (ret == 0) + fail ("server: didn't receive any data\n"); + else if (ret < 0) + { + // if (debug) + // fputs ("#", stdout); + fail ("server: error: %s\n", gnutls_strerror (ret)); + } + else + { + transferred += ret; + // if (debug) + // fputs ("*", stdout); + } + + msglen = strlen (MSG); + do + { + ns = gnutls_record_send (server, MSG, msglen); + } + while (ns == GNUTLS_E_AGAIN); + + do + { + ret = gnutls_record_recv (client, buffer, MAX_BUF); + } + while(ret == GNUTLS_E_AGAIN); + + + if (ret == 0) + { + fail ("client: Peer has closed the TLS connection\n"); + } + else if (ret < 0) + { + if (debug) + fputs ("!", stdout); + fail ("client: Error: %s\n", gnutls_strerror (ret)); + } + else + { + if (msglen != ret || memcmp (buffer, MSG, msglen) != 0) + { + fail ("client: Transmitted data do not match\n"); + } + + /* echo back */ + do + { + ns = gnutls_record_send (client, buffer, msglen); + } + while (ns == GNUTLS_E_AGAIN); + + transferred += ret; + if (debug) + fputs (".", stdout); + } + } + while (transferred < 70000); + if (debug) + fputs ("\n", stdout); + + gnutls_bye (client, GNUTLS_SHUT_WR); + gnutls_bye (server, GNUTLS_SHUT_WR); + + gnutls_deinit (client); + gnutls_deinit (server); + + gnutls_anon_free_client_credentials (c_anoncred); + gnutls_anon_free_server_credentials (s_anoncred); + + gnutls_dh_params_deinit (dh_params); + + gnutls_global_deinit (); +} diff --git a/tests/mini-eagain.c b/tests/mini-eagain.c index 9bb7e2c321..3b2ea2951c 100644 --- a/tests/mini-eagain.c +++ b/tests/mini-eagain.c @@ -32,6 +32,7 @@ #include <gnutls/crypto.h> #include "utils.h" +#include "eagain-common.h" static void tls_log_func (int level, const char *str) @@ -41,109 +42,6 @@ tls_log_func (int level, const char *str) static int handshake = 0; -char *to_server; -size_t to_server_len; - -char *to_client; -size_t to_client_len; - - -static ssize_t -client_pull (gnutls_transport_ptr_t tr, void *data, size_t len) -{ -// success ("client_pull len %d has %d\n", len, to_client_len); - static unsigned char rnd = 0; - - if (rnd++ % 2 == 0 || to_client_len < len) - { - gnutls_transport_set_global_errno (EAGAIN); - return -1; - } - - memcpy (data, to_client, len); - - memmove (to_client, to_client + len, to_client_len - len); - to_client_len -= len; - - return len; -} - -static ssize_t -client_push (gnutls_transport_ptr_t tr, const void *data, size_t len) -{ - char *tmp; - size_t newlen = to_server_len + len; - static unsigned char rnd = 0; - - if (rnd++ % 2 == 0) - { - gnutls_transport_set_global_errno (EAGAIN); - return -1; - } - - tmp = realloc (to_server, newlen); - if (!tmp) - { - fail ("Memory allocation failure...\n"); - exit (1); - } - to_server = tmp; - - memcpy (to_server + to_server_len, data, len); - to_server_len = newlen; - - return len; -} - -static ssize_t -server_pull (gnutls_transport_ptr_t tr, void *data, size_t len) -{ - //success ("server_pull len %d has %d\n", len, to_server_len); - static unsigned char rnd = 0; - - if (rnd++ % 2 == 0 || to_server_len < len) - { - gnutls_transport_set_global_errno (EAGAIN); - return -1; - } - - memcpy (data, to_server, len); - - memmove (to_server, to_server + len, to_server_len - len); - to_server_len -= len; - - return len; -} - -static ssize_t -server_push (gnutls_transport_ptr_t tr, const void *data, size_t len) -{ - char *tmp; - size_t newlen = to_client_len + len; - static unsigned char rnd = 0; - - if (rnd++ % 2 == 0) - { - gnutls_transport_set_global_errno (EAGAIN); - return -1; - } - -// hexprint (data, len); - - tmp = realloc (to_client, newlen); - if (!tmp) - { - fail ("Memory allocation failure...\n"); - exit (1); - } - to_client = tmp; - - memcpy (to_client + to_client_len, data, len); - to_client_len = newlen; - - return len; -} - #define MAX_BUF 1024 #define MSG "Hello TLS, and hi and how are you and more data here... and more... and even more and even more more data..." @@ -155,11 +53,10 @@ doit (void) const gnutls_datum_t p3 = { (char *) pkcs3, strlen (pkcs3) }; static gnutls_dh_params_t dh_params; gnutls_session_t server; - int sret = GNUTLS_E_AGAIN; + int sret, cret; /* Client stuff. */ gnutls_anon_client_credentials_t c_anoncred; gnutls_session_t client; - int cret = GNUTLS_E_AGAIN; /* Need to enable anonymous KX specifically. */ char buffer[MAX_BUF + 1]; ssize_t ns; @@ -169,7 +66,7 @@ doit (void) gnutls_global_init (); gnutls_global_set_log_function (tls_log_func); if (debug) - gnutls_global_set_log_level (99); + gnutls_global_set_log_level (2); /* Init server */ gnutls_anon_allocate_server_credentials (&s_anoncred); @@ -177,7 +74,9 @@ doit (void) gnutls_dh_params_import_pkcs3 (dh_params, &p3, GNUTLS_X509_FMT_PEM); gnutls_anon_set_server_dh_params (s_anoncred, dh_params); gnutls_init (&server, GNUTLS_SERVER); - gnutls_priority_set_direct (server, "NONE:+VERS-TLS-ALL:+CIPHER-ALL:+MAC-ALL:+SIGN-ALL:+COMP-ALL:+ANON-DH", NULL); + ret = gnutls_priority_set_direct (server, "NONE:+VERS-TLS-ALL:+CIPHER-ALL:+MAC-ALL:+SIGN-ALL:+COMP-ALL:+ANON-DH", NULL); + if (ret < 0) + exit(1); gnutls_credentials_set (server, GNUTLS_CRD_ANON, s_anoncred); gnutls_dh_set_prime_bits (server, 1024); gnutls_transport_set_push_function (server, server_push); @@ -186,12 +85,15 @@ doit (void) /* Init client */ gnutls_anon_allocate_client_credentials (&c_anoncred); gnutls_init (&client, GNUTLS_CLIENT); - gnutls_priority_set_direct (client, "NONE:+VERS-TLS-ALL:+CIPHER-ALL:+MAC-ALL:+SIGN-ALL:+COMP-ALL:+ANON-DH", NULL); + ret = gnutls_priority_set_direct (client, "NONE:+VERS-TLS-ALL:+CIPHER-ALL:+MAC-ALL:+SIGN-ALL:+COMP-ALL:+ANON-DH", NULL); + if (ret < 0) + exit(1); gnutls_credentials_set (client, GNUTLS_CRD_ANON, c_anoncred); gnutls_transport_set_push_function (client, client_push); gnutls_transport_set_pull_function (client, client_pull); handshake = 1; + sret = cret = GNUTLS_E_AGAIN; do { if (cret == GNUTLS_E_AGAIN) @@ -210,35 +112,48 @@ doit (void) } while (cret == GNUTLS_E_AGAIN || sret == GNUTLS_E_AGAIN); + if (cret < 0 || sret < 0) + { + fprintf(stderr, "client: %s\n", gnutls_strerror(cret)); + fprintf(stderr, "server: %s\n", gnutls_strerror(sret)); + fail("Handshake failed\n"); + exit(1); + } + handshake = 0; if (debug) success ("Handshake established\n"); - ns = gnutls_record_send (client, MSG, strlen (MSG)); + do + { + ret = gnutls_record_send (client, MSG, strlen (MSG)); + } + while(ret == GNUTLS_E_AGAIN); //success ("client: sent %d\n", ns); do { //success("transferred: %d\n", transferred); - ret = gnutls_record_recv (server, buffer, MAX_BUF); + do + { + ret = gnutls_record_recv (server, buffer, MAX_BUF); + } + while(ret == GNUTLS_E_AGAIN); + if (ret == 0) fail ("server: didn't receive any data\n"); else if (ret < 0) { -// if (debug) -// fputs ("#", stdout); - if (ret != GNUTLS_E_AGAIN) - { - fail ("server: error: %s\n", gnutls_strerror (ret)); - break; - } + // if (debug) + // fputs ("#", stdout); + fail ("server: error: %s\n", gnutls_strerror (ret)); } else { transferred += ret; -// if (debug) -// fputs ("*", stdout); + // if (debug) + // fputs ("*", stdout); } msglen = strlen (MSG); @@ -248,7 +163,12 @@ doit (void) } while (ns == GNUTLS_E_AGAIN); - ret = gnutls_record_recv (client, buffer, MAX_BUF); + do + { + ret = gnutls_record_recv (client, buffer, MAX_BUF); + } + while(ret == GNUTLS_E_AGAIN); + if (ret == 0) { fail ("client: Peer has closed the TLS connection\n"); @@ -257,11 +177,7 @@ doit (void) { if (debug) fputs ("!", stdout); - if (ret != GNUTLS_E_AGAIN) - { - fail ("client: Error: %s\n", gnutls_strerror (ret)); - break; - } + fail ("client: Error: %s\n", gnutls_strerror (ret)); } else { @@ -292,9 +208,6 @@ doit (void) gnutls_deinit (client); gnutls_deinit (server); - free (to_server); - free (to_client); - gnutls_anon_free_client_credentials (c_anoncred); gnutls_anon_free_server_credentials (s_anoncred); diff --git a/tests/utils.c b/tests/utils.c index 105869c903..c8ed85357f 100644 --- a/tests/utils.c +++ b/tests/utils.c @@ -60,7 +60,7 @@ success (const char *format, ...) va_list arg_ptr; va_start (arg_ptr, format); - vfprintf (stdout, format, arg_ptr); + vfprintf (stderr, format, arg_ptr); va_end (arg_ptr); } |