#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
#include <wolfssl/wolfcrypt/settings.h>
#ifdef WOLFSSL_AUTOSAR
#ifndef NO_WOLFSSL_AUTOSAR_CRYPTO
#include <wolfssl/wolfcrypt/port/autosar/Csm.h>
#include <wolfssl/wolfcrypt/port/autosar/Crypto.h>
#include <wolfssl/wolfcrypt/logging.h>
#include <wolfssl/wolfcrypt/aes.h>
#include <wolfssl/wolfcrypt/random.h>
#ifdef NO_INLINE
#include <wolfssl/wolfcrypt/misc.h>
#else
#define WOLFSSL_MISC_INCLUDED
#include <wolfcrypt/src/misc.c>
#endif
Std_ReturnType wolfSSL_Crypto_CBC(Crypto_JobType* job);
Std_ReturnType wolfSSL_Crypto(Crypto_JobType* job);
Std_ReturnType wolfSSL_Crypto_RNG(Crypto_JobType* job);
#ifndef MAX_KEYSTORE
#define MAX_KEYSTORE 15
#endif
#ifndef MAX_JOBS
#define MAX_JOBS 10
#endif
static wolfSSL_Mutex crypto_mutex;
struct Keys {
uint32 keyLen;
uint32 eId;
uint8 key[AES_MAX_KEY_SIZE/WOLFSSL_BIT_SIZE];
} Keys;
struct Jobs {
uint32 jobId;
uint8 inUse;
Aes aes;
} Jobs;
static struct Jobs activeJobs[MAX_JOBS];
static struct Keys keyStore[MAX_KEYSTORE];
static int GetKey(Crypto_JobType* job, uint32 eId, uint8 **key, uint32 *keySz)
{
int i, ret = 0;
if (key == NULL || keySz == NULL || *key != NULL) {
WOLFSSL_MSG("Bad parameter to GetKey");
return -1;
}
if (wc_LockMutex(&crypto_mutex) != 0) {
WOLFSSL_MSG("Unable to lock crypto mutex");
return -1;
}
#ifdef REDIRECTION_CONFIG
if (job->jobRedirectionInfoRef == NULL) {
WOLFSSL_MSG("Issue with getting key redirection");
wc_UnLockMutex(&crypto_mutex);
return -1;
}
switch (eId) {
case job->jobRedirectionInfoRef->inputKeyElementId:
if (job->jobRedirectionInfoRef->inputKeyId >= MAX_KEYSTORE) {
WOLFSSL_MSG("Bogus input key ID redirection (too large)");
ret = -1;
}
else {
i = job->jobRedirectionInfoRef->inputKeyId;
*key = keyStore[i].key;
*keySz = keyStore[i].keyLen;
}
break;
case job->jobRedirectionInfoRef->secondaryInputKeyElementId:
if (job->jobRedirectionInfoRef->secondaryInputKeyId >= MAX_KEYSTORE) {
WOLFSSL_MSG("Bogus input key ID redirection (too large)");
ret = -1;
}
else {
i = job->jobRedirectionInfoRef->secondaryInputKeyId;
*key = keyStore[i].key;
*keySz = keyStore[i].keyLen;
}
break;
case job->jobRedirectionInfoRef->tertiaryInputKeyElementId:
if (job->jobRedirectionInfoRef->tertiaryInputKeyId >= MAX_KEYSTORE) {
WOLFSSL_MSG("Bogus input key ID redirection (too large)");
ret = -1;
}
else {
i = job->jobRedirectionInfoRef->tertiaryInputKeyId;
*key = keyStore[i].key;
*keySz = keyStore[i].keyLen;
}
break;
default:
WOLFSSL_MSG("Unknown key element ID");
ret = -1;
break;
}
#else
for (i = 0; i < MAX_KEYSTORE; i++) {
if (keyStore[i].eId == eId && keyStore[i].keyLen ==
job->jobPrimitiveInfo->primitiveInfo->algorithm.keyLength) {
*key = keyStore[i].key;
*keySz = keyStore[i].keyLen;
break;
}
}
#endif
if (*key == NULL) {
WOLFSSL_MSG("Unable to find an available key");
ret = -1;
}
if (wc_UnLockMutex(&crypto_mutex) != 0) {
WOLFSSL_MSG("Unable to unlock crypto mutex");
ret = -1;
}
return ret;
}
static Aes* GetAesStruct(Crypto_JobType* job)
{
int i;
for (i = 0; i < MAX_JOBS; i++) {
if (activeJobs[i].inUse == 1 && activeJobs[i].jobId == job->jobId) {
return &activeJobs[i].aes;
}
}
return NULL;
}
static Aes* NewAesStruct(Crypto_JobType* job)
{
int i;
for (i = 0; i < MAX_JOBS; i++) {
if (activeJobs[i].inUse == 0) {
int ret;
activeJobs[i].inUse = 1;
activeJobs[i].jobId = job->jobId;
ret = wc_AesInit(&activeJobs[i].aes, NULL, INVALID_DEVID);
if (ret != 0) {
WOLFSSL_MSG("Error initializing AES structure");
activeJobs[i].inUse = 0;
activeJobs[i].jobId = 0;
return NULL;
}
return &activeJobs[i].aes;
}
}
return NULL;
}
static void FreeAesStruct(Crypto_JobType* job) {
int i;
for (i = 0; i < MAX_JOBS; i++) {
if (activeJobs[i].inUse == 1 && activeJobs[i].jobId == job->jobId) {
break;
}
}
if (i >= MAX_JOBS) {
WOLFSSL_MSG("Error finding AES structure");
}
else {
wc_AesFree(&activeJobs[i].aes);
activeJobs[i].inUse = 0;
activeJobs[i].jobId = 0;
}
}
Std_ReturnType wolfSSL_Crypto_CBC(Crypto_JobType* job)
{
Std_ReturnType ret = E_OK;
int encrypt;
Aes* aes ;
encrypt = (job->jobPrimitiveInfo->primitiveInfo->service == CRYPTO_ENCRYPT)
? AES_ENCRYPTION : AES_DECRYPTION;
if ((job->jobPrimitiveInputOutput.mode & CRYPTO_OPERATIONMODE_START) != 0) {
uint8 *key = NULL;
uint8 *iv = NULL;
uint32 keySz = 0;
uint32 ivSz = 0;
if (GetKey(job, CRYPTO_KE_CIPHER_KEY, &key, &keySz) != 0) {
WOLFSSL_MSG("Crypto error with getting a key");
return E_NOT_OK;
}
if (GetKey(job, CRYPTO_KE_CIPHER_IV, &iv, &ivSz) != 0) {
WOLFSSL_MSG("Crypto error with getting an IV");
return E_NOT_OK;
}
if (iv != NULL && ivSz < WC_AES_BLOCK_SIZE) {
WOLFSSL_MSG("Error IV is too small");
return E_NOT_OK;
}
aes = NewAesStruct(job);
if (aes == NULL) {
WOLFSSL_MSG("Unable to get AES structure for use");
return E_NOT_OK;
}
if (wc_AesSetKey(aes, key, keySz, iv, encrypt) != 0) {
FreeAesStruct(job);
WOLFSSL_MSG("Crypto error setting up AES key");
return E_NOT_OK;
}
}
if ((job->jobPrimitiveInputOutput.mode & CRYPTO_OPERATIONMODE_UPDATE)
!= 0) {
aes = GetAesStruct(job);
if (aes == NULL) {
WOLFSSL_MSG("Error finding AES structure");
return E_NOT_OK;
}
if (encrypt == AES_ENCRYPTION) {
if (wc_AesCbcEncrypt(aes, job->jobPrimitiveInputOutput.outputPtr,
job->jobPrimitiveInputOutput.inputPtr,
job->jobPrimitiveInputOutput.inputLength) != 0) {
WOLFSSL_MSG("AES-CBC encrypt error");
return E_NOT_OK;
}
}
else {
if (wc_AesCbcDecrypt(aes, job->jobPrimitiveInputOutput.outputPtr,
job->jobPrimitiveInputOutput.inputPtr,
job->jobPrimitiveInputOutput.inputLength) != 0) {
WOLFSSL_MSG("AES-CBC decrypt error");
return E_NOT_OK;
}
}
}
if ((job->jobPrimitiveInputOutput.mode & CRYPTO_OPERATIONMODE_FINISH)
!= 0) {
FreeAesStruct(job);
}
return ret;
}
Std_ReturnType wolfSSL_Crypto(Crypto_JobType* job)
{
Std_ReturnType ret = E_OK;
WOLFSSL_ENTER("wolfSSL_Crypto");
switch (job->jobPrimitiveInfo->primitiveInfo->algorithm.mode) {
case CRYPTO_ALGOMODE_CBC:
ret = wolfSSL_Crypto_CBC(job);
break;
case CRYPTO_ALGOMODE_NOT_SET:
WOLFSSL_MSG("Encrypt algo mode not set!");
ret = E_NOT_OK;
break;
default:
WOLFSSL_MSG("Unsupported encryption mode");
ret = E_NOT_OK;
break;
}
WOLFSSL_LEAVE("wolfSSL_Crypto", ret);
return ret;
}
static WC_RNG rng;
static wolfSSL_Mutex rngMutex;
static volatile byte rngInit = 0;
Std_ReturnType wolfSSL_Crypto_RNG(Crypto_JobType* job)
{
int ret;
uint8 *out = job->jobPrimitiveInputOutput.outputPtr;
uint32 *outSz = job->jobPrimitiveInputOutput.outputLengthPtr;
if (outSz == NULL || out == NULL) {
WOLFSSL_MSG("Bad parameter passed into wolfSSL_Crypto_RNG");
return E_NOT_OK;
}
if (wc_LockMutex(&rngMutex) != 0) {
WOLFSSL_MSG("Error locking RNG mutex");
return E_NOT_OK;
}
if (rngInit == 0) {
ret = wc_InitRng_ex(&rng, NULL, 0);
if (ret != 0) {
WOLFSSL_MSG("Error initializing RNG");
wc_UnLockMutex(&rngMutex);
return E_NOT_OK;
}
rngInit = 1;
}
ret = wc_RNG_GenerateBlock(&rng, out, *outSz);
if (ret != 0) {
WOLFSSL_MSG("Unable to generate random values");
ret = wc_FreeRng(&rng);
if (ret != 0) {
WOLFSSL_MSG("Error free'ing RNG");
}
rngInit = 0;
wc_UnLockMutex(&rngMutex);
return E_NOT_OK;
}
if (wc_UnLockMutex(&rngMutex) != 0) {
WOLFSSL_MSG("Error unlocking RNG mutex");
return E_NOT_OK;
}
return E_OK;
}
Std_ReturnType Crypto_ProcessJob(uint32 objectId, Crypto_JobType* job)
{
Std_ReturnType ret = E_OK;
(void)objectId;
WOLFSSL_ENTER("Crypto_ProcessJob");
if (job == NULL) {
WOLFSSL_MSG("Bad parameter passed to Crypto_ProcessJob");
ret = E_NOT_OK;
}
if (ret == E_OK &&
job->jobPrimitiveInfo->processingType != CRYPTO_PROCESSING_SYNC) {
WOLFSSL_MSG("Crypto only supporting synchronous jobs");
ret = E_NOT_OK;
}
if (ret == E_OK) {
job->jobState = CRYPTO_JOBSTATE_ACTIVE;
switch (job->jobPrimitiveInfo->primitiveInfo->service) {
case CRYPTO_ENCRYPT:
ret = wolfSSL_Crypto(job);
break;
case CRYPTO_DECRYPT:
ret = wolfSSL_Crypto(job);
break;
case CRYPTO_RANDOMGENERATE:
ret = wolfSSL_Crypto_RNG(job);
break;
default:
WOLFSSL_MSG("Unsupported Crypto service");
ret = E_NOT_OK;
break;
}
job->jobState = CRYPTO_JOBSTATE_IDLE;
}
WOLFSSL_LEAVE("Crypto_ProcessJob", ret);
return ret;
}
void Crypto_Init(const Crypto_ConfigType* config)
{
if (wc_InitMutex(&crypto_mutex) != 0) {
WOLFSSL_MSG("Issues setting up crypto mutex");
}
if (wc_InitMutex(&rngMutex) != 0) {
WOLFSSL_MSG("Error initializing RNG mutex");
}
XMEMSET(&keyStore, 0, MAX_KEYSTORE * sizeof(Keys));
XMEMSET(&activeJobs, 0, MAX_JOBS * sizeof(Jobs));
(void)config;
}
Std_ReturnType Crypto_KeyElementSet(uint32 keyId, uint32 eId, const uint8* key,
uint32 keySz)
{
Std_ReturnType ret = E_OK;
if (key == NULL || keySz == 0 || keyId >= MAX_KEYSTORE) {
WOLFSSL_MSG("Bad argument to Crypto_KeyElementSet");
ret = E_NOT_OK;
}
if (ret == E_OK && wc_LockMutex(&crypto_mutex) != 0) {
WOLFSSL_MSG("Unable to lock crypto mutex");
ret = E_NOT_OK;
}
if (ret == E_OK) {
if (keySz > sizeof(keyStore[keyId].key)) {
ret = E_NOT_OK;
}
if (ret == E_OK) {
WOLFSSL_MSG("Setting new key");
keyStore[keyId].eId = eId;
XMEMCPY(keyStore[keyId].key, key, keySz);
keyStore[keyId].keyLen = keySz;
}
if (wc_UnLockMutex(&crypto_mutex) != 0) {
WOLFSSL_MSG("Unable to unlock crypto mutex");
ret = E_NOT_OK;
}
}
return ret;
}
#endif
#endif