crypto/fsl: Add command for encapsulating/decapsulating blobs
Freescale's SEC block has built-in Blob Protocol which provides
a method for protecting user-defined data across system power
cycles. SEC block protects data in a data structure called a Blob,
which provides both confidentiality and integrity protection.
Encapsulating data as a blob
Each time that the Blob Protocol is used to protect data, a
different randomly generated key is used to encrypt the data.
This random key is itself encrypted using a key which is derived
from SoC's non volatile secret key and a 16 bit Key identifier.
The resulting encrypted key along with encrypted data is called a blob.
The non volatile secure key is available for use only during secure boot.
During decapsulation, the reverse process is performed to get back
the original data.
Commands added
--------------
blob enc - encapsulating data as a cryptgraphic blob
blob dec - decapsulating cryptgraphic blob to get the data
Commands Syntax
---------------
blob enc src dst len km
Encapsulate and create blob of data $len bytes long
at address $src and store the result at address $dst.
$km is the 16 byte key modifier is also required for
generation/use as key for cryptographic operation. Key
modifier should be 16 byte long.
blob dec src dst len km
Decapsulate the blob of data at address $src and
store result of $len byte at addr $dst.
$km is the 16 byte key modifier is also required for
generation/use as key for cryptographic operation. Key
modifier should be 16 byte long.
Signed-off-by: Ruchika Gupta <ruchika.gupta@freescale.com>
Reviewed-by: York Sun <yorksun@freescale.com>
This commit is contained in:
@@ -7,3 +7,4 @@
|
||||
#
|
||||
|
||||
obj-$(CONFIG_FSL_CAAM) += jr.o fsl_hash.o jobdesc.o error.o
|
||||
obj-$(CONFIG_CMD_BLOB) += fsl_blob.o
|
||||
|
||||
61
drivers/crypto/fsl/fsl_blob.c
Normal file
61
drivers/crypto/fsl/fsl_blob.c
Normal file
@@ -0,0 +1,61 @@
|
||||
/*
|
||||
* Copyright 2014 Freescale Semiconductor, Inc.
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0+
|
||||
*
|
||||
*/
|
||||
|
||||
#include <common.h>
|
||||
#include <malloc.h>
|
||||
#include "jobdesc.h"
|
||||
#include "desc.h"
|
||||
#include "jr.h"
|
||||
|
||||
int blob_decrypt(u8 *key_mod, u8 *src, u8 *dst, u8 len)
|
||||
{
|
||||
int ret, i = 0;
|
||||
u32 *desc;
|
||||
|
||||
printf("\nDecapsulating data to form blob\n");
|
||||
desc = malloc(sizeof(int) * MAX_CAAM_DESCSIZE);
|
||||
if (!desc) {
|
||||
debug("Not enough memory for descriptor allocation\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
inline_cnstr_jobdesc_blob_decap(desc, key_mod, src, dst, len);
|
||||
|
||||
for (i = 0; i < 14; i++)
|
||||
printf("%x\n", *(desc + i));
|
||||
ret = run_descriptor_jr(desc);
|
||||
|
||||
if (ret)
|
||||
printf("Error in Decapsulation %d\n", ret);
|
||||
|
||||
free(desc);
|
||||
return ret;
|
||||
}
|
||||
|
||||
int blob_encrypt(u8 *key_mod, u8 *src, u8 *dst, u8 len)
|
||||
{
|
||||
int ret, i = 0;
|
||||
u32 *desc;
|
||||
|
||||
printf("\nEncapsulating data to form blob\n");
|
||||
desc = malloc(sizeof(int) * MAX_CAAM_DESCSIZE);
|
||||
if (!desc) {
|
||||
debug("Not enough memory for descriptor allocation\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
inline_cnstr_jobdesc_blob_encap(desc, key_mod, src, dst, len);
|
||||
for (i = 0; i < 14; i++)
|
||||
printf("%x\n", *(desc + i));
|
||||
ret = run_descriptor_jr(desc);
|
||||
|
||||
if (ret)
|
||||
printf("Error in Encapsulation %d\n", ret);
|
||||
|
||||
free(desc);
|
||||
return ret;
|
||||
}
|
||||
@@ -12,6 +12,9 @@
|
||||
#include "desc_constr.h"
|
||||
#include "jobdesc.h"
|
||||
|
||||
#define KEY_BLOB_SIZE 32
|
||||
#define MAC_SIZE 16
|
||||
|
||||
void inline_cnstr_jobdesc_hash(uint32_t *desc,
|
||||
const uint8_t *msg, uint32_t msgsz, uint8_t *digest,
|
||||
u32 alg_type, uint32_t alg_size, int sg_tbl)
|
||||
@@ -43,3 +46,80 @@ void inline_cnstr_jobdesc_hash(uint32_t *desc,
|
||||
append_store(desc, dma_addr_out, storelen,
|
||||
LDST_CLASS_2_CCB | LDST_SRCDST_BYTE_CONTEXT);
|
||||
}
|
||||
|
||||
void inline_cnstr_jobdesc_blob_encap(uint32_t *desc, uint8_t *key_idnfr,
|
||||
uint8_t *plain_txt, uint8_t *enc_blob,
|
||||
uint32_t in_sz)
|
||||
{
|
||||
dma_addr_t dma_addr_key_idnfr, dma_addr_in, dma_addr_out;
|
||||
uint32_t key_sz = KEY_IDNFR_SZ_BYTES;
|
||||
/* output blob will have 32 bytes key blob in beginning and
|
||||
* 16 byte HMAC identifier at end of data blob */
|
||||
uint32_t out_sz = in_sz + KEY_BLOB_SIZE + MAC_SIZE;
|
||||
|
||||
dma_addr_key_idnfr = virt_to_phys((void *)key_idnfr);
|
||||
dma_addr_in = virt_to_phys((void *)plain_txt);
|
||||
dma_addr_out = virt_to_phys((void *)enc_blob);
|
||||
|
||||
init_job_desc(desc, 0);
|
||||
|
||||
append_key(desc, dma_addr_key_idnfr, key_sz, CLASS_2);
|
||||
|
||||
append_seq_in_ptr(desc, dma_addr_in, in_sz, 0);
|
||||
|
||||
append_seq_out_ptr(desc, dma_addr_out, out_sz, 0);
|
||||
|
||||
append_operation(desc, OP_TYPE_ENCAP_PROTOCOL | OP_PCLID_BLOB);
|
||||
}
|
||||
|
||||
void inline_cnstr_jobdesc_blob_decap(uint32_t *desc, uint8_t *key_idnfr,
|
||||
uint8_t *enc_blob, uint8_t *plain_txt,
|
||||
uint32_t out_sz)
|
||||
{
|
||||
dma_addr_t dma_addr_key_idnfr, dma_addr_in, dma_addr_out;
|
||||
uint32_t key_sz = KEY_IDNFR_SZ_BYTES;
|
||||
uint32_t in_sz = out_sz + KEY_BLOB_SIZE + MAC_SIZE;
|
||||
|
||||
dma_addr_key_idnfr = virt_to_phys((void *)key_idnfr);
|
||||
dma_addr_in = virt_to_phys((void *)enc_blob);
|
||||
dma_addr_out = virt_to_phys((void *)plain_txt);
|
||||
|
||||
init_job_desc(desc, 0);
|
||||
|
||||
append_key(desc, dma_addr_key_idnfr, key_sz, CLASS_2);
|
||||
|
||||
append_seq_in_ptr(desc, dma_addr_in, in_sz, 0);
|
||||
|
||||
append_seq_out_ptr(desc, dma_addr_out, out_sz, 0);
|
||||
|
||||
append_operation(desc, OP_TYPE_DECAP_PROTOCOL | OP_PCLID_BLOB);
|
||||
}
|
||||
|
||||
/*
|
||||
* Descriptor to instantiate RNG State Handle 0 in normal mode and
|
||||
* load the JDKEK, TDKEK and TDSK registers
|
||||
*/
|
||||
void inline_cnstr_jobdesc_rng_instantiation(uint32_t *desc)
|
||||
{
|
||||
u32 *jump_cmd;
|
||||
|
||||
init_job_desc(desc, 0);
|
||||
|
||||
/* INIT RNG in non-test mode */
|
||||
append_operation(desc, OP_TYPE_CLASS1_ALG | OP_ALG_ALGSEL_RNG |
|
||||
OP_ALG_AS_INIT);
|
||||
|
||||
/* wait for done */
|
||||
jump_cmd = append_jump(desc, JUMP_CLASS_CLASS1);
|
||||
set_jump_tgt_here(desc, jump_cmd);
|
||||
|
||||
/*
|
||||
* load 1 to clear written reg:
|
||||
* resets the done interrrupt and returns the RNG to idle.
|
||||
*/
|
||||
append_load_imm_u32(desc, 1, LDST_SRCDST_WORD_CLRW);
|
||||
|
||||
/* generate secure keys (non-test) */
|
||||
append_operation(desc, OP_TYPE_CLASS1_ALG | OP_ALG_ALGSEL_RNG |
|
||||
OP_ALG_RNG4_SK);
|
||||
}
|
||||
|
||||
@@ -11,8 +11,19 @@
|
||||
#include <common.h>
|
||||
#include <asm/io.h>
|
||||
|
||||
#define KEY_IDNFR_SZ_BYTES 16
|
||||
|
||||
void inline_cnstr_jobdesc_hash(uint32_t *desc,
|
||||
const uint8_t *msg, uint32_t msgsz, uint8_t *digest,
|
||||
u32 alg_type, uint32_t alg_size, int sg_tbl);
|
||||
|
||||
void inline_cnstr_jobdesc_blob_encap(uint32_t *desc, uint8_t *key_idnfr,
|
||||
uint8_t *plain_txt, uint8_t *enc_blob,
|
||||
uint32_t in_sz);
|
||||
|
||||
void inline_cnstr_jobdesc_blob_decap(uint32_t *desc, uint8_t *key_idnfr,
|
||||
uint8_t *enc_blob, uint8_t *plain_txt,
|
||||
uint32_t out_sz);
|
||||
|
||||
void inline_cnstr_jobdesc_rng_instantiation(uint32_t *desc);
|
||||
#endif
|
||||
|
||||
@@ -10,6 +10,7 @@
|
||||
#include <malloc.h>
|
||||
#include "fsl_sec.h"
|
||||
#include "jr.h"
|
||||
#include "jobdesc.h"
|
||||
|
||||
#define CIRC_CNT(head, tail, size) (((head) - (tail)) & (size - 1))
|
||||
#define CIRC_SPACE(head, tail, size) CIRC_CNT((tail), (head) + 1, (size))
|
||||
@@ -319,6 +320,120 @@ int sec_reset(void)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int instantiate_rng(void)
|
||||
{
|
||||
struct result op;
|
||||
u32 *desc;
|
||||
u32 rdsta_val;
|
||||
int ret = 0;
|
||||
ccsr_sec_t __iomem *sec =
|
||||
(ccsr_sec_t __iomem *)CONFIG_SYS_FSL_SEC_ADDR;
|
||||
struct rng4tst __iomem *rng =
|
||||
(struct rng4tst __iomem *)&sec->rng;
|
||||
|
||||
memset(&op, 0, sizeof(struct result));
|
||||
|
||||
desc = malloc(sizeof(int) * 6);
|
||||
if (!desc) {
|
||||
printf("cannot allocate RNG init descriptor memory\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
inline_cnstr_jobdesc_rng_instantiation(desc);
|
||||
ret = run_descriptor_jr(desc);
|
||||
|
||||
if (ret)
|
||||
printf("RNG: Instantiation failed with error %x\n", ret);
|
||||
|
||||
rdsta_val = sec_in32(&rng->rdsta);
|
||||
if (op.status || !(rdsta_val & RNG_STATE0_HANDLE_INSTANTIATED))
|
||||
return -1;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static u8 get_rng_vid(void)
|
||||
{
|
||||
ccsr_sec_t *sec = (void *)CONFIG_SYS_FSL_SEC_ADDR;
|
||||
u32 cha_vid = sec_in32(&sec->chavid_ls);
|
||||
|
||||
return (cha_vid & SEC_CHAVID_RNG_LS_MASK) >> SEC_CHAVID_LS_RNG_SHIFT;
|
||||
}
|
||||
|
||||
/*
|
||||
* By default, the TRNG runs for 200 clocks per sample;
|
||||
* 1200 clocks per sample generates better entropy.
|
||||
*/
|
||||
static void kick_trng(int ent_delay)
|
||||
{
|
||||
ccsr_sec_t __iomem *sec =
|
||||
(ccsr_sec_t __iomem *)CONFIG_SYS_FSL_SEC_ADDR;
|
||||
struct rng4tst __iomem *rng =
|
||||
(struct rng4tst __iomem *)&sec->rng;
|
||||
u32 val;
|
||||
|
||||
/* put RNG4 into program mode */
|
||||
sec_setbits32(&rng->rtmctl, RTMCTL_PRGM);
|
||||
/* rtsdctl bits 0-15 contain "Entropy Delay, which defines the
|
||||
* length (in system clocks) of each Entropy sample taken
|
||||
* */
|
||||
val = sec_in32(&rng->rtsdctl);
|
||||
val = (val & ~RTSDCTL_ENT_DLY_MASK) |
|
||||
(ent_delay << RTSDCTL_ENT_DLY_SHIFT);
|
||||
sec_out32(&rng->rtsdctl, val);
|
||||
/* min. freq. count, equal to 1/4 of the entropy sample length */
|
||||
sec_out32(&rng->rtfreqmin, ent_delay >> 2);
|
||||
/* max. freq. count, equal to 8 times the entropy sample length */
|
||||
sec_out32(&rng->rtfreqmax, ent_delay << 3);
|
||||
/* put RNG4 into run mode */
|
||||
sec_clrbits32(&rng->rtmctl, RTMCTL_PRGM);
|
||||
}
|
||||
|
||||
static int rng_init(void)
|
||||
{
|
||||
int ret, ent_delay = RTSDCTL_ENT_DLY_MIN;
|
||||
ccsr_sec_t __iomem *sec =
|
||||
(ccsr_sec_t __iomem *)CONFIG_SYS_FSL_SEC_ADDR;
|
||||
struct rng4tst __iomem *rng =
|
||||
(struct rng4tst __iomem *)&sec->rng;
|
||||
|
||||
u32 rdsta = sec_in32(&rng->rdsta);
|
||||
|
||||
/* Check if RNG state 0 handler is already instantiated */
|
||||
if (rdsta & RNG_STATE0_HANDLE_INSTANTIATED)
|
||||
return 0;
|
||||
|
||||
do {
|
||||
/*
|
||||
* If either of the SH's were instantiated by somebody else
|
||||
* then it is assumed that the entropy
|
||||
* parameters are properly set and thus the function
|
||||
* setting these (kick_trng(...)) is skipped.
|
||||
* Also, if a handle was instantiated, do not change
|
||||
* the TRNG parameters.
|
||||
*/
|
||||
kick_trng(ent_delay);
|
||||
ent_delay += 400;
|
||||
/*
|
||||
* if instantiate_rng(...) fails, the loop will rerun
|
||||
* and the kick_trng(...) function will modfiy the
|
||||
* upper and lower limits of the entropy sampling
|
||||
* interval, leading to a sucessful initialization of
|
||||
* the RNG.
|
||||
*/
|
||||
ret = instantiate_rng();
|
||||
} while ((ret == -1) && (ent_delay < RTSDCTL_ENT_DLY_MAX));
|
||||
if (ret) {
|
||||
printf("RNG: Failed to instantiate RNG\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* Enable RDB bit so that RNG works faster */
|
||||
sec_setbits32(&sec->scfgr, SEC_SCFGR_RDBENABLE);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
int sec_init(void)
|
||||
{
|
||||
int ret = 0;
|
||||
@@ -330,8 +445,18 @@ int sec_init(void)
|
||||
sec_out32(&sec->mcfgr, mcr | 1 << MCFGR_PS_SHIFT);
|
||||
#endif
|
||||
ret = jr_init();
|
||||
if (ret < 0)
|
||||
if (ret < 0) {
|
||||
printf("SEC initialization failed\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (get_rng_vid() >= 4) {
|
||||
if (rng_init() < 0) {
|
||||
printf("RNG instantiation failed\n");
|
||||
return -1;
|
||||
}
|
||||
printf("SEC: RNG instantiated\n");
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user