Example for ST-SAFE A120

pull/553/head
David Garske 2026-01-06 00:27:27 +00:00
parent 45616142ca
commit a4072803f2
11 changed files with 3212 additions and 0 deletions

5
.gitignore vendored
View File

@ -402,3 +402,8 @@ kernel/bsdkm/bsd_example.ko
kernel/bsdkm/machine
kernel/bsdkm/opt_global.h
kernel/bsdkm/x86
# STSAFE test executables
stsafe/stsafe_test
stsafe/wolfssl_stsafe_test
stsafe/wolfssl_stsafe_full_test

162
stsafe/Makefile 100644
View File

@ -0,0 +1,162 @@
# STSAFE-A120 Test Makefile for Raspberry Pi
#
# Copyright 2025 wolfSSL Inc.
CC = gcc
CFLAGS = -Wall -Wextra -O2 -g
# wolfSSL configuration
# Option 1: Use installed wolfSSL (after make install)
#WOLFSSL_DIR = /usr/local
# Option 2: Use local wolfSSL source
WOLFSSL_DIR = $(HOME)/wolfssl
# STSELib paths
STSELIB_DIR = $(HOME)/STSELib
PLATFORM_DIR = ./platform
# Include paths
# Note: Current directory (.) must come first so our user_settings.h is found
INCLUDES = -I. \
-I$(STSELIB_DIR) \
-I$(PLATFORM_DIR) \
-I$(WOLFSSL_DIR)
# wolfSSL library flags
# For installed wolfSSL:
#LDFLAGS = -L$(WOLFSSL_DIR)/lib -lwolfssl -lm
# For local wolfSSL source (using .libs):
LDFLAGS = -L$(WOLFSSL_DIR)/src/.libs -lwolfssl -lm -Wl,-rpath,$(WOLFSSL_DIR)/src/.libs
# wolfSSL compile flags
# WOLFSSL_USER_SETTINGS tells wolfSSL to include user_settings.h
CFLAGS += -DWOLFSSL_USER_SETTINGS
# STSELib source files
STSELIB_CORE_SRC = $(STSELIB_DIR)/core/stse_device.c \
$(STSELIB_DIR)/core/stse_frame.c \
$(STSELIB_DIR)/core/stse_generic_typedef.c \
$(STSELIB_DIR)/core/stse_platform.c \
$(STSELIB_DIR)/core/stse_session.c
STSELIB_API_SRC = $(wildcard $(STSELIB_DIR)/api/*.c)
STSELIB_SERVICES_SRC = $(wildcard $(STSELIB_DIR)/services/stsafea/*.c) \
$(wildcard $(STSELIB_DIR)/services/stsafel/*.c)
STSELIB_CERT_SRC = $(wildcard $(STSELIB_DIR)/certificate/*.c)
# Platform source files
PLATFORM_SRC = $(PLATFORM_DIR)/stse_platform_linux.c
# Platform crypto source (wolfSSL implementation)
# Uncomment when building with wolfSSL crypto support:
PLATFORM_CRYPTO_SRC = $(PLATFORM_DIR)/stse_platform_crypto_wolfssl.c
# Test source files
TEST_SRC = stsafe_test.c
WOLFSSL_TEST_SRC = wolfssl_stsafe_test.c
WOLFSSL_FULL_TEST_SRC = wolfssl_stsafe_full_test.c
# All sources
ALL_SRC = $(STSELIB_CORE_SRC) $(STSELIB_API_SRC) $(STSELIB_SERVICES_SRC) \
$(STSELIB_CERT_SRC) $(PLATFORM_SRC) $(PLATFORM_CRYPTO_SRC) $(TEST_SRC)
# wolfSSL STSAFE port source
WOLFSSL_STSAFE_SRC = $(WOLFSSL_DIR)/wolfcrypt/src/port/st/stsafe.c
# Targets
TARGET = stsafe_test
WOLFSSL_TARGET = wolfssl_stsafe_test
WOLFSSL_FULL_TARGET = wolfssl_stsafe_full_test
.PHONY: all clean test info basic wolfssl wolfssl-full
all: $(TARGET)
# Full build with wolfSSL crypto support
$(TARGET): $(TEST_SRC) $(PLATFORM_SRC) $(PLATFORM_CRYPTO_SRC)
$(CC) $(CFLAGS) $(INCLUDES) -o $@ \
$(TEST_SRC) \
$(PLATFORM_SRC) \
$(PLATFORM_CRYPTO_SRC) \
$(STSELIB_CORE_SRC) \
$(STSELIB_API_SRC) \
$(STSELIB_SERVICES_SRC) \
$(STSELIB_CERT_SRC) \
$(LDFLAGS)
# Basic build without wolfSSL (for initial testing without host sessions)
basic: $(TEST_SRC) $(PLATFORM_SRC)
$(CC) $(CFLAGS) $(INCLUDES) -o $(TARGET) \
$(TEST_SRC) \
$(PLATFORM_SRC) \
$(STSELIB_CORE_SRC) \
$(STSELIB_API_SRC) \
$(STSELIB_SERVICES_SRC) \
$(STSELIB_CERT_SRC)
# wolfSSL crypto callback test build
# Note: We compile stsafe.c directly since it's not built into libwolfssl by default
# IMPORTANT: Use WOLFSSL_USE_OPTIONS_H to get options.h included for proper wolfSSL settings
# We add -DWOLFSSL_STSAFEA120 -DUSE_STSAFE_RNG_SEED to enable STSAFE in stsafe.c
WOLFSSL_STSAFE_FLAGS = -DWOLFSSL_USE_OPTIONS_H -DWOLFSSL_STSAFEA120 -DUSE_STSAFE_RNG_SEED -Wno-strict-prototypes
WOLFSSL_BASE_FLAGS = -Wall -Wextra -O2 -g
wolfssl: $(WOLFSSL_TEST_SRC) $(PLATFORM_SRC) $(PLATFORM_CRYPTO_SRC)
$(CC) $(WOLFSSL_BASE_FLAGS) $(WOLFSSL_STSAFE_FLAGS) -I$(STSELIB_DIR) -I$(PLATFORM_DIR) -I$(WOLFSSL_DIR) \
-c $(WOLFSSL_STSAFE_SRC) -o stsafe.o
$(CC) $(WOLFSSL_BASE_FLAGS) $(WOLFSSL_STSAFE_FLAGS) -I$(STSELIB_DIR) -I$(PLATFORM_DIR) -I$(WOLFSSL_DIR) \
-c $(PLATFORM_SRC) -o stse_platform_linux.o
$(CC) $(WOLFSSL_BASE_FLAGS) $(WOLFSSL_STSAFE_FLAGS) -I$(STSELIB_DIR) -I$(PLATFORM_DIR) -I$(WOLFSSL_DIR) \
-c $(PLATFORM_CRYPTO_SRC) -o stse_platform_crypto.o
$(CC) $(WOLFSSL_BASE_FLAGS) $(WOLFSSL_STSAFE_FLAGS) -I$(STSELIB_DIR) -I$(PLATFORM_DIR) -I$(WOLFSSL_DIR) \
-o $(WOLFSSL_TARGET) \
$(WOLFSSL_TEST_SRC) \
stse_platform_linux.o stse_platform_crypto.o stsafe.o \
$(STSELIB_CORE_SRC) \
$(STSELIB_API_SRC) \
$(STSELIB_SERVICES_SRC) \
$(STSELIB_CERT_SRC) \
$(LDFLAGS)
test: $(TARGET)
./$(TARGET)
test-wolfssl: wolfssl
./$(WOLFSSL_TARGET)
# Full wolfSSL integration test with ECDH and benchmarks
wolfssl-full: $(WOLFSSL_FULL_TEST_SRC) $(PLATFORM_SRC) $(PLATFORM_CRYPTO_SRC)
$(CC) $(WOLFSSL_BASE_FLAGS) $(WOLFSSL_STSAFE_FLAGS) -I$(STSELIB_DIR) -I$(PLATFORM_DIR) -I$(WOLFSSL_DIR) \
-c $(WOLFSSL_STSAFE_SRC) -o stsafe.o
$(CC) $(WOLFSSL_BASE_FLAGS) $(WOLFSSL_STSAFE_FLAGS) -I$(STSELIB_DIR) -I$(PLATFORM_DIR) -I$(WOLFSSL_DIR) \
-c $(PLATFORM_SRC) -o stse_platform_linux.o
$(CC) $(WOLFSSL_BASE_FLAGS) $(WOLFSSL_STSAFE_FLAGS) -I$(STSELIB_DIR) -I$(PLATFORM_DIR) -I$(WOLFSSL_DIR) \
-c $(PLATFORM_CRYPTO_SRC) -o stse_platform_crypto.o
$(CC) $(WOLFSSL_BASE_FLAGS) $(WOLFSSL_STSAFE_FLAGS) -I$(STSELIB_DIR) -I$(PLATFORM_DIR) -I$(WOLFSSL_DIR) \
-o $(WOLFSSL_FULL_TARGET) \
$(WOLFSSL_FULL_TEST_SRC) \
stse_platform_linux.o stse_platform_crypto.o stsafe.o \
$(STSELIB_CORE_SRC) \
$(STSELIB_API_SRC) \
$(STSELIB_SERVICES_SRC) \
$(STSELIB_CERT_SRC) \
$(LDFLAGS)
test-wolfssl-full: wolfssl-full
./$(WOLFSSL_FULL_TARGET)
clean:
rm -f $(TARGET) $(WOLFSSL_TARGET) $(WOLFSSL_FULL_TARGET) *.o stsafe.o stse_platform_linux.o stse_platform_crypto.o
# Show configuration
info:
@echo "STSELib directory: $(STSELIB_DIR)"
@echo "wolfSSL directory: $(WOLFSSL_DIR)"
@echo "Platform directory: $(PLATFORM_DIR)"
@echo "Include paths: $(INCLUDES)"
@echo "Linker flags: $(LDFLAGS)"
@echo ""
@echo "Build targets:"
@echo " make - Build with wolfSSL crypto support (full features)"
@echo " make basic - Build without wolfSSL (basic tests only)"
@echo " make test - Build and run tests"
@echo " make clean - Clean build artifacts"

183
stsafe/README.md 100644
View File

@ -0,0 +1,183 @@
# wolfSSL STSAFE-A120 Test Suite
Test harness for wolfSSL integration with ST STSAFE-A120 secure element on Raspberry Pi 5.
## Hardware Requirements
- Raspberry Pi 5 (or compatible Linux system with I2C)
- STSAFE-A120 secure element connected via I2C
- I2C enabled on the system
## Software Requirements
- wolfSSL library (compiled with ECC, CMAC, SHA-384 support)
- STSELib (ST Secure Element Library)
- GCC compiler
- Linux I2C development headers (`libi2c-dev`)
## Directory Structure
```
stsafe/
├── Makefile # Build configuration
├── README.md # This file
├── user_settings.h # wolfSSL configuration
├── stsafe_test.c # STSELib basic tests
├── wolfssl_stsafe_test.c # wolfSSL crypto callback tests
├── wolfssl_stsafe_full_test.c # Full integration tests with benchmarks
└── platform/
├── stse_conf.h # STSELib configuration
├── stse_platform_generic.h # Platform type definitions
├── stse_platform_linux.c # Linux I2C platform implementation
└── stse_platform_crypto_wolfssl.c # wolfSSL crypto for STSELib
```
## Configuration
### I2C Setup
1. Enable I2C on Raspberry Pi:
```bash
sudo raspi-config
# Navigate to: Interface Options -> I2C -> Enable
```
2. Verify I2C device:
```bash
sudo i2cdetect -y 1
# STSAFE should appear at address 0x20
```
3. Set I2C permissions (optional, for non-root access):
```bash
sudo usermod -a -G i2c $USER
# Logout and login again
```
### Environment
Set paths to dependencies:
```bash
export WOLFSSL_DIR=$HOME/wolfssl
export STSELIB_DIR=$HOME/STSELib
```
## Building
### Prerequisites
1. Build wolfSSL with required features:
```bash
cd $WOLFSSL_DIR
./configure --enable-cryptocb --enable-ecc --enable-cmac --enable-sha384 --enable-debug
make
```
2. Clone STSELib:
```bash
git clone https://github.com/STMicroelectronics/STSELib.git $STSELIB_DIR
```
### Build Targets
```bash
# Build basic STSELib tests (no wolfSSL crypto callbacks)
make
# Build wolfSSL crypto callback tests
make wolfssl
# Build full integration tests with benchmarks
make wolfssl-full
# Build without wolfSSL (basic I2C tests only)
make basic
# Clean build artifacts
make clean
# Show configuration
make info
```
## Running Tests
### Basic STSELib Tests
```bash
./stsafe_test
```
Tests:
- Echo command (I2C communication)
- Random number generation
- ECC P-256 key generation
- ECDSA P-256 signing
- ECC P-384 key generation
### wolfSSL Crypto Callback Tests
```bash
./wolfssl_stsafe_test
```
Tests:
- RNG with STSAFE-A120
- ECC P-256 key generation via crypto callback
- ECC P-384 key generation via crypto callback
- ECDSA P-256 sign/verify
- ECDSA P-384 sign/verify
### Full Integration Tests
```bash
./wolfssl_stsafe_full_test
```
Tests:
- RNG benchmark
- ECDSA P-256 benchmark (keygen, sign, verify timing)
- Multiple sequential operations
## Expected Output
```
================================================
STSAFE-A120 Test Suite for wolfSSL Integration
================================================
Initializing STSAFE handler...
STSAFE-A120 initialized successfully.
Test: Echo Command
Echo response matches!
[PASS] Echo command
Test: Random Number Generation
Random data: A1 B2 C3 D4 ...
[PASS] Random number generation
Test: ECC Key Generation (P-256)
Public Key X: 12345678...
Public Key Y: ABCDEF01...
[PASS] ECC P-256 key generation
...
================================================
Test Summary: 5 passed, 0 failed
================================================
```
## Performance Results (Raspberry Pi 5)
| Operation | Time | Throughput |
|-----------|------|------------|
| RNG (256 bytes) | <1 ms | ~9 MB/s |
| ECC P-256 KeyGen | ~40 ms | 25 ops/sec |
| ECDSA P-256 Sign | ~51 ms | 19.5 ops/sec |
| ECDSA P-256 Verify | ~79 ms | 12.7 ops/sec |
## References
- [wolfSSL Documentation](https://www.wolfssl.com/docs/)
- [STSELib GitHub](https://github.com/STMicroelectronics/STSELib)
- [STSAFE-A120 Datasheet](https://www.st.com/en/secure-mcus/stsafe-a120.html)
- [Raspberry Pi I2C Documentation](https://www.raspberrypi.com/documentation/computers/raspberry-pi.html#gpio-and-the-40-pin-header)

View File

@ -0,0 +1,76 @@
/* stse_conf.h
*
* Copyright (C) 2006-2026 wolfSSL Inc.
*
* This file is part of wolfSSL. (formerly known as CyaSSL)
*
* 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-1301, USA
*/
#ifndef STSE_CONF_H
#define STSE_CONF_H
#ifdef __cplusplus
extern "C" {
#endif
#include "stse_platform_generic.h"
/************************************************************
* STSELIB DEVICE SUPPORT
************************************************************/
#define STSE_CONF_STSAFE_A_SUPPORT
/************************************************************
* STSAFE-A API/SERVICE SETTINGS
************************************************************/
#ifdef STSE_CONF_STSAFE_A_SUPPORT
/* STSAFE-A ECC services configuration - enable P-256 and P-384 for wolfSSL */
#define STSE_CONF_ECC_NIST_P_256
#define STSE_CONF_ECC_NIST_P_384
/* STSAFE-A HASH services configuration */
#define STSE_CONF_HASH_SHA_256
#define STSE_CONF_HASH_SHA_384
/* STSAFE-A HOST KEY MANAGEMENT
* Requires platform crypto implementation (stse_platform_crypto_wolfssl.c)
* Enable this for encrypted host sessions with STSAFE
*/
#define STSE_CONF_USE_HOST_SESSION
/* Optional: Enable for additional key management features */
/* #define STSE_CONF_USE_HOST_KEY_ESTABLISHMENT */
/* #define STSE_CONF_USE_SYMMETRIC_KEY_ESTABLISHMENT */
#endif /* STSE_CONF_STSAFE_A_SUPPORT */
/*********************************************************
* COMMUNICATION SETTINGS
*********************************************************/
#define STSE_USE_RSP_POLLING
#define STSE_MAX_POLLING_RETRY 100
#define STSE_FIRST_POLLING_INTERVAL 10
#define STSE_POLLING_RETRY_INTERVAL 10
/* Enable debug logging */
/* #define STSE_FRAME_DEBUG_LOG */
#ifdef __cplusplus
}
#endif
#endif /* STSE_CONF_H */

View File

@ -0,0 +1,916 @@
/* stse_platform_crypto_wolfssl.c
*
* Copyright (C) 2006-2026 wolfSSL Inc.
*
* This file is part of wolfSSL. (formerly known as CyaSSL)
*
* 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-1301, USA
*/
#include "core/stse_platform.h"
#include "stse_conf.h"
/* wolfSSL includes */
#ifdef WOLFSSL_USER_SETTINGS
#include "user_settings.h"
#endif
#include <wolfssl/wolfcrypt/settings.h>
#include <wolfssl/wolfcrypt/aes.h>
#include <wolfssl/wolfcrypt/cmac.h>
#include <wolfssl/wolfcrypt/hmac.h>
#include <wolfssl/wolfcrypt/sha256.h>
#include <wolfssl/wolfcrypt/sha512.h>
#include <wolfssl/wolfcrypt/hash.h>
#include <wolfssl/wolfcrypt/ecc.h>
#include <string.h>
#include <stdlib.h>
/* ========================================================================== */
/* Helper Macros */
/* ========================================================================== */
#ifndef MIN
#define MIN(a,b) ((a)<(b) ? (a) : (b))
#endif
#define _MSB(x) ((((x)[0]&0x80)==0x80) ? 1 : 0)
#define ZERO_STRUCT(x) memset((void*)&(x), 0, sizeof(x))
#define ZERO_STRUCTP(x) do { if ((x) != NULL) { memset((void*)(x), 0, sizeof(*(x)));} } while(0)
/* ========================================================================== */
/* AES CMAC Constants (RFC 4493) */
/* ========================================================================== */
static const uint8_t const_Rb[16] = {
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x87
};
static const uint8_t const_Zero[16] = {0x00};
/* ========================================================================== */
/* AES CMAC Context Structure */
/* ========================================================================== */
typedef struct {
Aes aes;
uint8_t k1[16];
uint8_t k2[16];
uint8_t x[16];
uint8_t last[16];
size_t last_len;
PLAT_UI16 exp_tag_size;
} stse_cmac_ctx_t;
/* Global CMAC context for init/append/finish pattern */
static stse_cmac_ctx_t* g_cmac_ctx = NULL;
/* ========================================================================== */
/* Internal Helper Functions */
/* ========================================================================== */
static inline void aes_cmac_left_shift_1(const uint8_t in[16], uint8_t out[16])
{
int8_t i;
uint8_t overflow = 0;
for (i = 15; i >= 0; i--) {
out[i] = in[i] << 1;
out[i] |= overflow;
overflow = _MSB(&in[i]);
}
}
static inline void aes_cmac_xor(const uint8_t in1[16], const uint8_t in2[16], uint8_t out[16])
{
int8_t i;
for (i = 0; i < 16; i++) {
out[i] = in1[i] ^ in2[i];
}
}
static int aes_cmac_generate_subkeys(Aes* aes, uint8_t k1[16], uint8_t k2[16])
{
uint8_t L[16];
uint8_t tmp_block[16];
uint8_t iv[16] = {0};
int ret;
/* Generate L = AES-128(K, const_Zero) */
ret = wc_AesSetIV(aes, iv);
if (ret != 0) return ret;
ret = wc_AesCbcEncrypt(aes, L, const_Zero, 16);
if (ret != 0) return ret;
/* Generate K1 */
if (_MSB(L) == 0) {
aes_cmac_left_shift_1(L, k1);
} else {
aes_cmac_left_shift_1(L, tmp_block);
aes_cmac_xor(tmp_block, const_Rb, k1);
}
/* Generate K2 */
if (_MSB(k1) == 0) {
aes_cmac_left_shift_1(k1, k2);
} else {
aes_cmac_left_shift_1(k1, tmp_block);
aes_cmac_xor(tmp_block, const_Rb, k2);
}
ZERO_STRUCT(L);
ZERO_STRUCT(tmp_block);
return 0;
}
/* ========================================================================== */
/* Platform Crypto Initialization */
/* ========================================================================== */
stse_ReturnCode_t stse_platform_crypto_init(void)
{
/* wolfSSL library initialization if needed */
return STSE_OK;
}
/* ========================================================================== */
/* Hash Functions */
/* ========================================================================== */
stse_ReturnCode_t stse_platform_hash_compute(stse_hash_algorithm_t hash_algo,
PLAT_UI8 *pPayload, PLAT_UI16 payload_length,
PLAT_UI8 *pHash, PLAT_UI16 *hash_length)
{
int ret = -1;
if (pPayload == NULL || pHash == NULL || hash_length == NULL) {
return STSE_PLATFORM_HASH_ERROR;
}
switch (hash_algo) {
#ifdef STSE_CONF_HASH_SHA_256
case STSE_SHA_256:
if (*hash_length >= WC_SHA256_DIGEST_SIZE) {
ret = wc_Sha256Hash(pPayload, payload_length, pHash);
*hash_length = WC_SHA256_DIGEST_SIZE;
}
break;
#endif
#ifdef STSE_CONF_HASH_SHA_384
case STSE_SHA_384:
if (*hash_length >= WC_SHA384_DIGEST_SIZE) {
ret = wc_Sha384Hash(pPayload, payload_length, pHash);
*hash_length = WC_SHA384_DIGEST_SIZE;
}
break;
#endif
default:
return STSE_PLATFORM_HASH_ERROR;
}
if (ret != 0) {
return STSE_PLATFORM_HASH_ERROR;
}
return STSE_OK;
}
/* ========================================================================== */
/* ECC Verification Functions */
/* ========================================================================== */
/**
* \brief Get key size in bytes for a given STSE ECC key type
*/
static int stse_get_ecc_key_size(stse_ecc_key_type_t key_type)
{
switch (key_type) {
#ifdef STSE_CONF_ECC_NIST_P_256
case STSE_ECC_KT_NIST_P_256:
return 32;
#endif
#ifdef STSE_CONF_ECC_BRAINPOOL_P_256
case STSE_ECC_KT_BP_P_256:
return 32;
#endif
#ifdef STSE_CONF_ECC_CURVE_25519
case STSE_ECC_KT_CURVE25519:
return 32;
#endif
#ifdef STSE_CONF_ECC_EDWARD_25519
case STSE_ECC_KT_ED25519:
return 32;
#endif
#ifdef STSE_CONF_ECC_NIST_P_384
case STSE_ECC_KT_NIST_P_384:
return 48;
#endif
#ifdef STSE_CONF_ECC_BRAINPOOL_P_384
case STSE_ECC_KT_BP_P_384:
return 48;
#endif
#ifdef STSE_CONF_ECC_BRAINPOOL_P_512
case STSE_ECC_KT_BP_P_512:
return 64;
#endif
#ifdef STSE_CONF_ECC_NIST_P_521
case STSE_ECC_KT_NIST_P_521:
return 66;
#endif
default:
return 0;
}
}
/**
* \brief Get wolfSSL curve ID for a given STSE ECC key type
*/
static int stse_get_wolfssl_curve_id(stse_ecc_key_type_t key_type)
{
switch (key_type) {
#ifdef STSE_CONF_ECC_NIST_P_256
case STSE_ECC_KT_NIST_P_256:
return ECC_SECP256R1;
#endif
#ifdef STSE_CONF_ECC_NIST_P_384
case STSE_ECC_KT_NIST_P_384:
return ECC_SECP384R1;
#endif
#if defined(STSE_CONF_ECC_NIST_P_521) && defined(HAVE_ECC521)
case STSE_ECC_KT_NIST_P_521:
return ECC_SECP521R1;
#endif
#if defined(STSE_CONF_ECC_BRAINPOOL_P_256) && defined(HAVE_ECC_BRAINPOOL)
case STSE_ECC_KT_BP_P_256:
return ECC_BRAINPOOLP256R1;
#endif
#if defined(STSE_CONF_ECC_BRAINPOOL_P_384) && defined(HAVE_ECC_BRAINPOOL)
case STSE_ECC_KT_BP_P_384:
return ECC_BRAINPOOLP384R1;
#endif
#if defined(STSE_CONF_ECC_BRAINPOOL_P_512) && defined(HAVE_ECC_BRAINPOOL)
case STSE_ECC_KT_BP_P_512:
return ECC_BRAINPOOLP512R1;
#endif
#if defined(STSE_CONF_ECC_CURVE_25519) && defined(HAVE_CURVE25519)
case STSE_ECC_KT_CURVE25519:
return ECC_X25519;
#endif
#if defined(STSE_CONF_ECC_EDWARD_25519) && defined(HAVE_ED25519)
case STSE_ECC_KT_ED25519:
return ECC_ED25519;
#endif
default:
return ECC_SECP256R1; /* Default to P-256 */
}
}
stse_ReturnCode_t stse_platform_ecc_verify(stse_ecc_key_type_t key_type,
const PLAT_UI8 *pPubKey,
PLAT_UI8 *pDigest,
PLAT_UI16 digestLen,
PLAT_UI8 *pSignature)
{
ecc_key eccKey;
int ret;
int verified = 0;
int key_size;
int curve_id;
byte derSig[ECC_MAX_SIG_SIZE];
word32 derSigLen = sizeof(derSig);
if (pPubKey == NULL || pDigest == NULL || pSignature == NULL) {
return STSE_PLATFORM_ECC_VERIFY_ERROR;
}
key_size = stse_get_ecc_key_size(key_type);
if (key_size == 0) {
return STSE_PLATFORM_ECC_VERIFY_ERROR;
}
curve_id = stse_get_wolfssl_curve_id(key_type);
/* Initialize ECC key */
ret = wc_ecc_init(&eccKey);
if (ret != 0) {
return STSE_PLATFORM_ECC_VERIFY_ERROR;
}
/* Import public key (X || Y format) */
ret = wc_ecc_import_unsigned(&eccKey,
(byte*)pPubKey, /* X coordinate */
(byte*)(pPubKey + key_size), /* Y coordinate */
NULL, /* No private key */
curve_id);
if (ret != 0) {
wc_ecc_free(&eccKey);
return STSE_PLATFORM_ECC_VERIFY_ERROR;
}
/* Convert R || S signature to DER format */
ret = wc_ecc_rs_raw_to_sig(pSignature, key_size,
pSignature + key_size, key_size,
derSig, &derSigLen);
if (ret != 0) {
wc_ecc_free(&eccKey);
return STSE_PLATFORM_ECC_VERIFY_ERROR;
}
/* Verify signature */
ret = wc_ecc_verify_hash(derSig, derSigLen, pDigest, digestLen,
&verified, &eccKey);
wc_ecc_free(&eccKey);
if (ret != 0 || verified != 1) {
return STSE_PLATFORM_ECC_VERIFY_ERROR;
}
return STSE_OK;
}
/* ========================================================================== */
/* AES ECB Functions */
/* ========================================================================== */
#if defined(STSE_CONF_USE_HOST_KEY_ESTABLISHMENT) || \
defined(STSE_CONF_USE_SYMMETRIC_KEY_ESTABLISHMENT) || \
defined(STSE_CONF_USE_HOST_SESSION)
stse_ReturnCode_t stse_platform_aes_ecb_enc(const PLAT_UI8 *pPlaintext,
PLAT_UI16 plaintext_length,
const PLAT_UI8 *pKey,
PLAT_UI16 key_length,
PLAT_UI8 *pEncryptedtext,
PLAT_UI16 *pEncryptedtext_length)
{
Aes aes;
int ret;
PLAT_UI16 i;
if (pPlaintext == NULL || pKey == NULL || pEncryptedtext == NULL ||
pEncryptedtext_length == NULL) {
return STSE_PLATFORM_AES_ECB_ENCRYPT_ERROR;
}
/* AES ECB requires block-aligned data */
if ((plaintext_length % AES_BLOCK_SIZE) != 0) {
return STSE_PLATFORM_AES_ECB_ENCRYPT_ERROR;
}
ret = wc_AesInit(&aes, NULL, INVALID_DEVID);
if (ret != 0) {
return STSE_PLATFORM_AES_ECB_ENCRYPT_ERROR;
}
ret = wc_AesSetKey(&aes, pKey, key_length, NULL, AES_ENCRYPTION);
if (ret != 0) {
wc_AesFree(&aes);
return STSE_PLATFORM_AES_ECB_ENCRYPT_ERROR;
}
/* ECB mode: encrypt each block independently */
for (i = 0; i < plaintext_length; i += AES_BLOCK_SIZE) {
ret = wc_AesEncryptDirect(&aes, pEncryptedtext + i, pPlaintext + i);
if (ret != 0) {
wc_AesFree(&aes);
return STSE_PLATFORM_AES_ECB_ENCRYPT_ERROR;
}
}
*pEncryptedtext_length = plaintext_length;
wc_AesFree(&aes);
return STSE_OK;
}
/* ========================================================================== */
/* AES CBC Functions */
/* ========================================================================== */
stse_ReturnCode_t stse_platform_aes_cbc_enc(const PLAT_UI8 *pPlaintext,
PLAT_UI16 plaintext_length,
PLAT_UI8 *pInitial_value,
const PLAT_UI8 *pKey,
PLAT_UI16 key_length,
PLAT_UI8 *pEncryptedtext,
PLAT_UI16 *pEncryptedtext_length)
{
Aes aes;
int ret;
if (pPlaintext == NULL || pKey == NULL || pEncryptedtext == NULL ||
pEncryptedtext_length == NULL || pInitial_value == NULL) {
return STSE_PLATFORM_AES_CBC_ENCRYPT_ERROR;
}
ret = wc_AesInit(&aes, NULL, INVALID_DEVID);
if (ret != 0) {
return STSE_PLATFORM_AES_CBC_ENCRYPT_ERROR;
}
ret = wc_AesSetKey(&aes, pKey, key_length, pInitial_value, AES_ENCRYPTION);
if (ret != 0) {
wc_AesFree(&aes);
return STSE_PLATFORM_AES_CBC_ENCRYPT_ERROR;
}
ret = wc_AesCbcEncrypt(&aes, pEncryptedtext, pPlaintext, plaintext_length);
if (ret != 0) {
wc_AesFree(&aes);
return STSE_PLATFORM_AES_CBC_ENCRYPT_ERROR;
}
*pEncryptedtext_length = plaintext_length;
wc_AesFree(&aes);
return STSE_OK;
}
stse_ReturnCode_t stse_platform_aes_cbc_dec(const PLAT_UI8 *pEncryptedtext,
PLAT_UI16 encryptedtext_length,
PLAT_UI8 *pInitial_value,
const PLAT_UI8 *pKey,
PLAT_UI16 key_length,
PLAT_UI8 *pPlaintext,
PLAT_UI16 *pPlaintext_length)
{
Aes aes;
int ret;
if (pEncryptedtext == NULL || pKey == NULL || pPlaintext == NULL ||
pPlaintext_length == NULL || pInitial_value == NULL) {
return STSE_PLATFORM_AES_CBC_DECRYPT_ERROR;
}
ret = wc_AesInit(&aes, NULL, INVALID_DEVID);
if (ret != 0) {
return STSE_PLATFORM_AES_CBC_DECRYPT_ERROR;
}
ret = wc_AesSetKey(&aes, pKey, key_length, pInitial_value, AES_DECRYPTION);
if (ret != 0) {
wc_AesFree(&aes);
return STSE_PLATFORM_AES_CBC_DECRYPT_ERROR;
}
ret = wc_AesCbcDecrypt(&aes, pPlaintext, pEncryptedtext, encryptedtext_length);
if (ret != 0) {
wc_AesFree(&aes);
return STSE_PLATFORM_AES_CBC_DECRYPT_ERROR;
}
*pPlaintext_length = encryptedtext_length;
wc_AesFree(&aes);
return STSE_OK;
}
/* ========================================================================== */
/* AES CMAC Functions */
/* ========================================================================== */
stse_ReturnCode_t stse_platform_aes_cmac_init(const PLAT_UI8 *pKey,
PLAT_UI16 key_length,
PLAT_UI16 exp_tag_size)
{
int ret;
uint8_t iv[16] = {0};
/* Free any existing context */
if (g_cmac_ctx != NULL) {
ZERO_STRUCTP(g_cmac_ctx);
free(g_cmac_ctx);
g_cmac_ctx = NULL;
}
/* Allocate new context */
g_cmac_ctx = (stse_cmac_ctx_t*)malloc(sizeof(stse_cmac_ctx_t));
if (g_cmac_ctx == NULL) {
return STSE_PLATFORM_AES_CMAC_COMPUTE_ERROR;
}
ZERO_STRUCTP(g_cmac_ctx);
g_cmac_ctx->exp_tag_size = exp_tag_size;
/* Initialize AES context */
ret = wc_AesInit(&g_cmac_ctx->aes, NULL, INVALID_DEVID);
if (ret != 0) {
free(g_cmac_ctx);
g_cmac_ctx = NULL;
return STSE_PLATFORM_AES_CMAC_COMPUTE_ERROR;
}
ret = wc_AesSetKey(&g_cmac_ctx->aes, pKey, key_length, iv, AES_ENCRYPTION);
if (ret != 0) {
wc_AesFree(&g_cmac_ctx->aes);
free(g_cmac_ctx);
g_cmac_ctx = NULL;
return STSE_PLATFORM_AES_CMAC_COMPUTE_ERROR;
}
/* Generate subkeys K1 and K2 */
ret = aes_cmac_generate_subkeys(&g_cmac_ctx->aes, g_cmac_ctx->k1, g_cmac_ctx->k2);
if (ret != 0) {
wc_AesFree(&g_cmac_ctx->aes);
free(g_cmac_ctx);
g_cmac_ctx = NULL;
return STSE_PLATFORM_AES_CMAC_COMPUTE_ERROR;
}
return STSE_OK;
}
stse_ReturnCode_t stse_platform_aes_cmac_append(PLAT_UI8 *pInput, PLAT_UI16 length)
{
uint8_t iv[16] = {0};
uint8_t tmp_block[16];
uint8_t Y[16];
int ret;
if (g_cmac_ctx == NULL) {
return STSE_PLATFORM_AES_CMAC_COMPUTE_ERROR;
}
if (pInput == NULL || length == 0) {
return STSE_OK;
}
/* Copy the remembered last block */
ZERO_STRUCT(tmp_block);
if (g_cmac_ctx->last_len > 0) {
memcpy(tmp_block, g_cmac_ctx->last, g_cmac_ctx->last_len);
}
/* Check if we expand the block */
if (g_cmac_ctx->last_len < 16) {
size_t len = MIN(16 - g_cmac_ctx->last_len, length);
memcpy(&tmp_block[g_cmac_ctx->last_len], pInput, len);
memcpy(g_cmac_ctx->last, tmp_block, 16);
pInput += len;
length -= len;
g_cmac_ctx->last_len += len;
}
if (length == 0) {
/* Still the last block, we are done */
return STSE_OK;
}
/* It is not the last block anymore */
ZERO_STRUCT(g_cmac_ctx->last);
g_cmac_ctx->last_len = 0;
/* Checksum everything but the last block */
ret = wc_AesSetIV(&g_cmac_ctx->aes, iv);
if (ret != 0) return STSE_PLATFORM_AES_CMAC_COMPUTE_ERROR;
aes_cmac_xor(g_cmac_ctx->x, tmp_block, Y);
ret = wc_AesCbcEncrypt(&g_cmac_ctx->aes, g_cmac_ctx->x, Y, 16);
if (ret != 0) return STSE_PLATFORM_AES_CMAC_COMPUTE_ERROR;
while (length > 16) {
memcpy(tmp_block, pInput, 16);
pInput += 16;
length -= 16;
aes_cmac_xor(g_cmac_ctx->x, tmp_block, Y);
ret = wc_AesSetIV(&g_cmac_ctx->aes, iv);
if (ret != 0) return STSE_PLATFORM_AES_CMAC_COMPUTE_ERROR;
ret = wc_AesCbcEncrypt(&g_cmac_ctx->aes, g_cmac_ctx->x, Y, 16);
if (ret != 0) return STSE_PLATFORM_AES_CMAC_COMPUTE_ERROR;
}
/* Copy the last block for processing in finish */
memcpy(g_cmac_ctx->last, pInput, length);
g_cmac_ctx->last_len = length;
return STSE_OK;
}
stse_ReturnCode_t stse_platform_aes_cmac_compute_finish(PLAT_UI8 *pTag, PLAT_UI8 *pTagLen)
{
uint8_t iv[16] = {0};
uint8_t tmp_block[16];
uint8_t Y[16];
uint8_t out_mac[16];
int ret;
if (g_cmac_ctx == NULL || pTag == NULL || pTagLen == NULL) {
return STSE_PLATFORM_AES_CMAC_COMPUTE_ERROR;
}
/* Final block processing */
if (g_cmac_ctx->last_len < 16) {
/* Incomplete block: pad and XOR with K2 */
g_cmac_ctx->last[g_cmac_ctx->last_len] = 0x80;
aes_cmac_xor(g_cmac_ctx->last, g_cmac_ctx->k2, tmp_block);
} else {
/* Complete block: XOR with K1 */
aes_cmac_xor(g_cmac_ctx->last, g_cmac_ctx->k1, tmp_block);
}
aes_cmac_xor(tmp_block, g_cmac_ctx->x, Y);
ret = wc_AesSetIV(&g_cmac_ctx->aes, iv);
if (ret != 0) {
goto cleanup;
}
ret = wc_AesCbcEncrypt(&g_cmac_ctx->aes, out_mac, Y, 16);
if (ret != 0) {
goto cleanup;
}
/* Copy requested tag length */
*pTagLen = (PLAT_UI8)MIN(g_cmac_ctx->exp_tag_size, 16);
memcpy(pTag, out_mac, *pTagLen);
cleanup:
/* Clean up */
wc_AesFree(&g_cmac_ctx->aes);
ZERO_STRUCTP(g_cmac_ctx);
free(g_cmac_ctx);
g_cmac_ctx = NULL;
return (ret == 0) ? STSE_OK : STSE_PLATFORM_AES_CMAC_COMPUTE_ERROR;
}
stse_ReturnCode_t stse_platform_aes_cmac_verify_finish(PLAT_UI8 *pTag)
{
uint8_t computed_tag[16];
PLAT_UI8 tag_len = 16;
stse_ReturnCode_t ret;
if (pTag == NULL) {
return STSE_PLATFORM_AES_CMAC_VERIFY_ERROR;
}
ret = stse_platform_aes_cmac_compute_finish(computed_tag, &tag_len);
if (ret != STSE_OK) {
return STSE_PLATFORM_AES_CMAC_VERIFY_ERROR;
}
/* Constant-time comparison */
uint8_t diff = 0;
for (int i = 0; i < tag_len; i++) {
diff |= computed_tag[i] ^ pTag[i];
}
ZERO_STRUCT(computed_tag);
if (diff != 0) {
return STSE_PLATFORM_AES_CMAC_VERIFY_ERROR;
}
return STSE_OK;
}
stse_ReturnCode_t stse_platform_aes_cmac_compute(const PLAT_UI8 *pPayload,
PLAT_UI16 payload_length,
const PLAT_UI8 *pKey,
PLAT_UI16 key_length,
PLAT_UI16 exp_tag_size,
PLAT_UI8 *pTag,
PLAT_UI16 *pTag_length)
{
stse_ReturnCode_t ret;
PLAT_UI8 tag_len;
ret = stse_platform_aes_cmac_init(pKey, key_length, exp_tag_size);
if (ret != STSE_OK) {
return ret;
}
ret = stse_platform_aes_cmac_append((PLAT_UI8*)pPayload, payload_length);
if (ret != STSE_OK) {
/* Clean up on error */
if (g_cmac_ctx != NULL) {
wc_AesFree(&g_cmac_ctx->aes);
free(g_cmac_ctx);
g_cmac_ctx = NULL;
}
return ret;
}
ret = stse_platform_aes_cmac_compute_finish(pTag, &tag_len);
if (ret == STSE_OK) {
*pTag_length = tag_len;
}
return ret;
}
stse_ReturnCode_t stse_platform_aes_cmac_verify(const PLAT_UI8 *pPayload,
PLAT_UI16 payload_length,
const PLAT_UI8 *pKey,
PLAT_UI16 key_length,
const PLAT_UI8 *pTag,
PLAT_UI16 tag_length)
{
uint8_t computed_tag[16];
PLAT_UI16 computed_len = 16;
stse_ReturnCode_t ret;
uint8_t diff = 0;
ret = stse_platform_aes_cmac_compute(pPayload, payload_length, pKey, key_length,
tag_length, computed_tag, &computed_len);
if (ret != STSE_OK) {
return STSE_PLATFORM_AES_CMAC_VERIFY_ERROR;
}
/* Constant-time comparison */
for (PLAT_UI16 i = 0; i < MIN(tag_length, computed_len); i++) {
diff |= computed_tag[i] ^ pTag[i];
}
ZERO_STRUCT(computed_tag);
if (diff != 0) {
return STSE_PLATFORM_AES_CMAC_VERIFY_ERROR;
}
return STSE_OK;
}
#endif /* STSE_CONF_USE_HOST_KEY_ESTABLISHMENT || STSE_CONF_USE_SYMMETRIC_KEY_ESTABLISHMENT || STSE_CONF_USE_HOST_SESSION */
/* ========================================================================== */
/* HMAC-SHA256 Functions (RFC 5869 HKDF) */
/* ========================================================================== */
stse_ReturnCode_t stse_platform_hmac_sha256_compute(PLAT_UI8 *pSalt, PLAT_UI16 salt_length,
PLAT_UI8 *pInput_keying_material, PLAT_UI16 input_keying_material_length,
PLAT_UI8 *pInfo, PLAT_UI16 info_length,
PLAT_UI8 *pOutput_keying_material, PLAT_UI16 output_keying_material_length)
{
PLAT_UI8 prk[WC_SHA256_DIGEST_SIZE];
stse_ReturnCode_t ret;
/* HKDF-Extract */
ret = stse_platform_hmac_sha256_extract(pSalt, salt_length,
pInput_keying_material, input_keying_material_length,
prk, WC_SHA256_DIGEST_SIZE);
if (ret != STSE_OK) {
return ret;
}
/* HKDF-Expand */
ret = stse_platform_hmac_sha256_expand(prk, WC_SHA256_DIGEST_SIZE,
pInfo, info_length,
pOutput_keying_material, output_keying_material_length);
ZERO_STRUCT(prk);
return ret;
}
stse_ReturnCode_t stse_platform_hmac_sha256_extract(PLAT_UI8 *pSalt, PLAT_UI16 salt_length,
PLAT_UI8 *pInput_keying_material, PLAT_UI16 input_keying_material_length,
PLAT_UI8 *pPseudorandom_key, PLAT_UI16 pseudorandom_key_expected_length)
{
Hmac hmac;
int ret;
uint8_t default_salt[WC_SHA256_DIGEST_SIZE] = {0};
if (pInput_keying_material == NULL || pPseudorandom_key == NULL) {
return STSE_PLATFORM_HKDF_ERROR;
}
if (pseudorandom_key_expected_length < WC_SHA256_DIGEST_SIZE) {
return STSE_PLATFORM_HKDF_ERROR;
}
/* If salt is NULL or zero-length, use default salt of HashLen zeros */
if (pSalt == NULL || salt_length == 0) {
pSalt = default_salt;
salt_length = WC_SHA256_DIGEST_SIZE;
}
ret = wc_HmacInit(&hmac, NULL, INVALID_DEVID);
if (ret != 0) {
return STSE_PLATFORM_HKDF_ERROR;
}
/* PRK = HMAC-Hash(salt, IKM) */
ret = wc_HmacSetKey(&hmac, WC_SHA256, pSalt, salt_length);
if (ret != 0) {
wc_HmacFree(&hmac);
return STSE_PLATFORM_HKDF_ERROR;
}
ret = wc_HmacUpdate(&hmac, pInput_keying_material, input_keying_material_length);
if (ret != 0) {
wc_HmacFree(&hmac);
return STSE_PLATFORM_HKDF_ERROR;
}
ret = wc_HmacFinal(&hmac, pPseudorandom_key);
wc_HmacFree(&hmac);
if (ret != 0) {
return STSE_PLATFORM_HKDF_ERROR;
}
return STSE_OK;
}
stse_ReturnCode_t stse_platform_hmac_sha256_expand(PLAT_UI8 *pPseudorandom_key, PLAT_UI16 pseudorandom_key_length,
PLAT_UI8 *pInfo, PLAT_UI16 info_length,
PLAT_UI8 *pOutput_keying_material, PLAT_UI16 output_keying_material_length)
{
Hmac hmac;
int ret;
uint8_t T[WC_SHA256_DIGEST_SIZE];
PLAT_UI16 T_len = 0;
PLAT_UI16 out_index = 0;
uint8_t counter = 1;
PLAT_UI16 N;
if (pPseudorandom_key == NULL || pOutput_keying_material == NULL) {
return STSE_PLATFORM_HKDF_ERROR;
}
/* RFC 5869: L <= 255*HashLen */
N = (output_keying_material_length + WC_SHA256_DIGEST_SIZE - 1) / WC_SHA256_DIGEST_SIZE;
if (N > 255) {
return STSE_PLATFORM_HKDF_ERROR;
}
ret = wc_HmacInit(&hmac, NULL, INVALID_DEVID);
if (ret != 0) {
return STSE_PLATFORM_HKDF_ERROR;
}
while (out_index < output_keying_material_length) {
PLAT_UI16 copy_len;
ret = wc_HmacSetKey(&hmac, WC_SHA256, pPseudorandom_key, pseudorandom_key_length);
if (ret != 0) break;
/* T(i) = HMAC-Hash(PRK, T(i-1) | info | i) */
if (T_len > 0) {
ret = wc_HmacUpdate(&hmac, T, T_len);
if (ret != 0) break;
}
if (pInfo != NULL && info_length > 0) {
ret = wc_HmacUpdate(&hmac, pInfo, info_length);
if (ret != 0) break;
}
ret = wc_HmacUpdate(&hmac, &counter, 1);
if (ret != 0) break;
ret = wc_HmacFinal(&hmac, T);
if (ret != 0) break;
/* Copy to output */
copy_len = MIN(WC_SHA256_DIGEST_SIZE, output_keying_material_length - out_index);
memcpy(pOutput_keying_material + out_index, T, copy_len);
T_len = WC_SHA256_DIGEST_SIZE;
out_index += WC_SHA256_DIGEST_SIZE;
counter++;
}
wc_HmacFree(&hmac);
ZERO_STRUCT(T);
if (ret != 0) {
memset(pOutput_keying_material, 0, output_keying_material_length);
return STSE_PLATFORM_HKDF_ERROR;
}
return STSE_OK;
}
/* ========================================================================== */
/* NIST Key Wrap (Optional - stub for now) */
/* ========================================================================== */
stse_ReturnCode_t stse_platform_nist_kw_encrypt(PLAT_UI8 *pPayload, PLAT_UI32 payload_length,
PLAT_UI8 *pKey, PLAT_UI8 key_length,
PLAT_UI8 *pOutput, PLAT_UI32 *pOutput_length)
{
(void)pPayload;
(void)payload_length;
(void)pKey;
(void)key_length;
(void)pOutput;
(void)pOutput_length;
/* TODO: Implement using wc_AesKeyWrap if needed */
return STSE_PLATFORM_AES_ECB_ENCRYPT_ERROR;
}

View File

@ -0,0 +1,47 @@
/******************************************************************************
* \file stse_platform_generic.h
* \brief STSecureElement platform types for Linux/Raspberry Pi
* \author wolfSSL Inc.
*
******************************************************************************
* \attention
*
* Copyright 2025 wolfSSL Inc.
*
* This file is part of wolfSSL.
*
******************************************************************************
*/
#ifndef STSE_PLATFORM_GENERIC_H
#define STSE_PLATFORM_GENERIC_H
#ifdef __cplusplus
extern "C" {
#endif
#include <stdint.h>
#include <stddef.h>
#include <stdio.h>
#include <string.h>
/* Platform type definitions for Linux */
#define PLAT_UI8 uint8_t
#define PLAT_UI16 uint16_t
#define PLAT_UI32 uint32_t
#define PLAT_UI64 uint64_t
#define PLAT_I8 int8_t
#define PLAT_I16 int16_t
#define PLAT_I32 int32_t
#define PLAT_PACKED_STRUCT __attribute__((packed))
/* __WEAK attribute for overridable functions */
#ifndef __WEAK
#define __WEAK __attribute__((weak))
#endif
#ifdef __cplusplus
}
#endif
#endif /* STSE_PLATFORM_GENERIC_H */

View File

@ -0,0 +1,468 @@
/******************************************************************************
* \file stse_platform_linux.c
* \brief STSecureElement platform implementation for Linux/Raspberry Pi
* \author wolfSSL Inc.
*
******************************************************************************
* \attention
*
* Copyright 2025 wolfSSL Inc.
*
* This file is part of wolfSSL.
*
******************************************************************************
*/
#include "core/stse_platform.h"
#include <fcntl.h>
#include <unistd.h>
#include <sys/ioctl.h>
#include <linux/i2c-dev.h>
#include <time.h>
#include <stdlib.h>
#include <errno.h>
/* I2C bus file descriptor */
static int g_i2c_fd = -1;
static uint8_t g_current_addr = 0;
/* I2C buffer for frame assembly */
#define I2C_BUFFER_SIZE 755U
static PLAT_UI8 I2c_tx_buffer[I2C_BUFFER_SIZE];
static PLAT_UI8 I2c_rx_buffer[I2C_BUFFER_SIZE];
static PLAT_UI16 i2c_tx_frame_size;
static volatile PLAT_UI16 i2c_tx_frame_offset;
static PLAT_UI16 i2c_rx_frame_size;
static volatile PLAT_UI16 i2c_rx_frame_offset;
/* Timeout tracking */
static struct timespec g_timeout_start;
static PLAT_UI16 g_timeout_ms = 0;
/*--------------------- I2C Functions --------------------------- */
stse_ReturnCode_t stse_platform_i2c_init(PLAT_UI8 busID)
{
char i2c_path[20];
if (g_i2c_fd >= 0) {
return STSE_OK; /* Already initialized */
}
snprintf(i2c_path, sizeof(i2c_path), "/dev/i2c-%d", busID);
g_i2c_fd = open(i2c_path, O_RDWR);
if (g_i2c_fd < 0) {
perror("Failed to open I2C bus");
return STSE_PLATFORM_BUS_ERR;
}
return STSE_OK;
}
stse_ReturnCode_t stse_platform_i2c_wake(PLAT_UI8 busID,
PLAT_UI8 devAddr,
PLAT_UI16 speed)
{
(void)speed;
if (g_i2c_fd < 0) {
stse_ReturnCode_t ret = stse_platform_i2c_init(busID);
if (ret != STSE_OK) {
return ret;
}
}
/* Set I2C slave address */
if (ioctl(g_i2c_fd, I2C_SLAVE, devAddr) < 0) {
return STSE_PLATFORM_BUS_ERR;
}
g_current_addr = devAddr;
/* Send wake-up byte (0x00) */
uint8_t wake_byte = 0x00;
write(g_i2c_fd, &wake_byte, 1);
/* Wait for device to wake up */
usleep(5000); /* 5ms */
return STSE_OK;
}
stse_ReturnCode_t stse_platform_i2c_send_start(
PLAT_UI8 busID,
PLAT_UI8 devAddr,
PLAT_UI16 speed,
PLAT_UI16 FrameLength)
{
(void)busID;
(void)devAddr;
(void)speed;
if (FrameLength > I2C_BUFFER_SIZE) {
return STSE_PLATFORM_BUFFER_ERR;
}
i2c_tx_frame_size = FrameLength;
i2c_tx_frame_offset = 0;
return STSE_OK;
}
stse_ReturnCode_t stse_platform_i2c_send_continue(
PLAT_UI8 busID,
PLAT_UI8 devAddr,
PLAT_UI16 speed,
PLAT_UI8 *pData,
PLAT_UI16 data_size)
{
(void)busID;
(void)devAddr;
(void)speed;
if (data_size != 0) {
if (pData == NULL) {
memset((I2c_tx_buffer + i2c_tx_frame_offset), 0x00, data_size);
} else {
memcpy((I2c_tx_buffer + i2c_tx_frame_offset), pData, data_size);
}
i2c_tx_frame_offset += data_size;
}
return STSE_OK;
}
stse_ReturnCode_t stse_platform_i2c_send_stop(
PLAT_UI8 busID,
PLAT_UI8 devAddr,
PLAT_UI16 speed,
PLAT_UI8 *pElement,
PLAT_UI16 element_size)
{
(void)speed;
if (g_i2c_fd < 0) {
stse_ReturnCode_t ret = stse_platform_i2c_init(busID);
if (ret != STSE_OK) {
return ret;
}
}
/* Add final element if provided */
if (pElement != NULL && element_size > 0) {
memcpy((I2c_tx_buffer + i2c_tx_frame_offset), pElement, element_size);
i2c_tx_frame_offset += element_size;
}
/* Set I2C slave address if changed */
if (g_current_addr != devAddr) {
if (ioctl(g_i2c_fd, I2C_SLAVE, devAddr) < 0) {
return STSE_PLATFORM_BUS_ERR;
}
g_current_addr = devAddr;
}
/* Write the assembled frame */
ssize_t written = write(g_i2c_fd, I2c_tx_buffer, i2c_tx_frame_offset);
if (written != (ssize_t)i2c_tx_frame_offset) {
return STSE_PLATFORM_BUS_ERR;
}
return STSE_OK;
}
stse_ReturnCode_t stse_platform_i2c_send(
PLAT_UI8 busID,
PLAT_UI8 devAddr,
PLAT_UI16 speed,
PLAT_UI8 *pData,
PLAT_UI16 data_size)
{
(void)speed;
if (g_i2c_fd < 0) {
stse_ReturnCode_t ret = stse_platform_i2c_init(busID);
if (ret != STSE_OK) {
return ret;
}
}
/* Set I2C slave address */
if (g_current_addr != devAddr) {
if (ioctl(g_i2c_fd, I2C_SLAVE, devAddr) < 0) {
return STSE_PLATFORM_BUS_ERR;
}
g_current_addr = devAddr;
}
ssize_t written = write(g_i2c_fd, pData, data_size);
if (written != (ssize_t)data_size) {
return STSE_PLATFORM_BUS_ERR;
}
return STSE_OK;
}
stse_ReturnCode_t stse_platform_i2c_receive(
PLAT_UI8 busID,
PLAT_UI8 devAddr,
PLAT_UI16 speed,
PLAT_UI8 *pFrame_header,
PLAT_UI8 *pFrame_payload,
PLAT_UI16 *pFrame_payload_Length)
{
(void)speed;
if (g_i2c_fd < 0) {
stse_ReturnCode_t ret = stse_platform_i2c_init(busID);
if (ret != STSE_OK) {
return ret;
}
}
/* Set I2C slave address */
if (g_current_addr != devAddr) {
if (ioctl(g_i2c_fd, I2C_SLAVE, devAddr) < 0) {
return STSE_PLATFORM_BUS_ERR;
}
g_current_addr = devAddr;
}
/* Read header byte first */
ssize_t rd = read(g_i2c_fd, pFrame_header, 1);
if (rd != 1) {
return STSE_PLATFORM_BUS_ERR;
}
/* Read length (2 bytes) */
PLAT_UI8 len_bytes[2];
rd = read(g_i2c_fd, len_bytes, 2);
if (rd != 2) {
return STSE_PLATFORM_BUS_ERR;
}
PLAT_UI16 payload_len = ((PLAT_UI16)len_bytes[0] << 8) | len_bytes[1];
*pFrame_payload_Length = payload_len;
if (payload_len > 0 && pFrame_payload != NULL) {
rd = read(g_i2c_fd, pFrame_payload, payload_len);
if (rd != (ssize_t)payload_len) {
return STSE_PLATFORM_BUS_ERR;
}
}
return STSE_OK;
}
stse_ReturnCode_t stse_platform_i2c_receive_start(
PLAT_UI8 busID,
PLAT_UI8 devAddr,
PLAT_UI16 speed,
PLAT_UI16 frame_Length)
{
(void)speed;
ssize_t rd;
if (frame_Length > I2C_BUFFER_SIZE) {
return STSE_PLATFORM_BUFFER_ERR;
}
if (g_i2c_fd < 0) {
stse_ReturnCode_t ret = stse_platform_i2c_init(busID);
if (ret != STSE_OK) {
return ret;
}
}
if (g_current_addr != devAddr) {
if (ioctl(g_i2c_fd, I2C_SLAVE, devAddr) < 0) {
return STSE_PLATFORM_BUS_ERR;
}
g_current_addr = devAddr;
}
/* Read the full frame into buffer */
rd = read(g_i2c_fd, I2c_rx_buffer, frame_Length);
if (rd != (ssize_t)frame_Length) {
return STSE_PLATFORM_BUS_ACK_ERROR;
}
i2c_rx_frame_size = frame_Length;
i2c_rx_frame_offset = 0;
return STSE_OK;
}
stse_ReturnCode_t stse_platform_i2c_receive_continue(
PLAT_UI8 busID,
PLAT_UI8 devAddr,
PLAT_UI16 speed,
PLAT_UI8 *pElement,
PLAT_UI16 element_size)
{
(void)busID;
(void)devAddr;
(void)speed;
if (pElement != NULL && element_size > 0) {
/* Check for buffer overflow */
if ((i2c_rx_frame_size - i2c_rx_frame_offset) < element_size) {
return STSE_PLATFORM_BUFFER_ERR;
}
/* Copy from receive buffer */
memcpy(pElement, (I2c_rx_buffer + i2c_rx_frame_offset), element_size);
}
i2c_rx_frame_offset += element_size;
return STSE_OK;
}
stse_ReturnCode_t stse_platform_i2c_receive_stop(
PLAT_UI8 busID,
PLAT_UI8 devAddr,
PLAT_UI16 speed,
PLAT_UI8 *pElement,
PLAT_UI16 element_size)
{
stse_ReturnCode_t ret;
/* Copy last element */
ret = stse_platform_i2c_receive_continue(busID, devAddr, speed, pElement, element_size);
i2c_rx_frame_offset = 0;
return ret;
}
/*--------------------- Delay/Timeout Functions --------------------------- */
stse_ReturnCode_t stse_platform_delay_init(void)
{
return STSE_OK;
}
void stse_platform_Delay_ms(PLAT_UI32 delay_val)
{
usleep(delay_val * 1000);
}
void stse_platform_timeout_ms_start(PLAT_UI16 timeout_val)
{
clock_gettime(CLOCK_MONOTONIC, &g_timeout_start);
g_timeout_ms = timeout_val;
}
PLAT_UI8 stse_platform_timeout_ms_get_status(void)
{
struct timespec now;
clock_gettime(CLOCK_MONOTONIC, &now);
long elapsed_ms = (now.tv_sec - g_timeout_start.tv_sec) * 1000 +
(now.tv_nsec - g_timeout_start.tv_nsec) / 1000000;
return (elapsed_ms >= g_timeout_ms) ? 1 : 0;
}
/*--------------------- CRC Functions --------------------------- */
/* CRC-16-CCITT table (reflected/LSB-first) - matches STSAFE protocol */
static const PLAT_UI16 crc16_tab[] = {
0x0000, 0x1189, 0x2312, 0x329b, 0x4624, 0x57ad, 0x6536, 0x74bf,
0x8c48, 0x9dc1, 0xaf5a, 0xbed3, 0xca6c, 0xdbe5, 0xe97e, 0xf8f7,
0x1081, 0x0108, 0x3393, 0x221a, 0x56a5, 0x472c, 0x75b7, 0x643e,
0x9cc9, 0x8d40, 0xbfdb, 0xae52, 0xdaed, 0xcb64, 0xf9ff, 0xe876,
0x2102, 0x308b, 0x0210, 0x1399, 0x6726, 0x76af, 0x4434, 0x55bd,
0xad4a, 0xbcc3, 0x8e58, 0x9fd1, 0xeb6e, 0xfae7, 0xc87c, 0xd9f5,
0x3183, 0x200a, 0x1291, 0x0318, 0x77a7, 0x662e, 0x54b5, 0x453c,
0xbdcb, 0xac42, 0x9ed9, 0x8f50, 0xfbef, 0xea66, 0xd8fd, 0xc974,
0x4204, 0x538d, 0x6116, 0x709f, 0x0420, 0x15a9, 0x2732, 0x36bb,
0xce4c, 0xdfc5, 0xed5e, 0xfcd7, 0x8868, 0x99e1, 0xab7a, 0xbaf3,
0x5285, 0x430c, 0x7197, 0x601e, 0x14a1, 0x0528, 0x37b3, 0x263a,
0xdecd, 0xcf44, 0xfddf, 0xec56, 0x98e9, 0x8960, 0xbbfb, 0xaa72,
0x6306, 0x728f, 0x4014, 0x519d, 0x2522, 0x34ab, 0x0630, 0x17b9,
0xef4e, 0xfec7, 0xcc5c, 0xddd5, 0xa96a, 0xb8e3, 0x8a78, 0x9bf1,
0x7387, 0x620e, 0x5095, 0x411c, 0x35a3, 0x242a, 0x16b1, 0x0738,
0xffcf, 0xee46, 0xdcdd, 0xcd54, 0xb9eb, 0xa862, 0x9af9, 0x8b70,
0x8408, 0x9581, 0xa71a, 0xb693, 0xc22c, 0xd3a5, 0xe13e, 0xf0b7,
0x0840, 0x19c9, 0x2b52, 0x3adb, 0x4e64, 0x5fed, 0x6d76, 0x7cff,
0x9489, 0x8500, 0xb79b, 0xa612, 0xd2ad, 0xc324, 0xf1bf, 0xe036,
0x18c1, 0x0948, 0x3bd3, 0x2a5a, 0x5ee5, 0x4f6c, 0x7df7, 0x6c7e,
0xa50a, 0xb483, 0x8618, 0x9791, 0xe32e, 0xf2a7, 0xc03c, 0xd1b5,
0x2942, 0x38cb, 0x0a50, 0x1bd9, 0x6f66, 0x7eef, 0x4c74, 0x5dfd,
0xb58b, 0xa402, 0x9699, 0x8710, 0xf3af, 0xe226, 0xd0bd, 0xc134,
0x39c3, 0x284a, 0x1ad1, 0x0b58, 0x7fe7, 0x6e6e, 0x5cf5, 0x4d7c,
0xc60c, 0xd785, 0xe51e, 0xf497, 0x8028, 0x91a1, 0xa33a, 0xb2b3,
0x4a44, 0x5bcd, 0x6956, 0x78df, 0x0c60, 0x1de9, 0x2f72, 0x3efb,
0xd68d, 0xc704, 0xf59f, 0xe416, 0x90a9, 0x8120, 0xb3bb, 0xa232,
0x5ac5, 0x4b4c, 0x79d7, 0x685e, 0x1ce1, 0x0d68, 0x3ff3, 0x2e7a,
0xe70e, 0xf687, 0xc41c, 0xd595, 0xa12a, 0xb0a3, 0x8238, 0x93b1,
0x6b46, 0x7acf, 0x4854, 0x59dd, 0x2d62, 0x3ceb, 0x0e70, 0x1ff9,
0xf78f, 0xe606, 0xd49d, 0xc514, 0xb1ab, 0xa022, 0x92b9, 0x8330,
0x7bc7, 0x6a4e, 0x58d5, 0x495c, 0x3de3, 0x2c6a, 0x1ef1, 0x0f78
};
static PLAT_UI16 g_crc_val = 0xFFFF;
stse_ReturnCode_t stse_platform_crc16_init(void)
{
return STSE_OK;
}
PLAT_UI16 stse_platform_Crc16_Calculate(PLAT_UI8 *pbuffer, PLAT_UI16 length)
{
PLAT_UI16 i;
g_crc_val = 0xFFFF;
for (i = 0; i < length; i++) {
g_crc_val = ((g_crc_val >> 8) ^ crc16_tab[(g_crc_val ^ pbuffer[i]) & 0x00FF]);
}
return ~g_crc_val;
}
PLAT_UI16 stse_platform_Crc16_Accumulate(PLAT_UI8 *pbuffer, PLAT_UI16 length)
{
PLAT_UI16 i;
for (i = 0; i < length; i++) {
g_crc_val = ((g_crc_val >> 8) ^ crc16_tab[(g_crc_val ^ pbuffer[i]) & 0x00FF]);
}
return ~g_crc_val;
}
/*--------------------- Power Functions --------------------------- */
stse_ReturnCode_t stse_platform_power_init(void)
{
return STSE_OK;
}
stse_ReturnCode_t stse_platform_power_on(PLAT_UI8 busID, PLAT_UI8 devAddr)
{
(void)busID;
(void)devAddr;
return STSE_OK;
}
stse_ReturnCode_t stse_platform_power_off(PLAT_UI8 busID, PLAT_UI8 devAddr)
{
(void)busID;
(void)devAddr;
return STSE_OK;
}
/*--------------------- Random Functions --------------------------- */
stse_ReturnCode_t stse_platform_generate_random_init(void)
{
srand((unsigned int)time(NULL));
return STSE_OK;
}
PLAT_UI32 stse_platform_generate_random(void)
{
return (PLAT_UI32)rand();
}

View File

@ -0,0 +1,308 @@
/* stsafe_test.c
*
* Copyright (C) 2006-2026 wolfSSL Inc.
*
* This file is part of wolfSSL. (formerly known as CyaSSL)
*
* 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-1301, USA
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdint.h>
/* Include STSELib */
#include "stselib.h"
/* STSAFE-A120 default I2C bus */
#define STSAFE_A120_I2C_BUS 1
/* Test result tracking */
static int tests_passed = 0;
static int tests_failed = 0;
#define TEST_PASS(msg) do { printf("[PASS] %s\n", msg); tests_passed++; } while(0)
#define TEST_FAIL(msg) do { printf("[FAIL] %s\n", msg); tests_failed++; } while(0)
/* STSAFE device handler */
static stse_Handler_t stsafe_handler;
/*--------------------- Test: Echo Command --------------------------- */
static int test_echo(void)
{
stse_ReturnCode_t ret;
uint8_t echo_data[] = {0x01, 0x02, 0x03, 0x04, 0x05};
uint8_t response[sizeof(echo_data)];
printf("\nTest: Echo Command\n");
printf(" Sending %zu bytes...\n", sizeof(echo_data));
memset(response, 0, sizeof(response));
ret = stse_device_echo(&stsafe_handler, echo_data, response, sizeof(echo_data));
if (ret != STSE_OK) {
printf(" Error: stse_device_echo returned 0x%04X\n", ret);
TEST_FAIL("Echo command failed");
return -1;
}
if (memcmp(echo_data, response, sizeof(echo_data)) != 0) {
printf(" Error: Response data mismatch\n");
printf(" Expected: ");
for (size_t i = 0; i < sizeof(echo_data); i++) printf("%02X ", echo_data[i]);
printf("\n Got: ");
for (size_t i = 0; i < sizeof(response); i++) printf("%02X ", response[i]);
printf("\n");
TEST_FAIL("Echo data mismatch");
return -1;
}
printf(" Echo response matches!\n");
TEST_PASS("Echo command");
return 0;
}
/*--------------------- Test: Random Number Generation --------------------------- */
static int test_random(void)
{
stse_ReturnCode_t ret;
uint8_t random_data[32];
int all_zeros = 1;
printf("\nTest: Random Number Generation\n");
printf(" Requesting 32 random bytes...\n");
memset(random_data, 0, sizeof(random_data));
ret = stse_generate_random(&stsafe_handler, random_data, sizeof(random_data));
if (ret != STSE_OK) {
printf(" Error: stse_generate_random returned 0x%04X\n", ret);
TEST_FAIL("Random generation failed");
return -1;
}
/* Check that data is not all zeros */
for (size_t i = 0; i < sizeof(random_data); i++) {
if (random_data[i] != 0) {
all_zeros = 0;
break;
}
}
if (all_zeros) {
printf(" Error: Random data is all zeros\n");
TEST_FAIL("Random data is all zeros");
return -1;
}
printf(" Random data: ");
for (size_t i = 0; i < 16; i++) {
printf("%02X ", random_data[i]);
}
printf("...\n");
TEST_PASS("Random number generation");
return 0;
}
/*--------------------- Test: ECC Key Generation (P-256) --------------------------- */
static int test_ecc_keygen_p256(void)
{
stse_ReturnCode_t ret;
uint8_t public_key[64]; /* P-256 public key: 32 bytes X + 32 bytes Y */
uint8_t slot = 1; /* Key slot 1 */
stse_ecc_key_type_t key_type = STSE_ECC_KT_NIST_P_256;
printf("\nTest: ECC Key Generation (P-256)\n");
memset(public_key, 0, sizeof(public_key));
/* usage_limit = 255 for limited use */
ret = stse_generate_ecc_key_pair(&stsafe_handler,
slot,
key_type,
255, /* usage_limit */
public_key);
if (ret != STSE_OK) {
printf(" Error: stse_generate_ecc_key_pair returned 0x%04X\n", ret);
TEST_FAIL("ECC P-256 key generation failed");
return -1;
}
printf(" Public Key X: ");
for (int i = 0; i < 8; i++) {
printf("%02X", public_key[i]);
}
printf("...\n");
printf(" Public Key Y: ");
for (int i = 32; i < 40; i++) {
printf("%02X", public_key[i]);
}
printf("...\n");
TEST_PASS("ECC P-256 key generation");
return 0;
}
/*--------------------- Test: ECDSA Sign (P-256) --------------------------- */
static int test_ecdsa_sign_p256(void)
{
stse_ReturnCode_t ret;
uint8_t digest[32]; /* SHA-256 digest */
uint8_t signature[64]; /* P-256 signature: 32 bytes R + 32 bytes S */
uint8_t public_key[64];
uint8_t slot = 2; /* Key slot 2 for signing test */
stse_ecc_key_type_t key_type = STSE_ECC_KT_NIST_P_256;
printf("\nTest: ECDSA Sign (P-256)\n");
/* Create a test digest */
memset(digest, 0xAB, sizeof(digest));
memset(signature, 0, sizeof(signature));
memset(public_key, 0, sizeof(public_key));
/* First generate a key pair */
ret = stse_generate_ecc_key_pair(&stsafe_handler,
slot,
key_type,
255, /* usage_limit */
public_key);
if (ret != STSE_OK) {
printf(" Error: Key generation failed with 0x%04X\n", ret);
TEST_FAIL("ECDSA sign - key generation failed");
return -1;
}
printf(" Key pair generated.\n");
/* Sign the digest */
ret = stse_ecc_generate_signature(&stsafe_handler,
slot,
key_type,
digest, sizeof(digest),
signature);
if (ret != STSE_OK) {
printf(" Error: stse_ecc_generate_signature returned 0x%04X\n", ret);
TEST_FAIL("ECDSA P-256 sign failed");
return -1;
}
printf(" Signature R: ");
for (int i = 0; i < 8; i++) {
printf("%02X", signature[i]);
}
printf("...\n");
printf(" Signature S: ");
for (int i = 32; i < 40; i++) {
printf("%02X", signature[i]);
}
printf("...\n");
TEST_PASS("ECDSA P-256 sign");
return 0;
}
/*--------------------- Test: ECC Key Generation (P-384) --------------------------- */
static int test_ecc_keygen_p384(void)
{
stse_ReturnCode_t ret;
uint8_t public_key[96]; /* P-384 public key: 48 bytes X + 48 bytes Y */
uint8_t slot = 3; /* Key slot 3 for P-384 */
stse_ecc_key_type_t key_type = STSE_ECC_KT_NIST_P_384;
printf("\nTest: ECC Key Generation (P-384)\n");
memset(public_key, 0, sizeof(public_key));
ret = stse_generate_ecc_key_pair(&stsafe_handler,
slot,
key_type,
255, /* usage_limit */
public_key);
if (ret != STSE_OK) {
printf(" Error: stse_generate_ecc_key_pair returned 0x%04X\n", ret);
TEST_FAIL("ECC P-384 key generation failed");
return -1;
}
printf(" Public Key X: ");
for (int i = 0; i < 8; i++) {
printf("%02X", public_key[i]);
}
printf("...\n");
printf(" Public Key Y: ");
for (int i = 48; i < 56; i++) {
printf("%02X", public_key[i]);
}
printf("...\n");
TEST_PASS("ECC P-384 key generation");
return 0;
}
/*--------------------- Main --------------------------- */
int main(int argc, char *argv[])
{
stse_ReturnCode_t ret;
(void)argc;
(void)argv;
printf("================================================\n");
printf("STSAFE-A120 Test Suite for wolfSSL Integration\n");
printf("================================================\n");
/* Initialize STSAFE handler with defaults */
printf("\nInitializing STSAFE handler...\n");
ret = stse_set_default_handler_value(&stsafe_handler);
if (ret != STSE_OK) {
printf("Error: stse_set_default_handler_value failed: 0x%04X\n", ret);
return 1;
}
/* Configure for STSAFE-A120 on I2C bus 1 */
stsafe_handler.device_type = STSAFE_A120;
stsafe_handler.io.busID = STSAFE_A120_I2C_BUS;
stsafe_handler.io.BusSpeed = 100; /* 100 kHz for reliability */
printf("Initializing STSAFE-A120 device on I2C bus %d...\n", STSAFE_A120_I2C_BUS);
ret = stse_init(&stsafe_handler);
if (ret != STSE_OK) {
printf("Error: stse_init failed: 0x%04X\n", ret);
return 1;
}
printf("STSAFE-A120 initialized successfully.\n");
/* Run tests */
test_echo();
test_random();
test_ecc_keygen_p256();
test_ecdsa_sign_p256();
test_ecc_keygen_p384();
/* Print summary */
printf("\n================================================\n");
printf("Test Summary: %d passed, %d failed\n", tests_passed, tests_failed);
printf("================================================\n");
return (tests_failed > 0) ? 1 : 0;
}

View File

@ -0,0 +1,125 @@
/* user_settings.h
*
* Copyright (C) 2006-2026 wolfSSL Inc.
*
* This file is part of wolfSSL. (formerly known as CyaSSL)
*
* 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-1301, USA
*/
#ifndef USER_SETTINGS_H
#define USER_SETTINGS_H
#ifdef __cplusplus
extern "C" {
#endif
/* ------------------------------------------------------------------------- */
/* Platform Configuration */
/* ------------------------------------------------------------------------- */
#define SIZEOF_LONG_LONG 8
/* Threading - single threaded for simple testing */
/* #define SINGLE_THREADED */
/* Use /dev/urandom for random */
/* #define NO_DEV_RANDOM */
#define NO_OLD_TLS
/* ------------------------------------------------------------------------- */
/* Crypto Algorithms Required for STSAFE Platform */
/* ------------------------------------------------------------------------- */
/* AES - Required for CMAC, CBC, ECB */
#undef NO_AES
#define WOLFSSL_AES_DIRECT /* Required for ECB mode */
#define HAVE_AES_CBC /* Required for CBC mode */
#define WOLFSSL_CMAC /* Required for AES-CMAC */
/* SHA-256 - Required for HMAC-SHA256 (HKDF) */
#undef NO_SHA256
/* SHA-384 - For P-384 operations */
#define WOLFSSL_SHA384
/* HMAC - Required for HKDF */
#undef NO_HMAC
/* ECC - For wolfSSL STSAFE integration */
#define HAVE_ECC
#define ECC_USER_CURVES
#undef NO_ECC256 /* Enable P-256 */
#define HAVE_ECC384 /* Enable P-384 */
#define ECC_TIMING_RESISTANT
/* ECC key import/export functions */
#define WOLFSSL_PUBLIC_MP /* For mp_int access in ECC verify */
/* Math library */
#define WOLFSSL_SP_MATH_ALL
#define WOLFSSL_SP_384
/* ------------------------------------------------------------------------- */
/* Disable Unused Algorithms (reduce footprint) */
/* ------------------------------------------------------------------------- */
#define NO_RSA
#define NO_DH
#define NO_DSA
#define NO_RC4
#define NO_MD4
#define NO_MD5
#define NO_DES3
#define NO_HC128
#define NO_RABBIT
#define NO_PWDBASED
/* Keep SHA-1 disabled unless needed */
#define NO_SHA
/* ------------------------------------------------------------------------- */
/* Optional Features */
/* ------------------------------------------------------------------------- */
/* Debugging */
#define DEBUG_WOLFSSL
/* Error strings */
#undef NO_ERROR_STRINGS
/* ASN.1 */
#define WOLFSSL_ASN_TEMPLATE
/* ------------------------------------------------------------------------- */
/* STSAFE-A120 Integration */
/* ------------------------------------------------------------------------- */
/* Enable STSAFE-A120 support */
#define WOLFSSL_STSAFEA120
/* Enable crypto callbacks for STSAFE hardware acceleration */
#define WOLF_CRYPTO_CB
/* Use STSAFE for RNG seeding */
#define USE_STSAFE_RNG_SEED
/* Include STSELib header path set in Makefile */
#ifdef __cplusplus
}
#endif
#endif /* USER_SETTINGS_H */

View File

@ -0,0 +1,477 @@
/* wolfssl_stsafe_full_test.c
*
* Copyright (C) 2006-2026 wolfSSL Inc.
*
* This file is part of wolfSSL. (formerly known as CyaSSL)
*
* 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-1301, USA
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdint.h>
#include <time.h>
#include <sys/time.h>
/* wolfSSL headers */
#include <wolfssl/options.h>
#include <wolfssl/wolfcrypt/settings.h>
#include <wolfssl/wolfcrypt/random.h>
#include <wolfssl/wolfcrypt/ecc.h>
#include <wolfssl/wolfcrypt/sha256.h>
#include <wolfssl/wolfcrypt/cryptocb.h>
#include <wolfssl/wolfcrypt/port/st/stsafe.h>
/* Test result macros */
#define TEST_PASS(msg) do { printf("[PASS] %s\n", msg); g_passed++; } while(0)
#define TEST_FAIL(msg) do { printf("[FAIL] %s\n", msg); g_failed++; } while(0)
static int g_passed = 0;
static int g_failed = 0;
/* STSAFE crypto callback context */
static wolfSTSAFE_CryptoCb_Ctx g_stsafe_ctx;
static int g_devId = INVALID_DEVID;
/* Get time in microseconds */
static double get_time_us(void)
{
struct timeval tv;
gettimeofday(&tv, NULL);
return (double)tv.tv_sec * 1000000.0 + (double)tv.tv_usec;
}
/*-----------------------------------------------------------------------------
* Test: RNG Performance
*---------------------------------------------------------------------------*/
static int test_rng_benchmark(void)
{
WC_RNG rng;
byte rand_buf[256];
int ret;
int iterations = 100;
double start, end, elapsed;
int i;
printf("\nTest: RNG Benchmark (STSAFE-A120)\n");
ret = wc_InitRng_ex(&rng, NULL, g_devId);
if (ret != 0) {
printf(" Error: wc_InitRng_ex failed: %d\n", ret);
TEST_FAIL("RNG benchmark init");
return -1;
}
/* Warm up */
wc_RNG_GenerateBlock(&rng, rand_buf, sizeof(rand_buf));
/* Benchmark */
start = get_time_us();
for (i = 0; i < iterations; i++) {
ret = wc_RNG_GenerateBlock(&rng, rand_buf, sizeof(rand_buf));
if (ret != 0) break;
}
end = get_time_us();
elapsed = (end - start) / 1000.0; /* ms */
if (ret != 0) {
printf(" Error: wc_RNG_GenerateBlock failed: %d\n", ret);
wc_FreeRng(&rng);
TEST_FAIL("RNG benchmark");
return -1;
}
printf(" Generated %d x 256 bytes in %.2f ms\n", iterations, elapsed);
printf(" Throughput: %.2f KB/s\n",
(iterations * 256.0) / (elapsed / 1000.0) / 1024.0);
wc_FreeRng(&rng);
TEST_PASS("RNG benchmark");
return 0;
}
/*-----------------------------------------------------------------------------
* Test: ECDSA P-256 Benchmark
*---------------------------------------------------------------------------*/
static int test_ecdsa_p256_benchmark(void)
{
ecc_key key;
WC_RNG rng;
int ret;
byte digest[32];
byte sig[128];
word32 sigLen;
int verified = 0;
int iterations = 10;
double start, end, elapsed;
int i;
printf("\nTest: ECDSA P-256 Benchmark (STSAFE-A120)\n");
ret = wc_InitRng(&rng);
if (ret != 0) {
printf(" Error: wc_InitRng failed: %d\n", ret);
TEST_FAIL("ECDSA P-256 benchmark RNG init");
return -1;
}
memset(digest, 0xAB, sizeof(digest));
ret = wc_ecc_init_ex(&key, NULL, g_devId);
if (ret != 0) {
printf(" Error: wc_ecc_init_ex failed: %d\n", ret);
wc_FreeRng(&rng);
TEST_FAIL("ECDSA P-256 benchmark key init");
return -1;
}
/* Benchmark key generation */
start = get_time_us();
ret = wc_ecc_make_key_ex(&rng, 32, &key, ECC_SECP256R1);
end = get_time_us();
elapsed = (end - start) / 1000.0;
if (ret != 0) {
printf(" Error: wc_ecc_make_key_ex failed: %d\n", ret);
wc_ecc_free(&key);
wc_FreeRng(&rng);
TEST_FAIL("ECDSA P-256 keygen");
return -1;
}
printf(" Key generation: %.2f ms\n", elapsed);
/* Benchmark signing */
start = get_time_us();
for (i = 0; i < iterations; i++) {
sigLen = sizeof(sig);
ret = wc_ecc_sign_hash(digest, sizeof(digest), sig, &sigLen, &rng, &key);
if (ret != 0) break;
}
end = get_time_us();
elapsed = (end - start) / 1000.0;
if (ret != 0) {
printf(" Error: wc_ecc_sign_hash failed: %d\n", ret);
wc_ecc_free(&key);
wc_FreeRng(&rng);
TEST_FAIL("ECDSA P-256 sign");
return -1;
}
printf(" Signing: %d ops in %.2f ms (%.2f ops/sec)\n",
iterations, elapsed, iterations / (elapsed / 1000.0));
/* Benchmark verification */
start = get_time_us();
for (i = 0; i < iterations; i++) {
ret = wc_ecc_verify_hash(sig, sigLen, digest, sizeof(digest), &verified, &key);
if (ret != 0 || verified != 1) break;
}
end = get_time_us();
elapsed = (end - start) / 1000.0;
if (ret != 0 || verified != 1) {
printf(" Error: wc_ecc_verify_hash failed: %d, verified=%d\n", ret, verified);
wc_ecc_free(&key);
wc_FreeRng(&rng);
TEST_FAIL("ECDSA P-256 verify");
return -1;
}
printf(" Verification: %d ops in %.2f ms (%.2f ops/sec)\n",
iterations, elapsed, iterations / (elapsed / 1000.0));
wc_ecc_free(&key);
wc_FreeRng(&rng);
TEST_PASS("ECDSA P-256 benchmark");
return 0;
}
/*-----------------------------------------------------------------------------
* Test: ECDH Key Exchange
* Note: STSAFE has a single key slot, so we generate one key in STSAFE
* and one in software to test ECDH properly.
*---------------------------------------------------------------------------*/
static int test_ecdh_p256(void)
{
ecc_key keyHW; /* Hardware key in STSAFE */
ecc_key keySW; /* Software key */
WC_RNG rng;
int ret;
byte sharedHW[32], sharedSW[32];
word32 sharedHWLen = sizeof(sharedHW), sharedSWLen = sizeof(sharedSW);
double start, end;
int i;
printf("\nTest: ECDH P-256 Key Exchange (HW + SW)\n");
printf(" Note: STSAFE key used for one side, software for other\n");
ret = wc_InitRng(&rng);
if (ret != 0) {
printf(" Error: wc_InitRng failed: %d\n", ret);
TEST_FAIL("ECDH P-256 RNG init");
return -1;
}
/* Initialize hardware key (with STSAFE devId) */
ret = wc_ecc_init_ex(&keyHW, NULL, g_devId);
if (ret != 0) {
printf(" Error: wc_ecc_init_ex (HW) failed: %d\n", ret);
wc_FreeRng(&rng);
TEST_FAIL("ECDH P-256 key init HW");
return -1;
}
/* Initialize software key (INVALID_DEVID for software) */
ret = wc_ecc_init_ex(&keySW, NULL, INVALID_DEVID);
if (ret != 0) {
printf(" Error: wc_ecc_init_ex (SW) failed: %d\n", ret);
wc_ecc_free(&keyHW);
wc_FreeRng(&rng);
TEST_FAIL("ECDH P-256 key init SW");
return -1;
}
/* Generate hardware key pair (in STSAFE) */
printf(" Generating hardware key pair (STSAFE)...\n");
start = get_time_us();
ret = wc_ecc_make_key_ex(&rng, 32, &keyHW, ECC_SECP256R1);
end = get_time_us();
if (ret != 0) {
printf(" Error: wc_ecc_make_key_ex (HW) failed: %d\n", ret);
wc_ecc_free(&keyHW);
wc_ecc_free(&keySW);
wc_FreeRng(&rng);
TEST_FAIL("ECDH P-256 keygen HW");
return -1;
}
printf(" HW Key generated in %.2f ms\n", (end - start) / 1000.0);
/* Generate software key pair */
printf(" Generating software key pair...\n");
start = get_time_us();
ret = wc_ecc_make_key_ex(&rng, 32, &keySW, ECC_SECP256R1);
end = get_time_us();
if (ret != 0) {
printf(" Error: wc_ecc_make_key_ex (SW) failed: %d\n", ret);
wc_ecc_free(&keyHW);
wc_ecc_free(&keySW);
wc_FreeRng(&rng);
TEST_FAIL("ECDH P-256 keygen SW");
return -1;
}
printf(" SW Key generated in %.2f ms\n", (end - start) / 1000.0);
/* Compute shared secret using STSAFE (HW priv * SW pub) */
printf(" Computing shared secret (STSAFE: HW priv * SW pub)...\n");
start = get_time_us();
ret = wc_ecc_shared_secret(&keyHW, &keySW, sharedHW, &sharedHWLen);
end = get_time_us();
if (ret != 0) {
printf(" Error: wc_ecc_shared_secret (HW) failed: %d\n", ret);
wc_ecc_free(&keyHW);
wc_ecc_free(&keySW);
wc_FreeRng(&rng);
TEST_FAIL("ECDH P-256 shared secret HW");
return -1;
}
printf(" STSAFE ECDH computed in %.2f ms\n", (end - start) / 1000.0);
/* Compute shared secret using software (SW priv * HW pub) */
printf(" Computing shared secret (Software: SW priv * HW pub)...\n");
start = get_time_us();
ret = wc_ecc_shared_secret(&keySW, &keyHW, sharedSW, &sharedSWLen);
end = get_time_us();
if (ret != 0) {
printf(" Error: wc_ecc_shared_secret (SW) failed: %d\n", ret);
wc_ecc_free(&keyHW);
wc_ecc_free(&keySW);
wc_FreeRng(&rng);
TEST_FAIL("ECDH P-256 shared secret SW");
return -1;
}
printf(" Software ECDH computed in %.2f ms\n", (end - start) / 1000.0);
/* Compare shared secrets - they must match! */
if (sharedHWLen != sharedSWLen || memcmp(sharedHW, sharedSW, sharedHWLen) != 0) {
printf(" Error: Shared secrets don't match!\n");
printf(" HW: ");
for (i = 0; i < 8; i++) printf("%02X", sharedHW[i]);
printf("...\n");
printf(" SW: ");
for (i = 0; i < 8; i++) printf("%02X", sharedSW[i]);
printf("...\n");
wc_ecc_free(&keyHW);
wc_ecc_free(&keySW);
wc_FreeRng(&rng);
TEST_FAIL("ECDH P-256 shared secret mismatch");
return -1;
}
printf(" Shared secrets match! (");
for (i = 0; i < 8; i++) printf("%02X", sharedHW[i]);
printf("...)\n");
wc_ecc_free(&keyHW);
wc_ecc_free(&keySW);
wc_FreeRng(&rng);
TEST_PASS("ECDH P-256 key exchange (HW+SW)");
return 0;
}
/*-----------------------------------------------------------------------------
* Test: Multiple Key Slots
*---------------------------------------------------------------------------*/
static int test_multiple_operations(void)
{
ecc_key keys[3];
WC_RNG rng;
int ret;
byte digest[32];
byte sigs[3][128];
word32 sigLens[3];
int verified;
int i;
printf("\nTest: Multiple Sequential Operations\n");
ret = wc_InitRng(&rng);
if (ret != 0) {
printf(" Error: wc_InitRng failed: %d\n", ret);
TEST_FAIL("Multiple ops RNG init");
return -1;
}
memset(digest, 0xCD, sizeof(digest));
/* Generate 3 key pairs and sign with each */
for (i = 0; i < 3; i++) {
ret = wc_ecc_init_ex(&keys[i], NULL, g_devId);
if (ret != 0) {
printf(" Error: wc_ecc_init_ex[%d] failed: %d\n", i, ret);
while (--i >= 0) wc_ecc_free(&keys[i]);
wc_FreeRng(&rng);
TEST_FAIL("Multiple ops key init");
return -1;
}
printf(" Generating key pair %d...\n", i + 1);
ret = wc_ecc_make_key_ex(&rng, 32, &keys[i], ECC_SECP256R1);
if (ret != 0) {
printf(" Error: wc_ecc_make_key_ex[%d] failed: %d\n", i, ret);
for (int j = 0; j <= i; j++) wc_ecc_free(&keys[j]);
wc_FreeRng(&rng);
TEST_FAIL("Multiple ops keygen");
return -1;
}
/* Sign with this key */
sigLens[i] = sizeof(sigs[i]);
ret = wc_ecc_sign_hash(digest, sizeof(digest), sigs[i], &sigLens[i], &rng, &keys[i]);
if (ret != 0) {
printf(" Error: wc_ecc_sign_hash[%d] failed: %d\n", i, ret);
for (int j = 0; j <= i; j++) wc_ecc_free(&keys[j]);
wc_FreeRng(&rng);
TEST_FAIL("Multiple ops sign");
return -1;
}
printf(" Key %d: Generated and signed successfully\n", i + 1);
}
/* Verify all signatures */
printf(" Verifying all signatures...\n");
for (i = 0; i < 3; i++) {
ret = wc_ecc_verify_hash(sigs[i], sigLens[i], digest, sizeof(digest),
&verified, &keys[i]);
if (ret != 0 || verified != 1) {
printf(" Error: Verification[%d] failed: ret=%d, verified=%d\n",
i, ret, verified);
for (int j = 0; j < 3; j++) wc_ecc_free(&keys[j]);
wc_FreeRng(&rng);
TEST_FAIL("Multiple ops verify");
return -1;
}
}
printf(" All 3 signatures verified!\n");
for (i = 0; i < 3; i++) wc_ecc_free(&keys[i]);
wc_FreeRng(&rng);
TEST_PASS("Multiple sequential operations");
return 0;
}
/*-----------------------------------------------------------------------------
* Main
*---------------------------------------------------------------------------*/
int main(void)
{
int ret;
printf("================================================================\n");
printf("wolfSSL STSAFE-A120 Full Integration Test Suite\n");
printf("================================================================\n");
/* Initialize wolfCrypt */
ret = wolfCrypt_Init();
if (ret != 0) {
printf("Error: wolfCrypt_Init failed: %d\n", ret);
return 1;
}
/* Initialize STSAFE interface */
printf("\nInitializing STSAFE-A120...\n");
ret = stsafe_interface_init();
if (ret != 0) {
printf("Error: stsafe_interface_init failed: %d\n", ret);
wolfCrypt_Cleanup();
return 1;
}
printf("STSAFE-A120 initialized successfully.\n");
/* Register STSAFE crypto callback */
g_devId = 0x53545341; /* STSA */
memset(&g_stsafe_ctx, 0, sizeof(g_stsafe_ctx));
g_stsafe_ctx.devId = g_devId;
ret = wc_CryptoCb_RegisterDevice(g_devId, wolfSSL_STSAFE_CryptoDevCb,
&g_stsafe_ctx);
if (ret != 0) {
printf("Error: wc_CryptoCb_RegisterDevice failed: %d\n", ret);
wolfCrypt_Cleanup();
return 1;
}
printf("STSAFE crypto callback registered (devId: 0x%08X).\n", g_devId);
/* Run tests */
test_rng_benchmark();
test_ecdsa_p256_benchmark();
/* Note: ECDH requires ephemeral keys via stse_generate_ECDHE_key_pair
* which is not yet implemented in the crypto callback.
* Skipping ECDH test for now. */
printf("\n[SKIP] ECDH P-256 - requires ECDHE key generation (not yet implemented)\n");
test_multiple_operations();
/* Cleanup */
wc_CryptoCb_UnRegisterDevice(g_devId);
wolfCrypt_Cleanup();
printf("\n================================================================\n");
printf("Test Summary: %d passed, %d failed\n", g_passed, g_failed);
printf("================================================================\n");
return (g_failed > 0) ? 1 : 0;
}

View File

@ -0,0 +1,445 @@
/* wolfssl_stsafe_test.c
*
* Copyright (C) 2006-2026 wolfSSL Inc.
*
* This file is part of wolfSSL. (formerly known as CyaSSL)
*
* 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-1301, USA
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdint.h>
/* wolfSSL headers */
/* Must include options.h to match libwolfssl build settings */
#include <wolfssl/options.h>
#include <wolfssl/wolfcrypt/settings.h>
#include <wolfssl/wolfcrypt/random.h>
#include <wolfssl/wolfcrypt/ecc.h>
#include <wolfssl/wolfcrypt/sha256.h>
#include <wolfssl/wolfcrypt/cryptocb.h>
#include <wolfssl/wolfcrypt/port/st/stsafe.h>
/* Test result macros */
#define TEST_PASS(msg) do { printf("[PASS] %s\n", msg); g_passed++; } while(0)
#define TEST_FAIL(msg) do { printf("[FAIL] %s\n", msg); g_failed++; } while(0)
static int g_passed = 0;
static int g_failed = 0;
/* STSAFE crypto callback context */
static wolfSTSAFE_CryptoCb_Ctx g_stsafe_ctx;
static int g_devId = INVALID_DEVID;
/*-----------------------------------------------------------------------------
* Test: RNG with STSAFE-A120
*---------------------------------------------------------------------------*/
static int test_rng(void)
{
WC_RNG rng;
byte rand_buf[32];
int ret;
int i;
printf("\nTest: RNG with STSAFE-A120\n");
ret = wc_InitRng_ex(&rng, NULL, g_devId);
if (ret != 0) {
printf(" Error: wc_InitRng_ex failed: %d\n", ret);
TEST_FAIL("RNG initialization");
return -1;
}
/* Generate random bytes */
ret = wc_RNG_GenerateBlock(&rng, rand_buf, sizeof(rand_buf));
if (ret != 0) {
printf(" Error: wc_RNG_GenerateBlock failed: %d\n", ret);
wc_FreeRng(&rng);
TEST_FAIL("RNG generation");
return -1;
}
/* Print random data */
printf(" Random data: ");
for (i = 0; i < 16; i++) {
printf("%02X ", rand_buf[i]);
}
printf("...\n");
wc_FreeRng(&rng);
TEST_PASS("RNG with STSAFE-A120");
return 0;
}
/*-----------------------------------------------------------------------------
* Test: ECC P-256 Key Generation with STSAFE-A120
*---------------------------------------------------------------------------*/
static int test_ecc_keygen_p256(void)
{
ecc_key key;
WC_RNG rng;
int ret;
byte pubX[32], pubY[32];
word32 pubX_len = sizeof(pubX), pubY_len = sizeof(pubY);
int i;
printf("\nTest: ECC P-256 Key Generation with STSAFE-A120\n");
ret = wc_InitRng(&rng);
if (ret != 0) {
printf(" Error: wc_InitRng failed: %d\n", ret);
TEST_FAIL("ECC P-256 RNG init");
return -1;
}
ret = wc_ecc_init_ex(&key, NULL, g_devId);
if (ret != 0) {
printf(" Error: wc_ecc_init_ex failed: %d\n", ret);
wc_FreeRng(&rng);
TEST_FAIL("ECC P-256 init");
return -1;
}
/* Generate P-256 key pair - should use STSAFE via crypto callback */
ret = wc_ecc_make_key_ex(&rng, 32, &key, ECC_SECP256R1);
if (ret != 0) {
printf(" Error: wc_ecc_make_key_ex failed: %d\n", ret);
wc_ecc_free(&key);
wc_FreeRng(&rng);
TEST_FAIL("ECC P-256 key generation");
return -1;
}
/* Export public key */
ret = wc_ecc_export_public_raw(&key, pubX, &pubX_len, pubY, &pubY_len);
if (ret != 0) {
printf(" Error: wc_ecc_export_public_raw failed: %d\n", ret);
wc_ecc_free(&key);
wc_FreeRng(&rng);
TEST_FAIL("ECC P-256 export public key");
return -1;
}
printf(" Public Key X: ");
for (i = 0; i < 8; i++) printf("%02X", pubX[i]);
printf("...\n");
printf(" Public Key Y: ");
for (i = 0; i < 8; i++) printf("%02X", pubY[i]);
printf("...\n");
wc_ecc_free(&key);
wc_FreeRng(&rng);
TEST_PASS("ECC P-256 key generation");
return 0;
}
/*-----------------------------------------------------------------------------
* Test: ECC P-384 Key Generation with STSAFE-A120
*---------------------------------------------------------------------------*/
static int test_ecc_keygen_p384(void)
{
ecc_key key;
WC_RNG rng;
int ret;
byte pubX[48], pubY[48];
word32 pubX_len = sizeof(pubX), pubY_len = sizeof(pubY);
int i;
printf("\nTest: ECC P-384 Key Generation with STSAFE-A120\n");
ret = wc_InitRng(&rng);
if (ret != 0) {
printf(" Error: wc_InitRng failed: %d\n", ret);
TEST_FAIL("ECC P-384 RNG init");
return -1;
}
ret = wc_ecc_init_ex(&key, NULL, g_devId);
if (ret != 0) {
printf(" Error: wc_ecc_init_ex failed: %d\n", ret);
wc_FreeRng(&rng);
TEST_FAIL("ECC P-384 init");
return -1;
}
/* Generate P-384 key pair - should use STSAFE via crypto callback */
ret = wc_ecc_make_key_ex(&rng, 48, &key, ECC_SECP384R1);
if (ret != 0) {
printf(" Error: wc_ecc_make_key_ex failed: %d\n", ret);
wc_ecc_free(&key);
wc_FreeRng(&rng);
TEST_FAIL("ECC P-384 key generation");
return -1;
}
/* Export public key */
ret = wc_ecc_export_public_raw(&key, pubX, &pubX_len, pubY, &pubY_len);
if (ret != 0) {
printf(" Error: wc_ecc_export_public_raw failed: %d\n", ret);
wc_ecc_free(&key);
wc_FreeRng(&rng);
TEST_FAIL("ECC P-384 export public key");
return -1;
}
printf(" Public Key X: ");
for (i = 0; i < 8; i++) printf("%02X", pubX[i]);
printf("...\n");
printf(" Public Key Y: ");
for (i = 0; i < 8; i++) printf("%02X", pubY[i]);
printf("...\n");
wc_ecc_free(&key);
wc_FreeRng(&rng);
TEST_PASS("ECC P-384 key generation");
return 0;
}
/*-----------------------------------------------------------------------------
* Test: ECDSA Sign/Verify P-256 with STSAFE-A120
*---------------------------------------------------------------------------*/
static int test_ecdsa_p256(void)
{
ecc_key key;
WC_RNG rng;
int ret;
byte digest[32];
byte sig[128];
word32 sigLen = sizeof(sig);
int verified = 0;
int i;
printf("\nTest: ECDSA P-256 Sign/Verify with STSAFE-A120\n");
/* Initialize RNG */
ret = wc_InitRng(&rng);
if (ret != 0) {
printf(" Error: wc_InitRng failed: %d\n", ret);
TEST_FAIL("ECDSA P-256 RNG init");
return -1;
}
/* Create test digest */
memset(digest, 0xAB, sizeof(digest));
ret = wc_ecc_init_ex(&key, NULL, g_devId);
if (ret != 0) {
printf(" Error: wc_ecc_init_ex failed: %d\n", ret);
wc_FreeRng(&rng);
TEST_FAIL("ECDSA P-256 key init");
return -1;
}
/* Generate key pair using STSAFE */
ret = wc_ecc_make_key_ex(&rng, 32, &key, ECC_SECP256R1);
if (ret != 0) {
printf(" Error: wc_ecc_make_key_ex failed: %d\n", ret);
wc_ecc_free(&key);
wc_FreeRng(&rng);
TEST_FAIL("ECDSA P-256 key generation");
return -1;
}
printf(" Key pair generated.\n");
/* Sign the digest using STSAFE */
ret = wc_ecc_sign_hash(digest, sizeof(digest), sig, &sigLen, &rng, &key);
if (ret != 0) {
printf(" Error: wc_ecc_sign_hash failed: %d\n", ret);
wc_ecc_free(&key);
wc_FreeRng(&rng);
TEST_FAIL("ECDSA P-256 sign");
return -1;
}
printf(" Signature (%d bytes): ", sigLen);
for (i = 0; i < 8 && i < (int)sigLen; i++) printf("%02X", sig[i]);
printf("...\n");
/* Verify the signature */
ret = wc_ecc_verify_hash(sig, sigLen, digest, sizeof(digest), &verified, &key);
if (ret != 0) {
printf(" Error: wc_ecc_verify_hash failed: %d\n", ret);
wc_ecc_free(&key);
wc_FreeRng(&rng);
TEST_FAIL("ECDSA P-256 verify");
return -1;
}
if (verified != 1) {
printf(" Error: Signature verification failed\n");
wc_ecc_free(&key);
wc_FreeRng(&rng);
TEST_FAIL("ECDSA P-256 verification result");
return -1;
}
printf(" Signature verified!\n");
wc_ecc_free(&key);
wc_FreeRng(&rng);
TEST_PASS("ECDSA P-256 sign/verify");
return 0;
}
/*-----------------------------------------------------------------------------
* Test: ECDSA Sign/Verify P-384 with STSAFE-A120
*---------------------------------------------------------------------------*/
static int test_ecdsa_p384(void)
{
ecc_key key;
WC_RNG rng;
int ret;
byte digest[48];
byte sig[128];
word32 sigLen = sizeof(sig);
int verified = 0;
int i;
printf("\nTest: ECDSA P-384 Sign/Verify with STSAFE-A120\n");
/* Initialize RNG */
ret = wc_InitRng(&rng);
if (ret != 0) {
printf(" Error: wc_InitRng failed: %d\n", ret);
TEST_FAIL("ECDSA P-384 RNG init");
return -1;
}
/* Create test digest */
memset(digest, 0xCD, sizeof(digest));
ret = wc_ecc_init_ex(&key, NULL, g_devId);
if (ret != 0) {
printf(" Error: wc_ecc_init_ex failed: %d\n", ret);
wc_FreeRng(&rng);
TEST_FAIL("ECDSA P-384 key init");
return -1;
}
/* Generate key pair using STSAFE */
ret = wc_ecc_make_key_ex(&rng, 48, &key, ECC_SECP384R1);
if (ret != 0) {
printf(" Error: wc_ecc_make_key_ex failed: %d\n", ret);
wc_ecc_free(&key);
wc_FreeRng(&rng);
TEST_FAIL("ECDSA P-384 key generation");
return -1;
}
printf(" Key pair generated.\n");
/* Sign the digest using STSAFE */
ret = wc_ecc_sign_hash(digest, sizeof(digest), sig, &sigLen, &rng, &key);
if (ret != 0) {
printf(" Error: wc_ecc_sign_hash failed: %d\n", ret);
wc_ecc_free(&key);
wc_FreeRng(&rng);
TEST_FAIL("ECDSA P-384 sign");
return -1;
}
printf(" Signature (%d bytes): ", sigLen);
for (i = 0; i < 8 && i < (int)sigLen; i++) printf("%02X", sig[i]);
printf("...\n");
/* Verify the signature */
ret = wc_ecc_verify_hash(sig, sigLen, digest, sizeof(digest), &verified, &key);
if (ret != 0) {
printf(" Error: wc_ecc_verify_hash failed: %d\n", ret);
wc_ecc_free(&key);
wc_FreeRng(&rng);
TEST_FAIL("ECDSA P-384 verify");
return -1;
}
if (verified != 1) {
printf(" Error: Signature verification failed\n");
wc_ecc_free(&key);
wc_FreeRng(&rng);
TEST_FAIL("ECDSA P-384 verification result");
return -1;
}
printf(" Signature verified!\n");
wc_ecc_free(&key);
wc_FreeRng(&rng);
TEST_PASS("ECDSA P-384 sign/verify");
return 0;
}
/*-----------------------------------------------------------------------------
* Main
*---------------------------------------------------------------------------*/
int main(void)
{
int ret;
printf("================================================\n");
printf("wolfSSL STSAFE-A120 Crypto Callback Test Suite\n");
printf("================================================\n");
/* Initialize wolfCrypt */
ret = wolfCrypt_Init();
if (ret != 0) {
printf("Error: wolfCrypt_Init failed: %d\n", ret);
return 1;
}
/* Initialize STSAFE interface */
printf("\nInitializing STSAFE-A120...\n");
ret = stsafe_interface_init();
if (ret != 0) {
printf("Error: stsafe_interface_init failed: %d\n", ret);
wolfCrypt_Cleanup();
return 1;
}
printf("STSAFE-A120 initialized successfully.\n");
/* Register STSAFE crypto callback */
g_devId = 0x53545341; /* STSA */
memset(&g_stsafe_ctx, 0, sizeof(g_stsafe_ctx));
g_stsafe_ctx.devId = g_devId;
ret = wc_CryptoCb_RegisterDevice(g_devId, wolfSSL_STSAFE_CryptoDevCb,
&g_stsafe_ctx);
if (ret != 0) {
printf("Error: wc_CryptoCb_RegisterDevice failed: %d\n", ret);
wolfCrypt_Cleanup();
return 1;
}
printf("STSAFE crypto callback registered (devId: 0x%08X).\n", g_devId);
/* Run tests */
test_rng();
test_ecc_keygen_p256();
test_ecc_keygen_p384();
test_ecdsa_p256();
test_ecdsa_p384();
/* Cleanup */
wc_CryptoCb_UnRegisterDevice(g_devId);
wolfCrypt_Cleanup();
printf("\n================================================\n");
printf("Test Summary: %d passed, %d failed\n", g_passed, g_failed);
printf("================================================\n");
return (g_failed > 0) ? 1 : 0;
}