Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 13 additions & 3 deletions .github/workflows/se050-sim.yml
Original file line number Diff line number Diff line change
Expand Up @@ -31,14 +31,16 @@ permissions:
# We patch it to COPY the PR checkout instead so CI reflects the PR's source.

env:
SIMULATORS_REF: 745893640e21a15b7df8c70567c522953aba2f2c
SIMULATORS_REF: 895ff41b2447efe952e902c467c5ef479f3eda37

jobs:
se050_sim:
name: wolfCrypt against SE050 simulator (${{ matrix.name }})
if: ${{ (github.repository_owner == 'wolfssl') && (github.event_name != 'pull_request' || github.event.pull_request.draft == false) }}
runs-on: ubuntu-24.04
timeout-minutes: 30
# Cold image rebuilds (registry cache miss after a SIMULATORS_REF bump,
# until the weekend cron refreshes the cache) need well over 30 minutes.
timeout-minutes: 60
strategy:
fail-fast: false
matrix:
Expand Down Expand Up @@ -100,4 +102,12 @@ jobs:
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' || '' }}

- name: Run wolfCrypt tests against simulator
Comment thread
dgarske marked this conversation as resolved.
run: docker run --rm wolfssl-se050-sim:ci-${{ matrix.name }}
# SE050_SIM_STRICT_ECDH=1 enforces the applet 7.2 InObject contract
# (a Tag7 target must already exist as an exactly-sized HMACKey).
# The port now always uses the Tag7-less direct variant, so this is
# a regression guard: it fails the run if the InObject flow comes
# back. Note the SDK in the image is built for applet 07_02, so only
# the >= 7.2 side of the port's version split is compiled here; the
# pre-7.2 Binary derive flow is hardware-verified (SE050C, applet
# 3.1.1) until an 03_XX matrix leg is added.
run: docker run --rm -e SE050_SIM_STRICT_ECDH=1 wolfssl-se050-sim:ci-${{ matrix.name }}
2 changes: 1 addition & 1 deletion .wolfssl_known_macro_extras
Original file line number Diff line number Diff line change
Expand Up @@ -609,6 +609,7 @@ SP_USE_DIVTI3
SQRTMOD_USE_MOD_EXP
SSL_SNIFFER_EXPORTS
SSN_BUILDING_LIBYASSL
SSS_HAVE_SE05X_VER_GTE_07_02
STATIC_CHUNKS_ONLY
STM32F107xC
STM32F207xx
Expand Down Expand Up @@ -891,7 +892,6 @@ WOLFSSL_MAKE_SYSTEM_NAME_LINUX
WOLFSSL_MAKE_SYSTEM_NAME_WSL
WOLFSSL_MANUALLY_SELECT_DEVICE_CONFIG
WOLFSSL_MDK5
WOLFSSL_MEM_FAIL_COUNT
WOLFSSL_MICROCHIP_AESGCM
WOLFSSL_MLKEM_ASM_TEST
WOLFSSL_MLKEM_INVNTT_UNROLL
Expand Down
170 changes: 165 additions & 5 deletions wolfcrypt/src/port/nxp/se050_port.c
Original file line number Diff line number Diff line change
Expand Up @@ -2754,14 +2754,16 @@ int se050_ecc_shared_secret(ecc_key* private_key, ecc_key* public_key,
sss_key_store_t host_keystore;
sss_object_t ref_private_key;
sss_object_t ref_public_key;
sss_object_t deriveKey;
sss_derive_key_t ctx_derive_key;
word32 keyId = 0;
int keySize;
int keySizeBits;
sss_cipher_type_t curveType;
#if !(defined(SSS_HAVE_SE05X_VER_GTE_07_02) && SSS_HAVE_SE05X_VER_GTE_07_02)
sss_object_t deriveKey;
sss_derive_key_t ctx_derive_key;
word32 keyId = 0;
int keyCreated = 0;
int deriveKeyCreated = 0;
#endif

#ifdef SE050_DEBUG
printf("se050_ecc_shared_secret: priv %p, pub %p, out %p (%d)\n",
Expand Down Expand Up @@ -2801,6 +2803,7 @@ int se050_ecc_shared_secret(ecc_key* private_key, ecc_key* public_key,
if (status == kStatus_SSS_Success) {
status = sss_key_object_init(&ref_public_key, &host_keystore);
}
#if !(defined(SSS_HAVE_SE05X_VER_GTE_07_02) && SSS_HAVE_SE05X_VER_GTE_07_02)
if (status == kStatus_SSS_Success) {
keyId = public_key->keyId;
if (public_key->keyIdSet == 0) {
Expand Down Expand Up @@ -2850,6 +2853,9 @@ int se050_ecc_shared_secret(ecc_key* private_key, ecc_key* public_key,
status = sss_key_object_allocate_handle(&deriveKey,
keyIdAes,
kSSS_KeyPart_Default,
/* The applet denies ReadObject on a symmetric key object no
* matter what policy is attached, so the derive target must
* be a Binary object, which ReadObject allows by default */
kSSS_CipherType_Binary,
keySize,
kKeyObject_Mode_Transient);
Expand Down Expand Up @@ -2882,8 +2888,70 @@ int se050_ecc_shared_secret(ecc_key* private_key, ecc_key* public_key,
sss_key_store_erase_key(&host_keystore, &deriveKey);
sss_key_object_free(&deriveKey);
}
#else
/* The direct APDU carries the peer public point in the command, so
* the peer key is never uploaded to the SE050 on this path; a
* reference object is only needed when the peer public key is
* already SE050-resident. */
if (status == kStatus_SSS_Success && public_key->keyIdSet != 0) {
status = sss_key_object_get_handle(&ref_public_key,
public_key->keyId);
}
if (status == kStatus_SSS_Success) {
/* Middleware built for applet >= 7.2 derives into an SE05x
* resident object, but the applet refuses to export a symmetric
* key object regardless of the policy attached at its creation
* (verified on SE051 applet 7.2.0 hardware), so a derived secret
* stored in an object can never be read back. Use the direct
* APDU that returns the shared secret in the response instead,
* as the middleware itself does whenever the derived key lives
* in a host keystore. */
byte peerPoint[SE050_ECC_DER_MAX];
Comment thread
dgarske marked this conversation as resolved.
word32 peerPointSz = (word32)sizeof(peerPoint);
smStatus_t sm;

if (public_key->keyIdSet == 0) {
ret = wc_ecc_export_x963(public_key, peerPoint, &peerPointSz);
if (ret != 0) {
status = kStatus_SSS_Fail;
}
}
else {
/* Peer public key is SE050-resident: read the DER encoding
* back and use the trailing uncompressed point */
size_t derSz = sizeof(peerPoint);
size_t derSzBits = derSz * 8;
word32 pointSz = (word32)(1 + 2 * keySize);
status = sss_key_store_get_key(&host_keystore, &ref_public_key,
peerPoint, &derSz, &derSzBits);
if (status == kStatus_SSS_Success && derSz >= pointSz &&
peerPoint[derSz - pointSz] == 0x04) {
XMEMMOVE(peerPoint, peerPoint + derSz - pointSz, pointSz);
peerPointSz = pointSz;
}
else {
status = kStatus_SSS_Fail;
}
}
if (status == kStatus_SSS_Success) {
Comment thread
dgarske marked this conversation as resolved.
size_t outSz = (size_t)*outlen;
sm = Se05x_API_ECDHGenerateSharedSecret(
&((sss_se05x_session_t*)cfg_se050_i2c_pi)->s_ctx,
private_key->keyId, peerPoint, peerPointSz, out, &outSz);
/* a NIST curve shared secret is always exactly keySize
* bytes; anything else indicates a malformed response */
if (sm == SM_OK && outSz == (size_t)keySize) {
*outlen = (word32)outSz;
}
else {
status = kStatus_SSS_Fail;
}
}
}
#endif

if (status == kStatus_SSS_Success) {
#if !(defined(SSS_HAVE_SE05X_VER_GTE_07_02) && SSS_HAVE_SE05X_VER_GTE_07_02)
#ifdef WOLFSSL_SE050_ONLY_KEY_ID
if (keyCreated) {
/* The peer's public key was uploaded for this derivation only. */
Expand All @@ -2896,13 +2964,16 @@ int se050_ecc_shared_secret(ecc_key* private_key, ecc_key* public_key,
public_key->keyId = keyId;
public_key->keyIdSet = 1;
}
#endif /* !SSS_HAVE_SE05X_VER_GTE_07_02 */
ret = 0;
}
else {
#if !(defined(SSS_HAVE_SE05X_VER_GTE_07_02) && SSS_HAVE_SE05X_VER_GTE_07_02)
if (keyCreated) {
sss_key_store_erase_key(&host_keystore, &ref_public_key);
sss_key_object_free(&ref_public_key);
}
#endif
if (ret == 0) {
ret = WC_HW_E;
}
Expand Down Expand Up @@ -3359,12 +3430,14 @@ int se050_curve25519_shared_secret(curve25519_key* private_key,
sss_key_store_t host_keystore;
sss_object_t ref_private_key;
sss_object_t ref_public_key;
#if !(defined(SSS_HAVE_SE05X_VER_GTE_07_02) && SSS_HAVE_SE05X_VER_GTE_07_02)
int keySize = CURVE25519_KEYSIZE;
sss_object_t deriveKey;
sss_derive_key_t ctx_derive_key;
word32 keyId;
int keySize = CURVE25519_KEYSIZE;
int keyCreated = 0;
int deriveKeyCreated = 0;
#endif

#ifdef SE050_DEBUG
printf("se050_curve25519_shared_secret: priv %p, pub %p, out %p (%d)\n",
Expand Down Expand Up @@ -3399,6 +3472,7 @@ int se050_curve25519_shared_secret(curve25519_key* private_key,
if (status == kStatus_SSS_Success) {
status = sss_key_object_init(&ref_public_key, &host_keystore);
}
#if !(defined(SSS_HAVE_SE05X_VER_GTE_07_02) && SSS_HAVE_SE05X_VER_GTE_07_02)
if (status == kStatus_SSS_Success) {
keyId = public_key->keyId;
if (public_key->keyIdSet == 0) {
Expand Down Expand Up @@ -3441,10 +3515,12 @@ int se050_curve25519_shared_secret(curve25519_key* private_key,
}
if (status == kStatus_SSS_Success) {
word32 keyIdAes = se050_allocate_key(SE050_AES_KEY);
deriveKeyCreated = 1;
status = sss_key_object_allocate_handle(&deriveKey,
keyIdAes,
kSSS_KeyPart_Default,
/* The applet denies ReadObject on a symmetric key object no
* matter what policy is attached, so the derive target must
* be a Binary object, which ReadObject allows by default */
kSSS_CipherType_Binary,
keySize,
kKeyObject_Mode_Transient);
Expand All @@ -3454,12 +3530,16 @@ int se050_curve25519_shared_secret(curve25519_key* private_key,
&ref_private_key, kAlgorithm_SSS_ECDH,
kMode_SSS_ComputeSharedSecret);
if (status == kStatus_SSS_Success) {
/* Try to delete existing key first, ignore return since will
* fail if no key exists yet */
sss_key_store_erase_key(&host_keystore, &deriveKey);
status = sss_derive_key_dh(&ctx_derive_key, &ref_public_key,
&deriveKey);
}
if (status == kStatus_SSS_Success) {
size_t outlenSz = sizeof(out->point);
size_t outlenSzBits = outlenSz * 8;
deriveKeyCreated = 1;
/* derived key export */
status = sss_key_store_get_key(&host_keystore, &deriveKey,
out->point, &outlenSz, &outlenSzBits);
Expand All @@ -3473,8 +3553,85 @@ int se050_curve25519_shared_secret(curve25519_key* private_key,
sss_key_store_erase_key(&host_keystore, &deriveKey);
sss_key_object_free(&deriveKey);
}
#else
/* The direct APDU carries the peer public point in the command, so
* the peer key is never uploaded to the SE050 on this path; a
* reference object is only needed when the peer public key is
* already SE050-resident. */
if (status == kStatus_SSS_Success && public_key->keyIdSet != 0) {
status = sss_key_object_get_handle(&ref_public_key,
public_key->keyId);
}
if (status == kStatus_SSS_Success) {
/* Middleware built for applet >= 7.2 derives into an SE05x
* resident object, but the applet refuses to export a symmetric
* key object regardless of the policy attached at its creation
* (verified on SE051 applet 7.2.0 hardware), so a derived secret
* stored in an object can never be read back. Use the direct
* APDU that returns the shared secret in the response instead,
* as the middleware itself does whenever the derived key lives
* in a host keystore. The applet speaks big endian for
* Montgomery keys, so the peer point and the returned secret are
* both byte swapped, matching sss_se05x_derive_key_dh. */
byte peerPoint[CURVE25519_KEYSIZE];
word32 peerPointSz = (word32)sizeof(peerPoint);
smStatus_t sm;
int i;
byte swp;

if (public_key->keyIdSet == 0) {
ret = wc_curve25519_export_public_ex(public_key, peerPoint,
&peerPointSz, EC25519_LITTLE_ENDIAN);
if (ret != 0) {
status = kStatus_SSS_Fail;
}
}
else {
/* Peer public key is SE050-resident: read the DER encoding
* back; the raw little endian point is the trailing bytes */
byte derBuf[CURVE25519_PUB_KEY_SIZE + 12];
size_t derSz = sizeof(derBuf);
size_t derSzBits = derSz * 8;
status = sss_key_store_get_key(&host_keystore, &ref_public_key,
derBuf, &derSz, &derSzBits);
if (status == kStatus_SSS_Success &&
derSz >= CURVE25519_KEYSIZE) {
XMEMCPY(peerPoint, derBuf + derSz - CURVE25519_KEYSIZE,
CURVE25519_KEYSIZE);
peerPointSz = CURVE25519_KEYSIZE;
}
else {
status = kStatus_SSS_Fail;
}
}
if (status == kStatus_SSS_Success) {
size_t outSz = sizeof(out->point);
for (i = 0; i < CURVE25519_KEYSIZE / 2; i++) {
swp = peerPoint[i];
peerPoint[i] = peerPoint[CURVE25519_KEYSIZE - 1 - i];
peerPoint[CURVE25519_KEYSIZE - 1 - i] = swp;
}
sm = Se05x_API_ECDHGenerateSharedSecret(
&((sss_se05x_session_t*)cfg_se050_i2c_pi)->s_ctx,
private_key->keyId, peerPoint, peerPointSz,
out->point, &outSz);
if (sm == SM_OK && outSz == CURVE25519_KEYSIZE) {
for (i = 0; i < CURVE25519_KEYSIZE / 2; i++) {
swp = out->point[i];
out->point[i] = out->point[CURVE25519_KEYSIZE - 1 - i];
out->point[CURVE25519_KEYSIZE - 1 - i] = swp;
}
out->pointSz = (word32)outSz;
}
else {
status = kStatus_SSS_Fail;
}
}
}
#endif

if (status == kStatus_SSS_Success) {
#if !(defined(SSS_HAVE_SE05X_VER_GTE_07_02) && SSS_HAVE_SE05X_VER_GTE_07_02)
#ifdef WOLFSSL_SE050_ONLY_KEY_ID
if (keyCreated) {
/* The peer's public key was uploaded for this derivation only.*/
Expand All @@ -3487,13 +3644,16 @@ int se050_curve25519_shared_secret(curve25519_key* private_key,
public_key->keyId = keyId;
public_key->keyIdSet = 1;
}
#endif /* !SSS_HAVE_SE05X_VER_GTE_07_02 */
ret = 0;
}
else {
#if !(defined(SSS_HAVE_SE05X_VER_GTE_07_02) && SSS_HAVE_SE05X_VER_GTE_07_02)
if (keyCreated) {
sss_key_store_erase_key(&host_keystore, &ref_public_key);
sss_key_object_free(&ref_public_key);
}
#endif
if (ret == 0)
ret = WC_HW_E;
}
Expand Down
Loading