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:
Ruchika Gupta 2014-10-07 15:46:20 +05:30 committed by York Sun
parent 7cad2e38d6
commit c5de15cbc8
8 changed files with 423 additions and 2 deletions

View file

@ -265,4 +265,6 @@ obj-y += aboot.o
obj-y += fb_mmc.o obj-y += fb_mmc.o
endif endif
obj-$(CONFIG_CMD_BLOB) += cmd_blob.o
CFLAGS_env_embedded.o := -Wa,--no-warn -DENV_CRC=$(shell tools/envcrc 2>/dev/null) CFLAGS_env_embedded.o := -Wa,--no-warn -DENV_CRC=$(shell tools/envcrc 2>/dev/null)

109
common/cmd_blob.c Normal file
View file

@ -0,0 +1,109 @@
/*
*
* Command for encapsulating/decapsulating blob of memory.
*
* SPDX-License-Identifier: GPL-2.0+
*/
#include <common.h>
#include <command.h>
#include <environment.h>
#include <malloc.h>
#include <asm/byteorder.h>
#include <linux/compiler.h>
DECLARE_GLOBAL_DATA_PTR;
/**
* blob_decap() - Decapsulate the data as a blob
* @key_mod: - Pointer to key modifier/key
* @src: - Address of data to be decapsulated
* @dst: - Address of data to be decapsulated
* @len: - Size of data to be decapsulated
*
* Returns zero on success,and negative on error.
*/
__weak int blob_decap(u8 *key_mod, u8 *src, u8 *dst, u32 len)
{
return 0;
}
/**
* blob_encap() - Encapsulate the data as a blob
* @key_mod: - Pointer to key modifier/key
* @src: - Address of data to be encapsulated
* @dst: - Address of data to be encapsulated
* @len: - Size of data to be encapsulated
*
* Returns zero on success,and negative on error.
*/
__weak int blob_encap(u8 *key_mod, u8 *src, u8 *dst, u32 len)
{
return 0;
}
/**
* do_blob() - Handle the "blob" command-line command
* @cmdtp: Command data struct pointer
* @flag: Command flag
* @argc: Command-line argument count
* @argv: Array of command-line arguments
*
* Returns zero on success, CMD_RET_USAGE in case of misuse and negative
* on error.
*/
static int do_blob(cmd_tbl_t *cmdtp, int flag, int argc, char *const argv[])
{
uint32_t key_addr, src_addr, dst_addr, len;
uint8_t *km_ptr, *src_ptr, *dst_ptr;
int enc, ret = 0;
if (argc != 6)
return CMD_RET_USAGE;
if (!strncmp(argv[1], "enc", 3))
enc = 1;
else if (!strncmp(argv[1], "dec", 3))
enc = 0;
else
return CMD_RET_USAGE;
src_addr = simple_strtoul(argv[2], NULL, 16);
dst_addr = simple_strtoul(argv[3], NULL, 16);
len = simple_strtoul(argv[4], NULL, 16);
key_addr = simple_strtoul(argv[5], NULL, 16);
km_ptr = (uint8_t *)key_addr;
src_ptr = (uint8_t *)src_addr;
dst_ptr = (uint8_t *)dst_addr;
if (enc)
ret = blob_encap(km_ptr, src_ptr, dst_ptr, len);
else
ret = blob_decap(km_ptr, src_ptr, dst_ptr, len);
return ret;
}
/***************************************************/
static char blob_help_text[] =
"enc src dst len km - Encapsulate and create blob of data\n"
" $len bytes long at address $src and\n"
" store the result at address $dst.\n"
" $km is the 16 byte key modifier\n"
" is also required for generation/use as\n"
" key for cryptographic operation. Key\n"
" modifier should be 16 byte long.\n"
"blob dec src dst len km - Decapsulate the blob of data at address\n"
" $src and store result of $len byte at\n"
" addr $dst.\n"
" $km is the 16 byte key modifier\n"
" is also required for generation/use as\n"
" key for cryptographic operation. Key\n"
" modifier should be 16 byte long.\n";
U_BOOT_CMD(
blob, 6, 1, do_blob,
"Blob encapsulation/decryption",
blob_help_text
);

View file

@ -7,3 +7,4 @@
# #
obj-$(CONFIG_FSL_CAAM) += jr.o fsl_hash.o jobdesc.o error.o obj-$(CONFIG_FSL_CAAM) += jr.o fsl_hash.o jobdesc.o error.o
obj-$(CONFIG_CMD_BLOB) += fsl_blob.o

View 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;
}

View file

@ -12,6 +12,9 @@
#include "desc_constr.h" #include "desc_constr.h"
#include "jobdesc.h" #include "jobdesc.h"
#define KEY_BLOB_SIZE 32
#define MAC_SIZE 16
void inline_cnstr_jobdesc_hash(uint32_t *desc, void inline_cnstr_jobdesc_hash(uint32_t *desc,
const uint8_t *msg, uint32_t msgsz, uint8_t *digest, const uint8_t *msg, uint32_t msgsz, uint8_t *digest,
u32 alg_type, uint32_t alg_size, int sg_tbl) 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, append_store(desc, dma_addr_out, storelen,
LDST_CLASS_2_CCB | LDST_SRCDST_BYTE_CONTEXT); 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);
}

