1 /*
2  * Copyright (c) 2017, Linaro Limited
3  * All rights reserved.
4  *
5  * SPDX-License-Identifier: BSD-2-Clause
6  */
7 #include <hotp_ta.h>
8 #include <string.h>
9 #include <tee_internal_api_extensions.h>
10 #include <tee_internal_api.h>
11 
12 /* The size of a SHA1 hash in bytes. */
13 #define SHA1_HASH_SIZE 20
14 
15 /* GP says that for HMAC SHA-1, max is 512 bits and min 80 bits. */
16 #define MAX_KEY_SIZE 64 /* In bytes */
17 #define MIN_KEY_SIZE 10 /* In bytes */
18 
19 /* Dynamic Binary Code 2 Modulo, which is 10^6 according to the spec. */
20 #define DBC2_MODULO 1000000
21 
22 /*
23  * Currently this only supports a single key, in the future this could be
24  * updated to support multiple users, all with different unique keys (stored
25  * using secure storage).
26  */
27 static uint8_t K[MAX_KEY_SIZE];
28 static uint32_t K_len;
29 
30 /* The counter as defined by RFC4226. */
31 static uint8_t counter[] = { 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0 };
32 
33 /*
34  *  HMAC a block of memory to produce the authentication tag
35  *  @param key       The secret key
36  *  @param keylen    The length of the secret key (bytes)
37  *  @param in        The data to HMAC
38  *  @param inlen     The length of the data to HMAC (bytes)
39  *  @param out       [out] Destination of the authentication tag
40  *  @param outlen    [in/out] Max size and resulting size of authentication tag
41  */
hmac_sha1(const uint8_t * key,const size_t keylen,const uint8_t * in,const size_t inlen,uint8_t * out,uint32_t * outlen)42 static TEE_Result hmac_sha1(const uint8_t *key, const size_t keylen,
43 			    const uint8_t *in, const size_t inlen,
44 			    uint8_t *out, uint32_t *outlen)
45 {
46 	TEE_Attribute attr = { 0 };
47 	TEE_ObjectHandle key_handle = TEE_HANDLE_NULL;
48 	TEE_OperationHandle op_handle = TEE_HANDLE_NULL;
49 	TEE_Result res = TEE_SUCCESS;
50 
51 	if (keylen < MIN_KEY_SIZE || keylen > MAX_KEY_SIZE)
52 		return TEE_ERROR_BAD_PARAMETERS;
53 
54 	if (!in || !out || !outlen)
55 		return TEE_ERROR_BAD_PARAMETERS;
56 
57 	/*
58 	 * 1. Allocate cryptographic (operation) handle for the HMAC operation.
59 	 *    Note that the expected size here is in bits (and therefore times
60 	 *    8)!
61 	 */
62 	res = TEE_AllocateOperation(&op_handle, TEE_ALG_HMAC_SHA1, TEE_MODE_MAC,
63 				    keylen * 8);
64 	if (res != TEE_SUCCESS) {
65 		EMSG("0x%08x", res);
66 		goto exit;
67 	}
68 
69 	/*
70 	 * 2. Allocate a container (key handle) for the HMAC attributes. Note
71 	 *    that the expected size here is in bits (and therefore times 8)!
72 	 */
73 	res = TEE_AllocateTransientObject(TEE_TYPE_HMAC_SHA1, keylen * 8,
74 					  &key_handle);
75 	if (res != TEE_SUCCESS) {
76 		EMSG("0x%08x", res);
77 		goto exit;
78 	}
79 
80 	/*
81 	 * 3. Initialize the attributes, i.e., point to the actual HMAC key.
82 	 *    Here, the expected size is in bytes and not bits as above!
83 	 */
84 	TEE_InitRefAttribute(&attr, TEE_ATTR_SECRET_VALUE, key, keylen);
85 
86 	/* 4. Populate/assign the attributes with the key object */
87 	res = TEE_PopulateTransientObject(key_handle, &attr, 1);
88 	if (res != TEE_SUCCESS) {
89 		EMSG("0x%08x", res);
90 		goto exit;
91 	}
92 
93 	/* 5. Associate the key (object) with the operation */
94 	res = TEE_SetOperationKey(op_handle, key_handle);
95 	if (res != TEE_SUCCESS) {
96 		EMSG("0x%08x", res);
97 		goto exit;
98 	}
99 
100 	/* 6. Do the HMAC operations */
101 	TEE_MACInit(op_handle, NULL, 0);
102 	TEE_MACUpdate(op_handle, in, inlen);
103 	res = TEE_MACComputeFinal(op_handle, NULL, 0, out, outlen);
104 exit:
105 	if (op_handle != TEE_HANDLE_NULL)
106 		TEE_FreeOperation(op_handle);
107 
108 	/* It is OK to call this when key_handle is TEE_HANDLE_NULL */
109 	TEE_FreeTransientObject(key_handle);
110 
111 	return res;
112 }
113 
114 /*
115  * Truncate function working as described in RFC4226.
116  */
truncate(uint8_t * hmac_result,uint32_t * bin_code)117 static void truncate(uint8_t *hmac_result, uint32_t *bin_code)
118 {
119 	int offset = hmac_result[19] & 0xf;
120 
121 	*bin_code = (hmac_result[offset] & 0x7f) << 24 |
122 		(hmac_result[offset+1] & 0xff) << 16 |
123 		(hmac_result[offset+2] & 0xff) <<  8 |
124 		(hmac_result[offset+3] & 0xff);
125 
126 	*bin_code %= DBC2_MODULO;
127 }
128 
register_shared_key(uint32_t param_types,TEE_Param params[4])129 static TEE_Result register_shared_key(uint32_t param_types, TEE_Param params[4])
130 {
131 	TEE_Result res = TEE_SUCCESS;
132 
133 	uint32_t exp_param_types = TEE_PARAM_TYPES(TEE_PARAM_TYPE_MEMREF_INPUT,
134 						   TEE_PARAM_TYPE_NONE,
135 						   TEE_PARAM_TYPE_NONE,
136 						   TEE_PARAM_TYPE_NONE);
137 
138 	if (param_types != exp_param_types) {
139 		EMSG("Expected: 0x%x, got: 0x%x", exp_param_types, param_types);
140 		return TEE_ERROR_BAD_PARAMETERS;
141 	}
142 
143 	if (params[0].memref.size > sizeof(K))
144 		return TEE_ERROR_BAD_PARAMETERS;
145 
146 	memset(K, 0, sizeof(K));
147 	memcpy(K, params[0].memref.buffer, params[0].memref.size);
148 
149 	K_len = params[0].memref.size;
150 	DMSG("Got shared key %s (%u bytes).", K, params[0].memref.size);
151 
152 	return res;
153 }
154 
get_hotp(uint32_t param_types,TEE_Param params[4])155 static TEE_Result get_hotp(uint32_t param_types, TEE_Param params[4])
156 {
157 	TEE_Result res = TEE_SUCCESS;
158 	uint32_t hotp_val;
159 	uint8_t mac[SHA1_HASH_SIZE];
160 	uint32_t mac_len = sizeof(mac);
161 	int i;
162 
163 	uint32_t exp_param_types = TEE_PARAM_TYPES(TEE_PARAM_TYPE_VALUE_OUTPUT,
164 						   TEE_PARAM_TYPE_NONE,
165 						   TEE_PARAM_TYPE_NONE,
166 						   TEE_PARAM_TYPE_NONE);
167 
168 	if (param_types != exp_param_types) {
169 		EMSG("Expected: 0x%x, got: 0x%x", exp_param_types, param_types);
170 		return TEE_ERROR_BAD_PARAMETERS;
171 	}
172 
173 	res = hmac_sha1(K, K_len, counter, sizeof(counter), mac, &mac_len);
174 
175 	/* Increment the counter. */
176 	for (i = sizeof(counter) - 1; i >= 0; i--) {
177 		if (++counter[i])
178 			break;
179 	}
180 
181 	truncate(mac, &hotp_val);
182 	DMSG("HOTP is: %d", hotp_val);
183 	params[0].value.a = hotp_val;
184 
185 	return res;
186 }
187 
188 /*******************************************************************************
189  * Mandatory TA functions.
190  ******************************************************************************/
TA_CreateEntryPoint(void)191 TEE_Result TA_CreateEntryPoint(void)
192 {
193 	return TEE_SUCCESS;
194 }
195 
TA_DestroyEntryPoint(void)196 void TA_DestroyEntryPoint(void)
197 {
198 }
199 
TA_OpenSessionEntryPoint(uint32_t param_types,TEE_Param __unused params[4],void __unused ** sess_ctx)200 TEE_Result TA_OpenSessionEntryPoint(uint32_t param_types,
201 				    TEE_Param __unused params[4],
202 				    void __unused **sess_ctx)
203 {
204 	uint32_t exp_param_types = TEE_PARAM_TYPES(TEE_PARAM_TYPE_NONE,
205 						   TEE_PARAM_TYPE_NONE,
206 						   TEE_PARAM_TYPE_NONE,
207 						   TEE_PARAM_TYPE_NONE);
208 	if (param_types != exp_param_types)
209 		return TEE_ERROR_BAD_PARAMETERS;
210 
211 	return TEE_SUCCESS;
212 }
213 
TA_CloseSessionEntryPoint(void __unused * sess_ctx)214 void TA_CloseSessionEntryPoint(void __unused *sess_ctx)
215 {
216 }
217 
TA_InvokeCommandEntryPoint(void __unused * sess_ctx,uint32_t cmd_id,uint32_t param_types,TEE_Param params[4])218 TEE_Result TA_InvokeCommandEntryPoint(void __unused *sess_ctx,
219 				      uint32_t cmd_id,
220 				      uint32_t param_types, TEE_Param params[4])
221 {
222 	switch (cmd_id) {
223 	case TA_HOTP_CMD_REGISTER_SHARED_KEY:
224 		return register_shared_key(param_types, params);
225 
226 	case TA_HOTP_CMD_GET_HOTP:
227 		return get_hotp(param_types, params);
228 
229 	default:
230 		return TEE_ERROR_BAD_PARAMETERS;
231 	}
232 }
233