Skip to content

Commit 240703c

Browse files
authored
Merge pull request #10219 from rizlik/se050
SE050: Fixes + NO_{RSA,ECDHE}_VERIFY options + simulator CI
2 parents 22b6b1a + 8b01033 commit 240703c

8 files changed

Lines changed: 270 additions & 37 deletions

File tree

.github/workflows/se050-sim.yml

Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
name: SE050 simulator test
2+
3+
# START OF COMMON SECTION
4+
on:
5+
push:
6+
branches: [ 'master', 'main', 'release/**' ]
7+
pull_request:
8+
branches: [ '*' ]
9+
10+
concurrency:
11+
group: ${{ github.workflow }}-${{ github.ref }}
12+
cancel-in-progress: true
13+
# END OF COMMON SECTION
14+
15+
# Build the SE050 software simulator (https://github.com/LinuxJedi/SE050Sim),
16+
# build wolfSSL against its NXP Plug&Trust SDK + simulator bridge, and run the
17+
# wolfCrypt SE050 test binary against the simulator TCP server.
18+
#
19+
# The simulator's own Dockerfile (Dockerfile.wolfcrypt) clones wolfSSL master.
20+
# We patch it to COPY the PR checkout instead so CI reflects the PR's source.
21+
22+
env:
23+
SE050SIM_REF: 8fda9212c306fbee0dcd66f2dd52b13f65f13e00
24+
25+
jobs:
26+
se050_sim:
27+
name: wolfCrypt against SE050 simulator
28+
if: github.repository_owner == 'wolfssl'
29+
runs-on: ubuntu-24.04
30+
timeout-minutes: 30
31+
steps:
32+
- name: Checkout wolfSSL (PR source)
33+
uses: actions/checkout@v4
34+
with:
35+
path: wolfssl-src
36+
37+
- name: Clone SE050 simulator
38+
run: |
39+
git clone https://github.com/LinuxJedi/SE050Sim se050sim
40+
cd se050sim && git checkout "$SE050SIM_REF"
41+
42+
- name: Stage PR wolfSSL into simulator build context
43+
run: mv wolfssl-src se050sim/wolfssl
44+
45+
- name: Patch Dockerfile to use PR wolfSSL instead of upstream master
46+
working-directory: se050sim
47+
run: |
48+
sed -i 's|^RUN git clone --depth 1 https://github.com/wolfSSL/wolfssl.git /app/wolfssl$|COPY wolfssl /app/wolfssl|' Dockerfile.wolfcrypt
49+
# Fail fast if the pattern drifted upstream -- better a clear error
50+
# than a CI run that silently tests master.
51+
grep -q '^COPY wolfssl /app/wolfssl$' Dockerfile.wolfcrypt
52+
! grep -q 'git clone .*wolfssl\.git' Dockerfile.wolfcrypt
53+
54+
- uses: docker/setup-buildx-action@v3
55+
56+
- name: Build wolfCrypt-SE050 test image
57+
uses: docker/build-push-action@v5
58+
with:
59+
context: se050sim
60+
file: se050sim/Dockerfile.wolfcrypt
61+
push: false
62+
load: true
63+
tags: wolfssl-se050-sim:ci
64+
cache-from: type=gha
65+
cache-to: type=gha,mode=max
66+
67+
- name: Run wolfCrypt tests against simulator
68+
run: docker run --rm wolfssl-se050-sim:ci

.wolfssl_known_macro_extras

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -880,7 +880,10 @@ WOLFSSL_SE050_AUTO_ERASE
880880
WOLFSSL_SE050_CRYPT
881881
WOLFSSL_SE050_HASH
882882
WOLFSSL_SE050_INIT
883+
WOLFSSL_SE050_NO_ECDHE
884+
WOLFSSL_SE050_NO_ECDSA_VERIFY
883885
WOLFSSL_SE050_NO_RSA
886+
WOLFSSL_SE050_NO_RSA_VERIFY
884887
WOLFSSL_SE050_NO_TRNG
885888
WOLFSSL_SECURE_RENEGOTIATION_ON_BY_DEFAULT
886889
WOLFSSL_SERVER_EXAMPLE

