Skip to content

Commit cafe66c

Browse files
committed
Add STM32 CubeMX HW ECDSA sign/verify crypto-callback
1 parent e838426 commit cafe66c

2 files changed

Lines changed: 113 additions & 13 deletions

File tree

wolfcrypt/src/port/st/README.md

Lines changed: 10 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -83,20 +83,25 @@ The TinyAES IP exposes a single key-size bit (128/256 only), so wolfSSL auto-def
8383

8484
Some newer families (H5/H7S/U3/U5/WBA/C5/N6, plus the L562 sub-variant) expose a Secure AES (SAES) instance in addition to (or instead of) a regular AES block. Define `WOLFSSL_STM32_USE_SAES` to route all wolfcrypt AES traffic through SAES via the `WC_STM32_AES_INST` indirection macro. This is required when the regular AES block is TrustZone-gated (H7S3) and is also a prerequisite for DHUK key-wrap on the families in the `WC_STM32_HAS_DHUK` gate (U3/U5/H5/WBA/C5).
8585

86-
### AES via crypto callback (`WOLF_CRYPTO_CB_ONLY_AES`)
86+
### HW crypto via crypto callback (`WOLF_CRYPTO_CB_ONLY_AES` / `_ECC`)
8787

88-
`WOLF_CRYPTO_CB_ONLY_AES` strips the software AES core (to shrink code) and routes every AES operation through the `WOLF_CRYPTO_CB` framework. On the CubeMX/HAL build, register the STM32 CubeMX AES device so those callbacks reach the HAL AES hardware:
88+
`WOLF_CRYPTO_CB_ONLY_AES` and `WOLF_CRYPTO_CB_ONLY_ECC` strip the software AES / ECC cores (to shrink code) and route those operations through the `WOLF_CRYPTO_CB` framework. On the CubeMX/HAL build the STM32 crypto-callback device services them in hardware:
89+
90+
- **AES** (ECB, and GCM via the HAL GCM engine) with the normal plaintext key.
91+
- **ECDSA sign + verify** on the HW PKA (`WOLFSSL_STM32_PKA`), plus CCB-protected sign (`WOLFSSL_STM32_CCB`) via `HAL_CCB`. This makes `WOLF_CRYPTO_CB_ONLY_ECC` usable on CubeMX -- that macro compiles out the direct `ecc.c` PKA path, so the callback provides HW ECDSA instead.
8992

9093
```
9194
#define WOLFSSL_STM32_CUBEMX
95+
#define WOLFSSL_STM32_PKA /* HW ECC sign/verify */
9296
#define WOLF_CRYPTO_CB
97+
#define WOLFSSL_STM32_CCB /* optional: CCB-protected ECDSA */
9398
#define WOLF_CRYPTO_CB_ONLY_AES
99+
#define WOLF_CRYPTO_CB_ONLY_ECC
94100
...
95-
wc_Stm32_CubeAesRegister(devId); /* once */
96-
wc_AesInit(&aes, NULL, devId); /* per Aes; then use wc_AesGcm* as normal */
101+
wc_Stm32_DhukRegister(devId); /* once; serves AES + ECDSA (+ CCB) */
97102
```
98103

99-
The device services AES-ECB on the HAL, which is what `wc_AesGcmSetKey` needs to derive the GHASH subkey; AES-GCM then runs on the native HAL GCM engine, all with the normal plaintext key. When `WOLFSSL_STM32_CCB` is enabled, `wc_Stm32_DhukRegister` dispatches these ciphers too, so a single devId serves both CCB ECDSA and AES. Worked example: [`STM32_Bare_Test/src/main_cubeaes.c`](https://github.com/wolfSSL/wolfssl-examples-stm32) (validated on NUCLEO-U385RG-Q).
104+
(For an AES-only build without CCB/ECC, `wc_Stm32_CubeAesRegister(devId)` registers a cipher-only device.) HW PKA on the HAL build requires the application to build/link ST's `stm32XXxx_hal_pka.c` and provide a `PKA_HandleTypeDef hpka;` initialized with `HAL_PKA_Init(&hpka)` (a CubeMX `MX_PKA_Init`); wolfSSL references `hpka` as `extern`. Note: CCB key *provisioning* (`wc_ecc_make_key`) derives the scalar in software, so it needs a build without `WOLF_CRYPTO_CB_ONLY_ECC` -- provision the CCB blob there, after which CCB *sign* runs under the stripped config. Worked examples in [`STM32_Bare_Test`](https://github.com/wolfSSL/wolfssl-examples-stm32): `main_cubeaes.c` (AES) and `main_cubecrypto.c` (ECC + CCB + AES), validated on NUCLEO-U385RG-Q.
100105

101106
### Coding
102107

wolfcrypt/src/port/st/stm32.c

Lines changed: 103 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -5161,7 +5161,72 @@ static int Stm32Cube_Cipher(struct wc_CryptoInfo* info)
51615161
}
51625162
}
51635163

