提交 16609980 编写于 作者: G Gilad Ben-Yossef 提交者: Greg Kroah-Hartman

staging: ccree: add FIPS support

Add FIPS mode support to CryptoCell driver
Signed-off-by: NGilad Ben-Yossef <gilad@benyossef.com>
Signed-off-by: NGreg Kroah-Hartman <gregkh@linuxfoundation.org>
上级 fe0a1951
......@@ -24,6 +24,15 @@ config CRYPTO_DEV_CCREE
cryptographic operations on the system REE.
If unsure say Y.
config CCREE_FIPS_SUPPORT
bool "Turn on CryptoCell 7XX REE FIPS mode support"
depends on CRYPTO_DEV_CCREE
default n
help
Say 'Y' to enable support for FIPS compliant mode by the
CCREE driver.
If unsure say N.
config CCREE_DISABLE_COHERENT_DMA_OPS
bool "Disable Coherent DMA operations for the CCREE driver"
depends on CRYPTO_DEV_CCREE
......
obj-$(CONFIG_CRYPTO_DEV_CCREE) := ccree.o
ccree-y := ssi_driver.o ssi_sysfs.o ssi_buffer_mgr.o ssi_request_mgr.o ssi_cipher.o ssi_hash.o ssi_aead.o ssi_ivgen.o ssi_sram_mgr.o ssi_pm.o ssi_pm_ext.o
ccree-$(CCREE_FIPS_SUPPORT) += ssi_fips.o ssi_fips_ll.o ssi_fips_ext.o ssi_fips_local.o
......@@ -36,6 +36,7 @@
#include "ssi_hash.h"
#include "ssi_sysfs.h"
#include "ssi_sram_mgr.h"
#include "ssi_fips_local.h"
#define template_aead template_u.aead
......@@ -153,6 +154,8 @@ static int ssi_aead_init(struct crypto_aead *tfm)
container_of(alg, struct ssi_crypto_alg, aead_alg);
SSI_LOG_DEBUG("Initializing context @%p for %s\n", ctx, crypto_tfm_alg_name(&(tfm->base)));
CHECK_AND_RETURN_UPON_FIPS_ERROR();
/* Initialize modes in instance */
ctx->cipher_mode = ssi_alg->cipher_mode;
ctx->flow_mode = ssi_alg->flow_mode;
......@@ -572,6 +575,7 @@ ssi_aead_setkey(struct crypto_aead *tfm, const u8 *key, unsigned int keylen)
SSI_LOG_DEBUG("Setting key in context @%p for %s. key=%p keylen=%u\n",
ctx, crypto_tfm_alg_name(crypto_aead_tfm(tfm)), key, keylen);
CHECK_AND_RETURN_UPON_FIPS_ERROR();
/* STAT_PHASE_0: Init and sanity checks */
START_CYCLE_COUNT();
......@@ -699,6 +703,7 @@ static int ssi_aead_setauthsize(
{
struct ssi_aead_ctx *ctx = crypto_aead_ctx(authenc);
CHECK_AND_RETURN_UPON_FIPS_ERROR();
/* Unsupported auth. sizes */
if ((authsize == 0) ||
(authsize >crypto_aead_maxauthsize(authenc))) {
......@@ -2006,6 +2011,7 @@ static int ssi_aead_process(struct aead_request *req, enum drv_crypto_direction
SSI_LOG_DEBUG("%s context=%p req=%p iv=%p src=%p src_ofs=%d dst=%p dst_ofs=%d cryptolen=%d\n",
((direct==DRV_CRYPTO_DIRECTION_ENCRYPT)?"Encrypt":"Decrypt"), ctx, req, req->iv,
sg_virt(req->src), req->src->offset, sg_virt(req->dst), req->dst->offset, req->cryptlen);
CHECK_AND_RETURN_UPON_FIPS_ERROR();
/* STAT_PHASE_0: Init and sanity checks */
START_CYCLE_COUNT();
......
......@@ -31,6 +31,7 @@
#include "ssi_cipher.h"
#include "ssi_request_mgr.h"
#include "ssi_sysfs.h"
#include "ssi_fips_local.h"
#define MAX_ABLKCIPHER_SEQ_LEN 6
......@@ -191,6 +192,7 @@ static int ssi_blkcipher_init(struct crypto_tfm *tfm)
SSI_LOG_DEBUG("Initializing context @%p for %s\n", ctx_p,
crypto_tfm_alg_name(tfm));
CHECK_AND_RETURN_UPON_FIPS_ERROR();
ctx_p->cipher_mode = ssi_alg->cipher_mode;
ctx_p->flow_mode = ssi_alg->flow_mode;
ctx_p->drvdata = ssi_alg->drvdata;
......@@ -269,6 +271,37 @@ static const u8 zero_buff[] = {0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0};
/* The function verifies that tdes keys are not weak.*/
static int ssi_fips_verify_3des_keys(const u8 *key, unsigned int keylen)
{
#ifdef CCREE_FIPS_SUPPORT
tdes_keys_t *tdes_key = (tdes_keys_t*)key;
/* verify key1 != key2 and key3 != key2*/
if (unlikely( (memcmp((u8*)tdes_key->key1, (u8*)tdes_key->key2, sizeof(tdes_key->key1)) == 0) ||
(memcmp((u8*)tdes_key->key3, (u8*)tdes_key->key2, sizeof(tdes_key->key3)) == 0) )) {
return -ENOEXEC;
}
#endif /* CCREE_FIPS_SUPPORT */
return 0;
}
/* The function verifies that xts keys are not weak.*/
static int ssi_fips_verify_xts_keys(const u8 *key, unsigned int keylen)
{
#ifdef CCREE_FIPS_SUPPORT
/* Weak key is define as key that its first half (128/256 lsb) equals its second half (128/256 msb) */
int singleKeySize = keylen >> 1;
if (unlikely(memcmp(key, &key[singleKeySize], singleKeySize) == 0)) {
return -ENOEXEC;
}
#endif /* CCREE_FIPS_SUPPORT */
return 0;
}
static enum HwCryptoKey hw_key_to_cc_hw_key(int slot_num)
{
switch (slot_num) {
......@@ -298,6 +331,10 @@ static int ssi_blkcipher_setkey(struct crypto_tfm *tfm,
ctx_p, crypto_tfm_alg_name(tfm), keylen);
dump_byte_array("key", (uint8_t *)key, keylen);
CHECK_AND_RETURN_UPON_FIPS_ERROR();
SSI_LOG_DEBUG("ssi_blkcipher_setkey: after FIPS check");
/* STAT_PHASE_0: Init and sanity checks */
START_CYCLE_COUNT();
......@@ -359,6 +396,18 @@ static int ssi_blkcipher_setkey(struct crypto_tfm *tfm,
return -EINVAL;
}
}
if ((ctx_p->cipher_mode == DRV_CIPHER_XTS) &&
ssi_fips_verify_xts_keys(key, keylen) != 0) {
SSI_LOG_DEBUG("ssi_blkcipher_setkey: weak XTS key");
return -EINVAL;
}
if ((ctx_p->flow_mode == S_DIN_to_DES) &&
(keylen == DES3_EDE_KEY_SIZE) &&
ssi_fips_verify_3des_keys(key, keylen) != 0) {
SSI_LOG_DEBUG("ssi_blkcipher_setkey: weak 3DES key");
return -EINVAL;
}
END_CYCLE_COUNT(STAT_OP_TYPE_SETKEY, STAT_PHASE_0);
......@@ -744,6 +793,7 @@ static int ssi_blkcipher_process(
((direction==DRV_CRYPTO_DIRECTION_ENCRYPT)?"Encrypt":"Decrypt"),
areq, info, nbytes);
CHECK_AND_RETURN_UPON_FIPS_ERROR();
/* STAT_PHASE_0: Init and sanity checks */
START_CYCLE_COUNT();
......@@ -864,6 +914,8 @@ static void ssi_ablkcipher_complete(struct device *dev, void *ssi_req, void __io
struct ssi_ablkcipher_ctx *ctx_p = crypto_ablkcipher_ctx(tfm);
unsigned int ivsize = crypto_ablkcipher_ivsize(tfm);
CHECK_AND_RETURN_VOID_UPON_FIPS_ERROR();
ssi_blkcipher_complete(dev, ctx_p, req_ctx, areq->dst, areq->src, areq->info, ivsize, areq, cc_base);
}
......
......@@ -69,6 +69,7 @@
#include "ssi_ivgen.h"
#include "ssi_sram_mgr.h"
#include "ssi_pm.h"
#include "ssi_fips_local.h"
#ifdef DX_DUMP_BYTES
......@@ -142,7 +143,15 @@ static irqreturn_t cc_isr(int irq, void *dev_id)
irr &= ~SSI_COMP_IRQ_MASK;
complete_request(drvdata);
}
#ifdef CC_SUPPORT_FIPS
/* TEE FIPS interrupt */
if (likely((irr & SSI_GPR0_IRQ_MASK) != 0)) {
/* Mask interrupt - will be unmasked in Deferred service handler */
CC_HAL_WRITE_REGISTER(CC_REG_OFFSET(HOST_RGF, HOST_IMR), imr | SSI_GPR0_IRQ_MASK);
irr &= ~SSI_GPR0_IRQ_MASK;
fips_handler(drvdata);
}
#endif
/* AXI error interrupt */
if (unlikely((irr & SSI_AXI_ERR_IRQ_MASK) != 0)) {
uint32_t axi_err;
......@@ -351,6 +360,12 @@ static int init_cc_resources(struct platform_device *plat_dev)
goto init_cc_res_err;
}
rc = ssi_fips_init(new_drvdata);
if (unlikely(rc != 0)) {
SSI_LOG_ERR("SSI_FIPS_INIT failed 0x%x\n", rc);
goto init_cc_res_err;
}
rc = ssi_ivgen_init(new_drvdata);
if (unlikely(rc != 0)) {
SSI_LOG_ERR("ssi_ivgen_init failed\n");
......@@ -391,6 +406,7 @@ static int init_cc_resources(struct platform_device *plat_dev)
ssi_buffer_mgr_fini(new_drvdata);
request_mgr_fini(new_drvdata);
ssi_sram_mgr_fini(new_drvdata);
ssi_fips_fini(new_drvdata);
#ifdef ENABLE_CC_SYSFS
ssi_sysfs_fini();
#endif
......@@ -434,6 +450,7 @@ static void cleanup_cc_resources(struct platform_device *plat_dev)
ssi_buffer_mgr_fini(drvdata);
request_mgr_fini(drvdata);
ssi_sram_mgr_fini(drvdata);
ssi_fips_fini(drvdata);
#ifdef ENABLE_CC_SYSFS
ssi_sysfs_fini();
#endif
......
......@@ -54,6 +54,7 @@
#include "cc_crypto_ctx.h"
#include "ssi_sysfs.h"
#include "hash_defs.h"
#include "ssi_fips_local.h"
#define DRV_MODULE_VERSION "3.0"
......@@ -152,6 +153,7 @@ struct ssi_drvdata {
void *aead_handle;
void *blkcipher_handle;
void *request_mgr_handle;
void *fips_handle;
void *ivgen_handle;
void *sram_mgr_handle;
......
/*
* Copyright (C) 2012-2017 ARM Limited or its affiliates.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, see <http://www.gnu.org/licenses/>.
*/
/**************************************************************
This file defines the driver FIPS APIs *
***************************************************************/
#include <linux/module.h>
#include "ssi_fips.h"
extern int ssi_fips_ext_get_state(ssi_fips_state_t *p_state);
extern int ssi_fips_ext_get_error(ssi_fips_error_t *p_err);
/*
This function returns the REE FIPS state.
It should be called by kernel module.
*/
int ssi_fips_get_state(ssi_fips_state_t *p_state)
{
int rc = 0;
if (p_state == NULL) {
return -EINVAL;
}
rc = ssi_fips_ext_get_state(p_state);
return rc;
}
EXPORT_SYMBOL(ssi_fips_get_state);
/*
This function returns the REE FIPS error.
It should be called by kernel module.
*/
int ssi_fips_get_error(ssi_fips_error_t *p_err)
{
int rc = 0;
if (p_err == NULL) {
return -EINVAL;
}
rc = ssi_fips_ext_get_error(p_err);
return rc;
}
EXPORT_SYMBOL(ssi_fips_get_error);
/*
* Copyright (C) 2012-2017 ARM Limited or its affiliates.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, see <http://www.gnu.org/licenses/>.
*/
#ifndef __SSI_FIPS_H__
#define __SSI_FIPS_H__
#ifndef INT32_MAX /* Missing in Linux kernel */
#define INT32_MAX 0x7FFFFFFFL
#endif
/*!
@file
@brief This file contains FIPS related defintions and APIs.
*/
typedef enum ssi_fips_state {
CC_FIPS_STATE_NOT_SUPPORTED = 0,
CC_FIPS_STATE_SUPPORTED,
CC_FIPS_STATE_ERROR,
CC_FIPS_STATE_RESERVE32B = INT32_MAX
} ssi_fips_state_t;
typedef enum ssi_fips_error {
CC_REE_FIPS_ERROR_OK = 0,
CC_REE_FIPS_ERROR_GENERAL,
CC_REE_FIPS_ERROR_FROM_TEE,
CC_REE_FIPS_ERROR_AES_ECB_PUT,
CC_REE_FIPS_ERROR_AES_CBC_PUT,
CC_REE_FIPS_ERROR_AES_OFB_PUT,
CC_REE_FIPS_ERROR_AES_CTR_PUT,
CC_REE_FIPS_ERROR_AES_CBC_CTS_PUT,
CC_REE_FIPS_ERROR_AES_XTS_PUT,
CC_REE_FIPS_ERROR_AES_CMAC_PUT,
CC_REE_FIPS_ERROR_AESCCM_PUT,
CC_REE_FIPS_ERROR_AESGCM_PUT,
CC_REE_FIPS_ERROR_DES_ECB_PUT,
CC_REE_FIPS_ERROR_DES_CBC_PUT,
CC_REE_FIPS_ERROR_SHA1_PUT,
CC_REE_FIPS_ERROR_SHA256_PUT,
CC_REE_FIPS_ERROR_SHA512_PUT,
CC_REE_FIPS_ERROR_HMAC_SHA1_PUT,
CC_REE_FIPS_ERROR_HMAC_SHA256_PUT,
CC_REE_FIPS_ERROR_HMAC_SHA512_PUT,
CC_REE_FIPS_ERROR_ROM_CHECKSUM,
CC_REE_FIPS_ERROR_RESERVE32B = INT32_MAX
} ssi_fips_error_t;
int ssi_fips_get_state(ssi_fips_state_t *p_state);
int ssi_fips_get_error(ssi_fips_error_t *p_err);
#endif /*__SSI_FIPS_H__*/
此差异已折叠。
/*
* Copyright (C) 2012-2017 ARM Limited or its affiliates.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, see <http://www.gnu.org/licenses/>.
*/
/**************************************************************
This file defines the driver FIPS functions that should be
implemented by the driver user. Current implementation is sample code only.
***************************************************************/
#include <linux/module.h>
#include "ssi_fips_local.h"
#include "ssi_driver.h"
static bool tee_error;
module_param(tee_error, bool, 0644);
MODULE_PARM_DESC(tee_error, "Simulate TEE library failure flag: 0 - no error (default), 1 - TEE error occured ");
static ssi_fips_state_t fips_state = CC_FIPS_STATE_NOT_SUPPORTED;
static ssi_fips_error_t fips_error = CC_REE_FIPS_ERROR_OK;
/*
This function returns the FIPS REE state.
The function should be implemented by the driver user, depends on where .
the state value is stored.
The reference code uses global variable.
*/
int ssi_fips_ext_get_state(ssi_fips_state_t *p_state)
{
int rc = 0;
if (p_state == NULL) {
return -EINVAL;
}
*p_state = fips_state;
return rc;
}
/*
This function returns the FIPS REE error.
The function should be implemented by the driver user, depends on where .
the error value is stored.
The reference code uses global variable.
*/
int ssi_fips_ext_get_error(ssi_fips_error_t *p_err)
{
int rc = 0;
if (p_err == NULL) {
return -EINVAL;
}
*p_err = fips_error;
return rc;
}
/*
This function sets the FIPS REE state.
The function should be implemented by the driver user, depends on where .
the state value is stored.
The reference code uses global variable.
*/
int ssi_fips_ext_set_state(ssi_fips_state_t state)
{
fips_state = state;
return 0;
}
/*
This function sets the FIPS REE error.
The function should be implemented by the driver user, depends on where .
the error value is stored.
The reference code uses global variable.
*/
int ssi_fips_ext_set_error(ssi_fips_error_t err)
{
fips_error = err;
return 0;
}
此差异已折叠。
/*
* Copyright (C) 2012-2017 ARM Limited or its affiliates.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, see <http://www.gnu.org/licenses/>.
*/
/**************************************************************
This file defines the driver FIPS internal function, used by the driver itself.
***************************************************************/
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/platform_device.h>
#include <crypto/des.h>
#include "ssi_config.h"
#include "ssi_driver.h"
#include "cc_hal.h"
#define FIPS_POWER_UP_TEST_CIPHER 1
#define FIPS_POWER_UP_TEST_CMAC 1
#define FIPS_POWER_UP_TEST_HASH 1
#define FIPS_POWER_UP_TEST_HMAC 1
#define FIPS_POWER_UP_TEST_CCM 1
#define FIPS_POWER_UP_TEST_GCM 1
static bool ssi_fips_support = 1;
module_param(ssi_fips_support, bool, 0644);
MODULE_PARM_DESC(ssi_fips_support, "FIPS supported flag: 0 - off , 1 - on (default)");
static void fips_dsr(unsigned long devarg);
struct ssi_fips_handle {
#ifdef COMP_IN_WQ
struct workqueue_struct *workq;
struct delayed_work fipswork;
#else
struct tasklet_struct fipstask;
#endif
};
extern int ssi_fips_get_state(ssi_fips_state_t *p_state);
extern int ssi_fips_get_error(ssi_fips_error_t *p_err);
extern int ssi_fips_ext_set_state(ssi_fips_state_t state);
extern int ssi_fips_ext_set_error(ssi_fips_error_t err);
/* FIPS power-up tests */
extern ssi_fips_error_t ssi_cipher_fips_power_up_tests(struct ssi_drvdata *drvdata, void *cpu_addr_buffer, dma_addr_t dma_coherent_buffer);
extern ssi_fips_error_t ssi_cmac_fips_power_up_tests(struct ssi_drvdata *drvdata, void *cpu_addr_buffer, dma_addr_t dma_coherent_buffer);
extern ssi_fips_error_t ssi_hash_fips_power_up_tests(struct ssi_drvdata *drvdata, void *cpu_addr_buffer, dma_addr_t dma_coherent_buffer);
extern ssi_fips_error_t ssi_hmac_fips_power_up_tests(struct ssi_drvdata *drvdata, void *cpu_addr_buffer, dma_addr_t dma_coherent_buffer);
extern ssi_fips_error_t ssi_ccm_fips_power_up_tests(struct ssi_drvdata *drvdata, void *cpu_addr_buffer, dma_addr_t dma_coherent_buffer);
extern ssi_fips_error_t ssi_gcm_fips_power_up_tests(struct ssi_drvdata *drvdata, void *cpu_addr_buffer, dma_addr_t dma_coherent_buffer);
extern size_t ssi_fips_max_mem_alloc_size(void);
/* The function called once at driver entry point to check whether TEE FIPS error occured.*/
static enum ssi_fips_error ssi_fips_get_tee_error(struct ssi_drvdata *drvdata)
{
uint32_t regVal;
void __iomem *cc_base = drvdata->cc_base;
regVal = CC_HAL_READ_REGISTER(CC_REG_OFFSET(HOST_RGF, GPR_HOST));
if (regVal == (CC_FIPS_SYNC_TEE_STATUS | CC_FIPS_SYNC_MODULE_OK)) {
return CC_REE_FIPS_ERROR_OK;
}
return CC_REE_FIPS_ERROR_FROM_TEE;
}
/*
This function should push the FIPS REE library status towards the TEE library.
By writing the error state to HOST_GPR0 register. The function is called from .
driver entry point so no need to protect by mutex.
*/
static void ssi_fips_update_tee_upon_ree_status(struct ssi_drvdata *drvdata, ssi_fips_error_t err)
{
void __iomem *cc_base = drvdata->cc_base;
if (err == CC_REE_FIPS_ERROR_OK) {
CC_HAL_WRITE_REGISTER(CC_REG_OFFSET(HOST_RGF, HOST_GPR0), (CC_FIPS_SYNC_REE_STATUS|CC_FIPS_SYNC_MODULE_OK));
} else {
CC_HAL_WRITE_REGISTER(CC_REG_OFFSET(HOST_RGF, HOST_GPR0), (CC_FIPS_SYNC_REE_STATUS|CC_FIPS_SYNC_MODULE_ERROR));
}
}
void ssi_fips_fini(struct ssi_drvdata *drvdata)
{
struct ssi_fips_handle *fips_h = drvdata->fips_handle;
if (fips_h == NULL)
return; /* Not allocated */
#ifdef COMP_IN_WQ
if (fips_h->workq != NULL) {
flush_workqueue(fips_h->workq);
destroy_workqueue(fips_h->workq);
}
#else
/* Kill tasklet */
tasklet_kill(&fips_h->fipstask);
#endif
memset(fips_h, 0, sizeof(struct ssi_fips_handle));
kfree(fips_h);
drvdata->fips_handle = NULL;
}
void fips_handler(struct ssi_drvdata *drvdata)
{
struct ssi_fips_handle *fips_handle_ptr =
drvdata->fips_handle;
#ifdef COMP_IN_WQ
queue_delayed_work(fips_handle_ptr->workq, &fips_handle_ptr->fipswork, 0);
#else
tasklet_schedule(&fips_handle_ptr->fipstask);
#endif
}
#ifdef COMP_IN_WQ
static void fips_wq_handler(struct work_struct *work)
{
struct ssi_drvdata *drvdata =
container_of(work, struct ssi_drvdata, fipswork.work);
fips_dsr((unsigned long)drvdata);
}
#endif
/* Deferred service handler, run as interrupt-fired tasklet */
static void fips_dsr(unsigned long devarg)
{
struct ssi_drvdata *drvdata = (struct ssi_drvdata *)devarg;
void __iomem *cc_base = drvdata->cc_base;
uint32_t irq;
uint32_t teeFipsError = 0;
irq = (drvdata->irq & (SSI_GPR0_IRQ_MASK));
if (irq & SSI_GPR0_IRQ_MASK) {
teeFipsError = CC_HAL_READ_REGISTER(CC_REG_OFFSET(HOST_RGF, GPR_HOST));
if (teeFipsError != (CC_FIPS_SYNC_TEE_STATUS | CC_FIPS_SYNC_MODULE_OK)) {
ssi_fips_set_error(drvdata, CC_REE_FIPS_ERROR_FROM_TEE);
}
}
/* after verifing that there is nothing to do, Unmask AXI completion interrupt */
CC_HAL_WRITE_REGISTER(CC_REG_OFFSET(HOST_RGF, HOST_IMR),
CC_HAL_READ_REGISTER(
CC_REG_OFFSET(HOST_RGF, HOST_IMR)) & ~irq);
}
ssi_fips_error_t cc_fips_run_power_up_tests(struct ssi_drvdata *drvdata)
{
ssi_fips_error_t fips_error = CC_REE_FIPS_ERROR_OK;
void * cpu_addr_buffer = NULL;
dma_addr_t dma_handle;
size_t alloc_buff_size = ssi_fips_max_mem_alloc_size();
struct device *dev = &drvdata->plat_dev->dev;
// allocate memory using dma_alloc_coherent - for phisical, consecutive and cache coherent buffer (memory map is not needed)
// the return value is the virtual address - use it to copy data into the buffer
// the dma_handle is the returned phy address - use it in the HW descriptor
FIPS_DBG("dma_alloc_coherent \n");
cpu_addr_buffer = dma_alloc_coherent(dev, alloc_buff_size, &dma_handle, GFP_KERNEL);
if (cpu_addr_buffer == NULL) {
return CC_REE_FIPS_ERROR_GENERAL;
}
FIPS_DBG("allocated coherent buffer - addr 0x%08X , size = %d \n", (size_t)cpu_addr_buffer, alloc_buff_size);
#if FIPS_POWER_UP_TEST_CIPHER
FIPS_DBG("ssi_cipher_fips_power_up_tests ...\n");
fips_error = ssi_cipher_fips_power_up_tests(drvdata, cpu_addr_buffer, dma_handle);
FIPS_DBG("ssi_cipher_fips_power_up_tests - done. (fips_error = %d) \n", fips_error);
#endif
#if FIPS_POWER_UP_TEST_CMAC
if (likely(fips_error == CC_REE_FIPS_ERROR_OK)) {
FIPS_DBG("ssi_cmac_fips_power_up_tests ...\n");
fips_error = ssi_cmac_fips_power_up_tests(drvdata, cpu_addr_buffer, dma_handle);
FIPS_DBG("ssi_cmac_fips_power_up_tests - done. (fips_error = %d) \n", fips_error);
}
#endif
#if FIPS_POWER_UP_TEST_HASH
if (likely(fips_error == CC_REE_FIPS_ERROR_OK)) {
FIPS_DBG("ssi_hash_fips_power_up_tests ...\n");
fips_error = ssi_hash_fips_power_up_tests(drvdata, cpu_addr_buffer, dma_handle);
FIPS_DBG("ssi_hash_fips_power_up_tests - done. (fips_error = %d) \n", fips_error);
}
#endif
#if FIPS_POWER_UP_TEST_HMAC
if (likely(fips_error == CC_REE_FIPS_ERROR_OK)) {
FIPS_DBG("ssi_hmac_fips_power_up_tests ...\n");
fips_error = ssi_hmac_fips_power_up_tests(drvdata, cpu_addr_buffer, dma_handle);
FIPS_DBG("ssi_hmac_fips_power_up_tests - done. (fips_error = %d) \n", fips_error);
}
#endif
#if FIPS_POWER_UP_TEST_CCM
if (likely(fips_error == CC_REE_FIPS_ERROR_OK)) {
FIPS_DBG("ssi_ccm_fips_power_up_tests ...\n");
fips_error = ssi_ccm_fips_power_up_tests(drvdata, cpu_addr_buffer, dma_handle);
FIPS_DBG("ssi_ccm_fips_power_up_tests - done. (fips_error = %d) \n", fips_error);
}
#endif
#if FIPS_POWER_UP_TEST_GCM
if (likely(fips_error == CC_REE_FIPS_ERROR_OK)) {
FIPS_DBG("ssi_gcm_fips_power_up_tests ...\n");
fips_error = ssi_gcm_fips_power_up_tests(drvdata, cpu_addr_buffer, dma_handle);
FIPS_DBG("ssi_gcm_fips_power_up_tests - done. (fips_error = %d) \n", fips_error);
}
#endif
/* deallocate the buffer when all tests are done... */
FIPS_DBG("dma_free_coherent \n");
dma_free_coherent(dev, alloc_buff_size, cpu_addr_buffer, dma_handle);
return fips_error;
}
/* The function checks if FIPS supported and FIPS error exists.*
* It should be used in every driver API.*/
int ssi_fips_check_fips_error(void)
{
ssi_fips_state_t fips_state;
if (ssi_fips_get_state(&fips_state) != 0) {
FIPS_LOG("ssi_fips_get_state FAILED, returning.. \n");
return -ENOEXEC;
}
if (fips_state == CC_FIPS_STATE_ERROR) {
FIPS_LOG("ssi_fips_get_state: fips_state is %d, returning.. \n", fips_state);
return -ENOEXEC;
}
return 0;
}
/* The function sets the REE FIPS state.*
* It should be used while driver is being loaded .*/
int ssi_fips_set_state(ssi_fips_state_t state)
{
return ssi_fips_ext_set_state(state);
}
/* The function sets the REE FIPS error, and pushes the error to TEE library. *
* It should be used when any of the KAT tests fails .*/
int ssi_fips_set_error(struct ssi_drvdata *p_drvdata, ssi_fips_error_t err)
{
int rc = 0;
ssi_fips_error_t current_err;
FIPS_LOG("ssi_fips_set_error - fips_error = %d \n", err);
// setting no error is not allowed
if (err == CC_REE_FIPS_ERROR_OK) {
return -ENOEXEC;
}
// If error exists, do not set new error
if (ssi_fips_get_error(&current_err) != 0) {
return -ENOEXEC;
}
if (current_err != CC_REE_FIPS_ERROR_OK) {
return -ENOEXEC;
}
// set REE internal error and state
rc = ssi_fips_ext_set_error(err);
if (rc != 0) {
return -ENOEXEC;
}
rc = ssi_fips_ext_set_state(CC_FIPS_STATE_ERROR);
if (rc != 0) {
return -ENOEXEC;
}
// push error towards TEE libraray, if it's not TEE error
if (err != CC_REE_FIPS_ERROR_FROM_TEE) {
ssi_fips_update_tee_upon_ree_status(p_drvdata, err);
}
return rc;
}
/* The function called once at driver entry point .*/
int ssi_fips_init(struct ssi_drvdata *p_drvdata)
{
ssi_fips_error_t rc = CC_REE_FIPS_ERROR_OK;
struct ssi_fips_handle *fips_h;
FIPS_DBG("CC FIPS code .. (fips=%d) \n", ssi_fips_support);
fips_h = kzalloc(sizeof(struct ssi_fips_handle),GFP_KERNEL);
if (fips_h == NULL) {
ssi_fips_set_error(p_drvdata, CC_REE_FIPS_ERROR_GENERAL);
return -ENOMEM;
}
p_drvdata->fips_handle = fips_h;
#ifdef COMP_IN_WQ
SSI_LOG_DEBUG("Initializing fips workqueue\n");
fips_h->workq = create_singlethread_workqueue("arm_cc7x_fips_wq");
if (unlikely(fips_h->workq == NULL)) {
SSI_LOG_ERR("Failed creating fips work queue\n");
ssi_fips_set_error(p_drvdata, CC_REE_FIPS_ERROR_GENERAL);
rc = -ENOMEM;
goto ssi_fips_init_err;
}
INIT_DELAYED_WORK(&fips_h->fipswork, fips_wq_handler);
#else
SSI_LOG_DEBUG("Initializing fips tasklet\n");
tasklet_init(&fips_h->fipstask, fips_dsr, (unsigned long)p_drvdata);
#endif
/* init fips driver data */
rc = ssi_fips_set_state((ssi_fips_support == 0)? CC_FIPS_STATE_NOT_SUPPORTED : CC_FIPS_STATE_SUPPORTED);
if (unlikely(rc != 0)) {
ssi_fips_set_error(p_drvdata, CC_REE_FIPS_ERROR_GENERAL);
rc = -EAGAIN;
goto ssi_fips_init_err;
}
/* Run power up tests (before registration and operating the HW engines) */
FIPS_DBG("ssi_fips_get_tee_error \n");
rc = ssi_fips_get_tee_error(p_drvdata);
if (unlikely(rc != CC_REE_FIPS_ERROR_OK)) {
ssi_fips_set_error(p_drvdata, CC_REE_FIPS_ERROR_FROM_TEE);
rc = -EAGAIN;
goto ssi_fips_init_err;
}
FIPS_DBG("cc_fips_run_power_up_tests \n");
rc = cc_fips_run_power_up_tests(p_drvdata);
if (unlikely(rc != CC_REE_FIPS_ERROR_OK)) {
ssi_fips_set_error(p_drvdata, rc);
rc = -EAGAIN;
goto ssi_fips_init_err;
}
FIPS_LOG("cc_fips_run_power_up_tests - done ... fips_error = %d \n", rc);
/* when all tests passed, update TEE with fips OK status after power up tests */
ssi_fips_update_tee_upon_ree_status(p_drvdata, CC_REE_FIPS_ERROR_OK);
if (unlikely(rc != 0)) {
rc = -EAGAIN;
ssi_fips_set_error(p_drvdata, CC_REE_FIPS_ERROR_GENERAL);
goto ssi_fips_init_err;
}
return 0;
ssi_fips_init_err:
ssi_fips_fini(p_drvdata);
return rc;
}
/*
* Copyright (C) 2012-2017 ARM Limited or its affiliates.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, see <http://www.gnu.org/licenses/>.
*/
#ifndef __SSI_FIPS_LOCAL_H__
#define __SSI_FIPS_LOCAL_H__
#ifdef CONFIG_CCX7REE_FIPS_SUPPORT
#include "ssi_fips.h"
struct ssi_drvdata;
// IG - how to make 1 file for TEE and REE
typedef enum CC_FipsSyncStatus{
CC_FIPS_SYNC_MODULE_OK = 0x0,
CC_FIPS_SYNC_MODULE_ERROR = 0x1,
CC_FIPS_SYNC_REE_STATUS = 0x4,
CC_FIPS_SYNC_TEE_STATUS = 0x8,
CC_FIPS_SYNC_STATUS_RESERVE32B = INT32_MAX
}CCFipsSyncStatus_t;
#define CHECK_AND_RETURN_UPON_FIPS_ERROR() {\
if (ssi_fips_check_fips_error() != 0) {\
return -ENOEXEC;\
}\
}
#define CHECK_AND_RETURN_VOID_UPON_FIPS_ERROR() {\
if (ssi_fips_check_fips_error() != 0) {\
return;\
}\
}
#define SSI_FIPS_INIT(p_drvData) (ssi_fips_init(p_drvData))
#define SSI_FIPS_FINI(p_drvData) (ssi_fips_fini(p_drvData))
#define FIPS_LOG(...) SSI_LOG(KERN_INFO, __VA_ARGS__)
#define FIPS_DBG(...) //SSI_LOG(KERN_INFO, __VA_ARGS__)
/* FIPS functions */
int ssi_fips_init(struct ssi_drvdata *p_drvdata);
void ssi_fips_fini(struct ssi_drvdata *drvdata);
int ssi_fips_check_fips_error(void);
int ssi_fips_set_error(struct ssi_drvdata *p_drvdata, ssi_fips_error_t err);
void fips_handler(struct ssi_drvdata *drvdata);
#else /* CONFIG_CC7XXREE_FIPS_SUPPORT */
#define CHECK_AND_RETURN_UPON_FIPS_ERROR()
#define CHECK_AND_RETURN_VOID_UPON_FIPS_ERROR()
static inline int ssi_fips_init(struct ssi_drvdata *p_drvdata)
{
return 0;
}
static inline void ssi_fips_fini(struct ssi_drvdata *drvdata) {}
void fips_handler(struct ssi_drvdata *drvdata);
#endif /* CONFIG_CC7XXREE_FIPS_SUPPORT */
#endif /*__SSI_FIPS_LOCAL_H__*/
......@@ -30,6 +30,7 @@
#include "ssi_sysfs.h"
#include "ssi_hash.h"
#include "ssi_sram_mgr.h"
#include "ssi_fips_local.h"
#define SSI_MAX_AHASH_SEQ_LEN 12
#define SSI_MAX_HASH_OPAD_TMP_KEYS_SIZE MAX(SSI_MAX_HASH_BLCK_SIZE, 3 * AES_BLOCK_SIZE)
......@@ -467,6 +468,8 @@ static int ssi_hash_digest(struct ahash_req_ctx *state,
SSI_LOG_DEBUG("===== %s-digest (%d) ====\n", is_hmac?"hmac":"hash", nbytes);
CHECK_AND_RETURN_UPON_FIPS_ERROR();
if (unlikely(ssi_hash_map_request(dev, state, ctx) != 0)) {
SSI_LOG_ERR("map_ahash_source() failed\n");
return -ENOMEM;
......@@ -623,6 +626,7 @@ static int ssi_hash_update(struct ahash_req_ctx *state,
SSI_LOG_DEBUG("===== %s-update (%d) ====\n", ctx->is_hmac ?
"hmac":"hash", nbytes);
CHECK_AND_RETURN_UPON_FIPS_ERROR();
if (nbytes == 0) {
/* no real updates required */
return 0;
......@@ -719,6 +723,8 @@ static int ssi_hash_finup(struct ahash_req_ctx *state,
SSI_LOG_DEBUG("===== %s-finup (%d) ====\n", is_hmac?"hmac":"hash", nbytes);
CHECK_AND_RETURN_UPON_FIPS_ERROR();
if (unlikely(ssi_buffer_mgr_map_hash_request_final(ctx->drvdata, state, src , nbytes, 1) != 0)) {
SSI_LOG_ERR("map_ahash_request_final() failed\n");
return -ENOMEM;
......@@ -848,6 +854,8 @@ static int ssi_hash_final(struct ahash_req_ctx *state,
SSI_LOG_DEBUG("===== %s-final (%d) ====\n", is_hmac?"hmac":"hash", nbytes);
CHECK_AND_RETURN_UPON_FIPS_ERROR();
if (unlikely(ssi_buffer_mgr_map_hash_request_final(ctx->drvdata, state, src, nbytes, 0) != 0)) {
SSI_LOG_ERR("map_ahash_request_final() failed\n");
return -ENOMEM;
......@@ -975,6 +983,7 @@ static int ssi_hash_init(struct ahash_req_ctx *state, struct ssi_hash_ctx *ctx)
struct device *dev = &ctx->drvdata->plat_dev->dev;
state->xcbc_count = 0;
CHECK_AND_RETURN_UPON_FIPS_ERROR();
ssi_hash_map_request(dev, state, ctx);
return 0;
......@@ -983,12 +992,14 @@ static int ssi_hash_init(struct ahash_req_ctx *state, struct ssi_hash_ctx *ctx)
#ifdef EXPORT_FIXED
static int ssi_hash_export(struct ssi_hash_ctx *ctx, void *out)
{
CHECK_AND_RETURN_UPON_FIPS_ERROR();
memcpy(out, ctx, sizeof(struct ssi_hash_ctx));
return 0;
}
static int ssi_hash_import(struct ssi_hash_ctx *ctx, const void *in)
{
CHECK_AND_RETURN_UPON_FIPS_ERROR();
memcpy(ctx, in, sizeof(struct ssi_hash_ctx));
return 0;
}
......@@ -1010,6 +1021,7 @@ static int ssi_hash_setkey(void *hash,
SSI_LOG_DEBUG("ssi_hash_setkey: start keylen: %d", keylen);
CHECK_AND_RETURN_UPON_FIPS_ERROR();
if (synchronize) {
ctx = crypto_shash_ctx(((struct crypto_shash *)hash));
blocksize = crypto_tfm_alg_blocksize(&((struct crypto_shash *)hash)->base);
......@@ -1218,6 +1230,7 @@ static int ssi_xcbc_setkey(struct crypto_ahash *ahash,
HwDesc_s desc[SSI_MAX_AHASH_SEQ_LEN];
SSI_LOG_DEBUG("===== setkey (%d) ====\n", keylen);
CHECK_AND_RETURN_UPON_FIPS_ERROR();
switch (keylen) {
case AES_KEYSIZE_128:
......@@ -1303,6 +1316,7 @@ static int ssi_cmac_setkey(struct crypto_ahash *ahash,
struct ssi_hash_ctx *ctx = crypto_ahash_ctx(ahash);
DECL_CYCLE_COUNT_RESOURCES;
SSI_LOG_DEBUG("===== setkey (%d) ====\n", keylen);
CHECK_AND_RETURN_UPON_FIPS_ERROR();
ctx->is_hmac = true;
......@@ -1418,6 +1432,7 @@ static int ssi_shash_cra_init(struct crypto_tfm *tfm)
struct ssi_hash_alg *ssi_alg =
container_of(shash_alg, struct ssi_hash_alg, shash_alg);
CHECK_AND_RETURN_UPON_FIPS_ERROR();
ctx->hash_mode = ssi_alg->hash_mode;
ctx->hw_mode = ssi_alg->hw_mode;
ctx->inter_digestsize = ssi_alg->inter_digestsize;
......@@ -1437,6 +1452,7 @@ static int ssi_ahash_cra_init(struct crypto_tfm *tfm)
container_of(ahash_alg, struct ssi_hash_alg, ahash_alg);
CHECK_AND_RETURN_UPON_FIPS_ERROR();
crypto_ahash_set_reqsize(__crypto_ahash_cast(tfm),
sizeof(struct ahash_req_ctx));
......@@ -1468,6 +1484,7 @@ static int ssi_mac_update(struct ahash_request *req)
int rc;
uint32_t idx = 0;
CHECK_AND_RETURN_UPON_FIPS_ERROR();
if (req->nbytes == 0) {
/* no real updates required */
return 0;
......@@ -1535,6 +1552,7 @@ static int ssi_mac_final(struct ahash_request *req)
state->buff0_cnt;
CHECK_AND_RETURN_UPON_FIPS_ERROR();
if (ctx->hw_mode == DRV_CIPHER_XCBC_MAC) {
keySize = CC_AES_128_BIT_KEY_SIZE;
keyLen = CC_AES_128_BIT_KEY_SIZE;
......@@ -1645,7 +1663,7 @@ static int ssi_mac_finup(struct ahash_request *req)
uint32_t digestsize = crypto_ahash_digestsize(tfm);
SSI_LOG_DEBUG("===== finup xcbc(%d) ====\n", req->nbytes);
CHECK_AND_RETURN_UPON_FIPS_ERROR();
if (state->xcbc_count > 0 && req->nbytes == 0) {
SSI_LOG_DEBUG("No data to update. Call to fdx_mac_final \n");
return ssi_mac_final(req);
......@@ -1718,6 +1736,7 @@ static int ssi_mac_digest(struct ahash_request *req)
int rc;
SSI_LOG_DEBUG("===== -digest mac (%d) ====\n", req->nbytes);
CHECK_AND_RETURN_UPON_FIPS_ERROR();
if (unlikely(ssi_hash_map_request(dev, state, ctx) != 0)) {
SSI_LOG_ERR("map_ahash_source() failed\n");
......
......@@ -30,6 +30,8 @@
#include "ssi_sysfs.h"
#include "ssi_ivgen.h"
#include "ssi_pm.h"
#include "ssi_fips.h"
#include "ssi_fips_local.h"
#define SSI_MAX_POLL_ITER 10
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册