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;
+}