// SPDX-License-Identifier: GPL-2.0/* Copyright (C) 2012-2019 ARM Limited (or its affiliates). */ #include <linux/kernel.h>#include <linux/module.h>#include <linux/string.h>#include <crypto/algapi.h>#include <crypto/internal/skcipher.h>#include <crypto/internal/des.h>#include <crypto/xts.h>#include <crypto/sm4.h>#include <crypto/scatterwalk.h> #include "cc_driver.h"#include "cc_lli_defs.h"#include "cc_buffer_mgr.h"#include "cc_cipher.h"#include "cc_request_mgr.h" #define MAX_SKCIPHER_SEQ_LEN 6 #define template_skcipher template_u.skcipher struct cc_user_key_info { u8 *key; dma_addr_t key_dma_addr;}; struct cc_hw_key_info { enum cc_hw_crypto_key key1_slot; 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 cipher_mode; int flow_mode; unsigned int flags; enum cc_key_type key_type; struct cc_user_key_info user; union { struct cc_hw_key_info hw; struct cc_cpp_key_info cpp; }; struct crypto_shash *shash_tfm; struct crypto_skcipher *fallback_tfm; bool fallback_on;}; static void cc_cipher_complete(struct device *dev, void *cc_req, int err); 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->key_type;} static int validate_keys_sizes(struct cc_cipher_ctx *ctx_p, u32 size){ switch (ctx_p->flow_mode) { case S_DIN_to_AES: switch (size) { case CC_AES_128_BIT_KEY_SIZE: case CC_AES_192_BIT_KEY_SIZE: if (ctx_p->cipher_mode != DRV_CIPHER_XTS) return 0; break; case CC_AES_256_BIT_KEY_SIZE: return 0; case (CC_AES_192_BIT_KEY_SIZE * 2): case (CC_AES_256_BIT_KEY_SIZE * 2): if (ctx_p->cipher_mode == DRV_CIPHER_XTS || ctx_p->cipher_mode == DRV_CIPHER_ESSIV) return 0; break; default: break; } break; case S_DIN_to_DES: if (size == DES3_EDE_KEY_SIZE || size == DES_KEY_SIZE) return 0; break; case S_DIN_to_SM4: if (size == SM4_KEY_SIZE) return 0; break; default: break; } return -EINVAL;} static int validate_data_size(struct cc_cipher_ctx *ctx_p, unsigned int size){ switch (ctx_p->flow_mode) { case S_DIN_to_AES: switch (ctx_p->cipher_mode) { case DRV_CIPHER_XTS: case DRV_CIPHER_CBC_CTS: if (size >= AES_BLOCK_SIZE) return 0; break; case DRV_CIPHER_OFB: case DRV_CIPHER_CTR: return 0; case DRV_CIPHER_ECB: case DRV_CIPHER_CBC: case DRV_CIPHER_ESSIV: if (IS_ALIGNED(size, AES_BLOCK_SIZE)) return 0; break; default: break; } break; case S_DIN_to_DES: if (IS_ALIGNED(size, DES_BLOCK_SIZE)) return 0; break; case S_DIN_to_SM4: switch (ctx_p->cipher_mode) { case DRV_CIPHER_CTR: return 0; case DRV_CIPHER_ECB: case DRV_CIPHER_CBC: if (IS_ALIGNED(size, SM4_BLOCK_SIZE)) return 0; break; default: break; } break; default: break; } return -EINVAL;} static int cc_cipher_init(struct crypto_tfm *tfm){ struct cc_cipher_ctx *ctx_p = crypto_tfm_ctx(tfm); struct cc_crypto_alg *cc_alg = container_of(tfm->__crt_alg, struct cc_crypto_alg, skcipher_alg.base); struct device *dev = drvdata_to_dev(cc_alg->drvdata); unsigned int max_key_buf_size = cc_alg->skcipher_alg.max_keysize; unsigned int fallback_req_size = 0; dev_dbg(dev, "Initializing context @%p for %s\n", ctx_p, crypto_tfm_alg_name(tfm)); ctx_p->cipher_mode = cc_alg->cipher_mode; ctx_p->flow_mode = cc_alg->flow_mode; ctx_p->drvdata = cc_alg->drvdata; if (ctx_p->cipher_mode == DRV_CIPHER_ESSIV) { const char *name = crypto_tfm_alg_name(tfm); /* Alloc hash tfm for essiv */ ctx_p->shash_tfm = crypto_alloc_shash("sha256", 0, 0); if (IS_ERR(ctx_p->shash_tfm)) { dev_err(dev, "Error allocating hash tfm for ESSIV.\n"); return PTR_ERR(ctx_p->shash_tfm); } max_key_buf_size <<= 1; /* Alloc fallback tfm or essiv when key size != 256 bit */ ctx_p->fallback_tfm = crypto_alloc_skcipher(name, 0, CRYPTO_ALG_NEED_FALLBACK | CRYPTO_ALG_ASYNC); if (IS_ERR(ctx_p->fallback_tfm)) { /* Note we're still allowing registration with no fallback since it's * better to have most modes supported than none at all. */ dev_warn(dev, "Error allocating fallback algo %s. Some modes may be available.\n", name); ctx_p->fallback_tfm = NULL; } else { fallback_req_size = crypto_skcipher_reqsize(ctx_p->fallback_tfm); } } crypto_skcipher_set_reqsize(__crypto_skcipher_cast(tfm), sizeof(struct cipher_req_ctx) + fallback_req_size); /* Allocate key buffer, cache line aligned */ ctx_p->user.key = kzalloc(max_key_buf_size, GFP_KERNEL); if (!ctx_p->user.key) goto free_fallback; dev_dbg(dev, "Allocated key buffer in context. key=@%p\n", ctx_p->user.key); /* Map key buffer */ ctx_p->user.key_dma_addr = dma_map_single(dev, ctx_p->user.key, max_key_buf_size, DMA_TO_DEVICE); if (dma_mapping_error(dev, ctx_p->user.key_dma_addr)) { dev_err(dev, "Mapping Key %u B at va=%p for DMA failed\n", max_key_buf_size, ctx_p->user.key); goto free_key; } dev_dbg(dev, "Mapped key %u B at va=%p to dma=%pad\n", max_key_buf_size, ctx_p->user.key, &ctx_p->user.key_dma_addr); return 0; free_key: kfree(ctx_p->user.key);free_fallback: crypto_free_skcipher(ctx_p->fallback_tfm); crypto_free_shash(ctx_p->shash_tfm); return -ENOMEM;} static void cc_cipher_exit(struct crypto_tfm *tfm){ struct crypto_alg *alg = tfm->__crt_alg; struct cc_crypto_alg *cc_alg = container_of(alg, struct cc_crypto_alg, skcipher_alg.base); unsigned int max_key_buf_size = cc_alg->skcipher_alg.max_keysize; struct cc_cipher_ctx *ctx_p = crypto_tfm_ctx(tfm); struct device *dev = drvdata_to_dev(ctx_p->drvdata); dev_dbg(dev, "Clearing context @%p for %s\n", crypto_tfm_ctx(tfm), crypto_tfm_alg_name(tfm)); if (ctx_p->cipher_mode == DRV_CIPHER_ESSIV) { /* Free hash tfm for essiv */ crypto_free_shash(ctx_p->shash_tfm); ctx_p->shash_tfm = NULL; crypto_free_skcipher(ctx_p->fallback_tfm); ctx_p->fallback_tfm = NULL; } /* Unmap key buffer */ dma_unmap_single(dev, ctx_p->user.key_dma_addr, max_key_buf_size, DMA_TO_DEVICE); dev_dbg(dev, "Unmapped key buffer key_dma_addr=%pad\n", &ctx_p->user.key_dma_addr); /* Free key buffer in context */ dev_dbg(dev, "Free key buffer in context. key=@%p\n", ctx_p->user.key); kfree_sensitive(ctx_p->user.key);} static enum cc_hw_crypto_key cc_slot_to_hw_key(u8 slot_num){ switch (slot_num) { case 0: return KFDE0_KEY; case 1: return KFDE1_KEY; case 2: return KFDE2_KEY; case 3: return KFDE3_KEY; } 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){ struct crypto_tfm *tfm = crypto_skcipher_tfm(sktfm); struct cc_cipher_ctx *ctx_p = crypto_tfm_ctx(tfm); struct device *dev = drvdata_to_dev(ctx_p->drvdata); struct cc_hkey_info hki; dev_dbg(dev, "Setting HW key in context @%p for %s. keylen=%u\n", ctx_p, crypto_tfm_alg_name(tfm), keylen); dump_byte_array("key", key, keylen); /* STAT_PHASE_0: Init and sanity checks */ /* This check the size of the protected key token */ if (keylen != sizeof(hki)) { dev_err(dev, "Unsupported protected key size %d.\n", keylen); return -EINVAL; } memcpy(&hki, key, keylen); /* The real key len for crypto op is the size of the HW key * referenced by the HW key slot, not the hardware key token */ keylen = hki.keylen; if (validate_keys_sizes(ctx_p, keylen)) { dev_dbg(dev, "Unsupported key size %d.\n", keylen); return -EINVAL; } ctx_p->keylen = keylen; ctx_p->fallback_on = false; 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.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; } if (ctx_p->cipher_mode == DRV_CIPHER_XTS || ctx_p->cipher_mode == DRV_CIPHER_ESSIV) { 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 protected 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;} static int cc_cipher_setkey(struct crypto_skcipher *sktfm, const u8 *key, unsigned int keylen){ struct crypto_tfm *tfm = crypto_skcipher_tfm(sktfm); struct cc_cipher_ctx *ctx_p = crypto_tfm_ctx(tfm); struct device *dev = drvdata_to_dev(ctx_p->drvdata); struct cc_crypto_alg *cc_alg = container_of(tfm->__crt_alg, struct cc_crypto_alg, skcipher_alg.base); unsigned int max_key_buf_size = cc_alg->skcipher_alg.max_keysize; dev_dbg(dev, "Setting key in context @%p for %s. keylen=%u\n", ctx_p, crypto_tfm_alg_name(tfm), keylen); dump_byte_array("key", key, keylen); /* STAT_PHASE_0: Init and sanity checks */ if (validate_keys_sizes(ctx_p, keylen)) { dev_dbg(dev, "Invalid key size %d.\n", keylen); return -EINVAL; } if (ctx_p->cipher_mode == DRV_CIPHER_ESSIV) { /* We only support 256 bit ESSIV-CBC-AES keys */ if (keylen != AES_KEYSIZE_256) { unsigned int flags = crypto_tfm_get_flags(tfm) & CRYPTO_TFM_REQ_MASK; if (likely(ctx_p->fallback_tfm)) { ctx_p->fallback_on = true; crypto_skcipher_clear_flags(ctx_p->fallback_tfm, CRYPTO_TFM_REQ_MASK); crypto_skcipher_clear_flags(ctx_p->fallback_tfm, flags); return crypto_skcipher_setkey(ctx_p->fallback_tfm, key, keylen); } dev_dbg(dev, "Unsupported key size %d and no fallback.\n", keylen); return -EINVAL; } /* Internal ESSIV key buffer is double sized */ max_key_buf_size <<= 1; } ctx_p->fallback_on = false; ctx_p->key_type = CC_UNPROTECTED_KEY; /* * Verify DES weak keys * Note that we're dropping the expanded key since the * HW does the expansion on its own. */ if (ctx_p->flow_mode == S_DIN_to_DES) { if ((keylen == DES3_EDE_KEY_SIZE && verify_skcipher_des3_key(sktfm, key)) || verify_skcipher_des_key(sktfm, key)) { dev_dbg(dev, "weak DES key"); return -EINVAL; } } if (ctx_p->cipher_mode == DRV_CIPHER_XTS && xts_verify_key(sktfm, key, keylen)) { dev_dbg(dev, "weak XTS key"); return -EINVAL; } /* STAT_PHASE_1: Copy key to ctx */ dma_sync_single_for_cpu(dev, ctx_p->user.key_dma_addr, max_key_buf_size, DMA_TO_DEVICE); memcpy(ctx_p->user.key, key, keylen); if (ctx_p->cipher_mode == DRV_CIPHER_ESSIV) { /* sha256 for key2 - use sw implementation */ int err; err = crypto_shash_tfm_digest(ctx_p->shash_tfm, ctx_p->user.key, keylen, ctx_p->user.key + keylen); if (err) { dev_err(dev, "Failed to hash ESSIV key.\n"); return err; } keylen <<= 1; } dma_sync_single_for_device(dev, ctx_p->user.key_dma_addr, max_key_buf_size, DMA_TO_DEVICE); ctx_p->keylen = keylen; dev_dbg(dev, "return safely"); return 0;} static int cc_out_setup_mode(struct cc_cipher_ctx *ctx_p){ switch (ctx_p->flow_mode) { case S_DIN_to_AES: return S_AES_to_DOUT; case S_DIN_to_DES: return S_DES_to_DOUT; case S_DIN_to_SM4: return S_SM4_to_DOUT; default:Lines 1–500 of 1471. Load more
// SPDX-License-Identifier: GPL-2.0 /* Copyright (C) 2012-2019 ARM Limited (or its affiliates). */ #include <linux/kernel.h> #include <linux/module.h> #include <linux/string.h> #include <crypto/algapi.h> #include <crypto/internal/skcipher.h> #include <crypto/internal/des.h> #include <crypto/xts.h> #include <crypto/sm4.h> #include <crypto/scatterwalk.h> #include "cc_driver.h" #include "cc_lli_defs.h" #include "cc_buffer_mgr.h" #include "cc_cipher.h" #include "cc_request_mgr.h" #define MAX_SKCIPHER_SEQ_LEN 6 #define template_skcipher template_u.skcipher struct cc_user_key_info { u8 *key; dma_addr_t key_dma_addr; }; struct cc_hw_key_info { enum cc_hw_crypto_key key1_slot; 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 cipher_mode; int flow_mode; unsigned int flags; enum cc_key_type key_type; struct cc_user_key_info user; union { struct cc_hw_key_info hw; struct cc_cpp_key_info cpp; }; struct crypto_shash *shash_tfm; struct crypto_skcipher *fallback_tfm; bool fallback_on; }; static void cc_cipher_complete(struct device *dev, void *cc_req, int err); 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->key_type; } static int validate_keys_sizes(struct cc_cipher_ctx *ctx_p, u32 size) { switch (ctx_p->flow_mode) { case S_DIN_to_AES: switch (size) { case CC_AES_128_BIT_KEY_SIZE: case CC_AES_192_BIT_KEY_SIZE: if (ctx_p->cipher_mode != DRV_CIPHER_XTS) return 0; break; case CC_AES_256_BIT_KEY_SIZE: return 0; case (CC_AES_192_BIT_KEY_SIZE * 2): case (CC_AES_256_BIT_KEY_SIZE * 2): if (ctx_p->cipher_mode == DRV_CIPHER_XTS || ctx_p->cipher_mode == DRV_CIPHER_ESSIV) return 0; break; default: break; } break; case S_DIN_to_DES: if (size == DES3_EDE_KEY_SIZE || size == DES_KEY_SIZE) return 0; break; case S_DIN_to_SM4: if (size == SM4_KEY_SIZE) return 0; break; default: break; } return -EINVAL; } static int validate_data_size(struct cc_cipher_ctx *ctx_p, unsigned int size) { switch (ctx_p->flow_mode) { case S_DIN_to_AES: switch (ctx_p->cipher_mode) { case DRV_CIPHER_XTS: case DRV_CIPHER_CBC_CTS: if (size >= AES_BLOCK_SIZE) return 0; break; case DRV_CIPHER_OFB: case DRV_CIPHER_CTR: return 0; case DRV_CIPHER_ECB: case DRV_CIPHER_CBC: case DRV_CIPHER_ESSIV: if (IS_ALIGNED(size, AES_BLOCK_SIZE)) return 0; break; default: break; } break; case S_DIN_to_DES: if (IS_ALIGNED(size, DES_BLOCK_SIZE)) return 0; break; case S_DIN_to_SM4: switch (ctx_p->cipher_mode) { case DRV_CIPHER_CTR: return 0; case DRV_CIPHER_ECB: case DRV_CIPHER_CBC: if (IS_ALIGNED(size, SM4_BLOCK_SIZE)) return 0; break; default: break; } break; default: break; } return -EINVAL; } static int cc_cipher_init(struct crypto_tfm *tfm) { struct cc_cipher_ctx *ctx_p = crypto_tfm_ctx(tfm); struct cc_crypto_alg *cc_alg = container_of(tfm->__crt_alg, struct cc_crypto_alg, skcipher_alg.base); struct device *dev = drvdata_to_dev(cc_alg->drvdata); unsigned int max_key_buf_size = cc_alg->skcipher_alg.max_keysize; unsigned int fallback_req_size = 0; dev_dbg(dev, "Initializing context @%p for %s\n", ctx_p, crypto_tfm_alg_name(tfm)); ctx_p->cipher_mode = cc_alg->cipher_mode; ctx_p->flow_mode = cc_alg->flow_mode; ctx_p->drvdata = cc_alg->drvdata; if (ctx_p->cipher_mode == DRV_CIPHER_ESSIV) { const char *name = crypto_tfm_alg_name(tfm); /* Alloc hash tfm for essiv */ ctx_p->shash_tfm = crypto_alloc_shash("sha256", 0, 0); if (IS_ERR(ctx_p->shash_tfm)) { dev_err(dev, "Error allocating hash tfm for ESSIV.\n"); return PTR_ERR(ctx_p->shash_tfm); } max_key_buf_size <<= 1; /* Alloc fallback tfm or essiv when key size != 256 bit */ ctx_p->fallback_tfm = crypto_alloc_skcipher(name, 0, CRYPTO_ALG_NEED_FALLBACK | CRYPTO_ALG_ASYNC); if (IS_ERR(ctx_p->fallback_tfm)) { /* Note we're still allowing registration with no fallback since it's * better to have most modes supported than none at all. */ dev_warn(dev, "Error allocating fallback algo %s. Some modes may be available.\n", name); ctx_p->fallback_tfm = NULL; } else { fallback_req_size = crypto_skcipher_reqsize(ctx_p->fallback_tfm); } } crypto_skcipher_set_reqsize(__crypto_skcipher_cast(tfm), sizeof(struct cipher_req_ctx) + fallback_req_size); /* Allocate key buffer, cache line aligned */ ctx_p->user.key = kzalloc(max_key_buf_size, GFP_KERNEL); if (!ctx_p->user.key) goto free_fallback; dev_dbg(dev, "Allocated key buffer in context. key=@%p\n", ctx_p->user.key); /* Map key buffer */ ctx_p->user.key_dma_addr = dma_map_single(dev, ctx_p->user.key, max_key_buf_size, DMA_TO_DEVICE); if (dma_mapping_error(dev, ctx_p->user.key_dma_addr)) { dev_err(dev, "Mapping Key %u B at va=%p for DMA failed\n", max_key_buf_size, ctx_p->user.key); goto free_key; } dev_dbg(dev, "Mapped key %u B at va=%p to dma=%pad\n", max_key_buf_size, ctx_p->user.key, &ctx_p->user.key_dma_addr); return 0; free_key: kfree(ctx_p->user.key); free_fallback: crypto_free_skcipher(ctx_p->fallback_tfm); crypto_free_shash(ctx_p->shash_tfm); return -ENOMEM; } static void cc_cipher_exit(struct crypto_tfm *tfm) { struct crypto_alg *alg = tfm->__crt_alg; struct cc_crypto_alg *cc_alg = container_of(alg, struct cc_crypto_alg, skcipher_alg.base); unsigned int max_key_buf_size = cc_alg->skcipher_alg.max_keysize; struct cc_cipher_ctx *ctx_p = crypto_tfm_ctx(tfm); struct device *dev = drvdata_to_dev(ctx_p->drvdata); dev_dbg(dev, "Clearing context @%p for %s\n", crypto_tfm_ctx(tfm), crypto_tfm_alg_name(tfm)); if (ctx_p->cipher_mode == DRV_CIPHER_ESSIV) { /* Free hash tfm for essiv */ crypto_free_shash(ctx_p->shash_tfm); ctx_p->shash_tfm = NULL; crypto_free_skcipher(ctx_p->fallback_tfm); ctx_p->fallback_tfm = NULL; } /* Unmap key buffer */ dma_unmap_single(dev, ctx_p->user.key_dma_addr, max_key_buf_size, DMA_TO_DEVICE); dev_dbg(dev, "Unmapped key buffer key_dma_addr=%pad\n", &ctx_p->user.key_dma_addr); /* Free key buffer in context */ dev_dbg(dev, "Free key buffer in context. key=@%p\n", ctx_p->user.key); kfree_sensitive(ctx_p->user.key); } static enum cc_hw_crypto_key cc_slot_to_hw_key(u8 slot_num) { switch (slot_num) { case 0: return KFDE0_KEY; case 1: return KFDE1_KEY; case 2: return KFDE2_KEY; case 3: return KFDE3_KEY; } 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) { struct crypto_tfm *tfm = crypto_skcipher_tfm(sktfm); struct cc_cipher_ctx *ctx_p = crypto_tfm_ctx(tfm); struct device *dev = drvdata_to_dev(ctx_p->drvdata); struct cc_hkey_info hki; dev_dbg(dev, "Setting HW key in context @%p for %s. keylen=%u\n", ctx_p, crypto_tfm_alg_name(tfm), keylen); dump_byte_array("key", key, keylen); /* STAT_PHASE_0: Init and sanity checks */ /* This check the size of the protected key token */ if (keylen != sizeof(hki)) { dev_err(dev, "Unsupported protected key size %d.\n", keylen); return -EINVAL; } memcpy(&hki, key, keylen); /* The real key len for crypto op is the size of the HW key * referenced by the HW key slot, not the hardware key token */ keylen = hki.keylen; if (validate_keys_sizes(ctx_p, keylen)) { dev_dbg(dev, "Unsupported key size %d.\n", keylen); return -EINVAL; } ctx_p->keylen = keylen; ctx_p->fallback_on = false; 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.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; } if (ctx_p->cipher_mode == DRV_CIPHER_XTS || ctx_p->cipher_mode == DRV_CIPHER_ESSIV) { 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 protected 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; } static int cc_cipher_setkey(struct crypto_skcipher *sktfm, const u8 *key, unsigned int keylen) { struct crypto_tfm *tfm = crypto_skcipher_tfm(sktfm); struct cc_cipher_ctx *ctx_p = crypto_tfm_ctx(tfm); struct device *dev = drvdata_to_dev(ctx_p->drvdata); struct cc_crypto_alg *cc_alg = container_of(tfm->__crt_alg, struct cc_crypto_alg, skcipher_alg.base); unsigned int max_key_buf_size = cc_alg->skcipher_alg.max_keysize; dev_dbg(dev, "Setting key in context @%p for %s. keylen=%u\n", ctx_p, crypto_tfm_alg_name(tfm), keylen); dump_byte_array("key", key, keylen); /* STAT_PHASE_0: Init and sanity checks */ if (validate_keys_sizes(ctx_p, keylen)) { dev_dbg(dev, "Invalid key size %d.\n", keylen); return -EINVAL; } if (ctx_p->cipher_mode == DRV_CIPHER_ESSIV) { /* We only support 256 bit ESSIV-CBC-AES keys */ if (keylen != AES_KEYSIZE_256) { unsigned int flags = crypto_tfm_get_flags(tfm) & CRYPTO_TFM_REQ_MASK; if (likely(ctx_p->fallback_tfm)) { ctx_p->fallback_on = true; crypto_skcipher_clear_flags(ctx_p->fallback_tfm, CRYPTO_TFM_REQ_MASK); crypto_skcipher_clear_flags(ctx_p->fallback_tfm, flags); return crypto_skcipher_setkey(ctx_p->fallback_tfm, key, keylen); } dev_dbg(dev, "Unsupported key size %d and no fallback.\n", keylen); return -EINVAL; } /* Internal ESSIV key buffer is double sized */ max_key_buf_size <<= 1; } ctx_p->fallback_on = false; ctx_p->key_type = CC_UNPROTECTED_KEY; /* * Verify DES weak keys * Note that we're dropping the expanded key since the * HW does the expansion on its own. */ if (ctx_p->flow_mode == S_DIN_to_DES) { if ((keylen == DES3_EDE_KEY_SIZE && verify_skcipher_des3_key(sktfm, key)) || verify_skcipher_des_key(sktfm, key)) { dev_dbg(dev, "weak DES key"); return -EINVAL; } } if (ctx_p->cipher_mode == DRV_CIPHER_XTS && xts_verify_key(sktfm, key, keylen)) { dev_dbg(dev, "weak XTS key"); return -EINVAL; } /* STAT_PHASE_1: Copy key to ctx */ dma_sync_single_for_cpu(dev, ctx_p->user.key_dma_addr, max_key_buf_size, DMA_TO_DEVICE); memcpy(ctx_p->user.key, key, keylen); if (ctx_p->cipher_mode == DRV_CIPHER_ESSIV) { /* sha256 for key2 - use sw implementation */ int err; err = crypto_shash_tfm_digest(ctx_p->shash_tfm, ctx_p->user.key, keylen, ctx_p->user.key + keylen); if (err) { dev_err(dev, "Failed to hash ESSIV key.\n"); return err; } keylen <<= 1; } dma_sync_single_for_device(dev, ctx_p->user.key_dma_addr, max_key_buf_size, DMA_TO_DEVICE); ctx_p->keylen = keylen; dev_dbg(dev, "return safely"); return 0; } static int cc_out_setup_mode(struct cc_cipher_ctx *ctx_p) { switch (ctx_p->flow_mode) { case S_DIN_to_AES: return S_AES_to_DOUT; case S_DIN_to_DES: return S_DES_to_DOUT; case S_DIN_to_SM4: return S_SM4_to_DOUT; default: