Blame tests/mini-dtls-record.c

Packit aea12f
/*
Packit aea12f
 * Copyright (C) 2012-2013 Free Software Foundation, Inc.
Packit aea12f
 * Copyright (C) 2013 Nikos Mavrogiannopoulos
Packit aea12f
 *
Packit aea12f
 * Author: Nikos Mavrogiannopoulos
Packit aea12f
 *
Packit aea12f
 * This file is part of GnuTLS.
Packit aea12f
 *
Packit aea12f
 * GnuTLS is free software; you can redistribute it and/or modify it
Packit aea12f
 * under the terms of the GNU General Public License as published by
Packit aea12f
 * the Free Software Foundation; either version 3 of the License, or
Packit aea12f
 * (at your option) any later version.
Packit aea12f
 *
Packit aea12f
 * GnuTLS is distributed in the hope that it will be useful, but
Packit aea12f
 * WITHOUT ANY WARRANTY; without even the implied warranty of
Packit aea12f
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
Packit aea12f
 * General Public License for more details.
Packit aea12f
 *
Packit aea12f
 * You should have received a copy of the GNU General Public License
Packit aea12f
 * along with GnuTLS; if not, write to the Free Software Foundation,
Packit aea12f
 * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
Packit aea12f
 */
Packit aea12f
Packit aea12f
#ifdef HAVE_CONFIG_H
Packit aea12f
#include <config.h>
Packit aea12f
#endif
Packit aea12f
Packit aea12f
#include <stdio.h>
Packit aea12f
#include <stdlib.h>
Packit aea12f
Packit aea12f
#if defined(_WIN32)
Packit aea12f
Packit aea12f
int main()
Packit aea12f
{
Packit aea12f
	exit(77);
Packit aea12f
}
Packit aea12f
Packit aea12f
#else
Packit aea12f
Packit aea12f
#include <string.h>
Packit aea12f
#include <errno.h>
Packit aea12f
#include <sys/types.h>
Packit aea12f
#include <netinet/in.h>
Packit aea12f
#include <sys/socket.h>
Packit aea12f
#include <sys/wait.h>
Packit aea12f
#include <arpa/inet.h>
Packit aea12f
#include <unistd.h>
Packit aea12f
#include <signal.h>
Packit aea12f
#include <gnutls/gnutls.h>
Packit aea12f
#include <gnutls/dtls.h>
Packit aea12f
Packit aea12f
#include "utils.h"
Packit aea12f
Packit aea12f
static int test_finished = 0;
Packit aea12f
static void terminate(void);
Packit aea12f
Packit aea12f
/* This program tests whether messages in DTLS are received
Packit aea12f
 * with the expected sequence. That is whether the message
Packit aea12f
 * sequence numbers returned correspond to the received messages.
Packit aea12f
 */
Packit aea12f
Packit aea12f
/*
Packit aea12f
static void
Packit aea12f
tls_audit_log_func (gnutls_session_t session, const char *str)
Packit aea12f
{
Packit aea12f
  fprintf (stderr, "|<%p>| %s", session, str);
Packit aea12f
}
Packit aea12f
*/
Packit aea12f
Packit aea12f
static void server_log_func(int level, const char *str)
Packit aea12f
{
Packit aea12f
	fprintf(stderr, "server|<%d>| %s", level, str);
Packit aea12f
}
Packit aea12f
Packit aea12f
static void client_log_func(int level, const char *str)
Packit aea12f
{
Packit aea12f
	fprintf(stderr, "client|<%d>| %s", level, str);
Packit aea12f
}
Packit aea12f
Packit aea12f
/* These are global */
Packit aea12f
static pid_t child;
Packit aea12f
Packit aea12f
/* A test client/server app for DTLS duplicate packet detection.
Packit aea12f
 */
