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/st | |
| download | wolfssl_windows-5015ddb9b1eee748efc24056e46f81888c975f7a.tar.xz wolfssl_windows-5015ddb9b1eee748efc24056e46f81888c975f7a.zip | |
Initial commit
Diffstat (limited to 'wolfcrypt/src/port/st')
| -rw-r--r-- | wolfcrypt/src/port/st/README.md | 132 | ||||
| -rw-r--r-- | wolfcrypt/src/port/st/stm32.c | 879 | ||||
| -rw-r--r-- | wolfcrypt/src/port/st/stsafe.c | 566 |
3 files changed, 1577 insertions, 0 deletions
diff --git a/wolfcrypt/src/port/st/README.md b/wolfcrypt/src/port/st/README.md new file mode 100644 index 0000000..011dd90 --- /dev/null +++ b/wolfcrypt/src/port/st/README.md @@ -0,0 +1,132 @@ +# ST Ports + +Support for the STM32 L4, F1, F2, F4 and F7 on-board crypto hardware acceleration for symmetric AES (ECB/CBC/CTR/GCM) and MD5/SHA1/SHA224/SHA256. + +Support for the STSAFE-A100 crypto hardware accelerator co-processor via I2C for ECC supporting NIST or Brainpool 256-bit and 384-bit curves. It requires the ST-Safe SDK including wolf stsafe_interface.c/.h files. Please contact ST for these. + + +For details see our [wolfSSL ST](https://www.wolfssl.com/docs/stm32/) page. + + +## STM32 Symmetric Acceleration + +We support using the STM32 CubeMX and Standard Peripheral Library. + +### Building + +To enable support define one of the following: + +``` +#define WOLFSSL_STM32L4 +#define WOLFSSL_STM32F1 +#define WOLFSSL_STM32F2 +#define WOLFSSL_STM32F4 +#define WOLFSSL_STM32F7 +``` + +To use CubeMX define `WOLFSSL_STM32_CUBEMX` otherwise StdPeriLib is used. + +To disable portions of the hardware acceleration you can optionally define: + +``` +#define NO_STM32_RNG +#define NO_STM32_CRYPTO +#define NO_STM32_HASH +``` + +### Coding + +In your application you must include <wolfssl/wolfcrypt/settings.h> before any other wolfSSL headers. If building the sources directly we recommend defining `WOLFSSL_USER_SETTINGS` and adding your own `user_settings.h` file. You can find a good reference for this in `IDE/GCC-ARM/Header/user_settings.h`. + + +### Benchmarks + +See our [benchmarks](https://www.wolfssl.com/docs/benchmarks/) on the wolfSSL website. + + + +## STSAFE-A100 ECC Acceleration + +Using the wolfSSL PK callbacks and the reference ST Safe reference API's we support an ECC only cipher suite such as ECDHE-ECDSA-AES128-SHA256 for TLS client or server. + +At the wolfCrypt level we also support ECC native API's for `wc_ecc_*` using the ST-Safe. + +### Building + +`./configure --enable-pkcallbacks CFLAGS="-DWOLFSSL_STSAFEA100"` + +or + +`#define HAVE_PK_CALLBACKS` +`#define WOLFSSL_STSAFEA100` + + +### Coding + +Setup the PK callbacks for TLS using: + +``` +/* Setup PK Callbacks for STSAFE-A100 */ +WOLFSSL_CTX* ctx; +wolfSSL_CTX_SetEccKeyGenCb(ctx, SSL_STSAFE_CreateKeyCb); +wolfSSL_CTX_SetEccSignCb(ctx, SSL_STSAFE_SignCertificateCb); +wolfSSL_CTX_SetEccVerifyCb(ctx, SSL_STSAFE_VerifyPeerCertCb); +wolfSSL_CTX_SetEccSharedSecretCb(ctx, SSL_STSAFE_SharedSecretCb); +wolfSSL_CTX_SetDevId(ctx, 0); /* enables wolfCrypt `wc_ecc_*` ST-Safe use */ +``` + +The reference STSAFE-A100 PK callback functions are located in the `wolfcrypt/src/port/st/stsafe.c` file. + +Adding a custom context to the callbacks: + +``` +/* Setup PK Callbacks context */ +WOLFSSL* ssl; +void* myOwnCtx; +wolfSSL_SetEccKeyGenCtx(ssl, myOwnCtx); +wolfSSL_SetEccVerifyCtx(ssl, myOwnCtx); +wolfSSL_SetEccSignCtx(ssl, myOwnCtx); +wolfSSL_SetEccSharedSecretCtx(ssl, myOwnCtx); +``` + +### Benchmarks and Memory Use + +Software only implementation (STM32L4 120Mhz, Cortex-M4, Fast Math): + +``` +ECDHE 256 key gen SW 4 ops took 1.278 sec, avg 319.500 ms, 3.130 ops/sec +ECDHE 256 agree SW 4 ops took 1.306 sec, avg 326.500 ms, 3.063 ops/sec +ECDSA 256 sign SW 4 ops took 1.298 sec, avg 324.500 ms, 3.082 ops/sec +ECDSA 256 verify SW 2 ops took 1.283 sec, avg 641.500 ms, 1.559 ops/sec +``` + +Memory Use: + +``` +Peak Stack: 18456 +Peak Heap: 2640 +Total: 21096 +``` + + +STSAFE-A100 acceleration: + +``` +ECDHE 256 key gen HW 8 ops took 1.008 sec, avg 126.000 ms, 7.937 ops/sec +ECDHE 256 agree HW 6 ops took 1.051 sec, avg 175.167 ms, 5.709 ops/sec +ECDSA 256 sign HW 14 ops took 1.161 sec, avg 82.929 ms, 12.059 ops/sec +ECDSA 256 verify HW 8 ops took 1.184 sec, avg 148.000 ms, 6.757 ops/sec +``` + +Memory Use: + +``` +Peak Stack: 9592 +Peak Heap: 170 +Total: 9762 +``` + + +## Support + +Email us at [[email protected]](mailto:[email protected]). diff --git a/wolfcrypt/src/port/st/stm32.c b/wolfcrypt/src/port/st/stm32.c new file mode 100644 index 0000000..b37dbd8 --- /dev/null +++ b/wolfcrypt/src/port/st/stm32.c @@ -0,0 +1,879 @@ +/* stm32.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 + */ + +/* Generic STM32 Hashing Function */ +/* Supports CubeMX HAL or Standard Peripheral Library */ + +#ifdef HAVE_CONFIG_H + #include <config.h> +#endif + +#include <wolfssl/wolfcrypt/settings.h> + +#include <wolfssl/wolfcrypt/port/st/stm32.h> +#include <wolfssl/wolfcrypt/types.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 + +#ifndef NO_AES + #include <wolfssl/wolfcrypt/aes.h> +#endif + + +#ifdef STM32_HASH + +#ifdef WOLFSSL_STM32L4 + #define HASH_STR_NBW HASH_STR_NBLW +#endif + +/* User can override STM32_HASH_CLOCK_ENABLE and STM32_HASH_CLOCK_DISABLE */ +#ifndef STM32_HASH_CLOCK_ENABLE + static WC_INLINE void wc_Stm32_Hash_Clock_Enable(STM32_HASH_Context* stmCtx) + { + #ifdef WOLFSSL_STM32_CUBEMX + __HAL_RCC_HASH_CLK_ENABLE(); + #else + RCC_AHB2PeriphClockCmd(RCC_AHB2Periph_HASH, ENABLE); + #endif + (void)stmCtx; + } + #define STM32_HASH_CLOCK_ENABLE(ctx) wc_Stm32_Hash_Clock_Enable(ctx) +#endif + +#ifndef STM32_HASH_CLOCK_DISABLE + static WC_INLINE void wc_Stm32_Hash_Clock_Disable(STM32_HASH_Context* stmCtx) + { + #ifdef WOLFSSL_STM32_CUBEMX + __HAL_RCC_HASH_CLK_DISABLE(); + #else + RCC_AHB2PeriphClockCmd(RCC_AHB2Periph_HASH, DISABLE); + #endif + (void)stmCtx; + } + #define STM32_HASH_CLOCK_DISABLE(ctx) wc_Stm32_Hash_Clock_Disable(ctx) +#endif + +/* STM32 Port Internal Functions */ +static WC_INLINE void wc_Stm32_Hash_SaveContext(STM32_HASH_Context* ctx) +{ + int i; + + /* save context registers */ + ctx->HASH_IMR = HASH->IMR; + ctx->HASH_STR = HASH->STR; + ctx->HASH_CR = HASH->CR; + for (i=0; i<HASH_CR_SIZE; i++) { + ctx->HASH_CSR[i] = HASH->CSR[i]; + } +} + +static WC_INLINE int wc_Stm32_Hash_RestoreContext(STM32_HASH_Context* ctx) +{ + int i; + + if (ctx->HASH_CR != 0) { + /* restore context registers */ + HASH->IMR = ctx->HASH_IMR; + HASH->STR = ctx->HASH_STR; + HASH->CR = ctx->HASH_CR; + + /* Initialize the hash processor */ + HASH->CR |= HASH_CR_INIT; + + /* continue restoring context registers */ + for (i=0; i<HASH_CR_SIZE; i++) { + HASH->CSR[i] = ctx->HASH_CSR[i]; + } + return 1; + } + return 0; +} + +static WC_INLINE void wc_Stm32_Hash_GetDigest(byte* hash, int digestSize) +{ + word32 digest[HASH_MAX_DIGEST/sizeof(word32)]; + + /* get digest result */ + digest[0] = HASH->HR[0]; + digest[1] = HASH->HR[1]; + digest[2] = HASH->HR[2]; + digest[3] = HASH->HR[3]; + if (digestSize >= 20) { + digest[4] = HASH->HR[4]; + #ifdef HASH_DIGEST + if (digestSize >= 28) { + digest[5] = HASH_DIGEST->HR[5]; + digest[6] = HASH_DIGEST->HR[6]; + if (digestSize == 32) + digest[7] = HASH_DIGEST->HR[7]; + } + #endif + } + + ByteReverseWords(digest, digest, digestSize); + + XMEMCPY(hash, digest, digestSize); +} + + +/* STM32 Port Exposed Functions */ +static WC_INLINE int wc_Stm32_Hash_WaitDone(void) +{ + /* wait until hash hardware is not busy */ + int timeout = 0; + while ((HASH->SR & HASH_SR_BUSY) && ++timeout < STM32_HASH_TIMEOUT) { + + } + /* verify timeout did not occur */ + if (timeout >= STM32_HASH_TIMEOUT) { + return WC_TIMEOUT_E; + } + return 0; +} + + +void wc_Stm32_Hash_Init(STM32_HASH_Context* stmCtx) +{ + /* clear context */ + XMEMSET(stmCtx, 0, sizeof(STM32_HASH_Context)); +} + +int wc_Stm32_Hash_Update(STM32_HASH_Context* stmCtx, word32 algo, + const byte* data, int len) +{ + int ret = 0; + byte* local = (byte*)stmCtx->buffer; + int wroteToFifo = 0; + + /* check that internal buffLen is valid */ + if (stmCtx->buffLen >= STM32_HASH_REG_SIZE) { + return BUFFER_E; + } + + /* turn on hash clock */ + STM32_HASH_CLOCK_ENABLE(stmCtx); + + /* restore hash context or init as new hash */ + if (wc_Stm32_Hash_RestoreContext(stmCtx) == 0) { + /* reset the control register */ + HASH->CR &= ~(HASH_CR_ALGO | HASH_CR_DATATYPE | HASH_CR_MODE); + + /* configure algorithm, mode and data type */ + HASH->CR |= (algo | HASH_ALGOMODE_HASH | HASH_DATATYPE_8B); + + /* reset HASH processor */ + HASH->CR |= HASH_CR_INIT; + } + + /* write 4-bytes at a time into FIFO */ + while (len) { + word32 add = min(len, STM32_HASH_REG_SIZE - stmCtx->buffLen); + XMEMCPY(&local[stmCtx->buffLen], data, add); + + stmCtx->buffLen += add; + data += add; + len -= add; + + if (stmCtx->buffLen == STM32_HASH_REG_SIZE) { + wroteToFifo = 1; + HASH->DIN = *(word32*)stmCtx->buffer; + + stmCtx->loLen += STM32_HASH_REG_SIZE; + stmCtx->buffLen = 0; + } + } + + if (wroteToFifo) { + /* save hash state for next operation */ + wc_Stm32_Hash_SaveContext(stmCtx); + } + + /* turn off hash clock */ + STM32_HASH_CLOCK_DISABLE(stmCtx); + + return ret; +} + +int wc_Stm32_Hash_Final(STM32_HASH_Context* stmCtx, word32 algo, + byte* hash, int digestSize) +{ + int ret = 0; + word32 nbvalidbitsdata = 0; + + /* turn on hash clock */ + STM32_HASH_CLOCK_ENABLE(stmCtx); + + /* restore hash state */ + wc_Stm32_Hash_RestoreContext(stmCtx); + + /* finish reading any trailing bytes into FIFO */ + if (stmCtx->buffLen > 0) { + HASH->DIN = *(word32*)stmCtx->buffer; + stmCtx->loLen += stmCtx->buffLen; + } + + /* calculate number of valid bits in last word */ + nbvalidbitsdata = 8 * (stmCtx->loLen % STM32_HASH_REG_SIZE); + HASH->STR &= ~HASH_STR_NBW; + HASH->STR |= nbvalidbitsdata; + + /* start hash processor */ + HASH->STR |= HASH_STR_DCAL; + + /* wait for hash done */ + ret = wc_Stm32_Hash_WaitDone(); + if (ret == 0) { + /* read message digest */ + wc_Stm32_Hash_GetDigest(hash, digestSize); + } + + /* turn off hash clock */ + STM32_HASH_CLOCK_DISABLE(stmCtx); + + return ret; +} + +#endif /* STM32_HASH */ + + +#ifdef STM32_CRYPTO + +#ifndef NO_AES +#ifdef WOLFSSL_STM32_CUBEMX +int wc_Stm32_Aes_Init(Aes* aes, CRYP_HandleTypeDef* hcryp) +{ + int ret; + word32 keySize; + + ret = wc_AesGetKeySize(aes, &keySize); + if (ret != 0) + return ret; + + XMEMSET(hcryp, 0, sizeof(CRYP_HandleTypeDef)); + switch (keySize) { + case 16: /* 128-bit key */ + hcryp->Init.KeySize = CRYP_KEYSIZE_128B; + break; + #ifdef CRYP_KEYSIZE_192B + case 24: /* 192-bit key */ + hcryp->Init.KeySize = CRYP_KEYSIZE_192B; + break; + #endif + case 32: /* 256-bit key */ + hcryp->Init.KeySize = CRYP_KEYSIZE_256B; + break; + default: + break; + } + hcryp->Instance = CRYP; + hcryp->Init.DataType = CRYP_DATATYPE_8B; + hcryp->Init.pKey = (STM_CRYPT_TYPE*)aes->key; +#ifdef STM32_HAL_V2 + hcryp->Init.DataWidthUnit = CRYP_DATAWIDTHUNIT_BYTE; +#endif + + return 0; +} + +#else /* STD_PERI_LIB */ + +int wc_Stm32_Aes_Init(Aes* aes, CRYP_InitTypeDef* cryptInit, + CRYP_KeyInitTypeDef* keyInit) +{ + int ret; + word32 keySize; + word32* aes_key; + + ret = wc_AesGetKeySize(aes, &keySize); + if (ret != 0) + return ret; + + aes_key = aes->key; + + /* crypto structure initialization */ + CRYP_KeyStructInit(keyInit); + CRYP_StructInit(cryptInit); + + /* load key into correct registers */ + switch (keySize) { + case 16: /* 128-bit key */ + cryptInit->CRYP_KeySize = CRYP_KeySize_128b; + keyInit->CRYP_Key2Left = aes_key[0]; + keyInit->CRYP_Key2Right = aes_key[1]; + keyInit->CRYP_Key3Left = aes_key[2]; + keyInit->CRYP_Key3Right = aes_key[3]; + break; + + case 24: /* 192-bit key */ + cryptInit->CRYP_KeySize = CRYP_KeySize_192b; + keyInit->CRYP_Key1Left = aes_key[0]; + keyInit->CRYP_Key1Right = aes_key[1]; + keyInit->CRYP_Key2Left = aes_key[2]; + keyInit->CRYP_Key2Right = aes_key[3]; + keyInit->CRYP_Key3Left = aes_key[4]; + keyInit->CRYP_Key3Right = aes_key[5]; + break; + + case 32: /* 256-bit key */ + cryptInit->CRYP_KeySize = CRYP_KeySize_256b; + keyInit->CRYP_Key0Left = aes_key[0]; + keyInit->CRYP_Key0Right = aes_key[1]; + keyInit->CRYP_Key1Left = aes_key[2]; + keyInit->CRYP_Key1Right = aes_key[3]; + keyInit->CRYP_Key2Left = aes_key[4]; + keyInit->CRYP_Key2Right = aes_key[5]; + keyInit->CRYP_Key3Left = aes_key[6]; + keyInit->CRYP_Key3Right = aes_key[7]; + break; + + default: + break; + } + cryptInit->CRYP_DataType = CRYP_DataType_8b; + + return 0; +} +#endif /* WOLFSSL_STM32_CUBEMX */ +#endif /* !NO_AES */ +#endif /* STM32_CRYPTO */ + +#ifdef WOLFSSL_STM32_PKA +#include <stdint.h> +#include <stm32wbxx_hal_conf.h> +#include <stm32wbxx_hal_pka.h> + +extern PKA_HandleTypeDef hpka; + +/* Reverse array in memory (in place) */ +#ifdef HAVE_ECC +#include <wolfssl/wolfcrypt/ecc.h> + +/* convert from mp_int to STM32 PKA HAL integer, as array of bytes of size sz. + * if mp_int has less bytes than sz, add zero bytes at most significant byte positions. + * This is when for example modulus is 32 bytes (P-256 curve) + * and mp_int has only 31 bytes, we add leading zeros + * so that result array has 32 bytes, same as modulus (sz). + */ +static int stm32_get_from_mp_int(uint8_t *dst, mp_int *a, int sz) +{ + int res; + int szbin; + int offset; + + if (!a || !dst || (sz < 0)) + return -1; + + /* check how many bytes are in the mp_int */ + szbin = mp_unsigned_bin_size(a); + if ((szbin < 0) || (szbin > sz)) + return -1; + + /* compute offset from dst */ + offset = sz - szbin; + if (offset < 0) + offset = 0; + if (offset > sz) + offset = sz; + + /* add leading zeroes */ + if (offset) + XMEMSET(dst, 0, offset); + + /* convert mp_int to array of bytes */ + res = mp_to_unsigned_bin(a, dst + offset); + return res; +} + +/* ECC specs in lsbyte at lowest address format for direct use by STM32_PKA PKHA driver functions */ +#if defined(HAVE_ECC192) || defined(HAVE_ALL_CURVES) +#define ECC192 +#endif +#if defined(HAVE_ECC224) || defined(HAVE_ALL_CURVES) +#define ECC224 +#endif +#if !defined(NO_ECC256) || defined(HAVE_ALL_CURVES) +#define ECC256 +#endif +#if defined(HAVE_ECC384) || defined(HAVE_ALL_CURVES) +#define ECC384 +#endif + +/* STM32 PKA supports up to 640bit numbers */ +#define STM32_MAX_ECC_SIZE (80) + + +/* P-192 */ +#ifdef ECC192 +#define ECC192_KEYSIZE (24) +static const uint8_t stm32_ecc192_prime[ECC192_KEYSIZE] = { + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff +}; +static const uint32_t stm32_ecc192_coef_sign = 1U; + +static const uint8_t stm32_ecc192_coef[ECC192_KEYSIZE] = { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03 +}; + +static const uint8_t stm32_ecc192_pointX[ECC192_KEYSIZE] = { + 0x18, 0x8D, 0xA8, 0x0E, 0xB0, 0x30, 0x90, 0xF6, + 0x7C, 0xBF, 0x20, 0xEB, 0x43, 0xA1, 0x88, 0x00, + 0xF4, 0xFF, 0x0A, 0xFD, 0x82, 0xFF, 0x10, 0x12 +}; + +const uint8_t stm32_ecc192_pointY[ECC192_KEYSIZE] = { + 0x07, 0x19, 0x2B, 0x95, 0xFF, 0xC8, 0xDA, 0x78, + 0x63, 0x10, 0x11, 0xED, 0x6B, 0x24, 0xCD, 0xD5, + 0x73, 0xF9, 0x77, 0xA1, 0x1E, 0x79, 0x48, 0x11 +}; + +const uint8_t stm32_ecc192_order[ECC192_KEYSIZE] = { + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0x99, 0xDE, 0xF8, 0x36, + 0x14, 0x6B, 0xC9, 0xB1, 0xB4, 0xD2, 0x28, 0x31 +}; +const uint32_t stm32_ecc192_cofactor = 1U; + +#endif /* ECC192 */ + +/* P-224 */ +#ifdef ECC224 +#define ECC224_KEYSIZE (28) +static const uint8_t stm32_ecc224_prime[ECC224_KEYSIZE] = { + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x01 +}; +static const uint32_t stm32_ecc224_coef_sign = 1U; + +static const uint8_t stm32_ecc224_coef[ECC224_KEYSIZE] = { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x03 +}; + +static const uint8_t stm32_ecc224_pointX[ECC224_KEYSIZE] = { + 0xB7, 0x0E, 0x0C, 0xBD, 0x6B, 0xB4, 0xBF, 0x7F, + 0x32, 0x13, 0x90, 0xB9, 0x4A, 0x03, 0xC1, 0xD3, + 0x56, 0xC2, 0x11, 0x22, 0x34, 0x32, 0x80, 0xD6, + 0x11, 0x5C, 0x1D, 0x21 +}; + +const uint8_t stm32_ecc224_pointY[ECC224_KEYSIZE] = { + 0xBD, 0x37, 0x63, 0x88, 0xB5, 0xF7, 0x23, 0xFB, + 0x4C, 0x22, 0xDF, 0xE6, 0xCD, 0x43, 0x75, 0xA0, + 0x5A, 0x07, 0x47, 0x64, 0x44, 0xD5, 0x81, 0x99, + 0x85, 0x00, 0x7E, 0x34 +}; + +const uint8_t stm32_ecc224_order[ECC224_KEYSIZE] = { +}; +const uint32_t stm32_ecc224_cofactor = 1U; + +#endif /* ECC224 */ + +/* P-256 */ +#ifdef ECC256 +#define ECC256_KEYSIZE (32) + +static const uint8_t stm32_ecc256_prime[ECC256_KEYSIZE] = { + 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x01, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff +}; +static const uint32_t stm32_ecc256_coef_sign = 1U; + +static const uint8_t stm32_ecc256_coef[ECC256_KEYSIZE] = { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03 +}; + +static const uint8_t stm32_ecc256_pointX[ECC256_KEYSIZE] = { + 0x6b, 0x17, 0xd1, 0xf2, 0xe1, 0x2c, 0x42, 0x47, + 0xf8, 0xbc, 0xe6, 0xe5, 0x63, 0xa4, 0x40, 0xf2, + 0x77, 0x03, 0x7d, 0x81, 0x2d, 0xeb, 0x33, 0xa0, + 0xf4, 0xa1, 0x39, 0x45, 0xd8, 0x98, 0xc2, 0x96 +}; + +const uint8_t stm32_ecc256_pointY[ECC256_KEYSIZE] = { + 0x4f, 0xe3, 0x42, 0xe2, 0xfe, 0x1a, 0x7f, 0x9b, + 0x8e, 0xe7, 0xeb, 0x4a, 0x7c, 0x0f, 0x9e, 0x16, + 0x2b, 0xce, 0x33, 0x57, 0x6b, 0x31, 0x5e, 0xce, + 0xcb, 0xb6, 0x40, 0x68, 0x37, 0xbf, 0x51, 0xf5 +}; + +const uint8_t stm32_ecc256_order[ECC256_KEYSIZE] = { + 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xbc, 0xe6, 0xfa, 0xad, 0xa7, 0x17, 0x9e, 0x84, + 0xf3, 0xb9, 0xca, 0xc2, 0xfc, 0x63, 0x25, 0x51 +}; +const uint32_t stm32_ecc256_cofactor = 1U; + +#endif /* ECC256 */ + +/* P-384 */ +#ifdef ECC384 +#define ECC384_KEYSIZE (48) + +static const uint8_t stm32_ecc384_prime[ECC384_KEYSIZE] = { + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFE, + 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF +}; +static const uint32_t stm32_ecc384_coef_sign = 1U; + +static const uint8_t stm32_ecc384_coef[ECC384_KEYSIZE] = { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03 +}; + +static const uint8_t stm32_ecc384_pointX[ECC384_KEYSIZE] = { + 0xAA, 0x87, 0xCA, 0x22, 0xBE, 0x8B, 0x05, 0x37, + 0x8E, 0xB1, 0xC7, 0x1E, 0xF3, 0x20, 0xAD, 0x74, + 0x6E, 0x1D, 0x3B, 0x62, 0x8B, 0xA7, 0x9B, 0x98, + 0x59, 0xF7, 0x41, 0xE0, 0x82, 0x54, 0x2A, 0x38, + 0x55, 0x02, 0xF2, 0x5D, 0xBF, 0x55, 0x29, 0x6C, + 0x3A, 0x54, 0x5E, 0x38, 0x72, 0x76, 0x0A, 0xB7, +}; + +const uint8_t stm32_ecc384_pointY[ECC384_KEYSIZE] = { + 0x36, 0x17, 0xDE, 0x4A, 0x96, 0x26, 0x2C, 0x6F, + 0x5D, 0x9E, 0x98, 0xBF, 0x92, 0x92, 0xDC, 0x29, + 0xF8, 0xF4, 0x1D, 0xBD, 0x28, 0x9A, 0x14, 0x7C, + 0xE9, 0xDA, 0x31, 0x13, 0xB5, 0xF0, 0xB8, 0xC0, + 0x0A, 0x60, 0xB1, 0xCE, 0x1D, 0x7E, 0x81, 0x9D, + 0x7A, 0x43, 0x1D, 0x7C, 0x90, 0xEA, 0x0E, 0x5F, +}; + +const uint8_t stm32_ecc384_order[ECC384_KEYSIZE] = { +}; +const uint32_t stm32_ecc384_cofactor = 1U; + +#endif /* ECC384 */ +static int stm32_get_ecc_specs(const uint8_t **prime, const uint8_t **coef, + const uint32_t **coef_sign, const uint8_t **GenPointX, const uint8_t **GenPointY, + const uint8_t **order, int size) +{ + switch(size) { + case 32: + *prime = stm32_ecc256_prime; + *coef = stm32_ecc256_coef; + *GenPointX = stm32_ecc256_pointX; + *GenPointY = stm32_ecc256_pointY; + *coef_sign = &stm32_ecc256_coef_sign; + *order = stm32_ecc256_order; + break; +#ifdef ECC224 + case 28: + *prime = stm32_ecc224_prime; + *coef = stm32_ecc224_coef; + *GenPointX = stm32_ecc224_pointX; + *GenPointY = stm32_ecc224_pointY; + *coef_sign = &stm32_ecc224_coef; + break; +#endif +#ifdef ECC192 + case 24: + *prime = stm32_ecc192_prime; + *coef = stm32_ecc192_coef; + *GenPointX = stm32_ecc192_pointX; + *GenPointY = stm32_ecc192_pointY; + *coef_sign = &stm32_ecc192_coef; + break; +#endif +#ifdef ECC384 + case 48: + *prime = stm32_ecc384_prime; + *coef = stm32_ecc384_coef; + *GenPointX = stm32_ecc384_pointX; + *GenPointY = stm32_ecc384_pointY; + *coef_sign = &stm32_ecc384_coef; + break; +#endif + default: + return -1; + } + return 0; +} + + +/** + Perform a point multiplication (timing resistant) + k The scalar to multiply by + G The base point + R [out] Destination for kG + modulus The modulus of the field the ECC curve is in + map Boolean whether to map back to affine or not + (1==map, 0 == leave in projective) + return MP_OKAY on success +*/ +int wc_ecc_mulmod_ex(mp_int *k, ecc_point *G, ecc_point *R, mp_int* a, + mp_int *modulus, int map, void* heap) +{ + PKA_ECCMulInTypeDef pka_mul; + PKA_ECCMulOutTypeDef pka_mul_res; + uint8_t size; + int szModulus; + int szkbin; + int status; + int res; + uint8_t Gxbin[STM32_MAX_ECC_SIZE]; + uint8_t Gybin[STM32_MAX_ECC_SIZE]; + uint8_t kbin[STM32_MAX_ECC_SIZE]; + uint8_t PtXbin[STM32_MAX_ECC_SIZE]; + uint8_t PtYbin[STM32_MAX_ECC_SIZE]; + const uint8_t *prime, *coef, *gen_x, *gen_y, *order; + const uint32_t *coef_sign; + (void)a; + (void)heap; + XMEMSET(&pka_mul, 0x00, sizeof(PKA_ECCMulInTypeDef)); + XMEMSET(&pka_mul_res, 0x00, sizeof(PKA_ECCMulOutTypeDef)); + pka_mul_res.ptX = PtXbin; + pka_mul_res.ptY = PtYbin; + + if (k == NULL || G == NULL || R == NULL || modulus == NULL) { + return ECC_BAD_ARG_E; + } + + szModulus = mp_unsigned_bin_size(modulus); + szkbin = mp_unsigned_bin_size(k); + + res = stm32_get_from_mp_int(kbin, k, szkbin); + if (res == MP_OKAY) + res = stm32_get_from_mp_int(Gxbin, G->x, szModulus); + if (res == MP_OKAY) + res = stm32_get_from_mp_int(Gybin, G->y, szModulus); + + if (res != MP_OKAY) + return res; + + size = (uint8_t)szModulus; + /* find STM32_PKA friendly parameters for the selected curve */ + if (0 != stm32_get_ecc_specs(&prime, &coef, &coef_sign, &gen_x, &gen_y, &order, size)) { + return ECC_BAD_ARG_E; + } + (void)order; + + pka_mul.modulusSize = szModulus; + pka_mul.coefSign = *coef_sign; + pka_mul.coefA = coef; + pka_mul.modulus = prime; + pka_mul.pointX = Gxbin; + pka_mul.pointY = Gybin; + pka_mul.scalarMulSize = size; + pka_mul.scalarMul = kbin; + + status = HAL_PKA_ECCMul(&hpka, &pka_mul, HAL_MAX_DELAY); + if (status != HAL_OK) { + return WC_HW_E; + } + pka_mul_res.ptX = Gxbin; + pka_mul_res.ptY = Gybin; + HAL_PKA_ECCMul_GetResult(&hpka, &pka_mul_res); + res = mp_read_unsigned_bin(R->x, Gxbin, size); + if (res == MP_OKAY) { + res = mp_read_unsigned_bin(R->y, Gybin, size); +#ifndef WOLFSSL_SP_MATH + /* if k is negative, we compute the multiplication with abs(-k) + * with result (x, y) and modify the result to (x, -y) + */ + R->y->sign = k->sign; +#endif + } + if (res == MP_OKAY) + res = mp_set(R->z, 1); + HAL_PKA_RAMReset(&hpka); + return res; +} + +int stm32_ecc_verify_hash_ex(mp_int *r, mp_int *s, const byte* hash, + word32 hashlen, int* res, ecc_key* key) +{ + PKA_ECDSAVerifInTypeDef pka_ecc; + uint8_t size; + int szModulus; + int szrbin; + int status; + uint8_t Rbin[STM32_MAX_ECC_SIZE]; + uint8_t Sbin[STM32_MAX_ECC_SIZE]; + uint8_t Qxbin[STM32_MAX_ECC_SIZE]; + uint8_t Qybin[STM32_MAX_ECC_SIZE]; + uint8_t Hashbin[STM32_MAX_ECC_SIZE]; + uint8_t privKeybin[STM32_MAX_ECC_SIZE]; + const uint8_t *prime, *coef, *gen_x, *gen_y, *order; + const uint32_t *coef_sign; + XMEMSET(&pka_ecc, 0x00, sizeof(PKA_ECDSAVerifInTypeDef)); + + if (r == NULL || s == NULL || hash == NULL || res == NULL || key == NULL) { + return ECC_BAD_ARG_E; + } + *res = 0; + + szModulus = mp_unsigned_bin_size(key->pubkey.x); + szrbin = mp_unsigned_bin_size(r); + + status = stm32_get_from_mp_int(Rbin, r, szrbin); + if (status == MP_OKAY) + status = stm32_get_from_mp_int(Sbin, s, szrbin); + if (status == MP_OKAY) + status = stm32_get_from_mp_int(Qxbin, key->pubkey.x, szModulus); + if (status == MP_OKAY) + status = stm32_get_from_mp_int(Qybin, key->pubkey.y, szModulus); + if (status == MP_OKAY) + status = stm32_get_from_mp_int(privKeybin, &key->k, szModulus); + if (status != MP_OKAY) + return status; + + size = (uint8_t)szModulus; + /* find parameters for the selected curve */ + if (0 != stm32_get_ecc_specs(&prime, &coef, &coef_sign, &gen_x, &gen_y, &order, size)) { + return ECC_BAD_ARG_E; + } + + + pka_ecc.primeOrderSize = size; + pka_ecc.modulusSize = size; + pka_ecc.coefSign = *coef_sign; + pka_ecc.coef = coef; + pka_ecc.modulus = prime; + pka_ecc.basePointX = gen_x; + pka_ecc.basePointY = gen_y; + pka_ecc.primeOrder = order; + + pka_ecc.pPubKeyCurvePtX = Qxbin; + pka_ecc.pPubKeyCurvePtY = Qybin; + pka_ecc.RSign = Rbin; + pka_ecc.SSign = Sbin; + XMEMSET(Hashbin, 0, STM32_MAX_ECC_SIZE); + XMEMCPY(Hashbin + (size - hashlen), hash, hashlen); + pka_ecc.hash = Hashbin; + + status = HAL_PKA_ECDSAVerif(&hpka, &pka_ecc, HAL_MAX_DELAY); + if (status != HAL_OK) { + HAL_PKA_RAMReset(&hpka); + return WC_HW_E; + } + *res = HAL_PKA_ECDSAVerif_IsValidSignature(&hpka); + HAL_PKA_RAMReset(&hpka); + return status; +} + +int stm32_ecc_sign_hash_ex(const byte* hash, word32 hashlen, WC_RNG* rng, + ecc_key* key, mp_int *r, mp_int *s) +{ + PKA_ECDSASignInTypeDef pka_ecc; + PKA_ECDSASignOutTypeDef pka_ecc_out; + int size; + int status; + mp_int gen_k; + mp_int order_mp; + uint8_t Keybin[STM32_MAX_ECC_SIZE]; + uint8_t Intbin[STM32_MAX_ECC_SIZE]; + uint8_t Rbin[STM32_MAX_ECC_SIZE]; + uint8_t Sbin[STM32_MAX_ECC_SIZE]; + uint8_t Hashbin[STM32_MAX_ECC_SIZE]; + const uint8_t *prime, *coef, *gen_x, *gen_y, *order; + const uint32_t *coef_sign; + XMEMSET(&pka_ecc, 0x00, sizeof(PKA_ECDSASignInTypeDef)); + XMEMSET(&pka_ecc, 0x00, sizeof(PKA_ECDSASignOutTypeDef)); + + if (r == NULL || s == NULL || hash == NULL || key == NULL) { + return ECC_BAD_ARG_E; + } + + mp_init(&gen_k); + mp_init(&order_mp); + + size = mp_unsigned_bin_size(key->pubkey.x); + + status = stm32_get_from_mp_int(Keybin, &key->k, size); + if (status != MP_OKAY) + return status; + + /* find parameters for the selected curve */ + if (0 != stm32_get_ecc_specs(&prime, &coef, &coef_sign, &gen_x, &gen_y, &order, size)) { + return ECC_BAD_ARG_E; + } + + status = mp_read_unsigned_bin(&order_mp, order, size); + if (status == MP_OKAY) + status = wc_ecc_gen_k(rng, size, &gen_k, &order_mp); + if (status == MP_OKAY) + status = stm32_get_from_mp_int(Intbin, &gen_k, size); + if (status != MP_OKAY) + return status; + + pka_ecc.primeOrderSize = size; + pka_ecc.modulusSize = size; + pka_ecc.coefSign = *coef_sign; + pka_ecc.coef = coef; + pka_ecc.modulus = prime; + pka_ecc.basePointX = gen_x; + pka_ecc.basePointY = gen_y; + pka_ecc.primeOrder = order; + + XMEMSET(Hashbin, 0, STM32_MAX_ECC_SIZE); + XMEMCPY(Hashbin + (size - hashlen), hash, hashlen); + pka_ecc.hash = Hashbin; + pka_ecc.integer = Intbin; + pka_ecc.privateKey = Keybin; + + /* Assign R, S static buffers */ + pka_ecc_out.RSign = Rbin; + pka_ecc_out.SSign = Sbin; + + status = HAL_PKA_ECDSASign(&hpka, &pka_ecc, HAL_MAX_DELAY); + if (status != HAL_OK) { + HAL_PKA_RAMReset(&hpka); + return WC_HW_E; + } + HAL_PKA_ECDSASign_GetResult(&hpka, &pka_ecc_out, NULL); + status = mp_read_unsigned_bin(r, pka_ecc_out.RSign, size); + if (status == MP_OKAY) + status = mp_read_unsigned_bin(s, pka_ecc_out.SSign, size); + HAL_PKA_RAMReset(&hpka); + return status; +} + +#endif /* HAVE_ECC */ +#endif /* WOLFSSL_STM32_PKA */ diff --git a/wolfcrypt/src/port/st/stsafe.c b/wolfcrypt/src/port/st/stsafe.c new file mode 100644 index 0000000..239b159 --- /dev/null +++ b/wolfcrypt/src/port/st/stsafe.c @@ -0,0 +1,566 @@ +/* stsafe.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/port/st/stsafe.h> +#include <wolfssl/wolfcrypt/logging.h> + +#ifndef STSAFE_INTERFACE_PRINTF +#define STSAFE_INTERFACE_PRINTF(...) +#endif + +#ifdef WOLFSSL_STSAFEA100 + +int SSL_STSAFE_LoadDeviceCertificate(byte** pRawCertificate, + word32* pRawCertificateLen) +{ + int err; + + if (pRawCertificate == NULL || pRawCertificateLen == NULL) { + return BAD_FUNC_ARG; + } + +#ifdef USE_STSAFE_VERBOSE + WOLFSSL_MSG("SSL_STSAFE_LoadDeviceCertificate"); +#endif + + /* Try reading device certificate from ST-SAFE Zone 0 */ + err = stsafe_interface_read_device_certificate_raw( + pRawCertificate, (uint32_t*)pRawCertificateLen); + if (err == STSAFE_A_OK) { + #if 0 + /* example for loading into WOLFSSL_CTX */ + err = wolfSSL_CTX_use_certificate_buffer(ctx, + *pRawCertificate, *pRawCertificateLen, SSL_FILETYPE_ASN1); + if (err != WOLFSSL_SUCCESS) { + /* failed */ + } + /* can free now */ + XFREE(*pRawCertificate, NULL, DYNAMIC_TEMP_BUFFER); + *pRawCertificate = NULL; + #endif + } + else { + err = WC_HW_E; + } + + return err; +} + +#ifdef HAVE_PK_CALLBACKS + +/** + * \brief Key Gen Callback (used by TLS server) + */ +int SSL_STSAFE_CreateKeyCb(WOLFSSL* ssl, ecc_key* key, word32 keySz, + int ecc_curve, void* ctx) +{ + int err; + byte pubKeyRaw[STSAFE_MAX_PUBKEY_RAW_LEN]; + StSafeA_KeySlotNumber slot; + StSafeA_CurveId curve_id; + + (void)ssl; + (void)ctx; + +#ifdef USE_STSAFE_VERBOSE + WOLFSSL_MSG("CreateKeyCb: STSAFE"); +#endif + + /* get curve */ + curve_id = stsafe_get_ecc_curve_id(ecc_curve); + + /* generate new ephemeral key on device */ + err = stsafe_interface_create_key(&slot, curve_id, (uint8_t*)&pubKeyRaw[0]); + if (err != STSAFE_A_OK) { + #ifdef USE_STSAFE_VERBOSE + STSAFE_INTERFACE_PRINTF("stsafe_interface_create_key error: %d\n", err); + #endif + err = WC_HW_E; + return err; + } + + /* load generated public key into key, used by wolfSSL */ + err = wc_ecc_import_unsigned(key, &pubKeyRaw[0], &pubKeyRaw[keySz], + NULL, ecc_curve); + + return err; +} + +/** + * \brief Verify Peer Cert Callback. + */ +int SSL_STSAFE_VerifyPeerCertCb(WOLFSSL* ssl, + const unsigned char* sig, unsigned int sigSz, + const unsigned char* hash, unsigned int hashSz, + const unsigned char* keyDer, unsigned int keySz, + int* result, void* ctx) +{ + int err; + byte sigRS[STSAFE_MAX_SIG_LEN]; + byte *r, *s; + word32 r_len = STSAFE_MAX_SIG_LEN/2, s_len = STSAFE_MAX_SIG_LEN/2; + byte pubKeyX[STSAFE_MAX_PUBKEY_RAW_LEN/2]; + byte pubKeyY[STSAFE_MAX_PUBKEY_RAW_LEN/2]; + word32 pubKeyX_len = sizeof(pubKeyX); + word32 pubKeyY_len = sizeof(pubKeyY); + ecc_key key; + word32 inOutIdx = 0; + StSafeA_CurveId curve_id; + int ecc_curve; + + (void)ssl; + (void)ctx; + +#ifdef USE_STSAFE_VERBOSE + WOLFSSL_MSG("VerifyPeerCertCB: STSAFE"); +#endif + + err = wc_ecc_init(&key); + if (err != 0) { + return err; + } + + /* Decode the public key */ + err = wc_EccPublicKeyDecode(keyDer, &inOutIdx, &key, keySz); + if (err == 0) { + /* Extract Raw X and Y coordinates of the public key */ + err = wc_ecc_export_public_raw(&key, pubKeyX, &pubKeyX_len, + pubKeyY, &pubKeyY_len); + } + if (err == 0) { + int key_sz; + + /* determine curve */ + ecc_curve = key.dp->id; + curve_id = stsafe_get_ecc_curve_id(ecc_curve); + key_sz = stsafe_get_key_size(curve_id); + + /* Extract R and S from signature */ + XMEMSET(sigRS, 0, sizeof(sigRS)); + r = &sigRS[0]; + s = &sigRS[key_sz]; + err = wc_ecc_sig_to_rs(sig, sigSz, r, &r_len, s, &s_len); + (void)r_len; + (void)s_len; + } + + if (err == 0) { + /* Verify signature */ + err = stsafe_interface_verify(curve_id, (uint8_t*)hash, sigRS, + pubKeyX, pubKeyY, (int32_t*)result); + if (err != STSAFE_A_OK) { + #ifdef USE_STSAFE_VERBOSE + STSAFE_INTERFACE_PRINTF("stsafe_interface_verify error: %d\n", err); + #endif + err = WC_HW_E; + } + } + + wc_ecc_free(&key); + return err; +} + +/** + * \brief Sign Certificate Callback. + */ +int SSL_STSAFE_SignCertificateCb(WOLFSSL* ssl, const byte* in, + word32 inSz, byte* out, word32* outSz, + const byte* key, word32 keySz, void* ctx) +{ + int err; + byte digest[STSAFE_MAX_KEY_LEN]; + byte sigRS[STSAFE_MAX_SIG_LEN]; + byte *r, *s; + StSafeA_CurveId curve_id; + int key_sz; + + (void)ssl; + (void)ctx; + +#ifdef USE_STSAFE_VERBOSE + WOLFSSL_MSG("SignCertificateCb: STSAFE"); +#endif + + curve_id = stsafe_get_curve_mode(); + key_sz = stsafe_get_key_size(curve_id); + + /* Build input digest */ + if (inSz > key_sz) + inSz = key_sz; + XMEMSET(&digest[0], 0, sizeof(digest)); + XMEMCPY(&digest[key_sz - inSz], in, inSz); + + /* Sign using slot 0: Result is R then S */ + /* Sign will always use the curve type in slot 0 (the TLS curve needs to match) */ + XMEMSET(sigRS, 0, sizeof(sigRS)); + err = stsafe_interface_sign(STSAFE_A_SLOT_0, curve_id, digest, sigRS); + if (err != STSAFE_A_OK) { + #ifdef USE_STSAFE_VERBOSE + STSAFE_INTERFACE_PRINTF("stsafe_interface_sign error: %d\n", err); + #endif + err = WC_HW_E; + return err; + } + + /* Convert R and S to signature */ + r = &sigRS[0]; + s = &sigRS[key_sz]; + err = wc_ecc_rs_raw_to_sig((const byte*)r, key_sz, (const byte*)s, key_sz, + out, outSz); + if (err != 0) { + #ifdef USE_STSAFE_VERBOSE + WOLFSSL_MSG("Error converting RS to Signature"); + #endif + } + + return err; +} + + +/** + * \brief Create pre master secret using peer's public key and self private key. + */ +int SSL_STSAFE_SharedSecretCb(WOLFSSL* ssl, ecc_key* otherKey, + unsigned char* pubKeyDer, unsigned int* pubKeySz, + unsigned char* out, unsigned int* outlen, + int side, void* ctx) +{ + int err; + byte otherKeyX[STSAFE_MAX_KEY_LEN]; + byte otherKeyY[STSAFE_MAX_KEY_LEN]; + word32 otherKeyX_len = sizeof(otherKeyX); + word32 otherKeyY_len = sizeof(otherKeyY); + byte pubKeyRaw[STSAFE_MAX_PUBKEY_RAW_LEN]; + StSafeA_KeySlotNumber slot; + StSafeA_CurveId curve_id; + ecc_key tmpKey; + int ecc_curve; + int key_sz; + + (void)ssl; + (void)ctx; + +#ifdef USE_STSAFE_VERBOSE + WOLFSSL_MSG("SharedSecretCb: STSAFE"); +#endif + + err = wc_ecc_init(&tmpKey); + if (err != 0) { + return err; + } + + /* set curve */ + ecc_curve = otherKey->dp->id; + curve_id = stsafe_get_ecc_curve_id(ecc_curve); + key_sz = stsafe_get_key_size(curve_id); + + /* for client: create and export public key */ + if (side == WOLFSSL_CLIENT_END) { + /* Export otherKey raw X and Y */ + err = wc_ecc_export_public_raw(otherKey, + &otherKeyX[0], (word32*)&otherKeyX_len, + &otherKeyY[0], (word32*)&otherKeyY_len); + if (err != 0) { + return err; + } + + err = stsafe_interface_create_key(&slot, curve_id, (uint8_t*)&pubKeyRaw[0]); + if (err != STSAFE_A_OK) { + #ifdef USE_STSAFE_VERBOSE + STSAFE_INTERFACE_PRINTF("stsafe_interface_create_key error: %d\n", err); + #endif + err = WC_HW_E; + return err; + } + + /* convert raw unsigned public key to X.963 format for TLS */ + err = wc_ecc_init(&tmpKey); + if (err == 0) { + err = wc_ecc_import_unsigned(&tmpKey, &pubKeyRaw[0], &pubKeyRaw[key_sz], + NULL, ecc_curve); + if (err == 0) { + err = wc_ecc_export_x963(&tmpKey, pubKeyDer, pubKeySz); + } + wc_ecc_free(&tmpKey); + } + } + /* for server: import public key */ + else if (side == WOLFSSL_SERVER_END) { + /* import peer's key and export as raw unsigned for hardware */ + err = wc_ecc_import_x963_ex(pubKeyDer, *pubKeySz, &tmpKey, ecc_curve); + if (err == 0) { + err = wc_ecc_export_public_raw(&tmpKey, otherKeyX, &otherKeyX_len, + otherKeyY, &otherKeyY_len); + } + } + else { + err = BAD_FUNC_ARG; + } + + wc_ecc_free(&tmpKey); + + if (err != 0) { + return err; + } + + /* Compute shared secret */ + err = stsafe_interface_shared_secret(curve_id, &otherKeyX[0], &otherKeyY[0], + out, (int32_t*)outlen); + if (err != STSAFE_A_OK) { + #ifdef USE_STSAFE_VERBOSE + STSAFE_INTERFACE_PRINTF("stsafe_interface_shared_secret error: %d\n", err); + #endif + err = WC_HW_E; + } + + return err; +} + +int SSL_STSAFE_SetupPkCallbacks(WOLFSSL_CTX* ctx) +{ + wolfSSL_CTX_SetEccKeyGenCb(ctx, SSL_STSAFE_CreateKeyCb); + wolfSSL_CTX_SetEccSignCb(ctx, SSL_STSAFE_SignCertificateCb); + wolfSSL_CTX_SetEccVerifyCb(ctx, SSL_STSAFE_VerifyPeerCertCb); + wolfSSL_CTX_SetEccSharedSecretCb(ctx, SSL_STSAFE_SharedSecretCb); + wolfSSL_CTX_SetDevId(ctx, 0); /* enables wolfCrypt `wc_ecc_*` ST-Safe use */ + return 0; +} + +int SSL_STSAFE_SetupPkCallbackCtx(WOLFSSL* ssl, void* user_ctx) +{ + wolfSSL_SetEccKeyGenCtx(ssl, user_ctx); + wolfSSL_SetEccSharedSecretCtx(ssl, user_ctx); + wolfSSL_SetEccSignCtx(ssl, user_ctx); + wolfSSL_SetEccVerifyCtx(ssl, user_ctx); + return 0; +} + + +#endif /* HAVE_PK_CALLBACKS */ + +#ifdef WOLF_CRYPTO_CB + +int wolfSSL_STSAFE_CryptoDevCb(int devId, wc_CryptoInfo* info, void* ctx) +{ + int rc = CRYPTOCB_UNAVAILABLE; + wolfSTSAFE_CryptoCb_Ctx* stsCtx = (wolfSTSAFE_CryptoCb_Ctx*)ctx; + + if (info == NULL || ctx == NULL) + return BAD_FUNC_ARG; + + (void)devId; + (void)stsCtx; + + if (info->algo_type == WC_ALGO_TYPE_SEED) { + /* use the STSAFE hardware for RNG seed */ + #if !defined(WC_NO_RNG) && defined(USE_STSAFE_RNG_SEED) + while (info->seed.sz > 0) { + rc = stsafe_interface_getrandom(info->seed.seed, info->seed.sz); + if (rc < 0) { + return rc; + } + info->seed.seed += rc; + info->seed.sz -= rc; + } + rc = 0; + #else + rc = CRYPTOCB_UNAVAILABLE; + #endif + } +#ifdef HAVE_ECC + else if (info->algo_type == WC_ALGO_TYPE_PK) { + #ifdef USE_STSAFE_VERBOSE + STSAFE_INTERFACE_PRINTF("STSAFE Pk: Type %d\n", info->pk.type); + #endif + + if (info->pk.type == WC_PK_TYPE_EC_KEYGEN) { + byte pubKeyRaw[STSAFE_MAX_PUBKEY_RAW_LEN]; + StSafeA_KeySlotNumber slot; + StSafeA_CurveId curve_id; + int ecc_curve, key_sz; + + WOLFSSL_MSG("STSAFE: ECC KeyGen"); + + /* get curve */ + ecc_curve = info->pk.eckg.curveId; + curve_id = stsafe_get_ecc_curve_id(ecc_curve); + key_sz = stsafe_get_key_size(curve_id); + + /* generate new ephemeral key on device */ + rc = stsafe_interface_create_key(&slot, curve_id, + (uint8_t*)pubKeyRaw); + if (rc != STSAFE_A_OK) { + #ifdef USE_STSAFE_VERBOSE + STSAFE_INTERFACE_PRINTF("stsafe_interface_create_key error: %d\n", rc); + #endif + rc = WC_HW_E; + return rc; + } + + /* load generated public key into key, used by wolfSSL */ + rc = wc_ecc_import_unsigned(info->pk.eckg.key, pubKeyRaw, + &pubKeyRaw[key_sz], NULL, ecc_curve); + } + else if (info->pk.type == WC_PK_TYPE_ECDSA_SIGN) { + byte digest[STSAFE_MAX_KEY_LEN]; + byte sigRS[STSAFE_MAX_SIG_LEN]; + byte *r, *s; + StSafeA_CurveId curve_id; + word32 inSz = info->pk.eccsign.inlen; + int key_sz; + + WOLFSSL_MSG("STSAFE: ECC Sign"); + + curve_id = stsafe_get_curve_mode(); + key_sz = stsafe_get_key_size(curve_id); + + /* truncate input to match key size */ + if (inSz > key_sz) + inSz = key_sz; + + /* Build input digest */ + XMEMSET(&digest[0], 0, sizeof(digest)); + XMEMCPY(&digest[key_sz - inSz], info->pk.eccsign.in, inSz); + + /* Sign using slot 0: Result is R then S */ + /* Sign will always use the curve type in slot 0 + (the TLS curve needs to match) */ + XMEMSET(sigRS, 0, sizeof(sigRS)); + rc = stsafe_interface_sign(STSAFE_A_SLOT_0, curve_id, + (uint8_t*)info->pk.eccsign.in, sigRS); + if (rc != STSAFE_A_OK) { + #ifdef USE_STSAFE_VERBOSE + STSAFE_INTERFACE_PRINTF("stsafe_interface_sign error: %d\n", rc); + #endif + rc = WC_HW_E; + return rc; + } + + /* Convert R and S to signature */ + r = &sigRS[0]; + s = &sigRS[key_sz]; + rc = wc_ecc_rs_raw_to_sig((const byte*)r, key_sz, (const byte*)s, + key_sz, info->pk.eccsign.out, info->pk.eccsign.outlen); + if (rc != 0) { + WOLFSSL_MSG("Error converting RS to Signature"); + } + } + else if (info->pk.type == WC_PK_TYPE_ECDSA_VERIFY) { + byte sigRS[STSAFE_MAX_SIG_LEN]; + byte *r, *s; + word32 r_len = STSAFE_MAX_SIG_LEN/2, s_len = STSAFE_MAX_SIG_LEN/2; + byte pubKeyX[STSAFE_MAX_PUBKEY_RAW_LEN/2]; + byte pubKeyY[STSAFE_MAX_PUBKEY_RAW_LEN/2]; + word32 pubKeyX_len = sizeof(pubKeyX); + word32 pubKeyY_len = sizeof(pubKeyY); + StSafeA_CurveId curve_id; + int ecc_curve, key_sz; + + WOLFSSL_MSG("STSAFE: ECC Verify"); + + if (info->pk.eccverify.key == NULL) + return BAD_FUNC_ARG; + + /* determine curve */ + ecc_curve = info->pk.eccverify.key->dp->id; + curve_id = stsafe_get_ecc_curve_id(ecc_curve); + key_sz = stsafe_get_key_size(curve_id); + + /* Extract Raw X and Y coordinates of the public key */ + rc = wc_ecc_export_public_raw(info->pk.eccverify.key, + pubKeyX, &pubKeyX_len, + pubKeyY, &pubKeyY_len); + if (rc == 0) { + /* Extract R and S from signature */ + XMEMSET(sigRS, 0, sizeof(sigRS)); + r = &sigRS[0]; + s = &sigRS[key_sz]; + rc = wc_ecc_sig_to_rs(info->pk.eccverify.sig, + info->pk.eccverify.siglen, r, &r_len, s, &s_len); + (void)r_len; + (void)s_len; + } + if (rc == 0) { + /* Verify signature */ + rc = stsafe_interface_verify(curve_id, + (uint8_t*)info->pk.eccverify.hash, sigRS, pubKeyX, pubKeyY, + (int32_t*)info->pk.eccverify.res); + if (rc != STSAFE_A_OK) { + #ifdef USE_STSAFE_VERBOSE + STSAFE_INTERFACE_PRINTF("stsafe_interface_verify error: %d\n", rc); + #endif + rc = WC_HW_E; + } + } + } + else if (info->pk.type == WC_PK_TYPE_ECDH) { + byte otherKeyX[STSAFE_MAX_KEY_LEN]; + byte otherKeyY[STSAFE_MAX_KEY_LEN]; + word32 otherKeyX_len = sizeof(otherKeyX); + word32 otherKeyY_len = sizeof(otherKeyY); + StSafeA_CurveId curve_id; + int ecc_curve; + + WOLFSSL_MSG("STSAFE: PMS"); + + if (info->pk.ecdh.public_key == NULL) + return BAD_FUNC_ARG; + + /* get curve */ + ecc_curve = info->pk.ecdh.public_key->dp->id; + curve_id = stsafe_get_ecc_curve_id(ecc_curve); + + /* Export otherKey raw X and Y */ + rc = wc_ecc_export_public_raw(info->pk.ecdh.public_key, + &otherKeyX[0], (word32*)&otherKeyX_len, + &otherKeyY[0], (word32*)&otherKeyY_len); + if (rc == 0) { + /* Compute shared secret */ + *info->pk.ecdh.outlen = 0; + rc = stsafe_interface_shared_secret(curve_id, + otherKeyX, otherKeyY, + info->pk.ecdh.out, (int32_t*)info->pk.ecdh.outlen); + if (rc != STSAFE_A_OK) { + #ifdef USE_STSAFE_VERBOSE + STSAFE_INTERFACE_PRINTF("stsafe_interface_shared_secret error: %d\n", rc); + #endif + rc = WC_HW_E; + } + } + } + } +#endif /* HAVE_ECC */ + + /* need to return negative here for error */ + if (rc != 0 && rc != CRYPTOCB_UNAVAILABLE) { + WOLFSSL_MSG("STSAFE: CryptoCb failed"); + #ifdef USE_STSAFE_VERBOSE + STSAFE_INTERFACE_PRINTF("STSAFE: CryptoCb failed %d\n", rc); + #endif + rc = WC_HW_E; + } + + return rc; +} + +#endif /* WOLF_CRYPTO_CB */ + +#endif /* WOLFSSL_STSAFEA100 */ |