linux-brain/drivers/crypto/caam/caamkeyblob_desc.c
Iuliana Prodan 84287c5d3b MLK-24420-2 crypto: caam - add support for black keys and blobs
CAAM's Black Key mechanism is intended for protection
of user keys against bus snooping. This automatically
encapsulates and decapsulates cryptographic keys ''on-the-fly''
in an encrypted data structure called a Black Key.
Before a value is copied from a Key Register to memory,
CAAM will automatically encrypt the key as a Black Key
(encrypted key) using the current value in the JDKEKR or
TDKEKR as the encryption key.

CAAM's built-in Blob Protocol provides a method for protecting
user-defined data across system power cycles. CAAM protects data
in a data structure called a Blob, which provides both confidentiality
and integrity protection. The data to be protected is encrypted so that
it can be safely placed into non-volatile storage before the SoC is
powered down.

This patch includes the support to generate a black key from random or
from a plaintext. Also one can encapsulate it into a blob or decapsulate
a black key from a blob.
The key and blob generation descriptors are exported into a separate file,
such that they could be shared with other interfaces (qi, qi2).

This feature has support only for black keys, encapsulated in
black blobs in General Memory.

In caamkeyblob_test.c file is a test that validates the above
operations: create a black key from plaintext or from random,
encapsulate and decapsulate a blob and compare the obtained black key.
This test is configured as a kernel module.

Signed-off-by: Franck LENORMAND <franck.lenormand@nxp.com>
Signed-off-by: Iuliana Prodan <iuliana.prodan@nxp.com>
Reviewed-by: Horia Geantă <horia.geanta@nxp.com>
2020-08-13 18:16:06 +03:00

456 lines
17 KiB
C

