summary refs log blame commit diff stats
path: root/libotr/libotr-4.1.1/tests/unit/test_sm.c
blob: 8f4162ab1af899fd6808c90425d3d2a65f460431 (plain) (tree)






















































































































































































































































































































































                                                                                   
/*
 * Copyright (C) 2014 - David Goulet <dgoulet@ev0ke.net>
 *
 * This program is free software; you can redistribute it and/or modify it
 * under the terms of the GNU General Public License, version 2 only, 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 <gcrypt.h>
#include <pthread.h>

#include <proto.h>
#include <sm.h>

#include <tap/tap.h>
#include <utils.h>

GCRY_THREAD_OPTION_PTHREAD_IMPL;

#define NUM_TESTS 23

/* Copied from sm.c */
static const int SM_MOD_LEN_BITS = 1536;
static const char *SM_GENERATOR_S = "0x02";
static gcry_mpi_t SM_GENERATOR = NULL;

static const int SM_MSG1_LEN = 6;
static const int SM_MSG2_LEN = 11;
static const int SM_MSG3_LEN = 8;
static const int SM_MSG4_LEN = 3;

/* Alice and Bob SM state for the SMP tests. */
static OtrlSMState *astate;
static OtrlSMState *bstate;
static const char *secret = "truie";
static unsigned char *alice_output;
static int alice_output_len;
static unsigned char *bob_output;
static int bob_output_len;

/* Stub. */
void otrl_sm_msg1_init(gcry_mpi_t **msg1);
void otrl_sm_msg2_init(gcry_mpi_t **msg2);
void otrl_sm_msg3_init(gcry_mpi_t **msg3);
void otrl_sm_msg4_init(gcry_mpi_t **msg4);
void otrl_sm_msg_free(gcry_mpi_t **message, int msglen);

static OtrlSMState *alloc_sm_state(void)
{
	OtrlSMState *smst = malloc(sizeof(*smst));
	ok(smst, "SM State allocated");

	return smst;
}

static void test_sm_state_new(void)
{
	OtrlSMState *smst;

	smst = alloc_sm_state();

	otrl_sm_state_new(smst);
	ok(!smst->secret &&
			!smst->x2 &&
			!smst->x3 &&
			!smst->g1 &&
			!smst->g2 &&
			!smst->g3 &&
			!smst->g3o &&
			!smst->p &&
			!smst->q &&
			!smst->pab &&
			!smst->qab &&
			smst->nextExpected == OTRL_SMP_EXPECT1 &&
			smst->received_question == 0 &&
			smst->sm_prog_state == OTRL_SMP_PROG_OK,
			"SM state new");

	otrl_sm_state_free(smst);
	free(smst);
}

static void test_sm_state_init(void)
{
	OtrlSMState *smst;

	smst = alloc_sm_state();

	otrl_sm_state_new(smst);
	otrl_sm_state_init(smst);
	ok(!gcry_mpi_cmp(smst->secret, gcry_mpi_snew(SM_MOD_LEN_BITS)) &&
			!smst->x2 &&
			!smst->x3 &&
			!gcry_mpi_cmp(smst->g1, gcry_mpi_copy(SM_GENERATOR)) &&
			!gcry_mpi_cmp(smst->g2, gcry_mpi_new(SM_MOD_LEN_BITS)) &&
			!gcry_mpi_cmp(smst->g3, gcry_mpi_new(SM_MOD_LEN_BITS)) &&
			!gcry_mpi_cmp(smst->g3o, gcry_mpi_new(SM_MOD_LEN_BITS)) &&
			!gcry_mpi_cmp(smst->p, gcry_mpi_new(SM_MOD_LEN_BITS)) &&
			!gcry_mpi_cmp(smst->q, gcry_mpi_new(SM_MOD_LEN_BITS)) &&
			!gcry_mpi_cmp(smst->pab, gcry_mpi_new(SM_MOD_LEN_BITS)) &&
			!gcry_mpi_cmp(smst->qab, gcry_mpi_new(SM_MOD_LEN_BITS)) &&
			smst->nextExpected == OTRL_SMP_EXPECT1 &&
			smst->received_question == 0 &&
			smst->sm_prog_state == OTRL_SMP_PROG_OK,
			"SM state init");

	otrl_sm_state_free(smst);
	free(smst);
}

static void test_sm_msg1_init(void)
{
	gcry_mpi_t *msg;

	otrl_sm_msg1_init(&msg);
	ok(msg &&
			!gcry_mpi_cmp(msg[0], gcry_mpi_new(SM_MOD_LEN_BITS)) &&
			!msg[1] &&
			!gcry_mpi_cmp(msg[2], gcry_mpi_new(SM_MOD_LEN_BITS)) &&
			!gcry_mpi_cmp(msg[3], gcry_mpi_new(SM_MOD_LEN_BITS)) &&
			!msg[4] &&
			!gcry_mpi_cmp(msg[5], gcry_mpi_new(SM_MOD_LEN_BITS)),
			"SM msg1 initialized");
	otrl_sm_msg_free(&msg, SM_MSG1_LEN);
	/* Test once here. */
	ok(!msg, "SM msg1 freed");
}

static void test_sm_msg2_init(void)
{
	gcry_mpi_t *msg;

	otrl_sm_msg2_init(&msg);
	ok(msg &&
			!gcry_mpi_cmp(msg[0], gcry_mpi_new(SM_MOD_LEN_BITS)) &&
			!msg[1] &&
			!gcry_mpi_cmp(msg[2], gcry_mpi_new(SM_MOD_LEN_BITS)) &&
			!gcry_mpi_cmp(msg[3], gcry_mpi_new(SM_MOD_LEN_BITS)) &&
			!msg[4] &&
			!gcry_mpi_cmp(msg[5], gcry_mpi_new(SM_MOD_LEN_BITS)) &&
			!gcry_mpi_cmp(msg[6], gcry_mpi_new(SM_MOD_LEN_BITS)) &&
			!gcry_mpi_cmp(msg[7], gcry_mpi_new(SM_MOD_LEN_BITS)) &&
			!msg[8] &&
			!gcry_mpi_cmp(msg[9], gcry_mpi_new(SM_MOD_LEN_BITS)) &&
			!gcry_mpi_cmp(msg[10], gcry_mpi_new(SM_MOD_LEN_BITS)),
			"SM msg2 initialized");
	otrl_sm_msg_free(&msg, SM_MSG2_LEN);
}

static void test_sm_msg3_init(void)
{
	gcry_mpi_t *msg;

	otrl_sm_msg3_init(&msg);
	ok(msg &&
			!gcry_mpi_cmp(msg[0], gcry_mpi_new(SM_MOD_LEN_BITS)) &&
			!gcry_mpi_cmp(msg[1], gcry_mpi_new(SM_MOD_LEN_BITS)) &&
			!msg[2] &&
			!gcry_mpi_cmp(msg[3], gcry_mpi_new(SM_MOD_LEN_BITS)) &&
			!gcry_mpi_cmp(msg[4], gcry_mpi_new(SM_MOD_LEN_BITS)) &&
			!gcry_mpi_cmp(msg[5], gcry_mpi_new(SM_MOD_LEN_BITS)) &&
			!msg[6] &&
			!gcry_mpi_cmp(msg[7], gcry_mpi_new(SM_MOD_LEN_BITS)),
			"SM msg3 initialized");
	otrl_sm_msg_free(&msg, SM_MSG3_LEN);
}

static void test_sm_msg4_init(void)
{
	gcry_mpi_t *msg;

	otrl_sm_msg4_init(&msg);
	ok(msg &&
			!gcry_mpi_cmp(msg[0], gcry_mpi_new(SM_MOD_LEN_BITS)) &&
			!msg[1] &&
			!gcry_mpi_cmp(msg[2], gcry_mpi_new(SM_MOD_LEN_BITS)),
			"SM msg4 initialized");
	otrl_sm_msg_free(&msg, SM_MSG4_LEN);
}

static void test_sm_step1(void)
{
	gcry_error_t err;
	unsigned char hash_secret[SM_DIGEST_SIZE];

	astate = alloc_sm_state();
	otrl_sm_state_new(astate);
	otrl_sm_state_init(astate);

	gcry_md_hash_buffer(SM_HASH_ALGORITHM, hash_secret, secret,
			strlen(secret));

	err = otrl_sm_step1(astate, hash_secret, sizeof(hash_secret),
			&alice_output, &alice_output_len);
	ok(err == GPG_ERR_NO_ERROR, "SMP step1 success");

	gcry_mpi_t secret_mpi;
	gcry_mpi_scan(&secret_mpi, GCRYMPI_FMT_USG, hash_secret,
			sizeof(hash_secret), NULL);
	ok(!gcry_mpi_cmp(astate->secret, secret_mpi) &&
			astate->received_question == 0 &&
			astate->x2 &&
			astate->x3 &&
			astate->sm_prog_state == OTRL_SMP_PROG_OK &&
			alice_output && alice_output_len > 0,
			"SMP step 1 validated");
	gcry_mpi_release(secret_mpi);
}

static void test_sm_step2a(void)
{
	gcry_error_t err;

	bstate = alloc_sm_state();
	otrl_sm_state_new(bstate);
	otrl_sm_state_init(bstate);

	err = otrl_sm_step2a(bstate, alice_output, alice_output_len, 1);
	ok(err == GPG_ERR_NO_ERROR, "SMP step2a success");

	ok(bstate->received_question == 1 &&
			bstate->sm_prog_state == OTRL_SMP_PROG_OK &&
			bstate->g3o &&
			bstate->x2 &&
			bstate->x3,
			"SMP step2a validate");
}

static void test_sm_step2b(void)
{
	gcry_error_t err;
	unsigned char hash_secret[SM_DIGEST_SIZE];

	gcry_md_hash_buffer(SM_HASH_ALGORITHM, hash_secret, secret,
			strlen(secret));

	err = otrl_sm_step2b(bstate, hash_secret, sizeof(hash_secret), &bob_output,
			&bob_output_len);
	ok(err == GPG_ERR_NO_ERROR, "SMP step2b success");

	/* Generate expected data. */
	gcry_mpi_t secret_mpi;
	gcry_mpi_scan(&secret_mpi, GCRYMPI_FMT_USG, hash_secret,
			sizeof(hash_secret), NULL);
	ok(bob_output && bob_output_len > 0 &&
			!gcry_mpi_cmp(bstate->secret, secret_mpi) &&
			bstate->p &&
			bstate->q,
			"SMP step2b validate");
	gcry_mpi_release(secret_mpi);
}

static void test_sm_step3(void)
{
	gcry_error_t err;

	free(alice_output);

	err = otrl_sm_step3(astate, bob_output, bob_output_len, &alice_output,
			&alice_output_len);
	ok(err == GPG_ERR_NO_ERROR, "SMP step3 success");

	ok(alice_output && alice_output_len > 0 &&
			astate->sm_prog_state == OTRL_SMP_PROG_OK &&
			astate->g3o &&
			astate->g2 &&
			astate->g3 &&
			astate->p &&
			astate->q &&
			astate->qab &&
			astate->pab,
			"SMP step3 validate");
}

static void test_sm_step4(void)
{
	gcry_error_t err;

	free(bob_output);

	err = otrl_sm_step4(bstate, alice_output, alice_output_len, &bob_output,
			&bob_output_len);
	ok(err == gcry_error(GPG_ERR_NO_ERROR), "SMP step4 success");

	ok(bob_output && bob_output_len > 0 &&
			bstate->sm_prog_state == OTRL_SMP_PROG_SUCCEEDED &&
			bstate->pab &&
			bstate->qab,
			"SMP step4 validate");
}

static void test_sm_step5(void)
{
	gcry_error_t err;

	err = otrl_sm_step5(astate, bob_output, bob_output_len);
	ok(err == gcry_error(GPG_ERR_NO_ERROR), "SMP step5 success");

	ok(astate && astate->sm_prog_state == OTRL_SMP_PROG_SUCCEEDED,
			"SMP step5 validate");
}

int main(int argc, char **argv)
{
	/* Libtap call for the number of tests planned. */
	plan_tests(NUM_TESTS);

	gcry_control(GCRYCTL_SET_THREAD_CBS, &gcry_threads_pthread);
	OTRL_INIT;

	/* Initialize sm subsystem. We can't really unit test that because every
	 * value that is being initialized is static to sm.c. */
	otrl_sm_init();

	/* Init variables we need for testing. */
	gcry_mpi_scan(&SM_GENERATOR, GCRYMPI_FMT_HEX,
			(const unsigned char *)SM_GENERATOR_S, 0, NULL);

	test_sm_state_new();
	test_sm_state_init();
	test_sm_msg1_init();
	test_sm_msg2_init();
	test_sm_msg3_init();
	test_sm_msg4_init();

	test_sm_step1();
	test_sm_step2a();
	test_sm_step2b();
	test_sm_step3();
	test_sm_step4();
	test_sm_step5();

	return 0;
}