wolfcrypt/src/ecc.c

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -291,6 +291,9 @@ ECC Curve Sizes:
291291
#undef HAVE_ECC_VERIFY_HELPER
292292
#define HAVE_ECC_VERIFY_HELPER
293293
#endif
294+
#if defined(WOLFSSL_SE050_NO_ECDSA_VERIFY) && defined(HAVE_ECC_VERIFY)
295+
#define HAVE_ECC_VERIFY_HELPER
296+
#endif
294297

295298
#if !defined(WOLFSSL_ATECC508A) && !defined(WOLFSSL_ATECC608A) && \
296299
!defined(WOLFSSL_CRYPTOCELL) && !defined(WOLFSSL_SILABS_SE_ACCEL) && \
@@ -4767,7 +4770,7 @@ int wc_ecc_shared_secret(ecc_key* private_key, ecc_key* public_key, byte* out,
47674770
err = silabs_ecc_shared_secret(private_key, public_key, out, outlen);
47684771
#elif defined(WOLFSSL_KCAPI_ECC)
47694772
err = KcapiEcc_SharedSecret(private_key, public_key, out, outlen);
4770-
#elif defined(WOLFSSL_SE050)
4773+
#elif defined(WOLFSSL_SE050) && !defined(WOLFSSL_SE050_NO_ECDHE)
47714774
err = se050_ecc_shared_secret(private_key, public_key, out, outlen);
47724775
#else
47734776
err = wc_ecc_shared_secret_ex(private_key, &public_key->pubkey, out, outlen);
@@ -5761,7 +5764,7 @@ static int _ecc_make_key_ex(WC_RNG* rng, int keysize, ecc_key* key,
57615764
else {
57625765
err = NOT_COMPILED_IN;
57635766
}
5764-
#elif defined(WOLFSSL_SE050)
5767+
#elif defined(WOLFSSL_SE050) && !defined(WOLFSSL_SE050_NO_ECDHE)
57655768
err = se050_ecc_create_key(key, key->dp->id, key->dp->size);
57665769
key->type = ECC_PRIVATEKEY;
57675770
#elif defined(WOLFSSL_CRYPTOCELL)
@@ -9261,7 +9264,7 @@ int wc_ecc_verify_hash_ex(mp_int *r, mp_int *s, const byte* hash,
92619264
#elif defined(WOLFSSL_XILINX_CRYPT_VERSAL)
92629265
byte sigRS[ECC_MAX_CRYPTO_HW_SIZE * 2];
92639266
byte hashcopy[ECC_MAX_CRYPTO_HW_SIZE] = {0};
9264-
#elif defined(WOLFSSL_SE050)
9267+
#elif defined(WOLFSSL_SE050) && !defined(WOLFSSL_SE050_NO_ECDSA_VERIFY)
92659268
#else
92669269
int curveLoaded = 0;
92679270
DECLARE_CURVE_SPECS(ECC_CURVE_FIELD_COUNT);

wolfcrypt/src/ed25519.c

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1169,6 +1169,18 @@ int wc_ed25519_import_public_ex(const byte* in, word32 inLen, ed25519_key* key,
11691169
if (inLen < ED25519_PUB_KEY_SIZE)
11701170
return BAD_FUNC_ARG;
11711171

1172+
#ifdef WOLFSSL_SE050
1173+
/* Importing new key material invalidates any prior SE050 object binding;
1174+
* erase the old object (no-op when keyIdSet == 0) so the host and the
1175+
* secure element agree on what's bound. Clear the binding fields
1176+
* explicitly afterwards so a stale keyId never survives, even when
1177+
* se050_ed25519_free_key() returns early because the SE050 session isn't
1178+
* configured yet. */
1179+
se050_ed25519_free_key(key);
1180+
key->keyId = 0;
1181+
key->keyIdSet = 0;
1182+
#endif
1183+
11721184
/* compressed prefix according to draft
11731185
http://www.ietf.org/id/draft-koch-eddsa-for-openpgp-02.txt */
11741186
if (in[0] == 0x40 && inLen == ED25519_PUB_KEY_SIZE + 1) {
@@ -1255,6 +1267,18 @@ int wc_ed25519_import_private_only(const byte* priv, word32 privSz,
12551267
if (privSz != ED25519_KEY_SIZE)
12561268
return BAD_FUNC_ARG;
12571269

1270+
#ifdef WOLFSSL_SE050
1271+
/* Importing new key material invalidates any prior SE050 object binding;
1272+
* erase the old object (no-op when keyIdSet == 0) so the host and the
1273+
* secure element agree on what's bound. Clear the binding fields
1274+
* explicitly afterwards so a stale keyId never survives, even when
1275+
* se050_ed25519_free_key() returns early because the SE050 session isn't
1276+
* configured yet. */
1277+
se050_ed25519_free_key(key);
1278+
key->keyId = 0;
1279+
key->keyIdSet = 0;
1280+
#endif
1281+
12581282
XMEMCPY(key->k, priv, ED25519_KEY_SIZE);
12591283
key->privKeySet = 1;
12601284

@@ -1311,6 +1335,21 @@ int wc_ed25519_import_private_key_ex(const byte* priv, word32 privSz,
13111335
return BAD_FUNC_ARG;
13121336
}
13131337

1338+
#ifdef WOLFSSL_SE050
1339+
/* Importing new key material invalidates any prior SE050 object binding;
1340+
* erase the old object (no-op when keyIdSet == 0) so the host and the
1341+
* secure element agree on what's bound. key->k is overwritten before the
1342+
* wc_ed25519_import_public_ex() call below, so the binding must be
1343+
* dropped here first in case that function fails its own early-return
1344+
* argument checks before reaching its reset. Clear the binding fields
1345+
* explicitly afterwards so a stale keyId never survives, even when
1346+
* se050_ed25519_free_key() returns early because the SE050 session isn't
1347+
* configured yet. */
1348+
se050_ed25519_free_key(key);
1349+
key->keyId = 0;
1350+
key->keyIdSet = 0;
1351+
#endif
1352+
13141353
XMEMCPY(key->k, priv, ED25519_KEY_SIZE);
13151354
key->privKeySet = 1;
13161355

wolfcrypt/src/port/nxp/README_SE050.md

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -246,6 +246,25 @@ defined, wolfCrypt will instead fall back to using `/dev/random` and
246246
Disables using the SE050 for RSA, useful for the SE050E which does not have
247247
RSA support.
248248

249+
**`WOLFSSL_SE050_NO_ECDHE`**
250+
251+
Disables offloading ECDH key generation and shared secret operations to the
252+
SE050. When defined, `wc_ecc_make_key()` and `wc_ecc_shared_secret()` will
253+
use wolfCrypt software instead of the SE050.
254+
255+
**`WOLFSSL_SE050_NO_ECDSA_VERIFY`**
256+
257+
When defined, ECDSA signing (`wc_ecc_sign_hash()`) continues to be offloaded
258+
to the SE050, but ECDSA verification (`wc_ecc_verify_hash()`) uses wolfCrypt
259+
software.
260+
261+
**`WOLFSSL_SE050_NO_RSA_VERIFY`**
262+
263+
When defined, RSA PKCS#1 v1.5 signing (`wc_RsaSSL_Sign()`) continues to be
264+
offloaded to the SE050, but RSA PKCS#1 v1.5 verification (`wc_RsaSSL_Verify()`)
265+
uses wolfCrypt software (public-key exponentiation + unpad). RSA PSS verify and
266+
RSA key-exchange decrypt are unaffected.
267+
249268
## wolfSSL HostCrypto Support
250269

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

wolfcrypt/src/port/nxp/se050_port.c

Lines changed: 56 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -810,7 +810,7 @@ int se050_rsa_get_key_id(struct RsaKey* key, word32* keyId)
810810
int se050_rsa_create_key(struct RsaKey* key, int size, long e)
811811
{
812812
int ret = 0;
813-
word32 keyId;
813+
word32 keyId = 0;
814814
int keyCreated = 0;
815815
sss_status_t status = kStatus_SSS_Success;
816816
sss_object_t keyPair;
@@ -1483,7 +1483,7 @@ int se050_rsa_verify(const byte* in, word32 inLen, byte* out, word32 outLen,
14831483
keyId = se050_allocate_key(SE050_RSA_KEY);
14841484
status = sss_key_object_allocate_handle(&newKey, keyId,
14851485
kSSS_KeyPart_Public, kSSS_CipherType_RSA, keySz,
1486-
kKeyObject_Mode_Persistent);
1486+
kKeyObject_Mode_Transient);
14871487
}
14881488
if (status == kStatus_SSS_Success) {
14891489
/* Try to delete existing key first, ignore return since will
@@ -1538,8 +1538,22 @@ int se050_rsa_verify(const byte* in, word32 inLen, byte* out, word32 outLen,
15381538
}
15391539

15401540
if (status == kStatus_SSS_Success) {
1541-
key->keyId = keyId;
1542-
key->keyIdSet = 1;
1541+
if (keyCreated) {
1542+
/* We uploaded only the public part of the key for this verify.
1543+
* Don't persist keyIdSet=1 -- a later sign on the same RsaKey
1544+
* would reuse this binding and fail because the SE050 object has
1545+
* no private material. Erase the transient object so the next
1546+
* SE050 op (sign or verify) re-uploads from whatever the host
1547+
* RsaKey currently holds. */
1548+
sss_key_store_erase_key(&host_keystore, &newKey);
1549+
sss_key_object_free(&newKey);
1550+
}
1551+
else {
1552+
/* Pre-existing keyIdSet=1 binding (e.g. wc_RsaUseKeyId or prior
1553+
* sign that uploaded a keypair). Preserve it. */
1554+
key->keyId = keyId;
1555+
key->keyIdSet = 1;
1556+
}
15431557
}
15441558
else {
15451559
if (keyCreated) {
@@ -1696,8 +1710,17 @@ int se050_rsa_public_encrypt(const byte* in, word32 inLen, byte* out,
16961710
}
16971711

16981712
if (status == kStatus_SSS_Success) {
1699-
key->keyId = keyId;
1700-
key->keyIdSet = 1;
1713+
if (keyCreated) {
1714+
/* Public-key encrypt imported a temporary public object only.
1715+
* Do not bind that SE050 object to the caller's RsaKey or later
1716+
* private-key operations will try to reuse a public handle. */
1717+
sss_key_store_erase_key(&host_keystore, &newKey);
1718+
sss_key_object_free(&newKey);
1719+
}
1720+
else {
1721+
key->keyId = keyId;
1722+
key->keyIdSet = 1;
1723+
}
17011724
ret = encSz;
17021725
}
17031726
else {
@@ -2123,11 +2146,8 @@ int se050_ecc_sign_hash_ex(const byte* in, word32 inLen, MATH_INT_T* r, MATH_INT
21232146

21242147
algorithm = se050_map_hash_alg(inLen);
21252148
if (algorithm == kAlgorithm_None) {
2126-
inLen = keySize; /* try key size */
2127-
algorithm = se050_map_hash_alg(inLen);
2128-
}
2129-
if (algorithm == kAlgorithm_None) {
2130-
return ECC_CURVE_OID_E;
2149+
WOLFSSL_MSG("SE050 ECDSA sign only supports SHA-1/224/256/384/512 digest sizes");
2150+
return BAD_LENGTH_E;
21312151
}
21322152

21332153
if (wolfSSL_CryptHwMutexLock() != 0) {
@@ -2294,11 +2314,8 @@ int se050_ecc_verify_hash_ex(const byte* hash, word32 hashLen, MATH_INT_T* r,
22942314

22952315
algorithm = se050_map_hash_alg(hashLen);
22962316
if (algorithm == kAlgorithm_None) {
2297-
hashLen = keySize; /* try key size */
2298-
algorithm = se050_map_hash_alg(hashLen);
2299-
}
2300-
if (algorithm == kAlgorithm_None) {
2301-
return ECC_CURVE_OID_E;
2317+
WOLFSSL_MSG("SE050 ECDSA verify only supports SHA-1/224/256/384/512 digest sizes");
2318+
return BAD_LENGTH_E;
23022319
}
23032320

23042321
if (wolfSSL_CryptHwMutexLock() != 0) {
@@ -2577,7 +2594,7 @@ int se050_ecc_create_key(struct ecc_key* key, int curve_id, int keySize)
25772594
sss_key_store_t host_keystore;
25782595
uint8_t derBuf[SE050_ECC_DER_MAX];
25792596
size_t derSz = sizeof(derBuf);
2580-
word32 keyId;
2597+
word32 keyId = 0;
25812598
int keySizeBits;
25822599
sss_cipher_type_t curveType;
25832600
int keyCreated = 0;
@@ -2671,7 +2688,7 @@ int se050_ecc_shared_secret(ecc_key* private_key, ecc_key* public_key,
26712688
sss_object_t ref_public_key;
26722689
sss_object_t deriveKey;
26732690
sss_derive_key_t ctx_derive_key;
2674-
word32 keyId;
2691+
word32 keyId = 0;
26752692
int keySize;
26762693
int keySizeBits;
26772694
sss_cipher_type_t curveType;
@@ -3039,6 +3056,12 @@ int se050_ed25519_verify_msg(const byte* signature, word32 signatureLen,
30393056
key, signature, signatureLen, msg, msgLen);
30403057
#endif
30413058

3059+
if (signature == NULL || msg == NULL || key == NULL || res == NULL) {
3060+
return BAD_FUNC_ARG;
3061+
}
3062+
3063+
*res = 0;
3064+
30423065
if (cfg_se050_i2c_pi == NULL) {
30433066
return WC_HW_E;
30443067
}
@@ -3099,8 +3122,21 @@ int se050_ed25519_verify_msg(const byte* signature, word32 signatureLen,
30993122
}
31003123

31013124
if (status == kStatus_SSS_Success) {
3102-
key->keyId = keyId;
3103-
key->keyIdSet = 1;
3125+
if (keyCreated) {
3126+
/* We uploaded only the public part of the key for this verify.
3127+
* Don't persist keyIdSet=1 -- a later sign on the same ed25519_key
3128+
* would reuse this binding and fail because the SE050 object has
3129+
* no private material. Erase the transient object so the next
3130+
* SE050 op re-uploads. Mirrors the fix in se050_rsa_verify. */
3131+
sss_key_store_erase_key(&host_keystore, &newKey);
3132+
sss_key_object_free(&newKey);
3133+
}
3134+
else {
3135+
/* Pre-existing keyIdSet=1 binding (from prior sign that uploaded
3136+
* a keypair, or explicit caller setup). Preserve it. */
3137+
key->keyId = keyId;
3138+
key->keyIdSet = 1;
3139+
}
31043140
*res = 1;
31053141
ret = 0;
31063142
}

wolfcrypt/src/rsa.c

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3660,6 +3660,7 @@ static int RsaPrivateDecryptEx(const byte* in, word32 inLen, byte* out,
36603660
}
36613661
return ret;
36623662
}
3663+
#if !defined(WOLFSSL_SE050_NO_RSA_VERIFY)
36633664
else if (rsa_type == RSA_PUBLIC_DECRYPT &&
36643665
pad_value == RSA_BLOCK_TYPE_1 &&
36653666
pad_type != WC_RSA_PSS_PAD) {
@@ -3675,6 +3676,7 @@ static int RsaPrivateDecryptEx(const byte* in, word32 inLen, byte* out,
36753676
}
36763677
return ret;
36773678
}
3679+
#endif /* !WOLFSSL_SE050_NO_RSA_VERIFY */
36783680
#endif /* RSA CRYPTO HW */
36793681

36803682

0 commit comments

Comments
 (0)