Skip to content

Commit e566531

Browse files
authored
Merge pull request #10862 from rizlik/se050_dynamic_hwsw
se050: implement dynamic hw/sw offload
2 parents f18ebef + cf98494 commit e566531

8 files changed

Lines changed: 736 additions & 32 deletions

File tree

.github/workflows/se050-sim.yml

Lines changed: 24 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -35,10 +35,22 @@ env:
3535

3636
jobs:
3737
se050_sim:
38-
name: wolfCrypt against SE050 simulator
38+
name: wolfCrypt against SE050 simulator (${{ matrix.name }})
3939
if: ${{ (github.repository_owner == 'wolfssl') && (github.event_name != 'pull_request' || github.event.pull_request.draft == false) }}
4040
runs-on: ubuntu-24.04
4141
timeout-minutes: 30
42+
strategy:
43+
fail-fast: false
44+
matrix:
45+
include:
46+
# Default build: every keyed operation is offloaded to the SE050.
47+
- name: default
48+
extra_cflags: ''
49+
# Per-key runtime HW/SW routing. The wolfCrypt test binary runs the
50+
# ecc/ed25519/curve25519/rsa SE050_ONLY_KEY_ID coverage (software key
51+
# vs SE050-resident key) added to wolfcrypt/test/test.c.
52+
- name: only-key-id
53+
extra_cflags: '-DWOLFSSL_SE050_ONLY_KEY_ID'
4254
steps:
4355
- name: Checkout wolfSSL (PR source)
4456
uses: actions/checkout@v5
@@ -75,9 +87,17 @@ jobs:
7587
file: simulators/SE050Sim/Dockerfile.wolfcrypt
7688
push: false
7789
load: true
78-
tags: wolfssl-se050-sim:ci
90+
tags: wolfssl-se050-sim:ci-${{ matrix.name }}
91+
# WOLFSSL_EXTRA_CFLAGS is appended to the wolfSSL ./configure CFLAGS by
92+
# the simulator's Dockerfile.wolfcrypt (ARG WOLFSSL_EXTRA_CFLAGS). When
93+
# bumping SIMULATORS_REF, keep that ARG in place so the only-key-id
94+
# matrix leg actually defines the macro.
95+
build-args: |
96+
WOLFSSL_EXTRA_CFLAGS=${{ matrix.extra_cflags }}
97+
# Only the default leg refreshes the shared cache to avoid two matrix
98+
# legs writing the same registry ref.
7999
cache-from: type=registry,ref=ghcr.io/wolfssl/wolfssl-sim-cache:se050
80-
cache-to: ${{ (github.event_name == 'schedule' || github.event_name == 'workflow_dispatch') && 'type=registry,ref=ghcr.io/wolfssl/wolfssl-sim-cache:se050,mode=max' || '' }}
100+
cache-to: ${{ ((github.event_name == 'schedule' || github.event_name == 'workflow_dispatch') && matrix.name == 'default') && 'type=registry,ref=ghcr.io/wolfssl/wolfssl-sim-cache:se050,mode=max' || '' }}
81101

82102
- name: Run wolfCrypt tests against simulator
83-
run: docker run --rm wolfssl-se050-sim:ci
103+
run: docker run --rm wolfssl-se050-sim:ci-${{ matrix.name }}

wolfcrypt/src/curve25519.c

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -585,15 +585,17 @@ int wc_curve25519_make_key(WC_RNG* rng, int keysize, curve25519_key* key)
585585
#endif /* WOLFSSL_ASYNC_CRYPT && WC_ASYNC_ENABLE_X25519 &&
586586
* WOLFSSL_ASYNC_CRYPT_SW */
587587

