Skip to content
Merged
68 changes: 68 additions & 0 deletions .github/workflows/se050-sim.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
name: SE050 simulator test

# START OF COMMON SECTION
on:
push:
branches: [ 'master', 'main', 'release/**' ]
pull_request:
branches: [ '*' ]

concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true
# END OF COMMON SECTION

# Build the SE050 software simulator (https://github.com/LinuxJedi/SE050Sim),
# build wolfSSL against its NXP Plug&Trust SDK + simulator bridge, and run the
# wolfCrypt SE050 test binary against the simulator TCP server.
#
# The simulator's own Dockerfile (Dockerfile.wolfcrypt) clones wolfSSL master.
# We patch it to COPY the PR checkout instead so CI reflects the PR's source.

env:
SE050SIM_REF: 8fda9212c306fbee0dcd66f2dd52b13f65f13e00

jobs:
se050_sim:
name: wolfCrypt against SE050 simulator
if: github.repository_owner == 'wolfssl'
runs-on: ubuntu-24.04
timeout-minutes: 30
steps:
- name: Checkout wolfSSL (PR source)
uses: actions/checkout@v4
with:
path: wolfssl-src

- name: Clone SE050 simulator
run: |
git clone https://github.com/LinuxJedi/SE050Sim se050sim
cd se050sim && git checkout "$SE050SIM_REF"

- name: Stage PR wolfSSL into simulator build context
run: mv wolfssl-src se050sim/wolfssl

- name: Patch Dockerfile to use PR wolfSSL instead of upstream master
working-directory: se050sim
run: |
sed -i 's|^RUN git clone --depth 1 https://github.com/wolfSSL/wolfssl.git /app/wolfssl$|COPY wolfssl /app/wolfssl|' Dockerfile.wolfcrypt
# Fail fast if the pattern drifted upstream -- better a clear error
# than a CI run that silently tests master.
grep -q '^COPY wolfssl /app/wolfssl$' Dockerfile.wolfcrypt
! grep -q 'git clone .*wolfssl\.git' Dockerfile.wolfcrypt

- uses: docker/setup-buildx-action@v3

- name: Build wolfCrypt-SE050 test image
uses: docker/build-push-action@v5
with:
context: se050sim
file: se050sim/Dockerfile.wolfcrypt
push: false
load: true
tags: wolfssl-se050-sim:ci
cache-from: type=gha
cache-to: type=gha,mode=max

- name: Run wolfCrypt tests against simulator
run: docker run --rm wolfssl-se050-sim:ci
3 changes: 3 additions & 0 deletions .wolfssl_known_macro_extras
Original file line number Diff line number Diff line change
Expand Up @@ -880,7 +880,10 @@ WOLFSSL_SE050_AUTO_ERASE
WOLFSSL_SE050_CRYPT
WOLFSSL_SE050_HASH
WOLFSSL_SE050_INIT
WOLFSSL_SE050_NO_ECDHE
WOLFSSL_SE050_NO_ECDSA_VERIFY
WOLFSSL_SE050_NO_RSA
WOLFSSL_SE050_NO_RSA_VERIFY
WOLFSSL_SE050_NO_TRNG
WOLFSSL_SECURE_RENEGOTIATION_ON_BY_DEFAULT
WOLFSSL_SERVER_EXAMPLE
Expand Down
9 changes: 6 additions & 3 deletions wolfcrypt/src/ecc.c
Original file line number Diff line number Diff line change
Expand Up @@ -291,6 +291,9 @@ ECC Curve Sizes:
#undef HAVE_ECC_VERIFY_HELPER
#define HAVE_ECC_VERIFY_HELPER
#endif
#if defined(WOLFSSL_SE050_NO_ECDSA_VERIFY) && defined(HAVE_ECC_VERIFY)
#define HAVE_ECC_VERIFY_HELPER
#endif

