Skip to content

Commit

Permalink
crypto: ccree - add remaining logic for CPP
Browse files Browse the repository at this point in the history
Add the missing logic to set usage policy protections for keys.
This enables key policy protection for AES.

Signed-off-by: Gilad Ben-Yossef <gilad@benyossef.com>
Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>
  • Loading branch information
Gilad Ben-Yossef authored and Herbert Xu committed Apr 25, 2019
1 parent cadfd89 commit 52f42c6
Showing 3 changed files with 178 additions and 51 deletions.
186 changes: 135 additions & 51 deletions drivers/crypto/ccree/cc_cipher.c
Original file line number Diff line number Diff line change
@@ -34,26 +34,41 @@ struct cc_hw_key_info {
enum cc_hw_crypto_key key2_slot;
};

struct cc_cpp_key_info {
u8 slot;
enum cc_cpp_alg alg;
};

enum cc_key_type {
CC_UNPROTECTED_KEY, /* User key */
CC_HW_PROTECTED_KEY, /* HW (FDE) key */
CC_POLICY_PROTECTED_KEY, /* CPP key */
CC_INVALID_PROTECTED_KEY /* Invalid key */
};

struct cc_cipher_ctx {
struct cc_drvdata *drvdata;
int keylen;
int key_round_number;
int cipher_mode;
int flow_mode;
unsigned int flags;
bool hw_key;
enum cc_key_type key_type;
struct cc_user_key_info user;
struct cc_hw_key_info hw;
union {
struct cc_hw_key_info hw;
struct cc_cpp_key_info cpp;
};
struct crypto_shash *shash_tfm;
};

static void cc_cipher_complete(struct device *dev, void *cc_req, int err);

static inline bool cc_is_hw_key(struct crypto_tfm *tfm)
static inline enum cc_key_type cc_key_type(struct crypto_tfm *tfm)
{
struct cc_cipher_ctx *ctx_p = crypto_tfm_ctx(tfm);

return ctx_p->hw_key;
return ctx_p->key_type;
}

static int validate_keys_sizes(struct cc_cipher_ctx *ctx_p, u32 size)
@@ -232,7 +247,7 @@ struct tdes_keys {
u8 key3[DES_KEY_SIZE];
};

