diff options
| author | auth12 <[email protected]> | 2020-07-22 08:34:12 -0700 |
|---|---|---|
| committer | auth12 <[email protected]> | 2020-07-22 08:34:12 -0700 |
| commit | 5015ddb9b1eee748efc24056e46f81888c975f7a (patch) | |
| tree | a810f6ee90f8bfe0e934fdd9142198e6b3862957 /wolfcrypt/src/port/caam | |
| download | wolfssl_windows-5015ddb9b1eee748efc24056e46f81888c975f7a.tar.xz wolfssl_windows-5015ddb9b1eee748efc24056e46f81888c975f7a.zip | |
Initial commit
Diffstat (limited to 'wolfcrypt/src/port/caam')
| -rw-r--r-- | wolfcrypt/src/port/caam/caam_aes.c | 649 | ||||
| -rw-r--r-- | wolfcrypt/src/port/caam/caam_doc.pdf | bin | 0 -> 1107370 bytes | |||
| -rw-r--r-- | wolfcrypt/src/port/caam/caam_driver.c | 1713 | ||||
| -rw-r--r-- | wolfcrypt/src/port/caam/caam_init.c | 289 | ||||
| -rw-r--r-- | wolfcrypt/src/port/caam/caam_sha.c | 397 |
5 files changed, 3048 insertions, 0 deletions
diff --git a/wolfcrypt/src/port/caam/caam_aes.c b/wolfcrypt/src/port/caam/caam_aes.c new file mode 100644 index 0000000..e00214d --- /dev/null +++ b/wolfcrypt/src/port/caam/caam_aes.c @@ -0,0 +1,649 @@ +/* caam_aes.c + * + * Copyright (C) 2006-2020 wolfSSL Inc. + * + * This file is part of wolfSSL. + * + * wolfSSL is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * wolfSSL 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, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335, USA + */ + + +#include <wolfssl/wolfcrypt/settings.h> + +#if defined(WOLFSSL_IMX6_CAAM) && !defined(NO_AES) && \ + !defined(NO_IMX6_CAAM_AES) + +#include <wolfssl/wolfcrypt/logging.h> +#include <wolfssl/wolfcrypt/error-crypt.h> +#include <wolfssl/wolfcrypt/aes.h> + +#ifdef NO_INLINE + #include <wolfssl/wolfcrypt/misc.h> +#else + #define WOLFSSL_MISC_INCLUDED + #include <wolfcrypt/src/misc.c> +#endif + +#include <wolfssl/wolfcrypt/port/caam/wolfcaam.h> +#include <wolfssl/wolfcrypt/port/caam/caam_driver.h> + +#if defined(WOLFSSL_CAAM_DEBUG) || defined(WOLFSSL_CAAM_PRINT) +#include <stdio.h> +#endif + +int wc_AesSetKey(Aes* aes, const byte* key, word32 len, + const byte* iv, int dir) +{ + int ret; + + if (aes == NULL || key == NULL) { + return BAD_FUNC_ARG; + } + + if (len > 32) { + byte out[32]; /* max AES key size */ + word32 outSz; + int ret; + + if (len != 64 && len != 72 && len != 80) { + return BAD_FUNC_ARG; + } + + outSz = sizeof(out); + /* if length greater then 32 then try to unencapsulate */ + if ((ret = wc_caamOpenBlob((byte*)key, len, out, &outSz)) != 0) { + return ret; + } + + XMEMCPY((byte*)aes->key, out, outSz); + aes->keylen = outSz; + } + else { + if (len != 16 && len != 24 && len != 32) { + return BAD_FUNC_ARG; + } + + XMEMCPY((byte*)aes->key, key, len); + aes->keylen = len; + } + + switch (aes->keylen) { + case 16: aes->rounds = 10; break; + case 24: aes->rounds = 12; break; + case 32: aes->rounds = 14; break; + default: + return BAD_FUNC_ARG; + } + + if ((ret = wc_AesSetIV(aes, iv)) != 0) { + return ret; + } + +#ifdef WOLFSSL_AES_COUNTER + aes->left = 0; +#endif + + return 0; +} + + +int wc_AesCbcEncrypt(Aes* aes, byte* out, + const byte* in, word32 sz) +{ + word32 blocks; + + WOLFSSL_ENTER("wc_AesCbcEncrypt"); + if (aes == NULL || out == NULL || in == NULL) { + return BAD_FUNC_ARG; + } + + blocks = sz / AES_BLOCK_SIZE; + + if (blocks > 0) { + Buffer buf[4]; + word32 arg[4]; + word32 keySz; + int ret; + + if (wc_AesGetKeySize(aes, &keySz) != 0) { + return BAD_FUNC_ARG; + } + + /* Set buffers for key, cipher text, and plain text */ + buf[0].BufferType = DataBuffer; + buf[0].TheAddress = (Address)aes->key; + buf[0].Length = keySz; + + buf[1].BufferType = DataBuffer; + buf[1].TheAddress = (Address)aes->reg; + buf[1].Length = AES_BLOCK_SIZE; + + buf[2].BufferType = DataBuffer; + buf[2].TheAddress = (Address)in; + buf[2].Length = blocks * AES_BLOCK_SIZE; + + buf[3].BufferType = DataBuffer | LastBuffer; + buf[3].TheAddress = (Address)out; + buf[3].Length = blocks * AES_BLOCK_SIZE; + + arg[0] = CAAM_ENC; + arg[1] = keySz; + arg[2] = blocks * AES_BLOCK_SIZE; + + if ((ret = wc_caamAddAndWait(buf, arg, CAAM_AESCBC)) != 0) { + WOLFSSL_MSG("Error with CAAM AES CBC encrypt"); + return ret; + } + } + + return 0; +} + + +int wc_AesCbcDecrypt(Aes* aes, byte* out, + const byte* in, word32 sz) +{ + word32 blocks; + + WOLFSSL_ENTER("wc_AesCbcDecrypt"); + if (aes == NULL || out == NULL || in == NULL) { + return BAD_FUNC_ARG; + } + + blocks = sz / AES_BLOCK_SIZE; + + if (blocks > 0) { + Buffer buf[4]; + word32 arg[4]; + word32 keySz; + int ret; + + if (wc_AesGetKeySize(aes, &keySz) != 0) { + return BAD_FUNC_ARG; + } + + /* Set buffers for key, cipher text, and plain text */ + buf[0].BufferType = DataBuffer; + buf[0].TheAddress = (Address)aes->key; + buf[0].Length = keySz; + + buf[1].BufferType = DataBuffer; + buf[1].TheAddress = (Address)aes->reg; + buf[1].Length = AES_BLOCK_SIZE; + + buf[2].BufferType = DataBuffer; + buf[2].TheAddress = (Address)in; + buf[2].Length = blocks * AES_BLOCK_SIZE; + + buf[3].BufferType = DataBuffer | LastBuffer; + buf[3].TheAddress = (Address)out; + buf[3].Length = blocks * AES_BLOCK_SIZE; + + arg[0] = CAAM_DEC; + arg[1] = keySz; + arg[2] = blocks * AES_BLOCK_SIZE; + + if ((ret = wc_caamAddAndWait(buf, arg, CAAM_AESCBC)) != 0) { + WOLFSSL_MSG("Error with CAAM AES CBC decrypt"); + return ret; + } + } + + return 0; +} + +#if defined(HAVE_AES_ECB) +/* is assumed that input size is a multiple of AES_BLOCK_SIZE */ +int wc_AesEcbEncrypt(Aes* aes, byte* out, + const byte* in, word32 sz) +{ + word32 blocks; + Buffer buf[3]; + word32 arg[4]; + word32 keySz; + int ret; + + if (aes == NULL || out == NULL || in == NULL) { + return BAD_FUNC_ARG; + } + + blocks = sz / AES_BLOCK_SIZE; + + if (wc_AesGetKeySize(aes, &keySz) != 0) { + return BAD_FUNC_ARG; + } + + /* Set buffers for key, cipher text, and plain text */ + buf[0].BufferType = DataBuffer; + buf[0].TheAddress = (Address)aes->key; + buf[0].Length = keySz; + + buf[1].BufferType = DataBuffer; + buf[1].TheAddress = (Address)in; + buf[1].Length = blocks * AES_BLOCK_SIZE; + + buf[2].BufferType = DataBuffer | LastBuffer; + buf[2].TheAddress = (Address)out; + buf[2].Length = blocks * AES_BLOCK_SIZE; + + arg[0] = CAAM_ENC; + arg[1] = keySz; + arg[2] = blocks * AES_BLOCK_SIZE; + + if ((ret = wc_caamAddAndWait(buf, arg, CAAM_AESECB)) != 0) { + WOLFSSL_MSG("Error with CAAM AES ECB encrypt"); + return ret; + } + + return 0; +} + + +int wc_AesEcbDecrypt(Aes* aes, byte* out, + const byte* in, word32 sz) +{ + word32 blocks; + Buffer buf[3]; + word32 arg[4]; + word32 keySz; + int ret; + + if (aes == NULL || out == NULL || in == NULL) { + return BAD_FUNC_ARG; + } + + blocks = sz / AES_BLOCK_SIZE; + + if (wc_AesGetKeySize(aes, &keySz) != 0) { + return BAD_FUNC_ARG; + } + + /* Set buffers for key, cipher text, and plain text */ + buf[0].BufferType = DataBuffer; + buf[0].TheAddress = (Address)aes->key; + buf[0].Length = keySz; + + buf[1].BufferType = DataBuffer; + buf[1].TheAddress = (Address)in; + buf[1].Length = blocks * AES_BLOCK_SIZE; + + buf[2].BufferType = DataBuffer | LastBuffer; + buf[2].TheAddress = (Address)out; + buf[2].Length = blocks * AES_BLOCK_SIZE; + + arg[0] = CAAM_DEC; + arg[1] = keySz; + arg[2] = blocks * AES_BLOCK_SIZE; + + if ((ret = wc_caamAddAndWait(buf, arg, CAAM_AESECB)) != 0) { + WOLFSSL_MSG("Error with CAAM AES ECB decrypt"); + return ret; + } + + return 0; +} +#endif + +/* AES-CTR */ +#ifdef WOLFSSL_AES_COUNTER +/* Increment AES counter (from wolfcrypt/src/aes.c) */ +static WC_INLINE void IncrementAesCounter(byte* inOutCtr) +{ + /* in network byte order so start at end and work back */ + int i; + for (i = AES_BLOCK_SIZE - 1; i >= 0; i--) { + if (++inOutCtr[i]) /* we're done unless we overflow */ + return; + } +} + + +int wc_AesCtrEncrypt(Aes* aes, byte* out, + const byte* in, word32 sz) +{ + byte* tmp; + Buffer buf[4]; + word32 arg[4]; + word32 keySz; + int ret, blocks; + + if (aes == NULL || out == NULL || in == NULL) { + return BAD_FUNC_ARG; + } + + if (wc_AesGetKeySize(aes, &keySz) != 0) { + return BAD_FUNC_ARG; + } + + /* consume any unused bytes left in aes->tmp */ + tmp = (byte*)aes->tmp + AES_BLOCK_SIZE - aes->left; + while (aes->left && sz) { + *(out++) = *(in++) ^ *(tmp++); + aes->left--; + sz--; + } + + /* do full blocks to then get potential left over amount */ + blocks = sz / AES_BLOCK_SIZE; + if (blocks > 0) { + /* Set buffers for key, cipher text, and plain text */ + buf[0].BufferType = DataBuffer; + buf[0].TheAddress = (Address)aes->key; + buf[0].Length = keySz; + + buf[1].BufferType = DataBuffer; + buf[1].TheAddress = (Address)aes->reg; + buf[1].Length = AES_BLOCK_SIZE; + + buf[2].BufferType = DataBuffer; + buf[2].TheAddress = (Address)in; + buf[2].Length = blocks * AES_BLOCK_SIZE; + + buf[3].BufferType = DataBuffer | LastBuffer; + buf[3].TheAddress = (Address)out; + buf[3].Length = blocks * AES_BLOCK_SIZE; + + arg[0] = CAAM_ENC; + arg[1] = keySz; + arg[2] = blocks * AES_BLOCK_SIZE; + + if ((ret = wc_caamAddAndWait(buf, arg, CAAM_AESCTR)) != 0) { + WOLFSSL_MSG("Error with CAAM AES CTR encrypt"); + return ret; + } + + out += blocks * AES_BLOCK_SIZE; + in += blocks * AES_BLOCK_SIZE; + sz -= blocks * AES_BLOCK_SIZE; + } + + if (sz) { + wc_AesEncryptDirect(aes, (byte*)aes->tmp, (byte*)aes->reg); + IncrementAesCounter((byte*)aes->reg); + + aes->left = AES_BLOCK_SIZE; + tmp = (byte*)aes->tmp; + + while (sz--) { + *(out++) = *(in++) ^ *(tmp++); + aes->left--; + } + } + + return 0; +} +#endif + + +/* AES-DIRECT */ +#if defined(WOLFSSL_AES_DIRECT) || defined(WOLFSSL_AES_COUNTER) +void wc_AesEncryptDirect(Aes* aes, byte* out, const byte* in) +{ + Buffer buf[3]; + word32 arg[4]; + word32 keySz; + + if (aes == NULL || out == NULL || in == NULL) { + /* return BAD_FUNC_ARG; */ + return; + } + + if (wc_AesGetKeySize(aes, &keySz) != 0) { + /* return BAD_FUNC_ARG; */ + return; + } + + /* Set buffers for key, cipher text, and plain text */ + buf[0].BufferType = DataBuffer; + buf[0].TheAddress = (Address)aes->key; + buf[0].Length = keySz; + + buf[1].BufferType = DataBuffer; + buf[1].TheAddress = (Address)in; + buf[1].Length = AES_BLOCK_SIZE; + + buf[2].BufferType = DataBuffer | LastBuffer; + buf[2].TheAddress = (Address)out; + buf[2].Length = AES_BLOCK_SIZE; + + arg[0] = CAAM_ENC; + arg[1] = keySz; + arg[2] = AES_BLOCK_SIZE; + + if (wc_caamAddAndWait(buf, arg, CAAM_AESECB) != 0) { + WOLFSSL_MSG("Error with CAAM AES direct encrypt"); + } +} + + +void wc_AesDecryptDirect(Aes* aes, byte* out, const byte* in) +{ + Buffer buf[3]; + word32 arg[4]; + word32 keySz; + + if (aes == NULL || out == NULL || in == NULL) { + /* return BAD_FUNC_ARG; */ + return; + } + + if (wc_AesGetKeySize(aes, &keySz) != 0) { + /* return BAD_FUNC_ARG; */ + return; + } + + /* Set buffers for key, cipher text, and plain text */ + buf[0].BufferType = DataBuffer; + buf[0].TheAddress = (Address)aes->key; + buf[0].Length = keySz; + + buf[1].BufferType = DataBuffer; + buf[1].TheAddress = (Address)in; + buf[1].Length = AES_BLOCK_SIZE; + + buf[2].BufferType = DataBuffer | LastBuffer; + buf[2].TheAddress = (Address)out; + buf[2].Length = AES_BLOCK_SIZE; + + arg[0] = CAAM_DEC; + arg[1] = keySz; + arg[2] = AES_BLOCK_SIZE; + + if (wc_caamAddAndWait(buf, arg, CAAM_AESECB) != 0) { + WOLFSSL_MSG("Error with CAAM AES direct decrypt"); + } +} + + +int wc_AesSetKeyDirect(Aes* aes, const byte* key, word32 len, + const byte* iv, int dir) +{ + return wc_AesSetKey(aes, key, len, iv, dir); +} +#endif + +#ifdef HAVE_AESCCM +int wc_AesCcmEncrypt(Aes* aes, byte* out, + const byte* in, word32 inSz, + const byte* nonce, word32 nonceSz, + byte* authTag, word32 authTagSz, + const byte* authIn, word32 authInSz) +{ + Buffer buf[5]; + word32 arg[4]; + word32 keySz; + word32 i; + byte B0Ctr0[AES_BLOCK_SIZE + AES_BLOCK_SIZE]; + int lenSz; + byte mask = 0xFF; + const word32 wordSz = (word32)sizeof(word32); + int ret; + + /* sanity check on arguments */ + if (aes == NULL || out == NULL || in == NULL || nonce == NULL + || authTag == NULL || nonceSz < 7 || nonceSz > 13 || + authTagSz > AES_BLOCK_SIZE) + return BAD_FUNC_ARG; + + if (wc_AesGetKeySize(aes, &keySz) != 0) { + return BAD_FUNC_ARG; + } + + /* set up B0 and CTR0 similar to how wolfcrypt/src/aes.c does */ + XMEMCPY(B0Ctr0+1, nonce, nonceSz); + XMEMCPY(B0Ctr0+AES_BLOCK_SIZE+1, nonce, nonceSz); + lenSz = AES_BLOCK_SIZE - 1 - (byte)nonceSz; + B0Ctr0[0] = (authInSz > 0 ? 64 : 0) + + (8 * (((byte)authTagSz - 2) / 2)) + + (lenSz - 1); + for (i = 0; i < lenSz; i++) { + if (mask && i >= wordSz) + mask = 0x00; + B0Ctr0[AES_BLOCK_SIZE - 1 - i] = (inSz >> ((8 * i) & mask)) & mask; + B0Ctr0[AES_BLOCK_SIZE + AES_BLOCK_SIZE - 1 - i] = 0; + } + B0Ctr0[AES_BLOCK_SIZE] = lenSz - 1; + + /* Set buffers for key, cipher text, and plain text */ + buf[0].BufferType = DataBuffer; + buf[0].TheAddress = (Address)aes->key; + buf[0].Length = keySz; + + buf[1].BufferType = DataBuffer; + buf[1].TheAddress = (Address)B0Ctr0; + buf[1].Length = AES_BLOCK_SIZE + AES_BLOCK_SIZE; + + buf[2].BufferType = DataBuffer; + buf[2].TheAddress = (Address)authIn; + buf[2].Length = authInSz; + + buf[3].BufferType = DataBuffer; + buf[3].TheAddress = (Address)in; + buf[3].Length = inSz; + + buf[4].BufferType = DataBuffer | LastBuffer; + buf[4].TheAddress = (Address)out; + buf[4].Length = inSz; + + arg[0] = CAAM_ENC; + arg[1] = keySz; + arg[2] = inSz; + arg[3] = authInSz; + + if ((ret = wc_caamAddAndWait(buf, arg, CAAM_AESCCM)) != 0) { + WOLFSSL_MSG("Error with CAAM AES-CCM encrypt"); + return ret; + } + + XMEMCPY(authTag, B0Ctr0, authTagSz); + return 0; +} + + +#ifdef HAVE_AES_DECRYPT +int wc_AesCcmDecrypt(Aes* aes, byte* out, + const byte* in, word32 inSz, + const byte* nonce, word32 nonceSz, + const byte* authTag, word32 authTagSz, + const byte* authIn, word32 authInSz) +{ + Buffer buf[5]; + word32 arg[4]; + word32 keySz; + word32 i; + byte B0Ctr0[AES_BLOCK_SIZE + AES_BLOCK_SIZE]; + byte tag[AES_BLOCK_SIZE]; + int lenSz; + byte mask = 0xFF; + const word32 wordSz = (word32)sizeof(word32); + int ret; + + /* sanity check on arguments */ + if (aes == NULL || out == NULL || in == NULL || nonce == NULL + || authTag == NULL || nonceSz < 7 || nonceSz > 13 || + authTagSz > AES_BLOCK_SIZE) + return BAD_FUNC_ARG; + + if (wc_AesGetKeySize(aes, &keySz) != 0) { + return BAD_FUNC_ARG; + } + + /* set up B0 and CTR0 similar to how wolfcrypt/src/aes.c does */ + XMEMCPY(B0Ctr0+1, nonce, nonceSz); + XMEMCPY(B0Ctr0+AES_BLOCK_SIZE+1, nonce, nonceSz); + lenSz = AES_BLOCK_SIZE - 1 - (byte)nonceSz; + B0Ctr0[0] = (authInSz > 0 ? 64 : 0) + + (8 * (((byte)authTagSz - 2) / 2)) + + (lenSz - 1); + for (i = 0; i < lenSz; i++) { + if (mask && i >= wordSz) + mask = 0x00; + B0Ctr0[AES_BLOCK_SIZE - 1 - i] = (inSz >> ((8 * i) & mask)) & mask; + B0Ctr0[AES_BLOCK_SIZE + AES_BLOCK_SIZE - 1 - i] = 0; + } + B0Ctr0[AES_BLOCK_SIZE] = lenSz - 1; + wc_AesEncryptDirect(aes, tag, B0Ctr0 + AES_BLOCK_SIZE); + + /* Set buffers for key, cipher text, and plain text */ + buf[0].BufferType = DataBuffer; + buf[0].TheAddress = (Address)aes->key; + buf[0].Length = keySz; + + buf[1].BufferType = DataBuffer; + buf[1].TheAddress = (Address)B0Ctr0; + buf[1].Length = AES_BLOCK_SIZE + AES_BLOCK_SIZE; + + buf[2].BufferType = DataBuffer; + buf[2].TheAddress = (Address)authIn; + buf[2].Length = authInSz; + + buf[3].BufferType = DataBuffer; + buf[3].TheAddress = (Address)in; + buf[3].Length = inSz; + + buf[4].BufferType = DataBuffer | LastBuffer; + buf[4].TheAddress = (Address)out; + buf[4].Length = inSz; + + arg[0] = CAAM_DEC; + arg[1] = keySz; + arg[2] = inSz; + arg[3] = authInSz; + + if ((ret = wc_caamAddAndWait(buf, arg, CAAM_AESCCM)) != 0) { + WOLFSSL_MSG("Error with CAAM AES-CCM derypt"); + return ret; + } + + xorbuf(tag, B0Ctr0, authTagSz); + if (ConstantCompare(tag, authTag, authTagSz) != 0) { + /* If the authTag check fails, don't keep the decrypted data. + * Unfortunately, you need the decrypted data to calculate the + * check value. */ + XMEMSET(out, 0, inSz); + ret = AES_CCM_AUTH_E; + } + + ForceZero(tag, AES_BLOCK_SIZE); + ForceZero(B0Ctr0, AES_BLOCK_SIZE * 2); + + return ret; + +} +#endif /* HAVE_AES_DECRYPT */ +#endif /* HAVE_AESCCM */ + +#endif /* WOLFSSL_IMX6_CAAM && !NO_AES */ + diff --git a/wolfcrypt/src/port/caam/caam_doc.pdf b/wolfcrypt/src/port/caam/caam_doc.pdf Binary files differnew file mode 100644 index 0000000..8213634 --- /dev/null +++ b/wolfcrypt/src/port/caam/caam_doc.pdf diff --git a/wolfcrypt/src/port/caam/caam_driver.c b/wolfcrypt/src/port/caam/caam_driver.c new file mode 100644 index 0000000..5d44f2d --- /dev/null +++ b/wolfcrypt/src/port/caam/caam_driver.c @@ -0,0 +1,1713 @@ +/* caam_driver.c + * + * Copyright (C) 2006-2020 wolfSSL Inc. + * + * This file is part of wolfSSL. + * + * wolfSSL is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * wolfSSL 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, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335, USA + */ + +#if defined(__INTEGRITY) || defined(INTEGRITY) + +/* build into Integrity kernel */ +#include <bsp.h> +#include "wolfssl/wolfcrypt/port/caam/caam_driver.h" + +#define CAAM_READ(reg) *(volatile unsigned int*)(reg) +#define CAAM_WRITE(reg, in) *(volatile unsigned int*)(reg) = (in); + +#define DESC_COUNT 1 +#define MAX_BUF 20 +#define BUFFER_COUNT (MAX_BUF * DESC_COUNT) + +/* CAAM descriptors can only be 64 unsigned ints */ +#define MAX_DESC_SZ 64 + +/* 64 byte buffer for when data crosses a page boundary */ +#define ALIGN_BUF 16 + +/* MAX_CTX is 64 bytes (sha512 digest) + 8 bytes (CAAM length value) */ +#define MAX_CTX 18 + +#define MIN_READ_REG 0xF2100000 +#define MAX_READ_REG 0XF2110000 + +struct JobRing { + Address JobIn; + Address JobOut; + Address Desc; + Value page; /* page allocation for descriptor to use */ +}; + +struct buffer { + Address data; + Address dataSz; +}; + +/* CAAM descriptor */ +struct DescStruct { + struct IORequestStruct TheIORequest; + struct CAAM_DEVICE* caam; + struct buffer buf[MAX_BUF]; /* buffers holding data input address */ + UINT4 desc[MAX_DESC_SZ]; /* max size of 64 word32 */ + UINT4 aadSzBuf[4]; /* Formatted AAD size for CCM */ + UINT4 alignBuf[ALIGN_BUF]; /* 64 byte buffer for non page + align */ + UINT4 iv[MAX_CTX]; /* AES IV and also hash state */ + UINT4 ctxBuf[MAX_CTX]; /* key */ + Address output; /* address to output buffer */ + Address ctxOut; /* address to update buffer holding state */ + Value alignIdx;/* index for align buffer */ + Value idx; /* index for descriptor buffer */ + Value headIdx; /* for first portion of descriptor buffer */ + Value lastIdx; /* for last portion of descriptor buffer */ + Value outputIdx; /* idx to output buffer in "buf" */ + Value inputSz; /* size of input buffer */ + Value ctxSz; /* size of CTX/Key buffer */ + Value aadSz; /* AAD size for CCM */ + Value lastFifo; + Value type; + Value state; + Value DescriptorCount; + Boolean running; /* True if building/running descriptor is + in process */ +}; + +struct CAAM_DEVICE { + struct IODeviceVectorStruct caamVector; + struct IODescriptorStruct IODescriptorArray[BUFFER_COUNT]; + struct DescStruct DescArray[DESC_COUNT]; + volatile Value InterruptStatus; + CALL HandleInterruptCall; + struct JobRing ring; +}; + +#define DRIVER_NAME "wolfSSL_CAAM_Driver" + +static struct CAAM_DEVICE caam; + +/****************************************************************************** + Internal CAAM Job Ring and partition functions + ****************************************************************************/ + +/* flush job ring and reset */ +static Error caamReset(void) +{ + int t = 100000; /* time out counter for flushing job ring */ + + /* make sure interrupts are masked in JRCFGR0_LS register */ + CAAM_WRITE(CAAM_BASE | 0x1054, CAAM_READ(CAAM_BASE | 0x1054) | 1); + + /* flush and reset job rings using JRCR0 register */ + CAAM_WRITE(CAAM_BASE | 0x106C, 1); + + /* check register JRINTR for if halt is in progress */ + while (t > 0 && ((CAAM_READ(CAAM_BASE | 0x104C) & 0x4) == 0x4)) t--; + if (t == 0) { + /*unrecoverable failure, the job ring is locked, up hard reset needed*/ + return NotRestartable; + } + + /* now that flush has been done restart the job ring */ + t = 100000; + CAAM_WRITE(CAAM_BASE | 0x106C, 1); + while (t > 0 && ((CAAM_READ(CAAM_BASE | 0x106C) & 1) == 1)) t--; + if (t == 0) { + /*unrecoverable failure, reset bit did not return to 0 */ + return NotRestartable; + } + + /* reset most registers and state machines in CAAM using MCFGR register + also reset DMA */ + CAAM_WRITE(CAAM_BASE | 0x0004, 0x90000000); + + return Success; +} + +/* returns MemoryMapMayNotBeEmpty if page/par is already owned + * returns Success on success + * all other returns is an error state + */ +static Error caamCreatePartition(unsigned char page, unsigned char par) +{ + /* check ownership of partition */ + if ((CAAM_READ(CAAM_BASE | 0x1FBC) & (0x3 << (par * 2))) > 0) { + return MemoryMapMayNotBeEmpty; + } + + /* set generic all access permissions, gets reset later */ + CAAM_WRITE(CAAM_BASE | (0x1108 + (par * 16)), 0xF); + CAAM_WRITE(CAAM_BASE | (0x110C + (par * 16)), 0xF); + CAAM_WRITE(CAAM_BASE | (0x1104 + (par * 16)), 0xFF); + + /* check ownership of page */ + CAAM_WRITE(CAAM_BASE | 0x10F4, (page << 16) | 0x5); + /* wait for inquiry cmd to complete */ + while ((CAAM_READ(CAAM_BASE | 0x10FC) & 0x0000C000) > 0 && + (CAAM_READ(CAAM_BASE | 0x10FC) & 0x00003000) == 0) { + } + if ((CAAM_READ(CAAM_BASE | 0x10FC) & 0x000000C0) == 0xC0) { + /* owns the page can dealloc it */ + CAAM_WRITE(CAAM_BASE | 0x10F4, (page << 16) | 0x2); + while ((CAAM_READ(CAAM_BASE | 0x10FC) & 0x0000C000) > 0 && + (CAAM_READ(CAAM_BASE | 0x10FC) & 0x00003000) == 0) {} + if ((CAAM_READ(CAAM_BASE | 0x10FC) & 0x00003000) > 0) { + /* error while deallocating page */ + return MemoryMapMayNotBeEmpty; /* PSP set on page or is unavailable */ + } + } + else { + /* check if owned by someone else */ + if ((CAAM_READ(CAAM_BASE | 0x10FC) & 0x000000C0) != 0) { + return MemoryMapMayNotBeEmpty; + } + } + + /* allocate page to partition */ + CAAM_WRITE(CAAM_BASE | 0x10F4, (page << 16) | (par << 8) | 0x1); + /* wait for alloc cmd to complete */ + while ((CAAM_READ(CAAM_BASE | 0x10FC) & 0x0000C000) > 0 && + (CAAM_READ(CAAM_BASE | 0x10FC) & 0x00003000) == 0) { + } + + if ((CAAM_READ(CAAM_BASE | 0x10FC) & 0x00003000) > 0) { + return MemoryOperationNotPerformed; + } + + /* double check ownership now of page */ + CAAM_WRITE(CAAM_BASE | 0x10F4, (page << 16) | 0x5); + /* wait for inquiry cmd to complete */ + while ((CAAM_READ(CAAM_BASE | 0x10FC) & 0x0000C000) > 0 && + (CAAM_READ(CAAM_BASE | 0x10FC) & 0x00003000) == 0) { + } + if ((CAAM_READ(CAAM_BASE | 0x10FC) & 0x0000000F) == 0 || + (CAAM_READ(CAAM_BASE | 0x10FC) & 0x00003000) > 0) { + /* page not owned */ + return MemoryOperationNotPerformed; + } + + return Success; +} + + +/* Gets the status of a job. Returns Waiting if no output jobs ready to be + * read. + * If no jobs are done then return Waiting + * If jobs are done but does not match desc then return NoActivityReady + * Status holds the error values if any */ +static Error caamGetJob(struct CAAM_DEVICE* dev, UINT4* status) +{ + UINT4 reg = CAAM_READ(CAAM_BASE | 0x1044); /* JRSTAR0 status */ + if (status) { + *status = 0; + } + + /* check for DECO, CCB, and Job Ring error state JRSTAR0 register */ + if (((reg & 0xF0000000) == 0x20000000) || /* CCB error */ + ((reg & 0xF0000000) == 0x40000000)|| /* DECO error */ + ((reg & 0xF0000000) == 0x60000000)) { /* Job Ring error */ + + if ((reg & 0x0000000F) > 0) { + *status = reg; + return Failure; + } + } + + /* Check number of done jobs in output list */ + reg = CAAM_READ(CAAM_BASE | 0x103C); + if ((reg & 0x000003FF) > 0) { + UINT4* out = (UINT4*)(dev->ring.JobOut); + if (status) { + *status = out[1]; + } + + if ((dev->ring.Desc ^ 0xF0000000) != out[0]) { + db_printf("CAAM job completed vs expected mismatch"); + return NoActivityReady; + } + + if (out[1] > 0) { + return Failure; + } + + /* increment jobs removed */ + CAAM_WRITE(CAAM_BASE | 0x1034, 1); + } + else { + /* check if the CAAM is idle and not processing any descriptors */ + if ((CAAM_READ(CAAM_BASE | 0x0FD4) & 0x00000002) == 2 /* idle */ + && (CAAM_READ(CAAM_BASE | 0x0FD4) & 0x00000001) == 0) { + return NoActivityReady; + } + + return Waiting; + } + + return Success; +} + + +/* Initialize CAAM RNG + * returns 0 on success */ +static int caamInitRng(struct CAAM_DEVICE* dev) +{ + UINT4 reg, status; + int ret = 0; + + /* Set up use of the TRNG for seeding wolfSSL HASH-DRBG */ + CAAM_WRITE(CAAM_RTMCTL, CAAM_PRGM); + CAAM_WRITE(CAAM_RTMCTL, CAAM_READ(CAAM_RTMCTL) | 0x40); /* reset */ + + /* Set up reading from TRNG */ + CAAM_WRITE(CAAM_RTMCTL, CAAM_READ(CAAM_RTMCTL) | CAAM_TRNG); + + /* Set up delay for TRNG @TODO Optimizations? + * Shift left with RTSDCTL because 0-15 is for sample number + * Also setting the max and min frequencies */ + CAAM_WRITE(CAAM_RTSDCTL, (CAAM_ENT_DLY << 16) | 0x09C4); + CAAM_WRITE(CAAM_RTFRQMIN, CAAM_ENT_DLY >> 1); /* 1/2 */ + CAAM_WRITE(CAAM_RTFRQMAX, CAAM_ENT_DLY << 3); /* up to 8x */ + + /* Set back to run mode and clear RTMCL error bit */ + reg = CAAM_READ(CAAM_RTMCTL) ^ CAAM_PRGM; + + CAAM_WRITE(CAAM_RTMCTL, reg); + reg = CAAM_READ(CAAM_RTMCTL); + reg |= CAAM_CTLERR; + CAAM_WRITE(CAAM_RTMCTL, reg); + + /* check input slot is available and then add */ + if (CAAM_READ(CAAM_BASE | 0x1014) > 0) { + UINT4* in = (UINT4*)dev->ring.JobIn; + + memcpy((unsigned char*)dev->ring.Desc, (unsigned char*)wc_rng_start, + sizeof(wc_rng_start)); + + in[0] = dev->ring.Desc ^ 0xF0000000; /* physical address */ + CAAM_WRITE(CAAM_IRJAR0, 0x00000001); + } + else { + return Waiting; + } + + do { + ret = caamGetJob(dev, &status); + /* @TODO use a better way to chill out CPU. */ + } while (ret == Waiting); + + return ret; +} + + +static Error caamDoJob(struct DescStruct* desc) +{ + Error ret; + UINT4 status; + + /* clear and set desc size */ + desc->desc[0] &= 0xFFFFFF80; + desc->desc[0] += desc->idx; + + /* check input slot is available and then add */ + if (CAAM_READ(CAAM_BASE | 0x1014) > 0) { + UINT4* in = (UINT4*)desc->caam->ring.JobIn; + + memcpy((unsigned char*)desc->caam->ring.Desc, (unsigned char*)desc->desc, + (desc->idx + 1) * sizeof(UINT4)); + + in[0] = desc->caam->ring.Desc ^ 0xF0000000; /* physical address */ + CAAM_WRITE(CAAM_IRJAR0, 0x00000001); + } + else { + return Waiting; + } + + do { + ret = caamGetJob(desc->caam, &status); + /* @TODO use a better way to chill out CPU. */ + } while (ret == Waiting); + + if (status != 0 || ret != Success) { + #if 0 + /* Used during testing to print out descriptor */ + { + char msg[2048]; + char* pt = msg; + int z; + + memset(msg, 0, sizeof(msg)); + for (z = 0; z < desc->idx; z++) { + snprintf(pt, sizeof(msg) - (z * 21), "desc[%d] = 0x%8.8x, ", + z, desc->desc[z]); + pt += 21; + } + snprintf(pt, sizeof(msg) - (z * 21), "status = 0x%8.8x\n", status); + if (desc->buf[0].data != 0) { /* for testing */ + memcpy((char*)desc->buf[0].data, msg, sizeof(msg)); + } + } + #endif + + + /* try to reset after error */ + caamReset(); + return ret; + } + + return Success; +} + + +/* handle input or output buffers + * NOTES: if sz == 0 then read all the rest of the buffers available + * when align == 1 then there is no alignment constraints + * + * returns the data size in bytes on success. With failure a negative value is + * returned. + */ +static int caamAddIO(struct DescStruct* desc, UINT4 options, UINT4 sz, + UINT4 align, UINT4* idx) +{ + int i, outSz = 0; + + if (align == 0) { + return -1; /* programming error */ + } + + for (i = *idx; i < desc->DescriptorCount; i++) { + /* input must be a multiple of "align" bytes */ + struct buffer* buf = &desc->buf[i]; + int blocks = buf->dataSz / align; + Address data = buf->data; + Address dataSz = buf->dataSz; + + if (outSz >= sz && sz != 0) { + break; + } + + if (dataSz % align > 0) { + /* store potential overlap */ + int tmpSz = dataSz % align; + int add = (tmpSz < (align - desc->alignIdx)) ? tmpSz : + align - desc->alignIdx; + unsigned char* local = (unsigned char*)desc->alignBuf; + + /* if already something in the buffer then add from front */ + if (desc->alignIdx > 0) { + memcpy((unsigned char*)&local[desc->alignIdx], + (unsigned char*)data, add); + data += add; + } + else { + memcpy((unsigned char*)&local[desc->alignIdx], + (unsigned char*)data + (blocks * align), add); + } + dataSz -= add; + desc->alignIdx += add; + } + + if (desc->alignIdx == align) { + desc->lastFifo = desc->idx; + if (desc->idx + 2 > MAX_DESC_SZ) { + return -1; + } + desc->desc[desc->idx++] = options + desc->alignIdx; + desc->desc[desc->idx++] = BSP_VirtualToPhysical(desc->alignBuf); + ASP_FlushCaches((Address)desc->alignBuf, desc->alignIdx); + outSz += desc->alignIdx; + } + + if (blocks > 0) { + desc->lastFifo = desc->idx; + if (desc->idx + 2 > MAX_DESC_SZ) { + return -1; + } + desc->desc[desc->idx++] = options + (blocks * align); + desc->desc[desc->idx++] = BSP_VirtualToPhysical(data); + outSz += (blocks * align); + + /* only one buffer available for align cases so exit here and make + a new descriptor after running current one */ + if (desc->alignIdx == align) { + desc->alignIdx = 0; + i++; /* start at next buffer */ + break; + } + } + } + + *idx = i; + return outSz; +} + + +/****************************************************************************** + IODevice Register Read and Write + ****************************************************************************/ + +static Error caamReadRegister(IODeviceVector ioCaam, Value reg, Value *out) +{ + if (reg < MIN_READ_REG || reg > MAX_READ_REG) { + return IllegalRegisterNumber; + } + + switch (reg) { + case CAAM_STATUS: + case CAAM_VERSION_MS: + case CAAM_VERSION_LS: + case CAMM_SUPPORT_MS: + case CAMM_SUPPORT_LS: + case CAAM_RTMCTL: + *out = CAAM_READ(reg); + break; + + default: + return IllegalRegisterNumber; + } + + (void)ioCaam; + return Success; +} + + +static Error caamWriteRegister(IODeviceVector ioCaam, Value reg, Value in) +{ + /* Should be no need for writes */ + return OperationNotAllowedOnTheUniversalIODevice; +} + + +/****************************************************************************** + CAAM Blob Operations + ****************************************************************************/ + +/* limit on size due to size of job ring being 64 word32's */ +static Error caamBlob(struct DescStruct* desc) +{ + Error err; + UINT4 keyType = 0x00000C08; /* default red */ + UINT4 i = 0; + int sz = 0, ret; + + if (desc->idx + 3 > MAX_DESC_SZ) { + return Failure; + } + + /*default to Red Key type, with offset of 12 and 8 byte load to context 2*/ + desc->desc[desc->idx++] = (CAAM_LOAD_CTX | CAAM_CLASS2 | CAAM_IMM | keyType); + + /* add key modifier */ + if (i < desc->DescriptorCount) { + UINT4* pt; + Address data = desc->buf[i].data; + Address dataSz = desc->buf[i].dataSz; + + pt = (UINT4*)data; + if (dataSz < 8) { /* expecting 8 bytes for key modifier*/ + return TooManyBuffers; + } + desc->desc[desc->idx++] = pt[0]; + desc->desc[desc->idx++] = pt[1]; + } + + /* add input */ + while (sz < desc->inputSz && i < desc->DescriptorCount) { + ret = caamAddIO(desc, CAAM_SEQI, desc->inputSz - sz, 1, &i); + if (ret < 0) { /* handle error case */ + return TooManyBuffers; + } + sz += ret; + } + desc->outputIdx = i; + + /* add output */ + if (caamAddIO(desc, CAAM_SEQO, 0, 1, &i) < 0) { + return TooManyBuffers; + } + + if (desc->idx + 1 > MAX_DESC_SZ) { + return Failure; + } + desc->desc[desc->idx++] = CAAM_OP | CAAM_OPID_BLOB | desc->type; + + if ((err = caamDoJob(desc)) != Success) { + return err; + } + + /* flush output buffers */ + for (i = desc->outputIdx; i < desc->DescriptorCount; i++) { + ASP_FlushCaches(desc->buf[i].data, desc->buf[i].dataSz); + } + + return Success; +} + + +/****************************************************************************** + CAAM AES Operations + ****************************************************************************/ + +/* returns amount written on success and negative value in error case. + * Is different from caamAddIO in that it only adds a single input buffer + * rather than multiple ones. + */ +static int caamAesInput(struct DescStruct* desc, UINT4* idx, int align, + UINT4 totalSz) +{ + int sz; + UINT4 i = *idx; + + /* handle alignment constraints on input */ + if (desc->alignIdx > 0) { + sz = desc->alignIdx; + + /* if there is more input buffers then add part of it */ + if (i < desc->outputIdx && i < desc->DescriptorCount) { + sz = align - desc->alignIdx; + sz = (sz <= desc->buf[i].dataSz) ? sz : desc->buf[i].dataSz; + memcpy((unsigned char*)(desc->alignBuf) + desc->alignIdx, + (unsigned char*)(desc->buf[i].data), sz); + + desc->buf[i].dataSz -= sz; + desc->buf[i].data += sz; + sz += desc->alignIdx; + } + + if (desc->idx + 2 > MAX_DESC_SZ) { + return -1; + } + ASP_FlushCaches((Address)desc->alignBuf, sz); + desc->desc[desc->idx++] = (CAAM_FIFO_L | FIFOL_TYPE_LC1 | + CAAM_CLASS1 | FIFOL_TYPE_MSG) + sz; + desc->desc[desc->idx++] = BSP_VirtualToPhysical(desc->alignBuf); + desc->alignIdx = 0; + } + else { + sz = desc->buf[i].dataSz; + if ((totalSz + sz) == desc->inputSz) { /* not an issue on final */ + align = 1; + } + + desc->alignIdx = sz % align; + if (desc->alignIdx != 0) { + sz -= desc->alignIdx; + memcpy((unsigned char*)desc->alignBuf, + (unsigned char*)(desc->buf[i].data) + sz, + desc->alignIdx); + } + + if (desc->idx + 2 > MAX_DESC_SZ) { + return -1; + } + desc->desc[desc->idx++] = (CAAM_FIFO_L | FIFOL_TYPE_LC1 | + CAAM_CLASS1 | FIFOL_TYPE_MSG) + sz; + desc->desc[desc->idx++] = BSP_VirtualToPhysical(desc->buf[i].data); + i++; + } + + *idx = i; + return sz; +} + + +/* returns enum Success on success, all other return values should be + * considered an error. + * + * ofst is the amount of leftover buffer from previous calls + * inputSz is the amount of input in bytes that is being matched to output + */ +static Error caamAesOutput(struct DescStruct* desc, int* ofst, UINT4 inputSz) +{ + int offset = *ofst; + + if (desc->output != 0 && offset > 0 && inputSz > 0) { + UINT4 addSz; + + /* handle potential leftovers */ + addSz = (inputSz >= offset) ? offset : inputSz; + + inputSz -= addSz; + desc->desc[desc->idx++] = CAAM_FIFO_S | FIFOS_TYPE_MSG + addSz; + if (inputSz > 0) { /* check if expecting more output */ + desc->desc[desc->idx - 1] |= CAAM_FIFOS_CONT; + } + desc->desc[desc->idx++] = BSP_VirtualToPhysical(desc->output); + + if (addSz == offset) { + /* reset */ + desc->output = 0; + offset = 0; + } + else { + offset -= addSz; + desc->output += addSz; + + if (offset < 0) { + return TransferFailed; + } + } + } + + for (; desc->lastIdx < desc->DescriptorCount; desc->lastIdx++) { + struct buffer* buf = &desc->buf[desc->lastIdx]; + + if (inputSz > 0) { + int tmp; + + if (buf->dataSz <= inputSz) { + tmp = buf->dataSz; + } + else { + offset = buf->dataSz - inputSz; + tmp = inputSz; + desc->output = buf->data + tmp; + } + inputSz -= tmp; + if (desc->idx + 2 > MAX_DESC_SZ) { + return TransferFailed; + } + desc->desc[desc->idx++] = CAAM_FIFO_S | FIFOS_TYPE_MSG + tmp; + if (inputSz > 0) { /* check if expecting more output */ + desc->desc[desc->idx - 1] |= CAAM_FIFOS_CONT; + } + desc->desc[desc->idx++] = BSP_VirtualToPhysical(buf->data); + } + else { + break; + } + } + + *ofst = offset; + return Success; +} + + +/* check size of output and get starting buffer for it */ +static Error caamAesOutSz(struct DescStruct* desc, UINT4 i) +{ + int sz = 0; + + for (desc->outputIdx = i; desc->outputIdx < desc->DescriptorCount && + sz < desc->inputSz; desc->outputIdx++) { + sz += desc->buf[desc->outputIdx].dataSz; + } + desc->lastIdx = desc->outputIdx; + + /* make certain that output size is same as input */ + sz = 0; + for (; desc->lastIdx < desc->DescriptorCount; desc->lastIdx++) { + sz += desc->buf[desc->lastIdx].dataSz; + } + if (sz != desc->inputSz) { + return SizeIsTooLarge; + } + desc->lastIdx = desc->outputIdx; + + return Success; +} + + +/* AES operations follow the buffer sequence of KEY -> (IV) -> Input -> Output + */ +static Error caamAes(struct DescStruct* desc) +{ + struct buffer* ctx[3]; + struct buffer* iv[3]; + Value ofst = 0; + Error err; + UINT4 i, totalSz = 0; + int ctxIdx = 0; + int ivIdx = 0; + int offset = 0; + int align = 1; + int sz = 0; + + int ctxSz = desc->ctxSz; + + if (desc->state != CAAM_ENC && desc->state != CAAM_DEC) { + return IllegalStatusNumber; + } + + if (ctxSz != 16 && ctxSz != 24 && ctxSz != 32) { + return ArgumentError; + } + + /* get key */ + for (i = 0; i < desc->DescriptorCount; i++) { + struct buffer* buf = &desc->buf[i]; + unsigned char* local = (unsigned char*)desc->ctxBuf; + + if (sz < ctxSz && sz < (MAX_CTX * sizeof(UINT4))) { + ctx[ctxIdx] = buf; + sz += buf->dataSz; + + memcpy((unsigned char*)&local[offset], + (unsigned char*)ctx[ctxIdx]->data, ctx[ctxIdx]->dataSz); + offset += ctx[ctxIdx]->dataSz; + ctxIdx++; + } + else { + break; + } + } + + /* sanity checks on size of key */ + if (sz > ctxSz) { + return SizeIsTooLarge; + } + if (ctxSz > (MAX_CTX * sizeof(UINT4)) - 16) { + return ArgumentError; + } + + /* Flush cache of ctx buffer then : + Add KEY Load command 0x0220000X + Add address to read key from 0xXXXXXXXX */ + ASP_FlushCaches((Address)desc->ctxBuf, ctxSz); + if (desc->idx + 2 > MAX_DESC_SZ) { + return TransferFailed; + } + desc->desc[desc->idx++] = (CAAM_KEY | CAAM_CLASS1 | CAAM_NWB) + ctxSz; + desc->desc[desc->idx++] = BSP_VirtualToPhysical(desc->ctxBuf); + + /* get IV if needed by algorithm */ + switch (desc->type) { + case CAAM_AESECB: + break; + + case CAAM_AESCTR: + ofst = 0x00001000; + /* fall through because states are the same only the offset changes */ + + case CAAM_AESCBC: + { + int maxSz = 16; /* default to CBC/CTR max size */ + + sz = 0; + offset = 0; + for (; i < desc->DescriptorCount; i++) { + struct buffer* buf = &desc->buf[i]; + unsigned char* local = (unsigned char*)desc->iv; + + if (sz < maxSz) { + iv[ivIdx] = buf; + + if (buf->dataSz + sz > maxSz) { + return SizeIsTooLarge; + } + + sz += buf->dataSz; + memcpy((unsigned char*)&local[offset], + (unsigned char*)iv[ivIdx]->data, iv[ivIdx]->dataSz); + offset += iv[ivIdx]->dataSz; + ivIdx++; + } + else { + break; + } + } + + if (sz != maxSz) { + /* invalid IV size */ + return SizeIsTooLarge; + } + + ASP_FlushCaches((Address)desc->iv, maxSz); + if (desc->idx + 2 > MAX_DESC_SZ) { + return TransferFailed; + } + desc->desc[desc->idx++] = (CAAM_LOAD_CTX | CAAM_CLASS1 | ofst) + maxSz; + desc->desc[desc->idx++] = BSP_VirtualToPhysical(desc->iv); + } + break; + + default: + return OperationNotImplemented; + } + + /* write operation */ + if (desc->idx + 1 > MAX_DESC_SZ) { + return TransferFailed; + } + desc->desc[desc->idx++] = CAAM_OP | CAAM_CLASS1 | desc->type | + CAAM_ALG_UPDATE | desc->state; + + /* find output buffers */ + if (caamAesOutSz(desc, i) != Success) { + return SizeIsTooLarge; + } + + /* set alignment constraints */ + if (desc->type == CAAM_AESCBC || desc->type == CAAM_AESECB) { + align = 16; + } + + /* indefinite loop for input/output buffers */ + desc->headIdx = desc->idx; + desc->output = 0; + offset = 0; /* store left over amount for output buffer */ + do { + desc->idx = desc->headIdx; /* reset for each loop */ + + /* add a single input buffer (multiple ones was giving deco watch dog + * time out errors on the FIFO load of 1c. + * @TODO this could be a place for optimization if more data could be + * loaded in at one time */ + if ((sz = caamAesInput(desc, &i, align, totalSz)) < 0) { + return TransferFailed; + } + totalSz += sz; + + if (caamAesOutput(desc, &offset, sz) != Success) { + return TransferFailed; + } + + /* store updated IV */ + if (ivIdx > 0) { + if (desc->idx + 2 > MAX_DESC_SZ) { + return TransferFailed; + } + desc->desc[desc->idx++] = CAAM_STORE_CTX | CAAM_CLASS1 | ofst | 16; + desc->desc[desc->idx++] = BSP_VirtualToPhysical((Address)desc->iv); + } + + if ((err = caamDoJob(desc)) != Success) { + return err; + } + ASP_FlushCaches((Address)desc->iv, 16); + } while (desc->lastIdx < desc->DescriptorCount || offset > 0); + + /* flush output buffers */ + for (i = desc->outputIdx; i < desc->lastIdx; i++) { + ASP_FlushCaches(desc->buf[i].data, desc->buf[i].dataSz); + } + + /* handle case with IV */ + if (ivIdx > 0) { + unsigned char* pt = (unsigned char*)desc->iv; + ASP_FlushCaches((Address)pt, 16); + for (i = 0; i < ivIdx; i++) { + memcpy((unsigned char*)iv[i]->data, pt, iv[i]->dataSz); + pt += iv[i]->dataSz; + ASP_FlushCaches(iv[i]->data, iv[i]->dataSz); + } + } + + return Success; +} + + +/****************************************************************************** + CAAM AEAD Operations + ****************************************************************************/ + +/* AEAD operations follow the buffer sequence of KEY -> (IV or B0 | CTR0) -> (AD) + * -> Input -> Output + * + */ +static Error caamAead(struct DescStruct* desc) +{ + struct buffer* ctx[3]; + struct buffer* iv[3]; + Value ofst = 0; + UINT4 state = CAAM_ALG_INIT; + UINT4 totalSz = 0; + Error err; + UINT4 i; + int ctxIdx = 0; + int ivIdx = 0; + int offset = 0; + int sz = 0; + int ivSz = 32; /* size of B0 | CTR0 for CCM mode */ + int ctxSz = desc->ctxSz; + int align = 16; /* input should be multiples of 16 bytes unless is final */ + int opIdx; + + if (desc->state != CAAM_ENC && desc->state != CAAM_DEC) { + return IllegalStatusNumber; + } + + /* sanity check is valid AES key size */ + if (ctxSz != 16 && ctxSz != 24 && ctxSz != 32) { + return ArgumentError; + } + + /* get key */ + for (i = 0; i < desc->DescriptorCount; i++) { + struct buffer* buf = &desc->buf[i]; + unsigned char* local = (unsigned char*)desc->ctxBuf; + + if (sz < ctxSz && sz < (MAX_CTX * sizeof(UINT4))) { + ctx[ctxIdx] = buf; + sz += buf->dataSz; + + memcpy((unsigned char*)&local[offset], + (unsigned char*)ctx[ctxIdx]->data, ctx[ctxIdx]->dataSz); + offset += ctx[ctxIdx]->dataSz; + ctxIdx++; + } + else { + break; + } + } + + /* sanity checks on size of key */ + if (sz > ctxSz) { + return SizeIsTooLarge; + } + + /* Flush cache of ctx buffer then : + Add KEY Load command 0x0220000X + Add address to read key from 0xXXXXXXXX */ + ASP_FlushCaches((Address)desc->ctxBuf, ctxSz); + if (desc->idx + 2 > MAX_DESC_SZ) { + return TransferFailed; + } + desc->desc[desc->idx++] = (CAAM_KEY | CAAM_CLASS1 | CAAM_NWB) + ctxSz; + desc->desc[desc->idx++] = BSP_VirtualToPhysical(desc->ctxBuf); + + desc->headIdx = desc->idx; + desc->output = 0; + offset = 0; /* store left over amount for output buffer */ + do { + desc->idx = desc->headIdx; /* reset for each loop */ + + /* write operation */ + if (desc->idx + 1 > MAX_DESC_SZ) { + return TransferFailed; + } + opIdx = desc->idx; + desc->desc[desc->idx++] = CAAM_OP | CAAM_CLASS1 | state | desc->type | + desc->state; + + /* get IV if needed by algorithm */ + switch (desc->type) { + case CAAM_AESCCM: + if ((state & CAAM_ALG_INIT) == CAAM_ALG_INIT) { + sz = 0; + offset = 0; + for (; i < desc->DescriptorCount; i++) { + struct buffer* buf = &desc->buf[i]; + unsigned char* local = (unsigned char*)desc->iv; + + if (sz < ivSz) { + iv[ivIdx] = buf; + + if (buf->dataSz + sz > ivSz) { + return SizeIsTooLarge; + } + + sz += buf->dataSz; + memcpy((unsigned char*)&local[offset], + (unsigned char*)iv[ivIdx]->data, iv[ivIdx]->dataSz); + offset += iv[ivIdx]->dataSz; + ivIdx++; + } + else { + break; + } + } + + if (sz != ivSz) { + /* invalid IV size */ + return SizeIsTooLarge; + } + offset = 0; + } + + ASP_FlushCaches((Address)desc->iv, ivSz); + if (desc->idx + 2 > MAX_DESC_SZ) { + return TransferFailed; + } + desc->desc[desc->idx++] = (CAAM_LOAD_CTX | CAAM_CLASS1 | ofst) + + ivSz; + desc->desc[desc->idx++] = BSP_VirtualToPhysical(desc->iv); + break; + + default: + return OperationNotImplemented; + } + + + /********* handle AAD -- is only done with Init **********************/ + if ((state & CAAM_ALG_INIT) == CAAM_ALG_INIT) { + if ((desc->type == CAAM_AESCCM) && (desc->aadSz > 0)) { + /* set formatted AAD buffer size for CCM */ + ASP_FlushCaches((Address)desc->aadSzBuf, sizeof(desc->aadSzBuf)); + desc->desc[desc->idx++] = CAAM_FIFO_L | CAAM_CLASS1 | + FIFOL_TYPE_AAD + desc->aadSz; + desc->desc[desc->idx++] = BSP_VirtualToPhysical(desc->aadSzBuf); + + /* now set aadSz to unformatted version for getting buffers */ + if (desc->aadSz == 2) { + unsigned char* pt = (unsigned char*)desc->aadSzBuf; + desc->aadSz = (((UINT4)pt[0] & 0xFF) << 8) | + ((UINT4)pt[1] & 0xFF); + } + else { + unsigned char* pt = (unsigned char*)desc->aadSzBuf; + desc->aadSz = (((UINT4)pt[2] & 0xFF) << 24) | + (((UINT4)pt[3] & 0xFF) << 16) | + (((UINT4)pt[4] & 0xFF) << 8) | + ((UINT4)pt[5] & 0xFF); + } + } + + /* get additional data buffers */ + if (desc->aadSz > 0) { + sz = 0; + for (; i < desc->DescriptorCount; i++) { + struct buffer* buf = &desc->buf[i]; + if (sz < desc->aadSz) { + if (desc->idx + 2 > MAX_DESC_SZ) { + return TransferFailed; + } + desc->lastFifo = desc->idx; + desc->desc[desc->idx++] = CAAM_FIFO_L | CAAM_CLASS1 | + FIFOL_TYPE_AAD + buf->dataSz; + desc->desc[desc->idx++] = BSP_VirtualToPhysical(buf->data); + sz += buf->dataSz; + } + else { + break; + } + } + + /* flush AAD from FIFO and pad it to 16 byte block */ + desc->desc[desc->lastFifo] |= FIFOL_TYPE_FC1; + } + + /* find output buffers */ + if (caamAesOutSz(desc, i) != Success) { + return SizeIsTooLarge; + } + } + + /* handle alignment constraints on input */ + if ((sz = caamAesInput(desc, &i, align, totalSz)) < 0) { + return TransferFailed; + } + totalSz += sz; + + /* handle output buffers */ + if (caamAesOutput(desc, &offset, sz) != Success) { + return TransferFailed; + } + + /* store updated IV, if is last then set offset and final for MAC */ + if ((desc->lastIdx == desc->DescriptorCount) && (offset == 0)) { + ivSz = 16; + if (desc->state == CAAM_ENC) { + ofst = 32 << 8; /* offset is in 15-8 bits */ + } + else { + ofst = 0; + } + desc->desc[opIdx] |= CAAM_ALG_FINAL; + } + else { + /* if not final then store and use ctr and encrypted ctr from + context dword 2,3 and 4,5. Also store MAC and AAD info from + context dword 6. */ + ivSz = 56; + ofst = 0; + } + + if (desc->idx + 2 > MAX_DESC_SZ) { + return TransferFailed; + } + desc->desc[desc->idx++] = CAAM_STORE_CTX | CAAM_CLASS1 | ofst | ivSz; + desc->desc[desc->idx++] = BSP_VirtualToPhysical((Address)desc->iv); + + if ((err = caamDoJob(desc)) != Success) { + return err; + } + state = CAAM_ALG_UPDATE; + } while (desc->lastIdx < desc->DescriptorCount || offset > 0); + + /* flush output buffers */ + for (i = desc->outputIdx; i < desc->lastIdx; i++) { + ASP_FlushCaches(desc->buf[i].data, desc->buf[i].dataSz); + } + + /* handle case with IV (This is also the output of MAC with AES-CCM) */ + if (ivIdx > 0) { + unsigned char* pt = (unsigned char*)desc->iv; + ASP_FlushCaches((Address)pt, ivSz); + for (i = 0; i < ivIdx; i++) { + memcpy((unsigned char*)iv[i]->data, pt, iv[i]->dataSz); + pt += iv[i]->dataSz; + ASP_FlushCaches(iv[i]->data, iv[i]->dataSz); + } + } + + return Success; +} + + +/****************************************************************************** + CAAM SHA Operations + ****************************************************************************/ +static int shaSize(struct DescStruct* desc) +{ + /* sanity check on dataSz for context */ + switch (desc->type) { + case CAAM_MD5: + return CAAM_MD5_CTXSZ; + + case CAAM_SHA: + return CAAM_SHA_CTXSZ; + + case CAAM_SHA224: + return CAAM_SHA224_CTXSZ; + + case CAAM_SHA256: + return CAAM_SHA256_CTXSZ; + + case CAAM_SHA384: + return CAAM_SHA384_CTXSZ; + + case CAAM_SHA512: + return CAAM_SHA512_CTXSZ; + + default: + return 0; + } +} + +/* SHA operations + * start: the index to start traversing through buffers. It's needed to allow + * for HMAC to reuse this code. + * + * return Success on success. All other return values are considered a fail + * case. + */ +static Error caamSha(struct DescStruct* desc, int start) +{ + struct buffer* ctx[3]; + Error err; + UINT4 i; + int sz = 0; + int ctxIdx = 0; + int offset = 0; + + int ctxSz = shaSize(desc); + + /* get context */ + for (i = start; i < desc->DescriptorCount; i++) { + struct buffer* buf = &desc->buf[i]; + unsigned char* local = (unsigned char*)desc->iv; + + if (sz < ctxSz && sz < (MAX_CTX * sizeof(UINT4))) { + ctx[ctxIdx] = buf; + sz += buf->dataSz; + + if (ctx[ctxIdx]->dataSz + offset > (MAX_CTX * sizeof(UINT4))) { + return SizeIsTooLarge; + } + memcpy((unsigned char*)&local[offset], (unsigned char*)ctx[ctxIdx]->data, + ctx[ctxIdx]->dataSz); + offset += ctx[ctxIdx]->dataSz; + ctxIdx++; + } + else { + break; + } + } + if (sz > ctxSz || ctxSz > (MAX_CTX * sizeof(UINT4))) { + return SizeIsTooLarge; + } + + ASP_FlushCaches((Address)desc->iv, ctxSz); + /*Manage Context (current digest + 8 byte running message length)*/ + if ((desc->state & CAAM_ALG_INIT) != CAAM_ALG_INIT) { + /* don't load into the class 2 context register on inti. + Found that loading in caused context to not get set. */ + if (desc->idx + 2 > MAX_DESC_SZ) { + return TransferFailed; + } + desc->desc[desc->idx++] = (CAAM_LOAD_CTX | CAAM_CLASS2) + ctxSz; + desc->desc[desc->idx++] = BSP_VirtualToPhysical((Address)desc->iv); + } + + /* add operation command */ + desc->desc[desc->idx++] = CAAM_OP | CAAM_CLASS2 | desc->state | + desc->type; + + /* Check case where there is no input. + In all cases the FIFO Load should be flushed. */ + if (i == desc->DescriptorCount) { + desc->lastFifo = desc->idx; + if (desc->idx + 1 > MAX_DESC_SZ) { + return TransferFailed; + } + desc->desc[desc->idx++] = CAAM_FIFO_L | CAAM_CLASS2 | + FIFOL_TYPE_MSG | CAAM_IMM; + } + + /* save index for looping over input */ + desc->headIdx = desc->idx; + do { + desc->idx = desc->headIdx; /* reset for each loop */ + if (i < desc->DescriptorCount) { + /* input must be a multiple of 64 bytes unless in final call */ + if (((desc->state & CAAM_ALG_FINAL) == CAAM_ALG_FINAL)) { + if (caamAddIO(desc, (CAAM_FIFO_L | CAAM_CLASS2 | + FIFOL_TYPE_MSG), 0, 1, &i) < 0) { + return TooManyBuffers; + } + } + else { + if (caamAddIO(desc, (CAAM_FIFO_L | CAAM_CLASS2 | + FIFOL_TYPE_MSG), 0, 64, &i) < 0) { + return TooManyBuffers; + } + } + } + + desc->desc[desc->lastFifo] |= FIFOL_TYPE_LC2; + + /* set context out */ + if (desc->idx + 2 > MAX_DESC_SZ) { + return TransferFailed; + } + desc->desc[desc->idx++] = CAAM_STORE_CTX | CAAM_CLASS2 + ctxSz; + desc->desc[desc->idx++] = BSP_VirtualToPhysical(desc->iv); + + if ((err = caamDoJob(desc)) != Success) { + return err; + } + /* flush context output for each loop */ + ASP_FlushCaches((Address)desc->iv, ctxSz); + } while (i < desc->DescriptorCount); + + /* store context to buffers */ + { + unsigned char* pt = (unsigned char*)desc->iv; + for (i = 0; i < ctxIdx; i++) { + memcpy((unsigned char*)ctx[i]->data, pt, ctx[i]->dataSz); + pt += ctx[i]->dataSz; + ASP_FlushCaches(ctx[i]->data, ctx[i]->dataSz); + } + } + + return Success; +} + + +/****************************************************************************** + CAAM TRNG Operations + ****************************************************************************/ + +/* If Entropy is not ready then return Waiting */ +static Error caamRng(struct DescStruct* desc) +{ + int sz = 0; + int i; + + Address reg; /* RTENT reg to read */ + int ofst = sizeof(UINT4); + + + /* Check ENT_VAL bit to make sure entropy is ready */ + if ((CAAM_READ(CAAM_RTMCTL) & CAAM_ENTVAL) != + CAAM_ENTVAL) { + return Waiting; + } + + /* check state of TRNG */ + if ((CAAM_READ(CAAM_RTSTATUS) & 0x0000FFFF) > 0) { + return Failure; + } + + /* read entropy from RTENT registers */ + reg = CAAM_RTENT0; + + for (i = 0; i < desc->DescriptorCount; i++) { + struct buffer* buf = &desc->buf[i]; + unsigned char* local = (unsigned char*)buf->data; + sz = buf->dataSz; + + while (sz > 3 && reg <= CAAM_RTENT11) { + *((UINT4*)local) = CAAM_READ(reg); + reg += ofst; + local += ofst; + sz -= ofst; + } + + if (reg > CAAM_RTENT11 && sz > 0) { + return SizeIsTooLarge; + } + + /* handle non word32 size amount left over */ + if (sz > 0) { + UINT4 tmp = CAAM_READ(reg); + memcpy(local, (unsigned char*)&tmp, sz); + } + + ASP_FlushCaches(buf->data, buf->dataSz); + } + + + /* read RTENT11 to trigger new entropy generation */ + if (reg != CAAM_RTENT11) { + CAAM_READ(CAAM_RTENT11); + } + + return Success; +} + + +/****************************************************************************** + IODevice Start, Transfer and Finish Buffer + ****************************************************************************/ +/* args[0] holds the state such as encrypt/decrypt or init/update/final + * args[1] holds the ctx/key size + * args[2] holds the input size + * args[3] dependent on algo (such as AAD size with AES-CCM) */ +static Error caamTransferStart(IODeviceVector ioCaam, + Value type, const volatile Value args[4]) +{ + struct CAAM_DEVICE* local = (struct CAAM_DEVICE*)ioCaam; + struct DescStruct* desc; + + /* currently only one desc is available for use */ + desc = &local->DescArray[0]; + + /* check if the desc is idle before using */ + if (GetIORequestStatus((IORequest)desc) != IdleIORequest) { + return ResourceNotAvailable; + } + + desc->idx = 0; + desc->output = 0; + desc->ctxOut = 0; + desc->outputIdx = 0; + desc->alignIdx = 0; + desc->lastFifo = 0; + desc->state = args[0]; + desc->ctxSz = args[1]; + desc->inputSz = args[2]; + desc->aadSz = 0; + desc->desc[desc->idx++] = CAAM_HEAD; /* later will put size to header*/ + + switch (type) { + case CAAM_AESECB: + case CAAM_AESCBC: + if (desc->inputSz % 16 != 0) { + return ArgumentError; + } + /* fall through to break */ + case CAAM_AESCTR: + break; + + case CAAM_AESCCM: + memset((unsigned char*)desc->aadSzBuf, 0, sizeof(desc->aadSzBuf)); + if (args[3] > 0) { + /* encode the length in */ + if (args[3] <= 0xFEFF) { + unsigned char* pt = (unsigned char*)desc->aadSzBuf; + desc->aadSz = 2; + pt[0] = ((args[3] & 0xFF00) >> 8); + pt[1] = (args[3] & 0x00FF); + } + else if (args[3] <= 0xFFFFFFFF) { + unsigned char* pt = (unsigned char*)desc->aadSzBuf; + desc->aadSz = 6; + pt[0] = 0xFF; pt[1] = 0xFE; + pt[2] = ((args[3] & 0xFF000000) >> 24); + pt[3] = ((args[3] & 0x00FF0000) >> 16); + pt[4] = ((args[3] & 0x0000FF00) >> 8); + pt[5] = (args[3] & 0x000000FF); + } + } + break; + + case CAAM_MD5: + case CAAM_SHA: + case CAAM_SHA224: + case CAAM_SHA256: + case CAAM_SHA384: + case CAAM_SHA512: + break; + + case CAAM_BLOB_ENCAP: + case CAAM_BLOB_DECAP: + break; + + case CAAM_ENTROPY: + break; + + default: + /* unknown type */ + return UsageNotSupported; + } + + desc->DescriptorCount = 0; + desc->type = type; + desc->running = true; + StartIORequest((IORequest)desc); + + /* For now only require READ permissions */ + SetIORequestBufferPermissions((IORequest)desc, MEMORY_READ); + return Success; +} + + +static Error caamTransferBuffer(IODeviceVector TheIODeviceVector, + IORequest req, IODescriptor NewIODescriptor, + Address data, Address dataSz) +{ + struct DescStruct* desc = (struct DescStruct*)req; + Error err; + + switch (desc->type) { + case CAAM_AESECB: + case CAAM_AESCTR: + case CAAM_AESCBC: + case CAAM_AESCCM: + + case CAAM_MD5: + case CAAM_SHA: + case CAAM_SHA224: + case CAAM_SHA256: + case CAAM_SHA384: + case CAAM_SHA512: + + case CAAM_BLOB_ENCAP: + case CAAM_BLOB_DECAP: + case CAAM_ENTROPY: + { /* set buffer for transfer finish */ + struct buffer* buf; + if (desc->DescriptorCount >= MAX_BUF) { + return TooManyBuffers; + } + buf = &desc->buf[desc->DescriptorCount]; + buf->data = data; + buf->dataSz = dataSz; + } + err = Success; + break; + + default: + err = UsageNotSupported; + } + + if (err != Success) { + desc->running = false; + DismissIORequest(req); + return err; + } + + desc->DescriptorCount++; + return Success; +} + + +static Error caamTransferFinish(IODeviceVector ioCaam, IORequest req) +{ + struct DescStruct* desc = (struct DescStruct*)req; + Error ret; + + /* construct desc */ + switch (desc->type) { + case CAAM_AESECB: + case CAAM_AESCTR: + case CAAM_AESCBC: + ret = caamAes(desc); + break; + + case CAAM_AESCCM: + ret = caamAead(desc); + break; + + case CAAM_MD5: + case CAAM_SHA: + case CAAM_SHA224: + case CAAM_SHA256: + case CAAM_SHA384: + case CAAM_SHA512: + ret = caamSha(desc, 0); + break; + + case CAAM_ENTROPY: + ret = caamRng(desc); + break; + + case CAAM_BLOB_ENCAP: + case CAAM_BLOB_DECAP: + ret = caamBlob(desc); + break; + + default: + ret = UsageNotSupported; + } + + desc->running = false; + DismissIORequest(req); + return ret; +} + + +/****************************************************************************** + IODevice Interrupt and Init + ****************************************************************************/ + +static Error caamTransferWrite(IODeviceVector ioCaam, + IORequest req, Value dataSz, const volatile Value *data) +{ + DismissIORequest(req); + return UsageNotSupported; +} + + +static void caamTransferAbort(IODeviceVector ioCaam, IORequest req) +{ + DismissIORequest(req); +} + + +static void caamTransferRecall(IODeviceVector ioCaam, IODescriptor req) +{ + +} + + +static void HandleInterrupt(Address id) +{ + struct CAAM_DEVICE* local = (struct CAAM_DEVICE*)id; + Value InterruptStatus = INTERRUPT_AtomicWrite(&local->InterruptStatus, 0); + int i; + + /* Loop through descriptors and try to dismiss them */ + for (i = 0; i < DESC_COUNT; i++) { + struct DescStruct* desc = &local->DescArray[i]; + if (InterruptStatus & (1 << i)) { + desc->running = false; + if (GetIORequestStatus((IORequest)desc) == IORequestSuspended) { + ContinueIORequest((IORequest)desc); + } + else { + DismissIORequest((IORequest)desc); + } + } + } +} + + +static Error caamCreate(IODeviceVector ioCaam) +{ + return Success; +} + + +void InitCAAM(void) +{ + /* get IO vector and set it up */ + IODeviceVector ioCaam = &caam.caamVector; + unsigned int reg; + int i; + Error ret; + + + ioCaam->Create = &caamCreate; + ioCaam->ReadRegister = &caamReadRegister; + ioCaam->WriteRegister = &caamWriteRegister; + + ioCaam->TransferStart = &caamTransferStart; + ioCaam->TransferBuffer = &caamTransferBuffer; + ioCaam->TransferWrite = &caamTransferWrite; + ioCaam->TransferFinish = &caamTransferFinish; + ioCaam->TransferAbort = &caamTransferAbort; + ioCaam->TransferRecall = &caamTransferRecall; +#ifdef HARDWARE_CACHE_COHERENCY + ioCaam->IOSynchronizationNotRequired = 1; +#endif + + RegisterIODeviceVector(ioCaam, DRIVER_NAME); + RequestIOTerminationTask(ioCaam, 10); + + /* Initialize descriptors */ + for (i = 0; i < BUFFER_COUNT; i++) { + InitializeIODescriptor(ioCaam, &caam.IODescriptorArray[i]); + } + + /* Initialize Descriptors */ + for (i = 0; i < DESC_COUNT; i++) { + InitializeIORequest(ioCaam, &caam.DescArray[i].TheIORequest, + IOREQUEST_STANDARD); + caam.DescArray[i].running = false; + caam.DescArray[i].caam = &caam; + } + + + /* call interrupt to make IORequests available */ + caam.InterruptStatus = 0; + INTERRUPT_InitCall(&caam.HandleInterruptCall, + &HandleInterrupt, "Start up CAAM IORequest"); + + /* set clock speed for CAAM. Setting it here to allow for restricting + access */ + #define REGS_CCM_BASE (0xf20c4000) + #define HW_CCM_CCGR0_ADDR (0xf20c4068) + #define CG(x) (3 << (x*2)) + + reg = CG(6) | CG(5) | CG(4); + *(volatile unsigned int*)HW_CCM_CCGR0_ADDR = + *(volatile unsigned int*)HW_CCM_CCGR0_ADDR | reg; + + /* set up job ring */ + + /* @TODO create partition in physical memory for job rings + current partition security is set to the default */ + for (i = 1; i < CAAM_PAGE_MAX; i++) { + ret = caamCreatePartition(i, i); + if (ret == 0) { + break; + } + + if (ret != MemoryMapMayNotBeEmpty) { + INTERRUPT_Panic(); + } + } + + if (ret != 0) { + INTERRUPT_Panic(); + } + + caam.ring.page = i; + caam.ring.JobIn = (CAAM_PAGE + (i << 12)); + caam.ring.JobOut = caam.ring.JobIn + 16; + caam.ring.Desc = caam.ring.JobOut + 16; + + /* set physical address of job rings */ + CAAM_WRITE(CAAM_IRBAR0, caam.ring.JobIn ^ 0xF0000000); + CAAM_WRITE(CAAM_ORBAR0, caam.ring.JobOut ^ 0xF0000000); + + /* Initialize job ring sizes to 1 */ + CAAM_WRITE(CAAM_IRSR0, 1); + CAAM_WRITE(CAAM_ORSR0, 1); + + /* set DECO watchdog to time out and flush jobs that cause the DECO to hang */ + CAAM_WRITE((CAAM_BASE | 0x0004), CAAM_READ(CAAM_BASE | 0x0004) | 0x40000000); + + /* start up RNG if not already started */ + if (caamInitRng(&caam) != 0) { + INTERRUPT_Panic(); + } +} + +void (*__ghsentry_bspuserinit_InitCAAM)(void) = &InitCAAM; + +#endif /* INTEGRITY */ diff --git a/wolfcrypt/src/port/caam/caam_init.c b/wolfcrypt/src/port/caam/caam_init.c new file mode 100644 index 0000000..014341c --- /dev/null +++ b/wolfcrypt/src/port/caam/caam_init.c @@ -0,0 +1,289 @@ +/* caam_init.c + * + * Copyright (C) 2006-2020 wolfSSL Inc. + * + * This file is part of wolfSSL. + * + * wolfSSL is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * wolfSSL 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, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335, USA + */ + + +#include <wolfssl/wolfcrypt/settings.h> + +#if defined(WOLFSSL_IMX6_CAAM) || defined(WOLFSSL_IMX6_CAAM_RNG) || \ + defined(WOLFSSL_IMX6_CAAM_BLOB) + +#include <wolfssl/wolfcrypt/logging.h> +#include <wolfssl/wolfcrypt/error-crypt.h> +#include <wolfssl/wolfcrypt/port/caam/wolfcaam.h> + +#define WC_CAAM_BLOB_SZ 48 + +#ifndef WC_CAAM_PASSWORD + #define WC_CAAM_PASSWORD "!systempassword" +#endif + +#if defined(__INTEGRITY) || defined(INTEGRITY) + #include <INTEGRITY.h> + #include <wolfssl/wolfcrypt/port/caam/caam_driver.h> + static IODevice caam = NULLIODevice; +#endif + +#if defined(WOLFSSL_CAAM_PRINT) || defined(WOLFSSL_CAAM_DEBUG) +#include <stdio.h> +#include <wolfssl/version.h> + +static void wc_caamBanner(void) +{ + printf("********* wolfSSL Version %s : Printing Out CAAM Information ********\n", + LIBWOLFSSL_VERSION_STRING); + printf("CAAM Status [0x%8.8x] = 0x%8.8x\n", + CAAM_STATUS, WC_CAAM_READ(CAAM_STATUS)); + printf("CAAM Version MS Register [0x%8.8x] = 0x%8.8x\n", + CAAM_VERSION_MS, WC_CAAM_READ(CAAM_VERSION_MS)); + printf("CAAM Version LS Register [0x%8.8x] = 0x%8.8x\n", + CAAM_VERSION_LS, WC_CAAM_READ(CAAM_VERSION_LS)); + printf("CAAM Support MS Register [0x%8.8x] = 0x%8.8x\n", + CAMM_SUPPORT_MS, WC_CAAM_READ(CAMM_SUPPORT_MS)); + printf("CAAM Support LS [0x%8.8x] = 0x%8.8x\n", + CAMM_SUPPORT_LS, WC_CAAM_READ(CAMM_SUPPORT_LS)); + printf("********************************************************************\n\n"); +} +#endif + + +/* Allow runtime setting for CAAM IODevice in case user wants to use password + * at run time. + * + * returns 0 on success + * + * NOTE this is how IODevice is defined in INTEGRITY "typedef struct + * IODeviceStruct *IODevice;" + */ +int wc_caamSetResource(IODevice ioDev) +{ + WOLFSSL_MSG("Setting CAAM driver"); + caam = ioDev; + + return 0; +} + +/* Check hardware support + * + * returns 0 on success + */ +int wc_caamInit(void) +{ + int ret; + word32 reg; + + /* get the driver up */ + if (caam == NULLIODevice) { + WOLFSSL_MSG("Starting CAAM driver"); + if ((ret = (int)RequestResource((Object *)&caam, "wolfSSL_CAAM_Driver", + WC_CAAM_PASSWORD)) != (int)Success) { + WOLFSSL_MSG("Unable to get the CAAM IODevice, check password?"); + WOLFSSL_LEAVE("wc_caamInit: error from driver = ", ret); + ret = 0; /* not a hard failure because user can set resource */ + } + } + +#if defined(WOLFSSL_CAAM_PRINT) || defined(WOLFSSL_CAAM_DEBUG) + /* print out CAAM version/info and wolfSSL version */ + wc_caamBanner(); +#endif + + /* check that for implemented modules + * bits 0-3 AES, 4-7 DES, 12-15 Hashing , 16-19 RNG */ + reg = WC_CAAM_READ(CAMM_SUPPORT_LS); + + #ifndef WC_NO_RNG + if (((reg & 0x000F0000) >> 16) > 0) { + WOLFSSL_MSG("Found CAAM RNG hardware module"); + if ((WC_CAAM_READ(CAAM_RTMCTL) & 0x40000001) != 0x40000001) { + WOLFSSL_MSG("Error CAAM RNG has not been set up"); + } + } + #endif + + #ifndef NO_SHA256 + if ((reg & 0x0000F000) > 0) { + WOLFSSL_MSG("Found CAAM MDHA module"); + } + else { + WOLFSSL_MSG("Hashing not supported by CAAM"); + return WC_HW_E; + } + #endif + + #ifndef NO_AES + if ((reg & 0x0000000F) > 0) { + WOLFSSL_MSG("Found CAAM AES module"); + } + else { + WOLFSSL_MSG("AES not supported by CAAM"); + return WC_HW_E; + } + #endif + + (void)ret; + return 0; +} + + +int wc_caamFree(void) +{ + return 0; +} + + +word32 wc_caamReadRegister(word32 reg) +{ + Value out = 0; + + if (caam == NULLIODevice) { + WOLFSSL_MSG("Error CAAM IODevice not found! Bad password?"); + return 0; + } + + if (ReadIODeviceRegister(caam, reg, &out) != Success) { + WOLFSSL_MSG("Error reading register\n"); + } + + return (word32)out; +} + +void wc_caamWriteRegister(word32 reg, word32 value) +{ + if (caam == NULLIODevice) { + WOLFSSL_MSG("Error CAAM IODevice not found! Bad password?"); + return; + } + + if (WriteIODeviceRegister(caam, reg, value) != Success) { + WOLFSSL_MSG("Error writing to register\n"); + } +} + + +/* return 0 on success and WC_HW_E on failure. Can also return WC_HW_WAIT_E + * in the case that the driver is waiting for a resource or RAN_BLOCK_E if + * waiting for entropy. */ +int wc_caamAddAndWait(Buffer* buf, word32 arg[4], word32 type) +{ + int ret; + if (caam == NULLIODevice) { + WOLFSSL_MSG("Error CAAM IODevice not found! Bad password?"); + return WC_HW_E; + } + + if ((ret = SynchronousSendIORequest(caam, type, (const Value*)arg, buf)) + != Success) { + #if defined(WOLFSSL_CAAM_PRINT) || defined(WOLFSSL_CAAM_DEBUG) + printf("ret of SynchronousSendIORequest = %d type = %d\n", ret, type); + #endif + + /* if waiting for resource or RNG return waiting */ + if (ret == Waiting) { + WOLFSSL_MSG("Waiting on entropy from driver"); + return RAN_BLOCK_E; + } + + if (ret == ResourceNotAvailable) { + WOLFSSL_MSG("Waiting on CAAM driver"); + return WC_HW_WAIT_E; + } + + return WC_HW_E; + } + + (void)ret; + return 0; +} + + +int wc_caamCreateBlob(byte* data, word32 dataSz, byte* out, word32* outSz) +{ + Buffer in[3]; + word32 arg[4]; + int ret; + word32 local[2] = {0,0}; + + if (data == NULL || out == NULL || outSz == NULL || + *outSz < dataSz + WC_CAAM_BLOB_SZ) { + return BAD_FUNC_ARG; + } + + in[0].BufferType = DataBuffer; + in[0].TheAddress = (Address)local; + in[0].Length = sizeof(local); + + in[1].BufferType = DataBuffer; + in[1].TheAddress = (Address)data; + in[1].Length = dataSz; + + in[2].BufferType = DataBuffer | LastBuffer; + in[2].TheAddress = (Address)out; + in[2].Length = dataSz + WC_CAAM_BLOB_SZ; + + arg[2] = dataSz; + + if ((ret = wc_caamAddAndWait(in, arg, CAAM_BLOB_ENCAP)) != 0) { + WOLFSSL_MSG("Error with CAAM blob create"); + return ret; + } + + *outSz = dataSz + WC_CAAM_BLOB_SZ; + return 0; +} + + +int wc_caamOpenBlob(byte* data, word32 dataSz, byte* out, word32* outSz) +{ + Buffer in[3]; + word32 arg[4]; + int ret; + word32 local[2] = {0,0}; + + if (data == NULL || out == NULL || outSz == NULL || + *outSz < dataSz - WC_CAAM_BLOB_SZ) { + return BAD_FUNC_ARG; + } + + in[0].BufferType = DataBuffer; + in[0].TheAddress = (Address)local; + in[0].Length = sizeof(local); + + in[0].BufferType = DataBuffer; + in[0].TheAddress = (Address)data; + in[0].Length = dataSz; + + in[1].BufferType = DataBuffer | LastBuffer; + in[1].TheAddress = (Address)out; + in[1].Length = dataSz - WC_CAAM_BLOB_SZ; + + arg[2] = dataSz; + + if ((ret = wc_caamAddAndWait(in, arg, CAAM_BLOB_DECAP)) != 0) { + WOLFSSL_MSG("Error with CAAM blob create"); + return ret; + } + + *outSz = dataSz - WC_CAAM_BLOB_SZ; + return 0; +} + +#endif /* WOLFSSL_IMX6_CAAM */ + diff --git a/wolfcrypt/src/port/caam/caam_sha.c b/wolfcrypt/src/port/caam/caam_sha.c new file mode 100644 index 0000000..74d62fb --- /dev/null +++ b/wolfcrypt/src/port/caam/caam_sha.c @@ -0,0 +1,397 @@ +/* caam_sha.c + * + * Copyright (C) 2006-2020 wolfSSL Inc. + * + * This file is part of wolfSSL. + * + * wolfSSL is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * wolfSSL 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, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335, USA + */ + + +#include <wolfssl/wolfcrypt/settings.h> + +#if defined(WOLFSSL_IMX6_CAAM) && !defined(NO_IMX6_CAAM_HASH) + +#include <wolfssl/wolfcrypt/logging.h> +#include <wolfssl/wolfcrypt/error-crypt.h> + +#ifdef NO_INLINE + #include <wolfssl/wolfcrypt/misc.h> +#else + #define WOLFSSL_MISC_INCLUDED + #include <wolfcrypt/src/misc.c> +#endif + + +#include <INTEGRITY.h> +#include <wolfssl/wolfcrypt/port/caam/caam_driver.h> +#include <wolfssl/wolfcrypt/port/caam/wolfcaam.h> + +#if defined(WOLFSSL_CAAM_DEBUG) || defined(WOLFSSL_CAAM_PRINT) +#include <stdio.h> +#endif + +#ifndef NO_SHA +#include <wolfssl/wolfcrypt/sha.h> +#endif + +#if !defined(NO_SHA256) || defined(WOLFSSL_SHA224) +#include <wolfssl/wolfcrypt/sha256.h> +#endif + +#if defined(WOLFSSL_SHA384) || defined(WOLFSSL_SHA512) +#include <wolfssl/wolfcrypt/sha512.h> +#endif + +#ifndef NO_MD5 +#include <wolfssl/wolfcrypt/md5.h> +#endif + +/****************************************************************************** + Common Code Between SHA Functions + ****************************************************************************/ + +static int _InitSha(wc_Sha* sha, void* heap, int devId, word32 digestSz, + word32 type) +{ + Buffer buf[1]; + word32 arg[4]; + int ret; + + (void)heap; + (void)devId; + + if (sha == NULL) { + return BAD_FUNC_ARG; + } + + XMEMSET(sha, 0, sizeof(Sha)); + + /* Set buffer for context */ + buf[0].BufferType = DataBuffer | LastBuffer; + buf[0].TheAddress = (Address)sha->ctx; + buf[0].Length = digestSz + WC_CAAM_CTXLEN; + buf[0].Transferred = 0; + + arg[0] = CAAM_ALG_INIT; + arg[1] = digestSz + WC_CAAM_CTXLEN; + + if ((ret = wc_caamAddAndWait(buf, arg, type)) != 0) { + WOLFSSL_MSG("Error with CAAM SHA init"); + return ret; + } + + return 0; +} + + +static int _ShaUpdate(wc_Sha* sha, const byte* data, word32 len, word32 digestSz, + word32 type) +{ + Buffer buf[2]; + word32 arg[4]; + int ret; + byte* local; + + if (sha == NULL ||(data == NULL && len > 0)) { + return BAD_FUNC_ARG; + } + + if (len == 0) return 0; /* nothing to do */ + + local = (byte*)sha->buffer; + /* check for filling out existing buffer */ + if (sha->buffLen > 0) { + word32 add = min(len, WC_CAAM_HASH_BLOCK - sha->buffLen); + XMEMCPY(&local[sha->buffLen], data, add); + + sha->buffLen += add; + data += add; + len -= add; + + if (sha->buffLen == WC_CAAM_HASH_BLOCK) { + /* Set buffer for context */ + buf[0].BufferType = DataBuffer; + buf[0].TheAddress = (Address)sha->ctx; + buf[0].Length = digestSz + WC_CAAM_CTXLEN; + buf[0].Transferred = 0; + + /* data to update with */ + buf[1].BufferType = DataBuffer | LastBuffer; + buf[1].TheAddress = (Address)sha->buffer; + buf[1].Length = sha->buffLen; + buf[1].Transferred = 0; + + arg[0] = CAAM_ALG_UPDATE; + arg[1] = digestSz + WC_CAAM_CTXLEN; + + if ((ret = wc_caamAddAndWait(buf, arg, type)) != 0) { + WOLFSSL_MSG("Error with CAAM SHA update"); + return ret; + } + sha->buffLen = 0; /* cleared out buffer */ + } + } + + /* check if multiple full blocks can be done */ + if (len >= WC_CAAM_HASH_BLOCK) { + word32 sz = len / WC_CAAM_HASH_BLOCK; + sz = sz * WC_CAAM_HASH_BLOCK; + + /* Set buffer for context */ + buf[0].BufferType = DataBuffer; + buf[0].TheAddress = (Address)sha->ctx; + buf[0].Length = digestSz + WC_CAAM_CTXLEN; + buf[0].Transferred = 0; + + /* data to update with */ + buf[1].BufferType = DataBuffer | LastBuffer; + buf[1].TheAddress = (Address)data; + buf[1].Length = sz; + buf[1].Transferred = 0; + + arg[0] = CAAM_ALG_UPDATE; + arg[1] = digestSz + WC_CAAM_CTXLEN; + + if ((ret = wc_caamAddAndWait(buf, arg, type)) != 0) { + WOLFSSL_MSG("Error with CAAM SHA update"); + return ret; + } + + len -= sz; + data += sz; + } + + /* check for left overs */ + if (len > 0) { + word32 add = min(len, WC_CAAM_HASH_BLOCK - sha->buffLen); + XMEMCPY(&local[sha->buffLen], data, add); + sha->buffLen += add; + } + + return 0; +} + + +static int _ShaFinal(wc_Sha* sha, byte* out, word32 digestSz, + word32 type) +{ + Buffer buf[2]; + word32 arg[4]; + int ret; + + if (sha == NULL || out == NULL) { + return BAD_FUNC_ARG; + } + + /* Set buffer for context */ + buf[0].BufferType = DataBuffer; + buf[0].TheAddress = (Address)sha->ctx; + buf[0].Length = digestSz + WC_CAAM_CTXLEN; + buf[0].Transferred = 0; + + /* add any potential left overs */ + buf[1].BufferType = DataBuffer | LastBuffer; + buf[1].TheAddress = (Address)sha->buffer; + buf[1].Length = sha->buffLen; + buf[1].Transferred = 0; + + arg[0] = CAAM_ALG_FINAL; + arg[1] = digestSz + WC_CAAM_CTXLEN; + + if ((ret = wc_caamAddAndWait(buf, arg, type)) != 0) { + WOLFSSL_MSG("Error with CAAM SHA init"); + return ret; + } + + return 0; +} + +/****************************************************************************** + MD5 + ****************************************************************************/ +#if !defined(NO_MD5) +int wc_InitMd5_ex(wc_Md5* sha, void* heap, int devId) +{ + return _InitSha(sha, heap, devId, MD5_DIGEST_SIZE, CAAM_MD5); +} + + +int wc_Md5Update(wc_Md5* sha, const byte* data, word32 len) +{ + return _ShaUpdate(sha, data, len, MD5_DIGEST_SIZE, CAAM_MD5); +} + + +int wc_Md5Final(wc_Md5* sha, byte* hash) +{ + int ret; + if ((ret = _ShaFinal(sha, hash, MD5_DIGEST_SIZE, CAAM_MD5)) != 0) { + return ret; + } + + XMEMCPY(hash, (byte*)sha->ctx, MD5_DIGEST_SIZE); + return _InitSha(sha, NULL, 0, MD5_DIGEST_SIZE, CAAM_MD5); +} +#endif /* !NO_MD5 */ + + +/****************************************************************************** + SHA 1 + ****************************************************************************/ +#if !defined(NO_SHA) +int wc_InitSha_ex(wc_Sha* sha, void* heap, int devId) +{ + return _InitSha(sha, heap, devId, SHA_DIGEST_SIZE, CAAM_SHA); +} + + +int wc_ShaUpdate(wc_Sha* sha, const byte* data, word32 len) +{ + return _ShaUpdate(sha, data, len, SHA_DIGEST_SIZE, CAAM_SHA); +} + + +int wc_ShaFinal(wc_Sha* sha, byte* out) +{ + int ret; + if ((ret = _ShaFinal(sha, out, SHA_DIGEST_SIZE, CAAM_SHA)) != 0) { + return ret; + } + + XMEMCPY(out, (byte*)sha->ctx, SHA_DIGEST_SIZE); + return _InitSha(sha, NULL, 0, SHA_DIGEST_SIZE, CAAM_SHA); +} +#endif /* !NO_SHA */ + + +/****************************************************************************** + SHA 224 + ****************************************************************************/ +#ifdef WOLFSSL_SHA224 +int wc_InitSha224_ex(wc_Sha224* sha, void* heap, int devId) +{ + return _InitSha(sha, heap, devId, SHA256_DIGEST_SIZE, CAAM_SHA224); +} + + +int wc_Sha224Update(wc_Sha224* sha, const byte* data, word32 len) +{ + return _ShaUpdate(sha, data, len, SHA256_DIGEST_SIZE, CAAM_SHA224); +} + + +int wc_Sha224Final(wc_Sha224* sha, byte* out) +{ + int ret; + if ((ret = _ShaFinal(sha, out, SHA256_DIGEST_SIZE, CAAM_SHA224)) != 0) { + return ret; + } + + XMEMCPY(out, (byte*)sha->ctx, SHA224_DIGEST_SIZE); + return _InitSha(sha, NULL, 0, SHA256_DIGEST_SIZE, CAAM_SHA224); +} +#endif /* WOLFSSL_SHA224 */ + + +/****************************************************************************** + SHA 256 + ****************************************************************************/ +#if !defined(NO_SHA256) +int wc_InitSha256_ex(wc_Sha256* sha, void* heap, int devId) +{ + return _InitSha(sha, heap, devId, SHA256_DIGEST_SIZE, CAAM_SHA256); +} + + +int wc_Sha256Update(wc_Sha256* sha, const byte* data, word32 len) +{ + return _ShaUpdate(sha, data, len, SHA256_DIGEST_SIZE, CAAM_SHA256); +} + + +int wc_Sha256Final(wc_Sha256* sha, byte* out) +{ + int ret; + if ((ret = _ShaFinal(sha, out, SHA256_DIGEST_SIZE, CAAM_SHA256)) != 0) { + return ret; + } + + XMEMCPY(out, (byte*)sha->ctx, SHA256_DIGEST_SIZE); + return _InitSha(sha, NULL, 0, SHA256_DIGEST_SIZE, CAAM_SHA256); +} +#endif /* !NO_SHA256 */ + + +/****************************************************************************** + SHA 384 + ****************************************************************************/ +#ifdef WOLFSSL_SHA384 +int wc_InitSha384_ex(wc_Sha384* sha, void* heap, int devId) +{ + return _InitSha(sha, heap, devId, SHA512_DIGEST_SIZE, CAAM_SHA384); +} + + +int wc_Sha384Update(wc_Sha384* sha, const byte* data, word32 len) +{ + return _ShaUpdate(sha, data, len, SHA512_DIGEST_SIZE, CAAM_SHA384); +} + + +int wc_Sha384Final(wc_Sha384* sha, byte* out) +{ + int ret; + if ((ret = _ShaFinal(sha, out, SHA512_DIGEST_SIZE, CAAM_SHA384)) != 0) { + return ret; + } + + XMEMCPY(out, (byte*)sha->ctx, SHA384_DIGEST_SIZE); + return _InitSha(sha, NULL, 0, SHA512_DIGEST_SIZE, CAAM_SHA384); +} +#endif /* WOLFSSL_SHA384 */ + + + +/****************************************************************************** + SHA 512 + ****************************************************************************/ +#ifdef WOLFSSL_SHA512 +int wc_InitSha512_ex(wc_Sha512* sha, void* heap, int devId) +{ + return _InitSha(sha, heap, devId, SHA512_DIGEST_SIZE, CAAM_SHA512); +} + + +int wc_Sha512Update(wc_Sha512* sha, const byte* data, word32 len) +{ + return _ShaUpdate(sha, data, len, SHA512_DIGEST_SIZE, CAAM_SHA512); +} + + +int wc_Sha512Final(wc_Sha512* sha, byte* out) +{ + int ret; + if ((ret = _ShaFinal(sha, out, SHA512_DIGEST_SIZE, CAAM_SHA512)) != 0) { + return ret; + } + + XMEMCPY(out, (byte*)sha->ctx, SHA512_DIGEST_SIZE); + return _InitSha(sha, NULL, 0, SHA512_DIGEST_SIZE, CAAM_SHA512); +} +#endif /* WOLFSSL_SHA512 */ + +#endif /* WOLFSSL_IMX6_CAAM */ + |