xref: /optee_os/core/arch/arm/plat-synquacer/rng_pta.c (revision 622eef2d551117f370a5cf563fb727c96384771a)
1 // SPDX-License-Identifier: BSD-2-Clause
2 /*
3  * Copyright (C) 2018-2022, Linaro Limited
4  */
5 
6 /*
7  * Developerbox doesn't provide a hardware based true random number
8  * generator. So this pseudo TA provides a good source of entropy using
9  * noise from 7 thermal sensors. Its suitable for entropy required
10  * during boot, seeding kernel entropy pool, cryptographic use etc.
11  *
12  * Assumption
13  * ==========
14  *
15  * We have assumed the entropy of the sensor is better than 8 bits per
16  * 14 sensor readings. This entropy estimate is based on our simple
17  * minimal entropy estimates done on 2.1G bytes of raw samples collected
18  * from thermal sensors.
19  *
20  * We believe our estimate to be conservative and have designed to
21  * health tests to trigger if a sensor does not achieve at least
22  * 8 bits in 16 sensor reading (we use 16 rather than 14 to prevent
23  * spurious failures on edge cases).
24  *
25  * Theory of operation
26  * ===================
27  *
28  * This routine uses secure timer interrupt to sample raw thermal sensor
29  * readings. As thermal sensor refresh rate is every 2ms, so interrupt
30  * fires every 2ms. It implements continuous health test counting rising
31  * and falling edges to report if sensors fail to provide entropy.
32  *
33  * It uses vetted conditioner as SHA512/256 (approved hash algorithm)
34  * to condense entropy. As per NIST.SP.800-90B spec, to get full entropy
35  * from vetted conditioner, we need to supply double of input entropy.
36  * According to assumption above and requirement for vetted conditioner,
37  * we need to supply 28 raw sensor readings to get 1 byte of full
38  * entropy as output. So for 32 bytes of conditioner output, we need to
39  * supply 896 bytes of raw sensor readings.
40  *
41  * Interfaces -> Input
42  * -------------------
43  *
44  * void rng_collect_entropy(void);
45  *
46  * Called as part of secure timer interrupt handler to sample raw
47  * thermal sensor readings and add entropy to the pool.
48  *
49  * Interfaces -> Output
50  * --------------------
51  *
52  * TEE_Result rng_get_entropy(uint32_t types,
53  *                            TEE_Param params[TEE_NUM_PARAMS]);
54  *
55  * Invoke command to expose an entropy interface to normal world.
56  *
57  * Testing
58  * =======
59  *
60  * Passes FIPS 140-2 rngtest.
61  *
62  * Limitations
63  * ===========
64  *
65  * Output rate is limited to approx. 125 bytes per second.
66  *
67  * Our entropy estimation was not reached using any approved or
68  * published estimation framework such as NIST.SP.800-90B and was tested
69  * on a very small set of physical samples. Instead we have adopted what
70  * we believe to be a conservative estimate and partnered it with a
71  * fairly agressive health check.
72  *
73  * Generating the SHA512/256 hash takes 24uS and will be run by an
74  * interrupt handler that pre-empts the normal world.
75  */
76 
77 #include <crypto/crypto.h>
78 #include <kernel/delay.h>
79 #include <kernel/pseudo_ta.h>
80 #include <kernel/spinlock.h>
81 #include <kernel/timer.h>
82 #include <mm/core_memprot.h>
83 #include <io.h>
84 #include <pta_rng.h>
85 #include <string.h>
86 
87 #include "synquacer_rng_pta.h"
88 
89 #define PTA_NAME "rng.pta"
90 
91 #define THERMAL_SENSOR_BASE0		0x54190800
92 #define THERMAL_SENSOR_OFFSET		0x80
93 #define NUM_SENSORS			7
94 #define NUM_SLOTS			((NUM_SENSORS * 2) - 1)
95 
96 #define TEMP_DATA_REG_OFFSET		0x34
97 
98 #define ENTROPY_POOL_SIZE		4096
99 
100 #define SENSOR_DATA_SIZE		128
101 #define CONDITIONER_PAYLOAD		(SENSOR_DATA_SIZE * NUM_SENSORS)
102 
103 /*
104  * The health test monitors each sensor's least significant bit and counts
105  * the number of rising and falling edges. It verifies that both counts
106  * lie within interval of between 12.5% and 37.5% of the samples.
107  * For true random data with 8 bits of entropy per byte, both counts would
108  * be close to 25%.
109  */
110 #define MAX_BIT_FLIP_EDGE_COUNT		((3 * SENSOR_DATA_SIZE) / 8)
111 #define MIN_BIT_FLIP_EDGE_COUNT		(SENSOR_DATA_SIZE / 8)
112 
113 static uint8_t entropy_pool[ENTROPY_POOL_SIZE] = {0};
114 static uint32_t entropy_size;
115 
116 static uint8_t sensors_data[NUM_SLOTS][SENSOR_DATA_SIZE] = {0};
117 static uint8_t sensors_data_slot_idx;
118 static uint8_t sensors_data_idx;
119 
120 static uint32_t health_test_fail_cnt;
121 static uint32_t health_test_cnt;
122 
123 static unsigned int entropy_lock = SPINLOCK_UNLOCK;
124 
125 static void pool_add_entropy(uint8_t *entropy, uint32_t size)
126 {
127 	uint32_t copy_size = 0;
128 
129 	if (entropy_size >= ENTROPY_POOL_SIZE)
130 		return;
131 
132 	if ((ENTROPY_POOL_SIZE - entropy_size) >= size)
133 		copy_size = size;
134 	else
135 		copy_size = ENTROPY_POOL_SIZE - entropy_size;
136 
137 	memcpy((entropy_pool + entropy_size), entropy, copy_size);
138 
139 	entropy_size += copy_size;
140 }
141 
142 static void pool_get_entropy(uint8_t *buf, uint32_t size)
143 {
144 	uint32_t off = 0;
145 
146 	if (size > entropy_size)
147 		return;
148 
149 	off = entropy_size - size;
150 
151 	memcpy(buf, &entropy_pool[off], size);
152 	entropy_size -= size;
153 }
154 
155 static bool health_test(uint8_t sensor_id)
156 {
157 	uint32_t falling_edge_count = 0;
158 	uint32_t rising_edge_count = 0;
159 	uint32_t lo_edge_count = 0;
160 	uint32_t hi_edge_count = 0;
161 	uint32_t i = 0;
162 
163 	for (i = 0; i < (SENSOR_DATA_SIZE - 1); i++) {
164 		if ((sensors_data[sensor_id][i] ^
165 		     sensors_data[sensor_id][i + 1]) & 0x1) {
166 			falling_edge_count += (sensors_data[sensor_id][i] &
167 					       0x1);
168 			rising_edge_count += (sensors_data[sensor_id][i + 1] &
169 					      0x1);
170 		}
171 	}
172 
173 	lo_edge_count = rising_edge_count < falling_edge_count ?
174 			rising_edge_count : falling_edge_count;
175 	hi_edge_count = rising_edge_count < falling_edge_count ?
176 			falling_edge_count : rising_edge_count;
177 
178 	return (lo_edge_count >= MIN_BIT_FLIP_EDGE_COUNT) &&
179 	       (hi_edge_count <= MAX_BIT_FLIP_EDGE_COUNT);
180 }
181 
182 static uint8_t pool_check_add_entropy(void)
183 {
184 	uint32_t i = 0;
185 	uint8_t entropy_sha512_256[TEE_SHA256_HASH_SIZE];
186 	uint8_t pool_status = 0;
187 	TEE_Result res = TEE_ERROR_GENERIC;
188 
189 	for (i = 0; i < NUM_SENSORS; i++) {
190 		/* Check if particular sensor data passes health test */
191 		if (health_test(sensors_data_slot_idx) == true) {
192 			sensors_data_slot_idx++;
193 		} else {
194 			health_test_fail_cnt++;
195 			memmove(sensors_data[sensors_data_slot_idx],
196 				sensors_data[sensors_data_slot_idx + 1],
197 				(SENSOR_DATA_SIZE * (NUM_SENSORS - i - 1)));
198 		}
199 	}
200 
201 	health_test_cnt += NUM_SENSORS;
202 
203 	/* Check if sensors_data have enough pass data for conditioning */
204 	if (sensors_data_slot_idx >= NUM_SENSORS) {
205 		/*
206 		 * Use vetted conditioner SHA512/256 as per
207 		 * NIST.SP.800-90B to condition raw data from entropy
208 		 * source.
209 		 */
210 		sensors_data_slot_idx -= NUM_SENSORS;
211 		res = hash_sha512_256_compute(entropy_sha512_256,
212 					sensors_data[sensors_data_slot_idx],
213 					CONDITIONER_PAYLOAD);
214 		if (res == TEE_SUCCESS)
215 			pool_add_entropy(entropy_sha512_256,
216 					 TEE_SHA256_HASH_SIZE);
217 	}
218 
219 	if (entropy_size >= ENTROPY_POOL_SIZE)
220 		pool_status = 1;
221 
222 	return pool_status;
223 }
224 
225 void rng_collect_entropy(void)
226 {
227 	uint8_t i = 0;
228 	void *vaddr = 0;
229 	uint8_t pool_full = 0;
230 	uint32_t exceptions = thread_mask_exceptions(THREAD_EXCP_ALL);
231 
232 	cpu_spin_lock(&entropy_lock);
233 
234 	for (i = 0; i < NUM_SENSORS; i++) {
235 		vaddr = phys_to_virt_io(THERMAL_SENSOR_BASE0 +
236 					(THERMAL_SENSOR_OFFSET * i) +
237 					TEMP_DATA_REG_OFFSET,
238 					sizeof(uint32_t));
239 		sensors_data[sensors_data_slot_idx + i][sensors_data_idx] =
240 					(uint8_t)io_read32((vaddr_t)vaddr);
241 	}
242 
243 	sensors_data_idx++;
244 
245 	if (sensors_data_idx >= SENSOR_DATA_SIZE) {
246 		pool_full = pool_check_add_entropy();
247 		sensors_data_idx = 0;
248 	}
249 
250 	if (pool_full)
251 		generic_timer_stop();
252 
253 	cpu_spin_unlock(&entropy_lock);
254 	thread_set_exceptions(exceptions);
255 }
256 
257 static TEE_Result rng_get_entropy(uint32_t types,
258 				  TEE_Param params[TEE_NUM_PARAMS])
259 {
260 	uint8_t *e = NULL;
261 	uint32_t rq_size = 0;
262 	uint32_t pool_size = 0;
263 	uint32_t exceptions = 0;
264 	TEE_Result res = TEE_SUCCESS;
265 
266 	if (types != TEE_PARAM_TYPES(TEE_PARAM_TYPE_MEMREF_INOUT,
267 				     TEE_PARAM_TYPE_NONE,
268 				     TEE_PARAM_TYPE_NONE,
269 				     TEE_PARAM_TYPE_NONE)) {
270 		EMSG("bad parameters types: 0x%" PRIx32, types);
271 		return TEE_ERROR_BAD_PARAMETERS;
272 	}
273 
274 	rq_size = params[0].memref.size;
275 
276 	if ((rq_size == 0) || (rq_size > ENTROPY_POOL_SIZE))
277 		return TEE_ERROR_NOT_SUPPORTED;
278 
279 	e = (uint8_t *)params[0].memref.buffer;
280 	if (!e)
281 		return TEE_ERROR_BAD_PARAMETERS;
282 
283 	exceptions = thread_mask_exceptions(THREAD_EXCP_ALL);
284 	cpu_spin_lock(&entropy_lock);
285 
286 	/*
287 	 * Report health test failure to normal world in case fail count
288 	 * exceeds 1% of pass count.
289 	 */
290 	if (health_test_fail_cnt > ((health_test_cnt + 100) / 100)) {
291 		res = TEE_ERROR_HEALTH_TEST_FAIL;
292 		params[0].memref.size = 0;
293 		health_test_cnt = 0;
294 		health_test_fail_cnt = 0;
295 		goto exit;
296 	}
297 
298 	pool_size = entropy_size;
299 
300 	if (pool_size < rq_size) {
301 		params[0].memref.size = pool_size;
302 		pool_get_entropy(e, pool_size);
303 	} else {
304 		params[0].memref.size = rq_size;
305 		pool_get_entropy(e, rq_size);
306 	}
307 
308 exit:
309 	/* Enable timer FIQ to fetch entropy */
310 	generic_timer_start(TIMER_PERIOD_MS);
311 
312 	cpu_spin_unlock(&entropy_lock);
313 	thread_set_exceptions(exceptions);
314 
315 	return res;
316 }
317 
318 static TEE_Result rng_get_info(uint32_t types,
319 			       TEE_Param params[TEE_NUM_PARAMS])
320 {
321 	if (types != TEE_PARAM_TYPES(TEE_PARAM_TYPE_VALUE_OUTPUT,
322 				     TEE_PARAM_TYPE_NONE,
323 				     TEE_PARAM_TYPE_NONE,
324 				     TEE_PARAM_TYPE_NONE)) {
325 		EMSG("bad parameters types: 0x%" PRIx32, types);
326 		return TEE_ERROR_BAD_PARAMETERS;
327 	}
328 
329 	/* Output RNG rate (per second) */
330 	params[0].value.a = 125;
331 
332 	/*
333 	 * Quality/entropy per 1024 bit of output data. As we have used
334 	 * a vetted conditioner as per NIST.SP.800-90B to provide full
335 	 * entropy given our assumption of entropy estimate for raw sensor
336 	 * data.
337 	 */
338 	params[0].value.b = 1024;
339 
340 	return TEE_SUCCESS;
341 }
342 
343 static TEE_Result invoke_command(void *pSessionContext __unused,
344 				 uint32_t nCommandID, uint32_t nParamTypes,
345 				 TEE_Param pParams[TEE_NUM_PARAMS])
346 {
347 	FMSG("command entry point for pseudo-TA \"%s\"", PTA_NAME);
348 
349 	switch (nCommandID) {
350 	case PTA_CMD_GET_ENTROPY:
351 		return rng_get_entropy(nParamTypes, pParams);
352 	case PTA_CMD_GET_RNG_INFO:
353 		return rng_get_info(nParamTypes, pParams);
354 	default:
355 		break;
356 	}
357 
358 	return TEE_ERROR_NOT_IMPLEMENTED;
359 }
360 
361 pseudo_ta_register(.uuid = PTA_RNG_UUID, .name = PTA_NAME,
362 		   .flags = PTA_DEFAULT_FLAGS | TA_FLAG_DEVICE_ENUM,
363 		   .invoke_command_entry_point = invoke_command);
364