588-
#ifdef WOLFSSL_SE050
588+
#if defined(WOLFSSL_SE050) && !defined(WOLFSSL_SE050_ONLY_KEY_ID)
589589
ret = se050_curve25519_create_key(key, keysize);
590590
#elif defined(WC_X25519_NONBLOCK)
591591
if (key->nb_ctx != NULL) {
592592
ret = wc_curve25519_make_key_nb(rng, keysize, key);
593593
}
594594
else
595595
#endif
596-
#if !defined(WOLFSSL_SE050)
596+
/* Under WOLFSSL_SE050_ONLY_KEY_ID, generate a software key (keyIdSet == 0);
597+
* its shared-secret computation routes through software (privSet == 1). */
598+
#if !defined(WOLFSSL_SE050) || defined(WOLFSSL_SE050_ONLY_KEY_ID)
597599
{
598600
ret = wc_curve25519_make_priv(rng, keysize, key->k);
599601
if (ret == 0) {

wolfcrypt/src/ecc.c

Lines changed: 52 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -296,7 +296,14 @@ ECC Curve Sizes:
296296
#undef HAVE_ECC_VERIFY_HELPER
297297
#define HAVE_ECC_VERIFY_HELPER
298298
#endif
299-
#if defined(WOLFSSL_SE050_NO_ECDSA_VERIFY) && defined(HAVE_ECC_VERIFY)
299+
/* Compile in the software verify helper whenever SE050 hardware ECDSA verify is
300+
* bypassed:
301+
* - WOLFSSL_SE050_NO_ECDSA_VERIFY disables SE050 ECDSA verify outright.
302+
* - WOLFSSL_SE050_ONLY_KEY_ID verifies software keys (keyIdSet == 0) in
303+
* wolfCrypt; the SE050 is used at runtime only for keys resident in HW. */
304+
#if (defined(WOLFSSL_SE050_NO_ECDSA_VERIFY) || \
305+
(defined(WOLFSSL_SE050) && defined(WOLFSSL_SE050_ONLY_KEY_ID))) && \
306+
defined(HAVE_ECC_VERIFY)
300307
#define HAVE_ECC_VERIFY_HELPER
301308
#endif
302309

@@ -4728,13 +4735,15 @@ int wc_ecc_shared_secret(ecc_key* private_key, ecc_key* public_key, byte* out,
47284735
word32* outlen)
47294736
{
47304737
int err = 0;
4738+
int privateKeyOk = 0;
47314739

47324740
#if defined(WOLFSSL_CRYPTOCELL) && !defined(WOLFSSL_ATECC508A) && \
47334741
!defined(WOLFSSL_ATECC608A) && !defined(WOLFSSL_MICROCHIP_TA100)
47344742
CRYS_ECDH_TempData_t tempBuff;
47354743
#endif
47364744

47374745
(void)err;
4746+
(void)privateKeyOk;
47384747

47394748
if (private_key == NULL || public_key == NULL || out == NULL ||
47404749
outlen == NULL) {
@@ -4757,8 +4766,16 @@ int wc_ecc_shared_secret(ecc_key* private_key, ecc_key* public_key, byte* out,
47574766
return NO_VALID_DEVID;
47584767
#else /* !WOLF_CRYPTO_CB_ONLY_ECC */
47594768
/* type valid? */
4760-
if (private_key->type != ECC_PRIVATEKEY &&
4761-
private_key->type != ECC_PRIVATEKEY_ONLY) {
4769+
privateKeyOk = private_key->type == ECC_PRIVATEKEY ||
4770+
private_key->type == ECC_PRIVATEKEY_ONLY;
4771+
#if defined(WOLFSSL_SE050) && !defined(WOLFSSL_SE050_NO_ECDHE) && \
4772+
defined(WOLFSSL_SE050_ONLY_KEY_ID)
4773+
/* A SE050 key-id handle can represent a private key even though
4774+
* wc_ecc_use_key_id() only loads the public point into the ecc_key. */
4775+
if (private_key->keyIdSet)
4776+
privateKeyOk = 1;
4777+
#endif
4778+
if (!privateKeyOk) {
47624779
return ECC_BAD_ARG_E;
47634780
}
47644781

@@ -4801,6 +4818,15 @@ int wc_ecc_shared_secret(ecc_key* private_key, ecc_key* public_key, byte* out,
48014818
err = silabs_ecc_shared_secret(private_key, public_key, out, outlen);
48024819
#elif defined(WOLFSSL_KCAPI_ECC)
48034820
err = KcapiEcc_SharedSecret(private_key, public_key, out, outlen);
4821+
#elif defined(WOLFSSL_SE050) && !defined(WOLFSSL_SE050_NO_ECDHE) && \
4822+
defined(WOLFSSL_SE050_ONLY_KEY_ID)
4823+
/* SE050-resident private key uses hardware ECDH; a software private key
4824+
* (keyIdSet == 0) uses the wolfCrypt software implementation. */
4825+
if (private_key->keyIdSet)
4826+
err = se050_ecc_shared_secret(private_key, public_key, out, outlen);
4827+
else
4828+
err = wc_ecc_shared_secret_ex(private_key, &public_key->pubkey, out,
4829+
outlen);
48044830
#elif defined(WOLFSSL_SE050) && !defined(WOLFSSL_SE050_NO_ECDHE)
48054831
err = se050_ecc_shared_secret(private_key, public_key, out, outlen);
48064832
#else
@@ -5881,7 +5907,8 @@ static int _ecc_make_key_ex(WC_RNG* rng, int keysize, ecc_key* key,
58815907
else {
58825908
err = NOT_COMPILED_IN;
58835909
}
5884-
#elif defined(WOLFSSL_SE050) && !defined(WOLFSSL_SE050_NO_ECDHE)
5910+
#elif defined(WOLFSSL_SE050) && !defined(WOLFSSL_SE050_NO_ECDHE) && \
5911+
!defined(WOLFSSL_SE050_ONLY_KEY_ID)
58855912
err = se050_ecc_create_key(key, key->dp->id, key->dp->size);
58865913
key->type = ECC_PRIVATEKEY;
58875914
#elif defined(WOLFSSL_CRYPTOCELL)
@@ -6981,7 +7008,14 @@ int wc_ecc_sign_hash(const byte* in, word32 inlen, byte* out, word32 *outlen,
69817008
}
69827009

69837010
/* hardware crypto */
6984-
#if defined(WOLFSSL_ATECC508A) || defined(WOLFSSL_ATECC608A) || \
7011+
#if defined(WOLFSSL_SE050) && defined(WOLFSSL_SE050_ONLY_KEY_ID)
7012+
/* Route by key location: SE050-resident keys sign in hardware, software
7013+
* keys (keyIdSet == 0) sign with the wolfCrypt software implementation. */
7014+
if (key->keyIdSet)
7015+
err = wc_ecc_sign_hash_hw(in, inlen, r, s, out, outlen, rng, key);
7016+
else
7017+
err = wc_ecc_sign_hash_ex(in, inlen, rng, key, r, s);
7018+
#elif defined(WOLFSSL_ATECC508A) || defined(WOLFSSL_ATECC608A) || \
69857019
defined(WOLFSSL_MICROCHIP_TA100) || \
69867020
defined(PLUTON_CRYPTO_ECC) || defined(WOLFSSL_CRYPTOCELL) || \
69877021
defined(WOLFSSL_SILABS_SE_ACCEL) || defined(WOLFSSL_KCAPI_ECC) || \
@@ -9753,8 +9787,11 @@ int wc_ecc_verify_hash_ex(mp_int *r, mp_int *s, const byte* hash,
97539787
#elif defined(WOLFSSL_XILINX_CRYPT_VERSAL)
97549788
byte sigRS[ECC_MAX_CRYPTO_HW_SIZE * 2];
97559789
byte hashcopy[ECC_MAX_CRYPTO_HW_SIZE] = {0};
9756-
#elif defined(WOLFSSL_SE050) && !defined(WOLFSSL_SE050_NO_ECDSA_VERIFY)
9790+
#elif defined(WOLFSSL_SE050) && !defined(WOLFSSL_SE050_NO_ECDSA_VERIFY) && \
9791+
!defined(WOLFSSL_SE050_ONLY_KEY_ID)
97579792
#else
9793+
/* Software verify helper (also used for SE050 software keys under
9794+
* WOLFSSL_SE050_ONLY_KEY_ID) needs the curve specs. */
97589795
int curveLoaded = 0;
97599796
DECLARE_CURVE_SPECS(ECC_CURVE_FIELD_COUNT);
97609797
#endif
@@ -9789,6 +9826,15 @@ int wc_ecc_verify_hash_ex(mp_int *r, mp_int *s, const byte* hash,
97899826
return err;
97909827
}
97919828

9829+
#if defined(WOLFSSL_SE050) && defined(WOLFSSL_SE050_ONLY_KEY_ID) && \
9830+
!defined(WOLFSSL_SE050_NO_ECDSA_VERIFY)
9831+
/* Key resident in the SE050: verify in hardware. Software keys fall through
9832+
* to the wolfCrypt verify helper below. */
9833+
if (key->keyIdSet) {
9834+
return se050_ecc_verify_hash_ex(hash, hashlen, r, s, key, res);
9835+
}
9836+
#endif
9837+
97929838
keySz = (word32)key->dp->size;
97939839

97949840
#if defined(WOLFSSL_ASYNC_CRYPT) && defined(WC_ASYNC_ENABLE_ECC) && \

wolfcrypt/src/ed25519.c

Lines changed: 40 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -471,7 +471,7 @@ int wc_ed25519_sign_msg_ex(const byte* in, word32 inLen, byte* out,
471471
const byte* context, byte contextLen)
472472
{
473473
int ret;
474-
#ifdef WOLFSSL_SE050
474+
#if defined(WOLFSSL_SE050) && !defined(WOLFSSL_SE050_ONLY_KEY_ID)
475475
(void)context;
476476
(void)contextLen;
477477
(void)type;
@@ -521,6 +521,20 @@ int wc_ed25519_sign_msg_ex(const byte* in, word32 inLen, byte* out,
521521
return BAD_FUNC_ARG;
522522
}
523523

524+
#if defined(WOLFSSL_SE050) && defined(WOLFSSL_SE050_ONLY_KEY_ID)
525+
/* Key resident in the SE050: sign in hardware. Software keys fall through
526+
* to the wolfCrypt software implementation below. */
527+
if (key->keyIdSet) {
528+
/* The SE050 performs only PureEdDSA; it cannot apply the Ed25519ctx or
529+
* Ed25519ph variants, so reject them rather than silently signing with
530+
* the wrong scheme. */
531+
if (type == Ed25519ctx || type == Ed25519ph || contextLen != 0) {
532+
return BAD_FUNC_ARG;
533+
}
534+
return se050_ed25519_sign_msg(in, inLen, out, outLen, key);
535+
}
536+
#endif
537+
524538
if ((type == Ed25519ph) &&
525539
(inLen != WC_SHA512_DIGEST_SIZE))
526540
{
@@ -768,7 +782,10 @@ int wc_ed25519ph_sign_msg(const byte* in, word32 inLen, byte* out,
768782
#endif /* HAVE_ED25519_SIGN */
769783

770784
#ifdef HAVE_ED25519_VERIFY
771-
#if !defined(WOLFSSL_SE050) && !defined(WOLF_CRYPTO_CB_ONLY_ED25519)
785+
/* The software verify helpers are also needed under WOLFSSL_SE050_ONLY_KEY_ID
786+
* so that software keys (keyIdSet == 0) can be verified in wolfCrypt. */
787+
#if (!defined(WOLFSSL_SE050) || defined(WOLFSSL_SE050_ONLY_KEY_ID)) && \
788+
!defined(WOLF_CRYPTO_CB_ONLY_ED25519)
772789

773790
#ifdef WOLFSSL_CHECK_VER_FAULTS
774791
static const byte sha512_empty[] = {
@@ -1000,9 +1017,11 @@ static int ed25519_verify_msg_final_with_sha(const byte* sig, word32 sigLen,
10001017

10011018
return ret;
10021019
}
1003-
#endif /* !WOLFSSL_SE050 && !WOLF_CRYPTO_CB_ONLY_ED25519 */
1020+
#endif /* (!WOLFSSL_SE050 || WOLFSSL_SE050_ONLY_KEY_ID) &&
1021+
* !WOLF_CRYPTO_CB_ONLY_ED25519 */
10041022

1005-
#if defined(WOLFSSL_ED25519_STREAMING_VERIFY) && !defined(WOLFSSL_SE050)
1023+
#if defined(WOLFSSL_ED25519_STREAMING_VERIFY) && \
1024+
(!defined(WOLFSSL_SE050) || defined(WOLFSSL_SE050_ONLY_KEY_ID))
10061025

10071026
int wc_ed25519_verify_msg_init(const byte* sig, word32 sigLen, ed25519_key* key,
10081027
byte type, const byte* context, byte contextLen) {
@@ -1028,7 +1047,8 @@ int wc_ed25519_verify_msg_final(const byte* sig, word32 sigLen, int* res,
10281047
key, &key->sha);
10291048
}
10301049

1031-
#endif /* WOLFSSL_ED25519_STREAMING_VERIFY && !WOLFSSL_SE050 */
1050+
#endif /* WOLFSSL_ED25519_STREAMING_VERIFY &&
1051+
* (!WOLFSSL_SE050 || WOLFSSL_SE050_ONLY_KEY_ID) */
10321052

10331053
/*
10341054
sig is array of bytes containing the signature
@@ -1044,7 +1064,7 @@ int wc_ed25519_verify_msg_ex(const byte* sig, word32 sigLen, const byte* msg,
10441064
byte type, const byte* context, byte contextLen)
10451065
{
10461066
int ret;
1047-
#ifdef WOLFSSL_SE050
1067+
#if defined(WOLFSSL_SE050) && !defined(WOLFSSL_SE050_ONLY_KEY_ID)
10481068
(void)type;
10491069
(void)context;
10501070
(void)contextLen;
@@ -1081,6 +1101,20 @@ int wc_ed25519_verify_msg_ex(const byte* sig, word32 sigLen, const byte* msg,
10811101
WC_DECLARE_VAR(sha, wc_Sha512, 1, key ? key->heap : NULL);
10821102
#endif
10831103

1104+
#if defined(WOLFSSL_SE050) && defined(WOLFSSL_SE050_ONLY_KEY_ID)
1105+
/* Key resident in the SE050: verify in hardware. Software keys fall through
1106+
* to the wolfCrypt software implementation below. */
1107+
if (key != NULL && key->keyIdSet) {
1108+
/* The SE050 performs only PureEdDSA; it cannot apply the Ed25519ctx or
1109+
* Ed25519ph variants, so reject them rather than silently verifying
1110+
* against the wrong scheme. */
1111+
if (type == Ed25519ctx || type == Ed25519ph || contextLen != 0) {
1112+
return BAD_FUNC_ARG;
1113+
}
1114+
return se050_ed25519_verify_msg(sig, sigLen, msg, msgLen, key, res);
1115+
}
1116+
#endif
1117+
10841118
/* sanity check on arguments */
10851119
if (sig == NULL || msg == NULL || res == NULL || key == NULL ||
10861120
(context == NULL && contextLen != 0))

wolfcrypt/src/port/nxp/README_SE050.md

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -265,6 +265,35 @@ offloaded to the SE050, but RSA PKCS#1 v1.5 verification (`wc_RsaSSL_Verify()`)
265265
uses wolfCrypt software (public-key exponentiation + unpad). RSA PSS verify and
266266
RSA key-exchange decrypt are unaffected.
267267

268+
**`WOLFSSL_SE050_ONLY_KEY_ID`**
269+
270+
Requires `WOLFSSL_SE050`. By default every keyed operation is routed to the
271+
SE050 at compile time. When this macro is defined, routing becomes a per-key
272+
*runtime* decision based on `key->keyIdSet`:
273+
274+
- A key resident in the SE050 (`keyIdSet == 1`, established via
275+
`wc_ecc_use_key_id()`, `wc_se050_ecc_insert_private_key()`, `wc_RsaUseKeyId()`,
276+
`wc_se050_rsa_insert_private_key()`, etc.) runs the operation on the SE050.
277+
- A software key (`keyIdSet == 0`) runs the operation in wolfCrypt software.
278+
279+
Because both paths must be available, the build compiles *both* the SE050 and
280+
the wolfCrypt software implementations (larger code size). Key generation
281+
(`wc_ecc_make_key()`, `wc_curve25519_make_key()`, `wc_MakeRsaKey()`; Ed25519
282+
key generation is already software-only) produces a *software* key
283+
(`keyIdSet == 0`); it does not implicitly create a key inside the SE050.
284+
285+
In-scope operations: ECC sign/verify/ECDH/keygen, Ed25519 sign/verify,
286+
Curve25519 shared-secret/keygen, and RSA sign/verify/encrypt/decrypt/keygen.
287+
RNG (TRNG) and hashing have no key and are unaffected. AES routing continues to
288+
be governed by `WOLFSSL_SE050_CRYPT` and the AES `useSWCrypt` flag (the SE050
289+
AES path is opt-in and already chosen per-key at runtime).
290+
291+
This macro composes with the `WOLFSSL_SE050_NO_*` macros above: if a `NO_*`
292+
macro disables an operation, that operation always uses wolfCrypt software
293+
regardless of `keyIdSet`. The SE050 port's "import a software key into the
294+
SE050 on first use" behavior is disabled under this macro, so a software key is
295+
never silently moved into hardware.
296+
268297
## wolfSSL HostCrypto Support
269298

270299
The NXP SE05x Plug & Trust Middleware by default can use either OpenSSL or

0 commit comments

Comments
 (0)