#if !defined(WOLFSSL_ATECC508A) && !defined(WOLFSSL_ATECC608A) && \
!defined(WOLFSSL_CRYPTOCELL) && !defined(WOLFSSL_SILABS_SE_ACCEL) && \
Expand Down Expand Up @@ -4767,7 +4770,7 @@ int wc_ecc_shared_secret(ecc_key* private_key, ecc_key* public_key, byte* out,
err = silabs_ecc_shared_secret(private_key, public_key, out, outlen);
#elif defined(WOLFSSL_KCAPI_ECC)
err = KcapiEcc_SharedSecret(private_key, public_key, out, outlen);
#elif defined(WOLFSSL_SE050)
#elif defined(WOLFSSL_SE050) && !defined(WOLFSSL_SE050_NO_ECDHE)
err = se050_ecc_shared_secret(private_key, public_key, out, outlen);
#else
err = wc_ecc_shared_secret_ex(private_key, &public_key->pubkey, out, outlen);
Expand Down Expand Up @@ -5761,7 +5764,7 @@ static int _ecc_make_key_ex(WC_RNG* rng, int keysize, ecc_key* key,
else {
err = NOT_COMPILED_IN;
}
#elif defined(WOLFSSL_SE050)
#elif defined(WOLFSSL_SE050) && !defined(WOLFSSL_SE050_NO_ECDHE)
err = se050_ecc_create_key(key, key->dp->id, key->dp->size);
key->type = ECC_PRIVATEKEY;
#elif defined(WOLFSSL_CRYPTOCELL)
Expand Down Expand Up @@ -9261,7 +9264,7 @@ int wc_ecc_verify_hash_ex(mp_int *r, mp_int *s, const byte* hash,
#elif defined(WOLFSSL_XILINX_CRYPT_VERSAL)
byte sigRS[ECC_MAX_CRYPTO_HW_SIZE * 2];
byte hashcopy[ECC_MAX_CRYPTO_HW_SIZE] = {0};
#elif defined(WOLFSSL_SE050)
#elif defined(WOLFSSL_SE050) && !defined(WOLFSSL_SE050_NO_ECDSA_VERIFY)
#else
int curveLoaded = 0;
DECLARE_CURVE_SPECS(ECC_CURVE_FIELD_COUNT);
Expand Down
39 changes: 39 additions & 0 deletions wolfcrypt/src/ed25519.c
Original file line number Diff line number Diff line change
Expand Up @@ -1169,6 +1169,18 @@ int wc_ed25519_import_public_ex(const byte* in, word32 inLen, ed25519_key* key,
if (inLen < ED25519_PUB_KEY_SIZE)
return BAD_FUNC_ARG;

#ifdef WOLFSSL_SE050
/* Importing new key material invalidates any prior SE050 object binding;
* erase the old object (no-op when keyIdSet == 0) so the host and the
* secure element agree on what's bound. Clear the binding fields
* explicitly afterwards so a stale keyId never survives, even when
* se050_ed25519_free_key() returns early because the SE050 session isn't
* configured yet. */
se050_ed25519_free_key(key);
key->keyId = 0;
key->keyIdSet = 0;
#endif

/* compressed prefix according to draft
http://www.ietf.org/id/draft-koch-eddsa-for-openpgp-02.txt */
if (in[0] == 0x40 && inLen == ED25519_PUB_KEY_SIZE + 1) {
Expand Down Expand Up @@ -1255,6 +1267,18 @@ int wc_ed25519_import_private_only(const byte* priv, word32 privSz,
if (privSz != ED25519_KEY_SIZE)
return BAD_FUNC_ARG;

#ifdef WOLFSSL_SE050
/* Importing new key material invalidates any prior SE050 object binding;
* erase the old object (no-op when keyIdSet == 0) so the host and the
* secure element agree on what's bound. Clear the binding fields
* explicitly afterwards so a stale keyId never survives, even when
* se050_ed25519_free_key() returns early because the SE050 session isn't
* configured yet. */
se050_ed25519_free_key(key);
key->keyId = 0;
key->keyIdSet = 0;
#endif

XMEMCPY(key->k, priv, ED25519_KEY_SIZE);
key->privKeySet = 1;

Expand Down Expand Up @@ -1311,6 +1335,21 @@ int wc_ed25519_import_private_key_ex(const byte* priv, word32 privSz,
return BAD_FUNC_ARG;
}

#ifdef WOLFSSL_SE050
/* Importing new key material invalidates any prior SE050 object binding;
* erase the old object (no-op when keyIdSet == 0) so the host and the
* secure element agree on what's bound. key->k is overwritten before the
* wc_ed25519_import_public_ex() call below, so the binding must be
* dropped here first in case that function fails its own early-return
* argument checks before reaching its reset. Clear the binding fields
* explicitly afterwards so a stale keyId never survives, even when
* se050_ed25519_free_key() returns early because the SE050 session isn't
* configured yet. */
se050_ed25519_free_key(key);
key->keyId = 0;
key->keyIdSet = 0;
#endif

XMEMCPY(key->k, priv, ED25519_KEY_SIZE);
key->privKeySet = 1;

Expand Down
19 changes: 19 additions & 0 deletions wolfcrypt/src/port/nxp/README_SE050.md
Original file line number Diff line number Diff line change
Expand Up @@ -246,6 +246,25 @@ defined, wolfCrypt will instead fall back to using `/dev/random` and
Disables using the SE050 for RSA, useful for the SE050E which does not have
RSA support.

**`WOLFSSL_SE050_NO_ECDHE`**

Disables offloading ECDH key generation and shared secret operations to the
SE050. When defined, `wc_ecc_make_key()` and `wc_ecc_shared_secret()` will
use wolfCrypt software instead of the SE050.

**`WOLFSSL_SE050_NO_ECDSA_VERIFY`**

When defined, ECDSA signing (`wc_ecc_sign_hash()`) continues to be offloaded
to the SE050, but ECDSA verification (`wc_ecc_verify_hash()`) uses wolfCrypt
software.

**`WOLFSSL_SE050_NO_RSA_VERIFY`**

When defined, RSA PKCS#1 v1.5 signing (`wc_RsaSSL_Sign()`) continues to be
offloaded to the SE050, but RSA PKCS#1 v1.5 verification (`wc_RsaSSL_Verify()`)
uses wolfCrypt software (public-key exponentiation + unpad). RSA PSS verify and
RSA key-exchange decrypt are unaffected.

## wolfSSL HostCrypto Support

The NXP SE05x Plug & Trust Middleware by default can use either OpenSSL or
Expand Down
76 changes: 56 additions & 20 deletions wolfcrypt/src/port/nxp/se050_port.c
Original file line number Diff line number Diff line change
Expand Up @@ -810,7 +810,7 @@ int se050_rsa_get_key_id(struct RsaKey* key, word32* keyId)
int se050_rsa_create_key(struct RsaKey* key, int size, long e)
{
int ret = 0;
word32 keyId;
word32 keyId = 0;
int keyCreated = 0;
sss_status_t status = kStatus_SSS_Success;
sss_object_t keyPair;
Expand Down Expand Up @@ -1483,7 +1483,7 @@ int se050_rsa_verify(const byte* in, word32 inLen, byte* out, word32 outLen,
keyId = se050_allocate_key(SE050_RSA_KEY);
status = sss_key_object_allocate_handle(&newKey, keyId,
kSSS_KeyPart_Public, kSSS_CipherType_RSA, keySz,
kKeyObject_Mode_Persistent);
kKeyObject_Mode_Transient);
}
if (status == kStatus_SSS_Success) {
/* Try to delete existing key first, ignore return since will
Expand Down Expand Up @@ -1538,8 +1538,22 @@ int se050_rsa_verify(const byte* in, word32 inLen, byte* out, word32 outLen,
}

if (status == kStatus_SSS_Success) {
key->keyId = keyId;
key->keyIdSet = 1;
if (keyCreated) {
/* We uploaded only the public part of the key for this verify.
* Don't persist keyIdSet=1 -- a later sign on the same RsaKey
* would reuse this binding and fail because the SE050 object has
* no private material. Erase the transient object so the next
* SE050 op (sign or verify) re-uploads from whatever the host
* RsaKey currently holds. */
sss_key_store_erase_key(&host_keystore, &newKey);
sss_key_object_free(&newKey);
}
else {
/* Pre-existing keyIdSet=1 binding (e.g. wc_RsaUseKeyId or prior
* sign that uploaded a keypair). Preserve it. */
key->keyId = keyId;
key->keyIdSet = 1;
}
}
else {
if (keyCreated) {
Expand Down Expand Up @@ -1696,8 +1710,17 @@ int se050_rsa_public_encrypt(const byte* in, word32 inLen, byte* out,
}

if (status == kStatus_SSS_Success) {
key->keyId = keyId;
key->keyIdSet = 1;
if (keyCreated) {
/* Public-key encrypt imported a temporary public object only.
* Do not bind that SE050 object to the caller's RsaKey or later
* private-key operations will try to reuse a public handle. */
sss_key_store_erase_key(&host_keystore, &newKey);
sss_key_object_free(&newKey);
}
else {
key->keyId = keyId;
key->keyIdSet = 1;
}
ret = encSz;
}
else {
Expand Down Expand Up @@ -2123,11 +2146,8 @@ int se050_ecc_sign_hash_ex(const byte* in, word32 inLen, MATH_INT_T* r, MATH_INT

algorithm = se050_map_hash_alg(inLen);
if (algorithm == kAlgorithm_None) {
inLen = keySize; /* try key size */
algorithm = se050_map_hash_alg(inLen);
}
if (algorithm == kAlgorithm_None) {
return ECC_CURVE_OID_E;
WOLFSSL_MSG("SE050 ECDSA sign only supports SHA-1/224/256/384/512 digest sizes");
return BAD_LENGTH_E;
}

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

algorithm = se050_map_hash_alg(hashLen);
if (algorithm == kAlgorithm_None) {
hashLen = keySize; /* try key size */
algorithm = se050_map_hash_alg(hashLen);
}
if (algorithm == kAlgorithm_None) {
return ECC_CURVE_OID_E;
WOLFSSL_MSG("SE050 ECDSA verify only supports SHA-1/224/256/384/512 digest sizes");
return BAD_LENGTH_E;
}

if (wolfSSL_CryptHwMutexLock() != 0) {
Expand Down Expand Up @@ -2577,7 +2594,7 @@ int se050_ecc_create_key(struct ecc_key* key, int curve_id, int keySize)
sss_key_store_t host_keystore;
uint8_t derBuf[SE050_ECC_DER_MAX];
size_t derSz = sizeof(derBuf);
word32 keyId;
word32 keyId = 0;
int keySizeBits;
sss_cipher_type_t curveType;
int keyCreated = 0;
Expand Down Expand Up @@ -2671,7 +2688,7 @@ int se050_ecc_shared_secret(ecc_key* private_key, ecc_key* public_key,
sss_object_t ref_public_key;
sss_object_t deriveKey;
sss_derive_key_t ctx_derive_key;
word32 keyId;
word32 keyId = 0;
int keySize;
int keySizeBits;
sss_cipher_type_t curveType;
Expand Down Expand Up @@ -3039,6 +3056,12 @@ int se050_ed25519_verify_msg(const byte* signature, word32 signatureLen,
key, signature, signatureLen, msg, msgLen);
#endif

if (signature == NULL || msg == NULL || key == NULL || res == NULL) {
return BAD_FUNC_ARG;
}

*res = 0;

if (cfg_se050_i2c_pi == NULL) {
return WC_HW_E;
}
Expand Down Expand Up @@ -3099,8 +3122,21 @@ int se050_ed25519_verify_msg(const byte* signature, word32 signatureLen,
}

if (status == kStatus_SSS_Success) {
key->keyId = keyId;
key->keyIdSet = 1;
if (keyCreated) {
/* We uploaded only the public part of the key for this verify.
* Don't persist keyIdSet=1 -- a later sign on the same ed25519_key
* would reuse this binding and fail because the SE050 object has
* no private material. Erase the transient object so the next
* SE050 op re-uploads. Mirrors the fix in se050_rsa_verify. */
sss_key_store_erase_key(&host_keystore, &newKey);
sss_key_object_free(&newKey);
}
else {
/* Pre-existing keyIdSet=1 binding (from prior sign that uploaded
* a keypair, or explicit caller setup). Preserve it. */
key->keyId = keyId;
key->keyIdSet = 1;
}
*res = 1;
ret = 0;
}
Expand Down
2 changes: 2 additions & 0 deletions wolfcrypt/src/rsa.c
Original file line number Diff line number Diff line change
Expand Up @@ -3660,6 +3660,7 @@ static int RsaPrivateDecryptEx(const byte* in, word32 inLen, byte* out,
}
return ret;
}
#if !defined(WOLFSSL_SE050_NO_RSA_VERIFY)
else if (rsa_type == RSA_PUBLIC_DECRYPT &&
pad_value == RSA_BLOCK_TYPE_1 &&
pad_type != WC_RSA_PSS_PAD) {
Expand All @@ -3675,6 +3676,7 @@ static int RsaPrivateDecryptEx(const byte* in, word32 inLen, byte* out,
}
return ret;
}
#endif /* !WOLFSSL_SE050_NO_RSA_VERIFY */
#endif /* RSA CRYPTO HW */


Expand Down
Loading
Loading