text: /*
   * 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(void)
  {
  	TEEC_Context ctx;
  	TEEC_Operation op = { 0 };
  	TEEC_Result res;
  	TEEC_Session sess;
  	TEEC_UUID uuid = TA_HOTP_UUID;
  
  	size_t 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;
  }
  