diff options
author | Nikos Mavrogiannopoulos <nmav@gnutls.org> | 2009-07-01 21:50:27 +0300 |
---|---|---|
committer | Nikos Mavrogiannopoulos <nmav@gnutls.org> | 2009-07-01 21:58:45 +0300 |
commit | 90bff7862c48c9a628e797b62ee9de6f34e0601f (patch) | |
tree | c6210f382634ccc35be308813f1606fe729a14b7 | |
parent | e8ab162c408fd921e730e60170643bda03ba1d62 (diff) | |
download | gnutls-90bff7862c48c9a628e797b62ee9de6f34e0601f.tar.gz |
Added bug fix that allows gnutls_record_recv/send resuming from previously interrupted
actions. Patch by from Tim Kosse <tim.kosse@filezilla-project.org>.
Added a self test to check those functions in handling interrupted states.
-rw-r--r-- | lib/gnutls_buffers.c | 4 | ||||
-rw-r--r-- | tests/Makefile.am | 2 | ||||
-rw-r--r-- | tests/mini-eagain.c | 300 |
3 files changed, 303 insertions, 3 deletions
diff --git a/lib/gnutls_buffers.c b/lib/gnutls_buffers.c index 0b94f6f173..a008e3f13b 100644 --- a/lib/gnutls_buffers.c +++ b/lib/gnutls_buffers.c @@ -657,7 +657,7 @@ _gnutls_io_write_buffered (gnutls_session_t session, { gnutls_datum bdata; /* checking is handled above */ - _gnutls_buffer_get_datum (&session->internals.record_send_buffer, &bdata, n); + _gnutls_buffer_get_datum (&session->internals.record_send_buffer, &bdata, session->internals.record_send_buffer.length); ptr = bdata.data; n = bdata.size; @@ -854,7 +854,7 @@ _gnutls_handshake_io_send_int (gnutls_session_t session, gnutls_assert (); /* checking is handled above */ - _gnutls_buffer_get_datum (&session->internals.handshake_send_buffer, &bdata, n); + _gnutls_buffer_get_datum (&session->internals.handshake_send_buffer, &bdata, session->internals.handshake_send_buffer.length); ptr = bdata.data; n = bdata.size; diff --git a/tests/Makefile.am b/tests/Makefile.am index 0b09cc80de..382c5fbdb0 100644 --- a/tests/Makefile.am +++ b/tests/Makefile.am @@ -56,7 +56,7 @@ libutils_la_SOURCES = utils.h utils.c ctests = simple gc set_pkcs12_cred certder mpi \ certificate_set_x509_crl dn parse_ca moredn crypto_rng mini \ finished hostname-check cve-2008-4989 pkcs12_s2k chainverify \ - crq_key_id x509sign-verify cve-2009-1415 cve-2009-1416 + crq_key_id x509sign-verify cve-2009-1415 cve-2009-1416 mini-eagain if ENABLE_OPENSSL ctests += openssl diff --git a/tests/mini-eagain.c b/tests/mini-eagain.c new file mode 100644 index 0000000000..d9fdee08c4 --- /dev/null +++ b/tests/mini-eagain.c @@ -0,0 +1,300 @@ +/* + * Copyright (C) 2008 Free Software Foundation + * + * Author: Simon Josefsson + * + * 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 "utils.h" + +static void +tls_log_func (int level, const char *str) +{ + fprintf (stderr, "|<%d>| %s", level, 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); + unsigned char rnd; + gcry_create_nonce (&rnd, 1); + + if (handshake == 0 && rnd % 2 == 0) + { + gnutls_transport_set_global_errno (EAGAIN); + return -1; + } + + if (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) +{ + unsigned char rnd; + char *tmp; + +#if 0 + gcry_create_nonce (&rnd, 1); + if (handshake == 0 && rnd % 2 == 0) + { + gnutls_transport_set_global_errno (EAGAIN); + return -1; + } +#endif + size_t newlen = to_server_len + len; +// success ("client_push len %d has %d\n", len, to_server_len); +// hexprint (data, len); + + 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); + unsigned char rnd; + + gcry_create_nonce (&rnd, 1); + if (handshake == 0 && rnd % 2 == 0) + { + gnutls_transport_set_global_errno (EAGAIN); + return -1; + } + + if (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) +{ + unsigned char rnd; + char *tmp; + + //success ("server_push len %d has %d\n", len, to_client_len); + gcry_create_nonce (&rnd, 1); + if (handshake == 0 && rnd % 2 == 0) + { + gnutls_transport_set_global_errno (EAGAIN); + return -1; + } + + size_t newlen = to_client_len + len; +// 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" + +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 = GNUTLS_E_AGAIN; + /* Client stuff. */ + gnutls_anon_client_credentials_t c_anoncred; + gnutls_session_t client; + int n, cret = GNUTLS_E_AGAIN; + /* Need to enable anonymous KX specifically. */ + const int kx_prio[] = { GNUTLS_KX_ANON_DH, 0 }; + char buffer[MAX_BUF + 1]; + ssize_t ns; + int ret, transferred = 0; + + /* 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_set_default_priority (server); + gnutls_kx_set_priority (server, kx_prio); + 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); + + /* Init client */ + gnutls_anon_allocate_client_credentials (&c_anoncred); + gnutls_init (&client, GNUTLS_CLIENT); + gnutls_set_default_priority (client); + gnutls_kx_set_priority (client, kx_prio); + 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; + 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 || sret == GNUTLS_E_AGAIN); + handshake = 0; + success ("Handshake established\n"); + + ns = gnutls_record_send (client, MSG, strlen (MSG)); + //success ("client: sent %d\n", ns); + + do + { + //success("transferred: %d\n", transferred); + + ret = gnutls_record_recv (server, buffer, MAX_BUF); + if (ret == 0) + fail ("server: didn't receive any data\n"); + else if (ret < 0) + { + if (ret != GNUTLS_E_AGAIN) { + fail ("server: error: %s\n", gnutls_strerror (ret)); + break; + } + } + else + { + transferred+=ret; + fputs ("*", stdout); + } + + ns = gnutls_record_send (server, MSG, strlen (MSG)); + //success ("server: sent %d\n", ns); + + ret = gnutls_record_recv (client, buffer, MAX_BUF); + if (ret == 0) + { + fail ("client: Peer has closed the TLS connection\n"); + } + else if (ret < 0) + { + if (ret != GNUTLS_E_AGAIN) { + fail ("client: Error: %s\n", gnutls_strerror (ret)); + break; + } + } + else + { + transferred+=ret; + fputs (".", stdout); + } + } + while (transferred < 55000); + fputs ("\n", stdout); + + gnutls_bye (client, GNUTLS_SHUT_RDWR); + gnutls_bye (server, GNUTLS_SHUT_RDWR); + + 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); + + gnutls_dh_params_deinit (dh_params); + + gnutls_global_deinit (); +} |