diff options
author | Simon Josefsson <simon@josefsson.org> | 2007-09-20 14:52:39 +0200 |
---|---|---|
committer | Simon Josefsson <simon@josefsson.org> | 2007-09-20 14:52:39 +0200 |
commit | bdcd70e2b483f15189855cf966d96759686555a1 (patch) | |
tree | 495c4d558b82c8ec266980e9c3f56f82d773e200 | |
parent | 15688b6cb74ad0a89b90a536db0771fc89eb3685 (diff) | |
download | gnutls-bdcd70e2b483f15189855cf966d96759686555a1.tar.gz |
Support for Opaque PRF Input TLS extension.
-rw-r--r-- | NEWS | 2 | ||||
-rw-r--r-- | configure.in | 23 | ||||
-rw-r--r-- | doc/gnutls.texi | 14 | ||||
-rw-r--r-- | includes/gnutls/gnutls.h.in | 20 | ||||
-rw-r--r-- | lib/Makefile.am | 6 | ||||
-rw-r--r-- | lib/ext_oprfi.c | 227 | ||||
-rw-r--r-- | lib/ext_oprfi.h | 33 | ||||
-rw-r--r-- | lib/gnutls_extensions.c | 6 | ||||
-rw-r--r-- | lib/gnutls_int.h | 11 | ||||
-rw-r--r-- | lib/gnutls_kx.c | 72 | ||||
-rw-r--r-- | tests/Makefile.am | 3 | ||||
-rw-r--r-- | tests/oprfi.c | 410 |
12 files changed, 821 insertions, 6 deletions
@@ -5,6 +5,8 @@ See the end for copying conditions. * Version 2.1.0 (unreleased) +** Support for draft-rescorla-tls-opaque-prf-input-00.txt. + ** Example code: Fix compilation flaw under MinGW. ** API and ABI modifications: diff --git a/configure.in b/configure.in index d9d3a3c4b7..ad23d965d9 100644 --- a/configure.in +++ b/configure.in @@ -368,6 +368,29 @@ AC_ARG_WITH(builtin-crypto, ac_cv_libgcrypt=yes) LTLIBGCRYPT=$LIBGCRYPT_LIBS +AC_MSG_CHECKING([whether to enable Opaque PRF input support]) +AC_ARG_ENABLE(opaque-prf-input, + AS_HELP_STRING([--enable-opaque-prf-input=DD], + [enable Opaque PRF input using DD as extension type]), + ac_opaque_prf_input=$enableval, ac_opaque_prf_input=no) +if test "$ac_opaque_prf_input" != "no"; then + if ! echo $ac_opaque_prf_input | egrep -q '^[[0-9]]+$'; then + ac_opaque_prf_input=no + AC_MSG_WARN([[ +*** Could not parse Opaque PRF Input extension type. +*** Use --enable-opaque-prf-input=XX where XX is decimal, for example +*** to use extension value 42 use --enable-opqaue-prf-input=42]]) + fi +fi +if test "$ac_opaque_prf_input" != "no"; then + AC_MSG_RESULT([yes (extension value $ac_opaque_prf_input)]) + AC_DEFINE_UNQUOTED(ENABLE_OPRFI, $ac_opaque_prf_input, + [enable Opaque PRF Input]) +else + AC_MSG_RESULT(no) +fi +AM_CONDITIONAL(ENABLE_OPRFI, test "$ac_opaque_prf_input" != "no") + AC_MSG_CHECKING([whether to disable SRP authentication support]) AC_ARG_ENABLE(srp-authentication, AS_HELP_STRING([--disable-srp-authentication], diff --git a/doc/gnutls.texi b/doc/gnutls.texi index 39aee0f21d..f2ba8f3ad5 100644 --- a/doc/gnutls.texi +++ b/doc/gnutls.texi @@ -2399,6 +2399,20 @@ Current limitations imposed by the compatibility layer include: @end itemize +@node Support for Opaque PRF Input extension +@section Support for Opaque PRF Input extension +@cindex Opaque PRF Input + +GnuTLS supports the Opaque PRF Input TLS extension +(@code{draft-rescorla-tls-opaque-prf-input-00.txt}). The API consists +of one API for use in the client, @ref{gnutls_oprfi_enable_client}, +and one API for use in the server, @ref{gnutls_oprfi_enable_server}. +You must invoke both functions before calling @ref{gnutls_handshake}. +The server utilizes a callback function into the application. The +callback can look at the random string provided by the client, and +also set the server string. The string lengths must be equal +according to the protocol. + @node Included programs @chapter Included Programs diff --git a/includes/gnutls/gnutls.h.in b/includes/gnutls/gnutls.h.in index e448a03ebd..3889d09eff 100644 --- a/includes/gnutls/gnutls.h.in +++ b/includes/gnutls/gnutls.h.in @@ -448,6 +448,26 @@ extern "C" void *data, size_t * data_length, unsigned int *type, unsigned int indx); + /* Opaque PRF Input + * http://tools.ietf.org/id/draft-rescorla-tls-opaque-prf-input-00.txt + */ + + void + gnutls_oprfi_enable_client (gnutls_session_t session, + size_t len, + unsigned char *data); + + typedef int (*gnutls_oprfi_callback_func) (gnutls_session_t session, + void *userdata, + size_t oprfi_len, + const unsigned char *in_oprfi, + unsigned char *out_oprfi); + + void + gnutls_oprfi_enable_server (gnutls_session_t session, + gnutls_oprfi_callback_func cb, + void *userdata); + /* Supplemental data, RFC 4680. */ typedef enum { diff --git a/lib/Makefile.am b/lib/Makefile.am index b20abb621d..50c83e31a3 100644 --- a/lib/Makefile.am +++ b/lib/Makefile.am @@ -80,6 +80,10 @@ if ENABLE_AUTHZ COBJECTS += ext_authz.c endif +if ENABLE_OPRFI +COBJECTS += ext_oprfi.c +endif + HFILES = debug.h gnutls_compress.h defines.h gnutls_cipher.h \ gnutls_buffers.h gnutls_errors.h gnutls_int.h \ gnutls_handshake.h gnutls_num.h gnutls_algorithms.h \ @@ -95,7 +99,7 @@ HFILES = debug.h gnutls_compress.h defines.h gnutls_cipher.h \ ext_srp.h gnutls_srp.h auth_srp.h auth_srp_passwd.h \ gnutls_helper.h auth_psk.h auth_psk_passwd.h \ ext_inner_application.h gnutls_extra_hooks.h \ - gnutls_supplemental.h ext_authz.h + gnutls_supplemental.h ext_authz.h ext_oprfi.h # Separate so we can create the documentation diff --git a/lib/ext_oprfi.c b/lib/ext_oprfi.c new file mode 100644 index 0000000000..9741641e5e --- /dev/null +++ b/lib/ext_oprfi.c @@ -0,0 +1,227 @@ +/* + * Copyright (C) 2007 Free Software Foundation + * + * Author: Simon Josefsson + * + * This file is part of GNUTLS. + * + * The GNUTLS library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public License + * as published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, + * USA + * + */ + +/* Implementation of Opaque PRF Input: + * http://tools.ietf.org/id/draft-rescorla-tls-opaque-prf-input-00.txt + * + */ + +#include <ext_oprfi.h> + +#include <gnutls_errors.h> +#include <gnutls_num.h> + +int +oprfi_recv_server (gnutls_session_t session, + const opaque * data, + size_t _data_size) +{ + ssize_t data_size = _data_size; + uint16_t len; + int ret; + + if (!session->security_parameters.extensions.oprfi_cb) + { + gnutls_assert (); + return 0; + } + + DECR_LEN (data_size, 2); + len = _gnutls_read_uint16 (data); + data += 2; + + if (len != data_size) + { + gnutls_assert (); + return GNUTLS_E_UNEXPECTED_PACKET_LENGTH; + } + + /* Store incoming data. */ + session->security_parameters.extensions.oprfi_client_len = len; + session->security_parameters.extensions.oprfi_client = gnutls_malloc (len); + if (!session->security_parameters.extensions.oprfi_client) + { + gnutls_assert (); + return GNUTLS_E_MEMORY_ERROR; + } + memcpy (session->security_parameters.extensions.oprfi_client, data, len); + + return 0; +} + +int +oprfi_recv_client (gnutls_session_t session, + const opaque * data, + size_t _data_size) +{ + ssize_t data_size = _data_size; + uint16_t len; + int ret; + + if (session->security_parameters.extensions.oprfi_client == NULL) + { + gnutls_assert (); + return 0; + } + + DECR_LEN (data_size, 2); + len = _gnutls_read_uint16 (data); + data += 2; + + if (len != data_size) + { + gnutls_assert (); + return GNUTLS_E_UNEXPECTED_PACKET_LENGTH; + } + + if (len != session->security_parameters.extensions.oprfi_client_len) + { + gnutls_assert (); + return GNUTLS_E_RECEIVED_ILLEGAL_PARAMETER; + } + + /* Store incoming data. */ + session->security_parameters.extensions.oprfi_server_len = len; + session->security_parameters.extensions.oprfi_server = gnutls_malloc (len); + if (!session->security_parameters.extensions.oprfi_server) + { + gnutls_assert (); + return GNUTLS_E_MEMORY_ERROR; + } + memcpy (session->security_parameters.extensions.oprfi_server, data, len); + + return 0; +} + +int +_gnutls_oprfi_recv_params (gnutls_session_t session, + const opaque * data, + size_t data_size) +{ + if (session->security_parameters.entity == GNUTLS_CLIENT) + return oprfi_recv_client (session, data, data_size); + else + return oprfi_recv_server (session, data, data_size); +} + +int +oprfi_send_client (gnutls_session_t session, + opaque * data, + size_t _data_size) +{ + opaque *p = data; + ssize_t data_size = _data_size; + int oprf_size = session->security_parameters.extensions.oprfi_client_len; + + if (oprf_size == 0) + return 0; + + DECR_LENGTH_RET (data_size, 2, GNUTLS_E_SHORT_MEMORY_BUFFER); + _gnutls_write_uint16 (oprf_size, p); + p += 2; + + DECR_LENGTH_RET (data_size, oprf_size, GNUTLS_E_SHORT_MEMORY_BUFFER); + + memcpy (p, session->security_parameters.extensions.oprfi_client, oprf_size); + + return 2 + oprf_size; +} + +int +oprfi_send_server (gnutls_session_t session, + opaque * data, + size_t _data_size) +{ + opaque *p = data; + int ret; + ssize_t data_size = _data_size; + size_t len; + + /* Allocate buffer for outgoing data. */ + session->security_parameters.extensions.oprfi_server_len = + session->security_parameters.extensions.oprfi_client_len; + session->security_parameters.extensions.oprfi_server = + gnutls_malloc (session->security_parameters.extensions.oprfi_server_len); + if (!session->security_parameters.extensions.oprfi_server) + { + gnutls_assert (); + return GNUTLS_E_MEMORY_ERROR; + } + + /* Get outgoing data. */ + ret = session->security_parameters.extensions.oprfi_cb + (session, session->security_parameters.extensions.oprfi_userdata, + session->security_parameters.extensions.oprfi_client_len, + session->security_parameters.extensions.oprfi_client, + session->security_parameters.extensions.oprfi_server); + if (ret < 0) + { + gnutls_assert (); + gnutls_free (session->security_parameters.extensions.oprfi_server); + return ret; + } + + DECR_LENGTH_RET (data_size, 2, GNUTLS_E_SHORT_MEMORY_BUFFER); + _gnutls_write_uint16 (session->security_parameters. + extensions.oprfi_server_len, p); + p += 2; + + DECR_LENGTH_RET (data_size, session->security_parameters. + extensions.oprfi_server_len, GNUTLS_E_SHORT_MEMORY_BUFFER); + + memcpy (p, session->security_parameters.extensions.oprfi_server, + session->security_parameters.extensions.oprfi_server_len); + + return 2 + session->security_parameters.extensions.oprfi_server_len; +} + +int +_gnutls_oprfi_send_params (gnutls_session_t session, + opaque * data, + size_t data_size) +{ + if (session->security_parameters.entity == GNUTLS_CLIENT) + return oprfi_send_client (session, data, data_size); + else + return oprfi_send_server (session, data, data_size); +} + +void +gnutls_oprfi_enable_client (gnutls_session_t session, + size_t len, + unsigned char *data) +{ + session->security_parameters.extensions.oprfi_client_len = len; + session->security_parameters.extensions.oprfi_client = data; +} + + +void +gnutls_oprfi_enable_server (gnutls_session_t session, + gnutls_oprfi_callback_func cb, + void *userdata) +{ + session->security_parameters.extensions.oprfi_cb = cb; + session->security_parameters.extensions.oprfi_userdata = userdata; +} diff --git a/lib/ext_oprfi.h b/lib/ext_oprfi.h new file mode 100644 index 0000000000..7f75be9c7e --- /dev/null +++ b/lib/ext_oprfi.h @@ -0,0 +1,33 @@ +/* + * Copyright (C) 2007 Free Software Foundation + * + * Author: Simon Josefsson + * + * This file is part of GNUTLS. + * + * The GNUTLS library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public License + * as published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, + * USA + * + */ + +#include <gnutls_int.h> + +int _gnutls_oprfi_recv_params (gnutls_session_t state, + const opaque * data, + size_t data_size); + +int _gnutls_oprfi_send_params (gnutls_session_t state, + opaque * data, + size_t data_size); diff --git a/lib/gnutls_extensions.c b/lib/gnutls_extensions.c index bb6a64d49a..20b1bbd414 100644 --- a/lib/gnutls_extensions.c +++ b/lib/gnutls_extensions.c @@ -33,6 +33,7 @@ #include "ext_max_record.h" #include <ext_cert_type.h> #include <ext_server_name.h> +#include <ext_oprfi.h> #include <ext_srp.h> #include <ext_inner_application.h> #include <ext_authz.h> @@ -64,6 +65,11 @@ gnutls_extension_entry _gnutls_extensions[MAX_EXT_SIZE] = { GNUTLS_EXTENSION_ENTRY (GNUTLS_EXTENSION_SERVER_NAME, _gnutls_server_name_recv_params, _gnutls_server_name_send_params), +#ifdef ENABLE_OPRFI + GNUTLS_EXTENSION_ENTRY (GNUTLS_EXTENSION_OPAQUE_PRF_INPUT, + _gnutls_oprfi_recv_params, + _gnutls_oprfi_send_params), +#endif #ifdef ENABLE_SRP GNUTLS_EXTENSION_ENTRY (GNUTLS_EXTENSION_SRP, _gnutls_srp_recv_params, diff --git a/lib/gnutls_int.h b/lib/gnutls_int.h index 3e6ef39575..1c9f10e5f5 100644 --- a/lib/gnutls_int.h +++ b/lib/gnutls_int.h @@ -144,6 +144,9 @@ typedef enum extensions_t GNUTLS_EXTENSION_AUTHZ_CLIENT = 7, GNUTLS_EXTENSION_AUTHZ_SERVER = 8, GNUTLS_EXTENSION_CERT_TYPE = 9, +#ifdef ENABLE_OPRFI + GNUTLS_EXTENSION_OPAQUE_PRF_INPUT = ENABLE_OPRFI, +#endif GNUTLS_EXTENSION_SRP = 12, GNUTLS_EXTENSION_INNER_APPLICATION = 37703 } extensions_t; @@ -284,6 +287,14 @@ typedef struct gnutls_authz_recv_callback_func authz_recv_callback; gnutls_authz_send_callback_func authz_send_callback; gnutls_buffer authz_data; + + /* Opaque PRF input. */ + gnutls_oprfi_callback_func oprfi_cb; + void *oprfi_userdata; + opaque *oprfi_client; + uint16_t oprfi_client_len; + opaque *oprfi_server; + uint16_t oprfi_server_len; } tls_ext_st; /* auth_info_t structures now MAY contain malloced diff --git a/lib/gnutls_kx.c b/lib/gnutls_kx.c index edd1fb696a..05a5dc95dd 100644 --- a/lib/gnutls_kx.c +++ b/lib/gnutls_kx.c @@ -59,13 +59,8 @@ static int generate_normal_master (gnutls_session_t session, int keep_premaster) { int ret = 0; - opaque rnd[2 * TLS_RANDOM_SIZE + 1]; char buf[512]; - memcpy (rnd, session->security_parameters.client_random, TLS_RANDOM_SIZE); - memcpy (&rnd[TLS_RANDOM_SIZE], - session->security_parameters.server_random, TLS_RANDOM_SIZE); - _gnutls_hard_log ("INT: PREMASTER SECRET[%d]: %s\n", PREMASTER.size, _gnutls_bin2hex (PREMASTER.data, PREMASTER.size, buf, sizeof (buf))); @@ -78,6 +73,12 @@ generate_normal_master (gnutls_session_t session, int keep_premaster) if (gnutls_protocol_get_version (session) == GNUTLS_SSL3) { + opaque rnd[2 * TLS_RANDOM_SIZE + 1]; + + memcpy (rnd, session->security_parameters.client_random, TLS_RANDOM_SIZE); + memcpy (&rnd[TLS_RANDOM_SIZE], + session->security_parameters.server_random, TLS_RANDOM_SIZE); + ret = _gnutls_ssl3_generate_random (PREMASTER.data, PREMASTER.size, rnd, 2 * TLS_RANDOM_SIZE, @@ -86,8 +87,69 @@ generate_normal_master (gnutls_session_t session, int keep_premaster) master_secret); } + else if (session->security_parameters.extensions.oprfi_client_len > 0 && + session->security_parameters.extensions.oprfi_server_len > 0) + { + opaque *rnd; + size_t rndlen = 2 * TLS_RANDOM_SIZE; + + rndlen += session->security_parameters.extensions.oprfi_client_len; + rndlen += session->security_parameters.extensions.oprfi_server_len; + + rnd = gnutls_malloc (rndlen + 1); + if (!rnd) + { + gnutls_assert (); + return GNUTLS_E_MEMORY_ERROR; + } + + _gnutls_hard_log ("INT: CLIENT OPRFI[%d]: %s\n", + session->security_parameters. + extensions.oprfi_server_len, + _gnutls_bin2hex (session->security_parameters. + extensions.oprfi_client, + session->security_parameters. + extensions.oprfi_client_len, + buf, sizeof (buf))); + _gnutls_hard_log ("INT: SERVER OPRFI[%d]: %s\n", + session->security_parameters. + extensions.oprfi_server_len, + _gnutls_bin2hex (session->security_parameters. + extensions.oprfi_server, + session->security_parameters. + extensions.oprfi_server_len, + buf, sizeof (buf))); + + memcpy (rnd, session->security_parameters.client_random, + TLS_RANDOM_SIZE); + memcpy (rnd + TLS_RANDOM_SIZE, + session->security_parameters.extensions.oprfi_client, + session->security_parameters.extensions.oprfi_client_len); + memcpy (rnd + TLS_RANDOM_SIZE + + session->security_parameters.extensions.oprfi_client_len, + session->security_parameters.server_random, + TLS_RANDOM_SIZE); + memcpy (rnd + TLS_RANDOM_SIZE + + session->security_parameters.extensions.oprfi_client_len + + TLS_RANDOM_SIZE, + session->security_parameters.extensions.oprfi_server, + session->security_parameters.extensions.oprfi_server_len); + + ret = _gnutls_PRF (session, PREMASTER.data, PREMASTER.size, + MASTER_SECRET, strlen (MASTER_SECRET), + rnd, rndlen, TLS_MASTER_SIZE, + session->security_parameters.master_secret); + + gnutls_free (rnd); + } else { + opaque rnd[2 * TLS_RANDOM_SIZE + 1]; + + memcpy (rnd, session->security_parameters.client_random, TLS_RANDOM_SIZE); + memcpy (&rnd[TLS_RANDOM_SIZE], + session->security_parameters.server_random, TLS_RANDOM_SIZE); + ret = _gnutls_PRF (session, PREMASTER.data, PREMASTER.size, MASTER_SECRET, strlen (MASTER_SECRET), diff --git a/tests/Makefile.am b/tests/Makefile.am index 209f343d71..eb9a16a59b 100644 --- a/tests/Makefile.am +++ b/tests/Makefile.am @@ -43,6 +43,9 @@ if HAVE_FORK ctests += x509self x509signself anonself pskself dhepskself tlsia resume tlsia_LDADD = ../libextra/libgnutls-extra.la $(LDADD) @LTLIBREADLINE@ endif +if ENABLE_OPRFI +ctests += oprfi +endif gc_LDADD = $(LDADD) $(LIBGCRYPT_LIBS) check_PROGRAMS = $(ctests) diff --git a/tests/oprfi.c b/tests/oprfi.c new file mode 100644 index 0000000000..303d008197 --- /dev/null +++ b/tests/oprfi.c @@ -0,0 +1,410 @@ +/* + * Copyright (C) 2004, 2005, 2006, 2007 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 2 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 + */ + +/* Parts copied from GnuTLS example programs. */ + +#if HAVE_CONFIG_H +# include <config.h> +#endif + +#include <stdio.h> +#include <stdlib.h> +#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 "utils.h" + +static void +tls_log_func (int level, const char *str) +{ + fprintf (stderr, "|<%d>| %s", level, str); +} + +/* A very basic TLS client, with anonymous authentication. + */ + +#define MAX_BUF 1024 +#define MSG "Hello TLS" + +/* Connects to the peer and returns a socket + * descriptor. + */ +int +tcp_connect (void) +{ + const char *PORT = "5556"; + const char *SERVER = "127.0.0.1"; + int err, sd; + struct sockaddr_in sa; + + /* connects to server + */ + sd = socket (AF_INET, SOCK_STREAM, 0); + + memset (&sa, '\0', sizeof (sa)); + sa.sin_family = AF_INET; + sa.sin_port = htons (atoi (PORT)); + inet_pton (AF_INET, SERVER, &sa.sin_addr); + + err = connect (sd, (struct sockaddr *) &sa, sizeof (sa)); + if (err < 0) + { + fprintf (stderr, "Connect error\n"); + exit (1); + } + + return sd; +} + +/* closes the given socket descriptor. + */ +void +tcp_close (int sd) +{ + shutdown (sd, SHUT_RDWR); /* no more receptions */ + close (sd); +} + +void +client (void) +{ + int ret, sd, ii; + gnutls_session_t session; + char buffer[MAX_BUF + 1]; + gnutls_anon_client_credentials_t anoncred; + /* Need to enable anonymous KX specifically. */ + const int kx_prio[] = { GNUTLS_KX_ANON_DH, 0 }; + + gnutls_global_init (); + + gnutls_global_set_log_function (tls_log_func); + gnutls_global_set_log_level (4711); + + gnutls_anon_allocate_client_credentials (&anoncred); + + /* Initialize TLS session + */ + gnutls_init (&session, GNUTLS_CLIENT); + + /* Use default priorities */ + gnutls_set_default_priority (session); + gnutls_kx_set_priority (session, kx_prio); + + /* put the anonymous credentials to the current session + */ + gnutls_credentials_set (session, GNUTLS_CRD_ANON, anoncred); + + gnutls_oprfi_enable_client (session, 3, "foo"); + + /* connect to the peer + */ + sd = tcp_connect (); + + gnutls_transport_set_ptr (session, (gnutls_transport_ptr_t) sd); + + /* Perform the TLS handshake + */ + ret = gnutls_handshake (session); + + if (ret < 0) + { + fail ("client: Handshake failed\n"); + gnutls_perror (ret); + goto end; + } + else + { + success ("client: Handshake was completed\n"); + } + + success ("client: TLS version is: %s\n", + gnutls_protocol_get_name (gnutls_protocol_get_version (session))); + + gnutls_record_send (session, MSG, strlen (MSG)); + + ret = gnutls_record_recv (session, buffer, MAX_BUF); + if (ret == 0) + { + 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; + } + + printf ("- Received %d bytes: ", ret); + for (ii = 0; ii < ret; ii++) + { + fputc (buffer[ii], stdout); + } + fputs ("\n", stdout); + + gnutls_bye (session, GNUTLS_SHUT_RDWR); + +end: + + tcp_close (sd); + + gnutls_deinit (session); + + gnutls_anon_free_client_credentials (anoncred); + + gnutls_global_deinit (); +} + +/* This is a sample TLS 1.0 echo server, for anonymous authentication only. + */ + +#define SA struct sockaddr +#define MAX_BUF 1024 +#define PORT 5556 /* listen to 5556 port */ +#define DH_BITS 1024 + +/* These are global */ +gnutls_anon_server_credentials_t anoncred; + +int +oprfi_callback (gnutls_session_t session, + void *userdata, + size_t oprfi_len, + const unsigned char *in_oprfi, + unsigned char *out_oprfi) +{ + size_t i; + + puts("cb"); + + for (i = 0; i < oprfi_len; i++) + printf ("OPRF[%d]: %02x %03d %c\n", i, in_oprfi[i], + in_oprfi[i], in_oprfi[i]); + + memset (out_oprfi, 42, oprfi_len); + + return 0; +} + +gnutls_session_t +initialize_tls_session (void) +{ + gnutls_session_t session; + const int kx_prio[] = { GNUTLS_KX_ANON_DH, 0 }; + + gnutls_init (&session, GNUTLS_SERVER); + + /* avoid calling all the priority functions, since the defaults + * are adequate. + */ + gnutls_set_default_priority (session); + gnutls_kx_set_priority (session, kx_prio); + + gnutls_credentials_set (session, GNUTLS_CRD_ANON, anoncred); + + gnutls_dh_set_prime_bits (session, DH_BITS); + + gnutls_oprfi_enable_server (session, oprfi_callback, NULL); + + return session; +} + +static gnutls_dh_params_t dh_params; + +static int +generate_dh_params (void) +{ + const gnutls_datum_t p3 = { pkcs3, strlen (pkcs3) }; + /* Generate Diffie Hellman parameters - for use with DHE + * kx algorithms. These should be discarded and regenerated + * once a day, once a week or once a month. Depending on the + * security requirements. + */ + gnutls_dh_params_init (&dh_params); + return gnutls_dh_params_import_pkcs3 (dh_params, &p3, GNUTLS_X509_FMT_PEM); +} + +int err, listen_sd, i; +int sd, ret; +struct sockaddr_in sa_serv; +struct sockaddr_in sa_cli; +int client_len; +char topbuf[512]; +gnutls_session_t session; +char buffer[MAX_BUF + 1]; +int optval = 1; + +void +server_start (void) +{ + /* this must be called once in the program + */ + gnutls_global_init (); + + gnutls_global_set_log_function (tls_log_func); + gnutls_global_set_log_level (4711); + + gnutls_anon_allocate_server_credentials (&anoncred); + + success ("Launched, generating DH parameters...\n"); + + generate_dh_params (); + + gnutls_anon_set_server_dh_params (anoncred, dh_params); + + /* Socket operations + */ + listen_sd = socket (AF_INET, SOCK_STREAM, 0); + if (err == -1) + { + perror ("socket"); + fail ("server: socket failed\n"); + return; + } + + memset (&sa_serv, '\0', sizeof (sa_serv)); + sa_serv.sin_family = AF_INET; + sa_serv.sin_addr.s_addr = INADDR_ANY; + sa_serv.sin_port = htons (PORT); /* Server Port number */ + + setsockopt (listen_sd, SOL_SOCKET, SO_REUSEADDR, &optval, sizeof (int)); + + err = bind (listen_sd, (SA *) & sa_serv, sizeof (sa_serv)); + if (err == -1) + { + perror ("bind"); + fail ("server: bind failed\n"); + return; + } + + err = listen (listen_sd, 1024); + if (err == -1) + { + perror ("listen"); + fail ("server: listen failed\n"); + return; + } + + success ("server: ready. Listening to port '%d'.\n", PORT); +} + +void +server (void) +{ + client_len = sizeof (sa_cli); + + session = initialize_tls_session (); + + sd = accept (listen_sd, (SA *) & sa_cli, &client_len); + + success ("server: connection from %s, port %d\n", + inet_ntop (AF_INET, &sa_cli.sin_addr, topbuf, + sizeof (topbuf)), ntohs (sa_cli.sin_port)); + + gnutls_transport_set_ptr (session, (gnutls_transport_ptr_t) sd); + ret = gnutls_handshake (session); + if (ret < 0) + { + close (sd); + gnutls_deinit (session); + fail ("server: Handshake has failed (%s)\n\n", gnutls_strerror (ret)); + return; + } + success ("server: Handshake was completed\n"); + + success ("server: TLS version is: %s\n", + gnutls_protocol_get_name (gnutls_protocol_get_version (session))); + + /* see the Getting peer's information example */ + /* print_info(session); */ + + i = 0; + for (;;) + { + bzero (buffer, MAX_BUF + 1); + ret = gnutls_record_recv (session, buffer, MAX_BUF); + + if (ret == 0) + { + success ("server: Peer has closed the GNUTLS connection\n"); + break; + } + else if (ret < 0) + { + 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); + + close (listen_sd); + + gnutls_anon_free_server_credentials (anoncred); + + gnutls_global_deinit (); + + success ("server: finished\n"); +} + +void +doit (void) +{ + pid_t child; + + server_start (); + if (error_count) + return; + + child = fork (); + if (child < 0) + { + perror ("fork"); + fail ("fork"); + return; + } + + if (child) + { + int status; + /* parent */ + server (); + wait (&status); + } + else + client (); +} |