447 lines
17 KiB
C
447 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 64
|
|
|
|
/*
|
|
* 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 : 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, char *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;
|
|
u32 bk_store;
|
|
u32 key_length_for_desc = key_len;
|
|
|
|
/* Trusted key not supported */
|
|
if (trusted_key != UNTRUSTED_KEY)
|
|
return -ENOTSUPP;
|
|
|
|
memset(tmpdesc, 0, sizeof(tmpdesc));
|
|
|
|
init_job_desc(tmpdesc, 0);
|
|
|
|
/*
|
|
* 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 */
|
|
append_load_as_imm(tmpdesc, (void *)key, key_length_for_desc,
|
|
LDST_CLASS_1_CCB | LDST_SRCDST_BYTE_KEY);
|
|
|
|
/* Load the size of the key */
|
|
append_load_imm_u32(tmpdesc, key_length_for_desc, LDST_CLASS_1_CCB |
|
|
LDST_IMM | LDST_SRCDST_WORD_KEYSZ_REG);
|
|
|
|
/* ...and write back out via FIFO store*/
|
|
bk_store = CLASS_1;
|
|
if (key_enc == KEY_COVER_ECB)
|
|
bk_store |= FIFOST_TYPE_KEY_KEK;
|
|
else
|
|
bk_store |= FIFOST_TYPE_KEY_CCM_JKEK;
|
|
|
|
/* 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 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, 0);
|
|
|
|
/* 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 : 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 key_len, u8 keycolor, u8 key_enc,
|
|
u8 trusted_key, u8 mem_type, const void *key_mod,
|
|
size_t key_mod_len, dma_addr_t blob, size_t blob_len)
|
|
{
|
|
u32 *tdesc, tmpdesc[INITIAL_DESCSZ];
|
|
u16 dsize;
|
|
u32 bk_store;
|
|
|
|
/* Trusted key not supported */
|
|
if (trusted_key != UNTRUSTED_KEY)
|
|
return -ENOTSUPP;
|
|
|
|
memset(tmpdesc, 0, sizeof(tmpdesc));
|
|
|
|
init_job_desc(tmpdesc, 0);
|
|
|
|
/*
|
|
* 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)
|
|
append_load_as_imm(tmpdesc, key_mod, key_mod_len,
|
|
LDST_CLASS_2_CCB | LDST_SRCDST_BYTE_KEY |
|
|
((12 << LDST_OFFSET_SHIFT) &
|
|
LDST_OFFSET_MASK));
|
|
else /* is general memory blob */
|
|
append_load_as_imm(tmpdesc, key_mod, key_mod_len,
|
|
LDST_CLASS_2_CCB | LDST_SRCDST_BYTE_KEY);
|
|
|
|
/* Input data, should be somewhere in secure memory */
|
|
append_seq_in_ptr_intlen(tmpdesc, black_key, key_len, 0);
|
|
|
|
/*
|
|
* Encapsulation output must include space for blob key encryption
|
|
* key and MAC tag
|
|
*/
|
|
append_seq_out_ptr_intlen(tmpdesc, blob, CCM_BLACK_KEY_SIZE(key_len) +
|
|
BLOB_OVERHEAD, 0);
|
|
|
|
bk_store = OP_PCLID_BLOB;
|
|
if (mem_type == DATA_SECMEM)
|
|
bk_store |= OP_PCL_BLOB_PTXT_SECMEM;
|
|
|
|
if (key_enc == KEY_COVER_CCM)
|
|
bk_store |= OP_PCL_BLOB_EKT;
|
|
|
|
/* An input black key cannot be stored in a red blob */
|
|
if (keycolor == BLACK_KEY)
|
|
bk_store |= OP_PCL_BLOB_BLACK;
|
|
|
|
/* Set blob encap, then color */
|
|
append_operation(tmpdesc, OP_TYPE_ENCAP_PROTOCOL | bk_store);
|
|
|
|
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 : 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,
|
|
const void *key_mod, size_t key_mod_len,
|
|
dma_addr_t black_key, size_t plaintext_len,
|
|
u8 keycolor, u8 key_enc, u8 trusted_key, u8 mem_type)
|
|
{
|
|
u32 *tdesc, tmpdesc[INITIAL_DESCSZ];
|
|
u16 dsize;
|
|
u32 bk_store;
|
|
|
|
/* Trusted key not supported */
|
|
if (trusted_key != UNTRUSTED_KEY)
|
|
return -ENOTSUPP;
|
|
|
|
memset(tmpdesc, 0, sizeof(tmpdesc));
|
|
|
|
init_job_desc(tmpdesc, 0);
|
|
|
|
/* Load key modifier */
|
|
if (mem_type == DATA_SECMEM)
|
|
append_load_as_imm(tmpdesc, key_mod, key_mod_len,
|
|
LDST_CLASS_2_CCB | LDST_SRCDST_BYTE_KEY |
|
|
((12 << LDST_OFFSET_SHIFT) &
|
|
LDST_OFFSET_MASK));
|
|
else /* is general memory blob */
|
|
append_load_as_imm(tmpdesc, key_mod, key_mod_len,
|
|
LDST_CLASS_2_CCB | LDST_SRCDST_BYTE_KEY);
|
|
|
|
/* Compensate blob header + MAC tag over size of encapsulated secret */
|
|
append_seq_in_ptr_intlen(tmpdesc, blob, plaintext_len + BLOB_OVERHEAD,
|
|
0);
|
|
|
|
append_seq_out_ptr_intlen(tmpdesc, black_key, plaintext_len, 0);
|
|
|
|
/* Decapsulate from secure memory partition to black blob */
|
|
bk_store = OP_PCLID_BLOB;
|
|
if (mem_type == DATA_SECMEM)
|
|
bk_store |= OP_PCL_BLOB_PTXT_SECMEM;
|
|
|
|
if (key_enc == KEY_COVER_CCM)
|
|
bk_store |= OP_PCL_BLOB_EKT;
|
|
|
|
/* An input black key cannot be stored in a red blob */
|
|
if (keycolor == BLACK_KEY)
|
|
bk_store |= OP_PCL_BLOB_BLACK;
|
|
|
|
/* Set blob encap, then color */
|
|
append_operation(tmpdesc, OP_TYPE_DECAP_PROTOCOL | bk_store);
|
|
|
|
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");
|