1 /*
2  * Copyright (c) 2017, Linaro Limited
3  * All rights reserved.
4  *
5  * SPDX-License-Identifier: BSD-2-Clause
6  */
7 
8 #include <err.h>
9 #include <stdio.h>
10 #include <string.h>
11 
12 /* OP-TEE TEE client API (built by optee_client) */
13 #include <tee_client_api.h>
14 
15 /* For the UUID (found in the TA's h-file(s)) */
16 #include <hotp_ta.h>
17 
18 struct test_value {
19 	size_t count;
20 	uint32_t expected;
21 };
22 
23 /*
24  * Test values coming from the RFC4226 specification.
25  */
26 struct test_value rfc4226_test_values[] = {
27 	{ 0, 755224 },
28 	{ 1, 287082 },
29 	{ 2, 359152 },
30 	{ 3, 969429 },
31 	{ 4, 338314 },
32 	{ 5, 254676 },
33 	{ 6, 287922 },
34 	{ 7, 162583 },
35 	{ 8, 399871 },
36 	{ 9, 520489 }
37 };
38 
main(void)39 int main(void)
40 {
41 	TEEC_Context ctx;
42 	TEEC_Operation op = { 0 };
43 	TEEC_Result res;
44 	TEEC_Session sess;
45 	TEEC_UUID uuid = TA_HOTP_UUID;
46 
47 	size_t i;
48 	uint32_t err_origin;
49 	uint32_t hotp_value;
50 
51 	/*
52 	 * Shared key K ("12345678901234567890"), this is the key used in
53 	 * RFC4226 - Test Vectors.
54 	 */
55 	uint8_t K[] = {
56 		0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38,
57 		0x39, 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36,
58 		0x37, 0x38, 0x39, 0x30
59 	};
60 
61 	/* Initialize a context connecting us to the TEE */
62 	res = TEEC_InitializeContext(NULL, &ctx);
63 	if (res != TEEC_SUCCESS)
64 		errx(1, "TEEC_InitializeContext failed with code 0x%x", res);
65 
66 	res = TEEC_OpenSession(&ctx, &sess, &uuid,
67 			       TEEC_LOGIN_PUBLIC, NULL, NULL, &err_origin);
68 	if (res != TEEC_SUCCESS)
69 		errx(1, "TEEC_Opensession failed with code 0x%x origin 0x%x",
70 		     res, err_origin);
71 
72 	/* 1. Register the shared key */
73 	op.paramTypes = TEEC_PARAM_TYPES(TEEC_MEMREF_TEMP_INPUT,
74 					 TEEC_NONE, TEEC_NONE, TEEC_NONE);
75 	op.params[0].tmpref.buffer = K;
76 	op.params[0].tmpref.size = sizeof(K);
77 
78 	fprintf(stdout, "Register the shared key: %s\n", K);
79 	res = TEEC_InvokeCommand(&sess, TA_HOTP_CMD_REGISTER_SHARED_KEY,
80 				 &op, &err_origin);
81 	if (res != TEEC_SUCCESS) {
82 		fprintf(stderr, "TEEC_InvokeCommand failed with code 0x%x "
83 			"origin 0x%x\n",
84 			res, err_origin);
85 		goto exit;
86 	}
87 
88 	/* 2. Get HMAC based One Time Passwords */
89 	op.paramTypes = TEEC_PARAM_TYPES(TEEC_VALUE_OUTPUT, TEEC_NONE,
90 					 TEEC_NONE, TEEC_NONE);
91 
92 	for (i = 0; i < sizeof(rfc4226_test_values) / sizeof(struct test_value);
93 	     i++) {
94 		res = TEEC_InvokeCommand(&sess, TA_HOTP_CMD_GET_HOTP, &op,
95 					 &err_origin);
96 		if (res != TEEC_SUCCESS) {
97 			fprintf(stderr, "TEEC_InvokeCommand failed with code "
98 				"0x%x origin 0x%x\n", res, err_origin);
99 			goto exit;
100 		}
101 
102 		hotp_value = op.params[0].value.a;
103 		fprintf(stdout, "HOTP: %d\n", hotp_value);
104 
105 		if (hotp_value != rfc4226_test_values[i].expected) {
106 			fprintf(stderr, "Got unexpected HOTP from TEE! "
107 				"Expected: %d, got: %d\n",
108 				rfc4226_test_values[i].expected, hotp_value);
109 		}
110 	}
111 exit:
112 	TEEC_CloseSession(&sess);
113 	TEEC_FinalizeContext(&ctx);
114 
115 	return 0;
116 }
117