You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
With WOLFSSL_SILABS_CRYPTOCB (PR #11267), a P-256 key created by wc_SilabsSe_EccGenerateWrappedKey() and bound with wc_SilabsSe_EccUseWrappedKey() cannot be used for ECDSA. wc_ecc_sign_hash() returns WC_HW_E (-248), because the Secure Engine rejects the sign command with SL_STATUS_INVALID_PARAMETER.
The Secure Engine only signs with an ECC key whose descriptor has SL_SE_KEY_FLAG_ASYMMETRIC_SIGNING_ONLY. The port's wrapped-key and built-in-key paths never set it. ECDH with the same key works.
With the same bound key, wc_ecc_shared_secret() against a P-256 public point succeeds. The result equals the expected X coordinate when the peer is the base point.
Expected
wc_ecc_sign_hash() returns 0 with a valid signature, or wc_SilabsSe_EccGenerateWrappedKey() documents that its keys are for key agreement only.
Actual
wc_ecc_sign_hash() returns WC_HW_E. Calling sl_se_ecc_sign() directly with the bound descriptor (key.key) returns SL_STATUS_INVALID_PARAMETER (0x21), whatever the arguments:
Wrapped key generated with HAS_PRIVATE_KEY | SIGNING_ONLY, bound with the same flags
0 (OK)
sl_se_validate_key() accepts the port's descriptor (flags 0x01004000, type 0x80000020, wrapped size 60). The rejection comes from the Secure Engine's response, not from a check in the SE Manager.
Cause
On this part an ECC private key is either signing-only (SL_SE_KEY_FLAG_ASYMMETRIC_SIGNING_ONLY), usable for ECDSA, or a key-agreement key, usable for ECDH. For a wrapped key the flags are part of the wrapped blob, so they are fixed when the key is generated or imported. They must be described the same way every time the key is used: a descriptor with different flags is refused.
The port uses HAS_PRIVATE_KEY | NON_EXPORTABLE without SIGNING_ONLY everywhere it creates or binds a device-resident ECC key:
silabs_key.c L537-L538, wc_SilabsSe_EccUseBuiltInKey(). Not tested here, but by the same rule a built-in slot such as SL_SE_KEY_SLOT_APPLICATION_ATTESTATION_KEY may not be able to sign through it.
The plaintext paths do set it (silabs_ecc.c L257-L259, L331-L334). That is presumably why wolfcrypt_test and the ECDSA benchmark pass: they sign with plaintext keys, so the wrapped-key sign path is not exercised by them.
Suggested fix
Because the usage is fixed at creation, it has to be chosen when the key is generated and repeated when it is bound. For example:
The existing calls could stay as they are (agreement keys) and say so in their documentation and the README's "Secure Vault key management" section. A test that signs with a wrapped key would cover the path.
Contact Details
lucas.holzen@mmbnetworks.com
Version
Commit f6a75d4
Description
Summary
With
WOLFSSL_SILABS_CRYPTOCB(PR #11267), a P-256 key created bywc_SilabsSe_EccGenerateWrappedKey()and bound withwc_SilabsSe_EccUseWrappedKey()cannot be used for ECDSA.wc_ecc_sign_hash()returnsWC_HW_E(-248), because the Secure Engine rejects the sign command withSL_STATUS_INVALID_PARAMETER.The Secure Engine only signs with an ECC key whose descriptor has
SL_SE_KEY_FLAG_ASYMMETRIC_SIGNING_ONLY. The port's wrapped-key and built-in-key paths never set it. ECDH with the same key works.Environment
f6a75d4aaf2a50eabf30b5718300d68578e26101(merge of Add Silicon Labs EFR32xG25 Secure Element crypto callback port #11267)arm-none-eabi-gcc14.2.rel1, FreeRTOSuser_settings.h:WOLFSSL_SILABS_CRYPTOCB(all engines),HAVE_ECC,ECC_USER_CURVES(P-256 only),WOLFSSL_SP_MATH,WOLFSSL_SMALL_STACKwolfCrypt_Init()called at start-up, which registers the device atWOLFSSL_SILABS_DEVIDReproduction steps
With the same bound key,
wc_ecc_shared_secret()against a P-256 public point succeeds. The result equals the expected X coordinate when the peer is the base point.Expected
wc_ecc_sign_hash()returns 0 with a valid signature, orwc_SilabsSe_EccGenerateWrappedKey()documents that its keys are for key agreement only.Actual
wc_ecc_sign_hash()returnsWC_HW_E. Callingsl_se_ecc_sign()directly with the bound descriptor (key.key) returnsSL_STATUS_INVALID_PARAMETER(0x21), whatever the arguments:sl_se_ecc_sign()hashed_message = true,SL_SE_HASH_NONEhashed_message = false,SL_SE_HASH_SHA256size = 0instead of 32HAS_PRIVATE_KEYHAS_PRIVATE_KEY | SIGNING_ONLYHAS_PRIVATE_KEY | SIGNING_ONLY, bound with the same flagssl_se_validate_key()accepts the port's descriptor (flags 0x01004000,type 0x80000020, wrapped size 60). The rejection comes from the Secure Engine's response, not from a check in the SE Manager.Cause
On this part an ECC private key is either signing-only (
SL_SE_KEY_FLAG_ASYMMETRIC_SIGNING_ONLY), usable for ECDSA, or a key-agreement key, usable for ECDH. For a wrapped key the flags are part of the wrapped blob, so they are fixed when the key is generated or imported. They must be described the same way every time the key is used: a descriptor with different flags is refused.The port uses
HAS_PRIVATE_KEY | NON_EXPORTABLEwithoutSIGNING_ONLYeverywhere it creates or binds a device-resident ECC key:silabs_key.cL374-L375,wc_SilabsSe_EccGetWrappedKeySize()silabs_key.cL424-L425,wc_SilabsSe_EccGenerateWrappedKey()silabs_key.cL492-L493,wc_SilabsSe_EccUseWrappedKey()silabs_key.cL537-L538,wc_SilabsSe_EccUseBuiltInKey(). Not tested here, but by the same rule a built-in slot such asSL_SE_KEY_SLOT_APPLICATION_ATTESTATION_KEYmay not be able to sign through it.The plaintext paths do set it (
silabs_ecc.cL257-L259, L331-L334). That is presumably whywolfcrypt_testand the ECDSA benchmark pass: they sign with plaintext keys, so the wrapped-key sign path is not exercised by them.Suggested fix
Because the usage is fixed at creation, it has to be chosen when the key is generated and repeated when it is bound. For example:
The existing calls could stay as they are (agreement keys) and say so in their documentation and the README's "Secure Vault key management" section. A test that signs with a wrapped key would cover the path.
Relevant log output