Skip to content

Commit 5facbf3

Browse files
committed
Fix SE050 Ed25519 port bugs and add simulator CI workflow
- se050_ed25519_verify_msg: initialize *res = 0 at entry so failures don't leak a stale res = 1 from a prior good verify. - Ed25519 import functions: reset keyIdSet / keyId under WOLFSSL_SE050 in wc_ed25519_import_private_key_ex, wc_ed25519_import_private_only, wc_ed25519_import_public_ex so overwriting host-side key material invalidates any prior SE050 object binding. - New workflow .github/workflows/se050-sim.yml: builds wolfSSL against the NXP Plug&Trust SDK and runs the wolfCrypt tests against the SE050Sim simulator. Patches the upstream Dockerfile to use the PR's wolfSSL source. - ed25519_test SE050 adjustments: - Cap the RFC 8032 loop at 5 iters — iter 5's 1023 B msg exceeds NXP SDK SE05X_TLV_BUF_SIZE_CMD = 900. - rareEd verifies and private-only sign: expect WC_HW_E (SE050 delegates malformed-input rejection to the secure element) instead of BAD_FUNC_ARG / SIG_VERIFY_E. - Skip ed25519ctx_test / ed25519ph_test — SE050 port drops the context/prehash params so RFC 8032 ctx/ph vectors can't byte-match.
1 parent d343ea6 commit 5facbf3

4 files changed

Lines changed: 135 additions & 5 deletions

File tree

.github/workflows/se050-sim.yml

Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,70 @@
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+
# Pin the simulator to a known-good revision. Bump this deliberately after
24+
# validating upstream changes in a standalone PR.
25+
SE050SIM_REF: main
26+
27+
jobs:
28+
se050_sim:
29+
name: wolfCrypt against SE050 simulator
30+
if: github.repository_owner == 'wolfssl'
31+
runs-on: ubuntu-24.04
32+
timeout-minutes: 30
33+
steps:
34+
- name: Checkout wolfSSL (PR source)
35+
uses: actions/checkout@v4
36+
with:
37+
path: wolfssl-src
38+
39+
- name: Clone SE050 simulator
40+
run: |
41+
git clone https://github.com/LinuxJedi/SE050Sim se050sim
42+
cd se050sim && git checkout "$SE050SIM_REF"
43+
44+
- name: Stage PR wolfSSL into simulator build context
45+
run: mv wolfssl-src se050sim/wolfssl
46+
47+
- name: Patch Dockerfile to use PR wolfSSL instead of upstream master
48+
working-directory: se050sim
49+
run: |
50+
sed -i 's|^RUN git clone --depth 1 https://github.com/wolfSSL/wolfssl.git /app/wolfssl$|COPY wolfssl /app/wolfssl|' Dockerfile.wolfcrypt
51+
# Fail fast if the pattern drifted upstream — better a clear error
52+
# than a CI run that silently tests master.
53+
grep -q '^COPY wolfssl /app/wolfssl$' Dockerfile.wolfcrypt
54+
! grep -q 'git clone .*wolfssl\.git' Dockerfile.wolfcrypt
55+
56+
- uses: docker/setup-buildx-action@v3
57+
58+
- name: Build wolfCrypt-SE050 test image
59+
uses: docker/build-push-action@v5
60+
with:
61+
context: se050sim
62+
file: se050sim/Dockerfile.wolfcrypt
63+
push: false
64+
load: true
65+
tags: wolfssl-se050-sim:ci
66+
cache-from: type=gha
67+
cache-to: type=gha,mode=max
68+
69+
- name: Run wolfCrypt tests against simulator
70+
run: docker run --rm wolfssl-se050-sim:ci

