diff --git a/.wolfssl_known_macro_extras b/.wolfssl_known_macro_extras index d0987881fc9..f9c89b0c09d 100644 --- a/.wolfssl_known_macro_extras +++ b/.wolfssl_known_macro_extras @@ -545,6 +545,9 @@ STM32WL55xx STM32_AESGCM_PARTIAL STM32_HW_CLOCK_AUTO STM32_NUTTX_RNG +STSAFE_HOST_KEY_CIPHER +STSAFE_HOST_KEY_MAC +STSAFE_I2C_BUS TASK_EXTRA_STACK_SIZE TCP_NODELAY TFM_ALREADY_SET diff --git a/wolfcrypt/src/port/st/README.md b/wolfcrypt/src/port/st/README.md index 1dae1036fff..fc5baf42a8e 100644 --- a/wolfcrypt/src/port/st/README.md +++ b/wolfcrypt/src/port/st/README.md @@ -9,7 +9,9 @@ Support for the STM32 PKA on WB55, H7, MP13 and other devices with on-board public-key acceleration: - ECC192/ECC224/ECC256/ECC384 -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 wolfSSL's `stsafe_interface.c/.h` files. Please contact us at support@wolfssl.com to get this code. +Support for the STSAFE-A secure element family via I2C for ECC supporting NIST P-256/P-384 and Brainpool 256/384-bit curves: + - **STSAFE-A100/A110**: Uses ST's proprietary STSAFE-A1xx middleware. Contact us at support@wolfssl.com for integration assistance. + - **STSAFE-A120**: Uses ST's open-source [STSELib](https://github.com/STMicroelectronics/STSELib) (BSD-3 license). For details see our [wolfSSL ST](https://www.wolfssl.com/docs/stm32/) page. @@ -65,29 +67,69 @@ To enable support define the following When the support is enabled, the ECC operations will be accelerated using the PKA crypto co-processor. -## STSAFE-A100 ECC Acceleration +## STSAFE-A 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. +Using the wolfSSL PK callbacks or Crypto callbacks with the ST-Safe reference API's we support ECC operations for TLS client/server: + - **ECDSA Sign/Verify**: P-256 and P-384 (NIST and Brainpool curves) + - **ECDH Key Agreement**: For TLS key exchange + - **ECC Key Generation**: Ephemeral keys for TLS -At the wolfCrypt level we also support ECC native API's for `wc_ecc_*` using the ST-Safe. +At the wolfCrypt level we also support ECC native API's for `wc_ecc_*` using the ST-Safe via Crypto Callbacks. + +### Supported Hardware + +| Model | Macro | SDK | +|-------|-------|-----| +| STSAFE-A100/A110 | `WOLFSSL_STSAFEA100` | ST STSAFE-A1xx Middleware (proprietary) | +| STSAFE-A120 | `WOLFSSL_STSAFEA120` | [STSELib](https://github.com/STMicroelectronics/STSELib) (BSD-3, open source) | ### Building -`./configure --enable-pkcallbacks CFLAGS="-DWOLFSSL_STSAFEA100"` +For STSAFE-A100/A110 (legacy): -or +``` +./configure --enable-pkcallbacks CFLAGS="-DWOLFSSL_STSAFEA100" +``` -`#define HAVE_PK_CALLBACKS` -`#define WOLFSSL_STSAFEA100` +or in `user_settings.h`: +```c +#define HAVE_PK_CALLBACKS +#define WOLFSSL_STSAFEA100 +``` + +For STSAFE-A120 with STSELib: + +``` +./configure --enable-pkcallbacks CFLAGS="-DWOLFSSL_STSAFEA120" +``` + +or in `user_settings.h`: + +```c +#define HAVE_PK_CALLBACKS +#define WOLFSSL_STSAFEA120 +``` + +To use Crypto Callbacks (recommended for wolfCrypt-level ECC operations): + +```c +#define WOLF_CRYPTO_CB +#define WOLFSSL_STSAFEA120 /* or WOLFSSL_STSAFEA100 */ +``` ### Coding +#### Using PK Callbacks (TLS) + Setup the PK callbacks for TLS using: -``` -/* Setup PK Callbacks for STSAFE-A100 */ +```c +/* Setup PK Callbacks for STSAFE */ WOLFSSL_CTX* ctx; +SSL_STSAFE_SetupPkCallbacks(ctx); + +/* Or manually: */ wolfSSL_CTX_SetEccKeyGenCb(ctx, SSL_STSAFE_CreateKeyCb); wolfSSL_CTX_SetEccSignCb(ctx, SSL_STSAFE_SignCertificateCb); wolfSSL_CTX_SetEccVerifyCb(ctx, SSL_STSAFE_VerifyPeerCertCb); @@ -95,20 +137,131 @@ 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. +The reference STSAFE PK callback functions are located in the `wolfcrypt/src/port/st/stsafe.c` file. Adding a custom context to the callbacks: -``` +```c /* Setup PK Callbacks context */ WOLFSSL* ssl; void* myOwnCtx; -wolfSSL_SetEccKeyGenCtx(ssl, myOwnCtx); -wolfSSL_SetEccVerifyCtx(ssl, myOwnCtx); -wolfSSL_SetEccSignCtx(ssl, myOwnCtx); -wolfSSL_SetEccSharedSecretCtx(ssl, myOwnCtx); +SSL_STSAFE_SetupPkCallbackCtx(ssl, myOwnCtx); +``` + +#### Using Crypto Callbacks (wolfCrypt) + +For direct wolfCrypt ECC operations using the hardware: + +```c +#include + +/* Register the crypto callback */ +wolfSTSAFE_CryptoCb_Ctx stsafeCtx; +stsafeCtx.devId = WOLF_STSAFE_DEVID; +wc_CryptoCb_RegisterDevice(WOLF_STSAFE_DEVID, wolfSSL_STSAFE_CryptoDevCb, &stsafeCtx); + +/* Use with ECC operations */ +ecc_key key; +wc_ecc_init_ex(&key, NULL, WOLF_STSAFE_DEVID); +/* ECC operations will now use STSAFE hardware */ ``` +### Implementation Details + +The STSAFE support is self-contained in `wolfcrypt/src/port/st/stsafe.c` with SDK-specific implementations selected at compile time: + +| Macro | SDK | Description | +|-------|-----|-------------| +| `WOLFSSL_STSAFEA100` | STSAFE-A1xx Middleware | ST's proprietary SDK for A100/A110 | +| `WOLFSSL_STSAFEA120` | [STSELib](https://github.com/STMicroelectronics/STSELib) | ST's open-source SDK for A120 (BSD-3) | + +#### External Interface (Backwards Compatibility) + +For customers with existing custom implementations, define `WOLFSSL_STSAFE_INTERFACE_EXTERNAL` to use an external `stsafe_interface.h` file instead of the built-in implementation: + +```c +#define WOLFSSL_STSAFEA100 /* or WOLFSSL_STSAFEA120 */ +#define WOLFSSL_STSAFE_INTERFACE_EXTERNAL +``` + +When `WOLFSSL_STSAFE_INTERFACE_EXTERNAL` is defined, the customer must provide a `stsafe_interface.h` header that defines: + +| Item | Type | Description | +|------|------|-------------| +| `stsafe_curve_id_t` | typedef | Curve identifier type | +| `stsafe_slot_t` | typedef | Key slot identifier type | +| `STSAFE_ECC_CURVE_P256` | macro | P-256 curve ID value | +| `STSAFE_ECC_CURVE_P384` | macro | P-384 curve ID value | +| `STSAFE_KEY_SLOT_0/1/EPHEMERAL` | macros | Key slot values | +| `STSAFE_A_OK` | macro | Success return code | +| `STSAFE_MAX_KEY_LEN` | macro | Max key size in bytes (48) | +| `STSAFE_MAX_PUBKEY_RAW_LEN` | macro | Max public key size (96) | +| `STSAFE_MAX_SIG_LEN` | macro | Max signature size (96) | + +And provide implementations for these internal interface functions: +- `int stsafe_interface_init(void)` +- `int stsafe_create_key(stsafe_slot_t*, stsafe_curve_id_t, uint8_t*)` +- `int stsafe_sign(stsafe_slot_t, stsafe_curve_id_t, uint8_t*, uint8_t*)` +- `int stsafe_verify(stsafe_curve_id_t, uint8_t*, uint8_t*, uint8_t*, uint8_t*, int32_t*)` +- `int stsafe_shared_secret(stsafe_slot_t, stsafe_curve_id_t, uint8_t*, uint8_t*, uint8_t*, int32_t*)` +- `int stsafe_read_certificate(uint8_t**, uint32_t*)` +- `int stsafe_get_random(uint8_t*, uint32_t)` (if `USE_STSAFE_RNG_SEED` defined) + +When **NOT** defined (default behavior): All code is self-contained in `stsafe.c` using the appropriate SDK automatically. + +The implementation provides these internal operations: + +| Operation | Description | +|-----------|-------------| +| `stsafe_interface_init()` | Initialize the STSAFE device (called by `wolfCrypt_Init()`) | +| `stsafe_sign()` | ECDSA signature generation (P-256/P-384) | +| `stsafe_verify()` | ECDSA signature verification (P-256/P-384) | +| `stsafe_create_key()` | Generate ECC key pair on device | +| `stsafe_shared_secret()` | ECDH shared secret computation | +| `stsafe_read_certificate()` | Read device certificate from secure storage | + +### STSELib Setup (A120) + +For STSAFE-A120, you need to include the STSELib library: + +1. Clone STSELib as a submodule or add to your project: + ```bash + git submodule add https://github.com/STMicroelectronics/STSELib.git lib/stselib + ``` + +2. Add STSELib headers to your include path + +3. Implement the platform abstraction files required by STSELib: + - `stse_conf.h` - Configuration (target device, features) + - `stse_platform_generic.h` - Platform callbacks (I2C, timing) + +4. See STSELib documentation for platform-specific integration details + +### Raspberry Pi with STSAFE-A120 + +For testing on a Raspberry Pi with an STSAFE-A120 connected via I2C: + +1. **Enable I2C** on the Raspberry Pi: + ```bash + sudo raspi-config + # Navigate to: Interface Options -> I2C -> Enable + ``` + +2. **Verify the STSAFE device is detected** (default I2C address is 0x20): + ```bash + sudo i2cdetect -y 1 + ``` + +3. **Build wolfSSL with STSAFE-A120 support**: + ```bash + ./configure --enable-pkcallbacks --enable-cryptocb \ + CFLAGS="-DWOLFSSL_STSAFEA120 -I/path/to/STSELib" + make + sudo make install + ``` + +4. **Platform abstraction**: Implement the STSELib I2C callbacks using the Linux I2C driver (`/dev/i2c-1`). + ### Benchmarks and Memory Use Software only implementation (STM32L4 120Mhz, Cortex-M4, Fast Math): diff --git a/wolfcrypt/src/port/st/stsafe.c b/wolfcrypt/src/port/st/stsafe.c index 832b702148c..7296974e4d4 100644 --- a/wolfcrypt/src/port/st/stsafe.c +++ b/wolfcrypt/src/port/st/stsafe.c @@ -28,48 +28,927 @@ #include #ifndef STSAFE_INTERFACE_PRINTF -#define STSAFE_INTERFACE_PRINTF(...) WC_DO_NOTHING + #define STSAFE_INTERFACE_PRINTF(...) WC_DO_NOTHING #endif -#ifdef WOLFSSL_STSAFEA100 +/* Combined STSAFE macro - set in stsafe.h when either A100/A120 is defined */ +#ifdef WOLFSSL_STSAFE + +/* ========================================================================== */ +/* Internal Implementation (when NOT using external stsafe_interface.h) */ +/* ========================================================================== */ + +/* When WOLFSSL_STSAFE_INTERFACE_EXTERNAL is defined, all internal + * implementation is skipped and the customer provides their own + * stsafe_interface.h with custom implementations. This maintains + * backwards compatibility with older integration approaches. */ +#ifndef WOLFSSL_STSAFE_INTERFACE_EXTERNAL + +/* ========================================================================== */ +/* SDK-Specific Includes */ +/* ========================================================================== */ + +#ifdef WOLFSSL_STSAFEA120 + /* STSELib includes for A120 */ + #include "stselib.h" +#else /* WOLFSSL_STSAFEA100 */ + /* Legacy STSAFE-A1xx SDK includes */ + #include + #include + #include + #include + #include + #include + #include + #include +#endif + +/* ========================================================================== */ +/* Global State */ +/* ========================================================================== */ + +#ifdef WOLFSSL_STSAFEA120 + /* STSELib handler */ + static stse_Handler_t g_stse_handler; + static int g_stse_initialized = 0; +#else /* WOLFSSL_STSAFEA100 */ + /* Legacy SDK handle */ + static void* g_stsafe_handle = NULL; + + /* Host MAC and Cipher Keys for secure communication */ + /* NOTE: These are example keys + * - real implementations should store securely */ + #ifndef STSAFE_HOST_KEY_MAC + static const uint8_t g_host_mac_key[16] = { + 0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, + 0x88, 0x99, 0xAA, 0xBB, 0xCC, 0xDD, 0xEE, 0xFF + }; + #endif + #ifndef STSAFE_HOST_KEY_CIPHER + static const uint8_t g_host_cipher_key[16] = { + 0x11, 0x11, 0x22, 0x22, 0x33, 0x33, 0x44, 0x44, + 0x55, 0x55, 0x66, 0x66, 0x77, 0x77, 0x88, 0x88 + }; + #endif +#endif + +/* Current curve mode for signing operations */ +static stsafe_curve_id_t g_stsafe_curve_mode = STSAFE_DEFAULT_CURVE; + + +/* ========================================================================== */ +/* Internal Helper Functions */ +/* ========================================================================== */ + +/** + * \brief Get key size in bytes for a given curve + */ +static int stsafe_get_key_size(stsafe_curve_id_t curve_id) +{ + switch (curve_id) { + case STSAFE_ECC_CURVE_P256: + #ifdef STSAFE_ECC_CURVE_BP256 + case STSAFE_ECC_CURVE_BP256: + #endif + return 32; + case STSAFE_ECC_CURVE_P384: + #ifdef STSAFE_ECC_CURVE_BP384 + case STSAFE_ECC_CURVE_BP384: + #endif + return 48; + default: + break; + } + return 0; +} + +/** + * \brief Convert wolfSSL ECC curve ID to STSAFE curve ID + */ +static stsafe_curve_id_t stsafe_get_ecc_curve_id(int ecc_curve) +{ + switch (ecc_curve) { + case ECC_SECP256R1: + return STSAFE_ECC_CURVE_P256; + case ECC_SECP384R1: + return STSAFE_ECC_CURVE_P384; + #if defined(HAVE_ECC_BRAINPOOL) && defined(STSAFE_ECC_CURVE_BP256) + case ECC_BRAINPOOLP256R1: + return STSAFE_ECC_CURVE_BP256; + #endif + #if defined(HAVE_ECC_BRAINPOOL) && defined(STSAFE_ECC_CURVE_BP384) + case ECC_BRAINPOOLP384R1: + return STSAFE_ECC_CURVE_BP384; + #endif + default: + break; + } + return STSAFE_DEFAULT_CURVE; +} + +/** + * \brief Convert STSAFE curve ID to wolfSSL ECC curve ID + */ +#if !defined(WOLFCRYPT_ONLY) && defined(HAVE_PK_CALLBACKS) +static int stsafe_get_ecc_curve(stsafe_curve_id_t curve_id) +{ + switch (curve_id) { + case STSAFE_ECC_CURVE_P256: + return ECC_SECP256R1; + case STSAFE_ECC_CURVE_P384: + return ECC_SECP384R1; + #if defined(HAVE_ECC_BRAINPOOL) && defined(STSAFE_ECC_CURVE_BP256) + case STSAFE_ECC_CURVE_BP256: + return ECC_BRAINPOOLP256R1; + #endif + #if defined(HAVE_ECC_BRAINPOOL) && defined(STSAFE_ECC_CURVE_BP384) + case STSAFE_ECC_CURVE_BP384: + return ECC_BRAINPOOLP384R1; + #endif + default: + break; + } + return ECC_SECP256R1; +} +#endif + +/** + * \brief Get current curve mode for signing + */ +static stsafe_curve_id_t stsafe_get_curve_mode(void) +{ + return g_stsafe_curve_mode; +} + +/** + * \brief Set current curve mode for signing + */ +static int stsafe_set_curve_mode(stsafe_curve_id_t curve_id) +{ + g_stsafe_curve_mode = curve_id; + return 0; +} + +/* Unused function workaround for some compilers */ +#ifdef __GNUC__ +__attribute__((unused)) +#endif +static void stsafe_unused_funcs(void) +{ +#if !defined(WOLFCRYPT_ONLY) && defined(HAVE_PK_CALLBACKS) + (void)stsafe_get_ecc_curve; +#endif + (void)stsafe_set_curve_mode; +} + +/* ========================================================================== */ +/* Internal Interface Functions - SDK Specific Implementations */ +/* ========================================================================== */ + +#ifdef WOLFSSL_STSAFEA120 +/* -------------------------------------------------------------------------- */ +/* STSELib (A120) Implementation */ +/* -------------------------------------------------------------------------- */ + +/** + * \brief Initialize STSAFE-A120 device using STSELib + */ +int stsafe_interface_init(void) +{ + int rc = 0; + stse_ReturnCode_t ret; + + if (g_stse_initialized) { + return 0; /* Already initialized */ + } + + /* Set default handler values */ + ret = stse_set_default_handler_value(&g_stse_handler); + if (ret != STSE_OK) { + STSAFE_INTERFACE_PRINTF("stse_set_default_handler_value error: %d\n", + ret); + rc = -1; + } + + if (rc == 0) { + /* Configure for STSAFE-A120 on I2C bus 1 */ + g_stse_handler.device_type = STSAFE_A120; + #ifdef STSAFE_I2C_BUS + g_stse_handler.io.busID = STSAFE_I2C_BUS; + #else + g_stse_handler.io.busID = 1; + #endif + g_stse_handler.io.BusSpeed = 400; /* 400 kHz */ + + /* Initialize STSELib - this sets up I2C communication */ + ret = stse_init(&g_stse_handler); + if (ret != STSE_OK) { + STSAFE_INTERFACE_PRINTF("stse_init error: %d\n", ret); + rc = -1; + } + } + + if (rc == 0) { + g_stse_initialized = 1; + #ifdef USE_STSAFE_VERBOSE + WOLFSSL_MSG("STSAFE-A120 (STSELib) initialized"); + #endif + } + + return rc; +} + +/** + * \brief Generate ECC key pair on STSAFE-A120 + */ +static int stsafe_create_key(stsafe_slot_t* pSlot, stsafe_curve_id_t curve_id, + uint8_t* pPubKeyRaw) +{ + int rc = STSAFE_A_OK; + stse_ReturnCode_t ret; + stsafe_slot_t slot = STSAFE_KEY_SLOT_1; /* Ephemeral slot */ + + /* Generate key pair - public key is X||Y concatenated */ + ret = stse_generate_ecc_key_pair(&g_stse_handler, slot, curve_id, + 255, /* usage_limit */ + pPubKeyRaw); + if (ret != STSE_OK) { + STSAFE_INTERFACE_PRINTF("stse_generate_ecc_key_pair error: %d\n", ret); + rc = (int)ret; + } + + if (rc == STSAFE_A_OK && pSlot != NULL) { + *pSlot = slot; + } + + return rc; +} + +/** + * \brief ECDSA sign using STSAFE-A120 + */ +static int stsafe_sign(stsafe_slot_t slot, stsafe_curve_id_t curve_id, + uint8_t* pHash, uint8_t* pSigRS) +{ + int rc = STSAFE_A_OK; + stse_ReturnCode_t ret; + int key_sz = stsafe_get_key_size(curve_id); + + /* Sign hash - output is R || S concatenated */ + ret = stse_ecc_generate_signature(&g_stse_handler, slot, curve_id, + pHash, (uint16_t)key_sz, pSigRS); + if (ret != STSE_OK) { + STSAFE_INTERFACE_PRINTF("stse_ecc_generate_signature error: %d\n", ret); + rc = (int)ret; + } + + return rc; +} + +/** + * \brief ECDSA verify using STSAFE-A120 + */ +static int stsafe_verify(stsafe_curve_id_t curve_id, uint8_t* pHash, + uint8_t* pSigRS, uint8_t* pPubKeyX, uint8_t* pPubKeyY, + int32_t* pResult) +{ + int rc = STSAFE_A_OK; + stse_ReturnCode_t ret; + int key_sz = stsafe_get_key_size(curve_id); + uint8_t pubKey[STSAFE_MAX_PUBKEY_RAW_LEN]; + uint8_t validity = 0; + + /* Combine X and Y into single buffer (X||Y) */ + XMEMCPY(pubKey, pPubKeyX, key_sz); + XMEMCPY(pubKey + key_sz, pPubKeyY, key_sz); + + /* Verify signature - pMessage is the hash, pSignature is R||S */ + ret = stse_ecc_verify_signature(&g_stse_handler, curve_id, + pubKey, /* public key X||Y */ + pSigRS, /* signature R||S */ + pHash, /* message (hash) */ + (uint16_t)key_sz, /* message length */ + 0, /* eddsa_variant (0 for non-EdDSA) */ + &validity); + if (ret != STSE_OK) { + STSAFE_INTERFACE_PRINTF("stse_ecc_verify_signature error: %d\n", ret); + *pResult = 0; + rc = (int)ret; + } + + if (rc == STSAFE_A_OK) { + *pResult = (validity != 0) ? 1 : 0; + } + + return rc; +} + +/** + * \brief ECDH shared secret using STSAFE-A120 + */ +static int stsafe_shared_secret(stsafe_slot_t slot, stsafe_curve_id_t curve_id, + uint8_t* pPubKeyX, uint8_t* pPubKeyY, + uint8_t* pSharedSecret, + int32_t* pSharedSecretLen) +{ + int rc = STSAFE_A_OK; + stse_ReturnCode_t ret; + int key_sz = stsafe_get_key_size(curve_id); + uint8_t peerPubKey[STSAFE_MAX_PUBKEY_RAW_LEN]; + + /* Combine peer X and Y (X||Y format) */ + XMEMCPY(peerPubKey, pPubKeyX, key_sz); + XMEMCPY(peerPubKey + key_sz, pPubKeyY, key_sz); + + /* Compute shared secret */ + ret = stse_ecc_establish_shared_secret(&g_stse_handler, slot, curve_id, + peerPubKey, pSharedSecret); + if (ret != STSE_OK) { + STSAFE_INTERFACE_PRINTF("stse_ecc_establish_shared_secret error: %d\n", + ret); + rc = (int)ret; + } + + if (rc == STSAFE_A_OK) { + *pSharedSecretLen = (int32_t)key_sz; + } + + return rc; +} + +/** + * \brief Read device certificate from STSAFE-A120 + */ +static int stsafe_read_certificate(uint8_t** ppCert, uint32_t* pCertLen) +{ +#ifdef WOLFSSL_NO_MALLOC + /* Certificate reading requires dynamic allocation */ + (void)ppCert; + (void)pCertLen; + return NOT_COMPILED_IN; +#else + int rc = STSAFE_A_OK; + stse_ReturnCode_t ret; + uint16_t certLen = 0; + uint8_t certZone = 0; /* Certificate zone 0 */ + + /* First, get certificate size */ + ret = stse_get_device_certificate_size(&g_stse_handler, certZone, &certLen); + if (ret != STSE_OK || certLen == 0) { + STSAFE_INTERFACE_PRINTF("stse_get_device_certificate_size error: %d\n", + ret); + rc = (int)ret; + } + + /* Allocate buffer */ + if (rc == STSAFE_A_OK) { + *ppCert = (uint8_t*)XMALLOC(certLen, NULL, DYNAMIC_TYPE_TMP_BUFFER); + if (*ppCert == NULL) { + rc = MEMORY_E; + } + } + + /* Read certificate */ + if (rc == STSAFE_A_OK) { + ret = stse_get_device_certificate(&g_stse_handler, certZone, certLen, + *ppCert); + if (ret != STSE_OK) { + XFREE(*ppCert, NULL, DYNAMIC_TYPE_TMP_BUFFER); + *ppCert = NULL; + STSAFE_INTERFACE_PRINTF("stse_get_device_certificate error: %d\n", + ret); + rc = (int)ret; + } + } + + if (rc == STSAFE_A_OK) { + *pCertLen = certLen; + } + + return rc; +#endif /* WOLFSSL_NO_MALLOC */ +} + +#if !defined(WC_NO_RNG) && defined(USE_STSAFE_RNG_SEED) +/** + * \brief Get random bytes from STSAFE-A120 + */ +static int stsafe_get_random(uint8_t* pRandom, uint32_t size) +{ + int rc; + stse_ReturnCode_t ret; + uint16_t len = (size > 0xFFFF) ? 0xFFFF : (uint16_t)size; + + ret = stse_generate_random(&g_stse_handler, pRandom, len); + if (ret != STSE_OK) { + rc = -1; + } + else { + rc = (int)len; + } + + return rc; +} +#endif + +#else /* WOLFSSL_STSAFEA100 */ +/* -------------------------------------------------------------------------- */ +/* Legacy STSAFE-A1xx SDK (A100/A110) Implementation */ +/* -------------------------------------------------------------------------- */ + +/** + * \brief Set host keys for secure communication + */ +static void stsafe_set_host_keys(void* handle) +{ + StSafeA_SetHostMacKey(handle, g_host_mac_key); + StSafeA_SetHostCipherKey(handle, g_host_cipher_key); +} + +/** + * \brief Check and initialize host keys + */ +static int stsafe_check_host_keys(void* handle) +{ + uint8_t status_code; + StSafeA_HostKeySlotBuffer* pHostKeySlot; + + status_code = StSafeA_HostKeySlotQuery(handle, &pHostKeySlot, + STSAFE_A_NO_MAC); + + if (status_code == STSAFE_A_OK && !pHostKeySlot->HostKeyPresenceFlag) { + /* Host keys not set, initialize them */ + uint8_t hostKeys[32]; + XMEMCPY(hostKeys, g_host_mac_key, 16); + XMEMCPY(hostKeys + 16, g_host_cipher_key, 16); + + status_code = StSafeA_PutAttribute(handle, STSAFE_A_HOST_KEY_SLOT_TAG, + hostKeys, sizeof(hostKeys), STSAFE_A_NO_MAC); + } + + return status_code; +} + +/** + * \brief Initialize STSAFE-A100/A110 device + */ +int stsafe_interface_init(void) +{ + int rc = 0; + uint8_t status_code; + const uint8_t echo_data[3] = {0x01, 0x02, 0x03}; + StSafeA_EchoBuffer* echo_resp = NULL; + + if (g_stsafe_handle != NULL) { + return 0; /* Already initialized */ + } + + /* Create handle */ + status_code = StSafeA_CreateHandle(&g_stsafe_handle, STSAFE_I2C_ADDR); + if (status_code != STSAFE_A_OK) { + STSAFE_INTERFACE_PRINTF("StSafeA_CreateHandle error: %d\n", + status_code); + rc = -1; + } + + /* Echo test to verify communication */ + if (rc == 0) { + status_code = StSafeA_Echo(g_stsafe_handle, (uint8_t*)echo_data, 3, + &echo_resp, STSAFE_A_NO_MAC); + if (status_code != STSAFE_A_OK || + XMEMCMP(echo_data, echo_resp->Data, 3) != 0) { + STSAFE_INTERFACE_PRINTF("StSafeA_Echo error: %d\n", status_code); + rc = -1; + } + XFREE(echo_resp, NULL, DYNAMIC_TYPE_TMP_BUFFER); + } + + /* Check/initialize host keys */ + if (rc == 0) { + status_code = stsafe_check_host_keys(g_stsafe_handle); + if (status_code != STSAFE_A_OK) { + STSAFE_INTERFACE_PRINTF("stsafe_check_host_keys error: %d\n", + status_code); + rc = -1; + } + } + +#ifdef USE_STSAFE_VERBOSE + if (rc == 0) { + WOLFSSL_MSG("STSAFE-A100/A110 initialized"); + } +#endif + + return rc; +} + +/** + * \brief Generate ECC key pair on STSAFE-A100/A110 + */ +static int stsafe_create_key(stsafe_slot_t* pSlot, stsafe_curve_id_t curve_id, + uint8_t* pPubKeyRaw) +{ + int rc; + uint8_t status_code; + int key_sz = stsafe_get_key_size(curve_id); + stsafe_slot_t slot = STSAFE_KEY_SLOT_1; + StSafeA_CoordinateBuffer* pubX = NULL; + StSafeA_CoordinateBuffer* pubY = NULL; + uint8_t* pointRepId = NULL; + + stsafe_set_host_keys(g_stsafe_handle); + + status_code = StSafeA_GenerateKeyPair(g_stsafe_handle, slot, 0xFFFF, 1, + (StSafeA_KeyUsageAuthorizationFlags)( + STSAFE_A_COMMAND_RESPONSE_SIGNATURE | + STSAFE_A_MESSAGE_DIGEST_SIGNATURE | + STSAFE_A_KEY_ESTABLISHMENT), + curve_id, &pointRepId, &pubX, &pubY, STSAFE_A_HOST_C_MAC); + + if (status_code == STSAFE_A_OK && pointRepId != NULL && + *pointRepId == STSAFE_A_POINT_REPRESENTATION_ID) { + XMEMCPY(pPubKeyRaw, pubX->Data, pubX->Length); + XMEMCPY(pPubKeyRaw + key_sz, pubY->Data, pubY->Length); + rc = STSAFE_A_OK; + } + else { + rc = (int)(uint8_t)-1; + } + + /* Free SDK-allocated buffers */ + XFREE(pubX, NULL, DYNAMIC_TYPE_TMP_BUFFER); + XFREE(pubY, NULL, DYNAMIC_TYPE_TMP_BUFFER); + + if (rc == STSAFE_A_OK && pSlot != NULL) { + *pSlot = slot; + } + + return rc; +} + +/** + * \brief ECDSA sign using STSAFE-A100/A110 + */ +static int stsafe_sign(stsafe_slot_t slot, stsafe_curve_id_t curve_id, + uint8_t* pHash, uint8_t* pSigRS) +{ + int rc; + uint8_t status_code; + int key_sz = stsafe_get_key_size(curve_id); + StSafeA_SignatureBuffer* signature = NULL; + StSafeA_HashTypes hashType; + size_t r_length, s_length; + + hashType = (curve_id == STSAFE_ECC_CURVE_P384 || + curve_id == STSAFE_ECC_CURVE_BP384) ? + STSAFE_HASH_SHA384 : STSAFE_HASH_SHA256; + + status_code = StSafeA_GenerateSignature(g_stsafe_handle, slot, pHash, + hashType, &signature, STSAFE_A_NO_MAC); + + if (status_code == STSAFE_A_OK && signature != NULL) { + /* Parse signature - format is: len(2) || R || len(2) || S */ + r_length = ((uint16_t)signature->Data[0] << 8) | signature->Data[1]; + s_length = ((uint16_t)signature->Data[2 + r_length] << 8) | + signature->Data[3 + r_length]; + + /* Copy R and S to output (zero-padded) */ + XMEMSET(pSigRS, 0, key_sz * 2); + XMEMCPY(pSigRS + (key_sz - r_length), &signature->Data[2], r_length); + XMEMCPY(pSigRS + key_sz + (key_sz - s_length), + &signature->Data[4 + r_length], s_length); + rc = STSAFE_A_OK; + } + else { + rc = (int)status_code; + } + + /* Free SDK-allocated buffer */ + XFREE(signature, NULL, DYNAMIC_TYPE_TMP_BUFFER); + + return rc; +} + +/** + * \brief ECDSA verify using STSAFE-A100/A110 + */ +static int stsafe_verify(stsafe_curve_id_t curve_id, uint8_t* pHash, + uint8_t* pSigRS, uint8_t* pPubKeyX, uint8_t* pPubKeyY, + int32_t* pResult) +{ + int rc = (int)(uint8_t)-1; + uint8_t status_code; + int key_sz = stsafe_get_key_size(curve_id); +#if defined(WOLFSSL_SMALL_STACK) && !defined(WOLFSSL_NO_MALLOC) + StSafeA_CoordinateBuffer* X = NULL; + StSafeA_CoordinateBuffer* Y = NULL; + StSafeA_SignatureBuffer* R = NULL; + StSafeA_SignatureBuffer* S = NULL; + StSafeA_SignatureBuffer* Hash = NULL; +#else + /* Stack buffers: 2 bytes for Length + STSAFE_MAX_KEY_LEN for Data */ + byte R_buf[2 + STSAFE_MAX_KEY_LEN]; + byte S_buf[2 + STSAFE_MAX_KEY_LEN]; + byte Hash_buf[2 + STSAFE_MAX_KEY_LEN]; + byte X_buf[2 + STSAFE_MAX_KEY_LEN]; + byte Y_buf[2 + STSAFE_MAX_KEY_LEN]; + StSafeA_SignatureBuffer* R = (StSafeA_SignatureBuffer*)R_buf; + StSafeA_SignatureBuffer* S = (StSafeA_SignatureBuffer*)S_buf; + StSafeA_SignatureBuffer* Hash = (StSafeA_SignatureBuffer*)Hash_buf; + StSafeA_CoordinateBuffer* X = (StSafeA_CoordinateBuffer*)X_buf; + StSafeA_CoordinateBuffer* Y = (StSafeA_CoordinateBuffer*)Y_buf; +#endif + StSafeA_VerifySignatureBuffer* Verif = NULL; + + *pResult = 0; + +#if defined(WOLFSSL_SMALL_STACK) && !defined(WOLFSSL_NO_MALLOC) + /* Allocate buffers */ + R = (StSafeA_SignatureBuffer*)XMALLOC(key_sz + 2, NULL, + DYNAMIC_TYPE_TMP_BUFFER); + S = (StSafeA_SignatureBuffer*)XMALLOC(key_sz + 2, NULL, + DYNAMIC_TYPE_TMP_BUFFER); + Hash = (StSafeA_SignatureBuffer*)XMALLOC(key_sz + 2, NULL, + DYNAMIC_TYPE_TMP_BUFFER); + X = (StSafeA_CoordinateBuffer*)XMALLOC(key_sz + 2, NULL, + DYNAMIC_TYPE_TMP_BUFFER); + Y = (StSafeA_CoordinateBuffer*)XMALLOC(key_sz + 2, NULL, + DYNAMIC_TYPE_TMP_BUFFER); + + if (X == NULL || Y == NULL || R == NULL || S == NULL || Hash == NULL) { + XFREE(R, NULL, DYNAMIC_TYPE_TMP_BUFFER); + XFREE(S, NULL, DYNAMIC_TYPE_TMP_BUFFER); + XFREE(Hash, NULL, DYNAMIC_TYPE_TMP_BUFFER); + XFREE(X, NULL, DYNAMIC_TYPE_TMP_BUFFER); + XFREE(Y, NULL, DYNAMIC_TYPE_TMP_BUFFER); + return MEMORY_E; + } +#endif + + R->Length = key_sz; + S->Length = key_sz; + Hash->Length = key_sz; + X->Length = key_sz; + Y->Length = key_sz; + + XMEMCPY(R->Data, pSigRS, key_sz); + XMEMCPY(S->Data, pSigRS + key_sz, key_sz); + XMEMCPY(Hash->Data, pHash, key_sz); + XMEMCPY(X->Data, pPubKeyX, key_sz); + XMEMCPY(Y->Data, pPubKeyY, key_sz); + + status_code = StSafeA_VerifyMessageSignature(g_stsafe_handle, + curve_id, X, Y, R, S, Hash, &Verif, STSAFE_A_NO_MAC); + + if (status_code == STSAFE_A_OK && Verif != NULL) { + *pResult = Verif->SignatureValidity ? 1 : 0; + if (Verif->SignatureValidity) { + rc = STSAFE_A_OK; + } + } +#ifndef WOLFSSL_NO_MALLOC + /* Free SDK-allocated buffer */ + XFREE(Verif, NULL, DYNAMIC_TYPE_TMP_BUFFER); +#endif + +#if defined(WOLFSSL_SMALL_STACK) && !defined(WOLFSSL_NO_MALLOC) + XFREE(R, NULL, DYNAMIC_TYPE_TMP_BUFFER); + XFREE(S, NULL, DYNAMIC_TYPE_TMP_BUFFER); + XFREE(Hash, NULL, DYNAMIC_TYPE_TMP_BUFFER); + XFREE(X, NULL, DYNAMIC_TYPE_TMP_BUFFER); + XFREE(Y, NULL, DYNAMIC_TYPE_TMP_BUFFER); +#endif + + return rc; +} + +/** + * \brief ECDH shared secret using STSAFE-A100/A110 + */ +static int stsafe_shared_secret(stsafe_slot_t slot, stsafe_curve_id_t curve_id, + uint8_t* pPubKeyX, uint8_t* pPubKeyY, + uint8_t* pSharedSecret, + int32_t* pSharedSecretLen) +{ + int rc = (int)(uint8_t)-1; + uint8_t status_code; + int key_sz = stsafe_get_key_size(curve_id); +#if defined(WOLFSSL_SMALL_STACK) && !defined(WOLFSSL_NO_MALLOC) + StSafeA_CoordinateBuffer* peerX = NULL; + StSafeA_CoordinateBuffer* peerY = NULL; +#else + /* Stack buffers: 2 bytes for Length + STSAFE_MAX_KEY_LEN for Data */ + byte peerX_buf[2 + STSAFE_MAX_KEY_LEN]; + byte peerY_buf[2 + STSAFE_MAX_KEY_LEN]; + StSafeA_CoordinateBuffer* peerX = (StSafeA_CoordinateBuffer*)peerX_buf; + StSafeA_CoordinateBuffer* peerY = (StSafeA_CoordinateBuffer*)peerY_buf; +#endif + StSafeA_SharedSecretBuffer* sharedSecret = NULL; + + stsafe_set_host_keys(g_stsafe_handle); + +#if defined(WOLFSSL_SMALL_STACK) && !defined(WOLFSSL_NO_MALLOC) + peerX = (StSafeA_CoordinateBuffer*)XMALLOC(key_sz + 2, NULL, + DYNAMIC_TYPE_TMP_BUFFER); + peerY = (StSafeA_CoordinateBuffer*)XMALLOC(key_sz + 2, NULL, + DYNAMIC_TYPE_TMP_BUFFER); + + if (peerX == NULL || peerY == NULL) { + XFREE(peerX, NULL, DYNAMIC_TYPE_TMP_BUFFER); + XFREE(peerY, NULL, DYNAMIC_TYPE_TMP_BUFFER); + return MEMORY_E; + } +#endif + + peerX->Length = key_sz; + peerY->Length = key_sz; + XMEMCPY(peerX->Data, pPubKeyX, key_sz); + XMEMCPY(peerY->Data, pPubKeyY, key_sz); + + status_code = StSafeA_EstablishKey(g_stsafe_handle, slot, + peerX, peerY, &sharedSecret, STSAFE_A_HOST_C_MAC); + + if (status_code == STSAFE_A_OK && sharedSecret != NULL) { + *pSharedSecretLen = sharedSecret->SharedSecret.Length; + XMEMCPY(pSharedSecret, sharedSecret->SharedSecret.Data, + sharedSecret->SharedSecret.Length); + rc = STSAFE_A_OK; + } +#ifndef WOLFSSL_NO_MALLOC + /* Free SDK-allocated buffer */ + XFREE(sharedSecret, NULL, DYNAMIC_TYPE_TMP_BUFFER); +#endif +#if defined(WOLFSSL_SMALL_STACK) && !defined(WOLFSSL_NO_MALLOC) + XFREE(peerX, NULL, DYNAMIC_TYPE_TMP_BUFFER); + XFREE(peerY, NULL, DYNAMIC_TYPE_TMP_BUFFER); +#endif + + return rc; +} + +/** + * \brief Read device certificate from STSAFE-A100/A110 + */ +static int stsafe_read_certificate(uint8_t** ppCert, uint32_t* pCertLen) +{ +#ifdef WOLFSSL_NO_MALLOC + /* Certificate reading requires dynamic allocation */ + (void)ppCert; + (void)pCertLen; + return NOT_COMPILED_IN; +#else + int rc = STSAFE_A_OK; + uint8_t status_code; + StSafeA_ReadBuffer* readBuf = NULL; + struct stsafe_a* stsafe_a = (struct stsafe_a*)g_stsafe_handle; + uint8_t step; + uint16_t i; + + *pCertLen = 0; + + /* Read first 4 bytes to determine certificate length */ + status_code = StSafeA_Read(g_stsafe_handle, 0, 0, STSAFE_A_ALWAYS, + 0, 0, 4, &readBuf, STSAFE_A_NO_MAC); + + if (status_code == STSAFE_A_OK && readBuf->Length == 4 && + readBuf->Data[0] == 0x30) { + /* Parse ASN.1 length */ + switch (readBuf->Data[1]) { + case 0x81: + *pCertLen = readBuf->Data[2] + 3; + break; + case 0x82: + *pCertLen = ((uint16_t)readBuf->Data[2] << 8) + + readBuf->Data[3] + 4; + break; + default: + if (readBuf->Data[1] < 0x81) { + *pCertLen = readBuf->Data[1] + 2; + } + break; + } + } + else { + rc = (int)status_code; + } + XFREE(readBuf, NULL, DYNAMIC_TYPE_TMP_BUFFER); + readBuf = NULL; + + if (rc == STSAFE_A_OK && *pCertLen > 0) { + *ppCert = (uint8_t*)XMALLOC(*pCertLen, NULL, DYNAMIC_TYPE_TMP_BUFFER); + if (*ppCert == NULL) { + rc = (int)(uint8_t)-1; + } + } + + if (rc == STSAFE_A_OK && *pCertLen > 0) { + step = 223 - (stsafe_a->CrcSupport ? 2 : 0); + + for (i = 0; rc == STSAFE_A_OK && i < *pCertLen / step; i++) { + status_code = StSafeA_Read(g_stsafe_handle, 0, 0, + STSAFE_A_ALWAYS, 0, i * step, step, &readBuf, + STSAFE_A_NO_MAC); + if (status_code == STSAFE_A_OK) { + XMEMCPY(*ppCert + (i * step), readBuf->Data, readBuf->Length); + } + else { + rc = (int)status_code; + } + XFREE(readBuf, NULL, DYNAMIC_TYPE_TMP_BUFFER); + readBuf = NULL; + } + + if (rc == STSAFE_A_OK && (*pCertLen % step)) { + status_code = StSafeA_Read(g_stsafe_handle, 0, 0, + STSAFE_A_ALWAYS, 0, i * step, *pCertLen % step, + &readBuf, STSAFE_A_NO_MAC); + if (status_code == STSAFE_A_OK) { + XMEMCPY(*ppCert + (i * step), readBuf->Data, readBuf->Length); + } + else { + rc = (int)status_code; + } + XFREE(readBuf, NULL, DYNAMIC_TYPE_TMP_BUFFER); + readBuf = NULL; + } + } + + return rc; +#endif /* WOLFSSL_NO_MALLOC */ +} + +#if !defined(WC_NO_RNG) && defined(USE_STSAFE_RNG_SEED) +/** + * \brief Get random bytes from STSAFE-A100/A110 + */ +static int stsafe_get_random(uint8_t* pRandom, uint32_t size) +{ + int rc; + uint8_t status_code; + StSafeA_GenerateRandomBuffer* rndBuf = NULL; + uint8_t reqSize = (size > 255) ? 255 : (uint8_t)size; + + status_code = StSafeA_GenerateRandom(g_stsafe_handle, STSAFE_A_EPHEMERAL, + reqSize, &rndBuf, STSAFE_A_NO_MAC); + + if (status_code == STSAFE_A_OK && rndBuf != NULL) { + rc = (int)rndBuf->Length; + XMEMCPY(pRandom, rndBuf->Data, rndBuf->Length); + } + else { + rc = -1; + } + + XFREE(rndBuf, NULL, DYNAMIC_TYPE_TMP_BUFFER); + + return rc; +} +#endif + +#endif /* WOLFSSL_STSAFEA120 */ + +#endif /* !WOLFSSL_STSAFE_INTERFACE_EXTERNAL */ + + +/* ========================================================================== */ +/* Public API Functions */ +/* ========================================================================== */ + +/** + * \brief Load device certificate from STSAFE + */ int SSL_STSAFE_LoadDeviceCertificate(byte** pRawCertificate, word32* pRawCertificateLen) { - int err; + int err = 0; if (pRawCertificate == NULL || pRawCertificateLen == NULL) { - return BAD_FUNC_ARG; + err = 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 + if (err == 0) { + WOLFSSL_MSG("SSL_STSAFE_LoadDeviceCertificate"); } - else { - err = WC_HW_E; +#endif + + if (err == 0) { + err = stsafe_read_certificate(pRawCertificate, pRawCertificateLen); + if (err != STSAFE_A_OK) { + err = WC_HW_E; + } } return err; } -#ifdef HAVE_PK_CALLBACKS + +/* ========================================================================== */ +/* PK Callbacks */ +/* ========================================================================== */ + +#if !defined(WOLFCRYPT_ONLY) && defined(HAVE_PK_CALLBACKS) /** * \brief Key Gen Callback (used by TLS server) @@ -77,10 +956,14 @@ int SSL_STSAFE_LoadDeviceCertificate(byte** pRawCertificate, int SSL_STSAFE_CreateKeyCb(WOLFSSL* ssl, ecc_key* key, word32 keySz, int ecc_curve, void* ctx) { - int err; + int err = 0; +#if defined(WOLFSSL_SMALL_STACK) && !defined(WOLFSSL_NO_MALLOC) + byte* pubKeyRaw = NULL; +#else byte pubKeyRaw[STSAFE_MAX_PUBKEY_RAW_LEN]; - StSafeA_KeySlotNumber slot; - StSafeA_CurveId curve_id; +#endif + stsafe_slot_t slot; + stsafe_curve_id_t curve_id; (void)ssl; (void)ctx; @@ -89,28 +972,38 @@ int SSL_STSAFE_CreateKeyCb(WOLFSSL* ssl, ecc_key* key, word32 keySz, WOLFSSL_MSG("CreateKeyCb: STSAFE"); #endif - /* get curve */ - curve_id = stsafe_get_ecc_curve_id(ecc_curve); +#if defined(WOLFSSL_SMALL_STACK) && !defined(WOLFSSL_NO_MALLOC) + pubKeyRaw = (byte*)XMALLOC(STSAFE_MAX_PUBKEY_RAW_LEN, NULL, + DYNAMIC_TYPE_TMP_BUFFER); + if (pubKeyRaw == NULL) { + err = MEMORY_E; + } +#endif - /* 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; + if (err == 0) { + curve_id = stsafe_get_ecc_curve_id(ecc_curve); + + err = stsafe_create_key(&slot, curve_id, pubKeyRaw); + if (err != STSAFE_A_OK) { + STSAFE_INTERFACE_PRINTF("stsafe_create_key error: %d\n", err); + err = WC_HW_E; + } } - /* load generated public key into key, used by wolfSSL */ - err = wc_ecc_import_unsigned(key, &pubKeyRaw[0], &pubKeyRaw[keySz], - NULL, ecc_curve); + if (err == 0) { + err = wc_ecc_import_unsigned(key, pubKeyRaw, &pubKeyRaw[keySz], + NULL, ecc_curve); + } + +#if defined(WOLFSSL_SMALL_STACK) && !defined(WOLFSSL_NO_MALLOC) + XFREE(pubKeyRaw, NULL, DYNAMIC_TYPE_TMP_BUFFER); +#endif return err; } /** - * \brief Verify Peer Cert Callback. + * \brief Verify Peer Cert Callback */ int SSL_STSAFE_VerifyPeerCertCb(WOLFSSL* ssl, const unsigned char* sig, unsigned int sigSz, @@ -118,42 +1011,63 @@ int SSL_STSAFE_VerifyPeerCertCb(WOLFSSL* ssl, const unsigned char* keyDer, unsigned int keySz, int* result, void* ctx) { - int err; + int err = 0; + int eccKeyInit = 0; +#if defined(WOLFSSL_SMALL_STACK) && !defined(WOLFSSL_NO_MALLOC) + byte* sigRS = NULL; + byte* pubKeyX = NULL; + byte* pubKeyY = NULL; +#else byte sigRS[STSAFE_MAX_SIG_LEN]; - byte *r = NULL, *s = NULL; - 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; +#endif + byte* r = NULL; + byte* s = NULL; + word32 r_len = STSAFE_MAX_SIG_LEN/2, s_len = STSAFE_MAX_SIG_LEN/2; + word32 pubKeyX_len = STSAFE_MAX_PUBKEY_RAW_LEN/2; + word32 pubKeyY_len = STSAFE_MAX_PUBKEY_RAW_LEN/2; + ecc_key eccKey; word32 inOutIdx = 0; - StSafeA_CurveId curve_id = STSAFE_A_NIST_P_256; + stsafe_curve_id_t curve_id = STSAFE_ECC_CURVE_P256; int ecc_curve; int key_sz = 0; (void)ssl; (void)ctx; + (void)hashSz; #ifdef USE_STSAFE_VERBOSE WOLFSSL_MSG("VerifyPeerCertCB: STSAFE"); #endif - err = wc_ecc_init(&key); - if (err != 0) { - return err; +#if defined(WOLFSSL_SMALL_STACK) && !defined(WOLFSSL_NO_MALLOC) + sigRS = (byte*)XMALLOC(STSAFE_MAX_SIG_LEN, NULL, DYNAMIC_TYPE_TMP_BUFFER); + pubKeyX = (byte*)XMALLOC(STSAFE_MAX_PUBKEY_RAW_LEN/2, NULL, + DYNAMIC_TYPE_TMP_BUFFER); + pubKeyY = (byte*)XMALLOC(STSAFE_MAX_PUBKEY_RAW_LEN/2, NULL, + DYNAMIC_TYPE_TMP_BUFFER); + if (sigRS == NULL || pubKeyX == NULL || pubKeyY == NULL) { + err = MEMORY_E; } +#endif - /* 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, + err = wc_ecc_init(&eccKey); + if (err == 0) { + eccKeyInit = 1; + } + } + + if (err == 0) { + err = wc_EccPublicKeyDecode(keyDer, &inOutIdx, &eccKey, keySz); + } + if (err == 0) { + err = wc_ecc_export_public_raw(&eccKey, pubKeyX, &pubKeyX_len, pubKeyY, &pubKeyY_len); } if (err == 0) { - /* determine curve */ - ecc_curve = key.dp->id; + ecc_curve = eccKey.dp->id; curve_id = stsafe_get_ecc_curve_id(ecc_curve); key_sz = stsafe_get_key_size(curve_id); if (key_sz <= 0 || key_sz > STSAFE_MAX_KEY_LEN) { @@ -161,113 +1075,139 @@ int SSL_STSAFE_VerifyPeerCertCb(WOLFSSL* ssl, } } if (err == 0) { - /* Extract R and S from signature */ - XMEMSET(sigRS, 0, sizeof(sigRS)); + XMEMSET(sigRS, 0, STSAFE_MAX_SIG_LEN); r = &sigRS[0]; s = &sigRS[key_sz]; err = wc_ecc_sig_to_rs(sig, sigSz, r, &r_len, s, &s_len); } if (err == 0) { - /* make sure R and S are not too large */ - if (r_len > key_sz || s_len > key_sz) { + if ((int)r_len > key_sz || (int)s_len > key_sz) { err = BAD_FUNC_ARG; } } if (err == 0) { - /* make sure R and S are zero padded on front */ - XMEMMOVE(&sigRS[key_sz-r_len], r, r_len); - XMEMSET(&sigRS[0], 0, key_sz-r_len); - XMEMMOVE(&sigRS[key_sz + (key_sz-s_len)], s, s_len); - XMEMSET(&sigRS[key_sz], 0, key_sz-s_len); - - /* Verify signature */ - err = stsafe_interface_verify(curve_id, (uint8_t*)hash, sigRS, + /* Zero-pad R and S */ + XMEMMOVE(&sigRS[key_sz - r_len], r, r_len); + XMEMSET(&sigRS[0], 0, key_sz - r_len); + XMEMMOVE(&sigRS[key_sz + (key_sz - s_len)], s, s_len); + XMEMSET(&sigRS[key_sz], 0, key_sz - s_len); + + err = stsafe_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 = -err; + STSAFE_INTERFACE_PRINTF("stsafe_verify error: %d\n", err); + err = WC_HW_E; } } - wc_ecc_free(&key); + if (eccKeyInit) { + wc_ecc_free(&eccKey); + } + +#if defined(WOLFSSL_SMALL_STACK) && !defined(WOLFSSL_NO_MALLOC) + XFREE(sigRS, NULL, DYNAMIC_TYPE_TMP_BUFFER); + XFREE(pubKeyX, NULL, DYNAMIC_TYPE_TMP_BUFFER); + XFREE(pubKeyY, NULL, DYNAMIC_TYPE_TMP_BUFFER); +#endif + return err; } /** - * \brief Sign Certificate Callback. + * \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; + int err = 0; +#if defined(WOLFSSL_SMALL_STACK) && !defined(WOLFSSL_NO_MALLOC) + byte* digest = NULL; + byte* sigRS = NULL; +#else byte digest[STSAFE_MAX_KEY_LEN]; byte sigRS[STSAFE_MAX_SIG_LEN]; - byte *r, *s; - StSafeA_CurveId curve_id; +#endif + byte* r; + byte* s; + stsafe_curve_id_t curve_id; int key_sz; (void)ssl; (void)ctx; + (void)key; + (void)keySz; #ifdef USE_STSAFE_VERBOSE WOLFSSL_MSG("SignCertificateCb: STSAFE"); #endif - curve_id = stsafe_get_curve_mode(); - key_sz = stsafe_get_key_size(curve_id); +#if defined(WOLFSSL_SMALL_STACK) && !defined(WOLFSSL_NO_MALLOC) + digest = (byte*)XMALLOC(STSAFE_MAX_KEY_LEN, NULL, DYNAMIC_TYPE_TMP_BUFFER); + sigRS = (byte*)XMALLOC(STSAFE_MAX_SIG_LEN, NULL, DYNAMIC_TYPE_TMP_BUFFER); + if (digest == NULL || sigRS == NULL) { + err = MEMORY_E; + } +#endif - /* Build input digest */ - if (inSz > key_sz) - inSz = key_sz; - XMEMSET(&digest[0], 0, sizeof(digest)); - XMEMCPY(&digest[key_sz - inSz], in, inSz); + if (err == 0) { + curve_id = stsafe_get_curve_mode(); + key_sz = stsafe_get_key_size(curve_id); - /* 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; + if ((int)inSz > key_sz) + inSz = key_sz; + + XMEMSET(digest, 0, STSAFE_MAX_KEY_LEN); + XMEMCPY(&digest[key_sz - inSz], in, inSz); + + XMEMSET(sigRS, 0, STSAFE_MAX_SIG_LEN); + err = stsafe_sign(STSAFE_KEY_SLOT_0, curve_id, digest, sigRS); + if (err != STSAFE_A_OK) { + STSAFE_INTERFACE_PRINTF("stsafe_sign error: %d\n", err); + err = WC_HW_E; + } } - /* 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 + if (err == 0) { + r = &sigRS[0]; + s = &sigRS[key_sz]; + err = wc_ecc_rs_raw_to_sig(r, key_sz, s, key_sz, out, outSz); + if (err != 0) { + WOLFSSL_MSG("Error converting RS to Signature"); + } } +#if defined(WOLFSSL_SMALL_STACK) && !defined(WOLFSSL_NO_MALLOC) + XFREE(digest, NULL, DYNAMIC_TYPE_TMP_BUFFER); + XFREE(sigRS, NULL, DYNAMIC_TYPE_TMP_BUFFER); +#endif + return err; } - /** - * \brief Create pre master secret using peer's public key and self private key. + * \brief Shared Secret Callback (ECDH) */ 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; + int err = 0; + int tmpKeyInit = 0; +#if defined(WOLFSSL_SMALL_STACK) && !defined(WOLFSSL_NO_MALLOC) + byte* otherKeyX = NULL; + byte* otherKeyY = NULL; + byte* pubKeyRaw = NULL; +#else 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 = STSAFE_A_SLOT_0; - StSafeA_CurveId curve_id; +#endif + word32 otherKeyX_len = STSAFE_MAX_KEY_LEN; + word32 otherKeyY_len = STSAFE_MAX_KEY_LEN; + stsafe_slot_t slot = STSAFE_KEY_SLOT_0; + stsafe_curve_id_t curve_id; ecc_key tmpKey; int ecc_curve; int key_sz; @@ -279,92 +1219,102 @@ int SSL_STSAFE_SharedSecretCb(WOLFSSL* ssl, ecc_key* otherKey, WOLFSSL_MSG("SharedSecretCb: STSAFE"); #endif - err = wc_ecc_init(&tmpKey); - if (err != 0) { - return err; +#if defined(WOLFSSL_SMALL_STACK) && !defined(WOLFSSL_NO_MALLOC) + otherKeyX = (byte*)XMALLOC(STSAFE_MAX_KEY_LEN, NULL, + DYNAMIC_TYPE_TMP_BUFFER); + otherKeyY = (byte*)XMALLOC(STSAFE_MAX_KEY_LEN, NULL, + DYNAMIC_TYPE_TMP_BUFFER); + pubKeyRaw = (byte*)XMALLOC(STSAFE_MAX_PUBKEY_RAW_LEN, NULL, + DYNAMIC_TYPE_TMP_BUFFER); + if (otherKeyX == NULL || otherKeyY == NULL || pubKeyRaw == NULL) { + err = MEMORY_E; } +#endif - /* 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; + if (err == 0) { + err = wc_ecc_init(&tmpKey); + if (err == 0) { + tmpKeyInit = 1; } + } - 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; - } + if (err == 0) { + ecc_curve = otherKey->dp->id; + curve_id = stsafe_get_ecc_curve_id(ecc_curve); + key_sz = stsafe_get_key_size(curve_id); + + if (side == WOLFSSL_CLIENT_END) { + err = wc_ecc_export_public_raw(otherKey, otherKeyX, &otherKeyX_len, + otherKeyY, &otherKeyY_len); - /* 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 = stsafe_create_key(&slot, curve_id, pubKeyRaw); + if (err != STSAFE_A_OK) { + STSAFE_INTERFACE_PRINTF("stsafe_create_key error: %d\n", + err); + err = WC_HW_E; + } + } + + if (err == 0) { + err = wc_ecc_import_unsigned(&tmpKey, pubKeyRaw, + &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 if (side == WOLFSSL_SERVER_END) { + 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; } - } - else { - err = BAD_FUNC_ARG; } - wc_ecc_free(&tmpKey); + if (err == 0) { + err = stsafe_shared_secret(slot, curve_id, otherKeyX, otherKeyY, + out, (int32_t*)outlen); + if (err != STSAFE_A_OK) { + STSAFE_INTERFACE_PRINTF("stsafe_shared_secret error: %d\n", err); + err = WC_HW_E; + } + } - if (err != 0) { - return err; + if (tmpKeyInit) { + wc_ecc_free(&tmpKey); } - /* Compute shared secret */ - err = stsafe_interface_shared_secret( -#ifdef WOLFSSL_STSAFE_TAKES_SLOT - slot, +#if defined(WOLFSSL_SMALL_STACK) && !defined(WOLFSSL_NO_MALLOC) + XFREE(otherKeyX, NULL, DYNAMIC_TYPE_TMP_BUFFER); + XFREE(otherKeyY, NULL, DYNAMIC_TYPE_TMP_BUFFER); + XFREE(pubKeyRaw, NULL, DYNAMIC_TYPE_TMP_BUFFER); #endif - 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; } +/** + * \brief Setup PK callbacks for STSAFE + */ 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 */ + wolfSSL_CTX_SetDevId(ctx, 0); return 0; } +/** + * \brief Setup PK callback context + */ int SSL_STSAFE_SetupPkCallbackCtx(WOLFSSL* ssl, void* user_ctx) { wolfSSL_SetEccKeyGenCtx(ssl, user_ctx); @@ -374,9 +1324,13 @@ int SSL_STSAFE_SetupPkCallbackCtx(WOLFSSL* ssl, void* user_ctx) return 0; } - #endif /* HAVE_PK_CALLBACKS */ + +/* ========================================================================== */ +/* Crypto Callbacks */ +/* ========================================================================== */ + #ifdef WOLF_CRYPTO_CB int wolfSSL_STSAFE_CryptoDevCb(int devId, wc_CryptoInfo* info, void* ctx) @@ -384,212 +1338,293 @@ 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; + if (info == NULL || ctx == NULL) { + rc = BAD_FUNC_ARG; + } (void)devId; (void)stsCtx; - if (info->algo_type == WC_ALGO_TYPE_SEED) { - /* use the STSAFE hardware for RNG seed */ + if (rc != BAD_FUNC_ARG && info->algo_type == WC_ALGO_TYPE_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; + rc = 0; + while (rc == 0 && info->seed.sz > 0) { + int len = stsafe_get_random(info->seed.seed, info->seed.sz); + if (len < 0) { + rc = len; + } + else { + info->seed.seed += len; + info->seed.sz -= len; } - 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) { + else if (rc != BAD_FUNC_ARG && 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) { + #if defined(WOLFSSL_SMALL_STACK) && !defined(WOLFSSL_NO_MALLOC) + byte* pubKeyRaw = NULL; + #else byte pubKeyRaw[STSAFE_MAX_PUBKEY_RAW_LEN]; - StSafeA_KeySlotNumber slot; - StSafeA_CurveId curve_id; + #endif + stsafe_slot_t slot; + stsafe_curve_id_t 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; + rc = 0; + #if defined(WOLFSSL_SMALL_STACK) && !defined(WOLFSSL_NO_MALLOC) + pubKeyRaw = (byte*)XMALLOC(STSAFE_MAX_PUBKEY_RAW_LEN, NULL, + DYNAMIC_TYPE_TMP_BUFFER); + if (pubKeyRaw == NULL) { + rc = MEMORY_E; } + #endif - /* 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); + if (rc == 0) { + ecc_curve = info->pk.eckg.curveId; + curve_id = stsafe_get_ecc_curve_id(ecc_curve); + key_sz = stsafe_get_key_size(curve_id); + + rc = stsafe_create_key(&slot, curve_id, pubKeyRaw); + if (rc != STSAFE_A_OK) { + STSAFE_INTERFACE_PRINTF("stsafe_create_key error: %d\n", + rc); + rc = WC_HW_E; + } + } + + if (rc == 0) { + rc = wc_ecc_import_unsigned(info->pk.eckg.key, pubKeyRaw, + &pubKeyRaw[key_sz], NULL, ecc_curve); + } + + #if defined(WOLFSSL_SMALL_STACK) && !defined(WOLFSSL_NO_MALLOC) + XFREE(pubKeyRaw, NULL, DYNAMIC_TYPE_TMP_BUFFER); + #endif } else if (info->pk.type == WC_PK_TYPE_ECDSA_SIGN) { + #if defined(WOLFSSL_SMALL_STACK) && !defined(WOLFSSL_NO_MALLOC) + byte* digest = NULL; + byte* sigRS = NULL; + #else byte digest[STSAFE_MAX_KEY_LEN]; byte sigRS[STSAFE_MAX_SIG_LEN]; - byte *r, *s; - StSafeA_CurveId curve_id; + #endif + byte* r; + byte* s; + stsafe_curve_id_t curve_id; + int ecc_curve; 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; + rc = 0; + #if defined(WOLFSSL_SMALL_STACK) && !defined(WOLFSSL_NO_MALLOC) + digest = (byte*)XMALLOC(STSAFE_MAX_KEY_LEN, NULL, + DYNAMIC_TYPE_TMP_BUFFER); + sigRS = (byte*)XMALLOC(STSAFE_MAX_SIG_LEN, NULL, + DYNAMIC_TYPE_TMP_BUFFER); + if (digest == NULL || sigRS == NULL) { + rc = MEMORY_E; } + #endif - /* 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"); + if (rc == 0) { + /* Get curve from signing key */ + if (info->pk.eccsign.key != NULL && + info->pk.eccsign.key->dp != NULL) { + ecc_curve = info->pk.eccsign.key->dp->id; + curve_id = stsafe_get_ecc_curve_id(ecc_curve); + } else { + curve_id = stsafe_get_curve_mode(); + } + key_sz = stsafe_get_key_size(curve_id); + + if ((int)inSz > key_sz) + inSz = key_sz; + + XMEMSET(digest, 0, STSAFE_MAX_KEY_LEN); + XMEMCPY(&digest[key_sz - inSz], info->pk.eccsign.in, inSz); + + XMEMSET(sigRS, 0, STSAFE_MAX_SIG_LEN); + /* Use slot 1 where keys are generated */ + rc = stsafe_sign(STSAFE_KEY_SLOT_1, curve_id, digest, sigRS); + if (rc != STSAFE_A_OK) { + STSAFE_INTERFACE_PRINTF("stsafe_sign error: %d\n", rc); + rc = WC_HW_E; + } + } + + if (rc == 0) { + r = &sigRS[0]; + s = &sigRS[key_sz]; + rc = wc_ecc_rs_raw_to_sig(r, key_sz, s, key_sz, + info->pk.eccsign.out, info->pk.eccsign.outlen); + if (rc != 0) { + WOLFSSL_MSG("Error converting RS to Signature"); + } } + + #if defined(WOLFSSL_SMALL_STACK) && !defined(WOLFSSL_NO_MALLOC) + XFREE(digest, NULL, DYNAMIC_TYPE_TMP_BUFFER); + XFREE(sigRS, NULL, DYNAMIC_TYPE_TMP_BUFFER); + #endif } else if (info->pk.type == WC_PK_TYPE_ECDSA_VERIFY) { + #if defined(WOLFSSL_SMALL_STACK) && !defined(WOLFSSL_NO_MALLOC) + byte* sigRS = NULL; + byte* pubKeyX = NULL; + byte* pubKeyY = NULL; + #else byte sigRS[STSAFE_MAX_SIG_LEN]; - byte *r = NULL, *s = NULL; - 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; + #endif + byte* r = NULL; + byte* s = NULL; + word32 r_len = STSAFE_MAX_SIG_LEN/2, s_len = STSAFE_MAX_SIG_LEN/2; + word32 pubKeyX_len = STSAFE_MAX_PUBKEY_RAW_LEN/2; + word32 pubKeyY_len = STSAFE_MAX_PUBKEY_RAW_LEN/2; + stsafe_curve_id_t curve_id; int ecc_curve, key_sz; WOLFSSL_MSG("STSAFE: ECC Verify"); + rc = 0; if (info->pk.eccverify.key == NULL || info->pk.eccverify.key->dp == NULL) { - return BAD_FUNC_ARG; + rc = 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); - if (key_sz <= 0 || key_sz > STSAFE_MAX_KEY_LEN) { - return BAD_FUNC_ARG; + #if defined(WOLFSSL_SMALL_STACK) && !defined(WOLFSSL_NO_MALLOC) + if (rc == 0) { + sigRS = (byte*)XMALLOC(STSAFE_MAX_SIG_LEN, NULL, + DYNAMIC_TYPE_TMP_BUFFER); + pubKeyX = (byte*)XMALLOC(STSAFE_MAX_PUBKEY_RAW_LEN/2, NULL, + DYNAMIC_TYPE_TMP_BUFFER); + pubKeyY = (byte*)XMALLOC(STSAFE_MAX_PUBKEY_RAW_LEN/2, NULL, + DYNAMIC_TYPE_TMP_BUFFER); + if (sigRS == NULL || pubKeyX == NULL || pubKeyY == NULL) { + rc = MEMORY_E; + } } + #endif - /* 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)); + 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); + if (key_sz <= 0 || key_sz > STSAFE_MAX_KEY_LEN) { + rc = BAD_FUNC_ARG; + } + } + + if (rc == 0) { + rc = wc_ecc_export_public_raw(info->pk.eccverify.key, + pubKeyX, &pubKeyX_len, pubKeyY, &pubKeyY_len); + } + if (rc == 0) { + XMEMSET(sigRS, 0, STSAFE_MAX_SIG_LEN); 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); } if (rc == 0) { - /* make sure R and S are not too large */ - if (r_len > key_sz || s_len > key_sz) { + if ((int)r_len > key_sz || (int)s_len > key_sz) { rc = BAD_FUNC_ARG; } } if (rc == 0) { - /* make sure R and S are zero padded on front */ - XMEMMOVE(&sigRS[key_sz-r_len], r, r_len); - XMEMSET(&sigRS[0], 0, key_sz-r_len); - XMEMMOVE(&sigRS[key_sz + (key_sz-s_len)], s, s_len); - XMEMSET(&sigRS[key_sz], 0, key_sz-s_len); - - /* Verify signature */ - rc = stsafe_interface_verify(curve_id, - (uint8_t*)info->pk.eccverify.hash, sigRS, pubKeyX, pubKeyY, - (int32_t*)info->pk.eccverify.res); + XMEMMOVE(&sigRS[key_sz - r_len], r, r_len); + XMEMSET(&sigRS[0], 0, key_sz - r_len); + XMEMMOVE(&sigRS[key_sz + (key_sz - s_len)], s, s_len); + XMEMSET(&sigRS[key_sz], 0, key_sz - s_len); + + rc = stsafe_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 = -rc; + STSAFE_INTERFACE_PRINTF("stsafe_verify error: %d\n", rc); + rc = WC_HW_E; } } + + #if defined(WOLFSSL_SMALL_STACK) && !defined(WOLFSSL_NO_MALLOC) + XFREE(sigRS, NULL, DYNAMIC_TYPE_TMP_BUFFER); + XFREE(pubKeyX, NULL, DYNAMIC_TYPE_TMP_BUFFER); + XFREE(pubKeyY, NULL, DYNAMIC_TYPE_TMP_BUFFER); + #endif } else if (info->pk.type == WC_PK_TYPE_ECDH) { + #if defined(WOLFSSL_SMALL_STACK) && !defined(WOLFSSL_NO_MALLOC) + byte* otherKeyX = NULL; + byte* otherKeyY = NULL; + #else 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; + #endif + word32 otherKeyX_len = STSAFE_MAX_KEY_LEN; + word32 otherKeyY_len = STSAFE_MAX_KEY_LEN; + stsafe_curve_id_t curve_id; int ecc_curve; - WOLFSSL_MSG("STSAFE: PMS"); + WOLFSSL_MSG("STSAFE: ECDH"); - if (info->pk.ecdh.public_key == NULL) - return BAD_FUNC_ARG; + rc = 0; + if (info->pk.ecdh.public_key == NULL) { + rc = BAD_FUNC_ARG; + } + + #if defined(WOLFSSL_SMALL_STACK) && !defined(WOLFSSL_NO_MALLOC) + if (rc == 0) { + otherKeyX = (byte*)XMALLOC(STSAFE_MAX_KEY_LEN, NULL, + DYNAMIC_TYPE_TMP_BUFFER); + otherKeyY = (byte*)XMALLOC(STSAFE_MAX_KEY_LEN, NULL, + DYNAMIC_TYPE_TMP_BUFFER); + if (otherKeyX == NULL || otherKeyY == NULL) { + rc = MEMORY_E; + } + } + #endif - /* get curve */ - ecc_curve = info->pk.ecdh.public_key->dp->id; - curve_id = stsafe_get_ecc_curve_id(ecc_curve); + if (rc == 0) { + 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); + rc = wc_ecc_export_public_raw(info->pk.ecdh.public_key, + otherKeyX, &otherKeyX_len, otherKeyY, &otherKeyY_len); + } if (rc == 0) { - /* Compute shared secret */ *info->pk.ecdh.outlen = 0; - rc = stsafe_interface_shared_secret( - #ifdef WOLFSSL_STSAFE_TAKES_SLOT - STSAFE_A_SLOT_0, - #endif - curve_id, + /* Use slot 1 where keys are generated */ + rc = stsafe_shared_secret(STSAFE_KEY_SLOT_1, 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 + STSAFE_INTERFACE_PRINTF("stsafe_shared_secret error: %d\n", + rc); rc = WC_HW_E; } } + + #if defined(WOLFSSL_SMALL_STACK) && !defined(WOLFSSL_NO_MALLOC) + XFREE(otherKeyX, NULL, DYNAMIC_TYPE_TMP_BUFFER); + XFREE(otherKeyY, NULL, DYNAMIC_TYPE_TMP_BUFFER); + #endif } } #endif /* HAVE_ECC */ - /* need to return negative here for error */ if (rc != 0 && rc != WC_NO_ERR_TRACE(CRYPTOCB_UNAVAILABLE)) { WOLFSSL_MSG("STSAFE: CryptoCb failed"); #ifdef USE_STSAFE_VERBOSE @@ -603,4 +1638,4 @@ int wolfSSL_STSAFE_CryptoDevCb(int devId, wc_CryptoInfo* info, void* ctx) #endif /* WOLF_CRYPTO_CB */ -#endif /* WOLFSSL_STSAFEA100 */ +#endif /* WOLFSSL_STSAFE */ diff --git a/wolfcrypt/src/wc_port.c b/wolfcrypt/src/wc_port.c index 462e85a6ca3..bf9c83821ce 100644 --- a/wolfcrypt/src/wc_port.c +++ b/wolfcrypt/src/wc_port.c @@ -68,7 +68,7 @@ #if defined(WOLFSSL_RENESAS_RX64_HASH) #include #endif -#if defined(WOLFSSL_STSAFEA100) +#ifdef WOLFSSL_STSAFE #include #endif @@ -298,8 +298,12 @@ int wolfCrypt_Init(void) return ret; } #endif - #if defined(WOLFSSL_STSAFEA100) - stsafe_interface_init(); + #ifdef WOLFSSL_STSAFE + ret = stsafe_interface_init(); + if (ret != 0) { + WOLFSSL_MSG("STSAFE init failed"); + return ret; + } #endif #if defined(WOLFSSL_TROPIC01) ret = Tropic01_Init(); diff --git a/wolfssl/wolfcrypt/port/st/stsafe.h b/wolfssl/wolfcrypt/port/st/stsafe.h index 08e39f08e8b..83b02c60531 100644 --- a/wolfssl/wolfcrypt/port/st/stsafe.h +++ b/wolfssl/wolfcrypt/port/st/stsafe.h @@ -23,6 +23,7 @@ #define _WOLFPORT_STSAFE_H_ #include +#include #include #include @@ -34,22 +35,129 @@ #include #endif -#ifdef WOLFSSL_STSAFEA100 +#ifdef WOLFSSL_STSAFE -/* The wolf STSAFE interface layer */ -/* Please contact wolfSSL for the STSAFE port files */ -#include "stsafe_interface.h" +/* -------------------------------------------------------------------------- */ +/* External Interface Support (Backwards Compatibility) */ +/* -------------------------------------------------------------------------- */ + +/* Define WOLFSSL_STSAFE_INTERFACE_EXTERNAL to use an external stsafe_ + * interface.h file that provides customer-specific implementations. + * This maintains backwards compatibility with older integrations that + * used a separate interface file. + * + * When NOT set (the default): All code is self-contained in stsafe.c using + * the appropriate SDK (STSELib for A120, STSAFE-A1xx SDK for A100/A110). + * + * When defined: Include customer-provided stsafe_interface.h which must define: + * - stsafe_curve_id_t, stsafe_slot_t types + * - STSAFE_ECC_CURVE_P256, STSAFE_ECC_CURVE_P384 macros + * - STSAFE_KEY_SLOT_0, STSAFE_KEY_SLOT_1, STSAFE_KEY_SLOT_EPHEMERAL macros + * - STSAFE_A_OK return code macro + * - STSAFE_MAX_KEY_LEN, STSAFE_MAX_PUBKEY_RAW_LEN, STSAFE_MAX_SIG_LEN macros + * - Function prototypes for interface functions (see stsafe.c) + */ +#ifdef WOLFSSL_STSAFE_INTERFACE_EXTERNAL + #include "stsafe_interface.h" +#else + +/* -------------------------------------------------------------------------- */ +/* STSAFE SDK Type Abstractions */ +/* -------------------------------------------------------------------------- */ + +#ifdef WOLFSSL_STSAFEA120 + /* STSAFE-A120 uses STSELib (open source BSD-3) */ + /* Note: stselib.h is included in stsafe.c to avoid warnings in headers */ + + /* Type mappings for STSELib - using byte for curve ID to avoid + * including full STSELib headers which have strict-prototype warnings */ + typedef byte stsafe_curve_id_t; + typedef byte stsafe_slot_t; + + /* Curve ID mappings - values depend on stse_conf.h settings! + * With only NIST P-256 and P-384 enabled: + * STSE_ECC_KT_NIST_P_256 = 0, STSE_ECC_KT_NIST_P_384 = 1 + * NOTE: If other curves are enabled, these values change! */ + #define STSAFE_ECC_CURVE_P256 0 /* STSE_ECC_KT_NIST_P_256 */ + #define STSAFE_ECC_CURVE_P384 1 /* STSE_ECC_KT_NIST_P_384 */ + /* Brainpool curves - only defined when enabled in stse_conf.h */ + /* #define STSAFE_ECC_CURVE_BP256 2 */ /* STSE_ECC_KT_BP_P_256 */ + /* #define STSAFE_ECC_CURVE_BP384 3 */ /* STSE_ECC_KT_BP_P_384 */ + + /* Slot mappings */ + #define STSAFE_KEY_SLOT_0 0 + #define STSAFE_KEY_SLOT_1 1 + #define STSAFE_KEY_SLOT_EPHEMERAL 0xFF + + /* Return codes */ + #define STSAFE_A_OK 0 /* STSE_OK */ + + /* Hash types - must match stse_hash_algorithm_t values in STSELib */ + #define STSAFE_HASH_SHA256 0 /* STSE_SHA_256 */ + #define STSAFE_HASH_SHA384 1 /* STSE_SHA_384 */ + +#else /* WOLFSSL_STSAFEA100 */ + /* STSAFE-A100/A110 uses legacy ST STSAFE-A1xx SDK */ + /* User must provide path to STSAFE-A1xx SDK headers */ + #include + + /* Type mappings for legacy SDK */ + typedef StSafeA_CurveId stsafe_curve_id_t; + typedef StSafeA_KeySlotNumber stsafe_slot_t; + + /* Curve ID mappings */ + #define STSAFE_ECC_CURVE_P256 STSAFE_A_NIST_P_256 + #define STSAFE_ECC_CURVE_P384 STSAFE_A_NIST_P_384 + #define STSAFE_ECC_CURVE_BP256 STSAFE_A_BRAINPOOL_P_256 + #define STSAFE_ECC_CURVE_BP384 STSAFE_A_BRAINPOOL_P_384 + + /* Slot mappings */ + #define STSAFE_KEY_SLOT_0 STSAFE_A_SLOT_0 + #define STSAFE_KEY_SLOT_1 STSAFE_A_SLOT_1 + #define STSAFE_KEY_SLOT_EPHEMERAL STSAFE_A_SLOT_EPHEMERAL + + /* Return codes - STSAFE_A_OK already defined in SDK */ + + /* Hash types */ + #define STSAFE_HASH_SHA256 STSAFE_A_SHA_256 + #define STSAFE_HASH_SHA384 STSAFE_A_SHA_384 + +#endif /* WOLFSSL_STSAFEA120 */ + +/* -------------------------------------------------------------------------- */ +/* Common Definitions */ +/* -------------------------------------------------------------------------- */ #ifndef STSAFE_MAX_KEY_LEN - #define STSAFE_MAX_KEY_LEN ((uint32_t)48) /* for up to 384-bit keys */ + #define STSAFE_MAX_KEY_LEN 48 /* for up to 384-bit keys */ #endif #ifndef STSAFE_MAX_PUBKEY_RAW_LEN - #define STSAFE_MAX_PUBKEY_RAW_LEN ((uint32_t)STSAFE_MAX_KEY_LEN * 2) /* x/y */ + #define STSAFE_MAX_PUBKEY_RAW_LEN (STSAFE_MAX_KEY_LEN * 2) /* x/y */ #endif #ifndef STSAFE_MAX_SIG_LEN - #define STSAFE_MAX_SIG_LEN ((uint32_t)STSAFE_MAX_KEY_LEN * 2) /* r/s */ + #define STSAFE_MAX_SIG_LEN (STSAFE_MAX_KEY_LEN * 2) /* r/s */ +#endif + +/* Default I2C address */ +#ifndef STSAFE_I2C_ADDR + #define STSAFE_I2C_ADDR 0x20 #endif +/* Default curve mode (for signing operations) */ +#ifndef STSAFE_DEFAULT_CURVE + #define STSAFE_DEFAULT_CURVE STSAFE_ECC_CURVE_P256 +#endif + +#endif /* !WOLFSSL_STSAFE_INTERFACE_EXTERNAL */ + +/* -------------------------------------------------------------------------- */ +/* Public API Functions */ +/* -------------------------------------------------------------------------- */ + +/* Initialize STSAFE device - called automatically by wolfCrypt_Init() */ +WOLFSSL_API int stsafe_interface_init(void); + +/* Load device certificate from STSAFE secure storage */ WOLFSSL_API int SSL_STSAFE_LoadDeviceCertificate(byte** pRawCertificate, word32* pRawCertificateLen); @@ -94,6 +202,6 @@ WOLFSSL_API int wolfSSL_STSAFE_CryptoDevCb(int devId, wc_CryptoInfo* info, #endif /* WOLF_CRYPTO_CB */ -#endif /* WOLFSSL_STSAFEA100 */ +#endif /* WOLFSSL_STSAFE */ #endif /* _WOLFPORT_STSAFE_H_ */ diff --git a/wolfssl/wolfcrypt/settings.h b/wolfssl/wolfcrypt/settings.h index 46a748b4fec..c46449f9c5f 100644 --- a/wolfssl/wolfcrypt/settings.h +++ b/wolfssl/wolfcrypt/settings.h @@ -2137,6 +2137,12 @@ extern void uITRON4_free(void *p) ; #endif /* WOLFSSL_MAXQ1065 || WOLFSSL_MAXQ108X */ +/* Combined STSAFE macro - enables when either A100 or A120 is defined */ +#if defined(WOLFSSL_STSAFEA100) || defined(WOLFSSL_STSAFEA120) + #undef WOLFSSL_STSAFE + #define WOLFSSL_STSAFE +#endif + #if defined(WOLFSSL_STM32F2) || defined(WOLFSSL_STM32F4) || \ defined(WOLFSSL_STM32F7) || defined(WOLFSSL_STM32F1) || \ defined(WOLFSSL_STM32L4) || defined(WOLFSSL_STM32L5) || \