SE050: skip peer key upload on applet 7.2 ECDH path (peer review)

The direct ECDH APDU carries the peer public point in the command, so
uploading the peer key to the SE050 on the applet >= 7.2 path wasted
APDU round trips, consumed a persistent object slot per distinct peer
in the default build, and added a failure path the derive does not
need. Confine the upload, the keyId bookkeeping and the keyCreated
cleanup to the pre-7.2 arm; on 7.2 builds a reference object is only
taken when the peer public key is already SE050-resident.

Also from review: validate the ECC direct-APDU response length against
the curve size, mirroring the Curve25519 arm; scope the derive-key
state (deriveKey, ctx_derive_key, deriveKeyCreated and their init and
cleanup) into the pre-7.2 arm instead of voiding it; and reword the CI
workflow comment to describe SE050_SIM_STRICT_ECDH as a regression
guard, noting the pre-7.2 arm is hardware-verified (SE050C applet
3.1.1) until an 03_XX matrix leg exists.

Verified: wolfCrypt suite passes against the strict simulator on the
07_02 build; the pre-7.2 arm compiles clean against an 03_XX SDK.
This commit is contained in:
Andrew Hutchings
2026-08-04 11:42:20 +01:00
parent e30200c236
commit 6176a5a77d
2 changed files with 53 additions and 23 deletions
+8 -4
View File
@@ -102,8 +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
# SE050_SIM_STRICT_ECDH=1 makes the simulator enforce the applet 7.2
# ECDH InObject contract: the Tag7 target must be pre-created as an
# HMACKey object of exactly the shared-secret size or the derive is
# refused with SW 0x6985, matching SE05x applet >= 7.2 hardware.
# 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 }}
+45 -19
View File
@@ -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",
@@ -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) {
@@ -2845,7 +2848,6 @@ int se050_ecc_shared_secret(ecc_key* private_key, ecc_key* public_key,
if (status == kStatus_SSS_Success) {
status = sss_key_object_init(&deriveKey, &host_keystore);
}
#if !(defined(SSS_HAVE_SE05X_VER_GTE_07_02) && SSS_HAVE_SE05X_VER_GTE_07_02)
if (status == kStatus_SSS_Success) {
word32 keyIdAes = se050_allocate_key(SE050_AES_KEY);
status = sss_key_object_allocate_handle(&deriveKey,
@@ -2882,7 +2884,19 @@ int se050_ecc_shared_secret(ecc_key* private_key, ecc_key* public_key,
sss_derive_key_context_free(&ctx_derive_key);
}
if (deriveKeyCreated) {
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
@@ -2924,7 +2938,9 @@ int se050_ecc_shared_secret(ecc_key* private_key, ecc_key* public_key,
sm = Se05x_API_ECDHGenerateSharedSecret(
&((sss_se05x_session_t*)cfg_se050_i2c_pi)->s_ctx,
private_key->keyId, peerPoint, peerPointSz, out, &outSz);
if (sm == SM_OK) {
/* 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 {
@@ -2932,15 +2948,10 @@ int se050_ecc_shared_secret(ecc_key* private_key, ecc_key* public_key,
}
}
}
(void)ctx_derive_key;
(void)deriveKey;
#endif
if (deriveKeyCreated) {
sss_key_store_erase_key(&host_keystore, &deriveKey);
sss_key_object_free(&deriveKey);
}
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. */
@@ -2953,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;
}
@@ -3416,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;
int keySize = CURVE25519_KEYSIZE;
#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;
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",
@@ -3456,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) {
@@ -3496,7 +3513,6 @@ int se050_curve25519_shared_secret(curve25519_key* private_key,
if (status == kStatus_SSS_Success) {
status = sss_key_object_init(&deriveKey, &host_keystore);
}
#if !(defined(SSS_HAVE_SE05X_VER_GTE_07_02) && SSS_HAVE_SE05X_VER_GTE_07_02)
if (status == kStatus_SSS_Success) {
word32 keyIdAes = se050_allocate_key(SE050_AES_KEY);
status = sss_key_object_allocate_handle(&deriveKey,
@@ -3533,7 +3549,19 @@ int se050_curve25519_shared_secret(curve25519_key* private_key,
sss_derive_key_context_free(&ctx_derive_key);
}
if (deriveKeyCreated) {
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
@@ -3600,15 +3628,10 @@ int se050_curve25519_shared_secret(curve25519_key* private_key,
}
}
}
(void)ctx_derive_key;
(void)deriveKey;
#endif
if (deriveKeyCreated) {
sss_key_store_erase_key(&host_keystore, &deriveKey);
sss_key_object_free(&deriveKey);
}
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.*/
@@ -3621,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;
}