ACK: [SRU][F:linux-bluefield][PATCH 1/1] UBUNTU: SAUCE: pka: Enable DRBG block in TRNG
Kleber Souza
kleber.souza at canonical.com
Wed May 5 09:08:53 UTC 2021
On 03.05.21 18:57, Mahantesh Salimath wrote:
> BugLink: https://bugs.launchpad.net/bugs/1926773
>
> * DRBG should be enabled for FIPS compliance. Besides,
> it makes TRNG more robust due to the AES core present inside.
>
> * DRBG should be reseeded often and currently it is configured to reseed
> after generating 256 blocks of 128-bit random output.
> DRBG is used in conjunction with Conditioning Functioning and without
> BC_DF block. Therefore, random output is not blocked during reseed operation.
>
> * Before using TRNG with DRBG configuration, NIST known answer test is performed
> on the entire DRBG block to verify if DRBG is functioning as expected.
>
> * Personalization string for DRBG is chosen so that it fits into the 12 registers (384 bits).
>
> * 'trng_read' local variable needs to be cleared after acknowledging the random
> output everytime. Else, it is always set and old random data might be used in certain cases.
>
> Signed-off-by: Mahantesh Salimath <mahantesh at nvidia.com>
> Reviewed-by: Khalil Blaiech <kblaiech at nvidia.com>
> Signed-off-by: Mahantesh Salimath <mahantesh at nvidia.com>
Acked-by: Kleber Sacilotto de Souza <kleber.souza at canonical.com>
Thanks
> ---
> diff --git a/drivers/platform/mellanox/mlxbf_pka/mlxbf_pka_addrs.h b/drivers/platform/mellanox/mlxbf_pka/mlxbf_pka_addrs.h
> index 1896612..3a30e79 100644
> --- a/drivers/platform/mellanox/mlxbf_pka/mlxbf_pka_addrs.h
> +++ b/drivers/platform/mellanox/mlxbf_pka/mlxbf_pka_addrs.h
> @@ -117,6 +117,19 @@
> #define TRNG_POKER_B_8 0x120D0
> #define TRNG_POKER_F_C 0x120D8
>
> +#define TRNG_PS_AI_0_ADDR 0x12080
> +#define TRNG_PS_AI_1_ADDR 0x12088
> +#define TRNG_PS_AI_2_ADDR 0x12090
> +#define TRNG_PS_AI_3_ADDR 0x12098
> +#define TRNG_PS_AI_4_ADDR 0x120A0
> +#define TRNG_PS_AI_5_ADDR 0x120A8
> +#define TRNG_PS_AI_6_ADDR 0x120B0
> +#define TRNG_PS_AI_7_ADDR 0x120B8
> +#define TRNG_PS_AI_8_ADDR 0x120C0
> +#define TRNG_PS_AI_9_ADDR 0x120C8
> +#define TRNG_PS_AI_10_ADDR 0x120D0
> +#define TRNG_PS_AI_11_ADDR 0x120D8
> +
> // Control register address/offset. This is accessed from the ARM using 8
> // byte reads/writes however only the bottom 32 bits are implemented.
> #define PKA_MASTER_SEQ_CTRL_ADDR 0x27F90
> diff --git a/drivers/platform/mellanox/mlxbf_pka/mlxbf_pka_config.h b/drivers/platform/mellanox/mlxbf_pka/mlxbf_pka_config.h
> index a562d39..2f2fd83 100644
> --- a/drivers/platform/mellanox/mlxbf_pka/mlxbf_pka_config.h
> +++ b/drivers/platform/mellanox/mlxbf_pka/mlxbf_pka_config.h
> @@ -183,6 +183,31 @@
> // TRNG Control bit
> #define PKA_TRNG_CONTROL_TEST_MODE 0x100
>
> +// TRNG Control Register Value; Set bit 10 and 12 to start the EIP-76 a.k.a TRNG
> +// engine with DRBG enabled, gathering entropy from the FROs.
> +#define PKA_TRNG_CONTROL_DRBG_REG_VAL 0x00001400
> +
> +// DRBG enabled TRNG 'request_data' value. REQ_DATA_VAL (in accordance with
> +// DATA_BLOCK_MASK) requests 256 blocks of 128-bit random output.
> +// 4095 blocks is the max number that can be requested for the TRNG(with DRBG)
> +// configuration on Bluefield platforms.
> +#define PKA_TRNG_CONTROL_REQ_DATA_VAL 0x10010000
> +
> +// Mask for 'Data Block' in TRNG Control Register.
> +#define PKA_TRNG_DRBG_DATA_BLOCK_MASK 0xfff00000
> +
> +// Set bit 12 of TRNG Control Register to enable DRBG functionality.
> +#define PKA_TRNG_CONTROL_DRBG_ENABLE_VAL 0x00001000
> +
> +// Set bit 8 a.ka 'test_sp_800_90 DRBG' bit in the TRNG Test Register.
> +#define PKA_TRNG_TEST_DRBG_VAL 0x00000080
> +
> +// Number of Personalization String/Additional Input Registers
> +#define PKA_TRNG_PS_AI_REG_COUNT 12
> +
> +// DRBG Reseed enable
> +#define PKA_TRNG_CONTROL_DRBG_RESEED 0x00008000
> +
> // TRNG Status bits
> #define PKA_TRNG_STATUS_READY 0x1
> #define PKA_TRNG_STATUS_SHUTDOWN_OFLO 0x2
> diff --git a/drivers/platform/mellanox/mlxbf_pka/mlxbf_pka_dev.c b/drivers/platform/mellanox/mlxbf_pka/mlxbf_pka_dev.c
> index 358989f..4ee4462a 100644
> --- a/drivers/platform/mellanox/mlxbf_pka/mlxbf_pka_dev.c
> +++ b/drivers/platform/mellanox/mlxbf_pka/mlxbf_pka_dev.c
> @@ -43,6 +43,44 @@
> #define BYTES_PER_WORD 4
> #define BYTES_PER_DOUBLE_WORD 8
>
> +// Personalization string "NVIDIA-MELLANOX-BLUEFIELD-TRUE_RANDOM_NUMBER_GEN"
> +uint32_t pka_trng_drbg_ps_str[] =
> +{
> + 0x4e564944, 0x49412d4d, 0x454c4c41, 0x4e4f582d,
> + 0x424c5545, 0x4649454c, 0x442d5452, 0x55455f52,
> + 0x414e444f, 0x4d5f4e55, 0x4d424552, 0x5f47454e
> +};
> +
> +// Personalization string for DRBG test
> +uint32_t pka_trng_drbg_test_ps_str[] =
> +{
> + 0x64299d83, 0xc34d7098, 0x5bd1f51d, 0xddccfdc1,
> + 0xdd0455b7, 0x166279e5, 0x0974cb1b, 0x2f2cd100,
> + 0x59a5060a, 0xca79940d, 0xd4e29a40, 0x56b7b779
> +};
> +
> +// First Entropy string for DRBG test
> +uint32_t pka_trng_drbg_test_etpy_str1[] =
> +{
> + 0xaa6bbcab, 0xef45e339, 0x136ca1e7, 0xbce1c881,
> + 0x9fa37b09, 0x63b53667, 0xb36e0053, 0xa202ed81,
> + 0x4650d90d, 0x8eed6127, 0x666f2402, 0x0dfd3af9
> +};
> +
> +// Second Entropy string for DRBG test
> +uint32_t pka_trng_drbg_test_etpy_str2[] =
> +{
> + 0x35c1b7a1, 0x0154c52b, 0xd5777390, 0x226a4fdb,
> + 0x5f16080d, 0x06b68369, 0xd0c93d00, 0x3336e27f,
> + 0x1abf2c37, 0xe6ab006c, 0xa4adc6e1, 0x8e1907a2
> +};
> +
> +// Known answer for DRBG test
> +uint32_t pka_trng_drbg_test_output[] =
> +{
> + 0xb663b9f1, 0x24943e13, 0x80f7dce5, 0xaba1a16f
> +};
> +
> pka_dev_gbl_config_t pka_gbl_config;
>
> // Global PKA shim resource info table
> @@ -1100,6 +1138,29 @@ static int pka_dev_config_trng_clk(pka_dev_res_t *aic_csr_ptr)
> return ret;
> }
>
> +static int pka_dev_trng_wait_test_ready(void *csr_reg_ptr, uint64_t csr_reg_base)
> +{
> + uint64_t csr_reg_off, timer, test_ready, csr_reg_val;
> +
> + test_ready = 0;
> + csr_reg_off = pka_dev_get_register_offset(csr_reg_base, TRNG_STATUS_ADDR);
> + timer = pka_dev_timer_start(1000000); // 1000 ms
> +
> + while (!test_ready)
> + {
> + csr_reg_val = pka_dev_io_read(csr_reg_ptr, csr_reg_off);
> + test_ready = csr_reg_val & PKA_TRNG_STATUS_TEST_READY;
> +
> + if (pka_dev_timer_done(timer))
> + {
> + PKA_DEBUG(PKA_DEV, "TRNG: TEST ready timer done, 0x%llx\n", csr_reg_val);
> + return 1;
> + }
> + }
> +
> + return 0;
> +}
> +
> static int pka_dev_trng_enable_test(void *csr_reg_ptr, uint64_t csr_reg_base,
> uint32_t test)
> {
> @@ -1434,9 +1495,106 @@ static int pka_dev_test_trng(void *csr_reg_ptr, uint64_t csr_reg_base)
> return ret;
> }
>
> +static void pka_dev_trng_write_ps_ai_str(void *csr_reg_ptr,
> + uint64_t csr_reg_base,
> + uint32_t input_str[])
> +{
> + uint64_t csr_reg_off;
> + int i;
> +
> + for (i = 0; i < PKA_TRNG_PS_AI_REG_COUNT; i++)
> + {
> + csr_reg_off = pka_dev_get_register_offset(csr_reg_base,
> + TRNG_PS_AI_0_ADDR + (i * 0x8));
> +
> + pka_dev_io_write(csr_reg_ptr, csr_reg_off, input_str[i]);
> + }
> +}
> +
> +static void pka_dev_trng_drbg_generate(void *csr_reg_ptr, uint64_t csr_reg_base)
> +{
> + uint64_t csr_reg_off;
> +
> + csr_reg_off = pka_dev_get_register_offset(csr_reg_base, TRNG_CONTROL_ADDR);
> + pka_dev_io_write(csr_reg_ptr, csr_reg_off, PKA_TRNG_CONTROL_REQ_DATA_VAL);
> +}
> +
> +static int pka_dev_test_trng_drbg(void *csr_reg_ptr, uint64_t csr_reg_base)
> +{
> + uint64_t csr_reg_off, csr_reg_val;
> + int i, ret;
> +
> + ret = 0;
> +
> + // Make sure the engine is idle.
> + csr_reg_off = pka_dev_get_register_offset(csr_reg_base, TRNG_CONTROL_ADDR);
> + pka_dev_io_write(csr_reg_ptr, csr_reg_off, 0);
> +
> + // Enable DRBG, TRNG need not be enabled for this test.
> + csr_reg_off = pka_dev_get_register_offset(csr_reg_base, TRNG_CONTROL_ADDR);
> + pka_dev_io_write(csr_reg_ptr, csr_reg_off, PKA_TRNG_CONTROL_DRBG_ENABLE_VAL);
> +
> + // Set 'test_sp_800_90' bit in the TRNG_TEST register
> + csr_reg_off = pka_dev_get_register_offset(csr_reg_base, TRNG_TEST_ADDR);
> + pka_dev_io_write(csr_reg_ptr, csr_reg_off, PKA_TRNG_TEST_DRBG_VAL);
> +
> + // Wait for 'test_ready' bit to be set.
> + ret = pka_dev_trng_wait_test_ready(csr_reg_ptr, csr_reg_base);
> + if (ret)
> + goto exit;
> +
> + // Instantiate
> + pka_dev_trng_write_ps_ai_str(csr_reg_ptr, csr_reg_base, pka_trng_drbg_test_ps_str);
> + ret = pka_dev_trng_wait_test_ready(csr_reg_ptr, csr_reg_base);
> + if (ret)
> + goto exit;
> +
> + // Generate
> + pka_dev_trng_write_ps_ai_str(csr_reg_ptr, csr_reg_base, pka_trng_drbg_test_etpy_str1);
> + ret = pka_dev_trng_wait_test_ready(csr_reg_ptr, csr_reg_base);
> + if (ret)
> + goto exit;
> +
> + // A standard NIST SP 800-90A DRBG known-answer test discards
> + // the result of the first 'Generate' function and only checks
> + // the result of the second 'Generate' function. Hence 'Generate'
> + // is performed again.
> +
> + // Generate
> + pka_dev_trng_write_ps_ai_str(csr_reg_ptr, csr_reg_base, pka_trng_drbg_test_etpy_str2);
> + ret = pka_dev_trng_wait_test_ready(csr_reg_ptr, csr_reg_base);
> + if (ret)
> + goto exit;
> +
> + // Check output registers
> + for (i = 0; i < PKA_TRNG_OUTPUT_CNT; i++)
> + {
> + csr_reg_off = pka_dev_get_register_offset(csr_reg_base,
> + TRNG_OUTPUT_0_ADDR + (i * 0x8));
> +
> + csr_reg_val = pka_dev_io_read(csr_reg_ptr, csr_reg_off);
> +
> + if ((uint32_t)csr_reg_val != pka_trng_drbg_test_output[i])
> + {
> + PKA_DEBUG(PKA_DEV,
> + "DRBG known answer test failed for output register:%d, 0x%x\n",
> + i, (uint32_t)csr_reg_val);
> + ret = 1;
> + goto exit;
> + }
> + }
> +
> + // Clear 'test_sp_800_90' bit in the TRNG_TEST register.
> + csr_reg_off = pka_dev_get_register_offset(csr_reg_base, TRNG_TEST_ADDR);
> + pka_dev_io_write(csr_reg_ptr, csr_reg_off, 0);
> +
> +exit:
> + return ret;
> +}
> +
> // Configure the TRNG.
> -static int pka_dev_config_trng(pka_dev_res_t *aic_csr_ptr,
> - pka_dev_res_t *trng_csr_ptr)
> +static int pka_dev_config_trng_drbg(pka_dev_res_t *aic_csr_ptr,
> + pka_dev_res_t *trng_csr_ptr)
> {
> int ret = 0;
>
> @@ -1456,10 +1614,13 @@ static int pka_dev_config_trng(pka_dev_res_t *aic_csr_ptr,
> csr_reg_base = trng_csr_ptr->base;
> csr_reg_ptr = trng_csr_ptr->ioaddr;
>
> - // Starting up the TRNG without a DRBG (default configuration);
> - // When not using the AES-256 DRBG, the startup sequence is relatively
> - // straightforward and the engine will generate data automatically to
> - // keep the output register and buffer RAM filled.
> + // Perform NIST known-answer tests on the complete SP 800-90A DRBG
> + // without BC_DF functionality.
> + ret = pka_dev_test_trng_drbg(csr_reg_ptr, csr_reg_base);
> + if (ret)
> + return ret;
> +
> + // Starting up the TRNG with a DRBG
>
> // Make sure the engine is idle.
> csr_reg_off =
> @@ -1496,16 +1657,31 @@ static int pka_dev_config_trng(pka_dev_res_t *aic_csr_ptr,
> pka_dev_get_register_offset(csr_reg_base, TRNG_FROENABLE_ADDR);
> pka_dev_io_write(csr_reg_ptr, csr_reg_off, PKA_TRNG_FROENABLE_REG_VAL);
>
> + // Optionally, write 'Personalization string' of upto 384 bits in
> + // TRNG_PS_AI_... registers. The contents of these registers will be
> + // XOR-ed into the output of the SHA-256 'Conditioning Function' to be
> + // used as seed value for the actual DRBG.
> + pka_dev_trng_write_ps_ai_str(csr_reg_ptr, csr_reg_base, pka_trng_drbg_ps_str);
> +
> +
> + // Run TRNG tests after configuring TRNG.
> + // NOTE: TRNG need not be enabled to carry out these tests.
> ret = pka_dev_test_trng(csr_reg_ptr, csr_reg_base);
> if (ret)
> return ret;
>
> - // Start the actual engine by setting the 'enable_trng' bit in the
> - // TRNG_CONTROL register (also a nice point to set the interrupt mask
> + // Start the actual engine by setting the 'enable_trng' and 'drbg_en' bit
> + // in the TRNG_CONTROL register (also a nice point to set the interrupt mask
> // bits).
> csr_reg_off =
> pka_dev_get_register_offset(csr_reg_base, TRNG_CONTROL_ADDR);
> - pka_dev_io_write(csr_reg_ptr, csr_reg_off, PKA_TRNG_CONTROL_REG_VAL);
> + pka_dev_io_write(csr_reg_ptr, csr_reg_off, PKA_TRNG_CONTROL_DRBG_REG_VAL);
> +
> + // The engine is now ready to handle the first 'Generate' request using
> + // the 'request_data' bit of the TRNG_CONTROL register. The first output
> + // for these requests will take a while, as Noise Source and Conditioning
> + // Function must first generate seed entropy for the DRBG.
> +
>
> // Optionally, when buffer RAM is configured: Set a data available
> // interrupt threshold using the 'load_thresh' and 'blocks_thresh'
> @@ -1513,6 +1689,11 @@ static int pka_dev_config_trng(pka_dev_res_t *aic_csr_ptr,
> // available interrupt until the indicated number of 128-bit words are
> // available in the buffer RAM.
>
> + // Start the actual 'Generate' operation using the 'request_data' and 'data_blocks'
> + // fields of the TRNG_CONTROL register.
> +
> + pka_dev_trng_drbg_generate(csr_reg_ptr, csr_reg_base);
> +
> mdelay(200);
>
> return ret;
> @@ -1637,8 +1818,8 @@ static int pka_dev_init_shim(pka_dev_shim_t *shim)
> shim->trng_err_cycle = 0;
>
> // Configure the TRNG
> - ret = pka_dev_config_trng(&shim->resources.aic_csr,
> - &shim->resources.trng_csr);
> + ret = pka_dev_config_trng_drbg(&shim->resources.aic_csr,
> + &shim->resources.trng_csr);
>
> // Pull out data from the content of the TRNG buffer RAM and
> // start the re-generation of new numbers; read and drop 512
> @@ -1948,6 +2129,27 @@ static bool pka_dev_trng_shutdown_oflo(pka_dev_res_t *trng_csr_ptr,
> return true;
> }
>
> +static int pka_dev_trng_drbg_reseed(void *csr_reg_ptr, uint64_t csr_reg_base)
> +{
> + uint64_t csr_reg_off;
> + int ret;
> +
> + ret = 0;
> +
> + csr_reg_off = pka_dev_get_register_offset(csr_reg_base, TRNG_CONTROL_ADDR);
> + pka_dev_io_write(csr_reg_ptr, csr_reg_off, PKA_TRNG_CONTROL_DRBG_RESEED);
> +
> + ret = pka_dev_trng_wait_test_ready(csr_reg_ptr, csr_reg_base);
> + if (ret)
> + return ret;
> +
> + // Write personalization string
> + pka_dev_trng_write_ps_ai_str(csr_reg_ptr, csr_reg_base, pka_trng_drbg_ps_str);
> +
> + return ret;
> +}
> +
> +// Read from DRBG enabled TRNG
> int pka_dev_trng_read(pka_dev_shim_t *shim, uint32_t *data, uint32_t cnt)
> {
> int ret = 0;
> @@ -1959,7 +2161,7 @@ int pka_dev_trng_read(pka_dev_shim_t *shim, uint32_t *data, uint32_t cnt)
> uint8_t output_idx, trng_ready = 0;
> void *csr_reg_ptr;
>
> - if (!shim || ! data || (cnt % PKA_TRNG_OUTPUT_CNT != 0))
> + if (!shim || !data || (cnt % PKA_TRNG_OUTPUT_CNT != 0))
> return -EINVAL;
>
> if (!cnt)
> @@ -1972,8 +2174,8 @@ int pka_dev_trng_read(pka_dev_shim_t *shim, uint32_t *data, uint32_t cnt)
> if (trng_csr_ptr->status != PKA_DEV_RES_STATUS_MAPPED ||
> trng_csr_ptr->type != PKA_DEV_RES_TYPE_REG)
> {
> - mutex_unlock(&shim->mutex);
> - return -EPERM;
> + ret = -EPERM;
> + goto exit;
> }
>
> csr_reg_base = trng_csr_ptr->base;
> @@ -1982,8 +2184,8 @@ int pka_dev_trng_read(pka_dev_shim_t *shim, uint32_t *data, uint32_t cnt)
> if (!pka_dev_trng_shutdown_oflo(trng_csr_ptr,
> &shim->trng_err_cycle))
> {
> - mutex_unlock(&shim->mutex);
> - return -EWOULDBLOCK;
> + ret = -EWOULDBLOCK;
> + goto exit;
> }
>
> // Determine the number of 32-bit words.
> @@ -1992,12 +2194,36 @@ int pka_dev_trng_read(pka_dev_shim_t *shim, uint32_t *data, uint32_t cnt)
> for (data_idx = 0; data_idx < word_cnt; data_idx++)
> {
> output_idx = data_idx % PKA_TRNG_OUTPUT_CNT;
> +
> // Tell the hardware to advance
> if (output_idx == 0)
> {
> csr_reg_off = pka_dev_get_register_offset(csr_reg_base,
> TRNG_INTACK_ADDR);
> pka_dev_io_write(csr_reg_ptr, csr_reg_off, PKA_TRNG_STATUS_READY);
> + trng_ready = 0;
> +
> + // Check if 'data_blocks' field is zero in TRNG_CONTROL register,
> + // if it is then we have to issue a 'Reseed' and Generate' request
> + // for DRBG enabled TRNG.
> + csr_reg_off = pka_dev_get_register_offset(csr_reg_base,
> + TRNG_CONTROL_ADDR);
> + csr_reg_value = pka_dev_io_read(csr_reg_ptr, csr_reg_off);
> +
> + if (!((uint32_t)csr_reg_value & PKA_TRNG_DRBG_DATA_BLOCK_MASK))
> + {
> + // Issue reseed
> + ret = pka_dev_trng_drbg_reseed(csr_reg_ptr, csr_reg_base);
> + if (ret)
> + {
> + ret = -EBUSY;
> + goto exit;
> + }
> +
> + // Issue generate request
> + pka_dev_trng_drbg_generate(csr_reg_ptr, csr_reg_base);
> + }
> +
> }
>
> // Wait until a data word is available in the TRNG_OUTPUT_X
> @@ -2018,8 +2244,8 @@ int pka_dev_trng_read(pka_dev_shim_t *shim, uint32_t *data, uint32_t cnt)
> PKA_DEBUG(PKA_DEV,
> "Shim %u got error obtaining random number\n",
> shim->shim_id);
> - mutex_unlock(&shim->mutex);
> - return -EBUSY;
> + ret = -EBUSY;
> + goto exit;
> }
> }
>
> @@ -2030,6 +2256,7 @@ int pka_dev_trng_read(pka_dev_shim_t *shim, uint32_t *data, uint32_t cnt)
> data[data_idx] = (uint32_t) csr_reg_value;
> }
>
> +exit:
> mutex_unlock(&shim->mutex);
> return ret;
> }
>
More information about the kernel-team
mailing list