From patchwork Thu Nov 22 06:52:57 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Sumit Garg X-Patchwork-Id: 151731 Delivered-To: patches@linaro.org Received: by 2002:a2e:299d:0:0:0:0:0 with SMTP id p29-v6csp370333ljp; Wed, 21 Nov 2018 22:53:25 -0800 (PST) X-Received: by 2002:a63:165e:: with SMTP id 30mr8958738pgw.103.1542869605043; Wed, 21 Nov 2018 22:53:25 -0800 (PST) ARC-Seal: i=1; a=rsa-sha256; t=1542869605; cv=none; d=google.com; s=arc-20160816; b=LjuHaapUeCGJN/otAMe4wsRomFgL72uGWLf6sMiU9GlYY6Y2qDwDmpw3pRuRqZ1yBG vDERKE6jutt29gZXzaQWBulYNC3YjKS+zeOvuk8dBVxKDVDubr8oOzFNr7J4+LCwTXYy Kon9jSvQaLMiPPuv/92S8Zm/oNFXdtVGH8kUuAJdsgWU0JyJ/f4ZadUCCbXVUOz0SNtv JNRNSrXDypxS9NE86uY/rjXOpQfRKxjHt0Z1wj/UknaYF/o7gfyQpeud9C4G0zNu+j0t RYbaSyBTpKv4RWJDY+rXrv+d51HFkRXwf5PoytqmxJbrarvIPGh/hMHrSA5XHNAMNOKA c3DQ== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=references:in-reply-to:message-id:date:subject:cc:to:from :dkim-signature; bh=HyTX9LefFGBZndFARqBJ7dUeAIwGJu2QJY9neomzqwM=; b=v0bt4NjOuAj+2gSlp6CJpGIGanPvUvjEHPlLtfMIx8Ls1PLQFNOzom2fhN2HtUtsK9 mORdh+BmPbIzZ+ekYoXV9ir/aBij3Jzpwp2wehpk6xjJ6xYHwdlkPhpACq6YwrkZV+zE G6ssPo9HimBSw/4toPXyEkoYtCHHKIv3qMXWDIrNjAmo9hY8B/YSwMMt45JCF4gQDH/Z YJ6a8vAoU+Up8cCRKI/S3nKlu6pmBm9ze/OdgmgsPrKA00RNZM7bItmEePCsfeV1HQyy 6b/6Sv7irgMpaXc8yCboESMWGUFOqxvGpQFW1Os5TYI6FrS9d23yftj2Ps1pb7p07Hjn 8hAA== ARC-Authentication-Results: i=1; mx.google.com; dkim=pass header.i=@linaro.org header.s=google header.b=YGWlxbFO; spf=pass (google.com: domain of sumit.garg@linaro.org designates 209.85.220.65 as permitted sender) smtp.mailfrom=sumit.garg@linaro.org; dmarc=pass (p=NONE sp=NONE dis=NONE) header.from=linaro.org Return-Path: Received: from mail-sor-f65.google.com (mail-sor-f65.google.com. [209.85.220.65]) by mx.google.com with SMTPS id q2sor5807465plh.10.2018.11.21.22.53.24 for (Google Transport Security); Wed, 21 Nov 2018 22:53:25 -0800 (PST) Received-SPF: pass (google.com: domain of sumit.garg@linaro.org designates 209.85.220.65 as permitted sender) client-ip=209.85.220.65; Authentication-Results: mx.google.com; dkim=pass header.i=@linaro.org header.s=google header.b=YGWlxbFO; spf=pass (google.com: domain of sumit.garg@linaro.org designates 209.85.220.65 as permitted sender) smtp.mailfrom=sumit.garg@linaro.org; dmarc=pass (p=NONE sp=NONE dis=NONE) header.from=linaro.org DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=linaro.org; s=google; h=from:to:cc:subject:date:message-id:in-reply-to:references; bh=HyTX9LefFGBZndFARqBJ7dUeAIwGJu2QJY9neomzqwM=; b=YGWlxbFO4CcyuPpsKvijATZf2OZQNJ2Bf8loLEReudsd9mUmyDFAX1+9n2vn0hBU5b +MCSOAMgFxkKe/EQqPQv/21HeQvIoPNh+y1ZpdJh1sWT+VfW0Fbbeba+Hi0/KzxCpYqr EJGBzWQF7CrsCKN+zjaEwGhgx4TJXK46HabJU= X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references; bh=HyTX9LefFGBZndFARqBJ7dUeAIwGJu2QJY9neomzqwM=; b=meIOnyI4mCwRNxpg8JxHq1U86TqDyGBBAXTW/970K9h7YGC70eLUvE121nDLrm0yDx ACddgeLbgkkxQwgZA8vyMmInMwk3z+GN8NAPYzn6QZ6cbONy2iLThAADN6zaqzhiTX+j hFICqNx8iGbAxwosK08vuTAwVyfNVnMQuggEyG5k1Q5DJceQjg8wPZ8AOAr+FHuA7gwk cadNCQi2WD9qttcQHAPev8AemG7cKQknVcUxrkUGyFtzbmTD5EkaUNP2DlWle+XgWTwG 0aAEdWJJ0dsVBHSUL2cHpdsoYESM3MXVwc6+Z1Ir4gHNDSuFv82iO+zjVI9BQrWqNVI4 gLDw== X-Gm-Message-State: AA+aEWYLW60222u+jCs8opGWq2U+vBRKk1MHrBqaaUY9fe85wF5v3K4Y QrNjXFLFhdC8KzTZsqi5hYr0d8/E X-Google-Smtp-Source: AFSGD/Wn86vNC9JhvtJdSqT6hLp1Hw8NdjiVwj3G06qEFbGJicdpVTN6+Rb0G89v9PZFcnDxTJEefQ== X-Received: by 2002:a17:902:8bca:: with SMTP id r10-v6mr9811090plo.199.1542869604339; Wed, 21 Nov 2018 22:53:24 -0800 (PST) Return-Path: Received: from localhost.localdomain ([117.252.69.224]) by smtp.gmail.com with ESMTPSA id c4sm18745043pfm.151.2018.11.21.22.53.21 (version=TLS1_2 cipher=ECDHE-RSA-AES128-SHA bits=128/128); Wed, 21 Nov 2018 22:53:23 -0800 (PST) From: Sumit Garg To: daniel.thompson@linaro.org Cc: patches@linaro.org, Sumit Garg Subject: [PATCH v4 3/3] synquacer: Add RNG pseudo TA Date: Thu, 22 Nov 2018 12:22:57 +0530 Message-Id: <1542869577-32435-3-git-send-email-sumit.garg@linaro.org> X-Mailer: git-send-email 2.7.4 In-Reply-To: <1542869577-32435-1-git-send-email-sumit.garg@linaro.org> References: <1542869577-32435-1-git-send-email-sumit.garg@linaro.org> This platform provides 7 on-chip thermal sensors accessible from secure world only. So, using thermal noise from these sensors we have tried to create an entropy source as a pseudo TA. Signed-off-by: Sumit Garg --- core/arch/arm/plat-synquacer/main.c | 8 + core/arch/arm/plat-synquacer/platform_config.h | 1 + core/arch/arm/plat-synquacer/rng_pta.c | 347 +++++++++++++++++++++++++ core/arch/arm/plat-synquacer/rng_pta.h | 11 + core/arch/arm/plat-synquacer/rng_pta_client.h | 30 +++ core/arch/arm/plat-synquacer/sub.mk | 1 + 6 files changed, 398 insertions(+) create mode 100644 core/arch/arm/plat-synquacer/rng_pta.c create mode 100644 core/arch/arm/plat-synquacer/rng_pta.h create mode 100644 core/arch/arm/plat-synquacer/rng_pta_client.h -- 2.7.4 diff --git a/core/arch/arm/plat-synquacer/main.c b/core/arch/arm/plat-synquacer/main.c index 714becd..c5af85d 100644 --- a/core/arch/arm/plat-synquacer/main.c +++ b/core/arch/arm/plat-synquacer/main.c @@ -18,6 +18,7 @@ #include #include #include +#include #include static void main_fiq(void); @@ -39,6 +40,7 @@ static struct pl011_data console_data; register_phys_mem(MEM_AREA_IO_NSEC, CONSOLE_UART_BASE, CORE_MMU_DEVICE_SIZE); register_phys_mem(MEM_AREA_IO_SEC, GIC_BASE, CORE_MMU_DEVICE_SIZE); +register_phys_mem(MEM_AREA_IO_SEC, THERMAL_SENSOR_BASE, CORE_MMU_DEVICE_SIZE); const struct thread_handlers *generic_boot_get_handlers(void) { @@ -78,6 +80,9 @@ static enum itr_return timer_itr_cb(struct itr_handler *h __unused) /* Reset timer for next FIQ */ generic_timer_handler(); + /* Collect entropy on each timer FIQ */ + rng_collect_entropy(); + return ITRR_HANDLED; } @@ -92,6 +97,9 @@ static TEE_Result init_timer_itr(void) itr_add(&timer_itr); itr_enable(IT_SEC_TIMER); + /* Enable timer FIQ to fetch entropy required during boot */ + generic_timer_start(); + return TEE_SUCCESS; } driver_init(init_timer_itr); diff --git a/core/arch/arm/plat-synquacer/platform_config.h b/core/arch/arm/plat-synquacer/platform_config.h index f9b1b40..8a91ddb 100644 --- a/core/arch/arm/plat-synquacer/platform_config.h +++ b/core/arch/arm/plat-synquacer/platform_config.h @@ -19,6 +19,7 @@ #define CONSOLE_UART_CLK_IN_HZ 62500000 #define CONSOLE_BAUDRATE 115200 +#define THERMAL_SENSOR_BASE 0x54190000 #define IT_SEC_TIMER 29 #define DRAM0_BASE 0x80000000 diff --git a/core/arch/arm/plat-synquacer/rng_pta.c b/core/arch/arm/plat-synquacer/rng_pta.c new file mode 100644 index 0000000..0329264 --- /dev/null +++ b/core/arch/arm/plat-synquacer/rng_pta.c @@ -0,0 +1,347 @@ +// SPDX-License-Identifier: BSD-2-Clause +/* + * Copyright (C) 2018, Linaro Limited + */ + +/* + * Developerbox doesn't provide a hardware based true random number + * generator. So this pseudo TA provides a good source of entropy using + * noise from 7 thermal sensors. Its suitable for entropy required + * during boot, seeding kernel entropy pool, cryptographic use etc. + * + * Assumption + * ========== + * + * We have assumed the entropy of the sensor is better than 8 bits per + * 14 sensor readings. This entropy estimate is based on our simple + * minimal entropy estimates done on 2.1G bytes of raw samples collected + * from thermal sensors. + * + * We believe our estimate to be conservative and have designed to + * health tests to trigger if a sensor does not achieve at least + * 8 bits in 16 sensor reading (we use 16 rather than 14 to prevent + * spurious failures on edge cases). + * + * Theory of operation + * =================== + * + * This routine uses secure timer interrupt to sample raw thermal sensor + * readings. As thermal sensor refresh rate is every 2ms, so interrupt + * fires every 2ms. It implements continuous health test counting rising + * and falling edges to report if sensors fail to provide entropy. + * + * It uses vetted conditioner as SHA512/256 (approved hash algorithm) + * to condense entropy. As per NIST.SP.800-90B spec, to get full entropy + * from vetted conditioner, we need to supply double of input entropy. + * According to assumption above and requirement for vetted conditioner, + * we need to supply 28 raw sensor readings to get 1 byte of full + * entropy as output. So for 32 bytes of conditioner output, we need to + * supply 896 bytes of raw sensor readings. + * + * Interfaces -> Input + * ------------------- + * + * void rng_collect_entropy(void); + * + * Called as part of secure timer interrupt handler to sample raw + * thermal sensor readings and add entropy to the pool. + * + * Interfaces -> Output + * -------------------- + * + * TEE_Result rng_get_entropy(uint32_t types, + * TEE_Param params[TEE_NUM_PARAMS]); + * + * Invoke command to expose an entropy interface to normal world. + * + * Testing + * ======= + * + * Passes FIPS 140-2 rngtest. + * + * Limitations + * =========== + * + * Output rate is limited to approx. 128 bytes per second. + * + * Our entropy estimation was not reached using any approved or + * published estimation framework such as NIST.SP.800-90B and was tests + * on a very small set of physical samples (instead we have adopted what + * we believe to be a conservative estimate and partnered it with a + * fairly agressive health check). + * + * Generating the SHA512/256 hash takes 24uS and will be run by an + * interrupt handler that pre-empts the normal world. The interrupt + * handler runs on core X. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define PTA_NAME "rng.pta" + +#define THERMAL_SENSOR_BASE0 0x54190800 +#define THERMAL_SENSOR_OFFSET 0x80 +#define NUM_SENSORS 7 +#define NUM_SLOTS 13 + +#define TEMP_DATA_REG_OFFSET 0x34 + +#define ENTROPY_POOL_SIZE 4096 + +#define SENSOR_DATA_SIZE 128 +#define CONDITIONER_PAYLOAD (SENSOR_DATA_SIZE * NUM_SENSORS) + +/* + * Used in heatlh test to check if count of either bit flips 1-0 or 0-1 lies + * in 12.5% to 37.5% of 128 bytes raw data from particular sensor reading. In + * ideal scenario (1 bit of entropy per LSB) either of bit flips should be + * around 25%. + */ +#define MAX_BIT_FLIP_EDGE_COUNT 48 +#define MIN_BIT_FLIP_EDGE_COUNT 16 + +static uint8_t entropy_pool[ENTROPY_POOL_SIZE] = {0}; +static uint32_t entropy_size; + +static uint8_t sensors_data[NUM_SLOTS][SENSOR_DATA_SIZE] = {0}; +static uint8_t slot_idx; +static uint8_t sensor_idx; + +static uint32_t health_test_fail_cnt; +static uint32_t health_test_pass_cnt; + +static unsigned int entropy_lock = SPINLOCK_UNLOCK; + +static void pool_add_entropy(uint8_t *entropy, uint32_t size) +{ + uint32_t copy_size; + + if (entropy_size >= ENTROPY_POOL_SIZE) + return; + + if ((ENTROPY_POOL_SIZE - entropy_size) >= size) + copy_size = size; + else + copy_size = ENTROPY_POOL_SIZE - entropy_size; + + memcpy((entropy_pool + entropy_size), entropy, copy_size); + + entropy_size += copy_size; +} + +static void pool_get_entropy(uint8_t *buf, uint32_t size) +{ + uint32_t off; + + if (size > entropy_size) + return; + + off = entropy_size - size; + + memcpy(buf, &entropy_pool[off], size); + entropy_size -= size; +} + +static bool health_test(uint8_t sensor_id) +{ + bool result = true; + uint8_t bit_flip_falling = 0, bit_flip_rising = 0; + uint8_t i; + + for (i = 0; i < (SENSOR_DATA_SIZE - 1); i++) { + if ((sensors_data[sensor_id][i] ^ + sensors_data[sensor_id][i + 1]) & 0x1) { + bit_flip_falling += sensors_data[sensor_id][i] & 0x1; + bit_flip_rising += sensors_data[sensor_id][i + 1] & 0x1; + } + } + + if (bit_flip_falling > bit_flip_rising) { + if (bit_flip_rising < MIN_BIT_FLIP_EDGE_COUNT) + result = false; + if (bit_flip_falling > MAX_BIT_FLIP_EDGE_COUNT) + result = false; + } else { + if (bit_flip_falling < MIN_BIT_FLIP_EDGE_COUNT) + result = false; + if (bit_flip_rising > MAX_BIT_FLIP_EDGE_COUNT) + result = false; + } + + return result; +} + +static uint8_t pool_check_add_entropy(void) +{ + uint32_t i; + uint8_t entropy_sha512_256[TEE_SHA256_HASH_SIZE]; + uint8_t pool_status = 0; + TEE_Result res; + + for (i = 0; i < NUM_SENSORS; i++) { + /* Check if particular sensor data passes health test */ + if (health_test(slot_idx) == true) { + health_test_pass_cnt++; + slot_idx++; + } else { + health_test_fail_cnt++; + memmove(sensors_data[slot_idx], + sensors_data[slot_idx + 1], + (SENSOR_DATA_SIZE * (NUM_SENSORS - i - 1))); + } + } + + /* Check if sensors_data have enough pass data for entropy */ + if (slot_idx >= NUM_SENSORS) { + /* + * Use vetted conditioner SHA512/256 as per + * NIST.SP.800-90B to condition raw data from entropy + * source. + */ + res = hash_sha512_256_compute(entropy_sha512_256, + (uint8_t *)sensors_data, + CONDITIONER_PAYLOAD); + if (res == TEE_SUCCESS) + pool_add_entropy(entropy_sha512_256, + TEE_SHA256_HASH_SIZE); + + slot_idx -= NUM_SENSORS; + memmove(sensors_data[0], + sensors_data[NUM_SENSORS], + (SENSOR_DATA_SIZE * slot_idx)); + } + + if (entropy_size >= ENTROPY_POOL_SIZE) + pool_status = 1; + + return pool_status; +} + +void rng_collect_entropy(void) +{ + uint8_t i, pool_full = 0; + void *vaddr; + uint32_t exceptions = thread_mask_exceptions(THREAD_EXCP_ALL); + + cpu_spin_lock(&entropy_lock); + + for (i = 0; i < NUM_SENSORS; i++) { + vaddr = phys_to_virt_io(THERMAL_SENSOR_BASE0 + + (THERMAL_SENSOR_OFFSET * i) + + TEMP_DATA_REG_OFFSET); + sensors_data[slot_idx + i][sensor_idx] = + (uint8_t)read32((vaddr_t)vaddr); + } + + sensor_idx++; + + if (sensor_idx >= SENSOR_DATA_SIZE) { + pool_full = pool_check_add_entropy(); + sensor_idx = 0; + } + + if (pool_full) + generic_timer_stop(); + + cpu_spin_unlock(&entropy_lock); + thread_set_exceptions(exceptions); +} + +static TEE_Result rng_get_entropy(uint32_t types, + TEE_Param params[TEE_NUM_PARAMS]) +{ + uint8_t *e = NULL; + uint32_t pool_size = 0, rq_size = 0; + uint32_t exceptions; + TEE_Result res = TEE_SUCCESS; + + if (types != TEE_PARAM_TYPES(TEE_PARAM_TYPE_MEMREF_INOUT, + TEE_PARAM_TYPE_NONE, + TEE_PARAM_TYPE_NONE, + TEE_PARAM_TYPE_NONE)) { + EMSG("bad parameters types: 0x%" PRIx32, types); + return TEE_ERROR_BAD_PARAMETERS; + } + + rq_size = params[0].memref.size; + + if ((rq_size == 0) || (rq_size > ENTROPY_POOL_SIZE)) + return TEE_ERROR_NOT_SUPPORTED; + + e = (uint8_t *)params[0].memref.buffer; + if (!e) + return TEE_ERROR_BAD_PARAMETERS; + + exceptions = thread_mask_exceptions(THREAD_EXCP_ALL); + cpu_spin_lock(&entropy_lock); + + /* + * Report health test failure to normal world in case fail count + * exceeds 1% of pass count. + */ + if (health_test_pass_cnt > 100) { + if (health_test_fail_cnt > (health_test_pass_cnt / 100)) { + res = TEE_ERROR_HEALTH_TEST_FAIL; + params[0].memref.size = 0; + health_test_pass_cnt = 0; + health_test_fail_cnt = 0; + goto exit; + } + } else { + if (health_test_fail_cnt > 1) { + res = TEE_ERROR_HEALTH_TEST_FAIL; + params[0].memref.size = 0; + health_test_pass_cnt = 0; + health_test_fail_cnt = 0; + goto exit; + } + } + + pool_size = entropy_size; + + if (pool_size < rq_size) { + params[0].memref.size = pool_size; + pool_get_entropy(e, pool_size); + } else { + params[0].memref.size = rq_size; + pool_get_entropy(e, rq_size); + } + +exit: + /* Enable timer FIQ to fetch entropy */ + generic_timer_start(); + + cpu_spin_unlock(&entropy_lock); + thread_set_exceptions(exceptions); + + return res; +} + +static TEE_Result invoke_command(void *pSessionContext __unused, + uint32_t nCommandID, uint32_t nParamTypes, + TEE_Param pParams[TEE_NUM_PARAMS]) +{ + FMSG("command entry point for pseudo-TA \"%s\"", PTA_NAME); + + switch (nCommandID) { + case PTA_CMD_GET_ENTROPY: + return rng_get_entropy(nParamTypes, pParams); + default: + break; + } + + return TEE_ERROR_NOT_IMPLEMENTED; +} + +pseudo_ta_register(.uuid = PTA_RNG_UUID, .name = PTA_NAME, + .flags = PTA_DEFAULT_FLAGS, + .invoke_command_entry_point = invoke_command); diff --git a/core/arch/arm/plat-synquacer/rng_pta.h b/core/arch/arm/plat-synquacer/rng_pta.h new file mode 100644 index 0000000..8ce2afa --- /dev/null +++ b/core/arch/arm/plat-synquacer/rng_pta.h @@ -0,0 +1,11 @@ +/* SPDX-License-Identifier: BSD-2-Clause */ +/* + * Copyright (C) 2018, Linaro Limited + */ + +#ifndef __RNG_PTA_H +#define __RNG_PTA_H + +void rng_collect_entropy(void); + +#endif /* __RNG_PTA_H */ diff --git a/core/arch/arm/plat-synquacer/rng_pta_client.h b/core/arch/arm/plat-synquacer/rng_pta_client.h new file mode 100644 index 0000000..b7986d3 --- /dev/null +++ b/core/arch/arm/plat-synquacer/rng_pta_client.h @@ -0,0 +1,30 @@ +/* SPDX-License-Identifier: BSD-2-Clause */ +/* + * Copyright (C) 2018, Linaro Limited + */ + +#ifndef __RNG_PTA_CLIENT_H +#define __RNG_PTA_CLIENT_H + +#define PTA_RNG_UUID { 0xab7a617c, 0xb8e7, 0x4d8f, \ + { 0x83, 0x01, 0xd0, 0x9b, 0x61, 0x03, 0x6b, 0x64 } } + +#define TEE_ERROR_HEALTH_TEST_FAIL 0x00000001 + +/* + * PTA_CMD_GET_ENTROPY - Get Entropy from RNG using Thermal Sensor + * + * param[0] (inout memref) - Entropy buffer memory reference + * param[1] unused + * param[2] unused + * param[3] unused + * + * Result: + * TEE_SUCCESS - Invoke command success + * TEE_ERROR_BAD_PARAMETERS - Incorrect input param + * TEE_ERROR_NOT_SUPPORTED - Requested entropy size greater than size of pool + * TEE_ERROR_HEALTH_TEST_FAIL - Continuous health testing failed + */ +#define PTA_CMD_GET_ENTROPY 0x0 + +#endif /* __RNG_PTA_CLIENT_H */ diff --git a/core/arch/arm/plat-synquacer/sub.mk b/core/arch/arm/plat-synquacer/sub.mk index cfa1dc3..013e57d 100644 --- a/core/arch/arm/plat-synquacer/sub.mk +++ b/core/arch/arm/plat-synquacer/sub.mk @@ -1,3 +1,4 @@ global-incdirs-y += . srcs-y += main.c +srcs-y += rng_pta.c srcs-y += timer_fiq.c