Packit aea12f
Packit aea12f
#define MAX_BUF 1024
Packit aea12f
Packit aea12f
#define MAX_SEQ 128
Packit aea12f
Packit aea12f
static int msg_seq[] =
Packit aea12f
    { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 10, 16, 5, 32, 11, 11, 11, 11, 12,
Packit aea12f
	10, 13, 14, 15, 16, 17, 19, 20, 18, 22, 24, 23, 25, 26, 27, 29, 28,
Packit aea12f
	29, 29, 30, 31, 32, 33, 34, 35, 37, 36, 38, 39, 42, 37, 40, 41, 41,
Packit aea12f
	-1
Packit aea12f
};
Packit aea12f
Packit aea12f
static unsigned int current = 0;
Packit aea12f
static unsigned int pos = 0;
Packit aea12f
Packit aea12f
unsigned char *stored_messages[MAX_SEQ];
Packit aea12f
unsigned int stored_sizes[MAX_SEQ];
Packit aea12f
Packit aea12f
static ssize_t odd_push(gnutls_transport_ptr_t tr, const void *data, size_t len)
Packit aea12f
{
Packit aea12f
	ssize_t ret;
Packit aea12f
	unsigned i;
Packit aea12f
Packit aea12f
	if (msg_seq[current] == -1 || test_finished != 0) {
Packit aea12f
		test_finished = 1;
Packit aea12f
		return len;
Packit aea12f
	}
Packit aea12f
Packit aea12f
	stored_messages[current] = malloc(len);
Packit aea12f
	memcpy(stored_messages[current], data, len);
Packit aea12f
	stored_sizes[current] = len;
Packit aea12f
Packit aea12f
	if (pos != current) {
Packit aea12f
		for (i = pos; i <= current; i++) {
Packit aea12f
			if (stored_messages[msg_seq[i]] != NULL) {
Packit aea12f
				do {
Packit aea12f
					ret =
Packit aea12f
					    send((long int)tr,
Packit aea12f
						 stored_messages[msg_seq
Packit aea12f
								 [i]],
Packit aea12f
						 stored_sizes[msg_seq[i]], 0);
Packit aea12f
				}
Packit aea12f
				while (ret == -1 && (errno == EAGAIN || errno == EINTR));
Packit aea12f
				pos++;
Packit aea12f
			} else
Packit aea12f
				break;
Packit aea12f
		}
Packit aea12f
	} else if (msg_seq[current] == (int)current) {
Packit aea12f
		do {
Packit aea12f
			ret = send((long int)tr, data, len, 0);
Packit aea12f
		}
Packit aea12f
		while (ret == -1 && (errno == EAGAIN || errno == EINTR));
Packit aea12f
Packit aea12f
		current++;
Packit aea12f
		pos++;
Packit aea12f
Packit aea12f
		return ret;
Packit aea12f
	} else if (stored_messages[msg_seq[current]] != NULL) {
Packit aea12f
		do {
Packit aea12f
			ret =
Packit aea12f
			    send((long int)tr,
Packit aea12f
				 stored_messages[msg_seq[current]],
Packit aea12f
				 stored_sizes[msg_seq[current]], 0);
Packit aea12f
		}
Packit aea12f
		while (ret == -1 && (errno == EAGAIN || errno == EINTR));
Packit aea12f
		current++;
Packit aea12f
		pos++;
Packit aea12f
		return ret;
Packit aea12f
	}
Packit aea12f
Packit aea12f
	current++;
Packit aea12f
Packit aea12f
	return len;
Packit aea12f
}
Packit aea12f
Packit aea12f
static ssize_t n_push(gnutls_transport_ptr_t tr, const void *data, size_t len)
Packit aea12f
{
Packit aea12f
	return send((unsigned long)tr, data, len, 0);
Packit aea12f
}
Packit aea12f
Packit aea12f
/* The first five messages are handshake. Thus corresponds to msg_seq+5 */
Packit aea12f
static int recv_msg_seq[] =
Packit aea12f
    { 1, 2, 3, 4, 5, 6, 12, 28, 7, 8, 9, 10, 11, 13, 15, 16, 14, 18, 20,
Packit aea12f
	19, 21, 22, 23, 25, 24, 26, 27, 29, 30, 31, 33, 32, 34, 35, 38, 36, 37,
Packit aea12f
	    -1
Packit aea12f
};
Packit aea12f
Packit aea12f
static void client(int fd)
Packit aea12f
{
Packit aea12f
	gnutls_session_t session;
Packit aea12f
	int ret;
Packit aea12f
	char buffer[MAX_BUF + 1];
Packit aea12f
	gnutls_anon_client_credentials_t anoncred;
Packit aea12f
	unsigned char seq[8];
Packit aea12f
	uint32_t useq;
Packit aea12f
Packit aea12f
	memset(buffer, 0, sizeof(buffer));
Packit aea12f
Packit aea12f
	/* Need to enable anonymous KX specifically. */
Packit aea12f
Packit aea12f
/*    gnutls_global_set_audit_log_function (tls_audit_log_func); */
Packit aea12f
	global_init();
Packit aea12f
Packit aea12f
	if (debug) {
Packit aea12f
		gnutls_global_set_log_function(client_log_func);
Packit aea12f
		gnutls_global_set_log_level(2);
Packit aea12f
	}
Packit aea12f
Packit aea12f
	gnutls_anon_allocate_client_credentials(&anoncred);
Packit aea12f
Packit aea12f
	/* Initialize TLS session
Packit aea12f
	 */
Packit aea12f
	gnutls_init(&session, GNUTLS_CLIENT | GNUTLS_DATAGRAM);
Packit aea12f
	gnutls_dtls_set_timeouts(session, 50 * 1000, 600 * 1000);
Packit aea12f
	gnutls_heartbeat_enable(session, GNUTLS_HB_PEER_ALLOWED_TO_SEND);
Packit aea12f
	gnutls_dtls_set_mtu(session, 1500);
Packit aea12f
Packit aea12f
	/* Use default priorities */
Packit aea12f
	gnutls_priority_set_direct(session,
Packit aea12f
				   "NONE:+VERS-DTLS1.0:+CIPHER-ALL:+MAC-ALL:+SIGN-ALL:+COMP-ALL:+ANON-ECDH:+CURVE-ALL",
Packit aea12f
				   NULL);
Packit aea12f
Packit aea12f
	/* put the anonymous credentials to the current session
Packit aea12f
	 */
Packit aea12f
	gnutls_credentials_set(session, GNUTLS_CRD_ANON, anoncred);
Packit aea12f
Packit aea12f
	gnutls_transport_set_int(session, fd);
Packit aea12f
Packit aea12f
	/* Perform the TLS handshake
Packit aea12f
	 */
Packit aea12f
	do {
Packit aea12f
		ret = gnutls_handshake(session);
Packit aea12f
	}
Packit aea12f
	while (ret < 0 && gnutls_error_is_fatal(ret) == 0);
Packit aea12f
Packit aea12f
	if (ret < 0) {
Packit aea12f
		fail("client: Handshake failed\n");
Packit aea12f
		gnutls_perror(ret);
Packit aea12f
		exit(1);
Packit aea12f
	} else {
Packit aea12f
		if (debug)
Packit aea12f
			success("client: Handshake was completed\n");
Packit aea12f
	}
Packit aea12f
Packit aea12f
	gnutls_record_send(session, buffer, 1);
Packit aea12f
Packit aea12f
	if (debug)
Packit aea12f
		success("client: DTLS version is: %s\n",
Packit aea12f
			gnutls_protocol_get_name
Packit aea12f
			(gnutls_protocol_get_version(session)));
Packit aea12f
	do {
Packit aea12f
		ret =
Packit aea12f
		    gnutls_record_recv_seq(session, buffer, sizeof(buffer),
Packit aea12f
					   seq);
Packit aea12f
Packit aea12f
		if (ret > 0) {
Packit aea12f
			useq =
Packit aea12f
			    seq[7] | (seq[6] << 8) | (seq[5] << 16) |
Packit aea12f
			    (seq[4] << 24);
Packit aea12f
Packit aea12f
			if (debug)
Packit aea12f
				success("received %u\n", (unsigned int)useq);
Packit aea12f
Packit aea12f
			if (recv_msg_seq[current] == -1) {
Packit aea12f
				fail("received message sequence differs\n");
Packit aea12f
				terminate();
Packit aea12f
			}
Packit aea12f
			if (((uint32_t)recv_msg_seq[current]) != useq) {
Packit aea12f
				fail("received message sequence differs (current: %u, got: %u, expected: %u)\n",
Packit aea12f
				     (unsigned)current, (unsigned)useq, (unsigned)recv_msg_seq[current]);
Packit aea12f
				terminate();
Packit aea12f
			}
Packit aea12f
Packit aea12f
			current++;
Packit aea12f
		}
Packit aea12f
	}
Packit aea12f
	while ((ret == GNUTLS_E_AGAIN || ret == GNUTLS_E_INTERRUPTED
Packit aea12f
		|| ret > 0));
Packit aea12f
Packit aea12f
	gnutls_bye(session, GNUTLS_SHUT_WR);
Packit aea12f
Packit aea12f
	close(fd);
Packit aea12f
Packit aea12f
	gnutls_deinit(session);
Packit aea12f
Packit aea12f
	gnutls_anon_free_client_credentials(anoncred);
Packit aea12f
Packit aea12f
	gnutls_global_deinit();
Packit aea12f
}
Packit aea12f
Packit aea12f
static void terminate(void)
Packit aea12f
{
Packit aea12f
	int status;
Packit aea12f
Packit aea12f
	kill(child, SIGTERM);
Packit aea12f
	wait(&status);
Packit aea12f
	exit(1);
Packit aea12f
}
Packit aea12f
Packit aea12f
static void server(int fd)
Packit aea12f
{
Packit aea12f
	int ret;
Packit aea12f
	gnutls_session_t session;
Packit aea12f
	gnutls_anon_server_credentials_t anoncred;
Packit aea12f
	char c;
Packit aea12f
Packit aea12f
	global_init();
Packit aea12f
Packit aea12f
	if (debug) {
Packit aea12f
		gnutls_global_set_log_function(server_log_func);
Packit aea12f
		gnutls_global_set_log_level(2);
Packit aea12f
	}
Packit aea12f
Packit aea12f
	gnutls_anon_allocate_server_credentials(&anoncred);
Packit aea12f
Packit aea12f
	gnutls_init(&session, GNUTLS_SERVER | GNUTLS_DATAGRAM);
Packit aea12f
	gnutls_dtls_set_timeouts(session, 50 * 1000, 600 * 1000);
Packit aea12f
	gnutls_transport_set_push_function(session, odd_push);
Packit aea12f
	gnutls_heartbeat_enable(session, GNUTLS_HB_PEER_ALLOWED_TO_SEND);
Packit aea12f
	gnutls_dtls_set_mtu(session, 1500);
Packit aea12f
Packit aea12f
	/* avoid calling all the priority functions, since the defaults
Packit aea12f
	 * are adequate.
Packit aea12f
	 */
Packit aea12f
	gnutls_priority_set_direct(session,
Packit aea12f
				   "NONE:+VERS-DTLS1.0:+CIPHER-ALL:+MAC-ALL:+SIGN-ALL:+COMP-ALL:+ANON-ECDH:+CURVE-ALL",
Packit aea12f
				   NULL);
Packit aea12f
	gnutls_credentials_set(session, GNUTLS_CRD_ANON, anoncred);
Packit aea12f
Packit aea12f
	gnutls_transport_set_int(session, fd);
Packit aea12f
Packit aea12f
	do {
Packit aea12f
		ret = gnutls_handshake(session);
Packit aea12f
	}
Packit aea12f
	while (ret < 0 && gnutls_error_is_fatal(ret) == 0);
Packit aea12f
	if (ret < 0) {
Packit aea12f
		close(fd);
Packit aea12f
		gnutls_deinit(session);
Packit aea12f
		fail("server: Handshake has failed (%s)\n\n",
Packit aea12f
		     gnutls_strerror(ret));
Packit aea12f
		terminate();
Packit aea12f
	}
Packit aea12f
	if (debug)
Packit aea12f
		success("server: Handshake was completed\n");
Packit aea12f
Packit aea12f
	if (debug)
Packit aea12f
		success("server: TLS version is: %s\n",
Packit aea12f
			gnutls_protocol_get_name
Packit aea12f
			(gnutls_protocol_get_version(session)));
Packit aea12f
Packit aea12f
	gnutls_record_recv(session, &c, 1);
Packit aea12f
	do {
Packit aea12f
		do {
Packit aea12f
			ret = gnutls_record_send(session, &c, 1);
Packit aea12f
		}
Packit aea12f
		while (ret == GNUTLS_E_AGAIN || ret == GNUTLS_E_INTERRUPTED);
Packit aea12f
Packit aea12f
		if (ret < 0) {
Packit aea12f
			fail("send: %s\n", gnutls_strerror(ret));
Packit aea12f
			terminate();
Packit aea12f
		}
Packit aea12f
	}
Packit aea12f
	while (test_finished == 0);
Packit aea12f
Packit aea12f
	gnutls_transport_set_push_function(session, n_push);
Packit aea12f
	do {
Packit aea12f
		ret = gnutls_bye(session, GNUTLS_SHUT_WR);
Packit aea12f
	}
Packit aea12f
	while (ret == GNUTLS_E_AGAIN || ret == GNUTLS_E_INTERRUPTED);
Packit aea12f
Packit aea12f
	close(fd);
Packit aea12f
	gnutls_deinit(session);
Packit aea12f
Packit aea12f
	gnutls_anon_free_server_credentials(anoncred);
Packit aea12f
Packit aea12f
	gnutls_global_deinit();
Packit aea12f
Packit aea12f
	if (debug)
Packit aea12f
		success("server: finished\n");
Packit aea12f
}
Packit aea12f
Packit aea12f
static void start(void)
Packit aea12f
{
Packit aea12f
	int fd[2];
Packit aea12f
	int ret;
Packit aea12f
Packit aea12f
	signal(SIGPIPE, SIG_IGN);
Packit aea12f
Packit aea12f
	ret = socketpair(AF_UNIX, SOCK_STREAM, 0, fd);
Packit aea12f
	if (ret < 0) {
Packit aea12f
		perror("socketpair");
Packit aea12f
		exit(1);
Packit aea12f
	}
Packit aea12f
Packit aea12f
	child = fork();
Packit aea12f
	if (child < 0) {
Packit aea12f
		perror("fork");
Packit aea12f
		fail("fork");
Packit aea12f
		exit(1);
Packit aea12f
	}
Packit aea12f
Packit aea12f
	if (child) {
Packit aea12f
		int status;
Packit aea12f
		/* parent */
Packit aea12f
		close(fd[1]);
Packit aea12f
		server(fd[0]);
Packit aea12f
		wait(&status);
Packit aea12f
		check_wait_status(status);
Packit aea12f
	} else {
Packit aea12f
		close(fd[0]);
Packit aea12f
		client(fd[1]);
Packit aea12f
		exit(0);
Packit aea12f
	}
Packit aea12f
}
Packit aea12f
Packit aea12f
void doit(void)
Packit aea12f
{
Packit aea12f
	start();
Packit aea12f
}
Packit aea12f
Packit aea12f
#endif				/* _WIN32 */