/* ********************************************************************** * Copyright (C) Miroslav Lichvar 2020 * * This program is free software; you can redistribute it and/or modify * it under the terms of version 2 of the GNU General Public License as * published by the Free Software Foundation. * * This program 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 this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * ********************************************************************** */ #include #include "test.h" #ifdef FEAT_NTS #include #include #include #include static NKSN_Instance client, server; static unsigned char record[NKE_MAX_MESSAGE_LENGTH]; static int record_length, critical, type_start, records; static int request_received; static int response_received; static void send_message(NKSN_Instance inst) { int i; record_length = random() % (NKE_MAX_MESSAGE_LENGTH - 4 + 1); for (i = 0; i < record_length; i++) record[i] = random() % 256; critical = random() % 2; type_start = random() % 30000 + 1; assert(sizeof (struct RecordHeader) == 4); records = random() % ((NKE_MAX_MESSAGE_LENGTH - 4) / (4 + record_length) + 1); DEBUG_LOG("critical=%d type_start=%d records=%d*%d", critical, type_start, records, record_length); NKSN_BeginMessage(inst); TEST_CHECK(check_message_format(&inst->message, 0)); TEST_CHECK(!check_message_format(&inst->message, 1)); TEST_CHECK(!NKSN_AddRecord(inst, 0, 1, record, NKE_MAX_MESSAGE_LENGTH - 4 + 1)); TEST_CHECK(check_message_format(&inst->message, 0)); TEST_CHECK(!check_message_format(&inst->message, 1)); for (i = 0; i < records; i++) { TEST_CHECK(NKSN_AddRecord(inst, critical, type_start + i, record, record_length)); TEST_CHECK(!NKSN_AddRecord(inst, 0, 1, &record, NKE_MAX_MESSAGE_LENGTH - inst->message.length - 4 + 1)); TEST_CHECK(check_message_format(&inst->message, 0)); TEST_CHECK(!check_message_format(&inst->message, 1)); } TEST_CHECK(NKSN_EndMessage(inst)); TEST_CHECK(check_message_format(&inst->message, 0)); TEST_CHECK(check_message_format(&inst->message, 1)); } static void verify_message(NKSN_Instance inst) { unsigned char buffer[NKE_MAX_MESSAGE_LENGTH]; int i, c, t, length, buffer_length, msg_length, prev_parsed; NKE_Key c2s, s2c; for (i = 0; i < records; i++) { memset(buffer, 0, sizeof (buffer)); buffer_length = random() % (record_length + 1); assert(buffer_length <= sizeof (buffer)); prev_parsed = inst->message.parsed; msg_length = inst->message.length; TEST_CHECK(NKSN_GetRecord(inst, &c, &t, &length, buffer, buffer_length)); TEST_CHECK(c == critical); TEST_CHECK(t == type_start + i); TEST_CHECK(length == record_length); TEST_CHECK(memcmp(record, buffer, buffer_length) == 0); if (buffer_length < record_length) TEST_CHECK(buffer[buffer_length] == 0); inst->message.length = inst->message.parsed - 1; inst->message.parsed = prev_parsed; TEST_CHECK(!get_record(&inst->message, NULL, NULL, NULL, buffer, buffer_length)); TEST_CHECK(inst->message.parsed == prev_parsed); inst->message.length = msg_length; if (msg_length < 0x8000) { inst->message.data[prev_parsed + 2] ^= 0x80; TEST_CHECK(!get_record(&inst->message, NULL, NULL, NULL, buffer, buffer_length)); TEST_CHECK(inst->message.parsed == prev_parsed); inst->message.data[prev_parsed + 2] ^= 0x80; } TEST_CHECK(get_record(&inst->message, NULL, NULL, NULL, buffer, buffer_length)); TEST_CHECK(inst->message.parsed > prev_parsed); } TEST_CHECK(!NKSN_GetRecord(inst, &critical, &t, &length, buffer, sizeof (buffer))); TEST_CHECK(NKSN_GetKeys(inst, AEAD_AES_SIV_CMAC_256, &c2s, &s2c)); TEST_CHECK(c2s.length == SIV_GetKeyLength(AEAD_AES_SIV_CMAC_256)); TEST_CHECK(s2c.length == SIV_GetKeyLength(AEAD_AES_SIV_CMAC_256)); } static int handle_request(void *arg) { NKSN_Instance server = arg; verify_message(server); request_received = 1; send_message(server); return 1; } static int handle_response(void *arg) { NKSN_Instance client = arg; response_received = 1; verify_message(client); return 1; } static void check_finished(void *arg) { DEBUG_LOG("checking for stopped sessions"); if (!NKSN_IsStopped(server) || !NKSN_IsStopped(client)) { SCH_AddTimeoutByDelay(0.001, check_finished, NULL); return; } SCH_QuitProgram(); } void test_unit(void) { NKSN_Credentials client_cred, server_cred; const char *cert, *key; int sock_fds[2], i; uint32_t cert_id; LCL_Initialise(); TST_RegisterDummyDrivers(); cert = "nts_ke.crt"; key = "nts_ke.key"; cert_id = 0; for (i = 0; i < 50; i++) { SCH_Initialise(); server = NKSN_CreateInstance(1, NULL, handle_request, NULL); client = NKSN_CreateInstance(0, "test", handle_response, NULL); server_cred = NKSN_CreateServerCertCredentials(&cert, &key, 1); client_cred = NKSN_CreateClientCertCredentials(&cert, &cert_id, 1, 0); TEST_CHECK(socketpair(AF_UNIX, SOCK_STREAM, 0, sock_fds) == 0); TEST_CHECK(fcntl(sock_fds[0], F_SETFL, O_NONBLOCK) == 0); TEST_CHECK(fcntl(sock_fds[1], F_SETFL, O_NONBLOCK) == 0); TEST_CHECK(NKSN_StartSession(server, sock_fds[0], "client", server_cred, 4.0)); TEST_CHECK(NKSN_StartSession(client, sock_fds[1], "server", client_cred, 4.0)); send_message(client); request_received = response_received = 0; check_finished(NULL); SCH_MainLoop(); TEST_CHECK(NKSN_IsStopped(server)); TEST_CHECK(NKSN_IsStopped(client)); TEST_CHECK(request_received); TEST_CHECK(response_received); NKSN_DestroyInstance(server); NKSN_DestroyInstance(client); NKSN_DestroyCertCredentials(server_cred); NKSN_DestroyCertCredentials(client_cred); SCH_Finalise(); } LCL_Finalise(); } #else void test_unit(void) { TEST_REQUIRE(0); } #endif