hotp: Initial commit for HMAC-OTP (RFC4226)

Add host application and a new TA that are capable of generating HMAC
based One Time Passwords according to the RFC4226 specification [1].

[1] https://www.ietf.org/rfc/rfc4226.txt

Signed-off-by: Joakim Bech <joakim.bech@linaro.org>
Tested-by: Joakim Bech <joakim.bech@linaro.org> (QEMU v7)
Acked-by: Jens Wiklander <jens.wiklander@linaro.org>
diff --git a/hotp/host/main.c b/hotp/host/main.c
new file mode 100644
index 0000000..c816b40
--- /dev/null
+++ b/hotp/host/main.c
@@ -0,0 +1,116 @@
+/*
+ * Copyright (c) 2017, Linaro Limited
+ * All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-2-Clause
+ */
+
+#include <err.h>
+#include <stdio.h>
+#include <string.h>
+
+/* OP-TEE TEE client API (built by optee_client) */
+#include <tee_client_api.h>
+
+/* For the UUID (found in the TA's h-file(s)) */
+#include <hotp_ta.h>
+
+struct test_value {
+	size_t count;
+	uint32_t expected;
+};
+
+/*
+ * Test values coming from the RFC4226 specification.
+ */
+struct test_value rfc4226_test_values[] = {
+	{ 0, 755224 },
+	{ 1, 287082 },
+	{ 2, 359152 },
+	{ 3, 969429 },
+	{ 4, 338314 },
+	{ 5, 254676 },
+	{ 6, 287922 },
+	{ 7, 162583 },
+	{ 8, 399871 },
+	{ 9, 520489 }
+};
+
+int main(int argc, char *argv[])
+{
+	TEEC_Context ctx;
+	TEEC_Operation op = { 0 };
+	TEEC_Result res;
+	TEEC_Session sess;
+	TEEC_UUID uuid = TA_HOTP_UUID;
+
+	int i;
+	uint32_t err_origin;
+	uint32_t hotp_value;
+
+	/*
+	 * Shared key K ("12345678901234567890"), this is the key used in
+	 * RFC4226 - Test Vectors.
+	 */
+	uint8_t K[] = {
+		0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38,
+		0x39, 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36,
+		0x37, 0x38, 0x39, 0x30
+	};
+
+	/* Initialize a context connecting us to the TEE */
+	res = TEEC_InitializeContext(NULL, &ctx);
+	if (res != TEEC_SUCCESS)
+		errx(1, "TEEC_InitializeContext failed with code 0x%x", res);
+
+	res = TEEC_OpenSession(&ctx, &sess, &uuid,
+			       TEEC_LOGIN_PUBLIC, NULL, NULL, &err_origin);
+	if (res != TEEC_SUCCESS)
+		errx(1, "TEEC_Opensession failed with code 0x%x origin 0x%x",
+		     res, err_origin);
+
+	/* 1. Register the shared key */
+	op.paramTypes = TEEC_PARAM_TYPES(TEEC_MEMREF_TEMP_INPUT,
+					 TEEC_NONE, TEEC_NONE, TEEC_NONE);
+	op.params[0].tmpref.buffer = K;
+	op.params[0].tmpref.size = sizeof(K);
+
+	fprintf(stdout, "Register the shared key: %s\n", K);
+	res = TEEC_InvokeCommand(&sess, TA_HOTP_CMD_REGISTER_SHARED_KEY,
+				 &op, &err_origin);
+	if (res != TEEC_SUCCESS) {
+		fprintf(stderr, "TEEC_InvokeCommand failed with code 0x%x "
+			"origin 0x%x\n",
+			res, err_origin);
+		goto exit;
+	}
+
+	/* 2. Get HMAC based One Time Passwords */
+	op.paramTypes = TEEC_PARAM_TYPES(TEEC_VALUE_OUTPUT, TEEC_NONE,
+					 TEEC_NONE, TEEC_NONE);
+
+	for (i = 0; i < sizeof(rfc4226_test_values) / sizeof(struct test_value);
+	     i++) {
+		res = TEEC_InvokeCommand(&sess, TA_HOTP_CMD_GET_HOTP, &op,
+					 &err_origin);
+		if (res != TEEC_SUCCESS) {
+			fprintf(stderr, "TEEC_InvokeCommand failed with code "
+				"0x%x origin 0x%x\n", res, err_origin);
+			goto exit;
+		}
+
+		hotp_value = op.params[0].value.a;
+		fprintf(stdout, "HOTP: %d\n", hotp_value);
+
+		if (hotp_value != rfc4226_test_values[i].expected) {
+			fprintf(stderr, "Got unexpected HOTP from TEE! "
+				"Expected: %d, got: %d\n",
+				rfc4226_test_values[i].expected, hotp_value);
+		}
+	}
+exit:
+	TEEC_CloseSession(&sess);
+	TEEC_FinalizeContext(&ctx);
+
+	return 0;
+}