static enum cc_hw_crypto_key cc_slot_to_hw_key(int slot_num)
static enum cc_hw_crypto_key cc_slot_to_hw_key(u8 slot_num)
{
switch (slot_num) {
case 0:
@@ -247,6 +262,22 @@ static enum cc_hw_crypto_key cc_slot_to_hw_key(int slot_num)
return END_OF_KEYS;
}

static u8 cc_slot_to_cpp_key(u8 slot_num)
{
return (slot_num - CC_FIRST_CPP_KEY_SLOT);
}

static inline enum cc_key_type cc_slot_to_key_type(u8 slot_num)
{
if (slot_num >= CC_FIRST_HW_KEY_SLOT && slot_num <= CC_LAST_HW_KEY_SLOT)
return CC_HW_PROTECTED_KEY;
else if (slot_num >= CC_FIRST_CPP_KEY_SLOT &&
slot_num <= CC_LAST_CPP_KEY_SLOT)
return CC_POLICY_PROTECTED_KEY;
else
return CC_INVALID_PROTECTED_KEY;
}

static int cc_cipher_sethkey(struct crypto_skcipher *sktfm, const u8 *key,
unsigned int keylen)
{
@@ -261,18 +292,13 @@ static int cc_cipher_sethkey(struct crypto_skcipher *sktfm, const u8 *key,

/* STAT_PHASE_0: Init and sanity checks */

/* This check the size of the hardware key token */
/* This check the size of the protected key token */
if (keylen != sizeof(hki)) {
dev_err(dev, "Unsupported HW key size %d.\n", keylen);
dev_err(dev, "Unsupported protected key size %d.\n", keylen);
crypto_tfm_set_flags(tfm, CRYPTO_TFM_RES_BAD_KEY_LEN);
return -EINVAL;
}

if (ctx_p->flow_mode != S_DIN_to_AES) {
dev_err(dev, "HW key not supported for non-AES flows\n");
return -EINVAL;
}

memcpy(&hki, key, keylen);

/* The real key len for crypto op is the size of the HW key
@@ -286,31 +312,70 @@ static int cc_cipher_sethkey(struct crypto_skcipher *sktfm, const u8 *key,
return -EINVAL;
}

ctx_p->hw.key1_slot = cc_slot_to_hw_key(hki.hw_key1);
if (ctx_p->hw.key1_slot == END_OF_KEYS) {
dev_err(dev, "Unsupported hw key1 number (%d)\n", hki.hw_key1);
return -EINVAL;
}
ctx_p->keylen = keylen;

if (ctx_p->cipher_mode == DRV_CIPHER_XTS ||
ctx_p->cipher_mode == DRV_CIPHER_ESSIV ||
ctx_p->cipher_mode == DRV_CIPHER_BITLOCKER) {
if (hki.hw_key1 == hki.hw_key2) {
dev_err(dev, "Illegal hw key numbers (%d,%d)\n",
hki.hw_key1, hki.hw_key2);
switch (cc_slot_to_key_type(hki.hw_key1)) {
case CC_HW_PROTECTED_KEY:
if (ctx_p->flow_mode == S_DIN_to_SM4) {
dev_err(dev, "Only AES HW protected keys are supported\n");
return -EINVAL;
}
ctx_p->hw.key2_slot = cc_slot_to_hw_key(hki.hw_key2);
if (ctx_p->hw.key2_slot == END_OF_KEYS) {
dev_err(dev, "Unsupported hw key2 number (%d)\n",
hki.hw_key2);

ctx_p->hw.key1_slot = cc_slot_to_hw_key(hki.hw_key1);
if (ctx_p->hw.key1_slot == END_OF_KEYS) {
dev_err(dev, "Unsupported hw key1 number (%d)\n",
hki.hw_key1);
return -EINVAL;
}
}

ctx_p->keylen = keylen;
ctx_p->hw_key = true;
dev_dbg(dev, "cc_is_hw_key ret 0");
if (ctx_p->cipher_mode == DRV_CIPHER_XTS ||
ctx_p->cipher_mode == DRV_CIPHER_ESSIV ||
ctx_p->cipher_mode == DRV_CIPHER_BITLOCKER) {
if (hki.hw_key1 == hki.hw_key2) {
dev_err(dev, "Illegal hw key numbers (%d,%d)\n",
hki.hw_key1, hki.hw_key2);
return -EINVAL;
}

ctx_p->hw.key2_slot = cc_slot_to_hw_key(hki.hw_key2);
if (ctx_p->hw.key2_slot == END_OF_KEYS) {
dev_err(dev, "Unsupported hw key2 number (%d)\n",
hki.hw_key2);
return -EINVAL;
}
}

ctx_p->key_type = CC_HW_PROTECTED_KEY;
dev_dbg(dev, "HW protected key %d/%d set\n.",
ctx_p->hw.key1_slot, ctx_p->hw.key2_slot);
break;

case CC_POLICY_PROTECTED_KEY:
if (ctx_p->drvdata->hw_rev < CC_HW_REV_713) {
dev_err(dev, "CPP keys not supported in this hardware revision.\n");
return -EINVAL;
}

if (ctx_p->cipher_mode != DRV_CIPHER_CBC &&
ctx_p->cipher_mode != DRV_CIPHER_CTR) {
dev_err(dev, "CPP keys only supported in CBC or CTR modes.\n");
return -EINVAL;
}

ctx_p->cpp.slot = cc_slot_to_cpp_key(hki.hw_key1);
if (ctx_p->flow_mode == S_DIN_to_AES)
ctx_p->cpp.alg = CC_CPP_AES;
else /* Must be SM4 since due to sethkey registration */
ctx_p->cpp.alg = CC_CPP_SM4;
ctx_p->key_type = CC_POLICY_PROTECTED_KEY;
dev_dbg(dev, "policy protedcted key alg: %d slot: %d.\n",
ctx_p->cpp.alg, ctx_p->cpp.slot);
break;

default:
dev_err(dev, "Unsupported protected key (%d)\n", hki.hw_key1);
return -EINVAL;
}

return 0;
}
@@ -338,7 +403,7 @@ static int cc_cipher_setkey(struct crypto_skcipher *sktfm, const u8 *key,
return -EINVAL;
}

ctx_p->hw_key = false;
ctx_p->key_type = CC_UNPROTECTED_KEY;

/*
* Verify DES weak keys
@@ -451,7 +516,7 @@ static void cc_setup_state_desc(struct crypto_tfm *tfm,
hw_desc_init(&desc[*seq_size]);
set_cipher_mode(&desc[*seq_size], cipher_mode);
set_cipher_config0(&desc[*seq_size], direction);
if (cc_is_hw_key(tfm)) {
if (cc_key_type(tfm) == CC_HW_PROTECTED_KEY) {
set_hw_crypto_key(&desc[*seq_size],
ctx_p->hw.key2_slot);
} else {
@@ -495,6 +560,7 @@ static void cc_setup_key_desc(struct crypto_tfm *tfm,
dma_addr_t key_dma_addr = ctx_p->user.key_dma_addr;
unsigned int key_len = ctx_p->keylen;
unsigned int du_size = nbytes;
unsigned int din_size;

struct cc_crypto_alg *cc_alg =
container_of(tfm->__crt_alg, struct cc_crypto_alg,
@@ -511,27 +577,38 @@ static void cc_setup_key_desc(struct crypto_tfm *tfm,
case DRV_CIPHER_ECB:
/* Load key */
hw_desc_init(&desc[*seq_size]);
set_cipher_mode(&desc[*seq_size], cipher_mode);
set_cipher_config0(&desc[*seq_size], direction);
if (flow_mode == S_DIN_to_AES) {
if (cc_is_hw_key(tfm)) {
set_hw_crypto_key(&desc[*seq_size],
ctx_p->hw.key1_slot);
if (cc_key_type(tfm) == CC_POLICY_PROTECTED_KEY) {
set_cpp_crypto_key(&desc[*seq_size], ctx_p->cpp.alg,
cipher_mode, ctx_p->cpp.slot);
} else {
set_cipher_mode(&desc[*seq_size], cipher_mode);
set_cipher_config0(&desc[*seq_size], direction);
if (flow_mode == S_DIN_to_AES) {
if (cc_key_type(tfm) == CC_HW_PROTECTED_KEY) {
set_hw_crypto_key(&desc[*seq_size],
ctx_p->hw.key1_slot);
} else {
/* CC_POLICY_UNPROTECTED_KEY
* Invalid keys are filtered out in
* sethkey()
*/
din_size = (key_len == 24) ?
AES_MAX_KEY_SIZE : key_len;

set_din_type(&desc[*seq_size], DMA_DLLI,
key_dma_addr, din_size,
NS_BIT);
}
set_key_size_aes(&desc[*seq_size], key_len);
} else {
/*des*/
set_din_type(&desc[*seq_size], DMA_DLLI,
key_dma_addr, ((key_len == 24) ?
AES_MAX_KEY_SIZE :
key_len), NS_BIT);
key_dma_addr, key_len, NS_BIT);
set_key_size_des(&desc[*seq_size], key_len);
}
set_key_size_aes(&desc[*seq_size], key_len);
} else {
/*des*/
set_din_type(&desc[*seq_size], DMA_DLLI, key_dma_addr,
key_len, NS_BIT);
set_key_size_des(&desc[*seq_size], key_len);
set_flow_mode(&desc[*seq_size], flow_mode);
set_setup_mode(&desc[*seq_size], SETUP_LOAD_KEY0);
}
set_flow_mode(&desc[*seq_size], flow_mode);
set_setup_mode(&desc[*seq_size], SETUP_LOAD_KEY0);
(*seq_size)++;
break;
case DRV_CIPHER_XTS:
@@ -541,7 +618,7 @@ static void cc_setup_key_desc(struct crypto_tfm *tfm,
hw_desc_init(&desc[*seq_size]);
set_cipher_mode(&desc[*seq_size], cipher_mode);
set_cipher_config0(&desc[*seq_size], direction);
if (cc_is_hw_key(tfm)) {
if (cc_key_type(tfm) == CC_HW_PROTECTED_KEY) {
set_hw_crypto_key(&desc[*seq_size],
ctx_p->hw.key1_slot);
} else {
@@ -789,6 +866,13 @@ static int cc_cipher_process(struct skcipher_request *req,
cc_req.user_cb = (void *)cc_cipher_complete;
cc_req.user_arg = (void *)req;

/* Setup CPP operation details */
if (ctx_p->key_type == CC_POLICY_PROTECTED_KEY) {
cc_req.cpp.is_cpp = true;
cc_req.cpp.alg = ctx_p->cpp.alg;
cc_req.cpp.slot = ctx_p->cpp.slot;
}

/* Setup request context */
req_ctx->gen_ctx.op_type = direction;

37 changes: 37 additions & 0 deletions drivers/crypto/ccree/cc_hw_queue_defs.h
Original file line number Diff line number Diff line change
@@ -28,11 +28,13 @@
GENMASK(CC_REG_HIGH(word, name), CC_REG_LOW(word, name))

#define WORD0_VALUE CC_GENMASK(0, VALUE)
#define WORD0_CPP_CIPHER_MODE CC_GENMASK(0, CPP_CIPHER_MODE)
#define WORD1_DIN_CONST_VALUE CC_GENMASK(1, DIN_CONST_VALUE)
#define WORD1_DIN_DMA_MODE CC_GENMASK(1, DIN_DMA_MODE)
#define WORD1_DIN_SIZE CC_GENMASK(1, DIN_SIZE)
#define WORD1_NOT_LAST CC_GENMASK(1, NOT_LAST)
#define WORD1_NS_BIT CC_GENMASK(1, NS_BIT)
#define WORD1_LOCK_QUEUE CC_GENMASK(1, LOCK_QUEUE)
#define WORD2_VALUE CC_GENMASK(2, VALUE)
#define WORD3_DOUT_DMA_MODE CC_GENMASK(3, DOUT_DMA_MODE)
#define WORD3_DOUT_LAST_IND CC_GENMASK(3, DOUT_LAST_IND)
@@ -53,6 +55,8 @@
#define WORD4_DATA_FLOW_MODE CC_GENMASK(4, DATA_FLOW_MODE)
#define WORD4_KEY_SIZE CC_GENMASK(4, KEY_SIZE)
#define WORD4_SETUP_OPERATION CC_GENMASK(4, SETUP_OPERATION)
#define WORD4_CPP_ALG CC_GENMASK(4, CPP_ALG)
#define WORD4_CPP_SLOT CC_GENMASK(4, CPP_SLOT)
#define WORD5_DIN_ADDR_HIGH CC_GENMASK(5, DIN_ADDR_HIGH)
#define WORD5_DOUT_ADDR_HIGH CC_GENMASK(5, DOUT_ADDR_HIGH)

@@ -176,6 +180,15 @@ enum cc_hw_crypto_key {
END_OF_KEYS = S32_MAX,
};

#define CC_NUM_HW_KEY_SLOTS 4
#define CC_FIRST_HW_KEY_SLOT 0
#define CC_LAST_HW_KEY_SLOT (CC_FIRST_HW_KEY_SLOT + CC_NUM_HW_KEY_SLOTS - 1)

#define CC_NUM_CPP_KEY_SLOTS 8
#define CC_FIRST_CPP_KEY_SLOT 16
#define CC_LAST_CPP_KEY_SLOT (CC_FIRST_CPP_KEY_SLOT + \
CC_NUM_CPP_KEY_SLOTS - 1)

enum cc_hw_aes_key_size {
AES_128_KEY = 0,
AES_192_KEY = 1,
@@ -189,6 +202,8 @@ enum cc_hash_cipher_pad {
HASH_CIPHER_DO_PADDING_RESERVE32 = S32_MAX,
};

#define CC_CPP_DESC_INDICATOR 0xFF0000UL

/*****************************/
/* Descriptor packing macros */
/*****************************/
@@ -248,6 +263,28 @@ static inline void set_din_no_dma(struct cc_hw_desc *pdesc, u32 addr, u32 size)
pdesc->word[1] |= FIELD_PREP(WORD1_DIN_SIZE, size);
}

/*
* Setup the special CPP descriptor
*
* @pdesc: pointer HW descriptor struct
* @alg: cipher used (AES / SM4)
* @mode: mode used (CTR or CBC)
* @slot: slot number
* @ksize: key size
*/
static inline void set_cpp_crypto_key(struct cc_hw_desc *pdesc,
enum cc_cpp_alg alg,
enum drv_cipher_mode mode, u8 slot)
{
u8 mode_val = (mode == DRV_CIPHER_CBC ? 0 : 1);

pdesc->word[1] |= FIELD_PREP(WORD1_DIN_SIZE, CC_CPP_DESC_INDICATOR);
pdesc->word[1] |= FIELD_PREP(WORD1_LOCK_QUEUE, 1);
pdesc->word[0] |= FIELD_PREP(WORD0_CPP_CIPHER_MODE, mode_val);
pdesc->word[4] |= FIELD_PREP(WORD4_CPP_ALG, alg);
pdesc->word[4] |= FIELD_PREP(WORD4_CPP_SLOT, slot);
}

/*
* Set the DIN field of a HW descriptors to SRAM mode.
* Note: No need to check SRAM alignment since host requests do not use SRAM and
6 changes: 6 additions & 0 deletions drivers/crypto/ccree/cc_kernel_regs.h
Original file line number Diff line number Diff line change
@@ -31,6 +31,8 @@
#define CC_DSCRPTR_QUEUE_WORD0_REG_OFFSET 0xE80UL
#define CC_DSCRPTR_QUEUE_WORD0_VALUE_BIT_SHIFT 0x0UL
#define CC_DSCRPTR_QUEUE_WORD0_VALUE_BIT_SIZE 0x20UL
#define CC_DSCRPTR_QUEUE_WORD0_CPP_CIPHER_MODE_BIT_SHIFT 0x5UL
#define CC_DSCRPTR_QUEUE_WORD0_CPP_CIPHER_MODE_BIT_SIZE 0x3UL
#define CC_DSCRPTR_QUEUE_WORD1_REG_OFFSET 0xE84UL
#define CC_DSCRPTR_QUEUE_WORD1_DIN_DMA_MODE_BIT_SHIFT 0x0UL
#define CC_DSCRPTR_QUEUE_WORD1_DIN_DMA_MODE_BIT_SIZE 0x2UL
@@ -97,6 +99,10 @@
#define CC_DSCRPTR_QUEUE_WORD4_WORD_SWAP_BIT_SIZE 0x1UL
#define CC_DSCRPTR_QUEUE_WORD4_BYTES_SWAP_BIT_SHIFT 0x1FUL
#define CC_DSCRPTR_QUEUE_WORD4_BYTES_SWAP_BIT_SIZE 0x1UL
#define CC_DSCRPTR_QUEUE_WORD4_CPP_SLOT_BIT_SHIFT 0xAUL
#define CC_DSCRPTR_QUEUE_WORD4_CPP_SLOT_BIT_SIZE 0x3UL
#define CC_DSCRPTR_QUEUE_WORD4_CPP_ALG_BIT_SHIFT 0xDUL
#define CC_DSCRPTR_QUEUE_WORD4_CPP_ALG_BIT_SIZE 0x1UL
#define CC_DSCRPTR_QUEUE_WORD5_REG_OFFSET 0xE94UL
#define CC_DSCRPTR_QUEUE_WORD5_DIN_ADDR_HIGH_BIT_SHIFT 0x0UL
#define CC_DSCRPTR_QUEUE_WORD5_DIN_ADDR_HIGH_BIT_SIZE 0x10UL

0 comments on commit 52f42c6

Please sign in to comment.