5164-
/* Standalone AES-only device for CubeMX builds without the CCB/DHUK ECDSA
5164+
#if defined(WOLFSSL_STM32_PKA) && defined(HAVE_ECC)
5165+
/* HW ECDSA sign/verify via the STM32 PKA, dispatched through the crypto
5166+
* callback. Needed on CubeMX under WOLF_CRYPTO_CB_ONLY_ECC, where ecc.c compiles
5167+
* out the direct PKA path and routes ECDSA through the callback instead. The
5168+
* PKA workers (stm32_ecc_*_hash_ex) run on the HAL PKA driver; the application
5169+
* must provide/init the PKA (extern hpka + HAL_PKA_Init). */
5170+
#if defined(HAVE_ECC_VERIFY) && !defined(WC_STM32_PKA_SIGN_ONLY)
5171+
static int Stm32Cube_EccVerify(struct wc_CryptoInfo* info)
5172+
{
5173+
ecc_key* key = info->pk.eccverify.key;
5174+
mp_int r;
5175+
mp_int s;
5176+
int ret;
5177+
5178+
if (key == NULL || info->pk.eccverify.sig == NULL ||
5179+
info->pk.eccverify.res == NULL) {
5180+
return CRYPTOCB_UNAVAILABLE;
5181+
}
5182+
XMEMSET(&r, 0, sizeof(r));
5183+
XMEMSET(&s, 0, sizeof(s));
5184+
5185+
/* DecodeECC_DSA_Sig() mp_init's r and s (mirrors the ecc.c verify path). */
5186+
ret = DecodeECC_DSA_Sig(info->pk.eccverify.sig,
5187+
info->pk.eccverify.siglen, &r, &s);
5188+
if (ret == 0) {
5189+
ret = stm32_ecc_verify_hash_ex(&r, &s, info->pk.eccverify.hash,
5190+
info->pk.eccverify.hashlen,
5191+
info->pk.eccverify.res, key);
5192+
}
5193+
mp_free(&r);
5194+
mp_free(&s);
5195+
return ret;
5196+
}
5197+
#endif /* HAVE_ECC_VERIFY && !WC_STM32_PKA_SIGN_ONLY */
5198+
5199+
#if defined(HAVE_ECC_SIGN) && !defined(WC_STM32_PKA_VERIFY_ONLY)
5200+
static int Stm32Cube_EccSign(struct wc_CryptoInfo* info)
5201+
{
5202+
ecc_key* key = info->pk.eccsign.key;
5203+
mp_int r;
5204+
mp_int s;
5205+
int ret;
5206+
5207+
if (key == NULL) {
5208+
return CRYPTOCB_UNAVAILABLE;
5209+
}
5210+
XMEMSET(&r, 0, sizeof(r));
5211+
XMEMSET(&s, 0, sizeof(s));
5212+
ret = mp_init_multi(&r, &s, NULL, NULL, NULL, NULL);
5213+
if (ret != 0) {
5214+
return ret;
5215+
}
5216+
ret = stm32_ecc_sign_hash_ex(info->pk.eccsign.in, info->pk.eccsign.inlen,
5217+
info->pk.eccsign.rng, key, &r, &s);
5218+
if (ret == 0) {
5219+
ret = StoreECC_DSA_Sig(info->pk.eccsign.out, info->pk.eccsign.outlen,
5220+
&r, &s);
5221+
}
5222+
mp_free(&r);
5223+
mp_free(&s);
5224+
return ret;
5225+
}
5226+
#endif /* HAVE_ECC_SIGN && !WC_STM32_PKA_VERIFY_ONLY */
5227+
#endif /* WOLFSSL_STM32_PKA && HAVE_ECC */
5228+
5229+
/* Standalone AES(+PKA-ECC) device for CubeMX builds without the CCB/DHUK ECDSA
51655230
* device. Register at a devId, then wc_AesInit(aes, heap, devId). (With
51665231
* WOLFSSL_STM32_CCB the CCB device dispatches ciphers here too.) */
51675232
static int Stm32Cube_AesCryptoDevCb(int devId, struct wc_CryptoInfo* info,
@@ -5176,6 +5241,20 @@ static int Stm32Cube_AesCryptoDevCb(int devId, struct wc_CryptoInfo* info,
51765241
if (info->algo_type == WC_ALGO_TYPE_CIPHER) {
51775242
return Stm32Cube_Cipher(info);
51785243
}
5244+
#if defined(WOLFSSL_STM32_PKA) && defined(HAVE_ECC)
5245+
if (info->algo_type == WC_ALGO_TYPE_PK) {
5246+
#if defined(HAVE_ECC_VERIFY) && !defined(WC_STM32_PKA_SIGN_ONLY)
5247+
if (info->pk.type == WC_PK_TYPE_ECDSA_VERIFY) {
5248+
return Stm32Cube_EccVerify(info);
5249+
}
5250+
#endif
5251+
#if defined(HAVE_ECC_SIGN) && !defined(WC_STM32_PKA_VERIFY_ONLY)
5252+
if (info->pk.type == WC_PK_TYPE_ECDSA_SIGN) {
5253+
return Stm32Cube_EccSign(info);
5254+
}
5255+
#endif
5256+
}
5257+
#endif /* WOLFSSL_STM32_PKA && HAVE_ECC */
51795258
return CRYPTOCB_UNAVAILABLE;
51805259
}
51815260

@@ -5362,12 +5441,11 @@ int wc_Stm32_Ccb_EccSign(int curveId, const byte* iv, const byte* tag,
53625441
}
53635442

53645443
#if defined(WOLF_CRYPTO_CB) && defined(HAVE_ECC) && defined(HAVE_ECC_SIGN)
5365-
/* CubeMX CCB crypto-callback device. Transparent DHUK AES/GMAC is bare-only, so
5366-
* under the HAL build the CCB-protected ECDSA sign is the only transparent DHUK
5367-
* operation. This minimal device routes WC_PK_TYPE_ECDSA_SIGN for a CCB key
5368-
* (key->dhuk_is_ccb) to the HAL CCB sign and returns the DER-encoded (r,s); it
5369-
* mirrors the bare-metal device's CCB branch so the same wc_ecc_sign_hash flow
5370-
* works on both build paths. */
5444+
/* CubeMX/HAL crypto-callback device. Routes AES (Stm32Cube_Cipher), ECDSA sign
5445+
* (CCB key -> HAL_CCB; normal key -> HW PKA), ECDSA verify -> HW PKA, and CCB
5446+
* keygen -- giving full HW ECC + AES through the callback on the HAL build, so
5447+
* WOLF_CRYPTO_CB_ONLY_ECC / _AES work here as they do on the bare device.
5448+
* (Transparent DHUK-derived AES/GMAC remains bare-only.) */
53715449
static int Stm32Ccb_CryptoDevCb(int devId, struct wc_CryptoInfo* info,
53725450
void* ctx)
53735451
{
@@ -5398,13 +5476,30 @@ static int Stm32Ccb_CryptoDevCb(int devId, struct wc_CryptoInfo* info,
53985476
return wc_ecc_dev_make_key(info->pk.eckg.rng, info->pk.eckg.size,
53995477
info->pk.eckg.key, info->pk.eckg.curveId);
54005478
}
5479+
#if defined(WOLFSSL_STM32_PKA) && defined(HAVE_ECC_VERIFY) && \
5480+
!defined(WC_STM32_PKA_SIGN_ONLY)
5481+
/* ECDSA verify -> HW PKA (public key). */
5482+
if (info->pk.type == WC_PK_TYPE_ECDSA_VERIFY) {
5483+
return Stm32Cube_EccVerify(info);
5484+
}
5485+
#endif
54015486
if (info->pk.type != WC_PK_TYPE_ECDSA_SIGN) {
54025487
return CRYPTOCB_UNAVAILABLE;
54035488
}
54045489
key = info->pk.eccsign.key;
5405-
if (key == NULL || key->dhuk_is_ccb == 0u) {
5490+
if (key == NULL) {
54065491
return CRYPTOCB_UNAVAILABLE;
54075492
}
5493+
if (key->dhuk_is_ccb == 0u) {
5494+
/* Normal (non-CCB) key: HW PKA sign. */
5495+
#if defined(WOLFSSL_STM32_PKA) && defined(HAVE_ECC_SIGN) && \
5496+
!defined(WC_STM32_PKA_VERIFY_ONLY)
5497+
return Stm32Cube_EccSign(info);
5498+
#else
5499+
return CRYPTOCB_UNAVAILABLE;
5500+
#endif
5501+
}
5502+
/* CCB-protected key: scalar unwrapped SAES->PKA in HW, returns raw (r,s). */
54085503
sz = (word32)wc_ecc_size(key);
54095504
ret = wc_Stm32_Ccb_EccSign(ECC_SECP256R1, key->ccb_iv, key->ccb_tag,
54105505
key->dhuk_wrapped_priv,

0 commit comments

Comments
 (0)