wolfcrypt/src/ed25519.c

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1169,6 +1169,12 @@ 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+
key->keyIdSet = 0;
1175+
key->keyId = 0;
1176+
#endif
1177+
11721178
/* compressed prefix according to draft
11731179
http://www.ietf.org/id/draft-koch-eddsa-for-openpgp-02.txt */
11741180
if (in[0] == 0x40 && inLen == ED25519_PUB_KEY_SIZE + 1) {
@@ -1255,6 +1261,12 @@ int wc_ed25519_import_private_only(const byte* priv, word32 privSz,
12551261
if (privSz != ED25519_KEY_SIZE)
12561262
return BAD_FUNC_ARG;
12571263

1264+
#ifdef WOLFSSL_SE050
1265+
/* Importing new key material invalidates any prior SE050 object binding. */
1266+
key->keyIdSet = 0;
1267+
key->keyId = 0;
1268+
#endif
1269+
12581270
XMEMCPY(key->k, priv, ED25519_KEY_SIZE);
12591271
key->privKeySet = 1;
12601272

@@ -1311,6 +1323,12 @@ int wc_ed25519_import_private_key_ex(const byte* priv, word32 privSz,
13111323
return BAD_FUNC_ARG;
13121324
}
13131325

1326+
#ifdef WOLFSSL_SE050
1327+
/* Importing new key material invalidates any prior SE050 object binding. */
1328+
key->keyIdSet = 0;
1329+
key->keyId = 0;
1330+
#endif
1331+
13141332
XMEMCPY(key->k, priv, ED25519_KEY_SIZE);
13151333
key->privKeySet = 1;
13161334

wolfcrypt/src/port/nxp/se050_port.c

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3039,6 +3039,8 @@ int se050_ed25519_verify_msg(const byte* signature, word32 signatureLen,
30393039
key, signature, signatureLen, msg, msgLen);
30403040
#endif
30413041

3042+
*res = 0;
3043+
30423044
if (cfg_se050_i2c_pi == NULL) {
30433045
return WC_HW_E;
30443046
}

wolfcrypt/test/test.c

Lines changed: 45 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -40971,7 +40971,16 @@ WOLFSSL_TEST_SUBROUTINE wc_test_ret_t ed25519_test(void)
4097140971

4097240972
#if defined(HAVE_ED25519_SIGN) && defined(HAVE_ED25519_KEY_EXPORT) && \
4097340973
defined(HAVE_ED25519_KEY_IMPORT)
40974+
#ifdef WOLFSSL_SE050
40975+
/* Iter 5 uses RFC 8032 msg4 (~1023 bytes), which exceeds the NXP
40976+
* Plug&Trust SDK's SE05X_TLV_BUF_SIZE_CMD = 900 byte APDU buffer:
40977+
* EdDSASign fails with "Not enough buffer" before the command reaches
40978+
* the secure element. Cap at 5 iterations until the SDK buffer is
40979+
* enlarged upstream. */
40980+
for (i = 0; i < 5; i++) {
40981+
#else
4097440982
for (i = 0; i < 6; i++) {
40983+
#endif
4097540984
outlen = sizeof(out);
4097640985
XMEMSET(out, 0, sizeof(out));
4097740986

@@ -41044,7 +41053,12 @@ WOLFSSL_TEST_SUBROUTINE wc_test_ret_t ed25519_test(void)
4104441053
#endif /* HAVE_ED25519_VERIFY */
4104541054
}
4104641055

41047-
#ifdef HAVE_ED25519_VERIFY
41056+
#if defined(HAVE_ED25519_VERIFY)
41057+
/* These cases exercise host-side signature-encoding pre-validation (e.g.,
41058+
* sig == curve order). The SE050 port delegates verify to the secure
41059+
* element, which rejects all four inputs with WC_HW_E rather than the
41060+
* BAD_FUNC_ARG / SIG_VERIFY_E the host-side path produces — so the
41061+
* expected error code differs below when built against an SE050. */
4104841062
{
4104941063
/* Run tests for some rare code paths */
4105041064
/* sig is exactly equal to the order */
@@ -41097,35 +41111,53 @@ WOLFSSL_TEST_SUBROUTINE wc_test_ret_t ed25519_test(void)
4109741111
if (ret != 0)
4109841112
ERROR_OUT(WC_TEST_RET_ENC_EC(ret), cleanup);
4109941113

41114+
#ifdef WOLFSSL_SE050
41115+
#define RARE_ED_BAD_ENC_E WC_HW_E
41116+
#define RARE_ED_BAD_SIG_E WC_HW_E
41117+
#else
41118+
#define RARE_ED_BAD_ENC_E BAD_FUNC_ARG
41119+
#define RARE_ED_BAD_SIG_E SIG_VERIFY_E
41120+
#endif
41121+
4110041122
ret = wc_ed25519_verify_msg(rareEd1, sizeof(rareEd1), msgs[0], msgSz[0],
4110141123
&verify, key);
41102-
if (ret != WC_NO_ERR_TRACE(BAD_FUNC_ARG))
41124+
if (ret != WC_NO_ERR_TRACE(RARE_ED_BAD_ENC_E))
4110341125
ERROR_OUT(WC_TEST_RET_ENC_EC(ret), cleanup);
4110441126

4110541127
ret = wc_ed25519_verify_msg(rareEd2, sizeof(rareEd2), msgs[0], msgSz[0],
4110641128
&verify, key);
41107-
if (ret != WC_NO_ERR_TRACE(BAD_FUNC_ARG))
41129+
if (ret != WC_NO_ERR_TRACE(RARE_ED_BAD_ENC_E))
4110841130
ERROR_OUT(WC_TEST_RET_ENC_EC(ret), cleanup);
4110941131

4111041132
ret = wc_ed25519_verify_msg(rareEd3, sizeof(rareEd3), msgs[0], msgSz[0],
4111141133
&verify, key);
41112-
if (ret != WC_NO_ERR_TRACE(BAD_FUNC_ARG))
41134+
if (ret != WC_NO_ERR_TRACE(RARE_ED_BAD_ENC_E))
4111341135
ERROR_OUT(WC_TEST_RET_ENC_EC(ret), cleanup);
4111441136

4111541137
ret = wc_ed25519_verify_msg(rareEd4, sizeof(rareEd4), msgs[0], msgSz[0],
4111641138
&verify, key);
41117-
if (ret != WC_NO_ERR_TRACE(SIG_VERIFY_E))
41139+
if (ret != WC_NO_ERR_TRACE(RARE_ED_BAD_SIG_E))
4111841140
ERROR_OUT(WC_TEST_RET_ENC_EC(ret), cleanup);
41141+
41142+
#undef RARE_ED_BAD_ENC_E
41143+
#undef RARE_ED_BAD_SIG_E
4111941144
}
4112041145
#endif /* HAVE_ED25519_VERIFY */
4112141146

41147+
#ifndef WOLFSSL_SE050
41148+
/* Ed25519ctx and Ed25519ph require passing a context / prehash flag
41149+
* through to the signer. The SE050 port's se050_ed25519_sign_msg /
41150+
* _verify_msg drop those parameters and always do plain Ed25519, so the
41151+
* RFC 8032 ctx/ph test vectors cannot match. Skip these variants when
41152+
* built against an SE050. */
4112241153
ret = ed25519ctx_test();
4112341154
if (ret != 0)
4112441155
goto cleanup;
4112541156

4112641157
ret = ed25519ph_test();
4112741158
if (ret != 0)
4112841159
goto cleanup;
41160+
#endif /* !WOLFSSL_SE050 */
4112941161

4113041162
#ifndef NO_ASN
4113141163
/* Try ASN.1 encoded private-only key and public key. */
@@ -41140,8 +41172,16 @@ WOLFSSL_TEST_SUBROUTINE wc_test_ret_t ed25519_test(void)
4114041172
sizeof(badPrivateEd25519)) == 0)
4114141173
ERROR_OUT(WC_TEST_RET_ENC_NC, cleanup);
4114241174

41175+
/* Signing with a private-only key (no public loaded yet) is rejected on
41176+
* the host with BAD_FUNC_ARG. The SE050 port instead fails inside
41177+
* sss_se05x_key_store_set_ecc_keypair and returns WC_HW_E, so accept
41178+
* that alternate error code when built against an SE050. */
4114341179
ret = wc_ed25519_sign_msg(msgs[0], msgSz[0], out, &outlen, key3);
41180+
#ifdef WOLFSSL_SE050
41181+
if (ret != WC_NO_ERR_TRACE(WC_HW_E))
41182+
#else
4114441183
if (ret != WC_NO_ERR_TRACE(BAD_FUNC_ARG))
41184+
#endif
4114541185
ERROR_OUT(WC_TEST_RET_ENC_EC(ret), cleanup);
4114641186

4114741187
/* try with a buffer size that is too large */

0 commit comments

Comments
 (0)