Skip to content

[Bug]: Silicon Labs crypto callback port: wc_SilabsSe_*UseWrappedKey() cannot bind wrapped keys created with other flags #11686

Description

@lucas-mmb

Contact Details

lucas.holzen@mmbnetworks.com

Version

commit f6a75d4

Description

wc_SilabsSe_AesUseWrappedKey() and wc_SilabsSe_EccUseWrappedKey() (PR #11267) hard-code the descriptor flags of the key they bind: NON_EXPORTABLE for AES, and HAS_PRIVATE_KEY | NON_EXPORTABLE for ECC. The Secure Engine checks a wrapped key's flags against the flags it was wrapped with. So a wrapped blob created by the application through the SE Manager with any other flags cannot be bound:

  • an exportable key, which the application still needs to read back in plaintext;
  • an ECC key marked SIGNING_ONLY (see the companion issue on signing).

The ECC bind fails outright. The AES bind returns 0, and the first cipher operation then fails.

Environment

  • wolfSSL f6a75d4aaf2a50eabf30b5718300d68578e26101 (merge of Add Silicon Labs EFR32xG25 Secure Element crypto callback port #11267)
  • EFR32FG25B121F1152IM56 (Secure Vault High), SE firmware 2.2.1
  • Simplicity SDK 2026.6.1, arm-none-eabi-gcc 14.2.rel1, FreeRTOS
  • user_settings.h: WOLFSSL_SILABS_CRYPTOCB (all engines), HAVE_ECC, HAVE_AES_ECB, WOLFSSL_AES_DIRECT

Reproduction steps

Wrap a key with the SE Manager, without SL_SE_KEY_FLAG_NON_EXPORTABLE, then bind it through the port:

/* AES-128, exportable */
sl_se_key_descriptor_t plain = {
    .type = SL_SE_KEY_TYPE_AES_128,
    .flags = 0,
    .storage.method = SL_SE_KEY_STORAGE_EXTERNAL_PLAINTEXT,
    .storage.location.buffer = { key16, 16 },
};
sl_se_key_descriptor_t wrap = plain;
wrap.storage.method = SL_SE_KEY_STORAGE_EXTERNAL_WRAPPED;
wrap.storage.location.buffer.pointer = wrapped;      /* word-aligned */
wrap.storage.location.buffer.size = 16 + SLI_SE_WRAPPED_KEY_OVERHEAD;
sl_se_import_key(&ctx, &plain, &wrap);                /* SL_STATUS_OK */

Aes aes;
wc_AesInit(&aes, NULL, WOLFSSL_SILABS_DEVID);
wc_SilabsSe_AesUseWrappedKey(&aes, wrapped, 16 + SLI_SE_WRAPPED_KEY_OVERHEAD,
                             128);                    /* 0 */
wc_AesEcbEncrypt(&aes, out, in, 16);                  /* WC_HW_E (-248) */
/* P-256, exportable private key, flags HAS_PRIVATE_KEY only */
/* ... sl_se_generate_key() into a wrapped descriptor with those flags ... */
ecc_key key;
wc_ecc_init_ex(&key, NULL, WOLFSSL_SILABS_DEVID);
wc_SilabsSe_EccUseWrappedKey(&key, wrapped, 32 + SLI_SE_WRAPPED_KEY_OVERHEAD,
                             ECC_SECP256R1);          /* fails: the public-point
                                                         export in
                                                         silabs_ecc_bind_pubkey()
                                                         is refused */

Expected

A way to bind a wrapped key the application created with its own flags, so the Secure Engine uses it through wolfCrypt with the flags it was wrapped with.

Actual

The descriptor always carries the port's flags:

The Secure Engine refuses the mismatched key, which the port reports as a wolfCrypt error (WC_HW_E for the AES operation). Binding the same blobs with descriptors that carry their real flags works: AES-ECB reproduces the FIPS-197 vector, and ECDH gives the expected shared secret, both run on the Secure Engine.

Why it matters

The port's own generators only make non-exportable keys, which suits keys that must never leave the device. Applications can also have keys that are wrapped at rest but must remain exportable, for example a key store whose contract includes reading the plaintext back. For those, the flags belong to the application. Today the only way to bind such a key is to fill in the ecc_key / Aes fields the port sets internally (cmd_ctx, key, silabsKeySet, key_raw, keyInstalled, ctx.keySet) and replicate silabs_ecc_bind_pubkey(), which depends on internals.

Suggested fix

Variants that take the flags, or the caller's own sl_se_key_descriptor_t, for example:

int wc_SilabsSe_AesUseWrappedKeyEx(Aes* aes, const byte* wrapped,
    word32 wrappedSz, int keyBits, word32 seKeyFlags);
int wc_SilabsSe_EccUseWrappedKeyEx(ecc_key* key, const byte* wrapped,
    word32 wrappedSz, int curveId, word32 seKeyFlags);

The same Ex form could carry the signing/agreement choice from the companion issue. Alternatively, document that the binders only accept keys from the port's own generators.

Relevant log output

Activity

  1. self-assigned this
    on Oct 7, 2026
  2. dgarske commented on Oct 8, 2026

    @dgarske
    Member

    Hi @lucas-mmb , please review the fix in #11687 . Looking forward to your feedback
    Thanks, David Garske, wolfSSL

  3. lucas-mmb commented on Oct 8, 2026

    @lucas-mmb
    Author

    That looks great, thank you very much. Its resolved the issue.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Labels

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions