summary refs log tree commit diff stats
path: root/libotr/libotr-4.1.1/tests/unit/test_proto.c
diff options
context:
space:
mode:
Diffstat (limited to 'libotr/libotr-4.1.1/tests/unit/test_proto.c')
-rw-r--r--libotr/libotr-4.1.1/tests/unit/test_proto.c371
1 files changed, 371 insertions, 0 deletions
diff --git a/libotr/libotr-4.1.1/tests/unit/test_proto.c b/libotr/libotr-4.1.1/tests/unit/test_proto.c
new file mode 100644
index 0000000..5b522ef
--- /dev/null
+++ b/libotr/libotr-4.1.1/tests/unit/test_proto.c
@@ -0,0 +1,371 @@
+/*
+ * Copyright (C) 2014 - Julien Voisin <julien.voisin@dustri.org>
+ *
+ * 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 <limits.h>
+#include <pthread.h>
+
+#include <proto.h>
+
+#include <tap/tap.h>
+
+GCRY_THREAD_OPTION_PTHREAD_IMPL;
+
+#define NUM_TESTS 48
+
+static ConnContext *new_context(const char *user, const char *accountname,
+		const char *protocol)
+{
+	ConnContext *context;
+	OtrlSMState *smstate;
+
+	context = malloc(sizeof(ConnContext));
+
+	context->username = strdup(user);
+	context->accountname = strdup(accountname);
+	context->protocol = strdup(protocol);
+
+	context->msgstate = OTRL_MSGSTATE_PLAINTEXT;
+	otrl_auth_new(context);
+
+	smstate = malloc(sizeof(OtrlSMState));
+	otrl_sm_state_new(smstate);
+	context->smstate = smstate;
+
+	context->our_instance = 0;
+	context->their_instance = OTRL_INSTAG_MASTER;
+	context->fingerprint_root.fingerprint = NULL;
+	context->fingerprint_root.context = context;
+	context->fingerprint_root.next = NULL;
+	context->fingerprint_root.tous = NULL;
+	context->active_fingerprint = NULL;
+	memset(context->sessionid, 0, 20);
+	context->sessionid_len = 0;
+	context->protocol_version = 0;
+	context->otr_offer = OFFER_NOT;
+	context->app_data = NULL;
+	context->app_data_free = NULL;
+	context->context_priv = otrl_context_priv_new();
+	context->next = NULL;
+	context->m_context = context;
+	context->recent_rcvd_child = NULL;
+	context->recent_sent_child = NULL;
+	context->recent_child = NULL;
+
+	return context;
+}
+
+static void test_otrl_proto_whitespace_bestversion(void)
+{
+	unsigned int ret;
+	const char *start, *end;
+	const char *test1 = OTRL_MESSAGE_TAG_BASE OTRL_MESSAGE_TAG_V2;
+	const char *test2 = OTRL_MESSAGE_TAG_BASE OTRL_MESSAGE_TAG_V3;
+	const char *test3 = OTRL_MESSAGE_TAG_BASE "foobar";
+
+	ret = otrl_proto_whitespace_bestversion(test1, &start, &end,
+			OTRL_POLICY_ALLOW_V2);
+	ok(ret == 2, "Best version whitespace v2");
+
+	ret = otrl_proto_whitespace_bestversion(test1, &start, &end,
+			OTRL_POLICY_ALLOW_V2 | OTRL_POLICY_ALLOW_V3);
+	ok(ret == 2, "Best version whitespace v2 dual policy");
+
+	ret = otrl_proto_whitespace_bestversion(test2, &start, &end,
+			OTRL_POLICY_ALLOW_V3);
+	ok(ret == 3, "Best version whitespace v3");
+
+	ret = otrl_proto_whitespace_bestversion(test2, &start, &end,
+			OTRL_POLICY_ALLOW_V2 | OTRL_POLICY_ALLOW_V3);
+	ok(ret == 3, "Best version whitespace v3 dual policy");
+
+	ret = otrl_proto_whitespace_bestversion(test3, &start, &end,
+			OTRL_POLICY_ALLOW_V2 | OTRL_POLICY_ALLOW_V3);
+	ok(ret == 0, "Best version whitespace invalid");
+}
+
+static void test_otrl_proto_query_bestversion(void)
+{
+	const char *query2 = "?OTRv2?\n<b>alice</b> has requested an "
+		"<a href=\"https://otr.cypherpunks.ca/\">Off-the-Record "
+		"private conversation</a>.  However, you do not have a plugin "
+		"to support that.\nSee <a href=\"https://otr.cypherpunks.ca/\">"
+		"https://otr.cypherpunks.ca/</a> for more information.";
+
+	const char *query23 = "?OTRv23?\n<b>alice</b> has requested an "
+		"<a href=\"https://otr.cypherpunks.ca/\">Off-the-Record "
+		"private conversation</a>.  However, you do not have a plugin "
+		"to support that.\nSee <a href=\"https://otr.cypherpunks.ca/\">"
+		"https://otr.cypherpunks.ca/</a> for more information.";
+
+	const char *query3 = "?OTRv3?\n<b>alice</b> has requested an "
+		"<a href=\"https://otr.cypherpunks.ca/\">Off-the-Record "
+		"private conversation</a>.  However, you do not have a plugin "
+		"to support that.\nSee <a href=\"https://otr.cypherpunks.ca/\">"
+		"https://otr.cypherpunks.ca/</a> for more information.";
+
+	ok(otrl_proto_query_bestversion(query2, OTRL_POLICY_ALLOW_V2) == 2,
+			"The best from query2 is 2");
+	ok(otrl_proto_query_bestversion(query3, OTRL_POLICY_ALLOW_V3) == 3,
+			"The best from query3 is 3");
+	ok(otrl_proto_query_bestversion(query23, OTRL_POLICY_ALLOW_V2) == 2,
+			"The best from query23 is 2");
+	ok(otrl_proto_query_bestversion(query23, OTRL_POLICY_ALLOW_V3) == 3,
+			"The best from query23 is 3");
+}
+
+static void test_otrl_proto_default_query_msg(void)
+{
+	const char *expected2 = "?OTRv2?\n<b>alice</b> has requested an "
+		"<a href=\"https://otr.cypherpunks.ca/\">Off-the-Record "
+		"private conversation</a>.  However, you do not have a plugin "
+		"to support that.\nSee <a href=\"https://otr.cypherpunks.ca/\">"
+		"https://otr.cypherpunks.ca/</a> for more information.";
+
+	const char *expected23 = "?OTRv23?\n<b>alice</b> has requested an "
+		"<a href=\"https://otr.cypherpunks.ca/\">Off-the-Record "
+		"private conversation</a>.  However, you do not have a plugin "
+		"to support that.\nSee <a href=\"https://otr.cypherpunks.ca/\">"
+		"https://otr.cypherpunks.ca/</a> for more information.";
+
+	const char *expected3 = "?OTRv3?\n<b>alice</b> has requested an "
+		"<a href=\"https://otr.cypherpunks.ca/\">Off-the-Record "
+		"private conversation</a>.  However, you do not have a plugin "
+		"to support that.\nSee <a href=\"https://otr.cypherpunks.ca/\">"
+		"https://otr.cypherpunks.ca/</a> for more information.";
+
+	const char *msg2 = otrl_proto_default_query_msg("alice",
+			OTRL_POLICY_ALLOW_V2);
+	const char *msg23 = otrl_proto_default_query_msg("alice",
+			OTRL_POLICY_ALLOW_V2 | OTRL_POLICY_ALLOW_V3);
+	const char *msg3 = otrl_proto_default_query_msg("alice",
+			OTRL_POLICY_ALLOW_V3);
+	ok(strcmp(expected2, msg2) == 0, "OTRv2 default query message is valid");
+	ok(strcmp(expected23, msg23) == 0,
+			"OTRv23 default query message is valid");
+	ok(strcmp(expected3, msg3) == 0, "OTRv3 default query message is valid");
+}
+
+void test_otrl_init(void)
+{
+	extern unsigned int otrl_api_version;
+
+	const unsigned int expected = rand();
+	otrl_api_version = expected;
+	ok(otrl_init(OTRL_VERSION_MAJOR+1, 0, 0) == gcry_error(GPG_ERR_INV_VALUE),
+			"Too recent major version");
+	ok(otrl_api_version == expected, "Api number unchanged");
+
+	ok(otrl_init(OTRL_VERSION_MAJOR-1, 0, 0) == gcry_error(GPG_ERR_INV_VALUE),
+			"Too old major version");
+	ok(otrl_api_version == expected, "Api number unchanged");
+
+	ok(otrl_init(OTRL_VERSION_MAJOR, OTRL_VERSION_MINOR+1, 0)
+			== gcry_error(GPG_ERR_INV_VALUE),
+			"Too recent minor version");
+	ok(otrl_api_version = expected, "Api number unchanged");
+
+	ok(otrl_init(OTRL_VERSION_MAJOR, OTRL_VERSION_MINOR?OTRL_VERSION_MINOR-1:0,
+			OTRL_VERSION_SUB) == gcry_error(GPG_ERR_NO_ERROR),
+			"Inferior minor version");
+	ok(otrl_api_version = expected, "Api number unchanged");
+
+	otrl_api_version = 0;
+
+	ok(otrl_init(OTRL_VERSION_MAJOR, OTRL_VERSION_MINOR, OTRL_VERSION_SUB)
+			== gcry_error(GPG_ERR_NO_ERROR), "Exact version");
+	ok(otrl_api_version == (
+				(OTRL_VERSION_MAJOR << 16) |
+				(OTRL_VERSION_MINOR << 8) |
+				(OTRL_VERSION_SUB)
+				), "Api version set for exact version");
+}
+
+static void test_otrl_proto_message_type(void)
+{
+	OtrlMessageType ret;
+
+	const char *test1 = "This is plaintext";
+	ret = otrl_proto_message_type(test1);
+	ok(ret == OTRL_MSGTYPE_NOTOTR, "Proto message type is not OTR");
+
+	const char *test2 = OTRL_MESSAGE_TAG_BASE "This is plaintext";
+	ret = otrl_proto_message_type(test2);
+	ok(ret == OTRL_MSGTYPE_TAGGEDPLAINTEXT,
+			"Proto message type is tagged plaintext");
+
+	const char *test3 = "?OTR:AAIC";
+	ret = otrl_proto_message_type(test3);
+	ok(ret == OTRL_MSGTYPE_DH_COMMIT, "Proto message type v2 is dh commit");
+
+	const char *test4 = "?OTR:AAMC";
+	ret = otrl_proto_message_type(test4);
+	ok(ret == OTRL_MSGTYPE_DH_COMMIT, "Proto message type v3 is dh commit");
+
+	const char *test5 = "?OTR:AAIK";
+	ret = otrl_proto_message_type(test5);
+	ok(ret == OTRL_MSGTYPE_DH_KEY, "Proto message type v2 is DH key");
+
+	const char *test6 = "?OTR:AAMK";
+	ret = otrl_proto_message_type(test6);
+	ok(ret == OTRL_MSGTYPE_DH_KEY, "Proto message type v3 is DH key");
+
+	const char *test7 = "?OTR:AAIR";
+	ret = otrl_proto_message_type(test7);
+	ok(ret == OTRL_MSGTYPE_REVEALSIG, "Proto message type v2 is revealsig");
+
+	const char *test8 = "?OTR:AAMR";
+	ret = otrl_proto_message_type(test8);
+	ok(ret == OTRL_MSGTYPE_REVEALSIG, "Proto message type v3 is revealsig");
+
+	const char *test9 = "?OTR:AAIS";
+	ret = otrl_proto_message_type(test9);
+	ok(ret == OTRL_MSGTYPE_SIGNATURE, "Proto message type v2 is a signature");
+
+	const char *test10 = "?OTR:AAMS";
+	ret = otrl_proto_message_type(test10);
+	ok(ret == OTRL_MSGTYPE_SIGNATURE, "Proto message type v3 is a signature");
+
+	const char *test11 = "?OTR:AAID";
+	ret = otrl_proto_message_type(test11);
+	ok(ret == OTRL_MSGTYPE_DATA, "Proto message type v2 is a data msg");
+
+	const char *test12 = "?OTR:AAMD";
+	ret = otrl_proto_message_type(test12);
+	ok(ret == OTRL_MSGTYPE_DATA, "Proto message type v3 is a data msg");
+
+	const char *test13 = "?OTR?";
+	ret = otrl_proto_message_type(test13);
+	ok(ret == OTRL_MSGTYPE_QUERY, "Proto message type is a query");
+
+	const char *test14 = "?OTR?v";
+	ret = otrl_proto_message_type(test14);
+	ok(ret == OTRL_MSGTYPE_QUERY, "Proto message type is a query");
+
+	const char *test15 = "?OTR Error:";
+	ret = otrl_proto_message_type(test15);
+	ok(ret == OTRL_MSGTYPE_ERROR, "Proto message type is an error");
+
+	const char *test16 = "?OTR: Please verify me";
+	ret = otrl_proto_message_type(test16);
+	ok(ret == OTRL_MSGTYPE_UNKNOWN, "Proto message type is unknown");
+
+	const char *test17 = "?OTR:AAMA";
+	ret = otrl_proto_message_type(test17);
+	ok(ret == OTRL_MSGTYPE_UNKNOWN, "Proto message type is unknown");
+}
+
+static void test_otrl_proto_message_version(void)
+{
+	int ret;
+
+	const char *test1 = "?OTR:AAI";
+	ret = otrl_proto_message_version(test1);
+	ok(ret == 2, "Protocol message version is 2");
+
+	const char *test2 = "?OTR:AAM";
+	ret = otrl_proto_message_version(test2);
+	ok(ret == 3, "Protocol message version is 3");
+
+	const char *test3 = "?OTR:BLAH";
+	ret = otrl_proto_message_version(test3);
+	ok(ret == 0, "Protocol message version is unknown");
+}
+
+static void test_otrl_proto_instance(void)
+{
+	/* Canary that shouldn't get modified on error. */
+	unsigned int inst_from = 42, inst_to = 42;
+	gcry_error_t ret;
+
+	/*
+	 * Instance tags only supported in protocol v3 (AAM in b64).  The msg type
+	 * here is "A" which does not represent a valid one but we don't care
+	 * followed by the Sender Instance set to 1 and Receiver Instance set to 2.
+	 */
+	const char *test1 = "?OTR:AAMAAAAAAQAAAAI==";
+	ret = otrl_proto_instance(test1, &inst_from, &inst_to);
+	ok(ret == gcry_error(GPG_ERR_NO_ERROR)
+		&& inst_from == 1
+		&& inst_to == 2,
+		"Proto instance find for v3");
+
+	/* Reset canary. */
+	inst_from = inst_to = 42;
+
+	/* Len is not enough here. */
+	const char *test2 = "?OTR:AAMAAA=";
+	ret = otrl_proto_instance(test2, &inst_from, &inst_to);
+	ok(ret == gcry_error(GPG_ERR_INV_VALUE)
+		&& inst_from == 42
+		&& inst_to == 42, "Proto instance failed for v3");
+
+	/* Reset canary. */
+	inst_from = inst_to = 42;
+
+	/* Message from protocol v2. */
+	const char *test3 = "?OTR:AAIAAAAAAQAAAAI==";
+	ret = otrl_proto_instance(test3, &inst_from, &inst_to);
+	ok(ret == gcry_error(GPG_ERR_INV_VALUE)
+			&& inst_from == 42
+			&& inst_to == 42, "Proto instance failed for v2");
+}
+
+static void test_otrl_version(void)
+{
+	ok(strcmp(otrl_version(), OTRL_VERSION) == 0, "Otrl version OK");
+}
+
+static void test_otrl_proto_create_data(void)
+{
+	char *encmessagep = NULL, *msg = "HELO";
+	unsigned char flags = 12;
+	unsigned char *extrakey = NULL;
+	OtrlTLV *tlvs = NULL;
+	ConnContext *context =
+		new_context("Alice", "Alice's account", "Secret protocol");
+
+	context->msgstate = OTRL_MSGSTATE_PLAINTEXT;
+	ok(otrl_proto_create_data(&encmessagep, context, msg, tlvs, flags,
+			extrakey) == gcry_error(GPG_ERR_CONFLICT),
+			"Conflict detected for msgstate plaintext");
+
+	context->msgstate = OTRL_MSGSTATE_ENCRYPTED;
+	context->context_priv->their_keyid = 0;
+	ok(otrl_proto_create_data(&encmessagep, context, msg, tlvs, flags,
+			extrakey) == gcry_error(GPG_ERR_CONFLICT),
+			"Conflict detected for msgstate encrypted");
+}
+
+int main(int argc, char **argv)
+{
+	plan_tests(NUM_TESTS);
+
+	gcry_control(GCRYCTL_SET_THREAD_CBS, &gcry_threads_pthread);
+	OTRL_INIT;
+
+	test_otrl_proto_default_query_msg();
+	test_otrl_proto_query_bestversion();
+	test_otrl_init();
+	test_otrl_proto_whitespace_bestversion();
+	test_otrl_proto_message_type();
+	test_otrl_proto_message_version();
+	test_otrl_proto_instance();
+	test_otrl_version();
+	test_otrl_proto_create_data();
+
+	return 0;
+}