// SPDX-License-Identifier: (GPL-2.0+ OR BSD-3-Clause)
/*
* Shared descriptors for CAAM black key
* and blob encapsulation/decapsulation
*
* Copyright 2018-2020 NXP
*/
#include "caamkeyblob_desc.h"
/* Size of tmp buffer for descriptor const. */
#define INITIAL_DESCSZ 16
/*
* Construct a black key conversion job descriptor
*
* This function constructs a job descriptor capable of performing
* a key blackening operation on a plaintext secure memory resident object.
*
* @desc : Pointer to a pointer to the descriptor generated by this
* function. Caller will be responsible to kfree() this
* descriptor after execution.
* @key : Physical pointer to the plaintext, which will also hold
* the result. Since encryption occurs in place, caller must
* ensure that the space is large enough to accommodate the
* blackened key
* @key_len : Size of the plaintext
* @black_key : DMA address of the black key obtained from hardware
* @black_key_len : Size of the black key
* @key_enc : Encrypted Key Type (AES-ECB or AES-CCM)
* @trusted_key : Trusted Key (use Job Descriptor Key Encryption Key (JDKEK)
* or Trusted Descriptor Key Encryption Key (TDKEK) to
* decrypt the key to be loaded into a Key Register).
*
* Return : '0' on success, error code otherwise
*/
int cnstr_desc_black_key(u32 **desc, dma_addr_t key, size_t key_len,
dma_addr_t black_key, size_t black_key_len,
u8 key_enc, u8 trusted_key)
{
u32 *tdesc, tmpdesc[INITIAL_DESCSZ];
u16 dsize, idx;
u32 key_length_for_desc = key_len;
/* Trusted key not supported */
if (trusted_key != UNTRUSTED_KEY)
return -ENOTSUPP;
memset(tmpdesc, 0, sizeof(tmpdesc));
idx = 1;
/*
* KEY commands seems limited to 32 bytes, so we should use the load
* command instead which can load up to 64 bytes.
* The size must also be loaded.
*
* TODO: The KEY command indicate it should be able to load key bigger
* than 32bytes but it doesn't work in practice
*
* TODO: The LOAD command indicate it should be able to load up to 96
* byte keys it doesn't work in practice and is limited to 64 bytes
*/
/* Load key to class 1 key register */
tmpdesc[idx++] = CMD_LOAD | LDST_CLASS_1_CCB | LDST_SRCDST_BYTE_KEY |
key_length_for_desc;
tmpdesc[idx++] = (uintptr_t)key;
/* Load the size of the key */
tmpdesc[idx++] = CMD_LOAD | LDST_CLASS_1_CCB | LDST_IMM |
LDST_SRCDST_WORD_KEYSZ_REG |
sizeof(key_length_for_desc);
tmpdesc[idx++] = key_length_for_desc;
/* ...and write back out via FIFO store*/
tmpdesc[idx] = CMD_FIFO_STORE | CLASS_1 |
(black_key_len & KEY_LENGTH_MASK);
/* Plus account for ECB/CCM option in FIFO_STORE */
if (key_enc == KEY_COVER_ECB)
tmpdesc[idx] |= FIFOST_TYPE_KEY_KEK;
else
tmpdesc[idx] |= FIFOST_TYPE_KEY_CCM_JKEK;
idx++;
tmpdesc[idx++] = (uintptr_t)black_key;
/* Finish off the job header */
tmpdesc[0] = CMD_DESC_HDR | HDR_ONE | (idx & HDR_DESCLEN_MASK);
dsize = desc_bytes(&tmpdesc);
/* Now allocate execution buffer and coat it with executable */
tdesc = kmemdup(tmpdesc, dsize, GFP_KERNEL | GFP_DMA);
if (!tdesc)
return -ENOMEM;
*desc = tdesc;
print_hex_dump_debug("black key desc@" __stringify(__LINE__) ":",
DUMP_PREFIX_ADDRESS, 16, 4, *desc,
desc_bytes(*desc), 1);
return 0;
}
EXPORT_SYMBOL(cnstr_desc_black_key);
/*
* Construct a black key using RNG job descriptor
*
* This function constructs a job descriptor capable of performing
* a key blackening operation on RNG generated.
*
* @desc : Pointer to a pointer to the descriptor generated by this
* function. Caller will be responsible to kfree() this
* descriptor after execution.
* @key_len : Size of the random plaintext
* @black_key : DMA address of the black key obtained from hardware
* @black_key_len : Size of the black key
* @key_enc : Encrypted Key Type (AES-ECB or AES-CCM)
* @trusted_key : Trusted Key (use Job Descriptor Key Encryption Key (JDKEK)
* or Trusted Descriptor Key Encryption Key (TDKEK) to
* decrypt the key to be loaded into a Key Register).
*
* Return : '0' on success, error code otherwise
*/
int cnstr_desc_random_black_key(u32 **desc, size_t key_len,
dma_addr_t black_key, size_t black_key_len,
u8 key_enc, u8 trusted_key)
{
u32 *tdesc, tmpdesc[INITIAL_DESCSZ];
u16 dsize;
u32 bk_store;
memset(tmpdesc, 0, sizeof(tmpdesc));
init_job_desc(tmpdesc, CMD_DESC_HDR);
/* Prepare RNG */
append_operation(tmpdesc, OP_ALG_ALGSEL_RNG | OP_TYPE_CLASS1_ALG);
/* Generate RNG and left it in output data fifo */
append_cmd(tmpdesc, CMD_FIFO_STORE | FIFOST_TYPE_RNGFIFO | key_len);
/* Copy RNG from outfifo to class 1 Key register */
append_move(tmpdesc, MOVE_SRC_OUTFIFO | MOVE_DEST_CLASS1KEY |
MOVE_WAITCOMP | (key_len & MOVE_LEN_MASK));
/* Write the size of the key moved */
append_load_imm_u32(tmpdesc, key_len, LDST_CLASS_1_CCB |
LDST_SRCDST_WORD_KEYSZ_REG | LDST_IMM);
bk_store = CLASS_1;
if (key_enc == KEY_COVER_ECB)
bk_store |= FIFOST_TYPE_KEY_KEK;
else
bk_store |= FIFOST_TYPE_KEY_CCM_JKEK;
/* Fifo store to save the key as black key in memory */
append_fifo_store(tmpdesc, black_key, black_key_len, bk_store);
dsize = desc_bytes(&tmpdesc);
/* Now allocate execution buffer and coat it with executable */
tdesc = kmemdup(tmpdesc, dsize, GFP_KERNEL | GFP_DMA);
if (!tdesc)
return -ENOMEM;
*desc = tdesc;
print_hex_dump_debug("black key random desc@" __stringify(__LINE__) ":",
DUMP_PREFIX_ADDRESS, 16, 4, *desc,
desc_bytes(*desc), 1);
return 0;
}
EXPORT_SYMBOL(cnstr_desc_random_black_key);
/*
* Construct a blob encapsulation job descriptor
*
* This function dynamically constructs a blob encapsulation job descriptor
* from the following arguments:
*
* @desc : Pointer to a pointer to the descriptor generated by this
* function. Caller will be responsible to kfree() this
* descriptor after execution.
* @black_key : Physical pointer to a secret, normally a black or red key,
* possibly residing within an accessible secure memory page,
* of the secret to be encapsulated to an output blob.
* @black_key_len : Size of input secret, in bytes. This is limited to 65536
* less the size of blob overhead, since the length embeds
* into DECO pointer in/out instructions.
* @keycolor : Determines if the source data is covered (black key) or
* plaintext (red key). RED_KEY or BLACK_KEY are defined in
* for this purpose.
* @key_enc : If BLACK_KEY source is covered via AES-CCM, specify
* KEY_COVER_CCM, else uses AES-ECB (KEY_COVER_ECB).
* @trusted_key : Trusted Key (use Job Descriptor Key Encryption Key (JDKEK)
* or Trusted Descriptor Key Encryption Key (TDKEK) to
* decrypt the key to be loaded into a Key Register).
* @mem_type : Determine if encapsulated blob should be a secure memory
* blob (DATA_SECMEM), with partition data embedded with key
* material, or a general memory blob (DATA_GENMEM).
* @key_mod : Physical pointer to a key modifier, which must reside in a
* contiguous piece of memory. Modifier will be assumed to be
* 8 bytes long for a blob of type DATA_SECMEM, or 16 bytes
* long for a blob of type DATA_GENMEM
* @key_mod_len : Modifier length is 8 bytes long for a blob of type
* DATA_SECMEM, or 16 bytes long for a blob of type DATA_GENMEM
* @blob : Physical pointer to the destination buffer to receive the
* encapsulated output. This buffer will need to be 48 bytes
* larger than the input because of the added encapsulation
* data. The generated descriptor will account for the
* increase in size, but the caller must also account for
* this increase in the buffer allocator.
* @blob_len : Size of the destination buffer to receive the
* encapsulated output.
* Return : '0' on success, error code otherwise
*
* Upon completion, desc points to a buffer containing a CAAM job
* descriptor which encapsulates data into an externally-storable blob
* suitable for use across power cycles.
*
* This is an example of a black key encapsulation job into a general memory
* blob. Notice the 16-byte key modifier in the LOAD instruction. Also note
* the output 48 bytes longer than the input:
*
* [00] B0800008 jobhdr: stidx=0 len=8
* [01] 14400010 ld: ccb2-key len=16 offs=0
* [02] 08144891 ptr->@0x08144891
* [03] F800003A seqoutptr: len=58
* [04] 01000000 out_ptr->@0x01000000
* [05] F000000A seqinptr: len=10
* [06] 09745090 in_ptr->@0x09745090
* [07] 870D0004 operation: encap blob reg=memory, black, format=normal
*
* This is an example of a red key encapsulation job for storing a red key
* into a secure memory blob. Note the 8 byte modifier on the 12 byte offset
* in the LOAD instruction; this accounts for blob permission storage:
*
* [00] B0800008 jobhdr: stidx=0 len=8
* [01] 14400C08 ld: ccb2-key len=8 offs=12
* [02] 087D0784 ptr->@0x087d0784
* [03] F8000050 seqoutptr: len=80
* [04] 09251BB2 out_ptr->@0x09251bb2
* [05] F0000020 seqinptr: len=32
* [06] 40000F31 in_ptr->@0x40000f31
* [07] 870D0008 operation: encap blob reg=memory, red, sec_mem,
* format=normal
*/
int cnstr_desc_blob_encap(u32 **desc, dma_addr_t black_key,
size_t black_key_len, u8 keycolor, u8 key_enc,
u8 trusted_key, u8 mem_type, dma_addr_t key_mod,
size_t key_mod_len, dma_addr_t blob, size_t blob_len)
{
u32 *tdesc, tmpdesc[INITIAL_DESCSZ];
u16 dsize, idx;
/* Trusted key not supported */
if (trusted_key != UNTRUSTED_KEY)
return -ENOTSUPP;
memset(tmpdesc, 0, sizeof(tmpdesc));
idx = 1;
/*
* Key modifier works differently for secure/general memory blobs
* This accounts for the permission/protection data encapsulated
* within the blob if a secure memory blob is requested
*/
if (mem_type == DATA_SECMEM)
tmpdesc[idx++] = CMD_LOAD | LDST_CLASS_2_CCB |
LDST_SRCDST_BYTE_KEY |
((12 << LDST_OFFSET_SHIFT) & LDST_OFFSET_MASK)
| (key_mod_len & LDST_LEN_MASK);
else /* is general memory blob */
tmpdesc[idx++] = CMD_LOAD | LDST_CLASS_2_CCB
| LDST_SRCDST_BYTE_KEY
| (key_mod_len & LDST_LEN_MASK);
tmpdesc[idx++] = (u32)key_mod;
/*
* Encapsulation output must include space for blob key encryption
* key and MAC tag
*/
tmpdesc[idx++] = CMD_SEQ_OUT_PTR | (black_key_len + BLOB_OVERHEAD);
tmpdesc[idx++] = (u32)blob;
/* Input data, should be somewhere in secure memory */
tmpdesc[idx++] = CMD_SEQ_IN_PTR | black_key_len;
tmpdesc[idx++] = (uintptr_t)black_key;
/* Set blob encap, then color */
tmpdesc[idx] = CMD_OPERATION | OP_TYPE_ENCAP_PROTOCOL | OP_PCLID_BLOB;
if (mem_type == DATA_SECMEM)
tmpdesc[idx] |= OP_PCL_BLOB_PTXT_SECMEM;
if (key_enc == KEY_COVER_CCM)
tmpdesc[idx] |= OP_PCL_BLOB_EKT;
/* An input black key cannot be stored in a red blob */
if (keycolor == BLACK_KEY)
tmpdesc[idx] |= OP_PCL_BLOB_BLACK;
idx++;
tmpdesc[0] = CMD_DESC_HDR | HDR_ONE | (idx & HDR_DESCLEN_MASK);
dsize = desc_bytes(&tmpdesc);
tdesc = kmemdup(tmpdesc, dsize, GFP_KERNEL | GFP_DMA);
if (!tdesc)
return -ENOMEM;
*desc = tdesc;
print_hex_dump_debug("blob encap desc@" __stringify(__LINE__) ":",
DUMP_PREFIX_ADDRESS, 16, 4, *desc,
desc_bytes(*desc), 1);
return 0;
}
EXPORT_SYMBOL(cnstr_desc_blob_encap);
/*
* Construct a blob decapsulation job descriptor
*
* This function dynamically constructs a blob decapsulation job descriptor
* from the following arguments:
*
* @desc : Pointer to a pointer to the descriptor generated by this
* function. Caller will be responsible to kfree() this
* descriptor after execution.
* @blob : Physical pointer (into external memory) of the blob to
* be decapsulated. Blob must reside in a contiguous memory
* segment.
* @blob_len : Size of the blob buffer to be decapsulated.
* @key_mod : Physical pointer to a key modifier, which must reside in a
* contiguous piece of memory. Modifier will be assumed to be
* 8 bytes long for a blob of type DATA_SECMEM, or 16 bytes
* long for a blob of type DATA_GENMEM
* @key_mod_len : Modifier length is 8 bytes long for a blob of type
* DATA_SECMEM, or 16 bytes long for a blob of type DATA_GENMEM
* @black_key : Physical pointer of the decapsulated output, possibly into
* a location within a secure memory page. Must be contiguous.
* @black_key_len : Size of encapsulated secret in bytes (not the size of the
* input blob).
* @keycolor : Determines if the source data is covered (black key) or
* plaintext (red key). RED_KEY or BLACK_KEY are defined in
* for this purpose.
* @key_enc : If BLACK_KEY source is covered via AES-CCM, specify
* KEY_COVER_CCM, else uses AES-ECB (KEY_COVER_ECB).
* @trusted_key : Trusted Key (use Job Descriptor Key Encryption Key (JDKEK)
* or Trusted Descriptor Key Encryption Key (TDKEK) to
* decrypt the key to be loaded into a Key Register).
* @mem_type : Determine if encapsulated blob should be a secure memory
* blob (DATA_SECMEM), with partition data embedded with key
* material, or a general memory blob (DATA_GENMEM).
* Return : '0' on success, error code otherwise
*
* Upon completion, desc points to a buffer containing a CAAM job descriptor
* that decapsulates a key blob from external memory into a black (encrypted)
* key or red (plaintext) content.
*
* This is an example of a black key decapsulation job from a general memory
* blob. Notice the 16-byte key modifier in the LOAD instruction.
*
* [00] B0800008 jobhdr: stidx=0 len=8
* [01] 14400010 ld: ccb2-key len=16 offs=0
* [02] 08A63B7F ptr->@0x08a63b7f
* [03] F8000010 seqoutptr: len=16
* [04] 01000000 out_ptr->@0x01000000
* [05] F000003A seqinptr: len=58
* [06] 01000010 in_ptr->@0x01000010
* [07] 860D0004 operation: decap blob reg=memory, black, format=normal
*
* This is an example of a red key decapsulation job for restoring a red key
* from a secure memory blob. Note the 8 byte modifier on the 12 byte offset
* in the LOAD instruction:
*
* [00] B0800008 jobhdr: stidx=0 len=8
* [01] 14400C08 ld: ccb2-key len=8 offs=12
* [02] 01000000 ptr->@0x01000000
* [03] F8000020 seqoutptr: len=32
* [04] 400000E6 out_ptr->@0x400000e6
* [05] F0000050 seqinptr: len=80
* [06] 08F0C0EA in_ptr->@0x08f0c0ea
* [07] 860D0008 operation: decap blob reg=memory, red, sec_mem,
* format=normal
*/
int cnstr_desc_blob_decap(u32 **desc, dma_addr_t blob, size_t blob_len,
dma_addr_t key_mod, size_t key_mod_len,
dma_addr_t black_key, size_t black_key_len,
u8 keycolor, u8 key_enc, u8 trusted_key, u8 mem_type)
{
u32 *tdesc, tmpdesc[INITIAL_DESCSZ];
u16 dsize, idx;
/* Trusted key not supported */
if (trusted_key != UNTRUSTED_KEY)
return -ENOTSUPP;
memset(tmpdesc, 0, sizeof(tmpdesc));
idx = 1;
/* Load key modifier */
if (mem_type == DATA_SECMEM)
tmpdesc[idx++] = CMD_LOAD | LDST_CLASS_2_CCB |
LDST_SRCDST_BYTE_KEY |
((12 << LDST_OFFSET_SHIFT) & LDST_OFFSET_MASK)
| (key_mod_len & LDST_LEN_MASK);
else /* is general memory blob */
tmpdesc[idx++] = CMD_LOAD
| LDST_CLASS_2_CCB
| LDST_SRCDST_BYTE_KEY
| (key_mod_len & LDST_LEN_MASK);
tmpdesc[idx++] = (u32)key_mod;
/* Compensate BKEK + MAC tag over size of encapsulated secret */
tmpdesc[idx++] = CMD_SEQ_IN_PTR | blob_len;
tmpdesc[idx++] = (u32)blob;
tmpdesc[idx++] = CMD_SEQ_OUT_PTR | black_key_len;
tmpdesc[idx++] = (uintptr_t)black_key;
/* Decapsulate from secure memory partition to black blob */
tmpdesc[idx] = CMD_OPERATION | OP_TYPE_DECAP_PROTOCOL | OP_PCLID_BLOB;
if (mem_type == DATA_SECMEM)
tmpdesc[idx] |= OP_PCL_BLOB_PTXT_SECMEM;
if (key_enc == KEY_COVER_CCM)
tmpdesc[idx] |= OP_PCL_BLOB_EKT;
if (keycolor == BLACK_KEY)
tmpdesc[idx] |= OP_PCL_BLOB_BLACK;
idx++;
tmpdesc[0] = CMD_DESC_HDR | HDR_ONE | (idx & HDR_DESCLEN_MASK);
dsize = desc_bytes(&tmpdesc);
tdesc = kmemdup(tmpdesc, dsize, GFP_KERNEL | GFP_DMA);
if (!tdesc)
return -ENOMEM;
*desc = tdesc;
print_hex_dump_debug("blob decap desc@" __stringify(__LINE__) ":",
DUMP_PREFIX_ADDRESS, 16, 4, *desc,
desc_bytes(*desc), 1);
return 0;
}
EXPORT_SYMBOL(cnstr_desc_blob_decap);
MODULE_LICENSE("Dual BSD/GPL");
MODULE_DESCRIPTION("NXP CAAM Black Key and Blob descriptors");
MODULE_AUTHOR("NXP Semiconductors");