Blame tests/tls13/key_update.c

Packit Service 4684c1
/*
Packit Service 4684c1
 * Copyright (C) 2017-2018 Red Hat, Inc.
Packit Service 4684c1
 *
Packit Service 4684c1
 * Author: Nikos Mavrogiannopoulos
Packit Service 4684c1
 *
Packit Service 4684c1
 * This file is part of GnuTLS.
Packit Service 4684c1
 *
Packit Service 4684c1
 * GnuTLS is free software; you can redistribute it and/or modify it
Packit Service 4684c1
 * under the terms of the GNU General Public License as published by
Packit Service 4684c1
 * the Free Software Foundation; either version 3 of the License, or
Packit Service 4684c1
 * (at your option) any later version.
Packit Service 4684c1
 *
Packit Service 4684c1
 * GnuTLS is distributed in the hope that it will be useful, but
Packit Service 4684c1
 * WITHOUT ANY WARRANTY; without even the implied warranty of
Packit Service 4684c1
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
Packit Service 4684c1
 * General Public License for more details.
Packit Service 4684c1
 *
Packit Service 4684c1
 * You should have received a copy of the GNU Lesser General Public License
Packit Service 4684c1
 * along with this program.  If not, see <https://www.gnu.org/licenses/>
Packit Service 4684c1
 */
Packit Service 4684c1
Packit Service 4684c1
#ifdef HAVE_CONFIG_H
Packit Service 4684c1
#include <config.h>
Packit Service 4684c1
#endif
Packit Service 4684c1
Packit Service 4684c1
#include <stdio.h>
Packit Service 4684c1
#include <stdlib.h>
Packit Service 4684c1
#include <string.h>
Packit Service 4684c1
#include <errno.h>
Packit Service 4684c1
#include <gnutls/gnutls.h>
Packit Service 4684c1
#include <gnutls/crypto.h>
Packit Service 4684c1
#include <assert.h>
Packit Service 4684c1
#include "cert-common.h"
Packit Service 4684c1
Packit Service 4684c1
#include "utils.h"
Packit Service 4684c1
#define RANDOMIZE
Packit Service 4684c1
#include "eagain-common.h"
Packit Service 4684c1
Packit Service 4684c1
const char *side = "";
Packit Service 4684c1
Packit Service 4684c1
static void tls_log_func(int level, const char *str)
Packit Service 4684c1
{
Packit Service 4684c1
	fprintf(stderr, "%s|<%d>| %s", side, level, str);
Packit Service 4684c1
}
Packit Service 4684c1
Packit Service 4684c1
#define MAX_BUF 1024
Packit Service 4684c1
#define MSG "Hello TLS, and hi and how are you and more data here... and more... and even more and even more more data..."
Packit Service 4684c1
Packit Service 4684c1
static unsigned key_update_msg_inc = 0;
Packit Service 4684c1
static unsigned key_update_msg_out = 0;
Packit Service 4684c1
Packit Service 4684c1
static int hsk_callback(gnutls_session_t session, unsigned int htype,
Packit Service 4684c1
			unsigned post, unsigned int incoming, const gnutls_datum_t *msg)
