1 // SPDX-License-Identifier: BSD-2-Clause
2 /*
3  * Copyright (c) 2019, Linaro Limited
4  */
5 
6 #include <pta_system.h>
7 #include <string.h>
8 #include <tee_internal_api.h>
9 
10 #include "derive_key_taf.h"
11 
12 #define TA_DERIVED_KEY_MIN_SIZE		16
13 #define TA_DERIVED_KEY_MAX_SIZE		32
14 #define TA_DERIVED_EXTRA_DATA_MAX_SIZE	1024
15 
16 static const TEE_UUID system_uuid = PTA_SYSTEM_UUID;
17 
18 /*
19  * Helper function that just derives a key.
20  */
derive_unique_key(TEE_TASessionHandle session,uint8_t * key,uint16_t key_size,uint8_t * extra,uint16_t extra_size)21 static TEE_Result derive_unique_key(TEE_TASessionHandle session,
22 				    uint8_t *key, uint16_t key_size,
23 				    uint8_t *extra, uint16_t extra_size)
24 {
25 	TEE_Param params[TEE_NUM_PARAMS] = { 0 };
26 	TEE_Result res = TEE_ERROR_GENERIC;
27 	uint32_t ret_origin = 0;
28 	uint32_t param_types = TEE_PARAM_TYPES(TEE_PARAM_TYPE_MEMREF_INPUT,
29 					       TEE_PARAM_TYPE_MEMREF_OUTPUT,
30 					       TEE_PARAM_TYPE_NONE,
31 					       TEE_PARAM_TYPE_NONE);
32 	if (extra && extra_size > 0) {
33 		params[0].memref.buffer = extra;
34 		params[0].memref.size = extra_size;
35 	}
36 
37 	params[1].memref.buffer = key;
38 	params[1].memref.size = key_size;
39 
40 	res = TEE_InvokeTACommand(session, TEE_TIMEOUT_INFINITE,
41 				  PTA_SYSTEM_DERIVE_TA_UNIQUE_KEY,
42 				  param_types, params, &ret_origin);
43 	if (res != TEE_SUCCESS)
44 		EMSG("Failure when calling PTA_SYSTEM_DERIVE_TA_UNIQUE_KEY");
45 
46 	return res;
47 }
48 
derive_ta_unique_key_test(uint32_t param_types,TEE_Param params[TEE_NUM_PARAMS]__unused)49 TEE_Result derive_ta_unique_key_test(uint32_t param_types,
50 				     TEE_Param params[TEE_NUM_PARAMS] __unused)
51 {
52 	size_t i = 0;
53 	TEE_Result res_final = TEE_SUCCESS;
54 	TEE_Result res = TEE_ERROR_GENERIC;
55 	TEE_TASessionHandle session = TEE_HANDLE_NULL;
56 	uint8_t big_key[64] = { };
57 	uint8_t extra_key_data[] = { "My dummy data" };
58 	uint8_t key1[32] = { };
59 	uint8_t key2[32] = { };
60 	uint32_t ret_origin = 0;
61 
62 	if (param_types != TEE_PARAM_TYPES(TEE_PARAM_TYPE_NONE,
63 					   TEE_PARAM_TYPE_NONE,
64 					   TEE_PARAM_TYPE_NONE,
65 					   TEE_PARAM_TYPE_NONE))
66 		return TEE_ERROR_BAD_PARAMETERS;
67 
68 	res = TEE_OpenTASession(&system_uuid, TEE_TIMEOUT_INFINITE, 0, NULL,
69 				&session, &ret_origin);
70 
71 	if (res != TEE_SUCCESS)
72 		return res;
73 
74 	/*
75 	 * Testing for successful calls to the PTA and that two calls with same
76 	 * input data generates the same output data (keys).
77 	 */
78 	res = derive_unique_key(session, key1, sizeof(key1), NULL, 0);
79 	if (res != TEE_SUCCESS)
80 		res_final = TEE_ERROR_GENERIC;
81 
82 	res = derive_unique_key(session, key2, sizeof(key2), NULL, 0);
83 	if (res != TEE_SUCCESS)
84 		res_final = TEE_ERROR_GENERIC;
85 
86 	if (TEE_MemCompare(key1, key2, sizeof(key1)) != 0)
87 		res_final = TEE_ERROR_GENERIC;
88 
89 	TEE_MemFill(key1, 0, sizeof(key1));
90 	TEE_MemFill(key2, 0, sizeof(key2));
91 
92 	/*
93 	 * Testing for successful calls to the PTA and that two calls with same
94 	 * input data generates the same output data (keys). Here we are using
95 	 * extra data also.
96 	 */
97 	res = derive_unique_key(session, key1, sizeof(key1), extra_key_data,
98 				sizeof(extra_key_data));
99 	if (res != TEE_SUCCESS)
100 		res_final = TEE_ERROR_GENERIC;
101 
102 	res = derive_unique_key(session, key2, sizeof(key2), extra_key_data,
103 				sizeof(extra_key_data));
104 	if (res != TEE_SUCCESS)
105 		res_final = TEE_ERROR_GENERIC;
106 
107 	if (TEE_MemCompare(key1, key2, sizeof(key1)) != 0)
108 		res_final = TEE_ERROR_GENERIC;
109 
110 	TEE_MemFill(key1, 0, sizeof(key1));
111 	TEE_MemFill(key2, 0, sizeof(key2));
112 
113 	/*
114 	 * Testing for successful calls to the PTA and that two calls with
115 	 * different input data do not generate the same output data (keys). We
116 	 * do that by using one key with and one key without extra data.
117 	 */
118 	res = derive_unique_key(session, key1, sizeof(key1), extra_key_data,
119 				sizeof(extra_key_data));
120 	if (res != TEE_SUCCESS)
121 		res_final = TEE_ERROR_GENERIC;
122 
123 	res = derive_unique_key(session, key2, sizeof(key2), NULL, 0);
124 	if (res != TEE_SUCCESS)
125 		res_final = TEE_ERROR_GENERIC;
126 
127 	/* They should not be equal */
128 	if (TEE_MemCompare(key1, key2, sizeof(key1)) == 0)
129 		res_final = TEE_ERROR_GENERIC;
130 
131 	TEE_MemFill(key1, 0, sizeof(key1));
132 	TEE_MemFill(key2, 0, sizeof(key2));
133 
134 	/*
135 	 * Testing limits for extra data size (if this would success, then we
136 	 * would overwrite the buffer extra_key_data also).
137 	 */
138 	res = derive_unique_key(session, key1, sizeof(key1), extra_key_data,
139 				TA_DERIVED_EXTRA_DATA_MAX_SIZE + 1);
140 	/* This shall fail */
141 	if (res == TEE_SUCCESS)
142 		res_final = TEE_ERROR_GENERIC;
143 
144 	TEE_MemFill(key1, 0, sizeof(key1));
145 
146 	/* Testing limits. */
147 	for (i = 0; i < sizeof(big_key); i++) {
148 		uint8_t *extra = NULL;
149 		uint8_t extra_size = 0;
150 
151 		TEE_MemFill(big_key, 0, sizeof(big_key));
152 
153 		/* Alternate between using and not using extra data. */
154 		if (i % 2) {
155 			extra = extra_key_data;
156 			extra_size = sizeof(extra_key_data);
157 		}
158 
159 		res = derive_unique_key(session, big_key, i, extra, extra_size);
160 		if (i < TA_DERIVED_KEY_MIN_SIZE) {
161 			if (res != TEE_SUCCESS)
162 				continue;
163 
164 			EMSG("Small key test iteration %zu failed", i);
165 			res_final = TEE_ERROR_GENERIC;
166 			break;
167 		}
168 
169 		if (i > TA_DERIVED_KEY_MAX_SIZE) {
170 			if (res != TEE_SUCCESS)
171 				continue;
172 
173 			EMSG("Big key test iteration %zu failed", i);
174 			res_final = TEE_ERROR_GENERIC;
175 			break;
176 		}
177 
178 		if (res != TEE_SUCCESS) {
179 			res_final = TEE_ERROR_GENERIC;
180 			break;
181 		}
182 	}
183 
184 	TEE_CloseTASession(session);
185 
186 	return res_final;
187 }
188 
derive_ta_unique_key_test_shm(uint32_t param_types,TEE_Param params[TEE_NUM_PARAMS])189 TEE_Result derive_ta_unique_key_test_shm(uint32_t param_types,
190 					 TEE_Param params[TEE_NUM_PARAMS])
191 {
192 	TEE_Result res = TEE_ERROR_GENERIC;
193 	TEE_TASessionHandle session = TEE_HANDLE_NULL;
194 	uint32_t ret_origin = 0;
195 
196 	if (param_types != TEE_PARAM_TYPES(TEE_PARAM_TYPE_MEMREF_INPUT,
197 					   TEE_PARAM_TYPE_MEMREF_OUTPUT,
198 					   TEE_PARAM_TYPE_NONE,
199 					   TEE_PARAM_TYPE_NONE))
200 		return TEE_ERROR_BAD_PARAMETERS;
201 
202 	res = TEE_OpenTASession(&system_uuid, TEE_TIMEOUT_INFINITE, 0, NULL,
203 				&session, &ret_origin);
204 
205 	if (res != TEE_SUCCESS)
206 		return res;
207 
208 	/*
209 	 * Testing for unsuccessful calls to the PTA. They should be
210 	 * unsuccessful since we are using an out buffer coming from normal
211 	 * world.
212 	 */
213 	res = TEE_InvokeTACommand(session, TEE_TIMEOUT_INFINITE,
214 				  PTA_SYSTEM_DERIVE_TA_UNIQUE_KEY,
215 				  param_types, params, &ret_origin);
216 	TEE_CloseTASession(session);
217 
218 	return res;
219 }
220