[Help-gnutls] gnutls_record_send() problem
Laurent Birtz
laurent.birtz at kryptiva.com
Mon Jan 21 22:02:12 CET 2008
I've encountered a weird problem with the stock code examples (anonymous
server and client). By itself the example works fine, but if I replace
the string sent ("GET / HTTP/1.0\r\n\r\n") by a zeroed buffer, then the
client hangs. This does not occur if I send a buffer containing bytes
with the value 1.
The sample code is shown below. I am using GnuTLS 2.2.1-1, kernel
2.6.22-3-686, Debian unstable, Debian package libgnutls26. Can someone
tell me what is going on?
***** Makefile *****
all:
gcc -Wall -g ex-serv-anon.c -o serv /usr/lib/libgnutls-openssl.so.26.1.2
gcc -Wall -g ex-client1.c tcp.c -o client
/usr/lib/libgnutls-openssl.so.26.1.2
***** tcp.c *****:
#if HAVE_CONFIG_H
# include <config.h>
#endif
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <netinet/in.h>
#include <unistd.h>
#define SA struct sockaddr
/* Connects to the peer and returns a socket
* descriptor.
*/
extern 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, (SA *) & sa, sizeof (sa));
if (err < 0)
{
fprintf (stderr, "Connect error\n");
exit (1);
}
return sd;
}
/* closes the given socket descriptor.
*/
extern void
tcp_close (int sd)
{
shutdown (sd, SHUT_RDWR); /* no more receptions */
close (sd);
}
***** ex-client1.c *****:
#if HAVE_CONFIG_H
# include <config.h>
#endif
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <gnutls/gnutls.h>
/* A very basic TLS client, with anonymous authentication.
*/
#define MAX_BUF 1024
#define SA struct sockaddr
#define MSG "GET / HTTP/1.0\r\n\r\n"
extern int tcp_connect (void);
extern void tcp_close (int sd);
int
main (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_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);
/* 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)
{
fprintf (stderr, "*** Handshake failed\n");
gnutls_perror (ret);
goto end;
}
else
{
printf ("- Handshake was completed\n");
}
/* CHANGE HERE */
#if 1
char s[100]; memset(s, 0, 100);
gnutls_record_send (session, s, 100);
#else
gnutls_record_send (session, MSG, strlen (MSG));
#endif
ret = gnutls_record_recv (session, buffer, MAX_BUF);
if (ret == 0)
{
printf ("- Peer has closed the TLS connection\n");
goto end;
}
else if (ret < 0)
{
fprintf (stderr, "*** 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 ();
return 0;
}
***** ex-serv-anon.c: *****
#if HAVE_CONFIG_H
# include <config.h>
#endif
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <netinet/in.h>
#include <string.h>
#include <unistd.h>
#include <gnutls/gnutls.h>
/* This is a sample TLS 1.0 echo server, for anonymous authentication only.
*/
#define SA struct sockaddr
#define SOCKET_ERR(err,s) if(err==-1) {perror(s);return(1);}
#define MAX_BUF 1024
#define PORT 5556 /* listen to 5556 port */
#define DH_BITS 1024
/* These are global */
gnutls_anon_server_credentials_t anoncred;
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);
return session;
}
static gnutls_dh_params_t dh_params;
static int
generate_dh_params (void)
{
/* 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);
gnutls_dh_params_generate2 (dh_params, DH_BITS);
return 0;
}
int
main (void)
{
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;
/* this must be called once in the program
*/
gnutls_global_init ();
gnutls_anon_allocate_server_credentials (&anoncred);
generate_dh_params ();
gnutls_anon_set_server_dh_params (anoncred, dh_params);
/* Socket operations
*/
listen_sd = socket (AF_INET, SOCK_STREAM, 0);
SOCKET_ERR (listen_sd, "socket");
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));
SOCKET_ERR (err, "bind");
err = listen (listen_sd, 1024);
SOCKET_ERR (err, "listen");
printf ("Server ready. Listening to port '%d'.\n\n", PORT);
client_len = sizeof (sa_cli);
for (;;)
{
session = initialize_tls_session ();
sd = accept (listen_sd, (SA *) & sa_cli, &client_len);
printf ("- 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);
fprintf (stderr, "*** Handshake has failed (%s)\n\n",
gnutls_strerror (ret));
continue;
}
printf ("- Handshake was completed\n");
/* see the Getting peer's information example */
/* print_info(session); */
i = 0;
for (;;)
{
memset (buffer, 0, MAX_BUF + 1);
ret = gnutls_record_recv (session, buffer, MAX_BUF);
if (ret == 0)
{
printf ("\n- Peer has closed the GNUTLS connection\n");
break;
}
else if (ret < 0)
{
fprintf (stderr, "\n*** Received corrupted "
"data(%d). Closing the connection.\n\n", ret);
break;
}
else if (ret > 0)
{
/* echo data back to the client
*/
gnutls_record_send (session, buffer, strlen (buffer));
}
}
printf ("\n");
/* 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 ();
return 0;
}
The 'ldd' dump of the server binary is:
> ldd serv
linux-gate.so.1 => (0xffffe000)
libgnutls-openssl.so.26 => /usr/lib/libgnutls-openssl.so.26 (0xb7f22000)
libc.so.6 => /lib/i686/cmov/libc.so.6 (0xb7dd5000)
libgnutls.so.26 => /usr/lib/libgnutls.so.26 (0xb7d5b000)
libtasn1.so.3 => /usr/lib/libtasn1.so.3 (0xb7d4b000)
libgcrypt.so.11 => /usr/lib/libgcrypt.so.11 (0xb7ce3000)
libgpg-error.so.0 => /usr/lib/libgpg-error.so.0 (0xb7cdf000)
/lib/ld-linux.so.2 (0xb7f45000)
Thanks,
Laurent Birtz
More information about the Gnutls-help
mailing list