Packit Service 4684c1
{
Packit Service 4684c1
	assert(post == GNUTLS_HOOK_PRE);
Packit Service 4684c1
Packit Service 4684c1
	assert(msg->size == 1);
Packit Service 4684c1
Packit Service 4684c1
	if (htype == GNUTLS_HANDSHAKE_KEY_UPDATE) {
Packit Service 4684c1
		if (incoming)
Packit Service 4684c1
			key_update_msg_inc++;
Packit Service 4684c1
		else
Packit Service 4684c1
			key_update_msg_out++;
Packit Service 4684c1
	}
Packit Service 4684c1
Packit Service 4684c1
	return 0;
Packit Service 4684c1
}
Packit Service 4684c1
Packit Service 4684c1
static void run(const char *name, unsigned test)
Packit Service 4684c1
{
Packit Service 4684c1
	/* Server stuff. */
Packit Service 4684c1
	gnutls_certificate_credentials_t ccred;
Packit Service 4684c1
	gnutls_certificate_credentials_t scred;
Packit Service 4684c1
	gnutls_session_t server;
Packit Service 4684c1
	int sret, cret;
Packit Service 4684c1
	/* Client stuff. */
Packit Service 4684c1
	gnutls_session_t client;
Packit Service 4684c1
	/* Need to enable anonymous KX specifically. */
Packit Service 4684c1
	char buffer[MAX_BUF + 1];
Packit Service 4684c1
	int ret, transferred = 0;
Packit Service 4684c1
Packit Service 4684c1
	/* General init. */
Packit Service 4684c1
	global_init();
Packit Service 4684c1
	gnutls_global_set_log_function(tls_log_func);
Packit Service 4684c1
	if (debug)
Packit Service 4684c1
		gnutls_global_set_log_level(9);
Packit Service 4684c1
Packit Service 4684c1
	/* Init server */
Packit Service 4684c1
	assert(gnutls_certificate_allocate_credentials(&scred) >= 0);
Packit Service 4684c1
	assert(gnutls_certificate_set_x509_key_mem(scred,
Packit Service 4684c1
						   &server_ca3_localhost_cert,
Packit Service 4684c1
						   &server_ca3_key,
Packit Service 4684c1
						   GNUTLS_X509_FMT_PEM) >= 0);
Packit Service 4684c1
Packit Service 4684c1
	assert(gnutls_init(&server, GNUTLS_SERVER) >= 0);
Packit Service 4684c1
	ret =
Packit Service 4684c1
	    gnutls_priority_set_direct(server,
Packit Service 4684c1
				       "NORMAL:-VERS-TLS-ALL:+VERS-TLS1.3",
Packit Service 4684c1
				       NULL);
Packit Service 4684c1
	if (ret < 0)
Packit Service 4684c1
		exit(1);
Packit Service 4684c1
Packit Service 4684c1
	gnutls_credentials_set(server, GNUTLS_CRD_CERTIFICATE, scred);
Packit Service 4684c1
	gnutls_transport_set_push_function(server, server_push);
Packit Service 4684c1
	gnutls_transport_set_pull_function(server, server_pull);
Packit Service 4684c1
	gnutls_transport_set_ptr(server, server);
Packit Service 4684c1
Packit Service 4684c1
	/* Init client */
Packit Service 4684c1
	assert(gnutls_certificate_allocate_credentials(&ccred) >= 0);
Packit Service 4684c1
	assert(gnutls_certificate_set_x509_trust_mem
Packit Service 4684c1
	       (ccred, &ca3_cert, GNUTLS_X509_FMT_PEM) >= 0);
Packit Service 4684c1
Packit Service 4684c1
	gnutls_init(&client, GNUTLS_CLIENT);
Packit Service 4684c1
	ret =
Packit Service 4684c1
	    gnutls_priority_set_direct(client,
Packit Service 4684c1
				       "NORMAL:-VERS-TLS-ALL:+VERS-TLS1.3",
Packit Service 4684c1
				       NULL);
Packit Service 4684c1
	assert(ret >= 0);
Packit Service 4684c1
Packit Service 4684c1
	ret = gnutls_credentials_set(client, GNUTLS_CRD_CERTIFICATE, ccred);
Packit Service 4684c1
	if (ret < 0)
Packit Service 4684c1
		exit(1);
Packit Service 4684c1
Packit Service 4684c1
	gnutls_transport_set_push_function(client, client_push);
Packit Service 4684c1
	gnutls_transport_set_pull_function(client, client_pull);
Packit Service 4684c1
	gnutls_transport_set_ptr(client, client);
Packit Service 4684c1
Packit Service 4684c1
Packit Service 4684c1
	HANDSHAKE(client, server);
Packit Service 4684c1
	if (debug)
Packit Service 4684c1
		success("Handshake established\n");
Packit Service 4684c1
Packit Service 4684c1
	switch (test) {
Packit Service 4684c1
	case 0:
Packit Service 4684c1
	case 1:
Packit Service 4684c1
		success("%s: updating client's key\n", name);
Packit Service 4684c1
		do {
Packit Service 4684c1
			ret = gnutls_session_key_update(client, 0);
Packit Service 4684c1
		} while (ret == GNUTLS_E_AGAIN || ret == GNUTLS_E_INTERRUPTED);
Packit Service 4684c1
Packit Service 4684c1
		/* server receives the client key update and sends data */
Packit Service 4684c1
		TRANSFER(client, server, MSG, strlen(MSG), buffer, MAX_BUF);
Packit Service 4684c1
		TRANSFER(server, client, MSG, strlen(MSG), buffer, MAX_BUF);
Packit Service 4684c1
		EMPTY_BUF(server, client, buffer, MAX_BUF);
Packit Service 4684c1
		if (test != 0)
Packit Service 4684c1
			break;
Packit Service 4684c1
		sec_sleep(2);
Packit Service 4684c1
		FALLTHROUGH;
Packit Service 4684c1
	case 2:
Packit Service 4684c1
		success("%s: updating server's key\n", name);
Packit Service 4684c1
Packit Service 4684c1
		do {
Packit Service 4684c1
			ret = gnutls_session_key_update(server, 0);
Packit Service 4684c1
		} while (ret == GNUTLS_E_AGAIN || ret == GNUTLS_E_INTERRUPTED);
Packit Service 4684c1
		if (ret < 0)
Packit Service 4684c1
			fail("error in key update: %s\n", gnutls_strerror(ret));
Packit Service 4684c1
Packit Service 4684c1
		/* client receives the key update and sends data */
Packit Service 4684c1
		TRANSFER(client, server, MSG, strlen(MSG), buffer, MAX_BUF);
Packit Service 4684c1
		TRANSFER(server, client, MSG, strlen(MSG), buffer, MAX_BUF);
Packit Service 4684c1
		EMPTY_BUF(server, client, buffer, MAX_BUF);
Packit Service 4684c1
		if (test != 0)
Packit Service 4684c1
			break;
Packit Service 4684c1
		sec_sleep(2);
Packit Service 4684c1
		FALLTHROUGH;
Packit Service 4684c1
	case 3:
Packit Service 4684c1
		success("%s: updating client's key and asking server\n", name);
Packit Service 4684c1
		do {
Packit Service 4684c1
			ret = gnutls_session_key_update(client, GNUTLS_KU_PEER);
Packit Service 4684c1
		} while (ret == GNUTLS_E_AGAIN || ret == GNUTLS_E_INTERRUPTED);
Packit Service 4684c1
		if (ret < 0)
Packit Service 4684c1
			fail("error in key update: %s\n", gnutls_strerror(ret));
Packit Service 4684c1
Packit Service 4684c1
		/* server receives the client key update and sends data */
Packit Service 4684c1
		TRANSFER(client, server, MSG, strlen(MSG), buffer, MAX_BUF);
Packit Service 4684c1
		TRANSFER(server, client, MSG, strlen(MSG), buffer, MAX_BUF);
Packit Service 4684c1
		EMPTY_BUF(server, client, buffer, MAX_BUF);
Packit Service 4684c1
		if (test != 0)
Packit Service 4684c1
			break;
Packit Service 4684c1
		sec_sleep(2);
Packit Service 4684c1
		FALLTHROUGH;
Packit Service 4684c1
	case 4:
Packit Service 4684c1
		success("%s: updating server's key and asking client\n", name);
Packit Service 4684c1
		do {
Packit Service 4684c1
			ret = gnutls_session_key_update(server, GNUTLS_KU_PEER);
Packit Service 4684c1
		} while (ret == GNUTLS_E_AGAIN || ret == GNUTLS_E_INTERRUPTED);
Packit Service 4684c1
		if (ret < 0)
Packit Service 4684c1
			fail("error in key update: %s\n", gnutls_strerror(ret));
Packit Service 4684c1
Packit Service 4684c1
		TRANSFER(client, server, MSG, strlen(MSG), buffer, MAX_BUF);
Packit Service 4684c1
		TRANSFER(server, client, MSG, strlen(MSG), buffer, MAX_BUF);
Packit Service 4684c1
		EMPTY_BUF(server, client, buffer, MAX_BUF);
Packit Service 4684c1
Packit Service 4684c1
		sec_sleep(2);
Packit Service 4684c1
		break;
Packit Service 4684c1
	case 5:
Packit Service 4684c1
		success("%s: client cork\n", name);
Packit Service 4684c1
		gnutls_record_cork(client);
Packit Service 4684c1
Packit Service 4684c1
		/* server sends key update */
Packit Service 4684c1
		do {
Packit Service 4684c1
			ret = gnutls_session_key_update(server, GNUTLS_KU_PEER);
Packit Service 4684c1
		} while (ret == GNUTLS_E_AGAIN || ret == GNUTLS_E_INTERRUPTED);
Packit Service 4684c1
		if (ret < 0)
Packit Service 4684c1
			fail("error in key update: %s\n", gnutls_strerror(ret));
Packit Service 4684c1
Packit Service 4684c1
		/* client has data in the corked buffer */
Packit Service 4684c1
		do {
Packit Service 4684c1
			ret = gnutls_record_send(client, MSG, strlen(MSG));
Packit Service 4684c1
		} while (ret == GNUTLS_E_AGAIN || ret == GNUTLS_E_INTERRUPTED);
Packit Service 4684c1
		if (ret < 0)
Packit Service 4684c1
			fail("cannot send: %s\n", gnutls_strerror(ret));
Packit Service 4684c1
Packit Service 4684c1
		/* client receives key update */
Packit Service 4684c1
		EMPTY_BUF(server, client, buffer, MAX_BUF);
Packit Service 4684c1
Packit Service 4684c1
		/* client uncorks and sends key update */
Packit Service 4684c1
		do {
Packit Service 4684c1
			ret = gnutls_record_uncork(client, GNUTLS_RECORD_WAIT);
Packit Service 4684c1
		} while (ret == GNUTLS_E_AGAIN || ret == GNUTLS_E_INTERRUPTED);
Packit Service 4684c1
		if (ret < 0)
Packit Service 4684c1
			fail("cannot send: %s\n", gnutls_strerror(ret));
Packit Service 4684c1
Packit Service 4684c1
		EMPTY_BUF(server, client, buffer, MAX_BUF);
Packit Service 4684c1
Packit Service 4684c1
		sec_sleep(2);
Packit Service 4684c1
		break;
Packit Service 4684c1
	case 6:
Packit Service 4684c1
		key_update_msg_inc = 0;
Packit Service 4684c1
		key_update_msg_out = 0;
Packit Service 4684c1
Packit Service 4684c1
		success("%s: callbacks are called\n", name);
Packit Service 4684c1
Packit Service 4684c1
		gnutls_handshake_set_hook_function(client, -1, GNUTLS_HOOK_PRE, hsk_callback);
Packit Service 4684c1
		gnutls_handshake_set_hook_function(server, -1, GNUTLS_HOOK_PRE, hsk_callback);
Packit Service 4684c1
Packit Service 4684c1
		do {
Packit Service 4684c1
			ret = gnutls_session_key_update(client, GNUTLS_KU_PEER);
Packit Service 4684c1
		} while (ret == GNUTLS_E_AGAIN || ret == GNUTLS_E_INTERRUPTED);
Packit Service 4684c1
		if (ret < 0)
Packit Service 4684c1
			fail("error in key update: %s\n", gnutls_strerror(ret));
Packit Service 4684c1
Packit Service 4684c1
		/* server receives the client key update and sends data */
Packit Service 4684c1
		TRANSFER(client, server, MSG, strlen(MSG), buffer, MAX_BUF);
Packit Service 4684c1
		TRANSFER(server, client, MSG, strlen(MSG), buffer, MAX_BUF);
Packit Service 4684c1
		EMPTY_BUF(server, client, buffer, MAX_BUF);
Packit Service 4684c1
Packit Service 4684c1
		assert(key_update_msg_inc == 2);
Packit Service 4684c1
		assert(key_update_msg_out == 2);
Packit Service 4684c1
		break;
Packit Service 4684c1
	}
Packit Service 4684c1
Packit Service 4684c1
Packit Service 4684c1
	gnutls_bye(client, GNUTLS_SHUT_WR);
Packit Service 4684c1
	gnutls_bye(server, GNUTLS_SHUT_WR);
Packit Service 4684c1
Packit Service 4684c1
	gnutls_deinit(client);
Packit Service 4684c1
	gnutls_deinit(server);
Packit Service 4684c1
Packit Service 4684c1
	gnutls_certificate_free_credentials(scred);
Packit Service 4684c1
	gnutls_certificate_free_credentials(ccred);
Packit Service 4684c1
Packit Service 4684c1
	gnutls_global_deinit();
Packit Service 4684c1
	reset_buffers();
Packit Service 4684c1
}
Packit Service 4684c1
Packit Service 4684c1
void doit(void)
Packit Service 4684c1
{
Packit Service 4684c1
	run("single", 1);
Packit Service 4684c1
	run("single", 2);
Packit Service 4684c1
	run("single", 3);
Packit Service 4684c1
	run("single", 4);
Packit Service 4684c1
	run("single", 5);
Packit Service 4684c1
	run("single", 6);
Packit Service 4684c1
	run("all", 0);			/* all one after each other */
Packit Service 4684c1
}