View file

@ -11,8 +11,19 @@
#include <common.h> #include <common.h>
#include <asm/io.h> #include <asm/io.h>
#define KEY_IDNFR_SZ_BYTES 16
void inline_cnstr_jobdesc_hash(uint32_t *desc, void inline_cnstr_jobdesc_hash(uint32_t *desc,
const uint8_t *msg, uint32_t msgsz, uint8_t *digest, const uint8_t *msg, uint32_t msgsz, uint8_t *digest,
u32 alg_type, uint32_t alg_size, int sg_tbl); 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 #endif

View file

@ -10,6 +10,7 @@
#include <malloc.h> #include <malloc.h>
#include "fsl_sec.h" #include "fsl_sec.h"
#include "jr.h" #include "jr.h"
#include "jobdesc.h"
#define CIRC_CNT(head, tail, size) (((head) - (tail)) & (size - 1)) #define CIRC_CNT(head, tail, size) (((head) - (tail)) & (size - 1))
#define CIRC_SPACE(head, tail, size) CIRC_CNT((tail), (head) + 1, (size)) #define CIRC_SPACE(head, tail, size) CIRC_CNT((tail), (head) + 1, (size))
@ -319,6 +320,120 @@ int sec_reset(void)
return 0; 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 sec_init(void)
{ {
int ret = 0; int ret = 0;
@ -330,8 +445,18 @@ int sec_init(void)
sec_out32(&sec->mcfgr, mcr | 1 << MCFGR_PS_SHIFT); sec_out32(&sec->mcfgr, mcr | 1 << MCFGR_PS_SHIFT);
#endif #endif
ret = jr_init(); ret = jr_init();
if (ret < 0) if (ret < 0) {
printf("SEC initialization failed\n");
return -1; 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; return ret;
} }

View file

@ -29,6 +29,36 @@
/* Security Engine Block (MS = Most Sig., LS = Least Sig.) */ /* Security Engine Block (MS = Most Sig., LS = Least Sig.) */
#if CONFIG_SYS_FSL_SEC_COMPAT >= 4 #if CONFIG_SYS_FSL_SEC_COMPAT >= 4
/* RNG4 TRNG test registers */
struct rng4tst {
#define RTMCTL_PRGM 0x00010000 /* 1 -> program mode, 0 -> run mode */
u32 rtmctl; /* misc. control register */
u32 rtscmisc; /* statistical check misc. register */
u32 rtpkrrng; /* poker range register */
#define RTSDCTL_ENT_DLY_MIN 1200
#define RTSDCTL_ENT_DLY_MAX 12800
union {
u32 rtpkrmax; /* PRGM=1: poker max. limit register */
u32 rtpkrsq; /* PRGM=0: poker square calc. result register */
};
#define RTSDCTL_ENT_DLY_SHIFT 16
#define RTSDCTL_ENT_DLY_MASK (0xffff << RTSDCTL_ENT_DLY_SHIFT)
u32 rtsdctl; /* seed control register */
union {
u32 rtsblim; /* PRGM=1: sparse bit limit register */
u32 rttotsam; /* PRGM=0: total samples register */
};
u32 rtfreqmin; /* frequency count min. limit register */
union {
u32 rtfreqmax; /* PRGM=1: freq. count max. limit register */
u32 rtfreqcnt; /* PRGM=0: freq. count register */
};
u32 rsvd1[40];
#define RNG_STATE0_HANDLE_INSTANTIATED 0x00000001
u32 rdsta; /*RNG DRNG Status Register*/
u32 rsvd2[15];
};
typedef struct ccsr_sec { typedef struct ccsr_sec {
u32 res0; u32 res0;
u32 mcfgr; /* Master CFG Register */ u32 mcfgr; /* Master CFG Register */
@ -53,7 +83,9 @@ typedef struct ccsr_sec {
u8 res4[0x40]; u8 res4[0x40];
u32 dar; /* DECO Avail Register */ u32 dar; /* DECO Avail Register */
u32 drr; /* DECO Reset Register */ u32 drr; /* DECO Reset Register */
u8 res5[0xe78]; u8 res5[0x4d8];
struct rng4tst rng; /* RNG Registers */
u8 res11[0x8a0];
u32 crnr_ms; /* CHA Revision Number Register, MS */ u32 crnr_ms; /* CHA Revision Number Register, MS */
u32 crnr_ls; /* CHA Revision Number Register, LS */ u32 crnr_ls; /* CHA Revision Number Register, LS */
u32 ctpr_ms; /* Compile Time Parameters Register, MS */ u32 ctpr_ms; /* Compile Time Parameters Register, MS */